From 9a587853724c6a1afa71bb40485d7e8f4801186c Mon Sep 17 00:00:00 2001 From: hayk Date: Wed, 13 Dec 2023 17:25:02 -0500 Subject: [PATCH 001/773] Update LICENSE --- LICENSE | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/LICENSE b/LICENSE index dd8742c86..e4887ddc7 100644 --- a/LICENSE +++ b/LICENSE @@ -1,14 +1,6 @@ BSD 3-Clause License -Copyright (c) 2022, Princeton University (PU), and -Princeton Plasma Physics Lab (PPPL). -All rights reserved. - -Contributors (alphabetical order): -Benjamin Crinquand (GRPIC), -Alisa Galishnikova (GRPIC), -Hayk Hakobyan (framework, PIC, GRPIC), -Sasha Philippov +Copyright (c) 2023, entity-toolkit Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: From 35ebe5328b2aa7df5fe95f0f6e9927b0769411b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20B=C3=B6ss?= Date: Sat, 3 Aug 2024 14:54:47 -0500 Subject: [PATCH 002/773] initial commit: modification to shock pgen to run magnetized shocks --- setups/srpic/shock/pgen.hpp | 57 ++++++++++++++++++++++++++++++++--- setups/srpic/shock/shock.toml | 4 +++ 2 files changed, 57 insertions(+), 4 deletions(-) diff --git a/setups/srpic/shock/pgen.hpp b/setups/srpic/shock/pgen.hpp index f07b99878..4a9cc3f09 100644 --- a/setups/srpic/shock/pgen.hpp +++ b/setups/srpic/shock/pgen.hpp @@ -14,6 +14,47 @@ namespace user { using namespace ntt; + template + struct InitFields + { + InitFields(real_t bmag, real_t btheta, real_t bphi, real_t bbeta) : + Bmag { bmag }, Btheta { btheta }, Bphi { bphi }, Bbeta { bbeta } {} + + // alternative: initialize magnetisation from simulation parameters as in Tristan? + // Bmag = math::sqrt(ppc0 * 0.5 * c * c * me * sigma); + + // magnetic field components + Inline auto bx1(const coord_t &x_Ph) const -> real_t + { + return Bmag * math::cos(Btheta / 180.0 * Kokkos::numbers::pi); + } + Inline auto bx2(const coord_t &x_Ph) const -> real_t + { + return Bmag * math::sin(Btheta / 180.0 * Kokkos::numbers::pi) * math::sin(Bphi / 180.0 * Kokkos::numbers::pi); + } + Inline auto bx3(const coord_t &x_Ph) const -> real_t + { + return Bmag * math::sin(Btheta / 180.0 * Kokkos::numbers::pi) * math::cos(Bphi / 180.0 * Kokkos::numbers::pi); + } + + // electric field components + Inline auto ex1(const coord_t &x_Ph) const -> real_t + { + return ZERO; + } + Inline auto ex2(const coord_t &x_Ph) const -> real_t + { + return -Bbeta * Bmag * math::sin(Btheta / 180.0 * Kokkos::numbers::pi) * math::cos(Bphi / 180.0 * Kokkos::numbers::pi); + } + Inline auto ex3(const coord_t &x_Ph) const -> real_t + { + return -Bbeta * Bmag * math::sin(Btheta / 180.0 * Kokkos::numbers::pi) * math::sin(Bphi / 180.0 * Kokkos::numbers::pi); + } + + private: + const real_t Btheta, Bphi, Bbeta, Bmag; + }; + template struct PGen : public arch::ProblemGenerator { // compatibility traits for the problem generator @@ -30,10 +71,18 @@ namespace user { const real_t drift_ux, temperature; - inline PGen(const SimulationParams& p, const Metadomain& m) - : arch::ProblemGenerator(p) - , drift_ux { p.template get("setup.drift_ux") } - , temperature { p.template get("setup.temperature") } {} + const real_t Btheta, Bphi, Bbeta, Bmag; + InitFields init_flds; + + inline PGen(const SimulationParams &p, const Metadomain &m) + : arch::ProblemGenerator { p } + , drift_ux { p.template get("setup.drift_ux") } + , temperature { p.template get("setup.temperature") } + , Bmag { p.template get("setup.Bmag", 0.0) } + , Btheta { p.template get("setup.Btheta", 0.0) } + , Bphi { p.template get("setup.Bphi", 0.0) } + , Bbeta { p.template get("setup.Bbeta", 0.0) } + , init_flds { Bmag, Btheta, Bphi, Bbeta } {} inline PGen() {} diff --git a/setups/srpic/shock/shock.toml b/setups/srpic/shock/shock.toml index f48edb2d6..90571631e 100644 --- a/setups/srpic/shock/shock.toml +++ b/setups/srpic/shock/shock.toml @@ -42,6 +42,10 @@ [setup] drift_ux = 0.1 temperature = 1e-3 + Bmag = 0.0 + Btheta = 0.0 + Bphi = 0.0 + Bbeta = 0.0 [output] interval_time = 0.1 From 9246d6855b9ffe42aba7b59762d393e2a4968c7a Mon Sep 17 00:00:00 2001 From: hayk Date: Thu, 8 Aug 2024 20:40:23 -0400 Subject: [PATCH 003/773] restructure adios to add checkpoints --- input.example.toml | 17 ++++++++++++ src/engines/engine.hpp | 43 +++++++++++------------------ src/engines/engine_init.cpp | 5 ++-- src/framework/domain/metadomain.cpp | 13 ++------- src/framework/domain/metadomain.h | 17 +++++------- src/framework/domain/output.cpp | 4 ++- src/framework/parameters.cpp | 8 ++++++ src/global/defaults.h | 5 ++++ src/output/writer.cpp | 19 ++++++++++--- src/output/writer.h | 24 ++++++++-------- 10 files changed, 88 insertions(+), 67 deletions(-) diff --git a/input.example.toml b/input.example.toml index 88589495c..eacb7f402 100644 --- a/input.example.toml +++ b/input.example.toml @@ -422,6 +422,23 @@ # @default: false ghosts = "" +[checkpoint] + # Number of timesteps between checkpoints: + # @type: unsigned int: > 0 + # @default: 1000 + interval = "" + # Physical (code) time interval between checkpoints: + # @type: float: > 0 + # @default: -1.0 (disabled) + # @note: When `interval_time` < 0, the output is controlled by `interval`, otherwise by `interval_time` + interval_time = "" + # Number of checkpoints to keep: + # @type: unsigned int: > 0 + # @default: 2 + # @note: 0 = disable checkpointing + # @note: -1 = keep all checkpoints + keep = "" + [diagnostics] # Number of timesteps between diagnostic logs: # @type: int: > 0 diff --git a/src/engines/engine.hpp b/src/engines/engine.hpp index a57b52d19..03d2da859 100644 --- a/src/engines/engine.hpp +++ b/src/engines/engine.hpp @@ -34,6 +34,15 @@ #include +#if defined(OUTPUT_ENABLED) + #include + #include +#endif // OUTPUT_ENABLED + +#if defined(MPI_ENABLED) + #include +#endif // MPI_ENABLED + #include #include @@ -45,6 +54,12 @@ namespace ntt { static_assert(user::PGen::is_pgen, "unrecognized problem generator"); protected: +#if MPI_ENABLED + adios2::ADIOS m_adios { MPI_COMM_WORLD }; +#else + adios2::ADIOS m_adios; +#endif + SimulationParams& m_params; Metadomain m_metadomain; user::PGen m_pgen; @@ -65,29 +80,6 @@ namespace ntt { static constexpr Dimension D { M::Dim }; static constexpr bool is_engine { true }; -#if defined(OUTPUT_ENABLED) - Engine(SimulationParams& params) - : m_params { params } - , m_metadomain { params.get("simulation.domain.number"), - params.get>( - "simulation.domain.decomposition"), - params.get>("grid.resolution"), - params.get>("grid.extent"), - params.get>( - "grid.boundaries.fields"), - params.get>( - "grid.boundaries.particles"), - params.get>( - "grid.metric.params"), - params.get>( - "particles.species"), - params.template get("output.format") } - , m_pgen { m_params, m_metadomain } - , runtime { params.get("simulation.runtime") } - , dt { params.get("algorithms.timestep.dt") } - , max_steps { static_cast(runtime / dt) } - -#else // not OUTPUT_ENABLED Engine(SimulationParams& params) : m_params { params } , m_metadomain { params.get("simulation.domain.number"), @@ -106,10 +98,7 @@ namespace ntt { , m_pgen { m_params, m_metadomain } , runtime { params.get("simulation.runtime") } , dt { params.get("algorithms.timestep.dt") } - , max_steps { static_cast(runtime / dt) } -#endif - { - + , max_steps { static_cast(runtime / dt) } { raise::ErrorIf(not pgen_is_ok, "Problem generator is not compatible with the picked engine/metric/dimension", HERE); print_report(); } diff --git a/src/engines/engine_init.cpp b/src/engines/engine_init.cpp index abb8754d9..71900a406 100644 --- a/src/engines/engine_init.cpp +++ b/src/engines/engine_init.cpp @@ -11,6 +11,7 @@ #include "metrics/spherical.h" #include "archetypes/field_setter.h" + #include "engines/engine.hpp" #include @@ -21,7 +22,7 @@ namespace ntt { void Engine::init() { if constexpr (pgen_is_ok) { #if defined(OUTPUT_ENABLED) - m_metadomain.InitWriter(m_params); + m_metadomain.InitWriter(&m_adios, m_params); #endif logger::Checkpoint("Initializing Engine", HERE); if constexpr ( @@ -55,4 +56,4 @@ namespace ntt { template class Engine>; template class Engine>; template class Engine>; -} // namespace ntt \ No newline at end of file +} // namespace ntt diff --git a/src/framework/domain/metadomain.cpp b/src/framework/domain/metadomain.cpp index b13475fd6..cdc9e5a3d 100644 --- a/src/framework/domain/metadomain.cpp +++ b/src/framework/domain/metadomain.cpp @@ -37,21 +37,12 @@ namespace ntt { const boundaries_t& global_flds_bc, const boundaries_t& global_prtl_bc, const std::map& metric_params, - const std::vector& species_params -#if defined(OUTPUT_ENABLED) - , - const std::string& output_engine -#endif - ) + const std::vector& species_params) : g_ndomains { global_ndomains } , g_decomposition { global_decomposition } , g_mesh { global_ncells, global_extent, metric_params, global_flds_bc, global_prtl_bc } , g_metric_params { metric_params } - , g_species_params { species_params } -#if defined(OUTPUT_ENABLED) - , g_writer { output_engine } -#endif - { + , g_species_params { species_params } { #if defined(MPI_ENABLED) MPI_Comm_size(MPI_COMM_WORLD, &g_mpi_size); MPI_Comm_rank(MPI_COMM_WORLD, &g_mpi_rank); diff --git a/src/framework/domain/metadomain.h b/src/framework/domain/metadomain.h index fb81fcfca..f7444c582 100644 --- a/src/framework/domain/metadomain.h +++ b/src/framework/domain/metadomain.h @@ -30,9 +30,12 @@ #include #endif // MPI_ENABLED -#if defined OUTPUT_ENABLED +#if defined(OUTPUT_ENABLED) #include "output/writer.h" -#endif + + #include + #include +#endif // OUTPUT_ENABLED #include #include @@ -95,7 +98,6 @@ namespace ntt { * @param global_prtl_bc boundary conditions for particles * @param metric_params parameters for the metric * @param species_params parameters for the particle species - * @param output_params parameters for the output */ Metadomain(unsigned int, const std::vector&, @@ -104,15 +106,10 @@ namespace ntt { const boundaries_t&, const boundaries_t&, const std::map&, - const std::vector& -#if defined(OUTPUT_ENABLED) - , - const std::string& -#endif - ); + const std::vector&); #if defined(OUTPUT_ENABLED) - void InitWriter(const SimulationParams&); + void InitWriter(adios2::ADIOS*, const SimulationParams&); auto Write(const SimulationParams&, std::size_t, long double, diff --git a/src/framework/domain/output.cpp b/src/framework/domain/output.cpp index cabb37093..0fcc89593 100644 --- a/src/framework/domain/output.cpp +++ b/src/framework/domain/output.cpp @@ -33,7 +33,8 @@ namespace ntt { template - void Metadomain::InitWriter(const SimulationParams& params) { + void Metadomain::InitWriter(adios2::ADIOS* ptr_adios, + const SimulationParams& params) { raise::ErrorIf( local_subdomain_indices().size() != 1, "Output for now is only supported for one subdomain per rank", @@ -57,6 +58,7 @@ namespace ntt { } } + g_writer.init(ptr_adios, params.template get("output.format")); g_writer.defineMeshLayout(glob_shape_with_ghosts, off_ncells_with_ghosts, loc_shape_with_ghosts, diff --git a/src/framework/parameters.cpp b/src/framework/parameters.cpp index 6e581a6b7..8926b6453 100644 --- a/src/framework/parameters.cpp +++ b/src/framework/parameters.cpp @@ -466,6 +466,14 @@ namespace ntt { set("output.debug.ghosts", toml::find_or(raw_data, "output", "debug", "ghosts", false)); + /* [checkpoint] --------------------------------------------------------- */ + set("checkpoint.interval", + toml::find_or(raw_data, "checkpoint", "interval", defaults::checkpoint::interval)); + set("checkpoint.interval_time", + toml::find_or(raw_data, "checkpoint", "interval_time", -1.0)); + set("checkpoint.keep", + toml::find_or(raw_data, "checkpoint", "keep", defaults::checkpoint::keep)); + /* [diagnostics] -------------------------------------------------------- */ set("diagnostics.interval", toml::find_or(raw_data, "diagnostics", "interval", defaults::diag::interval)); diff --git a/src/global/defaults.h b/src/global/defaults.h index d238a3492..fb874481e 100644 --- a/src/global/defaults.h +++ b/src/global/defaults.h @@ -60,6 +60,11 @@ namespace ntt::defaults { const std::size_t spec_nbins = 200; } // namespace output + namespace checkpoint { + const std::size_t interval = 1000; + const std::size_t keep = 2; + } // namespace checkpoint + namespace diag { const std::size_t interval = 1; } // namespace diag diff --git a/src/output/writer.cpp b/src/output/writer.cpp index 182705efa..aeb9dbce8 100644 --- a/src/output/writer.cpp +++ b/src/output/writer.cpp @@ -19,8 +19,11 @@ namespace out { - Writer::Writer(const std::string& engine) : m_engine { engine } { - m_io = m_adios.DeclareIO("Entity::ADIOS2"); + void Writer::init(adios2::ADIOS* ptr_adios, const std::string& engine) { + m_engine = engine; + p_adios = ptr_adios; + + m_io = p_adios->DeclareIO("Entity::ADIOS2"); m_io.SetEngine(engine); m_io.DefineVariable("Step"); @@ -284,7 +287,11 @@ namespace out { void Writer::beginWriting(const std::string& fname, std::size_t tstep, long double time) { - m_adios.ExitComputationBlock(); + p_adios->ExitComputationBlock(); + if (m_writing_mode) { + raise::Fatal("Already writing", HERE); + } + m_writing_mode = true; try { m_writer = m_io.Open(fname + (m_engine == "hdf5" ? ".h5" : ".bp"), m_mode); } catch (std::exception& e) { @@ -297,9 +304,13 @@ namespace out { } void Writer::endWriting() { + if (!m_writing_mode) { + raise::Fatal("Not writing", HERE); + } + m_writing_mode = false; m_writer.EndStep(); m_writer.Close(); - m_adios.EnterComputationBlock(); + p_adios->EnterComputationBlock(); } template void Writer::writeField(const std::vector&, diff --git a/src/output/writer.h b/src/output/writer.h index d6a089095..3fb958bc3 100644 --- a/src/output/writer.h +++ b/src/output/writer.h @@ -60,23 +60,20 @@ namespace out { }; class Writer { -#if !defined(MPI_ENABLED) - adios2::ADIOS m_adios; -#else // MPI_ENABLED - adios2::ADIOS m_adios { MPI_COMM_WORLD }; -#endif + adios2::ADIOS* p_adios { nullptr }; + adios2::IO m_io; adios2::Engine m_writer; adios2::Mode m_mode { adios2::Mode::Write }; // global shape of the fields array to output - adios2::Dims m_flds_g_shape; + adios2::Dims m_flds_g_shape; // local corner of the fields array to output - adios2::Dims m_flds_l_corner; + adios2::Dims m_flds_l_corner; // local shape of the fields array to output - adios2::Dims m_flds_l_shape; - bool m_flds_ghosts; - const std::string m_engine; + adios2::Dims m_flds_l_shape; + bool m_flds_ghosts; + std::string m_engine; std::map m_trackers; @@ -84,14 +81,17 @@ namespace out { std::vector m_prtl_writers; std::vector m_spectra_writers; + bool m_writing_mode { false }; + public: - Writer() : m_engine { "disabled" } {} + Writer() {} - Writer(const std::string& engine); ~Writer() = default; Writer(Writer&&) = default; + void init(adios2::ADIOS*, const std::string&); + void addTracker(const std::string&, std::size_t, long double); auto shouldWrite(const std::string&, std::size_t, long double) -> bool; From 7014037dd22a71162e2a5d71319a4851a4595cf1 Mon Sep 17 00:00:00 2001 From: hayk Date: Thu, 8 Aug 2024 20:50:29 -0400 Subject: [PATCH 004/773] bug in writer test --- src/output/tests/writer-mpi.cpp | 5 ++++- src/output/tests/writer-nompi.cpp | 10 ++++++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/output/tests/writer-mpi.cpp b/src/output/tests/writer-mpi.cpp index 72cf46e35..649590b49 100644 --- a/src/output/tests/writer-mpi.cpp +++ b/src/output/tests/writer-mpi.cpp @@ -32,7 +32,10 @@ auto main(int argc, char* argv[]) -> int { try { using namespace ntt; - auto writer = out::Writer("hdf5"); + + adios2::ADIOS adios { MPI_COMM_WORLD }; + auto writer = out::Writer(); + writer.init(&adios, "hdf5"); writer.defineMeshLayout({ static_cast(size) * 10 }, { static_cast(rank) * 10 }, { 10 }, diff --git a/src/output/tests/writer-nompi.cpp b/src/output/tests/writer-nompi.cpp index a2a116e65..e8e6facb7 100644 --- a/src/output/tests/writer-nompi.cpp +++ b/src/output/tests/writer-nompi.cpp @@ -26,10 +26,16 @@ auto main(int argc, char* argv[]) -> int { Kokkos::initialize(argc, argv); try { + adios2::ADIOS adios; using namespace ntt; - auto writer = out::Writer("hdf5"); - writer.defineMeshLayout({ 10, 10, 10 }, { 0, 0, 0 }, { 10, 10, 10 }, false, Coord::Cart); + auto writer = out::Writer(); + writer.init(&adios, "hdf5"); + writer.defineMeshLayout({ 10, 10, 10 }, + { 0, 0, 0 }, + { 10, 10, 10 }, + false, + Coord::Cart); writer.defineFieldOutputs(SimEngine::SRPIC, { "E", "B", "Rho_1_3", "N_2" }); ndfield_t field { "fld", From 0f3d68aed2f7c01266b81de3fbc3cbb562f91ad0 Mon Sep 17 00:00:00 2001 From: hayk Date: Sat, 10 Aug 2024 01:41:39 -0400 Subject: [PATCH 005/773] preliminary checkpoint framework --- .clang-format | 2 + .gitignore | 2 + CMakeLists.txt | 2 - extern/Kokkos | 2 +- extern/adios2 | 2 +- extern/toml11 | 2 +- src/CMakeLists.txt | 8 +- src/checkpoint/CMakeLists.txt | 29 + src/checkpoint/writer.cpp | 103 + src/checkpoint/writer.h | 62 + src/engines/CMakeLists.txt | 1 + src/engines/engine.hpp | 34 +- src/engines/engine_init.cpp | 1 + src/engines/engine_run.cpp | 16 +- src/engines/engine_step_report.cpp | 60 +- src/engines/grpic.hpp | 6 +- src/engines/srpic.hpp | 3 +- src/framework/CMakeLists.txt | 6 +- src/framework/domain/checkpoint.cpp | 60 + src/framework/domain/metadomain.h | 16 +- src/framework/parameters.cpp | 24 +- src/framework/parameters.h | 13 +- src/framework/simulation.cpp | 24 +- src/framework/simulation.h | 15 +- src/framework/tests/parameters.cpp | 2 +- src/global/CMakeLists.txt | 6 +- src/global/defaults.h | 2 +- src/global/global.h | 23 +- src/global/utils/param_container.cpp | 333 + src/global/utils/param_container.h | 9 + src/global/utils/timer.h | 34 +- src/global/utils/toml.h | 17972 +++++++++++++++++++++++++ src/global/utils/tools.h | 57 +- src/output/CMakeLists.txt | 1 - src/output/write_attrs.cpp | 136 - src/output/writer.cpp | 23 +- src/output/writer.h | 36 +- 37 files changed, 18813 insertions(+), 314 deletions(-) create mode 100644 src/checkpoint/CMakeLists.txt create mode 100644 src/checkpoint/writer.cpp create mode 100644 src/checkpoint/writer.h create mode 100644 src/framework/domain/checkpoint.cpp create mode 100644 src/global/utils/param_container.cpp create mode 100644 src/global/utils/toml.h delete mode 100644 src/output/write_attrs.cpp diff --git a/.clang-format b/.clang-format index ed150af9b..b3bb8d132 100644 --- a/.clang-format +++ b/.clang-format @@ -106,6 +106,8 @@ IncludeCategories: Priority: 4 - Regex: '^"engines\/.*\.h"' Priority: 4 + - Regex: '^"checkpoint\/.*\.h"' + Priority: 4 - Regex: '^"output\/.*\.h"' Priority: 4 - Regex: '^"archetypes\/.*\.h"' diff --git a/.gitignore b/.gitignore index 20bfe33a3..53d09b648 100644 --- a/.gitignore +++ b/.gitignore @@ -54,3 +54,5 @@ Testing/ .schema.json *_old/ action-token +*.vim +ignore-* diff --git a/CMakeLists.txt b/CMakeLists.txt index 2260323a3..62319559b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -82,10 +82,8 @@ include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/dependencies.cmake) find_or_fetch_dependency(Kokkos FALSE) find_or_fetch_dependency(plog TRUE) -find_or_fetch_dependency(toml11 TRUE) set(DEPENDENCIES Kokkos::kokkos) include_directories(${plog_SRC}/include) -include_directories(${toml11_SRC}) # -------------------------------- Main code ------------------------------- # set_precision(${precision}) diff --git a/extern/Kokkos b/extern/Kokkos index eb11070f6..5fc08a9a7 160000 --- a/extern/Kokkos +++ b/extern/Kokkos @@ -1 +1 @@ -Subproject commit eb11070f67565b2e660659f5207f0363bdf3b882 +Subproject commit 5fc08a9a7da14d8530f8c7035d008ef63ddb4e5c diff --git a/extern/adios2 b/extern/adios2 index b8761e2af..e524dce1b 160000 --- a/extern/adios2 +++ b/extern/adios2 @@ -1 +1 @@ -Subproject commit b8761e2afab2cd05b89d09b2ee4da1cd7a834225 +Subproject commit e524dce1b72ccf75422cea6342ee2d64a6a87964 diff --git a/extern/toml11 b/extern/toml11 index 12c0f379f..9b914db23 160000 --- a/extern/toml11 +++ b/extern/toml11 @@ -1 +1 @@ -Subproject commit 12c0f379f2e865b4ce984758d5ae004f9de07d69 +Subproject commit 9b914db23df4acb6f1885fee29e07e9af959251e diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5d7f0abb4..d75094c2b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -7,6 +7,7 @@ # - ntt_framework [required] # - ntt_metrics [required] # - ntt_engine [required] +# - ntt_pgen [required] # @uses: # - kokkos [required] # - plog [required] @@ -30,9 +31,12 @@ add_subdirectory(${SRC_DIR}/kernels ${CMAKE_CURRENT_BINARY_DIR}/kernels) add_subdirectory(${SRC_DIR}/archetypes ${CMAKE_CURRENT_BINARY_DIR}/archetypes) add_subdirectory(${SRC_DIR}/framework ${CMAKE_CURRENT_BINARY_DIR}/framework) add_subdirectory(${SRC_DIR}/engines ${CMAKE_CURRENT_BINARY_DIR}/engines) -if (${output} STREQUAL "ON") -add_subdirectory(${SRC_DIR}/output ${CMAKE_CURRENT_BINARY_DIR}/output) + +if (${output}) + add_subdirectory(${SRC_DIR}/output ${CMAKE_CURRENT_BINARY_DIR}/output) + add_subdirectory(${SRC_DIR}/checkpoint ${CMAKE_CURRENT_BINARY_DIR}/checkpoint) endif() + add_subdirectory(${SRC_DIR}/../setups ${CMAKE_CURRENT_BINARY_DIR}/setups) set(libs ntt_global ntt_framework ntt_metrics ntt_engines ntt_pgen) diff --git a/src/checkpoint/CMakeLists.txt b/src/checkpoint/CMakeLists.txt new file mode 100644 index 000000000..00c11ac04 --- /dev/null +++ b/src/checkpoint/CMakeLists.txt @@ -0,0 +1,29 @@ +# ------------------------------ +# @defines: ntt_checkpoint [STATIC/SHARED] +# @sources: +# - writer.cpp +# @includes: +# - ../ +# @depends: +# - ntt_global [required] +# @uses: +# - kokkos [required] +# - ADIOS2 [required] +# - mpi [optional] +# ------------------------------ + +set(SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}) +set(SOURCES + ${SRC_DIR}/writer.cpp +) +add_library(ntt_checkpoint ${SOURCES}) + +set(libs ntt_global) +add_dependencies(ntt_checkpoint ${libs}) +target_link_libraries(ntt_checkpoint PUBLIC ${libs}) +target_link_libraries(ntt_checkpoint PRIVATE stdc++fs) + +target_include_directories(ntt_checkpoint + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../ + INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/../ +) diff --git a/src/checkpoint/writer.cpp b/src/checkpoint/writer.cpp new file mode 100644 index 000000000..e56f59b36 --- /dev/null +++ b/src/checkpoint/writer.cpp @@ -0,0 +1,103 @@ +#include "checkpoint/writer.h" + +#include "global.h" + +#include "utils/error.h" +#include "utils/formatting.h" +#include "utils/log.h" + +#include "framework/parameters.h" + +#include +#include + +#include +#include +#include +#include +#include + +namespace checkpoint { + + void Writer::init(adios2::ADIOS* ptr_adios, + std::size_t interval, + long double interval_time, + int keep) { + m_keep = keep; + m_enabled = keep != 0; + if (!m_enabled) { + return; + } + m_tracker.init("checkpoint", interval, interval_time); + p_adios = ptr_adios; + raise::ErrorIf(p_adios == nullptr, "ADIOS pointer is null", HERE); + + m_io = p_adios->DeclareIO("Entity::Checkpoint"); + m_io.SetEngine("BPFile"); + + m_io.DefineVariable("Step"); + m_io.DefineVariable("Time"); + m_io.DefineAttribute("NGhosts", ntt::N_GHOSTS); + + const std::filesystem::path save_path { "checkpoints" }; + if (!std::filesystem::exists(save_path)) { + std::filesystem::create_directory(save_path); + } + p_adios->EnterComputationBlock(); + } + + auto Writer::shouldSave(std::size_t step, long double time) -> bool { + return m_enabled and m_tracker.shouldWrite(step, time); + } + + void Writer::beginSaving(const ntt::SimulationParams& params, + std::size_t step, + long double time) { + raise::ErrorIf(!m_enabled, "Checkpoint is not enabled", HERE); + raise::ErrorIf(p_adios == nullptr, "ADIOS pointer is null", HERE); + p_adios->ExitComputationBlock(); + if (m_writing_mode) { + raise::Fatal("Already writing", HERE); + } + m_writing_mode = true; + try { + auto fname = fmt::format("checkpoints/step-%08lu.bp", step); + m_writer = m_io.Open(fname, adios2::Mode::Write); + m_written.push_back(fname); + } catch (std::exception& e) { + raise::Fatal(e.what(), HERE); + } + + // write the metadata + std::ofstream metadata; + metadata.open(fmt::format("checkpoints/meta-%08lu.toml", step).c_str()); + metadata << params.data() << std::endl; + metadata.close(); + + m_writer.BeginStep(); + m_writer.Put(m_io.InquireVariable("Step"), &step); + m_writer.Put(m_io.InquireVariable("Time"), &time); + } + + void Writer::endSaving() { + raise::ErrorIf(p_adios == nullptr, "ADIOS pointer is null", HERE); + if (!m_writing_mode) { + raise::Fatal("Not writing", HERE); + } + m_writing_mode = false; + m_writer.EndStep(); + m_writer.Close(); + p_adios->EnterComputationBlock(); + + // optionally remove the oldest checkpoint + if (m_keep > 0 and m_written.size() > (std::size_t)m_keep) { + const auto oldest = m_written.front(); + if (std::filesystem::exists(oldest)) { + std::filesystem::remove_all(oldest); + m_written.erase(m_written.begin()); + } else { + raise::Warning("Checkpoint file does not exist for some reason", HERE); + } + } + } +} // namespace checkpoint diff --git a/src/checkpoint/writer.h b/src/checkpoint/writer.h new file mode 100644 index 000000000..ec2fa08d8 --- /dev/null +++ b/src/checkpoint/writer.h @@ -0,0 +1,62 @@ +/** + * @file checkpoint/writer.h + * @brief Class that dumps checkpoints + * @implements + * - checkpoint::Writer + * @cpp: + * - writer.cpp + * @namespaces: + * - save:: + */ + +#ifndef CHECKPOINT_WRITER_H +#define CHECKPOINT_WRITER_H + +#include "global.h" + +#include "utils/tools.h" + +#include "framework/parameters.h" + +#include +#include + +#include + +namespace checkpoint { + + class Writer { + adios2::ADIOS* p_adios { nullptr }; + + adios2::IO m_io; + adios2::Engine m_writer; + + tools::Tracker m_tracker {}; + + bool m_writing_mode { false }; + + std::vector m_written; + + int m_keep; + bool m_enabled; + + public: + Writer() {} + + ~Writer() = default; + + void init(adios2::ADIOS*, std::size_t, long double, int); + + auto shouldSave(std::size_t, long double) -> bool; + + void beginSaving(const ntt::SimulationParams&, std::size_t, long double); + void endSaving(); + + auto enabled() const -> bool { + return m_enabled; + } + }; + +} // namespace checkpoint + +#endif // CHECKPOINT_WRITER_H diff --git a/src/engines/CMakeLists.txt b/src/engines/CMakeLists.txt index 2cc61a265..c91475eb7 100644 --- a/src/engines/CMakeLists.txt +++ b/src/engines/CMakeLists.txt @@ -18,6 +18,7 @@ # @uses: # - kokkos [required] # - plog [required] +# - toml11 [required] # - adios2 [optional] # - hdf5 [optional] # - mpi [optional] diff --git a/src/engines/engine.hpp b/src/engines/engine.hpp index 03d2da859..a2bb09c26 100644 --- a/src/engines/engine.hpp +++ b/src/engines/engine.hpp @@ -25,6 +25,7 @@ #include "utils/error.h" #include "utils/progressbar.h" #include "utils/timer.h" +#include "utils/toml.h" #include "framework/containers/species.h" #include "framework/domain/metadomain.h" @@ -60,9 +61,9 @@ namespace ntt { adios2::ADIOS m_adios; #endif - SimulationParams& m_params; - Metadomain m_metadomain; - user::PGen m_pgen; + SimulationParams m_params; + Metadomain m_metadomain; + user::PGen m_pgen; const long double runtime; const real_t dt; @@ -80,24 +81,25 @@ namespace ntt { static constexpr Dimension D { M::Dim }; static constexpr bool is_engine { true }; - Engine(SimulationParams& params) - : m_params { params } - , m_metadomain { params.get("simulation.domain.number"), - params.get>( + Engine(const toml::value& raw_params) + : m_params { raw_params } + , m_metadomain { m_params.get("simulation.domain.number"), + m_params.get>( "simulation.domain.decomposition"), - params.get>("grid.resolution"), - params.get>("grid.extent"), - params.get>( + m_params.get>( + "grid.resolution"), + m_params.get>("grid.extent"), + m_params.get>( "grid.boundaries.fields"), - params.get>( + m_params.get>( "grid.boundaries.particles"), - params.get>( + m_params.get>( "grid.metric.params"), - params.get>( + m_params.get>( "particles.species") } , m_pgen { m_params, m_metadomain } - , runtime { params.get("simulation.runtime") } - , dt { params.get("algorithms.timestep.dt") } + , runtime { m_params.get("simulation.runtime") } + , dt { m_params.get("algorithms.timestep.dt") } , max_steps { static_cast(runtime / dt) } { raise::ErrorIf(not pgen_is_ok, "Problem generator is not compatible with the picked engine/metric/dimension", HERE); print_report(); @@ -107,7 +109,7 @@ namespace ntt { void init(); void print_report() const; - void print_step_report(timer::Timers&, pbar::DurationHistory&, bool, bool) const; + void print_step_report(timer::Timers&, pbar::DurationHistory&, bool, bool, bool) const; virtual void step_forward(timer::Timers&, Domain&) = 0; diff --git a/src/engines/engine_init.cpp b/src/engines/engine_init.cpp index 71900a406..926bb3f78 100644 --- a/src/engines/engine_init.cpp +++ b/src/engines/engine_init.cpp @@ -23,6 +23,7 @@ namespace ntt { if constexpr (pgen_is_ok) { #if defined(OUTPUT_ENABLED) m_metadomain.InitWriter(&m_adios, m_params); + m_metadomain.InitCheckpointWriter(&m_adios, m_params); #endif logger::Checkpoint("Initializing Engine", HERE); if constexpr ( diff --git a/src/engines/engine_run.cpp b/src/engines/engine_run.cpp index 4485e0e40..e5c8d8647 100644 --- a/src/engines/engine_run.cpp +++ b/src/engines/engine_run.cpp @@ -26,7 +26,8 @@ namespace ntt { "ParticlePusher", "FieldBoundaries", "ParticleBoundaries", "Communications", "Injector", "Sorting", - "Custom", "Output" }, + "Custom", "Output", + "Checkpoint" }, []() { Kokkos::fence(); }, @@ -60,7 +61,8 @@ namespace ntt { ++step; time += dt; - auto print_output = false; + auto print_output = false; + auto print_checkpoint = false; #if defined(OUTPUT_ENABLED) timers.start("Output"); if constexpr ( @@ -79,13 +81,21 @@ namespace ntt { print_output = m_metadomain.Write(m_params, step, time); } timers.stop("Output"); + + timers.start("Checkpoint"); + print_checkpoint = m_metadomain.WriteCheckpoint(m_params, step, time); + timers.stop("Checkpoint"); #endif // advance time_history time_history.tick(); // print final timestep report if (diag_interval > 0 and step % diag_interval == 0) { - print_step_report(timers, time_history, print_output, print_sorting); + print_step_report(timers, + time_history, + print_output, + print_checkpoint, + print_sorting); } timers.resetAll(); } diff --git a/src/engines/engine_step_report.cpp b/src/engines/engine_step_report.cpp index f2a35bb82..7edeaab67 100644 --- a/src/engines/engine_step_report.cpp +++ b/src/engines/engine_step_report.cpp @@ -32,6 +32,7 @@ namespace ntt { void Engine::print_step_report(timer::Timers& timers, pbar::DurationHistory& time_history, bool print_output, + bool print_checkpoint, bool print_sorting) const { DiagFlags diag_flags = Diag::Default; TimerFlags timer_flags = Timer::Default; @@ -45,6 +46,9 @@ namespace ntt { if (print_output) { timer_flags |= Timer::PrintOutput; } + if (print_checkpoint) { + timer_flags |= Timer::PrintCheckpoint; + } if (print_sorting) { timer_flags |= Timer::PrintSorting; } @@ -235,59 +239,3 @@ namespace ntt { template class Engine>; template class Engine>; } // namespace ntt - -// template -// auto Simulation::PrintDiagnostics(const std::size_t& step, -// const real_t& time, -// const timer::Timers& timers, -// std::vector& tstep_durations, -// const DiagFlags diag_flags, -// std::ostream& os) -> void { -// if (tstep_durations.size() > m_params.diagMaxnForPbar()) { -// tstep_durations.erase(tstep_durations.begin()); -// } -// tstep_durations.push_back(timers.get("Total")); -// if (step % m_params.diagInterval() == 0) { -// auto& mblock = this->meshblock; -// const auto title { -// fmt::format("Time = %f : step = %d : Δt = %f", time, step, mblock.timestep()) -// }; -// PrintOnce( -// [](std::ostream& os, std::string title) { -// os << title << std::endl; -// }, -// os, -// title); -// if (diag_flags & DiagFlags_Timers) { -// timers.printAll("", timer::TimerFlags_Default, os); -// } -// if (diag_flags & DiagFlags_Species) { -// auto header = fmt::format("%s %27s", "[SPECIES]", "[TOT]"); -// #if defined(MPI_ENABLED) -// header += fmt::format("%17s %s", "[MIN (%) :", "MAX (%)]"); -// #endif -// PrintOnce( -// [](std::ostream& os, std::string header) { -// os << header << std::endl; -// }, -// os, -// header); -// for (const auto& species : meshblock.particles) { -// species.PrintParticleCounts(os); -// } -// } -// if (diag_flags & DiagFlags_Progress) { -// PrintOnce( -// [](std::ostream& os) { -// os << std::setw(65) << std::setfill('-') << "" << std::endl; -// }, -// os); -// ProgressBar(tstep_durations, time, m_params.totalRuntime(), os); -// } -// PrintOnce( -// [](std::ostream& os) { -// os << std::setw(65) << std::setfill('=') << "" << std::endl; -// }, -// os); -// } -// } diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index 148c1c5c5..a20fc2a86 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -15,6 +15,7 @@ #include "enums.h" #include "utils/timer.h" +#include "utils/toml.h" #include "framework/domain/domain.h" @@ -24,14 +25,15 @@ namespace ntt { template class GRPICEngine : public Engine { + using base_t = Engine; + using Engine::m_params; using Engine::m_metadomain; public: static constexpr auto S { SimEngine::SRPIC }; - GRPICEngine(SimulationParams& params) - : Engine { params } {} + GRPICEngine(const toml::value& raw_data) : base_t { raw_data } {} ~GRPICEngine() = default; diff --git a/src/engines/srpic.hpp b/src/engines/srpic.hpp index bddc557c9..6f1a0d561 100644 --- a/src/engines/srpic.hpp +++ b/src/engines/srpic.hpp @@ -21,6 +21,7 @@ #include "utils/log.h" #include "utils/numeric.h" #include "utils/timer.h" +#include "utils/toml.h" #include "archetypes/particle_injector.h" #include "framework/domain/domain.h" @@ -70,7 +71,7 @@ namespace ntt { public: static constexpr auto S { SimEngine::SRPIC }; - SRPICEngine(SimulationParams& params) : base_t { params } {} + SRPICEngine(const toml::value& raw_data) : base_t { raw_data } {} ~SRPICEngine() = default; diff --git a/src/framework/CMakeLists.txt b/src/framework/CMakeLists.txt index c7c3ba8a1..8bfbf1430 100644 --- a/src/framework/CMakeLists.txt +++ b/src/framework/CMakeLists.txt @@ -6,6 +6,7 @@ # - domain/grid.cpp # - domain/metadomain.cpp # - domain/communications.cpp +# - domain/checkpoint.cpp # - containers/particles.cpp # - containers/fields.cpp # - domain/output.cpp @@ -31,17 +32,20 @@ set(SOURCES ${SRC_DIR}/domain/grid.cpp ${SRC_DIR}/domain/metadomain.cpp ${SRC_DIR}/domain/communications.cpp + ${SRC_DIR}/domain/checkpoint.cpp ${SRC_DIR}/containers/particles.cpp ${SRC_DIR}/containers/fields.cpp ) if (${output}) list(APPEND SOURCES ${SRC_DIR}/domain/output.cpp) + list(APPEND SOURCES ${SRC_DIR}/domain/checkpoint.cpp) endif() add_library(ntt_framework ${SOURCES}) set(libs ntt_global ntt_metrics ntt_kernels) if(${output}) list(APPEND libs ntt_output) + list(APPEND libs ntt_checkpoint) endif() add_dependencies(ntt_framework ${libs}) target_link_libraries(ntt_framework PUBLIC ${libs}) @@ -49,4 +53,4 @@ target_link_libraries(ntt_framework PUBLIC ${libs}) target_include_directories(ntt_framework PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../ INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/../ -) \ No newline at end of file +) diff --git a/src/framework/domain/checkpoint.cpp b/src/framework/domain/checkpoint.cpp new file mode 100644 index 000000000..3295e9430 --- /dev/null +++ b/src/framework/domain/checkpoint.cpp @@ -0,0 +1,60 @@ +#include "enums.h" +#include "global.h" + +#include "utils/error.h" + +#include "metrics/kerr_schild.h" +#include "metrics/kerr_schild_0.h" +#include "metrics/minkowski.h" +#include "metrics/qkerr_schild.h" +#include "metrics/qspherical.h" +#include "metrics/spherical.h" + +#include "checkpoint/writer.h" +#include "framework/domain/metadomain.h" +#include "framework/parameters.h" + +namespace ntt { + + template + void Metadomain::InitCheckpointWriter(adios2::ADIOS* ptr_adios, + const SimulationParams& params) { + raise::ErrorIf( + local_subdomain_indices().size() != 1, + "Checkpoint writing for now is only supported for one subdomain per rank", + HERE); + auto local_domain = subdomain_ptr(local_subdomain_indices()[0]); + raise::ErrorIf(local_domain->is_placeholder(), + "local_domain is a placeholder", + HERE); + + g_checkpoint_writer.init( + ptr_adios, + params.template get("checkpoint.interval"), + params.template get("checkpoint.interval_time"), + params.template get("checkpoint.keep")); + } + + template + auto Metadomain::WriteCheckpoint(const SimulationParams& params, + std::size_t step, + long double time) -> bool { + if (!g_checkpoint_writer.shouldSave(step, time)) { + return false; + } + logger::Checkpoint("Writing checkpoint", HERE); + g_checkpoint_writer.beginSaving(params, step, time); + g_checkpoint_writer.endSaving(); + return true; + } + + template struct Metadomain>; + template struct Metadomain>; + template struct Metadomain>; + template struct Metadomain>; + template struct Metadomain>; + template struct Metadomain>; + template struct Metadomain>; + template struct Metadomain>; + +} // namespace ntt diff --git a/src/framework/domain/metadomain.h b/src/framework/domain/metadomain.h index f7444c582..072a4183f 100644 --- a/src/framework/domain/metadomain.h +++ b/src/framework/domain/metadomain.h @@ -21,6 +21,7 @@ #include "arch/kokkos_aliases.h" #include "utils/timer.h" +#include "checkpoint/writer.h" #include "framework/containers/species.h" #include "framework/domain/domain.h" #include "framework/domain/mesh.h" @@ -108,6 +109,11 @@ namespace ntt { const std::map&, const std::vector&); + Metadomain(const Metadomain&) = delete; + Metadomain& operator=(const Metadomain&) = delete; + + ~Metadomain() = default; + #if defined(OUTPUT_ENABLED) void InitWriter(adios2::ADIOS*, const SimulationParams&); auto Write(const SimulationParams&, @@ -117,13 +123,10 @@ namespace ntt { ndfield_t&, std::size_t, const Domain&)> = {}) -> bool; + void InitCheckpointWriter(adios2::ADIOS*, const SimulationParams&); + auto WriteCheckpoint(const SimulationParams&, std::size_t, long double) -> bool; #endif - Metadomain(const Metadomain&) = delete; - Metadomain& operator=(const Metadomain&) = delete; - - ~Metadomain() = default; - /* setters -------------------------------------------------------------- */ /* getters -------------------------------------------------------------- */ @@ -181,7 +184,8 @@ namespace ntt { const std::vector g_species_params; #if defined(OUTPUT_ENABLED) - out::Writer g_writer; + out::Writer g_writer; + checkpoint::Writer g_checkpoint_writer; #endif #if defined(MPI_ENABLED) diff --git a/src/framework/parameters.cpp b/src/framework/parameters.cpp index 8926b6453..e161c8ad5 100644 --- a/src/framework/parameters.cpp +++ b/src/framework/parameters.cpp @@ -8,6 +8,7 @@ #include "utils/formatting.h" #include "utils/log.h" #include "utils/numeric.h" +#include "utils/toml.h" #include "metrics/kerr_schild.h" #include "metrics/kerr_schild_0.h" @@ -18,8 +19,6 @@ #include "framework/containers/species.h" -#include - #if defined(MPI_ENABLED) #include #endif @@ -46,15 +45,15 @@ namespace ntt { return { dx0, V0 }; } - SimulationParams::SimulationParams(const toml::value& raw_data) { + SimulationParams::SimulationParams(const toml::value& toml_data) + : raw_data { toml_data } { /* [simulation] --------------------------------------------------------- */ set("simulation.name", toml::find(raw_data, "simulation", "name")); set("simulation.runtime", toml::find(raw_data, "simulation", "runtime")); - const auto engine = fmt::toLower( - toml::find(raw_data, "simulation", "engine")); - const auto engine_enum = SimEngine::pick(engine.c_str()); + const auto engine_enum = SimEngine::pick( + fmt::toLower(toml::find(toml_data, "simulation", "engine")).c_str()); set("simulation.engine", engine_enum); int default_ndomains = 1; @@ -79,7 +78,7 @@ namespace ntt { promiseToDefine("simulation.domain.decomposition"); /* [grid] --------------------------------------------------------------- */ - const auto res = toml::find>(raw_data, + const auto res = toml::find>(toml_data, "grid", "resolution"); raise::ErrorIf(res.size() < 1 || res.size() > 3, @@ -107,17 +106,18 @@ namespace ntt { promiseToDefine("grid.extent"); /* [grid.metric] -------------------------------------------------------- */ - const auto metric = fmt::toLower( - toml::find(raw_data, "grid", "metric", "metric")); - const auto metric_enum = Metric::pick(metric.c_str()); + const auto metric_enum = Metric::pick( + fmt::toLower(toml::find(toml_data, "grid", "metric", "metric")) + .c_str()); promiseToDefine("grid.metric.metric"); std::string coord; - if (metric == "minkowski") { + if (metric_enum == Metric::Minkowski) { raise::ErrorIf(engine_enum != SimEngine::SRPIC, "minkowski metric is only supported for SRPIC", HERE); coord = "cart"; - } else if (metric[0] == 'q') { + } else if (metric_enum == Metric::QKerr_Schild or + metric_enum == Metric::QSpherical) { // quasi-spherical geometry raise::ErrorIf(dim == Dim::_1D, "not enough dimensions for qspherical geometry", diff --git a/src/framework/parameters.h b/src/framework/parameters.h index 301f7053f..afa730bcd 100644 --- a/src/framework/parameters.h +++ b/src/framework/parameters.h @@ -18,22 +18,31 @@ #define FRAMEWORK_PARAMETERS_H #include "utils/param_container.h" - -#include +#include "utils/toml.h" namespace ntt { struct SimulationParams : public prm::Parameters { + SimulationParams() = default; SimulationParams(const toml::value&); SimulationParams& operator=(const SimulationParams& other) { vars = std::move(other.vars); promises = std::move(other.promises); + raw_data = std::move(other.raw_data); return *this; } ~SimulationParams() = default; + + [[nodiscard]] + auto data() const -> const toml::value& { + return raw_data; + } + + private: + toml::value raw_data; }; } // namespace ntt diff --git a/src/framework/simulation.cpp b/src/framework/simulation.cpp index b913379b4..7cf989872 100644 --- a/src/framework/simulation.cpp +++ b/src/framework/simulation.cpp @@ -1,17 +1,17 @@ #include "framework/simulation.h" #include "defaults.h" +#include "enums.h" #include "global.h" #include "utils/cargs.h" #include "utils/error.h" #include "utils/formatting.h" #include "utils/plog.h" +#include "utils/toml.h" #include "framework/parameters.h" -#include - #include namespace ntt { @@ -26,15 +26,27 @@ namespace ntt { const auto outputdir = static_cast( cl_args.getArgument("-output", defaults::output_path)); - const auto inputdata = toml::parse(inputfname); - const auto sim_name = toml::find(inputdata, "simulation", "name"); + raw_params = toml::parse(inputfname); + const auto sim_name = toml::find(raw_params, "simulation", "name"); logger::initPlog(sim_name); - params = SimulationParams(inputdata); + m_requested_engine = SimEngine::pick( + fmt::toLower(toml::find(raw_params, "simulation", "engine")).c_str()); + m_requested_metric = Metric::pick( + fmt::toLower(toml::find(raw_params, "grid", "metric", "metric")) + .c_str()); + + const auto res = toml::find>(raw_params, + "grid", + "resolution"); + raise::ErrorIf(res.size() < 1 || res.size() > 3, + "invalid `grid.resolution`", + HERE); + m_requested_dimension = static_cast(res.size()); } Simulation::~Simulation() { GlobalFinalize(); } -} // namespace ntt \ No newline at end of file +} // namespace ntt diff --git a/src/framework/simulation.h b/src/framework/simulation.h index 2f4d3d321..c069aa484 100644 --- a/src/framework/simulation.h +++ b/src/framework/simulation.h @@ -18,6 +18,7 @@ #include "arch/traits.h" #include "utils/error.h" +#include "utils/toml.h" #include "framework/parameters.h" @@ -27,7 +28,11 @@ namespace ntt { class Simulation { - SimulationParams params; + toml::value raw_params; + + Dimension m_requested_dimension; + SimEngine m_requested_engine { SimEngine::INVALID }; + Metric m_requested_metric { Metric::INVALID }; public: Simulation(int argc, char* argv[]); @@ -41,7 +46,7 @@ namespace ntt { static_assert(traits::has_method::value, "Engine must contain a ::run() method"); try { - engine_t engine { params }; + engine_t engine { raw_params }; engine.run(); } catch (const std::exception& e) { raise::Fatal(e.what(), HERE); @@ -50,17 +55,17 @@ namespace ntt { [[nodiscard]] inline auto requested_dimension() const -> Dimension { - return params.get("grid.dim"); + return m_requested_dimension; } [[nodiscard]] inline auto requested_engine() const -> SimEngine { - return params.get("simulation.engine"); + return m_requested_engine; } [[nodiscard]] inline auto requested_metric() const -> Metric { - return params.get("grid.metric.metric"); + return m_requested_metric; } }; diff --git a/src/framework/tests/parameters.cpp b/src/framework/tests/parameters.cpp index 8f02d1750..9c80554cd 100644 --- a/src/framework/tests/parameters.cpp +++ b/src/framework/tests/parameters.cpp @@ -5,11 +5,11 @@ #include "utils/comparators.h" #include "utils/error.h" +#include "utils/toml.h" #include "framework/containers/species.h" #include -#include #include #include diff --git a/src/global/CMakeLists.txt b/src/global/CMakeLists.txt index d00689283..f8bd7ab07 100644 --- a/src/global/CMakeLists.txt +++ b/src/global/CMakeLists.txt @@ -4,6 +4,7 @@ # - global.cpp # - arch/kokkos_aliases.cpp # - utils/cargs.cpp +# - utils/param_container.cpp # @includes: # - ./ # @uses: @@ -18,9 +19,12 @@ set(SOURCES ${SRC_DIR}/arch/kokkos_aliases.cpp ${SRC_DIR}/utils/cargs.cpp ) +if (${output}) + list(APPEND SOURCES ${SRC_DIR}/utils/param_container.cpp) +endif() add_library(ntt_global ${SOURCES}) target_include_directories(ntt_global PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} INTERFACE ${CMAKE_CURRENT_SOURCE_DIR} ) -target_link_libraries(ntt_global PRIVATE stdc++fs) \ No newline at end of file +target_link_libraries(ntt_global PRIVATE stdc++fs) diff --git a/src/global/defaults.h b/src/global/defaults.h index fb874481e..b9eca9080 100644 --- a/src/global/defaults.h +++ b/src/global/defaults.h @@ -62,7 +62,7 @@ namespace ntt::defaults { namespace checkpoint { const std::size_t interval = 1000; - const std::size_t keep = 2; + const int keep = 2; } // namespace checkpoint namespace diag { diff --git a/src/global/global.h b/src/global/global.h index ca067d547..b3f640295 100644 --- a/src/global/global.h +++ b/src/global/global.h @@ -204,17 +204,18 @@ typedef int PrepareOutputFlags; namespace Timer { enum TimerFlags_ { - None = 0, - PrintRelative = 1 << 0, - PrintUnits = 1 << 1, - PrintIndents = 1 << 2, - PrintTotal = 1 << 3, - PrintTitle = 1 << 4, - AutoConvert = 1 << 5, - Colorful = 1 << 6, - PrintOutput = 1 << 7, - PrintSorting = 1 << 8, - Default = PrintRelative | PrintUnits | PrintIndents | PrintTotal | + None = 0, + PrintRelative = 1 << 0, + PrintUnits = 1 << 1, + PrintIndents = 1 << 2, + PrintTotal = 1 << 3, + PrintTitle = 1 << 4, + AutoConvert = 1 << 5, + Colorful = 1 << 6, + PrintOutput = 1 << 7, + PrintSorting = 1 << 8, + PrintCheckpoint = 1 << 9, + Default = PrintRelative | PrintUnits | PrintIndents | PrintTotal | PrintTitle | AutoConvert | Colorful, }; } // namespace Timer diff --git a/src/global/utils/param_container.cpp b/src/global/utils/param_container.cpp new file mode 100644 index 000000000..6e4f5e0f4 --- /dev/null +++ b/src/global/utils/param_container.cpp @@ -0,0 +1,333 @@ +#if defined(OUTPUT_ENABLED) + #include "utils/param_container.h" + + #include "enums.h" + #include "global.h" + + #include + #include + + #include + #include + #include + #include + #include + #include + #include + #include + #include + +namespace prm { + template + struct has_to_string : std::false_type {}; + + template + struct has_to_string().to_string())>> + : std::true_type {}; + + template + auto write(adios2::IO& io, const std::string& name, T var) -> + typename std::enable_if::value, void>::type { + io.DefineAttribute(name, std::string(var.to_string())); + } + + template + auto write(adios2::IO& io, const std::string& name, T var) + -> decltype(void(T()), void()) { + io.DefineAttribute(name, var); + } + + template <> + void write(adios2::IO& io, const std::string& name, bool var) { + io.DefineAttribute(name, var ? 1 : 0); + } + + template <> + void write(adios2::IO& io, const std::string& name, Dimension var) { + io.DefineAttribute(name, (unsigned short)var); + } + + template + auto write_pair(adios2::IO& io, const std::string& name, std::pair var) + -> typename std::enable_if::value, void>::type { + std::vector var_str; + var_str.push_back(var.first.to_string()); + var_str.push_back(var.second.to_string()); + io.DefineAttribute(name, var_str.data(), var_str.size()); + } + + template + auto write_pair(adios2::IO& io, const std::string& name, std::pair var) + -> decltype(void(T()), void()) { + std::vector var_vec; + var_vec.push_back(var.first); + var_vec.push_back(var.second); + io.DefineAttribute(name, var_vec.data(), var_vec.size()); + } + + template + auto write_vec(adios2::IO& io, const std::string& name, std::vector var) -> + typename std::enable_if::value, void>::type { + std::vector var_str; + for (const auto& v : var) { + var_str.push_back(v.to_string()); + } + io.DefineAttribute(name, var_str.data(), var_str.size()); + } + + template + auto write_vec(adios2::IO& io, const std::string& name, std::vector var) + -> decltype(void(T()), void()) { + io.DefineAttribute(name, var.data(), var.size()); + } + + template + auto write_vec_pair(adios2::IO& io, + const std::string& name, + std::vector> var) -> + typename std::enable_if::value, void>::type { + std::vector var_str; + for (const auto& v : var) { + var_str.push_back(v.first.to_string()); + var_str.push_back(v.second.to_string()); + } + io.DefineAttribute(name, var_str.data(), var_str.size()); + } + + template + auto write_vec_pair(adios2::IO& io, + const std::string& name, + std::vector> var) + -> decltype(void(T()), void()) { + std::vector var_vec; + for (const auto& v : var) { + var_vec.push_back(v.first); + var_vec.push_back(v.second); + } + io.DefineAttribute(name, var_vec.data(), var_vec.size()); + } + + template + auto write_vec_vec(adios2::IO& io, + const std::string& name, + std::vector> var) -> + typename std::enable_if::value, void>::type { + std::vector var_str; + for (const auto& vec : var) { + for (const auto& v : vec) { + var_str.push_back(v.to_string()); + } + } + io.DefineAttribute(name, var_str.data(), var_str.size()); + } + + template + auto write_vec_vec(adios2::IO& io, + const std::string& name, + std::vector> var) + -> decltype(void(T()), void()) { + std::vector var_vec; + for (const auto& vec : var) { + for (const auto& v : vec) { + var_vec.push_back(v); + } + } + io.DefineAttribute(name, var_vec.data(), var_vec.size()); + } + + template + auto write_dict(adios2::IO& io, + const std::string& name, + std::map var) -> + typename std::enable_if::value, void>::type { + for (const auto& [key, v] : var) { + io.DefineAttribute(name + "_" + key, v.to_string()); + } + } + + template + auto write_dict(adios2::IO& io, + const std::string& name, + std::map var) -> decltype(void(T()), void()) { + for (const auto& [key, v] : var) { + io.DefineAttribute(name + "_" + key, v); + } + } + + std::map> + write_functions; + + template + void register_write_function() { + write_functions[std::type_index(typeid(T))] = + [](adios2::IO& io, const std::string& name, std::any a) { + write(io, name, std::any_cast(a)); + }; + } + + template + void register_write_function_for_pair() { + write_functions[std::type_index(typeid(std::pair))] = + [](adios2::IO& io, const std::string& name, std::any a) { + write_pair(io, name, std::any_cast>(a)); + }; + } + + template + void register_write_function_for_vector() { + write_functions[std::type_index(typeid(std::vector))] = + [](adios2::IO& io, const std::string& name, std::any a) { + write_vec(io, name, std::any_cast>(a)); + }; + } + + template + void register_write_function_for_vector_of_pair() { + write_functions[std::type_index(typeid(std::vector>))] = + [](adios2::IO& io, const std::string& name, std::any a) { + write_vec_pair(io, name, std::any_cast>>(a)); + }; + } + + template + void register_write_function_for_vector_of_vector() { + write_functions[std::type_index(typeid(std::vector>))] = + [](adios2::IO& io, const std::string& name, std::any a) { + write_vec_vec(io, name, std::any_cast>>(a)); + }; + } + + template + void register_write_function_for_dict() { + write_functions[std::type_index(typeid(std::map))] = + [](adios2::IO& io, const std::string& name, std::any a) { + write_dict(io, name, std::any_cast>(a)); + }; + } + + void write_any(adios2::IO& io, const std::string& name, std::any a) { + auto it = write_functions.find(a.type()); + if (it != write_functions.end()) { + it->second(io, name, a); + } else { + throw std::runtime_error("No write function registered for this type"); + } + } + + void Parameters::write(adios2::IO& io) const { + register_write_function(); + register_write_function(); + register_write_function(); + register_write_function(); + register_write_function(); + register_write_function(); + register_write_function(); + register_write_function(); + register_write_function(); + register_write_function(); + register_write_function(); + register_write_function(); + register_write_function(); + register_write_function(); + register_write_function(); + register_write_function(); + register_write_function(); + register_write_function(); + register_write_function(); + + register_write_function_for_pair(); + register_write_function_for_pair(); + register_write_function_for_pair(); + register_write_function_for_pair(); + register_write_function_for_pair(); + register_write_function_for_pair(); + register_write_function_for_pair(); + register_write_function_for_pair(); + register_write_function_for_pair(); + register_write_function_for_pair(); + register_write_function_for_pair(); + register_write_function_for_pair(); + register_write_function_for_pair(); + register_write_function_for_pair(); + register_write_function_for_pair(); + register_write_function_for_pair(); + register_write_function_for_pair(); + + register_write_function_for_vector(); + register_write_function_for_vector(); + register_write_function_for_vector(); + register_write_function_for_vector(); + register_write_function_for_vector(); + register_write_function_for_vector(); + register_write_function_for_vector(); + register_write_function_for_vector(); + register_write_function_for_vector(); + register_write_function_for_vector(); + register_write_function_for_vector(); + register_write_function_for_vector(); + register_write_function_for_vector(); + register_write_function_for_vector(); + register_write_function_for_vector(); + register_write_function_for_vector(); + register_write_function_for_vector(); + + register_write_function_for_vector_of_pair(); + register_write_function_for_vector_of_pair(); + register_write_function_for_vector_of_pair(); + register_write_function_for_vector_of_pair(); + register_write_function_for_vector_of_pair(); + register_write_function_for_vector_of_pair(); + register_write_function_for_vector_of_pair(); + register_write_function_for_vector_of_pair(); + register_write_function_for_vector_of_pair(); + register_write_function_for_vector_of_pair(); + register_write_function_for_vector_of_pair(); + register_write_function_for_vector_of_pair(); + register_write_function_for_vector_of_pair(); + register_write_function_for_vector_of_pair(); + register_write_function_for_vector_of_pair(); + register_write_function_for_vector_of_pair(); + register_write_function_for_vector_of_pair(); + + register_write_function_for_vector_of_vector(); + register_write_function_for_vector_of_vector(); + register_write_function_for_vector_of_vector(); + register_write_function_for_vector_of_vector(); + register_write_function_for_vector_of_vector(); + register_write_function_for_vector_of_vector(); + register_write_function_for_vector_of_vector(); + register_write_function_for_vector_of_vector(); + register_write_function_for_vector_of_vector(); + register_write_function_for_vector_of_vector(); + register_write_function_for_vector_of_vector(); + register_write_function_for_vector_of_vector(); + register_write_function_for_vector_of_vector(); + register_write_function_for_vector_of_vector(); + register_write_function_for_vector_of_vector(); + register_write_function_for_vector_of_vector(); + register_write_function_for_vector_of_vector(); + + register_write_function_for_dict(); + register_write_function_for_dict(); + register_write_function_for_dict(); + register_write_function_for_dict(); + register_write_function_for_dict(); + register_write_function_for_dict(); + register_write_function_for_dict(); + register_write_function_for_dict(); + register_write_function_for_dict(); + register_write_function_for_dict(); + register_write_function_for_dict(); + + for (auto& [key, value] : allVars()) { + try { + write_any(io, key, value); + } catch (const std::exception& e) { + continue; + } + } + } + +} // namespace prm + +#endif diff --git a/src/global/utils/param_container.h b/src/global/utils/param_container.h index dccf91d09..679b80552 100644 --- a/src/global/utils/param_container.h +++ b/src/global/utils/param_container.h @@ -16,6 +16,11 @@ #include "utils/formatting.h" #include "utils/log.h" +#if defined(OUTPUT_ENABLED) + #include + #include +#endif + #include #include #include @@ -172,6 +177,10 @@ namespace prm { } return result.str(); } + +#if defined(OUTPUT_ENABLED) + void write(adios2::IO& io) const; +#endif }; } // namespace prm diff --git a/src/global/utils/timer.h b/src/global/utils/timer.h index 79f325f0e..84356f7b3 100644 --- a/src/global/utils/timer.h +++ b/src/global/utils/timer.h @@ -118,7 +118,11 @@ namespace timer { void printAll(const TimerFlags flags = Timer::Default, std::ostream& os = std::cout) const { +#if !defined(MPI_ENABLED) std::string header = fmt::format("%s %27s", "[SUBSTEP]", "[DURATION]"); +#else + std::string header = fmt::format("%s %32s", "[SUBSTEP]", "[DURATION]"); +#endif const auto c_bblack = color::get_color("bblack", flags & Timer::Colorful); const auto c_reset = color::get_color("reset", flags & Timer::Colorful); @@ -162,7 +166,7 @@ namespace timer { for (auto& [name, timer] : m_timers) { auto timers = mpi_timers[name]; long double tot = std::accumulate(timers.begin(), timers.end(), 0.0); - if (name != "Output") { + if (name != "Output" and name != "Checkpoint") { total += tot; } } @@ -214,12 +218,12 @@ namespace timer { #else // not MPI_ENABLED long double total = 0.0; for (auto& [name, timer] : m_timers) { - if (name != "Output") { + if (name != "Output" and name != "Checkpoint") { total += timer.second; } } for (auto& [name, timer] : m_timers) { - if (name == "Output") { + if (name == "Output" or name == "Checkpoint") { continue; } std::string units = "µs"; @@ -257,8 +261,13 @@ namespace timer { if (flags & Timer::AutoConvert) { convertTime(value, units); } +#if !defined(MPI_ENABLED) os << c_bblack << std::setw(22) << std::left << std::setfill(' ') << "Total" << c_reset; +#else + os << c_bblack << std::setw(27) << std::left << std::setfill(' ') + << "Total" << c_reset; +#endif os << c_blue << std::setw(12) << std::right << std::setfill(' ') << value; if (flags & Timer::PrintUnits) { os << " " << units; @@ -283,6 +292,25 @@ namespace timer { } os << c_reset << std::endl; } + { + std::string units = "µs"; + auto value = get("Checkpoint"); + if (flags & Timer::AutoConvert) { + convertTime(value, units); + } + os << ((flags & Timer::PrintCheckpoint) ? c_reset : c_bblack) + << "Checkpoint" << c_bblack + << fmt::pad("Checkpoint", 22, '.', true).substr(10, 22); + os << std::setw(17) << std::right << std::setfill('.') + << fmt::format("%s%.2Lf", + (flags & Timer::PrintCheckpoint) ? c_byellow.c_str() + : c_bblack.c_str(), + value); + if (flags & Timer::PrintUnits) { + os << " " << units; + } + os << c_reset << std::endl; + } } }; } // namespace timer diff --git a/src/global/utils/toml.h b/src/global/utils/toml.h new file mode 100644 index 000000000..b621f5839 --- /dev/null +++ b/src/global/utils/toml.h @@ -0,0 +1,17972 @@ +#ifndef TOML11_VERSION_HPP +#define TOML11_VERSION_HPP + +#define TOML11_VERSION_MAJOR 4 +#define TOML11_VERSION_MINOR 1 +#define TOML11_VERSION_PATCH 0 + +#ifndef __cplusplus + #error "__cplusplus is not defined" +#endif + +// Since MSVC does not define `__cplusplus` correctly unless you pass +// `/Zc:__cplusplus` when compiling, the workaround macros are added. +// +// The value of `__cplusplus` macro is defined in the C++ standard spec, but +// MSVC ignores the value, maybe because of backward compatibility. Instead, +// MSVC defines _MSVC_LANG that has the same value as __cplusplus defined in +// the C++ standard. So we check if _MSVC_LANG is defined before using `__cplusplus`. +// +// FYI: https://docs.microsoft.com/en-us/cpp/build/reference/zc-cplusplus?view=msvc-170 +// https://docs.microsoft.com/en-us/cpp/preprocessor/predefined-macros?view=msvc-170 +// + +#if defined(_MSVC_LANG) && defined(_MSC_VER) && 190024210 <= _MSC_FULL_VER + #define TOML11_CPLUSPLUS_STANDARD_VERSION _MSVC_LANG +#else + #define TOML11_CPLUSPLUS_STANDARD_VERSION __cplusplus +#endif + +#if TOML11_CPLUSPLUS_STANDARD_VERSION < 201103L + #error "toml11 requires C++11 or later." +#endif + +#if !defined(__has_include) + #define __has_include(x) 0 +#endif + +#if !defined(__has_cpp_attribute) + #define __has_cpp_attribute(x) 0 +#endif + +#if !defined(__has_builtin) + #define __has_builtin(x) 0 +#endif + +// hard to remember + +#ifndef TOML11_CXX14_VALUE + #define TOML11_CXX14_VALUE 201402L +#endif // TOML11_CXX14_VALUE + +#ifndef TOML11_CXX17_VALUE + #define TOML11_CXX17_VALUE 201703L +#endif // TOML11_CXX17_VALUE + +#ifndef TOML11_CXX20_VALUE + #define TOML11_CXX20_VALUE 202002L +#endif // TOML11_CXX20_VALUE + +#if defined(__cpp_char8_t) + #if __cpp_char8_t >= 201811L + #define TOML11_HAS_CHAR8_T 1 + #endif +#endif + +#if TOML11_CPLUSPLUS_STANDARD_VERSION >= TOML11_CXX17_VALUE + #if __has_include() + #define TOML11_HAS_STRING_VIEW 1 + #endif +#endif + +#ifndef TOML11_DISABLE_STD_FILESYSTEM + #if TOML11_CPLUSPLUS_STANDARD_VERSION >= TOML11_CXX17_VALUE + #if __has_include() + #define TOML11_HAS_FILESYSTEM 1 + #endif + #endif +#endif + +#if TOML11_CPLUSPLUS_STANDARD_VERSION >= TOML11_CXX17_VALUE + #if __has_include() + #define TOML11_HAS_OPTIONAL 1 + #endif +#endif + +#if defined(TOML11_COMPILE_SOURCES) + #define TOML11_INLINE +#else + #define TOML11_INLINE inline +#endif + +namespace toml { + + inline const char* license_notice() noexcept { + return R"(The MIT License (MIT) + +Copyright (c) 2017-now Toru Niina + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE.)"; + } + +} // namespace toml +#endif // TOML11_VERSION_HPP +#ifndef TOML11_FORMAT_HPP +#define TOML11_FORMAT_HPP + +#ifndef TOML11_FORMAT_FWD_HPP + #define TOML11_FORMAT_FWD_HPP + + #include + #include + #include + #include + #include + +namespace toml { + + // toml types with serialization info + + enum class indent_char : std::uint8_t { + space, // use space + tab, // use tab + none // no indent + }; + + std::ostream& operator<<(std::ostream& os, const indent_char& c); + std::string to_string(const indent_char c); + + // ---------------------------------------------------------------------------- + // boolean + + struct boolean_format_info { + // nothing, for now + }; + + inline bool operator==(const boolean_format_info&, + const boolean_format_info&) noexcept { + return true; + } + + inline bool operator!=(const boolean_format_info&, + const boolean_format_info&) noexcept { + return false; + } + + // ---------------------------------------------------------------------------- + // integer + + enum class integer_format : std::uint8_t { + dec = 0, + bin = 1, + oct = 2, + hex = 3, + }; + + std::ostream& operator<<(std::ostream& os, const integer_format f); + std::string to_string(const integer_format); + + struct integer_format_info { + integer_format fmt = integer_format::dec; + bool uppercase = true; // hex with uppercase + std::size_t width = 0; // minimal width (may exceed) + std::size_t spacer = 0; // position of `_` (if 0, no spacer) + std::string suffix = ""; // _suffix (library extension) + }; + + bool operator==(const integer_format_info&, const integer_format_info&) noexcept; + bool operator!=(const integer_format_info&, const integer_format_info&) noexcept; + + // ---------------------------------------------------------------------------- + // floating + + enum class floating_format : std::uint8_t { + defaultfloat = 0, + fixed = 1, // does not include exponential part + scientific = 2, // always include exponential part + hex = 3 // hexfloat extension + }; + + std::ostream& operator<<(std::ostream& os, const floating_format f); + std::string to_string(const floating_format); + + struct floating_format_info { + floating_format fmt = floating_format::defaultfloat; + std::size_t prec = 0; // precision (if 0, use the default) + std::string suffix = ""; // 1.0e+2_suffix (library extension) + }; + + bool operator==(const floating_format_info&, const floating_format_info&) noexcept; + bool operator!=(const floating_format_info&, const floating_format_info&) noexcept; + + // ---------------------------------------------------------------------------- + // string + + enum class string_format : std::uint8_t { + basic = 0, + literal = 1, + multiline_basic = 2, + multiline_literal = 3 + }; + + std::ostream& operator<<(std::ostream& os, const string_format f); + std::string to_string(const string_format); + + struct string_format_info { + string_format fmt = string_format::basic; + bool start_with_newline = false; + }; + + bool operator==(const string_format_info&, const string_format_info&) noexcept; + bool operator!=(const string_format_info&, const string_format_info&) noexcept; + + // ---------------------------------------------------------------------------- + // datetime + + enum class datetime_delimiter_kind : std::uint8_t { + upper_T = 0, + lower_t = 1, + space = 2, + }; + std::ostream& operator<<(std::ostream& os, const datetime_delimiter_kind d); + std::string to_string(const datetime_delimiter_kind); + + struct offset_datetime_format_info { + datetime_delimiter_kind delimiter = datetime_delimiter_kind::upper_T; + bool has_seconds = true; + std::size_t subsecond_precision = 6; // [us] + }; + + bool operator==(const offset_datetime_format_info&, + const offset_datetime_format_info&) noexcept; + bool operator!=(const offset_datetime_format_info&, + const offset_datetime_format_info&) noexcept; + + struct local_datetime_format_info { + datetime_delimiter_kind delimiter = datetime_delimiter_kind::upper_T; + bool has_seconds = true; + std::size_t subsecond_precision = 6; // [us] + }; + + bool operator==(const local_datetime_format_info&, + const local_datetime_format_info&) noexcept; + bool operator!=(const local_datetime_format_info&, + const local_datetime_format_info&) noexcept; + + struct local_date_format_info { + // nothing, for now + }; + + bool operator==(const local_date_format_info&, + const local_date_format_info&) noexcept; + bool operator!=(const local_date_format_info&, + const local_date_format_info&) noexcept; + + struct local_time_format_info { + bool has_seconds = true; + std::size_t subsecond_precision = 6; // [us] + }; + + bool operator==(const local_time_format_info&, + const local_time_format_info&) noexcept; + bool operator!=(const local_time_format_info&, + const local_time_format_info&) noexcept; + + // ---------------------------------------------------------------------------- + // array + + enum class array_format : std::uint8_t { + default_format = 0, + oneline = 1, + multiline = 2, + array_of_tables = 3 // [[format.in.this.way]] + }; + + std::ostream& operator<<(std::ostream& os, const array_format f); + std::string to_string(const array_format); + + struct array_format_info { + array_format fmt = array_format::default_format; + indent_char indent_type = indent_char::space; + std::int32_t body_indent = 4; // indent in case of multiline + std::int32_t closing_indent = 0; // indent of `]` + }; + + bool operator==(const array_format_info&, const array_format_info&) noexcept; + bool operator!=(const array_format_info&, const array_format_info&) noexcept; + + // ---------------------------------------------------------------------------- + // table + + enum class table_format : std::uint8_t { + multiline = 0, // [foo] \n bar = "baz" + oneline = 1, // foo = {bar = "baz"} + dotted = 2, // foo.bar = "baz" + multiline_oneline = 3, // foo = { \n bar = "baz" \n } + implicit = 4 // [x] defined by [x.y.z]. skip in serializer. + }; + + std::ostream& operator<<(std::ostream& os, const table_format f); + std::string to_string(const table_format); + + struct table_format_info { + table_format fmt = table_format::multiline; + indent_char indent_type = indent_char::space; + std::int32_t body_indent = 0; // indent of values + std::int32_t name_indent = 0; // indent of [table] + std::int32_t closing_indent = 0; // in case of {inline-table} + }; + + bool operator==(const table_format_info&, const table_format_info&) noexcept; + bool operator!=(const table_format_info&, const table_format_info&) noexcept; + + // ---------------------------------------------------------------------------- + // wrapper + + namespace detail { + template + struct value_with_format { + using value_type = T; + using format_type = F; + + value_with_format() = default; + ~value_with_format() = default; + value_with_format(const value_with_format&) = default; + value_with_format(value_with_format&&) = default; + value_with_format& operator=(const value_with_format&) = default; + value_with_format& operator=(value_with_format&&) = default; + + value_with_format(value_type v, format_type f) + : value { std::move(v) } + , format { std::move(f) } {} + + template + value_with_format(value_with_format other) + : value { std::move(other.value) } + , format { std::move(other.format) } {} + + value_type value; + format_type format; + }; + } // namespace detail + +} // namespace toml +#endif // TOML11_FORMAT_FWD_HPP + +#if !defined(TOML11_COMPILE_SOURCES) + #ifndef TOML11_FORMAT_IMPL_HPP + #define TOML11_FORMAT_IMPL_HPP + + #include + #include + +namespace toml { + + // toml types with serialization info + + TOML11_INLINE std::ostream& operator<<(std::ostream& os, const indent_char& c) { + switch (c) { + case indent_char::space: { + os << "space"; + break; + } + case indent_char::tab: { + os << "tab"; + break; + } + case indent_char::none: { + os << "none"; + break; + } + default: { + os << "unknown indent char: " << static_cast(c); + } + } + return os; + } + + TOML11_INLINE std::string to_string(const indent_char c) { + std::ostringstream oss; + oss << c; + return oss.str(); + } + + // ---------------------------------------------------------------------------- + // boolean + + // ---------------------------------------------------------------------------- + // integer + + TOML11_INLINE std::ostream& operator<<(std::ostream& os, const integer_format f) { + switch (f) { + case integer_format::dec: { + os << "dec"; + break; + } + case integer_format::bin: { + os << "bin"; + break; + } + case integer_format::oct: { + os << "oct"; + break; + } + case integer_format::hex: { + os << "hex"; + break; + } + default: { + os << "unknown integer_format: " << static_cast(f); + break; + } + } + return os; + } + + TOML11_INLINE std::string to_string(const integer_format c) { + std::ostringstream oss; + oss << c; + return oss.str(); + } + + TOML11_INLINE bool operator==(const integer_format_info& lhs, + const integer_format_info& rhs) noexcept { + return lhs.fmt == rhs.fmt && lhs.uppercase == rhs.uppercase && + lhs.width == rhs.width && lhs.spacer == rhs.spacer && + lhs.suffix == rhs.suffix; + } + + TOML11_INLINE bool operator!=(const integer_format_info& lhs, + const integer_format_info& rhs) noexcept { + return !(lhs == rhs); + } + + // ---------------------------------------------------------------------------- + // floating + + TOML11_INLINE std::ostream& operator<<(std::ostream& os, const floating_format f) { + switch (f) { + case floating_format::defaultfloat: { + os << "defaultfloat"; + break; + } + case floating_format::fixed: { + os << "fixed"; + break; + } + case floating_format::scientific: { + os << "scientific"; + break; + } + case floating_format::hex: { + os << "hex"; + break; + } + default: { + os << "unknown floating_format: " << static_cast(f); + break; + } + } + return os; + } + + TOML11_INLINE std::string to_string(const floating_format c) { + std::ostringstream oss; + oss << c; + return oss.str(); + } + + TOML11_INLINE bool operator==(const floating_format_info& lhs, + const floating_format_info& rhs) noexcept { + return lhs.fmt == rhs.fmt && lhs.prec == rhs.prec && lhs.suffix == rhs.suffix; + } + + TOML11_INLINE bool operator!=(const floating_format_info& lhs, + const floating_format_info& rhs) noexcept { + return !(lhs == rhs); + } + + // ---------------------------------------------------------------------------- + // string + + TOML11_INLINE std::ostream& operator<<(std::ostream& os, const string_format f) { + switch (f) { + case string_format::basic: { + os << "basic"; + break; + } + case string_format::literal: { + os << "literal"; + break; + } + case string_format::multiline_basic: { + os << "multiline_basic"; + break; + } + case string_format::multiline_literal: { + os << "multiline_literal"; + break; + } + default: { + os << "unknown string_format: " << static_cast(f); + break; + } + } + return os; + } + + TOML11_INLINE std::string to_string(const string_format c) { + std::ostringstream oss; + oss << c; + return oss.str(); + } + + TOML11_INLINE bool operator==(const string_format_info& lhs, + const string_format_info& rhs) noexcept { + return lhs.fmt == rhs.fmt && lhs.start_with_newline == rhs.start_with_newline; + } + + TOML11_INLINE bool operator!=(const string_format_info& lhs, + const string_format_info& rhs) noexcept { + return !(lhs == rhs); + } + + // ---------------------------------------------------------------------------- + // datetime + + TOML11_INLINE std::ostream& operator<<(std::ostream& os, + const datetime_delimiter_kind d) { + switch (d) { + case datetime_delimiter_kind::upper_T: { + os << "upper_T, "; + break; + } + case datetime_delimiter_kind::lower_t: { + os << "lower_t, "; + break; + } + case datetime_delimiter_kind::space: { + os << "space, "; + break; + } + default: { + os << "unknown datetime delimiter: " << static_cast(d); + break; + } + } + return os; + } + + TOML11_INLINE std::string to_string(const datetime_delimiter_kind c) { + std::ostringstream oss; + oss << c; + return oss.str(); + } + + TOML11_INLINE bool operator==(const offset_datetime_format_info& lhs, + const offset_datetime_format_info& rhs) noexcept { + return lhs.delimiter == rhs.delimiter && lhs.has_seconds == rhs.has_seconds && + lhs.subsecond_precision == rhs.subsecond_precision; + } + + TOML11_INLINE bool operator!=(const offset_datetime_format_info& lhs, + const offset_datetime_format_info& rhs) noexcept { + return !(lhs == rhs); + } + + TOML11_INLINE bool operator==(const local_datetime_format_info& lhs, + const local_datetime_format_info& rhs) noexcept { + return lhs.delimiter == rhs.delimiter && lhs.has_seconds == rhs.has_seconds && + lhs.subsecond_precision == rhs.subsecond_precision; + } + + TOML11_INLINE bool operator!=(const local_datetime_format_info& lhs, + const local_datetime_format_info& rhs) noexcept { + return !(lhs == rhs); + } + + TOML11_INLINE bool operator==(const local_date_format_info&, + const local_date_format_info&) noexcept { + return true; + } + + TOML11_INLINE bool operator!=(const local_date_format_info& lhs, + const local_date_format_info& rhs) noexcept { + return !(lhs == rhs); + } + + TOML11_INLINE bool operator==(const local_time_format_info& lhs, + const local_time_format_info& rhs) noexcept { + return lhs.has_seconds == rhs.has_seconds && + lhs.subsecond_precision == rhs.subsecond_precision; + } + + TOML11_INLINE bool operator!=(const local_time_format_info& lhs, + const local_time_format_info& rhs) noexcept { + return !(lhs == rhs); + } + + // ---------------------------------------------------------------------------- + // array + + TOML11_INLINE std::ostream& operator<<(std::ostream& os, const array_format f) { + switch (f) { + case array_format::default_format: { + os << "default_format"; + break; + } + case array_format::oneline: { + os << "oneline"; + break; + } + case array_format::multiline: { + os << "multiline"; + break; + } + case array_format::array_of_tables: { + os << "array_of_tables"; + break; + } + default: { + os << "unknown array_format: " << static_cast(f); + break; + } + } + return os; + } + + TOML11_INLINE std::string to_string(const array_format c) { + std::ostringstream oss; + oss << c; + return oss.str(); + } + + TOML11_INLINE bool operator==(const array_format_info& lhs, + const array_format_info& rhs) noexcept { + return lhs.fmt == rhs.fmt && lhs.indent_type == rhs.indent_type && + lhs.body_indent == rhs.body_indent && + lhs.closing_indent == rhs.closing_indent; + } + + TOML11_INLINE bool operator!=(const array_format_info& lhs, + const array_format_info& rhs) noexcept { + return !(lhs == rhs); + } + + // ---------------------------------------------------------------------------- + // table + + TOML11_INLINE std::ostream& operator<<(std::ostream& os, const table_format f) { + switch (f) { + case table_format::multiline: { + os << "multiline"; + break; + } + case table_format::oneline: { + os << "oneline"; + break; + } + case table_format::dotted: { + os << "dotted"; + break; + } + case table_format::multiline_oneline: { + os << "multiline_oneline"; + break; + } + case table_format::implicit: { + os << "implicit"; + break; + } + default: { + os << "unknown table_format: " << static_cast(f); + break; + } + } + return os; + } + + TOML11_INLINE std::string to_string(const table_format c) { + std::ostringstream oss; + oss << c; + return oss.str(); + } + + TOML11_INLINE bool operator==(const table_format_info& lhs, + const table_format_info& rhs) noexcept { + return lhs.fmt == rhs.fmt && lhs.indent_type == rhs.indent_type && + lhs.body_indent == rhs.body_indent && + lhs.name_indent == rhs.name_indent && + lhs.closing_indent == rhs.closing_indent; + } + + TOML11_INLINE bool operator!=(const table_format_info& lhs, + const table_format_info& rhs) noexcept { + return !(lhs == rhs); + } + +} // namespace toml + #endif // TOML11_FORMAT_IMPL_HPP +#endif + +#endif // TOML11_FORMAT_HPP +#ifndef TOML11_DATETIME_HPP +#define TOML11_DATETIME_HPP + +#ifndef TOML11_DATETIME_FWD_HPP + #define TOML11_DATETIME_FWD_HPP + + #include + #include + #include + #include + #include + #include + +namespace toml { + + enum class month_t : std::uint8_t { + Jan = 0, + Feb = 1, + Mar = 2, + Apr = 3, + May = 4, + Jun = 5, + Jul = 6, + Aug = 7, + Sep = 8, + Oct = 9, + Nov = 10, + Dec = 11 + }; + + // ---------------------------------------------------------------------------- + + struct local_date { + std::int16_t year { 0 }; // A.D. (like, 2018) + std::uint8_t month { 0 }; // [0, 11] + std::uint8_t day { 0 }; // [1, 31] + + local_date(int y, month_t m, int d) + : year { static_cast(y) } + , month { static_cast(m) } + , day { static_cast(d) } {} + + explicit local_date(const std::tm& t) + : year { static_cast(t.tm_year + 1900) } + , month { static_cast(t.tm_mon) } + , day { static_cast(t.tm_mday) } {} + + explicit local_date(const std::chrono::system_clock::time_point& tp); + explicit local_date(const std::time_t t); + + operator std::chrono::system_clock::time_point() const; + operator std::time_t() const; + + local_date() = default; + ~local_date() = default; + local_date(const local_date&) = default; + local_date(local_date&&) = default; + local_date& operator=(const local_date&) = default; + local_date& operator=(local_date&&) = default; + }; + + bool operator==(const local_date& lhs, const local_date& rhs); + bool operator!=(const local_date& lhs, const local_date& rhs); + bool operator<(const local_date& lhs, const local_date& rhs); + bool operator<=(const local_date& lhs, const local_date& rhs); + bool operator>(const local_date& lhs, const local_date& rhs); + bool operator>=(const local_date& lhs, const local_date& rhs); + + std::ostream& operator<<(std::ostream& os, const local_date& date); + std::string to_string(const local_date& date); + + // ----------------------------------------------------------------------------- + + struct local_time { + std::uint8_t hour { 0 }; // [0, 23] + std::uint8_t minute { 0 }; // [0, 59] + std::uint8_t second { 0 }; // [0, 60] + std::uint16_t millisecond { 0 }; // [0, 999] + std::uint16_t microsecond { 0 }; // [0, 999] + std::uint16_t nanosecond { 0 }; // [0, 999] + + local_time(int h, int m, int s, int ms = 0, int us = 0, int ns = 0) + : hour { static_cast(h) } + , minute { static_cast(m) } + , second { static_cast(s) } + , millisecond { static_cast(ms) } + , microsecond { static_cast(us) } + , nanosecond { static_cast(ns) } {} + + explicit local_time(const std::tm& t) + : hour { static_cast(t.tm_hour) } + , minute { static_cast(t.tm_min) } + , second { static_cast(t.tm_sec) } + , millisecond { 0 } + , microsecond { 0 } + , nanosecond { 0 } {} + + template + explicit local_time(const std::chrono::duration& t) { + const auto h = std::chrono::duration_cast(t); + this->hour = static_cast(h.count()); + const auto t2 = t - h; + const auto m = std::chrono::duration_cast(t2); + this->minute = static_cast(m.count()); + const auto t3 = t2 - m; + const auto s = std::chrono::duration_cast(t3); + this->second = static_cast(s.count()); + const auto t4 = t3 - s; + const auto ms = std::chrono::duration_cast(t4); + this->millisecond = static_cast(ms.count()); + const auto t5 = t4 - ms; + const auto us = std::chrono::duration_cast(t5); + this->microsecond = static_cast(us.count()); + const auto t6 = t5 - us; + const auto ns = std::chrono::duration_cast(t6); + this->nanosecond = static_cast(ns.count()); + } + + operator std::chrono::nanoseconds() const; + + local_time() = default; + ~local_time() = default; + local_time(const local_time&) = default; + local_time(local_time&&) = default; + local_time& operator=(const local_time&) = default; + local_time& operator=(local_time&&) = default; + }; + + bool operator==(const local_time& lhs, const local_time& rhs); + bool operator!=(const local_time& lhs, const local_time& rhs); + bool operator<(const local_time& lhs, const local_time& rhs); + bool operator<=(const local_time& lhs, const local_time& rhs); + bool operator>(const local_time& lhs, const local_time& rhs); + bool operator>=(const local_time& lhs, const local_time& rhs); + + std::ostream& operator<<(std::ostream& os, const local_time& time); + std::string to_string(const local_time& time); + + // ---------------------------------------------------------------------------- + + struct time_offset { + std::int8_t hour { 0 }; // [-12, 12] + std::int8_t minute { 0 }; // [-59, 59] + + time_offset(int h, int m) + : hour { static_cast(h) } + , minute { static_cast(m) } {} + + operator std::chrono::minutes() const; + + time_offset() = default; + ~time_offset() = default; + time_offset(const time_offset&) = default; + time_offset(time_offset&&) = default; + time_offset& operator=(const time_offset&) = default; + time_offset& operator=(time_offset&&) = default; + }; + + bool operator==(const time_offset& lhs, const time_offset& rhs); + bool operator!=(const time_offset& lhs, const time_offset& rhs); + bool operator<(const time_offset& lhs, const time_offset& rhs); + bool operator<=(const time_offset& lhs, const time_offset& rhs); + bool operator>(const time_offset& lhs, const time_offset& rhs); + bool operator>=(const time_offset& lhs, const time_offset& rhs); + + std::ostream& operator<<(std::ostream& os, const time_offset& offset); + + std::string to_string(const time_offset& offset); + + // ----------------------------------------------------------------------------- + + struct local_datetime { + local_date date {}; + local_time time {}; + + local_datetime(local_date d, local_time t) : date { d }, time { t } {} + + explicit local_datetime(const std::tm& t) : date { t }, time { t } {} + + explicit local_datetime(const std::chrono::system_clock::time_point& tp); + explicit local_datetime(const std::time_t t); + + operator std::chrono::system_clock::time_point() const; + operator std::time_t() const; + + local_datetime() = default; + ~local_datetime() = default; + local_datetime(const local_datetime&) = default; + local_datetime(local_datetime&&) = default; + local_datetime& operator=(const local_datetime&) = default; + local_datetime& operator=(local_datetime&&) = default; + }; + + bool operator==(const local_datetime& lhs, const local_datetime& rhs); + bool operator!=(const local_datetime& lhs, const local_datetime& rhs); + bool operator<(const local_datetime& lhs, const local_datetime& rhs); + bool operator<=(const local_datetime& lhs, const local_datetime& rhs); + bool operator>(const local_datetime& lhs, const local_datetime& rhs); + bool operator>=(const local_datetime& lhs, const local_datetime& rhs); + + std::ostream& operator<<(std::ostream& os, const local_datetime& dt); + + std::string to_string(const local_datetime& dt); + + // ----------------------------------------------------------------------------- + + struct offset_datetime { + local_date date {}; + local_time time {}; + time_offset offset {}; + + offset_datetime(local_date d, local_time t, time_offset o) + : date { d } + , time { t } + , offset { o } {} + + offset_datetime(const local_datetime& dt, time_offset o) + : date { dt.date } + , time { dt.time } + , offset { o } {} + + // use the current local timezone offset + explicit offset_datetime(const local_datetime& ld); + explicit offset_datetime(const std::chrono::system_clock::time_point& tp); + explicit offset_datetime(const std::time_t& t); + explicit offset_datetime(const std::tm& t); + + operator std::chrono::system_clock::time_point() const; + + operator std::time_t() const; + + offset_datetime() = default; + ~offset_datetime() = default; + offset_datetime(const offset_datetime&) = default; + offset_datetime(offset_datetime&&) = default; + offset_datetime& operator=(const offset_datetime&) = default; + offset_datetime& operator=(offset_datetime&&) = default; + + private: + static time_offset get_local_offset(const std::time_t* tp); + }; + + bool operator==(const offset_datetime& lhs, const offset_datetime& rhs); + bool operator!=(const offset_datetime& lhs, const offset_datetime& rhs); + bool operator<(const offset_datetime& lhs, const offset_datetime& rhs); + bool operator<=(const offset_datetime& lhs, const offset_datetime& rhs); + bool operator>(const offset_datetime& lhs, const offset_datetime& rhs); + bool operator>=(const offset_datetime& lhs, const offset_datetime& rhs); + + std::ostream& operator<<(std::ostream& os, const offset_datetime& dt); + + std::string to_string(const offset_datetime& dt); + +} // namespace toml +#endif // TOML11_DATETIME_FWD_HPP + +#if !defined(TOML11_COMPILE_SOURCES) + #ifndef TOML11_DATETIME_IMPL_HPP + #define TOML11_DATETIME_IMPL_HPP + + #include + #include + #include + #include + #include + #include + #include + +namespace toml { + + // To avoid non-threadsafe std::localtime. In C11 (not C++11!), localtime_s is + // provided in the absolutely same purpose, but C++11 is actually not + // compatible with C11. We need to dispatch the function depending on the OS. + namespace detail { + // TODO: find more sophisticated way to handle this + #if defined(_MSC_VER) + TOML11_INLINE std::tm localtime_s(const std::time_t* src) { + std::tm dst; + const auto result = ::localtime_s(&dst, src); + if (result) { + throw std::runtime_error("localtime_s failed."); + } + return dst; + } + + TOML11_INLINE std::tm gmtime_s(const std::time_t* src) { + std::tm dst; + const auto result = ::gmtime_s(&dst, src); + if (result) { + throw std::runtime_error("gmtime_s failed."); + } + return dst; + } + #elif (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 1) || \ + defined(_XOPEN_SOURCE) || defined(_BSD_SOURCE) || \ + defined(_SVID_SOURCE) || defined(_POSIX_SOURCE) + TOML11_INLINE std::tm localtime_s(const std::time_t* src) { + std::tm dst; + const auto result = ::localtime_r(src, &dst); + if (!result) { + throw std::runtime_error("localtime_r failed."); + } + return dst; + } + + TOML11_INLINE std::tm gmtime_s(const std::time_t* src) { + std::tm dst; + const auto result = ::gmtime_r(src, &dst); + if (!result) { + throw std::runtime_error("gmtime_r failed."); + } + return dst; + } + #else // fallback. not threadsafe + TOML11_INLINE std::tm localtime_s(const std::time_t* src) { + const auto result = std::localtime(src); + if (!result) { + throw std::runtime_error("localtime failed."); + } + return *result; + } + + TOML11_INLINE std::tm gmtime_s(const std::time_t* src) { + const auto result = std::gmtime(src); + if (!result) { + throw std::runtime_error("gmtime failed."); + } + return *result; + } + #endif + } // namespace detail + + // ---------------------------------------------------------------------------- + + TOML11_INLINE local_date::local_date( + const std::chrono::system_clock::time_point& tp) { + const auto t = std::chrono::system_clock::to_time_t(tp); + const auto time = detail::localtime_s(&t); + *this = local_date(time); + } + + TOML11_INLINE local_date::local_date(const std::time_t t) + : local_date { std::chrono::system_clock::from_time_t(t) } {} + + TOML11_INLINE local_date::operator std::chrono::system_clock::time_point() const { + // std::mktime returns date as local time zone. no conversion needed + std::tm t; + t.tm_sec = 0; + t.tm_min = 0; + t.tm_hour = 0; + t.tm_mday = static_cast(this->day); + t.tm_mon = static_cast(this->month); + t.tm_year = static_cast(this->year) - 1900; + t.tm_wday = 0; // the value will be ignored + t.tm_yday = 0; // the value will be ignored + t.tm_isdst = -1; + return std::chrono::system_clock::from_time_t(std::mktime(&t)); + } + + TOML11_INLINE local_date::operator std::time_t() const { + return std::chrono::system_clock::to_time_t( + std::chrono::system_clock::time_point(*this)); + } + + TOML11_INLINE bool operator==(const local_date& lhs, const local_date& rhs) { + return std::make_tuple(lhs.year, lhs.month, lhs.day) == + std::make_tuple(rhs.year, rhs.month, rhs.day); + } + + TOML11_INLINE bool operator!=(const local_date& lhs, const local_date& rhs) { + return !(lhs == rhs); + } + + TOML11_INLINE bool operator<(const local_date& lhs, const local_date& rhs) { + return std::make_tuple(lhs.year, lhs.month, lhs.day) < + std::make_tuple(rhs.year, rhs.month, rhs.day); + } + + TOML11_INLINE bool operator<=(const local_date& lhs, const local_date& rhs) { + return (lhs < rhs) || (lhs == rhs); + } + + TOML11_INLINE bool operator>(const local_date& lhs, const local_date& rhs) { + return !(lhs <= rhs); + } + + TOML11_INLINE bool operator>=(const local_date& lhs, const local_date& rhs) { + return !(lhs < rhs); + } + + TOML11_INLINE std::ostream& operator<<(std::ostream& os, const local_date& date) { + os << std::setfill('0') << std::setw(4) << static_cast(date.year) << '-'; + os << std::setfill('0') << std::setw(2) << static_cast(date.month) + 1 + << '-'; + os << std::setfill('0') << std::setw(2) << static_cast(date.day); + return os; + } + + TOML11_INLINE std::string to_string(const local_date& date) { + std::ostringstream oss; + oss.imbue(std::locale::classic()); + oss << date; + return oss.str(); + } + + // ----------------------------------------------------------------------------- + + TOML11_INLINE local_time::operator std::chrono::nanoseconds() const { + return std::chrono::nanoseconds(this->nanosecond) + + std::chrono::microseconds(this->microsecond) + + std::chrono::milliseconds(this->millisecond) + + std::chrono::seconds(this->second) + + std::chrono::minutes(this->minute) + std::chrono::hours(this->hour); + } + + TOML11_INLINE bool operator==(const local_time& lhs, const local_time& rhs) { + return std::make_tuple(lhs.hour, + lhs.minute, + lhs.second, + lhs.millisecond, + lhs.microsecond, + lhs.nanosecond) == std::make_tuple(rhs.hour, + rhs.minute, + rhs.second, + rhs.millisecond, + rhs.microsecond, + rhs.nanosecond); + } + + TOML11_INLINE bool operator!=(const local_time& lhs, const local_time& rhs) { + return !(lhs == rhs); + } + + TOML11_INLINE bool operator<(const local_time& lhs, const local_time& rhs) { + return std::make_tuple(lhs.hour, + lhs.minute, + lhs.second, + lhs.millisecond, + lhs.microsecond, + lhs.nanosecond) < std::make_tuple(rhs.hour, + rhs.minute, + rhs.second, + rhs.millisecond, + rhs.microsecond, + rhs.nanosecond); + } + + TOML11_INLINE bool operator<=(const local_time& lhs, const local_time& rhs) { + return (lhs < rhs) || (lhs == rhs); + } + + TOML11_INLINE bool operator>(const local_time& lhs, const local_time& rhs) { + return !(lhs <= rhs); + } + + TOML11_INLINE bool operator>=(const local_time& lhs, const local_time& rhs) { + return !(lhs < rhs); + } + + TOML11_INLINE std::ostream& operator<<(std::ostream& os, const local_time& time) { + os << std::setfill('0') << std::setw(2) << static_cast(time.hour) << ':'; + os << std::setfill('0') << std::setw(2) << static_cast(time.minute) << ':'; + os << std::setfill('0') << std::setw(2) << static_cast(time.second); + if (time.millisecond != 0 || time.microsecond != 0 || time.nanosecond != 0) { + os << '.'; + os << std::setfill('0') << std::setw(3) + << static_cast(time.millisecond); + if (time.microsecond != 0 || time.nanosecond != 0) { + os << std::setfill('0') << std::setw(3) + << static_cast(time.microsecond); + if (time.nanosecond != 0) { + os << std::setfill('0') << std::setw(3) + << static_cast(time.nanosecond); + } + } + } + return os; + } + + TOML11_INLINE std::string to_string(const local_time& time) { + std::ostringstream oss; + oss.imbue(std::locale::classic()); + oss << time; + return oss.str(); + } + + // ---------------------------------------------------------------------------- + + TOML11_INLINE time_offset::operator std::chrono::minutes() const { + return std::chrono::minutes(this->minute) + std::chrono::hours(this->hour); + } + + TOML11_INLINE bool operator==(const time_offset& lhs, const time_offset& rhs) { + return std::make_tuple(lhs.hour, lhs.minute) == + std::make_tuple(rhs.hour, rhs.minute); + } + + TOML11_INLINE bool operator!=(const time_offset& lhs, const time_offset& rhs) { + return !(lhs == rhs); + } + + TOML11_INLINE bool operator<(const time_offset& lhs, const time_offset& rhs) { + return std::make_tuple(lhs.hour, lhs.minute) < + std::make_tuple(rhs.hour, rhs.minute); + } + + TOML11_INLINE bool operator<=(const time_offset& lhs, const time_offset& rhs) { + return (lhs < rhs) || (lhs == rhs); + } + + TOML11_INLINE bool operator>(const time_offset& lhs, const time_offset& rhs) { + return !(lhs <= rhs); + } + + TOML11_INLINE bool operator>=(const time_offset& lhs, const time_offset& rhs) { + return !(lhs < rhs); + } + + TOML11_INLINE std::ostream& operator<<(std::ostream& os, + const time_offset& offset) { + if (offset.hour == 0 && offset.minute == 0) { + os << 'Z'; + return os; + } + int minute = static_cast(offset.hour) * 60 + offset.minute; + if (minute < 0) { + os << '-'; + minute = std::abs(minute); + } else { + os << '+'; + } + os << std::setfill('0') << std::setw(2) << minute / 60 << ':'; + os << std::setfill('0') << std::setw(2) << minute % 60; + return os; + } + + TOML11_INLINE std::string to_string(const time_offset& offset) { + std::ostringstream oss; + oss.imbue(std::locale::classic()); + oss << offset; + return oss.str(); + } + + // ----------------------------------------------------------------------------- + + TOML11_INLINE local_datetime::local_datetime( + const std::chrono::system_clock::time_point& tp) { + const auto t = std::chrono::system_clock::to_time_t(tp); + std::tm ltime = detail::localtime_s(&t); + + this->date = local_date(ltime); + this->time = local_time(ltime); + + // std::tm lacks subsecond information, so diff between tp and tm + // can be used to get millisecond & microsecond information. + const auto t_diff = tp - std::chrono::system_clock::from_time_t( + std::mktime(<ime)); + this->time.millisecond = static_cast( + std::chrono::duration_cast(t_diff).count()); + this->time.microsecond = static_cast( + std::chrono::duration_cast(t_diff).count()); + this->time.nanosecond = static_cast( + std::chrono::duration_cast(t_diff).count()); + } + + TOML11_INLINE local_datetime::local_datetime(const std::time_t t) + : local_datetime { std::chrono::system_clock::from_time_t(t) } {} + + TOML11_INLINE local_datetime::operator std::chrono::system_clock::time_point() const { + using internal_duration = typename std::chrono::system_clock::time_point::duration; + + // Normally DST begins at A.M. 3 or 4. If we re-use conversion operator + // of local_date and local_time independently, the conversion fails if + // it is the day when DST begins or ends. Since local_date considers the + // time is 00:00 A.M. and local_time does not consider DST because it + // does not have any date information. We need to consider both date and + // time information at the same time to convert it correctly. + + std::tm t; + t.tm_sec = static_cast(this->time.second); + t.tm_min = static_cast(this->time.minute); + t.tm_hour = static_cast(this->time.hour); + t.tm_mday = static_cast(this->date.day); + t.tm_mon = static_cast(this->date.month); + t.tm_year = static_cast(this->date.year) - 1900; + t.tm_wday = 0; // the value will be ignored + t.tm_yday = 0; // the value will be ignored + t.tm_isdst = -1; + + // std::mktime returns date as local time zone. no conversion needed + auto dt = std::chrono::system_clock::from_time_t(std::mktime(&t)); + dt += std::chrono::duration_cast( + std::chrono::milliseconds(this->time.millisecond) + + std::chrono::microseconds(this->time.microsecond) + + std::chrono::nanoseconds(this->time.nanosecond)); + return dt; + } + + TOML11_INLINE local_datetime::operator std::time_t() const { + return std::chrono::system_clock::to_time_t( + std::chrono::system_clock::time_point(*this)); + } + + TOML11_INLINE bool operator==(const local_datetime& lhs, + const local_datetime& rhs) { + return std::make_tuple(lhs.date, lhs.time) == + std::make_tuple(rhs.date, rhs.time); + } + + TOML11_INLINE bool operator!=(const local_datetime& lhs, + const local_datetime& rhs) { + return !(lhs == rhs); + } + + TOML11_INLINE bool operator<(const local_datetime& lhs, + const local_datetime& rhs) { + return std::make_tuple(lhs.date, lhs.time) < + std::make_tuple(rhs.date, rhs.time); + } + + TOML11_INLINE bool operator<=(const local_datetime& lhs, + const local_datetime& rhs) { + return (lhs < rhs) || (lhs == rhs); + } + + TOML11_INLINE bool operator>(const local_datetime& lhs, + const local_datetime& rhs) { + return !(lhs <= rhs); + } + + TOML11_INLINE bool operator>=(const local_datetime& lhs, + const local_datetime& rhs) { + return !(lhs < rhs); + } + + TOML11_INLINE std::ostream& operator<<(std::ostream& os, + const local_datetime& dt) { + os << dt.date << 'T' << dt.time; + return os; + } + + TOML11_INLINE std::string to_string(const local_datetime& dt) { + std::ostringstream oss; + oss.imbue(std::locale::classic()); + oss << dt; + return oss.str(); + } + + // ----------------------------------------------------------------------------- + + TOML11_INLINE offset_datetime::offset_datetime(const local_datetime& ld) + : date { ld.date } + , time { ld.time } + , offset { get_local_offset(nullptr) } + // use the current local timezone offset + {} + + TOML11_INLINE offset_datetime::offset_datetime( + const std::chrono::system_clock::time_point& tp) + : offset { 0, 0 } // use gmtime + { + const auto timet = std::chrono::system_clock::to_time_t(tp); + const auto tm = detail::gmtime_s(&timet); + this->date = local_date(tm); + this->time = local_time(tm); + } + + TOML11_INLINE offset_datetime::offset_datetime(const std::time_t& t) + : offset { 0, 0 } // use gmtime + { + const auto tm = detail::gmtime_s(&t); + this->date = local_date(tm); + this->time = local_time(tm); + } + + TOML11_INLINE offset_datetime::offset_datetime(const std::tm& t) + : offset { 0, 0 } // assume gmtime + { + this->date = local_date(t); + this->time = local_time(t); + } + + TOML11_INLINE offset_datetime::operator std::chrono::system_clock::time_point() const { + // get date-time + using internal_duration = typename std::chrono::system_clock::time_point::duration; + + // first, convert it to local date-time information in the same way as + // local_datetime does. later we will use time_t to adjust time offset. + std::tm t; + t.tm_sec = static_cast(this->time.second); + t.tm_min = static_cast(this->time.minute); + t.tm_hour = static_cast(this->time.hour); + t.tm_mday = static_cast(this->date.day); + t.tm_mon = static_cast(this->date.month); + t.tm_year = static_cast(this->date.year) - 1900; + t.tm_wday = 0; // the value will be ignored + t.tm_yday = 0; // the value will be ignored + t.tm_isdst = -1; + const std::time_t tp_loc = std::mktime(std::addressof(t)); + + auto tp = std::chrono::system_clock::from_time_t(tp_loc); + tp += std::chrono::duration_cast( + std::chrono::milliseconds(this->time.millisecond) + + std::chrono::microseconds(this->time.microsecond) + + std::chrono::nanoseconds(this->time.nanosecond)); + + // Since mktime uses local time zone, it should be corrected. + // `12:00:00+09:00` means `03:00:00Z`. So mktime returns `03:00:00Z` if + // we are in `+09:00` timezone. To represent `12:00:00Z` there, we need + // to add `+09:00` to `03:00:00Z`. + // Here, it uses the time_t converted from date-time info to handle + // daylight saving time. + const auto ofs = get_local_offset(std::addressof(tp_loc)); + tp += std::chrono::hours(ofs.hour); + tp += std::chrono::minutes(ofs.minute); + + // We got `12:00:00Z` by correcting local timezone applied by mktime. + // Then we will apply the offset. Let's say `12:00:00-08:00` is given. + // And now, we have `12:00:00Z`. `12:00:00-08:00` means `20:00:00Z`. + // So we need to subtract the offset. + tp -= std::chrono::minutes(this->offset); + return tp; + } + + TOML11_INLINE offset_datetime::operator std::time_t() const { + return std::chrono::system_clock::to_time_t( + std::chrono::system_clock::time_point(*this)); + } + + TOML11_INLINE time_offset offset_datetime::get_local_offset(const std::time_t* tp) { + // get local timezone with the same date-time information as mktime + const auto t = detail::localtime_s(tp); + + std::array buf; + const auto result = std::strftime(buf.data(), 6, "%z", &t); // +hhmm\0 + if (result != 5) { + throw std::runtime_error("toml::offset_datetime: cannot obtain " + "timezone information of current env"); + } + const int ofs = std::atoi(buf.data()); + const int ofs_h = ofs / 100; + const int ofs_m = ofs - (ofs_h * 100); + return time_offset(ofs_h, ofs_m); + } + + TOML11_INLINE bool operator==(const offset_datetime& lhs, + const offset_datetime& rhs) { + return std::make_tuple(lhs.date, lhs.time, lhs.offset) == + std::make_tuple(rhs.date, rhs.time, rhs.offset); + } + + TOML11_INLINE bool operator!=(const offset_datetime& lhs, + const offset_datetime& rhs) { + return !(lhs == rhs); + } + + TOML11_INLINE bool operator<(const offset_datetime& lhs, + const offset_datetime& rhs) { + return std::make_tuple(lhs.date, lhs.time, lhs.offset) < + std::make_tuple(rhs.date, rhs.time, rhs.offset); + } + + TOML11_INLINE bool operator<=(const offset_datetime& lhs, + const offset_datetime& rhs) { + return (lhs < rhs) || (lhs == rhs); + } + + TOML11_INLINE bool operator>(const offset_datetime& lhs, + const offset_datetime& rhs) { + return !(lhs <= rhs); + } + + TOML11_INLINE bool operator>=(const offset_datetime& lhs, + const offset_datetime& rhs) { + return !(lhs < rhs); + } + + TOML11_INLINE std::ostream& operator<<(std::ostream& os, + const offset_datetime& dt) { + os << dt.date << 'T' << dt.time << dt.offset; + return os; + } + + TOML11_INLINE std::string to_string(const offset_datetime& dt) { + std::ostringstream oss; + oss.imbue(std::locale::classic()); + oss << dt; + return oss.str(); + } + +} // namespace toml + #endif // TOML11_DATETIME_IMPL_HPP +#endif + +#endif // TOML11_DATETIME_HPP +#ifndef TOML11_COMPAT_HPP +#define TOML11_COMPAT_HPP + +#include +#include +#include +#include +#include +#include + +#if TOML11_CPLUSPLUS_STANDARD_VERSION >= TOML11_CXX20_VALUE + #if __has_include() + #include + #endif +#endif + +#include + +// ---------------------------------------------------------------------------- + +#if TOML11_CPLUSPLUS_STANDARD_VERSION >= TOML11_CXX14_VALUE + #if __has_cpp_attribute(deprecated) + #define TOML11_HAS_ATTR_DEPRECATED 1 + #endif +#endif + +#if defined(TOML11_HAS_ATTR_DEPRECATED) + #define TOML11_DEPRECATED(msg) [[deprecated(msg)]] +#elif defined(__GNUC__) + #define TOML11_DEPRECATED(msg) __attribute__((deprecated(msg))) +#elif defined(_MSC_VER) + #define TOML11_DEPRECATED(msg) __declspec(deprecated(msg)) +#else + #define TOML11_DEPRECATED(msg) +#endif + +// ---------------------------------------------------------------------------- + +#if defined(__cpp_if_constexpr) + #if __cpp_if_constexpr >= 201606L + #define TOML11_HAS_CONSTEXPR_IF 1 + #endif +#endif + +#if defined(TOML11_HAS_CONSTEXPR_IF) + #define TOML11_CONSTEXPR_IF if constexpr +#else + #define TOML11_CONSTEXPR_IF if +#endif + +// ---------------------------------------------------------------------------- + +#if TOML11_CPLUSPLUS_STANDARD_VERSION >= TOML11_CXX14_VALUE + #if defined(__cpp_lib_make_unique) + #if __cpp_lib_make_unique >= 201304L + #define TOML11_HAS_STD_MAKE_UNIQUE 1 + #endif + #endif +#endif + +namespace toml { + namespace cxx { + +#if defined(TOML11_HAS_STD_MAKE_UNIQUE) + + using std::make_unique; + +#else + + template + std::unique_ptr make_unique(Ts&&... args) { + return std::unique_ptr(new T(std::forward(args)...)); + } + +#endif // TOML11_HAS_STD_MAKE_UNIQUE + + } // namespace cxx +} // namespace toml + +// --------------------------------------------------------------------------- + +#if TOML11_CPLUSPLUS_STANDARD_VERSION >= TOML11_CXX14_VALUE + #if defined(__cpp_lib_make_reverse_iterator) + #if __cpp_lib_make_reverse_iterator >= 201402L + #define TOML11_HAS_STD_MAKE_REVERSE_ITERATOR 1 + #endif + #endif +#endif + +namespace toml { + namespace cxx { +#if defined(TOML11_HAS_STD_MAKE_REVERSE_ITERATOR) + + using std::make_reverse_iterator; + +#else + + template + std::reverse_iterator make_reverse_iterator(Iterator iter) { + return std::reverse_iterator(iter); + } + +#endif // TOML11_HAS_STD_MAKE_REVERSE_ITERATOR + + } // namespace cxx +} // namespace toml + +// --------------------------------------------------------------------------- + +#if TOML11_CPLUSPLUS_STANDARD_VERSION >= TOML11_CXX20_VALUE + #if defined(__cpp_lib_clamp) + #if __cpp_lib_clamp >= 201603L + #define TOML11_HAS_STD_CLAMP 1 + #endif + #endif +#endif + +namespace toml { + namespace cxx { +#if defined(TOML11_HAS_STD_CLAMP) + + using std::clamp; + +#else + + template + T clamp(const T& x, const T& low, const T& high) noexcept { + assert(low <= high); + return (std::min)((std::max)(x, low), high); + } + +#endif // TOML11_HAS_STD_CLAMP + + } // namespace cxx +} // namespace toml + +// --------------------------------------------------------------------------- + +#if TOML11_CPLUSPLUS_STANDARD_VERSION >= TOML11_CXX20_VALUE + #if defined(__cpp_lib_bit_cast) + #if __cpp_lib_bit_cast >= 201806L + #define TOML11_HAS_STD_BIT_CAST 1 + #endif + #endif +#endif + +namespace toml { + namespace cxx { +#if defined(TOML11_HAS_STD_BIT_CAST) + + using std::bit_cast; + +#else + + template + U bit_cast(const T& x) noexcept { + static_assert(sizeof(T) == sizeof(U), ""); + static_assert(std::is_default_constructible::value, ""); + + U z; + std::memcpy(reinterpret_cast(std::addressof(z)), + reinterpret_cast(std::addressof(x)), + sizeof(T)); + + return z; + } + +#endif // TOML11_HAS_STD_BIT_CAST + + } // namespace cxx +} // namespace toml + +// --------------------------------------------------------------------------- +// C++20 remove_cvref_t + +#if TOML11_CPLUSPLUS_STANDARD_VERSION >= TOML11_CXX20_VALUE + #if defined(__cpp_lib_remove_cvref) + #if __cpp_lib_remove_cvref >= 201711L + #define TOML11_HAS_STD_REMOVE_CVREF 1 + #endif + #endif +#endif + +namespace toml { + namespace cxx { +#if defined(TOML11_HAS_STD_REMOVE_CVREF) + + using std::remove_cvref; + using std::remove_cvref_t; + +#else + + template + struct remove_cvref { + using type = typename std::remove_cv::type>::type; + }; + + template + using remove_cvref_t = typename remove_cvref::type; + +#endif // TOML11_HAS_STD_REMOVE_CVREF + + } // namespace cxx +} // namespace toml + +// --------------------------------------------------------------------------- +// C++17 and/or/not + +#if TOML11_CPLUSPLUS_STANDARD_VERSION >= TOML11_CXX17_VALUE + #if defined(__cpp_lib_logical_traits) + #if __cpp_lib_logical_traits >= 201510L + #define TOML11_HAS_STD_CONJUNCTION 1 + #endif + #endif +#endif + +namespace toml { + namespace cxx { +#if defined(TOML11_HAS_STD_CONJUNCTION) + + using std::conjunction; + using std::disjunction; + using std::negation; + +#else + + template + struct conjunction : std::true_type {}; + + template + struct conjunction : T {}; + + template + struct conjunction + : std::conditional(T::value), conjunction, T>::type { + }; + + template + struct disjunction : std::false_type {}; + + template + struct disjunction : T {}; + + template + struct disjunction + : std::conditional(T::value), T, disjunction>::type { + }; + + template + struct negation + : std::integral_constant(T::value)> {}; + +#endif // TOML11_HAS_STD_CONJUNCTION + + } // namespace cxx +} // namespace toml + +// --------------------------------------------------------------------------- +// C++14 index_sequence + +#if TOML11_CPLUSPLUS_STANDARD_VERSION >= TOML11_CXX14_VALUE + #if defined(__cpp_lib_integer_sequence) + #if __cpp_lib_integer_sequence >= 201304L + #define TOML11_HAS_STD_INTEGER_SEQUENCE 1 + #endif + #endif +#endif + +namespace toml { + namespace cxx { +#if defined(TOML11_HAS_STD_INTEGER_SEQUENCE) + + using std::index_sequence; + using std::make_index_sequence; + +#else + + template + struct index_sequence {}; + + template + struct double_index_sequence; + + template + struct double_index_sequence> { + using type = index_sequence; + }; + + template + struct double_index_sequence> { + using type = index_sequence; + }; + + template + struct index_sequence_maker { + using type = + typename double_index_sequence::type>::type; + }; + + template <> + struct index_sequence_maker<0> { + using type = index_sequence<>; + }; + + template + using make_index_sequence = typename index_sequence_maker::type; + +#endif // TOML11_HAS_STD_INTEGER_SEQUENCE + + } // namespace cxx +} // namespace toml + +// --------------------------------------------------------------------------- +// C++14 enable_if_t + +#if TOML11_CPLUSPLUS_STANDARD_VERSION >= TOML11_CXX14_VALUE + #if defined(__cpp_lib_transformation_trait_aliases) + #if __cpp_lib_transformation_trait_aliases >= 201304L + #define TOML11_HAS_STD_ENABLE_IF_T 1 + #endif + #endif +#endif + +namespace toml { + namespace cxx { +#if defined(TOML11_HAS_STD_ENABLE_IF_T) + + using std::enable_if_t; + +#else + + template + using enable_if_t = typename std::enable_if::type; + +#endif // TOML11_HAS_STD_ENABLE_IF_T + + } // namespace cxx +} // namespace toml + +// --------------------------------------------------------------------------- +// return_type_of_t + +#if TOML11_CPLUSPLUS_STANDARD_VERSION >= TOML11_CXX17_VALUE + #if defined(__cpp_lib_is_invocable) + #if __cpp_lib_is_invocable >= 201703 + #define TOML11_HAS_STD_INVOKE_RESULT 1 + #endif + #endif +#endif + +namespace toml { + namespace cxx { +#if defined(TOML11_HAS_STD_INVOKE_RESULT) + + template + using return_type_of_t = std::invoke_result_t; + +#else + + // result_of is deprecated after C++17 + template + using return_type_of_t = typename std::result_of::type; + +#endif // TOML11_HAS_STD_INVOKE_RESULT + + } // namespace cxx +} // namespace toml + +// ---------------------------------------------------------------------------- +// (subset of) source_location + +#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 202002L + #if __has_include() + #define TOML11_HAS_STD_SOURCE_LOCATION + #endif // has_include +#endif // c++20 + +#if !defined(TOML11_HAS_STD_SOURCE_LOCATION) + #if defined(__GNUC__) && !defined(__clang__) + #if TOML11_CPLUSPLUS_STANDARD_VERSION >= TOML11_CXX14_VALUE + #if __has_include() + #define TOML11_HAS_EXPERIMENTAL_SOURCE_LOCATION + #endif + #endif + #endif // GNU g++ +#endif // not TOML11_HAS_STD_SOURCE_LOCATION + +#if !defined(TOML11_HAS_STD_SOURCE_LOCATION) && \ + !defined(TOML11_HAS_EXPERIMENTAL_SOURCE_LOCATION) + #if defined(__GNUC__) && !defined(__clang__) + #if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9)) + #define TOML11_HAS_BUILTIN_FILE_LINE 1 + #define TOML11_BUILTIN_LINE_TYPE int + #endif + #elif defined(__clang__) // clang 9.0.0 implements builtin_FILE/LINE + #if __has_builtin(__builtin_FILE) && __has_builtin(__builtin_LINE) + #define TOML11_HAS_BUILTIN_FILE_LINE 1 + #define TOML11_BUILTIN_LINE_TYPE unsigned int + #endif + #elif defined(_MSVC_LANG) && defined(_MSC_VER) + #if _MSC_VER > 1926 + #define TOML11_HAS_BUILTIN_FILE_LINE 1 + #define TOML11_BUILTIN_LINE_TYPE int + #endif + #endif +#endif + +#if defined(TOML11_HAS_STD_SOURCE_LOCATION) + #include + +namespace toml { + namespace cxx { + using source_location = std::source_location; + + inline std::string to_string(const source_location& loc) { + return std::string(" at line ") + std::to_string(loc.line()) + + std::string(" in file ") + std::string(loc.file_name()); + } + } // namespace cxx +} // namespace toml +#elif defined(TOML11_HAS_EXPERIMENTAL_SOURCE_LOCATION) + #include + +namespace toml { + namespace cxx { + using source_location = std::experimental::source_location; + + inline std::string to_string(const source_location& loc) { + return std::string(" at line ") + std::to_string(loc.line()) + + std::string(" in file ") + std::string(loc.file_name()); + } + } // namespace cxx +} // namespace toml +#elif defined(TOML11_HAS_BUILTIN_FILE_LINE) +namespace toml { + namespace cxx { + struct source_location { + using line_type = TOML11_BUILTIN_LINE_TYPE; + + static source_location current(const line_type line = __builtin_LINE(), + const char* file = __builtin_FILE()) { + return source_location(line, file); + } + + source_location(const line_type line, const char* file) + : line_(line) + , file_name_(file) {} + + line_type line() const noexcept { + return line_; + } + + const char* file_name() const noexcept { + return file_name_; + } + + private: + line_type line_; + const char* file_name_; + }; + + inline std::string to_string(const source_location& loc) { + return std::string(" at line ") + std::to_string(loc.line()) + + std::string(" in file ") + std::string(loc.file_name()); + } + } // namespace cxx +} // namespace toml +#else // no builtin +namespace toml { + namespace cxx { + struct source_location { + static source_location current() { + return source_location {}; + } + }; + + inline std::string to_string(const source_location&) { + return std::string(""); + } + } // namespace cxx +} // namespace toml +#endif // TOML11_HAS_STD_SOURCE_LOCATION + +// ---------------------------------------------------------------------------- +// (subset of) optional + +#if TOML11_CPLUSPLUS_STANDARD_VERSION >= TOML11_CXX17_VALUE + #if __has_include() + #include + #endif // has_include(optional) +#endif // C++17 + +#if TOML11_CPLUSPLUS_STANDARD_VERSION >= TOML11_CXX17_VALUE + #if defined(__cpp_lib_optional) + #if __cpp_lib_optional >= 201606L + #define TOML11_HAS_STD_OPTIONAL 1 + #endif + #endif +#endif + +#if defined(TOML11_HAS_STD_OPTIONAL) + +namespace toml { + namespace cxx { + using std::optional; + + inline std::nullopt_t make_nullopt() { + return std::nullopt; + } + + template + std::basic_ostream& operator<<( + std::basic_ostream& os, + const std::nullopt_t&) { + os << "nullopt"; + return os; + } + + } // namespace cxx +} // namespace toml + +#else // TOML11_HAS_STD_OPTIONAL + +namespace toml { + namespace cxx { + + struct nullopt_t {}; + + inline nullopt_t make_nullopt() { + return nullopt_t {}; + } + + inline bool operator==(const nullopt_t&, const nullopt_t&) noexcept { + return true; + } + + inline bool operator!=(const nullopt_t&, const nullopt_t&) noexcept { + return false; + } + + inline bool operator<(const nullopt_t&, const nullopt_t&) noexcept { + return false; + } + + inline bool operator<=(const nullopt_t&, const nullopt_t&) noexcept { + return true; + } + + inline bool operator>(const nullopt_t&, const nullopt_t&) noexcept { + return false; + } + + inline bool operator>=(const nullopt_t&, const nullopt_t&) noexcept { + return true; + } + + template + std::basic_ostream& operator<<( + std::basic_ostream& os, + const nullopt_t&) { + os << "nullopt"; + return os; + } + + template + class optional { + public: + using value_type = T; + + public: + optional() noexcept : has_value_(false), null_('\0') {} + + optional(nullopt_t) noexcept : has_value_(false), null_('\0') {} + + optional(const T& x) : has_value_(true), value_(x) {} + + optional(T&& x) : has_value_(true), value_(std::move(x)) {} + + template ::value, std::nullptr_t> = nullptr> + explicit optional(U&& x) : has_value_(true) + , value_(std::forward(x)) {} + + optional(const optional& rhs) : has_value_(rhs.has_value_) { + if (rhs.has_value_) { + this->assigner(rhs.value_); + } + } + + optional(optional&& rhs) : has_value_(rhs.has_value_) { + if (this->has_value_) { + this->assigner(std::move(rhs.value_)); + } + } + + optional& operator=(const optional& rhs) { + if (this == std::addressof(rhs)) { + return *this; + } + + this->cleanup(); + this->has_value_ = rhs.has_value_; + if (this->has_value_) { + this->assigner(rhs.value_); + } + return *this; + } + + optional& operator=(optional&& rhs) { + if (this == std::addressof(rhs)) { + return *this; + } + + this->cleanup(); + this->has_value_ = rhs.has_value_; + if (this->has_value_) { + this->assigner(std::move(rhs.value_)); + } + return *this; + } + + template >, + std::is_constructible>::value, + std::nullptr_t> = nullptr> + explicit optional(const optional& rhs) + : has_value_(rhs.has_value_) + , null_('\0') { + if (rhs.has_value_) { + this->assigner(rhs.value_); + } + } + + template >, + std::is_constructible>::value, + std::nullptr_t> = nullptr> + explicit optional(optional&& rhs) + : has_value_(rhs.has_value_) + , null_('\0') { + if (this->has_value_) { + this->assigner(std::move(rhs.value_)); + } + } + + template >, + std::is_constructible>::value, + std::nullptr_t> = nullptr> + optional& operator=(const optional& rhs) { + if (this == std::addressof(rhs)) { + return *this; + } + + this->cleanup(); + this->has_value_ = rhs.has_value_; + if (this->has_value_) { + this->assigner(rhs.value_); + } + return *this; + } + + template >, + std::is_constructible>::value, + std::nullptr_t> = nullptr> + optional& operator=(optional&& rhs) { + if (this == std::addressof(rhs)) { + return *this; + } + + this->cleanup(); + this->has_value_ = rhs.has_value_; + if (this->has_value_) { + this->assigner(std::move(rhs.value_)); + } + return *this; + } + + ~optional() noexcept { + this->cleanup(); + } + + explicit operator bool() const noexcept { + return has_value_; + } + + bool has_value() const noexcept { + return has_value_; + } + + const value_type& value(source_location loc = source_location::current()) const { + if (!this->has_value_) { + throw std::runtime_error( + "optional::value(): bad_unwrap" + to_string(loc)); + } + return this->value_; + } + + value_type& value(source_location loc = source_location::current()) { + if (!this->has_value_) { + throw std::runtime_error( + "optional::value(): bad_unwrap" + to_string(loc)); + } + return this->value_; + } + + const value_type& value_or(const value_type& opt) const { + if (this->has_value_) { + return this->value_; + } else { + return opt; + } + } + + value_type& value_or(value_type& opt) { + if (this->has_value_) { + return this->value_; + } else { + return opt; + } + } + + private: + void cleanup() noexcept { + if (this->has_value_) { + value_.~T(); + } + } + + template + void assigner(U&& x) { + const auto tmp = ::new (std::addressof(this->value_)) + value_type(std::forward(x)); + assert(tmp == std::addressof(this->value_)); + (void)tmp; + } + + private: + bool has_value_; + + union { + char null_; + T value_; + }; + }; + } // namespace cxx +} // namespace toml +#endif // TOML11_HAS_STD_OPTIONAL + +#endif // TOML11_COMPAT_HPP +#ifndef TOML11_VALUE_T_HPP +#define TOML11_VALUE_T_HPP + +#ifndef TOML11_VALUE_T_FWD_HPP + #define TOML11_VALUE_T_FWD_HPP + + #include + #include + #include + #include + +namespace toml { + + // forward decl + template + class basic_value; + + // ---------------------------------------------------------------------------- + // enum representing toml types + + enum class value_t : std::uint8_t { + empty = 0, + boolean = 1, + integer = 2, + floating = 3, + string = 4, + offset_datetime = 5, + local_datetime = 6, + local_date = 7, + local_time = 8, + array = 9, + table = 10 + }; + + std::ostream& operator<<(std::ostream& os, value_t t); + std::string to_string(value_t t); + + // ---------------------------------------------------------------------------- + // meta functions for internal use + + namespace detail { + + template + using value_t_constant = std::integral_constant; + + template + struct type_to_enum : value_t_constant {}; + + template + struct type_to_enum + : value_t_constant {}; + + template + struct type_to_enum + : value_t_constant {}; + + template + struct type_to_enum + : value_t_constant {}; + + template + struct type_to_enum + : value_t_constant {}; + + template + struct type_to_enum + : value_t_constant {}; + + template + struct type_to_enum + : value_t_constant {}; + + template + struct type_to_enum + : value_t_constant {}; + + template + struct type_to_enum + : value_t_constant {}; + + template + struct type_to_enum + : value_t_constant {}; + + template + struct type_to_enum + : value_t_constant {}; + + template + struct enum_to_type { + using type = void; + }; + + template + struct enum_to_type { + using type = typename V::boolean_type; + }; + + template + struct enum_to_type { + using type = typename V::integer_type; + }; + + template + struct enum_to_type { + using type = typename V::floating_type; + }; + + template + struct enum_to_type { + using type = typename V::string_type; + }; + + template + struct enum_to_type { + using type = typename V::offset_datetime_type; + }; + + template + struct enum_to_type { + using type = typename V::local_datetime_type; + }; + + template + struct enum_to_type { + using type = typename V::local_date_type; + }; + + template + struct enum_to_type { + using type = typename V::local_time_type; + }; + + template + struct enum_to_type { + using type = typename V::array_type; + }; + + template + struct enum_to_type { + using type = typename V::table_type; + }; + + template + using enum_to_type_t = typename enum_to_type::type; + + template + struct enum_to_fmt_type { + using type = void; + }; + + template <> + struct enum_to_fmt_type { + using type = boolean_format_info; + }; + + template <> + struct enum_to_fmt_type { + using type = integer_format_info; + }; + + template <> + struct enum_to_fmt_type { + using type = floating_format_info; + }; + + template <> + struct enum_to_fmt_type { + using type = string_format_info; + }; + + template <> + struct enum_to_fmt_type { + using type = offset_datetime_format_info; + }; + + template <> + struct enum_to_fmt_type { + using type = local_datetime_format_info; + }; + + template <> + struct enum_to_fmt_type { + using type = local_date_format_info; + }; + + template <> + struct enum_to_fmt_type { + using type = local_time_format_info; + }; + + template <> + struct enum_to_fmt_type { + using type = array_format_info; + }; + + template <> + struct enum_to_fmt_type { + using type = table_format_info; + }; + + template + using enum_to_fmt_type_t = typename enum_to_fmt_type::type; + + template + struct is_exact_toml_type0 + : cxx::disjunction, + std::is_same, + std::is_same, + std::is_same, + std::is_same, + std::is_same, + std::is_same, + std::is_same, + std::is_same, + std::is_same> {}; + + template + struct is_exact_toml_type : is_exact_toml_type0, V> {}; + + template + struct is_not_toml_type : cxx::negation> {}; + + } // namespace detail +} // namespace toml +#endif // TOML11_VALUE_T_FWD_HPP + +#if !defined(TOML11_COMPILE_SOURCES) + #ifndef TOML11_VALUE_T_IMPL_HPP + #define TOML11_VALUE_T_IMPL_HPP + + #include + #include + #include + +namespace toml { + + TOML11_INLINE std::ostream& operator<<(std::ostream& os, value_t t) { + switch (t) { + case value_t::boolean: + os << "boolean"; + return os; + case value_t::integer: + os << "integer"; + return os; + case value_t::floating: + os << "floating"; + return os; + case value_t::string: + os << "string"; + return os; + case value_t::offset_datetime: + os << "offset_datetime"; + return os; + case value_t::local_datetime: + os << "local_datetime"; + return os; + case value_t::local_date: + os << "local_date"; + return os; + case value_t::local_time: + os << "local_time"; + return os; + case value_t::array: + os << "array"; + return os; + case value_t::table: + os << "table"; + return os; + case value_t::empty: + os << "empty"; + return os; + default: + os << "unknown"; + return os; + } + } + + TOML11_INLINE std::string to_string(value_t t) { + std::ostringstream oss; + oss << t; + return oss.str(); + } + +} // namespace toml + #endif // TOML11_VALUE_T_IMPL_HPP +#endif + +#endif // TOML11_VALUE_T_HPP +#ifndef TOML11_STORAGE_HPP +#define TOML11_STORAGE_HPP + +namespace toml { + namespace detail { + + // It owns a pointer to T. It does deep-copy when copied. + // This struct is introduced to implement a recursive type. + // + // `toml::value` contains `std::vector` to represent a toml + // array. But, in the definition of `toml::value`, `toml::value` is still + // incomplete. `std::vector` of an incomplete type is not allowed in C++11 + // (it is allowed after C++17). To avoid this, we need to use a pointer to + // `toml::value`, like `std::vector>`. Although + // `std::unique_ptr` is noncopyable, we want to make `toml::value` copyable. + // `storage` is introduced to resolve those problems. + template + struct storage { + using value_type = T; + + explicit storage(value_type v) + : ptr_(cxx::make_unique(std::move(v))) {} + + ~storage() = default; + + storage(const storage& rhs) : ptr_(cxx::make_unique(*rhs.ptr_)) {} + + storage& operator=(const storage& rhs) { + this->ptr_ = cxx::make_unique(*rhs.ptr_); + return *this; + } + + storage(storage&&) = default; + storage& operator=(storage&&) = default; + + bool is_ok() const noexcept { + return static_cast(ptr_); + } + + value_type& get() const noexcept { + return *ptr_; + } + + private: + std::unique_ptr ptr_; + }; + + } // namespace detail +} // namespace toml +#endif // TOML11_STORAGE_HPP +#ifndef TOML11_COMMENTS_HPP +#define TOML11_COMMENTS_HPP + +#ifndef TOML11_COMMENTS_FWD_HPP + #define TOML11_COMMENTS_FWD_HPP + + // to use __has_builtin + + #include + #include + #include + #include + #include + #include + #include + #include + #include + +// This file provides mainly two classes, `preserve_comments` and `discard_comments`. +// Those two are a container that have the same interface as `std::vector` +// but bahaves in the opposite way. `preserve_comments` is just the same as +// `std::vector` and each `std::string` corresponds to a comment line. +// Conversely, `discard_comments` discards all the strings and ignores everything +// assigned in it. `discard_comments` is always empty and you will encounter an +// error whenever you access to the element. +namespace toml { + class discard_comments; // forward decl + + class preserve_comments { + public: + // `container_type` is not provided in discard_comments. + // do not use this inner-type in a generic code. + using container_type = std::vector; + + using size_type = container_type::size_type; + using difference_type = container_type::difference_type; + using value_type = container_type::value_type; + using reference = container_type::reference; + using const_reference = container_type::const_reference; + using pointer = container_type::pointer; + using const_pointer = container_type::const_pointer; + using iterator = container_type::iterator; + using const_iterator = container_type::const_iterator; + using reverse_iterator = container_type::reverse_iterator; + using const_reverse_iterator = container_type::const_reverse_iterator; + + public: + preserve_comments() = default; + ~preserve_comments() = default; + preserve_comments(const preserve_comments&) = default; + preserve_comments(preserve_comments&&) = default; + preserve_comments& operator=(const preserve_comments&) = default; + preserve_comments& operator=(preserve_comments&&) = default; + + explicit preserve_comments(const std::vector& c) + : comments(c) {} + + explicit preserve_comments(std::vector&& c) + : comments(std::move(c)) {} + + preserve_comments& operator=(const std::vector& c) { + comments = c; + return *this; + } + + preserve_comments& operator=(std::vector&& c) { + comments = std::move(c); + return *this; + } + + explicit preserve_comments(const discard_comments&) {} + + explicit preserve_comments(size_type n) : comments(n) {} + + preserve_comments(size_type n, const std::string& x) : comments(n, x) {} + + preserve_comments(std::initializer_list x) : comments(x) {} + + template + preserve_comments(InputIterator first, InputIterator last) + : comments(first, last) {} + + template + void assign(InputIterator first, InputIterator last) { + comments.assign(first, last); + } + + void assign(std::initializer_list ini) { + comments.assign(ini); + } + + void assign(size_type n, const std::string& val) { + comments.assign(n, val); + } + + // Related to the issue #97. + // + // `std::vector::insert` and `std::vector::erase` in the STL implementation + // included in GCC 4.8.5 takes `std::vector::iterator` instead of + // `std::vector::const_iterator`. It causes compilation error in GCC 4.8.5. + #if defined(__GNUC__) && defined(__GNUC_MINOR__) && \ + defined(__GNUC_PATCHLEVEL__) && !defined(__clang__) + #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) <= 40805 + #define TOML11_WORKAROUND_GCC_4_8_X_STANDARD_LIBRARY_IMPLEMENTATION + #endif + #endif + + #ifdef TOML11_WORKAROUND_GCC_4_8_X_STANDARD_LIBRARY_IMPLEMENTATION + iterator insert(iterator p, const std::string& x) { + return comments.insert(p, x); + } + + iterator insert(iterator p, std::string&& x) { + return comments.insert(p, std::move(x)); + } + + void insert(iterator p, size_type n, const std::string& x) { + return comments.insert(p, n, x); + } + + template + void insert(iterator p, InputIterator first, InputIterator last) { + return comments.insert(p, first, last); + } + + void insert(iterator p, std::initializer_list ini) { + return comments.insert(p, ini); + } + + template + iterator emplace(iterator p, Ts&&... args) { + return comments.emplace(p, std::forward(args)...); + } + + iterator erase(iterator pos) { + return comments.erase(pos); + } + + iterator erase(iterator first, iterator last) { + return comments.erase(first, last); + } + #else + iterator insert(const_iterator p, const std::string& x) { + return comments.insert(p, x); + } + + iterator insert(const_iterator p, std::string&& x) { + return comments.insert(p, std::move(x)); + } + + iterator insert(const_iterator p, size_type n, const std::string& x) { + return comments.insert(p, n, x); + } + + template + iterator insert(const_iterator p, InputIterator first, InputIterator last) { + return comments.insert(p, first, last); + } + + iterator insert(const_iterator p, std::initializer_list ini) { + return comments.insert(p, ini); + } + + template + iterator emplace(const_iterator p, Ts&&... args) { + return comments.emplace(p, std::forward(args)...); + } + + iterator erase(const_iterator pos) { + return comments.erase(pos); + } + + iterator erase(const_iterator first, const_iterator last) { + return comments.erase(first, last); + } + #endif + + void swap(preserve_comments& other) { + comments.swap(other.comments); + } + + void push_back(const std::string& v) { + comments.push_back(v); + } + + void push_back(std::string&& v) { + comments.push_back(std::move(v)); + } + + void pop_back() { + comments.pop_back(); + } + + template + void emplace_back(Ts&&... args) { + comments.emplace_back(std::forward(args)...); + } + + void clear() { + comments.clear(); + } + + size_type size() const noexcept { + return comments.size(); + } + + size_type max_size() const noexcept { + return comments.max_size(); + } + + size_type capacity() const noexcept { + return comments.capacity(); + } + + bool empty() const noexcept { + return comments.empty(); + } + + void reserve(size_type n) { + comments.reserve(n); + } + + void resize(size_type n) { + comments.resize(n); + } + + void resize(size_type n, const std::string& c) { + comments.resize(n, c); + } + + void shrink_to_fit() { + comments.shrink_to_fit(); + } + + reference operator[](const size_type n) noexcept { + return comments[n]; + } + + const_reference operator[](const size_type n) const noexcept { + return comments[n]; + } + + reference at(const size_type n) { + return comments.at(n); + } + + const_reference at(const size_type n) const { + return comments.at(n); + } + + reference front() noexcept { + return comments.front(); + } + + const_reference front() const noexcept { + return comments.front(); + } + + reference back() noexcept { + return comments.back(); + } + + const_reference back() const noexcept { + return comments.back(); + } + + pointer data() noexcept { + return comments.data(); + } + + const_pointer data() const noexcept { + return comments.data(); + } + + iterator begin() noexcept { + return comments.begin(); + } + + iterator end() noexcept { + return comments.end(); + } + + const_iterator begin() const noexcept { + return comments.begin(); + } + + const_iterator end() const noexcept { + return comments.end(); + } + + const_iterator cbegin() const noexcept { + return comments.cbegin(); + } + + const_iterator cend() const noexcept { + return comments.cend(); + } + + reverse_iterator rbegin() noexcept { + return comments.rbegin(); + } + + reverse_iterator rend() noexcept { + return comments.rend(); + } + + const_reverse_iterator rbegin() const noexcept { + return comments.rbegin(); + } + + const_reverse_iterator rend() const noexcept { + return comments.rend(); + } + + const_reverse_iterator crbegin() const noexcept { + return comments.crbegin(); + } + + const_reverse_iterator crend() const noexcept { + return comments.crend(); + } + + friend bool operator==(const preserve_comments&, const preserve_comments&); + friend bool operator!=(const preserve_comments&, const preserve_comments&); + friend bool operator<(const preserve_comments&, const preserve_comments&); + friend bool operator<=(const preserve_comments&, const preserve_comments&); + friend bool operator>(const preserve_comments&, const preserve_comments&); + friend bool operator>=(const preserve_comments&, const preserve_comments&); + + friend void swap(preserve_comments&, std::vector&); + friend void swap(std::vector&, preserve_comments&); + + private: + container_type comments; + }; + + bool operator==(const preserve_comments& lhs, const preserve_comments& rhs); + bool operator!=(const preserve_comments& lhs, const preserve_comments& rhs); + bool operator<(const preserve_comments& lhs, const preserve_comments& rhs); + bool operator<=(const preserve_comments& lhs, const preserve_comments& rhs); + bool operator>(const preserve_comments& lhs, const preserve_comments& rhs); + bool operator>=(const preserve_comments& lhs, const preserve_comments& rhs); + + void swap(preserve_comments& lhs, preserve_comments& rhs); + void swap(preserve_comments& lhs, std::vector& rhs); + void swap(std::vector& lhs, preserve_comments& rhs); + + std::ostream& operator<<(std::ostream& os, const preserve_comments& com); + + namespace detail { + + // To provide the same interface with `preserve_comments`, + // `discard_comments` should have an iterator. But it does not contain + // anything, so we need to add an iterator that points nothing. + // + // It always points null, so DO NOT unwrap this iterator. It always crashes + // your program. + template + struct empty_iterator { + using value_type = T; + using reference_type = typename std::conditional::type; + using pointer_type = typename std::conditional::type; + using difference_type = std::ptrdiff_t; + using iterator_category = std::random_access_iterator_tag; + + empty_iterator() = default; + ~empty_iterator() = default; + empty_iterator(const empty_iterator&) = default; + empty_iterator(empty_iterator&&) = default; + empty_iterator& operator=(const empty_iterator&) = default; + empty_iterator& operator=(empty_iterator&&) = default; + + // DO NOT call these operators. + reference_type operator*() const noexcept { + std::terminate(); + } + + pointer_type operator->() const noexcept { + return nullptr; + } + + reference_type operator[](difference_type) const noexcept { + return this->operator*(); + } + + // These operators do nothing. + empty_iterator& operator++() noexcept { + return *this; + } + + empty_iterator operator++(int) noexcept { + return *this; + } + + empty_iterator& operator--() noexcept { + return *this; + } + + empty_iterator operator--(int) noexcept { + return *this; + } + + empty_iterator& operator+=(difference_type) noexcept { + return *this; + } + + empty_iterator& operator-=(difference_type) noexcept { + return *this; + } + + empty_iterator operator+(difference_type) const noexcept { + return *this; + } + + empty_iterator operator-(difference_type) const noexcept { + return *this; + } + }; + + template + bool operator==(const empty_iterator&, + const empty_iterator&) noexcept { + return true; + } + + template + bool operator!=(const empty_iterator&, + const empty_iterator&) noexcept { + return false; + } + + template + bool operator<(const empty_iterator&, + const empty_iterator&) noexcept { + return false; + } + + template + bool operator<=(const empty_iterator&, + const empty_iterator&) noexcept { + return true; + } + + template + bool operator>(const empty_iterator&, + const empty_iterator&) noexcept { + return false; + } + + template + bool operator>=(const empty_iterator&, + const empty_iterator&) noexcept { + return true; + } + + template + typename empty_iterator::difference_type operator-( + const empty_iterator&, + const empty_iterator&) noexcept { + return 0; + } + + template + empty_iterator operator+(typename empty_iterator::difference_type, + const empty_iterator& rhs) noexcept { + return rhs; + } + + template + empty_iterator operator+( + const empty_iterator& lhs, + typename empty_iterator::difference_type) noexcept { + return lhs; + } + + } // namespace detail + + // The default comment type. It discards all the comments. It requires only one + // byte to contain, so the memory footprint is smaller than preserve_comments. + // + // It just ignores `push_back`, `insert`, `erase`, and any other modifications. + // IT always returns size() == 0, the iterator taken by `begin()` is always the + // same as that of `end()`, and accessing through `operator[]` or iterators + // always causes a segmentation fault. DO NOT access to the element of this. + // + // Why this is chose as the default type is because the last version (2.x.y) + // does not contain any comments in a value. To minimize the impact on the + // efficiency, this is chosen as a default. + // + // To reduce the memory footprint, later we can try empty base optimization (EBO). + class discard_comments { + public: + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; + using value_type = std::string; + using reference = std::string&; + using const_reference = const std::string&; + using pointer = std::string*; + using const_pointer = const std::string*; + using iterator = detail::empty_iterator; + using const_iterator = detail::empty_iterator; + using reverse_iterator = detail::empty_iterator; + using const_reverse_iterator = detail::empty_iterator; + + public: + discard_comments() = default; + ~discard_comments() = default; + discard_comments(const discard_comments&) = default; + discard_comments(discard_comments&&) = default; + discard_comments& operator=(const discard_comments&) = default; + discard_comments& operator=(discard_comments&&) = default; + + explicit discard_comments(const std::vector&) noexcept {} + + explicit discard_comments(std::vector&&) noexcept {} + + discard_comments& operator=(const std::vector&) noexcept { + return *this; + } + + discard_comments& operator=(std::vector&&) noexcept { + return *this; + } + + explicit discard_comments(const preserve_comments&) noexcept {} + + explicit discard_comments(size_type) noexcept {} + + discard_comments(size_type, const std::string&) noexcept {} + + discard_comments(std::initializer_list) noexcept {} + + template + discard_comments(InputIterator, InputIterator) noexcept {} + + template + void assign(InputIterator, InputIterator) noexcept {} + + void assign(std::initializer_list) noexcept {} + + void assign(size_type, const std::string&) noexcept {} + + iterator insert(const_iterator, const std::string&) { + return iterator {}; + } + + iterator insert(const_iterator, std::string&&) { + return iterator {}; + } + + iterator insert(const_iterator, size_type, const std::string&) { + return iterator {}; + } + + template + iterator insert(const_iterator, InputIterator, InputIterator) { + return iterator {}; + } + + iterator insert(const_iterator, std::initializer_list) { + return iterator {}; + } + + template + iterator emplace(const_iterator, Ts&&...) { + return iterator {}; + } + + iterator erase(const_iterator) { + return iterator {}; + } + + iterator erase(const_iterator, const_iterator) { + return iterator {}; + } + + void swap(discard_comments&) { + return; + } + + void push_back(const std::string&) { + return; + } + + void push_back(std::string&&) { + return; + } + + void pop_back() { + return; + } + + template + void emplace_back(Ts&&...) { + return; + } + + void clear() { + return; + } + + size_type size() const noexcept { + return 0; + } + + size_type max_size() const noexcept { + return 0; + } + + size_type capacity() const noexcept { + return 0; + } + + bool empty() const noexcept { + return true; + } + + void reserve(size_type) { + return; + } + + void resize(size_type) { + return; + } + + void resize(size_type, const std::string&) { + return; + } + + void shrink_to_fit() { + return; + } + + // DO NOT access to the element of this container. This container is always + // empty, so accessing through operator[], front/back, data causes address + // error. + + reference operator[](const size_type) noexcept { + never_call("toml::discard_comment::operator[]"); + } + + const_reference operator[](const size_type) const noexcept { + never_call("toml::discard_comment::operator[]"); + } + + reference at(const size_type) { + throw std::out_of_range("toml::discard_comment is always empty."); + } + + const_reference at(const size_type) const { + throw std::out_of_range("toml::discard_comment is always empty."); + } + + reference front() noexcept { + never_call("toml::discard_comment::front"); + } + + const_reference front() const noexcept { + never_call("toml::discard_comment::front"); + } + + reference back() noexcept { + never_call("toml::discard_comment::back"); + } + + const_reference back() const noexcept { + never_call("toml::discard_comment::back"); + } + + pointer data() noexcept { + return nullptr; + } + + const_pointer data() const noexcept { + return nullptr; + } + + iterator begin() noexcept { + return iterator {}; + } + + iterator end() noexcept { + return iterator {}; + } + + const_iterator begin() const noexcept { + return const_iterator {}; + } + + const_iterator end() const noexcept { + return const_iterator {}; + } + + const_iterator cbegin() const noexcept { + return const_iterator {}; + } + + const_iterator cend() const noexcept { + return const_iterator {}; + } + + reverse_iterator rbegin() noexcept { + return iterator {}; + } + + reverse_iterator rend() noexcept { + return iterator {}; + } + + const_reverse_iterator rbegin() const noexcept { + return const_iterator {}; + } + + const_reverse_iterator rend() const noexcept { + return const_iterator {}; + } + + const_reverse_iterator crbegin() const noexcept { + return const_iterator {}; + } + + const_reverse_iterator crend() const noexcept { + return const_iterator {}; + } + + private: + [[noreturn]] + static void never_call(const char* const this_function) { + #if __has_builtin(__builtin_unreachable) + __builtin_unreachable(); + #endif + throw std::logic_error { this_function }; + } + }; + + inline bool operator==(const discard_comments&, const discard_comments&) noexcept { + return true; + } + + inline bool operator!=(const discard_comments&, const discard_comments&) noexcept { + return false; + } + + inline bool operator<(const discard_comments&, const discard_comments&) noexcept { + return false; + } + + inline bool operator<=(const discard_comments&, const discard_comments&) noexcept { + return true; + } + + inline bool operator>(const discard_comments&, const discard_comments&) noexcept { + return false; + } + + inline bool operator>=(const discard_comments&, const discard_comments&) noexcept { + return true; + } + + inline void swap(const discard_comments&, const discard_comments&) noexcept { + return; + } + + inline std::ostream& operator<<(std::ostream& os, const discard_comments&) { + return os; + } + +} // namespace toml +#endif // TOML11_COMMENTS_FWD_HPP + +#if !defined(TOML11_COMPILE_SOURCES) + #ifndef TOML11_COMMENTS_IMPL_HPP + #define TOML11_COMMENTS_IMPL_HPP + +namespace toml { + + TOML11_INLINE bool operator==(const preserve_comments& lhs, + const preserve_comments& rhs) { + return lhs.comments == rhs.comments; + } + + TOML11_INLINE bool operator!=(const preserve_comments& lhs, + const preserve_comments& rhs) { + return lhs.comments != rhs.comments; + } + + TOML11_INLINE bool operator<(const preserve_comments& lhs, + const preserve_comments& rhs) { + return lhs.comments < rhs.comments; + } + + TOML11_INLINE bool operator<=(const preserve_comments& lhs, + const preserve_comments& rhs) { + return lhs.comments <= rhs.comments; + } + + TOML11_INLINE bool operator>(const preserve_comments& lhs, + const preserve_comments& rhs) { + return lhs.comments > rhs.comments; + } + + TOML11_INLINE bool operator>=(const preserve_comments& lhs, + const preserve_comments& rhs) { + return lhs.comments >= rhs.comments; + } + + TOML11_INLINE void swap(preserve_comments& lhs, preserve_comments& rhs) { + lhs.swap(rhs); + return; + } + + TOML11_INLINE void swap(preserve_comments& lhs, std::vector& rhs) { + lhs.comments.swap(rhs); + return; + } + + TOML11_INLINE void swap(std::vector& lhs, preserve_comments& rhs) { + lhs.swap(rhs.comments); + return; + } + + TOML11_INLINE std::ostream& operator<<(std::ostream& os, + const preserve_comments& com) { + for (const auto& c : com) { + if (c.front() != '#') { + os << '#'; + } + os << c << '\n'; + } + return os; + } + +} // namespace toml + #endif // TOML11_COMMENTS_IMPL_HPP +#endif + +#endif // TOML11_COMMENTS_HPP +#ifndef TOML11_COLOR_HPP +#define TOML11_COLOR_HPP + +#ifndef TOML11_COLOR_FWD_HPP + #define TOML11_COLOR_FWD_HPP + + #include + + #ifdef TOML11_COLORIZE_ERROR_MESSAGE + #define TOML11_ERROR_MESSAGE_COLORIZED true + #else + #define TOML11_ERROR_MESSAGE_COLORIZED false + #endif + + #ifdef TOML11_USE_THREAD_LOCAL_COLORIZATION + #define TOML11_THREAD_LOCAL_COLORIZATION thread_local + #else + #define TOML11_THREAD_LOCAL_COLORIZATION + #endif + +namespace toml { + namespace color { + // put ANSI escape sequence to ostream + inline namespace ansi { + namespace detail { + + // Control color mode globally + class color_mode { + public: + void enable() noexcept { + should_color_ = true; + } + + void disable() noexcept { + should_color_ = false; + } + + bool should_color() const noexcept { + return should_color_; + } + + private: + bool should_color_ = TOML11_ERROR_MESSAGE_COLORIZED; + }; + + inline color_mode& color_status() noexcept { + static TOML11_THREAD_LOCAL_COLORIZATION color_mode status; + return status; + } + + } // namespace detail + + std::ostream& reset(std::ostream& os); + std::ostream& bold(std::ostream& os); + std::ostream& grey(std::ostream& os); + std::ostream& gray(std::ostream& os); + std::ostream& red(std::ostream& os); + std::ostream& green(std::ostream& os); + std::ostream& yellow(std::ostream& os); + std::ostream& blue(std::ostream& os); + std::ostream& magenta(std::ostream& os); + std::ostream& cyan(std::ostream& os); + std::ostream& white(std::ostream& os); + + } // namespace ansi + + inline void enable() { + return detail::color_status().enable(); + } + + inline void disable() { + return detail::color_status().disable(); + } + + inline bool should_color() { + return detail::color_status().should_color(); + } + + } // namespace color +} // namespace toml +#endif // TOML11_COLOR_FWD_HPP + +#if !defined(TOML11_COMPILE_SOURCES) + #ifndef TOML11_COLOR_IMPL_HPP + #define TOML11_COLOR_IMPL_HPP + + #include + +namespace toml { + namespace color { + // put ANSI escape sequence to ostream + inline namespace ansi { + + TOML11_INLINE std::ostream& reset(std::ostream& os) { + if (detail::color_status().should_color()) { + os << "\033[00m"; + } + return os; + } + + TOML11_INLINE std::ostream& bold(std::ostream& os) { + if (detail::color_status().should_color()) { + os << "\033[01m"; + } + return os; + } + + TOML11_INLINE std::ostream& grey(std::ostream& os) { + if (detail::color_status().should_color()) { + os << "\033[30m"; + } + return os; + } + + TOML11_INLINE std::ostream& gray(std::ostream& os) { + if (detail::color_status().should_color()) { + os << "\033[30m"; + } + return os; + } + + TOML11_INLINE std::ostream& red(std::ostream& os) { + if (detail::color_status().should_color()) { + os << "\033[31m"; + } + return os; + } + + TOML11_INLINE std::ostream& green(std::ostream& os) { + if (detail::color_status().should_color()) { + os << "\033[32m"; + } + return os; + } + + TOML11_INLINE std::ostream& yellow(std::ostream& os) { + if (detail::color_status().should_color()) { + os << "\033[33m"; + } + return os; + } + + TOML11_INLINE std::ostream& blue(std::ostream& os) { + if (detail::color_status().should_color()) { + os << "\033[34m"; + } + return os; + } + + TOML11_INLINE std::ostream& magenta(std::ostream& os) { + if (detail::color_status().should_color()) { + os << "\033[35m"; + } + return os; + } + + TOML11_INLINE std::ostream& cyan(std::ostream& os) { + if (detail::color_status().should_color()) { + os << "\033[36m"; + } + return os; + } + + TOML11_INLINE std::ostream& white(std::ostream& os) { + if (detail::color_status().should_color()) { + os << "\033[37m"; + } + return os; + } + + } // namespace ansi + } // namespace color +} // namespace toml + #endif // TOML11_COLOR_IMPL_HPP +#endif + +#endif // TOML11_COLOR_HPP +#ifndef TOML11_SPEC_HPP +#define TOML11_SPEC_HPP + +#include +#include +#include + +namespace toml { + + struct semantic_version { + constexpr semantic_version(std::uint32_t mjr, + std::uint32_t mnr, + std::uint32_t p) noexcept + : major { mjr } + , minor { mnr } + , patch { p } {} + + std::uint32_t major; + std::uint32_t minor; + std::uint32_t patch; + }; + + constexpr inline semantic_version make_semver(std::uint32_t mjr, + std::uint32_t mnr, + std::uint32_t p) noexcept { + return semantic_version(mjr, mnr, p); + } + + constexpr inline bool operator==(const semantic_version& lhs, + const semantic_version& rhs) noexcept { + return lhs.major == rhs.major && lhs.minor == rhs.minor && + lhs.patch == rhs.patch; + } + + constexpr inline bool operator!=(const semantic_version& lhs, + const semantic_version& rhs) noexcept { + return !(lhs == rhs); + } + + constexpr inline bool operator<(const semantic_version& lhs, + const semantic_version& rhs) noexcept { + return lhs.major < rhs.major || + (lhs.major == rhs.major && lhs.minor < rhs.minor) || + (lhs.major == rhs.major && lhs.minor == rhs.minor && + lhs.patch < rhs.patch); + } + + constexpr inline bool operator>(const semantic_version& lhs, + const semantic_version& rhs) noexcept { + return rhs < lhs; + } + + constexpr inline bool operator<=(const semantic_version& lhs, + const semantic_version& rhs) noexcept { + return !(lhs > rhs); + } + + constexpr inline bool operator>=(const semantic_version& lhs, + const semantic_version& rhs) noexcept { + return !(lhs < rhs); + } + + inline std::ostream& operator<<(std::ostream& os, const semantic_version& v) { + os << v.major << '.' << v.minor << '.' << v.patch; + return os; + } + + inline std::string to_string(const semantic_version& v) { + std::ostringstream oss; + oss << v; + return oss.str(); + } + + struct spec { + constexpr static spec default_version() noexcept { + return spec::v(1, 0, 0); + } + + constexpr static spec v(std::uint32_t mjr, + std::uint32_t mnr, + std::uint32_t p) noexcept { + return spec(make_semver(mjr, mnr, p)); + } + + constexpr explicit spec(const semantic_version& semver) noexcept + : version{semver}, + v1_1_0_allow_control_characters_in_comments {semantic_version{1, 1, 0} <= semver}, + v1_1_0_allow_newlines_in_inline_tables {semantic_version{1, 1, 0} <= semver}, + v1_1_0_allow_trailing_comma_in_inline_tables{semantic_version{1, 1, 0} <= semver}, + v1_1_0_allow_non_english_in_bare_keys {semantic_version{1, 1, 0} <= semver}, + v1_1_0_add_escape_sequence_e {semantic_version{1, 1, 0} <= semver}, + v1_1_0_add_escape_sequence_x {semantic_version{1, 1, 0} <= semver}, + v1_1_0_make_seconds_optional {semantic_version{1, 1, 0} <= semver}, + ext_hex_float {false}, + ext_num_suffix{false}, + ext_null_value{false} + {} + + semantic_version version; // toml version + + // diff from v1.0.0 -> v1.1.0 + bool v1_1_0_allow_control_characters_in_comments; + bool v1_1_0_allow_newlines_in_inline_tables; + bool v1_1_0_allow_trailing_comma_in_inline_tables; + bool v1_1_0_allow_non_english_in_bare_keys; + bool v1_1_0_add_escape_sequence_e; + bool v1_1_0_add_escape_sequence_x; + bool v1_1_0_make_seconds_optional; + + // library extensions + bool ext_hex_float; // allow hex float (in C++ style) + bool ext_num_suffix; // allow number suffix (in C++ style) + bool ext_null_value; // allow `null` as a value + }; + +} // namespace toml +#endif // TOML11_SPEC_HPP +#ifndef TOML11_ORDERED_MAP_HPP +#define TOML11_ORDERED_MAP_HPP + +#include +#include +#include +#include + +namespace toml { + + namespace detail { + template + struct ordered_map_ebo_container { + Cmp cmp_; // empty base optimization for empty Cmp type + }; + } // namespace detail + + template , + typename Allocator = std::allocator>> + class ordered_map : detail::ordered_map_ebo_container { + public: + using key_type = Key; + using mapped_type = Val; + using value_type = std::pair; + + using key_compare = Cmp; + using allocator_type = Allocator; + + using container_type = std::vector; + using reference = typename container_type::reference; + using pointer = typename container_type::pointer; + using const_reference = typename container_type::const_reference; + using const_pointer = typename container_type::const_pointer; + using iterator = typename container_type::iterator; + using const_iterator = typename container_type::const_iterator; + using size_type = typename container_type::size_type; + using difference_type = typename container_type::difference_type; + + private: + using ebo_base = detail::ordered_map_ebo_container; + + public: + ordered_map() = default; + ~ordered_map() = default; + ordered_map(const ordered_map&) = default; + ordered_map(ordered_map&&) = default; + ordered_map& operator=(const ordered_map&) = default; + ordered_map& operator=(ordered_map&&) = default; + + ordered_map(const ordered_map& other, const Allocator& alloc) + : container_(other.container_, alloc) {} + + ordered_map(ordered_map&& other, const Allocator& alloc) + : container_(std::move(other.container_), alloc) {} + + explicit ordered_map(const Cmp& cmp, const Allocator& alloc = Allocator()) + : ebo_base { cmp } + , container_(alloc) {} + + explicit ordered_map(const Allocator& alloc) : container_(alloc) {} + + template + ordered_map(InputIterator first, + InputIterator last, + const Cmp& cmp = Cmp(), + const Allocator& alloc = Allocator()) + : ebo_base { cmp } + , container_(first, last, alloc) {} + + template + ordered_map(InputIterator first, InputIterator last, const Allocator& alloc) + : container_(first, last, alloc) {} + + ordered_map(std::initializer_list v, + const Cmp& cmp = Cmp(), + const Allocator& alloc = Allocator()) + : ebo_base { cmp } + , container_(std::move(v), alloc) {} + + ordered_map(std::initializer_list v, const Allocator& alloc) + : container_(std::move(v), alloc) {} + + ordered_map& operator=(std::initializer_list v) { + this->container_ = std::move(v); + return *this; + } + + iterator begin() noexcept { + return container_.begin(); + } + + iterator end() noexcept { + return container_.end(); + } + + const_iterator begin() const noexcept { + return container_.begin(); + } + + const_iterator end() const noexcept { + return container_.end(); + } + + const_iterator cbegin() const noexcept { + return container_.cbegin(); + } + + const_iterator cend() const noexcept { + return container_.cend(); + } + + bool empty() const noexcept { + return container_.empty(); + } + + std::size_t size() const noexcept { + return container_.size(); + } + + std::size_t max_size() const noexcept { + return container_.max_size(); + } + + void clear() { + container_.clear(); + } + + void push_back(const value_type& v) { + if (this->contains(v.first)) { + throw std::out_of_range("ordered_map: value already exists"); + } + container_.push_back(v); + } + + void push_back(value_type&& v) { + if (this->contains(v.first)) { + throw std::out_of_range("ordered_map: value already exists"); + } + container_.push_back(std::move(v)); + } + + void emplace_back(key_type k, mapped_type v) { + if (this->contains(k)) { + throw std::out_of_range("ordered_map: value already exists"); + } + container_.emplace_back(std::move(k), std::move(v)); + } + + void pop_back() { + container_.pop_back(); + } + + void insert(value_type kv) { + if (this->contains(kv.first)) { + throw std::out_of_range("ordered_map: value already exists"); + } + container_.push_back(std::move(kv)); + } + + void emplace(key_type k, mapped_type v) { + if (this->contains(k)) { + throw std::out_of_range("ordered_map: value already exists"); + } + container_.emplace_back(std::move(k), std::move(v)); + } + + std::size_t count(const key_type& key) const { + if (this->find(key) != this->end()) { + return 1; + } else { + return 0; + } + } + + bool contains(const key_type& key) const { + return this->find(key) != this->end(); + } + + iterator find(const key_type& key) noexcept { + return std::find_if(this->begin(), + this->end(), + [&key, this](const value_type& v) { + return this->cmp_(v.first, key); + }); + } + + const_iterator find(const key_type& key) const noexcept { + return std::find_if(this->begin(), + this->end(), + [&key, this](const value_type& v) { + return this->cmp_(v.first, key); + }); + } + + mapped_type& at(const key_type& k) { + const auto iter = this->find(k); + if (iter == this->end()) { + throw std::out_of_range("ordered_map: no such element"); + } + return iter->second; + } + + const mapped_type& at(const key_type& k) const { + const auto iter = this->find(k); + if (iter == this->end()) { + throw std::out_of_range("ordered_map: no such element"); + } + return iter->second; + } + + mapped_type& operator[](const key_type& k) { + const auto iter = this->find(k); + if (iter == this->end()) { + this->container_.emplace_back(k, mapped_type {}); + return this->container_.back().second; + } + return iter->second; + } + + const mapped_type& operator[](const key_type& k) const { + const auto iter = this->find(k); + if (iter == this->end()) { + throw std::out_of_range("ordered_map: no such element"); + } + return iter->second; + } + + key_compare key_comp() const { + return this->cmp_; + } + + void swap(ordered_map& other) { + container_.swap(other.container_); + } + + private: + container_type container_; + }; + + template + bool operator==(const ordered_map& lhs, + const ordered_map& rhs) { + return lhs.size() == rhs.size() && + std::equal(lhs.begin(), lhs.end(), rhs.begin()); + } + + template + bool operator!=(const ordered_map& lhs, + const ordered_map& rhs) { + return !(lhs == rhs); + } + + template + bool operator<(const ordered_map& lhs, + const ordered_map& rhs) { + return std::lexicographical_compare(lhs.begin(), + lhs.end(), + rhs.begin(), + rhs.end()); + } + + template + bool operator>(const ordered_map& lhs, + const ordered_map& rhs) { + return rhs < lhs; + } + + template + bool operator<=(const ordered_map& lhs, + const ordered_map& rhs) { + return !(lhs > rhs); + } + + template + bool operator>=(const ordered_map& lhs, + const ordered_map& rhs) { + return !(lhs < rhs); + } + + template + void swap(ordered_map& lhs, ordered_map& rhs) { + lhs.swap(rhs); + return; + } + +} // namespace toml +#endif // TOML11_ORDERED_MAP_HPP +#ifndef TOML11_INTO_HPP +#define TOML11_INTO_HPP + +namespace toml { + + template + struct into; + // { + // static toml::value into_toml(const T& user_defined_type) + // { + // // User-defined conversions ... + // } + // }; + +} // namespace toml +#endif // TOML11_INTO_HPP +#ifndef TOML11_FROM_HPP +#define TOML11_FROM_HPP + +namespace toml { + + template + struct from; + // { + // static T from_toml(const toml::value& v) + // { + // // User-defined conversions ... + // } + // }; + +} // namespace toml +#endif // TOML11_FROM_HPP +#ifndef TOML11_TRAITS_HPP +#define TOML11_TRAITS_HPP + +#include +#include +#include +#include +#include +#include +#include + +#if defined(TOML11_HAS_STRING_VIEW) + #include +#endif + +namespace toml { + template + class basic_value; + + namespace detail { + // --------------------------------------------------------------------------- + // check whether type T is a kind of container/map class + + struct has_iterator_impl { + template + static std::true_type check(typename T::iterator*); + template + static std::false_type check(...); + }; + + struct has_value_type_impl { + template + static std::true_type check(typename T::value_type*); + template + static std::false_type check(...); + }; + + struct has_key_type_impl { + template + static std::true_type check(typename T::key_type*); + template + static std::false_type check(...); + }; + + struct has_mapped_type_impl { + template + static std::true_type check(typename T::mapped_type*); + template + static std::false_type check(...); + }; + + struct has_reserve_method_impl { + template + static std::false_type check(...); + template + static std::true_type check( + decltype(std::declval().reserve(std::declval()))*); + }; + + struct has_push_back_method_impl { + template + static std::false_type check(...); + template + static std::true_type check(decltype(std::declval().push_back( + std::declval()))*); + }; + + struct is_comparable_impl { + template + static std::false_type check(...); + template + static std::true_type check(decltype(std::declval() < std::declval())*); + }; + + struct has_from_toml_method_impl { + template + static std::true_type check(decltype(std::declval().from_toml( + std::declval<::toml::basic_value>()))*); + + template + static std::false_type check(...); + }; + + struct has_into_toml_method_impl { + template + static std::true_type check(decltype(std::declval().into_toml())*); + template + static std::false_type check(...); + }; + + struct has_template_into_toml_method_impl { + template + static std::true_type check( + decltype(std::declval().template into_toml())*); + template + static std::false_type check(...); + }; + + struct has_specialized_from_impl { + template + static std::false_type check(...); + template )> + static std::true_type check(::toml::from*); + }; + + struct has_specialized_into_impl { + template + static std::false_type check(...); + template )> + static std::true_type check(::toml::into*); + }; + +/// Intel C++ compiler can not use decltype in parent class declaration, here +/// is a hack to work around it. https://stackoverflow.com/a/23953090/4692076 +#ifdef __INTEL_COMPILER + #define decltype(...) std::enable_if::type +#endif + + template + struct has_iterator : decltype(has_iterator_impl::check(nullptr)) {}; + + template + struct has_value_type : decltype(has_value_type_impl::check(nullptr)) {}; + + template + struct has_key_type : decltype(has_key_type_impl::check(nullptr)) {}; + + template + struct has_mapped_type : decltype(has_mapped_type_impl::check(nullptr)) {}; + + template + struct has_reserve_method + : decltype(has_reserve_method_impl::check(nullptr)) {}; + + template + struct has_push_back_method + : decltype(has_push_back_method_impl::check(nullptr)) {}; + + template + struct is_comparable : decltype(is_comparable_impl::check(nullptr)) {}; + + template + struct has_from_toml_method + : decltype(has_from_toml_method_impl::check(nullptr)) {}; + + template + struct has_into_toml_method + : decltype(has_into_toml_method_impl::check(nullptr)) {}; + + template + struct has_template_into_toml_method + : decltype(has_template_into_toml_method_impl::check(nullptr)) { + }; + + template + struct has_specialized_from + : decltype(has_specialized_from_impl::check(nullptr)) {}; + + template + struct has_specialized_into + : decltype(has_specialized_into_impl::check(nullptr)) {}; + +#ifdef __INTEL_COMPILER + #undef decltype +#endif + + // --------------------------------------------------------------------------- + // type checkers + + template + struct is_std_pair_impl : std::false_type {}; + + template + struct is_std_pair_impl> : std::true_type {}; + + template + using is_std_pair = is_std_pair_impl>; + + template + struct is_std_tuple_impl : std::false_type {}; + + template + struct is_std_tuple_impl> : std::true_type {}; + + template + using is_std_tuple = is_std_tuple_impl>; + + template + struct is_std_array_impl : std::false_type {}; + + template + struct is_std_array_impl> : std::true_type {}; + + template + using is_std_array = is_std_array_impl>; + + template + struct is_std_forward_list_impl : std::false_type {}; + + template + struct is_std_forward_list_impl> : std::true_type {}; + + template + using is_std_forward_list = is_std_forward_list_impl>; + + template + struct is_std_basic_string_impl : std::false_type {}; + + template + struct is_std_basic_string_impl> : std::true_type { + }; + + template + using is_std_basic_string = is_std_basic_string_impl>; + + template + struct is_1byte_std_basic_string_impl : std::false_type {}; + + template + struct is_1byte_std_basic_string_impl> + : std::integral_constant {}; + + template + using is_1byte_std_basic_string = is_std_basic_string_impl>; + +#if defined(TOML11_HAS_STRING_VIEW) + template + struct is_std_basic_string_view_impl : std::false_type {}; + + template + struct is_std_basic_string_view_impl> + : std::true_type {}; + + template + using is_std_basic_string_view = + is_std_basic_string_view_impl>; + + template + struct is_string_view_of : std::false_type {}; + + template + struct is_string_view_of, std::basic_string> + : std::true_type {}; +#endif + + template + struct is_chrono_duration_impl : std::false_type {}; + + template + struct is_chrono_duration_impl> + : std::true_type {}; + + template + using is_chrono_duration = is_chrono_duration_impl>; + + template + struct is_map_impl + : cxx::conjunction< // map satisfies all the following conditions + has_iterator, // has T::iterator + has_value_type, // has T::value_type + has_key_type, // has T::key_type + has_mapped_type // has T::mapped_type + > {}; + + template + using is_map = is_map_impl>; + + template + struct is_container_impl + : cxx::conjunction>, // not a map + cxx::negation>, // not a std::string +#ifdef TOML11_HAS_STRING_VIEW + cxx::negation>, // not a std::string_view +#endif + has_iterator, // has T::iterator + has_value_type // has T::value_type + > { + }; + + template + using is_container = is_container_impl>; + + template + struct is_basic_value_impl : std::false_type {}; + + template + struct is_basic_value_impl<::toml::basic_value> : std::true_type {}; + + template + using is_basic_value = is_basic_value_impl>; + + } // namespace detail +} // namespace toml +#endif // TOML11_TRAITS_HPP +#ifndef TOML11_EXCEPTION_HPP +#define TOML11_EXCEPTION_HPP + +#include + +namespace toml { + + struct exception : public std::exception { + public: + virtual ~exception() noexcept override = default; + + virtual const char* what() const noexcept override { + return ""; + } + }; + +} // namespace toml +#endif // TOMl11_EXCEPTION_HPP +#ifndef TOML11_RESULT_HPP +#define TOML11_RESULT_HPP + +#include +#include +#include +#include +#include + +namespace toml { + + struct bad_result_access final : public ::toml::exception { + public: + explicit bad_result_access(std::string what_arg) + : what_(std::move(what_arg)) {} + + ~bad_result_access() noexcept override = default; + + const char* what() const noexcept override { + return what_.c_str(); + } + + private: + std::string what_; + }; + + // ----------------------------------------------------------------------------- + + template + struct success { + static_assert(!std::is_same::value, ""); + + using value_type = T; + + explicit success(value_type v) noexcept( + std::is_nothrow_move_constructible::value) + : value(std::move(v)) {} + + template , T>::value, + std::nullptr_t> = nullptr> + explicit success(U&& v) : value(std::forward(v)) {} + + template + explicit success(success v) : value(std::move(v.value)) {} + + ~success() = default; + success(const success&) = default; + success(success&&) = default; + success& operator=(const success&) = default; + success& operator=(success&&) = default; + + value_type& get() noexcept { + return value; + } + + const value_type& get() const noexcept { + return value; + } + + private: + value_type value; + }; + + template + struct success> { + static_assert(!std::is_same::value, ""); + + using value_type = T; + + explicit success(std::reference_wrapper v) noexcept + : value(std::move(v)) {} + + ~success() = default; + success(const success&) = default; + success(success&&) = default; + success& operator=(const success&) = default; + success& operator=(success&&) = default; + + value_type& get() noexcept { + return value.get(); + } + + const value_type& get() const noexcept { + return value.get(); + } + + private: + std::reference_wrapper value; + }; + + template + success::type> ok(T&& v) { + return success::type>(std::forward(v)); + } + + template + success ok(const char (&literal)[N]) { + return success(std::string(literal)); + } + + // ----------------------------------------------------------------------------- + + template + struct failure { + using value_type = T; + + explicit failure(value_type v) noexcept( + std::is_nothrow_move_constructible::value) + : value(std::move(v)) {} + + template , T>::value, + std::nullptr_t> = nullptr> + explicit failure(U&& v) : value(std::forward(v)) {} + + template + explicit failure(failure v) : value(std::move(v.value)) {} + + ~failure() = default; + failure(const failure&) = default; + failure(failure&&) = default; + failure& operator=(const failure&) = default; + failure& operator=(failure&&) = default; + + value_type& get() noexcept { + return value; + } + + const value_type& get() const noexcept { + return value; + } + + private: + value_type value; + }; + + template + struct failure> { + using value_type = T; + + explicit failure(std::reference_wrapper v) noexcept + : value(std::move(v)) {} + + ~failure() = default; + failure(const failure&) = default; + failure(failure&&) = default; + failure& operator=(const failure&) = default; + failure& operator=(failure&&) = default; + + value_type& get() noexcept { + return value.get(); + } + + const value_type& get() const noexcept { + return value.get(); + } + + private: + std::reference_wrapper value; + }; + + template + failure::type> err(T&& v) { + return failure::type>(std::forward(v)); + } + + template + failure err(const char (&literal)[N]) { + return failure(std::string(literal)); + } + + /* ============================================================================ + * _ _ + * _ _ ___ ____ _| | |_ + * | '_/ -_|_-< || | | _| + * |_| \___/__/\_,_|_|\__| + */ + + template + struct result { + using success_type = success; + using failure_type = failure; + using value_type = typename success_type::value_type; + using error_type = typename failure_type::value_type; + + result(success_type s) : is_ok_(true), succ_(std::move(s)) {} + + result(failure_type f) : is_ok_(false), fail_(std::move(f)) {} + + template < + typename U, + cxx::enable_if_t< + cxx::conjunction, value_type>>, + std::is_convertible, value_type>>::value, + std::nullptr_t> = nullptr> + result(success s) : is_ok_(true) + , succ_(std::move(s.value)) {} + + template < + typename U, + cxx::enable_if_t< + cxx::conjunction, error_type>>, + std::is_convertible, error_type>>::value, + std::nullptr_t> = nullptr> + result(failure f) : is_ok_(false) + , fail_(std::move(f.value)) {} + + result& operator=(success_type s) { + this->cleanup(); + this->is_ok_ = true; + auto tmp = ::new (std::addressof(this->succ_)) success_type(std::move(s)); + assert(tmp == std::addressof(this->succ_)); + (void)tmp; + return *this; + } + + result& operator=(failure_type f) { + this->cleanup(); + this->is_ok_ = false; + auto tmp = ::new (std::addressof(this->fail_)) failure_type(std::move(f)); + assert(tmp == std::addressof(this->fail_)); + (void)tmp; + return *this; + } + + template + result& operator=(success s) { + this->cleanup(); + this->is_ok_ = true; + auto tmp = ::new (std::addressof(this->succ_)) + success_type(std::move(s.value)); + assert(tmp == std::addressof(this->succ_)); + (void)tmp; + return *this; + } + + template + result& operator=(failure f) { + this->cleanup(); + this->is_ok_ = false; + auto tmp = ::new (std::addressof(this->fail_)) + failure_type(std::move(f.value)); + assert(tmp == std::addressof(this->fail_)); + (void)tmp; + return *this; + } + + ~result() noexcept { + this->cleanup(); + } + + result(const result& other) : is_ok_(other.is_ok()) { + if (other.is_ok()) { + auto tmp = ::new (std::addressof(this->succ_)) success_type(other.succ_); + assert(tmp == std::addressof(this->succ_)); + (void)tmp; + } else { + auto tmp = ::new (std::addressof(this->fail_)) failure_type(other.fail_); + assert(tmp == std::addressof(this->fail_)); + (void)tmp; + } + } + + result(result&& other) : is_ok_(other.is_ok()) { + if (other.is_ok()) { + auto tmp = ::new (std::addressof(this->succ_)) + success_type(std::move(other.succ_)); + assert(tmp == std::addressof(this->succ_)); + (void)tmp; + } else { + auto tmp = ::new (std::addressof(this->fail_)) + failure_type(std::move(other.fail_)); + assert(tmp == std::addressof(this->fail_)); + (void)tmp; + } + } + + result& operator=(const result& other) { + this->cleanup(); + if (other.is_ok()) { + auto tmp = ::new (std::addressof(this->succ_)) success_type(other.succ_); + assert(tmp == std::addressof(this->succ_)); + (void)tmp; + } else { + auto tmp = ::new (std::addressof(this->fail_)) failure_type(other.fail_); + assert(tmp == std::addressof(this->fail_)); + (void)tmp; + } + is_ok_ = other.is_ok(); + return *this; + } + + result& operator=(result&& other) { + this->cleanup(); + if (other.is_ok()) { + auto tmp = ::new (std::addressof(this->succ_)) + success_type(std::move(other.succ_)); + assert(tmp == std::addressof(this->succ_)); + (void)tmp; + } else { + auto tmp = ::new (std::addressof(this->fail_)) + failure_type(std::move(other.fail_)); + assert(tmp == std::addressof(this->fail_)); + (void)tmp; + } + is_ok_ = other.is_ok(); + return *this; + } + + template < + typename U, + typename F, + cxx::enable_if_t< + cxx::conjunction, value_type>>, + cxx::negation, error_type>>, + std::is_convertible, value_type>, + std::is_convertible, error_type>>::value, + std::nullptr_t> = nullptr> + result(result other) : is_ok_(other.is_ok()) { + if (other.is_ok()) { + auto tmp = ::new (std::addressof(this->succ_)) + success_type(std::move(other.as_ok())); + assert(tmp == std::addressof(this->succ_)); + (void)tmp; + } else { + auto tmp = ::new (std::addressof(this->fail_)) + failure_type(std::move(other.as_err())); + assert(tmp == std::addressof(this->fail_)); + (void)tmp; + } + } + + template < + typename U, + typename F, + cxx::enable_if_t< + cxx::conjunction, value_type>>, + cxx::negation, error_type>>, + std::is_convertible, value_type>, + std::is_convertible, error_type>>::value, + std::nullptr_t> = nullptr> + result& operator=(result other) { + this->cleanup(); + if (other.is_ok()) { + auto tmp = ::new (std::addressof(this->succ_)) + success_type(std::move(other.as_ok())); + assert(tmp == std::addressof(this->succ_)); + (void)tmp; + } else { + auto tmp = ::new (std::addressof(this->fail_)) + failure_type(std::move(other.as_err())); + assert(tmp == std::addressof(this->fail_)); + (void)tmp; + } + is_ok_ = other.is_ok(); + return *this; + } + + bool is_ok() const noexcept { + return is_ok_; + } + + bool is_err() const noexcept { + return !is_ok_; + } + + explicit operator bool() const noexcept { + return is_ok_; + } + + value_type& unwrap(cxx::source_location loc = cxx::source_location::current()) { + if (this->is_err()) { + throw bad_result_access("toml::result: bad unwrap" + cxx::to_string(loc)); + } + return this->succ_.get(); + } + + const value_type& unwrap( + cxx::source_location loc = cxx::source_location::current()) const { + if (this->is_err()) { + throw bad_result_access("toml::result: bad unwrap" + cxx::to_string(loc)); + } + return this->succ_.get(); + } + + value_type& unwrap_or(value_type& opt) noexcept { + if (this->is_err()) { + return opt; + } + return this->succ_.get(); + } + + const value_type& unwrap_or(const value_type& opt) const noexcept { + if (this->is_err()) { + return opt; + } + return this->succ_.get(); + } + + error_type& unwrap_err( + cxx::source_location loc = cxx::source_location::current()) { + if (this->is_ok()) { + throw bad_result_access( + "toml::result: bad unwrap_err" + cxx::to_string(loc)); + } + return this->fail_.get(); + } + + const error_type& unwrap_err( + cxx::source_location loc = cxx::source_location::current()) const { + if (this->is_ok()) { + throw bad_result_access( + "toml::result: bad unwrap_err" + cxx::to_string(loc)); + } + return this->fail_.get(); + } + + value_type& as_ok() noexcept { + assert(this->is_ok()); + return this->succ_.get(); + } + + const value_type& as_ok() const noexcept { + assert(this->is_ok()); + return this->succ_.get(); + } + + error_type& as_err() noexcept { + assert(this->is_err()); + return this->fail_.get(); + } + + const error_type& as_err() const noexcept { + assert(this->is_err()); + return this->fail_.get(); + } + + private: + void cleanup() noexcept { +#if defined(__GNUC__) && !defined(__clang__) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wduplicated-branches" +#endif + + if (this->is_ok_) { + this->succ_.~success_type(); + } else { + this->fail_.~failure_type(); + } + +#if defined(__GNUC__) && !defined(__clang__) + #pragma GCC diagnostic pop +#endif + return; + } + + private: + bool is_ok_; + + union { + success_type succ_; + failure_type fail_; + }; + }; + + // ---------------------------------------------------------------------------- + + namespace detail { + struct none_t {}; + + inline bool operator==(const none_t&, const none_t&) noexcept { + return true; + } + + inline bool operator!=(const none_t&, const none_t&) noexcept { + return false; + } + + inline bool operator<(const none_t&, const none_t&) noexcept { + return false; + } + + inline bool operator<=(const none_t&, const none_t&) noexcept { + return true; + } + + inline bool operator>(const none_t&, const none_t&) noexcept { + return false; + } + + inline bool operator>=(const none_t&, const none_t&) noexcept { + return true; + } + + inline std::ostream& operator<<(std::ostream& os, const none_t&) { + os << "none"; + return os; + } + } // namespace detail + + inline success ok() noexcept { + return success(detail::none_t {}); + } + + inline failure err() noexcept { + return failure(detail::none_t {}); + } + +} // namespace toml +#endif // TOML11_RESULT_HPP +#ifndef TOML11_UTILITY_HPP +#define TOML11_UTILITY_HPP + +#include +#include +#include +#include +#include + +namespace toml { + namespace detail { + + // to output character in an error message. + inline std::string show_char(const int c) { + using char_type = unsigned char; + if (std::isgraph(c)) { + return std::string(1, static_cast(c)); + } else { + std::array buf; + buf.fill('\0'); + const auto r = std::snprintf(buf.data(), buf.size(), "0x%02x", c & 0xFF); + assert(r == static_cast(buf.size()) - 1); + (void)r; // Unused variable warning + auto in_hex = std::string(buf.data()); + switch (c) { + case char_type('\0'): { + in_hex += "(NUL)"; + break; + } + case char_type(' '): { + in_hex += "(SPACE)"; + break; + } + case char_type('\n'): { + in_hex += "(LINE FEED)"; + break; + } + case char_type('\r'): { + in_hex += "(CARRIAGE RETURN)"; + break; + } + case char_type('\t'): { + in_hex += "(TAB)"; + break; + } + case char_type('\v'): { + in_hex += "(VERTICAL TAB)"; + break; + } + case char_type('\f'): { + in_hex += "(FORM FEED)"; + break; + } + case char_type('\x1B'): { + in_hex += "(ESCAPE)"; + break; + } + default: + break; + } + return in_hex; + } + } + + // --------------------------------------------------------------------------- + + template + void try_reserve_impl(Container& container, std::size_t N, std::true_type) { + container.reserve(N); + return; + } + + template + void try_reserve_impl(Container&, std::size_t, std::false_type) noexcept { + return; + } + + template + void try_reserve(Container& container, std::size_t N) { + try_reserve_impl(container, N, has_reserve_method {}); + return; + } + + // --------------------------------------------------------------------------- + + template + result from_string(const std::string& str) { + T v; + std::istringstream iss(str); + iss >> v; + if (iss.fail()) { + return err(); + } + return ok(v); + } + + // --------------------------------------------------------------------------- + + // helper function to avoid std::string(0, 'c') or std::string(iter, iter) + template + std::string make_string(Iterator first, Iterator last) { + if (first == last) { + return ""; + } + return std::string(first, last); + } + + inline std::string make_string(std::size_t len, char c) { + if (len == 0) { + return ""; + } + return std::string(len, c); + } + + // --------------------------------------------------------------------------- + + template + struct string_conv_impl { + static_assert(sizeof(Char) == sizeof(char), ""); + static_assert(sizeof(Char2) == sizeof(char), ""); + + static std::basic_string invoke( + std::basic_string s) { + std::basic_string retval; + std::transform(s.begin(), + s.end(), + std::back_inserter(retval), + [](const Char2 c) { + return static_cast(c); + }); + return retval; + } + + template + static std::basic_string invoke(const Char2 (&s)[N]) { + std::basic_string retval; + // "string literal" has null-char at the end. to skip it, we use prev. + std::transform(std::begin(s), + std::prev(std::end(s)), + std::back_inserter(retval), + [](const Char2 c) { + return static_cast(c); + }); + return retval; + } + }; + + template + struct string_conv_impl { + static_assert(sizeof(Char) == sizeof(char), ""); + + static std::basic_string invoke( + std::basic_string s) { + return s; + } + + template + static std::basic_string invoke(const Char (&s)[N]) { + return std::basic_string(s); + } + }; + + template + cxx::enable_if_t::value, S> string_conv( + std::basic_string s) { + using C = typename S::value_type; + using T = typename S::traits_type; + using A = typename S::allocator_type; + return string_conv_impl::invoke( + std::move(s)); + } + + template + cxx::enable_if_t::value, S> string_conv( + const char (&s)[N]) { + using C = typename S::value_type; + using T = typename S::traits_type; + using A = typename S::allocator_type; + using C2 = char; + using T2 = std::char_traits; + using A2 = std::allocator; + + return string_conv_impl::template invoke(s); + } + + } // namespace detail +} // namespace toml +#endif // TOML11_UTILITY_HPP +#ifndef TOML11_LOCATION_HPP +#define TOML11_LOCATION_HPP + +#ifndef TOML11_LOCATION_FWD_HPP + #define TOML11_LOCATION_FWD_HPP + + #include + #include + #include + +namespace toml { + namespace detail { + + class region; // fwd decl + + // + // To represent where we are reading in the parse functions. + // Since it "points" somewhere in the input stream, the length is always 1. + // + class location { + public: + using char_type = unsigned char; // must be unsigned + using container_type = std::vector; + using difference_type = + typename container_type::difference_type; // to suppress sign-conversion warning + using source_ptr = std::shared_ptr; + + public: + location(source_ptr src, std::string src_name) + : source_(std::move(src)) + , source_name_(std::move(src_name)) + , location_(0) + , line_number_(1) {} + + location(const location&) = default; + location(location&&) = default; + location& operator=(const location&) = default; + location& operator=(location&&) = default; + ~location() = default; + + void advance(std::size_t n = 1) noexcept; + void retrace(std::size_t n = 1) noexcept; + + bool is_ok() const noexcept { + return static_cast(this->source_); + } + + bool eof() const noexcept; + char_type current() const; + + char_type peek(); + + std::size_t get_location() const noexcept { + return this->location_; + } + + void set_location(const std::size_t loc) noexcept; + + std::size_t line_number() const noexcept { + return this->line_number_; + } + + std::string get_line() const; + std::size_t column_number() const noexcept; + + const source_ptr& source() const noexcept { + return this->source_; + } + + const std::string& source_name() const noexcept { + return this->source_name_; + } + + private: + void advance_line_number(const std::size_t n); + void retrace_line_number(const std::size_t n); + + private: + friend region; + + private: + source_ptr source_; + std::string source_name_; + std::size_t location_; // std::vector<>::difference_type is signed + std::size_t line_number_; + }; + + bool operator==(const location& lhs, const location& rhs) noexcept; + bool operator!=(const location& lhs, const location& rhs); + + location prev(const location& loc); + location next(const location& loc); + location make_temporary_location(const std::string& str) noexcept; + + template + result find_if(const location& first, + const location& last, + const F& func) noexcept { + if (first.source() != last.source()) { + return err(); + } + if (first.get_location() >= last.get_location()) { + return err(); + } + + auto loc = first; + while (loc.get_location() != last.get_location()) { + if (func(loc.current())) { + return ok(loc); + } + loc.advance(); + } + return err(); + } + + template + result rfind_if(location first, + const location& last, + const F& func) { + if (first.source() != last.source()) { + return err(); + } + if (first.get_location() >= last.get_location()) { + return err(); + } + + auto loc = last; + while (loc.get_location() != first.get_location()) { + if (func(loc.current())) { + return ok(loc); + } + loc.retrace(); + } + if (func(first.current())) { + return ok(first); + } + return err(); + } + + result find(const location& first, + const location& last, + const location::char_type val); + result rfind(const location& first, + const location& last, + const location::char_type val); + + std::size_t count(const location& first, + const location& last, + const location::char_type& c); + + } // namespace detail +} // namespace toml +#endif // TOML11_LOCATION_FWD_HPP + +#if !defined(TOML11_COMPILE_SOURCES) + #ifndef TOML11_LOCATION_IMPL_HPP + #define TOML11_LOCATION_IMPL_HPP + +namespace toml { + namespace detail { + + TOML11_INLINE void location::advance(std::size_t n) noexcept { + assert(this->is_ok()); + if (this->location_ + n < this->source_->size()) { + this->advance_line_number(n); + this->location_ += n; + } else { + this->advance_line_number(this->source_->size() - this->location_); + this->location_ = this->source_->size(); + } + } + + TOML11_INLINE void location::retrace(std::size_t n) noexcept { + assert(this->is_ok()); + if (this->location_ < n) { + this->location_ = 0; + this->line_number_ = 1; + } else { + this->retrace_line_number(n); + this->location_ -= n; + } + } + + TOML11_INLINE bool location::eof() const noexcept { + assert(this->is_ok()); + return this->location_ >= this->source_->size(); + } + + TOML11_INLINE location::char_type location::current() const { + assert(this->is_ok()); + if (this->eof()) { + return '\0'; + } + + assert(this->location_ < this->source_->size()); + return this->source_->at(this->location_); + } + + TOML11_INLINE location::char_type location::peek() { + assert(this->is_ok()); + if (this->location_ >= this->source_->size()) { + return '\0'; + } else { + return this->source_->at(this->location_ + 1); + } + } + + TOML11_INLINE void location::set_location(const std::size_t loc) noexcept { + if (this->location_ == loc) { + return; + } + + if (loc == 0) { + this->line_number_ = 1; + } else if (this->location_ < loc) { + const auto d = loc - this->location_; + this->advance_line_number(d); + } else { + const auto d = this->location_ - loc; + this->retrace_line_number(d); + } + this->location_ = loc; + } + + TOML11_INLINE std::string location::get_line() const { + assert(this->is_ok()); + const auto iter = std::next(this->source_->cbegin(), + static_cast(this->location_)); + const auto riter = cxx::make_reverse_iterator(iter); + + const auto prev = std::find(riter, this->source_->crend(), char_type('\n')); + const auto next = std::find(iter, this->source_->cend(), char_type('\n')); + + return make_string(std::next(prev.base()), next); + } + + TOML11_INLINE std::size_t location::column_number() const noexcept { + assert(this->is_ok()); + const auto iter = std::next(this->source_->cbegin(), + static_cast(this->location_)); + const auto riter = cxx::make_reverse_iterator(iter); + const auto prev = std::find(riter, this->source_->crend(), char_type('\n')); + + assert(prev.base() <= iter); + return static_cast(std::distance(prev.base(), iter) + 1); // 1-origin + } + + TOML11_INLINE void location::advance_line_number(const std::size_t n) { + assert(this->is_ok()); + assert(this->location_ + n <= this->source_->size()); + + const auto iter = this->source_->cbegin(); + this->line_number_ += static_cast(std::count( + std::next(iter, static_cast(this->location_)), + std::next(iter, static_cast(this->location_ + n)), + char_type('\n'))); + + return; + } + + TOML11_INLINE void location::retrace_line_number(const std::size_t n) { + assert(this->is_ok()); + assert(n <= this->location_); // loc - n >= 0 + + const auto iter = this->source_->cbegin(); + const auto dline_num = static_cast(std::count( + std::next(iter, static_cast(this->location_ - n)), + std::next(iter, static_cast(this->location_)), + char_type('\n'))); + + if (this->line_number_ <= dline_num) { + this->line_number_ = 1; + } else { + this->line_number_ -= dline_num; + } + return; + } + + TOML11_INLINE bool operator==(const location& lhs, const location& rhs) noexcept { + if (!lhs.is_ok() || !rhs.is_ok()) { + return (!lhs.is_ok()) && (!rhs.is_ok()); + } + return lhs.source() == rhs.source() && + lhs.source_name() == rhs.source_name() && + lhs.get_location() == rhs.get_location(); + } + + TOML11_INLINE bool operator!=(const location& lhs, const location& rhs) { + return !(lhs == rhs); + } + + TOML11_INLINE location prev(const location& loc) { + location p(loc); + p.retrace(1); + return p; + } + + TOML11_INLINE location next(const location& loc) { + location p(loc); + p.advance(1); + return p; + } + + TOML11_INLINE location make_temporary_location(const std::string& str) noexcept { + location::container_type cont(str.size()); + std::transform(str.begin(), + str.end(), + cont.begin(), + [](const std::string::value_type& c) { + return cxx::bit_cast(c); + }); + return location( + std::make_shared(std::move(cont)), + "internal temporary"); + } + + TOML11_INLINE result find(const location& first, + const location& last, + const location::char_type val) { + return find_if(first, last, [val](const location::char_type c) { + return c == val; + }); + } + + TOML11_INLINE result rfind(const location& first, + const location& last, + const location::char_type val) { + return rfind_if(first, last, [val](const location::char_type c) { + return c == val; + }); + } + + TOML11_INLINE std::size_t count(const location& first, + const location& last, + const location::char_type& c) { + if (first.source() != last.source()) { + return 0; + } + if (first.get_location() >= last.get_location()) { + return 0; + } + + auto loc = first; + std::size_t num = 0; + while (loc.get_location() != last.get_location()) { + if (loc.current() == c) { + num += 1; + } + loc.advance(); + } + return num; + } + + } // namespace detail +} // namespace toml + #endif // TOML11_LOCATION_HPP +#endif + +#endif // TOML11_LOCATION_HPP +#ifndef TOML11_REGION_HPP +#define TOML11_REGION_HPP + +#ifndef TOML11_REGION_FWD_HPP + #define TOML11_REGION_FWD_HPP + + #include + #include + #include + +namespace toml { + namespace detail { + + // + // To represent where is a toml::value defined, or where does an error occur. + // Stored in toml::value. source_location will be constructed based on this. + // + class region { + public: + using char_type = location::char_type; + using container_type = location::container_type; + using difference_type = location::difference_type; + using source_ptr = location::source_ptr; + + using iterator = typename container_type::iterator; + using const_iterator = typename container_type::const_iterator; + + public: + // a value that is constructed manually does not have input stream info + region() + : source_(nullptr) + , source_name_("") + , length_(0) + , first_line_(0) + , first_column_(0) + , last_line_(0) + , last_column_(0) {} + + // a value defined in [first, last). + // Those source must be the same. Instread, `region` does not make sense. + region(const location& first, const location& last); + + // shorthand of [loc, loc+1) + explicit region(const location& loc); + + ~region() = default; + region(const region&) = default; + region(region&&) = default; + region& operator=(const region&) = default; + region& operator=(region&&) = default; + + bool is_ok() const noexcept { + return static_cast(this->source_); + } + + operator bool() const noexcept { + return this->is_ok(); + } + + std::size_t length() const noexcept { + return this->length_; + } + + std::size_t first_line_number() const noexcept { + return this->first_line_; + } + + std::size_t first_column_number() const noexcept { + return this->first_column_; + } + + std::size_t last_line_number() const noexcept { + return this->last_line_; + } + + std::size_t last_column_number() const noexcept { + return this->last_column_; + } + + char_type at(std::size_t i) const; + + const_iterator begin() const noexcept; + const_iterator end() const noexcept; + const_iterator cbegin() const noexcept; + const_iterator cend() const noexcept; + + std::string as_string() const; + std::vector as_lines() const; + + const source_ptr& source() const noexcept { + return this->source_; + } + + const std::string& source_name() const noexcept { + return this->source_name_; + } + + private: + source_ptr source_; + std::string source_name_; + std::size_t length_; + std::size_t first_; + std::size_t first_line_; + std::size_t first_column_; + std::size_t last_; + std::size_t last_line_; + std::size_t last_column_; + }; + + } // namespace detail +} // namespace toml +#endif // TOML11_REGION_FWD_HPP + +#if !defined(TOML11_COMPILE_SOURCES) + #ifndef TOML11_REGION_IMPL_HPP + #define TOML11_REGION_IMPL_HPP + + #include + #include + #include + #include + #include + #include + +namespace toml { + namespace detail { + + // a value defined in [first, last). + // Those source must be the same. Instread, `region` does not make sense. + TOML11_INLINE region::region(const location& first, const location& last) + : source_(first.source()) + , source_name_(first.source_name()) + , length_(last.get_location() - first.get_location()) + , first_(first.get_location()) + , first_line_(first.line_number()) + , first_column_(first.column_number()) + , last_(last.get_location()) + , last_line_(last.line_number()) + , last_column_(last.column_number()) { + assert(first.source() == last.source()); + assert(first.source_name() == last.source_name()); + } + + // shorthand of [loc, loc+1) + TOML11_INLINE region::region(const location& loc) + : source_(loc.source()) + , source_name_(loc.source_name()) + , length_(0) + , first_line_(0) + , first_column_(0) + , last_line_(0) + , last_column_(0) { + // if the file ends with LF, the resulting region points no char. + if (loc.eof()) { + if (loc.get_location() == 0) { + this->length_ = 0; + this->first_ = 0; + this->first_line_ = 0; + this->first_column_ = 0; + this->last_ = 0; + this->last_line_ = 0; + this->last_column_ = 0; + } else { + const auto first = prev(loc); + this->first_ = first.get_location(); + this->first_line_ = first.line_number(); + this->first_column_ = first.column_number(); + this->last_ = loc.get_location(); + this->last_line_ = loc.line_number(); + this->last_column_ = loc.column_number(); + this->length_ = 1; + } + } else { + this->first_ = loc.get_location(); + this->first_line_ = loc.line_number(); + this->first_column_ = loc.column_number(); + this->last_ = loc.get_location() + 1; + this->last_line_ = loc.line_number(); + this->last_column_ = loc.column_number() + 1; + this->length_ = 1; + } + } + + TOML11_INLINE region::char_type region::at(std::size_t i) const { + if (this->last_ <= this->first_ + i) { + throw std::out_of_range("range::at: index " + std::to_string(i) + + " exceeds length " + std::to_string(this->length_)); + } + const auto iter = std::next(this->source_->cbegin(), + static_cast(this->first_ + i)); + return *iter; + } + + TOML11_INLINE region::const_iterator region::begin() const noexcept { + return std::next(this->source_->cbegin(), + static_cast(this->first_)); + } + + TOML11_INLINE region::const_iterator region::end() const noexcept { + return std::next(this->source_->cbegin(), + static_cast(this->last_)); + } + + TOML11_INLINE region::const_iterator region::cbegin() const noexcept { + return std::next(this->source_->cbegin(), + static_cast(this->first_)); + } + + TOML11_INLINE region::const_iterator region::cend() const noexcept { + return std::next(this->source_->cbegin(), + static_cast(this->last_)); + } + + TOML11_INLINE std::string region::as_string() const { + if (this->is_ok()) { + const auto begin = std::next(this->source_->cbegin(), + static_cast(this->first_)); + const auto end = std::next(this->source_->cbegin(), + static_cast(this->last_)); + return ::toml::detail::make_string(begin, end); + } else { + return std::string(""); + } + } + + TOML11_INLINE std::vector region::as_lines() const { + assert(this->is_ok()); + if (this->length_ == 0) { + return std::vector { "" }; + } + + // Consider the following toml file + // ``` + // array = [ + // ] # comment + // ``` + // and the region represnets + // ``` + // [ + // ] + // ``` + // but we want to show the following. + // ``` + // array = [ + // ] # comment + // ``` + // So we need to find LFs before `begin` and after `end`. + // + // But, if region ends with LF, it should not include the next line. + // ``` + // a = 42 + // ^^^- with the last LF + // ``` + // So we start from `end-1` when looking for LF. + + const auto begin_idx = static_cast(this->first_); + const auto end_idx = static_cast(this->last_) - 1; + + // length_ != 0, so begin < end. then begin <= end-1 + assert(begin_idx <= end_idx); + + const auto begin = std::next(this->source_->cbegin(), begin_idx); + const auto end = std::next(this->source_->cbegin(), end_idx); + + const auto line_begin = std::find(cxx::make_reverse_iterator(begin), + this->source_->crend(), + char_type('\n')) + .base(); + const auto line_end = std::find(end, this->source_->cend(), char_type('\n')); + + const auto reg_lines = make_string(line_begin, line_end); + + if (reg_lines == "") // the region is an empty line that only contains LF + { + return std::vector { "" }; + } + + std::istringstream iss(reg_lines); + + std::vector lines; + std::string line; + while (std::getline(iss, line)) { + lines.push_back(line); + } + return lines; + } + + } // namespace detail +} // namespace toml + #endif // TOML11_REGION_IMPL_HPP +#endif + +#endif // TOML11_REGION_HPP +#ifndef TOML11_SOURCE_LOCATION_HPP +#define TOML11_SOURCE_LOCATION_HPP + +#ifndef TOML11_SOURCE_LOCATION_FWD_HPP + #define TOML11_SOURCE_LOCATION_FWD_HPP + + #include + #include + #include + +namespace toml { + + // A struct to contain location in a toml file. + struct source_location { + public: + explicit source_location(const detail::region& r); + ~source_location() = default; + source_location(const source_location&) = default; + source_location(source_location&&) = default; + source_location& operator=(const source_location&) = default; + source_location& operator=(source_location&&) = default; + + bool is_ok() const noexcept { + return this->is_ok_; + } + + std::size_t length() const noexcept { + return this->length_; + } + + std::size_t first_line_number() const noexcept { + return this->first_line_; + } + + std::size_t first_column_number() const noexcept { + return this->first_column_; + } + + std::size_t last_line_number() const noexcept { + return this->last_line_; + } + + std::size_t last_column_number() const noexcept { + return this->last_column_; + } + + const std::string& file_name() const noexcept { + return this->file_name_; + } + + std::size_t num_lines() const noexcept { + return this->line_str_.size(); + } + + const std::string& first_line() const; + const std::string& last_line() const; + + const std::vector& lines() const noexcept { + return line_str_; + } + + private: + bool is_ok_; + std::size_t first_line_; + std::size_t first_column_; + std::size_t last_line_; + std::size_t last_column_; + std::size_t length_; + std::string file_name_; + std::vector line_str_; + }; + + namespace detail { + + std::size_t integer_width_base10(std::size_t i) noexcept; + + inline std::size_t line_width() noexcept { + return 0; + } + + template + std::size_t line_width(const source_location& loc, + const std::string& /*msg*/, + const Ts&... tail) noexcept { + return (std::max)(integer_width_base10(loc.last_line_number()), + line_width(tail...)); + } + + std::ostringstream& format_filename(std::ostringstream& oss, + const source_location& loc); + + std::ostringstream& format_empty_line(std::ostringstream& oss, + const std::size_t lnw); + + std::ostringstream& format_line(std::ostringstream& oss, + const std::size_t lnw, + const std::size_t linenum, + const std::string& line); + + std::ostringstream& format_underline(std::ostringstream& oss, + const std::size_t lnw, + const std::size_t col, + const std::size_t len, + const std::string& msg); + + std::string format_location_impl(const std::size_t lnw, + const std::string& prev_fname, + const source_location& loc, + const std::string& msg); + + inline std::string format_location_rec(const std::size_t, const std::string&) { + return ""; + } + + template + std::string format_location_rec(const std::size_t lnw, + const std::string& prev_fname, + const source_location& loc, + const std::string& msg, + const Ts&... tail) { + return format_location_impl(lnw, prev_fname, loc, msg) + + format_location_rec(lnw, loc.file_name(), tail...); + } + + } // namespace detail + + // format a location info without title + template + std::string format_location(const source_location& loc, + const std::string& msg, + const Ts&... tail) { + const auto lnw = detail::line_width(loc, msg, tail...); + + const std::string f(""); // at the 1st iteration, no prev_filename is given + return detail::format_location_rec(lnw, f, loc, msg, tail...); + } + +} // namespace toml +#endif // TOML11_SOURCE_LOCATION_FWD_HPP + +#if !defined(TOML11_COMPILE_SOURCES) + #ifndef TOML11_SOURCE_LOCATION_IMPL_HPP + #define TOML11_SOURCE_LOCATION_IMPL_HPP + + #include + #include + #include + #include + #include + +namespace toml { + + TOML11_INLINE source_location::source_location(const detail::region& r) + : is_ok_(false) + , first_line_(1) + , first_column_(1) + , last_line_(1) + , last_column_(1) + , length_(0) + , file_name_("unknown file") { + if (r.is_ok()) { + this->is_ok_ = true; + this->file_name_ = r.source_name(); + this->first_line_ = r.first_line_number(); + this->first_column_ = r.first_column_number(); + this->last_line_ = r.last_line_number(); + this->last_column_ = r.last_column_number(); + this->length_ = r.length(); + this->line_str_ = r.as_lines(); + } + } + + TOML11_INLINE const std::string& source_location::first_line() const { + if (this->line_str_.size() == 0) { + throw std::out_of_range( + "toml::source_location::first_line: `lines` is empty"); + } + return this->line_str_.front(); + } + + TOML11_INLINE const std::string& source_location::last_line() const { + if (this->line_str_.size() == 0) { + throw std::out_of_range( + "toml::source_location::first_line: `lines` is empty"); + } + return this->line_str_.back(); + } + + namespace detail { + + TOML11_INLINE std::size_t integer_width_base10(std::size_t i) noexcept { + std::size_t width = 0; + while (i != 0) { + i /= 10; + width += 1; + } + return width; + } + + TOML11_INLINE std::ostringstream& format_filename(std::ostringstream& oss, + const source_location& loc) { + // --> example.toml + oss << color::bold << color::blue << " --> " << color::reset + << color::bold << loc.file_name() << '\n' + << color::reset; + return oss; + } + + TOML11_INLINE std::ostringstream& format_empty_line(std::ostringstream& oss, + const std::size_t lnw) { + // | + oss << detail::make_string(lnw + 1, ' ') << color::bold << color::blue + << " |\n" + << color::reset; + return oss; + } + + TOML11_INLINE std::ostringstream& format_line(std::ostringstream& oss, + const std::size_t lnw, + const std::size_t linenum, + const std::string& line) { + // 10 | key = "value" + oss << ' ' << color::bold << color::blue << std::setw(static_cast(lnw)) + << std::right << linenum << " | " << color::reset; + for (const char c : line) { + if (std::isgraph(c) || c == ' ') { + oss << c; + } else { + oss << show_char(c); + } + } + oss << '\n'; + return oss; + } + + TOML11_INLINE std::ostringstream& format_underline(std::ostringstream& oss, + const std::size_t lnw, + const std::size_t col, + const std::size_t len, + const std::string& msg) { + // | ^^^^^^^-- this part + oss << make_string(lnw + 1, ' ') << color::bold << color::blue << " | " + << color::reset; + + oss << make_string(col - 1 /*1-origin*/, ' ') << color::bold << color::red + << make_string(len, '^') << "-- " << color::reset << msg << '\n'; + + return oss; + } + + TOML11_INLINE std::string format_location_impl(const std::size_t lnw, + const std::string& prev_fname, + const source_location& loc, + const std::string& msg) { + std::ostringstream oss; + + if (loc.file_name() != prev_fname) { + format_filename(oss, loc); + if (!loc.lines().empty()) { + format_empty_line(oss, lnw); + } + } + + if (loc.lines().size() == 1) { + // when column points LF, it exceeds the size of the first line. + std::size_t underline_limit = 1; + if (loc.first_line().size() < loc.first_column_number()) { + underline_limit = 1; + } else { + underline_limit = loc.first_line().size() - loc.first_column_number() + 1; + } + const auto underline_len = (std::min)(underline_limit, loc.length()); + + format_line(oss, lnw, loc.first_line_number(), loc.first_line()); + format_underline(oss, lnw, loc.first_column_number(), underline_len, msg); + } else if (loc.lines().size() == 2) { + const auto first_underline_len = loc.first_line().size() - + loc.first_column_number() + 1; + format_line(oss, lnw, loc.first_line_number(), loc.first_line()); + format_underline(oss, lnw, loc.first_column_number(), first_underline_len, ""); + + format_line(oss, lnw, loc.last_line_number(), loc.last_line()); + format_underline(oss, lnw, 1, loc.last_column_number(), msg); + } else if (loc.lines().size() > 2) { + const auto first_underline_len = loc.first_line().size() - + loc.first_column_number() + 1; + format_line(oss, lnw, loc.first_line_number(), loc.first_line()); + format_underline(oss, lnw, loc.first_column_number(), first_underline_len, "and"); + + if (loc.lines().size() == 3) { + format_line(oss, lnw, loc.first_line_number() + 1, loc.lines().at(1)); + format_underline(oss, lnw, 1, loc.lines().at(1).size(), "and"); + } else { + format_line(oss, lnw, loc.first_line_number() + 1, " ..."); + format_empty_line(oss, lnw); + } + format_line(oss, lnw, loc.last_line_number(), loc.last_line()); + format_underline(oss, lnw, 1, loc.last_column_number(), msg); + } + // if loc is empty, do nothing. + return oss.str(); + } + + } // namespace detail +} // namespace toml + #endif // TOML11_SOURCE_LOCATION_IMPL_HPP +#endif + +#endif // TOML11_SOURCE_LOCATION_HPP +#ifndef TOML11_ERROR_INFO_HPP +#define TOML11_ERROR_INFO_HPP + +#ifndef TOML11_ERROR_INFO_FWD_HPP + #define TOML11_ERROR_INFO_FWD_HPP + +namespace toml { + + // error info returned from parser. + struct error_info { + error_info(std::string t, source_location l, std::string m, std::string s = "") + : title_(std::move(t)) + , locations_ { std::make_pair(std::move(l), std::move(m)) } + , suffix_(std::move(s)) {} + + error_info(std::string t, + std::vector> l, + std::string s = "") + : title_(std::move(t)) + , locations_(std::move(l)) + , suffix_(std::move(s)) {} + + const std::string& title() const noexcept { + return title_; + } + + std::string& title() noexcept { + return title_; + } + + const std::vector>& locations() const noexcept { + return locations_; + } + + void add_locations(source_location loc, std::string msg) noexcept { + locations_.emplace_back(std::move(loc), std::move(msg)); + } + + const std::string& suffix() const noexcept { + return suffix_; + } + + std::string& suffix() noexcept { + return suffix_; + } + + private: + std::string title_; + std::vector> locations_; + std::string suffix_; // hint or something like that + }; + + // forward decl + template + class basic_value; + + namespace detail { + inline error_info make_error_info_rec(error_info e) { + return e; + } + + inline error_info make_error_info_rec(error_info e, std::string s) { + e.suffix() = s; + return e; + } + + template + error_info make_error_info_rec(error_info e, + const basic_value& v, + std::string msg, + Ts&&... tail); + + template + error_info make_error_info_rec(error_info e, + source_location loc, + std::string msg, + Ts&&... tail) { + e.add_locations(std::move(loc), std::move(msg)); + return make_error_info_rec(std::move(e), std::forward(tail)...); + } + + } // namespace detail + + template + error_info make_error_info(std::string title, + source_location loc, + std::string msg, + Ts&&... tail) { + error_info ei(std::move(title), std::move(loc), std::move(msg)); + return detail::make_error_info_rec(ei, std::forward(tail)...); + } + + std::string format_error(const std::string& errkind, const error_info& err); + std::string format_error(const error_info& err); + + // for custom error message + template + std::string format_error(std::string title, + source_location loc, + std::string msg, + Ts&&... tail) { + return format_error("", + make_error_info(std::move(title), + std::move(loc), + std::move(msg), + std::forward(tail)...)); + } + + std::ostream& operator<<(std::ostream& os, const error_info& e); + +} // namespace toml +#endif // TOML11_ERROR_INFO_FWD_HPP + +#if !defined(TOML11_COMPILE_SOURCES) + #ifndef TOML11_ERROR_INFO_IMPL_HPP + #define TOML11_ERROR_INFO_IMPL_HPP + + #include + +namespace toml { + + TOML11_INLINE std::string format_error(const std::string& errkind, + const error_info& err) { + std::string errmsg; + if (!errkind.empty()) { + errmsg = errkind; + errmsg += ' '; + } + errmsg += err.title(); + errmsg += '\n'; + + const auto lnw = [&err]() { + std::size_t width = 0; + for (const auto& l : err.locations()) { + width = (std::max)(detail::integer_width_base10(l.first.last_line_number()), + width); + } + return width; + }(); + + bool first = true; + std::string prev_fname; + for (const auto& lm : err.locations()) { + if (!first) { + std::ostringstream oss; + oss << detail::make_string(lnw + 1, ' ') << color::bold << color::blue + << " |" << color::reset << color::bold << " ...\n" + << color::reset; + oss << detail::make_string(lnw + 1, ' ') << color::bold << color::blue + << " |\n" + << color::reset; + errmsg += oss.str(); + } + + const auto& l = lm.first; + const auto& m = lm.second; + + errmsg += detail::format_location_impl(lnw, prev_fname, l, m); + + prev_fname = l.file_name(); + first = false; + } + + errmsg += err.suffix(); + + return errmsg; + } + + TOML11_INLINE std::string format_error(const error_info& err) { + std::ostringstream oss; + oss << color::red << color::bold << "[error]" << color::reset; + return format_error(oss.str(), err); + } + + TOML11_INLINE std::ostream& operator<<(std::ostream& os, const error_info& e) { + os << format_error(e); + return os; + } + +} // namespace toml + #endif // TOML11_ERROR_INFO_IMPL_HPP +#endif + +#endif // TOML11_ERROR_INFO_HPP +#ifndef TOML11_VALUE_HPP +#define TOML11_VALUE_HPP + +#ifdef TOML11_HAS_STRING_VIEW + #include +#endif + +#include + +namespace toml { + template + class basic_value; + + struct type_error final : public ::toml::exception { + public: + type_error(std::string what_arg, source_location loc) + : what_(std::move(what_arg)) + , loc_(std::move(loc)) {} + + ~type_error() noexcept override = default; + + const char* what() const noexcept override { + return what_.c_str(); + } + + const source_location& location() const noexcept { + return loc_; + } + + private: + std::string what_; + source_location loc_; + }; + + // only for internal use + namespace detail { + template + error_info make_type_error(const basic_value&, + const std::string&, + const value_t); + + template + error_info make_not_found_error(const basic_value&, + const std::string&, + const typename basic_value::key_type&); + + template + void change_region_of_value(basic_value&, const basic_value&); + + template + struct getter; + } // namespace detail + + template + class basic_value { + public: + using config_type = TypeConfig; + using key_type = typename config_type::string_type; + using value_type = basic_value; + using boolean_type = typename config_type::boolean_type; + using integer_type = typename config_type::integer_type; + using floating_type = typename config_type::floating_type; + using string_type = typename config_type::string_type; + using local_time_type = ::toml::local_time; + using local_date_type = ::toml::local_date; + using local_datetime_type = ::toml::local_datetime; + using offset_datetime_type = ::toml::offset_datetime; + using array_type = typename config_type::template array_type; + using table_type = typename config_type::template table_type; + using comment_type = typename config_type::comment_type; + using char_type = typename string_type::value_type; + + private: + using region_type = detail::region; + + public: + basic_value() noexcept + : type_(value_t::empty) + , empty_('\0') + , region_ {} + , comments_ {} {} + + ~basic_value() noexcept { + this->cleanup(); + } + + // copy/move constructor/assigner ===================================== {{{ + + basic_value(const basic_value& v) + : type_(v.type_) + , region_(v.region_) + , comments_(v.comments_) { + switch (this->type_) { + case value_t::boolean: + assigner(boolean_, v.boolean_); + break; + case value_t::integer: + assigner(integer_, v.integer_); + break; + case value_t::floating: + assigner(floating_, v.floating_); + break; + case value_t::string: + assigner(string_, v.string_); + break; + case value_t::offset_datetime: + assigner(offset_datetime_, v.offset_datetime_); + break; + case value_t::local_datetime: + assigner(local_datetime_, v.local_datetime_); + break; + case value_t::local_date: + assigner(local_date_, v.local_date_); + break; + case value_t::local_time: + assigner(local_time_, v.local_time_); + break; + case value_t::array: + assigner(array_, v.array_); + break; + case value_t::table: + assigner(table_, v.table_); + break; + default: + assigner(empty_, '\0'); + break; + } + } + + basic_value(basic_value&& v) + : type_(v.type()) + , region_(std::move(v.region_)) + , comments_(std::move(v.comments_)) { + switch (this->type_) { + case value_t::boolean: + assigner(boolean_, std::move(v.boolean_)); + break; + case value_t::integer: + assigner(integer_, std::move(v.integer_)); + break; + case value_t::floating: + assigner(floating_, std::move(v.floating_)); + break; + case value_t::string: + assigner(string_, std::move(v.string_)); + break; + case value_t::offset_datetime: + assigner(offset_datetime_, std::move(v.offset_datetime_)); + break; + case value_t::local_datetime: + assigner(local_datetime_, std::move(v.local_datetime_)); + break; + case value_t::local_date: + assigner(local_date_, std::move(v.local_date_)); + break; + case value_t::local_time: + assigner(local_time_, std::move(v.local_time_)); + break; + case value_t::array: + assigner(array_, std::move(v.array_)); + break; + case value_t::table: + assigner(table_, std::move(v.table_)); + break; + default: + assigner(empty_, '\0'); + break; + } + } + + basic_value& operator=(const basic_value& v) { + if (this == std::addressof(v)) { + return *this; + } + + this->cleanup(); + this->type_ = v.type_; + this->region_ = v.region_; + this->comments_ = v.comments_; + switch (this->type_) { + case value_t::boolean: + assigner(boolean_, v.boolean_); + break; + case value_t::integer: + assigner(integer_, v.integer_); + break; + case value_t::floating: + assigner(floating_, v.floating_); + break; + case value_t::string: + assigner(string_, v.string_); + break; + case value_t::offset_datetime: + assigner(offset_datetime_, v.offset_datetime_); + break; + case value_t::local_datetime: + assigner(local_datetime_, v.local_datetime_); + break; + case value_t::local_date: + assigner(local_date_, v.local_date_); + break; + case value_t::local_time: + assigner(local_time_, v.local_time_); + break; + case value_t::array: + assigner(array_, v.array_); + break; + case value_t::table: + assigner(table_, v.table_); + break; + default: + assigner(empty_, '\0'); + break; + } + return *this; + } + + basic_value& operator=(basic_value&& v) { + if (this == std::addressof(v)) { + return *this; + } + + this->cleanup(); + this->type_ = v.type_; + this->region_ = std::move(v.region_); + this->comments_ = std::move(v.comments_); + switch (this->type_) { + case value_t::boolean: + assigner(boolean_, std::move(v.boolean_)); + break; + case value_t::integer: + assigner(integer_, std::move(v.integer_)); + break; + case value_t::floating: + assigner(floating_, std::move(v.floating_)); + break; + case value_t::string: + assigner(string_, std::move(v.string_)); + break; + case value_t::offset_datetime: + assigner(offset_datetime_, std::move(v.offset_datetime_)); + break; + case value_t::local_datetime: + assigner(local_datetime_, std::move(v.local_datetime_)); + break; + case value_t::local_date: + assigner(local_date_, std::move(v.local_date_)); + break; + case value_t::local_time: + assigner(local_time_, std::move(v.local_time_)); + break; + case value_t::array: + assigner(array_, std::move(v.array_)); + break; + case value_t::table: + assigner(table_, std::move(v.table_)); + break; + default: + assigner(empty_, '\0'); + break; + } + return *this; + } + + // }}} + + // constructor to overwrite commnets ================================== {{{ + + basic_value(basic_value v, std::vector com) + : type_(v.type()) + , region_(std::move(v.region_)) + , comments_(std::move(com)) { + switch (this->type_) { + case value_t::boolean: + assigner(boolean_, std::move(v.boolean_)); + break; + case value_t::integer: + assigner(integer_, std::move(v.integer_)); + break; + case value_t::floating: + assigner(floating_, std::move(v.floating_)); + break; + case value_t::string: + assigner(string_, std::move(v.string_)); + break; + case value_t::offset_datetime: + assigner(offset_datetime_, std::move(v.offset_datetime_)); + break; + case value_t::local_datetime: + assigner(local_datetime_, std::move(v.local_datetime_)); + break; + case value_t::local_date: + assigner(local_date_, std::move(v.local_date_)); + break; + case value_t::local_time: + assigner(local_time_, std::move(v.local_time_)); + break; + case value_t::array: + assigner(array_, std::move(v.array_)); + break; + case value_t::table: + assigner(table_, std::move(v.table_)); + break; + default: + assigner(empty_, '\0'); + break; + } + } + + // }}} + + // conversion between different basic_values ========================== {{{ + + template + basic_value(basic_value other) + : type_(other.type_) + , region_(std::move(other.region_)) + , comments_(std::move(other.comments_)) { + switch (other.type_) { + // use auto-convert in constructor + case value_t::boolean: + assigner(boolean_, std::move(other.boolean_)); + break; + case value_t::integer: + assigner(integer_, std::move(other.integer_)); + break; + case value_t::floating: + assigner(floating_, std::move(other.floating_)); + break; + case value_t::string: + assigner(string_, std::move(other.string_)); + break; + case value_t::offset_datetime: + assigner(offset_datetime_, std::move(other.offset_datetime_)); + break; + case value_t::local_datetime: + assigner(local_datetime_, std::move(other.local_datetime_)); + break; + case value_t::local_date: + assigner(local_date_, std::move(other.local_date_)); + break; + case value_t::local_time: + assigner(local_time_, std::move(other.local_time_)); + break; + + // may have different container type + case value_t::array: { + array_type tmp(std::make_move_iterator(other.array_.value.get().begin()), + std::make_move_iterator(other.array_.value.get().end())); + assigner(array_, + array_storage(detail::storage(std::move(tmp)), + other.array_.format)); + break; + } + case value_t::table: { + table_type tmp(std::make_move_iterator(other.table_.value.get().begin()), + std::make_move_iterator(other.table_.value.get().end())); + assigner(table_, + table_storage(detail::storage(std::move(tmp)), + other.table_.format)); + break; + } + default: + break; + } + } + + template + basic_value(basic_value other, std::vector com) + : type_(other.type_) + , region_(std::move(other.region_)) + , comments_(std::move(com)) { + switch (other.type_) { + // use auto-convert in constructor + case value_t::boolean: + assigner(boolean_, std::move(other.boolean_)); + break; + case value_t::integer: + assigner(integer_, std::move(other.integer_)); + break; + case value_t::floating: + assigner(floating_, std::move(other.floating_)); + break; + case value_t::string: + assigner(string_, std::move(other.string_)); + break; + case value_t::offset_datetime: + assigner(offset_datetime_, std::move(other.offset_datetime_)); + break; + case value_t::local_datetime: + assigner(local_datetime_, std::move(other.local_datetime_)); + break; + case value_t::local_date: + assigner(local_date_, std::move(other.local_date_)); + break; + case value_t::local_time: + assigner(local_time_, std::move(other.local_time_)); + break; + + // may have different container type + case value_t::array: { + array_type tmp(std::make_move_iterator(other.array_.value.get().begin()), + std::make_move_iterator(other.array_.value.get().end())); + assigner(array_, + array_storage(detail::storage(std::move(tmp)), + other.array_.format)); + break; + } + case value_t::table: { + table_type tmp(std::make_move_iterator(other.table_.value.get().begin()), + std::make_move_iterator(other.table_.value.get().end())); + assigner(table_, + table_storage(detail::storage(std::move(tmp)), + other.table_.format)); + break; + } + default: + break; + } + } + + template + basic_value& operator=(basic_value other) { + this->cleanup(); + this->region_ = other.region_; + this->comments_ = comment_type(other.comments_); + this->type_ = other.type_; + switch (other.type_) { + // use auto-convert in constructor + case value_t::boolean: + assigner(boolean_, std::move(other.boolean_)); + break; + case value_t::integer: + assigner(integer_, std::move(other.integer_)); + break; + case value_t::floating: + assigner(floating_, std::move(other.floating_)); + break; + case value_t::string: + assigner(string_, std::move(other.string_)); + break; + case value_t::offset_datetime: + assigner(offset_datetime_, std::move(other.offset_datetime_)); + break; + case value_t::local_datetime: + assigner(local_datetime_, std::move(other.local_datetime_)); + break; + case value_t::local_date: + assigner(local_date_, std::move(other.local_date_)); + break; + case value_t::local_time: + assigner(local_time_, std::move(other.local_time_)); + break; + + // may have different container type + case value_t::array: { + array_type tmp(std::make_move_iterator(other.array_.value.get().begin()), + std::make_move_iterator(other.array_.value.get().end())); + assigner(array_, + array_storage(detail::storage(std::move(tmp)), + other.array_.format)); + break; + } + case value_t::table: { + table_type tmp(std::make_move_iterator(other.table_.value.get().begin()), + std::make_move_iterator(other.table_.value.get().end())); + assigner(table_, + table_storage(detail::storage(std::move(tmp)), + other.table_.format)); + break; + } + default: + break; + } + return *this; + } + + // }}} + + // constructor (boolean) ============================================== {{{ + + basic_value(boolean_type x) + : basic_value(x, + boolean_format_info {}, + std::vector {}, + region_type {}) {} + + basic_value(boolean_type x, boolean_format_info fmt) + : basic_value(x, fmt, std::vector {}, region_type {}) {} + + basic_value(boolean_type x, std::vector com) + : basic_value(x, boolean_format_info {}, std::move(com), region_type {}) {} + + basic_value(boolean_type x, boolean_format_info fmt, std::vector com) + : basic_value(x, fmt, std::move(com), region_type {}) {} + + basic_value(boolean_type x, + boolean_format_info fmt, + std::vector com, + region_type reg) + : type_(value_t::boolean) + , boolean_(boolean_storage(x, fmt)) + , region_(std::move(reg)) + , comments_(std::move(com)) {} + + basic_value& operator=(boolean_type x) { + boolean_format_info fmt; + if (this->is_boolean()) { + fmt = this->as_boolean_fmt(); + } + this->cleanup(); + this->type_ = value_t::boolean; + this->region_ = region_type {}; + assigner(this->boolean_, boolean_storage(x, fmt)); + return *this; + } + + // }}} + + // constructor (integer) ============================================== {{{ + + basic_value(integer_type x) + : basic_value(std::move(x), + integer_format_info {}, + std::vector {}, + region_type {}) {} + + basic_value(integer_type x, integer_format_info fmt) + : basic_value(std::move(x), + std::move(fmt), + std::vector {}, + region_type {}) {} + + basic_value(integer_type x, std::vector com) + : basic_value(std::move(x), + integer_format_info {}, + std::move(com), + region_type {}) {} + + basic_value(integer_type x, integer_format_info fmt, std::vector com) + : basic_value(std::move(x), std::move(fmt), std::move(com), region_type {}) { + } + + basic_value(integer_type x, + integer_format_info fmt, + std::vector com, + region_type reg) + : type_(value_t::integer) + , integer_(integer_storage(std::move(x), std::move(fmt))) + , region_(std::move(reg)) + , comments_(std::move(com)) {} + + basic_value& operator=(integer_type x) { + integer_format_info fmt; + if (this->is_integer()) { + fmt = this->as_integer_fmt(); + } + this->cleanup(); + this->type_ = value_t::integer; + this->region_ = region_type {}; + assigner(this->integer_, integer_storage(std::move(x), std::move(fmt))); + return *this; + } + + private: + template + using enable_if_integer_like_t = cxx::enable_if_t< + cxx::conjunction, boolean_type>>, + cxx::negation, integer_type>>, + std::is_integral>>::value, + std::nullptr_t>; + + public: + template = nullptr> + basic_value(T x) + : basic_value(std::move(x), + integer_format_info {}, + std::vector {}, + region_type {}) {} + + template = nullptr> + basic_value(T x, integer_format_info fmt) + : basic_value(std::move(x), + std::move(fmt), + std::vector {}, + region_type {}) {} + + template = nullptr> + basic_value(T x, std::vector com) + : basic_value(std::move(x), + integer_format_info {}, + std::move(com), + region_type {}) {} + + template = nullptr> + basic_value(T x, integer_format_info fmt, std::vector com) + : basic_value(std::move(x), std::move(fmt), std::move(com), region_type {}) { + } + + template = nullptr> + basic_value(T x, + integer_format_info fmt, + std::vector com, + region_type reg) + : type_(value_t::integer) + , integer_(integer_storage(std::move(x), std::move(fmt))) + , region_(std::move(reg)) + , comments_(std::move(com)) {} + + template = nullptr> + basic_value& operator=(T x) { + integer_format_info fmt; + if (this->is_integer()) { + fmt = this->as_integer_fmt(); + } + this->cleanup(); + this->type_ = value_t::integer; + this->region_ = region_type {}; + assigner(this->integer_, integer_storage(x, std::move(fmt))); + return *this; + } + + // }}} + + // constructor (floating) ============================================= {{{ + + basic_value(floating_type x) + : basic_value(std::move(x), + floating_format_info {}, + std::vector {}, + region_type {}) {} + + basic_value(floating_type x, floating_format_info fmt) + : basic_value(std::move(x), + std::move(fmt), + std::vector {}, + region_type {}) {} + + basic_value(floating_type x, std::vector com) + : basic_value(std::move(x), + floating_format_info {}, + std::move(com), + region_type {}) {} + + basic_value(floating_type x, + floating_format_info fmt, + std::vector com) + : basic_value(std::move(x), std::move(fmt), std::move(com), region_type {}) { + } + + basic_value(floating_type x, + floating_format_info fmt, + std::vector com, + region_type reg) + : type_(value_t::floating) + , floating_(floating_storage(std::move(x), std::move(fmt))) + , region_(std::move(reg)) + , comments_(std::move(com)) {} + + basic_value& operator=(floating_type x) { + floating_format_info fmt; + if (this->is_floating()) { + fmt = this->as_floating_fmt(); + } + this->cleanup(); + this->type_ = value_t::floating; + this->region_ = region_type {}; + assigner(this->floating_, floating_storage(std::move(x), std::move(fmt))); + return *this; + } + + private: + template + using enable_if_floating_like_t = cxx::enable_if_t< + cxx::conjunction, floating_type>>, + std::is_floating_point>>::value, + std::nullptr_t>; + + public: + template = nullptr> + basic_value(T x) + : basic_value(x, + floating_format_info {}, + std::vector {}, + region_type {}) {} + + template = nullptr> + basic_value(T x, floating_format_info fmt) + : basic_value(x, std::move(fmt), std::vector {}, region_type {}) { + } + + template = nullptr> + basic_value(T x, std::vector com) + : basic_value(x, floating_format_info {}, std::move(com), region_type {}) {} + + template = nullptr> + basic_value(T x, floating_format_info fmt, std::vector com) + : basic_value(x, std::move(fmt), std::move(com), region_type {}) {} + + template = nullptr> + basic_value(T x, + floating_format_info fmt, + std::vector com, + region_type reg) + : type_(value_t::floating) + , floating_(floating_storage(x, std::move(fmt))) + , region_(std::move(reg)) + , comments_(std::move(com)) {} + + template = nullptr> + basic_value& operator=(T x) { + floating_format_info fmt; + if (this->is_floating()) { + fmt = this->as_floating_fmt(); + } + this->cleanup(); + this->type_ = value_t::floating; + this->region_ = region_type {}; + assigner(this->floating_, floating_storage(x, std::move(fmt))); + return *this; + } + + // }}} + + // constructor (string) =============================================== {{{ + + basic_value(string_type x) + : basic_value(std::move(x), + string_format_info {}, + std::vector {}, + region_type {}) {} + + basic_value(string_type x, string_format_info fmt) + : basic_value(std::move(x), + std::move(fmt), + std::vector {}, + region_type {}) {} + + basic_value(string_type x, std::vector com) + : basic_value(std::move(x), + string_format_info {}, + std::move(com), + region_type {}) {} + + basic_value(string_type x, string_format_info fmt, std::vector com) + : basic_value(std::move(x), std::move(fmt), std::move(com), region_type {}) { + } + + basic_value(string_type x, + string_format_info fmt, + std::vector com, + region_type reg) + : type_(value_t::string) + , string_(string_storage(std::move(x), std::move(fmt))) + , region_(std::move(reg)) + , comments_(std::move(com)) {} + + basic_value& operator=(string_type x) { + string_format_info fmt; + if (this->is_string()) { + fmt = this->as_string_fmt(); + } + this->cleanup(); + this->type_ = value_t::string; + this->region_ = region_type {}; + assigner(this->string_, string_storage(x, std::move(fmt))); + return *this; + } + + // "string literal" + + basic_value(const typename string_type::value_type* x) + : basic_value(x, + string_format_info {}, + std::vector {}, + region_type {}) {} + + basic_value(const typename string_type::value_type* x, string_format_info fmt) + : basic_value(x, std::move(fmt), std::vector {}, region_type {}) { + } + + basic_value(const typename string_type::value_type* x, + std::vector com) + : basic_value(x, string_format_info {}, std::move(com), region_type {}) {} + + basic_value(const typename string_type::value_type* x, + string_format_info fmt, + std::vector com) + : basic_value(x, std::move(fmt), std::move(com), region_type {}) {} + + basic_value(const typename string_type::value_type* x, + string_format_info fmt, + std::vector com, + region_type reg) + : type_(value_t::string) + , string_(string_storage(string_type(x), std::move(fmt))) + , region_(std::move(reg)) + , comments_(std::move(com)) {} + + basic_value& operator=(const typename string_type::value_type* x) { + string_format_info fmt; + if (this->is_string()) { + fmt = this->as_string_fmt(); + } + this->cleanup(); + this->type_ = value_t::string; + this->region_ = region_type {}; + assigner(this->string_, string_storage(string_type(x), std::move(fmt))); + return *this; + } + +#if defined(TOML11_HAS_STRING_VIEW) + using string_view_type = std::basic_string_view; + + basic_value(string_view_type x) + : basic_value(x, + string_format_info {}, + std::vector {}, + region_type {}) {} + + basic_value(string_view_type x, string_format_info fmt) + : basic_value(x, std::move(fmt), std::vector {}, region_type {}) { + } + + basic_value(string_view_type x, std::vector com) + : basic_value(x, string_format_info {}, std::move(com), region_type {}) {} + + basic_value(string_view_type x, + string_format_info fmt, + std::vector com) + : basic_value(x, std::move(fmt), std::move(com), region_type {}) {} + + basic_value(string_view_type x, + string_format_info fmt, + std::vector com, + region_type reg) + : type_(value_t::string) + , string_(string_storage(string_type(x), std::move(fmt))) + , region_(std::move(reg)) + , comments_(std::move(com)) {} + + basic_value& operator=(string_view_type x) { + string_format_info fmt; + if (this->is_string()) { + fmt = this->as_string_fmt(); + } + this->cleanup(); + this->type_ = value_t::string; + this->region_ = region_type {}; + assigner(this->string_, string_storage(string_type(x), std::move(fmt))); + return *this; + } + +#endif // TOML11_HAS_STRING_VIEW + + template , string_type>>, + detail::is_1byte_std_basic_string>::value, + std::nullptr_t> = nullptr> + basic_value(const T& x) + : basic_value(x, + string_format_info {}, + std::vector {}, + region_type {}) {} + + template , string_type>>, + detail::is_1byte_std_basic_string>::value, + std::nullptr_t> = nullptr> + basic_value(const T& x, string_format_info fmt) + : basic_value(x, std::move(fmt), std::vector {}, region_type {}) { + } + + template , string_type>>, + detail::is_1byte_std_basic_string>::value, + std::nullptr_t> = nullptr> + basic_value(const T& x, std::vector com) + : basic_value(x, string_format_info {}, std::move(com), region_type {}) {} + + template , string_type>>, + detail::is_1byte_std_basic_string>::value, + std::nullptr_t> = nullptr> + basic_value(const T& x, string_format_info fmt, std::vector com) + : basic_value(x, std::move(fmt), std::move(com), region_type {}) {} + + template , string_type>>, + detail::is_1byte_std_basic_string>::value, + std::nullptr_t> = nullptr> + basic_value(const T& x, + string_format_info fmt, + std::vector com, + region_type reg) + : type_(value_t::string) + , string_(string_storage(detail::string_conv(x), std::move(fmt))) + , region_(std::move(reg)) + , comments_(std::move(com)) {} + + template , string_type>>, + detail::is_1byte_std_basic_string>::value, + std::nullptr_t> = nullptr> + basic_value& operator=(const T& x) { + string_format_info fmt; + if (this->is_string()) { + fmt = this->as_string_fmt(); + } + this->cleanup(); + this->type_ = value_t::string; + this->region_ = region_type {}; + assigner(this->string_, + string_storage(detail::string_conv(x), std::move(fmt))); + return *this; + } + + // }}} + + // constructor (local_date) =========================================== {{{ + + basic_value(local_date_type x) + : basic_value(x, + local_date_format_info {}, + std::vector {}, + region_type {}) {} + + basic_value(local_date_type x, local_date_format_info fmt) + : basic_value(x, fmt, std::vector {}, region_type {}) {} + + basic_value(local_date_type x, std::vector com) + : basic_value(x, local_date_format_info {}, std::move(com), region_type {}) { + } + + basic_value(local_date_type x, + local_date_format_info fmt, + std::vector com) + : basic_value(x, fmt, std::move(com), region_type {}) {} + + basic_value(local_date_type x, + local_date_format_info fmt, + std::vector com, + region_type reg) + : type_(value_t::local_date) + , local_date_(local_date_storage(x, fmt)) + , region_(std::move(reg)) + , comments_(std::move(com)) {} + + basic_value& operator=(local_date_type x) { + local_date_format_info fmt; + if (this->is_local_date()) { + fmt = this->as_local_date_fmt(); + } + this->cleanup(); + this->type_ = value_t::local_date; + this->region_ = region_type {}; + assigner(this->local_date_, local_date_storage(x, fmt)); + return *this; + } + + // }}} + + // constructor (local_time) =========================================== {{{ + + basic_value(local_time_type x) + : basic_value(x, + local_time_format_info {}, + std::vector {}, + region_type {}) {} + + basic_value(local_time_type x, local_time_format_info fmt) + : basic_value(x, fmt, std::vector {}, region_type {}) {} + + basic_value(local_time_type x, std::vector com) + : basic_value(x, local_time_format_info {}, std::move(com), region_type {}) { + } + + basic_value(local_time_type x, + local_time_format_info fmt, + std::vector com) + : basic_value(x, fmt, std::move(com), region_type {}) {} + + basic_value(local_time_type x, + local_time_format_info fmt, + std::vector com, + region_type reg) + : type_(value_t::local_time) + , local_time_(local_time_storage(x, fmt)) + , region_(std::move(reg)) + , comments_(std::move(com)) {} + + basic_value& operator=(local_time_type x) { + local_time_format_info fmt; + if (this->is_local_time()) { + fmt = this->as_local_time_fmt(); + } + this->cleanup(); + this->type_ = value_t::local_time; + this->region_ = region_type {}; + assigner(this->local_time_, local_time_storage(x, fmt)); + return *this; + } + + template + basic_value(const std::chrono::duration& x) + : basic_value(local_time_type(x), + local_time_format_info {}, + std::vector {}, + region_type {}) {} + + template + basic_value(const std::chrono::duration& x, + local_time_format_info fmt) + : basic_value(local_time_type(x), + std::move(fmt), + std::vector {}, + region_type {}) {} + + template + basic_value(const std::chrono::duration& x, + std::vector com) + : basic_value(local_time_type(x), + local_time_format_info {}, + std::move(com), + region_type {}) {} + + template + basic_value(const std::chrono::duration& x, + local_time_format_info fmt, + std::vector com) + : basic_value(local_time_type(x), + std::move(fmt), + std::move(com), + region_type {}) {} + + template + basic_value(const std::chrono::duration& x, + local_time_format_info fmt, + std::vector com, + region_type reg) + : basic_value(local_time_type(x), + std::move(fmt), + std::move(com), + std::move(reg)) {} + + template + basic_value& operator=(const std::chrono::duration& x) { + local_time_format_info fmt; + if (this->is_local_time()) { + fmt = this->as_local_time_fmt(); + } + this->cleanup(); + this->type_ = value_t::local_time; + this->region_ = region_type {}; + assigner(this->local_time_, + local_time_storage(local_time_type(x), std::move(fmt))); + return *this; + } + + // }}} + + // constructor (local_datetime) =========================================== {{{ + + basic_value(local_datetime_type x) + : basic_value(x, + local_datetime_format_info {}, + std::vector {}, + region_type {}) {} + + basic_value(local_datetime_type x, local_datetime_format_info fmt) + : basic_value(x, fmt, std::vector {}, region_type {}) {} + + basic_value(local_datetime_type x, std::vector com) + : basic_value(x, local_datetime_format_info {}, std::move(com), region_type {}) { + } + + basic_value(local_datetime_type x, + local_datetime_format_info fmt, + std::vector com) + : basic_value(x, fmt, std::move(com), region_type {}) {} + + basic_value(local_datetime_type x, + local_datetime_format_info fmt, + std::vector com, + region_type reg) + : type_(value_t::local_datetime) + , local_datetime_(local_datetime_storage(x, fmt)) + , region_(std::move(reg)) + , comments_(std::move(com)) {} + + basic_value& operator=(local_datetime_type x) { + local_datetime_format_info fmt; + if (this->is_local_datetime()) { + fmt = this->as_local_datetime_fmt(); + } + this->cleanup(); + this->type_ = value_t::local_datetime; + this->region_ = region_type {}; + assigner(this->local_datetime_, local_datetime_storage(x, fmt)); + return *this; + } + + // }}} + + // constructor (offset_datetime) =========================================== {{{ + + basic_value(offset_datetime_type x) + : basic_value(x, + offset_datetime_format_info {}, + std::vector {}, + region_type {}) {} + + basic_value(offset_datetime_type x, offset_datetime_format_info fmt) + : basic_value(x, fmt, std::vector {}, region_type {}) {} + + basic_value(offset_datetime_type x, std::vector com) + : basic_value(x, + offset_datetime_format_info {}, + std::move(com), + region_type {}) {} + + basic_value(offset_datetime_type x, + offset_datetime_format_info fmt, + std::vector com) + : basic_value(x, fmt, std::move(com), region_type {}) {} + + basic_value(offset_datetime_type x, + offset_datetime_format_info fmt, + std::vector com, + region_type reg) + : type_(value_t::offset_datetime) + , offset_datetime_(offset_datetime_storage(x, fmt)) + , region_(std::move(reg)) + , comments_(std::move(com)) {} + + basic_value& operator=(offset_datetime_type x) { + offset_datetime_format_info fmt; + if (this->is_offset_datetime()) { + fmt = this->as_offset_datetime_fmt(); + } + this->cleanup(); + this->type_ = value_t::offset_datetime; + this->region_ = region_type {}; + assigner(this->offset_datetime_, offset_datetime_storage(x, fmt)); + return *this; + } + + // system_clock::time_point + + basic_value(std::chrono::system_clock::time_point x) + : basic_value(offset_datetime_type(x), + offset_datetime_format_info {}, + std::vector {}, + region_type {}) {} + + basic_value(std::chrono::system_clock::time_point x, + offset_datetime_format_info fmt) + : basic_value(offset_datetime_type(x), + fmt, + std::vector {}, + region_type {}) {} + + basic_value(std::chrono::system_clock::time_point x, + std::vector com) + : basic_value(offset_datetime_type(x), + offset_datetime_format_info {}, + std::move(com), + region_type {}) {} + + basic_value(std::chrono::system_clock::time_point x, + offset_datetime_format_info fmt, + std::vector com) + : basic_value(offset_datetime_type(x), fmt, std::move(com), region_type {}) { + } + + basic_value(std::chrono::system_clock::time_point x, + offset_datetime_format_info fmt, + std::vector com, + region_type reg) + : basic_value(offset_datetime_type(x), + std::move(fmt), + std::move(com), + std::move(reg)) {} + + basic_value& operator=(std::chrono::system_clock::time_point x) { + offset_datetime_format_info fmt; + if (this->is_offset_datetime()) { + fmt = this->as_offset_datetime_fmt(); + } + this->cleanup(); + this->type_ = value_t::offset_datetime; + this->region_ = region_type {}; + assigner(this->offset_datetime_, + offset_datetime_storage(offset_datetime_type(x), fmt)); + return *this; + } + + // }}} + + // constructor (array) ================================================ {{{ + + basic_value(array_type x) + : basic_value(std::move(x), + array_format_info {}, + std::vector {}, + region_type {}) {} + + basic_value(array_type x, array_format_info fmt) + : basic_value(std::move(x), + std::move(fmt), + std::vector {}, + region_type {}) {} + + basic_value(array_type x, std::vector com) + : basic_value(std::move(x), + array_format_info {}, + std::move(com), + region_type {}) {} + + basic_value(array_type x, array_format_info fmt, std::vector com) + : basic_value(std::move(x), fmt, std::move(com), region_type {}) {} + + basic_value(array_type x, + array_format_info fmt, + std::vector com, + region_type reg) + : type_(value_t::array) + , array_(array_storage(detail::storage(std::move(x)), + std::move(fmt))) + , region_(std::move(reg)) + , comments_(std::move(com)) {} + + basic_value& operator=(array_type x) { + array_format_info fmt; + if (this->is_array()) { + fmt = this->as_array_fmt(); + } + this->cleanup(); + this->type_ = value_t::array; + this->region_ = region_type {}; + assigner(this->array_, + array_storage(detail::storage(std::move(x)), + std::move(fmt))); + return *this; + } + + private: + template + using enable_if_array_like_t = cxx::enable_if_t< + cxx::conjunction, + cxx::negation>, + cxx::negation>, +#if defined(TOML11_HAS_STRING_VIEW) + cxx::negation>, +#endif + cxx::negation>, + cxx::negation>>::value, + std::nullptr_t>; + + public: + template = nullptr> + basic_value(T x) + : basic_value(std::move(x), + array_format_info {}, + std::vector {}, + region_type {}) {} + + template = nullptr> + basic_value(T x, array_format_info fmt) + : basic_value(std::move(x), + std::move(fmt), + std::vector {}, + region_type {}) {} + + template = nullptr> + basic_value(T x, std::vector com) + : basic_value(std::move(x), + array_format_info {}, + std::move(com), + region_type {}) {} + + template = nullptr> + basic_value(T x, array_format_info fmt, std::vector com) + : basic_value(std::move(x), fmt, std::move(com), region_type {}) {} + + template = nullptr> + basic_value(T x, array_format_info fmt, std::vector com, region_type reg) + : type_(value_t::array) + , array_(array_storage(detail::storage( + array_type(std::make_move_iterator(x.begin()), + std::make_move_iterator(x.end()))), + std::move(fmt))) + , region_(std::move(reg)) + , comments_(std::move(com)) {} + + template = nullptr> + basic_value& operator=(T x) { + array_format_info fmt; + if (this->is_array()) { + fmt = this->as_array_fmt(); + } + this->cleanup(); + this->type_ = value_t::array; + this->region_ = region_type {}; + + array_type a(std::make_move_iterator(x.begin()), + std::make_move_iterator(x.end())); + assigner(this->array_, + array_storage(detail::storage(std::move(a)), + std::move(fmt))); + return *this; + } + + // }}} + + // constructor (table) ================================================ {{{ + + basic_value(table_type x) + : basic_value(std::move(x), + table_format_info {}, + std::vector {}, + region_type {}) {} + + basic_value(table_type x, table_format_info fmt) + : basic_value(std::move(x), + std::move(fmt), + std::vector {}, + region_type {}) {} + + basic_value(table_type x, std::vector com) + : basic_value(std::move(x), + table_format_info {}, + std::move(com), + region_type {}) {} + + basic_value(table_type x, table_format_info fmt, std::vector com) + : basic_value(std::move(x), fmt, std::move(com), region_type {}) {} + + basic_value(table_type x, + table_format_info fmt, + std::vector com, + region_type reg) + : type_(value_t::table) + , table_(table_storage(detail::storage(std::move(x)), + std::move(fmt))) + , region_(std::move(reg)) + , comments_(std::move(com)) {} + + basic_value& operator=(table_type x) { + table_format_info fmt; + if (this->is_table()) { + fmt = this->as_table_fmt(); + } + this->cleanup(); + this->type_ = value_t::table; + this->region_ = region_type {}; + assigner(this->table_, + table_storage(detail::storage(std::move(x)), + std::move(fmt))); + return *this; + } + + // table-like + + private: + template + using enable_if_table_like_t = cxx::enable_if_t< + cxx::conjunction>, + detail::is_map, + cxx::negation>, + cxx::negation>>::value, + std::nullptr_t>; + + public: + template = nullptr> + basic_value(T x) + : basic_value(std::move(x), + table_format_info {}, + std::vector {}, + region_type {}) {} + + template = nullptr> + basic_value(T x, table_format_info fmt) + : basic_value(std::move(x), + std::move(fmt), + std::vector {}, + region_type {}) {} + + template = nullptr> + basic_value(T x, std::vector com) + : basic_value(std::move(x), + table_format_info {}, + std::move(com), + region_type {}) {} + + template = nullptr> + basic_value(T x, table_format_info fmt, std::vector com) + : basic_value(std::move(x), fmt, std::move(com), region_type {}) {} + + template = nullptr> + basic_value(T x, table_format_info fmt, std::vector com, region_type reg) + : type_(value_t::table) + , table_(table_storage(detail::storage( + table_type(std::make_move_iterator(x.begin()), + std::make_move_iterator(x.end()))), + std::move(fmt))) + , region_(std::move(reg)) + , comments_(std::move(com)) {} + + template = nullptr> + basic_value& operator=(T x) { + table_format_info fmt; + if (this->is_table()) { + fmt = this->as_table_fmt(); + } + this->cleanup(); + this->type_ = value_t::table; + this->region_ = region_type {}; + + table_type t(std::make_move_iterator(x.begin()), + std::make_move_iterator(x.end())); + assigner(this->table_, + table_storage(detail::storage(std::move(t)), + std::move(fmt))); + return *this; + } + + // }}} + + // constructor (user_defined) ========================================= {{{ + + template ::value, std::nullptr_t> = nullptr> + basic_value(const T& ud) + : basic_value( + into>::template into_toml(ud)) {} + + template ::value, std::nullptr_t> = nullptr> + basic_value(const T& ud, std::vector com) + : basic_value( + into>::template into_toml(ud), + std::move(com)) {} + + template ::value, std::nullptr_t> = nullptr> + basic_value& operator=(const T& ud) { + *this = into>::template into_toml(ud); + return *this; + } + + template , + cxx::negation>>::value, + std::nullptr_t> = nullptr> + basic_value(const T& ud) : basic_value(ud.into_toml()) {} + + template , + cxx::negation>>::value, + std::nullptr_t> = nullptr> + basic_value(const T& ud, std::vector com) + : basic_value(ud.into_toml(), std::move(com)) {} + + template , + cxx::negation>>::value, + std::nullptr_t> = nullptr> + basic_value& operator=(const T& ud) { + *this = ud.into_toml(); + return *this; + } + + template , + cxx::negation>>::value, + std::nullptr_t> = nullptr> + basic_value(const T& ud) + : basic_value(ud.template into_toml()) {} + + template , + cxx::negation>>::value, + std::nullptr_t> = nullptr> + basic_value(const T& ud, std::vector com) + : basic_value(ud.template into_toml(), std::move(com)) {} + + template , + cxx::negation>>::value, + std::nullptr_t> = nullptr> + basic_value& operator=(const T& ud) { + *this = ud.template into_toml(); + return *this; + } + + // }}} + + // empty value with region info ======================================= {{{ + + // mainly for `null` extension + basic_value(detail::none_t, region_type reg) noexcept + : type_(value_t::empty) + , empty_('\0') + , region_(std::move(reg)) + , comments_ {} {} + + // }}} + + // type checking ====================================================== {{{ + + template , value_type>::value, + std::nullptr_t> = nullptr> + bool is() const noexcept { + return detail::type_to_enum::value == this->type_; + } + + bool is(value_t t) const noexcept { + return t == this->type_; + } + + bool is_empty() const noexcept { + return this->is(value_t::empty); + } + + bool is_boolean() const noexcept { + return this->is(value_t::boolean); + } + + bool is_integer() const noexcept { + return this->is(value_t::integer); + } + + bool is_floating() const noexcept { + return this->is(value_t::floating); + } + + bool is_string() const noexcept { + return this->is(value_t::string); + } + + bool is_offset_datetime() const noexcept { + return this->is(value_t::offset_datetime); + } + + bool is_local_datetime() const noexcept { + return this->is(value_t::local_datetime); + } + + bool is_local_date() const noexcept { + return this->is(value_t::local_date); + } + + bool is_local_time() const noexcept { + return this->is(value_t::local_time); + } + + bool is_array() const noexcept { + return this->is(value_t::array); + } + + bool is_table() const noexcept { + return this->is(value_t::table); + } + + bool is_array_of_tables() const noexcept { + if (!this->is_array()) { + return false; + } + const auto& a = this->as_array(std::nothrow); // already checked. + + // when you define [[array.of.tables]], at least one empty table will be + // assigned. In case of array of inline tables, `array_of_tables = []`, + // there is no reason to consider this as an array of *tables*. + // So empty array is not an array-of-tables. + if (a.empty()) { + return false; + } + + // since toml v1.0.0 allows array of heterogeneous types, we need to + // check all the elements. if any of the elements is not a table, it + // is a heterogeneous array and cannot be expressed by `[[aot]]` form. + for (const auto& e : a) { + if (!e.is_table()) { + return false; + } + } + return true; + } + + value_t type() const noexcept { + return type_; + } + + // }}} + + // as_xxx (noexcept) version ========================================== {{{ + + template + const detail::enum_to_type_t>& as( + const std::nothrow_t&) const noexcept { + return detail::getter::get_nothrow(*this); + } + + template + detail::enum_to_type_t>& as( + const std::nothrow_t&) noexcept { + return detail::getter::get_nothrow(*this); + } + + const boolean_type& as_boolean(const std::nothrow_t&) const noexcept { + return this->boolean_.value; + } + + const integer_type& as_integer(const std::nothrow_t&) const noexcept { + return this->integer_.value; + } + + const floating_type& as_floating(const std::nothrow_t&) const noexcept { + return this->floating_.value; + } + + const string_type& as_string(const std::nothrow_t&) const noexcept { + return this->string_.value; + } + + const offset_datetime_type& as_offset_datetime( + const std::nothrow_t&) const noexcept { + return this->offset_datetime_.value; + } + + const local_datetime_type& as_local_datetime( + const std::nothrow_t&) const noexcept { + return this->local_datetime_.value; + } + + const local_date_type& as_local_date(const std::nothrow_t&) const noexcept { + return this->local_date_.value; + } + + const local_time_type& as_local_time(const std::nothrow_t&) const noexcept { + return this->local_time_.value; + } + + const array_type& as_array(const std::nothrow_t&) const noexcept { + return this->array_.value.get(); + } + + const table_type& as_table(const std::nothrow_t&) const noexcept { + return this->table_.value.get(); + } + + boolean_type& as_boolean(const std::nothrow_t&) noexcept { + return this->boolean_.value; + } + + integer_type& as_integer(const std::nothrow_t&) noexcept { + return this->integer_.value; + } + + floating_type& as_floating(const std::nothrow_t&) noexcept { + return this->floating_.value; + } + + string_type& as_string(const std::nothrow_t&) noexcept { + return this->string_.value; + } + + offset_datetime_type& as_offset_datetime(const std::nothrow_t&) noexcept { + return this->offset_datetime_.value; + } + + local_datetime_type& as_local_datetime(const std::nothrow_t&) noexcept { + return this->local_datetime_.value; + } + + local_date_type& as_local_date(const std::nothrow_t&) noexcept { + return this->local_date_.value; + } + + local_time_type& as_local_time(const std::nothrow_t&) noexcept { + return this->local_time_.value; + } + + array_type& as_array(const std::nothrow_t&) noexcept { + return this->array_.value.get(); + } + + table_type& as_table(const std::nothrow_t&) noexcept { + return this->table_.value.get(); + } + + // }}} + + // as_xxx (throw) ===================================================== {{{ + + template + const detail::enum_to_type_t>& as() const { + return detail::getter::get(*this); + } + + template + detail::enum_to_type_t>& as() { + return detail::getter::get(*this); + } + + const boolean_type& as_boolean() const { + if (this->type_ != value_t::boolean) { + this->throw_bad_cast("toml::value::as_boolean()", value_t::boolean); + } + return this->boolean_.value; + } + + const integer_type& as_integer() const { + if (this->type_ != value_t::integer) { + this->throw_bad_cast("toml::value::as_integer()", value_t::integer); + } + return this->integer_.value; + } + + const floating_type& as_floating() const { + if (this->type_ != value_t::floating) { + this->throw_bad_cast("toml::value::as_floating()", value_t::floating); + } + return this->floating_.value; + } + + const string_type& as_string() const { + if (this->type_ != value_t::string) { + this->throw_bad_cast("toml::value::as_string()", value_t::string); + } + return this->string_.value; + } + + const offset_datetime_type& as_offset_datetime() const { + if (this->type_ != value_t::offset_datetime) { + this->throw_bad_cast("toml::value::as_offset_datetime()", + value_t::offset_datetime); + } + return this->offset_datetime_.value; + } + + const local_datetime_type& as_local_datetime() const { + if (this->type_ != value_t::local_datetime) { + this->throw_bad_cast("toml::value::as_local_datetime()", + value_t::local_datetime); + } + return this->local_datetime_.value; + } + + const local_date_type& as_local_date() const { + if (this->type_ != value_t::local_date) { + this->throw_bad_cast("toml::value::as_local_date()", value_t::local_date); + } + return this->local_date_.value; + } + + const local_time_type& as_local_time() const { + if (this->type_ != value_t::local_time) { + this->throw_bad_cast("toml::value::as_local_time()", value_t::local_time); + } + return this->local_time_.value; + } + + const array_type& as_array() const { + if (this->type_ != value_t::array) { + this->throw_bad_cast("toml::value::as_array()", value_t::array); + } + return this->array_.value.get(); + } + + const table_type& as_table() const { + if (this->type_ != value_t::table) { + this->throw_bad_cast("toml::value::as_table()", value_t::table); + } + return this->table_.value.get(); + } + + // ------------------------------------------------------------------------ + // nonconst reference + + boolean_type& as_boolean() { + if (this->type_ != value_t::boolean) { + this->throw_bad_cast("toml::value::as_boolean()", value_t::boolean); + } + return this->boolean_.value; + } + + integer_type& as_integer() { + if (this->type_ != value_t::integer) { + this->throw_bad_cast("toml::value::as_integer()", value_t::integer); + } + return this->integer_.value; + } + + floating_type& as_floating() { + if (this->type_ != value_t::floating) { + this->throw_bad_cast("toml::value::as_floating()", value_t::floating); + } + return this->floating_.value; + } + + string_type& as_string() { + if (this->type_ != value_t::string) { + this->throw_bad_cast("toml::value::as_string()", value_t::string); + } + return this->string_.value; + } + + offset_datetime_type& as_offset_datetime() { + if (this->type_ != value_t::offset_datetime) { + this->throw_bad_cast("toml::value::as_offset_datetime()", + value_t::offset_datetime); + } + return this->offset_datetime_.value; + } + + local_datetime_type& as_local_datetime() { + if (this->type_ != value_t::local_datetime) { + this->throw_bad_cast("toml::value::as_local_datetime()", + value_t::local_datetime); + } + return this->local_datetime_.value; + } + + local_date_type& as_local_date() { + if (this->type_ != value_t::local_date) { + this->throw_bad_cast("toml::value::as_local_date()", value_t::local_date); + } + return this->local_date_.value; + } + + local_time_type& as_local_time() { + if (this->type_ != value_t::local_time) { + this->throw_bad_cast("toml::value::as_local_time()", value_t::local_time); + } + return this->local_time_.value; + } + + array_type& as_array() { + if (this->type_ != value_t::array) { + this->throw_bad_cast("toml::value::as_array()", value_t::array); + } + return this->array_.value.get(); + } + + table_type& as_table() { + if (this->type_ != value_t::table) { + this->throw_bad_cast("toml::value::as_table()", value_t::table); + } + return this->table_.value.get(); + } + + // }}} + + // format accessors (noexcept) ======================================== {{{ + + template + const detail::enum_to_fmt_type_t& as_fmt(const std::nothrow_t&) const noexcept { + return detail::getter::get_fmt_nothrow(*this); + } + + template + detail::enum_to_fmt_type_t& as_fmt(const std::nothrow_t&) noexcept { + return detail::getter::get_fmt_nothrow(*this); + } + + boolean_format_info& as_boolean_fmt(const std::nothrow_t&) noexcept { + return this->boolean_.format; + } + + integer_format_info& as_integer_fmt(const std::nothrow_t&) noexcept { + return this->integer_.format; + } + + floating_format_info& as_floating_fmt(const std::nothrow_t&) noexcept { + return this->floating_.format; + } + + string_format_info& as_string_fmt(const std::nothrow_t&) noexcept { + return this->string_.format; + } + + offset_datetime_format_info& as_offset_datetime_fmt( + const std::nothrow_t&) noexcept { + return this->offset_datetime_.format; + } + + local_datetime_format_info& as_local_datetime_fmt(const std::nothrow_t&) noexcept { + return this->local_datetime_.format; + } + + local_date_format_info& as_local_date_fmt(const std::nothrow_t&) noexcept { + return this->local_date_.format; + } + + local_time_format_info& as_local_time_fmt(const std::nothrow_t&) noexcept { + return this->local_time_.format; + } + + array_format_info& as_array_fmt(const std::nothrow_t&) noexcept { + return this->array_.format; + } + + table_format_info& as_table_fmt(const std::nothrow_t&) noexcept { + return this->table_.format; + } + + const boolean_format_info& as_boolean_fmt(const std::nothrow_t&) const noexcept { + return this->boolean_.format; + } + + const integer_format_info& as_integer_fmt(const std::nothrow_t&) const noexcept { + return this->integer_.format; + } + + const floating_format_info& as_floating_fmt(const std::nothrow_t&) const noexcept { + return this->floating_.format; + } + + const string_format_info& as_string_fmt(const std::nothrow_t&) const noexcept { + return this->string_.format; + } + + const offset_datetime_format_info& as_offset_datetime_fmt( + const std::nothrow_t&) const noexcept { + return this->offset_datetime_.format; + } + + const local_datetime_format_info& as_local_datetime_fmt( + const std::nothrow_t&) const noexcept { + return this->local_datetime_.format; + } + + const local_date_format_info& as_local_date_fmt( + const std::nothrow_t&) const noexcept { + return this->local_date_.format; + } + + const local_time_format_info& as_local_time_fmt( + const std::nothrow_t&) const noexcept { + return this->local_time_.format; + } + + const array_format_info& as_array_fmt(const std::nothrow_t&) const noexcept { + return this->array_.format; + } + + const table_format_info& as_table_fmt(const std::nothrow_t&) const noexcept { + return this->table_.format; + } + + // }}} + + // format accessors (throw) =========================================== {{{ + + template + const detail::enum_to_fmt_type_t& as_fmt() const { + return detail::getter::get_fmt(*this); + } + + template + detail::enum_to_fmt_type_t& as_fmt() { + return detail::getter::get_fmt(*this); + } + + const boolean_format_info& as_boolean_fmt() const { + if (this->type_ != value_t::boolean) { + this->throw_bad_cast("toml::value::as_boolean_fmt()", value_t::boolean); + } + return this->boolean_.format; + } + + const integer_format_info& as_integer_fmt() const { + if (this->type_ != value_t::integer) { + this->throw_bad_cast("toml::value::as_integer_fmt()", value_t::integer); + } + return this->integer_.format; + } + + const floating_format_info& as_floating_fmt() const { + if (this->type_ != value_t::floating) { + this->throw_bad_cast("toml::value::as_floating_fmt()", value_t::floating); + } + return this->floating_.format; + } + + const string_format_info& as_string_fmt() const { + if (this->type_ != value_t::string) { + this->throw_bad_cast("toml::value::as_string_fmt()", value_t::string); + } + return this->string_.format; + } + + const offset_datetime_format_info& as_offset_datetime_fmt() const { + if (this->type_ != value_t::offset_datetime) { + this->throw_bad_cast("toml::value::as_offset_datetime_fmt()", + value_t::offset_datetime); + } + return this->offset_datetime_.format; + } + + const local_datetime_format_info& as_local_datetime_fmt() const { + if (this->type_ != value_t::local_datetime) { + this->throw_bad_cast("toml::value::as_local_datetime_fmt()", + value_t::local_datetime); + } + return this->local_datetime_.format; + } + + const local_date_format_info& as_local_date_fmt() const { + if (this->type_ != value_t::local_date) { + this->throw_bad_cast("toml::value::as_local_date_fmt()", + value_t::local_date); + } + return this->local_date_.format; + } + + const local_time_format_info& as_local_time_fmt() const { + if (this->type_ != value_t::local_time) { + this->throw_bad_cast("toml::value::as_local_time_fmt()", + value_t::local_time); + } + return this->local_time_.format; + } + + const array_format_info& as_array_fmt() const { + if (this->type_ != value_t::array) { + this->throw_bad_cast("toml::value::as_array_fmt()", value_t::array); + } + return this->array_.format; + } + + const table_format_info& as_table_fmt() const { + if (this->type_ != value_t::table) { + this->throw_bad_cast("toml::value::as_table_fmt()", value_t::table); + } + return this->table_.format; + } + + // ------------------------------------------------------------------------ + // nonconst reference + + boolean_format_info& as_boolean_fmt() { + if (this->type_ != value_t::boolean) { + this->throw_bad_cast("toml::value::as_boolean_fmt()", value_t::boolean); + } + return this->boolean_.format; + } + + integer_format_info& as_integer_fmt() { + if (this->type_ != value_t::integer) { + this->throw_bad_cast("toml::value::as_integer_fmt()", value_t::integer); + } + return this->integer_.format; + } + + floating_format_info& as_floating_fmt() { + if (this->type_ != value_t::floating) { + this->throw_bad_cast("toml::value::as_floating_fmt()", value_t::floating); + } + return this->floating_.format; + } + + string_format_info& as_string_fmt() { + if (this->type_ != value_t::string) { + this->throw_bad_cast("toml::value::as_string_fmt()", value_t::string); + } + return this->string_.format; + } + + offset_datetime_format_info& as_offset_datetime_fmt() { + if (this->type_ != value_t::offset_datetime) { + this->throw_bad_cast("toml::value::as_offset_datetime_fmt()", + value_t::offset_datetime); + } + return this->offset_datetime_.format; + } + + local_datetime_format_info& as_local_datetime_fmt() { + if (this->type_ != value_t::local_datetime) { + this->throw_bad_cast("toml::value::as_local_datetime_fmt()", + value_t::local_datetime); + } + return this->local_datetime_.format; + } + + local_date_format_info& as_local_date_fmt() { + if (this->type_ != value_t::local_date) { + this->throw_bad_cast("toml::value::as_local_date_fmt()", + value_t::local_date); + } + return this->local_date_.format; + } + + local_time_format_info& as_local_time_fmt() { + if (this->type_ != value_t::local_time) { + this->throw_bad_cast("toml::value::as_local_time_fmt()", + value_t::local_time); + } + return this->local_time_.format; + } + + array_format_info& as_array_fmt() { + if (this->type_ != value_t::array) { + this->throw_bad_cast("toml::value::as_array_fmt()", value_t::array); + } + return this->array_.format; + } + + table_format_info& as_table_fmt() { + if (this->type_ != value_t::table) { + this->throw_bad_cast("toml::value::as_table_fmt()", value_t::table); + } + return this->table_.format; + } + + // }}} + + // table accessors ==================================================== {{{ + + value_type& at(const key_type& k) { + if (!this->is_table()) { + this->throw_bad_cast("toml::value::at(key_type)", value_t::table); + } + auto& table = this->as_table(std::nothrow); + const auto found = table.find(k); + if (found == table.end()) { + this->throw_key_not_found_error("toml::value::at", k); + } + assert(found->first == k); + return found->second; + } + + const value_type& at(const key_type& k) const { + if (!this->is_table()) { + this->throw_bad_cast("toml::value::at(key_type)", value_t::table); + } + const auto& table = this->as_table(std::nothrow); + const auto found = table.find(k); + if (found == table.end()) { + this->throw_key_not_found_error("toml::value::at", k); + } + assert(found->first == k); + return found->second; + } + + value_type& operator[](const key_type& k) { + if (this->is_empty()) { + (*this) = table_type {}; + } else if (!this->is_table()) // initialized, but not a table + { + this->throw_bad_cast("toml::value::operator[](key_type)", value_t::table); + } + return (this->as_table(std::nothrow))[k]; + } + + std::size_t count(const key_type& k) const { + if (!this->is_table()) { + this->throw_bad_cast("toml::value::count(key_type)", value_t::table); + } + return this->as_table(std::nothrow).count(k); + } + + bool contains(const key_type& k) const { + if (!this->is_table()) { + this->throw_bad_cast("toml::value::contains(key_type)", value_t::table); + } + const auto& table = this->as_table(std::nothrow); + return table.find(k) != table.end(); + } + + // }}} + + // array accessors ==================================================== {{{ + + value_type& at(const std::size_t idx) { + if (!this->is_array()) { + this->throw_bad_cast("toml::value::at(idx)", value_t::array); + } + auto& ar = this->as_array(std::nothrow); + + if (ar.size() <= idx) { + std::ostringstream oss; + oss << "actual length (" << ar.size() + << ") is shorter than the specified index (" << idx << ")."; + throw std::out_of_range(format_error( + "toml::value::at(idx): no element corresponding to the index", + this->location(), + oss.str())); + } + return ar.at(idx); + } + + const value_type& at(const std::size_t idx) const { + if (!this->is_array()) { + this->throw_bad_cast("toml::value::at(idx)", value_t::array); + } + const auto& ar = this->as_array(std::nothrow); + + if (ar.size() <= idx) { + std::ostringstream oss; + oss << "actual length (" << ar.size() + << ") is shorter than the specified index (" << idx << ")."; + + throw std::out_of_range(format_error( + "toml::value::at(idx): no element corresponding to the index", + this->location(), + oss.str())); + } + return ar.at(idx); + } + + value_type& operator[](const std::size_t idx) noexcept { + // no check... + return this->as_array(std::nothrow)[idx]; + } + + const value_type& operator[](const std::size_t idx) const noexcept { + // no check... + return this->as_array(std::nothrow)[idx]; + } + + void push_back(const value_type& x) { + if (!this->is_array()) { + this->throw_bad_cast("toml::value::push_back(idx)", value_t::array); + } + this->as_array(std::nothrow).push_back(x); + return; + } + + void push_back(value_type&& x) { + if (!this->is_array()) { + this->throw_bad_cast("toml::value::push_back(idx)", value_t::array); + } + this->as_array(std::nothrow).push_back(std::move(x)); + return; + } + + template + value_type& emplace_back(Ts&&... args) { + if (!this->is_array()) { + this->throw_bad_cast("toml::value::emplace_back(idx)", value_t::array); + } + auto& ar = this->as_array(std::nothrow); + ar.emplace_back(std::forward(args)...); + return ar.back(); + } + + std::size_t size() const { + switch (this->type_) { + case value_t::array: { + return this->as_array(std::nothrow).size(); + } + case value_t::table: { + return this->as_table(std::nothrow).size(); + } + case value_t::string: { + return this->as_string(std::nothrow).size(); + } + default: { + throw type_error( + format_error("toml::value::size(): bad_cast to container types", + this->location(), + "the actual type is " + to_string(this->type_)), + this->location()); + } + } + } + + // }}} + + source_location location() const { + return source_location(this->region_); + } + + const comment_type& comments() const noexcept { + return this->comments_; + } + + comment_type& comments() noexcept { + return this->comments_; + } + + private: + // private helper functions =========================================== {{{ + + void cleanup() noexcept { + switch (this->type_) { + case value_t::boolean: { + boolean_.~boolean_storage(); + break; + } + case value_t::integer: { + integer_.~integer_storage(); + break; + } + case value_t::floating: { + floating_.~floating_storage(); + break; + } + case value_t::string: { + string_.~string_storage(); + break; + } + case value_t::offset_datetime: { + offset_datetime_.~offset_datetime_storage(); + break; + } + case value_t::local_datetime: { + local_datetime_.~local_datetime_storage(); + break; + } + case value_t::local_date: { + local_date_.~local_date_storage(); + break; + } + case value_t::local_time: { + local_time_.~local_time_storage(); + break; + } + case value_t::array: { + array_.~array_storage(); + break; + } + case value_t::table: { + table_.~table_storage(); + break; + } + default: { + break; + } + } + this->type_ = value_t::empty; + return; + } + + template + static void assigner(T& dst, U&& v) { + const auto tmp = ::new (std::addressof(dst)) T(std::forward(v)); + assert(tmp == std::addressof(dst)); + (void)tmp; + } + + [[noreturn]] + void throw_bad_cast(const std::string& funcname, const value_t ty) const { + throw type_error(format_error(detail::make_type_error(*this, funcname, ty)), + this->location()); + } + + [[noreturn]] + void throw_key_not_found_error(const std::string& funcname, + const key_type& key) const { + throw std::out_of_range( + format_error(detail::make_not_found_error(*this, funcname, key))); + } + + template + friend void detail::change_region_of_value(basic_value&, + const basic_value&); + + template + friend class basic_value; + + // }}} + + private: + using boolean_storage = detail::value_with_format; + using integer_storage = detail::value_with_format; + using floating_storage = detail::value_with_format; + using string_storage = detail::value_with_format; + using offset_datetime_storage = + detail::value_with_format; + using local_datetime_storage = + detail::value_with_format; + using local_date_storage = + detail::value_with_format; + using local_time_storage = + detail::value_with_format; + using array_storage = + detail::value_with_format, array_format_info>; + using table_storage = + detail::value_with_format, table_format_info>; + + private: + value_t type_; + + union { + char empty_; // the smallest type + boolean_storage boolean_; + integer_storage integer_; + floating_storage floating_; + string_storage string_; + offset_datetime_storage offset_datetime_; + local_datetime_storage local_datetime_; + local_date_storage local_date_; + local_time_storage local_time_; + array_storage array_; + table_storage table_; + }; + + region_type region_; + comment_type comments_; + }; + + template + bool operator==(const basic_value& lhs, const basic_value& rhs) { + if (lhs.type() != rhs.type()) { + return false; + } + if (lhs.comments() != rhs.comments()) { + return false; + } + + switch (lhs.type()) { + case value_t::boolean: { + return lhs.as_boolean() == rhs.as_boolean(); + } + case value_t::integer: { + return lhs.as_integer() == rhs.as_integer(); + } + case value_t::floating: { + return lhs.as_floating() == rhs.as_floating(); + } + case value_t::string: { + return lhs.as_string() == rhs.as_string(); + } + case value_t::offset_datetime: { + return lhs.as_offset_datetime() == rhs.as_offset_datetime(); + } + case value_t::local_datetime: { + return lhs.as_local_datetime() == rhs.as_local_datetime(); + } + case value_t::local_date: { + return lhs.as_local_date() == rhs.as_local_date(); + } + case value_t::local_time: { + return lhs.as_local_time() == rhs.as_local_time(); + } + case value_t::array: { + return lhs.as_array() == rhs.as_array(); + } + case value_t::table: { + return lhs.as_table() == rhs.as_table(); + } + case value_t::empty: { + return true; + } + default: { + return false; + } + } + } + + template + bool operator!=(const basic_value& lhs, const basic_value& rhs) { + return !(lhs == rhs); + } + + template + cxx::enable_if_t< + cxx::conjunction::array_type>, + detail::is_comparable::table_type>>::value, + bool> + operator<(const basic_value& lhs, const basic_value& rhs) { + if (lhs.type() != rhs.type()) { + return (lhs.type() < rhs.type()); + } + switch (lhs.type()) { + case value_t::boolean: { + return lhs.as_boolean() < rhs.as_boolean() || + (lhs.as_boolean() == rhs.as_boolean() && + lhs.comments() < rhs.comments()); + } + case value_t::integer: { + return lhs.as_integer() < rhs.as_integer() || + (lhs.as_integer() == rhs.as_integer() && + lhs.comments() < rhs.comments()); + } + case value_t::floating: { + return lhs.as_floating() < rhs.as_floating() || + (lhs.as_floating() == rhs.as_floating() && + lhs.comments() < rhs.comments()); + } + case value_t::string: { + return lhs.as_string() < rhs.as_string() || + (lhs.as_string() == rhs.as_string() && + lhs.comments() < rhs.comments()); + } + case value_t::offset_datetime: { + return lhs.as_offset_datetime() < rhs.as_offset_datetime() || + (lhs.as_offset_datetime() == rhs.as_offset_datetime() && + lhs.comments() < rhs.comments()); + } + case value_t::local_datetime: { + return lhs.as_local_datetime() < rhs.as_local_datetime() || + (lhs.as_local_datetime() == rhs.as_local_datetime() && + lhs.comments() < rhs.comments()); + } + case value_t::local_date: { + return lhs.as_local_date() < rhs.as_local_date() || + (lhs.as_local_date() == rhs.as_local_date() && + lhs.comments() < rhs.comments()); + } + case value_t::local_time: { + return lhs.as_local_time() < rhs.as_local_time() || + (lhs.as_local_time() == rhs.as_local_time() && + lhs.comments() < rhs.comments()); + } + case value_t::array: { + return lhs.as_array() < rhs.as_array() || + (lhs.as_array() == rhs.as_array() && + lhs.comments() < rhs.comments()); + } + case value_t::table: { + return lhs.as_table() < rhs.as_table() || + (lhs.as_table() == rhs.as_table() && + lhs.comments() < rhs.comments()); + } + case value_t::empty: { + return lhs.comments() < rhs.comments(); + } + default: { + return lhs.comments() < rhs.comments(); + } + } + } + + template + cxx::enable_if_t< + cxx::conjunction::array_type>, + detail::is_comparable::table_type>>::value, + bool> + operator<=(const basic_value& lhs, const basic_value& rhs) { + return (lhs < rhs) || (lhs == rhs); + } + + template + cxx::enable_if_t< + cxx::conjunction::array_type>, + detail::is_comparable::table_type>>::value, + bool> + operator>(const basic_value& lhs, const basic_value& rhs) { + return !(lhs <= rhs); + } + + template + cxx::enable_if_t< + cxx::conjunction::array_type>, + detail::is_comparable::table_type>>::value, + bool> + operator>=(const basic_value& lhs, const basic_value& rhs) { + return !(lhs < rhs); + } + + // error_info helper + namespace detail { + template + error_info make_error_info_rec(error_info e, + const basic_value& v, + std::string msg, + Ts&&... tail) { + return make_error_info_rec(std::move(e), + v.location(), + std::move(msg), + std::forward(tail)...); + } + } // namespace detail + + template + error_info make_error_info(std::string title, + const basic_value& v, + std::string msg, + Ts&&... tail) { + return make_error_info(std::move(title), + v.location(), + std::move(msg), + std::forward(tail)...); + } + + template + std::string format_error(std::string title, + const basic_value& v, + std::string msg, + Ts&&... tail) { + return format_error(std::move(title), + v.location(), + std::move(msg), + std::forward(tail)...); + } + + namespace detail { + + template + error_info make_type_error(const basic_value& v, + const std::string& fname, + const value_t ty) { + return make_error_info(fname + ": bad_cast to " + to_string(ty), + v.location(), + "the actual type is " + to_string(v.type())); + } + + template + error_info make_not_found_error(const basic_value& v, + const std::string& fname, + const typename basic_value::key_type& key) { + const auto loc = v.location(); + const std::string title = fname + ": key \"" + + string_conv(key) + "\" not found"; + + std::vector> locs; + if (!loc.is_ok()) { + return error_info(title, locs); + } + + if (loc.first_line_number() == 1 && loc.first_column_number() == 1 && + loc.length() == 1) { + // The top-level table has its region at the 0th character of the file. + // That means that, in the case when a key is not found in the top-level + // table, the error message points to the first character. If the file has + // the first table at the first line, the error message would be like this. + // ```console + // [error] key "a" not found + // --> example.toml + // | + // 1 | [table] + // | ^------ in this table + // ``` + // It actually points to the top-level table at the first character, not + // `[table]`. But it is too confusing. To avoid the confusion, the error + // message should explicitly say "key not found in the top-level table". + locs.emplace_back(v.location(), "at the top-level table"); + } else { + locs.emplace_back(v.location(), "in this table"); + } + return error_info(title, locs); + } + +#define TOML11_DETAIL_GENERATE_COMPTIME_GETTER(ty) \ + template \ + struct getter { \ + using value_type = basic_value; \ + using result_type = enum_to_type_t; \ + using format_type = enum_to_fmt_type_t; \ + \ + static result_type& get(value_type& v) { \ + return v.as_##ty(); \ + } \ + static result_type const& get(const value_type& v) { \ + return v.as_##ty(); \ + } \ + \ + static result_type& get_nothrow(value_type& v) noexcept { \ + return v.as_##ty(std::nothrow); \ + } \ + static result_type const& get_nothrow(const value_type& v) noexcept { \ + return v.as_##ty(std::nothrow); \ + } \ + \ + static format_type& get_fmt(value_type& v) { \ + return v.as_##ty##_fmt(); \ + } \ + static format_type const& get_fmt(const value_type& v) { \ + return v.as_##ty##_fmt(); \ + } \ + \ + static format_type& get_fmt_nothrow(value_type& v) noexcept { \ + return v.as_##ty##_fmt(std::nothrow); \ + } \ + static format_type const& get_fmt_nothrow(const value_type& v) noexcept { \ + return v.as_##ty##_fmt(std::nothrow); \ + } \ + }; + + TOML11_DETAIL_GENERATE_COMPTIME_GETTER(boolean) + TOML11_DETAIL_GENERATE_COMPTIME_GETTER(integer) + TOML11_DETAIL_GENERATE_COMPTIME_GETTER(floating) + TOML11_DETAIL_GENERATE_COMPTIME_GETTER(string) + TOML11_DETAIL_GENERATE_COMPTIME_GETTER(offset_datetime) + TOML11_DETAIL_GENERATE_COMPTIME_GETTER(local_datetime) + TOML11_DETAIL_GENERATE_COMPTIME_GETTER(local_date) + TOML11_DETAIL_GENERATE_COMPTIME_GETTER(local_time) + TOML11_DETAIL_GENERATE_COMPTIME_GETTER(array) + TOML11_DETAIL_GENERATE_COMPTIME_GETTER(table) + +#undef TOML11_DETAIL_GENERATE_COMPTIME_GETTER + + template + void change_region_of_value(basic_value& dst, const basic_value& src) { + dst.region_ = std::move(src.region_); + return; + } + + } // namespace detail +} // namespace toml +#endif // TOML11_VALUE_HPP +#ifndef TOML11_VISIT_HPP +#define TOML11_VISIT_HPP + +namespace toml { + + template + cxx::return_type_of_t::boolean_type&> visit( + Visitor&& visitor, + const basic_value& v) { + switch (v.type()) { + case value_t::boolean: { + return visitor(v.as_boolean()); + } + case value_t::integer: { + return visitor(v.as_integer()); + } + case value_t::floating: { + return visitor(v.as_floating()); + } + case value_t::string: { + return visitor(v.as_string()); + } + case value_t::offset_datetime: { + return visitor(v.as_offset_datetime()); + } + case value_t::local_datetime: { + return visitor(v.as_local_datetime()); + } + case value_t::local_date: { + return visitor(v.as_local_date()); + } + case value_t::local_time: { + return visitor(v.as_local_time()); + } + case value_t::array: { + return visitor(v.as_array()); + } + case value_t::table: { + return visitor(v.as_table()); + } + case value_t::empty: + break; + default: + break; + } + throw type_error(format_error("[error] toml::visit: toml::basic_value " + "does not have any valid type.", + v.location(), + "here"), + v.location()); + } + + template + cxx::return_type_of_t::boolean_type&> visit( + Visitor&& visitor, + basic_value& v) { + switch (v.type()) { + case value_t::boolean: { + return visitor(v.as_boolean()); + } + case value_t::integer: { + return visitor(v.as_integer()); + } + case value_t::floating: { + return visitor(v.as_floating()); + } + case value_t::string: { + return visitor(v.as_string()); + } + case value_t::offset_datetime: { + return visitor(v.as_offset_datetime()); + } + case value_t::local_datetime: { + return visitor(v.as_local_datetime()); + } + case value_t::local_date: { + return visitor(v.as_local_date()); + } + case value_t::local_time: { + return visitor(v.as_local_time()); + } + case value_t::array: { + return visitor(v.as_array()); + } + case value_t::table: { + return visitor(v.as_table()); + } + case value_t::empty: + break; + default: + break; + } + throw type_error(format_error("[error] toml::visit: toml::basic_value " + "does not have any valid type.", + v.location(), + "here"), + v.location()); + } + + template + cxx::return_type_of_t::boolean_type&&> visit( + Visitor&& visitor, + basic_value&& v) { + switch (v.type()) { + case value_t::boolean: { + return visitor(std::move(v.as_boolean())); + } + case value_t::integer: { + return visitor(std::move(v.as_integer())); + } + case value_t::floating: { + return visitor(std::move(v.as_floating())); + } + case value_t::string: { + return visitor(std::move(v.as_string())); + } + case value_t::offset_datetime: { + return visitor(std::move(v.as_offset_datetime())); + } + case value_t::local_datetime: { + return visitor(std::move(v.as_local_datetime())); + } + case value_t::local_date: { + return visitor(std::move(v.as_local_date())); + } + case value_t::local_time: { + return visitor(std::move(v.as_local_time())); + } + case value_t::array: { + return visitor(std::move(v.as_array())); + } + case value_t::table: { + return visitor(std::move(v.as_table())); + } + case value_t::empty: + break; + default: + break; + } + throw type_error(format_error("[error] toml::visit: toml::basic_value " + "does not have any valid type.", + v.location(), + "here"), + v.location()); + } + +} // namespace toml +#endif // TOML11_VISIT_HPP +#ifndef TOML11_TYPES_HPP +#define TOML11_TYPES_HPP + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace toml { + + // forward decl + template + class basic_value; + + // when you use a special integer type as toml::value::integer_type, parse must + // be able to read it. So, type_config has static member functions that read the + // integer_type as {dec, hex, oct, bin}-integer. But, in most cases, operator<< + // is enough. To make config easy, we provide the default read functions. + // + // Before this functions is called, syntax is checked and prefix(`0x` etc) and + // spacer(`_`) are removed. + + template + result read_dec_int(const std::string& str, + const source_location src) { + constexpr auto max_digits = std::numeric_limits::digits; + assert(!str.empty()); + + T val { 0 }; + std::istringstream iss(str); + iss >> val; + if (iss.fail()) { + return err(make_error_info("toml::parse_dec_integer: " + "too large integer: current max digits = 2^" + + std::to_string(max_digits), + std::move(src), + "must be < 2^" + std::to_string(max_digits))); + } + return ok(val); + } + + template + result read_hex_int(const std::string& str, + const source_location src) { + constexpr auto max_digits = std::numeric_limits::digits; + assert(!str.empty()); + + T val { 0 }; + std::istringstream iss(str); + iss >> std::hex >> val; + if (iss.fail()) { + return err(make_error_info("toml::parse_hex_integer: " + "too large integer: current max value = 2^" + + std::to_string(max_digits), + std::move(src), + "must be < 2^" + std::to_string(max_digits))); + } + return ok(val); + } + + template + result read_oct_int(const std::string& str, + const source_location src) { + constexpr auto max_digits = std::numeric_limits::digits; + assert(!str.empty()); + + T val { 0 }; + std::istringstream iss(str); + iss >> std::oct >> val; + if (iss.fail()) { + return err(make_error_info("toml::parse_oct_integer: " + "too large integer: current max value = 2^" + + std::to_string(max_digits), + std::move(src), + "must be < 2^" + std::to_string(max_digits))); + } + return ok(val); + } + + template + result read_bin_int(const std::string& str, + const source_location src) { + constexpr auto is_bounded = std::numeric_limits::is_bounded; + constexpr auto max_digits = std::numeric_limits::digits; + const auto max_value = (std::numeric_limits::max)(); + + T val { 0 }; + T base { 1 }; + for (auto i = str.rbegin(); i != str.rend(); ++i) { + const auto c = *i; + if (c == '1') { + val += base; + // prevent `base` from overflow + if (is_bounded && max_value / 2 < base && std::next(i) != str.rend()) { + base = 0; + } else { + base *= 2; + } + } else { + assert(c == '0'); + + if (is_bounded && max_value / 2 < base && std::next(i) != str.rend()) { + base = 0; + } else { + base *= 2; + } + } + } + if (base == 0) { + return err(make_error_info("toml::parse_bin_integer: " + "too large integer: current max value = 2^" + + std::to_string(max_digits), + std::move(src), + "must be < 2^" + std::to_string(max_digits))); + } + return ok(val); + } + + template + result read_int(const std::string& str, + const source_location src, + const std::uint8_t base) { + assert(base == 10 || base == 16 || base == 8 || base == 2); + switch (base) { + case 2: { + return read_bin_int(str, src); + } + case 8: { + return read_oct_int(str, src); + } + case 16: { + return read_hex_int(str, src); + } + default: { + assert(base == 10); + return read_dec_int(str, src); + } + } + } + + inline result read_hex_float(const std::string& str, + const source_location src, + float val) { +#if defined(_MSC_VER) && !defined(__clang__) + const auto res = ::sscanf_s(str.c_str(), "%a", std::addressof(val)); +#else + const auto res = std::sscanf(str.c_str(), "%a", std::addressof(val)); +#endif + if (res != 1) { + return err( + make_error_info("toml::parse_floating: " + "failed to read hexadecimal floating point value ", + std::move(src), + "here")); + } + return ok(val); + } + + inline result read_hex_float(const std::string& str, + const source_location src, + double val) { +#if defined(_MSC_VER) && !defined(__clang__) + const auto res = ::sscanf_s(str.c_str(), "%la", std::addressof(val)); +#else + const auto res = std::sscanf(str.c_str(), "%la", std::addressof(val)); +#endif + if (res != 1) { + return err( + make_error_info("toml::parse_floating: " + "failed to read hexadecimal floating point value ", + std::move(src), + "here")); + } + return ok(val); + } + + template + cxx::enable_if_t< + cxx::conjunction, double>>, + cxx::negation, float>>>::value, + result> + read_hex_float(const std::string&, const source_location src, T) { + return err(make_error_info( + "toml::parse_floating: failed to read " + "floating point value because of unknown type in type_config", + std::move(src), + "here")); + } + + template + result read_dec_float(const std::string& str, + const source_location src) { + T val; + std::istringstream iss(str); + iss >> val; + if (iss.fail()) { + return err( + make_error_info("toml::parse_floating: " + "failed to read floating point value from stream", + std::move(src), + "here")); + } + return ok(val); + } + + template + result read_float(const std::string& str, + const source_location src, + const bool is_hex) { + if (is_hex) { + return read_hex_float(str, src, T {}); + } else { + return read_dec_float(str, src); + } + } + + struct type_config { + using comment_type = preserve_comments; + + using boolean_type = bool; + using integer_type = std::int64_t; + using floating_type = double; + using string_type = std::string; + + template + using array_type = std::vector; + template + using table_type = std::unordered_map; + + static result parse_int(const std::string& str, + const source_location src, + const std::uint8_t base) { + return read_int(str, src, base); + } + + static result parse_float(const std::string& str, + const source_location src, + const bool is_hex) { + return read_float(str, src, is_hex); + } + }; + + using value = basic_value; + using table = typename value::table_type; + using array = typename value::array_type; + + struct ordered_type_config { + using comment_type = preserve_comments; + + using boolean_type = bool; + using integer_type = std::int64_t; + using floating_type = double; + using string_type = std::string; + + template + using array_type = std::vector; + template + using table_type = ordered_map; + + static result parse_int(const std::string& str, + const source_location src, + const std::uint8_t base) { + return read_int(str, src, base); + } + + static result parse_float(const std::string& str, + const source_location src, + const bool is_hex) { + return read_float(str, src, is_hex); + } + }; + + using ordered_value = basic_value; + using ordered_table = typename ordered_value::table_type; + using ordered_array = typename ordered_value::array_type; + + // ---------------------------------------------------------------------------- + // meta functions for internal use + + namespace detail { + + // ---------------------------------------------------------------------------- + // check if type T has all the needed member types + + struct has_comment_type_impl { + template + static std::true_type check(typename T::comment_type*); + template + static std::false_type check(...); + }; + + template + using has_comment_type = decltype(has_comment_type_impl::check(nullptr)); + + struct has_integer_type_impl { + template + static std::true_type check(typename T::integer_type*); + template + static std::false_type check(...); + }; + + template + using has_integer_type = decltype(has_integer_type_impl::check(nullptr)); + + struct has_floating_type_impl { + template + static std::true_type check(typename T::floating_type*); + template + static std::false_type check(...); + }; + + template + using has_floating_type = decltype(has_floating_type_impl::check(nullptr)); + + struct has_string_type_impl { + template + static std::true_type check(typename T::string_type*); + template + static std::false_type check(...); + }; + + template + using has_string_type = decltype(has_string_type_impl::check(nullptr)); + + struct has_array_type_impl { + template + static std::true_type check(typename T::template array_type*); + template + static std::false_type check(...); + }; + + template + using has_array_type = decltype(has_array_type_impl::check(nullptr)); + + struct has_table_type_impl { + template + static std::true_type check(typename T::template table_type*); + template + static std::false_type check(...); + }; + + template + using has_table_type = decltype(has_table_type_impl::check(nullptr)); + + struct has_parse_int_impl { + template + static std::true_type check(decltype(std::declval().parse_int( + std::declval(), + std::declval(), + std::declval()))*); + template + static std::false_type check(...); + }; + + template + using has_parse_int = decltype(has_parse_int_impl::check(nullptr)); + + struct has_parse_float_impl { + template + static std::true_type check(decltype(std::declval().parse_float( + std::declval(), + std::declval(), + std::declval()))*); + template + static std::false_type check(...); + }; + + template + using has_parse_float = decltype(has_parse_float_impl::check(nullptr)); + + template + using is_type_config = cxx::conjunction, + has_integer_type, + has_floating_type, + has_string_type, + has_array_type, + has_table_type, + has_parse_int, + has_parse_float>; + + } // namespace detail +} // namespace toml + +#if defined(TOML11_COMPILE_SOURCES) +namespace toml { + extern template class basic_value; + extern template class basic_value; +} // namespace toml +#endif // TOML11_COMPILE_SOURCES + +#endif // TOML11_TYPES_HPP +#ifndef TOML11_GET_HPP +#define TOML11_GET_HPP + +#include + +#if defined(TOML11_HAS_STRING_VIEW) + #include +#endif // string_view + +namespace toml { + + // ============================================================================ + // T is toml::value; identity transformation. + + template + cxx::enable_if_t>::value, T>& get( + basic_value& v) { + return v; + } + + template + const cxx::enable_if_t>::value, T>& get( + const basic_value& v) { + return v; + } + + template + cxx::enable_if_t>::value, T> get( + basic_value&& v) { + return basic_value(std::move(v)); + } + + // ============================================================================ + // exact toml::* type + + template + cxx::enable_if_t>::value, T>& get( + basic_value& v) { + constexpr auto ty = detail::type_to_enum>::value; + return detail::getter::get(v); + } + + template + const cxx::enable_if_t>::value, T>& get( + const basic_value& v) { + constexpr auto ty = detail::type_to_enum>::value; + return detail::getter::get(v); + } + + template + cxx::enable_if_t>::value, T> get( + basic_value&& v) { + constexpr auto ty = detail::type_to_enum>::value; + return detail::getter::get(std::move(v)); + } + + // ============================================================================ + // T is toml::basic_value + + template + cxx::enable_if_t, + cxx::negation>>>::value, + T> + get(basic_value v) { + return T(std::move(v)); + } + + // ============================================================================ + // integer convertible from toml::value::integer_type + + template + cxx::enable_if_t, + cxx::negation>, + detail::is_not_toml_type>, + cxx::negation>, + cxx::negation>>::value, + T> + get(const basic_value& v) { + return static_cast(v.as_integer()); + } + + // ============================================================================ + // floating point convertible from toml::value::floating_type + + template + cxx::enable_if_t, + detail::is_not_toml_type>, + cxx::negation>, + cxx::negation>>::value, + T> + get(const basic_value& v) { + return static_cast(v.as_floating()); + } + + // ============================================================================ + // std::string with different char/trait/allocator + + template + cxx::enable_if_t>, + detail::is_1byte_std_basic_string>::value, + T> + get(const basic_value& v) { + return detail::string_conv>(v.as_string()); + } + + // ============================================================================ + // std::string_view + +#if defined(TOML11_HAS_STRING_VIEW) + + template + cxx::enable_if_t::string_type>::value, T> + get(const basic_value& v) { + return T(v.as_string()); + } + +#endif // string_view + + // ============================================================================ + // std::chrono::duration from toml::local_time + + template + cxx::enable_if_t::value, T> get( + const basic_value& v) { + return std::chrono::duration_cast( + std::chrono::nanoseconds(v.as_local_time())); + } + + // ============================================================================ + // std::chrono::system_clock::time_point from toml::datetime variants + + template + cxx::enable_if_t::value, T> get( + const basic_value& v) { + switch (v.type()) { + case value_t::local_date: { + return std::chrono::system_clock::time_point(v.as_local_date()); + } + case value_t::local_datetime: { + return std::chrono::system_clock::time_point(v.as_local_datetime()); + } + case value_t::offset_datetime: { + return std::chrono::system_clock::time_point(v.as_offset_datetime()); + } + default: { + const auto loc = v.location(); + throw type_error( + format_error("toml::get: " + "bad_cast to std::chrono::system_clock::time_point", + loc, + "the actual type is " + to_string(v.type())), + loc); + } + } + } + + // ============================================================================ + // forward declaration to use this recursively. ignore this and go ahead. + + // array-like (w/ push_back) + template + cxx::enable_if_t< + cxx::conjunction< + detail::is_container, // T is a container + detail::has_push_back_method, // .push_back() works + detail::is_not_toml_type>, // but not toml::array + cxx::negation>, // but not std::basic_string +#if defined(TOML11_HAS_STRING_VIEW) + cxx::negation>, // but not std::basic_string_view +#endif + cxx::negation>, // no T.from_toml() + cxx::negation>, // no toml::from + cxx::negation&>>>::value, + T> + get(const basic_value&); + + // std::array + template + cxx::enable_if_t::value, T> get(const basic_value&); + + // std::forward_list + template + cxx::enable_if_t::value, T> get( + const basic_value&); + + // std::pair + template + cxx::enable_if_t::value, T> get(const basic_value&); + + // std::tuple + template + cxx::enable_if_t::value, T> get(const basic_value&); + + // std::map (key is convertible from toml::value::key_type) + template + cxx::enable_if_t< + cxx::conjunction, // T is map + detail::is_not_toml_type>, // but not toml::table + std::is_convertible::key_type, + typename T::key_type>, // keys are convertible + cxx::negation>, // no T.from_toml() + cxx::negation>, // no toml::from + cxx::negation&>>>::value, + T> + get(const basic_value& v); + + // std::map (key is not convertible from toml::value::key_type, + // but is a std::basic_string) + template + cxx::enable_if_t< + cxx::conjunction< + detail::is_map, // T is map + detail::is_not_toml_type>, // but not toml::table + cxx::negation::key_type, + typename T::key_type>>, // keys are NOT convertible + detail::is_1byte_std_basic_string, // is std::basic_string + cxx::negation>, // no T.from_toml() + cxx::negation>, // no toml::from + cxx::negation&>>>::value, + T> + get(const basic_value& v); + + // toml::from::from_toml(v) + template + cxx::enable_if_t::value, T> get( + const basic_value&); + + // has T.from_toml(v) but no from + template + cxx::enable_if_t, // has T.from_toml() + cxx::negation>, // no toml::from + std::is_default_constructible // T{} works + >::value, + T> + get(const basic_value&); + + // T(const toml::value&) and T is not toml::basic_value, + // and it does not have `from` nor `from_toml`. + template + cxx::enable_if_t&>, // has T(const basic_value&) + cxx::negation>, // but not basic_value itself + cxx::negation>, // no .from_toml() + cxx::negation> // no toml::from + >::value, + T> + get(const basic_value&); + + // ============================================================================ + // array-like types; most likely STL container, like std::vector, etc. + + template + cxx::enable_if_t< + cxx::conjunction< + detail::is_container, // T is a container + detail::has_push_back_method, // .push_back() works + detail::is_not_toml_type>, // but not toml::array + cxx::negation>, // but not std::basic_string +#if defined(TOML11_HAS_STRING_VIEW) + cxx::negation>, // but not std::basic_string_view +#endif + cxx::negation>, // no T.from_toml() + cxx::negation>, // no toml::from + cxx::negation&>>>::value, + T> + get(const basic_value& v) { + using value_type = typename T::value_type; + const auto& a = v.as_array(); + + T container; + detail::try_reserve(container, a.size()); // if T has .reserve(), call it + + for (const auto& elem : a) { + container.push_back(get(elem)); + } + return container; + } + + // ============================================================================ + // std::array + + template + cxx::enable_if_t::value, T> get(const basic_value& v) { + using value_type = typename T::value_type; + const auto& a = v.as_array(); + + T container; + if (a.size() != container.size()) { + const auto loc = v.location(); + throw std::out_of_range( + format_error("toml::get: while converting to an array: " + " array size is " + + std::to_string(container.size()) + " but there are " + + std::to_string(a.size()) + " elements in toml array.", + loc, + "here")); + } + for (std::size_t i = 0; i < a.size(); ++i) { + container.at(i) = ::toml::get(a.at(i)); + } + return container; + } + + // ============================================================================ + // std::forward_list + + template + cxx::enable_if_t::value, T> get( + const basic_value& v) { + using value_type = typename T::value_type; + + T container; + for (const auto& elem : v.as_array()) { + container.push_front(get(elem)); + } + container.reverse(); + return container; + } + + // ============================================================================ + // std::pair + + template + cxx::enable_if_t::value, T> get(const basic_value& v) { + using first_type = typename T::first_type; + using second_type = typename T::second_type; + + const auto& ar = v.as_array(); + if (ar.size() != 2) { + const auto loc = v.location(); + throw std::out_of_range( + format_error("toml::get: while converting std::pair: " + " but there are " + + std::to_string(ar.size()) + " > 2 elements in toml array.", + loc, + "here")); + } + return std::make_pair(::toml::get(ar.at(0)), + ::toml::get(ar.at(1))); + } + + // ============================================================================ + // std::tuple. + + namespace detail { + template + T get_tuple_impl(const Array& a, cxx::index_sequence) { + return std::make_tuple( + ::toml::get::type>(a.at(I))...); + } + } // namespace detail + + template + cxx::enable_if_t::value, T> get(const basic_value& v) { + const auto& ar = v.as_array(); + if (ar.size() != std::tuple_size::value) { + const auto loc = v.location(); + throw std::out_of_range(format_error( + "toml::get: while converting std::tuple: " + " there are " + + std::to_string(ar.size()) + " > " + + std::to_string(std::tuple_size::value) + " elements in toml array.", + loc, + "here")); + } + return detail::get_tuple_impl( + ar, + cxx::make_index_sequence::value> {}); + } + + // ============================================================================ + // map-like types; most likely STL map, like std::map or std::unordered_map. + + // key is convertible from toml::value::key_type + template + cxx::enable_if_t< + cxx::conjunction, // T is map + detail::is_not_toml_type>, // but not toml::table + std::is_convertible::key_type, + typename T::key_type>, // keys are convertible + cxx::negation>, // no T.from_toml() + cxx::negation>, // no toml::from + cxx::negation&>>>::value, + T> + get(const basic_value& v) { + using key_type = typename T::key_type; + using mapped_type = typename T::mapped_type; + static_assert( + std::is_convertible::key_type, key_type>::value, + "toml::get only supports map type of which key_type is " + "convertible from toml::basic_value::key_type."); + + T m; + for (const auto& kv : v.as_table()) { + m.emplace(key_type(kv.first), get(kv.second)); + } + return m; + } + + // key is NOT convertible from toml::value::key_type but std::basic_string + template + cxx::enable_if_t< + cxx::conjunction< + detail::is_map, // T is map + detail::is_not_toml_type>, // but not toml::table + cxx::negation::key_type, + typename T::key_type>>, // keys are NOT convertible + detail::is_1byte_std_basic_string, // is std::basic_string + cxx::negation>, // no T.from_toml() + cxx::negation>, // no toml::from + cxx::negation&>>>::value, + T> + get(const basic_value& v) { + using key_type = typename T::key_type; + using mapped_type = typename T::mapped_type; + + T m; + for (const auto& kv : v.as_table()) { + m.emplace(detail::string_conv(kv.first), + get(kv.second)); + } + return m; + } + + // ============================================================================ + // user-defined, but convertible types. + + // toml::from + template + cxx::enable_if_t::value, T> get( + const basic_value& v) { + return ::toml::from::from_toml(v); + } + + // has T.from_toml(v) but no from + template + cxx::enable_if_t, // has T.from_toml() + cxx::negation>, // no toml::from + std::is_default_constructible // T{} works + >::value, + T> + get(const basic_value& v) { + T ud; + ud.from_toml(v); + return ud; + } + + // T(const toml::value&) and T is not toml::basic_value, + // and it does not have `from` nor `from_toml`. + template + cxx::enable_if_t&>, // has T(const basic_value&) + cxx::negation>, // but not basic_value itself + cxx::negation>, // no .from_toml() + cxx::negation> // no toml::from + >::value, + T> + get(const basic_value& v) { + return T(v); + } + + // ============================================================================ + // get_or(value, fallback) + + template + const cxx::enable_if_t::value, basic_value>& get_or( + const basic_value& v, + const basic_value&) { + return v; + } + + template + cxx::enable_if_t::value, basic_value>& get_or( + basic_value& v, + basic_value&) { + return v; + } + + template + cxx::enable_if_t::value, basic_value> get_or( + basic_value&& v, + basic_value&&) { + return v; + } + + // ---------------------------------------------------------------------------- + // specialization for the exact toml types (return type becomes lvalue ref) + + template + const cxx::enable_if_t>::value, T>& + get_or(const basic_value& v, const T& opt) noexcept { + try { + return get>(v); + } catch (...) { + return opt; + } + } + + template + cxx::enable_if_t>, + detail::is_exact_toml_type>>::value, + T>& + get_or(basic_value& v, T& opt) noexcept { + try { + return get>(v); + } catch (...) { + return opt; + } + } + + template + cxx::enable_if_t, basic_value>::value, + cxx::remove_cvref_t> + get_or(basic_value&& v, T&& opt) noexcept { + try { + return get>(std::move(v)); + } catch (...) { + return cxx::remove_cvref_t(std::forward(opt)); + } + } + + // ---------------------------------------------------------------------------- + // specialization for string literal + + // template + // typename basic_value::string_type + // get_or(const basic_value& v, + // const typename basic_value::string_type::value_type (&opt)[N]) + // { + // try + // { + // return v.as_string(); + // } + // catch(...) + // { + // return typename basic_value::string_type(opt); + // } + // } + // + // The above only matches to the literal, like `get_or(v, "foo");` but not + // ```cpp + // const auto opt = "foo"; + // const auto str = get_or(v, opt); + // ``` + // . And the latter causes an error. + // To match to both `"foo"` and `const auto opt = "foo"`, we take a pointer to + // a character here. + + template + typename basic_value::string_type get_or( + const basic_value& v, + const typename basic_value::string_type::value_type* opt) { + try { + return v.as_string(); + } catch (...) { + return typename basic_value::string_type(opt); + } + } + + // ---------------------------------------------------------------------------- + // others (require type conversion and return type cannot be lvalue reference) + + template + cxx::enable_if_t< + cxx::conjunction< + cxx::negation>, + cxx::negation>>, + cxx::negation, + const typename basic_value::string_type::value_type*>>>::value, + cxx::remove_cvref_t> + get_or(const basic_value& v, T&& opt) { + try { + return get>(v); + } catch (...) { + return cxx::remove_cvref_t(std::forward(opt)); + } + } + +} // namespace toml +#endif // TOML11_GET_HPP +#ifndef TOML11_FIND_HPP +#define TOML11_FIND_HPP + +#include + +#if defined(TOML11_HAS_STRING_VIEW) + #include +#endif + +namespace toml { + + // ---------------------------------------------------------------------------- + // find(value, key); + + template + decltype(::toml::get(std::declval&>())) find( + const basic_value& v, + const typename basic_value::key_type& ky) { + return ::toml::get(v.at(ky)); + } + + template + decltype(::toml::get(std::declval&>())) find( + basic_value& v, + const typename basic_value::key_type& ky) { + return ::toml::get(v.at(ky)); + } + + template + decltype(::toml::get(std::declval&&>())) find( + basic_value&& v, + const typename basic_value::key_type& ky) { + return ::toml::get(std::move(v.at(ky))); + } + + // ---------------------------------------------------------------------------- + // find(value, idx) + + template + decltype(::toml::get(std::declval&>())) find( + const basic_value& v, + const std::size_t idx) { + return ::toml::get(v.at(idx)); + } + + template + decltype(::toml::get(std::declval&>())) find( + basic_value& v, + const std::size_t idx) { + return ::toml::get(v.at(idx)); + } + + template + decltype(::toml::get(std::declval&&>())) find( + basic_value&& v, + const std::size_t idx) { + return ::toml::get(std::move(v.at(idx))); + } + + // ---------------------------------------------------------------------------- + // find(value, key/idx), w/o conversion + + template + cxx::enable_if_t::value, basic_value>& find( + basic_value& v, + const typename basic_value::key_type& ky) { + return v.at(ky); + } + + template + const cxx::enable_if_t::value, basic_value>& find( + const basic_value& v, + const typename basic_value::key_type& ky) { + return v.at(ky); + } + + template + cxx::enable_if_t::value, basic_value> find( + basic_value&& v, + const typename basic_value::key_type& ky) { + return basic_value(std::move(v.at(ky))); + } + + template + cxx::enable_if_t::value, basic_value>& find( + basic_value& v, + const std::size_t idx) { + return v.at(idx); + } + + template + const cxx::enable_if_t::value, basic_value>& find( + const basic_value& v, + const std::size_t idx) { + return v.at(idx); + } + + template + cxx::enable_if_t::value, basic_value> find( + basic_value&& v, + const std::size_t idx) { + return basic_value(std::move(v.at(idx))); + } + + // -------------------------------------------------------------------------- + // toml::find(toml::value, toml::key, Ts&& ... keys) + + namespace detail { + + // It suppresses warnings by -Wsign-conversion when we pass integer literal + // to toml::find. integer literal `0` is deduced as an int, and will be + // converted to std::size_t. This causes sign-conversion. + + template + std::size_t key_cast(const std::size_t& v) noexcept { + return v; + } + + template + cxx::enable_if_t>::value, std::size_t> key_cast( + const T& v) noexcept { + return static_cast(v); + } + + // for string-like (string, string literal, string_view) + + template + const typename basic_value::key_type& key_cast( + const typename basic_value::key_type& v) noexcept { + return v; + } + + template + typename basic_value::key_type key_cast( + const typename basic_value::key_type::value_type* v) { + return typename basic_value::key_type(v); + } +#if defined(TOML11_HAS_STRING_VIEW) + template + typename basic_value::key_type key_cast(const std::string_view v) { + return typename basic_value::key_type(v); + } +#endif // string_view + + } // namespace detail + + // ---------------------------------------------------------------------------- + // find(v, keys...) + + template + const cxx::enable_if_t::value, basic_value>& + find(const basic_value& v, const K1& k1, const K2& k2, const Ks&... ks) { + return find(v.at(detail::key_cast(k1)), detail::key_cast(k2), ks...); + } + + template + cxx::enable_if_t::value, basic_value>& find( + basic_value& v, + const K1& k1, + const K2& k2, + const Ks&... ks) { + return find(v.at(detail::key_cast(k1)), detail::key_cast(k2), ks...); + } + + template + cxx::enable_if_t::value, basic_value> find( + basic_value&& v, + const K1& k1, + const K2& k2, + const Ks&... ks) { + return find(std::move(v.at(detail::key_cast(k1))), + detail::key_cast(k2), + ks...); + } + + // ---------------------------------------------------------------------------- + // find(v, keys...) + + template + decltype(::toml::get(std::declval&>())) find( + const basic_value& v, + const K1& k1, + const K2& k2, + const Ks&... ks) { + return find(v.at(detail::key_cast(k1)), detail::key_cast(k2), ks...); + } + + template + decltype(::toml::get(std::declval&>())) find( + basic_value& v, + const K1& k1, + const K2& k2, + const Ks&... ks) { + return find(v.at(detail::key_cast(k1)), detail::key_cast(k2), ks...); + } + + template + decltype(::toml::get(std::declval&&>())) find( + basic_value&& v, + const K1& k1, + const K2& k2, + const Ks&... ks) { + return find(std::move(v.at(detail::key_cast(k1))), + detail::key_cast(k2), + ks...); + } + + // =========================================================================== + // find_or(value, key, fallback) + + // --------------------------------------------------------------------------- + // find_or(v, key, other_v) + + template + cxx::enable_if_t::value, basic_value>& find_or( + basic_value& v, + const K& k, + basic_value& opt) noexcept { + try { + return ::toml::find(v, detail::key_cast(k)); + } catch (...) { + return opt; + } + } + + template + const cxx::enable_if_t::value, basic_value>& find_or( + const basic_value& v, + const K& k, + const basic_value& opt) noexcept { + try { + return ::toml::find(v, detail::key_cast(k)); + } catch (...) { + return opt; + } + } + + template + cxx::enable_if_t::value, basic_value> find_or( + basic_value&& v, + const K& k, + basic_value&& opt) noexcept { + try { + return ::toml::find(v, detail::key_cast(k)); + } catch (...) { + return opt; + } + } + + // --------------------------------------------------------------------------- + // toml types (return type can be a reference) + + template + cxx::enable_if_t>::value, + const cxx::remove_cvref_t&> + find_or(const basic_value& v, const K& k, const T& opt) { + try { + return ::toml::get(v.at(detail::key_cast(k))); + } catch (...) { + return opt; + } + } + + template + cxx::enable_if_t>, + detail::is_exact_toml_type>>::value, + cxx::remove_cvref_t&> + find_or(basic_value& v, const K& k, T& opt) { + try { + return ::toml::get(v.at(detail::key_cast(k))); + } catch (...) { + return opt; + } + } + + template + cxx::enable_if_t>::value, + cxx::remove_cvref_t> + find_or(basic_value&& v, const K& k, T opt) { + try { + return ::toml::get(std::move(v.at(detail::key_cast(k)))); + } catch (...) { + return T(std::move(opt)); + } + } + + // --------------------------------------------------------------------------- + // string literal (deduced as std::string) + + // XXX to avoid confusion when T is explicitly specified in find_or(), + // we restrict the string type as std::string. + template + cxx::enable_if_t::value, std::string> find_or( + const basic_value& v, + const K& k, + const char* opt) { + try { + return ::toml::get(v.at(detail::key_cast(k))); + } catch (...) { + return std::string(opt); + } + } + + // --------------------------------------------------------------------------- + // other types (requires type conversion and return type cannot be a reference) + + template + cxx::enable_if_t< + cxx::conjunction< + cxx::negation>>, + detail::is_not_toml_type, basic_value>, + cxx::negation, + const typename basic_value::string_type::value_type*>>>::value, + cxx::remove_cvref_t> + find_or(const basic_value& v, const K& ky, T opt) { + try { + return ::toml::get>(v.at(detail::key_cast(ky))); + } catch (...) { + return cxx::remove_cvref_t(std::move(opt)); + } + } + + // ---------------------------------------------------------------------------- + // recursive + + namespace detail { + template + T& last_one(T& arg) { + return arg; + } + + template + auto last_one(T1&, T2& arg, Ts&... args) -> decltype(last_one(arg, args...)) { + return last_one(arg, args...); + } + } // namespace detail + + template + auto find_or(Value&& v, const K1& k1, const K2& k2, K3&& k3, Ks&&... keys) noexcept + -> cxx::enable_if_t< + detail::is_basic_value>::value, + decltype(find_or(v, k2, std::forward(k3), std::forward(keys)...))> { + try { + return find_or(v.at(k1), k2, std::forward(k3), std::forward(keys)...); + } catch (...) { + return detail::last_one(k3, keys...); + } + } + + template + T find_or(const basic_value& v, + const K1& k1, + const K2& k2, + const K3& k3, + const Ks&... keys) noexcept { + try { + return find_or(v.at(k1), k2, k3, keys...); + } catch (...) { + return static_cast(detail::last_one(k3, keys...)); + } + } + + template + auto find_or(Value&& v, const K1& k1, const K2& k2, K3&& k3, K4&& k4, Ks&&... keys) noexcept + -> cxx::enable_if_t>::value, + decltype(find_or(v, + k2, + std::forward(k3), + std::forward(k4), + std::forward(keys)...))> { + try { + return find_or(v.at(k1), + k2, + std::forward(k3), + std::forward(k4), + std::forward(keys)...); + } catch (...) { + return detail::last_one(k4, keys...); + } + } + + template + T find_or(const basic_value& v, + const K1& k1, + const K2& k2, + const K3& k3, + const K4& k4, + const Ks&... keys) noexcept { + try { + return find_or(v.at(k1), k2, k3, k4, keys...); + } catch (...) { + return static_cast(detail::last_one(k4, keys...)); + } + } + +} // namespace toml +#endif // TOML11_FIND_HPP +#ifndef TOML11_CONVERSION_HPP +#define TOML11_CONVERSION_HPP + +#if defined(TOML11_HAS_OPTIONAL) + + #include + +namespace toml { + namespace detail { + + template + inline constexpr bool is_optional_v = false; + + template + inline constexpr bool is_optional_v> = true; + + template + void find_member_variable_from_value(T& obj, + const basic_value& v, + const char* var_name) { + if constexpr (is_optional_v) { + if (v.contains(var_name)) { + obj = toml::find(v, var_name); + } else { + obj = std::nullopt; + } + } else { + obj = toml::find(v, var_name); + } + } + + template + void assign_member_variable_to_value(const T& obj, + basic_value& v, + const char* var_name) { + if constexpr (is_optional_v) { + if (obj.has_value()) { + v[var_name] = obj.value(); + } + } else { + v[var_name] = obj; + } + } + + } // namespace detail +} // namespace toml + +#else + +namespace toml { + namespace detail { + + template + void find_member_variable_from_value(T& obj, + const basic_value& v, + const char* var_name) { + obj = toml::find(v, var_name); + } + + template + void assign_member_variable_to_value(const T& obj, + basic_value& v, + const char* var_name) { + v[var_name] = obj; + } + + } // namespace detail +} // namespace toml + +#endif // optional + +// use it in the following way. +// ```cpp +// namespace foo +// { +// struct Foo +// { +// std::string s; +// double d; +// int i; +// }; +// } // foo +// +// TOML11_DEFINE_CONVERSION_NON_INTRUSIVE(foo::Foo, s, d, i) +// ``` +// +// And then you can use `toml::get(v)` and `toml::find(file, "foo");` +// + +#define TOML11_STRINGIZE_AUX(x) #x +#define TOML11_STRINGIZE(x) TOML11_STRINGIZE_AUX(x) + +#define TOML11_CONCATENATE_AUX(x, y) x##y +#define TOML11_CONCATENATE(x, y) TOML11_CONCATENATE_AUX(x, y) + +// ============================================================================ +// TOML11_DEFINE_CONVERSION_NON_INTRUSIVE + +#ifndef TOML11_WITHOUT_DEFINE_NON_INTRUSIVE + + // ---------------------------------------------------------------------------- + // TOML11_ARGS_SIZE + + #define TOML11_INDEX_RSEQ() \ + 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, \ + 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 + #define TOML11_ARGS_SIZE_IMPL(ARG1, \ + ARG2, \ + ARG3, \ + ARG4, \ + ARG5, \ + ARG6, \ + ARG7, \ + ARG8, \ + ARG9, \ + ARG10, \ + ARG11, \ + ARG12, \ + ARG13, \ + ARG14, \ + ARG15, \ + ARG16, \ + ARG17, \ + ARG18, \ + ARG19, \ + ARG20, \ + ARG21, \ + ARG22, \ + ARG23, \ + ARG24, \ + ARG25, \ + ARG26, \ + ARG27, \ + ARG28, \ + ARG29, \ + ARG30, \ + ARG31, \ + ARG32, \ + N, \ + ...) \ + N + #define TOML11_ARGS_SIZE_AUX(...) TOML11_ARGS_SIZE_IMPL(__VA_ARGS__) + #define TOML11_ARGS_SIZE(...) \ + TOML11_ARGS_SIZE_AUX(__VA_ARGS__, TOML11_INDEX_RSEQ()) + + // ---------------------------------------------------------------------------- + // TOML11_FOR_EACH_VA_ARGS + + #define TOML11_FOR_EACH_VA_ARGS_AUX_1(FUNCTOR, ARG1) FUNCTOR(ARG1) + #define TOML11_FOR_EACH_VA_ARGS_AUX_2(FUNCTOR, ARG1, ...) \ + FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_1(FUNCTOR, __VA_ARGS__) + #define TOML11_FOR_EACH_VA_ARGS_AUX_3(FUNCTOR, ARG1, ...) \ + FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_2(FUNCTOR, __VA_ARGS__) + #define TOML11_FOR_EACH_VA_ARGS_AUX_4(FUNCTOR, ARG1, ...) \ + FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_3(FUNCTOR, __VA_ARGS__) + #define TOML11_FOR_EACH_VA_ARGS_AUX_5(FUNCTOR, ARG1, ...) \ + FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_4(FUNCTOR, __VA_ARGS__) + #define TOML11_FOR_EACH_VA_ARGS_AUX_6(FUNCTOR, ARG1, ...) \ + FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_5(FUNCTOR, __VA_ARGS__) + #define TOML11_FOR_EACH_VA_ARGS_AUX_7(FUNCTOR, ARG1, ...) \ + FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_6(FUNCTOR, __VA_ARGS__) + #define TOML11_FOR_EACH_VA_ARGS_AUX_8(FUNCTOR, ARG1, ...) \ + FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_7(FUNCTOR, __VA_ARGS__) + #define TOML11_FOR_EACH_VA_ARGS_AUX_9(FUNCTOR, ARG1, ...) \ + FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_8(FUNCTOR, __VA_ARGS__) + #define TOML11_FOR_EACH_VA_ARGS_AUX_10(FUNCTOR, ARG1, ...) \ + FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_9(FUNCTOR, __VA_ARGS__) + #define TOML11_FOR_EACH_VA_ARGS_AUX_11(FUNCTOR, ARG1, ...) \ + FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_10(FUNCTOR, __VA_ARGS__) + #define TOML11_FOR_EACH_VA_ARGS_AUX_12(FUNCTOR, ARG1, ...) \ + FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_11(FUNCTOR, __VA_ARGS__) + #define TOML11_FOR_EACH_VA_ARGS_AUX_13(FUNCTOR, ARG1, ...) \ + FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_12(FUNCTOR, __VA_ARGS__) + #define TOML11_FOR_EACH_VA_ARGS_AUX_14(FUNCTOR, ARG1, ...) \ + FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_13(FUNCTOR, __VA_ARGS__) + #define TOML11_FOR_EACH_VA_ARGS_AUX_15(FUNCTOR, ARG1, ...) \ + FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_14(FUNCTOR, __VA_ARGS__) + #define TOML11_FOR_EACH_VA_ARGS_AUX_16(FUNCTOR, ARG1, ...) \ + FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_15(FUNCTOR, __VA_ARGS__) + #define TOML11_FOR_EACH_VA_ARGS_AUX_17(FUNCTOR, ARG1, ...) \ + FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_16(FUNCTOR, __VA_ARGS__) + #define TOML11_FOR_EACH_VA_ARGS_AUX_18(FUNCTOR, ARG1, ...) \ + FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_17(FUNCTOR, __VA_ARGS__) + #define TOML11_FOR_EACH_VA_ARGS_AUX_19(FUNCTOR, ARG1, ...) \ + FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_18(FUNCTOR, __VA_ARGS__) + #define TOML11_FOR_EACH_VA_ARGS_AUX_20(FUNCTOR, ARG1, ...) \ + FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_19(FUNCTOR, __VA_ARGS__) + #define TOML11_FOR_EACH_VA_ARGS_AUX_21(FUNCTOR, ARG1, ...) \ + FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_20(FUNCTOR, __VA_ARGS__) + #define TOML11_FOR_EACH_VA_ARGS_AUX_22(FUNCTOR, ARG1, ...) \ + FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_21(FUNCTOR, __VA_ARGS__) + #define TOML11_FOR_EACH_VA_ARGS_AUX_23(FUNCTOR, ARG1, ...) \ + FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_22(FUNCTOR, __VA_ARGS__) + #define TOML11_FOR_EACH_VA_ARGS_AUX_24(FUNCTOR, ARG1, ...) \ + FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_23(FUNCTOR, __VA_ARGS__) + #define TOML11_FOR_EACH_VA_ARGS_AUX_25(FUNCTOR, ARG1, ...) \ + FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_24(FUNCTOR, __VA_ARGS__) + #define TOML11_FOR_EACH_VA_ARGS_AUX_26(FUNCTOR, ARG1, ...) \ + FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_25(FUNCTOR, __VA_ARGS__) + #define TOML11_FOR_EACH_VA_ARGS_AUX_27(FUNCTOR, ARG1, ...) \ + FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_26(FUNCTOR, __VA_ARGS__) + #define TOML11_FOR_EACH_VA_ARGS_AUX_28(FUNCTOR, ARG1, ...) \ + FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_27(FUNCTOR, __VA_ARGS__) + #define TOML11_FOR_EACH_VA_ARGS_AUX_29(FUNCTOR, ARG1, ...) \ + FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_28(FUNCTOR, __VA_ARGS__) + #define TOML11_FOR_EACH_VA_ARGS_AUX_30(FUNCTOR, ARG1, ...) \ + FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_29(FUNCTOR, __VA_ARGS__) + #define TOML11_FOR_EACH_VA_ARGS_AUX_31(FUNCTOR, ARG1, ...) \ + FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_30(FUNCTOR, __VA_ARGS__) + #define TOML11_FOR_EACH_VA_ARGS_AUX_32(FUNCTOR, ARG1, ...) \ + FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_31(FUNCTOR, __VA_ARGS__) + + #define TOML11_FOR_EACH_VA_ARGS(FUNCTOR, ...) \ + TOML11_CONCATENATE(TOML11_FOR_EACH_VA_ARGS_AUX_, \ + TOML11_ARGS_SIZE(__VA_ARGS__)) \ + (FUNCTOR, __VA_ARGS__) + + #define TOML11_FIND_MEMBER_VARIABLE_FROM_VALUE(VAR_NAME) \ + toml::detail::find_member_variable_from_value(obj.VAR_NAME, \ + v, \ + TOML11_STRINGIZE(VAR_NAME)); + + #define TOML11_ASSIGN_MEMBER_VARIABLE_TO_VALUE(VAR_NAME) \ + toml::detail::assign_member_variable_to_value(obj.VAR_NAME, \ + v, \ + TOML11_STRINGIZE(VAR_NAME)); + + #define TOML11_DEFINE_CONVERSION_NON_INTRUSIVE(NAME, ...) \ + namespace toml { \ + template <> \ + struct from { \ + template \ + static NAME from_toml(const basic_value& v) { \ + NAME obj; \ + TOML11_FOR_EACH_VA_ARGS(TOML11_FIND_MEMBER_VARIABLE_FROM_VALUE, \ + __VA_ARGS__) \ + return obj; \ + } \ + }; \ + template <> \ + struct into { \ + template \ + static basic_value into_toml(const NAME& obj) { \ + ::toml::basic_value v = typename ::toml::basic_value::table_type {}; \ + TOML11_FOR_EACH_VA_ARGS(TOML11_ASSIGN_MEMBER_VARIABLE_TO_VALUE, \ + __VA_ARGS__) \ + return v; \ + } \ + }; \ + } /* toml */ + +#endif // TOML11_WITHOUT_DEFINE_NON_INTRUSIVE + +#endif // TOML11_CONVERSION_HPP +#ifndef TOML11_CONTEXT_HPP +#define TOML11_CONTEXT_HPP + +#include + +namespace toml { + namespace detail { + + template + class context { + public: + explicit context(const spec& toml_spec) + : toml_spec_(toml_spec) + , errors_ {} {} + + bool has_error() const noexcept { + return !errors_.empty(); + } + + const std::vector& errors() const noexcept { + return errors_; + } + + semantic_version& toml_version() noexcept { + return toml_spec_.version; + } + + const semantic_version& toml_version() const noexcept { + return toml_spec_.version; + } + + spec& toml_spec() noexcept { + return toml_spec_; + } + + const spec& toml_spec() const noexcept { + return toml_spec_; + } + + void report_error(error_info err) { + this->errors_.push_back(std::move(err)); + } + + error_info pop_last_error() { + assert(!errors_.empty()); + auto e = std::move(errors_.back()); + errors_.pop_back(); + return e; + } + + private: + spec toml_spec_; + std::vector errors_; + }; + + } // namespace detail +} // namespace toml + +#if defined(TOML11_COMPILE_SOURCES) +namespace toml { + struct type_config; + struct ordered_type_config; + + namespace detail { + extern template class context<::toml::type_config>; + extern template class context<::toml::ordered_type_config>; + } // namespace detail +} // namespace toml +#endif // TOML11_COMPILE_SOURCES + +#endif // TOML11_CONTEXT_HPP +#ifndef TOML11_SCANNER_HPP +#define TOML11_SCANNER_HPP + +#ifndef TOML11_SCANNER_FWD_HPP + #define TOML11_SCANNER_FWD_HPP + + #include + #include + #include + #include + #include + #include + #include + +namespace toml { + namespace detail { + + class scanner_base { + public: + virtual ~scanner_base() = default; + virtual region scan(location& loc) const = 0; + virtual scanner_base* clone() const = 0; + + // returns expected character or set of characters or literal. + // to show the error location, it changes loc (in `sequence`, especially). + virtual std::string expected_chars(location& loc) const = 0; + virtual std::string name() const = 0; + }; + + // make `scanner*` copyable + struct scanner_storage { + template >::value, + std::nullptr_t> = nullptr> + explicit scanner_storage(Scanner&& s) + : scanner_(cxx::make_unique>( + std::forward(s))) {} + + ~scanner_storage() = default; + + scanner_storage(const scanner_storage& other); + scanner_storage& operator=(const scanner_storage& other); + scanner_storage(scanner_storage&&) = default; + scanner_storage& operator=(scanner_storage&&) = default; + + bool is_ok() const noexcept { + return static_cast(scanner_); + } + + region scan(location& loc) const; + + std::string expected_chars(location& loc) const; + + scanner_base& get() const noexcept; + + std::string name() const; + + private: + std::unique_ptr scanner_; + }; + + // ---------------------------------------------------------------------------- + + class character final : public scanner_base { + public: + using char_type = location::char_type; + + public: + explicit character(const char_type c) noexcept : value_(c) {} + + ~character() override = default; + + region scan(location& loc) const override; + + std::string expected_chars(location&) const override; + + scanner_base* clone() const override; + + std::string name() const override; + + private: + char_type value_; + }; + + // ---------------------------------------------------------------------------- + + class character_either final : public scanner_base { + public: + using char_type = location::char_type; + + public: + explicit character_either(std::initializer_list cs) noexcept + : chars_(std::move(cs)) { + assert(!this->chars_.empty()); + } + + template + explicit character_either(const char (&cs)[N]) noexcept + : chars_(N - 1, '\0') { + static_assert(N >= 1, ""); + for (std::size_t i = 0; i + 1 < N; ++i) { + chars_.at(i) = char_type(cs[i]); + } + } + + ~character_either() override = default; + + region scan(location& loc) const override; + + std::string expected_chars(location&) const override; + + scanner_base* clone() const override; + + void push_back(const char_type c); + + std::string name() const override; + + private: + std::vector chars_; + }; + + // ---------------------------------------------------------------------------- + + class character_in_range final : public scanner_base { + public: + using char_type = location::char_type; + + public: + explicit character_in_range(const char_type from, const char_type to) noexcept + : from_(from) + , to_(to) {} + + ~character_in_range() override = default; + + region scan(location& loc) const override; + + std::string expected_chars(location&) const override; + + scanner_base* clone() const override; + + std::string name() const override; + + private: + char_type from_; + char_type to_; + }; + + // ---------------------------------------------------------------------------- + + class literal final : public scanner_base { + public: + using char_type = location::char_type; + + public: + template + explicit literal(const char (&cs)[N]) noexcept + : value_(cs) + , size_(N - 1) // remove null character at the end + {} + + ~literal() override = default; + + region scan(location& loc) const override; + + std::string expected_chars(location&) const override; + + scanner_base* clone() const override; + + std::string name() const override; + + private: + const char* value_; + std::size_t size_; + }; + + // ---------------------------------------------------------------------------- + + class sequence final : public scanner_base { + public: + using char_type = location::char_type; + + public: + template + explicit sequence(Ts&&... args) { + push_back_all(std::forward(args)...); + } + + sequence(const sequence&) = default; + sequence(sequence&&) = default; + sequence& operator=(const sequence&) = default; + sequence& operator=(sequence&&) = default; + ~sequence() override = default; + + region scan(location& loc) const override; + + std::string expected_chars(location& loc) const override; + + scanner_base* clone() const override; + + template + void push_back(Scanner&& other_scanner) { + this->others_.emplace_back(std::forward(other_scanner)); + } + + std::string name() const override; + + private: + void push_back_all() { + return; + } + + template + void push_back_all(T&& head, Ts&&... args) { + others_.emplace_back(std::forward(head)); + push_back_all(std::forward(args)...); + return; + } + + private: + std::vector others_; + }; + + // ---------------------------------------------------------------------------- + + class either final : public scanner_base { + public: + using char_type = location::char_type; + + public: + template + explicit either(Ts&&... args) { + push_back_all(std::forward(args)...); + } + + either(const either&) = default; + either(either&&) = default; + either& operator=(const either&) = default; + either& operator=(either&&) = default; + ~either() override = default; + + region scan(location& loc) const override; + + std::string expected_chars(location& loc) const override; + + scanner_base* clone() const override; + + template + void push_back(Scanner&& other_scanner) { + this->others_.emplace_back(std::forward(other_scanner)); + } + + std::string name() const override; + + private: + void push_back_all() { + return; + } + + template + void push_back_all(T&& head, Ts&&... args) { + others_.emplace_back(std::forward(head)); + push_back_all(std::forward(args)...); + return; + } + + private: + std::vector others_; + }; + + // ---------------------------------------------------------------------------- + + class repeat_exact final : public scanner_base { + public: + using char_type = location::char_type; + + public: + template + repeat_exact(const std::size_t length, Scanner&& other) + : length_(length) + , other_(std::forward(other)) {} + + repeat_exact(const repeat_exact&) = default; + repeat_exact(repeat_exact&&) = default; + repeat_exact& operator=(const repeat_exact&) = default; + repeat_exact& operator=(repeat_exact&&) = default; + ~repeat_exact() override = default; + + region scan(location& loc) const override; + + std::string expected_chars(location& loc) const override; + + scanner_base* clone() const override; + + std::string name() const override; + + private: + std::size_t length_; + scanner_storage other_; + }; + + // ---------------------------------------------------------------------------- + + class repeat_at_least final : public scanner_base { + public: + using char_type = location::char_type; + + public: + template + repeat_at_least(const std::size_t length, Scanner&& s) + : length_(length) + , other_(std::forward(s)) {} + + repeat_at_least(const repeat_at_least&) = default; + repeat_at_least(repeat_at_least&&) = default; + repeat_at_least& operator=(const repeat_at_least&) = default; + repeat_at_least& operator=(repeat_at_least&&) = default; + ~repeat_at_least() override = default; + + region scan(location& loc) const override; + + std::string expected_chars(location& loc) const override; + + scanner_base* clone() const override; + + std::string name() const override; + + private: + std::size_t length_; + scanner_storage other_; + }; + + // ---------------------------------------------------------------------------- + + class maybe final : public scanner_base { + public: + using char_type = location::char_type; + + public: + template + explicit maybe(Scanner&& s) : other_(std::forward(s)) {} + + maybe(const maybe&) = default; + maybe(maybe&&) = default; + maybe& operator=(const maybe&) = default; + maybe& operator=(maybe&&) = default; + ~maybe() override = default; + + region scan(location& loc) const override; + + std::string expected_chars(location&) const override; + + scanner_base* clone() const override; + + std::string name() const override; + + private: + scanner_storage other_; + }; + + } // namespace detail +} // namespace toml +#endif // TOML11_SCANNER_FWD_HPP + +#if !defined(TOML11_COMPILE_SOURCES) + #ifndef TOML11_SCANNER_IMPL_HPP + #define TOML11_SCANNER_IMPL_HPP + +namespace toml { + namespace detail { + + TOML11_INLINE scanner_storage::scanner_storage(const scanner_storage& other) + : scanner_(nullptr) { + if (other.is_ok()) { + scanner_.reset(other.get().clone()); + } + } + + TOML11_INLINE scanner_storage& scanner_storage::operator=( + const scanner_storage& other) { + if (this == std::addressof(other)) { + return *this; + } + if (other.is_ok()) { + scanner_.reset(other.get().clone()); + } + return *this; + } + + TOML11_INLINE region scanner_storage::scan(location& loc) const { + assert(this->is_ok()); + return this->scanner_->scan(loc); + } + + TOML11_INLINE std::string scanner_storage::expected_chars(location& loc) const { + assert(this->is_ok()); + return this->scanner_->expected_chars(loc); + } + + TOML11_INLINE scanner_base& scanner_storage::get() const noexcept { + assert(this->is_ok()); + return *scanner_; + } + + TOML11_INLINE std::string scanner_storage::name() const { + assert(this->is_ok()); + return this->scanner_->name(); + } + + // ---------------------------------------------------------------------------- + + TOML11_INLINE region character::scan(location& loc) const { + if (loc.eof()) { + return region {}; + } + + if (loc.current() == this->value_) { + const auto first = loc; + loc.advance(1); + return region(first, loc); + } + return region {}; + } + + TOML11_INLINE std::string character::expected_chars(location&) const { + return show_char(value_); + } + + TOML11_INLINE scanner_base* character::clone() const { + return new character(*this); + } + + TOML11_INLINE std::string character::name() const { + return "character{" + show_char(value_) + "}"; + } + + // ---------------------------------------------------------------------------- + + TOML11_INLINE region character_either::scan(location& loc) const { + if (loc.eof()) { + return region {}; + } + + for (const auto c : this->chars_) { + if (loc.current() == c) { + const auto first = loc; + loc.advance(1); + return region(first, loc); + } + } + return region {}; + } + + TOML11_INLINE std::string character_either::expected_chars(location&) const { + assert(!chars_.empty()); + + std::string expected; + if (chars_.size() == 1) { + expected += show_char(chars_.at(0)); + } else if (chars_.size() == 2) { + expected += show_char(chars_.at(0)) + " or " + show_char(chars_.at(1)); + } else { + for (std::size_t i = 0; i < chars_.size(); ++i) { + if (i != 0) { + expected += ", "; + } + if (i + 1 == chars_.size()) { + expected += "or "; + } + expected += show_char(chars_.at(i)); + } + } + return expected; + } + + TOML11_INLINE scanner_base* character_either::clone() const { + return new character_either(*this); + } + + TOML11_INLINE void character_either::push_back(const char_type c) { + chars_.push_back(c); + } + + TOML11_INLINE std::string character_either::name() const { + std::string n("character_either{"); + for (const auto c : this->chars_) { + n += show_char(c); + n += ", "; + } + if (!this->chars_.empty()) { + n.pop_back(); + n.pop_back(); + } + n += "}"; + return n; + } + + // ---------------------------------------------------------------------------- + // character_in_range + + TOML11_INLINE region character_in_range::scan(location& loc) const { + if (loc.eof()) { + return region {}; + } + + const auto curr = loc.current(); + if (this->from_ <= curr && curr <= this->to_) { + const auto first = loc; + loc.advance(1); + return region(first, loc); + } + return region {}; + } + + TOML11_INLINE std::string character_in_range::expected_chars(location&) const { + std::string expected("from `"); + expected += show_char(from_); + expected += "` to `"; + expected += show_char(to_); + expected += "`"; + return expected; + } + + TOML11_INLINE scanner_base* character_in_range::clone() const { + return new character_in_range(*this); + } + + TOML11_INLINE std::string character_in_range::name() const { + return "character_in_range{" + show_char(from_) + "," + show_char(to_) + "}"; + } + + // ---------------------------------------------------------------------------- + // literal + + TOML11_INLINE region literal::scan(location& loc) const { + const auto first = loc; + for (std::size_t i = 0; i < size_; ++i) { + if (loc.eof() || char_type(value_[i]) != loc.current()) { + loc = first; + return region {}; + } + loc.advance(1); + } + return region(first, loc); + } + + TOML11_INLINE std::string literal::expected_chars(location&) const { + return std::string(value_); + } + + TOML11_INLINE scanner_base* literal::clone() const { + return new literal(*this); + } + + TOML11_INLINE std::string literal::name() const { + return std::string("literal{") + std::string(value_, size_) + "}"; + } + + // ---------------------------------------------------------------------------- + // sequence + + TOML11_INLINE region sequence::scan(location& loc) const { + const auto first = loc; + for (const auto& other : others_) { + const auto reg = other.scan(loc); + if (!reg.is_ok()) { + loc = first; + return region {}; + } + } + return region(first, loc); + } + + TOML11_INLINE std::string sequence::expected_chars(location& loc) const { + const auto first = loc; + for (const auto& other : others_) { + const auto reg = other.scan(loc); + if (!reg.is_ok()) { + return other.expected_chars(loc); + } + } + assert(false); + return ""; // XXX + } + + TOML11_INLINE scanner_base* sequence::clone() const { + return new sequence(*this); + } + + TOML11_INLINE std::string sequence::name() const { + std::string n("sequence{"); + for (const auto& other : others_) { + n += other.name(); + n += ", "; + } + if (!this->others_.empty()) { + n.pop_back(); + n.pop_back(); + } + n += "}"; + return n; + } + + // ---------------------------------------------------------------------------- + // either + + TOML11_INLINE region either::scan(location& loc) const { + for (const auto& other : others_) { + const auto reg = other.scan(loc); + if (reg.is_ok()) { + return reg; + } + } + return region {}; + } + + TOML11_INLINE std::string either::expected_chars(location& loc) const { + assert(!others_.empty()); + + std::string expected = others_.at(0).expected_chars(loc); + if (others_.size() == 2) { + expected += " or "; + expected += others_.at(1).expected_chars(loc); + } else { + for (std::size_t i = 1; i < others_.size(); ++i) { + expected += ", "; + if (i + 1 == others_.size()) { + expected += "or "; + } + expected += others_.at(i).expected_chars(loc); + } + } + return expected; + } + + TOML11_INLINE scanner_base* either::clone() const { + return new either(*this); + } + + TOML11_INLINE std::string either::name() const { + std::string n("either{"); + for (const auto& other : others_) { + n += other.name(); + n += ", "; + } + if (!this->others_.empty()) { + n.pop_back(); + n.pop_back(); + } + n += "}"; + return n; + } + + // ---------------------------------------------------------------------------- + // repeat_exact + + TOML11_INLINE region repeat_exact::scan(location& loc) const { + const auto first = loc; + for (std::size_t i = 0; i < length_; ++i) { + const auto reg = other_.scan(loc); + if (!reg.is_ok()) { + loc = first; + return region {}; + } + } + return region(first, loc); + } + + TOML11_INLINE std::string repeat_exact::expected_chars(location& loc) const { + for (std::size_t i = 0; i < length_; ++i) { + const auto reg = other_.scan(loc); + if (!reg.is_ok()) { + return other_.expected_chars(loc); + } + } + assert(false); + return ""; + } + + TOML11_INLINE scanner_base* repeat_exact::clone() const { + return new repeat_exact(*this); + } + + TOML11_INLINE std::string repeat_exact::name() const { + return "repeat_exact{" + std::to_string(length_) + ", " + other_.name() + "}"; + } + + // ---------------------------------------------------------------------------- + // repeat_at_least + + TOML11_INLINE region repeat_at_least::scan(location& loc) const { + const auto first = loc; + for (std::size_t i = 0; i < length_; ++i) { + const auto reg = other_.scan(loc); + if (!reg.is_ok()) { + loc = first; + return region {}; + } + } + while (!loc.eof()) { + const auto checkpoint = loc; + const auto reg = other_.scan(loc); + if (!reg.is_ok()) { + loc = checkpoint; + return region(first, loc); + } + } + return region(first, loc); + } + + TOML11_INLINE std::string repeat_at_least::expected_chars(location& loc) const { + for (std::size_t i = 0; i < length_; ++i) { + const auto reg = other_.scan(loc); + if (!reg.is_ok()) { + return other_.expected_chars(loc); + } + } + assert(false); + return ""; + } + + TOML11_INLINE scanner_base* repeat_at_least::clone() const { + return new repeat_at_least(*this); + } + + TOML11_INLINE std::string repeat_at_least::name() const { + return "repeat_at_least{" + std::to_string(length_) + ", " + + other_.name() + "}"; + } + + // ---------------------------------------------------------------------------- + // maybe + + TOML11_INLINE region maybe::scan(location& loc) const { + const auto first = loc; + const auto reg = other_.scan(loc); + if (!reg.is_ok()) { + loc = first; + } + return region(first, loc); + } + + TOML11_INLINE std::string maybe::expected_chars(location&) const { + return ""; + } + + TOML11_INLINE scanner_base* maybe::clone() const { + return new maybe(*this); + } + + TOML11_INLINE std::string maybe::name() const { + return "maybe{" + other_.name() + "}"; + } + + } // namespace detail +} // namespace toml + #endif // TOML11_SCANNER_IMPL_HPP +#endif + +#endif // TOML11_SCANNER_HPP +#ifndef TOML11_SYNTAX_HPP +#define TOML11_SYNTAX_HPP + +#ifndef TOML11_SYNTAX_FWD_HPP + #define TOML11_SYNTAX_FWD_HPP + +namespace toml { + namespace detail { + namespace syntax { + + using char_type = location::char_type; + + // =========================================================================== + // UTF-8 + + // avoid redundant representation and out-of-unicode sequence + + character_in_range utf8_1byte(const spec&); + sequence utf8_2bytes(const spec&); + sequence utf8_3bytes(const spec&); + sequence utf8_4bytes(const spec&); + + class non_ascii final : public scanner_base { + public: + using char_type = location::char_type; + + public: + explicit non_ascii(const spec& s) noexcept; + ~non_ascii() override = default; + + region scan(location& loc) const override { + return scanner_.scan(loc); + } + + std::string expected_chars(location&) const override { + return "non-ascii utf-8 bytes"; + } + + scanner_base* clone() const override { + return new non_ascii(*this); + } + + std::string name() const override { + return "non_ascii"; + } + + private: + either scanner_; + }; + + // =========================================================================== + // Whitespace + + character_either wschar(const spec&); + + repeat_at_least ws(const spec& s); + + // =========================================================================== + // Newline + + either newline(const spec&); + + // =========================================================================== + // Comments + + either allowed_comment_char(const spec& s); + + // XXX Note that it does not take newline + sequence comment(const spec& s); + + // =========================================================================== + // Boolean + + either boolean(const spec&); + + // =========================================================================== + // Integer + + class digit final : public scanner_base { + public: + using char_type = location::char_type; + + public: + explicit digit(const spec&) noexcept; + ~digit() override = default; + + region scan(location& loc) const override { + return scanner_.scan(loc); + } + + std::string expected_chars(location&) const override { + return "digit [0-9]"; + } + + scanner_base* clone() const override { + return new digit(*this); + } + + std::string name() const override { + return "digit"; + } + + private: + character_in_range scanner_; + }; + + class alpha final : public scanner_base { + public: + using char_type = location::char_type; + + public: + explicit alpha(const spec&) noexcept; + ~alpha() override = default; + + region scan(location& loc) const override { + return scanner_.scan(loc); + } + + std::string expected_chars(location&) const override { + return "alpha [a-zA-Z]"; + } + + scanner_base* clone() const override { + return new alpha(*this); + } + + std::string name() const override { + return "alpha"; + } + + private: + either scanner_; + }; + + class hexdig final : public scanner_base { + public: + using char_type = location::char_type; + + public: + explicit hexdig(const spec& s) noexcept; + ~hexdig() override = default; + + region scan(location& loc) const override { + return scanner_.scan(loc); + } + + std::string expected_chars(location&) const override { + return "hex [0-9a-fA-F]"; + } + + scanner_base* clone() const override { + return new hexdig(*this); + } + + std::string name() const override { + return "hexdig"; + } + + private: + either scanner_; + }; + + sequence num_suffix(const spec& s); + + sequence dec_int(const spec& s); + sequence hex_int(const spec& s); + sequence oct_int(const spec&); + sequence bin_int(const spec&); + either integer(const spec& s); + + // =========================================================================== + // Floating + + sequence zero_prefixable_int(const spec& s); + sequence fractional_part(const spec& s); + sequence exponent_part(const spec& s); + sequence hex_floating(const spec& s); + either floating(const spec& s); + + // =========================================================================== + // Datetime + + sequence local_date(const spec& s); + sequence local_time(const spec& s); + either time_offset(const spec& s); + sequence full_time(const spec& s); + character_either time_delim(const spec&); + sequence local_datetime(const spec& s); + sequence offset_datetime(const spec& s); + + // =========================================================================== + // String + + sequence escaped(const spec& s); + + either basic_char(const spec& s); + + sequence basic_string(const spec& s); + + // --------------------------------------------------------------------------- + // multiline string + + sequence escaped_newline(const spec& s); + sequence ml_basic_string(const spec& s); + + // --------------------------------------------------------------------------- + // literal string + + either literal_char(const spec& s); + sequence literal_string(const spec& s); + + sequence ml_literal_string(const spec& s); + + either string(const spec& s); + + // =========================================================================== + // Keys + + // to keep `expected_chars` simple + class non_ascii_key_char final : public scanner_base { + public: + using char_type = location::char_type; + + private: + using in_range = character_in_range; // make definition short + + public: + explicit non_ascii_key_char(const spec& s) noexcept; + ~non_ascii_key_char() override = default; + + region scan(location& loc) const override; + + std::string expected_chars(location&) const override { + return "bare key non-ASCII script"; + } + + scanner_base* clone() const override { + return new non_ascii_key_char(*this); + } + + std::string name() const override { + return "non-ASCII bare key"; + } + + private: + std::uint32_t read_utf8(location& loc) const; + }; + + repeat_at_least unquoted_key(const spec& s); + + either quoted_key(const spec& s); + + either simple_key(const spec& s); + + sequence dot_sep(const spec& s); + + sequence dotted_key(const spec& s); + + class key final : public scanner_base { + public: + using char_type = location::char_type; + + public: + explicit key(const spec& s) noexcept; + ~key() override = default; + + region scan(location& loc) const override { + return scanner_.scan(loc); + } + + std::string expected_chars(location&) const override { + return "basic key([a-zA-Z0-9_-]) or quoted key(\" or ')"; + } + + scanner_base* clone() const override { + return new key(*this); + } + + std::string name() const override { + return "key"; + } + + private: + either scanner_; + }; + + sequence keyval_sep(const spec& s); + + // =========================================================================== + // Table key + + sequence std_table(const spec& s); + + sequence array_table(const spec& s); + + // =========================================================================== + // extension: null + + literal null_value(const spec&); + + } // namespace syntax + } // namespace detail +} // namespace toml +#endif // TOML11_SYNTAX_FWD_HPP + +#if !defined(TOML11_COMPILE_SOURCES) + #ifndef TOML11_SYNTAX_IMPL_HPP + #define TOML11_SYNTAX_IMPL_HPP + +namespace toml { + namespace detail { + namespace syntax { + + using char_type = location::char_type; + + // =========================================================================== + // UTF-8 + + // avoid redundant representation and out-of-unicode sequence + + TOML11_INLINE character_in_range utf8_1byte(const spec&) { + return character_in_range(0x00, 0x7F); + } + + TOML11_INLINE sequence utf8_2bytes(const spec&) { + return sequence(character_in_range(0xC2, 0xDF), + character_in_range(0x80, 0xBF)); + } + + TOML11_INLINE sequence utf8_3bytes(const spec&) { + return sequence( + /*1~2 bytes = */ either( + sequence(character(0xE0), character_in_range(0xA0, 0xBF)), + sequence(character_in_range(0xE1, 0xEC), character_in_range(0x80, 0xBF)), + sequence(character(0xED), character_in_range(0x80, 0x9F)), + sequence(character_in_range(0xEE, 0xEF), + character_in_range(0x80, 0xBF))), + /*3rd byte = */ character_in_range(0x80, 0xBF)); + } + + TOML11_INLINE sequence utf8_4bytes(const spec&) { + return sequence( + /*1~2 bytes = */ either( + sequence(character(0xF0), character_in_range(0x90, 0xBF)), + sequence(character_in_range(0xF1, 0xF3), character_in_range(0x80, 0xBF)), + sequence(character(0xF4), character_in_range(0x80, 0x8F))), + character_in_range(0x80, 0xBF), + character_in_range(0x80, 0xBF)); + } + + TOML11_INLINE non_ascii::non_ascii(const spec& s) noexcept + : scanner_(utf8_2bytes(s), utf8_3bytes(s), utf8_4bytes(s)) {} + + // =========================================================================== + // Whitespace + + TOML11_INLINE character_either wschar(const spec&) { + return character_either { char_type(' '), char_type('\t') }; + } + + TOML11_INLINE repeat_at_least ws(const spec& s) { + return repeat_at_least(0, wschar(s)); + } + + // =========================================================================== + // Newline + + TOML11_INLINE either newline(const spec&) { + return either(character(char_type('\n')), literal("\r\n")); + } + + // =========================================================================== + // Comments + + TOML11_INLINE either allowed_comment_char(const spec& s) { + if (s.v1_1_0_allow_control_characters_in_comments) { + return either(character_in_range(0x01, 0x09), + character_in_range(0x0E, 0x7F), + non_ascii(s)); + } else { + return either(character(0x09), + character_in_range(0x20, 0x7E), + non_ascii(s)); + } + } + + // XXX Note that it does not take newline + TOML11_INLINE sequence comment(const spec& s) { + return sequence(character(char_type('#')), + repeat_at_least(0, allowed_comment_char(s))); + } + + // =========================================================================== + // Boolean + + TOML11_INLINE either boolean(const spec&) { + return either(literal("true"), literal("false")); + } + + // =========================================================================== + // Integer + + TOML11_INLINE digit::digit(const spec&) noexcept + : scanner_(char_type('0'), char_type('9')) {} + + TOML11_INLINE alpha::alpha(const spec&) noexcept + : scanner_(character_in_range(char_type('a'), char_type('z')), + character_in_range(char_type('A'), char_type('Z'))) {} + + TOML11_INLINE hexdig::hexdig(const spec& s) noexcept + : scanner_(digit(s), + character_in_range(char_type('a'), char_type('f')), + character_in_range(char_type('A'), char_type('F'))) {} + + // non-digit-graph = ([a-zA-Z]|unicode mb char) + // graph = ([a-zA-Z0-9]|unicode mb char) + // suffix = _ non-digit-graph (graph | _graph) + TOML11_INLINE sequence num_suffix(const spec& s) { + const auto non_digit_graph = [&s]() { + return either(alpha(s), non_ascii(s)); + }; + const auto graph = [&s]() { + return either(alpha(s), digit(s), non_ascii(s)); + }; + + return sequence( + character(char_type('_')), + non_digit_graph(), + repeat_at_least( + 0, + either(sequence(character(char_type('_')), graph()), graph()))); + } + + TOML11_INLINE sequence dec_int(const spec& s) { + const auto digit19 = []() { + return character_in_range(char_type('1'), char_type('9')); + }; + return sequence( + maybe(character_either { char_type('-'), char_type('+') }), + either(sequence(digit19(), + repeat_at_least( + 1, + either(digit(s), + sequence(character(char_type('_')), digit(s))))), + digit(s))); + } + + TOML11_INLINE sequence hex_int(const spec& s) { + return sequence( + literal("0x"), + hexdig(s), + repeat_at_least( + 0, + either(hexdig(s), sequence(character(char_type('_')), hexdig(s))))); + } + + TOML11_INLINE sequence oct_int(const spec&) { + const auto digit07 = []() { + return character_in_range(char_type('0'), char_type('7')); + }; + return sequence( + literal("0o"), + digit07(), + repeat_at_least( + 0, + either(digit07(), sequence(character(char_type('_')), digit07())))); + } + + TOML11_INLINE sequence bin_int(const spec&) { + const auto digit01 = []() { + return character_either { char_type('0'), char_type('1') }; + }; + return sequence( + literal("0b"), + digit01(), + repeat_at_least( + 0, + either(digit01(), sequence(character(char_type('_')), digit01())))); + } + + TOML11_INLINE either integer(const spec& s) { + return either(hex_int(s), oct_int(s), bin_int(s), dec_int(s)); + } + + // =========================================================================== + // Floating + + TOML11_INLINE sequence zero_prefixable_int(const spec& s) { + return sequence( + digit(s), + repeat_at_least(0, either(digit(s), sequence(character('_'), digit(s))))); + } + + TOML11_INLINE sequence fractional_part(const spec& s) { + return sequence(character('.'), zero_prefixable_int(s)); + } + + TOML11_INLINE sequence exponent_part(const spec& s) { + return sequence(character_either { char_type('e'), char_type('E') }, + maybe(character_either { char_type('+'), char_type('-') }), + zero_prefixable_int(s)); + } + + TOML11_INLINE sequence hex_floating(const spec& s) { + // C99 hexfloat (%a) + // [+-]? 0x ( [0-9a-fA-F]*\.[0-9a-fA-F]+ | [0-9a-fA-F]+\.? ) [pP] [+-]? [0-9]+ + + // - 0x(int).(frac)p[+-](int) + // - 0x(int).p[+-](int) + // - 0x.(frac)p[+-](int) + // - 0x(int)p[+-](int) + + return sequence( + maybe(character_either { char_type('+'), char_type('-') }), + character('0'), + character_either { char_type('x'), char_type('X') }, + either(sequence(repeat_at_least(0, hexdig(s)), + character('.'), + repeat_at_least(1, hexdig(s))), + sequence(repeat_at_least(1, hexdig(s)), maybe(character('.')))), + character_either { char_type('p'), char_type('P') }, + maybe(character_either { char_type('+'), char_type('-') }), + repeat_at_least(1, character_in_range('0', '9'))); + } + + TOML11_INLINE either floating(const spec& s) { + return either( + sequence(dec_int(s), + either(exponent_part(s), + sequence(fractional_part(s), maybe(exponent_part(s))))), + sequence(maybe(character_either { char_type('-'), char_type('+') }), + either(literal("inf"), literal("nan")))); + } + + // =========================================================================== + // Datetime + + TOML11_INLINE sequence local_date(const spec& s) { + return sequence(repeat_exact(4, digit(s)), + character('-'), + repeat_exact(2, digit(s)), + character('-'), + repeat_exact(2, digit(s))); + } + + TOML11_INLINE sequence local_time(const spec& s) { + auto time = sequence(repeat_exact(2, digit(s)), + character(':'), + repeat_exact(2, digit(s))); + + if (s.v1_1_0_make_seconds_optional) { + time.push_back(maybe(sequence( + character(':'), + repeat_exact(2, digit(s)), + maybe(sequence(character('.'), repeat_at_least(1, digit(s))))))); + } else { + time.push_back(character(':')); + time.push_back(repeat_exact(2, digit(s))); + time.push_back( + maybe(sequence(character('.'), repeat_at_least(1, digit(s))))); + } + + return time; + } + + TOML11_INLINE either time_offset(const spec& s) { + return either(character_either { 'Z', 'z' }, + sequence(character_either { '+', '-' }, + repeat_exact(2, digit(s)), + character(':'), + repeat_exact(2, digit(s)))); + } + + TOML11_INLINE sequence full_time(const spec& s) { + return sequence(local_time(s), time_offset(s)); + } + + TOML11_INLINE character_either time_delim(const spec&) { + return character_either { 'T', 't', ' ' }; + } + + TOML11_INLINE sequence local_datetime(const spec& s) { + return sequence(local_date(s), time_delim(s), local_time(s)); + } + + TOML11_INLINE sequence offset_datetime(const spec& s) { + return sequence(local_date(s), time_delim(s), full_time(s)); + } + + // =========================================================================== + // String + + TOML11_INLINE sequence escaped(const spec& s) { + character_either escape_char { '\"', '\\', 'b', 'f', 'n', 'r', 't' }; + if (s.v1_1_0_add_escape_sequence_e) { + escape_char.push_back(char_type('e')); + } + + either escape_seq(std::move(escape_char), + sequence(character('u'), repeat_exact(4, hexdig(s))), + sequence(character('U'), repeat_exact(8, hexdig(s)))); + + if (s.v1_1_0_add_escape_sequence_x) { + escape_seq.push_back( + sequence(character('x'), repeat_exact(2, hexdig(s)))); + } + + return sequence(character('\\'), std::move(escape_seq)); + } + + TOML11_INLINE either basic_char(const spec& s) { + const auto basic_unescaped = [&s]() { + return either(wschar(s), + character(0x21), // 22 is " + character_in_range(0x23, 0x5B), // 5C is backslash + character_in_range(0x5D, 0x7E), // 7F is DEL + non_ascii(s)); + }; + return either(basic_unescaped(), escaped(s)); + } + + TOML11_INLINE sequence basic_string(const spec& s) { + return sequence(character('"'), + repeat_at_least(0, basic_char(s)), + character('"')); + } + + // --------------------------------------------------------------------------- + // multiline string + + TOML11_INLINE sequence escaped_newline(const spec& s) { + return sequence(character('\\'), + ws(s), + newline(s), + repeat_at_least(0, either(wschar(s), newline(s)))); + } + + TOML11_INLINE sequence ml_basic_string(const spec& s) { + const auto mlb_content = [&s]() { + return either(basic_char(s), newline(s), escaped_newline(s)); + }; + const auto mlb_quotes = []() { + return either(literal("\"\""), character('\"')); + }; + + return sequence( + literal("\"\"\""), + maybe(newline(s)), + repeat_at_least(0, mlb_content()), + repeat_at_least(0, + sequence(mlb_quotes(), repeat_at_least(1, mlb_content()))), + // XXX """ and mlb_quotes are intentionally reordered to avoid + // unexpected match of mlb_quotes + literal("\"\"\""), + maybe(mlb_quotes())); + } + + // --------------------------------------------------------------------------- + // literal string + + TOML11_INLINE either literal_char(const spec& s) { + return either(character(0x09), + character_in_range(0x20, 0x26), + character_in_range(0x28, 0x7E), + non_ascii(s)); + } + + TOML11_INLINE sequence literal_string(const spec& s) { + return sequence(character('\''), + repeat_at_least(0, literal_char(s)), + character('\'')); + } + + TOML11_INLINE sequence ml_literal_string(const spec& s) { + const auto mll_quotes = []() { + return either(literal("''"), character('\'')); + }; + const auto mll_content = [&s]() { + return either(literal_char(s), newline(s)); + }; + + return sequence( + literal("'''"), + maybe(newline(s)), + repeat_at_least(0, mll_content()), + repeat_at_least(0, + sequence(mll_quotes(), repeat_at_least(1, mll_content()))), + literal("'''"), + maybe(mll_quotes()) + // XXX ''' and mll_quotes are intentionally reordered to avoid + // unexpected match of mll_quotes + ); + } + + TOML11_INLINE either string(const spec& s) { + return either(ml_basic_string(s), + ml_literal_string(s), + basic_string(s), + literal_string(s)); + } + + // =========================================================================== + // Keys + + // to keep `expected_chars` simple + TOML11_INLINE non_ascii_key_char::non_ascii_key_char(const spec& s) noexcept { + assert(s.v1_1_0_allow_non_english_in_bare_keys); + (void)s; // for NDEBUG + } + + TOML11_INLINE std::uint32_t non_ascii_key_char::read_utf8(location& loc) const { + // U+0000 ... U+0079 ; 0xxx_xxxx + // U+0080 ... U+07FF ; 110y_yyyx 10xx_xxxx; + // U+0800 ... U+FFFF ; 1110_yyyy 10yx_xxxx 10xx_xxxx + // U+010000 ... U+10FFFF; 1111_0yyy 10yy_xxxx 10xx_xxxx 10xx_xxxx + + const unsigned char b1 = loc.current(); + loc.advance(1); + if (b1 < 0x80) { + return static_cast(b1); + } else if ((b1 >> 5) == 6) // 0b110 == 6 + { + const auto b2 = loc.current(); + loc.advance(1); + + const std::uint32_t c1 = b1 & ((1 << 5) - 1); + const std::uint32_t c2 = b2 & ((1 << 6) - 1); + const std::uint32_t codep = (c1 << 6) + c2; + + if (codep < 0x80) { + return 0xFFFFFFFF; + } + return codep; + } else if ((b1 >> 4) == 14) // 0b1110 == 14 + { + const auto b2 = loc.current(); + loc.advance(1); + if (loc.eof()) { + return 0xFFFFFFFF; + } + const auto b3 = loc.current(); + loc.advance(1); + + const std::uint32_t c1 = b1 & ((1 << 4) - 1); + const std::uint32_t c2 = b2 & ((1 << 6) - 1); + const std::uint32_t c3 = b3 & ((1 << 6) - 1); + + const std::uint32_t codep = (c1 << 12) + (c2 << 6) + c3; + if (codep < 0x800) { + return 0xFFFFFFFF; + } + return codep; + } else if ((b1 >> 3) == 30) // 0b11110 == 30 + { + const auto b2 = loc.current(); + loc.advance(1); + if (loc.eof()) { + return 0xFFFFFFFF; + } + const auto b3 = loc.current(); + loc.advance(1); + if (loc.eof()) { + return 0xFFFFFFFF; + } + const auto b4 = loc.current(); + loc.advance(1); + + const std::uint32_t c1 = b1 & ((1 << 3) - 1); + const std::uint32_t c2 = b2 & ((1 << 6) - 1); + const std::uint32_t c3 = b3 & ((1 << 6) - 1); + const std::uint32_t c4 = b4 & ((1 << 6) - 1); + const std::uint32_t codep = (c1 << 18) + (c2 << 12) + (c3 << 6) + c4; + + if (codep < 0x10000) { + return 0xFFFFFFFF; + } + return codep; + } else // not a Unicode codepoint in UTF-8 + { + return 0xFFFFFFFF; + } + } + + TOML11_INLINE region non_ascii_key_char::scan(location& loc) const { + if (loc.eof()) { + return region {}; + } + + const auto first = loc; + + const auto cp = read_utf8(loc); + + if (cp == 0xFFFFFFFF) { + return region {}; + } + + // ALPHA / DIGIT / %x2D / %x5F ; a-z A-Z 0-9 - _ + // / %xB2 / %xB3 / %xB9 / %xBC-BE ; superscript digits, fractions + // / %xC0-D6 / %xD8-F6 / %xF8-37D ; non-symbol chars in Latin block + // / %x37F-1FFF ; exclude GREEK QUESTION MARK, which + // is basically a semi-colon / %x200C-200D / %x203F-2040 ; from + // General Punctuation Block, include the two tie symbols and ZWNJ, ZWJ + // / %x2070-218F / %x2460-24FF ; include super-/subscripts, + // letterlike/numberlike forms, enclosed alphanumerics / %x2C00-2FEF / + // %x3001-D7FF ; skip arrows, math, box drawing etc, skip 2FF0-3000 + // ideographic up/down markers and spaces / %xF900-FDCF / %xFDF0-FFFD ; + // skip D800-DFFF surrogate block, E000-F8FF Private Use area, FDD0-FDEF + // intended for process-internal use (unicode) / %x10000-EFFFF ; all + // chars outside BMP range, excluding Private Use planes (F0000-10FFFF) + + if (cp == 0xB2 || cp == 0xB3 || cp == 0xB9 || + (0xBC <= cp && cp <= 0xBE) || (0xC0 <= cp && cp <= 0xD6) || + (0xD8 <= cp && cp <= 0xF6) || (0xF8 <= cp && cp <= 0x37D) || + (0x37F <= cp && cp <= 0x1FFF) || (0x200C <= cp && cp <= 0x200D) || + (0x203F <= cp && cp <= 0x2040) || (0x2070 <= cp && cp <= 0x218F) || + (0x2460 <= cp && cp <= 0x24FF) || (0x2C00 <= cp && cp <= 0x2FEF) || + (0x3001 <= cp && cp <= 0xD7FF) || (0xF900 <= cp && cp <= 0xFDCF) || + (0xFDF0 <= cp && cp <= 0xFFFD) || (0x10000 <= cp && cp <= 0xEFFFF)) { + return region(first, loc); + } + loc = first; + return region {}; + } + + TOML11_INLINE repeat_at_least unquoted_key(const spec& s) { + auto keychar = either(alpha(s), + digit(s), + character { 0x2D }, + character { 0x5F }); + + if (s.v1_1_0_allow_non_english_in_bare_keys) { + keychar.push_back(non_ascii_key_char(s)); + } + + return repeat_at_least(1, std::move(keychar)); + } + + TOML11_INLINE either quoted_key(const spec& s) { + return either(basic_string(s), literal_string(s)); + } + + TOML11_INLINE either simple_key(const spec& s) { + return either(unquoted_key(s), quoted_key(s)); + } + + TOML11_INLINE sequence dot_sep(const spec& s) { + return sequence(ws(s), character('.'), ws(s)); + } + + TOML11_INLINE sequence dotted_key(const spec& s) { + return sequence(simple_key(s), + repeat_at_least(1, sequence(dot_sep(s), simple_key(s)))); + } + + TOML11_INLINE key::key(const spec& s) noexcept + : scanner_(dotted_key(s), simple_key(s)) {} + + TOML11_INLINE sequence keyval_sep(const spec& s) { + return sequence(ws(s), character('='), ws(s)); + } + + // =========================================================================== + // Table key + + TOML11_INLINE sequence std_table(const spec& s) { + return sequence(character('['), ws(s), key(s), ws(s), character(']')); + } + + TOML11_INLINE sequence array_table(const spec& s) { + return sequence(literal("[["), ws(s), key(s), ws(s), literal("]]")); + } + + // =========================================================================== + // extension: null + + TOML11_INLINE literal null_value(const spec&) { + return literal("null"); + } + + } // namespace syntax + } // namespace detail +} // namespace toml + #endif // TOML11_SYNTAX_IMPL_HPP +#endif + +#endif // TOML11_SYNTAX_HPP +#ifndef TOML11_SKIP_HPP +#define TOML11_SKIP_HPP + +#include + +namespace toml { + namespace detail { + + template + bool skip_whitespace(location& loc, const context& ctx) { + return syntax::ws(ctx.toml_spec()).scan(loc).is_ok(); + } + + template + bool skip_empty_lines(location& loc, const context& ctx) { + return repeat_at_least(1, + sequence(syntax::ws(ctx.toml_spec()), + syntax::newline(ctx.toml_spec()))) + .scan(loc) + .is_ok(); + } + + // For error recovery. + // + // In case if a comment line contains an invalid character, we need to skip + // it to advance parsing. + template + void skip_comment_block(location& loc, const context& ctx) { + while (!loc.eof()) { + skip_whitespace(loc, ctx); + if (loc.current() == '#') { + while (!loc.eof()) { + // both CRLF and LF ends with LF. + if (loc.current() == '\n') { + loc.advance(); + break; + } + } + } else if (syntax::newline(ctx.toml_spec()).scan(loc).is_ok()) { + ; // an empty line. skip this also + } else { + // the next token is neither a comment nor empty line. + return; + } + } + return; + } + + template + void skip_empty_or_comment_lines(location& loc, const context& ctx) { + const auto& spec = ctx.toml_spec(); + repeat_at_least(0, + sequence(syntax::ws(spec), + maybe(syntax::comment(spec)), + syntax::newline(spec))) + .scan(loc); + return; + } + + // For error recovery. + // + // Sometimes we need to skip a value and find a delimiter, like `,`, `]`, or `}`. + // To find delimiter, we need to skip delimiters in a string. + // Since we are skipping invalid value while error recovery, we don't need + // to check the syntax. Here we just skip string-like region until closing quote + // is found. + template + void skip_string_like(location& loc, const context&) { + // if """ is found, skip until the closing """ is found. + if (literal("\"\"\"").scan(loc).is_ok()) { + while (!loc.eof()) { + if (literal("\"\"\"").scan(loc).is_ok()) { + return; + } + loc.advance(); + } + } else if (literal("'''").scan(loc).is_ok()) { + while (!loc.eof()) { + if (literal("'''").scan(loc).is_ok()) { + return; + } + loc.advance(); + } + } + // if " is found, skip until the closing " or newline is found. + else if (loc.current() == '"') { + while (!loc.eof()) { + loc.advance(); + if (loc.current() == '"' || loc.current() == '\n') { + loc.advance(); + return; + } + } + } else if (loc.current() == '\'') { + while (!loc.eof()) { + loc.advance(); + if (loc.current() == '\'' || loc.current() == '\n') { + loc.advance(); + return; + } + } + } + return; + } + + template + void skip_value(location& loc, const context& ctx); + template + void skip_array_like(location& loc, const context& ctx); + template + void skip_inline_table_like(location& loc, const context& ctx); + template + void skip_key_value_pair(location& loc, const context& ctx); + + template + result guess_value_type(const location& loc, + const context& ctx); + + template + void skip_array_like(location& loc, const context& ctx) { + const auto& spec = ctx.toml_spec(); + assert(loc.current() == '['); + loc.advance(); + + while (!loc.eof()) { + if (loc.current() == '\"' || loc.current() == '\'') { + skip_string_like(loc, ctx); + } else if (loc.current() == '#') { + skip_comment_block(loc, ctx); + } else if (loc.current() == '{') { + skip_inline_table_like(loc, ctx); + } else if (loc.current() == '[') { + const auto checkpoint = loc; + if (syntax::std_table(spec).scan(loc).is_ok() || + syntax::array_table(spec).scan(loc).is_ok()) { + loc = checkpoint; + break; + } + // if it is not a table-definition, then it is an array. + skip_array_like(loc, ctx); + } else if (loc.current() == '=') { + // key-value pair cannot be inside the array. + // guessing the error is "missing closing bracket `]`". + // find the previous key just before `=`. + while (loc.get_location() != 0) { + loc.retrace(); + if (loc.current() == '\n') { + loc.advance(); + break; + } + } + break; + } else if (loc.current() == ']') { + break; // found closing bracket + } else { + loc.advance(); + } + } + return; + } + + template + void skip_inline_table_like(location& loc, const context& ctx) { + assert(loc.current() == '{'); + loc.advance(); + + const auto& spec = ctx.toml_spec(); + + while (!loc.eof()) { + if (loc.current() == '\n' && !spec.v1_1_0_allow_newlines_in_inline_tables) { + break; // missing closing `}`. + } else if (loc.current() == '\"' || loc.current() == '\'') { + skip_string_like(loc, ctx); + } else if (loc.current() == '#') { + skip_comment_block(loc, ctx); + if (!spec.v1_1_0_allow_newlines_in_inline_tables) { + // comment must end with newline. + break; // missing closing `}`. + } + } else if (loc.current() == '[') { + const auto checkpoint = loc; + if (syntax::std_table(spec).scan(loc).is_ok() || + syntax::array_table(spec).scan(loc).is_ok()) { + loc = checkpoint; + break; // missing closing `}`. + } + // if it is not a table-definition, then it is an array. + skip_array_like(loc, ctx); + } else if (loc.current() == '{') { + skip_inline_table_like(loc, ctx); + } else if (loc.current() == '}') { + // closing brace found. guessing the error is inside the table. + break; + } else { + // skip otherwise. + loc.advance(); + } + } + return; + } + + template + void skip_value(location& loc, const context& ctx) { + value_t ty = guess_value_type(loc, ctx).unwrap_or(value_t::empty); + if (ty == value_t::string) { + skip_string_like(loc, ctx); + } else if (ty == value_t::array) { + skip_array_like(loc, ctx); + } else if (ty == value_t::table) { + // In case of multiline tables, it may skip key-value pair but not the + // whole table. + skip_inline_table_like(loc, ctx); + } else // others are an "in-line" values. skip until the next line + { + while (!loc.eof()) { + if (loc.current() == '\n') { + break; + } else if (loc.current() == ',' || loc.current() == ']' || + loc.current() == '}') { + break; + } + loc.advance(); + } + } + return; + } + + template + void skip_key_value_pair(location& loc, const context& ctx) { + while (!loc.eof()) { + if (loc.current() == '=') { + skip_whitespace(loc, ctx); + skip_value(loc, ctx); + return; + } else if (loc.current() == '\n') { + // newline is found before finding `=`. assuming "missing `=`". + return; + } + loc.advance(); + } + return; + } + + template + void skip_until_next_table(location& loc, const context& ctx) { + const auto& spec = ctx.toml_spec(); + while (!loc.eof()) { + if (loc.current() == '\n') { + loc.advance(); + const auto line_begin = loc; + + skip_whitespace(loc, ctx); + if (syntax::std_table(spec).scan(loc).is_ok()) { + loc = line_begin; + return; + } + if (syntax::array_table(spec).scan(loc).is_ok()) { + loc = line_begin; + return; + } + } + loc.advance(); + } + } + + } // namespace detail +} // namespace toml + +#if defined(TOML11_COMPILE_SOURCES) +namespace toml { + struct type_config; + struct ordered_type_config; + + namespace detail { + extern template bool skip_whitespace(location& loc, + const context&); + extern template bool skip_empty_lines(location& loc, + const context&); + extern template void skip_comment_block( + location& loc, + const context&); + extern template void skip_empty_or_comment_lines( + location& loc, + const context&); + extern template void skip_string_like(location& loc, + const context&); + extern template void skip_array_like(location& loc, + const context&); + extern template void skip_inline_table_like( + location& loc, + const context&); + extern template void skip_value(location& loc, + const context&); + extern template void skip_key_value_pair( + location& loc, + const context&); + extern template void skip_until_next_table( + location& loc, + const context&); + + extern template bool skip_whitespace( + location& loc, + const context&); + extern template bool skip_empty_lines( + location& loc, + const context&); + extern template void skip_comment_block( + location& loc, + const context&); + extern template void skip_empty_or_comment_lines( + location& loc, + const context&); + extern template void skip_string_like( + location& loc, + const context&); + extern template void skip_array_like( + location& loc, + const context&); + extern template void skip_inline_table_like( + location& loc, + const context&); + extern template void skip_value( + location& loc, + const context&); + extern template void skip_key_value_pair( + location& loc, + const context&); + extern template void skip_until_next_table( + location& loc, + const context&); + + } // namespace detail +} // namespace toml +#endif // TOML11_COMPILE_SOURCES + +#endif // TOML11_SKIP_HPP +#ifndef TOML11_PARSER_HPP +#define TOML11_PARSER_HPP + +#include +#include +#include +#include + +#if defined(TOML11_HAS_FILESYSTEM) && TOML11_HAS_FILESYSTEM + #include +#endif + +namespace toml { + + struct syntax_error final : public ::toml::exception { + public: + syntax_error(std::string what_arg, std::vector err) + : what_(std::move(what_arg)) + , err_(std::move(err)) {} + + ~syntax_error() noexcept override = default; + + const char* what() const noexcept override { + return what_.c_str(); + } + + const std::vector& errors() const noexcept { + return err_; + } + + private: + std::string what_; + std::vector err_; + }; + + struct file_io_error final : public ::toml::exception { + public: + file_io_error(const std::string& msg, const std::string& fname) + : errno_(cxx::make_nullopt()) + , what_(msg + " \"" + fname + "\"") {} + + file_io_error(int errnum, const std::string& msg, const std::string& fname) + : errno_(errnum) + , what_(msg + " \"" + fname + "\": errno=" + std::to_string(errnum)) {} + + ~file_io_error() noexcept override = default; + + const char* what() const noexcept override { + return what_.c_str(); + } + + bool has_errno() const noexcept { + return errno_.has_value(); + } + + int get_errno() const noexcept { + return errno_.value_or(0); + } + + private: + cxx::optional errno_; + std::string what_; + }; + + namespace detail { + + /* ============================================================================ + * __ ___ _ __ _ __ ___ _ _ + * / _/ _ \ ' \| ' \/ _ \ ' \ + * \__\___/_|_|_|_|_|_\___/_||_| + */ + + template + error_info make_syntax_error(std::string title, + const S& scanner, + location loc, + std::string suffix = "") { + auto msg = std::string("expected ") + scanner.expected_chars(loc); + auto src = source_location(region(loc)); + return make_error_info(std::move(title), + std::move(src), + std::move(msg), + std::move(suffix)); + } + + /* ============================================================================ + * _ + * __ ___ _ __ _ __ ___ _ _| |_ + * / _/ _ \ ' \| ' \/ -_) ' \ _| + * \__\___/_|_|_|_|_|_\___|_||_\__| + */ + + template + result, error_info> parse_comment_line( + location& loc, + context& ctx) { + const auto& spec = ctx.toml_spec(); + const auto first = loc; + + skip_whitespace(loc, ctx); + + const auto com_reg = syntax::comment(spec).scan(loc); + if (com_reg.is_ok()) { + // once comment started, newline must follow (or reach EOF). + if (!loc.eof() && !syntax::newline(spec).scan(loc).is_ok()) { + while (!loc.eof()) // skip until newline to continue parsing + { + loc.advance(); + if (loc.current() == '\n') { /*skip LF*/ + loc.advance(); + break; + } + } + return err(make_error_info("toml::parse_comment_line: " + "newline (LF / CRLF) or EOF is expected", + source_location(region(loc)), + "but got this", + "Hint: most of the control characters are " + "not allowed in comments")); + } + return ok(cxx::optional(com_reg.as_string())); + } else { + loc = first; // rollback whitespace to parse indent + return ok(cxx::optional(cxx::make_nullopt())); + } + } + + /* ============================================================================ + * ___ _ + * | _ ) ___ ___| |___ __ _ _ _ + * | _ \/ _ \/ _ \ / -_) _` | ' \ + * |___/\___/\___/_\___\__,_|_||_| + */ + + template + result, error_info> parse_boolean(location& loc, + const context& ctx) { + const auto& spec = ctx.toml_spec(); + + // ---------------------------------------------------------------------- + // check syntax + auto reg = syntax::boolean(spec).scan(loc); + if (!reg.is_ok()) { + return err(make_syntax_error( + "toml::parse_boolean: " + "invalid boolean: boolean must be `true` or `false`, in lowercase. " + "string must be surrounded by `\"`", + syntax::boolean(spec), + loc)); + } + + // ---------------------------------------------------------------------- + // it matches. gen value + const auto str = reg.as_string(); + const auto val = [&str]() { + if (str == "true") { + return true; + } else { + assert(str == "false"); + return false; + } + }(); + + // ---------------------------------------------------------------------- + // no format info for boolean + boolean_format_info fmt; + + return ok(basic_value(val, std::move(fmt), {}, std::move(reg))); + } + + /* ============================================================================ + * ___ _ + * |_ _|_ _| |_ ___ __ _ ___ _ _ + * | || ' \ _/ -_) _` / -_) '_| + * |___|_||_\__\___\__, \___|_| + * |___/ + */ + + template + result, error_info> parse_bin_integer(location& loc, + const context& ctx) { + const auto first = loc; + const auto& spec = ctx.toml_spec(); + auto reg = syntax::bin_int(spec).scan(loc); + if (!reg.is_ok()) { + return err(make_syntax_error( + "toml::parse_bin_integer: " + "invalid integer: bin_int must be like: 0b0101, 0b1111_0000", + syntax::bin_int(spec), + loc)); + } + + auto str = reg.as_string(); + + integer_format_info fmt; + fmt.fmt = integer_format::bin; + fmt.width = str.size() - 2 - + static_cast(std::count(str.begin(), str.end(), '_')); + + const auto first_underscore = std::find(str.rbegin(), str.rend(), '_'); + if (first_underscore != str.rend()) { + fmt.spacer = static_cast( + std::distance(str.rbegin(), first_underscore)); + } + + // skip prefix `0b` and zeros and underscores at the MSB + str.erase(str.begin(), std::find(std::next(str.begin(), 2), str.end(), '1')); + + // remove all `_` before calling TC::parse_int + str.erase(std::remove(str.begin(), str.end(), '_'), str.end()); + + // 0b0000_0000 becomes empty. + if (str.empty()) { + str = "0"; + } + + const auto val = TC::parse_int(str, source_location(region(loc)), 2); + if (val.is_ok()) { + return ok(basic_value(val.as_ok(), std::move(fmt), {}, std::move(reg))); + } else { + loc = first; + return err(val.as_err()); + } + } + + // ---------------------------------------------------------------------------- + + template + result, error_info> parse_oct_integer(location& loc, + const context& ctx) { + const auto first = loc; + const auto& spec = ctx.toml_spec(); + auto reg = syntax::oct_int(spec).scan(loc); + if (!reg.is_ok()) { + return err(make_syntax_error( + "toml::parse_oct_integer: " + "invalid integer: oct_int must be like: 0o775, 0o04_44", + syntax::oct_int(spec), + loc)); + } + + auto str = reg.as_string(); + + integer_format_info fmt; + fmt.fmt = integer_format::oct; + fmt.width = str.size() - 2 - + static_cast(std::count(str.begin(), str.end(), '_')); + + const auto first_underscore = std::find(str.rbegin(), str.rend(), '_'); + if (first_underscore != str.rend()) { + fmt.spacer = static_cast( + std::distance(str.rbegin(), first_underscore)); + } + + // skip prefix `0o` and zeros and underscores at the MSB + str.erase(str.begin(), + std::find_if(std::next(str.begin(), 2), str.end(), [](const char c) { + return c != '0' && c != '_'; + })); + + // remove all `_` before calling TC::parse_int + str.erase(std::remove(str.begin(), str.end(), '_'), str.end()); + + // 0o0000_0000 becomes empty. + if (str.empty()) { + str = "0"; + } + + const auto val = TC::parse_int(str, source_location(region(loc)), 8); + if (val.is_ok()) { + return ok(basic_value(val.as_ok(), std::move(fmt), {}, std::move(reg))); + } else { + loc = first; + return err(val.as_err()); + } + } + + template + result, error_info> parse_hex_integer(location& loc, + const context& ctx) { + const auto first = loc; + const auto& spec = ctx.toml_spec(); + auto reg = syntax::hex_int(spec).scan(loc); + if (!reg.is_ok()) { + return err(make_syntax_error( + "toml::parse_hex_integer: " + "invalid integer: hex_int must be like: 0xC0FFEE, 0xdead_beef", + syntax::hex_int(spec), + loc)); + } + + auto str = reg.as_string(); + + integer_format_info fmt; + fmt.fmt = integer_format::hex; + fmt.width = str.size() - 2 - + static_cast(std::count(str.begin(), str.end(), '_')); + + const auto first_underscore = std::find(str.rbegin(), str.rend(), '_'); + if (first_underscore != str.rend()) { + fmt.spacer = static_cast( + std::distance(str.rbegin(), first_underscore)); + } + + // skip prefix `0x` and zeros and underscores at the MSB + str.erase(str.begin(), + std::find_if(std::next(str.begin(), 2), str.end(), [](const char c) { + return c != '0' && c != '_'; + })); + + // remove all `_` before calling TC::parse_int + str.erase(std::remove(str.begin(), str.end(), '_'), str.end()); + + // 0x0000_0000 becomes empty. + if (str.empty()) { + str = "0"; + } + + // prefix zero and _ is removed. check if it uses upper/lower case. + // if both upper and lower case letters are found, set upper=true. + const auto lower_not_found = std::find_if(str.begin(), str.end(), [](const char c) { + return std::islower(static_cast(c)) != 0; + }) == str.end(); + const auto upper_found = std::find_if(str.begin(), str.end(), [](const char c) { + return std::isupper(static_cast(c)) != 0; + }) != str.end(); + fmt.uppercase = lower_not_found || upper_found; + + const auto val = TC::parse_int(str, source_location(region(loc)), 16); + if (val.is_ok()) { + return ok(basic_value(val.as_ok(), std::move(fmt), {}, std::move(reg))); + } else { + loc = first; + return err(val.as_err()); + } + } + + template + result, error_info> parse_dec_integer(location& loc, + const context& ctx) { + const auto first = loc; + const auto& spec = ctx.toml_spec(); + + // ---------------------------------------------------------------------- + // check syntax + auto reg = syntax::dec_int(spec).scan(loc); + if (!reg.is_ok()) { + return err(make_syntax_error( + "toml::parse_dec_integer: " + "invalid integer: dec_int must be like: 42, 123_456_789", + syntax::dec_int(spec), + loc)); + } + + // ---------------------------------------------------------------------- + // it matches. gen value + auto str = reg.as_string(); + + integer_format_info fmt; + fmt.fmt = integer_format::dec; + fmt.width = str.size() - static_cast( + std::count(str.begin(), str.end(), '_')); + + const auto first_underscore = std::find(str.rbegin(), str.rend(), '_'); + if (first_underscore != str.rend()) { + fmt.spacer = static_cast( + std::distance(str.rbegin(), first_underscore)); + } + + // remove all `_` before calling TC::parse_int + str.erase(std::remove(str.begin(), str.end(), '_'), str.end()); + + auto src = source_location(region(loc)); + const auto val = TC::parse_int(str, src, 10); + if (val.is_err()) { + loc = first; + return err(val.as_err()); + } + + // ---------------------------------------------------------------------- + // parse suffix (extension) + + if (spec.ext_num_suffix && loc.current() == '_') { + const auto sfx_reg = syntax::num_suffix(spec).scan(loc); + if (!sfx_reg.is_ok()) { + loc = first; + return err(make_error_info( + "toml::parse_dec_integer: " + "invalid suffix: should be `_ non-digit-graph (graph | _graph)`", + source_location(region(loc)), + "here")); + } + auto sfx = sfx_reg.as_string(); + assert(!sfx.empty() && sfx.front() == '_'); + sfx.erase(sfx.begin()); // remove the first `_` + + fmt.suffix = sfx; + } + + return ok(basic_value(val.as_ok(), std::move(fmt), {}, std::move(reg))); + } + + template + result, error_info> parse_integer(location& loc, + const context& ctx) { + const auto first = loc; + + if (!loc.eof() && (loc.current() == '+' || loc.current() == '-')) { + // skip +/- to diagnose +0xDEADBEEF or -0b0011 (invalid). + // without this, +0xDEAD_BEEF will be parsed as a decimal int and + // unexpected "xDEAD_BEEF" will appear after integer "+0". + loc.advance(); + } + + if (!loc.eof() && loc.current() == '0') { + loc.advance(); + if (loc.eof()) { + // `[+-]?0`. parse as an decimal integer. + loc = first; + return parse_dec_integer(loc, ctx); + } + + const auto prefix = loc.current(); + auto prefix_src = source_location(region(loc)); + + loc = first; + + if (prefix == 'b') { + return parse_bin_integer(loc, ctx); + } + if (prefix == 'o') { + return parse_oct_integer(loc, ctx); + } + if (prefix == 'x') { + return parse_hex_integer(loc, ctx); + } + + if (std::isdigit(prefix)) { + auto src = source_location(region(loc)); + return err( + make_error_info("toml::parse_integer: " + "leading zero in an decimal integer is not allowed", + std::move(src), + "leading zero")); + } + } + + loc = first; + return parse_dec_integer(loc, ctx); + } + + /* ============================================================================ + * ___ _ _ _ + * | __| |___ __ _| |_(_)_ _ __ _ + * | _|| / _ \/ _` | _| | ' \/ _` | + * |_| |_\___/\__,_|\__|_|_||_\__, | + * |___/ + */ + + template + result, error_info> parse_floating(location& loc, + const context& ctx) { + using floating_type = typename basic_value::floating_type; + + const auto first = loc; + const auto& spec = ctx.toml_spec(); + + // ---------------------------------------------------------------------- + // check syntax + bool is_hex = false; + std::string str; + region reg; + if (spec.ext_hex_float && + sequence(character('0'), character('x')).scan(loc).is_ok()) { + loc = first; + is_hex = true; + + reg = syntax::hex_floating(spec).scan(loc); + if (!reg.is_ok()) { + return err(make_syntax_error( + "toml::parse_floating: " + "invalid hex floating: float must be like: 0xABCp-3f", + syntax::floating(spec), + loc)); + } + str = reg.as_string(); + } else { + reg = syntax::floating(spec).scan(loc); + if (!reg.is_ok()) { + return err(make_syntax_error( + "toml::parse_floating: " + "invalid floating: float must be like: -3.14159_26535, 6.022e+23, " + "inf, or nan (lowercase).", + syntax::floating(spec), + loc)); + } + str = reg.as_string(); + } + + // ---------------------------------------------------------------------- + // it matches. gen value + + floating_format_info fmt; + + if (is_hex) { + fmt.fmt = floating_format::hex; + } else { + // since we already checked that the string conforms the TOML standard. + if (std::find(str.begin(), str.end(), 'e') != str.end() || + std::find(str.begin(), str.end(), 'E') != str.end()) { + fmt.fmt = floating_format::scientific; // use exponent part + } else { + fmt.fmt = floating_format::fixed; // do not use exponent part + } + } + + str.erase(std::remove(str.begin(), str.end(), '_'), str.end()); + + floating_type val { 0 }; + + if (str == "inf" || str == "+inf") { + TOML11_CONSTEXPR_IF(std::numeric_limits::has_infinity) { + val = std::numeric_limits::infinity(); + } + else { + return err(make_error_info( + "toml::parse_floating: inf value found" + " but the current environment does not support inf. Please" + " make sure that the floating-point implementation conforms" + " IEEE 754/ISO 60559 international standard.", + source_location(region(loc)), + "floating_type: inf is not supported")); + } + } else if (str == "-inf") { + TOML11_CONSTEXPR_IF(std::numeric_limits::has_infinity) { + val = -std::numeric_limits::infinity(); + } + else { + return err(make_error_info( + "toml::parse_floating: inf value found" + " but the current environment does not support inf. Please" + " make sure that the floating-point implementation conforms" + " IEEE 754/ISO 60559 international standard.", + source_location(region(loc)), + "floating_type: inf is not supported")); + } + } else if (str == "nan" || str == "+nan") { + TOML11_CONSTEXPR_IF(std::numeric_limits::has_quiet_NaN) { + val = std::numeric_limits::quiet_NaN(); + } + else TOML11_CONSTEXPR_IF( + std::numeric_limits::has_signaling_NaN) { + val = std::numeric_limits::signaling_NaN(); + } + else { + return err(make_error_info( + "toml::parse_floating: NaN value found" + " but the current environment does not support NaN. Please" + " make sure that the floating-point implementation conforms" + " IEEE 754/ISO 60559 international standard.", + source_location(region(loc)), + "floating_type: NaN is not supported")); + } + } else if (str == "-nan") { + using std::copysign; + TOML11_CONSTEXPR_IF(std::numeric_limits::has_quiet_NaN) { + val = copysign(std::numeric_limits::quiet_NaN(), + floating_type(-1)); + } + else TOML11_CONSTEXPR_IF( + std::numeric_limits::has_signaling_NaN) { + val = copysign(std::numeric_limits::signaling_NaN(), + floating_type(-1)); + } + else { + return err(make_error_info( + "toml::parse_floating: NaN value found" + " but the current environment does not support NaN. Please" + " make sure that the floating-point implementation conforms" + " IEEE 754/ISO 60559 international standard.", + source_location(region(loc)), + "floating_type: NaN is not supported")); + } + } else { + // set precision + const auto has_sign = !str.empty() && + (str.front() == '+' || str.front() == '-'); + const auto decpoint = std::find(str.begin(), str.end(), '.'); + const auto exponent = std::find_if(str.begin(), str.end(), [](const char c) { + return c == 'e' || c == 'E'; + }); + if (decpoint != str.end() && exponent != str.end()) { + assert(decpoint < exponent); + } + + if (fmt.fmt == floating_format::scientific) { + // total width + fmt.prec = static_cast(std::distance(str.begin(), exponent)); + if (has_sign) { + fmt.prec -= 1; + } + if (decpoint != str.end()) { + fmt.prec -= 1; + } + } else if (fmt.fmt == floating_format::hex) { + fmt.prec = std::numeric_limits::max_digits10; + } else { + // width after decimal point + fmt.prec = static_cast( + std::distance(std::next(decpoint), exponent)); + } + + auto src = source_location(region(loc)); + const auto res = TC::parse_float(str, src, is_hex); + if (res.is_ok()) { + val = res.as_ok(); + } else { + return err(res.as_err()); + } + } + + // ---------------------------------------------------------------------- + // parse suffix (extension) + + if (spec.ext_num_suffix && loc.current() == '_') { + const auto sfx_reg = syntax::num_suffix(spec).scan(loc); + if (!sfx_reg.is_ok()) { + auto src = source_location(region(loc)); + loc = first; + return err(make_error_info( + "toml::parse_floating: " + "invalid suffix: should be `_ non-digit-graph (graph | _graph)`", + std::move(src), + "here")); + } + auto sfx = sfx_reg.as_string(); + assert(!sfx.empty() && sfx.front() == '_'); + sfx.erase(sfx.begin()); // remove the first `_` + + fmt.suffix = sfx; + } + + return ok(basic_value(val, std::move(fmt), {}, std::move(reg))); + } + + /* ============================================================================ + * ___ _ _ _ + * | \ __ _| |_ ___| |_(_)_ __ ___ + * | |) / _` | _/ -_) _| | ' \/ -_) + * |___/\__,_|\__\___|\__|_|_|_|_\___| + */ + + // all the offset_datetime, local_datetime, local_date parses date part. + template + result, error_info> + parse_local_date_only(location& loc, const context& ctx) { + const auto first = loc; + const auto& spec = ctx.toml_spec(); + + local_date_format_info fmt; + + // ---------------------------------------------------------------------- + // check syntax + auto reg = syntax::local_date(spec).scan(loc); + if (!reg.is_ok()) { + return err(make_syntax_error( + "toml::parse_local_date: " + "invalid date: date must be like: 1234-05-06, yyyy-mm-dd.", + syntax::local_date(spec), + loc)); + } + + // ---------------------------------------------------------------------- + // it matches. gen value + const auto str = reg.as_string(); + + // 0123456789 + // yyyy-mm-dd + const auto year_r = from_string(str.substr(0, 4)); + const auto month_r = from_string(str.substr(5, 2)); + const auto day_r = from_string(str.substr(8, 2)); + + if (year_r.is_err()) { + auto src = source_location(region(first)); + return err(make_error_info("toml::parse_local_date: " + "failed to read year `" + + str.substr(0, 4) + "`", + std::move(src), + "here")); + } + if (month_r.is_err()) { + auto src = source_location(region(first)); + return err(make_error_info("toml::parse_local_date: " + "failed to read month `" + + str.substr(5, 2) + "`", + std::move(src), + "here")); + } + if (day_r.is_err()) { + auto src = source_location(region(first)); + return err(make_error_info("toml::parse_local_date: " + "failed to read day `" + + str.substr(8, 2) + "`", + std::move(src), + "here")); + } + + const auto year = year_r.unwrap(); + const auto month = month_r.unwrap(); + const auto day = day_r.unwrap(); + + { + // We briefly check whether the input date is valid or not. + // Actually, because of the historical reasons, there are several + // edge cases, such as 1582/10/5-1582/10/14 (only in several countries). + // But here, we do not care about it. + // It makes the code complicated and there is only low probability + // that such a specific date is needed in practice. If someone need to + // validate date accurately, that means that the one need a specialized + // library for their purpose in another layer. + + const bool is_leap = (year % 4 == 0) && + ((year % 100 != 0) || (year % 400 == 0)); + const auto max_day = [month, is_leap]() { + if (month == 2) { + return is_leap ? 29 : 28; + } + if (month == 4 || month == 6 || month == 9 || month == 11) { + return 30; + } + return 31; + }(); + + if ((month < 1 || 12 < month) || (day < 1 || max_day < day)) { + auto src = source_location(region(first)); + return err( + make_error_info("toml::parse_local_date: invalid date.", + std::move(src), + "month must be 01-12, day must be any of " + "01-28,29,30,31 depending on the month/year.")); + } + } + + return ok( + std::make_tuple(local_date(year, static_cast(month - 1), day), + std::move(fmt), + std::move(reg))); + } + + template + result, error_info> parse_local_date(location& loc, + const context& ctx) { + auto val_fmt_reg = parse_local_date_only(loc, ctx); + if (val_fmt_reg.is_err()) { + return err(val_fmt_reg.unwrap_err()); + } + + auto val = std::move(std::get<0>(val_fmt_reg.unwrap())); + auto fmt = std::move(std::get<1>(val_fmt_reg.unwrap())); + auto reg = std::move(std::get<2>(val_fmt_reg.unwrap())); + + return ok( + basic_value(std::move(val), std::move(fmt), {}, std::move(reg))); + } + + // all the offset_datetime, local_datetime, local_time parses date part. + template + result, error_info> + parse_local_time_only(location& loc, const context& ctx) { + const auto first = loc; + const auto& spec = ctx.toml_spec(); + + local_time_format_info fmt; + + // ---------------------------------------------------------------------- + // check syntax + auto reg = syntax::local_time(spec).scan(loc); + if (!reg.is_ok()) { + if (spec.v1_1_0_make_seconds_optional) { + return err(make_syntax_error( + "toml::parse_local_time: " + "invalid time: time must be HH:MM(:SS.sss) (seconds are optional)", + syntax::local_time(spec), + loc)); + } else { + return err( + make_syntax_error("toml::parse_local_time: " + "invalid time: time must be HH:MM:SS(.sss) " + "(subseconds are optional)", + syntax::local_time(spec), + loc)); + } + } + + // ---------------------------------------------------------------------- + // it matches. gen value + const auto str = reg.as_string(); + + // at least we have HH:MM. + // 01234 + // HH:MM + const auto hour_r = from_string(str.substr(0, 2)); + const auto minute_r = from_string(str.substr(3, 2)); + + if (hour_r.is_err()) { + auto src = source_location(region(first)); + return err(make_error_info("toml::parse_local_time: " + "failed to read hour `" + + str.substr(0, 2) + "`", + std::move(src), + "here")); + } + if (minute_r.is_err()) { + auto src = source_location(region(first)); + return err(make_error_info("toml::parse_local_time: " + "failed to read minute `" + + str.substr(3, 2) + "`", + std::move(src), + "here")); + } + + const auto hour = hour_r.unwrap(); + const auto minute = minute_r.unwrap(); + + if ((hour < 0 || 24 <= hour) || (minute < 0 || 60 <= minute)) { + auto src = source_location(region(first)); + return err( + make_error_info("toml::parse_local_time: invalid time.", + std::move(src), + "hour must be 00-23, minute must be 00-59.")); + } + + // ----------------------------------------------------------------------- + // we have hour and minute. + // Since toml v1.1.0, second and subsecond part becomes optional. + // Check the version and return if second does not exist. + + if (str.size() == 5 && spec.v1_1_0_make_seconds_optional) { + fmt.has_seconds = false; + fmt.subsecond_precision = 0; + return ok(std::make_tuple(local_time(hour, minute, 0), + std::move(fmt), + std::move(reg))); + } + assert(str.at(5) == ':'); + + // we have at least `:SS` part. `.subseconds` are optional. + + // 0 1 + // 012345678901234 + // HH:MM:SS.subsec + const auto sec_r = from_string(str.substr(6, 2)); + if (sec_r.is_err()) { + auto src = source_location(region(first)); + return err(make_error_info("toml::parse_local_time: " + "failed to read second `" + + str.substr(6, 2) + "`", + std::move(src), + "here")); + } + const auto sec = sec_r.unwrap(); + + if (sec < 0 || 60 < sec) // :60 is allowed + { + auto src = source_location(region(first)); + return err(make_error_info("toml::parse_local_time: invalid time.", + std::move(src), + "second must be 00-60.")); + } + + if (str.size() == 8) { + fmt.has_seconds = true; + fmt.subsecond_precision = 0; + return ok(std::make_tuple(local_time(hour, minute, sec), + std::move(fmt), + std::move(reg))); + } + + assert(str.at(8) == '.'); + + auto secfrac = str.substr(9, str.size() - 9); + + fmt.has_seconds = true; + fmt.subsecond_precision = secfrac.size(); + + while (secfrac.size() < 9) { + secfrac += '0'; + } + assert(9 <= secfrac.size()); + const auto ms_r = from_string(secfrac.substr(0, 3)); + const auto us_r = from_string(secfrac.substr(3, 3)); + const auto ns_r = from_string(secfrac.substr(6, 3)); + + if (ms_r.is_err()) { + auto src = source_location(region(first)); + return err(make_error_info("toml::parse_local_time: " + "failed to read milliseconds `" + + secfrac.substr(0, 3) + "`", + std::move(src), + "here")); + } + if (us_r.is_err()) { + auto src = source_location(region(first)); + return err(make_error_info("toml::parse_local_time: " + "failed to read microseconds`" + + str.substr(3, 3) + "`", + std::move(src), + "here")); + } + if (ns_r.is_err()) { + auto src = source_location(region(first)); + return err(make_error_info("toml::parse_local_time: " + "failed to read nanoseconds`" + + str.substr(6, 3) + "`", + std::move(src), + "here")); + } + const auto ms = ms_r.unwrap(); + const auto us = us_r.unwrap(); + const auto ns = ns_r.unwrap(); + + return ok(std::make_tuple(local_time(hour, minute, sec, ms, us, ns), + std::move(fmt), + std::move(reg))); + } + + template + result, error_info> parse_local_time(location& loc, + const context& ctx) { + const auto first = loc; + + auto val_fmt_reg = parse_local_time_only(loc, ctx); + if (val_fmt_reg.is_err()) { + return err(val_fmt_reg.unwrap_err()); + } + + auto val = std::move(std::get<0>(val_fmt_reg.unwrap())); + auto fmt = std::move(std::get<1>(val_fmt_reg.unwrap())); + auto reg = std::move(std::get<2>(val_fmt_reg.unwrap())); + + return ok( + basic_value(std::move(val), std::move(fmt), {}, std::move(reg))); + } + + template + result, error_info> parse_local_datetime(location& loc, + const context& ctx) { + using char_type = location::char_type; + + const auto first = loc; + + local_datetime_format_info fmt; + + // ---------------------------------------------------------------------- + + auto date_fmt_reg = parse_local_date_only(loc, ctx); + if (date_fmt_reg.is_err()) { + return err(date_fmt_reg.unwrap_err()); + } + + if (loc.current() == char_type('T')) { + loc.advance(); + fmt.delimiter = datetime_delimiter_kind::upper_T; + } else if (loc.current() == char_type('t')) { + loc.advance(); + fmt.delimiter = datetime_delimiter_kind::lower_t; + } else if (loc.current() == char_type(' ')) { + loc.advance(); + fmt.delimiter = datetime_delimiter_kind::space; + } else { + auto src = source_location(region(loc)); + return err( + make_error_info("toml::parse_local_datetime: " + "expect date-time delimiter `T`, `t` or ` `(space).", + std::move(src), + "here")); + } + + auto time_fmt_reg = parse_local_time_only(loc, ctx); + if (time_fmt_reg.is_err()) { + return err(time_fmt_reg.unwrap_err()); + } + + fmt.has_seconds = std::get<1>(time_fmt_reg.unwrap()).has_seconds; + fmt.subsecond_precision = std::get<1>(time_fmt_reg.unwrap()).subsecond_precision; + + // ---------------------------------------------------------------------- + + region reg(first, loc); + local_datetime val(std::get<0>(date_fmt_reg.unwrap()), + std::get<0>(time_fmt_reg.unwrap())); + + return ok(basic_value(val, std::move(fmt), {}, std::move(reg))); + } + + template + result, error_info> parse_offset_datetime( + location& loc, + const context& ctx) { + using char_type = location::char_type; + + const auto first = loc; + const auto& spec = ctx.toml_spec(); + + offset_datetime_format_info fmt; + + // ---------------------------------------------------------------------- + // date part + + auto date_fmt_reg = parse_local_date_only(loc, ctx); + if (date_fmt_reg.is_err()) { + return err(date_fmt_reg.unwrap_err()); + } + + // ---------------------------------------------------------------------- + // delimiter + + if (loc.current() == char_type('T')) { + loc.advance(); + fmt.delimiter = datetime_delimiter_kind::upper_T; + } else if (loc.current() == char_type('t')) { + loc.advance(); + fmt.delimiter = datetime_delimiter_kind::lower_t; + } else if (loc.current() == char_type(' ')) { + loc.advance(); + fmt.delimiter = datetime_delimiter_kind::space; + } else { + auto src = source_location(region(loc)); + return err( + make_error_info("toml::parse_offset_datetime: " + "expect date-time delimiter `T` or ` `(space).", + std::move(src), + "here")); + } + + // ---------------------------------------------------------------------- + // time part + + auto time_fmt_reg = parse_local_time_only(loc, ctx); + if (time_fmt_reg.is_err()) { + return err(time_fmt_reg.unwrap_err()); + } + + fmt.has_seconds = std::get<1>(time_fmt_reg.unwrap()).has_seconds; + fmt.subsecond_precision = std::get<1>(time_fmt_reg.unwrap()).subsecond_precision; + + // ---------------------------------------------------------------------- + // offset part + + const auto ofs_reg = syntax::time_offset(spec).scan(loc); + if (!ofs_reg.is_ok()) { + return err(make_syntax_error( + "toml::parse_offset_datetime: " + "invalid offset: offset must be like: Z, +01:00, or -10:00.", + syntax::time_offset(spec), + loc)); + } + + const auto ofs_str = ofs_reg.as_string(); + + time_offset offset(0, 0); + + assert(ofs_str.size() != 0); + + if (ofs_str.at(0) == char_type('+') || ofs_str.at(0) == char_type('-')) { + const auto hour_r = from_string(ofs_str.substr(1, 2)); + const auto minute_r = from_string(ofs_str.substr(4, 2)); + if (hour_r.is_err()) { + auto src = source_location(region(loc)); + return err(make_error_info("toml::parse_offset_datetime: " + "Failed to read offset hour part", + std::move(src), + "here")); + } + if (minute_r.is_err()) { + auto src = source_location(region(loc)); + return err(make_error_info("toml::parse_offset_datetime: " + "Failed to read offset minute part", + std::move(src), + "here")); + } + const auto hour = hour_r.unwrap(); + const auto minute = minute_r.unwrap(); + + if (ofs_str.at(0) == '+') { + offset = time_offset(hour, minute); + } else { + offset = time_offset(-hour, -minute); + } + } else { + assert(ofs_str.at(0) == char_type('Z') || ofs_str.at(0) == char_type('z')); + } + + if (offset.hour < -24 || 24 < offset.hour || offset.minute < -60 || + 60 < offset.minute) { + return err( + make_error_info("toml::parse_offset_datetime: " + "too large offset: |hour| <= 24, |minute| <= 60", + source_location(region(first, loc)), + "here")); + } + + // ---------------------------------------------------------------------- + + region reg(first, loc); + offset_datetime val(local_datetime(std::get<0>(date_fmt_reg.unwrap()), + std::get<0>(time_fmt_reg.unwrap())), + offset); + + return ok(basic_value(val, std::move(fmt), {}, std::move(reg))); + } + + /* ============================================================================ + * ___ _ _ + * / __| |_ _ _(_)_ _ __ _ + * \__ \ _| '_| | ' \/ _` | + * |___/\__|_| |_|_||_\__, | + * |___/ + */ + + template + result::string_type, error_info> parse_utf8_codepoint( + const region& reg) { + using string_type = typename basic_value::string_type; + using char_type = typename string_type::value_type; + + // assert(reg.as_lines().size() == 1); // XXX heavy check + + const auto str = reg.as_string(); + assert(!str.empty()); + assert(str.front() == 'u' || str.front() == 'U' || str.front() == 'x'); + + std::uint_least32_t codepoint; + std::istringstream iss(str.substr(1)); + iss >> std::hex >> codepoint; + + const auto to_char = [](const std::uint_least32_t i) noexcept -> char_type { + const auto uc = static_cast(i & 0xFF); + return cxx::bit_cast(uc); + }; + + string_type character; + if (codepoint < 0x80) // U+0000 ... U+0079 ; just an ASCII. + { + character += static_cast(codepoint); + } else if (codepoint < 0x800) // U+0080 ... U+07FF + { + // 110yyyyx 10xxxxxx; 0x3f == 0b0011'1111 + character += to_char(0xC0 | (codepoint >> 6)); + character += to_char(0x80 | (codepoint & 0x3F)); + } else if (codepoint < 0x10000) // U+0800...U+FFFF + { + if (0xD800 <= codepoint && codepoint <= 0xDFFF) { + auto src = source_location(reg); + return err(make_error_info("toml::parse_utf8_codepoint: " + "[0xD800, 0xDFFF] is not a valid UTF-8", + std::move(src), + "here")); + } + assert(codepoint < 0xD800 || 0xDFFF < codepoint); + // 1110yyyy 10yxxxxx 10xxxxxx + character += to_char(0xE0 | (codepoint >> 12)); + character += to_char(0x80 | ((codepoint >> 6) & 0x3F)); + character += to_char(0x80 | ((codepoint) & 0x3F)); + } else if (codepoint < 0x110000) // U+010000 ... U+10FFFF + { + // 11110yyy 10yyxxxx 10xxxxxx 10xxxxxx + character += to_char(0xF0 | (codepoint >> 18)); + character += to_char(0x80 | ((codepoint >> 12) & 0x3F)); + character += to_char(0x80 | ((codepoint >> 6) & 0x3F)); + character += to_char(0x80 | ((codepoint) & 0x3F)); + } else // out of UTF-8 region + { + auto src = source_location(reg); + return err(make_error_info("toml::parse_utf8_codepoint: " + "input codepoint is too large.", + std::move(src), + "must be in range [0x00, 0x10FFFF]")); + } + return ok(character); + } + + template + result::string_type, error_info> parse_escape_sequence( + location& loc, + const context& ctx) { + using string_type = typename basic_value::string_type; + using char_type = typename string_type::value_type; + + const auto& spec = ctx.toml_spec(); + + assert(!loc.eof()); + assert(loc.current() == '\\'); + loc.advance(); // consume the first backslash + + string_type retval; + + if (loc.current() == '\\') { + retval += char_type('\\'); + loc.advance(); + } else if (loc.current() == '"') { + retval += char_type('\"'); + loc.advance(); + } else if (loc.current() == 'b') { + retval += char_type('\b'); + loc.advance(); + } else if (loc.current() == 'f') { + retval += char_type('\f'); + loc.advance(); + } else if (loc.current() == 'n') { + retval += char_type('\n'); + loc.advance(); + } else if (loc.current() == 'r') { + retval += char_type('\r'); + loc.advance(); + } else if (loc.current() == 't') { + retval += char_type('\t'); + loc.advance(); + } else if (spec.v1_1_0_add_escape_sequence_e && loc.current() == 'e') { + retval += char_type('\x1b'); + loc.advance(); + } else if (spec.v1_1_0_add_escape_sequence_x && loc.current() == 'x') { + auto scanner = sequence(character('x'), + repeat_exact(2, syntax::hexdig(spec))); + const auto reg = scanner.scan(loc); + if (!reg.is_ok()) { + auto src = source_location(region(loc)); + return err( + make_error_info("toml::parse_escape_sequence: " + "invalid token found in UTF-8 codepoint \\xhh", + std::move(src), + "here")); + } + const auto utf8 = parse_utf8_codepoint(reg); + if (utf8.is_err()) { + return err(utf8.as_err()); + } + retval += utf8.unwrap(); + } else if (loc.current() == 'u') { + auto scanner = sequence(character('u'), + repeat_exact(4, syntax::hexdig(spec))); + const auto reg = scanner.scan(loc); + if (!reg.is_ok()) { + auto src = source_location(region(loc)); + return err( + make_error_info("toml::parse_escape_sequence: " + "invalid token found in UTF-8 codepoint \\uhhhh", + std::move(src), + "here")); + } + const auto utf8 = parse_utf8_codepoint(reg); + if (utf8.is_err()) { + return err(utf8.as_err()); + } + retval += utf8.unwrap(); + } else if (loc.current() == 'U') { + auto scanner = sequence(character('U'), + repeat_exact(8, syntax::hexdig(spec))); + const auto reg = scanner.scan(loc); + if (!reg.is_ok()) { + auto src = source_location(region(loc)); + return err(make_error_info( + "toml::parse_escape_sequence: " + "invalid token found in UTF-8 codepoint \\Uhhhhhhhh", + std::move(src), + "here")); + } + const auto utf8 = parse_utf8_codepoint(reg); + if (utf8.is_err()) { + return err(utf8.as_err()); + } + retval += utf8.unwrap(); + } else { + auto src = source_location(region(loc)); + std::string escape_seqs = + "allowed escape seqs: \\\\, \\\", \\b, \\f, \\n, \\r, \\t"; + if (spec.v1_1_0_add_escape_sequence_e) { + escape_seqs += ", \\e"; + } + if (spec.v1_1_0_add_escape_sequence_x) { + escape_seqs += ", \\xhh"; + } + escape_seqs += ", \\uhhhh, or \\Uhhhhhhhh"; + + return err(make_error_info("toml::parse_escape_sequence: " + "unknown escape sequence.", + std::move(src), + escape_seqs)); + } + return ok(retval); + } + + template + result, error_info> parse_ml_basic_string( + location& loc, + const context& ctx) { + const auto first = loc; + const auto& spec = ctx.toml_spec(); + + string_format_info fmt; + fmt.fmt = string_format::multiline_basic; + + auto reg = syntax::ml_basic_string(spec).scan(loc); + if (!reg.is_ok()) { + return err(make_syntax_error("toml::parse_ml_basic_string: " + "invalid string format", + syntax::ml_basic_string(spec), + loc)); + } + + // ---------------------------------------------------------------------- + // it matches. gen value + + auto str = reg.as_string(); + + // we already checked that it starts with """ and ends with """. + assert(str.substr(0, 3) == "\"\"\""); + str.erase(0, 3); + + assert(str.size() >= 3); + assert(str.substr(str.size() - 3, 3) == "\"\"\""); + str.erase(str.size() - 3, 3); + + // the first newline just after """ is trimmed + if (str.size() >= 1 && str.at(0) == '\n') { + str.erase(0, 1); + fmt.start_with_newline = true; + } else if (str.size() >= 2 && str.at(0) == '\r' && str.at(1) == '\n') { + str.erase(0, 2); + fmt.start_with_newline = true; + } + + using string_type = typename basic_value::string_type; + string_type val; + { + auto iter = str.cbegin(); + while (iter != str.cend()) { + if (*iter == '\\') // remove whitespaces around escaped-newline + { + // we assume that the string is not too long to copy + auto loc2 = make_temporary_location(make_string(iter, str.cend())); + if (syntax::escaped_newline(spec).scan(loc2).is_ok()) { + std::advance(iter, + loc2.get_location()); // skip escaped newline and indent + // now iter points non-WS char + assert(iter == str.end() || (*iter != ' ' && *iter != '\t')); + } else // normal escape seq. + { + auto esc = parse_escape_sequence(loc2, ctx); + + // syntax does not check its value. the unicode codepoint may be + // invalid, e.g. out-of-bound, [0xD800, 0xDFFF] + if (esc.is_err()) { + return err(esc.unwrap_err()); + } + + val += esc.unwrap(); + std::advance(iter, loc2.get_location()); + } + } else // we already checked the syntax. we don't need to check it again. + { + val += static_cast(*iter); + ++iter; + } + } + } + + return ok( + basic_value(std::move(val), std::move(fmt), {}, std::move(reg))); + } + + template + result::string_type, region>, error_info> + parse_basic_string_only(location& loc, const context& ctx) { + const auto first = loc; + const auto& spec = ctx.toml_spec(); + + auto reg = syntax::basic_string(spec).scan(loc); + if (!reg.is_ok()) { + return err(make_syntax_error("toml::parse_basic_string: " + "invalid string format", + syntax::basic_string(spec), + loc)); + } + + // ---------------------------------------------------------------------- + // it matches. gen value + + auto str = reg.as_string(); + + assert(str.back() == '\"'); + str.pop_back(); + assert(str.at(0) == '\"'); + str.erase(0, 1); + + using string_type = typename basic_value::string_type; + using char_type = typename string_type::value_type; + string_type val; + + { + auto iter = str.begin(); + while (iter != str.end()) { + if (*iter == '\\') { + auto loc2 = make_temporary_location(make_string(iter, str.end())); + + auto esc = parse_escape_sequence(loc2, ctx); + + // syntax does not check its value. the unicode codepoint may be + // invalid, e.g. out-of-bound, [0xD800, 0xDFFF] + if (esc.is_err()) { + return err(esc.unwrap_err()); + } + + val += esc.unwrap(); + std::advance(iter, loc2.get_location()); + } else { + val += char_type(*iter); // we already checked the syntax. + ++iter; + } + } + } + return ok(std::make_pair(val, reg)); + } + + template + result, error_info> parse_basic_string(location& loc, + const context& ctx) { + const auto first = loc; + + string_format_info fmt; + fmt.fmt = string_format::basic; + + auto val_res = parse_basic_string_only(loc, ctx); + if (val_res.is_err()) { + return err(std::move(val_res.unwrap_err())); + } + auto val = std::move(val_res.unwrap().first); + auto reg = std::move(val_res.unwrap().second); + + return ok( + basic_value(std::move(val), std::move(fmt), {}, std::move(reg))); + } + + template + result, error_info> parse_ml_literal_string( + location& loc, + const context& ctx) { + const auto first = loc; + const auto& spec = ctx.toml_spec(); + + string_format_info fmt; + fmt.fmt = string_format::multiline_literal; + + auto reg = syntax::ml_literal_string(spec).scan(loc); + if (!reg.is_ok()) { + return err(make_syntax_error("toml::parse_ml_literal_string: " + "invalid string format", + syntax::ml_literal_string(spec), + loc)); + } + + // ---------------------------------------------------------------------- + // it matches. gen value + + auto str = reg.as_string(); + + assert(str.substr(0, 3) == "'''"); + assert(str.substr(str.size() - 3, 3) == "'''"); + str.erase(0, 3); + str.erase(str.size() - 3, 3); + + // the first newline just after """ is trimmed + if (str.size() >= 1 && str.at(0) == '\n') { + str.erase(0, 1); + fmt.start_with_newline = true; + } else if (str.size() >= 2 && str.at(0) == '\r' && str.at(1) == '\n') { + str.erase(0, 2); + fmt.start_with_newline = true; + } + + using string_type = typename basic_value::string_type; + string_type val(str.begin(), str.end()); + + return ok( + basic_value(std::move(val), std::move(fmt), {}, std::move(reg))); + } + + template + result::string_type, region>, error_info> + parse_literal_string_only(location& loc, const context& ctx) { + const auto first = loc; + const auto& spec = ctx.toml_spec(); + + auto reg = syntax::literal_string(spec).scan(loc); + if (!reg.is_ok()) { + return err(make_syntax_error("toml::parse_literal_string: " + "invalid string format", + syntax::literal_string(spec), + loc)); + } + + // ---------------------------------------------------------------------- + // it matches. gen value + + auto str = reg.as_string(); + + assert(str.back() == '\''); + str.pop_back(); + assert(str.at(0) == '\''); + str.erase(0, 1); + + using string_type = typename basic_value::string_type; + string_type val(str.begin(), str.end()); + + return ok(std::make_pair(std::move(val), std::move(reg))); + } + + template + result, error_info> parse_literal_string(location& loc, + const context& ctx) { + const auto first = loc; + + string_format_info fmt; + fmt.fmt = string_format::literal; + + auto val_res = parse_literal_string_only(loc, ctx); + if (val_res.is_err()) { + return err(std::move(val_res.unwrap_err())); + } + auto val = std::move(val_res.unwrap().first); + auto reg = std::move(val_res.unwrap().second); + + return ok( + basic_value(std::move(val), std::move(fmt), {}, std::move(reg))); + } + + template + result, error_info> parse_string(location& loc, + const context& ctx) { + const auto first = loc; + + if (!loc.eof() && loc.current() == '"') { + if (literal("\"\"\"").scan(loc).is_ok()) { + loc = first; + return parse_ml_basic_string(loc, ctx); + } else { + loc = first; + return parse_basic_string(loc, ctx); + } + } else if (!loc.eof() && loc.current() == '\'') { + if (literal("'''").scan(loc).is_ok()) { + loc = first; + return parse_ml_literal_string(loc, ctx); + } else { + loc = first; + return parse_literal_string(loc, ctx); + } + } else { + auto src = source_location(region(loc)); + return err(make_error_info("toml::parse_string: " + "not a string", + std::move(src), + "here")); + } + } + + template + result, error_info> parse_null(location& loc, + const context& ctx) { + const auto& spec = ctx.toml_spec(); + if (!spec.ext_null_value) { + return err( + make_error_info("toml::parse_null: " + "invalid spec: spec.ext_null_value must be true.", + source_location(region(loc)), + "here")); + } + + // ---------------------------------------------------------------------- + // check syntax + auto reg = syntax::null_value(spec).scan(loc); + if (!reg.is_ok()) { + return err(make_syntax_error("toml::parse_null: " + "invalid null: null must be lowercase. ", + syntax::null_value(spec), + loc)); + } + + // ---------------------------------------------------------------------- + // it matches. gen value + + // ---------------------------------------------------------------------- + // no format info for boolean + + return ok(basic_value(detail::none_t {}, std::move(reg))); + } + + /* ============================================================================ + * _ __ + * | |/ /___ _ _ + * | ' + result::key_type, error_info> parse_simple_key( + location& loc, + const context& ctx) { + using key_type = typename basic_value::key_type; + const auto& spec = ctx.toml_spec(); + + if (loc.current() == '\"') { + auto str_res = parse_basic_string_only(loc, ctx); + if (str_res.is_ok()) { + return ok(std::move(str_res.unwrap().first)); + } else { + return err(std::move(str_res.unwrap_err())); + } + } else if (loc.current() == '\'') { + auto str_res = parse_literal_string_only(loc, ctx); + if (str_res.is_ok()) { + return ok(std::move(str_res.unwrap().first)); + } else { + return err(std::move(str_res.unwrap_err())); + } + } + + // bare key. + + if (const auto bare = syntax::unquoted_key(spec).scan(loc)) { + return ok(string_conv(bare.as_string())); + } else { + std::string postfix; + if (spec.v1_1_0_allow_non_english_in_bare_keys) { + postfix = + "Hint: Not all Unicode characters are allowed as bare key.\n"; + } else { + postfix = "Hint: non-ASCII scripts are allowed in toml v1.1.0, but " + "not in v1.0.0.\n"; + } + return err(make_syntax_error( + "toml::parse_simple_key: " + "invalid key: key must be \"quoted\", 'quoted-literal', or bare key.", + syntax::unquoted_key(spec), + loc, + postfix)); + } + } + + // dotted key become vector of keys + template + result::key_type>, region>, error_info> + parse_key(location& loc, const context& ctx) { + const auto first = loc; + const auto& spec = ctx.toml_spec(); + + using key_type = typename basic_value::key_type; + std::vector keys; + while (!loc.eof()) { + auto key = parse_simple_key(loc, ctx); + if (!key.is_ok()) { + return err(key.unwrap_err()); + } + keys.push_back(std::move(key.unwrap())); + + auto reg = syntax::dot_sep(spec).scan(loc); + if (!reg.is_ok()) { + break; + } + } + if (keys.empty()) { + auto src = source_location(region(first)); + return err(make_error_info("toml::parse_key: expected a new key, " + "but got nothing", + std::move(src), + "reached EOF")); + } + + return ok(std::make_pair(std::move(keys), region(first, loc))); + } + + // ============================================================================ + + // forward-decl to implement parse_array and parse_table + template + result, error_info> parse_value(location&, context& ctx); + + template + result::key_type>, region>, + basic_value>, + error_info> + parse_key_value_pair(location& loc, context& ctx) { + const auto first = loc; + const auto& spec = ctx.toml_spec(); + + auto key_res = parse_key(loc, ctx); + if (key_res.is_err()) { + loc = first; + return err(key_res.unwrap_err()); + } + + if (!syntax::keyval_sep(spec).scan(loc).is_ok()) { + auto e = make_syntax_error("toml::parse_key_value_pair: " + "invalid key value separator `=`", + syntax::keyval_sep(spec), + loc); + loc = first; + return err(std::move(e)); + } + + auto v_res = parse_value(loc, ctx); + if (v_res.is_err()) { + // loc = first; + return err(v_res.unwrap_err()); + } + return ok( + std::make_pair(std::move(key_res.unwrap()), std::move(v_res.unwrap()))); + } + + /* ============================================================================ + * __ _ _ _ _ _ __ _ _ _ + * / _` | '_| '_/ _` | || | + * \__,_|_| |_| \__,_|\_, | + * |__/ + */ + + // array(and multiline inline table with `{` and `}`) has the following format. + // `[` + // (ws|newline|comment-line)? (value) (ws|newline|comment-line)? `,` + // (ws|newline|comment-line)? (value) (ws|newline|comment-line)? `,` + // ... + // (ws|newline|comment-line)? (value) (ws|newline|comment-line)? (`,`)? + // (ws|newline|comment-line)? `]` + // it skips (ws|newline|comment-line) and returns the token. + template + struct multiline_spacer { + using comment_type = typename TC::comment_type; + bool newline_found; + indent_char indent_type; + std::int32_t indent; + comment_type comments; + }; + + template + std::ostream& operator<<(std::ostream& os, const multiline_spacer& sp) { + os << "{newline=" << sp.newline_found << ", "; + os << "indent_type=" << sp.indent_type << ", "; + os << "indent=" << sp.indent << ", "; + os << "comments=" << sp.comments.size() << "}"; + return os; + } + + template + cxx::optional> skip_multiline_spacer( + location& loc, + context& ctx, + const bool newline_found = false) { + const auto& spec = ctx.toml_spec(); + + multiline_spacer spacer; + spacer.newline_found = newline_found; + spacer.indent_type = indent_char::none; + spacer.indent = 0; + spacer.comments.clear(); + + bool spacer_found = false; + while (!loc.eof()) { + if (auto comm = sequence(syntax::comment(spec), syntax::newline(spec)) + .scan(loc)) { + spacer.newline_found = true; + auto comment = comm.as_string(); + if (!comment.empty() && comment.back() == '\n') { + comment.pop_back(); + if (!comment.empty() && comment.back() == '\r') { + comment.pop_back(); + } + } + + spacer.comments.push_back(std::move(comment)); + spacer.indent_type = indent_char::none; + spacer.indent = 0; + spacer_found = true; + } else if (auto nl = syntax::newline(spec).scan(loc)) { + spacer.newline_found = true; + spacer.comments.clear(); + spacer.indent_type = indent_char::none; + spacer.indent = 0; + spacer_found = true; + } else if (auto sp = repeat_at_least( + 1, + character(cxx::bit_cast(' '))) + .scan(loc)) { + spacer.indent_type = indent_char::space; + spacer.indent = static_cast(sp.length()); + spacer_found = true; + } else if ( + auto tabs = repeat_at_least( + 1, + character(cxx::bit_cast('\t'))) + .scan(loc)) { + spacer.indent_type = indent_char::tab; + spacer.indent = static_cast(tabs.length()); + spacer_found = true; + } else { + break; // done + } + } + if (!spacer_found) { + return cxx::make_nullopt(); + } + return spacer; + } + + // not an [[array.of.tables]]. It parses ["this", "type"] + template + result, error_info> parse_array(location& loc, + context& ctx) { + const auto num_errors = ctx.errors().size(); + + const auto first = loc; + + if (loc.eof() || loc.current() != '[') { + auto src = source_location(region(loc)); + return err(make_error_info("toml::parse_array: " + "The next token is not an array", + std::move(src), + "here")); + } + loc.advance(); + + typename basic_value::array_type val; + + array_format_info fmt; + fmt.fmt = array_format::oneline; + fmt.indent_type = indent_char::none; + + auto spacer = skip_multiline_spacer(loc, ctx); + if (spacer.has_value() && spacer.value().newline_found) { + fmt.fmt = array_format::multiline; + } + + bool comma_found = true; + while (!loc.eof()) { + if (loc.current() == location::char_type(']')) { + if (spacer.has_value() && spacer.value().newline_found && + spacer.value().indent_type != indent_char::none) { + fmt.indent_type = spacer.value().indent_type; + fmt.closing_indent = spacer.value().indent; + } + break; + } + + if (!comma_found) { + auto src = source_location(region(loc)); + return err( + make_error_info("toml::parse_array: " + "expected value-separator `,` or closing `]`", + std::move(src), + "here")); + } + + if (spacer.has_value() && spacer.value().newline_found && + spacer.value().indent_type != indent_char::none) { + fmt.indent_type = spacer.value().indent_type; + fmt.body_indent = spacer.value().indent; + } + + if (auto elem_res = parse_value(loc, ctx)) { + auto elem = std::move(elem_res.unwrap()); + + if (spacer.has_value()) // copy previous comments to value + { + elem.comments() = std::move(spacer.value().comments); + } + + // parse spaces between a value and a comma + // array = [ + // 42 , # the answer + // ^^^^ + // 3.14 # pi + // , 2.71 ^^^^ + // ^^ + spacer = skip_multiline_spacer(loc, ctx); + if (spacer.has_value()) { + for (std::size_t i = 0; i < spacer.value().comments.size(); ++i) { + elem.comments().push_back(std::move(spacer.value().comments.at(i))); + } + if (spacer.value().newline_found) { + fmt.fmt = array_format::multiline; + } + } + + comma_found = character(',').scan(loc).is_ok(); + + // parse comment after a comma + // array = [ + // 42 , # the answer + // ^^^^^^^^^^^^ + // 3.14 # pi + // ^^^^ + // ] + auto com_res = parse_comment_line(loc, ctx); + if (com_res.is_err()) { + ctx.report_error(com_res.unwrap_err()); + } + + const bool comment_found = com_res.is_ok() && + com_res.unwrap().has_value(); + if (comment_found) { + fmt.fmt = array_format::multiline; + elem.comments().push_back(com_res.unwrap().value()); + } + if (comma_found) { + spacer = skip_multiline_spacer(loc, ctx, comment_found); + if (spacer.has_value() && spacer.value().newline_found) { + fmt.fmt = array_format::multiline; + } + } + val.push_back(std::move(elem)); + } else { + // if err, push error to ctx and try recovery. + ctx.report_error(std::move(elem_res.unwrap_err())); + + // if it looks like some value, then skip the value. + // otherwise, it may be a new key-value pair or a new table and + // the error is "missing closing ]". stop parsing. + + const auto before_skip = loc.get_location(); + skip_value(loc, ctx); + if (before_skip == loc.get_location()) // cannot skip! break... + { + break; + } + } + } + + if (loc.current() != ']') { + auto src = source_location(region(loc)); + return err( + make_error_info("toml::parse_array: missing closing bracket `]`", + std::move(src), + "expected `]`, reached EOF")); + } else { + loc.advance(); + } + // any error reported from this function + if (num_errors != ctx.errors().size()) { + assert(ctx.has_error()); // already reported + return err(ctx.errors().back()); + } + + return ok( + basic_value(std::move(val), std::move(fmt), {}, region(first, loc))); + } + + /* ============================================================================ + * _ _ _ _ _ _ + * (_)_ _ | (_)_ _ ___ | |_ __ _| |__| |___ + * | | ' \| | | ' \/ -_) | _/ _` | '_ \ / -_) + * |_|_||_|_|_|_||_\___| \__\__,_|_.__/_\___| + */ + + // ---------------------------------------------------------------------------- + // insert_value is the most complicated part of the toml spec. + // + // To parse a toml file correctly, we sometimes need to check an exising + // value is appendable or not. + // + // For example while parsing an inline array of tables, + // + // ```toml + // aot = [ + // {a = "foo"}, + // {a = "bar", b = "baz"}, + // ] + // ``` + // + // this `aot` is appendable until parser reaches to `]`. After that, it + // becomes non-appendable. + // + // On the other hand, a normal array of tables, such as + // + // ```toml + // [[aot]] + // a = "foo" + // + // [[aot]] + // a = "bar" + // b = "baz" + // ``` + // This `[[aot]]` is appendable until the parser reaches to the EOF. + // + // + // It becomes a bit more difficult in case of dotted keys. + // In TOML, it is allowed to append a key-value pair to a table that is + // *implicitly* defined by a subtable definitino. + // + // ```toml + // [x.y.z] + // w = 123 + // + // [x] + // a = "foo" # OK. x is defined implicitly by `[x.y.z]`. + // ``` + // + // But if the table is defined by a dotted keys, it is not appendable. + // + // ```toml + // [x] + // y.z.w = 123 + // + // [x.y] + // # ERROR. x.y is already defined by a dotted table in the previous table. + // ``` + // + // Also, reopening a table using dotted keys is invalid. + // + // ```toml + // [x.y.z] + // w = 123 + // + // [x] + // y.z.v = 42 # ERROR. [x.y.z] is already defined. + // ``` + // + // + // ```toml + // [a] + // b.c = "foo" + // b.d = "bar" + // ``` + // + // + // ```toml + // a.b = "foo" + // [a] + // c = "bar" # ERROR + // ``` + // + // In summary, + // - a table must be defined only once. + // - assignment to an exising table is possible only when: + // - defining a subtable [x.y] to an existing table [x]. + // - defining supertable [x] explicitly after [x.y]. + // - adding dotted keys in the same table. + + enum class inserting_value_kind : std::uint8_t { + std_table, // insert [standard.table] + array_table, // insert [[array.of.tables]] + dotted_keys // insert a.b.c = "this" + }; + + template + result*, error_info> insert_value( + const inserting_value_kind kind, + typename basic_value::table_type* current_table_ptr, + const std::vector::key_type>& keys, + region key_reg, + basic_value val) { + using value_type = basic_value; + using array_type = typename basic_value::array_type; + using table_type = typename basic_value::table_type; + + auto key_loc = source_location(key_reg); + + assert(!keys.empty()); + + // dotted key can insert to dotted key tables defined at the same level. + // dotted key can NOT reopen a table even if it is implcitly-defined one. + // + // [x.y.z] # define x and x.y implicitly. + // a = 42 + // + // [x] # reopening implcitly defined table + // r.s.t = 3.14 # VALID r and r.s are new tables. + // r.s.u = 2.71 # VALID r and r.s are dotted-key tables. valid. + // + // y.z.b = "foo" # INVALID x.y.z are multiline table, not a dotted key. + // y.c = "bar" # INVALID x.y is implicit multiline table, not a dotted key. + + // a table cannot reopen dotted-key tables. + // + // [t1] + // t2.t3.v = 0 + // [t1.t2] # INVALID t1.t2 is defined as a dotted-key table. + + for (std::size_t i = 0; i < keys.size(); ++i) { + const auto& key = keys.at(i); + table_type& current_table = *current_table_ptr; + + if (i + 1 < keys.size()) // there are more keys. go down recursively... + { + const auto found = current_table.find(key); + if (found == current_table.end()) // not found. add new table + { + table_format_info fmt; + fmt.indent_type = indent_char::none; + if (kind == inserting_value_kind::dotted_keys) { + fmt.fmt = table_format::dotted; + } else // table / array of tables + { + fmt.fmt = table_format::implicit; + } + current_table.emplace( + key, + value_type(table_type {}, fmt, std::vector {}, key_reg)); + + assert(current_table.at(key).is_table()); + current_table_ptr = std::addressof(current_table.at(key).as_table()); + } else if (found->second.is_table()) { + const auto fmt = found->second.as_table_fmt().fmt; + if (fmt == table_format::oneline || + fmt == table_format::multiline_oneline) { + // foo = {bar = "baz"} or foo = { \n bar = "baz" \n } + return err(make_error_info( + "toml::insert_value: " + "failed to insert a value: inline table is immutable", + key_loc, + "inserting this", + found->second.location(), + "to this table")); + } + // dotted key cannot reopen a table. + if (kind == inserting_value_kind::dotted_keys && + fmt != table_format::dotted) { + return err(make_error_info("toml::insert_value: " + "reopening a table using dotted keys", + key_loc, + "dotted key cannot reopen a table", + found->second.location(), + "this table is already closed")); + } + assert(found->second.is_table()); + current_table_ptr = std::addressof(found->second.as_table()); + } else if (found->second.is_array_of_tables()) { + // aot = [{this = "type", of = "aot"}] # cannot be reopened + if (found->second.as_array_fmt().fmt != array_format::array_of_tables) { + return err(make_error_info("toml::insert_value:" + "inline array of tables are immutable", + key_loc, + "inserting this", + found->second.location(), + "inline array of tables")); + } + // appending to [[aot]] + + if (kind == inserting_value_kind::dotted_keys) { + // [[array.of.tables]] + // [array.of] # reopening supertable is okay + // tables.x = "foo" # appending `x` to the first table + return err( + make_error_info("toml::insert_value:" + "dotted key cannot reopen an array-of-tables", + key_loc, + "inserting this", + found->second.location(), + "to this array-of-tables.")); + } + + // insert_value_by_dotkeys::std_table + // [[array.of.tables]] + // [array.of.tables.subtable] # appending to the last aot + // + // insert_value_by_dotkeys::array_table + // [[array.of.tables]] + // [[array.of.tables.subtable]] # appending to the last aot + auto& current_array_table = found->second.as_array().back(); + + assert(current_array_table.is_table()); + current_table_ptr = std::addressof(current_array_table.as_table()); + } else { + return err( + make_error_info("toml::insert_value: " + "failed to insert a value, value already exists", + key_loc, + "while inserting this", + found->second.location(), + "non-table value already exists")); + } + } else // this is the last key. insert a new value. + { + switch (kind) { + case inserting_value_kind::dotted_keys: { + if (current_table.find(key) != current_table.end()) { + return err(make_error_info( + "toml::insert_value: " + "failed to insert a value, value already exists", + key_loc, + "inserting this", + current_table.at(key).location(), + "but value already exists")); + } + current_table.emplace(key, std::move(val)); + return ok(std::addressof(current_table.at(key))); + } + case inserting_value_kind::std_table: { + // defining a new table or reopening supertable + auto found = current_table.find(key); + if (found == current_table.end()) // define a new aot + { + current_table.emplace(key, std::move(val)); + return ok(std::addressof(current_table.at(key))); + } else // the table is already defined, reopen it + { + // assigning a [std.table]. it must be an implicit table. + auto& target = found->second; + if (!target.is_table() || // could be an array-of-tables + target.as_table_fmt().fmt != table_format::implicit) { + return err(make_error_info( + "toml::insert_value: " + "failed to insert a table, table already defined", + key_loc, + "inserting this", + target.location(), + "this table is explicitly defined")); + } + + // merge table + for (const auto& kv : val.as_table()) { + if (target.contains(kv.first)) { + // [x.y.z] + // w = "foo" + // [x] + // y = "bar" + return err( + make_error_info("toml::insert_value: " + "failed to insert a table, table keys " + "conflict to each other", + key_loc, + "inserting this table", + kv.second.location(), + "having this value", + target.at(kv.first).location(), + "already defined here")); + } else { + target[kv.first] = kv.second; + } + } + // change implicit -> explicit + target.as_table_fmt().fmt = table_format::multiline; + // change definition region + change_region_of_value(target, val); + + return ok(std::addressof(current_table.at(key))); + } + } + case inserting_value_kind::array_table: { + auto found = current_table.find(key); + if (found == current_table.end()) // define a new aot + { + array_format_info fmt; + fmt.fmt = array_format::array_of_tables; + fmt.indent_type = indent_char::none; + + current_table.emplace(key, + value_type(array_type { std::move(val) }, + std::move(fmt), + std::vector {}, + std::move(key_reg))); + + assert(!current_table.at(key).as_array().empty()); + return ok(std::addressof(current_table.at(key).as_array().back())); + } else // the array is already defined, append to it + { + if (!found->second.is_array_of_tables()) { + return err(make_error_info( + "toml::insert_value: " + "failed to insert an array of tables, value already exists", + key_loc, + "while inserting this", + found->second.location(), + "non-table value already exists")); + } + if (found->second.as_array_fmt().fmt != + array_format::array_of_tables) { + return err(make_error_info("toml::insert_value: " + "failed to insert a table, inline " + "array of tables is immutable", + key_loc, + "while inserting this", + found->second.location(), + "this is inline array-of-tables")); + } + found->second.as_array().push_back(std::move(val)); + assert(!current_table.at(key).as_array().empty()); + return ok(std::addressof(current_table.at(key).as_array().back())); + } + } + default: { + assert(false); + } + } + } + } + return err(make_error_info("toml::insert_key: no keys found", + std::move(key_loc), + "here")); + } + + // ---------------------------------------------------------------------------- + + template + result, error_info> parse_inline_table(location& loc, + context& ctx) { + using table_type = typename basic_value::table_type; + + const auto num_errors = ctx.errors().size(); + + const auto first = loc; + const auto& spec = ctx.toml_spec(); + + if (loc.eof() || loc.current() != '{') { + auto src = source_location(region(loc)); + return err(make_error_info("toml::parse_inline_table: " + "The next token is not an inline table", + std::move(src), + "here")); + } + loc.advance(); + + table_type table; + table_format_info fmt; + fmt.fmt = table_format::oneline; + fmt.indent_type = indent_char::none; + + cxx::optional> spacer(cxx::make_nullopt()); + + if (spec.v1_1_0_allow_newlines_in_inline_tables) { + spacer = skip_multiline_spacer(loc, ctx); + if (spacer.has_value() && spacer.value().newline_found) { + fmt.fmt = table_format::multiline_oneline; + } + } else { + skip_whitespace(loc, ctx); + } + + bool still_empty = true; + bool comma_found = false; + while (!loc.eof()) { + // closing! + if (loc.current() == '}') { + if (comma_found && !spec.v1_1_0_allow_trailing_comma_in_inline_tables) { + auto src = source_location(region(loc)); + return err(make_error_info("toml::parse_inline_table: trailing " + "comma is not allowed in TOML-v1.0.0)", + std::move(src), + "here")); + } + + if (spec.v1_1_0_allow_newlines_in_inline_tables) { + if (spacer.has_value() && spacer.value().newline_found && + spacer.value().indent_type != indent_char::none) { + fmt.indent_type = spacer.value().indent_type; + fmt.closing_indent = spacer.value().indent; + } + } + break; + } + + // if we already found a value and didn't found `,` nor `}`, error. + if (!comma_found && !still_empty) { + auto src = source_location(region(loc)); + return err( + make_error_info("toml::parse_inline_table: " + "expected value-separator `,` or closing `}`", + std::move(src), + "here")); + } + + // parse indent. + if (spacer.has_value() && spacer.value().newline_found && + spacer.value().indent_type != indent_char::none) { + fmt.indent_type = spacer.value().indent_type; + fmt.body_indent = spacer.value().indent; + } + + still_empty = false; // parsing a value... + if (auto kv_res = parse_key_value_pair(loc, ctx)) { + auto keys = std::move(kv_res.unwrap().first.first); + auto key_reg = std::move(kv_res.unwrap().first.second); + auto val = std::move(kv_res.unwrap().second); + + auto ins_res = insert_value(inserting_value_kind::dotted_keys, + std::addressof(table), + keys, + std::move(key_reg), + std::move(val)); + if (ins_res.is_err()) { + ctx.report_error(std::move(ins_res.unwrap_err())); + // we need to skip until the next value (or end of the table) + // because we don't have valid kv pair. + while (!loc.eof()) { + const auto c = loc.current(); + if (c == ',' || c == '\n' || c == '}') { + comma_found = (c == ','); + break; + } + loc.advance(); + } + continue; + } + + // if comment line follows immediately(without newline) after `,`, then + // the comment is for the elem. we need to check if comment follows `,`. + // + // (key) = (val) (ws|newline|comment-line)? `,` (ws)? (comment)? + + if (spec.v1_1_0_allow_newlines_in_inline_tables) { + if (spacer.has_value()) // copy previous comments to value + { + for (std::size_t i = 0; i < spacer.value().comments.size(); ++i) { + ins_res.unwrap()->comments().push_back( + spacer.value().comments.at(i)); + } + } + spacer = skip_multiline_spacer(loc, ctx); + if (spacer.has_value()) { + for (std::size_t i = 0; i < spacer.value().comments.size(); ++i) { + ins_res.unwrap()->comments().push_back( + spacer.value().comments.at(i)); + } + if (spacer.value().newline_found) { + fmt.fmt = table_format::multiline_oneline; + if (spacer.value().indent_type != indent_char::none) { + fmt.indent_type = spacer.value().indent_type; + fmt.body_indent = spacer.value().indent; + } + } + } + } else { + skip_whitespace(loc, ctx); + } + + comma_found = character(',').scan(loc).is_ok(); + + if (spec.v1_1_0_allow_newlines_in_inline_tables) { + auto com_res = parse_comment_line(loc, ctx); + if (com_res.is_err()) { + ctx.report_error(com_res.unwrap_err()); + } + const bool comment_found = com_res.is_ok() && + com_res.unwrap().has_value(); + if (comment_found) { + fmt.fmt = table_format::multiline_oneline; + ins_res.unwrap()->comments().push_back(com_res.unwrap().value()); + } + if (comma_found) { + spacer = skip_multiline_spacer(loc, ctx, comment_found); + if (spacer.has_value() && spacer.value().newline_found) { + fmt.fmt = table_format::multiline_oneline; + } + } + } else { + skip_whitespace(loc, ctx); + } + } else { + ctx.report_error(std::move(kv_res.unwrap_err())); + while (!loc.eof()) { + if (loc.current() == '}') { + break; + } + if (!spec.v1_1_0_allow_newlines_in_inline_tables && + loc.current() == '\n') { + break; + } + loc.advance(); + } + break; + } + } + + if (loc.current() != '}') { + auto src = source_location(region(loc)); + return err(make_error_info("toml::parse_inline_table: " + "missing closing bracket `}`", + std::move(src), + "expected `}`, reached line end")); + } else { + loc.advance(); // skip } + } + + // any error reported from this function + if (num_errors < ctx.errors().size()) { + assert(ctx.has_error()); // already reported + return err(ctx.pop_last_error()); + } + + basic_value retval(std::move(table), std::move(fmt), {}, region(first, loc)); + + return ok(std::move(retval)); + } + + /* ============================================================================ + * _ + * __ ____ _| |_ _ ___ + * \ V / _` | | || / -_) + * \_/\__,_|_|\_,_\___| + */ + + template + result guess_number_type(const location& first, + const context& ctx) { + const auto& spec = ctx.toml_spec(); + location loc = first; + + if (syntax::offset_datetime(spec).scan(loc).is_ok()) { + return ok(value_t::offset_datetime); + } + loc = first; + + if (syntax::local_datetime(spec).scan(loc).is_ok()) { + const auto curr = loc.current(); + // if offset_datetime contains bad offset, it syntax::offset_datetime + // fails to scan it. + if (curr == '+' || curr == '-') { + return err( + make_syntax_error("bad offset: must be [+-]HH:MM or Z", + syntax::time_offset(spec), + loc, + std::string("Hint: valid : +09:00, -05:30\n" + "Hint: invalid: +9:00, -5:30\n"))); + } + return ok(value_t::local_datetime); + } + loc = first; + + if (syntax::local_date(spec).scan(loc).is_ok()) { + // bad time may appear after this. + + if (!loc.eof()) { + const auto c = loc.current(); + if (c == 'T' || c == 't') { + loc.advance(); + + return err(make_syntax_error( + "bad time: must be HH:MM:SS.subsec", + syntax::local_time(spec), + loc, + std::string( + "Hint: valid : 1979-05-27T07:32:00, 1979-05-27 " + "07:32:00.999999\n" + "Hint: invalid: 1979-05-27T7:32:00, 1979-05-27 17:32\n"))); + } + if (c == ' ') { + // A space is allowed as a delimiter between local time. + // But there is a case where bad time follows a space. + // - invalid: 2019-06-16 7:00:00 + // - valid : 2019-06-16 07:00:00 + loc.advance(); + if (!loc.eof() && ('0' <= loc.current() && loc.current() <= '9')) { + return err(make_syntax_error( + "bad time: must be HH:MM:SS.subsec", + syntax::local_time(spec), + loc, + std::string( + "Hint: valid : 1979-05-27T07:32:00, 1979-05-27 " + "07:32:00.999999\n" + "Hint: invalid: 1979-05-27T7:32:00, 1979-05-27 17:32\n"))); + } + } + if ('0' <= c && c <= '9') { + return err(make_syntax_error( + "bad datetime: missing T or space", + character_either { 'T', 't', ' ' }, + loc, + std::string( + "Hint: valid : 1979-05-27T07:32:00, 1979-05-27 " + "07:32:00.999999\n" + "Hint: invalid: 1979-05-27T7:32:00, 1979-05-27 17:32\n"))); + } + } + return ok(value_t::local_date); + } + loc = first; + + if (syntax::local_time(spec).scan(loc).is_ok()) { + return ok(value_t::local_time); + } + loc = first; + + if (syntax::floating(spec).scan(loc).is_ok()) { + if (!loc.eof() && loc.current() == '_') { + if (spec.ext_num_suffix && syntax::num_suffix(spec).scan(loc).is_ok()) { + return ok(value_t::floating); + } + auto src = source_location(region(loc)); + return err(make_error_info( + "bad float: `_` must be surrounded by digits", + std::move(src), + "invalid underscore", + "Hint: valid : +1.0, -2e-2, 3.141_592_653_589, inf, nan\n" + "Hint: invalid: .0, 1., _1.0, 1.0_, 1_.0, 1.0__0\n")); + } + return ok(value_t::floating); + } + loc = first; + + if (spec.ext_hex_float) { + if (syntax::hex_floating(spec).scan(loc).is_ok()) { + if (!loc.eof() && loc.current() == '_') { + if (spec.ext_num_suffix && syntax::num_suffix(spec).scan(loc).is_ok()) { + return ok(value_t::floating); + } + auto src = source_location(region(loc)); + return err(make_error_info( + "bad float: `_` must be surrounded by digits", + std::move(src), + "invalid underscore", + "Hint: valid : +1.0, -2e-2, 3.141_592_653_589, inf, nan\n" + "Hint: invalid: .0, 1., _1.0, 1.0_, 1_.0, 1.0__0\n")); + } + return ok(value_t::floating); + } + loc = first; + } + + if (auto int_reg = syntax::integer(spec).scan(loc)) { + if (!loc.eof()) { + const auto c = loc.current(); + if (c == '_') { + if (spec.ext_num_suffix && syntax::num_suffix(spec).scan(loc).is_ok()) { + return ok(value_t::integer); + } + + if (int_reg.length() <= 2 && + (int_reg.as_string() == "0" || int_reg.as_string() == "-0" || + int_reg.as_string() == "+0")) { + auto src = source_location(region(loc)); + return err(make_error_info( + "bad integer: leading zero is not allowed in decimal int", + std::move(src), + "leading zero", + "Hint: valid : -42, 1_000, 1_2_3_4_5, 0xC0FFEE, 0b0010, " + "0o755\n" + "Hint: invalid: _42, 1__000, 0123\n")); + } else { + auto src = source_location(region(loc)); + return err( + make_error_info("bad integer: `_` must be surrounded by digits", + std::move(src), + "invalid underscore", + "Hint: valid : -42, 1_000, 1_2_3_4_5, " + "0xC0FFEE, 0b0010, 0o755\n" + "Hint: invalid: _42, 1__000, 0123\n")); + } + } + if ('0' <= c && c <= '9') { + if (loc.current() == '0') { + loc.retrace(); + return err(make_error_info( + "bad integer: leading zero", + source_location(region(loc)), + "leading zero is not allowed", + std::string("Hint: valid : -42, 1_000, 1_2_3_4_5, 0xC0FFEE, " + "0b0010, 0o755\n" + "Hint: invalid: _42, 1__000, 0123\n"))); + } else // invalid digits, especially in oct/bin ints. + { + return err(make_error_info( + "bad integer: invalid digit after an integer", + source_location(region(loc)), + "this digit is not allowed", + std::string("Hint: valid : -42, 1_000, 1_2_3_4_5, 0xC0FFEE, " + "0b0010, 0o755\n" + "Hint: invalid: _42, 1__000, 0123\n"))); + } + } + if (c == ':' || c == '-') { + auto src = source_location(region(loc)); + return err(make_error_info( + "bad datetime: invalid format", + std::move(src), + "here", + std::string("Hint: valid : 1979-05-27T07:32:00-07:00, " + "1979-05-27 07:32:00.999999Z\n" + "Hint: invalid: 1979-05-27T7:32:00-7:00, 1979-05-27 " + "7:32-00:30"))); + } + if (c == '.' || c == 'e' || c == 'E') { + auto src = source_location(region(loc)); + return err(make_error_info( + "bad float: invalid format", + std::move(src), + "here", + std::string( + "Hint: valid : +1.0, -2e-2, 3.141_592_653_589, inf, nan\n" + "Hint: invalid: .0, 1., _1.0, 1.0_, 1_.0, 1.0__0\n"))); + } + } + return ok(value_t::integer); + } + if (!loc.eof() && loc.current() == '.') { + auto src = source_location(region(loc)); + return err(make_error_info( + "bad float: integer part is required before decimal point", + std::move(src), + "missing integer part", + std::string( + "Hint: valid : +1.0, -2e-2, 3.141_592_653_589, inf, nan\n" + "Hint: invalid: .0, 1., _1.0, 1.0_, 1_.0, 1.0__0\n"))); + } + if (!loc.eof() && loc.current() == '_') { + auto src = source_location(region(loc)); + return err(make_error_info( + "bad number: `_` must be surrounded by digits", + std::move(src), + "digits required before `_`", + std::string( + "Hint: valid : -42, 1_000, 1_2_3_4_5, 0xC0FFEE, 0b0010, 0o755\n" + "Hint: invalid: _42, 1__000, 0123\n"))); + } + + auto src = source_location(region(loc)); + return err(make_error_info("bad format: unknown value appeared", + std::move(src), + "here")); + } + + template + result guess_value_type(const location& loc, + const context& ctx) { + const auto& sp = ctx.toml_spec(); + location inner(loc); + + switch (loc.current()) { + case '"': { + return ok(value_t::string); + } + case '\'': { + return ok(value_t::string); + } + case '[': { + return ok(value_t::array); + } + case '{': { + return ok(value_t::table); + } + case 't': { + return ok(value_t::boolean); + } + case 'f': { + return ok(value_t::boolean); + } + case 'T': // invalid boolean. + { + return err(make_syntax_error("toml::parse_value: " + "`true` must be in lowercase. " + "A string must be surrounded by quotes.", + syntax::boolean(sp), + inner)); + } + case 'F': { + return err(make_syntax_error("toml::parse_value: " + "`false` must be in lowercase. " + "A string must be surrounded by quotes.", + syntax::boolean(sp), + inner)); + } + case 'i': // inf or string without quotes(syntax error). + { + if (literal("inf").scan(inner).is_ok()) { + return ok(value_t::floating); + } else { + return err( + make_syntax_error("toml::parse_value: " + "`inf` must be in lowercase. " + "A string must be surrounded by quotes.", + syntax::floating(sp), + inner)); + } + } + case 'I': // Inf or string without quotes(syntax error). + { + return err(make_syntax_error("toml::parse_value: " + "`inf` must be in lowercase. " + "A string must be surrounded by quotes.", + syntax::floating(sp), + inner)); + } + case 'n': // nan or null-extension + { + if (sp.ext_null_value) { + if (literal("nan").scan(inner).is_ok()) { + return ok(value_t::floating); + } else if (literal("null").scan(inner).is_ok()) { + return ok(value_t::empty); + } else { + return err( + make_syntax_error("toml::parse_value: " + "Both `nan` and `null` must be in lowercase. " + "A string must be surrounded by quotes.", + syntax::floating(sp), + inner)); + } + } else // must be nan. + { + if (literal("nan").scan(inner).is_ok()) { + return ok(value_t::floating); + } else { + return err( + make_syntax_error("toml::parse_value: " + "`nan` must be in lowercase. " + "A string must be surrounded by quotes.", + syntax::floating(sp), + inner)); + } + } + } + case 'N': // nan or null-extension + { + if (sp.ext_null_value) { + return err( + make_syntax_error("toml::parse_value: " + "Both `nan` and `null` must be in lowercase. " + "A string must be surrounded by quotes.", + syntax::floating(sp), + inner)); + } else { + return err( + make_syntax_error("toml::parse_value: " + "`nan` must be in lowercase. " + "A string must be surrounded by quotes.", + syntax::floating(sp), + inner)); + } + } + default: { + return guess_number_type(loc, ctx); + } + } + } + + template + result, error_info> parse_value(location& loc, + context& ctx) { + const auto ty_res = guess_value_type(loc, ctx); + if (ty_res.is_err()) { + return err(ty_res.unwrap_err()); + } + + switch (ty_res.unwrap()) { + case value_t::empty: { + if (ctx.toml_spec().ext_null_value) { + return parse_null(loc, ctx); + } else { + auto src = source_location(region(loc)); + return err( + make_error_info("toml::parse_value: unknown value appeared", + std::move(src), + "here")); + } + } + case value_t::boolean: { + return parse_boolean(loc, ctx); + } + case value_t::integer: { + return parse_integer(loc, ctx); + } + case value_t::floating: { + return parse_floating(loc, ctx); + } + case value_t::string: { + return parse_string(loc, ctx); + } + case value_t::offset_datetime: { + return parse_offset_datetime(loc, ctx); + } + case value_t::local_datetime: { + return parse_local_datetime(loc, ctx); + } + case value_t::local_date: { + return parse_local_date(loc, ctx); + } + case value_t::local_time: { + return parse_local_time(loc, ctx); + } + case value_t::array: { + return parse_array(loc, ctx); + } + case value_t::table: { + return parse_inline_table(loc, ctx); + } + default: { + auto src = source_location(region(loc)); + return err( + make_error_info("toml::parse_value: unknown value appeared", + std::move(src), + "here")); + } + } + } + + /* ============================================================================ + * _____ _ _ + * |_ _|_ _| |__| |___ + * | |/ _` | '_ \ / -_) + * |_|\__,_|_.__/_\___| + */ + + template + result::key_type>, region>, error_info> + parse_table_key(location& loc, context& ctx) { + const auto first = loc; + const auto& spec = ctx.toml_spec(); + + auto reg = syntax::std_table(spec).scan(loc); + if (!reg.is_ok()) { + return err(make_syntax_error("toml::parse_table_key: invalid table key", + syntax::std_table(spec), + loc)); + } + + loc = first; + loc.advance(); // skip [ + skip_whitespace(loc, ctx); + + auto keys_res = parse_key(loc, ctx); + if (keys_res.is_err()) { + return err(std::move(keys_res.unwrap_err())); + } + + skip_whitespace(loc, ctx); + loc.advance(); // ] + + return ok(std::make_pair(std::move(keys_res.unwrap().first), std::move(reg))); + } + + template + result::key_type>, region>, error_info> + parse_array_table_key(location& loc, context& ctx) { + const auto first = loc; + const auto& spec = ctx.toml_spec(); + + auto reg = syntax::array_table(spec).scan(loc); + if (!reg.is_ok()) { + return err(make_syntax_error( + "toml::parse_array_table_key: invalid array-of-tables key", + syntax::array_table(spec), + loc)); + } + + loc = first; + loc.advance(); // [ + loc.advance(); // [ + skip_whitespace(loc, ctx); + + auto keys_res = parse_key(loc, ctx); + if (keys_res.is_err()) { + return err(std::move(keys_res.unwrap_err())); + } + + skip_whitespace(loc, ctx); + loc.advance(); // ] + loc.advance(); // ] + + return ok(std::make_pair(std::move(keys_res.unwrap().first), std::move(reg))); + } + + // called after reading [table.keys] and comments around it. + // Since table may already contain a subtable ([x.y.z] can be defined before + // [x]), the table that is being parsed is passed as an argument. + template + result parse_table(location& loc, + context& ctx, + basic_value& table) { + assert(table.is_table()); + + const auto num_errors = ctx.errors().size(); + const auto& spec = ctx.toml_spec(); + + // clear indent info + table.as_table_fmt().indent_type = indent_char::none; + + bool newline_found = true; + while (!loc.eof()) { + const auto start = loc; + + auto sp = skip_multiline_spacer(loc, ctx, newline_found); + + // if reached to EOF, the table ends here. return. + if (loc.eof()) { + break; + } + // if next table is comming, return. + if (sequence(syntax::ws(spec), character('[')).scan(loc).is_ok()) { + loc = start; + break; + } + // otherwise, it should be a key-value pair. + newline_found = newline_found || + (sp.has_value() && sp.value().newline_found); + if (!newline_found) { + return err(make_error_info("toml::parse_table: " + "newline (LF / CRLF) or EOF is expected", + source_location(region(loc)), + "here")); + } + if (sp.has_value() && sp.value().indent_type != indent_char::none) { + table.as_table_fmt().indent_type = sp.value().indent_type; + table.as_table_fmt().body_indent = sp.value().indent; + } + + newline_found = false; // reset + if (auto kv_res = parse_key_value_pair(loc, ctx)) { + auto keys = std::move(kv_res.unwrap().first.first); + auto key_reg = std::move(kv_res.unwrap().first.second); + auto val = std::move(kv_res.unwrap().second); + + if (sp.has_value()) { + for (const auto& com : sp.value().comments) { + val.comments().push_back(com); + } + } + + if (auto com_res = parse_comment_line(loc, ctx)) { + if (auto com_opt = com_res.unwrap()) { + val.comments().push_back(com_opt.value()); + newline_found = true; // comment includes newline at the end + } + } else { + ctx.report_error(std::move(com_res.unwrap_err())); + } + + auto ins_res = insert_value(inserting_value_kind::dotted_keys, + std::addressof(table.as_table()), + keys, + std::move(key_reg), + std::move(val)); + if (ins_res.is_err()) { + ctx.report_error(std::move(ins_res.unwrap_err())); + } + } else { + ctx.report_error(std::move(kv_res.unwrap_err())); + skip_key_value_pair(loc, ctx); + } + } + + if (num_errors < ctx.errors().size()) { + assert(ctx.has_error()); // already reported + return err(ctx.pop_last_error()); + } + return ok(); + } + + template + result, std::vector> parse_file(location& loc, + context& ctx) { + using value_type = basic_value; + using table_type = typename value_type::table_type; + + const auto first = loc; + const auto& spec = ctx.toml_spec(); + + if (loc.eof()) { + return ok(value_type(table_type(), table_format_info {}, {}, region(loc))); + } + + value_type root(table_type(), table_format_info {}, {}, region(loc)); + root.as_table_fmt().fmt = table_format::multiline; + root.as_table_fmt().indent_type = indent_char::none; + + // parse top comment. + // + // ```toml + // # this is a comment for the top-level table. + // + // key = "the first value" + // ``` + // + // ```toml + // # this is a comment for "the first value". + // key = "the first value" + // ``` + while (!loc.eof()) { + if (auto com_res = parse_comment_line(loc, ctx)) { + if (auto com_opt = com_res.unwrap()) { + root.comments().push_back(std::move(com_opt.value())); + } else // no comment found. + { + // if it is not an empty line, clear the root comment. + if (!sequence(syntax::ws(spec), syntax::newline(spec)).scan(loc).is_ok()) { + loc = first; + root.comments().clear(); + } + break; + } + } else { + ctx.report_error(std::move(com_res.unwrap_err())); + skip_comment_block(loc, ctx); + } + } + + // parse root table + { + const auto res = parse_table(loc, ctx, root); + if (res.is_err()) { + ctx.report_error(std::move(res.unwrap_err())); + skip_until_next_table(loc, ctx); + } + } + + // parse tables + + while (!loc.eof()) { + auto sp = skip_multiline_spacer(loc, ctx, /*newline_found=*/true); + + if (auto key_res = parse_array_table_key(loc, ctx)) { + auto key = std::move(std::get<0>(key_res.unwrap())); + auto reg = std::move(std::get<1>(key_res.unwrap())); + + std::vector com; + if (sp.has_value()) { + for (std::size_t i = 0; i < sp.value().comments.size(); ++i) { + com.push_back(std::move(sp.value().comments.at(i))); + } + } + + // [table.def] must be followed by one of + // - a comment line + // - whitespace + newline + // - EOF + if (auto com_res = parse_comment_line(loc, ctx)) { + if (auto com_opt = com_res.unwrap()) { + com.push_back(com_opt.value()); + } else // if there is no comment, ws+newline must exist (or EOF) + { + skip_whitespace(loc, ctx); + if (!loc.eof() && + !syntax::newline(ctx.toml_spec()).scan(loc).is_ok()) { + ctx.report_error(make_syntax_error("toml::parse_file: " + "newline (or EOF) expected", + syntax::newline(ctx.toml_spec()), + loc)); + skip_until_next_table(loc, ctx); + continue; + } + } + } else // comment syntax error (rare) + { + ctx.report_error(com_res.unwrap_err()); + skip_until_next_table(loc, ctx); + continue; + } + + table_format_info fmt; + fmt.fmt = table_format::multiline; + fmt.indent_type = indent_char::none; + auto tab = value_type(table_type {}, std::move(fmt), std::move(com), reg); + + auto inserted = insert_value(inserting_value_kind::array_table, + std::addressof(root.as_table()), + key, + std::move(reg), + std::move(tab)); + + if (inserted.is_err()) { + ctx.report_error(inserted.unwrap_err()); + + // check errors in the table + auto tmp = basic_value(table_type()); + auto res = parse_table(loc, ctx, tmp); + if (res.is_err()) { + ctx.report_error(res.unwrap_err()); + skip_until_next_table(loc, ctx); + } + continue; + } + + auto tab_ptr = inserted.unwrap(); + assert(tab_ptr); + + const auto tab_res = parse_table(loc, ctx, *tab_ptr); + if (tab_res.is_err()) { + ctx.report_error(tab_res.unwrap_err()); + skip_until_next_table(loc, ctx); + } + + // parse_table first clears `indent_type`. + // to keep header indent info, we must store it later. + if (sp.has_value() && sp.value().indent_type != indent_char::none) { + tab_ptr->as_table_fmt().indent_type = sp.value().indent_type; + tab_ptr->as_table_fmt().name_indent = sp.value().indent; + } + continue; + } + if (auto key_res = parse_table_key(loc, ctx)) { + auto key = std::move(std::get<0>(key_res.unwrap())); + auto reg = std::move(std::get<1>(key_res.unwrap())); + + std::vector com; + if (sp.has_value()) { + for (std::size_t i = 0; i < sp.value().comments.size(); ++i) { + com.push_back(std::move(sp.value().comments.at(i))); + } + } + + // [table.def] must be followed by one of + // - a comment line + // - whitespace + newline + // - EOF + if (auto com_res = parse_comment_line(loc, ctx)) { + if (auto com_opt = com_res.unwrap()) { + com.push_back(com_opt.value()); + } else // if there is no comment, ws+newline must exist (or EOF) + { + skip_whitespace(loc, ctx); + if (!loc.eof() && + !syntax::newline(ctx.toml_spec()).scan(loc).is_ok()) { + ctx.report_error(make_syntax_error("toml::parse_file: " + "newline (or EOF) expected", + syntax::newline(ctx.toml_spec()), + loc)); + skip_until_next_table(loc, ctx); + continue; + } + } + } else // comment syntax error (rare) + { + ctx.report_error(com_res.unwrap_err()); + skip_until_next_table(loc, ctx); + continue; + } + + table_format_info fmt; + fmt.fmt = table_format::multiline; + fmt.indent_type = indent_char::none; + auto tab = value_type(table_type {}, std::move(fmt), std::move(com), reg); + + auto inserted = insert_value(inserting_value_kind::std_table, + std::addressof(root.as_table()), + key, + std::move(reg), + std::move(tab)); + + if (inserted.is_err()) { + ctx.report_error(inserted.unwrap_err()); + + // check errors in the table + auto tmp = basic_value(table_type()); + auto res = parse_table(loc, ctx, tmp); + if (res.is_err()) { + ctx.report_error(res.unwrap_err()); + skip_until_next_table(loc, ctx); + } + continue; + } + + auto tab_ptr = inserted.unwrap(); + assert(tab_ptr); + + const auto tab_res = parse_table(loc, ctx, *tab_ptr); + if (tab_res.is_err()) { + ctx.report_error(tab_res.unwrap_err()); + skip_until_next_table(loc, ctx); + } + if (sp.has_value() && sp.value().indent_type != indent_char::none) { + tab_ptr->as_table_fmt().indent_type = sp.value().indent_type; + tab_ptr->as_table_fmt().name_indent = sp.value().indent; + } + continue; + } + + // does not match array_table nor std_table. report an error. + const auto keytop = loc; + const auto maybe_array_of_tables = literal("[[").scan(loc).is_ok(); + loc = keytop; + + if (maybe_array_of_tables) { + ctx.report_error( + make_syntax_error("toml::parse_file: invalid array-table key", + syntax::array_table(spec), + loc)); + } else { + ctx.report_error( + make_syntax_error("toml::parse_file: invalid table key", + syntax::std_table(spec), + loc)); + } + skip_until_next_table(loc, ctx); + } + + if (!ctx.errors().empty()) { + return err(std::move(ctx.errors())); + } + return ok(std::move(root)); + } + + template + result, std::vector> parse_impl( + std::vector cs, + std::string fname, + const spec& s) { + using value_type = basic_value; + using table_type = typename value_type::table_type; + + // an empty file is a valid toml file. + if (cs.empty()) { + auto src = std::make_shared>( + std::move(cs)); + location loc(std::move(src), std::move(fname)); + return ok(value_type(table_type(), + table_format_info {}, + std::vector {}, + region(loc))); + } + + // to simplify parser, add newline at the end if there is no LF. + // But, if it has raw CR, the file is invalid (in TOML, CR is not a valid + // newline char). if it ends with CR, do not add LF and report it. + if (cs.back() != '\n' && cs.back() != '\r') { + cs.push_back('\n'); + } + + auto src = std::make_shared>(std::move(cs)); + + location loc(std::move(src), std::move(fname)); + + // skip BOM if found + if (loc.source()->size() >= 3) { + auto first = loc.get_location(); + + const auto c0 = loc.current(); + loc.advance(); + const auto c1 = loc.current(); + loc.advance(); + const auto c2 = loc.current(); + loc.advance(); + + const auto bom_found = (c0 == 0xEF) && (c1 == 0xBB) && (c2 == 0xBF); + if (!bom_found) { + loc.set_location(first); + } + } + + context ctx(s); + + return parse_file(loc, ctx); + } + + } // namespace detail + + // ----------------------------------------------------------------------------- + // parse(byte array) + + template + result, std::vector> try_parse( + std::vector content, + std::string filename, + spec s = spec::default_version()) { + return detail::parse_impl(std::move(content), + std::move(filename), + std::move(s)); + } + + template + basic_value parse(std::vector content, + std::string filename, + spec s = spec::default_version()) { + auto res = try_parse(std::move(content), std::move(filename), std::move(s)); + if (res.is_ok()) { + return res.unwrap(); + } else { + std::string msg; + for (const auto& err : res.unwrap_err()) { + msg += format_error(err); + } + throw syntax_error(std::move(msg), std::move(res.unwrap_err())); + } + } + + // ----------------------------------------------------------------------------- + // parse(istream) + + template + result, std::vector> try_parse( + std::istream& is, + std::string fname = "unknown file", + spec s = spec::default_version()) { + const auto beg = is.tellg(); + is.seekg(0, std::ios::end); + const auto end = is.tellg(); + const auto fsize = end - beg; + is.seekg(beg); + + // read whole file as a sequence of char + assert(fsize >= 0); + std::vector letters(static_cast(fsize), + '\0'); + is.read(reinterpret_cast(letters.data()), + static_cast(fsize)); + + return detail::parse_impl(std::move(letters), + std::move(fname), + std::move(s)); + } + + template + basic_value parse(std::istream& is, + std::string fname = "unknown file", + spec s = spec::default_version()) { + auto res = try_parse(is, std::move(fname), std::move(s)); + if (res.is_ok()) { + return res.unwrap(); + } else { + std::string msg; + for (const auto& err : res.unwrap_err()) { + msg += format_error(err); + } + throw syntax_error(std::move(msg), std::move(res.unwrap_err())); + } + } + + // ----------------------------------------------------------------------------- + // parse(filename) + + template + result, std::vector> try_parse( + std::string fname, + spec s = spec::default_version()) { + std::ifstream ifs(fname, std::ios_base::binary); + if (!ifs.good()) { + std::vector e; + e.push_back( + error_info("toml::parse: Error opening file \"" + fname + "\"", {})); + return err(std::move(e)); + } + ifs.exceptions(std::ifstream::failbit | std::ifstream::badbit); + + return try_parse(ifs, std::move(fname), std::move(s)); + } + + template + basic_value parse(std::string fname, spec s = spec::default_version()) { + std::ifstream ifs(fname, std::ios_base::binary); + if (!ifs.good()) { + throw file_io_error("toml::parse: error opening file", fname); + } + ifs.exceptions(std::ifstream::failbit | std::ifstream::badbit); + + return parse(ifs, std::move(fname), std::move(s)); + } + + template + result, std::vector> try_parse( + const char (&fname)[N], + spec s = spec::default_version()) { + return try_parse(std::string(fname), std::move(s)); + } + + template + basic_value parse(const char (&fname)[N], spec s = spec::default_version()) { + return parse(std::string(fname), std::move(s)); + } + + // ---------------------------------------------------------------------------- + // parse_str + + template + result, std::vector> try_parse_str( + std::string content, + spec s = spec::default_version(), + cxx::source_location loc = cxx::source_location::current()) { + std::istringstream iss(std::move(content)); + std::string name("internal string" + cxx::to_string(loc)); + return try_parse(iss, std::move(name), std::move(s)); + } + + template + basic_value parse_str( + std::string content, + spec s = spec::default_version(), + cxx::source_location loc = cxx::source_location::current()) { + auto res = try_parse_str(std::move(content), std::move(s), std::move(loc)); + if (res.is_ok()) { + return res.unwrap(); + } else { + std::string msg; + for (const auto& err : res.unwrap_err()) { + msg += format_error(err); + } + throw syntax_error(std::move(msg), std::move(res.unwrap_err())); + } + } + + // ---------------------------------------------------------------------------- + // filesystem + +#if defined(TOML11_HAS_FILESYSTEM) + + template + cxx::enable_if_t::value, + result, std::vector>> + try_parse(const FSPATH& fpath, spec s = spec::default_version()) { + std::ifstream ifs(fpath, std::ios_base::binary); + if (!ifs.good()) { + std::vector e; + e.push_back( + error_info("toml::parse: Error opening file \"" + fpath.string() + "\"", + {})); + return err(std::move(e)); + } + ifs.exceptions(std::ifstream::failbit | std::ifstream::badbit); + + return try_parse(ifs, fpath.string(), std::move(s)); + } + + template + cxx::enable_if_t::value, basic_value> + parse(const FSPATH& fpath, spec s = spec::default_version()) { + std::ifstream ifs(fpath, std::ios_base::binary); + if (!ifs.good()) { + throw file_io_error("toml::parse: error opening file", fpath.string()); + } + ifs.exceptions(std::ifstream::failbit | std::ifstream::badbit); + + return parse(ifs, fpath.string(), std::move(s)); + } +#endif + + // ----------------------------------------------------------------------------- + // FILE* + + template + result, std::vector> try_parse( + FILE* fp, + std::string filename, + spec s = spec::default_version()) { + const long beg = std::ftell(fp); + if (beg == -1L) { + return err(std::vector { + error_info(std::string("Failed to access: \"") + filename + + "\", errno = " + std::to_string(errno), + {}) }); + } + + const int res_seekend = std::fseek(fp, 0, SEEK_END); + if (res_seekend != 0) { + return err(std::vector { + error_info(std::string("Failed to seek: \"") + filename + + "\", errno = " + std::to_string(errno), + {}) }); + } + + const long end = std::ftell(fp); + if (end == -1L) { + return err(std::vector { + error_info(std::string("Failed to access: \"") + filename + + "\", errno = " + std::to_string(errno), + {}) }); + } + + const auto fsize = end - beg; + + const auto res_seekbeg = std::fseek(fp, beg, SEEK_SET); + if (res_seekbeg != 0) { + return err(std::vector { + error_info(std::string("Failed to seek: \"") + filename + + "\", errno = " + std::to_string(errno), + {}) }); + } + + // read whole file as a sequence of char + assert(fsize >= 0); + std::vector letters( + static_cast(fsize)); + const auto actual = std::fread(letters.data(), + sizeof(char), + static_cast(fsize), + fp); + if (actual != static_cast(fsize)) { + return err(std::vector { + error_info(std::string("File size changed: \"") + filename + + std::string("\" make sure that FILE* is in binary mode " + "to avoid LF <-> CRLF conversion"), + {}) }); + } + + return detail::parse_impl(std::move(letters), + std::move(filename), + std::move(s)); + } + + template + basic_value parse(FILE* fp, + std::string filename, + spec s = spec::default_version()) { + const long beg = std::ftell(fp); + if (beg == -1L) { + throw file_io_error(errno, "Failed to access", filename); + } + + const int res_seekend = std::fseek(fp, 0, SEEK_END); + if (res_seekend != 0) { + throw file_io_error(errno, "Failed to seek", filename); + } + + const long end = std::ftell(fp); + if (end == -1L) { + throw file_io_error(errno, "Failed to access", filename); + } + + const auto fsize = end - beg; + + const auto res_seekbeg = std::fseek(fp, beg, SEEK_SET); + if (res_seekbeg != 0) { + throw file_io_error(errno, "Failed to seek", filename); + } + + // read whole file as a sequence of char + assert(fsize >= 0); + std::vector letters( + static_cast(fsize)); + const auto actual = std::fread(letters.data(), + sizeof(char), + static_cast(fsize), + fp); + if (actual != static_cast(fsize)) { + throw file_io_error( + errno, + "File size changed; make sure that " + "FILE* is in binary mode to avoid LF <-> CRLF conversion", + filename); + } + + auto res = detail::parse_impl(std::move(letters), + std::move(filename), + std::move(s)); + if (res.is_ok()) { + return res.unwrap(); + } else { + std::string msg; + for (const auto& err : res.unwrap_err()) { + msg += format_error(err); + } + throw syntax_error(std::move(msg), std::move(res.unwrap_err())); + } + } + +} // namespace toml + +#if defined(TOML11_COMPILE_SOURCES) +namespace toml { + struct type_config; + struct ordered_type_config; + + extern template result, std::vector> + try_parse(std::vector, std::string, spec); + extern template result, std::vector> + try_parse(std::istream&, std::string, spec); + extern template result, std::vector> + try_parse(std::string, spec); + extern template result, std::vector> + try_parse(FILE*, std::string, spec); + extern template result, std::vector> + try_parse_str(std::string, spec, cxx::source_location); + + extern template basic_value parse( + std::vector, + std::string, + spec); + extern template basic_value parse(std::istream&, + std::string, + spec); + extern template basic_value parse(std::string, spec); + extern template basic_value parse(FILE*, + std::string, + spec); + extern template basic_value parse_str( + std::string, + spec, + cxx::source_location); + + extern template result, std::vector> + try_parse(std::vector, std::string, spec); + extern template result, std::vector> + try_parse(std::istream&, std::string, spec); + extern template result, std::vector> + try_parse(std::string, spec); + extern template result, std::vector> + try_parse(FILE*, std::string, spec); + extern template result, std::vector> + try_parse_str(std::string, spec, cxx::source_location); + + extern template basic_value parse( + std::vector, + std::string, + spec); + extern template basic_value parse( + std::istream&, + std::string, + spec); + extern template basic_value parse( + std::string, + spec); + extern template basic_value parse( + FILE*, + std::string, + spec); + extern template basic_value parse_str( + std::string, + spec, + cxx::source_location); + + #if defined(TOML11_HAS_FILESYSTEM) + extern template cxx::enable_if_t< + std::is_same::value, + result, std::vector>> + try_parse(const std::filesystem::path&, + spec); + extern template cxx::enable_if_t< + std::is_same::value, + result, std::vector>> + try_parse( + const std::filesystem::path&, + spec); + extern template cxx::enable_if_t< + std::is_same::value, + basic_value> + parse(const std::filesystem::path&, spec); + extern template cxx::enable_if_t< + std::is_same::value, + basic_value> + parse(const std::filesystem::path&, + spec); + #endif // filesystem + +} // namespace toml +#endif // TOML11_COMPILE_SOURCES + +#endif // TOML11_PARSER_HPP +#ifndef TOML11_LITERAL_HPP +#define TOML11_LITERAL_HPP + +#ifndef TOML11_LITERAL_FWD_HPP + #define TOML11_LITERAL_FWD_HPP + +namespace toml { + + namespace detail { + // implementation + ::toml::value literal_internal_impl(location loc); + } // namespace detail + + inline namespace literals { + inline namespace toml_literals { + + ::toml::value operator"" _toml(const char* str, std::size_t len); + + #if defined(TOML11_HAS_CHAR8_T) + // value of u8"" literal has been changed from char to char8_t and char8_t + // is NOT compatible to char + ::toml::value operator"" _toml(const char8_t* str, std::size_t len); + #endif + + } // namespace toml_literals + } // namespace literals +} // namespace toml +#endif // TOML11_LITERAL_FWD_HPP + +#if !defined(TOML11_COMPILE_SOURCES) + #ifndef TOML11_LITERAL_IMPL_HPP + #define TOML11_LITERAL_IMPL_HPP + +namespace toml { + + namespace detail { + // implementation + TOML11_INLINE ::toml::value literal_internal_impl(location loc) { + const auto s = ::toml::spec::default_version(); + context ctx(s); + + const auto front = loc; + + // ------------------------------------------------------------------------ + // check if it is a raw value. + + // skip empty lines and comment lines + auto sp = skip_multiline_spacer(loc, ctx); + if (loc.eof()) { + ::toml::value val; + if (sp.has_value()) { + for (std::size_t i = 0; i < sp.value().comments.size(); ++i) { + val.comments().push_back(std::move(sp.value().comments.at(i))); + } + } + return val; + } + + // to distinguish arrays and tables, first check it is a table or not. + // + // "[1,2,3]"_toml; // json: [1, 2, 3] + // "[table]"_toml; // json: {"table": {}} + // "[[1,2,3]]"_toml; // json: [[1, 2, 3]] + // "[[table]]"_toml; // json: {"table": [{}]} + // + // "[[1]]"_toml; // json: {"1": [{}]} + // "1 = [{}]"_toml; // json: {"1": [{}]} + // "[[1,]]"_toml; // json: [[1]] + // "[[1],]"_toml; // json: [[1]] + const auto val_start = loc; + + const bool is_table_key = syntax::std_table(s).scan(loc).is_ok(); + loc = val_start; + const bool is_aots_key = syntax::array_table(s).scan(loc).is_ok(); + loc = val_start; + + // If it is neither a table-key or a array-of-table-key, it may be a value. + if (!is_table_key && !is_aots_key) { + auto data = parse_value(loc, ctx); + if (data.is_ok()) { + auto val = std::move(data.unwrap()); + if (sp.has_value()) { + for (std::size_t i = 0; i < sp.value().comments.size(); ++i) { + val.comments().push_back(std::move(sp.value().comments.at(i))); + } + } + auto com_res = parse_comment_line(loc, ctx); + if (com_res.is_ok() && com_res.unwrap().has_value()) { + val.comments().push_back(com_res.unwrap().value()); + } + return val; + } + } + + // ------------------------------------------------------------------------- + // Note that still it can be a table, because the literal might be + // something like the following. + // ```cpp + // // c++11 raw-string literal + // const auto val = R"( + // key = "value" + // int = 42 + // )"_toml; + // ``` + // It is a valid toml file. + // It should be parsed as if we parse a file with this content. + + loc = front; + auto data = parse_file(loc, ctx); + if (data.is_ok()) { + return data.unwrap(); + } else // not a value && not a file. error. + { + std::string msg; + for (const auto& err : data.unwrap_err()) { + msg += format_error(err); + } + throw ::toml::syntax_error(std::move(msg), std::move(data.unwrap_err())); + } + } + + } // namespace detail + + inline namespace literals { + inline namespace toml_literals { + + TOML11_INLINE ::toml::value operator"" _toml(const char* str, + std::size_t len) { + if (len == 0) { + return ::toml::value {}; + } + + ::toml::detail::location::container_type c(len); + std::copy( + reinterpret_cast(str), + reinterpret_cast(str + len), + c.begin()); + if (!c.empty() && c.back()) { + c.push_back('\n'); // to make it easy to parse comment, we add newline + } + + return literal_internal_impl(::toml::detail::location( + std::make_shared( + std::move(c)), + "TOML literal encoded in a C++ code")); + } + + #if defined(__cpp_char8_t) + #if __cpp_char8_t >= 201811L + #define TOML11_HAS_CHAR8_T 1 + #endif + #endif + + #if defined(TOML11_HAS_CHAR8_T) + // value of u8"" literal has been changed from char to char8_t and char8_t + // is NOT compatible to char + TOML11_INLINE ::toml::value operator"" _toml(const char8_t* str, + std::size_t len) { + if (len == 0) { + return ::toml::value {}; + } + + ::toml::detail::location::container_type c(len); + std::copy( + reinterpret_cast(str), + reinterpret_cast(str + len), + c.begin()); + if (!c.empty() && c.back()) { + c.push_back('\n'); // to make it easy to parse comment, we add newline + } + + return literal_internal_impl(::toml::detail::location( + std::make_shared( + std::move(c)), + "TOML literal encoded in a C++ code")); + } + #endif + + } // namespace toml_literals + } // namespace literals +} // namespace toml + #endif // TOML11_LITERAL_IMPL_HPP +#endif + +#endif // TOML11_LITERAL_HPP +#ifndef TOML11_SERIALIZER_HPP +#define TOML11_SERIALIZER_HPP + +#include +#include +#include +#include +#include + +namespace toml { + + struct serialization_error final : public ::toml::exception { + public: + explicit serialization_error(std::string what_arg, source_location loc) + : what_(std::move(what_arg)) + , loc_(std::move(loc)) {} + + ~serialization_error() noexcept override = default; + + const char* what() const noexcept override { + return what_.c_str(); + } + + const source_location& location() const noexcept { + return loc_; + } + + private: + std::string what_; + source_location loc_; + }; + + namespace detail { + template + class serializer { + public: + using value_type = basic_value; + + using key_type = typename value_type::key_type; + using comment_type = typename value_type::comment_type; + using boolean_type = typename value_type::boolean_type; + using integer_type = typename value_type::integer_type; + using floating_type = typename value_type::floating_type; + using string_type = typename value_type::string_type; + using local_time_type = typename value_type::local_time_type; + using local_date_type = typename value_type::local_date_type; + using local_datetime_type = typename value_type::local_datetime_type; + using offset_datetime_type = typename value_type::offset_datetime_type; + using array_type = typename value_type::array_type; + using table_type = typename value_type::table_type; + + using char_type = typename string_type::value_type; + + public: + explicit serializer(const spec& sp) + : spec_(sp) + , force_inline_(false) + , current_indent_(0) {} + + string_type operator()(const std::vector& ks, const value_type& v) { + for (const auto& k : ks) { + this->keys_.push_back(k); + } + return (*this)(v); + } + + string_type operator()(const key_type& k, const value_type& v) { + this->keys_.push_back(k); + return (*this)(v); + } + + string_type operator()(const value_type& v) { + switch (v.type()) { + case value_t::boolean: { + return (*this)(v.as_boolean(), v.as_boolean_fmt(), v.location()); + } + case value_t::integer: { + return (*this)(v.as_integer(), v.as_integer_fmt(), v.location()); + } + case value_t::floating: { + return (*this)(v.as_floating(), v.as_floating_fmt(), v.location()); + } + case value_t::string: { + return (*this)(v.as_string(), v.as_string_fmt(), v.location()); + } + case value_t::offset_datetime: { + return (*this)(v.as_offset_datetime(), + v.as_offset_datetime_fmt(), + v.location()); + } + case value_t::local_datetime: { + return (*this)(v.as_local_datetime(), + v.as_local_datetime_fmt(), + v.location()); + } + case value_t::local_date: { + return (*this)(v.as_local_date(), v.as_local_date_fmt(), v.location()); + } + case value_t::local_time: { + return (*this)(v.as_local_time(), v.as_local_time_fmt(), v.location()); + } + case value_t::array: { + return ( + *this)(v.as_array(), v.as_array_fmt(), v.comments(), v.location()); + } + case value_t::table: { + string_type retval; + if (this->keys_.empty()) // it might be the root table. emit comments here. + { + retval += format_comments(v.comments(), v.as_table_fmt().indent_type); + } + if (!retval.empty()) // we have comment. + { + retval += char_type('\n'); + } + + retval += (*this)(v.as_table(), + v.as_table_fmt(), + v.comments(), + v.location()); + return retval; + } + case value_t::empty: { + if (this->spec_.ext_null_value) { + return string_conv("null"); + } + break; + } + default: { + break; + } + } + throw serialization_error( + format_error("[error] toml::serializer: toml::basic_value " + "does not have any valid type.", + v.location(), + "here"), + v.location()); + } + + private: + string_type operator()(const boolean_type& b, + const boolean_format_info&, + const source_location&) // {{{ + { + if (b) { + return string_conv("true"); + } else { + return string_conv("false"); + } + } // }}} + + string_type operator()(const integer_type i, + const integer_format_info& fmt, + const source_location& loc) // {{{ + { + std::ostringstream oss; + this->set_locale(oss); + + const auto insert_spacer = [&fmt](std::string s) -> std::string { + if (fmt.spacer == 0) { + return s; + } + + std::string sign; + if (!s.empty() && (s.at(0) == '+' || s.at(0) == '-')) { + sign += s.at(0); + s.erase(s.begin()); + } + + std::string spaced; + std::size_t counter = 0; + for (auto iter = s.rbegin(); iter != s.rend(); ++iter) { + if (counter != 0 && counter % fmt.spacer == 0) { + spaced += '_'; + } + spaced += *iter; + counter += 1; + } + if (!spaced.empty() && spaced.back() == '_') { + spaced.pop_back(); + } + + s.clear(); + std::copy(spaced.rbegin(), spaced.rend(), std::back_inserter(s)); + return sign + s; + }; + + std::string retval; + if (fmt.fmt == integer_format::dec) { + oss << std::setw(static_cast(fmt.width)) << std::dec << i; + retval = insert_spacer(oss.str()); + + if (this->spec_.ext_num_suffix && !fmt.suffix.empty()) { + retval += '_'; + retval += fmt.suffix; + } + } else { + if (i < 0) { + throw serialization_error( + format_error("binary, octal, hexadecimal " + "integer does not allow negative value", + loc, + "here"), + loc); + } + switch (fmt.fmt) { + case integer_format::hex: { + oss << std::noshowbase << std::setw(static_cast(fmt.width)) + << std::setfill('0') << std::hex; + if (fmt.uppercase) { + oss << std::uppercase; + } else { + oss << std::nouppercase; + } + oss << i; + retval = std::string("0x") + insert_spacer(oss.str()); + break; + } + case integer_format::oct: { + oss << std::setw(static_cast(fmt.width)) << std::setfill('0') + << std::oct << i; + retval = std::string("0o") + insert_spacer(oss.str()); + break; + } + case integer_format::bin: { + integer_type x { i }; + std::string tmp; + std::size_t bits(0); + while (x != 0) { + if (fmt.spacer != 0) { + if (bits != 0 && (bits % fmt.spacer) == 0) { + tmp += '_'; + } + } + if (x % 2 == 1) { + tmp += '1'; + } else { + tmp += '0'; + } + x >>= 1; + bits += 1; + } + for (; bits < fmt.width; ++bits) { + if (fmt.spacer != 0) { + if (bits != 0 && (bits % fmt.spacer) == 0) { + tmp += '_'; + } + } + tmp += '0'; + } + for (auto iter = tmp.rbegin(); iter != tmp.rend(); ++iter) { + oss << *iter; + } + retval = std::string("0b") + oss.str(); + break; + } + default: { + throw serialization_error( + format_error("none of dec, hex, oct, bin: " + to_string(fmt.fmt), + loc, + "here"), + loc); + } + } + } + return string_conv(retval); + } // }}} + + string_type operator()(const floating_type f, + const floating_format_info& fmt, + const source_location&) // {{{ + { + using std::isinf; + using std::isnan; + using std::signbit; + + std::ostringstream oss; + this->set_locale(oss); + + if (isnan(f)) { + if (signbit(f)) { + oss << '-'; + } + oss << "nan"; + if (this->spec_.ext_num_suffix && !fmt.suffix.empty()) { + oss << '_'; + oss << fmt.suffix; + } + return string_conv(oss.str()); + } + + if (isinf(f)) { + if (signbit(f)) { + oss << '-'; + } + oss << "inf"; + if (this->spec_.ext_num_suffix && !fmt.suffix.empty()) { + oss << '_'; + oss << fmt.suffix; + } + return string_conv(oss.str()); + } + + switch (fmt.fmt) { + case floating_format::defaultfloat: { + if (fmt.prec != 0) { + oss << std::setprecision(static_cast(fmt.prec)); + } + oss << f; + // since defaultfloat may omit point, we need to add it + std::string s = oss.str(); + if (s.find('.') == std::string::npos && + s.find('e') == std::string::npos && + s.find('E') == std::string::npos) { + s += ".0"; + } + if (this->spec_.ext_num_suffix && !fmt.suffix.empty()) { + s += '_'; + s += fmt.suffix; + } + return string_conv(s); + } + case floating_format::fixed: { + if (fmt.prec != 0) { + oss << std::setprecision(static_cast(fmt.prec)); + } + oss << std::fixed << f; + if (this->spec_.ext_num_suffix && !fmt.suffix.empty()) { + oss << '_' << fmt.suffix; + } + return string_conv(oss.str()); + } + case floating_format::scientific: { + if (fmt.prec != 0) { + oss << std::setprecision(static_cast(fmt.prec)); + } + oss << std::scientific << f; + if (this->spec_.ext_num_suffix && !fmt.suffix.empty()) { + oss << '_' << fmt.suffix; + } + return string_conv(oss.str()); + } + case floating_format::hex: { + if (this->spec_.ext_hex_float) { + oss << std::hexfloat << f; + // suffix is only for decimal numbers. + return string_conv(oss.str()); + } else // no hex allowed. output with max precision. + { + oss << std::setprecision( + std::numeric_limits::max_digits10) + << std::scientific << f; + // suffix is only for decimal numbers. + return string_conv(oss.str()); + } + } + default: { + if (this->spec_.ext_num_suffix && !fmt.suffix.empty()) { + oss << '_' << fmt.suffix; + } + return string_conv(oss.str()); + } + } + } // }}} + + string_type operator()(string_type s, + const string_format_info& fmt, + const source_location& loc) // {{{ + { + string_type retval; + switch (fmt.fmt) { + case string_format::basic: { + retval += char_type('"'); + retval += this->escape_basic_string(s); + retval += char_type('"'); + return retval; + } + case string_format::literal: { + if (std::find(s.begin(), s.end(), char_type('\n')) != s.end()) { + throw serialization_error( + format_error( + "toml::serializer: " + "(non-multiline) literal string cannot have a newline", + loc, + "here"), + loc); + } + retval += char_type('\''); + retval += s; + retval += char_type('\''); + return retval; + } + case string_format::multiline_basic: { + retval += string_conv("\"\"\""); + if (fmt.start_with_newline) { + retval += char_type('\n'); + } + + retval += this->escape_ml_basic_string(s); + + retval += string_conv("\"\"\""); + return retval; + } + case string_format::multiline_literal: { + retval += string_conv("'''"); + if (fmt.start_with_newline) { + retval += char_type('\n'); + } + retval += s; + retval += string_conv("'''"); + return retval; + } + default: { + throw serialization_error( + format_error("[error] toml::serializer::operator()(string): " + "invalid string_format value", + loc, + "here"), + loc); + } + } + } // }}} + + string_type operator()(const local_date_type& d, + const local_date_format_info&, + const source_location&) // {{{ + { + std::ostringstream oss; + oss << d; + return string_conv(oss.str()); + } // }}} + + string_type operator()(const local_time_type& t, + const local_time_format_info& fmt, + const source_location&) // {{{ + { + return this->format_local_time(t, fmt.has_seconds, fmt.subsecond_precision); + } // }}} + + string_type operator()(const local_datetime_type& dt, + const local_datetime_format_info& fmt, + const source_location&) // {{{ + { + std::ostringstream oss; + oss << dt.date; + switch (fmt.delimiter) { + case datetime_delimiter_kind::upper_T: { + oss << 'T'; + break; + } + case datetime_delimiter_kind::lower_t: { + oss << 't'; + break; + } + case datetime_delimiter_kind::space: { + oss << ' '; + break; + } + default: { + oss << 'T'; + break; + } + } + return string_conv(oss.str()) + + this->format_local_time(dt.time, + fmt.has_seconds, + fmt.subsecond_precision); + } // }}} + + string_type operator()(const offset_datetime_type& odt, + const offset_datetime_format_info& fmt, + const source_location&) // {{{ + { + std::ostringstream oss; + oss << odt.date; + switch (fmt.delimiter) { + case datetime_delimiter_kind::upper_T: { + oss << 'T'; + break; + } + case datetime_delimiter_kind::lower_t: { + oss << 't'; + break; + } + case datetime_delimiter_kind::space: { + oss << ' '; + break; + } + default: { + oss << 'T'; + break; + } + } + oss << string_conv( + this->format_local_time(odt.time, fmt.has_seconds, fmt.subsecond_precision)); + oss << odt.offset; + return string_conv(oss.str()); + } // }}} + + string_type operator()(const array_type& a, + const array_format_info& fmt, + const comment_type& com, + const source_location& loc) // {{{ + { + array_format f = fmt.fmt; + if (fmt.fmt == array_format::default_format) { + // [[in.this.form]], you cannot add a comment to the array itself + // (but you can add a comment to each table). + // To keep comments, we need to avoid multiline array-of-tables + // if array itself has a comment. + if (!this->keys_.empty() && !a.empty() && com.empty() && + std::all_of(a.begin(), a.end(), [](const value_type& e) { + return e.is_table(); + })) { + f = array_format::array_of_tables; + } else { + f = array_format::oneline; + + // check if it becomes long + std::size_t approx_len = 0; + for (const auto& e : a) { + // have a comment. cannot be inlined + if (!e.comments().empty()) { + f = array_format::multiline; + break; + } + // possibly long types ... + if (e.is_array() || e.is_table() || e.is_offset_datetime() || + e.is_local_datetime()) { + f = array_format::multiline; + break; + } else if (e.is_boolean()) { + approx_len += + (*this)(e.as_boolean(), e.as_boolean_fmt(), e.location()).size(); + } else if (e.is_integer()) { + approx_len += + (*this)(e.as_integer(), e.as_integer_fmt(), e.location()).size(); + } else if (e.is_floating()) { + approx_len += + (*this)(e.as_floating(), e.as_floating_fmt(), e.location()).size(); + } else if (e.is_string()) { + if (e.as_string_fmt().fmt == string_format::multiline_basic || + e.as_string_fmt().fmt == string_format::multiline_literal) { + f = array_format::multiline; + break; + } + approx_len += + 2 + + (*this)(e.as_string(), e.as_string_fmt(), e.location()).size(); + } else if (e.is_local_date()) { + approx_len += 10; // 1234-56-78 + } else if (e.is_local_time()) { + approx_len += 15; // 12:34:56.789012 + } + + if (approx_len > 60) // key, ` = `, `[...]` < 80 + { + f = array_format::multiline; + break; + } + approx_len += 2; // `, ` + } + } + } + if (this->force_inline_ && f == array_format::array_of_tables) { + f = array_format::multiline; + } + if (a.empty() && f == array_format::array_of_tables) { + f = array_format::oneline; + } + + // -------------------------------------------------------------------- + + if (f == array_format::array_of_tables) { + if (this->keys_.empty()) { + throw serialization_error("array of table must have its key. " + "use format(key, v)", + loc); + } + string_type retval; + for (const auto& e : a) { + assert(e.is_table()); + + this->current_indent_ += e.as_table_fmt().name_indent; + retval += this->format_comments(e.comments(), + e.as_table_fmt().indent_type); + retval += this->format_indent(e.as_table_fmt().indent_type); + this->current_indent_ -= e.as_table_fmt().name_indent; + + retval += string_conv("[["); + retval += this->format_keys(this->keys_).value(); + retval += string_conv("]]\n"); + + retval += this->format_ml_table(e.as_table(), e.as_table_fmt()); + } + return retval; + } else if (f == array_format::oneline) { + // ignore comments. we cannot emit comments + string_type retval; + retval += char_type('['); + for (const auto& e : a) { + this->force_inline_ = true; + retval += (*this)(e); + retval += string_conv(", "); + } + if (!a.empty()) { + retval.pop_back(); // ` ` + retval.pop_back(); // `,` + } + retval += char_type(']'); + this->force_inline_ = false; + return retval; + } else { + assert(f == array_format::multiline); + + string_type retval; + retval += string_conv("[\n"); + + for (const auto& e : a) { + this->current_indent_ += fmt.body_indent; + retval += this->format_comments(e.comments(), fmt.indent_type); + retval += this->format_indent(fmt.indent_type); + this->current_indent_ -= fmt.body_indent; + + this->force_inline_ = true; + retval += (*this)(e); + retval += string_conv(",\n"); + } + this->force_inline_ = false; + + this->current_indent_ += fmt.closing_indent; + retval += this->format_indent(fmt.indent_type); + this->current_indent_ -= fmt.closing_indent; + + retval += char_type(']'); + return retval; + } + } // }}} + + string_type operator()(const table_type& t, + const table_format_info& fmt, + const comment_type& com, + const source_location& loc) // {{{ + { + if (this->force_inline_) { + if (fmt.fmt == table_format::multiline_oneline) { + return this->format_ml_inline_table(t, fmt); + } else { + return this->format_inline_table(t, fmt); + } + } else { + if (fmt.fmt == table_format::multiline) { + string_type retval; + // comment is emitted inside format_ml_table + if (auto k = this->format_keys(this->keys_)) { + this->current_indent_ += fmt.name_indent; + retval += this->format_comments(com, fmt.indent_type); + retval += this->format_indent(fmt.indent_type); + this->current_indent_ -= fmt.name_indent; + retval += char_type('['); + retval += k.value(); + retval += string_conv("]\n"); + } + // otherwise, its the root. + + retval += this->format_ml_table(t, fmt); + return retval; + } else if (fmt.fmt == table_format::oneline) { + return this->format_inline_table(t, fmt); + } else if (fmt.fmt == table_format::multiline_oneline) { + return this->format_ml_inline_table(t, fmt); + } else if (fmt.fmt == table_format::dotted) { + std::vector keys; + if (this->keys_.empty()) { + throw serialization_error( + format_error( + "toml::serializer: " + "dotted table must have its key. use format(key, v)", + loc, + "here"), + loc); + } + keys.push_back(this->keys_.back()); + + const auto retval = this->format_dotted_table(t, fmt, loc, keys); + keys.pop_back(); + return retval; + } else { + assert(fmt.fmt == table_format::implicit); + + string_type retval; + for (const auto& kv : t) { + const auto& k = kv.first; + const auto& v = kv.second; + + if (!v.is_table() && !v.is_array_of_tables()) { + throw serialization_error( + format_error("toml::serializer: " + "an implicit table cannot have non-table value.", + v.location(), + "here"), + v.location()); + } + if (v.is_table()) { + if (v.as_table_fmt().fmt != table_format::multiline && + v.as_table_fmt().fmt != table_format::implicit) { + throw serialization_error( + format_error( + "toml::serializer: " + "an implicit table cannot have non-multiline table", + v.location(), + "here"), + v.location()); + } + } else { + assert(v.is_array()); + for (const auto& e : v.as_array()) { + if (e.as_table_fmt().fmt != table_format::multiline && + v.as_table_fmt().fmt != table_format::implicit) { + throw serialization_error( + format_error( + "toml::serializer: " + "an implicit table cannot have non-multiline table", + e.location(), + "here"), + e.location()); + } + } + } + + keys_.push_back(k); + retval += (*this)(v); + keys_.pop_back(); + } + return retval; + } + } + } // }}} + + private: + string_type escape_basic_string(const string_type& s) const // {{{ + { + string_type retval; + for (const char_type c : s) { + switch (c) { + case char_type('\\'): { + retval += string_conv("\\\\"); + break; + } + case char_type('\"'): { + retval += string_conv("\\\""); + break; + } + case char_type('\b'): { + retval += string_conv("\\b"); + break; + } + case char_type('\t'): { + retval += string_conv("\\t"); + break; + } + case char_type('\f'): { + retval += string_conv("\\f"); + break; + } + case char_type('\n'): { + retval += string_conv("\\n"); + break; + } + case char_type('\r'): { + retval += string_conv("\\r"); + break; + } + default: { + if (c == char_type(0x1B) && spec_.v1_1_0_add_escape_sequence_e) { + retval += string_conv("\\e"); + } else if ((char_type(0x00) <= c && c <= char_type(0x08)) || + (char_type(0x0A) <= c && c <= char_type(0x1F)) || + c == char_type(0x7F)) { + if (spec_.v1_1_0_add_escape_sequence_x) { + retval += string_conv("\\x"); + } else { + retval += string_conv("\\u00"); + } + const auto c1 = c / 16; + const auto c2 = c % 16; + retval += static_cast('0' + c1); + if (c2 < 10) { + retval += static_cast('0' + c2); + } else // 10 <= c2 + { + retval += static_cast('A' + (c2 - 10)); + } + } else { + retval += c; + } + } + } + } + return retval; + } // }}} + + string_type escape_ml_basic_string(const string_type& s) // {{{ + { + string_type retval; + for (const char_type c : s) { + switch (c) { + case char_type('\\'): { + retval += string_conv("\\\\"); + break; + } + case char_type('\b'): { + retval += string_conv("\\b"); + break; + } + case char_type('\t'): { + retval += string_conv("\\t"); + break; + } + case char_type('\f'): { + retval += string_conv("\\f"); + break; + } + case char_type('\n'): { + retval += string_conv("\n"); + break; + } + case char_type('\r'): { + retval += string_conv("\\r"); + break; + } + default: { + if (c == char_type(0x1B) && spec_.v1_1_0_add_escape_sequence_e) { + retval += string_conv("\\e"); + } else if ((char_type(0x00) <= c && c <= char_type(0x08)) || + (char_type(0x0A) <= c && c <= char_type(0x1F)) || + c == char_type(0x7F)) { + if (spec_.v1_1_0_add_escape_sequence_x) { + retval += string_conv("\\x"); + } else { + retval += string_conv("\\u00"); + } + const auto c1 = c / 16; + const auto c2 = c % 16; + retval += static_cast('0' + c1); + if (c2 < 10) { + retval += static_cast('0' + c2); + } else // 10 <= c2 + { + retval += static_cast('A' + (c2 - 10)); + } + } else { + retval += c; + } + } + } + } + // Only 1 or 2 consecutive `"`s are allowed in multiline basic string. + // 3 consecutive `"`s are considered as a closing delimiter. + // We need to check if there are 3 or more consecutive `"`s and insert + // backslash to break them down into several short `"`s like the `str6` + // in the following example. + // ```toml + // str4 = """Here are two quotation marks: "". Simple enough.""" + // # str5 = """Here are three quotation marks: """.""" # INVALID + // str5 = """Here are three quotation marks: ""\".""" + // str6 = """Here are fifteen quotation marks: ""\"""\"""\"""\"""\".""" + // ``` + auto found_3_quotes = retval.find(string_conv("\"\"\"")); + while (found_3_quotes != string_type::npos) { + retval.replace(found_3_quotes, 3, string_conv("\"\"\\\"")); + found_3_quotes = retval.find(string_conv("\"\"\"")); + } + return retval; + } // }}} + + string_type format_local_time(const local_time_type& t, + const bool has_seconds, + const std::size_t subsec_prec) // {{{ + { + std::ostringstream oss; + oss << std::setfill('0') << std::setw(2) << static_cast(t.hour); + oss << ':'; + oss << std::setfill('0') << std::setw(2) << static_cast(t.minute); + if (has_seconds) { + oss << ':'; + oss << std::setfill('0') << std::setw(2) << static_cast(t.second); + if (subsec_prec != 0) { + std::ostringstream subsec; + subsec << std::setfill('0') << std::setw(3) + << static_cast(t.millisecond); + subsec << std::setfill('0') << std::setw(3) + << static_cast(t.microsecond); + subsec << std::setfill('0') << std::setw(3) + << static_cast(t.nanosecond); + std::string subsec_str = subsec.str(); + oss << '.' << subsec_str.substr(0, subsec_prec); + } + } + return string_conv(oss.str()); + } // }}} + + string_type format_ml_table(const table_type& t, + const table_format_info& fmt) // {{{ + { + const auto format_later = [](const value_type& v) -> bool { + const bool is_ml_table = v.is_table() && + v.as_table_fmt().fmt != table_format::oneline && + v.as_table_fmt().fmt != + table_format::multiline_oneline && + v.as_table_fmt().fmt != table_format::dotted; + + const bool is_ml_array_table = v.is_array_of_tables() && + v.as_array_fmt().fmt != + array_format::oneline && + v.as_array_fmt().fmt != + array_format::multiline; + + return is_ml_table || is_ml_array_table; + }; + + string_type retval; + this->current_indent_ += fmt.body_indent; + for (const auto& kv : t) { + const auto& key = kv.first; + const auto& val = kv.second; + if (format_later(val)) { + continue; + } + this->keys_.push_back(key); + + retval += format_comments(val.comments(), fmt.indent_type); + retval += format_indent(fmt.indent_type); + if (val.is_table() && val.as_table_fmt().fmt == table_format::dotted) { + retval += (*this)(val); + } else { + retval += format_key(key); + retval += string_conv(" = "); + retval += (*this)(val); + retval += char_type('\n'); + } + this->keys_.pop_back(); + } + this->current_indent_ -= fmt.body_indent; + + if (!retval.empty()) { + retval += char_type('\n'); // for readability, add empty line between tables + } + for (const auto& kv : t) { + if (!format_later(kv.second)) { + continue; + } + // must be a [multiline.table] or [[multiline.array.of.tables]]. + // comments will be generated inside it. + this->keys_.push_back(kv.first); + retval += (*this)(kv.second); + this->keys_.pop_back(); + } + return retval; + } // }}} + + string_type format_inline_table(const table_type& t, + const table_format_info&) // {{{ + { + // comments are ignored because we cannot write without newline + string_type retval; + retval += char_type('{'); + for (const auto& kv : t) { + this->force_inline_ = true; + retval += this->format_key(kv.first); + retval += string_conv(" = "); + retval += (*this)(kv.second); + retval += string_conv(", "); + } + if (!t.empty()) { + retval.pop_back(); // ' ' + retval.pop_back(); // ',' + } + retval += char_type('}'); + this->force_inline_ = false; + return retval; + } // }}} + + string_type format_ml_inline_table(const table_type& t, + const table_format_info& fmt) // {{{ + { + string_type retval; + retval += string_conv("{\n"); + this->current_indent_ += fmt.body_indent; + for (const auto& kv : t) { + this->force_inline_ = true; + retval += format_comments(kv.second.comments(), fmt.indent_type); + retval += format_indent(fmt.indent_type); + retval += kv.first; + retval += string_conv(" = "); + + this->force_inline_ = true; + retval += (*this)(kv.second); + + retval += string_conv(",\n"); + } + if (!t.empty()) { + retval.pop_back(); // '\n' + retval.pop_back(); // ',' + } + this->current_indent_ -= fmt.body_indent; + this->force_inline_ = false; + + this->current_indent_ += fmt.closing_indent; + retval += format_indent(fmt.indent_type); + this->current_indent_ -= fmt.closing_indent; + + retval += char_type('}'); + return retval; + } // }}} + + string_type format_dotted_table(const table_type& t, + const table_format_info& fmt, // {{{ + const source_location&, + std::vector& keys) { + // lets say we have: `{"a": {"b": {"c": {"d": "foo", "e": "bar"} } }` + // and `a` and `b` are `dotted`. + // + // - in case if `c` is `oneline`: + // ```toml + // a.b.c = {d = "foo", e = "bar"} + // ``` + // + // - in case if and `c` is `dotted`: + // ```toml + // a.b.c.d = "foo" + // a.b.c.e = "bar" + // ``` + + string_type retval; + + for (const auto& kv : t) { + const auto& key = kv.first; + const auto& val = kv.second; + + keys.push_back(key); + + // format recursive dotted table? + if (val.is_table() && val.as_table_fmt().fmt != table_format::oneline && + val.as_table_fmt().fmt != table_format::multiline_oneline) { + retval += this->format_dotted_table(val.as_table(), + val.as_table_fmt(), + val.location(), + keys); + } else // non-table or inline tables. format normally + { + retval += format_comments(val.comments(), fmt.indent_type); + retval += format_indent(fmt.indent_type); + retval += format_keys(keys).value(); + retval += string_conv(" = "); + this->force_inline_ = true; // sub-table must be inlined + retval += (*this)(val); + retval += char_type('\n'); + this->force_inline_ = false; + } + keys.pop_back(); + } + return retval; + } // }}} + + string_type format_key(const key_type& key) // {{{ + { + if (key.empty()) { + return string_conv("\"\""); + } + + // check the key can be a bare (unquoted) key + auto loc = detail::make_temporary_location(string_conv(key)); + auto reg = detail::syntax::unquoted_key(this->spec_).scan(loc); + if (reg.is_ok() && loc.eof()) { + return key; + } + + // if it includes special characters, then format it in a "quoted" key. + string_type formatted = string_conv("\""); + for (const char_type c : key) { + switch (c) { + case char_type('\\'): { + formatted += string_conv("\\\\"); + break; + } + case char_type('\"'): { + formatted += string_conv("\\\""); + break; + } + case char_type('\b'): { + formatted += string_conv("\\b"); + break; + } + case char_type('\t'): { + formatted += string_conv("\\t"); + break; + } + case char_type('\f'): { + formatted += string_conv("\\f"); + break; + } + case char_type('\n'): { + formatted += string_conv("\\n"); + break; + } + case char_type('\r'): { + formatted += string_conv("\\r"); + break; + } + default: { + // ASCII ctrl char + if ((char_type(0x00) <= c && c <= char_type(0x08)) || + (char_type(0x0A) <= c && c <= char_type(0x1F)) || + c == char_type(0x7F)) { + if (spec_.v1_1_0_add_escape_sequence_x) { + formatted += string_conv("\\x"); + } else { + formatted += string_conv("\\u00"); + } + const auto c1 = c / 16; + const auto c2 = c % 16; + formatted += static_cast('0' + c1); + if (c2 < 10) { + formatted += static_cast('0' + c2); + } else // 10 <= c2 + { + formatted += static_cast('A' + (c2 - 10)); + } + } else { + formatted += c; + } + break; + } + } + } + formatted += string_conv("\""); + return formatted; + } // }}} + + cxx::optional format_keys(const std::vector& keys) // {{{ + { + if (keys.empty()) { + return cxx::make_nullopt(); + } + + string_type formatted; + for (const auto& ky : keys) { + formatted += format_key(ky); + formatted += char_type('.'); + } + formatted.pop_back(); // remove the last dot '.' + return formatted; + } // }}} + + string_type format_comments(const discard_comments&, + const indent_char) const // {{{ + { + return string_conv(""); + } // }}} + + string_type format_comments(const preserve_comments& comments, + const indent_char indent_type) const // {{{ + { + string_type retval; + for (const auto& c : comments) { + if (c.empty()) { + continue; + } + retval += format_indent(indent_type); + if (c.front() != '#') { + retval += char_type('#'); + } + retval += string_conv(c); + if (c.back() != '\n') { + retval += char_type('\n'); + } + } + return retval; + } // }}} + + string_type format_indent(const indent_char indent_type) const // {{{ + { + const auto indent = static_cast( + (std::max)(0, this->current_indent_)); + if (indent_type == indent_char::space) { + return string_conv(make_string(indent, ' ')); + } else if (indent_type == indent_char::tab) { + return string_conv(make_string(indent, '\t')); + } else { + return string_type {}; + } + } // }}} + + std::locale set_locale(std::ostream& os) const { + return os.imbue(std::locale::classic()); + } + + private: + spec spec_; + bool force_inline_; // table inside an array without fmt specification + std::int32_t current_indent_; + std::vector keys_; + }; + } // namespace detail + + template + typename basic_value::string_type format( + const basic_value& v, + const spec s = spec::default_version()) { + detail::serializer ser(s); + return ser(v); + } + + template + typename basic_value::string_type format( + const typename basic_value::key_type& k, + const basic_value& v, + const spec s = spec::default_version()) { + detail::serializer ser(s); + return ser(k, v); + } + + template + typename basic_value::string_type format( + const std::vector::key_type>& ks, + const basic_value& v, + const spec s = spec::default_version()) { + detail::serializer ser(s); + return ser(ks, v); + } + + template + std::ostream& operator<<(std::ostream& os, const basic_value& v) { + os << format(v); + return os; + } + +} // namespace toml + +#if defined(TOML11_COMPILE_SOURCES) +namespace toml { + struct type_config; + struct ordered_type_config; + + extern template typename basic_value::string_type format( + const basic_value&, + const spec); + + extern template typename basic_value::string_type format( + const typename basic_value::key_type& k, + const basic_value& v, + const spec); + + extern template typename basic_value::string_type format( + const std::vector::key_type>& ks, + const basic_value& v, + const spec s); + + extern template typename basic_value::string_type + format(const basic_value&, + const spec); + + extern template typename basic_value::string_type format( + const typename basic_value::key_type& k, + const basic_value& v, + const spec); + + extern template typename basic_value::string_type format( + const std::vector::key_type>& ks, + const basic_value& v, + const spec s); + + namespace detail { + extern template class serializer<::toml::type_config>; + extern template class serializer<::toml::ordered_type_config>; + } // namespace detail +} // namespace toml +#endif // TOML11_COMPILE_SOURCES + +#endif // TOML11_SERIALIZER_HPP +#ifndef TOML11_TOML_HPP +#define TOML11_TOML_HPP + +// The MIT License (MIT) +// +// Copyright (c) 2017-now Toru Niina +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +// IWYU pragma: begin_exports +// IWYU pragma: end_exports + +#endif // TOML11_TOML_HPP diff --git a/src/global/utils/tools.h b/src/global/utils/tools.h index 451c24264..96d948ae4 100644 --- a/src/global/utils/tools.h +++ b/src/global/utils/tools.h @@ -7,12 +7,13 @@ * - tools::divideInProportions2D -> std::tuple * - tools::divideInProportions3D -> std::tuple * - tools::Decompose -> std::vector> + * - tools::Tracker * @namespaces: * - tools:: */ -#ifndef UTILS_HELPERS_H -#define UTILS_HELPERS_H +#ifndef UTILS_TOOLS_H +#define UTILS_TOOLS_H #include "global.h" @@ -227,7 +228,7 @@ namespace tools { raise::ErrorIf(ndomains % n1 != 0, "Decomposition error: does not divide evenly", HERE); - std::tie(n2, + std::tie(n2, n3) = divideInProportions2D(ndomains / n1, ncells[1], ncells[2]); } else if (decomposition[0] < 0 && decomposition[1] < 0 && decomposition[2] < 0) { @@ -245,6 +246,54 @@ namespace tools { } } + class Tracker { + bool m_initialized { false }; + + std::string m_type; + std::size_t m_interval; + long double m_interval_time; + bool m_use_time; + + long double m_last_output_time { -1.0 }; + + public: + Tracker() = default; + + Tracker(const std::string& type, std::size_t interval, long double interval_time) + : m_initialized { true } + , m_type { type } + , m_interval { interval } + , m_interval_time { interval_time } + , m_use_time { interval_time > 0.0 } {} + + ~Tracker() = default; + + void init(const std::string& type, + std::size_t interval, + long double interval_time) { + m_type = type; + m_interval = interval; + m_interval_time = interval_time; + m_use_time = interval_time > 0.0; + m_initialized = true; + } + + auto shouldWrite(std::size_t step, long double time) -> bool { + raise::ErrorIf(!m_initialized, "Tracker not initialized", HERE); + if (m_use_time) { + if ((m_last_output_time < 0) or + (time - m_last_output_time >= m_interval_time)) { + m_last_output_time = time; + return true; + } else { + return false; + } + } else { + return step % m_interval == 0; + } + } + }; + } // namespace tools -#endif // UTILS_HELPERS_H +#endif // UTILS_TOOLS_H diff --git a/src/output/CMakeLists.txt b/src/output/CMakeLists.txt index b262d7771..2c25631ec 100644 --- a/src/output/CMakeLists.txt +++ b/src/output/CMakeLists.txt @@ -17,7 +17,6 @@ set(SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}) set(SOURCES ${SRC_DIR}/writer.cpp - ${SRC_DIR}/write_attrs.cpp ${SRC_DIR}/fields.cpp ${SRC_DIR}/utils/interpret_prompt.cpp ) diff --git a/src/output/write_attrs.cpp b/src/output/write_attrs.cpp deleted file mode 100644 index e1e70f467..000000000 --- a/src/output/write_attrs.cpp +++ /dev/null @@ -1,136 +0,0 @@ -#include "enums.h" -#include "global.h" - -#include "output/writer.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace out { - - template - struct has_to_string : std::false_type {}; - - template - struct has_to_string().to_string())>> - : std::true_type {}; - - template - auto write(adios2::IO& io, const std::string& name, T var) -> - typename std::enable_if::value, void>::type { - io.DefineAttribute(name, std::string(var.to_string())); - } - - template - auto write(adios2::IO& io, const std::string& name, T var) - -> decltype(void(T()), void()) { - io.DefineAttribute(name, var); - } - - template <> - void write(adios2::IO& io, const std::string& name, bool var) { - io.DefineAttribute(name, var ? 1 : 0); - } - - template <> - void write(adios2::IO& io, const std::string& name, Dimension var) { - io.DefineAttribute(name, (unsigned short)var); - } - - template - auto write_vec(adios2::IO& io, const std::string& name, std::vector var) -> - typename std::enable_if::value, void>::type { - std::vector var_str; - for (const auto& v : var) { - var_str.push_back(v.to_string()); - } - io.DefineAttribute(name, var_str.data(), var_str.size()); - } - - template - auto write_vec(adios2::IO& io, const std::string& name, std::vector var) - -> decltype(void(T()), void()) { - io.DefineAttribute(name, var.data(), var.size()); - } - - std::map> - write_functions; - - template - void register_write_function() { - write_functions[std::type_index(typeid(T))] = - [](adios2::IO& io, const std::string& name, std::any a) { - write(io, name, std::any_cast(a)); - }; - } - - template - void register_write_function_for_vector() { - write_functions[std::type_index(typeid(std::vector))] = - [](adios2::IO& io, const std::string& name, std::any a) { - write_vec(io, name, std::any_cast>(a)); - }; - } - - void write_any(adios2::IO& io, const std::string& name, std::any a) { - auto it = write_functions.find(a.type()); - if (it != write_functions.end()) { - it->second(io, name, a); - } else { - throw std::runtime_error("No write function registered for this type"); - } - } - - void Writer::writeAttrs(const prm::Parameters& params) { - register_write_function(); - register_write_function(); - register_write_function(); - register_write_function(); - register_write_function(); - register_write_function(); - register_write_function(); - register_write_function(); - register_write_function(); - register_write_function(); - register_write_function(); - register_write_function(); - register_write_function(); - register_write_function(); - register_write_function(); - register_write_function(); - register_write_function(); - register_write_function(); - register_write_function(); - register_write_function_for_vector(); - register_write_function_for_vector(); - register_write_function_for_vector(); - register_write_function_for_vector(); - register_write_function_for_vector(); - register_write_function_for_vector(); - register_write_function_for_vector(); - register_write_function_for_vector(); - register_write_function_for_vector(); - register_write_function_for_vector(); - register_write_function_for_vector(); - register_write_function_for_vector(); - register_write_function_for_vector(); - register_write_function_for_vector(); - register_write_function_for_vector(); - register_write_function_for_vector(); - register_write_function_for_vector(); - - for (auto& [key, value] : params.allVars()) { - try { - write_any(m_io, key, value); - } catch (const std::exception& e) { - continue; - } - } - } -} // namespace out \ No newline at end of file diff --git a/src/output/writer.cpp b/src/output/writer.cpp index aeb9dbce8..549f7a25d 100644 --- a/src/output/writer.cpp +++ b/src/output/writer.cpp @@ -5,11 +5,11 @@ #include "arch/kokkos_aliases.h" #include "utils/error.h" #include "utils/param_container.h" +#include "utils/tools.h" #include - -#include -#include +#include +#include #if defined(MPI_ENABLED) #include "arch/mpi_aliases.h" @@ -17,13 +17,18 @@ #include #endif +#include +#include + namespace out { void Writer::init(adios2::ADIOS* ptr_adios, const std::string& engine) { m_engine = engine; p_adios = ptr_adios; - m_io = p_adios->DeclareIO("Entity::ADIOS2"); + raise::ErrorIf(p_adios == nullptr, "ADIOS pointer is null", HERE); + + m_io = p_adios->DeclareIO("Entity::Output"); m_io.SetEngine(engine); m_io.DefineVariable("Step"); @@ -33,8 +38,8 @@ namespace out { void Writer::addTracker(const std::string& type, std::size_t interval, long double interval_time) { - m_trackers.insert(std::pair( - { type, Tracker(type, interval, interval_time) })); + m_trackers.insert(std::pair( + { type, tools::Tracker(type, interval, interval_time) })); } auto Writer::shouldWrite(const std::string& type, @@ -158,6 +163,10 @@ namespace out { } } + void Writer::writeAttrs(const prm::Parameters& params) { + params.write(m_io); + } + template void WriteField(adios2::IO& io, adios2::Engine& writer, @@ -287,6 +296,7 @@ namespace out { void Writer::beginWriting(const std::string& fname, std::size_t tstep, long double time) { + raise::ErrorIf(p_adios == nullptr, "ADIOS pointer is null", HERE); p_adios->ExitComputationBlock(); if (m_writing_mode) { raise::Fatal("Already writing", HERE); @@ -304,6 +314,7 @@ namespace out { } void Writer::endWriting() { + raise::ErrorIf(p_adios == nullptr, "ADIOS pointer is null", HERE); if (!m_writing_mode) { raise::Fatal("Not writing", HERE); } diff --git a/src/output/writer.h b/src/output/writer.h index 3fb958bc3..7a3ed43ba 100644 --- a/src/output/writer.h +++ b/src/output/writer.h @@ -11,6 +11,7 @@ #include "arch/kokkos_aliases.h" #include "utils/param_container.h" +#include "utils/tools.h" #include "output/fields.h" #include "output/particles.h" @@ -28,37 +29,6 @@ namespace out { - class Tracker { - const std::string m_type; - const std::size_t m_interval; - const long double m_interval_time; - const bool m_use_time; - - long double m_last_output_time { -1.0 }; - - public: - Tracker(const std::string& type, std::size_t interval, long double interval_time) - : m_type { type } - , m_interval { interval } - , m_interval_time { interval_time } - , m_use_time { interval_time > 0.0 } {} - - ~Tracker() = default; - - auto shouldWrite(std::size_t step, long double time) -> bool { - if (m_use_time) { - if (time - m_last_output_time >= m_interval_time) { - m_last_output_time = time; - return true; - } else { - return false; - } - } else { - return step % m_interval == 0; - } - } - }; - class Writer { adios2::ADIOS* p_adios { nullptr }; @@ -75,7 +45,7 @@ namespace out { bool m_flds_ghosts; std::string m_engine; - std::map m_trackers; + std::map m_trackers; std::vector m_flds_writers; std::vector m_prtl_writers; @@ -95,7 +65,7 @@ namespace out { void addTracker(const std::string&, std::size_t, long double); auto shouldWrite(const std::string&, std::size_t, long double) -> bool; - void writeAttrs(const prm::Parameters& params); + void writeAttrs(const prm::Parameters&); void defineMeshLayout(const std::vector&, const std::vector&, From 517571aa03574952be374006de811c8384269d10 Mon Sep 17 00:00:00 2001 From: hayk Date: Sat, 10 Aug 2024 01:42:19 -0400 Subject: [PATCH 006/773] toml11 dependency removed --- .gitmodules | 3 --- extern/toml11 | 1 - 2 files changed, 4 deletions(-) delete mode 160000 extern/toml11 diff --git a/.gitmodules b/.gitmodules index bb2c39c87..e06c332fe 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,3 @@ -[submodule "extern/toml11"] - path = extern/toml11 - url = https://github.com/ToruNiina/toml11.git [submodule "extern/plog"] path = extern/plog url = https://github.com/SergiusTheBest/plog.git diff --git a/extern/toml11 b/extern/toml11 deleted file mode 160000 index 9b914db23..000000000 --- a/extern/toml11 +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 9b914db23df4acb6f1885fee29e07e9af959251e From 83c224907e39a35f54d3bfd3e419565da788e264 Mon Sep 17 00:00:00 2001 From: hayk Date: Sat, 10 Aug 2024 01:48:42 -0400 Subject: [PATCH 007/773] cmake in test fixed --- cmake/tests.cmake | 1 + 1 file changed, 1 insertion(+) diff --git a/cmake/tests.cmake b/cmake/tests.cmake index b53626723..7bfcb1d12 100644 --- a/cmake/tests.cmake +++ b/cmake/tests.cmake @@ -10,6 +10,7 @@ add_subdirectory(${SRC_DIR}/archetypes ${CMAKE_CURRENT_BINARY_DIR}/archetypes) add_subdirectory(${SRC_DIR}/framework ${CMAKE_CURRENT_BINARY_DIR}/framework) if (${output}) add_subdirectory(${SRC_DIR}/output ${CMAKE_CURRENT_BINARY_DIR}/output) + add_subdirectory(${SRC_DIR}/checkpoint ${CMAKE_CURRENT_BINARY_DIR}/checkpoint) endif() if (${mpi}) From 86e7f9de95739c99bfde7b1467214f09744c99ad Mon Sep 17 00:00:00 2001 From: hayk Date: Sat, 10 Aug 2024 04:34:36 -0400 Subject: [PATCH 008/773] restart dumping --- cmake/report.cmake | 7 +- src/checkpoint/writer.cpp | 221 +++++++++++++++++++++++++--- src/checkpoint/writer.h | 32 +++- src/framework/domain/checkpoint.cpp | 206 +++++++++++++++++++++++++- src/framework/domain/output.cpp | 1 - 5 files changed, 440 insertions(+), 27 deletions(-) diff --git a/cmake/report.cmake b/cmake/report.cmake index fe914baa8..6733dbcd4 100644 --- a/cmake/report.cmake +++ b/cmake/report.cmake @@ -276,10 +276,11 @@ endif() message(" ${PRECISION_REPORT}") message(" ${OUTPUT_REPORT}") -message("${DASHED_LINE_SYMBOL} -Compile configurations") +message("${DASHED_LINE_SYMBOL}\nCompile configurations") -message(" ${ARCH_REPORT}") +if(NOT "${ARCH_REPORT}" STREQUAL "") + message(" ${ARCH_REPORT}") +endif() message(" ${CUDA_REPORT}") message(" ${HIP_REPORT}") message(" ${OPENMP_REPORT}") diff --git a/src/checkpoint/writer.cpp b/src/checkpoint/writer.cpp index e56f59b36..53b2b2821 100644 --- a/src/checkpoint/writer.cpp +++ b/src/checkpoint/writer.cpp @@ -2,6 +2,8 @@ #include "global.h" +#include "arch/kokkos_aliases.h" +#include "arch/mpi_aliases.h" #include "utils/error.h" #include "utils/formatting.h" #include "utils/log.h" @@ -46,13 +48,96 @@ namespace checkpoint { p_adios->EnterComputationBlock(); } + void Writer::defineFieldVariables(const ntt::SimEngine& S, + const std::vector& glob_shape, + const std::vector& loc_corner, + const std::vector& loc_shape) { + auto gs3 = std::vector(glob_shape.begin(), glob_shape.end()); + auto lc3 = std::vector(loc_corner.begin(), loc_corner.end()); + auto ls3 = std::vector(loc_shape.begin(), loc_shape.end()); + auto gs6 = std::vector(glob_shape.begin(), glob_shape.end()); + auto lc6 = std::vector(loc_corner.begin(), loc_corner.end()); + auto ls6 = std::vector(loc_shape.begin(), loc_shape.end()); + + gs3.push_back(3); + lc3.push_back(0); + ls3.push_back(3); + + gs6.push_back(6); + lc6.push_back(0); + ls6.push_back(6); + + m_io.DefineVariable("em", gs6, lc6, ls6, adios2::ConstantDims); + if (S == ntt::SimEngine::GRPIC) { + m_io.DefineVariable("em0", gs6, lc6, ls6, adios2::ConstantDims); + m_io.DefineVariable("cur0", gs3, lc3, ls3, adios2::ConstantDims); + } + } + + void Writer::defineParticleVariables(const ntt::Coord& C, + Dimension dim, + std::size_t nspec, + const std::vector& nplds) { + raise::ErrorIf(nplds.size() != nspec, + "Number of payloads does not match the number of species", + HERE); + for (auto s { 0u }; s < nspec; ++s) { + m_io.DefineVariable(fmt::format("s%d_npart", s + 1), + { adios2::UnknownDim }, + { adios2::UnknownDim }, + { adios2::UnknownDim }); + for (auto d { 0u }; d < dim; ++d) { + m_io.DefineVariable(fmt::format("s%d_i%d", s + 1, d + 1), + { adios2::UnknownDim }, + { adios2::UnknownDim }, + { adios2::UnknownDim }); + m_io.DefineVariable(fmt::format("s%d_dx%d", s + 1, d + 1), + { adios2::UnknownDim }, + { adios2::UnknownDim }, + { adios2::UnknownDim }); + m_io.DefineVariable(fmt::format("s%d_i%d_prev", s + 1, d + 1), + { adios2::UnknownDim }, + { adios2::UnknownDim }, + { adios2::UnknownDim }); + m_io.DefineVariable(fmt::format("s%d_dx%d_prev", s + 1, d + 1), + { adios2::UnknownDim }, + { adios2::UnknownDim }, + { adios2::UnknownDim }); + } + if (dim == Dim::_2D and C != ntt::Coord::Cart) { + m_io.DefineVariable(fmt::format("s%d_phi", s + 1), + { adios2::UnknownDim }, + { adios2::UnknownDim }, + { adios2::UnknownDim }); + } + for (auto d { 0u }; d < 3; ++d) { + m_io.DefineVariable(fmt::format("s%d_ux%d", s + 1, d + 1), + { adios2::UnknownDim }, + { adios2::UnknownDim }, + { adios2::UnknownDim }); + } + m_io.DefineVariable(fmt::format("s%d_tag", s + 1), + { adios2::UnknownDim }, + { adios2::UnknownDim }, + { adios2::UnknownDim }); + m_io.DefineVariable(fmt::format("s%d_weight", s + 1), + { adios2::UnknownDim }, + { adios2::UnknownDim }, + { adios2::UnknownDim }); + for (auto p { 0u }; p < nplds[s]; ++p) { + m_io.DefineVariable(fmt::format("s%d_pld%d", s + 1, p + 1), + { adios2::UnknownDim }, + { adios2::UnknownDim }, + { adios2::UnknownDim }); + } + } + } + auto Writer::shouldSave(std::size_t step, long double time) -> bool { return m_enabled and m_tracker.shouldWrite(step, time); } - void Writer::beginSaving(const ntt::SimulationParams& params, - std::size_t step, - long double time) { + void Writer::beginSaving(std::size_t step, long double time) { raise::ErrorIf(!m_enabled, "Checkpoint is not enabled", HERE); raise::ErrorIf(p_adios == nullptr, "ADIOS pointer is null", HERE); p_adios->ExitComputationBlock(); @@ -61,19 +146,14 @@ namespace checkpoint { } m_writing_mode = true; try { - auto fname = fmt::format("checkpoints/step-%08lu.bp", step); - m_writer = m_io.Open(fname, adios2::Mode::Write); - m_written.push_back(fname); + auto fname = fmt::format("checkpoints/step-%08lu.bp", step); + m_writer = m_io.Open(fname, adios2::Mode::Write); + auto meta_fname = fmt::format("checkpoints/meta-%08lu.toml", step); + m_written.push_back({ fname, meta_fname }); } catch (std::exception& e) { raise::Fatal(e.what(), HERE); } - // write the metadata - std::ofstream metadata; - metadata.open(fmt::format("checkpoints/meta-%08lu.toml", step).c_str()); - metadata << params.data() << std::endl; - metadata.close(); - m_writer.BeginStep(); m_writer.Put(m_io.InquireVariable("Step"), &step); m_writer.Put(m_io.InquireVariable("Time"), &time); @@ -90,14 +170,115 @@ namespace checkpoint { p_adios->EnterComputationBlock(); // optionally remove the oldest checkpoint - if (m_keep > 0 and m_written.size() > (std::size_t)m_keep) { - const auto oldest = m_written.front(); - if (std::filesystem::exists(oldest)) { - std::filesystem::remove_all(oldest); - m_written.erase(m_written.begin()); - } else { - raise::Warning("Checkpoint file does not exist for some reason", HERE); + CallOnce([&]() { + if (m_keep > 0 and m_written.size() > (std::size_t)m_keep) { + const auto oldest = m_written.front(); + if (std::filesystem::exists(oldest.first) and + std::filesystem::exists(oldest.second)) { + std::filesystem::remove_all(oldest.first); + std::filesystem::remove(oldest.second); + m_written.erase(m_written.begin()); + } else { + raise::Warning("Checkpoint file does not exist for some reason", HERE); + } } - } + }); + } + + template + void Writer::savePerDomainVariable(const std::string& varname, + std::size_t total, + std::size_t offset, + T data) { + auto var = m_io.InquireVariable(varname); + var.SetShape({ total }); + var.SetSelection(adios2::Box({ offset }, { 1 })); + m_writer.Put(var, &data); } + + void Writer::saveAttrs(const ntt::SimulationParams& params) { + CallOnce([&]() { + std::ofstream metadata; + if (m_written.empty()) { + raise::Fatal("No checkpoint file to save metadata", HERE); + } + metadata.open(m_written.back().second.c_str()); + metadata << params.data() << std::endl; + metadata.close(); + }); + } + + template + void Writer::saveField(const std::string& fieldname, + const ndfield_t& field) { + auto field_h = Kokkos::create_mirror_view(field); + Kokkos::deep_copy(field_h, field); + m_writer.Put(m_io.InquireVariable(fieldname), field_h.data()); + } + + template + void Writer::saveParticleQuantity(const std::string& quantity, + std::size_t glob_total, + std::size_t loc_offset, + std::size_t loc_size, + const array_t& data) { + auto var = m_io.InquireVariable(quantity); + var.SetShape({ glob_total }); + var.SetSelection(adios2::Box({ loc_offset }, { loc_size })); + auto slice = range_tuple_t(0, loc_size); + auto data_h = Kokkos::create_mirror_view(data); + Kokkos::deep_copy(data_h, data); + m_writer.Put(var, Kokkos::subview(data_h, slice).data()); + } + + template void Writer::savePerDomainVariable(const std::string&, + std::size_t, + std::size_t, + int); + template void Writer::savePerDomainVariable(const std::string&, + std::size_t, + std::size_t, + float); + template void Writer::savePerDomainVariable(const std::string&, + std::size_t, + std::size_t, + double); + template void Writer::savePerDomainVariable(const std::string&, + std::size_t, + std::size_t, + std::size_t); + + template void Writer::saveField(const std::string&, + const ndfield_t&); + template void Writer::saveField(const std::string&, + const ndfield_t&); + template void Writer::saveField(const std::string&, + const ndfield_t&); + template void Writer::saveField(const std::string&, + const ndfield_t&); + template void Writer::saveField(const std::string&, + const ndfield_t&); + template void Writer::saveField(const std::string&, + const ndfield_t&); + + template void Writer::saveParticleQuantity(const std::string&, + std::size_t, + std::size_t, + std::size_t, + const array_t&); + template void Writer::saveParticleQuantity(const std::string&, + std::size_t, + std::size_t, + std::size_t, + const array_t&); + template void Writer::saveParticleQuantity(const std::string&, + std::size_t, + std::size_t, + std::size_t, + const array_t&); + template void Writer::saveParticleQuantity(const std::string&, + std::size_t, + std::size_t, + std::size_t, + const array_t&); } // namespace checkpoint diff --git a/src/checkpoint/writer.h b/src/checkpoint/writer.h index ec2fa08d8..c9fc8a7db 100644 --- a/src/checkpoint/writer.h +++ b/src/checkpoint/writer.h @@ -12,6 +12,7 @@ #ifndef CHECKPOINT_WRITER_H #define CHECKPOINT_WRITER_H +#include "enums.h" #include "global.h" #include "utils/tools.h" @@ -21,6 +22,8 @@ #include #include +#include +#include #include namespace checkpoint { @@ -35,7 +38,7 @@ namespace checkpoint { bool m_writing_mode { false }; - std::vector m_written; + std::vector> m_written; int m_keep; bool m_enabled; @@ -49,9 +52,34 @@ namespace checkpoint { auto shouldSave(std::size_t, long double) -> bool; - void beginSaving(const ntt::SimulationParams&, std::size_t, long double); + void beginSaving(std::size_t, long double); void endSaving(); + void saveAttrs(const ntt::SimulationParams&); + + template + void savePerDomainVariable(const std::string&, std::size_t, std::size_t, T); + + template + void saveField(const std::string&, const ndfield_t&); + + template + void saveParticleQuantity(const std::string&, + std::size_t, + std::size_t, + std::size_t, + const array_t&); + + void defineFieldVariables(const ntt::SimEngine&, + const std::vector&, + const std::vector&, + const std::vector&); + void defineParticleVariables(const ntt::Coord&, + Dimension, + std::size_t, + const std::vector&); + + [[nodiscard]] auto enabled() const -> bool { return m_enabled; } diff --git a/src/framework/domain/checkpoint.cpp b/src/framework/domain/checkpoint.cpp index 3295e9430..a5a77bf4d 100644 --- a/src/framework/domain/checkpoint.cpp +++ b/src/framework/domain/checkpoint.cpp @@ -2,6 +2,8 @@ #include "global.h" #include "utils/error.h" +#include "utils/formatting.h" +#include "utils/log.h" #include "metrics/kerr_schild.h" #include "metrics/kerr_schild_0.h" @@ -28,23 +30,225 @@ namespace ntt { "local_domain is a placeholder", HERE); + auto glob_shape_with_ghosts = mesh().n_active(); + auto off_ncells_with_ghosts = local_domain->offset_ncells(); + auto loc_shape_with_ghosts = local_domain->mesh.n_active(); + + std::vector nplds; + for (auto s { 0u }; s < local_domain->species.size(); ++s) { + nplds.push_back(local_domain->species[s].npld()); + } + g_checkpoint_writer.init( ptr_adios, params.template get("checkpoint.interval"), params.template get("checkpoint.interval_time"), params.template get("checkpoint.keep")); + g_checkpoint_writer.defineFieldVariables(S, + glob_shape_with_ghosts, + off_ncells_with_ghosts, + loc_shape_with_ghosts); + g_checkpoint_writer.defineParticleVariables(M::CoordType, + M::Dim, + local_domain->species.size(), + nplds); } template auto Metadomain::WriteCheckpoint(const SimulationParams& params, std::size_t step, long double time) -> bool { + raise::ErrorIf( + local_subdomain_indices().size() != 1, + "Checkpointing for now is only supported for one subdomain per rank", + HERE); if (!g_checkpoint_writer.shouldSave(step, time)) { return false; } + auto local_domain = subdomain_ptr(local_subdomain_indices()[0]); + raise::ErrorIf(local_domain->is_placeholder(), + "local_domain is a placeholder", + HERE); logger::Checkpoint("Writing checkpoint", HERE); - g_checkpoint_writer.beginSaving(params, step, time); + g_checkpoint_writer.beginSaving(step, time); + { + + g_checkpoint_writer.saveAttrs(params); + + g_checkpoint_writer.saveField("em", local_domain->fields.em); + if constexpr (S == SimEngine::GRPIC) { + g_checkpoint_writer.saveField("em0", local_domain->fields.em0); + g_checkpoint_writer.saveField("cur0", local_domain->fields.cur0); + } + std::size_t dom_offset = 0, dom_tot = 1; +#if defined(MPI_ENABLED) + dom_offset = g_mpi_rank; + dom_tot = g_mpi_size; +#endif // MPI_ENABLED + + for (auto s { 0u }; s < local_domain->species.size(); ++s) { + auto npart = local_domain->species[s].npart(); + std::size_t offset = 0; + auto glob_tot = npart; +#if defined(MPI_ENABLED) + auto glob_npart = std::vector(g_ndomains); + MPI_Allgather(&npart, + 1, + mpi::get_type(), + glob_npart.data(), + 1, + mpi::get_type(), + MPI_COMM_WORLD); + glob_tot = 0; + for (auto r = 0; r < g_mpi_size; ++r) { + if (r < g_mpi_rank) { + offset += glob_npart[r]; + } + glob_tot += glob_npart[r]; + } +#endif // MPI_ENABLED + g_checkpoint_writer.savePerDomainVariable( + fmt::format("s%d_npart", s + 1), + dom_tot, + dom_offset, + npart); + if constexpr (M::Dim == Dim::_1D or M::Dim == Dim::_2D or + M::Dim == Dim::_3D) { + g_checkpoint_writer.saveParticleQuantity( + fmt::format("s%d_i1", s + 1), + glob_tot, + offset, + npart, + local_domain->species[s].i1); + g_checkpoint_writer.saveParticleQuantity( + fmt::format("s%d_i1", s + 1), + glob_tot, + offset, + npart, + local_domain->species[s].i1); + g_checkpoint_writer.saveParticleQuantity( + fmt::format("s%d_dx1", s + 1), + glob_tot, + offset, + npart, + local_domain->species[s].dx1); + g_checkpoint_writer.saveParticleQuantity( + fmt::format("s%d_i1_prev", s + 1), + glob_tot, + offset, + npart, + local_domain->species[s].i1_prev); + g_checkpoint_writer.saveParticleQuantity( + fmt::format("s%d_dx1_prev", s + 1), + glob_tot, + offset, + npart, + local_domain->species[s].dx1_prev); + } + if constexpr (M::Dim == Dim::_1D or M::Dim == Dim::_2D) { + g_checkpoint_writer.saveParticleQuantity( + fmt::format("s%d_i2", s + 1), + glob_tot, + offset, + npart, + local_domain->species[s].i2); + g_checkpoint_writer.saveParticleQuantity( + fmt::format("s%d_dx2", s + 1), + glob_tot, + offset, + npart, + local_domain->species[s].dx2); + g_checkpoint_writer.saveParticleQuantity( + fmt::format("s%d_i2_prev", s + 1), + glob_tot, + offset, + npart, + local_domain->species[s].i2_prev); + g_checkpoint_writer.saveParticleQuantity( + fmt::format("s%d_dx2_prev", s + 1), + glob_tot, + offset, + npart, + local_domain->species[s].dx2_prev); + } + if constexpr (M::Dim == Dim::_3D) { + g_checkpoint_writer.saveParticleQuantity( + fmt::format("s%d_i3", s + 1), + glob_tot, + offset, + npart, + local_domain->species[s].i3); + g_checkpoint_writer.saveParticleQuantity( + fmt::format("s%d_dx3", s + 1), + glob_tot, + offset, + npart, + local_domain->species[s].dx3); + g_checkpoint_writer.saveParticleQuantity( + fmt::format("s%d_i3_prev", s + 1), + glob_tot, + offset, + npart, + local_domain->species[s].i3_prev); + g_checkpoint_writer.saveParticleQuantity( + fmt::format("s%d_dx3_prev", s + 1), + glob_tot, + offset, + npart, + local_domain->species[s].dx3_prev); + } + if constexpr (M::Dim == Dim::_2D and M::CoordType != Coord::Cart) { + g_checkpoint_writer.saveParticleQuantity( + fmt::format("s%d_phi", s + 1), + glob_tot, + offset, + npart, + local_domain->species[s].phi); + } + g_checkpoint_writer.saveParticleQuantity( + fmt::format("s%d_ux1", s + 1), + glob_tot, + offset, + npart, + local_domain->species[s].ux1); + g_checkpoint_writer.saveParticleQuantity( + fmt::format("s%d_ux2", s + 1), + glob_tot, + offset, + npart, + local_domain->species[s].ux2); + g_checkpoint_writer.saveParticleQuantity( + fmt::format("s%d_ux3", s + 1), + glob_tot, + offset, + npart, + local_domain->species[s].ux3); + g_checkpoint_writer.saveParticleQuantity( + fmt::format("s%d_tag", s + 1), + glob_tot, + offset, + npart, + local_domain->species[s].tag); + g_checkpoint_writer.saveParticleQuantity( + fmt::format("s%d_weight", s + 1), + glob_tot, + offset, + npart, + local_domain->species[s].weight); + + auto nplds = local_domain->species[s].npld(); + for (auto p { 0u }; p < nplds; ++p) { + g_checkpoint_writer.saveParticleQuantity( + fmt::format("s%d_pld%d", s + 1, p + 1), + glob_tot, + offset, + npart, + local_domain->species[s].pld[p]); + } + } + } g_checkpoint_writer.endSaving(); + logger::Checkpoint("Checkpoint written", HERE); return true; } diff --git a/src/framework/domain/output.cpp b/src/framework/domain/output.cpp index 0fcc89593..c79b284d5 100644 --- a/src/framework/domain/output.cpp +++ b/src/framework/domain/output.cpp @@ -197,7 +197,6 @@ namespace ntt { g_writer.beginWriting(params.template get("simulation.name"), step, time); - if (write_fields) { const auto incl_ghosts = params.template get("output.debug.ghosts"); From 48a7e3686f61a7a2bef731cc8029d54b4f13ffab Mon Sep 17 00:00:00 2001 From: hayk Date: Sat, 10 Aug 2024 16:10:33 -0400 Subject: [PATCH 009/773] toml.h bug fixed --- src/global/utils/toml.h | 46 ++++++----------------------------------- 1 file changed, 6 insertions(+), 40 deletions(-) diff --git a/src/global/utils/toml.h b/src/global/utils/toml.h index b621f5839..16b79f72d 100644 --- a/src/global/utils/toml.h +++ b/src/global/utils/toml.h @@ -10365,15 +10365,14 @@ namespace toml { // recursive namespace detail { - template - T& last_one(T& arg) { - return arg; - } - template - auto last_one(T1&, T2& arg, Ts&... args) -> decltype(last_one(arg, args...)) { - return last_one(arg, args...); + template + auto last_one(Ts&&... args) -> decltype(std::get( + std::forward_as_tuple(std::forward(args)...))) { + return std::get( + std::forward_as_tuple(std::forward(args)...)); } + } // namespace detail template @@ -10401,39 +10400,6 @@ namespace toml { } } - template - auto find_or(Value&& v, const K1& k1, const K2& k2, K3&& k3, K4&& k4, Ks&&... keys) noexcept - -> cxx::enable_if_t>::value, - decltype(find_or(v, - k2, - std::forward(k3), - std::forward(k4), - std::forward(keys)...))> { - try { - return find_or(v.at(k1), - k2, - std::forward(k3), - std::forward(k4), - std::forward(keys)...); - } catch (...) { - return detail::last_one(k4, keys...); - } - } - - template - T find_or(const basic_value& v, - const K1& k1, - const K2& k2, - const K3& k3, - const K4& k4, - const Ks&... keys) noexcept { - try { - return find_or(v.at(k1), k2, k3, k4, keys...); - } catch (...) { - return static_cast(detail::last_one(k4, keys...)); - } - } - } // namespace toml #endif // TOML11_FIND_HPP #ifndef TOML11_CONVERSION_HPP From d36d3cde11549788d13e680c3f7429eeaf41d7ae Mon Sep 17 00:00:00 2001 From: hayk Date: Tue, 13 Aug 2024 15:06:37 -0400 Subject: [PATCH 010/773] param reading adapted to checkpoint --- input.example.toml | 34 +- src/checkpoint/reader.cpp | 0 src/checkpoint/reader.h | 19 ++ src/checkpoint/writer.cpp | 6 +- src/checkpoint/writer.h | 4 +- src/engines/engine.hpp | 18 +- src/engines/engine_init.cpp | 43 +-- src/engines/grpic.hpp | 3 +- src/engines/srpic.hpp | 2 +- src/framework/CMakeLists.txt | 1 + src/framework/domain/checkpoint.cpp | 2 +- src/framework/domain/metadomain.h | 4 +- src/framework/domain/output.cpp | 10 +- src/framework/parameters.cpp | 502 +++++++++++++++------------- src/framework/parameters.h | 11 +- src/framework/simulation.cpp | 57 +++- src/framework/simulation.h | 4 +- src/global/defaults.h | 1 - src/output/writer.cpp | 4 + src/output/writer.h | 2 + 20 files changed, 442 insertions(+), 285 deletions(-) create mode 100644 src/checkpoint/reader.cpp create mode 100644 src/checkpoint/reader.h diff --git a/input.example.toml b/input.example.toml index eacb7f402..06225024a 100644 --- a/input.example.toml +++ b/input.example.toml @@ -232,7 +232,7 @@ # @default: 0.9 e_ovr_b_max = "" # Maximum Larmor radius allowed for GCA particles (in physical units): - # @type: float: > 0 + # @type: float # @default: 0.0 # @note: When `larmor_max` == 0, the limit is disabled larmor_max = "" @@ -253,7 +253,7 @@ # @default: false use_weights = "" # Timesteps between particle re-sorting: - # @type: unsigned int: >= 0 + # @type: unsigned int # @default: 100 # @note: When MPI is enable, particles are sorted every step. # @note: When `sort_interval` == 0, the sorting is disabled. @@ -293,7 +293,7 @@ # @valid: "Boris", "Vay", "Boris,GCA", "Vay,GCA", "Photon", "None" pusher = "" # Number of additional (payload) variables for each particle of the given species: - # @type: unsigned short: >= 0 + # @type: unsigned short # @default: 0 n_payloads = "" # Radiation reaction to use for the species: @@ -316,7 +316,7 @@ # @default: 1 interval = "" # Physical (code) time interval between all outputs (overriden by specific output intervals below): - # @type: float: > 0 + # @type: float # @default: -1.0 (disabled) # @note: When `interval_time` < 0, the output is controlled by `interval`, otherwise by `interval_time` interval_time = "" @@ -345,15 +345,15 @@ # @default: 1 stride = "" # Smoothing window for the output of moments (e.g., "Rho", "Charge", "T", etc.): - # @type: unsigned short: >= 0 + # @type: unsigned short # @default: 0 mom_smooth = "" # Number of timesteps between field outputs (overrides `output.interval`): - # @type: unsigned int: > 0 + # @type: unsigned int # @default: 0 (use `output.interval`) interval = "" # Physical (code) time interval between field outputs (overrides `output.interval_time`): - # @type: float: > 0 + # @type: float # @default: -1.0 (use `output.interval_time`) # @note: When `interval_time` < 0, the output is controlled by `interval`, otherwise by `interval_time` interval_time = "" @@ -376,7 +376,7 @@ # @default: 0 (use `output.interval`) interval = "" # Physical (code) time interval between field outputs (overrides `output.interval_time`): - # @type: float: > 0 + # @type: float # @default: -1.0 (use `output.interval_time`) # @note: When `interval_time` < 0, the output is controlled by `interval`, otherwise by `interval_time` interval_time = "" @@ -407,7 +407,7 @@ # @default: 0 (use `output.interval`) interval = "" # Physical (code) time interval between spectra outputs (overrides `output.interval_time`): - # @type: float: > 0 + # @type: float # @default: -1.0 (use `output.interval_time`) # @note: When `interval_time` < 0, the output is controlled by `interval`, otherwise by `interval_time` interval_time = "" @@ -433,12 +433,26 @@ # @note: When `interval_time` < 0, the output is controlled by `interval`, otherwise by `interval_time` interval_time = "" # Number of checkpoints to keep: - # @type: unsigned int: > 0 + # @type: int # @default: 2 # @note: 0 = disable checkpointing # @note: -1 = keep all checkpoints keep = "" + # @inferred: + # - is_resuming + # @brief: Whether the simulation is resuming from a checkpoint + # @type: bool + # @from: command-line flag + # - start_step + # @brief: Timestep of the checkpoint used to resume + # @type: unsigned int + # @from: automatically determined during restart + # - start_time + # @brief: Time of the checkpoint used to resume + # @type: float + # @from: automatically determined during restart + [diagnostics] # Number of timesteps between diagnostic logs: # @type: int: > 0 diff --git a/src/checkpoint/reader.cpp b/src/checkpoint/reader.cpp new file mode 100644 index 000000000..e69de29bb diff --git a/src/checkpoint/reader.h b/src/checkpoint/reader.h new file mode 100644 index 000000000..ea8653e72 --- /dev/null +++ b/src/checkpoint/reader.h @@ -0,0 +1,19 @@ +/** + * @file checkpoint/reader.h + * @brief Class that reads checkpoints + * @implements + * - checkpoint::Reader + * @cpp: + * - reader.cpp + * @namespaces: + * - checkpoint:: + */ + +#ifndef CHECKPOINT_READER_H +#define CHECKPOINT_READER_H + +namespace checkpoint { + class Reader {}; +} // namespace checkpoint + +#endif // CHECKPOINT_READER_H diff --git a/src/checkpoint/writer.cpp b/src/checkpoint/writer.cpp index 53b2b2821..c584d13fe 100644 --- a/src/checkpoint/writer.cpp +++ b/src/checkpoint/writer.cpp @@ -196,14 +196,16 @@ namespace checkpoint { m_writer.Put(var, &data); } - void Writer::saveAttrs(const ntt::SimulationParams& params) { + void Writer::saveAttrs(const ntt::SimulationParams& params, long double time) { CallOnce([&]() { std::ofstream metadata; if (m_written.empty()) { raise::Fatal("No checkpoint file to save metadata", HERE); } metadata.open(m_written.back().second.c_str()); - metadata << params.data() << std::endl; + metadata << "[metadata]\n" + << " time = " << time << "\n\n" + << params.data() << std::endl; metadata.close(); }); } diff --git a/src/checkpoint/writer.h b/src/checkpoint/writer.h index c9fc8a7db..a23ab556a 100644 --- a/src/checkpoint/writer.h +++ b/src/checkpoint/writer.h @@ -6,7 +6,7 @@ * @cpp: * - writer.cpp * @namespaces: - * - save:: + * - checkpoint:: */ #ifndef CHECKPOINT_WRITER_H @@ -55,7 +55,7 @@ namespace checkpoint { void beginSaving(std::size_t, long double); void endSaving(); - void saveAttrs(const ntt::SimulationParams&); + void saveAttrs(const ntt::SimulationParams&, long double); template void savePerDomainVariable(const std::string&, std::size_t, std::size_t, T); diff --git a/src/engines/engine.hpp b/src/engines/engine.hpp index a2bb09c26..f1bb46e98 100644 --- a/src/engines/engine.hpp +++ b/src/engines/engine.hpp @@ -65,11 +65,14 @@ namespace ntt { Metadomain m_metadomain; user::PGen m_pgen; + const bool is_resuming; const long double runtime; const real_t dt; const std::size_t max_steps; - long double time { 0.0 }; - std::size_t step { 0 }; + const std::size_t start_step; + const long double start_time; + long double time; + std::size_t step; public: static constexpr bool pgen_is_ok { @@ -81,8 +84,8 @@ namespace ntt { static constexpr Dimension D { M::Dim }; static constexpr bool is_engine { true }; - Engine(const toml::value& raw_params) - : m_params { raw_params } + Engine(const SimulationParams& params) + : m_params { params } , m_metadomain { m_params.get("simulation.domain.number"), m_params.get>( "simulation.domain.decomposition"), @@ -98,9 +101,14 @@ namespace ntt { m_params.get>( "particles.species") } , m_pgen { m_params, m_metadomain } + , is_resuming { m_params.get("checkpoint.is_resuming") } , runtime { m_params.get("simulation.runtime") } , dt { m_params.get("algorithms.timestep.dt") } - , max_steps { static_cast(runtime / dt) } { + , max_steps { static_cast(runtime / dt) } + , start_step { m_params.get("checkpoint.start_step") } + , start_time { m_params.get("checkpoint.start_time") } + , time { start_time } + , step { start_step } { raise::ErrorIf(not pgen_is_ok, "Problem generator is not compatible with the picked engine/metric/dimension", HERE); print_report(); } diff --git a/src/engines/engine_init.cpp b/src/engines/engine_init.cpp index 926bb3f78..5a8a693b0 100644 --- a/src/engines/engine_init.cpp +++ b/src/engines/engine_init.cpp @@ -22,29 +22,32 @@ namespace ntt { void Engine::init() { if constexpr (pgen_is_ok) { #if defined(OUTPUT_ENABLED) - m_metadomain.InitWriter(&m_adios, m_params); + m_metadomain.InitWriter(&m_adios, m_params, is_resuming); m_metadomain.InitCheckpointWriter(&m_adios, m_params); #endif logger::Checkpoint("Initializing Engine", HERE); - if constexpr ( - traits::has_member>::value) { - logger::Checkpoint("Initializing fields from problem generator", HERE); - m_metadomain.runOnLocalDomains([&](auto& loc_dom) { - Kokkos::parallel_for( - "InitFields", - loc_dom.mesh.rangeActiveCells(), - arch::SetEMFields_kernel { - loc_dom.fields.em, - m_pgen.init_flds, - loc_dom.mesh.metric }); - }); - } - if constexpr ( - traits::has_member>::value) { - logger::Checkpoint("Initializing particles from problem generator", HERE); - m_metadomain.runOnLocalDomains([&](auto& loc_dom) { - m_pgen.InitPrtls(loc_dom); - }); + if (not is_resuming) { + if constexpr ( + traits::has_member>::value) { + logger::Checkpoint("Initializing fields from problem generator", HERE); + m_metadomain.runOnLocalDomains([&](auto& loc_dom) { + Kokkos::parallel_for( + "InitFields", + loc_dom.mesh.rangeActiveCells(), + arch::SetEMFields_kernel { + loc_dom.fields.em, + m_pgen.init_flds, + loc_dom.mesh.metric }); + }); + } + if constexpr ( + traits::has_member>::value) { + logger::Checkpoint("Initializing particles from problem generator", HERE); + m_metadomain.runOnLocalDomains([&](auto& loc_dom) { + m_pgen.InitPrtls(loc_dom); + }); + } + } else { } } } diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index a20fc2a86..d082d617f 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -18,6 +18,7 @@ #include "utils/toml.h" #include "framework/domain/domain.h" +#include "framework/parameters.h" #include "engines/engine.hpp" @@ -33,7 +34,7 @@ namespace ntt { public: static constexpr auto S { SimEngine::SRPIC }; - GRPICEngine(const toml::value& raw_data) : base_t { raw_data } {} + GRPICEngine(const SimulationParams& params) : base_t { params } {} ~GRPICEngine() = default; diff --git a/src/engines/srpic.hpp b/src/engines/srpic.hpp index 6f1a0d561..9b8b3f19b 100644 --- a/src/engines/srpic.hpp +++ b/src/engines/srpic.hpp @@ -71,7 +71,7 @@ namespace ntt { public: static constexpr auto S { SimEngine::SRPIC }; - SRPICEngine(const toml::value& raw_data) : base_t { raw_data } {} + SRPICEngine(const SimulationParams& params) : base_t { params } {} ~SRPICEngine() = default; diff --git a/src/framework/CMakeLists.txt b/src/framework/CMakeLists.txt index 8bfbf1430..241780575 100644 --- a/src/framework/CMakeLists.txt +++ b/src/framework/CMakeLists.txt @@ -49,6 +49,7 @@ if(${output}) endif() add_dependencies(ntt_framework ${libs}) target_link_libraries(ntt_framework PUBLIC ${libs}) +target_link_libraries(ntt_framework PRIVATE stdc++fs) target_include_directories(ntt_framework PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../ diff --git a/src/framework/domain/checkpoint.cpp b/src/framework/domain/checkpoint.cpp index a5a77bf4d..569a61093 100644 --- a/src/framework/domain/checkpoint.cpp +++ b/src/framework/domain/checkpoint.cpp @@ -73,7 +73,7 @@ namespace ntt { g_checkpoint_writer.beginSaving(step, time); { - g_checkpoint_writer.saveAttrs(params); + g_checkpoint_writer.saveAttrs(params, time); g_checkpoint_writer.saveField("em", local_domain->fields.em); if constexpr (S == SimEngine::GRPIC) { diff --git a/src/framework/domain/metadomain.h b/src/framework/domain/metadomain.h index 072a4183f..6a3c64742 100644 --- a/src/framework/domain/metadomain.h +++ b/src/framework/domain/metadomain.h @@ -115,7 +115,7 @@ namespace ntt { ~Metadomain() = default; #if defined(OUTPUT_ENABLED) - void InitWriter(adios2::ADIOS*, const SimulationParams&); + void InitWriter(adios2::ADIOS*, const SimulationParams&, bool is_resuming); auto Write(const SimulationParams&, std::size_t, long double, @@ -125,6 +125,8 @@ namespace ntt { const Domain&)> = {}) -> bool; void InitCheckpointWriter(adios2::ADIOS*, const SimulationParams&); auto WriteCheckpoint(const SimulationParams&, std::size_t, long double) -> bool; + + void ContinueFromCheckpoint(); #endif /* setters -------------------------------------------------------------- */ diff --git a/src/framework/domain/output.cpp b/src/framework/domain/output.cpp index c79b284d5..e4e9b3e4b 100644 --- a/src/framework/domain/output.cpp +++ b/src/framework/domain/output.cpp @@ -34,7 +34,8 @@ namespace ntt { template void Metadomain::InitWriter(adios2::ADIOS* ptr_adios, - const SimulationParams& params) { + const SimulationParams& params, + bool is_resuming) { raise::ErrorIf( local_subdomain_indices().size() != 1, "Output for now is only supported for one subdomain per rank", @@ -43,7 +44,6 @@ namespace ntt { raise::ErrorIf(local_domain->is_placeholder(), "local_domain is a placeholder", HERE); - const auto incl_ghosts = params.template get("output.debug.ghosts"); auto glob_shape_with_ghosts = mesh().n_active(); @@ -91,7 +91,11 @@ namespace ntt { params.template get( "output." + std::string(type) + ".interval_time")); } - g_writer.writeAttrs(params); + if (is_resuming) { + g_writer.setMode(adios2::Mode::Append); + } else { + g_writer.writeAttrs(params); + } } template diff --git a/src/framework/parameters.cpp b/src/framework/parameters.cpp index e161c8ad5..12f4d2ffa 100644 --- a/src/framework/parameters.cpp +++ b/src/framework/parameters.cpp @@ -45,13 +45,13 @@ namespace ntt { return { dx0, V0 }; } - SimulationParams::SimulationParams(const toml::value& toml_data) - : raw_data { toml_data } { + /* + * . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + * Parameters that must not be changed during after the checkpoint restart + * . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + */ + void SimulationParams::setImmutableParams(const toml::value& toml_data) { /* [simulation] --------------------------------------------------------- */ - set("simulation.name", toml::find(raw_data, "simulation", "name")); - set("simulation.runtime", - toml::find(raw_data, "simulation", "runtime")); - const auto engine_enum = SimEngine::pick( fmt::toLower(toml::find(toml_data, "simulation", "engine")).c_str()); set("simulation.engine", engine_enum); @@ -62,7 +62,7 @@ namespace ntt { "MPI_Comm_size failed", HERE); #endif - const auto ndoms = toml::find_or(raw_data, + const auto ndoms = toml::find_or(toml_data, "simulation", "domain", "number", @@ -70,7 +70,7 @@ namespace ntt { set("simulation.domain.number", (unsigned int)ndoms); auto decomposition = toml::find_or>( - raw_data, + toml_data, "simulation", "domain", "decomposition", @@ -97,7 +97,7 @@ namespace ntt { HERE); set("simulation.domain.decomposition", decomposition); - auto extent = toml::find>>(raw_data, + auto extent = toml::find>>(toml_data, "grid", "extent"); raise::ErrorIf(extent.size() < 1 || extent.size() > 3, @@ -127,9 +127,9 @@ namespace ntt { HERE); coord = "qsph"; set("grid.metric.qsph_r0", - toml::find_or(raw_data, "grid", "metric", "qsph_r0", defaults::qsph::r0)); + toml::find_or(toml_data, "grid", "metric", "qsph_r0", defaults::qsph::r0)); set("grid.metric.qsph_h", - toml::find_or(raw_data, "grid", "metric", "qsph_h", defaults::qsph::h)); + toml::find_or(toml_data, "grid", "metric", "qsph_h", defaults::qsph::h)); } else { // spherical geometry raise::ErrorIf(dim == Dim::_1D, @@ -142,7 +142,7 @@ namespace ntt { } if ((engine_enum == SimEngine::GRPIC) && (metric_enum != Metric::Kerr_Schild_0)) { - const auto ks_a = toml::find_or(raw_data, + const auto ks_a = toml::find_or(toml_data, "grid", "metric", "ks_a", @@ -153,9 +153,194 @@ namespace ntt { const auto coord_enum = Coord::pick(coord.c_str()); set("grid.metric.coord", coord_enum); + /* [scales] ------------------------------------------------------------- */ + const auto larmor0 = toml::find(toml_data, "scales", "larmor0"); + const auto skindepth0 = toml::find(toml_data, "scales", "skindepth0"); + raise::ErrorIf(larmor0 <= ZERO || skindepth0 <= ZERO, + "larmor0 and skindepth0 must be positive", + HERE); + set("scales.larmor0", larmor0); + set("scales.skindepth0", skindepth0); + promiseToDefine("scales.dx0"); + promiseToDefine("scales.V0"); + promiseToDefine("scales.n0"); + promiseToDefine("scales.q0"); + set("scales.sigma0", SQR(skindepth0 / larmor0)); + set("scales.B0", ONE / larmor0); + set("scales.omegaB0", ONE / larmor0); + + /* [particles] ---------------------------------------------------------- */ + const auto ppc0 = toml::find(toml_data, "particles", "ppc0"); + set("particles.ppc0", ppc0); + raise::ErrorIf(ppc0 <= 0.0, "ppc0 must be positive", HERE); + set("particles.use_weights", + toml::find_or(toml_data, "particles", "use_weights", false)); + + /* [particles.species] -------------------------------------------------- */ + std::vector species; + const auto species_tab = toml::find_or(toml_data, + "particles", + "species", + toml::array {}); + set("particles.nspec", species_tab.size()); + + unsigned short idx = 1; + for (const auto& sp : species_tab) { + const auto label = toml::find_or(sp, + "label", + "s" + std::to_string(idx)); + const auto mass = toml::find(sp, "mass"); + const auto charge = toml::find(sp, "charge"); + raise::ErrorIf((charge != 0.0f) && (mass == 0.0f), + "mass of the charged species must be non-zero", + HERE); + const auto is_massless = (mass == 0.0f) && (charge == 0.0f); + const auto def_pusher = (is_massless ? defaults::ph_pusher + : defaults::em_pusher); + const auto maxnpart_real = toml::find(sp, "maxnpart"); + const auto maxnpart = static_cast(maxnpart_real); + auto pusher = toml::find_or(sp, "pusher", std::string(def_pusher)); + const auto npayloads = toml::find_or(sp, + "n_payloads", + static_cast(0)); + const auto cooling = toml::find_or(sp, "cooling", std::string("None")); + raise::ErrorIf((fmt::toLower(cooling) != "none") && is_massless, + "cooling is only applicable to massive particles", + HERE); + raise::ErrorIf((fmt::toLower(pusher) == "photon") && !is_massless, + "photon pusher is only applicable to massless particles", + HERE); + bool use_gca = false; + if (pusher.find(',') != std::string::npos) { + raise::ErrorIf(fmt::toLower(pusher.substr(pusher.find(',') + 1, + pusher.size())) != "gca", + "invalid pusher syntax", + HERE); + use_gca = true; + pusher = pusher.substr(0, pusher.find(',')); + } + const auto pusher_enum = PrtlPusher::pick(pusher.c_str()); + const auto cooling_enum = Cooling::pick(cooling.c_str()); + if (use_gca) { + raise::ErrorIf(engine_enum != SimEngine::SRPIC, + "GCA pushers are only supported for SRPIC", + HERE); + promiseToDefine("algorithms.gca.e_ovr_b_max"); + promiseToDefine("algorithms.gca.larmor_max"); + } + if (cooling_enum == Cooling::SYNCHROTRON) { + raise::ErrorIf(engine_enum != SimEngine::SRPIC, + "Synchrotron cooling is only supported for SRPIC", + HERE); + promiseToDefine("algorithms.synchrotron.gamma_rad"); + } + + species.emplace_back(ParticleSpecies(idx, + label, + mass, + charge, + maxnpart, + pusher_enum, + use_gca, + cooling_enum, + npayloads)); + idx += 1; + } + set("particles.species", species); + + /* inferred variables --------------------------------------------------- */ + // extent + if (extent.size() > dim) { + extent.erase(extent.begin() + (std::size_t)(dim), extent.end()); + } + raise::ErrorIf(extent[0].size() != 2, "invalid `grid.extent[0]`", HERE); + if (coord_enum != Coord::Cart) { + raise::ErrorIf(extent.size() > 1, + "invalid `grid.extent` for non-cartesian geometry", + HERE); + extent.push_back({ ZERO, constant::PI }); + if (dim == Dim::_3D) { + extent.push_back({ ZERO, TWO * constant::PI }); + } + } + raise::ErrorIf(extent.size() != dim, "invalid inferred `grid.extent`", HERE); + boundaries_t extent_pairwise; + for (unsigned short d = 0; d < (unsigned short)dim; ++d) { + raise::ErrorIf(extent[d].size() != 2, + fmt::format("invalid inferred `grid.extent[%d]`", d), + HERE); + extent_pairwise.push_back({ extent[d][0], extent[d][1] }); + } + set("grid.extent", extent_pairwise); + + // metric, dx0, V0, n0, q0 + { + boundaries_t ext; + for (const auto& e : extent) { + ext.push_back({ e[0], e[1] }); + } + std::map params; + if (coord_enum == Coord::Qsph) { + params["r0"] = get("grid.metric.qsph_r0"); + params["h"] = get("grid.metric.qsph_h"); + } + if ((engine_enum == SimEngine::GRPIC) && + (metric_enum != Metric::Kerr_Schild_0)) { + params["a"] = get("grid.metric.ks_a"); + } + set("grid.metric.params", params); + + std::pair dx0_V0; + if (metric_enum == Metric::Minkowski) { + if (dim == Dim::_1D) { + dx0_V0 = get_dx0_V0>(res, ext, params); + } else if (dim == Dim::_2D) { + dx0_V0 = get_dx0_V0>(res, ext, params); + } else { + dx0_V0 = get_dx0_V0>(res, ext, params); + } + } else if (metric_enum == Metric::Spherical) { + dx0_V0 = get_dx0_V0>(res, ext, params); + } else if (metric_enum == Metric::QSpherical) { + dx0_V0 = get_dx0_V0>(res, ext, params); + } else if (metric_enum == Metric::Kerr_Schild) { + dx0_V0 = get_dx0_V0>(res, ext, params); + } else if (metric_enum == Metric::Kerr_Schild_0) { + dx0_V0 = get_dx0_V0>(res, ext, params); + } else if (metric_enum == Metric::QKerr_Schild) { + dx0_V0 = get_dx0_V0>(res, ext, params); + } + auto [dx0, V0] = dx0_V0; + set("scales.dx0", dx0); + set("scales.V0", V0); + set("scales.n0", ppc0 / V0); + set("scales.q0", V0 / (ppc0 * SQR(skindepth0))); + + set("grid.metric.metric", metric_enum); + set("algorithms.timestep.dt", get("algorithms.timestep.CFL") * dx0); + } + } + + /* + * . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + * Parameters that may be changed during after the checkpoint restart + * . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + */ + void SimulationParams::setMutableParams(const toml::value& toml_data) { + const auto engine_enum = get("simulation.engine"); + const auto coord_enum = get("grid.metric.coord"); + const auto dim = get("grid.dim"); + const auto extent_pairwise = get>("grid.extent"); + + /* [simulation] --------------------------------------------------------- */ + set("simulation.name", + toml::find(toml_data, "simulation", "name")); + set("simulation.runtime", + toml::find(toml_data, "simulation", "runtime")); + /* [grid.boundaraies] --------------------------------------------------- */ auto flds_bc = toml::find>>( - raw_data, + toml_data, "grid", "boundaries", "fields"); @@ -188,7 +373,7 @@ namespace ntt { } auto prtl_bc = toml::find>>( - raw_data, + toml_data, "grid", "boundaries", "particles"); @@ -220,41 +405,25 @@ namespace ntt { } } - /* [scales] ------------------------------------------------------------- */ - const auto larmor0 = toml::find(raw_data, "scales", "larmor0"); - const auto skindepth0 = toml::find(raw_data, "scales", "skindepth0"); - raise::ErrorIf(larmor0 <= ZERO || skindepth0 <= ZERO, - "larmor0 and skindepth0 must be positive", - HERE); - set("scales.larmor0", larmor0); - set("scales.skindepth0", skindepth0); - promiseToDefine("scales.dx0"); - promiseToDefine("scales.V0"); - promiseToDefine("scales.n0"); - promiseToDefine("scales.q0"); - set("scales.sigma0", SQR(skindepth0 / larmor0)); - set("scales.B0", ONE / larmor0); - set("scales.omegaB0", ONE / larmor0); - /* [algorithms] --------------------------------------------------------- */ set("algorithms.current_filters", - toml::find_or(raw_data, + toml::find_or(toml_data, "algorithms", "current_filters", defaults::current_filters)); /* [algorithms.toggles] ------------------------------------------------- */ set("algorithms.toggles.fieldsolver", - toml::find_or(raw_data, "algorithms", "toggles", "fieldsolver", true)); + toml::find_or(toml_data, "algorithms", "toggles", "fieldsolver", true)); set("algorithms.toggles.deposit", - toml::find_or(raw_data, "algorithms", "toggles", "deposit", true)); + toml::find_or(toml_data, "algorithms", "toggles", "deposit", true)); /* [algorithms.timestep] ------------------------------------------------ */ set("algorithms.timestep.CFL", - toml::find_or(raw_data, "algorithms", "timestep", "CFL", defaults::cfl)); + toml::find_or(toml_data, "algorithms", "timestep", "CFL", defaults::cfl)); promiseToDefine("algorithms.timestep.dt"); set("algorithms.timestep.correction", - toml::find_or(raw_data, + toml::find_or(toml_data, "algorithms", "timestep", "correction", @@ -263,116 +432,37 @@ namespace ntt { /* [algorithms.gr] ------------------------------------------------------ */ if (engine_enum == SimEngine::GRPIC) { set("algorithms.gr.pusher_eps", - toml::find_or(raw_data, + toml::find_or(toml_data, "algorithms", "gr", "pusher_eps", defaults::gr::pusher_eps)); set("algorithms.gr.pusher_niter", - toml::find_or(raw_data, + toml::find_or(toml_data, "algorithms", "gr", "pusher_niter", defaults::gr::pusher_niter)); } - /* [particles] ---------------------------------------------------------- */ - const auto ppc0 = toml::find(raw_data, "particles", "ppc0"); - set("particles.ppc0", ppc0); - raise::ErrorIf(ppc0 <= 0.0, "ppc0 must be positive", HERE); - set("particles.use_weights", - toml::find_or(raw_data, "particles", "use_weights", false)); - #if defined(MPI_ENABLED) const std::size_t sort_interval = 1; #else - const std::size_t sort_interval = toml::find_or(raw_data, + const std::size_t sort_interval = toml::find_or(toml_data, "particles", "sort_interval", defaults::sort_interval); #endif set("particles.sort_interval", sort_interval); - /* [particles.species] -------------------------------------------------- */ - std::vector species; - const auto species_tab = toml::find_or(raw_data, - "particles", - "species", - toml::array {}); - set("particles.nspec", species_tab.size()); - - unsigned short idx = 1; - for (const auto& sp : species_tab) { - const auto label = toml::find_or(sp, - "label", - "s" + std::to_string(idx)); - const auto mass = toml::find(sp, "mass"); - const auto charge = toml::find(sp, "charge"); - raise::ErrorIf((charge != 0.0f) && (mass == 0.0f), - "mass of the charged species must be non-zero", - HERE); - const auto is_massless = (mass == 0.0f) && (charge == 0.0f); - const auto def_pusher = (is_massless ? defaults::ph_pusher - : defaults::em_pusher); - const auto maxnpart_real = toml::find(sp, "maxnpart"); - const auto maxnpart = static_cast(maxnpart_real); - auto pusher = toml::find_or(sp, "pusher", std::string(def_pusher)); - const auto npayloads = toml::find_or(sp, - "n_payloads", - static_cast(0)); - const auto cooling = toml::find_or(sp, "cooling", std::string("None")); - raise::ErrorIf((fmt::toLower(cooling) != "none") && is_massless, - "cooling is only applicable to massive particles", - HERE); - raise::ErrorIf((fmt::toLower(pusher) == "photon") && !is_massless, - "photon pusher is only applicable to massless particles", - HERE); - bool use_gca = false; - if (pusher.find(',') != std::string::npos) { - raise::ErrorIf(fmt::toLower(pusher.substr(pusher.find(',') + 1, - pusher.size())) != "gca", - "invalid pusher syntax", - HERE); - use_gca = true; - pusher = pusher.substr(0, pusher.find(',')); - } - const auto pusher_enum = PrtlPusher::pick(pusher.c_str()); - const auto cooling_enum = Cooling::pick(cooling.c_str()); - if (use_gca) { - raise::ErrorIf(engine_enum != SimEngine::SRPIC, - "GCA pushers are only supported for SRPIC", - HERE); - promiseToDefine("algorithms.gca.e_ovr_b_max"); - promiseToDefine("algorithms.gca.larmor_max"); - } - if (cooling_enum == Cooling::SYNCHROTRON) { - raise::ErrorIf(engine_enum != SimEngine::SRPIC, - "Synchrotron cooling is only supported for SRPIC", - HERE); - promiseToDefine("algorithms.synchrotron.gamma_rad"); - } - - species.emplace_back(ParticleSpecies(idx, - label, - mass, - charge, - maxnpart, - pusher_enum, - use_gca, - cooling_enum, - npayloads)); - idx += 1; - } - set("particles.species", species); - /* [output] ------------------------------------------------------------- */ // fields set("output.format", - toml::find_or(raw_data, "output", "format", defaults::output::format)); + toml::find_or(toml_data, "output", "format", defaults::output::format)); set("output.interval", - toml::find_or(raw_data, "output", "interval", defaults::output::interval)); + toml::find_or(toml_data, "output", "interval", defaults::output::interval)); set("output.interval_time", - toml::find_or(raw_data, "output", "interval_time", -1.0)); + toml::find_or(toml_data, "output", "interval_time", -1.0)); promiseToDefine("output.fields.interval"); promiseToDefine("output.fields.interval_time"); promiseToDefine("output.fields.enable"); @@ -383,12 +473,12 @@ namespace ntt { promiseToDefine("output.spectra.interval_time"); promiseToDefine("output.spectra.enable"); - const auto flds_out = toml::find_or(raw_data, + const auto flds_out = toml::find_or(toml_data, "output", "fields", "quantities", std::vector {}); - const auto custom_flds_out = toml::find_or(raw_data, + const auto custom_flds_out = toml::find_or(toml_data, "output", "fields", "custom", @@ -399,23 +489,27 @@ namespace ntt { set("output.fields.quantities", flds_out); set("output.fields.custom", custom_flds_out); set("output.fields.mom_smooth", - toml::find_or(raw_data, + toml::find_or(toml_data, "output", "fields", "mom_smooth", defaults::output::mom_smooth)); set("output.fields.stride", - toml::find_or(raw_data, "output", "fields", "stride", defaults::output::flds_stride)); + toml::find_or(toml_data, + "output", + "fields", + "stride", + defaults::output::flds_stride)); // particles - const auto prtl_out = toml::find_or(raw_data, + const auto prtl_out = toml::find_or(toml_data, "output", "particles", "species", std::vector {}); set("output.particles.species", prtl_out); set("output.particles.stride", - toml::find_or(raw_data, + toml::find_or(toml_data, "output", "particles", "stride", @@ -423,32 +517,36 @@ namespace ntt { // spectra set("output.spectra.e_min", - toml::find_or(raw_data, "output", "spectra", "e_min", defaults::output::spec_emin)); + toml::find_or(toml_data, "output", "spectra", "e_min", defaults::output::spec_emin)); set("output.spectra.e_max", - toml::find_or(raw_data, "output", "spectra", "e_max", defaults::output::spec_emax)); + toml::find_or(toml_data, "output", "spectra", "e_max", defaults::output::spec_emax)); set("output.spectra.log_bins", - toml::find_or(raw_data, + toml::find_or(toml_data, "output", "spectra", "log_bins", defaults::output::spec_log)); set("output.spectra.n_bins", - toml::find_or(raw_data, "output", "spectra", "n_bins", defaults::output::spec_nbins)); + toml::find_or(toml_data, + "output", + "spectra", + "n_bins", + defaults::output::spec_nbins)); // intervals for (const auto& type : { "fields", "particles", "spectra" }) { - const auto q_int = toml::find_or(raw_data, + const auto q_int = toml::find_or(toml_data, "output", std::string(type), "interval", 0); - const auto q_int_time = toml::find_or(raw_data, + const auto q_int_time = toml::find_or(toml_data, "output", std::string(type), "interval_time", -1.0); set("output." + std::string(type) + ".enable", - toml::find_or(raw_data, "output", std::string(type), "enable", true)); + toml::find_or(toml_data, "output", std::string(type), "enable", true)); if (q_int == 0 && q_int_time == -1.0) { set("output." + std::string(type) + ".interval", get("output.interval")); @@ -462,51 +560,30 @@ namespace ntt { /* [output.debug] ------------------------------------------------------- */ set("output.debug.as_is", - toml::find_or(raw_data, "output", "debug", "as_is", false)); + toml::find_or(toml_data, "output", "debug", "as_is", false)); set("output.debug.ghosts", - toml::find_or(raw_data, "output", "debug", "ghosts", false)); + toml::find_or(toml_data, "output", "debug", "ghosts", false)); /* [checkpoint] --------------------------------------------------------- */ set("checkpoint.interval", - toml::find_or(raw_data, "checkpoint", "interval", defaults::checkpoint::interval)); + toml::find_or(toml_data, + "checkpoint", + "interval", + defaults::checkpoint::interval)); set("checkpoint.interval_time", - toml::find_or(raw_data, "checkpoint", "interval_time", -1.0)); + toml::find_or(toml_data, "checkpoint", "interval_time", -1.0)); set("checkpoint.keep", - toml::find_or(raw_data, "checkpoint", "keep", defaults::checkpoint::keep)); + toml::find_or(toml_data, "checkpoint", "keep", defaults::checkpoint::keep)); /* [diagnostics] -------------------------------------------------------- */ set("diagnostics.interval", - toml::find_or(raw_data, "diagnostics", "interval", defaults::diag::interval)); + toml::find_or(toml_data, "diagnostics", "interval", defaults::diag::interval)); set("diagnostics.blocking_timers", - toml::find_or(raw_data, "diagnostics", "blocking_timers", false)); + toml::find_or(toml_data, "diagnostics", "blocking_timers", false)); set("diagnostics.colored_stdout", - toml::find_or(raw_data, "diagnostics", "colored_stdout", false)); + toml::find_or(toml_data, "diagnostics", "colored_stdout", false)); /* inferred variables --------------------------------------------------- */ - // extent - if (extent.size() > dim) { - extent.erase(extent.begin() + (std::size_t)(dim), extent.end()); - } - raise::ErrorIf(extent[0].size() != 2, "invalid `grid.extent[0]`", HERE); - if (coord_enum != Coord::Cart) { - raise::ErrorIf(extent.size() > 1, - "invalid `grid.extent` for non-cartesian geometry", - HERE); - extent.push_back({ ZERO, constant::PI }); - if (dim == Dim::_3D) { - extent.push_back({ ZERO, TWO * constant::PI }); - } - } - raise::ErrorIf(extent.size() != dim, "invalid inferred `grid.extent`", HERE); - boundaries_t extent_parwise; - for (unsigned short d = 0; d < (unsigned short)dim; ++d) { - raise::ErrorIf(extent[d].size() != 2, - fmt::format("invalid inferred `grid.extent[%d]`", d), - HERE); - extent_parwise.push_back({ extent[d][0], extent[d][1] }); - } - set("grid.extent", extent_parwise); - // fields/particle boundaries std::vector> flds_bc_enum; std::vector> prtl_bc_enum; @@ -637,20 +714,20 @@ namespace ntt { if (isPromised("grid.boundaries.absorb.ds")) { if (coord_enum == Coord::Cart) { auto min_extent = std::numeric_limits::max(); - for (const auto& e : extent) { - min_extent = std::min(min_extent, e[1] - e[0]); + for (const auto& e : extent_pairwise) { + min_extent = std::min(min_extent, e.second - e.first); } set("grid.boundaries.absorb.ds", - toml::find_or(raw_data, + toml::find_or(toml_data, "grid", "boundaries", "absorb", "ds", min_extent * defaults::bc::absorb::ds_frac)); } else { - auto r_extent = extent[0][1] - extent[0][0]; + auto r_extent = extent_pairwise[0].second - extent_pairwise[0].first; set("grid.boundaries.absorb.ds", - toml::find_or(raw_data, + toml::find_or(toml_data, "grid", "boundaries", "absorb", @@ -658,7 +735,7 @@ namespace ntt { r_extent * defaults::bc::absorb::ds_frac)); } set("grid.boundaries.absorb.coeff", - toml::find_or(raw_data, + toml::find_or(toml_data, "grid", "boundaries", "absorb", @@ -667,25 +744,25 @@ namespace ntt { } if (isPromised("grid.boundaries.atmosphere.temperature")) { - const auto atm_T = toml::find(raw_data, + const auto atm_T = toml::find(toml_data, "grid", "boundaries", "atmosphere", "temperature"); - const auto atm_h = toml::find(raw_data, + const auto atm_h = toml::find(toml_data, "grid", "boundaries", "atmosphere", "height"); set("grid.boundaries.atmosphere.temperature", atm_T); set("grid.boundaries.atmosphere.density", - toml::find(raw_data, "grid", "boundaries", "atmosphere", "density")); + toml::find(toml_data, "grid", "boundaries", "atmosphere", "density")); set("grid.boundaries.atmosphere.ds", - toml::find_or(raw_data, "grid", "boundaries", "atmosphere", "ds", ZERO)); + toml::find_or(toml_data, "grid", "boundaries", "atmosphere", "ds", ZERO)); set("grid.boundaries.atmosphere.height", atm_h); set("grid.boundaries.atmosphere.g", atm_T / atm_h); const auto atm_species = toml::find>( - raw_data, + toml_data, "grid", "boundaries", "atmosphere", @@ -696,76 +773,27 @@ namespace ntt { // gca if (isPromised("algorithms.gca.e_ovr_b_max")) { set("algorithms.gca.e_ovr_b_max", - toml::find_or(raw_data, + toml::find_or(toml_data, "algorithms", "gca", "e_ovr_b_max", defaults::gca::EovrB_max)); set("algorithms.gca.larmor_max", - toml::find_or(raw_data, "algorithms", "gca", "larmor_max", ZERO)); + toml::find_or(toml_data, "algorithms", "gca", "larmor_max", ZERO)); } // cooling if (isPromised("algorithms.synchrotron.gamma_rad")) { set("algorithms.synchrotron.gamma_rad", - toml::find_or(raw_data, + toml::find_or(toml_data, "algorithms", "synchrotron", "gamma_rad", defaults::synchrotron::gamma_rad)); } + } - // metric, dx0, V0, n0, q0 - { - boundaries_t ext; - for (const auto& e : extent) { - ext.push_back({ e[0], e[1] }); - } - std::map params; - if (coord_enum == Coord::Qsph) { - params["r0"] = get("grid.metric.qsph_r0"); - params["h"] = get("grid.metric.qsph_h"); - } - if ((engine_enum == SimEngine::GRPIC) && - (metric_enum != Metric::Kerr_Schild_0)) { - params["a"] = get("grid.metric.ks_a"); - } - set("grid.metric.params", params); - - std::pair dx0_V0; - if (metric_enum == Metric::Minkowski) { - if (dim == Dim::_1D) { - dx0_V0 = get_dx0_V0>(res, ext, params); - } else if (dim == Dim::_2D) { - dx0_V0 = get_dx0_V0>(res, ext, params); - } else { - dx0_V0 = get_dx0_V0>(res, ext, params); - } - } else if (metric_enum == Metric::Spherical) { - dx0_V0 = get_dx0_V0>(res, ext, params); - } else if (metric_enum == Metric::QSpherical) { - dx0_V0 = get_dx0_V0>(res, ext, params); - } else if (metric_enum == Metric::Kerr_Schild) { - dx0_V0 = get_dx0_V0>(res, ext, params); - } else if (metric_enum == Metric::Kerr_Schild_0) { - dx0_V0 = get_dx0_V0>(res, ext, params); - } else if (metric_enum == Metric::QKerr_Schild) { - dx0_V0 = get_dx0_V0>(res, ext, params); - } - auto [dx0, V0] = dx0_V0; - set("scales.dx0", dx0); - set("scales.V0", V0); - set("scales.n0", ppc0 / V0); - set("scales.q0", V0 / (ppc0 * SQR(skindepth0))); - - set("grid.metric.metric", metric_enum); - set("algorithms.timestep.dt", get("algorithms.timestep.CFL") * dx0); - } - - raise::ErrorIf(!promisesFulfilled(), - "Have not defined all the necessary variables", - HERE); - + void SimulationParams::setSetupParams(const toml::value& toml_data) { /* [setup] -------------------------------------------------------------- */ const auto& setup = toml::find_or(raw_data, "setup", toml::table {}); for (const auto& [key, val] : setup) { @@ -815,4 +843,18 @@ namespace ntt { } } } + + void SimulationParams::setCheckpointParams(bool is_resuming, + std::size_t start_step, + long double start_time) { + set("checkpoint.is_resuming", is_resuming); + set("checkpoint.start_step", start_step); + set("checkpoint.start_time", start_time); + } + + void SimulationParams::checkPromises() const { + raise::ErrorIf(!promisesFulfilled(), + "Have not defined all the necessary variables", + HERE); + } } // namespace ntt diff --git a/src/framework/parameters.h b/src/framework/parameters.h index afa730bcd..2c03ef812 100644 --- a/src/framework/parameters.h +++ b/src/framework/parameters.h @@ -25,7 +25,6 @@ namespace ntt { struct SimulationParams : public prm::Parameters { SimulationParams() = default; - SimulationParams(const toml::value&); SimulationParams& operator=(const SimulationParams& other) { vars = std::move(other.vars); @@ -36,11 +35,21 @@ namespace ntt { ~SimulationParams() = default; + void setImmutableParams(const toml::value&); + void setMutableParams(const toml::value&); + void setCheckpointParams(bool, std::size_t, long double); + void setSetupParams(const toml::value&); + void checkPromises() const; + [[nodiscard]] auto data() const -> const toml::value& { return raw_data; } + void setRawData(const toml::value& data) { + raw_data = data; + } + private: toml::value raw_data; }; diff --git a/src/framework/simulation.cpp b/src/framework/simulation.cpp index 7cf989872..74798ffa6 100644 --- a/src/framework/simulation.cpp +++ b/src/framework/simulation.cpp @@ -7,26 +7,30 @@ #include "utils/cargs.h" #include "utils/error.h" #include "utils/formatting.h" +#include "utils/log.h" #include "utils/plog.h" #include "utils/toml.h" #include "framework/parameters.h" +#include #include namespace ntt { Simulation::Simulation(int argc, char* argv[]) { - GlobalInitialize(argc, argv); - cargs::CommandLineArguments cl_args; cl_args.readCommandLineArguments(argc, argv); const auto inputfname = static_cast( cl_args.getArgument("-input", defaults::input_filename)); - const auto outputdir = static_cast( - cl_args.getArgument("-output", defaults::output_path)); - raw_params = toml::parse(inputfname); + const bool is_resuming = (cl_args.isSpecified("-continue") or + cl_args.isSpecified("-restart") or + cl_args.isSpecified("-resume") or + cl_args.isSpecified("-checkpoint")); + GlobalInitialize(argc, argv); + + const auto raw_params = toml::parse(inputfname); const auto sim_name = toml::find(raw_params, "simulation", "name"); logger::initPlog(sim_name); @@ -43,6 +47,49 @@ namespace ntt { "invalid `grid.resolution`", HERE); m_requested_dimension = static_cast(res.size()); + + // !TODO: when mixing checkpoint metadata with input, + // ... need to properly take care of the diffs + m_params.setRawData(raw_params); + std::size_t checkpoint_step = 0; + if (is_resuming) { + if (not std::filesystem::exists("checkpoints")) { + raise::Fatal("No checkpoints found", HERE); + } + for (const auto& entry : + std::filesystem::directory_iterator("checkpoints")) { + const auto fname = entry.path().filename().string(); + if (fname.find("step-") == 0) { + const std::size_t step = std::stoi(fname.substr(5, fname.size() - 5 - 3)); + if (step > checkpoint_step) { + checkpoint_step = step; + } + } + } + std::string checkpoint_inputfname = fmt::format( + "checkpoints/meta-%08lu.toml", + checkpoint_step); + if (not std::filesystem::exists(checkpoint_inputfname)) { + raise::Fatal( + fmt::format("metainformation for %lu not found", checkpoint_step), + HERE); + checkpoint_inputfname = inputfname; + } + const auto raw_checkpoint_params = toml::parse(checkpoint_inputfname); + const auto start_time = toml::find(raw_checkpoint_params, + "metadata", + "time"); + m_params.setImmutableParams(raw_checkpoint_params); + m_params.setMutableParams(raw_params); + m_params.setCheckpointParams(true, checkpoint_step, start_time); + m_params.setSetupParams(raw_checkpoint_params); + } else { + m_params.setImmutableParams(raw_params); + m_params.setMutableParams(raw_params); + m_params.setCheckpointParams(false, 0, 0.0); + m_params.setSetupParams(raw_params); + } + m_params.checkPromises(); } Simulation::~Simulation() { diff --git a/src/framework/simulation.h b/src/framework/simulation.h index c069aa484..3cc664995 100644 --- a/src/framework/simulation.h +++ b/src/framework/simulation.h @@ -28,7 +28,7 @@ namespace ntt { class Simulation { - toml::value raw_params; + SimulationParams m_params; Dimension m_requested_dimension; SimEngine m_requested_engine { SimEngine::INVALID }; @@ -46,7 +46,7 @@ namespace ntt { static_assert(traits::has_method::value, "Engine must contain a ::run() method"); try { - engine_t engine { raw_params }; + engine_t engine { m_params }; engine.run(); } catch (const std::exception& e) { raise::Fatal(e.what(), HERE); diff --git a/src/global/defaults.h b/src/global/defaults.h index b9eca9080..ee9a65af5 100644 --- a/src/global/defaults.h +++ b/src/global/defaults.h @@ -16,7 +16,6 @@ namespace ntt::defaults { constexpr std::string_view input_filename = "input"; - constexpr std::string_view output_path = "output"; const real_t correction = 1.0; const real_t cfl = 0.95; diff --git a/src/output/writer.cpp b/src/output/writer.cpp index 549f7a25d..37f574275 100644 --- a/src/output/writer.cpp +++ b/src/output/writer.cpp @@ -53,6 +53,10 @@ namespace out { } } + void Writer::setMode(adios2::Mode mode) { + m_mode = mode; + } + void Writer::defineMeshLayout(const std::vector& glob_shape, const std::vector& loc_corner, const std::vector& loc_shape, diff --git a/src/output/writer.h b/src/output/writer.h index 7a3ed43ba..39772e314 100644 --- a/src/output/writer.h +++ b/src/output/writer.h @@ -62,6 +62,8 @@ namespace out { void init(adios2::ADIOS*, const std::string&); + void setMode(adios2::Mode); + void addTracker(const std::string&, std::size_t, long double); auto shouldWrite(const std::string&, std::size_t, long double) -> bool; From 43d66a3366b96e0ea06275eeae8637c411883ea7 Mon Sep 17 00:00:00 2001 From: haykh Date: Fri, 16 Aug 2024 21:15:20 -0400 Subject: [PATCH 011/773] advanced diag output --- src/engines/engine_printer.cpp | 2 +- src/engines/engine_step_report.cpp | 241 ------------------------- src/global/CMakeLists.txt | 6 + src/global/arch/mpi_aliases.h | 3 +- src/global/global.h | 20 +-- src/global/utils/colors.h | 3 +- src/global/utils/diag.cpp | 246 +++++++++++++++++++++++++ src/global/utils/diag.h | 59 ++++++ src/global/utils/formatting.h | 62 +++++++ src/global/utils/log.h | 2 + src/global/utils/progressbar.cpp | 120 +++++++++++++ src/global/utils/progressbar.h | 106 ++--------- src/global/utils/timer.cpp | 279 +++++++++++++++++++++++++++++ src/global/utils/timer.h | 246 +++++-------------------- src/global/utils/tools.h | 27 +++ 15 files changed, 865 insertions(+), 557 deletions(-) delete mode 100644 src/engines/engine_step_report.cpp create mode 100644 src/global/utils/diag.cpp create mode 100644 src/global/utils/diag.h create mode 100644 src/global/utils/progressbar.cpp create mode 100644 src/global/utils/timer.cpp diff --git a/src/engines/engine_printer.cpp b/src/engines/engine_printer.cpp index 90dec3326..2608ea2f6 100644 --- a/src/engines/engine_printer.cpp +++ b/src/engines/engine_printer.cpp @@ -344,7 +344,7 @@ namespace ntt { for (unsigned int idx { 0 }; idx < m_metadomain.ndomains(); ++idx) { auto is_local = false; - for (const auto& lidx : m_metadomain.local_subdomain_indices()) { + for (const auto& lidx : m_metadomain.l_subdomain_indices()) { is_local |= (idx == lidx); } if (is_local) { diff --git a/src/engines/engine_step_report.cpp b/src/engines/engine_step_report.cpp deleted file mode 100644 index 7edeaab67..000000000 --- a/src/engines/engine_step_report.cpp +++ /dev/null @@ -1,241 +0,0 @@ -#include "enums.h" -#include "global.h" - -#include "arch/mpi_aliases.h" -#include "utils/colors.h" -#include "utils/formatting.h" -#include "utils/progressbar.h" -#include "utils/timer.h" - -#include "metrics/kerr_schild.h" -#include "metrics/kerr_schild_0.h" -#include "metrics/minkowski.h" -#include "metrics/qkerr_schild.h" -#include "metrics/qspherical.h" -#include "metrics/spherical.h" - -#include "engines/engine.hpp" - -#include -#include - -namespace ntt { - namespace {} // namespace - - template - void print_particles(const Metadomain&, - unsigned short, - DiagFlags, - std::ostream& = std::cout); - - template - void Engine::print_step_report(timer::Timers& timers, - pbar::DurationHistory& time_history, - bool print_output, - bool print_checkpoint, - bool print_sorting) const { - DiagFlags diag_flags = Diag::Default; - TimerFlags timer_flags = Timer::Default; - if (not m_params.get("diagnostics.colored_stdout")) { - diag_flags ^= Diag::Colorful; - timer_flags ^= Timer::Colorful; - } - if (m_params.get("particles.nspec") == 0) { - diag_flags ^= Diag::Species; - } - if (print_output) { - timer_flags |= Timer::PrintOutput; - } - if (print_checkpoint) { - timer_flags |= Timer::PrintCheckpoint; - } - if (print_sorting) { - timer_flags |= Timer::PrintSorting; - } - CallOnce( - [diag_flags](auto& time, auto& step, auto& max_steps, auto& dt) { - const auto c_bgreen = color::get_color("bgreen", - diag_flags & Diag::Colorful); - const auto c_bblack = color::get_color("bblack", - diag_flags & Diag::Colorful); - const auto c_reset = color::get_color("reset", diag_flags & Diag::Colorful); - std::cout << fmt::format("Step:%s %-8d%s %s[of %d]%s\n", - c_bgreen.c_str(), - step, - c_reset.c_str(), - c_bblack.c_str(), - max_steps, - c_reset.c_str()); - std::cout << fmt::format("Time:%s %-8.4f%s %s[Δt = %.4f]%s\n", - c_bgreen.c_str(), - (double)time, - c_reset.c_str(), - c_bblack.c_str(), - (double)dt, - c_reset.c_str()) - << std::endl; - }, - time, - step, - max_steps, - dt); - if (diag_flags & Diag::Timers) { - timers.printAll(timer_flags, std::cout); - } - CallOnce([]() { - std::cout << std::endl; - }); - if (diag_flags & Diag::Species) { - CallOnce([diag_flags]() { - std::cout << color::get_color("bblack", diag_flags & Diag::Colorful); -#if defined(MPI_ENABLED) - std::cout << "Particle count:" << std::setw(22) << std::right << "[TOT]" - << std::setw(20) << std::right << "[MIN (%)]" << std::setw(20) - << std::right << "[MAX (%)]"; -#else - std::cout << "Particle count:" << std::setw(25) << std::right - << "[TOT (%)]"; -#endif - std::cout << color::get_color("reset", diag_flags & Diag::Colorful) - << std::endl; - }); - for (std::size_t sp { 0 }; sp < m_metadomain.species_params().size(); ++sp) { - print_particles(m_metadomain, sp, diag_flags, std::cout); - } - CallOnce([]() { - std::cout << std::endl; - }); - } - if (diag_flags & Diag::Progress) { - pbar::ProgressBar(time_history, step, max_steps, diag_flags, std::cout); - } - CallOnce([]() { - std::cout << std::setw(80) << std::setfill('.') << "" << std::endl - << std::endl; - }); - } - - template - void print_particles(const Metadomain& md, - unsigned short sp, - DiagFlags flags, - std::ostream& os) { - - static_assert(M::is_metric, "template arg for Engine class has to be a metric"); - std::size_t npart { 0 }; - std::size_t maxnpart { 0 }; - std::string species_label; - int species_index; - // sum npart & maxnpart over all subdomains on the current rank - md.runOnLocalDomainsConst( - [&npart, &maxnpart, &species_label, &species_index, sp](auto& dom) { - npart += dom.species[sp].npart(); - maxnpart += dom.species[sp].maxnpart(); - species_label = dom.species[sp].label(); - species_index = dom.species[sp].index(); - }); -#if defined(MPI_ENABLED) - int rank, size; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - MPI_Comm_size(MPI_COMM_WORLD, &size); - std::vector mpi_npart(size, 0); - std::vector mpi_maxnpart(size, 0); - MPI_Gather(&npart, - 1, - mpi::get_type(), - mpi_npart.data(), - 1, - mpi::get_type(), - MPI_ROOT_RANK, - MPI_COMM_WORLD); - MPI_Gather(&maxnpart, - 1, - mpi::get_type(), - mpi_maxnpart.data(), - 1, - mpi::get_type(), - MPI_ROOT_RANK, - MPI_COMM_WORLD); - if (rank != MPI_ROOT_RANK) { - return; - } - auto tot_npart = std::accumulate(mpi_npart.begin(), mpi_npart.end(), 0); - std::size_t npart_max = *std::max_element(mpi_npart.begin(), mpi_npart.end()); - std::size_t npart_min = *std::min_element(mpi_npart.begin(), mpi_npart.end()); - std::vector mpi_load(size, 0.0); - for (auto r { 0 }; r < size; ++r) { - mpi_load[r] = 100.0 * (double)(mpi_npart[r]) / (double)(mpi_maxnpart[r]); - } - double load_max = *std::max_element(mpi_load.begin(), mpi_load.end()); - double load_min = *std::min_element(mpi_load.begin(), mpi_load.end()); - auto npart_min_str = npart_min > 9999 - ? fmt::format("%.2Le", (long double)npart_min) - : std::to_string(npart_min); - auto tot_npart_str = tot_npart > 9999 - ? fmt::format("%.2Le", (long double)tot_npart) - : std::to_string(tot_npart); - auto npart_max_str = npart_max > 9999 - ? fmt::format("%.2Le", (long double)npart_max) - : std::to_string(npart_max); - os << " species " << fmt::format("%2d", species_index) << " (" - << species_label << ")"; - - const auto c_bblack = color::get_color("bblack", flags & Diag::Colorful); - const auto c_red = color::get_color("red", flags & Diag::Colorful); - const auto c_yellow = color::get_color("yellow", flags & Diag::Colorful); - const auto c_green = color::get_color("green", flags & Diag::Colorful); - const auto c_reset = color::get_color("reset", flags & Diag::Colorful); - auto c_loadmin = (load_min > 80) ? c_red - : ((load_min > 50) ? c_yellow : c_green); - auto c_loadmax = (load_max > 80) ? c_red - : ((load_max > 50) ? c_yellow : c_green); - const auto raw1 = fmt::format("%s (%4.1f%%)", npart_min_str.c_str(), load_min); - const auto raw2 = fmt::format("%s (%4.1f%%)", npart_max_str.c_str(), load_max); - os << c_bblack - << fmt::pad(tot_npart_str, 20, '.', false).substr(0, 20 - tot_npart_str.size()) - << c_reset << tot_npart_str; - os << fmt::pad(raw1, 20, ' ', false).substr(0, 20 - raw1.size()) - << fmt::format("%s (%s%4.1f%%%s)", - npart_min_str.c_str(), - c_loadmin.c_str(), - load_min, - c_reset.c_str()); - os << fmt::pad(raw2, 20, ' ', false).substr(0, 20 - raw2.size()) - << fmt::format("%s (%s%4.1f%%%s)", - npart_max_str.c_str(), - c_loadmax.c_str(), - load_max, - c_reset.c_str()); -#else // not MPI_ENABLED - auto load = 100.0 * (double)(npart) / (double)(maxnpart); - auto npart_str = npart > 9999 ? fmt::format("%.2Le", (long double)npart) - : std::to_string(npart); - const auto c_bblack = color::get_color("bblack", flags & Diag::Colorful); - const auto c_red = color::get_color("red", flags & Diag::Colorful); - const auto c_yellow = color::get_color("yellow", flags & Diag::Colorful); - const auto c_green = color::get_color("green", flags & Diag::Colorful); - const auto c_reset = color::get_color("reset", flags & Diag::Colorful); - const auto c_load = (load > 80) - ? c_red.c_str() - : ((load > 50) ? c_yellow.c_str() : c_green.c_str()); - os << " species " << species_index << " (" << species_label << ")"; - const auto raw = fmt::format("%s (%4.1f%%)", npart_str.c_str(), load); - os << c_bblack << fmt::pad(raw, 24, '.').substr(0, 24 - raw.size()) << c_reset; - os << fmt::format("%s (%s%4.1f%%%s)", - npart_str.c_str(), - c_load, - load, - c_reset.c_str()); -#endif - os << std::endl; - } - - template class Engine>; - template class Engine>; - template class Engine>; - template class Engine>; - template class Engine>; - template class Engine>; - template class Engine>; - template class Engine>; -} // namespace ntt diff --git a/src/global/CMakeLists.txt b/src/global/CMakeLists.txt index f8bd7ab07..334ce078d 100644 --- a/src/global/CMakeLists.txt +++ b/src/global/CMakeLists.txt @@ -5,6 +5,9 @@ # - arch/kokkos_aliases.cpp # - utils/cargs.cpp # - utils/param_container.cpp +# - utils/timer.cpp +# - utils/diag.cpp +# - utils/progressbar.cpp # @includes: # - ./ # @uses: @@ -18,6 +21,9 @@ set(SOURCES ${SRC_DIR}/global.cpp ${SRC_DIR}/arch/kokkos_aliases.cpp ${SRC_DIR}/utils/cargs.cpp + ${SRC_DIR}/utils/timer.cpp + ${SRC_DIR}/utils/diag.cpp + ${SRC_DIR}/utils/progressbar.cpp ) if (${output}) list(APPEND SOURCES ${SRC_DIR}/utils/param_container.cpp) diff --git a/src/global/arch/mpi_aliases.h b/src/global/arch/mpi_aliases.h index 9669d6210..1f9a87f7b 100644 --- a/src/global/arch/mpi_aliases.h +++ b/src/global/arch/mpi_aliases.h @@ -14,6 +14,7 @@ #ifndef GLOBAL_ARCH_MPI_ALIASES_H #define GLOBAL_ARCH_MPI_ALIASES_H +#include #include #if defined(MPI_ENABLED) @@ -103,4 +104,4 @@ namespace mpi { #endif // MPI_ENABLED -#endif // GLOBAL_ARCH_MPI_ALIASES_H \ No newline at end of file +#endif // GLOBAL_ARCH_MPI_ALIASES_H diff --git a/src/global/global.h b/src/global/global.h index b3f640295..ad524fb0e 100644 --- a/src/global/global.h +++ b/src/global/global.h @@ -205,18 +205,14 @@ typedef int PrepareOutputFlags; namespace Timer { enum TimerFlags_ { None = 0, - PrintRelative = 1 << 0, - PrintUnits = 1 << 1, - PrintIndents = 1 << 2, - PrintTotal = 1 << 3, - PrintTitle = 1 << 4, - AutoConvert = 1 << 5, - Colorful = 1 << 6, - PrintOutput = 1 << 7, - PrintSorting = 1 << 8, - PrintCheckpoint = 1 << 9, - Default = PrintRelative | PrintUnits | PrintIndents | PrintTotal | - PrintTitle | AutoConvert | Colorful, + PrintTotal = 1 << 0, + PrintTitle = 1 << 1, + AutoConvert = 1 << 2, + PrintOutput = 1 << 3, + PrintSorting = 1 << 4, + PrintCheckpoint = 1 << 5, + PrintNormed = 1 << 6, + Default = PrintNormed | PrintTotal | PrintTitle | AutoConvert, }; } // namespace Timer diff --git a/src/global/utils/colors.h b/src/global/utils/colors.h index 512ad81c7..6f5e775cf 100644 --- a/src/global/utils/colors.h +++ b/src/global/utils/colors.h @@ -53,7 +53,8 @@ namespace color { return msg_nocol; } - inline auto get_color(const std::string& s, bool eight_bit) -> std::string { + inline auto get_color(const std::string& s, bool eight_bit = true) + -> std::string { if (not eight_bit) { return ""; } else { diff --git a/src/global/utils/diag.cpp b/src/global/utils/diag.cpp new file mode 100644 index 000000000..0a499dd56 --- /dev/null +++ b/src/global/utils/diag.cpp @@ -0,0 +1,246 @@ +#include "utils/diag.h" + +#include "global.h" + +#include "utils/colors.h" +#include "utils/formatting.h" +#include "utils/progressbar.h" +#include "utils/timer.h" + +#if defined(MPI_ENABLED) + #include "arch/mpi_aliases.h" + + #include +#endif // MPI_ENABLED + +#include +#include +#include +#include +#include +#include + +namespace diag { + auto npart_stats(std::size_t npart, std::size_t maxnpart) + -> std::vector> { + auto stats = std::vector>(); +#if !defined(MPI_ENABLED) + stats.push_back( + { npart, + static_cast( + 100.0f * static_cast(npart) / static_cast(maxnpart)) }); +#else + int rank, size; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Comm_size(MPI_COMM_WORLD, &size); + std::vector mpi_npart(size, 0); + std::vector mpi_maxnpart(size, 0); + MPI_Gather(&npart, + 1, + mpi::get_type(), + mpi_npart.data(), + 1, + mpi::get_type(), + MPI_ROOT_RANK, + MPI_COMM_WORLD); + MPI_Gather(&maxnpart, + 1, + mpi::get_type(), + mpi_maxnpart.data(), + 1, + mpi::get_type(), + MPI_ROOT_RANK, + MPI_COMM_WORLD); + if (rank != MPI_ROOT_RANK) { + return stats; + } + auto tot_npart = std::accumulate(mpi_npart.begin(), mpi_npart.end(), 0); + const auto max_idx = std::distance( + mpi_npart.begin(), + std::max_element(mpi_npart.begin(), mpi_npart.end())); + const auto min_idx = std::distance( + mpi_npart.begin(), + std::min_element(mpi_npart.begin(), mpi_npart.end())); + stats.push_back({ tot_npart, 0u }); + stats.push_back({ mpi_npart[min_idx], + static_cast( + 100.0f * static_cast(mpi_npart[min_idx]) / + static_cast(mpi_maxnpart[min_idx])) }); + stats.push_back({ mpi_npart[max_idx], + static_cast( + 100.0f * static_cast(mpi_npart[max_idx]) / + static_cast(mpi_maxnpart[max_idx])) }); +#endif + return stats; + } + + void printDiagnostics(std::size_t step, + std::size_t tot_steps, + long double time, + long double dt, + timer::Timers& timers, + pbar::DurationHistory& time_history, + std::size_t ncells, + const std::vector& species_labels, + const std::vector& species_npart, + const std::vector& species_maxnpart, + bool print_sorting, + bool print_output, + bool print_checkpoint, + bool print_colors) { + DiagFlags diag_flags = Diag::Default; + TimerFlags timer_flags = Timer::Default; + if (not print_colors) { + diag_flags ^= Diag::Colorful; + } + if (species_labels.size() == 0) { + diag_flags ^= Diag::Species; + } + if (print_sorting) { + timer_flags |= Timer::PrintSorting; + } + if (print_output) { + timer_flags |= Timer::PrintOutput; + } + if (print_checkpoint) { + timer_flags |= Timer::PrintCheckpoint; + } + + std::stringstream ss; + + const auto c_red = color::get_color("red"); + const auto c_yellow = color::get_color("yellow"); + const auto c_green = color::get_color("green"); + const auto c_bgreen = color::get_color("bgreen"); + const auto c_bblack = color::get_color("bblack"); + const auto c_reset = color::get_color("reset"); + + // basic info + CallOnce([&]() { + ss << fmt::alignedTable( + { "Step:", fmt::format("%lu", step), fmt::format("[of %lu]", tot_steps) }, + { c_reset, c_bgreen, c_bblack }, + { 0, -6, -15 }, + { ' ', ' ', ' ' }, + c_bblack, + c_reset); + + ss << fmt::alignedTable( + { "Time:", fmt::format("%.4Lf", time), fmt::format("[Δt = %.4Lf]", dt) }, + { c_reset, c_bgreen, c_bblack }, + { 0, -6, -15 }, + { ' ', ' ', ' ' }, + c_bblack, + c_reset); + }); + + // substep timers + if (diag_flags & Diag::Timers) { + const auto total_npart = std::accumulate(species_npart.begin(), + species_npart.end(), + 0); + const auto timer_diag = timers.printAll(timer_flags, total_npart, ncells); + CallOnce([&]() { + ss << std::endl << timer_diag << std::endl; + }); + } + + // particle counts + if (diag_flags & Diag::Species) { +#if defined(MPI_ENABLED) + CallOnce([&]() { + ss << fmt::alignedTable( + { "[PARTICLE SPECIES]", "[TOTAL]", "[% MIN", "MAX]", "[MIN", "MAX]" }, + { c_bblack, c_bblack, c_bblack, c_bblack, c_bblack, c_bblack }, + { 0, 37, 45, -48, 63, -66 }, + { ' ', ' ', ' ', ':', ' ', ':' }, + c_bblack, + c_reset); + }); +#else + CallOnce([&]() { + ss << fmt::alignedTable({ "[PARTICLE SPECIES]", "[TOTAL]", "[% TOT]" }, + { c_bblack, c_bblack, c_bblack }, + { 0, 37, 45 }, + { ' ', ' ', ' ' }, + c_bblack, + c_reset); + }); +#endif + for (std::size_t i = 0; i < species_labels.size(); ++i) { + const auto part_stats = npart_stats(species_npart[i], species_maxnpart[i]); + if (part_stats.size() == 0) { + continue; + } + const auto tot_npart = part_stats[0].first; +#if defined(MPI_ENABLED) + const auto min_npart = part_stats[1].first; + const auto min_pct = part_stats[1].second; + const auto max_npart = part_stats[2].first; + const auto max_pct = part_stats[2].second; + ss << fmt::alignedTable( + { + fmt::format("species %2lu (%s)", i, species_labels[i].c_str()), + tot_npart > 9999 ? fmt::format("%.2Le", (long double)tot_npart) + : std::to_string(tot_npart), + std::to_string(min_pct) + "%", + std::to_string(max_pct) + "%", + min_npart > 9999 ? fmt::format("%.2Le", (long double)min_npart) + : std::to_string(min_npart), + max_npart > 9999 ? fmt::format("%.2Le", (long double)max_npart) + : std::to_string(max_npart), + }, + { + c_reset, + c_reset, + (min_pct > 80) ? c_red : ((min_pct > 50) ? c_yellow : c_green), + (max_pct > 80) ? c_red : ((max_pct > 50) ? c_yellow : c_green), + c_reset, + c_reset, + }, + { -2, 37, 45, -48, 63, -66 }, + { ' ', '.', ' ', ':', ' ', ':' }, + c_bblack, + c_reset); +#else + const auto tot_pct = part_stats[0].second; + ss << fmt::alignedTable( + { + fmt::format("species %2lu (%s)", i, species_labels[i].c_str()), + tot_npart > 9999 ? fmt::format("%.2Le", (long double)tot_npart) + : std::to_string(tot_npart), + std::to_string(tot_pct) + "%", + }, + { + c_reset, + c_reset, + (tot_pct > 80) ? c_red : ((tot_pct > 50) ? c_yellow : c_green), + }, + { -2, 37, 45 }, + { ' ', '.', ' ' }, + c_bblack, + c_reset); +#endif + } + CallOnce([&]() { + ss << std::endl; + }); + } + + // progress bar + if (diag_flags & Diag::Progress) { + const auto progbar = pbar::ProgressBar(time_history, step, tot_steps, diag_flags); + CallOnce([&]() { + ss << progbar; + }); + } + + // separator + CallOnce([&]() { + ss << std::setw(80) << std::setfill('.') << "" << std::endl << std::endl; + }); + + std::cout << ((diag_flags & Diag::Colorful) ? ss.str() + : color::strip(ss.str())); + } +} // namespace diag diff --git a/src/global/utils/diag.h b/src/global/utils/diag.h new file mode 100644 index 000000000..9951602f8 --- /dev/null +++ b/src/global/utils/diag.h @@ -0,0 +1,59 @@ +/** + * @file utils/diag.h + * @brief Routines for diagnostics output at every step + * @implements + * - diag::printDiagnostics -> void + * @cpp: + * - diag.cpp + * @namespces: + * - diag:: + * @macros: + * - MPI_ENABLED + */ + +#ifndef GLOBAL_UTILS_DIAG_H +#define GLOBAL_UTILS_DIAG_H + +#include "utils/progressbar.h" +#include "utils/timer.h" + +#include +#include + +namespace diag { + + /** + * @brief Print diagnostics to the console + * @param step + * @param tot_steps + * @param time + * @param dt + * @param timers + * @param duration_history + * @param ncells (total) + * @param species_labels (vector of particle labels) + * @param npart (per each species) + * @param maxnpart (per each species) + * @param sorting_step (if true, particles were sorted) + * @param output_step (if true, output was written) + * @param checkpoint_step (if true, checkpoint was written) + * @param colorful_print (if true, print with colors) + */ + void printDiagnostics(std::size_t, + std::size_t, + long double, + long double, + timer::Timers&, + pbar::DurationHistory&, + std::size_t, + const std::vector&, + const std::vector&, + const std::vector&, + bool, + bool, + bool, + bool); + +} // namespace diag + +#endif // GLOBAL_UTILS_DIAG_H diff --git a/src/global/utils/formatting.h b/src/global/utils/formatting.h index 85f4e4b43..8dc7b6ba8 100644 --- a/src/global/utils/formatting.h +++ b/src/global/utils/formatting.h @@ -8,6 +8,8 @@ * - fmt::splitString -> std::vector * - fmt::repeat -> std::string * - fmt::formatVector -> std::string + * - fmt::strlen_utf8 -> std::size_t + * - fmt::alignedTable -> std::string * @namespaces: * - fmt:: */ @@ -132,6 +134,66 @@ namespace fmt { return result; } + inline auto repeat(char s, std::size_t n) -> std::string { + return repeat(std::string(1, s), n); + } + + /** + * @brief Calculate the length of a UTF-8 string + * @param str UTF-8 string + */ + inline auto strlenUTF8(const std::string& str) -> std::size_t { + std::size_t length = 0; + for (char c : str) { + if ((c & 0xC0) != 0x80) { + ++length; + } + } + return length; + } + + /** + * @brief Create a table with aligned columns and custom colors & separators + * @param columns Vector of column strings + * @param colors Vector of colors + * @param anchors Vector of column anchors (position of edge, negative means left-align) + * @param fillers Vector of separators + * @param c_bblack Black color + * @param c_reset Reset color + */ + inline auto alignedTable(const std::vector& columns, + const std::vector& colors, + const std::vector& anchors, + const std::vector& fillers, + const std::string& c_bblack, + const std::string& c_reset) -> std::string { + std::string result { c_reset }; + std::size_t cntr { 0 }; + for (auto i { 0u }; i < columns.size(); ++i) { + const auto anch { static_cast(anchors[i] < 0 ? -anchors[i] + : anchors[i]) }; + const auto leftalign { anchors[i] <= 0 }; + const auto cmn { columns[i] }; + const auto cmn_len { strlenUTF8(cmn) }; + std::string left { c_bblack }; + if (leftalign) { + if (fillers[i] == ':') { + left += " :"; + left += repeat(' ', anch - cntr - 2); + } else { + left += repeat(fillers[i], anch - cntr); + } + cntr += anch - cntr; + } else { + left += repeat(fillers[i], anch - cntr - cmn_len); + cntr += anch - cntr - cmn_len; + } + result += left + colors[i] + cmn + c_reset; + cntr += cmn_len; + } + return result + c_reset + "\n"; + } + } // namespace fmt #endif // GLOBAL_UTILS_FORMATTING_H diff --git a/src/global/utils/log.h b/src/global/utils/log.h index ac5bc4059..2434414a4 100644 --- a/src/global/utils/log.h +++ b/src/global/utils/log.h @@ -34,6 +34,8 @@ #endif namespace raise { + using namespace files; + inline void Warning(const std::string& msg, const std::string& file, const std::string& func, diff --git a/src/global/utils/progressbar.cpp b/src/global/utils/progressbar.cpp new file mode 100644 index 000000000..74f952382 --- /dev/null +++ b/src/global/utils/progressbar.cpp @@ -0,0 +1,120 @@ +#include "utils/progressbar.h" + +#include "utils/error.h" +#include "utils/formatting.h" + +#if defined(MPI_ENABLED) + #include "arch/mpi_aliases.h" + + #include +#endif // MPI_ENABLED + +#include +#include +#include +#include +#include +#include +#include + +namespace pbar { + + auto normalize_duration_fmt(long double t, const std::string& u) + -> std::pair { + const std::vector> units { + {"µs", 1e0}, + { "ms", 1e3}, + { "s", 1e6}, + {"min", 6e7}, + { "hr", 3.6e9} + }; + auto it = std::find_if(units.begin(), units.end(), [&u](const auto& pr) { + return pr.first == u; + }); + int u_idx = (it != units.end()) ? std::distance(units.begin(), it) : -1; + raise::ErrorIf(u_idx < 0, "Invalid unit", HERE); + int shift = 0; + if (t < 1) { + shift = -1; + } else if (1e3 <= t && t < 1e6) { + shift = 1; + } else if (1e6 <= t && t < 6e7) { + shift += 2; + } else if (6e7 <= t && t < 3.6e9) { + shift += 3; + } else if (3.6e9 <= t) { + shift += 4; + } + auto newu_idx = std::min(std::max(0, u_idx + shift), + static_cast(units.size())); + return { t * (units[u_idx].second / units[newu_idx].second), + units[newu_idx].first }; + } + + auto to_human_readable(long double t, const std::string& u) -> std::string { + const auto [tt, tu] = normalize_duration_fmt(t, u); + const auto t1 = static_cast(tt); + const auto t2 = tt - static_cast(t1); + const auto [tt2, tu2] = normalize_duration_fmt(t2, tu); + return fmt::format("%d%s %d%s", t1, tu.c_str(), static_cast(tt2), tu2.c_str()); + } + + auto ProgressBar(const DurationHistory& history, + std::size_t step, + std::size_t max_steps, + DiagFlags& flags) -> std::string { + auto avg_duration = history.average(); + +#if defined(MPI_ENABLED) + int rank, size; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Comm_size(MPI_COMM_WORLD, &size); + std::vector mpi_avg_durations(size, 0.0); + MPI_Gather(&avg_duration, + 1, + mpi::get_type(), + mpi_avg_durations.data(), + 1, + mpi::get_type(), + MPI_ROOT_RANK, + MPI_COMM_WORLD); + if (rank != MPI_ROOT_RANK) { + return ""; + } + avg_duration = *std::max_element(mpi_avg_durations.begin(), + mpi_avg_durations.end()); +#endif + + const auto avg = to_human_readable(avg_duration, "µs"); + const auto elapsed = to_human_readable(history.elapsed(), "µs"); + const auto remain = to_human_readable( + static_cast(max_steps - step) * avg_duration, + "µs"); + + const auto pct = static_cast(step) / + static_cast(max_steps); + const int nfilled = std::min(static_cast(pct * params::width), + params::width); + const int nempty = params::width - nfilled; + const auto c_bmagenta = color::get_color("bmagenta", flags & Diag::Colorful); + const auto c_reset = color::get_color("reset", flags & Diag::Colorful); + + std::stringstream ss; + + ss << "Timestep duration: " << c_bmagenta << avg << c_reset << std::endl; + ss << "Remaining time: " << c_bmagenta << remain << c_reset << std::endl; + ss << "Elapsed time: " << c_bmagenta << elapsed << c_reset << std::endl; + ss << params::start; + for (auto i { 0 }; i < nfilled; ++i) { + ss << params::fill; + } + for (auto i { 0 }; i < nempty; ++i) { + ss << params::empty; + } + ss << params::end << " " << std::fixed << std::setprecision(2) + << std::setfill(' ') << std::setw(6) << std::right << pct * 100.0 << "%\n"; + + return ss.str(); + } + +} // namespace pbar diff --git a/src/global/utils/progressbar.h b/src/global/utils/progressbar.h index ccbc6215e..f218bc3f4 100644 --- a/src/global/utils/progressbar.h +++ b/src/global/utils/progressbar.h @@ -3,6 +3,8 @@ * @brief Progress bar for logging the simulation progress * @implements * - pbar::ProgressBar -> void + * @cpp: + * - progressbar.cpp * @namespaces: * - pbar:: * @macros: @@ -16,22 +18,15 @@ #include "utils/colors.h" #include "utils/error.h" +#include "utils/formatting.h" #include -#include -#include #include #include #include #include #include -#if defined(MPI_ENABLED) - #include "arch/mpi_aliases.h" - - #include -#endif // MPI_ENABLED - namespace pbar { namespace params { inline constexpr int width { 70 }; @@ -81,96 +76,15 @@ namespace pbar { } }; - inline auto normalize_duration_fmt(long double t, const std::string& u) - -> std::pair { - const std::vector> units { - {"µs", 1e0}, - { "ms", 1e3}, - { "s", 1e6}, - {"min", 6e7}, - { "hr", 3.6e9} - }; - auto it = std::find_if(units.begin(), units.end(), [&u](const auto& pr) { - return pr.first == u; - }); - int u_idx = (it != units.end()) ? std::distance(units.begin(), it) : -1; - raise::ErrorIf(u_idx < 0, "Invalid unit", HERE); - int shift = 0; - if (t < 1e-2) { - shift = -1; - } else if (1e3 <= t && t < 1e6) { - shift = 1; - } else if (1e6 <= t && t < 6e7) { - shift += 2; - } else if (6e7 <= t && t < 3.6e9) { - shift += 3; - } else if (3.6e9 <= t) { - shift += 4; - } - auto newu_idx = std::min(std::max(0, u_idx + shift), - static_cast(units.size())); - return { t * (units[u_idx].second / units[newu_idx].second), - units[newu_idx].first }; - } - - inline void ProgressBar(const DurationHistory& history, - std::size_t step, - std::size_t max_steps, - DiagFlags& flags, - std::ostream& os = std::cout) { - auto avg_duration = history.average(); + auto normalize_duration_fmt(long double t, const std::string& u) + -> std::pair; -#if defined(MPI_ENABLED) - int rank, size; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - MPI_Comm_size(MPI_COMM_WORLD, &size); - std::vector mpi_avg_durations(size, 0.0); - MPI_Gather(&avg_duration, - 1, - mpi::get_type(), - mpi_avg_durations.data(), - 1, - mpi::get_type(), - MPI_ROOT_RANK, - MPI_COMM_WORLD); - if (rank != MPI_ROOT_RANK) { - return; - } - avg_duration = *std::max_element(mpi_avg_durations.begin(), - mpi_avg_durations.end()); -#endif - auto [avg_reduced, avg_units] = normalize_duration_fmt(avg_duration, "µs"); - - const auto remain_nsteps = max_steps - step; - auto [remain_time, remain_units] = normalize_duration_fmt( - static_cast(remain_nsteps) * avg_duration, - "µs"); - auto [elapsed_time, - elapsed_units] = normalize_duration_fmt(history.elapsed(), "µs"); + auto to_human_readable(long double t, const std::string& u) -> std::string; - const auto pct = static_cast(step) / - static_cast(max_steps); - const int nfilled = std::min(static_cast(pct * params::width), - params::width); - const int nempty = params::width - nfilled; - const auto c_bmagenta = color::get_color("bmagenta", flags & Diag::Colorful); - const auto c_reset = color::get_color("reset", flags & Diag::Colorful); - os << "Average timestep: " << c_bmagenta << avg_reduced << " " << avg_units - << c_reset << std::endl; - os << "Remaining time: " << c_bmagenta << remain_time << " " << remain_units - << c_reset << std::endl; - os << "Elapsed time: " << c_bmagenta << elapsed_time << " " << elapsed_units - << c_reset << std::endl; - os << params::start; - for (auto i { 0 }; i < nfilled; ++i) { - os << params::fill; - } - for (auto i { 0 }; i < nempty; ++i) { - os << params::empty; - } - os << params::end << " " << std::fixed << std::setprecision(2) - << std::setfill(' ') << std::setw(6) << std::right << pct * 100.0 << "%\n"; - } + auto ProgressBar(const DurationHistory& history, + std::size_t step, + std::size_t max_steps, + DiagFlags& flags) -> std::string; } // namespace pbar diff --git a/src/global/utils/timer.cpp b/src/global/utils/timer.cpp new file mode 100644 index 000000000..1a1a37848 --- /dev/null +++ b/src/global/utils/timer.cpp @@ -0,0 +1,279 @@ +#include "utils/timer.h" + +#include "utils/colors.h" +#include "utils/formatting.h" + +#if defined(MPI_ENABLED) + #include "arch/mpi_aliases.h" + + #include +#endif // MPI_ENABLED + +#include +#include +#include +#include +#include + +namespace timer { + + auto Timers::gather(const std::vector& ignore_in_tot, + std::size_t npart, + std::size_t ncells) const + -> std::map> { + auto timer_stats = std::map< + std::string, + std::tuple> {}; +#if defined(MPI_ENABLED) + int rank, size; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Comm_size(MPI_COMM_WORLD, &size); + std::map> all_timers {}; + + // accumulate timers from MPI blocks + for (auto& [name, timer] : m_timers) { + all_timers.insert({ name, std::vector(size, 0.0) }); + MPI_Gather(&timer.second, + 1, + mpi::get_type(), + all_timers[name].data(), + 1, + mpi::get_type(), + MPI_ROOT_RANK, + MPI_COMM_WORLD); + } + // accumulate nparts and ncells from MPI blocks + auto all_nparts = std::vector(size, 0); + auto all_ncells = std::vector(size, 0); + MPI_Gather(&npart, + 1, + mpi::get_type(), + all_nparts.data(), + 1, + mpi::get_type(), + MPI_ROOT_RANK, + MPI_COMM_WORLD); + MPI_Gather(&ncells, + 1, + mpi::get_type(), + all_ncells.data(), + 1, + mpi::get_type(), + MPI_ROOT_RANK, + MPI_COMM_WORLD); + if (rank != MPI_ROOT_RANK) { + return {}; + } + std::vector all_totals(size, 0.0); + for (auto i { 0u }; i < size; ++i) { + for (auto& [name, timer] : m_timers) { + if (std::find(ignore_in_tot.begin(), ignore_in_tot.end(), name) == + ignore_in_tot.end()) { + all_totals[i] += all_timers[name][i]; + } + } + } + for (auto& [name, timer] : m_timers) { + const auto max_time = *std::max_element(all_timers[name].begin(), + all_timers[name].end()); + const auto max_idx = std::distance( + all_timers[name].begin(), + std::max_element(all_timers[name].begin(), all_timers[name].end())); + + const auto per_npart = all_nparts[max_idx] > 0 + ? max_time / + static_cast(all_nparts[max_idx]) + : 0.0; + const auto per_ncells = all_ncells[max_idx] > 0 + ? max_time / + static_cast(all_ncells[max_idx]) + : 0.0; + const auto pcent = static_cast( + (max_time / all_totals[max_idx]) * 100.0); + timer_stats.insert( + { name, + std::make_tuple(max_time, + per_npart, + per_ncells, + pcent, + tools::ArrayImbalance(all_timers[name])) }); + } + const auto max_tot = *std::max_element(all_totals.begin(), all_totals.end()); + const auto tot_imb = tools::ArrayImbalance(all_totals); + timer_stats.insert( + { "Total", std::make_tuple(max_tot, 0.0, 0.0, 100u, tot_imb) }); +#else + duration_t local_tot = 0.0; + for (auto& [name, timer] : m_timers) { + if (std::find(ignore_in_tot.begin(), ignore_in_tot.end(), name) == + ignore_in_tot.end()) { + local_tot += timer.second; + } + } + for (auto& [name, timer] : m_timers) { + const auto pcent = static_cast( + (timer.second / local_tot) * 100.0); + timer_stats.insert( + { name, std::make_tuple(timer.second, pcent, 0.0, 0u, 0u) }); + } + timer_stats.insert({ "Total", std::make_tuple(local_tot, 0.0, 0.0, 100u, 0u) }); +#endif + return timer_stats; + } + + auto Timers::printAll(TimerFlags flags, std::size_t npart, std::size_t ncells) const + -> std::string { + const std::vector extras { "Sorting", "Output", "Checkpoint" }; + const auto stats = gather(extras, npart, ncells); + if (stats.empty()) { + return ""; + } + +#if defined(MPI_ENABLED) + const auto multi_rank = true; +#else + const auto multi_rank = false; +#endif + + std::stringstream ss; + + const auto c_bblack = color::get_color("bblack"); + const auto c_reset = color::get_color("reset"); + const auto c_byellow = color::get_color("byellow"); + const auto c_blue = color::get_color("blue"); + const auto c_red = color::get_color("red"); + const auto c_yellow = color::get_color("yellow"); + const auto c_green = color::get_color("green"); + + if (multi_rank and flags & Timer::PrintTitle) { + ss << fmt::alignedTable( + { "[SUBSTEP]", "[MAX DURATION]", "[% TOT", "VAR]", "[per PRTL", "CELL]" }, + { c_bblack, c_bblack, c_bblack, c_bblack, c_bblack, c_bblack }, + { 0, 37, 45, -48, 63, -66 }, + { ' ', '.', ' ', ':', ' ', ':' }, + c_bblack, + c_reset); + } else { + ss << fmt::alignedTable( + { "[SUBSTEP]", "[DURATION]", "[% TOT]", "[per PRTL", "CELL]" }, + { c_bblack, c_bblack, c_bblack, c_bblack, c_bblack }, + { 0, 37, 45, 55, -58 }, + { ' ', '.', ' ', ' ', ':' }, + c_bblack, + c_reset); + } + + for (auto& [name, timers] : m_timers) { + if (std::find(extras.begin(), extras.end(), name) != extras.end()) { + continue; + } + std::string units = "µs", units_npart = "µs", units_ncells = "µs"; + auto time = std::get<0>(stats.at(name)); + auto per_npart = std::get<1>(stats.at(name)); + auto per_ncells = std::get<2>(stats.at(name)); + const auto tot_pct = std::get<3>(stats.at(name)); + const auto var_pct = std::get<4>(stats.at(name)); + if (flags & Timer::AutoConvert) { + convertTime(time, units); + convertTime(per_npart, units_npart); + convertTime(per_ncells, units_ncells); + } + + if (multi_rank) { + ss << fmt::alignedTable( + { name, + fmt::format("%.2Lf", time) + " " + units, + std::to_string(tot_pct) + "%", + std::to_string(var_pct) + "%", + fmt::format("%.2Lf", per_npart) + " " + units_npart, + fmt::format("%.2Lf", per_ncells) + " " + units_ncells }, + { c_reset, + c_yellow, + ((tot_pct > 60) ? c_red : ((tot_pct > 40) ? c_yellow : c_green)), + ((var_pct > 50) ? c_red : ((var_pct > 30) ? c_yellow : c_green)), + c_yellow, + c_yellow }, + { -2, 37, 45, -48, 63, -66 }, + { ' ', '.', ' ', ':', ' ', ':' }, + c_bblack, + c_reset); + } else { + ss << fmt::alignedTable( + { name, + fmt::format("%.2Lf", time) + " " + units, + std::to_string(tot_pct) + "%", + fmt::format("%.2Lf", per_npart) + " " + units_npart, + fmt::format("%.2Lf", per_ncells) + " " + units_ncells }, + { c_reset, + c_yellow, + ((tot_pct > 60) ? c_red : ((tot_pct > 40) ? c_yellow : c_green)), + c_yellow, + c_yellow }, + { -2, 37, 45, 55, -58 }, + { ' ', '.', ' ', ' ', ':' }, + c_bblack, + c_reset); + } + } + + // total + if (flags & Timer::PrintTotal) { + std::string units = "µs"; + auto time = std::get<0>(stats.at("Total")); + const auto var_pct = std::get<4>(stats.at("Total")); + if (flags & Timer::AutoConvert) { + convertTime(time, units); + } + if (multi_rank) { + ss << fmt::alignedTable( + { "Total", + fmt::format("%.2Lf", time) + " " + units, + std::to_string(var_pct) + "%" }, + { c_reset, + c_blue, + ((var_pct > 50) ? c_red : ((var_pct > 30) ? c_yellow : c_green)) }, + { 0, 37, -48 }, + { ' ', ' ', ' ' }, + c_bblack, + c_reset); + } else { + ss << fmt::alignedTable( + { "Total", fmt::format("%.2Lf", time) + " " + units }, + { c_reset, c_blue }, + { 0, 37 }, + { ' ', ' ' }, + c_bblack, + c_reset); + } + } + + // print extra timers for output/checkpoint/sorting + const std::vector extras_f { Timer::PrintSorting, + Timer::PrintOutput, + Timer::PrintCheckpoint }; + for (auto i { 0u }; i < extras.size(); ++i) { + const auto name = extras[i]; + const auto active = flags & extras_f[i]; + std::string units = "µs"; + auto time = std::get<0>(stats.at(name)); + const auto tot_pct = std::get<3>(stats.at(name)); + const auto var_pct = std::get<4>(stats.at(name)); + if (flags & Timer::AutoConvert) { + convertTime(time, units); + } + ss << fmt::alignedTable({ name, + fmt::format("%.2Lf", time) + " " + units, + std::to_string(tot_pct) + "%" }, + { (active ? c_reset : c_bblack), + (active ? c_byellow : c_bblack), + (active ? c_byellow : c_bblack) }, + { -2, 37, 45 }, + { ' ', '.', ' ' }, + c_bblack, + c_reset); + } + return ss.str(); + } + +} // namespace timer diff --git a/src/global/utils/timer.h b/src/global/utils/timer.h index 84356f7b3..3e9c1433e 100644 --- a/src/global/utils/timer.h +++ b/src/global/utils/timer.h @@ -4,6 +4,8 @@ * @implements * - timer::Timers * - enum timer::TimerFlags + * @cpp: + * - timer.cpp * @namespces: * - timer:: * @macros: @@ -21,21 +23,28 @@ #include "utils/error.h" #include "utils/formatting.h" #include "utils/numeric.h" +#include "utils/tools.h" + +#if defined(MPI_ENABLED) + #include "arch/mpi_aliases.h" + + #include +#endif // MPI_ENABLED #include #include -#include -#include #include #include #include +#include #include #include namespace timer { - using timestamp = std::chrono::time_point; + using timestamp = std::chrono::time_point; + using duration_t = long double; - inline void convertTime(long double& value, std::string& units) { + inline void convertTime(duration_t& value, std::string& units) { if (value > 1e6) { value /= 1e6; units = " s"; @@ -49,10 +58,10 @@ namespace timer { } class Timers { - std::map> m_timers; - std::vector m_names; - const bool m_blocking; - const std::function m_synchronize; + std::map> m_timers; + std::vector m_names; + const bool m_blocking; + const std::function m_synchronize; public: Timers(std::initializer_list names, @@ -103,9 +112,9 @@ namespace timer { } [[nodiscard]] - auto get(const std::string& name) const -> long double { + auto get(const std::string& name) const -> duration_t { if (name == "Total") { - long double total = 0.0; + duration_t total = 0.0; for (auto& timer : m_timers) { total += timer.second.second; } @@ -116,202 +125,29 @@ namespace timer { } } - void printAll(const TimerFlags flags = Timer::Default, - std::ostream& os = std::cout) const { -#if !defined(MPI_ENABLED) - std::string header = fmt::format("%s %27s", "[SUBSTEP]", "[DURATION]"); -#else - std::string header = fmt::format("%s %32s", "[SUBSTEP]", "[DURATION]"); -#endif - - const auto c_bblack = color::get_color("bblack", flags & Timer::Colorful); - const auto c_reset = color::get_color("reset", flags & Timer::Colorful); - const auto c_byellow = color::get_color("byellow", flags & Timer::Colorful); - const auto c_blue = color::get_color("blue", flags & Timer::Colorful); + /** + * @brief Gather all timers from all ranks + * @param ignore_in_tot: vector of timer names to ignore in computing the total + * @return map: + * key: timer name + * value: vector of numbers + * - max duration across ranks + * - max duration per particle + * - max duration per cell + * - max duration as % of total on that rank + * - imbalance % of the given timer + */ + [[nodiscard]] + auto gather(const std::vector& ignore_in_tot, + std::size_t npart, + std::size_t ncells) const + -> std::map>; - if (flags & Timer::PrintRelative) { - header += " [% TOT]"; - } -#if defined(MPI_ENABLED) - header += " [MIN : MAX]"; -#endif - header = c_bblack + header + c_reset; - CallOnce( - [](std::ostream& os, std::string header) { - os << header << std::endl; - }, - os, - header); -#if defined(MPI_ENABLED) - int rank, size; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - MPI_Comm_size(MPI_COMM_WORLD, &size); - std::map> mpi_timers {}; - // accumulate timers from MPI blocks - for (auto& [name, timer] : m_timers) { - mpi_timers[name] = std::vector(size, 0.0); - MPI_Gather(&timer.second, - 1, - mpi::get_type(), - mpi_timers[name].data(), - 1, - mpi::get_type(), - MPI_ROOT_RANK, - MPI_COMM_WORLD); - } - if (rank != MPI_ROOT_RANK) { - return; - } - long double total = 0.0; - for (auto& [name, timer] : m_timers) { - auto timers = mpi_timers[name]; - long double tot = std::accumulate(timers.begin(), timers.end(), 0.0); - if (name != "Output" and name != "Checkpoint") { - total += tot; - } - } - for (auto& [name, timers] : mpi_timers) { - // compute min, max, mean - long double min_time = *std::min_element(timers.begin(), timers.end()); - long double max_time = *std::max_element(timers.begin(), timers.end()); - long double mean_time = std::accumulate(timers.begin(), timers.end(), 0.0) / - size; - std::string mean_units = "µs"; - const auto min_pct = mean_time > ZERO - ? (int)(((mean_time - min_time) / mean_time) * 100.0) - : 0; - const auto max_pct = mean_time > ZERO - ? (int)(((max_time - mean_time) / mean_time) * 100.0) - : 0; - const auto tot_pct = (cmp::AlmostZero_host(total) - ? 0 - : (mean_time * size / total) * 100.0); - if (flags & Timer::AutoConvert) { - convertTime(mean_time, mean_units); - } - if (flags & Timer::PrintIndents) { - os << " "; - } - os << ((name != "Sorting" or flags & Timer::PrintSorting) ? c_reset - : c_bblack) - << name << c_reset << c_bblack - << fmt::pad(name, 20, '.', true).substr(name.size(), 20); - os << std::setw(17) << std::right << std::setfill('.') - << fmt::format("%s%.2Lf", - (name != "Sorting" or flags & Timer::PrintSorting) - ? c_byellow.c_str() - : c_bblack.c_str(), - mean_time); - if (flags & Timer::PrintUnits) { - os << " " << mean_units << " "; - } - if (flags & Timer::PrintRelative) { - os << " " << std::setw(5) << std::right << std::setfill(' ') - << std::fixed << std::setprecision(2) << tot_pct << "%"; - } - os << fmt::format("%+7s : %-7s", - fmt::format("-%d%%", min_pct).c_str(), - fmt::format("+%d%%", max_pct).c_str()); - os << c_reset << std::endl; - } - total /= size; -#else // not MPI_ENABLED - long double total = 0.0; - for (auto& [name, timer] : m_timers) { - if (name != "Output" and name != "Checkpoint") { - total += timer.second; - } - } - for (auto& [name, timer] : m_timers) { - if (name == "Output" or name == "Checkpoint") { - continue; - } - std::string units = "µs"; - auto value = timer.second; - if (flags & Timer::AutoConvert) { - convertTime(value, units); - } - if (flags & Timer::PrintIndents) { - os << " "; - } - os << ((name != "Sorting" or flags & Timer::PrintSorting) ? c_reset - : c_bblack) - << name << c_bblack - << fmt::pad(name, 20, '.', true).substr(name.size(), 20); - os << std::setw(17) << std::right << std::setfill('.') - << fmt::format("%s%.2Lf", - (name != "Sorting" or flags & Timer::PrintSorting) - ? c_byellow.c_str() - : c_bblack.c_str(), - value); - if (flags & Timer::PrintUnits) { - os << " " << units; - } - if (flags & Timer::PrintRelative) { - os << " " << std::setw(7) << std::right << std::setfill(' ') - << std::fixed << std::setprecision(2) - << (cmp::AlmostZero_host(total) ? 0 : (timer.second / total) * 100.0); - } - os << c_reset << std::endl; - } -#endif // MPI_ENABLED - if (flags & Timer::PrintTotal) { - std::string units = "µs"; - auto value = total; - if (flags & Timer::AutoConvert) { - convertTime(value, units); - } -#if !defined(MPI_ENABLED) - os << c_bblack << std::setw(22) << std::left << std::setfill(' ') - << "Total" << c_reset; -#else - os << c_bblack << std::setw(27) << std::left << std::setfill(' ') - << "Total" << c_reset; -#endif - os << c_blue << std::setw(12) << std::right << std::setfill(' ') << value; - if (flags & Timer::PrintUnits) { - os << " " << units; - } - os << c_reset << std::endl; - } - { - std::string units = "µs"; - auto value = get("Output"); - if (flags & Timer::AutoConvert) { - convertTime(value, units); - } - os << ((flags & Timer::PrintOutput) ? c_reset : c_bblack) << "Output" - << c_bblack << fmt::pad("Output", 22, '.', true).substr(6, 22); - os << std::setw(17) << std::right << std::setfill('.') - << fmt::format("%s%.2Lf", - (flags & Timer::PrintOutput) ? c_byellow.c_str() - : c_bblack.c_str(), - value); - if (flags & Timer::PrintUnits) { - os << " " << units; - } - os << c_reset << std::endl; - } - { - std::string units = "µs"; - auto value = get("Checkpoint"); - if (flags & Timer::AutoConvert) { - convertTime(value, units); - } - os << ((flags & Timer::PrintCheckpoint) ? c_reset : c_bblack) - << "Checkpoint" << c_bblack - << fmt::pad("Checkpoint", 22, '.', true).substr(10, 22); - os << std::setw(17) << std::right << std::setfill('.') - << fmt::format("%s%.2Lf", - (flags & Timer::PrintCheckpoint) ? c_byellow.c_str() - : c_bblack.c_str(), - value); - if (flags & Timer::PrintUnits) { - os << " " << units; - } - os << c_reset << std::endl; - } - } + [[nodiscard]] + auto printAll(TimerFlags flags = Timer::Default, + std::size_t npart = 0, + std::size_t ncells = 0) const -> std::string; }; } // namespace timer diff --git a/src/global/utils/tools.h b/src/global/utils/tools.h index 96d948ae4..30687d01b 100644 --- a/src/global/utils/tools.h +++ b/src/global/utils/tools.h @@ -2,6 +2,7 @@ * @file utils/tools.h * @brief Helper functions for general use * @implements + * - tools::ArrayImbalance -> unsigned short * - tools::TensorProduct<> -> boundaries_t * - tools::decompose1D -> std::vector * - tools::divideInProportions2D -> std::tuple @@ -17,6 +18,8 @@ #include "global.h" +#include "arch/kokkos_aliases.h" +#include "utils/comparators.h" #include "utils/error.h" #include "utils/numeric.h" @@ -27,6 +30,30 @@ namespace tools { + /** + * @brief Compute the imbalance of a list of nonnegative values + * @param values List of values + * @return Imbalance of the list (0...100) + */ + template + auto ArrayImbalance(const std::vector& values) -> unsigned short { + raise::ErrorIf(values.empty(), "Disbalance error: value array is empty", HERE); + const auto mean = static_cast(std::accumulate(values.begin(), + values.end(), + static_cast(0))) / + static_cast(values.size()); + const auto sq_sum = static_cast(std::inner_product(values.begin(), + values.end(), + values.begin(), + static_cast(0))); + if (cmp::AlmostZero_host(sq_sum) || cmp::AlmostZero_host(mean)) { + return 0; + } + const auto cv = std::sqrt( + sq_sum / static_cast(values.size()) / mean - 1.0); + return static_cast(100.0 / (1.0 + math::exp(-cv))); + } + /** * @brief Compute a tensor product of a list of vectors * @param list List of vectors From e24959f0f3d94561921f18642f8b0da422cd92d7 Mon Sep 17 00:00:00 2001 From: haykh Date: Fri, 16 Aug 2024 21:15:35 -0400 Subject: [PATCH 012/773] checkpoint read/write --- src/checkpoint/CMakeLists.txt | 2 + src/checkpoint/reader.cpp | 142 +++++++++++++++++ src/checkpoint/reader.h | 37 ++++- src/checkpoint/writer.cpp | 22 +-- src/engines/CMakeLists.txt | 2 - src/engines/engine.hpp | 1 - src/engines/engine_init.cpp | 9 ++ src/engines/engine_run.cpp | 37 +++-- src/framework/domain/checkpoint.cpp | 238 ++++++++++++++++++++++++++-- src/framework/domain/metadomain.cpp | 2 +- src/framework/domain/metadomain.h | 66 +++++++- src/framework/domain/output.cpp | 30 ++-- src/framework/parameters.cpp | 4 +- src/framework/parameters.h | 2 +- src/framework/simulation.cpp | 2 + 15 files changed, 539 insertions(+), 57 deletions(-) diff --git a/src/checkpoint/CMakeLists.txt b/src/checkpoint/CMakeLists.txt index 00c11ac04..d97bd4a34 100644 --- a/src/checkpoint/CMakeLists.txt +++ b/src/checkpoint/CMakeLists.txt @@ -2,6 +2,7 @@ # @defines: ntt_checkpoint [STATIC/SHARED] # @sources: # - writer.cpp +# - reader.cpp # @includes: # - ../ # @depends: @@ -15,6 +16,7 @@ set(SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}) set(SOURCES ${SRC_DIR}/writer.cpp + ${SRC_DIR}/reader.cpp ) add_library(ntt_checkpoint ${SOURCES}) diff --git a/src/checkpoint/reader.cpp b/src/checkpoint/reader.cpp index e69de29bb..c53661b45 100644 --- a/src/checkpoint/reader.cpp +++ b/src/checkpoint/reader.cpp @@ -0,0 +1,142 @@ +#include "checkpoint/reader.h" + +#include "global.h" + +#include "arch/kokkos_aliases.h" +#include "utils/error.h" +#include "utils/formatting.h" +#include "utils/log.h" + +#include +#include +#include + +#include +#include +#include + +namespace checkpoint { + + template + void ReadFields(adios2::IO& io, + adios2::Engine& reader, + const std::string& field, + const adios2::Box& range, + ndfield_t& array) { + logger::Checkpoint(fmt::format("Reading field: %s", field.c_str()), HERE); + auto field_var = io.InquireVariable(field); + field_var.SetStepSelection(adios2::Box({ 0 }, { 1 })); + field_var.SetSelection(range); + auto array_h = Kokkos::create_mirror_view(array); + reader.Get(field_var, array_h.data()); + Kokkos::deep_copy(array, array_h); + } + + auto ReadParticleCount(adios2::IO& io, + adios2::Engine& reader, + unsigned short s, + std::size_t local_dom, + std::size_t ndomains) + -> std::pair { + logger::Checkpoint(fmt::format("Reading particle count for: %d", s + 1), HERE); + auto npart_var = io.InquireVariable( + fmt::format("s%d_npart", s + 1)); + raise::ErrorIf( + npart_var.Shape()[0] != ndomains or npart_var.Shape().size() != 1, + "npart_var.Shape()[0] != ndomains or npart_var.Shape().size() != 1", + HERE); + npart_var.SetStepSelection(adios2::Box({ 0 }, { 1 })); + npart_var.SetSelection( + adios2::Box({ 0 }, { npart_var.Shape()[0] })); + std::vector nparts(ndomains); + reader.Get(npart_var, nparts.data(), adios2::Mode::Sync); + + const auto loc_npart = nparts[local_dom]; + std::size_t offset_npart = 0; + for (auto d { 0u }; d < local_dom; ++d) { + offset_npart += nparts[d]; + } + return { loc_npart, offset_npart }; + } + + template + void ReadParticleData(adios2::IO& io, + adios2::Engine& reader, + const std::string& quantity, + unsigned short s, + array_t& array, + std::size_t count, + std::size_t offset) { + logger::Checkpoint( + fmt::format("Reading quantity: s%d_%s", s + 1, quantity.c_str()), + HERE); + auto var = io.InquireVariable( + fmt::format("s%d_%s", s + 1, quantity.c_str())); + var.SetStepSelection(adios2::Box({ 0 }, { 1 })); + var.SetSelection(adios2::Box({ offset }, { count })); + auto array_h = Kokkos::create_mirror_view(array); + reader.Get(var, array_h.data()); + Kokkos::deep_copy(array, array_h); + } + + template void ReadFields(adios2::IO&, + adios2::Engine&, + const std::string&, + const adios2::Box&, + ndfield_t&); + template void ReadFields(adios2::IO&, + adios2::Engine&, + const std::string&, + const adios2::Box&, + ndfield_t&); + template void ReadFields(adios2::IO&, + adios2::Engine&, + const std::string&, + const adios2::Box&, + ndfield_t&); + template void ReadFields(adios2::IO&, + adios2::Engine&, + const std::string&, + const adios2::Box&, + ndfield_t&); + template void ReadFields(adios2::IO&, + adios2::Engine&, + const std::string&, + const adios2::Box&, + ndfield_t&); + template void ReadFields(adios2::IO&, + adios2::Engine&, + const std::string&, + const adios2::Box&, + ndfield_t&); + + template void ReadParticleData(adios2::IO&, + adios2::Engine&, + const std::string&, + unsigned short, + array_t&, + std::size_t, + std::size_t); + template void ReadParticleData(adios2::IO&, + adios2::Engine&, + const std::string&, + unsigned short, + array_t&, + std::size_t, + std::size_t); + template void ReadParticleData(adios2::IO&, + adios2::Engine&, + const std::string&, + unsigned short, + array_t&, + std::size_t, + std::size_t); + template void ReadParticleData(adios2::IO&, + adios2::Engine&, + const std::string&, + unsigned short, + array_t&, + std::size_t, + std::size_t); + +} // namespace checkpoint diff --git a/src/checkpoint/reader.h b/src/checkpoint/reader.h index ea8653e72..b2358647b 100644 --- a/src/checkpoint/reader.h +++ b/src/checkpoint/reader.h @@ -1,8 +1,9 @@ /** * @file checkpoint/reader.h - * @brief Class that reads checkpoints + * @brief Function for reading field & particle data from checkpoint files * @implements - * - checkpoint::Reader + * - checkpoint::ReadFields -> void + * - checkpoint::ReadParticleData -> void * @cpp: * - reader.cpp * @namespaces: @@ -12,8 +13,38 @@ #ifndef CHECKPOINT_READER_H #define CHECKPOINT_READER_H +#include "arch/kokkos_aliases.h" + +#include +#include + +#include +#include + namespace checkpoint { - class Reader {}; + + template + void ReadFields(adios2::IO&, + adios2::Engine&, + const std::string&, + const adios2::Box&, + ndfield_t&); + + auto ReadParticleCount(adios2::IO&, + adios2::Engine&, + unsigned short, + std::size_t, + std::size_t) -> std::pair; + + template + void ReadParticleData(adios2::IO&, + adios2::Engine&, + const std::string&, + unsigned short, + array_t&, + std::size_t, + std::size_t); + } // namespace checkpoint #endif // CHECKPOINT_READER_H diff --git a/src/checkpoint/writer.cpp b/src/checkpoint/writer.cpp index c584d13fe..1740c47aa 100644 --- a/src/checkpoint/writer.cpp +++ b/src/checkpoint/writer.cpp @@ -91,25 +91,25 @@ namespace checkpoint { { adios2::UnknownDim }, { adios2::UnknownDim }, { adios2::UnknownDim }); - m_io.DefineVariable(fmt::format("s%d_dx%d", s + 1, d + 1), - { adios2::UnknownDim }, - { adios2::UnknownDim }, - { adios2::UnknownDim }); + m_io.DefineVariable(fmt::format("s%d_dx%d", s + 1, d + 1), + { adios2::UnknownDim }, + { adios2::UnknownDim }, + { adios2::UnknownDim }); m_io.DefineVariable(fmt::format("s%d_i%d_prev", s + 1, d + 1), { adios2::UnknownDim }, { adios2::UnknownDim }, { adios2::UnknownDim }); - m_io.DefineVariable(fmt::format("s%d_dx%d_prev", s + 1, d + 1), - { adios2::UnknownDim }, - { adios2::UnknownDim }, - { adios2::UnknownDim }); - } - if (dim == Dim::_2D and C != ntt::Coord::Cart) { - m_io.DefineVariable(fmt::format("s%d_phi", s + 1), + m_io.DefineVariable(fmt::format("s%d_dx%d_prev", s + 1, d + 1), { adios2::UnknownDim }, { adios2::UnknownDim }, { adios2::UnknownDim }); } + if (dim == Dim::_2D and C != ntt::Coord::Cart) { + m_io.DefineVariable(fmt::format("s%d_phi", s + 1), + { adios2::UnknownDim }, + { adios2::UnknownDim }, + { adios2::UnknownDim }); + } for (auto d { 0u }; d < 3; ++d) { m_io.DefineVariable(fmt::format("s%d_ux%d", s + 1, d + 1), { adios2::UnknownDim }, diff --git a/src/engines/CMakeLists.txt b/src/engines/CMakeLists.txt index c91475eb7..2ab7289b2 100644 --- a/src/engines/CMakeLists.txt +++ b/src/engines/CMakeLists.txt @@ -4,7 +4,6 @@ # - engine_printer.cpp # - engine_init.cpp # - engine_run.cpp -# - engine_step_report.cpp # @includes: # - ../ # @depends: @@ -29,7 +28,6 @@ set(SOURCES ${SRC_DIR}/engine_printer.cpp ${SRC_DIR}/engine_init.cpp ${SRC_DIR}/engine_run.cpp - ${SRC_DIR}/engine_step_report.cpp ) add_library(ntt_engines ${SOURCES}) diff --git a/src/engines/engine.hpp b/src/engines/engine.hpp index f1bb46e98..5b7caa502 100644 --- a/src/engines/engine.hpp +++ b/src/engines/engine.hpp @@ -117,7 +117,6 @@ namespace ntt { void init(); void print_report() const; - void print_step_report(timer::Timers&, pbar::DurationHistory&, bool, bool, bool) const; virtual void step_forward(timer::Timers&, Domain&) = 0; diff --git a/src/engines/engine_init.cpp b/src/engines/engine_init.cpp index 5a8a693b0..e4ce9fa5f 100644 --- a/src/engines/engine_init.cpp +++ b/src/engines/engine_init.cpp @@ -27,6 +27,8 @@ namespace ntt { #endif logger::Checkpoint("Initializing Engine", HERE); if (not is_resuming) { + // start a new simulation with initial conditions + logger::Checkpoint("Loading initial conditions", HERE); if constexpr ( traits::has_member>::value) { logger::Checkpoint("Initializing fields from problem generator", HERE); @@ -48,6 +50,13 @@ namespace ntt { }); } } else { + // read simulation data from the checkpoint + raise::ErrorIf( + m_params.template get("checkpoint.start_step") == 0, + "Resuming simulation from a checkpoint requires a valid start_step", + HERE); + logger::Checkpoint("Resuming simulation from a checkpoint", HERE); + m_metadomain.ContinueFromCheckpoint(&m_adios, m_params); } } } diff --git a/src/engines/engine_run.cpp b/src/engines/engine_run.cpp index e5c8d8647..bec5b8652 100644 --- a/src/engines/engine_run.cpp +++ b/src/engines/engine_run.cpp @@ -1,6 +1,7 @@ #include "enums.h" #include "arch/traits.h" +#include "utils/diag.h" #include "metrics/kerr_schild.h" #include "metrics/kerr_schild_0.h" @@ -57,9 +58,9 @@ namespace ntt { } auto print_sorting = (sort_interval > 0 and step % sort_interval == 0); - // advance time & timestep - ++step; + // advance time & step time += dt; + ++step; auto print_output = false; auto print_checkpoint = false; @@ -75,27 +76,43 @@ namespace ntt { }; print_output = m_metadomain.Write(m_params, step, + step - 1, time, + time - dt, lambda_custom_field_output); } else { - print_output = m_metadomain.Write(m_params, step, time); + print_output = m_metadomain.Write(m_params, step, step - 1, time, time - dt); } timers.stop("Output"); timers.start("Checkpoint"); - print_checkpoint = m_metadomain.WriteCheckpoint(m_params, step, time); + print_checkpoint = m_metadomain.WriteCheckpoint(m_params, + step, + step - 1, + time, + time - dt); timers.stop("Checkpoint"); #endif // advance time_history time_history.tick(); - // print final timestep report + // print timestep report if (diag_interval > 0 and step % diag_interval == 0) { - print_step_report(timers, - time_history, - print_output, - print_checkpoint, - print_sorting); + diag::printDiagnostics( + step - 1, + max_steps, + time - dt, + dt, + timers, + time_history, + m_metadomain.l_ncells(), + m_metadomain.species_labels(), + m_metadomain.l_npart_perspec(), + m_metadomain.l_maxnpart_perspec(), + print_sorting, + print_output, + print_checkpoint, + m_params.get("diagnostics.colored_stdout")); } timers.resetAll(); } diff --git a/src/framework/domain/checkpoint.cpp b/src/framework/domain/checkpoint.cpp index 569a61093..c95e3dd27 100644 --- a/src/framework/domain/checkpoint.cpp +++ b/src/framework/domain/checkpoint.cpp @@ -12,6 +12,7 @@ #include "metrics/qspherical.h" #include "metrics/spherical.h" +#include "checkpoint/reader.h" #include "checkpoint/writer.h" #include "framework/domain/metadomain.h" #include "framework/parameters.h" @@ -21,11 +22,12 @@ namespace ntt { template void Metadomain::InitCheckpointWriter(adios2::ADIOS* ptr_adios, const SimulationParams& params) { + raise::ErrorIf(ptr_adios == nullptr, "adios == nullptr", HERE); raise::ErrorIf( - local_subdomain_indices().size() != 1, + l_subdomain_indices().size() != 1, "Checkpoint writing for now is only supported for one subdomain per rank", HERE); - auto local_domain = subdomain_ptr(local_subdomain_indices()[0]); + auto local_domain = subdomain_ptr(l_subdomain_indices()[0]); raise::ErrorIf(local_domain->is_placeholder(), "local_domain is a placeholder", HERE); @@ -56,24 +58,26 @@ namespace ntt { template auto Metadomain::WriteCheckpoint(const SimulationParams& params, - std::size_t step, - long double time) -> bool { + std::size_t current_step, + std::size_t finished_step, + long double current_time, + long double finished_time) -> bool { raise::ErrorIf( - local_subdomain_indices().size() != 1, + l_subdomain_indices().size() != 1, "Checkpointing for now is only supported for one subdomain per rank", HERE); - if (!g_checkpoint_writer.shouldSave(step, time)) { + if (!g_checkpoint_writer.shouldSave(finished_step, finished_time) or + finished_step <= 1) { return false; } - auto local_domain = subdomain_ptr(local_subdomain_indices()[0]); + auto local_domain = subdomain_ptr(l_subdomain_indices()[0]); raise::ErrorIf(local_domain->is_placeholder(), "local_domain is a placeholder", HERE); logger::Checkpoint("Writing checkpoint", HERE); - g_checkpoint_writer.beginSaving(step, time); + g_checkpoint_writer.beginSaving(current_step, current_time); { - - g_checkpoint_writer.saveAttrs(params, time); + g_checkpoint_writer.saveAttrs(params, current_time); g_checkpoint_writer.saveField("em", local_domain->fields.em); if constexpr (S == SimEngine::GRPIC) { @@ -252,6 +256,220 @@ namespace ntt { return true; } + template + void Metadomain::ContinueFromCheckpoint(adios2::ADIOS* ptr_adios, + const SimulationParams& params) { + raise::ErrorIf(ptr_adios == nullptr, "adios == nullptr", HERE); + auto fname = fmt::format( + "checkpoints/step-%08lu.bp", + params.template get("checkpoint.start_step")); + logger::Checkpoint(fmt::format("Reading checkpoint from %s", fname.c_str()), + HERE); + + adios2::IO io = ptr_adios->DeclareIO("Entity::CheckpointRead"); + io.SetEngine("BPFile"); +#if !defined(MPI_ENABLED) + adios2::Engine reader = io.Open(fname, adios2::Mode::Read); +#else + adios2::Engine reader = io.Open(fname, adios2::Mode::Read, MPI_COMM_SELF); +#endif + + reader.BeginStep(); + for (auto& ldidx : l_subdomain_indices()) { + auto& domain = g_subdomains[ldidx]; + adios2::Box range; + for (auto d { 0u }; d < M::Dim; ++d) { + range.first.push_back(domain.offset_ncells()[d]); + range.second.push_back(domain.mesh.n_all()[d]); + } + range.first.push_back(0); + range.second.push_back(6); + checkpoint::ReadFields(io, reader, "em", range, domain.fields.em); + if constexpr (S == ntt::SimEngine::GRPIC) { + checkpoint::ReadFields(io, + reader, + "em0", + range, + domain.fields.em0); + adios2::Box range3; + for (auto d { 0u }; d < M::Dim; ++d) { + range3.first.push_back(domain.offset_ncells()[d]); + range3.second.push_back(domain.mesh.n_all()[d]); + } + range3.first.push_back(0); + range3.second.push_back(3); + checkpoint::ReadFields(io, + reader, + "cur0", + range3, + domain.fields.cur0); + } + for (auto s { 0u }; s < (unsigned short)(domain.species.size()); ++s) { + const auto [loc_npart, offset_npart] = + checkpoint::ReadParticleCount(io, reader, s, ldidx, ndomains()); + + raise::ErrorIf(loc_npart > domain.species[s].maxnpart(), + "loc_npart > domain.species[s].maxnpart()", + HERE); + if (loc_npart == 0) { + continue; + } + if constexpr (M::Dim == Dim::_1D or M::Dim == Dim::_2D or + M::Dim == Dim::_3D) { + checkpoint::ReadParticleData(io, + reader, + "i1", + s, + domain.species[s].i1, + loc_npart, + offset_npart); + checkpoint::ReadParticleData(io, + reader, + "dx1", + s, + domain.species[s].dx1, + loc_npart, + offset_npart); + checkpoint::ReadParticleData(io, + reader, + "i1_prev", + s, + domain.species[s].i1_prev, + loc_npart, + offset_npart); + checkpoint::ReadParticleData(io, + reader, + "dx1_prev", + s, + domain.species[s].dx1_prev, + loc_npart, + offset_npart); + } + if constexpr (M::Dim == Dim::_2D or M::Dim == Dim::_3D) { + checkpoint::ReadParticleData(io, + reader, + "i2", + s, + domain.species[s].i2, + loc_npart, + offset_npart); + checkpoint::ReadParticleData(io, + reader, + "dx2", + s, + domain.species[s].dx2, + loc_npart, + offset_npart); + checkpoint::ReadParticleData(io, + reader, + "i2_prev", + s, + domain.species[s].i2_prev, + loc_npart, + offset_npart); + checkpoint::ReadParticleData(io, + reader, + "dx2_prev", + s, + domain.species[s].dx2_prev, + loc_npart, + offset_npart); + } + if constexpr (M::Dim == Dim::_3D) { + checkpoint::ReadParticleData(io, + reader, + "i3", + s, + domain.species[s].i3, + loc_npart, + offset_npart); + checkpoint::ReadParticleData(io, + reader, + "dx3", + s, + domain.species[s].dx3, + loc_npart, + offset_npart); + checkpoint::ReadParticleData(io, + reader, + "i3_prev", + s, + domain.species[s].i3_prev, + loc_npart, + offset_npart); + checkpoint::ReadParticleData(io, + reader, + "dx3_prev", + s, + domain.species[s].dx3_prev, + loc_npart, + offset_npart); + } + if constexpr (M::Dim == Dim::_2D and M::CoordType != Coord::Cart) { + checkpoint::ReadParticleData(io, + reader, + "phi", + s, + domain.species[s].phi, + loc_npart, + offset_npart); + } + checkpoint::ReadParticleData(io, + reader, + "ux1", + s, + domain.species[s].ux1, + loc_npart, + offset_npart); + checkpoint::ReadParticleData(io, + reader, + "ux2", + s, + domain.species[s].ux2, + loc_npart, + offset_npart); + checkpoint::ReadParticleData(io, + reader, + "ux3", + s, + domain.species[s].ux3, + loc_npart, + offset_npart); + checkpoint::ReadParticleData(io, + reader, + "tag", + s, + domain.species[s].tag, + loc_npart, + offset_npart); + checkpoint::ReadParticleData(io, + reader, + "weight", + s, + domain.species[s].weight, + loc_npart, + offset_npart); + for (auto p { 0u }; p < domain.species[s].npld(); ++p) { + checkpoint::ReadParticleData(io, + reader, + fmt::format("pld%d", p + 1), + s, + domain.species[s].pld[p], + loc_npart, + offset_npart); + } + domain.species[s].set_npart(loc_npart); + } // species loop + + } // local subdomain loop + + reader.EndStep(); + reader.Close(); + logger::Checkpoint( + fmt::format("Checkpoint reading done from %s", fname.c_str()), + HERE); + } + template struct Metadomain>; template struct Metadomain>; template struct Metadomain>; diff --git a/src/framework/domain/metadomain.cpp b/src/framework/domain/metadomain.cpp index cdc9e5a3d..5e66bc366 100644 --- a/src/framework/domain/metadomain.cpp +++ b/src/framework/domain/metadomain.cpp @@ -342,7 +342,7 @@ namespace ntt { } // check that local subdomains are contained in g_local_subdomain_indices auto contained_in_local = false; - for (const auto& gidx : g_local_subdomain_indices) { + for (const auto& gidx : l_subdomain_indices()) { contained_in_local |= (idx == gidx); } #if defined(MPI_ENABLED) diff --git a/src/framework/domain/metadomain.h b/src/framework/domain/metadomain.h index 6a3c64742..027a2982d 100644 --- a/src/framework/domain/metadomain.h +++ b/src/framework/domain/metadomain.h @@ -74,14 +74,14 @@ namespace ntt { template void runOnLocalDomains(Func func, Args&&... args) { - for (auto& ldidx : g_local_subdomain_indices) { + for (auto& ldidx : l_subdomain_indices()) { func(g_subdomains[ldidx], std::forward(args)...); } } template void runOnLocalDomainsConst(Func func, Args&&... args) const { - for (auto& ldidx : g_local_subdomain_indices) { + for (auto& ldidx : l_subdomain_indices()) { func(g_subdomains[ldidx], std::forward(args)...); } } @@ -118,15 +118,21 @@ namespace ntt { void InitWriter(adios2::ADIOS*, const SimulationParams&, bool is_resuming); auto Write(const SimulationParams&, std::size_t, + std::size_t, + long double, long double, std::function&, std::size_t, const Domain&)> = {}) -> bool; void InitCheckpointWriter(adios2::ADIOS*, const SimulationParams&); - auto WriteCheckpoint(const SimulationParams&, std::size_t, long double) -> bool; + auto WriteCheckpoint(const SimulationParams&, + std::size_t, + std::size_t, + long double, + long double) -> bool; - void ContinueFromCheckpoint(); + void ContinueFromCheckpoint(adios2::ADIOS*, const SimulationParams&); #endif /* setters -------------------------------------------------------------- */ @@ -165,10 +171,60 @@ namespace ntt { } [[nodiscard]] - auto local_subdomain_indices() const -> std::vector { + auto l_subdomain_indices() const -> std::vector { return g_local_subdomain_indices; } + [[nodiscard]] + auto l_npart_perspec() const -> std::vector { + std::vector npart(g_species_params.size(), 0); + for (const auto& ldidx : l_subdomain_indices()) { + for (std::size_t i = 0; i < g_species_params.size(); ++i) { + npart[i] += g_subdomains[ldidx].species[i].npart(); + } + } + return npart; + } + + [[nodiscard]] + auto l_maxnpart_perspec() const -> std::vector { + std::vector maxnpart(g_species_params.size(), 0); + for (const auto& ldidx : l_subdomain_indices()) { + for (std::size_t i = 0; i < g_species_params.size(); ++i) { + maxnpart[i] += g_subdomains[ldidx].species[i].maxnpart(); + } + } + return maxnpart; + } + + [[nodiscard]] + auto l_npart() const -> std::size_t { + const auto npart = l_npart_perspec(); + return std::accumulate(npart.begin(), npart.end(), 0); + } + + [[nodiscard]] + auto l_ncells() const -> std::size_t { + std::size_t ncells_local = 0; + for (const auto& ldidx : l_subdomain_indices()) { + std::size_t ncells = 1; + for (const auto& n : g_subdomains[ldidx].mesh.n_all()) { + ncells *= n; + } + ncells_local += ncells; + } + return ncells_local; + } + + [[nodiscard]] + auto species_labels() const -> std::vector { + std::vector labels; + for (const auto& sp : g_species_params) { + labels.push_back(sp.label()); + } + return labels; + } + private: // domain information unsigned int g_ndomains; diff --git a/src/framework/domain/output.cpp b/src/framework/domain/output.cpp index e4e9b3e4b..b957a55df 100644 --- a/src/framework/domain/output.cpp +++ b/src/framework/domain/output.cpp @@ -37,10 +37,10 @@ namespace ntt { const SimulationParams& params, bool is_resuming) { raise::ErrorIf( - local_subdomain_indices().size() != 1, + l_subdomain_indices().size() != 1, "Output for now is only supported for one subdomain per rank", HERE); - auto local_domain = subdomain_ptr(local_subdomain_indices()[0]); + auto local_domain = subdomain_ptr(l_subdomain_indices()[0]); raise::ErrorIf(local_domain->is_placeholder(), "local_domain is a placeholder", HERE); @@ -172,35 +172,43 @@ namespace ntt { template auto Metadomain::Write( const SimulationParams& params, - std::size_t step, - long double time, + std::size_t current_step, + std::size_t finished_step, + long double current_time, + long double finished_time, std::function< void(const std::string&, ndfield_t&, std::size_t, const Domain&)> CustomFieldOutput) -> bool { raise::ErrorIf( - local_subdomain_indices().size() != 1, + l_subdomain_indices().size() != 1, "Output for now is only supported for one subdomain per rank", HERE); const auto write_fields = params.template get( "output.fields.enable") and - g_writer.shouldWrite("fields", step, time); + g_writer.shouldWrite("fields", + finished_step, + finished_time); const auto write_particles = params.template get( "output.particles.enable") and - g_writer.shouldWrite("particles", step, time); + g_writer.shouldWrite("particles", + finished_step, + finished_time); const auto write_spectra = params.template get( "output.spectra.enable") and - g_writer.shouldWrite("spectra", step, time); + g_writer.shouldWrite("spectra", + finished_step, + finished_time); if (not(write_fields or write_particles or write_spectra)) { return false; } - auto local_domain = subdomain_ptr(local_subdomain_indices()[0]); + auto local_domain = subdomain_ptr(l_subdomain_indices()[0]); raise::ErrorIf(local_domain->is_placeholder(), "local_domain is a placeholder", HERE); logger::Checkpoint("Writing output", HERE); g_writer.beginWriting(params.template get("simulation.name"), - step, - time); + current_step, + current_time); if (write_fields) { const auto incl_ghosts = params.template get("output.debug.ghosts"); diff --git a/src/framework/parameters.cpp b/src/framework/parameters.cpp index 12f4d2ffa..9a4c9c616 100644 --- a/src/framework/parameters.cpp +++ b/src/framework/parameters.cpp @@ -317,7 +317,6 @@ namespace ntt { set("scales.q0", V0 / (ppc0 * SQR(skindepth0))); set("grid.metric.metric", metric_enum); - set("algorithms.timestep.dt", get("algorithms.timestep.CFL") * dx0); } } @@ -421,7 +420,8 @@ namespace ntt { /* [algorithms.timestep] ------------------------------------------------ */ set("algorithms.timestep.CFL", toml::find_or(toml_data, "algorithms", "timestep", "CFL", defaults::cfl)); - promiseToDefine("algorithms.timestep.dt"); + set("algorithms.timestep.dt", + get("algorithms.timestep.CFL") * get("scales.dx0")); set("algorithms.timestep.correction", toml::find_or(toml_data, "algorithms", diff --git a/src/framework/parameters.h b/src/framework/parameters.h index 2c03ef812..0f9e29370 100644 --- a/src/framework/parameters.h +++ b/src/framework/parameters.h @@ -24,7 +24,7 @@ namespace ntt { struct SimulationParams : public prm::Parameters { - SimulationParams() = default; + SimulationParams() {} SimulationParams& operator=(const SimulationParams& other) { vars = std::move(other.vars); diff --git a/src/framework/simulation.cpp b/src/framework/simulation.cpp index 74798ffa6..db1b3d474 100644 --- a/src/framework/simulation.cpp +++ b/src/framework/simulation.cpp @@ -53,6 +53,7 @@ namespace ntt { m_params.setRawData(raw_params); std::size_t checkpoint_step = 0; if (is_resuming) { + logger::Checkpoint("Reading params from a checkpoint", HERE); if (not std::filesystem::exists("checkpoints")) { raise::Fatal("No checkpoints found", HERE); } @@ -84,6 +85,7 @@ namespace ntt { m_params.setCheckpointParams(true, checkpoint_step, start_time); m_params.setSetupParams(raw_checkpoint_params); } else { + logger::Checkpoint("Defining new params", HERE); m_params.setImmutableParams(raw_params); m_params.setMutableParams(raw_params); m_params.setCheckpointParams(false, 0, 0.0); From 71025ca84dfd6c6c438703f9781c7f69b4df644c Mon Sep 17 00:00:00 2001 From: haykh Date: Fri, 16 Aug 2024 21:22:48 -0400 Subject: [PATCH 013/773] diag minor issue with non-mpi --- TASKLIST.md | 30 ------------------------------ src/global/utils/timer.cpp | 7 ++++++- 2 files changed, 6 insertions(+), 31 deletions(-) diff --git a/TASKLIST.md b/TASKLIST.md index 82f44d0ea..069a7deb2 100644 --- a/TASKLIST.md +++ b/TASKLIST.md @@ -1,33 +1,3 @@ -# v0.8 - -- [x] thick layer boundary for the monopole -- [x] test with filters -- [x] add diagnostics for nans in fields and particles -- [x] add gravitationally bound atmosphere -- [x] rewrite UniformInjector with global random pool -- [x] add particle deletion routine -- [x] make more user-friendly and understandable boundary conditions -- [x] refine output -- [x] add different moments (momX, momY, momZ, meanGamma) -- [x] add charge -- [x] add per species densities - -# v0.9 - -- [x] add current deposit/filtering for GR -- [x] add moments for GR -- [x] add Maxwellian for GR - -# v1.0.0 - -- [x] particle output -- [x] BUG in MPI particles/currents - -# v1.1.0 - -- [ ] custom boundary conditions for particles and fields -- [ ] transfer GR from v0.9 - ### Performance improvements to try - [ ] removing temporary variables in interpolation diff --git a/src/global/utils/timer.cpp b/src/global/utils/timer.cpp index 1a1a37848..162ba33b7 100644 --- a/src/global/utils/timer.cpp +++ b/src/global/utils/timer.cpp @@ -115,7 +115,12 @@ namespace timer { const auto pcent = static_cast( (timer.second / local_tot) * 100.0); timer_stats.insert( - { name, std::make_tuple(timer.second, pcent, 0.0, 0u, 0u) }); + { name, + std::make_tuple(timer.second, + timer.second / static_cast(npart), + timer.second / static_cast(ncells), + pcent, + 0u) }); } timer_stats.insert({ "Total", std::make_tuple(local_tot, 0.0, 0.0, 100u, 0u) }); #endif From 4f2fd30da3f5d4f94a6f9fbbf905c5b1834a68e7 Mon Sep 17 00:00:00 2001 From: haykh Date: Fri, 16 Aug 2024 21:30:54 -0400 Subject: [PATCH 014/773] conditional action launch --- .github/workflows/actions.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/actions.yml b/.github/workflows/actions.yml index 04bc34050..cd7119789 100644 --- a/.github/workflows/actions.yml +++ b/.github/workflows/actions.yml @@ -16,8 +16,9 @@ jobs: exclude: - device: amd-gpu precision: double - # my AMD GPUs doesn't support fp64 atomics : ( + # my AMD GPU doesn't support fp64 atomics : ( runs-on: [self-hosted, "${{ matrix.device }}"] + if: contains(github.event.head_commit.message, 'totest') steps: - name: Checkout uses: actions/checkout@v3.3.0 From 08702a699d4860a7b99a8947a249834c988608f6 Mon Sep 17 00:00:00 2001 From: haykh Date: Fri, 16 Aug 2024 21:40:48 -0400 Subject: [PATCH 015/773] tasklist upd --- TASKLIST.md | 30 ------------------------------ 1 file changed, 30 deletions(-) diff --git a/TASKLIST.md b/TASKLIST.md index 82f44d0ea..069a7deb2 100644 --- a/TASKLIST.md +++ b/TASKLIST.md @@ -1,33 +1,3 @@ -# v0.8 - -- [x] thick layer boundary for the monopole -- [x] test with filters -- [x] add diagnostics for nans in fields and particles -- [x] add gravitationally bound atmosphere -- [x] rewrite UniformInjector with global random pool -- [x] add particle deletion routine -- [x] make more user-friendly and understandable boundary conditions -- [x] refine output -- [x] add different moments (momX, momY, momZ, meanGamma) -- [x] add charge -- [x] add per species densities - -# v0.9 - -- [x] add current deposit/filtering for GR -- [x] add moments for GR -- [x] add Maxwellian for GR - -# v1.0.0 - -- [x] particle output -- [x] BUG in MPI particles/currents - -# v1.1.0 - -- [ ] custom boundary conditions for particles and fields -- [ ] transfer GR from v0.9 - ### Performance improvements to try - [ ] removing temporary variables in interpolation From 859ee9ff767de89d809314988e4654d17cf79d4d Mon Sep 17 00:00:00 2001 From: haykh Date: Sat, 17 Aug 2024 02:27:54 -0400 Subject: [PATCH 016/773] minor --- src/checkpoint/writer.cpp | 32 ++++++++++++++++------------- src/engines/engine_init.cpp | 8 ++++---- src/engines/engine_run.cpp | 1 + src/framework/domain/checkpoint.cpp | 5 ++--- src/framework/simulation.cpp | 1 + 5 files changed, 26 insertions(+), 21 deletions(-) diff --git a/src/checkpoint/writer.cpp b/src/checkpoint/writer.cpp index 1740c47aa..362373831 100644 --- a/src/checkpoint/writer.cpp +++ b/src/checkpoint/writer.cpp @@ -3,13 +3,13 @@ #include "global.h" #include "arch/kokkos_aliases.h" -#include "arch/mpi_aliases.h" #include "utils/error.h" #include "utils/formatting.h" #include "utils/log.h" #include "framework/parameters.h" +#include #include #include @@ -52,17 +52,9 @@ namespace checkpoint { const std::vector& glob_shape, const std::vector& loc_corner, const std::vector& loc_shape) { - auto gs3 = std::vector(glob_shape.begin(), glob_shape.end()); - auto lc3 = std::vector(loc_corner.begin(), loc_corner.end()); - auto ls3 = std::vector(loc_shape.begin(), loc_shape.end()); auto gs6 = std::vector(glob_shape.begin(), glob_shape.end()); auto lc6 = std::vector(loc_corner.begin(), loc_corner.end()); auto ls6 = std::vector(loc_shape.begin(), loc_shape.end()); - - gs3.push_back(3); - lc3.push_back(0); - ls3.push_back(3); - gs6.push_back(6); lc6.push_back(0); ls6.push_back(6); @@ -70,6 +62,12 @@ namespace checkpoint { m_io.DefineVariable("em", gs6, lc6, ls6, adios2::ConstantDims); if (S == ntt::SimEngine::GRPIC) { m_io.DefineVariable("em0", gs6, lc6, ls6, adios2::ConstantDims); + auto gs3 = std::vector(glob_shape.begin(), glob_shape.end()); + auto lc3 = std::vector(loc_corner.begin(), loc_corner.end()); + auto ls3 = std::vector(loc_shape.begin(), loc_shape.end()); + gs3.push_back(3); + lc3.push_back(0); + ls3.push_back(3); m_io.DefineVariable("cur0", gs3, lc3, ls3, adios2::ConstantDims); } } @@ -150,6 +148,10 @@ namespace checkpoint { m_writer = m_io.Open(fname, adios2::Mode::Write); auto meta_fname = fmt::format("checkpoints/meta-%08lu.toml", step); m_written.push_back({ fname, meta_fname }); + logger::Checkpoint(fmt::format("Writing checkpoint to %s and %s", + fname.c_str(), + meta_fname.c_str()), + HERE); } catch (std::exception& e) { raise::Fatal(e.what(), HERE); } @@ -215,7 +217,9 @@ namespace checkpoint { const ndfield_t& field) { auto field_h = Kokkos::create_mirror_view(field); Kokkos::deep_copy(field_h, field); - m_writer.Put(m_io.InquireVariable(fieldname), field_h.data()); + m_writer.Put(m_io.InquireVariable(fieldname), + field_h.data(), + adios2::Mode::Sync); } template @@ -224,12 +228,12 @@ namespace checkpoint { std::size_t loc_offset, std::size_t loc_size, const array_t& data) { - auto var = m_io.InquireVariable(quantity); - var.SetShape({ glob_total }); - var.SetSelection(adios2::Box({ loc_offset }, { loc_size })); - auto slice = range_tuple_t(0, loc_size); auto data_h = Kokkos::create_mirror_view(data); Kokkos::deep_copy(data_h, data); + auto slice = range_tuple_t(0, loc_size); + auto var = m_io.InquireVariable(quantity); + var.SetShape({ glob_total }); + var.SetSelection(adios2::Box({ loc_offset }, { loc_size })); m_writer.Put(var, Kokkos::subview(data_h, slice).data()); } diff --git a/src/engines/engine_init.cpp b/src/engines/engine_init.cpp index e4ce9fa5f..538328e11 100644 --- a/src/engines/engine_init.cpp +++ b/src/engines/engine_init.cpp @@ -21,10 +21,10 @@ namespace ntt { template void Engine::init() { if constexpr (pgen_is_ok) { -#if defined(OUTPUT_ENABLED) - m_metadomain.InitWriter(&m_adios, m_params, is_resuming); - m_metadomain.InitCheckpointWriter(&m_adios, m_params); -#endif + // #if defined(OUTPUT_ENABLED) + // m_metadomain.InitWriter(&m_adios, m_params, is_resuming); + // m_metadomain.InitCheckpointWriter(&m_adios, m_params); + // #endif logger::Checkpoint("Initializing Engine", HERE); if (not is_resuming) { // start a new simulation with initial conditions diff --git a/src/engines/engine_run.cpp b/src/engines/engine_run.cpp index bec5b8652..3262fb023 100644 --- a/src/engines/engine_run.cpp +++ b/src/engines/engine_run.cpp @@ -20,6 +20,7 @@ namespace ntt { void Engine::run() { if constexpr (pgen_is_ok) { init(); + return; auto timers = timer::Timers { { "FieldSolver", diff --git a/src/framework/domain/checkpoint.cpp b/src/framework/domain/checkpoint.cpp index c95e3dd27..af2f919bf 100644 --- a/src/framework/domain/checkpoint.cpp +++ b/src/framework/domain/checkpoint.cpp @@ -32,9 +32,9 @@ namespace ntt { "local_domain is a placeholder", HERE); - auto glob_shape_with_ghosts = mesh().n_active(); + auto glob_shape_with_ghosts = mesh().n_all(); auto off_ncells_with_ghosts = local_domain->offset_ncells(); - auto loc_shape_with_ghosts = local_domain->mesh.n_active(); + auto loc_shape_with_ghosts = local_domain->mesh.n_all(); std::vector nplds; for (auto s { 0u }; s < local_domain->species.size(); ++s) { @@ -78,7 +78,6 @@ namespace ntt { g_checkpoint_writer.beginSaving(current_step, current_time); { g_checkpoint_writer.saveAttrs(params, current_time); - g_checkpoint_writer.saveField("em", local_domain->fields.em); if constexpr (S == SimEngine::GRPIC) { g_checkpoint_writer.saveField("em0", local_domain->fields.em0); diff --git a/src/framework/simulation.cpp b/src/framework/simulation.cpp index db1b3d474..9961eb3eb 100644 --- a/src/framework/simulation.cpp +++ b/src/framework/simulation.cpp @@ -76,6 +76,7 @@ namespace ntt { HERE); checkpoint_inputfname = inputfname; } + logger::Checkpoint(fmt::format("Using %08lu", checkpoint_step), HERE); const auto raw_checkpoint_params = toml::parse(checkpoint_inputfname); const auto start_time = toml::find(raw_checkpoint_params, "metadata", From 08e9acb8bf89a2c7ded76154c8688f6d42dc8c1f Mon Sep 17 00:00:00 2001 From: hayk Date: Wed, 21 Aug 2024 21:12:01 -0400 Subject: [PATCH 017/773] minor bugs & leftovers --- src/engines/engine_init.cpp | 8 ++++---- src/engines/engine_run.cpp | 1 - src/output/writer.cpp | 6 +++--- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/engines/engine_init.cpp b/src/engines/engine_init.cpp index 538328e11..e4ce9fa5f 100644 --- a/src/engines/engine_init.cpp +++ b/src/engines/engine_init.cpp @@ -21,10 +21,10 @@ namespace ntt { template void Engine::init() { if constexpr (pgen_is_ok) { - // #if defined(OUTPUT_ENABLED) - // m_metadomain.InitWriter(&m_adios, m_params, is_resuming); - // m_metadomain.InitCheckpointWriter(&m_adios, m_params); - // #endif +#if defined(OUTPUT_ENABLED) + m_metadomain.InitWriter(&m_adios, m_params, is_resuming); + m_metadomain.InitCheckpointWriter(&m_adios, m_params); +#endif logger::Checkpoint("Initializing Engine", HERE); if (not is_resuming) { // start a new simulation with initial conditions diff --git a/src/engines/engine_run.cpp b/src/engines/engine_run.cpp index 3262fb023..bec5b8652 100644 --- a/src/engines/engine_run.cpp +++ b/src/engines/engine_run.cpp @@ -20,7 +20,6 @@ namespace ntt { void Engine::run() { if constexpr (pgen_is_ok) { init(); - return; auto timers = timer::Timers { { "FieldSolver", diff --git a/src/output/writer.cpp b/src/output/writer.cpp index 37f574275..62b7f78c3 100644 --- a/src/output/writer.cpp +++ b/src/output/writer.cpp @@ -4,6 +4,7 @@ #include "arch/kokkos_aliases.h" #include "utils/error.h" +#include "utils/formatting.h" #include "utils/param_container.h" #include "utils/tools.h" @@ -38,8 +39,7 @@ namespace out { void Writer::addTracker(const std::string& type, std::size_t interval, long double interval_time) { - m_trackers.insert(std::pair( - { type, tools::Tracker(type, interval, interval_time) })); + m_trackers.insert({ type, tools::Tracker(type, interval, interval_time) }); } auto Writer::shouldWrite(const std::string& type, @@ -48,7 +48,7 @@ namespace out { if (m_trackers.find(type) != m_trackers.end()) { return m_trackers.at(type).shouldWrite(step, time); } else { - raise::Error("Tracker type not found", HERE); + raise::Error(fmt::format("Tracker type %s not found", type.c_str()), HERE); return false; } } From bbb3c46c86f56943782325c49c75f1d373360eb5 Mon Sep 17 00:00:00 2001 From: haykh Date: Mon, 26 Aug 2024 09:34:37 -0400 Subject: [PATCH 018/773] disable checkpoint @ keep=0 --- src/checkpoint/writer.cpp | 2 +- src/framework/domain/checkpoint.cpp | 20 +++++++++++--------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/checkpoint/writer.cpp b/src/checkpoint/writer.cpp index 362373831..9e73905ae 100644 --- a/src/checkpoint/writer.cpp +++ b/src/checkpoint/writer.cpp @@ -27,7 +27,7 @@ namespace checkpoint { int keep) { m_keep = keep; m_enabled = keep != 0; - if (!m_enabled) { + if (not m_enabled) { return; } m_tracker.init("checkpoint", interval, interval_time); diff --git a/src/framework/domain/checkpoint.cpp b/src/framework/domain/checkpoint.cpp index af2f919bf..6695e3965 100644 --- a/src/framework/domain/checkpoint.cpp +++ b/src/framework/domain/checkpoint.cpp @@ -46,14 +46,16 @@ namespace ntt { params.template get("checkpoint.interval"), params.template get("checkpoint.interval_time"), params.template get("checkpoint.keep")); - g_checkpoint_writer.defineFieldVariables(S, - glob_shape_with_ghosts, - off_ncells_with_ghosts, - loc_shape_with_ghosts); - g_checkpoint_writer.defineParticleVariables(M::CoordType, - M::Dim, - local_domain->species.size(), - nplds); + if (g_checkpoint_writer.enabled()) { + g_checkpoint_writer.defineFieldVariables(S, + glob_shape_with_ghosts, + off_ncells_with_ghosts, + loc_shape_with_ghosts); + g_checkpoint_writer.defineParticleVariables(M::CoordType, + M::Dim, + local_domain->species.size(), + nplds); + } } template @@ -66,7 +68,7 @@ namespace ntt { l_subdomain_indices().size() != 1, "Checkpointing for now is only supported for one subdomain per rank", HERE); - if (!g_checkpoint_writer.shouldSave(finished_step, finished_time) or + if (not g_checkpoint_writer.shouldSave(finished_step, finished_time) or finished_step <= 1) { return false; } From 0a3821bc1d0289aa61474929000fe45068ebe762 Mon Sep 17 00:00:00 2001 From: haykh Date: Mon, 26 Aug 2024 09:57:14 -0400 Subject: [PATCH 019/773] minor warnings & bugs --- src/engines/srpic.hpp | 11 +++++++++-- src/framework/parameters.cpp | 2 +- src/global/utils/timer.cpp | 1 - 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/engines/srpic.hpp b/src/engines/srpic.hpp index 9b8b3f19b..78c8f371e 100644 --- a/src/engines/srpic.hpp +++ b/src/engines/srpic.hpp @@ -885,8 +885,15 @@ namespace ntt { xi_min.size() != static_cast(M::Dim), "Invalid range size", HERE); - for (const unsigned short comp : - { normal_b_comp, tang_e_comp1, tang_e_comp2 }) { + std::vector comps; + if (tags & BC::E) { + comps.push_back(tang_e_comp1); + comps.push_back(tang_e_comp2); + } + if (tags & BC::B) { + comps.push_back(normal_b_comp); + } + for (const auto& comp : comps) { if constexpr (M::Dim == Dim::_1D) { Kokkos::deep_copy(Kokkos::subview(domain.fields.em, std::make_pair(xi_min[0], xi_max[0]), diff --git a/src/framework/parameters.cpp b/src/framework/parameters.cpp index 9a4c9c616..1d4672212 100644 --- a/src/framework/parameters.cpp +++ b/src/framework/parameters.cpp @@ -795,7 +795,7 @@ namespace ntt { void SimulationParams::setSetupParams(const toml::value& toml_data) { /* [setup] -------------------------------------------------------------- */ - const auto& setup = toml::find_or(raw_data, "setup", toml::table {}); + const auto& setup = toml::find_or(toml_data, "setup", toml::table {}); for (const auto& [key, val] : setup) { if (val.is_boolean()) { set("setup." + key, (bool)(val.as_boolean())); diff --git a/src/global/utils/timer.cpp b/src/global/utils/timer.cpp index 162ba33b7..b5f4408ca 100644 --- a/src/global/utils/timer.cpp +++ b/src/global/utils/timer.cpp @@ -263,7 +263,6 @@ namespace timer { std::string units = "µs"; auto time = std::get<0>(stats.at(name)); const auto tot_pct = std::get<3>(stats.at(name)); - const auto var_pct = std::get<4>(stats.at(name)); if (flags & Timer::AutoConvert) { convertTime(time, units); } From 1920f4415ec6d78c5f880a2afd73a2deac805213 Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Wed, 21 Aug 2024 20:15:11 -0400 Subject: [PATCH 020/773] Add bulk velocity as moment output. --- src/framework/domain/output.cpp | 8 ++++ src/global/enums.h | 5 ++- src/global/tests/enums.cpp | 2 +- src/kernels/particle_moments.hpp | 65 +++++++++++++++++++++++++++++++- src/output/fields.cpp | 3 ++ src/output/fields.h | 4 +- 6 files changed, 81 insertions(+), 6 deletions(-) diff --git a/src/framework/domain/output.cpp b/src/framework/domain/output.cpp index be154ce16..39c44192d 100644 --- a/src/framework/domain/output.cpp +++ b/src/framework/domain/output.cpp @@ -294,6 +294,14 @@ namespace ntt { {}, local_domain->fields.bckp, c); + } else if (fld.id() == FldsID::V) { + ComputeMoments(params, + local_domain->mesh, + local_domain->species, + fld.species, + fld.comp[0], + local_domain->fields.bckp, + c); } else { raise::Error("Wrong moment requested for output", HERE); } diff --git a/src/global/enums.h b/src/global/enums.h index 57822dec4..f7b1278c6 100644 --- a/src/global/enums.h +++ b/src/global/enums.h @@ -289,16 +289,17 @@ namespace ntt { N = 12, Nppc = 13, Custom = 14, + V = 15, }; constexpr FldsID(uint8_t c) : enums_hidden::BaseEnum { c } {} static constexpr type variants[] = { E, divE, D, divD, B, H, J, - A, T, Rho, Charge, N, Nppc, Custom }; + A, T, Rho, Charge, N, Nppc, Custom , V}; static constexpr const char* lookup[] = { "e", "dive", "d", "divd", "b", "h", "j", "a", "t", "rho", "charge", "n", - "nppc", "custom" }; + "nppc", "custom", "v" }; static constexpr std::size_t total = sizeof(variants) / sizeof(variants[0]); }; diff --git a/src/global/tests/enums.cpp b/src/global/tests/enums.cpp index 1fc57398f..8f814e9df 100644 --- a/src/global/tests/enums.cpp +++ b/src/global/tests/enums.cpp @@ -68,7 +68,7 @@ auto main() -> int { enum_str_t all_out_flds = { "e", "dive", "d", "divd", "b", "h", "j", "a", "t", "rho", - "charge", "n", "nppc", "custom" }; + "charge", "n", "nppc", "custom" , "v"}; checkEnum(all_coords); checkEnum(all_metrics); diff --git a/src/kernels/particle_moments.hpp b/src/kernels/particle_moments.hpp index 8b668a036..83caea563 100644 --- a/src/kernels/particle_moments.hpp +++ b/src/kernels/particle_moments.hpp @@ -41,7 +41,7 @@ namespace kernel { static constexpr auto D = M::Dim; static_assert((F == FldsID::Rho) || (F == FldsID::Charge) || - (F == FldsID::N) || (F == FldsID::Nppc) || (F == FldsID::T), + (F == FldsID::N) || (F == FldsID::Nppc) || (F == FldsID::T) || (F == FldsID::V), "Invalid field ID"); const unsigned short c1, c2; @@ -89,7 +89,7 @@ namespace kernel { std::size_t ni2, real_t inv_n0, unsigned short window) - : c1 { (components.size() == 2) ? components[0] + : c1 { (components.size() > 0) ? components[0] : static_cast(0) } , c2 { (components.size() == 2) ? components[1] : static_cast(0) } @@ -205,6 +205,67 @@ namespace kernel { coeff = contrib; } + if constexpr (F == FldsID::V) { + real_t gamma { ZERO }; + // for stress-energy tensor + vec_t u_Phys { ZERO }; + if constexpr (S == SimEngine::SRPIC) { + // SR + // stress-energy tensor for SR is computed in the tetrad (hatted) basis + if constexpr (M::CoordType == Coord::Cart) { + u_Phys[0] = ux1(p); + u_Phys[1] = ux2(p); + u_Phys[2] = ux3(p); + } else { + static_assert(D != Dim::_1D, "non-Cartesian SRPIC 1D"); + coord_t x_Code { ZERO }; + x_Code[0] = static_cast(i1(p)) + static_cast(dx1(p)); + x_Code[1] = static_cast(i2(p)) + static_cast(dx2(p)); + if constexpr (D == Dim::_3D) { + x_Code[2] = static_cast(i3(p)) + static_cast(dx3(p)); + } else { + x_Code[2] = phi(p); + } + metric.template transform_xyz( + x_Code, + { ux1(p), ux2(p), ux3(p) }, + u_Phys); + } + if (mass == ZERO) { + gamma = NORM(u_Phys[0], u_Phys[1], u_Phys[2]); + } else { + gamma = math::sqrt(ONE + NORM_SQR(u_Phys[0], u_Phys[1], u_Phys[2])); + } + } else { + // GR + // stress-energy tensor for GR is computed in contravariant basis + static_assert(D != Dim::_1D, "GRPIC 1D"); + coord_t x_Code { ZERO }; + x_Code[0] = static_cast(i1(p)) + static_cast(dx1(p)); + x_Code[1] = static_cast(i2(p)) + static_cast(dx2(p)); + if constexpr (D == Dim::_3D) { + x_Code[2] = static_cast(i3(p)) + static_cast(dx3(p)); + } + vec_t u_Cntrv { ZERO }; + // compute u_i u^i for energy + metric.template transform(x_Code, + { ux1(p), ux2(p), ux3(p) }, + u_Cntrv); + gamma = u_Cntrv[0] * ux1(p) + u_Cntrv[1] * ux2(p) + u_Cntrv[2] * ux3(p); + if (mass == ZERO) { + gamma = math::sqrt(gamma); + } else { + gamma = math::sqrt(ONE + gamma); + } + metric.template transform(x_Code, u_Cntrv, u_Phys); + } + // compute the corresponding moment + coeff = u_Phys[c1 - 1] / gamma; + } else { + // for other cases, use the `contrib` defined above + coeff = contrib; + } + if constexpr (F != FldsID::Nppc) { // for nppc calculation ... // ... do not take volume, weights or smoothing into account diff --git a/src/output/fields.cpp b/src/output/fields.cpp index aa5a752d4..0c2ea5e50 100644 --- a/src/output/fields.cpp +++ b/src/output/fields.cpp @@ -44,6 +44,9 @@ namespace out { } else if (id() == FldsID::T) { // energy-momentum tensor comp = InterpretComponents({ name.substr(1, 1), name.substr(2, 1) }); + } else if (id() == FldsID::V) { + // energy-momentum tensor + comp = InterpretComponents({ name.substr(1, 1) }); } else { // scalar (Rho, divE, Custom, etc.) comp = {}; diff --git a/src/output/fields.h b/src/output/fields.h index a520a246d..4fde18ed2 100644 --- a/src/output/fields.h +++ b/src/output/fields.h @@ -43,7 +43,7 @@ namespace out { [[nodiscard]] auto is_moment() const -> bool { return (id() == FldsID::T || id() == FldsID::Rho || id() == FldsID::Nppc || - id() == FldsID::N || id() == FldsID::Charge); + id() == FldsID::N || id() == FldsID::Charge || id() == FldsID::V); } [[nodiscard]] @@ -94,6 +94,8 @@ namespace out { tmp += m_name.substr(1, 2); } else if (id() == FldsID::A) { tmp += "3"; + } else if (id() == FldsID::V) { + tmp += m_name.substr(1, 1); } else if (is_field()) { tmp += "i"; } From bdd96be69727ba0b39ec02b4469a7dca56ed6f40 Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Mon, 26 Aug 2024 11:46:57 -0400 Subject: [PATCH 021/773] Update input. --- input.example.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/input.example.toml b/input.example.toml index 88589495c..1c4e0466d 100644 --- a/input.example.toml +++ b/input.example.toml @@ -329,7 +329,7 @@ # Field quantities to output: # @type: array of strings # @valid: fields: "E", "B", "J", "divE" - # @valid: moments: "Rho", "Charge", "N", "Nppc", "T0i", "Tij" + # @valid: moments: "Rho", "Charge", "N", "Nppc", "T0i", "Tij", "Vi" # @valid: for GR: "D", "H", "divD", "A" # @default: [] # @note: For T, you can use unspecified indices, e.g., Tij, T0i, or specific ones, e.g., Ttt, T00, T02, T23 From 52fc130aa11b8f11c20bfda8b5cc3f834cbf324a Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Mon, 26 Aug 2024 15:06:41 -0400 Subject: [PATCH 022/773] Add powerlaw distribution function. --- src/archetypes/energy_dist.h | 55 ++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/src/archetypes/energy_dist.h b/src/archetypes/energy_dist.h index c5b9d8a87..e2e53493d 100644 --- a/src/archetypes/energy_dist.h +++ b/src/archetypes/energy_dist.h @@ -4,6 +4,7 @@ * @implements * - arch::EnergyDistribution<> * - arch::ColdDist<> : arch::EnergyDistribution<> + * - arch::PowerlawDist<> : arch::EnergyDistribution<> * - arch::Maxwellian<> : arch::EnergyDistribution<> * @namespaces: * - arch:: @@ -67,6 +68,60 @@ namespace arch { } }; + template + struct PowerlawDist : public EnergyDistribution { + using EnergyDistribution::metric; + + PowerlawDist(const M& metric, + random_number_pool_t& pool, + real_t g_min, + real_t g_max, + real_t pl_ind ) + : EnergyDistribution { metric } + , pool { pool } + , g_min { g_min } + , g_max { g_max } + , pl_ind { pl_ind } {} + + + Inline void operator()(const coord_t& x_Code, + vec_t& v, + unsigned short sp) const override { + auto rand_gen = pool.get_state(); + auto rand_X1 = Random(rand_gen); + auto rand_gam = ONE; + + // Power-law distribution from uniform distribution (see https://mathworld.wolfram.com/RandomNumber.html) + if (pl_ind != -1.0) { + rand_gam += math::pow(math::pow(g_min,ONE + pl_ind) + (-math::pow(g_min,ONE + pl_ind) + math::pow(g_max,ONE + pl_ind))*rand_X1,ONE/(ONE + pl_ind)); + } else { + rand_gam += math::pow(g_min,ONE - rand_X1)*math::pow(g_max,rand_X1); + } + auto rand_u = math::sqrt( SQR(rand_gam) - ONE ); + auto rand_X2 = Random(rand_gen); + auto rand_X3 = Random(rand_gen); + v[0] = rand_u * (TWO * rand_X2 - ONE); + v[2] = TWO * rand_u * math::sqrt(rand_X2 * (ONE - rand_X2)); + v[1] = v[2] * math::cos(constant::TWO_PI * rand_X3); + v[2] = v[2] * math::sin(constant::TWO_PI * rand_X3); + + if constexpr (S == SimEngine::GRPIC) { + // convert from the tetrad basis to covariant + vec_t v_Hat; + v_Hat[0] = v[0]; + v_Hat[1] = v[1]; + v_Hat[2] = v[2]; + metric.template transform(x_Code, v_Hat, v); + } + + pool.free_state(rand_gen); + } + + private: + const real_t g_min, g_max, pl_ind; + random_number_pool_t pool; + }; + template struct Maxwellian : public EnergyDistribution { using EnergyDistribution::metric; From 9ad4a8a6d6bb6b4a38d2fc858611ab51fdc26272 Mon Sep 17 00:00:00 2001 From: haykh Date: Mon, 26 Aug 2024 16:50:09 -0400 Subject: [PATCH 023/773] checkpoint fixed --- src/checkpoint/reader.cpp | 8 ++------ src/framework/domain/output.cpp | 11 ++++++----- src/output/writer.cpp | 11 ++++++----- src/output/writer.h | 9 +++++++-- 4 files changed, 21 insertions(+), 18 deletions(-) diff --git a/src/checkpoint/reader.cpp b/src/checkpoint/reader.cpp index c53661b45..bef78f85b 100644 --- a/src/checkpoint/reader.cpp +++ b/src/checkpoint/reader.cpp @@ -27,9 +27,7 @@ namespace checkpoint { auto field_var = io.InquireVariable(field); field_var.SetStepSelection(adios2::Box({ 0 }, { 1 })); field_var.SetSelection(range); - auto array_h = Kokkos::create_mirror_view(array); - reader.Get(field_var, array_h.data()); - Kokkos::deep_copy(array, array_h); + reader.Get(field_var, array.data()); } auto ReadParticleCount(adios2::IO& io, @@ -74,9 +72,7 @@ namespace checkpoint { fmt::format("s%d_%s", s + 1, quantity.c_str())); var.SetStepSelection(adios2::Box({ 0 }, { 1 })); var.SetSelection(adios2::Box({ offset }, { count })); - auto array_h = Kokkos::create_mirror_view(array); - reader.Get(var, array_h.data()); - Kokkos::deep_copy(array, array_h); + reader.Get(var, array.data()); } template void ReadFields(adios2::IO&, diff --git a/src/framework/domain/output.cpp b/src/framework/domain/output.cpp index b957a55df..89f791369 100644 --- a/src/framework/domain/output.cpp +++ b/src/framework/domain/output.cpp @@ -27,6 +27,7 @@ #include #include +#include #include #include @@ -58,7 +59,9 @@ namespace ntt { } } - g_writer.init(ptr_adios, params.template get("output.format")); + g_writer.init(ptr_adios, + params.template get("output.format"), + params.template get("simulation.name")); g_writer.defineMeshLayout(glob_shape_with_ghosts, off_ncells_with_ghosts, loc_shape_with_ghosts, @@ -91,7 +94,7 @@ namespace ntt { params.template get( "output." + std::string(type) + ".interval_time")); } - if (is_resuming) { + if (is_resuming and std::filesystem::exists(g_writer.fname())) { g_writer.setMode(adios2::Mode::Append); } else { g_writer.writeAttrs(params); @@ -206,9 +209,7 @@ namespace ntt { "local_domain is a placeholder", HERE); logger::Checkpoint("Writing output", HERE); - g_writer.beginWriting(params.template get("simulation.name"), - current_step, - current_time); + g_writer.beginWriting(current_step, current_time); if (write_fields) { const auto incl_ghosts = params.template get("output.debug.ghosts"); diff --git a/src/output/writer.cpp b/src/output/writer.cpp index 62b7f78c3..be32fba79 100644 --- a/src/output/writer.cpp +++ b/src/output/writer.cpp @@ -23,7 +23,9 @@ namespace out { - void Writer::init(adios2::ADIOS* ptr_adios, const std::string& engine) { + void Writer::init(adios2::ADIOS* ptr_adios, + const std::string& engine, + const std::string& title) { m_engine = engine; p_adios = ptr_adios; @@ -34,6 +36,7 @@ namespace out { m_io.DefineVariable("Step"); m_io.DefineVariable("Time"); + m_fname = title + (m_engine == "hdf5" ? ".h5" : ".bp"); } void Writer::addTracker(const std::string& type, @@ -297,9 +300,7 @@ namespace out { m_writer.Put(vare, xe_h); } - void Writer::beginWriting(const std::string& fname, - std::size_t tstep, - long double time) { + void Writer::beginWriting(std::size_t tstep, long double time) { raise::ErrorIf(p_adios == nullptr, "ADIOS pointer is null", HERE); p_adios->ExitComputationBlock(); if (m_writing_mode) { @@ -307,7 +308,7 @@ namespace out { } m_writing_mode = true; try { - m_writer = m_io.Open(fname + (m_engine == "hdf5" ? ".h5" : ".bp"), m_mode); + m_writer = m_io.Open(m_fname, m_mode); } catch (std::exception& e) { raise::Fatal(e.what(), HERE); } diff --git a/src/output/writer.h b/src/output/writer.h index 39772e314..b12e2e5fe 100644 --- a/src/output/writer.h +++ b/src/output/writer.h @@ -44,6 +44,7 @@ namespace out { adios2::Dims m_flds_l_shape; bool m_flds_ghosts; std::string m_engine; + std::string m_fname; std::map m_trackers; @@ -60,7 +61,7 @@ namespace out { Writer(Writer&&) = default; - void init(adios2::ADIOS*, const std::string&); + void init(adios2::ADIOS*, const std::string&, const std::string&); void setMode(adios2::Mode); @@ -90,10 +91,14 @@ namespace out { void writeSpectrum(const array_t&, const std::string&); void writeSpectrumBins(const array_t&, const std::string&); - void beginWriting(const std::string&, std::size_t, long double); + void beginWriting(std::size_t, long double); void endWriting(); /* getters -------------------------------------------------------------- */ + auto fname() const -> const std::string& { + return m_fname; + } + auto fieldWriters() const -> const std::vector& { return m_flds_writers; } From 0301034e9c6790bdfd4352c4b8fb718c97964cae Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Mon, 26 Aug 2024 17:53:28 -0400 Subject: [PATCH 024/773] Ongoing. --- setups/srpic/turbulence/pgen.hpp | 29 ++++++++++++----------------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/setups/srpic/turbulence/pgen.hpp b/setups/srpic/turbulence/pgen.hpp index bd8b0ce41..bbd61cc3a 100644 --- a/setups/srpic/turbulence/pgen.hpp +++ b/setups/srpic/turbulence/pgen.hpp @@ -185,7 +185,7 @@ namespace user { const auto injector = arch::UniformInjector( energy_dist, { 1, 2 }); - const real_t ndens = 1.0; + const real_t ndens = 0.9; arch::InjectUniform(params, local_domain, injector, @@ -193,22 +193,17 @@ namespace user { } { - // const auto energy_dist = arch::Maxwellian(local_domain.mesh.metric, - // local_domain.random_pool, - // temperature*10); - // // const auto energy_dist = arch::Maxwellian(local_domain.mesh.metric, - // // local_domain.random_pool, - // // temperature * 2, - // // 10.0, - // // 1); - // const auto injector = arch::UniformInjector( - // energy_dist, - // { 1, 2 }); - // const real_t ndens = 0.01; - // arch::InjectUniform(params, - // local_domain, - // injector, - // ndens); + const auto energy_dist = arch::PowerlawDist(local_domain.mesh.metric, + local_domain.random_pool, + 0.1, 100.0, -3.0); + const auto injector = arch::UniformInjector( + energy_dist, + { 1, 2 }); + const real_t ndens = 0.1; + arch::InjectUniform(params, + local_domain, + injector, + ndens); } } From 531d4c1c8fd0ab356e8eae111bc67161dcd1282a Mon Sep 17 00:00:00 2001 From: hayk Date: Fri, 30 Aug 2024 03:21:41 -0400 Subject: [PATCH 025/773] updated checkpoint --- src/checkpoint/reader.cpp | 42 ++++++++++++++++++++++++++++----------- src/checkpoint/reader.h | 1 - src/checkpoint/writer.cpp | 30 ++++++++++++++-------------- src/checkpoint/writer.h | 1 - 4 files changed, 45 insertions(+), 29 deletions(-) diff --git a/src/checkpoint/reader.cpp b/src/checkpoint/reader.cpp index bef78f85b..9f410b220 100644 --- a/src/checkpoint/reader.cpp +++ b/src/checkpoint/reader.cpp @@ -9,7 +9,10 @@ #include #include -#include + +#if defined(MPI_ENABLED) + #include +#endif #include #include @@ -25,9 +28,11 @@ namespace checkpoint { ndfield_t& array) { logger::Checkpoint(fmt::format("Reading field: %s", field.c_str()), HERE); auto field_var = io.InquireVariable(field); - field_var.SetStepSelection(adios2::Box({ 0 }, { 1 })); field_var.SetSelection(range); - reader.Get(field_var, array.data()); + + auto array_h = Kokkos::create_mirror_view(array); + reader.Get(field_var, array_h.data()); + Kokkos::deep_copy(array, array_h); } auto ReadParticleCount(adios2::IO& io, @@ -43,17 +48,27 @@ namespace checkpoint { npart_var.Shape()[0] != ndomains or npart_var.Shape().size() != 1, "npart_var.Shape()[0] != ndomains or npart_var.Shape().size() != 1", HERE); - npart_var.SetStepSelection(adios2::Box({ 0 }, { 1 })); - npart_var.SetSelection( - adios2::Box({ 0 }, { npart_var.Shape()[0] })); - std::vector nparts(ndomains); - reader.Get(npart_var, nparts.data(), adios2::Mode::Sync); - const auto loc_npart = nparts[local_dom]; + npart_var.SetSelection(adios2::Box({ local_dom }, { 1 })); + std::size_t npart; + reader.Get(npart_var, &npart, adios2::Mode::Sync); + const auto loc_npart = npart; +#if !defined(MPI_ENABLED) + std::size_t offset_npart = 0; +#else + std::vector glob_nparts(ndomains); + MPI_Allgather(&npart, + 1, + mpi::get_type(), + glob_nparts.data(), + 1, + mpi::get_type(), + MPI_COMM_WORLD); std::size_t offset_npart = 0; for (auto d { 0u }; d < local_dom; ++d) { - offset_npart += nparts[d]; + offset_npart += glob_nparts[d]; } +#endif return { loc_npart, offset_npart }; } @@ -70,9 +85,12 @@ namespace checkpoint { HERE); auto var = io.InquireVariable( fmt::format("s%d_%s", s + 1, quantity.c_str())); - var.SetStepSelection(adios2::Box({ 0 }, { 1 })); var.SetSelection(adios2::Box({ offset }, { count })); - reader.Get(var, array.data()); + const auto slice = std::pair { 0, count }; + auto array_h = Kokkos::create_mirror_view(array); + reader.Get(var, Kokkos::subview(array_h, slice).data()); + Kokkos::deep_copy(Kokkos::subview(array, slice), + Kokkos::subview(array_h, slice)); } template void ReadFields(adios2::IO&, diff --git a/src/checkpoint/reader.h b/src/checkpoint/reader.h index b2358647b..f43493026 100644 --- a/src/checkpoint/reader.h +++ b/src/checkpoint/reader.h @@ -16,7 +16,6 @@ #include "arch/kokkos_aliases.h" #include -#include #include #include diff --git a/src/checkpoint/writer.cpp b/src/checkpoint/writer.cpp index 9e73905ae..0edc6cb06 100644 --- a/src/checkpoint/writer.cpp +++ b/src/checkpoint/writer.cpp @@ -11,7 +11,6 @@ #include #include -#include #include #include @@ -41,11 +40,12 @@ namespace checkpoint { m_io.DefineVariable("Time"); m_io.DefineAttribute("NGhosts", ntt::N_GHOSTS); - const std::filesystem::path save_path { "checkpoints" }; - if (!std::filesystem::exists(save_path)) { - std::filesystem::create_directory(save_path); - } - p_adios->EnterComputationBlock(); + CallOnce([]() { + const std::filesystem::path save_path { "checkpoints" }; + if (!std::filesystem::exists(save_path)) { + std::filesystem::create_directory(save_path); + } + }); } void Writer::defineFieldVariables(const ntt::SimEngine& S, @@ -169,7 +169,6 @@ namespace checkpoint { m_writing_mode = false; m_writer.EndStep(); m_writer.Close(); - p_adios->EnterComputationBlock(); // optionally remove the oldest checkpoint CallOnce([&]() { @@ -217,9 +216,7 @@ namespace checkpoint { const ndfield_t& field) { auto field_h = Kokkos::create_mirror_view(field); Kokkos::deep_copy(field_h, field); - m_writer.Put(m_io.InquireVariable(fieldname), - field_h.data(), - adios2::Mode::Sync); + m_writer.Put(m_io.InquireVariable(fieldname), field_h.data()); } template @@ -228,13 +225,16 @@ namespace checkpoint { std::size_t loc_offset, std::size_t loc_size, const array_t& data) { - auto data_h = Kokkos::create_mirror_view(data); - Kokkos::deep_copy(data_h, data); - auto slice = range_tuple_t(0, loc_size); - auto var = m_io.InquireVariable(quantity); + const auto slice = range_tuple_t(0, loc_size); + auto var = m_io.InquireVariable(quantity); + var.SetShape({ glob_total }); var.SetSelection(adios2::Box({ loc_offset }, { loc_size })); - m_writer.Put(var, Kokkos::subview(data_h, slice).data()); + + auto data_h = Kokkos::create_mirror_view(data); + Kokkos::deep_copy(data_h, data); + auto data_sub = Kokkos::subview(data_h, slice); + m_writer.Put(var, data_sub.data()); } template void Writer::savePerDomainVariable(const std::string&, diff --git a/src/checkpoint/writer.h b/src/checkpoint/writer.h index a23ab556a..34b5f043f 100644 --- a/src/checkpoint/writer.h +++ b/src/checkpoint/writer.h @@ -20,7 +20,6 @@ #include "framework/parameters.h" #include -#include #include #include From efff7893a74dd7fddba874320c34589d67f65b68 Mon Sep 17 00:00:00 2001 From: hayk Date: Sun, 1 Sep 2024 18:33:14 -0400 Subject: [PATCH 026/773] bugfix (i think it works) --- src/checkpoint/reader.cpp | 6 +++--- src/framework/domain/checkpoint.cpp | 19 +++++++++++++------ 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/src/checkpoint/reader.cpp b/src/checkpoint/reader.cpp index 9f410b220..6820a7787 100644 --- a/src/checkpoint/reader.cpp +++ b/src/checkpoint/reader.cpp @@ -31,7 +31,7 @@ namespace checkpoint { field_var.SetSelection(range); auto array_h = Kokkos::create_mirror_view(array); - reader.Get(field_var, array_h.data()); + reader.Get(field_var, array_h.data(), adios2::Mode::Sync); Kokkos::deep_copy(array, array_h); } @@ -57,7 +57,7 @@ namespace checkpoint { std::size_t offset_npart = 0; #else std::vector glob_nparts(ndomains); - MPI_Allgather(&npart, + MPI_Allgather(&loc_npart, 1, mpi::get_type(), glob_nparts.data(), @@ -88,7 +88,7 @@ namespace checkpoint { var.SetSelection(adios2::Box({ offset }, { count })); const auto slice = std::pair { 0, count }; auto array_h = Kokkos::create_mirror_view(array); - reader.Get(var, Kokkos::subview(array_h, slice).data()); + reader.Get(var, Kokkos::subview(array_h, slice).data(), adios2::Mode::Sync); Kokkos::deep_copy(Kokkos::subview(array, slice), Kokkos::subview(array_h, slice)); } diff --git a/src/framework/domain/checkpoint.cpp b/src/framework/domain/checkpoint.cpp index 6695e3965..beeb8504e 100644 --- a/src/framework/domain/checkpoint.cpp +++ b/src/framework/domain/checkpoint.cpp @@ -32,9 +32,15 @@ namespace ntt { "local_domain is a placeholder", HERE); - auto glob_shape_with_ghosts = mesh().n_all(); - auto off_ncells_with_ghosts = local_domain->offset_ncells(); - auto loc_shape_with_ghosts = local_domain->mesh.n_all(); + std::vector glob_shape_with_ghosts, off_ncells_with_ghosts; + for (auto d { 0u }; d < M::Dim; ++d) { + off_ncells_with_ghosts.push_back( + local_domain->offset_ncells()[d] + + 2 * N_GHOSTS * local_domain->offset_ndomains()[d]); + glob_shape_with_ghosts.push_back( + mesh().n_active()[d] + 2 * N_GHOSTS * ndomains_per_dim()[d]); + } + auto loc_shape_with_ghosts = local_domain->mesh.n_all(); std::vector nplds; for (auto s { 0u }; s < local_domain->species.size(); ++s) { @@ -280,7 +286,8 @@ namespace ntt { auto& domain = g_subdomains[ldidx]; adios2::Box range; for (auto d { 0u }; d < M::Dim; ++d) { - range.first.push_back(domain.offset_ncells()[d]); + range.first.push_back(domain.offset_ncells()[d] + + 2 * N_GHOSTS * domain.offset_ndomains()[d]); range.second.push_back(domain.mesh.n_all()[d]); } range.first.push_back(0); @@ -294,7 +301,8 @@ namespace ntt { domain.fields.em0); adios2::Box range3; for (auto d { 0u }; d < M::Dim; ++d) { - range3.first.push_back(domain.offset_ncells()[d]); + range3.first.push_back(domain.offset_ncells()[d] + + 2 * N_GHOSTS * domain.offset_ndomains()[d]); range3.second.push_back(domain.mesh.n_all()[d]); } range3.first.push_back(0); @@ -308,7 +316,6 @@ namespace ntt { for (auto s { 0u }; s < (unsigned short)(domain.species.size()); ++s) { const auto [loc_npart, offset_npart] = checkpoint::ReadParticleCount(io, reader, s, ldidx, ndomains()); - raise::ErrorIf(loc_npart > domain.species[s].maxnpart(), "loc_npart > domain.species[s].maxnpart()", HERE); From adfaf8409cd6a289b3635711794c8dd710fd71dd Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Tue, 3 Sep 2024 23:11:14 -0400 Subject: [PATCH 027/773] Fixing a bug in checkpoint writing (prtls). --- src/framework/domain/checkpoint.cpp | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/framework/domain/checkpoint.cpp b/src/framework/domain/checkpoint.cpp index beeb8504e..3d309c090 100644 --- a/src/framework/domain/checkpoint.cpp +++ b/src/framework/domain/checkpoint.cpp @@ -131,12 +131,6 @@ namespace ntt { offset, npart, local_domain->species[s].i1); - g_checkpoint_writer.saveParticleQuantity( - fmt::format("s%d_i1", s + 1), - glob_tot, - offset, - npart, - local_domain->species[s].i1); g_checkpoint_writer.saveParticleQuantity( fmt::format("s%d_dx1", s + 1), glob_tot, @@ -156,7 +150,7 @@ namespace ntt { npart, local_domain->species[s].dx1_prev); } - if constexpr (M::Dim == Dim::_1D or M::Dim == Dim::_2D) { + if constexpr (M::Dim == Dim::_2D or M::Dim == Dim::_3D) { g_checkpoint_writer.saveParticleQuantity( fmt::format("s%d_i2", s + 1), glob_tot, From 51323608d56e7a2cb594d4d921c40f03309e63ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20B=C3=B6ss?= Date: Thu, 5 Sep 2024 15:34:22 -0500 Subject: [PATCH 028/773] fix misunderstanding in setup --- setups/srpic/shock/pgen.hpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/setups/srpic/shock/pgen.hpp b/setups/srpic/shock/pgen.hpp index 4a9cc3f09..c3771cde2 100644 --- a/setups/srpic/shock/pgen.hpp +++ b/setups/srpic/shock/pgen.hpp @@ -17,8 +17,8 @@ namespace user { template struct InitFields { - InitFields(real_t bmag, real_t btheta, real_t bphi, real_t bbeta) : - Bmag { bmag }, Btheta { btheta }, Bphi { bphi }, Bbeta { bbeta } {} + InitFields(real_t bmag, real_t btheta, real_t bphi, real_t drift_ux) : + Bmag { bmag }, Btheta { btheta }, Bphi { bphi }, Vx { drift_ux } {} // alternative: initialize magnetisation from simulation parameters as in Tristan? // Bmag = math::sqrt(ppc0 * 0.5 * c * c * me * sigma); @@ -44,15 +44,15 @@ namespace user { } Inline auto ex2(const coord_t &x_Ph) const -> real_t { - return -Bbeta * Bmag * math::sin(Btheta / 180.0 * Kokkos::numbers::pi) * math::cos(Bphi / 180.0 * Kokkos::numbers::pi); + return -Vx * Bmag * math::sin(Btheta / 180.0 * Kokkos::numbers::pi) * math::cos(Bphi / 180.0 * Kokkos::numbers::pi); } Inline auto ex3(const coord_t &x_Ph) const -> real_t { - return -Bbeta * Bmag * math::sin(Btheta / 180.0 * Kokkos::numbers::pi) * math::sin(Bphi / 180.0 * Kokkos::numbers::pi); + return -Vx * Bmag * math::sin(Btheta / 180.0 * Kokkos::numbers::pi) * math::sin(Bphi / 180.0 * Kokkos::numbers::pi); } private: - const real_t Btheta, Bphi, Bbeta, Bmag; + const real_t Btheta, Bphi, Vx, Bmag; }; template @@ -71,7 +71,7 @@ namespace user { const real_t drift_ux, temperature; - const real_t Btheta, Bphi, Bbeta, Bmag; + const real_t Btheta, Bphi, Bmag; InitFields init_flds; inline PGen(const SimulationParams &p, const Metadomain &m) @@ -81,8 +81,7 @@ namespace user { , Bmag { p.template get("setup.Bmag", 0.0) } , Btheta { p.template get("setup.Btheta", 0.0) } , Bphi { p.template get("setup.Bphi", 0.0) } - , Bbeta { p.template get("setup.Bbeta", 0.0) } - , init_flds { Bmag, Btheta, Bphi, Bbeta } {} + , init_flds { Bmag, Btheta, Bphi, drift_ux } {} inline PGen() {} From cdfd2859c1c5bf163478ac2f48a5ca90916611b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20B=C3=B6ss?= Date: Wed, 11 Sep 2024 13:26:00 -0500 Subject: [PATCH 029/773] fix sign error --- setups/srpic/shock/pgen.hpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/setups/srpic/shock/pgen.hpp b/setups/srpic/shock/pgen.hpp index c3771cde2..1194e7fed 100644 --- a/setups/srpic/shock/pgen.hpp +++ b/setups/srpic/shock/pgen.hpp @@ -20,9 +20,6 @@ namespace user { InitFields(real_t bmag, real_t btheta, real_t bphi, real_t drift_ux) : Bmag { bmag }, Btheta { btheta }, Bphi { bphi }, Vx { drift_ux } {} - // alternative: initialize magnetisation from simulation parameters as in Tristan? - // Bmag = math::sqrt(ppc0 * 0.5 * c * c * me * sigma); - // magnetic field components Inline auto bx1(const coord_t &x_Ph) const -> real_t { @@ -44,7 +41,7 @@ namespace user { } Inline auto ex2(const coord_t &x_Ph) const -> real_t { - return -Vx * Bmag * math::sin(Btheta / 180.0 * Kokkos::numbers::pi) * math::cos(Bphi / 180.0 * Kokkos::numbers::pi); + return Vx * Bmag * math::sin(Btheta / 180.0 * Kokkos::numbers::pi) * math::cos(Bphi / 180.0 * Kokkos::numbers::pi); } Inline auto ex3(const coord_t &x_Ph) const -> real_t { From e24078cadd4096d57e75c1dd14c9e92cc96f60aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20B=C3=B6ss?= Date: Wed, 11 Sep 2024 14:07:43 -0500 Subject: [PATCH 030/773] fix sign error --- setups/srpic/shock/pgen.hpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/setups/srpic/shock/pgen.hpp b/setups/srpic/shock/pgen.hpp index c3771cde2..1194e7fed 100644 --- a/setups/srpic/shock/pgen.hpp +++ b/setups/srpic/shock/pgen.hpp @@ -20,9 +20,6 @@ namespace user { InitFields(real_t bmag, real_t btheta, real_t bphi, real_t drift_ux) : Bmag { bmag }, Btheta { btheta }, Bphi { bphi }, Vx { drift_ux } {} - // alternative: initialize magnetisation from simulation parameters as in Tristan? - // Bmag = math::sqrt(ppc0 * 0.5 * c * c * me * sigma); - // magnetic field components Inline auto bx1(const coord_t &x_Ph) const -> real_t { @@ -44,7 +41,7 @@ namespace user { } Inline auto ex2(const coord_t &x_Ph) const -> real_t { - return -Vx * Bmag * math::sin(Btheta / 180.0 * Kokkos::numbers::pi) * math::cos(Bphi / 180.0 * Kokkos::numbers::pi); + return Vx * Bmag * math::sin(Btheta / 180.0 * Kokkos::numbers::pi) * math::cos(Bphi / 180.0 * Kokkos::numbers::pi); } Inline auto ex3(const coord_t &x_Ph) const -> real_t { From 0fc366c76db99099c6eb98ee903abc47e0cf711c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20B=C3=B6ss?= Date: Wed, 11 Sep 2024 14:13:54 -0500 Subject: [PATCH 031/773] Added comment for `InitFields` --- setups/srpic/shock/pgen.hpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/setups/srpic/shock/pgen.hpp b/setups/srpic/shock/pgen.hpp index 1194e7fed..715c222df 100644 --- a/setups/srpic/shock/pgen.hpp +++ b/setups/srpic/shock/pgen.hpp @@ -16,7 +16,16 @@ namespace user { template struct InitFields - { + { + /* + Sets up magnetic and electric field components for the simulation. + Must satisfy E = -v x B for Lorentz Force to be zero. + + @param bmag: magnetic field scaling + @param btheta: magnetic field polar angle + @param bphi: magnetic field azimuthal angle + @param drift_ux: drift velocity in the x direction + */ InitFields(real_t bmag, real_t btheta, real_t bphi, real_t drift_ux) : Bmag { bmag }, Btheta { btheta }, Bphi { bphi }, Vx { drift_ux } {} From 2a258c1231ac205393886c5780694dee7734dba5 Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Fri, 13 Sep 2024 05:19:03 -0400 Subject: [PATCH 032/773] Optimizing checkpoint writing (flds/prtls). --- src/checkpoint/writer.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/checkpoint/writer.cpp b/src/checkpoint/writer.cpp index 0edc6cb06..85d9485e6 100644 --- a/src/checkpoint/writer.cpp +++ b/src/checkpoint/writer.cpp @@ -59,16 +59,16 @@ namespace checkpoint { lc6.push_back(0); ls6.push_back(6); - m_io.DefineVariable("em", gs6, lc6, ls6, adios2::ConstantDims); + m_io.DefineVariable("em", gs6, lc6, ls6); if (S == ntt::SimEngine::GRPIC) { - m_io.DefineVariable("em0", gs6, lc6, ls6, adios2::ConstantDims); + m_io.DefineVariable("em0", gs6, lc6, ls6); auto gs3 = std::vector(glob_shape.begin(), glob_shape.end()); auto lc3 = std::vector(loc_corner.begin(), loc_corner.end()); auto ls3 = std::vector(loc_shape.begin(), loc_shape.end()); gs3.push_back(3); lc3.push_back(0); ls3.push_back(3); - m_io.DefineVariable("cur0", gs3, lc3, ls3, adios2::ConstantDims); + m_io.DefineVariable("cur0", gs3, lc3, ls3); } } @@ -216,7 +216,7 @@ namespace checkpoint { const ndfield_t& field) { auto field_h = Kokkos::create_mirror_view(field); Kokkos::deep_copy(field_h, field); - m_writer.Put(m_io.InquireVariable(fieldname), field_h.data()); + m_writer.Put(m_io.InquireVariable(fieldname), field_h.data(), adios2::Mode::Sync); } template @@ -234,7 +234,7 @@ namespace checkpoint { auto data_h = Kokkos::create_mirror_view(data); Kokkos::deep_copy(data_h, data); auto data_sub = Kokkos::subview(data_h, slice); - m_writer.Put(var, data_sub.data()); + m_writer.Put(var, data_sub.data(), adios2::Mode::Sync); } template void Writer::savePerDomainVariable(const std::string&, From c3b1018069bba7ec582b1d612d3d4c8b9b48ed5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20B=C3=B6ss?= Date: Mon, 23 Sep 2024 11:25:57 -0500 Subject: [PATCH 033/773] fix signs (again) --- setups/srpic/shock/pgen.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setups/srpic/shock/pgen.hpp b/setups/srpic/shock/pgen.hpp index 715c222df..1fdd18faa 100644 --- a/setups/srpic/shock/pgen.hpp +++ b/setups/srpic/shock/pgen.hpp @@ -50,11 +50,11 @@ namespace user { } Inline auto ex2(const coord_t &x_Ph) const -> real_t { - return Vx * Bmag * math::sin(Btheta / 180.0 * Kokkos::numbers::pi) * math::cos(Bphi / 180.0 * Kokkos::numbers::pi); + return -Vx * Bmag * math::sin(Btheta / 180.0 * Kokkos::numbers::pi) * math::cos(Bphi / 180.0 * Kokkos::numbers::pi); } Inline auto ex3(const coord_t &x_Ph) const -> real_t { - return -Vx * Bmag * math::sin(Btheta / 180.0 * Kokkos::numbers::pi) * math::sin(Bphi / 180.0 * Kokkos::numbers::pi); + return Vx * Bmag * math::sin(Btheta / 180.0 * Kokkos::numbers::pi) * math::sin(Bphi / 180.0 * Kokkos::numbers::pi); } private: From d666d1ea0df93e38d048257a9fc48e7a24407504 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20B=C3=B6ss?= Date: Mon, 23 Sep 2024 11:37:27 -0500 Subject: [PATCH 034/773] removed redundant parameter and added comments --- setups/srpic/shock/shock.toml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/setups/srpic/shock/shock.toml b/setups/srpic/shock/shock.toml index 90571631e..e475ae097 100644 --- a/setups/srpic/shock/shock.toml +++ b/setups/srpic/shock/shock.toml @@ -42,10 +42,9 @@ [setup] drift_ux = 0.1 temperature = 1e-3 - Bmag = 0.0 - Btheta = 0.0 - Bphi = 0.0 - Bbeta = 0.0 + Bmag = 0.0 # set to 1.0 if magnetized shock is required + Btheta = 0.0 # magnetic field polar angle + Bphi = 0.0 # magnetic field azimuthal angle [output] interval_time = 0.1 From 1df0cce978d8da8e00a1f0c7d3154a8cb091585a Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova Date: Tue, 24 Sep 2024 12:20:06 -0400 Subject: [PATCH 035/773] compilable example for grpic --- setups/grpic/pgen_grpic_example.hpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/setups/grpic/pgen_grpic_example.hpp b/setups/grpic/pgen_grpic_example.hpp index f553ae849..3374a12d7 100644 --- a/setups/grpic/pgen_grpic_example.hpp +++ b/setups/grpic/pgen_grpic_example.hpp @@ -12,7 +12,7 @@ namespace user { using namespace ntt; template - struct PGen : public ProblemGenerator { + struct PGen : public arch::ProblemGenerator { // compatibility traits for the problem generator static constexpr auto engines { traits::compatible_with::value }; static constexpr auto metrics { @@ -21,13 +21,12 @@ namespace user { static constexpr auto dimensions { traits::compatible_with::value }; // for easy access to variables in the child class - using ProblemGenerator::D; - using ProblemGenerator::C; - using ProblemGenerator::params; - using ProblemGenerator::domain; + using arch::ProblemGenerator::D; + using arch::ProblemGenerator::C; + using arch::ProblemGenerator::params; inline PGen(SimulationParams& p, const Metadomain&) : - ProblemGenerator(p) {} + arch::ProblemGenerator(p) {} inline PGen() {} }; From 0c81d9b3ddebb3c64afdf13782d565d28fbbda25 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Tue, 24 Sep 2024 12:48:33 -0400 Subject: [PATCH 036/773] starting a test pgen --- setups/grpic/wald/pgen.hpp | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 setups/grpic/wald/pgen.hpp diff --git a/setups/grpic/wald/pgen.hpp b/setups/grpic/wald/pgen.hpp new file mode 100644 index 000000000..3374a12d7 --- /dev/null +++ b/setups/grpic/wald/pgen.hpp @@ -0,0 +1,36 @@ +#ifndef PROBLEM_GENERATOR_H +#define PROBLEM_GENERATOR_H + +#include "enums.h" +#include "global.h" + +#include "arch/traits.h" + +#include "archetypes/problem_generator.h" + +namespace user { + using namespace ntt; + + template + struct PGen : public arch::ProblemGenerator { + // compatibility traits for the problem generator + static constexpr auto engines { traits::compatible_with::value }; + static constexpr auto metrics { + traits::compatible_with::value + }; + static constexpr auto dimensions { traits::compatible_with::value }; + + // for easy access to variables in the child class + using arch::ProblemGenerator::D; + using arch::ProblemGenerator::C; + using arch::ProblemGenerator::params; + + inline PGen(SimulationParams& p, const Metadomain&) : + arch::ProblemGenerator(p) {} + + inline PGen() {} + }; + +} // namespace user + +#endif From fc126af8cf4dca5419b346d31bbdb58de5085d0f Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Tue, 24 Sep 2024 13:46:21 -0400 Subject: [PATCH 037/773] engines/grpic: added relevant libraries --- src/engines/grpic.hpp | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index 148c1c5c5..5ed9fe57d 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -13,13 +13,37 @@ #define ENGINES_GRPIC_GRPIC_H #include "enums.h" +#include "global.h" +#include "arch/kokkos_aliases.h" +#include "arch/traits.h" +#include "utils/log.h" +#include "utils/numeric.h" #include "utils/timer.h" +#include "archetypes/particle_injector.h" #include "framework/domain/domain.h" +#include "framework/parameters.h" #include "engines/engine.hpp" +#include "kernels/ampere_gr.hpp" +#include "kernels/aux_fields_gr.hpp" +#include "kernels/currents_deposit.hpp" +#include "kernels/digital_filter.hpp" +#include "kernels/faraday_gr.hpp" +#include "kernels/fields_bcs.hpp" +#include "kernels/particle_moments.hpp" +#include "kernels/particle_pusher_gr.hpp" + +#include "pgen.hpp" + +#include +#include + +#include +#include + namespace ntt { template @@ -27,6 +51,7 @@ namespace ntt { using Engine::m_params; using Engine::m_metadomain; + public: static constexpr auto S { SimEngine::SRPIC }; From c7fc87a85bc45d010dc1dbe9a00d5dd9310bc3e2 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Tue, 24 Sep 2024 13:58:39 -0400 Subject: [PATCH 038/773] kernels/ampere_gr: fixed dublicate ErrorIF --- src/kernels/ampere_gr.hpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/kernels/ampere_gr.hpp b/src/kernels/ampere_gr.hpp index 5af0fa4ef..045eb1729 100644 --- a/src/kernels/ampere_gr.hpp +++ b/src/kernels/ampere_gr.hpp @@ -57,9 +57,6 @@ namespace kernel::gr { , coeff { coeff } { if constexpr ((D == Dim::_2D) || (D == Dim::_3D)) { raise::ErrorIf(boundaries.size() < 2, "boundaries defined incorrectly", HERE); - raise::ErrorIf(boundaries[1].size() < 2, - "boundaries defined incorrectly", - HERE); is_axis_i2min = (boundaries[1].first == FldsBC::AXIS); is_axis_i2max = (boundaries[1].second == FldsBC::AXIS); } From d106f45dc6a4b18a40df73a66fc6efe726ad18a9 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Tue, 24 Sep 2024 14:21:40 -0400 Subject: [PATCH 039/773] engines/grpic: minor syntax adustments to match engines/srpic --- src/engines/grpic.hpp | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index 5ed9fe57d..687074a9e 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -4,7 +4,7 @@ * @implements * - ntt::GRPICEngine<> : ntt::Engine<> * @cpp: - * - srpic.cpp + * - grpic.cpp * @namespaces: * - ntt:: */ @@ -48,19 +48,32 @@ namespace ntt { template class GRPICEngine : public Engine { - using Engine::m_params; - using Engine::m_metadomain; - + using base_t = Engine; + using pgen_t = user::PGen; + using domain_t = Domain; + // constexprs + using base_t::pgen_is_ok; + // contents + using base_t::m_metadomain; + using base_t::m_params; + using base_t::m_pgen; + // methods + using base_t::init; + // variables + using base_t::dt; + using base_t::max_steps; + using base_t::runtime; + using base_t::step; + using base_t::time; public: - static constexpr auto S { SimEngine::SRPIC }; + static constexpr auto S { SimEngine::GRPIC }; - GRPICEngine(SimulationParams& params) - : Engine { params } {} + GRPICEngine(SimulationParams& params) : base_t { params } {} ~GRPICEngine() = default; - void step_forward(timer::Timers&, Domain&) override {} + void step_forward(timer::Timers& timers, domain_t& dom) override {} }; } // namespace ntt From 70fa507a00ca1f7fb488fcb9ebef46452fe9cfc8 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Tue, 24 Sep 2024 17:06:01 -0400 Subject: [PATCH 040/773] engines/grpic: added initialisation of fields and boundary conditions --- src/engines/grpic.hpp | 184 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 182 insertions(+), 2 deletions(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index 687074a9e..67091f9fb 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -73,9 +73,189 @@ namespace ntt { ~GRPICEngine() = default; - void step_forward(timer::Timers& timers, domain_t& dom) override {} - }; + void step_forward(timer::Timers& timers, domain_t& dom) override { + const auto fieldsolver_enabled = m_params.template get( + "algorithms.toggles.fieldsolver"); + const auto deposit_enabled = m_params.template get( + "algorithms.toggles.deposit"); + const auto sort_interval = m_params.template get( + "particles.sort_interval"); + + if (step == 0) { + // communicate fields and apply BCs on the first timestep + /** + * Initially: em0::B -- + * em0::D -- + * em::B at -1/2 + * em::D at -1/2 + * + * cur0::J -- + * cur::J -- + * + * aux::E -- + * aux::H -- + * + * x_prtl at -1/2 + * u_prtl at -1/2 + */ + + /** + * em0::D, em::D, em0::B, em::B <- boundary conditions + */ + m_metadomain.CommunicateFields(dom, Comm::B | Comm::B0 | Comm::D | Comm::D0); + FieldBoundaries(dom, BC::B | BC::D); + + } + } + + void FieldBoundaries(domain_t& domain, BCTags tags) { + for (auto& direction : dir::Directions::orth) { + if (m_metadomain.mesh().flds_bc_in(direction) == FldsBC::ABSORB) { + AbsorbFieldsIn(direction, domain, tags); + } else if (m_metadomain.mesh().flds_bc_in(direction) == FldsBC::AXIS) { + if (domain.mesh.flds_bc_in(direction) == FldsBC::AXIS) { + AxisFieldsIn(direction, domain, tags); + } + } else if (m_metadomain.mesh().flds_bc_in(direction) == FldsBC::CUSTOM) { + if (domain.mesh.flds_bc_in(direction) == FldsBC::CUSTOM) { + CustomFieldsIn(direction, domain, tags); + } + } else if (m_metadomain.mesh().flds_bc_in(direction) == FldsBC::HORIZON) { + raise::Error("HORIZON BCs only applicable for GR", HERE); + } + } // loop over directions + } + void AbsorbFieldsIn(dir::direction_t direction, + domain_t& domain, + BCTags tags) { + /** + * absorbing boundaries + */ + const auto ds = m_params.template get( + "grid.boundaries.absorb.ds"); + const auto dim = direction.get_dim(); + real_t xg_min, xg_max, xg_edge; + auto sign = direction.get_sign(); + if (sign > 0) { // + direction + xg_max = m_metadomain.mesh().extent(dim).second; + xg_min = xg_max - ds; + xg_edge = xg_max; + } else { // - direction + xg_min = m_metadomain.mesh().extent(dim).first; + xg_max = xg_min + ds; + xg_edge = xg_min; + } + boundaries_t box; + boundaries_t incl_ghosts; + for (unsigned short d { 0 }; d < M::Dim; ++d) { + if (d == static_cast(dim)) { + box.push_back({ xg_min, xg_max }); + if (sign > 0) { + incl_ghosts.push_back({ false, true }); + } else { + incl_ghosts.push_back({ true, false }); + } + } else { + box.push_back(Range::All); + incl_ghosts.push_back({ true, true }); + } + } + if (not domain.mesh.Intersects(box)) { + return; + } + const auto intersect_range = domain.mesh.ExtentToRange(box, incl_ghosts); + tuple_t range_min { 0 }; + tuple_t range_max { 0 }; + + for (unsigned short d { 0 }; d < M::Dim; ++d) { + range_min[d] = intersect_range[d].first; + range_max[d] = intersect_range[d].second; + } + if (dim == in::x1) { + Kokkos::parallel_for( + "AbsorbFields", + CreateRangePolicy(range_min, range_max), + kernel::AbsorbBoundaries_kernel(domain.fields.em, + domain.mesh.metric, + xg_edge, + ds, + tags)); + } else if (dim == in::x2) { + if constexpr (M::Dim == Dim::_2D or M::Dim == Dim::_3D) { + Kokkos::parallel_for( + "AbsorbFields", + CreateRangePolicy(range_min, range_max), + kernel::AbsorbBoundaries_kernel(domain.fields.em, + domain.mesh.metric, + xg_edge, + ds, + tags)); + } else { + raise::Error("Invalid dimension", HERE); + } + } else if (dim == in::x3) { + if constexpr (M::Dim == Dim::_3D) { + Kokkos::parallel_for( + "AbsorbFields", + CreateRangePolicy(range_min, range_max), + kernel::AbsorbBoundaries_kernel(domain.fields.em, + domain.mesh.metric, + xg_edge, + ds, + tags)); + } else { + raise::Error("Invalid dimension", HERE); + } + } + } + + void AxisFieldsIn(dir::direction_t direction, + domain_t& domain, + BCTags tags) { + /** + * axis boundaries + */ + raise::ErrorIf(M::CoordType == Coord::Cart, + "Invalid coordinate type for axis BCs", + HERE); + raise::ErrorIf(direction.get_dim() != in::x2, + "Invalid axis direction, should be x2", + HERE); + const auto i2_min = domain.mesh.i_min(in::x2); + const auto i2_max = domain.mesh.i_max(in::x2); + if (direction.get_sign() < 0) { + Kokkos::parallel_for( + "AxisBCFields", + domain.mesh.n_all(in::x1), + kernel::AxisBoundaries_kernel(domain.fields.em, i2_min, tags)); + } else { + Kokkos::parallel_for( + "AxisBCFields", + domain.mesh.n_all(in::x1), + kernel::AxisBoundaries_kernel(domain.fields.em, i2_max, tags)); + } + } + + void CustomFieldsIn(dir::direction_t direction, + domain_t& domain, + BCTags tags) { + (void)direction; + (void)domain; + (void)tags; + raise::Error("Custom boundaries not implemented", HERE); + // if constexpr ( + // traits::has_member::value) { + // const auto [box, custom_fields] = m_pgen.CustomFields(time); + // if (domain.mesh.Intersects(box)) { + // } + // + // } else { + // raise::Error("Custom boundaries not implemented", HERE); + // } + } + + }; } // namespace ntt #endif // ENGINES_GRPIC_GRPIC_H From 53e68610719c257928f9c7d39d1fabe258e54d9c Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Wed, 25 Sep 2024 12:55:12 -0400 Subject: [PATCH 041/773] engines/grpic: added cope of em field into em0 --- src/engines/grpic.hpp | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index 67091f9fb..a84a0ed5f 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -105,6 +105,13 @@ namespace ntt { m_metadomain.CommunicateFields(dom, Comm::B | Comm::B0 | Comm::D | Comm::D0); FieldBoundaries(dom, BC::B | BC::D); + /** + * em0::B <- em::B + * em0::D <- em::D + * + * Now: em0::B & em0::D at -1/2 + */ + CopyFields(dom); } } @@ -255,6 +262,22 @@ namespace ntt { // } } + /** + * @brief Swaps em and em0 fields, cur and cur0 currents. + */ + // void SwapFields() { + // auto& mblock = this->meshblock; + // std::swap(mblock.em, mblock.em0); + // std::swap(mblock.cur, mblock.cur0); + // } + + /** + * @brief Copies em fields into em0 + */ + void CopyFields(domain_t& domain) { + Kokkos::deep_copy(domain.fields.em0, domain.fields.em); + } + }; } // namespace ntt From 011e02416f1650268bf5c8cc712d9761f192a5a8 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Wed, 25 Sep 2024 15:00:21 -0400 Subject: [PATCH 042/773] engines/grpic: added computation of aux fields --- src/engines/grpic.hpp | 82 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 81 insertions(+), 1 deletion(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index a84a0ed5f..afc452948 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -46,6 +46,15 @@ namespace ntt { + enum class gr_getE { + D0_B, + D_B0 + }; + enum class gr_getH { + D_B0, + D0_B0 + }; + template class GRPICEngine : public Engine { using base_t = Engine; @@ -112,6 +121,15 @@ namespace ntt { * Now: em0::B & em0::D at -1/2 */ CopyFields(dom); + + /** + * aux::E <- alpha * em::D + beta x em0::B + * aux::H <- alpha * em::B0 - beta x em::D + * + * Now: aux::E & aux::H at -1/2 + */ + ComputeAuxE(dom, gr_getE::D0_B); + ComputeAuxH(dom, gr_getH::D_B0); } } @@ -274,10 +292,72 @@ namespace ntt { /** * @brief Copies em fields into em0 */ - void CopyFields(domain_t& domain) { + void CopyFields(domain_t& domain) { Kokkos::deep_copy(domain.fields.em0, domain.fields.em); } + void ComputeAuxE(domain_t& domain, const gr_getE& g) { + auto range = range_with_axis_BCs(domain); + if (g == gr_getE::D0_B) { + Kokkos::parallel_for("ComputeAuxE", + range, + kernel::gr::ComputeAuxE_kernel(domain.fields.em0, + domain.fields.em, + domain.fields.em, + domain.mesh.metric)); + } else if (g == gr_getE::D_B0) { + Kokkos::parallel_for("ComputeAuxE", + range, + kernel::gr::ComputeAuxE_kernel(domain.fields.em, + domain.fields.em0, + domain.fields.em, + domain.mesh.metric)); + } else { + raise::Error("Wrong option for `g`", HERE); + } + } + + void ComputeAuxH(domain_t& domain, const gr_getH& g) { + auto range = range_with_axis_BCs(domain); + if (g == gr_getH::D_B0) { + Kokkos::parallel_for("ComputeAuxH", + range, + kernel::gr::ComputeAuxH_kernel(domain.fields.em, + domain.fields.em0, + domain.fields.em, + domain.mesh.metric)); + } else if (g == gr_getH::D0_B0) { + Kokkos::parallel_for("ComputeAuxH", + range, + kernel::gr::ComputeAuxH_kernel(domain.fields.em0, + domain.fields.em0, + domain.fields.em, + domain.mesh.metric)); + } else { + raise::Error("Wrong option for `g`", HERE); + } + } + + auto range_with_axis_BCs(const domain_t& domain) -> range_t { + auto range = domain.mesh.rangeActiveCells(); + if constexpr (M::CoordType != Coord::Cart) { + /** + * @brief taking one extra cell in the x1 and x2 directions if AXIS BCs + */ + if constexpr (M::Dim == Dim::_2D) { + if (domain.mesh.flds_bc_in({ 0, +1 }) == FldsBC::AXIS) { + range = CreateRangePolicy( + { domain.mesh.i_min(in::x1) - 1, domain.mesh.i_min(in::x2) }, + { domain.mesh.i_max(in::x1), domain.mesh.i_max(in::x2) + 1 }); + } + } else if constexpr (M::Dim == Dim::_3D) { + raise::Error("Invalid dimension", HERE); + } + } + return range; + } + + }; } // namespace ntt From cdf69dbae9298eac92c1b362ee4dcccd7befdb00 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Wed, 25 Sep 2024 16:21:32 -0400 Subject: [PATCH 043/773] engines/grpis: fixed "aux" for passing to aux kernels, added Faraday function --- src/engines/grpic.hpp | 52 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 50 insertions(+), 2 deletions(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index afc452948..4bdd56fce 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -54,6 +54,15 @@ namespace ntt { D_B0, D0_B0 }; + enum class gr_faraday { + aux, + main + }; + enum class gr_ampere { + init, + aux, + main + }; template class GRPICEngine : public Engine { @@ -130,9 +139,17 @@ namespace ntt { */ ComputeAuxE(dom, gr_getE::D0_B); ComputeAuxH(dom, gr_getH::D_B0); + + /** + * aux::E, aux::H <- boundary conditions + */ + // ?? aux field boundaries ?? + + Faraday(dom, gr_faraday::aux, HALF); } } +/* algorithm substeps --------------------------------------------------- */ void FieldBoundaries(domain_t& domain, BCTags tags) { for (auto& direction : dir::Directions::orth) { if (m_metadomain.mesh().flds_bc_in(direction) == FldsBC::ABSORB) { @@ -324,14 +341,14 @@ namespace ntt { range, kernel::gr::ComputeAuxH_kernel(domain.fields.em, domain.fields.em0, - domain.fields.em, + domain.fields.aux, domain.mesh.metric)); } else if (g == gr_getH::D0_B0) { Kokkos::parallel_for("ComputeAuxH", range, kernel::gr::ComputeAuxH_kernel(domain.fields.em0, domain.fields.em0, - domain.fields.em, + domain.fields.aux, domain.mesh.metric)); } else { raise::Error("Wrong option for `g`", HERE); @@ -357,6 +374,37 @@ namespace ntt { return range; } + void Faraday(domain_t& domain, const gr_faraday& g, real_t fraction = ONE) { + logger::Checkpoint("Launching Faraday kernel", HERE); + const auto dT = fraction * + m_params.template get( + "algorithms.timestep.correction") * + dt; + if (g == gr_faraday::aux) { + Kokkos::parallel_for("Faraday", + domain.mesh.rangeActiveCells(), + kernel::gr::Faraday_kernel(domain.fields.em0, + domain.fields.em0, + domain.fields.aux, + domain.mesh.metric, + dT, + domain.mesh.i_max(in::x2), + domain.mesh.flds_bc())); + } else if (g == gr_faraday::main) { + Kokkos::parallel_for("Faraday", + domain.mesh.rangeActiveCells(), + kernel::gr::Faraday_kernel(domain.fields.em0, + domain.fields.em0, + domain.fields.aux, + domain.mesh.metric, + dT, + domain.mesh.i_max(in::x2), + domain.mesh.flds_bc())); + + } else { + raise::Error("Wrong option for `g`", HERE); + } + } }; } // namespace ntt From e96b41cd57c034dab9b4d3794bcd22306e101976 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Wed, 25 Sep 2024 16:55:27 -0400 Subject: [PATCH 044/773] minor: added a comment on Faraday step --- src/engines/grpic.hpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index 4bdd56fce..2d670a89c 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -145,6 +145,11 @@ namespace ntt { */ // ?? aux field boundaries ?? + /** + * em0::B <- (em0::B) <- -curl aux::E + * + * Now: em0::B at 0 + */ Faraday(dom, gr_faraday::aux, HALF); } } From ee954128e89b2323f13d874bfae36c96ddf450ec Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Wed, 25 Sep 2024 17:00:41 -0400 Subject: [PATCH 045/773] engines/grpic: bc for B&B0 --- src/engines/grpic.hpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index 2d670a89c..afe22eb47 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -151,6 +151,12 @@ namespace ntt { * Now: em0::B at 0 */ Faraday(dom, gr_faraday::aux, HALF); + + /** + * em0::B, em::B <- boundary conditions + */ + m_metadomain.CommunicateFields(dom, Comm::B | Comm::B0); + FieldBoundaries(dom, BC::B); } } From 25b4e766088df14039ebe9dcff8b6dcd3c970c98 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Wed, 25 Sep 2024 17:21:12 -0400 Subject: [PATCH 046/773] engine/grpic: fixed passing ni2 to faraday kernel. prep for ampere kernel --- src/engines/grpic.hpp | 35 +++++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index afe22eb47..d55d0a6b2 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -157,6 +157,13 @@ namespace ntt { */ m_metadomain.CommunicateFields(dom, Comm::B | Comm::B0); FieldBoundaries(dom, BC::B); + + /** + * em::D <- (em0::D) <- curl aux::H + * + * Now: em::D at 0 + */ + Ampere(dom, gr_ampere::init, HALF); } } @@ -399,7 +406,7 @@ namespace ntt { domain.fields.aux, domain.mesh.metric, dT, - domain.mesh.i_max(in::x2), + domain.mesh.n_active(in::x2), domain.mesh.flds_bc())); } else if (g == gr_faraday::main) { Kokkos::parallel_for("Faraday", @@ -409,13 +416,37 @@ namespace ntt { domain.fields.aux, domain.mesh.metric, dT, - domain.mesh.i_max(in::x2), + domain.mesh.n_active(in::x2), domain.mesh.flds_bc())); } else { raise::Error("Wrong option for `g`", HERE); } } + + void Ampere(domain_t& domain, const gr_ampere& g, real_t fraction = ONE) { + logger::Checkpoint("Launching Ampere kernel", HERE); + const auto dT = fraction * + m_params.template get( + "algorithms.timestep.correction") * + dt; + auto range = CreateRangePolicy( + { domain.mesh.i_min(in::x1), domain.mesh.i_min(in::x2) + 1}, + { domain.mesh.i_max(in::x1), domain.mesh.i_max(in::x2)}); + auto range_pole = CreateRangePolicy( + { domain.mesh.i_min(in::x1)}, + { domain.mesh.i_max(in::x1)}); + const auto ni2 = domain.mesh.n_active(in::x2); + Kokkos::parallel_for("Ampere", + range, + kernel::gr::Ampere_kernel(domain.fields.em, + domain.fields.em, + domain.fields.em, + domain.mesh.metric, + dT, + ni2, + domain.mesh.flds_bc())); + } }; } // namespace ntt From 9c04fe27c936f37a238706fe36d22f590a50cae1 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Wed, 25 Sep 2024 17:51:47 -0400 Subject: [PATCH 047/773] engines/grpic: added ampere and subsequent BC --- src/engines/grpic.hpp | 142 +++++++++++++++++++++++++----------------- 1 file changed, 85 insertions(+), 57 deletions(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index d55d0a6b2..3306c1060 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -26,7 +26,6 @@ #include "framework/parameters.h" #include "engines/engine.hpp" - #include "kernels/ampere_gr.hpp" #include "kernels/aux_fields_gr.hpp" #include "kernels/currents_deposit.hpp" @@ -35,7 +34,6 @@ #include "kernels/fields_bcs.hpp" #include "kernels/particle_moments.hpp" #include "kernels/particle_pusher_gr.hpp" - #include "pgen.hpp" #include @@ -102,25 +100,26 @@ namespace ntt { if (step == 0) { // communicate fields and apply BCs on the first timestep /** - * Initially: em0::B -- - * em0::D -- - * em::B at -1/2 - * em::D at -1/2 - * - * cur0::J -- - * cur::J -- - * - * aux::E -- - * aux::H -- - * - * x_prtl at -1/2 - * u_prtl at -1/2 - */ + * Initially: em0::B -- + * em0::D -- + * em::B at -1/2 + * em::D at -1/2 + * + * cur0::J -- + * cur::J -- + * + * aux::E -- + * aux::H -- + * + * x_prtl at -1/2 + * u_prtl at -1/2 + */ /** - * em0::D, em::D, em0::B, em::B <- boundary conditions - */ - m_metadomain.CommunicateFields(dom, Comm::B | Comm::B0 | Comm::D | Comm::D0); + * em0::D, em::D, em0::B, em::B <- boundary conditions + */ + m_metadomain.CommunicateFields(dom, + Comm::B | Comm::B0 | Comm::D | Comm::D0); FieldBoundaries(dom, BC::B | BC::D); /** @@ -167,7 +166,7 @@ namespace ntt { } } -/* algorithm substeps --------------------------------------------------- */ + /* algorithm substeps --------------------------------------------------- */ void FieldBoundaries(domain_t& domain, BCTags tags) { for (auto& direction : dir::Directions::orth) { if (m_metadomain.mesh().flds_bc_in(direction) == FldsBC::ABSORB) { @@ -361,7 +360,7 @@ namespace ntt { domain.fields.em0, domain.fields.aux, domain.mesh.metric)); - } else if (g == gr_getH::D0_B0) { + } else if (g == gr_getH::D0_B0) { Kokkos::parallel_for("ComputeAuxH", range, kernel::gr::ComputeAuxH_kernel(domain.fields.em0, @@ -399,31 +398,33 @@ namespace ntt { "algorithms.timestep.correction") * dt; if (g == gr_faraday::aux) { - Kokkos::parallel_for("Faraday", - domain.mesh.rangeActiveCells(), - kernel::gr::Faraday_kernel(domain.fields.em0, - domain.fields.em0, - domain.fields.aux, - domain.mesh.metric, - dT, - domain.mesh.n_active(in::x2), - domain.mesh.flds_bc())); + Kokkos::parallel_for( + "Faraday", + domain.mesh.rangeActiveCells(), + kernel::gr::Faraday_kernel(domain.fields.em0, + domain.fields.em0, + domain.fields.aux, + domain.mesh.metric, + dT, + domain.mesh.n_active(in::x2), + domain.mesh.flds_bc())); } else if (g == gr_faraday::main) { - Kokkos::parallel_for("Faraday", - domain.mesh.rangeActiveCells(), - kernel::gr::Faraday_kernel(domain.fields.em0, - domain.fields.em0, - domain.fields.aux, - domain.mesh.metric, - dT, - domain.mesh.n_active(in::x2), - domain.mesh.flds_bc())); + Kokkos::parallel_for( + "Faraday", + domain.mesh.rangeActiveCells(), + kernel::gr::Faraday_kernel(domain.fields.em0, + domain.fields.em0, + domain.fields.aux, + domain.mesh.metric, + dT, + domain.mesh.n_active(in::x2), + domain.mesh.flds_bc())); } else { - raise::Error("Wrong option for `g`", HERE); - } + raise::Error("Wrong option for `g`", HERE); + } } - + void Ampere(domain_t& domain, const gr_ampere& g, real_t fraction = ONE) { logger::Checkpoint("Launching Ampere kernel", HERE); const auto dT = fraction * @@ -431,23 +432,50 @@ namespace ntt { "algorithms.timestep.correction") * dt; auto range = CreateRangePolicy( - { domain.mesh.i_min(in::x1), domain.mesh.i_min(in::x2) + 1}, - { domain.mesh.i_max(in::x1), domain.mesh.i_max(in::x2)}); - auto range_pole = CreateRangePolicy( - { domain.mesh.i_min(in::x1)}, - { domain.mesh.i_max(in::x1)}); + { domain.mesh.i_min(in::x1), domain.mesh.i_min(in::x2) + 1 }, + { domain.mesh.i_max(in::x1), domain.mesh.i_max(in::x2) }); + auto range_pole = CreateRangePolicy({ domain.mesh.i_min(in::x1) }, + { domain.mesh.i_max(in::x1) }); const auto ni2 = domain.mesh.n_active(in::x2); - Kokkos::parallel_for("Ampere", - range, - kernel::gr::Ampere_kernel(domain.fields.em, - domain.fields.em, - domain.fields.em, - domain.mesh.metric, - dT, - ni2, - domain.mesh.flds_bc())); - } + if (g == gr_ampere::aux) { + // First push, updates D0 with J. + Kokkos::parallel_for("Ampere-1", + range, + kernel::gr::Ampere_kernel(domain.fields.em, // has to be zeros + domain.fields.em0, + domain.fields.aux, + domain.mesh.metric, + dT, + ni2, + domain.mesh.flds_bc())); + } else if (g == gr_ampere::main) { + // Second push, updates D with J0 but assigns it to D0. + Kokkos::parallel_for("Ampere-2", + range, + kernel::gr::Ampere_kernel(domain.fields.em, + domain.fields.em0, + domain.fields.aux, + domain.mesh.metric, + dT, + ni2, + domain.mesh.flds_bc())); + } else if (g == gr_ampere::init) { + // Second push, updates D with J0 and assigns it to D. + Kokkos::parallel_for("Ampere-3", + range, + kernel::gr::Ampere_kernel(domain.fields.em, //has to be zeros + domain.fields.em, + domain.fields.aux, + domain.mesh.metric, + dT, + ni2, + domain.mesh.flds_bc())); + } else { + raise::Error("Wrong option for `g`", HERE); + } + + } }; } // namespace ntt From f14b6430e94e7b97aca9bf67d41eebabf61f32ca Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Thu, 26 Sep 2024 15:25:56 -0400 Subject: [PATCH 048/773] engine/grpic: added everything for initial step, except BC for aux --- src/engines/grpic.hpp | 102 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 97 insertions(+), 5 deletions(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index 3306c1060..d23a966db 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -163,6 +163,99 @@ namespace ntt { * Now: em::D at 0 */ Ampere(dom, gr_ampere::init, HALF); + + /** + * em0::D, em::D <- boundary conditions + */ + m_metadomain.CommunicateFields(dom, Comm::D | Comm::D0); + FieldBoundaries(dom, BC::D); + + /** + * aux::E <- alpha * em::D + beta x em0::B + * aux::H <- alpha * em0::B - beta x em::D + * + * Now: aux::E & aux::H at 0 + */ + ComputeAuxE(dom, gr_getE::D_B0); + ComputeAuxH(dom, gr_getH::D_B0); + + /** + * aux::E, aux::H <- boundary conditions + */ + // ?? aux field boundaries ?? + + // !ADD: GR -- particles? + + /** + * em0::B <- (em::B) <- -curl aux::E + * + * Now: em0::B at 1/2 + */ + Faraday(dom, gr_faraday::main, ONE); + /** + * em0::B, em::B <- boundary conditions + */ + m_metadomain.CommunicateFields(dom, Comm::B | Comm::B0); + FieldBoundaries(dom, BC::B); + + /** + * em0::D <- (em0::D) <- curl aux::H + * + * Now: em0::D at 1/2 + */ + Ampere(dom, gr_ampere::aux, ONE); + /** + * em0::D, em::D <- boundary conditions + */ + m_metadomain.CommunicateFields(dom, Comm::D | Comm::D0); + FieldBoundaries(dom, BC::D); + + /** + * aux::H <- alpha * em0::B - beta x em0::D + * + * Now: aux::H at 1/2 + */ + ComputeAuxH(dom, gr_getH::D0_B0); + /** + * aux::H <- boundary conditions + */ + // ?? aux field boundaries ?? + + /** + * em0::D <- (em::D) <- curl aux::H + * + * Now: em0::D at 1 + * em::D at 0 + */ + Ampere(dom, gr_ampere::main, ONE); + /** + * em0::D, em::D <- boundary conditions + */ + m_metadomain.CommunicateFields(dom, Comm::D | Comm::D0); + FieldBoundaries(dom, BC::D); + + /** + * em::D <-> em0::D + * em::B <-> em0::B + * em::J <-> em0::J + */ + SwapFields(dom); + /** + * Finally: em0::B at -1/2 + * em0::D at 0 + * em::B at 1/2 + * em::D at 1 + * + * cur0::J -- + * cur::J -- + * + * aux::E -- + * aux::H -- + * + * x_prtl at 1 + * u_prtl at 1/2 + */ + } } @@ -317,11 +410,10 @@ namespace ntt { /** * @brief Swaps em and em0 fields, cur and cur0 currents. */ - // void SwapFields() { - // auto& mblock = this->meshblock; - // std::swap(mblock.em, mblock.em0); - // std::swap(mblock.cur, mblock.cur0); - // } + void SwapFields(domain_t& domain) { + std::swap(domain.fields.em, domain.fields.em0); + std::swap(domain.fields.cur, domain.fields.cur0); + } /** * @brief Copies em fields into em0 From 910e535a88687c24c9917d59767fe0e91183033f Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Fri, 27 Sep 2024 13:26:17 -0400 Subject: [PATCH 049/773] engines/grpis: minor update to first aux step for consistency --- src/engines/grpic.hpp | 51 +++++++++++++++++++++++++------------------ 1 file changed, 30 insertions(+), 21 deletions(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index d23a966db..7306e08ab 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -118,8 +118,7 @@ namespace ntt { /** * em0::D, em::D, em0::B, em::B <- boundary conditions */ - m_metadomain.CommunicateFields(dom, - Comm::B | Comm::B0 | Comm::D | Comm::D0); + m_metadomain.CommunicateFields(dom, Comm::B | Comm::B0 | Comm::D | Comm::D0); FieldBoundaries(dom, BC::B | BC::D); /** @@ -136,7 +135,7 @@ namespace ntt { * * Now: aux::E & aux::H at -1/2 */ - ComputeAuxE(dom, gr_getE::D0_B); + ComputeAuxE(dom, gr_getE::D_B0); ComputeAuxH(dom, gr_getH::D_B0); /** @@ -257,6 +256,20 @@ namespace ntt { */ } + + if (fieldsolver_enabled) { + + } + + { + + + } + + if (fieldsolver_enabled) { + + } + } /* algorithm substeps --------------------------------------------------- */ @@ -466,19 +479,17 @@ namespace ntt { auto range_with_axis_BCs(const domain_t& domain) -> range_t { auto range = domain.mesh.rangeActiveCells(); - if constexpr (M::CoordType != Coord::Cart) { - /** - * @brief taking one extra cell in the x1 and x2 directions if AXIS BCs - */ - if constexpr (M::Dim == Dim::_2D) { - if (domain.mesh.flds_bc_in({ 0, +1 }) == FldsBC::AXIS) { - range = CreateRangePolicy( - { domain.mesh.i_min(in::x1) - 1, domain.mesh.i_min(in::x2) }, - { domain.mesh.i_max(in::x1), domain.mesh.i_max(in::x2) + 1 }); - } - } else if constexpr (M::Dim == Dim::_3D) { - raise::Error("Invalid dimension", HERE); + /** + * @brief taking one extra cell in the x1 and x2 directions if AXIS BCs + */ + if constexpr (M::Dim == Dim::_2D) { + if (domain.mesh.flds_bc_in({ 0, +1 }) == FldsBC::AXIS) { + range = CreateRangePolicy( + { domain.mesh.i_min(in::x1) - 1, domain.mesh.i_min(in::x2) }, + { domain.mesh.i_max(in::x1), domain.mesh.i_max(in::x2) + 1 }); } + } else if constexpr (M::Dim == Dim::_3D) { + raise::Error("Invalid dimension", HERE); } return range; } @@ -524,17 +535,15 @@ namespace ntt { "algorithms.timestep.correction") * dt; auto range = CreateRangePolicy( - { domain.mesh.i_min(in::x1), domain.mesh.i_min(in::x2) + 1 }, - { domain.mesh.i_max(in::x1), domain.mesh.i_max(in::x2) }); - auto range_pole = CreateRangePolicy({ domain.mesh.i_min(in::x1) }, - { domain.mesh.i_max(in::x1) }); + { domain.mesh.i_min(in::x1), domain.mesh.i_min(in::x2)}, + { domain.mesh.i_max(in::x1), domain.mesh.i_max(in::x2) + 1}); const auto ni2 = domain.mesh.n_active(in::x2); if (g == gr_ampere::aux) { // First push, updates D0 with J. Kokkos::parallel_for("Ampere-1", range, - kernel::gr::Ampere_kernel(domain.fields.em, // has to be zeros + kernel::gr::Ampere_kernel(domain.fields.em, domain.fields.em0, domain.fields.aux, domain.mesh.metric, @@ -556,7 +565,7 @@ namespace ntt { // Second push, updates D with J0 and assigns it to D. Kokkos::parallel_for("Ampere-3", range, - kernel::gr::Ampere_kernel(domain.fields.em, //has to be zeros + kernel::gr::Ampere_kernel(domain.fields.em, domain.fields.em, domain.fields.aux, domain.mesh.metric, From faf471b60f40fab90cbb8b64b3767f6199e370f7 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Fri, 27 Sep 2024 13:28:35 -0400 Subject: [PATCH 050/773] engines/grpic: fixed ComputeAuxE function --- src/engines/grpic.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index 7306e08ab..7c3d13fbe 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -442,14 +442,14 @@ namespace ntt { range, kernel::gr::ComputeAuxE_kernel(domain.fields.em0, domain.fields.em, - domain.fields.em, + domain.fields.aux, domain.mesh.metric)); } else if (g == gr_getE::D_B0) { Kokkos::parallel_for("ComputeAuxE", range, kernel::gr::ComputeAuxE_kernel(domain.fields.em, domain.fields.em0, - domain.fields.em, + domain.fields.aux, domain.mesh.metric)); } else { raise::Error("Wrong option for `g`", HERE); From dfe51f4fd1d08dc1abcfce866040b77bb5991be2 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Fri, 27 Sep 2024 13:30:28 -0400 Subject: [PATCH 051/773] engines/grpic: fixed Faraday function --- src/engines/grpic.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index 7c3d13fbe..de7f04752 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -515,7 +515,7 @@ namespace ntt { Kokkos::parallel_for( "Faraday", domain.mesh.rangeActiveCells(), - kernel::gr::Faraday_kernel(domain.fields.em0, + kernel::gr::Faraday_kernel(domain.fields.em, domain.fields.em0, domain.fields.aux, domain.mesh.metric, From e57cbf8fa2e787f39e93ae10c7ccb1ef95cf6bb6 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Fri, 27 Sep 2024 13:32:17 -0400 Subject: [PATCH 052/773] engines/grpis: fixed Ampere function --- src/engines/grpic.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index de7f04752..6a7e23540 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -543,7 +543,7 @@ namespace ntt { // First push, updates D0 with J. Kokkos::parallel_for("Ampere-1", range, - kernel::gr::Ampere_kernel(domain.fields.em, + kernel::gr::Ampere_kernel(domain.fields.em0, domain.fields.em0, domain.fields.aux, domain.mesh.metric, From eeac7ff3474c10083550604639246c9cf7f2317b Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Fri, 27 Sep 2024 13:45:25 -0400 Subject: [PATCH 053/773] engines/grpic: added a class for field_bc to accomodate passing em, em0, aux to BC kernels --- src/engines/grpic.hpp | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index 6a7e23540..14ecffb28 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -61,6 +61,11 @@ namespace ntt { aux, main }; + enum class gr_bc { + main, + main0, + aux + }; template class GRPICEngine : public Engine { @@ -273,17 +278,17 @@ namespace ntt { } /* algorithm substeps --------------------------------------------------- */ - void FieldBoundaries(domain_t& domain, BCTags tags) { + void FieldBoundaries(domain_t& domain, BCTags tags, const gr_bc& g) { for (auto& direction : dir::Directions::orth) { if (m_metadomain.mesh().flds_bc_in(direction) == FldsBC::ABSORB) { - AbsorbFieldsIn(direction, domain, tags); + AbsorbFieldsIn(direction, domain, tags, g); } else if (m_metadomain.mesh().flds_bc_in(direction) == FldsBC::AXIS) { if (domain.mesh.flds_bc_in(direction) == FldsBC::AXIS) { - AxisFieldsIn(direction, domain, tags); + AxisFieldsIn(direction, domain, tags, g); } } else if (m_metadomain.mesh().flds_bc_in(direction) == FldsBC::CUSTOM) { if (domain.mesh.flds_bc_in(direction) == FldsBC::CUSTOM) { - CustomFieldsIn(direction, domain, tags); + CustomFieldsIn(direction, domain, tags, g); } } else if (m_metadomain.mesh().flds_bc_in(direction) == FldsBC::HORIZON) { raise::Error("HORIZON BCs only applicable for GR", HERE); @@ -293,7 +298,8 @@ namespace ntt { void AbsorbFieldsIn(dir::direction_t direction, domain_t& domain, - BCTags tags) { + BCTags tags + const gr_getE& g) { /** * absorbing boundaries */ @@ -377,7 +383,8 @@ namespace ntt { void AxisFieldsIn(dir::direction_t direction, domain_t& domain, - BCTags tags) { + BCTags tags + const gr_getE& g) { /** * axis boundaries */ @@ -404,7 +411,8 @@ namespace ntt { void CustomFieldsIn(dir::direction_t direction, domain_t& domain, - BCTags tags) { + BCTags tags + const gr_getE& g) { (void)direction; (void)domain; (void)tags; From c84140031d34576445e4471cb3a6c954cfc1abbe Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Fri, 27 Sep 2024 14:06:50 -0400 Subject: [PATCH 054/773] engines/grpic: cut out 3d from absorb BCs --- src/engines/grpic.hpp | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index 14ecffb28..5c5a54770 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -353,7 +353,7 @@ namespace ntt { ds, tags)); } else if (dim == in::x2) { - if constexpr (M::Dim == Dim::_2D or M::Dim == Dim::_3D) { + if constexpr (M::Dim == Dim::_2D) { Kokkos::parallel_for( "AbsorbFields", CreateRangePolicy(range_min, range_max), @@ -365,19 +365,8 @@ namespace ntt { } else { raise::Error("Invalid dimension", HERE); } - } else if (dim == in::x3) { - if constexpr (M::Dim == Dim::_3D) { - Kokkos::parallel_for( - "AbsorbFields", - CreateRangePolicy(range_min, range_max), - kernel::AbsorbBoundaries_kernel(domain.fields.em, - domain.mesh.metric, - xg_edge, - ds, - tags)); - } else { + } else { raise::Error("Invalid dimension", HERE); - } } } From 03b05593729e7689844f82ba14a9bc925ce0e26f Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Fri, 27 Sep 2024 14:10:10 -0400 Subject: [PATCH 055/773] minot: fix syntax --- src/engines/grpic.hpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index 5c5a54770..9032448ad 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -298,8 +298,8 @@ namespace ntt { void AbsorbFieldsIn(dir::direction_t direction, domain_t& domain, - BCTags tags - const gr_getE& g) { + BCTags tags, + const gr_bc& g) { /** * absorbing boundaries */ @@ -372,8 +372,8 @@ namespace ntt { void AxisFieldsIn(dir::direction_t direction, domain_t& domain, - BCTags tags - const gr_getE& g) { + BCTags tags, + const gr_bc& g) { /** * axis boundaries */ @@ -400,8 +400,8 @@ namespace ntt { void CustomFieldsIn(dir::direction_t direction, domain_t& domain, - BCTags tags - const gr_getE& g) { + BCTags tags, + const gr_bc& g) { (void)direction; (void)domain; (void)tags; From cbe2fee224701675b5753d426e42e8332ed7c0d9 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Fri, 27 Sep 2024 14:10:44 -0400 Subject: [PATCH 056/773] minor: cut out options from gr_bc class --- src/engines/grpic.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index 9032448ad..982e76ba9 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -63,7 +63,6 @@ namespace ntt { }; enum class gr_bc { main, - main0, aux }; From 67ec72092caf3eefacfaf13c72ed4d587c5bf422 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Fri, 27 Sep 2024 14:12:48 -0400 Subject: [PATCH 057/773] minor: cut out gr_bc from most bc functions since only horizon bc needs aux fields; em and em0 are always set together --- src/engines/grpic.hpp | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index 982e76ba9..4fc809a08 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -280,14 +280,14 @@ namespace ntt { void FieldBoundaries(domain_t& domain, BCTags tags, const gr_bc& g) { for (auto& direction : dir::Directions::orth) { if (m_metadomain.mesh().flds_bc_in(direction) == FldsBC::ABSORB) { - AbsorbFieldsIn(direction, domain, tags, g); + AbsorbFieldsIn(direction, domain, tags); } else if (m_metadomain.mesh().flds_bc_in(direction) == FldsBC::AXIS) { if (domain.mesh.flds_bc_in(direction) == FldsBC::AXIS) { - AxisFieldsIn(direction, domain, tags, g); + AxisFieldsIn(direction, domain, tags); } } else if (m_metadomain.mesh().flds_bc_in(direction) == FldsBC::CUSTOM) { if (domain.mesh.flds_bc_in(direction) == FldsBC::CUSTOM) { - CustomFieldsIn(direction, domain, tags, g); + CustomFieldsIn(direction, domain, tags); } } else if (m_metadomain.mesh().flds_bc_in(direction) == FldsBC::HORIZON) { raise::Error("HORIZON BCs only applicable for GR", HERE); @@ -297,8 +297,7 @@ namespace ntt { void AbsorbFieldsIn(dir::direction_t direction, domain_t& domain, - BCTags tags, - const gr_bc& g) { + BCTags tags) { /** * absorbing boundaries */ @@ -371,8 +370,7 @@ namespace ntt { void AxisFieldsIn(dir::direction_t direction, domain_t& domain, - BCTags tags, - const gr_bc& g) { + BCTags tags) { /** * axis boundaries */ From 34a42a4b8b8adabeab4774339e94ffb8d05afe62 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Fri, 27 Sep 2024 14:15:03 -0400 Subject: [PATCH 058/773] engines/grpic: added gr_bc into step=0 functions --- src/engines/grpic.hpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index 4fc809a08..5a8fb3987 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -123,7 +123,7 @@ namespace ntt { * em0::D, em::D, em0::B, em::B <- boundary conditions */ m_metadomain.CommunicateFields(dom, Comm::B | Comm::B0 | Comm::D | Comm::D0); - FieldBoundaries(dom, BC::B | BC::D); + FieldBoundaries(dom, BC::B | BC::D, gr_bc::main); /** * em0::B <- em::B @@ -158,7 +158,7 @@ namespace ntt { * em0::B, em::B <- boundary conditions */ m_metadomain.CommunicateFields(dom, Comm::B | Comm::B0); - FieldBoundaries(dom, BC::B); + FieldBoundaries(dom, BC::B, gr_bc::main); /** * em::D <- (em0::D) <- curl aux::H @@ -171,7 +171,7 @@ namespace ntt { * em0::D, em::D <- boundary conditions */ m_metadomain.CommunicateFields(dom, Comm::D | Comm::D0); - FieldBoundaries(dom, BC::D); + FieldBoundaries(dom, BC::D, gr_bc::main); /** * aux::E <- alpha * em::D + beta x em0::B @@ -199,7 +199,7 @@ namespace ntt { * em0::B, em::B <- boundary conditions */ m_metadomain.CommunicateFields(dom, Comm::B | Comm::B0); - FieldBoundaries(dom, BC::B); + FieldBoundaries(dom, BC::B, gr_bc::main); /** * em0::D <- (em0::D) <- curl aux::H @@ -211,7 +211,7 @@ namespace ntt { * em0::D, em::D <- boundary conditions */ m_metadomain.CommunicateFields(dom, Comm::D | Comm::D0); - FieldBoundaries(dom, BC::D); + FieldBoundaries(dom, BC::D, gr_bc::main); /** * aux::H <- alpha * em0::B - beta x em0::D @@ -235,7 +235,7 @@ namespace ntt { * em0::D, em::D <- boundary conditions */ m_metadomain.CommunicateFields(dom, Comm::D | Comm::D0); - FieldBoundaries(dom, BC::D); + FieldBoundaries(dom, BC::D, gr_bc::main); /** * em::D <-> em0::D From a3d5db85e50087b8412b8b09f7c26ab6a27b0e87 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Fri, 27 Sep 2024 14:22:49 -0400 Subject: [PATCH 059/773] engines/grpic: added BC for em0 --- src/engines/grpic.hpp | 56 +++++++++++++++++++++++++++++++++---------- 1 file changed, 44 insertions(+), 12 deletions(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index 5a8fb3987..cdce0c593 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -278,21 +278,29 @@ namespace ntt { /* algorithm substeps --------------------------------------------------- */ void FieldBoundaries(domain_t& domain, BCTags tags, const gr_bc& g) { - for (auto& direction : dir::Directions::orth) { - if (m_metadomain.mesh().flds_bc_in(direction) == FldsBC::ABSORB) { - AbsorbFieldsIn(direction, domain, tags); - } else if (m_metadomain.mesh().flds_bc_in(direction) == FldsBC::AXIS) { - if (domain.mesh.flds_bc_in(direction) == FldsBC::AXIS) { - AxisFieldsIn(direction, domain, tags); + if (g == gr_bc::main) { + for (auto& direction : dir::Directions::orth) { + if (m_metadomain.mesh().flds_bc_in(direction) == FldsBC::ABSORB) { + AbsorbFieldsIn(direction, domain, tags); + } else if (m_metadomain.mesh().flds_bc_in(direction) == FldsBC::AXIS) { + if (domain.mesh.flds_bc_in(direction) == FldsBC::AXIS) { + AxisFieldsIn(direction, domain, tags); + } + } else if (m_metadomain.mesh().flds_bc_in(direction) == FldsBC::CUSTOM) { + if (domain.mesh.flds_bc_in(direction) == FldsBC::CUSTOM) { + CustomFieldsIn(direction, domain, tags, g); + } + } else if (m_metadomain.mesh().flds_bc_in(direction) == FldsBC::HORIZON) { + raise::Error("HORIZON BCs only applicable for GR", HERE); } - } else if (m_metadomain.mesh().flds_bc_in(direction) == FldsBC::CUSTOM) { - if (domain.mesh.flds_bc_in(direction) == FldsBC::CUSTOM) { - CustomFieldsIn(direction, domain, tags); + } // loop over directions + } else if (g == gr_bc::aux) { + for (auto& direction : dir::Directions::orth) { + if (m_metadomain.mesh().flds_bc_in(direction) == FldsBC::HORIZON) { + raise::Error("HORIZON BCs only applicable for GR", HERE); } - } else if (m_metadomain.mesh().flds_bc_in(direction) == FldsBC::HORIZON) { - raise::Error("HORIZON BCs only applicable for GR", HERE); } - } // loop over directions + } } void AbsorbFieldsIn(dir::direction_t direction, @@ -350,6 +358,14 @@ namespace ntt { xg_edge, ds, tags)); + Kokkos::parallel_for( + "AbsorbFields", + CreateRangePolicy(range_min, range_max), + kernel::AbsorbBoundaries_kernel(domain.fields.em0, + domain.mesh.metric, + xg_edge, + ds, + tags)); } else if (dim == in::x2) { if constexpr (M::Dim == Dim::_2D) { Kokkos::parallel_for( @@ -360,6 +376,14 @@ namespace ntt { xg_edge, ds, tags)); + Kokkos::parallel_for( + "AbsorbFields", + CreateRangePolicy(range_min, range_max), + kernel::AbsorbBoundaries_kernel(domain.fields.em0, + domain.mesh.metric, + xg_edge, + ds, + tags)); } else { raise::Error("Invalid dimension", HERE); } @@ -387,11 +411,19 @@ namespace ntt { "AxisBCFields", domain.mesh.n_all(in::x1), kernel::AxisBoundaries_kernel(domain.fields.em, i2_min, tags)); + Kokkos::parallel_for( + "AxisBCFields", + domain.mesh.n_all(in::x1), + kernel::AxisBoundaries_kernel(domain.fields.em0, i2_min, tags)); } else { Kokkos::parallel_for( "AxisBCFields", domain.mesh.n_all(in::x1), kernel::AxisBoundaries_kernel(domain.fields.em, i2_max, tags)); + Kokkos::parallel_for( + "AxisBCFields", + domain.mesh.n_all(in::x1), + kernel::AxisBoundaries_kernel(domain.fields.em0, i2_max, tags)); } } From 313850bb0a20fd78dc690686eb2d1946d8154d2d Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Fri, 27 Sep 2024 16:07:17 -0400 Subject: [PATCH 060/773] added a kernel for OpenBoundaries --- src/kernels/fields_bcs.hpp | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/src/kernels/fields_bcs.hpp b/src/kernels/fields_bcs.hpp index e617010b4..5f1e6255e 100644 --- a/src/kernels/fields_bcs.hpp +++ b/src/kernels/fields_bcs.hpp @@ -489,6 +489,40 @@ namespace kernel { } }; +template + struct OpenBoundaries_kernel { + ndfield_t Fld; + const std::size_t i1_min; + const bool setE, setB; + + OpenBoundaries_kernel(ndfield_t Fld, BCTags tags) + : Fld { Fld } + , i1_min { i1_min } + , setE { tags & BC::Ex1 or tags & BC::Ex2 or tags & BC::Ex3 } + , setB { tags & BC::Bx1 or tags & BC::Bx2 or tags & BC::Bx3 } {} + + Inline void operator()(index_t i2) const { + if constexpr (M::Dim == Dim::_2D) { + if (setE) { + Fld(i1_min - 1, i2, em::ex1) = Fld(i1_min , i2, em::ex1); + Fld(i1_min , i2, em::ex2) = Fld(i1_min + 1, i2, em::ex2); + Fld(i1_min - 1, i2, em::ex2) = Fld(i1_min , i2, em::ex2); + Fld(i1_min , i2, em::ex3) = Fld(i1_min + 1, i2, em::ex3); + Fld(i1_min - 1, i2, em::ex3) = Fld(i1_min , i2, em::ex3); + } else if (setB) { + Fld(i1_min , i2, em::bx1) = Fld(i1_min + 1, i2, em::bx1); + Fld(i1_min - 1, i2, em::bx1) = Fld(i1_min , i2, em::bx1); + Fld(i1_min - 1, i2, em::bx2) = Fld(i1_min , i2, em::bx2); + Fld(i1_min - 1, i2, em::bx3) = Fld(i1_min , i2, em::bx3); + } + } else { + raise::KernelError( + HERE, + "AbsorbFields_kernel: 2D implementation called for D != 2"); + } + } + }; + } // namespace kernel #endif // KERNELS_FIELDS_BCS_HPP From 0d05349d207231bc6ebc775378a75f394fa7270d Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Mon, 30 Sep 2024 15:48:22 -0400 Subject: [PATCH 061/773] engines/grpic: implemented function to call for OpenBoundaries_kernel kernels/fields_bcs: fixed parameter passing in OpenBoundaries_kernel --- src/engines/grpic.hpp | 35 +++++++++++++++++++++++++++++++++-- src/kernels/fields_bcs.hpp | 2 +- 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index cdce0c593..54ffd3872 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -291,13 +291,13 @@ namespace ntt { CustomFieldsIn(direction, domain, tags, g); } } else if (m_metadomain.mesh().flds_bc_in(direction) == FldsBC::HORIZON) { - raise::Error("HORIZON BCs only applicable for GR", HERE); + OpenFieldsIn(direction, domain, tags); } } // loop over directions } else if (g == gr_bc::aux) { for (auto& direction : dir::Directions::orth) { if (m_metadomain.mesh().flds_bc_in(direction) == FldsBC::HORIZON) { - raise::Error("HORIZON BCs only applicable for GR", HERE); + OpenFieldsIn(direction, domain, tags); } } } @@ -392,6 +392,37 @@ namespace ntt { } } + void OpenFieldsIn(dir::direction_t direction, + domain_t& domain, + BCTags tags, + const gr_bc& g) { + /** + * open boundaries + */ + raise::ErrorIf(M::CoordType == Coord::Cart, + "Invalid coordinate type for axis BCs", + HERE); + raise::ErrorIf(direction.get_dim() != in::x1, + "Invalid axis direction, should be x2", + HERE); + const auto i1_min = domain.mesh.i_min(in::x1); + if (g == gr_bc::main) { + Kokkos::parallel_for( + "OpenBCFields", + domain.mesh.n_all(in::x1), + kernel::OpenBoundaries_kernel(domain.fields.em, i1_min, tags)); + Kokkos::parallel_for( + "OpenBCFields", + domain.mesh.n_all(in::x1), + kernel::AxisBoundaries_kernel(domain.fields.em0, i1_min, tags)); + } else if (g == gr_bc::aux) { + Kokkos::parallel_for( + "OpenBCFields", + domain.mesh.n_all(in::x1), + kernel::OpenBoundaries_kernel(domain.fields.aux, i1_min, tags)); + } + } + void AxisFieldsIn(dir::direction_t direction, domain_t& domain, BCTags tags) { diff --git a/src/kernels/fields_bcs.hpp b/src/kernels/fields_bcs.hpp index 5f1e6255e..5a50b6daf 100644 --- a/src/kernels/fields_bcs.hpp +++ b/src/kernels/fields_bcs.hpp @@ -495,7 +495,7 @@ template const std::size_t i1_min; const bool setE, setB; - OpenBoundaries_kernel(ndfield_t Fld, BCTags tags) + OpenBoundaries_kernel(ndfield_t Fld, std::size_t i1_min, BCTags tags) : Fld { Fld } , i1_min { i1_min } , setE { tags & BC::Ex1 or tags & BC::Ex2 or tags & BC::Ex3 } From 9c8efaa0e8cf676e461a11a09378f21bdb23291a Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Mon, 30 Sep 2024 15:54:30 -0400 Subject: [PATCH 062/773] enginesgrpic: added aux field boundaries calls to initial step --- src/engines/grpic.hpp | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index 54ffd3872..6da68dc18 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -145,7 +145,7 @@ namespace ntt { /** * aux::E, aux::H <- boundary conditions */ - // ?? aux field boundaries ?? + FieldBoundaries(dom, BC::B | BC::D, gr_bc::aux); /** * em0::B <- (em0::B) <- -curl aux::E @@ -185,7 +185,7 @@ namespace ntt { /** * aux::E, aux::H <- boundary conditions */ - // ?? aux field boundaries ?? + FieldBoundaries(dom, BC::B | BC::D, gr_bc::aux); // !ADD: GR -- particles? @@ -222,7 +222,7 @@ namespace ntt { /** * aux::H <- boundary conditions */ - // ?? aux field boundaries ?? + FieldBoundaries(dom, BC::B, gr_bc::aux); /** * em0::D <- (em::D) <- curl aux::H @@ -258,7 +258,6 @@ namespace ntt { * x_prtl at 1 * u_prtl at 1/2 */ - } if (fieldsolver_enabled) { @@ -291,13 +290,13 @@ namespace ntt { CustomFieldsIn(direction, domain, tags, g); } } else if (m_metadomain.mesh().flds_bc_in(direction) == FldsBC::HORIZON) { - OpenFieldsIn(direction, domain, tags); + OpenFieldsIn(direction, domain, tags, g); } } // loop over directions } else if (g == gr_bc::aux) { for (auto& direction : dir::Directions::orth) { if (m_metadomain.mesh().flds_bc_in(direction) == FldsBC::HORIZON) { - OpenFieldsIn(direction, domain, tags); + OpenFieldsIn(direction, domain, tags, g); } } } @@ -409,16 +408,16 @@ namespace ntt { if (g == gr_bc::main) { Kokkos::parallel_for( "OpenBCFields", - domain.mesh.n_all(in::x1), + domain.mesh.n_all(in::x2), kernel::OpenBoundaries_kernel(domain.fields.em, i1_min, tags)); Kokkos::parallel_for( "OpenBCFields", - domain.mesh.n_all(in::x1), - kernel::AxisBoundaries_kernel(domain.fields.em0, i1_min, tags)); + domain.mesh.n_all(in::x2), + kernel::OpenBoundaries_kernel(domain.fields.em0, i1_min, tags)); } else if (g == gr_bc::aux) { Kokkos::parallel_for( "OpenBCFields", - domain.mesh.n_all(in::x1), + domain.mesh.n_all(in::x2), kernel::OpenBoundaries_kernel(domain.fields.aux, i1_min, tags)); } } From 2569aec93f3dbe42fbe4bee1d0772f55f4a07ac7 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Mon, 30 Sep 2024 16:16:18 -0400 Subject: [PATCH 063/773] added TimeAverageDB() and kernel for it in kernels/aux --- src/engines/grpic.hpp | 34 ++++++++++++++++++++++++++++++- src/kernels/aux_fields_gr.hpp | 38 +++++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+), 1 deletion(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index 6da68dc18..a75742be2 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -260,8 +260,31 @@ namespace ntt { */ } - if (fieldsolver_enabled) { + /** + * Initially: em0::B at n-3/2 + * em0::D at n-1 + * em::B at n-1/2 + * em::D at n + * + * cur0::J -- + * cur::J at n-1/2 + * + * aux::E -- + * aux::H -- + * + * x_prtl at n + * u_prtl at n-1/2 + */ + if (fieldsolver_enabled) { + /** + * em0::D <- (em0::D + em::D) / 2 + * em0::B <- (em0::B + em::B) / 2 + * + * Now: em0::D at n-1/2 + * em0::B at n-1 + */ + TimeAverageDB(dom); } { @@ -633,6 +656,15 @@ namespace ntt { } } + + void TimeAverageDB(domain_t& domain) { + auto range = range_with_axis_BCs(domain); + Kokkos::parallel_for("TimeAverageDB", + range, + kernel::gr::TimeAverageDB_kernel(domain.fields.em, + domain.fields.em0, + domain.mesh.metric)); + } }; } // namespace ntt diff --git a/src/kernels/aux_fields_gr.hpp b/src/kernels/aux_fields_gr.hpp index 5744c3092..4f87ba1f2 100644 --- a/src/kernels/aux_fields_gr.hpp +++ b/src/kernels/aux_fields_gr.hpp @@ -230,6 +230,44 @@ namespace kernel::gr { } } }; + + /** + * @brief Kernel for computing time average of B and D + * @tparam M Metric + */ + template + class TimeAverageDB_kernel { + static_assert(M::is_metric, "M must be a metric class"); + static constexpr auto D = M::Dim; + + const ndfield_t BDf; + ndfield_t BDf0; + const M metric; + + public: + TimeAverageDB_kernel(const ndfield_t& BDf, + const ndfield_t& BDf0, + const M& metric) + : BDf { BDf } + , BDf0 { BDf0 } + , metric { metric } {} + + Inline void operator()(index_t i1, index_t i2) const { + if constexpr (D == Dim::_2D) { + BDf0(i1, i2, em::bx1) = HALF * (BDf0(i1, i2, em::bx1) + BDf(i1, i2, em::bx1)); + BDf0(i1, i2, em::bx2) = HALF * (BDf0(i1, i2, em::bx2) + BDf(i1, i2, em::bx2)); + BDf0(i1, i2, em::bx3) = HALF * (BDf0(i1, i2, em::bx3) + BDf(i1, i2, em::bx3)); + BDf0(i1, i2, em::ex1) = HALF * (BDf0(i1, i2, em::bx1) + BDf(i1, i2, em::ex1)); + BDf0(i1, i2, em::ex2) = HALF * (BDf0(i1, i2, em::bx2) + BDf(i1, i2, em::ex2)); + BDf0(i1, i2, em::ex3) = HALF * (BDf0(i1, i2, em::bx3) + BDf(i1, i2, em::ex3)); + } else { + raise::KernelError( + HERE, + "ComputeAuxH_kernel: 2D implementation called for D != 2"); + } + } + + }; } // namespace kernel::gr #endif // KERNELS_AUX_FIELDS_GR_HPP From 3cac38afd72002ffbcefd533b6ecbfa16f6a6eea Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Mon, 30 Sep 2024 16:26:17 -0400 Subject: [PATCH 064/773] engines/grpic: first half of the main step for field solver --- src/engines/grpic.hpp | 42 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index a75742be2..152b55e66 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -285,15 +285,53 @@ namespace ntt { * em0::B at n-1 */ TimeAverageDB(dom); + /** + * aux::E <- alpha * em0::D + beta x em::B + * + * Now: aux::E at n-1/2 + */ + ComputeAuxE(dom, gr_getE::D0_B); + /** + * aux::E <- boundary conditions + */ + FieldBoundaries(dom, BC::D, gr_bc::aux); + /** + * em0::B <- (em0::B) <- -curl aux::E + * + * Now: em0::B at n + */ + Faraday(dom, gr_faraday::aux, ONE); + + + /** + * em0::B, em::B <- boundary conditions + */ + FieldBoundaries(dom, BC::B, gr_bc::main); + m_metadomain.CommunicateFields(dom, Comm::B | Comm::B0); + + + /** + * aux::H <- alpha * em0::B - beta x em::D + * + * Now: aux::H at n + */ + ComputeAuxH(dom, gr_getH::D_B0); + /** + * aux::H <- boundary conditions + */ + FieldBoundaries(dom, BC::B, gr_bc::aux); } { - + /** + * particle pusher goes here + * + */ } if (fieldsolver_enabled) { - + } } From 386958f46d23341462a45457f1398cf5120f0c73 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Mon, 30 Sep 2024 16:36:45 -0400 Subject: [PATCH 065/773] added TimeAverageJ() and its kernel in kernels/aux --- src/engines/grpic.hpp | 11 ++++++++++- src/kernels/aux_fields_gr.hpp | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index 152b55e66..3a25f5ad2 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -331,7 +331,7 @@ namespace ntt { } if (fieldsolver_enabled) { - + TimeAverageJ(dom); } } @@ -703,6 +703,15 @@ namespace ntt { domain.fields.em0, domain.mesh.metric)); } + + void TimeAverageJ(domain_t& domain) { + auto range = range_with_axis_BCs(domain); + Kokkos::parallel_for("TimeAverageJ", + range, + kernel::gr::TimeAverageJ_kernel(domain.fields.cur, + domain.fields.cur0, + domain.mesh.metric)); + } }; } // namespace ntt diff --git a/src/kernels/aux_fields_gr.hpp b/src/kernels/aux_fields_gr.hpp index 4f87ba1f2..b56a819f9 100644 --- a/src/kernels/aux_fields_gr.hpp +++ b/src/kernels/aux_fields_gr.hpp @@ -266,7 +266,40 @@ namespace kernel::gr { "ComputeAuxH_kernel: 2D implementation called for D != 2"); } } + }; + /** + * @brief Kernel for computing time average of J + * @tparam M Metric + */ + template + class TimeAverageJ_kernel { + static_assert(M::is_metric, "M must be a metric class"); + static constexpr auto D = M::Dim; + + const ndfield_t Jf; + ndfield_t Jf0; + const M metric; + + public: + TimeAverageJ_kernel(const ndfield_t& Jf, + const ndfield_t& Jf0, + const M& metric) + : Jf { Jf } + , Jf0 { Jf0 } + , metric { metric } {} + + Inline void operator()(index_t i1, index_t i2) const { + if constexpr (D == Dim::_2D) { + Jf0(i1, i2, cur::jx1) = HALF * (Jf0(i1, i2, cur::jx1) + Jf(i1, i2, cur::jx1)); + Jf0(i1, i2, cur::jx2) = HALF * (Jf0(i1, i2, cur::jx2) + Jf(i1, i2, cur::jx2)); + Jf0(i1, i2, cur::jx3) = HALF * (Jf0(i1, i2, cur::jx3) + Jf(i1, i2, cur::jx3)); + } else { + raise::KernelError( + HERE, + "ComputeAuxH_kernel: 2D implementation called for D != 2"); + } + } }; } // namespace kernel::gr From 139d179fa5633d27e580214d8652233dedfc4490 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Mon, 30 Sep 2024 16:50:56 -0400 Subject: [PATCH 066/773] engines/grpic: added all steps relevant to field solver --- src/engines/grpic.hpp | 109 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 108 insertions(+), 1 deletion(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index 3a25f5ad2..c35c3f44c 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -331,9 +331,116 @@ namespace ntt { } if (fieldsolver_enabled) { + /** + * cur::J <- (cur0::J + cur::J) / 2 + * + * Now: cur::J at n + */ TimeAverageJ(dom); - } + + /** + * aux::Е <- alpha * em::D + beta x em0::B + * + * Now: aux::Е at n + */ + ComputeAuxE(dom, gr_getE::D_B0); + /** + * aux::Е <- boundary conditions + */ + FieldBoundaries(dom, BC::D, gr_bc::aux); + /** + * em0::B <- (em::B) <- -curl aux::E + * + * Now: em0::B at n+1/2 + * em::B at n-1/2 + */ + Faraday(dom, gr_faraday::main, ONE); + + /** + * em0::B, em::B <- boundary conditions + */ + m_metadomain.CommunicateFields(dom, Comm::B | Comm::B0); + FieldBoundaries(dom, BC::B, gr_bc::main); + + + /** + * em0::D <- (em0::D) <- curl aux::H + * + * Now: em0::D at n+1/2 + */ + Ampere(dom, gr_ampere::aux, ONE); + + + if (deposit_enabled) { + /** + * em0::D <- (em0::D) <- cur::J + * + * Now: em0::D at n+1/2 + */ + // AmpereCurrents(gr_ampere::aux); + } + + /** + * em0::D, em::D <- boundary conditions + */ + m_metadomain.CommunicateFields(dom, Comm::D | Comm::D0); + FieldBoundaries(dom, BC::D, gr_bc::main); + + /** + * aux::H <- alpha * em0::B - beta x em0::D + * + * Now: aux::H at n+1/2 + */ + ComputeAuxH(dom, gr_getH::D0_B0); + /** + * aux::H <- boundary conditions + */ + FieldBoundaries(dom, BC::B, gr_bc::aux); + /** + * em0::D <- (em::D) <- curl aux::H + * + * Now: em0::D at n+1 + * em::D at n + */ + Ampere(dom, gr_ampere::main, ONE); + if (deposit_enabled) { + /** + * em0::D <- (em0::D) <- cur0::J + * + * Now: em0::D at n+1 + */ + // AmpereCurrents(gr_ampere::main); + } + /** + * em::D <-> em0::D + * em::B <-> em0::B + * cur::J <-> cur0::J + */ + SwapFields(dom); + + + /** + * em0::D, em::D <- boundary conditions + */ + m_metadomain.CommunicateFields(dom, Comm::D | Comm::D0); + FieldBoundaries(dom, BC::D, gr_bc::main); + } + /** + * Finally: em0::B at n-1/2 + * em0::D at n + * em::B at n+1/2 + * em::D at n+1 + * + * cur0::J (at n) + * cur::J at n+1/2 + * + * aux::E (at n+1/2) + * aux::H (at n) + * + * x_prtl at n+1 + * u_prtl at n+1/2 + */ } /* algorithm substeps --------------------------------------------------- */ From 52fb48be7905c635a3996af90de66895e99e3ba6 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Mon, 30 Sep 2024 17:09:21 -0400 Subject: [PATCH 067/773] engines/grpic: added function for Ampere currents --- src/engines/grpic.hpp | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index c35c3f44c..60c00b1d9 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -799,6 +799,40 @@ namespace ntt { } else { raise::Error("Wrong option for `g`", HERE); } + } + + void AmpereCurrents(domain_t& domain, const gr_ampere& g) { + logger::Checkpoint("Launching Ampere kernel for adding currents", HERE); + const auto q0 = m_params.template get("scales.q0"); + const auto n0 = m_params.template get("scales.n0"); + const auto B0 = m_params.template get("scales.B0"); + const auto coeff = -dt * q0 * n0 / B0; + auto range = range_with_axis_BCs(domain); + const auto ni2 = domain.mesh.n_active(in::x2); + + if (g == gr_ampere::aux) { + // Updates D0 with J. + Kokkos::parallel_for("Ampere-1", + range, + kernel::gr::CurrentsAmpere_kernel(domain.fields.em0, + domain.fields.cur, + domain.mesh.metric, + coeff, + ni2, + domain.mesh.flds_bc())); + } else if (g == gr_ampere::main) { + // Updates D0 with J0. + Kokkos::parallel_for("Ampere-2", + range, + kernel::gr::CurrentsAmpere_kernel(domain.fields.em0, + domain.fields.cur0, + domain.mesh.metric, + coeff, + ni2, + domain.mesh.flds_bc())); + } else { + raise::Error("Wrong option for `g`", HERE); + } } From 781bd42769cc2a6379ee0e0bc74343bc1e0cbceb Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Mon, 30 Sep 2024 17:14:21 -0400 Subject: [PATCH 068/773] see below -- added call from the time step --- src/engines/grpic.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index 60c00b1d9..d19b87fe4 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -377,7 +377,7 @@ namespace ntt { * * Now: em0::D at n+1/2 */ - // AmpereCurrents(gr_ampere::aux); + AmpereCurrents(dom, gr_ampere::aux); } /** @@ -410,7 +410,7 @@ namespace ntt { * * Now: em0::D at n+1 */ - // AmpereCurrents(gr_ampere::main); + AmpereCurrents(dom, gr_ampere::main); } /** * em::D <-> em0::D From 3615f79af7080536ebc173db5503d0aa211671b1 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Tue, 1 Oct 2024 12:16:48 -0400 Subject: [PATCH 069/773] engines/grpic: started ParticlePush --- src/engines/grpic.hpp | 154 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 152 insertions(+), 2 deletions(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index d19b87fe4..9926756d2 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -324,10 +324,44 @@ namespace ntt { { /** - * particle pusher goes here - * + * x_prtl, u_prtl <- em::D, em0::B + * + * Now: x_prtl at n + 1, u_prtl at n + 1/2 */ + timers.start("ParticlePusher"); + ParticlePush(dom); + timers.stop("ParticlePusher"); + + /** + * cur0::J <- current deposition + * + * Now: cur0::J at n+1/2 + */ + if (deposit_enabled) { + timers.start("CurrentDeposit"); + Kokkos::deep_copy(dom.fields.cur, ZERO); + CurrentsDeposit(dom); + timers.stop("CurrentDeposit"); + + timers.start("Communications"); + m_metadomain.SynchronizeFields(dom, Comm::J); + m_metadomain.CommunicateFields(dom, Comm::J); + timers.stop("Communications"); + + // timers.start("FieldBoundaries"); + // CurrentsBoundaryConditions(); + // timers.stop("FieldBoundaries"); + + timers.start("CurrentFiltering"); + CurrentsFilter(dom); + timers.stop("CurrentFiltering"); + } + timers.start("Communications"); + if ((sort_interval > 0) and (step % sort_interval == 0)) { + m_metadomain.CommunicateParticles(dom, &timers); + } + timers.stop("Communications"); } if (fieldsolver_enabled) { @@ -853,6 +887,122 @@ namespace ntt { domain.fields.cur0, domain.mesh.metric)); } + + void CurrentsDeposit(domain_t& domain) { + auto scatter_cur = Kokkos::Experimental::create_scatter_view( + domain.fields.cur); + for (auto& species : domain.species) { + logger::Checkpoint( + fmt::format("Launching currents deposit kernel for %d [%s] : %lu %f", + species.index(), + species.label().c_str(), + species.npart(), + (double)species.charge()), + HERE); + if (species.npart() == 0 || cmp::AlmostZero(species.charge())) { + continue; + } + Kokkos::parallel_for("CurrentsDeposit", + species.rangeActiveParticles(), + kernel::DepositCurrents_kernel( + scatter_cur, + species.i1, + species.i2, + species.i3, + species.i1_prev, + species.i2_prev, + species.i3_prev, + species.dx1, + species.dx2, + species.dx3, + species.dx1_prev, + species.dx2_prev, + species.dx3_prev, + species.ux1, + species.ux2, + species.ux3, + species.phi, + species.weight, + species.tag, + domain.mesh.metric, + (real_t)(species.charge()), + dt)); + } + Kokkos::Experimental::contribute(domain.fields.cur, scatter_cur); + } + + void CurrentsFilter(domain_t& domain) { + logger::Checkpoint("Launching currents filtering kernels", HERE); + auto range = range_with_axis_BCs(domain); + const auto nfilter = m_params.template get( + "algorithms.current_filters"); + tuple_t size; + if constexpr (M::Dim == Dim::_1D || M::Dim == Dim::_2D || M::Dim == Dim::_3D) { + size[0] = domain.mesh.n_active(in::x1); + } + if constexpr (M::Dim == Dim::_2D || M::Dim == Dim::_3D) { + size[1] = domain.mesh.n_active(in::x2); + } + if constexpr (M::Dim == Dim::_3D) { + size[2] = domain.mesh.n_active(in::x3); + } + // !TODO: this needs to be done more efficiently + for (unsigned short i = 0; i < nfilter; ++i) { + Kokkos::deep_copy(domain.fields.buff, domain.fields.cur); + Kokkos::parallel_for("CurrentsFilter", + range, + kernel::DigitalFilter_kernel( + domain.fields.cur, + domain.fields.buff, + size, + domain.mesh.flds_bc())); + m_metadomain.CommunicateFields(domain, Comm::J); + } + } + + void ParticlePush(domain_t& domain) { + for (auto& species : domain.species) { + species.set_unsorted(); + logger::Checkpoint( + fmt::format("Launching particle pusher kernel for %d [%s] : %lu", + species.index(), + species.label().c_str(), + species.npart()), + HERE); + if (species.npart() == 0) { + continue; + } + const auto q_ovr_m = species.mass() > ZERO + ? species.charge() / species.mass() + : ZERO; + // coeff = q / m (dt / 2) omegaB0 + const auto coeff = q_ovr_m * HALF * dt * + m_params.template get("scales.omegaB0"); + // clang-format off + Kokkos::parallel_for( + "ParticlePusher", + species.rangeActiveParticles(), + kernel::gr::Pusher_kernel( + domain.fields.em, + domain.fields.em0, + species.i1, species.i2, species.i3, + species.i1_prev, species.i2_prev, species.i3_prev, + species.dx1, species.dx2, species.dx3, + species.dx1_prev, species.dx2_prev, species.dx3_prev, + species.ux1, species.ux2, species.ux3, + species.phi, species.tag, + domain.mesh.metric, + coeff, dt, + domain.mesh.n_active(in::x1), + domain.mesh.n_active(in::x2), + domain.mesh.n_active(in::x3), + m_params.template get("algorithms.gr.pusher_eps"), m_params.template get("algorithms.gr.pusher_niter"), + domain.mesh.prtl_bc() + )); + // clang-format on + } + } + }; } // namespace ntt From a3eba30cbac537f83a9e1679f73076eaea2cef3c Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Tue, 1 Oct 2024 12:21:25 -0400 Subject: [PATCH 070/773] see below --- src/engines/grpic.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index 9926756d2..b524fa19b 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -329,7 +329,7 @@ namespace ntt { * Now: x_prtl at n + 1, u_prtl at n + 1/2 */ timers.start("ParticlePusher"); - ParticlePush(dom); + // ParticlePush(dom); timers.stop("ParticlePusher"); /** From 1c6242482125f7797f3b15e14d641284ef173492 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Tue, 1 Oct 2024 12:32:47 -0400 Subject: [PATCH 071/773] engines/grpic: added timers --- src/engines/grpic.hpp | 65 +++++++++++++++++++++++++++++++++++++------ 1 file changed, 56 insertions(+), 9 deletions(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index b524fa19b..1c5d96593 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -277,6 +277,7 @@ namespace ntt { */ if (fieldsolver_enabled) { + timers.start("FieldSolver"); /** * em0::D <- (em0::D + em::D) / 2 * em0::B <- (em0::B + em::B) / 2 @@ -291,35 +292,49 @@ namespace ntt { * Now: aux::E at n-1/2 */ ComputeAuxE(dom, gr_getE::D0_B); + timers.stop("FieldSolver"); + + timers.start("FieldBoundaries"); /** * aux::E <- boundary conditions */ FieldBoundaries(dom, BC::D, gr_bc::aux); + timers.stop("FieldBoundaries"); + + timers.start("FieldSolver"); /** * em0::B <- (em0::B) <- -curl aux::E * * Now: em0::B at n */ Faraday(dom, gr_faraday::aux, ONE); - + timers.stop("FieldSolver"); /** * em0::B, em::B <- boundary conditions */ + timers.start("FieldBoundaries"); FieldBoundaries(dom, BC::B, gr_bc::main); + timers.stop("FieldBoundaries"); + timers.start("Communications"); m_metadomain.CommunicateFields(dom, Comm::B | Comm::B0); + timers.stop("Communications"); - + timers.start("FieldSolver"); /** * aux::H <- alpha * em0::B - beta x em::D * * Now: aux::H at n */ ComputeAuxH(dom, gr_getH::D_B0); + timers.stop("FieldSolver"); + + timers.start("FieldBoundaries"); /** * aux::H <- boundary conditions */ FieldBoundaries(dom, BC::B, gr_bc::aux); + timers.stop("FieldBoundaries"); } { @@ -365,23 +380,29 @@ namespace ntt { } if (fieldsolver_enabled) { + timers.start("FieldSolver"); /** * cur::J <- (cur0::J + cur::J) / 2 * * Now: cur::J at n */ TimeAverageJ(dom); - /** * aux::Е <- alpha * em::D + beta x em0::B * * Now: aux::Е at n */ ComputeAuxE(dom, gr_getE::D_B0); + timers.stop("FieldSolver"); + + timers.start("FieldBoundaries"); /** * aux::Е <- boundary conditions */ FieldBoundaries(dom, BC::D, gr_bc::aux); + timers.stop("FieldBoundaries"); + + timers.start("FieldSolver"); /** * em0::B <- (em::B) <- -curl aux::E * @@ -389,48 +410,65 @@ namespace ntt { * em::B at n-1/2 */ Faraday(dom, gr_faraday::main, ONE); - + timers.stop("FieldSolver"); + /** * em0::B, em::B <- boundary conditions */ + timers.start("Communications"); m_metadomain.CommunicateFields(dom, Comm::B | Comm::B0); + timers.stop("Communications"); + timers.start("FieldBoundaries"); FieldBoundaries(dom, BC::B, gr_bc::main); + timers.stop("FieldBoundaries"); - + timers.start("FieldSolver"); /** * em0::D <- (em0::D) <- curl aux::H * * Now: em0::D at n+1/2 */ Ampere(dom, gr_ampere::aux, ONE); - + timers.stop("FieldSolver"); if (deposit_enabled) { + timers.start("FieldSolver"); /** * em0::D <- (em0::D) <- cur::J * * Now: em0::D at n+1/2 */ AmpereCurrents(dom, gr_ampere::aux); + timers.stop("FieldSolver"); } - + /** * em0::D, em::D <- boundary conditions */ + timers.start("Communications"); m_metadomain.CommunicateFields(dom, Comm::D | Comm::D0); + timers.stop("Communications"); + timers.start("FieldBoundaries"); FieldBoundaries(dom, BC::D, gr_bc::main); - + timers.stop("FieldBoundaries"); + timers.start("FieldSolver"); /** * aux::H <- alpha * em0::B - beta x em0::D * * Now: aux::H at n+1/2 */ ComputeAuxH(dom, gr_getH::D0_B0); + timers.stop("FieldSolver"); + + timers.start("FieldBoundaries"); /** * aux::H <- boundary conditions */ FieldBoundaries(dom, BC::B, gr_bc::aux); + timers.stop("FieldBoundaries"); + + timers.start("FieldSolver"); /** * em0::D <- (em::D) <- curl aux::H * @@ -438,27 +476,36 @@ namespace ntt { * em::D at n */ Ampere(dom, gr_ampere::main, ONE); + timers.stop("FieldSolver"); + if (deposit_enabled) { + timers.start("FieldSolver"); /** * em0::D <- (em0::D) <- cur0::J * * Now: em0::D at n+1 */ AmpereCurrents(dom, gr_ampere::main); + timers.stop("FieldSolver"); } + timers.start("FieldSolver"); /** * em::D <-> em0::D * em::B <-> em0::B * cur::J <-> cur0::J */ SwapFields(dom); - + timers.stop("FieldSolver"); /** * em0::D, em::D <- boundary conditions */ + timers.start("Communications"); m_metadomain.CommunicateFields(dom, Comm::D | Comm::D0); + timers.stop("Communications"); + timers.start("FieldBoundaries"); FieldBoundaries(dom, BC::D, gr_bc::main); + timers.stop("FieldBoundaries"); } /** * Finally: em0::B at n-1/2 From ec795dbb6a25070ac40cd0abead8ff2d5984c775 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Tue, 1 Oct 2024 14:00:57 -0400 Subject: [PATCH 072/773] parameters: changed to requiring n=2 for GRPIC --- src/framework/parameters.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/framework/parameters.cpp b/src/framework/parameters.cpp index 20c7e83d8..e22470b1b 100644 --- a/src/framework/parameters.cpp +++ b/src/framework/parameters.cpp @@ -587,10 +587,10 @@ namespace ntt { prtl_bc_enum.push_back({ PrtlBC::PERIODIC, PrtlBC::PERIODIC }); } } else { - raise::ErrorIf(flds_bc[0].size() != 1, + raise::ErrorIf(flds_bc[0].size() != 2, "invalid `grid.boundaries.fields`", HERE); - raise::ErrorIf(prtl_bc[0].size() != 1, + raise::ErrorIf(prtl_bc[0].size() != 2, "invalid `grid.boundaries.particles`", HERE); flds_bc_enum.push_back( From bcc87d3a1378e20cedff7fe3dbce160dfa6867f1 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Tue, 1 Oct 2024 15:27:17 -0400 Subject: [PATCH 073/773] minor: fixed description for qkerr metric for h_tilde --- src/metrics/qkerr_schild.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/metrics/qkerr_schild.h b/src/metrics/qkerr_schild.h index d531b8b3b..85507c6e1 100644 --- a/src/metrics/qkerr_schild.h +++ b/src/metrics/qkerr_schild.h @@ -265,7 +265,7 @@ namespace metric { } /** - * sqrt(det(h_ij)) + * sqrt(det(h_ij)) divided by sin(theta). * @param x coordinate array in code units */ Inline auto sqrt_det_h_tilde(const coord_t& x) const -> real_t { From 4393c2101041f3d91c6da58afbab38560b6af4d1 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Tue, 1 Oct 2024 17:37:59 -0400 Subject: [PATCH 074/773] parameters: restored !=1 --- src/framework/parameters.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/framework/parameters.cpp b/src/framework/parameters.cpp index e22470b1b..20c7e83d8 100644 --- a/src/framework/parameters.cpp +++ b/src/framework/parameters.cpp @@ -587,10 +587,10 @@ namespace ntt { prtl_bc_enum.push_back({ PrtlBC::PERIODIC, PrtlBC::PERIODIC }); } } else { - raise::ErrorIf(flds_bc[0].size() != 2, + raise::ErrorIf(flds_bc[0].size() != 1, "invalid `grid.boundaries.fields`", HERE); - raise::ErrorIf(prtl_bc[0].size() != 2, + raise::ErrorIf(prtl_bc[0].size() != 1, "invalid `grid.boundaries.particles`", HERE); flds_bc_enum.push_back( From 0b65f557e56cbf2598c131f87cc8c8d9212179be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20B=C3=B6ss?= Date: Wed, 2 Oct 2024 10:10:44 -0500 Subject: [PATCH 075/773] added atmosphere bc to enforce initial magnetic field config at the boundaries --- setups/srpic/shock/pgen.hpp | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/setups/srpic/shock/pgen.hpp b/setups/srpic/shock/pgen.hpp index 1fdd18faa..999a7b608 100644 --- a/setups/srpic/shock/pgen.hpp +++ b/setups/srpic/shock/pgen.hpp @@ -57,9 +57,25 @@ namespace user { return Vx * Bmag * math::sin(Btheta / 180.0 * Kokkos::numbers::pi) * math::sin(Bphi / 180.0 * Kokkos::numbers::pi); } - private: - const real_t Btheta, Bphi, Vx, Bmag; - }; + private: + const real_t Btheta, Bphi, Vx, Bmag; + }; + + template + struct DriveFields : public InitFields { + DriveFields(real_t bmag, real_t btheta, real_t bphi, real_t drift_ux) : + InitFields {bmag, btheta, bphi, drift_ux} {} + + /* Enforce resetting magnetic and electric field at the boundary + This avoids weird */ + using InitFields::bx1; + using InitFields::bx2; + using InitFields::bx3; + + using InitFields::ex1; + using InitFields::ex2; + using InitFields::ex3; + }; template struct PGen : public arch::ProblemGenerator { @@ -91,6 +107,14 @@ namespace user { inline PGen() {} + auto FieldDriver(real_t time) const -> DriveFields { + const real_t bmag = Bmag; + const real_t btheta = Btheta; + const real_t bphi = Bphi; + const real_t ux = drift_ux; + return DriveFields{bmag, btheta, bphi, ux}; + } + inline void InitPrtls(Domain& local_domain) { const auto energy_dist = arch::Maxwellian(local_domain.mesh.metric, local_domain.random_pool, From 31582dc4672a763b2ba3f7ca78b9c58692a6888a Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Wed, 2 Oct 2024 16:42:43 -0400 Subject: [PATCH 076/773] archetypes/field_setter: fixed wrong conversion of theta and call for d() [instead of b] in 3D grpic --- src/archetypes/field_setter.h | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/archetypes/field_setter.h b/src/archetypes/field_setter.h index 281c28df6..171e9f8a8 100644 --- a/src/archetypes/field_setter.h +++ b/src/archetypes/field_setter.h @@ -202,13 +202,13 @@ namespace arch { const real_t x1_0 { metric.template convert<1, Crd::Cd, Crd::Ph>(i1_) }; const real_t x1_H { metric.template convert<1, Crd::Cd, Crd::Ph>( i1_ + HALF) }; - const real_t x2_0 { metric.template convert<1, Crd::Cd, Crd::Ph>(i2_) }; - const real_t x2_H { metric.template convert<1, Crd::Cd, Crd::Ph>( + const real_t x2_0 { metric.template convert<2, Crd::Cd, Crd::Ph>(i2_) }; + const real_t x2_H { metric.template convert<2, Crd::Cd, Crd::Ph>( i2_ + HALF) }; { // bx1 - vec_t b_PU { finit.dx1({ x1_0, x2_H }), - finit.dx2({ x1_0, x2_H }), - finit.dx3({ x1_0, x2_H }) }; + vec_t b_PU { finit.bx1({ x1_0, x2_H }), + finit.bx2({ x1_0, x2_H }), + finit.bx3({ x1_0, x2_H }) }; vec_t b_U { ZERO }; metric.template transform({ i1_, i2_ + HALF }, b_PU, @@ -216,9 +216,9 @@ namespace arch { EM(i1, i2, em::bx1) = b_U[0]; } { // bx2 - vec_t b_PU { finit.dx1({ x1_H, x2_0 }), - finit.dx2({ x1_H, x2_0 }), - finit.dx3({ x1_H, x2_0 }) }; + vec_t b_PU { finit.bx1({ x1_H, x2_0 }), + finit.bx2({ x1_H, x2_0 }), + finit.bx3({ x1_H, x2_0 }) }; vec_t b_U { ZERO }; metric.template transform({ i1_ + HALF, i2_ }, b_PU, @@ -226,9 +226,9 @@ namespace arch { EM(i1, i2, em::bx2) = b_U[1]; } { // bx3 - vec_t b_PU { finit.dx1({ x1_H, x2_H }), - finit.dx2({ x1_H, x2_H }), - finit.dx3({ x1_H, x2_H }) }; + vec_t b_PU { finit.bx1({ x1_H, x2_H }), + finit.bx2({ x1_H, x2_H }), + finit.bx3({ x1_H, x2_H }) }; vec_t b_U { ZERO }; metric.template transform({ i1_ + HALF, i2_ + HALF }, b_PU, From 09014694cc7a72601a5414996c683776d57043e4 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Wed, 2 Oct 2024 17:14:11 -0400 Subject: [PATCH 077/773] kernels/fields_bc: fixed if statement for open BC --- src/kernels/fields_bcs.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/kernels/fields_bcs.hpp b/src/kernels/fields_bcs.hpp index 5a50b6daf..d02bfc485 100644 --- a/src/kernels/fields_bcs.hpp +++ b/src/kernels/fields_bcs.hpp @@ -509,7 +509,7 @@ template Fld(i1_min - 1, i2, em::ex2) = Fld(i1_min , i2, em::ex2); Fld(i1_min , i2, em::ex3) = Fld(i1_min + 1, i2, em::ex3); Fld(i1_min - 1, i2, em::ex3) = Fld(i1_min , i2, em::ex3); - } else if (setB) { + } if (setB) { Fld(i1_min , i2, em::bx1) = Fld(i1_min + 1, i2, em::bx1); Fld(i1_min - 1, i2, em::bx1) = Fld(i1_min , i2, em::bx1); Fld(i1_min - 1, i2, em::bx2) = Fld(i1_min , i2, em::bx2); From f67d40ff8fc37de9d88a3ffedf690ad326894baa Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Wed, 2 Oct 2024 17:46:55 -0400 Subject: [PATCH 078/773] kernels/fields_bc: added a separate kernel for aux fields --- src/kernels/fields_bcs.hpp | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/kernels/fields_bcs.hpp b/src/kernels/fields_bcs.hpp index d02bfc485..441793ac0 100644 --- a/src/kernels/fields_bcs.hpp +++ b/src/kernels/fields_bcs.hpp @@ -523,6 +523,37 @@ template } }; +template + struct OpenBoundariesAux_kernel { + ndfield_t Fld; + const std::size_t i1_min; + const bool setE, setB; + + OpenBoundariesAux_kernel(ndfield_t Fld, std::size_t i1_min, BCTags tags) + : Fld { Fld } + , i1_min { i1_min } + , setE { tags & BC::Ex1 or tags & BC::Ex2 or tags & BC::Ex3 } + , setB { tags & BC::Bx1 or tags & BC::Bx2 or tags & BC::Bx3 } {} + + Inline void operator()(index_t i2) const { + if constexpr (M::Dim == Dim::_2D) { + if (setE) { + Fld(i1_min - 1, i2, em::ex1) = Fld(i1_min , i2, em::ex1); + Fld(i1_min - 1, i2, em::ex2) = Fld(i1_min , i2, em::ex2); + Fld(i1_min - 1, i2, em::ex3) = Fld(i1_min , i2, em::ex3); + } if (setB) { + Fld(i1_min - 1, i2, em::bx1) = Fld(i1_min , i2, em::bx1); + Fld(i1_min - 1, i2, em::bx2) = Fld(i1_min , i2, em::bx2); + Fld(i1_min - 1, i2, em::bx3) = Fld(i1_min , i2, em::bx3); + } + } else { + raise::KernelError( + HERE, + "AbsorbFields_kernel: 2D implementation called for D != 2"); + } + } + }; + } // namespace kernel #endif // KERNELS_FIELDS_BCS_HPP From fd4c61fe4e7aa91db0716848b1a20f80a2ddab8c Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Wed, 2 Oct 2024 17:47:57 -0400 Subject: [PATCH 079/773] see below --- src/engines/grpic.hpp | 30 ++++++------------------------ 1 file changed, 6 insertions(+), 24 deletions(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index 1c5d96593..9c71fe475 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -614,27 +614,6 @@ namespace ntt { xg_edge, ds, tags)); - } else if (dim == in::x2) { - if constexpr (M::Dim == Dim::_2D) { - Kokkos::parallel_for( - "AbsorbFields", - CreateRangePolicy(range_min, range_max), - kernel::AbsorbBoundaries_kernel(domain.fields.em, - domain.mesh.metric, - xg_edge, - ds, - tags)); - Kokkos::parallel_for( - "AbsorbFields", - CreateRangePolicy(range_min, range_max), - kernel::AbsorbBoundaries_kernel(domain.fields.em0, - domain.mesh.metric, - xg_edge, - ds, - tags)); - } else { - raise::Error("Invalid dimension", HERE); - } } else { raise::Error("Invalid dimension", HERE); } @@ -654,10 +633,13 @@ namespace ntt { "Invalid axis direction, should be x2", HERE); const auto i1_min = domain.mesh.i_min(in::x1); + auto range = CreateRangePolicy( + {domain.mesh.i_min(in::x2)}, + {domain.mesh.i_max(in::x2) + 1}); if (g == gr_bc::main) { Kokkos::parallel_for( "OpenBCFields", - domain.mesh.n_all(in::x2), + range, kernel::OpenBoundaries_kernel(domain.fields.em, i1_min, tags)); Kokkos::parallel_for( "OpenBCFields", @@ -666,8 +648,8 @@ namespace ntt { } else if (g == gr_bc::aux) { Kokkos::parallel_for( "OpenBCFields", - domain.mesh.n_all(in::x2), - kernel::OpenBoundaries_kernel(domain.fields.aux, i1_min, tags)); + range, + kernel::OpenBoundariesAux_kernel(domain.fields.aux, i1_min, tags)); } } From bbb272977a0520bb92c679ff791ee89ca3457698 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Wed, 2 Oct 2024 17:51:13 -0400 Subject: [PATCH 080/773] engines/grpic: also changed range for axis BC in this commit and commit below --- src/engines/grpic.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index 9c71fe475..5df9a314a 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -643,7 +643,7 @@ namespace ntt { kernel::OpenBoundaries_kernel(domain.fields.em, i1_min, tags)); Kokkos::parallel_for( "OpenBCFields", - domain.mesh.n_all(in::x2), + range, kernel::OpenBoundaries_kernel(domain.fields.em0, i1_min, tags)); } else if (g == gr_bc::aux) { Kokkos::parallel_for( From 8ef8b7f4c40c401b41a2c61311f403666f4b5ba4 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Wed, 2 Oct 2024 18:04:58 -0400 Subject: [PATCH 081/773] engines/grpic: changed range for axis BC --- src/engines/grpic.hpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index 5df9a314a..74d06a3f9 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -667,23 +667,26 @@ namespace ntt { HERE); const auto i2_min = domain.mesh.i_min(in::x2); const auto i2_max = domain.mesh.i_max(in::x2); + auto range = CreateRangePolicy( + {domain.mesh.i_min(in::x1) - 1}, + {domain.mesh.i_max(in::x1)}); if (direction.get_sign() < 0) { Kokkos::parallel_for( "AxisBCFields", - domain.mesh.n_all(in::x1), + range, kernel::AxisBoundaries_kernel(domain.fields.em, i2_min, tags)); Kokkos::parallel_for( "AxisBCFields", - domain.mesh.n_all(in::x1), + range, kernel::AxisBoundaries_kernel(domain.fields.em0, i2_min, tags)); } else { Kokkos::parallel_for( "AxisBCFields", - domain.mesh.n_all(in::x1), + range, kernel::AxisBoundaries_kernel(domain.fields.em, i2_max, tags)); Kokkos::parallel_for( "AxisBCFields", - domain.mesh.n_all(in::x1), + range, kernel::AxisBoundaries_kernel(domain.fields.em0, i2_max, tags)); } } From 67ad01a88664ef0740ffd4d139a07af5eb889369 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Thu, 3 Oct 2024 18:30:39 -0400 Subject: [PATCH 082/773] updated pgen for wald --- setups/grpic/wald/pgen.hpp | 47 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 45 insertions(+), 2 deletions(-) diff --git a/setups/grpic/wald/pgen.hpp b/setups/grpic/wald/pgen.hpp index 3374a12d7..efb9c78e7 100644 --- a/setups/grpic/wald/pgen.hpp +++ b/setups/grpic/wald/pgen.hpp @@ -4,13 +4,51 @@ #include "enums.h" #include "global.h" +#include "arch/kokkos_aliases.h" #include "arch/traits.h" #include "archetypes/problem_generator.h" +#include "framework/domain/metadomain.h" namespace user { using namespace ntt; + template + struct InitFields { + InitFields() {} + + Inline auto VerticalPotential(const coord_t& x_Ph) const -> real_t { + return HALF * SQR(x_Ph[0]) * SQR(math::sin(x_Ph[1])); + } + + Inline auto bx1(const coord_t& x_Ph) const -> real_t { + return x_Ph[0] * math::cos(x_Ph[1]); + } + + Inline auto bx2(const coord_t& x_Ph) const -> real_t { + return -x_Ph[0] * math::sin(x_Ph[1]); + } + + Inline auto bx3(const coord_t& x_Ph) const -> real_t { + return ZERO; + } + + Inline auto dx1(const coord_t& x_Ph) const -> real_t { + return ZERO; + } + + Inline auto dx2(const coord_t& x_Ph) const -> real_t { + return ZERO; + } + + Inline auto dx3(const coord_t& x_Ph) const -> real_t { + return ZERO; + } + + private: + // const real_t Bsurf, Rstar; + }; + template struct PGen : public arch::ProblemGenerator { // compatibility traits for the problem generator @@ -24,13 +62,18 @@ namespace user { using arch::ProblemGenerator::D; using arch::ProblemGenerator::C; using arch::ProblemGenerator::params; + + InitFields init_flds; - inline PGen(SimulationParams& p, const Metadomain&) : - arch::ProblemGenerator(p) {} + inline PGen(SimulationParams& p, const Metadomain& m) : + arch::ProblemGenerator(p) + // , init_flds { } + {} inline PGen() {} }; + } // namespace user #endif From 731559e2a4539ebe1f254ac3beae45ca5e81b142 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Thu, 3 Oct 2024 19:12:38 -0400 Subject: [PATCH 083/773] engines/grpic: adjusted ranges for all kernels --- src/engines/grpic.hpp | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index 74d06a3f9..40e743766 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -674,20 +674,20 @@ namespace ntt { Kokkos::parallel_for( "AxisBCFields", range, - kernel::AxisBoundaries_kernel(domain.fields.em, i2_min, tags)); + kernel::AxisBoundariesGR_kernel(domain.fields.em, i2_min, tags)); Kokkos::parallel_for( "AxisBCFields", range, - kernel::AxisBoundaries_kernel(domain.fields.em0, i2_min, tags)); + kernel::AxisBoundariesGR_kernel(domain.fields.em0, i2_min, tags)); } else { Kokkos::parallel_for( "AxisBCFields", range, - kernel::AxisBoundaries_kernel(domain.fields.em, i2_max, tags)); + kernel::AxisBoundariesGR_kernel(domain.fields.em, i2_max, tags)); Kokkos::parallel_for( "AxisBCFields", range, - kernel::AxisBoundaries_kernel(domain.fields.em0, i2_max, tags)); + kernel::AxisBoundariesGR_kernel(domain.fields.em0, i2_max, tags)); } } @@ -825,8 +825,8 @@ namespace ntt { "algorithms.timestep.correction") * dt; auto range = CreateRangePolicy( - { domain.mesh.i_min(in::x1), domain.mesh.i_min(in::x2)}, - { domain.mesh.i_max(in::x1), domain.mesh.i_max(in::x2) + 1}); + { domain.mesh.i_min(in::x1), domain.mesh.i_min(in::x2) + 1}, + { domain.mesh.i_max(in::x1), domain.mesh.i_max(in::x2)}); const auto ni2 = domain.mesh.n_active(in::x2); if (g == gr_ampere::aux) { @@ -873,7 +873,10 @@ namespace ntt { const auto n0 = m_params.template get("scales.n0"); const auto B0 = m_params.template get("scales.B0"); const auto coeff = -dt * q0 * n0 / B0; - auto range = range_with_axis_BCs(domain); + // auto range = range_with_axis_BCs(domain); + auto range = CreateRangePolicy( + { domain.mesh.i_min(in::x1), domain.mesh.i_min(in::x2) + 1}, + { domain.mesh.i_max(in::x1), domain.mesh.i_max(in::x2)}); const auto ni2 = domain.mesh.n_active(in::x2); if (g == gr_ampere::aux) { @@ -903,18 +906,16 @@ namespace ntt { } void TimeAverageDB(domain_t& domain) { - auto range = range_with_axis_BCs(domain); Kokkos::parallel_for("TimeAverageDB", - range, + domain.mesh.rangeActiveCells(), kernel::gr::TimeAverageDB_kernel(domain.fields.em, domain.fields.em0, domain.mesh.metric)); } void TimeAverageJ(domain_t& domain) { - auto range = range_with_axis_BCs(domain); Kokkos::parallel_for("TimeAverageJ", - range, + domain.mesh.rangeActiveCells(), kernel::gr::TimeAverageJ_kernel(domain.fields.cur, domain.fields.cur0, domain.mesh.metric)); From 4ea3c9c0e442a032709c0b9b0216147d9f8e09f6 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Thu, 3 Oct 2024 19:13:28 -0400 Subject: [PATCH 084/773] minor changes to kernels/fields_bc gr-specific --- src/kernels/fields_bcs.hpp | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/kernels/fields_bcs.hpp b/src/kernels/fields_bcs.hpp index 441793ac0..fd6ba542f 100644 --- a/src/kernels/fields_bcs.hpp +++ b/src/kernels/fields_bcs.hpp @@ -216,6 +216,29 @@ namespace kernel { } }; + template + struct AxisBoundariesGR_kernel { + ndfield_t Fld; + const std::size_t i_edge; + const bool setE, setB; + + AxisBoundariesGR_kernel(ndfield_t Fld, std::size_t i_edge, BCTags tags) + : Fld { Fld } + , i_edge { i_edge } + , setE { tags & BC::Ex1 or tags & BC::Ex2 or tags & BC::Ex3 } + , setB { tags & BC::Bx1 or tags & BC::Bx2 or tags & BC::Bx3 } {} + + Inline void operator()(index_t i1) const { + if constexpr (D == Dim::_2D) { + if (setB) { + Fld(i1, i_edge, em::bx2) = ZERO; + } + } else { + raise::KernelError(HERE, "AxisBoundaries_kernel: D != 2"); + } + } + }; + template struct AtmosphereBoundaries_kernel { static constexpr Dimension D = M::Dim; From 9b1f59f706dfaed2ba539a817b56197eedd5d3e3 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Fri, 4 Oct 2024 14:50:26 -0400 Subject: [PATCH 085/773] wald: vertical potential setup --- setups/grpic/wald/pgen.hpp | 44 +++++++++++++++++++++++++++----------- 1 file changed, 31 insertions(+), 13 deletions(-) diff --git a/setups/grpic/wald/pgen.hpp b/setups/grpic/wald/pgen.hpp index efb9c78e7..a5f8f503e 100644 --- a/setups/grpic/wald/pgen.hpp +++ b/setups/grpic/wald/pgen.hpp @@ -13,20 +13,40 @@ namespace user { using namespace ntt; - template + template struct InitFields { - InitFields() {} + InitFields(M metric_) : metric { metric_ } {} - Inline auto VerticalPotential(const coord_t& x_Ph) const -> real_t { + Inline auto VerticalPotential(const coord_t& x_Cd) const -> real_t { + coord_t x_Ph { ZERO }; + metric.template convert(x_Cd, x_Ph); return HALF * SQR(x_Ph[0]) * SQR(math::sin(x_Ph[1])); } Inline auto bx1(const coord_t& x_Ph) const -> real_t { - return x_Ph[0] * math::cos(x_Ph[1]); + coord_t xi {ZERO}, x0m { ZERO }, x0p { ZERO }; + metric.template convert(x_Ph, xi); + + x0m[0] = xi[0]; + x0m[1] = xi[1] - HALF; + x0p[0] = xi[0]; + x0p[1] = xi[1] + HALF; + + real_t inv_sqrt_detH_ijP { ONE / metric.sqrt_det_h({ xi[0], xi[1] }) }; + return (VerticalPotential(x0p) - VerticalPotential(x0m)) * inv_sqrt_detH_ijP; } Inline auto bx2(const coord_t& x_Ph) const -> real_t { - return -x_Ph[0] * math::sin(x_Ph[1]); + coord_t xi {ZERO}, x0m { ZERO }, x0p { ZERO }; + metric.template convert(x_Ph, xi); + + x0m[0] = xi[0] + HALF - HALF; + x0m[1] = xi[1]; + x0p[0] = xi[0] + HALF + HALF; + x0p[1] = xi[1]; + + real_t inv_sqrt_detH_ijP { ONE / metric.sqrt_det_h({ xi[0], xi[1] }) }; + return -(VerticalPotential(x0p) - VerticalPotential(x0m)) * inv_sqrt_detH_ijP; } Inline auto bx3(const coord_t& x_Ph) const -> real_t { @@ -46,7 +66,7 @@ namespace user { } private: - // const real_t Bsurf, Rstar; + const M metric; }; template @@ -62,18 +82,16 @@ namespace user { using arch::ProblemGenerator::D; using arch::ProblemGenerator::C; using arch::ProblemGenerator::params; - - InitFields init_flds; - inline PGen(SimulationParams& p, const Metadomain& m) : - arch::ProblemGenerator(p) - // , init_flds { } - {} + InitFields init_flds; + + inline PGen(SimulationParams& p, const Metadomain& m) + : arch::ProblemGenerator(p) + , init_flds { m.mesh().metric } {} inline PGen() {} }; - } // namespace user #endif From fca070fe6cd7f21c981cf5fbf745eef4c2e7f37a Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Fri, 4 Oct 2024 18:25:02 -0400 Subject: [PATCH 086/773] kernel/ampere_gr: bug for theta=0 --- src/kernels/ampere_gr.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/kernels/ampere_gr.hpp b/src/kernels/ampere_gr.hpp index 045eb1729..46b950796 100644 --- a/src/kernels/ampere_gr.hpp +++ b/src/kernels/ampere_gr.hpp @@ -74,6 +74,8 @@ namespace kernel::gr { if ((i2 == i2min) && is_axis_i2min) { // theta = 0 const real_t inv_polar_area_pH { ONE / metric.polar_area(i1_ + HALF) }; + const real_t inv_sqrt_detH_0pH { ONE / + metric.sqrt_det_h({ i1_, HALF }) }; Dout(i1, i2, em::dx1) = Din(i1, i2, em::dx1) + inv_polar_area_pH * coeff * H(i1, i2, em::hx3); Dout(i1, i2, em::dx2) = Din(i1, i2, em::dx2) + From 2a2a12f755ef333c66cd77fd4093b0f766bc3d14 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Fri, 4 Oct 2024 18:47:18 -0400 Subject: [PATCH 087/773] kernels/faraday_gr: bug at i2min --- src/kernels/faraday_gr.hpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/kernels/faraday_gr.hpp b/src/kernels/faraday_gr.hpp index 19eede5f2..5f6e5590b 100644 --- a/src/kernels/faraday_gr.hpp +++ b/src/kernels/faraday_gr.hpp @@ -73,7 +73,9 @@ namespace kernel::gr { Bout(i1, i2, em::bx1) = Bin(i1, i2, em::bx1) + coeff * inv_sqrt_detH_0pH * (E(i1, i2, em::ex3) - E(i1, i2 + 1, em::ex3)); - if ((i2 != i2min) || !is_axis_i2min) { + if ((i2 == i2min) && is_axis_i2min) { + Bout(i1, i2, em::bx2) = ZERO; + } else { const real_t inv_sqrt_detH_pH0 { ONE / metric.sqrt_det_h( { i1_ + HALF, i2_ }) }; Bout(i1, i2, em::bx2) = Bin(i1, i2, em::bx2) + From 2acf70bd850f1f59b858a4d05cc5b5230919f06e Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Fri, 4 Oct 2024 19:03:04 -0400 Subject: [PATCH 088/773] kernels/aux: bugs in time averaging --- src/kernels/aux_fields_gr.hpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/kernels/aux_fields_gr.hpp b/src/kernels/aux_fields_gr.hpp index b56a819f9..c739cffbd 100644 --- a/src/kernels/aux_fields_gr.hpp +++ b/src/kernels/aux_fields_gr.hpp @@ -257,9 +257,9 @@ namespace kernel::gr { BDf0(i1, i2, em::bx1) = HALF * (BDf0(i1, i2, em::bx1) + BDf(i1, i2, em::bx1)); BDf0(i1, i2, em::bx2) = HALF * (BDf0(i1, i2, em::bx2) + BDf(i1, i2, em::bx2)); BDf0(i1, i2, em::bx3) = HALF * (BDf0(i1, i2, em::bx3) + BDf(i1, i2, em::bx3)); - BDf0(i1, i2, em::ex1) = HALF * (BDf0(i1, i2, em::bx1) + BDf(i1, i2, em::ex1)); - BDf0(i1, i2, em::ex2) = HALF * (BDf0(i1, i2, em::bx2) + BDf(i1, i2, em::ex2)); - BDf0(i1, i2, em::ex3) = HALF * (BDf0(i1, i2, em::bx3) + BDf(i1, i2, em::ex3)); + BDf0(i1, i2, em::ex1) = HALF * (BDf0(i1, i2, em::ex1) + BDf(i1, i2, em::ex1)); + BDf0(i1, i2, em::ex2) = HALF * (BDf0(i1, i2, em::ex2) + BDf(i1, i2, em::ex2)); + BDf0(i1, i2, em::ex3) = HALF * (BDf0(i1, i2, em::ex3) + BDf(i1, i2, em::ex3)); } else { raise::KernelError( HERE, @@ -291,9 +291,9 @@ namespace kernel::gr { Inline void operator()(index_t i1, index_t i2) const { if constexpr (D == Dim::_2D) { - Jf0(i1, i2, cur::jx1) = HALF * (Jf0(i1, i2, cur::jx1) + Jf(i1, i2, cur::jx1)); - Jf0(i1, i2, cur::jx2) = HALF * (Jf0(i1, i2, cur::jx2) + Jf(i1, i2, cur::jx2)); - Jf0(i1, i2, cur::jx3) = HALF * (Jf0(i1, i2, cur::jx3) + Jf(i1, i2, cur::jx3)); + Jf(i1, i2, cur::jx1) = HALF * (Jf0(i1, i2, cur::jx1) + Jf(i1, i2, cur::jx1)); + Jf(i1, i2, cur::jx2) = HALF * (Jf0(i1, i2, cur::jx2) + Jf(i1, i2, cur::jx2)); + Jf(i1, i2, cur::jx3) = HALF * (Jf0(i1, i2, cur::jx3) + Jf(i1, i2, cur::jx3)); } else { raise::KernelError( HERE, From 1656da322b73545c5433576671112b5a2ce02257 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Fri, 4 Oct 2024 20:13:52 -0400 Subject: [PATCH 089/773] metric: kerr-schild a=0 minor fixes --- src/metrics/kerr_schild_0.h | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/metrics/kerr_schild_0.h b/src/metrics/kerr_schild_0.h index 70689f4f0..31080ed4c 100644 --- a/src/metrics/kerr_schild_0.h +++ b/src/metrics/kerr_schild_0.h @@ -36,6 +36,7 @@ namespace metric { private: const real_t dr, dtheta, dphi; const real_t dr_inv, dtheta_inv, dphi_inv; + const real_t a, rg_, rh_; public: static constexpr const char* Label { "kerr_schild_0" }; @@ -57,6 +58,9 @@ namespace metric { boundaries_t ext, const std::map& = {}) : MetricBase { res, ext } + , a { ZERO } + , rg_ { ONE } + , rh_ { TWO } , dr { (x1_max - x1_min) / nx1 } , dtheta { (x2_max - x2_min) / nx2 } , dphi { (x3_max - x3_min) / nx3 } @@ -70,17 +74,17 @@ namespace metric { [[nodiscard]] Inline auto spin() const -> const real_t& { - return ZERO; + return a; } [[nodiscard]] Inline auto rhorizon() const -> const real_t& { - return ZERO; + return rh_; } [[nodiscard]] Inline auto rg() const -> const real_t& { - return ZERO; + return rg_; } /** From 237294e73823c7bff64da6049fe206385f2a2f56 Mon Sep 17 00:00:00 2001 From: hayk Date: Mon, 14 Oct 2024 10:59:24 -0400 Subject: [PATCH 090/773] added test for plaw in all metrics --- .../framework/utils/particle_injectors.hpp | 16 +- src/archetypes/energy_dist.h | 75 ++++---- src/archetypes/particle_injector.h | 2 +- src/archetypes/spatial_dist.h | 20 +- src/archetypes/tests/CMakeLists.txt | 3 +- src/archetypes/tests/powerlaw.cpp | 171 ++++++++++++++++++ 6 files changed, 231 insertions(+), 56 deletions(-) create mode 100644 src/archetypes/tests/powerlaw.cpp diff --git a/legacy/src/framework/utils/particle_injectors.hpp b/legacy/src/framework/utils/particle_injectors.hpp index 21e3dad72..c275f170a 100644 --- a/legacy/src/framework/utils/particle_injectors.hpp +++ b/legacy/src/framework/utils/particle_injectors.hpp @@ -165,7 +165,7 @@ namespace ntt { * @brief Volumetrically uniform particle injector parallelized over particles. * @tparam D dimension. * @tparam S simulation engine. - * @tparam EnDist energy distribution [default = ColdDist]. + * @tparam EnDist energy distribution [default = Cold]. * * @param params simulation parameters. * @param mblock meshblock. @@ -174,7 +174,7 @@ namespace ntt { * @param region region to inject particles as a list of coordinates [optional]. * @param time current time [optional]. */ - template class EnDist = ColdDist> + template class EnDist = Cold> inline void InjectUniform(const SimulationParams& params, Meshblock& mblock, const std::vector& species, @@ -613,8 +613,8 @@ namespace ntt { * @brief Particle injector parallelized by cells in a volume. * @tparam D dimension. * @tparam S simulation engine. - * @tparam EnDist energy distribution [default = ColdDist]. - * @tparam SpDist spatial distribution [default = UniformDist]. + * @tparam EnDist energy distribution [default = Cold]. + * @tparam SpDist spatial distribution [default = Uniform]. * @tparam InjCrit injection criterion [default = NoCriterion]. * * @param params simulation parameters. @@ -626,8 +626,8 @@ namespace ntt { */ template class EnDist = ColdDist, - template class SpDist = UniformDist, + template class EnDist = Cold, + template class SpDist = Uniform, template class InjCrit = NoCriterion> inline void InjectInVolume(const SimulationParams& params, Meshblock& mblock, @@ -928,7 +928,7 @@ namespace ntt { * @brief ... up to certain number density. * @tparam D dimension. * @tparam S simulation engine. - * @tparam EnDist energy distribution [default = ColdDist]. + * @tparam EnDist energy distribution [default = Cold]. * @tparam InjCrit injection criterion [default = NoCriterion]. * * @param params simulation parameters. @@ -940,7 +940,7 @@ namespace ntt { */ template class EnDist = ColdDist, + template class EnDist = Cold, template class InjCrit = NoCriterion> inline void InjectNonUniform(const SimulationParams& params, Meshblock& mblock, diff --git a/src/archetypes/energy_dist.h b/src/archetypes/energy_dist.h index e2e53493d..e9bc9051a 100644 --- a/src/archetypes/energy_dist.h +++ b/src/archetypes/energy_dist.h @@ -3,8 +3,8 @@ * @brief Defines an archetype for energy distributions * @implements * - arch::EnergyDistribution<> - * - arch::ColdDist<> : arch::EnergyDistribution<> - * - arch::PowerlawDist<> : arch::EnergyDistribution<> + * - arch::Cold<> : arch::EnergyDistribution<> + * - arch::Powerlaw<> : arch::EnergyDistribution<> * - arch::Maxwellian<> : arch::EnergyDistribution<> * @namespaces: * - arch:: @@ -56,8 +56,8 @@ namespace arch { }; template - struct ColdDist : public EnergyDistribution { - ColdDist(const M& metric) : EnergyDistribution { metric } {} + struct Cold : public EnergyDistribution { + Cold(const M& metric) : EnergyDistribution { metric } {} Inline void operator()(const coord_t&, vec_t& v, @@ -69,41 +69,44 @@ namespace arch { }; template - struct PowerlawDist : public EnergyDistribution { - using EnergyDistribution::metric; - - PowerlawDist(const M& metric, - random_number_pool_t& pool, - real_t g_min, - real_t g_max, - real_t pl_ind ) - : EnergyDistribution { metric } - , pool { pool } - , g_min { g_min } - , g_max { g_max } - , pl_ind { pl_ind } {} + struct Powerlaw : public EnergyDistribution { + using EnergyDistribution::metric; + Powerlaw(const M& metric, + random_number_pool_t& pool, + real_t g_min, + real_t g_max, + real_t pl_ind) + : EnergyDistribution { metric } + , pool { pool } + , g_min { g_min } + , g_max { g_max } + , pl_ind { pl_ind } {} Inline void operator()(const coord_t& x_Code, vec_t& v, - unsigned short sp) const override { - auto rand_gen = pool.get_state(); - auto rand_X1 = Random(rand_gen); - auto rand_gam = ONE; + unsigned short sp = 0) const override { + auto rand_gen = pool.get_state(); + auto rand_X1 = Random(rand_gen); + auto rand_gam = ONE; - // Power-law distribution from uniform distribution (see https://mathworld.wolfram.com/RandomNumber.html) - if (pl_ind != -1.0) { - rand_gam += math::pow(math::pow(g_min,ONE + pl_ind) + (-math::pow(g_min,ONE + pl_ind) + math::pow(g_max,ONE + pl_ind))*rand_X1,ONE/(ONE + pl_ind)); - } else { - rand_gam += math::pow(g_min,ONE - rand_X1)*math::pow(g_max,rand_X1); - } - auto rand_u = math::sqrt( SQR(rand_gam) - ONE ); - auto rand_X2 = Random(rand_gen); - auto rand_X3 = Random(rand_gen); - v[0] = rand_u * (TWO * rand_X2 - ONE); - v[2] = TWO * rand_u * math::sqrt(rand_X2 * (ONE - rand_X2)); - v[1] = v[2] * math::cos(constant::TWO_PI * rand_X3); - v[2] = v[2] * math::sin(constant::TWO_PI * rand_X3); + // Power-law distribution from uniform (see https://mathworld.wolfram.com/RandomNumber.html) + if (pl_ind != -ONE) { + rand_gam += math::pow( + math::pow(g_min, ONE + pl_ind) + + (-math::pow(g_min, ONE + pl_ind) + math::pow(g_max, ONE + pl_ind)) * + rand_X1, + ONE / (ONE + pl_ind)); + } else { + rand_gam += math::pow(g_min, ONE - rand_X1) * math::pow(g_max, rand_X1); + } + auto rand_u = math::sqrt(SQR(rand_gam) - ONE); + auto rand_X2 = Random(rand_gen); + auto rand_X3 = Random(rand_gen); + v[0] = rand_u * (TWO * rand_X2 - ONE); + v[2] = TWO * rand_u * math::sqrt(rand_X2 * (ONE - rand_X2)); + v[1] = v[2] * math::cos(constant::TWO_PI * rand_X3); + v[2] = v[2] * math::sin(constant::TWO_PI * rand_X3); if constexpr (S == SimEngine::GRPIC) { // convert from the tetrad basis to covariant @@ -114,11 +117,11 @@ namespace arch { metric.template transform(x_Code, v_Hat, v); } - pool.free_state(rand_gen); + pool.free_state(rand_gen); } private: - const real_t g_min, g_max, pl_ind; + const real_t g_min, g_max, pl_ind; random_number_pool_t pool; }; diff --git a/src/archetypes/particle_injector.h b/src/archetypes/particle_injector.h index 4e75003bb..cbcbbd389 100644 --- a/src/archetypes/particle_injector.h +++ b/src/archetypes/particle_injector.h @@ -142,7 +142,7 @@ namespace arch { }; using energy_dist_t = Maxwellian; - using spatial_dist_t = ReplenishDist; + using spatial_dist_t = Replenish; static_assert(M::is_metric, "M must be a metric class"); static constexpr bool is_nonuniform_injector { true }; static constexpr Dimension D { M::Dim }; diff --git a/src/archetypes/spatial_dist.h b/src/archetypes/spatial_dist.h index 6c19d44d0..be2836da2 100644 --- a/src/archetypes/spatial_dist.h +++ b/src/archetypes/spatial_dist.h @@ -3,8 +3,8 @@ * @brief Spatial distribution class passed to injectors * @implements * - arch::SpatialDistribution<> - * - arch::UniformDist<> : arch::SpatialDistribution<> - * - arch::ReplenishDist<> : arch::SpatialDistribution<> + * - arch::Uniform<> : arch::SpatialDistribution<> + * - arch::Replenish<> : arch::SpatialDistribution<> * @namespace * - arch:: * @note @@ -41,8 +41,8 @@ namespace arch { }; template - struct UniformDist : public SpatialDistribution { - UniformDist(const M& metric) : SpatialDistribution { metric } {} + struct Uniform : public SpatialDistribution { + Uniform(const M& metric) : SpatialDistribution { metric } {} Inline auto operator()(const coord_t&) const -> real_t override { return ONE; @@ -50,7 +50,7 @@ namespace arch { }; template - struct ReplenishDist : public SpatialDistribution { + struct Replenish : public SpatialDistribution { using SpatialDistribution::metric; const ndfield_t density; const unsigned short idx; @@ -58,11 +58,11 @@ namespace arch { const T target_density; const real_t target_max_density; - ReplenishDist(const M& metric, - const ndfield_t& density, - unsigned short idx, - const T& target_density, - real_t target_max_density) + Replenish(const M& metric, + const ndfield_t& density, + unsigned short idx, + const T& target_density, + real_t target_max_density) : SpatialDistribution { metric } , density { density } , idx { idx } diff --git a/src/archetypes/tests/CMakeLists.txt b/src/archetypes/tests/CMakeLists.txt index ceee1edc9..4ffc35322 100644 --- a/src/archetypes/tests/CMakeLists.txt +++ b/src/archetypes/tests/CMakeLists.txt @@ -22,4 +22,5 @@ endfunction() gen_test(energy_dist) gen_test(spatial_dist) -gen_test(field_setter) \ No newline at end of file +gen_test(field_setter) +gen_test(powerlaw) diff --git a/src/archetypes/tests/powerlaw.cpp b/src/archetypes/tests/powerlaw.cpp new file mode 100644 index 000000000..dfcb6b247 --- /dev/null +++ b/src/archetypes/tests/powerlaw.cpp @@ -0,0 +1,171 @@ +#include "enums.h" +#include "global.h" + +#include "utils/error.h" + +#include "metrics/kerr_schild.h" +#include "metrics/kerr_schild_0.h" +#include "metrics/minkowski.h" +#include "metrics/qkerr_schild.h" +#include "metrics/qspherical.h" +#include "metrics/spherical.h" + +#include "archetypes/energy_dist.h" + +#include + +#include + +using namespace ntt; +using namespace metric; +using namespace arch; + +template +struct Caller { + static constexpr auto D = M::Dim; + + Caller(const M& metric, const EnrgDist& dist) + : metric { metric } + , dist { dist } {} + + Inline void operator()(index_t) const { + vec_t vp { ZERO }; + coord_t xp { ZERO }; + for (unsigned short d = 0; d < D; ++d) { + xp[d] = 2.0; + } + dist(xp, vp); + if (not Kokkos::isfinite(vp[0]) or not Kokkos::isfinite(vp[1]) or + not Kokkos::isfinite(vp[2])) { + raise::KernelError(HERE, "Non-finite velocity generated"); + } + if constexpr (S == SimEngine::SRPIC) { + const auto gamma = math::sqrt(ONE + SQR(vp[0]) + SQR(vp[1]) + SQR(vp[2])); + if (gamma < 10 or gamma > 1000) { + raise::KernelError(HERE, "Gamma out of bounds"); + } + } else { + vec_t vup { ZERO }; + metric.template transform(xp, vp, vup); + const auto gamma = math::sqrt( + ONE + vup[0] * vp[0] + vup[1] * vp[1] + vup[2] * vp[2]); + if (gamma < 10 or gamma > 1000) { + raise::KernelError(HERE, "Gamma out of bounds"); + } + } + } + +private: + M metric; + EnrgDist dist; +}; + +template +void testEnergyDist(const std::vector& res, + const boundaries_t& ext, + const std::map& params = {}) { + raise::ErrorIf(res.size() != M::Dim, "res.size() != M::Dim", HERE); + + boundaries_t extent; + if constexpr (M::CoordType == Coord::Cart) { + extent = ext; + } else { + if constexpr (M::Dim == Dim::_2D) { + extent = { + ext[0], + {ZERO, constant::PI} + }; + } else if constexpr (M::Dim == Dim::_3D) { + extent = { + ext[0], + {ZERO, constant::PI}, + {ZERO, constant::TWO_PI} + }; + } + } + raise::ErrorIf(extent.size() != M::Dim, "extent.size() != M::Dim", HERE); + + M metric { res, extent, params }; + + random_number_pool_t pool { constant::RandomSeed }; + Powerlaw plaw { metric, + pool, + static_cast(10), + static_cast(1000), + static_cast(-2.5) }; + Kokkos::parallel_for("Powerlaw", 100, Caller, S, M>(metric, plaw)); +} + +auto main(int argc, char* argv[]) -> int { + Kokkos::initialize(argc, argv); + + try { + using namespace ntt; + testEnergyDist>( + { + 10 + }, + { { 0.0, 55.0 } }); + + testEnergyDist>( + { + 10, + 10 + }, + { { 0.0, 55.0 }, { 0.0, 55.0 } }); + + testEnergyDist>( + { + 10, + 10, + 10 + }, + { { 0.0, 55.0 }, { 0.0, 55.0 }, { 0.0, 55.0 } }); + + testEnergyDist>( + { + 10, + 10 + }, + { { 1.0, 100.0 } }); + + testEnergyDist>( + { + 10, + 10 + }, + { { 1.0, 100.0 } }, + { { "r0", 0.0 }, { "h", 0.25 } }); + + testEnergyDist>( + { + 10, + 10 + }, + { { 1.0, 100.0 } }, + { { "a", 0.9 } }); + + testEnergyDist>( + { + 10, + 10 + }, + { { 1.0, 100.0 } }, + { { "r0", 0.0 }, { "h", 0.25 }, { "a", 0.9 } }); + + testEnergyDist>( + { + 10, + 10 + }, + { { 1.0, 100.0 } }, + { { "a", 0.9 } }); + + } catch (std::exception& e) { + std::cerr << e.what() << std::endl; + Kokkos::finalize(); + return 1; + } + Kokkos::finalize(); + return 0; +} From a03c0da25bf9945448ca55d96dc459d61b276b3d Mon Sep 17 00:00:00 2001 From: hayk Date: Mon, 14 Oct 2024 11:39:35 -0400 Subject: [PATCH 091/773] runner cuda upd --- dev/runners/Dockerfile.runner.cuda | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/dev/runners/Dockerfile.runner.cuda b/dev/runners/Dockerfile.runner.cuda index 4ff132990..6e0b0755c 100644 --- a/dev/runners/Dockerfile.runner.cuda +++ b/dev/runners/Dockerfile.runner.cuda @@ -59,14 +59,17 @@ ARG HOME=/home/$USER WORKDIR $HOME # gh runner +ARG RUNNER_VERSION=2.317.0 RUN mkdir actions-runner WORKDIR $HOME/actions-runner -RUN --mount=type=secret,id=ghtoken \ - curl -o actions-runner-linux-x64-2.317.0.tar.gz \ - -L https://github.com/actions/runner/releases/download/v2.317.0/actions-runner-linux-x64-2.317.0.tar.gz && \ - tar xzf ./actions-runner-linux-x64-2.317.0.tar.gz && \ - sudo ./bin/installdependencies.sh && \ - ./config.sh --url https://github.com/entity-toolkit/entity --token "$(sudo cat /run/secrets/ghtoken)" --labels nvidia-gpu +RUN curl -o actions-runner-linux-x64-${RUNNER_VERSION}.tar.gz \ + -L https://github.com/actions/runner/releases/download/v${RUNNER_VERSION}/actions-runner-linux-x64-${RUNNER_VERSION}.tar.gz && \ + tar xzf ./actions-runner-linux-x64-${RUNNER_VERSION}.tar.gz && \ + sudo ./bin/installdependencies.sh -ENTRYPOINT ["./run.sh"] +ADD start.sh start.sh +RUN sudo chown $USER:$USER start.sh && \ + sudo chmod +x start.sh + +ENTRYPOINT ["./start.sh"] From 4f2c6567489144ef0ef2eb74a1479c8bb75a3275 Mon Sep 17 00:00:00 2001 From: hayk Date: Mon, 14 Oct 2024 11:40:00 -0400 Subject: [PATCH 092/773] version reverse to 1.2.0 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2152ebcf2..2260323a3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,7 +5,7 @@ set(PROJECT_NAME entity) project( ${PROJECT_NAME} - VERSION 1.1.1 + VERSION 1.2.0 LANGUAGES CXX C) add_compile_options("-D ENTITY_VERSION=\"${PROJECT_VERSION}\"") execute_process(COMMAND From 3949af9f29fd9b2a9703859b3adf2483dd904aaf Mon Sep 17 00:00:00 2001 From: hayk Date: Thu, 8 Aug 2024 20:40:23 -0400 Subject: [PATCH 093/773] restructure adios to add checkpoints --- input.example.toml | 17 ++++++++++++ src/engines/engine.hpp | 43 +++++++++++------------------ src/engines/engine_init.cpp | 5 ++-- src/framework/domain/metadomain.cpp | 13 ++------- src/framework/domain/metadomain.h | 17 +++++------- src/framework/domain/output.cpp | 4 ++- src/framework/parameters.cpp | 8 ++++++ src/global/defaults.h | 5 ++++ src/output/writer.cpp | 19 ++++++++++--- src/output/writer.h | 24 ++++++++-------- 10 files changed, 88 insertions(+), 67 deletions(-) diff --git a/input.example.toml b/input.example.toml index 88589495c..eacb7f402 100644 --- a/input.example.toml +++ b/input.example.toml @@ -422,6 +422,23 @@ # @default: false ghosts = "" +[checkpoint] + # Number of timesteps between checkpoints: + # @type: unsigned int: > 0 + # @default: 1000 + interval = "" + # Physical (code) time interval between checkpoints: + # @type: float: > 0 + # @default: -1.0 (disabled) + # @note: When `interval_time` < 0, the output is controlled by `interval`, otherwise by `interval_time` + interval_time = "" + # Number of checkpoints to keep: + # @type: unsigned int: > 0 + # @default: 2 + # @note: 0 = disable checkpointing + # @note: -1 = keep all checkpoints + keep = "" + [diagnostics] # Number of timesteps between diagnostic logs: # @type: int: > 0 diff --git a/src/engines/engine.hpp b/src/engines/engine.hpp index a57b52d19..03d2da859 100644 --- a/src/engines/engine.hpp +++ b/src/engines/engine.hpp @@ -34,6 +34,15 @@ #include +#if defined(OUTPUT_ENABLED) + #include + #include +#endif // OUTPUT_ENABLED + +#if defined(MPI_ENABLED) + #include +#endif // MPI_ENABLED + #include #include @@ -45,6 +54,12 @@ namespace ntt { static_assert(user::PGen::is_pgen, "unrecognized problem generator"); protected: +#if MPI_ENABLED + adios2::ADIOS m_adios { MPI_COMM_WORLD }; +#else + adios2::ADIOS m_adios; +#endif + SimulationParams& m_params; Metadomain m_metadomain; user::PGen m_pgen; @@ -65,29 +80,6 @@ namespace ntt { static constexpr Dimension D { M::Dim }; static constexpr bool is_engine { true }; -#if defined(OUTPUT_ENABLED) - Engine(SimulationParams& params) - : m_params { params } - , m_metadomain { params.get("simulation.domain.number"), - params.get>( - "simulation.domain.decomposition"), - params.get>("grid.resolution"), - params.get>("grid.extent"), - params.get>( - "grid.boundaries.fields"), - params.get>( - "grid.boundaries.particles"), - params.get>( - "grid.metric.params"), - params.get>( - "particles.species"), - params.template get("output.format") } - , m_pgen { m_params, m_metadomain } - , runtime { params.get("simulation.runtime") } - , dt { params.get("algorithms.timestep.dt") } - , max_steps { static_cast(runtime / dt) } - -#else // not OUTPUT_ENABLED Engine(SimulationParams& params) : m_params { params } , m_metadomain { params.get("simulation.domain.number"), @@ -106,10 +98,7 @@ namespace ntt { , m_pgen { m_params, m_metadomain } , runtime { params.get("simulation.runtime") } , dt { params.get("algorithms.timestep.dt") } - , max_steps { static_cast(runtime / dt) } -#endif - { - + , max_steps { static_cast(runtime / dt) } { raise::ErrorIf(not pgen_is_ok, "Problem generator is not compatible with the picked engine/metric/dimension", HERE); print_report(); } diff --git a/src/engines/engine_init.cpp b/src/engines/engine_init.cpp index abb8754d9..71900a406 100644 --- a/src/engines/engine_init.cpp +++ b/src/engines/engine_init.cpp @@ -11,6 +11,7 @@ #include "metrics/spherical.h" #include "archetypes/field_setter.h" + #include "engines/engine.hpp" #include @@ -21,7 +22,7 @@ namespace ntt { void Engine::init() { if constexpr (pgen_is_ok) { #if defined(OUTPUT_ENABLED) - m_metadomain.InitWriter(m_params); + m_metadomain.InitWriter(&m_adios, m_params); #endif logger::Checkpoint("Initializing Engine", HERE); if constexpr ( @@ -55,4 +56,4 @@ namespace ntt { template class Engine>; template class Engine>; template class Engine>; -} // namespace ntt \ No newline at end of file +} // namespace ntt diff --git a/src/framework/domain/metadomain.cpp b/src/framework/domain/metadomain.cpp index b13475fd6..cdc9e5a3d 100644 --- a/src/framework/domain/metadomain.cpp +++ b/src/framework/domain/metadomain.cpp @@ -37,21 +37,12 @@ namespace ntt { const boundaries_t& global_flds_bc, const boundaries_t& global_prtl_bc, const std::map& metric_params, - const std::vector& species_params -#if defined(OUTPUT_ENABLED) - , - const std::string& output_engine -#endif - ) + const std::vector& species_params) : g_ndomains { global_ndomains } , g_decomposition { global_decomposition } , g_mesh { global_ncells, global_extent, metric_params, global_flds_bc, global_prtl_bc } , g_metric_params { metric_params } - , g_species_params { species_params } -#if defined(OUTPUT_ENABLED) - , g_writer { output_engine } -#endif - { + , g_species_params { species_params } { #if defined(MPI_ENABLED) MPI_Comm_size(MPI_COMM_WORLD, &g_mpi_size); MPI_Comm_rank(MPI_COMM_WORLD, &g_mpi_rank); diff --git a/src/framework/domain/metadomain.h b/src/framework/domain/metadomain.h index fb81fcfca..f7444c582 100644 --- a/src/framework/domain/metadomain.h +++ b/src/framework/domain/metadomain.h @@ -30,9 +30,12 @@ #include #endif // MPI_ENABLED -#if defined OUTPUT_ENABLED +#if defined(OUTPUT_ENABLED) #include "output/writer.h" -#endif + + #include + #include +#endif // OUTPUT_ENABLED #include #include @@ -95,7 +98,6 @@ namespace ntt { * @param global_prtl_bc boundary conditions for particles * @param metric_params parameters for the metric * @param species_params parameters for the particle species - * @param output_params parameters for the output */ Metadomain(unsigned int, const std::vector&, @@ -104,15 +106,10 @@ namespace ntt { const boundaries_t&, const boundaries_t&, const std::map&, - const std::vector& -#if defined(OUTPUT_ENABLED) - , - const std::string& -#endif - ); + const std::vector&); #if defined(OUTPUT_ENABLED) - void InitWriter(const SimulationParams&); + void InitWriter(adios2::ADIOS*, const SimulationParams&); auto Write(const SimulationParams&, std::size_t, long double, diff --git a/src/framework/domain/output.cpp b/src/framework/domain/output.cpp index be154ce16..36960816f 100644 --- a/src/framework/domain/output.cpp +++ b/src/framework/domain/output.cpp @@ -37,7 +37,8 @@ namespace ntt { template - void Metadomain::InitWriter(const SimulationParams& params) { + void Metadomain::InitWriter(adios2::ADIOS* ptr_adios, + const SimulationParams& params) { raise::ErrorIf( local_subdomain_indices().size() != 1, "Output for now is only supported for one subdomain per rank", @@ -61,6 +62,7 @@ namespace ntt { } } + g_writer.init(ptr_adios, params.template get("output.format")); g_writer.defineMeshLayout(glob_shape_with_ghosts, off_ncells_with_ghosts, loc_shape_with_ghosts, diff --git a/src/framework/parameters.cpp b/src/framework/parameters.cpp index 20c7e83d8..65ff6a994 100644 --- a/src/framework/parameters.cpp +++ b/src/framework/parameters.cpp @@ -471,6 +471,14 @@ namespace ntt { set("output.debug.ghosts", toml::find_or(raw_data, "output", "debug", "ghosts", false)); + /* [checkpoint] --------------------------------------------------------- */ + set("checkpoint.interval", + toml::find_or(raw_data, "checkpoint", "interval", defaults::checkpoint::interval)); + set("checkpoint.interval_time", + toml::find_or(raw_data, "checkpoint", "interval_time", -1.0)); + set("checkpoint.keep", + toml::find_or(raw_data, "checkpoint", "keep", defaults::checkpoint::keep)); + /* [diagnostics] -------------------------------------------------------- */ set("diagnostics.interval", toml::find_or(raw_data, "diagnostics", "interval", defaults::diag::interval)); diff --git a/src/global/defaults.h b/src/global/defaults.h index d238a3492..fb874481e 100644 --- a/src/global/defaults.h +++ b/src/global/defaults.h @@ -60,6 +60,11 @@ namespace ntt::defaults { const std::size_t spec_nbins = 200; } // namespace output + namespace checkpoint { + const std::size_t interval = 1000; + const std::size_t keep = 2; + } // namespace checkpoint + namespace diag { const std::size_t interval = 1; } // namespace diag diff --git a/src/output/writer.cpp b/src/output/writer.cpp index 91bf596a8..6be195794 100644 --- a/src/output/writer.cpp +++ b/src/output/writer.cpp @@ -19,8 +19,11 @@ namespace out { - Writer::Writer(const std::string& engine) : m_engine { engine } { - m_io = m_adios.DeclareIO("Entity::ADIOS2"); + void Writer::init(adios2::ADIOS* ptr_adios, const std::string& engine) { + m_engine = engine; + p_adios = ptr_adios; + + m_io = p_adios->DeclareIO("Entity::ADIOS2"); m_io.SetEngine(engine); m_io.DefineVariable("Step"); @@ -291,7 +294,11 @@ namespace out { void Writer::beginWriting(const std::string& fname, std::size_t tstep, long double time) { - m_adios.ExitComputationBlock(); + p_adios->ExitComputationBlock(); + if (m_writing_mode) { + raise::Fatal("Already writing", HERE); + } + m_writing_mode = true; try { m_writer = m_io.Open(fname + (m_engine == "hdf5" ? ".h5" : ".bp"), m_mode); } catch (std::exception& e) { @@ -304,9 +311,13 @@ namespace out { } void Writer::endWriting() { + if (!m_writing_mode) { + raise::Fatal("Not writing", HERE); + } + m_writing_mode = false; m_writer.EndStep(); m_writer.Close(); - m_adios.EnterComputationBlock(); + p_adios->EnterComputationBlock(); } template void Writer::writeField(const std::vector&, diff --git a/src/output/writer.h b/src/output/writer.h index 517a1655d..c8170c6b3 100644 --- a/src/output/writer.h +++ b/src/output/writer.h @@ -60,23 +60,20 @@ namespace out { }; class Writer { -#if !defined(MPI_ENABLED) - adios2::ADIOS m_adios; -#else // MPI_ENABLED - adios2::ADIOS m_adios { MPI_COMM_WORLD }; -#endif + adios2::ADIOS* p_adios { nullptr }; + adios2::IO m_io; adios2::Engine m_writer; adios2::Mode m_mode { adios2::Mode::Write }; // global shape of the fields array to output - adios2::Dims m_flds_g_shape; + adios2::Dims m_flds_g_shape; // local corner of the fields array to output - adios2::Dims m_flds_l_corner; + adios2::Dims m_flds_l_corner; // local shape of the fields array to output - adios2::Dims m_flds_l_shape; - bool m_flds_ghosts; - const std::string m_engine; + adios2::Dims m_flds_l_shape; + bool m_flds_ghosts; + std::string m_engine; std::map m_trackers; @@ -84,14 +81,17 @@ namespace out { std::vector m_prtl_writers; std::vector m_spectra_writers; + bool m_writing_mode { false }; + public: - Writer() : m_engine { "disabled" } {} + Writer() {} - Writer(const std::string& engine); ~Writer() = default; Writer(Writer&&) = default; + void init(adios2::ADIOS*, const std::string&); + void addTracker(const std::string&, std::size_t, long double); auto shouldWrite(const std::string&, std::size_t, long double) -> bool; From 377fa0a5c8993935d70568700a543dea69cf17e9 Mon Sep 17 00:00:00 2001 From: hayk Date: Thu, 8 Aug 2024 20:50:29 -0400 Subject: [PATCH 094/773] bug in writer test --- src/output/tests/writer-mpi.cpp | 5 ++++- src/output/tests/writer-nompi.cpp | 10 ++++++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/output/tests/writer-mpi.cpp b/src/output/tests/writer-mpi.cpp index 72cf46e35..649590b49 100644 --- a/src/output/tests/writer-mpi.cpp +++ b/src/output/tests/writer-mpi.cpp @@ -32,7 +32,10 @@ auto main(int argc, char* argv[]) -> int { try { using namespace ntt; - auto writer = out::Writer("hdf5"); + + adios2::ADIOS adios { MPI_COMM_WORLD }; + auto writer = out::Writer(); + writer.init(&adios, "hdf5"); writer.defineMeshLayout({ static_cast(size) * 10 }, { static_cast(rank) * 10 }, { 10 }, diff --git a/src/output/tests/writer-nompi.cpp b/src/output/tests/writer-nompi.cpp index a2a116e65..e8e6facb7 100644 --- a/src/output/tests/writer-nompi.cpp +++ b/src/output/tests/writer-nompi.cpp @@ -26,10 +26,16 @@ auto main(int argc, char* argv[]) -> int { Kokkos::initialize(argc, argv); try { + adios2::ADIOS adios; using namespace ntt; - auto writer = out::Writer("hdf5"); - writer.defineMeshLayout({ 10, 10, 10 }, { 0, 0, 0 }, { 10, 10, 10 }, false, Coord::Cart); + auto writer = out::Writer(); + writer.init(&adios, "hdf5"); + writer.defineMeshLayout({ 10, 10, 10 }, + { 0, 0, 0 }, + { 10, 10, 10 }, + false, + Coord::Cart); writer.defineFieldOutputs(SimEngine::SRPIC, { "E", "B", "Rho_1_3", "N_2" }); ndfield_t field { "fld", From c8e809d2cb586bef636dda2e7c611eaa5d9a0c6f Mon Sep 17 00:00:00 2001 From: hayk Date: Sat, 10 Aug 2024 01:41:39 -0400 Subject: [PATCH 095/773] preliminary checkpoint framework --- .clang-format | 2 + .gitignore | 2 + CMakeLists.txt | 2 - extern/Kokkos | 2 +- extern/adios2 | 2 +- extern/toml11 | 2 +- src/CMakeLists.txt | 8 +- src/checkpoint/CMakeLists.txt | 29 + src/checkpoint/writer.cpp | 103 + src/checkpoint/writer.h | 62 + src/engines/CMakeLists.txt | 1 + src/engines/engine.hpp | 34 +- src/engines/engine_init.cpp | 1 + src/engines/engine_run.cpp | 16 +- src/engines/engine_step_report.cpp | 60 +- src/engines/grpic.hpp | 6 +- src/engines/srpic.hpp | 3 +- src/framework/CMakeLists.txt | 6 +- src/framework/domain/checkpoint.cpp | 60 + src/framework/domain/metadomain.h | 16 +- src/framework/parameters.cpp | 24 +- src/framework/parameters.h | 13 +- src/framework/simulation.cpp | 24 +- src/framework/simulation.h | 15 +- src/framework/tests/parameters.cpp | 2 +- src/global/CMakeLists.txt | 6 +- src/global/defaults.h | 2 +- src/global/global.h | 23 +- src/global/utils/param_container.cpp | 333 + src/global/utils/param_container.h | 9 + src/global/utils/timer.h | 34 +- src/global/utils/toml.h | 17972 +++++++++++++++++++++++++ src/global/utils/tools.h | 57 +- src/output/CMakeLists.txt | 1 - src/output/write_attrs.cpp | 136 - src/output/writer.cpp | 23 +- src/output/writer.h | 36 +- 37 files changed, 18813 insertions(+), 314 deletions(-) create mode 100644 src/checkpoint/CMakeLists.txt create mode 100644 src/checkpoint/writer.cpp create mode 100644 src/checkpoint/writer.h create mode 100644 src/framework/domain/checkpoint.cpp create mode 100644 src/global/utils/param_container.cpp create mode 100644 src/global/utils/toml.h delete mode 100644 src/output/write_attrs.cpp diff --git a/.clang-format b/.clang-format index ed150af9b..b3bb8d132 100644 --- a/.clang-format +++ b/.clang-format @@ -106,6 +106,8 @@ IncludeCategories: Priority: 4 - Regex: '^"engines\/.*\.h"' Priority: 4 + - Regex: '^"checkpoint\/.*\.h"' + Priority: 4 - Regex: '^"output\/.*\.h"' Priority: 4 - Regex: '^"archetypes\/.*\.h"' diff --git a/.gitignore b/.gitignore index 20bfe33a3..53d09b648 100644 --- a/.gitignore +++ b/.gitignore @@ -54,3 +54,5 @@ Testing/ .schema.json *_old/ action-token +*.vim +ignore-* diff --git a/CMakeLists.txt b/CMakeLists.txt index 2260323a3..62319559b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -82,10 +82,8 @@ include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/dependencies.cmake) find_or_fetch_dependency(Kokkos FALSE) find_or_fetch_dependency(plog TRUE) -find_or_fetch_dependency(toml11 TRUE) set(DEPENDENCIES Kokkos::kokkos) include_directories(${plog_SRC}/include) -include_directories(${toml11_SRC}) # -------------------------------- Main code ------------------------------- # set_precision(${precision}) diff --git a/extern/Kokkos b/extern/Kokkos index eb11070f6..5fc08a9a7 160000 --- a/extern/Kokkos +++ b/extern/Kokkos @@ -1 +1 @@ -Subproject commit eb11070f67565b2e660659f5207f0363bdf3b882 +Subproject commit 5fc08a9a7da14d8530f8c7035d008ef63ddb4e5c diff --git a/extern/adios2 b/extern/adios2 index b8761e2af..e524dce1b 160000 --- a/extern/adios2 +++ b/extern/adios2 @@ -1 +1 @@ -Subproject commit b8761e2afab2cd05b89d09b2ee4da1cd7a834225 +Subproject commit e524dce1b72ccf75422cea6342ee2d64a6a87964 diff --git a/extern/toml11 b/extern/toml11 index 12c0f379f..9b914db23 160000 --- a/extern/toml11 +++ b/extern/toml11 @@ -1 +1 @@ -Subproject commit 12c0f379f2e865b4ce984758d5ae004f9de07d69 +Subproject commit 9b914db23df4acb6f1885fee29e07e9af959251e diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5d7f0abb4..d75094c2b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -7,6 +7,7 @@ # - ntt_framework [required] # - ntt_metrics [required] # - ntt_engine [required] +# - ntt_pgen [required] # @uses: # - kokkos [required] # - plog [required] @@ -30,9 +31,12 @@ add_subdirectory(${SRC_DIR}/kernels ${CMAKE_CURRENT_BINARY_DIR}/kernels) add_subdirectory(${SRC_DIR}/archetypes ${CMAKE_CURRENT_BINARY_DIR}/archetypes) add_subdirectory(${SRC_DIR}/framework ${CMAKE_CURRENT_BINARY_DIR}/framework) add_subdirectory(${SRC_DIR}/engines ${CMAKE_CURRENT_BINARY_DIR}/engines) -if (${output} STREQUAL "ON") -add_subdirectory(${SRC_DIR}/output ${CMAKE_CURRENT_BINARY_DIR}/output) + +if (${output}) + add_subdirectory(${SRC_DIR}/output ${CMAKE_CURRENT_BINARY_DIR}/output) + add_subdirectory(${SRC_DIR}/checkpoint ${CMAKE_CURRENT_BINARY_DIR}/checkpoint) endif() + add_subdirectory(${SRC_DIR}/../setups ${CMAKE_CURRENT_BINARY_DIR}/setups) set(libs ntt_global ntt_framework ntt_metrics ntt_engines ntt_pgen) diff --git a/src/checkpoint/CMakeLists.txt b/src/checkpoint/CMakeLists.txt new file mode 100644 index 000000000..00c11ac04 --- /dev/null +++ b/src/checkpoint/CMakeLists.txt @@ -0,0 +1,29 @@ +# ------------------------------ +# @defines: ntt_checkpoint [STATIC/SHARED] +# @sources: +# - writer.cpp +# @includes: +# - ../ +# @depends: +# - ntt_global [required] +# @uses: +# - kokkos [required] +# - ADIOS2 [required] +# - mpi [optional] +# ------------------------------ + +set(SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}) +set(SOURCES + ${SRC_DIR}/writer.cpp +) +add_library(ntt_checkpoint ${SOURCES}) + +set(libs ntt_global) +add_dependencies(ntt_checkpoint ${libs}) +target_link_libraries(ntt_checkpoint PUBLIC ${libs}) +target_link_libraries(ntt_checkpoint PRIVATE stdc++fs) + +target_include_directories(ntt_checkpoint + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../ + INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/../ +) diff --git a/src/checkpoint/writer.cpp b/src/checkpoint/writer.cpp new file mode 100644 index 000000000..e56f59b36 --- /dev/null +++ b/src/checkpoint/writer.cpp @@ -0,0 +1,103 @@ +#include "checkpoint/writer.h" + +#include "global.h" + +#include "utils/error.h" +#include "utils/formatting.h" +#include "utils/log.h" + +#include "framework/parameters.h" + +#include +#include + +#include +#include +#include +#include +#include + +namespace checkpoint { + + void Writer::init(adios2::ADIOS* ptr_adios, + std::size_t interval, + long double interval_time, + int keep) { + m_keep = keep; + m_enabled = keep != 0; + if (!m_enabled) { + return; + } + m_tracker.init("checkpoint", interval, interval_time); + p_adios = ptr_adios; + raise::ErrorIf(p_adios == nullptr, "ADIOS pointer is null", HERE); + + m_io = p_adios->DeclareIO("Entity::Checkpoint"); + m_io.SetEngine("BPFile"); + + m_io.DefineVariable("Step"); + m_io.DefineVariable("Time"); + m_io.DefineAttribute("NGhosts", ntt::N_GHOSTS); + + const std::filesystem::path save_path { "checkpoints" }; + if (!std::filesystem::exists(save_path)) { + std::filesystem::create_directory(save_path); + } + p_adios->EnterComputationBlock(); + } + + auto Writer::shouldSave(std::size_t step, long double time) -> bool { + return m_enabled and m_tracker.shouldWrite(step, time); + } + + void Writer::beginSaving(const ntt::SimulationParams& params, + std::size_t step, + long double time) { + raise::ErrorIf(!m_enabled, "Checkpoint is not enabled", HERE); + raise::ErrorIf(p_adios == nullptr, "ADIOS pointer is null", HERE); + p_adios->ExitComputationBlock(); + if (m_writing_mode) { + raise::Fatal("Already writing", HERE); + } + m_writing_mode = true; + try { + auto fname = fmt::format("checkpoints/step-%08lu.bp", step); + m_writer = m_io.Open(fname, adios2::Mode::Write); + m_written.push_back(fname); + } catch (std::exception& e) { + raise::Fatal(e.what(), HERE); + } + + // write the metadata + std::ofstream metadata; + metadata.open(fmt::format("checkpoints/meta-%08lu.toml", step).c_str()); + metadata << params.data() << std::endl; + metadata.close(); + + m_writer.BeginStep(); + m_writer.Put(m_io.InquireVariable("Step"), &step); + m_writer.Put(m_io.InquireVariable("Time"), &time); + } + + void Writer::endSaving() { + raise::ErrorIf(p_adios == nullptr, "ADIOS pointer is null", HERE); + if (!m_writing_mode) { + raise::Fatal("Not writing", HERE); + } + m_writing_mode = false; + m_writer.EndStep(); + m_writer.Close(); + p_adios->EnterComputationBlock(); + + // optionally remove the oldest checkpoint + if (m_keep > 0 and m_written.size() > (std::size_t)m_keep) { + const auto oldest = m_written.front(); + if (std::filesystem::exists(oldest)) { + std::filesystem::remove_all(oldest); + m_written.erase(m_written.begin()); + } else { + raise::Warning("Checkpoint file does not exist for some reason", HERE); + } + } + } +} // namespace checkpoint diff --git a/src/checkpoint/writer.h b/src/checkpoint/writer.h new file mode 100644 index 000000000..ec2fa08d8 --- /dev/null +++ b/src/checkpoint/writer.h @@ -0,0 +1,62 @@ +/** + * @file checkpoint/writer.h + * @brief Class that dumps checkpoints + * @implements + * - checkpoint::Writer + * @cpp: + * - writer.cpp + * @namespaces: + * - save:: + */ + +#ifndef CHECKPOINT_WRITER_H +#define CHECKPOINT_WRITER_H + +#include "global.h" + +#include "utils/tools.h" + +#include "framework/parameters.h" + +#include +#include + +#include + +namespace checkpoint { + + class Writer { + adios2::ADIOS* p_adios { nullptr }; + + adios2::IO m_io; + adios2::Engine m_writer; + + tools::Tracker m_tracker {}; + + bool m_writing_mode { false }; + + std::vector m_written; + + int m_keep; + bool m_enabled; + + public: + Writer() {} + + ~Writer() = default; + + void init(adios2::ADIOS*, std::size_t, long double, int); + + auto shouldSave(std::size_t, long double) -> bool; + + void beginSaving(const ntt::SimulationParams&, std::size_t, long double); + void endSaving(); + + auto enabled() const -> bool { + return m_enabled; + } + }; + +} // namespace checkpoint + +#endif // CHECKPOINT_WRITER_H diff --git a/src/engines/CMakeLists.txt b/src/engines/CMakeLists.txt index 2cc61a265..c91475eb7 100644 --- a/src/engines/CMakeLists.txt +++ b/src/engines/CMakeLists.txt @@ -18,6 +18,7 @@ # @uses: # - kokkos [required] # - plog [required] +# - toml11 [required] # - adios2 [optional] # - hdf5 [optional] # - mpi [optional] diff --git a/src/engines/engine.hpp b/src/engines/engine.hpp index 03d2da859..a2bb09c26 100644 --- a/src/engines/engine.hpp +++ b/src/engines/engine.hpp @@ -25,6 +25,7 @@ #include "utils/error.h" #include "utils/progressbar.h" #include "utils/timer.h" +#include "utils/toml.h" #include "framework/containers/species.h" #include "framework/domain/metadomain.h" @@ -60,9 +61,9 @@ namespace ntt { adios2::ADIOS m_adios; #endif - SimulationParams& m_params; - Metadomain m_metadomain; - user::PGen m_pgen; + SimulationParams m_params; + Metadomain m_metadomain; + user::PGen m_pgen; const long double runtime; const real_t dt; @@ -80,24 +81,25 @@ namespace ntt { static constexpr Dimension D { M::Dim }; static constexpr bool is_engine { true }; - Engine(SimulationParams& params) - : m_params { params } - , m_metadomain { params.get("simulation.domain.number"), - params.get>( + Engine(const toml::value& raw_params) + : m_params { raw_params } + , m_metadomain { m_params.get("simulation.domain.number"), + m_params.get>( "simulation.domain.decomposition"), - params.get>("grid.resolution"), - params.get>("grid.extent"), - params.get>( + m_params.get>( + "grid.resolution"), + m_params.get>("grid.extent"), + m_params.get>( "grid.boundaries.fields"), - params.get>( + m_params.get>( "grid.boundaries.particles"), - params.get>( + m_params.get>( "grid.metric.params"), - params.get>( + m_params.get>( "particles.species") } , m_pgen { m_params, m_metadomain } - , runtime { params.get("simulation.runtime") } - , dt { params.get("algorithms.timestep.dt") } + , runtime { m_params.get("simulation.runtime") } + , dt { m_params.get("algorithms.timestep.dt") } , max_steps { static_cast(runtime / dt) } { raise::ErrorIf(not pgen_is_ok, "Problem generator is not compatible with the picked engine/metric/dimension", HERE); print_report(); @@ -107,7 +109,7 @@ namespace ntt { void init(); void print_report() const; - void print_step_report(timer::Timers&, pbar::DurationHistory&, bool, bool) const; + void print_step_report(timer::Timers&, pbar::DurationHistory&, bool, bool, bool) const; virtual void step_forward(timer::Timers&, Domain&) = 0; diff --git a/src/engines/engine_init.cpp b/src/engines/engine_init.cpp index 71900a406..926bb3f78 100644 --- a/src/engines/engine_init.cpp +++ b/src/engines/engine_init.cpp @@ -23,6 +23,7 @@ namespace ntt { if constexpr (pgen_is_ok) { #if defined(OUTPUT_ENABLED) m_metadomain.InitWriter(&m_adios, m_params); + m_metadomain.InitCheckpointWriter(&m_adios, m_params); #endif logger::Checkpoint("Initializing Engine", HERE); if constexpr ( diff --git a/src/engines/engine_run.cpp b/src/engines/engine_run.cpp index 4485e0e40..e5c8d8647 100644 --- a/src/engines/engine_run.cpp +++ b/src/engines/engine_run.cpp @@ -26,7 +26,8 @@ namespace ntt { "ParticlePusher", "FieldBoundaries", "ParticleBoundaries", "Communications", "Injector", "Sorting", - "Custom", "Output" }, + "Custom", "Output", + "Checkpoint" }, []() { Kokkos::fence(); }, @@ -60,7 +61,8 @@ namespace ntt { ++step; time += dt; - auto print_output = false; + auto print_output = false; + auto print_checkpoint = false; #if defined(OUTPUT_ENABLED) timers.start("Output"); if constexpr ( @@ -79,13 +81,21 @@ namespace ntt { print_output = m_metadomain.Write(m_params, step, time); } timers.stop("Output"); + + timers.start("Checkpoint"); + print_checkpoint = m_metadomain.WriteCheckpoint(m_params, step, time); + timers.stop("Checkpoint"); #endif // advance time_history time_history.tick(); // print final timestep report if (diag_interval > 0 and step % diag_interval == 0) { - print_step_report(timers, time_history, print_output, print_sorting); + print_step_report(timers, + time_history, + print_output, + print_checkpoint, + print_sorting); } timers.resetAll(); } diff --git a/src/engines/engine_step_report.cpp b/src/engines/engine_step_report.cpp index f2a35bb82..7edeaab67 100644 --- a/src/engines/engine_step_report.cpp +++ b/src/engines/engine_step_report.cpp @@ -32,6 +32,7 @@ namespace ntt { void Engine::print_step_report(timer::Timers& timers, pbar::DurationHistory& time_history, bool print_output, + bool print_checkpoint, bool print_sorting) const { DiagFlags diag_flags = Diag::Default; TimerFlags timer_flags = Timer::Default; @@ -45,6 +46,9 @@ namespace ntt { if (print_output) { timer_flags |= Timer::PrintOutput; } + if (print_checkpoint) { + timer_flags |= Timer::PrintCheckpoint; + } if (print_sorting) { timer_flags |= Timer::PrintSorting; } @@ -235,59 +239,3 @@ namespace ntt { template class Engine>; template class Engine>; } // namespace ntt - -// template -// auto Simulation::PrintDiagnostics(const std::size_t& step, -// const real_t& time, -// const timer::Timers& timers, -// std::vector& tstep_durations, -// const DiagFlags diag_flags, -// std::ostream& os) -> void { -// if (tstep_durations.size() > m_params.diagMaxnForPbar()) { -// tstep_durations.erase(tstep_durations.begin()); -// } -// tstep_durations.push_back(timers.get("Total")); -// if (step % m_params.diagInterval() == 0) { -// auto& mblock = this->meshblock; -// const auto title { -// fmt::format("Time = %f : step = %d : Δt = %f", time, step, mblock.timestep()) -// }; -// PrintOnce( -// [](std::ostream& os, std::string title) { -// os << title << std::endl; -// }, -// os, -// title); -// if (diag_flags & DiagFlags_Timers) { -// timers.printAll("", timer::TimerFlags_Default, os); -// } -// if (diag_flags & DiagFlags_Species) { -// auto header = fmt::format("%s %27s", "[SPECIES]", "[TOT]"); -// #if defined(MPI_ENABLED) -// header += fmt::format("%17s %s", "[MIN (%) :", "MAX (%)]"); -// #endif -// PrintOnce( -// [](std::ostream& os, std::string header) { -// os << header << std::endl; -// }, -// os, -// header); -// for (const auto& species : meshblock.particles) { -// species.PrintParticleCounts(os); -// } -// } -// if (diag_flags & DiagFlags_Progress) { -// PrintOnce( -// [](std::ostream& os) { -// os << std::setw(65) << std::setfill('-') << "" << std::endl; -// }, -// os); -// ProgressBar(tstep_durations, time, m_params.totalRuntime(), os); -// } -// PrintOnce( -// [](std::ostream& os) { -// os << std::setw(65) << std::setfill('=') << "" << std::endl; -// }, -// os); -// } -// } diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index 148c1c5c5..a20fc2a86 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -15,6 +15,7 @@ #include "enums.h" #include "utils/timer.h" +#include "utils/toml.h" #include "framework/domain/domain.h" @@ -24,14 +25,15 @@ namespace ntt { template class GRPICEngine : public Engine { + using base_t = Engine; + using Engine::m_params; using Engine::m_metadomain; public: static constexpr auto S { SimEngine::SRPIC }; - GRPICEngine(SimulationParams& params) - : Engine { params } {} + GRPICEngine(const toml::value& raw_data) : base_t { raw_data } {} ~GRPICEngine() = default; diff --git a/src/engines/srpic.hpp b/src/engines/srpic.hpp index bddc557c9..6f1a0d561 100644 --- a/src/engines/srpic.hpp +++ b/src/engines/srpic.hpp @@ -21,6 +21,7 @@ #include "utils/log.h" #include "utils/numeric.h" #include "utils/timer.h" +#include "utils/toml.h" #include "archetypes/particle_injector.h" #include "framework/domain/domain.h" @@ -70,7 +71,7 @@ namespace ntt { public: static constexpr auto S { SimEngine::SRPIC }; - SRPICEngine(SimulationParams& params) : base_t { params } {} + SRPICEngine(const toml::value& raw_data) : base_t { raw_data } {} ~SRPICEngine() = default; diff --git a/src/framework/CMakeLists.txt b/src/framework/CMakeLists.txt index c7c3ba8a1..8bfbf1430 100644 --- a/src/framework/CMakeLists.txt +++ b/src/framework/CMakeLists.txt @@ -6,6 +6,7 @@ # - domain/grid.cpp # - domain/metadomain.cpp # - domain/communications.cpp +# - domain/checkpoint.cpp # - containers/particles.cpp # - containers/fields.cpp # - domain/output.cpp @@ -31,17 +32,20 @@ set(SOURCES ${SRC_DIR}/domain/grid.cpp ${SRC_DIR}/domain/metadomain.cpp ${SRC_DIR}/domain/communications.cpp + ${SRC_DIR}/domain/checkpoint.cpp ${SRC_DIR}/containers/particles.cpp ${SRC_DIR}/containers/fields.cpp ) if (${output}) list(APPEND SOURCES ${SRC_DIR}/domain/output.cpp) + list(APPEND SOURCES ${SRC_DIR}/domain/checkpoint.cpp) endif() add_library(ntt_framework ${SOURCES}) set(libs ntt_global ntt_metrics ntt_kernels) if(${output}) list(APPEND libs ntt_output) + list(APPEND libs ntt_checkpoint) endif() add_dependencies(ntt_framework ${libs}) target_link_libraries(ntt_framework PUBLIC ${libs}) @@ -49,4 +53,4 @@ target_link_libraries(ntt_framework PUBLIC ${libs}) target_include_directories(ntt_framework PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../ INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/../ -) \ No newline at end of file +) diff --git a/src/framework/domain/checkpoint.cpp b/src/framework/domain/checkpoint.cpp new file mode 100644 index 000000000..3295e9430 --- /dev/null +++ b/src/framework/domain/checkpoint.cpp @@ -0,0 +1,60 @@ +#include "enums.h" +#include "global.h" + +#include "utils/error.h" + +#include "metrics/kerr_schild.h" +#include "metrics/kerr_schild_0.h" +#include "metrics/minkowski.h" +#include "metrics/qkerr_schild.h" +#include "metrics/qspherical.h" +#include "metrics/spherical.h" + +#include "checkpoint/writer.h" +#include "framework/domain/metadomain.h" +#include "framework/parameters.h" + +namespace ntt { + + template + void Metadomain::InitCheckpointWriter(adios2::ADIOS* ptr_adios, + const SimulationParams& params) { + raise::ErrorIf( + local_subdomain_indices().size() != 1, + "Checkpoint writing for now is only supported for one subdomain per rank", + HERE); + auto local_domain = subdomain_ptr(local_subdomain_indices()[0]); + raise::ErrorIf(local_domain->is_placeholder(), + "local_domain is a placeholder", + HERE); + + g_checkpoint_writer.init( + ptr_adios, + params.template get("checkpoint.interval"), + params.template get("checkpoint.interval_time"), + params.template get("checkpoint.keep")); + } + + template + auto Metadomain::WriteCheckpoint(const SimulationParams& params, + std::size_t step, + long double time) -> bool { + if (!g_checkpoint_writer.shouldSave(step, time)) { + return false; + } + logger::Checkpoint("Writing checkpoint", HERE); + g_checkpoint_writer.beginSaving(params, step, time); + g_checkpoint_writer.endSaving(); + return true; + } + + template struct Metadomain>; + template struct Metadomain>; + template struct Metadomain>; + template struct Metadomain>; + template struct Metadomain>; + template struct Metadomain>; + template struct Metadomain>; + template struct Metadomain>; + +} // namespace ntt diff --git a/src/framework/domain/metadomain.h b/src/framework/domain/metadomain.h index f7444c582..072a4183f 100644 --- a/src/framework/domain/metadomain.h +++ b/src/framework/domain/metadomain.h @@ -21,6 +21,7 @@ #include "arch/kokkos_aliases.h" #include "utils/timer.h" +#include "checkpoint/writer.h" #include "framework/containers/species.h" #include "framework/domain/domain.h" #include "framework/domain/mesh.h" @@ -108,6 +109,11 @@ namespace ntt { const std::map&, const std::vector&); + Metadomain(const Metadomain&) = delete; + Metadomain& operator=(const Metadomain&) = delete; + + ~Metadomain() = default; + #if defined(OUTPUT_ENABLED) void InitWriter(adios2::ADIOS*, const SimulationParams&); auto Write(const SimulationParams&, @@ -117,13 +123,10 @@ namespace ntt { ndfield_t&, std::size_t, const Domain&)> = {}) -> bool; + void InitCheckpointWriter(adios2::ADIOS*, const SimulationParams&); + auto WriteCheckpoint(const SimulationParams&, std::size_t, long double) -> bool; #endif - Metadomain(const Metadomain&) = delete; - Metadomain& operator=(const Metadomain&) = delete; - - ~Metadomain() = default; - /* setters -------------------------------------------------------------- */ /* getters -------------------------------------------------------------- */ @@ -181,7 +184,8 @@ namespace ntt { const std::vector g_species_params; #if defined(OUTPUT_ENABLED) - out::Writer g_writer; + out::Writer g_writer; + checkpoint::Writer g_checkpoint_writer; #endif #if defined(MPI_ENABLED) diff --git a/src/framework/parameters.cpp b/src/framework/parameters.cpp index 65ff6a994..6df5ce3cc 100644 --- a/src/framework/parameters.cpp +++ b/src/framework/parameters.cpp @@ -8,6 +8,7 @@ #include "utils/formatting.h" #include "utils/log.h" #include "utils/numeric.h" +#include "utils/toml.h" #include "metrics/kerr_schild.h" #include "metrics/kerr_schild_0.h" @@ -18,8 +19,6 @@ #include "framework/containers/species.h" -#include - #if defined(MPI_ENABLED) #include #endif @@ -46,15 +45,15 @@ namespace ntt { return { dx0, V0 }; } - SimulationParams::SimulationParams(const toml::value& raw_data) { + SimulationParams::SimulationParams(const toml::value& toml_data) + : raw_data { toml_data } { /* [simulation] --------------------------------------------------------- */ set("simulation.name", toml::find(raw_data, "simulation", "name")); set("simulation.runtime", toml::find(raw_data, "simulation", "runtime")); - const auto engine = fmt::toLower( - toml::find(raw_data, "simulation", "engine")); - const auto engine_enum = SimEngine::pick(engine.c_str()); + const auto engine_enum = SimEngine::pick( + fmt::toLower(toml::find(toml_data, "simulation", "engine")).c_str()); set("simulation.engine", engine_enum); int default_ndomains = 1; @@ -79,7 +78,7 @@ namespace ntt { promiseToDefine("simulation.domain.decomposition"); /* [grid] --------------------------------------------------------------- */ - const auto res = toml::find>(raw_data, + const auto res = toml::find>(toml_data, "grid", "resolution"); raise::ErrorIf(res.size() < 1 || res.size() > 3, @@ -107,17 +106,18 @@ namespace ntt { promiseToDefine("grid.extent"); /* [grid.metric] -------------------------------------------------------- */ - const auto metric = fmt::toLower( - toml::find(raw_data, "grid", "metric", "metric")); - const auto metric_enum = Metric::pick(metric.c_str()); + const auto metric_enum = Metric::pick( + fmt::toLower(toml::find(toml_data, "grid", "metric", "metric")) + .c_str()); promiseToDefine("grid.metric.metric"); std::string coord; - if (metric == "minkowski") { + if (metric_enum == Metric::Minkowski) { raise::ErrorIf(engine_enum != SimEngine::SRPIC, "minkowski metric is only supported for SRPIC", HERE); coord = "cart"; - } else if (metric[0] == 'q') { + } else if (metric_enum == Metric::QKerr_Schild or + metric_enum == Metric::QSpherical) { // quasi-spherical geometry raise::ErrorIf(dim == Dim::_1D, "not enough dimensions for qspherical geometry", diff --git a/src/framework/parameters.h b/src/framework/parameters.h index 301f7053f..afa730bcd 100644 --- a/src/framework/parameters.h +++ b/src/framework/parameters.h @@ -18,22 +18,31 @@ #define FRAMEWORK_PARAMETERS_H #include "utils/param_container.h" - -#include +#include "utils/toml.h" namespace ntt { struct SimulationParams : public prm::Parameters { + SimulationParams() = default; SimulationParams(const toml::value&); SimulationParams& operator=(const SimulationParams& other) { vars = std::move(other.vars); promises = std::move(other.promises); + raw_data = std::move(other.raw_data); return *this; } ~SimulationParams() = default; + + [[nodiscard]] + auto data() const -> const toml::value& { + return raw_data; + } + + private: + toml::value raw_data; }; } // namespace ntt diff --git a/src/framework/simulation.cpp b/src/framework/simulation.cpp index b913379b4..7cf989872 100644 --- a/src/framework/simulation.cpp +++ b/src/framework/simulation.cpp @@ -1,17 +1,17 @@ #include "framework/simulation.h" #include "defaults.h" +#include "enums.h" #include "global.h" #include "utils/cargs.h" #include "utils/error.h" #include "utils/formatting.h" #include "utils/plog.h" +#include "utils/toml.h" #include "framework/parameters.h" -#include - #include namespace ntt { @@ -26,15 +26,27 @@ namespace ntt { const auto outputdir = static_cast( cl_args.getArgument("-output", defaults::output_path)); - const auto inputdata = toml::parse(inputfname); - const auto sim_name = toml::find(inputdata, "simulation", "name"); + raw_params = toml::parse(inputfname); + const auto sim_name = toml::find(raw_params, "simulation", "name"); logger::initPlog(sim_name); - params = SimulationParams(inputdata); + m_requested_engine = SimEngine::pick( + fmt::toLower(toml::find(raw_params, "simulation", "engine")).c_str()); + m_requested_metric = Metric::pick( + fmt::toLower(toml::find(raw_params, "grid", "metric", "metric")) + .c_str()); + + const auto res = toml::find>(raw_params, + "grid", + "resolution"); + raise::ErrorIf(res.size() < 1 || res.size() > 3, + "invalid `grid.resolution`", + HERE); + m_requested_dimension = static_cast(res.size()); } Simulation::~Simulation() { GlobalFinalize(); } -} // namespace ntt \ No newline at end of file +} // namespace ntt diff --git a/src/framework/simulation.h b/src/framework/simulation.h index 2f4d3d321..c069aa484 100644 --- a/src/framework/simulation.h +++ b/src/framework/simulation.h @@ -18,6 +18,7 @@ #include "arch/traits.h" #include "utils/error.h" +#include "utils/toml.h" #include "framework/parameters.h" @@ -27,7 +28,11 @@ namespace ntt { class Simulation { - SimulationParams params; + toml::value raw_params; + + Dimension m_requested_dimension; + SimEngine m_requested_engine { SimEngine::INVALID }; + Metric m_requested_metric { Metric::INVALID }; public: Simulation(int argc, char* argv[]); @@ -41,7 +46,7 @@ namespace ntt { static_assert(traits::has_method::value, "Engine must contain a ::run() method"); try { - engine_t engine { params }; + engine_t engine { raw_params }; engine.run(); } catch (const std::exception& e) { raise::Fatal(e.what(), HERE); @@ -50,17 +55,17 @@ namespace ntt { [[nodiscard]] inline auto requested_dimension() const -> Dimension { - return params.get("grid.dim"); + return m_requested_dimension; } [[nodiscard]] inline auto requested_engine() const -> SimEngine { - return params.get("simulation.engine"); + return m_requested_engine; } [[nodiscard]] inline auto requested_metric() const -> Metric { - return params.get("grid.metric.metric"); + return m_requested_metric; } }; diff --git a/src/framework/tests/parameters.cpp b/src/framework/tests/parameters.cpp index 8f02d1750..9c80554cd 100644 --- a/src/framework/tests/parameters.cpp +++ b/src/framework/tests/parameters.cpp @@ -5,11 +5,11 @@ #include "utils/comparators.h" #include "utils/error.h" +#include "utils/toml.h" #include "framework/containers/species.h" #include -#include #include #include diff --git a/src/global/CMakeLists.txt b/src/global/CMakeLists.txt index d00689283..f8bd7ab07 100644 --- a/src/global/CMakeLists.txt +++ b/src/global/CMakeLists.txt @@ -4,6 +4,7 @@ # - global.cpp # - arch/kokkos_aliases.cpp # - utils/cargs.cpp +# - utils/param_container.cpp # @includes: # - ./ # @uses: @@ -18,9 +19,12 @@ set(SOURCES ${SRC_DIR}/arch/kokkos_aliases.cpp ${SRC_DIR}/utils/cargs.cpp ) +if (${output}) + list(APPEND SOURCES ${SRC_DIR}/utils/param_container.cpp) +endif() add_library(ntt_global ${SOURCES}) target_include_directories(ntt_global PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} INTERFACE ${CMAKE_CURRENT_SOURCE_DIR} ) -target_link_libraries(ntt_global PRIVATE stdc++fs) \ No newline at end of file +target_link_libraries(ntt_global PRIVATE stdc++fs) diff --git a/src/global/defaults.h b/src/global/defaults.h index fb874481e..b9eca9080 100644 --- a/src/global/defaults.h +++ b/src/global/defaults.h @@ -62,7 +62,7 @@ namespace ntt::defaults { namespace checkpoint { const std::size_t interval = 1000; - const std::size_t keep = 2; + const int keep = 2; } // namespace checkpoint namespace diag { diff --git a/src/global/global.h b/src/global/global.h index ca067d547..b3f640295 100644 --- a/src/global/global.h +++ b/src/global/global.h @@ -204,17 +204,18 @@ typedef int PrepareOutputFlags; namespace Timer { enum TimerFlags_ { - None = 0, - PrintRelative = 1 << 0, - PrintUnits = 1 << 1, - PrintIndents = 1 << 2, - PrintTotal = 1 << 3, - PrintTitle = 1 << 4, - AutoConvert = 1 << 5, - Colorful = 1 << 6, - PrintOutput = 1 << 7, - PrintSorting = 1 << 8, - Default = PrintRelative | PrintUnits | PrintIndents | PrintTotal | + None = 0, + PrintRelative = 1 << 0, + PrintUnits = 1 << 1, + PrintIndents = 1 << 2, + PrintTotal = 1 << 3, + PrintTitle = 1 << 4, + AutoConvert = 1 << 5, + Colorful = 1 << 6, + PrintOutput = 1 << 7, + PrintSorting = 1 << 8, + PrintCheckpoint = 1 << 9, + Default = PrintRelative | PrintUnits | PrintIndents | PrintTotal | PrintTitle | AutoConvert | Colorful, }; } // namespace Timer diff --git a/src/global/utils/param_container.cpp b/src/global/utils/param_container.cpp new file mode 100644 index 000000000..6e4f5e0f4 --- /dev/null +++ b/src/global/utils/param_container.cpp @@ -0,0 +1,333 @@ +#if defined(OUTPUT_ENABLED) + #include "utils/param_container.h" + + #include "enums.h" + #include "global.h" + + #include + #include + + #include + #include + #include + #include + #include + #include + #include + #include + #include + +namespace prm { + template + struct has_to_string : std::false_type {}; + + template + struct has_to_string().to_string())>> + : std::true_type {}; + + template + auto write(adios2::IO& io, const std::string& name, T var) -> + typename std::enable_if::value, void>::type { + io.DefineAttribute(name, std::string(var.to_string())); + } + + template + auto write(adios2::IO& io, const std::string& name, T var) + -> decltype(void(T()), void()) { + io.DefineAttribute(name, var); + } + + template <> + void write(adios2::IO& io, const std::string& name, bool var) { + io.DefineAttribute(name, var ? 1 : 0); + } + + template <> + void write(adios2::IO& io, const std::string& name, Dimension var) { + io.DefineAttribute(name, (unsigned short)var); + } + + template + auto write_pair(adios2::IO& io, const std::string& name, std::pair var) + -> typename std::enable_if::value, void>::type { + std::vector var_str; + var_str.push_back(var.first.to_string()); + var_str.push_back(var.second.to_string()); + io.DefineAttribute(name, var_str.data(), var_str.size()); + } + + template + auto write_pair(adios2::IO& io, const std::string& name, std::pair var) + -> decltype(void(T()), void()) { + std::vector var_vec; + var_vec.push_back(var.first); + var_vec.push_back(var.second); + io.DefineAttribute(name, var_vec.data(), var_vec.size()); + } + + template + auto write_vec(adios2::IO& io, const std::string& name, std::vector var) -> + typename std::enable_if::value, void>::type { + std::vector var_str; + for (const auto& v : var) { + var_str.push_back(v.to_string()); + } + io.DefineAttribute(name, var_str.data(), var_str.size()); + } + + template + auto write_vec(adios2::IO& io, const std::string& name, std::vector var) + -> decltype(void(T()), void()) { + io.DefineAttribute(name, var.data(), var.size()); + } + + template + auto write_vec_pair(adios2::IO& io, + const std::string& name, + std::vector> var) -> + typename std::enable_if::value, void>::type { + std::vector var_str; + for (const auto& v : var) { + var_str.push_back(v.first.to_string()); + var_str.push_back(v.second.to_string()); + } + io.DefineAttribute(name, var_str.data(), var_str.size()); + } + + template + auto write_vec_pair(adios2::IO& io, + const std::string& name, + std::vector> var) + -> decltype(void(T()), void()) { + std::vector var_vec; + for (const auto& v : var) { + var_vec.push_back(v.first); + var_vec.push_back(v.second); + } + io.DefineAttribute(name, var_vec.data(), var_vec.size()); + } + + template + auto write_vec_vec(adios2::IO& io, + const std::string& name, + std::vector> var) -> + typename std::enable_if::value, void>::type { + std::vector var_str; + for (const auto& vec : var) { + for (const auto& v : vec) { + var_str.push_back(v.to_string()); + } + } + io.DefineAttribute(name, var_str.data(), var_str.size()); + } + + template + auto write_vec_vec(adios2::IO& io, + const std::string& name, + std::vector> var) + -> decltype(void(T()), void()) { + std::vector var_vec; + for (const auto& vec : var) { + for (const auto& v : vec) { + var_vec.push_back(v); + } + } + io.DefineAttribute(name, var_vec.data(), var_vec.size()); + } + + template + auto write_dict(adios2::IO& io, + const std::string& name, + std::map var) -> + typename std::enable_if::value, void>::type { + for (const auto& [key, v] : var) { + io.DefineAttribute(name + "_" + key, v.to_string()); + } + } + + template + auto write_dict(adios2::IO& io, + const std::string& name, + std::map var) -> decltype(void(T()), void()) { + for (const auto& [key, v] : var) { + io.DefineAttribute(name + "_" + key, v); + } + } + + std::map> + write_functions; + + template + void register_write_function() { + write_functions[std::type_index(typeid(T))] = + [](adios2::IO& io, const std::string& name, std::any a) { + write(io, name, std::any_cast(a)); + }; + } + + template + void register_write_function_for_pair() { + write_functions[std::type_index(typeid(std::pair))] = + [](adios2::IO& io, const std::string& name, std::any a) { + write_pair(io, name, std::any_cast>(a)); + }; + } + + template + void register_write_function_for_vector() { + write_functions[std::type_index(typeid(std::vector))] = + [](adios2::IO& io, const std::string& name, std::any a) { + write_vec(io, name, std::any_cast>(a)); + }; + } + + template + void register_write_function_for_vector_of_pair() { + write_functions[std::type_index(typeid(std::vector>))] = + [](adios2::IO& io, const std::string& name, std::any a) { + write_vec_pair(io, name, std::any_cast>>(a)); + }; + } + + template + void register_write_function_for_vector_of_vector() { + write_functions[std::type_index(typeid(std::vector>))] = + [](adios2::IO& io, const std::string& name, std::any a) { + write_vec_vec(io, name, std::any_cast>>(a)); + }; + } + + template + void register_write_function_for_dict() { + write_functions[std::type_index(typeid(std::map))] = + [](adios2::IO& io, const std::string& name, std::any a) { + write_dict(io, name, std::any_cast>(a)); + }; + } + + void write_any(adios2::IO& io, const std::string& name, std::any a) { + auto it = write_functions.find(a.type()); + if (it != write_functions.end()) { + it->second(io, name, a); + } else { + throw std::runtime_error("No write function registered for this type"); + } + } + + void Parameters::write(adios2::IO& io) const { + register_write_function(); + register_write_function(); + register_write_function(); + register_write_function(); + register_write_function(); + register_write_function(); + register_write_function(); + register_write_function(); + register_write_function(); + register_write_function(); + register_write_function(); + register_write_function(); + register_write_function(); + register_write_function(); + register_write_function(); + register_write_function(); + register_write_function(); + register_write_function(); + register_write_function(); + + register_write_function_for_pair(); + register_write_function_for_pair(); + register_write_function_for_pair(); + register_write_function_for_pair(); + register_write_function_for_pair(); + register_write_function_for_pair(); + register_write_function_for_pair(); + register_write_function_for_pair(); + register_write_function_for_pair(); + register_write_function_for_pair(); + register_write_function_for_pair(); + register_write_function_for_pair(); + register_write_function_for_pair(); + register_write_function_for_pair(); + register_write_function_for_pair(); + register_write_function_for_pair(); + register_write_function_for_pair(); + + register_write_function_for_vector(); + register_write_function_for_vector(); + register_write_function_for_vector(); + register_write_function_for_vector(); + register_write_function_for_vector(); + register_write_function_for_vector(); + register_write_function_for_vector(); + register_write_function_for_vector(); + register_write_function_for_vector(); + register_write_function_for_vector(); + register_write_function_for_vector(); + register_write_function_for_vector(); + register_write_function_for_vector(); + register_write_function_for_vector(); + register_write_function_for_vector(); + register_write_function_for_vector(); + register_write_function_for_vector(); + + register_write_function_for_vector_of_pair(); + register_write_function_for_vector_of_pair(); + register_write_function_for_vector_of_pair(); + register_write_function_for_vector_of_pair(); + register_write_function_for_vector_of_pair(); + register_write_function_for_vector_of_pair(); + register_write_function_for_vector_of_pair(); + register_write_function_for_vector_of_pair(); + register_write_function_for_vector_of_pair(); + register_write_function_for_vector_of_pair(); + register_write_function_for_vector_of_pair(); + register_write_function_for_vector_of_pair(); + register_write_function_for_vector_of_pair(); + register_write_function_for_vector_of_pair(); + register_write_function_for_vector_of_pair(); + register_write_function_for_vector_of_pair(); + register_write_function_for_vector_of_pair(); + + register_write_function_for_vector_of_vector(); + register_write_function_for_vector_of_vector(); + register_write_function_for_vector_of_vector(); + register_write_function_for_vector_of_vector(); + register_write_function_for_vector_of_vector(); + register_write_function_for_vector_of_vector(); + register_write_function_for_vector_of_vector(); + register_write_function_for_vector_of_vector(); + register_write_function_for_vector_of_vector(); + register_write_function_for_vector_of_vector(); + register_write_function_for_vector_of_vector(); + register_write_function_for_vector_of_vector(); + register_write_function_for_vector_of_vector(); + register_write_function_for_vector_of_vector(); + register_write_function_for_vector_of_vector(); + register_write_function_for_vector_of_vector(); + register_write_function_for_vector_of_vector(); + + register_write_function_for_dict(); + register_write_function_for_dict(); + register_write_function_for_dict(); + register_write_function_for_dict(); + register_write_function_for_dict(); + register_write_function_for_dict(); + register_write_function_for_dict(); + register_write_function_for_dict(); + register_write_function_for_dict(); + register_write_function_for_dict(); + register_write_function_for_dict(); + + for (auto& [key, value] : allVars()) { + try { + write_any(io, key, value); + } catch (const std::exception& e) { + continue; + } + } + } + +} // namespace prm + +#endif diff --git a/src/global/utils/param_container.h b/src/global/utils/param_container.h index dccf91d09..679b80552 100644 --- a/src/global/utils/param_container.h +++ b/src/global/utils/param_container.h @@ -16,6 +16,11 @@ #include "utils/formatting.h" #include "utils/log.h" +#if defined(OUTPUT_ENABLED) + #include + #include +#endif + #include #include #include @@ -172,6 +177,10 @@ namespace prm { } return result.str(); } + +#if defined(OUTPUT_ENABLED) + void write(adios2::IO& io) const; +#endif }; } // namespace prm diff --git a/src/global/utils/timer.h b/src/global/utils/timer.h index 79f325f0e..84356f7b3 100644 --- a/src/global/utils/timer.h +++ b/src/global/utils/timer.h @@ -118,7 +118,11 @@ namespace timer { void printAll(const TimerFlags flags = Timer::Default, std::ostream& os = std::cout) const { +#if !defined(MPI_ENABLED) std::string header = fmt::format("%s %27s", "[SUBSTEP]", "[DURATION]"); +#else + std::string header = fmt::format("%s %32s", "[SUBSTEP]", "[DURATION]"); +#endif const auto c_bblack = color::get_color("bblack", flags & Timer::Colorful); const auto c_reset = color::get_color("reset", flags & Timer::Colorful); @@ -162,7 +166,7 @@ namespace timer { for (auto& [name, timer] : m_timers) { auto timers = mpi_timers[name]; long double tot = std::accumulate(timers.begin(), timers.end(), 0.0); - if (name != "Output") { + if (name != "Output" and name != "Checkpoint") { total += tot; } } @@ -214,12 +218,12 @@ namespace timer { #else // not MPI_ENABLED long double total = 0.0; for (auto& [name, timer] : m_timers) { - if (name != "Output") { + if (name != "Output" and name != "Checkpoint") { total += timer.second; } } for (auto& [name, timer] : m_timers) { - if (name == "Output") { + if (name == "Output" or name == "Checkpoint") { continue; } std::string units = "µs"; @@ -257,8 +261,13 @@ namespace timer { if (flags & Timer::AutoConvert) { convertTime(value, units); } +#if !defined(MPI_ENABLED) os << c_bblack << std::setw(22) << std::left << std::setfill(' ') << "Total" << c_reset; +#else + os << c_bblack << std::setw(27) << std::left << std::setfill(' ') + << "Total" << c_reset; +#endif os << c_blue << std::setw(12) << std::right << std::setfill(' ') << value; if (flags & Timer::PrintUnits) { os << " " << units; @@ -283,6 +292,25 @@ namespace timer { } os << c_reset << std::endl; } + { + std::string units = "µs"; + auto value = get("Checkpoint"); + if (flags & Timer::AutoConvert) { + convertTime(value, units); + } + os << ((flags & Timer::PrintCheckpoint) ? c_reset : c_bblack) + << "Checkpoint" << c_bblack + << fmt::pad("Checkpoint", 22, '.', true).substr(10, 22); + os << std::setw(17) << std::right << std::setfill('.') + << fmt::format("%s%.2Lf", + (flags & Timer::PrintCheckpoint) ? c_byellow.c_str() + : c_bblack.c_str(), + value); + if (flags & Timer::PrintUnits) { + os << " " << units; + } + os << c_reset << std::endl; + } } }; } // namespace timer diff --git a/src/global/utils/toml.h b/src/global/utils/toml.h new file mode 100644 index 000000000..b621f5839 --- /dev/null +++ b/src/global/utils/toml.h @@ -0,0 +1,17972 @@ +#ifndef TOML11_VERSION_HPP +#define TOML11_VERSION_HPP + +#define TOML11_VERSION_MAJOR 4 +#define TOML11_VERSION_MINOR 1 +#define TOML11_VERSION_PATCH 0 + +#ifndef __cplusplus + #error "__cplusplus is not defined" +#endif + +// Since MSVC does not define `__cplusplus` correctly unless you pass +// `/Zc:__cplusplus` when compiling, the workaround macros are added. +// +// The value of `__cplusplus` macro is defined in the C++ standard spec, but +// MSVC ignores the value, maybe because of backward compatibility. Instead, +// MSVC defines _MSVC_LANG that has the same value as __cplusplus defined in +// the C++ standard. So we check if _MSVC_LANG is defined before using `__cplusplus`. +// +// FYI: https://docs.microsoft.com/en-us/cpp/build/reference/zc-cplusplus?view=msvc-170 +// https://docs.microsoft.com/en-us/cpp/preprocessor/predefined-macros?view=msvc-170 +// + +#if defined(_MSVC_LANG) && defined(_MSC_VER) && 190024210 <= _MSC_FULL_VER + #define TOML11_CPLUSPLUS_STANDARD_VERSION _MSVC_LANG +#else + #define TOML11_CPLUSPLUS_STANDARD_VERSION __cplusplus +#endif + +#if TOML11_CPLUSPLUS_STANDARD_VERSION < 201103L + #error "toml11 requires C++11 or later." +#endif + +#if !defined(__has_include) + #define __has_include(x) 0 +#endif + +#if !defined(__has_cpp_attribute) + #define __has_cpp_attribute(x) 0 +#endif + +#if !defined(__has_builtin) + #define __has_builtin(x) 0 +#endif + +// hard to remember + +#ifndef TOML11_CXX14_VALUE + #define TOML11_CXX14_VALUE 201402L +#endif // TOML11_CXX14_VALUE + +#ifndef TOML11_CXX17_VALUE + #define TOML11_CXX17_VALUE 201703L +#endif // TOML11_CXX17_VALUE + +#ifndef TOML11_CXX20_VALUE + #define TOML11_CXX20_VALUE 202002L +#endif // TOML11_CXX20_VALUE + +#if defined(__cpp_char8_t) + #if __cpp_char8_t >= 201811L + #define TOML11_HAS_CHAR8_T 1 + #endif +#endif + +#if TOML11_CPLUSPLUS_STANDARD_VERSION >= TOML11_CXX17_VALUE + #if __has_include() + #define TOML11_HAS_STRING_VIEW 1 + #endif +#endif + +#ifndef TOML11_DISABLE_STD_FILESYSTEM + #if TOML11_CPLUSPLUS_STANDARD_VERSION >= TOML11_CXX17_VALUE + #if __has_include() + #define TOML11_HAS_FILESYSTEM 1 + #endif + #endif +#endif + +#if TOML11_CPLUSPLUS_STANDARD_VERSION >= TOML11_CXX17_VALUE + #if __has_include() + #define TOML11_HAS_OPTIONAL 1 + #endif +#endif + +#if defined(TOML11_COMPILE_SOURCES) + #define TOML11_INLINE +#else + #define TOML11_INLINE inline +#endif + +namespace toml { + + inline const char* license_notice() noexcept { + return R"(The MIT License (MIT) + +Copyright (c) 2017-now Toru Niina + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE.)"; + } + +} // namespace toml +#endif // TOML11_VERSION_HPP +#ifndef TOML11_FORMAT_HPP +#define TOML11_FORMAT_HPP + +#ifndef TOML11_FORMAT_FWD_HPP + #define TOML11_FORMAT_FWD_HPP + + #include + #include + #include + #include + #include + +namespace toml { + + // toml types with serialization info + + enum class indent_char : std::uint8_t { + space, // use space + tab, // use tab + none // no indent + }; + + std::ostream& operator<<(std::ostream& os, const indent_char& c); + std::string to_string(const indent_char c); + + // ---------------------------------------------------------------------------- + // boolean + + struct boolean_format_info { + // nothing, for now + }; + + inline bool operator==(const boolean_format_info&, + const boolean_format_info&) noexcept { + return true; + } + + inline bool operator!=(const boolean_format_info&, + const boolean_format_info&) noexcept { + return false; + } + + // ---------------------------------------------------------------------------- + // integer + + enum class integer_format : std::uint8_t { + dec = 0, + bin = 1, + oct = 2, + hex = 3, + }; + + std::ostream& operator<<(std::ostream& os, const integer_format f); + std::string to_string(const integer_format); + + struct integer_format_info { + integer_format fmt = integer_format::dec; + bool uppercase = true; // hex with uppercase + std::size_t width = 0; // minimal width (may exceed) + std::size_t spacer = 0; // position of `_` (if 0, no spacer) + std::string suffix = ""; // _suffix (library extension) + }; + + bool operator==(const integer_format_info&, const integer_format_info&) noexcept; + bool operator!=(const integer_format_info&, const integer_format_info&) noexcept; + + // ---------------------------------------------------------------------------- + // floating + + enum class floating_format : std::uint8_t { + defaultfloat = 0, + fixed = 1, // does not include exponential part + scientific = 2, // always include exponential part + hex = 3 // hexfloat extension + }; + + std::ostream& operator<<(std::ostream& os, const floating_format f); + std::string to_string(const floating_format); + + struct floating_format_info { + floating_format fmt = floating_format::defaultfloat; + std::size_t prec = 0; // precision (if 0, use the default) + std::string suffix = ""; // 1.0e+2_suffix (library extension) + }; + + bool operator==(const floating_format_info&, const floating_format_info&) noexcept; + bool operator!=(const floating_format_info&, const floating_format_info&) noexcept; + + // ---------------------------------------------------------------------------- + // string + + enum class string_format : std::uint8_t { + basic = 0, + literal = 1, + multiline_basic = 2, + multiline_literal = 3 + }; + + std::ostream& operator<<(std::ostream& os, const string_format f); + std::string to_string(const string_format); + + struct string_format_info { + string_format fmt = string_format::basic; + bool start_with_newline = false; + }; + + bool operator==(const string_format_info&, const string_format_info&) noexcept; + bool operator!=(const string_format_info&, const string_format_info&) noexcept; + + // ---------------------------------------------------------------------------- + // datetime + + enum class datetime_delimiter_kind : std::uint8_t { + upper_T = 0, + lower_t = 1, + space = 2, + }; + std::ostream& operator<<(std::ostream& os, const datetime_delimiter_kind d); + std::string to_string(const datetime_delimiter_kind); + + struct offset_datetime_format_info { + datetime_delimiter_kind delimiter = datetime_delimiter_kind::upper_T; + bool has_seconds = true; + std::size_t subsecond_precision = 6; // [us] + }; + + bool operator==(const offset_datetime_format_info&, + const offset_datetime_format_info&) noexcept; + bool operator!=(const offset_datetime_format_info&, + const offset_datetime_format_info&) noexcept; + + struct local_datetime_format_info { + datetime_delimiter_kind delimiter = datetime_delimiter_kind::upper_T; + bool has_seconds = true; + std::size_t subsecond_precision = 6; // [us] + }; + + bool operator==(const local_datetime_format_info&, + const local_datetime_format_info&) noexcept; + bool operator!=(const local_datetime_format_info&, + const local_datetime_format_info&) noexcept; + + struct local_date_format_info { + // nothing, for now + }; + + bool operator==(const local_date_format_info&, + const local_date_format_info&) noexcept; + bool operator!=(const local_date_format_info&, + const local_date_format_info&) noexcept; + + struct local_time_format_info { + bool has_seconds = true; + std::size_t subsecond_precision = 6; // [us] + }; + + bool operator==(const local_time_format_info&, + const local_time_format_info&) noexcept; + bool operator!=(const local_time_format_info&, + const local_time_format_info&) noexcept; + + // ---------------------------------------------------------------------------- + // array + + enum class array_format : std::uint8_t { + default_format = 0, + oneline = 1, + multiline = 2, + array_of_tables = 3 // [[format.in.this.way]] + }; + + std::ostream& operator<<(std::ostream& os, const array_format f); + std::string to_string(const array_format); + + struct array_format_info { + array_format fmt = array_format::default_format; + indent_char indent_type = indent_char::space; + std::int32_t body_indent = 4; // indent in case of multiline + std::int32_t closing_indent = 0; // indent of `]` + }; + + bool operator==(const array_format_info&, const array_format_info&) noexcept; + bool operator!=(const array_format_info&, const array_format_info&) noexcept; + + // ---------------------------------------------------------------------------- + // table + + enum class table_format : std::uint8_t { + multiline = 0, // [foo] \n bar = "baz" + oneline = 1, // foo = {bar = "baz"} + dotted = 2, // foo.bar = "baz" + multiline_oneline = 3, // foo = { \n bar = "baz" \n } + implicit = 4 // [x] defined by [x.y.z]. skip in serializer. + }; + + std::ostream& operator<<(std::ostream& os, const table_format f); + std::string to_string(const table_format); + + struct table_format_info { + table_format fmt = table_format::multiline; + indent_char indent_type = indent_char::space; + std::int32_t body_indent = 0; // indent of values + std::int32_t name_indent = 0; // indent of [table] + std::int32_t closing_indent = 0; // in case of {inline-table} + }; + + bool operator==(const table_format_info&, const table_format_info&) noexcept; + bool operator!=(const table_format_info&, const table_format_info&) noexcept; + + // ---------------------------------------------------------------------------- + // wrapper + + namespace detail { + template + struct value_with_format { + using value_type = T; + using format_type = F; + + value_with_format() = default; + ~value_with_format() = default; + value_with_format(const value_with_format&) = default; + value_with_format(value_with_format&&) = default; + value_with_format& operator=(const value_with_format&) = default; + value_with_format& operator=(value_with_format&&) = default; + + value_with_format(value_type v, format_type f) + : value { std::move(v) } + , format { std::move(f) } {} + + template + value_with_format(value_with_format other) + : value { std::move(other.value) } + , format { std::move(other.format) } {} + + value_type value; + format_type format; + }; + } // namespace detail + +} // namespace toml +#endif // TOML11_FORMAT_FWD_HPP + +#if !defined(TOML11_COMPILE_SOURCES) + #ifndef TOML11_FORMAT_IMPL_HPP + #define TOML11_FORMAT_IMPL_HPP + + #include + #include + +namespace toml { + + // toml types with serialization info + + TOML11_INLINE std::ostream& operator<<(std::ostream& os, const indent_char& c) { + switch (c) { + case indent_char::space: { + os << "space"; + break; + } + case indent_char::tab: { + os << "tab"; + break; + } + case indent_char::none: { + os << "none"; + break; + } + default: { + os << "unknown indent char: " << static_cast(c); + } + } + return os; + } + + TOML11_INLINE std::string to_string(const indent_char c) { + std::ostringstream oss; + oss << c; + return oss.str(); + } + + // ---------------------------------------------------------------------------- + // boolean + + // ---------------------------------------------------------------------------- + // integer + + TOML11_INLINE std::ostream& operator<<(std::ostream& os, const integer_format f) { + switch (f) { + case integer_format::dec: { + os << "dec"; + break; + } + case integer_format::bin: { + os << "bin"; + break; + } + case integer_format::oct: { + os << "oct"; + break; + } + case integer_format::hex: { + os << "hex"; + break; + } + default: { + os << "unknown integer_format: " << static_cast(f); + break; + } + } + return os; + } + + TOML11_INLINE std::string to_string(const integer_format c) { + std::ostringstream oss; + oss << c; + return oss.str(); + } + + TOML11_INLINE bool operator==(const integer_format_info& lhs, + const integer_format_info& rhs) noexcept { + return lhs.fmt == rhs.fmt && lhs.uppercase == rhs.uppercase && + lhs.width == rhs.width && lhs.spacer == rhs.spacer && + lhs.suffix == rhs.suffix; + } + + TOML11_INLINE bool operator!=(const integer_format_info& lhs, + const integer_format_info& rhs) noexcept { + return !(lhs == rhs); + } + + // ---------------------------------------------------------------------------- + // floating + + TOML11_INLINE std::ostream& operator<<(std::ostream& os, const floating_format f) { + switch (f) { + case floating_format::defaultfloat: { + os << "defaultfloat"; + break; + } + case floating_format::fixed: { + os << "fixed"; + break; + } + case floating_format::scientific: { + os << "scientific"; + break; + } + case floating_format::hex: { + os << "hex"; + break; + } + default: { + os << "unknown floating_format: " << static_cast(f); + break; + } + } + return os; + } + + TOML11_INLINE std::string to_string(const floating_format c) { + std::ostringstream oss; + oss << c; + return oss.str(); + } + + TOML11_INLINE bool operator==(const floating_format_info& lhs, + const floating_format_info& rhs) noexcept { + return lhs.fmt == rhs.fmt && lhs.prec == rhs.prec && lhs.suffix == rhs.suffix; + } + + TOML11_INLINE bool operator!=(const floating_format_info& lhs, + const floating_format_info& rhs) noexcept { + return !(lhs == rhs); + } + + // ---------------------------------------------------------------------------- + // string + + TOML11_INLINE std::ostream& operator<<(std::ostream& os, const string_format f) { + switch (f) { + case string_format::basic: { + os << "basic"; + break; + } + case string_format::literal: { + os << "literal"; + break; + } + case string_format::multiline_basic: { + os << "multiline_basic"; + break; + } + case string_format::multiline_literal: { + os << "multiline_literal"; + break; + } + default: { + os << "unknown string_format: " << static_cast(f); + break; + } + } + return os; + } + + TOML11_INLINE std::string to_string(const string_format c) { + std::ostringstream oss; + oss << c; + return oss.str(); + } + + TOML11_INLINE bool operator==(const string_format_info& lhs, + const string_format_info& rhs) noexcept { + return lhs.fmt == rhs.fmt && lhs.start_with_newline == rhs.start_with_newline; + } + + TOML11_INLINE bool operator!=(const string_format_info& lhs, + const string_format_info& rhs) noexcept { + return !(lhs == rhs); + } + + // ---------------------------------------------------------------------------- + // datetime + + TOML11_INLINE std::ostream& operator<<(std::ostream& os, + const datetime_delimiter_kind d) { + switch (d) { + case datetime_delimiter_kind::upper_T: { + os << "upper_T, "; + break; + } + case datetime_delimiter_kind::lower_t: { + os << "lower_t, "; + break; + } + case datetime_delimiter_kind::space: { + os << "space, "; + break; + } + default: { + os << "unknown datetime delimiter: " << static_cast(d); + break; + } + } + return os; + } + + TOML11_INLINE std::string to_string(const datetime_delimiter_kind c) { + std::ostringstream oss; + oss << c; + return oss.str(); + } + + TOML11_INLINE bool operator==(const offset_datetime_format_info& lhs, + const offset_datetime_format_info& rhs) noexcept { + return lhs.delimiter == rhs.delimiter && lhs.has_seconds == rhs.has_seconds && + lhs.subsecond_precision == rhs.subsecond_precision; + } + + TOML11_INLINE bool operator!=(const offset_datetime_format_info& lhs, + const offset_datetime_format_info& rhs) noexcept { + return !(lhs == rhs); + } + + TOML11_INLINE bool operator==(const local_datetime_format_info& lhs, + const local_datetime_format_info& rhs) noexcept { + return lhs.delimiter == rhs.delimiter && lhs.has_seconds == rhs.has_seconds && + lhs.subsecond_precision == rhs.subsecond_precision; + } + + TOML11_INLINE bool operator!=(const local_datetime_format_info& lhs, + const local_datetime_format_info& rhs) noexcept { + return !(lhs == rhs); + } + + TOML11_INLINE bool operator==(const local_date_format_info&, + const local_date_format_info&) noexcept { + return true; + } + + TOML11_INLINE bool operator!=(const local_date_format_info& lhs, + const local_date_format_info& rhs) noexcept { + return !(lhs == rhs); + } + + TOML11_INLINE bool operator==(const local_time_format_info& lhs, + const local_time_format_info& rhs) noexcept { + return lhs.has_seconds == rhs.has_seconds && + lhs.subsecond_precision == rhs.subsecond_precision; + } + + TOML11_INLINE bool operator!=(const local_time_format_info& lhs, + const local_time_format_info& rhs) noexcept { + return !(lhs == rhs); + } + + // ---------------------------------------------------------------------------- + // array + + TOML11_INLINE std::ostream& operator<<(std::ostream& os, const array_format f) { + switch (f) { + case array_format::default_format: { + os << "default_format"; + break; + } + case array_format::oneline: { + os << "oneline"; + break; + } + case array_format::multiline: { + os << "multiline"; + break; + } + case array_format::array_of_tables: { + os << "array_of_tables"; + break; + } + default: { + os << "unknown array_format: " << static_cast(f); + break; + } + } + return os; + } + + TOML11_INLINE std::string to_string(const array_format c) { + std::ostringstream oss; + oss << c; + return oss.str(); + } + + TOML11_INLINE bool operator==(const array_format_info& lhs, + const array_format_info& rhs) noexcept { + return lhs.fmt == rhs.fmt && lhs.indent_type == rhs.indent_type && + lhs.body_indent == rhs.body_indent && + lhs.closing_indent == rhs.closing_indent; + } + + TOML11_INLINE bool operator!=(const array_format_info& lhs, + const array_format_info& rhs) noexcept { + return !(lhs == rhs); + } + + // ---------------------------------------------------------------------------- + // table + + TOML11_INLINE std::ostream& operator<<(std::ostream& os, const table_format f) { + switch (f) { + case table_format::multiline: { + os << "multiline"; + break; + } + case table_format::oneline: { + os << "oneline"; + break; + } + case table_format::dotted: { + os << "dotted"; + break; + } + case table_format::multiline_oneline: { + os << "multiline_oneline"; + break; + } + case table_format::implicit: { + os << "implicit"; + break; + } + default: { + os << "unknown table_format: " << static_cast(f); + break; + } + } + return os; + } + + TOML11_INLINE std::string to_string(const table_format c) { + std::ostringstream oss; + oss << c; + return oss.str(); + } + + TOML11_INLINE bool operator==(const table_format_info& lhs, + const table_format_info& rhs) noexcept { + return lhs.fmt == rhs.fmt && lhs.indent_type == rhs.indent_type && + lhs.body_indent == rhs.body_indent && + lhs.name_indent == rhs.name_indent && + lhs.closing_indent == rhs.closing_indent; + } + + TOML11_INLINE bool operator!=(const table_format_info& lhs, + const table_format_info& rhs) noexcept { + return !(lhs == rhs); + } + +} // namespace toml + #endif // TOML11_FORMAT_IMPL_HPP +#endif + +#endif // TOML11_FORMAT_HPP +#ifndef TOML11_DATETIME_HPP +#define TOML11_DATETIME_HPP + +#ifndef TOML11_DATETIME_FWD_HPP + #define TOML11_DATETIME_FWD_HPP + + #include + #include + #include + #include + #include + #include + +namespace toml { + + enum class month_t : std::uint8_t { + Jan = 0, + Feb = 1, + Mar = 2, + Apr = 3, + May = 4, + Jun = 5, + Jul = 6, + Aug = 7, + Sep = 8, + Oct = 9, + Nov = 10, + Dec = 11 + }; + + // ---------------------------------------------------------------------------- + + struct local_date { + std::int16_t year { 0 }; // A.D. (like, 2018) + std::uint8_t month { 0 }; // [0, 11] + std::uint8_t day { 0 }; // [1, 31] + + local_date(int y, month_t m, int d) + : year { static_cast(y) } + , month { static_cast(m) } + , day { static_cast(d) } {} + + explicit local_date(const std::tm& t) + : year { static_cast(t.tm_year + 1900) } + , month { static_cast(t.tm_mon) } + , day { static_cast(t.tm_mday) } {} + + explicit local_date(const std::chrono::system_clock::time_point& tp); + explicit local_date(const std::time_t t); + + operator std::chrono::system_clock::time_point() const; + operator std::time_t() const; + + local_date() = default; + ~local_date() = default; + local_date(const local_date&) = default; + local_date(local_date&&) = default; + local_date& operator=(const local_date&) = default; + local_date& operator=(local_date&&) = default; + }; + + bool operator==(const local_date& lhs, const local_date& rhs); + bool operator!=(const local_date& lhs, const local_date& rhs); + bool operator<(const local_date& lhs, const local_date& rhs); + bool operator<=(const local_date& lhs, const local_date& rhs); + bool operator>(const local_date& lhs, const local_date& rhs); + bool operator>=(const local_date& lhs, const local_date& rhs); + + std::ostream& operator<<(std::ostream& os, const local_date& date); + std::string to_string(const local_date& date); + + // ----------------------------------------------------------------------------- + + struct local_time { + std::uint8_t hour { 0 }; // [0, 23] + std::uint8_t minute { 0 }; // [0, 59] + std::uint8_t second { 0 }; // [0, 60] + std::uint16_t millisecond { 0 }; // [0, 999] + std::uint16_t microsecond { 0 }; // [0, 999] + std::uint16_t nanosecond { 0 }; // [0, 999] + + local_time(int h, int m, int s, int ms = 0, int us = 0, int ns = 0) + : hour { static_cast(h) } + , minute { static_cast(m) } + , second { static_cast(s) } + , millisecond { static_cast(ms) } + , microsecond { static_cast(us) } + , nanosecond { static_cast(ns) } {} + + explicit local_time(const std::tm& t) + : hour { static_cast(t.tm_hour) } + , minute { static_cast(t.tm_min) } + , second { static_cast(t.tm_sec) } + , millisecond { 0 } + , microsecond { 0 } + , nanosecond { 0 } {} + + template + explicit local_time(const std::chrono::duration& t) { + const auto h = std::chrono::duration_cast(t); + this->hour = static_cast(h.count()); + const auto t2 = t - h; + const auto m = std::chrono::duration_cast(t2); + this->minute = static_cast(m.count()); + const auto t3 = t2 - m; + const auto s = std::chrono::duration_cast(t3); + this->second = static_cast(s.count()); + const auto t4 = t3 - s; + const auto ms = std::chrono::duration_cast(t4); + this->millisecond = static_cast(ms.count()); + const auto t5 = t4 - ms; + const auto us = std::chrono::duration_cast(t5); + this->microsecond = static_cast(us.count()); + const auto t6 = t5 - us; + const auto ns = std::chrono::duration_cast(t6); + this->nanosecond = static_cast(ns.count()); + } + + operator std::chrono::nanoseconds() const; + + local_time() = default; + ~local_time() = default; + local_time(const local_time&) = default; + local_time(local_time&&) = default; + local_time& operator=(const local_time&) = default; + local_time& operator=(local_time&&) = default; + }; + + bool operator==(const local_time& lhs, const local_time& rhs); + bool operator!=(const local_time& lhs, const local_time& rhs); + bool operator<(const local_time& lhs, const local_time& rhs); + bool operator<=(const local_time& lhs, const local_time& rhs); + bool operator>(const local_time& lhs, const local_time& rhs); + bool operator>=(const local_time& lhs, const local_time& rhs); + + std::ostream& operator<<(std::ostream& os, const local_time& time); + std::string to_string(const local_time& time); + + // ---------------------------------------------------------------------------- + + struct time_offset { + std::int8_t hour { 0 }; // [-12, 12] + std::int8_t minute { 0 }; // [-59, 59] + + time_offset(int h, int m) + : hour { static_cast(h) } + , minute { static_cast(m) } {} + + operator std::chrono::minutes() const; + + time_offset() = default; + ~time_offset() = default; + time_offset(const time_offset&) = default; + time_offset(time_offset&&) = default; + time_offset& operator=(const time_offset&) = default; + time_offset& operator=(time_offset&&) = default; + }; + + bool operator==(const time_offset& lhs, const time_offset& rhs); + bool operator!=(const time_offset& lhs, const time_offset& rhs); + bool operator<(const time_offset& lhs, const time_offset& rhs); + bool operator<=(const time_offset& lhs, const time_offset& rhs); + bool operator>(const time_offset& lhs, const time_offset& rhs); + bool operator>=(const time_offset& lhs, const time_offset& rhs); + + std::ostream& operator<<(std::ostream& os, const time_offset& offset); + + std::string to_string(const time_offset& offset); + + // ----------------------------------------------------------------------------- + + struct local_datetime { + local_date date {}; + local_time time {}; + + local_datetime(local_date d, local_time t) : date { d }, time { t } {} + + explicit local_datetime(const std::tm& t) : date { t }, time { t } {} + + explicit local_datetime(const std::chrono::system_clock::time_point& tp); + explicit local_datetime(const std::time_t t); + + operator std::chrono::system_clock::time_point() const; + operator std::time_t() const; + + local_datetime() = default; + ~local_datetime() = default; + local_datetime(const local_datetime&) = default; + local_datetime(local_datetime&&) = default; + local_datetime& operator=(const local_datetime&) = default; + local_datetime& operator=(local_datetime&&) = default; + }; + + bool operator==(const local_datetime& lhs, const local_datetime& rhs); + bool operator!=(const local_datetime& lhs, const local_datetime& rhs); + bool operator<(const local_datetime& lhs, const local_datetime& rhs); + bool operator<=(const local_datetime& lhs, const local_datetime& rhs); + bool operator>(const local_datetime& lhs, const local_datetime& rhs); + bool operator>=(const local_datetime& lhs, const local_datetime& rhs); + + std::ostream& operator<<(std::ostream& os, const local_datetime& dt); + + std::string to_string(const local_datetime& dt); + + // ----------------------------------------------------------------------------- + + struct offset_datetime { + local_date date {}; + local_time time {}; + time_offset offset {}; + + offset_datetime(local_date d, local_time t, time_offset o) + : date { d } + , time { t } + , offset { o } {} + + offset_datetime(const local_datetime& dt, time_offset o) + : date { dt.date } + , time { dt.time } + , offset { o } {} + + // use the current local timezone offset + explicit offset_datetime(const local_datetime& ld); + explicit offset_datetime(const std::chrono::system_clock::time_point& tp); + explicit offset_datetime(const std::time_t& t); + explicit offset_datetime(const std::tm& t); + + operator std::chrono::system_clock::time_point() const; + + operator std::time_t() const; + + offset_datetime() = default; + ~offset_datetime() = default; + offset_datetime(const offset_datetime&) = default; + offset_datetime(offset_datetime&&) = default; + offset_datetime& operator=(const offset_datetime&) = default; + offset_datetime& operator=(offset_datetime&&) = default; + + private: + static time_offset get_local_offset(const std::time_t* tp); + }; + + bool operator==(const offset_datetime& lhs, const offset_datetime& rhs); + bool operator!=(const offset_datetime& lhs, const offset_datetime& rhs); + bool operator<(const offset_datetime& lhs, const offset_datetime& rhs); + bool operator<=(const offset_datetime& lhs, const offset_datetime& rhs); + bool operator>(const offset_datetime& lhs, const offset_datetime& rhs); + bool operator>=(const offset_datetime& lhs, const offset_datetime& rhs); + + std::ostream& operator<<(std::ostream& os, const offset_datetime& dt); + + std::string to_string(const offset_datetime& dt); + +} // namespace toml +#endif // TOML11_DATETIME_FWD_HPP + +#if !defined(TOML11_COMPILE_SOURCES) + #ifndef TOML11_DATETIME_IMPL_HPP + #define TOML11_DATETIME_IMPL_HPP + + #include + #include + #include + #include + #include + #include + #include + +namespace toml { + + // To avoid non-threadsafe std::localtime. In C11 (not C++11!), localtime_s is + // provided in the absolutely same purpose, but C++11 is actually not + // compatible with C11. We need to dispatch the function depending on the OS. + namespace detail { + // TODO: find more sophisticated way to handle this + #if defined(_MSC_VER) + TOML11_INLINE std::tm localtime_s(const std::time_t* src) { + std::tm dst; + const auto result = ::localtime_s(&dst, src); + if (result) { + throw std::runtime_error("localtime_s failed."); + } + return dst; + } + + TOML11_INLINE std::tm gmtime_s(const std::time_t* src) { + std::tm dst; + const auto result = ::gmtime_s(&dst, src); + if (result) { + throw std::runtime_error("gmtime_s failed."); + } + return dst; + } + #elif (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 1) || \ + defined(_XOPEN_SOURCE) || defined(_BSD_SOURCE) || \ + defined(_SVID_SOURCE) || defined(_POSIX_SOURCE) + TOML11_INLINE std::tm localtime_s(const std::time_t* src) { + std::tm dst; + const auto result = ::localtime_r(src, &dst); + if (!result) { + throw std::runtime_error("localtime_r failed."); + } + return dst; + } + + TOML11_INLINE std::tm gmtime_s(const std::time_t* src) { + std::tm dst; + const auto result = ::gmtime_r(src, &dst); + if (!result) { + throw std::runtime_error("gmtime_r failed."); + } + return dst; + } + #else // fallback. not threadsafe + TOML11_INLINE std::tm localtime_s(const std::time_t* src) { + const auto result = std::localtime(src); + if (!result) { + throw std::runtime_error("localtime failed."); + } + return *result; + } + + TOML11_INLINE std::tm gmtime_s(const std::time_t* src) { + const auto result = std::gmtime(src); + if (!result) { + throw std::runtime_error("gmtime failed."); + } + return *result; + } + #endif + } // namespace detail + + // ---------------------------------------------------------------------------- + + TOML11_INLINE local_date::local_date( + const std::chrono::system_clock::time_point& tp) { + const auto t = std::chrono::system_clock::to_time_t(tp); + const auto time = detail::localtime_s(&t); + *this = local_date(time); + } + + TOML11_INLINE local_date::local_date(const std::time_t t) + : local_date { std::chrono::system_clock::from_time_t(t) } {} + + TOML11_INLINE local_date::operator std::chrono::system_clock::time_point() const { + // std::mktime returns date as local time zone. no conversion needed + std::tm t; + t.tm_sec = 0; + t.tm_min = 0; + t.tm_hour = 0; + t.tm_mday = static_cast(this->day); + t.tm_mon = static_cast(this->month); + t.tm_year = static_cast(this->year) - 1900; + t.tm_wday = 0; // the value will be ignored + t.tm_yday = 0; // the value will be ignored + t.tm_isdst = -1; + return std::chrono::system_clock::from_time_t(std::mktime(&t)); + } + + TOML11_INLINE local_date::operator std::time_t() const { + return std::chrono::system_clock::to_time_t( + std::chrono::system_clock::time_point(*this)); + } + + TOML11_INLINE bool operator==(const local_date& lhs, const local_date& rhs) { + return std::make_tuple(lhs.year, lhs.month, lhs.day) == + std::make_tuple(rhs.year, rhs.month, rhs.day); + } + + TOML11_INLINE bool operator!=(const local_date& lhs, const local_date& rhs) { + return !(lhs == rhs); + } + + TOML11_INLINE bool operator<(const local_date& lhs, const local_date& rhs) { + return std::make_tuple(lhs.year, lhs.month, lhs.day) < + std::make_tuple(rhs.year, rhs.month, rhs.day); + } + + TOML11_INLINE bool operator<=(const local_date& lhs, const local_date& rhs) { + return (lhs < rhs) || (lhs == rhs); + } + + TOML11_INLINE bool operator>(const local_date& lhs, const local_date& rhs) { + return !(lhs <= rhs); + } + + TOML11_INLINE bool operator>=(const local_date& lhs, const local_date& rhs) { + return !(lhs < rhs); + } + + TOML11_INLINE std::ostream& operator<<(std::ostream& os, const local_date& date) { + os << std::setfill('0') << std::setw(4) << static_cast(date.year) << '-'; + os << std::setfill('0') << std::setw(2) << static_cast(date.month) + 1 + << '-'; + os << std::setfill('0') << std::setw(2) << static_cast(date.day); + return os; + } + + TOML11_INLINE std::string to_string(const local_date& date) { + std::ostringstream oss; + oss.imbue(std::locale::classic()); + oss << date; + return oss.str(); + } + + // ----------------------------------------------------------------------------- + + TOML11_INLINE local_time::operator std::chrono::nanoseconds() const { + return std::chrono::nanoseconds(this->nanosecond) + + std::chrono::microseconds(this->microsecond) + + std::chrono::milliseconds(this->millisecond) + + std::chrono::seconds(this->second) + + std::chrono::minutes(this->minute) + std::chrono::hours(this->hour); + } + + TOML11_INLINE bool operator==(const local_time& lhs, const local_time& rhs) { + return std::make_tuple(lhs.hour, + lhs.minute, + lhs.second, + lhs.millisecond, + lhs.microsecond, + lhs.nanosecond) == std::make_tuple(rhs.hour, + rhs.minute, + rhs.second, + rhs.millisecond, + rhs.microsecond, + rhs.nanosecond); + } + + TOML11_INLINE bool operator!=(const local_time& lhs, const local_time& rhs) { + return !(lhs == rhs); + } + + TOML11_INLINE bool operator<(const local_time& lhs, const local_time& rhs) { + return std::make_tuple(lhs.hour, + lhs.minute, + lhs.second, + lhs.millisecond, + lhs.microsecond, + lhs.nanosecond) < std::make_tuple(rhs.hour, + rhs.minute, + rhs.second, + rhs.millisecond, + rhs.microsecond, + rhs.nanosecond); + } + + TOML11_INLINE bool operator<=(const local_time& lhs, const local_time& rhs) { + return (lhs < rhs) || (lhs == rhs); + } + + TOML11_INLINE bool operator>(const local_time& lhs, const local_time& rhs) { + return !(lhs <= rhs); + } + + TOML11_INLINE bool operator>=(const local_time& lhs, const local_time& rhs) { + return !(lhs < rhs); + } + + TOML11_INLINE std::ostream& operator<<(std::ostream& os, const local_time& time) { + os << std::setfill('0') << std::setw(2) << static_cast(time.hour) << ':'; + os << std::setfill('0') << std::setw(2) << static_cast(time.minute) << ':'; + os << std::setfill('0') << std::setw(2) << static_cast(time.second); + if (time.millisecond != 0 || time.microsecond != 0 || time.nanosecond != 0) { + os << '.'; + os << std::setfill('0') << std::setw(3) + << static_cast(time.millisecond); + if (time.microsecond != 0 || time.nanosecond != 0) { + os << std::setfill('0') << std::setw(3) + << static_cast(time.microsecond); + if (time.nanosecond != 0) { + os << std::setfill('0') << std::setw(3) + << static_cast(time.nanosecond); + } + } + } + return os; + } + + TOML11_INLINE std::string to_string(const local_time& time) { + std::ostringstream oss; + oss.imbue(std::locale::classic()); + oss << time; + return oss.str(); + } + + // ---------------------------------------------------------------------------- + + TOML11_INLINE time_offset::operator std::chrono::minutes() const { + return std::chrono::minutes(this->minute) + std::chrono::hours(this->hour); + } + + TOML11_INLINE bool operator==(const time_offset& lhs, const time_offset& rhs) { + return std::make_tuple(lhs.hour, lhs.minute) == + std::make_tuple(rhs.hour, rhs.minute); + } + + TOML11_INLINE bool operator!=(const time_offset& lhs, const time_offset& rhs) { + return !(lhs == rhs); + } + + TOML11_INLINE bool operator<(const time_offset& lhs, const time_offset& rhs) { + return std::make_tuple(lhs.hour, lhs.minute) < + std::make_tuple(rhs.hour, rhs.minute); + } + + TOML11_INLINE bool operator<=(const time_offset& lhs, const time_offset& rhs) { + return (lhs < rhs) || (lhs == rhs); + } + + TOML11_INLINE bool operator>(const time_offset& lhs, const time_offset& rhs) { + return !(lhs <= rhs); + } + + TOML11_INLINE bool operator>=(const time_offset& lhs, const time_offset& rhs) { + return !(lhs < rhs); + } + + TOML11_INLINE std::ostream& operator<<(std::ostream& os, + const time_offset& offset) { + if (offset.hour == 0 && offset.minute == 0) { + os << 'Z'; + return os; + } + int minute = static_cast(offset.hour) * 60 + offset.minute; + if (minute < 0) { + os << '-'; + minute = std::abs(minute); + } else { + os << '+'; + } + os << std::setfill('0') << std::setw(2) << minute / 60 << ':'; + os << std::setfill('0') << std::setw(2) << minute % 60; + return os; + } + + TOML11_INLINE std::string to_string(const time_offset& offset) { + std::ostringstream oss; + oss.imbue(std::locale::classic()); + oss << offset; + return oss.str(); + } + + // ----------------------------------------------------------------------------- + + TOML11_INLINE local_datetime::local_datetime( + const std::chrono::system_clock::time_point& tp) { + const auto t = std::chrono::system_clock::to_time_t(tp); + std::tm ltime = detail::localtime_s(&t); + + this->date = local_date(ltime); + this->time = local_time(ltime); + + // std::tm lacks subsecond information, so diff between tp and tm + // can be used to get millisecond & microsecond information. + const auto t_diff = tp - std::chrono::system_clock::from_time_t( + std::mktime(<ime)); + this->time.millisecond = static_cast( + std::chrono::duration_cast(t_diff).count()); + this->time.microsecond = static_cast( + std::chrono::duration_cast(t_diff).count()); + this->time.nanosecond = static_cast( + std::chrono::duration_cast(t_diff).count()); + } + + TOML11_INLINE local_datetime::local_datetime(const std::time_t t) + : local_datetime { std::chrono::system_clock::from_time_t(t) } {} + + TOML11_INLINE local_datetime::operator std::chrono::system_clock::time_point() const { + using internal_duration = typename std::chrono::system_clock::time_point::duration; + + // Normally DST begins at A.M. 3 or 4. If we re-use conversion operator + // of local_date and local_time independently, the conversion fails if + // it is the day when DST begins or ends. Since local_date considers the + // time is 00:00 A.M. and local_time does not consider DST because it + // does not have any date information. We need to consider both date and + // time information at the same time to convert it correctly. + + std::tm t; + t.tm_sec = static_cast(this->time.second); + t.tm_min = static_cast(this->time.minute); + t.tm_hour = static_cast(this->time.hour); + t.tm_mday = static_cast(this->date.day); + t.tm_mon = static_cast(this->date.month); + t.tm_year = static_cast(this->date.year) - 1900; + t.tm_wday = 0; // the value will be ignored + t.tm_yday = 0; // the value will be ignored + t.tm_isdst = -1; + + // std::mktime returns date as local time zone. no conversion needed + auto dt = std::chrono::system_clock::from_time_t(std::mktime(&t)); + dt += std::chrono::duration_cast( + std::chrono::milliseconds(this->time.millisecond) + + std::chrono::microseconds(this->time.microsecond) + + std::chrono::nanoseconds(this->time.nanosecond)); + return dt; + } + + TOML11_INLINE local_datetime::operator std::time_t() const { + return std::chrono::system_clock::to_time_t( + std::chrono::system_clock::time_point(*this)); + } + + TOML11_INLINE bool operator==(const local_datetime& lhs, + const local_datetime& rhs) { + return std::make_tuple(lhs.date, lhs.time) == + std::make_tuple(rhs.date, rhs.time); + } + + TOML11_INLINE bool operator!=(const local_datetime& lhs, + const local_datetime& rhs) { + return !(lhs == rhs); + } + + TOML11_INLINE bool operator<(const local_datetime& lhs, + const local_datetime& rhs) { + return std::make_tuple(lhs.date, lhs.time) < + std::make_tuple(rhs.date, rhs.time); + } + + TOML11_INLINE bool operator<=(const local_datetime& lhs, + const local_datetime& rhs) { + return (lhs < rhs) || (lhs == rhs); + } + + TOML11_INLINE bool operator>(const local_datetime& lhs, + const local_datetime& rhs) { + return !(lhs <= rhs); + } + + TOML11_INLINE bool operator>=(const local_datetime& lhs, + const local_datetime& rhs) { + return !(lhs < rhs); + } + + TOML11_INLINE std::ostream& operator<<(std::ostream& os, + const local_datetime& dt) { + os << dt.date << 'T' << dt.time; + return os; + } + + TOML11_INLINE std::string to_string(const local_datetime& dt) { + std::ostringstream oss; + oss.imbue(std::locale::classic()); + oss << dt; + return oss.str(); + } + + // ----------------------------------------------------------------------------- + + TOML11_INLINE offset_datetime::offset_datetime(const local_datetime& ld) + : date { ld.date } + , time { ld.time } + , offset { get_local_offset(nullptr) } + // use the current local timezone offset + {} + + TOML11_INLINE offset_datetime::offset_datetime( + const std::chrono::system_clock::time_point& tp) + : offset { 0, 0 } // use gmtime + { + const auto timet = std::chrono::system_clock::to_time_t(tp); + const auto tm = detail::gmtime_s(&timet); + this->date = local_date(tm); + this->time = local_time(tm); + } + + TOML11_INLINE offset_datetime::offset_datetime(const std::time_t& t) + : offset { 0, 0 } // use gmtime + { + const auto tm = detail::gmtime_s(&t); + this->date = local_date(tm); + this->time = local_time(tm); + } + + TOML11_INLINE offset_datetime::offset_datetime(const std::tm& t) + : offset { 0, 0 } // assume gmtime + { + this->date = local_date(t); + this->time = local_time(t); + } + + TOML11_INLINE offset_datetime::operator std::chrono::system_clock::time_point() const { + // get date-time + using internal_duration = typename std::chrono::system_clock::time_point::duration; + + // first, convert it to local date-time information in the same way as + // local_datetime does. later we will use time_t to adjust time offset. + std::tm t; + t.tm_sec = static_cast(this->time.second); + t.tm_min = static_cast(this->time.minute); + t.tm_hour = static_cast(this->time.hour); + t.tm_mday = static_cast(this->date.day); + t.tm_mon = static_cast(this->date.month); + t.tm_year = static_cast(this->date.year) - 1900; + t.tm_wday = 0; // the value will be ignored + t.tm_yday = 0; // the value will be ignored + t.tm_isdst = -1; + const std::time_t tp_loc = std::mktime(std::addressof(t)); + + auto tp = std::chrono::system_clock::from_time_t(tp_loc); + tp += std::chrono::duration_cast( + std::chrono::milliseconds(this->time.millisecond) + + std::chrono::microseconds(this->time.microsecond) + + std::chrono::nanoseconds(this->time.nanosecond)); + + // Since mktime uses local time zone, it should be corrected. + // `12:00:00+09:00` means `03:00:00Z`. So mktime returns `03:00:00Z` if + // we are in `+09:00` timezone. To represent `12:00:00Z` there, we need + // to add `+09:00` to `03:00:00Z`. + // Here, it uses the time_t converted from date-time info to handle + // daylight saving time. + const auto ofs = get_local_offset(std::addressof(tp_loc)); + tp += std::chrono::hours(ofs.hour); + tp += std::chrono::minutes(ofs.minute); + + // We got `12:00:00Z` by correcting local timezone applied by mktime. + // Then we will apply the offset. Let's say `12:00:00-08:00` is given. + // And now, we have `12:00:00Z`. `12:00:00-08:00` means `20:00:00Z`. + // So we need to subtract the offset. + tp -= std::chrono::minutes(this->offset); + return tp; + } + + TOML11_INLINE offset_datetime::operator std::time_t() const { + return std::chrono::system_clock::to_time_t( + std::chrono::system_clock::time_point(*this)); + } + + TOML11_INLINE time_offset offset_datetime::get_local_offset(const std::time_t* tp) { + // get local timezone with the same date-time information as mktime + const auto t = detail::localtime_s(tp); + + std::array buf; + const auto result = std::strftime(buf.data(), 6, "%z", &t); // +hhmm\0 + if (result != 5) { + throw std::runtime_error("toml::offset_datetime: cannot obtain " + "timezone information of current env"); + } + const int ofs = std::atoi(buf.data()); + const int ofs_h = ofs / 100; + const int ofs_m = ofs - (ofs_h * 100); + return time_offset(ofs_h, ofs_m); + } + + TOML11_INLINE bool operator==(const offset_datetime& lhs, + const offset_datetime& rhs) { + return std::make_tuple(lhs.date, lhs.time, lhs.offset) == + std::make_tuple(rhs.date, rhs.time, rhs.offset); + } + + TOML11_INLINE bool operator!=(const offset_datetime& lhs, + const offset_datetime& rhs) { + return !(lhs == rhs); + } + + TOML11_INLINE bool operator<(const offset_datetime& lhs, + const offset_datetime& rhs) { + return std::make_tuple(lhs.date, lhs.time, lhs.offset) < + std::make_tuple(rhs.date, rhs.time, rhs.offset); + } + + TOML11_INLINE bool operator<=(const offset_datetime& lhs, + const offset_datetime& rhs) { + return (lhs < rhs) || (lhs == rhs); + } + + TOML11_INLINE bool operator>(const offset_datetime& lhs, + const offset_datetime& rhs) { + return !(lhs <= rhs); + } + + TOML11_INLINE bool operator>=(const offset_datetime& lhs, + const offset_datetime& rhs) { + return !(lhs < rhs); + } + + TOML11_INLINE std::ostream& operator<<(std::ostream& os, + const offset_datetime& dt) { + os << dt.date << 'T' << dt.time << dt.offset; + return os; + } + + TOML11_INLINE std::string to_string(const offset_datetime& dt) { + std::ostringstream oss; + oss.imbue(std::locale::classic()); + oss << dt; + return oss.str(); + } + +} // namespace toml + #endif // TOML11_DATETIME_IMPL_HPP +#endif + +#endif // TOML11_DATETIME_HPP +#ifndef TOML11_COMPAT_HPP +#define TOML11_COMPAT_HPP + +#include +#include +#include +#include +#include +#include + +#if TOML11_CPLUSPLUS_STANDARD_VERSION >= TOML11_CXX20_VALUE + #if __has_include() + #include + #endif +#endif + +#include + +// ---------------------------------------------------------------------------- + +#if TOML11_CPLUSPLUS_STANDARD_VERSION >= TOML11_CXX14_VALUE + #if __has_cpp_attribute(deprecated) + #define TOML11_HAS_ATTR_DEPRECATED 1 + #endif +#endif + +#if defined(TOML11_HAS_ATTR_DEPRECATED) + #define TOML11_DEPRECATED(msg) [[deprecated(msg)]] +#elif defined(__GNUC__) + #define TOML11_DEPRECATED(msg) __attribute__((deprecated(msg))) +#elif defined(_MSC_VER) + #define TOML11_DEPRECATED(msg) __declspec(deprecated(msg)) +#else + #define TOML11_DEPRECATED(msg) +#endif + +// ---------------------------------------------------------------------------- + +#if defined(__cpp_if_constexpr) + #if __cpp_if_constexpr >= 201606L + #define TOML11_HAS_CONSTEXPR_IF 1 + #endif +#endif + +#if defined(TOML11_HAS_CONSTEXPR_IF) + #define TOML11_CONSTEXPR_IF if constexpr +#else + #define TOML11_CONSTEXPR_IF if +#endif + +// ---------------------------------------------------------------------------- + +#if TOML11_CPLUSPLUS_STANDARD_VERSION >= TOML11_CXX14_VALUE + #if defined(__cpp_lib_make_unique) + #if __cpp_lib_make_unique >= 201304L + #define TOML11_HAS_STD_MAKE_UNIQUE 1 + #endif + #endif +#endif + +namespace toml { + namespace cxx { + +#if defined(TOML11_HAS_STD_MAKE_UNIQUE) + + using std::make_unique; + +#else + + template + std::unique_ptr make_unique(Ts&&... args) { + return std::unique_ptr(new T(std::forward(args)...)); + } + +#endif // TOML11_HAS_STD_MAKE_UNIQUE + + } // namespace cxx +} // namespace toml + +// --------------------------------------------------------------------------- + +#if TOML11_CPLUSPLUS_STANDARD_VERSION >= TOML11_CXX14_VALUE + #if defined(__cpp_lib_make_reverse_iterator) + #if __cpp_lib_make_reverse_iterator >= 201402L + #define TOML11_HAS_STD_MAKE_REVERSE_ITERATOR 1 + #endif + #endif +#endif + +namespace toml { + namespace cxx { +#if defined(TOML11_HAS_STD_MAKE_REVERSE_ITERATOR) + + using std::make_reverse_iterator; + +#else + + template + std::reverse_iterator make_reverse_iterator(Iterator iter) { + return std::reverse_iterator(iter); + } + +#endif // TOML11_HAS_STD_MAKE_REVERSE_ITERATOR + + } // namespace cxx +} // namespace toml + +// --------------------------------------------------------------------------- + +#if TOML11_CPLUSPLUS_STANDARD_VERSION >= TOML11_CXX20_VALUE + #if defined(__cpp_lib_clamp) + #if __cpp_lib_clamp >= 201603L + #define TOML11_HAS_STD_CLAMP 1 + #endif + #endif +#endif + +namespace toml { + namespace cxx { +#if defined(TOML11_HAS_STD_CLAMP) + + using std::clamp; + +#else + + template + T clamp(const T& x, const T& low, const T& high) noexcept { + assert(low <= high); + return (std::min)((std::max)(x, low), high); + } + +#endif // TOML11_HAS_STD_CLAMP + + } // namespace cxx +} // namespace toml + +// --------------------------------------------------------------------------- + +#if TOML11_CPLUSPLUS_STANDARD_VERSION >= TOML11_CXX20_VALUE + #if defined(__cpp_lib_bit_cast) + #if __cpp_lib_bit_cast >= 201806L + #define TOML11_HAS_STD_BIT_CAST 1 + #endif + #endif +#endif + +namespace toml { + namespace cxx { +#if defined(TOML11_HAS_STD_BIT_CAST) + + using std::bit_cast; + +#else + + template + U bit_cast(const T& x) noexcept { + static_assert(sizeof(T) == sizeof(U), ""); + static_assert(std::is_default_constructible::value, ""); + + U z; + std::memcpy(reinterpret_cast(std::addressof(z)), + reinterpret_cast(std::addressof(x)), + sizeof(T)); + + return z; + } + +#endif // TOML11_HAS_STD_BIT_CAST + + } // namespace cxx +} // namespace toml + +// --------------------------------------------------------------------------- +// C++20 remove_cvref_t + +#if TOML11_CPLUSPLUS_STANDARD_VERSION >= TOML11_CXX20_VALUE + #if defined(__cpp_lib_remove_cvref) + #if __cpp_lib_remove_cvref >= 201711L + #define TOML11_HAS_STD_REMOVE_CVREF 1 + #endif + #endif +#endif + +namespace toml { + namespace cxx { +#if defined(TOML11_HAS_STD_REMOVE_CVREF) + + using std::remove_cvref; + using std::remove_cvref_t; + +#else + + template + struct remove_cvref { + using type = typename std::remove_cv::type>::type; + }; + + template + using remove_cvref_t = typename remove_cvref::type; + +#endif // TOML11_HAS_STD_REMOVE_CVREF + + } // namespace cxx +} // namespace toml + +// --------------------------------------------------------------------------- +// C++17 and/or/not + +#if TOML11_CPLUSPLUS_STANDARD_VERSION >= TOML11_CXX17_VALUE + #if defined(__cpp_lib_logical_traits) + #if __cpp_lib_logical_traits >= 201510L + #define TOML11_HAS_STD_CONJUNCTION 1 + #endif + #endif +#endif + +namespace toml { + namespace cxx { +#if defined(TOML11_HAS_STD_CONJUNCTION) + + using std::conjunction; + using std::disjunction; + using std::negation; + +#else + + template + struct conjunction : std::true_type {}; + + template + struct conjunction : T {}; + + template + struct conjunction + : std::conditional(T::value), conjunction, T>::type { + }; + + template + struct disjunction : std::false_type {}; + + template + struct disjunction : T {}; + + template + struct disjunction + : std::conditional(T::value), T, disjunction>::type { + }; + + template + struct negation + : std::integral_constant(T::value)> {}; + +#endif // TOML11_HAS_STD_CONJUNCTION + + } // namespace cxx +} // namespace toml + +// --------------------------------------------------------------------------- +// C++14 index_sequence + +#if TOML11_CPLUSPLUS_STANDARD_VERSION >= TOML11_CXX14_VALUE + #if defined(__cpp_lib_integer_sequence) + #if __cpp_lib_integer_sequence >= 201304L + #define TOML11_HAS_STD_INTEGER_SEQUENCE 1 + #endif + #endif +#endif + +namespace toml { + namespace cxx { +#if defined(TOML11_HAS_STD_INTEGER_SEQUENCE) + + using std::index_sequence; + using std::make_index_sequence; + +#else + + template + struct index_sequence {}; + + template + struct double_index_sequence; + + template + struct double_index_sequence> { + using type = index_sequence; + }; + + template + struct double_index_sequence> { + using type = index_sequence; + }; + + template + struct index_sequence_maker { + using type = + typename double_index_sequence::type>::type; + }; + + template <> + struct index_sequence_maker<0> { + using type = index_sequence<>; + }; + + template + using make_index_sequence = typename index_sequence_maker::type; + +#endif // TOML11_HAS_STD_INTEGER_SEQUENCE + + } // namespace cxx +} // namespace toml + +// --------------------------------------------------------------------------- +// C++14 enable_if_t + +#if TOML11_CPLUSPLUS_STANDARD_VERSION >= TOML11_CXX14_VALUE + #if defined(__cpp_lib_transformation_trait_aliases) + #if __cpp_lib_transformation_trait_aliases >= 201304L + #define TOML11_HAS_STD_ENABLE_IF_T 1 + #endif + #endif +#endif + +namespace toml { + namespace cxx { +#if defined(TOML11_HAS_STD_ENABLE_IF_T) + + using std::enable_if_t; + +#else + + template + using enable_if_t = typename std::enable_if::type; + +#endif // TOML11_HAS_STD_ENABLE_IF_T + + } // namespace cxx +} // namespace toml + +// --------------------------------------------------------------------------- +// return_type_of_t + +#if TOML11_CPLUSPLUS_STANDARD_VERSION >= TOML11_CXX17_VALUE + #if defined(__cpp_lib_is_invocable) + #if __cpp_lib_is_invocable >= 201703 + #define TOML11_HAS_STD_INVOKE_RESULT 1 + #endif + #endif +#endif + +namespace toml { + namespace cxx { +#if defined(TOML11_HAS_STD_INVOKE_RESULT) + + template + using return_type_of_t = std::invoke_result_t; + +#else + + // result_of is deprecated after C++17 + template + using return_type_of_t = typename std::result_of::type; + +#endif // TOML11_HAS_STD_INVOKE_RESULT + + } // namespace cxx +} // namespace toml + +// ---------------------------------------------------------------------------- +// (subset of) source_location + +#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 202002L + #if __has_include() + #define TOML11_HAS_STD_SOURCE_LOCATION + #endif // has_include +#endif // c++20 + +#if !defined(TOML11_HAS_STD_SOURCE_LOCATION) + #if defined(__GNUC__) && !defined(__clang__) + #if TOML11_CPLUSPLUS_STANDARD_VERSION >= TOML11_CXX14_VALUE + #if __has_include() + #define TOML11_HAS_EXPERIMENTAL_SOURCE_LOCATION + #endif + #endif + #endif // GNU g++ +#endif // not TOML11_HAS_STD_SOURCE_LOCATION + +#if !defined(TOML11_HAS_STD_SOURCE_LOCATION) && \ + !defined(TOML11_HAS_EXPERIMENTAL_SOURCE_LOCATION) + #if defined(__GNUC__) && !defined(__clang__) + #if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9)) + #define TOML11_HAS_BUILTIN_FILE_LINE 1 + #define TOML11_BUILTIN_LINE_TYPE int + #endif + #elif defined(__clang__) // clang 9.0.0 implements builtin_FILE/LINE + #if __has_builtin(__builtin_FILE) && __has_builtin(__builtin_LINE) + #define TOML11_HAS_BUILTIN_FILE_LINE 1 + #define TOML11_BUILTIN_LINE_TYPE unsigned int + #endif + #elif defined(_MSVC_LANG) && defined(_MSC_VER) + #if _MSC_VER > 1926 + #define TOML11_HAS_BUILTIN_FILE_LINE 1 + #define TOML11_BUILTIN_LINE_TYPE int + #endif + #endif +#endif + +#if defined(TOML11_HAS_STD_SOURCE_LOCATION) + #include + +namespace toml { + namespace cxx { + using source_location = std::source_location; + + inline std::string to_string(const source_location& loc) { + return std::string(" at line ") + std::to_string(loc.line()) + + std::string(" in file ") + std::string(loc.file_name()); + } + } // namespace cxx +} // namespace toml +#elif defined(TOML11_HAS_EXPERIMENTAL_SOURCE_LOCATION) + #include + +namespace toml { + namespace cxx { + using source_location = std::experimental::source_location; + + inline std::string to_string(const source_location& loc) { + return std::string(" at line ") + std::to_string(loc.line()) + + std::string(" in file ") + std::string(loc.file_name()); + } + } // namespace cxx +} // namespace toml +#elif defined(TOML11_HAS_BUILTIN_FILE_LINE) +namespace toml { + namespace cxx { + struct source_location { + using line_type = TOML11_BUILTIN_LINE_TYPE; + + static source_location current(const line_type line = __builtin_LINE(), + const char* file = __builtin_FILE()) { + return source_location(line, file); + } + + source_location(const line_type line, const char* file) + : line_(line) + , file_name_(file) {} + + line_type line() const noexcept { + return line_; + } + + const char* file_name() const noexcept { + return file_name_; + } + + private: + line_type line_; + const char* file_name_; + }; + + inline std::string to_string(const source_location& loc) { + return std::string(" at line ") + std::to_string(loc.line()) + + std::string(" in file ") + std::string(loc.file_name()); + } + } // namespace cxx +} // namespace toml +#else // no builtin +namespace toml { + namespace cxx { + struct source_location { + static source_location current() { + return source_location {}; + } + }; + + inline std::string to_string(const source_location&) { + return std::string(""); + } + } // namespace cxx +} // namespace toml +#endif // TOML11_HAS_STD_SOURCE_LOCATION + +// ---------------------------------------------------------------------------- +// (subset of) optional + +#if TOML11_CPLUSPLUS_STANDARD_VERSION >= TOML11_CXX17_VALUE + #if __has_include() + #include + #endif // has_include(optional) +#endif // C++17 + +#if TOML11_CPLUSPLUS_STANDARD_VERSION >= TOML11_CXX17_VALUE + #if defined(__cpp_lib_optional) + #if __cpp_lib_optional >= 201606L + #define TOML11_HAS_STD_OPTIONAL 1 + #endif + #endif +#endif + +#if defined(TOML11_HAS_STD_OPTIONAL) + +namespace toml { + namespace cxx { + using std::optional; + + inline std::nullopt_t make_nullopt() { + return std::nullopt; + } + + template + std::basic_ostream& operator<<( + std::basic_ostream& os, + const std::nullopt_t&) { + os << "nullopt"; + return os; + } + + } // namespace cxx +} // namespace toml + +#else // TOML11_HAS_STD_OPTIONAL + +namespace toml { + namespace cxx { + + struct nullopt_t {}; + + inline nullopt_t make_nullopt() { + return nullopt_t {}; + } + + inline bool operator==(const nullopt_t&, const nullopt_t&) noexcept { + return true; + } + + inline bool operator!=(const nullopt_t&, const nullopt_t&) noexcept { + return false; + } + + inline bool operator<(const nullopt_t&, const nullopt_t&) noexcept { + return false; + } + + inline bool operator<=(const nullopt_t&, const nullopt_t&) noexcept { + return true; + } + + inline bool operator>(const nullopt_t&, const nullopt_t&) noexcept { + return false; + } + + inline bool operator>=(const nullopt_t&, const nullopt_t&) noexcept { + return true; + } + + template + std::basic_ostream& operator<<( + std::basic_ostream& os, + const nullopt_t&) { + os << "nullopt"; + return os; + } + + template + class optional { + public: + using value_type = T; + + public: + optional() noexcept : has_value_(false), null_('\0') {} + + optional(nullopt_t) noexcept : has_value_(false), null_('\0') {} + + optional(const T& x) : has_value_(true), value_(x) {} + + optional(T&& x) : has_value_(true), value_(std::move(x)) {} + + template ::value, std::nullptr_t> = nullptr> + explicit optional(U&& x) : has_value_(true) + , value_(std::forward(x)) {} + + optional(const optional& rhs) : has_value_(rhs.has_value_) { + if (rhs.has_value_) { + this->assigner(rhs.value_); + } + } + + optional(optional&& rhs) : has_value_(rhs.has_value_) { + if (this->has_value_) { + this->assigner(std::move(rhs.value_)); + } + } + + optional& operator=(const optional& rhs) { + if (this == std::addressof(rhs)) { + return *this; + } + + this->cleanup(); + this->has_value_ = rhs.has_value_; + if (this->has_value_) { + this->assigner(rhs.value_); + } + return *this; + } + + optional& operator=(optional&& rhs) { + if (this == std::addressof(rhs)) { + return *this; + } + + this->cleanup(); + this->has_value_ = rhs.has_value_; + if (this->has_value_) { + this->assigner(std::move(rhs.value_)); + } + return *this; + } + + template >, + std::is_constructible>::value, + std::nullptr_t> = nullptr> + explicit optional(const optional& rhs) + : has_value_(rhs.has_value_) + , null_('\0') { + if (rhs.has_value_) { + this->assigner(rhs.value_); + } + } + + template >, + std::is_constructible>::value, + std::nullptr_t> = nullptr> + explicit optional(optional&& rhs) + : has_value_(rhs.has_value_) + , null_('\0') { + if (this->has_value_) { + this->assigner(std::move(rhs.value_)); + } + } + + template >, + std::is_constructible>::value, + std::nullptr_t> = nullptr> + optional& operator=(const optional& rhs) { + if (this == std::addressof(rhs)) { + return *this; + } + + this->cleanup(); + this->has_value_ = rhs.has_value_; + if (this->has_value_) { + this->assigner(rhs.value_); + } + return *this; + } + + template >, + std::is_constructible>::value, + std::nullptr_t> = nullptr> + optional& operator=(optional&& rhs) { + if (this == std::addressof(rhs)) { + return *this; + } + + this->cleanup(); + this->has_value_ = rhs.has_value_; + if (this->has_value_) { + this->assigner(std::move(rhs.value_)); + } + return *this; + } + + ~optional() noexcept { + this->cleanup(); + } + + explicit operator bool() const noexcept { + return has_value_; + } + + bool has_value() const noexcept { + return has_value_; + } + + const value_type& value(source_location loc = source_location::current()) const { + if (!this->has_value_) { + throw std::runtime_error( + "optional::value(): bad_unwrap" + to_string(loc)); + } + return this->value_; + } + + value_type& value(source_location loc = source_location::current()) { + if (!this->has_value_) { + throw std::runtime_error( + "optional::value(): bad_unwrap" + to_string(loc)); + } + return this->value_; + } + + const value_type& value_or(const value_type& opt) const { + if (this->has_value_) { + return this->value_; + } else { + return opt; + } + } + + value_type& value_or(value_type& opt) { + if (this->has_value_) { + return this->value_; + } else { + return opt; + } + } + + private: + void cleanup() noexcept { + if (this->has_value_) { + value_.~T(); + } + } + + template + void assigner(U&& x) { + const auto tmp = ::new (std::addressof(this->value_)) + value_type(std::forward(x)); + assert(tmp == std::addressof(this->value_)); + (void)tmp; + } + + private: + bool has_value_; + + union { + char null_; + T value_; + }; + }; + } // namespace cxx +} // namespace toml +#endif // TOML11_HAS_STD_OPTIONAL + +#endif // TOML11_COMPAT_HPP +#ifndef TOML11_VALUE_T_HPP +#define TOML11_VALUE_T_HPP + +#ifndef TOML11_VALUE_T_FWD_HPP + #define TOML11_VALUE_T_FWD_HPP + + #include + #include + #include + #include + +namespace toml { + + // forward decl + template + class basic_value; + + // ---------------------------------------------------------------------------- + // enum representing toml types + + enum class value_t : std::uint8_t { + empty = 0, + boolean = 1, + integer = 2, + floating = 3, + string = 4, + offset_datetime = 5, + local_datetime = 6, + local_date = 7, + local_time = 8, + array = 9, + table = 10 + }; + + std::ostream& operator<<(std::ostream& os, value_t t); + std::string to_string(value_t t); + + // ---------------------------------------------------------------------------- + // meta functions for internal use + + namespace detail { + + template + using value_t_constant = std::integral_constant; + + template + struct type_to_enum : value_t_constant {}; + + template + struct type_to_enum + : value_t_constant {}; + + template + struct type_to_enum + : value_t_constant {}; + + template + struct type_to_enum + : value_t_constant {}; + + template + struct type_to_enum + : value_t_constant {}; + + template + struct type_to_enum + : value_t_constant {}; + + template + struct type_to_enum + : value_t_constant {}; + + template + struct type_to_enum + : value_t_constant {}; + + template + struct type_to_enum + : value_t_constant {}; + + template + struct type_to_enum + : value_t_constant {}; + + template + struct type_to_enum + : value_t_constant {}; + + template + struct enum_to_type { + using type = void; + }; + + template + struct enum_to_type { + using type = typename V::boolean_type; + }; + + template + struct enum_to_type { + using type = typename V::integer_type; + }; + + template + struct enum_to_type { + using type = typename V::floating_type; + }; + + template + struct enum_to_type { + using type = typename V::string_type; + }; + + template + struct enum_to_type { + using type = typename V::offset_datetime_type; + }; + + template + struct enum_to_type { + using type = typename V::local_datetime_type; + }; + + template + struct enum_to_type { + using type = typename V::local_date_type; + }; + + template + struct enum_to_type { + using type = typename V::local_time_type; + }; + + template + struct enum_to_type { + using type = typename V::array_type; + }; + + template + struct enum_to_type { + using type = typename V::table_type; + }; + + template + using enum_to_type_t = typename enum_to_type::type; + + template + struct enum_to_fmt_type { + using type = void; + }; + + template <> + struct enum_to_fmt_type { + using type = boolean_format_info; + }; + + template <> + struct enum_to_fmt_type { + using type = integer_format_info; + }; + + template <> + struct enum_to_fmt_type { + using type = floating_format_info; + }; + + template <> + struct enum_to_fmt_type { + using type = string_format_info; + }; + + template <> + struct enum_to_fmt_type { + using type = offset_datetime_format_info; + }; + + template <> + struct enum_to_fmt_type { + using type = local_datetime_format_info; + }; + + template <> + struct enum_to_fmt_type { + using type = local_date_format_info; + }; + + template <> + struct enum_to_fmt_type { + using type = local_time_format_info; + }; + + template <> + struct enum_to_fmt_type { + using type = array_format_info; + }; + + template <> + struct enum_to_fmt_type { + using type = table_format_info; + }; + + template + using enum_to_fmt_type_t = typename enum_to_fmt_type::type; + + template + struct is_exact_toml_type0 + : cxx::disjunction, + std::is_same, + std::is_same, + std::is_same, + std::is_same, + std::is_same, + std::is_same, + std::is_same, + std::is_same, + std::is_same> {}; + + template + struct is_exact_toml_type : is_exact_toml_type0, V> {}; + + template + struct is_not_toml_type : cxx::negation> {}; + + } // namespace detail +} // namespace toml +#endif // TOML11_VALUE_T_FWD_HPP + +#if !defined(TOML11_COMPILE_SOURCES) + #ifndef TOML11_VALUE_T_IMPL_HPP + #define TOML11_VALUE_T_IMPL_HPP + + #include + #include + #include + +namespace toml { + + TOML11_INLINE std::ostream& operator<<(std::ostream& os, value_t t) { + switch (t) { + case value_t::boolean: + os << "boolean"; + return os; + case value_t::integer: + os << "integer"; + return os; + case value_t::floating: + os << "floating"; + return os; + case value_t::string: + os << "string"; + return os; + case value_t::offset_datetime: + os << "offset_datetime"; + return os; + case value_t::local_datetime: + os << "local_datetime"; + return os; + case value_t::local_date: + os << "local_date"; + return os; + case value_t::local_time: + os << "local_time"; + return os; + case value_t::array: + os << "array"; + return os; + case value_t::table: + os << "table"; + return os; + case value_t::empty: + os << "empty"; + return os; + default: + os << "unknown"; + return os; + } + } + + TOML11_INLINE std::string to_string(value_t t) { + std::ostringstream oss; + oss << t; + return oss.str(); + } + +} // namespace toml + #endif // TOML11_VALUE_T_IMPL_HPP +#endif + +#endif // TOML11_VALUE_T_HPP +#ifndef TOML11_STORAGE_HPP +#define TOML11_STORAGE_HPP + +namespace toml { + namespace detail { + + // It owns a pointer to T. It does deep-copy when copied. + // This struct is introduced to implement a recursive type. + // + // `toml::value` contains `std::vector` to represent a toml + // array. But, in the definition of `toml::value`, `toml::value` is still + // incomplete. `std::vector` of an incomplete type is not allowed in C++11 + // (it is allowed after C++17). To avoid this, we need to use a pointer to + // `toml::value`, like `std::vector>`. Although + // `std::unique_ptr` is noncopyable, we want to make `toml::value` copyable. + // `storage` is introduced to resolve those problems. + template + struct storage { + using value_type = T; + + explicit storage(value_type v) + : ptr_(cxx::make_unique(std::move(v))) {} + + ~storage() = default; + + storage(const storage& rhs) : ptr_(cxx::make_unique(*rhs.ptr_)) {} + + storage& operator=(const storage& rhs) { + this->ptr_ = cxx::make_unique(*rhs.ptr_); + return *this; + } + + storage(storage&&) = default; + storage& operator=(storage&&) = default; + + bool is_ok() const noexcept { + return static_cast(ptr_); + } + + value_type& get() const noexcept { + return *ptr_; + } + + private: + std::unique_ptr ptr_; + }; + + } // namespace detail +} // namespace toml +#endif // TOML11_STORAGE_HPP +#ifndef TOML11_COMMENTS_HPP +#define TOML11_COMMENTS_HPP + +#ifndef TOML11_COMMENTS_FWD_HPP + #define TOML11_COMMENTS_FWD_HPP + + // to use __has_builtin + + #include + #include + #include + #include + #include + #include + #include + #include + #include + +// This file provides mainly two classes, `preserve_comments` and `discard_comments`. +// Those two are a container that have the same interface as `std::vector` +// but bahaves in the opposite way. `preserve_comments` is just the same as +// `std::vector` and each `std::string` corresponds to a comment line. +// Conversely, `discard_comments` discards all the strings and ignores everything +// assigned in it. `discard_comments` is always empty and you will encounter an +// error whenever you access to the element. +namespace toml { + class discard_comments; // forward decl + + class preserve_comments { + public: + // `container_type` is not provided in discard_comments. + // do not use this inner-type in a generic code. + using container_type = std::vector; + + using size_type = container_type::size_type; + using difference_type = container_type::difference_type; + using value_type = container_type::value_type; + using reference = container_type::reference; + using const_reference = container_type::const_reference; + using pointer = container_type::pointer; + using const_pointer = container_type::const_pointer; + using iterator = container_type::iterator; + using const_iterator = container_type::const_iterator; + using reverse_iterator = container_type::reverse_iterator; + using const_reverse_iterator = container_type::const_reverse_iterator; + + public: + preserve_comments() = default; + ~preserve_comments() = default; + preserve_comments(const preserve_comments&) = default; + preserve_comments(preserve_comments&&) = default; + preserve_comments& operator=(const preserve_comments&) = default; + preserve_comments& operator=(preserve_comments&&) = default; + + explicit preserve_comments(const std::vector& c) + : comments(c) {} + + explicit preserve_comments(std::vector&& c) + : comments(std::move(c)) {} + + preserve_comments& operator=(const std::vector& c) { + comments = c; + return *this; + } + + preserve_comments& operator=(std::vector&& c) { + comments = std::move(c); + return *this; + } + + explicit preserve_comments(const discard_comments&) {} + + explicit preserve_comments(size_type n) : comments(n) {} + + preserve_comments(size_type n, const std::string& x) : comments(n, x) {} + + preserve_comments(std::initializer_list x) : comments(x) {} + + template + preserve_comments(InputIterator first, InputIterator last) + : comments(first, last) {} + + template + void assign(InputIterator first, InputIterator last) { + comments.assign(first, last); + } + + void assign(std::initializer_list ini) { + comments.assign(ini); + } + + void assign(size_type n, const std::string& val) { + comments.assign(n, val); + } + + // Related to the issue #97. + // + // `std::vector::insert` and `std::vector::erase` in the STL implementation + // included in GCC 4.8.5 takes `std::vector::iterator` instead of + // `std::vector::const_iterator`. It causes compilation error in GCC 4.8.5. + #if defined(__GNUC__) && defined(__GNUC_MINOR__) && \ + defined(__GNUC_PATCHLEVEL__) && !defined(__clang__) + #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) <= 40805 + #define TOML11_WORKAROUND_GCC_4_8_X_STANDARD_LIBRARY_IMPLEMENTATION + #endif + #endif + + #ifdef TOML11_WORKAROUND_GCC_4_8_X_STANDARD_LIBRARY_IMPLEMENTATION + iterator insert(iterator p, const std::string& x) { + return comments.insert(p, x); + } + + iterator insert(iterator p, std::string&& x) { + return comments.insert(p, std::move(x)); + } + + void insert(iterator p, size_type n, const std::string& x) { + return comments.insert(p, n, x); + } + + template + void insert(iterator p, InputIterator first, InputIterator last) { + return comments.insert(p, first, last); + } + + void insert(iterator p, std::initializer_list ini) { + return comments.insert(p, ini); + } + + template + iterator emplace(iterator p, Ts&&... args) { + return comments.emplace(p, std::forward(args)...); + } + + iterator erase(iterator pos) { + return comments.erase(pos); + } + + iterator erase(iterator first, iterator last) { + return comments.erase(first, last); + } + #else + iterator insert(const_iterator p, const std::string& x) { + return comments.insert(p, x); + } + + iterator insert(const_iterator p, std::string&& x) { + return comments.insert(p, std::move(x)); + } + + iterator insert(const_iterator p, size_type n, const std::string& x) { + return comments.insert(p, n, x); + } + + template + iterator insert(const_iterator p, InputIterator first, InputIterator last) { + return comments.insert(p, first, last); + } + + iterator insert(const_iterator p, std::initializer_list ini) { + return comments.insert(p, ini); + } + + template + iterator emplace(const_iterator p, Ts&&... args) { + return comments.emplace(p, std::forward(args)...); + } + + iterator erase(const_iterator pos) { + return comments.erase(pos); + } + + iterator erase(const_iterator first, const_iterator last) { + return comments.erase(first, last); + } + #endif + + void swap(preserve_comments& other) { + comments.swap(other.comments); + } + + void push_back(const std::string& v) { + comments.push_back(v); + } + + void push_back(std::string&& v) { + comments.push_back(std::move(v)); + } + + void pop_back() { + comments.pop_back(); + } + + template + void emplace_back(Ts&&... args) { + comments.emplace_back(std::forward(args)...); + } + + void clear() { + comments.clear(); + } + + size_type size() const noexcept { + return comments.size(); + } + + size_type max_size() const noexcept { + return comments.max_size(); + } + + size_type capacity() const noexcept { + return comments.capacity(); + } + + bool empty() const noexcept { + return comments.empty(); + } + + void reserve(size_type n) { + comments.reserve(n); + } + + void resize(size_type n) { + comments.resize(n); + } + + void resize(size_type n, const std::string& c) { + comments.resize(n, c); + } + + void shrink_to_fit() { + comments.shrink_to_fit(); + } + + reference operator[](const size_type n) noexcept { + return comments[n]; + } + + const_reference operator[](const size_type n) const noexcept { + return comments[n]; + } + + reference at(const size_type n) { + return comments.at(n); + } + + const_reference at(const size_type n) const { + return comments.at(n); + } + + reference front() noexcept { + return comments.front(); + } + + const_reference front() const noexcept { + return comments.front(); + } + + reference back() noexcept { + return comments.back(); + } + + const_reference back() const noexcept { + return comments.back(); + } + + pointer data() noexcept { + return comments.data(); + } + + const_pointer data() const noexcept { + return comments.data(); + } + + iterator begin() noexcept { + return comments.begin(); + } + + iterator end() noexcept { + return comments.end(); + } + + const_iterator begin() const noexcept { + return comments.begin(); + } + + const_iterator end() const noexcept { + return comments.end(); + } + + const_iterator cbegin() const noexcept { + return comments.cbegin(); + } + + const_iterator cend() const noexcept { + return comments.cend(); + } + + reverse_iterator rbegin() noexcept { + return comments.rbegin(); + } + + reverse_iterator rend() noexcept { + return comments.rend(); + } + + const_reverse_iterator rbegin() const noexcept { + return comments.rbegin(); + } + + const_reverse_iterator rend() const noexcept { + return comments.rend(); + } + + const_reverse_iterator crbegin() const noexcept { + return comments.crbegin(); + } + + const_reverse_iterator crend() const noexcept { + return comments.crend(); + } + + friend bool operator==(const preserve_comments&, const preserve_comments&); + friend bool operator!=(const preserve_comments&, const preserve_comments&); + friend bool operator<(const preserve_comments&, const preserve_comments&); + friend bool operator<=(const preserve_comments&, const preserve_comments&); + friend bool operator>(const preserve_comments&, const preserve_comments&); + friend bool operator>=(const preserve_comments&, const preserve_comments&); + + friend void swap(preserve_comments&, std::vector&); + friend void swap(std::vector&, preserve_comments&); + + private: + container_type comments; + }; + + bool operator==(const preserve_comments& lhs, const preserve_comments& rhs); + bool operator!=(const preserve_comments& lhs, const preserve_comments& rhs); + bool operator<(const preserve_comments& lhs, const preserve_comments& rhs); + bool operator<=(const preserve_comments& lhs, const preserve_comments& rhs); + bool operator>(const preserve_comments& lhs, const preserve_comments& rhs); + bool operator>=(const preserve_comments& lhs, const preserve_comments& rhs); + + void swap(preserve_comments& lhs, preserve_comments& rhs); + void swap(preserve_comments& lhs, std::vector& rhs); + void swap(std::vector& lhs, preserve_comments& rhs); + + std::ostream& operator<<(std::ostream& os, const preserve_comments& com); + + namespace detail { + + // To provide the same interface with `preserve_comments`, + // `discard_comments` should have an iterator. But it does not contain + // anything, so we need to add an iterator that points nothing. + // + // It always points null, so DO NOT unwrap this iterator. It always crashes + // your program. + template + struct empty_iterator { + using value_type = T; + using reference_type = typename std::conditional::type; + using pointer_type = typename std::conditional::type; + using difference_type = std::ptrdiff_t; + using iterator_category = std::random_access_iterator_tag; + + empty_iterator() = default; + ~empty_iterator() = default; + empty_iterator(const empty_iterator&) = default; + empty_iterator(empty_iterator&&) = default; + empty_iterator& operator=(const empty_iterator&) = default; + empty_iterator& operator=(empty_iterator&&) = default; + + // DO NOT call these operators. + reference_type operator*() const noexcept { + std::terminate(); + } + + pointer_type operator->() const noexcept { + return nullptr; + } + + reference_type operator[](difference_type) const noexcept { + return this->operator*(); + } + + // These operators do nothing. + empty_iterator& operator++() noexcept { + return *this; + } + + empty_iterator operator++(int) noexcept { + return *this; + } + + empty_iterator& operator--() noexcept { + return *this; + } + + empty_iterator operator--(int) noexcept { + return *this; + } + + empty_iterator& operator+=(difference_type) noexcept { + return *this; + } + + empty_iterator& operator-=(difference_type) noexcept { + return *this; + } + + empty_iterator operator+(difference_type) const noexcept { + return *this; + } + + empty_iterator operator-(difference_type) const noexcept { + return *this; + } + }; + + template + bool operator==(const empty_iterator&, + const empty_iterator&) noexcept { + return true; + } + + template + bool operator!=(const empty_iterator&, + const empty_iterator&) noexcept { + return false; + } + + template + bool operator<(const empty_iterator&, + const empty_iterator&) noexcept { + return false; + } + + template + bool operator<=(const empty_iterator&, + const empty_iterator&) noexcept { + return true; + } + + template + bool operator>(const empty_iterator&, + const empty_iterator&) noexcept { + return false; + } + + template + bool operator>=(const empty_iterator&, + const empty_iterator&) noexcept { + return true; + } + + template + typename empty_iterator::difference_type operator-( + const empty_iterator&, + const empty_iterator&) noexcept { + return 0; + } + + template + empty_iterator operator+(typename empty_iterator::difference_type, + const empty_iterator& rhs) noexcept { + return rhs; + } + + template + empty_iterator operator+( + const empty_iterator& lhs, + typename empty_iterator::difference_type) noexcept { + return lhs; + } + + } // namespace detail + + // The default comment type. It discards all the comments. It requires only one + // byte to contain, so the memory footprint is smaller than preserve_comments. + // + // It just ignores `push_back`, `insert`, `erase`, and any other modifications. + // IT always returns size() == 0, the iterator taken by `begin()` is always the + // same as that of `end()`, and accessing through `operator[]` or iterators + // always causes a segmentation fault. DO NOT access to the element of this. + // + // Why this is chose as the default type is because the last version (2.x.y) + // does not contain any comments in a value. To minimize the impact on the + // efficiency, this is chosen as a default. + // + // To reduce the memory footprint, later we can try empty base optimization (EBO). + class discard_comments { + public: + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; + using value_type = std::string; + using reference = std::string&; + using const_reference = const std::string&; + using pointer = std::string*; + using const_pointer = const std::string*; + using iterator = detail::empty_iterator; + using const_iterator = detail::empty_iterator; + using reverse_iterator = detail::empty_iterator; + using const_reverse_iterator = detail::empty_iterator; + + public: + discard_comments() = default; + ~discard_comments() = default; + discard_comments(const discard_comments&) = default; + discard_comments(discard_comments&&) = default; + discard_comments& operator=(const discard_comments&) = default; + discard_comments& operator=(discard_comments&&) = default; + + explicit discard_comments(const std::vector&) noexcept {} + + explicit discard_comments(std::vector&&) noexcept {} + + discard_comments& operator=(const std::vector&) noexcept { + return *this; + } + + discard_comments& operator=(std::vector&&) noexcept { + return *this; + } + + explicit discard_comments(const preserve_comments&) noexcept {} + + explicit discard_comments(size_type) noexcept {} + + discard_comments(size_type, const std::string&) noexcept {} + + discard_comments(std::initializer_list) noexcept {} + + template + discard_comments(InputIterator, InputIterator) noexcept {} + + template + void assign(InputIterator, InputIterator) noexcept {} + + void assign(std::initializer_list) noexcept {} + + void assign(size_type, const std::string&) noexcept {} + + iterator insert(const_iterator, const std::string&) { + return iterator {}; + } + + iterator insert(const_iterator, std::string&&) { + return iterator {}; + } + + iterator insert(const_iterator, size_type, const std::string&) { + return iterator {}; + } + + template + iterator insert(const_iterator, InputIterator, InputIterator) { + return iterator {}; + } + + iterator insert(const_iterator, std::initializer_list) { + return iterator {}; + } + + template + iterator emplace(const_iterator, Ts&&...) { + return iterator {}; + } + + iterator erase(const_iterator) { + return iterator {}; + } + + iterator erase(const_iterator, const_iterator) { + return iterator {}; + } + + void swap(discard_comments&) { + return; + } + + void push_back(const std::string&) { + return; + } + + void push_back(std::string&&) { + return; + } + + void pop_back() { + return; + } + + template + void emplace_back(Ts&&...) { + return; + } + + void clear() { + return; + } + + size_type size() const noexcept { + return 0; + } + + size_type max_size() const noexcept { + return 0; + } + + size_type capacity() const noexcept { + return 0; + } + + bool empty() const noexcept { + return true; + } + + void reserve(size_type) { + return; + } + + void resize(size_type) { + return; + } + + void resize(size_type, const std::string&) { + return; + } + + void shrink_to_fit() { + return; + } + + // DO NOT access to the element of this container. This container is always + // empty, so accessing through operator[], front/back, data causes address + // error. + + reference operator[](const size_type) noexcept { + never_call("toml::discard_comment::operator[]"); + } + + const_reference operator[](const size_type) const noexcept { + never_call("toml::discard_comment::operator[]"); + } + + reference at(const size_type) { + throw std::out_of_range("toml::discard_comment is always empty."); + } + + const_reference at(const size_type) const { + throw std::out_of_range("toml::discard_comment is always empty."); + } + + reference front() noexcept { + never_call("toml::discard_comment::front"); + } + + const_reference front() const noexcept { + never_call("toml::discard_comment::front"); + } + + reference back() noexcept { + never_call("toml::discard_comment::back"); + } + + const_reference back() const noexcept { + never_call("toml::discard_comment::back"); + } + + pointer data() noexcept { + return nullptr; + } + + const_pointer data() const noexcept { + return nullptr; + } + + iterator begin() noexcept { + return iterator {}; + } + + iterator end() noexcept { + return iterator {}; + } + + const_iterator begin() const noexcept { + return const_iterator {}; + } + + const_iterator end() const noexcept { + return const_iterator {}; + } + + const_iterator cbegin() const noexcept { + return const_iterator {}; + } + + const_iterator cend() const noexcept { + return const_iterator {}; + } + + reverse_iterator rbegin() noexcept { + return iterator {}; + } + + reverse_iterator rend() noexcept { + return iterator {}; + } + + const_reverse_iterator rbegin() const noexcept { + return const_iterator {}; + } + + const_reverse_iterator rend() const noexcept { + return const_iterator {}; + } + + const_reverse_iterator crbegin() const noexcept { + return const_iterator {}; + } + + const_reverse_iterator crend() const noexcept { + return const_iterator {}; + } + + private: + [[noreturn]] + static void never_call(const char* const this_function) { + #if __has_builtin(__builtin_unreachable) + __builtin_unreachable(); + #endif + throw std::logic_error { this_function }; + } + }; + + inline bool operator==(const discard_comments&, const discard_comments&) noexcept { + return true; + } + + inline bool operator!=(const discard_comments&, const discard_comments&) noexcept { + return false; + } + + inline bool operator<(const discard_comments&, const discard_comments&) noexcept { + return false; + } + + inline bool operator<=(const discard_comments&, const discard_comments&) noexcept { + return true; + } + + inline bool operator>(const discard_comments&, const discard_comments&) noexcept { + return false; + } + + inline bool operator>=(const discard_comments&, const discard_comments&) noexcept { + return true; + } + + inline void swap(const discard_comments&, const discard_comments&) noexcept { + return; + } + + inline std::ostream& operator<<(std::ostream& os, const discard_comments&) { + return os; + } + +} // namespace toml +#endif // TOML11_COMMENTS_FWD_HPP + +#if !defined(TOML11_COMPILE_SOURCES) + #ifndef TOML11_COMMENTS_IMPL_HPP + #define TOML11_COMMENTS_IMPL_HPP + +namespace toml { + + TOML11_INLINE bool operator==(const preserve_comments& lhs, + const preserve_comments& rhs) { + return lhs.comments == rhs.comments; + } + + TOML11_INLINE bool operator!=(const preserve_comments& lhs, + const preserve_comments& rhs) { + return lhs.comments != rhs.comments; + } + + TOML11_INLINE bool operator<(const preserve_comments& lhs, + const preserve_comments& rhs) { + return lhs.comments < rhs.comments; + } + + TOML11_INLINE bool operator<=(const preserve_comments& lhs, + const preserve_comments& rhs) { + return lhs.comments <= rhs.comments; + } + + TOML11_INLINE bool operator>(const preserve_comments& lhs, + const preserve_comments& rhs) { + return lhs.comments > rhs.comments; + } + + TOML11_INLINE bool operator>=(const preserve_comments& lhs, + const preserve_comments& rhs) { + return lhs.comments >= rhs.comments; + } + + TOML11_INLINE void swap(preserve_comments& lhs, preserve_comments& rhs) { + lhs.swap(rhs); + return; + } + + TOML11_INLINE void swap(preserve_comments& lhs, std::vector& rhs) { + lhs.comments.swap(rhs); + return; + } + + TOML11_INLINE void swap(std::vector& lhs, preserve_comments& rhs) { + lhs.swap(rhs.comments); + return; + } + + TOML11_INLINE std::ostream& operator<<(std::ostream& os, + const preserve_comments& com) { + for (const auto& c : com) { + if (c.front() != '#') { + os << '#'; + } + os << c << '\n'; + } + return os; + } + +} // namespace toml + #endif // TOML11_COMMENTS_IMPL_HPP +#endif + +#endif // TOML11_COMMENTS_HPP +#ifndef TOML11_COLOR_HPP +#define TOML11_COLOR_HPP + +#ifndef TOML11_COLOR_FWD_HPP + #define TOML11_COLOR_FWD_HPP + + #include + + #ifdef TOML11_COLORIZE_ERROR_MESSAGE + #define TOML11_ERROR_MESSAGE_COLORIZED true + #else + #define TOML11_ERROR_MESSAGE_COLORIZED false + #endif + + #ifdef TOML11_USE_THREAD_LOCAL_COLORIZATION + #define TOML11_THREAD_LOCAL_COLORIZATION thread_local + #else + #define TOML11_THREAD_LOCAL_COLORIZATION + #endif + +namespace toml { + namespace color { + // put ANSI escape sequence to ostream + inline namespace ansi { + namespace detail { + + // Control color mode globally + class color_mode { + public: + void enable() noexcept { + should_color_ = true; + } + + void disable() noexcept { + should_color_ = false; + } + + bool should_color() const noexcept { + return should_color_; + } + + private: + bool should_color_ = TOML11_ERROR_MESSAGE_COLORIZED; + }; + + inline color_mode& color_status() noexcept { + static TOML11_THREAD_LOCAL_COLORIZATION color_mode status; + return status; + } + + } // namespace detail + + std::ostream& reset(std::ostream& os); + std::ostream& bold(std::ostream& os); + std::ostream& grey(std::ostream& os); + std::ostream& gray(std::ostream& os); + std::ostream& red(std::ostream& os); + std::ostream& green(std::ostream& os); + std::ostream& yellow(std::ostream& os); + std::ostream& blue(std::ostream& os); + std::ostream& magenta(std::ostream& os); + std::ostream& cyan(std::ostream& os); + std::ostream& white(std::ostream& os); + + } // namespace ansi + + inline void enable() { + return detail::color_status().enable(); + } + + inline void disable() { + return detail::color_status().disable(); + } + + inline bool should_color() { + return detail::color_status().should_color(); + } + + } // namespace color +} // namespace toml +#endif // TOML11_COLOR_FWD_HPP + +#if !defined(TOML11_COMPILE_SOURCES) + #ifndef TOML11_COLOR_IMPL_HPP + #define TOML11_COLOR_IMPL_HPP + + #include + +namespace toml { + namespace color { + // put ANSI escape sequence to ostream + inline namespace ansi { + + TOML11_INLINE std::ostream& reset(std::ostream& os) { + if (detail::color_status().should_color()) { + os << "\033[00m"; + } + return os; + } + + TOML11_INLINE std::ostream& bold(std::ostream& os) { + if (detail::color_status().should_color()) { + os << "\033[01m"; + } + return os; + } + + TOML11_INLINE std::ostream& grey(std::ostream& os) { + if (detail::color_status().should_color()) { + os << "\033[30m"; + } + return os; + } + + TOML11_INLINE std::ostream& gray(std::ostream& os) { + if (detail::color_status().should_color()) { + os << "\033[30m"; + } + return os; + } + + TOML11_INLINE std::ostream& red(std::ostream& os) { + if (detail::color_status().should_color()) { + os << "\033[31m"; + } + return os; + } + + TOML11_INLINE std::ostream& green(std::ostream& os) { + if (detail::color_status().should_color()) { + os << "\033[32m"; + } + return os; + } + + TOML11_INLINE std::ostream& yellow(std::ostream& os) { + if (detail::color_status().should_color()) { + os << "\033[33m"; + } + return os; + } + + TOML11_INLINE std::ostream& blue(std::ostream& os) { + if (detail::color_status().should_color()) { + os << "\033[34m"; + } + return os; + } + + TOML11_INLINE std::ostream& magenta(std::ostream& os) { + if (detail::color_status().should_color()) { + os << "\033[35m"; + } + return os; + } + + TOML11_INLINE std::ostream& cyan(std::ostream& os) { + if (detail::color_status().should_color()) { + os << "\033[36m"; + } + return os; + } + + TOML11_INLINE std::ostream& white(std::ostream& os) { + if (detail::color_status().should_color()) { + os << "\033[37m"; + } + return os; + } + + } // namespace ansi + } // namespace color +} // namespace toml + #endif // TOML11_COLOR_IMPL_HPP +#endif + +#endif // TOML11_COLOR_HPP +#ifndef TOML11_SPEC_HPP +#define TOML11_SPEC_HPP + +#include +#include +#include + +namespace toml { + + struct semantic_version { + constexpr semantic_version(std::uint32_t mjr, + std::uint32_t mnr, + std::uint32_t p) noexcept + : major { mjr } + , minor { mnr } + , patch { p } {} + + std::uint32_t major; + std::uint32_t minor; + std::uint32_t patch; + }; + + constexpr inline semantic_version make_semver(std::uint32_t mjr, + std::uint32_t mnr, + std::uint32_t p) noexcept { + return semantic_version(mjr, mnr, p); + } + + constexpr inline bool operator==(const semantic_version& lhs, + const semantic_version& rhs) noexcept { + return lhs.major == rhs.major && lhs.minor == rhs.minor && + lhs.patch == rhs.patch; + } + + constexpr inline bool operator!=(const semantic_version& lhs, + const semantic_version& rhs) noexcept { + return !(lhs == rhs); + } + + constexpr inline bool operator<(const semantic_version& lhs, + const semantic_version& rhs) noexcept { + return lhs.major < rhs.major || + (lhs.major == rhs.major && lhs.minor < rhs.minor) || + (lhs.major == rhs.major && lhs.minor == rhs.minor && + lhs.patch < rhs.patch); + } + + constexpr inline bool operator>(const semantic_version& lhs, + const semantic_version& rhs) noexcept { + return rhs < lhs; + } + + constexpr inline bool operator<=(const semantic_version& lhs, + const semantic_version& rhs) noexcept { + return !(lhs > rhs); + } + + constexpr inline bool operator>=(const semantic_version& lhs, + const semantic_version& rhs) noexcept { + return !(lhs < rhs); + } + + inline std::ostream& operator<<(std::ostream& os, const semantic_version& v) { + os << v.major << '.' << v.minor << '.' << v.patch; + return os; + } + + inline std::string to_string(const semantic_version& v) { + std::ostringstream oss; + oss << v; + return oss.str(); + } + + struct spec { + constexpr static spec default_version() noexcept { + return spec::v(1, 0, 0); + } + + constexpr static spec v(std::uint32_t mjr, + std::uint32_t mnr, + std::uint32_t p) noexcept { + return spec(make_semver(mjr, mnr, p)); + } + + constexpr explicit spec(const semantic_version& semver) noexcept + : version{semver}, + v1_1_0_allow_control_characters_in_comments {semantic_version{1, 1, 0} <= semver}, + v1_1_0_allow_newlines_in_inline_tables {semantic_version{1, 1, 0} <= semver}, + v1_1_0_allow_trailing_comma_in_inline_tables{semantic_version{1, 1, 0} <= semver}, + v1_1_0_allow_non_english_in_bare_keys {semantic_version{1, 1, 0} <= semver}, + v1_1_0_add_escape_sequence_e {semantic_version{1, 1, 0} <= semver}, + v1_1_0_add_escape_sequence_x {semantic_version{1, 1, 0} <= semver}, + v1_1_0_make_seconds_optional {semantic_version{1, 1, 0} <= semver}, + ext_hex_float {false}, + ext_num_suffix{false}, + ext_null_value{false} + {} + + semantic_version version; // toml version + + // diff from v1.0.0 -> v1.1.0 + bool v1_1_0_allow_control_characters_in_comments; + bool v1_1_0_allow_newlines_in_inline_tables; + bool v1_1_0_allow_trailing_comma_in_inline_tables; + bool v1_1_0_allow_non_english_in_bare_keys; + bool v1_1_0_add_escape_sequence_e; + bool v1_1_0_add_escape_sequence_x; + bool v1_1_0_make_seconds_optional; + + // library extensions + bool ext_hex_float; // allow hex float (in C++ style) + bool ext_num_suffix; // allow number suffix (in C++ style) + bool ext_null_value; // allow `null` as a value + }; + +} // namespace toml +#endif // TOML11_SPEC_HPP +#ifndef TOML11_ORDERED_MAP_HPP +#define TOML11_ORDERED_MAP_HPP + +#include +#include +#include +#include + +namespace toml { + + namespace detail { + template + struct ordered_map_ebo_container { + Cmp cmp_; // empty base optimization for empty Cmp type + }; + } // namespace detail + + template , + typename Allocator = std::allocator>> + class ordered_map : detail::ordered_map_ebo_container { + public: + using key_type = Key; + using mapped_type = Val; + using value_type = std::pair; + + using key_compare = Cmp; + using allocator_type = Allocator; + + using container_type = std::vector; + using reference = typename container_type::reference; + using pointer = typename container_type::pointer; + using const_reference = typename container_type::const_reference; + using const_pointer = typename container_type::const_pointer; + using iterator = typename container_type::iterator; + using const_iterator = typename container_type::const_iterator; + using size_type = typename container_type::size_type; + using difference_type = typename container_type::difference_type; + + private: + using ebo_base = detail::ordered_map_ebo_container; + + public: + ordered_map() = default; + ~ordered_map() = default; + ordered_map(const ordered_map&) = default; + ordered_map(ordered_map&&) = default; + ordered_map& operator=(const ordered_map&) = default; + ordered_map& operator=(ordered_map&&) = default; + + ordered_map(const ordered_map& other, const Allocator& alloc) + : container_(other.container_, alloc) {} + + ordered_map(ordered_map&& other, const Allocator& alloc) + : container_(std::move(other.container_), alloc) {} + + explicit ordered_map(const Cmp& cmp, const Allocator& alloc = Allocator()) + : ebo_base { cmp } + , container_(alloc) {} + + explicit ordered_map(const Allocator& alloc) : container_(alloc) {} + + template + ordered_map(InputIterator first, + InputIterator last, + const Cmp& cmp = Cmp(), + const Allocator& alloc = Allocator()) + : ebo_base { cmp } + , container_(first, last, alloc) {} + + template + ordered_map(InputIterator first, InputIterator last, const Allocator& alloc) + : container_(first, last, alloc) {} + + ordered_map(std::initializer_list v, + const Cmp& cmp = Cmp(), + const Allocator& alloc = Allocator()) + : ebo_base { cmp } + , container_(std::move(v), alloc) {} + + ordered_map(std::initializer_list v, const Allocator& alloc) + : container_(std::move(v), alloc) {} + + ordered_map& operator=(std::initializer_list v) { + this->container_ = std::move(v); + return *this; + } + + iterator begin() noexcept { + return container_.begin(); + } + + iterator end() noexcept { + return container_.end(); + } + + const_iterator begin() const noexcept { + return container_.begin(); + } + + const_iterator end() const noexcept { + return container_.end(); + } + + const_iterator cbegin() const noexcept { + return container_.cbegin(); + } + + const_iterator cend() const noexcept { + return container_.cend(); + } + + bool empty() const noexcept { + return container_.empty(); + } + + std::size_t size() const noexcept { + return container_.size(); + } + + std::size_t max_size() const noexcept { + return container_.max_size(); + } + + void clear() { + container_.clear(); + } + + void push_back(const value_type& v) { + if (this->contains(v.first)) { + throw std::out_of_range("ordered_map: value already exists"); + } + container_.push_back(v); + } + + void push_back(value_type&& v) { + if (this->contains(v.first)) { + throw std::out_of_range("ordered_map: value already exists"); + } + container_.push_back(std::move(v)); + } + + void emplace_back(key_type k, mapped_type v) { + if (this->contains(k)) { + throw std::out_of_range("ordered_map: value already exists"); + } + container_.emplace_back(std::move(k), std::move(v)); + } + + void pop_back() { + container_.pop_back(); + } + + void insert(value_type kv) { + if (this->contains(kv.first)) { + throw std::out_of_range("ordered_map: value already exists"); + } + container_.push_back(std::move(kv)); + } + + void emplace(key_type k, mapped_type v) { + if (this->contains(k)) { + throw std::out_of_range("ordered_map: value already exists"); + } + container_.emplace_back(std::move(k), std::move(v)); + } + + std::size_t count(const key_type& key) const { + if (this->find(key) != this->end()) { + return 1; + } else { + return 0; + } + } + + bool contains(const key_type& key) const { + return this->find(key) != this->end(); + } + + iterator find(const key_type& key) noexcept { + return std::find_if(this->begin(), + this->end(), + [&key, this](const value_type& v) { + return this->cmp_(v.first, key); + }); + } + + const_iterator find(const key_type& key) const noexcept { + return std::find_if(this->begin(), + this->end(), + [&key, this](const value_type& v) { + return this->cmp_(v.first, key); + }); + } + + mapped_type& at(const key_type& k) { + const auto iter = this->find(k); + if (iter == this->end()) { + throw std::out_of_range("ordered_map: no such element"); + } + return iter->second; + } + + const mapped_type& at(const key_type& k) const { + const auto iter = this->find(k); + if (iter == this->end()) { + throw std::out_of_range("ordered_map: no such element"); + } + return iter->second; + } + + mapped_type& operator[](const key_type& k) { + const auto iter = this->find(k); + if (iter == this->end()) { + this->container_.emplace_back(k, mapped_type {}); + return this->container_.back().second; + } + return iter->second; + } + + const mapped_type& operator[](const key_type& k) const { + const auto iter = this->find(k); + if (iter == this->end()) { + throw std::out_of_range("ordered_map: no such element"); + } + return iter->second; + } + + key_compare key_comp() const { + return this->cmp_; + } + + void swap(ordered_map& other) { + container_.swap(other.container_); + } + + private: + container_type container_; + }; + + template + bool operator==(const ordered_map& lhs, + const ordered_map& rhs) { + return lhs.size() == rhs.size() && + std::equal(lhs.begin(), lhs.end(), rhs.begin()); + } + + template + bool operator!=(const ordered_map& lhs, + const ordered_map& rhs) { + return !(lhs == rhs); + } + + template + bool operator<(const ordered_map& lhs, + const ordered_map& rhs) { + return std::lexicographical_compare(lhs.begin(), + lhs.end(), + rhs.begin(), + rhs.end()); + } + + template + bool operator>(const ordered_map& lhs, + const ordered_map& rhs) { + return rhs < lhs; + } + + template + bool operator<=(const ordered_map& lhs, + const ordered_map& rhs) { + return !(lhs > rhs); + } + + template + bool operator>=(const ordered_map& lhs, + const ordered_map& rhs) { + return !(lhs < rhs); + } + + template + void swap(ordered_map& lhs, ordered_map& rhs) { + lhs.swap(rhs); + return; + } + +} // namespace toml +#endif // TOML11_ORDERED_MAP_HPP +#ifndef TOML11_INTO_HPP +#define TOML11_INTO_HPP + +namespace toml { + + template + struct into; + // { + // static toml::value into_toml(const T& user_defined_type) + // { + // // User-defined conversions ... + // } + // }; + +} // namespace toml +#endif // TOML11_INTO_HPP +#ifndef TOML11_FROM_HPP +#define TOML11_FROM_HPP + +namespace toml { + + template + struct from; + // { + // static T from_toml(const toml::value& v) + // { + // // User-defined conversions ... + // } + // }; + +} // namespace toml +#endif // TOML11_FROM_HPP +#ifndef TOML11_TRAITS_HPP +#define TOML11_TRAITS_HPP + +#include +#include +#include +#include +#include +#include +#include + +#if defined(TOML11_HAS_STRING_VIEW) + #include +#endif + +namespace toml { + template + class basic_value; + + namespace detail { + // --------------------------------------------------------------------------- + // check whether type T is a kind of container/map class + + struct has_iterator_impl { + template + static std::true_type check(typename T::iterator*); + template + static std::false_type check(...); + }; + + struct has_value_type_impl { + template + static std::true_type check(typename T::value_type*); + template + static std::false_type check(...); + }; + + struct has_key_type_impl { + template + static std::true_type check(typename T::key_type*); + template + static std::false_type check(...); + }; + + struct has_mapped_type_impl { + template + static std::true_type check(typename T::mapped_type*); + template + static std::false_type check(...); + }; + + struct has_reserve_method_impl { + template + static std::false_type check(...); + template + static std::true_type check( + decltype(std::declval().reserve(std::declval()))*); + }; + + struct has_push_back_method_impl { + template + static std::false_type check(...); + template + static std::true_type check(decltype(std::declval().push_back( + std::declval()))*); + }; + + struct is_comparable_impl { + template + static std::false_type check(...); + template + static std::true_type check(decltype(std::declval() < std::declval())*); + }; + + struct has_from_toml_method_impl { + template + static std::true_type check(decltype(std::declval().from_toml( + std::declval<::toml::basic_value>()))*); + + template + static std::false_type check(...); + }; + + struct has_into_toml_method_impl { + template + static std::true_type check(decltype(std::declval().into_toml())*); + template + static std::false_type check(...); + }; + + struct has_template_into_toml_method_impl { + template + static std::true_type check( + decltype(std::declval().template into_toml())*); + template + static std::false_type check(...); + }; + + struct has_specialized_from_impl { + template + static std::false_type check(...); + template )> + static std::true_type check(::toml::from*); + }; + + struct has_specialized_into_impl { + template + static std::false_type check(...); + template )> + static std::true_type check(::toml::into*); + }; + +/// Intel C++ compiler can not use decltype in parent class declaration, here +/// is a hack to work around it. https://stackoverflow.com/a/23953090/4692076 +#ifdef __INTEL_COMPILER + #define decltype(...) std::enable_if::type +#endif + + template + struct has_iterator : decltype(has_iterator_impl::check(nullptr)) {}; + + template + struct has_value_type : decltype(has_value_type_impl::check(nullptr)) {}; + + template + struct has_key_type : decltype(has_key_type_impl::check(nullptr)) {}; + + template + struct has_mapped_type : decltype(has_mapped_type_impl::check(nullptr)) {}; + + template + struct has_reserve_method + : decltype(has_reserve_method_impl::check(nullptr)) {}; + + template + struct has_push_back_method + : decltype(has_push_back_method_impl::check(nullptr)) {}; + + template + struct is_comparable : decltype(is_comparable_impl::check(nullptr)) {}; + + template + struct has_from_toml_method + : decltype(has_from_toml_method_impl::check(nullptr)) {}; + + template + struct has_into_toml_method + : decltype(has_into_toml_method_impl::check(nullptr)) {}; + + template + struct has_template_into_toml_method + : decltype(has_template_into_toml_method_impl::check(nullptr)) { + }; + + template + struct has_specialized_from + : decltype(has_specialized_from_impl::check(nullptr)) {}; + + template + struct has_specialized_into + : decltype(has_specialized_into_impl::check(nullptr)) {}; + +#ifdef __INTEL_COMPILER + #undef decltype +#endif + + // --------------------------------------------------------------------------- + // type checkers + + template + struct is_std_pair_impl : std::false_type {}; + + template + struct is_std_pair_impl> : std::true_type {}; + + template + using is_std_pair = is_std_pair_impl>; + + template + struct is_std_tuple_impl : std::false_type {}; + + template + struct is_std_tuple_impl> : std::true_type {}; + + template + using is_std_tuple = is_std_tuple_impl>; + + template + struct is_std_array_impl : std::false_type {}; + + template + struct is_std_array_impl> : std::true_type {}; + + template + using is_std_array = is_std_array_impl>; + + template + struct is_std_forward_list_impl : std::false_type {}; + + template + struct is_std_forward_list_impl> : std::true_type {}; + + template + using is_std_forward_list = is_std_forward_list_impl>; + + template + struct is_std_basic_string_impl : std::false_type {}; + + template + struct is_std_basic_string_impl> : std::true_type { + }; + + template + using is_std_basic_string = is_std_basic_string_impl>; + + template + struct is_1byte_std_basic_string_impl : std::false_type {}; + + template + struct is_1byte_std_basic_string_impl> + : std::integral_constant {}; + + template + using is_1byte_std_basic_string = is_std_basic_string_impl>; + +#if defined(TOML11_HAS_STRING_VIEW) + template + struct is_std_basic_string_view_impl : std::false_type {}; + + template + struct is_std_basic_string_view_impl> + : std::true_type {}; + + template + using is_std_basic_string_view = + is_std_basic_string_view_impl>; + + template + struct is_string_view_of : std::false_type {}; + + template + struct is_string_view_of, std::basic_string> + : std::true_type {}; +#endif + + template + struct is_chrono_duration_impl : std::false_type {}; + + template + struct is_chrono_duration_impl> + : std::true_type {}; + + template + using is_chrono_duration = is_chrono_duration_impl>; + + template + struct is_map_impl + : cxx::conjunction< // map satisfies all the following conditions + has_iterator, // has T::iterator + has_value_type, // has T::value_type + has_key_type, // has T::key_type + has_mapped_type // has T::mapped_type + > {}; + + template + using is_map = is_map_impl>; + + template + struct is_container_impl + : cxx::conjunction>, // not a map + cxx::negation>, // not a std::string +#ifdef TOML11_HAS_STRING_VIEW + cxx::negation>, // not a std::string_view +#endif + has_iterator, // has T::iterator + has_value_type // has T::value_type + > { + }; + + template + using is_container = is_container_impl>; + + template + struct is_basic_value_impl : std::false_type {}; + + template + struct is_basic_value_impl<::toml::basic_value> : std::true_type {}; + + template + using is_basic_value = is_basic_value_impl>; + + } // namespace detail +} // namespace toml +#endif // TOML11_TRAITS_HPP +#ifndef TOML11_EXCEPTION_HPP +#define TOML11_EXCEPTION_HPP + +#include + +namespace toml { + + struct exception : public std::exception { + public: + virtual ~exception() noexcept override = default; + + virtual const char* what() const noexcept override { + return ""; + } + }; + +} // namespace toml +#endif // TOMl11_EXCEPTION_HPP +#ifndef TOML11_RESULT_HPP +#define TOML11_RESULT_HPP + +#include +#include +#include +#include +#include + +namespace toml { + + struct bad_result_access final : public ::toml::exception { + public: + explicit bad_result_access(std::string what_arg) + : what_(std::move(what_arg)) {} + + ~bad_result_access() noexcept override = default; + + const char* what() const noexcept override { + return what_.c_str(); + } + + private: + std::string what_; + }; + + // ----------------------------------------------------------------------------- + + template + struct success { + static_assert(!std::is_same::value, ""); + + using value_type = T; + + explicit success(value_type v) noexcept( + std::is_nothrow_move_constructible::value) + : value(std::move(v)) {} + + template , T>::value, + std::nullptr_t> = nullptr> + explicit success(U&& v) : value(std::forward(v)) {} + + template + explicit success(success v) : value(std::move(v.value)) {} + + ~success() = default; + success(const success&) = default; + success(success&&) = default; + success& operator=(const success&) = default; + success& operator=(success&&) = default; + + value_type& get() noexcept { + return value; + } + + const value_type& get() const noexcept { + return value; + } + + private: + value_type value; + }; + + template + struct success> { + static_assert(!std::is_same::value, ""); + + using value_type = T; + + explicit success(std::reference_wrapper v) noexcept + : value(std::move(v)) {} + + ~success() = default; + success(const success&) = default; + success(success&&) = default; + success& operator=(const success&) = default; + success& operator=(success&&) = default; + + value_type& get() noexcept { + return value.get(); + } + + const value_type& get() const noexcept { + return value.get(); + } + + private: + std::reference_wrapper value; + }; + + template + success::type> ok(T&& v) { + return success::type>(std::forward(v)); + } + + template + success ok(const char (&literal)[N]) { + return success(std::string(literal)); + } + + // ----------------------------------------------------------------------------- + + template + struct failure { + using value_type = T; + + explicit failure(value_type v) noexcept( + std::is_nothrow_move_constructible::value) + : value(std::move(v)) {} + + template , T>::value, + std::nullptr_t> = nullptr> + explicit failure(U&& v) : value(std::forward(v)) {} + + template + explicit failure(failure v) : value(std::move(v.value)) {} + + ~failure() = default; + failure(const failure&) = default; + failure(failure&&) = default; + failure& operator=(const failure&) = default; + failure& operator=(failure&&) = default; + + value_type& get() noexcept { + return value; + } + + const value_type& get() const noexcept { + return value; + } + + private: + value_type value; + }; + + template + struct failure> { + using value_type = T; + + explicit failure(std::reference_wrapper v) noexcept + : value(std::move(v)) {} + + ~failure() = default; + failure(const failure&) = default; + failure(failure&&) = default; + failure& operator=(const failure&) = default; + failure& operator=(failure&&) = default; + + value_type& get() noexcept { + return value.get(); + } + + const value_type& get() const noexcept { + return value.get(); + } + + private: + std::reference_wrapper value; + }; + + template + failure::type> err(T&& v) { + return failure::type>(std::forward(v)); + } + + template + failure err(const char (&literal)[N]) { + return failure(std::string(literal)); + } + + /* ============================================================================ + * _ _ + * _ _ ___ ____ _| | |_ + * | '_/ -_|_-< || | | _| + * |_| \___/__/\_,_|_|\__| + */ + + template + struct result { + using success_type = success; + using failure_type = failure; + using value_type = typename success_type::value_type; + using error_type = typename failure_type::value_type; + + result(success_type s) : is_ok_(true), succ_(std::move(s)) {} + + result(failure_type f) : is_ok_(false), fail_(std::move(f)) {} + + template < + typename U, + cxx::enable_if_t< + cxx::conjunction, value_type>>, + std::is_convertible, value_type>>::value, + std::nullptr_t> = nullptr> + result(success s) : is_ok_(true) + , succ_(std::move(s.value)) {} + + template < + typename U, + cxx::enable_if_t< + cxx::conjunction, error_type>>, + std::is_convertible, error_type>>::value, + std::nullptr_t> = nullptr> + result(failure f) : is_ok_(false) + , fail_(std::move(f.value)) {} + + result& operator=(success_type s) { + this->cleanup(); + this->is_ok_ = true; + auto tmp = ::new (std::addressof(this->succ_)) success_type(std::move(s)); + assert(tmp == std::addressof(this->succ_)); + (void)tmp; + return *this; + } + + result& operator=(failure_type f) { + this->cleanup(); + this->is_ok_ = false; + auto tmp = ::new (std::addressof(this->fail_)) failure_type(std::move(f)); + assert(tmp == std::addressof(this->fail_)); + (void)tmp; + return *this; + } + + template + result& operator=(success s) { + this->cleanup(); + this->is_ok_ = true; + auto tmp = ::new (std::addressof(this->succ_)) + success_type(std::move(s.value)); + assert(tmp == std::addressof(this->succ_)); + (void)tmp; + return *this; + } + + template + result& operator=(failure f) { + this->cleanup(); + this->is_ok_ = false; + auto tmp = ::new (std::addressof(this->fail_)) + failure_type(std::move(f.value)); + assert(tmp == std::addressof(this->fail_)); + (void)tmp; + return *this; + } + + ~result() noexcept { + this->cleanup(); + } + + result(const result& other) : is_ok_(other.is_ok()) { + if (other.is_ok()) { + auto tmp = ::new (std::addressof(this->succ_)) success_type(other.succ_); + assert(tmp == std::addressof(this->succ_)); + (void)tmp; + } else { + auto tmp = ::new (std::addressof(this->fail_)) failure_type(other.fail_); + assert(tmp == std::addressof(this->fail_)); + (void)tmp; + } + } + + result(result&& other) : is_ok_(other.is_ok()) { + if (other.is_ok()) { + auto tmp = ::new (std::addressof(this->succ_)) + success_type(std::move(other.succ_)); + assert(tmp == std::addressof(this->succ_)); + (void)tmp; + } else { + auto tmp = ::new (std::addressof(this->fail_)) + failure_type(std::move(other.fail_)); + assert(tmp == std::addressof(this->fail_)); + (void)tmp; + } + } + + result& operator=(const result& other) { + this->cleanup(); + if (other.is_ok()) { + auto tmp = ::new (std::addressof(this->succ_)) success_type(other.succ_); + assert(tmp == std::addressof(this->succ_)); + (void)tmp; + } else { + auto tmp = ::new (std::addressof(this->fail_)) failure_type(other.fail_); + assert(tmp == std::addressof(this->fail_)); + (void)tmp; + } + is_ok_ = other.is_ok(); + return *this; + } + + result& operator=(result&& other) { + this->cleanup(); + if (other.is_ok()) { + auto tmp = ::new (std::addressof(this->succ_)) + success_type(std::move(other.succ_)); + assert(tmp == std::addressof(this->succ_)); + (void)tmp; + } else { + auto tmp = ::new (std::addressof(this->fail_)) + failure_type(std::move(other.fail_)); + assert(tmp == std::addressof(this->fail_)); + (void)tmp; + } + is_ok_ = other.is_ok(); + return *this; + } + + template < + typename U, + typename F, + cxx::enable_if_t< + cxx::conjunction, value_type>>, + cxx::negation, error_type>>, + std::is_convertible, value_type>, + std::is_convertible, error_type>>::value, + std::nullptr_t> = nullptr> + result(result other) : is_ok_(other.is_ok()) { + if (other.is_ok()) { + auto tmp = ::new (std::addressof(this->succ_)) + success_type(std::move(other.as_ok())); + assert(tmp == std::addressof(this->succ_)); + (void)tmp; + } else { + auto tmp = ::new (std::addressof(this->fail_)) + failure_type(std::move(other.as_err())); + assert(tmp == std::addressof(this->fail_)); + (void)tmp; + } + } + + template < + typename U, + typename F, + cxx::enable_if_t< + cxx::conjunction, value_type>>, + cxx::negation, error_type>>, + std::is_convertible, value_type>, + std::is_convertible, error_type>>::value, + std::nullptr_t> = nullptr> + result& operator=(result other) { + this->cleanup(); + if (other.is_ok()) { + auto tmp = ::new (std::addressof(this->succ_)) + success_type(std::move(other.as_ok())); + assert(tmp == std::addressof(this->succ_)); + (void)tmp; + } else { + auto tmp = ::new (std::addressof(this->fail_)) + failure_type(std::move(other.as_err())); + assert(tmp == std::addressof(this->fail_)); + (void)tmp; + } + is_ok_ = other.is_ok(); + return *this; + } + + bool is_ok() const noexcept { + return is_ok_; + } + + bool is_err() const noexcept { + return !is_ok_; + } + + explicit operator bool() const noexcept { + return is_ok_; + } + + value_type& unwrap(cxx::source_location loc = cxx::source_location::current()) { + if (this->is_err()) { + throw bad_result_access("toml::result: bad unwrap" + cxx::to_string(loc)); + } + return this->succ_.get(); + } + + const value_type& unwrap( + cxx::source_location loc = cxx::source_location::current()) const { + if (this->is_err()) { + throw bad_result_access("toml::result: bad unwrap" + cxx::to_string(loc)); + } + return this->succ_.get(); + } + + value_type& unwrap_or(value_type& opt) noexcept { + if (this->is_err()) { + return opt; + } + return this->succ_.get(); + } + + const value_type& unwrap_or(const value_type& opt) const noexcept { + if (this->is_err()) { + return opt; + } + return this->succ_.get(); + } + + error_type& unwrap_err( + cxx::source_location loc = cxx::source_location::current()) { + if (this->is_ok()) { + throw bad_result_access( + "toml::result: bad unwrap_err" + cxx::to_string(loc)); + } + return this->fail_.get(); + } + + const error_type& unwrap_err( + cxx::source_location loc = cxx::source_location::current()) const { + if (this->is_ok()) { + throw bad_result_access( + "toml::result: bad unwrap_err" + cxx::to_string(loc)); + } + return this->fail_.get(); + } + + value_type& as_ok() noexcept { + assert(this->is_ok()); + return this->succ_.get(); + } + + const value_type& as_ok() const noexcept { + assert(this->is_ok()); + return this->succ_.get(); + } + + error_type& as_err() noexcept { + assert(this->is_err()); + return this->fail_.get(); + } + + const error_type& as_err() const noexcept { + assert(this->is_err()); + return this->fail_.get(); + } + + private: + void cleanup() noexcept { +#if defined(__GNUC__) && !defined(__clang__) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wduplicated-branches" +#endif + + if (this->is_ok_) { + this->succ_.~success_type(); + } else { + this->fail_.~failure_type(); + } + +#if defined(__GNUC__) && !defined(__clang__) + #pragma GCC diagnostic pop +#endif + return; + } + + private: + bool is_ok_; + + union { + success_type succ_; + failure_type fail_; + }; + }; + + // ---------------------------------------------------------------------------- + + namespace detail { + struct none_t {}; + + inline bool operator==(const none_t&, const none_t&) noexcept { + return true; + } + + inline bool operator!=(const none_t&, const none_t&) noexcept { + return false; + } + + inline bool operator<(const none_t&, const none_t&) noexcept { + return false; + } + + inline bool operator<=(const none_t&, const none_t&) noexcept { + return true; + } + + inline bool operator>(const none_t&, const none_t&) noexcept { + return false; + } + + inline bool operator>=(const none_t&, const none_t&) noexcept { + return true; + } + + inline std::ostream& operator<<(std::ostream& os, const none_t&) { + os << "none"; + return os; + } + } // namespace detail + + inline success ok() noexcept { + return success(detail::none_t {}); + } + + inline failure err() noexcept { + return failure(detail::none_t {}); + } + +} // namespace toml +#endif // TOML11_RESULT_HPP +#ifndef TOML11_UTILITY_HPP +#define TOML11_UTILITY_HPP + +#include +#include +#include +#include +#include + +namespace toml { + namespace detail { + + // to output character in an error message. + inline std::string show_char(const int c) { + using char_type = unsigned char; + if (std::isgraph(c)) { + return std::string(1, static_cast(c)); + } else { + std::array buf; + buf.fill('\0'); + const auto r = std::snprintf(buf.data(), buf.size(), "0x%02x", c & 0xFF); + assert(r == static_cast(buf.size()) - 1); + (void)r; // Unused variable warning + auto in_hex = std::string(buf.data()); + switch (c) { + case char_type('\0'): { + in_hex += "(NUL)"; + break; + } + case char_type(' '): { + in_hex += "(SPACE)"; + break; + } + case char_type('\n'): { + in_hex += "(LINE FEED)"; + break; + } + case char_type('\r'): { + in_hex += "(CARRIAGE RETURN)"; + break; + } + case char_type('\t'): { + in_hex += "(TAB)"; + break; + } + case char_type('\v'): { + in_hex += "(VERTICAL TAB)"; + break; + } + case char_type('\f'): { + in_hex += "(FORM FEED)"; + break; + } + case char_type('\x1B'): { + in_hex += "(ESCAPE)"; + break; + } + default: + break; + } + return in_hex; + } + } + + // --------------------------------------------------------------------------- + + template + void try_reserve_impl(Container& container, std::size_t N, std::true_type) { + container.reserve(N); + return; + } + + template + void try_reserve_impl(Container&, std::size_t, std::false_type) noexcept { + return; + } + + template + void try_reserve(Container& container, std::size_t N) { + try_reserve_impl(container, N, has_reserve_method {}); + return; + } + + // --------------------------------------------------------------------------- + + template + result from_string(const std::string& str) { + T v; + std::istringstream iss(str); + iss >> v; + if (iss.fail()) { + return err(); + } + return ok(v); + } + + // --------------------------------------------------------------------------- + + // helper function to avoid std::string(0, 'c') or std::string(iter, iter) + template + std::string make_string(Iterator first, Iterator last) { + if (first == last) { + return ""; + } + return std::string(first, last); + } + + inline std::string make_string(std::size_t len, char c) { + if (len == 0) { + return ""; + } + return std::string(len, c); + } + + // --------------------------------------------------------------------------- + + template + struct string_conv_impl { + static_assert(sizeof(Char) == sizeof(char), ""); + static_assert(sizeof(Char2) == sizeof(char), ""); + + static std::basic_string invoke( + std::basic_string s) { + std::basic_string retval; + std::transform(s.begin(), + s.end(), + std::back_inserter(retval), + [](const Char2 c) { + return static_cast(c); + }); + return retval; + } + + template + static std::basic_string invoke(const Char2 (&s)[N]) { + std::basic_string retval; + // "string literal" has null-char at the end. to skip it, we use prev. + std::transform(std::begin(s), + std::prev(std::end(s)), + std::back_inserter(retval), + [](const Char2 c) { + return static_cast(c); + }); + return retval; + } + }; + + template + struct string_conv_impl { + static_assert(sizeof(Char) == sizeof(char), ""); + + static std::basic_string invoke( + std::basic_string s) { + return s; + } + + template + static std::basic_string invoke(const Char (&s)[N]) { + return std::basic_string(s); + } + }; + + template + cxx::enable_if_t::value, S> string_conv( + std::basic_string s) { + using C = typename S::value_type; + using T = typename S::traits_type; + using A = typename S::allocator_type; + return string_conv_impl::invoke( + std::move(s)); + } + + template + cxx::enable_if_t::value, S> string_conv( + const char (&s)[N]) { + using C = typename S::value_type; + using T = typename S::traits_type; + using A = typename S::allocator_type; + using C2 = char; + using T2 = std::char_traits; + using A2 = std::allocator; + + return string_conv_impl::template invoke(s); + } + + } // namespace detail +} // namespace toml +#endif // TOML11_UTILITY_HPP +#ifndef TOML11_LOCATION_HPP +#define TOML11_LOCATION_HPP + +#ifndef TOML11_LOCATION_FWD_HPP + #define TOML11_LOCATION_FWD_HPP + + #include + #include + #include + +namespace toml { + namespace detail { + + class region; // fwd decl + + // + // To represent where we are reading in the parse functions. + // Since it "points" somewhere in the input stream, the length is always 1. + // + class location { + public: + using char_type = unsigned char; // must be unsigned + using container_type = std::vector; + using difference_type = + typename container_type::difference_type; // to suppress sign-conversion warning + using source_ptr = std::shared_ptr; + + public: + location(source_ptr src, std::string src_name) + : source_(std::move(src)) + , source_name_(std::move(src_name)) + , location_(0) + , line_number_(1) {} + + location(const location&) = default; + location(location&&) = default; + location& operator=(const location&) = default; + location& operator=(location&&) = default; + ~location() = default; + + void advance(std::size_t n = 1) noexcept; + void retrace(std::size_t n = 1) noexcept; + + bool is_ok() const noexcept { + return static_cast(this->source_); + } + + bool eof() const noexcept; + char_type current() const; + + char_type peek(); + + std::size_t get_location() const noexcept { + return this->location_; + } + + void set_location(const std::size_t loc) noexcept; + + std::size_t line_number() const noexcept { + return this->line_number_; + } + + std::string get_line() const; + std::size_t column_number() const noexcept; + + const source_ptr& source() const noexcept { + return this->source_; + } + + const std::string& source_name() const noexcept { + return this->source_name_; + } + + private: + void advance_line_number(const std::size_t n); + void retrace_line_number(const std::size_t n); + + private: + friend region; + + private: + source_ptr source_; + std::string source_name_; + std::size_t location_; // std::vector<>::difference_type is signed + std::size_t line_number_; + }; + + bool operator==(const location& lhs, const location& rhs) noexcept; + bool operator!=(const location& lhs, const location& rhs); + + location prev(const location& loc); + location next(const location& loc); + location make_temporary_location(const std::string& str) noexcept; + + template + result find_if(const location& first, + const location& last, + const F& func) noexcept { + if (first.source() != last.source()) { + return err(); + } + if (first.get_location() >= last.get_location()) { + return err(); + } + + auto loc = first; + while (loc.get_location() != last.get_location()) { + if (func(loc.current())) { + return ok(loc); + } + loc.advance(); + } + return err(); + } + + template + result rfind_if(location first, + const location& last, + const F& func) { + if (first.source() != last.source()) { + return err(); + } + if (first.get_location() >= last.get_location()) { + return err(); + } + + auto loc = last; + while (loc.get_location() != first.get_location()) { + if (func(loc.current())) { + return ok(loc); + } + loc.retrace(); + } + if (func(first.current())) { + return ok(first); + } + return err(); + } + + result find(const location& first, + const location& last, + const location::char_type val); + result rfind(const location& first, + const location& last, + const location::char_type val); + + std::size_t count(const location& first, + const location& last, + const location::char_type& c); + + } // namespace detail +} // namespace toml +#endif // TOML11_LOCATION_FWD_HPP + +#if !defined(TOML11_COMPILE_SOURCES) + #ifndef TOML11_LOCATION_IMPL_HPP + #define TOML11_LOCATION_IMPL_HPP + +namespace toml { + namespace detail { + + TOML11_INLINE void location::advance(std::size_t n) noexcept { + assert(this->is_ok()); + if (this->location_ + n < this->source_->size()) { + this->advance_line_number(n); + this->location_ += n; + } else { + this->advance_line_number(this->source_->size() - this->location_); + this->location_ = this->source_->size(); + } + } + + TOML11_INLINE void location::retrace(std::size_t n) noexcept { + assert(this->is_ok()); + if (this->location_ < n) { + this->location_ = 0; + this->line_number_ = 1; + } else { + this->retrace_line_number(n); + this->location_ -= n; + } + } + + TOML11_INLINE bool location::eof() const noexcept { + assert(this->is_ok()); + return this->location_ >= this->source_->size(); + } + + TOML11_INLINE location::char_type location::current() const { + assert(this->is_ok()); + if (this->eof()) { + return '\0'; + } + + assert(this->location_ < this->source_->size()); + return this->source_->at(this->location_); + } + + TOML11_INLINE location::char_type location::peek() { + assert(this->is_ok()); + if (this->location_ >= this->source_->size()) { + return '\0'; + } else { + return this->source_->at(this->location_ + 1); + } + } + + TOML11_INLINE void location::set_location(const std::size_t loc) noexcept { + if (this->location_ == loc) { + return; + } + + if (loc == 0) { + this->line_number_ = 1; + } else if (this->location_ < loc) { + const auto d = loc - this->location_; + this->advance_line_number(d); + } else { + const auto d = this->location_ - loc; + this->retrace_line_number(d); + } + this->location_ = loc; + } + + TOML11_INLINE std::string location::get_line() const { + assert(this->is_ok()); + const auto iter = std::next(this->source_->cbegin(), + static_cast(this->location_)); + const auto riter = cxx::make_reverse_iterator(iter); + + const auto prev = std::find(riter, this->source_->crend(), char_type('\n')); + const auto next = std::find(iter, this->source_->cend(), char_type('\n')); + + return make_string(std::next(prev.base()), next); + } + + TOML11_INLINE std::size_t location::column_number() const noexcept { + assert(this->is_ok()); + const auto iter = std::next(this->source_->cbegin(), + static_cast(this->location_)); + const auto riter = cxx::make_reverse_iterator(iter); + const auto prev = std::find(riter, this->source_->crend(), char_type('\n')); + + assert(prev.base() <= iter); + return static_cast(std::distance(prev.base(), iter) + 1); // 1-origin + } + + TOML11_INLINE void location::advance_line_number(const std::size_t n) { + assert(this->is_ok()); + assert(this->location_ + n <= this->source_->size()); + + const auto iter = this->source_->cbegin(); + this->line_number_ += static_cast(std::count( + std::next(iter, static_cast(this->location_)), + std::next(iter, static_cast(this->location_ + n)), + char_type('\n'))); + + return; + } + + TOML11_INLINE void location::retrace_line_number(const std::size_t n) { + assert(this->is_ok()); + assert(n <= this->location_); // loc - n >= 0 + + const auto iter = this->source_->cbegin(); + const auto dline_num = static_cast(std::count( + std::next(iter, static_cast(this->location_ - n)), + std::next(iter, static_cast(this->location_)), + char_type('\n'))); + + if (this->line_number_ <= dline_num) { + this->line_number_ = 1; + } else { + this->line_number_ -= dline_num; + } + return; + } + + TOML11_INLINE bool operator==(const location& lhs, const location& rhs) noexcept { + if (!lhs.is_ok() || !rhs.is_ok()) { + return (!lhs.is_ok()) && (!rhs.is_ok()); + } + return lhs.source() == rhs.source() && + lhs.source_name() == rhs.source_name() && + lhs.get_location() == rhs.get_location(); + } + + TOML11_INLINE bool operator!=(const location& lhs, const location& rhs) { + return !(lhs == rhs); + } + + TOML11_INLINE location prev(const location& loc) { + location p(loc); + p.retrace(1); + return p; + } + + TOML11_INLINE location next(const location& loc) { + location p(loc); + p.advance(1); + return p; + } + + TOML11_INLINE location make_temporary_location(const std::string& str) noexcept { + location::container_type cont(str.size()); + std::transform(str.begin(), + str.end(), + cont.begin(), + [](const std::string::value_type& c) { + return cxx::bit_cast(c); + }); + return location( + std::make_shared(std::move(cont)), + "internal temporary"); + } + + TOML11_INLINE result find(const location& first, + const location& last, + const location::char_type val) { + return find_if(first, last, [val](const location::char_type c) { + return c == val; + }); + } + + TOML11_INLINE result rfind(const location& first, + const location& last, + const location::char_type val) { + return rfind_if(first, last, [val](const location::char_type c) { + return c == val; + }); + } + + TOML11_INLINE std::size_t count(const location& first, + const location& last, + const location::char_type& c) { + if (first.source() != last.source()) { + return 0; + } + if (first.get_location() >= last.get_location()) { + return 0; + } + + auto loc = first; + std::size_t num = 0; + while (loc.get_location() != last.get_location()) { + if (loc.current() == c) { + num += 1; + } + loc.advance(); + } + return num; + } + + } // namespace detail +} // namespace toml + #endif // TOML11_LOCATION_HPP +#endif + +#endif // TOML11_LOCATION_HPP +#ifndef TOML11_REGION_HPP +#define TOML11_REGION_HPP + +#ifndef TOML11_REGION_FWD_HPP + #define TOML11_REGION_FWD_HPP + + #include + #include + #include + +namespace toml { + namespace detail { + + // + // To represent where is a toml::value defined, or where does an error occur. + // Stored in toml::value. source_location will be constructed based on this. + // + class region { + public: + using char_type = location::char_type; + using container_type = location::container_type; + using difference_type = location::difference_type; + using source_ptr = location::source_ptr; + + using iterator = typename container_type::iterator; + using const_iterator = typename container_type::const_iterator; + + public: + // a value that is constructed manually does not have input stream info + region() + : source_(nullptr) + , source_name_("") + , length_(0) + , first_line_(0) + , first_column_(0) + , last_line_(0) + , last_column_(0) {} + + // a value defined in [first, last). + // Those source must be the same. Instread, `region` does not make sense. + region(const location& first, const location& last); + + // shorthand of [loc, loc+1) + explicit region(const location& loc); + + ~region() = default; + region(const region&) = default; + region(region&&) = default; + region& operator=(const region&) = default; + region& operator=(region&&) = default; + + bool is_ok() const noexcept { + return static_cast(this->source_); + } + + operator bool() const noexcept { + return this->is_ok(); + } + + std::size_t length() const noexcept { + return this->length_; + } + + std::size_t first_line_number() const noexcept { + return this->first_line_; + } + + std::size_t first_column_number() const noexcept { + return this->first_column_; + } + + std::size_t last_line_number() const noexcept { + return this->last_line_; + } + + std::size_t last_column_number() const noexcept { + return this->last_column_; + } + + char_type at(std::size_t i) const; + + const_iterator begin() const noexcept; + const_iterator end() const noexcept; + const_iterator cbegin() const noexcept; + const_iterator cend() const noexcept; + + std::string as_string() const; + std::vector as_lines() const; + + const source_ptr& source() const noexcept { + return this->source_; + } + + const std::string& source_name() const noexcept { + return this->source_name_; + } + + private: + source_ptr source_; + std::string source_name_; + std::size_t length_; + std::size_t first_; + std::size_t first_line_; + std::size_t first_column_; + std::size_t last_; + std::size_t last_line_; + std::size_t last_column_; + }; + + } // namespace detail +} // namespace toml +#endif // TOML11_REGION_FWD_HPP + +#if !defined(TOML11_COMPILE_SOURCES) + #ifndef TOML11_REGION_IMPL_HPP + #define TOML11_REGION_IMPL_HPP + + #include + #include + #include + #include + #include + #include + +namespace toml { + namespace detail { + + // a value defined in [first, last). + // Those source must be the same. Instread, `region` does not make sense. + TOML11_INLINE region::region(const location& first, const location& last) + : source_(first.source()) + , source_name_(first.source_name()) + , length_(last.get_location() - first.get_location()) + , first_(first.get_location()) + , first_line_(first.line_number()) + , first_column_(first.column_number()) + , last_(last.get_location()) + , last_line_(last.line_number()) + , last_column_(last.column_number()) { + assert(first.source() == last.source()); + assert(first.source_name() == last.source_name()); + } + + // shorthand of [loc, loc+1) + TOML11_INLINE region::region(const location& loc) + : source_(loc.source()) + , source_name_(loc.source_name()) + , length_(0) + , first_line_(0) + , first_column_(0) + , last_line_(0) + , last_column_(0) { + // if the file ends with LF, the resulting region points no char. + if (loc.eof()) { + if (loc.get_location() == 0) { + this->length_ = 0; + this->first_ = 0; + this->first_line_ = 0; + this->first_column_ = 0; + this->last_ = 0; + this->last_line_ = 0; + this->last_column_ = 0; + } else { + const auto first = prev(loc); + this->first_ = first.get_location(); + this->first_line_ = first.line_number(); + this->first_column_ = first.column_number(); + this->last_ = loc.get_location(); + this->last_line_ = loc.line_number(); + this->last_column_ = loc.column_number(); + this->length_ = 1; + } + } else { + this->first_ = loc.get_location(); + this->first_line_ = loc.line_number(); + this->first_column_ = loc.column_number(); + this->last_ = loc.get_location() + 1; + this->last_line_ = loc.line_number(); + this->last_column_ = loc.column_number() + 1; + this->length_ = 1; + } + } + + TOML11_INLINE region::char_type region::at(std::size_t i) const { + if (this->last_ <= this->first_ + i) { + throw std::out_of_range("range::at: index " + std::to_string(i) + + " exceeds length " + std::to_string(this->length_)); + } + const auto iter = std::next(this->source_->cbegin(), + static_cast(this->first_ + i)); + return *iter; + } + + TOML11_INLINE region::const_iterator region::begin() const noexcept { + return std::next(this->source_->cbegin(), + static_cast(this->first_)); + } + + TOML11_INLINE region::const_iterator region::end() const noexcept { + return std::next(this->source_->cbegin(), + static_cast(this->last_)); + } + + TOML11_INLINE region::const_iterator region::cbegin() const noexcept { + return std::next(this->source_->cbegin(), + static_cast(this->first_)); + } + + TOML11_INLINE region::const_iterator region::cend() const noexcept { + return std::next(this->source_->cbegin(), + static_cast(this->last_)); + } + + TOML11_INLINE std::string region::as_string() const { + if (this->is_ok()) { + const auto begin = std::next(this->source_->cbegin(), + static_cast(this->first_)); + const auto end = std::next(this->source_->cbegin(), + static_cast(this->last_)); + return ::toml::detail::make_string(begin, end); + } else { + return std::string(""); + } + } + + TOML11_INLINE std::vector region::as_lines() const { + assert(this->is_ok()); + if (this->length_ == 0) { + return std::vector { "" }; + } + + // Consider the following toml file + // ``` + // array = [ + // ] # comment + // ``` + // and the region represnets + // ``` + // [ + // ] + // ``` + // but we want to show the following. + // ``` + // array = [ + // ] # comment + // ``` + // So we need to find LFs before `begin` and after `end`. + // + // But, if region ends with LF, it should not include the next line. + // ``` + // a = 42 + // ^^^- with the last LF + // ``` + // So we start from `end-1` when looking for LF. + + const auto begin_idx = static_cast(this->first_); + const auto end_idx = static_cast(this->last_) - 1; + + // length_ != 0, so begin < end. then begin <= end-1 + assert(begin_idx <= end_idx); + + const auto begin = std::next(this->source_->cbegin(), begin_idx); + const auto end = std::next(this->source_->cbegin(), end_idx); + + const auto line_begin = std::find(cxx::make_reverse_iterator(begin), + this->source_->crend(), + char_type('\n')) + .base(); + const auto line_end = std::find(end, this->source_->cend(), char_type('\n')); + + const auto reg_lines = make_string(line_begin, line_end); + + if (reg_lines == "") // the region is an empty line that only contains LF + { + return std::vector { "" }; + } + + std::istringstream iss(reg_lines); + + std::vector lines; + std::string line; + while (std::getline(iss, line)) { + lines.push_back(line); + } + return lines; + } + + } // namespace detail +} // namespace toml + #endif // TOML11_REGION_IMPL_HPP +#endif + +#endif // TOML11_REGION_HPP +#ifndef TOML11_SOURCE_LOCATION_HPP +#define TOML11_SOURCE_LOCATION_HPP + +#ifndef TOML11_SOURCE_LOCATION_FWD_HPP + #define TOML11_SOURCE_LOCATION_FWD_HPP + + #include + #include + #include + +namespace toml { + + // A struct to contain location in a toml file. + struct source_location { + public: + explicit source_location(const detail::region& r); + ~source_location() = default; + source_location(const source_location&) = default; + source_location(source_location&&) = default; + source_location& operator=(const source_location&) = default; + source_location& operator=(source_location&&) = default; + + bool is_ok() const noexcept { + return this->is_ok_; + } + + std::size_t length() const noexcept { + return this->length_; + } + + std::size_t first_line_number() const noexcept { + return this->first_line_; + } + + std::size_t first_column_number() const noexcept { + return this->first_column_; + } + + std::size_t last_line_number() const noexcept { + return this->last_line_; + } + + std::size_t last_column_number() const noexcept { + return this->last_column_; + } + + const std::string& file_name() const noexcept { + return this->file_name_; + } + + std::size_t num_lines() const noexcept { + return this->line_str_.size(); + } + + const std::string& first_line() const; + const std::string& last_line() const; + + const std::vector& lines() const noexcept { + return line_str_; + } + + private: + bool is_ok_; + std::size_t first_line_; + std::size_t first_column_; + std::size_t last_line_; + std::size_t last_column_; + std::size_t length_; + std::string file_name_; + std::vector line_str_; + }; + + namespace detail { + + std::size_t integer_width_base10(std::size_t i) noexcept; + + inline std::size_t line_width() noexcept { + return 0; + } + + template + std::size_t line_width(const source_location& loc, + const std::string& /*msg*/, + const Ts&... tail) noexcept { + return (std::max)(integer_width_base10(loc.last_line_number()), + line_width(tail...)); + } + + std::ostringstream& format_filename(std::ostringstream& oss, + const source_location& loc); + + std::ostringstream& format_empty_line(std::ostringstream& oss, + const std::size_t lnw); + + std::ostringstream& format_line(std::ostringstream& oss, + const std::size_t lnw, + const std::size_t linenum, + const std::string& line); + + std::ostringstream& format_underline(std::ostringstream& oss, + const std::size_t lnw, + const std::size_t col, + const std::size_t len, + const std::string& msg); + + std::string format_location_impl(const std::size_t lnw, + const std::string& prev_fname, + const source_location& loc, + const std::string& msg); + + inline std::string format_location_rec(const std::size_t, const std::string&) { + return ""; + } + + template + std::string format_location_rec(const std::size_t lnw, + const std::string& prev_fname, + const source_location& loc, + const std::string& msg, + const Ts&... tail) { + return format_location_impl(lnw, prev_fname, loc, msg) + + format_location_rec(lnw, loc.file_name(), tail...); + } + + } // namespace detail + + // format a location info without title + template + std::string format_location(const source_location& loc, + const std::string& msg, + const Ts&... tail) { + const auto lnw = detail::line_width(loc, msg, tail...); + + const std::string f(""); // at the 1st iteration, no prev_filename is given + return detail::format_location_rec(lnw, f, loc, msg, tail...); + } + +} // namespace toml +#endif // TOML11_SOURCE_LOCATION_FWD_HPP + +#if !defined(TOML11_COMPILE_SOURCES) + #ifndef TOML11_SOURCE_LOCATION_IMPL_HPP + #define TOML11_SOURCE_LOCATION_IMPL_HPP + + #include + #include + #include + #include + #include + +namespace toml { + + TOML11_INLINE source_location::source_location(const detail::region& r) + : is_ok_(false) + , first_line_(1) + , first_column_(1) + , last_line_(1) + , last_column_(1) + , length_(0) + , file_name_("unknown file") { + if (r.is_ok()) { + this->is_ok_ = true; + this->file_name_ = r.source_name(); + this->first_line_ = r.first_line_number(); + this->first_column_ = r.first_column_number(); + this->last_line_ = r.last_line_number(); + this->last_column_ = r.last_column_number(); + this->length_ = r.length(); + this->line_str_ = r.as_lines(); + } + } + + TOML11_INLINE const std::string& source_location::first_line() const { + if (this->line_str_.size() == 0) { + throw std::out_of_range( + "toml::source_location::first_line: `lines` is empty"); + } + return this->line_str_.front(); + } + + TOML11_INLINE const std::string& source_location::last_line() const { + if (this->line_str_.size() == 0) { + throw std::out_of_range( + "toml::source_location::first_line: `lines` is empty"); + } + return this->line_str_.back(); + } + + namespace detail { + + TOML11_INLINE std::size_t integer_width_base10(std::size_t i) noexcept { + std::size_t width = 0; + while (i != 0) { + i /= 10; + width += 1; + } + return width; + } + + TOML11_INLINE std::ostringstream& format_filename(std::ostringstream& oss, + const source_location& loc) { + // --> example.toml + oss << color::bold << color::blue << " --> " << color::reset + << color::bold << loc.file_name() << '\n' + << color::reset; + return oss; + } + + TOML11_INLINE std::ostringstream& format_empty_line(std::ostringstream& oss, + const std::size_t lnw) { + // | + oss << detail::make_string(lnw + 1, ' ') << color::bold << color::blue + << " |\n" + << color::reset; + return oss; + } + + TOML11_INLINE std::ostringstream& format_line(std::ostringstream& oss, + const std::size_t lnw, + const std::size_t linenum, + const std::string& line) { + // 10 | key = "value" + oss << ' ' << color::bold << color::blue << std::setw(static_cast(lnw)) + << std::right << linenum << " | " << color::reset; + for (const char c : line) { + if (std::isgraph(c) || c == ' ') { + oss << c; + } else { + oss << show_char(c); + } + } + oss << '\n'; + return oss; + } + + TOML11_INLINE std::ostringstream& format_underline(std::ostringstream& oss, + const std::size_t lnw, + const std::size_t col, + const std::size_t len, + const std::string& msg) { + // | ^^^^^^^-- this part + oss << make_string(lnw + 1, ' ') << color::bold << color::blue << " | " + << color::reset; + + oss << make_string(col - 1 /*1-origin*/, ' ') << color::bold << color::red + << make_string(len, '^') << "-- " << color::reset << msg << '\n'; + + return oss; + } + + TOML11_INLINE std::string format_location_impl(const std::size_t lnw, + const std::string& prev_fname, + const source_location& loc, + const std::string& msg) { + std::ostringstream oss; + + if (loc.file_name() != prev_fname) { + format_filename(oss, loc); + if (!loc.lines().empty()) { + format_empty_line(oss, lnw); + } + } + + if (loc.lines().size() == 1) { + // when column points LF, it exceeds the size of the first line. + std::size_t underline_limit = 1; + if (loc.first_line().size() < loc.first_column_number()) { + underline_limit = 1; + } else { + underline_limit = loc.first_line().size() - loc.first_column_number() + 1; + } + const auto underline_len = (std::min)(underline_limit, loc.length()); + + format_line(oss, lnw, loc.first_line_number(), loc.first_line()); + format_underline(oss, lnw, loc.first_column_number(), underline_len, msg); + } else if (loc.lines().size() == 2) { + const auto first_underline_len = loc.first_line().size() - + loc.first_column_number() + 1; + format_line(oss, lnw, loc.first_line_number(), loc.first_line()); + format_underline(oss, lnw, loc.first_column_number(), first_underline_len, ""); + + format_line(oss, lnw, loc.last_line_number(), loc.last_line()); + format_underline(oss, lnw, 1, loc.last_column_number(), msg); + } else if (loc.lines().size() > 2) { + const auto first_underline_len = loc.first_line().size() - + loc.first_column_number() + 1; + format_line(oss, lnw, loc.first_line_number(), loc.first_line()); + format_underline(oss, lnw, loc.first_column_number(), first_underline_len, "and"); + + if (loc.lines().size() == 3) { + format_line(oss, lnw, loc.first_line_number() + 1, loc.lines().at(1)); + format_underline(oss, lnw, 1, loc.lines().at(1).size(), "and"); + } else { + format_line(oss, lnw, loc.first_line_number() + 1, " ..."); + format_empty_line(oss, lnw); + } + format_line(oss, lnw, loc.last_line_number(), loc.last_line()); + format_underline(oss, lnw, 1, loc.last_column_number(), msg); + } + // if loc is empty, do nothing. + return oss.str(); + } + + } // namespace detail +} // namespace toml + #endif // TOML11_SOURCE_LOCATION_IMPL_HPP +#endif + +#endif // TOML11_SOURCE_LOCATION_HPP +#ifndef TOML11_ERROR_INFO_HPP +#define TOML11_ERROR_INFO_HPP + +#ifndef TOML11_ERROR_INFO_FWD_HPP + #define TOML11_ERROR_INFO_FWD_HPP + +namespace toml { + + // error info returned from parser. + struct error_info { + error_info(std::string t, source_location l, std::string m, std::string s = "") + : title_(std::move(t)) + , locations_ { std::make_pair(std::move(l), std::move(m)) } + , suffix_(std::move(s)) {} + + error_info(std::string t, + std::vector> l, + std::string s = "") + : title_(std::move(t)) + , locations_(std::move(l)) + , suffix_(std::move(s)) {} + + const std::string& title() const noexcept { + return title_; + } + + std::string& title() noexcept { + return title_; + } + + const std::vector>& locations() const noexcept { + return locations_; + } + + void add_locations(source_location loc, std::string msg) noexcept { + locations_.emplace_back(std::move(loc), std::move(msg)); + } + + const std::string& suffix() const noexcept { + return suffix_; + } + + std::string& suffix() noexcept { + return suffix_; + } + + private: + std::string title_; + std::vector> locations_; + std::string suffix_; // hint or something like that + }; + + // forward decl + template + class basic_value; + + namespace detail { + inline error_info make_error_info_rec(error_info e) { + return e; + } + + inline error_info make_error_info_rec(error_info e, std::string s) { + e.suffix() = s; + return e; + } + + template + error_info make_error_info_rec(error_info e, + const basic_value& v, + std::string msg, + Ts&&... tail); + + template + error_info make_error_info_rec(error_info e, + source_location loc, + std::string msg, + Ts&&... tail) { + e.add_locations(std::move(loc), std::move(msg)); + return make_error_info_rec(std::move(e), std::forward(tail)...); + } + + } // namespace detail + + template + error_info make_error_info(std::string title, + source_location loc, + std::string msg, + Ts&&... tail) { + error_info ei(std::move(title), std::move(loc), std::move(msg)); + return detail::make_error_info_rec(ei, std::forward(tail)...); + } + + std::string format_error(const std::string& errkind, const error_info& err); + std::string format_error(const error_info& err); + + // for custom error message + template + std::string format_error(std::string title, + source_location loc, + std::string msg, + Ts&&... tail) { + return format_error("", + make_error_info(std::move(title), + std::move(loc), + std::move(msg), + std::forward(tail)...)); + } + + std::ostream& operator<<(std::ostream& os, const error_info& e); + +} // namespace toml +#endif // TOML11_ERROR_INFO_FWD_HPP + +#if !defined(TOML11_COMPILE_SOURCES) + #ifndef TOML11_ERROR_INFO_IMPL_HPP + #define TOML11_ERROR_INFO_IMPL_HPP + + #include + +namespace toml { + + TOML11_INLINE std::string format_error(const std::string& errkind, + const error_info& err) { + std::string errmsg; + if (!errkind.empty()) { + errmsg = errkind; + errmsg += ' '; + } + errmsg += err.title(); + errmsg += '\n'; + + const auto lnw = [&err]() { + std::size_t width = 0; + for (const auto& l : err.locations()) { + width = (std::max)(detail::integer_width_base10(l.first.last_line_number()), + width); + } + return width; + }(); + + bool first = true; + std::string prev_fname; + for (const auto& lm : err.locations()) { + if (!first) { + std::ostringstream oss; + oss << detail::make_string(lnw + 1, ' ') << color::bold << color::blue + << " |" << color::reset << color::bold << " ...\n" + << color::reset; + oss << detail::make_string(lnw + 1, ' ') << color::bold << color::blue + << " |\n" + << color::reset; + errmsg += oss.str(); + } + + const auto& l = lm.first; + const auto& m = lm.second; + + errmsg += detail::format_location_impl(lnw, prev_fname, l, m); + + prev_fname = l.file_name(); + first = false; + } + + errmsg += err.suffix(); + + return errmsg; + } + + TOML11_INLINE std::string format_error(const error_info& err) { + std::ostringstream oss; + oss << color::red << color::bold << "[error]" << color::reset; + return format_error(oss.str(), err); + } + + TOML11_INLINE std::ostream& operator<<(std::ostream& os, const error_info& e) { + os << format_error(e); + return os; + } + +} // namespace toml + #endif // TOML11_ERROR_INFO_IMPL_HPP +#endif + +#endif // TOML11_ERROR_INFO_HPP +#ifndef TOML11_VALUE_HPP +#define TOML11_VALUE_HPP + +#ifdef TOML11_HAS_STRING_VIEW + #include +#endif + +#include + +namespace toml { + template + class basic_value; + + struct type_error final : public ::toml::exception { + public: + type_error(std::string what_arg, source_location loc) + : what_(std::move(what_arg)) + , loc_(std::move(loc)) {} + + ~type_error() noexcept override = default; + + const char* what() const noexcept override { + return what_.c_str(); + } + + const source_location& location() const noexcept { + return loc_; + } + + private: + std::string what_; + source_location loc_; + }; + + // only for internal use + namespace detail { + template + error_info make_type_error(const basic_value&, + const std::string&, + const value_t); + + template + error_info make_not_found_error(const basic_value&, + const std::string&, + const typename basic_value::key_type&); + + template + void change_region_of_value(basic_value&, const basic_value&); + + template + struct getter; + } // namespace detail + + template + class basic_value { + public: + using config_type = TypeConfig; + using key_type = typename config_type::string_type; + using value_type = basic_value; + using boolean_type = typename config_type::boolean_type; + using integer_type = typename config_type::integer_type; + using floating_type = typename config_type::floating_type; + using string_type = typename config_type::string_type; + using local_time_type = ::toml::local_time; + using local_date_type = ::toml::local_date; + using local_datetime_type = ::toml::local_datetime; + using offset_datetime_type = ::toml::offset_datetime; + using array_type = typename config_type::template array_type; + using table_type = typename config_type::template table_type; + using comment_type = typename config_type::comment_type; + using char_type = typename string_type::value_type; + + private: + using region_type = detail::region; + + public: + basic_value() noexcept + : type_(value_t::empty) + , empty_('\0') + , region_ {} + , comments_ {} {} + + ~basic_value() noexcept { + this->cleanup(); + } + + // copy/move constructor/assigner ===================================== {{{ + + basic_value(const basic_value& v) + : type_(v.type_) + , region_(v.region_) + , comments_(v.comments_) { + switch (this->type_) { + case value_t::boolean: + assigner(boolean_, v.boolean_); + break; + case value_t::integer: + assigner(integer_, v.integer_); + break; + case value_t::floating: + assigner(floating_, v.floating_); + break; + case value_t::string: + assigner(string_, v.string_); + break; + case value_t::offset_datetime: + assigner(offset_datetime_, v.offset_datetime_); + break; + case value_t::local_datetime: + assigner(local_datetime_, v.local_datetime_); + break; + case value_t::local_date: + assigner(local_date_, v.local_date_); + break; + case value_t::local_time: + assigner(local_time_, v.local_time_); + break; + case value_t::array: + assigner(array_, v.array_); + break; + case value_t::table: + assigner(table_, v.table_); + break; + default: + assigner(empty_, '\0'); + break; + } + } + + basic_value(basic_value&& v) + : type_(v.type()) + , region_(std::move(v.region_)) + , comments_(std::move(v.comments_)) { + switch (this->type_) { + case value_t::boolean: + assigner(boolean_, std::move(v.boolean_)); + break; + case value_t::integer: + assigner(integer_, std::move(v.integer_)); + break; + case value_t::floating: + assigner(floating_, std::move(v.floating_)); + break; + case value_t::string: + assigner(string_, std::move(v.string_)); + break; + case value_t::offset_datetime: + assigner(offset_datetime_, std::move(v.offset_datetime_)); + break; + case value_t::local_datetime: + assigner(local_datetime_, std::move(v.local_datetime_)); + break; + case value_t::local_date: + assigner(local_date_, std::move(v.local_date_)); + break; + case value_t::local_time: + assigner(local_time_, std::move(v.local_time_)); + break; + case value_t::array: + assigner(array_, std::move(v.array_)); + break; + case value_t::table: + assigner(table_, std::move(v.table_)); + break; + default: + assigner(empty_, '\0'); + break; + } + } + + basic_value& operator=(const basic_value& v) { + if (this == std::addressof(v)) { + return *this; + } + + this->cleanup(); + this->type_ = v.type_; + this->region_ = v.region_; + this->comments_ = v.comments_; + switch (this->type_) { + case value_t::boolean: + assigner(boolean_, v.boolean_); + break; + case value_t::integer: + assigner(integer_, v.integer_); + break; + case value_t::floating: + assigner(floating_, v.floating_); + break; + case value_t::string: + assigner(string_, v.string_); + break; + case value_t::offset_datetime: + assigner(offset_datetime_, v.offset_datetime_); + break; + case value_t::local_datetime: + assigner(local_datetime_, v.local_datetime_); + break; + case value_t::local_date: + assigner(local_date_, v.local_date_); + break; + case value_t::local_time: + assigner(local_time_, v.local_time_); + break; + case value_t::array: + assigner(array_, v.array_); + break; + case value_t::table: + assigner(table_, v.table_); + break; + default: + assigner(empty_, '\0'); + break; + } + return *this; + } + + basic_value& operator=(basic_value&& v) { + if (this == std::addressof(v)) { + return *this; + } + + this->cleanup(); + this->type_ = v.type_; + this->region_ = std::move(v.region_); + this->comments_ = std::move(v.comments_); + switch (this->type_) { + case value_t::boolean: + assigner(boolean_, std::move(v.boolean_)); + break; + case value_t::integer: + assigner(integer_, std::move(v.integer_)); + break; + case value_t::floating: + assigner(floating_, std::move(v.floating_)); + break; + case value_t::string: + assigner(string_, std::move(v.string_)); + break; + case value_t::offset_datetime: + assigner(offset_datetime_, std::move(v.offset_datetime_)); + break; + case value_t::local_datetime: + assigner(local_datetime_, std::move(v.local_datetime_)); + break; + case value_t::local_date: + assigner(local_date_, std::move(v.local_date_)); + break; + case value_t::local_time: + assigner(local_time_, std::move(v.local_time_)); + break; + case value_t::array: + assigner(array_, std::move(v.array_)); + break; + case value_t::table: + assigner(table_, std::move(v.table_)); + break; + default: + assigner(empty_, '\0'); + break; + } + return *this; + } + + // }}} + + // constructor to overwrite commnets ================================== {{{ + + basic_value(basic_value v, std::vector com) + : type_(v.type()) + , region_(std::move(v.region_)) + , comments_(std::move(com)) { + switch (this->type_) { + case value_t::boolean: + assigner(boolean_, std::move(v.boolean_)); + break; + case value_t::integer: + assigner(integer_, std::move(v.integer_)); + break; + case value_t::floating: + assigner(floating_, std::move(v.floating_)); + break; + case value_t::string: + assigner(string_, std::move(v.string_)); + break; + case value_t::offset_datetime: + assigner(offset_datetime_, std::move(v.offset_datetime_)); + break; + case value_t::local_datetime: + assigner(local_datetime_, std::move(v.local_datetime_)); + break; + case value_t::local_date: + assigner(local_date_, std::move(v.local_date_)); + break; + case value_t::local_time: + assigner(local_time_, std::move(v.local_time_)); + break; + case value_t::array: + assigner(array_, std::move(v.array_)); + break; + case value_t::table: + assigner(table_, std::move(v.table_)); + break; + default: + assigner(empty_, '\0'); + break; + } + } + + // }}} + + // conversion between different basic_values ========================== {{{ + + template + basic_value(basic_value other) + : type_(other.type_) + , region_(std::move(other.region_)) + , comments_(std::move(other.comments_)) { + switch (other.type_) { + // use auto-convert in constructor + case value_t::boolean: + assigner(boolean_, std::move(other.boolean_)); + break; + case value_t::integer: + assigner(integer_, std::move(other.integer_)); + break; + case value_t::floating: + assigner(floating_, std::move(other.floating_)); + break; + case value_t::string: + assigner(string_, std::move(other.string_)); + break; + case value_t::offset_datetime: + assigner(offset_datetime_, std::move(other.offset_datetime_)); + break; + case value_t::local_datetime: + assigner(local_datetime_, std::move(other.local_datetime_)); + break; + case value_t::local_date: + assigner(local_date_, std::move(other.local_date_)); + break; + case value_t::local_time: + assigner(local_time_, std::move(other.local_time_)); + break; + + // may have different container type + case value_t::array: { + array_type tmp(std::make_move_iterator(other.array_.value.get().begin()), + std::make_move_iterator(other.array_.value.get().end())); + assigner(array_, + array_storage(detail::storage(std::move(tmp)), + other.array_.format)); + break; + } + case value_t::table: { + table_type tmp(std::make_move_iterator(other.table_.value.get().begin()), + std::make_move_iterator(other.table_.value.get().end())); + assigner(table_, + table_storage(detail::storage(std::move(tmp)), + other.table_.format)); + break; + } + default: + break; + } + } + + template + basic_value(basic_value other, std::vector com) + : type_(other.type_) + , region_(std::move(other.region_)) + , comments_(std::move(com)) { + switch (other.type_) { + // use auto-convert in constructor + case value_t::boolean: + assigner(boolean_, std::move(other.boolean_)); + break; + case value_t::integer: + assigner(integer_, std::move(other.integer_)); + break; + case value_t::floating: + assigner(floating_, std::move(other.floating_)); + break; + case value_t::string: + assigner(string_, std::move(other.string_)); + break; + case value_t::offset_datetime: + assigner(offset_datetime_, std::move(other.offset_datetime_)); + break; + case value_t::local_datetime: + assigner(local_datetime_, std::move(other.local_datetime_)); + break; + case value_t::local_date: + assigner(local_date_, std::move(other.local_date_)); + break; + case value_t::local_time: + assigner(local_time_, std::move(other.local_time_)); + break; + + // may have different container type + case value_t::array: { + array_type tmp(std::make_move_iterator(other.array_.value.get().begin()), + std::make_move_iterator(other.array_.value.get().end())); + assigner(array_, + array_storage(detail::storage(std::move(tmp)), + other.array_.format)); + break; + } + case value_t::table: { + table_type tmp(std::make_move_iterator(other.table_.value.get().begin()), + std::make_move_iterator(other.table_.value.get().end())); + assigner(table_, + table_storage(detail::storage(std::move(tmp)), + other.table_.format)); + break; + } + default: + break; + } + } + + template + basic_value& operator=(basic_value other) { + this->cleanup(); + this->region_ = other.region_; + this->comments_ = comment_type(other.comments_); + this->type_ = other.type_; + switch (other.type_) { + // use auto-convert in constructor + case value_t::boolean: + assigner(boolean_, std::move(other.boolean_)); + break; + case value_t::integer: + assigner(integer_, std::move(other.integer_)); + break; + case value_t::floating: + assigner(floating_, std::move(other.floating_)); + break; + case value_t::string: + assigner(string_, std::move(other.string_)); + break; + case value_t::offset_datetime: + assigner(offset_datetime_, std::move(other.offset_datetime_)); + break; + case value_t::local_datetime: + assigner(local_datetime_, std::move(other.local_datetime_)); + break; + case value_t::local_date: + assigner(local_date_, std::move(other.local_date_)); + break; + case value_t::local_time: + assigner(local_time_, std::move(other.local_time_)); + break; + + // may have different container type + case value_t::array: { + array_type tmp(std::make_move_iterator(other.array_.value.get().begin()), + std::make_move_iterator(other.array_.value.get().end())); + assigner(array_, + array_storage(detail::storage(std::move(tmp)), + other.array_.format)); + break; + } + case value_t::table: { + table_type tmp(std::make_move_iterator(other.table_.value.get().begin()), + std::make_move_iterator(other.table_.value.get().end())); + assigner(table_, + table_storage(detail::storage(std::move(tmp)), + other.table_.format)); + break; + } + default: + break; + } + return *this; + } + + // }}} + + // constructor (boolean) ============================================== {{{ + + basic_value(boolean_type x) + : basic_value(x, + boolean_format_info {}, + std::vector {}, + region_type {}) {} + + basic_value(boolean_type x, boolean_format_info fmt) + : basic_value(x, fmt, std::vector {}, region_type {}) {} + + basic_value(boolean_type x, std::vector com) + : basic_value(x, boolean_format_info {}, std::move(com), region_type {}) {} + + basic_value(boolean_type x, boolean_format_info fmt, std::vector com) + : basic_value(x, fmt, std::move(com), region_type {}) {} + + basic_value(boolean_type x, + boolean_format_info fmt, + std::vector com, + region_type reg) + : type_(value_t::boolean) + , boolean_(boolean_storage(x, fmt)) + , region_(std::move(reg)) + , comments_(std::move(com)) {} + + basic_value& operator=(boolean_type x) { + boolean_format_info fmt; + if (this->is_boolean()) { + fmt = this->as_boolean_fmt(); + } + this->cleanup(); + this->type_ = value_t::boolean; + this->region_ = region_type {}; + assigner(this->boolean_, boolean_storage(x, fmt)); + return *this; + } + + // }}} + + // constructor (integer) ============================================== {{{ + + basic_value(integer_type x) + : basic_value(std::move(x), + integer_format_info {}, + std::vector {}, + region_type {}) {} + + basic_value(integer_type x, integer_format_info fmt) + : basic_value(std::move(x), + std::move(fmt), + std::vector {}, + region_type {}) {} + + basic_value(integer_type x, std::vector com) + : basic_value(std::move(x), + integer_format_info {}, + std::move(com), + region_type {}) {} + + basic_value(integer_type x, integer_format_info fmt, std::vector com) + : basic_value(std::move(x), std::move(fmt), std::move(com), region_type {}) { + } + + basic_value(integer_type x, + integer_format_info fmt, + std::vector com, + region_type reg) + : type_(value_t::integer) + , integer_(integer_storage(std::move(x), std::move(fmt))) + , region_(std::move(reg)) + , comments_(std::move(com)) {} + + basic_value& operator=(integer_type x) { + integer_format_info fmt; + if (this->is_integer()) { + fmt = this->as_integer_fmt(); + } + this->cleanup(); + this->type_ = value_t::integer; + this->region_ = region_type {}; + assigner(this->integer_, integer_storage(std::move(x), std::move(fmt))); + return *this; + } + + private: + template + using enable_if_integer_like_t = cxx::enable_if_t< + cxx::conjunction, boolean_type>>, + cxx::negation, integer_type>>, + std::is_integral>>::value, + std::nullptr_t>; + + public: + template = nullptr> + basic_value(T x) + : basic_value(std::move(x), + integer_format_info {}, + std::vector {}, + region_type {}) {} + + template = nullptr> + basic_value(T x, integer_format_info fmt) + : basic_value(std::move(x), + std::move(fmt), + std::vector {}, + region_type {}) {} + + template = nullptr> + basic_value(T x, std::vector com) + : basic_value(std::move(x), + integer_format_info {}, + std::move(com), + region_type {}) {} + + template = nullptr> + basic_value(T x, integer_format_info fmt, std::vector com) + : basic_value(std::move(x), std::move(fmt), std::move(com), region_type {}) { + } + + template = nullptr> + basic_value(T x, + integer_format_info fmt, + std::vector com, + region_type reg) + : type_(value_t::integer) + , integer_(integer_storage(std::move(x), std::move(fmt))) + , region_(std::move(reg)) + , comments_(std::move(com)) {} + + template = nullptr> + basic_value& operator=(T x) { + integer_format_info fmt; + if (this->is_integer()) { + fmt = this->as_integer_fmt(); + } + this->cleanup(); + this->type_ = value_t::integer; + this->region_ = region_type {}; + assigner(this->integer_, integer_storage(x, std::move(fmt))); + return *this; + } + + // }}} + + // constructor (floating) ============================================= {{{ + + basic_value(floating_type x) + : basic_value(std::move(x), + floating_format_info {}, + std::vector {}, + region_type {}) {} + + basic_value(floating_type x, floating_format_info fmt) + : basic_value(std::move(x), + std::move(fmt), + std::vector {}, + region_type {}) {} + + basic_value(floating_type x, std::vector com) + : basic_value(std::move(x), + floating_format_info {}, + std::move(com), + region_type {}) {} + + basic_value(floating_type x, + floating_format_info fmt, + std::vector com) + : basic_value(std::move(x), std::move(fmt), std::move(com), region_type {}) { + } + + basic_value(floating_type x, + floating_format_info fmt, + std::vector com, + region_type reg) + : type_(value_t::floating) + , floating_(floating_storage(std::move(x), std::move(fmt))) + , region_(std::move(reg)) + , comments_(std::move(com)) {} + + basic_value& operator=(floating_type x) { + floating_format_info fmt; + if (this->is_floating()) { + fmt = this->as_floating_fmt(); + } + this->cleanup(); + this->type_ = value_t::floating; + this->region_ = region_type {}; + assigner(this->floating_, floating_storage(std::move(x), std::move(fmt))); + return *this; + } + + private: + template + using enable_if_floating_like_t = cxx::enable_if_t< + cxx::conjunction, floating_type>>, + std::is_floating_point>>::value, + std::nullptr_t>; + + public: + template = nullptr> + basic_value(T x) + : basic_value(x, + floating_format_info {}, + std::vector {}, + region_type {}) {} + + template = nullptr> + basic_value(T x, floating_format_info fmt) + : basic_value(x, std::move(fmt), std::vector {}, region_type {}) { + } + + template = nullptr> + basic_value(T x, std::vector com) + : basic_value(x, floating_format_info {}, std::move(com), region_type {}) {} + + template = nullptr> + basic_value(T x, floating_format_info fmt, std::vector com) + : basic_value(x, std::move(fmt), std::move(com), region_type {}) {} + + template = nullptr> + basic_value(T x, + floating_format_info fmt, + std::vector com, + region_type reg) + : type_(value_t::floating) + , floating_(floating_storage(x, std::move(fmt))) + , region_(std::move(reg)) + , comments_(std::move(com)) {} + + template = nullptr> + basic_value& operator=(T x) { + floating_format_info fmt; + if (this->is_floating()) { + fmt = this->as_floating_fmt(); + } + this->cleanup(); + this->type_ = value_t::floating; + this->region_ = region_type {}; + assigner(this->floating_, floating_storage(x, std::move(fmt))); + return *this; + } + + // }}} + + // constructor (string) =============================================== {{{ + + basic_value(string_type x) + : basic_value(std::move(x), + string_format_info {}, + std::vector {}, + region_type {}) {} + + basic_value(string_type x, string_format_info fmt) + : basic_value(std::move(x), + std::move(fmt), + std::vector {}, + region_type {}) {} + + basic_value(string_type x, std::vector com) + : basic_value(std::move(x), + string_format_info {}, + std::move(com), + region_type {}) {} + + basic_value(string_type x, string_format_info fmt, std::vector com) + : basic_value(std::move(x), std::move(fmt), std::move(com), region_type {}) { + } + + basic_value(string_type x, + string_format_info fmt, + std::vector com, + region_type reg) + : type_(value_t::string) + , string_(string_storage(std::move(x), std::move(fmt))) + , region_(std::move(reg)) + , comments_(std::move(com)) {} + + basic_value& operator=(string_type x) { + string_format_info fmt; + if (this->is_string()) { + fmt = this->as_string_fmt(); + } + this->cleanup(); + this->type_ = value_t::string; + this->region_ = region_type {}; + assigner(this->string_, string_storage(x, std::move(fmt))); + return *this; + } + + // "string literal" + + basic_value(const typename string_type::value_type* x) + : basic_value(x, + string_format_info {}, + std::vector {}, + region_type {}) {} + + basic_value(const typename string_type::value_type* x, string_format_info fmt) + : basic_value(x, std::move(fmt), std::vector {}, region_type {}) { + } + + basic_value(const typename string_type::value_type* x, + std::vector com) + : basic_value(x, string_format_info {}, std::move(com), region_type {}) {} + + basic_value(const typename string_type::value_type* x, + string_format_info fmt, + std::vector com) + : basic_value(x, std::move(fmt), std::move(com), region_type {}) {} + + basic_value(const typename string_type::value_type* x, + string_format_info fmt, + std::vector com, + region_type reg) + : type_(value_t::string) + , string_(string_storage(string_type(x), std::move(fmt))) + , region_(std::move(reg)) + , comments_(std::move(com)) {} + + basic_value& operator=(const typename string_type::value_type* x) { + string_format_info fmt; + if (this->is_string()) { + fmt = this->as_string_fmt(); + } + this->cleanup(); + this->type_ = value_t::string; + this->region_ = region_type {}; + assigner(this->string_, string_storage(string_type(x), std::move(fmt))); + return *this; + } + +#if defined(TOML11_HAS_STRING_VIEW) + using string_view_type = std::basic_string_view; + + basic_value(string_view_type x) + : basic_value(x, + string_format_info {}, + std::vector {}, + region_type {}) {} + + basic_value(string_view_type x, string_format_info fmt) + : basic_value(x, std::move(fmt), std::vector {}, region_type {}) { + } + + basic_value(string_view_type x, std::vector com) + : basic_value(x, string_format_info {}, std::move(com), region_type {}) {} + + basic_value(string_view_type x, + string_format_info fmt, + std::vector com) + : basic_value(x, std::move(fmt), std::move(com), region_type {}) {} + + basic_value(string_view_type x, + string_format_info fmt, + std::vector com, + region_type reg) + : type_(value_t::string) + , string_(string_storage(string_type(x), std::move(fmt))) + , region_(std::move(reg)) + , comments_(std::move(com)) {} + + basic_value& operator=(string_view_type x) { + string_format_info fmt; + if (this->is_string()) { + fmt = this->as_string_fmt(); + } + this->cleanup(); + this->type_ = value_t::string; + this->region_ = region_type {}; + assigner(this->string_, string_storage(string_type(x), std::move(fmt))); + return *this; + } + +#endif // TOML11_HAS_STRING_VIEW + + template , string_type>>, + detail::is_1byte_std_basic_string>::value, + std::nullptr_t> = nullptr> + basic_value(const T& x) + : basic_value(x, + string_format_info {}, + std::vector {}, + region_type {}) {} + + template , string_type>>, + detail::is_1byte_std_basic_string>::value, + std::nullptr_t> = nullptr> + basic_value(const T& x, string_format_info fmt) + : basic_value(x, std::move(fmt), std::vector {}, region_type {}) { + } + + template , string_type>>, + detail::is_1byte_std_basic_string>::value, + std::nullptr_t> = nullptr> + basic_value(const T& x, std::vector com) + : basic_value(x, string_format_info {}, std::move(com), region_type {}) {} + + template , string_type>>, + detail::is_1byte_std_basic_string>::value, + std::nullptr_t> = nullptr> + basic_value(const T& x, string_format_info fmt, std::vector com) + : basic_value(x, std::move(fmt), std::move(com), region_type {}) {} + + template , string_type>>, + detail::is_1byte_std_basic_string>::value, + std::nullptr_t> = nullptr> + basic_value(const T& x, + string_format_info fmt, + std::vector com, + region_type reg) + : type_(value_t::string) + , string_(string_storage(detail::string_conv(x), std::move(fmt))) + , region_(std::move(reg)) + , comments_(std::move(com)) {} + + template , string_type>>, + detail::is_1byte_std_basic_string>::value, + std::nullptr_t> = nullptr> + basic_value& operator=(const T& x) { + string_format_info fmt; + if (this->is_string()) { + fmt = this->as_string_fmt(); + } + this->cleanup(); + this->type_ = value_t::string; + this->region_ = region_type {}; + assigner(this->string_, + string_storage(detail::string_conv(x), std::move(fmt))); + return *this; + } + + // }}} + + // constructor (local_date) =========================================== {{{ + + basic_value(local_date_type x) + : basic_value(x, + local_date_format_info {}, + std::vector {}, + region_type {}) {} + + basic_value(local_date_type x, local_date_format_info fmt) + : basic_value(x, fmt, std::vector {}, region_type {}) {} + + basic_value(local_date_type x, std::vector com) + : basic_value(x, local_date_format_info {}, std::move(com), region_type {}) { + } + + basic_value(local_date_type x, + local_date_format_info fmt, + std::vector com) + : basic_value(x, fmt, std::move(com), region_type {}) {} + + basic_value(local_date_type x, + local_date_format_info fmt, + std::vector com, + region_type reg) + : type_(value_t::local_date) + , local_date_(local_date_storage(x, fmt)) + , region_(std::move(reg)) + , comments_(std::move(com)) {} + + basic_value& operator=(local_date_type x) { + local_date_format_info fmt; + if (this->is_local_date()) { + fmt = this->as_local_date_fmt(); + } + this->cleanup(); + this->type_ = value_t::local_date; + this->region_ = region_type {}; + assigner(this->local_date_, local_date_storage(x, fmt)); + return *this; + } + + // }}} + + // constructor (local_time) =========================================== {{{ + + basic_value(local_time_type x) + : basic_value(x, + local_time_format_info {}, + std::vector {}, + region_type {}) {} + + basic_value(local_time_type x, local_time_format_info fmt) + : basic_value(x, fmt, std::vector {}, region_type {}) {} + + basic_value(local_time_type x, std::vector com) + : basic_value(x, local_time_format_info {}, std::move(com), region_type {}) { + } + + basic_value(local_time_type x, + local_time_format_info fmt, + std::vector com) + : basic_value(x, fmt, std::move(com), region_type {}) {} + + basic_value(local_time_type x, + local_time_format_info fmt, + std::vector com, + region_type reg) + : type_(value_t::local_time) + , local_time_(local_time_storage(x, fmt)) + , region_(std::move(reg)) + , comments_(std::move(com)) {} + + basic_value& operator=(local_time_type x) { + local_time_format_info fmt; + if (this->is_local_time()) { + fmt = this->as_local_time_fmt(); + } + this->cleanup(); + this->type_ = value_t::local_time; + this->region_ = region_type {}; + assigner(this->local_time_, local_time_storage(x, fmt)); + return *this; + } + + template + basic_value(const std::chrono::duration& x) + : basic_value(local_time_type(x), + local_time_format_info {}, + std::vector {}, + region_type {}) {} + + template + basic_value(const std::chrono::duration& x, + local_time_format_info fmt) + : basic_value(local_time_type(x), + std::move(fmt), + std::vector {}, + region_type {}) {} + + template + basic_value(const std::chrono::duration& x, + std::vector com) + : basic_value(local_time_type(x), + local_time_format_info {}, + std::move(com), + region_type {}) {} + + template + basic_value(const std::chrono::duration& x, + local_time_format_info fmt, + std::vector com) + : basic_value(local_time_type(x), + std::move(fmt), + std::move(com), + region_type {}) {} + + template + basic_value(const std::chrono::duration& x, + local_time_format_info fmt, + std::vector com, + region_type reg) + : basic_value(local_time_type(x), + std::move(fmt), + std::move(com), + std::move(reg)) {} + + template + basic_value& operator=(const std::chrono::duration& x) { + local_time_format_info fmt; + if (this->is_local_time()) { + fmt = this->as_local_time_fmt(); + } + this->cleanup(); + this->type_ = value_t::local_time; + this->region_ = region_type {}; + assigner(this->local_time_, + local_time_storage(local_time_type(x), std::move(fmt))); + return *this; + } + + // }}} + + // constructor (local_datetime) =========================================== {{{ + + basic_value(local_datetime_type x) + : basic_value(x, + local_datetime_format_info {}, + std::vector {}, + region_type {}) {} + + basic_value(local_datetime_type x, local_datetime_format_info fmt) + : basic_value(x, fmt, std::vector {}, region_type {}) {} + + basic_value(local_datetime_type x, std::vector com) + : basic_value(x, local_datetime_format_info {}, std::move(com), region_type {}) { + } + + basic_value(local_datetime_type x, + local_datetime_format_info fmt, + std::vector com) + : basic_value(x, fmt, std::move(com), region_type {}) {} + + basic_value(local_datetime_type x, + local_datetime_format_info fmt, + std::vector com, + region_type reg) + : type_(value_t::local_datetime) + , local_datetime_(local_datetime_storage(x, fmt)) + , region_(std::move(reg)) + , comments_(std::move(com)) {} + + basic_value& operator=(local_datetime_type x) { + local_datetime_format_info fmt; + if (this->is_local_datetime()) { + fmt = this->as_local_datetime_fmt(); + } + this->cleanup(); + this->type_ = value_t::local_datetime; + this->region_ = region_type {}; + assigner(this->local_datetime_, local_datetime_storage(x, fmt)); + return *this; + } + + // }}} + + // constructor (offset_datetime) =========================================== {{{ + + basic_value(offset_datetime_type x) + : basic_value(x, + offset_datetime_format_info {}, + std::vector {}, + region_type {}) {} + + basic_value(offset_datetime_type x, offset_datetime_format_info fmt) + : basic_value(x, fmt, std::vector {}, region_type {}) {} + + basic_value(offset_datetime_type x, std::vector com) + : basic_value(x, + offset_datetime_format_info {}, + std::move(com), + region_type {}) {} + + basic_value(offset_datetime_type x, + offset_datetime_format_info fmt, + std::vector com) + : basic_value(x, fmt, std::move(com), region_type {}) {} + + basic_value(offset_datetime_type x, + offset_datetime_format_info fmt, + std::vector com, + region_type reg) + : type_(value_t::offset_datetime) + , offset_datetime_(offset_datetime_storage(x, fmt)) + , region_(std::move(reg)) + , comments_(std::move(com)) {} + + basic_value& operator=(offset_datetime_type x) { + offset_datetime_format_info fmt; + if (this->is_offset_datetime()) { + fmt = this->as_offset_datetime_fmt(); + } + this->cleanup(); + this->type_ = value_t::offset_datetime; + this->region_ = region_type {}; + assigner(this->offset_datetime_, offset_datetime_storage(x, fmt)); + return *this; + } + + // system_clock::time_point + + basic_value(std::chrono::system_clock::time_point x) + : basic_value(offset_datetime_type(x), + offset_datetime_format_info {}, + std::vector {}, + region_type {}) {} + + basic_value(std::chrono::system_clock::time_point x, + offset_datetime_format_info fmt) + : basic_value(offset_datetime_type(x), + fmt, + std::vector {}, + region_type {}) {} + + basic_value(std::chrono::system_clock::time_point x, + std::vector com) + : basic_value(offset_datetime_type(x), + offset_datetime_format_info {}, + std::move(com), + region_type {}) {} + + basic_value(std::chrono::system_clock::time_point x, + offset_datetime_format_info fmt, + std::vector com) + : basic_value(offset_datetime_type(x), fmt, std::move(com), region_type {}) { + } + + basic_value(std::chrono::system_clock::time_point x, + offset_datetime_format_info fmt, + std::vector com, + region_type reg) + : basic_value(offset_datetime_type(x), + std::move(fmt), + std::move(com), + std::move(reg)) {} + + basic_value& operator=(std::chrono::system_clock::time_point x) { + offset_datetime_format_info fmt; + if (this->is_offset_datetime()) { + fmt = this->as_offset_datetime_fmt(); + } + this->cleanup(); + this->type_ = value_t::offset_datetime; + this->region_ = region_type {}; + assigner(this->offset_datetime_, + offset_datetime_storage(offset_datetime_type(x), fmt)); + return *this; + } + + // }}} + + // constructor (array) ================================================ {{{ + + basic_value(array_type x) + : basic_value(std::move(x), + array_format_info {}, + std::vector {}, + region_type {}) {} + + basic_value(array_type x, array_format_info fmt) + : basic_value(std::move(x), + std::move(fmt), + std::vector {}, + region_type {}) {} + + basic_value(array_type x, std::vector com) + : basic_value(std::move(x), + array_format_info {}, + std::move(com), + region_type {}) {} + + basic_value(array_type x, array_format_info fmt, std::vector com) + : basic_value(std::move(x), fmt, std::move(com), region_type {}) {} + + basic_value(array_type x, + array_format_info fmt, + std::vector com, + region_type reg) + : type_(value_t::array) + , array_(array_storage(detail::storage(std::move(x)), + std::move(fmt))) + , region_(std::move(reg)) + , comments_(std::move(com)) {} + + basic_value& operator=(array_type x) { + array_format_info fmt; + if (this->is_array()) { + fmt = this->as_array_fmt(); + } + this->cleanup(); + this->type_ = value_t::array; + this->region_ = region_type {}; + assigner(this->array_, + array_storage(detail::storage(std::move(x)), + std::move(fmt))); + return *this; + } + + private: + template + using enable_if_array_like_t = cxx::enable_if_t< + cxx::conjunction, + cxx::negation>, + cxx::negation>, +#if defined(TOML11_HAS_STRING_VIEW) + cxx::negation>, +#endif + cxx::negation>, + cxx::negation>>::value, + std::nullptr_t>; + + public: + template = nullptr> + basic_value(T x) + : basic_value(std::move(x), + array_format_info {}, + std::vector {}, + region_type {}) {} + + template = nullptr> + basic_value(T x, array_format_info fmt) + : basic_value(std::move(x), + std::move(fmt), + std::vector {}, + region_type {}) {} + + template = nullptr> + basic_value(T x, std::vector com) + : basic_value(std::move(x), + array_format_info {}, + std::move(com), + region_type {}) {} + + template = nullptr> + basic_value(T x, array_format_info fmt, std::vector com) + : basic_value(std::move(x), fmt, std::move(com), region_type {}) {} + + template = nullptr> + basic_value(T x, array_format_info fmt, std::vector com, region_type reg) + : type_(value_t::array) + , array_(array_storage(detail::storage( + array_type(std::make_move_iterator(x.begin()), + std::make_move_iterator(x.end()))), + std::move(fmt))) + , region_(std::move(reg)) + , comments_(std::move(com)) {} + + template = nullptr> + basic_value& operator=(T x) { + array_format_info fmt; + if (this->is_array()) { + fmt = this->as_array_fmt(); + } + this->cleanup(); + this->type_ = value_t::array; + this->region_ = region_type {}; + + array_type a(std::make_move_iterator(x.begin()), + std::make_move_iterator(x.end())); + assigner(this->array_, + array_storage(detail::storage(std::move(a)), + std::move(fmt))); + return *this; + } + + // }}} + + // constructor (table) ================================================ {{{ + + basic_value(table_type x) + : basic_value(std::move(x), + table_format_info {}, + std::vector {}, + region_type {}) {} + + basic_value(table_type x, table_format_info fmt) + : basic_value(std::move(x), + std::move(fmt), + std::vector {}, + region_type {}) {} + + basic_value(table_type x, std::vector com) + : basic_value(std::move(x), + table_format_info {}, + std::move(com), + region_type {}) {} + + basic_value(table_type x, table_format_info fmt, std::vector com) + : basic_value(std::move(x), fmt, std::move(com), region_type {}) {} + + basic_value(table_type x, + table_format_info fmt, + std::vector com, + region_type reg) + : type_(value_t::table) + , table_(table_storage(detail::storage(std::move(x)), + std::move(fmt))) + , region_(std::move(reg)) + , comments_(std::move(com)) {} + + basic_value& operator=(table_type x) { + table_format_info fmt; + if (this->is_table()) { + fmt = this->as_table_fmt(); + } + this->cleanup(); + this->type_ = value_t::table; + this->region_ = region_type {}; + assigner(this->table_, + table_storage(detail::storage(std::move(x)), + std::move(fmt))); + return *this; + } + + // table-like + + private: + template + using enable_if_table_like_t = cxx::enable_if_t< + cxx::conjunction>, + detail::is_map, + cxx::negation>, + cxx::negation>>::value, + std::nullptr_t>; + + public: + template = nullptr> + basic_value(T x) + : basic_value(std::move(x), + table_format_info {}, + std::vector {}, + region_type {}) {} + + template = nullptr> + basic_value(T x, table_format_info fmt) + : basic_value(std::move(x), + std::move(fmt), + std::vector {}, + region_type {}) {} + + template = nullptr> + basic_value(T x, std::vector com) + : basic_value(std::move(x), + table_format_info {}, + std::move(com), + region_type {}) {} + + template = nullptr> + basic_value(T x, table_format_info fmt, std::vector com) + : basic_value(std::move(x), fmt, std::move(com), region_type {}) {} + + template = nullptr> + basic_value(T x, table_format_info fmt, std::vector com, region_type reg) + : type_(value_t::table) + , table_(table_storage(detail::storage( + table_type(std::make_move_iterator(x.begin()), + std::make_move_iterator(x.end()))), + std::move(fmt))) + , region_(std::move(reg)) + , comments_(std::move(com)) {} + + template = nullptr> + basic_value& operator=(T x) { + table_format_info fmt; + if (this->is_table()) { + fmt = this->as_table_fmt(); + } + this->cleanup(); + this->type_ = value_t::table; + this->region_ = region_type {}; + + table_type t(std::make_move_iterator(x.begin()), + std::make_move_iterator(x.end())); + assigner(this->table_, + table_storage(detail::storage(std::move(t)), + std::move(fmt))); + return *this; + } + + // }}} + + // constructor (user_defined) ========================================= {{{ + + template ::value, std::nullptr_t> = nullptr> + basic_value(const T& ud) + : basic_value( + into>::template into_toml(ud)) {} + + template ::value, std::nullptr_t> = nullptr> + basic_value(const T& ud, std::vector com) + : basic_value( + into>::template into_toml(ud), + std::move(com)) {} + + template ::value, std::nullptr_t> = nullptr> + basic_value& operator=(const T& ud) { + *this = into>::template into_toml(ud); + return *this; + } + + template , + cxx::negation>>::value, + std::nullptr_t> = nullptr> + basic_value(const T& ud) : basic_value(ud.into_toml()) {} + + template , + cxx::negation>>::value, + std::nullptr_t> = nullptr> + basic_value(const T& ud, std::vector com) + : basic_value(ud.into_toml(), std::move(com)) {} + + template , + cxx::negation>>::value, + std::nullptr_t> = nullptr> + basic_value& operator=(const T& ud) { + *this = ud.into_toml(); + return *this; + } + + template , + cxx::negation>>::value, + std::nullptr_t> = nullptr> + basic_value(const T& ud) + : basic_value(ud.template into_toml()) {} + + template , + cxx::negation>>::value, + std::nullptr_t> = nullptr> + basic_value(const T& ud, std::vector com) + : basic_value(ud.template into_toml(), std::move(com)) {} + + template , + cxx::negation>>::value, + std::nullptr_t> = nullptr> + basic_value& operator=(const T& ud) { + *this = ud.template into_toml(); + return *this; + } + + // }}} + + // empty value with region info ======================================= {{{ + + // mainly for `null` extension + basic_value(detail::none_t, region_type reg) noexcept + : type_(value_t::empty) + , empty_('\0') + , region_(std::move(reg)) + , comments_ {} {} + + // }}} + + // type checking ====================================================== {{{ + + template , value_type>::value, + std::nullptr_t> = nullptr> + bool is() const noexcept { + return detail::type_to_enum::value == this->type_; + } + + bool is(value_t t) const noexcept { + return t == this->type_; + } + + bool is_empty() const noexcept { + return this->is(value_t::empty); + } + + bool is_boolean() const noexcept { + return this->is(value_t::boolean); + } + + bool is_integer() const noexcept { + return this->is(value_t::integer); + } + + bool is_floating() const noexcept { + return this->is(value_t::floating); + } + + bool is_string() const noexcept { + return this->is(value_t::string); + } + + bool is_offset_datetime() const noexcept { + return this->is(value_t::offset_datetime); + } + + bool is_local_datetime() const noexcept { + return this->is(value_t::local_datetime); + } + + bool is_local_date() const noexcept { + return this->is(value_t::local_date); + } + + bool is_local_time() const noexcept { + return this->is(value_t::local_time); + } + + bool is_array() const noexcept { + return this->is(value_t::array); + } + + bool is_table() const noexcept { + return this->is(value_t::table); + } + + bool is_array_of_tables() const noexcept { + if (!this->is_array()) { + return false; + } + const auto& a = this->as_array(std::nothrow); // already checked. + + // when you define [[array.of.tables]], at least one empty table will be + // assigned. In case of array of inline tables, `array_of_tables = []`, + // there is no reason to consider this as an array of *tables*. + // So empty array is not an array-of-tables. + if (a.empty()) { + return false; + } + + // since toml v1.0.0 allows array of heterogeneous types, we need to + // check all the elements. if any of the elements is not a table, it + // is a heterogeneous array and cannot be expressed by `[[aot]]` form. + for (const auto& e : a) { + if (!e.is_table()) { + return false; + } + } + return true; + } + + value_t type() const noexcept { + return type_; + } + + // }}} + + // as_xxx (noexcept) version ========================================== {{{ + + template + const detail::enum_to_type_t>& as( + const std::nothrow_t&) const noexcept { + return detail::getter::get_nothrow(*this); + } + + template + detail::enum_to_type_t>& as( + const std::nothrow_t&) noexcept { + return detail::getter::get_nothrow(*this); + } + + const boolean_type& as_boolean(const std::nothrow_t&) const noexcept { + return this->boolean_.value; + } + + const integer_type& as_integer(const std::nothrow_t&) const noexcept { + return this->integer_.value; + } + + const floating_type& as_floating(const std::nothrow_t&) const noexcept { + return this->floating_.value; + } + + const string_type& as_string(const std::nothrow_t&) const noexcept { + return this->string_.value; + } + + const offset_datetime_type& as_offset_datetime( + const std::nothrow_t&) const noexcept { + return this->offset_datetime_.value; + } + + const local_datetime_type& as_local_datetime( + const std::nothrow_t&) const noexcept { + return this->local_datetime_.value; + } + + const local_date_type& as_local_date(const std::nothrow_t&) const noexcept { + return this->local_date_.value; + } + + const local_time_type& as_local_time(const std::nothrow_t&) const noexcept { + return this->local_time_.value; + } + + const array_type& as_array(const std::nothrow_t&) const noexcept { + return this->array_.value.get(); + } + + const table_type& as_table(const std::nothrow_t&) const noexcept { + return this->table_.value.get(); + } + + boolean_type& as_boolean(const std::nothrow_t&) noexcept { + return this->boolean_.value; + } + + integer_type& as_integer(const std::nothrow_t&) noexcept { + return this->integer_.value; + } + + floating_type& as_floating(const std::nothrow_t&) noexcept { + return this->floating_.value; + } + + string_type& as_string(const std::nothrow_t&) noexcept { + return this->string_.value; + } + + offset_datetime_type& as_offset_datetime(const std::nothrow_t&) noexcept { + return this->offset_datetime_.value; + } + + local_datetime_type& as_local_datetime(const std::nothrow_t&) noexcept { + return this->local_datetime_.value; + } + + local_date_type& as_local_date(const std::nothrow_t&) noexcept { + return this->local_date_.value; + } + + local_time_type& as_local_time(const std::nothrow_t&) noexcept { + return this->local_time_.value; + } + + array_type& as_array(const std::nothrow_t&) noexcept { + return this->array_.value.get(); + } + + table_type& as_table(const std::nothrow_t&) noexcept { + return this->table_.value.get(); + } + + // }}} + + // as_xxx (throw) ===================================================== {{{ + + template + const detail::enum_to_type_t>& as() const { + return detail::getter::get(*this); + } + + template + detail::enum_to_type_t>& as() { + return detail::getter::get(*this); + } + + const boolean_type& as_boolean() const { + if (this->type_ != value_t::boolean) { + this->throw_bad_cast("toml::value::as_boolean()", value_t::boolean); + } + return this->boolean_.value; + } + + const integer_type& as_integer() const { + if (this->type_ != value_t::integer) { + this->throw_bad_cast("toml::value::as_integer()", value_t::integer); + } + return this->integer_.value; + } + + const floating_type& as_floating() const { + if (this->type_ != value_t::floating) { + this->throw_bad_cast("toml::value::as_floating()", value_t::floating); + } + return this->floating_.value; + } + + const string_type& as_string() const { + if (this->type_ != value_t::string) { + this->throw_bad_cast("toml::value::as_string()", value_t::string); + } + return this->string_.value; + } + + const offset_datetime_type& as_offset_datetime() const { + if (this->type_ != value_t::offset_datetime) { + this->throw_bad_cast("toml::value::as_offset_datetime()", + value_t::offset_datetime); + } + return this->offset_datetime_.value; + } + + const local_datetime_type& as_local_datetime() const { + if (this->type_ != value_t::local_datetime) { + this->throw_bad_cast("toml::value::as_local_datetime()", + value_t::local_datetime); + } + return this->local_datetime_.value; + } + + const local_date_type& as_local_date() const { + if (this->type_ != value_t::local_date) { + this->throw_bad_cast("toml::value::as_local_date()", value_t::local_date); + } + return this->local_date_.value; + } + + const local_time_type& as_local_time() const { + if (this->type_ != value_t::local_time) { + this->throw_bad_cast("toml::value::as_local_time()", value_t::local_time); + } + return this->local_time_.value; + } + + const array_type& as_array() const { + if (this->type_ != value_t::array) { + this->throw_bad_cast("toml::value::as_array()", value_t::array); + } + return this->array_.value.get(); + } + + const table_type& as_table() const { + if (this->type_ != value_t::table) { + this->throw_bad_cast("toml::value::as_table()", value_t::table); + } + return this->table_.value.get(); + } + + // ------------------------------------------------------------------------ + // nonconst reference + + boolean_type& as_boolean() { + if (this->type_ != value_t::boolean) { + this->throw_bad_cast("toml::value::as_boolean()", value_t::boolean); + } + return this->boolean_.value; + } + + integer_type& as_integer() { + if (this->type_ != value_t::integer) { + this->throw_bad_cast("toml::value::as_integer()", value_t::integer); + } + return this->integer_.value; + } + + floating_type& as_floating() { + if (this->type_ != value_t::floating) { + this->throw_bad_cast("toml::value::as_floating()", value_t::floating); + } + return this->floating_.value; + } + + string_type& as_string() { + if (this->type_ != value_t::string) { + this->throw_bad_cast("toml::value::as_string()", value_t::string); + } + return this->string_.value; + } + + offset_datetime_type& as_offset_datetime() { + if (this->type_ != value_t::offset_datetime) { + this->throw_bad_cast("toml::value::as_offset_datetime()", + value_t::offset_datetime); + } + return this->offset_datetime_.value; + } + + local_datetime_type& as_local_datetime() { + if (this->type_ != value_t::local_datetime) { + this->throw_bad_cast("toml::value::as_local_datetime()", + value_t::local_datetime); + } + return this->local_datetime_.value; + } + + local_date_type& as_local_date() { + if (this->type_ != value_t::local_date) { + this->throw_bad_cast("toml::value::as_local_date()", value_t::local_date); + } + return this->local_date_.value; + } + + local_time_type& as_local_time() { + if (this->type_ != value_t::local_time) { + this->throw_bad_cast("toml::value::as_local_time()", value_t::local_time); + } + return this->local_time_.value; + } + + array_type& as_array() { + if (this->type_ != value_t::array) { + this->throw_bad_cast("toml::value::as_array()", value_t::array); + } + return this->array_.value.get(); + } + + table_type& as_table() { + if (this->type_ != value_t::table) { + this->throw_bad_cast("toml::value::as_table()", value_t::table); + } + return this->table_.value.get(); + } + + // }}} + + // format accessors (noexcept) ======================================== {{{ + + template + const detail::enum_to_fmt_type_t& as_fmt(const std::nothrow_t&) const noexcept { + return detail::getter::get_fmt_nothrow(*this); + } + + template + detail::enum_to_fmt_type_t& as_fmt(const std::nothrow_t&) noexcept { + return detail::getter::get_fmt_nothrow(*this); + } + + boolean_format_info& as_boolean_fmt(const std::nothrow_t&) noexcept { + return this->boolean_.format; + } + + integer_format_info& as_integer_fmt(const std::nothrow_t&) noexcept { + return this->integer_.format; + } + + floating_format_info& as_floating_fmt(const std::nothrow_t&) noexcept { + return this->floating_.format; + } + + string_format_info& as_string_fmt(const std::nothrow_t&) noexcept { + return this->string_.format; + } + + offset_datetime_format_info& as_offset_datetime_fmt( + const std::nothrow_t&) noexcept { + return this->offset_datetime_.format; + } + + local_datetime_format_info& as_local_datetime_fmt(const std::nothrow_t&) noexcept { + return this->local_datetime_.format; + } + + local_date_format_info& as_local_date_fmt(const std::nothrow_t&) noexcept { + return this->local_date_.format; + } + + local_time_format_info& as_local_time_fmt(const std::nothrow_t&) noexcept { + return this->local_time_.format; + } + + array_format_info& as_array_fmt(const std::nothrow_t&) noexcept { + return this->array_.format; + } + + table_format_info& as_table_fmt(const std::nothrow_t&) noexcept { + return this->table_.format; + } + + const boolean_format_info& as_boolean_fmt(const std::nothrow_t&) const noexcept { + return this->boolean_.format; + } + + const integer_format_info& as_integer_fmt(const std::nothrow_t&) const noexcept { + return this->integer_.format; + } + + const floating_format_info& as_floating_fmt(const std::nothrow_t&) const noexcept { + return this->floating_.format; + } + + const string_format_info& as_string_fmt(const std::nothrow_t&) const noexcept { + return this->string_.format; + } + + const offset_datetime_format_info& as_offset_datetime_fmt( + const std::nothrow_t&) const noexcept { + return this->offset_datetime_.format; + } + + const local_datetime_format_info& as_local_datetime_fmt( + const std::nothrow_t&) const noexcept { + return this->local_datetime_.format; + } + + const local_date_format_info& as_local_date_fmt( + const std::nothrow_t&) const noexcept { + return this->local_date_.format; + } + + const local_time_format_info& as_local_time_fmt( + const std::nothrow_t&) const noexcept { + return this->local_time_.format; + } + + const array_format_info& as_array_fmt(const std::nothrow_t&) const noexcept { + return this->array_.format; + } + + const table_format_info& as_table_fmt(const std::nothrow_t&) const noexcept { + return this->table_.format; + } + + // }}} + + // format accessors (throw) =========================================== {{{ + + template + const detail::enum_to_fmt_type_t& as_fmt() const { + return detail::getter::get_fmt(*this); + } + + template + detail::enum_to_fmt_type_t& as_fmt() { + return detail::getter::get_fmt(*this); + } + + const boolean_format_info& as_boolean_fmt() const { + if (this->type_ != value_t::boolean) { + this->throw_bad_cast("toml::value::as_boolean_fmt()", value_t::boolean); + } + return this->boolean_.format; + } + + const integer_format_info& as_integer_fmt() const { + if (this->type_ != value_t::integer) { + this->throw_bad_cast("toml::value::as_integer_fmt()", value_t::integer); + } + return this->integer_.format; + } + + const floating_format_info& as_floating_fmt() const { + if (this->type_ != value_t::floating) { + this->throw_bad_cast("toml::value::as_floating_fmt()", value_t::floating); + } + return this->floating_.format; + } + + const string_format_info& as_string_fmt() const { + if (this->type_ != value_t::string) { + this->throw_bad_cast("toml::value::as_string_fmt()", value_t::string); + } + return this->string_.format; + } + + const offset_datetime_format_info& as_offset_datetime_fmt() const { + if (this->type_ != value_t::offset_datetime) { + this->throw_bad_cast("toml::value::as_offset_datetime_fmt()", + value_t::offset_datetime); + } + return this->offset_datetime_.format; + } + + const local_datetime_format_info& as_local_datetime_fmt() const { + if (this->type_ != value_t::local_datetime) { + this->throw_bad_cast("toml::value::as_local_datetime_fmt()", + value_t::local_datetime); + } + return this->local_datetime_.format; + } + + const local_date_format_info& as_local_date_fmt() const { + if (this->type_ != value_t::local_date) { + this->throw_bad_cast("toml::value::as_local_date_fmt()", + value_t::local_date); + } + return this->local_date_.format; + } + + const local_time_format_info& as_local_time_fmt() const { + if (this->type_ != value_t::local_time) { + this->throw_bad_cast("toml::value::as_local_time_fmt()", + value_t::local_time); + } + return this->local_time_.format; + } + + const array_format_info& as_array_fmt() const { + if (this->type_ != value_t::array) { + this->throw_bad_cast("toml::value::as_array_fmt()", value_t::array); + } + return this->array_.format; + } + + const table_format_info& as_table_fmt() const { + if (this->type_ != value_t::table) { + this->throw_bad_cast("toml::value::as_table_fmt()", value_t::table); + } + return this->table_.format; + } + + // ------------------------------------------------------------------------ + // nonconst reference + + boolean_format_info& as_boolean_fmt() { + if (this->type_ != value_t::boolean) { + this->throw_bad_cast("toml::value::as_boolean_fmt()", value_t::boolean); + } + return this->boolean_.format; + } + + integer_format_info& as_integer_fmt() { + if (this->type_ != value_t::integer) { + this->throw_bad_cast("toml::value::as_integer_fmt()", value_t::integer); + } + return this->integer_.format; + } + + floating_format_info& as_floating_fmt() { + if (this->type_ != value_t::floating) { + this->throw_bad_cast("toml::value::as_floating_fmt()", value_t::floating); + } + return this->floating_.format; + } + + string_format_info& as_string_fmt() { + if (this->type_ != value_t::string) { + this->throw_bad_cast("toml::value::as_string_fmt()", value_t::string); + } + return this->string_.format; + } + + offset_datetime_format_info& as_offset_datetime_fmt() { + if (this->type_ != value_t::offset_datetime) { + this->throw_bad_cast("toml::value::as_offset_datetime_fmt()", + value_t::offset_datetime); + } + return this->offset_datetime_.format; + } + + local_datetime_format_info& as_local_datetime_fmt() { + if (this->type_ != value_t::local_datetime) { + this->throw_bad_cast("toml::value::as_local_datetime_fmt()", + value_t::local_datetime); + } + return this->local_datetime_.format; + } + + local_date_format_info& as_local_date_fmt() { + if (this->type_ != value_t::local_date) { + this->throw_bad_cast("toml::value::as_local_date_fmt()", + value_t::local_date); + } + return this->local_date_.format; + } + + local_time_format_info& as_local_time_fmt() { + if (this->type_ != value_t::local_time) { + this->throw_bad_cast("toml::value::as_local_time_fmt()", + value_t::local_time); + } + return this->local_time_.format; + } + + array_format_info& as_array_fmt() { + if (this->type_ != value_t::array) { + this->throw_bad_cast("toml::value::as_array_fmt()", value_t::array); + } + return this->array_.format; + } + + table_format_info& as_table_fmt() { + if (this->type_ != value_t::table) { + this->throw_bad_cast("toml::value::as_table_fmt()", value_t::table); + } + return this->table_.format; + } + + // }}} + + // table accessors ==================================================== {{{ + + value_type& at(const key_type& k) { + if (!this->is_table()) { + this->throw_bad_cast("toml::value::at(key_type)", value_t::table); + } + auto& table = this->as_table(std::nothrow); + const auto found = table.find(k); + if (found == table.end()) { + this->throw_key_not_found_error("toml::value::at", k); + } + assert(found->first == k); + return found->second; + } + + const value_type& at(const key_type& k) const { + if (!this->is_table()) { + this->throw_bad_cast("toml::value::at(key_type)", value_t::table); + } + const auto& table = this->as_table(std::nothrow); + const auto found = table.find(k); + if (found == table.end()) { + this->throw_key_not_found_error("toml::value::at", k); + } + assert(found->first == k); + return found->second; + } + + value_type& operator[](const key_type& k) { + if (this->is_empty()) { + (*this) = table_type {}; + } else if (!this->is_table()) // initialized, but not a table + { + this->throw_bad_cast("toml::value::operator[](key_type)", value_t::table); + } + return (this->as_table(std::nothrow))[k]; + } + + std::size_t count(const key_type& k) const { + if (!this->is_table()) { + this->throw_bad_cast("toml::value::count(key_type)", value_t::table); + } + return this->as_table(std::nothrow).count(k); + } + + bool contains(const key_type& k) const { + if (!this->is_table()) { + this->throw_bad_cast("toml::value::contains(key_type)", value_t::table); + } + const auto& table = this->as_table(std::nothrow); + return table.find(k) != table.end(); + } + + // }}} + + // array accessors ==================================================== {{{ + + value_type& at(const std::size_t idx) { + if (!this->is_array()) { + this->throw_bad_cast("toml::value::at(idx)", value_t::array); + } + auto& ar = this->as_array(std::nothrow); + + if (ar.size() <= idx) { + std::ostringstream oss; + oss << "actual length (" << ar.size() + << ") is shorter than the specified index (" << idx << ")."; + throw std::out_of_range(format_error( + "toml::value::at(idx): no element corresponding to the index", + this->location(), + oss.str())); + } + return ar.at(idx); + } + + const value_type& at(const std::size_t idx) const { + if (!this->is_array()) { + this->throw_bad_cast("toml::value::at(idx)", value_t::array); + } + const auto& ar = this->as_array(std::nothrow); + + if (ar.size() <= idx) { + std::ostringstream oss; + oss << "actual length (" << ar.size() + << ") is shorter than the specified index (" << idx << ")."; + + throw std::out_of_range(format_error( + "toml::value::at(idx): no element corresponding to the index", + this->location(), + oss.str())); + } + return ar.at(idx); + } + + value_type& operator[](const std::size_t idx) noexcept { + // no check... + return this->as_array(std::nothrow)[idx]; + } + + const value_type& operator[](const std::size_t idx) const noexcept { + // no check... + return this->as_array(std::nothrow)[idx]; + } + + void push_back(const value_type& x) { + if (!this->is_array()) { + this->throw_bad_cast("toml::value::push_back(idx)", value_t::array); + } + this->as_array(std::nothrow).push_back(x); + return; + } + + void push_back(value_type&& x) { + if (!this->is_array()) { + this->throw_bad_cast("toml::value::push_back(idx)", value_t::array); + } + this->as_array(std::nothrow).push_back(std::move(x)); + return; + } + + template + value_type& emplace_back(Ts&&... args) { + if (!this->is_array()) { + this->throw_bad_cast("toml::value::emplace_back(idx)", value_t::array); + } + auto& ar = this->as_array(std::nothrow); + ar.emplace_back(std::forward(args)...); + return ar.back(); + } + + std::size_t size() const { + switch (this->type_) { + case value_t::array: { + return this->as_array(std::nothrow).size(); + } + case value_t::table: { + return this->as_table(std::nothrow).size(); + } + case value_t::string: { + return this->as_string(std::nothrow).size(); + } + default: { + throw type_error( + format_error("toml::value::size(): bad_cast to container types", + this->location(), + "the actual type is " + to_string(this->type_)), + this->location()); + } + } + } + + // }}} + + source_location location() const { + return source_location(this->region_); + } + + const comment_type& comments() const noexcept { + return this->comments_; + } + + comment_type& comments() noexcept { + return this->comments_; + } + + private: + // private helper functions =========================================== {{{ + + void cleanup() noexcept { + switch (this->type_) { + case value_t::boolean: { + boolean_.~boolean_storage(); + break; + } + case value_t::integer: { + integer_.~integer_storage(); + break; + } + case value_t::floating: { + floating_.~floating_storage(); + break; + } + case value_t::string: { + string_.~string_storage(); + break; + } + case value_t::offset_datetime: { + offset_datetime_.~offset_datetime_storage(); + break; + } + case value_t::local_datetime: { + local_datetime_.~local_datetime_storage(); + break; + } + case value_t::local_date: { + local_date_.~local_date_storage(); + break; + } + case value_t::local_time: { + local_time_.~local_time_storage(); + break; + } + case value_t::array: { + array_.~array_storage(); + break; + } + case value_t::table: { + table_.~table_storage(); + break; + } + default: { + break; + } + } + this->type_ = value_t::empty; + return; + } + + template + static void assigner(T& dst, U&& v) { + const auto tmp = ::new (std::addressof(dst)) T(std::forward(v)); + assert(tmp == std::addressof(dst)); + (void)tmp; + } + + [[noreturn]] + void throw_bad_cast(const std::string& funcname, const value_t ty) const { + throw type_error(format_error(detail::make_type_error(*this, funcname, ty)), + this->location()); + } + + [[noreturn]] + void throw_key_not_found_error(const std::string& funcname, + const key_type& key) const { + throw std::out_of_range( + format_error(detail::make_not_found_error(*this, funcname, key))); + } + + template + friend void detail::change_region_of_value(basic_value&, + const basic_value&); + + template + friend class basic_value; + + // }}} + + private: + using boolean_storage = detail::value_with_format; + using integer_storage = detail::value_with_format; + using floating_storage = detail::value_with_format; + using string_storage = detail::value_with_format; + using offset_datetime_storage = + detail::value_with_format; + using local_datetime_storage = + detail::value_with_format; + using local_date_storage = + detail::value_with_format; + using local_time_storage = + detail::value_with_format; + using array_storage = + detail::value_with_format, array_format_info>; + using table_storage = + detail::value_with_format, table_format_info>; + + private: + value_t type_; + + union { + char empty_; // the smallest type + boolean_storage boolean_; + integer_storage integer_; + floating_storage floating_; + string_storage string_; + offset_datetime_storage offset_datetime_; + local_datetime_storage local_datetime_; + local_date_storage local_date_; + local_time_storage local_time_; + array_storage array_; + table_storage table_; + }; + + region_type region_; + comment_type comments_; + }; + + template + bool operator==(const basic_value& lhs, const basic_value& rhs) { + if (lhs.type() != rhs.type()) { + return false; + } + if (lhs.comments() != rhs.comments()) { + return false; + } + + switch (lhs.type()) { + case value_t::boolean: { + return lhs.as_boolean() == rhs.as_boolean(); + } + case value_t::integer: { + return lhs.as_integer() == rhs.as_integer(); + } + case value_t::floating: { + return lhs.as_floating() == rhs.as_floating(); + } + case value_t::string: { + return lhs.as_string() == rhs.as_string(); + } + case value_t::offset_datetime: { + return lhs.as_offset_datetime() == rhs.as_offset_datetime(); + } + case value_t::local_datetime: { + return lhs.as_local_datetime() == rhs.as_local_datetime(); + } + case value_t::local_date: { + return lhs.as_local_date() == rhs.as_local_date(); + } + case value_t::local_time: { + return lhs.as_local_time() == rhs.as_local_time(); + } + case value_t::array: { + return lhs.as_array() == rhs.as_array(); + } + case value_t::table: { + return lhs.as_table() == rhs.as_table(); + } + case value_t::empty: { + return true; + } + default: { + return false; + } + } + } + + template + bool operator!=(const basic_value& lhs, const basic_value& rhs) { + return !(lhs == rhs); + } + + template + cxx::enable_if_t< + cxx::conjunction::array_type>, + detail::is_comparable::table_type>>::value, + bool> + operator<(const basic_value& lhs, const basic_value& rhs) { + if (lhs.type() != rhs.type()) { + return (lhs.type() < rhs.type()); + } + switch (lhs.type()) { + case value_t::boolean: { + return lhs.as_boolean() < rhs.as_boolean() || + (lhs.as_boolean() == rhs.as_boolean() && + lhs.comments() < rhs.comments()); + } + case value_t::integer: { + return lhs.as_integer() < rhs.as_integer() || + (lhs.as_integer() == rhs.as_integer() && + lhs.comments() < rhs.comments()); + } + case value_t::floating: { + return lhs.as_floating() < rhs.as_floating() || + (lhs.as_floating() == rhs.as_floating() && + lhs.comments() < rhs.comments()); + } + case value_t::string: { + return lhs.as_string() < rhs.as_string() || + (lhs.as_string() == rhs.as_string() && + lhs.comments() < rhs.comments()); + } + case value_t::offset_datetime: { + return lhs.as_offset_datetime() < rhs.as_offset_datetime() || + (lhs.as_offset_datetime() == rhs.as_offset_datetime() && + lhs.comments() < rhs.comments()); + } + case value_t::local_datetime: { + return lhs.as_local_datetime() < rhs.as_local_datetime() || + (lhs.as_local_datetime() == rhs.as_local_datetime() && + lhs.comments() < rhs.comments()); + } + case value_t::local_date: { + return lhs.as_local_date() < rhs.as_local_date() || + (lhs.as_local_date() == rhs.as_local_date() && + lhs.comments() < rhs.comments()); + } + case value_t::local_time: { + return lhs.as_local_time() < rhs.as_local_time() || + (lhs.as_local_time() == rhs.as_local_time() && + lhs.comments() < rhs.comments()); + } + case value_t::array: { + return lhs.as_array() < rhs.as_array() || + (lhs.as_array() == rhs.as_array() && + lhs.comments() < rhs.comments()); + } + case value_t::table: { + return lhs.as_table() < rhs.as_table() || + (lhs.as_table() == rhs.as_table() && + lhs.comments() < rhs.comments()); + } + case value_t::empty: { + return lhs.comments() < rhs.comments(); + } + default: { + return lhs.comments() < rhs.comments(); + } + } + } + + template + cxx::enable_if_t< + cxx::conjunction::array_type>, + detail::is_comparable::table_type>>::value, + bool> + operator<=(const basic_value& lhs, const basic_value& rhs) { + return (lhs < rhs) || (lhs == rhs); + } + + template + cxx::enable_if_t< + cxx::conjunction::array_type>, + detail::is_comparable::table_type>>::value, + bool> + operator>(const basic_value& lhs, const basic_value& rhs) { + return !(lhs <= rhs); + } + + template + cxx::enable_if_t< + cxx::conjunction::array_type>, + detail::is_comparable::table_type>>::value, + bool> + operator>=(const basic_value& lhs, const basic_value& rhs) { + return !(lhs < rhs); + } + + // error_info helper + namespace detail { + template + error_info make_error_info_rec(error_info e, + const basic_value& v, + std::string msg, + Ts&&... tail) { + return make_error_info_rec(std::move(e), + v.location(), + std::move(msg), + std::forward(tail)...); + } + } // namespace detail + + template + error_info make_error_info(std::string title, + const basic_value& v, + std::string msg, + Ts&&... tail) { + return make_error_info(std::move(title), + v.location(), + std::move(msg), + std::forward(tail)...); + } + + template + std::string format_error(std::string title, + const basic_value& v, + std::string msg, + Ts&&... tail) { + return format_error(std::move(title), + v.location(), + std::move(msg), + std::forward(tail)...); + } + + namespace detail { + + template + error_info make_type_error(const basic_value& v, + const std::string& fname, + const value_t ty) { + return make_error_info(fname + ": bad_cast to " + to_string(ty), + v.location(), + "the actual type is " + to_string(v.type())); + } + + template + error_info make_not_found_error(const basic_value& v, + const std::string& fname, + const typename basic_value::key_type& key) { + const auto loc = v.location(); + const std::string title = fname + ": key \"" + + string_conv(key) + "\" not found"; + + std::vector> locs; + if (!loc.is_ok()) { + return error_info(title, locs); + } + + if (loc.first_line_number() == 1 && loc.first_column_number() == 1 && + loc.length() == 1) { + // The top-level table has its region at the 0th character of the file. + // That means that, in the case when a key is not found in the top-level + // table, the error message points to the first character. If the file has + // the first table at the first line, the error message would be like this. + // ```console + // [error] key "a" not found + // --> example.toml + // | + // 1 | [table] + // | ^------ in this table + // ``` + // It actually points to the top-level table at the first character, not + // `[table]`. But it is too confusing. To avoid the confusion, the error + // message should explicitly say "key not found in the top-level table". + locs.emplace_back(v.location(), "at the top-level table"); + } else { + locs.emplace_back(v.location(), "in this table"); + } + return error_info(title, locs); + } + +#define TOML11_DETAIL_GENERATE_COMPTIME_GETTER(ty) \ + template \ + struct getter { \ + using value_type = basic_value; \ + using result_type = enum_to_type_t; \ + using format_type = enum_to_fmt_type_t; \ + \ + static result_type& get(value_type& v) { \ + return v.as_##ty(); \ + } \ + static result_type const& get(const value_type& v) { \ + return v.as_##ty(); \ + } \ + \ + static result_type& get_nothrow(value_type& v) noexcept { \ + return v.as_##ty(std::nothrow); \ + } \ + static result_type const& get_nothrow(const value_type& v) noexcept { \ + return v.as_##ty(std::nothrow); \ + } \ + \ + static format_type& get_fmt(value_type& v) { \ + return v.as_##ty##_fmt(); \ + } \ + static format_type const& get_fmt(const value_type& v) { \ + return v.as_##ty##_fmt(); \ + } \ + \ + static format_type& get_fmt_nothrow(value_type& v) noexcept { \ + return v.as_##ty##_fmt(std::nothrow); \ + } \ + static format_type const& get_fmt_nothrow(const value_type& v) noexcept { \ + return v.as_##ty##_fmt(std::nothrow); \ + } \ + }; + + TOML11_DETAIL_GENERATE_COMPTIME_GETTER(boolean) + TOML11_DETAIL_GENERATE_COMPTIME_GETTER(integer) + TOML11_DETAIL_GENERATE_COMPTIME_GETTER(floating) + TOML11_DETAIL_GENERATE_COMPTIME_GETTER(string) + TOML11_DETAIL_GENERATE_COMPTIME_GETTER(offset_datetime) + TOML11_DETAIL_GENERATE_COMPTIME_GETTER(local_datetime) + TOML11_DETAIL_GENERATE_COMPTIME_GETTER(local_date) + TOML11_DETAIL_GENERATE_COMPTIME_GETTER(local_time) + TOML11_DETAIL_GENERATE_COMPTIME_GETTER(array) + TOML11_DETAIL_GENERATE_COMPTIME_GETTER(table) + +#undef TOML11_DETAIL_GENERATE_COMPTIME_GETTER + + template + void change_region_of_value(basic_value& dst, const basic_value& src) { + dst.region_ = std::move(src.region_); + return; + } + + } // namespace detail +} // namespace toml +#endif // TOML11_VALUE_HPP +#ifndef TOML11_VISIT_HPP +#define TOML11_VISIT_HPP + +namespace toml { + + template + cxx::return_type_of_t::boolean_type&> visit( + Visitor&& visitor, + const basic_value& v) { + switch (v.type()) { + case value_t::boolean: { + return visitor(v.as_boolean()); + } + case value_t::integer: { + return visitor(v.as_integer()); + } + case value_t::floating: { + return visitor(v.as_floating()); + } + case value_t::string: { + return visitor(v.as_string()); + } + case value_t::offset_datetime: { + return visitor(v.as_offset_datetime()); + } + case value_t::local_datetime: { + return visitor(v.as_local_datetime()); + } + case value_t::local_date: { + return visitor(v.as_local_date()); + } + case value_t::local_time: { + return visitor(v.as_local_time()); + } + case value_t::array: { + return visitor(v.as_array()); + } + case value_t::table: { + return visitor(v.as_table()); + } + case value_t::empty: + break; + default: + break; + } + throw type_error(format_error("[error] toml::visit: toml::basic_value " + "does not have any valid type.", + v.location(), + "here"), + v.location()); + } + + template + cxx::return_type_of_t::boolean_type&> visit( + Visitor&& visitor, + basic_value& v) { + switch (v.type()) { + case value_t::boolean: { + return visitor(v.as_boolean()); + } + case value_t::integer: { + return visitor(v.as_integer()); + } + case value_t::floating: { + return visitor(v.as_floating()); + } + case value_t::string: { + return visitor(v.as_string()); + } + case value_t::offset_datetime: { + return visitor(v.as_offset_datetime()); + } + case value_t::local_datetime: { + return visitor(v.as_local_datetime()); + } + case value_t::local_date: { + return visitor(v.as_local_date()); + } + case value_t::local_time: { + return visitor(v.as_local_time()); + } + case value_t::array: { + return visitor(v.as_array()); + } + case value_t::table: { + return visitor(v.as_table()); + } + case value_t::empty: + break; + default: + break; + } + throw type_error(format_error("[error] toml::visit: toml::basic_value " + "does not have any valid type.", + v.location(), + "here"), + v.location()); + } + + template + cxx::return_type_of_t::boolean_type&&> visit( + Visitor&& visitor, + basic_value&& v) { + switch (v.type()) { + case value_t::boolean: { + return visitor(std::move(v.as_boolean())); + } + case value_t::integer: { + return visitor(std::move(v.as_integer())); + } + case value_t::floating: { + return visitor(std::move(v.as_floating())); + } + case value_t::string: { + return visitor(std::move(v.as_string())); + } + case value_t::offset_datetime: { + return visitor(std::move(v.as_offset_datetime())); + } + case value_t::local_datetime: { + return visitor(std::move(v.as_local_datetime())); + } + case value_t::local_date: { + return visitor(std::move(v.as_local_date())); + } + case value_t::local_time: { + return visitor(std::move(v.as_local_time())); + } + case value_t::array: { + return visitor(std::move(v.as_array())); + } + case value_t::table: { + return visitor(std::move(v.as_table())); + } + case value_t::empty: + break; + default: + break; + } + throw type_error(format_error("[error] toml::visit: toml::basic_value " + "does not have any valid type.", + v.location(), + "here"), + v.location()); + } + +} // namespace toml +#endif // TOML11_VISIT_HPP +#ifndef TOML11_TYPES_HPP +#define TOML11_TYPES_HPP + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace toml { + + // forward decl + template + class basic_value; + + // when you use a special integer type as toml::value::integer_type, parse must + // be able to read it. So, type_config has static member functions that read the + // integer_type as {dec, hex, oct, bin}-integer. But, in most cases, operator<< + // is enough. To make config easy, we provide the default read functions. + // + // Before this functions is called, syntax is checked and prefix(`0x` etc) and + // spacer(`_`) are removed. + + template + result read_dec_int(const std::string& str, + const source_location src) { + constexpr auto max_digits = std::numeric_limits::digits; + assert(!str.empty()); + + T val { 0 }; + std::istringstream iss(str); + iss >> val; + if (iss.fail()) { + return err(make_error_info("toml::parse_dec_integer: " + "too large integer: current max digits = 2^" + + std::to_string(max_digits), + std::move(src), + "must be < 2^" + std::to_string(max_digits))); + } + return ok(val); + } + + template + result read_hex_int(const std::string& str, + const source_location src) { + constexpr auto max_digits = std::numeric_limits::digits; + assert(!str.empty()); + + T val { 0 }; + std::istringstream iss(str); + iss >> std::hex >> val; + if (iss.fail()) { + return err(make_error_info("toml::parse_hex_integer: " + "too large integer: current max value = 2^" + + std::to_string(max_digits), + std::move(src), + "must be < 2^" + std::to_string(max_digits))); + } + return ok(val); + } + + template + result read_oct_int(const std::string& str, + const source_location src) { + constexpr auto max_digits = std::numeric_limits::digits; + assert(!str.empty()); + + T val { 0 }; + std::istringstream iss(str); + iss >> std::oct >> val; + if (iss.fail()) { + return err(make_error_info("toml::parse_oct_integer: " + "too large integer: current max value = 2^" + + std::to_string(max_digits), + std::move(src), + "must be < 2^" + std::to_string(max_digits))); + } + return ok(val); + } + + template + result read_bin_int(const std::string& str, + const source_location src) { + constexpr auto is_bounded = std::numeric_limits::is_bounded; + constexpr auto max_digits = std::numeric_limits::digits; + const auto max_value = (std::numeric_limits::max)(); + + T val { 0 }; + T base { 1 }; + for (auto i = str.rbegin(); i != str.rend(); ++i) { + const auto c = *i; + if (c == '1') { + val += base; + // prevent `base` from overflow + if (is_bounded && max_value / 2 < base && std::next(i) != str.rend()) { + base = 0; + } else { + base *= 2; + } + } else { + assert(c == '0'); + + if (is_bounded && max_value / 2 < base && std::next(i) != str.rend()) { + base = 0; + } else { + base *= 2; + } + } + } + if (base == 0) { + return err(make_error_info("toml::parse_bin_integer: " + "too large integer: current max value = 2^" + + std::to_string(max_digits), + std::move(src), + "must be < 2^" + std::to_string(max_digits))); + } + return ok(val); + } + + template + result read_int(const std::string& str, + const source_location src, + const std::uint8_t base) { + assert(base == 10 || base == 16 || base == 8 || base == 2); + switch (base) { + case 2: { + return read_bin_int(str, src); + } + case 8: { + return read_oct_int(str, src); + } + case 16: { + return read_hex_int(str, src); + } + default: { + assert(base == 10); + return read_dec_int(str, src); + } + } + } + + inline result read_hex_float(const std::string& str, + const source_location src, + float val) { +#if defined(_MSC_VER) && !defined(__clang__) + const auto res = ::sscanf_s(str.c_str(), "%a", std::addressof(val)); +#else + const auto res = std::sscanf(str.c_str(), "%a", std::addressof(val)); +#endif + if (res != 1) { + return err( + make_error_info("toml::parse_floating: " + "failed to read hexadecimal floating point value ", + std::move(src), + "here")); + } + return ok(val); + } + + inline result read_hex_float(const std::string& str, + const source_location src, + double val) { +#if defined(_MSC_VER) && !defined(__clang__) + const auto res = ::sscanf_s(str.c_str(), "%la", std::addressof(val)); +#else + const auto res = std::sscanf(str.c_str(), "%la", std::addressof(val)); +#endif + if (res != 1) { + return err( + make_error_info("toml::parse_floating: " + "failed to read hexadecimal floating point value ", + std::move(src), + "here")); + } + return ok(val); + } + + template + cxx::enable_if_t< + cxx::conjunction, double>>, + cxx::negation, float>>>::value, + result> + read_hex_float(const std::string&, const source_location src, T) { + return err(make_error_info( + "toml::parse_floating: failed to read " + "floating point value because of unknown type in type_config", + std::move(src), + "here")); + } + + template + result read_dec_float(const std::string& str, + const source_location src) { + T val; + std::istringstream iss(str); + iss >> val; + if (iss.fail()) { + return err( + make_error_info("toml::parse_floating: " + "failed to read floating point value from stream", + std::move(src), + "here")); + } + return ok(val); + } + + template + result read_float(const std::string& str, + const source_location src, + const bool is_hex) { + if (is_hex) { + return read_hex_float(str, src, T {}); + } else { + return read_dec_float(str, src); + } + } + + struct type_config { + using comment_type = preserve_comments; + + using boolean_type = bool; + using integer_type = std::int64_t; + using floating_type = double; + using string_type = std::string; + + template + using array_type = std::vector; + template + using table_type = std::unordered_map; + + static result parse_int(const std::string& str, + const source_location src, + const std::uint8_t base) { + return read_int(str, src, base); + } + + static result parse_float(const std::string& str, + const source_location src, + const bool is_hex) { + return read_float(str, src, is_hex); + } + }; + + using value = basic_value; + using table = typename value::table_type; + using array = typename value::array_type; + + struct ordered_type_config { + using comment_type = preserve_comments; + + using boolean_type = bool; + using integer_type = std::int64_t; + using floating_type = double; + using string_type = std::string; + + template + using array_type = std::vector; + template + using table_type = ordered_map; + + static result parse_int(const std::string& str, + const source_location src, + const std::uint8_t base) { + return read_int(str, src, base); + } + + static result parse_float(const std::string& str, + const source_location src, + const bool is_hex) { + return read_float(str, src, is_hex); + } + }; + + using ordered_value = basic_value; + using ordered_table = typename ordered_value::table_type; + using ordered_array = typename ordered_value::array_type; + + // ---------------------------------------------------------------------------- + // meta functions for internal use + + namespace detail { + + // ---------------------------------------------------------------------------- + // check if type T has all the needed member types + + struct has_comment_type_impl { + template + static std::true_type check(typename T::comment_type*); + template + static std::false_type check(...); + }; + + template + using has_comment_type = decltype(has_comment_type_impl::check(nullptr)); + + struct has_integer_type_impl { + template + static std::true_type check(typename T::integer_type*); + template + static std::false_type check(...); + }; + + template + using has_integer_type = decltype(has_integer_type_impl::check(nullptr)); + + struct has_floating_type_impl { + template + static std::true_type check(typename T::floating_type*); + template + static std::false_type check(...); + }; + + template + using has_floating_type = decltype(has_floating_type_impl::check(nullptr)); + + struct has_string_type_impl { + template + static std::true_type check(typename T::string_type*); + template + static std::false_type check(...); + }; + + template + using has_string_type = decltype(has_string_type_impl::check(nullptr)); + + struct has_array_type_impl { + template + static std::true_type check(typename T::template array_type*); + template + static std::false_type check(...); + }; + + template + using has_array_type = decltype(has_array_type_impl::check(nullptr)); + + struct has_table_type_impl { + template + static std::true_type check(typename T::template table_type*); + template + static std::false_type check(...); + }; + + template + using has_table_type = decltype(has_table_type_impl::check(nullptr)); + + struct has_parse_int_impl { + template + static std::true_type check(decltype(std::declval().parse_int( + std::declval(), + std::declval(), + std::declval()))*); + template + static std::false_type check(...); + }; + + template + using has_parse_int = decltype(has_parse_int_impl::check(nullptr)); + + struct has_parse_float_impl { + template + static std::true_type check(decltype(std::declval().parse_float( + std::declval(), + std::declval(), + std::declval()))*); + template + static std::false_type check(...); + }; + + template + using has_parse_float = decltype(has_parse_float_impl::check(nullptr)); + + template + using is_type_config = cxx::conjunction, + has_integer_type, + has_floating_type, + has_string_type, + has_array_type, + has_table_type, + has_parse_int, + has_parse_float>; + + } // namespace detail +} // namespace toml + +#if defined(TOML11_COMPILE_SOURCES) +namespace toml { + extern template class basic_value; + extern template class basic_value; +} // namespace toml +#endif // TOML11_COMPILE_SOURCES + +#endif // TOML11_TYPES_HPP +#ifndef TOML11_GET_HPP +#define TOML11_GET_HPP + +#include + +#if defined(TOML11_HAS_STRING_VIEW) + #include +#endif // string_view + +namespace toml { + + // ============================================================================ + // T is toml::value; identity transformation. + + template + cxx::enable_if_t>::value, T>& get( + basic_value& v) { + return v; + } + + template + const cxx::enable_if_t>::value, T>& get( + const basic_value& v) { + return v; + } + + template + cxx::enable_if_t>::value, T> get( + basic_value&& v) { + return basic_value(std::move(v)); + } + + // ============================================================================ + // exact toml::* type + + template + cxx::enable_if_t>::value, T>& get( + basic_value& v) { + constexpr auto ty = detail::type_to_enum>::value; + return detail::getter::get(v); + } + + template + const cxx::enable_if_t>::value, T>& get( + const basic_value& v) { + constexpr auto ty = detail::type_to_enum>::value; + return detail::getter::get(v); + } + + template + cxx::enable_if_t>::value, T> get( + basic_value&& v) { + constexpr auto ty = detail::type_to_enum>::value; + return detail::getter::get(std::move(v)); + } + + // ============================================================================ + // T is toml::basic_value + + template + cxx::enable_if_t, + cxx::negation>>>::value, + T> + get(basic_value v) { + return T(std::move(v)); + } + + // ============================================================================ + // integer convertible from toml::value::integer_type + + template + cxx::enable_if_t, + cxx::negation>, + detail::is_not_toml_type>, + cxx::negation>, + cxx::negation>>::value, + T> + get(const basic_value& v) { + return static_cast(v.as_integer()); + } + + // ============================================================================ + // floating point convertible from toml::value::floating_type + + template + cxx::enable_if_t, + detail::is_not_toml_type>, + cxx::negation>, + cxx::negation>>::value, + T> + get(const basic_value& v) { + return static_cast(v.as_floating()); + } + + // ============================================================================ + // std::string with different char/trait/allocator + + template + cxx::enable_if_t>, + detail::is_1byte_std_basic_string>::value, + T> + get(const basic_value& v) { + return detail::string_conv>(v.as_string()); + } + + // ============================================================================ + // std::string_view + +#if defined(TOML11_HAS_STRING_VIEW) + + template + cxx::enable_if_t::string_type>::value, T> + get(const basic_value& v) { + return T(v.as_string()); + } + +#endif // string_view + + // ============================================================================ + // std::chrono::duration from toml::local_time + + template + cxx::enable_if_t::value, T> get( + const basic_value& v) { + return std::chrono::duration_cast( + std::chrono::nanoseconds(v.as_local_time())); + } + + // ============================================================================ + // std::chrono::system_clock::time_point from toml::datetime variants + + template + cxx::enable_if_t::value, T> get( + const basic_value& v) { + switch (v.type()) { + case value_t::local_date: { + return std::chrono::system_clock::time_point(v.as_local_date()); + } + case value_t::local_datetime: { + return std::chrono::system_clock::time_point(v.as_local_datetime()); + } + case value_t::offset_datetime: { + return std::chrono::system_clock::time_point(v.as_offset_datetime()); + } + default: { + const auto loc = v.location(); + throw type_error( + format_error("toml::get: " + "bad_cast to std::chrono::system_clock::time_point", + loc, + "the actual type is " + to_string(v.type())), + loc); + } + } + } + + // ============================================================================ + // forward declaration to use this recursively. ignore this and go ahead. + + // array-like (w/ push_back) + template + cxx::enable_if_t< + cxx::conjunction< + detail::is_container, // T is a container + detail::has_push_back_method, // .push_back() works + detail::is_not_toml_type>, // but not toml::array + cxx::negation>, // but not std::basic_string +#if defined(TOML11_HAS_STRING_VIEW) + cxx::negation>, // but not std::basic_string_view +#endif + cxx::negation>, // no T.from_toml() + cxx::negation>, // no toml::from + cxx::negation&>>>::value, + T> + get(const basic_value&); + + // std::array + template + cxx::enable_if_t::value, T> get(const basic_value&); + + // std::forward_list + template + cxx::enable_if_t::value, T> get( + const basic_value&); + + // std::pair + template + cxx::enable_if_t::value, T> get(const basic_value&); + + // std::tuple + template + cxx::enable_if_t::value, T> get(const basic_value&); + + // std::map (key is convertible from toml::value::key_type) + template + cxx::enable_if_t< + cxx::conjunction, // T is map + detail::is_not_toml_type>, // but not toml::table + std::is_convertible::key_type, + typename T::key_type>, // keys are convertible + cxx::negation>, // no T.from_toml() + cxx::negation>, // no toml::from + cxx::negation&>>>::value, + T> + get(const basic_value& v); + + // std::map (key is not convertible from toml::value::key_type, + // but is a std::basic_string) + template + cxx::enable_if_t< + cxx::conjunction< + detail::is_map, // T is map + detail::is_not_toml_type>, // but not toml::table + cxx::negation::key_type, + typename T::key_type>>, // keys are NOT convertible + detail::is_1byte_std_basic_string, // is std::basic_string + cxx::negation>, // no T.from_toml() + cxx::negation>, // no toml::from + cxx::negation&>>>::value, + T> + get(const basic_value& v); + + // toml::from::from_toml(v) + template + cxx::enable_if_t::value, T> get( + const basic_value&); + + // has T.from_toml(v) but no from + template + cxx::enable_if_t, // has T.from_toml() + cxx::negation>, // no toml::from + std::is_default_constructible // T{} works + >::value, + T> + get(const basic_value&); + + // T(const toml::value&) and T is not toml::basic_value, + // and it does not have `from` nor `from_toml`. + template + cxx::enable_if_t&>, // has T(const basic_value&) + cxx::negation>, // but not basic_value itself + cxx::negation>, // no .from_toml() + cxx::negation> // no toml::from + >::value, + T> + get(const basic_value&); + + // ============================================================================ + // array-like types; most likely STL container, like std::vector, etc. + + template + cxx::enable_if_t< + cxx::conjunction< + detail::is_container, // T is a container + detail::has_push_back_method, // .push_back() works + detail::is_not_toml_type>, // but not toml::array + cxx::negation>, // but not std::basic_string +#if defined(TOML11_HAS_STRING_VIEW) + cxx::negation>, // but not std::basic_string_view +#endif + cxx::negation>, // no T.from_toml() + cxx::negation>, // no toml::from + cxx::negation&>>>::value, + T> + get(const basic_value& v) { + using value_type = typename T::value_type; + const auto& a = v.as_array(); + + T container; + detail::try_reserve(container, a.size()); // if T has .reserve(), call it + + for (const auto& elem : a) { + container.push_back(get(elem)); + } + return container; + } + + // ============================================================================ + // std::array + + template + cxx::enable_if_t::value, T> get(const basic_value& v) { + using value_type = typename T::value_type; + const auto& a = v.as_array(); + + T container; + if (a.size() != container.size()) { + const auto loc = v.location(); + throw std::out_of_range( + format_error("toml::get: while converting to an array: " + " array size is " + + std::to_string(container.size()) + " but there are " + + std::to_string(a.size()) + " elements in toml array.", + loc, + "here")); + } + for (std::size_t i = 0; i < a.size(); ++i) { + container.at(i) = ::toml::get(a.at(i)); + } + return container; + } + + // ============================================================================ + // std::forward_list + + template + cxx::enable_if_t::value, T> get( + const basic_value& v) { + using value_type = typename T::value_type; + + T container; + for (const auto& elem : v.as_array()) { + container.push_front(get(elem)); + } + container.reverse(); + return container; + } + + // ============================================================================ + // std::pair + + template + cxx::enable_if_t::value, T> get(const basic_value& v) { + using first_type = typename T::first_type; + using second_type = typename T::second_type; + + const auto& ar = v.as_array(); + if (ar.size() != 2) { + const auto loc = v.location(); + throw std::out_of_range( + format_error("toml::get: while converting std::pair: " + " but there are " + + std::to_string(ar.size()) + " > 2 elements in toml array.", + loc, + "here")); + } + return std::make_pair(::toml::get(ar.at(0)), + ::toml::get(ar.at(1))); + } + + // ============================================================================ + // std::tuple. + + namespace detail { + template + T get_tuple_impl(const Array& a, cxx::index_sequence) { + return std::make_tuple( + ::toml::get::type>(a.at(I))...); + } + } // namespace detail + + template + cxx::enable_if_t::value, T> get(const basic_value& v) { + const auto& ar = v.as_array(); + if (ar.size() != std::tuple_size::value) { + const auto loc = v.location(); + throw std::out_of_range(format_error( + "toml::get: while converting std::tuple: " + " there are " + + std::to_string(ar.size()) + " > " + + std::to_string(std::tuple_size::value) + " elements in toml array.", + loc, + "here")); + } + return detail::get_tuple_impl( + ar, + cxx::make_index_sequence::value> {}); + } + + // ============================================================================ + // map-like types; most likely STL map, like std::map or std::unordered_map. + + // key is convertible from toml::value::key_type + template + cxx::enable_if_t< + cxx::conjunction, // T is map + detail::is_not_toml_type>, // but not toml::table + std::is_convertible::key_type, + typename T::key_type>, // keys are convertible + cxx::negation>, // no T.from_toml() + cxx::negation>, // no toml::from + cxx::negation&>>>::value, + T> + get(const basic_value& v) { + using key_type = typename T::key_type; + using mapped_type = typename T::mapped_type; + static_assert( + std::is_convertible::key_type, key_type>::value, + "toml::get only supports map type of which key_type is " + "convertible from toml::basic_value::key_type."); + + T m; + for (const auto& kv : v.as_table()) { + m.emplace(key_type(kv.first), get(kv.second)); + } + return m; + } + + // key is NOT convertible from toml::value::key_type but std::basic_string + template + cxx::enable_if_t< + cxx::conjunction< + detail::is_map, // T is map + detail::is_not_toml_type>, // but not toml::table + cxx::negation::key_type, + typename T::key_type>>, // keys are NOT convertible + detail::is_1byte_std_basic_string, // is std::basic_string + cxx::negation>, // no T.from_toml() + cxx::negation>, // no toml::from + cxx::negation&>>>::value, + T> + get(const basic_value& v) { + using key_type = typename T::key_type; + using mapped_type = typename T::mapped_type; + + T m; + for (const auto& kv : v.as_table()) { + m.emplace(detail::string_conv(kv.first), + get(kv.second)); + } + return m; + } + + // ============================================================================ + // user-defined, but convertible types. + + // toml::from + template + cxx::enable_if_t::value, T> get( + const basic_value& v) { + return ::toml::from::from_toml(v); + } + + // has T.from_toml(v) but no from + template + cxx::enable_if_t, // has T.from_toml() + cxx::negation>, // no toml::from + std::is_default_constructible // T{} works + >::value, + T> + get(const basic_value& v) { + T ud; + ud.from_toml(v); + return ud; + } + + // T(const toml::value&) and T is not toml::basic_value, + // and it does not have `from` nor `from_toml`. + template + cxx::enable_if_t&>, // has T(const basic_value&) + cxx::negation>, // but not basic_value itself + cxx::negation>, // no .from_toml() + cxx::negation> // no toml::from + >::value, + T> + get(const basic_value& v) { + return T(v); + } + + // ============================================================================ + // get_or(value, fallback) + + template + const cxx::enable_if_t::value, basic_value>& get_or( + const basic_value& v, + const basic_value&) { + return v; + } + + template + cxx::enable_if_t::value, basic_value>& get_or( + basic_value& v, + basic_value&) { + return v; + } + + template + cxx::enable_if_t::value, basic_value> get_or( + basic_value&& v, + basic_value&&) { + return v; + } + + // ---------------------------------------------------------------------------- + // specialization for the exact toml types (return type becomes lvalue ref) + + template + const cxx::enable_if_t>::value, T>& + get_or(const basic_value& v, const T& opt) noexcept { + try { + return get>(v); + } catch (...) { + return opt; + } + } + + template + cxx::enable_if_t>, + detail::is_exact_toml_type>>::value, + T>& + get_or(basic_value& v, T& opt) noexcept { + try { + return get>(v); + } catch (...) { + return opt; + } + } + + template + cxx::enable_if_t, basic_value>::value, + cxx::remove_cvref_t> + get_or(basic_value&& v, T&& opt) noexcept { + try { + return get>(std::move(v)); + } catch (...) { + return cxx::remove_cvref_t(std::forward(opt)); + } + } + + // ---------------------------------------------------------------------------- + // specialization for string literal + + // template + // typename basic_value::string_type + // get_or(const basic_value& v, + // const typename basic_value::string_type::value_type (&opt)[N]) + // { + // try + // { + // return v.as_string(); + // } + // catch(...) + // { + // return typename basic_value::string_type(opt); + // } + // } + // + // The above only matches to the literal, like `get_or(v, "foo");` but not + // ```cpp + // const auto opt = "foo"; + // const auto str = get_or(v, opt); + // ``` + // . And the latter causes an error. + // To match to both `"foo"` and `const auto opt = "foo"`, we take a pointer to + // a character here. + + template + typename basic_value::string_type get_or( + const basic_value& v, + const typename basic_value::string_type::value_type* opt) { + try { + return v.as_string(); + } catch (...) { + return typename basic_value::string_type(opt); + } + } + + // ---------------------------------------------------------------------------- + // others (require type conversion and return type cannot be lvalue reference) + + template + cxx::enable_if_t< + cxx::conjunction< + cxx::negation>, + cxx::negation>>, + cxx::negation, + const typename basic_value::string_type::value_type*>>>::value, + cxx::remove_cvref_t> + get_or(const basic_value& v, T&& opt) { + try { + return get>(v); + } catch (...) { + return cxx::remove_cvref_t(std::forward(opt)); + } + } + +} // namespace toml +#endif // TOML11_GET_HPP +#ifndef TOML11_FIND_HPP +#define TOML11_FIND_HPP + +#include + +#if defined(TOML11_HAS_STRING_VIEW) + #include +#endif + +namespace toml { + + // ---------------------------------------------------------------------------- + // find(value, key); + + template + decltype(::toml::get(std::declval&>())) find( + const basic_value& v, + const typename basic_value::key_type& ky) { + return ::toml::get(v.at(ky)); + } + + template + decltype(::toml::get(std::declval&>())) find( + basic_value& v, + const typename basic_value::key_type& ky) { + return ::toml::get(v.at(ky)); + } + + template + decltype(::toml::get(std::declval&&>())) find( + basic_value&& v, + const typename basic_value::key_type& ky) { + return ::toml::get(std::move(v.at(ky))); + } + + // ---------------------------------------------------------------------------- + // find(value, idx) + + template + decltype(::toml::get(std::declval&>())) find( + const basic_value& v, + const std::size_t idx) { + return ::toml::get(v.at(idx)); + } + + template + decltype(::toml::get(std::declval&>())) find( + basic_value& v, + const std::size_t idx) { + return ::toml::get(v.at(idx)); + } + + template + decltype(::toml::get(std::declval&&>())) find( + basic_value&& v, + const std::size_t idx) { + return ::toml::get(std::move(v.at(idx))); + } + + // ---------------------------------------------------------------------------- + // find(value, key/idx), w/o conversion + + template + cxx::enable_if_t::value, basic_value>& find( + basic_value& v, + const typename basic_value::key_type& ky) { + return v.at(ky); + } + + template + const cxx::enable_if_t::value, basic_value>& find( + const basic_value& v, + const typename basic_value::key_type& ky) { + return v.at(ky); + } + + template + cxx::enable_if_t::value, basic_value> find( + basic_value&& v, + const typename basic_value::key_type& ky) { + return basic_value(std::move(v.at(ky))); + } + + template + cxx::enable_if_t::value, basic_value>& find( + basic_value& v, + const std::size_t idx) { + return v.at(idx); + } + + template + const cxx::enable_if_t::value, basic_value>& find( + const basic_value& v, + const std::size_t idx) { + return v.at(idx); + } + + template + cxx::enable_if_t::value, basic_value> find( + basic_value&& v, + const std::size_t idx) { + return basic_value(std::move(v.at(idx))); + } + + // -------------------------------------------------------------------------- + // toml::find(toml::value, toml::key, Ts&& ... keys) + + namespace detail { + + // It suppresses warnings by -Wsign-conversion when we pass integer literal + // to toml::find. integer literal `0` is deduced as an int, and will be + // converted to std::size_t. This causes sign-conversion. + + template + std::size_t key_cast(const std::size_t& v) noexcept { + return v; + } + + template + cxx::enable_if_t>::value, std::size_t> key_cast( + const T& v) noexcept { + return static_cast(v); + } + + // for string-like (string, string literal, string_view) + + template + const typename basic_value::key_type& key_cast( + const typename basic_value::key_type& v) noexcept { + return v; + } + + template + typename basic_value::key_type key_cast( + const typename basic_value::key_type::value_type* v) { + return typename basic_value::key_type(v); + } +#if defined(TOML11_HAS_STRING_VIEW) + template + typename basic_value::key_type key_cast(const std::string_view v) { + return typename basic_value::key_type(v); + } +#endif // string_view + + } // namespace detail + + // ---------------------------------------------------------------------------- + // find(v, keys...) + + template + const cxx::enable_if_t::value, basic_value>& + find(const basic_value& v, const K1& k1, const K2& k2, const Ks&... ks) { + return find(v.at(detail::key_cast(k1)), detail::key_cast(k2), ks...); + } + + template + cxx::enable_if_t::value, basic_value>& find( + basic_value& v, + const K1& k1, + const K2& k2, + const Ks&... ks) { + return find(v.at(detail::key_cast(k1)), detail::key_cast(k2), ks...); + } + + template + cxx::enable_if_t::value, basic_value> find( + basic_value&& v, + const K1& k1, + const K2& k2, + const Ks&... ks) { + return find(std::move(v.at(detail::key_cast(k1))), + detail::key_cast(k2), + ks...); + } + + // ---------------------------------------------------------------------------- + // find(v, keys...) + + template + decltype(::toml::get(std::declval&>())) find( + const basic_value& v, + const K1& k1, + const K2& k2, + const Ks&... ks) { + return find(v.at(detail::key_cast(k1)), detail::key_cast(k2), ks...); + } + + template + decltype(::toml::get(std::declval&>())) find( + basic_value& v, + const K1& k1, + const K2& k2, + const Ks&... ks) { + return find(v.at(detail::key_cast(k1)), detail::key_cast(k2), ks...); + } + + template + decltype(::toml::get(std::declval&&>())) find( + basic_value&& v, + const K1& k1, + const K2& k2, + const Ks&... ks) { + return find(std::move(v.at(detail::key_cast(k1))), + detail::key_cast(k2), + ks...); + } + + // =========================================================================== + // find_or(value, key, fallback) + + // --------------------------------------------------------------------------- + // find_or(v, key, other_v) + + template + cxx::enable_if_t::value, basic_value>& find_or( + basic_value& v, + const K& k, + basic_value& opt) noexcept { + try { + return ::toml::find(v, detail::key_cast(k)); + } catch (...) { + return opt; + } + } + + template + const cxx::enable_if_t::value, basic_value>& find_or( + const basic_value& v, + const K& k, + const basic_value& opt) noexcept { + try { + return ::toml::find(v, detail::key_cast(k)); + } catch (...) { + return opt; + } + } + + template + cxx::enable_if_t::value, basic_value> find_or( + basic_value&& v, + const K& k, + basic_value&& opt) noexcept { + try { + return ::toml::find(v, detail::key_cast(k)); + } catch (...) { + return opt; + } + } + + // --------------------------------------------------------------------------- + // toml types (return type can be a reference) + + template + cxx::enable_if_t>::value, + const cxx::remove_cvref_t&> + find_or(const basic_value& v, const K& k, const T& opt) { + try { + return ::toml::get(v.at(detail::key_cast(k))); + } catch (...) { + return opt; + } + } + + template + cxx::enable_if_t>, + detail::is_exact_toml_type>>::value, + cxx::remove_cvref_t&> + find_or(basic_value& v, const K& k, T& opt) { + try { + return ::toml::get(v.at(detail::key_cast(k))); + } catch (...) { + return opt; + } + } + + template + cxx::enable_if_t>::value, + cxx::remove_cvref_t> + find_or(basic_value&& v, const K& k, T opt) { + try { + return ::toml::get(std::move(v.at(detail::key_cast(k)))); + } catch (...) { + return T(std::move(opt)); + } + } + + // --------------------------------------------------------------------------- + // string literal (deduced as std::string) + + // XXX to avoid confusion when T is explicitly specified in find_or(), + // we restrict the string type as std::string. + template + cxx::enable_if_t::value, std::string> find_or( + const basic_value& v, + const K& k, + const char* opt) { + try { + return ::toml::get(v.at(detail::key_cast(k))); + } catch (...) { + return std::string(opt); + } + } + + // --------------------------------------------------------------------------- + // other types (requires type conversion and return type cannot be a reference) + + template + cxx::enable_if_t< + cxx::conjunction< + cxx::negation>>, + detail::is_not_toml_type, basic_value>, + cxx::negation, + const typename basic_value::string_type::value_type*>>>::value, + cxx::remove_cvref_t> + find_or(const basic_value& v, const K& ky, T opt) { + try { + return ::toml::get>(v.at(detail::key_cast(ky))); + } catch (...) { + return cxx::remove_cvref_t(std::move(opt)); + } + } + + // ---------------------------------------------------------------------------- + // recursive + + namespace detail { + template + T& last_one(T& arg) { + return arg; + } + + template + auto last_one(T1&, T2& arg, Ts&... args) -> decltype(last_one(arg, args...)) { + return last_one(arg, args...); + } + } // namespace detail + + template + auto find_or(Value&& v, const K1& k1, const K2& k2, K3&& k3, Ks&&... keys) noexcept + -> cxx::enable_if_t< + detail::is_basic_value>::value, + decltype(find_or(v, k2, std::forward(k3), std::forward(keys)...))> { + try { + return find_or(v.at(k1), k2, std::forward(k3), std::forward(keys)...); + } catch (...) { + return detail::last_one(k3, keys...); + } + } + + template + T find_or(const basic_value& v, + const K1& k1, + const K2& k2, + const K3& k3, + const Ks&... keys) noexcept { + try { + return find_or(v.at(k1), k2, k3, keys...); + } catch (...) { + return static_cast(detail::last_one(k3, keys...)); + } + } + + template + auto find_or(Value&& v, const K1& k1, const K2& k2, K3&& k3, K4&& k4, Ks&&... keys) noexcept + -> cxx::enable_if_t>::value, + decltype(find_or(v, + k2, + std::forward(k3), + std::forward(k4), + std::forward(keys)...))> { + try { + return find_or(v.at(k1), + k2, + std::forward(k3), + std::forward(k4), + std::forward(keys)...); + } catch (...) { + return detail::last_one(k4, keys...); + } + } + + template + T find_or(const basic_value& v, + const K1& k1, + const K2& k2, + const K3& k3, + const K4& k4, + const Ks&... keys) noexcept { + try { + return find_or(v.at(k1), k2, k3, k4, keys...); + } catch (...) { + return static_cast(detail::last_one(k4, keys...)); + } + } + +} // namespace toml +#endif // TOML11_FIND_HPP +#ifndef TOML11_CONVERSION_HPP +#define TOML11_CONVERSION_HPP + +#if defined(TOML11_HAS_OPTIONAL) + + #include + +namespace toml { + namespace detail { + + template + inline constexpr bool is_optional_v = false; + + template + inline constexpr bool is_optional_v> = true; + + template + void find_member_variable_from_value(T& obj, + const basic_value& v, + const char* var_name) { + if constexpr (is_optional_v) { + if (v.contains(var_name)) { + obj = toml::find(v, var_name); + } else { + obj = std::nullopt; + } + } else { + obj = toml::find(v, var_name); + } + } + + template + void assign_member_variable_to_value(const T& obj, + basic_value& v, + const char* var_name) { + if constexpr (is_optional_v) { + if (obj.has_value()) { + v[var_name] = obj.value(); + } + } else { + v[var_name] = obj; + } + } + + } // namespace detail +} // namespace toml + +#else + +namespace toml { + namespace detail { + + template + void find_member_variable_from_value(T& obj, + const basic_value& v, + const char* var_name) { + obj = toml::find(v, var_name); + } + + template + void assign_member_variable_to_value(const T& obj, + basic_value& v, + const char* var_name) { + v[var_name] = obj; + } + + } // namespace detail +} // namespace toml + +#endif // optional + +// use it in the following way. +// ```cpp +// namespace foo +// { +// struct Foo +// { +// std::string s; +// double d; +// int i; +// }; +// } // foo +// +// TOML11_DEFINE_CONVERSION_NON_INTRUSIVE(foo::Foo, s, d, i) +// ``` +// +// And then you can use `toml::get(v)` and `toml::find(file, "foo");` +// + +#define TOML11_STRINGIZE_AUX(x) #x +#define TOML11_STRINGIZE(x) TOML11_STRINGIZE_AUX(x) + +#define TOML11_CONCATENATE_AUX(x, y) x##y +#define TOML11_CONCATENATE(x, y) TOML11_CONCATENATE_AUX(x, y) + +// ============================================================================ +// TOML11_DEFINE_CONVERSION_NON_INTRUSIVE + +#ifndef TOML11_WITHOUT_DEFINE_NON_INTRUSIVE + + // ---------------------------------------------------------------------------- + // TOML11_ARGS_SIZE + + #define TOML11_INDEX_RSEQ() \ + 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, \ + 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 + #define TOML11_ARGS_SIZE_IMPL(ARG1, \ + ARG2, \ + ARG3, \ + ARG4, \ + ARG5, \ + ARG6, \ + ARG7, \ + ARG8, \ + ARG9, \ + ARG10, \ + ARG11, \ + ARG12, \ + ARG13, \ + ARG14, \ + ARG15, \ + ARG16, \ + ARG17, \ + ARG18, \ + ARG19, \ + ARG20, \ + ARG21, \ + ARG22, \ + ARG23, \ + ARG24, \ + ARG25, \ + ARG26, \ + ARG27, \ + ARG28, \ + ARG29, \ + ARG30, \ + ARG31, \ + ARG32, \ + N, \ + ...) \ + N + #define TOML11_ARGS_SIZE_AUX(...) TOML11_ARGS_SIZE_IMPL(__VA_ARGS__) + #define TOML11_ARGS_SIZE(...) \ + TOML11_ARGS_SIZE_AUX(__VA_ARGS__, TOML11_INDEX_RSEQ()) + + // ---------------------------------------------------------------------------- + // TOML11_FOR_EACH_VA_ARGS + + #define TOML11_FOR_EACH_VA_ARGS_AUX_1(FUNCTOR, ARG1) FUNCTOR(ARG1) + #define TOML11_FOR_EACH_VA_ARGS_AUX_2(FUNCTOR, ARG1, ...) \ + FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_1(FUNCTOR, __VA_ARGS__) + #define TOML11_FOR_EACH_VA_ARGS_AUX_3(FUNCTOR, ARG1, ...) \ + FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_2(FUNCTOR, __VA_ARGS__) + #define TOML11_FOR_EACH_VA_ARGS_AUX_4(FUNCTOR, ARG1, ...) \ + FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_3(FUNCTOR, __VA_ARGS__) + #define TOML11_FOR_EACH_VA_ARGS_AUX_5(FUNCTOR, ARG1, ...) \ + FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_4(FUNCTOR, __VA_ARGS__) + #define TOML11_FOR_EACH_VA_ARGS_AUX_6(FUNCTOR, ARG1, ...) \ + FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_5(FUNCTOR, __VA_ARGS__) + #define TOML11_FOR_EACH_VA_ARGS_AUX_7(FUNCTOR, ARG1, ...) \ + FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_6(FUNCTOR, __VA_ARGS__) + #define TOML11_FOR_EACH_VA_ARGS_AUX_8(FUNCTOR, ARG1, ...) \ + FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_7(FUNCTOR, __VA_ARGS__) + #define TOML11_FOR_EACH_VA_ARGS_AUX_9(FUNCTOR, ARG1, ...) \ + FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_8(FUNCTOR, __VA_ARGS__) + #define TOML11_FOR_EACH_VA_ARGS_AUX_10(FUNCTOR, ARG1, ...) \ + FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_9(FUNCTOR, __VA_ARGS__) + #define TOML11_FOR_EACH_VA_ARGS_AUX_11(FUNCTOR, ARG1, ...) \ + FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_10(FUNCTOR, __VA_ARGS__) + #define TOML11_FOR_EACH_VA_ARGS_AUX_12(FUNCTOR, ARG1, ...) \ + FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_11(FUNCTOR, __VA_ARGS__) + #define TOML11_FOR_EACH_VA_ARGS_AUX_13(FUNCTOR, ARG1, ...) \ + FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_12(FUNCTOR, __VA_ARGS__) + #define TOML11_FOR_EACH_VA_ARGS_AUX_14(FUNCTOR, ARG1, ...) \ + FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_13(FUNCTOR, __VA_ARGS__) + #define TOML11_FOR_EACH_VA_ARGS_AUX_15(FUNCTOR, ARG1, ...) \ + FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_14(FUNCTOR, __VA_ARGS__) + #define TOML11_FOR_EACH_VA_ARGS_AUX_16(FUNCTOR, ARG1, ...) \ + FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_15(FUNCTOR, __VA_ARGS__) + #define TOML11_FOR_EACH_VA_ARGS_AUX_17(FUNCTOR, ARG1, ...) \ + FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_16(FUNCTOR, __VA_ARGS__) + #define TOML11_FOR_EACH_VA_ARGS_AUX_18(FUNCTOR, ARG1, ...) \ + FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_17(FUNCTOR, __VA_ARGS__) + #define TOML11_FOR_EACH_VA_ARGS_AUX_19(FUNCTOR, ARG1, ...) \ + FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_18(FUNCTOR, __VA_ARGS__) + #define TOML11_FOR_EACH_VA_ARGS_AUX_20(FUNCTOR, ARG1, ...) \ + FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_19(FUNCTOR, __VA_ARGS__) + #define TOML11_FOR_EACH_VA_ARGS_AUX_21(FUNCTOR, ARG1, ...) \ + FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_20(FUNCTOR, __VA_ARGS__) + #define TOML11_FOR_EACH_VA_ARGS_AUX_22(FUNCTOR, ARG1, ...) \ + FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_21(FUNCTOR, __VA_ARGS__) + #define TOML11_FOR_EACH_VA_ARGS_AUX_23(FUNCTOR, ARG1, ...) \ + FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_22(FUNCTOR, __VA_ARGS__) + #define TOML11_FOR_EACH_VA_ARGS_AUX_24(FUNCTOR, ARG1, ...) \ + FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_23(FUNCTOR, __VA_ARGS__) + #define TOML11_FOR_EACH_VA_ARGS_AUX_25(FUNCTOR, ARG1, ...) \ + FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_24(FUNCTOR, __VA_ARGS__) + #define TOML11_FOR_EACH_VA_ARGS_AUX_26(FUNCTOR, ARG1, ...) \ + FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_25(FUNCTOR, __VA_ARGS__) + #define TOML11_FOR_EACH_VA_ARGS_AUX_27(FUNCTOR, ARG1, ...) \ + FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_26(FUNCTOR, __VA_ARGS__) + #define TOML11_FOR_EACH_VA_ARGS_AUX_28(FUNCTOR, ARG1, ...) \ + FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_27(FUNCTOR, __VA_ARGS__) + #define TOML11_FOR_EACH_VA_ARGS_AUX_29(FUNCTOR, ARG1, ...) \ + FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_28(FUNCTOR, __VA_ARGS__) + #define TOML11_FOR_EACH_VA_ARGS_AUX_30(FUNCTOR, ARG1, ...) \ + FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_29(FUNCTOR, __VA_ARGS__) + #define TOML11_FOR_EACH_VA_ARGS_AUX_31(FUNCTOR, ARG1, ...) \ + FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_30(FUNCTOR, __VA_ARGS__) + #define TOML11_FOR_EACH_VA_ARGS_AUX_32(FUNCTOR, ARG1, ...) \ + FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_31(FUNCTOR, __VA_ARGS__) + + #define TOML11_FOR_EACH_VA_ARGS(FUNCTOR, ...) \ + TOML11_CONCATENATE(TOML11_FOR_EACH_VA_ARGS_AUX_, \ + TOML11_ARGS_SIZE(__VA_ARGS__)) \ + (FUNCTOR, __VA_ARGS__) + + #define TOML11_FIND_MEMBER_VARIABLE_FROM_VALUE(VAR_NAME) \ + toml::detail::find_member_variable_from_value(obj.VAR_NAME, \ + v, \ + TOML11_STRINGIZE(VAR_NAME)); + + #define TOML11_ASSIGN_MEMBER_VARIABLE_TO_VALUE(VAR_NAME) \ + toml::detail::assign_member_variable_to_value(obj.VAR_NAME, \ + v, \ + TOML11_STRINGIZE(VAR_NAME)); + + #define TOML11_DEFINE_CONVERSION_NON_INTRUSIVE(NAME, ...) \ + namespace toml { \ + template <> \ + struct from { \ + template \ + static NAME from_toml(const basic_value& v) { \ + NAME obj; \ + TOML11_FOR_EACH_VA_ARGS(TOML11_FIND_MEMBER_VARIABLE_FROM_VALUE, \ + __VA_ARGS__) \ + return obj; \ + } \ + }; \ + template <> \ + struct into { \ + template \ + static basic_value into_toml(const NAME& obj) { \ + ::toml::basic_value v = typename ::toml::basic_value::table_type {}; \ + TOML11_FOR_EACH_VA_ARGS(TOML11_ASSIGN_MEMBER_VARIABLE_TO_VALUE, \ + __VA_ARGS__) \ + return v; \ + } \ + }; \ + } /* toml */ + +#endif // TOML11_WITHOUT_DEFINE_NON_INTRUSIVE + +#endif // TOML11_CONVERSION_HPP +#ifndef TOML11_CONTEXT_HPP +#define TOML11_CONTEXT_HPP + +#include + +namespace toml { + namespace detail { + + template + class context { + public: + explicit context(const spec& toml_spec) + : toml_spec_(toml_spec) + , errors_ {} {} + + bool has_error() const noexcept { + return !errors_.empty(); + } + + const std::vector& errors() const noexcept { + return errors_; + } + + semantic_version& toml_version() noexcept { + return toml_spec_.version; + } + + const semantic_version& toml_version() const noexcept { + return toml_spec_.version; + } + + spec& toml_spec() noexcept { + return toml_spec_; + } + + const spec& toml_spec() const noexcept { + return toml_spec_; + } + + void report_error(error_info err) { + this->errors_.push_back(std::move(err)); + } + + error_info pop_last_error() { + assert(!errors_.empty()); + auto e = std::move(errors_.back()); + errors_.pop_back(); + return e; + } + + private: + spec toml_spec_; + std::vector errors_; + }; + + } // namespace detail +} // namespace toml + +#if defined(TOML11_COMPILE_SOURCES) +namespace toml { + struct type_config; + struct ordered_type_config; + + namespace detail { + extern template class context<::toml::type_config>; + extern template class context<::toml::ordered_type_config>; + } // namespace detail +} // namespace toml +#endif // TOML11_COMPILE_SOURCES + +#endif // TOML11_CONTEXT_HPP +#ifndef TOML11_SCANNER_HPP +#define TOML11_SCANNER_HPP + +#ifndef TOML11_SCANNER_FWD_HPP + #define TOML11_SCANNER_FWD_HPP + + #include + #include + #include + #include + #include + #include + #include + +namespace toml { + namespace detail { + + class scanner_base { + public: + virtual ~scanner_base() = default; + virtual region scan(location& loc) const = 0; + virtual scanner_base* clone() const = 0; + + // returns expected character or set of characters or literal. + // to show the error location, it changes loc (in `sequence`, especially). + virtual std::string expected_chars(location& loc) const = 0; + virtual std::string name() const = 0; + }; + + // make `scanner*` copyable + struct scanner_storage { + template >::value, + std::nullptr_t> = nullptr> + explicit scanner_storage(Scanner&& s) + : scanner_(cxx::make_unique>( + std::forward(s))) {} + + ~scanner_storage() = default; + + scanner_storage(const scanner_storage& other); + scanner_storage& operator=(const scanner_storage& other); + scanner_storage(scanner_storage&&) = default; + scanner_storage& operator=(scanner_storage&&) = default; + + bool is_ok() const noexcept { + return static_cast(scanner_); + } + + region scan(location& loc) const; + + std::string expected_chars(location& loc) const; + + scanner_base& get() const noexcept; + + std::string name() const; + + private: + std::unique_ptr scanner_; + }; + + // ---------------------------------------------------------------------------- + + class character final : public scanner_base { + public: + using char_type = location::char_type; + + public: + explicit character(const char_type c) noexcept : value_(c) {} + + ~character() override = default; + + region scan(location& loc) const override; + + std::string expected_chars(location&) const override; + + scanner_base* clone() const override; + + std::string name() const override; + + private: + char_type value_; + }; + + // ---------------------------------------------------------------------------- + + class character_either final : public scanner_base { + public: + using char_type = location::char_type; + + public: + explicit character_either(std::initializer_list cs) noexcept + : chars_(std::move(cs)) { + assert(!this->chars_.empty()); + } + + template + explicit character_either(const char (&cs)[N]) noexcept + : chars_(N - 1, '\0') { + static_assert(N >= 1, ""); + for (std::size_t i = 0; i + 1 < N; ++i) { + chars_.at(i) = char_type(cs[i]); + } + } + + ~character_either() override = default; + + region scan(location& loc) const override; + + std::string expected_chars(location&) const override; + + scanner_base* clone() const override; + + void push_back(const char_type c); + + std::string name() const override; + + private: + std::vector chars_; + }; + + // ---------------------------------------------------------------------------- + + class character_in_range final : public scanner_base { + public: + using char_type = location::char_type; + + public: + explicit character_in_range(const char_type from, const char_type to) noexcept + : from_(from) + , to_(to) {} + + ~character_in_range() override = default; + + region scan(location& loc) const override; + + std::string expected_chars(location&) const override; + + scanner_base* clone() const override; + + std::string name() const override; + + private: + char_type from_; + char_type to_; + }; + + // ---------------------------------------------------------------------------- + + class literal final : public scanner_base { + public: + using char_type = location::char_type; + + public: + template + explicit literal(const char (&cs)[N]) noexcept + : value_(cs) + , size_(N - 1) // remove null character at the end + {} + + ~literal() override = default; + + region scan(location& loc) const override; + + std::string expected_chars(location&) const override; + + scanner_base* clone() const override; + + std::string name() const override; + + private: + const char* value_; + std::size_t size_; + }; + + // ---------------------------------------------------------------------------- + + class sequence final : public scanner_base { + public: + using char_type = location::char_type; + + public: + template + explicit sequence(Ts&&... args) { + push_back_all(std::forward(args)...); + } + + sequence(const sequence&) = default; + sequence(sequence&&) = default; + sequence& operator=(const sequence&) = default; + sequence& operator=(sequence&&) = default; + ~sequence() override = default; + + region scan(location& loc) const override; + + std::string expected_chars(location& loc) const override; + + scanner_base* clone() const override; + + template + void push_back(Scanner&& other_scanner) { + this->others_.emplace_back(std::forward(other_scanner)); + } + + std::string name() const override; + + private: + void push_back_all() { + return; + } + + template + void push_back_all(T&& head, Ts&&... args) { + others_.emplace_back(std::forward(head)); + push_back_all(std::forward(args)...); + return; + } + + private: + std::vector others_; + }; + + // ---------------------------------------------------------------------------- + + class either final : public scanner_base { + public: + using char_type = location::char_type; + + public: + template + explicit either(Ts&&... args) { + push_back_all(std::forward(args)...); + } + + either(const either&) = default; + either(either&&) = default; + either& operator=(const either&) = default; + either& operator=(either&&) = default; + ~either() override = default; + + region scan(location& loc) const override; + + std::string expected_chars(location& loc) const override; + + scanner_base* clone() const override; + + template + void push_back(Scanner&& other_scanner) { + this->others_.emplace_back(std::forward(other_scanner)); + } + + std::string name() const override; + + private: + void push_back_all() { + return; + } + + template + void push_back_all(T&& head, Ts&&... args) { + others_.emplace_back(std::forward(head)); + push_back_all(std::forward(args)...); + return; + } + + private: + std::vector others_; + }; + + // ---------------------------------------------------------------------------- + + class repeat_exact final : public scanner_base { + public: + using char_type = location::char_type; + + public: + template + repeat_exact(const std::size_t length, Scanner&& other) + : length_(length) + , other_(std::forward(other)) {} + + repeat_exact(const repeat_exact&) = default; + repeat_exact(repeat_exact&&) = default; + repeat_exact& operator=(const repeat_exact&) = default; + repeat_exact& operator=(repeat_exact&&) = default; + ~repeat_exact() override = default; + + region scan(location& loc) const override; + + std::string expected_chars(location& loc) const override; + + scanner_base* clone() const override; + + std::string name() const override; + + private: + std::size_t length_; + scanner_storage other_; + }; + + // ---------------------------------------------------------------------------- + + class repeat_at_least final : public scanner_base { + public: + using char_type = location::char_type; + + public: + template + repeat_at_least(const std::size_t length, Scanner&& s) + : length_(length) + , other_(std::forward(s)) {} + + repeat_at_least(const repeat_at_least&) = default; + repeat_at_least(repeat_at_least&&) = default; + repeat_at_least& operator=(const repeat_at_least&) = default; + repeat_at_least& operator=(repeat_at_least&&) = default; + ~repeat_at_least() override = default; + + region scan(location& loc) const override; + + std::string expected_chars(location& loc) const override; + + scanner_base* clone() const override; + + std::string name() const override; + + private: + std::size_t length_; + scanner_storage other_; + }; + + // ---------------------------------------------------------------------------- + + class maybe final : public scanner_base { + public: + using char_type = location::char_type; + + public: + template + explicit maybe(Scanner&& s) : other_(std::forward(s)) {} + + maybe(const maybe&) = default; + maybe(maybe&&) = default; + maybe& operator=(const maybe&) = default; + maybe& operator=(maybe&&) = default; + ~maybe() override = default; + + region scan(location& loc) const override; + + std::string expected_chars(location&) const override; + + scanner_base* clone() const override; + + std::string name() const override; + + private: + scanner_storage other_; + }; + + } // namespace detail +} // namespace toml +#endif // TOML11_SCANNER_FWD_HPP + +#if !defined(TOML11_COMPILE_SOURCES) + #ifndef TOML11_SCANNER_IMPL_HPP + #define TOML11_SCANNER_IMPL_HPP + +namespace toml { + namespace detail { + + TOML11_INLINE scanner_storage::scanner_storage(const scanner_storage& other) + : scanner_(nullptr) { + if (other.is_ok()) { + scanner_.reset(other.get().clone()); + } + } + + TOML11_INLINE scanner_storage& scanner_storage::operator=( + const scanner_storage& other) { + if (this == std::addressof(other)) { + return *this; + } + if (other.is_ok()) { + scanner_.reset(other.get().clone()); + } + return *this; + } + + TOML11_INLINE region scanner_storage::scan(location& loc) const { + assert(this->is_ok()); + return this->scanner_->scan(loc); + } + + TOML11_INLINE std::string scanner_storage::expected_chars(location& loc) const { + assert(this->is_ok()); + return this->scanner_->expected_chars(loc); + } + + TOML11_INLINE scanner_base& scanner_storage::get() const noexcept { + assert(this->is_ok()); + return *scanner_; + } + + TOML11_INLINE std::string scanner_storage::name() const { + assert(this->is_ok()); + return this->scanner_->name(); + } + + // ---------------------------------------------------------------------------- + + TOML11_INLINE region character::scan(location& loc) const { + if (loc.eof()) { + return region {}; + } + + if (loc.current() == this->value_) { + const auto first = loc; + loc.advance(1); + return region(first, loc); + } + return region {}; + } + + TOML11_INLINE std::string character::expected_chars(location&) const { + return show_char(value_); + } + + TOML11_INLINE scanner_base* character::clone() const { + return new character(*this); + } + + TOML11_INLINE std::string character::name() const { + return "character{" + show_char(value_) + "}"; + } + + // ---------------------------------------------------------------------------- + + TOML11_INLINE region character_either::scan(location& loc) const { + if (loc.eof()) { + return region {}; + } + + for (const auto c : this->chars_) { + if (loc.current() == c) { + const auto first = loc; + loc.advance(1); + return region(first, loc); + } + } + return region {}; + } + + TOML11_INLINE std::string character_either::expected_chars(location&) const { + assert(!chars_.empty()); + + std::string expected; + if (chars_.size() == 1) { + expected += show_char(chars_.at(0)); + } else if (chars_.size() == 2) { + expected += show_char(chars_.at(0)) + " or " + show_char(chars_.at(1)); + } else { + for (std::size_t i = 0; i < chars_.size(); ++i) { + if (i != 0) { + expected += ", "; + } + if (i + 1 == chars_.size()) { + expected += "or "; + } + expected += show_char(chars_.at(i)); + } + } + return expected; + } + + TOML11_INLINE scanner_base* character_either::clone() const { + return new character_either(*this); + } + + TOML11_INLINE void character_either::push_back(const char_type c) { + chars_.push_back(c); + } + + TOML11_INLINE std::string character_either::name() const { + std::string n("character_either{"); + for (const auto c : this->chars_) { + n += show_char(c); + n += ", "; + } + if (!this->chars_.empty()) { + n.pop_back(); + n.pop_back(); + } + n += "}"; + return n; + } + + // ---------------------------------------------------------------------------- + // character_in_range + + TOML11_INLINE region character_in_range::scan(location& loc) const { + if (loc.eof()) { + return region {}; + } + + const auto curr = loc.current(); + if (this->from_ <= curr && curr <= this->to_) { + const auto first = loc; + loc.advance(1); + return region(first, loc); + } + return region {}; + } + + TOML11_INLINE std::string character_in_range::expected_chars(location&) const { + std::string expected("from `"); + expected += show_char(from_); + expected += "` to `"; + expected += show_char(to_); + expected += "`"; + return expected; + } + + TOML11_INLINE scanner_base* character_in_range::clone() const { + return new character_in_range(*this); + } + + TOML11_INLINE std::string character_in_range::name() const { + return "character_in_range{" + show_char(from_) + "," + show_char(to_) + "}"; + } + + // ---------------------------------------------------------------------------- + // literal + + TOML11_INLINE region literal::scan(location& loc) const { + const auto first = loc; + for (std::size_t i = 0; i < size_; ++i) { + if (loc.eof() || char_type(value_[i]) != loc.current()) { + loc = first; + return region {}; + } + loc.advance(1); + } + return region(first, loc); + } + + TOML11_INLINE std::string literal::expected_chars(location&) const { + return std::string(value_); + } + + TOML11_INLINE scanner_base* literal::clone() const { + return new literal(*this); + } + + TOML11_INLINE std::string literal::name() const { + return std::string("literal{") + std::string(value_, size_) + "}"; + } + + // ---------------------------------------------------------------------------- + // sequence + + TOML11_INLINE region sequence::scan(location& loc) const { + const auto first = loc; + for (const auto& other : others_) { + const auto reg = other.scan(loc); + if (!reg.is_ok()) { + loc = first; + return region {}; + } + } + return region(first, loc); + } + + TOML11_INLINE std::string sequence::expected_chars(location& loc) const { + const auto first = loc; + for (const auto& other : others_) { + const auto reg = other.scan(loc); + if (!reg.is_ok()) { + return other.expected_chars(loc); + } + } + assert(false); + return ""; // XXX + } + + TOML11_INLINE scanner_base* sequence::clone() const { + return new sequence(*this); + } + + TOML11_INLINE std::string sequence::name() const { + std::string n("sequence{"); + for (const auto& other : others_) { + n += other.name(); + n += ", "; + } + if (!this->others_.empty()) { + n.pop_back(); + n.pop_back(); + } + n += "}"; + return n; + } + + // ---------------------------------------------------------------------------- + // either + + TOML11_INLINE region either::scan(location& loc) const { + for (const auto& other : others_) { + const auto reg = other.scan(loc); + if (reg.is_ok()) { + return reg; + } + } + return region {}; + } + + TOML11_INLINE std::string either::expected_chars(location& loc) const { + assert(!others_.empty()); + + std::string expected = others_.at(0).expected_chars(loc); + if (others_.size() == 2) { + expected += " or "; + expected += others_.at(1).expected_chars(loc); + } else { + for (std::size_t i = 1; i < others_.size(); ++i) { + expected += ", "; + if (i + 1 == others_.size()) { + expected += "or "; + } + expected += others_.at(i).expected_chars(loc); + } + } + return expected; + } + + TOML11_INLINE scanner_base* either::clone() const { + return new either(*this); + } + + TOML11_INLINE std::string either::name() const { + std::string n("either{"); + for (const auto& other : others_) { + n += other.name(); + n += ", "; + } + if (!this->others_.empty()) { + n.pop_back(); + n.pop_back(); + } + n += "}"; + return n; + } + + // ---------------------------------------------------------------------------- + // repeat_exact + + TOML11_INLINE region repeat_exact::scan(location& loc) const { + const auto first = loc; + for (std::size_t i = 0; i < length_; ++i) { + const auto reg = other_.scan(loc); + if (!reg.is_ok()) { + loc = first; + return region {}; + } + } + return region(first, loc); + } + + TOML11_INLINE std::string repeat_exact::expected_chars(location& loc) const { + for (std::size_t i = 0; i < length_; ++i) { + const auto reg = other_.scan(loc); + if (!reg.is_ok()) { + return other_.expected_chars(loc); + } + } + assert(false); + return ""; + } + + TOML11_INLINE scanner_base* repeat_exact::clone() const { + return new repeat_exact(*this); + } + + TOML11_INLINE std::string repeat_exact::name() const { + return "repeat_exact{" + std::to_string(length_) + ", " + other_.name() + "}"; + } + + // ---------------------------------------------------------------------------- + // repeat_at_least + + TOML11_INLINE region repeat_at_least::scan(location& loc) const { + const auto first = loc; + for (std::size_t i = 0; i < length_; ++i) { + const auto reg = other_.scan(loc); + if (!reg.is_ok()) { + loc = first; + return region {}; + } + } + while (!loc.eof()) { + const auto checkpoint = loc; + const auto reg = other_.scan(loc); + if (!reg.is_ok()) { + loc = checkpoint; + return region(first, loc); + } + } + return region(first, loc); + } + + TOML11_INLINE std::string repeat_at_least::expected_chars(location& loc) const { + for (std::size_t i = 0; i < length_; ++i) { + const auto reg = other_.scan(loc); + if (!reg.is_ok()) { + return other_.expected_chars(loc); + } + } + assert(false); + return ""; + } + + TOML11_INLINE scanner_base* repeat_at_least::clone() const { + return new repeat_at_least(*this); + } + + TOML11_INLINE std::string repeat_at_least::name() const { + return "repeat_at_least{" + std::to_string(length_) + ", " + + other_.name() + "}"; + } + + // ---------------------------------------------------------------------------- + // maybe + + TOML11_INLINE region maybe::scan(location& loc) const { + const auto first = loc; + const auto reg = other_.scan(loc); + if (!reg.is_ok()) { + loc = first; + } + return region(first, loc); + } + + TOML11_INLINE std::string maybe::expected_chars(location&) const { + return ""; + } + + TOML11_INLINE scanner_base* maybe::clone() const { + return new maybe(*this); + } + + TOML11_INLINE std::string maybe::name() const { + return "maybe{" + other_.name() + "}"; + } + + } // namespace detail +} // namespace toml + #endif // TOML11_SCANNER_IMPL_HPP +#endif + +#endif // TOML11_SCANNER_HPP +#ifndef TOML11_SYNTAX_HPP +#define TOML11_SYNTAX_HPP + +#ifndef TOML11_SYNTAX_FWD_HPP + #define TOML11_SYNTAX_FWD_HPP + +namespace toml { + namespace detail { + namespace syntax { + + using char_type = location::char_type; + + // =========================================================================== + // UTF-8 + + // avoid redundant representation and out-of-unicode sequence + + character_in_range utf8_1byte(const spec&); + sequence utf8_2bytes(const spec&); + sequence utf8_3bytes(const spec&); + sequence utf8_4bytes(const spec&); + + class non_ascii final : public scanner_base { + public: + using char_type = location::char_type; + + public: + explicit non_ascii(const spec& s) noexcept; + ~non_ascii() override = default; + + region scan(location& loc) const override { + return scanner_.scan(loc); + } + + std::string expected_chars(location&) const override { + return "non-ascii utf-8 bytes"; + } + + scanner_base* clone() const override { + return new non_ascii(*this); + } + + std::string name() const override { + return "non_ascii"; + } + + private: + either scanner_; + }; + + // =========================================================================== + // Whitespace + + character_either wschar(const spec&); + + repeat_at_least ws(const spec& s); + + // =========================================================================== + // Newline + + either newline(const spec&); + + // =========================================================================== + // Comments + + either allowed_comment_char(const spec& s); + + // XXX Note that it does not take newline + sequence comment(const spec& s); + + // =========================================================================== + // Boolean + + either boolean(const spec&); + + // =========================================================================== + // Integer + + class digit final : public scanner_base { + public: + using char_type = location::char_type; + + public: + explicit digit(const spec&) noexcept; + ~digit() override = default; + + region scan(location& loc) const override { + return scanner_.scan(loc); + } + + std::string expected_chars(location&) const override { + return "digit [0-9]"; + } + + scanner_base* clone() const override { + return new digit(*this); + } + + std::string name() const override { + return "digit"; + } + + private: + character_in_range scanner_; + }; + + class alpha final : public scanner_base { + public: + using char_type = location::char_type; + + public: + explicit alpha(const spec&) noexcept; + ~alpha() override = default; + + region scan(location& loc) const override { + return scanner_.scan(loc); + } + + std::string expected_chars(location&) const override { + return "alpha [a-zA-Z]"; + } + + scanner_base* clone() const override { + return new alpha(*this); + } + + std::string name() const override { + return "alpha"; + } + + private: + either scanner_; + }; + + class hexdig final : public scanner_base { + public: + using char_type = location::char_type; + + public: + explicit hexdig(const spec& s) noexcept; + ~hexdig() override = default; + + region scan(location& loc) const override { + return scanner_.scan(loc); + } + + std::string expected_chars(location&) const override { + return "hex [0-9a-fA-F]"; + } + + scanner_base* clone() const override { + return new hexdig(*this); + } + + std::string name() const override { + return "hexdig"; + } + + private: + either scanner_; + }; + + sequence num_suffix(const spec& s); + + sequence dec_int(const spec& s); + sequence hex_int(const spec& s); + sequence oct_int(const spec&); + sequence bin_int(const spec&); + either integer(const spec& s); + + // =========================================================================== + // Floating + + sequence zero_prefixable_int(const spec& s); + sequence fractional_part(const spec& s); + sequence exponent_part(const spec& s); + sequence hex_floating(const spec& s); + either floating(const spec& s); + + // =========================================================================== + // Datetime + + sequence local_date(const spec& s); + sequence local_time(const spec& s); + either time_offset(const spec& s); + sequence full_time(const spec& s); + character_either time_delim(const spec&); + sequence local_datetime(const spec& s); + sequence offset_datetime(const spec& s); + + // =========================================================================== + // String + + sequence escaped(const spec& s); + + either basic_char(const spec& s); + + sequence basic_string(const spec& s); + + // --------------------------------------------------------------------------- + // multiline string + + sequence escaped_newline(const spec& s); + sequence ml_basic_string(const spec& s); + + // --------------------------------------------------------------------------- + // literal string + + either literal_char(const spec& s); + sequence literal_string(const spec& s); + + sequence ml_literal_string(const spec& s); + + either string(const spec& s); + + // =========================================================================== + // Keys + + // to keep `expected_chars` simple + class non_ascii_key_char final : public scanner_base { + public: + using char_type = location::char_type; + + private: + using in_range = character_in_range; // make definition short + + public: + explicit non_ascii_key_char(const spec& s) noexcept; + ~non_ascii_key_char() override = default; + + region scan(location& loc) const override; + + std::string expected_chars(location&) const override { + return "bare key non-ASCII script"; + } + + scanner_base* clone() const override { + return new non_ascii_key_char(*this); + } + + std::string name() const override { + return "non-ASCII bare key"; + } + + private: + std::uint32_t read_utf8(location& loc) const; + }; + + repeat_at_least unquoted_key(const spec& s); + + either quoted_key(const spec& s); + + either simple_key(const spec& s); + + sequence dot_sep(const spec& s); + + sequence dotted_key(const spec& s); + + class key final : public scanner_base { + public: + using char_type = location::char_type; + + public: + explicit key(const spec& s) noexcept; + ~key() override = default; + + region scan(location& loc) const override { + return scanner_.scan(loc); + } + + std::string expected_chars(location&) const override { + return "basic key([a-zA-Z0-9_-]) or quoted key(\" or ')"; + } + + scanner_base* clone() const override { + return new key(*this); + } + + std::string name() const override { + return "key"; + } + + private: + either scanner_; + }; + + sequence keyval_sep(const spec& s); + + // =========================================================================== + // Table key + + sequence std_table(const spec& s); + + sequence array_table(const spec& s); + + // =========================================================================== + // extension: null + + literal null_value(const spec&); + + } // namespace syntax + } // namespace detail +} // namespace toml +#endif // TOML11_SYNTAX_FWD_HPP + +#if !defined(TOML11_COMPILE_SOURCES) + #ifndef TOML11_SYNTAX_IMPL_HPP + #define TOML11_SYNTAX_IMPL_HPP + +namespace toml { + namespace detail { + namespace syntax { + + using char_type = location::char_type; + + // =========================================================================== + // UTF-8 + + // avoid redundant representation and out-of-unicode sequence + + TOML11_INLINE character_in_range utf8_1byte(const spec&) { + return character_in_range(0x00, 0x7F); + } + + TOML11_INLINE sequence utf8_2bytes(const spec&) { + return sequence(character_in_range(0xC2, 0xDF), + character_in_range(0x80, 0xBF)); + } + + TOML11_INLINE sequence utf8_3bytes(const spec&) { + return sequence( + /*1~2 bytes = */ either( + sequence(character(0xE0), character_in_range(0xA0, 0xBF)), + sequence(character_in_range(0xE1, 0xEC), character_in_range(0x80, 0xBF)), + sequence(character(0xED), character_in_range(0x80, 0x9F)), + sequence(character_in_range(0xEE, 0xEF), + character_in_range(0x80, 0xBF))), + /*3rd byte = */ character_in_range(0x80, 0xBF)); + } + + TOML11_INLINE sequence utf8_4bytes(const spec&) { + return sequence( + /*1~2 bytes = */ either( + sequence(character(0xF0), character_in_range(0x90, 0xBF)), + sequence(character_in_range(0xF1, 0xF3), character_in_range(0x80, 0xBF)), + sequence(character(0xF4), character_in_range(0x80, 0x8F))), + character_in_range(0x80, 0xBF), + character_in_range(0x80, 0xBF)); + } + + TOML11_INLINE non_ascii::non_ascii(const spec& s) noexcept + : scanner_(utf8_2bytes(s), utf8_3bytes(s), utf8_4bytes(s)) {} + + // =========================================================================== + // Whitespace + + TOML11_INLINE character_either wschar(const spec&) { + return character_either { char_type(' '), char_type('\t') }; + } + + TOML11_INLINE repeat_at_least ws(const spec& s) { + return repeat_at_least(0, wschar(s)); + } + + // =========================================================================== + // Newline + + TOML11_INLINE either newline(const spec&) { + return either(character(char_type('\n')), literal("\r\n")); + } + + // =========================================================================== + // Comments + + TOML11_INLINE either allowed_comment_char(const spec& s) { + if (s.v1_1_0_allow_control_characters_in_comments) { + return either(character_in_range(0x01, 0x09), + character_in_range(0x0E, 0x7F), + non_ascii(s)); + } else { + return either(character(0x09), + character_in_range(0x20, 0x7E), + non_ascii(s)); + } + } + + // XXX Note that it does not take newline + TOML11_INLINE sequence comment(const spec& s) { + return sequence(character(char_type('#')), + repeat_at_least(0, allowed_comment_char(s))); + } + + // =========================================================================== + // Boolean + + TOML11_INLINE either boolean(const spec&) { + return either(literal("true"), literal("false")); + } + + // =========================================================================== + // Integer + + TOML11_INLINE digit::digit(const spec&) noexcept + : scanner_(char_type('0'), char_type('9')) {} + + TOML11_INLINE alpha::alpha(const spec&) noexcept + : scanner_(character_in_range(char_type('a'), char_type('z')), + character_in_range(char_type('A'), char_type('Z'))) {} + + TOML11_INLINE hexdig::hexdig(const spec& s) noexcept + : scanner_(digit(s), + character_in_range(char_type('a'), char_type('f')), + character_in_range(char_type('A'), char_type('F'))) {} + + // non-digit-graph = ([a-zA-Z]|unicode mb char) + // graph = ([a-zA-Z0-9]|unicode mb char) + // suffix = _ non-digit-graph (graph | _graph) + TOML11_INLINE sequence num_suffix(const spec& s) { + const auto non_digit_graph = [&s]() { + return either(alpha(s), non_ascii(s)); + }; + const auto graph = [&s]() { + return either(alpha(s), digit(s), non_ascii(s)); + }; + + return sequence( + character(char_type('_')), + non_digit_graph(), + repeat_at_least( + 0, + either(sequence(character(char_type('_')), graph()), graph()))); + } + + TOML11_INLINE sequence dec_int(const spec& s) { + const auto digit19 = []() { + return character_in_range(char_type('1'), char_type('9')); + }; + return sequence( + maybe(character_either { char_type('-'), char_type('+') }), + either(sequence(digit19(), + repeat_at_least( + 1, + either(digit(s), + sequence(character(char_type('_')), digit(s))))), + digit(s))); + } + + TOML11_INLINE sequence hex_int(const spec& s) { + return sequence( + literal("0x"), + hexdig(s), + repeat_at_least( + 0, + either(hexdig(s), sequence(character(char_type('_')), hexdig(s))))); + } + + TOML11_INLINE sequence oct_int(const spec&) { + const auto digit07 = []() { + return character_in_range(char_type('0'), char_type('7')); + }; + return sequence( + literal("0o"), + digit07(), + repeat_at_least( + 0, + either(digit07(), sequence(character(char_type('_')), digit07())))); + } + + TOML11_INLINE sequence bin_int(const spec&) { + const auto digit01 = []() { + return character_either { char_type('0'), char_type('1') }; + }; + return sequence( + literal("0b"), + digit01(), + repeat_at_least( + 0, + either(digit01(), sequence(character(char_type('_')), digit01())))); + } + + TOML11_INLINE either integer(const spec& s) { + return either(hex_int(s), oct_int(s), bin_int(s), dec_int(s)); + } + + // =========================================================================== + // Floating + + TOML11_INLINE sequence zero_prefixable_int(const spec& s) { + return sequence( + digit(s), + repeat_at_least(0, either(digit(s), sequence(character('_'), digit(s))))); + } + + TOML11_INLINE sequence fractional_part(const spec& s) { + return sequence(character('.'), zero_prefixable_int(s)); + } + + TOML11_INLINE sequence exponent_part(const spec& s) { + return sequence(character_either { char_type('e'), char_type('E') }, + maybe(character_either { char_type('+'), char_type('-') }), + zero_prefixable_int(s)); + } + + TOML11_INLINE sequence hex_floating(const spec& s) { + // C99 hexfloat (%a) + // [+-]? 0x ( [0-9a-fA-F]*\.[0-9a-fA-F]+ | [0-9a-fA-F]+\.? ) [pP] [+-]? [0-9]+ + + // - 0x(int).(frac)p[+-](int) + // - 0x(int).p[+-](int) + // - 0x.(frac)p[+-](int) + // - 0x(int)p[+-](int) + + return sequence( + maybe(character_either { char_type('+'), char_type('-') }), + character('0'), + character_either { char_type('x'), char_type('X') }, + either(sequence(repeat_at_least(0, hexdig(s)), + character('.'), + repeat_at_least(1, hexdig(s))), + sequence(repeat_at_least(1, hexdig(s)), maybe(character('.')))), + character_either { char_type('p'), char_type('P') }, + maybe(character_either { char_type('+'), char_type('-') }), + repeat_at_least(1, character_in_range('0', '9'))); + } + + TOML11_INLINE either floating(const spec& s) { + return either( + sequence(dec_int(s), + either(exponent_part(s), + sequence(fractional_part(s), maybe(exponent_part(s))))), + sequence(maybe(character_either { char_type('-'), char_type('+') }), + either(literal("inf"), literal("nan")))); + } + + // =========================================================================== + // Datetime + + TOML11_INLINE sequence local_date(const spec& s) { + return sequence(repeat_exact(4, digit(s)), + character('-'), + repeat_exact(2, digit(s)), + character('-'), + repeat_exact(2, digit(s))); + } + + TOML11_INLINE sequence local_time(const spec& s) { + auto time = sequence(repeat_exact(2, digit(s)), + character(':'), + repeat_exact(2, digit(s))); + + if (s.v1_1_0_make_seconds_optional) { + time.push_back(maybe(sequence( + character(':'), + repeat_exact(2, digit(s)), + maybe(sequence(character('.'), repeat_at_least(1, digit(s))))))); + } else { + time.push_back(character(':')); + time.push_back(repeat_exact(2, digit(s))); + time.push_back( + maybe(sequence(character('.'), repeat_at_least(1, digit(s))))); + } + + return time; + } + + TOML11_INLINE either time_offset(const spec& s) { + return either(character_either { 'Z', 'z' }, + sequence(character_either { '+', '-' }, + repeat_exact(2, digit(s)), + character(':'), + repeat_exact(2, digit(s)))); + } + + TOML11_INLINE sequence full_time(const spec& s) { + return sequence(local_time(s), time_offset(s)); + } + + TOML11_INLINE character_either time_delim(const spec&) { + return character_either { 'T', 't', ' ' }; + } + + TOML11_INLINE sequence local_datetime(const spec& s) { + return sequence(local_date(s), time_delim(s), local_time(s)); + } + + TOML11_INLINE sequence offset_datetime(const spec& s) { + return sequence(local_date(s), time_delim(s), full_time(s)); + } + + // =========================================================================== + // String + + TOML11_INLINE sequence escaped(const spec& s) { + character_either escape_char { '\"', '\\', 'b', 'f', 'n', 'r', 't' }; + if (s.v1_1_0_add_escape_sequence_e) { + escape_char.push_back(char_type('e')); + } + + either escape_seq(std::move(escape_char), + sequence(character('u'), repeat_exact(4, hexdig(s))), + sequence(character('U'), repeat_exact(8, hexdig(s)))); + + if (s.v1_1_0_add_escape_sequence_x) { + escape_seq.push_back( + sequence(character('x'), repeat_exact(2, hexdig(s)))); + } + + return sequence(character('\\'), std::move(escape_seq)); + } + + TOML11_INLINE either basic_char(const spec& s) { + const auto basic_unescaped = [&s]() { + return either(wschar(s), + character(0x21), // 22 is " + character_in_range(0x23, 0x5B), // 5C is backslash + character_in_range(0x5D, 0x7E), // 7F is DEL + non_ascii(s)); + }; + return either(basic_unescaped(), escaped(s)); + } + + TOML11_INLINE sequence basic_string(const spec& s) { + return sequence(character('"'), + repeat_at_least(0, basic_char(s)), + character('"')); + } + + // --------------------------------------------------------------------------- + // multiline string + + TOML11_INLINE sequence escaped_newline(const spec& s) { + return sequence(character('\\'), + ws(s), + newline(s), + repeat_at_least(0, either(wschar(s), newline(s)))); + } + + TOML11_INLINE sequence ml_basic_string(const spec& s) { + const auto mlb_content = [&s]() { + return either(basic_char(s), newline(s), escaped_newline(s)); + }; + const auto mlb_quotes = []() { + return either(literal("\"\""), character('\"')); + }; + + return sequence( + literal("\"\"\""), + maybe(newline(s)), + repeat_at_least(0, mlb_content()), + repeat_at_least(0, + sequence(mlb_quotes(), repeat_at_least(1, mlb_content()))), + // XXX """ and mlb_quotes are intentionally reordered to avoid + // unexpected match of mlb_quotes + literal("\"\"\""), + maybe(mlb_quotes())); + } + + // --------------------------------------------------------------------------- + // literal string + + TOML11_INLINE either literal_char(const spec& s) { + return either(character(0x09), + character_in_range(0x20, 0x26), + character_in_range(0x28, 0x7E), + non_ascii(s)); + } + + TOML11_INLINE sequence literal_string(const spec& s) { + return sequence(character('\''), + repeat_at_least(0, literal_char(s)), + character('\'')); + } + + TOML11_INLINE sequence ml_literal_string(const spec& s) { + const auto mll_quotes = []() { + return either(literal("''"), character('\'')); + }; + const auto mll_content = [&s]() { + return either(literal_char(s), newline(s)); + }; + + return sequence( + literal("'''"), + maybe(newline(s)), + repeat_at_least(0, mll_content()), + repeat_at_least(0, + sequence(mll_quotes(), repeat_at_least(1, mll_content()))), + literal("'''"), + maybe(mll_quotes()) + // XXX ''' and mll_quotes are intentionally reordered to avoid + // unexpected match of mll_quotes + ); + } + + TOML11_INLINE either string(const spec& s) { + return either(ml_basic_string(s), + ml_literal_string(s), + basic_string(s), + literal_string(s)); + } + + // =========================================================================== + // Keys + + // to keep `expected_chars` simple + TOML11_INLINE non_ascii_key_char::non_ascii_key_char(const spec& s) noexcept { + assert(s.v1_1_0_allow_non_english_in_bare_keys); + (void)s; // for NDEBUG + } + + TOML11_INLINE std::uint32_t non_ascii_key_char::read_utf8(location& loc) const { + // U+0000 ... U+0079 ; 0xxx_xxxx + // U+0080 ... U+07FF ; 110y_yyyx 10xx_xxxx; + // U+0800 ... U+FFFF ; 1110_yyyy 10yx_xxxx 10xx_xxxx + // U+010000 ... U+10FFFF; 1111_0yyy 10yy_xxxx 10xx_xxxx 10xx_xxxx + + const unsigned char b1 = loc.current(); + loc.advance(1); + if (b1 < 0x80) { + return static_cast(b1); + } else if ((b1 >> 5) == 6) // 0b110 == 6 + { + const auto b2 = loc.current(); + loc.advance(1); + + const std::uint32_t c1 = b1 & ((1 << 5) - 1); + const std::uint32_t c2 = b2 & ((1 << 6) - 1); + const std::uint32_t codep = (c1 << 6) + c2; + + if (codep < 0x80) { + return 0xFFFFFFFF; + } + return codep; + } else if ((b1 >> 4) == 14) // 0b1110 == 14 + { + const auto b2 = loc.current(); + loc.advance(1); + if (loc.eof()) { + return 0xFFFFFFFF; + } + const auto b3 = loc.current(); + loc.advance(1); + + const std::uint32_t c1 = b1 & ((1 << 4) - 1); + const std::uint32_t c2 = b2 & ((1 << 6) - 1); + const std::uint32_t c3 = b3 & ((1 << 6) - 1); + + const std::uint32_t codep = (c1 << 12) + (c2 << 6) + c3; + if (codep < 0x800) { + return 0xFFFFFFFF; + } + return codep; + } else if ((b1 >> 3) == 30) // 0b11110 == 30 + { + const auto b2 = loc.current(); + loc.advance(1); + if (loc.eof()) { + return 0xFFFFFFFF; + } + const auto b3 = loc.current(); + loc.advance(1); + if (loc.eof()) { + return 0xFFFFFFFF; + } + const auto b4 = loc.current(); + loc.advance(1); + + const std::uint32_t c1 = b1 & ((1 << 3) - 1); + const std::uint32_t c2 = b2 & ((1 << 6) - 1); + const std::uint32_t c3 = b3 & ((1 << 6) - 1); + const std::uint32_t c4 = b4 & ((1 << 6) - 1); + const std::uint32_t codep = (c1 << 18) + (c2 << 12) + (c3 << 6) + c4; + + if (codep < 0x10000) { + return 0xFFFFFFFF; + } + return codep; + } else // not a Unicode codepoint in UTF-8 + { + return 0xFFFFFFFF; + } + } + + TOML11_INLINE region non_ascii_key_char::scan(location& loc) const { + if (loc.eof()) { + return region {}; + } + + const auto first = loc; + + const auto cp = read_utf8(loc); + + if (cp == 0xFFFFFFFF) { + return region {}; + } + + // ALPHA / DIGIT / %x2D / %x5F ; a-z A-Z 0-9 - _ + // / %xB2 / %xB3 / %xB9 / %xBC-BE ; superscript digits, fractions + // / %xC0-D6 / %xD8-F6 / %xF8-37D ; non-symbol chars in Latin block + // / %x37F-1FFF ; exclude GREEK QUESTION MARK, which + // is basically a semi-colon / %x200C-200D / %x203F-2040 ; from + // General Punctuation Block, include the two tie symbols and ZWNJ, ZWJ + // / %x2070-218F / %x2460-24FF ; include super-/subscripts, + // letterlike/numberlike forms, enclosed alphanumerics / %x2C00-2FEF / + // %x3001-D7FF ; skip arrows, math, box drawing etc, skip 2FF0-3000 + // ideographic up/down markers and spaces / %xF900-FDCF / %xFDF0-FFFD ; + // skip D800-DFFF surrogate block, E000-F8FF Private Use area, FDD0-FDEF + // intended for process-internal use (unicode) / %x10000-EFFFF ; all + // chars outside BMP range, excluding Private Use planes (F0000-10FFFF) + + if (cp == 0xB2 || cp == 0xB3 || cp == 0xB9 || + (0xBC <= cp && cp <= 0xBE) || (0xC0 <= cp && cp <= 0xD6) || + (0xD8 <= cp && cp <= 0xF6) || (0xF8 <= cp && cp <= 0x37D) || + (0x37F <= cp && cp <= 0x1FFF) || (0x200C <= cp && cp <= 0x200D) || + (0x203F <= cp && cp <= 0x2040) || (0x2070 <= cp && cp <= 0x218F) || + (0x2460 <= cp && cp <= 0x24FF) || (0x2C00 <= cp && cp <= 0x2FEF) || + (0x3001 <= cp && cp <= 0xD7FF) || (0xF900 <= cp && cp <= 0xFDCF) || + (0xFDF0 <= cp && cp <= 0xFFFD) || (0x10000 <= cp && cp <= 0xEFFFF)) { + return region(first, loc); + } + loc = first; + return region {}; + } + + TOML11_INLINE repeat_at_least unquoted_key(const spec& s) { + auto keychar = either(alpha(s), + digit(s), + character { 0x2D }, + character { 0x5F }); + + if (s.v1_1_0_allow_non_english_in_bare_keys) { + keychar.push_back(non_ascii_key_char(s)); + } + + return repeat_at_least(1, std::move(keychar)); + } + + TOML11_INLINE either quoted_key(const spec& s) { + return either(basic_string(s), literal_string(s)); + } + + TOML11_INLINE either simple_key(const spec& s) { + return either(unquoted_key(s), quoted_key(s)); + } + + TOML11_INLINE sequence dot_sep(const spec& s) { + return sequence(ws(s), character('.'), ws(s)); + } + + TOML11_INLINE sequence dotted_key(const spec& s) { + return sequence(simple_key(s), + repeat_at_least(1, sequence(dot_sep(s), simple_key(s)))); + } + + TOML11_INLINE key::key(const spec& s) noexcept + : scanner_(dotted_key(s), simple_key(s)) {} + + TOML11_INLINE sequence keyval_sep(const spec& s) { + return sequence(ws(s), character('='), ws(s)); + } + + // =========================================================================== + // Table key + + TOML11_INLINE sequence std_table(const spec& s) { + return sequence(character('['), ws(s), key(s), ws(s), character(']')); + } + + TOML11_INLINE sequence array_table(const spec& s) { + return sequence(literal("[["), ws(s), key(s), ws(s), literal("]]")); + } + + // =========================================================================== + // extension: null + + TOML11_INLINE literal null_value(const spec&) { + return literal("null"); + } + + } // namespace syntax + } // namespace detail +} // namespace toml + #endif // TOML11_SYNTAX_IMPL_HPP +#endif + +#endif // TOML11_SYNTAX_HPP +#ifndef TOML11_SKIP_HPP +#define TOML11_SKIP_HPP + +#include + +namespace toml { + namespace detail { + + template + bool skip_whitespace(location& loc, const context& ctx) { + return syntax::ws(ctx.toml_spec()).scan(loc).is_ok(); + } + + template + bool skip_empty_lines(location& loc, const context& ctx) { + return repeat_at_least(1, + sequence(syntax::ws(ctx.toml_spec()), + syntax::newline(ctx.toml_spec()))) + .scan(loc) + .is_ok(); + } + + // For error recovery. + // + // In case if a comment line contains an invalid character, we need to skip + // it to advance parsing. + template + void skip_comment_block(location& loc, const context& ctx) { + while (!loc.eof()) { + skip_whitespace(loc, ctx); + if (loc.current() == '#') { + while (!loc.eof()) { + // both CRLF and LF ends with LF. + if (loc.current() == '\n') { + loc.advance(); + break; + } + } + } else if (syntax::newline(ctx.toml_spec()).scan(loc).is_ok()) { + ; // an empty line. skip this also + } else { + // the next token is neither a comment nor empty line. + return; + } + } + return; + } + + template + void skip_empty_or_comment_lines(location& loc, const context& ctx) { + const auto& spec = ctx.toml_spec(); + repeat_at_least(0, + sequence(syntax::ws(spec), + maybe(syntax::comment(spec)), + syntax::newline(spec))) + .scan(loc); + return; + } + + // For error recovery. + // + // Sometimes we need to skip a value and find a delimiter, like `,`, `]`, or `}`. + // To find delimiter, we need to skip delimiters in a string. + // Since we are skipping invalid value while error recovery, we don't need + // to check the syntax. Here we just skip string-like region until closing quote + // is found. + template + void skip_string_like(location& loc, const context&) { + // if """ is found, skip until the closing """ is found. + if (literal("\"\"\"").scan(loc).is_ok()) { + while (!loc.eof()) { + if (literal("\"\"\"").scan(loc).is_ok()) { + return; + } + loc.advance(); + } + } else if (literal("'''").scan(loc).is_ok()) { + while (!loc.eof()) { + if (literal("'''").scan(loc).is_ok()) { + return; + } + loc.advance(); + } + } + // if " is found, skip until the closing " or newline is found. + else if (loc.current() == '"') { + while (!loc.eof()) { + loc.advance(); + if (loc.current() == '"' || loc.current() == '\n') { + loc.advance(); + return; + } + } + } else if (loc.current() == '\'') { + while (!loc.eof()) { + loc.advance(); + if (loc.current() == '\'' || loc.current() == '\n') { + loc.advance(); + return; + } + } + } + return; + } + + template + void skip_value(location& loc, const context& ctx); + template + void skip_array_like(location& loc, const context& ctx); + template + void skip_inline_table_like(location& loc, const context& ctx); + template + void skip_key_value_pair(location& loc, const context& ctx); + + template + result guess_value_type(const location& loc, + const context& ctx); + + template + void skip_array_like(location& loc, const context& ctx) { + const auto& spec = ctx.toml_spec(); + assert(loc.current() == '['); + loc.advance(); + + while (!loc.eof()) { + if (loc.current() == '\"' || loc.current() == '\'') { + skip_string_like(loc, ctx); + } else if (loc.current() == '#') { + skip_comment_block(loc, ctx); + } else if (loc.current() == '{') { + skip_inline_table_like(loc, ctx); + } else if (loc.current() == '[') { + const auto checkpoint = loc; + if (syntax::std_table(spec).scan(loc).is_ok() || + syntax::array_table(spec).scan(loc).is_ok()) { + loc = checkpoint; + break; + } + // if it is not a table-definition, then it is an array. + skip_array_like(loc, ctx); + } else if (loc.current() == '=') { + // key-value pair cannot be inside the array. + // guessing the error is "missing closing bracket `]`". + // find the previous key just before `=`. + while (loc.get_location() != 0) { + loc.retrace(); + if (loc.current() == '\n') { + loc.advance(); + break; + } + } + break; + } else if (loc.current() == ']') { + break; // found closing bracket + } else { + loc.advance(); + } + } + return; + } + + template + void skip_inline_table_like(location& loc, const context& ctx) { + assert(loc.current() == '{'); + loc.advance(); + + const auto& spec = ctx.toml_spec(); + + while (!loc.eof()) { + if (loc.current() == '\n' && !spec.v1_1_0_allow_newlines_in_inline_tables) { + break; // missing closing `}`. + } else if (loc.current() == '\"' || loc.current() == '\'') { + skip_string_like(loc, ctx); + } else if (loc.current() == '#') { + skip_comment_block(loc, ctx); + if (!spec.v1_1_0_allow_newlines_in_inline_tables) { + // comment must end with newline. + break; // missing closing `}`. + } + } else if (loc.current() == '[') { + const auto checkpoint = loc; + if (syntax::std_table(spec).scan(loc).is_ok() || + syntax::array_table(spec).scan(loc).is_ok()) { + loc = checkpoint; + break; // missing closing `}`. + } + // if it is not a table-definition, then it is an array. + skip_array_like(loc, ctx); + } else if (loc.current() == '{') { + skip_inline_table_like(loc, ctx); + } else if (loc.current() == '}') { + // closing brace found. guessing the error is inside the table. + break; + } else { + // skip otherwise. + loc.advance(); + } + } + return; + } + + template + void skip_value(location& loc, const context& ctx) { + value_t ty = guess_value_type(loc, ctx).unwrap_or(value_t::empty); + if (ty == value_t::string) { + skip_string_like(loc, ctx); + } else if (ty == value_t::array) { + skip_array_like(loc, ctx); + } else if (ty == value_t::table) { + // In case of multiline tables, it may skip key-value pair but not the + // whole table. + skip_inline_table_like(loc, ctx); + } else // others are an "in-line" values. skip until the next line + { + while (!loc.eof()) { + if (loc.current() == '\n') { + break; + } else if (loc.current() == ',' || loc.current() == ']' || + loc.current() == '}') { + break; + } + loc.advance(); + } + } + return; + } + + template + void skip_key_value_pair(location& loc, const context& ctx) { + while (!loc.eof()) { + if (loc.current() == '=') { + skip_whitespace(loc, ctx); + skip_value(loc, ctx); + return; + } else if (loc.current() == '\n') { + // newline is found before finding `=`. assuming "missing `=`". + return; + } + loc.advance(); + } + return; + } + + template + void skip_until_next_table(location& loc, const context& ctx) { + const auto& spec = ctx.toml_spec(); + while (!loc.eof()) { + if (loc.current() == '\n') { + loc.advance(); + const auto line_begin = loc; + + skip_whitespace(loc, ctx); + if (syntax::std_table(spec).scan(loc).is_ok()) { + loc = line_begin; + return; + } + if (syntax::array_table(spec).scan(loc).is_ok()) { + loc = line_begin; + return; + } + } + loc.advance(); + } + } + + } // namespace detail +} // namespace toml + +#if defined(TOML11_COMPILE_SOURCES) +namespace toml { + struct type_config; + struct ordered_type_config; + + namespace detail { + extern template bool skip_whitespace(location& loc, + const context&); + extern template bool skip_empty_lines(location& loc, + const context&); + extern template void skip_comment_block( + location& loc, + const context&); + extern template void skip_empty_or_comment_lines( + location& loc, + const context&); + extern template void skip_string_like(location& loc, + const context&); + extern template void skip_array_like(location& loc, + const context&); + extern template void skip_inline_table_like( + location& loc, + const context&); + extern template void skip_value(location& loc, + const context&); + extern template void skip_key_value_pair( + location& loc, + const context&); + extern template void skip_until_next_table( + location& loc, + const context&); + + extern template bool skip_whitespace( + location& loc, + const context&); + extern template bool skip_empty_lines( + location& loc, + const context&); + extern template void skip_comment_block( + location& loc, + const context&); + extern template void skip_empty_or_comment_lines( + location& loc, + const context&); + extern template void skip_string_like( + location& loc, + const context&); + extern template void skip_array_like( + location& loc, + const context&); + extern template void skip_inline_table_like( + location& loc, + const context&); + extern template void skip_value( + location& loc, + const context&); + extern template void skip_key_value_pair( + location& loc, + const context&); + extern template void skip_until_next_table( + location& loc, + const context&); + + } // namespace detail +} // namespace toml +#endif // TOML11_COMPILE_SOURCES + +#endif // TOML11_SKIP_HPP +#ifndef TOML11_PARSER_HPP +#define TOML11_PARSER_HPP + +#include +#include +#include +#include + +#if defined(TOML11_HAS_FILESYSTEM) && TOML11_HAS_FILESYSTEM + #include +#endif + +namespace toml { + + struct syntax_error final : public ::toml::exception { + public: + syntax_error(std::string what_arg, std::vector err) + : what_(std::move(what_arg)) + , err_(std::move(err)) {} + + ~syntax_error() noexcept override = default; + + const char* what() const noexcept override { + return what_.c_str(); + } + + const std::vector& errors() const noexcept { + return err_; + } + + private: + std::string what_; + std::vector err_; + }; + + struct file_io_error final : public ::toml::exception { + public: + file_io_error(const std::string& msg, const std::string& fname) + : errno_(cxx::make_nullopt()) + , what_(msg + " \"" + fname + "\"") {} + + file_io_error(int errnum, const std::string& msg, const std::string& fname) + : errno_(errnum) + , what_(msg + " \"" + fname + "\": errno=" + std::to_string(errnum)) {} + + ~file_io_error() noexcept override = default; + + const char* what() const noexcept override { + return what_.c_str(); + } + + bool has_errno() const noexcept { + return errno_.has_value(); + } + + int get_errno() const noexcept { + return errno_.value_or(0); + } + + private: + cxx::optional errno_; + std::string what_; + }; + + namespace detail { + + /* ============================================================================ + * __ ___ _ __ _ __ ___ _ _ + * / _/ _ \ ' \| ' \/ _ \ ' \ + * \__\___/_|_|_|_|_|_\___/_||_| + */ + + template + error_info make_syntax_error(std::string title, + const S& scanner, + location loc, + std::string suffix = "") { + auto msg = std::string("expected ") + scanner.expected_chars(loc); + auto src = source_location(region(loc)); + return make_error_info(std::move(title), + std::move(src), + std::move(msg), + std::move(suffix)); + } + + /* ============================================================================ + * _ + * __ ___ _ __ _ __ ___ _ _| |_ + * / _/ _ \ ' \| ' \/ -_) ' \ _| + * \__\___/_|_|_|_|_|_\___|_||_\__| + */ + + template + result, error_info> parse_comment_line( + location& loc, + context& ctx) { + const auto& spec = ctx.toml_spec(); + const auto first = loc; + + skip_whitespace(loc, ctx); + + const auto com_reg = syntax::comment(spec).scan(loc); + if (com_reg.is_ok()) { + // once comment started, newline must follow (or reach EOF). + if (!loc.eof() && !syntax::newline(spec).scan(loc).is_ok()) { + while (!loc.eof()) // skip until newline to continue parsing + { + loc.advance(); + if (loc.current() == '\n') { /*skip LF*/ + loc.advance(); + break; + } + } + return err(make_error_info("toml::parse_comment_line: " + "newline (LF / CRLF) or EOF is expected", + source_location(region(loc)), + "but got this", + "Hint: most of the control characters are " + "not allowed in comments")); + } + return ok(cxx::optional(com_reg.as_string())); + } else { + loc = first; // rollback whitespace to parse indent + return ok(cxx::optional(cxx::make_nullopt())); + } + } + + /* ============================================================================ + * ___ _ + * | _ ) ___ ___| |___ __ _ _ _ + * | _ \/ _ \/ _ \ / -_) _` | ' \ + * |___/\___/\___/_\___\__,_|_||_| + */ + + template + result, error_info> parse_boolean(location& loc, + const context& ctx) { + const auto& spec = ctx.toml_spec(); + + // ---------------------------------------------------------------------- + // check syntax + auto reg = syntax::boolean(spec).scan(loc); + if (!reg.is_ok()) { + return err(make_syntax_error( + "toml::parse_boolean: " + "invalid boolean: boolean must be `true` or `false`, in lowercase. " + "string must be surrounded by `\"`", + syntax::boolean(spec), + loc)); + } + + // ---------------------------------------------------------------------- + // it matches. gen value + const auto str = reg.as_string(); + const auto val = [&str]() { + if (str == "true") { + return true; + } else { + assert(str == "false"); + return false; + } + }(); + + // ---------------------------------------------------------------------- + // no format info for boolean + boolean_format_info fmt; + + return ok(basic_value(val, std::move(fmt), {}, std::move(reg))); + } + + /* ============================================================================ + * ___ _ + * |_ _|_ _| |_ ___ __ _ ___ _ _ + * | || ' \ _/ -_) _` / -_) '_| + * |___|_||_\__\___\__, \___|_| + * |___/ + */ + + template + result, error_info> parse_bin_integer(location& loc, + const context& ctx) { + const auto first = loc; + const auto& spec = ctx.toml_spec(); + auto reg = syntax::bin_int(spec).scan(loc); + if (!reg.is_ok()) { + return err(make_syntax_error( + "toml::parse_bin_integer: " + "invalid integer: bin_int must be like: 0b0101, 0b1111_0000", + syntax::bin_int(spec), + loc)); + } + + auto str = reg.as_string(); + + integer_format_info fmt; + fmt.fmt = integer_format::bin; + fmt.width = str.size() - 2 - + static_cast(std::count(str.begin(), str.end(), '_')); + + const auto first_underscore = std::find(str.rbegin(), str.rend(), '_'); + if (first_underscore != str.rend()) { + fmt.spacer = static_cast( + std::distance(str.rbegin(), first_underscore)); + } + + // skip prefix `0b` and zeros and underscores at the MSB + str.erase(str.begin(), std::find(std::next(str.begin(), 2), str.end(), '1')); + + // remove all `_` before calling TC::parse_int + str.erase(std::remove(str.begin(), str.end(), '_'), str.end()); + + // 0b0000_0000 becomes empty. + if (str.empty()) { + str = "0"; + } + + const auto val = TC::parse_int(str, source_location(region(loc)), 2); + if (val.is_ok()) { + return ok(basic_value(val.as_ok(), std::move(fmt), {}, std::move(reg))); + } else { + loc = first; + return err(val.as_err()); + } + } + + // ---------------------------------------------------------------------------- + + template + result, error_info> parse_oct_integer(location& loc, + const context& ctx) { + const auto first = loc; + const auto& spec = ctx.toml_spec(); + auto reg = syntax::oct_int(spec).scan(loc); + if (!reg.is_ok()) { + return err(make_syntax_error( + "toml::parse_oct_integer: " + "invalid integer: oct_int must be like: 0o775, 0o04_44", + syntax::oct_int(spec), + loc)); + } + + auto str = reg.as_string(); + + integer_format_info fmt; + fmt.fmt = integer_format::oct; + fmt.width = str.size() - 2 - + static_cast(std::count(str.begin(), str.end(), '_')); + + const auto first_underscore = std::find(str.rbegin(), str.rend(), '_'); + if (first_underscore != str.rend()) { + fmt.spacer = static_cast( + std::distance(str.rbegin(), first_underscore)); + } + + // skip prefix `0o` and zeros and underscores at the MSB + str.erase(str.begin(), + std::find_if(std::next(str.begin(), 2), str.end(), [](const char c) { + return c != '0' && c != '_'; + })); + + // remove all `_` before calling TC::parse_int + str.erase(std::remove(str.begin(), str.end(), '_'), str.end()); + + // 0o0000_0000 becomes empty. + if (str.empty()) { + str = "0"; + } + + const auto val = TC::parse_int(str, source_location(region(loc)), 8); + if (val.is_ok()) { + return ok(basic_value(val.as_ok(), std::move(fmt), {}, std::move(reg))); + } else { + loc = first; + return err(val.as_err()); + } + } + + template + result, error_info> parse_hex_integer(location& loc, + const context& ctx) { + const auto first = loc; + const auto& spec = ctx.toml_spec(); + auto reg = syntax::hex_int(spec).scan(loc); + if (!reg.is_ok()) { + return err(make_syntax_error( + "toml::parse_hex_integer: " + "invalid integer: hex_int must be like: 0xC0FFEE, 0xdead_beef", + syntax::hex_int(spec), + loc)); + } + + auto str = reg.as_string(); + + integer_format_info fmt; + fmt.fmt = integer_format::hex; + fmt.width = str.size() - 2 - + static_cast(std::count(str.begin(), str.end(), '_')); + + const auto first_underscore = std::find(str.rbegin(), str.rend(), '_'); + if (first_underscore != str.rend()) { + fmt.spacer = static_cast( + std::distance(str.rbegin(), first_underscore)); + } + + // skip prefix `0x` and zeros and underscores at the MSB + str.erase(str.begin(), + std::find_if(std::next(str.begin(), 2), str.end(), [](const char c) { + return c != '0' && c != '_'; + })); + + // remove all `_` before calling TC::parse_int + str.erase(std::remove(str.begin(), str.end(), '_'), str.end()); + + // 0x0000_0000 becomes empty. + if (str.empty()) { + str = "0"; + } + + // prefix zero and _ is removed. check if it uses upper/lower case. + // if both upper and lower case letters are found, set upper=true. + const auto lower_not_found = std::find_if(str.begin(), str.end(), [](const char c) { + return std::islower(static_cast(c)) != 0; + }) == str.end(); + const auto upper_found = std::find_if(str.begin(), str.end(), [](const char c) { + return std::isupper(static_cast(c)) != 0; + }) != str.end(); + fmt.uppercase = lower_not_found || upper_found; + + const auto val = TC::parse_int(str, source_location(region(loc)), 16); + if (val.is_ok()) { + return ok(basic_value(val.as_ok(), std::move(fmt), {}, std::move(reg))); + } else { + loc = first; + return err(val.as_err()); + } + } + + template + result, error_info> parse_dec_integer(location& loc, + const context& ctx) { + const auto first = loc; + const auto& spec = ctx.toml_spec(); + + // ---------------------------------------------------------------------- + // check syntax + auto reg = syntax::dec_int(spec).scan(loc); + if (!reg.is_ok()) { + return err(make_syntax_error( + "toml::parse_dec_integer: " + "invalid integer: dec_int must be like: 42, 123_456_789", + syntax::dec_int(spec), + loc)); + } + + // ---------------------------------------------------------------------- + // it matches. gen value + auto str = reg.as_string(); + + integer_format_info fmt; + fmt.fmt = integer_format::dec; + fmt.width = str.size() - static_cast( + std::count(str.begin(), str.end(), '_')); + + const auto first_underscore = std::find(str.rbegin(), str.rend(), '_'); + if (first_underscore != str.rend()) { + fmt.spacer = static_cast( + std::distance(str.rbegin(), first_underscore)); + } + + // remove all `_` before calling TC::parse_int + str.erase(std::remove(str.begin(), str.end(), '_'), str.end()); + + auto src = source_location(region(loc)); + const auto val = TC::parse_int(str, src, 10); + if (val.is_err()) { + loc = first; + return err(val.as_err()); + } + + // ---------------------------------------------------------------------- + // parse suffix (extension) + + if (spec.ext_num_suffix && loc.current() == '_') { + const auto sfx_reg = syntax::num_suffix(spec).scan(loc); + if (!sfx_reg.is_ok()) { + loc = first; + return err(make_error_info( + "toml::parse_dec_integer: " + "invalid suffix: should be `_ non-digit-graph (graph | _graph)`", + source_location(region(loc)), + "here")); + } + auto sfx = sfx_reg.as_string(); + assert(!sfx.empty() && sfx.front() == '_'); + sfx.erase(sfx.begin()); // remove the first `_` + + fmt.suffix = sfx; + } + + return ok(basic_value(val.as_ok(), std::move(fmt), {}, std::move(reg))); + } + + template + result, error_info> parse_integer(location& loc, + const context& ctx) { + const auto first = loc; + + if (!loc.eof() && (loc.current() == '+' || loc.current() == '-')) { + // skip +/- to diagnose +0xDEADBEEF or -0b0011 (invalid). + // without this, +0xDEAD_BEEF will be parsed as a decimal int and + // unexpected "xDEAD_BEEF" will appear after integer "+0". + loc.advance(); + } + + if (!loc.eof() && loc.current() == '0') { + loc.advance(); + if (loc.eof()) { + // `[+-]?0`. parse as an decimal integer. + loc = first; + return parse_dec_integer(loc, ctx); + } + + const auto prefix = loc.current(); + auto prefix_src = source_location(region(loc)); + + loc = first; + + if (prefix == 'b') { + return parse_bin_integer(loc, ctx); + } + if (prefix == 'o') { + return parse_oct_integer(loc, ctx); + } + if (prefix == 'x') { + return parse_hex_integer(loc, ctx); + } + + if (std::isdigit(prefix)) { + auto src = source_location(region(loc)); + return err( + make_error_info("toml::parse_integer: " + "leading zero in an decimal integer is not allowed", + std::move(src), + "leading zero")); + } + } + + loc = first; + return parse_dec_integer(loc, ctx); + } + + /* ============================================================================ + * ___ _ _ _ + * | __| |___ __ _| |_(_)_ _ __ _ + * | _|| / _ \/ _` | _| | ' \/ _` | + * |_| |_\___/\__,_|\__|_|_||_\__, | + * |___/ + */ + + template + result, error_info> parse_floating(location& loc, + const context& ctx) { + using floating_type = typename basic_value::floating_type; + + const auto first = loc; + const auto& spec = ctx.toml_spec(); + + // ---------------------------------------------------------------------- + // check syntax + bool is_hex = false; + std::string str; + region reg; + if (spec.ext_hex_float && + sequence(character('0'), character('x')).scan(loc).is_ok()) { + loc = first; + is_hex = true; + + reg = syntax::hex_floating(spec).scan(loc); + if (!reg.is_ok()) { + return err(make_syntax_error( + "toml::parse_floating: " + "invalid hex floating: float must be like: 0xABCp-3f", + syntax::floating(spec), + loc)); + } + str = reg.as_string(); + } else { + reg = syntax::floating(spec).scan(loc); + if (!reg.is_ok()) { + return err(make_syntax_error( + "toml::parse_floating: " + "invalid floating: float must be like: -3.14159_26535, 6.022e+23, " + "inf, or nan (lowercase).", + syntax::floating(spec), + loc)); + } + str = reg.as_string(); + } + + // ---------------------------------------------------------------------- + // it matches. gen value + + floating_format_info fmt; + + if (is_hex) { + fmt.fmt = floating_format::hex; + } else { + // since we already checked that the string conforms the TOML standard. + if (std::find(str.begin(), str.end(), 'e') != str.end() || + std::find(str.begin(), str.end(), 'E') != str.end()) { + fmt.fmt = floating_format::scientific; // use exponent part + } else { + fmt.fmt = floating_format::fixed; // do not use exponent part + } + } + + str.erase(std::remove(str.begin(), str.end(), '_'), str.end()); + + floating_type val { 0 }; + + if (str == "inf" || str == "+inf") { + TOML11_CONSTEXPR_IF(std::numeric_limits::has_infinity) { + val = std::numeric_limits::infinity(); + } + else { + return err(make_error_info( + "toml::parse_floating: inf value found" + " but the current environment does not support inf. Please" + " make sure that the floating-point implementation conforms" + " IEEE 754/ISO 60559 international standard.", + source_location(region(loc)), + "floating_type: inf is not supported")); + } + } else if (str == "-inf") { + TOML11_CONSTEXPR_IF(std::numeric_limits::has_infinity) { + val = -std::numeric_limits::infinity(); + } + else { + return err(make_error_info( + "toml::parse_floating: inf value found" + " but the current environment does not support inf. Please" + " make sure that the floating-point implementation conforms" + " IEEE 754/ISO 60559 international standard.", + source_location(region(loc)), + "floating_type: inf is not supported")); + } + } else if (str == "nan" || str == "+nan") { + TOML11_CONSTEXPR_IF(std::numeric_limits::has_quiet_NaN) { + val = std::numeric_limits::quiet_NaN(); + } + else TOML11_CONSTEXPR_IF( + std::numeric_limits::has_signaling_NaN) { + val = std::numeric_limits::signaling_NaN(); + } + else { + return err(make_error_info( + "toml::parse_floating: NaN value found" + " but the current environment does not support NaN. Please" + " make sure that the floating-point implementation conforms" + " IEEE 754/ISO 60559 international standard.", + source_location(region(loc)), + "floating_type: NaN is not supported")); + } + } else if (str == "-nan") { + using std::copysign; + TOML11_CONSTEXPR_IF(std::numeric_limits::has_quiet_NaN) { + val = copysign(std::numeric_limits::quiet_NaN(), + floating_type(-1)); + } + else TOML11_CONSTEXPR_IF( + std::numeric_limits::has_signaling_NaN) { + val = copysign(std::numeric_limits::signaling_NaN(), + floating_type(-1)); + } + else { + return err(make_error_info( + "toml::parse_floating: NaN value found" + " but the current environment does not support NaN. Please" + " make sure that the floating-point implementation conforms" + " IEEE 754/ISO 60559 international standard.", + source_location(region(loc)), + "floating_type: NaN is not supported")); + } + } else { + // set precision + const auto has_sign = !str.empty() && + (str.front() == '+' || str.front() == '-'); + const auto decpoint = std::find(str.begin(), str.end(), '.'); + const auto exponent = std::find_if(str.begin(), str.end(), [](const char c) { + return c == 'e' || c == 'E'; + }); + if (decpoint != str.end() && exponent != str.end()) { + assert(decpoint < exponent); + } + + if (fmt.fmt == floating_format::scientific) { + // total width + fmt.prec = static_cast(std::distance(str.begin(), exponent)); + if (has_sign) { + fmt.prec -= 1; + } + if (decpoint != str.end()) { + fmt.prec -= 1; + } + } else if (fmt.fmt == floating_format::hex) { + fmt.prec = std::numeric_limits::max_digits10; + } else { + // width after decimal point + fmt.prec = static_cast( + std::distance(std::next(decpoint), exponent)); + } + + auto src = source_location(region(loc)); + const auto res = TC::parse_float(str, src, is_hex); + if (res.is_ok()) { + val = res.as_ok(); + } else { + return err(res.as_err()); + } + } + + // ---------------------------------------------------------------------- + // parse suffix (extension) + + if (spec.ext_num_suffix && loc.current() == '_') { + const auto sfx_reg = syntax::num_suffix(spec).scan(loc); + if (!sfx_reg.is_ok()) { + auto src = source_location(region(loc)); + loc = first; + return err(make_error_info( + "toml::parse_floating: " + "invalid suffix: should be `_ non-digit-graph (graph | _graph)`", + std::move(src), + "here")); + } + auto sfx = sfx_reg.as_string(); + assert(!sfx.empty() && sfx.front() == '_'); + sfx.erase(sfx.begin()); // remove the first `_` + + fmt.suffix = sfx; + } + + return ok(basic_value(val, std::move(fmt), {}, std::move(reg))); + } + + /* ============================================================================ + * ___ _ _ _ + * | \ __ _| |_ ___| |_(_)_ __ ___ + * | |) / _` | _/ -_) _| | ' \/ -_) + * |___/\__,_|\__\___|\__|_|_|_|_\___| + */ + + // all the offset_datetime, local_datetime, local_date parses date part. + template + result, error_info> + parse_local_date_only(location& loc, const context& ctx) { + const auto first = loc; + const auto& spec = ctx.toml_spec(); + + local_date_format_info fmt; + + // ---------------------------------------------------------------------- + // check syntax + auto reg = syntax::local_date(spec).scan(loc); + if (!reg.is_ok()) { + return err(make_syntax_error( + "toml::parse_local_date: " + "invalid date: date must be like: 1234-05-06, yyyy-mm-dd.", + syntax::local_date(spec), + loc)); + } + + // ---------------------------------------------------------------------- + // it matches. gen value + const auto str = reg.as_string(); + + // 0123456789 + // yyyy-mm-dd + const auto year_r = from_string(str.substr(0, 4)); + const auto month_r = from_string(str.substr(5, 2)); + const auto day_r = from_string(str.substr(8, 2)); + + if (year_r.is_err()) { + auto src = source_location(region(first)); + return err(make_error_info("toml::parse_local_date: " + "failed to read year `" + + str.substr(0, 4) + "`", + std::move(src), + "here")); + } + if (month_r.is_err()) { + auto src = source_location(region(first)); + return err(make_error_info("toml::parse_local_date: " + "failed to read month `" + + str.substr(5, 2) + "`", + std::move(src), + "here")); + } + if (day_r.is_err()) { + auto src = source_location(region(first)); + return err(make_error_info("toml::parse_local_date: " + "failed to read day `" + + str.substr(8, 2) + "`", + std::move(src), + "here")); + } + + const auto year = year_r.unwrap(); + const auto month = month_r.unwrap(); + const auto day = day_r.unwrap(); + + { + // We briefly check whether the input date is valid or not. + // Actually, because of the historical reasons, there are several + // edge cases, such as 1582/10/5-1582/10/14 (only in several countries). + // But here, we do not care about it. + // It makes the code complicated and there is only low probability + // that such a specific date is needed in practice. If someone need to + // validate date accurately, that means that the one need a specialized + // library for their purpose in another layer. + + const bool is_leap = (year % 4 == 0) && + ((year % 100 != 0) || (year % 400 == 0)); + const auto max_day = [month, is_leap]() { + if (month == 2) { + return is_leap ? 29 : 28; + } + if (month == 4 || month == 6 || month == 9 || month == 11) { + return 30; + } + return 31; + }(); + + if ((month < 1 || 12 < month) || (day < 1 || max_day < day)) { + auto src = source_location(region(first)); + return err( + make_error_info("toml::parse_local_date: invalid date.", + std::move(src), + "month must be 01-12, day must be any of " + "01-28,29,30,31 depending on the month/year.")); + } + } + + return ok( + std::make_tuple(local_date(year, static_cast(month - 1), day), + std::move(fmt), + std::move(reg))); + } + + template + result, error_info> parse_local_date(location& loc, + const context& ctx) { + auto val_fmt_reg = parse_local_date_only(loc, ctx); + if (val_fmt_reg.is_err()) { + return err(val_fmt_reg.unwrap_err()); + } + + auto val = std::move(std::get<0>(val_fmt_reg.unwrap())); + auto fmt = std::move(std::get<1>(val_fmt_reg.unwrap())); + auto reg = std::move(std::get<2>(val_fmt_reg.unwrap())); + + return ok( + basic_value(std::move(val), std::move(fmt), {}, std::move(reg))); + } + + // all the offset_datetime, local_datetime, local_time parses date part. + template + result, error_info> + parse_local_time_only(location& loc, const context& ctx) { + const auto first = loc; + const auto& spec = ctx.toml_spec(); + + local_time_format_info fmt; + + // ---------------------------------------------------------------------- + // check syntax + auto reg = syntax::local_time(spec).scan(loc); + if (!reg.is_ok()) { + if (spec.v1_1_0_make_seconds_optional) { + return err(make_syntax_error( + "toml::parse_local_time: " + "invalid time: time must be HH:MM(:SS.sss) (seconds are optional)", + syntax::local_time(spec), + loc)); + } else { + return err( + make_syntax_error("toml::parse_local_time: " + "invalid time: time must be HH:MM:SS(.sss) " + "(subseconds are optional)", + syntax::local_time(spec), + loc)); + } + } + + // ---------------------------------------------------------------------- + // it matches. gen value + const auto str = reg.as_string(); + + // at least we have HH:MM. + // 01234 + // HH:MM + const auto hour_r = from_string(str.substr(0, 2)); + const auto minute_r = from_string(str.substr(3, 2)); + + if (hour_r.is_err()) { + auto src = source_location(region(first)); + return err(make_error_info("toml::parse_local_time: " + "failed to read hour `" + + str.substr(0, 2) + "`", + std::move(src), + "here")); + } + if (minute_r.is_err()) { + auto src = source_location(region(first)); + return err(make_error_info("toml::parse_local_time: " + "failed to read minute `" + + str.substr(3, 2) + "`", + std::move(src), + "here")); + } + + const auto hour = hour_r.unwrap(); + const auto minute = minute_r.unwrap(); + + if ((hour < 0 || 24 <= hour) || (minute < 0 || 60 <= minute)) { + auto src = source_location(region(first)); + return err( + make_error_info("toml::parse_local_time: invalid time.", + std::move(src), + "hour must be 00-23, minute must be 00-59.")); + } + + // ----------------------------------------------------------------------- + // we have hour and minute. + // Since toml v1.1.0, second and subsecond part becomes optional. + // Check the version and return if second does not exist. + + if (str.size() == 5 && spec.v1_1_0_make_seconds_optional) { + fmt.has_seconds = false; + fmt.subsecond_precision = 0; + return ok(std::make_tuple(local_time(hour, minute, 0), + std::move(fmt), + std::move(reg))); + } + assert(str.at(5) == ':'); + + // we have at least `:SS` part. `.subseconds` are optional. + + // 0 1 + // 012345678901234 + // HH:MM:SS.subsec + const auto sec_r = from_string(str.substr(6, 2)); + if (sec_r.is_err()) { + auto src = source_location(region(first)); + return err(make_error_info("toml::parse_local_time: " + "failed to read second `" + + str.substr(6, 2) + "`", + std::move(src), + "here")); + } + const auto sec = sec_r.unwrap(); + + if (sec < 0 || 60 < sec) // :60 is allowed + { + auto src = source_location(region(first)); + return err(make_error_info("toml::parse_local_time: invalid time.", + std::move(src), + "second must be 00-60.")); + } + + if (str.size() == 8) { + fmt.has_seconds = true; + fmt.subsecond_precision = 0; + return ok(std::make_tuple(local_time(hour, minute, sec), + std::move(fmt), + std::move(reg))); + } + + assert(str.at(8) == '.'); + + auto secfrac = str.substr(9, str.size() - 9); + + fmt.has_seconds = true; + fmt.subsecond_precision = secfrac.size(); + + while (secfrac.size() < 9) { + secfrac += '0'; + } + assert(9 <= secfrac.size()); + const auto ms_r = from_string(secfrac.substr(0, 3)); + const auto us_r = from_string(secfrac.substr(3, 3)); + const auto ns_r = from_string(secfrac.substr(6, 3)); + + if (ms_r.is_err()) { + auto src = source_location(region(first)); + return err(make_error_info("toml::parse_local_time: " + "failed to read milliseconds `" + + secfrac.substr(0, 3) + "`", + std::move(src), + "here")); + } + if (us_r.is_err()) { + auto src = source_location(region(first)); + return err(make_error_info("toml::parse_local_time: " + "failed to read microseconds`" + + str.substr(3, 3) + "`", + std::move(src), + "here")); + } + if (ns_r.is_err()) { + auto src = source_location(region(first)); + return err(make_error_info("toml::parse_local_time: " + "failed to read nanoseconds`" + + str.substr(6, 3) + "`", + std::move(src), + "here")); + } + const auto ms = ms_r.unwrap(); + const auto us = us_r.unwrap(); + const auto ns = ns_r.unwrap(); + + return ok(std::make_tuple(local_time(hour, minute, sec, ms, us, ns), + std::move(fmt), + std::move(reg))); + } + + template + result, error_info> parse_local_time(location& loc, + const context& ctx) { + const auto first = loc; + + auto val_fmt_reg = parse_local_time_only(loc, ctx); + if (val_fmt_reg.is_err()) { + return err(val_fmt_reg.unwrap_err()); + } + + auto val = std::move(std::get<0>(val_fmt_reg.unwrap())); + auto fmt = std::move(std::get<1>(val_fmt_reg.unwrap())); + auto reg = std::move(std::get<2>(val_fmt_reg.unwrap())); + + return ok( + basic_value(std::move(val), std::move(fmt), {}, std::move(reg))); + } + + template + result, error_info> parse_local_datetime(location& loc, + const context& ctx) { + using char_type = location::char_type; + + const auto first = loc; + + local_datetime_format_info fmt; + + // ---------------------------------------------------------------------- + + auto date_fmt_reg = parse_local_date_only(loc, ctx); + if (date_fmt_reg.is_err()) { + return err(date_fmt_reg.unwrap_err()); + } + + if (loc.current() == char_type('T')) { + loc.advance(); + fmt.delimiter = datetime_delimiter_kind::upper_T; + } else if (loc.current() == char_type('t')) { + loc.advance(); + fmt.delimiter = datetime_delimiter_kind::lower_t; + } else if (loc.current() == char_type(' ')) { + loc.advance(); + fmt.delimiter = datetime_delimiter_kind::space; + } else { + auto src = source_location(region(loc)); + return err( + make_error_info("toml::parse_local_datetime: " + "expect date-time delimiter `T`, `t` or ` `(space).", + std::move(src), + "here")); + } + + auto time_fmt_reg = parse_local_time_only(loc, ctx); + if (time_fmt_reg.is_err()) { + return err(time_fmt_reg.unwrap_err()); + } + + fmt.has_seconds = std::get<1>(time_fmt_reg.unwrap()).has_seconds; + fmt.subsecond_precision = std::get<1>(time_fmt_reg.unwrap()).subsecond_precision; + + // ---------------------------------------------------------------------- + + region reg(first, loc); + local_datetime val(std::get<0>(date_fmt_reg.unwrap()), + std::get<0>(time_fmt_reg.unwrap())); + + return ok(basic_value(val, std::move(fmt), {}, std::move(reg))); + } + + template + result, error_info> parse_offset_datetime( + location& loc, + const context& ctx) { + using char_type = location::char_type; + + const auto first = loc; + const auto& spec = ctx.toml_spec(); + + offset_datetime_format_info fmt; + + // ---------------------------------------------------------------------- + // date part + + auto date_fmt_reg = parse_local_date_only(loc, ctx); + if (date_fmt_reg.is_err()) { + return err(date_fmt_reg.unwrap_err()); + } + + // ---------------------------------------------------------------------- + // delimiter + + if (loc.current() == char_type('T')) { + loc.advance(); + fmt.delimiter = datetime_delimiter_kind::upper_T; + } else if (loc.current() == char_type('t')) { + loc.advance(); + fmt.delimiter = datetime_delimiter_kind::lower_t; + } else if (loc.current() == char_type(' ')) { + loc.advance(); + fmt.delimiter = datetime_delimiter_kind::space; + } else { + auto src = source_location(region(loc)); + return err( + make_error_info("toml::parse_offset_datetime: " + "expect date-time delimiter `T` or ` `(space).", + std::move(src), + "here")); + } + + // ---------------------------------------------------------------------- + // time part + + auto time_fmt_reg = parse_local_time_only(loc, ctx); + if (time_fmt_reg.is_err()) { + return err(time_fmt_reg.unwrap_err()); + } + + fmt.has_seconds = std::get<1>(time_fmt_reg.unwrap()).has_seconds; + fmt.subsecond_precision = std::get<1>(time_fmt_reg.unwrap()).subsecond_precision; + + // ---------------------------------------------------------------------- + // offset part + + const auto ofs_reg = syntax::time_offset(spec).scan(loc); + if (!ofs_reg.is_ok()) { + return err(make_syntax_error( + "toml::parse_offset_datetime: " + "invalid offset: offset must be like: Z, +01:00, or -10:00.", + syntax::time_offset(spec), + loc)); + } + + const auto ofs_str = ofs_reg.as_string(); + + time_offset offset(0, 0); + + assert(ofs_str.size() != 0); + + if (ofs_str.at(0) == char_type('+') || ofs_str.at(0) == char_type('-')) { + const auto hour_r = from_string(ofs_str.substr(1, 2)); + const auto minute_r = from_string(ofs_str.substr(4, 2)); + if (hour_r.is_err()) { + auto src = source_location(region(loc)); + return err(make_error_info("toml::parse_offset_datetime: " + "Failed to read offset hour part", + std::move(src), + "here")); + } + if (minute_r.is_err()) { + auto src = source_location(region(loc)); + return err(make_error_info("toml::parse_offset_datetime: " + "Failed to read offset minute part", + std::move(src), + "here")); + } + const auto hour = hour_r.unwrap(); + const auto minute = minute_r.unwrap(); + + if (ofs_str.at(0) == '+') { + offset = time_offset(hour, minute); + } else { + offset = time_offset(-hour, -minute); + } + } else { + assert(ofs_str.at(0) == char_type('Z') || ofs_str.at(0) == char_type('z')); + } + + if (offset.hour < -24 || 24 < offset.hour || offset.minute < -60 || + 60 < offset.minute) { + return err( + make_error_info("toml::parse_offset_datetime: " + "too large offset: |hour| <= 24, |minute| <= 60", + source_location(region(first, loc)), + "here")); + } + + // ---------------------------------------------------------------------- + + region reg(first, loc); + offset_datetime val(local_datetime(std::get<0>(date_fmt_reg.unwrap()), + std::get<0>(time_fmt_reg.unwrap())), + offset); + + return ok(basic_value(val, std::move(fmt), {}, std::move(reg))); + } + + /* ============================================================================ + * ___ _ _ + * / __| |_ _ _(_)_ _ __ _ + * \__ \ _| '_| | ' \/ _` | + * |___/\__|_| |_|_||_\__, | + * |___/ + */ + + template + result::string_type, error_info> parse_utf8_codepoint( + const region& reg) { + using string_type = typename basic_value::string_type; + using char_type = typename string_type::value_type; + + // assert(reg.as_lines().size() == 1); // XXX heavy check + + const auto str = reg.as_string(); + assert(!str.empty()); + assert(str.front() == 'u' || str.front() == 'U' || str.front() == 'x'); + + std::uint_least32_t codepoint; + std::istringstream iss(str.substr(1)); + iss >> std::hex >> codepoint; + + const auto to_char = [](const std::uint_least32_t i) noexcept -> char_type { + const auto uc = static_cast(i & 0xFF); + return cxx::bit_cast(uc); + }; + + string_type character; + if (codepoint < 0x80) // U+0000 ... U+0079 ; just an ASCII. + { + character += static_cast(codepoint); + } else if (codepoint < 0x800) // U+0080 ... U+07FF + { + // 110yyyyx 10xxxxxx; 0x3f == 0b0011'1111 + character += to_char(0xC0 | (codepoint >> 6)); + character += to_char(0x80 | (codepoint & 0x3F)); + } else if (codepoint < 0x10000) // U+0800...U+FFFF + { + if (0xD800 <= codepoint && codepoint <= 0xDFFF) { + auto src = source_location(reg); + return err(make_error_info("toml::parse_utf8_codepoint: " + "[0xD800, 0xDFFF] is not a valid UTF-8", + std::move(src), + "here")); + } + assert(codepoint < 0xD800 || 0xDFFF < codepoint); + // 1110yyyy 10yxxxxx 10xxxxxx + character += to_char(0xE0 | (codepoint >> 12)); + character += to_char(0x80 | ((codepoint >> 6) & 0x3F)); + character += to_char(0x80 | ((codepoint) & 0x3F)); + } else if (codepoint < 0x110000) // U+010000 ... U+10FFFF + { + // 11110yyy 10yyxxxx 10xxxxxx 10xxxxxx + character += to_char(0xF0 | (codepoint >> 18)); + character += to_char(0x80 | ((codepoint >> 12) & 0x3F)); + character += to_char(0x80 | ((codepoint >> 6) & 0x3F)); + character += to_char(0x80 | ((codepoint) & 0x3F)); + } else // out of UTF-8 region + { + auto src = source_location(reg); + return err(make_error_info("toml::parse_utf8_codepoint: " + "input codepoint is too large.", + std::move(src), + "must be in range [0x00, 0x10FFFF]")); + } + return ok(character); + } + + template + result::string_type, error_info> parse_escape_sequence( + location& loc, + const context& ctx) { + using string_type = typename basic_value::string_type; + using char_type = typename string_type::value_type; + + const auto& spec = ctx.toml_spec(); + + assert(!loc.eof()); + assert(loc.current() == '\\'); + loc.advance(); // consume the first backslash + + string_type retval; + + if (loc.current() == '\\') { + retval += char_type('\\'); + loc.advance(); + } else if (loc.current() == '"') { + retval += char_type('\"'); + loc.advance(); + } else if (loc.current() == 'b') { + retval += char_type('\b'); + loc.advance(); + } else if (loc.current() == 'f') { + retval += char_type('\f'); + loc.advance(); + } else if (loc.current() == 'n') { + retval += char_type('\n'); + loc.advance(); + } else if (loc.current() == 'r') { + retval += char_type('\r'); + loc.advance(); + } else if (loc.current() == 't') { + retval += char_type('\t'); + loc.advance(); + } else if (spec.v1_1_0_add_escape_sequence_e && loc.current() == 'e') { + retval += char_type('\x1b'); + loc.advance(); + } else if (spec.v1_1_0_add_escape_sequence_x && loc.current() == 'x') { + auto scanner = sequence(character('x'), + repeat_exact(2, syntax::hexdig(spec))); + const auto reg = scanner.scan(loc); + if (!reg.is_ok()) { + auto src = source_location(region(loc)); + return err( + make_error_info("toml::parse_escape_sequence: " + "invalid token found in UTF-8 codepoint \\xhh", + std::move(src), + "here")); + } + const auto utf8 = parse_utf8_codepoint(reg); + if (utf8.is_err()) { + return err(utf8.as_err()); + } + retval += utf8.unwrap(); + } else if (loc.current() == 'u') { + auto scanner = sequence(character('u'), + repeat_exact(4, syntax::hexdig(spec))); + const auto reg = scanner.scan(loc); + if (!reg.is_ok()) { + auto src = source_location(region(loc)); + return err( + make_error_info("toml::parse_escape_sequence: " + "invalid token found in UTF-8 codepoint \\uhhhh", + std::move(src), + "here")); + } + const auto utf8 = parse_utf8_codepoint(reg); + if (utf8.is_err()) { + return err(utf8.as_err()); + } + retval += utf8.unwrap(); + } else if (loc.current() == 'U') { + auto scanner = sequence(character('U'), + repeat_exact(8, syntax::hexdig(spec))); + const auto reg = scanner.scan(loc); + if (!reg.is_ok()) { + auto src = source_location(region(loc)); + return err(make_error_info( + "toml::parse_escape_sequence: " + "invalid token found in UTF-8 codepoint \\Uhhhhhhhh", + std::move(src), + "here")); + } + const auto utf8 = parse_utf8_codepoint(reg); + if (utf8.is_err()) { + return err(utf8.as_err()); + } + retval += utf8.unwrap(); + } else { + auto src = source_location(region(loc)); + std::string escape_seqs = + "allowed escape seqs: \\\\, \\\", \\b, \\f, \\n, \\r, \\t"; + if (spec.v1_1_0_add_escape_sequence_e) { + escape_seqs += ", \\e"; + } + if (spec.v1_1_0_add_escape_sequence_x) { + escape_seqs += ", \\xhh"; + } + escape_seqs += ", \\uhhhh, or \\Uhhhhhhhh"; + + return err(make_error_info("toml::parse_escape_sequence: " + "unknown escape sequence.", + std::move(src), + escape_seqs)); + } + return ok(retval); + } + + template + result, error_info> parse_ml_basic_string( + location& loc, + const context& ctx) { + const auto first = loc; + const auto& spec = ctx.toml_spec(); + + string_format_info fmt; + fmt.fmt = string_format::multiline_basic; + + auto reg = syntax::ml_basic_string(spec).scan(loc); + if (!reg.is_ok()) { + return err(make_syntax_error("toml::parse_ml_basic_string: " + "invalid string format", + syntax::ml_basic_string(spec), + loc)); + } + + // ---------------------------------------------------------------------- + // it matches. gen value + + auto str = reg.as_string(); + + // we already checked that it starts with """ and ends with """. + assert(str.substr(0, 3) == "\"\"\""); + str.erase(0, 3); + + assert(str.size() >= 3); + assert(str.substr(str.size() - 3, 3) == "\"\"\""); + str.erase(str.size() - 3, 3); + + // the first newline just after """ is trimmed + if (str.size() >= 1 && str.at(0) == '\n') { + str.erase(0, 1); + fmt.start_with_newline = true; + } else if (str.size() >= 2 && str.at(0) == '\r' && str.at(1) == '\n') { + str.erase(0, 2); + fmt.start_with_newline = true; + } + + using string_type = typename basic_value::string_type; + string_type val; + { + auto iter = str.cbegin(); + while (iter != str.cend()) { + if (*iter == '\\') // remove whitespaces around escaped-newline + { + // we assume that the string is not too long to copy + auto loc2 = make_temporary_location(make_string(iter, str.cend())); + if (syntax::escaped_newline(spec).scan(loc2).is_ok()) { + std::advance(iter, + loc2.get_location()); // skip escaped newline and indent + // now iter points non-WS char + assert(iter == str.end() || (*iter != ' ' && *iter != '\t')); + } else // normal escape seq. + { + auto esc = parse_escape_sequence(loc2, ctx); + + // syntax does not check its value. the unicode codepoint may be + // invalid, e.g. out-of-bound, [0xD800, 0xDFFF] + if (esc.is_err()) { + return err(esc.unwrap_err()); + } + + val += esc.unwrap(); + std::advance(iter, loc2.get_location()); + } + } else // we already checked the syntax. we don't need to check it again. + { + val += static_cast(*iter); + ++iter; + } + } + } + + return ok( + basic_value(std::move(val), std::move(fmt), {}, std::move(reg))); + } + + template + result::string_type, region>, error_info> + parse_basic_string_only(location& loc, const context& ctx) { + const auto first = loc; + const auto& spec = ctx.toml_spec(); + + auto reg = syntax::basic_string(spec).scan(loc); + if (!reg.is_ok()) { + return err(make_syntax_error("toml::parse_basic_string: " + "invalid string format", + syntax::basic_string(spec), + loc)); + } + + // ---------------------------------------------------------------------- + // it matches. gen value + + auto str = reg.as_string(); + + assert(str.back() == '\"'); + str.pop_back(); + assert(str.at(0) == '\"'); + str.erase(0, 1); + + using string_type = typename basic_value::string_type; + using char_type = typename string_type::value_type; + string_type val; + + { + auto iter = str.begin(); + while (iter != str.end()) { + if (*iter == '\\') { + auto loc2 = make_temporary_location(make_string(iter, str.end())); + + auto esc = parse_escape_sequence(loc2, ctx); + + // syntax does not check its value. the unicode codepoint may be + // invalid, e.g. out-of-bound, [0xD800, 0xDFFF] + if (esc.is_err()) { + return err(esc.unwrap_err()); + } + + val += esc.unwrap(); + std::advance(iter, loc2.get_location()); + } else { + val += char_type(*iter); // we already checked the syntax. + ++iter; + } + } + } + return ok(std::make_pair(val, reg)); + } + + template + result, error_info> parse_basic_string(location& loc, + const context& ctx) { + const auto first = loc; + + string_format_info fmt; + fmt.fmt = string_format::basic; + + auto val_res = parse_basic_string_only(loc, ctx); + if (val_res.is_err()) { + return err(std::move(val_res.unwrap_err())); + } + auto val = std::move(val_res.unwrap().first); + auto reg = std::move(val_res.unwrap().second); + + return ok( + basic_value(std::move(val), std::move(fmt), {}, std::move(reg))); + } + + template + result, error_info> parse_ml_literal_string( + location& loc, + const context& ctx) { + const auto first = loc; + const auto& spec = ctx.toml_spec(); + + string_format_info fmt; + fmt.fmt = string_format::multiline_literal; + + auto reg = syntax::ml_literal_string(spec).scan(loc); + if (!reg.is_ok()) { + return err(make_syntax_error("toml::parse_ml_literal_string: " + "invalid string format", + syntax::ml_literal_string(spec), + loc)); + } + + // ---------------------------------------------------------------------- + // it matches. gen value + + auto str = reg.as_string(); + + assert(str.substr(0, 3) == "'''"); + assert(str.substr(str.size() - 3, 3) == "'''"); + str.erase(0, 3); + str.erase(str.size() - 3, 3); + + // the first newline just after """ is trimmed + if (str.size() >= 1 && str.at(0) == '\n') { + str.erase(0, 1); + fmt.start_with_newline = true; + } else if (str.size() >= 2 && str.at(0) == '\r' && str.at(1) == '\n') { + str.erase(0, 2); + fmt.start_with_newline = true; + } + + using string_type = typename basic_value::string_type; + string_type val(str.begin(), str.end()); + + return ok( + basic_value(std::move(val), std::move(fmt), {}, std::move(reg))); + } + + template + result::string_type, region>, error_info> + parse_literal_string_only(location& loc, const context& ctx) { + const auto first = loc; + const auto& spec = ctx.toml_spec(); + + auto reg = syntax::literal_string(spec).scan(loc); + if (!reg.is_ok()) { + return err(make_syntax_error("toml::parse_literal_string: " + "invalid string format", + syntax::literal_string(spec), + loc)); + } + + // ---------------------------------------------------------------------- + // it matches. gen value + + auto str = reg.as_string(); + + assert(str.back() == '\''); + str.pop_back(); + assert(str.at(0) == '\''); + str.erase(0, 1); + + using string_type = typename basic_value::string_type; + string_type val(str.begin(), str.end()); + + return ok(std::make_pair(std::move(val), std::move(reg))); + } + + template + result, error_info> parse_literal_string(location& loc, + const context& ctx) { + const auto first = loc; + + string_format_info fmt; + fmt.fmt = string_format::literal; + + auto val_res = parse_literal_string_only(loc, ctx); + if (val_res.is_err()) { + return err(std::move(val_res.unwrap_err())); + } + auto val = std::move(val_res.unwrap().first); + auto reg = std::move(val_res.unwrap().second); + + return ok( + basic_value(std::move(val), std::move(fmt), {}, std::move(reg))); + } + + template + result, error_info> parse_string(location& loc, + const context& ctx) { + const auto first = loc; + + if (!loc.eof() && loc.current() == '"') { + if (literal("\"\"\"").scan(loc).is_ok()) { + loc = first; + return parse_ml_basic_string(loc, ctx); + } else { + loc = first; + return parse_basic_string(loc, ctx); + } + } else if (!loc.eof() && loc.current() == '\'') { + if (literal("'''").scan(loc).is_ok()) { + loc = first; + return parse_ml_literal_string(loc, ctx); + } else { + loc = first; + return parse_literal_string(loc, ctx); + } + } else { + auto src = source_location(region(loc)); + return err(make_error_info("toml::parse_string: " + "not a string", + std::move(src), + "here")); + } + } + + template + result, error_info> parse_null(location& loc, + const context& ctx) { + const auto& spec = ctx.toml_spec(); + if (!spec.ext_null_value) { + return err( + make_error_info("toml::parse_null: " + "invalid spec: spec.ext_null_value must be true.", + source_location(region(loc)), + "here")); + } + + // ---------------------------------------------------------------------- + // check syntax + auto reg = syntax::null_value(spec).scan(loc); + if (!reg.is_ok()) { + return err(make_syntax_error("toml::parse_null: " + "invalid null: null must be lowercase. ", + syntax::null_value(spec), + loc)); + } + + // ---------------------------------------------------------------------- + // it matches. gen value + + // ---------------------------------------------------------------------- + // no format info for boolean + + return ok(basic_value(detail::none_t {}, std::move(reg))); + } + + /* ============================================================================ + * _ __ + * | |/ /___ _ _ + * | ' + result::key_type, error_info> parse_simple_key( + location& loc, + const context& ctx) { + using key_type = typename basic_value::key_type; + const auto& spec = ctx.toml_spec(); + + if (loc.current() == '\"') { + auto str_res = parse_basic_string_only(loc, ctx); + if (str_res.is_ok()) { + return ok(std::move(str_res.unwrap().first)); + } else { + return err(std::move(str_res.unwrap_err())); + } + } else if (loc.current() == '\'') { + auto str_res = parse_literal_string_only(loc, ctx); + if (str_res.is_ok()) { + return ok(std::move(str_res.unwrap().first)); + } else { + return err(std::move(str_res.unwrap_err())); + } + } + + // bare key. + + if (const auto bare = syntax::unquoted_key(spec).scan(loc)) { + return ok(string_conv(bare.as_string())); + } else { + std::string postfix; + if (spec.v1_1_0_allow_non_english_in_bare_keys) { + postfix = + "Hint: Not all Unicode characters are allowed as bare key.\n"; + } else { + postfix = "Hint: non-ASCII scripts are allowed in toml v1.1.0, but " + "not in v1.0.0.\n"; + } + return err(make_syntax_error( + "toml::parse_simple_key: " + "invalid key: key must be \"quoted\", 'quoted-literal', or bare key.", + syntax::unquoted_key(spec), + loc, + postfix)); + } + } + + // dotted key become vector of keys + template + result::key_type>, region>, error_info> + parse_key(location& loc, const context& ctx) { + const auto first = loc; + const auto& spec = ctx.toml_spec(); + + using key_type = typename basic_value::key_type; + std::vector keys; + while (!loc.eof()) { + auto key = parse_simple_key(loc, ctx); + if (!key.is_ok()) { + return err(key.unwrap_err()); + } + keys.push_back(std::move(key.unwrap())); + + auto reg = syntax::dot_sep(spec).scan(loc); + if (!reg.is_ok()) { + break; + } + } + if (keys.empty()) { + auto src = source_location(region(first)); + return err(make_error_info("toml::parse_key: expected a new key, " + "but got nothing", + std::move(src), + "reached EOF")); + } + + return ok(std::make_pair(std::move(keys), region(first, loc))); + } + + // ============================================================================ + + // forward-decl to implement parse_array and parse_table + template + result, error_info> parse_value(location&, context& ctx); + + template + result::key_type>, region>, + basic_value>, + error_info> + parse_key_value_pair(location& loc, context& ctx) { + const auto first = loc; + const auto& spec = ctx.toml_spec(); + + auto key_res = parse_key(loc, ctx); + if (key_res.is_err()) { + loc = first; + return err(key_res.unwrap_err()); + } + + if (!syntax::keyval_sep(spec).scan(loc).is_ok()) { + auto e = make_syntax_error("toml::parse_key_value_pair: " + "invalid key value separator `=`", + syntax::keyval_sep(spec), + loc); + loc = first; + return err(std::move(e)); + } + + auto v_res = parse_value(loc, ctx); + if (v_res.is_err()) { + // loc = first; + return err(v_res.unwrap_err()); + } + return ok( + std::make_pair(std::move(key_res.unwrap()), std::move(v_res.unwrap()))); + } + + /* ============================================================================ + * __ _ _ _ _ _ __ _ _ _ + * / _` | '_| '_/ _` | || | + * \__,_|_| |_| \__,_|\_, | + * |__/ + */ + + // array(and multiline inline table with `{` and `}`) has the following format. + // `[` + // (ws|newline|comment-line)? (value) (ws|newline|comment-line)? `,` + // (ws|newline|comment-line)? (value) (ws|newline|comment-line)? `,` + // ... + // (ws|newline|comment-line)? (value) (ws|newline|comment-line)? (`,`)? + // (ws|newline|comment-line)? `]` + // it skips (ws|newline|comment-line) and returns the token. + template + struct multiline_spacer { + using comment_type = typename TC::comment_type; + bool newline_found; + indent_char indent_type; + std::int32_t indent; + comment_type comments; + }; + + template + std::ostream& operator<<(std::ostream& os, const multiline_spacer& sp) { + os << "{newline=" << sp.newline_found << ", "; + os << "indent_type=" << sp.indent_type << ", "; + os << "indent=" << sp.indent << ", "; + os << "comments=" << sp.comments.size() << "}"; + return os; + } + + template + cxx::optional> skip_multiline_spacer( + location& loc, + context& ctx, + const bool newline_found = false) { + const auto& spec = ctx.toml_spec(); + + multiline_spacer spacer; + spacer.newline_found = newline_found; + spacer.indent_type = indent_char::none; + spacer.indent = 0; + spacer.comments.clear(); + + bool spacer_found = false; + while (!loc.eof()) { + if (auto comm = sequence(syntax::comment(spec), syntax::newline(spec)) + .scan(loc)) { + spacer.newline_found = true; + auto comment = comm.as_string(); + if (!comment.empty() && comment.back() == '\n') { + comment.pop_back(); + if (!comment.empty() && comment.back() == '\r') { + comment.pop_back(); + } + } + + spacer.comments.push_back(std::move(comment)); + spacer.indent_type = indent_char::none; + spacer.indent = 0; + spacer_found = true; + } else if (auto nl = syntax::newline(spec).scan(loc)) { + spacer.newline_found = true; + spacer.comments.clear(); + spacer.indent_type = indent_char::none; + spacer.indent = 0; + spacer_found = true; + } else if (auto sp = repeat_at_least( + 1, + character(cxx::bit_cast(' '))) + .scan(loc)) { + spacer.indent_type = indent_char::space; + spacer.indent = static_cast(sp.length()); + spacer_found = true; + } else if ( + auto tabs = repeat_at_least( + 1, + character(cxx::bit_cast('\t'))) + .scan(loc)) { + spacer.indent_type = indent_char::tab; + spacer.indent = static_cast(tabs.length()); + spacer_found = true; + } else { + break; // done + } + } + if (!spacer_found) { + return cxx::make_nullopt(); + } + return spacer; + } + + // not an [[array.of.tables]]. It parses ["this", "type"] + template + result, error_info> parse_array(location& loc, + context& ctx) { + const auto num_errors = ctx.errors().size(); + + const auto first = loc; + + if (loc.eof() || loc.current() != '[') { + auto src = source_location(region(loc)); + return err(make_error_info("toml::parse_array: " + "The next token is not an array", + std::move(src), + "here")); + } + loc.advance(); + + typename basic_value::array_type val; + + array_format_info fmt; + fmt.fmt = array_format::oneline; + fmt.indent_type = indent_char::none; + + auto spacer = skip_multiline_spacer(loc, ctx); + if (spacer.has_value() && spacer.value().newline_found) { + fmt.fmt = array_format::multiline; + } + + bool comma_found = true; + while (!loc.eof()) { + if (loc.current() == location::char_type(']')) { + if (spacer.has_value() && spacer.value().newline_found && + spacer.value().indent_type != indent_char::none) { + fmt.indent_type = spacer.value().indent_type; + fmt.closing_indent = spacer.value().indent; + } + break; + } + + if (!comma_found) { + auto src = source_location(region(loc)); + return err( + make_error_info("toml::parse_array: " + "expected value-separator `,` or closing `]`", + std::move(src), + "here")); + } + + if (spacer.has_value() && spacer.value().newline_found && + spacer.value().indent_type != indent_char::none) { + fmt.indent_type = spacer.value().indent_type; + fmt.body_indent = spacer.value().indent; + } + + if (auto elem_res = parse_value(loc, ctx)) { + auto elem = std::move(elem_res.unwrap()); + + if (spacer.has_value()) // copy previous comments to value + { + elem.comments() = std::move(spacer.value().comments); + } + + // parse spaces between a value and a comma + // array = [ + // 42 , # the answer + // ^^^^ + // 3.14 # pi + // , 2.71 ^^^^ + // ^^ + spacer = skip_multiline_spacer(loc, ctx); + if (spacer.has_value()) { + for (std::size_t i = 0; i < spacer.value().comments.size(); ++i) { + elem.comments().push_back(std::move(spacer.value().comments.at(i))); + } + if (spacer.value().newline_found) { + fmt.fmt = array_format::multiline; + } + } + + comma_found = character(',').scan(loc).is_ok(); + + // parse comment after a comma + // array = [ + // 42 , # the answer + // ^^^^^^^^^^^^ + // 3.14 # pi + // ^^^^ + // ] + auto com_res = parse_comment_line(loc, ctx); + if (com_res.is_err()) { + ctx.report_error(com_res.unwrap_err()); + } + + const bool comment_found = com_res.is_ok() && + com_res.unwrap().has_value(); + if (comment_found) { + fmt.fmt = array_format::multiline; + elem.comments().push_back(com_res.unwrap().value()); + } + if (comma_found) { + spacer = skip_multiline_spacer(loc, ctx, comment_found); + if (spacer.has_value() && spacer.value().newline_found) { + fmt.fmt = array_format::multiline; + } + } + val.push_back(std::move(elem)); + } else { + // if err, push error to ctx and try recovery. + ctx.report_error(std::move(elem_res.unwrap_err())); + + // if it looks like some value, then skip the value. + // otherwise, it may be a new key-value pair or a new table and + // the error is "missing closing ]". stop parsing. + + const auto before_skip = loc.get_location(); + skip_value(loc, ctx); + if (before_skip == loc.get_location()) // cannot skip! break... + { + break; + } + } + } + + if (loc.current() != ']') { + auto src = source_location(region(loc)); + return err( + make_error_info("toml::parse_array: missing closing bracket `]`", + std::move(src), + "expected `]`, reached EOF")); + } else { + loc.advance(); + } + // any error reported from this function + if (num_errors != ctx.errors().size()) { + assert(ctx.has_error()); // already reported + return err(ctx.errors().back()); + } + + return ok( + basic_value(std::move(val), std::move(fmt), {}, region(first, loc))); + } + + /* ============================================================================ + * _ _ _ _ _ _ + * (_)_ _ | (_)_ _ ___ | |_ __ _| |__| |___ + * | | ' \| | | ' \/ -_) | _/ _` | '_ \ / -_) + * |_|_||_|_|_|_||_\___| \__\__,_|_.__/_\___| + */ + + // ---------------------------------------------------------------------------- + // insert_value is the most complicated part of the toml spec. + // + // To parse a toml file correctly, we sometimes need to check an exising + // value is appendable or not. + // + // For example while parsing an inline array of tables, + // + // ```toml + // aot = [ + // {a = "foo"}, + // {a = "bar", b = "baz"}, + // ] + // ``` + // + // this `aot` is appendable until parser reaches to `]`. After that, it + // becomes non-appendable. + // + // On the other hand, a normal array of tables, such as + // + // ```toml + // [[aot]] + // a = "foo" + // + // [[aot]] + // a = "bar" + // b = "baz" + // ``` + // This `[[aot]]` is appendable until the parser reaches to the EOF. + // + // + // It becomes a bit more difficult in case of dotted keys. + // In TOML, it is allowed to append a key-value pair to a table that is + // *implicitly* defined by a subtable definitino. + // + // ```toml + // [x.y.z] + // w = 123 + // + // [x] + // a = "foo" # OK. x is defined implicitly by `[x.y.z]`. + // ``` + // + // But if the table is defined by a dotted keys, it is not appendable. + // + // ```toml + // [x] + // y.z.w = 123 + // + // [x.y] + // # ERROR. x.y is already defined by a dotted table in the previous table. + // ``` + // + // Also, reopening a table using dotted keys is invalid. + // + // ```toml + // [x.y.z] + // w = 123 + // + // [x] + // y.z.v = 42 # ERROR. [x.y.z] is already defined. + // ``` + // + // + // ```toml + // [a] + // b.c = "foo" + // b.d = "bar" + // ``` + // + // + // ```toml + // a.b = "foo" + // [a] + // c = "bar" # ERROR + // ``` + // + // In summary, + // - a table must be defined only once. + // - assignment to an exising table is possible only when: + // - defining a subtable [x.y] to an existing table [x]. + // - defining supertable [x] explicitly after [x.y]. + // - adding dotted keys in the same table. + + enum class inserting_value_kind : std::uint8_t { + std_table, // insert [standard.table] + array_table, // insert [[array.of.tables]] + dotted_keys // insert a.b.c = "this" + }; + + template + result*, error_info> insert_value( + const inserting_value_kind kind, + typename basic_value::table_type* current_table_ptr, + const std::vector::key_type>& keys, + region key_reg, + basic_value val) { + using value_type = basic_value; + using array_type = typename basic_value::array_type; + using table_type = typename basic_value::table_type; + + auto key_loc = source_location(key_reg); + + assert(!keys.empty()); + + // dotted key can insert to dotted key tables defined at the same level. + // dotted key can NOT reopen a table even if it is implcitly-defined one. + // + // [x.y.z] # define x and x.y implicitly. + // a = 42 + // + // [x] # reopening implcitly defined table + // r.s.t = 3.14 # VALID r and r.s are new tables. + // r.s.u = 2.71 # VALID r and r.s are dotted-key tables. valid. + // + // y.z.b = "foo" # INVALID x.y.z are multiline table, not a dotted key. + // y.c = "bar" # INVALID x.y is implicit multiline table, not a dotted key. + + // a table cannot reopen dotted-key tables. + // + // [t1] + // t2.t3.v = 0 + // [t1.t2] # INVALID t1.t2 is defined as a dotted-key table. + + for (std::size_t i = 0; i < keys.size(); ++i) { + const auto& key = keys.at(i); + table_type& current_table = *current_table_ptr; + + if (i + 1 < keys.size()) // there are more keys. go down recursively... + { + const auto found = current_table.find(key); + if (found == current_table.end()) // not found. add new table + { + table_format_info fmt; + fmt.indent_type = indent_char::none; + if (kind == inserting_value_kind::dotted_keys) { + fmt.fmt = table_format::dotted; + } else // table / array of tables + { + fmt.fmt = table_format::implicit; + } + current_table.emplace( + key, + value_type(table_type {}, fmt, std::vector {}, key_reg)); + + assert(current_table.at(key).is_table()); + current_table_ptr = std::addressof(current_table.at(key).as_table()); + } else if (found->second.is_table()) { + const auto fmt = found->second.as_table_fmt().fmt; + if (fmt == table_format::oneline || + fmt == table_format::multiline_oneline) { + // foo = {bar = "baz"} or foo = { \n bar = "baz" \n } + return err(make_error_info( + "toml::insert_value: " + "failed to insert a value: inline table is immutable", + key_loc, + "inserting this", + found->second.location(), + "to this table")); + } + // dotted key cannot reopen a table. + if (kind == inserting_value_kind::dotted_keys && + fmt != table_format::dotted) { + return err(make_error_info("toml::insert_value: " + "reopening a table using dotted keys", + key_loc, + "dotted key cannot reopen a table", + found->second.location(), + "this table is already closed")); + } + assert(found->second.is_table()); + current_table_ptr = std::addressof(found->second.as_table()); + } else if (found->second.is_array_of_tables()) { + // aot = [{this = "type", of = "aot"}] # cannot be reopened + if (found->second.as_array_fmt().fmt != array_format::array_of_tables) { + return err(make_error_info("toml::insert_value:" + "inline array of tables are immutable", + key_loc, + "inserting this", + found->second.location(), + "inline array of tables")); + } + // appending to [[aot]] + + if (kind == inserting_value_kind::dotted_keys) { + // [[array.of.tables]] + // [array.of] # reopening supertable is okay + // tables.x = "foo" # appending `x` to the first table + return err( + make_error_info("toml::insert_value:" + "dotted key cannot reopen an array-of-tables", + key_loc, + "inserting this", + found->second.location(), + "to this array-of-tables.")); + } + + // insert_value_by_dotkeys::std_table + // [[array.of.tables]] + // [array.of.tables.subtable] # appending to the last aot + // + // insert_value_by_dotkeys::array_table + // [[array.of.tables]] + // [[array.of.tables.subtable]] # appending to the last aot + auto& current_array_table = found->second.as_array().back(); + + assert(current_array_table.is_table()); + current_table_ptr = std::addressof(current_array_table.as_table()); + } else { + return err( + make_error_info("toml::insert_value: " + "failed to insert a value, value already exists", + key_loc, + "while inserting this", + found->second.location(), + "non-table value already exists")); + } + } else // this is the last key. insert a new value. + { + switch (kind) { + case inserting_value_kind::dotted_keys: { + if (current_table.find(key) != current_table.end()) { + return err(make_error_info( + "toml::insert_value: " + "failed to insert a value, value already exists", + key_loc, + "inserting this", + current_table.at(key).location(), + "but value already exists")); + } + current_table.emplace(key, std::move(val)); + return ok(std::addressof(current_table.at(key))); + } + case inserting_value_kind::std_table: { + // defining a new table or reopening supertable + auto found = current_table.find(key); + if (found == current_table.end()) // define a new aot + { + current_table.emplace(key, std::move(val)); + return ok(std::addressof(current_table.at(key))); + } else // the table is already defined, reopen it + { + // assigning a [std.table]. it must be an implicit table. + auto& target = found->second; + if (!target.is_table() || // could be an array-of-tables + target.as_table_fmt().fmt != table_format::implicit) { + return err(make_error_info( + "toml::insert_value: " + "failed to insert a table, table already defined", + key_loc, + "inserting this", + target.location(), + "this table is explicitly defined")); + } + + // merge table + for (const auto& kv : val.as_table()) { + if (target.contains(kv.first)) { + // [x.y.z] + // w = "foo" + // [x] + // y = "bar" + return err( + make_error_info("toml::insert_value: " + "failed to insert a table, table keys " + "conflict to each other", + key_loc, + "inserting this table", + kv.second.location(), + "having this value", + target.at(kv.first).location(), + "already defined here")); + } else { + target[kv.first] = kv.second; + } + } + // change implicit -> explicit + target.as_table_fmt().fmt = table_format::multiline; + // change definition region + change_region_of_value(target, val); + + return ok(std::addressof(current_table.at(key))); + } + } + case inserting_value_kind::array_table: { + auto found = current_table.find(key); + if (found == current_table.end()) // define a new aot + { + array_format_info fmt; + fmt.fmt = array_format::array_of_tables; + fmt.indent_type = indent_char::none; + + current_table.emplace(key, + value_type(array_type { std::move(val) }, + std::move(fmt), + std::vector {}, + std::move(key_reg))); + + assert(!current_table.at(key).as_array().empty()); + return ok(std::addressof(current_table.at(key).as_array().back())); + } else // the array is already defined, append to it + { + if (!found->second.is_array_of_tables()) { + return err(make_error_info( + "toml::insert_value: " + "failed to insert an array of tables, value already exists", + key_loc, + "while inserting this", + found->second.location(), + "non-table value already exists")); + } + if (found->second.as_array_fmt().fmt != + array_format::array_of_tables) { + return err(make_error_info("toml::insert_value: " + "failed to insert a table, inline " + "array of tables is immutable", + key_loc, + "while inserting this", + found->second.location(), + "this is inline array-of-tables")); + } + found->second.as_array().push_back(std::move(val)); + assert(!current_table.at(key).as_array().empty()); + return ok(std::addressof(current_table.at(key).as_array().back())); + } + } + default: { + assert(false); + } + } + } + } + return err(make_error_info("toml::insert_key: no keys found", + std::move(key_loc), + "here")); + } + + // ---------------------------------------------------------------------------- + + template + result, error_info> parse_inline_table(location& loc, + context& ctx) { + using table_type = typename basic_value::table_type; + + const auto num_errors = ctx.errors().size(); + + const auto first = loc; + const auto& spec = ctx.toml_spec(); + + if (loc.eof() || loc.current() != '{') { + auto src = source_location(region(loc)); + return err(make_error_info("toml::parse_inline_table: " + "The next token is not an inline table", + std::move(src), + "here")); + } + loc.advance(); + + table_type table; + table_format_info fmt; + fmt.fmt = table_format::oneline; + fmt.indent_type = indent_char::none; + + cxx::optional> spacer(cxx::make_nullopt()); + + if (spec.v1_1_0_allow_newlines_in_inline_tables) { + spacer = skip_multiline_spacer(loc, ctx); + if (spacer.has_value() && spacer.value().newline_found) { + fmt.fmt = table_format::multiline_oneline; + } + } else { + skip_whitespace(loc, ctx); + } + + bool still_empty = true; + bool comma_found = false; + while (!loc.eof()) { + // closing! + if (loc.current() == '}') { + if (comma_found && !spec.v1_1_0_allow_trailing_comma_in_inline_tables) { + auto src = source_location(region(loc)); + return err(make_error_info("toml::parse_inline_table: trailing " + "comma is not allowed in TOML-v1.0.0)", + std::move(src), + "here")); + } + + if (spec.v1_1_0_allow_newlines_in_inline_tables) { + if (spacer.has_value() && spacer.value().newline_found && + spacer.value().indent_type != indent_char::none) { + fmt.indent_type = spacer.value().indent_type; + fmt.closing_indent = spacer.value().indent; + } + } + break; + } + + // if we already found a value and didn't found `,` nor `}`, error. + if (!comma_found && !still_empty) { + auto src = source_location(region(loc)); + return err( + make_error_info("toml::parse_inline_table: " + "expected value-separator `,` or closing `}`", + std::move(src), + "here")); + } + + // parse indent. + if (spacer.has_value() && spacer.value().newline_found && + spacer.value().indent_type != indent_char::none) { + fmt.indent_type = spacer.value().indent_type; + fmt.body_indent = spacer.value().indent; + } + + still_empty = false; // parsing a value... + if (auto kv_res = parse_key_value_pair(loc, ctx)) { + auto keys = std::move(kv_res.unwrap().first.first); + auto key_reg = std::move(kv_res.unwrap().first.second); + auto val = std::move(kv_res.unwrap().second); + + auto ins_res = insert_value(inserting_value_kind::dotted_keys, + std::addressof(table), + keys, + std::move(key_reg), + std::move(val)); + if (ins_res.is_err()) { + ctx.report_error(std::move(ins_res.unwrap_err())); + // we need to skip until the next value (or end of the table) + // because we don't have valid kv pair. + while (!loc.eof()) { + const auto c = loc.current(); + if (c == ',' || c == '\n' || c == '}') { + comma_found = (c == ','); + break; + } + loc.advance(); + } + continue; + } + + // if comment line follows immediately(without newline) after `,`, then + // the comment is for the elem. we need to check if comment follows `,`. + // + // (key) = (val) (ws|newline|comment-line)? `,` (ws)? (comment)? + + if (spec.v1_1_0_allow_newlines_in_inline_tables) { + if (spacer.has_value()) // copy previous comments to value + { + for (std::size_t i = 0; i < spacer.value().comments.size(); ++i) { + ins_res.unwrap()->comments().push_back( + spacer.value().comments.at(i)); + } + } + spacer = skip_multiline_spacer(loc, ctx); + if (spacer.has_value()) { + for (std::size_t i = 0; i < spacer.value().comments.size(); ++i) { + ins_res.unwrap()->comments().push_back( + spacer.value().comments.at(i)); + } + if (spacer.value().newline_found) { + fmt.fmt = table_format::multiline_oneline; + if (spacer.value().indent_type != indent_char::none) { + fmt.indent_type = spacer.value().indent_type; + fmt.body_indent = spacer.value().indent; + } + } + } + } else { + skip_whitespace(loc, ctx); + } + + comma_found = character(',').scan(loc).is_ok(); + + if (spec.v1_1_0_allow_newlines_in_inline_tables) { + auto com_res = parse_comment_line(loc, ctx); + if (com_res.is_err()) { + ctx.report_error(com_res.unwrap_err()); + } + const bool comment_found = com_res.is_ok() && + com_res.unwrap().has_value(); + if (comment_found) { + fmt.fmt = table_format::multiline_oneline; + ins_res.unwrap()->comments().push_back(com_res.unwrap().value()); + } + if (comma_found) { + spacer = skip_multiline_spacer(loc, ctx, comment_found); + if (spacer.has_value() && spacer.value().newline_found) { + fmt.fmt = table_format::multiline_oneline; + } + } + } else { + skip_whitespace(loc, ctx); + } + } else { + ctx.report_error(std::move(kv_res.unwrap_err())); + while (!loc.eof()) { + if (loc.current() == '}') { + break; + } + if (!spec.v1_1_0_allow_newlines_in_inline_tables && + loc.current() == '\n') { + break; + } + loc.advance(); + } + break; + } + } + + if (loc.current() != '}') { + auto src = source_location(region(loc)); + return err(make_error_info("toml::parse_inline_table: " + "missing closing bracket `}`", + std::move(src), + "expected `}`, reached line end")); + } else { + loc.advance(); // skip } + } + + // any error reported from this function + if (num_errors < ctx.errors().size()) { + assert(ctx.has_error()); // already reported + return err(ctx.pop_last_error()); + } + + basic_value retval(std::move(table), std::move(fmt), {}, region(first, loc)); + + return ok(std::move(retval)); + } + + /* ============================================================================ + * _ + * __ ____ _| |_ _ ___ + * \ V / _` | | || / -_) + * \_/\__,_|_|\_,_\___| + */ + + template + result guess_number_type(const location& first, + const context& ctx) { + const auto& spec = ctx.toml_spec(); + location loc = first; + + if (syntax::offset_datetime(spec).scan(loc).is_ok()) { + return ok(value_t::offset_datetime); + } + loc = first; + + if (syntax::local_datetime(spec).scan(loc).is_ok()) { + const auto curr = loc.current(); + // if offset_datetime contains bad offset, it syntax::offset_datetime + // fails to scan it. + if (curr == '+' || curr == '-') { + return err( + make_syntax_error("bad offset: must be [+-]HH:MM or Z", + syntax::time_offset(spec), + loc, + std::string("Hint: valid : +09:00, -05:30\n" + "Hint: invalid: +9:00, -5:30\n"))); + } + return ok(value_t::local_datetime); + } + loc = first; + + if (syntax::local_date(spec).scan(loc).is_ok()) { + // bad time may appear after this. + + if (!loc.eof()) { + const auto c = loc.current(); + if (c == 'T' || c == 't') { + loc.advance(); + + return err(make_syntax_error( + "bad time: must be HH:MM:SS.subsec", + syntax::local_time(spec), + loc, + std::string( + "Hint: valid : 1979-05-27T07:32:00, 1979-05-27 " + "07:32:00.999999\n" + "Hint: invalid: 1979-05-27T7:32:00, 1979-05-27 17:32\n"))); + } + if (c == ' ') { + // A space is allowed as a delimiter between local time. + // But there is a case where bad time follows a space. + // - invalid: 2019-06-16 7:00:00 + // - valid : 2019-06-16 07:00:00 + loc.advance(); + if (!loc.eof() && ('0' <= loc.current() && loc.current() <= '9')) { + return err(make_syntax_error( + "bad time: must be HH:MM:SS.subsec", + syntax::local_time(spec), + loc, + std::string( + "Hint: valid : 1979-05-27T07:32:00, 1979-05-27 " + "07:32:00.999999\n" + "Hint: invalid: 1979-05-27T7:32:00, 1979-05-27 17:32\n"))); + } + } + if ('0' <= c && c <= '9') { + return err(make_syntax_error( + "bad datetime: missing T or space", + character_either { 'T', 't', ' ' }, + loc, + std::string( + "Hint: valid : 1979-05-27T07:32:00, 1979-05-27 " + "07:32:00.999999\n" + "Hint: invalid: 1979-05-27T7:32:00, 1979-05-27 17:32\n"))); + } + } + return ok(value_t::local_date); + } + loc = first; + + if (syntax::local_time(spec).scan(loc).is_ok()) { + return ok(value_t::local_time); + } + loc = first; + + if (syntax::floating(spec).scan(loc).is_ok()) { + if (!loc.eof() && loc.current() == '_') { + if (spec.ext_num_suffix && syntax::num_suffix(spec).scan(loc).is_ok()) { + return ok(value_t::floating); + } + auto src = source_location(region(loc)); + return err(make_error_info( + "bad float: `_` must be surrounded by digits", + std::move(src), + "invalid underscore", + "Hint: valid : +1.0, -2e-2, 3.141_592_653_589, inf, nan\n" + "Hint: invalid: .0, 1., _1.0, 1.0_, 1_.0, 1.0__0\n")); + } + return ok(value_t::floating); + } + loc = first; + + if (spec.ext_hex_float) { + if (syntax::hex_floating(spec).scan(loc).is_ok()) { + if (!loc.eof() && loc.current() == '_') { + if (spec.ext_num_suffix && syntax::num_suffix(spec).scan(loc).is_ok()) { + return ok(value_t::floating); + } + auto src = source_location(region(loc)); + return err(make_error_info( + "bad float: `_` must be surrounded by digits", + std::move(src), + "invalid underscore", + "Hint: valid : +1.0, -2e-2, 3.141_592_653_589, inf, nan\n" + "Hint: invalid: .0, 1., _1.0, 1.0_, 1_.0, 1.0__0\n")); + } + return ok(value_t::floating); + } + loc = first; + } + + if (auto int_reg = syntax::integer(spec).scan(loc)) { + if (!loc.eof()) { + const auto c = loc.current(); + if (c == '_') { + if (spec.ext_num_suffix && syntax::num_suffix(spec).scan(loc).is_ok()) { + return ok(value_t::integer); + } + + if (int_reg.length() <= 2 && + (int_reg.as_string() == "0" || int_reg.as_string() == "-0" || + int_reg.as_string() == "+0")) { + auto src = source_location(region(loc)); + return err(make_error_info( + "bad integer: leading zero is not allowed in decimal int", + std::move(src), + "leading zero", + "Hint: valid : -42, 1_000, 1_2_3_4_5, 0xC0FFEE, 0b0010, " + "0o755\n" + "Hint: invalid: _42, 1__000, 0123\n")); + } else { + auto src = source_location(region(loc)); + return err( + make_error_info("bad integer: `_` must be surrounded by digits", + std::move(src), + "invalid underscore", + "Hint: valid : -42, 1_000, 1_2_3_4_5, " + "0xC0FFEE, 0b0010, 0o755\n" + "Hint: invalid: _42, 1__000, 0123\n")); + } + } + if ('0' <= c && c <= '9') { + if (loc.current() == '0') { + loc.retrace(); + return err(make_error_info( + "bad integer: leading zero", + source_location(region(loc)), + "leading zero is not allowed", + std::string("Hint: valid : -42, 1_000, 1_2_3_4_5, 0xC0FFEE, " + "0b0010, 0o755\n" + "Hint: invalid: _42, 1__000, 0123\n"))); + } else // invalid digits, especially in oct/bin ints. + { + return err(make_error_info( + "bad integer: invalid digit after an integer", + source_location(region(loc)), + "this digit is not allowed", + std::string("Hint: valid : -42, 1_000, 1_2_3_4_5, 0xC0FFEE, " + "0b0010, 0o755\n" + "Hint: invalid: _42, 1__000, 0123\n"))); + } + } + if (c == ':' || c == '-') { + auto src = source_location(region(loc)); + return err(make_error_info( + "bad datetime: invalid format", + std::move(src), + "here", + std::string("Hint: valid : 1979-05-27T07:32:00-07:00, " + "1979-05-27 07:32:00.999999Z\n" + "Hint: invalid: 1979-05-27T7:32:00-7:00, 1979-05-27 " + "7:32-00:30"))); + } + if (c == '.' || c == 'e' || c == 'E') { + auto src = source_location(region(loc)); + return err(make_error_info( + "bad float: invalid format", + std::move(src), + "here", + std::string( + "Hint: valid : +1.0, -2e-2, 3.141_592_653_589, inf, nan\n" + "Hint: invalid: .0, 1., _1.0, 1.0_, 1_.0, 1.0__0\n"))); + } + } + return ok(value_t::integer); + } + if (!loc.eof() && loc.current() == '.') { + auto src = source_location(region(loc)); + return err(make_error_info( + "bad float: integer part is required before decimal point", + std::move(src), + "missing integer part", + std::string( + "Hint: valid : +1.0, -2e-2, 3.141_592_653_589, inf, nan\n" + "Hint: invalid: .0, 1., _1.0, 1.0_, 1_.0, 1.0__0\n"))); + } + if (!loc.eof() && loc.current() == '_') { + auto src = source_location(region(loc)); + return err(make_error_info( + "bad number: `_` must be surrounded by digits", + std::move(src), + "digits required before `_`", + std::string( + "Hint: valid : -42, 1_000, 1_2_3_4_5, 0xC0FFEE, 0b0010, 0o755\n" + "Hint: invalid: _42, 1__000, 0123\n"))); + } + + auto src = source_location(region(loc)); + return err(make_error_info("bad format: unknown value appeared", + std::move(src), + "here")); + } + + template + result guess_value_type(const location& loc, + const context& ctx) { + const auto& sp = ctx.toml_spec(); + location inner(loc); + + switch (loc.current()) { + case '"': { + return ok(value_t::string); + } + case '\'': { + return ok(value_t::string); + } + case '[': { + return ok(value_t::array); + } + case '{': { + return ok(value_t::table); + } + case 't': { + return ok(value_t::boolean); + } + case 'f': { + return ok(value_t::boolean); + } + case 'T': // invalid boolean. + { + return err(make_syntax_error("toml::parse_value: " + "`true` must be in lowercase. " + "A string must be surrounded by quotes.", + syntax::boolean(sp), + inner)); + } + case 'F': { + return err(make_syntax_error("toml::parse_value: " + "`false` must be in lowercase. " + "A string must be surrounded by quotes.", + syntax::boolean(sp), + inner)); + } + case 'i': // inf or string without quotes(syntax error). + { + if (literal("inf").scan(inner).is_ok()) { + return ok(value_t::floating); + } else { + return err( + make_syntax_error("toml::parse_value: " + "`inf` must be in lowercase. " + "A string must be surrounded by quotes.", + syntax::floating(sp), + inner)); + } + } + case 'I': // Inf or string without quotes(syntax error). + { + return err(make_syntax_error("toml::parse_value: " + "`inf` must be in lowercase. " + "A string must be surrounded by quotes.", + syntax::floating(sp), + inner)); + } + case 'n': // nan or null-extension + { + if (sp.ext_null_value) { + if (literal("nan").scan(inner).is_ok()) { + return ok(value_t::floating); + } else if (literal("null").scan(inner).is_ok()) { + return ok(value_t::empty); + } else { + return err( + make_syntax_error("toml::parse_value: " + "Both `nan` and `null` must be in lowercase. " + "A string must be surrounded by quotes.", + syntax::floating(sp), + inner)); + } + } else // must be nan. + { + if (literal("nan").scan(inner).is_ok()) { + return ok(value_t::floating); + } else { + return err( + make_syntax_error("toml::parse_value: " + "`nan` must be in lowercase. " + "A string must be surrounded by quotes.", + syntax::floating(sp), + inner)); + } + } + } + case 'N': // nan or null-extension + { + if (sp.ext_null_value) { + return err( + make_syntax_error("toml::parse_value: " + "Both `nan` and `null` must be in lowercase. " + "A string must be surrounded by quotes.", + syntax::floating(sp), + inner)); + } else { + return err( + make_syntax_error("toml::parse_value: " + "`nan` must be in lowercase. " + "A string must be surrounded by quotes.", + syntax::floating(sp), + inner)); + } + } + default: { + return guess_number_type(loc, ctx); + } + } + } + + template + result, error_info> parse_value(location& loc, + context& ctx) { + const auto ty_res = guess_value_type(loc, ctx); + if (ty_res.is_err()) { + return err(ty_res.unwrap_err()); + } + + switch (ty_res.unwrap()) { + case value_t::empty: { + if (ctx.toml_spec().ext_null_value) { + return parse_null(loc, ctx); + } else { + auto src = source_location(region(loc)); + return err( + make_error_info("toml::parse_value: unknown value appeared", + std::move(src), + "here")); + } + } + case value_t::boolean: { + return parse_boolean(loc, ctx); + } + case value_t::integer: { + return parse_integer(loc, ctx); + } + case value_t::floating: { + return parse_floating(loc, ctx); + } + case value_t::string: { + return parse_string(loc, ctx); + } + case value_t::offset_datetime: { + return parse_offset_datetime(loc, ctx); + } + case value_t::local_datetime: { + return parse_local_datetime(loc, ctx); + } + case value_t::local_date: { + return parse_local_date(loc, ctx); + } + case value_t::local_time: { + return parse_local_time(loc, ctx); + } + case value_t::array: { + return parse_array(loc, ctx); + } + case value_t::table: { + return parse_inline_table(loc, ctx); + } + default: { + auto src = source_location(region(loc)); + return err( + make_error_info("toml::parse_value: unknown value appeared", + std::move(src), + "here")); + } + } + } + + /* ============================================================================ + * _____ _ _ + * |_ _|_ _| |__| |___ + * | |/ _` | '_ \ / -_) + * |_|\__,_|_.__/_\___| + */ + + template + result::key_type>, region>, error_info> + parse_table_key(location& loc, context& ctx) { + const auto first = loc; + const auto& spec = ctx.toml_spec(); + + auto reg = syntax::std_table(spec).scan(loc); + if (!reg.is_ok()) { + return err(make_syntax_error("toml::parse_table_key: invalid table key", + syntax::std_table(spec), + loc)); + } + + loc = first; + loc.advance(); // skip [ + skip_whitespace(loc, ctx); + + auto keys_res = parse_key(loc, ctx); + if (keys_res.is_err()) { + return err(std::move(keys_res.unwrap_err())); + } + + skip_whitespace(loc, ctx); + loc.advance(); // ] + + return ok(std::make_pair(std::move(keys_res.unwrap().first), std::move(reg))); + } + + template + result::key_type>, region>, error_info> + parse_array_table_key(location& loc, context& ctx) { + const auto first = loc; + const auto& spec = ctx.toml_spec(); + + auto reg = syntax::array_table(spec).scan(loc); + if (!reg.is_ok()) { + return err(make_syntax_error( + "toml::parse_array_table_key: invalid array-of-tables key", + syntax::array_table(spec), + loc)); + } + + loc = first; + loc.advance(); // [ + loc.advance(); // [ + skip_whitespace(loc, ctx); + + auto keys_res = parse_key(loc, ctx); + if (keys_res.is_err()) { + return err(std::move(keys_res.unwrap_err())); + } + + skip_whitespace(loc, ctx); + loc.advance(); // ] + loc.advance(); // ] + + return ok(std::make_pair(std::move(keys_res.unwrap().first), std::move(reg))); + } + + // called after reading [table.keys] and comments around it. + // Since table may already contain a subtable ([x.y.z] can be defined before + // [x]), the table that is being parsed is passed as an argument. + template + result parse_table(location& loc, + context& ctx, + basic_value& table) { + assert(table.is_table()); + + const auto num_errors = ctx.errors().size(); + const auto& spec = ctx.toml_spec(); + + // clear indent info + table.as_table_fmt().indent_type = indent_char::none; + + bool newline_found = true; + while (!loc.eof()) { + const auto start = loc; + + auto sp = skip_multiline_spacer(loc, ctx, newline_found); + + // if reached to EOF, the table ends here. return. + if (loc.eof()) { + break; + } + // if next table is comming, return. + if (sequence(syntax::ws(spec), character('[')).scan(loc).is_ok()) { + loc = start; + break; + } + // otherwise, it should be a key-value pair. + newline_found = newline_found || + (sp.has_value() && sp.value().newline_found); + if (!newline_found) { + return err(make_error_info("toml::parse_table: " + "newline (LF / CRLF) or EOF is expected", + source_location(region(loc)), + "here")); + } + if (sp.has_value() && sp.value().indent_type != indent_char::none) { + table.as_table_fmt().indent_type = sp.value().indent_type; + table.as_table_fmt().body_indent = sp.value().indent; + } + + newline_found = false; // reset + if (auto kv_res = parse_key_value_pair(loc, ctx)) { + auto keys = std::move(kv_res.unwrap().first.first); + auto key_reg = std::move(kv_res.unwrap().first.second); + auto val = std::move(kv_res.unwrap().second); + + if (sp.has_value()) { + for (const auto& com : sp.value().comments) { + val.comments().push_back(com); + } + } + + if (auto com_res = parse_comment_line(loc, ctx)) { + if (auto com_opt = com_res.unwrap()) { + val.comments().push_back(com_opt.value()); + newline_found = true; // comment includes newline at the end + } + } else { + ctx.report_error(std::move(com_res.unwrap_err())); + } + + auto ins_res = insert_value(inserting_value_kind::dotted_keys, + std::addressof(table.as_table()), + keys, + std::move(key_reg), + std::move(val)); + if (ins_res.is_err()) { + ctx.report_error(std::move(ins_res.unwrap_err())); + } + } else { + ctx.report_error(std::move(kv_res.unwrap_err())); + skip_key_value_pair(loc, ctx); + } + } + + if (num_errors < ctx.errors().size()) { + assert(ctx.has_error()); // already reported + return err(ctx.pop_last_error()); + } + return ok(); + } + + template + result, std::vector> parse_file(location& loc, + context& ctx) { + using value_type = basic_value; + using table_type = typename value_type::table_type; + + const auto first = loc; + const auto& spec = ctx.toml_spec(); + + if (loc.eof()) { + return ok(value_type(table_type(), table_format_info {}, {}, region(loc))); + } + + value_type root(table_type(), table_format_info {}, {}, region(loc)); + root.as_table_fmt().fmt = table_format::multiline; + root.as_table_fmt().indent_type = indent_char::none; + + // parse top comment. + // + // ```toml + // # this is a comment for the top-level table. + // + // key = "the first value" + // ``` + // + // ```toml + // # this is a comment for "the first value". + // key = "the first value" + // ``` + while (!loc.eof()) { + if (auto com_res = parse_comment_line(loc, ctx)) { + if (auto com_opt = com_res.unwrap()) { + root.comments().push_back(std::move(com_opt.value())); + } else // no comment found. + { + // if it is not an empty line, clear the root comment. + if (!sequence(syntax::ws(spec), syntax::newline(spec)).scan(loc).is_ok()) { + loc = first; + root.comments().clear(); + } + break; + } + } else { + ctx.report_error(std::move(com_res.unwrap_err())); + skip_comment_block(loc, ctx); + } + } + + // parse root table + { + const auto res = parse_table(loc, ctx, root); + if (res.is_err()) { + ctx.report_error(std::move(res.unwrap_err())); + skip_until_next_table(loc, ctx); + } + } + + // parse tables + + while (!loc.eof()) { + auto sp = skip_multiline_spacer(loc, ctx, /*newline_found=*/true); + + if (auto key_res = parse_array_table_key(loc, ctx)) { + auto key = std::move(std::get<0>(key_res.unwrap())); + auto reg = std::move(std::get<1>(key_res.unwrap())); + + std::vector com; + if (sp.has_value()) { + for (std::size_t i = 0; i < sp.value().comments.size(); ++i) { + com.push_back(std::move(sp.value().comments.at(i))); + } + } + + // [table.def] must be followed by one of + // - a comment line + // - whitespace + newline + // - EOF + if (auto com_res = parse_comment_line(loc, ctx)) { + if (auto com_opt = com_res.unwrap()) { + com.push_back(com_opt.value()); + } else // if there is no comment, ws+newline must exist (or EOF) + { + skip_whitespace(loc, ctx); + if (!loc.eof() && + !syntax::newline(ctx.toml_spec()).scan(loc).is_ok()) { + ctx.report_error(make_syntax_error("toml::parse_file: " + "newline (or EOF) expected", + syntax::newline(ctx.toml_spec()), + loc)); + skip_until_next_table(loc, ctx); + continue; + } + } + } else // comment syntax error (rare) + { + ctx.report_error(com_res.unwrap_err()); + skip_until_next_table(loc, ctx); + continue; + } + + table_format_info fmt; + fmt.fmt = table_format::multiline; + fmt.indent_type = indent_char::none; + auto tab = value_type(table_type {}, std::move(fmt), std::move(com), reg); + + auto inserted = insert_value(inserting_value_kind::array_table, + std::addressof(root.as_table()), + key, + std::move(reg), + std::move(tab)); + + if (inserted.is_err()) { + ctx.report_error(inserted.unwrap_err()); + + // check errors in the table + auto tmp = basic_value(table_type()); + auto res = parse_table(loc, ctx, tmp); + if (res.is_err()) { + ctx.report_error(res.unwrap_err()); + skip_until_next_table(loc, ctx); + } + continue; + } + + auto tab_ptr = inserted.unwrap(); + assert(tab_ptr); + + const auto tab_res = parse_table(loc, ctx, *tab_ptr); + if (tab_res.is_err()) { + ctx.report_error(tab_res.unwrap_err()); + skip_until_next_table(loc, ctx); + } + + // parse_table first clears `indent_type`. + // to keep header indent info, we must store it later. + if (sp.has_value() && sp.value().indent_type != indent_char::none) { + tab_ptr->as_table_fmt().indent_type = sp.value().indent_type; + tab_ptr->as_table_fmt().name_indent = sp.value().indent; + } + continue; + } + if (auto key_res = parse_table_key(loc, ctx)) { + auto key = std::move(std::get<0>(key_res.unwrap())); + auto reg = std::move(std::get<1>(key_res.unwrap())); + + std::vector com; + if (sp.has_value()) { + for (std::size_t i = 0; i < sp.value().comments.size(); ++i) { + com.push_back(std::move(sp.value().comments.at(i))); + } + } + + // [table.def] must be followed by one of + // - a comment line + // - whitespace + newline + // - EOF + if (auto com_res = parse_comment_line(loc, ctx)) { + if (auto com_opt = com_res.unwrap()) { + com.push_back(com_opt.value()); + } else // if there is no comment, ws+newline must exist (or EOF) + { + skip_whitespace(loc, ctx); + if (!loc.eof() && + !syntax::newline(ctx.toml_spec()).scan(loc).is_ok()) { + ctx.report_error(make_syntax_error("toml::parse_file: " + "newline (or EOF) expected", + syntax::newline(ctx.toml_spec()), + loc)); + skip_until_next_table(loc, ctx); + continue; + } + } + } else // comment syntax error (rare) + { + ctx.report_error(com_res.unwrap_err()); + skip_until_next_table(loc, ctx); + continue; + } + + table_format_info fmt; + fmt.fmt = table_format::multiline; + fmt.indent_type = indent_char::none; + auto tab = value_type(table_type {}, std::move(fmt), std::move(com), reg); + + auto inserted = insert_value(inserting_value_kind::std_table, + std::addressof(root.as_table()), + key, + std::move(reg), + std::move(tab)); + + if (inserted.is_err()) { + ctx.report_error(inserted.unwrap_err()); + + // check errors in the table + auto tmp = basic_value(table_type()); + auto res = parse_table(loc, ctx, tmp); + if (res.is_err()) { + ctx.report_error(res.unwrap_err()); + skip_until_next_table(loc, ctx); + } + continue; + } + + auto tab_ptr = inserted.unwrap(); + assert(tab_ptr); + + const auto tab_res = parse_table(loc, ctx, *tab_ptr); + if (tab_res.is_err()) { + ctx.report_error(tab_res.unwrap_err()); + skip_until_next_table(loc, ctx); + } + if (sp.has_value() && sp.value().indent_type != indent_char::none) { + tab_ptr->as_table_fmt().indent_type = sp.value().indent_type; + tab_ptr->as_table_fmt().name_indent = sp.value().indent; + } + continue; + } + + // does not match array_table nor std_table. report an error. + const auto keytop = loc; + const auto maybe_array_of_tables = literal("[[").scan(loc).is_ok(); + loc = keytop; + + if (maybe_array_of_tables) { + ctx.report_error( + make_syntax_error("toml::parse_file: invalid array-table key", + syntax::array_table(spec), + loc)); + } else { + ctx.report_error( + make_syntax_error("toml::parse_file: invalid table key", + syntax::std_table(spec), + loc)); + } + skip_until_next_table(loc, ctx); + } + + if (!ctx.errors().empty()) { + return err(std::move(ctx.errors())); + } + return ok(std::move(root)); + } + + template + result, std::vector> parse_impl( + std::vector cs, + std::string fname, + const spec& s) { + using value_type = basic_value; + using table_type = typename value_type::table_type; + + // an empty file is a valid toml file. + if (cs.empty()) { + auto src = std::make_shared>( + std::move(cs)); + location loc(std::move(src), std::move(fname)); + return ok(value_type(table_type(), + table_format_info {}, + std::vector {}, + region(loc))); + } + + // to simplify parser, add newline at the end if there is no LF. + // But, if it has raw CR, the file is invalid (in TOML, CR is not a valid + // newline char). if it ends with CR, do not add LF and report it. + if (cs.back() != '\n' && cs.back() != '\r') { + cs.push_back('\n'); + } + + auto src = std::make_shared>(std::move(cs)); + + location loc(std::move(src), std::move(fname)); + + // skip BOM if found + if (loc.source()->size() >= 3) { + auto first = loc.get_location(); + + const auto c0 = loc.current(); + loc.advance(); + const auto c1 = loc.current(); + loc.advance(); + const auto c2 = loc.current(); + loc.advance(); + + const auto bom_found = (c0 == 0xEF) && (c1 == 0xBB) && (c2 == 0xBF); + if (!bom_found) { + loc.set_location(first); + } + } + + context ctx(s); + + return parse_file(loc, ctx); + } + + } // namespace detail + + // ----------------------------------------------------------------------------- + // parse(byte array) + + template + result, std::vector> try_parse( + std::vector content, + std::string filename, + spec s = spec::default_version()) { + return detail::parse_impl(std::move(content), + std::move(filename), + std::move(s)); + } + + template + basic_value parse(std::vector content, + std::string filename, + spec s = spec::default_version()) { + auto res = try_parse(std::move(content), std::move(filename), std::move(s)); + if (res.is_ok()) { + return res.unwrap(); + } else { + std::string msg; + for (const auto& err : res.unwrap_err()) { + msg += format_error(err); + } + throw syntax_error(std::move(msg), std::move(res.unwrap_err())); + } + } + + // ----------------------------------------------------------------------------- + // parse(istream) + + template + result, std::vector> try_parse( + std::istream& is, + std::string fname = "unknown file", + spec s = spec::default_version()) { + const auto beg = is.tellg(); + is.seekg(0, std::ios::end); + const auto end = is.tellg(); + const auto fsize = end - beg; + is.seekg(beg); + + // read whole file as a sequence of char + assert(fsize >= 0); + std::vector letters(static_cast(fsize), + '\0'); + is.read(reinterpret_cast(letters.data()), + static_cast(fsize)); + + return detail::parse_impl(std::move(letters), + std::move(fname), + std::move(s)); + } + + template + basic_value parse(std::istream& is, + std::string fname = "unknown file", + spec s = spec::default_version()) { + auto res = try_parse(is, std::move(fname), std::move(s)); + if (res.is_ok()) { + return res.unwrap(); + } else { + std::string msg; + for (const auto& err : res.unwrap_err()) { + msg += format_error(err); + } + throw syntax_error(std::move(msg), std::move(res.unwrap_err())); + } + } + + // ----------------------------------------------------------------------------- + // parse(filename) + + template + result, std::vector> try_parse( + std::string fname, + spec s = spec::default_version()) { + std::ifstream ifs(fname, std::ios_base::binary); + if (!ifs.good()) { + std::vector e; + e.push_back( + error_info("toml::parse: Error opening file \"" + fname + "\"", {})); + return err(std::move(e)); + } + ifs.exceptions(std::ifstream::failbit | std::ifstream::badbit); + + return try_parse(ifs, std::move(fname), std::move(s)); + } + + template + basic_value parse(std::string fname, spec s = spec::default_version()) { + std::ifstream ifs(fname, std::ios_base::binary); + if (!ifs.good()) { + throw file_io_error("toml::parse: error opening file", fname); + } + ifs.exceptions(std::ifstream::failbit | std::ifstream::badbit); + + return parse(ifs, std::move(fname), std::move(s)); + } + + template + result, std::vector> try_parse( + const char (&fname)[N], + spec s = spec::default_version()) { + return try_parse(std::string(fname), std::move(s)); + } + + template + basic_value parse(const char (&fname)[N], spec s = spec::default_version()) { + return parse(std::string(fname), std::move(s)); + } + + // ---------------------------------------------------------------------------- + // parse_str + + template + result, std::vector> try_parse_str( + std::string content, + spec s = spec::default_version(), + cxx::source_location loc = cxx::source_location::current()) { + std::istringstream iss(std::move(content)); + std::string name("internal string" + cxx::to_string(loc)); + return try_parse(iss, std::move(name), std::move(s)); + } + + template + basic_value parse_str( + std::string content, + spec s = spec::default_version(), + cxx::source_location loc = cxx::source_location::current()) { + auto res = try_parse_str(std::move(content), std::move(s), std::move(loc)); + if (res.is_ok()) { + return res.unwrap(); + } else { + std::string msg; + for (const auto& err : res.unwrap_err()) { + msg += format_error(err); + } + throw syntax_error(std::move(msg), std::move(res.unwrap_err())); + } + } + + // ---------------------------------------------------------------------------- + // filesystem + +#if defined(TOML11_HAS_FILESYSTEM) + + template + cxx::enable_if_t::value, + result, std::vector>> + try_parse(const FSPATH& fpath, spec s = spec::default_version()) { + std::ifstream ifs(fpath, std::ios_base::binary); + if (!ifs.good()) { + std::vector e; + e.push_back( + error_info("toml::parse: Error opening file \"" + fpath.string() + "\"", + {})); + return err(std::move(e)); + } + ifs.exceptions(std::ifstream::failbit | std::ifstream::badbit); + + return try_parse(ifs, fpath.string(), std::move(s)); + } + + template + cxx::enable_if_t::value, basic_value> + parse(const FSPATH& fpath, spec s = spec::default_version()) { + std::ifstream ifs(fpath, std::ios_base::binary); + if (!ifs.good()) { + throw file_io_error("toml::parse: error opening file", fpath.string()); + } + ifs.exceptions(std::ifstream::failbit | std::ifstream::badbit); + + return parse(ifs, fpath.string(), std::move(s)); + } +#endif + + // ----------------------------------------------------------------------------- + // FILE* + + template + result, std::vector> try_parse( + FILE* fp, + std::string filename, + spec s = spec::default_version()) { + const long beg = std::ftell(fp); + if (beg == -1L) { + return err(std::vector { + error_info(std::string("Failed to access: \"") + filename + + "\", errno = " + std::to_string(errno), + {}) }); + } + + const int res_seekend = std::fseek(fp, 0, SEEK_END); + if (res_seekend != 0) { + return err(std::vector { + error_info(std::string("Failed to seek: \"") + filename + + "\", errno = " + std::to_string(errno), + {}) }); + } + + const long end = std::ftell(fp); + if (end == -1L) { + return err(std::vector { + error_info(std::string("Failed to access: \"") + filename + + "\", errno = " + std::to_string(errno), + {}) }); + } + + const auto fsize = end - beg; + + const auto res_seekbeg = std::fseek(fp, beg, SEEK_SET); + if (res_seekbeg != 0) { + return err(std::vector { + error_info(std::string("Failed to seek: \"") + filename + + "\", errno = " + std::to_string(errno), + {}) }); + } + + // read whole file as a sequence of char + assert(fsize >= 0); + std::vector letters( + static_cast(fsize)); + const auto actual = std::fread(letters.data(), + sizeof(char), + static_cast(fsize), + fp); + if (actual != static_cast(fsize)) { + return err(std::vector { + error_info(std::string("File size changed: \"") + filename + + std::string("\" make sure that FILE* is in binary mode " + "to avoid LF <-> CRLF conversion"), + {}) }); + } + + return detail::parse_impl(std::move(letters), + std::move(filename), + std::move(s)); + } + + template + basic_value parse(FILE* fp, + std::string filename, + spec s = spec::default_version()) { + const long beg = std::ftell(fp); + if (beg == -1L) { + throw file_io_error(errno, "Failed to access", filename); + } + + const int res_seekend = std::fseek(fp, 0, SEEK_END); + if (res_seekend != 0) { + throw file_io_error(errno, "Failed to seek", filename); + } + + const long end = std::ftell(fp); + if (end == -1L) { + throw file_io_error(errno, "Failed to access", filename); + } + + const auto fsize = end - beg; + + const auto res_seekbeg = std::fseek(fp, beg, SEEK_SET); + if (res_seekbeg != 0) { + throw file_io_error(errno, "Failed to seek", filename); + } + + // read whole file as a sequence of char + assert(fsize >= 0); + std::vector letters( + static_cast(fsize)); + const auto actual = std::fread(letters.data(), + sizeof(char), + static_cast(fsize), + fp); + if (actual != static_cast(fsize)) { + throw file_io_error( + errno, + "File size changed; make sure that " + "FILE* is in binary mode to avoid LF <-> CRLF conversion", + filename); + } + + auto res = detail::parse_impl(std::move(letters), + std::move(filename), + std::move(s)); + if (res.is_ok()) { + return res.unwrap(); + } else { + std::string msg; + for (const auto& err : res.unwrap_err()) { + msg += format_error(err); + } + throw syntax_error(std::move(msg), std::move(res.unwrap_err())); + } + } + +} // namespace toml + +#if defined(TOML11_COMPILE_SOURCES) +namespace toml { + struct type_config; + struct ordered_type_config; + + extern template result, std::vector> + try_parse(std::vector, std::string, spec); + extern template result, std::vector> + try_parse(std::istream&, std::string, spec); + extern template result, std::vector> + try_parse(std::string, spec); + extern template result, std::vector> + try_parse(FILE*, std::string, spec); + extern template result, std::vector> + try_parse_str(std::string, spec, cxx::source_location); + + extern template basic_value parse( + std::vector, + std::string, + spec); + extern template basic_value parse(std::istream&, + std::string, + spec); + extern template basic_value parse(std::string, spec); + extern template basic_value parse(FILE*, + std::string, + spec); + extern template basic_value parse_str( + std::string, + spec, + cxx::source_location); + + extern template result, std::vector> + try_parse(std::vector, std::string, spec); + extern template result, std::vector> + try_parse(std::istream&, std::string, spec); + extern template result, std::vector> + try_parse(std::string, spec); + extern template result, std::vector> + try_parse(FILE*, std::string, spec); + extern template result, std::vector> + try_parse_str(std::string, spec, cxx::source_location); + + extern template basic_value parse( + std::vector, + std::string, + spec); + extern template basic_value parse( + std::istream&, + std::string, + spec); + extern template basic_value parse( + std::string, + spec); + extern template basic_value parse( + FILE*, + std::string, + spec); + extern template basic_value parse_str( + std::string, + spec, + cxx::source_location); + + #if defined(TOML11_HAS_FILESYSTEM) + extern template cxx::enable_if_t< + std::is_same::value, + result, std::vector>> + try_parse(const std::filesystem::path&, + spec); + extern template cxx::enable_if_t< + std::is_same::value, + result, std::vector>> + try_parse( + const std::filesystem::path&, + spec); + extern template cxx::enable_if_t< + std::is_same::value, + basic_value> + parse(const std::filesystem::path&, spec); + extern template cxx::enable_if_t< + std::is_same::value, + basic_value> + parse(const std::filesystem::path&, + spec); + #endif // filesystem + +} // namespace toml +#endif // TOML11_COMPILE_SOURCES + +#endif // TOML11_PARSER_HPP +#ifndef TOML11_LITERAL_HPP +#define TOML11_LITERAL_HPP + +#ifndef TOML11_LITERAL_FWD_HPP + #define TOML11_LITERAL_FWD_HPP + +namespace toml { + + namespace detail { + // implementation + ::toml::value literal_internal_impl(location loc); + } // namespace detail + + inline namespace literals { + inline namespace toml_literals { + + ::toml::value operator"" _toml(const char* str, std::size_t len); + + #if defined(TOML11_HAS_CHAR8_T) + // value of u8"" literal has been changed from char to char8_t and char8_t + // is NOT compatible to char + ::toml::value operator"" _toml(const char8_t* str, std::size_t len); + #endif + + } // namespace toml_literals + } // namespace literals +} // namespace toml +#endif // TOML11_LITERAL_FWD_HPP + +#if !defined(TOML11_COMPILE_SOURCES) + #ifndef TOML11_LITERAL_IMPL_HPP + #define TOML11_LITERAL_IMPL_HPP + +namespace toml { + + namespace detail { + // implementation + TOML11_INLINE ::toml::value literal_internal_impl(location loc) { + const auto s = ::toml::spec::default_version(); + context ctx(s); + + const auto front = loc; + + // ------------------------------------------------------------------------ + // check if it is a raw value. + + // skip empty lines and comment lines + auto sp = skip_multiline_spacer(loc, ctx); + if (loc.eof()) { + ::toml::value val; + if (sp.has_value()) { + for (std::size_t i = 0; i < sp.value().comments.size(); ++i) { + val.comments().push_back(std::move(sp.value().comments.at(i))); + } + } + return val; + } + + // to distinguish arrays and tables, first check it is a table or not. + // + // "[1,2,3]"_toml; // json: [1, 2, 3] + // "[table]"_toml; // json: {"table": {}} + // "[[1,2,3]]"_toml; // json: [[1, 2, 3]] + // "[[table]]"_toml; // json: {"table": [{}]} + // + // "[[1]]"_toml; // json: {"1": [{}]} + // "1 = [{}]"_toml; // json: {"1": [{}]} + // "[[1,]]"_toml; // json: [[1]] + // "[[1],]"_toml; // json: [[1]] + const auto val_start = loc; + + const bool is_table_key = syntax::std_table(s).scan(loc).is_ok(); + loc = val_start; + const bool is_aots_key = syntax::array_table(s).scan(loc).is_ok(); + loc = val_start; + + // If it is neither a table-key or a array-of-table-key, it may be a value. + if (!is_table_key && !is_aots_key) { + auto data = parse_value(loc, ctx); + if (data.is_ok()) { + auto val = std::move(data.unwrap()); + if (sp.has_value()) { + for (std::size_t i = 0; i < sp.value().comments.size(); ++i) { + val.comments().push_back(std::move(sp.value().comments.at(i))); + } + } + auto com_res = parse_comment_line(loc, ctx); + if (com_res.is_ok() && com_res.unwrap().has_value()) { + val.comments().push_back(com_res.unwrap().value()); + } + return val; + } + } + + // ------------------------------------------------------------------------- + // Note that still it can be a table, because the literal might be + // something like the following. + // ```cpp + // // c++11 raw-string literal + // const auto val = R"( + // key = "value" + // int = 42 + // )"_toml; + // ``` + // It is a valid toml file. + // It should be parsed as if we parse a file with this content. + + loc = front; + auto data = parse_file(loc, ctx); + if (data.is_ok()) { + return data.unwrap(); + } else // not a value && not a file. error. + { + std::string msg; + for (const auto& err : data.unwrap_err()) { + msg += format_error(err); + } + throw ::toml::syntax_error(std::move(msg), std::move(data.unwrap_err())); + } + } + + } // namespace detail + + inline namespace literals { + inline namespace toml_literals { + + TOML11_INLINE ::toml::value operator"" _toml(const char* str, + std::size_t len) { + if (len == 0) { + return ::toml::value {}; + } + + ::toml::detail::location::container_type c(len); + std::copy( + reinterpret_cast(str), + reinterpret_cast(str + len), + c.begin()); + if (!c.empty() && c.back()) { + c.push_back('\n'); // to make it easy to parse comment, we add newline + } + + return literal_internal_impl(::toml::detail::location( + std::make_shared( + std::move(c)), + "TOML literal encoded in a C++ code")); + } + + #if defined(__cpp_char8_t) + #if __cpp_char8_t >= 201811L + #define TOML11_HAS_CHAR8_T 1 + #endif + #endif + + #if defined(TOML11_HAS_CHAR8_T) + // value of u8"" literal has been changed from char to char8_t and char8_t + // is NOT compatible to char + TOML11_INLINE ::toml::value operator"" _toml(const char8_t* str, + std::size_t len) { + if (len == 0) { + return ::toml::value {}; + } + + ::toml::detail::location::container_type c(len); + std::copy( + reinterpret_cast(str), + reinterpret_cast(str + len), + c.begin()); + if (!c.empty() && c.back()) { + c.push_back('\n'); // to make it easy to parse comment, we add newline + } + + return literal_internal_impl(::toml::detail::location( + std::make_shared( + std::move(c)), + "TOML literal encoded in a C++ code")); + } + #endif + + } // namespace toml_literals + } // namespace literals +} // namespace toml + #endif // TOML11_LITERAL_IMPL_HPP +#endif + +#endif // TOML11_LITERAL_HPP +#ifndef TOML11_SERIALIZER_HPP +#define TOML11_SERIALIZER_HPP + +#include +#include +#include +#include +#include + +namespace toml { + + struct serialization_error final : public ::toml::exception { + public: + explicit serialization_error(std::string what_arg, source_location loc) + : what_(std::move(what_arg)) + , loc_(std::move(loc)) {} + + ~serialization_error() noexcept override = default; + + const char* what() const noexcept override { + return what_.c_str(); + } + + const source_location& location() const noexcept { + return loc_; + } + + private: + std::string what_; + source_location loc_; + }; + + namespace detail { + template + class serializer { + public: + using value_type = basic_value; + + using key_type = typename value_type::key_type; + using comment_type = typename value_type::comment_type; + using boolean_type = typename value_type::boolean_type; + using integer_type = typename value_type::integer_type; + using floating_type = typename value_type::floating_type; + using string_type = typename value_type::string_type; + using local_time_type = typename value_type::local_time_type; + using local_date_type = typename value_type::local_date_type; + using local_datetime_type = typename value_type::local_datetime_type; + using offset_datetime_type = typename value_type::offset_datetime_type; + using array_type = typename value_type::array_type; + using table_type = typename value_type::table_type; + + using char_type = typename string_type::value_type; + + public: + explicit serializer(const spec& sp) + : spec_(sp) + , force_inline_(false) + , current_indent_(0) {} + + string_type operator()(const std::vector& ks, const value_type& v) { + for (const auto& k : ks) { + this->keys_.push_back(k); + } + return (*this)(v); + } + + string_type operator()(const key_type& k, const value_type& v) { + this->keys_.push_back(k); + return (*this)(v); + } + + string_type operator()(const value_type& v) { + switch (v.type()) { + case value_t::boolean: { + return (*this)(v.as_boolean(), v.as_boolean_fmt(), v.location()); + } + case value_t::integer: { + return (*this)(v.as_integer(), v.as_integer_fmt(), v.location()); + } + case value_t::floating: { + return (*this)(v.as_floating(), v.as_floating_fmt(), v.location()); + } + case value_t::string: { + return (*this)(v.as_string(), v.as_string_fmt(), v.location()); + } + case value_t::offset_datetime: { + return (*this)(v.as_offset_datetime(), + v.as_offset_datetime_fmt(), + v.location()); + } + case value_t::local_datetime: { + return (*this)(v.as_local_datetime(), + v.as_local_datetime_fmt(), + v.location()); + } + case value_t::local_date: { + return (*this)(v.as_local_date(), v.as_local_date_fmt(), v.location()); + } + case value_t::local_time: { + return (*this)(v.as_local_time(), v.as_local_time_fmt(), v.location()); + } + case value_t::array: { + return ( + *this)(v.as_array(), v.as_array_fmt(), v.comments(), v.location()); + } + case value_t::table: { + string_type retval; + if (this->keys_.empty()) // it might be the root table. emit comments here. + { + retval += format_comments(v.comments(), v.as_table_fmt().indent_type); + } + if (!retval.empty()) // we have comment. + { + retval += char_type('\n'); + } + + retval += (*this)(v.as_table(), + v.as_table_fmt(), + v.comments(), + v.location()); + return retval; + } + case value_t::empty: { + if (this->spec_.ext_null_value) { + return string_conv("null"); + } + break; + } + default: { + break; + } + } + throw serialization_error( + format_error("[error] toml::serializer: toml::basic_value " + "does not have any valid type.", + v.location(), + "here"), + v.location()); + } + + private: + string_type operator()(const boolean_type& b, + const boolean_format_info&, + const source_location&) // {{{ + { + if (b) { + return string_conv("true"); + } else { + return string_conv("false"); + } + } // }}} + + string_type operator()(const integer_type i, + const integer_format_info& fmt, + const source_location& loc) // {{{ + { + std::ostringstream oss; + this->set_locale(oss); + + const auto insert_spacer = [&fmt](std::string s) -> std::string { + if (fmt.spacer == 0) { + return s; + } + + std::string sign; + if (!s.empty() && (s.at(0) == '+' || s.at(0) == '-')) { + sign += s.at(0); + s.erase(s.begin()); + } + + std::string spaced; + std::size_t counter = 0; + for (auto iter = s.rbegin(); iter != s.rend(); ++iter) { + if (counter != 0 && counter % fmt.spacer == 0) { + spaced += '_'; + } + spaced += *iter; + counter += 1; + } + if (!spaced.empty() && spaced.back() == '_') { + spaced.pop_back(); + } + + s.clear(); + std::copy(spaced.rbegin(), spaced.rend(), std::back_inserter(s)); + return sign + s; + }; + + std::string retval; + if (fmt.fmt == integer_format::dec) { + oss << std::setw(static_cast(fmt.width)) << std::dec << i; + retval = insert_spacer(oss.str()); + + if (this->spec_.ext_num_suffix && !fmt.suffix.empty()) { + retval += '_'; + retval += fmt.suffix; + } + } else { + if (i < 0) { + throw serialization_error( + format_error("binary, octal, hexadecimal " + "integer does not allow negative value", + loc, + "here"), + loc); + } + switch (fmt.fmt) { + case integer_format::hex: { + oss << std::noshowbase << std::setw(static_cast(fmt.width)) + << std::setfill('0') << std::hex; + if (fmt.uppercase) { + oss << std::uppercase; + } else { + oss << std::nouppercase; + } + oss << i; + retval = std::string("0x") + insert_spacer(oss.str()); + break; + } + case integer_format::oct: { + oss << std::setw(static_cast(fmt.width)) << std::setfill('0') + << std::oct << i; + retval = std::string("0o") + insert_spacer(oss.str()); + break; + } + case integer_format::bin: { + integer_type x { i }; + std::string tmp; + std::size_t bits(0); + while (x != 0) { + if (fmt.spacer != 0) { + if (bits != 0 && (bits % fmt.spacer) == 0) { + tmp += '_'; + } + } + if (x % 2 == 1) { + tmp += '1'; + } else { + tmp += '0'; + } + x >>= 1; + bits += 1; + } + for (; bits < fmt.width; ++bits) { + if (fmt.spacer != 0) { + if (bits != 0 && (bits % fmt.spacer) == 0) { + tmp += '_'; + } + } + tmp += '0'; + } + for (auto iter = tmp.rbegin(); iter != tmp.rend(); ++iter) { + oss << *iter; + } + retval = std::string("0b") + oss.str(); + break; + } + default: { + throw serialization_error( + format_error("none of dec, hex, oct, bin: " + to_string(fmt.fmt), + loc, + "here"), + loc); + } + } + } + return string_conv(retval); + } // }}} + + string_type operator()(const floating_type f, + const floating_format_info& fmt, + const source_location&) // {{{ + { + using std::isinf; + using std::isnan; + using std::signbit; + + std::ostringstream oss; + this->set_locale(oss); + + if (isnan(f)) { + if (signbit(f)) { + oss << '-'; + } + oss << "nan"; + if (this->spec_.ext_num_suffix && !fmt.suffix.empty()) { + oss << '_'; + oss << fmt.suffix; + } + return string_conv(oss.str()); + } + + if (isinf(f)) { + if (signbit(f)) { + oss << '-'; + } + oss << "inf"; + if (this->spec_.ext_num_suffix && !fmt.suffix.empty()) { + oss << '_'; + oss << fmt.suffix; + } + return string_conv(oss.str()); + } + + switch (fmt.fmt) { + case floating_format::defaultfloat: { + if (fmt.prec != 0) { + oss << std::setprecision(static_cast(fmt.prec)); + } + oss << f; + // since defaultfloat may omit point, we need to add it + std::string s = oss.str(); + if (s.find('.') == std::string::npos && + s.find('e') == std::string::npos && + s.find('E') == std::string::npos) { + s += ".0"; + } + if (this->spec_.ext_num_suffix && !fmt.suffix.empty()) { + s += '_'; + s += fmt.suffix; + } + return string_conv(s); + } + case floating_format::fixed: { + if (fmt.prec != 0) { + oss << std::setprecision(static_cast(fmt.prec)); + } + oss << std::fixed << f; + if (this->spec_.ext_num_suffix && !fmt.suffix.empty()) { + oss << '_' << fmt.suffix; + } + return string_conv(oss.str()); + } + case floating_format::scientific: { + if (fmt.prec != 0) { + oss << std::setprecision(static_cast(fmt.prec)); + } + oss << std::scientific << f; + if (this->spec_.ext_num_suffix && !fmt.suffix.empty()) { + oss << '_' << fmt.suffix; + } + return string_conv(oss.str()); + } + case floating_format::hex: { + if (this->spec_.ext_hex_float) { + oss << std::hexfloat << f; + // suffix is only for decimal numbers. + return string_conv(oss.str()); + } else // no hex allowed. output with max precision. + { + oss << std::setprecision( + std::numeric_limits::max_digits10) + << std::scientific << f; + // suffix is only for decimal numbers. + return string_conv(oss.str()); + } + } + default: { + if (this->spec_.ext_num_suffix && !fmt.suffix.empty()) { + oss << '_' << fmt.suffix; + } + return string_conv(oss.str()); + } + } + } // }}} + + string_type operator()(string_type s, + const string_format_info& fmt, + const source_location& loc) // {{{ + { + string_type retval; + switch (fmt.fmt) { + case string_format::basic: { + retval += char_type('"'); + retval += this->escape_basic_string(s); + retval += char_type('"'); + return retval; + } + case string_format::literal: { + if (std::find(s.begin(), s.end(), char_type('\n')) != s.end()) { + throw serialization_error( + format_error( + "toml::serializer: " + "(non-multiline) literal string cannot have a newline", + loc, + "here"), + loc); + } + retval += char_type('\''); + retval += s; + retval += char_type('\''); + return retval; + } + case string_format::multiline_basic: { + retval += string_conv("\"\"\""); + if (fmt.start_with_newline) { + retval += char_type('\n'); + } + + retval += this->escape_ml_basic_string(s); + + retval += string_conv("\"\"\""); + return retval; + } + case string_format::multiline_literal: { + retval += string_conv("'''"); + if (fmt.start_with_newline) { + retval += char_type('\n'); + } + retval += s; + retval += string_conv("'''"); + return retval; + } + default: { + throw serialization_error( + format_error("[error] toml::serializer::operator()(string): " + "invalid string_format value", + loc, + "here"), + loc); + } + } + } // }}} + + string_type operator()(const local_date_type& d, + const local_date_format_info&, + const source_location&) // {{{ + { + std::ostringstream oss; + oss << d; + return string_conv(oss.str()); + } // }}} + + string_type operator()(const local_time_type& t, + const local_time_format_info& fmt, + const source_location&) // {{{ + { + return this->format_local_time(t, fmt.has_seconds, fmt.subsecond_precision); + } // }}} + + string_type operator()(const local_datetime_type& dt, + const local_datetime_format_info& fmt, + const source_location&) // {{{ + { + std::ostringstream oss; + oss << dt.date; + switch (fmt.delimiter) { + case datetime_delimiter_kind::upper_T: { + oss << 'T'; + break; + } + case datetime_delimiter_kind::lower_t: { + oss << 't'; + break; + } + case datetime_delimiter_kind::space: { + oss << ' '; + break; + } + default: { + oss << 'T'; + break; + } + } + return string_conv(oss.str()) + + this->format_local_time(dt.time, + fmt.has_seconds, + fmt.subsecond_precision); + } // }}} + + string_type operator()(const offset_datetime_type& odt, + const offset_datetime_format_info& fmt, + const source_location&) // {{{ + { + std::ostringstream oss; + oss << odt.date; + switch (fmt.delimiter) { + case datetime_delimiter_kind::upper_T: { + oss << 'T'; + break; + } + case datetime_delimiter_kind::lower_t: { + oss << 't'; + break; + } + case datetime_delimiter_kind::space: { + oss << ' '; + break; + } + default: { + oss << 'T'; + break; + } + } + oss << string_conv( + this->format_local_time(odt.time, fmt.has_seconds, fmt.subsecond_precision)); + oss << odt.offset; + return string_conv(oss.str()); + } // }}} + + string_type operator()(const array_type& a, + const array_format_info& fmt, + const comment_type& com, + const source_location& loc) // {{{ + { + array_format f = fmt.fmt; + if (fmt.fmt == array_format::default_format) { + // [[in.this.form]], you cannot add a comment to the array itself + // (but you can add a comment to each table). + // To keep comments, we need to avoid multiline array-of-tables + // if array itself has a comment. + if (!this->keys_.empty() && !a.empty() && com.empty() && + std::all_of(a.begin(), a.end(), [](const value_type& e) { + return e.is_table(); + })) { + f = array_format::array_of_tables; + } else { + f = array_format::oneline; + + // check if it becomes long + std::size_t approx_len = 0; + for (const auto& e : a) { + // have a comment. cannot be inlined + if (!e.comments().empty()) { + f = array_format::multiline; + break; + } + // possibly long types ... + if (e.is_array() || e.is_table() || e.is_offset_datetime() || + e.is_local_datetime()) { + f = array_format::multiline; + break; + } else if (e.is_boolean()) { + approx_len += + (*this)(e.as_boolean(), e.as_boolean_fmt(), e.location()).size(); + } else if (e.is_integer()) { + approx_len += + (*this)(e.as_integer(), e.as_integer_fmt(), e.location()).size(); + } else if (e.is_floating()) { + approx_len += + (*this)(e.as_floating(), e.as_floating_fmt(), e.location()).size(); + } else if (e.is_string()) { + if (e.as_string_fmt().fmt == string_format::multiline_basic || + e.as_string_fmt().fmt == string_format::multiline_literal) { + f = array_format::multiline; + break; + } + approx_len += + 2 + + (*this)(e.as_string(), e.as_string_fmt(), e.location()).size(); + } else if (e.is_local_date()) { + approx_len += 10; // 1234-56-78 + } else if (e.is_local_time()) { + approx_len += 15; // 12:34:56.789012 + } + + if (approx_len > 60) // key, ` = `, `[...]` < 80 + { + f = array_format::multiline; + break; + } + approx_len += 2; // `, ` + } + } + } + if (this->force_inline_ && f == array_format::array_of_tables) { + f = array_format::multiline; + } + if (a.empty() && f == array_format::array_of_tables) { + f = array_format::oneline; + } + + // -------------------------------------------------------------------- + + if (f == array_format::array_of_tables) { + if (this->keys_.empty()) { + throw serialization_error("array of table must have its key. " + "use format(key, v)", + loc); + } + string_type retval; + for (const auto& e : a) { + assert(e.is_table()); + + this->current_indent_ += e.as_table_fmt().name_indent; + retval += this->format_comments(e.comments(), + e.as_table_fmt().indent_type); + retval += this->format_indent(e.as_table_fmt().indent_type); + this->current_indent_ -= e.as_table_fmt().name_indent; + + retval += string_conv("[["); + retval += this->format_keys(this->keys_).value(); + retval += string_conv("]]\n"); + + retval += this->format_ml_table(e.as_table(), e.as_table_fmt()); + } + return retval; + } else if (f == array_format::oneline) { + // ignore comments. we cannot emit comments + string_type retval; + retval += char_type('['); + for (const auto& e : a) { + this->force_inline_ = true; + retval += (*this)(e); + retval += string_conv(", "); + } + if (!a.empty()) { + retval.pop_back(); // ` ` + retval.pop_back(); // `,` + } + retval += char_type(']'); + this->force_inline_ = false; + return retval; + } else { + assert(f == array_format::multiline); + + string_type retval; + retval += string_conv("[\n"); + + for (const auto& e : a) { + this->current_indent_ += fmt.body_indent; + retval += this->format_comments(e.comments(), fmt.indent_type); + retval += this->format_indent(fmt.indent_type); + this->current_indent_ -= fmt.body_indent; + + this->force_inline_ = true; + retval += (*this)(e); + retval += string_conv(",\n"); + } + this->force_inline_ = false; + + this->current_indent_ += fmt.closing_indent; + retval += this->format_indent(fmt.indent_type); + this->current_indent_ -= fmt.closing_indent; + + retval += char_type(']'); + return retval; + } + } // }}} + + string_type operator()(const table_type& t, + const table_format_info& fmt, + const comment_type& com, + const source_location& loc) // {{{ + { + if (this->force_inline_) { + if (fmt.fmt == table_format::multiline_oneline) { + return this->format_ml_inline_table(t, fmt); + } else { + return this->format_inline_table(t, fmt); + } + } else { + if (fmt.fmt == table_format::multiline) { + string_type retval; + // comment is emitted inside format_ml_table + if (auto k = this->format_keys(this->keys_)) { + this->current_indent_ += fmt.name_indent; + retval += this->format_comments(com, fmt.indent_type); + retval += this->format_indent(fmt.indent_type); + this->current_indent_ -= fmt.name_indent; + retval += char_type('['); + retval += k.value(); + retval += string_conv("]\n"); + } + // otherwise, its the root. + + retval += this->format_ml_table(t, fmt); + return retval; + } else if (fmt.fmt == table_format::oneline) { + return this->format_inline_table(t, fmt); + } else if (fmt.fmt == table_format::multiline_oneline) { + return this->format_ml_inline_table(t, fmt); + } else if (fmt.fmt == table_format::dotted) { + std::vector keys; + if (this->keys_.empty()) { + throw serialization_error( + format_error( + "toml::serializer: " + "dotted table must have its key. use format(key, v)", + loc, + "here"), + loc); + } + keys.push_back(this->keys_.back()); + + const auto retval = this->format_dotted_table(t, fmt, loc, keys); + keys.pop_back(); + return retval; + } else { + assert(fmt.fmt == table_format::implicit); + + string_type retval; + for (const auto& kv : t) { + const auto& k = kv.first; + const auto& v = kv.second; + + if (!v.is_table() && !v.is_array_of_tables()) { + throw serialization_error( + format_error("toml::serializer: " + "an implicit table cannot have non-table value.", + v.location(), + "here"), + v.location()); + } + if (v.is_table()) { + if (v.as_table_fmt().fmt != table_format::multiline && + v.as_table_fmt().fmt != table_format::implicit) { + throw serialization_error( + format_error( + "toml::serializer: " + "an implicit table cannot have non-multiline table", + v.location(), + "here"), + v.location()); + } + } else { + assert(v.is_array()); + for (const auto& e : v.as_array()) { + if (e.as_table_fmt().fmt != table_format::multiline && + v.as_table_fmt().fmt != table_format::implicit) { + throw serialization_error( + format_error( + "toml::serializer: " + "an implicit table cannot have non-multiline table", + e.location(), + "here"), + e.location()); + } + } + } + + keys_.push_back(k); + retval += (*this)(v); + keys_.pop_back(); + } + return retval; + } + } + } // }}} + + private: + string_type escape_basic_string(const string_type& s) const // {{{ + { + string_type retval; + for (const char_type c : s) { + switch (c) { + case char_type('\\'): { + retval += string_conv("\\\\"); + break; + } + case char_type('\"'): { + retval += string_conv("\\\""); + break; + } + case char_type('\b'): { + retval += string_conv("\\b"); + break; + } + case char_type('\t'): { + retval += string_conv("\\t"); + break; + } + case char_type('\f'): { + retval += string_conv("\\f"); + break; + } + case char_type('\n'): { + retval += string_conv("\\n"); + break; + } + case char_type('\r'): { + retval += string_conv("\\r"); + break; + } + default: { + if (c == char_type(0x1B) && spec_.v1_1_0_add_escape_sequence_e) { + retval += string_conv("\\e"); + } else if ((char_type(0x00) <= c && c <= char_type(0x08)) || + (char_type(0x0A) <= c && c <= char_type(0x1F)) || + c == char_type(0x7F)) { + if (spec_.v1_1_0_add_escape_sequence_x) { + retval += string_conv("\\x"); + } else { + retval += string_conv("\\u00"); + } + const auto c1 = c / 16; + const auto c2 = c % 16; + retval += static_cast('0' + c1); + if (c2 < 10) { + retval += static_cast('0' + c2); + } else // 10 <= c2 + { + retval += static_cast('A' + (c2 - 10)); + } + } else { + retval += c; + } + } + } + } + return retval; + } // }}} + + string_type escape_ml_basic_string(const string_type& s) // {{{ + { + string_type retval; + for (const char_type c : s) { + switch (c) { + case char_type('\\'): { + retval += string_conv("\\\\"); + break; + } + case char_type('\b'): { + retval += string_conv("\\b"); + break; + } + case char_type('\t'): { + retval += string_conv("\\t"); + break; + } + case char_type('\f'): { + retval += string_conv("\\f"); + break; + } + case char_type('\n'): { + retval += string_conv("\n"); + break; + } + case char_type('\r'): { + retval += string_conv("\\r"); + break; + } + default: { + if (c == char_type(0x1B) && spec_.v1_1_0_add_escape_sequence_e) { + retval += string_conv("\\e"); + } else if ((char_type(0x00) <= c && c <= char_type(0x08)) || + (char_type(0x0A) <= c && c <= char_type(0x1F)) || + c == char_type(0x7F)) { + if (spec_.v1_1_0_add_escape_sequence_x) { + retval += string_conv("\\x"); + } else { + retval += string_conv("\\u00"); + } + const auto c1 = c / 16; + const auto c2 = c % 16; + retval += static_cast('0' + c1); + if (c2 < 10) { + retval += static_cast('0' + c2); + } else // 10 <= c2 + { + retval += static_cast('A' + (c2 - 10)); + } + } else { + retval += c; + } + } + } + } + // Only 1 or 2 consecutive `"`s are allowed in multiline basic string. + // 3 consecutive `"`s are considered as a closing delimiter. + // We need to check if there are 3 or more consecutive `"`s and insert + // backslash to break them down into several short `"`s like the `str6` + // in the following example. + // ```toml + // str4 = """Here are two quotation marks: "". Simple enough.""" + // # str5 = """Here are three quotation marks: """.""" # INVALID + // str5 = """Here are three quotation marks: ""\".""" + // str6 = """Here are fifteen quotation marks: ""\"""\"""\"""\"""\".""" + // ``` + auto found_3_quotes = retval.find(string_conv("\"\"\"")); + while (found_3_quotes != string_type::npos) { + retval.replace(found_3_quotes, 3, string_conv("\"\"\\\"")); + found_3_quotes = retval.find(string_conv("\"\"\"")); + } + return retval; + } // }}} + + string_type format_local_time(const local_time_type& t, + const bool has_seconds, + const std::size_t subsec_prec) // {{{ + { + std::ostringstream oss; + oss << std::setfill('0') << std::setw(2) << static_cast(t.hour); + oss << ':'; + oss << std::setfill('0') << std::setw(2) << static_cast(t.minute); + if (has_seconds) { + oss << ':'; + oss << std::setfill('0') << std::setw(2) << static_cast(t.second); + if (subsec_prec != 0) { + std::ostringstream subsec; + subsec << std::setfill('0') << std::setw(3) + << static_cast(t.millisecond); + subsec << std::setfill('0') << std::setw(3) + << static_cast(t.microsecond); + subsec << std::setfill('0') << std::setw(3) + << static_cast(t.nanosecond); + std::string subsec_str = subsec.str(); + oss << '.' << subsec_str.substr(0, subsec_prec); + } + } + return string_conv(oss.str()); + } // }}} + + string_type format_ml_table(const table_type& t, + const table_format_info& fmt) // {{{ + { + const auto format_later = [](const value_type& v) -> bool { + const bool is_ml_table = v.is_table() && + v.as_table_fmt().fmt != table_format::oneline && + v.as_table_fmt().fmt != + table_format::multiline_oneline && + v.as_table_fmt().fmt != table_format::dotted; + + const bool is_ml_array_table = v.is_array_of_tables() && + v.as_array_fmt().fmt != + array_format::oneline && + v.as_array_fmt().fmt != + array_format::multiline; + + return is_ml_table || is_ml_array_table; + }; + + string_type retval; + this->current_indent_ += fmt.body_indent; + for (const auto& kv : t) { + const auto& key = kv.first; + const auto& val = kv.second; + if (format_later(val)) { + continue; + } + this->keys_.push_back(key); + + retval += format_comments(val.comments(), fmt.indent_type); + retval += format_indent(fmt.indent_type); + if (val.is_table() && val.as_table_fmt().fmt == table_format::dotted) { + retval += (*this)(val); + } else { + retval += format_key(key); + retval += string_conv(" = "); + retval += (*this)(val); + retval += char_type('\n'); + } + this->keys_.pop_back(); + } + this->current_indent_ -= fmt.body_indent; + + if (!retval.empty()) { + retval += char_type('\n'); // for readability, add empty line between tables + } + for (const auto& kv : t) { + if (!format_later(kv.second)) { + continue; + } + // must be a [multiline.table] or [[multiline.array.of.tables]]. + // comments will be generated inside it. + this->keys_.push_back(kv.first); + retval += (*this)(kv.second); + this->keys_.pop_back(); + } + return retval; + } // }}} + + string_type format_inline_table(const table_type& t, + const table_format_info&) // {{{ + { + // comments are ignored because we cannot write without newline + string_type retval; + retval += char_type('{'); + for (const auto& kv : t) { + this->force_inline_ = true; + retval += this->format_key(kv.first); + retval += string_conv(" = "); + retval += (*this)(kv.second); + retval += string_conv(", "); + } + if (!t.empty()) { + retval.pop_back(); // ' ' + retval.pop_back(); // ',' + } + retval += char_type('}'); + this->force_inline_ = false; + return retval; + } // }}} + + string_type format_ml_inline_table(const table_type& t, + const table_format_info& fmt) // {{{ + { + string_type retval; + retval += string_conv("{\n"); + this->current_indent_ += fmt.body_indent; + for (const auto& kv : t) { + this->force_inline_ = true; + retval += format_comments(kv.second.comments(), fmt.indent_type); + retval += format_indent(fmt.indent_type); + retval += kv.first; + retval += string_conv(" = "); + + this->force_inline_ = true; + retval += (*this)(kv.second); + + retval += string_conv(",\n"); + } + if (!t.empty()) { + retval.pop_back(); // '\n' + retval.pop_back(); // ',' + } + this->current_indent_ -= fmt.body_indent; + this->force_inline_ = false; + + this->current_indent_ += fmt.closing_indent; + retval += format_indent(fmt.indent_type); + this->current_indent_ -= fmt.closing_indent; + + retval += char_type('}'); + return retval; + } // }}} + + string_type format_dotted_table(const table_type& t, + const table_format_info& fmt, // {{{ + const source_location&, + std::vector& keys) { + // lets say we have: `{"a": {"b": {"c": {"d": "foo", "e": "bar"} } }` + // and `a` and `b` are `dotted`. + // + // - in case if `c` is `oneline`: + // ```toml + // a.b.c = {d = "foo", e = "bar"} + // ``` + // + // - in case if and `c` is `dotted`: + // ```toml + // a.b.c.d = "foo" + // a.b.c.e = "bar" + // ``` + + string_type retval; + + for (const auto& kv : t) { + const auto& key = kv.first; + const auto& val = kv.second; + + keys.push_back(key); + + // format recursive dotted table? + if (val.is_table() && val.as_table_fmt().fmt != table_format::oneline && + val.as_table_fmt().fmt != table_format::multiline_oneline) { + retval += this->format_dotted_table(val.as_table(), + val.as_table_fmt(), + val.location(), + keys); + } else // non-table or inline tables. format normally + { + retval += format_comments(val.comments(), fmt.indent_type); + retval += format_indent(fmt.indent_type); + retval += format_keys(keys).value(); + retval += string_conv(" = "); + this->force_inline_ = true; // sub-table must be inlined + retval += (*this)(val); + retval += char_type('\n'); + this->force_inline_ = false; + } + keys.pop_back(); + } + return retval; + } // }}} + + string_type format_key(const key_type& key) // {{{ + { + if (key.empty()) { + return string_conv("\"\""); + } + + // check the key can be a bare (unquoted) key + auto loc = detail::make_temporary_location(string_conv(key)); + auto reg = detail::syntax::unquoted_key(this->spec_).scan(loc); + if (reg.is_ok() && loc.eof()) { + return key; + } + + // if it includes special characters, then format it in a "quoted" key. + string_type formatted = string_conv("\""); + for (const char_type c : key) { + switch (c) { + case char_type('\\'): { + formatted += string_conv("\\\\"); + break; + } + case char_type('\"'): { + formatted += string_conv("\\\""); + break; + } + case char_type('\b'): { + formatted += string_conv("\\b"); + break; + } + case char_type('\t'): { + formatted += string_conv("\\t"); + break; + } + case char_type('\f'): { + formatted += string_conv("\\f"); + break; + } + case char_type('\n'): { + formatted += string_conv("\\n"); + break; + } + case char_type('\r'): { + formatted += string_conv("\\r"); + break; + } + default: { + // ASCII ctrl char + if ((char_type(0x00) <= c && c <= char_type(0x08)) || + (char_type(0x0A) <= c && c <= char_type(0x1F)) || + c == char_type(0x7F)) { + if (spec_.v1_1_0_add_escape_sequence_x) { + formatted += string_conv("\\x"); + } else { + formatted += string_conv("\\u00"); + } + const auto c1 = c / 16; + const auto c2 = c % 16; + formatted += static_cast('0' + c1); + if (c2 < 10) { + formatted += static_cast('0' + c2); + } else // 10 <= c2 + { + formatted += static_cast('A' + (c2 - 10)); + } + } else { + formatted += c; + } + break; + } + } + } + formatted += string_conv("\""); + return formatted; + } // }}} + + cxx::optional format_keys(const std::vector& keys) // {{{ + { + if (keys.empty()) { + return cxx::make_nullopt(); + } + + string_type formatted; + for (const auto& ky : keys) { + formatted += format_key(ky); + formatted += char_type('.'); + } + formatted.pop_back(); // remove the last dot '.' + return formatted; + } // }}} + + string_type format_comments(const discard_comments&, + const indent_char) const // {{{ + { + return string_conv(""); + } // }}} + + string_type format_comments(const preserve_comments& comments, + const indent_char indent_type) const // {{{ + { + string_type retval; + for (const auto& c : comments) { + if (c.empty()) { + continue; + } + retval += format_indent(indent_type); + if (c.front() != '#') { + retval += char_type('#'); + } + retval += string_conv(c); + if (c.back() != '\n') { + retval += char_type('\n'); + } + } + return retval; + } // }}} + + string_type format_indent(const indent_char indent_type) const // {{{ + { + const auto indent = static_cast( + (std::max)(0, this->current_indent_)); + if (indent_type == indent_char::space) { + return string_conv(make_string(indent, ' ')); + } else if (indent_type == indent_char::tab) { + return string_conv(make_string(indent, '\t')); + } else { + return string_type {}; + } + } // }}} + + std::locale set_locale(std::ostream& os) const { + return os.imbue(std::locale::classic()); + } + + private: + spec spec_; + bool force_inline_; // table inside an array without fmt specification + std::int32_t current_indent_; + std::vector keys_; + }; + } // namespace detail + + template + typename basic_value::string_type format( + const basic_value& v, + const spec s = spec::default_version()) { + detail::serializer ser(s); + return ser(v); + } + + template + typename basic_value::string_type format( + const typename basic_value::key_type& k, + const basic_value& v, + const spec s = spec::default_version()) { + detail::serializer ser(s); + return ser(k, v); + } + + template + typename basic_value::string_type format( + const std::vector::key_type>& ks, + const basic_value& v, + const spec s = spec::default_version()) { + detail::serializer ser(s); + return ser(ks, v); + } + + template + std::ostream& operator<<(std::ostream& os, const basic_value& v) { + os << format(v); + return os; + } + +} // namespace toml + +#if defined(TOML11_COMPILE_SOURCES) +namespace toml { + struct type_config; + struct ordered_type_config; + + extern template typename basic_value::string_type format( + const basic_value&, + const spec); + + extern template typename basic_value::string_type format( + const typename basic_value::key_type& k, + const basic_value& v, + const spec); + + extern template typename basic_value::string_type format( + const std::vector::key_type>& ks, + const basic_value& v, + const spec s); + + extern template typename basic_value::string_type + format(const basic_value&, + const spec); + + extern template typename basic_value::string_type format( + const typename basic_value::key_type& k, + const basic_value& v, + const spec); + + extern template typename basic_value::string_type format( + const std::vector::key_type>& ks, + const basic_value& v, + const spec s); + + namespace detail { + extern template class serializer<::toml::type_config>; + extern template class serializer<::toml::ordered_type_config>; + } // namespace detail +} // namespace toml +#endif // TOML11_COMPILE_SOURCES + +#endif // TOML11_SERIALIZER_HPP +#ifndef TOML11_TOML_HPP +#define TOML11_TOML_HPP + +// The MIT License (MIT) +// +// Copyright (c) 2017-now Toru Niina +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +// IWYU pragma: begin_exports +// IWYU pragma: end_exports + +#endif // TOML11_TOML_HPP diff --git a/src/global/utils/tools.h b/src/global/utils/tools.h index 451c24264..96d948ae4 100644 --- a/src/global/utils/tools.h +++ b/src/global/utils/tools.h @@ -7,12 +7,13 @@ * - tools::divideInProportions2D -> std::tuple * - tools::divideInProportions3D -> std::tuple * - tools::Decompose -> std::vector> + * - tools::Tracker * @namespaces: * - tools:: */ -#ifndef UTILS_HELPERS_H -#define UTILS_HELPERS_H +#ifndef UTILS_TOOLS_H +#define UTILS_TOOLS_H #include "global.h" @@ -227,7 +228,7 @@ namespace tools { raise::ErrorIf(ndomains % n1 != 0, "Decomposition error: does not divide evenly", HERE); - std::tie(n2, + std::tie(n2, n3) = divideInProportions2D(ndomains / n1, ncells[1], ncells[2]); } else if (decomposition[0] < 0 && decomposition[1] < 0 && decomposition[2] < 0) { @@ -245,6 +246,54 @@ namespace tools { } } + class Tracker { + bool m_initialized { false }; + + std::string m_type; + std::size_t m_interval; + long double m_interval_time; + bool m_use_time; + + long double m_last_output_time { -1.0 }; + + public: + Tracker() = default; + + Tracker(const std::string& type, std::size_t interval, long double interval_time) + : m_initialized { true } + , m_type { type } + , m_interval { interval } + , m_interval_time { interval_time } + , m_use_time { interval_time > 0.0 } {} + + ~Tracker() = default; + + void init(const std::string& type, + std::size_t interval, + long double interval_time) { + m_type = type; + m_interval = interval; + m_interval_time = interval_time; + m_use_time = interval_time > 0.0; + m_initialized = true; + } + + auto shouldWrite(std::size_t step, long double time) -> bool { + raise::ErrorIf(!m_initialized, "Tracker not initialized", HERE); + if (m_use_time) { + if ((m_last_output_time < 0) or + (time - m_last_output_time >= m_interval_time)) { + m_last_output_time = time; + return true; + } else { + return false; + } + } else { + return step % m_interval == 0; + } + } + }; + } // namespace tools -#endif // UTILS_HELPERS_H +#endif // UTILS_TOOLS_H diff --git a/src/output/CMakeLists.txt b/src/output/CMakeLists.txt index b262d7771..2c25631ec 100644 --- a/src/output/CMakeLists.txt +++ b/src/output/CMakeLists.txt @@ -17,7 +17,6 @@ set(SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}) set(SOURCES ${SRC_DIR}/writer.cpp - ${SRC_DIR}/write_attrs.cpp ${SRC_DIR}/fields.cpp ${SRC_DIR}/utils/interpret_prompt.cpp ) diff --git a/src/output/write_attrs.cpp b/src/output/write_attrs.cpp deleted file mode 100644 index e1e70f467..000000000 --- a/src/output/write_attrs.cpp +++ /dev/null @@ -1,136 +0,0 @@ -#include "enums.h" -#include "global.h" - -#include "output/writer.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace out { - - template - struct has_to_string : std::false_type {}; - - template - struct has_to_string().to_string())>> - : std::true_type {}; - - template - auto write(adios2::IO& io, const std::string& name, T var) -> - typename std::enable_if::value, void>::type { - io.DefineAttribute(name, std::string(var.to_string())); - } - - template - auto write(adios2::IO& io, const std::string& name, T var) - -> decltype(void(T()), void()) { - io.DefineAttribute(name, var); - } - - template <> - void write(adios2::IO& io, const std::string& name, bool var) { - io.DefineAttribute(name, var ? 1 : 0); - } - - template <> - void write(adios2::IO& io, const std::string& name, Dimension var) { - io.DefineAttribute(name, (unsigned short)var); - } - - template - auto write_vec(adios2::IO& io, const std::string& name, std::vector var) -> - typename std::enable_if::value, void>::type { - std::vector var_str; - for (const auto& v : var) { - var_str.push_back(v.to_string()); - } - io.DefineAttribute(name, var_str.data(), var_str.size()); - } - - template - auto write_vec(adios2::IO& io, const std::string& name, std::vector var) - -> decltype(void(T()), void()) { - io.DefineAttribute(name, var.data(), var.size()); - } - - std::map> - write_functions; - - template - void register_write_function() { - write_functions[std::type_index(typeid(T))] = - [](adios2::IO& io, const std::string& name, std::any a) { - write(io, name, std::any_cast(a)); - }; - } - - template - void register_write_function_for_vector() { - write_functions[std::type_index(typeid(std::vector))] = - [](adios2::IO& io, const std::string& name, std::any a) { - write_vec(io, name, std::any_cast>(a)); - }; - } - - void write_any(adios2::IO& io, const std::string& name, std::any a) { - auto it = write_functions.find(a.type()); - if (it != write_functions.end()) { - it->second(io, name, a); - } else { - throw std::runtime_error("No write function registered for this type"); - } - } - - void Writer::writeAttrs(const prm::Parameters& params) { - register_write_function(); - register_write_function(); - register_write_function(); - register_write_function(); - register_write_function(); - register_write_function(); - register_write_function(); - register_write_function(); - register_write_function(); - register_write_function(); - register_write_function(); - register_write_function(); - register_write_function(); - register_write_function(); - register_write_function(); - register_write_function(); - register_write_function(); - register_write_function(); - register_write_function(); - register_write_function_for_vector(); - register_write_function_for_vector(); - register_write_function_for_vector(); - register_write_function_for_vector(); - register_write_function_for_vector(); - register_write_function_for_vector(); - register_write_function_for_vector(); - register_write_function_for_vector(); - register_write_function_for_vector(); - register_write_function_for_vector(); - register_write_function_for_vector(); - register_write_function_for_vector(); - register_write_function_for_vector(); - register_write_function_for_vector(); - register_write_function_for_vector(); - register_write_function_for_vector(); - register_write_function_for_vector(); - - for (auto& [key, value] : params.allVars()) { - try { - write_any(m_io, key, value); - } catch (const std::exception& e) { - continue; - } - } - } -} // namespace out \ No newline at end of file diff --git a/src/output/writer.cpp b/src/output/writer.cpp index 6be195794..dbd24e6c7 100644 --- a/src/output/writer.cpp +++ b/src/output/writer.cpp @@ -5,11 +5,11 @@ #include "arch/kokkos_aliases.h" #include "utils/error.h" #include "utils/param_container.h" +#include "utils/tools.h" #include - -#include -#include +#include +#include #if defined(MPI_ENABLED) #include "arch/mpi_aliases.h" @@ -17,13 +17,18 @@ #include #endif +#include +#include + namespace out { void Writer::init(adios2::ADIOS* ptr_adios, const std::string& engine) { m_engine = engine; p_adios = ptr_adios; - m_io = p_adios->DeclareIO("Entity::ADIOS2"); + raise::ErrorIf(p_adios == nullptr, "ADIOS pointer is null", HERE); + + m_io = p_adios->DeclareIO("Entity::Output"); m_io.SetEngine(engine); m_io.DefineVariable("Step"); @@ -33,8 +38,8 @@ namespace out { void Writer::addTracker(const std::string& type, std::size_t interval, long double interval_time) { - m_trackers.insert(std::pair( - { type, Tracker(type, interval, interval_time) })); + m_trackers.insert(std::pair( + { type, tools::Tracker(type, interval, interval_time) })); } auto Writer::shouldWrite(const std::string& type, @@ -161,6 +166,10 @@ namespace out { } } + void Writer::writeAttrs(const prm::Parameters& params) { + params.write(m_io); + } + template void WriteField(adios2::IO& io, adios2::Engine& writer, @@ -294,6 +303,7 @@ namespace out { void Writer::beginWriting(const std::string& fname, std::size_t tstep, long double time) { + raise::ErrorIf(p_adios == nullptr, "ADIOS pointer is null", HERE); p_adios->ExitComputationBlock(); if (m_writing_mode) { raise::Fatal("Already writing", HERE); @@ -311,6 +321,7 @@ namespace out { } void Writer::endWriting() { + raise::ErrorIf(p_adios == nullptr, "ADIOS pointer is null", HERE); if (!m_writing_mode) { raise::Fatal("Not writing", HERE); } diff --git a/src/output/writer.h b/src/output/writer.h index c8170c6b3..dc9483f56 100644 --- a/src/output/writer.h +++ b/src/output/writer.h @@ -11,6 +11,7 @@ #include "arch/kokkos_aliases.h" #include "utils/param_container.h" +#include "utils/tools.h" #include "output/fields.h" #include "output/particles.h" @@ -28,37 +29,6 @@ namespace out { - class Tracker { - const std::string m_type; - const std::size_t m_interval; - const long double m_interval_time; - const bool m_use_time; - - long double m_last_output_time { -1.0 }; - - public: - Tracker(const std::string& type, std::size_t interval, long double interval_time) - : m_type { type } - , m_interval { interval } - , m_interval_time { interval_time } - , m_use_time { interval_time > 0.0 } {} - - ~Tracker() = default; - - auto shouldWrite(std::size_t step, long double time) -> bool { - if (m_use_time) { - if (time - m_last_output_time >= m_interval_time) { - m_last_output_time = time; - return true; - } else { - return false; - } - } else { - return step % m_interval == 0; - } - } - }; - class Writer { adios2::ADIOS* p_adios { nullptr }; @@ -75,7 +45,7 @@ namespace out { bool m_flds_ghosts; std::string m_engine; - std::map m_trackers; + std::map m_trackers; std::vector m_flds_writers; std::vector m_prtl_writers; @@ -95,7 +65,7 @@ namespace out { void addTracker(const std::string&, std::size_t, long double); auto shouldWrite(const std::string&, std::size_t, long double) -> bool; - void writeAttrs(const prm::Parameters& params); + void writeAttrs(const prm::Parameters&); void defineMeshLayout(const std::vector&, const std::vector&, From b0f4673a90a4518e017f29037bd91a37b5dfcfd4 Mon Sep 17 00:00:00 2001 From: hayk Date: Sat, 10 Aug 2024 01:42:19 -0400 Subject: [PATCH 096/773] toml11 dependency removed --- .gitmodules | 3 --- extern/toml11 | 1 - 2 files changed, 4 deletions(-) delete mode 160000 extern/toml11 diff --git a/.gitmodules b/.gitmodules index bb2c39c87..e06c332fe 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,3 @@ -[submodule "extern/toml11"] - path = extern/toml11 - url = https://github.com/ToruNiina/toml11.git [submodule "extern/plog"] path = extern/plog url = https://github.com/SergiusTheBest/plog.git diff --git a/extern/toml11 b/extern/toml11 deleted file mode 160000 index 9b914db23..000000000 --- a/extern/toml11 +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 9b914db23df4acb6f1885fee29e07e9af959251e From 747d73ad2cdb071c65d954c8fc0c73c717282776 Mon Sep 17 00:00:00 2001 From: hayk Date: Sat, 10 Aug 2024 01:48:42 -0400 Subject: [PATCH 097/773] cmake in test fixed --- cmake/tests.cmake | 1 + 1 file changed, 1 insertion(+) diff --git a/cmake/tests.cmake b/cmake/tests.cmake index b53626723..7bfcb1d12 100644 --- a/cmake/tests.cmake +++ b/cmake/tests.cmake @@ -10,6 +10,7 @@ add_subdirectory(${SRC_DIR}/archetypes ${CMAKE_CURRENT_BINARY_DIR}/archetypes) add_subdirectory(${SRC_DIR}/framework ${CMAKE_CURRENT_BINARY_DIR}/framework) if (${output}) add_subdirectory(${SRC_DIR}/output ${CMAKE_CURRENT_BINARY_DIR}/output) + add_subdirectory(${SRC_DIR}/checkpoint ${CMAKE_CURRENT_BINARY_DIR}/checkpoint) endif() if (${mpi}) From b20606522318e4a5725bf894af5a59f56a09c69e Mon Sep 17 00:00:00 2001 From: hayk Date: Sat, 10 Aug 2024 04:34:36 -0400 Subject: [PATCH 098/773] restart dumping --- cmake/report.cmake | 7 +- src/checkpoint/writer.cpp | 221 +++++++++++++++++++++++++--- src/checkpoint/writer.h | 32 +++- src/framework/domain/checkpoint.cpp | 206 +++++++++++++++++++++++++- src/framework/domain/output.cpp | 1 - 5 files changed, 440 insertions(+), 27 deletions(-) diff --git a/cmake/report.cmake b/cmake/report.cmake index fe914baa8..6733dbcd4 100644 --- a/cmake/report.cmake +++ b/cmake/report.cmake @@ -276,10 +276,11 @@ endif() message(" ${PRECISION_REPORT}") message(" ${OUTPUT_REPORT}") -message("${DASHED_LINE_SYMBOL} -Compile configurations") +message("${DASHED_LINE_SYMBOL}\nCompile configurations") -message(" ${ARCH_REPORT}") +if(NOT "${ARCH_REPORT}" STREQUAL "") + message(" ${ARCH_REPORT}") +endif() message(" ${CUDA_REPORT}") message(" ${HIP_REPORT}") message(" ${OPENMP_REPORT}") diff --git a/src/checkpoint/writer.cpp b/src/checkpoint/writer.cpp index e56f59b36..53b2b2821 100644 --- a/src/checkpoint/writer.cpp +++ b/src/checkpoint/writer.cpp @@ -2,6 +2,8 @@ #include "global.h" +#include "arch/kokkos_aliases.h" +#include "arch/mpi_aliases.h" #include "utils/error.h" #include "utils/formatting.h" #include "utils/log.h" @@ -46,13 +48,96 @@ namespace checkpoint { p_adios->EnterComputationBlock(); } + void Writer::defineFieldVariables(const ntt::SimEngine& S, + const std::vector& glob_shape, + const std::vector& loc_corner, + const std::vector& loc_shape) { + auto gs3 = std::vector(glob_shape.begin(), glob_shape.end()); + auto lc3 = std::vector(loc_corner.begin(), loc_corner.end()); + auto ls3 = std::vector(loc_shape.begin(), loc_shape.end()); + auto gs6 = std::vector(glob_shape.begin(), glob_shape.end()); + auto lc6 = std::vector(loc_corner.begin(), loc_corner.end()); + auto ls6 = std::vector(loc_shape.begin(), loc_shape.end()); + + gs3.push_back(3); + lc3.push_back(0); + ls3.push_back(3); + + gs6.push_back(6); + lc6.push_back(0); + ls6.push_back(6); + + m_io.DefineVariable("em", gs6, lc6, ls6, adios2::ConstantDims); + if (S == ntt::SimEngine::GRPIC) { + m_io.DefineVariable("em0", gs6, lc6, ls6, adios2::ConstantDims); + m_io.DefineVariable("cur0", gs3, lc3, ls3, adios2::ConstantDims); + } + } + + void Writer::defineParticleVariables(const ntt::Coord& C, + Dimension dim, + std::size_t nspec, + const std::vector& nplds) { + raise::ErrorIf(nplds.size() != nspec, + "Number of payloads does not match the number of species", + HERE); + for (auto s { 0u }; s < nspec; ++s) { + m_io.DefineVariable(fmt::format("s%d_npart", s + 1), + { adios2::UnknownDim }, + { adios2::UnknownDim }, + { adios2::UnknownDim }); + for (auto d { 0u }; d < dim; ++d) { + m_io.DefineVariable(fmt::format("s%d_i%d", s + 1, d + 1), + { adios2::UnknownDim }, + { adios2::UnknownDim }, + { adios2::UnknownDim }); + m_io.DefineVariable(fmt::format("s%d_dx%d", s + 1, d + 1), + { adios2::UnknownDim }, + { adios2::UnknownDim }, + { adios2::UnknownDim }); + m_io.DefineVariable(fmt::format("s%d_i%d_prev", s + 1, d + 1), + { adios2::UnknownDim }, + { adios2::UnknownDim }, + { adios2::UnknownDim }); + m_io.DefineVariable(fmt::format("s%d_dx%d_prev", s + 1, d + 1), + { adios2::UnknownDim }, + { adios2::UnknownDim }, + { adios2::UnknownDim }); + } + if (dim == Dim::_2D and C != ntt::Coord::Cart) { + m_io.DefineVariable(fmt::format("s%d_phi", s + 1), + { adios2::UnknownDim }, + { adios2::UnknownDim }, + { adios2::UnknownDim }); + } + for (auto d { 0u }; d < 3; ++d) { + m_io.DefineVariable(fmt::format("s%d_ux%d", s + 1, d + 1), + { adios2::UnknownDim }, + { adios2::UnknownDim }, + { adios2::UnknownDim }); + } + m_io.DefineVariable(fmt::format("s%d_tag", s + 1), + { adios2::UnknownDim }, + { adios2::UnknownDim }, + { adios2::UnknownDim }); + m_io.DefineVariable(fmt::format("s%d_weight", s + 1), + { adios2::UnknownDim }, + { adios2::UnknownDim }, + { adios2::UnknownDim }); + for (auto p { 0u }; p < nplds[s]; ++p) { + m_io.DefineVariable(fmt::format("s%d_pld%d", s + 1, p + 1), + { adios2::UnknownDim }, + { adios2::UnknownDim }, + { adios2::UnknownDim }); + } + } + } + auto Writer::shouldSave(std::size_t step, long double time) -> bool { return m_enabled and m_tracker.shouldWrite(step, time); } - void Writer::beginSaving(const ntt::SimulationParams& params, - std::size_t step, - long double time) { + void Writer::beginSaving(std::size_t step, long double time) { raise::ErrorIf(!m_enabled, "Checkpoint is not enabled", HERE); raise::ErrorIf(p_adios == nullptr, "ADIOS pointer is null", HERE); p_adios->ExitComputationBlock(); @@ -61,19 +146,14 @@ namespace checkpoint { } m_writing_mode = true; try { - auto fname = fmt::format("checkpoints/step-%08lu.bp", step); - m_writer = m_io.Open(fname, adios2::Mode::Write); - m_written.push_back(fname); + auto fname = fmt::format("checkpoints/step-%08lu.bp", step); + m_writer = m_io.Open(fname, adios2::Mode::Write); + auto meta_fname = fmt::format("checkpoints/meta-%08lu.toml", step); + m_written.push_back({ fname, meta_fname }); } catch (std::exception& e) { raise::Fatal(e.what(), HERE); } - // write the metadata - std::ofstream metadata; - metadata.open(fmt::format("checkpoints/meta-%08lu.toml", step).c_str()); - metadata << params.data() << std::endl; - metadata.close(); - m_writer.BeginStep(); m_writer.Put(m_io.InquireVariable("Step"), &step); m_writer.Put(m_io.InquireVariable("Time"), &time); @@ -90,14 +170,115 @@ namespace checkpoint { p_adios->EnterComputationBlock(); // optionally remove the oldest checkpoint - if (m_keep > 0 and m_written.size() > (std::size_t)m_keep) { - const auto oldest = m_written.front(); - if (std::filesystem::exists(oldest)) { - std::filesystem::remove_all(oldest); - m_written.erase(m_written.begin()); - } else { - raise::Warning("Checkpoint file does not exist for some reason", HERE); + CallOnce([&]() { + if (m_keep > 0 and m_written.size() > (std::size_t)m_keep) { + const auto oldest = m_written.front(); + if (std::filesystem::exists(oldest.first) and + std::filesystem::exists(oldest.second)) { + std::filesystem::remove_all(oldest.first); + std::filesystem::remove(oldest.second); + m_written.erase(m_written.begin()); + } else { + raise::Warning("Checkpoint file does not exist for some reason", HERE); + } } - } + }); + } + + template + void Writer::savePerDomainVariable(const std::string& varname, + std::size_t total, + std::size_t offset, + T data) { + auto var = m_io.InquireVariable(varname); + var.SetShape({ total }); + var.SetSelection(adios2::Box({ offset }, { 1 })); + m_writer.Put(var, &data); } + + void Writer::saveAttrs(const ntt::SimulationParams& params) { + CallOnce([&]() { + std::ofstream metadata; + if (m_written.empty()) { + raise::Fatal("No checkpoint file to save metadata", HERE); + } + metadata.open(m_written.back().second.c_str()); + metadata << params.data() << std::endl; + metadata.close(); + }); + } + + template + void Writer::saveField(const std::string& fieldname, + const ndfield_t& field) { + auto field_h = Kokkos::create_mirror_view(field); + Kokkos::deep_copy(field_h, field); + m_writer.Put(m_io.InquireVariable(fieldname), field_h.data()); + } + + template + void Writer::saveParticleQuantity(const std::string& quantity, + std::size_t glob_total, + std::size_t loc_offset, + std::size_t loc_size, + const array_t& data) { + auto var = m_io.InquireVariable(quantity); + var.SetShape({ glob_total }); + var.SetSelection(adios2::Box({ loc_offset }, { loc_size })); + auto slice = range_tuple_t(0, loc_size); + auto data_h = Kokkos::create_mirror_view(data); + Kokkos::deep_copy(data_h, data); + m_writer.Put(var, Kokkos::subview(data_h, slice).data()); + } + + template void Writer::savePerDomainVariable(const std::string&, + std::size_t, + std::size_t, + int); + template void Writer::savePerDomainVariable(const std::string&, + std::size_t, + std::size_t, + float); + template void Writer::savePerDomainVariable(const std::string&, + std::size_t, + std::size_t, + double); + template void Writer::savePerDomainVariable(const std::string&, + std::size_t, + std::size_t, + std::size_t); + + template void Writer::saveField(const std::string&, + const ndfield_t&); + template void Writer::saveField(const std::string&, + const ndfield_t&); + template void Writer::saveField(const std::string&, + const ndfield_t&); + template void Writer::saveField(const std::string&, + const ndfield_t&); + template void Writer::saveField(const std::string&, + const ndfield_t&); + template void Writer::saveField(const std::string&, + const ndfield_t&); + + template void Writer::saveParticleQuantity(const std::string&, + std::size_t, + std::size_t, + std::size_t, + const array_t&); + template void Writer::saveParticleQuantity(const std::string&, + std::size_t, + std::size_t, + std::size_t, + const array_t&); + template void Writer::saveParticleQuantity(const std::string&, + std::size_t, + std::size_t, + std::size_t, + const array_t&); + template void Writer::saveParticleQuantity(const std::string&, + std::size_t, + std::size_t, + std::size_t, + const array_t&); } // namespace checkpoint diff --git a/src/checkpoint/writer.h b/src/checkpoint/writer.h index ec2fa08d8..c9fc8a7db 100644 --- a/src/checkpoint/writer.h +++ b/src/checkpoint/writer.h @@ -12,6 +12,7 @@ #ifndef CHECKPOINT_WRITER_H #define CHECKPOINT_WRITER_H +#include "enums.h" #include "global.h" #include "utils/tools.h" @@ -21,6 +22,8 @@ #include #include +#include +#include #include namespace checkpoint { @@ -35,7 +38,7 @@ namespace checkpoint { bool m_writing_mode { false }; - std::vector m_written; + std::vector> m_written; int m_keep; bool m_enabled; @@ -49,9 +52,34 @@ namespace checkpoint { auto shouldSave(std::size_t, long double) -> bool; - void beginSaving(const ntt::SimulationParams&, std::size_t, long double); + void beginSaving(std::size_t, long double); void endSaving(); + void saveAttrs(const ntt::SimulationParams&); + + template + void savePerDomainVariable(const std::string&, std::size_t, std::size_t, T); + + template + void saveField(const std::string&, const ndfield_t&); + + template + void saveParticleQuantity(const std::string&, + std::size_t, + std::size_t, + std::size_t, + const array_t&); + + void defineFieldVariables(const ntt::SimEngine&, + const std::vector&, + const std::vector&, + const std::vector&); + void defineParticleVariables(const ntt::Coord&, + Dimension, + std::size_t, + const std::vector&); + + [[nodiscard]] auto enabled() const -> bool { return m_enabled; } diff --git a/src/framework/domain/checkpoint.cpp b/src/framework/domain/checkpoint.cpp index 3295e9430..a5a77bf4d 100644 --- a/src/framework/domain/checkpoint.cpp +++ b/src/framework/domain/checkpoint.cpp @@ -2,6 +2,8 @@ #include "global.h" #include "utils/error.h" +#include "utils/formatting.h" +#include "utils/log.h" #include "metrics/kerr_schild.h" #include "metrics/kerr_schild_0.h" @@ -28,23 +30,225 @@ namespace ntt { "local_domain is a placeholder", HERE); + auto glob_shape_with_ghosts = mesh().n_active(); + auto off_ncells_with_ghosts = local_domain->offset_ncells(); + auto loc_shape_with_ghosts = local_domain->mesh.n_active(); + + std::vector nplds; + for (auto s { 0u }; s < local_domain->species.size(); ++s) { + nplds.push_back(local_domain->species[s].npld()); + } + g_checkpoint_writer.init( ptr_adios, params.template get("checkpoint.interval"), params.template get("checkpoint.interval_time"), params.template get("checkpoint.keep")); + g_checkpoint_writer.defineFieldVariables(S, + glob_shape_with_ghosts, + off_ncells_with_ghosts, + loc_shape_with_ghosts); + g_checkpoint_writer.defineParticleVariables(M::CoordType, + M::Dim, + local_domain->species.size(), + nplds); } template auto Metadomain::WriteCheckpoint(const SimulationParams& params, std::size_t step, long double time) -> bool { + raise::ErrorIf( + local_subdomain_indices().size() != 1, + "Checkpointing for now is only supported for one subdomain per rank", + HERE); if (!g_checkpoint_writer.shouldSave(step, time)) { return false; } + auto local_domain = subdomain_ptr(local_subdomain_indices()[0]); + raise::ErrorIf(local_domain->is_placeholder(), + "local_domain is a placeholder", + HERE); logger::Checkpoint("Writing checkpoint", HERE); - g_checkpoint_writer.beginSaving(params, step, time); + g_checkpoint_writer.beginSaving(step, time); + { + + g_checkpoint_writer.saveAttrs(params); + + g_checkpoint_writer.saveField("em", local_domain->fields.em); + if constexpr (S == SimEngine::GRPIC) { + g_checkpoint_writer.saveField("em0", local_domain->fields.em0); + g_checkpoint_writer.saveField("cur0", local_domain->fields.cur0); + } + std::size_t dom_offset = 0, dom_tot = 1; +#if defined(MPI_ENABLED) + dom_offset = g_mpi_rank; + dom_tot = g_mpi_size; +#endif // MPI_ENABLED + + for (auto s { 0u }; s < local_domain->species.size(); ++s) { + auto npart = local_domain->species[s].npart(); + std::size_t offset = 0; + auto glob_tot = npart; +#if defined(MPI_ENABLED) + auto glob_npart = std::vector(g_ndomains); + MPI_Allgather(&npart, + 1, + mpi::get_type(), + glob_npart.data(), + 1, + mpi::get_type(), + MPI_COMM_WORLD); + glob_tot = 0; + for (auto r = 0; r < g_mpi_size; ++r) { + if (r < g_mpi_rank) { + offset += glob_npart[r]; + } + glob_tot += glob_npart[r]; + } +#endif // MPI_ENABLED + g_checkpoint_writer.savePerDomainVariable( + fmt::format("s%d_npart", s + 1), + dom_tot, + dom_offset, + npart); + if constexpr (M::Dim == Dim::_1D or M::Dim == Dim::_2D or + M::Dim == Dim::_3D) { + g_checkpoint_writer.saveParticleQuantity( + fmt::format("s%d_i1", s + 1), + glob_tot, + offset, + npart, + local_domain->species[s].i1); + g_checkpoint_writer.saveParticleQuantity( + fmt::format("s%d_i1", s + 1), + glob_tot, + offset, + npart, + local_domain->species[s].i1); + g_checkpoint_writer.saveParticleQuantity( + fmt::format("s%d_dx1", s + 1), + glob_tot, + offset, + npart, + local_domain->species[s].dx1); + g_checkpoint_writer.saveParticleQuantity( + fmt::format("s%d_i1_prev", s + 1), + glob_tot, + offset, + npart, + local_domain->species[s].i1_prev); + g_checkpoint_writer.saveParticleQuantity( + fmt::format("s%d_dx1_prev", s + 1), + glob_tot, + offset, + npart, + local_domain->species[s].dx1_prev); + } + if constexpr (M::Dim == Dim::_1D or M::Dim == Dim::_2D) { + g_checkpoint_writer.saveParticleQuantity( + fmt::format("s%d_i2", s + 1), + glob_tot, + offset, + npart, + local_domain->species[s].i2); + g_checkpoint_writer.saveParticleQuantity( + fmt::format("s%d_dx2", s + 1), + glob_tot, + offset, + npart, + local_domain->species[s].dx2); + g_checkpoint_writer.saveParticleQuantity( + fmt::format("s%d_i2_prev", s + 1), + glob_tot, + offset, + npart, + local_domain->species[s].i2_prev); + g_checkpoint_writer.saveParticleQuantity( + fmt::format("s%d_dx2_prev", s + 1), + glob_tot, + offset, + npart, + local_domain->species[s].dx2_prev); + } + if constexpr (M::Dim == Dim::_3D) { + g_checkpoint_writer.saveParticleQuantity( + fmt::format("s%d_i3", s + 1), + glob_tot, + offset, + npart, + local_domain->species[s].i3); + g_checkpoint_writer.saveParticleQuantity( + fmt::format("s%d_dx3", s + 1), + glob_tot, + offset, + npart, + local_domain->species[s].dx3); + g_checkpoint_writer.saveParticleQuantity( + fmt::format("s%d_i3_prev", s + 1), + glob_tot, + offset, + npart, + local_domain->species[s].i3_prev); + g_checkpoint_writer.saveParticleQuantity( + fmt::format("s%d_dx3_prev", s + 1), + glob_tot, + offset, + npart, + local_domain->species[s].dx3_prev); + } + if constexpr (M::Dim == Dim::_2D and M::CoordType != Coord::Cart) { + g_checkpoint_writer.saveParticleQuantity( + fmt::format("s%d_phi", s + 1), + glob_tot, + offset, + npart, + local_domain->species[s].phi); + } + g_checkpoint_writer.saveParticleQuantity( + fmt::format("s%d_ux1", s + 1), + glob_tot, + offset, + npart, + local_domain->species[s].ux1); + g_checkpoint_writer.saveParticleQuantity( + fmt::format("s%d_ux2", s + 1), + glob_tot, + offset, + npart, + local_domain->species[s].ux2); + g_checkpoint_writer.saveParticleQuantity( + fmt::format("s%d_ux3", s + 1), + glob_tot, + offset, + npart, + local_domain->species[s].ux3); + g_checkpoint_writer.saveParticleQuantity( + fmt::format("s%d_tag", s + 1), + glob_tot, + offset, + npart, + local_domain->species[s].tag); + g_checkpoint_writer.saveParticleQuantity( + fmt::format("s%d_weight", s + 1), + glob_tot, + offset, + npart, + local_domain->species[s].weight); + + auto nplds = local_domain->species[s].npld(); + for (auto p { 0u }; p < nplds; ++p) { + g_checkpoint_writer.saveParticleQuantity( + fmt::format("s%d_pld%d", s + 1, p + 1), + glob_tot, + offset, + npart, + local_domain->species[s].pld[p]); + } + } + } g_checkpoint_writer.endSaving(); + logger::Checkpoint("Checkpoint written", HERE); return true; } diff --git a/src/framework/domain/output.cpp b/src/framework/domain/output.cpp index 36960816f..84860b223 100644 --- a/src/framework/domain/output.cpp +++ b/src/framework/domain/output.cpp @@ -201,7 +201,6 @@ namespace ntt { g_writer.beginWriting(params.template get("simulation.name"), step, time); - if (write_fields) { const auto incl_ghosts = params.template get("output.debug.ghosts"); From 631793a13895209288668513db0a2a74113f6b62 Mon Sep 17 00:00:00 2001 From: hayk Date: Sat, 10 Aug 2024 16:10:33 -0400 Subject: [PATCH 099/773] toml.h bug fixed --- src/global/utils/toml.h | 46 ++++++----------------------------------- 1 file changed, 6 insertions(+), 40 deletions(-) diff --git a/src/global/utils/toml.h b/src/global/utils/toml.h index b621f5839..16b79f72d 100644 --- a/src/global/utils/toml.h +++ b/src/global/utils/toml.h @@ -10365,15 +10365,14 @@ namespace toml { // recursive namespace detail { - template - T& last_one(T& arg) { - return arg; - } - template - auto last_one(T1&, T2& arg, Ts&... args) -> decltype(last_one(arg, args...)) { - return last_one(arg, args...); + template + auto last_one(Ts&&... args) -> decltype(std::get( + std::forward_as_tuple(std::forward(args)...))) { + return std::get( + std::forward_as_tuple(std::forward(args)...)); } + } // namespace detail template @@ -10401,39 +10400,6 @@ namespace toml { } } - template - auto find_or(Value&& v, const K1& k1, const K2& k2, K3&& k3, K4&& k4, Ks&&... keys) noexcept - -> cxx::enable_if_t>::value, - decltype(find_or(v, - k2, - std::forward(k3), - std::forward(k4), - std::forward(keys)...))> { - try { - return find_or(v.at(k1), - k2, - std::forward(k3), - std::forward(k4), - std::forward(keys)...); - } catch (...) { - return detail::last_one(k4, keys...); - } - } - - template - T find_or(const basic_value& v, - const K1& k1, - const K2& k2, - const K3& k3, - const K4& k4, - const Ks&... keys) noexcept { - try { - return find_or(v.at(k1), k2, k3, k4, keys...); - } catch (...) { - return static_cast(detail::last_one(k4, keys...)); - } - } - } // namespace toml #endif // TOML11_FIND_HPP #ifndef TOML11_CONVERSION_HPP From 2fb148e7a8904e8dd3b38bcb4cce2e23e313e0d9 Mon Sep 17 00:00:00 2001 From: hayk Date: Tue, 13 Aug 2024 15:06:37 -0400 Subject: [PATCH 100/773] param reading adapted to checkpoint --- input.example.toml | 34 +- src/checkpoint/reader.cpp | 0 src/checkpoint/reader.h | 19 + src/checkpoint/writer.cpp | 6 +- src/checkpoint/writer.h | 4 +- src/engines/engine.hpp | 18 +- src/engines/engine_init.cpp | 43 +-- src/engines/grpic.hpp | 3 +- src/engines/srpic.hpp | 2 +- src/framework/CMakeLists.txt | 1 + src/framework/domain/checkpoint.cpp | 2 +- src/framework/domain/metadomain.h | 4 +- src/framework/domain/output.cpp | 10 +- src/framework/parameters.cpp | 515 +++++++++++++++------------- src/framework/parameters.h | 11 +- src/framework/simulation.cpp | 57 ++- src/framework/simulation.h | 4 +- src/global/defaults.h | 1 - src/output/writer.cpp | 4 + src/output/writer.h | 2 + 20 files changed, 446 insertions(+), 294 deletions(-) create mode 100644 src/checkpoint/reader.cpp create mode 100644 src/checkpoint/reader.h diff --git a/input.example.toml b/input.example.toml index eacb7f402..06225024a 100644 --- a/input.example.toml +++ b/input.example.toml @@ -232,7 +232,7 @@ # @default: 0.9 e_ovr_b_max = "" # Maximum Larmor radius allowed for GCA particles (in physical units): - # @type: float: > 0 + # @type: float # @default: 0.0 # @note: When `larmor_max` == 0, the limit is disabled larmor_max = "" @@ -253,7 +253,7 @@ # @default: false use_weights = "" # Timesteps between particle re-sorting: - # @type: unsigned int: >= 0 + # @type: unsigned int # @default: 100 # @note: When MPI is enable, particles are sorted every step. # @note: When `sort_interval` == 0, the sorting is disabled. @@ -293,7 +293,7 @@ # @valid: "Boris", "Vay", "Boris,GCA", "Vay,GCA", "Photon", "None" pusher = "" # Number of additional (payload) variables for each particle of the given species: - # @type: unsigned short: >= 0 + # @type: unsigned short # @default: 0 n_payloads = "" # Radiation reaction to use for the species: @@ -316,7 +316,7 @@ # @default: 1 interval = "" # Physical (code) time interval between all outputs (overriden by specific output intervals below): - # @type: float: > 0 + # @type: float # @default: -1.0 (disabled) # @note: When `interval_time` < 0, the output is controlled by `interval`, otherwise by `interval_time` interval_time = "" @@ -345,15 +345,15 @@ # @default: 1 stride = "" # Smoothing window for the output of moments (e.g., "Rho", "Charge", "T", etc.): - # @type: unsigned short: >= 0 + # @type: unsigned short # @default: 0 mom_smooth = "" # Number of timesteps between field outputs (overrides `output.interval`): - # @type: unsigned int: > 0 + # @type: unsigned int # @default: 0 (use `output.interval`) interval = "" # Physical (code) time interval between field outputs (overrides `output.interval_time`): - # @type: float: > 0 + # @type: float # @default: -1.0 (use `output.interval_time`) # @note: When `interval_time` < 0, the output is controlled by `interval`, otherwise by `interval_time` interval_time = "" @@ -376,7 +376,7 @@ # @default: 0 (use `output.interval`) interval = "" # Physical (code) time interval between field outputs (overrides `output.interval_time`): - # @type: float: > 0 + # @type: float # @default: -1.0 (use `output.interval_time`) # @note: When `interval_time` < 0, the output is controlled by `interval`, otherwise by `interval_time` interval_time = "" @@ -407,7 +407,7 @@ # @default: 0 (use `output.interval`) interval = "" # Physical (code) time interval between spectra outputs (overrides `output.interval_time`): - # @type: float: > 0 + # @type: float # @default: -1.0 (use `output.interval_time`) # @note: When `interval_time` < 0, the output is controlled by `interval`, otherwise by `interval_time` interval_time = "" @@ -433,12 +433,26 @@ # @note: When `interval_time` < 0, the output is controlled by `interval`, otherwise by `interval_time` interval_time = "" # Number of checkpoints to keep: - # @type: unsigned int: > 0 + # @type: int # @default: 2 # @note: 0 = disable checkpointing # @note: -1 = keep all checkpoints keep = "" + # @inferred: + # - is_resuming + # @brief: Whether the simulation is resuming from a checkpoint + # @type: bool + # @from: command-line flag + # - start_step + # @brief: Timestep of the checkpoint used to resume + # @type: unsigned int + # @from: automatically determined during restart + # - start_time + # @brief: Time of the checkpoint used to resume + # @type: float + # @from: automatically determined during restart + [diagnostics] # Number of timesteps between diagnostic logs: # @type: int: > 0 diff --git a/src/checkpoint/reader.cpp b/src/checkpoint/reader.cpp new file mode 100644 index 000000000..e69de29bb diff --git a/src/checkpoint/reader.h b/src/checkpoint/reader.h new file mode 100644 index 000000000..ea8653e72 --- /dev/null +++ b/src/checkpoint/reader.h @@ -0,0 +1,19 @@ +/** + * @file checkpoint/reader.h + * @brief Class that reads checkpoints + * @implements + * - checkpoint::Reader + * @cpp: + * - reader.cpp + * @namespaces: + * - checkpoint:: + */ + +#ifndef CHECKPOINT_READER_H +#define CHECKPOINT_READER_H + +namespace checkpoint { + class Reader {}; +} // namespace checkpoint + +#endif // CHECKPOINT_READER_H diff --git a/src/checkpoint/writer.cpp b/src/checkpoint/writer.cpp index 53b2b2821..c584d13fe 100644 --- a/src/checkpoint/writer.cpp +++ b/src/checkpoint/writer.cpp @@ -196,14 +196,16 @@ namespace checkpoint { m_writer.Put(var, &data); } - void Writer::saveAttrs(const ntt::SimulationParams& params) { + void Writer::saveAttrs(const ntt::SimulationParams& params, long double time) { CallOnce([&]() { std::ofstream metadata; if (m_written.empty()) { raise::Fatal("No checkpoint file to save metadata", HERE); } metadata.open(m_written.back().second.c_str()); - metadata << params.data() << std::endl; + metadata << "[metadata]\n" + << " time = " << time << "\n\n" + << params.data() << std::endl; metadata.close(); }); } diff --git a/src/checkpoint/writer.h b/src/checkpoint/writer.h index c9fc8a7db..a23ab556a 100644 --- a/src/checkpoint/writer.h +++ b/src/checkpoint/writer.h @@ -6,7 +6,7 @@ * @cpp: * - writer.cpp * @namespaces: - * - save:: + * - checkpoint:: */ #ifndef CHECKPOINT_WRITER_H @@ -55,7 +55,7 @@ namespace checkpoint { void beginSaving(std::size_t, long double); void endSaving(); - void saveAttrs(const ntt::SimulationParams&); + void saveAttrs(const ntt::SimulationParams&, long double); template void savePerDomainVariable(const std::string&, std::size_t, std::size_t, T); diff --git a/src/engines/engine.hpp b/src/engines/engine.hpp index a2bb09c26..f1bb46e98 100644 --- a/src/engines/engine.hpp +++ b/src/engines/engine.hpp @@ -65,11 +65,14 @@ namespace ntt { Metadomain m_metadomain; user::PGen m_pgen; + const bool is_resuming; const long double runtime; const real_t dt; const std::size_t max_steps; - long double time { 0.0 }; - std::size_t step { 0 }; + const std::size_t start_step; + const long double start_time; + long double time; + std::size_t step; public: static constexpr bool pgen_is_ok { @@ -81,8 +84,8 @@ namespace ntt { static constexpr Dimension D { M::Dim }; static constexpr bool is_engine { true }; - Engine(const toml::value& raw_params) - : m_params { raw_params } + Engine(const SimulationParams& params) + : m_params { params } , m_metadomain { m_params.get("simulation.domain.number"), m_params.get>( "simulation.domain.decomposition"), @@ -98,9 +101,14 @@ namespace ntt { m_params.get>( "particles.species") } , m_pgen { m_params, m_metadomain } + , is_resuming { m_params.get("checkpoint.is_resuming") } , runtime { m_params.get("simulation.runtime") } , dt { m_params.get("algorithms.timestep.dt") } - , max_steps { static_cast(runtime / dt) } { + , max_steps { static_cast(runtime / dt) } + , start_step { m_params.get("checkpoint.start_step") } + , start_time { m_params.get("checkpoint.start_time") } + , time { start_time } + , step { start_step } { raise::ErrorIf(not pgen_is_ok, "Problem generator is not compatible with the picked engine/metric/dimension", HERE); print_report(); } diff --git a/src/engines/engine_init.cpp b/src/engines/engine_init.cpp index 926bb3f78..5a8a693b0 100644 --- a/src/engines/engine_init.cpp +++ b/src/engines/engine_init.cpp @@ -22,29 +22,32 @@ namespace ntt { void Engine::init() { if constexpr (pgen_is_ok) { #if defined(OUTPUT_ENABLED) - m_metadomain.InitWriter(&m_adios, m_params); + m_metadomain.InitWriter(&m_adios, m_params, is_resuming); m_metadomain.InitCheckpointWriter(&m_adios, m_params); #endif logger::Checkpoint("Initializing Engine", HERE); - if constexpr ( - traits::has_member>::value) { - logger::Checkpoint("Initializing fields from problem generator", HERE); - m_metadomain.runOnLocalDomains([&](auto& loc_dom) { - Kokkos::parallel_for( - "InitFields", - loc_dom.mesh.rangeActiveCells(), - arch::SetEMFields_kernel { - loc_dom.fields.em, - m_pgen.init_flds, - loc_dom.mesh.metric }); - }); - } - if constexpr ( - traits::has_member>::value) { - logger::Checkpoint("Initializing particles from problem generator", HERE); - m_metadomain.runOnLocalDomains([&](auto& loc_dom) { - m_pgen.InitPrtls(loc_dom); - }); + if (not is_resuming) { + if constexpr ( + traits::has_member>::value) { + logger::Checkpoint("Initializing fields from problem generator", HERE); + m_metadomain.runOnLocalDomains([&](auto& loc_dom) { + Kokkos::parallel_for( + "InitFields", + loc_dom.mesh.rangeActiveCells(), + arch::SetEMFields_kernel { + loc_dom.fields.em, + m_pgen.init_flds, + loc_dom.mesh.metric }); + }); + } + if constexpr ( + traits::has_member>::value) { + logger::Checkpoint("Initializing particles from problem generator", HERE); + m_metadomain.runOnLocalDomains([&](auto& loc_dom) { + m_pgen.InitPrtls(loc_dom); + }); + } + } else { } } } diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index a20fc2a86..d082d617f 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -18,6 +18,7 @@ #include "utils/toml.h" #include "framework/domain/domain.h" +#include "framework/parameters.h" #include "engines/engine.hpp" @@ -33,7 +34,7 @@ namespace ntt { public: static constexpr auto S { SimEngine::SRPIC }; - GRPICEngine(const toml::value& raw_data) : base_t { raw_data } {} + GRPICEngine(const SimulationParams& params) : base_t { params } {} ~GRPICEngine() = default; diff --git a/src/engines/srpic.hpp b/src/engines/srpic.hpp index 6f1a0d561..9b8b3f19b 100644 --- a/src/engines/srpic.hpp +++ b/src/engines/srpic.hpp @@ -71,7 +71,7 @@ namespace ntt { public: static constexpr auto S { SimEngine::SRPIC }; - SRPICEngine(const toml::value& raw_data) : base_t { raw_data } {} + SRPICEngine(const SimulationParams& params) : base_t { params } {} ~SRPICEngine() = default; diff --git a/src/framework/CMakeLists.txt b/src/framework/CMakeLists.txt index 8bfbf1430..241780575 100644 --- a/src/framework/CMakeLists.txt +++ b/src/framework/CMakeLists.txt @@ -49,6 +49,7 @@ if(${output}) endif() add_dependencies(ntt_framework ${libs}) target_link_libraries(ntt_framework PUBLIC ${libs}) +target_link_libraries(ntt_framework PRIVATE stdc++fs) target_include_directories(ntt_framework PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../ diff --git a/src/framework/domain/checkpoint.cpp b/src/framework/domain/checkpoint.cpp index a5a77bf4d..569a61093 100644 --- a/src/framework/domain/checkpoint.cpp +++ b/src/framework/domain/checkpoint.cpp @@ -73,7 +73,7 @@ namespace ntt { g_checkpoint_writer.beginSaving(step, time); { - g_checkpoint_writer.saveAttrs(params); + g_checkpoint_writer.saveAttrs(params, time); g_checkpoint_writer.saveField("em", local_domain->fields.em); if constexpr (S == SimEngine::GRPIC) { diff --git a/src/framework/domain/metadomain.h b/src/framework/domain/metadomain.h index 072a4183f..6a3c64742 100644 --- a/src/framework/domain/metadomain.h +++ b/src/framework/domain/metadomain.h @@ -115,7 +115,7 @@ namespace ntt { ~Metadomain() = default; #if defined(OUTPUT_ENABLED) - void InitWriter(adios2::ADIOS*, const SimulationParams&); + void InitWriter(adios2::ADIOS*, const SimulationParams&, bool is_resuming); auto Write(const SimulationParams&, std::size_t, long double, @@ -125,6 +125,8 @@ namespace ntt { const Domain&)> = {}) -> bool; void InitCheckpointWriter(adios2::ADIOS*, const SimulationParams&); auto WriteCheckpoint(const SimulationParams&, std::size_t, long double) -> bool; + + void ContinueFromCheckpoint(); #endif /* setters -------------------------------------------------------------- */ diff --git a/src/framework/domain/output.cpp b/src/framework/domain/output.cpp index 84860b223..701ea4fb3 100644 --- a/src/framework/domain/output.cpp +++ b/src/framework/domain/output.cpp @@ -38,7 +38,8 @@ namespace ntt { template void Metadomain::InitWriter(adios2::ADIOS* ptr_adios, - const SimulationParams& params) { + const SimulationParams& params, + bool is_resuming) { raise::ErrorIf( local_subdomain_indices().size() != 1, "Output for now is only supported for one subdomain per rank", @@ -47,7 +48,6 @@ namespace ntt { raise::ErrorIf(local_domain->is_placeholder(), "local_domain is a placeholder", HERE); - const auto incl_ghosts = params.template get("output.debug.ghosts"); auto glob_shape_with_ghosts = mesh().n_active(); @@ -95,7 +95,11 @@ namespace ntt { params.template get( "output." + std::string(type) + ".interval_time")); } - g_writer.writeAttrs(params); + if (is_resuming) { + g_writer.setMode(adios2::Mode::Append); + } else { + g_writer.writeAttrs(params); + } } template diff --git a/src/framework/parameters.cpp b/src/framework/parameters.cpp index 6df5ce3cc..12f4d2ffa 100644 --- a/src/framework/parameters.cpp +++ b/src/framework/parameters.cpp @@ -45,13 +45,13 @@ namespace ntt { return { dx0, V0 }; } - SimulationParams::SimulationParams(const toml::value& toml_data) - : raw_data { toml_data } { + /* + * . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + * Parameters that must not be changed during after the checkpoint restart + * . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + */ + void SimulationParams::setImmutableParams(const toml::value& toml_data) { /* [simulation] --------------------------------------------------------- */ - set("simulation.name", toml::find(raw_data, "simulation", "name")); - set("simulation.runtime", - toml::find(raw_data, "simulation", "runtime")); - const auto engine_enum = SimEngine::pick( fmt::toLower(toml::find(toml_data, "simulation", "engine")).c_str()); set("simulation.engine", engine_enum); @@ -62,7 +62,7 @@ namespace ntt { "MPI_Comm_size failed", HERE); #endif - const auto ndoms = toml::find_or(raw_data, + const auto ndoms = toml::find_or(toml_data, "simulation", "domain", "number", @@ -70,7 +70,7 @@ namespace ntt { set("simulation.domain.number", (unsigned int)ndoms); auto decomposition = toml::find_or>( - raw_data, + toml_data, "simulation", "domain", "decomposition", @@ -97,7 +97,7 @@ namespace ntt { HERE); set("simulation.domain.decomposition", decomposition); - auto extent = toml::find>>(raw_data, + auto extent = toml::find>>(toml_data, "grid", "extent"); raise::ErrorIf(extent.size() < 1 || extent.size() > 3, @@ -127,9 +127,9 @@ namespace ntt { HERE); coord = "qsph"; set("grid.metric.qsph_r0", - toml::find_or(raw_data, "grid", "metric", "qsph_r0", defaults::qsph::r0)); + toml::find_or(toml_data, "grid", "metric", "qsph_r0", defaults::qsph::r0)); set("grid.metric.qsph_h", - toml::find_or(raw_data, "grid", "metric", "qsph_h", defaults::qsph::h)); + toml::find_or(toml_data, "grid", "metric", "qsph_h", defaults::qsph::h)); } else { // spherical geometry raise::ErrorIf(dim == Dim::_1D, @@ -142,7 +142,7 @@ namespace ntt { } if ((engine_enum == SimEngine::GRPIC) && (metric_enum != Metric::Kerr_Schild_0)) { - const auto ks_a = toml::find_or(raw_data, + const auto ks_a = toml::find_or(toml_data, "grid", "metric", "ks_a", @@ -153,9 +153,194 @@ namespace ntt { const auto coord_enum = Coord::pick(coord.c_str()); set("grid.metric.coord", coord_enum); + /* [scales] ------------------------------------------------------------- */ + const auto larmor0 = toml::find(toml_data, "scales", "larmor0"); + const auto skindepth0 = toml::find(toml_data, "scales", "skindepth0"); + raise::ErrorIf(larmor0 <= ZERO || skindepth0 <= ZERO, + "larmor0 and skindepth0 must be positive", + HERE); + set("scales.larmor0", larmor0); + set("scales.skindepth0", skindepth0); + promiseToDefine("scales.dx0"); + promiseToDefine("scales.V0"); + promiseToDefine("scales.n0"); + promiseToDefine("scales.q0"); + set("scales.sigma0", SQR(skindepth0 / larmor0)); + set("scales.B0", ONE / larmor0); + set("scales.omegaB0", ONE / larmor0); + + /* [particles] ---------------------------------------------------------- */ + const auto ppc0 = toml::find(toml_data, "particles", "ppc0"); + set("particles.ppc0", ppc0); + raise::ErrorIf(ppc0 <= 0.0, "ppc0 must be positive", HERE); + set("particles.use_weights", + toml::find_or(toml_data, "particles", "use_weights", false)); + + /* [particles.species] -------------------------------------------------- */ + std::vector species; + const auto species_tab = toml::find_or(toml_data, + "particles", + "species", + toml::array {}); + set("particles.nspec", species_tab.size()); + + unsigned short idx = 1; + for (const auto& sp : species_tab) { + const auto label = toml::find_or(sp, + "label", + "s" + std::to_string(idx)); + const auto mass = toml::find(sp, "mass"); + const auto charge = toml::find(sp, "charge"); + raise::ErrorIf((charge != 0.0f) && (mass == 0.0f), + "mass of the charged species must be non-zero", + HERE); + const auto is_massless = (mass == 0.0f) && (charge == 0.0f); + const auto def_pusher = (is_massless ? defaults::ph_pusher + : defaults::em_pusher); + const auto maxnpart_real = toml::find(sp, "maxnpart"); + const auto maxnpart = static_cast(maxnpart_real); + auto pusher = toml::find_or(sp, "pusher", std::string(def_pusher)); + const auto npayloads = toml::find_or(sp, + "n_payloads", + static_cast(0)); + const auto cooling = toml::find_or(sp, "cooling", std::string("None")); + raise::ErrorIf((fmt::toLower(cooling) != "none") && is_massless, + "cooling is only applicable to massive particles", + HERE); + raise::ErrorIf((fmt::toLower(pusher) == "photon") && !is_massless, + "photon pusher is only applicable to massless particles", + HERE); + bool use_gca = false; + if (pusher.find(',') != std::string::npos) { + raise::ErrorIf(fmt::toLower(pusher.substr(pusher.find(',') + 1, + pusher.size())) != "gca", + "invalid pusher syntax", + HERE); + use_gca = true; + pusher = pusher.substr(0, pusher.find(',')); + } + const auto pusher_enum = PrtlPusher::pick(pusher.c_str()); + const auto cooling_enum = Cooling::pick(cooling.c_str()); + if (use_gca) { + raise::ErrorIf(engine_enum != SimEngine::SRPIC, + "GCA pushers are only supported for SRPIC", + HERE); + promiseToDefine("algorithms.gca.e_ovr_b_max"); + promiseToDefine("algorithms.gca.larmor_max"); + } + if (cooling_enum == Cooling::SYNCHROTRON) { + raise::ErrorIf(engine_enum != SimEngine::SRPIC, + "Synchrotron cooling is only supported for SRPIC", + HERE); + promiseToDefine("algorithms.synchrotron.gamma_rad"); + } + + species.emplace_back(ParticleSpecies(idx, + label, + mass, + charge, + maxnpart, + pusher_enum, + use_gca, + cooling_enum, + npayloads)); + idx += 1; + } + set("particles.species", species); + + /* inferred variables --------------------------------------------------- */ + // extent + if (extent.size() > dim) { + extent.erase(extent.begin() + (std::size_t)(dim), extent.end()); + } + raise::ErrorIf(extent[0].size() != 2, "invalid `grid.extent[0]`", HERE); + if (coord_enum != Coord::Cart) { + raise::ErrorIf(extent.size() > 1, + "invalid `grid.extent` for non-cartesian geometry", + HERE); + extent.push_back({ ZERO, constant::PI }); + if (dim == Dim::_3D) { + extent.push_back({ ZERO, TWO * constant::PI }); + } + } + raise::ErrorIf(extent.size() != dim, "invalid inferred `grid.extent`", HERE); + boundaries_t extent_pairwise; + for (unsigned short d = 0; d < (unsigned short)dim; ++d) { + raise::ErrorIf(extent[d].size() != 2, + fmt::format("invalid inferred `grid.extent[%d]`", d), + HERE); + extent_pairwise.push_back({ extent[d][0], extent[d][1] }); + } + set("grid.extent", extent_pairwise); + + // metric, dx0, V0, n0, q0 + { + boundaries_t ext; + for (const auto& e : extent) { + ext.push_back({ e[0], e[1] }); + } + std::map params; + if (coord_enum == Coord::Qsph) { + params["r0"] = get("grid.metric.qsph_r0"); + params["h"] = get("grid.metric.qsph_h"); + } + if ((engine_enum == SimEngine::GRPIC) && + (metric_enum != Metric::Kerr_Schild_0)) { + params["a"] = get("grid.metric.ks_a"); + } + set("grid.metric.params", params); + + std::pair dx0_V0; + if (metric_enum == Metric::Minkowski) { + if (dim == Dim::_1D) { + dx0_V0 = get_dx0_V0>(res, ext, params); + } else if (dim == Dim::_2D) { + dx0_V0 = get_dx0_V0>(res, ext, params); + } else { + dx0_V0 = get_dx0_V0>(res, ext, params); + } + } else if (metric_enum == Metric::Spherical) { + dx0_V0 = get_dx0_V0>(res, ext, params); + } else if (metric_enum == Metric::QSpherical) { + dx0_V0 = get_dx0_V0>(res, ext, params); + } else if (metric_enum == Metric::Kerr_Schild) { + dx0_V0 = get_dx0_V0>(res, ext, params); + } else if (metric_enum == Metric::Kerr_Schild_0) { + dx0_V0 = get_dx0_V0>(res, ext, params); + } else if (metric_enum == Metric::QKerr_Schild) { + dx0_V0 = get_dx0_V0>(res, ext, params); + } + auto [dx0, V0] = dx0_V0; + set("scales.dx0", dx0); + set("scales.V0", V0); + set("scales.n0", ppc0 / V0); + set("scales.q0", V0 / (ppc0 * SQR(skindepth0))); + + set("grid.metric.metric", metric_enum); + set("algorithms.timestep.dt", get("algorithms.timestep.CFL") * dx0); + } + } + + /* + * . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + * Parameters that may be changed during after the checkpoint restart + * . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . + */ + void SimulationParams::setMutableParams(const toml::value& toml_data) { + const auto engine_enum = get("simulation.engine"); + const auto coord_enum = get("grid.metric.coord"); + const auto dim = get("grid.dim"); + const auto extent_pairwise = get>("grid.extent"); + + /* [simulation] --------------------------------------------------------- */ + set("simulation.name", + toml::find(toml_data, "simulation", "name")); + set("simulation.runtime", + toml::find(toml_data, "simulation", "runtime")); + /* [grid.boundaraies] --------------------------------------------------- */ auto flds_bc = toml::find>>( - raw_data, + toml_data, "grid", "boundaries", "fields"); @@ -188,7 +373,7 @@ namespace ntt { } auto prtl_bc = toml::find>>( - raw_data, + toml_data, "grid", "boundaries", "particles"); @@ -220,41 +405,25 @@ namespace ntt { } } - /* [scales] ------------------------------------------------------------- */ - const auto larmor0 = toml::find(raw_data, "scales", "larmor0"); - const auto skindepth0 = toml::find(raw_data, "scales", "skindepth0"); - raise::ErrorIf(larmor0 <= ZERO || skindepth0 <= ZERO, - "larmor0 and skindepth0 must be positive", - HERE); - set("scales.larmor0", larmor0); - set("scales.skindepth0", skindepth0); - promiseToDefine("scales.dx0"); - promiseToDefine("scales.V0"); - promiseToDefine("scales.n0"); - promiseToDefine("scales.q0"); - set("scales.sigma0", SQR(skindepth0 / larmor0)); - set("scales.B0", ONE / larmor0); - set("scales.omegaB0", ONE / larmor0); - /* [algorithms] --------------------------------------------------------- */ set("algorithms.current_filters", - toml::find_or(raw_data, + toml::find_or(toml_data, "algorithms", "current_filters", defaults::current_filters)); /* [algorithms.toggles] ------------------------------------------------- */ set("algorithms.toggles.fieldsolver", - toml::find_or(raw_data, "algorithms", "toggles", "fieldsolver", true)); + toml::find_or(toml_data, "algorithms", "toggles", "fieldsolver", true)); set("algorithms.toggles.deposit", - toml::find_or(raw_data, "algorithms", "toggles", "deposit", true)); + toml::find_or(toml_data, "algorithms", "toggles", "deposit", true)); /* [algorithms.timestep] ------------------------------------------------ */ set("algorithms.timestep.CFL", - toml::find_or(raw_data, "algorithms", "timestep", "CFL", defaults::cfl)); + toml::find_or(toml_data, "algorithms", "timestep", "CFL", defaults::cfl)); promiseToDefine("algorithms.timestep.dt"); set("algorithms.timestep.correction", - toml::find_or(raw_data, + toml::find_or(toml_data, "algorithms", "timestep", "correction", @@ -263,116 +432,37 @@ namespace ntt { /* [algorithms.gr] ------------------------------------------------------ */ if (engine_enum == SimEngine::GRPIC) { set("algorithms.gr.pusher_eps", - toml::find_or(raw_data, + toml::find_or(toml_data, "algorithms", "gr", "pusher_eps", defaults::gr::pusher_eps)); set("algorithms.gr.pusher_niter", - toml::find_or(raw_data, + toml::find_or(toml_data, "algorithms", "gr", "pusher_niter", defaults::gr::pusher_niter)); } - /* [particles] ---------------------------------------------------------- */ - const auto ppc0 = toml::find(raw_data, "particles", "ppc0"); - set("particles.ppc0", ppc0); - raise::ErrorIf(ppc0 <= 0.0, "ppc0 must be positive", HERE); - set("particles.use_weights", - toml::find_or(raw_data, "particles", "use_weights", false)); - #if defined(MPI_ENABLED) const std::size_t sort_interval = 1; #else - const std::size_t sort_interval = toml::find_or(raw_data, + const std::size_t sort_interval = toml::find_or(toml_data, "particles", "sort_interval", defaults::sort_interval); #endif set("particles.sort_interval", sort_interval); - /* [particles.species] -------------------------------------------------- */ - std::vector species; - const auto species_tab = toml::find_or(raw_data, - "particles", - "species", - toml::array {}); - set("particles.nspec", species_tab.size()); - - unsigned short idx = 1; - for (const auto& sp : species_tab) { - const auto label = toml::find_or(sp, - "label", - "s" + std::to_string(idx)); - const auto mass = toml::find(sp, "mass"); - const auto charge = toml::find(sp, "charge"); - raise::ErrorIf((charge != 0.0f) && (mass == 0.0f), - "mass of the charged species must be non-zero", - HERE); - const auto is_massless = (mass == 0.0f) && (charge == 0.0f); - const auto def_pusher = (is_massless ? defaults::ph_pusher - : defaults::em_pusher); - const auto maxnpart_real = toml::find(sp, "maxnpart"); - const auto maxnpart = static_cast(maxnpart_real); - auto pusher = toml::find_or(sp, "pusher", std::string(def_pusher)); - const auto npayloads = toml::find_or(sp, - "n_payloads", - static_cast(0)); - const auto cooling = toml::find_or(sp, "cooling", std::string("None")); - raise::ErrorIf((fmt::toLower(cooling) != "none") && is_massless, - "cooling is only applicable to massive particles", - HERE); - raise::ErrorIf((fmt::toLower(pusher) == "photon") && !is_massless, - "photon pusher is only applicable to massless particles", - HERE); - bool use_gca = false; - if (pusher.find(',') != std::string::npos) { - raise::ErrorIf(fmt::toLower(pusher.substr(pusher.find(',') + 1, - pusher.size())) != "gca", - "invalid pusher syntax", - HERE); - use_gca = true; - pusher = pusher.substr(0, pusher.find(',')); - } - const auto pusher_enum = PrtlPusher::pick(pusher.c_str()); - const auto cooling_enum = Cooling::pick(cooling.c_str()); - if (use_gca) { - raise::ErrorIf(engine_enum != SimEngine::SRPIC, - "GCA pushers are only supported for SRPIC", - HERE); - promiseToDefine("algorithms.gca.e_ovr_b_max"); - promiseToDefine("algorithms.gca.larmor_max"); - } - if (cooling_enum == Cooling::SYNCHROTRON) { - raise::ErrorIf(engine_enum != SimEngine::SRPIC, - "Synchrotron cooling is only supported for SRPIC", - HERE); - promiseToDefine("algorithms.synchrotron.gamma_rad"); - } - - species.emplace_back(ParticleSpecies(idx, - label, - mass, - charge, - maxnpart, - pusher_enum, - use_gca, - cooling_enum, - npayloads)); - idx += 1; - } - set("particles.species", species); - /* [output] ------------------------------------------------------------- */ // fields set("output.format", - toml::find_or(raw_data, "output", "format", defaults::output::format)); + toml::find_or(toml_data, "output", "format", defaults::output::format)); set("output.interval", - toml::find_or(raw_data, "output", "interval", defaults::output::interval)); + toml::find_or(toml_data, "output", "interval", defaults::output::interval)); set("output.interval_time", - toml::find_or(raw_data, "output", "interval_time", -1.0)); + toml::find_or(toml_data, "output", "interval_time", -1.0)); promiseToDefine("output.fields.interval"); promiseToDefine("output.fields.interval_time"); promiseToDefine("output.fields.enable"); @@ -383,12 +473,12 @@ namespace ntt { promiseToDefine("output.spectra.interval_time"); promiseToDefine("output.spectra.enable"); - const auto flds_out = toml::find_or(raw_data, + const auto flds_out = toml::find_or(toml_data, "output", "fields", "quantities", std::vector {}); - const auto custom_flds_out = toml::find_or(raw_data, + const auto custom_flds_out = toml::find_or(toml_data, "output", "fields", "custom", @@ -399,28 +489,27 @@ namespace ntt { set("output.fields.quantities", flds_out); set("output.fields.custom", custom_flds_out); set("output.fields.mom_smooth", - toml::find_or(raw_data, + toml::find_or(toml_data, "output", "fields", "mom_smooth", defaults::output::mom_smooth)); set("output.fields.stride", - toml::find_or(raw_data, "output", "fields", "stride", defaults::output::flds_stride)); + toml::find_or(toml_data, + "output", + "fields", + "stride", + defaults::output::flds_stride)); // particles - auto prtl_out = toml::find_or(raw_data, - "output", - "particles", - "species", - std::vector {}); - if (prtl_out.size() == 0) { - for (unsigned short i = 0; i < species.size(); ++i) { - prtl_out.push_back(i + 1); - } - } + const auto prtl_out = toml::find_or(toml_data, + "output", + "particles", + "species", + std::vector {}); set("output.particles.species", prtl_out); set("output.particles.stride", - toml::find_or(raw_data, + toml::find_or(toml_data, "output", "particles", "stride", @@ -428,32 +517,36 @@ namespace ntt { // spectra set("output.spectra.e_min", - toml::find_or(raw_data, "output", "spectra", "e_min", defaults::output::spec_emin)); + toml::find_or(toml_data, "output", "spectra", "e_min", defaults::output::spec_emin)); set("output.spectra.e_max", - toml::find_or(raw_data, "output", "spectra", "e_max", defaults::output::spec_emax)); + toml::find_or(toml_data, "output", "spectra", "e_max", defaults::output::spec_emax)); set("output.spectra.log_bins", - toml::find_or(raw_data, + toml::find_or(toml_data, "output", "spectra", "log_bins", defaults::output::spec_log)); set("output.spectra.n_bins", - toml::find_or(raw_data, "output", "spectra", "n_bins", defaults::output::spec_nbins)); + toml::find_or(toml_data, + "output", + "spectra", + "n_bins", + defaults::output::spec_nbins)); // intervals for (const auto& type : { "fields", "particles", "spectra" }) { - const auto q_int = toml::find_or(raw_data, + const auto q_int = toml::find_or(toml_data, "output", std::string(type), "interval", 0); - const auto q_int_time = toml::find_or(raw_data, + const auto q_int_time = toml::find_or(toml_data, "output", std::string(type), "interval_time", -1.0); set("output." + std::string(type) + ".enable", - toml::find_or(raw_data, "output", std::string(type), "enable", true)); + toml::find_or(toml_data, "output", std::string(type), "enable", true)); if (q_int == 0 && q_int_time == -1.0) { set("output." + std::string(type) + ".interval", get("output.interval")); @@ -467,51 +560,30 @@ namespace ntt { /* [output.debug] ------------------------------------------------------- */ set("output.debug.as_is", - toml::find_or(raw_data, "output", "debug", "as_is", false)); + toml::find_or(toml_data, "output", "debug", "as_is", false)); set("output.debug.ghosts", - toml::find_or(raw_data, "output", "debug", "ghosts", false)); + toml::find_or(toml_data, "output", "debug", "ghosts", false)); /* [checkpoint] --------------------------------------------------------- */ set("checkpoint.interval", - toml::find_or(raw_data, "checkpoint", "interval", defaults::checkpoint::interval)); + toml::find_or(toml_data, + "checkpoint", + "interval", + defaults::checkpoint::interval)); set("checkpoint.interval_time", - toml::find_or(raw_data, "checkpoint", "interval_time", -1.0)); + toml::find_or(toml_data, "checkpoint", "interval_time", -1.0)); set("checkpoint.keep", - toml::find_or(raw_data, "checkpoint", "keep", defaults::checkpoint::keep)); + toml::find_or(toml_data, "checkpoint", "keep", defaults::checkpoint::keep)); /* [diagnostics] -------------------------------------------------------- */ set("diagnostics.interval", - toml::find_or(raw_data, "diagnostics", "interval", defaults::diag::interval)); + toml::find_or(toml_data, "diagnostics", "interval", defaults::diag::interval)); set("diagnostics.blocking_timers", - toml::find_or(raw_data, "diagnostics", "blocking_timers", false)); + toml::find_or(toml_data, "diagnostics", "blocking_timers", false)); set("diagnostics.colored_stdout", - toml::find_or(raw_data, "diagnostics", "colored_stdout", false)); + toml::find_or(toml_data, "diagnostics", "colored_stdout", false)); /* inferred variables --------------------------------------------------- */ - // extent - if (extent.size() > dim) { - extent.erase(extent.begin() + (std::size_t)(dim), extent.end()); - } - raise::ErrorIf(extent[0].size() != 2, "invalid `grid.extent[0]`", HERE); - if (coord_enum != Coord::Cart) { - raise::ErrorIf(extent.size() > 1, - "invalid `grid.extent` for non-cartesian geometry", - HERE); - extent.push_back({ ZERO, constant::PI }); - if (dim == Dim::_3D) { - extent.push_back({ ZERO, TWO * constant::PI }); - } - } - raise::ErrorIf(extent.size() != dim, "invalid inferred `grid.extent`", HERE); - boundaries_t extent_parwise; - for (unsigned short d = 0; d < (unsigned short)dim; ++d) { - raise::ErrorIf(extent[d].size() != 2, - fmt::format("invalid inferred `grid.extent[%d]`", d), - HERE); - extent_parwise.push_back({ extent[d][0], extent[d][1] }); - } - set("grid.extent", extent_parwise); - // fields/particle boundaries std::vector> flds_bc_enum; std::vector> prtl_bc_enum; @@ -642,20 +714,20 @@ namespace ntt { if (isPromised("grid.boundaries.absorb.ds")) { if (coord_enum == Coord::Cart) { auto min_extent = std::numeric_limits::max(); - for (const auto& e : extent) { - min_extent = std::min(min_extent, e[1] - e[0]); + for (const auto& e : extent_pairwise) { + min_extent = std::min(min_extent, e.second - e.first); } set("grid.boundaries.absorb.ds", - toml::find_or(raw_data, + toml::find_or(toml_data, "grid", "boundaries", "absorb", "ds", min_extent * defaults::bc::absorb::ds_frac)); } else { - auto r_extent = extent[0][1] - extent[0][0]; + auto r_extent = extent_pairwise[0].second - extent_pairwise[0].first; set("grid.boundaries.absorb.ds", - toml::find_or(raw_data, + toml::find_or(toml_data, "grid", "boundaries", "absorb", @@ -663,7 +735,7 @@ namespace ntt { r_extent * defaults::bc::absorb::ds_frac)); } set("grid.boundaries.absorb.coeff", - toml::find_or(raw_data, + toml::find_or(toml_data, "grid", "boundaries", "absorb", @@ -672,25 +744,25 @@ namespace ntt { } if (isPromised("grid.boundaries.atmosphere.temperature")) { - const auto atm_T = toml::find(raw_data, + const auto atm_T = toml::find(toml_data, "grid", "boundaries", "atmosphere", "temperature"); - const auto atm_h = toml::find(raw_data, + const auto atm_h = toml::find(toml_data, "grid", "boundaries", "atmosphere", "height"); set("grid.boundaries.atmosphere.temperature", atm_T); set("grid.boundaries.atmosphere.density", - toml::find(raw_data, "grid", "boundaries", "atmosphere", "density")); + toml::find(toml_data, "grid", "boundaries", "atmosphere", "density")); set("grid.boundaries.atmosphere.ds", - toml::find_or(raw_data, "grid", "boundaries", "atmosphere", "ds", ZERO)); + toml::find_or(toml_data, "grid", "boundaries", "atmosphere", "ds", ZERO)); set("grid.boundaries.atmosphere.height", atm_h); set("grid.boundaries.atmosphere.g", atm_T / atm_h); const auto atm_species = toml::find>( - raw_data, + toml_data, "grid", "boundaries", "atmosphere", @@ -701,76 +773,27 @@ namespace ntt { // gca if (isPromised("algorithms.gca.e_ovr_b_max")) { set("algorithms.gca.e_ovr_b_max", - toml::find_or(raw_data, + toml::find_or(toml_data, "algorithms", "gca", "e_ovr_b_max", defaults::gca::EovrB_max)); set("algorithms.gca.larmor_max", - toml::find_or(raw_data, "algorithms", "gca", "larmor_max", ZERO)); + toml::find_or(toml_data, "algorithms", "gca", "larmor_max", ZERO)); } // cooling if (isPromised("algorithms.synchrotron.gamma_rad")) { set("algorithms.synchrotron.gamma_rad", - toml::find_or(raw_data, + toml::find_or(toml_data, "algorithms", "synchrotron", "gamma_rad", defaults::synchrotron::gamma_rad)); } + } - // metric, dx0, V0, n0, q0 - { - boundaries_t ext; - for (const auto& e : extent) { - ext.push_back({ e[0], e[1] }); - } - std::map params; - if (coord_enum == Coord::Qsph) { - params["r0"] = get("grid.metric.qsph_r0"); - params["h"] = get("grid.metric.qsph_h"); - } - if ((engine_enum == SimEngine::GRPIC) && - (metric_enum != Metric::Kerr_Schild_0)) { - params["a"] = get("grid.metric.ks_a"); - } - set("grid.metric.params", params); - - std::pair dx0_V0; - if (metric_enum == Metric::Minkowski) { - if (dim == Dim::_1D) { - dx0_V0 = get_dx0_V0>(res, ext, params); - } else if (dim == Dim::_2D) { - dx0_V0 = get_dx0_V0>(res, ext, params); - } else { - dx0_V0 = get_dx0_V0>(res, ext, params); - } - } else if (metric_enum == Metric::Spherical) { - dx0_V0 = get_dx0_V0>(res, ext, params); - } else if (metric_enum == Metric::QSpherical) { - dx0_V0 = get_dx0_V0>(res, ext, params); - } else if (metric_enum == Metric::Kerr_Schild) { - dx0_V0 = get_dx0_V0>(res, ext, params); - } else if (metric_enum == Metric::Kerr_Schild_0) { - dx0_V0 = get_dx0_V0>(res, ext, params); - } else if (metric_enum == Metric::QKerr_Schild) { - dx0_V0 = get_dx0_V0>(res, ext, params); - } - auto [dx0, V0] = dx0_V0; - set("scales.dx0", dx0); - set("scales.V0", V0); - set("scales.n0", ppc0 / V0); - set("scales.q0", V0 / (ppc0 * SQR(skindepth0))); - - set("grid.metric.metric", metric_enum); - set("algorithms.timestep.dt", get("algorithms.timestep.CFL") * dx0); - } - - raise::ErrorIf(!promisesFulfilled(), - "Have not defined all the necessary variables", - HERE); - + void SimulationParams::setSetupParams(const toml::value& toml_data) { /* [setup] -------------------------------------------------------------- */ const auto& setup = toml::find_or(raw_data, "setup", toml::table {}); for (const auto& [key, val] : setup) { @@ -820,4 +843,18 @@ namespace ntt { } } } + + void SimulationParams::setCheckpointParams(bool is_resuming, + std::size_t start_step, + long double start_time) { + set("checkpoint.is_resuming", is_resuming); + set("checkpoint.start_step", start_step); + set("checkpoint.start_time", start_time); + } + + void SimulationParams::checkPromises() const { + raise::ErrorIf(!promisesFulfilled(), + "Have not defined all the necessary variables", + HERE); + } } // namespace ntt diff --git a/src/framework/parameters.h b/src/framework/parameters.h index afa730bcd..2c03ef812 100644 --- a/src/framework/parameters.h +++ b/src/framework/parameters.h @@ -25,7 +25,6 @@ namespace ntt { struct SimulationParams : public prm::Parameters { SimulationParams() = default; - SimulationParams(const toml::value&); SimulationParams& operator=(const SimulationParams& other) { vars = std::move(other.vars); @@ -36,11 +35,21 @@ namespace ntt { ~SimulationParams() = default; + void setImmutableParams(const toml::value&); + void setMutableParams(const toml::value&); + void setCheckpointParams(bool, std::size_t, long double); + void setSetupParams(const toml::value&); + void checkPromises() const; + [[nodiscard]] auto data() const -> const toml::value& { return raw_data; } + void setRawData(const toml::value& data) { + raw_data = data; + } + private: toml::value raw_data; }; diff --git a/src/framework/simulation.cpp b/src/framework/simulation.cpp index 7cf989872..74798ffa6 100644 --- a/src/framework/simulation.cpp +++ b/src/framework/simulation.cpp @@ -7,26 +7,30 @@ #include "utils/cargs.h" #include "utils/error.h" #include "utils/formatting.h" +#include "utils/log.h" #include "utils/plog.h" #include "utils/toml.h" #include "framework/parameters.h" +#include #include namespace ntt { Simulation::Simulation(int argc, char* argv[]) { - GlobalInitialize(argc, argv); - cargs::CommandLineArguments cl_args; cl_args.readCommandLineArguments(argc, argv); const auto inputfname = static_cast( cl_args.getArgument("-input", defaults::input_filename)); - const auto outputdir = static_cast( - cl_args.getArgument("-output", defaults::output_path)); - raw_params = toml::parse(inputfname); + const bool is_resuming = (cl_args.isSpecified("-continue") or + cl_args.isSpecified("-restart") or + cl_args.isSpecified("-resume") or + cl_args.isSpecified("-checkpoint")); + GlobalInitialize(argc, argv); + + const auto raw_params = toml::parse(inputfname); const auto sim_name = toml::find(raw_params, "simulation", "name"); logger::initPlog(sim_name); @@ -43,6 +47,49 @@ namespace ntt { "invalid `grid.resolution`", HERE); m_requested_dimension = static_cast(res.size()); + + // !TODO: when mixing checkpoint metadata with input, + // ... need to properly take care of the diffs + m_params.setRawData(raw_params); + std::size_t checkpoint_step = 0; + if (is_resuming) { + if (not std::filesystem::exists("checkpoints")) { + raise::Fatal("No checkpoints found", HERE); + } + for (const auto& entry : + std::filesystem::directory_iterator("checkpoints")) { + const auto fname = entry.path().filename().string(); + if (fname.find("step-") == 0) { + const std::size_t step = std::stoi(fname.substr(5, fname.size() - 5 - 3)); + if (step > checkpoint_step) { + checkpoint_step = step; + } + } + } + std::string checkpoint_inputfname = fmt::format( + "checkpoints/meta-%08lu.toml", + checkpoint_step); + if (not std::filesystem::exists(checkpoint_inputfname)) { + raise::Fatal( + fmt::format("metainformation for %lu not found", checkpoint_step), + HERE); + checkpoint_inputfname = inputfname; + } + const auto raw_checkpoint_params = toml::parse(checkpoint_inputfname); + const auto start_time = toml::find(raw_checkpoint_params, + "metadata", + "time"); + m_params.setImmutableParams(raw_checkpoint_params); + m_params.setMutableParams(raw_params); + m_params.setCheckpointParams(true, checkpoint_step, start_time); + m_params.setSetupParams(raw_checkpoint_params); + } else { + m_params.setImmutableParams(raw_params); + m_params.setMutableParams(raw_params); + m_params.setCheckpointParams(false, 0, 0.0); + m_params.setSetupParams(raw_params); + } + m_params.checkPromises(); } Simulation::~Simulation() { diff --git a/src/framework/simulation.h b/src/framework/simulation.h index c069aa484..3cc664995 100644 --- a/src/framework/simulation.h +++ b/src/framework/simulation.h @@ -28,7 +28,7 @@ namespace ntt { class Simulation { - toml::value raw_params; + SimulationParams m_params; Dimension m_requested_dimension; SimEngine m_requested_engine { SimEngine::INVALID }; @@ -46,7 +46,7 @@ namespace ntt { static_assert(traits::has_method::value, "Engine must contain a ::run() method"); try { - engine_t engine { raw_params }; + engine_t engine { m_params }; engine.run(); } catch (const std::exception& e) { raise::Fatal(e.what(), HERE); diff --git a/src/global/defaults.h b/src/global/defaults.h index b9eca9080..ee9a65af5 100644 --- a/src/global/defaults.h +++ b/src/global/defaults.h @@ -16,7 +16,6 @@ namespace ntt::defaults { constexpr std::string_view input_filename = "input"; - constexpr std::string_view output_path = "output"; const real_t correction = 1.0; const real_t cfl = 0.95; diff --git a/src/output/writer.cpp b/src/output/writer.cpp index dbd24e6c7..f120cad10 100644 --- a/src/output/writer.cpp +++ b/src/output/writer.cpp @@ -53,6 +53,10 @@ namespace out { } } + void Writer::setMode(adios2::Mode mode) { + m_mode = mode; + } + void Writer::defineMeshLayout(const std::vector& glob_shape, const std::vector& loc_corner, const std::vector& loc_shape, diff --git a/src/output/writer.h b/src/output/writer.h index dc9483f56..d188fa93a 100644 --- a/src/output/writer.h +++ b/src/output/writer.h @@ -62,6 +62,8 @@ namespace out { void init(adios2::ADIOS*, const std::string&); + void setMode(adios2::Mode); + void addTracker(const std::string&, std::size_t, long double); auto shouldWrite(const std::string&, std::size_t, long double) -> bool; From d55d7187f39ca260b878813e704f07b754d65852 Mon Sep 17 00:00:00 2001 From: haykh Date: Fri, 16 Aug 2024 21:15:20 -0400 Subject: [PATCH 101/773] advanced diag output --- src/engines/engine_printer.cpp | 2 +- src/engines/engine_step_report.cpp | 241 ------------------------- src/global/CMakeLists.txt | 6 + src/global/arch/mpi_aliases.h | 3 +- src/global/global.h | 20 +-- src/global/utils/colors.h | 3 +- src/global/utils/diag.cpp | 246 +++++++++++++++++++++++++ src/global/utils/diag.h | 59 ++++++ src/global/utils/formatting.h | 62 +++++++ src/global/utils/log.h | 2 + src/global/utils/progressbar.cpp | 120 +++++++++++++ src/global/utils/progressbar.h | 106 ++--------- src/global/utils/timer.cpp | 279 +++++++++++++++++++++++++++++ src/global/utils/timer.h | 246 +++++-------------------- src/global/utils/tools.h | 27 +++ 15 files changed, 865 insertions(+), 557 deletions(-) delete mode 100644 src/engines/engine_step_report.cpp create mode 100644 src/global/utils/diag.cpp create mode 100644 src/global/utils/diag.h create mode 100644 src/global/utils/progressbar.cpp create mode 100644 src/global/utils/timer.cpp diff --git a/src/engines/engine_printer.cpp b/src/engines/engine_printer.cpp index 90dec3326..2608ea2f6 100644 --- a/src/engines/engine_printer.cpp +++ b/src/engines/engine_printer.cpp @@ -344,7 +344,7 @@ namespace ntt { for (unsigned int idx { 0 }; idx < m_metadomain.ndomains(); ++idx) { auto is_local = false; - for (const auto& lidx : m_metadomain.local_subdomain_indices()) { + for (const auto& lidx : m_metadomain.l_subdomain_indices()) { is_local |= (idx == lidx); } if (is_local) { diff --git a/src/engines/engine_step_report.cpp b/src/engines/engine_step_report.cpp deleted file mode 100644 index 7edeaab67..000000000 --- a/src/engines/engine_step_report.cpp +++ /dev/null @@ -1,241 +0,0 @@ -#include "enums.h" -#include "global.h" - -#include "arch/mpi_aliases.h" -#include "utils/colors.h" -#include "utils/formatting.h" -#include "utils/progressbar.h" -#include "utils/timer.h" - -#include "metrics/kerr_schild.h" -#include "metrics/kerr_schild_0.h" -#include "metrics/minkowski.h" -#include "metrics/qkerr_schild.h" -#include "metrics/qspherical.h" -#include "metrics/spherical.h" - -#include "engines/engine.hpp" - -#include -#include - -namespace ntt { - namespace {} // namespace - - template - void print_particles(const Metadomain&, - unsigned short, - DiagFlags, - std::ostream& = std::cout); - - template - void Engine::print_step_report(timer::Timers& timers, - pbar::DurationHistory& time_history, - bool print_output, - bool print_checkpoint, - bool print_sorting) const { - DiagFlags diag_flags = Diag::Default; - TimerFlags timer_flags = Timer::Default; - if (not m_params.get("diagnostics.colored_stdout")) { - diag_flags ^= Diag::Colorful; - timer_flags ^= Timer::Colorful; - } - if (m_params.get("particles.nspec") == 0) { - diag_flags ^= Diag::Species; - } - if (print_output) { - timer_flags |= Timer::PrintOutput; - } - if (print_checkpoint) { - timer_flags |= Timer::PrintCheckpoint; - } - if (print_sorting) { - timer_flags |= Timer::PrintSorting; - } - CallOnce( - [diag_flags](auto& time, auto& step, auto& max_steps, auto& dt) { - const auto c_bgreen = color::get_color("bgreen", - diag_flags & Diag::Colorful); - const auto c_bblack = color::get_color("bblack", - diag_flags & Diag::Colorful); - const auto c_reset = color::get_color("reset", diag_flags & Diag::Colorful); - std::cout << fmt::format("Step:%s %-8d%s %s[of %d]%s\n", - c_bgreen.c_str(), - step, - c_reset.c_str(), - c_bblack.c_str(), - max_steps, - c_reset.c_str()); - std::cout << fmt::format("Time:%s %-8.4f%s %s[Δt = %.4f]%s\n", - c_bgreen.c_str(), - (double)time, - c_reset.c_str(), - c_bblack.c_str(), - (double)dt, - c_reset.c_str()) - << std::endl; - }, - time, - step, - max_steps, - dt); - if (diag_flags & Diag::Timers) { - timers.printAll(timer_flags, std::cout); - } - CallOnce([]() { - std::cout << std::endl; - }); - if (diag_flags & Diag::Species) { - CallOnce([diag_flags]() { - std::cout << color::get_color("bblack", diag_flags & Diag::Colorful); -#if defined(MPI_ENABLED) - std::cout << "Particle count:" << std::setw(22) << std::right << "[TOT]" - << std::setw(20) << std::right << "[MIN (%)]" << std::setw(20) - << std::right << "[MAX (%)]"; -#else - std::cout << "Particle count:" << std::setw(25) << std::right - << "[TOT (%)]"; -#endif - std::cout << color::get_color("reset", diag_flags & Diag::Colorful) - << std::endl; - }); - for (std::size_t sp { 0 }; sp < m_metadomain.species_params().size(); ++sp) { - print_particles(m_metadomain, sp, diag_flags, std::cout); - } - CallOnce([]() { - std::cout << std::endl; - }); - } - if (diag_flags & Diag::Progress) { - pbar::ProgressBar(time_history, step, max_steps, diag_flags, std::cout); - } - CallOnce([]() { - std::cout << std::setw(80) << std::setfill('.') << "" << std::endl - << std::endl; - }); - } - - template - void print_particles(const Metadomain& md, - unsigned short sp, - DiagFlags flags, - std::ostream& os) { - - static_assert(M::is_metric, "template arg for Engine class has to be a metric"); - std::size_t npart { 0 }; - std::size_t maxnpart { 0 }; - std::string species_label; - int species_index; - // sum npart & maxnpart over all subdomains on the current rank - md.runOnLocalDomainsConst( - [&npart, &maxnpart, &species_label, &species_index, sp](auto& dom) { - npart += dom.species[sp].npart(); - maxnpart += dom.species[sp].maxnpart(); - species_label = dom.species[sp].label(); - species_index = dom.species[sp].index(); - }); -#if defined(MPI_ENABLED) - int rank, size; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - MPI_Comm_size(MPI_COMM_WORLD, &size); - std::vector mpi_npart(size, 0); - std::vector mpi_maxnpart(size, 0); - MPI_Gather(&npart, - 1, - mpi::get_type(), - mpi_npart.data(), - 1, - mpi::get_type(), - MPI_ROOT_RANK, - MPI_COMM_WORLD); - MPI_Gather(&maxnpart, - 1, - mpi::get_type(), - mpi_maxnpart.data(), - 1, - mpi::get_type(), - MPI_ROOT_RANK, - MPI_COMM_WORLD); - if (rank != MPI_ROOT_RANK) { - return; - } - auto tot_npart = std::accumulate(mpi_npart.begin(), mpi_npart.end(), 0); - std::size_t npart_max = *std::max_element(mpi_npart.begin(), mpi_npart.end()); - std::size_t npart_min = *std::min_element(mpi_npart.begin(), mpi_npart.end()); - std::vector mpi_load(size, 0.0); - for (auto r { 0 }; r < size; ++r) { - mpi_load[r] = 100.0 * (double)(mpi_npart[r]) / (double)(mpi_maxnpart[r]); - } - double load_max = *std::max_element(mpi_load.begin(), mpi_load.end()); - double load_min = *std::min_element(mpi_load.begin(), mpi_load.end()); - auto npart_min_str = npart_min > 9999 - ? fmt::format("%.2Le", (long double)npart_min) - : std::to_string(npart_min); - auto tot_npart_str = tot_npart > 9999 - ? fmt::format("%.2Le", (long double)tot_npart) - : std::to_string(tot_npart); - auto npart_max_str = npart_max > 9999 - ? fmt::format("%.2Le", (long double)npart_max) - : std::to_string(npart_max); - os << " species " << fmt::format("%2d", species_index) << " (" - << species_label << ")"; - - const auto c_bblack = color::get_color("bblack", flags & Diag::Colorful); - const auto c_red = color::get_color("red", flags & Diag::Colorful); - const auto c_yellow = color::get_color("yellow", flags & Diag::Colorful); - const auto c_green = color::get_color("green", flags & Diag::Colorful); - const auto c_reset = color::get_color("reset", flags & Diag::Colorful); - auto c_loadmin = (load_min > 80) ? c_red - : ((load_min > 50) ? c_yellow : c_green); - auto c_loadmax = (load_max > 80) ? c_red - : ((load_max > 50) ? c_yellow : c_green); - const auto raw1 = fmt::format("%s (%4.1f%%)", npart_min_str.c_str(), load_min); - const auto raw2 = fmt::format("%s (%4.1f%%)", npart_max_str.c_str(), load_max); - os << c_bblack - << fmt::pad(tot_npart_str, 20, '.', false).substr(0, 20 - tot_npart_str.size()) - << c_reset << tot_npart_str; - os << fmt::pad(raw1, 20, ' ', false).substr(0, 20 - raw1.size()) - << fmt::format("%s (%s%4.1f%%%s)", - npart_min_str.c_str(), - c_loadmin.c_str(), - load_min, - c_reset.c_str()); - os << fmt::pad(raw2, 20, ' ', false).substr(0, 20 - raw2.size()) - << fmt::format("%s (%s%4.1f%%%s)", - npart_max_str.c_str(), - c_loadmax.c_str(), - load_max, - c_reset.c_str()); -#else // not MPI_ENABLED - auto load = 100.0 * (double)(npart) / (double)(maxnpart); - auto npart_str = npart > 9999 ? fmt::format("%.2Le", (long double)npart) - : std::to_string(npart); - const auto c_bblack = color::get_color("bblack", flags & Diag::Colorful); - const auto c_red = color::get_color("red", flags & Diag::Colorful); - const auto c_yellow = color::get_color("yellow", flags & Diag::Colorful); - const auto c_green = color::get_color("green", flags & Diag::Colorful); - const auto c_reset = color::get_color("reset", flags & Diag::Colorful); - const auto c_load = (load > 80) - ? c_red.c_str() - : ((load > 50) ? c_yellow.c_str() : c_green.c_str()); - os << " species " << species_index << " (" << species_label << ")"; - const auto raw = fmt::format("%s (%4.1f%%)", npart_str.c_str(), load); - os << c_bblack << fmt::pad(raw, 24, '.').substr(0, 24 - raw.size()) << c_reset; - os << fmt::format("%s (%s%4.1f%%%s)", - npart_str.c_str(), - c_load, - load, - c_reset.c_str()); -#endif - os << std::endl; - } - - template class Engine>; - template class Engine>; - template class Engine>; - template class Engine>; - template class Engine>; - template class Engine>; - template class Engine>; - template class Engine>; -} // namespace ntt diff --git a/src/global/CMakeLists.txt b/src/global/CMakeLists.txt index f8bd7ab07..334ce078d 100644 --- a/src/global/CMakeLists.txt +++ b/src/global/CMakeLists.txt @@ -5,6 +5,9 @@ # - arch/kokkos_aliases.cpp # - utils/cargs.cpp # - utils/param_container.cpp +# - utils/timer.cpp +# - utils/diag.cpp +# - utils/progressbar.cpp # @includes: # - ./ # @uses: @@ -18,6 +21,9 @@ set(SOURCES ${SRC_DIR}/global.cpp ${SRC_DIR}/arch/kokkos_aliases.cpp ${SRC_DIR}/utils/cargs.cpp + ${SRC_DIR}/utils/timer.cpp + ${SRC_DIR}/utils/diag.cpp + ${SRC_DIR}/utils/progressbar.cpp ) if (${output}) list(APPEND SOURCES ${SRC_DIR}/utils/param_container.cpp) diff --git a/src/global/arch/mpi_aliases.h b/src/global/arch/mpi_aliases.h index 9669d6210..1f9a87f7b 100644 --- a/src/global/arch/mpi_aliases.h +++ b/src/global/arch/mpi_aliases.h @@ -14,6 +14,7 @@ #ifndef GLOBAL_ARCH_MPI_ALIASES_H #define GLOBAL_ARCH_MPI_ALIASES_H +#include #include #if defined(MPI_ENABLED) @@ -103,4 +104,4 @@ namespace mpi { #endif // MPI_ENABLED -#endif // GLOBAL_ARCH_MPI_ALIASES_H \ No newline at end of file +#endif // GLOBAL_ARCH_MPI_ALIASES_H diff --git a/src/global/global.h b/src/global/global.h index b3f640295..ad524fb0e 100644 --- a/src/global/global.h +++ b/src/global/global.h @@ -205,18 +205,14 @@ typedef int PrepareOutputFlags; namespace Timer { enum TimerFlags_ { None = 0, - PrintRelative = 1 << 0, - PrintUnits = 1 << 1, - PrintIndents = 1 << 2, - PrintTotal = 1 << 3, - PrintTitle = 1 << 4, - AutoConvert = 1 << 5, - Colorful = 1 << 6, - PrintOutput = 1 << 7, - PrintSorting = 1 << 8, - PrintCheckpoint = 1 << 9, - Default = PrintRelative | PrintUnits | PrintIndents | PrintTotal | - PrintTitle | AutoConvert | Colorful, + PrintTotal = 1 << 0, + PrintTitle = 1 << 1, + AutoConvert = 1 << 2, + PrintOutput = 1 << 3, + PrintSorting = 1 << 4, + PrintCheckpoint = 1 << 5, + PrintNormed = 1 << 6, + Default = PrintNormed | PrintTotal | PrintTitle | AutoConvert, }; } // namespace Timer diff --git a/src/global/utils/colors.h b/src/global/utils/colors.h index 512ad81c7..6f5e775cf 100644 --- a/src/global/utils/colors.h +++ b/src/global/utils/colors.h @@ -53,7 +53,8 @@ namespace color { return msg_nocol; } - inline auto get_color(const std::string& s, bool eight_bit) -> std::string { + inline auto get_color(const std::string& s, bool eight_bit = true) + -> std::string { if (not eight_bit) { return ""; } else { diff --git a/src/global/utils/diag.cpp b/src/global/utils/diag.cpp new file mode 100644 index 000000000..0a499dd56 --- /dev/null +++ b/src/global/utils/diag.cpp @@ -0,0 +1,246 @@ +#include "utils/diag.h" + +#include "global.h" + +#include "utils/colors.h" +#include "utils/formatting.h" +#include "utils/progressbar.h" +#include "utils/timer.h" + +#if defined(MPI_ENABLED) + #include "arch/mpi_aliases.h" + + #include +#endif // MPI_ENABLED + +#include +#include +#include +#include +#include +#include + +namespace diag { + auto npart_stats(std::size_t npart, std::size_t maxnpart) + -> std::vector> { + auto stats = std::vector>(); +#if !defined(MPI_ENABLED) + stats.push_back( + { npart, + static_cast( + 100.0f * static_cast(npart) / static_cast(maxnpart)) }); +#else + int rank, size; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Comm_size(MPI_COMM_WORLD, &size); + std::vector mpi_npart(size, 0); + std::vector mpi_maxnpart(size, 0); + MPI_Gather(&npart, + 1, + mpi::get_type(), + mpi_npart.data(), + 1, + mpi::get_type(), + MPI_ROOT_RANK, + MPI_COMM_WORLD); + MPI_Gather(&maxnpart, + 1, + mpi::get_type(), + mpi_maxnpart.data(), + 1, + mpi::get_type(), + MPI_ROOT_RANK, + MPI_COMM_WORLD); + if (rank != MPI_ROOT_RANK) { + return stats; + } + auto tot_npart = std::accumulate(mpi_npart.begin(), mpi_npart.end(), 0); + const auto max_idx = std::distance( + mpi_npart.begin(), + std::max_element(mpi_npart.begin(), mpi_npart.end())); + const auto min_idx = std::distance( + mpi_npart.begin(), + std::min_element(mpi_npart.begin(), mpi_npart.end())); + stats.push_back({ tot_npart, 0u }); + stats.push_back({ mpi_npart[min_idx], + static_cast( + 100.0f * static_cast(mpi_npart[min_idx]) / + static_cast(mpi_maxnpart[min_idx])) }); + stats.push_back({ mpi_npart[max_idx], + static_cast( + 100.0f * static_cast(mpi_npart[max_idx]) / + static_cast(mpi_maxnpart[max_idx])) }); +#endif + return stats; + } + + void printDiagnostics(std::size_t step, + std::size_t tot_steps, + long double time, + long double dt, + timer::Timers& timers, + pbar::DurationHistory& time_history, + std::size_t ncells, + const std::vector& species_labels, + const std::vector& species_npart, + const std::vector& species_maxnpart, + bool print_sorting, + bool print_output, + bool print_checkpoint, + bool print_colors) { + DiagFlags diag_flags = Diag::Default; + TimerFlags timer_flags = Timer::Default; + if (not print_colors) { + diag_flags ^= Diag::Colorful; + } + if (species_labels.size() == 0) { + diag_flags ^= Diag::Species; + } + if (print_sorting) { + timer_flags |= Timer::PrintSorting; + } + if (print_output) { + timer_flags |= Timer::PrintOutput; + } + if (print_checkpoint) { + timer_flags |= Timer::PrintCheckpoint; + } + + std::stringstream ss; + + const auto c_red = color::get_color("red"); + const auto c_yellow = color::get_color("yellow"); + const auto c_green = color::get_color("green"); + const auto c_bgreen = color::get_color("bgreen"); + const auto c_bblack = color::get_color("bblack"); + const auto c_reset = color::get_color("reset"); + + // basic info + CallOnce([&]() { + ss << fmt::alignedTable( + { "Step:", fmt::format("%lu", step), fmt::format("[of %lu]", tot_steps) }, + { c_reset, c_bgreen, c_bblack }, + { 0, -6, -15 }, + { ' ', ' ', ' ' }, + c_bblack, + c_reset); + + ss << fmt::alignedTable( + { "Time:", fmt::format("%.4Lf", time), fmt::format("[Δt = %.4Lf]", dt) }, + { c_reset, c_bgreen, c_bblack }, + { 0, -6, -15 }, + { ' ', ' ', ' ' }, + c_bblack, + c_reset); + }); + + // substep timers + if (diag_flags & Diag::Timers) { + const auto total_npart = std::accumulate(species_npart.begin(), + species_npart.end(), + 0); + const auto timer_diag = timers.printAll(timer_flags, total_npart, ncells); + CallOnce([&]() { + ss << std::endl << timer_diag << std::endl; + }); + } + + // particle counts + if (diag_flags & Diag::Species) { +#if defined(MPI_ENABLED) + CallOnce([&]() { + ss << fmt::alignedTable( + { "[PARTICLE SPECIES]", "[TOTAL]", "[% MIN", "MAX]", "[MIN", "MAX]" }, + { c_bblack, c_bblack, c_bblack, c_bblack, c_bblack, c_bblack }, + { 0, 37, 45, -48, 63, -66 }, + { ' ', ' ', ' ', ':', ' ', ':' }, + c_bblack, + c_reset); + }); +#else + CallOnce([&]() { + ss << fmt::alignedTable({ "[PARTICLE SPECIES]", "[TOTAL]", "[% TOT]" }, + { c_bblack, c_bblack, c_bblack }, + { 0, 37, 45 }, + { ' ', ' ', ' ' }, + c_bblack, + c_reset); + }); +#endif + for (std::size_t i = 0; i < species_labels.size(); ++i) { + const auto part_stats = npart_stats(species_npart[i], species_maxnpart[i]); + if (part_stats.size() == 0) { + continue; + } + const auto tot_npart = part_stats[0].first; +#if defined(MPI_ENABLED) + const auto min_npart = part_stats[1].first; + const auto min_pct = part_stats[1].second; + const auto max_npart = part_stats[2].first; + const auto max_pct = part_stats[2].second; + ss << fmt::alignedTable( + { + fmt::format("species %2lu (%s)", i, species_labels[i].c_str()), + tot_npart > 9999 ? fmt::format("%.2Le", (long double)tot_npart) + : std::to_string(tot_npart), + std::to_string(min_pct) + "%", + std::to_string(max_pct) + "%", + min_npart > 9999 ? fmt::format("%.2Le", (long double)min_npart) + : std::to_string(min_npart), + max_npart > 9999 ? fmt::format("%.2Le", (long double)max_npart) + : std::to_string(max_npart), + }, + { + c_reset, + c_reset, + (min_pct > 80) ? c_red : ((min_pct > 50) ? c_yellow : c_green), + (max_pct > 80) ? c_red : ((max_pct > 50) ? c_yellow : c_green), + c_reset, + c_reset, + }, + { -2, 37, 45, -48, 63, -66 }, + { ' ', '.', ' ', ':', ' ', ':' }, + c_bblack, + c_reset); +#else + const auto tot_pct = part_stats[0].second; + ss << fmt::alignedTable( + { + fmt::format("species %2lu (%s)", i, species_labels[i].c_str()), + tot_npart > 9999 ? fmt::format("%.2Le", (long double)tot_npart) + : std::to_string(tot_npart), + std::to_string(tot_pct) + "%", + }, + { + c_reset, + c_reset, + (tot_pct > 80) ? c_red : ((tot_pct > 50) ? c_yellow : c_green), + }, + { -2, 37, 45 }, + { ' ', '.', ' ' }, + c_bblack, + c_reset); +#endif + } + CallOnce([&]() { + ss << std::endl; + }); + } + + // progress bar + if (diag_flags & Diag::Progress) { + const auto progbar = pbar::ProgressBar(time_history, step, tot_steps, diag_flags); + CallOnce([&]() { + ss << progbar; + }); + } + + // separator + CallOnce([&]() { + ss << std::setw(80) << std::setfill('.') << "" << std::endl << std::endl; + }); + + std::cout << ((diag_flags & Diag::Colorful) ? ss.str() + : color::strip(ss.str())); + } +} // namespace diag diff --git a/src/global/utils/diag.h b/src/global/utils/diag.h new file mode 100644 index 000000000..9951602f8 --- /dev/null +++ b/src/global/utils/diag.h @@ -0,0 +1,59 @@ +/** + * @file utils/diag.h + * @brief Routines for diagnostics output at every step + * @implements + * - diag::printDiagnostics -> void + * @cpp: + * - diag.cpp + * @namespces: + * - diag:: + * @macros: + * - MPI_ENABLED + */ + +#ifndef GLOBAL_UTILS_DIAG_H +#define GLOBAL_UTILS_DIAG_H + +#include "utils/progressbar.h" +#include "utils/timer.h" + +#include +#include + +namespace diag { + + /** + * @brief Print diagnostics to the console + * @param step + * @param tot_steps + * @param time + * @param dt + * @param timers + * @param duration_history + * @param ncells (total) + * @param species_labels (vector of particle labels) + * @param npart (per each species) + * @param maxnpart (per each species) + * @param sorting_step (if true, particles were sorted) + * @param output_step (if true, output was written) + * @param checkpoint_step (if true, checkpoint was written) + * @param colorful_print (if true, print with colors) + */ + void printDiagnostics(std::size_t, + std::size_t, + long double, + long double, + timer::Timers&, + pbar::DurationHistory&, + std::size_t, + const std::vector&, + const std::vector&, + const std::vector&, + bool, + bool, + bool, + bool); + +} // namespace diag + +#endif // GLOBAL_UTILS_DIAG_H diff --git a/src/global/utils/formatting.h b/src/global/utils/formatting.h index 85f4e4b43..8dc7b6ba8 100644 --- a/src/global/utils/formatting.h +++ b/src/global/utils/formatting.h @@ -8,6 +8,8 @@ * - fmt::splitString -> std::vector * - fmt::repeat -> std::string * - fmt::formatVector -> std::string + * - fmt::strlen_utf8 -> std::size_t + * - fmt::alignedTable -> std::string * @namespaces: * - fmt:: */ @@ -132,6 +134,66 @@ namespace fmt { return result; } + inline auto repeat(char s, std::size_t n) -> std::string { + return repeat(std::string(1, s), n); + } + + /** + * @brief Calculate the length of a UTF-8 string + * @param str UTF-8 string + */ + inline auto strlenUTF8(const std::string& str) -> std::size_t { + std::size_t length = 0; + for (char c : str) { + if ((c & 0xC0) != 0x80) { + ++length; + } + } + return length; + } + + /** + * @brief Create a table with aligned columns and custom colors & separators + * @param columns Vector of column strings + * @param colors Vector of colors + * @param anchors Vector of column anchors (position of edge, negative means left-align) + * @param fillers Vector of separators + * @param c_bblack Black color + * @param c_reset Reset color + */ + inline auto alignedTable(const std::vector& columns, + const std::vector& colors, + const std::vector& anchors, + const std::vector& fillers, + const std::string& c_bblack, + const std::string& c_reset) -> std::string { + std::string result { c_reset }; + std::size_t cntr { 0 }; + for (auto i { 0u }; i < columns.size(); ++i) { + const auto anch { static_cast(anchors[i] < 0 ? -anchors[i] + : anchors[i]) }; + const auto leftalign { anchors[i] <= 0 }; + const auto cmn { columns[i] }; + const auto cmn_len { strlenUTF8(cmn) }; + std::string left { c_bblack }; + if (leftalign) { + if (fillers[i] == ':') { + left += " :"; + left += repeat(' ', anch - cntr - 2); + } else { + left += repeat(fillers[i], anch - cntr); + } + cntr += anch - cntr; + } else { + left += repeat(fillers[i], anch - cntr - cmn_len); + cntr += anch - cntr - cmn_len; + } + result += left + colors[i] + cmn + c_reset; + cntr += cmn_len; + } + return result + c_reset + "\n"; + } + } // namespace fmt #endif // GLOBAL_UTILS_FORMATTING_H diff --git a/src/global/utils/log.h b/src/global/utils/log.h index ac5bc4059..2434414a4 100644 --- a/src/global/utils/log.h +++ b/src/global/utils/log.h @@ -34,6 +34,8 @@ #endif namespace raise { + using namespace files; + inline void Warning(const std::string& msg, const std::string& file, const std::string& func, diff --git a/src/global/utils/progressbar.cpp b/src/global/utils/progressbar.cpp new file mode 100644 index 000000000..74f952382 --- /dev/null +++ b/src/global/utils/progressbar.cpp @@ -0,0 +1,120 @@ +#include "utils/progressbar.h" + +#include "utils/error.h" +#include "utils/formatting.h" + +#if defined(MPI_ENABLED) + #include "arch/mpi_aliases.h" + + #include +#endif // MPI_ENABLED + +#include +#include +#include +#include +#include +#include +#include + +namespace pbar { + + auto normalize_duration_fmt(long double t, const std::string& u) + -> std::pair { + const std::vector> units { + {"µs", 1e0}, + { "ms", 1e3}, + { "s", 1e6}, + {"min", 6e7}, + { "hr", 3.6e9} + }; + auto it = std::find_if(units.begin(), units.end(), [&u](const auto& pr) { + return pr.first == u; + }); + int u_idx = (it != units.end()) ? std::distance(units.begin(), it) : -1; + raise::ErrorIf(u_idx < 0, "Invalid unit", HERE); + int shift = 0; + if (t < 1) { + shift = -1; + } else if (1e3 <= t && t < 1e6) { + shift = 1; + } else if (1e6 <= t && t < 6e7) { + shift += 2; + } else if (6e7 <= t && t < 3.6e9) { + shift += 3; + } else if (3.6e9 <= t) { + shift += 4; + } + auto newu_idx = std::min(std::max(0, u_idx + shift), + static_cast(units.size())); + return { t * (units[u_idx].second / units[newu_idx].second), + units[newu_idx].first }; + } + + auto to_human_readable(long double t, const std::string& u) -> std::string { + const auto [tt, tu] = normalize_duration_fmt(t, u); + const auto t1 = static_cast(tt); + const auto t2 = tt - static_cast(t1); + const auto [tt2, tu2] = normalize_duration_fmt(t2, tu); + return fmt::format("%d%s %d%s", t1, tu.c_str(), static_cast(tt2), tu2.c_str()); + } + + auto ProgressBar(const DurationHistory& history, + std::size_t step, + std::size_t max_steps, + DiagFlags& flags) -> std::string { + auto avg_duration = history.average(); + +#if defined(MPI_ENABLED) + int rank, size; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Comm_size(MPI_COMM_WORLD, &size); + std::vector mpi_avg_durations(size, 0.0); + MPI_Gather(&avg_duration, + 1, + mpi::get_type(), + mpi_avg_durations.data(), + 1, + mpi::get_type(), + MPI_ROOT_RANK, + MPI_COMM_WORLD); + if (rank != MPI_ROOT_RANK) { + return ""; + } + avg_duration = *std::max_element(mpi_avg_durations.begin(), + mpi_avg_durations.end()); +#endif + + const auto avg = to_human_readable(avg_duration, "µs"); + const auto elapsed = to_human_readable(history.elapsed(), "µs"); + const auto remain = to_human_readable( + static_cast(max_steps - step) * avg_duration, + "µs"); + + const auto pct = static_cast(step) / + static_cast(max_steps); + const int nfilled = std::min(static_cast(pct * params::width), + params::width); + const int nempty = params::width - nfilled; + const auto c_bmagenta = color::get_color("bmagenta", flags & Diag::Colorful); + const auto c_reset = color::get_color("reset", flags & Diag::Colorful); + + std::stringstream ss; + + ss << "Timestep duration: " << c_bmagenta << avg << c_reset << std::endl; + ss << "Remaining time: " << c_bmagenta << remain << c_reset << std::endl; + ss << "Elapsed time: " << c_bmagenta << elapsed << c_reset << std::endl; + ss << params::start; + for (auto i { 0 }; i < nfilled; ++i) { + ss << params::fill; + } + for (auto i { 0 }; i < nempty; ++i) { + ss << params::empty; + } + ss << params::end << " " << std::fixed << std::setprecision(2) + << std::setfill(' ') << std::setw(6) << std::right << pct * 100.0 << "%\n"; + + return ss.str(); + } + +} // namespace pbar diff --git a/src/global/utils/progressbar.h b/src/global/utils/progressbar.h index ccbc6215e..f218bc3f4 100644 --- a/src/global/utils/progressbar.h +++ b/src/global/utils/progressbar.h @@ -3,6 +3,8 @@ * @brief Progress bar for logging the simulation progress * @implements * - pbar::ProgressBar -> void + * @cpp: + * - progressbar.cpp * @namespaces: * - pbar:: * @macros: @@ -16,22 +18,15 @@ #include "utils/colors.h" #include "utils/error.h" +#include "utils/formatting.h" #include -#include -#include #include #include #include #include #include -#if defined(MPI_ENABLED) - #include "arch/mpi_aliases.h" - - #include -#endif // MPI_ENABLED - namespace pbar { namespace params { inline constexpr int width { 70 }; @@ -81,96 +76,15 @@ namespace pbar { } }; - inline auto normalize_duration_fmt(long double t, const std::string& u) - -> std::pair { - const std::vector> units { - {"µs", 1e0}, - { "ms", 1e3}, - { "s", 1e6}, - {"min", 6e7}, - { "hr", 3.6e9} - }; - auto it = std::find_if(units.begin(), units.end(), [&u](const auto& pr) { - return pr.first == u; - }); - int u_idx = (it != units.end()) ? std::distance(units.begin(), it) : -1; - raise::ErrorIf(u_idx < 0, "Invalid unit", HERE); - int shift = 0; - if (t < 1e-2) { - shift = -1; - } else if (1e3 <= t && t < 1e6) { - shift = 1; - } else if (1e6 <= t && t < 6e7) { - shift += 2; - } else if (6e7 <= t && t < 3.6e9) { - shift += 3; - } else if (3.6e9 <= t) { - shift += 4; - } - auto newu_idx = std::min(std::max(0, u_idx + shift), - static_cast(units.size())); - return { t * (units[u_idx].second / units[newu_idx].second), - units[newu_idx].first }; - } - - inline void ProgressBar(const DurationHistory& history, - std::size_t step, - std::size_t max_steps, - DiagFlags& flags, - std::ostream& os = std::cout) { - auto avg_duration = history.average(); + auto normalize_duration_fmt(long double t, const std::string& u) + -> std::pair; -#if defined(MPI_ENABLED) - int rank, size; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - MPI_Comm_size(MPI_COMM_WORLD, &size); - std::vector mpi_avg_durations(size, 0.0); - MPI_Gather(&avg_duration, - 1, - mpi::get_type(), - mpi_avg_durations.data(), - 1, - mpi::get_type(), - MPI_ROOT_RANK, - MPI_COMM_WORLD); - if (rank != MPI_ROOT_RANK) { - return; - } - avg_duration = *std::max_element(mpi_avg_durations.begin(), - mpi_avg_durations.end()); -#endif - auto [avg_reduced, avg_units] = normalize_duration_fmt(avg_duration, "µs"); - - const auto remain_nsteps = max_steps - step; - auto [remain_time, remain_units] = normalize_duration_fmt( - static_cast(remain_nsteps) * avg_duration, - "µs"); - auto [elapsed_time, - elapsed_units] = normalize_duration_fmt(history.elapsed(), "µs"); + auto to_human_readable(long double t, const std::string& u) -> std::string; - const auto pct = static_cast(step) / - static_cast(max_steps); - const int nfilled = std::min(static_cast(pct * params::width), - params::width); - const int nempty = params::width - nfilled; - const auto c_bmagenta = color::get_color("bmagenta", flags & Diag::Colorful); - const auto c_reset = color::get_color("reset", flags & Diag::Colorful); - os << "Average timestep: " << c_bmagenta << avg_reduced << " " << avg_units - << c_reset << std::endl; - os << "Remaining time: " << c_bmagenta << remain_time << " " << remain_units - << c_reset << std::endl; - os << "Elapsed time: " << c_bmagenta << elapsed_time << " " << elapsed_units - << c_reset << std::endl; - os << params::start; - for (auto i { 0 }; i < nfilled; ++i) { - os << params::fill; - } - for (auto i { 0 }; i < nempty; ++i) { - os << params::empty; - } - os << params::end << " " << std::fixed << std::setprecision(2) - << std::setfill(' ') << std::setw(6) << std::right << pct * 100.0 << "%\n"; - } + auto ProgressBar(const DurationHistory& history, + std::size_t step, + std::size_t max_steps, + DiagFlags& flags) -> std::string; } // namespace pbar diff --git a/src/global/utils/timer.cpp b/src/global/utils/timer.cpp new file mode 100644 index 000000000..1a1a37848 --- /dev/null +++ b/src/global/utils/timer.cpp @@ -0,0 +1,279 @@ +#include "utils/timer.h" + +#include "utils/colors.h" +#include "utils/formatting.h" + +#if defined(MPI_ENABLED) + #include "arch/mpi_aliases.h" + + #include +#endif // MPI_ENABLED + +#include +#include +#include +#include +#include + +namespace timer { + + auto Timers::gather(const std::vector& ignore_in_tot, + std::size_t npart, + std::size_t ncells) const + -> std::map> { + auto timer_stats = std::map< + std::string, + std::tuple> {}; +#if defined(MPI_ENABLED) + int rank, size; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Comm_size(MPI_COMM_WORLD, &size); + std::map> all_timers {}; + + // accumulate timers from MPI blocks + for (auto& [name, timer] : m_timers) { + all_timers.insert({ name, std::vector(size, 0.0) }); + MPI_Gather(&timer.second, + 1, + mpi::get_type(), + all_timers[name].data(), + 1, + mpi::get_type(), + MPI_ROOT_RANK, + MPI_COMM_WORLD); + } + // accumulate nparts and ncells from MPI blocks + auto all_nparts = std::vector(size, 0); + auto all_ncells = std::vector(size, 0); + MPI_Gather(&npart, + 1, + mpi::get_type(), + all_nparts.data(), + 1, + mpi::get_type(), + MPI_ROOT_RANK, + MPI_COMM_WORLD); + MPI_Gather(&ncells, + 1, + mpi::get_type(), + all_ncells.data(), + 1, + mpi::get_type(), + MPI_ROOT_RANK, + MPI_COMM_WORLD); + if (rank != MPI_ROOT_RANK) { + return {}; + } + std::vector all_totals(size, 0.0); + for (auto i { 0u }; i < size; ++i) { + for (auto& [name, timer] : m_timers) { + if (std::find(ignore_in_tot.begin(), ignore_in_tot.end(), name) == + ignore_in_tot.end()) { + all_totals[i] += all_timers[name][i]; + } + } + } + for (auto& [name, timer] : m_timers) { + const auto max_time = *std::max_element(all_timers[name].begin(), + all_timers[name].end()); + const auto max_idx = std::distance( + all_timers[name].begin(), + std::max_element(all_timers[name].begin(), all_timers[name].end())); + + const auto per_npart = all_nparts[max_idx] > 0 + ? max_time / + static_cast(all_nparts[max_idx]) + : 0.0; + const auto per_ncells = all_ncells[max_idx] > 0 + ? max_time / + static_cast(all_ncells[max_idx]) + : 0.0; + const auto pcent = static_cast( + (max_time / all_totals[max_idx]) * 100.0); + timer_stats.insert( + { name, + std::make_tuple(max_time, + per_npart, + per_ncells, + pcent, + tools::ArrayImbalance(all_timers[name])) }); + } + const auto max_tot = *std::max_element(all_totals.begin(), all_totals.end()); + const auto tot_imb = tools::ArrayImbalance(all_totals); + timer_stats.insert( + { "Total", std::make_tuple(max_tot, 0.0, 0.0, 100u, tot_imb) }); +#else + duration_t local_tot = 0.0; + for (auto& [name, timer] : m_timers) { + if (std::find(ignore_in_tot.begin(), ignore_in_tot.end(), name) == + ignore_in_tot.end()) { + local_tot += timer.second; + } + } + for (auto& [name, timer] : m_timers) { + const auto pcent = static_cast( + (timer.second / local_tot) * 100.0); + timer_stats.insert( + { name, std::make_tuple(timer.second, pcent, 0.0, 0u, 0u) }); + } + timer_stats.insert({ "Total", std::make_tuple(local_tot, 0.0, 0.0, 100u, 0u) }); +#endif + return timer_stats; + } + + auto Timers::printAll(TimerFlags flags, std::size_t npart, std::size_t ncells) const + -> std::string { + const std::vector extras { "Sorting", "Output", "Checkpoint" }; + const auto stats = gather(extras, npart, ncells); + if (stats.empty()) { + return ""; + } + +#if defined(MPI_ENABLED) + const auto multi_rank = true; +#else + const auto multi_rank = false; +#endif + + std::stringstream ss; + + const auto c_bblack = color::get_color("bblack"); + const auto c_reset = color::get_color("reset"); + const auto c_byellow = color::get_color("byellow"); + const auto c_blue = color::get_color("blue"); + const auto c_red = color::get_color("red"); + const auto c_yellow = color::get_color("yellow"); + const auto c_green = color::get_color("green"); + + if (multi_rank and flags & Timer::PrintTitle) { + ss << fmt::alignedTable( + { "[SUBSTEP]", "[MAX DURATION]", "[% TOT", "VAR]", "[per PRTL", "CELL]" }, + { c_bblack, c_bblack, c_bblack, c_bblack, c_bblack, c_bblack }, + { 0, 37, 45, -48, 63, -66 }, + { ' ', '.', ' ', ':', ' ', ':' }, + c_bblack, + c_reset); + } else { + ss << fmt::alignedTable( + { "[SUBSTEP]", "[DURATION]", "[% TOT]", "[per PRTL", "CELL]" }, + { c_bblack, c_bblack, c_bblack, c_bblack, c_bblack }, + { 0, 37, 45, 55, -58 }, + { ' ', '.', ' ', ' ', ':' }, + c_bblack, + c_reset); + } + + for (auto& [name, timers] : m_timers) { + if (std::find(extras.begin(), extras.end(), name) != extras.end()) { + continue; + } + std::string units = "µs", units_npart = "µs", units_ncells = "µs"; + auto time = std::get<0>(stats.at(name)); + auto per_npart = std::get<1>(stats.at(name)); + auto per_ncells = std::get<2>(stats.at(name)); + const auto tot_pct = std::get<3>(stats.at(name)); + const auto var_pct = std::get<4>(stats.at(name)); + if (flags & Timer::AutoConvert) { + convertTime(time, units); + convertTime(per_npart, units_npart); + convertTime(per_ncells, units_ncells); + } + + if (multi_rank) { + ss << fmt::alignedTable( + { name, + fmt::format("%.2Lf", time) + " " + units, + std::to_string(tot_pct) + "%", + std::to_string(var_pct) + "%", + fmt::format("%.2Lf", per_npart) + " " + units_npart, + fmt::format("%.2Lf", per_ncells) + " " + units_ncells }, + { c_reset, + c_yellow, + ((tot_pct > 60) ? c_red : ((tot_pct > 40) ? c_yellow : c_green)), + ((var_pct > 50) ? c_red : ((var_pct > 30) ? c_yellow : c_green)), + c_yellow, + c_yellow }, + { -2, 37, 45, -48, 63, -66 }, + { ' ', '.', ' ', ':', ' ', ':' }, + c_bblack, + c_reset); + } else { + ss << fmt::alignedTable( + { name, + fmt::format("%.2Lf", time) + " " + units, + std::to_string(tot_pct) + "%", + fmt::format("%.2Lf", per_npart) + " " + units_npart, + fmt::format("%.2Lf", per_ncells) + " " + units_ncells }, + { c_reset, + c_yellow, + ((tot_pct > 60) ? c_red : ((tot_pct > 40) ? c_yellow : c_green)), + c_yellow, + c_yellow }, + { -2, 37, 45, 55, -58 }, + { ' ', '.', ' ', ' ', ':' }, + c_bblack, + c_reset); + } + } + + // total + if (flags & Timer::PrintTotal) { + std::string units = "µs"; + auto time = std::get<0>(stats.at("Total")); + const auto var_pct = std::get<4>(stats.at("Total")); + if (flags & Timer::AutoConvert) { + convertTime(time, units); + } + if (multi_rank) { + ss << fmt::alignedTable( + { "Total", + fmt::format("%.2Lf", time) + " " + units, + std::to_string(var_pct) + "%" }, + { c_reset, + c_blue, + ((var_pct > 50) ? c_red : ((var_pct > 30) ? c_yellow : c_green)) }, + { 0, 37, -48 }, + { ' ', ' ', ' ' }, + c_bblack, + c_reset); + } else { + ss << fmt::alignedTable( + { "Total", fmt::format("%.2Lf", time) + " " + units }, + { c_reset, c_blue }, + { 0, 37 }, + { ' ', ' ' }, + c_bblack, + c_reset); + } + } + + // print extra timers for output/checkpoint/sorting + const std::vector extras_f { Timer::PrintSorting, + Timer::PrintOutput, + Timer::PrintCheckpoint }; + for (auto i { 0u }; i < extras.size(); ++i) { + const auto name = extras[i]; + const auto active = flags & extras_f[i]; + std::string units = "µs"; + auto time = std::get<0>(stats.at(name)); + const auto tot_pct = std::get<3>(stats.at(name)); + const auto var_pct = std::get<4>(stats.at(name)); + if (flags & Timer::AutoConvert) { + convertTime(time, units); + } + ss << fmt::alignedTable({ name, + fmt::format("%.2Lf", time) + " " + units, + std::to_string(tot_pct) + "%" }, + { (active ? c_reset : c_bblack), + (active ? c_byellow : c_bblack), + (active ? c_byellow : c_bblack) }, + { -2, 37, 45 }, + { ' ', '.', ' ' }, + c_bblack, + c_reset); + } + return ss.str(); + } + +} // namespace timer diff --git a/src/global/utils/timer.h b/src/global/utils/timer.h index 84356f7b3..3e9c1433e 100644 --- a/src/global/utils/timer.h +++ b/src/global/utils/timer.h @@ -4,6 +4,8 @@ * @implements * - timer::Timers * - enum timer::TimerFlags + * @cpp: + * - timer.cpp * @namespces: * - timer:: * @macros: @@ -21,21 +23,28 @@ #include "utils/error.h" #include "utils/formatting.h" #include "utils/numeric.h" +#include "utils/tools.h" + +#if defined(MPI_ENABLED) + #include "arch/mpi_aliases.h" + + #include +#endif // MPI_ENABLED #include #include -#include -#include #include #include #include +#include #include #include namespace timer { - using timestamp = std::chrono::time_point; + using timestamp = std::chrono::time_point; + using duration_t = long double; - inline void convertTime(long double& value, std::string& units) { + inline void convertTime(duration_t& value, std::string& units) { if (value > 1e6) { value /= 1e6; units = " s"; @@ -49,10 +58,10 @@ namespace timer { } class Timers { - std::map> m_timers; - std::vector m_names; - const bool m_blocking; - const std::function m_synchronize; + std::map> m_timers; + std::vector m_names; + const bool m_blocking; + const std::function m_synchronize; public: Timers(std::initializer_list names, @@ -103,9 +112,9 @@ namespace timer { } [[nodiscard]] - auto get(const std::string& name) const -> long double { + auto get(const std::string& name) const -> duration_t { if (name == "Total") { - long double total = 0.0; + duration_t total = 0.0; for (auto& timer : m_timers) { total += timer.second.second; } @@ -116,202 +125,29 @@ namespace timer { } } - void printAll(const TimerFlags flags = Timer::Default, - std::ostream& os = std::cout) const { -#if !defined(MPI_ENABLED) - std::string header = fmt::format("%s %27s", "[SUBSTEP]", "[DURATION]"); -#else - std::string header = fmt::format("%s %32s", "[SUBSTEP]", "[DURATION]"); -#endif - - const auto c_bblack = color::get_color("bblack", flags & Timer::Colorful); - const auto c_reset = color::get_color("reset", flags & Timer::Colorful); - const auto c_byellow = color::get_color("byellow", flags & Timer::Colorful); - const auto c_blue = color::get_color("blue", flags & Timer::Colorful); + /** + * @brief Gather all timers from all ranks + * @param ignore_in_tot: vector of timer names to ignore in computing the total + * @return map: + * key: timer name + * value: vector of numbers + * - max duration across ranks + * - max duration per particle + * - max duration per cell + * - max duration as % of total on that rank + * - imbalance % of the given timer + */ + [[nodiscard]] + auto gather(const std::vector& ignore_in_tot, + std::size_t npart, + std::size_t ncells) const + -> std::map>; - if (flags & Timer::PrintRelative) { - header += " [% TOT]"; - } -#if defined(MPI_ENABLED) - header += " [MIN : MAX]"; -#endif - header = c_bblack + header + c_reset; - CallOnce( - [](std::ostream& os, std::string header) { - os << header << std::endl; - }, - os, - header); -#if defined(MPI_ENABLED) - int rank, size; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - MPI_Comm_size(MPI_COMM_WORLD, &size); - std::map> mpi_timers {}; - // accumulate timers from MPI blocks - for (auto& [name, timer] : m_timers) { - mpi_timers[name] = std::vector(size, 0.0); - MPI_Gather(&timer.second, - 1, - mpi::get_type(), - mpi_timers[name].data(), - 1, - mpi::get_type(), - MPI_ROOT_RANK, - MPI_COMM_WORLD); - } - if (rank != MPI_ROOT_RANK) { - return; - } - long double total = 0.0; - for (auto& [name, timer] : m_timers) { - auto timers = mpi_timers[name]; - long double tot = std::accumulate(timers.begin(), timers.end(), 0.0); - if (name != "Output" and name != "Checkpoint") { - total += tot; - } - } - for (auto& [name, timers] : mpi_timers) { - // compute min, max, mean - long double min_time = *std::min_element(timers.begin(), timers.end()); - long double max_time = *std::max_element(timers.begin(), timers.end()); - long double mean_time = std::accumulate(timers.begin(), timers.end(), 0.0) / - size; - std::string mean_units = "µs"; - const auto min_pct = mean_time > ZERO - ? (int)(((mean_time - min_time) / mean_time) * 100.0) - : 0; - const auto max_pct = mean_time > ZERO - ? (int)(((max_time - mean_time) / mean_time) * 100.0) - : 0; - const auto tot_pct = (cmp::AlmostZero_host(total) - ? 0 - : (mean_time * size / total) * 100.0); - if (flags & Timer::AutoConvert) { - convertTime(mean_time, mean_units); - } - if (flags & Timer::PrintIndents) { - os << " "; - } - os << ((name != "Sorting" or flags & Timer::PrintSorting) ? c_reset - : c_bblack) - << name << c_reset << c_bblack - << fmt::pad(name, 20, '.', true).substr(name.size(), 20); - os << std::setw(17) << std::right << std::setfill('.') - << fmt::format("%s%.2Lf", - (name != "Sorting" or flags & Timer::PrintSorting) - ? c_byellow.c_str() - : c_bblack.c_str(), - mean_time); - if (flags & Timer::PrintUnits) { - os << " " << mean_units << " "; - } - if (flags & Timer::PrintRelative) { - os << " " << std::setw(5) << std::right << std::setfill(' ') - << std::fixed << std::setprecision(2) << tot_pct << "%"; - } - os << fmt::format("%+7s : %-7s", - fmt::format("-%d%%", min_pct).c_str(), - fmt::format("+%d%%", max_pct).c_str()); - os << c_reset << std::endl; - } - total /= size; -#else // not MPI_ENABLED - long double total = 0.0; - for (auto& [name, timer] : m_timers) { - if (name != "Output" and name != "Checkpoint") { - total += timer.second; - } - } - for (auto& [name, timer] : m_timers) { - if (name == "Output" or name == "Checkpoint") { - continue; - } - std::string units = "µs"; - auto value = timer.second; - if (flags & Timer::AutoConvert) { - convertTime(value, units); - } - if (flags & Timer::PrintIndents) { - os << " "; - } - os << ((name != "Sorting" or flags & Timer::PrintSorting) ? c_reset - : c_bblack) - << name << c_bblack - << fmt::pad(name, 20, '.', true).substr(name.size(), 20); - os << std::setw(17) << std::right << std::setfill('.') - << fmt::format("%s%.2Lf", - (name != "Sorting" or flags & Timer::PrintSorting) - ? c_byellow.c_str() - : c_bblack.c_str(), - value); - if (flags & Timer::PrintUnits) { - os << " " << units; - } - if (flags & Timer::PrintRelative) { - os << " " << std::setw(7) << std::right << std::setfill(' ') - << std::fixed << std::setprecision(2) - << (cmp::AlmostZero_host(total) ? 0 : (timer.second / total) * 100.0); - } - os << c_reset << std::endl; - } -#endif // MPI_ENABLED - if (flags & Timer::PrintTotal) { - std::string units = "µs"; - auto value = total; - if (flags & Timer::AutoConvert) { - convertTime(value, units); - } -#if !defined(MPI_ENABLED) - os << c_bblack << std::setw(22) << std::left << std::setfill(' ') - << "Total" << c_reset; -#else - os << c_bblack << std::setw(27) << std::left << std::setfill(' ') - << "Total" << c_reset; -#endif - os << c_blue << std::setw(12) << std::right << std::setfill(' ') << value; - if (flags & Timer::PrintUnits) { - os << " " << units; - } - os << c_reset << std::endl; - } - { - std::string units = "µs"; - auto value = get("Output"); - if (flags & Timer::AutoConvert) { - convertTime(value, units); - } - os << ((flags & Timer::PrintOutput) ? c_reset : c_bblack) << "Output" - << c_bblack << fmt::pad("Output", 22, '.', true).substr(6, 22); - os << std::setw(17) << std::right << std::setfill('.') - << fmt::format("%s%.2Lf", - (flags & Timer::PrintOutput) ? c_byellow.c_str() - : c_bblack.c_str(), - value); - if (flags & Timer::PrintUnits) { - os << " " << units; - } - os << c_reset << std::endl; - } - { - std::string units = "µs"; - auto value = get("Checkpoint"); - if (flags & Timer::AutoConvert) { - convertTime(value, units); - } - os << ((flags & Timer::PrintCheckpoint) ? c_reset : c_bblack) - << "Checkpoint" << c_bblack - << fmt::pad("Checkpoint", 22, '.', true).substr(10, 22); - os << std::setw(17) << std::right << std::setfill('.') - << fmt::format("%s%.2Lf", - (flags & Timer::PrintCheckpoint) ? c_byellow.c_str() - : c_bblack.c_str(), - value); - if (flags & Timer::PrintUnits) { - os << " " << units; - } - os << c_reset << std::endl; - } - } + [[nodiscard]] + auto printAll(TimerFlags flags = Timer::Default, + std::size_t npart = 0, + std::size_t ncells = 0) const -> std::string; }; } // namespace timer diff --git a/src/global/utils/tools.h b/src/global/utils/tools.h index 96d948ae4..30687d01b 100644 --- a/src/global/utils/tools.h +++ b/src/global/utils/tools.h @@ -2,6 +2,7 @@ * @file utils/tools.h * @brief Helper functions for general use * @implements + * - tools::ArrayImbalance -> unsigned short * - tools::TensorProduct<> -> boundaries_t * - tools::decompose1D -> std::vector * - tools::divideInProportions2D -> std::tuple @@ -17,6 +18,8 @@ #include "global.h" +#include "arch/kokkos_aliases.h" +#include "utils/comparators.h" #include "utils/error.h" #include "utils/numeric.h" @@ -27,6 +30,30 @@ namespace tools { + /** + * @brief Compute the imbalance of a list of nonnegative values + * @param values List of values + * @return Imbalance of the list (0...100) + */ + template + auto ArrayImbalance(const std::vector& values) -> unsigned short { + raise::ErrorIf(values.empty(), "Disbalance error: value array is empty", HERE); + const auto mean = static_cast(std::accumulate(values.begin(), + values.end(), + static_cast(0))) / + static_cast(values.size()); + const auto sq_sum = static_cast(std::inner_product(values.begin(), + values.end(), + values.begin(), + static_cast(0))); + if (cmp::AlmostZero_host(sq_sum) || cmp::AlmostZero_host(mean)) { + return 0; + } + const auto cv = std::sqrt( + sq_sum / static_cast(values.size()) / mean - 1.0); + return static_cast(100.0 / (1.0 + math::exp(-cv))); + } + /** * @brief Compute a tensor product of a list of vectors * @param list List of vectors From fc3d9677f1d074e5bee53bf4028e980e97eed1f7 Mon Sep 17 00:00:00 2001 From: haykh Date: Fri, 16 Aug 2024 21:15:35 -0400 Subject: [PATCH 102/773] checkpoint read/write --- src/checkpoint/CMakeLists.txt | 2 + src/checkpoint/reader.cpp | 142 +++++++++++++++++ src/checkpoint/reader.h | 37 ++++- src/checkpoint/writer.cpp | 22 +-- src/engines/CMakeLists.txt | 2 - src/engines/engine.hpp | 1 - src/engines/engine_init.cpp | 9 ++ src/engines/engine_run.cpp | 37 +++-- src/framework/domain/checkpoint.cpp | 238 ++++++++++++++++++++++++++-- src/framework/domain/metadomain.cpp | 2 +- src/framework/domain/metadomain.h | 66 +++++++- src/framework/domain/output.cpp | 30 ++-- src/framework/parameters.cpp | 4 +- src/framework/parameters.h | 2 +- src/framework/simulation.cpp | 2 + 15 files changed, 539 insertions(+), 57 deletions(-) diff --git a/src/checkpoint/CMakeLists.txt b/src/checkpoint/CMakeLists.txt index 00c11ac04..d97bd4a34 100644 --- a/src/checkpoint/CMakeLists.txt +++ b/src/checkpoint/CMakeLists.txt @@ -2,6 +2,7 @@ # @defines: ntt_checkpoint [STATIC/SHARED] # @sources: # - writer.cpp +# - reader.cpp # @includes: # - ../ # @depends: @@ -15,6 +16,7 @@ set(SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}) set(SOURCES ${SRC_DIR}/writer.cpp + ${SRC_DIR}/reader.cpp ) add_library(ntt_checkpoint ${SOURCES}) diff --git a/src/checkpoint/reader.cpp b/src/checkpoint/reader.cpp index e69de29bb..c53661b45 100644 --- a/src/checkpoint/reader.cpp +++ b/src/checkpoint/reader.cpp @@ -0,0 +1,142 @@ +#include "checkpoint/reader.h" + +#include "global.h" + +#include "arch/kokkos_aliases.h" +#include "utils/error.h" +#include "utils/formatting.h" +#include "utils/log.h" + +#include +#include +#include + +#include +#include +#include + +namespace checkpoint { + + template + void ReadFields(adios2::IO& io, + adios2::Engine& reader, + const std::string& field, + const adios2::Box& range, + ndfield_t& array) { + logger::Checkpoint(fmt::format("Reading field: %s", field.c_str()), HERE); + auto field_var = io.InquireVariable(field); + field_var.SetStepSelection(adios2::Box({ 0 }, { 1 })); + field_var.SetSelection(range); + auto array_h = Kokkos::create_mirror_view(array); + reader.Get(field_var, array_h.data()); + Kokkos::deep_copy(array, array_h); + } + + auto ReadParticleCount(adios2::IO& io, + adios2::Engine& reader, + unsigned short s, + std::size_t local_dom, + std::size_t ndomains) + -> std::pair { + logger::Checkpoint(fmt::format("Reading particle count for: %d", s + 1), HERE); + auto npart_var = io.InquireVariable( + fmt::format("s%d_npart", s + 1)); + raise::ErrorIf( + npart_var.Shape()[0] != ndomains or npart_var.Shape().size() != 1, + "npart_var.Shape()[0] != ndomains or npart_var.Shape().size() != 1", + HERE); + npart_var.SetStepSelection(adios2::Box({ 0 }, { 1 })); + npart_var.SetSelection( + adios2::Box({ 0 }, { npart_var.Shape()[0] })); + std::vector nparts(ndomains); + reader.Get(npart_var, nparts.data(), adios2::Mode::Sync); + + const auto loc_npart = nparts[local_dom]; + std::size_t offset_npart = 0; + for (auto d { 0u }; d < local_dom; ++d) { + offset_npart += nparts[d]; + } + return { loc_npart, offset_npart }; + } + + template + void ReadParticleData(adios2::IO& io, + adios2::Engine& reader, + const std::string& quantity, + unsigned short s, + array_t& array, + std::size_t count, + std::size_t offset) { + logger::Checkpoint( + fmt::format("Reading quantity: s%d_%s", s + 1, quantity.c_str()), + HERE); + auto var = io.InquireVariable( + fmt::format("s%d_%s", s + 1, quantity.c_str())); + var.SetStepSelection(adios2::Box({ 0 }, { 1 })); + var.SetSelection(adios2::Box({ offset }, { count })); + auto array_h = Kokkos::create_mirror_view(array); + reader.Get(var, array_h.data()); + Kokkos::deep_copy(array, array_h); + } + + template void ReadFields(adios2::IO&, + adios2::Engine&, + const std::string&, + const adios2::Box&, + ndfield_t&); + template void ReadFields(adios2::IO&, + adios2::Engine&, + const std::string&, + const adios2::Box&, + ndfield_t&); + template void ReadFields(adios2::IO&, + adios2::Engine&, + const std::string&, + const adios2::Box&, + ndfield_t&); + template void ReadFields(adios2::IO&, + adios2::Engine&, + const std::string&, + const adios2::Box&, + ndfield_t&); + template void ReadFields(adios2::IO&, + adios2::Engine&, + const std::string&, + const adios2::Box&, + ndfield_t&); + template void ReadFields(adios2::IO&, + adios2::Engine&, + const std::string&, + const adios2::Box&, + ndfield_t&); + + template void ReadParticleData(adios2::IO&, + adios2::Engine&, + const std::string&, + unsigned short, + array_t&, + std::size_t, + std::size_t); + template void ReadParticleData(adios2::IO&, + adios2::Engine&, + const std::string&, + unsigned short, + array_t&, + std::size_t, + std::size_t); + template void ReadParticleData(adios2::IO&, + adios2::Engine&, + const std::string&, + unsigned short, + array_t&, + std::size_t, + std::size_t); + template void ReadParticleData(adios2::IO&, + adios2::Engine&, + const std::string&, + unsigned short, + array_t&, + std::size_t, + std::size_t); + +} // namespace checkpoint diff --git a/src/checkpoint/reader.h b/src/checkpoint/reader.h index ea8653e72..b2358647b 100644 --- a/src/checkpoint/reader.h +++ b/src/checkpoint/reader.h @@ -1,8 +1,9 @@ /** * @file checkpoint/reader.h - * @brief Class that reads checkpoints + * @brief Function for reading field & particle data from checkpoint files * @implements - * - checkpoint::Reader + * - checkpoint::ReadFields -> void + * - checkpoint::ReadParticleData -> void * @cpp: * - reader.cpp * @namespaces: @@ -12,8 +13,38 @@ #ifndef CHECKPOINT_READER_H #define CHECKPOINT_READER_H +#include "arch/kokkos_aliases.h" + +#include +#include + +#include +#include + namespace checkpoint { - class Reader {}; + + template + void ReadFields(adios2::IO&, + adios2::Engine&, + const std::string&, + const adios2::Box&, + ndfield_t&); + + auto ReadParticleCount(adios2::IO&, + adios2::Engine&, + unsigned short, + std::size_t, + std::size_t) -> std::pair; + + template + void ReadParticleData(adios2::IO&, + adios2::Engine&, + const std::string&, + unsigned short, + array_t&, + std::size_t, + std::size_t); + } // namespace checkpoint #endif // CHECKPOINT_READER_H diff --git a/src/checkpoint/writer.cpp b/src/checkpoint/writer.cpp index c584d13fe..1740c47aa 100644 --- a/src/checkpoint/writer.cpp +++ b/src/checkpoint/writer.cpp @@ -91,25 +91,25 @@ namespace checkpoint { { adios2::UnknownDim }, { adios2::UnknownDim }, { adios2::UnknownDim }); - m_io.DefineVariable(fmt::format("s%d_dx%d", s + 1, d + 1), - { adios2::UnknownDim }, - { adios2::UnknownDim }, - { adios2::UnknownDim }); + m_io.DefineVariable(fmt::format("s%d_dx%d", s + 1, d + 1), + { adios2::UnknownDim }, + { adios2::UnknownDim }, + { adios2::UnknownDim }); m_io.DefineVariable(fmt::format("s%d_i%d_prev", s + 1, d + 1), { adios2::UnknownDim }, { adios2::UnknownDim }, { adios2::UnknownDim }); - m_io.DefineVariable(fmt::format("s%d_dx%d_prev", s + 1, d + 1), - { adios2::UnknownDim }, - { adios2::UnknownDim }, - { adios2::UnknownDim }); - } - if (dim == Dim::_2D and C != ntt::Coord::Cart) { - m_io.DefineVariable(fmt::format("s%d_phi", s + 1), + m_io.DefineVariable(fmt::format("s%d_dx%d_prev", s + 1, d + 1), { adios2::UnknownDim }, { adios2::UnknownDim }, { adios2::UnknownDim }); } + if (dim == Dim::_2D and C != ntt::Coord::Cart) { + m_io.DefineVariable(fmt::format("s%d_phi", s + 1), + { adios2::UnknownDim }, + { adios2::UnknownDim }, + { adios2::UnknownDim }); + } for (auto d { 0u }; d < 3; ++d) { m_io.DefineVariable(fmt::format("s%d_ux%d", s + 1, d + 1), { adios2::UnknownDim }, diff --git a/src/engines/CMakeLists.txt b/src/engines/CMakeLists.txt index c91475eb7..2ab7289b2 100644 --- a/src/engines/CMakeLists.txt +++ b/src/engines/CMakeLists.txt @@ -4,7 +4,6 @@ # - engine_printer.cpp # - engine_init.cpp # - engine_run.cpp -# - engine_step_report.cpp # @includes: # - ../ # @depends: @@ -29,7 +28,6 @@ set(SOURCES ${SRC_DIR}/engine_printer.cpp ${SRC_DIR}/engine_init.cpp ${SRC_DIR}/engine_run.cpp - ${SRC_DIR}/engine_step_report.cpp ) add_library(ntt_engines ${SOURCES}) diff --git a/src/engines/engine.hpp b/src/engines/engine.hpp index f1bb46e98..5b7caa502 100644 --- a/src/engines/engine.hpp +++ b/src/engines/engine.hpp @@ -117,7 +117,6 @@ namespace ntt { void init(); void print_report() const; - void print_step_report(timer::Timers&, pbar::DurationHistory&, bool, bool, bool) const; virtual void step_forward(timer::Timers&, Domain&) = 0; diff --git a/src/engines/engine_init.cpp b/src/engines/engine_init.cpp index 5a8a693b0..e4ce9fa5f 100644 --- a/src/engines/engine_init.cpp +++ b/src/engines/engine_init.cpp @@ -27,6 +27,8 @@ namespace ntt { #endif logger::Checkpoint("Initializing Engine", HERE); if (not is_resuming) { + // start a new simulation with initial conditions + logger::Checkpoint("Loading initial conditions", HERE); if constexpr ( traits::has_member>::value) { logger::Checkpoint("Initializing fields from problem generator", HERE); @@ -48,6 +50,13 @@ namespace ntt { }); } } else { + // read simulation data from the checkpoint + raise::ErrorIf( + m_params.template get("checkpoint.start_step") == 0, + "Resuming simulation from a checkpoint requires a valid start_step", + HERE); + logger::Checkpoint("Resuming simulation from a checkpoint", HERE); + m_metadomain.ContinueFromCheckpoint(&m_adios, m_params); } } } diff --git a/src/engines/engine_run.cpp b/src/engines/engine_run.cpp index e5c8d8647..bec5b8652 100644 --- a/src/engines/engine_run.cpp +++ b/src/engines/engine_run.cpp @@ -1,6 +1,7 @@ #include "enums.h" #include "arch/traits.h" +#include "utils/diag.h" #include "metrics/kerr_schild.h" #include "metrics/kerr_schild_0.h" @@ -57,9 +58,9 @@ namespace ntt { } auto print_sorting = (sort_interval > 0 and step % sort_interval == 0); - // advance time & timestep - ++step; + // advance time & step time += dt; + ++step; auto print_output = false; auto print_checkpoint = false; @@ -75,27 +76,43 @@ namespace ntt { }; print_output = m_metadomain.Write(m_params, step, + step - 1, time, + time - dt, lambda_custom_field_output); } else { - print_output = m_metadomain.Write(m_params, step, time); + print_output = m_metadomain.Write(m_params, step, step - 1, time, time - dt); } timers.stop("Output"); timers.start("Checkpoint"); - print_checkpoint = m_metadomain.WriteCheckpoint(m_params, step, time); + print_checkpoint = m_metadomain.WriteCheckpoint(m_params, + step, + step - 1, + time, + time - dt); timers.stop("Checkpoint"); #endif // advance time_history time_history.tick(); - // print final timestep report + // print timestep report if (diag_interval > 0 and step % diag_interval == 0) { - print_step_report(timers, - time_history, - print_output, - print_checkpoint, - print_sorting); + diag::printDiagnostics( + step - 1, + max_steps, + time - dt, + dt, + timers, + time_history, + m_metadomain.l_ncells(), + m_metadomain.species_labels(), + m_metadomain.l_npart_perspec(), + m_metadomain.l_maxnpart_perspec(), + print_sorting, + print_output, + print_checkpoint, + m_params.get("diagnostics.colored_stdout")); } timers.resetAll(); } diff --git a/src/framework/domain/checkpoint.cpp b/src/framework/domain/checkpoint.cpp index 569a61093..c95e3dd27 100644 --- a/src/framework/domain/checkpoint.cpp +++ b/src/framework/domain/checkpoint.cpp @@ -12,6 +12,7 @@ #include "metrics/qspherical.h" #include "metrics/spherical.h" +#include "checkpoint/reader.h" #include "checkpoint/writer.h" #include "framework/domain/metadomain.h" #include "framework/parameters.h" @@ -21,11 +22,12 @@ namespace ntt { template void Metadomain::InitCheckpointWriter(adios2::ADIOS* ptr_adios, const SimulationParams& params) { + raise::ErrorIf(ptr_adios == nullptr, "adios == nullptr", HERE); raise::ErrorIf( - local_subdomain_indices().size() != 1, + l_subdomain_indices().size() != 1, "Checkpoint writing for now is only supported for one subdomain per rank", HERE); - auto local_domain = subdomain_ptr(local_subdomain_indices()[0]); + auto local_domain = subdomain_ptr(l_subdomain_indices()[0]); raise::ErrorIf(local_domain->is_placeholder(), "local_domain is a placeholder", HERE); @@ -56,24 +58,26 @@ namespace ntt { template auto Metadomain::WriteCheckpoint(const SimulationParams& params, - std::size_t step, - long double time) -> bool { + std::size_t current_step, + std::size_t finished_step, + long double current_time, + long double finished_time) -> bool { raise::ErrorIf( - local_subdomain_indices().size() != 1, + l_subdomain_indices().size() != 1, "Checkpointing for now is only supported for one subdomain per rank", HERE); - if (!g_checkpoint_writer.shouldSave(step, time)) { + if (!g_checkpoint_writer.shouldSave(finished_step, finished_time) or + finished_step <= 1) { return false; } - auto local_domain = subdomain_ptr(local_subdomain_indices()[0]); + auto local_domain = subdomain_ptr(l_subdomain_indices()[0]); raise::ErrorIf(local_domain->is_placeholder(), "local_domain is a placeholder", HERE); logger::Checkpoint("Writing checkpoint", HERE); - g_checkpoint_writer.beginSaving(step, time); + g_checkpoint_writer.beginSaving(current_step, current_time); { - - g_checkpoint_writer.saveAttrs(params, time); + g_checkpoint_writer.saveAttrs(params, current_time); g_checkpoint_writer.saveField("em", local_domain->fields.em); if constexpr (S == SimEngine::GRPIC) { @@ -252,6 +256,220 @@ namespace ntt { return true; } + template + void Metadomain::ContinueFromCheckpoint(adios2::ADIOS* ptr_adios, + const SimulationParams& params) { + raise::ErrorIf(ptr_adios == nullptr, "adios == nullptr", HERE); + auto fname = fmt::format( + "checkpoints/step-%08lu.bp", + params.template get("checkpoint.start_step")); + logger::Checkpoint(fmt::format("Reading checkpoint from %s", fname.c_str()), + HERE); + + adios2::IO io = ptr_adios->DeclareIO("Entity::CheckpointRead"); + io.SetEngine("BPFile"); +#if !defined(MPI_ENABLED) + adios2::Engine reader = io.Open(fname, adios2::Mode::Read); +#else + adios2::Engine reader = io.Open(fname, adios2::Mode::Read, MPI_COMM_SELF); +#endif + + reader.BeginStep(); + for (auto& ldidx : l_subdomain_indices()) { + auto& domain = g_subdomains[ldidx]; + adios2::Box range; + for (auto d { 0u }; d < M::Dim; ++d) { + range.first.push_back(domain.offset_ncells()[d]); + range.second.push_back(domain.mesh.n_all()[d]); + } + range.first.push_back(0); + range.second.push_back(6); + checkpoint::ReadFields(io, reader, "em", range, domain.fields.em); + if constexpr (S == ntt::SimEngine::GRPIC) { + checkpoint::ReadFields(io, + reader, + "em0", + range, + domain.fields.em0); + adios2::Box range3; + for (auto d { 0u }; d < M::Dim; ++d) { + range3.first.push_back(domain.offset_ncells()[d]); + range3.second.push_back(domain.mesh.n_all()[d]); + } + range3.first.push_back(0); + range3.second.push_back(3); + checkpoint::ReadFields(io, + reader, + "cur0", + range3, + domain.fields.cur0); + } + for (auto s { 0u }; s < (unsigned short)(domain.species.size()); ++s) { + const auto [loc_npart, offset_npart] = + checkpoint::ReadParticleCount(io, reader, s, ldidx, ndomains()); + + raise::ErrorIf(loc_npart > domain.species[s].maxnpart(), + "loc_npart > domain.species[s].maxnpart()", + HERE); + if (loc_npart == 0) { + continue; + } + if constexpr (M::Dim == Dim::_1D or M::Dim == Dim::_2D or + M::Dim == Dim::_3D) { + checkpoint::ReadParticleData(io, + reader, + "i1", + s, + domain.species[s].i1, + loc_npart, + offset_npart); + checkpoint::ReadParticleData(io, + reader, + "dx1", + s, + domain.species[s].dx1, + loc_npart, + offset_npart); + checkpoint::ReadParticleData(io, + reader, + "i1_prev", + s, + domain.species[s].i1_prev, + loc_npart, + offset_npart); + checkpoint::ReadParticleData(io, + reader, + "dx1_prev", + s, + domain.species[s].dx1_prev, + loc_npart, + offset_npart); + } + if constexpr (M::Dim == Dim::_2D or M::Dim == Dim::_3D) { + checkpoint::ReadParticleData(io, + reader, + "i2", + s, + domain.species[s].i2, + loc_npart, + offset_npart); + checkpoint::ReadParticleData(io, + reader, + "dx2", + s, + domain.species[s].dx2, + loc_npart, + offset_npart); + checkpoint::ReadParticleData(io, + reader, + "i2_prev", + s, + domain.species[s].i2_prev, + loc_npart, + offset_npart); + checkpoint::ReadParticleData(io, + reader, + "dx2_prev", + s, + domain.species[s].dx2_prev, + loc_npart, + offset_npart); + } + if constexpr (M::Dim == Dim::_3D) { + checkpoint::ReadParticleData(io, + reader, + "i3", + s, + domain.species[s].i3, + loc_npart, + offset_npart); + checkpoint::ReadParticleData(io, + reader, + "dx3", + s, + domain.species[s].dx3, + loc_npart, + offset_npart); + checkpoint::ReadParticleData(io, + reader, + "i3_prev", + s, + domain.species[s].i3_prev, + loc_npart, + offset_npart); + checkpoint::ReadParticleData(io, + reader, + "dx3_prev", + s, + domain.species[s].dx3_prev, + loc_npart, + offset_npart); + } + if constexpr (M::Dim == Dim::_2D and M::CoordType != Coord::Cart) { + checkpoint::ReadParticleData(io, + reader, + "phi", + s, + domain.species[s].phi, + loc_npart, + offset_npart); + } + checkpoint::ReadParticleData(io, + reader, + "ux1", + s, + domain.species[s].ux1, + loc_npart, + offset_npart); + checkpoint::ReadParticleData(io, + reader, + "ux2", + s, + domain.species[s].ux2, + loc_npart, + offset_npart); + checkpoint::ReadParticleData(io, + reader, + "ux3", + s, + domain.species[s].ux3, + loc_npart, + offset_npart); + checkpoint::ReadParticleData(io, + reader, + "tag", + s, + domain.species[s].tag, + loc_npart, + offset_npart); + checkpoint::ReadParticleData(io, + reader, + "weight", + s, + domain.species[s].weight, + loc_npart, + offset_npart); + for (auto p { 0u }; p < domain.species[s].npld(); ++p) { + checkpoint::ReadParticleData(io, + reader, + fmt::format("pld%d", p + 1), + s, + domain.species[s].pld[p], + loc_npart, + offset_npart); + } + domain.species[s].set_npart(loc_npart); + } // species loop + + } // local subdomain loop + + reader.EndStep(); + reader.Close(); + logger::Checkpoint( + fmt::format("Checkpoint reading done from %s", fname.c_str()), + HERE); + } + template struct Metadomain>; template struct Metadomain>; template struct Metadomain>; diff --git a/src/framework/domain/metadomain.cpp b/src/framework/domain/metadomain.cpp index cdc9e5a3d..5e66bc366 100644 --- a/src/framework/domain/metadomain.cpp +++ b/src/framework/domain/metadomain.cpp @@ -342,7 +342,7 @@ namespace ntt { } // check that local subdomains are contained in g_local_subdomain_indices auto contained_in_local = false; - for (const auto& gidx : g_local_subdomain_indices) { + for (const auto& gidx : l_subdomain_indices()) { contained_in_local |= (idx == gidx); } #if defined(MPI_ENABLED) diff --git a/src/framework/domain/metadomain.h b/src/framework/domain/metadomain.h index 6a3c64742..027a2982d 100644 --- a/src/framework/domain/metadomain.h +++ b/src/framework/domain/metadomain.h @@ -74,14 +74,14 @@ namespace ntt { template void runOnLocalDomains(Func func, Args&&... args) { - for (auto& ldidx : g_local_subdomain_indices) { + for (auto& ldidx : l_subdomain_indices()) { func(g_subdomains[ldidx], std::forward(args)...); } } template void runOnLocalDomainsConst(Func func, Args&&... args) const { - for (auto& ldidx : g_local_subdomain_indices) { + for (auto& ldidx : l_subdomain_indices()) { func(g_subdomains[ldidx], std::forward(args)...); } } @@ -118,15 +118,21 @@ namespace ntt { void InitWriter(adios2::ADIOS*, const SimulationParams&, bool is_resuming); auto Write(const SimulationParams&, std::size_t, + std::size_t, + long double, long double, std::function&, std::size_t, const Domain&)> = {}) -> bool; void InitCheckpointWriter(adios2::ADIOS*, const SimulationParams&); - auto WriteCheckpoint(const SimulationParams&, std::size_t, long double) -> bool; + auto WriteCheckpoint(const SimulationParams&, + std::size_t, + std::size_t, + long double, + long double) -> bool; - void ContinueFromCheckpoint(); + void ContinueFromCheckpoint(adios2::ADIOS*, const SimulationParams&); #endif /* setters -------------------------------------------------------------- */ @@ -165,10 +171,60 @@ namespace ntt { } [[nodiscard]] - auto local_subdomain_indices() const -> std::vector { + auto l_subdomain_indices() const -> std::vector { return g_local_subdomain_indices; } + [[nodiscard]] + auto l_npart_perspec() const -> std::vector { + std::vector npart(g_species_params.size(), 0); + for (const auto& ldidx : l_subdomain_indices()) { + for (std::size_t i = 0; i < g_species_params.size(); ++i) { + npart[i] += g_subdomains[ldidx].species[i].npart(); + } + } + return npart; + } + + [[nodiscard]] + auto l_maxnpart_perspec() const -> std::vector { + std::vector maxnpart(g_species_params.size(), 0); + for (const auto& ldidx : l_subdomain_indices()) { + for (std::size_t i = 0; i < g_species_params.size(); ++i) { + maxnpart[i] += g_subdomains[ldidx].species[i].maxnpart(); + } + } + return maxnpart; + } + + [[nodiscard]] + auto l_npart() const -> std::size_t { + const auto npart = l_npart_perspec(); + return std::accumulate(npart.begin(), npart.end(), 0); + } + + [[nodiscard]] + auto l_ncells() const -> std::size_t { + std::size_t ncells_local = 0; + for (const auto& ldidx : l_subdomain_indices()) { + std::size_t ncells = 1; + for (const auto& n : g_subdomains[ldidx].mesh.n_all()) { + ncells *= n; + } + ncells_local += ncells; + } + return ncells_local; + } + + [[nodiscard]] + auto species_labels() const -> std::vector { + std::vector labels; + for (const auto& sp : g_species_params) { + labels.push_back(sp.label()); + } + return labels; + } + private: // domain information unsigned int g_ndomains; diff --git a/src/framework/domain/output.cpp b/src/framework/domain/output.cpp index 701ea4fb3..3186cc1b0 100644 --- a/src/framework/domain/output.cpp +++ b/src/framework/domain/output.cpp @@ -41,10 +41,10 @@ namespace ntt { const SimulationParams& params, bool is_resuming) { raise::ErrorIf( - local_subdomain_indices().size() != 1, + l_subdomain_indices().size() != 1, "Output for now is only supported for one subdomain per rank", HERE); - auto local_domain = subdomain_ptr(local_subdomain_indices()[0]); + auto local_domain = subdomain_ptr(l_subdomain_indices()[0]); raise::ErrorIf(local_domain->is_placeholder(), "local_domain is a placeholder", HERE); @@ -176,35 +176,43 @@ namespace ntt { template auto Metadomain::Write( const SimulationParams& params, - std::size_t step, - long double time, + std::size_t current_step, + std::size_t finished_step, + long double current_time, + long double finished_time, std::function< void(const std::string&, ndfield_t&, std::size_t, const Domain&)> CustomFieldOutput) -> bool { raise::ErrorIf( - local_subdomain_indices().size() != 1, + l_subdomain_indices().size() != 1, "Output for now is only supported for one subdomain per rank", HERE); const auto write_fields = params.template get( "output.fields.enable") and - g_writer.shouldWrite("fields", step, time); + g_writer.shouldWrite("fields", + finished_step, + finished_time); const auto write_particles = params.template get( "output.particles.enable") and - g_writer.shouldWrite("particles", step, time); + g_writer.shouldWrite("particles", + finished_step, + finished_time); const auto write_spectra = params.template get( "output.spectra.enable") and - g_writer.shouldWrite("spectra", step, time); + g_writer.shouldWrite("spectra", + finished_step, + finished_time); if (not(write_fields or write_particles or write_spectra)) { return false; } - auto local_domain = subdomain_ptr(local_subdomain_indices()[0]); + auto local_domain = subdomain_ptr(l_subdomain_indices()[0]); raise::ErrorIf(local_domain->is_placeholder(), "local_domain is a placeholder", HERE); logger::Checkpoint("Writing output", HERE); g_writer.beginWriting(params.template get("simulation.name"), - step, - time); + current_step, + current_time); if (write_fields) { const auto incl_ghosts = params.template get("output.debug.ghosts"); diff --git a/src/framework/parameters.cpp b/src/framework/parameters.cpp index 12f4d2ffa..9a4c9c616 100644 --- a/src/framework/parameters.cpp +++ b/src/framework/parameters.cpp @@ -317,7 +317,6 @@ namespace ntt { set("scales.q0", V0 / (ppc0 * SQR(skindepth0))); set("grid.metric.metric", metric_enum); - set("algorithms.timestep.dt", get("algorithms.timestep.CFL") * dx0); } } @@ -421,7 +420,8 @@ namespace ntt { /* [algorithms.timestep] ------------------------------------------------ */ set("algorithms.timestep.CFL", toml::find_or(toml_data, "algorithms", "timestep", "CFL", defaults::cfl)); - promiseToDefine("algorithms.timestep.dt"); + set("algorithms.timestep.dt", + get("algorithms.timestep.CFL") * get("scales.dx0")); set("algorithms.timestep.correction", toml::find_or(toml_data, "algorithms", diff --git a/src/framework/parameters.h b/src/framework/parameters.h index 2c03ef812..0f9e29370 100644 --- a/src/framework/parameters.h +++ b/src/framework/parameters.h @@ -24,7 +24,7 @@ namespace ntt { struct SimulationParams : public prm::Parameters { - SimulationParams() = default; + SimulationParams() {} SimulationParams& operator=(const SimulationParams& other) { vars = std::move(other.vars); diff --git a/src/framework/simulation.cpp b/src/framework/simulation.cpp index 74798ffa6..db1b3d474 100644 --- a/src/framework/simulation.cpp +++ b/src/framework/simulation.cpp @@ -53,6 +53,7 @@ namespace ntt { m_params.setRawData(raw_params); std::size_t checkpoint_step = 0; if (is_resuming) { + logger::Checkpoint("Reading params from a checkpoint", HERE); if (not std::filesystem::exists("checkpoints")) { raise::Fatal("No checkpoints found", HERE); } @@ -84,6 +85,7 @@ namespace ntt { m_params.setCheckpointParams(true, checkpoint_step, start_time); m_params.setSetupParams(raw_checkpoint_params); } else { + logger::Checkpoint("Defining new params", HERE); m_params.setImmutableParams(raw_params); m_params.setMutableParams(raw_params); m_params.setCheckpointParams(false, 0, 0.0); From 0321b9ac70f03015fe3cbff3723a775b51653dd4 Mon Sep 17 00:00:00 2001 From: haykh Date: Fri, 16 Aug 2024 21:22:48 -0400 Subject: [PATCH 103/773] diag minor issue with non-mpi --- src/global/utils/timer.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/global/utils/timer.cpp b/src/global/utils/timer.cpp index 1a1a37848..162ba33b7 100644 --- a/src/global/utils/timer.cpp +++ b/src/global/utils/timer.cpp @@ -115,7 +115,12 @@ namespace timer { const auto pcent = static_cast( (timer.second / local_tot) * 100.0); timer_stats.insert( - { name, std::make_tuple(timer.second, pcent, 0.0, 0u, 0u) }); + { name, + std::make_tuple(timer.second, + timer.second / static_cast(npart), + timer.second / static_cast(ncells), + pcent, + 0u) }); } timer_stats.insert({ "Total", std::make_tuple(local_tot, 0.0, 0.0, 100u, 0u) }); #endif From 43e3acbd5dcbe622d311ca3ecef2b360ff8fdb05 Mon Sep 17 00:00:00 2001 From: haykh Date: Fri, 16 Aug 2024 21:30:54 -0400 Subject: [PATCH 104/773] conditional action launch --- .github/workflows/actions.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/actions.yml b/.github/workflows/actions.yml index 04bc34050..cd7119789 100644 --- a/.github/workflows/actions.yml +++ b/.github/workflows/actions.yml @@ -16,8 +16,9 @@ jobs: exclude: - device: amd-gpu precision: double - # my AMD GPUs doesn't support fp64 atomics : ( + # my AMD GPU doesn't support fp64 atomics : ( runs-on: [self-hosted, "${{ matrix.device }}"] + if: contains(github.event.head_commit.message, 'totest') steps: - name: Checkout uses: actions/checkout@v3.3.0 From ddc70942b69c60c27fd666da59b43802da74c15a Mon Sep 17 00:00:00 2001 From: haykh Date: Sat, 17 Aug 2024 02:27:54 -0400 Subject: [PATCH 105/773] minor --- src/checkpoint/writer.cpp | 32 ++++++++++++++++------------- src/engines/engine_init.cpp | 8 ++++---- src/engines/engine_run.cpp | 1 + src/framework/domain/checkpoint.cpp | 5 ++--- src/framework/simulation.cpp | 1 + 5 files changed, 26 insertions(+), 21 deletions(-) diff --git a/src/checkpoint/writer.cpp b/src/checkpoint/writer.cpp index 1740c47aa..362373831 100644 --- a/src/checkpoint/writer.cpp +++ b/src/checkpoint/writer.cpp @@ -3,13 +3,13 @@ #include "global.h" #include "arch/kokkos_aliases.h" -#include "arch/mpi_aliases.h" #include "utils/error.h" #include "utils/formatting.h" #include "utils/log.h" #include "framework/parameters.h" +#include #include #include @@ -52,17 +52,9 @@ namespace checkpoint { const std::vector& glob_shape, const std::vector& loc_corner, const std::vector& loc_shape) { - auto gs3 = std::vector(glob_shape.begin(), glob_shape.end()); - auto lc3 = std::vector(loc_corner.begin(), loc_corner.end()); - auto ls3 = std::vector(loc_shape.begin(), loc_shape.end()); auto gs6 = std::vector(glob_shape.begin(), glob_shape.end()); auto lc6 = std::vector(loc_corner.begin(), loc_corner.end()); auto ls6 = std::vector(loc_shape.begin(), loc_shape.end()); - - gs3.push_back(3); - lc3.push_back(0); - ls3.push_back(3); - gs6.push_back(6); lc6.push_back(0); ls6.push_back(6); @@ -70,6 +62,12 @@ namespace checkpoint { m_io.DefineVariable("em", gs6, lc6, ls6, adios2::ConstantDims); if (S == ntt::SimEngine::GRPIC) { m_io.DefineVariable("em0", gs6, lc6, ls6, adios2::ConstantDims); + auto gs3 = std::vector(glob_shape.begin(), glob_shape.end()); + auto lc3 = std::vector(loc_corner.begin(), loc_corner.end()); + auto ls3 = std::vector(loc_shape.begin(), loc_shape.end()); + gs3.push_back(3); + lc3.push_back(0); + ls3.push_back(3); m_io.DefineVariable("cur0", gs3, lc3, ls3, adios2::ConstantDims); } } @@ -150,6 +148,10 @@ namespace checkpoint { m_writer = m_io.Open(fname, adios2::Mode::Write); auto meta_fname = fmt::format("checkpoints/meta-%08lu.toml", step); m_written.push_back({ fname, meta_fname }); + logger::Checkpoint(fmt::format("Writing checkpoint to %s and %s", + fname.c_str(), + meta_fname.c_str()), + HERE); } catch (std::exception& e) { raise::Fatal(e.what(), HERE); } @@ -215,7 +217,9 @@ namespace checkpoint { const ndfield_t& field) { auto field_h = Kokkos::create_mirror_view(field); Kokkos::deep_copy(field_h, field); - m_writer.Put(m_io.InquireVariable(fieldname), field_h.data()); + m_writer.Put(m_io.InquireVariable(fieldname), + field_h.data(), + adios2::Mode::Sync); } template @@ -224,12 +228,12 @@ namespace checkpoint { std::size_t loc_offset, std::size_t loc_size, const array_t& data) { - auto var = m_io.InquireVariable(quantity); - var.SetShape({ glob_total }); - var.SetSelection(adios2::Box({ loc_offset }, { loc_size })); - auto slice = range_tuple_t(0, loc_size); auto data_h = Kokkos::create_mirror_view(data); Kokkos::deep_copy(data_h, data); + auto slice = range_tuple_t(0, loc_size); + auto var = m_io.InquireVariable(quantity); + var.SetShape({ glob_total }); + var.SetSelection(adios2::Box({ loc_offset }, { loc_size })); m_writer.Put(var, Kokkos::subview(data_h, slice).data()); } diff --git a/src/engines/engine_init.cpp b/src/engines/engine_init.cpp index e4ce9fa5f..538328e11 100644 --- a/src/engines/engine_init.cpp +++ b/src/engines/engine_init.cpp @@ -21,10 +21,10 @@ namespace ntt { template void Engine::init() { if constexpr (pgen_is_ok) { -#if defined(OUTPUT_ENABLED) - m_metadomain.InitWriter(&m_adios, m_params, is_resuming); - m_metadomain.InitCheckpointWriter(&m_adios, m_params); -#endif + // #if defined(OUTPUT_ENABLED) + // m_metadomain.InitWriter(&m_adios, m_params, is_resuming); + // m_metadomain.InitCheckpointWriter(&m_adios, m_params); + // #endif logger::Checkpoint("Initializing Engine", HERE); if (not is_resuming) { // start a new simulation with initial conditions diff --git a/src/engines/engine_run.cpp b/src/engines/engine_run.cpp index bec5b8652..3262fb023 100644 --- a/src/engines/engine_run.cpp +++ b/src/engines/engine_run.cpp @@ -20,6 +20,7 @@ namespace ntt { void Engine::run() { if constexpr (pgen_is_ok) { init(); + return; auto timers = timer::Timers { { "FieldSolver", diff --git a/src/framework/domain/checkpoint.cpp b/src/framework/domain/checkpoint.cpp index c95e3dd27..af2f919bf 100644 --- a/src/framework/domain/checkpoint.cpp +++ b/src/framework/domain/checkpoint.cpp @@ -32,9 +32,9 @@ namespace ntt { "local_domain is a placeholder", HERE); - auto glob_shape_with_ghosts = mesh().n_active(); + auto glob_shape_with_ghosts = mesh().n_all(); auto off_ncells_with_ghosts = local_domain->offset_ncells(); - auto loc_shape_with_ghosts = local_domain->mesh.n_active(); + auto loc_shape_with_ghosts = local_domain->mesh.n_all(); std::vector nplds; for (auto s { 0u }; s < local_domain->species.size(); ++s) { @@ -78,7 +78,6 @@ namespace ntt { g_checkpoint_writer.beginSaving(current_step, current_time); { g_checkpoint_writer.saveAttrs(params, current_time); - g_checkpoint_writer.saveField("em", local_domain->fields.em); if constexpr (S == SimEngine::GRPIC) { g_checkpoint_writer.saveField("em0", local_domain->fields.em0); diff --git a/src/framework/simulation.cpp b/src/framework/simulation.cpp index db1b3d474..9961eb3eb 100644 --- a/src/framework/simulation.cpp +++ b/src/framework/simulation.cpp @@ -76,6 +76,7 @@ namespace ntt { HERE); checkpoint_inputfname = inputfname; } + logger::Checkpoint(fmt::format("Using %08lu", checkpoint_step), HERE); const auto raw_checkpoint_params = toml::parse(checkpoint_inputfname); const auto start_time = toml::find(raw_checkpoint_params, "metadata", From 4ac34e236a7f2634e9db04d48d4dc4ec13f19813 Mon Sep 17 00:00:00 2001 From: hayk Date: Wed, 21 Aug 2024 21:12:01 -0400 Subject: [PATCH 106/773] minor bugs & leftovers --- src/engines/engine_init.cpp | 8 ++++---- src/engines/engine_run.cpp | 1 - src/output/writer.cpp | 6 +++--- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/engines/engine_init.cpp b/src/engines/engine_init.cpp index 538328e11..e4ce9fa5f 100644 --- a/src/engines/engine_init.cpp +++ b/src/engines/engine_init.cpp @@ -21,10 +21,10 @@ namespace ntt { template void Engine::init() { if constexpr (pgen_is_ok) { - // #if defined(OUTPUT_ENABLED) - // m_metadomain.InitWriter(&m_adios, m_params, is_resuming); - // m_metadomain.InitCheckpointWriter(&m_adios, m_params); - // #endif +#if defined(OUTPUT_ENABLED) + m_metadomain.InitWriter(&m_adios, m_params, is_resuming); + m_metadomain.InitCheckpointWriter(&m_adios, m_params); +#endif logger::Checkpoint("Initializing Engine", HERE); if (not is_resuming) { // start a new simulation with initial conditions diff --git a/src/engines/engine_run.cpp b/src/engines/engine_run.cpp index 3262fb023..bec5b8652 100644 --- a/src/engines/engine_run.cpp +++ b/src/engines/engine_run.cpp @@ -20,7 +20,6 @@ namespace ntt { void Engine::run() { if constexpr (pgen_is_ok) { init(); - return; auto timers = timer::Timers { { "FieldSolver", diff --git a/src/output/writer.cpp b/src/output/writer.cpp index f120cad10..08c3c5cbc 100644 --- a/src/output/writer.cpp +++ b/src/output/writer.cpp @@ -4,6 +4,7 @@ #include "arch/kokkos_aliases.h" #include "utils/error.h" +#include "utils/formatting.h" #include "utils/param_container.h" #include "utils/tools.h" @@ -38,8 +39,7 @@ namespace out { void Writer::addTracker(const std::string& type, std::size_t interval, long double interval_time) { - m_trackers.insert(std::pair( - { type, tools::Tracker(type, interval, interval_time) })); + m_trackers.insert({ type, tools::Tracker(type, interval, interval_time) }); } auto Writer::shouldWrite(const std::string& type, @@ -48,7 +48,7 @@ namespace out { if (m_trackers.find(type) != m_trackers.end()) { return m_trackers.at(type).shouldWrite(step, time); } else { - raise::Error("Tracker type not found", HERE); + raise::Error(fmt::format("Tracker type %s not found", type.c_str()), HERE); return false; } } From 550e19dff3d76819dd4d91c048ecb705d01665ce Mon Sep 17 00:00:00 2001 From: haykh Date: Mon, 26 Aug 2024 09:34:37 -0400 Subject: [PATCH 107/773] disable checkpoint @ keep=0 --- src/checkpoint/writer.cpp | 2 +- src/framework/domain/checkpoint.cpp | 20 +++++++++++--------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/checkpoint/writer.cpp b/src/checkpoint/writer.cpp index 362373831..9e73905ae 100644 --- a/src/checkpoint/writer.cpp +++ b/src/checkpoint/writer.cpp @@ -27,7 +27,7 @@ namespace checkpoint { int keep) { m_keep = keep; m_enabled = keep != 0; - if (!m_enabled) { + if (not m_enabled) { return; } m_tracker.init("checkpoint", interval, interval_time); diff --git a/src/framework/domain/checkpoint.cpp b/src/framework/domain/checkpoint.cpp index af2f919bf..6695e3965 100644 --- a/src/framework/domain/checkpoint.cpp +++ b/src/framework/domain/checkpoint.cpp @@ -46,14 +46,16 @@ namespace ntt { params.template get("checkpoint.interval"), params.template get("checkpoint.interval_time"), params.template get("checkpoint.keep")); - g_checkpoint_writer.defineFieldVariables(S, - glob_shape_with_ghosts, - off_ncells_with_ghosts, - loc_shape_with_ghosts); - g_checkpoint_writer.defineParticleVariables(M::CoordType, - M::Dim, - local_domain->species.size(), - nplds); + if (g_checkpoint_writer.enabled()) { + g_checkpoint_writer.defineFieldVariables(S, + glob_shape_with_ghosts, + off_ncells_with_ghosts, + loc_shape_with_ghosts); + g_checkpoint_writer.defineParticleVariables(M::CoordType, + M::Dim, + local_domain->species.size(), + nplds); + } } template @@ -66,7 +68,7 @@ namespace ntt { l_subdomain_indices().size() != 1, "Checkpointing for now is only supported for one subdomain per rank", HERE); - if (!g_checkpoint_writer.shouldSave(finished_step, finished_time) or + if (not g_checkpoint_writer.shouldSave(finished_step, finished_time) or finished_step <= 1) { return false; } From d77a16aba747c6e12faa34b55f25d1763471e58a Mon Sep 17 00:00:00 2001 From: haykh Date: Mon, 26 Aug 2024 09:57:14 -0400 Subject: [PATCH 108/773] minor warnings & bugs --- src/engines/srpic.hpp | 11 +++++++++-- src/framework/parameters.cpp | 2 +- src/global/utils/timer.cpp | 1 - 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/engines/srpic.hpp b/src/engines/srpic.hpp index 9b8b3f19b..78c8f371e 100644 --- a/src/engines/srpic.hpp +++ b/src/engines/srpic.hpp @@ -885,8 +885,15 @@ namespace ntt { xi_min.size() != static_cast(M::Dim), "Invalid range size", HERE); - for (const unsigned short comp : - { normal_b_comp, tang_e_comp1, tang_e_comp2 }) { + std::vector comps; + if (tags & BC::E) { + comps.push_back(tang_e_comp1); + comps.push_back(tang_e_comp2); + } + if (tags & BC::B) { + comps.push_back(normal_b_comp); + } + for (const auto& comp : comps) { if constexpr (M::Dim == Dim::_1D) { Kokkos::deep_copy(Kokkos::subview(domain.fields.em, std::make_pair(xi_min[0], xi_max[0]), diff --git a/src/framework/parameters.cpp b/src/framework/parameters.cpp index 9a4c9c616..1d4672212 100644 --- a/src/framework/parameters.cpp +++ b/src/framework/parameters.cpp @@ -795,7 +795,7 @@ namespace ntt { void SimulationParams::setSetupParams(const toml::value& toml_data) { /* [setup] -------------------------------------------------------------- */ - const auto& setup = toml::find_or(raw_data, "setup", toml::table {}); + const auto& setup = toml::find_or(toml_data, "setup", toml::table {}); for (const auto& [key, val] : setup) { if (val.is_boolean()) { set("setup." + key, (bool)(val.as_boolean())); diff --git a/src/global/utils/timer.cpp b/src/global/utils/timer.cpp index 162ba33b7..b5f4408ca 100644 --- a/src/global/utils/timer.cpp +++ b/src/global/utils/timer.cpp @@ -263,7 +263,6 @@ namespace timer { std::string units = "µs"; auto time = std::get<0>(stats.at(name)); const auto tot_pct = std::get<3>(stats.at(name)); - const auto var_pct = std::get<4>(stats.at(name)); if (flags & Timer::AutoConvert) { convertTime(time, units); } From f96f750ef911386558e75ffc4b9177696e56f6e1 Mon Sep 17 00:00:00 2001 From: haykh Date: Mon, 26 Aug 2024 16:50:09 -0400 Subject: [PATCH 109/773] checkpoint fixed --- src/checkpoint/reader.cpp | 8 ++------ src/framework/domain/output.cpp | 11 ++++++----- src/output/writer.cpp | 11 ++++++----- src/output/writer.h | 9 +++++++-- 4 files changed, 21 insertions(+), 18 deletions(-) diff --git a/src/checkpoint/reader.cpp b/src/checkpoint/reader.cpp index c53661b45..bef78f85b 100644 --- a/src/checkpoint/reader.cpp +++ b/src/checkpoint/reader.cpp @@ -27,9 +27,7 @@ namespace checkpoint { auto field_var = io.InquireVariable(field); field_var.SetStepSelection(adios2::Box({ 0 }, { 1 })); field_var.SetSelection(range); - auto array_h = Kokkos::create_mirror_view(array); - reader.Get(field_var, array_h.data()); - Kokkos::deep_copy(array, array_h); + reader.Get(field_var, array.data()); } auto ReadParticleCount(adios2::IO& io, @@ -74,9 +72,7 @@ namespace checkpoint { fmt::format("s%d_%s", s + 1, quantity.c_str())); var.SetStepSelection(adios2::Box({ 0 }, { 1 })); var.SetSelection(adios2::Box({ offset }, { count })); - auto array_h = Kokkos::create_mirror_view(array); - reader.Get(var, array_h.data()); - Kokkos::deep_copy(array, array_h); + reader.Get(var, array.data()); } template void ReadFields(adios2::IO&, diff --git a/src/framework/domain/output.cpp b/src/framework/domain/output.cpp index 3186cc1b0..0918eb2d3 100644 --- a/src/framework/domain/output.cpp +++ b/src/framework/domain/output.cpp @@ -31,6 +31,7 @@ #endif // MPI_ENABLED #include +#include #include #include @@ -62,7 +63,9 @@ namespace ntt { } } - g_writer.init(ptr_adios, params.template get("output.format")); + g_writer.init(ptr_adios, + params.template get("output.format"), + params.template get("simulation.name")); g_writer.defineMeshLayout(glob_shape_with_ghosts, off_ncells_with_ghosts, loc_shape_with_ghosts, @@ -95,7 +98,7 @@ namespace ntt { params.template get( "output." + std::string(type) + ".interval_time")); } - if (is_resuming) { + if (is_resuming and std::filesystem::exists(g_writer.fname())) { g_writer.setMode(adios2::Mode::Append); } else { g_writer.writeAttrs(params); @@ -210,9 +213,7 @@ namespace ntt { "local_domain is a placeholder", HERE); logger::Checkpoint("Writing output", HERE); - g_writer.beginWriting(params.template get("simulation.name"), - current_step, - current_time); + g_writer.beginWriting(current_step, current_time); if (write_fields) { const auto incl_ghosts = params.template get("output.debug.ghosts"); diff --git a/src/output/writer.cpp b/src/output/writer.cpp index 08c3c5cbc..3d526b306 100644 --- a/src/output/writer.cpp +++ b/src/output/writer.cpp @@ -23,7 +23,9 @@ namespace out { - void Writer::init(adios2::ADIOS* ptr_adios, const std::string& engine) { + void Writer::init(adios2::ADIOS* ptr_adios, + const std::string& engine, + const std::string& title) { m_engine = engine; p_adios = ptr_adios; @@ -34,6 +36,7 @@ namespace out { m_io.DefineVariable("Step"); m_io.DefineVariable("Time"); + m_fname = title + (m_engine == "hdf5" ? ".h5" : ".bp"); } void Writer::addTracker(const std::string& type, @@ -304,9 +307,7 @@ namespace out { m_writer.Put(vare, xe_h); } - void Writer::beginWriting(const std::string& fname, - std::size_t tstep, - long double time) { + void Writer::beginWriting(std::size_t tstep, long double time) { raise::ErrorIf(p_adios == nullptr, "ADIOS pointer is null", HERE); p_adios->ExitComputationBlock(); if (m_writing_mode) { @@ -314,7 +315,7 @@ namespace out { } m_writing_mode = true; try { - m_writer = m_io.Open(fname + (m_engine == "hdf5" ? ".h5" : ".bp"), m_mode); + m_writer = m_io.Open(m_fname, m_mode); } catch (std::exception& e) { raise::Fatal(e.what(), HERE); } diff --git a/src/output/writer.h b/src/output/writer.h index d188fa93a..ba24a3d65 100644 --- a/src/output/writer.h +++ b/src/output/writer.h @@ -44,6 +44,7 @@ namespace out { adios2::Dims m_flds_l_shape; bool m_flds_ghosts; std::string m_engine; + std::string m_fname; std::map m_trackers; @@ -60,7 +61,7 @@ namespace out { Writer(Writer&&) = default; - void init(adios2::ADIOS*, const std::string&); + void init(adios2::ADIOS*, const std::string&, const std::string&); void setMode(adios2::Mode); @@ -93,10 +94,14 @@ namespace out { void writeSpectrum(const array_t&, const std::string&); void writeSpectrumBins(const array_t&, const std::string&); - void beginWriting(const std::string&, std::size_t, long double); + void beginWriting(std::size_t, long double); void endWriting(); /* getters -------------------------------------------------------------- */ + auto fname() const -> const std::string& { + return m_fname; + } + auto fieldWriters() const -> const std::vector& { return m_flds_writers; } From a610fee342d34c4ef600de6062013c1aa7e1c09a Mon Sep 17 00:00:00 2001 From: hayk Date: Fri, 30 Aug 2024 03:21:41 -0400 Subject: [PATCH 110/773] updated checkpoint --- src/checkpoint/reader.cpp | 42 ++++++++++++++++++++++++++++----------- src/checkpoint/reader.h | 1 - src/checkpoint/writer.cpp | 30 ++++++++++++++-------------- src/checkpoint/writer.h | 1 - 4 files changed, 45 insertions(+), 29 deletions(-) diff --git a/src/checkpoint/reader.cpp b/src/checkpoint/reader.cpp index bef78f85b..9f410b220 100644 --- a/src/checkpoint/reader.cpp +++ b/src/checkpoint/reader.cpp @@ -9,7 +9,10 @@ #include #include -#include + +#if defined(MPI_ENABLED) + #include +#endif #include #include @@ -25,9 +28,11 @@ namespace checkpoint { ndfield_t& array) { logger::Checkpoint(fmt::format("Reading field: %s", field.c_str()), HERE); auto field_var = io.InquireVariable(field); - field_var.SetStepSelection(adios2::Box({ 0 }, { 1 })); field_var.SetSelection(range); - reader.Get(field_var, array.data()); + + auto array_h = Kokkos::create_mirror_view(array); + reader.Get(field_var, array_h.data()); + Kokkos::deep_copy(array, array_h); } auto ReadParticleCount(adios2::IO& io, @@ -43,17 +48,27 @@ namespace checkpoint { npart_var.Shape()[0] != ndomains or npart_var.Shape().size() != 1, "npart_var.Shape()[0] != ndomains or npart_var.Shape().size() != 1", HERE); - npart_var.SetStepSelection(adios2::Box({ 0 }, { 1 })); - npart_var.SetSelection( - adios2::Box({ 0 }, { npart_var.Shape()[0] })); - std::vector nparts(ndomains); - reader.Get(npart_var, nparts.data(), adios2::Mode::Sync); - const auto loc_npart = nparts[local_dom]; + npart_var.SetSelection(adios2::Box({ local_dom }, { 1 })); + std::size_t npart; + reader.Get(npart_var, &npart, adios2::Mode::Sync); + const auto loc_npart = npart; +#if !defined(MPI_ENABLED) + std::size_t offset_npart = 0; +#else + std::vector glob_nparts(ndomains); + MPI_Allgather(&npart, + 1, + mpi::get_type(), + glob_nparts.data(), + 1, + mpi::get_type(), + MPI_COMM_WORLD); std::size_t offset_npart = 0; for (auto d { 0u }; d < local_dom; ++d) { - offset_npart += nparts[d]; + offset_npart += glob_nparts[d]; } +#endif return { loc_npart, offset_npart }; } @@ -70,9 +85,12 @@ namespace checkpoint { HERE); auto var = io.InquireVariable( fmt::format("s%d_%s", s + 1, quantity.c_str())); - var.SetStepSelection(adios2::Box({ 0 }, { 1 })); var.SetSelection(adios2::Box({ offset }, { count })); - reader.Get(var, array.data()); + const auto slice = std::pair { 0, count }; + auto array_h = Kokkos::create_mirror_view(array); + reader.Get(var, Kokkos::subview(array_h, slice).data()); + Kokkos::deep_copy(Kokkos::subview(array, slice), + Kokkos::subview(array_h, slice)); } template void ReadFields(adios2::IO&, diff --git a/src/checkpoint/reader.h b/src/checkpoint/reader.h index b2358647b..f43493026 100644 --- a/src/checkpoint/reader.h +++ b/src/checkpoint/reader.h @@ -16,7 +16,6 @@ #include "arch/kokkos_aliases.h" #include -#include #include #include diff --git a/src/checkpoint/writer.cpp b/src/checkpoint/writer.cpp index 9e73905ae..0edc6cb06 100644 --- a/src/checkpoint/writer.cpp +++ b/src/checkpoint/writer.cpp @@ -11,7 +11,6 @@ #include #include -#include #include #include @@ -41,11 +40,12 @@ namespace checkpoint { m_io.DefineVariable("Time"); m_io.DefineAttribute("NGhosts", ntt::N_GHOSTS); - const std::filesystem::path save_path { "checkpoints" }; - if (!std::filesystem::exists(save_path)) { - std::filesystem::create_directory(save_path); - } - p_adios->EnterComputationBlock(); + CallOnce([]() { + const std::filesystem::path save_path { "checkpoints" }; + if (!std::filesystem::exists(save_path)) { + std::filesystem::create_directory(save_path); + } + }); } void Writer::defineFieldVariables(const ntt::SimEngine& S, @@ -169,7 +169,6 @@ namespace checkpoint { m_writing_mode = false; m_writer.EndStep(); m_writer.Close(); - p_adios->EnterComputationBlock(); // optionally remove the oldest checkpoint CallOnce([&]() { @@ -217,9 +216,7 @@ namespace checkpoint { const ndfield_t& field) { auto field_h = Kokkos::create_mirror_view(field); Kokkos::deep_copy(field_h, field); - m_writer.Put(m_io.InquireVariable(fieldname), - field_h.data(), - adios2::Mode::Sync); + m_writer.Put(m_io.InquireVariable(fieldname), field_h.data()); } template @@ -228,13 +225,16 @@ namespace checkpoint { std::size_t loc_offset, std::size_t loc_size, const array_t& data) { - auto data_h = Kokkos::create_mirror_view(data); - Kokkos::deep_copy(data_h, data); - auto slice = range_tuple_t(0, loc_size); - auto var = m_io.InquireVariable(quantity); + const auto slice = range_tuple_t(0, loc_size); + auto var = m_io.InquireVariable(quantity); + var.SetShape({ glob_total }); var.SetSelection(adios2::Box({ loc_offset }, { loc_size })); - m_writer.Put(var, Kokkos::subview(data_h, slice).data()); + + auto data_h = Kokkos::create_mirror_view(data); + Kokkos::deep_copy(data_h, data); + auto data_sub = Kokkos::subview(data_h, slice); + m_writer.Put(var, data_sub.data()); } template void Writer::savePerDomainVariable(const std::string&, diff --git a/src/checkpoint/writer.h b/src/checkpoint/writer.h index a23ab556a..34b5f043f 100644 --- a/src/checkpoint/writer.h +++ b/src/checkpoint/writer.h @@ -20,7 +20,6 @@ #include "framework/parameters.h" #include -#include #include #include From 795b4407b62474d35701c58c94954b003853c0d7 Mon Sep 17 00:00:00 2001 From: hayk Date: Sun, 1 Sep 2024 18:33:14 -0400 Subject: [PATCH 111/773] bugfix (i think it works) --- src/checkpoint/reader.cpp | 6 +++--- src/framework/domain/checkpoint.cpp | 19 +++++++++++++------ 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/src/checkpoint/reader.cpp b/src/checkpoint/reader.cpp index 9f410b220..6820a7787 100644 --- a/src/checkpoint/reader.cpp +++ b/src/checkpoint/reader.cpp @@ -31,7 +31,7 @@ namespace checkpoint { field_var.SetSelection(range); auto array_h = Kokkos::create_mirror_view(array); - reader.Get(field_var, array_h.data()); + reader.Get(field_var, array_h.data(), adios2::Mode::Sync); Kokkos::deep_copy(array, array_h); } @@ -57,7 +57,7 @@ namespace checkpoint { std::size_t offset_npart = 0; #else std::vector glob_nparts(ndomains); - MPI_Allgather(&npart, + MPI_Allgather(&loc_npart, 1, mpi::get_type(), glob_nparts.data(), @@ -88,7 +88,7 @@ namespace checkpoint { var.SetSelection(adios2::Box({ offset }, { count })); const auto slice = std::pair { 0, count }; auto array_h = Kokkos::create_mirror_view(array); - reader.Get(var, Kokkos::subview(array_h, slice).data()); + reader.Get(var, Kokkos::subview(array_h, slice).data(), adios2::Mode::Sync); Kokkos::deep_copy(Kokkos::subview(array, slice), Kokkos::subview(array_h, slice)); } diff --git a/src/framework/domain/checkpoint.cpp b/src/framework/domain/checkpoint.cpp index 6695e3965..beeb8504e 100644 --- a/src/framework/domain/checkpoint.cpp +++ b/src/framework/domain/checkpoint.cpp @@ -32,9 +32,15 @@ namespace ntt { "local_domain is a placeholder", HERE); - auto glob_shape_with_ghosts = mesh().n_all(); - auto off_ncells_with_ghosts = local_domain->offset_ncells(); - auto loc_shape_with_ghosts = local_domain->mesh.n_all(); + std::vector glob_shape_with_ghosts, off_ncells_with_ghosts; + for (auto d { 0u }; d < M::Dim; ++d) { + off_ncells_with_ghosts.push_back( + local_domain->offset_ncells()[d] + + 2 * N_GHOSTS * local_domain->offset_ndomains()[d]); + glob_shape_with_ghosts.push_back( + mesh().n_active()[d] + 2 * N_GHOSTS * ndomains_per_dim()[d]); + } + auto loc_shape_with_ghosts = local_domain->mesh.n_all(); std::vector nplds; for (auto s { 0u }; s < local_domain->species.size(); ++s) { @@ -280,7 +286,8 @@ namespace ntt { auto& domain = g_subdomains[ldidx]; adios2::Box range; for (auto d { 0u }; d < M::Dim; ++d) { - range.first.push_back(domain.offset_ncells()[d]); + range.first.push_back(domain.offset_ncells()[d] + + 2 * N_GHOSTS * domain.offset_ndomains()[d]); range.second.push_back(domain.mesh.n_all()[d]); } range.first.push_back(0); @@ -294,7 +301,8 @@ namespace ntt { domain.fields.em0); adios2::Box range3; for (auto d { 0u }; d < M::Dim; ++d) { - range3.first.push_back(domain.offset_ncells()[d]); + range3.first.push_back(domain.offset_ncells()[d] + + 2 * N_GHOSTS * domain.offset_ndomains()[d]); range3.second.push_back(domain.mesh.n_all()[d]); } range3.first.push_back(0); @@ -308,7 +316,6 @@ namespace ntt { for (auto s { 0u }; s < (unsigned short)(domain.species.size()); ++s) { const auto [loc_npart, offset_npart] = checkpoint::ReadParticleCount(io, reader, s, ldidx, ndomains()); - raise::ErrorIf(loc_npart > domain.species[s].maxnpart(), "loc_npart > domain.species[s].maxnpart()", HERE); From aa2b00dfe8fc1d9f917bd2a27ece8c9ec6087e7d Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Tue, 3 Sep 2024 23:11:14 -0400 Subject: [PATCH 112/773] Fixing a bug in checkpoint writing (prtls). --- src/framework/domain/checkpoint.cpp | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/framework/domain/checkpoint.cpp b/src/framework/domain/checkpoint.cpp index beeb8504e..3d309c090 100644 --- a/src/framework/domain/checkpoint.cpp +++ b/src/framework/domain/checkpoint.cpp @@ -131,12 +131,6 @@ namespace ntt { offset, npart, local_domain->species[s].i1); - g_checkpoint_writer.saveParticleQuantity( - fmt::format("s%d_i1", s + 1), - glob_tot, - offset, - npart, - local_domain->species[s].i1); g_checkpoint_writer.saveParticleQuantity( fmt::format("s%d_dx1", s + 1), glob_tot, @@ -156,7 +150,7 @@ namespace ntt { npart, local_domain->species[s].dx1_prev); } - if constexpr (M::Dim == Dim::_1D or M::Dim == Dim::_2D) { + if constexpr (M::Dim == Dim::_2D or M::Dim == Dim::_3D) { g_checkpoint_writer.saveParticleQuantity( fmt::format("s%d_i2", s + 1), glob_tot, From 1efeffccad57cec7e500cb23a1e31993c202b191 Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Fri, 13 Sep 2024 05:19:03 -0400 Subject: [PATCH 113/773] Optimizing checkpoint writing (flds/prtls). --- src/checkpoint/writer.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/checkpoint/writer.cpp b/src/checkpoint/writer.cpp index 0edc6cb06..85d9485e6 100644 --- a/src/checkpoint/writer.cpp +++ b/src/checkpoint/writer.cpp @@ -59,16 +59,16 @@ namespace checkpoint { lc6.push_back(0); ls6.push_back(6); - m_io.DefineVariable("em", gs6, lc6, ls6, adios2::ConstantDims); + m_io.DefineVariable("em", gs6, lc6, ls6); if (S == ntt::SimEngine::GRPIC) { - m_io.DefineVariable("em0", gs6, lc6, ls6, adios2::ConstantDims); + m_io.DefineVariable("em0", gs6, lc6, ls6); auto gs3 = std::vector(glob_shape.begin(), glob_shape.end()); auto lc3 = std::vector(loc_corner.begin(), loc_corner.end()); auto ls3 = std::vector(loc_shape.begin(), loc_shape.end()); gs3.push_back(3); lc3.push_back(0); ls3.push_back(3); - m_io.DefineVariable("cur0", gs3, lc3, ls3, adios2::ConstantDims); + m_io.DefineVariable("cur0", gs3, lc3, ls3); } } @@ -216,7 +216,7 @@ namespace checkpoint { const ndfield_t& field) { auto field_h = Kokkos::create_mirror_view(field); Kokkos::deep_copy(field_h, field); - m_writer.Put(m_io.InquireVariable(fieldname), field_h.data()); + m_writer.Put(m_io.InquireVariable(fieldname), field_h.data(), adios2::Mode::Sync); } template @@ -234,7 +234,7 @@ namespace checkpoint { auto data_h = Kokkos::create_mirror_view(data); Kokkos::deep_copy(data_h, data); auto data_sub = Kokkos::subview(data_h, slice); - m_writer.Put(var, data_sub.data()); + m_writer.Put(var, data_sub.data(), adios2::Mode::Sync); } template void Writer::savePerDomainVariable(const std::string&, From c7225eb3bb440e8b0c6e5a4d7ac0511367a7cd25 Mon Sep 17 00:00:00 2001 From: hayk Date: Mon, 14 Oct 2024 18:28:15 -0400 Subject: [PATCH 114/773] tests fixed --- src/framework/tests/parameters.cpp | 18 +++++++++++++++--- src/output/tests/writer-nompi.cpp | 6 +++--- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/src/framework/tests/parameters.cpp b/src/framework/tests/parameters.cpp index 9c80554cd..8d30355b9 100644 --- a/src/framework/tests/parameters.cpp +++ b/src/framework/tests/parameters.cpp @@ -242,7 +242,11 @@ auto main(int argc, char* argv[]) -> int { using namespace ntt; { - const auto params_mink_1d = SimulationParams(mink_1d); + auto params_mink_1d = SimulationParams(); + params_mink_1d.setImmutableParams(mink_1d); + params_mink_1d.setMutableParams(mink_1d); + params_mink_1d.setSetupParams(mink_1d); + params_mink_1d.checkPromises(); assert_equal(params_mink_1d.get("grid.metric.metric"), Metric::Minkowski, @@ -314,7 +318,11 @@ auto main(int argc, char* argv[]) -> int { } { - const auto params_sph_2d = SimulationParams(sph_2d); + auto params_sph_2d = SimulationParams(); + params_sph_2d.setImmutableParams(sph_2d); + params_sph_2d.setMutableParams(sph_2d); + params_sph_2d.setSetupParams(sph_2d); + params_sph_2d.checkPromises(); assert_equal(params_sph_2d.get("grid.metric.metric"), Metric::Spherical, @@ -427,7 +435,11 @@ auto main(int argc, char* argv[]) -> int { } { - const auto params_qks_2d = SimulationParams(qks_2d); + auto params_qks_2d = SimulationParams(); + params_qks_2d.setImmutableParams(qks_2d); + params_qks_2d.setMutableParams(qks_2d); + params_qks_2d.setSetupParams(qks_2d); + params_qks_2d.checkPromises(); assert_equal(params_qks_2d.get("grid.metric.metric"), Metric::QKerr_Schild, diff --git a/src/output/tests/writer-nompi.cpp b/src/output/tests/writer-nompi.cpp index e8e6facb7..25a9a2c51 100644 --- a/src/output/tests/writer-nompi.cpp +++ b/src/output/tests/writer-nompi.cpp @@ -30,7 +30,7 @@ auto main(int argc, char* argv[]) -> int { using namespace ntt; auto writer = out::Writer(); - writer.init(&adios, "hdf5"); + writer.init(&adios, "hdf5", "test"); writer.defineMeshLayout({ 10, 10, 10 }, { 0, 0, 0 }, { 10, 10, 10 }, @@ -57,11 +57,11 @@ auto main(int argc, char* argv[]) -> int { names.push_back(writer.fieldWriters()[0].name(i)); addresses.push_back(i); } - writer.beginWriting("test", 0, 0.0); + writer.beginWriting(0, 0.0); writer.writeField(names, field, addresses); writer.endWriting(); - writer.beginWriting("test", 1, 0.1); + writer.beginWriting(1, 0.1); writer.writeField(names, field, addresses); writer.endWriting(); From 684627c2a1cc1ee83f1f271fb7e05cd98ac583e7 Mon Sep 17 00:00:00 2001 From: hayk Date: Tue, 15 Oct 2024 18:10:04 -0400 Subject: [PATCH 115/773] checkpoint test --- cmake/tests.cmake | 2 + src/checkpoint/reader.cpp | 82 +++++---- src/checkpoint/reader.h | 1 + src/checkpoint/tests/CMakeLists.txt | 27 +++ src/checkpoint/tests/checkpoint-nompi.cpp | 205 ++++++++++++++++++++++ src/checkpoint/writer.cpp | 5 +- src/framework/tests/CMakeLists.txt | 18 +- src/output/tests/writer-mpi.cpp | 9 +- 8 files changed, 302 insertions(+), 47 deletions(-) create mode 100644 src/checkpoint/tests/CMakeLists.txt create mode 100644 src/checkpoint/tests/checkpoint-nompi.cpp diff --git a/cmake/tests.cmake b/cmake/tests.cmake index 7bfcb1d12..f1342f679 100644 --- a/cmake/tests.cmake +++ b/cmake/tests.cmake @@ -17,6 +17,7 @@ if (${mpi}) # tests with mpi if (${output}) add_subdirectory(${SRC_DIR}/output/tests ${CMAKE_CURRENT_BINARY_DIR}/output/tests) + add_subdirectory(${SRC_DIR}/framework/tests ${CMAKE_CURRENT_BINARY_DIR}/checkpoint/tests) add_subdirectory(${SRC_DIR}/framework/tests ${CMAKE_CURRENT_BINARY_DIR}/framework/tests) endif() else() @@ -28,5 +29,6 @@ else() add_subdirectory(${SRC_DIR}/framework/tests ${CMAKE_CURRENT_BINARY_DIR}/framework/tests) if (${output}) add_subdirectory(${SRC_DIR}/output/tests ${CMAKE_CURRENT_BINARY_DIR}/output/tests) + add_subdirectory(${SRC_DIR}/checkpoint/tests ${CMAKE_CURRENT_BINARY_DIR}/checkpoint/tests) endif() endif() diff --git a/src/checkpoint/reader.cpp b/src/checkpoint/reader.cpp index 6820a7787..66fcd6757 100644 --- a/src/checkpoint/reader.cpp +++ b/src/checkpoint/reader.cpp @@ -28,11 +28,15 @@ namespace checkpoint { ndfield_t& array) { logger::Checkpoint(fmt::format("Reading field: %s", field.c_str()), HERE); auto field_var = io.InquireVariable(field); - field_var.SetSelection(range); + if (field_var) { + field_var.SetSelection(range); - auto array_h = Kokkos::create_mirror_view(array); - reader.Get(field_var, array_h.data(), adios2::Mode::Sync); - Kokkos::deep_copy(array, array_h); + auto array_h = Kokkos::create_mirror_view(array); + reader.Get(field_var, array_h.data(), adios2::Mode::Sync); + Kokkos::deep_copy(array, array_h); + } else { + raise::Error(fmt::format("Field variable: %s not found", field), HERE); + } } auto ReadParticleCount(adios2::IO& io, @@ -44,32 +48,38 @@ namespace checkpoint { logger::Checkpoint(fmt::format("Reading particle count for: %d", s + 1), HERE); auto npart_var = io.InquireVariable( fmt::format("s%d_npart", s + 1)); - raise::ErrorIf( - npart_var.Shape()[0] != ndomains or npart_var.Shape().size() != 1, - "npart_var.Shape()[0] != ndomains or npart_var.Shape().size() != 1", - HERE); - - npart_var.SetSelection(adios2::Box({ local_dom }, { 1 })); - std::size_t npart; - reader.Get(npart_var, &npart, adios2::Mode::Sync); - const auto loc_npart = npart; + if (npart_var) { + raise::ErrorIf(npart_var.Shape()[0] != ndomains, + "npart_var.Shape()[0] != ndomains", + HERE); + raise::ErrorIf(npart_var.Shape().size() != 1, + "npart_var.Shape().size() != 1", + HERE); + npart_var.SetSelection(adios2::Box({ local_dom }, { 1 })); + std::size_t npart; + reader.Get(npart_var, &npart, adios2::Mode::Sync); + const auto loc_npart = npart; #if !defined(MPI_ENABLED) - std::size_t offset_npart = 0; + std::size_t offset_npart = 0; #else - std::vector glob_nparts(ndomains); - MPI_Allgather(&loc_npart, - 1, - mpi::get_type(), - glob_nparts.data(), - 1, - mpi::get_type(), - MPI_COMM_WORLD); - std::size_t offset_npart = 0; - for (auto d { 0u }; d < local_dom; ++d) { - offset_npart += glob_nparts[d]; - } + std::vector glob_nparts(ndomains); + MPI_Allgather(&loc_npart, + 1, + mpi::get_type(), + glob_nparts.data(), + 1, + mpi::get_type(), + MPI_COMM_WORLD); + std::size_t offset_npart = 0; + for (auto d { 0u }; d < local_dom; ++d) { + offset_npart += glob_nparts[d]; + } #endif - return { loc_npart, offset_npart }; + return { loc_npart, offset_npart }; + } else { + raise::Error("npart_var is not found", HERE); + return { 0, 0 }; + } } template @@ -85,12 +95,18 @@ namespace checkpoint { HERE); auto var = io.InquireVariable( fmt::format("s%d_%s", s + 1, quantity.c_str())); - var.SetSelection(adios2::Box({ offset }, { count })); - const auto slice = std::pair { 0, count }; - auto array_h = Kokkos::create_mirror_view(array); - reader.Get(var, Kokkos::subview(array_h, slice).data(), adios2::Mode::Sync); - Kokkos::deep_copy(Kokkos::subview(array, slice), - Kokkos::subview(array_h, slice)); + if (var) { + var.SetSelection(adios2::Box({ offset }, { count })); + const auto slice = std::pair { 0, count }; + auto array_h = Kokkos::create_mirror_view(array); + reader.Get(var, Kokkos::subview(array_h, slice).data(), adios2::Mode::Sync); + Kokkos::deep_copy(Kokkos::subview(array, slice), + Kokkos::subview(array_h, slice)); + } else { + raise::Error( + fmt::format("Variable: s%d_%s not found", s + 1, quantity.c_str()), + HERE); + } } template void ReadFields(adios2::IO&, diff --git a/src/checkpoint/reader.h b/src/checkpoint/reader.h index f43493026..2ea11bdb1 100644 --- a/src/checkpoint/reader.h +++ b/src/checkpoint/reader.h @@ -4,6 +4,7 @@ * @implements * - checkpoint::ReadFields -> void * - checkpoint::ReadParticleData -> void + * - checkpoint::ReadParticleCount -> std::pair * @cpp: * - reader.cpp * @namespaces: diff --git a/src/checkpoint/tests/CMakeLists.txt b/src/checkpoint/tests/CMakeLists.txt new file mode 100644 index 000000000..3d7475a52 --- /dev/null +++ b/src/checkpoint/tests/CMakeLists.txt @@ -0,0 +1,27 @@ +# ------------------------------ +# @brief: Generates tests for the `ntt_checkpoint` module +# @uses: +# - kokkos [required] +# - adios2 [required] +# - mpi [optional] +# ------------------------------ + +set(SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../) + +function(gen_test title) + set(exec test-output-${title}.xc) + set(src ${title}.cpp) + add_executable(${exec} ${src}) + + set (libs ntt_checkpoint ntt_global) + add_dependencies(${exec} ${libs}) + target_link_libraries(${exec} PRIVATE ${libs} stdc++fs) + + add_test(NAME "CHECKPOINT::${title}" COMMAND "${exec}") +endfunction() + +if (NOT ${mpi}) + gen_test(checkpoint-nompi) +else() + # gen_test(checkpoint-mpi) +endif() diff --git a/src/checkpoint/tests/checkpoint-nompi.cpp b/src/checkpoint/tests/checkpoint-nompi.cpp new file mode 100644 index 000000000..8f7a522fd --- /dev/null +++ b/src/checkpoint/tests/checkpoint-nompi.cpp @@ -0,0 +1,205 @@ +#include "enums.h" +#include "global.h" + +#include "utils/comparators.h" + +#include "checkpoint/reader.h" +#include "checkpoint/writer.h" + +#include +#include +#include + +#include +#include +#include + +using namespace ntt; +using namespace checkpoint; + +void cleanup() { + namespace fs = std::filesystem; + fs::path temp_path { "checkpoints" }; + fs::remove_all(temp_path); +} + +auto main(int argc, char* argv[]) -> int { + Kokkos::initialize(argc, argv); + + try { + constexpr auto nx1 = 10; + constexpr auto nx1_gh = nx1 + 2 * N_GHOSTS; + constexpr auto nx2 = 10; + constexpr auto nx2_gh = nx2 + 2 * N_GHOSTS; + constexpr auto nx3 = 10; + constexpr auto nx3_gh = nx3 + 2 * N_GHOSTS; + constexpr auto i1min = N_GHOSTS; + constexpr auto i2min = N_GHOSTS; + constexpr auto i3min = N_GHOSTS; + constexpr auto i1max = nx1 + N_GHOSTS; + constexpr auto i2max = nx2 + N_GHOSTS; + constexpr auto i3max = nx3 + N_GHOSTS; + constexpr auto npart1 = 100; + constexpr auto npart2 = 100; + + // init data + ndfield_t field1 { "fld1", nx1_gh, nx2_gh, nx3_gh }; + ndfield_t field2 { "fld2", nx1_gh, nx2_gh, nx3_gh }; + + array_t i1 { "i_1", npart1 }; + array_t u1 { "u_1", npart1 }; + array_t i2 { "i_2", npart2 }; + array_t u2 { "u_2", npart2 }; + + { + // fill data + Kokkos::parallel_for( + "fillFlds", + CreateRangePolicy({ i1min, i2min, i3min }, + { i1max, i2max, i3max }), + Lambda(index_t i1, index_t i2, index_t i3) { + field1(i1, i2, i3, 0) = i1 + i2 + i3; + field1(i1, i2, i3, 1) = i1 * i2 / i3; + field1(i1, i2, i3, 2) = i1 / i2 * i3; + field1(i1, i2, i3, 3) = i1 + i2 - i3; + field1(i1, i2, i3, 4) = i1 * i2 + i3; + field1(i1, i2, i3, 5) = i1 / i2 - i3; + field2(i1, i2, i3, 0) = -(i1 + i2 + i3); + field2(i1, i2, i3, 1) = -(i1 * i2 / i3); + field2(i1, i2, i3, 2) = -(i1 / i2 * i3); + field2(i1, i2, i3, 3) = -(i1 + i2 - i3); + field2(i1, i2, i3, 4) = -(i1 * i2 + i3); + field2(i1, i2, i3, 5) = -(i1 / i2 - i3); + }); + Kokkos::parallel_for( + "fillPrtl1", + npart1, + Lambda(index_t p) { + u1(p) = static_cast(p); + i1(p) = static_cast(p); + }); + Kokkos::parallel_for( + "fillPrtl2", + npart2, + Lambda(index_t p) { + u2(p) = -static_cast(p); + i2(p) = -static_cast(p); + }); + } + + adios2::ADIOS adios; + + { + // write checkpoint + Writer writer; + writer.init(&adios, 0, 0.0, 1); + + writer.defineFieldVariables(SimEngine::GRPIC, + { nx1_gh, nx2_gh, nx3_gh }, + { 0, 0, 0 }, + { nx1_gh, nx2_gh, nx3_gh }); + writer.defineParticleVariables(Coord::Sph, Dim::_3D, 2, { 0, 2 }); + + writer.beginSaving(0, 0.0); + + writer.saveField("em", field1); + writer.saveField("em0", field2); + + writer.savePerDomainVariable("s1_npart", 1, 0, npart1); + writer.savePerDomainVariable("s2_npart", 1, 0, npart2); + + writer.saveParticleQuantity("s1_i1", npart1, 0, npart1, i1); + writer.saveParticleQuantity("s1_ux1", npart1, 0, npart1, u1); + writer.saveParticleQuantity("s2_i1", npart2, 0, npart2, i2); + writer.saveParticleQuantity("s2_ux1", npart2, 0, npart2, u2); + + writer.endSaving(); + } + + { + // read checkpoint + ndfield_t field1_read { "fld1_read", nx1_gh, nx2_gh, nx3_gh }; + ndfield_t field2_read { "fld2_read", nx1_gh, nx2_gh, nx3_gh }; + + array_t i1_read { "i_1", npart1 }; + array_t u1_read { "u_1", npart1 }; + array_t i2_read { "i_2", npart2 }; + array_t u2_read { "u_2", npart2 }; + + adios2::IO io = adios.DeclareIO("checkpointRead"); + adios2::Engine reader = io.Open("checkpoints/step-00000000.bp", + adios2::Mode::Read); + reader.BeginStep(); + + auto fieldRange = adios2::Box({ 0, 0, 0, 0 }, + { nx1_gh, nx2_gh, nx3_gh, 6 }); + ReadFields(io, reader, "em", fieldRange, field1_read); + ReadFields(io, reader, "em0", fieldRange, field2_read); + + auto [nprtl1, noff1] = ReadParticleCount(io, reader, 0, 0, 1); + auto [nprtl2, noff2] = ReadParticleCount(io, reader, 1, 0, 1); + + ReadParticleData(io, reader, "ux1", 0, u1_read, nprtl1, noff1); + ReadParticleData(io, reader, "ux1", 1, u2_read, nprtl2, noff2); + ReadParticleData(io, reader, "i1", 0, i1_read, nprtl1, noff1); + ReadParticleData(io, reader, "i1", 1, i2_read, nprtl2, noff2); + + reader.EndStep(); + reader.Close(); + + // check the validity + Kokkos::parallel_for( + "checkFields", + CreateRangePolicy({ 0, 0, 0 }, { nx1_gh, nx2_gh, nx3_gh }), + Lambda(index_t i1, index_t i2, index_t i3) { + for (int i = 0; i < 6; ++i) { + if (not cmp::AlmostEqual(field1(i1, i2, i3, i), + field1_read(i1, i2, i3, i))) { + raise::KernelError(HERE, "Field1 read failed"); + } + if (not cmp::AlmostEqual(field2(i1, i2, i3, i), + field2_read(i1, i2, i3, i))) { + raise::KernelError(HERE, "Field2 read failed"); + } + } + }); + + raise::ErrorIf(npart1 != nprtl1, "Particle count 1 mismatch", HERE); + raise::ErrorIf(npart2 != nprtl2, "Particle count 2 mismatch", HERE); + raise::ErrorIf(noff1 != 0, "Particle offset 1 mismatch", HERE); + raise::ErrorIf(noff2 != 0, "Particle offset 2 mismatch", HERE); + + Kokkos::parallel_for( + "checkPrtl1", + npart1, + Lambda(index_t p) { + if (not cmp::AlmostEqual(u1(p), u1_read(p))) { + raise::KernelError(HERE, "u1 read failed"); + } + if (i1(p) != i1_read(p)) { + raise::KernelError(HERE, "i1 read failed"); + } + }); + Kokkos::parallel_for( + "checkPrtl2", + npart2, + Lambda(index_t p) { + if (not cmp::AlmostEqual(u2(p), u2_read(p))) { + raise::KernelError(HERE, "u2 read failed"); + } + if (i2(p) != i2_read(p)) { + raise::KernelError(HERE, "i2 read failed"); + } + }); + } + + } catch (std::exception& e) { + std::cerr << e.what() << std::endl; + cleanup(); + Kokkos::finalize(); + return 1; + } + cleanup(); + Kokkos::finalize(); + return 0; +} diff --git a/src/checkpoint/writer.cpp b/src/checkpoint/writer.cpp index 85d9485e6..9ef0b51c7 100644 --- a/src/checkpoint/writer.cpp +++ b/src/checkpoint/writer.cpp @@ -138,7 +138,6 @@ namespace checkpoint { void Writer::beginSaving(std::size_t step, long double time) { raise::ErrorIf(!m_enabled, "Checkpoint is not enabled", HERE); raise::ErrorIf(p_adios == nullptr, "ADIOS pointer is null", HERE); - p_adios->ExitComputationBlock(); if (m_writing_mode) { raise::Fatal("Already writing", HERE); } @@ -216,7 +215,9 @@ namespace checkpoint { const ndfield_t& field) { auto field_h = Kokkos::create_mirror_view(field); Kokkos::deep_copy(field_h, field); - m_writer.Put(m_io.InquireVariable(fieldname), field_h.data(), adios2::Mode::Sync); + m_writer.Put(m_io.InquireVariable(fieldname), + field_h.data(), + adios2::Mode::Sync); } template diff --git a/src/framework/tests/CMakeLists.txt b/src/framework/tests/CMakeLists.txt index c09d4ecc0..56ad0783b 100644 --- a/src/framework/tests/CMakeLists.txt +++ b/src/framework/tests/CMakeLists.txt @@ -26,16 +26,16 @@ function(gen_test title) endfunction() if (${mpi}) -gen_test(comm_mpi) + gen_test(comm_mpi) else() -gen_test(parameters) -gen_test(particles) -gen_test(fields) -gen_test(grid_mesh) -if (${DEBUG}) - gen_test(metadomain) -endif() -gen_test(comm_nompi) + gen_test(parameters) + gen_test(particles) + gen_test(fields) + gen_test(grid_mesh) + if (${DEBUG}) + gen_test(metadomain) + endif() + gen_test(comm_nompi) endif() diff --git a/src/output/tests/writer-mpi.cpp b/src/output/tests/writer-mpi.cpp index 649590b49..6b810fa22 100644 --- a/src/output/tests/writer-mpi.cpp +++ b/src/output/tests/writer-mpi.cpp @@ -1,6 +1,7 @@ #include "enums.h" #include "global.h" +#include "arch/mpi_aliases.h" #include "utils/formatting.h" #include "output/fields.h" @@ -19,8 +20,8 @@ void cleanup() { namespace fs = std::filesystem; - // fs::path tempfile_path { "test.h5" }; - // fs::remove(tempfile_path); + fs::path tempfile_path { "test.h5" }; + fs::remove(tempfile_path); } auto main(int argc, char* argv[]) -> int { @@ -68,7 +69,9 @@ auto main(int argc, char* argv[]) -> int { } catch (std::exception& e) { std::cerr << e.what() << std::endl; - cleanup(); + CallOnce([]() { + cleanup(); + }); MPI_Finalize(); Kokkos::finalize(); return 1; From cbeca51456c0717e08cfb00106d053db7a79fe15 Mon Sep 17 00:00:00 2001 From: hayk Date: Tue, 15 Oct 2024 23:19:47 -0400 Subject: [PATCH 116/773] proper output readwrite test --- src/output/tests/writer-nompi.cpp | 170 +++++++++++++++++++----------- 1 file changed, 107 insertions(+), 63 deletions(-) diff --git a/src/output/tests/writer-nompi.cpp b/src/output/tests/writer-nompi.cpp index 25a9a2c51..c087d2895 100644 --- a/src/output/tests/writer-nompi.cpp +++ b/src/output/tests/writer-nompi.cpp @@ -16,6 +16,8 @@ #include #include +using namespace ntt; + void cleanup() { namespace fs = std::filesystem; fs::path tempfile_path { "test.h5" }; @@ -26,86 +28,128 @@ auto main(int argc, char* argv[]) -> int { Kokkos::initialize(argc, argv); try { - adios2::ADIOS adios; + constexpr auto nx1 = 10; + constexpr auto nx1_gh = nx1 + 2 * N_GHOSTS; + constexpr auto nx2 = 10; + constexpr auto nx2_gh = nx2 + 2 * N_GHOSTS; + constexpr auto nx3 = 10; + constexpr auto nx3_gh = nx3 + 2 * N_GHOSTS; + constexpr auto i1min = N_GHOSTS; + constexpr auto i2min = N_GHOSTS; + constexpr auto i3min = N_GHOSTS; + constexpr auto i1max = nx1 + N_GHOSTS; + constexpr auto i2max = nx2 + N_GHOSTS; + constexpr auto i3max = nx3 + N_GHOSTS; + + ndfield_t field { "fld", nx1_gh, nx2_gh, nx3_gh }; + std::vector field_names; - using namespace ntt; - auto writer = out::Writer(); - writer.init(&adios, "hdf5", "test"); - writer.defineMeshLayout({ 10, 10, 10 }, - { 0, 0, 0 }, - { 10, 10, 10 }, - false, - Coord::Cart); - writer.defineFieldOutputs(SimEngine::SRPIC, { "E", "B", "Rho_1_3", "N_2" }); - - ndfield_t field { "fld", - 10 + 2 * N_GHOSTS, - 10 + 2 * N_GHOSTS, - 10 + 2 * N_GHOSTS }; - Kokkos::parallel_for( - "fill", - CreateRangePolicy({ N_GHOSTS, N_GHOSTS, N_GHOSTS }, - { 10 + N_GHOSTS, 10 + N_GHOSTS, 10 + N_GHOSTS }), - Lambda(index_t i1, index_t i2, index_t i3) { - field(i1, i2, i3, 0) = i1 + i2 + i3; - field(i1, i2, i3, 1) = i1 * i2 / i3; - field(i1, i2, i3, 2) = i1 / i2 * i3; - }); - std::vector names; - std::vector addresses; - for (auto i = 0; i < 3; ++i) { - names.push_back(writer.fieldWriters()[0].name(i)); - addresses.push_back(i); + { + // fill data + Kokkos::parallel_for( + "fill", + CreateRangePolicy({ i1min, i2min, i3min }, + { i1max, i2max, i3max }), + Lambda(index_t i1, index_t i2, index_t i3) { + field(i1, i2, i3, 0) = i1 + i2 + i3; + field(i1, i2, i3, 1) = i1 * i2 / i3; + field(i1, i2, i3, 2) = i1 / i2 * i3; + }); } - writer.beginWriting(0, 0.0); - writer.writeField(names, field, addresses); - writer.endWriting(); - writer.beginWriting(1, 0.1); - writer.writeField(names, field, addresses); - writer.endWriting(); + adios2::ADIOS adios; + + { + // write + auto writer = out::Writer(); + writer.init(&adios, "hdf5", "test"); + writer.defineMeshLayout({ nx1, nx2, nx3 }, + { 0, 0, 0 }, + { nx1, nx3, nx3 }, + false, + Coord::Cart); + writer.defineFieldOutputs(SimEngine::SRPIC, { "E", "B", "Rho_1_3", "N_2" }); + + std::vector addresses; + for (auto i = 0; i < 3; ++i) { + field_names.push_back(writer.fieldWriters()[0].name(i)); + addresses.push_back(i); + } + writer.beginWriting(10, 123.0); + writer.writeField(field_names, field, addresses); + writer.endWriting(); + + writer.beginWriting(20, 123.4); + writer.writeField(field_names, field, addresses); + writer.endWriting(); + } { // read - adios2::ADIOS adios; - adios2::IO io = adios.DeclareIO("read-test"); + adios2::IO io = adios.DeclareIO("read-test"); io.SetEngine("hdf5"); adios2::Engine reader = io.Open("test.h5", adios2::Mode::Read); - std::size_t step { 0 }; - long double time { 0.0 }; - reader.Get(io.InquireVariable("Step"), step); - reader.Get(io.InquireVariable("Time"), time); - raise::ErrorIf(step != 0, "Step is not 0", HERE); - raise::ErrorIf(time != 0.0, "Time is not 0.0", HERE); + raise::ErrorIf(io.InquireAttribute("NGhosts").Data()[0] != 0, + "NGhosts is not correct", + HERE); + raise::ErrorIf(io.InquireAttribute("Dimension").Data()[0] != 3, + "Dimension is not correct", + HERE); for (std::size_t step = 0; reader.BeginStep() == adios2::StepStatus::OK; ++step) { - std::size_t step_read; - adios2::Variable stepVar = io.InquireVariable( - "Step"); - reader.Get(stepVar, step_read); - + std::size_t step_read; long double time_read; + + reader.Get(io.InquireVariable("Step"), step_read); reader.Get(io.InquireVariable("Time"), time_read); - raise::ErrorIf(step_read != step, "Step is not correct", HERE); - raise::ErrorIf((float)time_read != (float)step / 10.0f, + raise::ErrorIf(step_read != (step + 1) * 10, "Step is not correct", HERE); + raise::ErrorIf((float)time_read != 123 + (float)step * 0.4f, "Time is not correct", HERE); - for (const auto& name : names) { - auto data = io.InquireVariable(name); - raise::ErrorIf(data.Shape().size() != 3, - fmt::format("%s is not 3D", name.c_str()), - HERE); - - auto dims = data.Shape(); - std::size_t nx1 = dims[0]; - std::size_t nx2 = dims[1]; - std::size_t nx3 = dims[2]; - raise::ErrorIf((nx1 != 10) || (nx2 != 10) || (nx3 != 10), - fmt::format("%s is not 10x10x10", name.c_str()), - HERE); + array_t field_read { "fld_read", nx1, nx2, nx3 }; + auto field_read_h = Kokkos::create_mirror_view(field_read); + + int cntr = 0; + for (const auto& name : field_names) { + auto fieldVar = io.InquireVariable(name); + if (fieldVar) { + raise::ErrorIf(fieldVar.Shape().size() != 3, + fmt::format("%s is not 3D", name.c_str()), + HERE); + + auto dims = fieldVar.Shape(); + std::size_t nx1_r = dims[0]; + std::size_t nx2_r = dims[1]; + std::size_t nx3_r = dims[2]; + raise::ErrorIf( + (nx1_r != 10) || (nx2_r != 10) || (nx3_r != 10), + fmt::format("%s is not %dx%dx%d", name.c_str(), nx1_r, nx2_r, nx3_r), + HERE); + fieldVar.SetSelection( + adios2::Box({ 0, 0, 0 }, { nx1_r, nx2_r, nx3_r })); + reader.Get(fieldVar, field_read_h.data(), adios2::Mode::Sync); + Kokkos::deep_copy(field_read, field_read_h); + + Kokkos::parallel_for( + "check", + CreateRangePolicy({ 0, 0, 0 }, { nx1_r, nx2_r, nx3_r }), + Lambda(index_t i1, index_t i2, index_t i3) { + if (not cmp::AlmostEqual( + field_read(i1, i2, i3), + field(i1 + i1min, i2 + i2min, i3 + i3min, cntr))) { + printf("%e %e\n", + field_read(i1, i2, i3), + field(i1 + i1min, i2 + i2min, i3 + i3min, cntr)); + raise::KernelError(HERE, "Field is not read correctly"); + } + }); + ++cntr; + } else { + raise::Error("Field not found", HERE); + } } reader.EndStep(); } From de597cfa3d1745fa488bab56a9da0c2af5ce11d0 Mon Sep 17 00:00:00 2001 From: hayk Date: Tue, 15 Oct 2024 23:20:13 -0400 Subject: [PATCH 117/773] TODO marked --- src/output/tests/CMakeLists.txt | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/output/tests/CMakeLists.txt b/src/output/tests/CMakeLists.txt index d33cc6c54..37af95fac 100644 --- a/src/output/tests/CMakeLists.txt +++ b/src/output/tests/CMakeLists.txt @@ -4,8 +4,6 @@ # - kokkos [required] # - mpi [optional] # - adios2 [optional] -# !TODO: -# - add more proper write tests for ADIOS2 # ------------------------------ set(SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../) @@ -27,4 +25,4 @@ if (NOT ${mpi}) gen_test(writer-nompi) else() gen_test(writer-mpi) -endif() \ No newline at end of file +endif() From f91ca40039eced9db228964c50cac8af8e0e965e Mon Sep 17 00:00:00 2001 From: hayk Date: Wed, 16 Oct 2024 00:10:56 -0400 Subject: [PATCH 118/773] added downsampling input param --- input.example.toml | 9 +++++---- src/framework/parameters.cpp | 16 ++++++++++------ src/framework/tests/parameters.cpp | 24 ++++++++++++++++++------ src/global/defaults.h | 1 - 4 files changed, 33 insertions(+), 17 deletions(-) diff --git a/input.example.toml b/input.example.toml index 06225024a..5ee34d65d 100644 --- a/input.example.toml +++ b/input.example.toml @@ -340,10 +340,6 @@ # @type: array of strings # @default: [] custom = "" - # @NOT_IMPLEMENTED: Stride for the output of fields: - # @type: unsigned short: > 1 - # @default: 1 - stride = "" # Smoothing window for the output of moments (e.g., "Rho", "Charge", "T", etc.): # @type: unsigned short # @default: 0 @@ -357,6 +353,11 @@ # @default: -1.0 (use `output.interval_time`) # @note: When `interval_time` < 0, the output is controlled by `interval`, otherwise by `interval_time` interval_time = "" + # Downsample factor for the output of fields: + # @type: array of unsigned int >= 1 + # @default: [1, 1, 1] + # @note: The output is downsampled by the given factors in each direction + downsampling = "" [output.particles] # Toggle for the particles output: diff --git a/src/framework/parameters.cpp b/src/framework/parameters.cpp index 1d4672212..3e2f1f9d7 100644 --- a/src/framework/parameters.cpp +++ b/src/framework/parameters.cpp @@ -494,12 +494,16 @@ namespace ntt { "fields", "mom_smooth", defaults::output::mom_smooth)); - set("output.fields.stride", - toml::find_or(toml_data, - "output", - "fields", - "stride", - defaults::output::flds_stride)); + auto field_dwn = toml::find_or(toml_data, + "output", + "fields", + "downsampling", + std::vector { 1, 1, 1 }); + raise::ErrorIf(field_dwn.size() > 3, "invalid `output.fields.downsampling`", HERE); + if (field_dwn.size() > dim) { + field_dwn.erase(field_dwn.begin() + (std::size_t)(dim), field_dwn.end()); + } + set("output.fields.downsampling", field_dwn); // particles const auto prtl_out = toml::find_or(toml_data, diff --git a/src/framework/tests/parameters.cpp b/src/framework/tests/parameters.cpp index 8d30355b9..393cd2409 100644 --- a/src/framework/tests/parameters.cpp +++ b/src/framework/tests/parameters.cpp @@ -73,13 +73,18 @@ const auto mink_1d = u8R"( mystr = "hi" [output] - fields = ["Rho", "J", "B"] - particles = ["X", "U"] format = "hdf5" - mom_smooth = 2 - fields_stride = 1 - prtl_stride = 100 - interval_time = 0.01 + + [output.fields] + quantities = ["Rho", "J", "B"] + mom_smooth = 2 + downsampling = [4, 5] + interval = 100 + + [output.particles] + species = [1, 2] + stride = 100 + interval_time = 0.01 )"_toml; const auto sph_2d = u8R"( @@ -315,6 +320,13 @@ auto main(int argc, char* argv[]) -> int { assert_equal(params_mink_1d.get("setup.mystr"), "hi", "setup.mystr"); + + const auto output_stride = params_mink_1d.get>( + "output.fields.downsampling"); + assert_equal(output_stride.size(), + 1, + "output.fields.downsampling.size()"); + assert_equal(output_stride[0], 4, "output.fields.downsampling[0]"); } { diff --git a/src/global/defaults.h b/src/global/defaults.h index ee9a65af5..be92acbf9 100644 --- a/src/global/defaults.h +++ b/src/global/defaults.h @@ -51,7 +51,6 @@ namespace ntt::defaults { const std::string format = "hdf5"; const std::size_t interval = 100; const unsigned short mom_smooth = 0; - const unsigned short flds_stride = 1; const std::size_t prtl_stride = 100; const real_t spec_emin = 1e-3; const real_t spec_emax = 1e3; From 97cccfaf260568e4aa5945f76e12589211625368 Mon Sep 17 00:00:00 2001 From: hayk Date: Wed, 16 Oct 2024 04:05:50 -0400 Subject: [PATCH 119/773] added field downsampling + test --- extern/adios2 | 2 +- src/checkpoint/tests/checkpoint-nompi.cpp | 4 +- src/framework/domain/output.cpp | 53 ++++-- src/framework/parameters.cpp | 19 +- src/output/tests/writer-nompi.cpp | 66 +++++-- src/output/writer.cpp | 213 ++++++++++++++++------ src/output/writer.h | 26 ++- 7 files changed, 275 insertions(+), 108 deletions(-) diff --git a/extern/adios2 b/extern/adios2 index e524dce1b..a6e8314cc 160000 --- a/extern/adios2 +++ b/extern/adios2 @@ -1 +1 @@ -Subproject commit e524dce1b72ccf75422cea6342ee2d64a6a87964 +Subproject commit a6e8314cc3c0b28d496b44dcd4f15685013b887b diff --git a/src/checkpoint/tests/checkpoint-nompi.cpp b/src/checkpoint/tests/checkpoint-nompi.cpp index 8f7a522fd..23dbd8871 100644 --- a/src/checkpoint/tests/checkpoint-nompi.cpp +++ b/src/checkpoint/tests/checkpoint-nompi.cpp @@ -29,9 +29,9 @@ auto main(int argc, char* argv[]) -> int { try { constexpr auto nx1 = 10; constexpr auto nx1_gh = nx1 + 2 * N_GHOSTS; - constexpr auto nx2 = 10; + constexpr auto nx2 = 13; constexpr auto nx2_gh = nx2 + 2 * N_GHOSTS; - constexpr auto nx3 = 10; + constexpr auto nx3 = 9; constexpr auto nx3_gh = nx3 + 2 * N_GHOSTS; constexpr auto i1min = N_GHOSTS; constexpr auto i2min = N_GHOSTS; diff --git a/src/framework/domain/output.cpp b/src/framework/domain/output.cpp index 0918eb2d3..46ca95ede 100644 --- a/src/framework/domain/output.cpp +++ b/src/framework/domain/output.cpp @@ -69,6 +69,8 @@ namespace ntt { g_writer.defineMeshLayout(glob_shape_with_ghosts, off_ncells_with_ghosts, loc_shape_with_ghosts, + params.template get>( + "output.fields.downsampling"), incl_ghosts, M::CoordType); const auto fields_to_write = params.template get>( @@ -216,37 +218,50 @@ namespace ntt { g_writer.beginWriting(current_step, current_time); if (write_fields) { const auto incl_ghosts = params.template get("output.debug.ghosts"); + const auto dwn = params.template get>( + "output.fields.downsampling"); for (unsigned short dim = 0; dim < M::Dim; ++dim) { - const auto is_last = local_domain->offset_ncells()[dim] + - local_domain->mesh.n_active()[dim] == - mesh().n_active()[dim]; - array_t xc { "Xc", - local_domain->mesh.n_active()[dim] + - (incl_ghosts ? 2 * N_GHOSTS : 0) }; - array_t xe { "Xe", - local_domain->mesh.n_active()[dim] + - (incl_ghosts ? 2 * N_GHOSTS : 0) + - (is_last ? 1 : 0) }; - const auto offset = (incl_ghosts ? N_GHOSTS : 0); - const auto ncells = local_domain->mesh.n_active()[dim]; - const auto& metric = local_domain->mesh.metric; + const auto l_size = local_domain->mesh.n_active()[dim]; + const auto l_offset = local_domain->offset_ncells()[dim]; + const auto g_size = mesh().n_active()[dim]; + + const auto dwn_in_dim = dwn[dim]; + const auto l_size_dwn = static_cast(l_size / dwn_in_dim); + + const auto is_last = l_offset + l_size == g_size; + + const auto add_ghost = (incl_ghosts ? 2 * N_GHOSTS : 0); + const auto add_last = (is_last ? 1 : 0); + + array_t xc { "Xc", l_size_dwn + add_ghost }; + array_t xe { "Xe", l_size_dwn + add_ghost + add_last }; + + const auto offset = (incl_ghosts ? N_GHOSTS : 0); + const auto ncells = l_size_dwn; + const auto first_cell = static_cast(l_offset / dwn_in_dim) * + dwn_in_dim - + l_offset; + + const auto& metric = local_domain->mesh.metric; + Kokkos::parallel_for( "GenerateMesh", ncells, - Lambda(index_t i) { + Lambda(index_t i_dwn) { + const auto i = first_cell + i_dwn * dwn_in_dim; const auto i_ = static_cast(i); coord_t x_Cd { ZERO }, x_Ph { ZERO }; x_Cd[dim] = i_ + HALF; metric.template convert(x_Cd, x_Ph); - xc(offset + i) = x_Ph[dim]; - x_Cd[dim] = i_; + xc(offset + i_dwn) = x_Ph[dim]; + x_Cd[dim] = i_; metric.template convert(x_Cd, x_Ph); - xe(offset + i) = x_Ph[dim]; - if (is_last && i == ncells - 1) { + xe(offset + i_dwn) = x_Ph[dim]; + if (is_last && i_dwn == ncells - 1) { x_Cd[dim] = i_ + ONE; metric.template convert(x_Cd, x_Ph); - xe(offset + i + 1) = x_Ph[dim]; + xe(offset + i_dwn + 1) = x_Ph[dim]; } }); g_writer.writeMesh(dim, xc, xe); diff --git a/src/framework/parameters.cpp b/src/framework/parameters.cpp index 3e2f1f9d7..b667b5ac9 100644 --- a/src/framework/parameters.cpp +++ b/src/framework/parameters.cpp @@ -503,6 +503,9 @@ namespace ntt { if (field_dwn.size() > dim) { field_dwn.erase(field_dwn.begin() + (std::size_t)(dim), field_dwn.end()); } + for (const auto& dwn : field_dwn) { + raise::ErrorIf(dwn == 0, "downsampling factor must be nonzero", HERE); + } set("output.fields.downsampling", field_dwn); // particles @@ -565,8 +568,20 @@ namespace ntt { /* [output.debug] ------------------------------------------------------- */ set("output.debug.as_is", toml::find_or(toml_data, "output", "debug", "as_is", false)); - set("output.debug.ghosts", - toml::find_or(toml_data, "output", "debug", "ghosts", false)); + const auto output_ghosts = toml::find_or(toml_data, + "output", + "debug", + "ghosts", + false); + set("output.debug.ghosts", output_ghosts); + if (output_ghosts) { + for (const auto& dwn : field_dwn) { + raise::ErrorIf( + dwn != 1, + "full resolution required when outputting with ghost cells", + HERE); + } + } /* [checkpoint] --------------------------------------------------------- */ set("checkpoint.interval", diff --git a/src/output/tests/writer-nompi.cpp b/src/output/tests/writer-nompi.cpp index c087d2895..4c032094b 100644 --- a/src/output/tests/writer-nompi.cpp +++ b/src/output/tests/writer-nompi.cpp @@ -30,9 +30,9 @@ auto main(int argc, char* argv[]) -> int { try { constexpr auto nx1 = 10; constexpr auto nx1_gh = nx1 + 2 * N_GHOSTS; - constexpr auto nx2 = 10; + constexpr auto nx2 = 14; constexpr auto nx2_gh = nx2 + 2 * N_GHOSTS; - constexpr auto nx3 = 10; + constexpr auto nx3 = 17; constexpr auto nx3_gh = nx3 + 2 * N_GHOSTS; constexpr auto i1min = N_GHOSTS; constexpr auto i2min = N_GHOSTS; @@ -41,6 +41,10 @@ auto main(int argc, char* argv[]) -> int { constexpr auto i2max = nx2 + N_GHOSTS; constexpr auto i3max = nx3 + N_GHOSTS; + constexpr auto dwn1 = 2; + constexpr auto dwn2 = 1; + constexpr auto dwn3 = 5; + ndfield_t field { "fld", nx1_gh, nx2_gh, nx3_gh }; std::vector field_names; @@ -51,9 +55,12 @@ auto main(int argc, char* argv[]) -> int { CreateRangePolicy({ i1min, i2min, i3min }, { i1max, i2max, i3max }), Lambda(index_t i1, index_t i2, index_t i3) { - field(i1, i2, i3, 0) = i1 + i2 + i3; - field(i1, i2, i3, 1) = i1 * i2 / i3; - field(i1, i2, i3, 2) = i1 / i2 * i3; + const auto i1_ = static_cast(i1); + const auto i2_ = static_cast(i2); + const auto i3_ = static_cast(i3); + field(i1, i2, i3, 0) = i1_; + field(i1, i2, i3, 1) = i2_; + field(i1, i2, i3, 2) = i3_; }); } @@ -65,7 +72,8 @@ auto main(int argc, char* argv[]) -> int { writer.init(&adios, "hdf5", "test"); writer.defineMeshLayout({ nx1, nx2, nx3 }, { 0, 0, 0 }, - { nx1, nx3, nx3 }, + { nx1, nx2, nx3 }, + { dwn1, dwn2, dwn3 }, false, Coord::Cart); writer.defineFieldOutputs(SimEngine::SRPIC, { "E", "B", "Rho_1_3", "N_2" }); @@ -109,8 +117,7 @@ auto main(int argc, char* argv[]) -> int { "Time is not correct", HERE); - array_t field_read { "fld_read", nx1, nx2, nx3 }; - auto field_read_h = Kokkos::create_mirror_view(field_read); + array_t field_read {}; int cntr = 0; for (const auto& name : field_names) { @@ -124,12 +131,22 @@ auto main(int argc, char* argv[]) -> int { std::size_t nx1_r = dims[0]; std::size_t nx2_r = dims[1]; std::size_t nx3_r = dims[2]; - raise::ErrorIf( - (nx1_r != 10) || (nx2_r != 10) || (nx3_r != 10), - fmt::format("%s is not %dx%dx%d", name.c_str(), nx1_r, nx2_r, nx3_r), - HERE); + raise::ErrorIf((nx1_r != nx1 / dwn1) || (nx2_r != nx2 / dwn2) || + (nx3_r != nx3 / dwn3), + fmt::format("%s = %ldx%ldx%ld is not %dx%dx%d", + name.c_str(), + nx1_r, + nx2_r, + nx3_r, + nx1 / dwn1, + nx2 / dwn2, + nx3 / dwn3), + HERE); + fieldVar.SetSelection( adios2::Box({ 0, 0, 0 }, { nx1_r, nx2_r, nx3_r })); + field_read = array_t(name, nx1_r, nx2_r, nx3_r); + auto field_read_h = Kokkos::create_mirror_view(field_read); reader.Get(fieldVar, field_read_h.data(), adios2::Mode::Sync); Kokkos::deep_copy(field_read, field_read_h); @@ -137,19 +154,32 @@ auto main(int argc, char* argv[]) -> int { "check", CreateRangePolicy({ 0, 0, 0 }, { nx1_r, nx2_r, nx3_r }), Lambda(index_t i1, index_t i2, index_t i3) { - if (not cmp::AlmostEqual( - field_read(i1, i2, i3), - field(i1 + i1min, i2 + i2min, i3 + i3min, cntr))) { - printf("%e %e\n", + if (not cmp::AlmostEqual(field_read(i1, i2, i3), + field(i1 * dwn1 + i1min, + i2 * dwn2 + i2min, + i3 * dwn3 + i3min, + cntr))) { + printf("\n:::::::::::::::\nfield_read(%ld, %ld, %ld) = %f != " + "field(%ld, %ld, %ld, %d) = %f\n:::::::::::::::\n", + i1, + i2, + i3, field_read(i1, i2, i3), - field(i1 + i1min, i2 + i2min, i3 + i3min, cntr)); + i1 * dwn1 + i1min, + i2 * dwn2 + i2min, + i3 * dwn3 + i3min, + cntr, + field(i1 * dwn1 + i1min, + i2 * dwn2 + i2min, + i3 * dwn3 + i3min, + cntr)); raise::KernelError(HERE, "Field is not read correctly"); } }); - ++cntr; } else { raise::Error("Field not found", HERE); } + ++cntr; } reader.EndStep(); } diff --git a/src/output/writer.cpp b/src/output/writer.cpp index 3d526b306..5c6dfe6d6 100644 --- a/src/output/writer.cpp +++ b/src/output/writer.cpp @@ -60,25 +60,44 @@ namespace out { m_mode = mode; } - void Writer::defineMeshLayout(const std::vector& glob_shape, - const std::vector& loc_corner, - const std::vector& loc_shape, - bool incl_ghosts, - Coord coords) { - m_flds_ghosts = incl_ghosts; + void Writer::defineMeshLayout(const std::vector& glob_shape, + const std::vector& loc_corner, + const std::vector& loc_shape, + const std::vector& dwn, + bool incl_ghosts, + Coord coords) { + m_flds_ghosts = incl_ghosts; + m_dwn = dwn; + m_flds_g_shape = glob_shape; m_flds_l_corner = loc_corner; m_flds_l_shape = loc_shape; + for (std::size_t i { 0 }; i < glob_shape.size(); ++i) { + raise::ErrorIf(dwn[i] != 1 && incl_ghosts, + "Downsampling with ghosts not supported", + HERE); + m_flds_g_shape_dwn.push_back( + static_cast(glob_shape[i] / m_dwn[i])); + m_flds_l_corner_dwn.push_back( + static_cast(loc_corner[i] / m_dwn[i])); + m_flds_l_shape_dwn.push_back( + static_cast((loc_corner[i] + loc_shape[i]) / m_dwn[i]) - + static_cast(loc_corner[i] / m_dwn[i])); + m_flds_l_first.push_back( + static_cast(loc_corner[i] / m_dwn[i]) * m_dwn[i] - + loc_corner[i]); + } + m_io.DefineAttribute("NGhosts", incl_ghosts ? N_GHOSTS : 0); m_io.DefineAttribute("Dimension", m_flds_g_shape.size()); m_io.DefineAttribute("Coordinates", std::string(coords.to_string())); for (std::size_t i { 0 }; i < m_flds_g_shape.size(); ++i) { // cell-centers - adios2::Dims g_shape = { m_flds_g_shape[i] }; - adios2::Dims l_corner = { m_flds_l_corner[i] }; - adios2::Dims l_shape = { m_flds_l_shape[i] }; + adios2::Dims g_shape = { m_flds_g_shape_dwn[i] }; + adios2::Dims l_corner = { m_flds_l_corner_dwn[i] }; + adios2::Dims l_shape = { m_flds_l_shape_dwn[i] }; m_io.DefineVariable("X" + std::to_string(i + 1), g_shape, l_corner, @@ -87,8 +106,8 @@ namespace out { // cell-edges const auto is_last = (m_flds_l_corner[i] + m_flds_l_shape[i] == m_flds_g_shape[i]); - adios2::Dims g_shape1 = { m_flds_g_shape[i] + 1 }; - adios2::Dims l_shape1 = { m_flds_l_shape[i] + (is_last ? 1 : 0) }; + adios2::Dims g_shape1 = { m_flds_g_shape_dwn[i] + 1 }; + adios2::Dims l_shape1 = { m_flds_l_shape_dwn[i] + (is_last ? 1 : 0) }; m_io.DefineVariable("X" + std::to_string(i + 1) + "e", g_shape1, l_corner, @@ -100,9 +119,6 @@ namespace out { Kokkos::LayoutRight>::value) { m_io.DefineAttribute("LayoutRight", 1); } else { - std::reverse(m_flds_g_shape.begin(), m_flds_g_shape.end()); - std::reverse(m_flds_l_corner.begin(), m_flds_l_corner.end()); - std::reverse(m_flds_l_shape.begin(), m_flds_l_shape.end()); m_io.DefineAttribute("LayoutRight", 0); } } @@ -110,8 +126,9 @@ namespace out { void Writer::defineFieldOutputs(const SimEngine& S, const std::vector& flds_out) { m_flds_writers.clear(); - raise::ErrorIf((m_flds_g_shape.size() == 0) || (m_flds_l_corner.size() == 0) || - (m_flds_l_shape.size() == 0), + raise::ErrorIf((m_flds_g_shape_dwn.size() == 0) || + (m_flds_l_corner_dwn.size() == 0) || + (m_flds_l_shape_dwn.size() == 0), "Mesh layout must be defined before field output", HERE); for (const auto& fld : flds_out) { @@ -119,17 +136,19 @@ namespace out { } for (const auto& fld : m_flds_writers) { if (fld.comp.size() == 0) { + // scalar m_io.DefineVariable(fld.name(), - m_flds_g_shape, - m_flds_l_corner, - m_flds_l_shape, + m_flds_g_shape_dwn, + m_flds_l_corner_dwn, + m_flds_l_shape_dwn, adios2::ConstantDims); } else { + // vector or tensor for (std::size_t i { 0 }; i < fld.comp.size(); ++i) { m_io.DefineVariable(fld.name(i), - m_flds_g_shape, - m_flds_l_corner, - m_flds_l_shape, + m_flds_g_shape_dwn, + m_flds_l_corner_dwn, + m_flds_l_shape_dwn, adios2::ConstantDims); } } @@ -178,48 +197,105 @@ namespace out { } template - void WriteField(adios2::IO& io, - adios2::Engine& writer, - const std::string& varname, - const ndfield_t& field, - std::size_t comp, - bool ghosts) { - auto var = io.InquireVariable(varname); - const auto gh_zones = ghosts ? 0 : N_GHOSTS; + void WriteField(adios2::IO& io, + adios2::Engine& writer, + const std::string& varname, + const ndfield_t& field, + std::size_t comp, + std::vector dwn, + std::vector first_cell, + bool ghosts) { + // when dwn != 1 in any direction, it is assumed that ghosts == false + auto var = io.InquireVariable(varname); + const auto gh_zones = ghosts ? 0 : N_GHOSTS; + ndarray_t output_field {}; if constexpr (D == Dim::_1D) { - auto slice_i1 = range_tuple_t(gh_zones, field.extent(0) - gh_zones); - auto slice = Kokkos::subview(field, slice_i1, comp); - auto output_field = array_t("output_field", slice.extent(0)); - Kokkos::deep_copy(output_field, slice); - auto output_field_host = Kokkos::create_mirror_view(output_field); - Kokkos::deep_copy(output_field_host, output_field); - writer.Put(var, output_field_host); + if (ghosts || dwn[0] == 1) { + auto slice_i1 = range_tuple_t(gh_zones, field.extent(0) - gh_zones); + auto slice = Kokkos::subview(field, slice_i1, comp); + output_field = array_t { "output_field", slice.extent(0) }; + Kokkos::deep_copy(output_field, slice); + } else { + const auto dwn1 = dwn[0]; + const auto nx1_dwn = static_cast( + (field.extent(0) - 2 * N_GHOSTS) / dwn1); + const auto first_cell1 = first_cell[0]; + output_field = array_t { "output_field", nx1_dwn }; + Kokkos::parallel_for( + "outputField", + nx1_dwn, + Lambda(index_t i1) { + output_field(i1) = field(first_cell1 + i1 * dwn1 + N_GHOSTS, comp); + }); + } } else if constexpr (D == Dim::_2D) { - auto slice_i1 = range_tuple_t(gh_zones, field.extent(0) - gh_zones); - auto slice_i2 = range_tuple_t(gh_zones, field.extent(1) - gh_zones); - auto slice = Kokkos::subview(field, slice_i1, slice_i2, comp); - auto output_field = array_t("output_field", + if (ghosts || (dwn[0] == 1 && dwn[1] == 1)) { + auto slice_i1 = range_tuple_t(gh_zones, field.extent(0) - gh_zones); + auto slice_i2 = range_tuple_t(gh_zones, field.extent(1) - gh_zones); + auto slice = Kokkos::subview(field, slice_i1, slice_i2, comp); + output_field = array_t { "output_field", slice.extent(0), - slice.extent(1)); - Kokkos::deep_copy(output_field, slice); - auto output_field_host = Kokkos::create_mirror_view(output_field); - Kokkos::deep_copy(output_field_host, output_field); - writer.Put(var, output_field_host); + slice.extent(1) }; + Kokkos::deep_copy(output_field, slice); + } else { + const auto dwn1 = dwn[0]; + const auto dwn2 = dwn[1]; + const auto nx1_dwn = static_cast( + (field.extent(0) - 2 * N_GHOSTS) / dwn1); + const auto nx2_dwn = static_cast( + (field.extent(1) - 2 * N_GHOSTS) / dwn2); + const auto first_cell1 = first_cell[0]; + const auto first_cell2 = first_cell[1]; + output_field = array_t { "output_field", nx1_dwn, nx2_dwn }; + Kokkos::parallel_for( + "outputField", + CreateRangePolicy({ 0, 0 }, { nx1_dwn, nx2_dwn }), + Lambda(index_t i1, index_t i2) { + output_field(i1, i2) = field(first_cell1 + i1 * dwn1 + N_GHOSTS, + first_cell2 + i2 * dwn2 + N_GHOSTS, + comp); + }); + } } else if constexpr (D == Dim::_3D) { - auto slice_i1 = range_tuple_t(gh_zones, field.extent(0) - gh_zones); - auto slice_i2 = range_tuple_t(gh_zones, field.extent(1) - gh_zones); - auto slice_i3 = range_tuple_t(gh_zones, field.extent(2) - gh_zones); - auto slice = Kokkos::subview(field, slice_i1, slice_i2, slice_i3, comp); - auto output_field = array_t("output_field", - slice.extent(0), - slice.extent(1), - slice.extent(2)); - Kokkos::deep_copy(output_field, slice); - auto output_field_host = Kokkos::create_mirror_view(output_field); - Kokkos::deep_copy(output_field_host, output_field); - writer.Put(var, output_field_host); + if (ghosts || (dwn[0] == 1 && dwn[1] == 1 && dwn[2] == 1)) { + auto slice_i1 = range_tuple_t(gh_zones, field.extent(0) - gh_zones); + auto slice_i2 = range_tuple_t(gh_zones, field.extent(1) - gh_zones); + auto slice_i3 = range_tuple_t(gh_zones, field.extent(2) - gh_zones); + auto slice = Kokkos::subview(field, slice_i1, slice_i2, slice_i3, comp); + output_field = array_t { "output_field", + slice.extent(0), + slice.extent(1), + slice.extent(2) }; + Kokkos::deep_copy(output_field, slice); + } else { + const auto dwn1 = dwn[0]; + const auto dwn2 = dwn[1]; + const auto dwn3 = dwn[2]; + const auto nx1_dwn = static_cast( + (field.extent(0) - 2 * N_GHOSTS) / dwn1); + const auto nx2_dwn = static_cast( + (field.extent(1) - 2 * N_GHOSTS) / dwn2); + const auto nx3_dwn = static_cast( + (field.extent(2) - 2 * N_GHOSTS) / dwn3); + const auto first_cell1 = first_cell[0]; + const auto first_cell2 = first_cell[1]; + const auto first_cell3 = first_cell[2]; + output_field = array_t { "output_field", nx1_dwn, nx2_dwn, nx3_dwn }; + Kokkos::parallel_for( + "outputField", + CreateRangePolicy({ 0, 0, 0 }, { nx1_dwn, nx2_dwn, nx3_dwn }), + Lambda(index_t i1, index_t i2, index_t i3) { + output_field(i1, i2, i3) = field(first_cell1 + i1 * dwn1 + N_GHOSTS, + first_cell2 + i2 * dwn2 + N_GHOSTS, + first_cell3 + i3 * dwn3 + N_GHOSTS, + comp); + }); + } } + auto output_field_h = Kokkos::create_mirror_view(output_field); + Kokkos::deep_copy(output_field_h, output_field); + writer.Put(var, output_field_h); } template @@ -233,7 +309,14 @@ namespace out { "# of names != # of addresses ", HERE); for (std::size_t i { 0 }; i < addresses.size(); ++i) { - WriteField(m_io, m_writer, names[i], fld, addresses[i], m_flds_ghosts); + WriteField(m_io, + m_writer, + names[i], + fld, + addresses[i], + m_dwn, + m_flds_l_first, + m_flds_ghosts); } } @@ -360,36 +443,48 @@ namespace out { const std::string&, const ndfield_t&, std::size_t, + std::vector, + std::vector, bool); template void WriteField(adios2::IO&, adios2::Engine&, const std::string&, const ndfield_t&, std::size_t, + std::vector, + std::vector, bool); template void WriteField(adios2::IO&, adios2::Engine&, const std::string&, const ndfield_t&, std::size_t, + std::vector, + std::vector, bool); template void WriteField(adios2::IO&, adios2::Engine&, const std::string&, const ndfield_t&, std::size_t, + std::vector, + std::vector, bool); template void WriteField(adios2::IO&, adios2::Engine&, const std::string&, const ndfield_t&, std::size_t, + std::vector, + std::vector, bool); template void WriteField(adios2::IO&, adios2::Engine&, const std::string&, const ndfield_t&, std::size_t, + std::vector, + std::vector, bool); } // namespace out diff --git a/src/output/writer.h b/src/output/writer.h index ba24a3d65..566da44b2 100644 --- a/src/output/writer.h +++ b/src/output/writer.h @@ -37,14 +37,25 @@ namespace out { adios2::Mode m_mode { adios2::Mode::Write }; // global shape of the fields array to output - adios2::Dims m_flds_g_shape; + std::vector m_flds_g_shape; // local corner of the fields array to output - adios2::Dims m_flds_l_corner; + std::vector m_flds_l_corner; // local shape of the fields array to output - adios2::Dims m_flds_l_shape; - bool m_flds_ghosts; - std::string m_engine; - std::string m_fname; + std::vector m_flds_l_shape; + + // downsampling factors for each dimension + std::vector m_dwn; + // starting cell in each dimension (not including ghosts) + std::vector m_flds_l_first; + + // same but downsampled + adios2::Dims m_flds_g_shape_dwn; + adios2::Dims m_flds_l_corner_dwn; + adios2::Dims m_flds_l_shape_dwn; + + bool m_flds_ghosts; + std::string m_engine; + std::string m_fname; std::map m_trackers; @@ -73,7 +84,8 @@ namespace out { void defineMeshLayout(const std::vector&, const std::vector&, const std::vector&, - bool incl_ghosts, + const std::vector&, + bool, Coord); void defineFieldOutputs(const SimEngine&, const std::vector&); From 24691ea2fe8a8ae6ca48e2a9e082e8b099274b73 Mon Sep 17 00:00:00 2001 From: hayk Date: Wed, 16 Oct 2024 04:28:17 -0400 Subject: [PATCH 120/773] added a cpu runner for actions (totest) --- .github/workflows/actions.yml | 4 +- dev/runners/Dockerfile.runner.cpu | 73 +++++++++++++++++++++++++++++++ dev/runners/README.md | 6 +++ 3 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 dev/runners/Dockerfile.runner.cpu diff --git a/.github/workflows/actions.yml b/.github/workflows/actions.yml index cd7119789..331d6526c 100644 --- a/.github/workflows/actions.yml +++ b/.github/workflows/actions.yml @@ -11,7 +11,7 @@ jobs: strategy: fail-fast: false matrix: - device: [amd-gpu, nvidia-gpu] + device: [cpu, amd-gpu, nvidia-gpu] precision: [double, single] exclude: - device: amd-gpu @@ -35,6 +35,8 @@ jobs: fi elif [ "${{ matrix.device }}" = "amd-gpu" ]; then FLAGS="-D Kokkos_ENABLE_HIP=ON -D Kokkos_ARCH_AMD_GFX1100=ON" + elif [ "${{ matrix.device }}" = "cpu" ]; then + FLAGS="" fi cmake -B build -D TESTS=ON -D output=ON -D precision=${{ matrix.precision }} $FLAGS - name: Compile diff --git a/dev/runners/Dockerfile.runner.cpu b/dev/runners/Dockerfile.runner.cpu new file mode 100644 index 000000000..fc13ec9b5 --- /dev/null +++ b/dev/runners/Dockerfile.runner.cpu @@ -0,0 +1,73 @@ +FROM ubuntu:22.04 + +ARG DEBIAN_FRONTEND=noninteractive + +# upgrade +RUN apt-get update && apt-get upgrade -y + +# cmake & build tools +RUN apt-get remove -y --purge cmake && \ + apt-get install -y sudo wget curl build-essential && \ + wget "https://github.com/Kitware/CMake/releases/download/v3.29.6/cmake-3.29.6-linux-x86_64.tar.gz" -P /opt && \ + tar xvf /opt/cmake-3.29.6-linux-x86_64.tar.gz -C /opt && \ + rm /opt/cmake-3.29.6-linux-x86_64.tar.gz +ENV PATH=/opt/cmake-3.29.6-linux-x86_64/bin:$PATH + +# adios2 +RUN apt-get update && apt-get install -y git libhdf5-dev && \ + git clone https://github.com/ornladios/ADIOS2.git /opt/adios2-src && \ + cd /opt/adios2-src && \ + cmake -B build \ + -D CMAKE_CXX_STANDARD=17 \ + -D CMAKE_CXX_EXTENSIONS=OFF \ + -D CMAKE_POSITION_INDEPENDENT_CODE=TRUE \ + -D BUILD_SHARED_LIBS=ON \ + -D ADIOS2_USE_HDF5=ON \ + -D ADIOS2_USE_Python=OFF \ + -D ADIOS2_USE_Fortran=OFF \ + -D ADIOS2_USE_ZeroMQ=OFF \ + -D BUILD_TESTING=OFF \ + -D ADIOS2_BUILD_EXAMPLES=OFF \ + -D ADIOS2_USE_MPI=OFF \ + -D ADIOS2_HAVE_HDF5_VOL=OFF \ + -D CMAKE_INSTALL_PREFIX=/opt/adios2 && \ + cmake --build build -j && \ + cmake --install build && \ + rm -rf /opt/adios2-src + +ENV HDF5_ROOT=/usr +ENV ADIOS2_DIR=/opt/adios2 +ENV PATH=/opt/adios2/bin:$PATH + +# cleanup +RUN apt-get clean && \ + apt-get autoclean && \ + apt-get autoremove -y && \ + rm -rf /var/lib/cache/* && \ + rm -rf /var/lib/log/* && \ + rm -rf /var/lib/apt/lists/* + +ARG USER=runner +RUN useradd -ms /usr/bin/zsh $USER && \ + usermod -aG sudo $USER && \ + echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers + +USER $USER +ARG HOME=/home/$USER +WORKDIR $HOME + +# gh runner +ARG RUNNER_VERSION=2.317.0 +RUN mkdir actions-runner +WORKDIR $HOME/actions-runner + +RUN curl -o actions-runner-linux-x64-${RUNNER_VERSION}.tar.gz \ + -L https://github.com/actions/runner/releases/download/v${RUNNER_VERSION}/actions-runner-linux-x64-${RUNNER_VERSION}.tar.gz && \ + tar xzf ./actions-runner-linux-x64-${RUNNER_VERSION}.tar.gz && \ + sudo ./bin/installdependencies.sh + +ADD start.sh start.sh +RUN sudo chown $USER:$USER start.sh && \ + sudo chmod +x start.sh + +ENTRYPOINT ["./start.sh"] diff --git a/dev/runners/README.md b/dev/runners/README.md index 08d0cd176..957898fa7 100644 --- a/dev/runners/README.md +++ b/dev/runners/README.md @@ -19,3 +19,9 @@ docker run -e TOKEN= -e LABEL=nvidia-gpu --runtime=nvidia --gpus=all -dt docker build -t ghrunner:amd -f Dockerfile.runner.rocm . docker run -e TOKEN= -e LABEL=amd-gpu --device=/dev/kfd --device=/dev/dri --security-opt seccomp=unconfined --group-add video -dt ghrunner:amd ``` + +### CPU + +```sh +docker build -t ghrunner:cpu -f Dockerfile.runner.cpu . +``` From e3d40c3b10d2088d95acd215713ac934283a4488 Mon Sep 17 00:00:00 2001 From: hayk Date: Wed, 16 Oct 2024 04:30:59 -0400 Subject: [PATCH 121/773] RUNTEST --- .github/workflows/actions.yml | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/.github/workflows/actions.yml b/.github/workflows/actions.yml index 331d6526c..4db596243 100644 --- a/.github/workflows/actions.yml +++ b/.github/workflows/actions.yml @@ -1,27 +1,36 @@ name: Unit tests on: - pull_request: - branches: - - '**rc' - - 'master' + push: jobs: + check-commit: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + - name: Check commit message + id: check_message + run: | + if git log -1 --pretty=%B | grep -q "RUNTEST"; then + echo "::set-output name=run_tests::true" + else + echo "::set-output name=run_tests::false" + exit 1 tests: + needs: check-commit + if: steps.check_message.outputs.run_tests == 'true' strategy: fail-fast: false matrix: device: [cpu, amd-gpu, nvidia-gpu] precision: [double, single] - exclude: + exclude: # my AMD GPU doesn't support fp64 atomics : ( - device: amd-gpu precision: double - # my AMD GPU doesn't support fp64 atomics : ( - runs-on: [self-hosted, "${{ matrix.device }}"] - if: contains(github.event.head_commit.message, 'totest') steps: - name: Checkout - uses: actions/checkout@v3.3.0 + uses: actions/checkout@v4 - name: Configure run: | if [ "${{ matrix.device }}" = "nvidia-gpu" ]; then From 81f5df0baee2eac88d7220f9d29b6abf4ac2ffa2 Mon Sep 17 00:00:00 2001 From: hayk Date: Wed, 16 Oct 2024 04:33:16 -0400 Subject: [PATCH 122/773] RUNTEST --- .github/workflows/actions.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/actions.yml b/.github/workflows/actions.yml index 4db596243..703f97a6a 100644 --- a/.github/workflows/actions.yml +++ b/.github/workflows/actions.yml @@ -28,6 +28,7 @@ jobs: exclude: # my AMD GPU doesn't support fp64 atomics : ( - device: amd-gpu precision: double + runs-on: [self-hosted, "${{ matrix.device }}"] steps: - name: Checkout uses: actions/checkout@v4 From 7b7382bc90427654c1baf0b23e56adfdab969027 Mon Sep 17 00:00:00 2001 From: hayk Date: Wed, 16 Oct 2024 04:35:26 -0400 Subject: [PATCH 123/773] RUNTEST --- .github/workflows/actions.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/actions.yml b/.github/workflows/actions.yml index 703f97a6a..3af457b6e 100644 --- a/.github/workflows/actions.yml +++ b/.github/workflows/actions.yml @@ -6,6 +6,8 @@ on: jobs: check-commit: runs-on: ubuntu-latest + outputs: + run_tests: ${{ steps.check_message.outputs.run_tests }} steps: - name: Checkout repository uses: actions/checkout@v4 @@ -19,7 +21,7 @@ jobs: exit 1 tests: needs: check-commit - if: steps.check_message.outputs.run_tests == 'true' + if: needs.check-commit.outputs.run_tests == 'true' strategy: fail-fast: false matrix: From 0a465ad47accef51a4767eb3302182d1fcf1c2ed Mon Sep 17 00:00:00 2001 From: hayk Date: Wed, 16 Oct 2024 04:38:12 -0400 Subject: [PATCH 124/773] RUNTEST --- .github/workflows/actions.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/actions.yml b/.github/workflows/actions.yml index 3af457b6e..22f55d8be 100644 --- a/.github/workflows/actions.yml +++ b/.github/workflows/actions.yml @@ -19,6 +19,7 @@ jobs: else echo "::set-output name=run_tests::false" exit 1 + fi tests: needs: check-commit if: needs.check-commit.outputs.run_tests == 'true' From a52d07d3aad40f53500eb052836d5016141fc8d1 Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Wed, 16 Oct 2024 08:53:39 -0400 Subject: [PATCH 125/773] Bugfix in moment calculation. --- src/kernels/particle_moments.hpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/kernels/particle_moments.hpp b/src/kernels/particle_moments.hpp index 83caea563..904dc3b08 100644 --- a/src/kernels/particle_moments.hpp +++ b/src/kernels/particle_moments.hpp @@ -261,10 +261,7 @@ namespace kernel { } // compute the corresponding moment coeff = u_Phys[c1 - 1] / gamma; - } else { - // for other cases, use the `contrib` defined above - coeff = contrib; - } + } if constexpr (F != FldsID::Nppc) { // for nppc calculation ... From 0caddf9f24103cc5bd1539527921d684261cc06e Mon Sep 17 00:00:00 2001 From: hayk Date: Thu, 17 Oct 2024 07:42:12 -0400 Subject: [PATCH 126/773] WIP proper mpi test for checkpoints --- cmake/tests.cmake | 2 +- src/checkpoint/tests/checkpoint-mpi.cpp | 223 ++++++++++++++++++++++++ src/framework/CMakeLists.txt | 1 - src/framework/domain/metadomain.h | 2 +- src/output/tests/writer-mpi.cpp | 7 +- 5 files changed, 229 insertions(+), 6 deletions(-) create mode 100644 src/checkpoint/tests/checkpoint-mpi.cpp diff --git a/cmake/tests.cmake b/cmake/tests.cmake index f1342f679..643ac3d29 100644 --- a/cmake/tests.cmake +++ b/cmake/tests.cmake @@ -17,7 +17,7 @@ if (${mpi}) # tests with mpi if (${output}) add_subdirectory(${SRC_DIR}/output/tests ${CMAKE_CURRENT_BINARY_DIR}/output/tests) - add_subdirectory(${SRC_DIR}/framework/tests ${CMAKE_CURRENT_BINARY_DIR}/checkpoint/tests) + add_subdirectory(${SRC_DIR}/checkpoint/tests ${CMAKE_CURRENT_BINARY_DIR}/checkpoint/tests) add_subdirectory(${SRC_DIR}/framework/tests ${CMAKE_CURRENT_BINARY_DIR}/framework/tests) endif() else() diff --git a/src/checkpoint/tests/checkpoint-mpi.cpp b/src/checkpoint/tests/checkpoint-mpi.cpp new file mode 100644 index 000000000..3ce4bab14 --- /dev/null +++ b/src/checkpoint/tests/checkpoint-mpi.cpp @@ -0,0 +1,223 @@ +#include "enums.h" +#include "global.h" + +#include "utils/comparators.h" + +#include "checkpoint/reader.h" +#include "checkpoint/writer.h" + +#include +#include +#include +#include + +#include +#include +#include + +using namespace ntt; +using namespace checkpoint; + +void cleanup() { + namespace fs = std::filesystem; + fs::path temp_path { "checkpoints" }; + fs::remove_all(temp_path); +} + +auto main(int argc, char* argv[]) -> int { + Kokkos::initialize(argc, argv); + MPI_Init(&argc, &argv); + int rank, size; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Comm_size(MPI_COMM_WORLD, &size); + + try { + // assuming 4 ranks + // |------|------| + // | 2 | 3 | + // |------|------| + // | | | + // | 0 | 1 | + // |------|------| + constexpr auto g_nx1 = 20; + constexpr auto g_nx2 = 15; + constexpr auto g_nx1_gh = g_nx1 + 4 * N_GHOSTS; + constexpr auto g_nx2_gh = g_nx2 + 4 * N_GHOSTS; + + constexpr auto l_nx1 = 10; + constexpr auto l_nx2 = (rank < 2) ? 10 : 5; + + constexpr auto l_nx1_gh = l_nx1 + 2 * N_GHOSTS; + constexpr auto l_nx2_gh = l_nx2 + 2 * N_GHOSTS; + + constexpr auto l_corner_x1 = (rank % 2) * l_nx1; + constexpr auto l_corner_x2 = (rank / 2) * l_nx2; + + constexpr auto i1min = N_GHOSTS; + constexpr auto i2min = N_GHOSTS; + constexpr auto i1max = l_nx1 + N_GHOSTS; + constexpr auto i2max = l_nx2 + N_GHOSTS; + + constexpr auto npart1 = (rank % 2 + rank) * 23 + 100; + constexpr auto npart2 = (rank % 2 + rank) * 37 + 100; + + // init data + ndfield_t field1 { "fld1", l_nx1_gh, l_nx2_gh }; + ndfield_t field2 { "fld2", l_nx1_gh, l_nx2_gh }; + + array_t i1 { "i_1", npart1 }; + array_t u1 { "u_1", npart1 }; + array_t i2 { "i_2", npart2 }; + array_t u2 { "u_2", npart2 }; + + { + // fill data + Kokkos::parallel_for( + "fillFlds", + CreateRangePolicy({ i1min, i2min }, { i1max, i2max }), + Lambda(index_t i1, index_t i2) { + field1(i1, i2, 0) = static_cast(i1 + i2); + field1(i1, i2, 1) = static_cast(i1 * i2); + field1(i1, i2, 2) = static_cast(i1 / i2); + field1(i1, i2, 3) = static_cast(i1 - i2); + field1(i1, i2, 4) = static_cast(i2 / i1); + field1(i1, i2, 5) = static_cast(i1); + field2(i1, i2, 0) = static_cast(-(i1 + i2)); + field2(i1, i2, 1) = static_cast(-(i1 * i2)); + field2(i1, i2, 2) = static_cast(-(i1 / i2)); + field2(i1, i2, 3) = static_cast(-(i1 - i2)); + field2(i1, i2, 4) = static_cast(-(i2 / i1)); + field2(i1, i2, 5) = static_cast(-i1); + }); + Kokkos::parallel_for( + "fillPrtl1", + npart1, + Lambda(index_t p) { + u1(p) = static_cast(p); + i1(p) = static_cast(p); + }); + Kokkos::parallel_for( + "fillPrtl2", + npart2, + Lambda(index_t p) { + u2(p) = -static_cast(p); + i2(p) = -static_cast(p); + }); + } + + adios2::ADIOS adios; + + { + // write checkpoint + Writer writer; + writer.init(&adios, 0, 0.0, 1); + + writer.defineFieldVariables(SimEngine::GRPIC, + { g_nx1_gh, g_nx2_gh }, + { l_corner_x1, l_corner_x2 }, + { l_nx1, l_nx2 }); + writer.defineParticleVariables(Coord::Sph, Dim::_2D, 2, { 0, 0 }); + + writer.beginSaving(0, 0.0); + + writer.saveField("em", field1); + writer.saveField("em0", field2); + + writer.savePerDomainVariable("s1_npart", 1, 0, npart1); + writer.savePerDomainVariable("s2_npart", 1, 0, npart2); + + writer.saveParticleQuantity("s1_i1", npart1, 0, npart1, i1); + writer.saveParticleQuantity("s1_ux1", npart1, 0, npart1, u1); + writer.saveParticleQuantity("s2_i1", npart2, 0, npart2, i2); + writer.saveParticleQuantity("s2_ux1", npart2, 0, npart2, u2); + + writer.endSaving(); + } + + { + // read checkpoint + ndfield_t field1_read { "fld1_read", nx1_gh, nx2_gh, nx3_gh }; + ndfield_t field2_read { "fld2_read", nx1_gh, nx2_gh, nx3_gh }; + + array_t i1_read { "i_1", npart1 }; + array_t u1_read { "u_1", npart1 }; + array_t i2_read { "i_2", npart2 }; + array_t u2_read { "u_2", npart2 }; + + adios2::IO io = adios.DeclareIO("checkpointRead"); + adios2::Engine reader = io.Open("checkpoints/step-00000000.bp", + adios2::Mode::Read); + reader.BeginStep(); + + auto fieldRange = adios2::Box({ 0, 0, 0, 0 }, + { nx1_gh, nx2_gh, nx3_gh, 6 }); + ReadFields(io, reader, "em", fieldRange, field1_read); + ReadFields(io, reader, "em0", fieldRange, field2_read); + + auto [nprtl1, noff1] = ReadParticleCount(io, reader, 0, 0, 1); + auto [nprtl2, noff2] = ReadParticleCount(io, reader, 1, 0, 1); + + ReadParticleData(io, reader, "ux1", 0, u1_read, nprtl1, noff1); + ReadParticleData(io, reader, "ux1", 1, u2_read, nprtl2, noff2); + ReadParticleData(io, reader, "i1", 0, i1_read, nprtl1, noff1); + ReadParticleData(io, reader, "i1", 1, i2_read, nprtl2, noff2); + + reader.EndStep(); + reader.Close(); + + // check the validity + Kokkos::parallel_for( + "checkFields", + CreateRangePolicy({ 0, 0, 0 }, { nx1_gh, nx2_gh, nx3_gh }), + Lambda(index_t i1, index_t i2, index_t i3) { + for (int i = 0; i < 6; ++i) { + if (not cmp::AlmostEqual(field1(i1, i2, i3, i), + field1_read(i1, i2, i3, i))) { + raise::KernelError(HERE, "Field1 read failed"); + } + if (not cmp::AlmostEqual(field2(i1, i2, i3, i), + field2_read(i1, i2, i3, i))) { + raise::KernelError(HERE, "Field2 read failed"); + } + } + }); + + raise::ErrorIf(npart1 != nprtl1, "Particle count 1 mismatch", HERE); + raise::ErrorIf(npart2 != nprtl2, "Particle count 2 mismatch", HERE); + raise::ErrorIf(noff1 != 0, "Particle offset 1 mismatch", HERE); + raise::ErrorIf(noff2 != 0, "Particle offset 2 mismatch", HERE); + + Kokkos::parallel_for( + "checkPrtl1", + npart1, + Lambda(index_t p) { + if (not cmp::AlmostEqual(u1(p), u1_read(p))) { + raise::KernelError(HERE, "u1 read failed"); + } + if (i1(p) != i1_read(p)) { + raise::KernelError(HERE, "i1 read failed"); + } + }); + Kokkos::parallel_for( + "checkPrtl2", + npart2, + Lambda(index_t p) { + if (not cmp::AlmostEqual(u2(p), u2_read(p))) { + raise::KernelError(HERE, "u2 read failed"); + } + if (i2(p) != i2_read(p)) { + raise::KernelError(HERE, "i2 read failed"); + } + }); + } + + } catch (std::exception& e) { + std::cerr << e.what() << std::endl; + cleanup(); + Kokkos::finalize(); + return 1; + } + cleanup(); + Kokkos::finalize(); + return 0; +} diff --git a/src/framework/CMakeLists.txt b/src/framework/CMakeLists.txt index 241780575..e01759d14 100644 --- a/src/framework/CMakeLists.txt +++ b/src/framework/CMakeLists.txt @@ -32,7 +32,6 @@ set(SOURCES ${SRC_DIR}/domain/grid.cpp ${SRC_DIR}/domain/metadomain.cpp ${SRC_DIR}/domain/communications.cpp - ${SRC_DIR}/domain/checkpoint.cpp ${SRC_DIR}/containers/particles.cpp ${SRC_DIR}/containers/fields.cpp ) diff --git a/src/framework/domain/metadomain.h b/src/framework/domain/metadomain.h index 027a2982d..7b3042b5b 100644 --- a/src/framework/domain/metadomain.h +++ b/src/framework/domain/metadomain.h @@ -21,7 +21,6 @@ #include "arch/kokkos_aliases.h" #include "utils/timer.h" -#include "checkpoint/writer.h" #include "framework/containers/species.h" #include "framework/domain/domain.h" #include "framework/domain/mesh.h" @@ -32,6 +31,7 @@ #endif // MPI_ENABLED #if defined(OUTPUT_ENABLED) + #include "checkpoint/writer.h" #include "output/writer.h" #include diff --git a/src/output/tests/writer-mpi.cpp b/src/output/tests/writer-mpi.cpp index 6b810fa22..074b9acf0 100644 --- a/src/output/tests/writer-mpi.cpp +++ b/src/output/tests/writer-mpi.cpp @@ -36,10 +36,11 @@ auto main(int argc, char* argv[]) -> int { adios2::ADIOS adios { MPI_COMM_WORLD }; auto writer = out::Writer(); - writer.init(&adios, "hdf5"); + writer.init(&adios, "hdf5", "test"); writer.defineMeshLayout({ static_cast(size) * 10 }, { static_cast(rank) * 10 }, { 10 }, + { 1 }, false, Coord::Cart); writer.defineFieldOutputs(SimEngine::SRPIC, { "E" }); @@ -59,11 +60,11 @@ auto main(int argc, char* argv[]) -> int { names.push_back(writer.fieldWriters()[0].name(i)); addresses.push_back(i); } - writer.beginWriting("test", 0, 0.0); + writer.beginWriting(0, 0.0); writer.writeField(names, field, addresses); writer.endWriting(); - writer.beginWriting("test", 1, 0.1); + writer.beginWriting(1, 0.1); writer.writeField(names, field, addresses); writer.endWriting(); From c51f80c92edf5d7a031e6d5846772d8d97077825 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Fri, 18 Oct 2024 17:15:06 -0400 Subject: [PATCH 127/773] minor kernels/aux_gr --- src/kernels/aux_fields_gr.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/kernels/aux_fields_gr.hpp b/src/kernels/aux_fields_gr.hpp index c739cffbd..0983b6b7e 100644 --- a/src/kernels/aux_fields_gr.hpp +++ b/src/kernels/aux_fields_gr.hpp @@ -277,8 +277,8 @@ namespace kernel::gr { static_assert(M::is_metric, "M must be a metric class"); static constexpr auto D = M::Dim; - const ndfield_t Jf; - ndfield_t Jf0; + ndfield_t Jf; + const ndfield_t Jf0; const M metric; public: From be2ec2bd64e5e3dae61635bca8369104018cf060 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Fri, 18 Oct 2024 17:16:06 -0400 Subject: [PATCH 128/773] monor style --- src/kernels/fields_bcs.hpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/kernels/fields_bcs.hpp b/src/kernels/fields_bcs.hpp index fd6ba542f..c980d1e77 100644 --- a/src/kernels/fields_bcs.hpp +++ b/src/kernels/fields_bcs.hpp @@ -561,13 +561,13 @@ template Inline void operator()(index_t i2) const { if constexpr (M::Dim == Dim::_2D) { if (setE) { - Fld(i1_min - 1, i2, em::ex1) = Fld(i1_min , i2, em::ex1); - Fld(i1_min - 1, i2, em::ex2) = Fld(i1_min , i2, em::ex2); - Fld(i1_min - 1, i2, em::ex3) = Fld(i1_min , i2, em::ex3); + Fld(i1_min - 1, i2, em::ex1) = Fld(i1_min, i2, em::ex1); + Fld(i1_min - 1, i2, em::ex2) = Fld(i1_min, i2, em::ex2); + Fld(i1_min - 1, i2, em::ex3) = Fld(i1_min, i2, em::ex3); } if (setB) { - Fld(i1_min - 1, i2, em::bx1) = Fld(i1_min , i2, em::bx1); - Fld(i1_min - 1, i2, em::bx2) = Fld(i1_min , i2, em::bx2); - Fld(i1_min - 1, i2, em::bx3) = Fld(i1_min , i2, em::bx3); + Fld(i1_min - 1, i2, em::bx1) = Fld(i1_min, i2, em::bx1); + Fld(i1_min - 1, i2, em::bx2) = Fld(i1_min, i2, em::bx2); + Fld(i1_min - 1, i2, em::bx3) = Fld(i1_min, i2, em::bx3); } } else { raise::KernelError( From 50dfdb35a913eff798ce1b9c26ef05813fb1f41a Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Fri, 18 Oct 2024 17:17:40 -0400 Subject: [PATCH 129/773] engines/grpic: parameters for field boundaries --- src/engines/grpic.hpp | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index 40e743766..0c21c0728 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -123,7 +123,7 @@ namespace ntt { * em0::D, em::D, em0::B, em::B <- boundary conditions */ m_metadomain.CommunicateFields(dom, Comm::B | Comm::B0 | Comm::D | Comm::D0); - FieldBoundaries(dom, BC::B | BC::D, gr_bc::main); + FieldBoundaries(dom, BC::B | BC::E, gr_bc::main); /** * em0::B <- em::B @@ -145,7 +145,7 @@ namespace ntt { /** * aux::E, aux::H <- boundary conditions */ - FieldBoundaries(dom, BC::B | BC::D, gr_bc::aux); + FieldBoundaries(dom, BC::B | BC::E, gr_bc::aux); /** * em0::B <- (em0::B) <- -curl aux::E @@ -171,7 +171,7 @@ namespace ntt { * em0::D, em::D <- boundary conditions */ m_metadomain.CommunicateFields(dom, Comm::D | Comm::D0); - FieldBoundaries(dom, BC::D, gr_bc::main); + FieldBoundaries(dom, BC::E, gr_bc::main); /** * aux::E <- alpha * em::D + beta x em0::B @@ -185,7 +185,7 @@ namespace ntt { /** * aux::E, aux::H <- boundary conditions */ - FieldBoundaries(dom, BC::B | BC::D, gr_bc::aux); + FieldBoundaries(dom, BC::B | BC::E, gr_bc::aux); // !ADD: GR -- particles? @@ -211,7 +211,7 @@ namespace ntt { * em0::D, em::D <- boundary conditions */ m_metadomain.CommunicateFields(dom, Comm::D | Comm::D0); - FieldBoundaries(dom, BC::D, gr_bc::main); + FieldBoundaries(dom, BC::E, gr_bc::main); /** * aux::H <- alpha * em0::B - beta x em0::D @@ -235,7 +235,7 @@ namespace ntt { * em0::D, em::D <- boundary conditions */ m_metadomain.CommunicateFields(dom, Comm::D | Comm::D0); - FieldBoundaries(dom, BC::D, gr_bc::main); + FieldBoundaries(dom, BC::E, gr_bc::main); /** * em::D <-> em0::D @@ -298,7 +298,7 @@ namespace ntt { /** * aux::E <- boundary conditions */ - FieldBoundaries(dom, BC::D, gr_bc::aux); + FieldBoundaries(dom, BC::E, gr_bc::aux); timers.stop("FieldBoundaries"); timers.start("FieldSolver"); @@ -399,7 +399,7 @@ namespace ntt { /** * aux::Е <- boundary conditions */ - FieldBoundaries(dom, BC::D, gr_bc::aux); + FieldBoundaries(dom, BC::E, gr_bc::aux); timers.stop("FieldBoundaries"); timers.start("FieldSolver"); @@ -449,7 +449,7 @@ namespace ntt { m_metadomain.CommunicateFields(dom, Comm::D | Comm::D0); timers.stop("Communications"); timers.start("FieldBoundaries"); - FieldBoundaries(dom, BC::D, gr_bc::main); + FieldBoundaries(dom, BC::E, gr_bc::main); timers.stop("FieldBoundaries"); timers.start("FieldSolver"); @@ -504,7 +504,7 @@ namespace ntt { m_metadomain.CommunicateFields(dom, Comm::D | Comm::D0); timers.stop("Communications"); timers.start("FieldBoundaries"); - FieldBoundaries(dom, BC::D, gr_bc::main); + FieldBoundaries(dom, BC::E, gr_bc::main); timers.stop("FieldBoundaries"); } /** @@ -833,7 +833,7 @@ namespace ntt { // First push, updates D0 with J. Kokkos::parallel_for("Ampere-1", range, - kernel::gr::Ampere_kernel(domain.fields.em0, + kernel::gr::Ampere_kernel(domain.fields.em0, // Din, Dout, aux domain.fields.em0, domain.fields.aux, domain.mesh.metric, From 418d035ae83cdea732a4e8206c0fe510bb2a96db Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Mon, 21 Oct 2024 19:05:10 -0400 Subject: [PATCH 130/773] minor notes --- src/engines/grpic.hpp | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index 0c21c0728..b2ca0671e 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -730,9 +730,9 @@ namespace ntt { if (g == gr_getE::D0_B) { Kokkos::parallel_for("ComputeAuxE", range, - kernel::gr::ComputeAuxE_kernel(domain.fields.em0, - domain.fields.em, - domain.fields.aux, + kernel::gr::ComputeAuxE_kernel(domain.fields.em0, // D + domain.fields.em, // B + domain.fields.aux, // E domain.mesh.metric)); } else if (g == gr_getE::D_B0) { Kokkos::parallel_for("ComputeAuxE", @@ -751,9 +751,9 @@ namespace ntt { if (g == gr_getH::D_B0) { Kokkos::parallel_for("ComputeAuxH", range, - kernel::gr::ComputeAuxH_kernel(domain.fields.em, - domain.fields.em0, - domain.fields.aux, + kernel::gr::ComputeAuxH_kernel(domain.fields.em, // D + domain.fields.em0, // B + domain.fields.aux, // H domain.mesh.metric)); } else if (g == gr_getH::D0_B0) { Kokkos::parallel_for("ComputeAuxH", @@ -794,9 +794,9 @@ namespace ntt { Kokkos::parallel_for( "Faraday", domain.mesh.rangeActiveCells(), - kernel::gr::Faraday_kernel(domain.fields.em0, - domain.fields.em0, - domain.fields.aux, + kernel::gr::Faraday_kernel(domain.fields.em0, // Bin + domain.fields.em0, // Bout + domain.fields.aux, // E domain.mesh.metric, dT, domain.mesh.n_active(in::x2), @@ -825,16 +825,16 @@ namespace ntt { "algorithms.timestep.correction") * dt; auto range = CreateRangePolicy( - { domain.mesh.i_min(in::x1), domain.mesh.i_min(in::x2) + 1}, - { domain.mesh.i_max(in::x1), domain.mesh.i_max(in::x2)}); + { domain.mesh.i_min(in::x1), domain.mesh.i_min(in::x2)}, + { domain.mesh.i_max(in::x1), domain.mesh.i_max(in::x2) + 1}); const auto ni2 = domain.mesh.n_active(in::x2); if (g == gr_ampere::aux) { // First push, updates D0 with J. Kokkos::parallel_for("Ampere-1", range, - kernel::gr::Ampere_kernel(domain.fields.em0, // Din, Dout, aux - domain.fields.em0, + kernel::gr::Ampere_kernel(domain.fields.em0, // Din + domain.fields.em0, // Dout domain.fields.aux, domain.mesh.metric, dT, From 0cf9baf37667726f8d2e1a1711d5a7c2ae4980c3 Mon Sep 17 00:00:00 2001 From: Sasha Chernoglazov Date: Wed, 23 Oct 2024 14:18:31 -0400 Subject: [PATCH 131/773] bookkeeping for downsampling --- src/framework/domain/output.cpp | 21 +++++++++++++++++---- src/output/writer.cpp | 27 ++++++++++++++++++++------- 2 files changed, 37 insertions(+), 11 deletions(-) diff --git a/src/framework/domain/output.cpp b/src/framework/domain/output.cpp index 46ca95ede..4a8871324 100644 --- a/src/framework/domain/output.cpp +++ b/src/framework/domain/output.cpp @@ -224,10 +224,16 @@ namespace ntt { for (unsigned short dim = 0; dim < M::Dim; ++dim) { const auto l_size = local_domain->mesh.n_active()[dim]; const auto l_offset = local_domain->offset_ncells()[dim]; + //std::cout << "offset " << l_offset << " " << dim << std::endl; const auto g_size = mesh().n_active()[dim]; const auto dwn_in_dim = dwn[dim]; - const auto l_size_dwn = static_cast(l_size / dwn_in_dim); + double n {l_size}; + double d {dwn_in_dim}; + double l {l_offset}; + double f = math::ceil(l/d)*d-l; + const auto first_cell = static_cast(f); + const auto l_size_dwn = static_cast(math::ceil((n-f) / d)); const auto is_last = l_offset + l_size == g_size; @@ -239,9 +245,12 @@ namespace ntt { const auto offset = (incl_ghosts ? N_GHOSTS : 0); const auto ncells = l_size_dwn; - const auto first_cell = static_cast(l_offset / dwn_in_dim) * - dwn_in_dim - - l_offset; + //const auto first_cell = ((static_cast(l_offset / dwn_in_dim) + 1) * dwn_in_dim - l_offset) % dwn_in_dim; + //const auto first_cell = static_cast(l_offset / dwn_in_dim) * + // dwn_in_dim - + // l_offset; + std::cout << "first cell " << first_cell << " dim " << dim << " l_offset " << l_offset << " dwn_in_dim " << dwn_in_dim << std::endl; + const auto& metric = local_domain->mesh.metric; @@ -251,8 +260,12 @@ namespace ntt { Lambda(index_t i_dwn) { const auto i = first_cell + i_dwn * dwn_in_dim; const auto i_ = static_cast(i); + //if (dim == 1){ + // printf(" i %lu and %f \n", i, i_ ); + // } coord_t x_Cd { ZERO }, x_Ph { ZERO }; x_Cd[dim] = i_ + HALF; + // TODO : change to convert by component metric.template convert(x_Cd, x_Ph); xc(offset + i_dwn) = x_Ph[dim]; x_Cd[dim] = i_; diff --git a/src/output/writer.cpp b/src/output/writer.cpp index 5c6dfe6d6..a63fafa51 100644 --- a/src/output/writer.cpp +++ b/src/output/writer.cpp @@ -77,17 +77,26 @@ namespace out { raise::ErrorIf(dwn[i] != 1 && incl_ghosts, "Downsampling with ghosts not supported", HERE); + + double g = glob_shape[i]; + double d = m_dwn[i]; + double l = loc_corner[i]; + double n = loc_shape[i]; + double f = math::ceil(l/d)*d-l; m_flds_g_shape_dwn.push_back( - static_cast(glob_shape[i] / m_dwn[i])); + static_cast(math::ceil(g / d))); m_flds_l_corner_dwn.push_back( - static_cast(loc_corner[i] / m_dwn[i])); - m_flds_l_shape_dwn.push_back( - static_cast((loc_corner[i] + loc_shape[i]) / m_dwn[i]) - - static_cast(loc_corner[i] / m_dwn[i])); + static_cast(math::ceil(l /d))); m_flds_l_first.push_back( - static_cast(loc_corner[i] / m_dwn[i]) * m_dwn[i] - - loc_corner[i]); + static_cast(f)); + + m_flds_l_shape_dwn.push_back( + static_cast(math::ceil((n - f) / d))); + //m_flds_l_first.push_back( + // static_cast(loc_corner[i] / m_dwn[i]) * m_dwn[i] - + // loc_corner[i]); } + m_io.DefineAttribute("NGhosts", incl_ghosts ? N_GHOSTS : 0); m_io.DefineAttribute("Dimension", m_flds_g_shape.size()); @@ -119,6 +128,9 @@ namespace out { Kokkos::LayoutRight>::value) { m_io.DefineAttribute("LayoutRight", 1); } else { + std::reverse(m_flds_g_shape_dwn.begin(), m_flds_g_shape_dwn.end()); + std::reverse(m_flds_l_corner_dwn.begin(), m_flds_l_corner_dwn.end()); + std::reverse(m_flds_l_shape_dwn.begin(), m_flds_l_shape_dwn.end()); m_io.DefineAttribute("LayoutRight", 0); } } @@ -247,6 +259,7 @@ namespace out { (field.extent(1) - 2 * N_GHOSTS) / dwn2); const auto first_cell1 = first_cell[0]; const auto first_cell2 = first_cell[1]; + printf("%ld %ld : %ld %ld \n", nx1_dwn, nx2_dwn, first_cell1, first_cell2); output_field = array_t { "output_field", nx1_dwn, nx2_dwn }; Kokkos::parallel_for( "outputField", From 117426ac52f7a7f55faa20ec05b2c5995192b58e Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Wed, 23 Oct 2024 17:27:09 -0400 Subject: [PATCH 132/773] implemented absorbing boundaries for gr --- src/engines/grpic.hpp | 25 ++++------ src/kernels/fields_bcs.hpp | 94 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 103 insertions(+), 16 deletions(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index b2ca0671e..3f90220ec 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -562,25 +562,16 @@ namespace ntt { const auto dim = direction.get_dim(); real_t xg_min, xg_max, xg_edge; auto sign = direction.get_sign(); - if (sign > 0) { // + direction - xg_max = m_metadomain.mesh().extent(dim).second; - xg_min = xg_max - ds; - xg_edge = xg_max; - } else { // - direction - xg_min = m_metadomain.mesh().extent(dim).first; - xg_max = xg_min + ds; - xg_edge = xg_min; - } + xg_max = m_metadomain.mesh().extent(dim).second; + xg_min = xg_max - ds; + xg_edge = xg_max; + boundaries_t box; boundaries_t incl_ghosts; for (unsigned short d { 0 }; d < M::Dim; ++d) { if (d == static_cast(dim)) { box.push_back({ xg_min, xg_max }); - if (sign > 0) { - incl_ghosts.push_back({ false, true }); - } else { - incl_ghosts.push_back({ true, false }); - } + incl_ghosts.push_back({ false, true }); } else { box.push_back(Range::All); incl_ghosts.push_back({ true, true }); @@ -601,7 +592,8 @@ namespace ntt { Kokkos::parallel_for( "AbsorbFields", CreateRangePolicy(range_min, range_max), - kernel::AbsorbBoundaries_kernel(domain.fields.em, + kernel::AbsorbBoundariesGR_kernel(domain.fields.em, + m_pgen.init_flds, domain.mesh.metric, xg_edge, ds, @@ -609,7 +601,8 @@ namespace ntt { Kokkos::parallel_for( "AbsorbFields", CreateRangePolicy(range_min, range_max), - kernel::AbsorbBoundaries_kernel(domain.fields.em0, + kernel::AbsorbBoundariesGR_kernel(domain.fields.em0, + m_pgen.init_flds, domain.mesh.metric, xg_edge, ds, diff --git a/src/kernels/fields_bcs.hpp b/src/kernels/fields_bcs.hpp index c980d1e77..e69fbcc13 100644 --- a/src/kernels/fields_bcs.hpp +++ b/src/kernels/fields_bcs.hpp @@ -577,6 +577,100 @@ template } }; + template + struct AbsorbBoundariesGR_kernel { + static_assert(M::is_metric, "M must be a metric class"); + static_assert(i <= static_cast(M::Dim), + "Invalid component index"); + + ndfield_t Fld; + const I finit; + const M metric; + const real_t xg_edge; + const real_t dx_abs; + const BCTags tags; + + AbsorbBoundariesGR_kernel(ndfield_t Fld, + const I& finit, + const M& metric, + real_t xg_edge, + real_t dx_abs, + BCTags tags) + : Fld { Fld } + , finit { finit } + , metric { metric } + , xg_edge { xg_edge } + , dx_abs { dx_abs } + , tags { tags } {} + + Inline void operator()(index_t i1, index_t i2) const { + if constexpr (M::Dim == Dim::_2D) { + const auto i1_ = COORD(i1); + const auto i2_ = COORD(i2); + for (const auto comp : + { em::ex1, em::ex2, em::ex3, em::bx1, em::bx2, em::bx3 }) { + if ((comp == em::ex1) and not(tags & BC::Ex1)) { + continue; + } else if ((comp == em::ex2) and not(tags & BC::Ex2)) { + continue; + } else if ((comp == em::ex3) and not(tags & BC::Ex3)) { + continue; + } else if ((comp == em::bx1) and not(tags & BC::Bx1)) { + continue; + } else if ((comp == em::bx2) and not(tags & BC::Bx2)) { + continue; + } else if ((comp == em::bx3) and not(tags & BC::Bx3)) { + continue; + } + coord_t x_Cd { ZERO }; + if (comp == em::ex1 or comp == em::bx2 or comp == em::bx3) { + x_Cd[0] = i1_ + HALF; + x_Cd[1] = i2_; + } else if (comp == em::ex2 or comp == em::ex3 or comp == em::bx1) { + x_Cd[0] = i1_; + x_Cd[1] = i2_; + } + + const auto dx = math::abs( + metric.template convert(x_Cd[i - 1]) - xg_edge); + Fld(i1, i2, comp) *= math::tanh(dx / (INV_4 * dx_abs)); + + if (comp == em::bx1) { + const real_t x1_0 { metric.template convert<1, Crd::Cd, Crd::Ph>(i1_) }; + const real_t x2_H { metric.template convert<2, Crd::Cd, Crd::Ph>( + i2_ + HALF) }; + + vec_t b_PU { finit.bx1({ x1_0, x2_H }), + finit.bx2({ x1_0, x2_H }), + finit.bx3({ x1_0, x2_H }) }; + vec_t b_U { ZERO }; + metric.template transform({ i1_, i2_ + HALF }, + b_PU, + b_U); + Fld(i1, i2, comp) += (ONE - math::tanh(dx / (INV_4 * dx_abs))) * b_U[0]; + } else if (comp == em::bx2) { + const real_t x1_H { metric.template convert<1, Crd::Cd, Crd::Ph>( + i1_ + HALF) }; + const real_t x2_0 { metric.template convert<2, Crd::Cd, Crd::Ph>(i2_) }; + + vec_t b_PU { finit.bx1({ x1_H, x2_0 }), + finit.bx2({ x1_H, x2_0 }), + finit.bx3({ x1_H, x2_0 }) }; + vec_t b_U { ZERO }; + metric.template transform({ i1_ + HALF, i2_ }, + b_PU, + b_U); + Fld(i1, i2, comp) += (ONE - math::tanh(dx / (INV_4 * dx_abs))) * b_U[1]; + } + } + } else { + raise::KernelError( + HERE, + "AbsorbFields_kernel: 2D implementation called for D != 2"); + } + } + }; + } // namespace kernel #endif // KERNELS_FIELDS_BCS_HPP From a0b1ff244c0448e8434c5931847ff3b76d54e0de Mon Sep 17 00:00:00 2001 From: Sasha Chernoglazov Date: Wed, 23 Oct 2024 22:05:07 -0400 Subject: [PATCH 133/773] correct downsampling of field output --- src/framework/domain/output.cpp | 16 ++------ src/output/writer.cpp | 68 +++++++++++++++++---------------- 2 files changed, 39 insertions(+), 45 deletions(-) diff --git a/src/framework/domain/output.cpp b/src/framework/domain/output.cpp index 4a8871324..ac2108a75 100644 --- a/src/framework/domain/output.cpp +++ b/src/framework/domain/output.cpp @@ -224,13 +224,12 @@ namespace ntt { for (unsigned short dim = 0; dim < M::Dim; ++dim) { const auto l_size = local_domain->mesh.n_active()[dim]; const auto l_offset = local_domain->offset_ncells()[dim]; - //std::cout << "offset " << l_offset << " " << dim << std::endl; const auto g_size = mesh().n_active()[dim]; const auto dwn_in_dim = dwn[dim]; - double n {l_size}; - double d {dwn_in_dim}; - double l {l_offset}; + double n = l_size; + double d = dwn_in_dim; + double l = l_offset; double f = math::ceil(l/d)*d-l; const auto first_cell = static_cast(f); const auto l_size_dwn = static_cast(math::ceil((n-f) / d)); @@ -245,13 +244,7 @@ namespace ntt { const auto offset = (incl_ghosts ? N_GHOSTS : 0); const auto ncells = l_size_dwn; - //const auto first_cell = ((static_cast(l_offset / dwn_in_dim) + 1) * dwn_in_dim - l_offset) % dwn_in_dim; - //const auto first_cell = static_cast(l_offset / dwn_in_dim) * - // dwn_in_dim - - // l_offset; - std::cout << "first cell " << first_cell << " dim " << dim << " l_offset " << l_offset << " dwn_in_dim " << dwn_in_dim << std::endl; - const auto& metric = local_domain->mesh.metric; Kokkos::parallel_for( @@ -260,9 +253,6 @@ namespace ntt { Lambda(index_t i_dwn) { const auto i = first_cell + i_dwn * dwn_in_dim; const auto i_ = static_cast(i); - //if (dim == 1){ - // printf(" i %lu and %f \n", i, i_ ); - // } coord_t x_Cd { ZERO }, x_Ph { ZERO }; x_Cd[dim] = i_ + HALF; // TODO : change to convert by component diff --git a/src/output/writer.cpp b/src/output/writer.cpp index a63fafa51..b35e3ab17 100644 --- a/src/output/writer.cpp +++ b/src/output/writer.cpp @@ -83,18 +83,10 @@ namespace out { double l = loc_corner[i]; double n = loc_shape[i]; double f = math::ceil(l/d)*d-l; - m_flds_g_shape_dwn.push_back( - static_cast(math::ceil(g / d))); - m_flds_l_corner_dwn.push_back( - static_cast(math::ceil(l /d))); - m_flds_l_first.push_back( - static_cast(f)); - - m_flds_l_shape_dwn.push_back( - static_cast(math::ceil((n - f) / d))); - //m_flds_l_first.push_back( - // static_cast(loc_corner[i] / m_dwn[i]) * m_dwn[i] - - // loc_corner[i]); + m_flds_g_shape_dwn.push_back(static_cast(math::ceil(g / d))); + m_flds_l_corner_dwn.push_back(static_cast(math::ceil(l /d))); + m_flds_l_first.push_back(static_cast(f)); + m_flds_l_shape_dwn.push_back(static_cast(math::ceil((n - f) / d))); } @@ -229,10 +221,14 @@ namespace out { output_field = array_t { "output_field", slice.extent(0) }; Kokkos::deep_copy(output_field, slice); } else { - const auto dwn1 = dwn[0]; - const auto nx1_dwn = static_cast( - (field.extent(0) - 2 * N_GHOSTS) / dwn1); + + const auto dwn1 = dwn[0]; + const double first_cell1_d = first_cell[0]; + const double nx1_full = field.extent(0) - 2 * N_GHOSTS; const auto first_cell1 = first_cell[0]; + + const auto nx1_dwn = static_cast(math::ceil((nx1_full - first_cell1_d) / dwn1)); + output_field = array_t { "output_field", nx1_dwn }; Kokkos::parallel_for( "outputField", @@ -251,15 +247,17 @@ namespace out { slice.extent(1) }; Kokkos::deep_copy(output_field, slice); } else { - const auto dwn1 = dwn[0]; - const auto dwn2 = dwn[1]; - const auto nx1_dwn = static_cast( - (field.extent(0) - 2 * N_GHOSTS) / dwn1); - const auto nx2_dwn = static_cast( - (field.extent(1) - 2 * N_GHOSTS) / dwn2); + const auto dwn1 = dwn[0]; + const auto dwn2 = dwn[1]; + const double first_cell1_d = first_cell[0]; + const double first_cell2_d = first_cell[1]; + const double nx1_full = field.extent(0) - 2 * N_GHOSTS; + const double nx2_full = field.extent(1) - 2 * N_GHOSTS; const auto first_cell1 = first_cell[0]; const auto first_cell2 = first_cell[1]; - printf("%ld %ld : %ld %ld \n", nx1_dwn, nx2_dwn, first_cell1, first_cell2); + + const auto nx1_dwn = static_cast(math::ceil((nx1_full - first_cell1_d) / dwn1)); + const auto nx2_dwn = static_cast(math::ceil((nx2_full - first_cell2_d) / dwn2)); output_field = array_t { "output_field", nx1_dwn, nx2_dwn }; Kokkos::parallel_for( "outputField", @@ -282,18 +280,24 @@ namespace out { slice.extent(2) }; Kokkos::deep_copy(output_field, slice); } else { - const auto dwn1 = dwn[0]; - const auto dwn2 = dwn[1]; - const auto dwn3 = dwn[2]; - const auto nx1_dwn = static_cast( - (field.extent(0) - 2 * N_GHOSTS) / dwn1); - const auto nx2_dwn = static_cast( - (field.extent(1) - 2 * N_GHOSTS) / dwn2); - const auto nx3_dwn = static_cast( - (field.extent(2) - 2 * N_GHOSTS) / dwn3); + const auto dwn1 = dwn[0]; + const auto dwn2 = dwn[1]; + const auto dwn3 = dwn[2]; + const double first_cell1_d = first_cell[0]; + const double first_cell2_d = first_cell[1]; + const double first_cell3_d = first_cell[2]; + const double nx1_full = field.extent(0) - 2 * N_GHOSTS; + const double nx2_full = field.extent(1) - 2 * N_GHOSTS; + const double nx3_full = field.extent(2) - 2 * N_GHOSTS; const auto first_cell1 = first_cell[0]; const auto first_cell2 = first_cell[1]; - const auto first_cell3 = first_cell[2]; + const auto first_cell3 = first_cell[2]; + + const auto nx1_dwn = static_cast(math::ceil((nx1_full - first_cell1_d) / dwn1)); + const auto nx2_dwn = static_cast(math::ceil((nx2_full - first_cell2_d) / dwn2)); + const auto nx3_dwn = static_cast(math::ceil((nx3_full - first_cell3_d) / dwn3)); + + output_field = array_t { "output_field", nx1_dwn, nx2_dwn, nx3_dwn }; Kokkos::parallel_for( "outputField", From 4abd1071ae7d33b3021860d1b050928bf8bda1c6 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Thu, 31 Oct 2024 15:49:40 -0400 Subject: [PATCH 134/773] working EM solver fully implemented --- setups/grpic/wald/pgen.hpp | 41 +++++++++++++++++++-- setups/grpic/wald/wald.toml | 72 +++++++++++++++++++++++++++++++++++++ 2 files changed, 110 insertions(+), 3 deletions(-) create mode 100644 setups/grpic/wald/wald.toml diff --git a/setups/grpic/wald/pgen.hpp b/setups/grpic/wald/pgen.hpp index a5f8f503e..51636314b 100644 --- a/setups/grpic/wald/pgen.hpp +++ b/setups/grpic/wald/pgen.hpp @@ -17,12 +17,30 @@ namespace user { struct InitFields { InitFields(M metric_) : metric { metric_ } {} - Inline auto VerticalPotential(const coord_t& x_Cd) const -> real_t { + Inline auto A_3(const coord_t& x_Cd) const -> real_t { + // return HALF * (metric.template h_<3, 3>(x_Cd) ); + // + TWO * metric.spin() * metric.template h_<1, 3>(x_Cd) * metric.beta1(x_Cd) + // ); + coord_t x_Ph { ZERO }; metric.template convert(x_Cd, x_Ph); return HALF * SQR(x_Ph[0]) * SQR(math::sin(x_Ph[1])); } + Inline auto A_1(const coord_t& x_Cd) const -> real_t { + return HALF * (metric.template h_<1, 3>(x_Cd) + + TWO * metric.spin() * metric.template h_<1, 1>(x_Cd) * metric.beta1(x_Cd) + ); + } + + Inline auto A_0(const coord_t& x_Cd) const -> real_t { + real_t g_00 { -metric.alpha(x_Cd) * metric.alpha(x_Cd) + + metric.template h_<1, 1>(x_Cd) * metric.beta1(x_Cd) * metric.beta1(x_Cd) + }; + return HALF * (metric.template h_<1, 3>(x_Cd) * metric.beta1(x_Cd) + + TWO * metric.spin() * g_00); + } + Inline auto bx1(const coord_t& x_Ph) const -> real_t { coord_t xi {ZERO}, x0m { ZERO }, x0p { ZERO }; metric.template convert(x_Ph, xi); @@ -33,7 +51,11 @@ namespace user { x0p[1] = xi[1] + HALF; real_t inv_sqrt_detH_ijP { ONE / metric.sqrt_det_h({ xi[0], xi[1] }) }; - return (VerticalPotential(x0p) - VerticalPotential(x0m)) * inv_sqrt_detH_ijP; + + if (cmp::AlmostZero(x_Ph[1])) + return ONE; + else + return (A_3(x0p) - A_3(x0m)) * inv_sqrt_detH_ijP; } Inline auto bx2(const coord_t& x_Ph) const -> real_t { @@ -46,10 +68,23 @@ namespace user { x0p[1] = xi[1]; real_t inv_sqrt_detH_ijP { ONE / metric.sqrt_det_h({ xi[0], xi[1] }) }; - return -(VerticalPotential(x0p) - VerticalPotential(x0m)) * inv_sqrt_detH_ijP; + if (cmp::AlmostZero(x_Ph[1])) + return ZERO; + else + return -(A_3(x0p) - A_3(x0m)) * inv_sqrt_detH_ijP; } Inline auto bx3(const coord_t& x_Ph) const -> real_t { + // coord_t xi {ZERO}, x0m { ZERO }, x0p { ZERO }; + // metric.template convert(x_Ph, xi); + + // x0m[0] = xi[0] + HALF - HALF; + // x0m[1] = xi[1]; + // x0p[0] = xi[0] + HALF + HALF; + // x0p[1] = xi[1]; + + // real_t inv_sqrt_detH_ijP { ONE / metric.sqrt_det_h({ xi[0], xi[1] }) }; + // return -(A_1(x0p) - A_1(x0m)) * inv_sqrt_detH_ijP; return ZERO; } diff --git a/setups/grpic/wald/wald.toml b/setups/grpic/wald/wald.toml new file mode 100644 index 000000000..36c746ae5 --- /dev/null +++ b/setups/grpic/wald/wald.toml @@ -0,0 +1,72 @@ +[simulation] + name = "wald" + engine = "grpic" + runtime = 500.0 + +[grid] + resolution = [128,128] + extent = [[1.2, 8.0]] + + [grid.metric] + metric = "qkerr_schild" + qsph_r0 = 0.0 + qsph_h = 0.0 + ks_a = 0.95 + + [grid.boundaries] + fields = [["ABSORB"]] + particles = [["ABSORB"]] + + [grid.boundaries.absorb] + ds = 0.5 + +[scales] + larmor0 = 1.0 + skindepth0 = 1.0 + +[algorithms] + current_filters = 4 + + [algorithms.timestep] + CFL = 0.5 + + [algorithms.toggles] + deposit = false + fieldsolver = true + +[particles] + ppc0 = 8.0 + use_weights = true + sort_interval = 100 + +# [[particles.species]] +# label = "e-" +# mass = 1.0 +# charge = -1.0 +# maxnpart = 2e6 +# pusher = "Boris" +# +# [[particles.species]] +# label = "e+" +# mass = 1.0 +# charge = 1.0 +# maxnpart = 2e6 +# pusher = "Boris" + +[setup] + +[output] + format = "hdf5" + + [output.fields] + interval_time = 1.0 + quantities = ["D", "H", "B", "J", "A"] + + [output.particles] + enable = false + + [output.spectra] + enable = false + +[diagnostics] + interval = 1 From 905fb98167d5ffe304ad8d65372ea84deb82a1b3 Mon Sep 17 00:00:00 2001 From: hayk Date: Mon, 4 Nov 2024 13:24:33 -0500 Subject: [PATCH 135/773] MPI write test --- .gitignore | 1 + src/checkpoint/reader.cpp | 2 +- src/engines/engine_init.cpp | 6 + src/framework/domain/output.cpp | 18 +-- src/output/tests/writer-mpi.cpp | 176 ++++++++++++++++++++++++------ src/output/tests/writer-nompi.cpp | 18 +-- src/output/writer.cpp | 93 ++++++++-------- 7 files changed, 218 insertions(+), 96 deletions(-) diff --git a/.gitignore b/.gitignore index 53d09b648..a1b05e751 100644 --- a/.gitignore +++ b/.gitignore @@ -51,6 +51,7 @@ venv/ # CMake testing files Testing/ +.clangd .schema.json *_old/ action-token diff --git a/src/checkpoint/reader.cpp b/src/checkpoint/reader.cpp index 66fcd6757..e89b7d384 100644 --- a/src/checkpoint/reader.cpp +++ b/src/checkpoint/reader.cpp @@ -35,7 +35,7 @@ namespace checkpoint { reader.Get(field_var, array_h.data(), adios2::Mode::Sync); Kokkos::deep_copy(array, array_h); } else { - raise::Error(fmt::format("Field variable: %s not found", field), HERE); + raise::Error(fmt::format("Field variable: %s not found", field.c_str()), HERE); } } diff --git a/src/engines/engine_init.cpp b/src/engines/engine_init.cpp index e4ce9fa5f..0239724e1 100644 --- a/src/engines/engine_init.cpp +++ b/src/engines/engine_init.cpp @@ -50,6 +50,7 @@ namespace ntt { }); } } else { +#if defined(OUTPUT_ENABLED) // read simulation data from the checkpoint raise::ErrorIf( m_params.template get("checkpoint.start_step") == 0, @@ -57,6 +58,11 @@ namespace ntt { HERE); logger::Checkpoint("Resuming simulation from a checkpoint", HERE); m_metadomain.ContinueFromCheckpoint(&m_adios, m_params); +#else + raise::Error( + "Resuming simulation from a checkpoint requires -D output=ON", + HERE); +#endif } } } diff --git a/src/framework/domain/output.cpp b/src/framework/domain/output.cpp index ac2108a75..c7cb6bb65 100644 --- a/src/framework/domain/output.cpp +++ b/src/framework/domain/output.cpp @@ -227,12 +227,14 @@ namespace ntt { const auto g_size = mesh().n_active()[dim]; const auto dwn_in_dim = dwn[dim]; - double n = l_size; - double d = dwn_in_dim; - double l = l_offset; - double f = math::ceil(l/d)*d-l; - const auto first_cell = static_cast(f); - const auto l_size_dwn = static_cast(math::ceil((n-f) / d)); + + const double n = l_size; + const double d = dwn_in_dim; + const double l = l_offset; + const double f = math::ceil(l / d) * d - l; + + const auto first_cell = static_cast(f); + const auto l_size_dwn = static_cast(math::ceil((n - f) / d)); const auto is_last = l_offset + l_size == g_size; @@ -244,7 +246,7 @@ namespace ntt { const auto offset = (incl_ghosts ? N_GHOSTS : 0); const auto ncells = l_size_dwn; - + const auto& metric = local_domain->mesh.metric; Kokkos::parallel_for( @@ -255,7 +257,7 @@ namespace ntt { const auto i_ = static_cast(i); coord_t x_Cd { ZERO }, x_Ph { ZERO }; x_Cd[dim] = i_ + HALF; - // TODO : change to convert by component + // TODO : change to convert by component metric.template convert(x_Cd, x_Ph); xc(offset + i_dwn) = x_Ph[dim]; x_Cd[dim] = i_; diff --git a/src/output/tests/writer-mpi.cpp b/src/output/tests/writer-mpi.cpp index 074b9acf0..c2729f658 100644 --- a/src/output/tests/writer-mpi.cpp +++ b/src/output/tests/writer-mpi.cpp @@ -2,9 +2,7 @@ #include "global.h" #include "arch/mpi_aliases.h" -#include "utils/formatting.h" -#include "output/fields.h" #include "output/writer.h" #include @@ -14,7 +12,6 @@ #include #include -#include #include #include @@ -24,49 +21,154 @@ void cleanup() { fs::remove(tempfile_path); } +#define CEILDIV(a, b) \ + (static_cast(math::ceil(static_cast(a) / static_cast(b)))) + auto main(int argc, char* argv[]) -> int { Kokkos::initialize(argc, argv); MPI_Init(&argc, &argv); - int rank, size; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - MPI_Comm_size(MPI_COMM_WORLD, &size); + int mpi_rank, mpi_size; + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + MPI_Comm_size(MPI_COMM_WORLD, &mpi_size); try { using namespace ntt; + constexpr auto nx1 = 10; + constexpr auto nx1_gh = nx1 + 2 * N_GHOSTS; + constexpr auto i1min = N_GHOSTS; + constexpr auto i1max = nx1 + N_GHOSTS; + constexpr auto dwn1 = 3; + + ndfield_t field { "fld", nx1_gh }; + std::vector field_names; + + { + // fill data + Kokkos::parallel_for( + "fill", + CreateRangePolicy({ i1min }, { i1max }), + Lambda(index_t i1) { + const auto i1_ = static_cast(i1); + field(i1, 0) = i1_; + field(i1, 1) = -i1_; + field(i1, 2) = SQR(i1_); + }); + } adios2::ADIOS adios { MPI_COMM_WORLD }; - auto writer = out::Writer(); - writer.init(&adios, "hdf5", "test"); - writer.defineMeshLayout({ static_cast(size) * 10 }, - { static_cast(rank) * 10 }, - { 10 }, - { 1 }, - false, - Coord::Cart); - writer.defineFieldOutputs(SimEngine::SRPIC, { "E" }); - - ndfield_t field { "fld", 10 + 2 * N_GHOSTS }; - Kokkos::parallel_for( - "fill", - CreateRangePolicy({ N_GHOSTS }, { 10 + N_GHOSTS }), - Lambda(index_t i1) { - field(i1, 0) = i1; - field(i1, 1) = -(real_t)(i1); - field(i1, 2) = i1 / 2; - }); - std::vector names; - std::vector addresses; - for (auto i = 0; i < 3; ++i) { - names.push_back(writer.fieldWriters()[0].name(i)); - addresses.push_back(i); + + { + // write + auto writer = out::Writer(); + writer.init(&adios, "hdf5", "test"); + writer.defineMeshLayout({ static_cast(mpi_size) * nx1 }, + { static_cast(mpi_rank) * nx1 }, + { nx1 }, + { dwn1 }, + false, + Coord::Cart); + writer.defineFieldOutputs(SimEngine::SRPIC, { "E" }); + + std::vector addresses; + for (auto i = 0; i < 3; ++i) { + field_names.push_back(writer.fieldWriters()[0].name(i)); + addresses.push_back(i); + } + writer.beginWriting(0, 0.0); + writer.writeField(field_names, field, addresses); + writer.endWriting(); + + writer.beginWriting(1, 0.1); + writer.writeField(field_names, field, addresses); + writer.endWriting(); + adios.ExitComputationBlock(); } - writer.beginWriting(0, 0.0); - writer.writeField(names, field, addresses); - writer.endWriting(); - writer.beginWriting(1, 0.1); - writer.writeField(names, field, addresses); - writer.endWriting(); + { + // read + adios2::IO io = adios.DeclareIO("read-test"); + io.SetEngine("hdf5"); + adios2::Engine reader = io.Open("test.h5", adios2::Mode::Read, MPI_COMM_SELF); + raise::ErrorIf(io.InquireAttribute("NGhosts").Data()[0] != 0, + "NGhosts is not correct", + HERE); + raise::ErrorIf(io.InquireAttribute("Dimension").Data()[0] != 1, + "Dimension is not correct", + HERE); + for (std::size_t step = 0; reader.BeginStep() == adios2::StepStatus::OK; + ++step) { + std::size_t step_read; + long double time_read; + + reader.Get(io.InquireVariable("Step"), step_read); + reader.Get(io.InquireVariable("Time"), time_read); + raise::ErrorIf(step_read != step, "Step is not correct", HERE); + raise::ErrorIf((float)time_read != (float)step * 0.1f, + "Time is not correct", + HERE); + + const auto l_size = nx1; + const auto l_offset = nx1 * mpi_rank; + const auto g_size = nx1 * mpi_size; + + const double n = l_size; + const double d = dwn1; + const double l = l_offset; + const double f = math::ceil(l / d) * d - l; + + const auto first_cell = static_cast(f); + const auto l_size_dwn = static_cast(math::ceil((n - f) / d)); + const auto l_corner_dwn = static_cast(math::ceil(l / d)); + + array_t field_read {}; + int cntr = 0; + for (const auto& name : field_names) { + auto fieldVar = io.InquireVariable(name); + if (fieldVar) { + raise::ErrorIf(fieldVar.Shape().size() != 1, + fmt::format("%s is not 1D", name.c_str()), + HERE); + auto dims = fieldVar.Shape(); + std::size_t nx1_r = dims[0]; + raise::ErrorIf((nx1_r != CEILDIV(nx1 * mpi_size, dwn1)), + fmt::format("%s = %ld is not %d", + name.c_str(), + nx1_r, + CEILDIV(nx1 * mpi_size, dwn1)), + HERE); + + fieldVar.SetSelection( + adios2::Box({ l_corner_dwn }, { l_size_dwn })); + field_read = array_t(name, l_size_dwn); + auto field_read_h = Kokkos::create_mirror_view(field_read); + reader.Get(fieldVar, field_read_h.data(), adios2::Mode::Sync); + Kokkos::deep_copy(field_read, field_read_h); + + Kokkos::parallel_for( + "check", + CreateRangePolicy({ 0 }, { l_size_dwn }), + Lambda(index_t i1) { + if (not cmp::AlmostEqual( + field_read(i1), + field(i1 * dwn1 + first_cell + i1min, cntr))) { + printf("\n:::::::::::::::\nfield_read(%ld) = %f != " + "field(%ld, %d) = %f\n:::::::::::::::\n", + i1, + field_read(i1), + i1 * dwn1 + first_cell + i1min, + cntr, + field(i1 * dwn1 + first_cell + i1min, cntr)); + raise::KernelError(HERE, "Field is not read correctly"); + } + }); + } else { + raise::Error("Field not found", HERE); + } + ++cntr; + } + } + reader.Close(); + } } catch (std::exception& e) { std::cerr << e.what() << std::endl; @@ -82,3 +184,5 @@ auto main(int argc, char* argv[]) -> int { Kokkos::finalize(); return 0; } + +#undef CEILDIV diff --git a/src/output/tests/writer-nompi.cpp b/src/output/tests/writer-nompi.cpp index 4c032094b..3fe42bf1b 100644 --- a/src/output/tests/writer-nompi.cpp +++ b/src/output/tests/writer-nompi.cpp @@ -3,7 +3,6 @@ #include "utils/formatting.h" -#include "output/fields.h" #include "output/writer.h" #include @@ -12,7 +11,6 @@ #include #include -#include #include #include @@ -24,6 +22,9 @@ void cleanup() { fs::remove(tempfile_path); } +#define CEILDIV(a, b) \ + (static_cast(math::ceil(static_cast(a) / static_cast(b)))) + auto main(int argc, char* argv[]) -> int { Kokkos::initialize(argc, argv); @@ -131,16 +132,17 @@ auto main(int argc, char* argv[]) -> int { std::size_t nx1_r = dims[0]; std::size_t nx2_r = dims[1]; std::size_t nx3_r = dims[2]; - raise::ErrorIf((nx1_r != nx1 / dwn1) || (nx2_r != nx2 / dwn2) || - (nx3_r != nx3 / dwn3), + raise::ErrorIf((nx1_r != CEILDIV(nx1, dwn1)) || + (nx2_r != CEILDIV(nx2, dwn2)) || + (nx3_r != CEILDIV(nx3, dwn3)), fmt::format("%s = %ldx%ldx%ld is not %dx%dx%d", name.c_str(), nx1_r, nx2_r, nx3_r, - nx1 / dwn1, - nx2 / dwn2, - nx3 / dwn3), + CEILDIV(nx1, dwn1), + CEILDIV(nx2, dwn2), + CEILDIV(nx3, dwn3)), HERE); fieldVar.SetSelection( @@ -195,3 +197,5 @@ auto main(int argc, char* argv[]) -> int { Kokkos::finalize(); return 0; } + +#undef CEILDIV diff --git a/src/output/writer.cpp b/src/output/writer.cpp index b35e3ab17..4ba0ea14c 100644 --- a/src/output/writer.cpp +++ b/src/output/writer.cpp @@ -78,17 +78,17 @@ namespace out { "Downsampling with ghosts not supported", HERE); - double g = glob_shape[i]; - double d = m_dwn[i]; - double l = loc_corner[i]; - double n = loc_shape[i]; - double f = math::ceil(l/d)*d-l; + const double g = glob_shape[i]; + const double d = m_dwn[i]; + const double l = loc_corner[i]; + const double n = loc_shape[i]; + const double f = math::ceil(l / d) * d - l; m_flds_g_shape_dwn.push_back(static_cast(math::ceil(g / d))); - m_flds_l_corner_dwn.push_back(static_cast(math::ceil(l /d))); + m_flds_l_corner_dwn.push_back(static_cast(math::ceil(l / d))); m_flds_l_first.push_back(static_cast(f)); - m_flds_l_shape_dwn.push_back(static_cast(math::ceil((n - f) / d))); + m_flds_l_shape_dwn.push_back( + static_cast(math::ceil((n - f) / d))); } - m_io.DefineAttribute("NGhosts", incl_ghosts ? N_GHOSTS : 0); m_io.DefineAttribute("Dimension", m_flds_g_shape.size()); @@ -222,14 +222,15 @@ namespace out { Kokkos::deep_copy(output_field, slice); } else { - const auto dwn1 = dwn[0]; - const double first_cell1_d = first_cell[0]; - const double nx1_full = field.extent(0) - 2 * N_GHOSTS; - const auto first_cell1 = first_cell[0]; + const auto dwn1 = dwn[0]; + const double first_cell1_d = first_cell[0]; + const double nx1_full = field.extent(0) - 2 * N_GHOSTS; + const auto first_cell1 = first_cell[0]; - const auto nx1_dwn = static_cast(math::ceil((nx1_full - first_cell1_d) / dwn1)); - - output_field = array_t { "output_field", nx1_dwn }; + const auto nx1_dwn = static_cast( + math::ceil((nx1_full - first_cell1_d) / dwn1)); + + output_field = array_t { "output_field", nx1_dwn }; Kokkos::parallel_for( "outputField", nx1_dwn, @@ -247,17 +248,19 @@ namespace out { slice.extent(1) }; Kokkos::deep_copy(output_field, slice); } else { - const auto dwn1 = dwn[0]; - const auto dwn2 = dwn[1]; - const double first_cell1_d = first_cell[0]; - const double first_cell2_d = first_cell[1]; - const double nx1_full = field.extent(0) - 2 * N_GHOSTS; - const double nx2_full = field.extent(1) - 2 * N_GHOSTS; - const auto first_cell1 = first_cell[0]; - const auto first_cell2 = first_cell[1]; - - const auto nx1_dwn = static_cast(math::ceil((nx1_full - first_cell1_d) / dwn1)); - const auto nx2_dwn = static_cast(math::ceil((nx2_full - first_cell2_d) / dwn2)); + const auto dwn1 = dwn[0]; + const auto dwn2 = dwn[1]; + const double first_cell1_d = first_cell[0]; + const double first_cell2_d = first_cell[1]; + const double nx1_full = field.extent(0) - 2 * N_GHOSTS; + const double nx2_full = field.extent(1) - 2 * N_GHOSTS; + const auto first_cell1 = first_cell[0]; + const auto first_cell2 = first_cell[1]; + + const auto nx1_dwn = static_cast( + math::ceil((nx1_full - first_cell1_d) / dwn1)); + const auto nx2_dwn = static_cast( + math::ceil((nx2_full - first_cell2_d) / dwn2)); output_field = array_t { "output_field", nx1_dwn, nx2_dwn }; Kokkos::parallel_for( "outputField", @@ -280,24 +283,26 @@ namespace out { slice.extent(2) }; Kokkos::deep_copy(output_field, slice); } else { - const auto dwn1 = dwn[0]; - const auto dwn2 = dwn[1]; - const auto dwn3 = dwn[2]; - const double first_cell1_d = first_cell[0]; - const double first_cell2_d = first_cell[1]; - const double first_cell3_d = first_cell[2]; - const double nx1_full = field.extent(0) - 2 * N_GHOSTS; - const double nx2_full = field.extent(1) - 2 * N_GHOSTS; - const double nx3_full = field.extent(2) - 2 * N_GHOSTS; - const auto first_cell1 = first_cell[0]; - const auto first_cell2 = first_cell[1]; - const auto first_cell3 = first_cell[2]; - - const auto nx1_dwn = static_cast(math::ceil((nx1_full - first_cell1_d) / dwn1)); - const auto nx2_dwn = static_cast(math::ceil((nx2_full - first_cell2_d) / dwn2)); - const auto nx3_dwn = static_cast(math::ceil((nx3_full - first_cell3_d) / dwn3)); - - + const auto dwn1 = dwn[0]; + const auto dwn2 = dwn[1]; + const auto dwn3 = dwn[2]; + const double first_cell1_d = first_cell[0]; + const double first_cell2_d = first_cell[1]; + const double first_cell3_d = first_cell[2]; + const double nx1_full = field.extent(0) - 2 * N_GHOSTS; + const double nx2_full = field.extent(1) - 2 * N_GHOSTS; + const double nx3_full = field.extent(2) - 2 * N_GHOSTS; + const auto first_cell1 = first_cell[0]; + const auto first_cell2 = first_cell[1]; + const auto first_cell3 = first_cell[2]; + + const auto nx1_dwn = static_cast( + math::ceil((nx1_full - first_cell1_d) / dwn1)); + const auto nx2_dwn = static_cast( + math::ceil((nx2_full - first_cell2_d) / dwn2)); + const auto nx3_dwn = static_cast( + math::ceil((nx3_full - first_cell3_d) / dwn3)); + output_field = array_t { "output_field", nx1_dwn, nx2_dwn, nx3_dwn }; Kokkos::parallel_for( "outputField", From af5ac780f96043ce277b1e2df0c76d771ade6e93 Mon Sep 17 00:00:00 2001 From: hayk Date: Mon, 4 Nov 2024 14:22:13 -0500 Subject: [PATCH 136/773] cmake formatting --- CMakeLists.txt | 67 ++++++------ cmake/MPIConfig.cmake | 3 +- cmake/adios2Config.cmake | 24 +++-- cmake/config.cmake | 31 ++++-- cmake/defaults.cmake | 76 ++++++++++---- cmake/dependencies.cmake | 106 ++++++++++++------- cmake/kokkosConfig.cmake | 52 +++++++--- cmake/report.cmake | 155 +++++++++++++++++----------- cmake/styling.cmake | 27 +++-- cmake/tests.cmake | 37 ++++--- setups/CMakeLists.txt | 28 ++--- src/CMakeLists.txt | 35 ++++--- src/archetypes/CMakeLists.txt | 20 ++-- src/archetypes/tests/CMakeLists.txt | 8 +- src/checkpoint/CMakeLists.txt | 33 +++--- src/checkpoint/tests/CMakeLists.txt | 12 ++- src/engines/CMakeLists.txt | 58 ++++++----- src/framework/CMakeLists.txt | 71 +++++++------ src/framework/tests/CMakeLists.txt | 50 +++++---- src/global/CMakeLists.txt | 48 ++++----- src/global/tests/CMakeLists.txt | 12 ++- src/kernels/CMakeLists.txt | 20 ++-- src/kernels/tests/CMakeLists.txt | 8 +- src/metrics/CMakeLists.txt | 16 ++- src/metrics/tests/CMakeLists.txt | 13 ++- src/output/CMakeLists.txt | 37 ++++--- src/output/tests/CMakeLists.txt | 28 +++-- 27 files changed, 662 insertions(+), 413 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 62319559b..4ee00d1b4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,12 +8,13 @@ project( VERSION 1.2.0 LANGUAGES CXX C) add_compile_options("-D ENTITY_VERSION=\"${PROJECT_VERSION}\"") -execute_process(COMMAND - bash -c "git diff --quiet src/ && echo $(git rev-parse HEAD) || echo $(git rev-parse HEAD)-mod" +execute_process( + COMMAND + bash -c + "git diff --quiet src/ && echo $(git rev-parse HEAD) || echo $(git rev-parse HEAD)-mod" WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" OUTPUT_VARIABLE GIT_HASH - ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE -) + ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) message(STATUS "Git hash: ${GIT_HASH}") add_compile_options("-D ENTITY_GIT_HASH=\"${GIT_HASH}\"") @@ -25,56 +26,57 @@ include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/defaults.cmake) # defaults set(DEBUG - ${default_debug} - CACHE BOOL "Debug mode") + ${default_debug} + CACHE BOOL "Debug mode") set(precision - ${default_precision} - CACHE STRING "Precision") + ${default_precision} + CACHE STRING "Precision") set(pgen - ${default_pgen} - CACHE STRING "Problem generator") + ${default_pgen} + CACHE STRING "Problem generator") set(gui - ${default_gui} - CACHE BOOL "Use GUI [nttiny]") + ${default_gui} + CACHE BOOL "Use GUI [nttiny]") set(output - ${default_output} - CACHE BOOL "Enable output") + ${default_output} + CACHE BOOL "Enable output") set(mpi - ${default_mpi} - CACHE BOOL "Use MPI") + ${default_mpi} + CACHE BOOL "Use MPI") # -------------------------- Compilation settings -------------------------- # set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) if(${DEBUG} STREQUAL "OFF") set(CMAKE_BUILD_TYPE - Release - CACHE STRING "CMake build type") + Release + CACHE STRING "CMake build type") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DNDEBUG") else() set(CMAKE_BUILD_TYPE - Debug - CACHE STRING "CMake build type") + Debug + CACHE STRING "CMake build type") set(CMAKE_CXX_FLAGS - "${CMAKE_CXX_FLAGS} -DDEBUG -Wall -Wextra -Wno-unknown-pragmas") + "${CMAKE_CXX_FLAGS} -DDEBUG -Wall -Wextra -Wno-unknown-pragmas") endif() set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unused-local-typedefs") # options set(precisions - "single" "double" - CACHE STRING "Precisions") + "single" "double" + CACHE STRING "Precisions") include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/config.cmake) # ------------------------- Third-Party Tests ------------------------------ # set(BUILD_TESTING - OFF - CACHE BOOL "Build tests") + OFF + CACHE BOOL "Build tests") # ------------------------ Third-party dependencies ------------------------ # include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/kokkosConfig.cmake) @@ -98,12 +100,12 @@ endif() if(${output}) include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/adios2Config.cmake) find_or_fetch_dependency(adios2 FALSE) - if (NOT DEFINED ENV{HDF5_ROOT}) + if(NOT DEFINED ENV{HDF5_ROOT}) set(USE_CUSTOM_HDF5 OFF) - if (DEFINED ENV{CONDA_PREFIX}) + if(DEFINED ENV{CONDA_PREFIX}) execute_process(COMMAND bash -c "conda list | grep \"hdf5\" -q" - RESULT_VARIABLE HDF5_INSTALLED) - if (HDF5_INSTALLED EQUAL 0) + RESULT_VARIABLE HDF5_INSTALLED) + if(HDF5_INSTALLED EQUAL 0) set(HDF5_ROOT $ENV{CONDA_PREFIX}) else() set(USE_CUSTOM_HDF5 ON) @@ -111,8 +113,11 @@ if(${output}) else() set(USE_CUSTOM_HDF5 ON) endif() - if (USE_CUSTOM_HDF5) - message(FATAL_ERROR "HDF5_ROOT is not set. Please set it to the root of the HDF5 installation") + if(USE_CUSTOM_HDF5) + message( + FATAL_ERROR + "HDF5_ROOT is not set. Please set it to the root of the HDF5 installation" + ) endif() endif() find_package(HDF5 REQUIRED) diff --git a/cmake/MPIConfig.cmake b/cmake/MPIConfig.cmake index b426641ec..d1bfeaab2 100644 --- a/cmake/MPIConfig.cmake +++ b/cmake/MPIConfig.cmake @@ -1,3 +1,4 @@ find_package(MPI REQUIRED) include_directories(${MPI_CXX_INCLUDE_PATH}) -add_compile_options("-D MPI_ENABLED") \ No newline at end of file +add_compile_options("-D MPI_ENABLED") + diff --git a/cmake/adios2Config.cmake b/cmake/adios2Config.cmake index 16c0c30c7..5c480f3d8 100644 --- a/cmake/adios2Config.cmake +++ b/cmake/adios2Config.cmake @@ -1,15 +1,27 @@ # ----------------------------- Adios2 settings ---------------------------- # -set(ADIOS2_BUILD_EXAMPLES OFF CACHE BOOL "Build ADIOS2 examples") +set(ADIOS2_BUILD_EXAMPLES + OFF + CACHE BOOL "Build ADIOS2 examples") # Language support -set(ADIOS2_USE_Python OFF CACHE BOOL "Use Python for ADIOS2") -set(ADIOS2_USE_Fortran OFF CACHE BOOL "Use Fortran for ADIOS2") +set(ADIOS2_USE_Python + OFF + CACHE BOOL "Use Python for ADIOS2") +set(ADIOS2_USE_Fortran + OFF + CACHE BOOL "Use Fortran for ADIOS2") # Format/compression support -set(ADIOS2_USE_ZeroMQ OFF CACHE BOOL "Use ZeroMQ for ADIOS2") +set(ADIOS2_USE_ZeroMQ + OFF + CACHE BOOL "Use ZeroMQ for ADIOS2") -set(ADIOS2_USE_MPI ${mpi} CACHE BOOL "Use MPI for ADIOS2") +set(ADIOS2_USE_MPI + ${mpi} + CACHE BOOL "Use MPI for ADIOS2") -set(ADIOS2_USE_CUDA OFF CACHE BOOL "Use CUDA for ADIOS2") +set(ADIOS2_USE_CUDA + OFF + CACHE BOOL "Use CUDA for ADIOS2") add_compile_options("-D OUTPUT_ENABLED") diff --git a/cmake/config.cmake b/cmake/config.cmake index fa18a87eb..58dd467e9 100644 --- a/cmake/config.cmake +++ b/cmake/config.cmake @@ -3,7 +3,10 @@ function(set_precision precision_name) list(FIND precisions ${precision_name} PRECISION_FOUND) if(${PRECISION_FOUND} EQUAL -1) - message(FATAL_ERROR "Invalid precision: ${precision_name}\nValid options are: ${precisions}") + message( + FATAL_ERROR + "Invalid precision: ${precision_name}\nValid options are: ${precisions}" + ) endif() if(${precision_name} STREQUAL "single") @@ -13,19 +16,31 @@ endfunction() # ---------------------------- Problem generator --------------------------- # function(set_problem_generator pgen_name) - file(GLOB_RECURSE PGENS "${CMAKE_CURRENT_SOURCE_DIR}/setups/**/pgen.hpp" "${CMAKE_CURRENT_SOURCE_DIR}/setups/pgen.hpp") + file(GLOB_RECURSE PGENS "${CMAKE_CURRENT_SOURCE_DIR}/setups/**/pgen.hpp" + "${CMAKE_CURRENT_SOURCE_DIR}/setups/pgen.hpp") foreach(PGEN ${PGENS}) get_filename_component(PGEN_NAME ${PGEN} DIRECTORY) - string(REPLACE "${CMAKE_CURRENT_SOURCE_DIR}/setups/" "" PGEN_NAME ${PGEN_NAME}) - string(REPLACE "${CMAKE_CURRENT_SOURCE_DIR}/setups" "" PGEN_NAME ${PGEN_NAME}) + string(REPLACE "${CMAKE_CURRENT_SOURCE_DIR}/setups/" "" PGEN_NAME + ${PGEN_NAME}) + string(REPLACE "${CMAKE_CURRENT_SOURCE_DIR}/setups" "" PGEN_NAME + ${PGEN_NAME}) list(APPEND PGEN_NAMES ${PGEN_NAME}) endforeach() list(FIND PGEN_NAMES ${pgen_name} PGEN_FOUND) if(NOT ${pgen_name} STREQUAL "." AND ${PGEN_FOUND} EQUAL -1) - message(FATAL_ERROR "Invalid problem generator: ${pgen_name}\nValid options are: ${PGEN_NAMES}") + message( + FATAL_ERROR + "Invalid problem generator: ${pgen_name}\nValid options are: ${PGEN_NAMES}" + ) endif() - set(PGEN ${pgen_name} PARENT_SCOPE) + set(PGEN + ${pgen_name} + PARENT_SCOPE) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/setups/${pgen_name}) - set(PGEN_FOUND TRUE PARENT_SCOPE) - set(problem_generators ${PGEN_NAMES} PARENT_SCOPE) + set(PGEN_FOUND + TRUE + PARENT_SCOPE) + set(problem_generators + ${PGEN_NAMES} + PARENT_SCOPE) endfunction() diff --git a/cmake/defaults.cmake b/cmake/defaults.cmake index f70120e0d..46b4609c5 100644 --- a/cmake/defaults.cmake +++ b/cmake/defaults.cmake @@ -1,62 +1,100 @@ # ----------------------------- Defaults ---------------------------------- # if(DEFINED ENV{Entity_ENABLE_DEBUG}) - set(default_debug $ENV{Entity_ENABLE_DEBUG} CACHE INTERNAL "Default flag for debug mode") + set(default_debug + $ENV{Entity_ENABLE_DEBUG} + CACHE INTERNAL "Default flag for debug mode") else() - set(default_debug OFF CACHE INTERNAL "Default flag for debug mode") + set(default_debug + OFF + CACHE INTERNAL "Default flag for debug mode") endif() set_property(CACHE default_debug PROPERTY TYPE BOOL) -set(default_engine "pic" CACHE INTERNAL "Default engine") -set(default_precision "single" CACHE INTERNAL "Default precision") -set(default_pgen "." CACHE INTERNAL "Default problem generator") -set(default_sr_metric "minkowski" CACHE INTERNAL "Default SR metric") -set(default_gr_metric "kerr_schild" CACHE INTERNAL "Default GR metric") +set(default_engine + "pic" + CACHE INTERNAL "Default engine") +set(default_precision + "single" + CACHE INTERNAL "Default precision") +set(default_pgen + "." + CACHE INTERNAL "Default problem generator") +set(default_sr_metric + "minkowski" + CACHE INTERNAL "Default SR metric") +set(default_gr_metric + "kerr_schild" + CACHE INTERNAL "Default GR metric") if(DEFINED ENV{Entity_ENABLE_OUTPUT}) - set(default_output $ENV{Entity_ENABLE_OUTPUT} CACHE INTERNAL "Default flag for output") + set(default_output + $ENV{Entity_ENABLE_OUTPUT} + CACHE INTERNAL "Default flag for output") else() - set(default_output OFF CACHE INTERNAL "Default flag for output") + set(default_output + OFF + CACHE INTERNAL "Default flag for output") endif() set_property(CACHE default_output PROPERTY TYPE BOOL) if(DEFINED ENV{Entity_ENABLE_GUI}) - set(default_gui $ENV{Entity_ENABLE_GUI} CACHE INTERNAL "Default flag for GUI") + set(default_gui + $ENV{Entity_ENABLE_GUI} + CACHE INTERNAL "Default flag for GUI") else() - set(default_gui OFF CACHE INTERNAL "Default flag for GUI") + set(default_gui + OFF + CACHE INTERNAL "Default flag for GUI") endif() set_property(CACHE default_gui PROPERTY TYPE BOOL) if(DEFINED ENV{Kokkos_ENABLE_CUDA}) - set(default_KOKKOS_ENABLE_CUDA $ENV{Kokkos_ENABLE_CUDA} CACHE INTERNAL "Default flag for CUDA") + set(default_KOKKOS_ENABLE_CUDA + $ENV{Kokkos_ENABLE_CUDA} + CACHE INTERNAL "Default flag for CUDA") else() - set(default_KOKKOS_ENABLE_CUDA OFF CACHE INTERNAL "Default flag for CUDA") + set(default_KOKKOS_ENABLE_CUDA + OFF + CACHE INTERNAL "Default flag for CUDA") endif() set_property(CACHE default_KOKKOS_ENABLE_CUDA PROPERTY TYPE BOOL) if(DEFINED ENV{Kokkos_ENABLE_HIP}) - set(default_KOKKOS_ENABLE_HIP $ENV{Kokkos_ENABLE_HIP} CACHE INTERNAL "Default flag for HIP") + set(default_KOKKOS_ENABLE_HIP + $ENV{Kokkos_ENABLE_HIP} + CACHE INTERNAL "Default flag for HIP") else() - set(default_KOKKOS_ENABLE_HIP OFF CACHE INTERNAL "Default flag for HIP") + set(default_KOKKOS_ENABLE_HIP + OFF + CACHE INTERNAL "Default flag for HIP") endif() set_property(CACHE default_KOKKOS_ENABLE_HIP PROPERTY TYPE BOOL) if(DEFINED ENV{Kokkos_ENABLE_OPENMP}) - set(default_KOKKOS_ENABLE_OPENMP $ENV{Kokkos_ENABLE_OPENMP} CACHE INTERNAL "Default flag for OpenMP") + set(default_KOKKOS_ENABLE_OPENMP + $ENV{Kokkos_ENABLE_OPENMP} + CACHE INTERNAL "Default flag for OpenMP") else() - set(default_KOKKOS_ENABLE_OPENMP OFF CACHE INTERNAL "Default flag for OpenMP") + set(default_KOKKOS_ENABLE_OPENMP + OFF + CACHE INTERNAL "Default flag for OpenMP") endif() set_property(CACHE default_KOKKOS_ENABLE_OPENMP PROPERTY TYPE BOOL) if(DEFINED ENV{Entity_ENABLE_MPI}) - set(default_mpi $ENV{Entity_ENABLE_MPI} CACHE INTERNAL "Default flag for MPI") + set(default_mpi + $ENV{Entity_ENABLE_MPI} + CACHE INTERNAL "Default flag for MPI") else() - set(default_mpi OFF CACHE INTERNAL "Default flag for MPI") + set(default_mpi + OFF + CACHE INTERNAL "Default flag for MPI") endif() set_property(CACHE default_mpi PROPERTY TYPE BOOL) diff --git a/cmake/dependencies.cmake b/cmake/dependencies.cmake index b143befdf..06a3e6a1f 100644 --- a/cmake/dependencies.cmake +++ b/cmake/dependencies.cmake @@ -1,24 +1,34 @@ -set(Kokkos_REPOSITORY https://github.com/kokkos/kokkos.git CACHE STRING "Kokkos repository") -set(plog_REPOSITORY https://github.com/SergiusTheBest/plog.git CACHE STRING "plog repository") -set(toml11_REPOSITORY https://github.com/ToruNiina/toml11 CACHE STRING "toml11 repository") +set(Kokkos_REPOSITORY + https://github.com/kokkos/kokkos.git + CACHE STRING "Kokkos repository") +set(plog_REPOSITORY + https://github.com/SergiusTheBest/plog.git + CACHE STRING "plog repository") -# set (adios2_REPOSITORY https://github.com/ornladios/ADIOS2.git CACHE STRING "ADIOS2 repository") +# set (adios2_REPOSITORY https://github.com/ornladios/ADIOS2.git CACHE STRING +# "ADIOS2 repository") function(check_internet_connection) if(OFFLINE STREQUAL "ON") - set(FETCHCONTENT_FULLY_DISCONNECTED ON CACHE BOOL "Connection status") + set(FETCHCONTENT_FULLY_DISCONNECTED + ON + CACHE BOOL "Connection status") message(STATUS "${Blue}Offline mode.${ColorReset}") else() execute_process( COMMAND ping 8.8.8.8 -c 2 RESULT_VARIABLE NO_CONNECTION - OUTPUT_QUIET - ) + OUTPUT_QUIET) if(NO_CONNECTION GREATER 0) - set(FETCHCONTENT_FULLY_DISCONNECTED ON CACHE BOOL "Connection status") - message(STATUS "${Red}No internet connection. Fetching disabled.${ColorReset}") + set(FETCHCONTENT_FULLY_DISCONNECTED + ON + CACHE BOOL "Connection status") + message( + STATUS "${Red}No internet connection. Fetching disabled.${ColorReset}") else() - set(FETCHCONTENT_FULLY_DISCONNECTED OFF CACHE BOOL "Connection status") + set(FETCHCONTENT_FULLY_DISCONNECTED + OFF + CACHE BOOL "Connection status") message(STATUS "${Green}Internet connection established.${ColorReset}") endif() endif() @@ -30,66 +40,92 @@ function(find_or_fetch_dependency package_name header_only) endif() if(NOT ${package_name}_FOUND) - if(DEFINED ${package_name}_REPOSITORY AND NOT FETCHCONTENT_FULLY_DISCONNECTED) + if(DEFINED ${package_name}_REPOSITORY AND NOT + FETCHCONTENT_FULLY_DISCONNECTED) # fetching package - message(STATUS "${Blue}${package_name} not found. Fetching from ${${package_name}_REPOSITORY}${ColorReset}") + message( + STATUS + "${Blue}${package_name} not found. Fetching from ${${package_name}_REPOSITORY}${ColorReset}" + ) include(FetchContent) if(${package_name} STREQUAL "Kokkos") FetchContent_Declare( ${package_name} GIT_REPOSITORY ${${package_name}_REPOSITORY} - GIT_TAG 4.3.00 - ) + GIT_TAG 4.3.00) else() - FetchContent_Declare( - ${package_name} - GIT_REPOSITORY ${${package_name}_REPOSITORY} - ) + FetchContent_Declare(${package_name} + GIT_REPOSITORY ${${package_name}_REPOSITORY}) endif() FetchContent_MakeAvailable(${package_name}) set(lower_pckg_name ${package_name}) string(TOLOWER ${lower_pckg_name} lower_pckg_name) - set(${package_name}_SRC ${CMAKE_CURRENT_BINARY_DIR}/_deps/${lower_pckg_name}-src CACHE PATH "Path to ${package_name} src") - set(${package_name}_FETCHED TRUE CACHE BOOL "Whether ${package_name} was fetched") + set(${package_name}_SRC + ${CMAKE_CURRENT_BINARY_DIR}/_deps/${lower_pckg_name}-src + CACHE PATH "Path to ${package_name} src") + set(${package_name}_FETCHED + TRUE + CACHE BOOL "Whether ${package_name} was fetched") message(STATUS "${Green}${package_name} fetched.${ColorReset}") else() # get as submodule - message(STATUS "${Yellow}${package_name} not found. Using as submodule.${ColorReset}") + message( + STATUS + "${Yellow}${package_name} not found. Using as submodule.${ColorReset}" + ) - set(${package_name}_FETCHED FALSE CACHE BOOL "Whether ${package_name} was fetched") + set(${package_name}_FETCHED + FALSE + CACHE BOOL "Whether ${package_name} was fetched") if(NOT FETCHCONTENT_FULLY_DISCONNECTED) - message(STATUS "${GREEN}Updating ${package_name} submodule.${ColorReset}") + message( + STATUS "${GREEN}Updating ${package_name} submodule.${ColorReset}") execute_process( - COMMAND git submodule update --init --remote ${CMAKE_CURRENT_SOURCE_DIR}/extern/${package_name} - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} - ) + COMMAND git submodule update --init --remote + ${CMAKE_CURRENT_SOURCE_DIR}/extern/${package_name} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) endif() - add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/extern/${package_name} extern/${package_name}) - set(${package_name}_SRC ${CMAKE_CURRENT_SOURCE_DIR}/extern/${package_name} CACHE PATH "Path to ${package_name} src") - set(${package_name}_BUILD_DIR ${CMAKE_CURRENT_SOURCE_DIR}/build/extern/${package_name} CACHE PATH "Path to ${package_name} build") + add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/extern/${package_name} + extern/${package_name}) + set(${package_name}_SRC + ${CMAKE_CURRENT_SOURCE_DIR}/extern/${package_name} + CACHE PATH "Path to ${package_name} src") + set(${package_name}_BUILD_DIR + ${CMAKE_CURRENT_SOURCE_DIR}/build/extern/${package_name} + CACHE PATH "Path to ${package_name} build") endif() else() message(STATUS "${Green}${package_name} found.${ColorReset}") - set(${package_name}_FETCHED FALSE CACHE BOOL "Whether ${package_name} was fetched") - set(${package_name}_VERSION ${${package_name}_VERSION} CACHE INTERNAL "${package_name} version") + set(${package_name}_FETCHED + FALSE + CACHE BOOL "Whether ${package_name} was fetched") + set(${package_name}_VERSION + ${${package_name}_VERSION} + CACHE INTERNAL "${package_name} version") endif() if(${package_name} STREQUAL "adios2") if(NOT DEFINED adios2_VERSION OR adios2_VERSION STREQUAL "") - get_directory_property(adios2_VERSION DIRECTORY ${adios2_BUILD_DIR} DEFINITION ADIOS2_VERSION) - set(adios2_VERSION ${adios2_VERSION} CACHE INTERNAL "ADIOS2 version") + get_directory_property(adios2_VERSION DIRECTORY ${adios2_BUILD_DIR} + DEFINITION ADIOS2_VERSION) + set(adios2_VERSION + ${adios2_VERSION} + CACHE INTERNAL "ADIOS2 version") endif() endif() if(${package_name} STREQUAL "Kokkos") if(NOT DEFINED Kokkos_VERSION OR Kokkos_VERSION STREQUAL "") - get_directory_property(Kokkos_VERSION DIRECTORY ${Kokkos_SRC} DEFINITION Kokkos_VERSION) - set(Kokkos_VERSION ${Kokkos_VERSION} CACHE INTERNAL "Kokkos version") + get_directory_property(Kokkos_VERSION DIRECTORY ${Kokkos_SRC} DEFINITION + Kokkos_VERSION) + set(Kokkos_VERSION + ${Kokkos_VERSION} + CACHE INTERNAL "Kokkos version") endif() endif() endfunction() diff --git a/cmake/kokkosConfig.cmake b/cmake/kokkosConfig.cmake index 8928253ae..63c32622d 100644 --- a/cmake/kokkosConfig.cmake +++ b/cmake/kokkosConfig.cmake @@ -1,19 +1,41 @@ # ----------------------------- Kokkos settings ---------------------------- # if(${DEBUG} STREQUAL "OFF") - set(Kokkos_ENABLE_AGGRESSIVE_VECTORIZATION ON CACHE BOOL "Kokkos aggressive vectorization") - set(Kokkos_ENABLE_COMPILER_WARNINGS OFF CACHE BOOL "Kokkos compiler warnings") - set(Kokkos_ENABLE_DEBUG OFF CACHE BOOL "Kokkos debug") - set(Kokkos_ENABLE_DEBUG_BOUNDS_CHECK OFF CACHE BOOL "Kokkos debug bounds check") + set(Kokkos_ENABLE_AGGRESSIVE_VECTORIZATION + ON + CACHE BOOL "Kokkos aggressive vectorization") + set(Kokkos_ENABLE_COMPILER_WARNINGS + OFF + CACHE BOOL "Kokkos compiler warnings") + set(Kokkos_ENABLE_DEBUG + OFF + CACHE BOOL "Kokkos debug") + set(Kokkos_ENABLE_DEBUG_BOUNDS_CHECK + OFF + CACHE BOOL "Kokkos debug bounds check") else() - set(Kokkos_ENABLE_AGGRESSIVE_VECTORIZATION OFF CACHE BOOL "Kokkos aggressive vectorization") - set(Kokkos_ENABLE_COMPILER_WARNINGS ON CACHE BOOL "Kokkos compiler warnings") - set(Kokkos_ENABLE_DEBUG ON CACHE BOOL "Kokkos debug") - set(Kokkos_ENABLE_DEBUG_BOUNDS_CHECK ON CACHE BOOL "Kokkos debug bounds check") + set(Kokkos_ENABLE_AGGRESSIVE_VECTORIZATION + OFF + CACHE BOOL "Kokkos aggressive vectorization") + set(Kokkos_ENABLE_COMPILER_WARNINGS + ON + CACHE BOOL "Kokkos compiler warnings") + set(Kokkos_ENABLE_DEBUG + ON + CACHE BOOL "Kokkos debug") + set(Kokkos_ENABLE_DEBUG_BOUNDS_CHECK + ON + CACHE BOOL "Kokkos debug bounds check") endif() -set(Kokkos_ENABLE_HIP ${default_KOKKOS_ENABLE_HIP} CACHE BOOL "Enable HIP") -set(Kokkos_ENABLE_CUDA ${default_KOKKOS_ENABLE_CUDA} CACHE BOOL "Enable CUDA") -set(Kokkos_ENABLE_OPENMP ${default_KOKKOS_ENABLE_OPENMP} CACHE BOOL "Enable OpenMP") +set(Kokkos_ENABLE_HIP + ${default_KOKKOS_ENABLE_HIP} + CACHE BOOL "Enable HIP") +set(Kokkos_ENABLE_CUDA + ${default_KOKKOS_ENABLE_CUDA} + CACHE BOOL "Enable CUDA") +set(Kokkos_ENABLE_OPENMP + ${default_KOKKOS_ENABLE_OPENMP} + CACHE BOOL "Enable OpenMP") # set memory space if(${Kokkos_ENABLE_CUDA}) @@ -51,7 +73,11 @@ add_compile_options("-D HostExeSpace=${HOST_EXE_SPACE}") add_compile_options("-D HostMemSpace=${HOST_MEM_SPACE}") if(${BUILD_TESTING} STREQUAL "OFF") - set(Kokkos_ENABLE_TESTS OFF CACHE BOOL "Kokkos tests") + set(Kokkos_ENABLE_TESTS + OFF + CACHE BOOL "Kokkos tests") else() - set(Kokkos_ENABLE_TESTS ON CACHE BOOL "Kokkos tests") + set(Kokkos_ENABLE_TESTS + ON + CACHE BOOL "Kokkos tests") endif() diff --git a/cmake/report.cmake b/cmake/report.cmake index 6733dbcd4..13dde63f7 100644 --- a/cmake/report.cmake +++ b/cmake/report.cmake @@ -18,10 +18,22 @@ function(PadTo Text Padding Target Result) set(${rt} "${rt}") endif() - set(${Result} "${rt}" PARENT_SCOPE) + set(${Result} + "${rt}" + PARENT_SCOPE) endfunction() -function(PrintChoices Label Flag Choices Value Default Color OutputString Multiline Padding) +function( + PrintChoices + Label + Flag + Choices + Value + Default + Color + OutputString + Multiline + Padding) list(LENGTH "${Choices}" nchoices) set(rstring "") set(counter 0) @@ -35,14 +47,14 @@ function(PrintChoices Label Flag Choices Value Default Color OutputString Multil endif() set(rstring_i "${rstring_i}:") - PadTo("${rstring_i}" " " ${Padding} rstring_i) + padto("${rstring_i}" " " ${Padding} rstring_i) else() set(rstring_i "") if(NOT ${counter} EQUAL ${nchoices}) if(${Multiline} EQUAL 1) set(rstring_i "${rstring_i}\n") - PadTo("${rstring_i}" " " ${Padding} rstring_i) + padto("${rstring_i}" " " ${Padding} rstring_i) else() set(rstring_i "${rstring_i}/") endif() @@ -71,13 +83,16 @@ function(PrintChoices Label Flag Choices Value Default Color OutputString Multil set(rstring_i "") endforeach() - set(${OutputString} "${rstring}" PARENT_SCOPE) + set(${OutputString} + "${rstring}" + PARENT_SCOPE) endfunction() set(ON_OFF_VALUES "ON" "OFF") if(${PGEN_FOUND}) - PrintChoices("Problem generator" + printchoices( + "Problem generator" "pgen" "${problem_generators}" ${PGEN} @@ -85,11 +100,11 @@ if(${PGEN_FOUND}) "${Blue}" PGEN_REPORT 1 - 36 - ) + 36) endif() -PrintChoices("Precision" +printchoices( + "Precision" "precision" "${precisions}" ${precision} @@ -97,9 +112,9 @@ PrintChoices("Precision" "${Blue}" PRECISION_REPORT 1 - 36 -) -PrintChoices("Output" + 36) +printchoices( + "Output" "output" "${ON_OFF_VALUES}" ${output} @@ -107,9 +122,9 @@ PrintChoices("Output" "${Green}" OUTPUT_REPORT 0 - 36 -) -PrintChoices("GUI" + 36) +printchoices( + "GUI" "gui" "${ON_OFF_VALUES}" ${gui} @@ -117,9 +132,9 @@ PrintChoices("GUI" "${Green}" GUI_REPORT 0 - 36 -) -PrintChoices("MPI" + 36) +printchoices( + "MPI" "mpi" "${ON_OFF_VALUES}" ${mpi} @@ -127,9 +142,9 @@ PrintChoices("MPI" "${Green}" MPI_REPORT 0 - 42 -) -PrintChoices("Debug mode" + 42) +printchoices( + "Debug mode" "DEBUG" "${ON_OFF_VALUES}" ${DEBUG} @@ -137,10 +152,10 @@ PrintChoices("Debug mode" "${Green}" DEBUG_REPORT 0 - 42 -) + 42) -PrintChoices("CUDA" +printchoices( + "CUDA" "Kokkos_ENABLE_CUDA" "${ON_OFF_VALUES}" ${Kokkos_ENABLE_CUDA} @@ -148,9 +163,9 @@ PrintChoices("CUDA" "${Green}" CUDA_REPORT 0 - 42 -) -PrintChoices("HIP" + 42) +printchoices( + "HIP" "Kokkos_ENABLE_HIP" "${ON_OFF_VALUES}" ${Kokkos_ENABLE_HIP} @@ -158,9 +173,9 @@ PrintChoices("HIP" "${Green}" HIP_REPORT 0 - 42 -) -PrintChoices("OpenMP" + 42) +printchoices( + "OpenMP" "Kokkos_ENABLE_OPENMP" "${ON_OFF_VALUES}" ${Kokkos_ENABLE_OPENMP} @@ -168,10 +183,10 @@ PrintChoices("OpenMP" "${Green}" OPENMP_REPORT 0 - 42 -) + 42) -PrintChoices("C++ compiler" +printchoices( + "C++ compiler" "CMAKE_CXX_COMPILER" "${CMAKE_CXX_COMPILER} v${CMAKE_CXX_COMPILER_VERSION}" "${CMAKE_CXX_COMPILER} v${CMAKE_CXX_COMPILER_VERSION}" @@ -179,10 +194,10 @@ PrintChoices("C++ compiler" "${ColorReset}" CXX_COMPILER_REPORT 0 - 42 -) + 42) -PrintChoices("C compiler" +printchoices( + "C compiler" "CMAKE_C_COMPILER" "${CMAKE_C_COMPILER} v${CMAKE_C_COMPILER_VERSION}" "${CMAKE_C_COMPILER} v${CMAKE_C_COMPILER_VERSION}" @@ -190,21 +205,24 @@ PrintChoices("C compiler" "${ColorReset}" C_COMPILER_REPORT 0 - 42 -) + 42) get_cmake_property(_variableNames VARIABLES) -foreach (_variableName ${_variableNames}) - string(REGEX MATCH "Kokkos_ARCH_*" _isMatched ${_variableName}) - if(_isMatched) - get_property(isSet CACHE ${_variableName} PROPERTY VALUE) - if(isSet STREQUAL "ON") - string(REGEX REPLACE "Kokkos_ARCH_" "" ARCH ${_variableName}) - break() - endif() +foreach(_variableName ${_variableNames}) + string(REGEX MATCH "Kokkos_ARCH_*" _isMatched ${_variableName}) + if(_isMatched) + get_property( + isSet + CACHE ${_variableName} + PROPERTY VALUE) + if(isSet STREQUAL "ON") + string(REGEX REPLACE "Kokkos_ARCH_" "" ARCH ${_variableName}) + break() endif() + endif() endforeach() -PrintChoices("Architecture" +printchoices( + "Architecture" "Kokkos_ARCH_*" "${ARCH}" "${ARCH}" @@ -212,8 +230,7 @@ PrintChoices("Architecture" "${ColorReset}" ARCH_REPORT 0 - 42 -) + 42) if(${Kokkos_ENABLE_CUDA}) if("${CMAKE_CUDA_COMPILER}" STREQUAL "") @@ -225,11 +242,15 @@ if(${Kokkos_ENABLE_CUDA}) string(STRIP ${CUDACOMP} CUDACOMP) message(STATUS "CUDA compiler: ${CUDACOMP}") - execute_process(COMMAND bash -c "${CUDACOMP} --version | grep release | sed -e 's/.*release //' -e 's/,.*//'" + execute_process( + COMMAND + bash -c + "${CUDACOMP} --version | grep release | sed -e 's/.*release //' -e 's/,.*//'" OUTPUT_VARIABLE CUDACOMP_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE) - PrintChoices("CUDA compiler" + printchoices( + "CUDA compiler" "CMAKE_CUDA_COMPILER" "${CUDACOMP}" "${CUDACOMP}" @@ -237,28 +258,37 @@ if(${Kokkos_ENABLE_CUDA}) "${ColorReset}" CUDA_COMPILER_REPORT 0 - 42 - ) + 42) endif() -if (${Kokkos_ENABLE_HIP}) - execute_process(COMMAND bash -c "hipcc --version | grep HIP | cut -d ':' -f 2 | tr -d ' '" +if(${Kokkos_ENABLE_HIP}) + execute_process( + COMMAND bash -c "hipcc --version | grep HIP | cut -d ':' -f 2 | tr -d ' '" OUTPUT_VARIABLE ROCM_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE) endif() set(DOT_SYMBOL "${ColorReset}.") -set(DOTTED_LINE_SYMBOL "${ColorReset}. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ") +set(DOTTED_LINE_SYMBOL + "${ColorReset}. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . " +) -set(DASHED_LINE_SYMBOL "${ColorReset}....................................................................... ") +set(DASHED_LINE_SYMBOL + "${ColorReset}....................................................................... " +) if(NOT ${PROJECT_VERSION_TWEAK} EQUAL 0) - set(VERSION_SYMBOL "v${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}-rc${PROJECT_VERSION_TWEAK}") + set(VERSION_SYMBOL + "v${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}-rc${PROJECT_VERSION_TWEAK}" + ) else() - set(VERSION_SYMBOL "v${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH} ") + set(VERSION_SYMBOL + "v${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH} " + ) endif() -message("${Blue} __ __ +message( + "${Blue} __ __ /\\ \\__ __/\\ \\__ __ ___\\ \\ _\\/\\_\\ \\ _\\ __ __ / __ \\ / __ \\ \\ \\/\\/\\ \\ \\ \\/ /\\ \\/\\ \\ @@ -299,7 +329,7 @@ message(" ${DEBUG_REPORT}") message("${DASHED_LINE_SYMBOL}\nDependencies") -if (NOT "${CUDACOMP_VERSION}" STREQUAL "") +if(NOT "${CUDACOMP_VERSION}" STREQUAL "") message(" - CUDA:\tv${CUDACOMP_VERSION}") elseif(NOT "${ROCM_VERSION}" STREQUAL "") message(" - ROCm:\tv${ROCM_VERSION}") @@ -312,7 +342,8 @@ if(${HDF5_FOUND}) message(" - HDF5:\tv${HDF5_VERSION}") endif() -message("${DASHED_LINE_SYMBOL} +message( + "${DASHED_LINE_SYMBOL} Notes ${Dim}: Set flags with `cmake ... -D ${Magenta}${ColorReset}${Dim}=`, the ${Underline}default${ColorReset}${Dim} value : will be used unless the variable is explicitly set.${ColorReset} diff --git a/cmake/styling.cmake b/cmake/styling.cmake index fb9cfcc87..70c448fff 100644 --- a/cmake/styling.cmake +++ b/cmake/styling.cmake @@ -23,20 +23,17 @@ if(NOT WIN32) set(StrikeEnd "${Esc}[0m") endif() -# message("This is normal") -# message("${Red}This is Red${ColorReset}") -# message("${Green}This is Green${ColorReset}") -# message("${Yellow}This is Yellow${ColorReset}") -# message("${Blue}This is Blue${ColorReset}") -# message("${Magenta}This is Magenta${ColorReset}") -# message("${Cyan}This is Cyan${ColorReset}") -# message("${White}This is White${ColorReset}") -# message("${BoldRed}This is BoldRed${ColorReset}") -# message("${BoldGreen}This is BoldGreen${ColorReset}") -# message("${BoldYellow}This is BoldYellow${ColorReset}") -# message("${BoldBlue}This is BoldBlue${ColorReset}") +# message("This is normal") message("${Red}This is Red${ColorReset}") +# message("${Green}This is Green${ColorReset}") message("${Yellow}This is +# Yellow${ColorReset}") message("${Blue}This is Blue${ColorReset}") +# message("${Magenta}This is Magenta${ColorReset}") message("${Cyan}This is +# Cyan${ColorReset}") message("${White}This is White${ColorReset}") +# message("${BoldRed}This is BoldRed${ColorReset}") message("${BoldGreen}This is +# BoldGreen${ColorReset}") message("${BoldYellow}This is +# BoldYellow${ColorReset}") message("${BoldBlue}This is BoldBlue${ColorReset}") # message("${BoldMagenta}This is BoldMagenta${ColorReset}") -# message("${BoldCyan}This is BoldCyan${ColorReset}") -# message("${BoldWhite}This is BoldWhite\n\n${ColorReset}") +# message("${BoldCyan}This is BoldCyan${ColorReset}") message("${BoldWhite}This +# is BoldWhite\n\n${ColorReset}") + +# message() -# message() \ No newline at end of file diff --git a/cmake/tests.cmake b/cmake/tests.cmake index 643ac3d29..7820a5192 100644 --- a/cmake/tests.cmake +++ b/cmake/tests.cmake @@ -8,27 +8,36 @@ add_subdirectory(${SRC_DIR}/metrics ${CMAKE_CURRENT_BINARY_DIR}/metrics) add_subdirectory(${SRC_DIR}/kernels ${CMAKE_CURRENT_BINARY_DIR}/kernels) add_subdirectory(${SRC_DIR}/archetypes ${CMAKE_CURRENT_BINARY_DIR}/archetypes) add_subdirectory(${SRC_DIR}/framework ${CMAKE_CURRENT_BINARY_DIR}/framework) -if (${output}) +if(${output}) add_subdirectory(${SRC_DIR}/output ${CMAKE_CURRENT_BINARY_DIR}/output) add_subdirectory(${SRC_DIR}/checkpoint ${CMAKE_CURRENT_BINARY_DIR}/checkpoint) endif() -if (${mpi}) +if(${mpi}) # tests with mpi - if (${output}) - add_subdirectory(${SRC_DIR}/output/tests ${CMAKE_CURRENT_BINARY_DIR}/output/tests) - add_subdirectory(${SRC_DIR}/checkpoint/tests ${CMAKE_CURRENT_BINARY_DIR}/checkpoint/tests) - add_subdirectory(${SRC_DIR}/framework/tests ${CMAKE_CURRENT_BINARY_DIR}/framework/tests) + if(${output}) + add_subdirectory(${SRC_DIR}/output/tests + ${CMAKE_CURRENT_BINARY_DIR}/output/tests) + add_subdirectory(${SRC_DIR}/checkpoint/tests + ${CMAKE_CURRENT_BINARY_DIR}/checkpoint/tests) + add_subdirectory(${SRC_DIR}/framework/tests + ${CMAKE_CURRENT_BINARY_DIR}/framework/tests) endif() else() # tests without mpi - add_subdirectory(${SRC_DIR}/global/tests ${CMAKE_CURRENT_BINARY_DIR}/global/tests) - add_subdirectory(${SRC_DIR}/metrics/tests ${CMAKE_CURRENT_BINARY_DIR}/metrics/tests) - add_subdirectory(${SRC_DIR}/kernels/tests ${CMAKE_CURRENT_BINARY_DIR}/kernels/tests) - add_subdirectory(${SRC_DIR}/archetypes/tests ${CMAKE_CURRENT_BINARY_DIR}/archetypes/tests) - add_subdirectory(${SRC_DIR}/framework/tests ${CMAKE_CURRENT_BINARY_DIR}/framework/tests) - if (${output}) - add_subdirectory(${SRC_DIR}/output/tests ${CMAKE_CURRENT_BINARY_DIR}/output/tests) - add_subdirectory(${SRC_DIR}/checkpoint/tests ${CMAKE_CURRENT_BINARY_DIR}/checkpoint/tests) + add_subdirectory(${SRC_DIR}/global/ ${CMAKE_CURRENT_BINARY_DIR}/global/tests) + add_subdirectory(${SRC_DIR}/metrics/tests + ${CMAKE_CURRENT_BINARY_DIR}/metrics/tests) + add_subdirectory(${SRC_DIR}/kernels/tests + ${CMAKE_CURRENT_BINARY_DIR}/kernels/tests) + add_subdirectory(${SRC_DIR}/archetypes/tests + ${CMAKE_CURRENT_BINARY_DIR}/archetypes/tests) + add_subdirectory(${SRC_DIR}/framework/tests + ${CMAKE_CURRENT_BINARY_DIR}/framework/tests) + if(${output}) + add_subdirectory(${SRC_DIR}/output/tests + ${CMAKE_CURRENT_BINARY_DIR}/output/tests) + add_subdirectory(${SRC_DIR}/checkpoint/tests + ${CMAKE_CURRENT_BINARY_DIR}/checkpoint/tests) endif() endif() diff --git a/setups/CMakeLists.txt b/setups/CMakeLists.txt index b1753d7b8..c92c1d345 100644 --- a/setups/CMakeLists.txt +++ b/setups/CMakeLists.txt @@ -1,23 +1,25 @@ # ------------------------------ # @defines: ntt_pgen [INTERFACE] +# # @includes: -# - ../ +# +# * ../ +# # @depends: -# - ntt_pgen [required] +# +# * ntt_pgen [required] +# # @uses: -# - kokkos [required] -# - plog [required] -# - mpi [optional] +# +# * kokkos [required] +# * plog [required] +# * mpi [optional] # ------------------------------ add_library(ntt_pgen INTERFACE) -target_link_libraries(ntt_pgen INTERFACE - ntt_global - ntt_framework - ntt_archetypes - ntt_kernels -) +target_link_libraries(ntt_pgen INTERFACE ntt_global ntt_framework + ntt_archetypes ntt_kernels) target_include_directories(ntt_pgen - INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/${PGEN} -) \ No newline at end of file + INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/${PGEN}) + diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d75094c2b..a41b84900 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,27 +1,30 @@ # ------------------------------ # @defines: entity [STATIC/SHARED] +# # @sources: -# - entity.cpp +# +# * entity.cpp +# # @depends: -# - ntt_global [required] -# - ntt_framework [required] -# - ntt_metrics [required] -# - ntt_engine [required] -# - ntt_pgen [required] +# +# * ntt_global [required] +# * ntt_framework [required] +# * ntt_metrics [required] +# * ntt_engine [required] +# * ntt_pgen [required] +# # @uses: -# - kokkos [required] -# - plog [required] -# - toml11 [required] -# - ADIOS2 [optional] -# - mpi [optional] +# +# * kokkos [required] +# * plog [required] +# * toml11 [required] +# * ADIOS2 [optional] +# * mpi [optional] # ------------------------------ - set(ENTITY ${PROJECT_NAME}.xc) set(SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}) -set(SOURCES - ${SRC_DIR}/entity.cpp -) +set(SOURCES ${SRC_DIR}/entity.cpp) add_executable(${ENTITY} entity.cpp) # dependencies @@ -32,7 +35,7 @@ add_subdirectory(${SRC_DIR}/archetypes ${CMAKE_CURRENT_BINARY_DIR}/archetypes) add_subdirectory(${SRC_DIR}/framework ${CMAKE_CURRENT_BINARY_DIR}/framework) add_subdirectory(${SRC_DIR}/engines ${CMAKE_CURRENT_BINARY_DIR}/engines) -if (${output}) +if(${output}) add_subdirectory(${SRC_DIR}/output ${CMAKE_CURRENT_BINARY_DIR}/output) add_subdirectory(${SRC_DIR}/checkpoint ${CMAKE_CURRENT_BINARY_DIR}/checkpoint) endif() diff --git a/src/archetypes/CMakeLists.txt b/src/archetypes/CMakeLists.txt index 7883ba6a5..8e2f325af 100644 --- a/src/archetypes/CMakeLists.txt +++ b/src/archetypes/CMakeLists.txt @@ -1,13 +1,19 @@ # ------------------------------ # @defines: ntt_archetypes [INTERFACE] +# # @includes: -# - ../ +# +# * ../ +# # @depends: -# - ntt_global [required] -# - ntt_kernels [required] +# +# * ntt_global [required] +# * ntt_kernels [required] +# # @uses: -# - kokkos [required] -# - mpi [optional] +# +# * kokkos [required] +# * mpi [optional] # ------------------------------ add_library(ntt_archetypes INTERFACE) @@ -17,5 +23,5 @@ add_dependencies(ntt_archetypes ${libs}) target_link_libraries(ntt_archetypes INTERFACE ${libs}) target_include_directories(ntt_archetypes - INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/../ -) \ No newline at end of file + INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/../) + diff --git a/src/archetypes/tests/CMakeLists.txt b/src/archetypes/tests/CMakeLists.txt index 4ffc35322..694a6b4f9 100644 --- a/src/archetypes/tests/CMakeLists.txt +++ b/src/archetypes/tests/CMakeLists.txt @@ -1,9 +1,11 @@ # ------------------------------ # @brief: Generates tests for the `ntt_archetypes` module +# # @uses: -# - kokkos [required] -# - plog [required] -# - mpi [optional] +# +# * kokkos [required] +# * plog [required] +# * mpi [optional] # ------------------------------ set(SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../) diff --git a/src/checkpoint/CMakeLists.txt b/src/checkpoint/CMakeLists.txt index d97bd4a34..fa641bfb5 100644 --- a/src/checkpoint/CMakeLists.txt +++ b/src/checkpoint/CMakeLists.txt @@ -1,23 +1,28 @@ # ------------------------------ # @defines: ntt_checkpoint [STATIC/SHARED] +# # @sources: -# - writer.cpp -# - reader.cpp +# +# * writer.cpp +# * reader.cpp +# # @includes: -# - ../ +# +# * ../ +# # @depends: -# - ntt_global [required] +# +# * ntt_global [required] +# # @uses: -# - kokkos [required] -# - ADIOS2 [required] -# - mpi [optional] +# +# * kokkos [required] +# * ADIOS2 [required] +# * mpi [optional] # ------------------------------ set(SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}) -set(SOURCES - ${SRC_DIR}/writer.cpp - ${SRC_DIR}/reader.cpp -) +set(SOURCES ${SRC_DIR}/writer.cpp ${SRC_DIR}/reader.cpp) add_library(ntt_checkpoint ${SOURCES}) set(libs ntt_global) @@ -25,7 +30,7 @@ add_dependencies(ntt_checkpoint ${libs}) target_link_libraries(ntt_checkpoint PUBLIC ${libs}) target_link_libraries(ntt_checkpoint PRIVATE stdc++fs) -target_include_directories(ntt_checkpoint +target_include_directories( + ntt_checkpoint PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../ - INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/../ -) + INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/../) diff --git a/src/checkpoint/tests/CMakeLists.txt b/src/checkpoint/tests/CMakeLists.txt index 3d7475a52..10836554b 100644 --- a/src/checkpoint/tests/CMakeLists.txt +++ b/src/checkpoint/tests/CMakeLists.txt @@ -1,9 +1,11 @@ # ------------------------------ # @brief: Generates tests for the `ntt_checkpoint` module +# # @uses: -# - kokkos [required] -# - adios2 [required] -# - mpi [optional] +# +# * kokkos [required] +# * adios2 [required] +# * mpi [optional] # ------------------------------ set(SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../) @@ -13,14 +15,14 @@ function(gen_test title) set(src ${title}.cpp) add_executable(${exec} ${src}) - set (libs ntt_checkpoint ntt_global) + set(libs ntt_checkpoint ntt_global) add_dependencies(${exec} ${libs}) target_link_libraries(${exec} PRIVATE ${libs} stdc++fs) add_test(NAME "CHECKPOINT::${title}" COMMAND "${exec}") endfunction() -if (NOT ${mpi}) +if(NOT ${mpi}) gen_test(checkpoint-nompi) else() # gen_test(checkpoint-mpi) diff --git a/src/engines/CMakeLists.txt b/src/engines/CMakeLists.txt index 2ab7289b2..6da2f4efd 100644 --- a/src/engines/CMakeLists.txt +++ b/src/engines/CMakeLists.txt @@ -1,37 +1,43 @@ # ------------------------------ # @defines: ntt_engines [STATIC/SHARED] +# # @sources: -# - engine_printer.cpp -# - engine_init.cpp -# - engine_run.cpp +# +# * engine_printer.cpp +# * engine_init.cpp +# * engine_run.cpp +# # @includes: -# - ../ +# +# * ../ +# # @depends: -# - ntt_global [required] -# - ntt_framework [required] -# - ntt_metrics [required] -# - ntt_kernels [required] -# - ntt_archetypes [required] -# - ntt_pgen [required] -# - ntt_output [optional] +# +# * ntt_global [required] +# * ntt_framework [required] +# * ntt_metrics [required] +# * ntt_kernels [required] +# * ntt_archetypes [required] +# * ntt_pgen [required] +# * ntt_output [optional] +# # @uses: -# - kokkos [required] -# - plog [required] -# - toml11 [required] -# - adios2 [optional] -# - hdf5 [optional] -# - mpi [optional] +# +# * kokkos [required] +# * plog [required] +# * toml11 [required] +# * adios2 [optional] +# * hdf5 [optional] +# * mpi [optional] # ------------------------------ set(SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}) -set(SOURCES - ${SRC_DIR}/engine_printer.cpp - ${SRC_DIR}/engine_init.cpp - ${SRC_DIR}/engine_run.cpp -) +set(SOURCES ${SRC_DIR}/engine_printer.cpp ${SRC_DIR}/engine_init.cpp + ${SRC_DIR}/engine_run.cpp) add_library(ntt_engines ${SOURCES}) -set(libs ntt_global ntt_framework ntt_metrics ntt_archetypes ntt_kernels ntt_pgen) +set(libs ntt_global ntt_framework ntt_metrics ntt_archetypes ntt_kernels + ntt_pgen) if(${output}) list(APPEND libs ntt_output hdf5::hdf5) endif() @@ -39,7 +45,7 @@ add_dependencies(ntt_engines ${libs}) target_link_libraries(ntt_engines PUBLIC ${libs}) target_compile_definitions(ntt_engines PRIVATE PGEN=\"${PGEN}\") -target_include_directories(ntt_engines +target_include_directories( + ntt_engines PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../ - INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/../ -) + INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/../) diff --git a/src/framework/CMakeLists.txt b/src/framework/CMakeLists.txt index e01759d14..8802f696b 100644 --- a/src/framework/CMakeLists.txt +++ b/src/framework/CMakeLists.txt @@ -1,41 +1,48 @@ # ------------------------------ # @defines: ntt_framework [STATIC/SHARED] +# # @sources: -# - parameters.cpp -# - simulation.cpp -# - domain/grid.cpp -# - domain/metadomain.cpp -# - domain/communications.cpp -# - domain/checkpoint.cpp -# - containers/particles.cpp -# - containers/fields.cpp -# - domain/output.cpp +# +# * parameters.cpp +# * simulation.cpp +# * domain/grid.cpp +# * domain/metadomain.cpp +# * domain/communications.cpp +# * domain/checkpoint.cpp +# * containers/particles.cpp +# * containers/fields.cpp +# * domain/output.cpp +# # @includes: -# - ../ +# +# * ../ +# # @depends: -# - ntt_global [required] -# - ntt_metrics [required] -# - ntt_kernels [required] -# - ntt_output [optional] +# +# * ntt_global [required] +# * ntt_metrics [required] +# * ntt_kernels [required] +# * ntt_output [optional] +# # @uses: -# - kokkos [required] -# - plog [required] -# - toml11 [required] -# - ADIOS2 [optional] -# - mpi [optional] +# +# * kokkos [required] +# * plog [required] +# * toml11 [required] +# * ADIOS2 [optional] +# * mpi [optional] # ------------------------------ set(SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}) -set(SOURCES - ${SRC_DIR}/parameters.cpp - ${SRC_DIR}/simulation.cpp - ${SRC_DIR}/domain/grid.cpp - ${SRC_DIR}/domain/metadomain.cpp - ${SRC_DIR}/domain/communications.cpp - ${SRC_DIR}/containers/particles.cpp - ${SRC_DIR}/containers/fields.cpp -) -if (${output}) +set(SOURCES + ${SRC_DIR}/parameters.cpp + ${SRC_DIR}/simulation.cpp + ${SRC_DIR}/domain/grid.cpp + ${SRC_DIR}/domain/metadomain.cpp + ${SRC_DIR}/domain/communications.cpp + ${SRC_DIR}/containers/particles.cpp + ${SRC_DIR}/containers/fields.cpp) +if(${output}) list(APPEND SOURCES ${SRC_DIR}/domain/output.cpp) list(APPEND SOURCES ${SRC_DIR}/domain/checkpoint.cpp) endif() @@ -50,7 +57,7 @@ add_dependencies(ntt_framework ${libs}) target_link_libraries(ntt_framework PUBLIC ${libs}) target_link_libraries(ntt_framework PRIVATE stdc++fs) -target_include_directories(ntt_framework +target_include_directories( + ntt_framework PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../ - INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/../ -) + INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/../) diff --git a/src/framework/tests/CMakeLists.txt b/src/framework/tests/CMakeLists.txt index 56ad0783b..ce188e9f1 100644 --- a/src/framework/tests/CMakeLists.txt +++ b/src/framework/tests/CMakeLists.txt @@ -1,19 +1,23 @@ # ------------------------------ # @brief: Generates tests for the `ntt_framework` module +# # @uses: -# - kokkos [required] -# - plog [required] -# - toml11 [required] -# - mpi [optional] -# - adios2 [optional] +# +# * kokkos [required] +# * plog [required] +# * toml11 [required] +# * mpi [optional] +# * adios2 [optional] +# # !TODO: -# - add tests for mesh separately -# - add test for 3D metadomain +# +# * add tests for mesh separately +# * add test for 3D metadomain # ------------------------------ set(SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../) -function(gen_test title) +function(gen_test title is_parallel) set(exec test-framework-${title}.xc) set(src ${title}.cpp) add_executable(${exec} ${src}) @@ -22,24 +26,30 @@ function(gen_test title) add_dependencies(${exec} ${libs}) target_link_libraries(${exec} PRIVATE ${libs}) - add_test(NAME "FRAMEWORK::${title}" COMMAND "${exec}") + if(${is_parallel}) + add_test(NAME "FRAMEWORK::${title}" + COMMAND "${MPIEXEC_EXECUTABLE}" "${MPIEXEC_NUMPROC_FLAG}" "4" + "${exec}") + else() + add_test(NAME "FRAMEWORK::${title}" COMMAND "${exec}") + endif() endfunction() -if (${mpi}) - gen_test(comm_mpi) +if(${mpi}) + gen_test(comm_mpi true) else() - gen_test(parameters) - gen_test(particles) - gen_test(fields) - gen_test(grid_mesh) - if (${DEBUG}) - gen_test(metadomain) + gen_test(parameters false) + gen_test(particles false) + gen_test(fields false) + gen_test(grid_mesh false) + if(${DEBUG}) + gen_test(metadomain false) endif() - gen_test(comm_nompi) + gen_test(comm_nompi false) endif() - # this test is only run manually to ensure ... # ... command line args are working properly ... # ... and that the logging is done correctly -# gen_test(simulation) +# +# gen_test(simulation) diff --git a/src/global/CMakeLists.txt b/src/global/CMakeLists.txt index 334ce078d..97946f059 100644 --- a/src/global/CMakeLists.txt +++ b/src/global/CMakeLists.txt @@ -1,36 +1,38 @@ # ------------------------------ # @defines: ntt_global [STATIC/SHARED] +# # @sources: -# - global.cpp -# - arch/kokkos_aliases.cpp -# - utils/cargs.cpp -# - utils/param_container.cpp -# - utils/timer.cpp -# - utils/diag.cpp -# - utils/progressbar.cpp +# +# * global.cpp +# * arch/kokkos_aliases.cpp +# * utils/cargs.cpp +# * utils/param_container.cpp +# * utils/timer.cpp +# * utils/diag.cpp +# * utils/progressbar.cpp +# # @includes: -# - ./ +# +# * ./ +# # @uses: -# - kokkos [required] -# - plog [required] -# - mpi [optional] +# +# * kokkos [required] +# * plog [required] +# * mpi [optional] # ------------------------------ set(SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}) -set(SOURCES - ${SRC_DIR}/global.cpp - ${SRC_DIR}/arch/kokkos_aliases.cpp - ${SRC_DIR}/utils/cargs.cpp - ${SRC_DIR}/utils/timer.cpp - ${SRC_DIR}/utils/diag.cpp - ${SRC_DIR}/utils/progressbar.cpp -) -if (${output}) +set(SOURCES + ${SRC_DIR}/global.cpp ${SRC_DIR}/arch/kokkos_aliases.cpp + ${SRC_DIR}/utils/cargs.cpp ${SRC_DIR}/utils/timer.cpp + ${SRC_DIR}/utils/diag.cpp ${SRC_DIR}/utils/progressbar.cpp) +if(${output}) list(APPEND SOURCES ${SRC_DIR}/utils/param_container.cpp) endif() add_library(ntt_global ${SOURCES}) -target_include_directories(ntt_global +target_include_directories( + ntt_global PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} - INTERFACE ${CMAKE_CURRENT_SOURCE_DIR} -) + INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) target_link_libraries(ntt_global PRIVATE stdc++fs) diff --git a/src/global/tests/CMakeLists.txt b/src/global/tests/CMakeLists.txt index e9e5de687..e30da20a0 100644 --- a/src/global/tests/CMakeLists.txt +++ b/src/global/tests/CMakeLists.txt @@ -1,11 +1,15 @@ # ------------------------------ # @brief: Generates tests for the `ntt_global` module +# # @uses: -# - kokkos [required] -# - plog [required] -# - mpi [optional] +# +# * kokkos [required] +# * plog [required] +# * mpi [optional] +# # !TODO: -# - add optional tests for the `mpi_aliases.h` +# +# * add optional tests for the `mpi_aliases.h` # ------------------------------ set(SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../) diff --git a/src/kernels/CMakeLists.txt b/src/kernels/CMakeLists.txt index d24dff0a4..c8a1f409f 100644 --- a/src/kernels/CMakeLists.txt +++ b/src/kernels/CMakeLists.txt @@ -1,13 +1,19 @@ # ------------------------------ # @defines: ntt_kernels [INTERFACE] +# # @includes: -# - ../ +# +# * ../ +# # @depends: -# - ntt_global [required] +# +# * ntt_global [required] +# # @uses: -# - kokkos [required] -# - plog [required] -# - mpi [optional] +# +# * kokkos [required] +# * plog [required] +# * mpi [optional] # ------------------------------ add_library(ntt_kernels INTERFACE) @@ -17,5 +23,5 @@ add_dependencies(ntt_kernels ${libs}) target_link_libraries(ntt_kernels INTERFACE ${libs}) target_include_directories(ntt_kernels - INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/../ -) \ No newline at end of file + INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/../) + diff --git a/src/kernels/tests/CMakeLists.txt b/src/kernels/tests/CMakeLists.txt index e55dbc111..10e8bb944 100644 --- a/src/kernels/tests/CMakeLists.txt +++ b/src/kernels/tests/CMakeLists.txt @@ -1,9 +1,11 @@ # ------------------------------ # @brief: Generates tests for the `ntt_kernels` module +# # @uses: -# - kokkos [required] -# - plog [required] -# - mpi [optional] +# +# * kokkos [required] +# * plog [required] +# * mpi [optional] # ------------------------------ set(SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../) diff --git a/src/metrics/CMakeLists.txt b/src/metrics/CMakeLists.txt index 0f303fcfc..e053bb61c 100644 --- a/src/metrics/CMakeLists.txt +++ b/src/metrics/CMakeLists.txt @@ -1,11 +1,17 @@ # ------------------------------ # @defines: ntt_metrics [INTERFACE] +# # @includes: -# - ../ +# +# * ../ +# # @depends: -# - ntt_global [required] +# +# * ntt_global [required] +# # @uses: -# - kokkos [required] +# +# * kokkos [required] # ------------------------------ add_library(ntt_metrics INTERFACE) @@ -15,5 +21,5 @@ add_dependencies(ntt_metrics ${libs}) target_link_libraries(ntt_metrics INTERFACE ${libs}) target_include_directories(ntt_metrics - INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/../ -) \ No newline at end of file + INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/../) + diff --git a/src/metrics/tests/CMakeLists.txt b/src/metrics/tests/CMakeLists.txt index 117cb3295..c997ab079 100644 --- a/src/metrics/tests/CMakeLists.txt +++ b/src/metrics/tests/CMakeLists.txt @@ -1,9 +1,11 @@ # ------------------------------ # @brief: Generates tests for the `ntt_metrics` module +# # @uses: -# - kokkos [required] -# - plog [required] -# - mpi [optional] +# +# * kokkos [required] +# * plog [required] +# * mpi [optional] # ------------------------------ set(SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../) @@ -13,7 +15,7 @@ function(gen_test title) set(src ${title}.cpp) add_executable(${exec} ${src}) - set (libs ntt_metrics) + set(libs ntt_metrics) add_dependencies(${exec} ${libs}) target_link_libraries(${exec} PRIVATE ${libs}) @@ -25,4 +27,5 @@ gen_test(vec_trans) gen_test(coord_trans) gen_test(sph-qsph) gen_test(ks-qks) -gen_test(sr-cart-sph) \ No newline at end of file +gen_test(sr-cart-sph) + diff --git a/src/output/CMakeLists.txt b/src/output/CMakeLists.txt index 2c25631ec..e6dbcc03a 100644 --- a/src/output/CMakeLists.txt +++ b/src/output/CMakeLists.txt @@ -1,32 +1,37 @@ # ------------------------------ # @defines: ntt_output [STATIC/SHARED] +# # @sources: -# - writer.cpp -# - fields.cpp -# - utils/interpret_prompt.cpp +# +# * writer.cpp +# * fields.cpp +# * utils/interpret_prompt.cpp +# # @includes: -# - ../ +# +# * ../ +# # @depends: -# - ntt_global [required] +# +# * ntt_global [required] +# # @uses: -# - kokkos [required] -# - ADIOS2 [required] -# - mpi [optional] +# +# * kokkos [required] +# * ADIOS2 [required] +# * mpi [optional] # ------------------------------ set(SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}) -set(SOURCES - ${SRC_DIR}/writer.cpp - ${SRC_DIR}/fields.cpp - ${SRC_DIR}/utils/interpret_prompt.cpp -) +set(SOURCES ${SRC_DIR}/writer.cpp ${SRC_DIR}/fields.cpp + ${SRC_DIR}/utils/interpret_prompt.cpp) add_library(ntt_output ${SOURCES}) set(libs ntt_global) add_dependencies(ntt_output ${libs}) target_link_libraries(ntt_output PUBLIC ${libs}) -target_include_directories(ntt_output +target_include_directories( + ntt_output PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../ - INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/../ -) + INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/../) diff --git a/src/output/tests/CMakeLists.txt b/src/output/tests/CMakeLists.txt index 37af95fac..afc7950c4 100644 --- a/src/output/tests/CMakeLists.txt +++ b/src/output/tests/CMakeLists.txt @@ -1,28 +1,36 @@ # ------------------------------ # @brief: Generates tests for the `ntt_output` module +# # @uses: -# - kokkos [required] -# - mpi [optional] -# - adios2 [optional] +# +# * kokkos [required] +# * mpi [optional] +# * adios2 [optional] # ------------------------------ set(SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../) -function(gen_test title) +function(gen_test title is_parallel) set(exec test-output-${title}.xc) set(src ${title}.cpp) add_executable(${exec} ${src}) - set (libs ntt_output ntt_global ntt_metrics ntt_framework) + set(libs ntt_output ntt_global ntt_metrics ntt_framework) add_dependencies(${exec} ${libs}) target_link_libraries(${exec} PRIVATE ${libs} stdc++fs) - add_test(NAME "OUTPUT::${title}" COMMAND "${exec}") + if(${is_parallel}) + add_test(NAME "OUTPUT::${title}" + COMMAND "${MPIEXEC_EXECUTABLE}" "${MPIEXEC_NUMPROC_FLAG}" "4" + "${exec}") + else() + add_test(NAME "OUTPUT::${title}" COMMAND "${exec}") + endif() endfunction() -if (NOT ${mpi}) - gen_test(fields) - gen_test(writer-nompi) +if(NOT ${mpi}) + gen_test(fields false) + gen_test(writer-nompi false) else() - gen_test(writer-mpi) + gen_test(writer-mpi true) endif() From 8a6321b5309cce50bbe9b56c83736645fd24807c Mon Sep 17 00:00:00 2001 From: hayk Date: Mon, 4 Nov 2024 14:30:45 -0500 Subject: [PATCH 137/773] proper gh action (hopefully) --- .github/workflows/actions.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/actions.yml b/.github/workflows/actions.yml index 22f55d8be..3e0de8808 100644 --- a/.github/workflows/actions.yml +++ b/.github/workflows/actions.yml @@ -15,10 +15,9 @@ jobs: id: check_message run: | if git log -1 --pretty=%B | grep -q "RUNTEST"; then - echo "::set-output name=run_tests::true" + echo "run_tests=true" >> "$GITHUB_OUTPUT" else - echo "::set-output name=run_tests::false" - exit 1 + echo "run_tests=false" >> "$GITHUB_OUTPUT" fi tests: needs: check-commit From 50c7b9be966dd83183038fd14840fee2246f289f Mon Sep 17 00:00:00 2001 From: hayk Date: Mon, 4 Nov 2024 14:36:10 -0500 Subject: [PATCH 138/773] readme (RUNTEST) --- README.md | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index d6f4597f5..26ca92072 100644 --- a/README.md +++ b/README.md @@ -10,21 +10,23 @@ Our [detailed documentation](https://entity-toolkit.github.io/) includes everyth [![License](https://img.shields.io/badge/License-BSD%203--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause) -## Core developers (alphabetical) +## Lead developers -👀 __Yangyang Cai__ {[@StaticObserver](https://github.com/StaticObserver): GRPIC} +☕ __Hayk Hakobyan__ {[@haykh](https://github.com/haykh)} -💁‍♂️ __Alexander Chernoglazov__ {[@SChernoglazov](https://github.com/SChernoglazov): PIC} +🥔 __Jens Mahlmann__ {[@jmahlmann](https://github.com/jmahlmann)} -🍵 __Benjamin Crinquand__ {[@bcrinquand](https://github.com/bcrinquand): GRPIC, cubed-sphere} +💁‍♂️ __Alexander Chernoglazov__ {[@SChernoglazov](https://github.com/SChernoglazov)} -🧋 __Alisa Galishnikova__ {[@alisagk](https://github.com/alisagk): GRPIC} +🧋 __Alisa Galishnikova__ {[@alisagk](https://github.com/alisagk)} -☕ __Hayk Hakobyan__ {[@haykh](https://github.com/haykh): framework, PIC, GRPIC, cubed-sphere} +🐬 __Sasha Philippov__ {[@sashaph](https://github.com/sashaph)} -🥔 __Jens Mahlmann__ {[@jmahlmann](https://github.com/jmahlmann): framework, MPI, cubed-sphere} +## Contributors (alphabetical) -🐬 __Sasha Philippov__ {[@sashaph](https://github.com/sashaph): all-around} +👀 __Yangyang Cai__ {[@StaticObserver](https://github.com/StaticObserver): GRPIC} + +🍵 __Benjamin Crinquand__ {[@bcrinquand](https://github.com/bcrinquand): GRPIC, cubed-sphere} 🤷 __Arno Vanthieghem__ {[@vanthieg](https://github.com/vanthieg): framework, PIC} From 6cd75c105b19f64ee317daab60125ff4ea44ce30 Mon Sep 17 00:00:00 2001 From: hayk Date: Mon, 4 Nov 2024 14:43:30 -0500 Subject: [PATCH 139/773] minor issue in cmake (RUNTEST) --- cmake/tests.cmake | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cmake/tests.cmake b/cmake/tests.cmake index 7820a5192..ca8ee69c4 100644 --- a/cmake/tests.cmake +++ b/cmake/tests.cmake @@ -25,7 +25,8 @@ if(${mpi}) endif() else() # tests without mpi - add_subdirectory(${SRC_DIR}/global/ ${CMAKE_CURRENT_BINARY_DIR}/global/tests) + add_subdirectory(${SRC_DIR}/global/tests + ${CMAKE_CURRENT_BINARY_DIR}/global/tests) add_subdirectory(${SRC_DIR}/metrics/tests ${CMAKE_CURRENT_BINARY_DIR}/metrics/tests) add_subdirectory(${SRC_DIR}/kernels/tests From 727eb1eff09315129acb0e72e81a2d1969554faa Mon Sep 17 00:00:00 2001 From: hayk Date: Mon, 4 Nov 2024 14:54:43 -0500 Subject: [PATCH 140/773] test fixed (RUNTEST) --- src/metrics/tests/sr-cart-sph.cpp | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/metrics/tests/sr-cart-sph.cpp b/src/metrics/tests/sr-cart-sph.cpp index ec2f6ddc0..42aa5d639 100644 --- a/src/metrics/tests/sr-cart-sph.cpp +++ b/src/metrics/tests/sr-cart-sph.cpp @@ -123,30 +123,30 @@ auto main(int argc, char* argv[]) -> int { const auto res2d = std::vector { 64, 32 }; const auto res3d = std::vector { 64, 32, 16 }; const auto ext1dcart = boundaries_t { - {10.0, 20.0} + { 10.0, 20.0 } }; const auto ext2dcart = boundaries_t { - {0.0, 20.0}, - {0.0, 10.0} + { 0.0, 20.0 }, + { 0.0, 10.0 } }; const auto ext3dcart = boundaries_t { - {-2.0, 2.0}, - {-1.0, 1.0}, - {-0.5, 0.5} + { -2.0, 2.0 }, + { -1.0, 1.0 }, + { -0.5, 0.5 } }; const auto extsph = boundaries_t { - {1.0, 10.0}, - {0.0, constant::PI} + { 1.0, 10.0 }, + { 0.0, constant::PI } }; const auto params = std::map { - {"r0", -ONE}, - { "h", (real_t)0.25} + { "r0", -ONE }, + { "h", (real_t)0.25 } }; testMetric>({ 128 }, ext1dcart); testMetric>(res2d, ext2dcart, 200); testMetric>(res3d, ext3dcart, 500); - testMetric>(res2d, extsph, 10); + testMetric>(res2d, extsph, 100); testMetric>(res2d, extsph, 200, params); } catch (std::exception& e) { From 6bdbeb93806f21a8ca8eede8a70312a988f4dc4c Mon Sep 17 00:00:00 2001 From: hayk Date: Mon, 4 Nov 2024 16:56:12 -0500 Subject: [PATCH 141/773] issues in writer tests (RUNTEST) --- .github/workflows/actions.yml | 2 +- dev/runners/Dockerfile.runner.cpu | 6 +++--- src/output/tests/writer-mpi.cpp | 4 ++-- src/output/tests/writer-nompi.cpp | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/actions.yml b/.github/workflows/actions.yml index 3e0de8808..f60ee9061 100644 --- a/.github/workflows/actions.yml +++ b/.github/workflows/actions.yml @@ -48,7 +48,7 @@ jobs: elif [ "${{ matrix.device }}" = "amd-gpu" ]; then FLAGS="-D Kokkos_ENABLE_HIP=ON -D Kokkos_ARCH_AMD_GFX1100=ON" elif [ "${{ matrix.device }}" = "cpu" ]; then - FLAGS="" + FLAGS="-D mpi=ON" fi cmake -B build -D TESTS=ON -D output=ON -D precision=${{ matrix.precision }} $FLAGS - name: Compile diff --git a/dev/runners/Dockerfile.runner.cpu b/dev/runners/Dockerfile.runner.cpu index fc13ec9b5..3c2cf4926 100644 --- a/dev/runners/Dockerfile.runner.cpu +++ b/dev/runners/Dockerfile.runner.cpu @@ -7,14 +7,14 @@ RUN apt-get update && apt-get upgrade -y # cmake & build tools RUN apt-get remove -y --purge cmake && \ - apt-get install -y sudo wget curl build-essential && \ + apt-get install -y sudo wget curl build-essential openmpi-bin openmpi-common libopenmpi-dev && \ wget "https://github.com/Kitware/CMake/releases/download/v3.29.6/cmake-3.29.6-linux-x86_64.tar.gz" -P /opt && \ tar xvf /opt/cmake-3.29.6-linux-x86_64.tar.gz -C /opt && \ rm /opt/cmake-3.29.6-linux-x86_64.tar.gz ENV PATH=/opt/cmake-3.29.6-linux-x86_64/bin:$PATH # adios2 -RUN apt-get update && apt-get install -y git libhdf5-dev && \ +RUN apt-get update && apt-get install -y git libhdf5-openmpi-dev && \ git clone https://github.com/ornladios/ADIOS2.git /opt/adios2-src && \ cd /opt/adios2-src && \ cmake -B build \ @@ -28,7 +28,7 @@ RUN apt-get update && apt-get install -y git libhdf5-dev && \ -D ADIOS2_USE_ZeroMQ=OFF \ -D BUILD_TESTING=OFF \ -D ADIOS2_BUILD_EXAMPLES=OFF \ - -D ADIOS2_USE_MPI=OFF \ + -D ADIOS2_USE_MPI=ON \ -D ADIOS2_HAVE_HDF5_VOL=OFF \ -D CMAKE_INSTALL_PREFIX=/opt/adios2 && \ cmake --build build -j && \ diff --git a/src/output/tests/writer-mpi.cpp b/src/output/tests/writer-mpi.cpp index c2729f658..5a5ae8007 100644 --- a/src/output/tests/writer-mpi.cpp +++ b/src/output/tests/writer-mpi.cpp @@ -100,8 +100,8 @@ auto main(int argc, char* argv[]) -> int { std::size_t step_read; long double time_read; - reader.Get(io.InquireVariable("Step"), step_read); - reader.Get(io.InquireVariable("Time"), time_read); + reader.Get(io.InquireVariable("Step"), &step_read); + reader.Get(io.InquireVariable("Time"), &time_read); raise::ErrorIf(step_read != step, "Step is not correct", HERE); raise::ErrorIf((float)time_read != (float)step * 0.1f, "Time is not correct", diff --git a/src/output/tests/writer-nompi.cpp b/src/output/tests/writer-nompi.cpp index 3fe42bf1b..803f907e8 100644 --- a/src/output/tests/writer-nompi.cpp +++ b/src/output/tests/writer-nompi.cpp @@ -111,8 +111,8 @@ auto main(int argc, char* argv[]) -> int { std::size_t step_read; long double time_read; - reader.Get(io.InquireVariable("Step"), step_read); - reader.Get(io.InquireVariable("Time"), time_read); + reader.Get(io.InquireVariable("Step"), &step_read); + reader.Get(io.InquireVariable("Time"), &time_read); raise::ErrorIf(step_read != (step + 1) * 10, "Step is not correct", HERE); raise::ErrorIf((float)time_read != 123 + (float)step * 0.4f, "Time is not correct", From cdd3e8717735c43a34ecae4227886693a0ae69a1 Mon Sep 17 00:00:00 2001 From: hayk Date: Mon, 4 Nov 2024 17:10:28 -0500 Subject: [PATCH 142/773] writer test -> Sync (RUNTEST) --- src/output/tests/writer-mpi.cpp | 8 ++++++-- src/output/tests/writer-nompi.cpp | 8 ++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/output/tests/writer-mpi.cpp b/src/output/tests/writer-mpi.cpp index 5a5ae8007..c6f5e5a09 100644 --- a/src/output/tests/writer-mpi.cpp +++ b/src/output/tests/writer-mpi.cpp @@ -100,8 +100,12 @@ auto main(int argc, char* argv[]) -> int { std::size_t step_read; long double time_read; - reader.Get(io.InquireVariable("Step"), &step_read); - reader.Get(io.InquireVariable("Time"), &time_read); + reader.Get(io.InquireVariable("Step"), + &step_read, + adios2::Mode::Sync); + reader.Get(io.InquireVariable("Time"), + &time_read, + adios2::Mode::Sync); raise::ErrorIf(step_read != step, "Step is not correct", HERE); raise::ErrorIf((float)time_read != (float)step * 0.1f, "Time is not correct", diff --git a/src/output/tests/writer-nompi.cpp b/src/output/tests/writer-nompi.cpp index 803f907e8..ee93202b9 100644 --- a/src/output/tests/writer-nompi.cpp +++ b/src/output/tests/writer-nompi.cpp @@ -111,8 +111,12 @@ auto main(int argc, char* argv[]) -> int { std::size_t step_read; long double time_read; - reader.Get(io.InquireVariable("Step"), &step_read); - reader.Get(io.InquireVariable("Time"), &time_read); + reader.Get(io.InquireVariable("Step"), + &step_read, + adios2::Mode::Sync); + reader.Get(io.InquireVariable("Time"), + &time_read, + adios2::Mode::Sync); raise::ErrorIf(step_read != (step + 1) * 10, "Step is not correct", HERE); raise::ErrorIf((float)time_read != 123 + (float)step * 0.4f, "Time is not correct", From 3c793cdd31c04035be3a20106a98a7d49a77be53 Mon Sep 17 00:00:00 2001 From: hayk Date: Mon, 4 Nov 2024 17:19:06 -0500 Subject: [PATCH 143/773] added flushall to tests (RUNTEST) --- src/output/tests/writer-mpi.cpp | 2 ++ src/output/tests/writer-nompi.cpp | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/output/tests/writer-mpi.cpp b/src/output/tests/writer-mpi.cpp index c6f5e5a09..6ab16305f 100644 --- a/src/output/tests/writer-mpi.cpp +++ b/src/output/tests/writer-mpi.cpp @@ -84,6 +84,8 @@ auto main(int argc, char* argv[]) -> int { adios.ExitComputationBlock(); } + adios.FlushAll(); + { // read adios2::IO io = adios.DeclareIO("read-test"); diff --git a/src/output/tests/writer-nompi.cpp b/src/output/tests/writer-nompi.cpp index ee93202b9..d22881741 100644 --- a/src/output/tests/writer-nompi.cpp +++ b/src/output/tests/writer-nompi.cpp @@ -93,6 +93,8 @@ auto main(int argc, char* argv[]) -> int { writer.endWriting(); } + adios.FlushAll(); + { // read adios2::IO io = adios.DeclareIO("read-test"); From c18162d9e04ed366895da4905653b45d0e3473f7 Mon Sep 17 00:00:00 2001 From: haykh Date: Mon, 4 Nov 2024 18:09:55 -0500 Subject: [PATCH 144/773] correct layout in tests (RUNTEST) --- src/output/tests/writer-nompi.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/output/tests/writer-nompi.cpp b/src/output/tests/writer-nompi.cpp index d22881741..08200d804 100644 --- a/src/output/tests/writer-nompi.cpp +++ b/src/output/tests/writer-nompi.cpp @@ -100,6 +100,8 @@ auto main(int argc, char* argv[]) -> int { adios2::IO io = adios.DeclareIO("read-test"); io.SetEngine("hdf5"); adios2::Engine reader = io.Open("test.h5", adios2::Mode::Read); + const auto layoutRight = io.InquireAttribute("LayoutRight").Data()[0] == + 1; raise::ErrorIf(io.InquireAttribute("NGhosts").Data()[0] != 0, "NGhosts is not correct", @@ -138,6 +140,9 @@ auto main(int argc, char* argv[]) -> int { std::size_t nx1_r = dims[0]; std::size_t nx2_r = dims[1]; std::size_t nx3_r = dims[2]; + if (!layoutRight) { + std::swap(nx1_r, nx3_r); + } raise::ErrorIf((nx1_r != CEILDIV(nx1, dwn1)) || (nx2_r != CEILDIV(nx2, dwn2)) || (nx3_r != CEILDIV(nx3, dwn3)), @@ -151,8 +156,14 @@ auto main(int argc, char* argv[]) -> int { CEILDIV(nx3, dwn3)), HERE); + if (!layoutRight) { + std::swap(nx1_r, nx3_r); + } fieldVar.SetSelection( adios2::Box({ 0, 0, 0 }, { nx1_r, nx2_r, nx3_r })); + if (!layoutRight) { + std::swap(nx1_r, nx3_r); + } field_read = array_t(name, nx1_r, nx2_r, nx3_r); auto field_read_h = Kokkos::create_mirror_view(field_read); reader.Get(fieldVar, field_read_h.data(), adios2::Mode::Sync); From 96a295c62ed9ab8d1a5a5337b851cfc419869534 Mon Sep 17 00:00:00 2001 From: haykh Date: Mon, 29 Jul 2024 09:56:03 -0400 Subject: [PATCH 145/773] patch for mpich send buffr --- src/framework/domain/metadomain.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/framework/domain/metadomain.cpp b/src/framework/domain/metadomain.cpp index 5e66bc366..ca52a53cf 100644 --- a/src/framework/domain/metadomain.cpp +++ b/src/framework/domain/metadomain.cpp @@ -381,7 +381,7 @@ namespace ntt { #if defined(MPI_ENABLED) auto dx_mins = std::vector(g_ndomains); dx_mins[g_mpi_rank] = dx_min; - MPI_Allgather(&dx_mins[g_mpi_rank], + MPI_Allgather(&dx_min, 1, mpi::get_type(), dx_mins.data(), From 2344629a5210d54294cea1e35dfc0e1eae682b90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20B=C3=B6ss?= Date: Sat, 3 Aug 2024 14:54:47 -0500 Subject: [PATCH 146/773] initial commit: modification to shock pgen to run magnetized shocks --- setups/srpic/shock/pgen.hpp | 57 ++++++++++++++++++++++++++++++++--- setups/srpic/shock/shock.toml | 4 +++ 2 files changed, 57 insertions(+), 4 deletions(-) diff --git a/setups/srpic/shock/pgen.hpp b/setups/srpic/shock/pgen.hpp index f07b99878..4a9cc3f09 100644 --- a/setups/srpic/shock/pgen.hpp +++ b/setups/srpic/shock/pgen.hpp @@ -14,6 +14,47 @@ namespace user { using namespace ntt; + template + struct InitFields + { + InitFields(real_t bmag, real_t btheta, real_t bphi, real_t bbeta) : + Bmag { bmag }, Btheta { btheta }, Bphi { bphi }, Bbeta { bbeta } {} + + // alternative: initialize magnetisation from simulation parameters as in Tristan? + // Bmag = math::sqrt(ppc0 * 0.5 * c * c * me * sigma); + + // magnetic field components + Inline auto bx1(const coord_t &x_Ph) const -> real_t + { + return Bmag * math::cos(Btheta / 180.0 * Kokkos::numbers::pi); + } + Inline auto bx2(const coord_t &x_Ph) const -> real_t + { + return Bmag * math::sin(Btheta / 180.0 * Kokkos::numbers::pi) * math::sin(Bphi / 180.0 * Kokkos::numbers::pi); + } + Inline auto bx3(const coord_t &x_Ph) const -> real_t + { + return Bmag * math::sin(Btheta / 180.0 * Kokkos::numbers::pi) * math::cos(Bphi / 180.0 * Kokkos::numbers::pi); + } + + // electric field components + Inline auto ex1(const coord_t &x_Ph) const -> real_t + { + return ZERO; + } + Inline auto ex2(const coord_t &x_Ph) const -> real_t + { + return -Bbeta * Bmag * math::sin(Btheta / 180.0 * Kokkos::numbers::pi) * math::cos(Bphi / 180.0 * Kokkos::numbers::pi); + } + Inline auto ex3(const coord_t &x_Ph) const -> real_t + { + return -Bbeta * Bmag * math::sin(Btheta / 180.0 * Kokkos::numbers::pi) * math::sin(Bphi / 180.0 * Kokkos::numbers::pi); + } + + private: + const real_t Btheta, Bphi, Bbeta, Bmag; + }; + template struct PGen : public arch::ProblemGenerator { // compatibility traits for the problem generator @@ -30,10 +71,18 @@ namespace user { const real_t drift_ux, temperature; - inline PGen(const SimulationParams& p, const Metadomain& m) - : arch::ProblemGenerator(p) - , drift_ux { p.template get("setup.drift_ux") } - , temperature { p.template get("setup.temperature") } {} + const real_t Btheta, Bphi, Bbeta, Bmag; + InitFields init_flds; + + inline PGen(const SimulationParams &p, const Metadomain &m) + : arch::ProblemGenerator { p } + , drift_ux { p.template get("setup.drift_ux") } + , temperature { p.template get("setup.temperature") } + , Bmag { p.template get("setup.Bmag", 0.0) } + , Btheta { p.template get("setup.Btheta", 0.0) } + , Bphi { p.template get("setup.Bphi", 0.0) } + , Bbeta { p.template get("setup.Bbeta", 0.0) } + , init_flds { Bmag, Btheta, Bphi, Bbeta } {} inline PGen() {} diff --git a/setups/srpic/shock/shock.toml b/setups/srpic/shock/shock.toml index f48edb2d6..90571631e 100644 --- a/setups/srpic/shock/shock.toml +++ b/setups/srpic/shock/shock.toml @@ -42,6 +42,10 @@ [setup] drift_ux = 0.1 temperature = 1e-3 + Bmag = 0.0 + Btheta = 0.0 + Bphi = 0.0 + Bbeta = 0.0 [output] interval_time = 0.1 From a5f3485eb9e7f0cddeb45c3e6ebd032c72f1a7fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20B=C3=B6ss?= Date: Thu, 5 Sep 2024 15:34:22 -0500 Subject: [PATCH 147/773] fix misunderstanding in setup --- setups/srpic/shock/pgen.hpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/setups/srpic/shock/pgen.hpp b/setups/srpic/shock/pgen.hpp index 4a9cc3f09..c3771cde2 100644 --- a/setups/srpic/shock/pgen.hpp +++ b/setups/srpic/shock/pgen.hpp @@ -17,8 +17,8 @@ namespace user { template struct InitFields { - InitFields(real_t bmag, real_t btheta, real_t bphi, real_t bbeta) : - Bmag { bmag }, Btheta { btheta }, Bphi { bphi }, Bbeta { bbeta } {} + InitFields(real_t bmag, real_t btheta, real_t bphi, real_t drift_ux) : + Bmag { bmag }, Btheta { btheta }, Bphi { bphi }, Vx { drift_ux } {} // alternative: initialize magnetisation from simulation parameters as in Tristan? // Bmag = math::sqrt(ppc0 * 0.5 * c * c * me * sigma); @@ -44,15 +44,15 @@ namespace user { } Inline auto ex2(const coord_t &x_Ph) const -> real_t { - return -Bbeta * Bmag * math::sin(Btheta / 180.0 * Kokkos::numbers::pi) * math::cos(Bphi / 180.0 * Kokkos::numbers::pi); + return -Vx * Bmag * math::sin(Btheta / 180.0 * Kokkos::numbers::pi) * math::cos(Bphi / 180.0 * Kokkos::numbers::pi); } Inline auto ex3(const coord_t &x_Ph) const -> real_t { - return -Bbeta * Bmag * math::sin(Btheta / 180.0 * Kokkos::numbers::pi) * math::sin(Bphi / 180.0 * Kokkos::numbers::pi); + return -Vx * Bmag * math::sin(Btheta / 180.0 * Kokkos::numbers::pi) * math::sin(Bphi / 180.0 * Kokkos::numbers::pi); } private: - const real_t Btheta, Bphi, Bbeta, Bmag; + const real_t Btheta, Bphi, Vx, Bmag; }; template @@ -71,7 +71,7 @@ namespace user { const real_t drift_ux, temperature; - const real_t Btheta, Bphi, Bbeta, Bmag; + const real_t Btheta, Bphi, Bmag; InitFields init_flds; inline PGen(const SimulationParams &p, const Metadomain &m) @@ -81,8 +81,7 @@ namespace user { , Bmag { p.template get("setup.Bmag", 0.0) } , Btheta { p.template get("setup.Btheta", 0.0) } , Bphi { p.template get("setup.Bphi", 0.0) } - , Bbeta { p.template get("setup.Bbeta", 0.0) } - , init_flds { Bmag, Btheta, Bphi, Bbeta } {} + , init_flds { Bmag, Btheta, Bphi, drift_ux } {} inline PGen() {} From 6eb034f3e1637eb4f5e0d1c82747045c7a4ad8ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20B=C3=B6ss?= Date: Wed, 11 Sep 2024 14:07:43 -0500 Subject: [PATCH 148/773] fix sign error --- setups/srpic/shock/pgen.hpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/setups/srpic/shock/pgen.hpp b/setups/srpic/shock/pgen.hpp index c3771cde2..1194e7fed 100644 --- a/setups/srpic/shock/pgen.hpp +++ b/setups/srpic/shock/pgen.hpp @@ -20,9 +20,6 @@ namespace user { InitFields(real_t bmag, real_t btheta, real_t bphi, real_t drift_ux) : Bmag { bmag }, Btheta { btheta }, Bphi { bphi }, Vx { drift_ux } {} - // alternative: initialize magnetisation from simulation parameters as in Tristan? - // Bmag = math::sqrt(ppc0 * 0.5 * c * c * me * sigma); - // magnetic field components Inline auto bx1(const coord_t &x_Ph) const -> real_t { @@ -44,7 +41,7 @@ namespace user { } Inline auto ex2(const coord_t &x_Ph) const -> real_t { - return -Vx * Bmag * math::sin(Btheta / 180.0 * Kokkos::numbers::pi) * math::cos(Bphi / 180.0 * Kokkos::numbers::pi); + return Vx * Bmag * math::sin(Btheta / 180.0 * Kokkos::numbers::pi) * math::cos(Bphi / 180.0 * Kokkos::numbers::pi); } Inline auto ex3(const coord_t &x_Ph) const -> real_t { From 9d1b39b03a909fe3f7c234e85e1c43b7d6226ce3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20B=C3=B6ss?= Date: Wed, 11 Sep 2024 14:13:54 -0500 Subject: [PATCH 149/773] Added comment for `InitFields` --- setups/srpic/shock/pgen.hpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/setups/srpic/shock/pgen.hpp b/setups/srpic/shock/pgen.hpp index 1194e7fed..715c222df 100644 --- a/setups/srpic/shock/pgen.hpp +++ b/setups/srpic/shock/pgen.hpp @@ -16,7 +16,16 @@ namespace user { template struct InitFields - { + { + /* + Sets up magnetic and electric field components for the simulation. + Must satisfy E = -v x B for Lorentz Force to be zero. + + @param bmag: magnetic field scaling + @param btheta: magnetic field polar angle + @param bphi: magnetic field azimuthal angle + @param drift_ux: drift velocity in the x direction + */ InitFields(real_t bmag, real_t btheta, real_t bphi, real_t drift_ux) : Bmag { bmag }, Btheta { btheta }, Bphi { bphi }, Vx { drift_ux } {} From 037c705a2c11649713e7b81e33778e37fdddc85c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20B=C3=B6ss?= Date: Mon, 23 Sep 2024 11:25:57 -0500 Subject: [PATCH 150/773] fix signs (again) --- setups/srpic/shock/pgen.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setups/srpic/shock/pgen.hpp b/setups/srpic/shock/pgen.hpp index 715c222df..1fdd18faa 100644 --- a/setups/srpic/shock/pgen.hpp +++ b/setups/srpic/shock/pgen.hpp @@ -50,11 +50,11 @@ namespace user { } Inline auto ex2(const coord_t &x_Ph) const -> real_t { - return Vx * Bmag * math::sin(Btheta / 180.0 * Kokkos::numbers::pi) * math::cos(Bphi / 180.0 * Kokkos::numbers::pi); + return -Vx * Bmag * math::sin(Btheta / 180.0 * Kokkos::numbers::pi) * math::cos(Bphi / 180.0 * Kokkos::numbers::pi); } Inline auto ex3(const coord_t &x_Ph) const -> real_t { - return -Vx * Bmag * math::sin(Btheta / 180.0 * Kokkos::numbers::pi) * math::sin(Bphi / 180.0 * Kokkos::numbers::pi); + return Vx * Bmag * math::sin(Btheta / 180.0 * Kokkos::numbers::pi) * math::sin(Bphi / 180.0 * Kokkos::numbers::pi); } private: From a613d0aa43bf932bf43e756d1a96c080ab9676b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20B=C3=B6ss?= Date: Mon, 23 Sep 2024 11:37:27 -0500 Subject: [PATCH 151/773] removed redundant parameter and added comments --- setups/srpic/shock/shock.toml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/setups/srpic/shock/shock.toml b/setups/srpic/shock/shock.toml index 90571631e..e475ae097 100644 --- a/setups/srpic/shock/shock.toml +++ b/setups/srpic/shock/shock.toml @@ -42,10 +42,9 @@ [setup] drift_ux = 0.1 temperature = 1e-3 - Bmag = 0.0 - Btheta = 0.0 - Bphi = 0.0 - Bbeta = 0.0 + Bmag = 0.0 # set to 1.0 if magnetized shock is required + Btheta = 0.0 # magnetic field polar angle + Bphi = 0.0 # magnetic field azimuthal angle [output] interval_time = 0.1 From 31a7d5b1105fdec1ebc48f4623b3a85fbf5513e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20B=C3=B6ss?= Date: Wed, 2 Oct 2024 10:10:44 -0500 Subject: [PATCH 152/773] added atmosphere bc to enforce initial magnetic field config at the boundaries --- setups/srpic/shock/pgen.hpp | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/setups/srpic/shock/pgen.hpp b/setups/srpic/shock/pgen.hpp index 1fdd18faa..999a7b608 100644 --- a/setups/srpic/shock/pgen.hpp +++ b/setups/srpic/shock/pgen.hpp @@ -57,9 +57,25 @@ namespace user { return Vx * Bmag * math::sin(Btheta / 180.0 * Kokkos::numbers::pi) * math::sin(Bphi / 180.0 * Kokkos::numbers::pi); } - private: - const real_t Btheta, Bphi, Vx, Bmag; - }; + private: + const real_t Btheta, Bphi, Vx, Bmag; + }; + + template + struct DriveFields : public InitFields { + DriveFields(real_t bmag, real_t btheta, real_t bphi, real_t drift_ux) : + InitFields {bmag, btheta, bphi, drift_ux} {} + + /* Enforce resetting magnetic and electric field at the boundary + This avoids weird */ + using InitFields::bx1; + using InitFields::bx2; + using InitFields::bx3; + + using InitFields::ex1; + using InitFields::ex2; + using InitFields::ex3; + }; template struct PGen : public arch::ProblemGenerator { @@ -91,6 +107,14 @@ namespace user { inline PGen() {} + auto FieldDriver(real_t time) const -> DriveFields { + const real_t bmag = Bmag; + const real_t btheta = Btheta; + const real_t bphi = Bphi; + const real_t ux = drift_ux; + return DriveFields{bmag, btheta, bphi, ux}; + } + inline void InitPrtls(Domain& local_domain) { const auto energy_dist = arch::Maxwellian(local_domain.mesh.metric, local_domain.random_pool, From 78412c85f7b20b592a6919679d747f5711aaf762 Mon Sep 17 00:00:00 2001 From: hayk Date: Mon, 4 Nov 2024 21:10:04 -0500 Subject: [PATCH 153/773] changed FieldBC to FIXED --- .gitignore | 1 + input.example.toml | 4 +- setups/srpic/magnetar/magnetar.toml | 2 +- setups/srpic/magnetosphere/magnetosphere.toml | 2 +- setups/srpic/monopole/monopole.toml | 2 +- setups/srpic/shock/pgen.hpp | 143 +++++++++--------- setups/srpic/shock/shock.py | 4 +- setups/srpic/shock/shock.toml | 8 +- src/engines/srpic.hpp | 40 +++-- src/global/enums.h | 32 ++-- src/global/utils/numeric.h | 4 + src/kernels/fields_bcs.hpp | 12 +- 12 files changed, 127 insertions(+), 127 deletions(-) diff --git a/.gitignore b/.gitignore index a1b05e751..9a167b9d5 100644 --- a/.gitignore +++ b/.gitignore @@ -51,6 +51,7 @@ venv/ # CMake testing files Testing/ +tags .clangd .schema.json *_old/ diff --git a/input.example.toml b/input.example.toml index 5ee34d65d..e541f6e2b 100644 --- a/input.example.toml +++ b/input.example.toml @@ -90,10 +90,10 @@ # Boundary conditions for fields: # @required # @type: 1/2/3-size array of string tuples, each of size 1 or 2 - # @valid: "PERIODIC", "ABSORB", "ATMOSPHERE", "CUSTOM", "HORIZON" + # @valid: "PERIODIC", "ABSORB", "FIXED", "CUSTOM", "HORIZON" # @example: [["CUSTOM", "ABSORB"]] (for 2D spherical [[rmin, rmax]]) # @note: When periodic in any of the directions, you should only set one value [..., ["PERIODIC"], ...] - # @note: In spherical, bondaries in theta/phi are set automatically (only specify bc @ [rmin, rmax]) [["ATMOSPHERE", "ABSORB"]] + # @note: In spherical, bondaries in theta/phi are set automatically (only specify bc @ [rmin, rmax]) [["FIXED", "ABSORB"]] # @note: In GR, the horizon boundary is set automatically (only specify bc @ rmax): [["ABSORB"]] fields = "" # Boundary conditions for fields: diff --git a/setups/srpic/magnetar/magnetar.toml b/setups/srpic/magnetar/magnetar.toml index 2a2260af5..cd9ff5695 100644 --- a/setups/srpic/magnetar/magnetar.toml +++ b/setups/srpic/magnetar/magnetar.toml @@ -11,7 +11,7 @@ metric = "qspherical" [grid.boundaries] - fields = [["ATMOSPHERE", "ABSORB"]] + fields = [["FIXED", "ABSORB"]] particles = [["ATMOSPHERE", "ABSORB"]] [grid.boundaries.absorb] diff --git a/setups/srpic/magnetosphere/magnetosphere.toml b/setups/srpic/magnetosphere/magnetosphere.toml index 34e04b02d..83ade6e48 100644 --- a/setups/srpic/magnetosphere/magnetosphere.toml +++ b/setups/srpic/magnetosphere/magnetosphere.toml @@ -11,7 +11,7 @@ metric = "qspherical" [grid.boundaries] - fields = [["ATMOSPHERE", "ABSORB"]] + fields = [["FIXED", "ABSORB"]] particles = [["ATMOSPHERE", "ABSORB"]] [grid.boundaries.absorb] diff --git a/setups/srpic/monopole/monopole.toml b/setups/srpic/monopole/monopole.toml index 169837489..322c15dd4 100644 --- a/setups/srpic/monopole/monopole.toml +++ b/setups/srpic/monopole/monopole.toml @@ -11,7 +11,7 @@ metric = "qspherical" [grid.boundaries] - fields = [["ATMOSPHERE", "ABSORB"]] + fields = [["FIXED", "ABSORB"]] particles = [["ATMOSPHERE", "ABSORB"]] [grid.boundaries.absorb] diff --git a/setups/srpic/shock/pgen.hpp b/setups/srpic/shock/pgen.hpp index 999a7b608..30929383f 100644 --- a/setups/srpic/shock/pgen.hpp +++ b/setups/srpic/shock/pgen.hpp @@ -5,6 +5,7 @@ #include "global.h" #include "arch/traits.h" +#include "utils/numeric.h" #include "archetypes/energy_dist.h" #include "archetypes/particle_injector.h" @@ -15,67 +16,66 @@ namespace user { using namespace ntt; template - struct InitFields - { - /* - Sets up magnetic and electric field components for the simulation. - Must satisfy E = -v x B for Lorentz Force to be zero. - - @param bmag: magnetic field scaling - @param btheta: magnetic field polar angle - @param bphi: magnetic field azimuthal angle - @param drift_ux: drift velocity in the x direction - */ - InitFields(real_t bmag, real_t btheta, real_t bphi, real_t drift_ux) : - Bmag { bmag }, Btheta { btheta }, Bphi { bphi }, Vx { drift_ux } {} - - // magnetic field components - Inline auto bx1(const coord_t &x_Ph) const -> real_t - { - return Bmag * math::cos(Btheta / 180.0 * Kokkos::numbers::pi); - } - Inline auto bx2(const coord_t &x_Ph) const -> real_t - { - return Bmag * math::sin(Btheta / 180.0 * Kokkos::numbers::pi) * math::sin(Bphi / 180.0 * Kokkos::numbers::pi); - } - Inline auto bx3(const coord_t &x_Ph) const -> real_t - { - return Bmag * math::sin(Btheta / 180.0 * Kokkos::numbers::pi) * math::cos(Bphi / 180.0 * Kokkos::numbers::pi); - } - - // electric field components - Inline auto ex1(const coord_t &x_Ph) const -> real_t - { - return ZERO; - } - Inline auto ex2(const coord_t &x_Ph) const -> real_t - { - return -Vx * Bmag * math::sin(Btheta / 180.0 * Kokkos::numbers::pi) * math::cos(Bphi / 180.0 * Kokkos::numbers::pi); - } - Inline auto ex3(const coord_t &x_Ph) const -> real_t - { - return Vx * Bmag * math::sin(Btheta / 180.0 * Kokkos::numbers::pi) * math::sin(Bphi / 180.0 * Kokkos::numbers::pi); - } - - private: - const real_t Btheta, Bphi, Vx, Bmag; - }; + struct InitFields { + /* + Sets up magnetic and electric field components for the simulation. + Must satisfy E = -v x B for Lorentz Force to be zero. + + @param bmag: magnetic field scaling + @param btheta: magnetic field polar angle + @param bphi: magnetic field azimuthal angle + @param drift_ux: drift velocity in the x direction + */ + InitFields(real_t bmag, real_t btheta, real_t bphi, real_t drift_ux) + : Bmag { bmag * static_cast(convert::deg2rad) } + , Btheta { btheta * static_cast(convert::deg2rad) } + , Bphi { bphi * static_cast(convert::deg2rad) } + , Vx { drift_ux } {} + + // magnetic field components + Inline auto bx1(const coord_t& x_Ph) const -> real_t { + return Bmag * math::cos(Btheta); + } + + Inline auto bx2(const coord_t& x_Ph) const -> real_t { + return Bmag * math::sin(Btheta) * math::sin(Bphi); + } + + Inline auto bx3(const coord_t& x_Ph) const -> real_t { + return Bmag * math::sin(Btheta) * math::cos(Bphi); + } + + // electric field components + Inline auto ex1(const coord_t& x_Ph) const -> real_t { + return ZERO; + } + + Inline auto ex2(const coord_t& x_Ph) const -> real_t { + return -Vx * Bmag * math::sin(Btheta) * math::cos(Bphi); + } + Inline auto ex3(const coord_t& x_Ph) const -> real_t { + return Vx * Bmag * math::sin(Btheta) * math::sin(Bphi); + } + + private: + const real_t Btheta, Bphi, Vx, Bmag; + }; + + /* Enforce resetting magnetic and electric field at the boundary */ template struct DriveFields : public InitFields { - DriveFields(real_t bmag, real_t btheta, real_t bphi, real_t drift_ux) : - InitFields {bmag, btheta, bphi, drift_ux} {} - - /* Enforce resetting magnetic and electric field at the boundary - This avoids weird */ - using InitFields::bx1; - using InitFields::bx2; - using InitFields::bx3; - - using InitFields::ex1; - using InitFields::ex2; - using InitFields::ex3; - }; + DriveFields(real_t bmag, real_t btheta, real_t bphi, real_t drift_ux) + : InitFields { bmag, btheta, bphi, drift_ux } {} + + using InitFields::bx1; + using InitFields::bx2; + using InitFields::bx3; + + using InitFields::ex1; + using InitFields::ex2; + using InitFields::ex3; + }; template struct PGen : public arch::ProblemGenerator { @@ -93,26 +93,22 @@ namespace user { const real_t drift_ux, temperature; - const real_t Btheta, Bphi, Bmag; + const real_t Btheta, Bphi, Bmag; InitFields init_flds; - inline PGen(const SimulationParams &p, const Metadomain &m) - : arch::ProblemGenerator { p } - , drift_ux { p.template get("setup.drift_ux") } - , temperature { p.template get("setup.temperature") } - , Bmag { p.template get("setup.Bmag", 0.0) } - , Btheta { p.template get("setup.Btheta", 0.0) } - , Bphi { p.template get("setup.Bphi", 0.0) } - , init_flds { Bmag, Btheta, Bphi, drift_ux } {} + inline PGen(const SimulationParams& p, const Metadomain& m) + : arch::ProblemGenerator { p } + , drift_ux { p.template get("setup.drift_ux") } + , temperature { p.template get("setup.temperature") } + , Bmag { p.template get("setup.Bmag", ZERO) } + , Btheta { p.template get("setup.Btheta", ZERO) } + , Bphi { p.template get("setup.Bphi", ZERO) } + , init_flds { Bmag, Btheta, Bphi, drift_ux } {} inline PGen() {} auto FieldDriver(real_t time) const -> DriveFields { - const real_t bmag = Bmag; - const real_t btheta = Btheta; - const real_t bphi = Bphi; - const real_t ux = drift_ux; - return DriveFields{bmag, btheta, bphi, ux}; + return DriveFields { Bmag, Btheta, Bphi, drift_ux }; } inline void InitPrtls(Domain& local_domain) { @@ -121,7 +117,8 @@ namespace user { temperature, -drift_ux, in::x1); - const auto injector = arch::UniformInjector( + + const auto injector = arch::UniformInjector( energy_dist, { 1, 2 }); arch::InjectUniform>( diff --git a/setups/srpic/shock/shock.py b/setups/srpic/shock/shock.py index 64224c728..dc1565572 100644 --- a/setups/srpic/shock/shock.py +++ b/setups/srpic/shock/shock.py @@ -2,7 +2,7 @@ import matplotlib.pyplot as plt import matplotlib as mpl -data = nt2r.Data("shock-03.h5") +data = nt2r.Data("shock.h5") def frame(ti, f): @@ -55,7 +55,7 @@ def frame(ti, f): axs = [fig.add_subplot(gs[i]) for i in range(len(quantities))] for ax, q in zip(axs, quantities): - q["compute"](f).coarsen(x=2, y=2).mean().plot( + q["compute"](f.isel(t=ti)).plot( ax=ax, cmap=q["cmap"], norm=q["norm"], diff --git a/setups/srpic/shock/shock.toml b/setups/srpic/shock/shock.toml index e475ae097..f8f5e81a7 100644 --- a/setups/srpic/shock/shock.toml +++ b/setups/srpic/shock/shock.toml @@ -11,7 +11,7 @@ metric = "minkowski" [grid.boundaries] - fields = [["CONDUCTOR", "ABSORB"], ["PERIODIC"]] + fields = [["FIXED", "ABSORB"], ["PERIODIC"]] particles = [["REFLECT", "ABSORB"], ["PERIODIC"]] [scales] @@ -42,9 +42,9 @@ [setup] drift_ux = 0.1 temperature = 1e-3 - Bmag = 0.0 # set to 1.0 if magnetized shock is required - Btheta = 0.0 # magnetic field polar angle - Bphi = 0.0 # magnetic field azimuthal angle + Bmag = 1.0 + Btheta = 0.0 + Bphi = 0.0 [output] interval_time = 0.1 diff --git a/src/engines/srpic.hpp b/src/engines/srpic.hpp index 78c8f371e..1747c5138 100644 --- a/src/engines/srpic.hpp +++ b/src/engines/srpic.hpp @@ -42,7 +42,6 @@ #include #include -#include #include namespace ntt { @@ -586,8 +585,8 @@ namespace ntt { if (domain.mesh.flds_bc_in(direction) == FldsBC::AXIS) { AxisFieldsIn(direction, domain, tags); } - } else if (m_metadomain.mesh().flds_bc_in(direction) == FldsBC::ATMOSPHERE) { - AtmosphereFieldsIn(direction, domain, tags); + } else if (m_metadomain.mesh().flds_bc_in(direction) == FldsBC::FIXED) { + FixedFieldsIn(direction, domain, tags); } else if (m_metadomain.mesh().flds_bc_in(direction) == FldsBC::CONDUCTOR) { if (domain.mesh.flds_bc_in(direction) == FldsBC::CONDUCTOR) { ConductorFieldsIn(direction, domain, tags); @@ -713,11 +712,11 @@ namespace ntt { } } - void AtmosphereFieldsIn(dir::direction_t direction, - domain_t& domain, - BCTags tags) { + void FixedFieldsIn(dir::direction_t direction, + domain_t& domain, + BCTags tags) { /** - * atmosphere boundaries + * fixed field boundaries */ if constexpr (traits::has_member::value) { const auto [sign, dim, xg_min, xg_max] = get_atm_extent(direction); @@ -759,9 +758,9 @@ namespace ntt { if (dim == in::x1) { if (sign > 0) { Kokkos::parallel_for( - "AtmosphereBCFields", + "FixedBCFields", range, - kernel::AtmosphereBoundaries_kernel( + kernel::FixedBoundaries_kernel( domain.fields.em, field_driver, domain.mesh.metric, @@ -769,9 +768,9 @@ namespace ntt { tags)); } else { Kokkos::parallel_for( - "AtmosphereBCFields", + "FixedBCFields", range, - kernel::AtmosphereBoundaries_kernel( + kernel::FixedBoundaries_kernel( domain.fields.em, field_driver, domain.mesh.metric, @@ -782,9 +781,9 @@ namespace ntt { if constexpr (M::Dim == Dim::_2D or M::Dim == Dim::_3D) { if (sign > 0) { Kokkos::parallel_for( - "AtmosphereBCFields", + "FixedBCFields", range, - kernel::AtmosphereBoundaries_kernel( + kernel::FixedBoundaries_kernel( domain.fields.em, field_driver, domain.mesh.metric, @@ -792,9 +791,9 @@ namespace ntt { tags)); } else { Kokkos::parallel_for( - "AtmosphereBCFields", + "FixedBCFields", range, - kernel::AtmosphereBoundaries_kernel( + kernel::FixedBoundaries_kernel( domain.fields.em, field_driver, domain.mesh.metric, @@ -808,9 +807,9 @@ namespace ntt { if constexpr (M::Dim == Dim::_3D) { if (sign > 0) { Kokkos::parallel_for( - "AtmosphereBCFields", + "FixedBCFields", range, - kernel::AtmosphereBoundaries_kernel( + kernel::FixedBoundaries_kernel( domain.fields.em, field_driver, domain.mesh.metric, @@ -818,9 +817,9 @@ namespace ntt { tags)); } else { Kokkos::parallel_for( - "AtmosphereBCFields", + "FixedBCFields", range, - kernel::AtmosphereBoundaries_kernel( + kernel::FixedBoundaries_kernel( domain.fields.em, field_driver, domain.mesh.metric, @@ -834,8 +833,7 @@ namespace ntt { raise::Error("Invalid dimension", HERE); } } else { - raise::Error("Field driver not implemented in PGEN for atmosphere BCs", - HERE); + raise::Error("Field driver not implemented in PGEN for fixed BCs", HERE); } } diff --git a/src/global/enums.h b/src/global/enums.h index 57822dec4..1946da4b8 100644 --- a/src/global/enums.h +++ b/src/global/enums.h @@ -8,7 +8,7 @@ * - enum ntt::SimEngine // SRPIC, GRPIC * - enum ntt::PrtlBC // periodic, absorb, atmosphere, custom, * reflect, horizon, axis, sync - * - enum ntt::FldsBC // periodic, absorb, atmosphere, custom, + * - enum ntt::FldsBC // periodic, absorb, fixed, custom, * conductor, horizon, axis, sync * - enum ntt::PrtlPusher // boris, vay, photon, none * - enum ntt::Cooling // synchrotron, none @@ -213,25 +213,25 @@ namespace ntt { static constexpr const char* label = "flds_bc"; enum type : uint8_t { - INVALID = 0, - PERIODIC = 1, - ABSORB = 2, - ATMOSPHERE = 3, - CUSTOM = 4, - CONDUCTOR = 5, - HORIZON = 6, - AXIS = 7, - SYNC = 8, // <- SYNC means synchronization with other domains + INVALID = 0, + PERIODIC = 1, + ABSORB = 2, + FIXED = 3, + CUSTOM = 4, + CONDUCTOR = 5, + HORIZON = 6, + AXIS = 7, + SYNC = 8, // <- SYNC means synchronization with other domains }; constexpr FldsBC(uint8_t c) : enums_hidden::BaseEnum { c } {} - static constexpr type variants[] = { PERIODIC, ABSORB, ATMOSPHERE, CUSTOM, - CONDUCTOR, HORIZON, AXIS, SYNC }; - static constexpr const char* lookup[] = { "periodic", "absorb", - "atmosphere", "custom", - "conductor", "horizon", - "axis", "sync" }; + static constexpr type variants[] = { PERIODIC, ABSORB, FIXED, CUSTOM, + CONDUCTOR, HORIZON, AXIS, SYNC }; + static constexpr const char* lookup[] = { "periodic", "absorb", + "fixed", "custom", + "conductor", "horizon", + "axis", "sync" }; static constexpr std::size_t total = sizeof(variants) / sizeof(variants[0]); }; diff --git a/src/global/utils/numeric.h b/src/global/utils/numeric.h index 0b09f6c11..719256d1d 100644 --- a/src/global/utils/numeric.h +++ b/src/global/utils/numeric.h @@ -91,4 +91,8 @@ namespace constant { inline constexpr double SQRT3 = 1.73205080756887729352; } // namespace constant +namespace convert { + inline constexpr double deg2rad = constant::PI / 180.0; +} // namespace convert + #endif // GLOBAL_UTILS_NUMERIC_H diff --git a/src/kernels/fields_bcs.hpp b/src/kernels/fields_bcs.hpp index e617010b4..1a9ffcff4 100644 --- a/src/kernels/fields_bcs.hpp +++ b/src/kernels/fields_bcs.hpp @@ -217,7 +217,7 @@ namespace kernel { }; template - struct AtmosphereBoundaries_kernel { + struct FixedBoundaries_kernel { static constexpr Dimension D = M::Dim; static constexpr bool defines_ex1 = traits::has_method::value; static constexpr bool defines_ex2 = traits::has_method::value; @@ -240,11 +240,11 @@ namespace kernel { const std::size_t i_edge; const bool setE, setB; - AtmosphereBoundaries_kernel(ndfield_t& Fld, - const I& finit, - const M& metric, - std::size_t i_edge, - BCTags tags) + FixedBoundaries_kernel(ndfield_t& Fld, + const I& finit, + const M& metric, + std::size_t i_edge, + BCTags tags) : Fld { Fld } , finit { finit } , metric { metric } From 98349950f7392364248c353906e6440369c322ca Mon Sep 17 00:00:00 2001 From: hayk Date: Tue, 5 Nov 2024 13:43:39 -0500 Subject: [PATCH 154/773] FIXED bc + ATM --- CMakeLists.txt | 6 +- input.example.toml | 6 +- setups/srpic/magnetar/magnetar.toml | 2 +- setups/srpic/magnetosphere/magnetosphere.toml | 2 +- setups/srpic/monopole/monopole.toml | 2 +- setups/srpic/shock/pgen.hpp | 42 ++-- src/engines/srpic.hpp | 206 ++++++++++-------- src/global/arch/traits.h | 3 + src/global/enums.h | 33 ++- src/global/tests/enums.cpp | 4 +- src/kernels/fields_bcs.hpp | 12 +- 11 files changed, 166 insertions(+), 152 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4ee00d1b4..1a977c990 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -55,7 +55,9 @@ if(${DEBUG} STREQUAL "OFF") set(CMAKE_BUILD_TYPE Release CACHE STRING "CMake build type") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DNDEBUG") + set(CMAKE_CXX_FLAGS + "${CMAKE_CXX_FLAGS} -DNDEBUG -Wno-unused-local-typedefs -Wno-unknown-cuda-version" + ) else() set(CMAKE_BUILD_TYPE Debug @@ -64,8 +66,6 @@ else() "${CMAKE_CXX_FLAGS} -DDEBUG -Wall -Wextra -Wno-unknown-pragmas") endif() -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unused-local-typedefs") - # options set(precisions "single" "double" diff --git a/input.example.toml b/input.example.toml index e541f6e2b..4bf005b0e 100644 --- a/input.example.toml +++ b/input.example.toml @@ -90,10 +90,10 @@ # Boundary conditions for fields: # @required # @type: 1/2/3-size array of string tuples, each of size 1 or 2 - # @valid: "PERIODIC", "ABSORB", "FIXED", "CUSTOM", "HORIZON" + # @valid: "PERIODIC", "ABSORB", "FIXED", "ATMOSPHERE", "CUSTOM", "HORIZON" # @example: [["CUSTOM", "ABSORB"]] (for 2D spherical [[rmin, rmax]]) - # @note: When periodic in any of the directions, you should only set one value [..., ["PERIODIC"], ...] - # @note: In spherical, bondaries in theta/phi are set automatically (only specify bc @ [rmin, rmax]) [["FIXED", "ABSORB"]] + # @note: When periodic in any of the directions, you should only set one value: [..., ["PERIODIC"], ...] + # @note: In spherical, bondaries in theta/phi are set automatically (only specify bc @ [rmin, rmax]): [["ATMOSPHERE", "ABSORB"]] # @note: In GR, the horizon boundary is set automatically (only specify bc @ rmax): [["ABSORB"]] fields = "" # Boundary conditions for fields: diff --git a/setups/srpic/magnetar/magnetar.toml b/setups/srpic/magnetar/magnetar.toml index cd9ff5695..2a2260af5 100644 --- a/setups/srpic/magnetar/magnetar.toml +++ b/setups/srpic/magnetar/magnetar.toml @@ -11,7 +11,7 @@ metric = "qspherical" [grid.boundaries] - fields = [["FIXED", "ABSORB"]] + fields = [["ATMOSPHERE", "ABSORB"]] particles = [["ATMOSPHERE", "ABSORB"]] [grid.boundaries.absorb] diff --git a/setups/srpic/magnetosphere/magnetosphere.toml b/setups/srpic/magnetosphere/magnetosphere.toml index 83ade6e48..34e04b02d 100644 --- a/setups/srpic/magnetosphere/magnetosphere.toml +++ b/setups/srpic/magnetosphere/magnetosphere.toml @@ -11,7 +11,7 @@ metric = "qspherical" [grid.boundaries] - fields = [["FIXED", "ABSORB"]] + fields = [["ATMOSPHERE", "ABSORB"]] particles = [["ATMOSPHERE", "ABSORB"]] [grid.boundaries.absorb] diff --git a/setups/srpic/monopole/monopole.toml b/setups/srpic/monopole/monopole.toml index 322c15dd4..169837489 100644 --- a/setups/srpic/monopole/monopole.toml +++ b/setups/srpic/monopole/monopole.toml @@ -11,7 +11,7 @@ metric = "qspherical" [grid.boundaries] - fields = [["FIXED", "ABSORB"]] + fields = [["ATMOSPHERE", "ABSORB"]] particles = [["ATMOSPHERE", "ABSORB"]] [grid.boundaries.absorb] diff --git a/setups/srpic/shock/pgen.hpp b/setups/srpic/shock/pgen.hpp index 30929383f..1eedb3a01 100644 --- a/setups/srpic/shock/pgen.hpp +++ b/setups/srpic/shock/pgen.hpp @@ -5,6 +5,7 @@ #include "global.h" #include "arch/traits.h" +#include "utils/error.h" #include "utils/numeric.h" #include "archetypes/energy_dist.h" @@ -33,28 +34,28 @@ namespace user { , Vx { drift_ux } {} // magnetic field components - Inline auto bx1(const coord_t& x_Ph) const -> real_t { + Inline auto bx1(const coord_t&) const -> real_t { return Bmag * math::cos(Btheta); } - Inline auto bx2(const coord_t& x_Ph) const -> real_t { + Inline auto bx2(const coord_t&) const -> real_t { return Bmag * math::sin(Btheta) * math::sin(Bphi); } - Inline auto bx3(const coord_t& x_Ph) const -> real_t { + Inline auto bx3(const coord_t&) const -> real_t { return Bmag * math::sin(Btheta) * math::cos(Bphi); } // electric field components - Inline auto ex1(const coord_t& x_Ph) const -> real_t { + Inline auto ex1(const coord_t&) const -> real_t { return ZERO; } - Inline auto ex2(const coord_t& x_Ph) const -> real_t { + Inline auto ex2(const coord_t&) const -> real_t { return -Vx * Bmag * math::sin(Btheta) * math::cos(Bphi); } - Inline auto ex3(const coord_t& x_Ph) const -> real_t { + Inline auto ex3(const coord_t&) const -> real_t { return Vx * Bmag * math::sin(Btheta) * math::sin(Bphi); } @@ -62,21 +63,6 @@ namespace user { const real_t Btheta, Bphi, Vx, Bmag; }; - /* Enforce resetting magnetic and electric field at the boundary */ - template - struct DriveFields : public InitFields { - DriveFields(real_t bmag, real_t btheta, real_t bphi, real_t drift_ux) - : InitFields { bmag, btheta, bphi, drift_ux } {} - - using InitFields::bx1; - using InitFields::bx2; - using InitFields::bx3; - - using InitFields::ex1; - using InitFields::ex2; - using InitFields::ex3; - }; - template struct PGen : public arch::ProblemGenerator { // compatibility traits for the problem generator @@ -107,8 +93,18 @@ namespace user { inline PGen() {} - auto FieldDriver(real_t time) const -> DriveFields { - return DriveFields { Bmag, Btheta, Bphi, drift_ux }; + auto FixField(const em& comp) const -> real_t { + if (comp == em::ex2) { + return init_flds.ex2({ ZERO }); + } else if (comp == em::ex3) { + return init_flds.ex3({ ZERO }); + } else if (comp == em::bx1) { + return init_flds.bx1({ ZERO }); + } else { + raise::Error("Other components should not be requested when BC is in X", + HERE); + return ZERO; + } } inline void InitPrtls(Domain& local_domain) { diff --git a/src/engines/srpic.hpp b/src/engines/srpic.hpp index 1747c5138..244a5f863 100644 --- a/src/engines/srpic.hpp +++ b/src/engines/srpic.hpp @@ -585,11 +585,11 @@ namespace ntt { if (domain.mesh.flds_bc_in(direction) == FldsBC::AXIS) { AxisFieldsIn(direction, domain, tags); } + } else if (m_metadomain.mesh().flds_bc_in(direction) == FldsBC::ATMOSPHERE) { + AtmosphereFieldsIn(direction, domain, tags); } else if (m_metadomain.mesh().flds_bc_in(direction) == FldsBC::FIXED) { - FixedFieldsIn(direction, domain, tags); - } else if (m_metadomain.mesh().flds_bc_in(direction) == FldsBC::CONDUCTOR) { - if (domain.mesh.flds_bc_in(direction) == FldsBC::CONDUCTOR) { - ConductorFieldsIn(direction, domain, tags); + if (domain.mesh.flds_bc_in(direction) == FldsBC::FIXED) { + FixedFieldsIn(direction, domain, tags); } } else if (m_metadomain.mesh().flds_bc_in(direction) == FldsBC::CUSTOM) { if (domain.mesh.flds_bc_in(direction) == FldsBC::CUSTOM) { @@ -718,6 +718,100 @@ namespace ntt { /** * fixed field boundaries */ + const auto sign = direction.get_sign(); + const auto dim = direction.get_dim(); + raise::ErrorIf(dim != in::x1 and M::CoordType != Coord::Cart, + "Fixed BCs only implemented for x1 in " + "non-cartesian coordinates", + HERE); + em normal_b_comp, tang_e_comp1, tang_e_comp2; + if (dim == in::x1) { + normal_b_comp = em::bx1; + tang_e_comp1 = em::ex2; + tang_e_comp2 = em::ex3; + } else if (dim == in::x2) { + normal_b_comp = em::bx2; + tang_e_comp1 = em::ex1; + tang_e_comp2 = em::ex3; + } else if (dim == in::x3) { + normal_b_comp = em::bx3; + tang_e_comp1 = em::ex1; + tang_e_comp2 = em::ex2; + } else { + raise::Error("Invalid dimension", HERE); + } + std::vector xi_min, xi_max; + const std::vector all_dirs { in::x1, in::x2, in::x3 }; + for (unsigned short d { 0 }; d < static_cast(M::Dim); ++d) { + const auto dd = all_dirs[d]; + if (dim == dd) { + if (sign > 0) { // + direction + xi_min.push_back(domain.mesh.n_all(dd) - N_GHOSTS); + xi_max.push_back(domain.mesh.n_all(dd)); + } else { // - direction + xi_min.push_back(0); + xi_max.push_back(N_GHOSTS); + } + } else { + xi_min.push_back(0); + xi_max.push_back(domain.mesh.n_all(dd)); + } + } + raise::ErrorIf(xi_min.size() != xi_max.size() or + xi_min.size() != static_cast(M::Dim), + "Invalid range size", + HERE); + std::vector comps; + if (tags & BC::E) { + comps.push_back(tang_e_comp1); + comps.push_back(tang_e_comp2); + } + if (tags & BC::B) { + comps.push_back(normal_b_comp); + } + if constexpr (traits::has_member::value) { + raise::Error("Field driver for fixed fields not implemented", HERE); + } else { + // if field driver not present, set fields to fixed values + for (const auto& comp : comps) { + auto value = ZERO; + if constexpr ( + traits::has_member::value) { + // if fix field function present, read from it + value = m_pgen.FixField((em)comp); + } + if constexpr (M::Dim == Dim::_1D) { + Kokkos::deep_copy(Kokkos::subview(domain.fields.em, + std::make_pair(xi_min[0], xi_max[0]), + comp), + value); + } else if constexpr (M::Dim == Dim::_2D) { + Kokkos::deep_copy(Kokkos::subview(domain.fields.em, + std::make_pair(xi_min[0], xi_max[0]), + std::make_pair(xi_min[1], xi_max[1]), + comp), + value); + } else if constexpr (M::Dim == Dim::_3D) { + Kokkos::deep_copy( + Kokkos::subview(domain.fields.em, + std::make_pair(xi_min[0], xi_max[0]), + std::make_pair(xi_min[1], xi_max[1]), + std::make_pair(xi_min[2], xi_max[2]), + comp), + value); + } else { + raise::Error("Invalid dimension", HERE); + } + } + } + } + + void AtmosphereFieldsIn(dir::direction_t direction, + domain_t& domain, + BCTags tags) { + /** + * atmosphere field boundaries + */ if constexpr (traits::has_member::value) { const auto [sign, dim, xg_min, xg_max] = get_atm_extent(direction); const auto dd = static_cast(dim); @@ -758,9 +852,9 @@ namespace ntt { if (dim == in::x1) { if (sign > 0) { Kokkos::parallel_for( - "FixedBCFields", + "AtmosphereBCFields", range, - kernel::FixedBoundaries_kernel( + kernel::EnforcedBoundaries_kernel( domain.fields.em, field_driver, domain.mesh.metric, @@ -768,9 +862,9 @@ namespace ntt { tags)); } else { Kokkos::parallel_for( - "FixedBCFields", + "AtmosphereBCFields", range, - kernel::FixedBoundaries_kernel( + kernel::EnforcedBoundaries_kernel( domain.fields.em, field_driver, domain.mesh.metric, @@ -781,9 +875,9 @@ namespace ntt { if constexpr (M::Dim == Dim::_2D or M::Dim == Dim::_3D) { if (sign > 0) { Kokkos::parallel_for( - "FixedBCFields", + "AtmosphereBCFields", range, - kernel::FixedBoundaries_kernel( + kernel::EnforcedBoundaries_kernel( domain.fields.em, field_driver, domain.mesh.metric, @@ -791,9 +885,9 @@ namespace ntt { tags)); } else { Kokkos::parallel_for( - "FixedBCFields", + "AtmosphereBCFields", range, - kernel::FixedBoundaries_kernel( + kernel::EnforcedBoundaries_kernel( domain.fields.em, field_driver, domain.mesh.metric, @@ -807,9 +901,9 @@ namespace ntt { if constexpr (M::Dim == Dim::_3D) { if (sign > 0) { Kokkos::parallel_for( - "FixedBCFields", + "AtmosphereBCFields", range, - kernel::FixedBoundaries_kernel( + kernel::EnforcedBoundaries_kernel( domain.fields.em, field_driver, domain.mesh.metric, @@ -817,9 +911,9 @@ namespace ntt { tags)); } else { Kokkos::parallel_for( - "FixedBCFields", + "AtmosphereBCFields", range, - kernel::FixedBoundaries_kernel( + kernel::EnforcedBoundaries_kernel( domain.fields.em, field_driver, domain.mesh.metric, @@ -833,86 +927,8 @@ namespace ntt { raise::Error("Invalid dimension", HERE); } } else { - raise::Error("Field driver not implemented in PGEN for fixed BCs", HERE); - } - } - - void ConductorFieldsIn(dir::direction_t direction, - domain_t& domain, - BCTags tags) { - const auto sign = direction.get_sign(); - const auto dim = direction.get_dim(); - raise::ErrorIf( - dim != in::x1 and M::CoordType != Coord::Cart, - "Conductor BCs only implemented for x1 in non-cartesian coordinates", - HERE); - em normal_b_comp, tang_e_comp1, tang_e_comp2; - if (dim == in::x1) { - normal_b_comp = em::bx1; - tang_e_comp1 = em::ex2; - tang_e_comp2 = em::ex3; - } else if (dim == in::x2) { - normal_b_comp = em::bx2; - tang_e_comp1 = em::ex1; - tang_e_comp2 = em::ex3; - } else if (dim == in::x3) { - normal_b_comp = em::bx3; - tang_e_comp1 = em::ex1; - tang_e_comp2 = em::ex2; - } else { - raise::Error("Invalid dimension", HERE); - } - std::vector xi_min, xi_max; - const std::vector all_dirs { in::x1, in::x2, in::x3 }; - for (unsigned short d { 0 }; d < static_cast(M::Dim); ++d) { - const auto dd = all_dirs[d]; - if (dim == dd) { - if (sign > 0) { // + direction - xi_min.push_back(domain.mesh.n_all(dd) - N_GHOSTS); - xi_max.push_back(domain.mesh.n_all(dd)); - } else { // - direction - xi_min.push_back(0); - xi_max.push_back(N_GHOSTS); - } - } else { - xi_min.push_back(0); - xi_max.push_back(domain.mesh.n_all(dd)); - } - } - raise::ErrorIf(xi_min.size() != xi_max.size() or - xi_min.size() != static_cast(M::Dim), - "Invalid range size", + raise::Error("Field driver not implemented in PGEN for atmosphere BCs", HERE); - std::vector comps; - if (tags & BC::E) { - comps.push_back(tang_e_comp1); - comps.push_back(tang_e_comp2); - } - if (tags & BC::B) { - comps.push_back(normal_b_comp); - } - for (const auto& comp : comps) { - if constexpr (M::Dim == Dim::_1D) { - Kokkos::deep_copy(Kokkos::subview(domain.fields.em, - std::make_pair(xi_min[0], xi_max[0]), - comp), - ZERO); - } else if constexpr (M::Dim == Dim::_2D) { - Kokkos::deep_copy(Kokkos::subview(domain.fields.em, - std::make_pair(xi_min[0], xi_max[0]), - std::make_pair(xi_min[1], xi_max[1]), - comp), - ZERO); - } else if constexpr (M::Dim == Dim::_3D) { - Kokkos::deep_copy(Kokkos::subview(domain.fields.em, - std::make_pair(xi_min[0], xi_max[0]), - std::make_pair(xi_min[1], xi_max[1]), - std::make_pair(xi_min[2], xi_max[2]), - comp), - ZERO); - } else { - raise::Error("Invalid dimension", HERE); - } } } diff --git a/src/global/arch/traits.h b/src/global/arch/traits.h index e915bdf1a..9fd40e201 100644 --- a/src/global/arch/traits.h +++ b/src/global/arch/traits.h @@ -96,6 +96,9 @@ namespace traits { template using field_driver_t = decltype(&T::FieldDriver); + template + using fix_field_t = decltype(&T::FixField); + template using custom_fields_t = decltype(&T::CustomFields); diff --git a/src/global/enums.h b/src/global/enums.h index 1946da4b8..283cb456d 100644 --- a/src/global/enums.h +++ b/src/global/enums.h @@ -8,8 +8,8 @@ * - enum ntt::SimEngine // SRPIC, GRPIC * - enum ntt::PrtlBC // periodic, absorb, atmosphere, custom, * reflect, horizon, axis, sync - * - enum ntt::FldsBC // periodic, absorb, fixed, custom, - * conductor, horizon, axis, sync + * - enum ntt::FldsBC // periodic, absorb, fixed, atmosphere, + * custom, horizon, axis, sync * - enum ntt::PrtlPusher // boris, vay, photon, none * - enum ntt::Cooling // synchrotron, none * - enum ntt::FldsID // e, dive, d, divd, b, h, j, @@ -213,25 +213,24 @@ namespace ntt { static constexpr const char* label = "flds_bc"; enum type : uint8_t { - INVALID = 0, - PERIODIC = 1, - ABSORB = 2, - FIXED = 3, - CUSTOM = 4, - CONDUCTOR = 5, - HORIZON = 6, - AXIS = 7, - SYNC = 8, // <- SYNC means synchronization with other domains + INVALID = 0, + PERIODIC = 1, + ABSORB = 2, + FIXED = 3, + ATMOSPHERE = 4, + CUSTOM = 5, + HORIZON = 6, + AXIS = 7, + SYNC = 8, // <- SYNC means synchronization with other domains }; constexpr FldsBC(uint8_t c) : enums_hidden::BaseEnum { c } {} - static constexpr type variants[] = { PERIODIC, ABSORB, FIXED, CUSTOM, - CONDUCTOR, HORIZON, AXIS, SYNC }; - static constexpr const char* lookup[] = { "periodic", "absorb", - "fixed", "custom", - "conductor", "horizon", - "axis", "sync" }; + static constexpr type variants[] = { PERIODIC, ABSORB, FIXED, ATMOSPHERE, + CUSTOM, HORIZON, AXIS, SYNC }; + static constexpr const char* lookup[] = { "periodic", "absorb", "fixed", + "atmosphere", "custom", "horizon", + "axis", "sync" }; static constexpr std::size_t total = sizeof(variants) / sizeof(variants[0]); }; diff --git a/src/global/tests/enums.cpp b/src/global/tests/enums.cpp index 1fc57398f..4d678e85e 100644 --- a/src/global/tests/enums.cpp +++ b/src/global/tests/enums.cpp @@ -61,8 +61,8 @@ auto main() -> int { enum_str_t all_simulation_engines = { "srpic", "grpic" }; enum_str_t all_particle_bcs = { "periodic", "absorb", "atmosphere", "custom", "reflect", "horizon", "axis", "sync" }; - enum_str_t all_fields_bcs = { "periodic", "absorb", "atmosphere", "custom", - "horizon", "conductor", "axis", "sync" }; + enum_str_t all_fields_bcs = { "periodic", "absorb", "fixed", "atmosphere", + "custom", "horizon", "axis", "sync" }; enum_str_t all_particle_pushers = { "boris", "vay", "photon", "none" }; enum_str_t all_coolings = { "synchrotron", "none" }; diff --git a/src/kernels/fields_bcs.hpp b/src/kernels/fields_bcs.hpp index 1a9ffcff4..2f2a458bb 100644 --- a/src/kernels/fields_bcs.hpp +++ b/src/kernels/fields_bcs.hpp @@ -217,7 +217,7 @@ namespace kernel { }; template - struct FixedBoundaries_kernel { + struct EnforcedBoundaries_kernel { static constexpr Dimension D = M::Dim; static constexpr bool defines_ex1 = traits::has_method::value; static constexpr bool defines_ex2 = traits::has_method::value; @@ -240,11 +240,11 @@ namespace kernel { const std::size_t i_edge; const bool setE, setB; - FixedBoundaries_kernel(ndfield_t& Fld, - const I& finit, - const M& metric, - std::size_t i_edge, - BCTags tags) + EnforcedBoundaries_kernel(ndfield_t& Fld, + const I& finit, + const M& metric, + std::size_t i_edge, + BCTags tags) : Fld { Fld } , finit { finit } , metric { metric } From 59be02a6e9f4e50bb0bcf3cc5299dc3c73cb1440 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Tue, 5 Nov 2024 17:52:11 -0500 Subject: [PATCH 155/773] compilible pusher in gr --- src/engines/grpic.hpp | 41 ++++++++++++++++++-- src/kernels/particle_pusher_gr.hpp | 61 +++++++++++++++--------------- 2 files changed, 69 insertions(+), 33 deletions(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index 3f90220ec..d48fb950e 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -344,7 +344,7 @@ namespace ntt { * Now: x_prtl at n + 1, u_prtl at n + 1/2 */ timers.start("ParticlePusher"); - // ParticlePush(dom); + ParticlePush(dom); timers.stop("ParticlePusher"); /** @@ -1004,10 +1004,16 @@ namespace ntt { // coeff = q / m (dt / 2) omegaB0 const auto coeff = q_ovr_m * HALF * dt * m_params.template get("scales.omegaB0"); + // clang-format off + + if (species.pusher() == PrtlPusher::PHOTON) { + auto range_policy = Kokkos::RangePolicy( + 0, + species.npart()); Kokkos::parallel_for( "ParticlePusher", - species.rangeActiveParticles(), + range_policy, kernel::gr::Pusher_kernel( domain.fields.em, domain.fields.em0, @@ -1022,9 +1028,38 @@ namespace ntt { domain.mesh.n_active(in::x1), domain.mesh.n_active(in::x2), domain.mesh.n_active(in::x3), - m_params.template get("algorithms.gr.pusher_eps"), m_params.template get("algorithms.gr.pusher_niter"), + m_params.template get("algorithms.gr.pusher_eps"), m_params.template get("algorithms.gr.pusher_niter"), domain.mesh.prtl_bc() )); + } else if (species.pusher() == PrtlPusher::BORIS) { + auto range_policy = Kokkos::RangePolicy( + 0, + species.npart()); + Kokkos::parallel_for( + "ParticlePusher", + range_policy, + kernel::gr::Pusher_kernel( + domain.fields.em, + domain.fields.em0, + species.i1, species.i2, species.i3, + species.i1_prev, species.i2_prev, species.i3_prev, + species.dx1, species.dx2, species.dx3, + species.dx1_prev, species.dx2_prev, species.dx3_prev, + species.ux1, species.ux2, species.ux3, + species.phi, species.tag, + domain.mesh.metric, + coeff, dt, + domain.mesh.n_active(in::x1), + domain.mesh.n_active(in::x2), + domain.mesh.n_active(in::x3), + m_params.template get("algorithms.gr.pusher_eps"), m_params.template get("algorithms.gr.pusher_niter"), + domain.mesh.prtl_bc() + )); + } else if (species.pusher() == PrtlPusher::NONE) { + // do nothing + } else { + raise::Error("not implemented", HERE); + } // clang-format on } } diff --git a/src/kernels/particle_pusher_gr.hpp b/src/kernels/particle_pusher_gr.hpp index 547463fa7..fd6246217 100644 --- a/src/kernels/particle_pusher_gr.hpp +++ b/src/kernels/particle_pusher_gr.hpp @@ -65,6 +65,7 @@ namespace kernel::gr { static_assert(M::is_metric, "M must be a metric class"); static constexpr auto D = M::Dim; + private: const randacc_ndfield_t DB; const randacc_ndfield_t DB0; array_t i1, i2, i3; @@ -86,34 +87,34 @@ namespace kernel::gr { bool is_absorb_i1min { false }, is_absorb_i1max { false }; public: - Pusher_kernel(const ndfield_t& DB, - const ndfield_t& DB0, - const array_t& i1, - const array_t& i2, - const array_t& i3, - const array_t& i1_prev, - const array_t& i2_prev, - const array_t& i3_prev, - const array_t& dx1, - const array_t& dx2, - const array_t& dx3, - const array_t& dx1_prev, - const array_t& dx2_prev, - const array_t& dx3_prev, - const array_t& ux1, - const array_t& ux2, - const array_t& ux3, - const array_t& phi, - const array_t& tag, - const M& metric, - const real_t& coeff, - const real_t& dt, - const int& ni1, - const int& ni2, - const int& ni3, - const real_t& epsilon, - const int& niter, - const boundaries_t& boundaries) + Pusher_kernel(const ndfield_t& DB, + const ndfield_t& DB0, + array_t& i1, + array_t& i2, + array_t& i3, + array_t& i1_prev, + array_t& i2_prev, + array_t& i3_prev, + array_t& dx1, + array_t& dx2, + array_t& dx3, + array_t& dx1_prev, + array_t& dx2_prev, + array_t& dx3_prev, + array_t& ux1, + array_t& ux2, + array_t& ux3, + array_t& phi, + array_t& tag, + const M& metric, + real_t coeff, + real_t dt, + int ni1, + int ni2, + int ni3, + const real_t& epsilon, + const int& niter, + const boundaries_t& boundaries) : DB { DB } , DB0 { DB0 } , i1 { i1 } @@ -351,8 +352,8 @@ namespace kernel::gr { vp_upd[1] = vp[1] + dt * - (-metric.alpha(xp) * u0 * DERIVATIVE_IN_TH(alpha, xp) + - vp_mid[1] * DERIVATIVE_IN_TH(beta1, xp) - + (-metric.alpha(xp) * u0 * DERIVATIVE_IN_TH(metric.alpha, xp) + + vp_mid[1] * DERIVATIVE_IN_TH(metric.beta1, xp) - (HALF / u0) * (DERIVATIVE_IN_TH((metric.template h<1, 1>), xp) * SQR(vp_mid[0]) + DERIVATIVE_IN_TH((metric.template h<2, 2>), xp) * SQR(vp_mid[1]) + From fb0788b5b5119cd69ca70a5fa8873250665254ef Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Wed, 6 Nov 2024 14:58:22 -0500 Subject: [PATCH 156/773] consistent type for pusher_niter --- src/engines/grpic.hpp | 4 ++-- src/kernels/particle_pusher_gr.hpp | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index d48fb950e..13d8899bf 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -1028,7 +1028,7 @@ namespace ntt { domain.mesh.n_active(in::x1), domain.mesh.n_active(in::x2), domain.mesh.n_active(in::x3), - m_params.template get("algorithms.gr.pusher_eps"), m_params.template get("algorithms.gr.pusher_niter"), + m_params.template get("algorithms.gr.pusher_eps"), m_params.template get("algorithms.gr.pusher_niter"), domain.mesh.prtl_bc() )); } else if (species.pusher() == PrtlPusher::BORIS) { @@ -1052,7 +1052,7 @@ namespace ntt { domain.mesh.n_active(in::x1), domain.mesh.n_active(in::x2), domain.mesh.n_active(in::x3), - m_params.template get("algorithms.gr.pusher_eps"), m_params.template get("algorithms.gr.pusher_niter"), + m_params.template get("algorithms.gr.pusher_eps"), m_params.template get("algorithms.gr.pusher_niter"), domain.mesh.prtl_bc() )); } else if (species.pusher() == PrtlPusher::NONE) { diff --git a/src/kernels/particle_pusher_gr.hpp b/src/kernels/particle_pusher_gr.hpp index fd6246217..fba40890f 100644 --- a/src/kernels/particle_pusher_gr.hpp +++ b/src/kernels/particle_pusher_gr.hpp @@ -77,11 +77,11 @@ namespace kernel::gr { array_t tag; const M metric; - const real_t coeff, dt; - const int ni1, ni2, ni3; - const real_t epsilon; - const int niter; - const int i1_absorb; + const real_t coeff, dt; + const int ni1, ni2, ni3; + const real_t epsilon; + const unsigned short niter; + const int i1_absorb; bool is_axis_i2min { false }, is_axis_i2max { false }; bool is_absorb_i1min { false }, is_absorb_i1max { false }; @@ -113,7 +113,7 @@ namespace kernel::gr { int ni2, int ni3, const real_t& epsilon, - const int& niter, + const unsigned short& niter, const boundaries_t& boundaries) : DB { DB } , DB0 { DB0 } From 833f038e88e2b0b00bccdea2425127dc777d4e1a Mon Sep 17 00:00:00 2001 From: hayk Date: Wed, 6 Nov 2024 17:02:16 -0500 Subject: [PATCH 157/773] multifile output --- input.example.toml | 4 ++ src/framework/domain/output.cpp | 11 +++-- src/framework/parameters.cpp | 10 ++++- src/global/global.h | 11 +++++ src/output/CMakeLists.txt | 1 + src/output/writer.cpp | 73 ++++++++++++++++++++++++++------- src/output/writer.h | 10 +++-- 7 files changed, 98 insertions(+), 22 deletions(-) diff --git a/input.example.toml b/input.example.toml index 4bf005b0e..ce5a2079d 100644 --- a/input.example.toml +++ b/input.example.toml @@ -320,6 +320,10 @@ # @default: -1.0 (disabled) # @note: When `interval_time` < 0, the output is controlled by `interval`, otherwise by `interval_time` interval_time = "" + # Whether to output each timestep into separate files: + # @type: bool + # @default: true + separate_files = "" [output.fields] # Toggle for the field output: diff --git a/src/framework/domain/output.cpp b/src/framework/domain/output.cpp index c7cb6bb65..d88e593b5 100644 --- a/src/framework/domain/output.cpp +++ b/src/framework/domain/output.cpp @@ -65,7 +65,8 @@ namespace ntt { g_writer.init(ptr_adios, params.template get("output.format"), - params.template get("simulation.name")); + params.template get("simulation.name"), + params.template get("output.separate_files")); g_writer.defineMeshLayout(glob_shape_with_ghosts, off_ncells_with_ghosts, loc_shape_with_ghosts, @@ -215,8 +216,8 @@ namespace ntt { "local_domain is a placeholder", HERE); logger::Checkpoint("Writing output", HERE); - g_writer.beginWriting(current_step, current_time); if (write_fields) { + g_writer.beginWriting(WriteMode::Fields, current_step, current_time); const auto incl_ghosts = params.template get("output.debug.ghosts"); const auto dwn = params.template get>( "output.fields.downsampling"); @@ -467,9 +468,11 @@ namespace ntt { } g_writer.writeField(names, local_domain->fields.bckp, addresses); } + g_writer.endWriting(WriteMode::Fields); } // end shouldWrite("fields", step, time) if (write_particles) { + g_writer.beginWriting(WriteMode::Particles, current_step, current_time); const auto prtl_stride = params.template get( "output.particles.stride"); for (const auto& prtl : g_writer.speciesWriters()) { @@ -547,9 +550,11 @@ namespace ntt { g_writer.writeParticleQuantity(buff_x3, glob_tot, offset, prtl.name("X", 3)); } } + g_writer.endWriting(WriteMode::Particles); } // end shouldWrite("particles", step, time) if (write_spectra) { + g_writer.beginWriting(WriteMode::Spectra, current_step, current_time); const auto log_bins = params.template get( "output.spectra.log_bins"); const auto n_bins = params.template get( @@ -613,9 +618,9 @@ namespace ntt { g_writer.writeSpectrum(dn, spec.name()); } g_writer.writeSpectrumBins(energy, "sEbn"); + g_writer.endWriting(WriteMode::Spectra); } // end shouldWrite("spectra", step, time) - g_writer.endWriting(); return true; } diff --git a/src/framework/parameters.cpp b/src/framework/parameters.cpp index b667b5ac9..91a14ae09 100644 --- a/src/framework/parameters.cpp +++ b/src/framework/parameters.cpp @@ -463,6 +463,9 @@ namespace ntt { toml::find_or(toml_data, "output", "interval", defaults::output::interval)); set("output.interval_time", toml::find_or(toml_data, "output", "interval_time", -1.0)); + set("output.separate_files", + toml::find_or(toml_data, "output", "separate_files", true)); + promiseToDefine("output.fields.interval"); promiseToDefine("output.fields.interval_time"); promiseToDefine("output.fields.enable"); @@ -509,11 +512,16 @@ namespace ntt { set("output.fields.downsampling", field_dwn); // particles + auto all_specs = std::vector {}; + const auto nspec = get("particles.nspec"); + for (auto i = 0u; i < nspec; ++i) { + all_specs.push_back(static_cast(i + 1)); + } const auto prtl_out = toml::find_or(toml_data, "output", "particles", "species", - std::vector {}); + all_specs); set("output.particles.species", prtl_out); set("output.particles.stride", toml::find_or(toml_data, diff --git a/src/global/global.h b/src/global/global.h index ad524fb0e..d55d8e21e 100644 --- a/src/global/global.h +++ b/src/global/global.h @@ -249,6 +249,17 @@ namespace Comm { typedef int CommTags; +namespace WriteMode { + enum WriteModeTags_ { + None = 0, + Fields = 1 << 0, + Particles = 1 << 1, + Spectra = 1 << 2, + }; +} // namespace WriteMode + +typedef int WriteModeTags; + namespace BC { enum BCTags_ { None = 0, diff --git a/src/output/CMakeLists.txt b/src/output/CMakeLists.txt index e6dbcc03a..81333e9ff 100644 --- a/src/output/CMakeLists.txt +++ b/src/output/CMakeLists.txt @@ -30,6 +30,7 @@ add_library(ntt_output ${SOURCES}) set(libs ntt_global) add_dependencies(ntt_output ${libs}) target_link_libraries(ntt_output PUBLIC ${libs}) +target_link_libraries(ntt_output PRIVATE stdc++fs) target_include_directories( ntt_output diff --git a/src/output/writer.cpp b/src/output/writer.cpp index 4ba0ea14c..95965c864 100644 --- a/src/output/writer.cpp +++ b/src/output/writer.cpp @@ -18,6 +18,7 @@ #include #endif +#include #include #include @@ -25,9 +26,11 @@ namespace out { void Writer::init(adios2::ADIOS* ptr_adios, const std::string& engine, - const std::string& title) { - m_engine = engine; - p_adios = ptr_adios; + const std::string& title, + bool use_separate_files) { + m_separate_files = use_separate_files; + m_engine = engine; + p_adios = ptr_adios; raise::ErrorIf(p_adios == nullptr, "ADIOS pointer is null", HERE); @@ -36,7 +39,7 @@ namespace out { m_io.DefineVariable("Step"); m_io.DefineVariable("Time"); - m_fname = title + (m_engine == "hdf5" ? ".h5" : ".bp"); + m_fname = title; } void Writer::addTracker(const std::string& type, @@ -412,33 +415,75 @@ namespace out { m_writer.Put(vare, xe_h); } - void Writer::beginWriting(std::size_t tstep, long double time) { + void Writer::beginWriting(WriteModeTags write_mode, + std::size_t tstep, + long double time) { + raise::ErrorIf(write_mode == WriteMode::None, "None is not a valid mode", HERE); raise::ErrorIf(p_adios == nullptr, "ADIOS pointer is null", HERE); - p_adios->ExitComputationBlock(); - if (m_writing_mode) { + if (m_active_mode != WriteMode::None) { raise::Fatal("Already writing", HERE); } - m_writing_mode = true; + m_active_mode = write_mode; try { - m_writer = m_io.Open(m_fname, m_mode); + std::string filename; + const std::string ext = m_engine == "hdf5" ? "h5" : "bp"; + if (m_separate_files) { + std::string mode_str; + if (m_active_mode == WriteMode::Fields) { + mode_str = "fields"; + } else if (m_active_mode == WriteMode::Particles) { + mode_str = "particles"; + } else if (m_active_mode == WriteMode::Spectra) { + mode_str = "spectra"; + } else { + raise::Fatal("Unknown write mode", HERE); + } + CallOnce( + [](auto& main_path, auto& mode_path) { + const std::filesystem::path main { main_path }; + const std::filesystem::path mode { mode_path }; + if (!std::filesystem::exists(main_path)) { + std::filesystem::create_directory(main_path); + } + if (!std::filesystem::exists(main / mode)) { + std::filesystem::create_directory(main / mode); + } + }, + m_fname, + mode_str); + filename = fmt::format("%s/%s/%s.%08lu.%s", + m_fname.c_str(), + mode_str.c_str(), + mode_str.c_str(), + tstep, + ext.c_str()); + m_mode = adios2::Mode::Write; + } else { + filename = fmt::format("%s.%s", m_fname.c_str(), ext.c_str()); + m_mode = std::filesystem::exists(filename) ? adios2::Mode::Append + : adios2::Mode::Write; + } + m_writer = m_io.Open(filename, m_mode); } catch (std::exception& e) { raise::Fatal(e.what(), HERE); } - m_mode = adios2::Mode::Append; m_writer.BeginStep(); m_writer.Put(m_io.InquireVariable("Step"), &tstep); m_writer.Put(m_io.InquireVariable("Time"), &time); } - void Writer::endWriting() { + void Writer::endWriting(WriteModeTags write_mode) { + raise::ErrorIf(write_mode == WriteMode::None, "None is not a valid mode", HERE); raise::ErrorIf(p_adios == nullptr, "ADIOS pointer is null", HERE); - if (!m_writing_mode) { + if (m_active_mode == WriteMode::None) { raise::Fatal("Not writing", HERE); } - m_writing_mode = false; + if (m_active_mode != write_mode) { + raise::Fatal("Writing mode mismatch", HERE); + } + m_active_mode = WriteMode::None; m_writer.EndStep(); m_writer.Close(); - p_adios->EnterComputationBlock(); } template void Writer::writeField(const std::vector&, diff --git a/src/output/writer.h b/src/output/writer.h index 566da44b2..a8abf4b12 100644 --- a/src/output/writer.h +++ b/src/output/writer.h @@ -36,6 +36,8 @@ namespace out { adios2::Engine m_writer; adios2::Mode m_mode { adios2::Mode::Write }; + bool m_separate_files; + // global shape of the fields array to output std::vector m_flds_g_shape; // local corner of the fields array to output @@ -63,7 +65,7 @@ namespace out { std::vector m_prtl_writers; std::vector m_spectra_writers; - bool m_writing_mode { false }; + WriteModeTags m_active_mode { WriteMode::None }; public: Writer() {} @@ -72,7 +74,7 @@ namespace out { Writer(Writer&&) = default; - void init(adios2::ADIOS*, const std::string&, const std::string&); + void init(adios2::ADIOS*, const std::string&, const std::string&, bool); void setMode(adios2::Mode); @@ -106,8 +108,8 @@ namespace out { void writeSpectrum(const array_t&, const std::string&); void writeSpectrumBins(const array_t&, const std::string&); - void beginWriting(std::size_t, long double); - void endWriting(); + void beginWriting(WriteModeTags, std::size_t, long double); + void endWriting(WriteModeTags); /* getters -------------------------------------------------------------- */ auto fname() const -> const std::string& { From 619bacd377b7e63893b9d940f1afbab28f3958a1 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Thu, 7 Nov 2024 10:14:22 -0500 Subject: [PATCH 158/773] cleaned up an unused var --- src/engines/grpic.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index 13d8899bf..40e2776e0 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -561,7 +561,6 @@ namespace ntt { "grid.boundaries.absorb.ds"); const auto dim = direction.get_dim(); real_t xg_min, xg_max, xg_edge; - auto sign = direction.get_sign(); xg_max = m_metadomain.mesh().extent(dim).second; xg_min = xg_max - ds; xg_edge = xg_max; From 483510184ad2aa69ca5c0608020831e61cb7269b Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Thu, 7 Nov 2024 16:01:16 -0500 Subject: [PATCH 159/773] fixed bug in output for dimensions of coordinates of particles in GR --- src/framework/domain/output.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/framework/domain/output.cpp b/src/framework/domain/output.cpp index be154ce16..c669eb8ae 100644 --- a/src/framework/domain/output.cpp +++ b/src/framework/domain/output.cpp @@ -79,7 +79,13 @@ namespace ntt { const auto species_to_write = params.template get>( "output.particles.species"); g_writer.defineFieldOutputs(S, all_fields_to_write); - g_writer.defineParticleOutputs(M::PrtlDim, species_to_write); + + Dimension dim = M::PrtlDim; + if constexpr (M::CoordType != Coord::Cart) { + dim = Dim::_3D; + } + g_writer.defineParticleOutputs(dim, species_to_write); + // spectra write all particle species std::vector spectra_species {}; for (const auto& sp : species_params()) { From 247177ee1a45a92f8c6fe02f0c73922e9af5c815 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Fri, 8 Nov 2024 16:08:26 -0500 Subject: [PATCH 160/773] fixed coordinate transformation for a global injector. When we inject a small amount of particles with given velocities, this is usually in physical coordinates rather than tetrads as in injection for a given energy distribution --- src/kernels/injectors.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/kernels/injectors.hpp b/src/kernels/injectors.hpp index 9d3fd7d81..dd5e2d21d 100644 --- a/src/kernels/injectors.hpp +++ b/src/kernels/injectors.hpp @@ -335,7 +335,7 @@ namespace kernel { if constexpr (S == SimEngine::SRPIC) { global_metric.template transform_xyz(x_Cd_, u_Ph, u_Cd); } else if constexpr (S == SimEngine::GRPIC) { - global_metric.template transform(x_Cd, u_Ph, u_Cd); + global_metric.template transform(x_Cd, u_Ph, u_Cd); } else { raise::KernelError(HERE, "Unknown simulation engine"); } @@ -380,7 +380,7 @@ namespace kernel { if constexpr (S == SimEngine::SRPIC) { global_metric.template transform_xyz(x_Cd, u_Ph, u_Cd); } else if constexpr (S == SimEngine::GRPIC) { - global_metric.template transform(x_Cd, u_Ph, u_Cd); + global_metric.template transform(x_Cd, u_Ph, u_Cd); } else { raise::KernelError(HERE, "Unknown simulation engine"); } From a33d66442db07a14f36d890dd065e38415cde00d Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Fri, 8 Nov 2024 16:11:23 -0500 Subject: [PATCH 161/773] minor consistensy with sr --- src/kernels/particle_pusher_gr.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/kernels/particle_pusher_gr.hpp b/src/kernels/particle_pusher_gr.hpp index fba40890f..2e9ddbde2 100644 --- a/src/kernels/particle_pusher_gr.hpp +++ b/src/kernels/particle_pusher_gr.hpp @@ -29,7 +29,7 @@ /* Local macros */ /* -------------------------------------------------------------------------- */ #define from_Xi_to_i(XI, I) \ - { I = static_cast((XI)); } + { I = static_cast((XI + 1)) - 1; } #define from_Xi_to_i_di(XI, I, DI) \ { \ From 7c940f7586b95173546106622297b85bb9c01cec Mon Sep 17 00:00:00 2001 From: haykh Date: Mon, 11 Nov 2024 19:37:57 -0500 Subject: [PATCH 162/773] 0 particle case in timers --- src/global/utils/timer.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/global/utils/timer.cpp b/src/global/utils/timer.cpp index b5f4408ca..249feb6f5 100644 --- a/src/global/utils/timer.cpp +++ b/src/global/utils/timer.cpp @@ -116,11 +116,12 @@ namespace timer { (timer.second / local_tot) * 100.0); timer_stats.insert( { name, - std::make_tuple(timer.second, - timer.second / static_cast(npart), - timer.second / static_cast(ncells), - pcent, - 0u) }); + std::make_tuple( + timer.second, + npart > 0 ? timer.second / static_cast(npart) : 0.0, + timer.second / static_cast(ncells), + pcent, + 0u) }); } timer_stats.insert({ "Total", std::make_tuple(local_tot, 0.0, 0.0, 100u, 0u) }); #endif From c1f5ab67174a2b075f8f335647b600fb3a578216 Mon Sep 17 00:00:00 2001 From: hayk Date: Sat, 30 Nov 2024 19:21:08 -0500 Subject: [PATCH 163/773] benchmark flow --- CMakeLists.txt | 3 +++ benchmark/benchmark.cpp | 35 +++++++++++++++++++++++++++++++++++ cmake/benchmark.cmake | 24 ++++++++++++++++++++++++ 3 files changed, 62 insertions(+) create mode 100644 benchmark/benchmark.cpp create mode 100644 cmake/benchmark.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 4ee00d1b4..2618a0cb2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -134,6 +134,9 @@ link_libraries(${DEPENDENCIES}) if(TESTS) # ---------------------------------- Tests --------------------------------- # include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/tests.cmake) +elseif(BENCHMARK) + # ------------------------------ Benchmark --------------------------------- # + include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/benchmark.cmake) else() # ----------------------------------- GUI ---------------------------------- # if(${gui}) diff --git a/benchmark/benchmark.cpp b/benchmark/benchmark.cpp new file mode 100644 index 000000000..b5a7631c4 --- /dev/null +++ b/benchmark/benchmark.cpp @@ -0,0 +1,35 @@ +#include "enums.h" +#include "global.h" + +#include "framework/containers/particles.h" + +auto main(int argc, char* argv[]) -> int { + ntt::GlobalInitialize(argc, argv); + // auto species = ntt::ParticleSpecies(1u, + // "test_e", + // 1.0f, + // 1.0f, + // 10000000, + // ntt::PrtlPusher::BORIS, + // false, + // ntt::Cooling::NONE); + ntt::GlobalFinalize(); + // * @param global_ndomains total number of domains + // * @param global_decomposition decomposition of the global domain + // * @param global_ncells number of cells in each dimension + // * @param global_extent physical extent of the global domain + // * @param global_flds_bc boundary conditions for fields + // * @param global_prtl_bc boundary conditions for particles + // * @param metric_params parameters for the metric + // * @param species_params parameters for the particle species + // Metadomain(unsigned int, + // const std::vector&, + // const std::vector&, + // const boundaries_t&, + // const boundaries_t&, + // const boundaries_t&, + // const std::map&, + // const std::vector&); + + return 0; +} diff --git a/cmake/benchmark.cmake b/cmake/benchmark.cmake new file mode 100644 index 000000000..d2e8ca47c --- /dev/null +++ b/cmake/benchmark.cmake @@ -0,0 +1,24 @@ +set(SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src) + +add_subdirectory(${SRC_DIR}/global ${CMAKE_CURRENT_BINARY_DIR}/global) +add_subdirectory(${SRC_DIR}/metrics ${CMAKE_CURRENT_BINARY_DIR}/metrics) +add_subdirectory(${SRC_DIR}/kernels ${CMAKE_CURRENT_BINARY_DIR}/kernels) +add_subdirectory(${SRC_DIR}/archetypes ${CMAKE_CURRENT_BINARY_DIR}/archetypes) +add_subdirectory(${SRC_DIR}/framework ${CMAKE_CURRENT_BINARY_DIR}/framework) + +if(${output}) + add_subdirectory(${SRC_DIR}/output ${CMAKE_CURRENT_BINARY_DIR}/output) + add_subdirectory(${SRC_DIR}/checkpoint ${CMAKE_CURRENT_BINARY_DIR}/checkpoint) +endif() + +set(exec benchmark.xc) +set(src ${CMAKE_CURRENT_SOURCE_DIR}/benchmark/benchmark.cpp) + +add_executable(${exec} ${src}) + +set(libs ntt_global ntt_metrics ntt_kernels ntt_archetypes ntt_framework) +if(${output}) + list(APPEND libs ntt_output ntt_checkpoint) +endif() +add_dependencies(${exec} ${libs}) +target_link_libraries(${exec} PRIVATE ${libs} stdc++fs) From 553bcae7d6fff7980815b1f510a5fef7271dd3db Mon Sep 17 00:00:00 2001 From: Siddhant Solanki Date: Mon, 2 Dec 2024 16:37:34 -0500 Subject: [PATCH 164/773] added new particle array --- src/framework/containers/particles.cpp | 9 +++++++++ src/framework/containers/particles.h | 4 ++++ 2 files changed, 13 insertions(+) diff --git a/src/framework/containers/particles.cpp b/src/framework/containers/particles.cpp index f0c64c4ee..c7f8f3b7c 100644 --- a/src/framework/containers/particles.cpp +++ b/src/framework/containers/particles.cpp @@ -47,6 +47,9 @@ namespace ntt { tag = array_t { label + "_tag", maxnpart }; tag_h = Kokkos::create_mirror_view(tag); + tag_offset = array_t { label + "_tag_offset", ntags() }; + tag_offset_h = Kokkos::create_mirror_view(tag_offset); + for (unsigned short n { 0 }; n < npld; ++n) { pld.push_back(array_t("pld", maxnpart)); pld_h.push_back(Kokkos::create_mirror_view(pld[n])); @@ -98,7 +101,13 @@ namespace ntt { std::vector npart_tag_vec; for (std::size_t t { 0 }; t < ntags(); ++t) { npart_tag_vec.push_back(npart_tag_host(t)); + tag_offset_h(t) = (t > 0) ? npart_tag_vec[t - 1] : 0; + } + for (std::size_t t { 0 }; t < ntags(); ++t) { + tag_offset_h(t) += (t > 0) ? tag_offset_h(t - 1) : 0; } + // Copy to device + Kokkos::deep_copy(tag_offset, tag_offset_h); return npart_tag_vec; } diff --git a/src/framework/containers/particles.h b/src/framework/containers/particles.h index b4831b64a..7496db78c 100644 --- a/src/framework/containers/particles.h +++ b/src/framework/containers/particles.h @@ -60,6 +60,8 @@ namespace ntt { array_t dx1_prev, dx2_prev, dx3_prev; // Array to tag the particles array_t tag; + // Array to store the cumulative number of particles per tag + array_t tag_offset; // Array to store the particle load std::vector> pld; // phi coordinate (for axisymmetry) @@ -72,6 +74,7 @@ namespace ntt { array_mirror_t weight_h; array_mirror_t phi_h; array_mirror_t tag_h; + array_mirror_t tag_offset_h; std::vector> pld_h; // for empty allocation @@ -178,6 +181,7 @@ namespace ntt { footprint += sizeof(prtldx_t) * dx2_prev.extent(0); footprint += sizeof(prtldx_t) * dx3_prev.extent(0); footprint += sizeof(short) * tag.extent(0); + footprint += sizeof(int) * tag_offset.extent(0); for (auto& p : pld) { footprint += sizeof(real_t) * p.extent(0); } From cffc563f664aeaceebe2e611945fb6852f9052e8 Mon Sep 17 00:00:00 2001 From: Siddhant Solanki Date: Mon, 2 Dec 2024 16:37:56 -0500 Subject: [PATCH 165/773] added new sendbuffer function --- src/framework/domain/comm_mpi.hpp | 144 +++++++++++++++++ src/framework/domain/communications.cpp | 195 ++++++++++++++++++++++++ src/framework/domain/metadomain.h | 1 + 3 files changed, 340 insertions(+) diff --git a/src/framework/domain/comm_mpi.hpp b/src/framework/domain/comm_mpi.hpp index 63dd8271a..2067ab9a4 100644 --- a/src/framework/domain/comm_mpi.hpp +++ b/src/framework/domain/comm_mpi.hpp @@ -316,6 +316,7 @@ namespace comm { } } + void ParticleSendRecvCount(int send_rank, int recv_rank, const std::size_t& send_count, @@ -441,6 +442,149 @@ namespace comm { return recv_count; } + + template + void CommunicateParticleQuantityBuffer( array_t& arr, + int send_rank, + int recv_rank, + const range_tuple_t& send_slice, + const range_tuple_t& recv_slice, + Kokkos::View indices_to_send, + Kokkos::View indices_to_allocate) { + + array_t buffer( "buffer", indices_to_send.size() + + indices_to_allocate.size()); + // Populate the buffer for particle array + Kokkos::parallel_for( + "PopulateBuffer", + Kokkos::RangePolicy(0, indices_to_send.size()), + KOKKOS_LAMBDA(const size_t i) { + const auto idx = indices_to_send(i); + buffer(i) = arr(idx); + }); + CommunicateParticleQuantity(buffer, send_rank, recv_rank, send_slice, recv_slice); + // Populate from buffer to the particle array + Kokkos::parallel_for( + "PopulateFromBuffer", + Kokkos::RangePolicy(0, indices_to_allocate.size()), + KOKKOS_LAMBDA(const size_t i) { + const auto idx = indices_to_allocate(i); + arr(idx) = buffer(indices_to_send.size() + i); + }); + return; + } + + + template + void CommunicateParticlesBuffer(Particles& species, + Kokkos::View indices_to_send, + Kokkos::View indices_to_allocate, + int send_rank, + int recv_rank, + std::vector shifts_in_x){ + if ((send_rank < 0) && (recv_rank < 0)) { + raise::Error("No send or recv in SendRecvParticlesBuffered", HERE); + } + // Construct send and receive slice for the buffer + auto send_slice = range_tuple_t({ 0, indices_to_send.size() }); + auto recv_slice = range_tuple_t({ indices_to_send.size(), indices_to_send.size() + + indices_to_allocate.size() }); + // Send and receive the particles + CommunicateParticleQuantityBuffer(species.i1, send_rank, recv_rank, send_slice, recv_slice, indices_to_send, indices_to_allocate); + CommunicateParticleQuantityBuffer(species.dx1, send_rank, recv_rank, send_slice, recv_slice, indices_to_send, indices_to_allocate); + CommunicateParticleQuantityBuffer(species.i1_prev, send_rank, recv_rank, send_slice, recv_slice, indices_to_send, indices_to_allocate); + CommunicateParticleQuantityBuffer(species.dx1_prev, send_rank, recv_rank, send_slice, recv_slice, indices_to_send, indices_to_allocate); + if constexpr (D == Dim::_2D || D == Dim::_3D) { + CommunicateParticleQuantityBuffer(species.i2, send_rank, recv_rank, send_slice, recv_slice, indices_to_send, indices_to_allocate); + CommunicateParticleQuantityBuffer(species.dx2, send_rank, recv_rank, send_slice, recv_slice, indices_to_send, indices_to_allocate); + CommunicateParticleQuantityBuffer(species.i2_prev, send_rank, recv_rank, send_slice, recv_slice, indices_to_send, indices_to_allocate); + CommunicateParticleQuantityBuffer(species.dx2_prev, send_rank, recv_rank, send_slice, recv_slice, indices_to_send, indices_to_allocate); + } + if constexpr (D == Dim::_3D) { + CommunicateParticleQuantityBuffer(species.i3, send_rank, recv_rank, send_slice, recv_slice, indices_to_send, indices_to_allocate); + CommunicateParticleQuantityBuffer(species.dx3, send_rank, recv_rank, send_slice, recv_slice, indices_to_send, indices_to_allocate); + CommunicateParticleQuantityBuffer(species.i3_prev, send_rank, recv_rank, send_slice, recv_slice, indices_to_send, indices_to_allocate); + CommunicateParticleQuantityBuffer(species.dx3_prev, send_rank, recv_rank, send_slice, recv_slice, indices_to_send, indices_to_allocate); + } + CommunicateParticleQuantityBuffer(species.ux1, send_rank, recv_rank, send_slice, recv_slice, indices_to_send, indices_to_allocate); + CommunicateParticleQuantityBuffer(species.ux2, send_rank, recv_rank, send_slice, recv_slice, indices_to_send, indices_to_allocate); + CommunicateParticleQuantityBuffer(species.ux3, send_rank, recv_rank, send_slice, recv_slice, indices_to_send, indices_to_allocate); + CommunicateParticleQuantityBuffer(species.weight, send_rank, recv_rank, send_slice, recv_slice, indices_to_send, indices_to_allocate); + if constexpr (D == Dim::_2D and C != Coord::Cart) { + CommunicateParticleQuantityBuffer(species.phi, send_rank, recv_rank, send_slice, recv_slice, indices_to_send, indices_to_allocate); + } + for (auto p { 0 }; p < species.npld(); ++p) { + CommunicateParticleQuantityBuffer(species.pld[p], send_rank, recv_rank, send_slice, recv_slice, indices_to_send, indices_to_allocate); + } + // Set the tag for the received particles to be alive and perform the necessary displacements + auto& this_tag = species.tag; + + if constexpr (D == Dim::_1D) + { + const auto shift_in_x1 = shifts_in_x[0]; + auto& this_i1 = species.i1; + auto& this_i1_prev = species.i1_prev; + Kokkos::parallel_for( + "SetTagAlive", + Kokkos::RangePolicy(0, indices_to_allocate.size()), + KOKKOS_LAMBDA(const size_t i) { + const auto idx = indices_to_allocate(i); + this_tag(idx) = static_cast(ParticleTag::alive); + this_i1(idx) += shift_in_x1; + this_i1_prev(idx) += shift_in_x1; + }); + } + + else if constexpr (D == Dim::_2D) + { + const auto shift_in_x1 = shifts_in_x[0]; + const auto shift_in_x2 = shifts_in_x[1]; + auto& this_i1 = species.i1; + auto& this_i2 = species.i2; + auto& this_i1_prev = species.i1_prev; + auto& this_i2_prev = species.i2_prev; + Kokkos::parallel_for( + "SetTagAlive", + Kokkos::RangePolicy(0, indices_to_allocate.size()), + KOKKOS_LAMBDA(const size_t i) { + const auto idx = indices_to_allocate(i); + this_tag(idx) = static_cast(ParticleTag::alive); + this_i1(idx) += shift_in_x1; + this_i2(idx) += shift_in_x2; + this_i1_prev(idx) += shift_in_x1; + this_i2_prev(idx) += shift_in_x2; + }); + } + + else if constexpr (D == Dim::_3D) + { + const auto shift_in_x1 = shifts_in_x[0]; + const auto shift_in_x2 = shifts_in_x[1]; + const auto shift_in_x3 = shifts_in_x[2]; + auto& this_i1 = species.i1; + auto& this_i2 = species.i2; + auto& this_i3 = species.i3; + auto& this_i1_prev = species.i1_prev; + auto& this_i2_prev = species.i2_prev; + auto& this_i3_prev = species.i3_prev; + Kokkos::parallel_for( + "SetTagAlive", + Kokkos::RangePolicy(0, indices_to_allocate.size()), + KOKKOS_LAMBDA(const size_t i) { + const auto idx = indices_to_allocate(i); + this_tag(idx) = static_cast(ParticleTag::alive); + this_i1(idx) += shift_in_x1; + this_i2(idx) += shift_in_x2; + this_i3(idx) += shift_in_x3; + this_i1_prev(idx) += shift_in_x1; + this_i2_prev(idx) += shift_in_x2; + this_i3_prev(idx) += shift_in_x3; + }); + } + return; + } + + } // namespace comm #endif // FRAMEWORK_DOMAIN_COMM_MPI_HPP diff --git a/src/framework/domain/communications.cpp b/src/framework/domain/communications.cpp index 60524eedd..f484f664d 100644 --- a/src/framework/domain/communications.cpp +++ b/src/framework/domain/communications.cpp @@ -646,6 +646,201 @@ namespace ntt { } } + +/* + New function to communicate particles using a buffer +*/ +template + void Metadomain::CommunicateParticlesBuffer(Domain& domain, + timer::Timers* timers) { + raise::ErrorIf(timers == nullptr, + "Timers not passed when Comm::Prtl called", + HERE); + logger::Checkpoint("Communicating particles\n", HERE); + for (auto& species : domain.species) { + const auto npart_per_tag_arr = species.npart_per_tag(); + const auto tag_offset = species.tag_offset_h; + auto index_last = tag_offset[tag_offset.size() - 1] + + npart_per_tag_arr[npart_per_tag_arr.size() - 1]; + std::vector send_ranks, send_inds; + std::vector recv_ranks, recv_inds; + // at this point particles should already by tagged in the pusher +#if defined(MPI_ENABLED) + timers->start("Communications_sendrecv"); + // array that holds the number of particles to be received per tag + std::vector npart_per_tag_arr_recv(npart_per_tag_arr.size(), 0); + std::size_t total_recv_count = 0; + const std::size_t total_send_count = species.npart() - npart_per_tag_arr[ParticleTag::alive]; + for (auto& direction : dir::Directions::all) { + const auto [send_params, + recv_params] = GetSendRecvParams(this, domain, direction, true); + const auto [send_indrank, send_slice] = send_params; + const auto [recv_indrank, recv_slice] = recv_params; + const auto [send_ind, send_rank] = send_indrank; + const auto [recv_ind, recv_rank] = recv_indrank; + if (send_rank < 0 and recv_rank < 0) { + continue; + } + const auto send_dir_tag = mpi::PrtlSendTag::dir2tag(direction); + const auto nsend = npart_per_tag_arr[send_dir_tag]; + std::size_t nrecv = 0; + // Get the receive count + send_ranks.push_back(send_rank); + recv_ranks.push_back(recv_rank); + send_inds.push_back(send_ind); + recv_inds.push_back(recv_ind); + comm::ParticleSendRecvCount(send_rank, + recv_rank, + nsend, + nrecv); + total_recv_count += nrecv; + npart_per_tag_arr_recv[mpi::PrtlSendTag::dir2tag(-direction)] = nrecv; + } + timers->stop("Communications_sendrecv"); + raise::FatalIf((index_last + total_recv_count) >= species.maxnpart(), + "Too many particles to receive (cannot fit into maxptl)", + HERE); + // Now we know the number of particles to be sent and received per direction + /* permute vector contains the indices of the tags to send and receive + in the order of the directions + E.g., consider the following tag array + [ 0, 0, 3, 0, 1,...] + Then, permute vector will look something like + [0, 1, 3, ..., 2, ..., 4, ... ] + |<--------- >| |<----->| |<----->| .... + tag=0 ct tag=1 ct tag=3 ct + (dead) (alive) (tag1) ... + */ + timers->start("PermuteVector"); + auto& this_tag = species.tag; + auto& this_tag_offset = species.tag_offset; + Kokkos::View permute_vector("permute_vector", species.npart()); + Kokkos::View current_offset("current_offset", species.ntags()); + Kokkos::parallel_for( + "PermuteVector", + species.npart(), + Lambda(const std::size_t p) { + auto current_tag = this_tag(p); + auto idx_permute_vec = this_tag_offset(current_tag) + current_offset(current_tag); + Kokkos::atomic_fetch_add(¤t_offset(current_tag), 1); + permute_vector(idx_permute_vec) = static_cast(p); + }); + timers->stop("PermuteVector"); + + // allocation_vector(p) assigns the pth received particle + // to the pth hole in the array, or after npart() if p > sent+dead count. + Kokkos::View allocation_vector("allocation_vector", total_recv_count); + auto allocation_vector_h = Kokkos::create_mirror_view(allocation_vector); + std::size_t n_alive = npart_per_tag_arr[ParticleTag::alive]; + std::size_t n_dead = npart_per_tag_arr[ParticleTag::dead]; + std::size_t n_holes = species.npart() - n_alive; + + timers->start("AllocationVector"); + Kokkos::parallel_for( + "AllocationVector", + total_recv_count, + Lambda(const std::size_t p) { + // Case: recevied particle count less than dead particle count -> replace dead particles + if (p < n_dead){ + allocation_vector(p) = permute_vector(p); + } + // Case: received particle count > dead particle count but < sent particle count -> replace + // sent particles + else if (p <= n_holes){ + allocation_vector(p) = permute_vector(n_alive + p); + } + // Case: received particle count exceeds sent + dead particles -> append at the end + else { + allocation_vector(p) = static_cast(index_last + (p - n_holes)); + } + }); + Kokkos::deep_copy(allocation_vector_h, allocation_vector); + timers->stop("AllocationVector"); + + std::size_t count_recv = 0; + std::size_t iteration = 0; + for (auto& direction : dir::Directions::all) { + // Get the coordinate shifts in xi + std::vector shifts_in_x; + auto recv_ind = recv_inds[iteration]; + if constexpr (D == Dim::_1D) { + int shift_in_x1 { 0 }; + if ((-direction)[0] == -1) { + shift_in_x1 = -subdomain(recv_ind).mesh.n_active(in::x1); + } else if ((-direction)[0] == 1) { + shift_in_x1 = domain.mesh.n_active(in::x1); + } + shifts_in_x.push_back(shift_in_x1); + } + else if constexpr (D == Dim::_2D) { + int shift_in_x1 { 0 }, shift_in_x2 { 0 }; + if ((-direction)[0] == -1) { + shift_in_x1 = -subdomain(recv_ind).mesh.n_active(in::x1); + } else if ((-direction)[0] == 1) { + shift_in_x1 = domain.mesh.n_active()[0]; + } + if ((-direction)[1] == -1) { + shift_in_x2 = -subdomain(recv_ind).mesh.n_active(in::x2); + } else if ((-direction)[1] == 1) { + shift_in_x2 = domain.mesh.n_active(in::x2); + } + shifts_in_x.push_back(shift_in_x1); + shifts_in_x.push_back(shift_in_x2); + } + else if constexpr (D == Dim::_3D) { + int shift_in_x1 { 0 }, shift_in_x2 { 0 }, shift_in_x3 { 0 }; + if ((-direction)[0] == -1) { + shift_in_x1 = -subdomain(recv_ind).mesh.n_active(in::x1); + } else if ((-direction)[0] == 1) { + shift_in_x1 = domain.mesh.n_active(in::x1); + } + if ((-direction)[1] == -1) { + shift_in_x2 = -subdomain(recv_ind).mesh.n_active(in::x2); + } else if ((-direction)[1] == 1) { + shift_in_x2 = domain.mesh.n_active(in::x2); + } + if ((-direction)[2] == -1) { + shift_in_x3 = -subdomain(recv_ind).mesh.n_active(in::x3); + } else if ((-direction)[2] == 1) { + shift_in_x3 = domain.mesh.n_active(in::x3); + } + shifts_in_x.push_back(shift_in_x1); + shifts_in_x.push_back(shift_in_x2); + shifts_in_x.push_back(shift_in_x3); + } + + auto range_permute = std::make_pair(static_cast(tag_offset[mpi::PrtlSendTag::dir2tag(direction)]), + static_cast(tag_offset[mpi::PrtlSendTag::dir2tag(direction)] + + npart_per_tag_arr[mpi::PrtlSendTag::dir2tag(direction)])); + + auto range_allocate = std::make_pair(static_cast(allocation_vector_h(count_recv)), + static_cast(allocation_vector_h(count_recv) + + npart_per_tag_arr_recv[mpi::PrtlSendTag::dir2tag(-direction)])); + + // contains the indices of the holes where the received particles will be placed + auto indices_to_allocate = Kokkos::subview(allocation_vector, range_allocate); + // contains the indices of all particles of a given tag = mpi::PrtlSendTag::dir2tag(direction) + auto indices_to_send = Kokkos::subview(permute_vector, range_permute); + + // Main function that sends the particles and receives the arrays + auto send_rank = send_ranks[iteration]; + auto recv_rank = recv_ranks[iteration]; + comm::CommunicateParticlesBuffer( species, + indices_to_send, + indices_to_allocate, + send_rank, + recv_rank, + shifts_in_x); + count_recv += npart_per_tag_arr_recv[mpi::PrtlSendTag::dir2tag(-direction)]; + iteration++; + } + species.set_npart(index_last + std::max(total_recv_count, total_send_count) - total_send_count); +#endif + } + } + + + template struct Metadomain>; template struct Metadomain>; template struct Metadomain>; diff --git a/src/framework/domain/metadomain.h b/src/framework/domain/metadomain.h index 7b3042b5b..e30bc8e97 100644 --- a/src/framework/domain/metadomain.h +++ b/src/framework/domain/metadomain.h @@ -89,6 +89,7 @@ namespace ntt { void CommunicateFields(Domain&, CommTags); void SynchronizeFields(Domain&, CommTags, const range_tuple_t& = { 0, 0 }); void CommunicateParticles(Domain&, timer::Timers*); + void CommunicateParticlesBuffer(Domain&, timer::Timers*); /** * @param global_ndomains total number of domains From 702b0137794fb05def96aa7efccae34efb1863da Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Tue, 3 Dec 2024 10:18:51 -0500 Subject: [PATCH 166/773] kernels/particle_pusher_gr: 1. derivatives of the metric in geodesic pusher now use their functional form. Saved numerical derivatives for future testing 2. Added placeholders for storing previous coordinate 3. Fixed bug in geodesic pusher in updating utheta 4. Changes to boundary conditions at the axis --- src/kernels/particle_pusher_gr.hpp | 62 ++++++++++++++++++++++-------- 1 file changed, 46 insertions(+), 16 deletions(-) diff --git a/src/kernels/particle_pusher_gr.hpp b/src/kernels/particle_pusher_gr.hpp index 2e9ddbde2..306f19013 100644 --- a/src/kernels/particle_pusher_gr.hpp +++ b/src/kernels/particle_pusher_gr.hpp @@ -334,31 +334,53 @@ namespace kernel::gr { // find contravariant midpoint velocity metric.template transform(xp, vp_mid, vp_mid_cntrv); - // find Gamma / alpha at midpoint + // find Gamma / alpha at midpointы real_t u0 { computeGamma(T {}, vp_mid, vp_mid_cntrv) / metric.alpha(xp) }; // find updated velocity + // vp_upd[0] = + // vp[0] + + // dt * + // (-metric.alpha(xp) * u0 * DERIVATIVE_IN_R(metric.alpha, xp) + + // vp_mid[0] * DERIVATIVE_IN_R(metric.beta1, xp) - + // (HALF / u0) * + // (DERIVATIVE_IN_R((metric.template h<1, 1>), xp) * SQR(vp_mid[0]) + + // DERIVATIVE_IN_R((metric.template h<2, 2>), xp) * SQR(vp_mid[1]) + + // DERIVATIVE_IN_R((metric.template h<3, 3>), xp) * SQR(vp_mid[2]) + + // TWO * DERIVATIVE_IN_R((metric.template h<1, 3>), xp) * + // vp_mid[0] * vp_mid[2])); + // vp_upd[1] = + // vp[1] + + // dt * + // (-metric.alpha(xp) * u0 * DERIVATIVE_IN_TH(metric.alpha, xp) + + // vp_mid[0] * DERIVATIVE_IN_TH(metric.beta1, xp) - + // (HALF / u0) * + // (DERIVATIVE_IN_TH((metric.template h<1, 1>), xp) * SQR(vp_mid[0]) + + // DERIVATIVE_IN_TH((metric.template h<2, 2>), xp) * SQR(vp_mid[1]) + + // DERIVATIVE_IN_TH((metric.template h<3, 3>), xp) * SQR(vp_mid[2]) + + // TWO * DERIVATIVE_IN_TH((metric.template h<1, 3>), xp) * + // vp_mid[0] * vp_mid[2])); vp_upd[0] = vp[0] + dt * - (-metric.alpha(xp) * u0 * DERIVATIVE_IN_R(metric.alpha, xp) + - vp_mid[0] * DERIVATIVE_IN_R(metric.beta1, xp) - + (-metric.alpha(xp) * u0 * metric.dr_alpha(xp) + + vp_mid[0] * metric.dr_beta1(xp) - (HALF / u0) * - (DERIVATIVE_IN_R((metric.template h<1, 1>), xp) * SQR(vp_mid[0]) + - DERIVATIVE_IN_R((metric.template h<2, 2>), xp) * SQR(vp_mid[1]) + - DERIVATIVE_IN_R((metric.template h<3, 3>), xp) * SQR(vp_mid[2]) + - TWO * DERIVATIVE_IN_R((metric.template h<1, 3>), xp) * + (metric.dr_h11(xp) * SQR(vp_mid[0]) + + metric.dr_h22(xp) * SQR(vp_mid[1]) + + metric.dr_h33(xp) * SQR(vp_mid[2]) + + TWO * metric.dr_h13(xp) * vp_mid[0] * vp_mid[2])); vp_upd[1] = vp[1] + dt * - (-metric.alpha(xp) * u0 * DERIVATIVE_IN_TH(metric.alpha, xp) + - vp_mid[1] * DERIVATIVE_IN_TH(metric.beta1, xp) - + (-metric.alpha(xp) * u0 * metric.dt_alpha(xp) + + vp_mid[0] * metric.dt_beta1(xp) - (HALF / u0) * - (DERIVATIVE_IN_TH((metric.template h<1, 1>), xp) * SQR(vp_mid[0]) + - DERIVATIVE_IN_TH((metric.template h<2, 2>), xp) * SQR(vp_mid[1]) + - DERIVATIVE_IN_TH((metric.template h<3, 3>), xp) * SQR(vp_mid[2]) + - TWO * DERIVATIVE_IN_TH((metric.template h<1, 3>), xp) * + (metric.dt_h11(xp) * SQR(vp_mid[0]) + + metric.dt_h22(xp) * SQR(vp_mid[1]) + + metric.dt_h33(xp) * SQR(vp_mid[2]) + + TWO * metric.dt_h13(xp) * vp_mid[0] * vp_mid[2])); } } else if constexpr (D == Dim::_3D) { @@ -656,9 +678,13 @@ namespace kernel::gr { dx2_prev(p) = dx2(p); coord_t xp { ZERO }; + coord_t xp_prev { ZERO }; xp[0] = i_di_to_Xi(i1(p), dx1(p)); xp[1] = i_di_to_Xi(i2(p), dx2(p)); + + xp_prev[0] = i_di_to_Xi(i1_prev(p), dx1_prev(p)); + xp_prev[1] = i_di_to_Xi(i2_prev(p), dx2_prev(p)); vec_t Dp_cntrv { ZERO }, Bp_cntrv { ZERO }, Dp_hat { ZERO }, Bp_hat { ZERO }; @@ -692,7 +718,7 @@ namespace kernel::gr { { (xp[0] + xp_upd[0]) * HALF, (xp[1] + xp_upd[1]) * HALF }, vp_upd, phi(p)); - + // update coordinate int i1_, i2_; prtldx_t dx1_, dx2_; @@ -726,12 +752,16 @@ namespace kernel::gr { } } if constexpr (D == Dim::_2D || D == Dim::_3D) { - if (i2(p) < 1) { + if (i2(p) < 0) { if (is_axis_i2min) { + i2(p) = 0; + dx2(p) = ONE - dx2(p); ux2(p) = -ux2(p); } - } else if (i2(p) >= ni2 - 1) { + } else if (i2(p) >= ni2) { if (is_axis_i2min) { + i2(p) = ni2 - 1; + dx2(p) = ONE - dx2(p); ux2(p) = -ux2(p); } } From b58ede49f3cb7e70ffee675088a3d58252362b32 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Tue, 3 Dec 2024 10:22:49 -0500 Subject: [PATCH 167/773] metrics: all gr metrics now have functional form of derivatives of the metric componets --- src/metrics/kerr_schild.h | 163 +++++++++++++++++++++++++++++ src/metrics/kerr_schild_0.h | 102 ++++++++++++++++++ src/metrics/qkerr_schild.h | 201 ++++++++++++++++++++++++++++++++++++ 3 files changed, 466 insertions(+) diff --git a/src/metrics/kerr_schild.h b/src/metrics/kerr_schild.h index 5a60def53..9ec6f7c98 100644 --- a/src/metrics/kerr_schild.h +++ b/src/metrics/kerr_schild.h @@ -17,6 +17,7 @@ #include "arch/kokkos_aliases.h" #include "utils/numeric.h" +#include "utils/comparators.h" #include "metrics/metric_base.h" @@ -216,6 +217,28 @@ namespace metric { return ONE / math::sqrt(ONE + z(r, theta)); } + /** + * dr derivative of lapse function + * @param x coordinate array in code units + */ + Inline auto dr_alpha(const coord_t& x) const -> real_t { + const real_t r {x[0] * dr + x1_min}; + const real_t theta {x[1] * dtheta + x2_min}; + const real_t dr_Sigma {TWO * r * dr}; + + return - (dr * Sigma(r, theta) - r * dr_Sigma) * CUBE(alpha(x)) / SQR(Sigma(r, theta)); + } + + /** + * dtheta derivative of lapse function + * @param x coordinate array in code units + */ + Inline auto dt_alpha(const coord_t& x) const -> real_t { + const real_t r {x[0] * dr + x1_min}; + const real_t theta {x[1] * dtheta + x2_min}; + return CUBE(alpha(x)) * r * dt_Sigma(theta) / SQR(Sigma(r, theta)); + } + /** * radial component of shift vector * @param x coordinate array in code units @@ -225,6 +248,146 @@ namespace metric { return dr_inv * z_ / (ONE + z_); } + /** + * dr derivative of radial component of shift vector + * @param x coordinate array in code units + */ + Inline auto dr_beta1(const coord_t& x) const -> real_t { + const real_t r {x[0] * dr + x1_min}; + const real_t theta {x[1] * dtheta + x2_min}; + const real_t dr_Sigma {TWO * r * dr}; + + return dr_inv * TWO * (dr * Sigma(r, theta) - r * dr_Sigma) / SQR(Sigma(r, theta) + TWO * r); + } + + /** + * dtheta derivative of radial component of shift vector + * @param x coordinate array in code units + */ + Inline auto dt_beta1(const coord_t& x) const -> real_t { + const real_t r {x[0] * dr + x1_min}; + const real_t theta {x[1] * dtheta + x2_min}; + return - dr_inv * TWO * r * dt_Sigma(theta) / SQR(Sigma(r, theta) * (ONE + z(r, theta))); + } + + /** + * dr derivative of h^11 + * @param x coordinate array in code units + */ + Inline auto dr_h11(const coord_t& x) const -> real_t { + const real_t r {x[0] * dr + x1_min}; + const real_t theta {x[1] * dtheta + x2_min}; + const real_t dr_Sigma {TWO * r * dr}; + const real_t dr_Delta {TWO * dr * (r - ONE)}; + const real_t dr_A {FOUR * r * dr * (SQR(r) + SQR(a)) - SQR(a) * SQR(math::sin(theta)) * dr_Delta}; + + return (Sigma(r, theta) * (Sigma(r, theta) + TWO * r) * dr_A + - TWO * A(r, theta) * (r * dr_Sigma + Sigma(r, theta) * (dr_Sigma + dr))) + / (SQR(Sigma(r, theta) * (Sigma(r, theta) + TWO * r))) * SQR(dr_inv); + } + + /** + * dr derivative of h^22 + * @param x coordinate array in code units + */ + Inline auto dr_h22(const coord_t& x) const -> real_t { + const real_t r {x[0] * dr + x1_min}; + const real_t theta {x[1] * dtheta + x2_min}; + const real_t dr_Sigma {TWO * r * dr}; + + return - dr_Sigma / SQR(Sigma(r, theta)) * SQR(dtheta_inv); + } + + /** + * dr derivative of h^33 + * @param x coordinate array in code units + */ + Inline auto dr_h33(const coord_t& x) const -> real_t { + const real_t r {x[0] * dr + x1_min}; + const real_t theta {x[1] * dtheta + x2_min}; + const real_t dr_Sigma {TWO * r * dr}; + + return - dr_Sigma / SQR(Sigma(r, theta)) / SQR(math::sin(theta)); + } + + /** + * dr derivative of h^13 + * @param x coordinate array in code units + */ + Inline auto dr_h13(const coord_t& x) const -> real_t { + const real_t r {x[0] * dr + x1_min}; + const real_t theta {x[1] * dtheta + x2_min}; + const real_t dr_Sigma {TWO * r * dr}; + + return - a * dr_Sigma / SQR(Sigma(r, theta)) * dr_inv; + } + + /** + * dtheta derivative of Sigma + * @param x coordinate array in code units + */ + Inline auto dt_Sigma(const real_t& theta) const -> real_t { + const real_t dt_Sigma {- TWO * SQR(a) * math::sin(theta) * math::cos(theta) * dtheta}; + if (cmp::AlmostZero(dt_Sigma)) + return ZERO; + else + return dt_Sigma; + } + + /** + * dtheta derivative of A + * @param x coordinate array in code units + */ + Inline auto dt_A(const real_t& r, const real_t& theta) const -> real_t { + const real_t dt_A {- TWO * SQR(a) * math::sin(theta) * math::cos(theta) * Delta(r) * dtheta}; + if (cmp::AlmostZero(dt_A)) + return ZERO; + else + return dt_A; + } + + /** + * dtheta derivative of h^11 + * @param x coordinate array in code units + */ + Inline auto dt_h11(const coord_t& x) const -> real_t { + const real_t r {x[0] * dr + x1_min}; + const real_t theta {x[1] * dtheta + x2_min}; + return (Sigma(r, theta) * (Sigma(r, theta) + TWO * r) * dt_A(r, theta) + - TWO * A(r, theta) * dt_Sigma(theta) * (r + Sigma(r, theta))) + / (SQR(Sigma(r, theta) * (Sigma(r, theta) + TWO * r))) * SQR(dr_inv); + } + + /** + * dtheta derivative of h^22 + * @param x coordinate array in code units + */ + Inline auto dt_h22(const coord_t& x) const -> real_t { + const real_t r {x[0] * dr + x1_min}; + const real_t theta {x[1] * dtheta + x2_min}; + return - dt_Sigma(theta) / SQR(Sigma(r, theta)) * SQR(dtheta_inv); + } + + /** + * dtheta derivative of h^33 + * @param x coordinate array in code units + */ + Inline auto dt_h33(const coord_t& x) const -> real_t { + const real_t r {x[0] * dr + x1_min}; + const real_t theta {x[1] * dtheta + x2_min}; + return - TWO * dtheta * math::cos(theta) * (Sigma(r, theta) - SQR(a) * SQR(math::sin(theta))) / CUBE(math::sin(theta)) / SQR(Sigma(r, theta)); + } + + /** + * dtheta derivative of h^13 + * @param x coordinate array in code units + */ + Inline auto dt_h13(const coord_t& x) const -> real_t { + const real_t r {x[0] * dr + x1_min}; + const real_t theta {x[1] * dtheta + x2_min}; + return - a * dt_Sigma(theta) / SQR(Sigma(r, theta)) * dr_inv; + } + /** * sqrt(det(h_ij)) * @param x coordinate array in code units diff --git a/src/metrics/kerr_schild_0.h b/src/metrics/kerr_schild_0.h index 31080ed4c..baea9b4c1 100644 --- a/src/metrics/kerr_schild_0.h +++ b/src/metrics/kerr_schild_0.h @@ -171,6 +171,22 @@ namespace metric { return ONE; } + /** + * dr derivative of lapse function + * @param x coordinate array in code units + */ + Inline auto dr_alpha(const coord_t& x) const -> real_t { + return ZERO; + } + + /** + * dtheta derivative of lapse function + * @param x coordinate array in code units + */ + Inline auto dt_alpha(const coord_t& x) const -> real_t { + return ZERO; + } + /** * radial component of shift vector * @param x coordinate array in code units @@ -179,6 +195,92 @@ namespace metric { return ZERO; } + /** + * dr derivative of radial component of shift vector + * @param x coordinate array in code units + */ + Inline auto dr_beta1(const coord_t& x) const -> real_t { + return ZERO; + } + + /** + * dtheta derivative of radial component of shift vector + * @param x coordinate array in code units + */ + Inline auto dt_beta1(const coord_t& x) const -> real_t { + return ZERO; + } + + /** + * dr derivative of h^11 + * @param x coordinate array in code units + */ + Inline auto dr_h11(const coord_t& x) const -> real_t { + return ZERO; + } + + /** + * dr derivative of h^22 + * @param x coordinate array in code units + */ + Inline auto dr_h22(const coord_t& x) const -> real_t { + const real_t r {x[0] * dr + x1_min}; + const real_t theta {x[1] * dtheta + x2_min}; + return - TWO / CUBE(r) * SQR(dtheta_inv) * dr; + } + + /** + * dr derivative of h^33 + * @param x coordinate array in code units + */ + Inline auto dr_h33(const coord_t& x) const -> real_t { + const real_t r {x[0] * dr + x1_min}; + const real_t theta {x[1] * dtheta + x2_min}; + return - TWO / CUBE(r) / SQR(math::sin(theta)) * dr; + } + + /** + * dr derivative of h^13 + * @param x coordinate array in code units + */ + Inline auto dr_h13(const coord_t& x) const -> real_t { + return ZERO; + } + + /** + * dtheta derivative of h^11 + * @param x coordinate array in code units + */ + Inline auto dt_h11(const coord_t& x) const -> real_t { + return ZERO; + } + + /** + * dtheta derivative of h^22 + * @param x coordinate array in code units + */ + Inline auto dt_h22(const coord_t& x) const -> real_t { + return ZERO; + } + + /** + * dtheta derivative of h^33 + * @param x coordinate array in code units + */ + Inline auto dt_h33(const coord_t& x) const -> real_t { + const real_t r {x[0] * dr + x1_min}; + const real_t theta {x[1] * dtheta + x2_min}; + return - TWO * math::cos(theta) / SQR(r) / CUBE(math::sin(theta)) * dtheta; + } + + /** + * dtheta derivative of h^13 + * @param x coordinate array in code units + */ + Inline auto dt_h13(const coord_t& x) const -> real_t { + return ZERO; + } + /** * sqrt(det(h_ij)) * @param x coordinate array in code units diff --git a/src/metrics/qkerr_schild.h b/src/metrics/qkerr_schild.h index 85507c6e1..e45376a24 100644 --- a/src/metrics/qkerr_schild.h +++ b/src/metrics/qkerr_schild.h @@ -234,6 +234,33 @@ namespace metric { return ONE / math::sqrt(ONE + z(r, theta)); } + /** + * dr derivative of lapse function + * @param x coordinate array in code units + */ + Inline auto dr_alpha(const coord_t& x) const -> real_t { + const real_t r { r0 + math::exp(x[0] * dchi + chi_min) }; + const real_t theta { eta2theta(x[1] * deta + eta_min) }; + const real_t dx_r {dchi * math::exp(x[0] * dchi + chi_min)}; + const real_t dr_Sigma {TWO * r * dx_r}; + + return - (dx_r * Sigma(r, theta) - r * dr_Sigma) * CUBE(alpha(x)) / SQR(Sigma(r, theta)); + } + + /** + * dtheta derivative of lapse function + * @param x coordinate array in code units + */ + Inline auto dt_alpha(const coord_t& x) const -> real_t { + const real_t r { r0 + math::exp(x[0] * dchi + chi_min) }; + const real_t eta {x[1] * deta + eta_min }; + const real_t theta { eta2theta(eta) }; + const real_t dx_dt {deta * (ONE + TWO * h0 * constant::INV_PI_SQR * (TWO * THREE * SQR(eta) - TWO * THREE * constant::PI * eta + constant::PI_SQR)) }; + const real_t dt_Sigma {- TWO * SQR(a) * math::sin(theta) * math::cos(theta) * dx_dt}; + + return r * dt_Sigma * CUBE(alpha(x)) / SQR(Sigma(r, theta)); + } + /** * radial component of shift vector * @param x coordinate array in code units @@ -246,6 +273,167 @@ namespace metric { return math::exp(-chi) * dchi_inv * z_ / (ONE + z_); } + /** + * dr derivative of radial component of shift vector + * @param x coordinate array in code units + */ + Inline auto dr_beta1(const coord_t& x) const -> real_t { + const real_t chi { x[0] * dchi + chi_min }; + const real_t r { r0 + math::exp(chi) }; + const real_t theta { eta2theta(x[1] * deta + eta_min) }; + const real_t z_ { z(r, theta) }; + const real_t dx_r {dchi * math::exp(x[0] * dchi + chi_min)}; + const real_t dr_Sigma {TWO * r * dx_r}; + + return math::exp(-chi) * dchi_inv * TWO * (dx_r * Sigma(r, theta) - r * dr_Sigma) / SQR(Sigma(r, theta) + TWO * r) + - dchi * math::exp(-chi) * dchi_inv * z_ / (ONE + z_); + } + + /** + * dr derivative of radial component of shift vector + * @param x coordinate array in code units + */ + Inline auto dt_beta1(const coord_t& x) const -> real_t { + const real_t chi { x[0] * dchi + chi_min }; + const real_t r { r0 + math::exp(chi) }; + const real_t eta {x[1] * deta + eta_min }; + const real_t theta { eta2theta(eta) }; + return - math::exp(-chi) * dchi_inv * TWO * r * dt_Sigma(eta) / SQR(Sigma(r, theta) * (ONE + z(r, theta))); + } + + /** + * dr derivative of h^11 + * @param x coordinate array in code units + */ + Inline auto dr_h11(const coord_t& x) const -> real_t { + const real_t r { r0 + math::exp(x[0] * dchi + chi_min) }; + const real_t theta { eta2theta(x[1] * deta + eta_min) }; + + const real_t dx_r {dchi * math::exp(x[0] * dchi + chi_min)}; + const real_t dr_Sigma {TWO * r * dx_r}; + const real_t dr_Delta {TWO * dx_r * (r - ONE)}; + const real_t dr_A {FOUR * r * dx_r * (SQR(r) + SQR(a)) - SQR(a) * SQR(math::sin(theta)) * dr_Delta}; + + return (math::exp(-TWO * (x[0] * dchi + chi_min)) / SQR(dchi) + * (Sigma(r, theta) * (Sigma(r, theta) + TWO * r) * dr_A + - TWO * A(r, theta) * (r * dr_Sigma + Sigma(r, theta) * (dr_Sigma + dx_r))) + / (SQR(Sigma(r, theta) * (Sigma(r, theta) + TWO * r))) ) + -TWO * dchi * math::exp(-TWO * (x[0] * dchi + chi_min)) / SQR(dchi) * A(r, theta) / (Sigma(r, theta) * (Sigma(r, theta) + TWO * r)); + } + + /** + * dr derivative of h^22 + * @param x coordinate array in code units + */ + Inline auto dr_h22(const coord_t& x) const -> real_t { + const real_t r { r0 + math::exp(x[0] * dchi + chi_min) }; + const real_t theta { eta2theta(x[1] * deta + eta_min) }; + const real_t dx_r {dchi * math::exp(x[0] * dchi + chi_min)}; + const real_t dr_Sigma {TWO * r * dx_r}; + + return - dr_Sigma / SQR(Sigma(r, theta)) / SQR(deta); + } + + /** + * dr derivative of h^33 + * @param x coordinate array in code units + */ + Inline auto dr_h33(const coord_t& x) const -> real_t { + const real_t r { r0 + math::exp(x[0] * dchi + chi_min) }; + const real_t theta { eta2theta(x[1] * deta + eta_min) }; + const real_t dx_r {dchi * math::exp(x[0] * dchi + chi_min)}; + const real_t dr_Sigma {TWO * r * dx_r}; + + return - dr_Sigma / SQR(Sigma(r, theta)) / SQR(math::sin(theta)); + } + + /** + * dr derivative of h^13 + * @param x coordinate array in code units + */ + Inline auto dr_h13(const coord_t& x) const -> real_t { + const real_t r { r0 + math::exp(x[0] * dchi + chi_min) }; + const real_t theta { eta2theta(x[1] * deta + eta_min) }; + const real_t dx_r {dchi * math::exp(x[0] * dchi + chi_min)}; + const real_t dr_Sigma {TWO * r * dx_r}; + + return - a * dr_Sigma / SQR(Sigma(r, theta)) * (math::exp(-(x[0] * dchi + chi_min)) * dchi_inv) + - dchi * (math::exp(-(x[0] * dchi + chi_min)) * dchi_inv) * a / Sigma(r, theta); + } + + /** + * dtheta derivative of Sigma + * @param x coordinate array in code units + */ + Inline auto dt_Sigma(const real_t& eta) const -> real_t { + const real_t theta { eta2theta(eta) }; + const real_t dt_Sigma {- TWO * SQR(a) * math::sin(theta) * math::cos(theta) * dx_dt(eta)}; + if (cmp::AlmostZero(dt_Sigma)) + return ZERO; + else + return dt_Sigma; + } + + /** + * dtheta derivative of A + * @param x coordinate array in code units + */ + Inline auto dt_A(const real_t& r, const real_t& eta) const -> real_t { + const real_t theta { eta2theta(eta) }; + const real_t dt_A {- TWO * SQR(a) * math::sin(theta) * math::cos(theta) * Delta(r) * dx_dt(eta)}; + if (cmp::AlmostZero(dt_A)) + return ZERO; + else + return dt_A; + } + + /** + * dtheta derivative of h^11 + * @param x coordinate array in code units + */ + Inline auto dt_h11(const coord_t& x) const -> real_t { + const real_t r { r0 + math::exp(x[0] * dchi + chi_min) }; + const real_t eta {x[1] * deta + eta_min }; + const real_t theta { eta2theta(eta) }; + return math::exp(-TWO * (x[0] * dchi + chi_min)) / SQR(dchi) + * (Sigma(r, theta) * (Sigma(r, theta) + TWO * r) * dt_A(r, eta) + - TWO * A(r, theta) * dt_Sigma(eta) * (r + Sigma(r, theta))) + / (SQR(Sigma(r, theta) * (Sigma(r, theta) + TWO * r))); + } + + /** + * dtheta derivative of h^22 + * @param x coordinate array in code units + */ + Inline auto dt_h22(const coord_t& x) const -> real_t { + const real_t r { r0 + math::exp(x[0] * dchi + chi_min) }; + const real_t eta {x[1] * deta + eta_min }; + const real_t theta { eta2theta(eta) }; + return - dt_Sigma(eta) / SQR(Sigma(r, theta)) / SQR(deta); + } + + /** + * dtheta derivative of h^33 + * @param x coordinate array in code units + */ + Inline auto dt_h33(const coord_t& x) const -> real_t { + const real_t r { r0 + math::exp(x[0] * dchi + chi_min) }; + const real_t eta {x[1] * deta + eta_min }; + const real_t theta { eta2theta(eta) }; + return - (dt_Sigma(eta) + TWO * math::cos(theta) / math::sin(theta) * Sigma(r, theta) * dx_dt(eta)) / SQR(Sigma(r, theta) * math::sin(theta)); + } + + /** + * dtheta derivative of h^13 + * @param x coordinate array in code units + */ + Inline auto dt_h13(const coord_t& x) const -> real_t { + const real_t r { r0 + math::exp(x[0] * dchi + chi_min) }; + const real_t eta {x[1] * deta + eta_min }; + const real_t theta { eta2theta(eta) }; + return - a * dt_Sigma(eta) / SQR(Sigma(r, theta)) * (math::exp(-(x[0] * dchi + chi_min)) * dchi_inv); + } + /** * sqrt(det(h_ij)) * @param x coordinate array in code units @@ -456,6 +644,19 @@ namespace metric { } } + /** + * @brief quasi-spherical eta to spherical theta + */ + Inline auto dx_dt(const real_t& eta) const -> real_t { + if (cmp::AlmostZero(h0)) { + return deta; + } else { + return deta * (ONE + + TWO * h0 * constant::INV_PI_SQR * + (TWO * THREE * SQR(eta) - TWO * THREE * constant::PI * eta + constant::PI_SQR)); + } + } + /** * @brief spherical theta to quasi-spherical eta */ From 2edb1972c037b1147be91b4e759d86b29cb69605 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Tue, 3 Dec 2024 10:24:38 -0500 Subject: [PATCH 168/773] setups/grpic/pusher: pgen and inputs for pusher tests --- setups/grpic/pusher/boris.toml | 97 +++++++++ setups/grpic/pusher/massive_gravity_3d.toml | 84 ++++++++ setups/grpic/pusher/massive_gravity_a0.toml | 93 +++++++++ .../grpic/pusher/massive_gravity_a0995.toml | 93 +++++++++ setups/grpic/pusher/pgen.hpp | 184 ++++++++++++++++++ 5 files changed, 551 insertions(+) create mode 100644 setups/grpic/pusher/boris.toml create mode 100644 setups/grpic/pusher/massive_gravity_3d.toml create mode 100644 setups/grpic/pusher/massive_gravity_a0.toml create mode 100644 setups/grpic/pusher/massive_gravity_a0995.toml create mode 100644 setups/grpic/pusher/pgen.hpp diff --git a/setups/grpic/pusher/boris.toml b/setups/grpic/pusher/boris.toml new file mode 100644 index 000000000..6483eb2c6 --- /dev/null +++ b/setups/grpic/pusher/boris.toml @@ -0,0 +1,97 @@ +[simulation] + name = "boris_a0" + engine = "grpic" + runtime = 100.0 + +[grid] + resolution = [128,128] + extent = [[0.9, 20.0]] + + [grid.metric] + metric = "qkerr_schild" + qsph_r0 = 0.0 + qsph_h = 0.0 + ks_a = 0.0 + + [grid.boundaries] + fields = [["ABSORB"]] + particles = [["ABSORB"]] + + [grid.boundaries.absorb] + ds = 0.5 + +[scales] + larmor0 = 5.0 + skindepth0 = 1e-3 + +[algorithms] + current_filters = 4 + + [algorithms.gr] + pusher_niter = 10 + pusher_eps = 1e-6 + + [algorithms.timestep] + CFL = 0.1 + + [algorithms.toggles] + deposit = false + fieldsolver = false + +[particles] + ppc0 = 1.0 + + [[particles.species]] + label = "e-" + mass = 1.0 + charge = -1.0 + maxnpart = 1e0 + + [[particles.species]] + label = "e+" + mass = 1.0 + charge = -1.0 + maxnpart = 1e1 + +[setup] + x1s = [5.77] + y1s = [1.570796] + z1s = [0.000000] + ux1s = [0.4376657824933686] + uy1s = [0.000000] + uz1s = [4.0] +# x1s = [10.0] +# y1s = [1.570796] +# z1s = [0.000000] +# ux1s = [0.0] +# uy1s = [0.000000] +# uz1s = [10.00000] + + #x2s = [7.5] + #y2s = [0.15745454545454546] + #z2s = [0.000000] + #ux2s = [0.029637] + #uy2s = [0.000000] + #uz2s = [3.75] + +[output] + format = "hdf5" + + [output.fields] + enable = true + interval_time = 1.0 + quantities = ["D", "B"] + + [output.particles] + enable = true + stride = 1 + interval_time = 0.2 + species = [] + + [output.spectra] + enable = false + +[diagnostics] + interval = 10 + colored_stdout = true + blocking_timers = true diff --git a/setups/grpic/pusher/massive_gravity_3d.toml b/setups/grpic/pusher/massive_gravity_3d.toml new file mode 100644 index 000000000..5b87554b2 --- /dev/null +++ b/setups/grpic/pusher/massive_gravity_3d.toml @@ -0,0 +1,84 @@ +[simulation] + name = "massive_3d" + engine = "grpic" + runtime = 1000.0 + +[grid] + resolution = [128, 128] + extent = [[0.1, 15.0]] + + [grid.metric] + metric = "qkerr_schild" + qsph_r0 = 0.0 + qsph_h = 0.0 + ks_a = 0.995 + + [grid.boundaries] + fields = [["ABSORB"]] + particles = [["ABSORB"]] + + [grid.boundaries.absorb] + ds = 0.5 + +[scales] + larmor0 = 2e-3 + skindepth0 = 0.1 + +[algorithms] + current_filters = 4 + + [algorithms.gr] + pusher_niter = 20 + pusher_eps = 1e-3 + + [algorithms.timestep] + CFL = 0.8 + + [algorithms.toggles] + deposit = false + fieldsolver = false + +[particles] + ppc0 = 4.0 + + [[particles.species]] + label = "e-" + mass = 1.0 + charge = 0.0 + maxnpart = 1e1 + + [[particles.species]] + label = "e+" + mass = 1.0 + charge = 0.0 + maxnpart = 1e1 + +[setup] + x1s = [10.00000] + y1s = [1.570796] + z1s = [0.000000] + ux1s = [0.2181435531189523] + uy1s = [2.89] + uz1s = [1.05769] + +[output] + format = "hdf5" + + [output.fields] + enable = true + interval_time = 5.0 + quantities = ["D", "B"] + + [output.particles] + enable = true + stride = 1 + interval_time = 0.5 + species = [] + + [output.spectra] + enable = false + +[diagnostics] + interval = 10 + colored_stdout = true + blocking_timers = true diff --git a/setups/grpic/pusher/massive_gravity_a0.toml b/setups/grpic/pusher/massive_gravity_a0.toml new file mode 100644 index 000000000..08b607d4b --- /dev/null +++ b/setups/grpic/pusher/massive_gravity_a0.toml @@ -0,0 +1,93 @@ +[simulation] + name = "massive_a0" + engine = "grpic" + runtime = 500.0 + +[grid] + resolution = [256,256] + extent = [[1.2, 15.0]] + + [grid.metric] + metric = "qkerr_schild" + qsph_r0 = 0.0 + qsph_h = 0.0 + ks_a = 0.0 + + [grid.boundaries] + fields = [["ABSORB"]] + particles = [["ABSORB"]] + + [grid.boundaries.absorb] + ds = 0.5 + +[scales] + larmor0 = 2e-3 + skindepth0 = 0.1 + +[algorithms] + current_filters = 4 + + [algorithms.gr] + pusher_niter = 10 + pusher_eps = 1e-3 + + [algorithms.timestep] + CFL = 0.8 + + [algorithms.toggles] + deposit = false + fieldsolver = false + +[particles] + ppc0 = 4.0 + + [[particles.species]] + label = "e-" + mass = 1.0 + charge = 0.0 + maxnpart = 1e1 + + [[particles.species]] + label = "e+" + mass = 1.0 + charge = 0.0 + maxnpart = 1e1 + +[setup] + # (1,2,0) from Levin&Perez-Giz (2008) + x1s = [9.85180645] + y1s = [1.570796] + z1s = [0.5235987755982988] + ux1s = [0.24159816] + uy1s = [3.535534] + uz1s = [0.000000] + + # (4,1,1) from Levin&Perez-Giz (2008) + x2s = [68.600387] + y2s = [1.570796] + z2s = [0.000000] + ux2s = [0.029637] + uy2s = [0.000000] + uz2s = [3.900000] + +[output] + format = "hdf5" + + [output.fields] + enable = true + interval_time = 1.0 + quantities = ["D", "B"] + + [output.particles] + enable = true + stride = 1 + interval_time = 1.0 + species = [] + + [output.spectra] + enable = false + +[diagnostics] + interval = 10 + colored_stdout = true + blocking_timers = true diff --git a/setups/grpic/pusher/massive_gravity_a0995.toml b/setups/grpic/pusher/massive_gravity_a0995.toml new file mode 100644 index 000000000..b04538e10 --- /dev/null +++ b/setups/grpic/pusher/massive_gravity_a0995.toml @@ -0,0 +1,93 @@ +[simulation] + name = "massive_a0995" + engine = "grpic" + runtime = 2000.0 + +[grid] + resolution = [512, 512] + extent = [[0.9, 15.0]] + + [grid.metric] + metric = "kerr_schild" + qsph_r0 = 0.0 + qsph_h = 0.0 + ks_a = 0.0 + + [grid.boundaries] + fields = [["ABSORB"]] + particles = [["ABSORB"]] + + [grid.boundaries.absorb] + ds = 0.5 + +[scales] + larmor0 = 2e-3 + skindepth0 = 0.1 + +[algorithms] + current_filters = 4 + + [algorithms.gr] + pusher_niter = 10 + pusher_eps = 1e-10 + + [algorithms.timestep] + CFL = 6.0 + + [algorithms.toggles] + deposit = false + fieldsolver = false + +[particles] + ppc0 = 4.0 + + [[particles.species]] + label = "e-" + mass = 1.0 + charge = 0.0 + maxnpart = 1e1 + + [[particles.species]] + label = "e+" + mass = 1.0 + charge = 0.0 + maxnpart = 1e1 + +[setup] + # (2,3,1) from Levin&Perez-Giz (2008) + x1s = [10.343515586064923] + y1s = [1.570796] + z1s = [0.000000] + ux1s = [0.19483849893499136] + uy1s = [0.000000] + uz1s = [2.000000] + + # (~1000, 3, ~671) from Levin&Perez-Giz (2008) + x2s = [10.64975354] + y2s = [1.570796] + z2s = [0.000000] + ux2s = [0.18914503] + uy2s = [0.000000] + uz2s = [2.000000] + +[output] + format = "hdf5" + + [output.fields] + enable = true + interval_time = 5.0 + quantities = ["D", "B"] + + [output.particles] + enable = true + stride = 1 + interval_time = 2.0 + species = [] + + [output.spectra] + enable = false + +[diagnostics] + interval = 10 + colored_stdout = true + blocking_timers = true diff --git a/setups/grpic/pusher/pgen.hpp b/setups/grpic/pusher/pgen.hpp new file mode 100644 index 000000000..d6a29a185 --- /dev/null +++ b/setups/grpic/pusher/pgen.hpp @@ -0,0 +1,184 @@ +#ifndef PROBLEM_GENERATOR_H +#define PROBLEM_GENERATOR_H + +#include "enums.h" +#include "global.h" + +#include "arch/kokkos_aliases.h" +#include "arch/traits.h" +#include "utils/comparators.h" +#include "utils/formatting.h" +#include "utils/log.h" +#include "utils/numeric.h" + +#include "archetypes/problem_generator.h" +#include "framework/domain/metadomain.h" +#include "framework/domain/domain.h" +#include "archetypes/energy_dist.h" +#include "archetypes/particle_injector.h" + +#include + +namespace user { + using namespace ntt; + + template + struct InitFields { + InitFields(M metric_) : metric { metric_ } {} + + Inline auto A_3(const coord_t& x_Cd) const -> real_t { + // return HALF * (metric.template h_<3, 3>(x_Cd) ); + // + TWO * metric.spin() * metric.template h_<1, 3>(x_Cd) * metric.beta1(x_Cd) + // ); + coord_t x_Ph { ZERO }; + metric.template convert(x_Cd, x_Ph); + return HALF * SQR(x_Ph[0]) * SQR(math::sin(x_Ph[1])); + } + + Inline auto A_1(const coord_t& x_Cd) const -> real_t { + return HALF * (metric.template h_<1, 3>(x_Cd) + + TWO * metric.spin() * metric.template h_<1, 1>(x_Cd) * metric.beta1(x_Cd) + ); + } + + Inline auto A_0(const coord_t& x_Cd) const -> real_t { + real_t g_00 { -metric.alpha(x_Cd) * metric.alpha(x_Cd) + + metric.template h_<1, 1>(x_Cd) * metric.beta1(x_Cd) * metric.beta1(x_Cd) + }; + return HALF * (metric.template h_<1, 3>(x_Cd) * metric.beta1(x_Cd) + + TWO * metric.spin() * g_00); + } + + Inline auto bx1(const coord_t& x_Ph) const -> real_t { + coord_t xi {ZERO}, x0m { ZERO }, x0p { ZERO }; + metric.template convert(x_Ph, xi); + + x0m[0] = xi[0]; + x0m[1] = xi[1] - HALF; + x0p[0] = xi[0]; + x0p[1] = xi[1] + HALF; + + real_t inv_sqrt_detH_ijP { ONE / metric.sqrt_det_h({ xi[0], xi[1] }) }; + + if (cmp::AlmostZero(x_Ph[1])) + return ONE; + else + return (A_3(x0p) - A_3(x0m)) * inv_sqrt_detH_ijP; + // return ZERO; + } + + Inline auto bx2(const coord_t& x_Ph) const -> real_t { + coord_t xi {ZERO}, x0m { ZERO }, x0p { ZERO }; + metric.template convert(x_Ph, xi); + + x0m[0] = xi[0] + HALF - HALF; + x0m[1] = xi[1]; + x0p[0] = xi[0] + HALF + HALF; + x0p[1] = xi[1]; + + real_t inv_sqrt_detH_ijP { ONE / metric.sqrt_det_h({ xi[0], xi[1] }) }; + if (cmp::AlmostZero(x_Ph[1])) + return ZERO; + else + return -(A_3(x0p) - A_3(x0m)) * inv_sqrt_detH_ijP; + // return ZERO; + } + + Inline auto bx3(const coord_t& x_Ph) const -> real_t { + // coord_t xi {ZERO}, x0m { ZERO }, x0p { ZERO }; + // metric.template convert(x_Ph, xi); + + // x0m[0] = xi[0] + HALF - HALF; + // x0m[1] = xi[1]; + // x0p[0] = xi[0] + HALF + HALF; + // x0p[1] = xi[1]; + + // real_t inv_sqrt_detH_ijP { ONE / metric.sqrt_det_h({ xi[0], xi[1] }) }; + // return -(A_1(x0p) - A_1(x0m)) * inv_sqrt_detH_ijP; + return ZERO; + } + + Inline auto dx1(const coord_t& x_Ph) const -> real_t { + return ZERO; + } + + Inline auto dx2(const coord_t& x_Ph) const -> real_t { + return ZERO; + } + + Inline auto dx3(const coord_t& x_Ph) const -> real_t { + return ZERO; + } + + private: + const M metric; + }; + + template + struct PGen : public arch::ProblemGenerator { + // compatibility traits for the problem generator + static constexpr auto engines { traits::compatible_with::value }; + static constexpr auto metrics { + traits::compatible_with::value + }; + static constexpr auto dimensions { traits::compatible_with::value }; + + // for easy access to variables in the child class + using arch::ProblemGenerator::D; + using arch::ProblemGenerator::C; + using arch::ProblemGenerator::params; + + InitFields init_flds; + const Metadomain& global_domain; + inline PGen(const SimulationParams& p, const Metadomain& m) + : arch::ProblemGenerator { p } + , global_domain { m } + , init_flds { m.mesh().metric } {} + + inline void InitPrtls(Domain& local_domain) { + const auto empty = std::vector {}; + const auto x1s = params.template get>("setup.x1s", empty); + const auto y1s = params.template get>("setup.y1s", empty); + const auto z1s = params.template get>("setup.z1s", empty); + const auto ux1s = params.template get>("setup.ux1s", + empty); + const auto uy1s = params.template get>("setup.uy1s", + empty); + const auto uz1s = params.template get>("setup.uz1s", + empty); + + const auto x2s = params.template get>("setup.x2s", empty); + const auto y2s = params.template get>("setup.y2s", empty); + const auto z2s = params.template get>("setup.z2s", empty); + const auto ux2s = params.template get>("setup.ux2s", + empty); + const auto uy2s = params.template get>("setup.uy2s", + empty); + const auto uz2s = params.template get>("setup.uz2s", + empty); + const std::map> data_1 { + { "x1", x1s}, + { "x2", y1s}, + { "phi", z1s}, + {"ux1", ux1s}, + {"ux2", uy1s}, + {"ux3", uz1s} + }; + const std::map> data_2 { + { "x1", x2s}, + { "x2", y2s}, + { "phi", z2s}, + {"ux1", ux2s}, + {"ux2", uy2s}, + {"ux3", uz2s} + }; + + arch::InjectGlobally(global_domain, local_domain, (arch::spidx_t)1, data_1); + arch::InjectGlobally(global_domain, local_domain, (arch::spidx_t)2, data_2); + } + // inline PGen() {} + }; + +} // namespace user + +#endif From 796cfcbb979240d094fa039a28a780d2be5ad99f Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Tue, 3 Dec 2024 12:28:14 -0500 Subject: [PATCH 169/773] engines/grpic: added timestep correction for gr pusher --- src/engines/grpic.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index 40e2776e0..4c2278f1f 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -1001,9 +1001,9 @@ namespace ntt { ? species.charge() / species.mass() : ZERO; // coeff = q / m (dt / 2) omegaB0 - const auto coeff = q_ovr_m * HALF * dt * - m_params.template get("scales.omegaB0"); - + const auto coeff = q_ovr_m * HALF * dt * m_params.template get( + "algorithms.timestep.correction") * + m_params.template get("scales.omegaB0"); // clang-format off if (species.pusher() == PrtlPusher::PHOTON) { From 3c55ee7e4fc6255a2dcc772ab75b067df11281b1 Mon Sep 17 00:00:00 2001 From: Siddhant Solanki Date: Tue, 3 Dec 2024 15:57:16 -0500 Subject: [PATCH 170/773] fixed bug in CommunicateParticlesBuffer and created metadomain object in benchmark.cpp --- benchmark/benchmark.cpp | 183 ++++++++++++++++++++---- src/framework/domain/comm_mpi.hpp | 15 +- src/framework/domain/communications.cpp | 44 +++--- 3 files changed, 193 insertions(+), 49 deletions(-) diff --git a/benchmark/benchmark.cpp b/benchmark/benchmark.cpp index b5a7631c4..5ab9124f0 100644 --- a/benchmark/benchmark.cpp +++ b/benchmark/benchmark.cpp @@ -1,35 +1,170 @@ #include "enums.h" #include "global.h" +#include "utils/timer.h" +#include "utils/error.h" +#include "framework/domain/domain.h" +#include "framework/domain/metadomain.h" #include "framework/containers/particles.h" +#include "metrics/metric_base.h" +#include "metrics/minkowski.h" +#include "arch/mpi_tags.h" + +#include + +/* + Test to check the performance of the new particle allocation scheme + - Create a metadomain object + - Create particle array + - Initialize the position and velocities of the particles + - Set a large timestep (see where that is set) + - Make a loop of N iterations, where the positions of particles is sorted + and pushed + - Check if the particle tags are correct after each iteration + - Compute the time taken for best of N iterations for the communication + */ + + +/* + Structure of the 2D domain + ---------------------------------- (3,3) + | | | | + | | | | + | | | | + | | | | + ---------------------------------- (3,2) + | | | | + | | | | + | | | | + | | | | + ---------------------------------- (3,1) + | | | | + | | | | + | | | | + | | | | + ---------------------------------- + (0,0) (1,0) (2,0) (3,0) +*/ + +/* + Function to check the tags of a domain object to make sure that + all the tags are alive. If the tags are not alive then the function + prints the tag count for each of the particles along with the rank + of the domain. +*/ +template +void CheckDomainTags(Domain& domain, + timer::Timers* timers) +{ + bool all_alive = true; + bool no_dead_particles = true; + bool tag_check = true; + for (auto& species : domain.species) { + std::cout << "Checking domain tags for species: " << species.label << std::endl; + const auto npart_per_tag_arr = species.npart_per_tag(); + const auto npart = species.npart(); + if (npart != npart_per_tag_arr[ParticleTag::alive]){ + all_alive = false; + } + for (std::size_t i = 0; i < npart_per_tag_arr.size(); ++i) { + if (i == ParticleTag::alive) { + continue; + } + if (npart_per_tag_arr[i] != 0) { + no_dead_particles = false; + } + } + auto this_tag = species.tag; + Kokkos::parallel_for("CheckTags", + npart, Lambda(const std::size_t i) { + if (this_tag(i) != ParticleTag::alive) { + tag_check = false; + } + }); + raise::ErrorIf(all_alive == false, + "Array contains particles with tags other than alive", + HERE); + raise::ErrorIf(no_dead_particles == false, + "Array contains dead particles", + HERE); + raise::ErrorIf(tag_check == false, + "Tag check failed", + HERE); + } + return; +} + + auto main(int argc, char* argv[]) -> int { + std::cout << "Constructing the domain" << std::endl; ntt::GlobalInitialize(argc, argv); - // auto species = ntt::ParticleSpecies(1u, - // "test_e", - // 1.0f, - // 1.0f, - // 10000000, - // ntt::PrtlPusher::BORIS, - // false, - // ntt::Cooling::NONE); + // Create a Metadomain object + const unsigned int ndomains = 9; + const std::vector global_decomposition = {-1, -1}; + const std::vector global_ncells = {32, 32}; + const boundaries_t global_extent = {{0.0, 0.0}, {3.0, 3.0}}; + const boundaries_t global_flds_bc = {{FldsBC::PERIODIC, FldsBC::PERIODIC}, {FldsBC::PERIODIC, FldsBC::PERIODIC}}; + const boundaries_t global_prtl_bc = {{PrtlBC::PERIODIC, PrtlBC::PERIODIC}, {PrtlBC::PERIODIC, PrtlBC::PERIODIC}}; + const std::map metric_params = {}; + const int npart = 10000; + auto species = ntt::Particles(1u, + "test_e", + 1.0f, + 1.0f, + npart, + ntt::PrtlPusher::BORIS, + false, + ntt::Cooling::NONE); + auto metadomain = Metadomain> + ( + ndomains, + global_decomposition, + global_ncells, + global_extent, + global_flds_bc, + global_prtl_bc, + metric_params, + {species} + ); + // Get the pointers to all the subdomains + const auto local_subdomain_idx = metadomain.l_subdomain_indices()[0]; + auto local_domain = metadomain.subdomain_ptr(local_subdomain_idx); + + // Set the positions of the particles in each domain + for (auto& species : local_domain->species) + { + auto tag = ParticleTag::alive; + auto &this_i1 = species.i1; + auto &this_i2 = species.i2; + auto &this_i3 = species.i3; + auto &this_dx1 = species.dx1; + auto &this_dx2 = species.dx2; + auto &this_dx3 = species.dx3; + auto &this_ux1 = species.ux1; + auto &this_ux2 = species.ux2; + auto &this_ux3 = species.ux3; + auto &this_tag = species.tag; + Kokkos::parallel_for("SetPositions", + species.npart(), Lambda(const std::size_t i) { + this_i1(i) = 1; + this_i2(i) = 1; + this_dx1(i) = 0.01; + this_dx2(i) = 0.01; + this_ux1(i) = 0.5; + this_ux2(i) = 0.5; + this_tag(i) = tag; + }); + } + + + // Print the number of particles per domain + std::cout << "Number of particles in domain " << local_subdomain_idx << ": " << local_domain->species[0].npart() << std::endl; + // Print the position of the 5 particles in the domain + ntt::GlobalFinalize(); - // * @param global_ndomains total number of domains - // * @param global_decomposition decomposition of the global domain - // * @param global_ncells number of cells in each dimension - // * @param global_extent physical extent of the global domain - // * @param global_flds_bc boundary conditions for fields - // * @param global_prtl_bc boundary conditions for particles - // * @param metric_params parameters for the metric - // * @param species_params parameters for the particle species - // Metadomain(unsigned int, - // const std::vector&, - // const std::vector&, - // const boundaries_t&, - // const boundaries_t&, - // const boundaries_t&, - // const std::map&, - // const std::vector&); + + std::cout << "Terminating" << std::endl; return 0; } diff --git a/src/framework/domain/comm_mpi.hpp b/src/framework/domain/comm_mpi.hpp index 2067ab9a4..ed73302b2 100644 --- a/src/framework/domain/comm_mpi.hpp +++ b/src/framework/domain/comm_mpi.hpp @@ -452,13 +452,13 @@ namespace comm { Kokkos::View indices_to_send, Kokkos::View indices_to_allocate) { - array_t buffer( "buffer", indices_to_send.size() + - indices_to_allocate.size()); + array_t buffer( "buffer", indices_to_send.extent(0) + + indices_to_allocate.extent(0)); // Populate the buffer for particle array Kokkos::parallel_for( "PopulateBuffer", - Kokkos::RangePolicy(0, indices_to_send.size()), - KOKKOS_LAMBDA(const size_t i) { + indices_to_send.extent(0), + Lambda(const size_t i) { const auto idx = indices_to_send(i); buffer(i) = arr(idx); }); @@ -466,15 +466,14 @@ namespace comm { // Populate from buffer to the particle array Kokkos::parallel_for( "PopulateFromBuffer", - Kokkos::RangePolicy(0, indices_to_allocate.size()), - KOKKOS_LAMBDA(const size_t i) { + indices_to_allocate.extent(0), + Lambda(const size_t i) { const auto idx = indices_to_allocate(i); - arr(idx) = buffer(indices_to_send.size() + i); + arr(idx) = buffer(indices_to_send.extent(0) + i); }); return; } - template void CommunicateParticlesBuffer(Particles& species, Kokkos::View indices_to_send, diff --git a/src/framework/domain/communications.cpp b/src/framework/domain/communications.cpp index f484f664d..4ad29a327 100644 --- a/src/framework/domain/communications.cpp +++ b/src/framework/domain/communications.cpp @@ -660,7 +660,7 @@ template for (auto& species : domain.species) { const auto npart_per_tag_arr = species.npart_per_tag(); const auto tag_offset = species.tag_offset_h; - auto index_last = tag_offset[tag_offset.size() - 1] + + auto index_last = tag_offset[tag_offset.extent(0) - 1] + npart_per_tag_arr[npart_per_tag_arr.size() - 1]; std::vector send_ranks, send_inds; std::vector recv_ranks, recv_inds; @@ -668,9 +668,11 @@ template #if defined(MPI_ENABLED) timers->start("Communications_sendrecv"); // array that holds the number of particles to be received per tag - std::vector npart_per_tag_arr_recv(npart_per_tag_arr.size(), 0); + std::vector npart_per_tag_arr_recv(npart_per_tag_arr.size(), 0); std::size_t total_recv_count = 0; - const std::size_t total_send_count = species.npart() - npart_per_tag_arr[ParticleTag::alive]; + const std::size_t total_send_count = species.npart() - + npart_per_tag_arr[ParticleTag::alive] - + npart_per_tag_arr[ParticleTag::dead]; for (auto& direction : dir::Directions::all) { const auto [send_params, recv_params] = GetSendRecvParams(this, domain, direction, true); @@ -714,8 +716,10 @@ template timers->start("PermuteVector"); auto& this_tag = species.tag; auto& this_tag_offset = species.tag_offset; - Kokkos::View permute_vector("permute_vector", species.npart()); - Kokkos::View current_offset("current_offset", species.ntags()); + Kokkos::View permute_vector("permute_vector", species.npart()); + // Current offset is a helper array used to create permute vector + // It stores the number of particles of a given tag type stored during the loop + Kokkos::View current_offset("current_offset", species.ntags()); Kokkos::parallel_for( "PermuteVector", species.npart(), @@ -729,7 +733,7 @@ template // allocation_vector(p) assigns the pth received particle // to the pth hole in the array, or after npart() if p > sent+dead count. - Kokkos::View allocation_vector("allocation_vector", total_recv_count); + Kokkos::View allocation_vector("allocation_vector", total_recv_count); auto allocation_vector_h = Kokkos::create_mirror_view(allocation_vector); std::size_t n_alive = npart_per_tag_arr[ParticleTag::alive]; std::size_t n_dead = npart_per_tag_arr[ParticleTag::dead]; @@ -759,7 +763,15 @@ template std::size_t count_recv = 0; std::size_t iteration = 0; + // Main loop over all direction where we send the data for (auto& direction : dir::Directions::all) { + // When nowhere to send and receive + auto send_rank = send_ranks[iteration]; + auto recv_rank = recv_ranks[iteration]; + + if (send_rank < 0 and recv_rank < 0) { + continue; + } // Get the coordinate shifts in xi std::vector shifts_in_x; auto recv_ind = recv_inds[iteration]; @@ -809,22 +821,20 @@ template shifts_in_x.push_back(shift_in_x3); } - auto range_permute = std::make_pair(static_cast(tag_offset[mpi::PrtlSendTag::dir2tag(direction)]), - static_cast(tag_offset[mpi::PrtlSendTag::dir2tag(direction)] + + // Tuple that contains the start and end indices of permtute_vec pointing to a given tag type = dir2tag(dir) + auto range_permute = std::make_pair(static_cast(tag_offset[mpi::PrtlSendTag::dir2tag(direction)]), + static_cast(tag_offset[mpi::PrtlSendTag::dir2tag(direction)] + npart_per_tag_arr[mpi::PrtlSendTag::dir2tag(direction)])); - - auto range_allocate = std::make_pair(static_cast(allocation_vector_h(count_recv)), - static_cast(allocation_vector_h(count_recv) + - npart_per_tag_arr_recv[mpi::PrtlSendTag::dir2tag(-direction)])); - - // contains the indices of the holes where the received particles will be placed - auto indices_to_allocate = Kokkos::subview(allocation_vector, range_allocate); + // Tuple that contains the start and end indices for allocation_vector pointing to a given tag type = dir2tag(dir) + auto range_allocate = std::make_pair(static_cast(count_recv), + static_cast(count_recv + + npart_per_tag_arr_recv[mpi::PrtlSendTag::dir2tag(-direction)])); // contains the indices of all particles of a given tag = mpi::PrtlSendTag::dir2tag(direction) auto indices_to_send = Kokkos::subview(permute_vector, range_permute); + // contains the indices of the holes where the received particles will be placed + auto indices_to_allocate = Kokkos::subview(allocation_vector, range_allocate); // Main function that sends the particles and receives the arrays - auto send_rank = send_ranks[iteration]; - auto recv_rank = recv_ranks[iteration]; comm::CommunicateParticlesBuffer( species, indices_to_send, indices_to_allocate, From 5f1fe4a46881b4b28262e7d439a0da15600b9324 Mon Sep 17 00:00:00 2001 From: Siddhant Solanki Date: Tue, 3 Dec 2024 16:35:07 -0500 Subject: [PATCH 171/773] Printing nparticles per domain --- benchmark/benchmark.cpp | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/benchmark/benchmark.cpp b/benchmark/benchmark.cpp index 5ab9124f0..4a8923027 100644 --- a/benchmark/benchmark.cpp +++ b/benchmark/benchmark.cpp @@ -128,7 +128,11 @@ auto main(int argc, char* argv[]) -> int { {species} ); // Get the pointers to all the subdomains - const auto local_subdomain_idx = metadomain.l_subdomain_indices()[0]; + //int rank; + //MPI_Comm_rank(MPI_COMM_WORLD, &rank); + for (int i=0; i int { species.npart(), Lambda(const std::size_t i) { this_i1(i) = 1; this_i2(i) = 1; + this_i3(i) = 0; this_dx1(i) = 0.01; this_dx2(i) = 0.01; this_ux1(i) = 0.5; @@ -157,11 +162,17 @@ auto main(int argc, char* argv[]) -> int { }); } - + // Get and print the extent of each domain + std::cout << fmt::format("x1 extent {%.2f; %.2f} \n", + local_domain->mesh.extent(in::x1).first, + local_domain->mesh.extent(in::x1).second); + std::cout << fmt::format("x2 extent {%.2f; %.2f} \n", + local_domain->mesh.extent(in::x2).first, + local_domain->mesh.extent(in::x2).second); // Print the number of particles per domain std::cout << "Number of particles in domain " << local_subdomain_idx << ": " << local_domain->species[0].npart() << std::endl; // Print the position of the 5 particles in the domain - + } ntt::GlobalFinalize(); std::cout << "Terminating" << std::endl; From 5b14e3474ec4f9494db572cdaf22add4d2e4768f Mon Sep 17 00:00:00 2001 From: Siddhant Solanki Date: Tue, 3 Dec 2024 18:45:56 -0500 Subject: [PATCH 172/773] Printing particle count in domain --- benchmark/benchmark.cpp | 150 ++++++++++++++++++++++++++-------------- 1 file changed, 97 insertions(+), 53 deletions(-) diff --git a/benchmark/benchmark.cpp b/benchmark/benchmark.cpp index 4a8923027..5eebb4d2d 100644 --- a/benchmark/benchmark.cpp +++ b/benchmark/benchmark.cpp @@ -1,7 +1,6 @@ #include "enums.h" #include "global.h" -#include "utils/timer.h" #include "utils/error.h" #include "framework/domain/domain.h" #include "framework/domain/metadomain.h" @@ -11,6 +10,15 @@ #include "arch/mpi_tags.h" #include +#define TIMER_START(label) \ + Kokkos::fence(); \ + auto start_##label = std::chrono::high_resolution_clock::now(); + +#define TIMER_STOP(label) \ + Kokkos::fence(); \ + auto stop_##label = std::chrono::high_resolution_clock::now(); \ + auto duration_##label = std::chrono::duration_cast(stop_##label - start_##label).count(); \ + std::cout << "Timer [" #label "]: " << duration_##label << " microseconds" << std::endl; /* Test to check the performance of the new particle allocation scheme @@ -53,14 +61,12 @@ of the domain. */ template -void CheckDomainTags(Domain& domain, - timer::Timers* timers) +void CheckDomainTags(Domain& domain) { bool all_alive = true; bool no_dead_particles = true; - bool tag_check = true; for (auto& species : domain.species) { - std::cout << "Checking domain tags for species: " << species.label << std::endl; + std::cout << "Checking domain tags for species: " << species.label() << std::endl; const auto npart_per_tag_arr = species.npart_per_tag(); const auto npart = species.npart(); if (npart != npart_per_tag_arr[ParticleTag::alive]){ @@ -74,26 +80,33 @@ void CheckDomainTags(Domain& domain, no_dead_particles = false; } } - auto this_tag = species.tag; - Kokkos::parallel_for("CheckTags", - npart, Lambda(const std::size_t i) { - if (this_tag(i) != ParticleTag::alive) { - tag_check = false; - } - }); + raise::ErrorIf(all_alive == false, "Array contains particles with tags other than alive", HERE); raise::ErrorIf(no_dead_particles == false, "Array contains dead particles", HERE); - raise::ErrorIf(tag_check == false, - "Tag check failed", - HERE); + //raise::ErrorIf(tag_check_h(0) == false, + // "Tag check failed", + // HERE); } return; } +void InitializePositionsDomain(Domain>& domain) +{ + for (auto& species : domain.species) { + TIMER_START(Sorting_timer); + species.SortByTags(); + TIMER_STOP(Sorting_timer); + species.SyncHostDevice(); + std::cout << "Number of particles in domain: " << species.npart() << std::endl; + //std::cout << "Extent of i1" << species.i1.extent(0) << std::endl; + } + CheckDomainTags(domain); +} + auto main(int argc, char* argv[]) -> int { @@ -101,44 +114,23 @@ auto main(int argc, char* argv[]) -> int { ntt::GlobalInitialize(argc, argv); // Create a Metadomain object const unsigned int ndomains = 9; - const std::vector global_decomposition = {-1, -1}; + const std::vector global_decomposition = {{}}; const std::vector global_ncells = {32, 32}; const boundaries_t global_extent = {{0.0, 0.0}, {3.0, 3.0}}; const boundaries_t global_flds_bc = {{FldsBC::PERIODIC, FldsBC::PERIODIC}, {FldsBC::PERIODIC, FldsBC::PERIODIC}}; const boundaries_t global_prtl_bc = {{PrtlBC::PERIODIC, PrtlBC::PERIODIC}, {PrtlBC::PERIODIC, PrtlBC::PERIODIC}}; const std::map metric_params = {}; - const int npart = 10000; + const int maxnpart = 1000; auto species = ntt::Particles(1u, "test_e", 1.0f, 1.0f, - npart, + maxnpart, ntt::PrtlPusher::BORIS, false, ntt::Cooling::NONE); - auto metadomain = Metadomain> - ( - ndomains, - global_decomposition, - global_ncells, - global_extent, - global_flds_bc, - global_prtl_bc, - metric_params, - {species} - ); - // Get the pointers to all the subdomains - //int rank; - //MPI_Comm_rank(MPI_COMM_WORLD, &rank); - for (int i=0; ispecies) - { - auto tag = ParticleTag::alive; + species.set_npart(maxnpart); auto &this_i1 = species.i1; auto &this_i2 = species.i2; auto &this_i3 = species.i3; @@ -149,30 +141,82 @@ auto main(int argc, char* argv[]) -> int { auto &this_ux2 = species.ux2; auto &this_ux3 = species.ux3; auto &this_tag = species.tag; + + std::cout << "Species particle count is " << species.npart() << std::endl; Kokkos::parallel_for("SetPositions", species.npart(), Lambda(const std::size_t i) { this_i1(i) = 1; this_i2(i) = 1; - this_i3(i) = 0; + this_i3(i) = 1; this_dx1(i) = 0.01; this_dx2(i) = 0.01; - this_ux1(i) = 0.5; - this_ux2(i) = 0.5; - this_tag(i) = tag; + this_ux1(i) = 0.; + this_ux2(i) = 0.; + this_ux3(i) = 0.; + this_tag(i) = 1; }); - } + Kokkos::fence(); + std::cout << "Species set " << species.npart() << std::endl; + auto metadomain = Metadomain> + ( ndomains, + global_decomposition, + global_ncells, + global_extent, + global_flds_bc, + global_prtl_bc, + metric_params, + {species} + ); + + //metadomain.runOnLocalDomains([&](auto& loc_dom) { + // InitializePositionsDomain(loc_dom); + //}); + + // Get the pointer to the subdomain + //const auto local_subdomain_idx = metadomain.l_subdomain_indices()[0]; + //auto local_domain = metadomain.subdomain_ptr(local_subdomain_idx); + + // Set the positions of the particles in each domain + //for (auto& species : local_domain->species) + //{ + // auto tag = ParticleTag::alive; + // auto &this_i1 = species.i1; + // auto &this_i2 = species.i2; + // auto &this_i3 = species.i3; + // auto &this_dx1 = species.dx1; + // auto &this_dx2 = species.dx2; + // auto &this_dx3 = species.dx3; + // auto &this_ux1 = species.ux1; + // auto &this_ux2 = species.ux2; + // auto &this_ux3 = species.ux3; + // auto &this_tag = species.tag; + // Kokkos::parallel_for("SetPositions", + // species.npart(), Lambda(const std::size_t i) { + // this_i1(i) = 1; + // this_i2(i) = 1; + // this_i3(i) = 0; + // this_dx1(i) = 0.01; + // this_dx2(i) = 0.01; + // this_ux1(i) = 0.5; + // this_ux2(i) = 0.5; + // this_tag(i) = tag; + // }); +// + //species.SortByTags(); + //species.SyncHostDevice(); + //} // Get and print the extent of each domain - std::cout << fmt::format("x1 extent {%.2f; %.2f} \n", - local_domain->mesh.extent(in::x1).first, - local_domain->mesh.extent(in::x1).second); - std::cout << fmt::format("x2 extent {%.2f; %.2f} \n", - local_domain->mesh.extent(in::x2).first, - local_domain->mesh.extent(in::x2).second); + //std::cout << fmt::format("x1 extent {%.2f; %.2f} \n", + // local_domain->mesh.extent(in::x1).first, + // local_domain->mesh.extent(in::x1).second); + //std::cout << fmt::format("x2 extent {%.2f; %.2f} \n", + // local_domain->mesh.extent(in::x2).first, + // local_domain->mesh.extent(in::x2).second); // Print the number of particles per domain - std::cout << "Number of particles in domain " << local_subdomain_idx << ": " << local_domain->species[0].npart() << std::endl; + //std::cout << "Number of particles in domain " << local_subdomain_idx << ": " << local_domain->species[0].npart() << std::endl; // Print the position of the 5 particles in the domain - } + ntt::GlobalFinalize(); std::cout << "Terminating" << std::endl; From 3d7e78156083c7566b1a80c1a94b154ac70c00fa Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Wed, 4 Dec 2024 14:58:18 -0500 Subject: [PATCH 173/773] erased stretching of initial field --- src/archetypes/field_setter.h | 52 ++++------------------------------- src/kernels/fields_bcs.hpp | 20 ++------------ 2 files changed, 8 insertions(+), 64 deletions(-) diff --git a/src/archetypes/field_setter.h b/src/archetypes/field_setter.h index 171e9f8a8..5c5c4dbe4 100644 --- a/src/archetypes/field_setter.h +++ b/src/archetypes/field_setter.h @@ -170,32 +170,13 @@ namespace arch { const real_t x2_H { metric.template convert<2, Crd::Cd, Crd::Ph>( i2_ + HALF) }; { // dx1 - vec_t d_PU { finit.dx1({ x1_H, x2_0 }), - finit.dx2({ x1_H, x2_0 }), - finit.dx3({ x1_H, x2_0 }) }; - vec_t d_U { ZERO }; - metric.template transform({ i1_ + HALF, i2_ }, - d_PU, - d_U); - EM(i1, i2, em::dx1) = d_U[0]; + EM(i1, i2, em::dx1) = finit.dx1({ x1_H, x2_0 }); } { // dx2 - vec_t d_PU { finit.dx1({ x1_0, x2_H }), - finit.dx2({ x1_0, x2_H }), - finit.dx3({ x1_0, x2_H }) }; - vec_t d_U { ZERO }; - metric.template transform({ i1_, i2_ + HALF }, - d_PU, - d_U); - EM(i1, i2, em::dx2) = d_U[1]; + EM(i1, i2, em::dx2) = finit.dx2({ x1_0, x2_H }); } { // dx3 - vec_t d_PU { finit.dx1({ x1_0, x2_0 }), - finit.dx2({ x1_0, x2_0 }), - finit.dx3({ x1_0, x2_0 }) }; - vec_t d_U { ZERO }; - metric.template transform({ i1_, i2_ }, d_PU, d_U); - EM(i1, i2, em::dx3) = d_U[2]; + EM(i1, i2, em::dx3) = finit.dx3({ x1_0, x2_0 }); } } if constexpr (defines_bx1 && defines_bx2 && defines_bx3) { @@ -206,34 +187,13 @@ namespace arch { const real_t x2_H { metric.template convert<2, Crd::Cd, Crd::Ph>( i2_ + HALF) }; { // bx1 - vec_t b_PU { finit.bx1({ x1_0, x2_H }), - finit.bx2({ x1_0, x2_H }), - finit.bx3({ x1_0, x2_H }) }; - vec_t b_U { ZERO }; - metric.template transform({ i1_, i2_ + HALF }, - b_PU, - b_U); - EM(i1, i2, em::bx1) = b_U[0]; + EM(i1, i2, em::bx1) = finit.bx1({ x1_0, x2_H }); } { // bx2 - vec_t b_PU { finit.bx1({ x1_H, x2_0 }), - finit.bx2({ x1_H, x2_0 }), - finit.bx3({ x1_H, x2_0 }) }; - vec_t b_U { ZERO }; - metric.template transform({ i1_ + HALF, i2_ }, - b_PU, - b_U); - EM(i1, i2, em::bx2) = b_U[1]; + EM(i1, i2, em::bx2) = finit.bx2({ x1_H, x2_0 }); } { // bx3 - vec_t b_PU { finit.bx1({ x1_H, x2_H }), - finit.bx2({ x1_H, x2_H }), - finit.bx3({ x1_H, x2_H }) }; - vec_t b_U { ZERO }; - metric.template transform({ i1_ + HALF, i2_ + HALF }, - b_PU, - b_U); - EM(i1, i2, em::bx3) = b_U[2]; + EM(i1, i2, em::bx3) = finit.bx3({ x1_H, x2_H }); } } } else { diff --git a/src/kernels/fields_bcs.hpp b/src/kernels/fields_bcs.hpp index e69fbcc13..e5b3de647 100644 --- a/src/kernels/fields_bcs.hpp +++ b/src/kernels/fields_bcs.hpp @@ -639,28 +639,12 @@ template const real_t x1_0 { metric.template convert<1, Crd::Cd, Crd::Ph>(i1_) }; const real_t x2_H { metric.template convert<2, Crd::Cd, Crd::Ph>( i2_ + HALF) }; - - vec_t b_PU { finit.bx1({ x1_0, x2_H }), - finit.bx2({ x1_0, x2_H }), - finit.bx3({ x1_0, x2_H }) }; - vec_t b_U { ZERO }; - metric.template transform({ i1_, i2_ + HALF }, - b_PU, - b_U); - Fld(i1, i2, comp) += (ONE - math::tanh(dx / (INV_4 * dx_abs))) * b_U[0]; + Fld(i1, i2, comp) += (ONE - math::tanh(dx / (INV_4 * dx_abs))) * finit.bx1({ x1_0, x2_H }); } else if (comp == em::bx2) { const real_t x1_H { metric.template convert<1, Crd::Cd, Crd::Ph>( i1_ + HALF) }; const real_t x2_0 { metric.template convert<2, Crd::Cd, Crd::Ph>(i2_) }; - - vec_t b_PU { finit.bx1({ x1_H, x2_0 }), - finit.bx2({ x1_H, x2_0 }), - finit.bx3({ x1_H, x2_0 }) }; - vec_t b_U { ZERO }; - metric.template transform({ i1_ + HALF, i2_ }, - b_PU, - b_U); - Fld(i1, i2, comp) += (ONE - math::tanh(dx / (INV_4 * dx_abs))) * b_U[1]; + Fld(i1, i2, comp) += (ONE - math::tanh(dx / (INV_4 * dx_abs))) * finit.bx2({ x1_H, x2_0 }); } } } else { From d0a44184ad84e043616c7fcd4a322842346fd429 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Wed, 4 Dec 2024 18:06:57 -0500 Subject: [PATCH 174/773] engines/grpic: updated routines for current (cur --> cur0) and added BC for currents --- src/engines/grpic.hpp | 74 +++++++++++++++++++++++++++++++++---------- 1 file changed, 57 insertions(+), 17 deletions(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index 4c2278f1f..06088c1eb 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -354,7 +354,7 @@ namespace ntt { */ if (deposit_enabled) { timers.start("CurrentDeposit"); - Kokkos::deep_copy(dom.fields.cur, ZERO); + Kokkos::deep_copy(dom.fields.cur0, ZERO); CurrentsDeposit(dom); timers.stop("CurrentDeposit"); @@ -611,6 +611,50 @@ namespace ntt { } } + void CurrentsBoundaryConditions(domain_t& domain) { + /** + * absorbing boundaries + */ + const auto ds = m_params.template get( + "grid.boundaries.absorb.ds"); + const auto dim = in::x1; + real_t xg_min, xg_max, xg_edge; + xg_max = m_metadomain.mesh().extent(dim).second; + xg_min = xg_max - ds; + xg_edge = xg_max; + + boundaries_t box; + boundaries_t incl_ghosts; + for (unsigned short d { 0 }; d < M::Dim; ++d) { + if (d == static_cast(dim)) { + box.push_back({ xg_min, xg_max }); + incl_ghosts.push_back({ false, true }); + } else { + box.push_back(Range::All); + incl_ghosts.push_back({ true, true }); + } + } + if (not domain.mesh.Intersects(box)) { + return; + } + const auto intersect_range = domain.mesh.ExtentToRange(box, incl_ghosts); + tuple_t range_min { 0 }; + tuple_t range_max { 0 }; + + for (unsigned short d { 0 }; d < M::Dim; ++d) { + range_min[d] = intersect_range[d].first; + range_max[d] = intersect_range[d].second; + } + Kokkos::parallel_for( + "AbsorbCurrent", + CreateRangePolicy(range_min, range_max), + kernel::AbsorbCurrentGR_kernel(domain.fields.cur0, + domain.mesh.metric, + xg_edge, + ds, + tags)); + } + void OpenFieldsIn(dir::direction_t direction, domain_t& domain, BCTags tags, @@ -867,8 +911,8 @@ namespace ntt { const auto coeff = -dt * q0 * n0 / B0; // auto range = range_with_axis_BCs(domain); auto range = CreateRangePolicy( - { domain.mesh.i_min(in::x1), domain.mesh.i_min(in::x2) + 1}, - { domain.mesh.i_max(in::x1), domain.mesh.i_max(in::x2)}); + { domain.mesh.i_min(in::x1), domain.mesh.i_min(in::x2)}, + { domain.mesh.i_max(in::x1), domain.mesh.i_max(in::x2) + 1}); const auto ni2 = domain.mesh.n_active(in::x2); if (g == gr_ampere::aux) { @@ -915,7 +959,7 @@ namespace ntt { void CurrentsDeposit(domain_t& domain) { auto scatter_cur = Kokkos::Experimental::create_scatter_view( - domain.fields.cur); + domain.fields.cur0); for (auto& species : domain.species) { logger::Checkpoint( fmt::format("Launching currents deposit kernel for %d [%s] : %lu %f", @@ -953,31 +997,27 @@ namespace ntt { (real_t)(species.charge()), dt)); } - Kokkos::Experimental::contribute(domain.fields.cur, scatter_cur); + Kokkos::Experimental::contribute(domain.fields.cur0, scatter_cur); } void CurrentsFilter(domain_t& domain) { logger::Checkpoint("Launching currents filtering kernels", HERE); - auto range = range_with_axis_BCs(domain); + auto range = CreateRangePolicy( + { domain.mesh.i_min(in::x1), domain.mesh.i_min(in::x2)}, + { domain.mesh.i_max(in::x1), domain.mesh.i_max(in::x2) + 1}); const auto nfilter = m_params.template get( "algorithms.current_filters"); tuple_t size; - if constexpr (M::Dim == Dim::_1D || M::Dim == Dim::_2D || M::Dim == Dim::_3D) { - size[0] = domain.mesh.n_active(in::x1); - } - if constexpr (M::Dim == Dim::_2D || M::Dim == Dim::_3D) { - size[1] = domain.mesh.n_active(in::x2); - } - if constexpr (M::Dim == Dim::_3D) { - size[2] = domain.mesh.n_active(in::x3); - } + size[0] = domain.mesh.n_active(in::x1); + size[1] = domain.mesh.n_active(in::x2); + // !TODO: this needs to be done more efficiently for (unsigned short i = 0; i < nfilter; ++i) { - Kokkos::deep_copy(domain.fields.buff, domain.fields.cur); + Kokkos::deep_copy(domain.fields.buff, domain.fields.cur0); Kokkos::parallel_for("CurrentsFilter", range, kernel::DigitalFilter_kernel( - domain.fields.cur, + domain.fields.cur0, domain.fields.buff, size, domain.mesh.flds_bc())); From 794beaab8a5afa9a635fc95d06413ac0cd50b2d3 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Wed, 4 Dec 2024 18:25:27 -0500 Subject: [PATCH 175/773] BC for currents --- src/engines/grpic.hpp | 3 +-- src/kernels/fields_bcs.hpp | 42 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index 06088c1eb..6ce571bac 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -651,8 +651,7 @@ namespace ntt { kernel::AbsorbCurrentGR_kernel(domain.fields.cur0, domain.mesh.metric, xg_edge, - ds, - tags)); + ds)); } void OpenFieldsIn(dir::direction_t direction, diff --git a/src/kernels/fields_bcs.hpp b/src/kernels/fields_bcs.hpp index e5b3de647..34f4ac887 100644 --- a/src/kernels/fields_bcs.hpp +++ b/src/kernels/fields_bcs.hpp @@ -655,6 +655,48 @@ template } }; + template + struct AbsorbCurrentGR_kernel { + static_assert(M::is_metric, "M must be a metric class"); + static_assert(i <= static_cast(M::Dim), + "Invalid component index"); + + ndfield_t J; + const M metric; + const real_t xg_edge; + const real_t dx_abs; + const BCTags tags; + + AbsorbCurrentGR_kernel(ndfield_t J, + const M& metric, + real_t xg_edge, + real_t dx_abs, + BCTags tags) + : J { J } + , metric { metric } + , xg_edge { xg_edge } + , dx_abs { dx_abs } + , tags { tags } {} + + Inline void operator()(index_t i1, index_t i2) const { + if constexpr (M::Dim == Dim::_2D) { + const auto i1_ = COORD(i1); + const auto i2_ = COORD(i2); + coord_t x_Cd { ZERO }; + x_Cd[0] = i1_; + x_Cd[1] = i2_; + const auto dx = math::abs( + metric.template convert(x_Cd[i - 1]) - xg_edge); + J(i1, i2) *= math::tanh(dx / (INV_4 * dx_abs)); + + } else { + raise::KernelError( + HERE, + "AbsorbFields_kernel: 2D implementation called for D != 2"); + } + } + }; + } // namespace kernel #endif // KERNELS_FIELDS_BCS_HPP From 28f590ac3a53d2becd4f6335e9757b0cf5925a95 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Fri, 6 Dec 2024 11:22:07 -0500 Subject: [PATCH 176/773] engines/grpic: discard first step if fieldsolver = false --- src/engines/grpic.hpp | 292 ++++++++++++++++++++++-------------------- 1 file changed, 151 insertions(+), 141 deletions(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index 6ce571bac..6b36ec35c 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -100,164 +100,174 @@ namespace ntt { "algorithms.toggles.deposit"); const auto sort_interval = m_params.template get( "particles.sort_interval"); - + if (step == 0) { - // communicate fields and apply BCs on the first timestep - /** - * Initially: em0::B -- - * em0::D -- - * em::B at -1/2 - * em::D at -1/2 - * - * cur0::J -- - * cur::J -- - * - * aux::E -- - * aux::H -- - * - * x_prtl at -1/2 - * u_prtl at -1/2 - */ + if (fieldsolver_enabled) { + // communicate fields and apply BCs on the first timestep + /** + * Initially: em0::B -- + * em0::D -- + * em::B at -1/2 + * em::D at -1/2 + * + * cur0::J -- + * cur::J -- + * + * aux::E -- + * aux::H -- + * + * x_prtl at -1/2 + * u_prtl at -1/2 + */ - /** - * em0::D, em::D, em0::B, em::B <- boundary conditions - */ - m_metadomain.CommunicateFields(dom, Comm::B | Comm::B0 | Comm::D | Comm::D0); - FieldBoundaries(dom, BC::B | BC::E, gr_bc::main); + /** + * em0::D, em::D, em0::B, em::B <- boundary conditions + */ + m_metadomain.CommunicateFields(dom, Comm::B | Comm::B0 | Comm::D | Comm::D0); + FieldBoundaries(dom, BC::B | BC::E, gr_bc::main); - /** - * em0::B <- em::B - * em0::D <- em::D - * - * Now: em0::B & em0::D at -1/2 - */ - CopyFields(dom); + /** + * em0::B <- em::B + * em0::D <- em::D + * + * Now: em0::B & em0::D at -1/2 + */ + CopyFields(dom); - /** - * aux::E <- alpha * em::D + beta x em0::B - * aux::H <- alpha * em::B0 - beta x em::D - * - * Now: aux::E & aux::H at -1/2 - */ - ComputeAuxE(dom, gr_getE::D_B0); - ComputeAuxH(dom, gr_getH::D_B0); + /** + * aux::E <- alpha * em::D + beta x em0::B + * aux::H <- alpha * em::B0 - beta x em::D + * + * Now: aux::E & aux::H at -1/2 + */ + ComputeAuxE(dom, gr_getE::D_B0); + ComputeAuxH(dom, gr_getH::D_B0); - /** - * aux::E, aux::H <- boundary conditions - */ - FieldBoundaries(dom, BC::B | BC::E, gr_bc::aux); + /** + * aux::E, aux::H <- boundary conditions + */ + FieldBoundaries(dom, BC::B | BC::E, gr_bc::aux); - /** - * em0::B <- (em0::B) <- -curl aux::E - * - * Now: em0::B at 0 - */ - Faraday(dom, gr_faraday::aux, HALF); + /** + * em0::B <- (em0::B) <- -curl aux::E + * + * Now: em0::B at 0 + */ + Faraday(dom, gr_faraday::aux, HALF); - /** - * em0::B, em::B <- boundary conditions - */ - m_metadomain.CommunicateFields(dom, Comm::B | Comm::B0); - FieldBoundaries(dom, BC::B, gr_bc::main); + /** + * em0::B, em::B <- boundary conditions + */ + m_metadomain.CommunicateFields(dom, Comm::B | Comm::B0); + FieldBoundaries(dom, BC::B, gr_bc::main); - /** - * em::D <- (em0::D) <- curl aux::H - * - * Now: em::D at 0 - */ - Ampere(dom, gr_ampere::init, HALF); + /** + * em::D <- (em0::D) <- curl aux::H + * + * Now: em::D at 0 + */ + Ampere(dom, gr_ampere::init, HALF); - /** - * em0::D, em::D <- boundary conditions - */ - m_metadomain.CommunicateFields(dom, Comm::D | Comm::D0); - FieldBoundaries(dom, BC::E, gr_bc::main); + /** + * em0::D, em::D <- boundary conditions + */ + m_metadomain.CommunicateFields(dom, Comm::D | Comm::D0); + FieldBoundaries(dom, BC::E, gr_bc::main); - /** - * aux::E <- alpha * em::D + beta x em0::B - * aux::H <- alpha * em0::B - beta x em::D - * - * Now: aux::E & aux::H at 0 - */ - ComputeAuxE(dom, gr_getE::D_B0); - ComputeAuxH(dom, gr_getH::D_B0); + /** + * aux::E <- alpha * em::D + beta x em0::B + * aux::H <- alpha * em0::B - beta x em::D + * + * Now: aux::E & aux::H at 0 + */ + ComputeAuxE(dom, gr_getE::D_B0); + ComputeAuxH(dom, gr_getH::D_B0); - /** - * aux::E, aux::H <- boundary conditions - */ - FieldBoundaries(dom, BC::B | BC::E, gr_bc::aux); + /** + * aux::E, aux::H <- boundary conditions + */ + FieldBoundaries(dom, BC::B | BC::E, gr_bc::aux); - // !ADD: GR -- particles? + // !ADD: GR -- particles? - /** - * em0::B <- (em::B) <- -curl aux::E - * - * Now: em0::B at 1/2 - */ - Faraday(dom, gr_faraday::main, ONE); - /** - * em0::B, em::B <- boundary conditions - */ - m_metadomain.CommunicateFields(dom, Comm::B | Comm::B0); - FieldBoundaries(dom, BC::B, gr_bc::main); + /** + * em0::B <- (em::B) <- -curl aux::E + * + * Now: em0::B at 1/2 + */ + Faraday(dom, gr_faraday::main, ONE); + /** + * em0::B, em::B <- boundary conditions + */ + m_metadomain.CommunicateFields(dom, Comm::B | Comm::B0); + FieldBoundaries(dom, BC::B, gr_bc::main); - /** - * em0::D <- (em0::D) <- curl aux::H - * - * Now: em0::D at 1/2 - */ - Ampere(dom, gr_ampere::aux, ONE); - /** - * em0::D, em::D <- boundary conditions - */ - m_metadomain.CommunicateFields(dom, Comm::D | Comm::D0); - FieldBoundaries(dom, BC::E, gr_bc::main); + /** + * em0::D <- (em0::D) <- curl aux::H + * + * Now: em0::D at 1/2 + */ + Ampere(dom, gr_ampere::aux, ONE); + /** + * em0::D, em::D <- boundary conditions + */ + m_metadomain.CommunicateFields(dom, Comm::D | Comm::D0); + FieldBoundaries(dom, BC::E, gr_bc::main); - /** - * aux::H <- alpha * em0::B - beta x em0::D - * - * Now: aux::H at 1/2 - */ - ComputeAuxH(dom, gr_getH::D0_B0); - /** - * aux::H <- boundary conditions - */ - FieldBoundaries(dom, BC::B, gr_bc::aux); + /** + * aux::H <- alpha * em0::B - beta x em0::D + * + * Now: aux::H at 1/2 + */ + ComputeAuxH(dom, gr_getH::D0_B0); + /** + * aux::H <- boundary conditions + */ + FieldBoundaries(dom, BC::B, gr_bc::aux); - /** - * em0::D <- (em::D) <- curl aux::H - * - * Now: em0::D at 1 - * em::D at 0 - */ - Ampere(dom, gr_ampere::main, ONE); - /** - * em0::D, em::D <- boundary conditions - */ - m_metadomain.CommunicateFields(dom, Comm::D | Comm::D0); - FieldBoundaries(dom, BC::E, gr_bc::main); + /** + * em0::D <- (em::D) <- curl aux::H + * + * Now: em0::D at 1 + * em::D at 0 + */ + Ampere(dom, gr_ampere::main, ONE); + /** + * em0::D, em::D <- boundary conditions + */ + m_metadomain.CommunicateFields(dom, Comm::D | Comm::D0); + FieldBoundaries(dom, BC::E, gr_bc::main); - /** - * em::D <-> em0::D - * em::B <-> em0::B - * em::J <-> em0::J - */ - SwapFields(dom); - /** - * Finally: em0::B at -1/2 - * em0::D at 0 - * em::B at 1/2 - * em::D at 1 - * - * cur0::J -- - * cur::J -- - * - * aux::E -- - * aux::H -- - * - * x_prtl at 1 - * u_prtl at 1/2 - */ + /** + * em::D <-> em0::D + * em::B <-> em0::B + * em::J <-> em0::J + */ + SwapFields(dom); + /** + * Finally: em0::B at -1/2 + * em0::D at 0 + * em::B at 1/2 + * em::D at 1 + * + * cur0::J -- + * cur::J -- + * + * aux::E -- + * aux::H -- + * + * x_prtl at 1 + * u_prtl at 1/2 + */ + } + } else { + /** + * em0::B <- em::B + * em0::D <- em::D + * + * Now: em0::B & em0::D at -1/2 + */ + CopyFields(dom); } /** From 6ad04be0072bf42a28719bce32d16365d4a06b14 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Fri, 6 Dec 2024 13:58:38 -0500 Subject: [PATCH 177/773] GeodesicFullPush bug for utheta --- src/kernels/particle_pusher_gr.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/kernels/particle_pusher_gr.hpp b/src/kernels/particle_pusher_gr.hpp index 306f19013..4b5432891 100644 --- a/src/kernels/particle_pusher_gr.hpp +++ b/src/kernels/particle_pusher_gr.hpp @@ -478,7 +478,7 @@ namespace kernel::gr { dt * (-metric.alpha(xp_mid) * u0 * DERIVATIVE_IN_TH(metric.alpha, xp_mid) + - vp_mid[1] * DERIVATIVE_IN_TH(metric.beta1, xp_mid) - + vp_mid[0] * DERIVATIVE_IN_TH(metric.beta1, xp_mid) - (HALF / u0) * (DERIVATIVE_IN_TH((metric.template h<1, 1>), xp_mid) * SQR(vp_mid[0]) + From 1b0993d7b475a0be005686cbd1516f13a7b762e5 Mon Sep 17 00:00:00 2001 From: Siddhant Solanki Date: Fri, 6 Dec 2024 15:13:14 -0500 Subject: [PATCH 178/773] benchmark/benchmark.cpp fixed benchmark.cpp --- src/framework/containers/particles.cpp | 3 +++ src/framework/domain/comm_mpi.hpp | 2 -- src/framework/domain/communications.cpp | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/framework/containers/particles.cpp b/src/framework/containers/particles.cpp index c7f8f3b7c..c97f8da2d 100644 --- a/src/framework/containers/particles.cpp +++ b/src/framework/containers/particles.cpp @@ -85,6 +85,9 @@ namespace ntt { auto this_tag = tag; array_t npart_tag("npart_tags", ntags()); + // Print tag_h array + auto tag_host = Kokkos::create_mirror_view(tag); + Kokkos::deep_copy(tag_host, tag); auto npart_tag_scatter = Kokkos::Experimental::create_scatter_view(npart_tag); Kokkos::parallel_for( "NpartPerTag", diff --git a/src/framework/domain/comm_mpi.hpp b/src/framework/domain/comm_mpi.hpp index ed73302b2..d29a5758b 100644 --- a/src/framework/domain/comm_mpi.hpp +++ b/src/framework/domain/comm_mpi.hpp @@ -363,12 +363,10 @@ namespace comm { recv_rank, send_slice.second - send_slice.first, recv_count); - raise::FatalIf((index_last + recv_count) >= species.maxnpart(), "Too many particles to receive (cannot fit into maxptl)", HERE); const auto recv_slice = range_tuple_t({ index_last, index_last + recv_count }); - CommunicateParticleQuantity(species.i1, send_rank, recv_rank, send_slice, recv_slice); CommunicateParticleQuantity(species.dx1, send_rank, recv_rank, send_slice, recv_slice); CommunicateParticleQuantity(species.i1_prev, diff --git a/src/framework/domain/communications.cpp b/src/framework/domain/communications.cpp index 4ad29a327..cdd32aed6 100644 --- a/src/framework/domain/communications.cpp +++ b/src/framework/domain/communications.cpp @@ -631,7 +631,6 @@ namespace ntt { index_last += recv_count; species.set_npart(index_last); } - Kokkos::deep_copy( Kokkos::subview(species.tag, std::make_pair(send_pmin, send_pmax)), ParticleTag::dead); @@ -844,6 +843,7 @@ template count_recv += npart_per_tag_arr_recv[mpi::PrtlSendTag::dir2tag(-direction)]; iteration++; } + // If receive count is less than send count then make the tags of sent dead ? Ask Hayk species.set_npart(index_last + std::max(total_recv_count, total_send_count) - total_send_count); #endif } From 9f34be4dcc2f2cdb610df4401dbe192b3c562b2d Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Wed, 11 Dec 2024 16:36:19 -0500 Subject: [PATCH 179/773] minor gr pusher --- src/kernels/particle_pusher_gr.hpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/kernels/particle_pusher_gr.hpp b/src/kernels/particle_pusher_gr.hpp index 4b5432891..e220239bf 100644 --- a/src/kernels/particle_pusher_gr.hpp +++ b/src/kernels/particle_pusher_gr.hpp @@ -678,13 +678,9 @@ namespace kernel::gr { dx2_prev(p) = dx2(p); coord_t xp { ZERO }; - coord_t xp_prev { ZERO }; xp[0] = i_di_to_Xi(i1(p), dx1(p)); xp[1] = i_di_to_Xi(i2(p), dx2(p)); - - xp_prev[0] = i_di_to_Xi(i1_prev(p), dx1_prev(p)); - xp_prev[1] = i_di_to_Xi(i2_prev(p), dx2_prev(p)); vec_t Dp_cntrv { ZERO }, Bp_cntrv { ZERO }, Dp_hat { ZERO }, Bp_hat { ZERO }; From e5b0267f869d3028ded1513a9ebe0038ed363fa4 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Wed, 11 Dec 2024 18:20:10 -0500 Subject: [PATCH 180/773] pgen and inputs for pusher debugging updated --- setups/grpic/pusher/boris.toml | 52 ++++---- setups/grpic/pusher/massive_gravity_a0.toml | 4 +- .../grpic/pusher/massive_gravity_a0995.toml | 4 +- setups/grpic/pusher/pgen.hpp | 124 +++++++++++++----- 4 files changed, 122 insertions(+), 62 deletions(-) diff --git a/setups/grpic/pusher/boris.toml b/setups/grpic/pusher/boris.toml index 6483eb2c6..5d4d92a9d 100644 --- a/setups/grpic/pusher/boris.toml +++ b/setups/grpic/pusher/boris.toml @@ -1,14 +1,14 @@ [simulation] name = "boris_a0" engine = "grpic" - runtime = 100.0 + runtime = 500.0 [grid] resolution = [128,128] - extent = [[0.9, 20.0]] + extent = [[1.2, 20.0]] [grid.metric] - metric = "qkerr_schild" + metric = "kerr_schild" qsph_r0 = 0.0 qsph_h = 0.0 ks_a = 0.0 @@ -22,7 +22,7 @@ [scales] larmor0 = 5.0 - skindepth0 = 1e-3 + skindepth0 = 1e0 [algorithms] current_filters = 4 @@ -32,7 +32,7 @@ pusher_eps = 1e-6 [algorithms.timestep] - CFL = 0.1 + CFL = 1.0 [algorithms.toggles] deposit = false @@ -42,37 +42,33 @@ ppc0 = 1.0 [[particles.species]] - label = "e-" + label = "e+" mass = 1.0 - charge = -1.0 + charge = 1.0 maxnpart = 1e0 [[particles.species]] - label = "e+" + label = "e-" mass = 1.0 charge = -1.0 - maxnpart = 1e1 + maxnpart = 1e0 [setup] - x1s = [5.77] - y1s = [1.570796] - z1s = [0.000000] - ux1s = [0.4376657824933686] - uy1s = [0.000000] - uz1s = [4.0] -# x1s = [10.0] -# y1s = [1.570796] -# z1s = [0.000000] -# ux1s = [0.0] -# uy1s = [0.000000] -# uz1s = [10.00000] - - #x2s = [7.5] - #y2s = [0.15745454545454546] - #z2s = [0.000000] - #ux2s = [0.029637] - #uy2s = [0.000000] - #uz2s = [3.75] + # Fig. 6.4 from Kolos, Stuchlik and Tursunov (2015) + x1s = [5.77] + y1s = [1.5707963267948966] + z1s = [0.000000] + ux1s = [0.43766578249336874] + uy1s = [0.000000] + uz1s = [1.1707100000000000] + + # Fig. 5.3 from Kolos, Stuchlik and Tursunov (2015) + x2s = [6.79] + y2s = [1.5707963267948966] + z2s = [0.000000] + ux2s = [0.7398747390396659] + uy2s = [0.000000] + uz2s = [12.610410000000002] [output] format = "hdf5" diff --git a/setups/grpic/pusher/massive_gravity_a0.toml b/setups/grpic/pusher/massive_gravity_a0.toml index 08b607d4b..8179432da 100644 --- a/setups/grpic/pusher/massive_gravity_a0.toml +++ b/setups/grpic/pusher/massive_gravity_a0.toml @@ -56,7 +56,7 @@ [setup] # (1,2,0) from Levin&Perez-Giz (2008) x1s = [9.85180645] - y1s = [1.570796] + y1s = [1.5707963267948966] z1s = [0.5235987755982988] ux1s = [0.24159816] uy1s = [3.535534] @@ -64,7 +64,7 @@ # (4,1,1) from Levin&Perez-Giz (2008) x2s = [68.600387] - y2s = [1.570796] + y2s = [1.5707963267948966] z2s = [0.000000] ux2s = [0.029637] uy2s = [0.000000] diff --git a/setups/grpic/pusher/massive_gravity_a0995.toml b/setups/grpic/pusher/massive_gravity_a0995.toml index b04538e10..3b64d2066 100644 --- a/setups/grpic/pusher/massive_gravity_a0995.toml +++ b/setups/grpic/pusher/massive_gravity_a0995.toml @@ -56,7 +56,7 @@ [setup] # (2,3,1) from Levin&Perez-Giz (2008) x1s = [10.343515586064923] - y1s = [1.570796] + y1s = [1.5707963267948966] z1s = [0.000000] ux1s = [0.19483849893499136] uy1s = [0.000000] @@ -64,7 +64,7 @@ # (~1000, 3, ~671) from Levin&Perez-Giz (2008) x2s = [10.64975354] - y2s = [1.570796] + y2s = [1.5707963267948966] z2s = [0.000000] ux2s = [0.18914503] uy2s = [0.000000] diff --git a/setups/grpic/pusher/pgen.hpp b/setups/grpic/pusher/pgen.hpp index d6a29a185..8f60b1515 100644 --- a/setups/grpic/pusher/pgen.hpp +++ b/setups/grpic/pusher/pgen.hpp @@ -27,12 +27,12 @@ namespace user { InitFields(M metric_) : metric { metric_ } {} Inline auto A_3(const coord_t& x_Cd) const -> real_t { - // return HALF * (metric.template h_<3, 3>(x_Cd) ); - // + TWO * metric.spin() * metric.template h_<1, 3>(x_Cd) * metric.beta1(x_Cd) - // ); - coord_t x_Ph { ZERO }; - metric.template convert(x_Cd, x_Ph); - return HALF * SQR(x_Ph[0]) * SQR(math::sin(x_Ph[1])); + return HALF * (metric.template h_<3, 3>(x_Cd) + + TWO * metric.spin() * metric.template h_<1, 3>(x_Cd) * metric.beta1(x_Cd) + ); + // coord_t x_Ph { ZERO }; + // metric.template convert(x_Cd, x_Ph); + // return HALF * SQR(x_Ph[0]) * SQR(math::sin(x_Ph[1])); } Inline auto A_1(const coord_t& x_Cd) const -> real_t { @@ -49,7 +49,7 @@ namespace user { + TWO * metric.spin() * g_00); } - Inline auto bx1(const coord_t& x_Ph) const -> real_t { + Inline auto bx1(const coord_t& x_Ph) const -> real_t { // at ( i , j + HALF ) coord_t xi {ZERO}, x0m { ZERO }, x0p { ZERO }; metric.template convert(x_Ph, xi); @@ -64,50 +64,114 @@ namespace user { return ONE; else return (A_3(x0p) - A_3(x0m)) * inv_sqrt_detH_ijP; - // return ZERO; } - Inline auto bx2(const coord_t& x_Ph) const -> real_t { + Inline auto bx2(const coord_t& x_Ph) const -> real_t { // at ( i + HALF , j ) coord_t xi {ZERO}, x0m { ZERO }, x0p { ZERO }; metric.template convert(x_Ph, xi); - x0m[0] = xi[0] + HALF - HALF; + x0m[0] = xi[0] - HALF; x0m[1] = xi[1]; - x0p[0] = xi[0] + HALF + HALF; + x0p[0] = xi[0] + HALF; x0p[1] = xi[1]; - real_t inv_sqrt_detH_ijP { ONE / metric.sqrt_det_h({ xi[0], xi[1] }) }; + real_t inv_sqrt_detH_iPj { ONE / metric.sqrt_det_h({ xi[0], xi[1] }) }; if (cmp::AlmostZero(x_Ph[1])) return ZERO; else - return -(A_3(x0p) - A_3(x0m)) * inv_sqrt_detH_ijP; - // return ZERO; + return -(A_3(x0p) - A_3(x0m)) * inv_sqrt_detH_iPj; } - Inline auto bx3(const coord_t& x_Ph) const -> real_t { - // coord_t xi {ZERO}, x0m { ZERO }, x0p { ZERO }; - // metric.template convert(x_Ph, xi); + Inline auto bx3(const coord_t& x_Ph) const -> real_t { // at ( i + HALF , j + HALF ) + coord_t xi {ZERO}, x0m { ZERO }, x0p { ZERO }; + metric.template convert(x_Ph, xi); - // x0m[0] = xi[0] + HALF - HALF; - // x0m[1] = xi[1]; - // x0p[0] = xi[0] + HALF + HALF; - // x0p[1] = xi[1]; + x0m[0] = xi[0]; + x0m[1] = xi[1] - HALF; + x0p[0] = xi[0]; + x0p[1] = xi[1] + HALF; - // real_t inv_sqrt_detH_ijP { ONE / metric.sqrt_det_h({ xi[0], xi[1] }) }; - // return -(A_1(x0p) - A_1(x0m)) * inv_sqrt_detH_ijP; - return ZERO; + real_t inv_sqrt_detH_iPjP { ONE / metric.sqrt_det_h({ xi[0], xi[1]}) }; + return -(A_1(x0p) - A_1(x0m)) * inv_sqrt_detH_iPjP; } - Inline auto dx1(const coord_t& x_Ph) const -> real_t { - return ZERO; + Inline auto dx1(const coord_t& x_Ph) const -> real_t { // at ( i + HALF , j ) + coord_t xi {ZERO}, x0m { ZERO }, x0p { ZERO }; + metric.template convert(x_Ph, xi); + + real_t alpha_iPj { metric.alpha({ xi[0], xi[1] }) }; + real_t inv_sqrt_detH_ij { ONE / metric.sqrt_det_h({ xi[0] - HALF, xi[1] }) }; + real_t sqrt_detH_ij { metric.sqrt_det_h({ xi[0] - HALF, xi[1] }) }; + real_t beta_ij { metric.beta1({ xi[0] - HALF, xi[1]}) }; + real_t alpha_ij { metric.alpha({ xi[0] - HALF, xi[1]}) }; + + // D1 at ( i + HALF , j ) + x0m[0] = xi[0] - HALF; + x0m[1] = xi[1]; + x0p[0] = xi[0] + HALF; + x0p[1] = xi[1]; + real_t E1d { (A_0(x0p) - A_0(x0m)) }; + real_t D1d { E1d / alpha_iPj }; + + // D3 at ( i , j ) + x0m[0] = xi[0] - HALF - HALF; + x0m[1] = xi[1]; + x0p[0] = xi[0] - HALF + HALF; + x0p[1] = xi[1]; + real_t B2_aux { -(A_3(x0p) - A_3(x0m)) * inv_sqrt_detH_ij }; + real_t D3d { -sqrt_detH_ij * beta_ij * B2_aux / alpha_ij }; + + real_t D1u { metric.template h<1, 1>({ xi[0], xi[1] }) * D1d + metric.template h<1, 3>({ xi[0], xi[1] }) * D3d }; + + return D1u; } - Inline auto dx2(const coord_t& x_Ph) const -> real_t { - return ZERO; + Inline auto dx2(const coord_t& x_Ph) const -> real_t { // at ( i , j + HALF ) + coord_t xi {ZERO}, x0m { ZERO }, x0p { ZERO }; + metric.template convert(x_Ph, xi); + x0m[0] = xi[0]; + x0m[1] = xi[1] - HALF; + x0p[0] = xi[0]; + x0p[1] = xi[1] + HALF; + real_t inv_sqrt_detH_ijP { ONE / metric.sqrt_det_h({ xi[0], xi[1] }) }; + real_t sqrt_detH_ijP { metric.sqrt_det_h({ xi[0], xi[1] }) }; + real_t alpha_ijP { metric.alpha({ xi[0], xi[1] }) }; + real_t beta_ijP { metric.beta1({ xi[0], xi[1] }) }; + + real_t E2d { (A_0(x0p) - A_0(x0m)) }; + real_t B3_aux { -(A_1(x0p) - A_1(x0m)) * inv_sqrt_detH_ijP }; + real_t D2d { E2d / alpha_ijP + sqrt_detH_ijP * beta_ijP * B3_aux / alpha_ijP }; + real_t D2u { metric.template h<2, 2>({ xi[0], xi[1] }) * D2d }; + + return D2u; } - Inline auto dx3(const coord_t& x_Ph) const -> real_t { - return ZERO; + Inline auto dx3(const coord_t& x_Ph) const -> real_t { // at ( i , j ) + coord_t xi {ZERO}, x0m { ZERO }, x0p { ZERO }; + metric.template convert(x_Ph, xi); + real_t inv_sqrt_detH_ij { ONE / metric.sqrt_det_h({ xi[0], xi[1] }) }; + real_t sqrt_detH_ij { metric.sqrt_det_h({ xi[0], xi[1] }) }; + real_t beta_ij { metric.beta1({ xi[0], xi[1] }) }; + real_t alpha_ij { metric.alpha({ xi[0], xi[1] }) }; + real_t alpha_iPj { metric.alpha({ xi[0] + HALF, xi[1] }) }; + + // D3 at ( i , j ) + x0m[0] = xi[0] - HALF; + x0m[1] = xi[1]; + x0p[0] = xi[0] + HALF; + x0p[1] = xi[1]; + real_t B2_aux { -(A_3(x0p) - A_3(x0m)) * inv_sqrt_detH_ij}; + real_t D3d { -sqrt_detH_ij * beta_ij * B2_aux / alpha_ij }; + + // D1 at ( i + HALF , j ) + x0m[0] = xi[0] + HALF - HALF; + x0m[1] = xi[1]; + x0p[0] = xi[0] + HALF + HALF; + x0p[1] = xi[1]; + real_t E1d { (A_0(x0p) - A_0(x0m)) }; + real_t D1d { E1d / alpha_iPj }; + + return metric.template h<3, 3>({ xi[0], xi[1] }) * D3d + metric.template h<1, 3>({ xi[0], xi[1] }) * D1d; } private: From 320292467f50dbd31ceb4036ab7a9489765b7420 Mon Sep 17 00:00:00 2001 From: Siddhant Solanki Date: Thu, 12 Dec 2024 16:48:27 -0500 Subject: [PATCH 181/773] create mirror views for MPISendRecv in comm_mpi --- src/framework/domain/comm_mpi.hpp | 41 ++++++++++++++++++++++--------- 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/src/framework/domain/comm_mpi.hpp b/src/framework/domain/comm_mpi.hpp index d29a5758b..33431cfe7 100644 --- a/src/framework/domain/comm_mpi.hpp +++ b/src/framework/domain/comm_mpi.hpp @@ -47,15 +47,19 @@ namespace comm { int rank; MPI_Comm_rank(MPI_COMM_WORLD, &rank); + raise::ErrorIf( (send_rank == rank && send_idx != idx) || (recv_rank == rank && recv_idx != idx), "Multiple-domain single-rank communication not yet implemented", HERE); + if ((send_idx == idx) and (recv_idx == idx)) { // trivial copy if sending to self and receiving from self + if (not additive) { + // simply filling the ghost cells if constexpr (D == Dim::_1D) { Kokkos::deep_copy(Kokkos::subview(fld, recv_slice[0], comps), @@ -65,6 +69,7 @@ namespace comm { Kokkos::subview(fld, recv_slice[0], recv_slice[1], comps), Kokkos::subview(fld, send_slice[0], send_slice[1], comps)); } else if constexpr (D == Dim::_3D) { + Kokkos::deep_copy( Kokkos::subview(fld, recv_slice[0], recv_slice[1], recv_slice[2], comps), Kokkos::subview(fld, send_slice[0], send_slice[1], send_slice[2], comps)); @@ -177,13 +182,19 @@ namespace comm { comps.second - comps.first); } } + + auto send_fld_h = Kokkos::create_mirror_view(send_fld); + auto recv_fld_h = Kokkos::create_mirror_view(recv_fld); + Kokkos::deep_copy(send_fld_h, send_fld); if (send_rank >= 0 && recv_rank >= 0) { - MPI_Sendrecv(send_fld.data(), + // Segfault here: print mpi params + // Create host views + MPI_Sendrecv(send_fld_h.data(), nsend, mpi::get_type(), send_rank, 0, - recv_fld.data(), + recv_fld_h.data(), nrecv, mpi::get_type(), recv_rank, @@ -191,14 +202,16 @@ namespace comm { MPI_COMM_WORLD, MPI_STATUS_IGNORE); } else if (send_rank >= 0) { - MPI_Send(send_fld.data(), + MPI_Send(send_fld_h.data(), nsend, mpi::get_type(), send_rank, 0, MPI_COMM_WORLD); + } else if (recv_rank >= 0) { - MPI_Recv(recv_fld.data(), + auto recv_fld_h = Kokkos::create_mirror_view(recv_fld); + MPI_Recv(recv_fld_h.data(), nrecv, mpi::get_type(), recv_rank, @@ -208,7 +221,10 @@ namespace comm { } else { raise::Error("CommunicateField called with negative ranks", HERE); } + Kokkos::deep_copy(recv_fld, recv_fld_h); + if (recv_rank >= 0) { + // !TODO: perhaps directly recv to the fld? if (not additive) { if constexpr (D == Dim::_1D) { @@ -282,16 +298,18 @@ namespace comm { int recv_rank, const range_tuple_t& send_slice, const range_tuple_t& recv_slice) { + auto array_h = Kokkos::create_mirror_view(arr); + Kokkos::deep_copy(array_h, arr); const std::size_t send_count = send_slice.second - send_slice.first; const std::size_t recv_count = recv_slice.second - recv_slice.first; if ((send_rank >= 0) and (recv_rank >= 0) and (send_count > 0) and (recv_count > 0)) { - MPI_Sendrecv(arr.data() + send_slice.first, + MPI_Sendrecv(array_h.data() + send_slice.first, send_count, mpi::get_type(), send_rank, 0, - arr.data() + recv_slice.first, + array_h.data() + recv_slice.first, recv_count, mpi::get_type(), recv_rank, @@ -299,14 +317,14 @@ namespace comm { MPI_COMM_WORLD, MPI_STATUS_IGNORE); } else if ((send_rank >= 0) and (send_count > 0)) { - MPI_Send(arr.data() + send_slice.first, + MPI_Send(array_h.data() + send_slice.first, send_count, mpi::get_type(), send_rank, 0, MPI_COMM_WORLD); } else if ((recv_rank >= 0) and (recv_count > 0)) { - MPI_Recv(arr.data() + recv_slice.first, + MPI_Recv(array_h.data() + recv_slice.first, recv_count, mpi::get_type(), recv_rank, @@ -314,6 +332,7 @@ namespace comm { MPI_COMM_WORLD, MPI_STATUS_IGNORE); } + Kokkos::deep_copy(arr, array_h); } @@ -457,8 +476,7 @@ namespace comm { "PopulateBuffer", indices_to_send.extent(0), Lambda(const size_t i) { - const auto idx = indices_to_send(i); - buffer(i) = arr(idx); + buffer(i) = arr(indices_to_send(i)); }); CommunicateParticleQuantity(buffer, send_rank, recv_rank, send_slice, recv_slice); // Populate from buffer to the particle array @@ -466,8 +484,7 @@ namespace comm { "PopulateFromBuffer", indices_to_allocate.extent(0), Lambda(const size_t i) { - const auto idx = indices_to_allocate(i); - arr(idx) = buffer(indices_to_send.extent(0) + i); + arr(indices_to_allocate(i)) = buffer(indices_to_send.extent(0) + i); }); return; } From 831e7d9cc12e3f484e14c09e3362dfbf00049a39 Mon Sep 17 00:00:00 2001 From: Siddhant Solanki Date: Thu, 12 Dec 2024 16:49:43 -0500 Subject: [PATCH 182/773] fixed function to time old and new communication routines --- benchmark/benchmark.cpp | 282 +++++++++++++++++----------------------- 1 file changed, 116 insertions(+), 166 deletions(-) diff --git a/benchmark/benchmark.cpp b/benchmark/benchmark.cpp index 5eebb4d2d..6bfe5c7c7 100644 --- a/benchmark/benchmark.cpp +++ b/benchmark/benchmark.cpp @@ -5,11 +5,11 @@ #include "framework/domain/domain.h" #include "framework/domain/metadomain.h" #include "framework/containers/particles.h" +#include "framework/domain/communications.cpp" #include "metrics/metric_base.h" #include "metrics/minkowski.h" -#include "arch/mpi_tags.h" - #include + #define TIMER_START(label) \ Kokkos::fence(); \ auto start_##label = std::chrono::high_resolution_clock::now(); @@ -22,105 +22,88 @@ /* Test to check the performance of the new particle allocation scheme - - Create a metadomain object - - Create particle array - - Initialize the position and velocities of the particles - - Set a large timestep (see where that is set) - - Make a loop of N iterations, where the positions of particles is sorted - and pushed - - Check if the particle tags are correct after each iteration + - Create a metadomain object main() + - Set npart + initialize tags InitializeParticleArrays() + - 'Push' the particles by randomly updating the tags PushParticles() + - Communicate particles to neighbors and time the communication - Compute the time taken for best of N iterations for the communication */ - -/* - Structure of the 2D domain - ---------------------------------- (3,3) - | | | | - | | | | - | | | | - | | | | - ---------------------------------- (3,2) - | | | | - | | | | - | | | | - | | | | - ---------------------------------- (3,1) - | | | | - | | | | - | | | | - | | | | - ---------------------------------- - (0,0) (1,0) (2,0) (3,0) -*/ - -/* - Function to check the tags of a domain object to make sure that - all the tags are alive. If the tags are not alive then the function - prints the tag count for each of the particles along with the rank - of the domain. -*/ +// Set npart and set the particle tags to alive template -void CheckDomainTags(Domain& domain) -{ - bool all_alive = true; - bool no_dead_particles = true; - for (auto& species : domain.species) { - std::cout << "Checking domain tags for species: " << species.label() << std::endl; - const auto npart_per_tag_arr = species.npart_per_tag(); - const auto npart = species.npart(); - if (npart != npart_per_tag_arr[ParticleTag::alive]){ - all_alive = false; - } - for (std::size_t i = 0; i < npart_per_tag_arr.size(); ++i) { - if (i == ParticleTag::alive) { - continue; - } - if (npart_per_tag_arr[i] != 0) { - no_dead_particles = false; +void InitializeParticleArrays(Domain &domain, const int npart){ + raise::ErrorIf(npart > domain.species[0].maxnpart(), + "Npart cannot be greater than maxnpart", HERE); + const auto nspecies = domain.species.size(); + for (int i_spec = 0; i_spec < nspecies; i_spec++) { + domain.species[i_spec].set_npart(npart); + domain.species[i_spec].SyncHostDevice(); + auto &this_tag = domain.species[i_spec].tag; + Kokkos::parallel_for( + "Initialize particles", + npart, + Lambda(const std::size_t i) + { + this_tag(i) = ParticleTag::alive; } - } - - raise::ErrorIf(all_alive == false, - "Array contains particles with tags other than alive", - HERE); - raise::ErrorIf(no_dead_particles == false, - "Array contains dead particles", - HERE); - //raise::ErrorIf(tag_check_h(0) == false, - // "Tag check failed", - // HERE); + ); } return; } -void InitializePositionsDomain(Domain>& domain) -{ - for (auto& species : domain.species) { - TIMER_START(Sorting_timer); - species.SortByTags(); - TIMER_STOP(Sorting_timer); - species.SyncHostDevice(); - std::cout << "Number of particles in domain: " << species.npart() << std::endl; - //std::cout << "Extent of i1" << species.i1.extent(0) << std::endl; +// Randomly reassign tags to particles for a fraction of particles +template +void PushParticles(Domain &domain, const double send_frac, + const int seed_ind, const int seed_tag){ + raise::ErrorIf(send_frac > 1.0, "send_frac cannot be greater than 1.0", HERE); + const auto nspecies = domain.species.size(); + for (int i_spec = 0; i_spec < nspecies; i_spec++) { + domain.species[i_spec].set_unsorted(); + const auto nparticles = domain.species[i_spec].npart(); + const auto nparticles_to_send = static_cast(send_frac * nparticles); + // Generate random indices to send + Kokkos::Random_XorShift64_Pool<> random_pool(seed_ind); + Kokkos::View indices_to_send("indices_to_send", nparticles_to_send); + Kokkos::fill_random(indices_to_send, random_pool, 0, nparticles); + // Generate random tags to send + Kokkos::Random_XorShift64_Pool<> random_pool_tag(seed_tag); + Kokkos::View tags_to_send("tags_to_send", nparticles_to_send); + Kokkos::fill_random(tags_to_send, random_pool_tag, 0, domain.species[i_spec].ntags()); + auto &this_tag = domain.species[i_spec].tag; + Kokkos::parallel_for( + "Push particles", + nparticles_to_send, + Lambda(const std::size_t i) + { + auto prtl_to_send = indices_to_send(i); + auto tag_to_send = tags_to_send(i); + this_tag(prtl_to_send) = tag_to_send; + } + ); + domain.species[i_spec].npart_per_tag(); + domain.species[i_spec].SyncHostDevice(); } - CheckDomainTags(domain); + return; } - - auto main(int argc, char* argv[]) -> int { std::cout << "Constructing the domain" << std::endl; ntt::GlobalInitialize(argc, argv); // Create a Metadomain object - const unsigned int ndomains = 9; - const std::vector global_decomposition = {{}}; - const std::vector global_ncells = {32, 32}; - const boundaries_t global_extent = {{0.0, 0.0}, {3.0, 3.0}}; - const boundaries_t global_flds_bc = {{FldsBC::PERIODIC, FldsBC::PERIODIC}, {FldsBC::PERIODIC, FldsBC::PERIODIC}}; - const boundaries_t global_prtl_bc = {{PrtlBC::PERIODIC, PrtlBC::PERIODIC}, {PrtlBC::PERIODIC, PrtlBC::PERIODIC}}; + const unsigned int ndomains = 1; + const std::vector global_decomposition = {{-1,-1, -1}}; + const std::vector global_ncells = {32, 32, 32}; + const boundaries_t global_extent = {{0.0, 3.0}, {0.0, 3.0}, {0.0, 3.0}}; + const boundaries_t global_flds_bc = { {FldsBC::PERIODIC, FldsBC::PERIODIC}, + {FldsBC::PERIODIC, FldsBC::PERIODIC}, + {FldsBC::PERIODIC, FldsBC::PERIODIC}}; + const boundaries_t global_prtl_bc = { {PrtlBC::PERIODIC, PrtlBC::PERIODIC}, + {PrtlBC::PERIODIC, PrtlBC::PERIODIC}, + {PrtlBC::PERIODIC, PrtlBC::PERIODIC}}; const std::map metric_params = {}; - const int maxnpart = 1000; + const int maxnpart = argc > 1 ? std::stoi(argv[1]) : 1000; + const double npart_to_send_frac = 0.01; + const int npart = static_cast(maxnpart * (1 - 2 * npart_to_send_frac)); auto species = ntt::Particles(1u, "test_e", 1.0f, @@ -129,35 +112,7 @@ auto main(int argc, char* argv[]) -> int { ntt::PrtlPusher::BORIS, false, ntt::Cooling::NONE); - - species.set_npart(maxnpart); - auto &this_i1 = species.i1; - auto &this_i2 = species.i2; - auto &this_i3 = species.i3; - auto &this_dx1 = species.dx1; - auto &this_dx2 = species.dx2; - auto &this_dx3 = species.dx3; - auto &this_ux1 = species.ux1; - auto &this_ux2 = species.ux2; - auto &this_ux3 = species.ux3; - auto &this_tag = species.tag; - - std::cout << "Species particle count is " << species.npart() << std::endl; - Kokkos::parallel_for("SetPositions", - species.npart(), Lambda(const std::size_t i) { - this_i1(i) = 1; - this_i2(i) = 1; - this_i3(i) = 1; - this_dx1(i) = 0.01; - this_dx2(i) = 0.01; - this_ux1(i) = 0.; - this_ux2(i) = 0.; - this_ux3(i) = 0.; - this_tag(i) = 1; - }); - Kokkos::fence(); - std::cout << "Species set " << species.npart() << std::endl; - auto metadomain = Metadomain> + auto metadomain = Metadomain> ( ndomains, global_decomposition, global_ncells, @@ -168,58 +123,53 @@ auto main(int argc, char* argv[]) -> int { {species} ); - //metadomain.runOnLocalDomains([&](auto& loc_dom) { - // InitializePositionsDomain(loc_dom); - //}); - - // Get the pointer to the subdomain - //const auto local_subdomain_idx = metadomain.l_subdomain_indices()[0]; - //auto local_domain = metadomain.subdomain_ptr(local_subdomain_idx); - - // Set the positions of the particles in each domain - //for (auto& species : local_domain->species) - //{ - // auto tag = ParticleTag::alive; - // auto &this_i1 = species.i1; - // auto &this_i2 = species.i2; - // auto &this_i3 = species.i3; - // auto &this_dx1 = species.dx1; - // auto &this_dx2 = species.dx2; - // auto &this_dx3 = species.dx3; - // auto &this_ux1 = species.ux1; - // auto &this_ux2 = species.ux2; - // auto &this_ux3 = species.ux3; - // auto &this_tag = species.tag; - // Kokkos::parallel_for("SetPositions", - // species.npart(), Lambda(const std::size_t i) { - // this_i1(i) = 1; - // this_i2(i) = 1; - // this_i3(i) = 0; - // this_dx1(i) = 0.01; - // this_dx2(i) = 0.01; - // this_ux1(i) = 0.5; - // this_ux2(i) = 0.5; - // this_tag(i) = tag; - // }); -// - //species.SortByTags(); - //species.SyncHostDevice(); - //} - - // Get and print the extent of each domain - //std::cout << fmt::format("x1 extent {%.2f; %.2f} \n", - // local_domain->mesh.extent(in::x1).first, - // local_domain->mesh.extent(in::x1).second); - //std::cout << fmt::format("x2 extent {%.2f; %.2f} \n", - // local_domain->mesh.extent(in::x2).first, - // local_domain->mesh.extent(in::x2).second); - // Print the number of particles per domain - //std::cout << "Number of particles in domain " << local_subdomain_idx << ": " << local_domain->species[0].npart() << std::endl; - // Print the position of the 5 particles in the domain - - ntt::GlobalFinalize(); - - std::cout << "Terminating" << std::endl; - + const auto local_subdomain_idx = metadomain.l_subdomain_indices()[0]; + auto local_domain = metadomain.subdomain_ptr(local_subdomain_idx); + auto timers = timer::Timers {{"Communication"}, nullptr, false}; + InitializeParticleArrays(*local_domain, npart); + // Timers for both the communication routines + auto total_time_elapsed_old = 0; + auto total_time_elapsed_new = 0; + + int seed_ind = 0; + int seed_tag = 1; + for (int i = 0; i < 10; ++i) { + // Push + seed_ind += 2; + seed_tag += 3; + PushParticles(*local_domain, npart_to_send_frac, seed_ind, seed_tag); + // Sort new + Kokkos::fence(); + auto start_new = std::chrono::high_resolution_clock::now(); + metadomain.CommunicateParticlesBuffer(*local_domain, &timers); + auto stop_new = std::chrono::high_resolution_clock::now(); + auto duration_new = std::chrono::duration_cast(stop_new - start_new).count(); + total_time_elapsed_new += duration_new; + Kokkos::fence(); + // Push + seed_ind += 2; + seed_tag += 3; + PushParticles(*local_domain, npart_to_send_frac, seed_ind, seed_tag); + // Sort old + Kokkos::fence(); + auto start_old = std::chrono::high_resolution_clock::now(); + metadomain.CommunicateParticles(*local_domain, &timers); + auto stop_old = std::chrono::high_resolution_clock::now(); + auto duration_old = std::chrono::duration_cast(stop_old - start_old).count(); + total_time_elapsed_old += duration_old; + Kokkos::fence(); + } + std::cout << "Total time elapsed for old: " << total_time_elapsed_old << " microseconds" << std::endl; + std::cout << "Total time elapsed for new: " << total_time_elapsed_new << " microseconds" << std::endl; return 0; } + +/* + Buggy behavior: + Consider a single domain with a single mpi rank + Particle tag arrays is set to [0, 0, 1, 1, 2, 3, ...] for a single domain + CommunicateParticles() discounts all the dead particles and reassigns the + other tags to alive + CommunicateParticlesBuffer() only keeps the ParticleTag::Alive particles + and discounts the rest +*/ \ No newline at end of file From c9b70f528790f11a9a2827631502df78062b4f28 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Mon, 16 Dec 2024 15:38:24 -0500 Subject: [PATCH 183/773] boris tests with non-zero spin --- setups/grpic/pusher/boris_a09.toml | 85 ++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 setups/grpic/pusher/boris_a09.toml diff --git a/setups/grpic/pusher/boris_a09.toml b/setups/grpic/pusher/boris_a09.toml new file mode 100644 index 000000000..379e9c323 --- /dev/null +++ b/setups/grpic/pusher/boris_a09.toml @@ -0,0 +1,85 @@ +[simulation] + name = "boris_a09" + engine = "grpic" + runtime = 500.0 + +[grid] + resolution = [128,128] + extent = [[1.2, 20.0]] + + [grid.metric] + metric = "kerr_schild" + qsph_r0 = 0.0 + qsph_h = 0.0 + ks_a = 0.9 + + [grid.boundaries] + fields = [["ABSORB"]] + particles = [["ABSORB"]] + + [grid.boundaries.absorb] + ds = 0.5 + +[scales] + larmor0 = 0.5 + skindepth0 = 1e0 + +[algorithms] + current_filters = 4 + + [algorithms.gr] + pusher_niter = 10 + pusher_eps = 1e-6 + + [algorithms.timestep] + CFL = 1.0 + + [algorithms.toggles] + deposit = false + fieldsolver = false + +[particles] + ppc0 = 1.0 + + [[particles.species]] + label = "e+" + mass = 1.0 + charge = 1.0 + maxnpart = 1e0 + + [[particles.species]] + label = "e-" + mass = 1.0 + charge = -1.0 + maxnpart = 1e0 + +[setup] + # Stuchlik and Kolos (2015) Fig.11 ~ RKA3 from Bacchini et al + x1s = [4.000000] + y1s = [1.3707963268] + z1s = [0.000000] + ux1s = [0.625666] + uy1s = [0.000000] + uz1s = [1.580567] + +[output] + format = "hdf5" + + [output.fields] + enable = true + interval_time = 1.0 + quantities = ["D", "B"] + + [output.particles] + enable = true + stride = 1 + interval_time = 0.2 + species = [] + + [output.spectra] + enable = false + +[diagnostics] + interval = 10 + colored_stdout = true + blocking_timers = true From 896a9570fa0347abd2e158167ec73189f2ff8541 Mon Sep 17 00:00:00 2001 From: Siddhant Solanki Date: Mon, 16 Dec 2024 16:13:27 -0500 Subject: [PATCH 184/773] bug fix in comm --- src/framework/domain/comm_mpi.hpp | 13 +- src/framework/domain/communications.cpp | 193 +++++++++++++++++++----- 2 files changed, 165 insertions(+), 41 deletions(-) diff --git a/src/framework/domain/comm_mpi.hpp b/src/framework/domain/comm_mpi.hpp index 33431cfe7..2251968c4 100644 --- a/src/framework/domain/comm_mpi.hpp +++ b/src/framework/domain/comm_mpi.hpp @@ -499,6 +499,16 @@ namespace comm { if ((send_rank < 0) && (recv_rank < 0)) { raise::Error("No send or recv in SendRecvParticlesBuffered", HERE); } + // First set the tags of the sent particles to be dead + auto& this_tag = species.tag; + //Kokkos::parallel_for( + //"SetTagDead", + //Kokkos::RangePolicy(0, indices_to_allocate.size()), + //KOKKOS_LAMBDA(const size_t i) { + // const auto idx = indices_to_send(i); + // this_tag(idx) = static_cast(ParticleTag::dead); + //}); + // Construct send and receive slice for the buffer auto send_slice = range_tuple_t({ 0, indices_to_send.size() }); auto recv_slice = range_tuple_t({ indices_to_send.size(), indices_to_send.size() + @@ -531,8 +541,6 @@ namespace comm { CommunicateParticleQuantityBuffer(species.pld[p], send_rank, recv_rank, send_slice, recv_slice, indices_to_send, indices_to_allocate); } // Set the tag for the received particles to be alive and perform the necessary displacements - auto& this_tag = species.tag; - if constexpr (D == Dim::_1D) { const auto shift_in_x1 = shifts_in_x[0]; @@ -595,6 +603,7 @@ namespace comm { this_i3_prev(idx) += shift_in_x3; }); } + Kokkos::fence(); return; } diff --git a/src/framework/domain/communications.cpp b/src/framework/domain/communications.cpp index cdd32aed6..a43b635b7 100644 --- a/src/framework/domain/communications.cpp +++ b/src/framework/domain/communications.cpp @@ -657,22 +657,26 @@ template HERE); logger::Checkpoint("Communicating particles\n", HERE); for (auto& species : domain.species) { - const auto npart_per_tag_arr = species.npart_per_tag(); - const auto tag_offset = species.tag_offset_h; - auto index_last = tag_offset[tag_offset.extent(0) - 1] + - npart_per_tag_arr[npart_per_tag_arr.size() - 1]; + auto npart_per_tag_arr = species.npart_per_tag(); + auto npart = static_cast(species.npart()); + auto total_alive = static_cast(npart_per_tag_arr[ParticleTag::alive]); + auto total_dead = static_cast(npart_per_tag_arr[ParticleTag::dead]); + auto total_holes = static_cast(npart - total_alive); + auto total_send = static_cast(npart - total_alive - total_dead); + auto total_recv = static_cast(0); + auto tag_count = static_cast(npart_per_tag_arr.size()); + std::vector send_ranks, send_inds; std::vector recv_ranks, recv_inds; // at this point particles should already by tagged in the pusher #if defined(MPI_ENABLED) - timers->start("Communications_sendrecv"); + // Defined for debugging + int mpi_rank; + MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); + // array that holds the number of particles to be received per tag - std::vector npart_per_tag_arr_recv(npart_per_tag_arr.size(), 0); - std::size_t total_recv_count = 0; - const std::size_t total_send_count = species.npart() - - npart_per_tag_arr[ParticleTag::alive] - - npart_per_tag_arr[ParticleTag::dead]; - for (auto& direction : dir::Directions::all) { + std::vector npart_per_tag_arr_recv(tag_count, 0); + for (auto& direction : dir::Directions::all) { const auto [send_params, recv_params] = GetSendRecvParams(this, domain, direction, true); const auto [send_indrank, send_slice] = send_params; @@ -694,11 +698,11 @@ template recv_rank, nsend, nrecv); - total_recv_count += nrecv; + total_recv += nrecv; npart_per_tag_arr_recv[mpi::PrtlSendTag::dir2tag(-direction)] = nrecv; } - timers->stop("Communications_sendrecv"); - raise::FatalIf((index_last + total_recv_count) >= species.maxnpart(), + + raise::FatalIf((npart + total_recv) >= species.maxnpart(), "Too many particles to receive (cannot fit into maxptl)", HERE); // Now we know the number of particles to be sent and received per direction @@ -712,54 +716,89 @@ template tag=0 ct tag=1 ct tag=3 ct (dead) (alive) (tag1) ... */ - timers->start("PermuteVector"); auto& this_tag = species.tag; auto& this_tag_offset = species.tag_offset; Kokkos::View permute_vector("permute_vector", species.npart()); - // Current offset is a helper array used to create permute vector - // It stores the number of particles of a given tag type stored during the loop Kokkos::View current_offset("current_offset", species.ntags()); + Kokkos::parallel_for( "PermuteVector", species.npart(), Lambda(const std::size_t p) { - auto current_tag = this_tag(p); - auto idx_permute_vec = this_tag_offset(current_tag) + current_offset(current_tag); - Kokkos::atomic_fetch_add(¤t_offset(current_tag), 1); + auto current_tag = this_tag(p); + auto i_current_tag_offset = Kokkos::atomic_fetch_add(¤t_offset(current_tag), 1); + auto idx_permute_vec = this_tag_offset(current_tag) + i_current_tag_offset; permute_vector(idx_permute_vec) = static_cast(p); }); - timers->stop("PermuteVector"); + + // Check: add the end of the loop, current_offset should be equal to npart_per_tag + auto current_offset_h = Kokkos::create_mirror_view(current_offset); + Kokkos::deep_copy(current_offset_h, current_offset); + for (std::size_t i { 0 }; i < current_offset_h.size(); ++i) { + raise::FatalIf(current_offset_h(i) != npart_per_tag_arr[i], + "Error in permute vector construction", + HERE); + } // allocation_vector(p) assigns the pth received particle // to the pth hole in the array, or after npart() if p > sent+dead count. - Kokkos::View allocation_vector("allocation_vector", total_recv_count); - auto allocation_vector_h = Kokkos::create_mirror_view(allocation_vector); - std::size_t n_alive = npart_per_tag_arr[ParticleTag::alive]; - std::size_t n_dead = npart_per_tag_arr[ParticleTag::dead]; - std::size_t n_holes = species.npart() - n_alive; + Kokkos::View allocation_vector("allocation_vector", total_recv); + + // TWO BUGS: when nsend = nrecv, an extra dead particle is created out of nowhere + // when nrecv > nsend but < nrecv < nsend + ndead, tags of alive particles are not changed - timers->start("AllocationVector"); Kokkos::parallel_for( "AllocationVector", - total_recv_count, + total_recv, Lambda(const std::size_t p) { // Case: recevied particle count less than dead particle count -> replace dead particles - if (p < n_dead){ + if (p < total_dead){ allocation_vector(p) = permute_vector(p); } // Case: received particle count > dead particle count but < sent particle count -> replace // sent particles - else if (p <= n_holes){ - allocation_vector(p) = permute_vector(n_alive + p); + else if (p < total_holes && p >= total_dead){ + allocation_vector(p) = permute_vector(total_alive + p); } // Case: received particle count exceeds sent + dead particles -> append at the end else { - allocation_vector(p) = static_cast(index_last + (p - n_holes)); + allocation_vector(p) = static_cast(npart + (p - total_holes)); } }); - Kokkos::deep_copy(allocation_vector_h, allocation_vector); - timers->stop("AllocationVector"); + Kokkos::fence(); + + // Compute where the received particles are allocated + if (mpi_rank == 0){ + Kokkos::View particles_allocated_per_tag("particles allocated per tag", tag_count); + Kokkos::parallel_for( + "ParticlesAllocatedPerTag", + total_recv, + Lambda(const std::size_t i) { + auto index = allocation_vector(i); + auto tag = this_tag(index); + Kokkos::atomic_fetch_add(&particles_allocated_per_tag(tag), 1); + }); + Kokkos::fence(); + auto particles_allocated_per_tag_h = Kokkos::create_mirror_view(particles_allocated_per_tag); + Kokkos::deep_copy(particles_allocated_per_tag_h, particles_allocated_per_tag); + std::cout << "Particles allocated per tag (pre recv): "; + for (std::size_t i = 0; i < tag_count; i++){ + std::cout << "[" << particles_allocated_per_tag_h[i] << "] "; + } + std::cout << std::endl; + } + + + // Check if the particle tags are only dead or alive + //if (mpi_rank == 0){ + // std::cout << "Before COMM: " << std::endl; + // std::cout << "Tag counts: "; + // for (std::size_t i = 0; i < tag_count; i++){ + // std::cout << "[" << npart_per_tag_arr[i] << "] "; + // } + // std::cout << std::endl; + //} std::size_t count_recv = 0; std::size_t iteration = 0; // Main loop over all direction where we send the data @@ -821,8 +860,8 @@ template } // Tuple that contains the start and end indices of permtute_vec pointing to a given tag type = dir2tag(dir) - auto range_permute = std::make_pair(static_cast(tag_offset[mpi::PrtlSendTag::dir2tag(direction)]), - static_cast(tag_offset[mpi::PrtlSendTag::dir2tag(direction)] + + auto range_permute = std::make_pair(static_cast(species.tag_offset_h[mpi::PrtlSendTag::dir2tag(direction)]), + static_cast(species.tag_offset_h[mpi::PrtlSendTag::dir2tag(direction)] + npart_per_tag_arr[mpi::PrtlSendTag::dir2tag(direction)])); // Tuple that contains the start and end indices for allocation_vector pointing to a given tag type = dir2tag(dir) auto range_allocate = std::make_pair(static_cast(count_recv), @@ -843,9 +882,85 @@ template count_recv += npart_per_tag_arr_recv[mpi::PrtlSendTag::dir2tag(-direction)]; iteration++; } - // If receive count is less than send count then make the tags of sent dead ? Ask Hayk - species.set_npart(index_last + std::max(total_recv_count, total_send_count) - total_send_count); -#endif + // Compute where the received particles are allocated + //if (mpi_rank == 0){ + //Kokkos::View particles_allocated_per_tag("particles allocated per tag", tag_count); + //Kokkos::parallel_for( + // "ParticlesAllocatedPerTag", + // total_recv, + // Lambda(const std::size_t i) { + // auto index = allocation_vector(i); + // auto tag = this_tag(index); + // Kokkos::atomic_fetch_add(&particles_allocated_per_tag(tag), 1); + // }); + //Kokkos::fence(); + //auto particles_allocated_per_tag_h = Kokkos::create_mirror_view(particles_allocated_per_tag); + //Kokkos::deep_copy(particles_allocated_per_tag_h, particles_allocated_per_tag); + + //std::cout << "Particles allocated per tag (post recv): "; + //for (std::size_t i = 0; i < tag_count; i++){ + // std::cout << "[" << particles_allocated_per_tag_h[i] << "] "; + //} + //std::cout << std::endl; + // } + // If receive count is less than send count then make the tags of sent dead + if (total_recv <= total_holes){ + if (total_recv <= total_dead){ + // Case: all sent particles' tags are set to dead + /* (received) + [ | <------------------> | <-------->] + (dead) (alive) (sent) + || + (to be made dead) + ^ + (offset) + */ + + auto offset = total_alive + total_dead; + Kokkos::parallel_for( + "CommunicateParticles", + total_send, + Lambda(index_t p) { + this_tag(permute_vector(offset + p)) = ParticleTag::dead; + }); + } + else{ + // Case: tags of sent particles that are not replaced by recevied particles are made dead + /* (received) (received) + [ | <------------------> |] + (dead) (alive) (sent) + || + (to be made dead) + ^ + (offset) + */ + auto offset = total_alive + total_recv; + Kokkos::parallel_for( + "CommunicateParticles", + total_send - (total_recv - total_dead), + Lambda(index_t p) { + this_tag(permute_vector(offset + p)) = ParticleTag::dead; + }); + } + } + + + // Check if the particle tags are only dead or alive + species.set_npart(npart + std::max(total_send, total_recv) - total_send); + npart_per_tag_arr = species.npart_per_tag(); + //if (mpi_rank == 0) + //{ + // std::cout << "After COMM: " << std::endl; + // std::cout << "Tag counts: "; + // for (std::size_t i = 0; i < tag_count; i++){ + // std::cout << "[" << npart_per_tag_arr[i] << "] "; + // } + // std::cout << std::endl; + // std::cout << "Holes filled: " << total_holes << " Total recv: " << total_recv << + // "Total send: " << total_send << std::endl; + // std::cout << std::endl << "*************"<< std::endl; + //} + #endif } } From 9391c196f5e8c65ef4d43a9e924b948b9ab77adf Mon Sep 17 00:00:00 2001 From: hayk Date: Mon, 16 Dec 2024 17:19:36 -0500 Subject: [PATCH 185/773] fmt --- TASKLIST.md | 4 + benchmark/benchmark.cpp | 230 +++++++++------- extern/Kokkos | 2 +- extern/adios2 | 2 +- extern/plog | 2 +- src/framework/domain/comm_mpi.hpp | 333 +++++++++++++++--------- src/framework/domain/communications.cpp | 322 +++++++++++------------ 7 files changed, 499 insertions(+), 396 deletions(-) diff --git a/TASKLIST.md b/TASKLIST.md index 069a7deb2..c12f60f4c 100644 --- a/TASKLIST.md +++ b/TASKLIST.md @@ -3,3 +3,7 @@ - [ ] removing temporary variables in interpolation - [ ] passing by value vs const ref in metric - [ ] return physical coords one-by-one instead of by passing full vector + +### Things to look into + +1. _h fields in mpi communication diff --git a/benchmark/benchmark.cpp b/benchmark/benchmark.cpp index 6bfe5c7c7..797c8ed87 100644 --- a/benchmark/benchmark.cpp +++ b/benchmark/benchmark.cpp @@ -2,59 +2,65 @@ #include "global.h" #include "utils/error.h" -#include "framework/domain/domain.h" -#include "framework/domain/metadomain.h" -#include "framework/containers/particles.h" -#include "framework/domain/communications.cpp" + #include "metrics/metric_base.h" #include "metrics/minkowski.h" + +#include "framework/containers/species.h" +#include "framework/domain/domain.h" +#include "framework/domain/metadomain.h" + #include -#define TIMER_START(label) \ - Kokkos::fence(); \ - auto start_##label = std::chrono::high_resolution_clock::now(); +#include "framework/domain/communications.cpp" + +#define TIMER_START(label) \ + Kokkos::fence(); \ + auto start_##label = std::chrono::high_resolution_clock::now(); -#define TIMER_STOP(label) \ - Kokkos::fence(); \ - auto stop_##label = std::chrono::high_resolution_clock::now(); \ - auto duration_##label = std::chrono::duration_cast(stop_##label - start_##label).count(); \ - std::cout << "Timer [" #label "]: " << duration_##label << " microseconds" << std::endl; +#define TIMER_STOP(label) \ + Kokkos::fence(); \ + auto stop_##label = std::chrono::high_resolution_clock::now(); \ + auto duration_##label = std::chrono::duration_cast( \ + stop_##label - start_##label) \ + .count(); \ + std::cout << "Timer [" #label "]: " << duration_##label << " microseconds" \ + << std::endl; /* Test to check the performance of the new particle allocation scheme - - Create a metadomain object main() - - Set npart + initialize tags InitializeParticleArrays() - - 'Push' the particles by randomly updating the tags PushParticles() + - Create a metadomain object main() + - Set npart + initialize tags InitializeParticleArrays() + - 'Push' the particles by randomly updating the tags PushParticles() - Communicate particles to neighbors and time the communication - Compute the time taken for best of N iterations for the communication */ // Set npart and set the particle tags to alive template -void InitializeParticleArrays(Domain &domain, const int npart){ - raise::ErrorIf(npart > domain.species[0].maxnpart(), - "Npart cannot be greater than maxnpart", HERE); +void InitializeParticleArrays(Domain& domain, const int npart) { + raise::ErrorIf(npart > domain.species[0].maxnpart(), + "Npart cannot be greater than maxnpart", + HERE); const auto nspecies = domain.species.size(); for (int i_spec = 0; i_spec < nspecies; i_spec++) { domain.species[i_spec].set_npart(npart); domain.species[i_spec].SyncHostDevice(); - auto &this_tag = domain.species[i_spec].tag; + auto& this_tag = domain.species[i_spec].tag; Kokkos::parallel_for( "Initialize particles", npart, - Lambda(const std::size_t i) - { - this_tag(i) = ParticleTag::alive; - } - ); + Lambda(const std::size_t i) { this_tag(i) = ParticleTag::alive; }); } return; } // Randomly reassign tags to particles for a fraction of particles template -void PushParticles(Domain &domain, const double send_frac, - const int seed_ind, const int seed_tag){ +void PushParticles(Domain& domain, + const double send_frac, + const int seed_ind, + const int seed_tag) { raise::ErrorIf(send_frac > 1.0, "send_frac cannot be greater than 1.0", HERE); const auto nspecies = domain.species.size(); for (int i_spec = 0; i_spec < nspecies; i_spec++) { @@ -62,26 +68,27 @@ void PushParticles(Domain &domain, const double send_frac, const auto nparticles = domain.species[i_spec].npart(); const auto nparticles_to_send = static_cast(send_frac * nparticles); // Generate random indices to send - Kokkos::Random_XorShift64_Pool<> random_pool(seed_ind); + // Kokkos::Random_XorShift64_Pool<> random_pool(seed_ind); Kokkos::View indices_to_send("indices_to_send", nparticles_to_send); - Kokkos::fill_random(indices_to_send, random_pool, 0, nparticles); + Kokkos::fill_random(indices_to_send, domain.random_pool, 0, nparticles); // Generate random tags to send - Kokkos::Random_XorShift64_Pool<> random_pool_tag(seed_tag); + // Kokkos::Random_XorShift64_Pool<> random_pool_tag(seed_tag); Kokkos::View tags_to_send("tags_to_send", nparticles_to_send); - Kokkos::fill_random(tags_to_send, random_pool_tag, 0, domain.species[i_spec].ntags()); - auto &this_tag = domain.species[i_spec].tag; + Kokkos::fill_random(tags_to_send, + domain.random_pool, + 0, + domain.species[i_spec].ntags()); + auto& this_tag = domain.species[i_spec].tag; Kokkos::parallel_for( - "Push particles", - nparticles_to_send, - Lambda(const std::size_t i) - { - auto prtl_to_send = indices_to_send(i); - auto tag_to_send = tags_to_send(i); - this_tag(prtl_to_send) = tag_to_send; - } - ); - domain.species[i_spec].npart_per_tag(); - domain.species[i_spec].SyncHostDevice(); + "Push particles", + nparticles_to_send, + Lambda(const std::size_t i) { + auto prtl_to_send = indices_to_send(i); + auto tag_to_send = tags_to_send(i); + this_tag(prtl_to_send) = tag_to_send; + }); + domain.species[i_spec].npart_per_tag(); + domain.species[i_spec].SyncHostDevice(); } return; } @@ -90,42 +97,51 @@ auto main(int argc, char* argv[]) -> int { std::cout << "Constructing the domain" << std::endl; ntt::GlobalInitialize(argc, argv); // Create a Metadomain object - const unsigned int ndomains = 1; - const std::vector global_decomposition = {{-1,-1, -1}}; - const std::vector global_ncells = {32, 32, 32}; - const boundaries_t global_extent = {{0.0, 3.0}, {0.0, 3.0}, {0.0, 3.0}}; - const boundaries_t global_flds_bc = { {FldsBC::PERIODIC, FldsBC::PERIODIC}, - {FldsBC::PERIODIC, FldsBC::PERIODIC}, - {FldsBC::PERIODIC, FldsBC::PERIODIC}}; - const boundaries_t global_prtl_bc = { {PrtlBC::PERIODIC, PrtlBC::PERIODIC}, - {PrtlBC::PERIODIC, PrtlBC::PERIODIC}, - {PrtlBC::PERIODIC, PrtlBC::PERIODIC}}; + const unsigned int ndomains = 1; + const std::vector global_decomposition = { + { -1, -1, -1 } + }; + const std::vector global_ncells = { 32, 32, 32 }; + const boundaries_t global_extent = { + { 0.0, 3.0 }, + { 0.0, 3.0 }, + { 0.0, 3.0 } + }; + const boundaries_t global_flds_bc = { + { FldsBC::PERIODIC, FldsBC::PERIODIC }, + { FldsBC::PERIODIC, FldsBC::PERIODIC }, + { FldsBC::PERIODIC, FldsBC::PERIODIC } + }; + const boundaries_t global_prtl_bc = { + { PrtlBC::PERIODIC, PrtlBC::PERIODIC }, + { PrtlBC::PERIODIC, PrtlBC::PERIODIC }, + { PrtlBC::PERIODIC, PrtlBC::PERIODIC } + }; const std::map metric_params = {}; - const int maxnpart = argc > 1 ? std::stoi(argv[1]) : 1000; + const int maxnpart = argc > 1 ? std::stoi(argv[1]) : 1000; const double npart_to_send_frac = 0.01; - const int npart = static_cast(maxnpart * (1 - 2 * npart_to_send_frac)); - auto species = ntt::Particles(1u, - "test_e", - 1.0f, - 1.0f, - maxnpart, - ntt::PrtlPusher::BORIS, - false, - ntt::Cooling::NONE); - auto metadomain = Metadomain> - ( ndomains, - global_decomposition, - global_ncells, - global_extent, - global_flds_bc, - global_prtl_bc, - metric_params, - {species} - ); + const int npart = static_cast(maxnpart * (1 - 2 * npart_to_send_frac)); + auto species = ntt::ParticlesSpecies(1u, + "test_e", + 1.0f, + 1.0f, + maxnpart, + ntt::PrtlPusher::BORIS, + false, + ntt::Cooling::NONE); + auto metadomain = Metadomain>( + ndomains, + global_decomposition, + global_ncells, + global_extent, + global_flds_bc, + global_prtl_bc, + metric_params, + { species }); const auto local_subdomain_idx = metadomain.l_subdomain_indices()[0]; - auto local_domain = metadomain.subdomain_ptr(local_subdomain_idx); - auto timers = timer::Timers {{"Communication"}, nullptr, false}; + auto local_domain = metadomain.subdomain_ptr(local_subdomain_idx); + auto timers = timer::Timers { { "Communication" }, nullptr, false }; InitializeParticleArrays(*local_domain, npart); // Timers for both the communication routines auto total_time_elapsed_old = 0; @@ -133,34 +149,46 @@ auto main(int argc, char* argv[]) -> int { int seed_ind = 0; int seed_tag = 1; + Kokkos::fence(); + for (int i = 0; i < 10; ++i) { - // Push - seed_ind += 2; - seed_tag += 3; - PushParticles(*local_domain, npart_to_send_frac, seed_ind, seed_tag); - // Sort new - Kokkos::fence(); - auto start_new = std::chrono::high_resolution_clock::now(); - metadomain.CommunicateParticlesBuffer(*local_domain, &timers); - auto stop_new = std::chrono::high_resolution_clock::now(); - auto duration_new = std::chrono::duration_cast(stop_new - start_new).count(); - total_time_elapsed_new += duration_new; - Kokkos::fence(); - // Push - seed_ind += 2; - seed_tag += 3; - PushParticles(*local_domain, npart_to_send_frac, seed_ind, seed_tag); - // Sort old - Kokkos::fence(); - auto start_old = std::chrono::high_resolution_clock::now(); - metadomain.CommunicateParticles(*local_domain, &timers); - auto stop_old = std::chrono::high_resolution_clock::now(); - auto duration_old = std::chrono::duration_cast(stop_old - start_old).count(); - total_time_elapsed_old += duration_old; - Kokkos::fence(); + { + // Push + seed_ind += 2; + seed_tag += 3; + PushParticles(*local_domain, npart_to_send_frac, seed_ind, seed_tag); + // Sort new + Kokkos::fence(); + auto start_new = std::chrono::high_resolution_clock::now(); + metadomain.CommunicateParticlesBuffer(*local_domain, &timers); + auto stop_new = std::chrono::high_resolution_clock::now(); + auto duration_new = std::chrono::duration_cast( + stop_new - start_new) + .count(); + total_time_elapsed_new += duration_new; + Kokkos::fence(); + } + { + // Push + seed_ind += 2; + seed_tag += 3; + PushParticles(*local_domain, npart_to_send_frac, seed_ind, seed_tag); + // Sort old + Kokkos::fence(); + auto start_old = std::chrono::high_resolution_clock::now(); + metadomain.CommunicateParticles(*local_domain, &timers); + auto stop_old = std::chrono::high_resolution_clock::now(); + auto duration_old = std::chrono::duration_cast( + stop_old - start_old) + .count(); + total_time_elapsed_old += duration_old; + Kokkos::fence(); + } } - std::cout << "Total time elapsed for old: " << total_time_elapsed_old << " microseconds" << std::endl; - std::cout << "Total time elapsed for new: " << total_time_elapsed_new << " microseconds" << std::endl; + std::cout << "Total time elapsed for old: " << total_time_elapsed_old + << " microseconds" << std::endl; + std::cout << "Total time elapsed for new: " << total_time_elapsed_new + << " microseconds" << std::endl; return 0; } @@ -172,4 +200,4 @@ auto main(int argc, char* argv[]) -> int { other tags to alive CommunicateParticlesBuffer() only keeps the ParticleTag::Alive particles and discounts the rest -*/ \ No newline at end of file +*/ diff --git a/extern/Kokkos b/extern/Kokkos index 5fc08a9a7..b6a16bc9d 160000 --- a/extern/Kokkos +++ b/extern/Kokkos @@ -1 +1 @@ -Subproject commit 5fc08a9a7da14d8530f8c7035d008ef63ddb4e5c +Subproject commit b6a16bc9d88a9252d76e64fd2be20c58eb5d7f2e diff --git a/extern/adios2 b/extern/adios2 index a6e8314cc..25ccd6aaa 160000 --- a/extern/adios2 +++ b/extern/adios2 @@ -1 +1 @@ -Subproject commit a6e8314cc3c0b28d496b44dcd4f15685013b887b +Subproject commit 25ccd6aaa810bbc217b43421f9c43140082c65b9 diff --git a/extern/plog b/extern/plog index 85a871b13..96637a6e5 160000 --- a/extern/plog +++ b/extern/plog @@ -1 +1 @@ -Subproject commit 85a871b13be0bd1a9e0110744fa60cc9bd1e8380 +Subproject commit 96637a6e5e53f54e4e56d667d312c564d979ec0e diff --git a/src/framework/domain/comm_mpi.hpp b/src/framework/domain/comm_mpi.hpp index 2251968c4..9b2ad0a33 100644 --- a/src/framework/domain/comm_mpi.hpp +++ b/src/framework/domain/comm_mpi.hpp @@ -47,14 +47,12 @@ namespace comm { int rank; MPI_Comm_rank(MPI_COMM_WORLD, &rank); - raise::ErrorIf( (send_rank == rank && send_idx != idx) || (recv_rank == rank && recv_idx != idx), "Multiple-domain single-rank communication not yet implemented", HERE); - if ((send_idx == idx) and (recv_idx == idx)) { // trivial copy if sending to self and receiving from self @@ -332,10 +330,11 @@ namespace comm { MPI_COMM_WORLD, MPI_STATUS_IGNORE); } - Kokkos::deep_copy(arr, array_h); + if ((recv_rank >= 0) and (recv_count > 0)) { + Kokkos::deep_copy(arr, array_h); + } } - void ParticleSendRecvCount(int send_rank, int recv_rank, const std::size_t& send_count, @@ -459,154 +458,256 @@ namespace comm { return recv_count; } - template - void CommunicateParticleQuantityBuffer( array_t& arr, - int send_rank, - int recv_rank, - const range_tuple_t& send_slice, - const range_tuple_t& recv_slice, - Kokkos::View indices_to_send, - Kokkos::View indices_to_allocate) { - - array_t buffer( "buffer", indices_to_send.extent(0) + - indices_to_allocate.extent(0)); + void CommunicateParticleQuantityBuffer(array_t& arr, + int send_rank, + int recv_rank, + const range_tuple_t& send_slice, + const range_tuple_t& recv_slice, + Kokkos::View indices_to_send, + Kokkos::View indices_to_allocate) { + + array_t buffer("buffer", + indices_to_send.extent(0) + indices_to_allocate.extent(0)); // Populate the buffer for particle array Kokkos::parallel_for( - "PopulateBuffer", - indices_to_send.extent(0), - Lambda(const size_t i) { - buffer(i) = arr(indices_to_send(i)); - }); + "PopulateBuffer", + indices_to_send.extent(0), + Lambda(const size_t i) { buffer(i) = arr(indices_to_send(i)); }); CommunicateParticleQuantity(buffer, send_rank, recv_rank, send_slice, recv_slice); // Populate from buffer to the particle array Kokkos::parallel_for( - "PopulateFromBuffer", - indices_to_allocate.extent(0), - Lambda(const size_t i) { - arr(indices_to_allocate(i)) = buffer(indices_to_send.extent(0) + i); - }); - return; + "PopulateFromBuffer", + indices_to_allocate.extent(0), + Lambda(const size_t i) { + arr(indices_to_allocate(i)) = buffer(indices_to_send.extent(0) + i); + }); + return; } template - void CommunicateParticlesBuffer(Particles& species, - Kokkos::View indices_to_send, - Kokkos::View indices_to_allocate, - int send_rank, - int recv_rank, - std::vector shifts_in_x){ + void CommunicateParticlesBuffer(Particles& species, + Kokkos::View indices_to_send, + Kokkos::View indices_to_allocate, + int send_rank, + int recv_rank, + std::vector shifts_in_x) { if ((send_rank < 0) && (recv_rank < 0)) { raise::Error("No send or recv in SendRecvParticlesBuffered", HERE); } // First set the tags of the sent particles to be dead - auto& this_tag = species.tag; - //Kokkos::parallel_for( + auto& this_tag = species.tag; + // Kokkos::parallel_for( //"SetTagDead", - //Kokkos::RangePolicy(0, indices_to_allocate.size()), - //KOKKOS_LAMBDA(const size_t i) { - // const auto idx = indices_to_send(i); - // this_tag(idx) = static_cast(ParticleTag::dead); - //}); - + // Kokkos::RangePolicy(0, indices_to_allocate.size()), + // KOKKOS_LAMBDA(const size_t i) { + // const auto idx = indices_to_send(i); + // this_tag(idx) = static_cast(ParticleTag::dead); + // }); + // Construct send and receive slice for the buffer auto send_slice = range_tuple_t({ 0, indices_to_send.size() }); - auto recv_slice = range_tuple_t({ indices_to_send.size(), indices_to_send.size() + - indices_to_allocate.size() }); + auto recv_slice = range_tuple_t( + { indices_to_send.size(), + indices_to_send.size() + indices_to_allocate.size() }); // Send and receive the particles - CommunicateParticleQuantityBuffer(species.i1, send_rank, recv_rank, send_slice, recv_slice, indices_to_send, indices_to_allocate); - CommunicateParticleQuantityBuffer(species.dx1, send_rank, recv_rank, send_slice, recv_slice, indices_to_send, indices_to_allocate); - CommunicateParticleQuantityBuffer(species.i1_prev, send_rank, recv_rank, send_slice, recv_slice, indices_to_send, indices_to_allocate); - CommunicateParticleQuantityBuffer(species.dx1_prev, send_rank, recv_rank, send_slice, recv_slice, indices_to_send, indices_to_allocate); + CommunicateParticleQuantityBuffer(species.i1, + send_rank, + recv_rank, + send_slice, + recv_slice, + indices_to_send, + indices_to_allocate); + CommunicateParticleQuantityBuffer(species.dx1, + send_rank, + recv_rank, + send_slice, + recv_slice, + indices_to_send, + indices_to_allocate); + CommunicateParticleQuantityBuffer(species.i1_prev, + send_rank, + recv_rank, + send_slice, + recv_slice, + indices_to_send, + indices_to_allocate); + CommunicateParticleQuantityBuffer(species.dx1_prev, + send_rank, + recv_rank, + send_slice, + recv_slice, + indices_to_send, + indices_to_allocate); if constexpr (D == Dim::_2D || D == Dim::_3D) { - CommunicateParticleQuantityBuffer(species.i2, send_rank, recv_rank, send_slice, recv_slice, indices_to_send, indices_to_allocate); - CommunicateParticleQuantityBuffer(species.dx2, send_rank, recv_rank, send_slice, recv_slice, indices_to_send, indices_to_allocate); - CommunicateParticleQuantityBuffer(species.i2_prev, send_rank, recv_rank, send_slice, recv_slice, indices_to_send, indices_to_allocate); - CommunicateParticleQuantityBuffer(species.dx2_prev, send_rank, recv_rank, send_slice, recv_slice, indices_to_send, indices_to_allocate); + CommunicateParticleQuantityBuffer(species.i2, + send_rank, + recv_rank, + send_slice, + recv_slice, + indices_to_send, + indices_to_allocate); + CommunicateParticleQuantityBuffer(species.dx2, + send_rank, + recv_rank, + send_slice, + recv_slice, + indices_to_send, + indices_to_allocate); + CommunicateParticleQuantityBuffer(species.i2_prev, + send_rank, + recv_rank, + send_slice, + recv_slice, + indices_to_send, + indices_to_allocate); + CommunicateParticleQuantityBuffer(species.dx2_prev, + send_rank, + recv_rank, + send_slice, + recv_slice, + indices_to_send, + indices_to_allocate); } if constexpr (D == Dim::_3D) { - CommunicateParticleQuantityBuffer(species.i3, send_rank, recv_rank, send_slice, recv_slice, indices_to_send, indices_to_allocate); - CommunicateParticleQuantityBuffer(species.dx3, send_rank, recv_rank, send_slice, recv_slice, indices_to_send, indices_to_allocate); - CommunicateParticleQuantityBuffer(species.i3_prev, send_rank, recv_rank, send_slice, recv_slice, indices_to_send, indices_to_allocate); - CommunicateParticleQuantityBuffer(species.dx3_prev, send_rank, recv_rank, send_slice, recv_slice, indices_to_send, indices_to_allocate); + CommunicateParticleQuantityBuffer(species.i3, + send_rank, + recv_rank, + send_slice, + recv_slice, + indices_to_send, + indices_to_allocate); + CommunicateParticleQuantityBuffer(species.dx3, + send_rank, + recv_rank, + send_slice, + recv_slice, + indices_to_send, + indices_to_allocate); + CommunicateParticleQuantityBuffer(species.i3_prev, + send_rank, + recv_rank, + send_slice, + recv_slice, + indices_to_send, + indices_to_allocate); + CommunicateParticleQuantityBuffer(species.dx3_prev, + send_rank, + recv_rank, + send_slice, + recv_slice, + indices_to_send, + indices_to_allocate); } - CommunicateParticleQuantityBuffer(species.ux1, send_rank, recv_rank, send_slice, recv_slice, indices_to_send, indices_to_allocate); - CommunicateParticleQuantityBuffer(species.ux2, send_rank, recv_rank, send_slice, recv_slice, indices_to_send, indices_to_allocate); - CommunicateParticleQuantityBuffer(species.ux3, send_rank, recv_rank, send_slice, recv_slice, indices_to_send, indices_to_allocate); - CommunicateParticleQuantityBuffer(species.weight, send_rank, recv_rank, send_slice, recv_slice, indices_to_send, indices_to_allocate); + CommunicateParticleQuantityBuffer(species.ux1, + send_rank, + recv_rank, + send_slice, + recv_slice, + indices_to_send, + indices_to_allocate); + CommunicateParticleQuantityBuffer(species.ux2, + send_rank, + recv_rank, + send_slice, + recv_slice, + indices_to_send, + indices_to_allocate); + CommunicateParticleQuantityBuffer(species.ux3, + send_rank, + recv_rank, + send_slice, + recv_slice, + indices_to_send, + indices_to_allocate); + CommunicateParticleQuantityBuffer(species.weight, + send_rank, + recv_rank, + send_slice, + recv_slice, + indices_to_send, + indices_to_allocate); if constexpr (D == Dim::_2D and C != Coord::Cart) { - CommunicateParticleQuantityBuffer(species.phi, send_rank, recv_rank, send_slice, recv_slice, indices_to_send, indices_to_allocate); + CommunicateParticleQuantityBuffer(species.phi, + send_rank, + recv_rank, + send_slice, + recv_slice, + indices_to_send, + indices_to_allocate); } for (auto p { 0 }; p < species.npld(); ++p) { - CommunicateParticleQuantityBuffer(species.pld[p], send_rank, recv_rank, send_slice, recv_slice, indices_to_send, indices_to_allocate); + CommunicateParticleQuantityBuffer(species.pld[p], + send_rank, + recv_rank, + send_slice, + recv_slice, + indices_to_send, + indices_to_allocate); } // Set the tag for the received particles to be alive and perform the necessary displacements - if constexpr (D == Dim::_1D) - { - const auto shift_in_x1 = shifts_in_x[0]; - auto& this_i1 = species.i1; - auto& this_i1_prev = species.i1_prev; + if constexpr (D == Dim::_1D) { + const auto shift_in_x1 = shifts_in_x[0]; + auto& this_i1 = species.i1; + auto& this_i1_prev = species.i1_prev; Kokkos::parallel_for( - "SetTagAlive", - Kokkos::RangePolicy(0, indices_to_allocate.size()), - KOKKOS_LAMBDA(const size_t i) { - const auto idx = indices_to_allocate(i); - this_tag(idx) = static_cast(ParticleTag::alive); - this_i1(idx) += shift_in_x1; - this_i1_prev(idx) += shift_in_x1; - }); + "SetTagAlive", + Kokkos::RangePolicy(0, indices_to_allocate.size()), + KOKKOS_LAMBDA(const size_t i) { + const auto idx = indices_to_allocate(i); + this_tag(idx) = static_cast(ParticleTag::alive); + this_i1(idx) += shift_in_x1; + this_i1_prev(idx) += shift_in_x1; + }); } - else if constexpr (D == Dim::_2D) - { - const auto shift_in_x1 = shifts_in_x[0]; - const auto shift_in_x2 = shifts_in_x[1]; - auto& this_i1 = species.i1; - auto& this_i2 = species.i2; - auto& this_i1_prev = species.i1_prev; - auto& this_i2_prev = species.i2_prev; + else if constexpr (D == Dim::_2D) { + const auto shift_in_x1 = shifts_in_x[0]; + const auto shift_in_x2 = shifts_in_x[1]; + auto& this_i1 = species.i1; + auto& this_i2 = species.i2; + auto& this_i1_prev = species.i1_prev; + auto& this_i2_prev = species.i2_prev; Kokkos::parallel_for( - "SetTagAlive", - Kokkos::RangePolicy(0, indices_to_allocate.size()), - KOKKOS_LAMBDA(const size_t i) { - const auto idx = indices_to_allocate(i); - this_tag(idx) = static_cast(ParticleTag::alive); - this_i1(idx) += shift_in_x1; - this_i2(idx) += shift_in_x2; - this_i1_prev(idx) += shift_in_x1; - this_i2_prev(idx) += shift_in_x2; - }); + "SetTagAlive", + Kokkos::RangePolicy(0, indices_to_allocate.size()), + KOKKOS_LAMBDA(const size_t i) { + const auto idx = indices_to_allocate(i); + this_tag(idx) = static_cast(ParticleTag::alive); + this_i1(idx) += shift_in_x1; + this_i2(idx) += shift_in_x2; + this_i1_prev(idx) += shift_in_x1; + this_i2_prev(idx) += shift_in_x2; + }); } - else if constexpr (D == Dim::_3D) - { - const auto shift_in_x1 = shifts_in_x[0]; - const auto shift_in_x2 = shifts_in_x[1]; - const auto shift_in_x3 = shifts_in_x[2]; - auto& this_i1 = species.i1; - auto& this_i2 = species.i2; - auto& this_i3 = species.i3; - auto& this_i1_prev = species.i1_prev; - auto& this_i2_prev = species.i2_prev; - auto& this_i3_prev = species.i3_prev; + else if constexpr (D == Dim::_3D) { + const auto shift_in_x1 = shifts_in_x[0]; + const auto shift_in_x2 = shifts_in_x[1]; + const auto shift_in_x3 = shifts_in_x[2]; + auto& this_i1 = species.i1; + auto& this_i2 = species.i2; + auto& this_i3 = species.i3; + auto& this_i1_prev = species.i1_prev; + auto& this_i2_prev = species.i2_prev; + auto& this_i3_prev = species.i3_prev; Kokkos::parallel_for( - "SetTagAlive", - Kokkos::RangePolicy(0, indices_to_allocate.size()), - KOKKOS_LAMBDA(const size_t i) { - const auto idx = indices_to_allocate(i); - this_tag(idx) = static_cast(ParticleTag::alive); - this_i1(idx) += shift_in_x1; - this_i2(idx) += shift_in_x2; - this_i3(idx) += shift_in_x3; - this_i1_prev(idx) += shift_in_x1; - this_i2_prev(idx) += shift_in_x2; - this_i3_prev(idx) += shift_in_x3; - }); + "SetTagAlive", + Kokkos::RangePolicy(0, indices_to_allocate.size()), + KOKKOS_LAMBDA(const size_t i) { + const auto idx = indices_to_allocate(i); + this_tag(idx) = static_cast(ParticleTag::alive); + this_i1(idx) += shift_in_x1; + this_i2(idx) += shift_in_x2; + this_i3(idx) += shift_in_x3; + this_i1_prev(idx) += shift_in_x1; + this_i2_prev(idx) += shift_in_x2; + this_i3_prev(idx) += shift_in_x3; + }); } Kokkos::fence(); return; - } - + } } // namespace comm diff --git a/src/framework/domain/communications.cpp b/src/framework/domain/communications.cpp index a43b635b7..5e5da4a0c 100644 --- a/src/framework/domain/communications.cpp +++ b/src/framework/domain/communications.cpp @@ -86,8 +86,8 @@ namespace ntt { } else { // no communication necessary return { - {0, -1}, - {0, -1} + { 0, -1 }, + { 0, -1 } }; } #if defined(MPI_ENABLED) @@ -110,8 +110,8 @@ namespace ntt { (void)send_rank; (void)recv_rank; return { - {send_ind, send_rank}, - {recv_ind, recv_rank} + { send_ind, send_rank }, + { recv_ind, recv_rank } }; } @@ -129,8 +129,8 @@ namespace ntt { const auto is_receiving = (recv_rank >= 0); if (not(is_sending or is_receiving)) { return { - {{ 0, -1 }, {}}, - {{ 0, -1 }, {}} + { { 0, -1 }, {} }, + { { 0, -1 }, {} } }; } auto send_slice = std::vector {}; @@ -196,8 +196,8 @@ namespace ntt { } return { - {{ send_ind, send_rank }, send_slice}, - {{ recv_ind, recv_rank }, recv_slice}, + { { send_ind, send_rank }, send_slice }, + { { recv_ind, recv_rank }, recv_slice }, }; } @@ -645,26 +645,27 @@ namespace ntt { } } - -/* - New function to communicate particles using a buffer -*/ -template + /* + New function to communicate particles using a buffer + */ + template void Metadomain::CommunicateParticlesBuffer(Domain& domain, - timer::Timers* timers) { + timer::Timers* timers) { raise::ErrorIf(timers == nullptr, "Timers not passed when Comm::Prtl called", HERE); logger::Checkpoint("Communicating particles\n", HERE); for (auto& species : domain.species) { - auto npart_per_tag_arr = species.npart_per_tag(); - auto npart = static_cast(species.npart()); - auto total_alive = static_cast(npart_per_tag_arr[ParticleTag::alive]); - auto total_dead = static_cast(npart_per_tag_arr[ParticleTag::dead]); - auto total_holes = static_cast(npart - total_alive); - auto total_send = static_cast(npart - total_alive - total_dead); - auto total_recv = static_cast(0); - auto tag_count = static_cast(npart_per_tag_arr.size()); + auto npart_per_tag_arr = species.npart_per_tag(); + auto npart = static_cast(species.npart()); + auto total_alive = static_cast( + npart_per_tag_arr[ParticleTag::alive]); + auto total_dead = static_cast( + npart_per_tag_arr[ParticleTag::dead]); + auto total_holes = static_cast(npart - total_alive); + auto total_send = static_cast(npart - total_alive - total_dead); + auto total_recv = static_cast(0); + auto tag_count = static_cast(npart_per_tag_arr.size()); std::vector send_ranks, send_inds; std::vector recv_ranks, recv_inds; @@ -676,9 +677,9 @@ template // array that holds the number of particles to be received per tag std::vector npart_per_tag_arr_recv(tag_count, 0); - for (auto& direction : dir::Directions::all) { + for (auto& direction : dir::Directions::all) { const auto [send_params, - recv_params] = GetSendRecvParams(this, domain, direction, true); + recv_params] = GetSendRecvParams(this, domain, direction, true); const auto [send_indrank, send_slice] = send_params; const auto [recv_indrank, recv_slice] = recv_params; const auto [send_ind, send_rank] = send_indrank; @@ -686,78 +687,76 @@ template if (send_rank < 0 and recv_rank < 0) { continue; } - const auto send_dir_tag = mpi::PrtlSendTag::dir2tag(direction); - const auto nsend = npart_per_tag_arr[send_dir_tag]; - std::size_t nrecv = 0; + const auto send_dir_tag = mpi::PrtlSendTag::dir2tag(direction); + const auto nsend = npart_per_tag_arr[send_dir_tag]; + std::size_t nrecv = 0; // Get the receive count send_ranks.push_back(send_rank); recv_ranks.push_back(recv_rank); send_inds.push_back(send_ind); recv_inds.push_back(recv_ind); - comm::ParticleSendRecvCount(send_rank, - recv_rank, - nsend, - nrecv); - total_recv += nrecv; + comm::ParticleSendRecvCount(send_rank, recv_rank, nsend, nrecv); + total_recv += nrecv; npart_per_tag_arr_recv[mpi::PrtlSendTag::dir2tag(-direction)] = nrecv; } raise::FatalIf((npart + total_recv) >= species.maxnpart(), - "Too many particles to receive (cannot fit into maxptl)", - HERE); + "Too many particles to receive (cannot fit into maxptl)", + HERE); // Now we know the number of particles to be sent and received per direction /* permute vector contains the indices of the tags to send and receive in the order of the directions E.g., consider the following tag array [ 0, 0, 3, 0, 1,...] Then, permute vector will look something like - [0, 1, 3, ..., 2, ..., 4, ... ] - |<--------- >| |<----->| |<----->| .... - tag=0 ct tag=1 ct tag=3 ct - (dead) (alive) (tag1) ... + [0, 1, 3, ..., 4, ..., ... 2, ... ] + |<--------- >| |<----->| |<----->| .... + tag=0 ct tag=1 ct tag=3 ct + (dead) (alive) (tag1) ... */ - auto& this_tag = species.tag; - auto& this_tag_offset = species.tag_offset; + auto& this_tag = species.tag; + auto& this_tag_offset = species.tag_offset; Kokkos::View permute_vector("permute_vector", species.npart()); Kokkos::View current_offset("current_offset", species.ntags()); + // @TODO: do not save tag = 1 particles into permute_vector + // instead of species.npart(), size will be species.npart() - npart_per_tag[ParticleTag::alive]; Kokkos::parallel_for( "PermuteVector", species.npart(), - Lambda(const std::size_t p) { - auto current_tag = this_tag(p); - auto i_current_tag_offset = Kokkos::atomic_fetch_add(¤t_offset(current_tag), 1); - auto idx_permute_vec = this_tag_offset(current_tag) + i_current_tag_offset; - permute_vector(idx_permute_vec) = static_cast(p); + Lambda(index_t p) { + const auto current_tag = this_tag(p); + const auto idx_permute_vec = this_tag_offset(current_tag) + + Kokkos::atomic_fetch_add( + ¤t_offset(current_tag), + 1); + permute_vector(idx_permute_vec) = p; }); - // Check: add the end of the loop, current_offset should be equal to npart_per_tag - auto current_offset_h = Kokkos::create_mirror_view(current_offset); - Kokkos::deep_copy(current_offset_h, current_offset); - for (std::size_t i { 0 }; i < current_offset_h.size(); ++i) { - raise::FatalIf(current_offset_h(i) != npart_per_tag_arr[i], - "Error in permute vector construction", - HERE); - } + // Check: add the end of the loop, current_offset should be equal to npart_per_tag + auto current_offset_h = Kokkos::create_mirror_view(current_offset); + Kokkos::deep_copy(current_offset_h, current_offset); + for (std::size_t i { 0 }; i < current_offset_h.size(); ++i) { + raise::FatalIf(current_offset_h(i) != npart_per_tag_arr[i], + "Error in permute vector construction", + HERE); + } // allocation_vector(p) assigns the pth received particle // to the pth hole in the array, or after npart() if p > sent+dead count. Kokkos::View allocation_vector("allocation_vector", total_recv); - // TWO BUGS: when nsend = nrecv, an extra dead particle is created out of nowhere - // when nrecv > nsend but < nrecv < nsend + ndead, tags of alive particles are not changed - Kokkos::parallel_for( "AllocationVector", total_recv, - Lambda(const std::size_t p) { - // Case: recevied particle count less than dead particle count -> replace dead particles - if (p < total_dead){ + Lambda(index_t p) { + // Case: received particle count less than dead particle count -> replace dead particles + if (p < total_dead) { allocation_vector(p) = permute_vector(p); } // Case: received particle count > dead particle count but < sent particle count -> replace // sent particles - else if (p < total_holes && p >= total_dead){ + else if (p < total_holes && p >= total_dead) { allocation_vector(p) = permute_vector(total_alive + p); } // Case: received particle count exceeds sent + dead particles -> append at the end @@ -767,52 +766,20 @@ template }); Kokkos::fence(); - // Compute where the received particles are allocated - if (mpi_rank == 0){ - Kokkos::View particles_allocated_per_tag("particles allocated per tag", tag_count); - Kokkos::parallel_for( - "ParticlesAllocatedPerTag", - total_recv, - Lambda(const std::size_t i) { - auto index = allocation_vector(i); - auto tag = this_tag(index); - Kokkos::atomic_fetch_add(&particles_allocated_per_tag(tag), 1); - }); - Kokkos::fence(); - auto particles_allocated_per_tag_h = Kokkos::create_mirror_view(particles_allocated_per_tag); - Kokkos::deep_copy(particles_allocated_per_tag_h, particles_allocated_per_tag); - - std::cout << "Particles allocated per tag (pre recv): "; - for (std::size_t i = 0; i < tag_count; i++){ - std::cout << "[" << particles_allocated_per_tag_h[i] << "] "; - } - std::cout << std::endl; - } - - - // Check if the particle tags are only dead or alive - //if (mpi_rank == 0){ - // std::cout << "Before COMM: " << std::endl; - // std::cout << "Tag counts: "; - // for (std::size_t i = 0; i < tag_count; i++){ - // std::cout << "[" << npart_per_tag_arr[i] << "] "; - // } - // std::cout << std::endl; - //} std::size_t count_recv = 0; std::size_t iteration = 0; // Main loop over all direction where we send the data for (auto& direction : dir::Directions::all) { // When nowhere to send and receive - auto send_rank = send_ranks[iteration]; - auto recv_rank = recv_ranks[iteration]; + auto send_rank = send_ranks[iteration]; + auto recv_rank = recv_ranks[iteration]; if (send_rank < 0 and recv_rank < 0) { continue; } // Get the coordinate shifts in xi std::vector shifts_in_x; - auto recv_ind = recv_inds[iteration]; + auto recv_ind = recv_inds[iteration]; if constexpr (D == Dim::_1D) { int shift_in_x1 { 0 }; if ((-direction)[0] == -1) { @@ -821,8 +788,7 @@ template shift_in_x1 = domain.mesh.n_active(in::x1); } shifts_in_x.push_back(shift_in_x1); - } - else if constexpr (D == Dim::_2D) { + } else if constexpr (D == Dim::_2D) { int shift_in_x1 { 0 }, shift_in_x2 { 0 }; if ((-direction)[0] == -1) { shift_in_x1 = -subdomain(recv_ind).mesh.n_active(in::x1); @@ -836,8 +802,7 @@ template } shifts_in_x.push_back(shift_in_x1); shifts_in_x.push_back(shift_in_x2); - } - else if constexpr (D == Dim::_3D) { + } else if constexpr (D == Dim::_3D) { int shift_in_x1 { 0 }, shift_in_x2 { 0 }, shift_in_x3 { 0 }; if ((-direction)[0] == -1) { shift_in_x1 = -subdomain(recv_ind).mesh.n_active(in::x1); @@ -860,32 +825,39 @@ template } // Tuple that contains the start and end indices of permtute_vec pointing to a given tag type = dir2tag(dir) - auto range_permute = std::make_pair(static_cast(species.tag_offset_h[mpi::PrtlSendTag::dir2tag(direction)]), - static_cast(species.tag_offset_h[mpi::PrtlSendTag::dir2tag(direction)] + - npart_per_tag_arr[mpi::PrtlSendTag::dir2tag(direction)])); + auto range_permute = std::make_pair( + static_cast( + species.tag_offset_h[mpi::PrtlSendTag::dir2tag(direction)]), + static_cast( + species.tag_offset_h[mpi::PrtlSendTag::dir2tag(direction)] + + npart_per_tag_arr[mpi::PrtlSendTag::dir2tag(direction)])); // Tuple that contains the start and end indices for allocation_vector pointing to a given tag type = dir2tag(dir) - auto range_allocate = std::make_pair(static_cast(count_recv), - static_cast(count_recv + - npart_per_tag_arr_recv[mpi::PrtlSendTag::dir2tag(-direction)])); + auto range_allocate = std::make_pair( + static_cast(count_recv), + static_cast( + count_recv + + npart_per_tag_arr_recv[mpi::PrtlSendTag::dir2tag(-direction)])); + // @TODO: check subview index // contains the indices of all particles of a given tag = mpi::PrtlSendTag::dir2tag(direction) - auto indices_to_send = Kokkos::subview(permute_vector, range_permute); + auto indices_to_send = Kokkos::subview(permute_vector, range_permute); // contains the indices of the holes where the received particles will be placed - auto indices_to_allocate = Kokkos::subview(allocation_vector, range_allocate); + auto indices_to_allocate = Kokkos::subview(allocation_vector, + range_allocate); // Main function that sends the particles and receives the arrays - comm::CommunicateParticlesBuffer( species, - indices_to_send, - indices_to_allocate, - send_rank, - recv_rank, - shifts_in_x); + comm::CommunicateParticlesBuffer(species, + indices_to_send, + indices_to_allocate, + send_rank, + recv_rank, + shifts_in_x); count_recv += npart_per_tag_arr_recv[mpi::PrtlSendTag::dir2tag(-direction)]; iteration++; } // Compute where the received particles are allocated - //if (mpi_rank == 0){ - //Kokkos::View particles_allocated_per_tag("particles allocated per tag", tag_count); - //Kokkos::parallel_for( + // if (mpi_rank == 0){ + // Kokkos::View particles_allocated_per_tag("particles + // allocated per tag", tag_count); Kokkos::parallel_for( // "ParticlesAllocatedPerTag", // total_recv, // Lambda(const std::size_t i) { @@ -893,79 +865,77 @@ template // auto tag = this_tag(index); // Kokkos::atomic_fetch_add(&particles_allocated_per_tag(tag), 1); // }); - //Kokkos::fence(); - //auto particles_allocated_per_tag_h = Kokkos::create_mirror_view(particles_allocated_per_tag); - //Kokkos::deep_copy(particles_allocated_per_tag_h, particles_allocated_per_tag); - - //std::cout << "Particles allocated per tag (post recv): "; - //for (std::size_t i = 0; i < tag_count; i++){ - // std::cout << "[" << particles_allocated_per_tag_h[i] << "] "; - //} - //std::cout << std::endl; + // Kokkos::fence(); + // auto particles_allocated_per_tag_h = + // Kokkos::create_mirror_view(particles_allocated_per_tag); + // Kokkos::deep_copy(particles_allocated_per_tag_h, + // particles_allocated_per_tag); + + // std::cout << "Particles allocated per tag (post recv): "; + // for (std::size_t i = 0; i < tag_count; i++){ + // std::cout << "[" << particles_allocated_per_tag_h[i] << "] "; // } - // If receive count is less than send count then make the tags of sent dead - if (total_recv <= total_holes){ - if (total_recv <= total_dead){ - // Case: all sent particles' tags are set to dead - /* (received) - [ | <------------------> | <-------->] - (dead) (alive) (sent) - || - (to be made dead) - ^ - (offset) - */ - - auto offset = total_alive + total_dead; + // std::cout << std::endl; + // } + // If receive count is less than send count then make the tags of sent dead + if (total_recv <= total_holes) { + if (total_recv <= total_dead) { + // Case: all sent particles' tags are set to dead + /* (received) + [ | <------------------> | <-------->] + (dead) (alive) (sent) + || + (to be made dead) + ^ + (offset) + */ + + auto offset = total_alive + total_dead; Kokkos::parallel_for( - "CommunicateParticles", - total_send, - Lambda(index_t p) { - this_tag(permute_vector(offset + p)) = ParticleTag::dead; - }); - } - else{ - // Case: tags of sent particles that are not replaced by recevied particles are made dead - /* (received) (received) - [ | <------------------> |] - (dead) (alive) (sent) - || - (to be made dead) - ^ - (offset) - */ - auto offset = total_alive + total_recv; + "CommunicateParticles", + total_send, + Lambda(index_t p) { + this_tag(permute_vector(offset + p)) = ParticleTag::dead; + }); + } else { + // Case: tags of sent particles that are not replaced by recevied particles are made dead + /* (received) (received) + [ | <------------------> |] + (dead) (alive) (sent) + || + (to be made dead) + ^ + (offset) + */ + auto offset = total_alive + total_recv; Kokkos::parallel_for( - "CommunicateParticles", - total_send - (total_recv - total_dead), - Lambda(index_t p) { - this_tag(permute_vector(offset + p)) = ParticleTag::dead; - }); + "CommunicateParticles", + total_send - (total_recv - total_dead), + Lambda(index_t p) { + this_tag(permute_vector(offset + p)) = ParticleTag::dead; + }); } } - // Check if the particle tags are only dead or alive species.set_npart(npart + std::max(total_send, total_recv) - total_send); npart_per_tag_arr = species.npart_per_tag(); - //if (mpi_rank == 0) + // if (mpi_rank == 0) //{ - // std::cout << "After COMM: " << std::endl; - // std::cout << "Tag counts: "; - // for (std::size_t i = 0; i < tag_count; i++){ - // std::cout << "[" << npart_per_tag_arr[i] << "] "; - // } - // std::cout << std::endl; - // std::cout << "Holes filled: " << total_holes << " Total recv: " << total_recv << - // "Total send: " << total_send << std::endl; - // std::cout << std::endl << "*************"<< std::endl; - //} - #endif + // std::cout << "After COMM: " << std::endl; + // std::cout << "Tag counts: "; + // for (std::size_t i = 0; i < tag_count; i++){ + // std::cout << "[" << npart_per_tag_arr[i] << "] "; + // } + // std::cout << std::endl; + // std::cout << "Holes filled: " << total_holes << " Total recv: " << total_recv << + // "Total send: " << total_send << std::endl; + // std::cout << std::endl << "*************"<< std::endl; + // } +#endif } } - - template struct Metadomain>; template struct Metadomain>; template struct Metadomain>; From c0d465205889775c30843d7368bd1f5c28a31f25 Mon Sep 17 00:00:00 2001 From: hayk Date: Mon, 16 Dec 2024 18:29:21 -0500 Subject: [PATCH 186/773] tested prtlsort (WIP) --- benchmark/benchmark.cpp | 186 ++++++++++++------------ extern/Kokkos | 2 +- extern/adios2 | 2 +- extern/plog | 2 +- src/framework/containers/particles.h | 1 - src/framework/domain/comm_mpi.hpp | 18 +-- src/framework/domain/communications.cpp | 17 ++- src/framework/domain/metadomain.cpp | 3 + 8 files changed, 120 insertions(+), 111 deletions(-) diff --git a/benchmark/benchmark.cpp b/benchmark/benchmark.cpp index 797c8ed87..593b7f190 100644 --- a/benchmark/benchmark.cpp +++ b/benchmark/benchmark.cpp @@ -35,6 +35,7 @@ - Communicate particles to neighbors and time the communication - Compute the time taken for best of N iterations for the communication */ +using namespace ntt; // Set npart and set the particle tags to alive template @@ -94,101 +95,106 @@ void PushParticles(Domain& domain, } auto main(int argc, char* argv[]) -> int { - std::cout << "Constructing the domain" << std::endl; - ntt::GlobalInitialize(argc, argv); - // Create a Metadomain object - const unsigned int ndomains = 1; - const std::vector global_decomposition = { - { -1, -1, -1 } - }; - const std::vector global_ncells = { 32, 32, 32 }; - const boundaries_t global_extent = { - { 0.0, 3.0 }, - { 0.0, 3.0 }, - { 0.0, 3.0 } - }; - const boundaries_t global_flds_bc = { - { FldsBC::PERIODIC, FldsBC::PERIODIC }, - { FldsBC::PERIODIC, FldsBC::PERIODIC }, - { FldsBC::PERIODIC, FldsBC::PERIODIC } - }; - const boundaries_t global_prtl_bc = { - { PrtlBC::PERIODIC, PrtlBC::PERIODIC }, - { PrtlBC::PERIODIC, PrtlBC::PERIODIC }, - { PrtlBC::PERIODIC, PrtlBC::PERIODIC } - }; - const std::map metric_params = {}; - const int maxnpart = argc > 1 ? std::stoi(argv[1]) : 1000; - const double npart_to_send_frac = 0.01; - const int npart = static_cast(maxnpart * (1 - 2 * npart_to_send_frac)); - auto species = ntt::ParticlesSpecies(1u, - "test_e", - 1.0f, - 1.0f, - maxnpart, - ntt::PrtlPusher::BORIS, - false, - ntt::Cooling::NONE); - auto metadomain = Metadomain>( - ndomains, - global_decomposition, - global_ncells, - global_extent, - global_flds_bc, - global_prtl_bc, - metric_params, - { species }); + GlobalInitialize(argc, argv); + { + std::cout << "Constructing the domain" << std::endl; + // Create a Metadomain object + const unsigned int ndomains = 2; + const std::vector global_decomposition = { + {-1, -1, -1} + }; + const std::vector global_ncells = { 32, 32, 32 }; + const boundaries_t global_extent = { + {0.0, 3.0}, + {0.0, 3.0}, + {0.0, 3.0} + }; + const boundaries_t global_flds_bc = { + {FldsBC::PERIODIC, FldsBC::PERIODIC}, + {FldsBC::PERIODIC, FldsBC::PERIODIC}, + {FldsBC::PERIODIC, FldsBC::PERIODIC} + }; + const boundaries_t global_prtl_bc = { + {PrtlBC::PERIODIC, PrtlBC::PERIODIC}, + {PrtlBC::PERIODIC, PrtlBC::PERIODIC}, + {PrtlBC::PERIODIC, PrtlBC::PERIODIC} + }; + const std::map metric_params = {}; + const int maxnpart = argc > 1 ? std::stoi(argv[1]) : 1000; + const double npart_to_send_frac = 0.01; + const int npart = static_cast(maxnpart * (1 - 2 * npart_to_send_frac)); + auto species = ntt::ParticleSpecies(1u, + "test_e", + 1.0f, + 1.0f, + maxnpart, + ntt::PrtlPusher::BORIS, + false, + ntt::Cooling::NONE); + auto metadomain = Metadomain>( + ndomains, + global_decomposition, + global_ncells, + global_extent, + global_flds_bc, + global_prtl_bc, + metric_params, + { species }); - const auto local_subdomain_idx = metadomain.l_subdomain_indices()[0]; - auto local_domain = metadomain.subdomain_ptr(local_subdomain_idx); - auto timers = timer::Timers { { "Communication" }, nullptr, false }; - InitializeParticleArrays(*local_domain, npart); - // Timers for both the communication routines - auto total_time_elapsed_old = 0; - auto total_time_elapsed_new = 0; + const auto local_subdomain_idx = metadomain.l_subdomain_indices()[0]; + auto local_domain = metadomain.subdomain_ptr(local_subdomain_idx); + auto timers = timer::Timers { { "Communication" }, nullptr, false }; + InitializeParticleArrays(*local_domain, npart); + // Timers for both the communication routines + auto total_time_elapsed_old = 0; + auto total_time_elapsed_new = 0; - int seed_ind = 0; - int seed_tag = 1; - Kokkos::fence(); + int seed_ind = 0; + int seed_tag = 1; + Kokkos::fence(); - for (int i = 0; i < 10; ++i) { - { - // Push - seed_ind += 2; - seed_tag += 3; - PushParticles(*local_domain, npart_to_send_frac, seed_ind, seed_tag); - // Sort new - Kokkos::fence(); - auto start_new = std::chrono::high_resolution_clock::now(); - metadomain.CommunicateParticlesBuffer(*local_domain, &timers); - auto stop_new = std::chrono::high_resolution_clock::now(); - auto duration_new = std::chrono::duration_cast( - stop_new - start_new) - .count(); - total_time_elapsed_new += duration_new; - Kokkos::fence(); - } - { - // Push - seed_ind += 2; - seed_tag += 3; - PushParticles(*local_domain, npart_to_send_frac, seed_ind, seed_tag); - // Sort old - Kokkos::fence(); - auto start_old = std::chrono::high_resolution_clock::now(); - metadomain.CommunicateParticles(*local_domain, &timers); - auto stop_old = std::chrono::high_resolution_clock::now(); - auto duration_old = std::chrono::duration_cast( - stop_old - start_old) - .count(); - total_time_elapsed_old += duration_old; - Kokkos::fence(); + for (int i = 0; i < 10; ++i) { + { + // Push + seed_ind += 2; + seed_tag += 3; + PushParticles(*local_domain, npart_to_send_frac, seed_ind, seed_tag); + // Sort new + Kokkos::fence(); + auto start_new = std::chrono::high_resolution_clock::now(); + metadomain.CommunicateParticlesBuffer(*local_domain, &timers); + auto stop_new = std::chrono::high_resolution_clock::now(); + auto duration_new = std::chrono::duration_cast( + stop_new - start_new) + .count(); + total_time_elapsed_new += duration_new; + Kokkos::fence(); + } + { + // Push + seed_ind += 2; + seed_tag += 3; + PushParticles(*local_domain, npart_to_send_frac, seed_ind, seed_tag); + // Sort old + Kokkos::fence(); + auto start_old = std::chrono::high_resolution_clock::now(); + metadomain.CommunicateParticles(*local_domain, &timers); + auto stop_old = std::chrono::high_resolution_clock::now(); + auto duration_old = std::chrono::duration_cast( + stop_old - start_old) + .count(); + total_time_elapsed_old += duration_old; + Kokkos::fence(); + } } + printf("Total time elapsed for old: %f us : %f us/prtl\n", + total_time_elapsed_old / 10.0, + total_time_elapsed_old / 10.0 * 1000 / npart); + printf("Total time elapsed for new: %f us : %f us/prtl\n", + total_time_elapsed_new / 10.0, + total_time_elapsed_new / 10.0 * 1000 / npart); } - std::cout << "Total time elapsed for old: " << total_time_elapsed_old - << " microseconds" << std::endl; - std::cout << "Total time elapsed for new: " << total_time_elapsed_new - << " microseconds" << std::endl; + GlobalFinalize(); return 0; } diff --git a/extern/Kokkos b/extern/Kokkos index b6a16bc9d..eb11070f6 160000 --- a/extern/Kokkos +++ b/extern/Kokkos @@ -1 +1 @@ -Subproject commit b6a16bc9d88a9252d76e64fd2be20c58eb5d7f2e +Subproject commit eb11070f67565b2e660659f5207f0363bdf3b882 diff --git a/extern/adios2 b/extern/adios2 index 25ccd6aaa..b8761e2af 160000 --- a/extern/adios2 +++ b/extern/adios2 @@ -1 +1 @@ -Subproject commit 25ccd6aaa810bbc217b43421f9c43140082c65b9 +Subproject commit b8761e2afab2cd05b89d09b2ee4da1cd7a834225 diff --git a/extern/plog b/extern/plog index 96637a6e5..85a871b13 160000 --- a/extern/plog +++ b/extern/plog @@ -1 +1 @@ -Subproject commit 96637a6e5e53f54e4e56d667d312c564d979ec0e +Subproject commit 85a871b13be0bd1a9e0110744fa60cc9bd1e8380 diff --git a/src/framework/containers/particles.h b/src/framework/containers/particles.h index 7496db78c..86443c98f 100644 --- a/src/framework/containers/particles.h +++ b/src/framework/containers/particles.h @@ -193,7 +193,6 @@ namespace ntt { * @brief Count the number of particles with a specific tag. * @return The vector of counts for each tag. */ - [[nodiscard]] auto npart_per_tag() const -> std::vector; /* setters -------------------------------------------------------------- */ diff --git a/src/framework/domain/comm_mpi.hpp b/src/framework/domain/comm_mpi.hpp index 9b2ad0a33..d7d19c983 100644 --- a/src/framework/domain/comm_mpi.hpp +++ b/src/framework/domain/comm_mpi.hpp @@ -296,18 +296,18 @@ namespace comm { int recv_rank, const range_tuple_t& send_slice, const range_tuple_t& recv_slice) { - auto array_h = Kokkos::create_mirror_view(arr); - Kokkos::deep_copy(array_h, arr); + // auto array_h = Kokkos::create_mirror_view(arr); + // Kokkos::deep_copy(array, arr); const std::size_t send_count = send_slice.second - send_slice.first; const std::size_t recv_count = recv_slice.second - recv_slice.first; if ((send_rank >= 0) and (recv_rank >= 0) and (send_count > 0) and (recv_count > 0)) { - MPI_Sendrecv(array_h.data() + send_slice.first, + MPI_Sendrecv(arr.data() + send_slice.first, send_count, mpi::get_type(), send_rank, 0, - array_h.data() + recv_slice.first, + arr.data() + recv_slice.first, recv_count, mpi::get_type(), recv_rank, @@ -315,14 +315,14 @@ namespace comm { MPI_COMM_WORLD, MPI_STATUS_IGNORE); } else if ((send_rank >= 0) and (send_count > 0)) { - MPI_Send(array_h.data() + send_slice.first, + MPI_Send(arr.data() + send_slice.first, send_count, mpi::get_type(), send_rank, 0, MPI_COMM_WORLD); } else if ((recv_rank >= 0) and (recv_count > 0)) { - MPI_Recv(array_h.data() + recv_slice.first, + MPI_Recv(arr.data() + recv_slice.first, recv_count, mpi::get_type(), recv_rank, @@ -330,9 +330,9 @@ namespace comm { MPI_COMM_WORLD, MPI_STATUS_IGNORE); } - if ((recv_rank >= 0) and (recv_count > 0)) { - Kokkos::deep_copy(arr, array_h); - } + // if ((recv_rank >= 0) and (recv_count > 0)) { + // Kokkos::deep_copy(arr, array_h); + // } } void ParticleSendRecvCount(int send_rank, diff --git a/src/framework/domain/communications.cpp b/src/framework/domain/communications.cpp index 5e5da4a0c..ff7edfec6 100644 --- a/src/framework/domain/communications.cpp +++ b/src/framework/domain/communications.cpp @@ -86,8 +86,8 @@ namespace ntt { } else { // no communication necessary return { - { 0, -1 }, - { 0, -1 } + {0, -1}, + {0, -1} }; } #if defined(MPI_ENABLED) @@ -110,8 +110,8 @@ namespace ntt { (void)send_rank; (void)recv_rank; return { - { send_ind, send_rank }, - { recv_ind, recv_rank } + {send_ind, send_rank}, + {recv_ind, recv_rank} }; } @@ -129,8 +129,8 @@ namespace ntt { const auto is_receiving = (recv_rank >= 0); if (not(is_sending or is_receiving)) { return { - { { 0, -1 }, {} }, - { { 0, -1 }, {} } + {{ 0, -1 }, {}}, + {{ 0, -1 }, {}} }; } auto send_slice = std::vector {}; @@ -196,8 +196,8 @@ namespace ntt { } return { - { { send_ind, send_rank }, send_slice }, - { { recv_ind, recv_rank }, recv_slice }, + {{ send_ind, send_rank }, send_slice}, + {{ recv_ind, recv_rank }, recv_slice}, }; } @@ -746,6 +746,7 @@ namespace ntt { // to the pth hole in the array, or after npart() if p > sent+dead count. Kokkos::View allocation_vector("allocation_vector", total_recv); + // @CRITICAL: this may overwrite unsent data Kokkos::parallel_for( "AllocationVector", total_recv, diff --git a/src/framework/domain/metadomain.cpp b/src/framework/domain/metadomain.cpp index 5e66bc366..ec8561a9a 100644 --- a/src/framework/domain/metadomain.cpp +++ b/src/framework/domain/metadomain.cpp @@ -46,6 +46,9 @@ namespace ntt { #if defined(MPI_ENABLED) MPI_Comm_size(MPI_COMM_WORLD, &g_mpi_size); MPI_Comm_rank(MPI_COMM_WORLD, &g_mpi_rank); + raise::ErrorIf(global_ndomains != g_mpi_size, + "Exactly 1 domain per MPI rank is allowed", + HERE); #endif initialValidityCheck(); From 668db7b255f12b3ceb1420134986d8c846d9c669 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Tue, 17 Dec 2024 15:22:31 -0500 Subject: [PATCH 187/773] updated setups --- setups/grpic/orbits/orbits.toml | 73 ++++++++++++++++ setups/grpic/orbits/pgen.hpp | 132 ++++++++++++++++++++++++++++ setups/grpic/pusher/deposit.toml | 91 +++++++++++++++++++ setups/grpic/vacuum/pgen.hpp | 146 +++++++++++++++++++++++++++++++ setups/grpic/vacuum/wald.toml | 93 ++++++++++++++++++++ setups/grpic/wald/pgen.hpp | 26 ++++-- setups/grpic/wald/wald.toml | 48 +++++----- 7 files changed, 583 insertions(+), 26 deletions(-) create mode 100644 setups/grpic/orbits/orbits.toml create mode 100644 setups/grpic/orbits/pgen.hpp create mode 100644 setups/grpic/pusher/deposit.toml create mode 100644 setups/grpic/vacuum/pgen.hpp create mode 100644 setups/grpic/vacuum/wald.toml diff --git a/setups/grpic/orbits/orbits.toml b/setups/grpic/orbits/orbits.toml new file mode 100644 index 000000000..ab8f2bef5 --- /dev/null +++ b/setups/grpic/orbits/orbits.toml @@ -0,0 +1,73 @@ +[simulation] + name = "wald" + engine = "grpic" + runtime = 110.0 + +[grid] + resolution = [128,128] + extent = [[1.2, 8.0]] + + [grid.metric] + metric = "kerr_schild" + qsph_r0 = 0.0 + qsph_h = 0.0 + ks_a = 0.95 + + [grid.boundaries] + fields = [["ABSORB"]] + particles = [["ABSORB"]] + + [grid.boundaries.absorb] + ds = 0.5 + +[scales] + larmor0 = 1.0 + skindepth0 = 1.0 + +[algorithms] + current_filters = 4 + + [algorithms.timestep] + CFL = 0.5 + + [algorithms.toggles] + deposit = false + fieldsolver = true + +[particles] + ppc0 = 8.0 + use_weights = true + sort_interval = 100 + +# [[particles.species]] +# label = "e-" +# mass = 1.0 +# charge = -1.0 +# maxnpart = 2e6 +# pusher = "Boris" +# +# [[particles.species]] +# label = "e+" +# mass = 1.0 +# charge = 1.0 +# maxnpart = 2e6 +# pusher = "Boris" + +[setup] + +[output] + format = "hdf5" + + [output.fields] + interval_time = 1.0 + quantities = ["D", "H", "B", "J"] + + [output.particles] + interval_time = 1.0 + quantities = ["X", "U"] + + [output.spectra] + enable = false + +[diagnostics] + interval = 1 diff --git a/setups/grpic/orbits/pgen.hpp b/setups/grpic/orbits/pgen.hpp new file mode 100644 index 000000000..54965b1ee --- /dev/null +++ b/setups/grpic/orbits/pgen.hpp @@ -0,0 +1,132 @@ +#ifndef PROBLEM_GENERATOR_H +#define PROBLEM_GENERATOR_H + +#include "enums.h" +#include "global.h" + +#include "arch/kokkos_aliases.h" +#include "arch/traits.h" + +#include "archetypes/problem_generator.h" +#include "framework/domain/metadomain.h" + +namespace user { + using namespace ntt; + + template + struct InitFields { + InitFields(M metric_) : metric { metric_ } {} + + Inline auto A_3(const coord_t& x_Cd) const -> real_t { + // return HALF * (metric.template h_<3, 3>(x_Cd) ); + // + TWO * metric.spin() * metric.template h_<1, 3>(x_Cd) * metric.beta1(x_Cd) + // ); + + coord_t x_Ph { ZERO }; + metric.template convert(x_Cd, x_Ph); + return HALF * SQR(x_Ph[0]) * SQR(math::sin(x_Ph[1])); + } + + Inline auto A_1(const coord_t& x_Cd) const -> real_t { + return HALF * (metric.template h_<1, 3>(x_Cd) + + TWO * metric.spin() * metric.template h_<1, 1>(x_Cd) * metric.beta1(x_Cd) + ); + } + + Inline auto A_0(const coord_t& x_Cd) const -> real_t { + real_t g_00 { -metric.alpha(x_Cd) * metric.alpha(x_Cd) + + metric.template h_<1, 1>(x_Cd) * metric.beta1(x_Cd) * metric.beta1(x_Cd) + }; + return HALF * (metric.template h_<1, 3>(x_Cd) * metric.beta1(x_Cd) + + TWO * metric.spin() * g_00); + } + + Inline auto bx1(const coord_t& x_Ph) const -> real_t { + coord_t xi {ZERO}, x0m { ZERO }, x0p { ZERO }; + metric.template convert(x_Ph, xi); + + x0m[0] = xi[0]; + x0m[1] = xi[1] - HALF; + x0p[0] = xi[0]; + x0p[1] = xi[1] + HALF; + + real_t inv_sqrt_detH_ijP { ONE / metric.sqrt_det_h({ xi[0], xi[1] }) }; + + if (cmp::AlmostZero(x_Ph[1])) + return ONE; + else + return (A_3(x0p) - A_3(x0m)) * inv_sqrt_detH_ijP; + } + + Inline auto bx2(const coord_t& x_Ph) const -> real_t { + coord_t xi {ZERO}, x0m { ZERO }, x0p { ZERO }; + metric.template convert(x_Ph, xi); + + x0m[0] = xi[0] + HALF - HALF; + x0m[1] = xi[1]; + x0p[0] = xi[0] + HALF + HALF; + x0p[1] = xi[1]; + + real_t inv_sqrt_detH_ijP { ONE / metric.sqrt_det_h({ xi[0], xi[1] }) }; + if (cmp::AlmostZero(x_Ph[1])) + return ZERO; + else + return -(A_3(x0p) - A_3(x0m)) * inv_sqrt_detH_ijP; + } + + Inline auto bx3(const coord_t& x_Ph) const -> real_t { + coord_t xi {ZERO}, x0m { ZERO }, x0p { ZERO }; + metric.template convert(x_Ph, xi); + + x0m[0] = xi[0] + HALF - HALF; + x0m[1] = xi[1]; + x0p[0] = xi[0] + HALF + HALF; + x0p[1] = xi[1]; + + real_t inv_sqrt_detH_ijP { ONE / metric.sqrt_det_h({ xi[0], xi[1] }) }; + return -(A_1(x0p) - A_1(x0m)) * inv_sqrt_detH_ijP; + // return ZERO; + } + + Inline auto dx1(const coord_t& x_Ph) const -> real_t { + return ZERO; + } + + Inline auto dx2(const coord_t& x_Ph) const -> real_t { + return ZERO; + } + + Inline auto dx3(const coord_t& x_Ph) const -> real_t { + return ZERO; + } + + private: + const M metric; + }; + + template + struct PGen : public arch::ProblemGenerator { + // compatibility traits for the problem generator + static constexpr auto engines { traits::compatible_with::value }; + static constexpr auto metrics { + traits::compatible_with::value + }; + static constexpr auto dimensions { traits::compatible_with::value }; + + // for easy access to variables in the child class + using arch::ProblemGenerator::D; + using arch::ProblemGenerator::C; + using arch::ProblemGenerator::params; + + InitFields init_flds; + + inline PGen(SimulationParams& p, const Metadomain& m) + : arch::ProblemGenerator(p) + , init_flds { m.mesh().metric } {} + + inline PGen() {} + }; + +} // namespace user + +#endif diff --git a/setups/grpic/pusher/deposit.toml b/setups/grpic/pusher/deposit.toml new file mode 100644 index 000000000..359d4eaa7 --- /dev/null +++ b/setups/grpic/pusher/deposit.toml @@ -0,0 +1,91 @@ +[simulation] + name = "deposit" + engine = "grpic" + runtime = 10.0 + +[grid] + resolution = [512,512] + extent = [[1.2, 20.0]] + + [grid.metric] + metric = "kerr_schild" + qsph_r0 = 0.0 + qsph_h = 0.0 + ks_a = 0.0 + + [grid.boundaries] + fields = [["ABSORB"]] + particles = [["ABSORB"]] + + [grid.boundaries.absorb] + ds = 2.0 + +[scales] + larmor0 = 2.0 + skindepth0 = 2.0 + +[algorithms] + current_filters = 4 + + [algorithms.gr] + pusher_niter = 10 + pusher_eps = 1e-6 + + [algorithms.timestep] + CFL = 0.5 + + [algorithms.toggles] + deposit = true + fieldsolver = true + +[particles] + ppc0 = 1.0 + + [[particles.species]] + label = "e-" + mass = 1.0 + charge = -1.0 + maxnpart = 1e0 + + [[particles.species]] + label = "e+" + mass = 1.0 + charge = 1.0 + maxnpart = 1e0 + +[setup] + x1s = [17.00000] + y1s = [1.570796] + z1s = [0.000000] + ux1s = [8.000000] + uy1s = [0.000000] + uz1s = [0.000000] + + x2s = [17.00000] + y2s = [1.570796] + z2s = [0.000000] + ux2s = [-8.000000] + uy2s = [0.000000] + uz2s = [0.000000] + +[output] + format = "hdf5" + + [output.fields] + enable = true + interval_time = 0.5 + quantities = ["D", "B"] + + [output.particles] + enable = true + stride = 1 + interval_time = 0.5 + species = [] + + [output.spectra] + enable = false + +[diagnostics] + interval = 10 + colored_stdout = true + blocking_timers = true diff --git a/setups/grpic/vacuum/pgen.hpp b/setups/grpic/vacuum/pgen.hpp new file mode 100644 index 000000000..c02c198e8 --- /dev/null +++ b/setups/grpic/vacuum/pgen.hpp @@ -0,0 +1,146 @@ +#ifndef PROBLEM_GENERATOR_H +#define PROBLEM_GENERATOR_H + +#include "enums.h" +#include "global.h" + +#include "arch/kokkos_aliases.h" +#include "arch/traits.h" +#include "utils/comparators.h" +#include "utils/formatting.h" +#include "utils/log.h" +#include "utils/numeric.h" + +#include "archetypes/problem_generator.h" +#include "framework/domain/metadomain.h" +#include "framework/domain/domain.h" +#include "archetypes/energy_dist.h" +#include "archetypes/particle_injector.h" + +#include + +namespace user { + using namespace ntt; + + template + struct InitFields { + InitFields(M metric_) : metric { metric_ } {} + + Inline auto A_3(const coord_t& x_Cd) const -> real_t { + return HALF * (metric.template h_<3, 3>(x_Cd) ); + // + TWO * metric.spin() * metric.template h_<1, 3>(x_Cd) * metric.beta1(x_Cd) + // ); + coord_t x_Ph { ZERO }; + metric.template convert(x_Cd, x_Ph); + return HALF * SQR(x_Ph[0]) * SQR(math::sin(x_Ph[1])); + } + + Inline auto A_1(const coord_t& x_Cd) const -> real_t { + return HALF * (metric.template h_<1, 3>(x_Cd) + + TWO * metric.spin() * metric.template h_<1, 1>(x_Cd) * metric.beta1(x_Cd) + ); + } + + Inline auto A_0(const coord_t& x_Cd) const -> real_t { + real_t g_00 { -metric.alpha(x_Cd) * metric.alpha(x_Cd) + + metric.template h_<1, 1>(x_Cd) * metric.beta1(x_Cd) * metric.beta1(x_Cd) + }; + return HALF * (metric.template h_<1, 3>(x_Cd) * metric.beta1(x_Cd) + + TWO * metric.spin() * g_00); + } + + Inline auto bx1(const coord_t& x_Ph) const -> real_t { + coord_t xi {ZERO}, x0m { ZERO }, x0p { ZERO }; + metric.template convert(x_Ph, xi); + + x0m[0] = xi[0]; + x0m[1] = xi[1] - HALF; + x0p[0] = xi[0]; + x0p[1] = xi[1] + HALF; + + real_t inv_sqrt_detH_ijP { ONE / metric.sqrt_det_h({ xi[0], xi[1] }) }; + + if (cmp::AlmostZero(x_Ph[1])) + return ONE; + else + return (A_3(x0p) - A_3(x0m)) * inv_sqrt_detH_ijP; + } + + Inline auto bx2(const coord_t& x_Ph) const -> real_t { + coord_t xi {ZERO}, x0m { ZERO }, x0p { ZERO }; + metric.template convert(x_Ph, xi); + + x0m[0] = xi[0] + HALF - HALF; + x0m[1] = xi[1]; + x0p[0] = xi[0] + HALF + HALF; + x0p[1] = xi[1]; + + real_t inv_sqrt_detH_ijP { ONE / metric.sqrt_det_h({ xi[0], xi[1] }) }; + if (cmp::AlmostZero(x_Ph[1])) + return ZERO; + else + return -(A_3(x0p) - A_3(x0m)) * inv_sqrt_detH_ijP; + } + + Inline auto bx3(const coord_t& x_Ph) const -> real_t { + // coord_t xi {ZERO}, x0m { ZERO }, x0p { ZERO }; + // metric.template convert(x_Ph, xi); + + // x0m[0] = xi[0] + HALF - HALF; + // x0m[1] = xi[1]; + // x0p[0] = xi[0] + HALF + HALF; + // x0p[1] = xi[1]; + + // real_t inv_sqrt_detH_ijP { ONE / metric.sqrt_det_h({ xi[0], xi[1] }) }; + // return -(A_1(x0p) - A_1(x0m)) * inv_sqrt_detH_ijP; + return ZERO; + } + + Inline auto dx1(const coord_t& x_Ph) const -> real_t { + return ZERO; + } + + Inline auto dx2(const coord_t& x_Ph) const -> real_t { + return ZERO; + } + + Inline auto dx3(const coord_t& x_Ph) const -> real_t { + return ZERO; + } + + private: + const M metric; + }; + + template + struct PGen : public arch::ProblemGenerator { + // compatibility traits for the problem generator + static constexpr auto engines { traits::compatible_with::value }; + static constexpr auto metrics { + traits::compatible_with::value + }; + static constexpr auto dimensions { traits::compatible_with::value }; + + // for easy access to variables in the child class + using arch::ProblemGenerator::D; + using arch::ProblemGenerator::C; + using arch::ProblemGenerator::params; + + InitFields init_flds; + const Metadomain& global_domain; + inline PGen(const SimulationParams& p, const Metadomain& m) + : arch::ProblemGenerator { p } + , global_domain { m } + , init_flds { m.mesh().metric } {} + + // inline void InitPrtls(Domain& local_domain) { + + // arch::InjectGlobally(global_domain, local_domain, (arch::spidx_t)1, data_1); + // arch::InjectGlobally(global_domain, local_domain, (arch::spidx_t)2, data_2); + // } + // inline PGen() {} + }; + +} // namespace user + +#endif diff --git a/setups/grpic/vacuum/wald.toml b/setups/grpic/vacuum/wald.toml new file mode 100644 index 000000000..6864efb17 --- /dev/null +++ b/setups/grpic/vacuum/wald.toml @@ -0,0 +1,93 @@ +[simulation] + name = "wald" + engine = "grpic" + runtime = 5000.0 + +[grid] + resolution = [128,128] + extent = [[1.2, 100.0]] + + [grid.metric] + metric = "qkerr_schild" + qsph_r0 = 0.0 + qsph_h = 0.0 + ks_a = 0.0 + + [grid.boundaries] + fields = [["ABSORB"]] + particles = [["ABSORB"]] + + [grid.boundaries.absorb] + ds = 0.5 + +[scales] + larmor0 = 2e-3 + skindepth0 = 0.1 + +[algorithms] + current_filters = 4 + + [algorithms.gr] + pusher_niter = 10 + pusher_eps = 1e-2 + + [algorithms.timestep] + CFL = 10.0 + + [algorithms.toggles] + deposit = false + fieldsolver = false + +[particles] + ppc0 = 4.0 + + [[particles.species]] + label = "e-" + mass = 1.0 + charge = 0.0 + maxnpart = 1e1 + + [[particles.species]] + label = "e+" + mass = 1.0 + charge = -1.0 + maxnpart = 1e1 + +[setup] + # (1,1,0) from Levin&Perez-Giz (2008) + x1s = [59.921203] + y1s = [1.570796] + z1s = [0.000000] + ux1s = [0.034020] + uy1s = [0.000000] + uz1s = [3.900000] + + # (4,1,1) from Levin&Perez-Giz (2008) + x2s = [68.600387] + y2s = [1.570796] + z2s = [0.000000] + ux2s = [0.029637] + uy2s = [0.000000] + uz2s = [3.900000] + +[output] + format = "hdf5" + + [output.fields] + enable = true + interval_time = 1.0 + quantities = ["D", "B"] + + [output.particles] + enable = true + stride = 1 + interval_time = 10.0 + species = [] + + [output.spectra] + enable = false + +[diagnostics] + interval = 10 + colored_stdout = true + blocking_timers = true diff --git a/setups/grpic/wald/pgen.hpp b/setups/grpic/wald/pgen.hpp index 51636314b..8dd1a6e4e 100644 --- a/setups/grpic/wald/pgen.hpp +++ b/setups/grpic/wald/pgen.hpp @@ -18,10 +18,9 @@ namespace user { InitFields(M metric_) : metric { metric_ } {} Inline auto A_3(const coord_t& x_Cd) const -> real_t { - // return HALF * (metric.template h_<3, 3>(x_Cd) ); - // + TWO * metric.spin() * metric.template h_<1, 3>(x_Cd) * metric.beta1(x_Cd) + // return HALF * (metric.template h_<3, 3>(x_Cd) + // + TWO * metric.spin() * metric.template h_<1, 3>(x_Cd) * metric.beta1(x_Cd) // ); - coord_t x_Ph { ZERO }; metric.template convert(x_Cd, x_Ph); return HALF * SQR(x_Ph[0]) * SQR(math::sin(x_Ph[1])); @@ -122,9 +121,26 @@ namespace user { inline PGen(SimulationParams& p, const Metadomain& m) : arch::ProblemGenerator(p) + // , xi_min { p.template get>("setup.inj_rmin") } + // , xi_max { p.template get>("setup.inj_rmax") } , init_flds { m.mesh().metric } {} - - inline PGen() {} + + // inline void InitPrtls(Domain& local_domain) { + // const auto energy_dist = arch::ColdDist(local_domain.mesh.metric); + // const auto spatial_dist = PointDistribution(domain.mesh.metric, + // xi_min, + // xi_max); + // const auto injector = arch::NonUniformInjector( + // energy_dist, + // spatial_dist, + // { 1, 2 }); + // arch::InjectNonUniform>(params, + // local_domain, + // injector, + // 1.0); + // } + + // inline PGen() {} }; } // namespace user diff --git a/setups/grpic/wald/wald.toml b/setups/grpic/wald/wald.toml index 36c746ae5..44d1c8a24 100644 --- a/setups/grpic/wald/wald.toml +++ b/setups/grpic/wald/wald.toml @@ -1,17 +1,17 @@ [simulation] name = "wald" engine = "grpic" - runtime = 500.0 + runtime = 110.0 [grid] resolution = [128,128] - extent = [[1.2, 8.0]] + extent = [[2.0, 8.0]] [grid.metric] metric = "qkerr_schild" qsph_r0 = 0.0 qsph_h = 0.0 - ks_a = 0.95 + ks_a = 0.0 [grid.boundaries] fields = [["ABSORB"]] @@ -21,14 +21,14 @@ ds = 0.5 [scales] - larmor0 = 1.0 - skindepth0 = 1.0 + larmor0 = 1.0 #0.0025 + skindepth0 = 1.0 #0.05 [algorithms] current_filters = 4 [algorithms.timestep] - CFL = 0.5 + CFL = 0.3 [algorithms.toggles] deposit = false @@ -39,28 +39,32 @@ use_weights = true sort_interval = 100 -# [[particles.species]] -# label = "e-" -# mass = 1.0 -# charge = -1.0 -# maxnpart = 2e6 -# pusher = "Boris" -# -# [[particles.species]] -# label = "e+" -# mass = 1.0 -# charge = 1.0 -# maxnpart = 2e6 -# pusher = "Boris" + #[[particles.species]] + #label = "e-" + #mass = 1.0 + #charge = -1.0 + #maxnpart = 1e6 + #pusher = "Boris" + # + #[[particles.species]] + #label = "e+" + #mass = 1.0 + #charge = 1.0 + #maxnpart = 1e6 + #pusher = "Boris" [setup] + #multiplicity = 1.0 + #sigma_max = 1000.0 + #inj_rmin = 1.2 + #inj_rmax = 7.5 [output] format = "hdf5" [output.fields] interval_time = 1.0 - quantities = ["D", "H", "B", "J", "A"] + quantities = ["D", "H", "B", "J"] [output.particles] enable = false @@ -69,4 +73,6 @@ enable = false [diagnostics] - interval = 1 + interval = 2 + colored_stdout = true + blocking_timers = true From 646a208a5c122ef168a12ac169fab2acd2e5e454 Mon Sep 17 00:00:00 2001 From: Siddhant Solanki Date: Tue, 17 Dec 2024 20:04:54 -0500 Subject: [PATCH 188/773] removed tag_offset array from the particle class. The npart_per_tag() method now returns a pair of npart_per_tag and tag_offset arrays --- src/framework/containers/particles.cpp | 16 ++++++---------- src/framework/containers/particles.h | 4 ---- 2 files changed, 6 insertions(+), 14 deletions(-) diff --git a/src/framework/containers/particles.cpp b/src/framework/containers/particles.cpp index c97f8da2d..52efdaf6d 100644 --- a/src/framework/containers/particles.cpp +++ b/src/framework/containers/particles.cpp @@ -47,9 +47,6 @@ namespace ntt { tag = array_t { label + "_tag", maxnpart }; tag_h = Kokkos::create_mirror_view(tag); - tag_offset = array_t { label + "_tag_offset", ntags() }; - tag_offset_h = Kokkos::create_mirror_view(tag_offset); - for (unsigned short n { 0 }; n < npld; ++n) { pld.push_back(array_t("pld", maxnpart)); pld_h.push_back(Kokkos::create_mirror_view(pld[n])); @@ -101,17 +98,16 @@ namespace ntt { auto npart_tag_host = Kokkos::create_mirror_view(npart_tag); Kokkos::deep_copy(npart_tag_host, npart_tag); - std::vector npart_tag_vec; + std::vector npart_tag_vec(ntags()); + std::vector tag_offset(ntags()); for (std::size_t t { 0 }; t < ntags(); ++t) { - npart_tag_vec.push_back(npart_tag_host(t)); - tag_offset_h(t) = (t > 0) ? npart_tag_vec[t - 1] : 0; + npart_tag_vec[t] = npart_tag_host(t); + tag_offset[t] = (t > 0) ? npart_tag_vec[t - 1] : 0; } for (std::size_t t { 0 }; t < ntags(); ++t) { - tag_offset_h(t) += (t > 0) ? tag_offset_h(t - 1) : 0; + tag_offset[t] += (t > 0) ? tag_offset[t - 1] : 0; } - // Copy to device - Kokkos::deep_copy(tag_offset, tag_offset_h); - return npart_tag_vec; + return std::make_pair(npart_tag_vec, tag_offset); } template diff --git a/src/framework/containers/particles.h b/src/framework/containers/particles.h index 86443c98f..e4d78cd0d 100644 --- a/src/framework/containers/particles.h +++ b/src/framework/containers/particles.h @@ -60,8 +60,6 @@ namespace ntt { array_t dx1_prev, dx2_prev, dx3_prev; // Array to tag the particles array_t tag; - // Array to store the cumulative number of particles per tag - array_t tag_offset; // Array to store the particle load std::vector> pld; // phi coordinate (for axisymmetry) @@ -74,7 +72,6 @@ namespace ntt { array_mirror_t weight_h; array_mirror_t phi_h; array_mirror_t tag_h; - array_mirror_t tag_offset_h; std::vector> pld_h; // for empty allocation @@ -181,7 +178,6 @@ namespace ntt { footprint += sizeof(prtldx_t) * dx2_prev.extent(0); footprint += sizeof(prtldx_t) * dx3_prev.extent(0); footprint += sizeof(short) * tag.extent(0); - footprint += sizeof(int) * tag_offset.extent(0); for (auto& p : pld) { footprint += sizeof(real_t) * p.extent(0); } From 708115c4408d276e1e67f8afd291f793f7a6a831 Mon Sep 17 00:00:00 2001 From: Siddhant Solanki Date: Tue, 17 Dec 2024 20:47:52 -0500 Subject: [PATCH 189/773] changed functions that called npart_per_tag() --- src/framework/containers/particles.cpp | 18 ++++++++------ src/framework/containers/particles.h | 2 +- src/framework/domain/communications.cpp | 31 ++++++++++++++----------- 3 files changed, 29 insertions(+), 22 deletions(-) diff --git a/src/framework/containers/particles.cpp b/src/framework/containers/particles.cpp index 52efdaf6d..fe2346132 100644 --- a/src/framework/containers/particles.cpp +++ b/src/framework/containers/particles.cpp @@ -78,7 +78,8 @@ namespace ntt { } template - auto Particles::npart_per_tag() const -> std::vector { + auto Particles::npart_per_tag() const -> std::pair, + array_t>{ auto this_tag = tag; array_t npart_tag("npart_tags", ntags()); @@ -97,23 +98,25 @@ namespace ntt { auto npart_tag_host = Kokkos::create_mirror_view(npart_tag); Kokkos::deep_copy(npart_tag_host, npart_tag); + array_t tag_offset("tag_offset", ntags()); + auto tag_offset_host = Kokkos::create_mirror_view(tag_offset); std::vector npart_tag_vec(ntags()); - std::vector tag_offset(ntags()); for (std::size_t t { 0 }; t < ntags(); ++t) { - npart_tag_vec[t] = npart_tag_host(t); - tag_offset[t] = (t > 0) ? npart_tag_vec[t - 1] : 0; + npart_tag_vec[t] = npart_tag_host(t); + tag_offset_host(t) = (t > 0) ? npart_tag_vec[t - 1] : 0; } for (std::size_t t { 0 }; t < ntags(); ++t) { - tag_offset[t] += (t > 0) ? tag_offset[t - 1] : 0; + tag_offset_host(t) += (t > 0) ? tag_offset_host(t - 1) : 0; } + Kokkos::deep_copy(tag_offset, tag_offset_host); return std::make_pair(npart_tag_vec, tag_offset); } template auto Particles::SortByTags() -> std::vector { if (npart() == 0 || is_sorted()) { - return npart_per_tag(); + return npart_per_tag().first; } using KeyType = array_t; using BinOp = sort::BinTag; @@ -156,7 +159,8 @@ namespace ntt { Sorter.sort(Kokkos::subview(phi, slice)); } - const auto np_per_tag = npart_per_tag(); + auto np_per_tag_tag_offset = npart_per_tag(); + const auto np_per_tag = np_per_tag_tag_offset.first; set_npart(np_per_tag[(short)(ParticleTag::alive)]); m_is_sorted = true; diff --git a/src/framework/containers/particles.h b/src/framework/containers/particles.h index e4d78cd0d..ea692bdd9 100644 --- a/src/framework/containers/particles.h +++ b/src/framework/containers/particles.h @@ -189,7 +189,7 @@ namespace ntt { * @brief Count the number of particles with a specific tag. * @return The vector of counts for each tag. */ - auto npart_per_tag() const -> std::vector; + auto npart_per_tag() const -> std::pair, array_t>; /* setters -------------------------------------------------------------- */ /** diff --git a/src/framework/domain/communications.cpp b/src/framework/domain/communications.cpp index ff7edfec6..36f7a1858 100644 --- a/src/framework/domain/communications.cpp +++ b/src/framework/domain/communications.cpp @@ -656,16 +656,18 @@ namespace ntt { HERE); logger::Checkpoint("Communicating particles\n", HERE); for (auto& species : domain.species) { - auto npart_per_tag_arr = species.npart_per_tag(); - auto npart = static_cast(species.npart()); - auto total_alive = static_cast( - npart_per_tag_arr[ParticleTag::alive]); - auto total_dead = static_cast( - npart_per_tag_arr[ParticleTag::dead]); - auto total_holes = static_cast(npart - total_alive); - auto total_send = static_cast(npart - total_alive - total_dead); - auto total_recv = static_cast(0); - auto tag_count = static_cast(npart_per_tag_arr.size()); + // TO DO: npart per tag must return npart_per_tag_arr and the cumsum array + auto [npart_per_tag_arr, + tag_offset] = species.npart_per_tag(); + auto npart = static_cast(species.npart()); + auto total_alive = static_cast( + npart_per_tag_arr[ParticleTag::alive]); + auto total_dead = static_cast( + npart_per_tag_arr[ParticleTag::dead]); + auto total_holes = static_cast(npart - total_alive); + auto total_send = static_cast(npart - total_alive - total_dead); + auto total_recv = static_cast(0); + auto tag_count = static_cast(npart_per_tag_arr.size()); std::vector send_ranks, send_inds; std::vector recv_ranks, recv_inds; @@ -715,7 +717,6 @@ namespace ntt { (dead) (alive) (tag1) ... */ auto& this_tag = species.tag; - auto& this_tag_offset = species.tag_offset; Kokkos::View permute_vector("permute_vector", species.npart()); Kokkos::View current_offset("current_offset", species.ntags()); // @TODO: do not save tag = 1 particles into permute_vector @@ -726,7 +727,7 @@ namespace ntt { species.npart(), Lambda(index_t p) { const auto current_tag = this_tag(p); - const auto idx_permute_vec = this_tag_offset(current_tag) + + const auto idx_permute_vec = tag_offset(current_tag) + Kokkos::atomic_fetch_add( ¤t_offset(current_tag), 1); @@ -826,11 +827,13 @@ namespace ntt { } // Tuple that contains the start and end indices of permtute_vec pointing to a given tag type = dir2tag(dir) + auto tag_offset_h = Kokkos::create_mirror_view(tag_offset); + Kokkos::deep_copy(tag_offset_h, tag_offset); auto range_permute = std::make_pair( static_cast( - species.tag_offset_h[mpi::PrtlSendTag::dir2tag(direction)]), + tag_offset_h[mpi::PrtlSendTag::dir2tag(direction)]), static_cast( - species.tag_offset_h[mpi::PrtlSendTag::dir2tag(direction)] + + tag_offset_h[mpi::PrtlSendTag::dir2tag(direction)] + npart_per_tag_arr[mpi::PrtlSendTag::dir2tag(direction)])); // Tuple that contains the start and end indices for allocation_vector pointing to a given tag type = dir2tag(dir) auto range_allocate = std::make_pair( From 98287db43bea318d0bb449486e24149e64d6620d Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Wed, 18 Dec 2024 10:59:29 -0500 Subject: [PATCH 190/773] engines/grpic: fixed the bug i introduced --- src/engines/grpic.hpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index 6b36ec35c..01a61118e 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -259,15 +259,15 @@ namespace ntt { * x_prtl at 1 * u_prtl at 1/2 */ + } else { + /** + * em0::B <- em::B + * em0::D <- em::D + * + * Now: em0::B & em0::D at -1/2 + */ + CopyFields(dom); } - } else { - /** - * em0::B <- em::B - * em0::D <- em::D - * - * Now: em0::B & em0::D at -1/2 - */ - CopyFields(dom); } /** From fc48458292b1e5962cf1d5c45587ba2a3236de13 Mon Sep 17 00:00:00 2001 From: alisagk <55898700+alisagk@users.noreply.github.com> Date: Wed, 18 Dec 2024 11:10:37 -0500 Subject: [PATCH 191/773] Delete setups/grpic/orbits directory --- setups/grpic/orbits/orbits.toml | 73 ------------------ setups/grpic/orbits/pgen.hpp | 132 -------------------------------- 2 files changed, 205 deletions(-) delete mode 100644 setups/grpic/orbits/orbits.toml delete mode 100644 setups/grpic/orbits/pgen.hpp diff --git a/setups/grpic/orbits/orbits.toml b/setups/grpic/orbits/orbits.toml deleted file mode 100644 index ab8f2bef5..000000000 --- a/setups/grpic/orbits/orbits.toml +++ /dev/null @@ -1,73 +0,0 @@ -[simulation] - name = "wald" - engine = "grpic" - runtime = 110.0 - -[grid] - resolution = [128,128] - extent = [[1.2, 8.0]] - - [grid.metric] - metric = "kerr_schild" - qsph_r0 = 0.0 - qsph_h = 0.0 - ks_a = 0.95 - - [grid.boundaries] - fields = [["ABSORB"]] - particles = [["ABSORB"]] - - [grid.boundaries.absorb] - ds = 0.5 - -[scales] - larmor0 = 1.0 - skindepth0 = 1.0 - -[algorithms] - current_filters = 4 - - [algorithms.timestep] - CFL = 0.5 - - [algorithms.toggles] - deposit = false - fieldsolver = true - -[particles] - ppc0 = 8.0 - use_weights = true - sort_interval = 100 - -# [[particles.species]] -# label = "e-" -# mass = 1.0 -# charge = -1.0 -# maxnpart = 2e6 -# pusher = "Boris" -# -# [[particles.species]] -# label = "e+" -# mass = 1.0 -# charge = 1.0 -# maxnpart = 2e6 -# pusher = "Boris" - -[setup] - -[output] - format = "hdf5" - - [output.fields] - interval_time = 1.0 - quantities = ["D", "H", "B", "J"] - - [output.particles] - interval_time = 1.0 - quantities = ["X", "U"] - - [output.spectra] - enable = false - -[diagnostics] - interval = 1 diff --git a/setups/grpic/orbits/pgen.hpp b/setups/grpic/orbits/pgen.hpp deleted file mode 100644 index 54965b1ee..000000000 --- a/setups/grpic/orbits/pgen.hpp +++ /dev/null @@ -1,132 +0,0 @@ -#ifndef PROBLEM_GENERATOR_H -#define PROBLEM_GENERATOR_H - -#include "enums.h" -#include "global.h" - -#include "arch/kokkos_aliases.h" -#include "arch/traits.h" - -#include "archetypes/problem_generator.h" -#include "framework/domain/metadomain.h" - -namespace user { - using namespace ntt; - - template - struct InitFields { - InitFields(M metric_) : metric { metric_ } {} - - Inline auto A_3(const coord_t& x_Cd) const -> real_t { - // return HALF * (metric.template h_<3, 3>(x_Cd) ); - // + TWO * metric.spin() * metric.template h_<1, 3>(x_Cd) * metric.beta1(x_Cd) - // ); - - coord_t x_Ph { ZERO }; - metric.template convert(x_Cd, x_Ph); - return HALF * SQR(x_Ph[0]) * SQR(math::sin(x_Ph[1])); - } - - Inline auto A_1(const coord_t& x_Cd) const -> real_t { - return HALF * (metric.template h_<1, 3>(x_Cd) - + TWO * metric.spin() * metric.template h_<1, 1>(x_Cd) * metric.beta1(x_Cd) - ); - } - - Inline auto A_0(const coord_t& x_Cd) const -> real_t { - real_t g_00 { -metric.alpha(x_Cd) * metric.alpha(x_Cd) - + metric.template h_<1, 1>(x_Cd) * metric.beta1(x_Cd) * metric.beta1(x_Cd) - }; - return HALF * (metric.template h_<1, 3>(x_Cd) * metric.beta1(x_Cd) - + TWO * metric.spin() * g_00); - } - - Inline auto bx1(const coord_t& x_Ph) const -> real_t { - coord_t xi {ZERO}, x0m { ZERO }, x0p { ZERO }; - metric.template convert(x_Ph, xi); - - x0m[0] = xi[0]; - x0m[1] = xi[1] - HALF; - x0p[0] = xi[0]; - x0p[1] = xi[1] + HALF; - - real_t inv_sqrt_detH_ijP { ONE / metric.sqrt_det_h({ xi[0], xi[1] }) }; - - if (cmp::AlmostZero(x_Ph[1])) - return ONE; - else - return (A_3(x0p) - A_3(x0m)) * inv_sqrt_detH_ijP; - } - - Inline auto bx2(const coord_t& x_Ph) const -> real_t { - coord_t xi {ZERO}, x0m { ZERO }, x0p { ZERO }; - metric.template convert(x_Ph, xi); - - x0m[0] = xi[0] + HALF - HALF; - x0m[1] = xi[1]; - x0p[0] = xi[0] + HALF + HALF; - x0p[1] = xi[1]; - - real_t inv_sqrt_detH_ijP { ONE / metric.sqrt_det_h({ xi[0], xi[1] }) }; - if (cmp::AlmostZero(x_Ph[1])) - return ZERO; - else - return -(A_3(x0p) - A_3(x0m)) * inv_sqrt_detH_ijP; - } - - Inline auto bx3(const coord_t& x_Ph) const -> real_t { - coord_t xi {ZERO}, x0m { ZERO }, x0p { ZERO }; - metric.template convert(x_Ph, xi); - - x0m[0] = xi[0] + HALF - HALF; - x0m[1] = xi[1]; - x0p[0] = xi[0] + HALF + HALF; - x0p[1] = xi[1]; - - real_t inv_sqrt_detH_ijP { ONE / metric.sqrt_det_h({ xi[0], xi[1] }) }; - return -(A_1(x0p) - A_1(x0m)) * inv_sqrt_detH_ijP; - // return ZERO; - } - - Inline auto dx1(const coord_t& x_Ph) const -> real_t { - return ZERO; - } - - Inline auto dx2(const coord_t& x_Ph) const -> real_t { - return ZERO; - } - - Inline auto dx3(const coord_t& x_Ph) const -> real_t { - return ZERO; - } - - private: - const M metric; - }; - - template - struct PGen : public arch::ProblemGenerator { - // compatibility traits for the problem generator - static constexpr auto engines { traits::compatible_with::value }; - static constexpr auto metrics { - traits::compatible_with::value - }; - static constexpr auto dimensions { traits::compatible_with::value }; - - // for easy access to variables in the child class - using arch::ProblemGenerator::D; - using arch::ProblemGenerator::C; - using arch::ProblemGenerator::params; - - InitFields init_flds; - - inline PGen(SimulationParams& p, const Metadomain& m) - : arch::ProblemGenerator(p) - , init_flds { m.mesh().metric } {} - - inline PGen() {} - }; - -} // namespace user - -#endif From 6c502a2b8f6135092b59578092a9c950ce4b7cfa Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Wed, 18 Dec 2024 11:08:29 -0500 Subject: [PATCH 192/773] setups/grpic: updated setup for vacuum --- setups/grpic/vacuum/pgen.hpp | 37 +--------------- setups/grpic/vacuum/vacuum.toml | 78 +++++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+), 35 deletions(-) create mode 100644 setups/grpic/vacuum/vacuum.toml diff --git a/setups/grpic/vacuum/pgen.hpp b/setups/grpic/vacuum/pgen.hpp index c02c198e8..6d5e5fba5 100644 --- a/setups/grpic/vacuum/pgen.hpp +++ b/setups/grpic/vacuum/pgen.hpp @@ -27,28 +27,11 @@ namespace user { InitFields(M metric_) : metric { metric_ } {} Inline auto A_3(const coord_t& x_Cd) const -> real_t { - return HALF * (metric.template h_<3, 3>(x_Cd) ); - // + TWO * metric.spin() * metric.template h_<1, 3>(x_Cd) * metric.beta1(x_Cd) - // ); coord_t x_Ph { ZERO }; metric.template convert(x_Cd, x_Ph); return HALF * SQR(x_Ph[0]) * SQR(math::sin(x_Ph[1])); } - Inline auto A_1(const coord_t& x_Cd) const -> real_t { - return HALF * (metric.template h_<1, 3>(x_Cd) - + TWO * metric.spin() * metric.template h_<1, 1>(x_Cd) * metric.beta1(x_Cd) - ); - } - - Inline auto A_0(const coord_t& x_Cd) const -> real_t { - real_t g_00 { -metric.alpha(x_Cd) * metric.alpha(x_Cd) - + metric.template h_<1, 1>(x_Cd) * metric.beta1(x_Cd) * metric.beta1(x_Cd) - }; - return HALF * (metric.template h_<1, 3>(x_Cd) * metric.beta1(x_Cd) - + TWO * metric.spin() * g_00); - } - Inline auto bx1(const coord_t& x_Ph) const -> real_t { coord_t xi {ZERO}, x0m { ZERO }, x0p { ZERO }; metric.template convert(x_Ph, xi); @@ -70,9 +53,9 @@ namespace user { coord_t xi {ZERO}, x0m { ZERO }, x0p { ZERO }; metric.template convert(x_Ph, xi); - x0m[0] = xi[0] + HALF - HALF; + x0m[0] = xi[0] - HALF; x0m[1] = xi[1]; - x0p[0] = xi[0] + HALF + HALF; + x0p[0] = xi[0] + HALF; x0p[1] = xi[1]; real_t inv_sqrt_detH_ijP { ONE / metric.sqrt_det_h({ xi[0], xi[1] }) }; @@ -83,16 +66,6 @@ namespace user { } Inline auto bx3(const coord_t& x_Ph) const -> real_t { - // coord_t xi {ZERO}, x0m { ZERO }, x0p { ZERO }; - // metric.template convert(x_Ph, xi); - - // x0m[0] = xi[0] + HALF - HALF; - // x0m[1] = xi[1]; - // x0p[0] = xi[0] + HALF + HALF; - // x0p[1] = xi[1]; - - // real_t inv_sqrt_detH_ijP { ONE / metric.sqrt_det_h({ xi[0], xi[1] }) }; - // return -(A_1(x0p) - A_1(x0m)) * inv_sqrt_detH_ijP; return ZERO; } @@ -132,13 +105,7 @@ namespace user { : arch::ProblemGenerator { p } , global_domain { m } , init_flds { m.mesh().metric } {} - - // inline void InitPrtls(Domain& local_domain) { - // arch::InjectGlobally(global_domain, local_domain, (arch::spidx_t)1, data_1); - // arch::InjectGlobally(global_domain, local_domain, (arch::spidx_t)2, data_2); - // } - // inline PGen() {} }; } // namespace user diff --git a/setups/grpic/vacuum/vacuum.toml b/setups/grpic/vacuum/vacuum.toml new file mode 100644 index 000000000..3992b9f12 --- /dev/null +++ b/setups/grpic/vacuum/vacuum.toml @@ -0,0 +1,78 @@ +[simulation] + name = "wald" + engine = "grpic" + runtime = 500.0 + +[grid] + resolution = [128,128] + extent = [[2.0, 8.0]] + + [grid.metric] + metric = "qkerr_schild" + qsph_r0 = 0.0 + qsph_h = 0.0 + ks_a = 0.0 + + [grid.boundaries] + fields = [["ABSORB"]] + particles = [["ABSORB"]] + + [grid.boundaries.absorb] + ds = 0.5 + +[scales] + larmor0 = 0.0025 + skindepth0 = 0.05 + +[algorithms] + current_filters = 4 + + [algorithms.timestep] + CFL = 0.5 + + [algorithms.toggles] + deposit = false + fieldsolver = true + +[particles] + ppc0 = 8.0 + use_weights = true + sort_interval = 100 + + #[[particles.species]] + #label = "e-" + #mass = 1.0 + #charge = -1.0 + #maxnpart = 1e6 + #pusher = "Boris" + # + #[[particles.species]] + #label = "e+" + #mass = 1.0 + #charge = 1.0 + #maxnpart = 1e6 + #pusher = "Boris" + +[setup] + #multiplicity = 1.0 + #sigma_max = 1000.0 + inj_rmin = 1.2 + inj_rmax = 7.5 + +[output] + format = "hdf5" + + [output.fields] + interval_time = 1.0 + quantities = ["D", "H", "B", "J"] + + [output.particles] + enable = false + + [output.spectra] + enable = false + +[diagnostics] + interval = 2 + colored_stdout = true + blocking_timers = true From 1b81abe0653d29f34236208e6a3ac4fee8a6e892 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Wed, 18 Dec 2024 11:15:32 -0500 Subject: [PATCH 193/773] updated setups --- setups/grpic/vacuum/wald.toml | 93 ----------------------------------- setups/grpic/wald/pgen.hpp | 4 +- setups/grpic/wald/wald.toml | 12 ++--- 3 files changed, 8 insertions(+), 101 deletions(-) delete mode 100644 setups/grpic/vacuum/wald.toml diff --git a/setups/grpic/vacuum/wald.toml b/setups/grpic/vacuum/wald.toml deleted file mode 100644 index 6864efb17..000000000 --- a/setups/grpic/vacuum/wald.toml +++ /dev/null @@ -1,93 +0,0 @@ -[simulation] - name = "wald" - engine = "grpic" - runtime = 5000.0 - -[grid] - resolution = [128,128] - extent = [[1.2, 100.0]] - - [grid.metric] - metric = "qkerr_schild" - qsph_r0 = 0.0 - qsph_h = 0.0 - ks_a = 0.0 - - [grid.boundaries] - fields = [["ABSORB"]] - particles = [["ABSORB"]] - - [grid.boundaries.absorb] - ds = 0.5 - -[scales] - larmor0 = 2e-3 - skindepth0 = 0.1 - -[algorithms] - current_filters = 4 - - [algorithms.gr] - pusher_niter = 10 - pusher_eps = 1e-2 - - [algorithms.timestep] - CFL = 10.0 - - [algorithms.toggles] - deposit = false - fieldsolver = false - -[particles] - ppc0 = 4.0 - - [[particles.species]] - label = "e-" - mass = 1.0 - charge = 0.0 - maxnpart = 1e1 - - [[particles.species]] - label = "e+" - mass = 1.0 - charge = -1.0 - maxnpart = 1e1 - -[setup] - # (1,1,0) from Levin&Perez-Giz (2008) - x1s = [59.921203] - y1s = [1.570796] - z1s = [0.000000] - ux1s = [0.034020] - uy1s = [0.000000] - uz1s = [3.900000] - - # (4,1,1) from Levin&Perez-Giz (2008) - x2s = [68.600387] - y2s = [1.570796] - z2s = [0.000000] - ux2s = [0.029637] - uy2s = [0.000000] - uz2s = [3.900000] - -[output] - format = "hdf5" - - [output.fields] - enable = true - interval_time = 1.0 - quantities = ["D", "B"] - - [output.particles] - enable = true - stride = 1 - interval_time = 10.0 - species = [] - - [output.spectra] - enable = false - -[diagnostics] - interval = 10 - colored_stdout = true - blocking_timers = true diff --git a/setups/grpic/wald/pgen.hpp b/setups/grpic/wald/pgen.hpp index 8dd1a6e4e..b87d25ed2 100644 --- a/setups/grpic/wald/pgen.hpp +++ b/setups/grpic/wald/pgen.hpp @@ -61,9 +61,9 @@ namespace user { coord_t xi {ZERO}, x0m { ZERO }, x0p { ZERO }; metric.template convert(x_Ph, xi); - x0m[0] = xi[0] + HALF - HALF; + x0m[0] = xi[0] - HALF; x0m[1] = xi[1]; - x0p[0] = xi[0] + HALF + HALF; + x0p[0] = xi[0] + HALF; x0p[1] = xi[1]; real_t inv_sqrt_detH_ijP { ONE / metric.sqrt_det_h({ xi[0], xi[1] }) }; diff --git a/setups/grpic/wald/wald.toml b/setups/grpic/wald/wald.toml index 44d1c8a24..6e68d4324 100644 --- a/setups/grpic/wald/wald.toml +++ b/setups/grpic/wald/wald.toml @@ -1,7 +1,7 @@ [simulation] name = "wald" engine = "grpic" - runtime = 110.0 + runtime = 510.0 [grid] resolution = [128,128] @@ -21,14 +21,14 @@ ds = 0.5 [scales] - larmor0 = 1.0 #0.0025 - skindepth0 = 1.0 #0.05 + larmor0 = 0.0025 + skindepth0 = 0.05 [algorithms] current_filters = 4 [algorithms.timestep] - CFL = 0.3 + CFL = 0.5 [algorithms.toggles] deposit = false @@ -56,8 +56,8 @@ [setup] #multiplicity = 1.0 #sigma_max = 1000.0 - #inj_rmin = 1.2 - #inj_rmax = 7.5 + inj_rmin = 1.2 + inj_rmax = 7.5 [output] format = "hdf5" From 2e1cb0c69f570ee3c811be833f749465a19a06d1 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Wed, 18 Dec 2024 13:55:24 -0500 Subject: [PATCH 194/773] added separate setup for deposit debugging --- setups/grpic/deposit/deposit.toml | 91 ++++++++++++++++++++++++ setups/grpic/deposit/pgen.hpp | 113 ++++++++++++++++++++++++++++++ 2 files changed, 204 insertions(+) create mode 100644 setups/grpic/deposit/deposit.toml create mode 100644 setups/grpic/deposit/pgen.hpp diff --git a/setups/grpic/deposit/deposit.toml b/setups/grpic/deposit/deposit.toml new file mode 100644 index 000000000..359d4eaa7 --- /dev/null +++ b/setups/grpic/deposit/deposit.toml @@ -0,0 +1,91 @@ +[simulation] + name = "deposit" + engine = "grpic" + runtime = 10.0 + +[grid] + resolution = [512,512] + extent = [[1.2, 20.0]] + + [grid.metric] + metric = "kerr_schild" + qsph_r0 = 0.0 + qsph_h = 0.0 + ks_a = 0.0 + + [grid.boundaries] + fields = [["ABSORB"]] + particles = [["ABSORB"]] + + [grid.boundaries.absorb] + ds = 2.0 + +[scales] + larmor0 = 2.0 + skindepth0 = 2.0 + +[algorithms] + current_filters = 4 + + [algorithms.gr] + pusher_niter = 10 + pusher_eps = 1e-6 + + [algorithms.timestep] + CFL = 0.5 + + [algorithms.toggles] + deposit = true + fieldsolver = true + +[particles] + ppc0 = 1.0 + + [[particles.species]] + label = "e-" + mass = 1.0 + charge = -1.0 + maxnpart = 1e0 + + [[particles.species]] + label = "e+" + mass = 1.0 + charge = 1.0 + maxnpart = 1e0 + +[setup] + x1s = [17.00000] + y1s = [1.570796] + z1s = [0.000000] + ux1s = [8.000000] + uy1s = [0.000000] + uz1s = [0.000000] + + x2s = [17.00000] + y2s = [1.570796] + z2s = [0.000000] + ux2s = [-8.000000] + uy2s = [0.000000] + uz2s = [0.000000] + +[output] + format = "hdf5" + + [output.fields] + enable = true + interval_time = 0.5 + quantities = ["D", "B"] + + [output.particles] + enable = true + stride = 1 + interval_time = 0.5 + species = [] + + [output.spectra] + enable = false + +[diagnostics] + interval = 10 + colored_stdout = true + blocking_timers = true diff --git a/setups/grpic/deposit/pgen.hpp b/setups/grpic/deposit/pgen.hpp new file mode 100644 index 000000000..6d5e5fba5 --- /dev/null +++ b/setups/grpic/deposit/pgen.hpp @@ -0,0 +1,113 @@ +#ifndef PROBLEM_GENERATOR_H +#define PROBLEM_GENERATOR_H + +#include "enums.h" +#include "global.h" + +#include "arch/kokkos_aliases.h" +#include "arch/traits.h" +#include "utils/comparators.h" +#include "utils/formatting.h" +#include "utils/log.h" +#include "utils/numeric.h" + +#include "archetypes/problem_generator.h" +#include "framework/domain/metadomain.h" +#include "framework/domain/domain.h" +#include "archetypes/energy_dist.h" +#include "archetypes/particle_injector.h" + +#include + +namespace user { + using namespace ntt; + + template + struct InitFields { + InitFields(M metric_) : metric { metric_ } {} + + Inline auto A_3(const coord_t& x_Cd) const -> real_t { + coord_t x_Ph { ZERO }; + metric.template convert(x_Cd, x_Ph); + return HALF * SQR(x_Ph[0]) * SQR(math::sin(x_Ph[1])); + } + + Inline auto bx1(const coord_t& x_Ph) const -> real_t { + coord_t xi {ZERO}, x0m { ZERO }, x0p { ZERO }; + metric.template convert(x_Ph, xi); + + x0m[0] = xi[0]; + x0m[1] = xi[1] - HALF; + x0p[0] = xi[0]; + x0p[1] = xi[1] + HALF; + + real_t inv_sqrt_detH_ijP { ONE / metric.sqrt_det_h({ xi[0], xi[1] }) }; + + if (cmp::AlmostZero(x_Ph[1])) + return ONE; + else + return (A_3(x0p) - A_3(x0m)) * inv_sqrt_detH_ijP; + } + + Inline auto bx2(const coord_t& x_Ph) const -> real_t { + coord_t xi {ZERO}, x0m { ZERO }, x0p { ZERO }; + metric.template convert(x_Ph, xi); + + x0m[0] = xi[0] - HALF; + x0m[1] = xi[1]; + x0p[0] = xi[0] + HALF; + x0p[1] = xi[1]; + + real_t inv_sqrt_detH_ijP { ONE / metric.sqrt_det_h({ xi[0], xi[1] }) }; + if (cmp::AlmostZero(x_Ph[1])) + return ZERO; + else + return -(A_3(x0p) - A_3(x0m)) * inv_sqrt_detH_ijP; + } + + Inline auto bx3(const coord_t& x_Ph) const -> real_t { + return ZERO; + } + + Inline auto dx1(const coord_t& x_Ph) const -> real_t { + return ZERO; + } + + Inline auto dx2(const coord_t& x_Ph) const -> real_t { + return ZERO; + } + + Inline auto dx3(const coord_t& x_Ph) const -> real_t { + return ZERO; + } + + private: + const M metric; + }; + + template + struct PGen : public arch::ProblemGenerator { + // compatibility traits for the problem generator + static constexpr auto engines { traits::compatible_with::value }; + static constexpr auto metrics { + traits::compatible_with::value + }; + static constexpr auto dimensions { traits::compatible_with::value }; + + // for easy access to variables in the child class + using arch::ProblemGenerator::D; + using arch::ProblemGenerator::C; + using arch::ProblemGenerator::params; + + InitFields init_flds; + const Metadomain& global_domain; + inline PGen(const SimulationParams& p, const Metadomain& m) + : arch::ProblemGenerator { p } + , global_domain { m } + , init_flds { m.mesh().metric } {} + + }; + +} // namespace user + +#endif From 58a3e5daee471620a92fa53498d86e7c2e0ded49 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Wed, 18 Dec 2024 13:57:33 -0500 Subject: [PATCH 195/773] deleted deposit test from pusher tests --- setups/grpic/pusher/deposit.toml | 91 -------------------------------- 1 file changed, 91 deletions(-) delete mode 100644 setups/grpic/pusher/deposit.toml diff --git a/setups/grpic/pusher/deposit.toml b/setups/grpic/pusher/deposit.toml deleted file mode 100644 index 359d4eaa7..000000000 --- a/setups/grpic/pusher/deposit.toml +++ /dev/null @@ -1,91 +0,0 @@ -[simulation] - name = "deposit" - engine = "grpic" - runtime = 10.0 - -[grid] - resolution = [512,512] - extent = [[1.2, 20.0]] - - [grid.metric] - metric = "kerr_schild" - qsph_r0 = 0.0 - qsph_h = 0.0 - ks_a = 0.0 - - [grid.boundaries] - fields = [["ABSORB"]] - particles = [["ABSORB"]] - - [grid.boundaries.absorb] - ds = 2.0 - -[scales] - larmor0 = 2.0 - skindepth0 = 2.0 - -[algorithms] - current_filters = 4 - - [algorithms.gr] - pusher_niter = 10 - pusher_eps = 1e-6 - - [algorithms.timestep] - CFL = 0.5 - - [algorithms.toggles] - deposit = true - fieldsolver = true - -[particles] - ppc0 = 1.0 - - [[particles.species]] - label = "e-" - mass = 1.0 - charge = -1.0 - maxnpart = 1e0 - - [[particles.species]] - label = "e+" - mass = 1.0 - charge = 1.0 - maxnpart = 1e0 - -[setup] - x1s = [17.00000] - y1s = [1.570796] - z1s = [0.000000] - ux1s = [8.000000] - uy1s = [0.000000] - uz1s = [0.000000] - - x2s = [17.00000] - y2s = [1.570796] - z2s = [0.000000] - ux2s = [-8.000000] - uy2s = [0.000000] - uz2s = [0.000000] - -[output] - format = "hdf5" - - [output.fields] - enable = true - interval_time = 0.5 - quantities = ["D", "B"] - - [output.particles] - enable = true - stride = 1 - interval_time = 0.5 - species = [] - - [output.spectra] - enable = false - -[diagnostics] - interval = 10 - colored_stdout = true - blocking_timers = true From 44668406af783d1e05033a669feb39d654be67b1 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Wed, 18 Dec 2024 15:58:12 -0500 Subject: [PATCH 196/773] communication should be for j0 for GRPIC --- src/framework/domain/communications.cpp | 73 ++++++++++++++++++------- 1 file changed, 54 insertions(+), 19 deletions(-) diff --git a/src/framework/domain/communications.cpp b/src/framework/domain/communications.cpp index 60524eedd..65eb603c9 100644 --- a/src/framework/domain/communications.cpp +++ b/src/framework/domain/communications.cpp @@ -300,11 +300,10 @@ namespace ntt { comp_range_fld, false); } - } - if (comm_j) { + if (comm_j) { comm::CommunicateField(domain.index(), - domain.fields.cur, - domain.fields.cur, + domain.fields.cur0, + domain.fields.cur0, send_ind, recv_ind, send_rank, @@ -313,6 +312,21 @@ namespace ntt { recv_slice, comp_range_cur, false); + } + } else { + if (comm_j) { + comm::CommunicateField(domain.index(), + domain.fields.cur, + domain.fields.cur, + send_ind, + recv_ind, + send_rank, + recv_rank, + send_slice, + recv_slice, + comp_range_cur, + false); + } } } } @@ -432,17 +446,31 @@ namespace ntt { continue; } if (comm_j) { - comm::CommunicateField(domain.index(), - domain.fields.cur, - domain.fields.buff, - send_ind, - recv_ind, - send_rank, - recv_rank, - send_slice, - recv_slice, - comp_range_cur, - synchronize); + if constexpr (S == SimEngine::GRPIC) { + comm::CommunicateField(domain.index(), + domain.fields.cur0, + domain.fields.buff, + send_ind, + recv_ind, + send_rank, + recv_rank, + send_slice, + recv_slice, + comp_range_cur, + synchronize); + } else { + comm::CommunicateField(domain.index(), + domain.fields.cur, + domain.fields.buff, + send_ind, + recv_ind, + send_rank, + recv_rank, + send_slice, + recv_slice, + comp_range_cur, + synchronize); + } } if (comm_bckp) { comm::CommunicateField(domain.index(), @@ -472,10 +500,17 @@ namespace ntt { } } if (comm_j) { - AddBufferedFields(domain.fields.cur, - domain.fields.buff, - domain.mesh.rangeActiveCells(), - comp_range_cur); + if constexpr (S == SimEngine::GRPIC) { + AddBufferedFields(domain.fields.cur0, + domain.fields.buff, + domain.mesh.rangeActiveCells(), + comp_range_cur); + } else { + AddBufferedFields(domain.fields.cur, + domain.fields.buff, + domain.mesh.rangeActiveCells(), + comp_range_cur); + } } if (comm_bckp) { AddBufferedFields(domain.fields.bckp, From ef835907e620a3682671af118ac6a4ddbf8e9ced Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Wed, 18 Dec 2024 15:59:21 -0500 Subject: [PATCH 197/773] 1. implemented working boundary conditions for currents, 2. fixed normaliation for AmpereCurrents -- currents should not be normilized as they are used repeatedl3. minor style --- src/engines/grpic.hpp | 22 +++++++++++----------- src/kernels/fields_bcs.hpp | 11 +++++------ 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index 01a61118e..7ce584680 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -373,9 +373,9 @@ namespace ntt { m_metadomain.CommunicateFields(dom, Comm::J); timers.stop("Communications"); - // timers.start("FieldBoundaries"); - // CurrentsBoundaryConditions(); - // timers.stop("FieldBoundaries"); + timers.start("FieldBoundaries"); + CurrentsBoundaryConditions(dom); + timers.stop("FieldBoundaries"); timers.start("CurrentFiltering"); CurrentsFilter(dom); @@ -659,9 +659,9 @@ namespace ntt { "AbsorbCurrent", CreateRangePolicy(range_min, range_max), kernel::AbsorbCurrentGR_kernel(domain.fields.cur0, - domain.mesh.metric, - xg_edge, - ds)); + domain.mesh.metric, + xg_edge, + ds)); } void OpenFieldsIn(dir::direction_t direction, @@ -917,7 +917,7 @@ namespace ntt { const auto q0 = m_params.template get("scales.q0"); const auto n0 = m_params.template get("scales.n0"); const auto B0 = m_params.template get("scales.B0"); - const auto coeff = -dt * q0 * n0 / B0; + const auto coeff = -dt * q0 / B0; // auto range = range_with_axis_BCs(domain); auto range = CreateRangePolicy( { domain.mesh.i_min(in::x1), domain.mesh.i_min(in::x2)}, @@ -967,7 +967,7 @@ namespace ntt { } void CurrentsDeposit(domain_t& domain) { - auto scatter_cur = Kokkos::Experimental::create_scatter_view( + auto scatter_cur0 = Kokkos::Experimental::create_scatter_view( domain.fields.cur0); for (auto& species : domain.species) { logger::Checkpoint( @@ -983,7 +983,7 @@ namespace ntt { Kokkos::parallel_for("CurrentsDeposit", species.rangeActiveParticles(), kernel::DepositCurrents_kernel( - scatter_cur, + scatter_cur0, species.i1, species.i2, species.i3, @@ -1006,7 +1006,7 @@ namespace ntt { (real_t)(species.charge()), dt)); } - Kokkos::Experimental::contribute(domain.fields.cur0, scatter_cur); + Kokkos::Experimental::contribute(domain.fields.cur0, scatter_cur0); } void CurrentsFilter(domain_t& domain) { @@ -1030,7 +1030,7 @@ namespace ntt { domain.fields.buff, size, domain.mesh.flds_bc())); - m_metadomain.CommunicateFields(domain, Comm::J); + m_metadomain.CommunicateFields(domain, Comm::J); //J0 } } diff --git a/src/kernels/fields_bcs.hpp b/src/kernels/fields_bcs.hpp index 34f4ac887..445e0be74 100644 --- a/src/kernels/fields_bcs.hpp +++ b/src/kernels/fields_bcs.hpp @@ -665,18 +665,15 @@ template const M metric; const real_t xg_edge; const real_t dx_abs; - const BCTags tags; AbsorbCurrentGR_kernel(ndfield_t J, const M& metric, real_t xg_edge, - real_t dx_abs, - BCTags tags) + real_t dx_abs) : J { J } , metric { metric } , xg_edge { xg_edge } - , dx_abs { dx_abs } - , tags { tags } {} + , dx_abs { dx_abs } {} Inline void operator()(index_t i1, index_t i2) const { if constexpr (M::Dim == Dim::_2D) { @@ -687,7 +684,9 @@ template x_Cd[1] = i2_; const auto dx = math::abs( metric.template convert(x_Cd[i - 1]) - xg_edge); - J(i1, i2) *= math::tanh(dx / (INV_4 * dx_abs)); + J(i1, i2, 0) *= math::tanh(dx / (INV_4 * dx_abs)); + J(i1, i2, 1) *= math::tanh(dx / (INV_4 * dx_abs)); + J(i1, i2, 2) *= math::tanh(dx / (INV_4 * dx_abs)); } else { raise::KernelError( From 03c0af14219de6d97e94172b757ad49cd64caf2d Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Wed, 18 Dec 2024 16:03:25 -0500 Subject: [PATCH 198/773] improved setup for deposit testing --- setups/grpic/deposit/deposit.py | 53 +++++++++++++++++++++ setups/grpic/deposit/deposit.toml | 12 ++--- setups/grpic/deposit/pgen.hpp | 79 ++++++++++++++++++------------- 3 files changed, 104 insertions(+), 40 deletions(-) create mode 100644 setups/grpic/deposit/deposit.py diff --git a/setups/grpic/deposit/deposit.py b/setups/grpic/deposit/deposit.py new file mode 100644 index 000000000..e3aa97dfc --- /dev/null +++ b/setups/grpic/deposit/deposit.py @@ -0,0 +1,53 @@ +import nt2.read as nt2r +import matplotlib as mpl +import matplotlib.pyplot as plt +import numpy as np + +data = nt2r.Data("deposit.h5") +def frame(ti): + t0 = data.t.isel(t=ti).values[()] + vmax = 1e-5 + fig, ax = plt.subplots(figsize=(6, 8), dpi=150) + data.Dr.isel(t=ti).polar.pcolor( + ax=ax, + norm=mpl.colors.SymLogNorm( + vmin=-vmax, vmax=vmax, linthresh=vmax / 1e3, linscale=1 + ), + cmap="RdBu_r", + ) + x1, x2 = data.particles[1].isel(t=ti).r * np.sin( + data.particles[1].isel(t=ti).th + ), data.particles[1].isel(t=ti).r * np.cos(data.particles[1].isel(t=ti).th) + ax.scatter(x1, x2, s=5, c="b", ec="w", lw=0.5) + x1, x2 = data.particles[2].isel(t=ti).r * np.sin( + data.particles[2].isel(t=ti).th + ), data.particles[2].isel(t=ti).r * np.cos(data.particles[2].isel(t=ti).th) + ax.scatter(x1, x2, s=5, c="r", ec="w", lw=0.5) + ax.add_artist( + mpl.patches.Arc( + (0, 0), + 2 * 10, + 2 * 10, + fill=False, + ec="k", + ls=":", + lw=0.5, + theta1=-90, + theta2=90, + ) + ) + axins = ax.inset_axes([0.4, 0.8, 0.6 - 0.025, 0.2 - 0.01]) + ( + data.Dr.sel(t=slice(data.t.min(), t0)).sel(r=10, method="nearest") + * np.sin(data.th) + ).sum(dim="th").plot(ax=axins) + axins.set( + ylim=(-3 * vmax, 3 * vmax), + xlim=(data.t.min(), data.t.max()), + title="", + ylabel=rf"$\int D_r d\Omega$ @ (r = 10)", + ) + axins.axvline(t0, color="b", lw=0.5, ls=":") + axins.axhline(0, color="r", lw=0.5, ls="--") + +frame(30) \ No newline at end of file diff --git a/setups/grpic/deposit/deposit.toml b/setups/grpic/deposit/deposit.toml index 359d4eaa7..c577f9c68 100644 --- a/setups/grpic/deposit/deposit.toml +++ b/setups/grpic/deposit/deposit.toml @@ -1,7 +1,7 @@ [simulation] name = "deposit" engine = "grpic" - runtime = 10.0 + runtime = 50.0 [grid] resolution = [512,512] @@ -21,8 +21,8 @@ ds = 2.0 [scales] - larmor0 = 2.0 - skindepth0 = 2.0 + larmor0 = 2e-3 + skindepth0 = 0.1 [algorithms] current_filters = 4 @@ -57,14 +57,14 @@ x1s = [17.00000] y1s = [1.570796] z1s = [0.000000] - ux1s = [8.000000] + ux1s = [5.000000] uy1s = [0.000000] uz1s = [0.000000] x2s = [17.00000] y2s = [1.570796] z2s = [0.000000] - ux2s = [-8.000000] + ux2s = [-5.000000] uy2s = [0.000000] uz2s = [0.000000] @@ -74,7 +74,7 @@ [output.fields] enable = true interval_time = 0.5 - quantities = ["D", "B"] + quantities = ["D"] [output.particles] enable = true diff --git a/setups/grpic/deposit/pgen.hpp b/setups/grpic/deposit/pgen.hpp index 6d5e5fba5..8ff89fa92 100644 --- a/setups/grpic/deposit/pgen.hpp +++ b/setups/grpic/deposit/pgen.hpp @@ -26,43 +26,12 @@ namespace user { struct InitFields { InitFields(M metric_) : metric { metric_ } {} - Inline auto A_3(const coord_t& x_Cd) const -> real_t { - coord_t x_Ph { ZERO }; - metric.template convert(x_Cd, x_Ph); - return HALF * SQR(x_Ph[0]) * SQR(math::sin(x_Ph[1])); - } - Inline auto bx1(const coord_t& x_Ph) const -> real_t { - coord_t xi {ZERO}, x0m { ZERO }, x0p { ZERO }; - metric.template convert(x_Ph, xi); - - x0m[0] = xi[0]; - x0m[1] = xi[1] - HALF; - x0p[0] = xi[0]; - x0p[1] = xi[1] + HALF; - - real_t inv_sqrt_detH_ijP { ONE / metric.sqrt_det_h({ xi[0], xi[1] }) }; - - if (cmp::AlmostZero(x_Ph[1])) - return ONE; - else - return (A_3(x0p) - A_3(x0m)) * inv_sqrt_detH_ijP; + return ZERO; } Inline auto bx2(const coord_t& x_Ph) const -> real_t { - coord_t xi {ZERO}, x0m { ZERO }, x0p { ZERO }; - metric.template convert(x_Ph, xi); - - x0m[0] = xi[0] - HALF; - x0m[1] = xi[1]; - x0p[0] = xi[0] + HALF; - x0p[1] = xi[1]; - - real_t inv_sqrt_detH_ijP { ONE / metric.sqrt_det_h({ xi[0], xi[1] }) }; - if (cmp::AlmostZero(x_Ph[1])) - return ZERO; - else - return -(A_3(x0p) - A_3(x0m)) * inv_sqrt_detH_ijP; + return ZERO; } Inline auto bx3(const coord_t& x_Ph) const -> real_t { @@ -105,7 +74,49 @@ namespace user { : arch::ProblemGenerator { p } , global_domain { m } , init_flds { m.mesh().metric } {} - + + inline void InitPrtls(Domain& local_domain) { + const auto empty = std::vector {}; + const auto x1s = params.template get>("setup.x1s", empty); + const auto y1s = params.template get>("setup.y1s", empty); + const auto z1s = params.template get>("setup.z1s", empty); + const auto ux1s = params.template get>("setup.ux1s", + empty); + const auto uy1s = params.template get>("setup.uy1s", + empty); + const auto uz1s = params.template get>("setup.uz1s", + empty); + + const auto x2s = params.template get>("setup.x2s", empty); + const auto y2s = params.template get>("setup.y2s", empty); + const auto z2s = params.template get>("setup.z2s", empty); + const auto ux2s = params.template get>("setup.ux2s", + empty); + const auto uy2s = params.template get>("setup.uy2s", + empty); + const auto uz2s = params.template get>("setup.uz2s", + empty); + const std::map> data_1 { + { "x1", x1s}, + { "x2", y1s}, + { "phi", z1s}, + {"ux1", ux1s}, + {"ux2", uy1s}, + {"ux3", uz1s} + }; + const std::map> data_2 { + { "x1", x2s}, + { "x2", y2s}, + { "phi", z2s}, + {"ux1", ux2s}, + {"ux2", uy2s}, + {"ux3", uz2s} + }; + + arch::InjectGlobally(global_domain, local_domain, (arch::spidx_t)1, data_1); + arch::InjectGlobally(global_domain, local_domain, (arch::spidx_t)2, data_2); + } + // inline PGen() {} }; } // namespace user From d6a325b3251e414331f89d85eba0ad061fb07bfe Mon Sep 17 00:00:00 2001 From: Siddhant Solanki Date: Thu, 19 Dec 2024 15:14:43 -0500 Subject: [PATCH 199/773] changed comms to dispatch arrays of same type in one buffer --- src/framework/domain/comm_mpi.hpp | 619 +++++++++++++++--------- src/framework/domain/communications.cpp | 433 ++++++++--------- 2 files changed, 593 insertions(+), 459 deletions(-) diff --git a/src/framework/domain/comm_mpi.hpp b/src/framework/domain/comm_mpi.hpp index d7d19c983..66ea17d23 100644 --- a/src/framework/domain/comm_mpi.hpp +++ b/src/framework/domain/comm_mpi.hpp @@ -14,6 +14,7 @@ #include "enums.h" #include "global.h" +#include "arch/directions.h" #include "arch/kokkos_aliases.h" #include "arch/mpi_aliases.h" #include "utils/error.h" @@ -296,8 +297,8 @@ namespace comm { int recv_rank, const range_tuple_t& send_slice, const range_tuple_t& recv_slice) { - // auto array_h = Kokkos::create_mirror_view(arr); - // Kokkos::deep_copy(array, arr); + //auto arr_h = Kokkos::create_mirror_view(arr); + //Kokkos::deep_copy(arr_h, arr); const std::size_t send_count = send_slice.second - send_slice.first; const std::size_t recv_count = recv_slice.second - recv_slice.first; if ((send_rank >= 0) and (recv_rank >= 0) and (send_count > 0) and @@ -331,7 +332,7 @@ namespace comm { MPI_STATUS_IGNORE); } // if ((recv_rank >= 0) and (recv_count > 0)) { - // Kokkos::deep_copy(arr, array_h); + // Kokkos::deep_copy(arr, arr_h); // } } @@ -458,256 +459,398 @@ namespace comm { return recv_count; } - template - void CommunicateParticleQuantityBuffer(array_t& arr, - int send_rank, - int recv_rank, - const range_tuple_t& send_slice, - const range_tuple_t& recv_slice, - Kokkos::View indices_to_send, - Kokkos::View indices_to_allocate) { - - array_t buffer("buffer", - indices_to_send.extent(0) + indices_to_allocate.extent(0)); - // Populate the buffer for particle array - Kokkos::parallel_for( - "PopulateBuffer", - indices_to_send.extent(0), - Lambda(const size_t i) { buffer(i) = arr(indices_to_send(i)); }); - CommunicateParticleQuantity(buffer, send_rank, recv_rank, send_slice, recv_slice); - // Populate from buffer to the particle array - Kokkos::parallel_for( - "PopulateFromBuffer", - indices_to_allocate.extent(0), - Lambda(const size_t i) { - arr(indices_to_allocate(i)) = buffer(indices_to_send.extent(0) + i); - }); - return; - } template - void CommunicateParticlesBuffer(Particles& species, - Kokkos::View indices_to_send, - Kokkos::View indices_to_allocate, - int send_rank, - int recv_rank, - std::vector shifts_in_x) { - if ((send_rank < 0) && (recv_rank < 0)) { - raise::Error("No send or recv in SendRecvParticlesBuffered", HERE); - } - // First set the tags of the sent particles to be dead - auto& this_tag = species.tag; - // Kokkos::parallel_for( - //"SetTagDead", - // Kokkos::RangePolicy(0, indices_to_allocate.size()), - // KOKKOS_LAMBDA(const size_t i) { - // const auto idx = indices_to_send(i); - // this_tag(idx) = static_cast(ParticleTag::dead); - // }); - - // Construct send and receive slice for the buffer - auto send_slice = range_tuple_t({ 0, indices_to_send.size() }); - auto recv_slice = range_tuple_t( - { indices_to_send.size(), - indices_to_send.size() + indices_to_allocate.size() }); - // Send and receive the particles - CommunicateParticleQuantityBuffer(species.i1, - send_rank, - recv_rank, - send_slice, - recv_slice, - indices_to_send, - indices_to_allocate); - CommunicateParticleQuantityBuffer(species.dx1, - send_rank, - recv_rank, - send_slice, - recv_slice, - indices_to_send, - indices_to_allocate); - CommunicateParticleQuantityBuffer(species.i1_prev, - send_rank, - recv_rank, - send_slice, - recv_slice, - indices_to_send, - indices_to_allocate); - CommunicateParticleQuantityBuffer(species.dx1_prev, - send_rank, - recv_rank, - send_slice, - recv_slice, - indices_to_send, - indices_to_allocate); - if constexpr (D == Dim::_2D || D == Dim::_3D) { - CommunicateParticleQuantityBuffer(species.i2, - send_rank, - recv_rank, - send_slice, - recv_slice, - indices_to_send, - indices_to_allocate); - CommunicateParticleQuantityBuffer(species.dx2, - send_rank, - recv_rank, - send_slice, - recv_slice, - indices_to_send, - indices_to_allocate); - CommunicateParticleQuantityBuffer(species.i2_prev, - send_rank, - recv_rank, - send_slice, - recv_slice, - indices_to_send, - indices_to_allocate); - CommunicateParticleQuantityBuffer(species.dx2_prev, - send_rank, - recv_rank, - send_slice, - recv_slice, - indices_to_send, - indices_to_allocate); + void CommunicateParticlesBuffer(Particles& species, + Kokkos::View permute_vector, + Kokkos::View allocation_vector, + Kokkos::View tag_offset, + std::vector npart_per_tag_arr, + std::vector npart_per_tag_arr_recv, + std::vector send_ranks, + std::vector recv_ranks) { + // Pointers to the particle data arrays + auto &this_ux1 = species.ux1; + auto &this_ux2 = species.ux2; + auto &this_ux3 = species.ux3; + auto &this_weight = species.weight; + auto &this_phi = species.phi; + auto &this_i1 = species.i1; + auto &this_i1_prev = species.i1_prev; + auto &this_i2 = species.i2; + auto &this_i3 = species.i3; + auto &this_i2_prev = species.i2_prev; + auto &this_i3_prev = species.i3_prev; + auto &this_dx1 = species.dx1; + auto &this_dx1_prev = species.dx1_prev; + auto &this_dx2 = species.dx2; + auto &this_dx3 = species.dx3; + auto &this_dx2_prev = species.dx2_prev; + auto &this_dx3_prev = species.dx3_prev; + auto &this_tag = species.tag; + + // Number of arrays of each type to send/recv + auto NREALS = 4; + auto NINTS = 2; + auto NFLOATS = 2; + if constexpr (D == Dim::_2D) { + this_i2 = species.i2; + this_i2_prev = species.i2_prev; + this_dx2 = species.dx2; + this_dx2_prev = species.dx2_prev; + if (C != Coord::Cart) { + NREALS = 5; + NINTS = 4; + NFLOATS = 4; + this_phi = species.phi; + } else { + NREALS = 4; + NINTS = 4; + NFLOATS = 4; + } } if constexpr (D == Dim::_3D) { - CommunicateParticleQuantityBuffer(species.i3, - send_rank, - recv_rank, - send_slice, - recv_slice, - indices_to_send, - indices_to_allocate); - CommunicateParticleQuantityBuffer(species.dx3, - send_rank, - recv_rank, - send_slice, - recv_slice, - indices_to_send, - indices_to_allocate); - CommunicateParticleQuantityBuffer(species.i3_prev, - send_rank, - recv_rank, - send_slice, - recv_slice, - indices_to_send, - indices_to_allocate); - CommunicateParticleQuantityBuffer(species.dx3_prev, - send_rank, - recv_rank, - send_slice, - recv_slice, - indices_to_send, - indices_to_allocate); + this_i2 = species.i2; + this_i2_prev = species.i2_prev; + this_dx2 = species.dx2; + this_dx2_prev = species.dx2_prev; + this_i3 = species.i3; + this_i3_prev = species.i3_prev; + this_dx3 = species.dx3; + this_dx3_prev = species.dx3_prev; + NREALS = 4; + NINTS = 6; + NFLOATS = 6; } - CommunicateParticleQuantityBuffer(species.ux1, - send_rank, - recv_rank, - send_slice, - recv_slice, - indices_to_send, - indices_to_allocate); - CommunicateParticleQuantityBuffer(species.ux2, - send_rank, - recv_rank, - send_slice, - recv_slice, - indices_to_send, - indices_to_allocate); - CommunicateParticleQuantityBuffer(species.ux3, - send_rank, - recv_rank, - send_slice, - recv_slice, - indices_to_send, - indices_to_allocate); - CommunicateParticleQuantityBuffer(species.weight, - send_rank, - recv_rank, - send_slice, - recv_slice, - indices_to_send, - indices_to_allocate); - if constexpr (D == Dim::_2D and C != Coord::Cart) { - CommunicateParticleQuantityBuffer(species.phi, - send_rank, - recv_rank, - send_slice, - recv_slice, - indices_to_send, - indices_to_allocate); - } - for (auto p { 0 }; p < species.npld(); ++p) { - CommunicateParticleQuantityBuffer(species.pld[p], - send_rank, - recv_rank, - send_slice, - recv_slice, - indices_to_send, - indices_to_allocate); + + // Now make buffers to store recevied data (don't need global send buffers) + const auto total_send = permute_vector.extent(0) - npart_per_tag_arr[ParticleTag::dead]; + const auto total_recv = allocation_vector.extent(0); + const auto n_alive = npart_per_tag_arr[ParticleTag::alive]; + const auto n_dead = npart_per_tag_arr[ParticleTag::dead]; + + /* + Brief on recv buffers: Each recv buffer contains all the received arrays of + a given type. The different physical quantities are stored next to each other + to avoid cache misses. The array is structured as follows: + E.g., + recv_buffer_int: | qty1 | qty2 | ... | qtyNINTS | qty1 | qty2 | ... | qtyNINTS | ... + <-------particle to recv1------> <-------particle to recv2--------> + <----------------------------------total_recv----------------------------> + */ + Kokkos::View recv_buffer_int("recv_buffer_int", total_recv * NINTS); + Kokkos::View recv_buffer_real("recv_buffer_real", total_recv * NREALS); + Kokkos::View recv_buffer_prtldx("recv_buffer_prtldx",total_recv * NFLOATS); + auto recv_buffer_int_h = Kokkos::create_mirror_view(recv_buffer_int); + auto recv_buffer_real_h = Kokkos::create_mirror_view(recv_buffer_real); + auto recv_buffer_prtldx_h = Kokkos::create_mirror_view(recv_buffer_prtldx); + + + auto iteration = 0; + auto current_received = 0; + for (auto& direction : dir::Directions::all) { + const auto send_rank = send_ranks[iteration]; + const auto recv_rank = recv_ranks[iteration]; + const auto tag_send = mpi::PrtlSendTag::dir2tag(direction); + const auto tag_recv = mpi::PrtlSendTag::dir2tag(-direction); + const auto send_count = npart_per_tag_arr[tag_send]; + const auto recv_count = npart_per_tag_arr_recv[tag_recv]; + if (send_rank < 0 and recv_rank < 0) { + continue; + } + Kokkos::View send_buffer_int("send_buffer_int", send_count * NINTS); + Kokkos::View send_buffer_real("send_buffer_real", send_count * NREALS); + Kokkos::View send_buffer_prtldx("send_buffer_prtldx",send_count * NFLOATS); + auto send_buffer_int_h = Kokkos::create_mirror_view(send_buffer_int); + auto send_buffer_real_h = Kokkos::create_mirror_view(send_buffer_real); + auto send_buffer_prtldx_h = Kokkos::create_mirror_view(send_buffer_prtldx); + + // Need different constexpr parallel fors for different dims + if constexpr(D == Dim::_1D) { + Kokkos::parallel_for( + "PopulateSendBuffer", + send_count, + Lambda(const std::size_t p){ + const auto idx = permute_vector(tag_offset(tag_send) - n_alive + p); + send_buffer_int(NINTS * p + 0) = this_i1(idx); + send_buffer_int(NINTS * p + 1) = this_i1_prev(idx); + send_buffer_real(NREALS * p + 0) = this_ux1(idx); + send_buffer_real(NREALS * p + 1) = this_ux2(idx); + send_buffer_real(NREALS * p + 2) = this_ux3(idx); + send_buffer_real(NREALS * p + 3) = this_weight(idx); + send_buffer_prtldx(NFLOATS * p + 0) = this_dx1(idx); + send_buffer_prtldx(NFLOATS * p + 1) = this_dx1_prev(idx); + }); + } + if constexpr(D == Dim::_2D && C == Coord::Cart) { + Kokkos::parallel_for( + "PopulateSendBuffer", + send_count, + Lambda(const std::size_t p){ + const auto idx = permute_vector(tag_offset(tag_send) - n_alive + p); + send_buffer_int(NINTS * p + 0) = this_i1(idx); + send_buffer_int(NINTS * p + 1) = this_i1_prev(idx); + send_buffer_int(NINTS * p + 2) = this_i2(idx); + send_buffer_int(NINTS * p + 3) = this_i2_prev(idx); + send_buffer_real(NREALS * p + 0) = this_ux1(idx); + send_buffer_real(NREALS * p + 1) = this_ux2(idx); + send_buffer_real(NREALS * p + 2) = this_ux3(idx); + send_buffer_real(NREALS * p + 3) = this_weight(idx); + send_buffer_prtldx(NFLOATS * p + 0) = this_dx1(idx); + send_buffer_prtldx(NFLOATS * p + 1) = this_dx1_prev(idx); + send_buffer_prtldx(NFLOATS * p + 2) = this_dx2(idx); + send_buffer_prtldx(NFLOATS * p + 3) = this_dx2_prev(idx); + }); + } + if constexpr(D == Dim::_2D && C != Coord::Cart) { + Kokkos::parallel_for( + "PopulateSendBuffer", + send_count, + Lambda(const std::size_t p){ + const auto idx = permute_vector(tag_offset(tag_send) - n_alive + p); + send_buffer_int(NINTS * p + 0) = this_i1(idx); + send_buffer_int(NINTS * p + 1) = this_i1_prev(idx); + send_buffer_int(NINTS * p + 2) = this_i2(idx); + send_buffer_int(NINTS * p + 3) = this_i2_prev(idx); + send_buffer_real(NREALS * p + 0) = this_ux1(idx); + send_buffer_real(NREALS * p + 1) = this_ux2(idx); + send_buffer_real(NREALS * p + 2) = this_ux3(idx); + send_buffer_real(NREALS * p + 3) = this_weight(idx); + send_buffer_real(NREALS * p + 4) = this_phi(idx); + send_buffer_prtldx(NFLOATS * p + 0) = this_dx1(idx); + send_buffer_prtldx(NFLOATS * p + 1) = this_dx1_prev(idx); + send_buffer_prtldx(NFLOATS * p + 2) = this_dx2(idx); + send_buffer_prtldx(NFLOATS * p + 3) = this_dx2_prev(idx); + }); + } + if constexpr(D == Dim::_3D) { + Kokkos::parallel_for( + "PopulateSendBuffer", + send_count, + Lambda(const std::size_t p){ + const auto idx = permute_vector(tag_offset(tag_send) - n_alive + p); + send_buffer_int(NINTS * p + 0) = this_i1(idx); + send_buffer_int(NINTS * p + 1) = this_i1_prev(idx); + send_buffer_int(NINTS * p + 2) = this_i2(idx); + send_buffer_int(NINTS * p + 3) = this_i2_prev(idx); + send_buffer_int(NINTS * p + 4) = this_i3(idx); + send_buffer_int(NINTS * p + 5) = this_i3_prev(idx); + send_buffer_real(NREALS * p + 0) = this_ux1(idx); + send_buffer_real(NREALS * p + 1) = this_ux2(idx); + send_buffer_real(NREALS * p + 2) = this_ux3(idx); + send_buffer_real(NREALS * p + 3) = this_weight(idx); + send_buffer_prtldx(NFLOATS * p + 0) = this_dx1(idx); + send_buffer_prtldx(NFLOATS * p + 1) = this_dx1_prev(idx); + send_buffer_prtldx(NFLOATS * p + 2) = this_dx2(idx); + send_buffer_prtldx(NFLOATS * p + 3) = this_dx2_prev(idx); + send_buffer_prtldx(NFLOATS * p + 4) = this_dx3(idx); + send_buffer_prtldx(NFLOATS * p + 5) = this_dx3_prev(idx); + }); + } + + auto tag_offset_h = Kokkos::create_mirror_view(tag_offset); + Kokkos::deep_copy(tag_offset_h, tag_offset); + /* + Brief on receive offset: + The receive buffer looks like this + <-----------------------------------> + |NINT|NINT|NINT|NINT|NINT|NINT|NINT|NINT|...xnrecv + <--------><--------><--------><--------> + recv1 recv2 recv3 recv4 + |________| + ^ ^ + offset offset + nrecv + */ + const auto receive_offset_int = current_received * NINTS; + const auto receive_offset_real = current_received * NREALS; + const auto receive_offset_prtldx = current_received * NFLOATS; + // Comms + // Make host arrays for send and recv buffers + Kokkos::deep_copy(send_buffer_int_h, send_buffer_int); + Kokkos::deep_copy(send_buffer_real_h, send_buffer_real); + Kokkos::deep_copy(send_buffer_prtldx_h, send_buffer_prtldx); + + if ((send_rank >= 0) and (recv_rank >= 0) and (send_count > 0) and + (recv_count > 0)) { + MPI_Sendrecv(send_buffer_int_h.data(), + send_count * NINTS, + mpi::get_type(), + send_rank, + 0, + recv_buffer_int_h.data() + receive_offset_int, + recv_count*NINTS, + mpi::get_type(), + recv_rank, + 0, + MPI_COMM_WORLD, + MPI_STATUS_IGNORE); + MPI_Sendrecv(send_buffer_real_h.data(), + send_count * NREALS, + mpi::get_type(), + send_rank, + 0, + recv_buffer_real_h.data() + receive_offset_real, + recv_count*NREALS, + mpi::get_type(), + recv_rank, + 0, + MPI_COMM_WORLD, + MPI_STATUS_IGNORE); + MPI_Sendrecv(send_buffer_prtldx_h.data(), + send_count * NFLOATS, + mpi::get_type(), + send_rank, + 0, + recv_buffer_prtldx_h.data() + receive_offset_prtldx, + recv_count*NFLOATS, + mpi::get_type(), + recv_rank, + 0, + MPI_COMM_WORLD, + MPI_STATUS_IGNORE); + } else if ((send_rank >= 0) and (send_count > 0)) { + MPI_Send(send_buffer_int_h.data(), + send_count * NINTS, + mpi::get_type(), + send_rank, + 0, + MPI_COMM_WORLD); + MPI_Send(send_buffer_real_h.data(), + send_count * NREALS, + mpi::get_type(), + send_rank, + 0, + MPI_COMM_WORLD); + MPI_Send(send_buffer_prtldx_h.data(), + send_count * NFLOATS, + mpi::get_type(), + send_rank, + 0, + MPI_COMM_WORLD); + } else if ((recv_rank >= 0) and (recv_count > 0)) { + MPI_Recv(recv_buffer_int_h.data() + receive_offset_int, + recv_count * NINTS, + mpi::get_type(), + recv_rank, + 0, + MPI_COMM_WORLD, + MPI_STATUS_IGNORE); + MPI_Recv(recv_buffer_real_h.data() + receive_offset_real, + recv_count * NREALS, + mpi::get_type(), + recv_rank, + 0, + MPI_COMM_WORLD, + MPI_STATUS_IGNORE); + MPI_Recv(recv_buffer_prtldx_h.data() + receive_offset_prtldx, + recv_count * NFLOATS, + mpi::get_type(), + recv_rank, + 0, + MPI_COMM_WORLD, + MPI_STATUS_IGNORE); } - // Set the tag for the received particles to be alive and perform the necessary displacements - if constexpr (D == Dim::_1D) { - const auto shift_in_x1 = shifts_in_x[0]; - auto& this_i1 = species.i1; - auto& this_i1_prev = species.i1_prev; + current_received += recv_count; + iteration++; + } // end over direction loop + Kokkos::deep_copy(recv_buffer_int, recv_buffer_int_h); + Kokkos::deep_copy(recv_buffer_real, recv_buffer_real_h); + Kokkos::deep_copy(recv_buffer_prtldx, recv_buffer_prtldx_h); + if constexpr (D == Dim::_1D) + { Kokkos::parallel_for( - "SetTagAlive", - Kokkos::RangePolicy(0, indices_to_allocate.size()), - KOKKOS_LAMBDA(const size_t i) { - const auto idx = indices_to_allocate(i); - this_tag(idx) = static_cast(ParticleTag::alive); - this_i1(idx) += shift_in_x1; - this_i1_prev(idx) += shift_in_x1; - }); + "PopulateFromRecvBuffer", + total_recv, + Lambda(const std::size_t p){ + auto idx = allocation_vector(p); + this_tag(idx) = ParticleTag::alive; + this_i1(idx) = recv_buffer_int(NINTS * p + 0); + this_i1_prev(idx) = recv_buffer_int(NINTS * p + 1); + this_ux1(idx) = recv_buffer_real(NREALS * p + 0); + this_ux2(idx) = recv_buffer_real(NREALS * p + 1); + this_ux3(idx) = recv_buffer_real(NREALS * p + 2); + this_weight(idx) = recv_buffer_real(NREALS * p + 3); + this_dx1(idx) = recv_buffer_prtldx(NFLOATS * p + 0); + this_dx1_prev(idx) = recv_buffer_prtldx(NFLOATS * p + 1); + }); } - else if constexpr (D == Dim::_2D) { - const auto shift_in_x1 = shifts_in_x[0]; - const auto shift_in_x2 = shifts_in_x[1]; - auto& this_i1 = species.i1; - auto& this_i2 = species.i2; - auto& this_i1_prev = species.i1_prev; - auto& this_i2_prev = species.i2_prev; + if constexpr (D == Dim::_2D && C == Coord::Cart) + { + Kokkos::parallel_for( + "PopulateFromRecvBuffer", + total_recv, + Lambda(const std::size_t p){ + auto idx = allocation_vector(p); + this_tag(idx) = ParticleTag::alive; + this_i1(idx) = recv_buffer_int(NINTS * p + 0); + this_i1_prev(idx) = recv_buffer_int(NINTS * p + 1); + this_i2(idx) = recv_buffer_int(NINTS * p + 2); + this_i2_prev(idx) = recv_buffer_int(NINTS * p + 3); + this_ux1(idx) = recv_buffer_real(NREALS * p + 0); + this_ux2(idx) = recv_buffer_real(NREALS * p + 1); + this_ux3(idx) = recv_buffer_real(NREALS * p + 2); + this_weight(idx) = recv_buffer_real(NREALS * p + 3); + this_dx1(idx) = recv_buffer_prtldx(NFLOATS * p + 0); + this_dx1_prev(idx) = recv_buffer_prtldx(NFLOATS * p + 1); + this_dx2(idx) = recv_buffer_prtldx(NFLOATS * p + 2); + this_dx2_prev(idx) = recv_buffer_prtldx(NFLOATS * p + 3); + }); + } + + if constexpr (D == Dim::_2D && C == Coord::Cart) + { Kokkos::parallel_for( - "SetTagAlive", - Kokkos::RangePolicy(0, indices_to_allocate.size()), - KOKKOS_LAMBDA(const size_t i) { - const auto idx = indices_to_allocate(i); - this_tag(idx) = static_cast(ParticleTag::alive); - this_i1(idx) += shift_in_x1; - this_i2(idx) += shift_in_x2; - this_i1_prev(idx) += shift_in_x1; - this_i2_prev(idx) += shift_in_x2; - }); + "PopulateFromRecvBuffer", + total_recv, + Lambda(const std::size_t p){ + auto idx = allocation_vector(p); + this_tag(idx) = ParticleTag::alive; + this_i1(idx) = recv_buffer_int(NINTS * p + 0); + this_i1_prev(idx) = recv_buffer_int(NINTS * p + 1); + this_i2(idx) = recv_buffer_int(NINTS * p + 2); + this_i2_prev(idx) = recv_buffer_int(NINTS * p + 3); + this_ux1(idx) = recv_buffer_real(NREALS * p + 0); + this_ux2(idx) = recv_buffer_real(NREALS * p + 1); + this_ux3(idx) = recv_buffer_real(NREALS * p + 2); + this_weight(idx) = recv_buffer_real(NREALS * p + 3); + this_phi(idx) = recv_buffer_real(NREALS * p + 4); + this_dx1(idx) = recv_buffer_prtldx(NFLOATS * p + 0); + this_dx1_prev(idx) = recv_buffer_prtldx(NFLOATS * p + 1); + this_dx2(idx) = recv_buffer_prtldx(NFLOATS * p + 2); + this_dx2_prev(idx) = recv_buffer_prtldx(NFLOATS * p + 3); + }); } - else if constexpr (D == Dim::_3D) { - const auto shift_in_x1 = shifts_in_x[0]; - const auto shift_in_x2 = shifts_in_x[1]; - const auto shift_in_x3 = shifts_in_x[2]; - auto& this_i1 = species.i1; - auto& this_i2 = species.i2; - auto& this_i3 = species.i3; - auto& this_i1_prev = species.i1_prev; - auto& this_i2_prev = species.i2_prev; - auto& this_i3_prev = species.i3_prev; + if constexpr (D == Dim::_3D) + { Kokkos::parallel_for( - "SetTagAlive", - Kokkos::RangePolicy(0, indices_to_allocate.size()), - KOKKOS_LAMBDA(const size_t i) { - const auto idx = indices_to_allocate(i); - this_tag(idx) = static_cast(ParticleTag::alive); - this_i1(idx) += shift_in_x1; - this_i2(idx) += shift_in_x2; - this_i3(idx) += shift_in_x3; - this_i1_prev(idx) += shift_in_x1; - this_i2_prev(idx) += shift_in_x2; - this_i3_prev(idx) += shift_in_x3; - }); + "PopulateFromRecvBuffer", + total_recv, + Lambda(const std::size_t p){ + auto idx = allocation_vector(p); + this_tag(idx) = ParticleTag::alive; + this_i1(idx) = recv_buffer_int(NINTS * p + 0); + this_i1_prev(idx) = recv_buffer_int(NINTS * p + 1); + this_i2(idx) = recv_buffer_int(NINTS * p + 2); + this_i2_prev(idx) = recv_buffer_int(NINTS * p + 3); + this_i3(idx) = recv_buffer_int(NINTS * p + 4); + this_i3_prev(idx) = recv_buffer_int(NINTS * p + 5); + this_ux1(idx) = recv_buffer_real(NREALS * p + 0); + this_ux2(idx) = recv_buffer_real(NREALS * p + 1); + this_ux3(idx) = recv_buffer_real(NREALS * p + 2); + this_weight(idx) = recv_buffer_real(NREALS * p + 3); + this_dx1(idx) = recv_buffer_prtldx(NFLOATS * p + 0); + this_dx1_prev(idx) = recv_buffer_prtldx(NFLOATS * p + 1); + this_dx2(idx) = recv_buffer_prtldx(NFLOATS * p + 2); + this_dx2_prev(idx) = recv_buffer_prtldx(NFLOATS * p + 3); + this_dx3(idx) = recv_buffer_prtldx(NFLOATS * p + 4); + this_dx3_prev(idx) = recv_buffer_prtldx(NFLOATS * p + 5); + }); } - Kokkos::fence(); + species.set_npart(species.npart() + std::max(total_send, total_recv) - total_send); return; - } +} } // namespace comm diff --git a/src/framework/domain/communications.cpp b/src/framework/domain/communications.cpp index 36f7a1858..cdc9e5b5a 100644 --- a/src/framework/domain/communications.cpp +++ b/src/framework/domain/communications.cpp @@ -656,7 +656,15 @@ namespace ntt { HERE); logger::Checkpoint("Communicating particles\n", HERE); for (auto& species : domain.species) { - // TO DO: npart per tag must return npart_per_tag_arr and the cumsum array + /* + Brief on arrays + npart_per_tag_arr (vector): | dead count| alive count | tag=1 count | tag=2 count | ... + <--------------------------size = ntags()--------------------------> + tag_offset (Kokkos::View): | 0 | dead count | dead + alive count | dead + alive + tag=1 count | ... + <--------------------------size = ntags()--------------------------> + npart_per_tag_arr_recv (vector): | 0 | 0 | nrecv1 | nrecv2 | ... + <--------------------------size = ntags()--------------------------> + */ auto [npart_per_tag_arr, tag_offset] = species.npart_per_tag(); auto npart = static_cast(species.npart()); @@ -665,21 +673,24 @@ namespace ntt { auto total_dead = static_cast( npart_per_tag_arr[ParticleTag::dead]); auto total_holes = static_cast(npart - total_alive); - auto total_send = static_cast(npart - total_alive - total_dead); auto total_recv = static_cast(0); - auto tag_count = static_cast(npart_per_tag_arr.size()); std::vector send_ranks, send_inds; std::vector recv_ranks, recv_inds; // at this point particles should already by tagged in the pusher #if defined(MPI_ENABLED) - // Defined for debugging - int mpi_rank; - MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); - - // array that holds the number of particles to be received per tag - std::vector npart_per_tag_arr_recv(tag_count, 0); + std::vector npart_per_tag_arr_recv(species.ntags(), 0); + Kokkos::View shifts_in_x1("shifts_in_x1", species.ntags()); + Kokkos::View shifts_in_x2("shifts_in_x2", species.ntags()); + Kokkos::View shifts_in_x3("shifts_in_x3", species.ntags()); + auto shifts_in_x1_h = Kokkos::create_mirror_view(shifts_in_x1); + auto shifts_in_x2_h = Kokkos::create_mirror_view(shifts_in_x2); + auto shifts_in_x3_h = Kokkos::create_mirror_view(shifts_in_x3); + + // Get receive counts + displacements for (auto& direction : dir::Directions::all) { + const auto tag_recv = mpi::PrtlSendTag::dir2tag(-direction); + const auto tag_send = mpi::PrtlSendTag::dir2tag(direction); const auto [send_params, recv_params] = GetSendRecvParams(this, domain, direction, true); const auto [send_indrank, send_slice] = send_params; @@ -689,253 +700,233 @@ namespace ntt { if (send_rank < 0 and recv_rank < 0) { continue; } - const auto send_dir_tag = mpi::PrtlSendTag::dir2tag(direction); - const auto nsend = npart_per_tag_arr[send_dir_tag]; + const auto nsend = npart_per_tag_arr[tag_send]; std::size_t nrecv = 0; - // Get the receive count + send_ranks.push_back(send_rank); recv_ranks.push_back(recv_rank); send_inds.push_back(send_ind); recv_inds.push_back(recv_ind); comm::ParticleSendRecvCount(send_rank, recv_rank, nsend, nrecv); total_recv += nrecv; - npart_per_tag_arr_recv[mpi::PrtlSendTag::dir2tag(-direction)] = nrecv; - } - - raise::FatalIf((npart + total_recv) >= species.maxnpart(), - "Too many particles to receive (cannot fit into maxptl)", - HERE); - // Now we know the number of particles to be sent and received per direction - /* permute vector contains the indices of the tags to send and receive - in the order of the directions - E.g., consider the following tag array - [ 0, 0, 3, 0, 1,...] - Then, permute vector will look something like - [0, 1, 3, ..., 4, ..., ... 2, ... ] - |<--------- >| |<----->| |<----->| .... - tag=0 ct tag=1 ct tag=3 ct - (dead) (alive) (tag1) ... - */ - auto& this_tag = species.tag; - Kokkos::View permute_vector("permute_vector", species.npart()); - Kokkos::View current_offset("current_offset", species.ntags()); - // @TODO: do not save tag = 1 particles into permute_vector - // instead of species.npart(), size will be species.npart() - npart_per_tag[ParticleTag::alive]; - - Kokkos::parallel_for( - "PermuteVector", - species.npart(), - Lambda(index_t p) { - const auto current_tag = this_tag(p); - const auto idx_permute_vec = tag_offset(current_tag) + - Kokkos::atomic_fetch_add( - ¤t_offset(current_tag), - 1); - permute_vector(idx_permute_vec) = p; - }); - - // Check: add the end of the loop, current_offset should be equal to npart_per_tag - auto current_offset_h = Kokkos::create_mirror_view(current_offset); - Kokkos::deep_copy(current_offset_h, current_offset); - for (std::size_t i { 0 }; i < current_offset_h.size(); ++i) { - raise::FatalIf(current_offset_h(i) != npart_per_tag_arr[i], - "Error in permute vector construction", - HERE); - } - - // allocation_vector(p) assigns the pth received particle - // to the pth hole in the array, or after npart() if p > sent+dead count. - Kokkos::View allocation_vector("allocation_vector", total_recv); - - // @CRITICAL: this may overwrite unsent data - Kokkos::parallel_for( - "AllocationVector", - total_recv, - Lambda(index_t p) { - // Case: received particle count less than dead particle count -> replace dead particles - if (p < total_dead) { - allocation_vector(p) = permute_vector(p); - } - // Case: received particle count > dead particle count but < sent particle count -> replace - // sent particles - else if (p < total_holes && p >= total_dead) { - allocation_vector(p) = permute_vector(total_alive + p); - } - // Case: received particle count exceeds sent + dead particles -> append at the end - else { - allocation_vector(p) = static_cast(npart + (p - total_holes)); - } - }); - Kokkos::fence(); + npart_per_tag_arr_recv[tag_recv] = nrecv; - std::size_t count_recv = 0; - std::size_t iteration = 0; - // Main loop over all direction where we send the data - for (auto& direction : dir::Directions::all) { - // When nowhere to send and receive - auto send_rank = send_ranks[iteration]; - auto recv_rank = recv_ranks[iteration]; - - if (send_rank < 0 and recv_rank < 0) { - continue; - } - // Get the coordinate shifts in xi - std::vector shifts_in_x; - auto recv_ind = recv_inds[iteration]; + // @CRITICAL: Ask Hayk if the displacements are correctly set before sending if constexpr (D == Dim::_1D) { - int shift_in_x1 { 0 }; if ((-direction)[0] == -1) { - shift_in_x1 = -subdomain(recv_ind).mesh.n_active(in::x1); + shifts_in_x1_h(tag_send) = -subdomain(recv_ind).mesh.n_active(in::x1); } else if ((-direction)[0] == 1) { - shift_in_x1 = domain.mesh.n_active(in::x1); + shifts_in_x1_h(tag_send) = domain.mesh.n_active(in::x1); } - shifts_in_x.push_back(shift_in_x1); } else if constexpr (D == Dim::_2D) { - int shift_in_x1 { 0 }, shift_in_x2 { 0 }; if ((-direction)[0] == -1) { - shift_in_x1 = -subdomain(recv_ind).mesh.n_active(in::x1); + shifts_in_x1_h(tag_send) = -subdomain(recv_ind).mesh.n_active(in::x1); } else if ((-direction)[0] == 1) { - shift_in_x1 = domain.mesh.n_active()[0]; + shifts_in_x1_h(tag_send) = domain.mesh.n_active()[0]; } if ((-direction)[1] == -1) { - shift_in_x2 = -subdomain(recv_ind).mesh.n_active(in::x2); + shifts_in_x2_h(tag_send) = -subdomain(recv_ind).mesh.n_active(in::x2); } else if ((-direction)[1] == 1) { - shift_in_x2 = domain.mesh.n_active(in::x2); + shifts_in_x2_h(tag_send) = domain.mesh.n_active(in::x2); } - shifts_in_x.push_back(shift_in_x1); - shifts_in_x.push_back(shift_in_x2); } else if constexpr (D == Dim::_3D) { - int shift_in_x1 { 0 }, shift_in_x2 { 0 }, shift_in_x3 { 0 }; if ((-direction)[0] == -1) { - shift_in_x1 = -subdomain(recv_ind).mesh.n_active(in::x1); + shifts_in_x1_h(tag_send) = -subdomain(recv_ind).mesh.n_active(in::x1); } else if ((-direction)[0] == 1) { - shift_in_x1 = domain.mesh.n_active(in::x1); + shifts_in_x1_h(tag_send) = domain.mesh.n_active(in::x1); } if ((-direction)[1] == -1) { - shift_in_x2 = -subdomain(recv_ind).mesh.n_active(in::x2); + shifts_in_x2_h(tag_send) = -subdomain(recv_ind).mesh.n_active(in::x2); } else if ((-direction)[1] == 1) { - shift_in_x2 = domain.mesh.n_active(in::x2); + shifts_in_x2_h(tag_send) = domain.mesh.n_active(in::x2); } if ((-direction)[2] == -1) { - shift_in_x3 = -subdomain(recv_ind).mesh.n_active(in::x3); + shifts_in_x3_h(tag_send) = -subdomain(recv_ind).mesh.n_active(in::x3); } else if ((-direction)[2] == 1) { - shift_in_x3 = domain.mesh.n_active(in::x3); + shifts_in_x3_h(tag_send) = domain.mesh.n_active(in::x3); } - shifts_in_x.push_back(shift_in_x1); - shifts_in_x.push_back(shift_in_x2); - shifts_in_x.push_back(shift_in_x3); } + } // end directions loop + Kokkos::deep_copy(shifts_in_x1, shifts_in_x1_h); + Kokkos::deep_copy(shifts_in_x2, shifts_in_x2_h); + Kokkos::deep_copy(shifts_in_x3, shifts_in_x3_h); - // Tuple that contains the start and end indices of permtute_vec pointing to a given tag type = dir2tag(dir) - auto tag_offset_h = Kokkos::create_mirror_view(tag_offset); - Kokkos::deep_copy(tag_offset_h, tag_offset); - auto range_permute = std::make_pair( - static_cast( - tag_offset_h[mpi::PrtlSendTag::dir2tag(direction)]), - static_cast( - tag_offset_h[mpi::PrtlSendTag::dir2tag(direction)] + - npart_per_tag_arr[mpi::PrtlSendTag::dir2tag(direction)])); - // Tuple that contains the start and end indices for allocation_vector pointing to a given tag type = dir2tag(dir) - auto range_allocate = std::make_pair( - static_cast(count_recv), - static_cast( - count_recv + - npart_per_tag_arr_recv[mpi::PrtlSendTag::dir2tag(-direction)])); - // @TODO: check subview index - // contains the indices of all particles of a given tag = mpi::PrtlSendTag::dir2tag(direction) - auto indices_to_send = Kokkos::subview(permute_vector, range_permute); - // contains the indices of the holes where the received particles will be placed - auto indices_to_allocate = Kokkos::subview(allocation_vector, - range_allocate); - - // Main function that sends the particles and receives the arrays - comm::CommunicateParticlesBuffer(species, - indices_to_send, - indices_to_allocate, - send_rank, - recv_rank, - shifts_in_x); - count_recv += npart_per_tag_arr_recv[mpi::PrtlSendTag::dir2tag(-direction)]; - iteration++; + raise::FatalIf((npart + total_recv) >= species.maxnpart(), + "Too many particles to receive (cannot fit into maxptl)", + HERE); + + auto& this_tag = species.tag; + auto& this_i1 = species.i1; + auto& this_i1_prev = species.i1_prev; + auto& this_i2 = species.i2; + auto& this_i2_prev = species.i2_prev; + auto& this_i3 = species.i3; + auto& this_i3_prev = species.i3_prev; + + /* + Brief on permute vector: It contains the sorted indices of tag != alive particles + E.g., consider the following tag array + species.tag = [ 0, 0, 3, 0, 1, 2,...] + Then, permute vector will look something like + permute_vector = [0, 1, 3, ..., 4, ..., ... 5, ... ] + |<--------- >| |<----->| |<----->| .... + tag=0 ct tag=1 ct tag=2 ct + */ + Kokkos::View permute_vector("permute_vector", total_holes); + Kokkos::View current_offset("current_offset", species.ntags()); + auto &this_tag_offset = tag_offset; + + auto n_alive = npart_per_tag_arr[ParticleTag::alive]; + + if constexpr (D == Dim::_1D){ + Kokkos::parallel_for( + "PermuteVector and Displace", + species.npart(), + Lambda(index_t p) { + const auto current_tag = this_tag(p); + if (current_tag != ParticleTag::alive){ + // dead tags only + if (current_tag == ParticleTag::dead) { + const auto idx_permute_vec = Kokkos::atomic_fetch_add( + ¤t_offset(current_tag), + 1); + } + // tag = 1->N (excluding dead and alive) + else{ + const auto idx_permute_vec = this_tag_offset(current_tag) - + n_alive + + Kokkos::atomic_fetch_add( + ¤t_offset(current_tag), + 1); + permute_vector(idx_permute_vec) = p; + this_i1(p) += shifts_in_x1(current_tag); + this_i1_prev(p) += shifts_in_x1(current_tag); + } + } + }); } - // Compute where the received particles are allocated - // if (mpi_rank == 0){ - // Kokkos::View particles_allocated_per_tag("particles - // allocated per tag", tag_count); Kokkos::parallel_for( - // "ParticlesAllocatedPerTag", - // total_recv, - // Lambda(const std::size_t i) { - // auto index = allocation_vector(i); - // auto tag = this_tag(index); - // Kokkos::atomic_fetch_add(&particles_allocated_per_tag(tag), 1); - // }); - // Kokkos::fence(); - // auto particles_allocated_per_tag_h = - // Kokkos::create_mirror_view(particles_allocated_per_tag); - // Kokkos::deep_copy(particles_allocated_per_tag_h, - // particles_allocated_per_tag); - - // std::cout << "Particles allocated per tag (post recv): "; - // for (std::size_t i = 0; i < tag_count; i++){ - // std::cout << "[" << particles_allocated_per_tag_h[i] << "] "; - // } - // std::cout << std::endl; - // } - // If receive count is less than send count then make the tags of sent dead - if (total_recv <= total_holes) { - if (total_recv <= total_dead) { - // Case: all sent particles' tags are set to dead - /* (received) - [ | <------------------> | <-------->] - (dead) (alive) (sent) - || - (to be made dead) - ^ - (offset) - */ - - auto offset = total_alive + total_dead; - Kokkos::parallel_for( - "CommunicateParticles", - total_send, - Lambda(index_t p) { - this_tag(permute_vector(offset + p)) = ParticleTag::dead; - }); - } else { - // Case: tags of sent particles that are not replaced by recevied particles are made dead - /* (received) (received) - [ | <------------------> |] - (dead) (alive) (sent) - || - (to be made dead) - ^ - (offset) - */ - auto offset = total_alive + total_recv; - Kokkos::parallel_for( - "CommunicateParticles", - total_send - (total_recv - total_dead), - Lambda(index_t p) { - this_tag(permute_vector(offset + p)) = ParticleTag::dead; - }); + + if constexpr (D == Dim::_2D){ + Kokkos::parallel_for( + "PermuteVector and Displace", + species.npart(), + Lambda(index_t p) { + const auto current_tag = this_tag(p); + if (current_tag != ParticleTag::alive){ + // dead tags only + if (current_tag == ParticleTag::dead) { + const auto idx_permute_vec = Kokkos::atomic_fetch_add( + ¤t_offset(current_tag), + 1); + } + // tag = 1->N (excluding dead and alive) + else{ + const auto idx_permute_vec = this_tag_offset(current_tag) - + n_alive + + Kokkos::atomic_fetch_add( + ¤t_offset(current_tag), + 1); + permute_vector(idx_permute_vec) = p; + this_i1(p) += shifts_in_x1(current_tag); + this_i1_prev(p) += shifts_in_x1(current_tag); + this_i2(p) += shifts_in_x2(current_tag); + this_i2_prev(p) += shifts_in_x2(current_tag); + } + } + }); + } + + if constexpr (D == Dim::_3D){ + Kokkos::parallel_for( + "PermuteVector and Displace", + species.npart(), + Lambda(index_t p) { + const auto current_tag = this_tag(p); + if (current_tag != ParticleTag::alive){ + // dead tags only + if (current_tag == ParticleTag::dead) { + const auto idx_permute_vec = Kokkos::atomic_fetch_add( + ¤t_offset(current_tag), + 1); + } + // tag = 1->N (excluding dead and alive) + else{ + const auto idx_permute_vec = this_tag_offset(current_tag) - + n_alive + + Kokkos::atomic_fetch_add( + ¤t_offset(current_tag), + 1); + permute_vector(idx_permute_vec) = p; + this_i1(p) += shifts_in_x1(current_tag); + this_i1_prev(p) += shifts_in_x1(current_tag); + this_i2(p) += shifts_in_x2(current_tag); + this_i2_prev(p) += shifts_in_x2(current_tag); + this_i3(p) += shifts_in_x3(current_tag); + this_i3_prev(p) += shifts_in_x3(current_tag); + } + } + }); + } + + // Sanity check: npart_per_tag must be equal to the current offset except tag=alive + auto current_offset_h = Kokkos::create_mirror_view(current_offset); + Kokkos::deep_copy(current_offset_h, current_offset); + for (std::size_t i { 0 }; i < species.ntags(); ++i) { + if (i != ParticleTag::alive){ + raise::FatalIf(current_offset_h(i) != npart_per_tag_arr[i], + "Error in permute vector construction", + HERE); + } + else{ + raise::FatalIf(current_offset_h(i) != 0, + "Error in permute vector construction", + HERE); } } - // Check if the particle tags are only dead or alive - species.set_npart(npart + std::max(total_send, total_recv) - total_send); - npart_per_tag_arr = species.npart_per_tag(); - // if (mpi_rank == 0) - //{ - // std::cout << "After COMM: " << std::endl; - // std::cout << "Tag counts: "; - // for (std::size_t i = 0; i < tag_count; i++){ - // std::cout << "[" << npart_per_tag_arr[i] << "] "; - // } - // std::cout << std::endl; - // std::cout << "Holes filled: " << total_holes << " Total recv: " << total_recv << - // "Total send: " << total_send << std::endl; - // std::cout << std::endl << "*************"<< std::endl; - // } + /* + Brief on allocation vector: It contains the indices of holes that are filled + by the particles received from other domains + case 1: total_recv > nholes + allocation_vector = | i1 | i2 | i3 | .... | npart | npart + 1 | ... + <-------total_holes------> <---total_recv - nholes--> + (same as permuute vector) (extra particles appended at end) + case 2: total_recv <= nholes + allocation_vector = | i1 | i2 | i3 | .... + <----total_recv-----> + (same as permuute vector) + */ + Kokkos::View allocation_vector("allocation_vector", total_recv); + if (total_recv > total_holes) + { + // Fill the first bit with the permute vector; these are the holes to be filled + Kokkos::parallel_for( + "AllocationVector", + total_holes, + Lambda(index_t p) { + allocation_vector(p) = permute_vector(p); + }); + + // Now allocate the rest to the end of the array + Kokkos::parallel_for( + "AllocationVector", + total_recv - total_holes, + Lambda(index_t p) { + allocation_vector(total_holes + p) = static_cast(npart + p); + }); + } + else + { Kokkos::parallel_for( + "AllocationVector", + total_recv, + Lambda(index_t p) { + allocation_vector(p) = permute_vector(p); + }); + } + // Communicate the arrays + comm::CommunicateParticlesBuffer(species, permute_vector, allocation_vector, + this_tag_offset, npart_per_tag_arr, npart_per_tag_arr_recv, + send_ranks, recv_ranks); #endif } } From 89a109dcfe61fcb30c478857d40a55791dee6476 Mon Sep 17 00:00:00 2001 From: Siddhant Solanki Date: Sun, 29 Dec 2024 11:24:23 -0500 Subject: [PATCH 200/773] test for cuda mpi --- benchmark/benchmark.cpp | 64 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/benchmark/benchmark.cpp b/benchmark/benchmark.cpp index 593b7f190..54fc17cf9 100644 --- a/benchmark/benchmark.cpp +++ b/benchmark/benchmark.cpp @@ -13,6 +13,8 @@ #include #include "framework/domain/communications.cpp" +#include "mpi.h" +#include "mpi-ext.h" #define TIMER_START(label) \ Kokkos::fence(); \ @@ -97,6 +99,68 @@ void PushParticles(Domain& domain, auto main(int argc, char* argv[]) -> int { GlobalInitialize(argc, argv); { + /* + MPI checks + */ + printf("Compile time check:\n"); +#if defined(MPIX_CUDA_AWARE_SUPPORT) && MPIX_CUDA_AWARE_SUPPORT + printf("This MPI library has CUDA-aware support.\n", MPIX_CUDA_AWARE_SUPPORT); +#elif defined(MPIX_CUDA_AWARE_SUPPORT) && !MPIX_CUDA_AWARE_SUPPORT + printf("This MPI library does not have CUDA-aware support.\n"); +#else + printf("This MPI library cannot determine if there is CUDA-aware support.\n"); +#endif /* MPIX_CUDA_AWARE_SUPPORT */ +printf("Run time check:\n"); +#if defined(MPIX_CUDA_AWARE_SUPPORT) + if (1 == MPIX_Query_cuda_support()) { + printf("This MPI library has CUDA-aware support.\n"); + } else { + printf("This MPI library does not have CUDA-aware support.\n"); + } +#else /* !defined(MPIX_CUDA_AWARE_SUPPORT) */ + printf("This MPI library cannot determine if there is CUDA-aware support.\n"); +#endif /* MPIX_CUDA_AWARE_SUPPORT */ + + /* + Test to send and receive Kokkos arrays + */ + int sender_rank; + MPI_Comm_rank(MPI_COMM_WORLD, &sender_rank); + + int neighbor_rank = 0; + if (sender_rank == 0) { + neighbor_rank = 1; + } + else if (sender_rank == 1) { + neighbor_rank = 0; + } + else { + raise::Error("This test is only for 2 ranks", HERE); + } + Kokkos::View send_array("send_array", 10); + Kokkos::View recv_array("recv_array", 10); + if (sender_rank == 0) { + Kokkos::deep_copy(send_array, 10); + } + else { + Kokkos::deep_copy(send_array, 20); + } + + auto send_array_host = Kokkos::create_mirror_view(send_array); + Kokkos::deep_copy(send_array_host, send_array); + auto host_recv_array = Kokkos::create_mirror_view(recv_array); + + MPI_Sendrecv(send_array.data(), send_array.extent(0), MPI_INT, neighbor_rank, 0, + recv_array.data(), recv_array.extent(0), MPI_INT, neighbor_rank, 0, + MPI_COMM_WORLD, MPI_STATUS_IGNORE); + + // Print the received array + Kokkos::deep_copy(host_recv_array, recv_array); + for (int i = 0; i < 10; ++i) { + printf("Rank %d: Received %d\n", sender_rank, host_recv_array(i)); + } + + std::cout << "Constructing the domain" << std::endl; // Create a Metadomain object const unsigned int ndomains = 2; From 43924f5fbbcbc14092e7966ff0c4245ba04e71aa Mon Sep 17 00:00:00 2001 From: Siddhant Solanki Date: Mon, 30 Dec 2024 22:33:47 -0500 Subject: [PATCH 201/773] fixed displacements --- src/engines/srpic.hpp | 1 + src/framework/domain/comm_mpi.hpp | 67 +++++++++++++++++-------- src/framework/domain/communications.cpp | 36 +++++-------- 3 files changed, 60 insertions(+), 44 deletions(-) diff --git a/src/engines/srpic.hpp b/src/engines/srpic.hpp index 78c8f371e..4772b975a 100644 --- a/src/engines/srpic.hpp +++ b/src/engines/srpic.hpp @@ -1008,6 +1008,7 @@ namespace ntt { Kokkos::Experimental::contribute(domain.fields.bckp, scatter_bckp); m_metadomain.SynchronizeFields(domain, Comm::Bckp, { 0, 1 }); } + logger::Checkpoint("Atmosphere particles injected\n", HERE); if (dim == in::x1) { if (sign > 0) { diff --git a/src/framework/domain/comm_mpi.hpp b/src/framework/domain/comm_mpi.hpp index 66ea17d23..0e4817571 100644 --- a/src/framework/domain/comm_mpi.hpp +++ b/src/framework/domain/comm_mpi.hpp @@ -297,43 +297,70 @@ namespace comm { int recv_rank, const range_tuple_t& send_slice, const range_tuple_t& recv_slice) { - //auto arr_h = Kokkos::create_mirror_view(arr); - //Kokkos::deep_copy(arr_h, arr); const std::size_t send_count = send_slice.second - send_slice.first; const std::size_t recv_count = recv_slice.second - recv_slice.first; + // Make arrays on the host + auto send_arr_h = Kokkos::create_mirror_view(Kokkos::subview(arr, send_slice)); + Kokkos::deep_copy(send_arr_h, Kokkos::subview(arr, send_slice)); + auto recv_arr_h = Kokkos::create_mirror_view(Kokkos::subview(arr, recv_slice)); if ((send_rank >= 0) and (recv_rank >= 0) and (send_count > 0) and (recv_count > 0)) { - MPI_Sendrecv(arr.data() + send_slice.first, + MPI_Sendrecv(send_arr_h.data(), send_count, mpi::get_type(), send_rank, 0, - arr.data() + recv_slice.first, + recv_arr_h.data(), recv_count, mpi::get_type(), recv_rank, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + //MPI_Sendrecv(arr.data() + send_slice.first, + // send_count, + // mpi::get_type(), + // send_rank, + // 0, + // arr.data() + recv_slice.first, + // recv_count, + // mpi::get_type(), + // recv_rank, + // 0, + // MPI_COMM_WORLD, + // MPI_STATUS_IGNORE); } else if ((send_rank >= 0) and (send_count > 0)) { - MPI_Send(arr.data() + send_slice.first, - send_count, - mpi::get_type(), - send_rank, - 0, - MPI_COMM_WORLD); + MPI_Send( send_arr_h.data(), + send_count, + mpi::get_type(), + send_rank, + 0, + MPI_COMM_WORLD); + //MPI_Send(arr.data() + send_slice.first, + // send_count, + // mpi::get_type(), + // send_rank, + // 0, + // MPI_COMM_WORLD); } else if ((recv_rank >= 0) and (recv_count > 0)) { - MPI_Recv(arr.data() + recv_slice.first, - recv_count, - mpi::get_type(), - recv_rank, - 0, - MPI_COMM_WORLD, - MPI_STATUS_IGNORE); + MPI_Recv( recv_arr_h.data(), + recv_count, + mpi::get_type(), + recv_rank, + 0, + MPI_COMM_WORLD, + MPI_STATUS_IGNORE); + //MPI_Recv(arr.data() + recv_slice.first, + // recv_count, + // mpi::get_type(), + // recv_rank, + // 0, + // MPI_COMM_WORLD, + // MPI_STATUS_IGNORE); + } + if ((recv_rank >= 0) and (recv_count > 0)) { + Kokkos::deep_copy(Kokkos::subview(arr, recv_slice), recv_arr_h); } - // if ((recv_rank >= 0) and (recv_count > 0)) { - // Kokkos::deep_copy(arr, arr_h); - // } } void ParticleSendRecvCount(int send_rank, diff --git a/src/framework/domain/communications.cpp b/src/framework/domain/communications.cpp index cdc9e5b5a..428db1ea6 100644 --- a/src/framework/domain/communications.cpp +++ b/src/framework/domain/communications.cpp @@ -712,38 +712,26 @@ namespace ntt { npart_per_tag_arr_recv[tag_recv] = nrecv; // @CRITICAL: Ask Hayk if the displacements are correctly set before sending - if constexpr (D == Dim::_1D) { + // direction must be defined + if constexpr (D == Dim::_1D || D == Dim::_2D || D == Dim::_3D) { if ((-direction)[0] == -1) { - shifts_in_x1_h(tag_send) = -subdomain(recv_ind).mesh.n_active(in::x1); + shifts_in_x1_h(tag_send) = subdomain(recv_ind).mesh.n_active(in::x1); } else if ((-direction)[0] == 1) { - shifts_in_x1_h(tag_send) = domain.mesh.n_active(in::x1); - } - } else if constexpr (D == Dim::_2D) { - if ((-direction)[0] == -1) { - shifts_in_x1_h(tag_send) = -subdomain(recv_ind).mesh.n_active(in::x1); - } else if ((-direction)[0] == 1) { - shifts_in_x1_h(tag_send) = domain.mesh.n_active()[0]; - } - if ((-direction)[1] == -1) { - shifts_in_x2_h(tag_send) = -subdomain(recv_ind).mesh.n_active(in::x2); - } else if ((-direction)[1] == 1) { - shifts_in_x2_h(tag_send) = domain.mesh.n_active(in::x2); - } - } else if constexpr (D == Dim::_3D) { - if ((-direction)[0] == -1) { - shifts_in_x1_h(tag_send) = -subdomain(recv_ind).mesh.n_active(in::x1); - } else if ((-direction)[0] == 1) { - shifts_in_x1_h(tag_send) = domain.mesh.n_active(in::x1); + shifts_in_x1_h(tag_send) = -domain.mesh.n_active(in::x1); } + } + if constexpr (D == Dim::_2D || D == Dim::_3D) { if ((-direction)[1] == -1) { - shifts_in_x2_h(tag_send) = -subdomain(recv_ind).mesh.n_active(in::x2); + shifts_in_x2_h(tag_send) = subdomain(recv_ind).mesh.n_active(in::x2); } else if ((-direction)[1] == 1) { - shifts_in_x2_h(tag_send) = domain.mesh.n_active(in::x2); + shifts_in_x2_h(tag_send) = -domain.mesh.n_active(in::x2); } + } + if constexpr (D == Dim::_3D) { if ((-direction)[2] == -1) { - shifts_in_x3_h(tag_send) = -subdomain(recv_ind).mesh.n_active(in::x3); + shifts_in_x3_h(tag_send) = subdomain(recv_ind).mesh.n_active(in::x3); } else if ((-direction)[2] == 1) { - shifts_in_x3_h(tag_send) = domain.mesh.n_active(in::x3); + shifts_in_x3_h(tag_send) = -domain.mesh.n_active(in::x3); } } } // end directions loop From 8571797268f689e572ea290df480fe6c49a73707 Mon Sep 17 00:00:00 2001 From: Siddhant Solanki Date: Mon, 30 Dec 2024 22:34:09 -0500 Subject: [PATCH 202/773] changed mpi init call --- src/global/global.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/global/global.cpp b/src/global/global.cpp index ec22fd2f3..434740446 100644 --- a/src/global/global.cpp +++ b/src/global/global.cpp @@ -9,7 +9,17 @@ void ntt::GlobalInitialize(int argc, char* argv[]) { Kokkos::initialize(argc, argv); #if defined(MPI_ENABLED) - MPI_Init(&argc, &argv); + int required = MPI_THREAD_MULTIPLE; + int provided; + MPI_Init_thread(&argc, + &argv, + required, + &provided); + if (provided != required) { + std::cerr << "MPI_Init_thread() did not provide the requested threading support." << std::endl; + MPI_Abort(MPI_COMM_WORLD, 1); + } + //MPI_Init(&argc, &argv); #endif // MPI_ENABLED } From ea99f3bc86cdfeebc871f14eab00d30dca4fa096 Mon Sep 17 00:00:00 2001 From: Siddhant Solanki Date: Wed, 1 Jan 2025 13:54:18 -0500 Subject: [PATCH 203/773] fixed displacements --- src/engines/srpic.hpp | 4 ++-- src/entity.cpp | 2 +- src/framework/domain/comm_mpi.hpp | 7 ++++++- src/framework/domain/communications.cpp | 26 +++++++++++++------------ src/framework/domain/output.cpp | 2 +- src/global/utils/progressbar.cpp | 4 ++-- src/kernels/particle_moments.hpp | 1 - 7 files changed, 26 insertions(+), 20 deletions(-) diff --git a/src/engines/srpic.hpp b/src/engines/srpic.hpp index 4772b975a..6e0d9634e 100644 --- a/src/engines/srpic.hpp +++ b/src/engines/srpic.hpp @@ -102,6 +102,7 @@ namespace ntt { timers.start("FieldBoundaries"); FieldBoundaries(dom, BC::B); timers.stop("FieldBoundaries"); + Kokkos::fence(); } { @@ -127,7 +128,7 @@ namespace ntt { timers.start("Communications"); if ((sort_interval > 0) and (step % sort_interval == 0)) { - m_metadomain.CommunicateParticles(dom, &timers); + m_metadomain.CommunicateParticlesBuffer(dom, &timers); } timers.stop("Communications"); } @@ -1008,7 +1009,6 @@ namespace ntt { Kokkos::Experimental::contribute(domain.fields.bckp, scatter_bckp); m_metadomain.SynchronizeFields(domain, Comm::Bckp, { 0, 1 }); } - logger::Checkpoint("Atmosphere particles injected\n", HERE); if (dim == in::x1) { if (sign > 0) { diff --git a/src/entity.cpp b/src/entity.cpp index 272635d68..79b2f1335 100644 --- a/src/entity.cpp +++ b/src/entity.cpp @@ -114,4 +114,4 @@ auto main(int argc, char* argv[]) -> int { } return 0; -} +} \ No newline at end of file diff --git a/src/framework/domain/comm_mpi.hpp b/src/framework/domain/comm_mpi.hpp index 0e4817571..c8e7de3a7 100644 --- a/src/framework/domain/comm_mpi.hpp +++ b/src/framework/domain/comm_mpi.hpp @@ -607,6 +607,7 @@ namespace comm { send_buffer_real(NREALS * p + 3) = this_weight(idx); send_buffer_prtldx(NFLOATS * p + 0) = this_dx1(idx); send_buffer_prtldx(NFLOATS * p + 1) = this_dx1_prev(idx); + this_tag(idx) = ParticleTag::dead; }); } if constexpr(D == Dim::_2D && C == Coord::Cart) { @@ -627,6 +628,7 @@ namespace comm { send_buffer_prtldx(NFLOATS * p + 1) = this_dx1_prev(idx); send_buffer_prtldx(NFLOATS * p + 2) = this_dx2(idx); send_buffer_prtldx(NFLOATS * p + 3) = this_dx2_prev(idx); + this_tag(idx) = ParticleTag::dead; }); } if constexpr(D == Dim::_2D && C != Coord::Cart) { @@ -648,6 +650,7 @@ namespace comm { send_buffer_prtldx(NFLOATS * p + 1) = this_dx1_prev(idx); send_buffer_prtldx(NFLOATS * p + 2) = this_dx2(idx); send_buffer_prtldx(NFLOATS * p + 3) = this_dx2_prev(idx); + this_tag(idx) = ParticleTag::dead; }); } if constexpr(D == Dim::_3D) { @@ -672,6 +675,7 @@ namespace comm { send_buffer_prtldx(NFLOATS * p + 3) = this_dx2_prev(idx); send_buffer_prtldx(NFLOATS * p + 4) = this_dx3(idx); send_buffer_prtldx(NFLOATS * p + 5) = this_dx3_prev(idx); + this_tag(idx) = ParticleTag::dead; }); } @@ -825,7 +829,7 @@ namespace comm { }); } - if constexpr (D == Dim::_2D && C == Coord::Cart) + if constexpr (D == Dim::_2D && C != Coord::Cart) { Kokkos::parallel_for( "PopulateFromRecvBuffer", @@ -875,6 +879,7 @@ namespace comm { this_dx3_prev(idx) = recv_buffer_prtldx(NFLOATS * p + 5); }); } + species.set_npart(species.npart() + std::max(total_send, total_recv) - total_send); return; } diff --git a/src/framework/domain/communications.cpp b/src/framework/domain/communications.cpp index 428db1ea6..80414bd93 100644 --- a/src/framework/domain/communications.cpp +++ b/src/framework/domain/communications.cpp @@ -787,8 +787,8 @@ namespace ntt { ¤t_offset(current_tag), 1); permute_vector(idx_permute_vec) = p; - this_i1(p) += shifts_in_x1(current_tag); - this_i1_prev(p) += shifts_in_x1(current_tag); + this_i1(p) -= shifts_in_x1(current_tag); + this_i1_prev(p) -= shifts_in_x1(current_tag); } } }); @@ -815,10 +815,10 @@ namespace ntt { ¤t_offset(current_tag), 1); permute_vector(idx_permute_vec) = p; - this_i1(p) += shifts_in_x1(current_tag); - this_i1_prev(p) += shifts_in_x1(current_tag); - this_i2(p) += shifts_in_x2(current_tag); - this_i2_prev(p) += shifts_in_x2(current_tag); + this_i1(p) -= shifts_in_x1(current_tag); + this_i1_prev(p) -= shifts_in_x1(current_tag); + this_i2(p) -= shifts_in_x2(current_tag); + this_i2_prev(p) -= shifts_in_x2(current_tag); } } }); @@ -845,17 +845,19 @@ namespace ntt { ¤t_offset(current_tag), 1); permute_vector(idx_permute_vec) = p; - this_i1(p) += shifts_in_x1(current_tag); - this_i1_prev(p) += shifts_in_x1(current_tag); - this_i2(p) += shifts_in_x2(current_tag); - this_i2_prev(p) += shifts_in_x2(current_tag); - this_i3(p) += shifts_in_x3(current_tag); - this_i3_prev(p) += shifts_in_x3(current_tag); + this_i1(p) -= shifts_in_x1(current_tag); + this_i1_prev(p) -= shifts_in_x1(current_tag); + this_i2(p) -= shifts_in_x2(current_tag); + this_i2_prev(p) -= shifts_in_x2(current_tag); + this_i3(p) -= shifts_in_x3(current_tag); + this_i3_prev(p) -= shifts_in_x3(current_tag); } } }); } + + // Sanity check: npart_per_tag must be equal to the current offset except tag=alive auto current_offset_h = Kokkos::create_mirror_view(current_offset); Kokkos::deep_copy(current_offset_h, current_offset); diff --git a/src/framework/domain/output.cpp b/src/framework/domain/output.cpp index c7cb6bb65..4a6b2c908 100644 --- a/src/framework/domain/output.cpp +++ b/src/framework/domain/output.cpp @@ -107,6 +107,7 @@ namespace ntt { } } + template void ComputeMoments(const SimulationParams& params, const Mesh& mesh, @@ -271,7 +272,6 @@ namespace ntt { }); g_writer.writeMesh(dim, xc, xe); } - const auto output_asis = params.template get("output.debug.as_is"); // !TODO: this can probably be optimized to dump things at once for (auto& fld : g_writer.fieldWriters()) { diff --git a/src/global/utils/progressbar.cpp b/src/global/utils/progressbar.cpp index 74f952382..38f65a790 100644 --- a/src/global/utils/progressbar.cpp +++ b/src/global/utils/progressbar.cpp @@ -52,10 +52,10 @@ namespace pbar { } auto to_human_readable(long double t, const std::string& u) -> std::string { - const auto [tt, tu] = normalize_duration_fmt(t, u); + const auto [tt, tu] = std::pair{t, u};//normalize_duration_fmt(t, u); const auto t1 = static_cast(tt); const auto t2 = tt - static_cast(t1); - const auto [tt2, tu2] = normalize_duration_fmt(t2, tu); + const auto [tt2, tu2] = std::pair{t2, tu};//normalize_duration_fmt(t2, tu); return fmt::format("%d%s %d%s", t1, tu.c_str(), static_cast(tt2), tu2.c_str()); } diff --git a/src/kernels/particle_moments.hpp b/src/kernels/particle_moments.hpp index 8b668a036..0621646ad 100644 --- a/src/kernels/particle_moments.hpp +++ b/src/kernels/particle_moments.hpp @@ -223,7 +223,6 @@ namespace kernel { } coeff *= weight(p) * smooth; } - auto buff_access = Buff.access(); if constexpr (D == Dim::_1D) { for (auto di1 { -window }; di1 <= window; ++di1) { From 8faf54347cbed49c81b7064f730a243763020b9c Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Thu, 2 Jan 2025 15:33:52 -0500 Subject: [PATCH 204/773] minor fix for qks --- src/metrics/qkerr_schild.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/metrics/qkerr_schild.h b/src/metrics/qkerr_schild.h index e45376a24..e3d849952 100644 --- a/src/metrics/qkerr_schild.h +++ b/src/metrics/qkerr_schild.h @@ -255,7 +255,7 @@ namespace metric { const real_t r { r0 + math::exp(x[0] * dchi + chi_min) }; const real_t eta {x[1] * deta + eta_min }; const real_t theta { eta2theta(eta) }; - const real_t dx_dt {deta * (ONE + TWO * h0 * constant::INV_PI_SQR * (TWO * THREE * SQR(eta) - TWO * THREE * constant::PI * eta + constant::PI_SQR)) }; + const real_t dx_dt {deta * (ONE + TWO * h0 * static_cast(constant::INV_PI_SQR) * (TWO * THREE * SQR(eta) - TWO * THREE * static_cast(constant::PI) * eta + static_cast(constant::PI_SQR))) }; const real_t dt_Sigma {- TWO * SQR(a) * math::sin(theta) * math::cos(theta) * dx_dt}; return r * dt_Sigma * CUBE(alpha(x)) / SQR(Sigma(r, theta)); From b4a874e2bd15fdd647f2bb564628cd019567b74d Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Thu, 2 Jan 2025 15:52:50 -0500 Subject: [PATCH 205/773] minor for engines/grpic --- src/engines/grpic.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index 7ce584680..d6a45c953 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -743,6 +743,7 @@ namespace ntt { (void)direction; (void)domain; (void)tags; + (void)g; raise::Error("Custom boundaries not implemented", HERE); // if constexpr ( // traits::has_member::value) { @@ -915,7 +916,7 @@ namespace ntt { void AmpereCurrents(domain_t& domain, const gr_ampere& g) { logger::Checkpoint("Launching Ampere kernel for adding currents", HERE); const auto q0 = m_params.template get("scales.q0"); - const auto n0 = m_params.template get("scales.n0"); + // const auto n0 = m_params.template get("scales.n0"); const auto B0 = m_params.template get("scales.B0"); const auto coeff = -dt * q0 / B0; // auto range = range_with_axis_BCs(domain); From d817b47603333d6498ba21b224b4b8434c9af18f Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Fri, 3 Jan 2025 15:01:25 -0500 Subject: [PATCH 206/773] implementing threshold-dependent injection is in progress --- setups/grpic/wald/pgen.hpp | 211 ++++++++++++++++++++++++++++-------- setups/grpic/wald/wald.toml | 48 ++++---- 2 files changed, 188 insertions(+), 71 deletions(-) diff --git a/setups/grpic/wald/pgen.hpp b/setups/grpic/wald/pgen.hpp index b87d25ed2..457c24107 100644 --- a/setups/grpic/wald/pgen.hpp +++ b/setups/grpic/wald/pgen.hpp @@ -7,8 +7,13 @@ #include "arch/kokkos_aliases.h" #include "arch/traits.h" +#include "archetypes/energy_dist.h" +#include "archetypes/spatial_dist.h" +#include "archetypes/particle_injector.h" #include "archetypes/problem_generator.h" #include "framework/domain/metadomain.h" +#include "kernels/particle_moments.hpp" +#include "utils/numeric.h" namespace user { using namespace ntt; @@ -18,26 +23,12 @@ namespace user { InitFields(M metric_) : metric { metric_ } {} Inline auto A_3(const coord_t& x_Cd) const -> real_t { - // return HALF * (metric.template h_<3, 3>(x_Cd) - // + TWO * metric.spin() * metric.template h_<1, 3>(x_Cd) * metric.beta1(x_Cd) - // ); - coord_t x_Ph { ZERO }; - metric.template convert(x_Cd, x_Ph); - return HALF * SQR(x_Ph[0]) * SQR(math::sin(x_Ph[1])); - } - - Inline auto A_1(const coord_t& x_Cd) const -> real_t { - return HALF * (metric.template h_<1, 3>(x_Cd) - + TWO * metric.spin() * metric.template h_<1, 1>(x_Cd) * metric.beta1(x_Cd) + return HALF * (metric.template h_<3, 3>(x_Cd) + + TWO * metric.spin() * metric.template h_<1, 3>(x_Cd) * metric.beta1(x_Cd) ); - } - - Inline auto A_0(const coord_t& x_Cd) const -> real_t { - real_t g_00 { -metric.alpha(x_Cd) * metric.alpha(x_Cd) - + metric.template h_<1, 1>(x_Cd) * metric.beta1(x_Cd) * metric.beta1(x_Cd) - }; - return HALF * (metric.template h_<1, 3>(x_Cd) * metric.beta1(x_Cd) - + TWO * metric.spin() * g_00); + // coord_t x_Ph { ZERO }; + // metric.template convert(x_Cd, x_Ph); + // return HALF * SQR(x_Ph[0]) * SQR(math::sin(x_Ph[1])); } Inline auto bx1(const coord_t& x_Ph) const -> real_t { @@ -74,16 +65,6 @@ namespace user { } Inline auto bx3(const coord_t& x_Ph) const -> real_t { - // coord_t xi {ZERO}, x0m { ZERO }, x0p { ZERO }; - // metric.template convert(x_Ph, xi); - - // x0m[0] = xi[0] + HALF - HALF; - // x0m[1] = xi[1]; - // x0p[0] = xi[0] + HALF + HALF; - // x0p[1] = xi[1]; - - // real_t inv_sqrt_detH_ijP { ONE / metric.sqrt_det_h({ xi[0], xi[1] }) }; - // return -(A_1(x0p) - A_1(x0m)) * inv_sqrt_detH_ijP; return ZERO; } @@ -103,6 +84,105 @@ namespace user { const M metric; }; + template + struct PointDistribution : public arch::SpatialDistribution { + PointDistribution(const std::vector& xi_min, + const std::vector& xi_max, + const real_t sigma_thr, + const real_t dens_thr, + long double time, + const SimulationParams& params, + Domain* domain_ptr + ) + : arch::SpatialDistribution { domain_ptr->mesh.metric } + , metric { domain_ptr->mesh.metric } + , EM { domain_ptr->fields.em } + , sigma_thr {sigma_thr} + , dens_thr {dens_thr} + , time {time} { + std::copy(xi_min.begin(), xi_min.end(), x_min); + std::copy(xi_max.begin(), xi_max.end(), x_max); + + std::vector specs {}; + for (auto& sp : domain_ptr->species) { + if (sp.mass() > 0) { + specs.push_back(sp.index()); + } + } + + auto scatter_buff = Kokkos::Experimental::create_scatter_view(domain_ptr->fields.buff); + printf("%f\n", domain_ptr->fields.buff(10, 10, 0)); + // some parameters + auto& mesh = domain_ptr->mesh; + const auto use_weights = params.template get("particles.use_weights"); + const auto ni2 = mesh.n_active(in::x2); + const auto inv_n0 = ONE / params.template get("scales.n0"); + + for (const auto& sp : specs) { + auto& prtl_spec = domain_ptr->species[sp - 1]; + // clang-format off + Kokkos::parallel_for( + "ComputeMoments", + prtl_spec.rangeActiveParticles(), + kernel::ParticleMoments_kernel({}, scatter_buff, 0u, + prtl_spec.i1, prtl_spec.i2, prtl_spec.i3, + prtl_spec.dx1, prtl_spec.dx2, prtl_spec.dx3, + prtl_spec.ux1, prtl_spec.ux2, prtl_spec.ux3, + prtl_spec.phi, prtl_spec.weight, prtl_spec.tag, + prtl_spec.mass(), prtl_spec.charge(), + use_weights, + metric, mesh.flds_bc(), + ni2, inv_n0, 0)); + // clang-format on + } + Kokkos::Experimental::contribute(domain_ptr->fields.buff, scatter_buff); + // auto density = domain_ptr->fields.buff; + auto density = Kokkos::create_mirror_view(domain_ptr->fields.buff); + Kokkos::deep_copy(density, domain_ptr->fields.buff); + } + + Inline auto sigma_crit(const coord_t& x_Ph) const -> real_t { + coord_t xi {ZERO}; + if constexpr (M::Dim == Dim::_2D) { + metric.template convert(x_Ph, xi); + const auto i1 = static_cast(xi[0]) + static_cast(N_GHOSTS); + const auto i2 = static_cast(xi[1]) + static_cast(N_GHOSTS); + // printf("%f %f\n", xi[0], xi[1]); + const vec_t B_cntrv { EM(i1, i2, em::bx1), EM(i1, i2, em::bx2), EM(i1, i2, em::bx3) }; + vec_t B_cov { ZERO }; + metric.template transform(xi, B_cntrv, B_cov); + const auto bsqr = DOT(B_cntrv[0], B_cntrv[1], B_cntrv[2], B_cov[0], B_cov[1], B_cov[2]); + const auto dens = density(i1, i2, 0); + // printf("%f\n", domain_ptr->fields.buff(10, 10, 0)); + // return (bsqr / dens > sigma_thr) || (dens < dens_thr); + return 2.0; + } + return ZERO; + } + + Inline auto operator()(const coord_t& x_Ph) const -> real_t override { + auto fill = true; + for (auto d = 0u; d < M::Dim; ++d) { + fill &= x_Ph[d] > x_min[d] and x_Ph[d] < x_max[d]; + } + if (time > ZERO) { + fill &= sigma_crit(x_Ph) > ONE; + } + return fill ? ONE : ZERO; + } + + private: + tuple_t x_min; + tuple_t x_max; + const real_t sigma_thr; + const real_t dens_thr; + long double time, + Domain* domain_ptr; + ndfield_t density; + ndfield_t EM; + const M metric; + }; + template struct PGen : public arch::ProblemGenerator { // compatibility traits for the problem generator @@ -117,30 +197,67 @@ namespace user { using arch::ProblemGenerator::C; using arch::ProblemGenerator::params; + const std::vector xi_min; + const std::vector xi_max; + const real_t sigma0, sigma_max, multiplicity, nGJ; + InitFields init_flds; inline PGen(SimulationParams& p, const Metadomain& m) : arch::ProblemGenerator(p) - // , xi_min { p.template get>("setup.inj_rmin") } - // , xi_max { p.template get>("setup.inj_rmax") } + , xi_min { p.template get>("setup.xi_min") } + , xi_max { p.template get>("setup.xi_max") } + , sigma_max { p.template get("setup.sigma_max") } + , sigma0 { p.template get("scales.sigma0") } + , multiplicity { p.template get("setup.multiplicity") } + , nGJ { p.template get("scales.B0") * SQR(p.template get("scales.skindepth0")) } //m.mesh().metric.spin() * , init_flds { m.mesh().metric } {} - // inline void InitPrtls(Domain& local_domain) { - // const auto energy_dist = arch::ColdDist(local_domain.mesh.metric); - // const auto spatial_dist = PointDistribution(domain.mesh.metric, - // xi_min, - // xi_max); - // const auto injector = arch::NonUniformInjector( - // energy_dist, - // spatial_dist, - // { 1, 2 }); - // arch::InjectNonUniform>(params, - // local_domain, - // injector, - // 1.0); - // } - - // inline PGen() {} + inline void InitPrtls(Domain& local_domain) { + const auto energy_dist = arch::ColdDist(local_domain.mesh.metric); + const auto spatial_dist = PointDistribution(xi_min, + xi_max, + sigma_max / sigma0, + multiplicity * nGJ, + ZERO, + params, + &local_domain + ); + + const auto injector = arch::NonUniformInjector( + energy_dist, + spatial_dist, + { 1, 2 }); + arch::InjectNonUniform(params, + local_domain, + injector, + 1.0, + true); + } + + void CustomPostStep(std::size_t, long double time, Domain& local_domain) { + // const auto energy_dist = arch::ColdDist(local_domain.mesh.metric); + // const auto spatial_dist = PointDistribution(local_domain.mesh.metric, + // xi_min, + // xi_max); + + // const auto spatial_dist = ReplenishDist(local_domain.mesh.metric, + // const ndfield_t& density, + // unsigned short idx, + // const T& target_density, + // real_t target_max_density) + + // const auto injector = arch::NonUniformInjector( + // energy_dist, + // spatial_dist, + // { 1, 2 }); + // arch::InjectNonUniform(params, + // local_domain, + // injector, + // 1.0, + // true); + } + }; } // namespace user diff --git a/setups/grpic/wald/wald.toml b/setups/grpic/wald/wald.toml index 6e68d4324..2f12705de 100644 --- a/setups/grpic/wald/wald.toml +++ b/setups/grpic/wald/wald.toml @@ -1,17 +1,17 @@ [simulation] name = "wald" engine = "grpic" - runtime = 510.0 + runtime = 100.0 [grid] - resolution = [128,128] - extent = [[2.0, 8.0]] + resolution = [256,256] + extent = [[0.8, 8.0]] [grid.metric] metric = "qkerr_schild" qsph_r0 = 0.0 qsph_h = 0.0 - ks_a = 0.0 + ks_a = 0.95 [grid.boundaries] fields = [["ABSORB"]] @@ -31,7 +31,7 @@ CFL = 0.5 [algorithms.toggles] - deposit = false + deposit = true fieldsolver = true [particles] @@ -39,33 +39,33 @@ use_weights = true sort_interval = 100 - #[[particles.species]] - #label = "e-" - #mass = 1.0 - #charge = -1.0 - #maxnpart = 1e6 - #pusher = "Boris" - # - #[[particles.species]] - #label = "e+" - #mass = 1.0 - #charge = 1.0 - #maxnpart = 1e6 - #pusher = "Boris" + [[particles.species]] + label = "e-" + mass = 1.0 + charge = -1.0 + maxnpart = 1e6 + pusher = "Boris" + + [[particles.species]] + label = "e+" + mass = 1.0 + charge = 1.0 + maxnpart = 1e6 + pusher = "Boris" [setup] - #multiplicity = 1.0 - #sigma_max = 1000.0 - inj_rmin = 1.2 - inj_rmax = 7.5 + multiplicity = 1.0 + sigma_max = 10.0 + xi_min = [1.2, 0.1] + xi_max = [7.5, 3.04159265] [output] format = "hdf5" [output.fields] interval_time = 1.0 - quantities = ["D", "H", "B", "J"] - + quantities = ["D", "B", "J", "N_1", "N_2", "Nppc_1", "Nppc_2"] + [output.particles] enable = false From 1328097476d0727f2a59861056825ca455d08ab4 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Fri, 3 Jan 2025 16:57:41 -0500 Subject: [PATCH 207/773] updated pgen --- setups/grpic/wald/pgen.hpp | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/setups/grpic/wald/pgen.hpp b/setups/grpic/wald/pgen.hpp index 457c24107..78f922700 100644 --- a/setups/grpic/wald/pgen.hpp +++ b/setups/grpic/wald/pgen.hpp @@ -90,7 +90,6 @@ namespace user { const std::vector& xi_max, const real_t sigma_thr, const real_t dens_thr, - long double time, const SimulationParams& params, Domain* domain_ptr ) @@ -98,8 +97,7 @@ namespace user { , metric { domain_ptr->mesh.metric } , EM { domain_ptr->fields.em } , sigma_thr {sigma_thr} - , dens_thr {dens_thr} - , time {time} { + , dens_thr {dens_thr} { std::copy(xi_min.begin(), xi_min.end(), x_min); std::copy(xi_max.begin(), xi_max.end(), x_max); @@ -136,7 +134,6 @@ namespace user { // clang-format on } Kokkos::Experimental::contribute(domain_ptr->fields.buff, scatter_buff); - // auto density = domain_ptr->fields.buff; auto density = Kokkos::create_mirror_view(domain_ptr->fields.buff); Kokkos::deep_copy(density, domain_ptr->fields.buff); } @@ -147,7 +144,6 @@ namespace user { metric.template convert(x_Ph, xi); const auto i1 = static_cast(xi[0]) + static_cast(N_GHOSTS); const auto i2 = static_cast(xi[1]) + static_cast(N_GHOSTS); - // printf("%f %f\n", xi[0], xi[1]); const vec_t B_cntrv { EM(i1, i2, em::bx1), EM(i1, i2, em::bx2), EM(i1, i2, em::bx3) }; vec_t B_cov { ZERO }; metric.template transform(xi, B_cntrv, B_cov); @@ -163,10 +159,7 @@ namespace user { Inline auto operator()(const coord_t& x_Ph) const -> real_t override { auto fill = true; for (auto d = 0u; d < M::Dim; ++d) { - fill &= x_Ph[d] > x_min[d] and x_Ph[d] < x_max[d]; - } - if (time > ZERO) { - fill &= sigma_crit(x_Ph) > ONE; + fill &= x_Ph[d] > x_min[d] and x_Ph[d] < x_max[d] and sigma_crit(x_Ph) > ONE; } return fill ? ONE : ZERO; } @@ -176,7 +169,6 @@ namespace user { tuple_t x_max; const real_t sigma_thr; const real_t dens_thr; - long double time, Domain* domain_ptr; ndfield_t density; ndfield_t EM; @@ -219,7 +211,6 @@ namespace user { xi_max, sigma_max / sigma0, multiplicity * nGJ, - ZERO, params, &local_domain ); From a400ced79c5d6838ed2189db5452f21b59df6567 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Fri, 3 Jan 2025 17:19:57 -0500 Subject: [PATCH 208/773] minor --- setups/grpic/wald/pgen.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/setups/grpic/wald/pgen.hpp b/setups/grpic/wald/pgen.hpp index 78f922700..41d9a2462 100644 --- a/setups/grpic/wald/pgen.hpp +++ b/setups/grpic/wald/pgen.hpp @@ -108,6 +108,7 @@ namespace user { } } + Kokkos::deep_copy(domain_ptr->fields.buff, ZERO); auto scatter_buff = Kokkos::Experimental::create_scatter_view(domain_ptr->fields.buff); printf("%f\n", domain_ptr->fields.buff(10, 10, 0)); // some parameters From 73377c2cba083a25d3e449b7632402d24d2b8a32 Mon Sep 17 00:00:00 2001 From: Siddhant Solanki Date: Sat, 4 Jan 2025 10:33:22 -0500 Subject: [PATCH 209/773] fixed permute vector construction --- src/engines/srpic.hpp | 5 + src/framework/containers/particles.cpp | 3 + src/framework/containers/particles.h | 4 + src/framework/domain/comm_mpi.hpp | 178 +++++++++++++++++++++--- src/framework/domain/communications.cpp | 84 ++++++++--- src/framework/domain/metadomain.cpp | 27 ++++ src/framework/domain/metadomain.h | 1 + 7 files changed, 263 insertions(+), 39 deletions(-) diff --git a/src/engines/srpic.hpp b/src/engines/srpic.hpp index 6e0d9634e..d751c712a 100644 --- a/src/engines/srpic.hpp +++ b/src/engines/srpic.hpp @@ -126,6 +126,11 @@ namespace ntt { timers.stop("CurrentFiltering"); } + // Tags are assigned by now + if (step == 0){ + m_metadomain.SetParticleIDs(dom); + } + timers.start("Communications"); if ((sort_interval > 0) and (step % sort_interval == 0)) { m_metadomain.CommunicateParticlesBuffer(dom, &timers); diff --git a/src/framework/containers/particles.cpp b/src/framework/containers/particles.cpp index fe2346132..1cb63bf43 100644 --- a/src/framework/containers/particles.cpp +++ b/src/framework/containers/particles.cpp @@ -47,6 +47,9 @@ namespace ntt { tag = array_t { label + "_tag", maxnpart }; tag_h = Kokkos::create_mirror_view(tag); + particleID = array_t {label + "_particleID", maxnpart}; + particleID_h = Kokkos::create_mirror_view(particleID); + for (unsigned short n { 0 }; n < npld; ++n) { pld.push_back(array_t("pld", maxnpart)); pld_h.push_back(Kokkos::create_mirror_view(pld[n])); diff --git a/src/framework/containers/particles.h b/src/framework/containers/particles.h index ea692bdd9..131ff45c0 100644 --- a/src/framework/containers/particles.h +++ b/src/framework/containers/particles.h @@ -64,6 +64,8 @@ namespace ntt { std::vector> pld; // phi coordinate (for axisymmetry) array_t phi; + // Array to store the particle ids + array_t particleID; // host mirrors array_mirror_t i1_h, i2_h, i3_h; @@ -73,6 +75,7 @@ namespace ntt { array_mirror_t phi_h; array_mirror_t tag_h; std::vector> pld_h; + array_mirror_t particleID_h; // for empty allocation Particles() {} @@ -178,6 +181,7 @@ namespace ntt { footprint += sizeof(prtldx_t) * dx2_prev.extent(0); footprint += sizeof(prtldx_t) * dx3_prev.extent(0); footprint += sizeof(short) * tag.extent(0); + footprint += sizeof(long) * particleID.extent(0); for (auto& p : pld) { footprint += sizeof(real_t) * p.extent(0); } diff --git a/src/framework/domain/comm_mpi.hpp b/src/framework/domain/comm_mpi.hpp index c8e7de3a7..82308e107 100644 --- a/src/framework/domain/comm_mpi.hpp +++ b/src/framework/domain/comm_mpi.hpp @@ -186,8 +186,6 @@ namespace comm { auto recv_fld_h = Kokkos::create_mirror_view(recv_fld); Kokkos::deep_copy(send_fld_h, send_fld); if (send_rank >= 0 && recv_rank >= 0) { - // Segfault here: print mpi params - // Create host views MPI_Sendrecv(send_fld_h.data(), nsend, mpi::get_type(), @@ -515,16 +513,14 @@ namespace comm { auto &this_dx2_prev = species.dx2_prev; auto &this_dx3_prev = species.dx3_prev; auto &this_tag = species.tag; + auto &this_particleID = species.particleID; // Number of arrays of each type to send/recv auto NREALS = 4; auto NINTS = 2; auto NFLOATS = 2; + auto NLONGS = 2; if constexpr (D == Dim::_2D) { - this_i2 = species.i2; - this_i2_prev = species.i2_prev; - this_dx2 = species.dx2; - this_dx2_prev = species.dx2_prev; if (C != Coord::Cart) { NREALS = 5; NINTS = 4; @@ -537,14 +533,6 @@ namespace comm { } } if constexpr (D == Dim::_3D) { - this_i2 = species.i2; - this_i2_prev = species.i2_prev; - this_dx2 = species.dx2; - this_dx2_prev = species.dx2_prev; - this_i3 = species.i3; - this_i3_prev = species.i3_prev; - this_dx3 = species.dx3; - this_dx3_prev = species.dx3_prev; NREALS = 4; NINTS = 6; NFLOATS = 6; @@ -556,6 +544,12 @@ namespace comm { const auto n_alive = npart_per_tag_arr[ParticleTag::alive]; const auto n_dead = npart_per_tag_arr[ParticleTag::dead]; + // Debug test: print send and recv count + { + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + //printf("MPI rank: %d, Total send: %d, Total recv: %d \n", rank, total_send, total_recv); + } /* Brief on recv buffers: Each recv buffer contains all the received arrays of a given type. The different physical quantities are stored next to each other @@ -568,10 +562,11 @@ namespace comm { Kokkos::View recv_buffer_int("recv_buffer_int", total_recv * NINTS); Kokkos::View recv_buffer_real("recv_buffer_real", total_recv * NREALS); Kokkos::View recv_buffer_prtldx("recv_buffer_prtldx",total_recv * NFLOATS); + Kokkos::View recv_buffer_long("recv_buffer_long", total_recv * NLONGS); auto recv_buffer_int_h = Kokkos::create_mirror_view(recv_buffer_int); auto recv_buffer_real_h = Kokkos::create_mirror_view(recv_buffer_real); auto recv_buffer_prtldx_h = Kokkos::create_mirror_view(recv_buffer_prtldx); - + auto recv_buffer_long_h = Kokkos::create_mirror_view(recv_buffer_long); auto iteration = 0; auto current_received = 0; @@ -588,9 +583,11 @@ namespace comm { Kokkos::View send_buffer_int("send_buffer_int", send_count * NINTS); Kokkos::View send_buffer_real("send_buffer_real", send_count * NREALS); Kokkos::View send_buffer_prtldx("send_buffer_prtldx",send_count * NFLOATS); + Kokkos::View send_buffer_long("send_buffer_long", send_count * NLONGS); auto send_buffer_int_h = Kokkos::create_mirror_view(send_buffer_int); auto send_buffer_real_h = Kokkos::create_mirror_view(send_buffer_real); auto send_buffer_prtldx_h = Kokkos::create_mirror_view(send_buffer_prtldx); + auto send_buffer_long_h = Kokkos::create_mirror_view(send_buffer_long); // Need different constexpr parallel fors for different dims if constexpr(D == Dim::_1D) { @@ -607,6 +604,8 @@ namespace comm { send_buffer_real(NREALS * p + 3) = this_weight(idx); send_buffer_prtldx(NFLOATS * p + 0) = this_dx1(idx); send_buffer_prtldx(NFLOATS * p + 1) = this_dx1_prev(idx); + send_buffer_long(NLONGS * p + 0) = this_particleID(idx); + send_buffer_long(NLONGS * p + 1) = this_tag(idx); this_tag(idx) = ParticleTag::dead; }); } @@ -628,6 +627,8 @@ namespace comm { send_buffer_prtldx(NFLOATS * p + 1) = this_dx1_prev(idx); send_buffer_prtldx(NFLOATS * p + 2) = this_dx2(idx); send_buffer_prtldx(NFLOATS * p + 3) = this_dx2_prev(idx); + send_buffer_long(NLONGS * p + 0) = this_particleID(idx); + send_buffer_long(NLONGS * p + 1) = this_tag(idx); this_tag(idx) = ParticleTag::dead; }); } @@ -650,6 +651,8 @@ namespace comm { send_buffer_prtldx(NFLOATS * p + 1) = this_dx1_prev(idx); send_buffer_prtldx(NFLOATS * p + 2) = this_dx2(idx); send_buffer_prtldx(NFLOATS * p + 3) = this_dx2_prev(idx); + send_buffer_long(NLONGS * p + 0) = this_particleID(idx); + send_buffer_long(NLONGS * p + 1) = this_tag(idx); this_tag(idx) = ParticleTag::dead; }); } @@ -675,6 +678,8 @@ namespace comm { send_buffer_prtldx(NFLOATS * p + 3) = this_dx2_prev(idx); send_buffer_prtldx(NFLOATS * p + 4) = this_dx3(idx); send_buffer_prtldx(NFLOATS * p + 5) = this_dx3_prev(idx); + send_buffer_long(NLONGS * p + 0) = this_particleID(idx); + send_buffer_long(NLONGS * p + 1) = this_tag(idx); this_tag(idx) = ParticleTag::dead; }); } @@ -695,14 +700,22 @@ namespace comm { const auto receive_offset_int = current_received * NINTS; const auto receive_offset_real = current_received * NREALS; const auto receive_offset_prtldx = current_received * NFLOATS; + const auto receive_offset_long = current_received * NLONGS; // Comms // Make host arrays for send and recv buffers Kokkos::deep_copy(send_buffer_int_h, send_buffer_int); Kokkos::deep_copy(send_buffer_real_h, send_buffer_real); Kokkos::deep_copy(send_buffer_prtldx_h, send_buffer_prtldx); + Kokkos::deep_copy(send_buffer_long_h, send_buffer_long); if ((send_rank >= 0) and (recv_rank >= 0) and (send_count > 0) and (recv_count > 0)) { + // Debug: Print the rank and type of mpi operation performed + { + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + //printf("MPI rank: %d, Performing sendrecv operation \n", rank); + } MPI_Sendrecv(send_buffer_int_h.data(), send_count * NINTS, mpi::get_type(), @@ -739,7 +752,25 @@ namespace comm { 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Sendrecv(send_buffer_long_h.data(), + send_count * NLONGS, + mpi::get_type(), + send_rank, + 0, + recv_buffer_long_h.data() + receive_offset_long, + recv_count*NLONGS, + mpi::get_type(), + recv_rank, + 0, + MPI_COMM_WORLD, + MPI_STATUS_IGNORE); } else if ((send_rank >= 0) and (send_count > 0)) { + // Debug: Print the rank and type of mpi operation performed + { + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + //printf("MPI rank: %d, Performing send operation \n", rank); + } MPI_Send(send_buffer_int_h.data(), send_count * NINTS, mpi::get_type(), @@ -758,7 +789,19 @@ namespace comm { send_rank, 0, MPI_COMM_WORLD); + MPI_Send(send_buffer_long_h.data(), + send_count * NLONGS, + mpi::get_type(), + send_rank, + 0, + MPI_COMM_WORLD); } else if ((recv_rank >= 0) and (recv_count > 0)) { + // Debug: Print the rank and type of mpi operation performed + { + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + //printf("MPI rank: %d, Performing recv operation \n", rank); + } MPI_Recv(recv_buffer_int_h.data() + receive_offset_int, recv_count * NINTS, mpi::get_type(), @@ -780,9 +823,69 @@ namespace comm { 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + MPI_Recv(recv_buffer_long_h.data() + receive_offset_long, + recv_count * NLONGS, + mpi::get_type(), + recv_rank, + 0, + MPI_COMM_WORLD, + MPI_STATUS_IGNORE); } current_received += recv_count; iteration++; + + // Debug test: Print recv buffer before and after + /* + { + int total_ranks; + MPI_Comm_size(MPI_COMM_WORLD, &total_ranks); + for (int allranks=0; allranks| |<----->| |<----->| .... - tag=0 ct tag=1 ct tag=2 ct + tag=dead ct tag=2 ct tag=3 ct */ Kokkos::View permute_vector("permute_vector", total_holes); Kokkos::View current_offset("current_offset", species.ntags()); @@ -778,6 +776,7 @@ namespace ntt { const auto idx_permute_vec = Kokkos::atomic_fetch_add( ¤t_offset(current_tag), 1); + permute_vector(idx_permute_vec) = p; } // tag = 1->N (excluding dead and alive) else{ @@ -787,8 +786,8 @@ namespace ntt { ¤t_offset(current_tag), 1); permute_vector(idx_permute_vec) = p; - this_i1(p) -= shifts_in_x1(current_tag); - this_i1_prev(p) -= shifts_in_x1(current_tag); + this_i1(p) += shifts_in_x1(current_tag); + this_i1_prev(p) += shifts_in_x1(current_tag); } } }); @@ -806,6 +805,7 @@ namespace ntt { const auto idx_permute_vec = Kokkos::atomic_fetch_add( ¤t_offset(current_tag), 1); + permute_vector(idx_permute_vec) = p; } // tag = 1->N (excluding dead and alive) else{ @@ -815,10 +815,10 @@ namespace ntt { ¤t_offset(current_tag), 1); permute_vector(idx_permute_vec) = p; - this_i1(p) -= shifts_in_x1(current_tag); - this_i1_prev(p) -= shifts_in_x1(current_tag); - this_i2(p) -= shifts_in_x2(current_tag); - this_i2_prev(p) -= shifts_in_x2(current_tag); + this_i1(p) += shifts_in_x1(current_tag); + this_i1_prev(p) += shifts_in_x1(current_tag); + this_i2(p) += shifts_in_x2(current_tag); + this_i2_prev(p) += shifts_in_x2(current_tag); } } }); @@ -836,6 +836,7 @@ namespace ntt { const auto idx_permute_vec = Kokkos::atomic_fetch_add( ¤t_offset(current_tag), 1); + permute_vector(idx_permute_vec) = p; } // tag = 1->N (excluding dead and alive) else{ @@ -845,12 +846,12 @@ namespace ntt { ¤t_offset(current_tag), 1); permute_vector(idx_permute_vec) = p; - this_i1(p) -= shifts_in_x1(current_tag); - this_i1_prev(p) -= shifts_in_x1(current_tag); - this_i2(p) -= shifts_in_x2(current_tag); - this_i2_prev(p) -= shifts_in_x2(current_tag); - this_i3(p) -= shifts_in_x3(current_tag); - this_i3_prev(p) -= shifts_in_x3(current_tag); + this_i1(p) += shifts_in_x1(current_tag); + this_i1_prev(p) += shifts_in_x1(current_tag); + this_i2(p) += shifts_in_x2(current_tag); + this_i2_prev(p) += shifts_in_x2(current_tag); + this_i3(p) += shifts_in_x3(current_tag); + this_i3_prev(p) += shifts_in_x3(current_tag); } } }); @@ -913,6 +914,43 @@ namespace ntt { allocation_vector(p) = permute_vector(p); }); } + + /* + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + if (rank == 1 && species.label() == "e+_b") + { + // Copy the tag array to host + auto tag_h = Kokkos::create_mirror_view(species.tag); + Kokkos::deep_copy(tag_h, species.tag); + std::cout << "Tag locs before send" << std::endl; + for (std::size_t i { 0 }; i < species.npart(); i++) { + if (tag_h(i) != ParticleTag::alive) + std::cout <<" Tag: " << tag_h(i) << " loc: "<< i << std::endl; + } + + // Print allocation vector after copying to host + auto allocation_vector_h = Kokkos::create_mirror_view(allocation_vector); + std::cout << "Total holes: " << total_holes << " Total recv: " << total_recv << std::endl; + Kokkos::deep_copy(allocation_vector_h, allocation_vector); + for (std::size_t i { 0 }; i < total_recv; ++i) { + std::cout << "Rank: " << rank << " Allocation vector: " << allocation_vector_h(i) << std::endl; + } + // Print the permute vector as well + auto permute_vector_h = Kokkos::create_mirror_view(permute_vector); + Kokkos::deep_copy(permute_vector_h, permute_vector); + for (std::size_t i { 0 }; i < total_holes; ++i) { + std::cout << "Rank: " << rank << " Permuted vector: " << permute_vector_h(i) << + " tag: " << tag_h(permute_vector_h(i)) << std::endl; + } + } + */ + { + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + std::cout << "Rank: " << rank << " Total sent: " << total_holes - total_dead << " Total recv: " << total_recv << std::endl; + } + // Communicate the arrays comm::CommunicateParticlesBuffer(species, permute_vector, allocation_vector, this_tag_offset, npart_per_tag_arr, npart_per_tag_arr_recv, diff --git a/src/framework/domain/metadomain.cpp b/src/framework/domain/metadomain.cpp index ec8561a9a..a01296823 100644 --- a/src/framework/domain/metadomain.cpp +++ b/src/framework/domain/metadomain.cpp @@ -399,6 +399,33 @@ namespace ntt { #endif } + // Function to assign a unique ID to each particle + template + void Metadomain::SetParticleIDs(Domain& domain){ + for (auto& species : domain.species) { + auto &this_particleID = species.particleID; + auto &this_tag = species.tag; + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + const auto offset_per_rank = static_cast(1e9 * rank); + std::size_t current_particleID = 0; + Kokkos::View counter_view("current_particleID", 1); + Kokkos::deep_copy(counter_view, current_particleID); + + Kokkos::parallel_for( + "Set Particle IDs", + species.npart(), + Lambda(const std::size_t p){ + if (this_tag(p) == ParticleTag::alive) + { + Kokkos::atomic_increment(&counter_view(0)); + this_particleID(p) = offset_per_rank + static_cast(counter_view(0)); + } + }); + } + return; + } + template struct Metadomain>; template struct Metadomain>; template struct Metadomain>; diff --git a/src/framework/domain/metadomain.h b/src/framework/domain/metadomain.h index e30bc8e97..9e94bf89f 100644 --- a/src/framework/domain/metadomain.h +++ b/src/framework/domain/metadomain.h @@ -90,6 +90,7 @@ namespace ntt { void SynchronizeFields(Domain&, CommTags, const range_tuple_t& = { 0, 0 }); void CommunicateParticles(Domain&, timer::Timers*); void CommunicateParticlesBuffer(Domain&, timer::Timers*); + void SetParticleIDs(Domain&); /** * @param global_ndomains total number of domains From 0d18e5c07cdd6b9cb336b9ec976d032003eae687 Mon Sep 17 00:00:00 2001 From: Sasha Chernoglazov Date: Sat, 4 Jan 2025 18:18:47 -0500 Subject: [PATCH 210/773] test of the number of particles --- extern/adios2 | 2 +- setups/srpic/blob/blob.py | 62 +++++++++++++++++++++ setups/srpic/blob/blob.toml | 66 +++++++++++++++++++++++ setups/srpic/blob/nparts.py | 38 +++++++++++++ setups/srpic/blob/pgen.hpp | 104 ++++++++++++++++++++++++++++++++++++ 5 files changed, 271 insertions(+), 1 deletion(-) create mode 100644 setups/srpic/blob/blob.py create mode 100644 setups/srpic/blob/blob.toml create mode 100644 setups/srpic/blob/nparts.py create mode 100644 setups/srpic/blob/pgen.hpp diff --git a/extern/adios2 b/extern/adios2 index b8761e2af..f80ad829d 160000 --- a/extern/adios2 +++ b/extern/adios2 @@ -1 +1 @@ -Subproject commit b8761e2afab2cd05b89d09b2ee4da1cd7a834225 +Subproject commit f80ad829d751241140c40923503e1888e27e22e1 diff --git a/setups/srpic/blob/blob.py b/setups/srpic/blob/blob.py new file mode 100644 index 000000000..77337d3b2 --- /dev/null +++ b/setups/srpic/blob/blob.py @@ -0,0 +1,62 @@ +import h5py +import numpy as np +import matplotlib.pyplot as plt + +f = open("report", "r") +Lines = f.readlines() +f.close() + +em_new = [] +ep_new = [] +time_new = [] +for i in range (len(Lines)): + line = Lines[i] + line = line.strip() + arr = line.split() + + if (len(arr)>0 and arr[0]=='species'): + nparts = arr[2].split("..") + if (nparts[0]=="(e-_p)"): + em_new.append(float(nparts[-1])) + if (nparts[0]=="(e+_p)"): + ep_new.append(float(nparts[-1])) + + if (len(arr)>0 and arr[0]=='Time:'): + time_new.append(float(arr[1])) + +f = h5py.File('blob.h5', 'r') + +Nsteps = len(f.keys()) +print(list(f['Step0'].keys())) + +for i in range (Nsteps): + print (i) + fig = plt.figure(dpi=300, figsize=(8,8), facecolor='white') + + densMax = max(np.max(f['Step'+str(i)]['fN_1']),np.max(f['Step'+str(i)]['fN_2'])) + print(densMax) + ax1 = fig.add_axes([0.05,0.05,0.4,0.4]) + im1=ax1.pcolormesh(f['Step'+str(i)]['X1'],f['Step'+str(i)]['X2'],f['Step'+str(i)]['fN_1'],cmap='turbo',vmin=0,vmax=1.0) + ax1.set_title(r"$N_1$") + ax1.vlines(0,-10.0,10.0,color='white') + + ax1 = fig.add_axes([0.48,0.05,0.4,0.4]) + ax1.pcolormesh(f['Step'+str(i)]['X1'],f['Step'+str(i)]['X2'],f['Step'+str(i)]['fN_2'],cmap='turbo',vmin=0,vmax=1.0) + ax1.set_yticklabels([]) + ax1.set_title(r"$N_2$") + ax1.vlines(0,-10.0,10.0,color='white') + + ax4cb = fig.add_axes([0.89, 0.05, 0.01, 0.4]) + cbar4 = fig.colorbar(im1,cax=ax4cb) + + ax1= fig.add_axes([0.05,0.5,0.83,0.4]) + ax1.plot(time_new,em_new, color='blue', label=r'$e^-$, new') + ax1.plot(time_new,ep_new, color='red', label=r'$e^+$, new') + ax1.legend() + ax1.set_ylim(0,1.8e5) + ax1.set_xlim(0,100) + ax1.vlines(i, 0,1.8e5, color='green',linewidth=0.6) + + + fig.savefig("%05d"%i+".png",dpi=300,bbox_inches='tight') + plt.close() diff --git a/setups/srpic/blob/blob.toml b/setups/srpic/blob/blob.toml new file mode 100644 index 000000000..7c03b1f9e --- /dev/null +++ b/setups/srpic/blob/blob.toml @@ -0,0 +1,66 @@ +[simulation] + name = "blob" + engine = "srpic" + runtime = 100.0 + + [simulation.domain] + decomposition = [2,1,1] + +[grid] + resolution = [1024, 1024] + extent = [[-10.0, 10.0], [-10.0, 10.0]] + + [grid.metric] + metric = "minkowski" + + [grid.boundaries] + fields = [["PERIODIC"], ["PERIODIC"]] + particles = [["PERIODIC"], ["PERIODIC"]] + +[scales] + larmor0 = 1.0 + skindepth0 = 1.0 + +[algorithms] + current_filters = 4 + + [algorithms.timestep] + CFL = 0.5 + +[particles] + ppc0 = 16.0 + + [[particles.species]] + label = "e-_p" + mass = 1.0 + charge = -1.0 + maxnpart = 1e7 + + [[particles.species]] + label = "e+_p" + mass = 1.0 + charge = 1.0 + maxnpart = 1e7 + +[setup] + temp_1 = 1e-4 + x1c = -5.0 + x2c = 0.0 + v_max = 50.0 + dr = 1.0 + +[output] + format = "hdf5" + interval_time = 1.0 + + [output.fields] + quantities = ["N_1", "N_2", "B", "E"] + + [output.particles] + enable = false + + [output.spectra] + enable = false + +[diagnostics] + colored_stdout = false diff --git a/setups/srpic/blob/nparts.py b/setups/srpic/blob/nparts.py new file mode 100644 index 000000000..e759422c0 --- /dev/null +++ b/setups/srpic/blob/nparts.py @@ -0,0 +1,38 @@ +import h5py +import numpy as np +import matplotlib.pyplot as plt + +f = open("report", "r") +Lines = f.readlines() +f.close() + +em_new = [] +ep_new = [] +time_new = [] +for i in range (len(Lines)): + line = Lines[i] + line = line.strip() + arr = line.split() + + if (len(arr)>0 and arr[0]=='species'): + nparts = arr[2].split("..") + if (nparts[0]=="(e-_p)"): + em_new.append(float(nparts[-1])) + if (nparts[0]=="(e+_p)"): + ep_new.append(float(nparts[-1])) + + if (len(arr)>0 and arr[0]=='Time:'): + time_new.append(float(arr[1])) + + +fig = plt.figure(dpi=300, figsize=(8,8), facecolor='white') + +ax1= fig.add_axes([0.05,0.5,0.83,0.4]) +ax1.plot(time_new,em_new, color='blue', label=r'$e^-$, new') +ax1.plot(time_new,ep_new, color='red', label=r'$e^+$, new') +ax1.legend() +ax1.set_ylim(0,1.8e5) +ax1.set_xlim(0,100) + +fig.savefig("nparts.png",dpi=300,bbox_inches='tight') +plt.close() diff --git a/setups/srpic/blob/pgen.hpp b/setups/srpic/blob/pgen.hpp new file mode 100644 index 000000000..38b3db1c5 --- /dev/null +++ b/setups/srpic/blob/pgen.hpp @@ -0,0 +1,104 @@ +#ifndef PROBLEM_GENERATOR_H +#define PROBLEM_GENERATOR_H + +#include "enums.h" +#include "global.h" + +#include "arch/kokkos_aliases.h" +#include "arch/traits.h" + +#include "archetypes/energy_dist.h" +#include "archetypes/particle_injector.h" +#include "archetypes/problem_generator.h" +#include "framework/domain/domain.h" +#include "framework/domain/metadomain.h" + +namespace user { + using namespace ntt; + + template + struct CounterstreamEnergyDist : public arch::EnergyDistribution { + CounterstreamEnergyDist(const M& metric, real_t v_max) + : arch::EnergyDistribution { metric } + , v_max { v_max } {} + + Inline void operator()(const coord_t& x_Ph, + vec_t& v, + unsigned short sp) const override { + v[0] = v_max; + } + + private: + const real_t v_max; + }; + + template + struct GaussianDist : public arch::SpatialDistribution { + GaussianDist(const M& metric, real_t x1c, real_t x2c, real_t dr) + : arch::SpatialDistribution { metric } + , x1c { x1c } + , x2c { x2c } + , dr { dr } {} + + // to properly scale the number density, the probability should be normalized to 1 + Inline auto operator()(const coord_t& x_Ph) const -> real_t override { + if (math::abs(x_Ph[0] - x1c) < dr && math::abs(x_Ph[1] - x2c) < dr){ + return 1.0; + }else{ + return 0.0; + } + } + + private: + const real_t x1c, x2c, dr; + }; + + template + struct PGen : public arch::ProblemGenerator { + + // compatibility traits for the problem generator + static constexpr auto engines = traits::compatible_with::value; + static constexpr auto metrics = traits::compatible_with::value; + static constexpr auto dimensions = + traits::compatible_with::value; + + // for easy access to variables in the child class + using arch::ProblemGenerator::D; + using arch::ProblemGenerator::C; + using arch::ProblemGenerator::params; + + const real_t temp_1, x1c, x2c, dr, v_max; + + inline PGen(const SimulationParams& p, const Metadomain& global_domain) + : arch::ProblemGenerator { p } + , temp_1 { p.template get("setup.temp_1") } + , x1c { p.template get("setup.x1c") } + , x2c { p.template get("setup.x2c") } + , v_max { p.template get("setup.v_max") } + , dr { p.template get("setup.dr") } {} + + inline void InitPrtls(Domain& local_domain) { + const auto energy_dist = CounterstreamEnergyDist( + local_domain.mesh.metric, + v_max); + const auto spatial_dist = GaussianDist(local_domain.mesh.metric, + x1c, + x2c, + dr); + const auto injector = + arch::NonUniformInjector( + energy_dist, + spatial_dist, + { 1, 2 }); + + arch::InjectNonUniform>( + params, + local_domain, + injector, + 1.0); + } + }; + +} // namespace user + +#endif From d7f92f0ae4ea7a7c4407625c8822f417eb8810d1 Mon Sep 17 00:00:00 2001 From: Siddhant Solanki Date: Sun, 5 Jan 2025 00:37:22 -0500 Subject: [PATCH 211/773] added function to remove dead particles --- src/engines/srpic.hpp | 8 + src/framework/domain/comm_mpi.hpp | 114 +-------- src/framework/domain/communications.cpp | 306 ++++++++++++++++++++---- src/framework/domain/metadomain.h | 1 + 4 files changed, 275 insertions(+), 154 deletions(-) diff --git a/src/engines/srpic.hpp b/src/engines/srpic.hpp index d751c712a..686ed0c35 100644 --- a/src/engines/srpic.hpp +++ b/src/engines/srpic.hpp @@ -175,6 +175,14 @@ namespace ntt { ParticleInjector(dom); timers.stop("Injector"); } + + if (step % 10 == 0 && step > 0){ + + timers.start("RemoveDead"); + m_metadomain.RemoveDeadParticles(dom, &timers); + timers.stop("RemoveDead"); + } + } /* algorithm substeps --------------------------------------------------- */ diff --git a/src/framework/domain/comm_mpi.hpp b/src/framework/domain/comm_mpi.hpp index 82308e107..7b9a22eee 100644 --- a/src/framework/domain/comm_mpi.hpp +++ b/src/framework/domain/comm_mpi.hpp @@ -544,12 +544,6 @@ namespace comm { const auto n_alive = npart_per_tag_arr[ParticleTag::alive]; const auto n_dead = npart_per_tag_arr[ParticleTag::dead]; - // Debug test: print send and recv count - { - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - //printf("MPI rank: %d, Total send: %d, Total recv: %d \n", rank, total_send, total_recv); - } /* Brief on recv buffers: Each recv buffer contains all the received arrays of a given type. The different physical quantities are stored next to each other @@ -710,12 +704,6 @@ namespace comm { if ((send_rank >= 0) and (recv_rank >= 0) and (send_count > 0) and (recv_count > 0)) { - // Debug: Print the rank and type of mpi operation performed - { - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - //printf("MPI rank: %d, Performing sendrecv operation \n", rank); - } MPI_Sendrecv(send_buffer_int_h.data(), send_count * NINTS, mpi::get_type(), @@ -765,12 +753,6 @@ namespace comm { MPI_COMM_WORLD, MPI_STATUS_IGNORE); } else if ((send_rank >= 0) and (send_count > 0)) { - // Debug: Print the rank and type of mpi operation performed - { - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - //printf("MPI rank: %d, Performing send operation \n", rank); - } MPI_Send(send_buffer_int_h.data(), send_count * NINTS, mpi::get_type(), @@ -796,12 +778,6 @@ namespace comm { 0, MPI_COMM_WORLD); } else if ((recv_rank >= 0) and (recv_count > 0)) { - // Debug: Print the rank and type of mpi operation performed - { - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - //printf("MPI rank: %d, Performing recv operation \n", rank); - } MPI_Recv(recv_buffer_int_h.data() + receive_offset_int, recv_count * NINTS, mpi::get_type(), @@ -833,59 +809,8 @@ namespace comm { } current_received += recv_count; iteration++; + - // Debug test: Print recv buffer before and after - /* - { - int total_ranks; - MPI_Comm_size(MPI_COMM_WORLD, &total_ranks); - for (int allranks=0; allranks current_offset("current_offset", species.ntags()); auto &this_tag_offset = tag_offset; - auto n_alive = npart_per_tag_arr[ParticleTag::alive]; - if constexpr (D == Dim::_1D){ Kokkos::parallel_for( "PermuteVector and Displace", @@ -781,7 +779,7 @@ namespace ntt { // tag = 1->N (excluding dead and alive) else{ const auto idx_permute_vec = this_tag_offset(current_tag) - - n_alive + + total_alive + Kokkos::atomic_fetch_add( ¤t_offset(current_tag), 1); @@ -810,7 +808,7 @@ namespace ntt { // tag = 1->N (excluding dead and alive) else{ const auto idx_permute_vec = this_tag_offset(current_tag) - - n_alive + + total_alive + Kokkos::atomic_fetch_add( ¤t_offset(current_tag), 1); @@ -841,7 +839,7 @@ namespace ntt { // tag = 1->N (excluding dead and alive) else{ const auto idx_permute_vec = this_tag_offset(current_tag) - - n_alive + + total_alive + Kokkos::atomic_fetch_add( ¤t_offset(current_tag), 1); @@ -915,42 +913,6 @@ namespace ntt { }); } - /* - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - if (rank == 1 && species.label() == "e+_b") - { - // Copy the tag array to host - auto tag_h = Kokkos::create_mirror_view(species.tag); - Kokkos::deep_copy(tag_h, species.tag); - std::cout << "Tag locs before send" << std::endl; - for (std::size_t i { 0 }; i < species.npart(); i++) { - if (tag_h(i) != ParticleTag::alive) - std::cout <<" Tag: " << tag_h(i) << " loc: "<< i << std::endl; - } - - // Print allocation vector after copying to host - auto allocation_vector_h = Kokkos::create_mirror_view(allocation_vector); - std::cout << "Total holes: " << total_holes << " Total recv: " << total_recv << std::endl; - Kokkos::deep_copy(allocation_vector_h, allocation_vector); - for (std::size_t i { 0 }; i < total_recv; ++i) { - std::cout << "Rank: " << rank << " Allocation vector: " << allocation_vector_h(i) << std::endl; - } - // Print the permute vector as well - auto permute_vector_h = Kokkos::create_mirror_view(permute_vector); - Kokkos::deep_copy(permute_vector_h, permute_vector); - for (std::size_t i { 0 }; i < total_holes; ++i) { - std::cout << "Rank: " << rank << " Permuted vector: " << permute_vector_h(i) << - " tag: " << tag_h(permute_vector_h(i)) << std::endl; - } - } - */ - { - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - std::cout << "Rank: " << rank << " Total sent: " << total_holes - total_dead << " Total recv: " << total_recv << std::endl; - } - // Communicate the arrays comm::CommunicateParticlesBuffer(species, permute_vector, allocation_vector, this_tag_offset, npart_per_tag_arr, npart_per_tag_arr_recv, @@ -959,6 +921,268 @@ namespace ntt { } } + /* + Function to remove dead particles from the domain + */ + template + void Metadomain::RemoveDeadParticles(Domain& domain, + timer::Timers* timers){ + MPI_Barrier(MPI_COMM_WORLD); + for (auto& species : domain.species) { + auto [npart_per_tag_arr, + tag_offset] = species.npart_per_tag(); + auto npart = static_cast(species.npart()); + auto total_alive = static_cast( + npart_per_tag_arr[ParticleTag::alive]); + auto total_dead = static_cast( + npart_per_tag_arr[ParticleTag::dead]); + + if (total_dead != 0){ + // Check that only alive and dead particles are present + for (std::size_t i { 0 }; i < species.ntags(); i++) { + if (i != ParticleTag::alive && i != ParticleTag::dead){ + raise::FatalIf(npart_per_tag_arr[i] != 0, + "Particle tags can only be dead or alive at this point", + HERE); + } + } + + // Get the indices of all alive particles + auto &this_ux1 = species.ux1; + auto &this_ux2 = species.ux2; + auto &this_ux3 = species.ux3; + auto &this_weight = species.weight; + auto &this_phi = species.phi; + auto &this_i1 = species.i1; + auto &this_i1_prev = species.i1_prev; + auto &this_i2 = species.i2; + auto &this_i3 = species.i3; + auto &this_i2_prev = species.i2_prev; + auto &this_i3_prev = species.i3_prev; + auto &this_dx1 = species.dx1; + auto &this_dx1_prev = species.dx1_prev; + auto &this_dx2 = species.dx2; + auto &this_dx3 = species.dx3; + auto &this_dx2_prev = species.dx2_prev; + auto &this_dx3_prev = species.dx3_prev; + auto &this_tag = species.tag; + + // Create buffers to store alive particles + Kokkos::View buffer_ctr("buffer_ctr", 1); + Kokkos::View buffer_int("buffer_int", total_alive); + Kokkos::View buffer_real("buffer_real", total_alive); + Kokkos::View buffer_prtldx("buffer_prtldx",total_alive); + + // Simulaneously update i1, u1, dx1 + Kokkos::parallel_for( + "CopyToBuffer i1 u1 dx1", + total_alive, + Lambda(index_t p) { + if (this_tag(p) == ParticleTag::alive){ + const auto idx = Kokkos::atomic_fetch_add(&buffer_ctr(0), 1); + buffer_int(idx) = this_i1(p); + buffer_real(idx) = this_ux1(p); + buffer_prtldx(idx) = this_dx1(p); + } + }); + + Kokkos::parallel_for( + "i1 u1 dx1 from Buffer", + total_alive, + Lambda(index_t p) { + this_i1(p) = buffer_int(p); + this_ux1(p) = buffer_real(p); + this_dx1(p) = buffer_prtldx(p); + }); + + // Update i1_prev, dx1_prev, u2 + Kokkos::deep_copy(buffer_ctr, 0); + Kokkos::parallel_for( + "CopyToBuffer i1_prev dx1_prev u2", + total_alive, + Lambda(index_t p) { + if (this_tag(p) == ParticleTag::alive){ + const auto idx = Kokkos::atomic_fetch_add(&buffer_ctr(0), 1); + buffer_real(idx) = this_ux2(p); + buffer_prtldx(idx) = this_dx1_prev(p); + buffer_int(idx) = this_i1_prev(p); + } + }); + + Kokkos::parallel_for( + "i1_prev u2 dx1_prev from Buffer", + total_alive, + Lambda(index_t p) { + this_i1_prev(p) = buffer_int(p); + this_ux2(p) = buffer_real(p); + this_dx1_prev(p) = buffer_prtldx(p); + }); + + // Update u3 + Kokkos::deep_copy(buffer_ctr, 0); + Kokkos::parallel_for( + "CopyToBuffer u3", + total_alive, + Lambda(index_t p) { + if (this_tag(p) == ParticleTag::alive){ + const auto idx = Kokkos::atomic_fetch_add(&buffer_ctr(0), 1); + buffer_real(idx) = this_ux3(p); + } + }); + + Kokkos::parallel_for( + "u3 from Buffer", + total_alive, + Lambda(index_t p) { + this_ux3(p) = buffer_real(p); + }); + + + // Update weight + Kokkos::deep_copy(buffer_ctr, 0); + Kokkos::parallel_for( + "CopyToBuffer weight", + total_alive, + Lambda(index_t p) { + if (this_tag(p) == ParticleTag::alive){ + const auto idx = Kokkos::atomic_fetch_add(&buffer_ctr(0), 1); + buffer_real(idx) = this_weight(p); + } + }); + + Kokkos::parallel_for( + "weight from Buffer", + total_alive, + Lambda(index_t p) { + this_weight(p) = buffer_real(p); + }); + + // Update i2, dx2, i2_prev, dx2_prev + if constexpr(D == Dim::_2D || D == Dim::_3D){ + // i2, dx2 + Kokkos::deep_copy(buffer_ctr, 0); + Kokkos::parallel_for( + "CopyToBuffer i2 dx2", + total_alive, + Lambda(index_t p) { + if (this_tag(p) == ParticleTag::alive){ + const auto idx = Kokkos::atomic_fetch_add(&buffer_ctr(0), 1); + buffer_int(idx) = this_i2(p); + buffer_prtldx(idx) = this_dx2(p); + } + }); + + Kokkos::parallel_for( + "i2 dx2 from Buffer", + total_alive, + Lambda(index_t p) { + this_i2(p) = buffer_int(p); + this_dx2(p) = buffer_prtldx(p); + }); + + // i2_prev, dx2_prev + Kokkos::deep_copy(buffer_ctr, 0); + Kokkos::parallel_for( + "CopyToBuffer i2_prev dx2_prev", + total_alive, + Lambda(index_t p) { + if (this_tag(p) == ParticleTag::alive){ + const auto idx = Kokkos::atomic_fetch_add(&buffer_ctr(0), 1); + buffer_int(idx) = this_i2_prev(p); + buffer_prtldx(idx) = this_dx2_prev(p); + } + }); + + Kokkos::parallel_for( + "i2_prev dx2_prev from Buffer", + total_alive, + Lambda(index_t p) { + this_i2_prev(p) = buffer_int(p); + this_dx2_prev(p) = buffer_prtldx(p); + }); + + } + + // Update i3, dx3, i3_prev, dx3_prev + if constexpr(D == Dim::_3D){ + // i3, dx3 + Kokkos::deep_copy(buffer_ctr, 0); + Kokkos::parallel_for( + "CopyToBuffer i3 dx3", + total_alive, + Lambda(index_t p) { + if (this_tag(p) == ParticleTag::alive){ + const auto idx = Kokkos::atomic_fetch_add(&buffer_ctr(0), 1); + buffer_int(idx) = this_i3(p); + buffer_prtldx(idx) = this_dx3(p); + } + }); + + Kokkos::parallel_for( + "i3 dx3 from Buffer", + total_alive, + Lambda(index_t p) { + this_i3(p) = buffer_int(p); + this_dx3(p) = buffer_prtldx(p); + }); + + // i3_prev, dx3_prev + Kokkos::deep_copy(buffer_ctr, 0); + Kokkos::parallel_for( + "CopyToBuffer i3_prev dx3_prev", + total_alive, + Lambda(index_t p) { + if (this_tag(p) == ParticleTag::alive){ + const auto idx = Kokkos::atomic_fetch_add(&buffer_ctr(0), 1); + buffer_int(idx) = this_i3_prev(p); + buffer_prtldx(idx) = this_dx3_prev(p); + } + }); + + Kokkos::parallel_for( + "i3_prev dx3_prev from Buffer", + total_alive, + Lambda(index_t p) { + this_i3_prev(p) = buffer_int(p); + this_dx3_prev(p) = buffer_prtldx(p); + }); + } + + // phi + if constexpr(D == Dim::_2D && M::CoordType != Coord::Cart){ + Kokkos::deep_copy(buffer_ctr, 0); + Kokkos::parallel_for( + "CopyToBuffer phi", + total_alive, + Lambda(index_t p) { + if (this_tag(p) == ParticleTag::alive){ + const auto idx = Kokkos::atomic_fetch_add(&buffer_ctr(0), 1); + buffer_real(idx) = this_phi(p); + } + }); + + Kokkos::parallel_for( + "phi from Buffer", + total_alive, + Lambda(index_t p) { + this_phi(p) = buffer_real(p); + }); + + } + + // tags + Kokkos::parallel_for( + "Make tags alive", + total_alive, + Lambda(index_t p) { + this_tag(p) = ParticleTag::alive; + }); + species.set_npart(total_alive); + } + } + return; + } + template struct Metadomain>; template struct Metadomain>; template struct Metadomain>; diff --git a/src/framework/domain/metadomain.h b/src/framework/domain/metadomain.h index 9e94bf89f..6bd3d29d8 100644 --- a/src/framework/domain/metadomain.h +++ b/src/framework/domain/metadomain.h @@ -91,6 +91,7 @@ namespace ntt { void CommunicateParticles(Domain&, timer::Timers*); void CommunicateParticlesBuffer(Domain&, timer::Timers*); void SetParticleIDs(Domain&); + void RemoveDeadParticles(Domain&, timer::Timers* ); /** * @param global_ndomains total number of domains From 39f6c9f64f5dd9f5df34734036277ecf81a57c84 Mon Sep 17 00:00:00 2001 From: Siddhant Solanki Date: Sun, 5 Jan 2025 23:44:32 -0500 Subject: [PATCH 212/773] testing: remove dead prtls --- src/engines/srpic.hpp | 2 +- src/framework/domain/comm_mpi.hpp | 27 ++ src/framework/domain/communications.cpp | 348 ++++++++---------------- 3 files changed, 138 insertions(+), 239 deletions(-) diff --git a/src/engines/srpic.hpp b/src/engines/srpic.hpp index 686ed0c35..b54327076 100644 --- a/src/engines/srpic.hpp +++ b/src/engines/srpic.hpp @@ -176,7 +176,7 @@ namespace ntt { timers.stop("Injector"); } - if (step % 10 == 0 && step > 0){ + if (step % 100 == 0 && step > 0){ timers.start("RemoveDead"); m_metadomain.RemoveDeadParticles(dom, &timers); diff --git a/src/framework/domain/comm_mpi.hpp b/src/framework/domain/comm_mpi.hpp index 7b9a22eee..aa35ce2a6 100644 --- a/src/framework/domain/comm_mpi.hpp +++ b/src/framework/domain/comm_mpi.hpp @@ -918,6 +918,33 @@ namespace comm { return; } +/* + Function to copy the alive particle data the arrays to a buffer and then back + to the particle arrays +*/ + template + void MoveDeadToEnd(array_t& arr, + Kokkos::View indices_alive) { + auto n_alive = indices_alive.extent(0); + auto buffer = Kokkos::View("buffer", n_alive); + Kokkos::parallel_for( + "PopulateBufferAlive", + n_alive, + Lambda(const std::size_t p) { + buffer(p) = arr(indices_alive(p)); + }); + + Kokkos::parallel_for( + "CopyBufferToArr", + n_alive, + Lambda(const std::size_t p) { + arr(p) = buffer(p); + }); + + return; + } + + } // namespace comm #endif // FRAMEWORK_DOMAIN_COMM_MPI_HPP diff --git a/src/framework/domain/communications.cpp b/src/framework/domain/communications.cpp index 433a97fb8..ee0d37f10 100644 --- a/src/framework/domain/communications.cpp +++ b/src/framework/domain/communications.cpp @@ -927,7 +927,6 @@ namespace ntt { template void Metadomain::RemoveDeadParticles(Domain& domain, timer::Timers* timers){ - MPI_Barrier(MPI_COMM_WORLD); for (auto& species : domain.species) { auto [npart_per_tag_arr, tag_offset] = species.npart_per_tag(); @@ -936,250 +935,123 @@ namespace ntt { npart_per_tag_arr[ParticleTag::alive]); auto total_dead = static_cast( npart_per_tag_arr[ParticleTag::dead]); - - if (total_dead != 0){ - // Check that only alive and dead particles are present - for (std::size_t i { 0 }; i < species.ntags(); i++) { - if (i != ParticleTag::alive && i != ParticleTag::dead){ - raise::FatalIf(npart_per_tag_arr[i] != 0, - "Particle tags can only be dead or alive at this point", - HERE); - } - } - - // Get the indices of all alive particles - auto &this_ux1 = species.ux1; - auto &this_ux2 = species.ux2; - auto &this_ux3 = species.ux3; - auto &this_weight = species.weight; - auto &this_phi = species.phi; - auto &this_i1 = species.i1; - auto &this_i1_prev = species.i1_prev; - auto &this_i2 = species.i2; - auto &this_i3 = species.i3; - auto &this_i2_prev = species.i2_prev; - auto &this_i3_prev = species.i3_prev; - auto &this_dx1 = species.dx1; - auto &this_dx1_prev = species.dx1_prev; - auto &this_dx2 = species.dx2; - auto &this_dx3 = species.dx3; - auto &this_dx2_prev = species.dx2_prev; - auto &this_dx3_prev = species.dx3_prev; - auto &this_tag = species.tag; - - // Create buffers to store alive particles - Kokkos::View buffer_ctr("buffer_ctr", 1); - Kokkos::View buffer_int("buffer_int", total_alive); - Kokkos::View buffer_real("buffer_real", total_alive); - Kokkos::View buffer_prtldx("buffer_prtldx",total_alive); - - // Simulaneously update i1, u1, dx1 - Kokkos::parallel_for( - "CopyToBuffer i1 u1 dx1", - total_alive, - Lambda(index_t p) { - if (this_tag(p) == ParticleTag::alive){ - const auto idx = Kokkos::atomic_fetch_add(&buffer_ctr(0), 1); - buffer_int(idx) = this_i1(p); - buffer_real(idx) = this_ux1(p); - buffer_prtldx(idx) = this_dx1(p); - } - }); - - Kokkos::parallel_for( - "i1 u1 dx1 from Buffer", - total_alive, - Lambda(index_t p) { - this_i1(p) = buffer_int(p); - this_ux1(p) = buffer_real(p); - this_dx1(p) = buffer_prtldx(p); - }); - - // Update i1_prev, dx1_prev, u2 - Kokkos::deep_copy(buffer_ctr, 0); - Kokkos::parallel_for( - "CopyToBuffer i1_prev dx1_prev u2", - total_alive, - Lambda(index_t p) { - if (this_tag(p) == ParticleTag::alive){ - const auto idx = Kokkos::atomic_fetch_add(&buffer_ctr(0), 1); - buffer_real(idx) = this_ux2(p); - buffer_prtldx(idx) = this_dx1_prev(p); - buffer_int(idx) = this_i1_prev(p); - } - }); - - Kokkos::parallel_for( - "i1_prev u2 dx1_prev from Buffer", - total_alive, - Lambda(index_t p) { - this_i1_prev(p) = buffer_int(p); - this_ux2(p) = buffer_real(p); - this_dx1_prev(p) = buffer_prtldx(p); - }); - - // Update u3 - Kokkos::deep_copy(buffer_ctr, 0); - Kokkos::parallel_for( - "CopyToBuffer u3", - total_alive, - Lambda(index_t p) { - if (this_tag(p) == ParticleTag::alive){ - const auto idx = Kokkos::atomic_fetch_add(&buffer_ctr(0), 1); - buffer_real(idx) = this_ux3(p); - } - }); - - Kokkos::parallel_for( - "u3 from Buffer", - total_alive, - Lambda(index_t p) { - this_ux3(p) = buffer_real(p); - }); - - - // Update weight - Kokkos::deep_copy(buffer_ctr, 0); - Kokkos::parallel_for( - "CopyToBuffer weight", - total_alive, - Lambda(index_t p) { - if (this_tag(p) == ParticleTag::alive){ - const auto idx = Kokkos::atomic_fetch_add(&buffer_ctr(0), 1); - buffer_real(idx) = this_weight(p); - } - }); - - Kokkos::parallel_for( - "weight from Buffer", - total_alive, - Lambda(index_t p) { - this_weight(p) = buffer_real(p); - }); - - // Update i2, dx2, i2_prev, dx2_prev - if constexpr(D == Dim::_2D || D == Dim::_3D){ - // i2, dx2 - Kokkos::deep_copy(buffer_ctr, 0); - Kokkos::parallel_for( - "CopyToBuffer i2 dx2", - total_alive, - Lambda(index_t p) { - if (this_tag(p) == ParticleTag::alive){ - const auto idx = Kokkos::atomic_fetch_add(&buffer_ctr(0), 1); - buffer_int(idx) = this_i2(p); - buffer_prtldx(idx) = this_dx2(p); - } - }); - - Kokkos::parallel_for( - "i2 dx2 from Buffer", - total_alive, - Lambda(index_t p) { - this_i2(p) = buffer_int(p); - this_dx2(p) = buffer_prtldx(p); - }); - - // i2_prev, dx2_prev - Kokkos::deep_copy(buffer_ctr, 0); - Kokkos::parallel_for( - "CopyToBuffer i2_prev dx2_prev", - total_alive, - Lambda(index_t p) { - if (this_tag(p) == ParticleTag::alive){ - const auto idx = Kokkos::atomic_fetch_add(&buffer_ctr(0), 1); - buffer_int(idx) = this_i2_prev(p); - buffer_prtldx(idx) = this_dx2_prev(p); - } - }); - - Kokkos::parallel_for( - "i2_prev dx2_prev from Buffer", - total_alive, - Lambda(index_t p) { - this_i2_prev(p) = buffer_int(p); - this_dx2_prev(p) = buffer_prtldx(p); - }); + // Check that only alive and dead particles are present + for (std::size_t i { 0 }; i < species.ntags(); i++) { + if (i != ParticleTag::alive && i != ParticleTag::dead){ + raise::FatalIf(npart_per_tag_arr[i] != 0, + "Particle tags can only be dead or alive at this point", + HERE); } - - // Update i3, dx3, i3_prev, dx3_prev - if constexpr(D == Dim::_3D){ - // i3, dx3 - Kokkos::deep_copy(buffer_ctr, 0); - Kokkos::parallel_for( - "CopyToBuffer i3 dx3", - total_alive, - Lambda(index_t p) { - if (this_tag(p) == ParticleTag::alive){ - const auto idx = Kokkos::atomic_fetch_add(&buffer_ctr(0), 1); - buffer_int(idx) = this_i3(p); - buffer_prtldx(idx) = this_dx3(p); - } - }); - - Kokkos::parallel_for( - "i3 dx3 from Buffer", - total_alive, - Lambda(index_t p) { - this_i3(p) = buffer_int(p); - this_dx3(p) = buffer_prtldx(p); - }); - - // i3_prev, dx3_prev - Kokkos::deep_copy(buffer_ctr, 0); - Kokkos::parallel_for( - "CopyToBuffer i3_prev dx3_prev", - total_alive, - Lambda(index_t p) { - if (this_tag(p) == ParticleTag::alive){ - const auto idx = Kokkos::atomic_fetch_add(&buffer_ctr(0), 1); - buffer_int(idx) = this_i3_prev(p); - buffer_prtldx(idx) = this_dx3_prev(p); + } + { + int rank, totranks; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Comm_size(MPI_COMM_WORLD, &totranks); + for (std::size_t current_rank=0; current_rank indices_alive("indices_alive", total_alive); + Kokkos::View alive_counter("counter_alive", 1); + Kokkos::deep_copy(alive_counter, 0); + Kokkos::parallel_for( + "Indices of Alive Particles", + species.npart(), + Lambda(index_t p) { + if (this_tag(p) == ParticleTag::alive){ + const auto idx = Kokkos::atomic_fetch_add(&alive_counter(0), 1); + indices_alive(idx) = p; } - - // tags - Kokkos::parallel_for( - "Make tags alive", - total_alive, - Lambda(index_t p) { - this_tag(p) = ParticleTag::alive; - }); - species.set_npart(total_alive); + }); + // Sanity check: alive_counter must be equal to total_alive + auto alive_counter_h = Kokkos::create_mirror_view(alive_counter); + Kokkos::deep_copy(alive_counter_h, alive_counter); + raise::FatalIf(alive_counter_h(0) != total_alive, + "Error in finding alive particles", + HERE); + comm::MoveDeadToEnd(species.i1, indices_alive); + comm::MoveDeadToEnd(species.i1_prev, indices_alive); + comm::MoveDeadToEnd(species.dx1_prev, indices_alive); + comm::MoveDeadToEnd(species.ux1, indices_alive); + comm::MoveDeadToEnd(species.ux2, indices_alive); + comm::MoveDeadToEnd(species.ux3, indices_alive); + comm::MoveDeadToEnd(species.weight, indices_alive); + // Update i2, dx2, i2_prev, dx2_prev + if constexpr(D == Dim::_2D || D == Dim::_3D){ + comm::MoveDeadToEnd(species.i2, indices_alive); + comm::MoveDeadToEnd(species.i2_prev, indices_alive); + comm::MoveDeadToEnd(species.dx2, indices_alive); + comm::MoveDeadToEnd(species.dx2_prev, indices_alive); + if constexpr(D == Dim::_2D && M::CoordType != Coord::Cart){ + comm::MoveDeadToEnd(species.phi, indices_alive); + } } + // Update i3, dx3, i3_prev, dx3_prev + if constexpr(D == Dim::_3D){ + comm::MoveDeadToEnd(species.i3, indices_alive); + comm::MoveDeadToEnd(species.i3_prev, indices_alive); + comm::MoveDeadToEnd(species.dx3, indices_alive); + comm::MoveDeadToEnd(species.dx3_prev, indices_alive); + } + // tags + Kokkos::parallel_for( + "Make tags alive", + total_alive, + Lambda(index_t p) { + this_tag(p) = ParticleTag::alive; + }); + species.set_npart(total_alive); + + + int rank, totranks; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Comm_size(MPI_COMM_WORLD, &totranks); + for (std::size_t current_rank=0; current_rank Date: Mon, 6 Jan 2025 01:39:18 -0500 Subject: [PATCH 213/773] testing removedeadparticles() --- src/framework/domain/communications.cpp | 79 +++++++++++++++++++++---- 1 file changed, 66 insertions(+), 13 deletions(-) diff --git a/src/framework/domain/communications.cpp b/src/framework/domain/communications.cpp index ee0d37f10..6450aa4b7 100644 --- a/src/framework/domain/communications.cpp +++ b/src/framework/domain/communications.cpp @@ -923,6 +923,33 @@ namespace ntt { /* Function to remove dead particles from the domain + + Consider the following particle quantity array + <---xxx---x---xx---xx-----------xx----x--> (qty) + - = alive + x = dead + ntot = nalive + ndead + + (1) Copy all alive particle data to buffer + <---xxx---x---xx---xx-----------xx----x--> (qty) + | + | + v + <--------------------------> buffer + (nalive) + + (2) Copy from buffer to the beginning of the array + overwritting all particles + <--------------------------> buffer + (nalive) + | + | + v + <--------------------------xx----x--> (qty) + ^ + (nalive) + + (3) Set npart to nalive */ template void Metadomain::RemoveDeadParticles(Domain& domain, @@ -930,11 +957,11 @@ namespace ntt { for (auto& species : domain.species) { auto [npart_per_tag_arr, tag_offset] = species.npart_per_tag(); - auto npart = static_cast(species.npart()); - auto total_alive = static_cast( - npart_per_tag_arr[ParticleTag::alive]); - auto total_dead = static_cast( - npart_per_tag_arr[ParticleTag::dead]); + const auto npart = static_cast(species.npart()); + const auto total_alive = static_cast( + npart_per_tag_arr[ParticleTag::alive]); + const auto total_dead = static_cast( + npart_per_tag_arr[ParticleTag::dead]); // Check that only alive and dead particles are present for (std::size_t i { 0 }; i < species.ntags(); i++) { @@ -945,6 +972,14 @@ namespace ntt { } } { + auto [npart_per_tag_arr_, + tag_offset_] = species.npart_per_tag(); + auto npart_ = static_cast(species.npart()); + auto total_alive_ = static_cast( + npart_per_tag_arr_[ParticleTag::alive]); + auto total_dead_ = static_cast( + npart_per_tag_arr_[ParticleTag::dead]); + int rank, totranks; MPI_Comm_rank(MPI_COMM_WORLD, &rank); MPI_Comm_size(MPI_COMM_WORLD, &totranks); @@ -952,8 +987,8 @@ namespace ntt { if (rank == current_rank && species.label() == "e-_p"){ std::cout << "Before removing dead particles" << std::endl; std::cout << "Rank: " << rank << std::endl; - std::cout << "Total alive: " << total_alive << std::endl; - std::cout << "Total dead: " << total_dead << std::endl; + std::cout << "Total alive: " << total_alive_ << std::endl; + std::cout << "Total dead: " << total_dead_ << std::endl; std::cout << "Total particles: " << npart << std::endl; for (std::size_t i { 0 }; i < species.ntags(); i++) { std::cout << "Tag: " << i << " count: " << npart_per_tag_arr[i] << std::endl; @@ -1000,6 +1035,7 @@ namespace ntt { raise::FatalIf(alive_counter_h(0) != total_alive, "Error in finding alive particles", HERE); + comm::MoveDeadToEnd(species.i1, indices_alive); comm::MoveDeadToEnd(species.i1_prev, indices_alive); comm::MoveDeadToEnd(species.dx1_prev, indices_alive); @@ -1024,25 +1060,41 @@ namespace ntt { comm::MoveDeadToEnd(species.dx3, indices_alive); comm::MoveDeadToEnd(species.dx3_prev, indices_alive); } - // tags + // tags (set first total_alive to alive and rest to dead) Kokkos::parallel_for( "Make tags alive", total_alive, Lambda(index_t p) { this_tag(p) = ParticleTag::alive; }); + + Kokkos::parallel_for( + "Make tags dead", + total_dead, + Lambda(index_t p) { + this_tag(total_alive + p) = ParticleTag::dead; + }); + species.set_npart(total_alive); - - + + { + auto [npart_per_tag_arr_, + tag_offset_] = species.npart_per_tag(); + auto npart_ = static_cast(species.npart()); + auto total_alive_ = static_cast( + npart_per_tag_arr_[ParticleTag::alive]); + auto total_dead_ = static_cast( + npart_per_tag_arr_[ParticleTag::dead]); + int rank, totranks; MPI_Comm_rank(MPI_COMM_WORLD, &rank); MPI_Comm_size(MPI_COMM_WORLD, &totranks); for (std::size_t current_rank=0; current_rank Date: Mon, 6 Jan 2025 23:17:18 -0500 Subject: [PATCH 214/773] fixed dead particle removal bug --- src/engines/srpic.hpp | 5 +- src/framework/domain/comm_mpi.hpp | 27 ------ src/framework/domain/communications.cpp | 112 ++++++++++++++++-------- 3 files changed, 77 insertions(+), 67 deletions(-) diff --git a/src/engines/srpic.hpp b/src/engines/srpic.hpp index b54327076..fd1ca226a 100644 --- a/src/engines/srpic.hpp +++ b/src/engines/srpic.hpp @@ -176,11 +176,12 @@ namespace ntt { timers.stop("Injector"); } - if (step % 100 == 0 && step > 0){ - + if (step % 1 == 0 && step > 0){ + MPI_Barrier(MPI_COMM_WORLD); timers.start("RemoveDead"); m_metadomain.RemoveDeadParticles(dom, &timers); timers.stop("RemoveDead"); + MPI_Barrier(MPI_COMM_WORLD); } } diff --git a/src/framework/domain/comm_mpi.hpp b/src/framework/domain/comm_mpi.hpp index aa35ce2a6..7b9a22eee 100644 --- a/src/framework/domain/comm_mpi.hpp +++ b/src/framework/domain/comm_mpi.hpp @@ -918,33 +918,6 @@ namespace comm { return; } -/* - Function to copy the alive particle data the arrays to a buffer and then back - to the particle arrays -*/ - template - void MoveDeadToEnd(array_t& arr, - Kokkos::View indices_alive) { - auto n_alive = indices_alive.extent(0); - auto buffer = Kokkos::View("buffer", n_alive); - Kokkos::parallel_for( - "PopulateBufferAlive", - n_alive, - Lambda(const std::size_t p) { - buffer(p) = arr(indices_alive(p)); - }); - - Kokkos::parallel_for( - "CopyBufferToArr", - n_alive, - Lambda(const std::size_t p) { - arr(p) = buffer(p); - }); - - return; - } - - } // namespace comm #endif // FRAMEWORK_DOMAIN_COMM_MPI_HPP diff --git a/src/framework/domain/communications.cpp b/src/framework/domain/communications.cpp index 6450aa4b7..9f7b088f0 100644 --- a/src/framework/domain/communications.cpp +++ b/src/framework/domain/communications.cpp @@ -921,6 +921,32 @@ namespace ntt { } } + +/* + Function to copy the alive particle data the arrays to a buffer and then back + to the particle arrays +*/ + template + void MoveDeadToEnd(array_t& arr, + Kokkos::View indices_alive) { + auto n_alive = indices_alive.extent(0); + auto buffer = Kokkos::View("buffer", n_alive); + Kokkos::parallel_for( + "PopulateBufferAlive", + n_alive, + Lambda(const std::size_t p) { + buffer(p) = arr(indices_alive(p)); + }); + + Kokkos::parallel_for( + "CopyBufferToArr", + n_alive, + Lambda(const std::size_t p) { + arr(p) = buffer(p); + }); + return; + } + /* Function to remove dead particles from the domain @@ -989,33 +1015,33 @@ namespace ntt { std::cout << "Rank: " << rank << std::endl; std::cout << "Total alive: " << total_alive_ << std::endl; std::cout << "Total dead: " << total_dead_ << std::endl; - std::cout << "Total particles: " << npart << std::endl; + std::cout << "Total particles: " << npart_ << std::endl; for (std::size_t i { 0 }; i < species.ntags(); i++) { - std::cout << "Tag: " << i << " count: " << npart_per_tag_arr[i] << std::endl; + std::cout << "Tag: " << i << " count: " << npart_per_tag_arr_[i] << std::endl; } } MPI_Barrier(MPI_COMM_WORLD); } } // Get the indices of all alive particles - auto &this_ux1 = species.ux1; - auto &this_ux2 = species.ux2; - auto &this_ux3 = species.ux3; - auto &this_weight = species.weight; - auto &this_phi = species.phi; - auto &this_i1 = species.i1; - auto &this_i1_prev = species.i1_prev; - auto &this_i2 = species.i2; - auto &this_i3 = species.i3; - auto &this_i2_prev = species.i2_prev; - auto &this_i3_prev = species.i3_prev; - auto &this_dx1 = species.dx1; - auto &this_dx1_prev = species.dx1_prev; - auto &this_dx2 = species.dx2; - auto &this_dx3 = species.dx3; - auto &this_dx2_prev = species.dx2_prev; - auto &this_dx3_prev = species.dx3_prev; - auto &this_tag = species.tag; + auto &this_i1 = species.i1; + auto &this_i2 = species.i2; + auto &this_i3 = species.i3; + auto &this_i1_prev = species.i1_prev; + auto &this_i2_prev = species.i2_prev; + auto &this_i3_prev = species.i3_prev; + auto &this_dx1 = species.dx1; + auto &this_dx2 = species.dx2; + auto &this_dx3 = species.dx3; + auto &this_dx1_prev = species.dx1_prev; + auto &this_dx2_prev = species.dx2_prev; + auto &this_dx3_prev = species.dx3_prev; + auto &this_ux1 = species.ux1; + auto &this_ux2 = species.ux2; + auto &this_ux3 = species.ux3; + auto &this_weight = species.weight; + auto &this_phi = species.phi; + auto &this_tag = species.tag; // Find indices of tag = alive particles Kokkos::View indices_alive("indices_alive", total_alive); Kokkos::View alive_counter("counter_alive", 1); @@ -1036,29 +1062,29 @@ namespace ntt { "Error in finding alive particles", HERE); - comm::MoveDeadToEnd(species.i1, indices_alive); - comm::MoveDeadToEnd(species.i1_prev, indices_alive); - comm::MoveDeadToEnd(species.dx1_prev, indices_alive); - comm::MoveDeadToEnd(species.ux1, indices_alive); - comm::MoveDeadToEnd(species.ux2, indices_alive); - comm::MoveDeadToEnd(species.ux3, indices_alive); - comm::MoveDeadToEnd(species.weight, indices_alive); + MoveDeadToEnd(species.i1, indices_alive); + MoveDeadToEnd(species.dx1, indices_alive); + MoveDeadToEnd(species.dx1_prev, indices_alive); + MoveDeadToEnd(species.ux1, indices_alive); + MoveDeadToEnd(species.ux2, indices_alive); + MoveDeadToEnd(species.ux3, indices_alive); + MoveDeadToEnd(species.weight, indices_alive); // Update i2, dx2, i2_prev, dx2_prev if constexpr(D == Dim::_2D || D == Dim::_3D){ - comm::MoveDeadToEnd(species.i2, indices_alive); - comm::MoveDeadToEnd(species.i2_prev, indices_alive); - comm::MoveDeadToEnd(species.dx2, indices_alive); - comm::MoveDeadToEnd(species.dx2_prev, indices_alive); + MoveDeadToEnd(species.i2, indices_alive); + MoveDeadToEnd(species.i2_prev, indices_alive); + MoveDeadToEnd(species.dx2, indices_alive); + MoveDeadToEnd(species.dx2_prev, indices_alive); if constexpr(D == Dim::_2D && M::CoordType != Coord::Cart){ - comm::MoveDeadToEnd(species.phi, indices_alive); + MoveDeadToEnd(species.phi, indices_alive); } } // Update i3, dx3, i3_prev, dx3_prev if constexpr(D == Dim::_3D){ - comm::MoveDeadToEnd(species.i3, indices_alive); - comm::MoveDeadToEnd(species.i3_prev, indices_alive); - comm::MoveDeadToEnd(species.dx3, indices_alive); - comm::MoveDeadToEnd(species.dx3_prev, indices_alive); + MoveDeadToEnd(species.i3, indices_alive); + MoveDeadToEnd(species.i3_prev, indices_alive); + MoveDeadToEnd(species.dx3, indices_alive); + MoveDeadToEnd(species.dx3_prev, indices_alive); } // tags (set first total_alive to alive and rest to dead) Kokkos::parallel_for( @@ -1077,6 +1103,16 @@ namespace ntt { species.set_npart(total_alive); + std::tie(npart_per_tag_arr, + tag_offset) = species.npart_per_tag(); + raise::FatalIf(npart_per_tag_arr[ParticleTag::alive] != total_alive, + "Error in removing dead particles: alive count doesn't match", + HERE); + raise::FatalIf(npart_per_tag_arr[ParticleTag::dead] != 0, + "Error in removing dead particles: not all particles are dead", + HERE); + + { auto [npart_per_tag_arr_, tag_offset_] = species.npart_per_tag(); @@ -1095,9 +1131,9 @@ namespace ntt { std::cout << "Rank: " << rank << std::endl; std::cout << "Total alive: " << total_alive_ << std::endl; std::cout << "Total dead: " << total_dead_ << std::endl; - std::cout << "Total particles: " << npart << std::endl; + std::cout << "Total particles: " << npart_ << std::endl; for (std::size_t i { 0 }; i < species.ntags(); i++) { - std::cout << "Tag: " << i << " count: " << npart_per_tag_arr[i] << std::endl; + std::cout << "Tag: " << i << " count: " << npart_per_tag_arr_[i] << std::endl; } } MPI_Barrier(MPI_COMM_WORLD); From c719c1f8bcee71d9300ed7b537f2a7b6e2a30f70 Mon Sep 17 00:00:00 2001 From: Siddhant Solanki Date: Tue, 7 Jan 2025 06:59:25 -0500 Subject: [PATCH 215/773] print mpi ranks during sendrecv --- src/framework/domain/comm_mpi.hpp | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/framework/domain/comm_mpi.hpp b/src/framework/domain/comm_mpi.hpp index 7b9a22eee..cb3e18caa 100644 --- a/src/framework/domain/comm_mpi.hpp +++ b/src/framework/domain/comm_mpi.hpp @@ -564,6 +564,31 @@ namespace comm { auto iteration = 0; auto current_received = 0; + + { + // For debugging purposes + // Loop over all mpi processes + int rank, maxranks; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Comm_size(MPI_COMM_WORLD, &maxranks); + for (auto i = 0; i < maxranks; ++i) { + MPI_Barrier(MPI_COMM_WORLD); + if (rank == i) { + for (auto &direction : dir::Directions::all){ + const auto send_rank = send_ranks[iteration]; + const auto recv_rank = recv_ranks[iteration]; + const auto tag_recv = mpi::PrtlSendTag::dir2tag(-direction); + const auto send_count = npart_per_tag_arr[tag_send]; + const auto recv_count = npart_per_tag_arr_recv[tag_recv]; + printf("Current MPI rank %d, send rank %d recv rank %d, ", rank, + send_rank, recv_rank); + printf("send count %d, recv count %d\n", send_count, recv_count); + } + } + } + } + + for (auto& direction : dir::Directions::all) { const auto send_rank = send_ranks[iteration]; const auto recv_rank = recv_ranks[iteration]; From e43b7162d2f3e8d76df28d841140d75005d66d4e Mon Sep 17 00:00:00 2001 From: Siddhant Solanki Date: Tue, 7 Jan 2025 11:53:24 -0500 Subject: [PATCH 216/773] changed communications in fields --- src/framework/domain/comm_mpi.hpp | 216 +++++++++++-------- src/framework/domain/communications.cpp | 265 ++++-------------------- 2 files changed, 173 insertions(+), 308 deletions(-) diff --git a/src/framework/domain/comm_mpi.hpp b/src/framework/domain/comm_mpi.hpp index cb3e18caa..1395c8191 100644 --- a/src/framework/domain/comm_mpi.hpp +++ b/src/framework/domain/comm_mpi.hpp @@ -182,16 +182,13 @@ namespace comm { } } - auto send_fld_h = Kokkos::create_mirror_view(send_fld); - auto recv_fld_h = Kokkos::create_mirror_view(recv_fld); - Kokkos::deep_copy(send_fld_h, send_fld); if (send_rank >= 0 && recv_rank >= 0) { - MPI_Sendrecv(send_fld_h.data(), + MPI_Sendrecv(send_fld.data(), nsend, mpi::get_type(), send_rank, 0, - recv_fld_h.data(), + recv_fld.data(), nrecv, mpi::get_type(), recv_rank, @@ -199,7 +196,7 @@ namespace comm { MPI_COMM_WORLD, MPI_STATUS_IGNORE); } else if (send_rank >= 0) { - MPI_Send(send_fld_h.data(), + MPI_Send(send_fld.data(), nsend, mpi::get_type(), send_rank, @@ -207,8 +204,7 @@ namespace comm { MPI_COMM_WORLD); } else if (recv_rank >= 0) { - auto recv_fld_h = Kokkos::create_mirror_view(recv_fld); - MPI_Recv(recv_fld_h.data(), + MPI_Recv(recv_fld.data(), nrecv, mpi::get_type(), recv_rank, @@ -218,7 +214,6 @@ namespace comm { } else { raise::Error("CommunicateField called with negative ranks", HERE); } - Kokkos::deep_copy(recv_fld, recv_fld_h); if (recv_rank >= 0) { @@ -297,67 +292,35 @@ namespace comm { const range_tuple_t& recv_slice) { const std::size_t send_count = send_slice.second - send_slice.first; const std::size_t recv_count = recv_slice.second - recv_slice.first; - // Make arrays on the host - auto send_arr_h = Kokkos::create_mirror_view(Kokkos::subview(arr, send_slice)); - Kokkos::deep_copy(send_arr_h, Kokkos::subview(arr, send_slice)); - auto recv_arr_h = Kokkos::create_mirror_view(Kokkos::subview(arr, recv_slice)); if ((send_rank >= 0) and (recv_rank >= 0) and (send_count > 0) and (recv_count > 0)) { - MPI_Sendrecv(send_arr_h.data(), + MPI_Sendrecv(arr.data() + send_slice.first, send_count, mpi::get_type(), send_rank, 0, - recv_arr_h.data(), + arr.data() + recv_slice.first, recv_count, mpi::get_type(), recv_rank, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE); - //MPI_Sendrecv(arr.data() + send_slice.first, - // send_count, - // mpi::get_type(), - // send_rank, - // 0, - // arr.data() + recv_slice.first, - // recv_count, - // mpi::get_type(), - // recv_rank, - // 0, - // MPI_COMM_WORLD, - // MPI_STATUS_IGNORE); } else if ((send_rank >= 0) and (send_count > 0)) { - MPI_Send( send_arr_h.data(), - send_count, - mpi::get_type(), - send_rank, - 0, - MPI_COMM_WORLD); - //MPI_Send(arr.data() + send_slice.first, - // send_count, - // mpi::get_type(), - // send_rank, - // 0, - // MPI_COMM_WORLD); + MPI_Send(arr.data() + send_slice.first, + send_count, + mpi::get_type(), + send_rank, + 0, + MPI_COMM_WORLD); } else if ((recv_rank >= 0) and (recv_count > 0)) { - MPI_Recv( recv_arr_h.data(), - recv_count, - mpi::get_type(), - recv_rank, - 0, - MPI_COMM_WORLD, - MPI_STATUS_IGNORE); - //MPI_Recv(arr.data() + recv_slice.first, - // recv_count, - // mpi::get_type(), - // recv_rank, - // 0, - // MPI_COMM_WORLD, - // MPI_STATUS_IGNORE); - } - if ((recv_rank >= 0) and (recv_count > 0)) { - Kokkos::deep_copy(Kokkos::subview(arr, recv_slice), recv_arr_h); + MPI_Recv(arr.data() + recv_slice.first, + recv_count, + mpi::get_type(), + recv_rank, + 0, + MPI_COMM_WORLD, + MPI_STATUS_IGNORE); } } @@ -544,6 +507,12 @@ namespace comm { const auto n_alive = npart_per_tag_arr[ParticleTag::alive]; const auto n_dead = npart_per_tag_arr[ParticleTag::dead]; + // Debug test: print send and recv count + { + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + //printf("MPI rank: %d, Total send: %d, Total recv: %d \n", rank, total_send, total_recv); + } /* Brief on recv buffers: Each recv buffer contains all the received arrays of a given type. The different physical quantities are stored next to each other @@ -564,31 +533,6 @@ namespace comm { auto iteration = 0; auto current_received = 0; - - { - // For debugging purposes - // Loop over all mpi processes - int rank, maxranks; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - MPI_Comm_size(MPI_COMM_WORLD, &maxranks); - for (auto i = 0; i < maxranks; ++i) { - MPI_Barrier(MPI_COMM_WORLD); - if (rank == i) { - for (auto &direction : dir::Directions::all){ - const auto send_rank = send_ranks[iteration]; - const auto recv_rank = recv_ranks[iteration]; - const auto tag_recv = mpi::PrtlSendTag::dir2tag(-direction); - const auto send_count = npart_per_tag_arr[tag_send]; - const auto recv_count = npart_per_tag_arr_recv[tag_recv]; - printf("Current MPI rank %d, send rank %d recv rank %d, ", rank, - send_rank, recv_rank); - printf("send count %d, recv count %d\n", send_count, recv_count); - } - } - } - } - - for (auto& direction : dir::Directions::all) { const auto send_rank = send_ranks[iteration]; const auto recv_rank = recv_ranks[iteration]; @@ -729,6 +673,12 @@ namespace comm { if ((send_rank >= 0) and (recv_rank >= 0) and (send_count > 0) and (recv_count > 0)) { + // Debug: Print the rank and type of mpi operation performed + { + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + //printf("MPI rank: %d, Performing sendrecv operation \n", rank); + } MPI_Sendrecv(send_buffer_int_h.data(), send_count * NINTS, mpi::get_type(), @@ -778,6 +728,12 @@ namespace comm { MPI_COMM_WORLD, MPI_STATUS_IGNORE); } else if ((send_rank >= 0) and (send_count > 0)) { + // Debug: Print the rank and type of mpi operation performed + { + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + //printf("MPI rank: %d, Performing send operation \n", rank); + } MPI_Send(send_buffer_int_h.data(), send_count * NINTS, mpi::get_type(), @@ -803,6 +759,12 @@ namespace comm { 0, MPI_COMM_WORLD); } else if ((recv_rank >= 0) and (recv_count > 0)) { + // Debug: Print the rank and type of mpi operation performed + { + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + //printf("MPI rank: %d, Performing recv operation \n", rank); + } MPI_Recv(recv_buffer_int_h.data() + receive_offset_int, recv_count * NINTS, mpi::get_type(), @@ -834,8 +796,59 @@ namespace comm { } current_received += recv_count; iteration++; - + // Debug test: Print recv buffer before and after + /* + { + int total_ranks; + MPI_Comm_size(MPI_COMM_WORLD, &total_ranks); + for (int allranks=0; allranks current_offset("current_offset", species.ntags()); auto &this_tag_offset = tag_offset; + auto n_alive = npart_per_tag_arr[ParticleTag::alive]; + if constexpr (D == Dim::_1D){ Kokkos::parallel_for( "PermuteVector and Displace", @@ -779,7 +781,7 @@ namespace ntt { // tag = 1->N (excluding dead and alive) else{ const auto idx_permute_vec = this_tag_offset(current_tag) - - total_alive + + n_alive + Kokkos::atomic_fetch_add( ¤t_offset(current_tag), 1); @@ -808,7 +810,7 @@ namespace ntt { // tag = 1->N (excluding dead and alive) else{ const auto idx_permute_vec = this_tag_offset(current_tag) - - total_alive + + n_alive + Kokkos::atomic_fetch_add( ¤t_offset(current_tag), 1); @@ -839,7 +841,7 @@ namespace ntt { // tag = 1->N (excluding dead and alive) else{ const auto idx_permute_vec = this_tag_offset(current_tag) - - total_alive + + n_alive + Kokkos::atomic_fetch_add( ¤t_offset(current_tag), 1); @@ -913,235 +915,48 @@ namespace ntt { }); } - // Communicate the arrays - comm::CommunicateParticlesBuffer(species, permute_vector, allocation_vector, - this_tag_offset, npart_per_tag_arr, npart_per_tag_arr_recv, - send_ranks, recv_ranks); -#endif - } - } - - -/* - Function to copy the alive particle data the arrays to a buffer and then back - to the particle arrays -*/ - template - void MoveDeadToEnd(array_t& arr, - Kokkos::View indices_alive) { - auto n_alive = indices_alive.extent(0); - auto buffer = Kokkos::View("buffer", n_alive); - Kokkos::parallel_for( - "PopulateBufferAlive", - n_alive, - Lambda(const std::size_t p) { - buffer(p) = arr(indices_alive(p)); - }); - - Kokkos::parallel_for( - "CopyBufferToArr", - n_alive, - Lambda(const std::size_t p) { - arr(p) = buffer(p); - }); - return; - } - - /* - Function to remove dead particles from the domain - - Consider the following particle quantity array - <---xxx---x---xx---xx-----------xx----x--> (qty) - - = alive - x = dead - ntot = nalive + ndead - - (1) Copy all alive particle data to buffer - <---xxx---x---xx---xx-----------xx----x--> (qty) - | - | - v - <--------------------------> buffer - (nalive) - - (2) Copy from buffer to the beginning of the array - overwritting all particles - <--------------------------> buffer - (nalive) - | - | - v - <--------------------------xx----x--> (qty) - ^ - (nalive) - - (3) Set npart to nalive - */ - template - void Metadomain::RemoveDeadParticles(Domain& domain, - timer::Timers* timers){ - for (auto& species : domain.species) { - auto [npart_per_tag_arr, - tag_offset] = species.npart_per_tag(); - const auto npart = static_cast(species.npart()); - const auto total_alive = static_cast( - npart_per_tag_arr[ParticleTag::alive]); - const auto total_dead = static_cast( - npart_per_tag_arr[ParticleTag::dead]); - - // Check that only alive and dead particles are present - for (std::size_t i { 0 }; i < species.ntags(); i++) { - if (i != ParticleTag::alive && i != ParticleTag::dead){ - raise::FatalIf(npart_per_tag_arr[i] != 0, - "Particle tags can only be dead or alive at this point", - HERE); - } - } + /* + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + if (rank == 1 && species.label() == "e+_b") { - auto [npart_per_tag_arr_, - tag_offset_] = species.npart_per_tag(); - auto npart_ = static_cast(species.npart()); - auto total_alive_ = static_cast( - npart_per_tag_arr_[ParticleTag::alive]); - auto total_dead_ = static_cast( - npart_per_tag_arr_[ParticleTag::dead]); + // Copy the tag array to host + auto tag_h = Kokkos::create_mirror_view(species.tag); + Kokkos::deep_copy(tag_h, species.tag); + std::cout << "Tag locs before send" << std::endl; + for (std::size_t i { 0 }; i < species.npart(); i++) { + if (tag_h(i) != ParticleTag::alive) + std::cout <<" Tag: " << tag_h(i) << " loc: "<< i << std::endl; + } - int rank, totranks; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - MPI_Comm_size(MPI_COMM_WORLD, &totranks); - for (std::size_t current_rank=0; current_rank indices_alive("indices_alive", total_alive); - Kokkos::View alive_counter("counter_alive", 1); - Kokkos::deep_copy(alive_counter, 0); - Kokkos::parallel_for( - "Indices of Alive Particles", - species.npart(), - Lambda(index_t p) { - if (this_tag(p) == ParticleTag::alive){ - const auto idx = Kokkos::atomic_fetch_add(&alive_counter(0), 1); - indices_alive(idx) = p; + // Print the permute vector as well + auto permute_vector_h = Kokkos::create_mirror_view(permute_vector); + Kokkos::deep_copy(permute_vector_h, permute_vector); + for (std::size_t i { 0 }; i < total_holes; ++i) { + std::cout << "Rank: " << rank << " Permuted vector: " << permute_vector_h(i) << + " tag: " << tag_h(permute_vector_h(i)) << std::endl; } - }); - // Sanity check: alive_counter must be equal to total_alive - auto alive_counter_h = Kokkos::create_mirror_view(alive_counter); - Kokkos::deep_copy(alive_counter_h, alive_counter); - raise::FatalIf(alive_counter_h(0) != total_alive, - "Error in finding alive particles", - HERE); - - MoveDeadToEnd(species.i1, indices_alive); - MoveDeadToEnd(species.dx1, indices_alive); - MoveDeadToEnd(species.dx1_prev, indices_alive); - MoveDeadToEnd(species.ux1, indices_alive); - MoveDeadToEnd(species.ux2, indices_alive); - MoveDeadToEnd(species.ux3, indices_alive); - MoveDeadToEnd(species.weight, indices_alive); - // Update i2, dx2, i2_prev, dx2_prev - if constexpr(D == Dim::_2D || D == Dim::_3D){ - MoveDeadToEnd(species.i2, indices_alive); - MoveDeadToEnd(species.i2_prev, indices_alive); - MoveDeadToEnd(species.dx2, indices_alive); - MoveDeadToEnd(species.dx2_prev, indices_alive); - if constexpr(D == Dim::_2D && M::CoordType != Coord::Cart){ - MoveDeadToEnd(species.phi, indices_alive); } - } - // Update i3, dx3, i3_prev, dx3_prev - if constexpr(D == Dim::_3D){ - MoveDeadToEnd(species.i3, indices_alive); - MoveDeadToEnd(species.i3_prev, indices_alive); - MoveDeadToEnd(species.dx3, indices_alive); - MoveDeadToEnd(species.dx3_prev, indices_alive); - } - // tags (set first total_alive to alive and rest to dead) - Kokkos::parallel_for( - "Make tags alive", - total_alive, - Lambda(index_t p) { - this_tag(p) = ParticleTag::alive; - }); - - Kokkos::parallel_for( - "Make tags dead", - total_dead, - Lambda(index_t p) { - this_tag(total_alive + p) = ParticleTag::dead; - }); - - species.set_npart(total_alive); - - std::tie(npart_per_tag_arr, - tag_offset) = species.npart_per_tag(); - raise::FatalIf(npart_per_tag_arr[ParticleTag::alive] != total_alive, - "Error in removing dead particles: alive count doesn't match", - HERE); - raise::FatalIf(npart_per_tag_arr[ParticleTag::dead] != 0, - "Error in removing dead particles: not all particles are dead", - HERE); - - - { - auto [npart_per_tag_arr_, - tag_offset_] = species.npart_per_tag(); - auto npart_ = static_cast(species.npart()); - auto total_alive_ = static_cast( - npart_per_tag_arr_[ParticleTag::alive]); - auto total_dead_ = static_cast( - npart_per_tag_arr_[ParticleTag::dead]); - - int rank, totranks; + */ + { + int rank; MPI_Comm_rank(MPI_COMM_WORLD, &rank); - MPI_Comm_size(MPI_COMM_WORLD, &totranks); - for (std::size_t current_rank=0; current_rank(species, permute_vector, allocation_vector, + this_tag_offset, npart_per_tag_arr, npart_per_tag_arr_recv, + send_ranks, recv_ranks); +#endif + } } template struct Metadomain>; From 42a6ea2668e31b58b0830ad6f48d4cfffa7024b8 Mon Sep 17 00:00:00 2001 From: Siddhant Solanki Date: Tue, 7 Jan 2025 12:13:53 -0500 Subject: [PATCH 217/773] small change in metadomain header --- src/engines/srpic.hpp | 9 --------- src/framework/domain/metadomain.h | 1 - 2 files changed, 10 deletions(-) diff --git a/src/engines/srpic.hpp b/src/engines/srpic.hpp index fd1ca226a..d751c712a 100644 --- a/src/engines/srpic.hpp +++ b/src/engines/srpic.hpp @@ -175,15 +175,6 @@ namespace ntt { ParticleInjector(dom); timers.stop("Injector"); } - - if (step % 1 == 0 && step > 0){ - MPI_Barrier(MPI_COMM_WORLD); - timers.start("RemoveDead"); - m_metadomain.RemoveDeadParticles(dom, &timers); - timers.stop("RemoveDead"); - MPI_Barrier(MPI_COMM_WORLD); - } - } /* algorithm substeps --------------------------------------------------- */ diff --git a/src/framework/domain/metadomain.h b/src/framework/domain/metadomain.h index 6bd3d29d8..9e94bf89f 100644 --- a/src/framework/domain/metadomain.h +++ b/src/framework/domain/metadomain.h @@ -91,7 +91,6 @@ namespace ntt { void CommunicateParticles(Domain&, timer::Timers*); void CommunicateParticlesBuffer(Domain&, timer::Timers*); void SetParticleIDs(Domain&); - void RemoveDeadParticles(Domain&, timer::Timers* ); /** * @param global_ndomains total number of domains From 530485c3e1e89053570da488eaa2bc92b9f5241e Mon Sep 17 00:00:00 2001 From: pmocz Date: Wed, 8 Jan 2025 14:08:07 -0500 Subject: [PATCH 218/773] bugfix for duplicate symbols --- src/engines/engine_printer.cpp | 16 ++++++++-------- src/engines/engine_run.cpp | 16 ++++++++-------- src/engines/engine_step_report.cpp | 16 ++++++++-------- 3 files changed, 24 insertions(+), 24 deletions(-) diff --git a/src/engines/engine_printer.cpp b/src/engines/engine_printer.cpp index 90dec3326..1b8009618 100644 --- a/src/engines/engine_printer.cpp +++ b/src/engines/engine_printer.cpp @@ -415,13 +415,13 @@ namespace ntt { } } - template class Engine>; - template class Engine>; - template class Engine>; - template class Engine>; - template class Engine>; - template class Engine>; - template class Engine>; - template class Engine>; + template void Engine>::print_report() const; + template void Engine>::print_report() const; + template void Engine>::print_report() const; + template void Engine>::print_report() const; + template void Engine>::print_report() const; + template void Engine>::print_report() const; + template void Engine>::print_report() const; + template void Engine>::print_report() const; } // namespace ntt diff --git a/src/engines/engine_run.cpp b/src/engines/engine_run.cpp index 4485e0e40..60c5e30ab 100644 --- a/src/engines/engine_run.cpp +++ b/src/engines/engine_run.cpp @@ -92,12 +92,12 @@ namespace ntt { } } - template class Engine>; - template class Engine>; - template class Engine>; - template class Engine>; - template class Engine>; - template class Engine>; - template class Engine>; - template class Engine>; + template void Engine>::run(); + template void Engine>::run(); + template void Engine>::run(); + template void Engine>::run(); + template void Engine>::run(); + template void Engine>::run(); + template void Engine>::run(); + template void Engine>::run(); } // namespace ntt diff --git a/src/engines/engine_step_report.cpp b/src/engines/engine_step_report.cpp index f2a35bb82..1681aabcc 100644 --- a/src/engines/engine_step_report.cpp +++ b/src/engines/engine_step_report.cpp @@ -226,14 +226,14 @@ namespace ntt { os << std::endl; } - template class Engine>; - template class Engine>; - template class Engine>; - template class Engine>; - template class Engine>; - template class Engine>; - template class Engine>; - template class Engine>; + template void Engine>::print_step_report(timer::Timers&,pbar::DurationHistory&,bool,bool) const; + template void Engine>::print_step_report(timer::Timers&,pbar::DurationHistory&,bool,bool) const; + template void Engine>::print_step_report(timer::Timers&,pbar::DurationHistory&,bool,bool) const; + template void Engine>::print_step_report(timer::Timers&,pbar::DurationHistory&,bool,bool) const; + template void Engine>::print_step_report(timer::Timers&,pbar::DurationHistory&,bool,bool) const; + template void Engine>::print_step_report(timer::Timers&,pbar::DurationHistory&,bool,bool) const; + template void Engine>::print_step_report(timer::Timers&,pbar::DurationHistory&,bool,bool) const; + template void Engine>::print_step_report(timer::Timers&,pbar::DurationHistory&,bool,bool) const; } // namespace ntt // template From 5b653e05e92e6d2b0175269bcf8b51bdf5092920 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Wed, 8 Jan 2025 19:14:18 -0500 Subject: [PATCH 219/773] implemented output of Aph for 2d GRPIC --- src/framework/domain/output.cpp | 44 +++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/src/framework/domain/output.cpp b/src/framework/domain/output.cpp index c669eb8ae..a5d4bc26d 100644 --- a/src/framework/domain/output.cpp +++ b/src/framework/domain/output.cpp @@ -173,6 +173,39 @@ namespace ntt { } } + template + void ComputeVectorPotential(ndfield_t& buffer, + ndfield_t& EM, + unsigned short buff_idx, + const Mesh mesh) { + if constexpr (M::Dim == Dim::_2D) { + const auto i2_min = mesh.i_min(in::x2); + // !TODO: this is quite slow + Kokkos::parallel_for( + "ComputeVectorPotential", + mesh.rangeActiveCells(), + Lambda(index_t i, index_t j) { + const real_t i_ { static_cast(static_cast(i) - (N_GHOSTS)) }; + const auto k_min = (i2_min - (N_GHOSTS)) + 1; + const auto k_max = (j - (N_GHOSTS)); + real_t A3 = ZERO; + for (auto k { k_min }; k <= k_max; ++k) { + real_t k_ = static_cast(k); + real_t sqrt_detH_ij1 { mesh.metric.sqrt_det_h({ i_, k_ - HALF }) }; + real_t sqrt_detH_ij2 { mesh.metric.sqrt_det_h({ i_, k_ + HALF }) }; + auto k1 { k + N_GHOSTS }; + A3 += HALF * (sqrt_detH_ij1 * EM(i, k1 - 1, em::bx1) + + sqrt_detH_ij2 * EM(i, k1, em::bx1)); + } + buffer(i, j, buff_idx) = A3; + }); + } else { + raise::KernelError( + HERE, + "ComputeVectorPotential: 2D implementation called for D != 2"); + } + } + template auto Metadomain::Write( const SimulationParams& params, @@ -313,6 +346,17 @@ namespace ntt { raise::Error("Custom output requested but no function provided", HERE); } + } else if (fld.is_vpotential()) { + if (S == SimEngine::GRPIC && M::Dim == Dim::_2D) { + const auto c = static_cast(addresses.back()); + ComputeVectorPotential(local_domain->fields.bckp, + local_domain->fields.em, + c, + local_domain->mesh); + } else { + raise::Error("Vector potential can only be computed for GRPIC in 2D", + HERE); + } } else { raise::Error("Wrong # of components requested for " "non-moment/non-custom output", From c8c81c7ce324c2e8251130a42463d002d94acab1 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Wed, 8 Jan 2025 19:17:43 -0500 Subject: [PATCH 220/773] updated pgen for wald solution with plasma --- setups/grpic/wald/pgen.hpp | 76 ++++++++++++++++++------------------- setups/grpic/wald/wald.toml | 17 +++++---- 2 files changed, 45 insertions(+), 48 deletions(-) diff --git a/setups/grpic/wald/pgen.hpp b/setups/grpic/wald/pgen.hpp index 41d9a2462..7e8eea216 100644 --- a/setups/grpic/wald/pgen.hpp +++ b/setups/grpic/wald/pgen.hpp @@ -26,9 +26,6 @@ namespace user { return HALF * (metric.template h_<3, 3>(x_Cd) + TWO * metric.spin() * metric.template h_<1, 3>(x_Cd) * metric.beta1(x_Cd) ); - // coord_t x_Ph { ZERO }; - // metric.template convert(x_Cd, x_Ph); - // return HALF * SQR(x_Ph[0]) * SQR(math::sin(x_Ph[1])); } Inline auto bx1(const coord_t& x_Ph) const -> real_t { @@ -96,6 +93,7 @@ namespace user { : arch::SpatialDistribution { domain_ptr->mesh.metric } , metric { domain_ptr->mesh.metric } , EM { domain_ptr->fields.em } + , density { domain_ptr->fields.buff } , sigma_thr {sigma_thr} , dens_thr {dens_thr} { std::copy(xi_min.begin(), xi_min.end(), x_min); @@ -108,9 +106,8 @@ namespace user { } } - Kokkos::deep_copy(domain_ptr->fields.buff, ZERO); - auto scatter_buff = Kokkos::Experimental::create_scatter_view(domain_ptr->fields.buff); - printf("%f\n", domain_ptr->fields.buff(10, 10, 0)); + Kokkos::deep_copy(density, ZERO); + auto scatter_buff = Kokkos::Experimental::create_scatter_view(density); // some parameters auto& mesh = domain_ptr->mesh; const auto use_weights = params.template get("particles.use_weights"); @@ -131,15 +128,13 @@ namespace user { prtl_spec.mass(), prtl_spec.charge(), use_weights, metric, mesh.flds_bc(), - ni2, inv_n0, 0)); + ni2, inv_n0, ZERO)); // clang-format on } - Kokkos::Experimental::contribute(domain_ptr->fields.buff, scatter_buff); - auto density = Kokkos::create_mirror_view(domain_ptr->fields.buff); - Kokkos::deep_copy(density, domain_ptr->fields.buff); + Kokkos::Experimental::contribute(density, scatter_buff); } - Inline auto sigma_crit(const coord_t& x_Ph) const -> real_t { + Inline auto sigma_crit(const coord_t& x_Ph) const -> bool { coord_t xi {ZERO}; if constexpr (M::Dim == Dim::_2D) { metric.template convert(x_Ph, xi); @@ -150,17 +145,15 @@ namespace user { metric.template transform(xi, B_cntrv, B_cov); const auto bsqr = DOT(B_cntrv[0], B_cntrv[1], B_cntrv[2], B_cov[0], B_cov[1], B_cov[2]); const auto dens = density(i1, i2, 0); - // printf("%f\n", domain_ptr->fields.buff(10, 10, 0)); - // return (bsqr / dens > sigma_thr) || (dens < dens_thr); - return 2.0; + return (bsqr > sigma_thr * dens) || (dens < dens_thr); } - return ZERO; + return false; } Inline auto operator()(const coord_t& x_Ph) const -> real_t override { auto fill = true; for (auto d = 0u; d < M::Dim; ++d) { - fill &= x_Ph[d] > x_min[d] and x_Ph[d] < x_max[d] and sigma_crit(x_Ph) > ONE; + fill &= x_Ph[d] > x_min[d] and x_Ph[d] < x_max[d] and sigma_crit(x_Ph); } return fill ? ONE : ZERO; } @@ -192,7 +185,7 @@ namespace user { const std::vector xi_min; const std::vector xi_max; - const real_t sigma0, sigma_max, multiplicity, nGJ; + const real_t sigma0, sigma_max, multiplicity, nGJ, temperature; InitFields init_flds; @@ -203,11 +196,14 @@ namespace user { , sigma_max { p.template get("setup.sigma_max") } , sigma0 { p.template get("scales.sigma0") } , multiplicity { p.template get("setup.multiplicity") } - , nGJ { p.template get("scales.B0") * SQR(p.template get("scales.skindepth0")) } //m.mesh().metric.spin() * + , nGJ { p.template get("scales.B0") * SQR(p.template get("scales.skindepth0")) } + , temperature { p.template get("setup.temperature") } , init_flds { m.mesh().metric } {} inline void InitPrtls(Domain& local_domain) { - const auto energy_dist = arch::ColdDist(local_domain.mesh.metric); + const auto energy_dist = arch::Maxwellian(local_domain.mesh.metric, + local_domain.random_pool, + temperature); const auto spatial_dist = PointDistribution(xi_min, xi_max, sigma_max / sigma0, @@ -216,7 +212,7 @@ namespace user { &local_domain ); - const auto injector = arch::NonUniformInjector( + const auto injector = arch::NonUniformInjector( energy_dist, spatial_dist, { 1, 2 }); @@ -228,26 +224,26 @@ namespace user { } void CustomPostStep(std::size_t, long double time, Domain& local_domain) { - // const auto energy_dist = arch::ColdDist(local_domain.mesh.metric); - // const auto spatial_dist = PointDistribution(local_domain.mesh.metric, - // xi_min, - // xi_max); - - // const auto spatial_dist = ReplenishDist(local_domain.mesh.metric, - // const ndfield_t& density, - // unsigned short idx, - // const T& target_density, - // real_t target_max_density) - - // const auto injector = arch::NonUniformInjector( - // energy_dist, - // spatial_dist, - // { 1, 2 }); - // arch::InjectNonUniform(params, - // local_domain, - // injector, - // 1.0, - // true); + const auto energy_dist = arch::Maxwellian(local_domain.mesh.metric, + local_domain.random_pool, + temperature); + const auto spatial_dist = PointDistribution(xi_min, + xi_max, + sigma_max / sigma0, + multiplicity * nGJ, + params, + &local_domain + ); + + const auto injector = arch::NonUniformInjector( + energy_dist, + spatial_dist, + { 1, 2 }); + arch::InjectNonUniform(params, + local_domain, + injector, + 1.0, + true); } }; diff --git a/setups/grpic/wald/wald.toml b/setups/grpic/wald/wald.toml index 2f12705de..3bf243afc 100644 --- a/setups/grpic/wald/wald.toml +++ b/setups/grpic/wald/wald.toml @@ -4,8 +4,8 @@ runtime = 100.0 [grid] - resolution = [256,256] - extent = [[0.8, 8.0]] + resolution = [512, 512] + extent = [[1.22, 6.0]] [grid.metric] metric = "qkerr_schild" @@ -43,28 +43,29 @@ label = "e-" mass = 1.0 charge = -1.0 - maxnpart = 1e6 + maxnpart = 2e8 pusher = "Boris" [[particles.species]] label = "e+" mass = 1.0 charge = 1.0 - maxnpart = 1e6 + maxnpart = 2e8 pusher = "Boris" [setup] multiplicity = 1.0 - sigma_max = 10.0 - xi_min = [1.2, 0.1] - xi_max = [7.5, 3.04159265] + sigma_max = 1000.0 + temperature = 0.01 + xi_min = [1.32, 0.1] + xi_max = [4.0, 3.04159265] [output] format = "hdf5" [output.fields] interval_time = 1.0 - quantities = ["D", "B", "J", "N_1", "N_2", "Nppc_1", "Nppc_2"] + quantities = ["D", "B", "J", "N_1", "N_2", "A"] [output.particles] enable = false From a5704740678b49aa7c819754d67cb3df8ebb07b8 Mon Sep 17 00:00:00 2001 From: Sasha Chernoglazov Date: Wed, 8 Jan 2025 20:25:15 -0500 Subject: [PATCH 221/773] correct communications with boundaries --- src/framework/domain/comm_mpi.hpp | 56 +++++++++++++------------ src/framework/domain/communications.cpp | 11 ++--- src/global/utils/progressbar.cpp | 4 +- 3 files changed, 35 insertions(+), 36 deletions(-) diff --git a/src/framework/domain/comm_mpi.hpp b/src/framework/domain/comm_mpi.hpp index 1395c8191..ce38a8261 100644 --- a/src/framework/domain/comm_mpi.hpp +++ b/src/framework/domain/comm_mpi.hpp @@ -53,7 +53,6 @@ namespace comm { (recv_rank == rank && recv_idx != idx), "Multiple-domain single-rank communication not yet implemented", HERE); - if ((send_idx == idx) and (recv_idx == idx)) { // trivial copy if sending to self and receiving from self @@ -456,7 +455,8 @@ namespace comm { std::vector npart_per_tag_arr, std::vector npart_per_tag_arr_recv, std::vector send_ranks, - std::vector recv_ranks) { + std::vector recv_ranks, + const dir::dirs_t& legal_directions) { // Pointers to the particle data arrays auto &this_ux1 = species.ux1; auto &this_ux2 = species.ux2; @@ -533,13 +533,17 @@ namespace comm { auto iteration = 0; auto current_received = 0; - for (auto& direction : dir::Directions::all) { + for (const auto& direction : legal_directions) { const auto send_rank = send_ranks[iteration]; const auto recv_rank = recv_ranks[iteration]; const auto tag_send = mpi::PrtlSendTag::dir2tag(direction); const auto tag_recv = mpi::PrtlSendTag::dir2tag(-direction); const auto send_count = npart_per_tag_arr[tag_send]; const auto recv_count = npart_per_tag_arr_recv[tag_recv]; + { + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + } if (send_rank < 0 and recv_rank < 0) { continue; } @@ -677,50 +681,50 @@ namespace comm { { int rank; MPI_Comm_rank(MPI_COMM_WORLD, &rank); - //printf("MPI rank: %d, Performing sendrecv operation \n", rank); + //printf("MPI rank: %d, Performing sendrecv operation, direction %d \n", rank, direction); } - MPI_Sendrecv(send_buffer_int_h.data(), + MPI_Sendrecv(send_buffer_int.data(), send_count * NINTS, mpi::get_type(), send_rank, 0, - recv_buffer_int_h.data() + receive_offset_int, + recv_buffer_int.data() + receive_offset_int, recv_count*NINTS, mpi::get_type(), recv_rank, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE); - MPI_Sendrecv(send_buffer_real_h.data(), + MPI_Sendrecv(send_buffer_real.data(), send_count * NREALS, mpi::get_type(), send_rank, 0, - recv_buffer_real_h.data() + receive_offset_real, + recv_buffer_real.data() + receive_offset_real, recv_count*NREALS, mpi::get_type(), recv_rank, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE); - MPI_Sendrecv(send_buffer_prtldx_h.data(), + MPI_Sendrecv(send_buffer_prtldx.data(), send_count * NFLOATS, mpi::get_type(), send_rank, 0, - recv_buffer_prtldx_h.data() + receive_offset_prtldx, + recv_buffer_prtldx.data() + receive_offset_prtldx, recv_count*NFLOATS, mpi::get_type(), recv_rank, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE); - MPI_Sendrecv(send_buffer_long_h.data(), + MPI_Sendrecv(send_buffer_long.data(), send_count * NLONGS, mpi::get_type(), send_rank, 0, - recv_buffer_long_h.data() + receive_offset_long, + recv_buffer_long.data() + receive_offset_long, recv_count*NLONGS, mpi::get_type(), recv_rank, @@ -732,61 +736,61 @@ namespace comm { { int rank; MPI_Comm_rank(MPI_COMM_WORLD, &rank); - //printf("MPI rank: %d, Performing send operation \n", rank); + //printf("MPI rank: %d, Performing send operation, direction %d \n", rank, direction); } - MPI_Send(send_buffer_int_h.data(), + MPI_Send(send_buffer_int.data(), send_count * NINTS, mpi::get_type(), send_rank, 0, MPI_COMM_WORLD); - MPI_Send(send_buffer_real_h.data(), + MPI_Send(send_buffer_real.data(), send_count * NREALS, mpi::get_type(), send_rank, 0, MPI_COMM_WORLD); - MPI_Send(send_buffer_prtldx_h.data(), + MPI_Send(send_buffer_prtldx.data(), send_count * NFLOATS, mpi::get_type(), send_rank, 0, MPI_COMM_WORLD); - MPI_Send(send_buffer_long_h.data(), + MPI_Send(send_buffer_long.data(), send_count * NLONGS, mpi::get_type(), send_rank, 0, MPI_COMM_WORLD); - } else if ((recv_rank >= 0) and (recv_count > 0)) { + } else if ((recv_rank >= 0) and (recv_count > 0)) { // Debug: Print the rank and type of mpi operation performed { int rank; MPI_Comm_rank(MPI_COMM_WORLD, &rank); - //printf("MPI rank: %d, Performing recv operation \n", rank); + //printf("MPI rank: %d, Performing recv operation, direction %d \n", rank, direction); } - MPI_Recv(recv_buffer_int_h.data() + receive_offset_int, + MPI_Recv(recv_buffer_int.data() + receive_offset_int, recv_count * NINTS, mpi::get_type(), recv_rank, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE); - MPI_Recv(recv_buffer_real_h.data() + receive_offset_real, + MPI_Recv(recv_buffer_real.data() + receive_offset_real, recv_count * NREALS, mpi::get_type(), recv_rank, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE); - MPI_Recv(recv_buffer_prtldx_h.data() + receive_offset_prtldx, + MPI_Recv(recv_buffer_prtldx.data() + receive_offset_prtldx, recv_count * NFLOATS, mpi::get_type(), recv_rank, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE); - MPI_Recv(recv_buffer_long_h.data() + receive_offset_long, + MPI_Recv(recv_buffer_long.data() + receive_offset_long, recv_count * NLONGS, mpi::get_type(), recv_rank, @@ -850,9 +854,9 @@ namespace comm { */ } // end over direction loop - Kokkos::deep_copy(recv_buffer_int, recv_buffer_int_h); + /*Kokkos::deep_copy(recv_buffer_int, recv_buffer_int_h); Kokkos::deep_copy(recv_buffer_real, recv_buffer_real_h); - Kokkos::deep_copy(recv_buffer_prtldx, recv_buffer_prtldx_h); + Kokkos::deep_copy(recv_buffer_prtldx, recv_buffer_prtldx_h);*/ if constexpr (D == Dim::_1D) { Kokkos::parallel_for( @@ -949,10 +953,8 @@ namespace comm { this_particleID(idx) = recv_buffer_long(NLONGS * p + 0); }); } - species.set_npart(species.npart() + std::max(permute_vector.extent(0), allocation_vector.extent(0)) - permute_vector.extent(0)); - /* { int rank; diff --git a/src/framework/domain/communications.cpp b/src/framework/domain/communications.cpp index d1ce06609..dc62338f7 100644 --- a/src/framework/domain/communications.cpp +++ b/src/framework/domain/communications.cpp @@ -686,6 +686,7 @@ namespace ntt { auto shifts_in_x1_h = Kokkos::create_mirror_view(shifts_in_x1); auto shifts_in_x2_h = Kokkos::create_mirror_view(shifts_in_x2); auto shifts_in_x3_h = Kokkos::create_mirror_view(shifts_in_x3); + dir::dirs_t legal_directions; // Get receive counts + displacements for (auto& direction : dir::Directions::all) { @@ -703,6 +704,7 @@ namespace ntt { const auto nsend = npart_per_tag_arr[tag_send]; std::size_t nrecv = 0; + legal_directions.push_back(direction); send_ranks.push_back(send_rank); recv_ranks.push_back(recv_rank); send_inds.push_back(send_ind); @@ -945,16 +947,11 @@ namespace ntt { } } */ - { - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - std::cout << "Rank: " << rank << " Total sent: " << total_holes - total_dead << " Total recv: " << total_recv << std::endl; - } - + // Communicate the arrays comm::CommunicateParticlesBuffer(species, permute_vector, allocation_vector, this_tag_offset, npart_per_tag_arr, npart_per_tag_arr_recv, - send_ranks, recv_ranks); + send_ranks, recv_ranks, legal_directions); #endif } } diff --git a/src/global/utils/progressbar.cpp b/src/global/utils/progressbar.cpp index 38f65a790..74f952382 100644 --- a/src/global/utils/progressbar.cpp +++ b/src/global/utils/progressbar.cpp @@ -52,10 +52,10 @@ namespace pbar { } auto to_human_readable(long double t, const std::string& u) -> std::string { - const auto [tt, tu] = std::pair{t, u};//normalize_duration_fmt(t, u); + const auto [tt, tu] = normalize_duration_fmt(t, u); const auto t1 = static_cast(tt); const auto t2 = tt - static_cast(t1); - const auto [tt2, tu2] = std::pair{t2, tu};//normalize_duration_fmt(t2, tu); + const auto [tt2, tu2] = normalize_duration_fmt(t2, tu); return fmt::format("%d%s %d%s", t1, tu.c_str(), static_cast(tt2), tu2.c_str()); } From d63595f3a326eed5fb27268bb02af15b93f98a4a Mon Sep 17 00:00:00 2001 From: Siddhant Solanki Date: Wed, 8 Jan 2025 22:47:55 -0500 Subject: [PATCH 222/773] added dead particle function --- src/engines/srpic.hpp | 8 ++ src/framework/domain/communications.cpp | 170 ++++++++++++++++++++++++ 2 files changed, 178 insertions(+) diff --git a/src/engines/srpic.hpp b/src/engines/srpic.hpp index d751c712a..0489d8508 100644 --- a/src/engines/srpic.hpp +++ b/src/engines/srpic.hpp @@ -175,6 +175,14 @@ namespace ntt { ParticleInjector(dom); timers.stop("Injector"); } + + if (step % 100 == 0 && step > 0){ + MPI_Barrier(MPI_COMM_WORLD); + timers.start("RemoveDead"); + m_metadomain.RemoveDeadParticles(dom, &timers); + timers.stop("RemoveDead"); + MPI_Barrier(MPI_COMM_WORLD); + } } /* algorithm substeps --------------------------------------------------- */ diff --git a/src/framework/domain/communications.cpp b/src/framework/domain/communications.cpp index dc62338f7..390c27fa8 100644 --- a/src/framework/domain/communications.cpp +++ b/src/framework/domain/communications.cpp @@ -956,6 +956,176 @@ namespace ntt { } } + /* + Function to copy the alive particle data the arrays to a buffer and then back + to the particle arrays +*/ + template + void MoveDeadToEnd(array_t& arr, + Kokkos::View indices_alive) { + auto n_alive = indices_alive.extent(0); + auto buffer = Kokkos::View("buffer", n_alive); + Kokkos::parallel_for( + "PopulateBufferAlive", + n_alive, + Lambda(const std::size_t p) { + buffer(p) = arr(indices_alive(p)); + }); + + Kokkos::parallel_for( + "CopyBufferToArr", + n_alive, + Lambda(const std::size_t p) { + arr(p) = buffer(p); + }); + return; + } + + /* + Function to remove dead particles from the domain + + Consider the following particle quantity array + <---xxx---x---xx---xx-----------xx----x--> (qty) + - = alive + x = dead + ntot = nalive + ndead + + (1) Copy all alive particle data to buffer + <---xxx---x---xx---xx-----------xx----x--> (qty) + | + | + v + <--------------------------> buffer + (nalive) + + (2) Copy from buffer to the beginning of the array + overwritting all particles + <--------------------------> buffer + (nalive) + | + | + v + <--------------------------xx----x--> (qty) + ^ + (nalive) + + (3) Set npart to nalive + */ + template + void Metadomain::RemoveDeadParticles(Domain& domain, + timer::Timers* timers){ + for (auto& species : domain.species) { + auto [npart_per_tag_arr, + tag_offset] = species.npart_per_tag(); + const auto npart = static_cast(species.npart()); + const auto total_alive = static_cast( + npart_per_tag_arr[ParticleTag::alive]); + const auto total_dead = static_cast( + npart_per_tag_arr[ParticleTag::dead]); + + // Check that only alive and dead particles are present + for (std::size_t i { 0 }; i < species.ntags(); i++) { + if (i != ParticleTag::alive && i != ParticleTag::dead){ + raise::FatalIf(npart_per_tag_arr[i] != 0, + "Particle tags can only be dead or alive at this point", + HERE); + } + } + + // Get the indices of all alive particles + auto &this_i1 = species.i1; + auto &this_i2 = species.i2; + auto &this_i3 = species.i3; + auto &this_i1_prev = species.i1_prev; + auto &this_i2_prev = species.i2_prev; + auto &this_i3_prev = species.i3_prev; + auto &this_dx1 = species.dx1; + auto &this_dx2 = species.dx2; + auto &this_dx3 = species.dx3; + auto &this_dx1_prev = species.dx1_prev; + auto &this_dx2_prev = species.dx2_prev; + auto &this_dx3_prev = species.dx3_prev; + auto &this_ux1 = species.ux1; + auto &this_ux2 = species.ux2; + auto &this_ux3 = species.ux3; + auto &this_weight = species.weight; + auto &this_phi = species.phi; + auto &this_tag = species.tag; + // Find indices of tag = alive particles + Kokkos::View indices_alive("indices_alive", total_alive); + Kokkos::View alive_counter("counter_alive", 1); + Kokkos::deep_copy(alive_counter, 0); + Kokkos::parallel_for( + "Indices of Alive Particles", + species.npart(), + Lambda(index_t p) { + if (this_tag(p) == ParticleTag::alive){ + const auto idx = Kokkos::atomic_fetch_add(&alive_counter(0), 1); + indices_alive(idx) = p; + } + }); + // Sanity check: alive_counter must be equal to total_alive + auto alive_counter_h = Kokkos::create_mirror_view(alive_counter); + Kokkos::deep_copy(alive_counter_h, alive_counter); + raise::FatalIf(alive_counter_h(0) != total_alive, + "Error in finding alive particles", + HERE); + + MoveDeadToEnd(species.i1, indices_alive); + MoveDeadToEnd(species.dx1, indices_alive); + MoveDeadToEnd(species.dx1_prev, indices_alive); + MoveDeadToEnd(species.ux1, indices_alive); + MoveDeadToEnd(species.ux2, indices_alive); + MoveDeadToEnd(species.ux3, indices_alive); + MoveDeadToEnd(species.weight, indices_alive); + // Update i2, dx2, i2_prev, dx2_prev + if constexpr(D == Dim::_2D || D == Dim::_3D){ + MoveDeadToEnd(species.i2, indices_alive); + MoveDeadToEnd(species.i2_prev, indices_alive); + MoveDeadToEnd(species.dx2, indices_alive); + MoveDeadToEnd(species.dx2_prev, indices_alive); + if constexpr(D == Dim::_2D && M::CoordType != Coord::Cart){ + MoveDeadToEnd(species.phi, indices_alive); + } + } + // Update i3, dx3, i3_prev, dx3_prev + if constexpr(D == Dim::_3D){ + MoveDeadToEnd(species.i3, indices_alive); + MoveDeadToEnd(species.i3_prev, indices_alive); + MoveDeadToEnd(species.dx3, indices_alive); + MoveDeadToEnd(species.dx3_prev, indices_alive); + } + // tags (set first total_alive to alive and rest to dead) + Kokkos::parallel_for( + "Make tags alive", + total_alive, + Lambda(index_t p) { + this_tag(p) = ParticleTag::alive; + }); + + Kokkos::parallel_for( + "Make tags dead", + total_dead, + Lambda(index_t p) { + this_tag(total_alive + p) = ParticleTag::dead; + }); + + species.set_npart(total_alive); + + std::tie(npart_per_tag_arr, + tag_offset) = species.npart_per_tag(); + raise::FatalIf(npart_per_tag_arr[ParticleTag::alive] != total_alive, + "Error in removing dead particles: alive count doesn't match", + HERE); + raise::FatalIf(npart_per_tag_arr[ParticleTag::dead] != 0, + "Error in removing dead particles: not all particles are dead", + HERE); + + } + + return; + } + template struct Metadomain>; template struct Metadomain>; template struct Metadomain>; From 8fc0cd6dd2137e0ccd0b69f66ade66d3b9c12480 Mon Sep 17 00:00:00 2001 From: Siddhant Solanki Date: Wed, 8 Jan 2025 23:28:45 -0500 Subject: [PATCH 223/773] added header --- src/framework/domain/metadomain.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/framework/domain/metadomain.h b/src/framework/domain/metadomain.h index 9e94bf89f..9e2c2bb9d 100644 --- a/src/framework/domain/metadomain.h +++ b/src/framework/domain/metadomain.h @@ -91,6 +91,7 @@ namespace ntt { void CommunicateParticles(Domain&, timer::Timers*); void CommunicateParticlesBuffer(Domain&, timer::Timers*); void SetParticleIDs(Domain&); + void RemoveDeadParticles(Domain& ,timer::Timers* ); /** * @param global_ndomains total number of domains From 2d9a0fa801f2afce0d88079df9775284c5238280 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Mon, 13 Jan 2025 14:26:55 -0500 Subject: [PATCH 224/773] gr minor --- src/kernels/fields_bcs.hpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/kernels/fields_bcs.hpp b/src/kernels/fields_bcs.hpp index 445e0be74..1bd45b8df 100644 --- a/src/kernels/fields_bcs.hpp +++ b/src/kernels/fields_bcs.hpp @@ -591,11 +591,11 @@ template const BCTags tags; AbsorbBoundariesGR_kernel(ndfield_t Fld, - const I& finit, - const M& metric, - real_t xg_edge, - real_t dx_abs, - BCTags tags) + const I& finit, + const M& metric, + real_t xg_edge, + real_t dx_abs, + BCTags tags) : Fld { Fld } , finit { finit } , metric { metric } From c836ceb3c5c3d04d7133aa3dc8f0c8f1fd7e35b6 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Tue, 14 Jan 2025 17:19:13 -0500 Subject: [PATCH 225/773] added an option for controlling initial B-field discretisation --- setups/grpic/wald/pgen.hpp | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/setups/grpic/wald/pgen.hpp b/setups/grpic/wald/pgen.hpp index 7e8eea216..b27dd370e 100644 --- a/setups/grpic/wald/pgen.hpp +++ b/setups/grpic/wald/pgen.hpp @@ -20,7 +20,7 @@ namespace user { template struct InitFields { - InitFields(M metric_) : metric { metric_ } {} + InitFields(M metric_, real_t m_eps) : metric { metric_ }, m_eps { m_eps } {} Inline auto A_3(const coord_t& x_Cd) const -> real_t { return HALF * (metric.template h_<3, 3>(x_Cd) @@ -28,37 +28,37 @@ namespace user { ); } - Inline auto bx1(const coord_t& x_Ph) const -> real_t { + Inline auto bx1(const coord_t& x_Ph) const -> real_t { // at ( i , j + HALF ) coord_t xi {ZERO}, x0m { ZERO }, x0p { ZERO }; metric.template convert(x_Ph, xi); x0m[0] = xi[0]; - x0m[1] = xi[1] - HALF; + x0m[1] = xi[1] - HALF * m_eps; x0p[0] = xi[0]; - x0p[1] = xi[1] + HALF; + x0p[1] = xi[1] + HALF * m_eps; real_t inv_sqrt_detH_ijP { ONE / metric.sqrt_det_h({ xi[0], xi[1] }) }; if (cmp::AlmostZero(x_Ph[1])) return ONE; else - return (A_3(x0p) - A_3(x0m)) * inv_sqrt_detH_ijP; + return (A_3(x0p) - A_3(x0m)) * inv_sqrt_detH_ijP / m_eps; } - Inline auto bx2(const coord_t& x_Ph) const -> real_t { + Inline auto bx2(const coord_t& x_Ph) const -> real_t { // at ( i + HALF , j ) coord_t xi {ZERO}, x0m { ZERO }, x0p { ZERO }; metric.template convert(x_Ph, xi); - x0m[0] = xi[0] - HALF; + x0m[0] = xi[0] - HALF * m_eps; x0m[1] = xi[1]; - x0p[0] = xi[0] + HALF; + x0p[0] = xi[0] + HALF * m_eps; x0p[1] = xi[1]; - real_t inv_sqrt_detH_ijP { ONE / metric.sqrt_det_h({ xi[0], xi[1] }) }; + real_t inv_sqrt_detH_ijP { ONE / metric.sqrt_det_h({ xi[0] , xi[1] }) }; if (cmp::AlmostZero(x_Ph[1])) return ZERO; else - return -(A_3(x0p) - A_3(x0m)) * inv_sqrt_detH_ijP; + return -(A_3(x0p) - A_3(x0m)) * inv_sqrt_detH_ijP / m_eps; } Inline auto bx3(const coord_t& x_Ph) const -> real_t { @@ -79,6 +79,7 @@ namespace user { private: const M metric; + const real_t m_eps; }; template @@ -185,7 +186,7 @@ namespace user { const std::vector xi_min; const std::vector xi_max; - const real_t sigma0, sigma_max, multiplicity, nGJ, temperature; + const real_t sigma0, sigma_max, multiplicity, nGJ, temperature, m_eps; InitFields init_flds; @@ -198,7 +199,8 @@ namespace user { , multiplicity { p.template get("setup.multiplicity") } , nGJ { p.template get("scales.B0") * SQR(p.template get("scales.skindepth0")) } , temperature { p.template get("setup.temperature") } - , init_flds { m.mesh().metric } {} + , m_eps { p.template get("setup.m_eps") } + , init_flds { m.mesh().metric, m_eps } {} inline void InitPrtls(Domain& local_domain) { const auto energy_dist = arch::Maxwellian(local_domain.mesh.metric, From 1227bf6950934296defd096f4d10a3ed237ddc95 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Wed, 15 Jan 2025 15:36:42 -0500 Subject: [PATCH 226/773] grpic vacuum wald test improved --- setups/grpic/vacuum/pgen.hpp | 116 ++++++++++++++++++++++++++++---- setups/grpic/vacuum/vacuum.toml | 38 +++-------- 2 files changed, 112 insertions(+), 42 deletions(-) diff --git a/setups/grpic/vacuum/pgen.hpp b/setups/grpic/vacuum/pgen.hpp index 6d5e5fba5..60a2bfe05 100644 --- a/setups/grpic/vacuum/pgen.hpp +++ b/setups/grpic/vacuum/pgen.hpp @@ -27,12 +27,26 @@ namespace user { InitFields(M metric_) : metric { metric_ } {} Inline auto A_3(const coord_t& x_Cd) const -> real_t { - coord_t x_Ph { ZERO }; - metric.template convert(x_Cd, x_Ph); - return HALF * SQR(x_Ph[0]) * SQR(math::sin(x_Ph[1])); + return HALF * (metric.template h_<3, 3>(x_Cd) + + TWO * metric.spin() * metric.template h_<1, 3>(x_Cd) * metric.beta1(x_Cd) + ); } - Inline auto bx1(const coord_t& x_Ph) const -> real_t { + Inline auto A_1(const coord_t& x_Cd) const -> real_t { + return HALF * (metric.template h_<1, 3>(x_Cd) + + TWO * metric.spin() * metric.template h_<1, 1>(x_Cd) * metric.beta1(x_Cd) + ); + } + + Inline auto A_0(const coord_t& x_Cd) const -> real_t { + real_t g_00 { -metric.alpha(x_Cd) * metric.alpha(x_Cd) + + metric.template h_<1, 1>(x_Cd) * metric.beta1(x_Cd) * metric.beta1(x_Cd) + }; + return HALF * (metric.template h_<1, 3>(x_Cd) * metric.beta1(x_Cd) + + TWO * metric.spin() * g_00); + } + + Inline auto bx1(const coord_t& x_Ph) const -> real_t { // at ( i , j + HALF ) coord_t xi {ZERO}, x0m { ZERO }, x0p { ZERO }; metric.template convert(x_Ph, xi); @@ -49,7 +63,7 @@ namespace user { return (A_3(x0p) - A_3(x0m)) * inv_sqrt_detH_ijP; } - Inline auto bx2(const coord_t& x_Ph) const -> real_t { + Inline auto bx2(const coord_t& x_Ph) const -> real_t { // at ( i + HALF , j ) coord_t xi {ZERO}, x0m { ZERO }, x0p { ZERO }; metric.template convert(x_Ph, xi); @@ -65,20 +79,96 @@ namespace user { return -(A_3(x0p) - A_3(x0m)) * inv_sqrt_detH_ijP; } - Inline auto bx3(const coord_t& x_Ph) const -> real_t { - return ZERO; + Inline auto bx3(const coord_t& x_Ph) const -> real_t { // at ( i + HALF , j + HALF ) + coord_t xi {ZERO}, x0m { ZERO }, x0p { ZERO }; + metric.template convert(x_Ph, xi); + + x0m[0] = xi[0]; + x0m[1] = xi[1] - HALF; + x0p[0] = xi[0]; + x0p[1] = xi[1] + HALF; + + real_t inv_sqrt_detH_iPjP { ONE / metric.sqrt_det_h({ xi[0], xi[1]}) }; + return -(A_1(x0p) - A_1(x0m)) * inv_sqrt_detH_iPjP; } - Inline auto dx1(const coord_t& x_Ph) const -> real_t { - return ZERO; + Inline auto dx1(const coord_t& x_Ph) const -> real_t { // at ( i + HALF , j ) + coord_t xi {ZERO}, x0m { ZERO }, x0p { ZERO }; + metric.template convert(x_Ph, xi); + + real_t alpha_iPj { metric.alpha({ xi[0], xi[1] }) }; + real_t inv_sqrt_detH_ij { ONE / metric.sqrt_det_h({ xi[0] - HALF, xi[1] }) }; + real_t sqrt_detH_ij { metric.sqrt_det_h({ xi[0] - HALF, xi[1] }) }; + real_t beta_ij { metric.beta1({ xi[0] - HALF, xi[1]}) }; + real_t alpha_ij { metric.alpha({ xi[0] - HALF, xi[1]}) }; + + // D1 at ( i + HALF , j ) + x0m[0] = xi[0] - HALF; + x0m[1] = xi[1]; + x0p[0] = xi[0] + HALF; + x0p[1] = xi[1]; + real_t E1d { (A_0(x0p) - A_0(x0m)) }; + real_t D1d { E1d / alpha_iPj }; + + // D3 at ( i , j ) + x0m[0] = xi[0] - HALF - HALF; + x0m[1] = xi[1]; + x0p[0] = xi[0] - HALF + HALF; + x0p[1] = xi[1]; + real_t D3d { (A_3(x0p) - A_3(x0m)) * beta_ij / alpha_ij }; + + real_t D1u { metric.template h<1, 1>({ xi[0], xi[1] }) * D1d + metric.template h<1, 3>({ xi[0], xi[1] }) * D3d }; + + return D1u; } - Inline auto dx2(const coord_t& x_Ph) const -> real_t { - return ZERO; + Inline auto dx2(const coord_t& x_Ph) const -> real_t { // at ( i , j + HALF ) + coord_t xi {ZERO}, x0m { ZERO }, x0p { ZERO }; + metric.template convert(x_Ph, xi); + x0m[0] = xi[0]; + x0m[1] = xi[1] - HALF; + x0p[0] = xi[0]; + x0p[1] = xi[1] + HALF; + real_t inv_sqrt_detH_ijP { ONE / metric.sqrt_det_h({ xi[0], xi[1] }) }; + real_t sqrt_detH_ijP { metric.sqrt_det_h({ xi[0], xi[1] }) }; + real_t alpha_ijP { metric.alpha({ xi[0], xi[1] }) }; + real_t beta_ijP { metric.beta1({ xi[0], xi[1] }) }; + + real_t E2d { (A_0(x0p) - A_0(x0m)) }; + real_t D2d { E2d / alpha_ijP - (A_1(x0p) - A_1(x0m)) * beta_ijP / alpha_ijP }; + real_t D2u { metric.template h<2, 2>({ xi[0], xi[1] }) * D2d }; + + return D2u; } - Inline auto dx3(const coord_t& x_Ph) const -> real_t { - return ZERO; + Inline auto dx3(const coord_t& x_Ph) const -> real_t { // at ( i , j ) + coord_t xi {ZERO}, x0m { ZERO }, x0p { ZERO }; + metric.template convert(x_Ph, xi); + real_t inv_sqrt_detH_ij { ONE / metric.sqrt_det_h({ xi[0], xi[1] }) }; + real_t sqrt_detH_ij { metric.sqrt_det_h({ xi[0], xi[1] }) }; + real_t beta_ij { metric.beta1({ xi[0], xi[1] }) }; + real_t alpha_ij { metric.alpha({ xi[0], xi[1] }) }; + real_t alpha_iPj { metric.alpha({ xi[0] + HALF, xi[1] }) }; + + // D3 at ( i , j ) + x0m[0] = xi[0] - HALF; + x0m[1] = xi[1]; + x0p[0] = xi[0] + HALF; + x0p[1] = xi[1]; + real_t D3d { (A_3(x0p) - A_3(x0m)) * beta_ij / alpha_ij }; + + // D1 at ( i + HALF , j ) + x0m[0] = xi[0] + HALF - HALF; + x0m[1] = xi[1]; + x0p[0] = xi[0] + HALF + HALF; + x0p[1] = xi[1]; + real_t E1d { (A_0(x0p) - A_0(x0m)) }; + real_t D1d { E1d / alpha_iPj }; + + if (cmp::AlmostZero(x_Ph[1])) + return metric.template h<1, 3>({ xi[0], xi[1] }) * D1d; + else + return metric.template h<3, 3>({ xi[0], xi[1] }) * D3d + metric.template h<1, 3>({ xi[0], xi[1] }) * D1d; } private: diff --git a/setups/grpic/vacuum/vacuum.toml b/setups/grpic/vacuum/vacuum.toml index 3992b9f12..621f5d127 100644 --- a/setups/grpic/vacuum/vacuum.toml +++ b/setups/grpic/vacuum/vacuum.toml @@ -1,31 +1,31 @@ [simulation] - name = "wald" + name = "wald_Dph_abs_a95" engine = "grpic" - runtime = 500.0 + runtime = 1.0 [grid] resolution = [128,128] - extent = [[2.0, 8.0]] + extent = [[1.0, 10.0]] [grid.metric] - metric = "qkerr_schild" + metric = "kerr_schild" qsph_r0 = 0.0 qsph_h = 0.0 - ks_a = 0.0 + ks_a = 0.95 [grid.boundaries] fields = [["ABSORB"]] particles = [["ABSORB"]] [grid.boundaries.absorb] - ds = 0.5 + ds = 1.0 [scales] larmor0 = 0.0025 skindepth0 = 0.05 [algorithms] - current_filters = 4 + current_filters = 0 [algorithms.timestep] CFL = 0.5 @@ -35,36 +35,16 @@ fieldsolver = true [particles] - ppc0 = 8.0 - use_weights = true - sort_interval = 100 - - #[[particles.species]] - #label = "e-" - #mass = 1.0 - #charge = -1.0 - #maxnpart = 1e6 - #pusher = "Boris" - # - #[[particles.species]] - #label = "e+" - #mass = 1.0 - #charge = 1.0 - #maxnpart = 1e6 - #pusher = "Boris" + ppc0 = 2.0 [setup] - #multiplicity = 1.0 - #sigma_max = 1000.0 - inj_rmin = 1.2 - inj_rmax = 7.5 [output] format = "hdf5" [output.fields] interval_time = 1.0 - quantities = ["D", "H", "B", "J"] + quantities = ["D", "H", "B", "A"] [output.particles] enable = false From 02c8d5e0c82990f6309c26dd6b1671b4b21ee36b Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Wed, 15 Jan 2025 15:37:20 -0500 Subject: [PATCH 227/773] kernels: all fields are absorbed in GR BC --- src/kernels/fields_bcs.hpp | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/kernels/fields_bcs.hpp b/src/kernels/fields_bcs.hpp index 1bd45b8df..c885d7d43 100644 --- a/src/kernels/fields_bcs.hpp +++ b/src/kernels/fields_bcs.hpp @@ -645,6 +645,26 @@ template i1_ + HALF) }; const real_t x2_0 { metric.template convert<2, Crd::Cd, Crd::Ph>(i2_) }; Fld(i1, i2, comp) += (ONE - math::tanh(dx / (INV_4 * dx_abs))) * finit.bx2({ x1_H, x2_0 }); + } else if (comp == em::bx3) { + const real_t x1_H { metric.template convert<1, Crd::Cd, Crd::Ph>( + i1_ + HALF) }; + const real_t x2_H { metric.template convert<2, Crd::Cd, Crd::Ph>( + i2_ + HALF) }; + Fld(i1, i2, comp) += (ONE - math::tanh(dx / (INV_4 * dx_abs))) * finit.bx3({ x1_H, x2_H }); + } else if (comp == em::ex1) { + const real_t x1_H { metric.template convert<1, Crd::Cd, Crd::Ph>( + i1_ + HALF) }; + const real_t x2_0 { metric.template convert<2, Crd::Cd, Crd::Ph>(i2_) }; + Fld(i1, i2, comp) += (ONE - math::tanh(dx / (INV_4 * dx_abs))) * finit.dx1({ x1_H, x2_0 }); + } else if (comp == em::ex2) { + const real_t x1_0 { metric.template convert<1, Crd::Cd, Crd::Ph>(i1_) }; + const real_t x2_H { metric.template convert<2, Crd::Cd, Crd::Ph>( + i2_ + HALF) }; + Fld(i1, i2, comp) += (ONE - math::tanh(dx / (INV_4 * dx_abs))) * finit.dx2({ x1_0, x2_H }); + } else if (comp == em::ex3) { + const real_t x1_0 { metric.template convert<1, Crd::Cd, Crd::Ph>(i1_) }; + const real_t x2_0 { metric.template convert<2, Crd::Cd, Crd::Ph>(i2_) }; + Fld(i1, i2, comp) += (ONE - math::tanh(dx / (INV_4 * dx_abs))) * finit.dx3({ x1_0, x2_0 }); } } } else { From 0ef23120b66a85dc4a3a2feb6303b4eb76185e03 Mon Sep 17 00:00:00 2001 From: haykh Date: Wed, 22 Jan 2025 15:19:34 -0500 Subject: [PATCH 228/773] hdf5_root -- optionally set --- CMakeLists.txt | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2618a0cb2..efd240993 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -101,23 +101,12 @@ if(${output}) include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/adios2Config.cmake) find_or_fetch_dependency(adios2 FALSE) if(NOT DEFINED ENV{HDF5_ROOT}) - set(USE_CUSTOM_HDF5 OFF) if(DEFINED ENV{CONDA_PREFIX}) execute_process(COMMAND bash -c "conda list | grep \"hdf5\" -q" RESULT_VARIABLE HDF5_INSTALLED) if(HDF5_INSTALLED EQUAL 0) set(HDF5_ROOT $ENV{CONDA_PREFIX}) - else() - set(USE_CUSTOM_HDF5 ON) endif() - else() - set(USE_CUSTOM_HDF5 ON) - endif() - if(USE_CUSTOM_HDF5) - message( - FATAL_ERROR - "HDF5_ROOT is not set. Please set it to the root of the HDF5 installation" - ) endif() endif() find_package(HDF5 REQUIRED) From 16a4086ccd1f8ef8fb54fc02d2682b11bc8693c0 Mon Sep 17 00:00:00 2001 From: haykh Date: Wed, 22 Jan 2025 15:20:30 -0500 Subject: [PATCH 229/773] sort_interval -> clear_interval --- input.example.toml | 13 ++- setups/srpic/blob/blob.toml | 40 ++++---- setups/srpic/em_vacuum/em_vacuum.toml | 22 ++--- setups/srpic/langmuir/langmuir.toml | 36 +++---- setups/srpic/magnetar/magnetar.toml | 96 +++++++++---------- setups/srpic/magnetosphere/magnetosphere.toml | 58 +++++------ setups/srpic/monopole/monopole.toml | 56 +++++------ setups/srpic/shock/shock.toml | 30 +++--- setups/srpic/turbulence/turbulence.toml | 34 +++---- setups/srpic/weibel/weibel.toml | 48 +++++----- 10 files changed, 216 insertions(+), 217 deletions(-) diff --git a/input.example.toml b/input.example.toml index 5ee34d65d..2f6d2b285 100644 --- a/input.example.toml +++ b/input.example.toml @@ -105,7 +105,7 @@ # @note: In spherical, bondaries in theta/phi are set automatically (only specify bc @ [rmin, rmax]) [["ATMOSPHERE", "ABSORB"]] # @note: In GR, the horizon boundary is set automatically (only specify bc @ rmax): [["ABSORB"]] particles = "" - + [grid.boundaries.absorb] # Size of the absorption layer in physical (code) units: # @type: float @@ -119,7 +119,7 @@ coeff = "" [grid.boundaries.atmosphere] - # @required: if ATMOSPHERE is one of the boundaries + # @required: if ATMOSPHERE is one of the boundaries # Temperature of the atmosphere in units of m0 c^2 # @type: float temperature = "" @@ -210,7 +210,7 @@ # @type: float: ~1 # @default: 1.0 correction = "" - + # @inferred: # - dt [= CFL * dx0] # @brief: timestep duration @@ -252,12 +252,11 @@ # @type: bool # @default: false use_weights = "" - # Timesteps between particle re-sorting: + # Timesteps between particle re-sorting (removing dead particles): # @type: unsigned int # @default: 100 - # @note: When MPI is enable, particles are sorted every step. - # @note: When `sort_interval` == 0, the sorting is disabled. - sort_interval = "" + # @note: set to 0 to disable re-sorting + clear_interval = "" # @inferred: # - nspec diff --git a/setups/srpic/blob/blob.toml b/setups/srpic/blob/blob.toml index 7c03b1f9e..7a047f348 100644 --- a/setups/srpic/blob/blob.toml +++ b/setups/srpic/blob/blob.toml @@ -1,24 +1,24 @@ [simulation] - name = "blob" - engine = "srpic" + name = "blob" + engine = "srpic" runtime = 100.0 [simulation.domain] - decomposition = [2,1,1] + decomposition = [2, 1, 1] [grid] resolution = [1024, 1024] - extent = [[-10.0, 10.0], [-10.0, 10.0]] + extent = [[-10.0, 10.0], [-10.0, 10.0]] [grid.metric] metric = "minkowski" [grid.boundaries] - fields = [["PERIODIC"], ["PERIODIC"]] + fields = [["PERIODIC"], ["PERIODIC"]] particles = [["PERIODIC"], ["PERIODIC"]] - + [scales] - larmor0 = 1.0 + larmor0 = 1.0 skindepth0 = 1.0 [algorithms] @@ -31,26 +31,26 @@ ppc0 = 16.0 [[particles.species]] - label = "e-_p" - mass = 1.0 - charge = -1.0 + label = "e-_p" + mass = 1.0 + charge = -1.0 maxnpart = 1e7 [[particles.species]] - label = "e+_p" - mass = 1.0 - charge = 1.0 + label = "e+_p" + mass = 1.0 + charge = 1.0 maxnpart = 1e7 [setup] - temp_1 = 1e-4 - x1c = -5.0 - x2c = 0.0 - v_max = 50.0 - dr = 1.0 - + temp_1 = 1e-4 + x1c = -5.0 + x2c = 0.0 + v_max = 50.0 + dr = 1.0 + [output] - format = "hdf5" + format = "hdf5" interval_time = 1.0 [output.fields] diff --git a/setups/srpic/em_vacuum/em_vacuum.toml b/setups/srpic/em_vacuum/em_vacuum.toml index 156c8d308..23381b1c6 100644 --- a/setups/srpic/em_vacuum/em_vacuum.toml +++ b/setups/srpic/em_vacuum/em_vacuum.toml @@ -1,21 +1,21 @@ [simulation] - name = "em_vacuum" - engine = "srpic" + name = "em_vacuum" + engine = "srpic" runtime = 2.0 [grid] resolution = [256, 512] - extent = [[-1.0, 1.0], [-2.0, 2.0]] + extent = [[-1.0, 1.0], [-2.0, 2.0]] [grid.metric] metric = "minkowski" [grid.boundaries] - fields = [["PERIODIC"], ["PERIODIC"]] + fields = [["PERIODIC"], ["PERIODIC"]] particles = [["PERIODIC"], ["PERIODIC"]] - + [scales] - larmor0 = 0.1 + larmor0 = 0.1 skindepth0 = 0.01 [algorithms] @@ -28,12 +28,12 @@ [setup] amplitude = 1.0 - kx1 = 1 - kx2 = 1 - kx3 = 0 - + kx1 = 1 + kx2 = 1 + kx3 = 0 + [output] - format = "hdf5" + format = "hdf5" interval_time = 0.1 [output.fields] diff --git a/setups/srpic/langmuir/langmuir.toml b/setups/srpic/langmuir/langmuir.toml index 2f3520fc5..b054a940d 100644 --- a/setups/srpic/langmuir/langmuir.toml +++ b/setups/srpic/langmuir/langmuir.toml @@ -1,21 +1,21 @@ [simulation] - name = "langmuir" - engine = "srpic" + name = "langmuir" + engine = "srpic" runtime = 1.0 [grid] resolution = [2048, 512] - extent = [[0.0, 1.0], [0.0, 0.25]] + extent = [[0.0, 1.0], [0.0, 0.25]] [grid.metric] metric = "minkowski" [grid.boundaries] - fields = [["PERIODIC"], ["PERIODIC"]] + fields = [["PERIODIC"], ["PERIODIC"]] particles = [["PERIODIC"], ["PERIODIC"]] - + [scales] - larmor0 = 0.1 + larmor0 = 0.1 skindepth0 = 0.01 [algorithms] @@ -28,24 +28,24 @@ ppc0 = 14.0 [[particles.species]] - label = "e-" - mass = 1.0 - charge = -1.0 - maxnpart = 1e7 + label = "e-" + mass = 1.0 + charge = -1.0 + maxnpart = 1e7 [[particles.species]] - label = "e+" - mass = 1.0 - charge = 1.0 - maxnpart = 1e7 + label = "e+" + mass = 1.0 + charge = 1.0 + maxnpart = 1e7 [setup] vmax = 0.1 - nx1 = 4 - nx2 = 2 - + nx1 = 4 + nx2 = 2 + [output] - format = "hdf5" + format = "hdf5" interval_time = 0.0025 [output.fields] diff --git a/setups/srpic/magnetar/magnetar.toml b/setups/srpic/magnetar/magnetar.toml index 2a2260af5..fab2eb01c 100644 --- a/setups/srpic/magnetar/magnetar.toml +++ b/setups/srpic/magnetar/magnetar.toml @@ -1,17 +1,17 @@ [simulation] - name = "magnetar" - engine = "srpic" + name = "magnetar" + engine = "srpic" runtime = 50.0 [grid] - resolution = [2048,1024] - extent = [[1.0, 400.0]] + resolution = [2048, 1024] + extent = [[1.0, 400.0]] [grid.metric] metric = "qspherical" [grid.boundaries] - fields = [["ATMOSPHERE", "ABSORB"]] + fields = [["ATMOSPHERE", "ABSORB"]] particles = [["ATMOSPHERE", "ABSORB"]] [grid.boundaries.absorb] @@ -19,13 +19,13 @@ [grid.boundaries.atmosphere] temperature = 0.1 - density = 40.0 - height = 0.02 - species = [1, 2] - ds = 0.5 + density = 40.0 + height = 0.02 + species = [1, 2] + ds = 0.5 [scales] - larmor0 = 1e-5 + larmor0 = 1e-5 skindepth0 = 0.01 [algorithms] @@ -36,59 +36,59 @@ [algorithms.gca] e_ovr_b_max = 0.9 - larmor_max = 100.0 + larmor_max = 100.0 [particles] - ppc0 = 4.0 - use_weights = true - sort_interval = 100 + ppc0 = 4.0 + use_weights = true + clear_interval = 100 [[particles.species]] - label = "e-" - mass = 1.0 - charge = -1.0 - maxnpart = 5e7 - pusher = "Boris,GCA" + label = "e-" + mass = 1.0 + charge = -1.0 + maxnpart = 5e7 + pusher = "Boris,GCA" [[particles.species]] - label = "e+" - mass = 1.0 - charge = 1.0 - maxnpart = 5e7 - pusher = "Boris,GCA" + label = "e+" + mass = 1.0 + charge = 1.0 + maxnpart = 5e7 + pusher = "Boris,GCA" [[particles.species]] - label = "e-" - mass = 1.0 - charge = -1.0 - maxnpart = 5e7 - pusher = "Boris,GCA" + label = "e-" + mass = 1.0 + charge = -1.0 + maxnpart = 5e7 + pusher = "Boris,GCA" [[particles.species]] - label = "e+" - mass = 1.0 - charge = 1.0 - maxnpart = 5e7 - pusher = "Boris,GCA" + label = "e+" + mass = 1.0 + charge = 1.0 + maxnpart = 5e7 + pusher = "Boris,GCA" [[particles.species]] - label = "e-" - mass = 1.0 - charge = -1.0 - maxnpart = 5e7 - pusher = "Boris,GCA" + label = "e-" + mass = 1.0 + charge = -1.0 + maxnpart = 5e7 + pusher = "Boris,GCA" [[particles.species]] - label = "e+" - mass = 1.0 - charge = 1.0 - maxnpart = 5e7 - pusher = "Boris,GCA" + label = "e+" + mass = 1.0 + charge = 1.0 + maxnpart = 5e7 + pusher = "Boris,GCA" [setup] - Bsurf = 1.0 - omega = 0.0125 - pp_thres = 10.0 + Bsurf = 1.0 + omega = 0.0125 + pp_thres = 10.0 gamma_pairs = 1.75 [output] @@ -96,7 +96,7 @@ [output.fields] interval_time = 0.5 - quantities = ["N_1", "N_2", "N_3", "N_4", "N_5", "N_6", "B", "E", "J"] + quantities = ["N_1", "N_2", "N_3", "N_4", "N_5", "N_6", "B", "E", "J"] [output.particles] enable = false diff --git a/setups/srpic/magnetosphere/magnetosphere.toml b/setups/srpic/magnetosphere/magnetosphere.toml index 34e04b02d..4c7c9117d 100644 --- a/setups/srpic/magnetosphere/magnetosphere.toml +++ b/setups/srpic/magnetosphere/magnetosphere.toml @@ -1,31 +1,31 @@ [simulation] - name = "magnetosphere" - engine = "srpic" + name = "magnetosphere" + engine = "srpic" runtime = 60.0 [grid] resolution = [2048, 1024] - extent = [[1.0, 50.0]] + extent = [[1.0, 50.0]] [grid.metric] metric = "qspherical" [grid.boundaries] - fields = [["ATMOSPHERE", "ABSORB"]] + fields = [["ATMOSPHERE", "ABSORB"]] particles = [["ATMOSPHERE", "ABSORB"]] - + [grid.boundaries.absorb] ds = 1.0 [grid.boundaries.atmosphere] temperature = 0.1 - density = 10.0 - height = 0.02 - species = [1, 2] - ds = 2.0 - + density = 10.0 + height = 0.02 + species = [1, 2] + ds = 2.0 + [scales] - larmor0 = 2e-5 + larmor0 = 2e-5 skindepth0 = 0.01 [algorithms] @@ -36,37 +36,37 @@ [algorithms.gca] e_ovr_b_max = 0.9 - larmor_max = 1.0 + larmor_max = 1.0 [particles] - ppc0 = 5.0 - use_weights = true - sort_interval = 100 + ppc0 = 5.0 + use_weights = true + clear_interval = 100 [[particles.species]] - label = "e-" - mass = 1.0 - charge = -1.0 - maxnpart = 1e8 - pusher = "Boris,GCA" + label = "e-" + mass = 1.0 + charge = -1.0 + maxnpart = 1e8 + pusher = "Boris,GCA" [[particles.species]] - label = "e+" - mass = 1.0 - charge = 1.0 - maxnpart = 1e8 - pusher = "Boris,GCA" + label = "e+" + mass = 1.0 + charge = 1.0 + maxnpart = 1e8 + pusher = "Boris,GCA" [setup] - Bsurf = 1.0 + Bsurf = 1.0 period = 60.0 [output] format = "hdf5" - + [output.fields] interval_time = 0.1 - quantities = ["N_1", "N_2", "E", "B", "T00"] + quantities = ["N_1", "N_2", "E", "B", "T00"] [output.particles] enable = false @@ -75,5 +75,5 @@ enable = false [diagnostics] - interval = 50 + interval = 50 colored_stdout = true diff --git a/setups/srpic/monopole/monopole.toml b/setups/srpic/monopole/monopole.toml index 169837489..cf735fce8 100644 --- a/setups/srpic/monopole/monopole.toml +++ b/setups/srpic/monopole/monopole.toml @@ -1,31 +1,31 @@ [simulation] - name = "monopole" - engine = "srpic" + name = "monopole" + engine = "srpic" runtime = 60.0 [grid] resolution = [2048, 1024] - extent = [[1.0, 50.0]] + extent = [[1.0, 50.0]] [grid.metric] metric = "qspherical" [grid.boundaries] - fields = [["ATMOSPHERE", "ABSORB"]] + fields = [["ATMOSPHERE", "ABSORB"]] particles = [["ATMOSPHERE", "ABSORB"]] - + [grid.boundaries.absorb] ds = 1.0 [grid.boundaries.atmosphere] temperature = 0.1 - density = 10.0 - height = 0.02 - species = [1, 2] - ds = 2.0 - + density = 10.0 + height = 0.02 + species = [1, 2] + ds = 2.0 + [scales] - larmor0 = 2e-5 + larmor0 = 2e-5 skindepth0 = 0.01 [algorithms] @@ -36,38 +36,38 @@ [algorithms.gca] e_ovr_b_max = 0.9 - larmor_max = 1.0 + larmor_max = 1.0 [particles] - ppc0 = 5.0 - use_weights = true - sort_interval = 100 + ppc0 = 5.0 + use_weights = true + clear_interval = 100 [[particles.species]] - label = "e-" - mass = 1.0 - charge = -1.0 + label = "e-" + mass = 1.0 + charge = -1.0 maxnpart = 1e8 - pusher = "Boris,GCA" + pusher = "Boris,GCA" [[particles.species]] - label = "e+" - mass = 1.0 - charge = 1.0 + label = "e+" + mass = 1.0 + charge = 1.0 maxnpart = 1e8 - pusher = "Boris,GCA" + pusher = "Boris,GCA" [setup] - Bsurf = 1.0 + Bsurf = 1.0 period = 60.0 [output] format = "hdf5" - + [output.fields] interval_time = 0.1 - quantities = ["N_1", "N_2", "E", "B", "T00"] - mom_smooth = 2 + quantities = ["N_1", "N_2", "E", "B", "T00"] + mom_smooth = 2 [output.particles] enable = false @@ -76,5 +76,5 @@ enable = false [diagnostics] - interval = 50 + interval = 50 colored_stdout = true diff --git a/setups/srpic/shock/shock.toml b/setups/srpic/shock/shock.toml index f48edb2d6..7b2cdde2c 100644 --- a/setups/srpic/shock/shock.toml +++ b/setups/srpic/shock/shock.toml @@ -1,21 +1,21 @@ [simulation] - name = "shock" - engine = "srpic" + name = "shock" + engine = "srpic" runtime = 50.0 [grid] resolution = [2048, 128] - extent = [[0.0, 10.0], [-0.3125, 0.3125]] + extent = [[0.0, 10.0], [-0.3125, 0.3125]] [grid.metric] metric = "minkowski" [grid.boundaries] - fields = [["CONDUCTOR", "ABSORB"], ["PERIODIC"]] + fields = [["CONDUCTOR", "ABSORB"], ["PERIODIC"]] particles = [["REFLECT", "ABSORB"], ["PERIODIC"]] - + [scales] - larmor0 = 1e-2 + larmor0 = 1e-2 skindepth0 = 1e-2 [algorithms] @@ -28,24 +28,24 @@ ppc0 = 16.0 [[particles.species]] - label = "e-" - mass = 1.0 - charge = -1.0 + label = "e-" + mass = 1.0 + charge = -1.0 maxnpart = 1e8 [[particles.species]] - label = "e+" - mass = 1.0 - charge = 1.0 + label = "e+" + mass = 1.0 + charge = 1.0 maxnpart = 1e8 [setup] - drift_ux = 0.1 + drift_ux = 0.1 temperature = 1e-3 [output] interval_time = 0.1 - format = "hdf5" - + format = "hdf5" + [output.fields] quantities = ["N_1", "N_2", "E", "B", "T0i_1", "T0i_2", "J"] diff --git a/setups/srpic/turbulence/turbulence.toml b/setups/srpic/turbulence/turbulence.toml index a28afde15..a1f8e29c1 100644 --- a/setups/srpic/turbulence/turbulence.toml +++ b/setups/srpic/turbulence/turbulence.toml @@ -1,21 +1,21 @@ [simulation] - name = "turbulence" - engine = "srpic" + name = "turbulence" + engine = "srpic" runtime = 20.0 [grid] resolution = [184, 184, 184] - extent = [[-1.0, 1.0], [-1.0, 1.0], [-1.0, 1.0]] + extent = [[-1.0, 1.0], [-1.0, 1.0], [-1.0, 1.0]] [grid.metric] metric = "minkowski" [grid.boundaries] - fields = [["PERIODIC"], ["PERIODIC"], ["PERIODIC"]] + fields = [["PERIODIC"], ["PERIODIC"], ["PERIODIC"]] particles = [["PERIODIC"], ["PERIODIC"], ["PERIODIC"]] - + [scales] - larmor0 = 0.02 + larmor0 = 0.02 skindepth0 = 0.02 [algorithms] @@ -28,22 +28,22 @@ ppc0 = 32.0 [[particles.species]] - label = "e-" - mass = 1.0 - charge = -1.0 - maxnpart = 1e8 + label = "e-" + mass = 1.0 + charge = -1.0 + maxnpart = 1e8 [[particles.species]] - label = "e+" - mass = 1.0 - charge = 1.0 - maxnpart = 1e8 + label = "e+" + mass = 1.0 + charge = 1.0 + maxnpart = 1e8 [setup] - + [output] - format = "hdf5" + format = "hdf5" interval_time = 0.1 - + [output.fields] quantities = ["N_1", "N_2", "E", "B", "J", "T00_1", "T00_2"] diff --git a/setups/srpic/weibel/weibel.toml b/setups/srpic/weibel/weibel.toml index c8e2506f6..23d119b24 100644 --- a/setups/srpic/weibel/weibel.toml +++ b/setups/srpic/weibel/weibel.toml @@ -1,21 +1,21 @@ [simulation] - name = "weibel" - engine = "srpic" + name = "weibel" + engine = "srpic" runtime = 100.0 [grid] resolution = [512, 512] - extent = [[-10.0, 10.0], [-10.0, 10.0]] + extent = [[-10.0, 10.0], [-10.0, 10.0]] [grid.metric] metric = "minkowski" [grid.boundaries] - fields = [["PERIODIC"], ["PERIODIC"]] + fields = [["PERIODIC"], ["PERIODIC"]] particles = [["PERIODIC"], ["PERIODIC"]] - + [scales] - larmor0 = 1.0 + larmor0 = 1.0 skindepth0 = 1.0 [algorithms] @@ -28,37 +28,37 @@ ppc0 = 16.0 [[particles.species]] - label = "e-_p" - mass = 1.0 - charge = -1.0 + label = "e-_p" + mass = 1.0 + charge = -1.0 maxnpart = 1e7 [[particles.species]] - label = "e+_p" - mass = 1.0 - charge = 1.0 + label = "e+_p" + mass = 1.0 + charge = 1.0 maxnpart = 1e7 [[particles.species]] - label = "e-_b" - mass = 1.0 - charge = -1.0 + label = "e-_b" + mass = 1.0 + charge = -1.0 maxnpart = 1e7 [[particles.species]] - label = "e+_b" - mass = 1.0 - charge = 1.0 + label = "e+_b" + mass = 1.0 + charge = 1.0 maxnpart = 1e7 [setup] - drift_u_1 = 0.2 - drift_u_2 = 0.2 - temp_1 = 1e-4 - temp_2 = 1e-4 - + drift_u_1 = 0.2 + drift_u_2 = 0.2 + temp_1 = 1e-4 + temp_2 = 1e-4 + [output] - format = "hdf5" + format = "hdf5" interval_time = 0.25 [output.fields] From e2644a691eab9107b9cd338f2804e82391576a80 Mon Sep 17 00:00:00 2001 From: haykh Date: Wed, 22 Jan 2025 15:21:41 -0500 Subject: [PATCH 230/773] rm old sorting + added new comm --- src/engines/engine.hpp | 6 +- src/engines/engine_printer.cpp | 4 +- src/engines/engine_run.cpp | 15 +- src/engines/srpic.hpp | 23 +- src/framework/containers/particles.cpp | 184 +++-- src/framework/containers/particles.h | 23 +- src/framework/domain/comm_mpi.hpp | 895 ++++++------------------ src/framework/domain/communications.cpp | 755 ++++---------------- src/framework/domain/domain.h | 11 +- src/framework/domain/metadomain.cpp | 27 - src/framework/domain/metadomain.h | 6 +- src/framework/domain/output.cpp | 13 +- src/framework/parameters.cpp | 19 +- src/framework/tests/parameters.cpp | 105 +-- src/global/arch/directions.h | 126 ++-- src/global/arch/kokkos_aliases.cpp | 52 +- src/global/defaults.h | 8 +- src/global/global.cpp | 12 +- src/global/global.h | 2 +- src/global/utils/diag.cpp | 11 +- src/global/utils/diag.h | 6 +- src/global/utils/timer.cpp | 13 +- src/kernels/particle_pusher_sr.hpp | 2 +- 23 files changed, 674 insertions(+), 1644 deletions(-) diff --git a/src/engines/engine.hpp b/src/engines/engine.hpp index 5b7caa502..dac553dcd 100644 --- a/src/engines/engine.hpp +++ b/src/engines/engine.hpp @@ -55,10 +55,12 @@ namespace ntt { static_assert(user::PGen::is_pgen, "unrecognized problem generator"); protected: -#if MPI_ENABLED +#if defined(OUTPUT_ENABLED) + #if defined(MPI_ENABLED) adios2::ADIOS m_adios { MPI_COMM_WORLD }; -#else + #else adios2::ADIOS m_adios; + #endif #endif SimulationParams m_params; diff --git a/src/engines/engine_printer.cpp b/src/engines/engine_printer.cpp index 2608ea2f6..4b6ed42d7 100644 --- a/src/engines/engine_printer.cpp +++ b/src/engines/engine_printer.cpp @@ -105,8 +105,8 @@ namespace ntt { color::RESET); } - auto bytes_to_human_readable(std::size_t bytes) - -> std::pair { + auto bytes_to_human_readable( + std::size_t bytes) -> std::pair { const std::vector units { "B", "KB", "MB", "GB", "TB" }; std::size_t unit_idx = 0; auto size = static_cast(bytes); diff --git a/src/engines/engine_run.cpp b/src/engines/engine_run.cpp index bec5b8652..1db2de2ca 100644 --- a/src/engines/engine_run.cpp +++ b/src/engines/engine_run.cpp @@ -26,8 +26,8 @@ namespace ntt { "CurrentFiltering", "CurrentDeposit", "ParticlePusher", "FieldBoundaries", "ParticleBoundaries", "Communications", - "Injector", "Sorting", - "Custom", "Output", + "Injector", "Custom", + "PrtlClear", "Output", "Checkpoint" }, []() { Kokkos::fence(); @@ -37,9 +37,9 @@ namespace ntt { const auto diag_interval = m_params.get( "diagnostics.interval"); - auto time_history = pbar::DurationHistory { 1000 }; - const auto sort_interval = m_params.template get( - "particles.sort_interval"); + auto time_history = pbar::DurationHistory { 1000 }; + const auto clear_interval = m_params.template get( + "particles.clear_interval"); // main algorithm loop while (step < max_steps) { @@ -56,7 +56,8 @@ namespace ntt { }); timers.stop("Custom"); } - auto print_sorting = (sort_interval > 0 and step % sort_interval == 0); + auto print_prtl_clear = (clear_interval > 0 and + step % clear_interval == 0 and step > 0); // advance time & step time += dt; @@ -109,7 +110,7 @@ namespace ntt { m_metadomain.species_labels(), m_metadomain.l_npart_perspec(), m_metadomain.l_maxnpart_perspec(), - print_sorting, + print_prtl_clear, print_output, print_checkpoint, m_params.get("diagnostics.colored_stdout")); diff --git a/src/engines/srpic.hpp b/src/engines/srpic.hpp index 0489d8508..b54291540 100644 --- a/src/engines/srpic.hpp +++ b/src/engines/srpic.hpp @@ -80,8 +80,8 @@ namespace ntt { "algorithms.toggles.fieldsolver"); const auto deposit_enabled = m_params.template get( "algorithms.toggles.deposit"); - const auto sort_interval = m_params.template get( - "particles.sort_interval"); + const auto clear_interval = m_params.template get( + "particles.clear_interval"); if (step == 0) { // communicate fields and apply BCs on the first timestep @@ -126,15 +126,8 @@ namespace ntt { timers.stop("CurrentFiltering"); } - // Tags are assigned by now - if (step == 0){ - m_metadomain.SetParticleIDs(dom); - } - timers.start("Communications"); - if ((sort_interval > 0) and (step % sort_interval == 0)) { - m_metadomain.CommunicateParticlesBuffer(dom, &timers); - } + m_metadomain.CommunicateParticles(dom); timers.stop("Communications"); } @@ -176,12 +169,10 @@ namespace ntt { timers.stop("Injector"); } - if (step % 100 == 0 && step > 0){ - MPI_Barrier(MPI_COMM_WORLD); - timers.start("RemoveDead"); - m_metadomain.RemoveDeadParticles(dom, &timers); - timers.stop("RemoveDead"); - MPI_Barrier(MPI_COMM_WORLD); + if (clear_interval > 0 and step % clear_interval == 0 and step > 0) { + timers.start("PrtlClear"); + m_metadomain.RemoveDeadParticles(dom); + timers.stop("PrtlClear"); } } diff --git a/src/framework/containers/particles.cpp b/src/framework/containers/particles.cpp index 1cb63bf43..758118d6c 100644 --- a/src/framework/containers/particles.cpp +++ b/src/framework/containers/particles.cpp @@ -10,7 +10,9 @@ #include #include +#include +#include #include #include @@ -47,9 +49,6 @@ namespace ntt { tag = array_t { label + "_tag", maxnpart }; tag_h = Kokkos::create_mirror_view(tag); - particleID = array_t {label + "_particleID", maxnpart}; - particleID_h = Kokkos::create_mirror_view(particleID); - for (unsigned short n { 0 }; n < npld; ++n) { pld.push_back(array_t("pld", maxnpart)); pld_h.push_back(Kokkos::create_mirror_view(pld[n])); @@ -81,93 +80,150 @@ namespace ntt { } template - auto Particles::npart_per_tag() const -> std::pair, - array_t>{ + auto Particles::NpartsPerTagAndOffsets() const + -> std::pair, array_t> { auto this_tag = tag; - array_t npart_tag("npart_tags", ntags()); + const auto num_tags = ntags(); + array_t npptag("nparts_per_tag", ntags()); - // Print tag_h array - auto tag_host = Kokkos::create_mirror_view(tag); - Kokkos::deep_copy(tag_host, tag); - auto npart_tag_scatter = Kokkos::Experimental::create_scatter_view(npart_tag); + // count # of particles per each tag + auto npptag_scat = Kokkos::Experimental::create_scatter_view(npptag); Kokkos::parallel_for( "NpartPerTag", - npart(), + rangeActiveParticles(), Lambda(index_t p) { - auto npart_tag_scatter_access = npart_tag_scatter.access(); - npart_tag_scatter_access((int)(this_tag(p))) += 1; + auto npptag_acc = npptag_scat.access(); + if (this_tag(p) < 0 || this_tag(p) >= num_tags) { + raise::KernelError(HERE, "Invalid tag value"); + } + npptag_acc(this_tag(p)) += 1; }); - Kokkos::Experimental::contribute(npart_tag, npart_tag_scatter); + Kokkos::Experimental::contribute(npptag, npptag_scat); + + // copy the count to a vector on the host + auto npptag_h = Kokkos::create_mirror_view(npptag); + Kokkos::deep_copy(npptag_h, npptag); + std::vector npptag_vec(num_tags); + for (auto t { 0u }; t < num_tags; ++t) { + npptag_vec[t] = npptag_h(t); + } - auto npart_tag_host = Kokkos::create_mirror_view(npart_tag); - Kokkos::deep_copy(npart_tag_host, npart_tag); - array_t tag_offset("tag_offset", ntags()); - auto tag_offset_host = Kokkos::create_mirror_view(tag_offset); + // count the offsets on the host and copy to device + array_t tag_offset("tag_offset", num_tags - 3); + auto tag_offset_h = Kokkos::create_mirror_view(tag_offset); - std::vector npart_tag_vec(ntags()); - for (std::size_t t { 0 }; t < ntags(); ++t) { - npart_tag_vec[t] = npart_tag_host(t); - tag_offset_host(t) = (t > 0) ? npart_tag_vec[t - 1] : 0; - } - for (std::size_t t { 0 }; t < ntags(); ++t) { - tag_offset_host(t) += (t > 0) ? tag_offset_host(t - 1) : 0; + for (auto t { 0u }; t < num_tags - 3; ++t) { + tag_offset_h(t) = npptag_vec[t + 2] + (t > 0u ? tag_offset_h(t - 1) : 0); } - Kokkos::deep_copy(tag_offset, tag_offset_host); - return std::make_pair(npart_tag_vec, tag_offset); + Kokkos::deep_copy(tag_offset, tag_offset_h); + + return { npptag_vec, tag_offset }; } - template - auto Particles::SortByTags() -> std::vector { - if (npart() == 0 || is_sorted()) { - return npart_per_tag().first; - } - using KeyType = array_t; - using BinOp = sort::BinTag; - BinOp bin_op(ntags()); - auto slice = range_tuple_t(0, npart()); - Kokkos::BinSort Sorter(Kokkos::subview(tag, slice), bin_op, false); - Sorter.create_permute_vector(); + template + void RemoveDeadInArray(array_t& arr, + const array_t& indices_alive) { + auto n_alive = indices_alive.extent(0); + auto buffer = Kokkos::View("buffer", n_alive); + Kokkos::parallel_for( + "PopulateBufferAlive", + n_alive, + Lambda(index_t p) { buffer(p) = arr(indices_alive(p)); }); - Sorter.sort(Kokkos::subview(i1, slice)); - Sorter.sort(Kokkos::subview(dx1, slice)); - Sorter.sort(Kokkos::subview(i1_prev, slice)); - Sorter.sort(Kokkos::subview(dx1_prev, slice)); - Sorter.sort(Kokkos::subview(ux1, slice)); - Sorter.sort(Kokkos::subview(ux2, slice)); - Sorter.sort(Kokkos::subview(ux3, slice)); + Kokkos::deep_copy( + Kokkos::subview(arr, std::make_pair(static_cast(0), n_alive)), + buffer); + } + + template + void Particles::RemoveDead() { + const auto n_part = npart(); + std::size_t n_alive = 0, n_dead = 0; + auto& this_tag = tag; + + Kokkos::parallel_reduce( + "CountDeadAlive", + rangeActiveParticles(), + Lambda(index_t p, std::size_t & nalive, std::size_t & ndead) { + nalive += (this_tag(p) == ParticleTag::alive); + ndead += (this_tag(p) == ParticleTag::dead); + if (this_tag(p) != ParticleTag::alive and this_tag(p) != ParticleTag::dead) { + raise::KernelError(HERE, "wrong particle tag"); + } + }, + n_alive, + n_dead); + + array_t indices_alive { "indices_alive", n_alive }; + array_t alive_counter { "counter_alive", 1 }; - Sorter.sort(Kokkos::subview(tag, slice)); - Sorter.sort(Kokkos::subview(weight, slice)); + Kokkos::parallel_for( + "AliveIndices", + rangeActiveParticles(), + Lambda(index_t p) { + if (this_tag(p) == ParticleTag::alive) { + const auto idx = Kokkos::atomic_fetch_add(&alive_counter(0), 1); + indices_alive(idx) = p; + } + }); - for (unsigned short n { 0 }; n < npld(); ++n) { - Sorter.sort(Kokkos::subview(pld[n], slice)); + { + auto alive_counter_h = Kokkos::create_mirror_view(alive_counter); + Kokkos::deep_copy(alive_counter_h, alive_counter); + raise::ErrorIf(alive_counter_h(0) != n_alive, + "error in finding alive particle indices", + HERE); } - if constexpr ((D == Dim::_2D) || (D == Dim::_3D)) { - Sorter.sort(Kokkos::subview(i2, slice)); - Sorter.sort(Kokkos::subview(dx2, slice)); + if constexpr (D == Dim::_1D or D == Dim::_2D or D == Dim::_3D) { + RemoveDeadInArray(i1, indices_alive); + RemoveDeadInArray(i1_prev, indices_alive); + RemoveDeadInArray(dx1, indices_alive); + RemoveDeadInArray(dx1_prev, indices_alive); + } - Sorter.sort(Kokkos::subview(i2_prev, slice)); - Sorter.sort(Kokkos::subview(dx2_prev, slice)); + if constexpr (D == Dim::_2D or D == Dim::_3D) { + RemoveDeadInArray(i2, indices_alive); + RemoveDeadInArray(i2_prev, indices_alive); + RemoveDeadInArray(dx2, indices_alive); + RemoveDeadInArray(dx2_prev, indices_alive); } + if constexpr (D == Dim::_3D) { - Sorter.sort(Kokkos::subview(i3, slice)); - Sorter.sort(Kokkos::subview(dx3, slice)); + RemoveDeadInArray(i3, indices_alive); + RemoveDeadInArray(i3_prev, indices_alive); + RemoveDeadInArray(dx3, indices_alive); + RemoveDeadInArray(dx3_prev, indices_alive); + } + + RemoveDeadInArray(ux1, indices_alive); + RemoveDeadInArray(ux2, indices_alive); + RemoveDeadInArray(ux3, indices_alive); + RemoveDeadInArray(weight, indices_alive); - Sorter.sort(Kokkos::subview(i3_prev, slice)); - Sorter.sort(Kokkos::subview(dx3_prev, slice)); + if constexpr (D == Dim::_2D && C != Coord::Cart) { + RemoveDeadInArray(phi, indices_alive); } - if ((D == Dim::_2D) && (C != Coord::Cart)) { - Sorter.sort(Kokkos::subview(phi, slice)); + for (auto& payload : pld) { + RemoveDeadInArray(payload, indices_alive); } - auto np_per_tag_tag_offset = npart_per_tag(); - const auto np_per_tag = np_per_tag_tag_offset.first; - set_npart(np_per_tag[(short)(ParticleTag::alive)]); + Kokkos::Experimental::fill( + "TagAliveParticles", + AccelExeSpace(), + Kokkos::subview(this_tag, + std::make_pair(static_cast(0), n_alive)), + ParticleTag::alive); + + Kokkos::Experimental::fill( + "TagDeadParticles", + AccelExeSpace(), + Kokkos::subview(this_tag, std::make_pair(n_alive, n_alive + n_dead)), + ParticleTag::dead); + set_npart(n_alive); m_is_sorted = true; - return np_per_tag; } template diff --git a/src/framework/containers/particles.h b/src/framework/containers/particles.h index 131ff45c0..3ae68b402 100644 --- a/src/framework/containers/particles.h +++ b/src/framework/containers/particles.h @@ -64,8 +64,6 @@ namespace ntt { std::vector> pld; // phi coordinate (for axisymmetry) array_t phi; - // Array to store the particle ids - array_t particleID; // host mirrors array_mirror_t i1_h, i2_h, i3_h; @@ -75,7 +73,6 @@ namespace ntt { array_mirror_t phi_h; array_mirror_t tag_h; std::vector> pld_h; - array_mirror_t particleID_h; // for empty allocation Particles() {} @@ -181,7 +178,6 @@ namespace ntt { footprint += sizeof(prtldx_t) * dx2_prev.extent(0); footprint += sizeof(prtldx_t) * dx3_prev.extent(0); footprint += sizeof(short) * tag.extent(0); - footprint += sizeof(long) * particleID.extent(0); for (auto& p : pld) { footprint += sizeof(real_t) * p.extent(0); } @@ -191,9 +187,19 @@ namespace ntt { /** * @brief Count the number of particles with a specific tag. - * @return The vector of counts for each tag. + * @return The vector of counts for each tag + offsets + * @note For instance, given the counts: 0 -> n0, 1 -> n1, 2 -> n2, 3 -> n3, + * ... it returns: + * ... [n0, n1, n2, n3, ...] of size ntags + * ... [n2, n2 + n3, n2 + n3 + n4, ...] of size ntags - 3 + * ... so in buffer array: + * ... tag=2 particles are offset by 0 + * ... tag=3 particles are offset by n2 + * ... tag=4 particles are offset by n2 + n3 + * ... etc. */ - auto npart_per_tag() const -> std::pair, array_t>; + auto NpartsPerTagAndOffsets() const + -> std::pair, array_t>; /* setters -------------------------------------------------------------- */ /** @@ -216,10 +222,9 @@ namespace ntt { } /** - * @brief Sort particles by their tags. - * @return The vector of counts per each tag. + * @brief Move dead particles to the end of arrays */ - auto SortByTags() -> std::vector; + void RemoveDead(); /** * @brief Copy particle data from device to host. diff --git a/src/framework/domain/comm_mpi.hpp b/src/framework/domain/comm_mpi.hpp index ce38a8261..370c02b18 100644 --- a/src/framework/domain/comm_mpi.hpp +++ b/src/framework/domain/comm_mpi.hpp @@ -24,6 +24,7 @@ #include #include +#include #include namespace comm { @@ -283,50 +284,10 @@ namespace comm { } } - template - void CommunicateParticleQuantity(array_t& arr, - int send_rank, - int recv_rank, - const range_tuple_t& send_slice, - const range_tuple_t& recv_slice) { - const std::size_t send_count = send_slice.second - send_slice.first; - const std::size_t recv_count = recv_slice.second - recv_slice.first; - if ((send_rank >= 0) and (recv_rank >= 0) and (send_count > 0) and - (recv_count > 0)) { - MPI_Sendrecv(arr.data() + send_slice.first, - send_count, - mpi::get_type(), - send_rank, - 0, - arr.data() + recv_slice.first, - recv_count, - mpi::get_type(), - recv_rank, - 0, - MPI_COMM_WORLD, - MPI_STATUS_IGNORE); - } else if ((send_rank >= 0) and (send_count > 0)) { - MPI_Send(arr.data() + send_slice.first, - send_count, - mpi::get_type(), - send_rank, - 0, - MPI_COMM_WORLD); - } else if ((recv_rank >= 0) and (recv_count > 0)) { - MPI_Recv(arr.data() + recv_slice.first, - recv_count, - mpi::get_type(), - recv_rank, - 0, - MPI_COMM_WORLD, - MPI_STATUS_IGNORE); - } - } - - void ParticleSendRecvCount(int send_rank, - int recv_rank, - const std::size_t& send_count, - std::size_t& recv_count) { + void ParticleSendRecvCount(int send_rank, + int recv_rank, + std::size_t send_count, + std::size_t& recv_count) { if ((send_rank >= 0) && (recv_rank >= 0)) { MPI_Sendrecv(&send_count, 1, @@ -356,644 +317,246 @@ namespace comm { } template - auto CommunicateParticles(Particles& species, - int send_rank, - int recv_rank, - const range_tuple_t& send_slice, - std::size_t& index_last) -> std::size_t { - if ((send_rank < 0) && (recv_rank < 0)) { - raise::Error("No send or recv in CommunicateParticles", HERE); - } - std::size_t recv_count { 0 }; - ParticleSendRecvCount(send_rank, - recv_rank, - send_slice.second - send_slice.first, - recv_count); - raise::FatalIf((index_last + recv_count) >= species.maxnpart(), - "Too many particles to receive (cannot fit into maxptl)", - HERE); - const auto recv_slice = range_tuple_t({ index_last, index_last + recv_count }); - CommunicateParticleQuantity(species.i1, send_rank, recv_rank, send_slice, recv_slice); - CommunicateParticleQuantity(species.dx1, send_rank, recv_rank, send_slice, recv_slice); - CommunicateParticleQuantity(species.i1_prev, - send_rank, - recv_rank, - send_slice, - recv_slice); - CommunicateParticleQuantity(species.dx1_prev, - send_rank, - recv_rank, - send_slice, - recv_slice); - if constexpr (D == Dim::_2D || D == Dim::_3D) { - CommunicateParticleQuantity(species.i2, send_rank, recv_rank, send_slice, recv_slice); - CommunicateParticleQuantity(species.dx2, - send_rank, - recv_rank, - send_slice, - recv_slice); - CommunicateParticleQuantity(species.i2_prev, - send_rank, - recv_rank, - send_slice, - recv_slice); - CommunicateParticleQuantity(species.dx2_prev, - send_rank, - recv_rank, - send_slice, - recv_slice); - } - if constexpr (D == Dim::_3D) { - CommunicateParticleQuantity(species.i3, send_rank, recv_rank, send_slice, recv_slice); - CommunicateParticleQuantity(species.dx3, - send_rank, - recv_rank, - send_slice, - recv_slice); - CommunicateParticleQuantity(species.i3_prev, - send_rank, - recv_rank, - send_slice, - recv_slice); - CommunicateParticleQuantity(species.dx3_prev, - send_rank, - recv_rank, - send_slice, - recv_slice); - } - CommunicateParticleQuantity(species.ux1, send_rank, recv_rank, send_slice, recv_slice); - CommunicateParticleQuantity(species.ux2, send_rank, recv_rank, send_slice, recv_slice); - CommunicateParticleQuantity(species.ux3, send_rank, recv_rank, send_slice, recv_slice); - CommunicateParticleQuantity(species.weight, - send_rank, - recv_rank, - send_slice, - recv_slice); - if constexpr (D == Dim::_2D and C != Coord::Cart) { - CommunicateParticleQuantity(species.phi, - send_rank, - recv_rank, - send_slice, - recv_slice); - } - for (auto p { 0 }; p < species.npld(); ++p) { - CommunicateParticleQuantity(species.pld[p], - send_rank, - recv_rank, - send_slice, - recv_slice); - } - return recv_count; - } + void CommunicateParticles(Particles& species, + Kokkos::View outgoing_indices, + Kokkos::View tag_offsets, + std::vector npptag_vec, + std::vector npptag_recv_vec, + std::vector send_ranks, + std::vector recv_ranks, + const dir::dirs_t& dirs_to_comm) { + // Pointers to the particle data arrays + auto& this_i1 = species.i1; + auto& this_i1_prev = species.i1_prev; + auto& this_i2 = species.i2; + auto& this_i2_prev = species.i2_prev; + auto& this_i3 = species.i3; + auto& this_i3_prev = species.i3_prev; + auto& this_dx1 = species.dx1; + auto& this_dx1_prev = species.dx1_prev; + auto& this_dx2 = species.dx2; + auto& this_dx2_prev = species.dx2_prev; + auto& this_dx3 = species.dx3; + auto& this_dx3_prev = species.dx3_prev; + auto& this_phi = species.phi; + auto& this_ux1 = species.ux1; + auto& this_ux2 = species.ux2; + auto& this_ux3 = species.ux3; + auto& this_weight = species.weight; + auto& this_tag = species.tag; + + // number of arrays of each type to send/recv + const unsigned short NREALS = 4 + static_cast( + D == Dim::_2D and C != Coord::Cart); + const unsigned short NINTS = 2 * static_cast(D); + const unsigned short NPRTLDX = 2 * static_cast(D); + const unsigned short NPLD = species.npld(); + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + // buffers to store recv data + const auto npart_alive = npptag_vec[ParticleTag::alive]; + const auto npart_dead = npptag_vec[ParticleTag::dead]; + const auto npart_send = outgoing_indices.extent(0) - npart_dead; + const auto npart_recv = std::accumulate(npptag_recv_vec.begin(), + npptag_recv_vec.end(), + static_cast(0)); - template - void CommunicateParticlesBuffer(Particles& species, - Kokkos::View permute_vector, - Kokkos::View allocation_vector, - Kokkos::View tag_offset, - std::vector npart_per_tag_arr, - std::vector npart_per_tag_arr_recv, - std::vector send_ranks, - std::vector recv_ranks, - const dir::dirs_t& legal_directions) { - // Pointers to the particle data arrays - auto &this_ux1 = species.ux1; - auto &this_ux2 = species.ux2; - auto &this_ux3 = species.ux3; - auto &this_weight = species.weight; - auto &this_phi = species.phi; - auto &this_i1 = species.i1; - auto &this_i1_prev = species.i1_prev; - auto &this_i2 = species.i2; - auto &this_i3 = species.i3; - auto &this_i2_prev = species.i2_prev; - auto &this_i3_prev = species.i3_prev; - auto &this_dx1 = species.dx1; - auto &this_dx1_prev = species.dx1_prev; - auto &this_dx2 = species.dx2; - auto &this_dx3 = species.dx3; - auto &this_dx2_prev = species.dx2_prev; - auto &this_dx3_prev = species.dx3_prev; - auto &this_tag = species.tag; - auto &this_particleID = species.particleID; - - // Number of arrays of each type to send/recv - auto NREALS = 4; - auto NINTS = 2; - auto NFLOATS = 2; - auto NLONGS = 2; - if constexpr (D == Dim::_2D) { - if (C != Coord::Cart) { - NREALS = 5; - NINTS = 4; - NFLOATS = 4; - this_phi = species.phi; - } else { - NREALS = 4; - NINTS = 4; - NFLOATS = 4; - } - } - if constexpr (D == Dim::_3D) { - NREALS = 4; - NINTS = 6; - NFLOATS = 6; - } + Kokkos::View recv_buff_int { "recv_buff_int", npart_recv * NINTS }; + Kokkos::View recv_buff_real { "recv_buff_real", npart_recv * NREALS }; + Kokkos::View recv_buff_prtldx { "recv_buff_prtldx", + npart_recv * NPRTLDX }; - // Now make buffers to store recevied data (don't need global send buffers) - const auto total_send = permute_vector.extent(0) - npart_per_tag_arr[ParticleTag::dead]; - const auto total_recv = allocation_vector.extent(0); - const auto n_alive = npart_per_tag_arr[ParticleTag::alive]; - const auto n_dead = npart_per_tag_arr[ParticleTag::dead]; - - // Debug test: print send and recv count - { - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - //printf("MPI rank: %d, Total send: %d, Total recv: %d \n", rank, total_send, total_recv); - } - /* - Brief on recv buffers: Each recv buffer contains all the received arrays of - a given type. The different physical quantities are stored next to each other - to avoid cache misses. The array is structured as follows: - E.g., - recv_buffer_int: | qty1 | qty2 | ... | qtyNINTS | qty1 | qty2 | ... | qtyNINTS | ... - <-------particle to recv1------> <-------particle to recv2--------> - <----------------------------------total_recv----------------------------> - */ - Kokkos::View recv_buffer_int("recv_buffer_int", total_recv * NINTS); - Kokkos::View recv_buffer_real("recv_buffer_real", total_recv * NREALS); - Kokkos::View recv_buffer_prtldx("recv_buffer_prtldx",total_recv * NFLOATS); - Kokkos::View recv_buffer_long("recv_buffer_long", total_recv * NLONGS); - auto recv_buffer_int_h = Kokkos::create_mirror_view(recv_buffer_int); - auto recv_buffer_real_h = Kokkos::create_mirror_view(recv_buffer_real); - auto recv_buffer_prtldx_h = Kokkos::create_mirror_view(recv_buffer_prtldx); - auto recv_buffer_long_h = Kokkos::create_mirror_view(recv_buffer_long); - - auto iteration = 0; + auto iteration = 0; auto current_received = 0; - for (const auto& direction : legal_directions) { - const auto send_rank = send_ranks[iteration]; - const auto recv_rank = recv_ranks[iteration]; - const auto tag_send = mpi::PrtlSendTag::dir2tag(direction); - const auto tag_recv = mpi::PrtlSendTag::dir2tag(-direction); - const auto send_count = npart_per_tag_arr[tag_send]; - const auto recv_count = npart_per_tag_arr_recv[tag_recv]; - { - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - } + + for (const auto& direction : dirs_to_comm) { + const auto send_rank = send_ranks[iteration]; + const auto recv_rank = recv_ranks[iteration]; + const auto tag_send = mpi::PrtlSendTag::dir2tag(direction); + const auto tag_recv = mpi::PrtlSendTag::dir2tag(-direction); + const auto npart_send_in = npptag_vec[tag_send]; + const auto npart_recv_in = npptag_recv_vec[tag_recv - 2]; if (send_rank < 0 and recv_rank < 0) { continue; } - Kokkos::View send_buffer_int("send_buffer_int", send_count * NINTS); - Kokkos::View send_buffer_real("send_buffer_real", send_count * NREALS); - Kokkos::View send_buffer_prtldx("send_buffer_prtldx",send_count * NFLOATS); - Kokkos::View send_buffer_long("send_buffer_long", send_count * NLONGS); - auto send_buffer_int_h = Kokkos::create_mirror_view(send_buffer_int); - auto send_buffer_real_h = Kokkos::create_mirror_view(send_buffer_real); - auto send_buffer_prtldx_h = Kokkos::create_mirror_view(send_buffer_prtldx); - auto send_buffer_long_h = Kokkos::create_mirror_view(send_buffer_long); - - // Need different constexpr parallel fors for different dims - if constexpr(D == Dim::_1D) { - Kokkos::parallel_for( - "PopulateSendBuffer", - send_count, - Lambda(const std::size_t p){ - const auto idx = permute_vector(tag_offset(tag_send) - n_alive + p); - send_buffer_int(NINTS * p + 0) = this_i1(idx); - send_buffer_int(NINTS * p + 1) = this_i1_prev(idx); - send_buffer_real(NREALS * p + 0) = this_ux1(idx); - send_buffer_real(NREALS * p + 1) = this_ux2(idx); - send_buffer_real(NREALS * p + 2) = this_ux3(idx); - send_buffer_real(NREALS * p + 3) = this_weight(idx); - send_buffer_prtldx(NFLOATS * p + 0) = this_dx1(idx); - send_buffer_prtldx(NFLOATS * p + 1) = this_dx1_prev(idx); - send_buffer_long(NLONGS * p + 0) = this_particleID(idx); - send_buffer_long(NLONGS * p + 1) = this_tag(idx); - this_tag(idx) = ParticleTag::dead; - }); - } - if constexpr(D == Dim::_2D && C == Coord::Cart) { - Kokkos::parallel_for( - "PopulateSendBuffer", - send_count, - Lambda(const std::size_t p){ - const auto idx = permute_vector(tag_offset(tag_send) - n_alive + p); - send_buffer_int(NINTS * p + 0) = this_i1(idx); - send_buffer_int(NINTS * p + 1) = this_i1_prev(idx); - send_buffer_int(NINTS * p + 2) = this_i2(idx); - send_buffer_int(NINTS * p + 3) = this_i2_prev(idx); - send_buffer_real(NREALS * p + 0) = this_ux1(idx); - send_buffer_real(NREALS * p + 1) = this_ux2(idx); - send_buffer_real(NREALS * p + 2) = this_ux3(idx); - send_buffer_real(NREALS * p + 3) = this_weight(idx); - send_buffer_prtldx(NFLOATS * p + 0) = this_dx1(idx); - send_buffer_prtldx(NFLOATS * p + 1) = this_dx1_prev(idx); - send_buffer_prtldx(NFLOATS * p + 2) = this_dx2(idx); - send_buffer_prtldx(NFLOATS * p + 3) = this_dx2_prev(idx); - send_buffer_long(NLONGS * p + 0) = this_particleID(idx); - send_buffer_long(NLONGS * p + 1) = this_tag(idx); - this_tag(idx) = ParticleTag::dead; - }); - } - if constexpr(D == Dim::_2D && C != Coord::Cart) { - Kokkos::parallel_for( - "PopulateSendBuffer", - send_count, - Lambda(const std::size_t p){ - const auto idx = permute_vector(tag_offset(tag_send) - n_alive + p); - send_buffer_int(NINTS * p + 0) = this_i1(idx); - send_buffer_int(NINTS * p + 1) = this_i1_prev(idx); - send_buffer_int(NINTS * p + 2) = this_i2(idx); - send_buffer_int(NINTS * p + 3) = this_i2_prev(idx); - send_buffer_real(NREALS * p + 0) = this_ux1(idx); - send_buffer_real(NREALS * p + 1) = this_ux2(idx); - send_buffer_real(NREALS * p + 2) = this_ux3(idx); - send_buffer_real(NREALS * p + 3) = this_weight(idx); - send_buffer_real(NREALS * p + 4) = this_phi(idx); - send_buffer_prtldx(NFLOATS * p + 0) = this_dx1(idx); - send_buffer_prtldx(NFLOATS * p + 1) = this_dx1_prev(idx); - send_buffer_prtldx(NFLOATS * p + 2) = this_dx2(idx); - send_buffer_prtldx(NFLOATS * p + 3) = this_dx2_prev(idx); - send_buffer_long(NLONGS * p + 0) = this_particleID(idx); - send_buffer_long(NLONGS * p + 1) = this_tag(idx); - this_tag(idx) = ParticleTag::dead; - }); - } - if constexpr(D == Dim::_3D) { - Kokkos::parallel_for( - "PopulateSendBuffer", - send_count, - Lambda(const std::size_t p){ - const auto idx = permute_vector(tag_offset(tag_send) - n_alive + p); - send_buffer_int(NINTS * p + 0) = this_i1(idx); - send_buffer_int(NINTS * p + 1) = this_i1_prev(idx); - send_buffer_int(NINTS * p + 2) = this_i2(idx); - send_buffer_int(NINTS * p + 3) = this_i2_prev(idx); - send_buffer_int(NINTS * p + 4) = this_i3(idx); - send_buffer_int(NINTS * p + 5) = this_i3_prev(idx); - send_buffer_real(NREALS * p + 0) = this_ux1(idx); - send_buffer_real(NREALS * p + 1) = this_ux2(idx); - send_buffer_real(NREALS * p + 2) = this_ux3(idx); - send_buffer_real(NREALS * p + 3) = this_weight(idx); - send_buffer_prtldx(NFLOATS * p + 0) = this_dx1(idx); - send_buffer_prtldx(NFLOATS * p + 1) = this_dx1_prev(idx); - send_buffer_prtldx(NFLOATS * p + 2) = this_dx2(idx); - send_buffer_prtldx(NFLOATS * p + 3) = this_dx2_prev(idx); - send_buffer_prtldx(NFLOATS * p + 4) = this_dx3(idx); - send_buffer_prtldx(NFLOATS * p + 5) = this_dx3_prev(idx); - send_buffer_long(NLONGS * p + 0) = this_particleID(idx); - send_buffer_long(NLONGS * p + 1) = this_tag(idx); - this_tag(idx) = ParticleTag::dead; - }); - } - - auto tag_offset_h = Kokkos::create_mirror_view(tag_offset); - Kokkos::deep_copy(tag_offset_h, tag_offset); - /* - Brief on receive offset: - The receive buffer looks like this - <-----------------------------------> - |NINT|NINT|NINT|NINT|NINT|NINT|NINT|NINT|...xnrecv - <--------><--------><--------><--------> - recv1 recv2 recv3 recv4 - |________| - ^ ^ - offset offset + nrecv - */ - const auto receive_offset_int = current_received * NINTS; - const auto receive_offset_real = current_received * NREALS; - const auto receive_offset_prtldx = current_received * NFLOATS; - const auto receive_offset_long = current_received * NLONGS; - // Comms - // Make host arrays for send and recv buffers - Kokkos::deep_copy(send_buffer_int_h, send_buffer_int); - Kokkos::deep_copy(send_buffer_real_h, send_buffer_real); - Kokkos::deep_copy(send_buffer_prtldx_h, send_buffer_prtldx); - Kokkos::deep_copy(send_buffer_long_h, send_buffer_long); - - if ((send_rank >= 0) and (recv_rank >= 0) and (send_count > 0) and - (recv_count > 0)) { - // Debug: Print the rank and type of mpi operation performed - { - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - //printf("MPI rank: %d, Performing sendrecv operation, direction %d \n", rank, direction); - } - MPI_Sendrecv(send_buffer_int.data(), - send_count * NINTS, - mpi::get_type(), - send_rank, - 0, - recv_buffer_int.data() + receive_offset_int, - recv_count*NINTS, - mpi::get_type(), - recv_rank, - 0, - MPI_COMM_WORLD, - MPI_STATUS_IGNORE); - MPI_Sendrecv(send_buffer_real.data(), - send_count * NREALS, - mpi::get_type(), - send_rank, - 0, - recv_buffer_real.data() + receive_offset_real, - recv_count*NREALS, - mpi::get_type(), - recv_rank, - 0, - MPI_COMM_WORLD, - MPI_STATUS_IGNORE); - MPI_Sendrecv(send_buffer_prtldx.data(), - send_count * NFLOATS, - mpi::get_type(), - send_rank, - 0, - recv_buffer_prtldx.data() + receive_offset_prtldx, - recv_count*NFLOATS, - mpi::get_type(), - recv_rank, - 0, - MPI_COMM_WORLD, - MPI_STATUS_IGNORE); - MPI_Sendrecv(send_buffer_long.data(), - send_count * NLONGS, - mpi::get_type(), - send_rank, - 0, - recv_buffer_long.data() + receive_offset_long, - recv_count*NLONGS, - mpi::get_type(), - recv_rank, - 0, - MPI_COMM_WORLD, - MPI_STATUS_IGNORE); - } else if ((send_rank >= 0) and (send_count > 0)) { - // Debug: Print the rank and type of mpi operation performed - { - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - //printf("MPI rank: %d, Performing send operation, direction %d \n", rank, direction); - } - MPI_Send(send_buffer_int.data(), - send_count * NINTS, - mpi::get_type(), - send_rank, - 0, - MPI_COMM_WORLD); - MPI_Send(send_buffer_real.data(), - send_count * NREALS, - mpi::get_type(), - send_rank, - 0, - MPI_COMM_WORLD); - MPI_Send(send_buffer_prtldx.data(), - send_count * NFLOATS, - mpi::get_type(), - send_rank, - 0, - MPI_COMM_WORLD); - MPI_Send(send_buffer_long.data(), - send_count * NLONGS, - mpi::get_type(), - send_rank, - 0, - MPI_COMM_WORLD); - } else if ((recv_rank >= 0) and (recv_count > 0)) { - // Debug: Print the rank and type of mpi operation performed - { - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - //printf("MPI rank: %d, Performing recv operation, direction %d \n", rank, direction); - } - MPI_Recv(recv_buffer_int.data() + receive_offset_int, - recv_count * NINTS, - mpi::get_type(), - recv_rank, - 0, - MPI_COMM_WORLD, - MPI_STATUS_IGNORE); - MPI_Recv(recv_buffer_real.data() + receive_offset_real, - recv_count * NREALS, - mpi::get_type(), - recv_rank, - 0, - MPI_COMM_WORLD, - MPI_STATUS_IGNORE); - MPI_Recv(recv_buffer_prtldx.data() + receive_offset_prtldx, - recv_count * NFLOATS, - mpi::get_type(), - recv_rank, - 0, - MPI_COMM_WORLD, - MPI_STATUS_IGNORE); - MPI_Recv(recv_buffer_long.data() + receive_offset_long, - recv_count * NLONGS, - mpi::get_type(), - recv_rank, - 0, - MPI_COMM_WORLD, - MPI_STATUS_IGNORE); - } - current_received += recv_count; - iteration++; - - // Debug test: Print recv buffer before and after - /* - { - int total_ranks; - MPI_Comm_size(MPI_COMM_WORLD, &total_ranks); - for (int allranks=0; allranks send_buff_int { "send_buff_int", npart_send_in * NINTS }; + Kokkos::View send_buff_real { "send_buff_real", + npart_send_in * NREALS }; + Kokkos::View send_buff_prtldx { "send_buff_prtldx", + npart_send_in * NPRTLDX }; + Kokkos::parallel_for( + "PopulateSendBuffer", + npart_send_in, + Lambda(index_t p) { + const auto idx = outgoing_indices( + (tag_send > 2 ? tag_offsets(tag_send - 3) : 0) + npart_dead + p); + if constexpr (D == Dim::_1D or D == Dim::_2D or D == Dim::_3D) { + send_buff_int(NINTS * p + 0) = this_i1(idx); + send_buff_int(NINTS * p + 1) = this_i1_prev(idx); + send_buff_prtldx(NPRTLDX * p + 0) = this_dx1(idx); + send_buff_prtldx(NPRTLDX * p + 1) = this_dx1_prev(idx); } - auto allocation_vector_h = Kokkos::create_mirror_view(allocation_vector); - Kokkos::deep_copy(allocation_vector_h, allocation_vector); - - for (int i=0; i= 0) and (recv_rank >= 0) and (npart_send_in > 0) and + (npart_recv_in > 0)) { + raise::ErrorIf(recv_offset_int + npart_recv_in * NINTS > + recv_buff_int.extent(0), + "incorrect # of recv particles", + HERE); + MPI_Sendrecv(send_buff_int.data(), + npart_send_in * NINTS, + mpi::get_type(), + send_rank, + 0, + recv_buff_int.data() + recv_offset_int, + npart_recv_in * NINTS, + mpi::get_type(), + recv_rank, + 0, + MPI_COMM_WORLD, + MPI_STATUS_IGNORE); + MPI_Sendrecv(send_buff_real.data(), + npart_send_in * NREALS, + mpi::get_type(), + send_rank, + 0, + recv_buff_real.data() + recv_offset_real, + npart_recv_in * NREALS, + mpi::get_type(), + recv_rank, + 0, + MPI_COMM_WORLD, + MPI_STATUS_IGNORE); + MPI_Sendrecv(send_buff_prtldx.data(), + npart_send_in * NPRTLDX, + mpi::get_type(), + send_rank, + 0, + recv_buff_prtldx.data() + recv_offset_prtldx, + npart_recv_in * NPRTLDX, + mpi::get_type(), + recv_rank, + 0, + MPI_COMM_WORLD, + MPI_STATUS_IGNORE); + } else if ((send_rank >= 0) and (npart_send_in > 0)) { + MPI_Send(send_buff_int.data(), + npart_send_in * NINTS, + mpi::get_type(), + send_rank, + 0, + MPI_COMM_WORLD); + MPI_Send(send_buff_real.data(), + npart_send_in * NREALS, + mpi::get_type(), + send_rank, + 0, + MPI_COMM_WORLD); + MPI_Send(send_buff_prtldx.data(), + npart_send_in * NPRTLDX, + mpi::get_type(), + send_rank, + 0, + MPI_COMM_WORLD); + } else if ((recv_rank >= 0) and (npart_recv_in > 0)) { + raise::ErrorIf(recv_offset_int + npart_recv_in * NINTS > + recv_buff_int.extent(0), + "incorrect # of recv particles", + HERE); + MPI_Recv(recv_buff_int.data() + recv_offset_int, + npart_recv_in * NINTS, + mpi::get_type(), + recv_rank, + 0, + MPI_COMM_WORLD, + MPI_STATUS_IGNORE); + MPI_Recv(recv_buff_real.data() + recv_offset_real, + npart_recv_in * NREALS, + mpi::get_type(), + recv_rank, + 0, + MPI_COMM_WORLD, + MPI_STATUS_IGNORE); + MPI_Recv(recv_buff_prtldx.data() + recv_offset_prtldx, + npart_recv_in * NPRTLDX, + mpi::get_type(), + recv_rank, + 0, + MPI_COMM_WORLD, + MPI_STATUS_IGNORE); } - } - */ - - } // end over direction loop - /*Kokkos::deep_copy(recv_buffer_int, recv_buffer_int_h); - Kokkos::deep_copy(recv_buffer_real, recv_buffer_real_h); - Kokkos::deep_copy(recv_buffer_prtldx, recv_buffer_prtldx_h);*/ - if constexpr (D == Dim::_1D) - { - Kokkos::parallel_for( - "PopulateFromRecvBuffer", - total_recv, - Lambda(const std::size_t p){ - auto idx = allocation_vector(p); - this_tag(idx) = ParticleTag::alive; - this_i1(idx) = recv_buffer_int(NINTS * p + 0); - this_i1_prev(idx) = recv_buffer_int(NINTS * p + 1); - this_ux1(idx) = recv_buffer_real(NREALS * p + 0); - this_ux2(idx) = recv_buffer_real(NREALS * p + 1); - this_ux3(idx) = recv_buffer_real(NREALS * p + 2); - this_weight(idx) = recv_buffer_real(NREALS * p + 3); - this_dx1(idx) = recv_buffer_prtldx(NFLOATS * p + 0); - this_dx1_prev(idx) = recv_buffer_prtldx(NFLOATS * p + 1); - this_particleID(idx) = recv_buffer_long(NLONGS * p + 0); - }); - } + current_received += npart_recv_in; + iteration++; - if constexpr (D == Dim::_2D && C == Coord::Cart) - { - Kokkos::parallel_for( - "PopulateFromRecvBuffer", - total_recv, - Lambda(const std::size_t p){ - auto idx = allocation_vector(p); - this_tag(idx) = ParticleTag::alive; - this_i1(idx) = recv_buffer_int(NINTS * p + 0); - this_i1_prev(idx) = recv_buffer_int(NINTS * p + 1); - this_i2(idx) = recv_buffer_int(NINTS * p + 2); - this_i2_prev(idx) = recv_buffer_int(NINTS * p + 3); - this_ux1(idx) = recv_buffer_real(NREALS * p + 0); - this_ux2(idx) = recv_buffer_real(NREALS * p + 1); - this_ux3(idx) = recv_buffer_real(NREALS * p + 2); - this_weight(idx) = recv_buffer_real(NREALS * p + 3); - this_dx1(idx) = recv_buffer_prtldx(NFLOATS * p + 0); - this_dx1_prev(idx) = recv_buffer_prtldx(NFLOATS * p + 1); - this_dx2(idx) = recv_buffer_prtldx(NFLOATS * p + 2); - this_dx2_prev(idx) = recv_buffer_prtldx(NFLOATS * p + 3); - this_particleID(idx) = recv_buffer_long(NLONGS * p + 0); - }); - } + } // end direction loop - if constexpr (D == Dim::_2D && C != Coord::Cart) - { - Kokkos::parallel_for( - "PopulateFromRecvBuffer", - total_recv, - Lambda(const std::size_t p){ - auto idx = allocation_vector(p); - this_tag(idx) = ParticleTag::alive; - this_i1(idx) = recv_buffer_int(NINTS * p + 0); - this_i1_prev(idx) = recv_buffer_int(NINTS * p + 1); - this_i2(idx) = recv_buffer_int(NINTS * p + 2); - this_i2_prev(idx) = recv_buffer_int(NINTS * p + 3); - this_ux1(idx) = recv_buffer_real(NREALS * p + 0); - this_ux2(idx) = recv_buffer_real(NREALS * p + 1); - this_ux3(idx) = recv_buffer_real(NREALS * p + 2); - this_weight(idx) = recv_buffer_real(NREALS * p + 3); - this_phi(idx) = recv_buffer_real(NREALS * p + 4); - this_dx1(idx) = recv_buffer_prtldx(NFLOATS * p + 0); - this_dx1_prev(idx) = recv_buffer_prtldx(NFLOATS * p + 1); - this_dx2(idx) = recv_buffer_prtldx(NFLOATS * p + 2); - this_dx2_prev(idx) = recv_buffer_prtldx(NFLOATS * p + 3); - this_particleID(idx) = recv_buffer_long(NLONGS * p + 0); - }); - } + const auto npart = species.npart(); + const auto npart_holes = outgoing_indices.extent(0); - if constexpr (D == Dim::_3D) - { - Kokkos::parallel_for( + Kokkos::parallel_for( "PopulateFromRecvBuffer", - total_recv, - Lambda(const std::size_t p){ - auto idx = allocation_vector(p); - this_tag(idx) = ParticleTag::alive; - this_i1(idx) = recv_buffer_int(NINTS * p + 0); - this_i1_prev(idx) = recv_buffer_int(NINTS * p + 1); - this_i2(idx) = recv_buffer_int(NINTS * p + 2); - this_i2_prev(idx) = recv_buffer_int(NINTS * p + 3); - this_i3(idx) = recv_buffer_int(NINTS * p + 4); - this_i3_prev(idx) = recv_buffer_int(NINTS * p + 5); - this_ux1(idx) = recv_buffer_real(NREALS * p + 0); - this_ux2(idx) = recv_buffer_real(NREALS * p + 1); - this_ux3(idx) = recv_buffer_real(NREALS * p + 2); - this_weight(idx) = recv_buffer_real(NREALS * p + 3); - this_dx1(idx) = recv_buffer_prtldx(NFLOATS * p + 0); - this_dx1_prev(idx) = recv_buffer_prtldx(NFLOATS * p + 1); - this_dx2(idx) = recv_buffer_prtldx(NFLOATS * p + 2); - this_dx2_prev(idx) = recv_buffer_prtldx(NFLOATS * p + 3); - this_dx3(idx) = recv_buffer_prtldx(NFLOATS * p + 4); - this_dx3_prev(idx) = recv_buffer_prtldx(NFLOATS * p + 5); - this_particleID(idx) = recv_buffer_long(NLONGS * p + 0); - }); - } - species.set_npart(species.npart() + std::max(permute_vector.extent(0), - allocation_vector.extent(0)) - permute_vector.extent(0)); - /* - { - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - // Print the total number of particles after each pass - int species_npart = species.npart(); - int global_species_npart = 0; - // Reduce all local sums into global_sum on rank 0 - MPI_Reduce(&species_npart, &global_species_npart, 1, MPI_INT, MPI_SUM, 0, MPI_COMM_WORLD); - int total_ranks; - MPI_Comm_size(MPI_COMM_WORLD, &total_ranks); - for (int allranks=0; allranks= npart_holes ? npart + p - npart_holes + : outgoing_indices(p)); + if constexpr (D == Dim::_1D or D == Dim::_2D or D == Dim::_3D) { + this_i1(idx) = recv_buff_int(NINTS * p + 0); + this_i1_prev(idx) = recv_buff_int(NINTS * p + 1); + this_dx1(idx) = recv_buff_prtldx(NPRTLDX * p + 0); + this_dx1_prev(idx) = recv_buff_prtldx(NPRTLDX * p + 1); } - } + if constexpr (D == Dim::_2D or D == Dim::_3D) { + this_i2(idx) = recv_buff_int(NINTS * p + 2); + this_i2_prev(idx) = recv_buff_int(NINTS * p + 3); + this_dx2(idx) = recv_buff_prtldx(NPRTLDX * p + 2); + this_dx2_prev(idx) = recv_buff_prtldx(NPRTLDX * p + 3); + } + if constexpr (D == Dim::_3D) { + this_i3(idx) = recv_buff_int(NINTS * p + 4); + this_i3_prev(idx) = recv_buff_int(NINTS * p + 5); + this_dx3(idx) = recv_buff_prtldx(NPRTLDX * p + 4); + this_dx3_prev(idx) = recv_buff_prtldx(NPRTLDX * p + 5); + } + this_ux1(idx) = recv_buff_real(NREALS * p + 0); + this_ux2(idx) = recv_buff_real(NREALS * p + 1); + this_ux3(idx) = recv_buff_real(NREALS * p + 2); + this_weight(idx) = recv_buff_real(NREALS * p + 3); + if constexpr (D == Dim::_2D and C != Coord::Cart) { + this_phi(idx) = recv_buff_real(NREALS * p + 4); + } + this_tag(idx) = ParticleTag::alive; + }); + + if (npart_recv > npart_holes) { + species.set_npart(npart + npart_recv - npart_holes); } - */ - return; -} + } } // namespace comm diff --git a/src/framework/domain/communications.cpp b/src/framework/domain/communications.cpp index 390c27fa8..6175cc4bb 100644 --- a/src/framework/domain/communications.cpp +++ b/src/framework/domain/communications.cpp @@ -24,6 +24,8 @@ #include "framework/domain/comm_nompi.hpp" #endif +#include + #include #include @@ -33,10 +35,10 @@ namespace ntt { using comm_params_t = std::pair>; template - auto GetSendRecvRanks(Metadomain* metadomain, - Domain& domain, - dir::direction_t direction) - -> std::pair { + auto GetSendRecvRanks( + Metadomain* metadomain, + Domain& domain, + dir::direction_t direction) -> std::pair { Domain* send_to_nghbr_ptr = nullptr; Domain* recv_from_nghbr_ptr = nullptr; // set pointers to the correct send/recv domains @@ -86,8 +88,8 @@ namespace ntt { } else { // no communication necessary return { - {0, -1}, - {0, -1} + { 0, -1 }, + { 0, -1 } }; } #if defined(MPI_ENABLED) @@ -110,17 +112,17 @@ namespace ntt { (void)send_rank; (void)recv_rank; return { - {send_ind, send_rank}, - {recv_ind, recv_rank} + { send_ind, send_rank }, + { recv_ind, recv_rank } }; } template - auto GetSendRecvParams(Metadomain* metadomain, - Domain& domain, - dir::direction_t direction, - bool synchronize) - -> std::pair { + auto GetSendRecvParams( + Metadomain* metadomain, + Domain& domain, + dir::direction_t direction, + bool synchronize) -> std::pair { const auto [send_indrank, recv_indrank] = GetSendRecvRanks(metadomain, domain, direction); const auto [send_ind, send_rank] = send_indrank; @@ -129,8 +131,8 @@ namespace ntt { const auto is_receiving = (recv_rank >= 0); if (not(is_sending or is_receiving)) { return { - {{ 0, -1 }, {}}, - {{ 0, -1 }, {}} + { { 0, -1 }, {} }, + { { 0, -1 }, {} } }; } auto send_slice = std::vector {}; @@ -196,8 +198,8 @@ namespace ntt { } return { - {{ send_ind, send_rank }, send_slice}, - {{ recv_ind, recv_rank }, recv_slice}, + { { send_ind, send_rank }, send_slice }, + { { recv_ind, recv_rank }, recv_slice }, }; } @@ -492,638 +494,177 @@ namespace ntt { } template - void Metadomain::CommunicateParticles(Domain& domain, - timer::Timers* timers) { - raise::ErrorIf(timers == nullptr, - "Timers not passed when Comm::Prtl called", - HERE); - logger::Checkpoint("Communicating particles\n", HERE); - for (auto& species : domain.species) { - // at this point particles should already by tagged in the pusher - timers->start("Sorting"); - const auto npart_per_tag = species.SortByTags(); - timers->stop("Sorting"); + void Metadomain::CommunicateParticles(Domain& domain) { #if defined(MPI_ENABLED) - timers->start("Communications"); - // only necessary when MPI is enabled - /** - * index_last - * | - * alive new dead tag1 tag2 v dead - * [ 11111111 000000000 222222222 3333333 .... nnnnnnn 00000000 ... ] - * ^ ^ - * | | - * tag_offset[tag1] -----+ +----- tag_offset[tag1] + npart_per_tag[tag1] - * "send_pmin" "send_pmax" (after last element) - */ - auto tag_offset { npart_per_tag }; - for (std::size_t i { 1 }; i < tag_offset.size(); ++i) { - tag_offset[i] += tag_offset[i - 1]; - } - for (std::size_t i { 0 }; i < tag_offset.size(); ++i) { - tag_offset[i] -= npart_per_tag[i]; - } - auto index_last = tag_offset[tag_offset.size() - 1] + - npart_per_tag[npart_per_tag.size() - 1]; - for (auto& direction : dir::Directions::all) { - const auto [send_params, - recv_params] = GetSendRecvParams(this, domain, direction, true); - const auto [send_indrank, send_slice] = send_params; - const auto [recv_indrank, recv_slice] = recv_params; - const auto [send_ind, send_rank] = send_indrank; - const auto [recv_ind, recv_rank] = recv_indrank; - if (send_rank < 0 and recv_rank < 0) { - continue; - } - const auto send_dir_tag = mpi::PrtlSendTag::dir2tag(direction); - const auto nsend = npart_per_tag[send_dir_tag]; - const auto send_pmin = tag_offset[send_dir_tag]; - const auto send_pmax = tag_offset[send_dir_tag] + nsend; - const auto recv_count = comm::CommunicateParticles( - species, - send_rank, - recv_rank, - { send_pmin, send_pmax }, - index_last); - if (recv_count > 0) { - if constexpr (D == Dim::_1D) { - int shift_in_x1 { 0 }; - if ((-direction)[0] == -1) { - shift_in_x1 = -subdomain(recv_ind).mesh.n_active(in::x1); - } else if ((-direction)[0] == 1) { - shift_in_x1 = domain.mesh.n_active(in::x1); - } - auto& this_tag = species.tag; - auto& this_i1 = species.i1; - auto& this_i1_prev = species.i1_prev; - Kokkos::parallel_for( - "CommunicateParticles", - recv_count, - Lambda(index_t p) { - this_tag(index_last + p) = ParticleTag::alive; - this_i1(index_last + p) += shift_in_x1; - this_i1_prev(index_last + p) += shift_in_x1; - }); - } else if constexpr (D == Dim::_2D) { - int shift_in_x1 { 0 }, shift_in_x2 { 0 }; - if ((-direction)[0] == -1) { - shift_in_x1 = -subdomain(recv_ind).mesh.n_active(in::x1); - } else if ((-direction)[0] == 1) { - shift_in_x1 = domain.mesh.n_active()[0]; - } - if ((-direction)[1] == -1) { - shift_in_x2 = -subdomain(recv_ind).mesh.n_active(in::x2); - } else if ((-direction)[1] == 1) { - shift_in_x2 = domain.mesh.n_active(in::x2); - } - auto& this_tag = species.tag; - auto& this_i1 = species.i1; - auto& this_i2 = species.i2; - auto& this_i1_prev = species.i1_prev; - auto& this_i2_prev = species.i2_prev; - Kokkos::parallel_for( - "CommunicateParticles", - recv_count, - Lambda(index_t p) { - this_tag(index_last + p) = ParticleTag::alive; - this_i1(index_last + p) += shift_in_x1; - this_i2(index_last + p) += shift_in_x2; - this_i1_prev(index_last + p) += shift_in_x1; - this_i2_prev(index_last + p) += shift_in_x2; - }); - } else if constexpr (D == Dim::_3D) { - int shift_in_x1 { 0 }, shift_in_x2 { 0 }, shift_in_x3 { 0 }; - if ((-direction)[0] == -1) { - shift_in_x1 = -subdomain(recv_ind).mesh.n_active(in::x1); - } else if ((-direction)[0] == 1) { - shift_in_x1 = domain.mesh.n_active(in::x1); - } - if ((-direction)[1] == -1) { - shift_in_x2 = -subdomain(recv_ind).mesh.n_active(in::x2); - } else if ((-direction)[1] == 1) { - shift_in_x2 = domain.mesh.n_active(in::x2); - } - if ((-direction)[2] == -1) { - shift_in_x3 = -subdomain(recv_ind).mesh.n_active(in::x3); - } else if ((-direction)[2] == 1) { - shift_in_x3 = domain.mesh.n_active(in::x3); - } - auto& this_tag = species.tag; - auto& this_i1 = species.i1; - auto& this_i2 = species.i2; - auto& this_i3 = species.i3; - auto& this_i1_prev = species.i1_prev; - auto& this_i2_prev = species.i2_prev; - auto& this_i3_prev = species.i3_prev; - Kokkos::parallel_for( - "CommunicateParticles", - recv_count, - Lambda(index_t p) { - this_tag(index_last + p) = ParticleTag::alive; - this_i1(index_last + p) += shift_in_x1; - this_i2(index_last + p) += shift_in_x2; - this_i3(index_last + p) += shift_in_x3; - this_i1_prev(index_last + p) += shift_in_x1; - this_i2_prev(index_last + p) += shift_in_x2; - this_i3_prev(index_last + p) += shift_in_x3; - }); - } - index_last += recv_count; - species.set_npart(index_last); - } - Kokkos::deep_copy( - Kokkos::subview(species.tag, std::make_pair(send_pmin, send_pmax)), - ParticleTag::dead); - } - timers->stop("Communications"); - // !TODO: maybe there is a way to not sort twice - timers->start("Sorting"); - species.set_unsorted(); - species.SortByTags(); - timers->stop("Sorting"); -#endif - } - } - - /* - New function to communicate particles using a buffer - */ - template - void Metadomain::CommunicateParticlesBuffer(Domain& domain, - timer::Timers* timers) { - raise::ErrorIf(timers == nullptr, - "Timers not passed when Comm::Prtl called", - HERE); logger::Checkpoint("Communicating particles\n", HERE); for (auto& species : domain.species) { - /* - Brief on arrays - npart_per_tag_arr (vector): | dead count| alive count | tag=1 count | tag=2 count | ... - <--------------------------size = ntags()--------------------------> - tag_offset (Kokkos::View): | 0 | dead count | dead + alive count | dead + alive + tag=1 count | ... - <--------------------------size = ntags()--------------------------> - npart_per_tag_arr_recv (vector): | 0 | 0 | nrecv1 | nrecv2 | ... - <--------------------------size = ntags()--------------------------> - */ - auto [npart_per_tag_arr, - tag_offset] = species.npart_per_tag(); - auto npart = static_cast(species.npart()); - auto total_alive = static_cast( - npart_per_tag_arr[ParticleTag::alive]); - auto total_dead = static_cast( - npart_per_tag_arr[ParticleTag::dead]); - auto total_holes = static_cast(npart - total_alive); - auto total_recv = static_cast(0); - + const auto ntags = species.ntags(); + + // at this point particles should already be tagged in the pusher + auto [npptag_vec, tag_offsets] = species.NpartsPerTagAndOffsets(); + const auto npart_dead = npptag_vec[ParticleTag::dead]; + const auto npart_alive = npptag_vec[ParticleTag::alive]; + + const auto npart = species.npart(); + const auto npart_holes = npart - npart_alive; + + // # of particles to receive per each tag (direction) + std::vector npptag_recv_vec(ntags - 2, 0); + // coordinate shifts per each direction + array_t shifts_in_x1("shifts_in_x1", ntags - 2); + array_t shifts_in_x2("shifts_in_x2", ntags - 2); + array_t shifts_in_x3("shifts_in_x3", ntags - 2); + // all directions requiring communication + dir::dirs_t dirs_to_comm; + + // ranks & indices of meshblock to send/recv from std::vector send_ranks, send_inds; std::vector recv_ranks, recv_inds; - // at this point particles should already by tagged in the pusher -#if defined(MPI_ENABLED) - std::vector npart_per_tag_arr_recv(species.ntags(), 0); - Kokkos::View shifts_in_x1("shifts_in_x1", species.ntags()); - Kokkos::View shifts_in_x2("shifts_in_x2", species.ntags()); - Kokkos::View shifts_in_x3("shifts_in_x3", species.ntags()); - auto shifts_in_x1_h = Kokkos::create_mirror_view(shifts_in_x1); - auto shifts_in_x2_h = Kokkos::create_mirror_view(shifts_in_x2); - auto shifts_in_x3_h = Kokkos::create_mirror_view(shifts_in_x3); - dir::dirs_t legal_directions; - // Get receive counts + displacements - for (auto& direction : dir::Directions::all) { + // total # of reaceived particles from all directions + std::size_t npart_recv = 0u; + + for (const auto& direction : dir::Directions::all) { + // tags corresponding to the direction (both send & recv) const auto tag_recv = mpi::PrtlSendTag::dir2tag(-direction); const auto tag_send = mpi::PrtlSendTag::dir2tag(direction); + + // get indices & ranks of send/recv meshblocks const auto [send_params, recv_params] = GetSendRecvParams(this, domain, direction, true); const auto [send_indrank, send_slice] = send_params; const auto [recv_indrank, recv_slice] = recv_params; const auto [send_ind, send_rank] = send_indrank; const auto [recv_ind, recv_rank] = recv_indrank; - if (send_rank < 0 and recv_rank < 0) { + + // skip if no communication is necessary + const auto is_sending = (send_rank >= 0); + const auto is_receiving = (recv_rank >= 0); + if (not is_sending and not is_receiving) { continue; } - const auto nsend = npart_per_tag_arr[tag_send]; - std::size_t nrecv = 0; - - legal_directions.push_back(direction); + dirs_to_comm.push_back(direction); send_ranks.push_back(send_rank); recv_ranks.push_back(recv_rank); send_inds.push_back(send_ind); recv_inds.push_back(recv_ind); - comm::ParticleSendRecvCount(send_rank, recv_rank, nsend, nrecv); - total_recv += nrecv; - npart_per_tag_arr_recv[tag_recv] = nrecv; - // Perform displacements before sending - if constexpr (D == Dim::_1D || D == Dim::_2D || D == Dim::_3D) { - if ((-direction)[0] == -1) { - shifts_in_x1_h(tag_recv) = subdomain(recv_ind).mesh.n_active(in::x1); - } else if ((-direction)[0] == 1) { - shifts_in_x1_h(tag_recv) = -domain.mesh.n_active(in::x1); - } - } - if constexpr (D == Dim::_2D || D == Dim::_3D) { - if ((-direction)[1] == -1) { - shifts_in_x2_h(tag_recv) = subdomain(recv_ind).mesh.n_active(in::x2); - } else if ((-direction)[1] == 1) { - shifts_in_x2_h(tag_recv) = -domain.mesh.n_active(in::x2); - } - } - if constexpr (D == Dim::_3D) { - if ((-direction)[2] == -1) { - shifts_in_x3_h(tag_recv) = subdomain(recv_ind).mesh.n_active(in::x3); - } else if ((-direction)[2] == 1) { - shifts_in_x3_h(tag_recv) = -domain.mesh.n_active(in::x3); - } - } - } // end directions loop - Kokkos::deep_copy(shifts_in_x1, shifts_in_x1_h); - Kokkos::deep_copy(shifts_in_x2, shifts_in_x2_h); - Kokkos::deep_copy(shifts_in_x3, shifts_in_x3_h); - - raise::FatalIf((npart + total_recv) >= species.maxnpart(), - "Too many particles to receive (cannot fit into maxptl)", - HERE); - auto& this_tag = species.tag; - auto& this_i1 = species.i1; - auto& this_i1_prev = species.i1_prev; - auto& this_i2 = species.i2; - auto& this_i2_prev = species.i2_prev; - auto& this_i3 = species.i3; - auto& this_i3_prev = species.i3_prev; + // record the # of particles to-be-sent + const auto nsend = npptag_vec[tag_send]; - /* - Brief on permute vector: It contains the sorted indices of tag != alive particles - E.g., consider the following tag array - species.tag = [ 0, 0, 1, 0, 2, 3,...] - Then, permute vector will look something like - permute_vector = [0, 1, 3, ..., 4, ..., ... 5, ... ] - |<--------- >| |<----->| |<----->| .... - tag=dead ct tag=2 ct tag=3 ct - */ - Kokkos::View permute_vector("permute_vector", total_holes); - Kokkos::View current_offset("current_offset", species.ntags()); - auto &this_tag_offset = tag_offset; + // request the # of particles to-be-received ... + // ... and send the # of particles to-be-sent + std::size_t nrecv = 0; + comm::ParticleSendRecvCount(send_rank, recv_rank, nsend, nrecv); + npart_recv += nrecv; + npptag_recv_vec[tag_recv - 2] = nrecv; - auto n_alive = npart_per_tag_arr[ParticleTag::alive]; + raise::ErrorIf((npart + npart_recv) >= species.maxnpart(), + "Too many particles to receive (cannot fit into maxptl)", + HERE); - if constexpr (D == Dim::_1D){ - Kokkos::parallel_for( - "PermuteVector and Displace", - species.npart(), - Lambda(index_t p) { - const auto current_tag = this_tag(p); - if (current_tag != ParticleTag::alive){ - // dead tags only - if (current_tag == ParticleTag::dead) { - const auto idx_permute_vec = Kokkos::atomic_fetch_add( - ¤t_offset(current_tag), - 1); - permute_vector(idx_permute_vec) = p; - } - // tag = 1->N (excluding dead and alive) - else{ - const auto idx_permute_vec = this_tag_offset(current_tag) - - n_alive + - Kokkos::atomic_fetch_add( - ¤t_offset(current_tag), - 1); - permute_vector(idx_permute_vec) = p; - this_i1(p) += shifts_in_x1(current_tag); - this_i1_prev(p) += shifts_in_x1(current_tag); + // if sending, record displacements to apply before + // ... tag_send - 2: because we only shift tags > 2 (i.e. no dead/alive) + if (is_sending) { + if constexpr (D == Dim::_1D || D == Dim::_2D || D == Dim::_3D) { + auto shifts_in_x1_h = Kokkos::create_mirror_view(shifts_in_x1); + if (direction[0] == -1) { + // sending backwards in x1 (add sx1 of target meshblock) + shifts_in_x1_h(tag_send - 2) = subdomain(send_ind).mesh.n_active( + in::x1); + } else if (direction[0] == 1) { + // sending forward in x1 (subtract sx1 of source meshblock) + shifts_in_x1_h(tag_send - 2) = -domain.mesh.n_active(in::x1); } + Kokkos::deep_copy(shifts_in_x1, shifts_in_x1_h); } - }); - } - - if constexpr (D == Dim::_2D){ - Kokkos::parallel_for( - "PermuteVector and Displace", - species.npart(), - Lambda(index_t p) { - const auto current_tag = this_tag(p); - if (current_tag != ParticleTag::alive){ - // dead tags only - if (current_tag == ParticleTag::dead) { - const auto idx_permute_vec = Kokkos::atomic_fetch_add( - ¤t_offset(current_tag), - 1); - permute_vector(idx_permute_vec) = p; + if constexpr (D == Dim::_2D || D == Dim::_3D) { + auto shifts_in_x2_h = Kokkos::create_mirror_view(shifts_in_x2); + if (direction[1] == -1) { + shifts_in_x2_h(tag_send - 2) = subdomain(send_ind).mesh.n_active( + in::x2); + } else if (direction[1] == 1) { + shifts_in_x2_h(tag_send - 2) = -domain.mesh.n_active(in::x2); } - // tag = 1->N (excluding dead and alive) - else{ - const auto idx_permute_vec = this_tag_offset(current_tag) - - n_alive + - Kokkos::atomic_fetch_add( - ¤t_offset(current_tag), - 1); - permute_vector(idx_permute_vec) = p; - this_i1(p) += shifts_in_x1(current_tag); - this_i1_prev(p) += shifts_in_x1(current_tag); - this_i2(p) += shifts_in_x2(current_tag); - this_i2_prev(p) += shifts_in_x2(current_tag); + Kokkos::deep_copy(shifts_in_x2, shifts_in_x2_h); + } + if constexpr (D == Dim::_3D) { + auto shifts_in_x3_h = Kokkos::create_mirror_view(shifts_in_x3); + if (direction[2] == -1) { + shifts_in_x3_h(tag_send - 2) = subdomain(send_ind).mesh.n_active( + in::x3); + } else if (direction[2] == 1) { + shifts_in_x3_h(tag_send - 2) = -domain.mesh.n_active(in::x3); } + Kokkos::deep_copy(shifts_in_x3, shifts_in_x3_h); } - }); - } + } + } // end directions loop - if constexpr (D == Dim::_3D){ + auto& this_tag = species.tag; + auto& this_i1 = species.i1; + auto& this_i1_prev = species.i1_prev; + auto& this_i2 = species.i2; + auto& this_i2_prev = species.i2_prev; + auto& this_i3 = species.i3; + auto& this_i3_prev = species.i3_prev; + + array_t outgoing_indices("outgoing_indices", + npart - npart_alive); + + array_t current_offset("current_offset", ntags); Kokkos::parallel_for( - "PermuteVector and Displace", - species.npart(), + "OutgoingIndicesAndDisplace", + species.rangeActiveParticles(), Lambda(index_t p) { - const auto current_tag = this_tag(p); - if (current_tag != ParticleTag::alive){ - // dead tags only - if (current_tag == ParticleTag::dead) { - const auto idx_permute_vec = Kokkos::atomic_fetch_add( - ¤t_offset(current_tag), - 1); - permute_vector(idx_permute_vec) = p; + if (this_tag(p) != ParticleTag::alive) { + // dead or to-be-sent + const auto idx_for_tag = + Kokkos::atomic_fetch_add(¤t_offset(this_tag(p)), 1) + + (this_tag(p) != ParticleTag::dead ? npart_dead : 0) + + (this_tag(p) > 2 ? tag_offsets(this_tag(p) - 3) : 0); + if (idx_for_tag >= npart - npart_alive) { + raise::KernelError(HERE, + "Outgoing indices idx exceeds the array size"); } - // tag = 1->N (excluding dead and alive) - else{ - const auto idx_permute_vec = this_tag_offset(current_tag) - - n_alive + - Kokkos::atomic_fetch_add( - ¤t_offset(current_tag), - 1); - permute_vector(idx_permute_vec) = p; - this_i1(p) += shifts_in_x1(current_tag); - this_i1_prev(p) += shifts_in_x1(current_tag); - this_i2(p) += shifts_in_x2(current_tag); - this_i2_prev(p) += shifts_in_x2(current_tag); - this_i3(p) += shifts_in_x3(current_tag); - this_i3_prev(p) += shifts_in_x3(current_tag); + outgoing_indices(idx_for_tag) = p; + // apply offsets + if (this_tag(p) != ParticleTag::dead) { + if constexpr (D == Dim::_1D or D == Dim::_2D or D == Dim::_3D) { + this_i1(p) += shifts_in_x1(this_tag(p) - 2); + this_i1_prev(p) += shifts_in_x1(this_tag(p) - 2); + } + if constexpr (D == Dim::_2D or D == Dim::_3D) { + this_i2(p) += shifts_in_x2(this_tag(p) - 2); + this_i2_prev(p) += shifts_in_x2(this_tag(p) - 2); + } + if constexpr (D == Dim::_3D) { + this_i3(p) += shifts_in_x3(this_tag(p) - 2); + this_i3_prev(p) += shifts_in_x3(this_tag(p) - 2); + } } } }); - } - - - - // Sanity check: npart_per_tag must be equal to the current offset except tag=alive - auto current_offset_h = Kokkos::create_mirror_view(current_offset); - Kokkos::deep_copy(current_offset_h, current_offset); - for (std::size_t i { 0 }; i < species.ntags(); ++i) { - if (i != ParticleTag::alive){ - raise::FatalIf(current_offset_h(i) != npart_per_tag_arr[i], - "Error in permute vector construction", - HERE); - } - else{ - raise::FatalIf(current_offset_h(i) != 0, - "Error in permute vector construction", - HERE); - } - } - - /* - Brief on allocation vector: It contains the indices of holes that are filled - by the particles received from other domains - case 1: total_recv > nholes - allocation_vector = | i1 | i2 | i3 | .... | npart | npart + 1 | ... - <-------total_holes------> <---total_recv - nholes--> - (same as permuute vector) (extra particles appended at end) - case 2: total_recv <= nholes - allocation_vector = | i1 | i2 | i3 | .... - <----total_recv-----> - (same as permuute vector) - */ - Kokkos::View allocation_vector("allocation_vector", total_recv); - if (total_recv > total_holes) - { - // Fill the first bit with the permute vector; these are the holes to be filled - Kokkos::parallel_for( - "AllocationVector", - total_holes, - Lambda(index_t p) { - allocation_vector(p) = permute_vector(p); - }); - - // Now allocate the rest to the end of the array - Kokkos::parallel_for( - "AllocationVector", - total_recv - total_holes, - Lambda(index_t p) { - allocation_vector(total_holes + p) = static_cast(npart + p); - }); - } - else - { Kokkos::parallel_for( - "AllocationVector", - total_recv, - Lambda(index_t p) { - allocation_vector(p) = permute_vector(p); - }); - } - - /* - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - if (rank == 1 && species.label() == "e+_b") - { - // Copy the tag array to host - auto tag_h = Kokkos::create_mirror_view(species.tag); - Kokkos::deep_copy(tag_h, species.tag); - std::cout << "Tag locs before send" << std::endl; - for (std::size_t i { 0 }; i < species.npart(); i++) { - if (tag_h(i) != ParticleTag::alive) - std::cout <<" Tag: " << tag_h(i) << " loc: "<< i << std::endl; - } - - // Print allocation vector after copying to host - auto allocation_vector_h = Kokkos::create_mirror_view(allocation_vector); - std::cout << "Total holes: " << total_holes << " Total recv: " << total_recv << std::endl; - Kokkos::deep_copy(allocation_vector_h, allocation_vector); - for (std::size_t i { 0 }; i < total_recv; ++i) { - std::cout << "Rank: " << rank << " Allocation vector: " << allocation_vector_h(i) << std::endl; - } - // Print the permute vector as well - auto permute_vector_h = Kokkos::create_mirror_view(permute_vector); - Kokkos::deep_copy(permute_vector_h, permute_vector); - for (std::size_t i { 0 }; i < total_holes; ++i) { - std::cout << "Rank: " << rank << " Permuted vector: " << permute_vector_h(i) << - " tag: " << tag_h(permute_vector_h(i)) << std::endl; - } - } - */ - - // Communicate the arrays - comm::CommunicateParticlesBuffer(species, permute_vector, allocation_vector, - this_tag_offset, npart_per_tag_arr, npart_per_tag_arr_recv, - send_ranks, recv_ranks, legal_directions); + comm::CommunicateParticles(species, + outgoing_indices, + tag_offsets, + npptag_vec, + npptag_recv_vec, + send_ranks, + recv_ranks, + dirs_to_comm); + species.set_unsorted(); + } // end species loop +#else + (void)domain; #endif - } } - /* - Function to copy the alive particle data the arrays to a buffer and then back - to the particle arrays -*/ - template - void MoveDeadToEnd(array_t& arr, - Kokkos::View indices_alive) { - auto n_alive = indices_alive.extent(0); - auto buffer = Kokkos::View("buffer", n_alive); - Kokkos::parallel_for( - "PopulateBufferAlive", - n_alive, - Lambda(const std::size_t p) { - buffer(p) = arr(indices_alive(p)); - }); - - Kokkos::parallel_for( - "CopyBufferToArr", - n_alive, - Lambda(const std::size_t p) { - arr(p) = buffer(p); - }); - return; - } - - /* - Function to remove dead particles from the domain - - Consider the following particle quantity array - <---xxx---x---xx---xx-----------xx----x--> (qty) - - = alive - x = dead - ntot = nalive + ndead - - (1) Copy all alive particle data to buffer - <---xxx---x---xx---xx-----------xx----x--> (qty) - | - | - v - <--------------------------> buffer - (nalive) - - (2) Copy from buffer to the beginning of the array - overwritting all particles - <--------------------------> buffer - (nalive) - | - | - v - <--------------------------xx----x--> (qty) - ^ - (nalive) - - (3) Set npart to nalive - */ template - void Metadomain::RemoveDeadParticles(Domain& domain, - timer::Timers* timers){ + void Metadomain::RemoveDeadParticles(Domain& domain) { for (auto& species : domain.species) { - auto [npart_per_tag_arr, - tag_offset] = species.npart_per_tag(); - const auto npart = static_cast(species.npart()); - const auto total_alive = static_cast( - npart_per_tag_arr[ParticleTag::alive]); - const auto total_dead = static_cast( - npart_per_tag_arr[ParticleTag::dead]); - - // Check that only alive and dead particles are present - for (std::size_t i { 0 }; i < species.ntags(); i++) { - if (i != ParticleTag::alive && i != ParticleTag::dead){ - raise::FatalIf(npart_per_tag_arr[i] != 0, - "Particle tags can only be dead or alive at this point", - HERE); - } - } - - // Get the indices of all alive particles - auto &this_i1 = species.i1; - auto &this_i2 = species.i2; - auto &this_i3 = species.i3; - auto &this_i1_prev = species.i1_prev; - auto &this_i2_prev = species.i2_prev; - auto &this_i3_prev = species.i3_prev; - auto &this_dx1 = species.dx1; - auto &this_dx2 = species.dx2; - auto &this_dx3 = species.dx3; - auto &this_dx1_prev = species.dx1_prev; - auto &this_dx2_prev = species.dx2_prev; - auto &this_dx3_prev = species.dx3_prev; - auto &this_ux1 = species.ux1; - auto &this_ux2 = species.ux2; - auto &this_ux3 = species.ux3; - auto &this_weight = species.weight; - auto &this_phi = species.phi; - auto &this_tag = species.tag; - // Find indices of tag = alive particles - Kokkos::View indices_alive("indices_alive", total_alive); - Kokkos::View alive_counter("counter_alive", 1); - Kokkos::deep_copy(alive_counter, 0); - Kokkos::parallel_for( - "Indices of Alive Particles", - species.npart(), - Lambda(index_t p) { - if (this_tag(p) == ParticleTag::alive){ - const auto idx = Kokkos::atomic_fetch_add(&alive_counter(0), 1); - indices_alive(idx) = p; - } - }); - // Sanity check: alive_counter must be equal to total_alive - auto alive_counter_h = Kokkos::create_mirror_view(alive_counter); - Kokkos::deep_copy(alive_counter_h, alive_counter); - raise::FatalIf(alive_counter_h(0) != total_alive, - "Error in finding alive particles", - HERE); - - MoveDeadToEnd(species.i1, indices_alive); - MoveDeadToEnd(species.dx1, indices_alive); - MoveDeadToEnd(species.dx1_prev, indices_alive); - MoveDeadToEnd(species.ux1, indices_alive); - MoveDeadToEnd(species.ux2, indices_alive); - MoveDeadToEnd(species.ux3, indices_alive); - MoveDeadToEnd(species.weight, indices_alive); - // Update i2, dx2, i2_prev, dx2_prev - if constexpr(D == Dim::_2D || D == Dim::_3D){ - MoveDeadToEnd(species.i2, indices_alive); - MoveDeadToEnd(species.i2_prev, indices_alive); - MoveDeadToEnd(species.dx2, indices_alive); - MoveDeadToEnd(species.dx2_prev, indices_alive); - if constexpr(D == Dim::_2D && M::CoordType != Coord::Cart){ - MoveDeadToEnd(species.phi, indices_alive); - } - } - // Update i3, dx3, i3_prev, dx3_prev - if constexpr(D == Dim::_3D){ - MoveDeadToEnd(species.i3, indices_alive); - MoveDeadToEnd(species.i3_prev, indices_alive); - MoveDeadToEnd(species.dx3, indices_alive); - MoveDeadToEnd(species.dx3_prev, indices_alive); - } - // tags (set first total_alive to alive and rest to dead) - Kokkos::parallel_for( - "Make tags alive", - total_alive, - Lambda(index_t p) { - this_tag(p) = ParticleTag::alive; - }); - - Kokkos::parallel_for( - "Make tags dead", - total_dead, - Lambda(index_t p) { - this_tag(total_alive + p) = ParticleTag::dead; - }); - - species.set_npart(total_alive); - - std::tie(npart_per_tag_arr, - tag_offset) = species.npart_per_tag(); - raise::FatalIf(npart_per_tag_arr[ParticleTag::alive] != total_alive, - "Error in removing dead particles: alive count doesn't match", - HERE); - raise::FatalIf(npart_per_tag_arr[ParticleTag::dead] != 0, - "Error in removing dead particles: not all particles are dead", - HERE); - + species.RemoveDead(); } - - return; } template struct Metadomain>; diff --git a/src/framework/domain/domain.h b/src/framework/domain/domain.h index 397907fef..bc7c6e4b5 100644 --- a/src/framework/domain/domain.h +++ b/src/framework/domain/domain.h @@ -65,7 +65,7 @@ namespace ntt { Mesh mesh; Fields fields; std::vector> species; - random_number_pool_t random_pool { constant::RandomSeed }; + random_number_pool_t random_pool; /** * @brief constructor for "empty" allocation of non-local domain placeholders @@ -81,6 +81,7 @@ namespace ntt { : mesh { ncells, extent, metric_params } , fields {} , species {} + , random_pool { constant::RandomSeed } , m_index { index } , m_offset_ndomains { offset_ndomains } , m_offset_ncells { offset_ncells } {} @@ -95,6 +96,7 @@ namespace ntt { : mesh { ncells, extent, metric_params } , fields { ncells } , species { species_params.begin(), species_params.end() } + , random_pool { constant::RandomSeed + static_cast(index) } , m_index { index } , m_offset_ndomains { offset_ndomains } , m_offset_ncells { offset_ncells } {} @@ -144,8 +146,7 @@ namespace ntt { } /* setters -------------------------------------------------------------- */ - auto set_neighbor_idx(const dir::direction_t& dir, unsigned int idx) - -> void { + auto set_neighbor_idx(const dir::direction_t& dir, unsigned int idx) -> void { m_neighbor_idx[dir] = idx; } @@ -163,8 +164,8 @@ namespace ntt { }; template - inline auto operator<<(std::ostream& os, const Domain& domain) - -> std::ostream& { + inline auto operator<<(std::ostream& os, + const Domain& domain) -> std::ostream& { os << "Domain #" << domain.index(); #if defined(MPI_ENABLED) os << " [MPI rank: " << domain.mpi_rank() << "]"; diff --git a/src/framework/domain/metadomain.cpp b/src/framework/domain/metadomain.cpp index a01296823..ec8561a9a 100644 --- a/src/framework/domain/metadomain.cpp +++ b/src/framework/domain/metadomain.cpp @@ -399,33 +399,6 @@ namespace ntt { #endif } - // Function to assign a unique ID to each particle - template - void Metadomain::SetParticleIDs(Domain& domain){ - for (auto& species : domain.species) { - auto &this_particleID = species.particleID; - auto &this_tag = species.tag; - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - const auto offset_per_rank = static_cast(1e9 * rank); - std::size_t current_particleID = 0; - Kokkos::View counter_view("current_particleID", 1); - Kokkos::deep_copy(counter_view, current_particleID); - - Kokkos::parallel_for( - "Set Particle IDs", - species.npart(), - Lambda(const std::size_t p){ - if (this_tag(p) == ParticleTag::alive) - { - Kokkos::atomic_increment(&counter_view(0)); - this_particleID(p) = offset_per_rank + static_cast(counter_view(0)); - } - }); - } - return; - } - template struct Metadomain>; template struct Metadomain>; template struct Metadomain>; diff --git a/src/framework/domain/metadomain.h b/src/framework/domain/metadomain.h index 9e2c2bb9d..5177571d0 100644 --- a/src/framework/domain/metadomain.h +++ b/src/framework/domain/metadomain.h @@ -88,10 +88,8 @@ namespace ntt { void CommunicateFields(Domain&, CommTags); void SynchronizeFields(Domain&, CommTags, const range_tuple_t& = { 0, 0 }); - void CommunicateParticles(Domain&, timer::Timers*); - void CommunicateParticlesBuffer(Domain&, timer::Timers*); - void SetParticleIDs(Domain&); - void RemoveDeadParticles(Domain& ,timer::Timers* ); + void CommunicateParticles(Domain&); + void RemoveDeadParticles(Domain&); /** * @param global_ndomains total number of domains diff --git a/src/framework/domain/output.cpp b/src/framework/domain/output.cpp index 4a6b2c908..c39f0c67f 100644 --- a/src/framework/domain/output.cpp +++ b/src/framework/domain/output.cpp @@ -107,7 +107,6 @@ namespace ntt { } } - template void ComputeMoments(const SimulationParams& params, const Mesh& mesh, @@ -475,16 +474,14 @@ namespace ntt { for (const auto& prtl : g_writer.speciesWriters()) { auto& species = local_domain->species[prtl.species() - 1]; if (not species.is_sorted()) { - species.SortByTags(); + species.RemoveDead(); } const std::size_t nout = species.npart() / prtl_stride; array_t buff_x1, buff_x2, buff_x3; - array_t buff_ux1, buff_ux2, buff_ux3; - array_t buff_wei; - buff_wei = array_t { "w", nout }; - buff_ux1 = array_t { "u1", nout }; - buff_ux2 = array_t { "u2", nout }; - buff_ux3 = array_t { "u3", nout }; + array_t buff_ux1 { "u1", nout }; + array_t buff_ux2 { "ux2", nout }; + array_t buff_ux3 { "ux3", nout }; + array_t buff_wei { "w", nout }; if constexpr (M::Dim == Dim::_1D or M::Dim == Dim::_2D or M::Dim == Dim::_3D) { buff_x1 = array_t { "x1", nout }; diff --git a/src/framework/parameters.cpp b/src/framework/parameters.cpp index b667b5ac9..af7a773ed 100644 --- a/src/framework/parameters.cpp +++ b/src/framework/parameters.cpp @@ -31,10 +31,10 @@ namespace ntt { template - auto get_dx0_V0(const std::vector& resolution, - const boundaries_t& extent, - const std::map& params) - -> std::pair { + auto get_dx0_V0( + const std::vector& resolution, + const boundaries_t& extent, + const std::map& params) -> std::pair { const auto metric = M(resolution, extent, params); const auto dx0 = metric.dxMin(); coord_t x_corner { ZERO }; @@ -445,15 +445,8 @@ namespace ntt { defaults::gr::pusher_niter)); } /* [particles] ---------------------------------------------------------- */ -#if defined(MPI_ENABLED) - const std::size_t sort_interval = 1; -#else - const std::size_t sort_interval = toml::find_or(toml_data, - "particles", - "sort_interval", - defaults::sort_interval); -#endif - set("particles.sort_interval", sort_interval); + set("particles.clear_interval", + toml::find_or(toml_data, "particles", "clear_interval", defaults::clear_interval)); /* [output] ------------------------------------------------------------- */ // fields diff --git a/src/framework/tests/parameters.cpp b/src/framework/tests/parameters.cpp index 393cd2409..1a4228642 100644 --- a/src/framework/tests/parameters.cpp +++ b/src/framework/tests/parameters.cpp @@ -48,7 +48,7 @@ const auto mink_1d = u8R"( [particles] ppc0 = 10.0 - sort_interval = 100 + clear_interval = 100 [[particles.species]] label = "e-" @@ -134,7 +134,7 @@ const auto sph_2d = u8R"( [particles] ppc0 = 25.0 use_weights = true - sort_interval = 50 + clear_interval = 50 [[particles.species]] @@ -199,7 +199,7 @@ const auto qks_2d = u8R"( [particles] ppc0 = 4.0 - sort_interval = 100 + clear_interval = 100 [[particles.species]] label = "e-" @@ -269,7 +269,7 @@ auto main(int argc, char* argv[]) -> int { (real_t)0.0078125, "scales.V0"); boundaries_t fbc = { - {FldsBC::PERIODIC, FldsBC::PERIODIC} + { FldsBC::PERIODIC, FldsBC::PERIODIC } }; assert_equal( params_mink_1d.get>("grid.boundaries.fields")[0].first, @@ -345,8 +345,8 @@ auto main(int argc, char* argv[]) -> int { "simulation.engine"); boundaries_t fbc = { - {FldsBC::ATMOSPHERE, FldsBC::ABSORB}, - { FldsBC::AXIS, FldsBC::AXIS} + { FldsBC::ATMOSPHERE, FldsBC::ABSORB }, + { FldsBC::AXIS, FldsBC::AXIS } }; assert_equal(params_sph_2d.get("scales.B0"), @@ -480,9 +480,9 @@ auto main(int argc, char* argv[]) -> int { "grid.metric.ks_rh"); const auto expect = std::map { - {"r0", 0.0}, - { "h", 0.25}, - { "a", 0.99} + { "r0", 0.0 }, + { "h", 0.25 }, + { "a", 0.99 } }; auto read = params_qks_2d.get>( "grid.metric.params"); @@ -501,8 +501,8 @@ auto main(int argc, char* argv[]) -> int { "algorithms.gr.pusher_niter"); boundaries_t pbc = { - {PrtlBC::HORIZON, PrtlBC::ABSORB}, - { PrtlBC::AXIS, PrtlBC::AXIS} + { PrtlBC::HORIZON, PrtlBC::ABSORB }, + { PrtlBC::AXIS, PrtlBC::AXIS } }; assert_equal(params_qks_2d.get("scales.B0"), @@ -579,86 +579,3 @@ auto main(int argc, char* argv[]) -> int { return 0; } - -// const auto mink_1d = R"( -// [simulation] -// name = "" -// engine = "" -// runtime = "" - -// [grid] -// resolution = "" -// extent = "" - -// [grid.metric] -// metric = "" -// qsph_r0 = "" -// qsph_h = "" -// ks_a = "" - -// [grid.boundaries] -// fields = "" -// particles = "" -// absorb_d = "" -// absorb_coeff = "" - -// [scales] -// larmor0 = "" -// skindepth0 = "" - -// [algorithms] -// current_filters = "" - -// [algorithms.toggles] -// fieldsolver = "" -// deposit = "" - -// [algorithms.timestep] -// CFL = "" -// correction = "" - -// [algorithms.gr] -// pusher_eps = "" -// pusher_niter = "" - -// [algorithms.gca] -// e_ovr_b_max = "" -// larmor_max = "" - -// [algorithms.synchrotron] -// gamma_rad = "" - -// [particles] -// ppc0 = "" -// use_weights = "" -// sort_interval = "" - -// [[particles.species]] -// label = "" -// mass = "" -// charge = "" -// maxnpart = "" -// pusher = "" -// n_payloads = "" -// cooling = "" -// [setup] - -// [output] -// fields = "" -// particles = "" -// format = "" -// mom_smooth = "" -// fields_stride = "" -// prtl_stride = "" -// interval = "" -// interval_time = "" - -// [output.debug] -// as_is = "" -// ghosts = "" - -// [diagnostics] -// interval = "" -// log_level = "" -// blocking_timers = "" -// )"_toml; diff --git a/src/global/arch/directions.h b/src/global/arch/directions.h index 19cf182d6..ccd4e67b0 100644 --- a/src/global/arch/directions.h +++ b/src/global/arch/directions.h @@ -132,8 +132,8 @@ namespace dir { using dirs_t = std::vector>; template - inline auto operator<<(std::ostream& os, const direction_t& dir) - -> std::ostream& { + inline auto operator<<(std::ostream& os, + const direction_t& dir) -> std::ostream& { for (auto& d : dir) { os << std::setw(2) << std::left; if (d > 0) { @@ -175,81 +175,81 @@ namespace dir { template <> struct Directions { inline static const dirs_t all = { - {-1, -1}, - {-1, 0}, - {-1, 1}, - { 0, -1}, - { 0, 1}, - { 1, -1}, - { 1, 0}, - { 1, 1} + { -1, -1 }, + { -1, 0 }, + { -1, 1 }, + { 0, -1 }, + { 0, 1 }, + { 1, -1 }, + { 1, 0 }, + { 1, 1 } }; inline static const dirs_t orth = { - {-1, 0}, - { 0, -1}, - { 0, 1}, - { 1, 0} + { -1, 0 }, + { 0, -1 }, + { 0, 1 }, + { 1, 0 } }; inline static const dirs_t unique = { - { 0, 1}, - { 1, 1}, - { 1, 0}, - {-1, 1} + { 0, 1 }, + { 1, 1 }, + { 1, 0 }, + { -1, 1 } }; }; template <> struct Directions { inline static const dirs_t all = { - {-1, -1, -1}, - {-1, -1, 0}, - {-1, -1, 1}, - {-1, 0, -1}, - {-1, 0, 0}, - {-1, 0, 1}, - {-1, 1, -1}, - {-1, 1, 0}, - {-1, 1, 1}, - { 0, -1, -1}, - { 0, -1, 0}, - { 0, -1, 1}, - { 0, 0, -1}, - { 0, 0, 1}, - { 0, 1, -1}, - { 0, 1, 0}, - { 0, 1, 1}, - { 1, -1, -1}, - { 1, -1, 0}, - { 1, -1, 1}, - { 1, 0, -1}, - { 1, 0, 0}, - { 1, 0, 1}, - { 1, 1, -1}, - { 1, 1, 0}, - { 1, 1, 1} + { -1, -1, -1 }, + { -1, -1, 0 }, + { -1, -1, 1 }, + { -1, 0, -1 }, + { -1, 0, 0 }, + { -1, 0, 1 }, + { -1, 1, -1 }, + { -1, 1, 0 }, + { -1, 1, 1 }, + { 0, -1, -1 }, + { 0, -1, 0 }, + { 0, -1, 1 }, + { 0, 0, -1 }, + { 0, 0, 1 }, + { 0, 1, -1 }, + { 0, 1, 0 }, + { 0, 1, 1 }, + { 1, -1, -1 }, + { 1, -1, 0 }, + { 1, -1, 1 }, + { 1, 0, -1 }, + { 1, 0, 0 }, + { 1, 0, 1 }, + { 1, 1, -1 }, + { 1, 1, 0 }, + { 1, 1, 1 } }; inline static const dirs_t orth = { - {-1, 0, 0}, - { 0, -1, 0}, - { 0, 0, -1}, - { 0, 0, 1}, - { 0, 1, 0}, - { 1, 0, 0} + { -1, 0, 0 }, + { 0, -1, 0 }, + { 0, 0, -1 }, + { 0, 0, 1 }, + { 0, 1, 0 }, + { 1, 0, 0 } }; inline static const dirs_t unique = { - { 0, 0, 1}, - { 0, 1, 0}, - { 1, 0, 0}, - { 1, 1, 0}, - {-1, 1, 0}, - { 0, 1, 1}, - { 0, -1, 1}, - { 1, 0, 1}, - {-1, 0, 1}, - { 1, 1, 1}, - {-1, 1, 1}, - { 1, -1, 1}, - { 1, 1, -1} + { 0, 0, 1 }, + { 0, 1, 0 }, + { 1, 0, 0 }, + { 1, 1, 0 }, + { -1, 1, 0 }, + { 0, 1, 1 }, + { 0, -1, 1 }, + { 1, 0, 1 }, + { -1, 0, 1 }, + { 1, 1, 1 }, + { -1, 1, 1 }, + { 1, -1, 1 }, + { 1, 1, -1 } }; }; diff --git a/src/global/arch/kokkos_aliases.cpp b/src/global/arch/kokkos_aliases.cpp index 4311a40bd..6c15e3d52 100644 --- a/src/global/arch/kokkos_aliases.cpp +++ b/src/global/arch/kokkos_aliases.cpp @@ -5,18 +5,18 @@ #include template <> -auto CreateRangePolicy(const tuple_t& i1, - const tuple_t& i2) - -> range_t { +auto CreateRangePolicy( + const tuple_t& i1, + const tuple_t& i2) -> range_t { index_t i1min = i1[0]; index_t i1max = i2[0]; return Kokkos::RangePolicy(i1min, i1max); } template <> -auto CreateRangePolicy(const tuple_t& i1, - const tuple_t& i2) - -> range_t { +auto CreateRangePolicy( + const tuple_t& i1, + const tuple_t& i2) -> range_t { index_t i1min = i1[0]; index_t i1max = i2[0]; index_t i2min = i1[1]; @@ -26,9 +26,9 @@ auto CreateRangePolicy(const tuple_t& i1, } template <> -auto CreateRangePolicy(const tuple_t& i1, - const tuple_t& i2) - -> range_t { +auto CreateRangePolicy( + const tuple_t& i1, + const tuple_t& i2) -> range_t { index_t i1min = i1[0]; index_t i1max = i2[0]; index_t i2min = i1[1]; @@ -41,18 +41,18 @@ auto CreateRangePolicy(const tuple_t& i1, } template <> -auto CreateRangePolicyOnHost(const tuple_t& i1, - const tuple_t& i2) - -> range_h_t { +auto CreateRangePolicyOnHost( + const tuple_t& i1, + const tuple_t& i2) -> range_h_t { index_t i1min = i1[0]; index_t i1max = i2[0]; return Kokkos::RangePolicy(i1min, i1max); } template <> -auto CreateRangePolicyOnHost(const tuple_t& i1, - const tuple_t& i2) - -> range_h_t { +auto CreateRangePolicyOnHost( + const tuple_t& i1, + const tuple_t& i2) -> range_h_t { index_t i1min = i1[0]; index_t i1max = i2[0]; index_t i2min = i1[1]; @@ -62,9 +62,9 @@ auto CreateRangePolicyOnHost(const tuple_t& i1, } template <> -auto CreateRangePolicyOnHost(const tuple_t& i1, - const tuple_t& i2) - -> range_h_t { +auto CreateRangePolicyOnHost( + const tuple_t& i1, + const tuple_t& i2) -> range_h_t { index_t i1min = i1[0]; index_t i1max = i2[0]; index_t i2min = i1[1]; @@ -76,11 +76,11 @@ auto CreateRangePolicyOnHost(const tuple_t& i1, { i1max, i2max, i3max }); } -// auto WaitAndSynchronize(bool debug_only) -> void { -// if (debug_only) { -// #ifndef DEBUG -// return; -// #endif -// } -// Kokkos::fence(); -// } \ No newline at end of file +auto WaitAndSynchronize(bool debug_only) -> void { + if (debug_only) { +#ifndef DEBUG + return; +#endif + } + Kokkos::fence(); +} diff --git a/src/global/defaults.h b/src/global/defaults.h index be92acbf9..b7b0107e7 100644 --- a/src/global/defaults.h +++ b/src/global/defaults.h @@ -22,9 +22,9 @@ namespace ntt::defaults { const unsigned short current_filters = 0; - const std::string em_pusher = "Boris"; - const std::string ph_pusher = "Photon"; - const std::size_t sort_interval = 100; + const std::string em_pusher = "Boris"; + const std::string ph_pusher = "Photon"; + const std::size_t clear_interval = 100; namespace qsph { const real_t r0 = 0.0; @@ -45,7 +45,7 @@ namespace ntt::defaults { const real_t ds_frac = 0.01; const real_t coeff = 1.0; } // namespace absorb - } // namespace bc + } // namespace bc namespace output { const std::string format = "hdf5"; diff --git a/src/global/global.cpp b/src/global/global.cpp index 434740446..ec22fd2f3 100644 --- a/src/global/global.cpp +++ b/src/global/global.cpp @@ -9,17 +9,7 @@ void ntt::GlobalInitialize(int argc, char* argv[]) { Kokkos::initialize(argc, argv); #if defined(MPI_ENABLED) - int required = MPI_THREAD_MULTIPLE; - int provided; - MPI_Init_thread(&argc, - &argv, - required, - &provided); - if (provided != required) { - std::cerr << "MPI_Init_thread() did not provide the requested threading support." << std::endl; - MPI_Abort(MPI_COMM_WORLD, 1); - } - //MPI_Init(&argc, &argv); + MPI_Init(&argc, &argv); #endif // MPI_ENABLED } diff --git a/src/global/global.h b/src/global/global.h index ad524fb0e..dad6afccc 100644 --- a/src/global/global.h +++ b/src/global/global.h @@ -209,7 +209,7 @@ namespace Timer { PrintTitle = 1 << 1, AutoConvert = 1 << 2, PrintOutput = 1 << 3, - PrintSorting = 1 << 4, + PrintPrtlClear = 1 << 4, PrintCheckpoint = 1 << 5, PrintNormed = 1 << 6, Default = PrintNormed | PrintTotal | PrintTitle | AutoConvert, diff --git a/src/global/utils/diag.cpp b/src/global/utils/diag.cpp index 0a499dd56..c053cdacf 100644 --- a/src/global/utils/diag.cpp +++ b/src/global/utils/diag.cpp @@ -21,8 +21,9 @@ #include namespace diag { - auto npart_stats(std::size_t npart, std::size_t maxnpart) - -> std::vector> { + auto npart_stats( + std::size_t npart, + std::size_t maxnpart) -> std::vector> { auto stats = std::vector>(); #if !defined(MPI_ENABLED) stats.push_back( @@ -84,7 +85,7 @@ namespace diag { const std::vector& species_labels, const std::vector& species_npart, const std::vector& species_maxnpart, - bool print_sorting, + bool print_prtl_clear, bool print_output, bool print_checkpoint, bool print_colors) { @@ -96,8 +97,8 @@ namespace diag { if (species_labels.size() == 0) { diag_flags ^= Diag::Species; } - if (print_sorting) { - timer_flags |= Timer::PrintSorting; + if (print_prtl_clear) { + timer_flags |= Timer::PrintPrtlClear; } if (print_output) { timer_flags |= Timer::PrintOutput; diff --git a/src/global/utils/diag.h b/src/global/utils/diag.h index 9951602f8..30cca5705 100644 --- a/src/global/utils/diag.h +++ b/src/global/utils/diag.h @@ -34,9 +34,9 @@ namespace diag { * @param species_labels (vector of particle labels) * @param npart (per each species) * @param maxnpart (per each species) - * @param sorting_step (if true, particles were sorted) - * @param output_step (if true, output was written) - * @param checkpoint_step (if true, checkpoint was written) + * @param prtlclear (if true, dead particles were removed) + * @param output (if true, output was written) + * @param checkpoint (if true, checkpoint was written) * @param colorful_print (if true, print with colors) */ void printDiagnostics(std::size_t, diff --git a/src/global/utils/timer.cpp b/src/global/utils/timer.cpp index b5f4408ca..7d5a9bebd 100644 --- a/src/global/utils/timer.cpp +++ b/src/global/utils/timer.cpp @@ -127,10 +127,11 @@ namespace timer { return timer_stats; } - auto Timers::printAll(TimerFlags flags, std::size_t npart, std::size_t ncells) const - -> std::string { - const std::vector extras { "Sorting", "Output", "Checkpoint" }; - const auto stats = gather(extras, npart, ncells); + auto Timers::printAll(TimerFlags flags, + std::size_t npart, + std::size_t ncells) const -> std::string { + const std::vector extras { "PrtlClear", "Output", "Checkpoint" }; + const auto stats = gather(extras, npart, ncells); if (stats.empty()) { return ""; } @@ -253,8 +254,8 @@ namespace timer { } } - // print extra timers for output/checkpoint/sorting - const std::vector extras_f { Timer::PrintSorting, + // print extra timers for output/checkpoint/prtlClear + const std::vector extras_f { Timer::PrintPrtlClear, Timer::PrintOutput, Timer::PrintCheckpoint }; for (auto i { 0u }; i < extras.size(); ++i) { diff --git a/src/kernels/particle_pusher_sr.hpp b/src/kernels/particle_pusher_sr.hpp index 0deb73c6f..b4808f12a 100644 --- a/src/kernels/particle_pusher_sr.hpp +++ b/src/kernels/particle_pusher_sr.hpp @@ -90,7 +90,7 @@ namespace kernel::sr { Force(const F& pgen_force) : Force { pgen_force, - {ZERO, ZERO, ZERO}, + { ZERO, ZERO, ZERO }, ZERO, ZERO } { From 541633ead6dfde4444836c901059e9b0221e2e0a Mon Sep 17 00:00:00 2001 From: haykh Date: Wed, 22 Jan 2025 15:21:53 -0500 Subject: [PATCH 231/773] toml schema --- .taplo.toml | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .taplo.toml diff --git a/.taplo.toml b/.taplo.toml new file mode 100644 index 000000000..423a47594 --- /dev/null +++ b/.taplo.toml @@ -0,0 +1,6 @@ +[formatting] + align_entries = true + indent_tables = true + indent_entries = true + trailing_newline = true + align_comments = true From 9d0c8dbd5f85983d5ef05b970d99ae9742cd4f66 Mon Sep 17 00:00:00 2001 From: haykh Date: Wed, 22 Jan 2025 15:22:41 -0500 Subject: [PATCH 232/773] nix shells --- dev/nix/adios2.nix | 61 ++++++++++++++++++++++++++++++++++++++++++++++ dev/nix/shell.nix | 56 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 117 insertions(+) create mode 100644 dev/nix/adios2.nix create mode 100644 dev/nix/shell.nix diff --git a/dev/nix/adios2.nix b/dev/nix/adios2.nix new file mode 100644 index 000000000..19c706aa4 --- /dev/null +++ b/dev/nix/adios2.nix @@ -0,0 +1,61 @@ +{ + pkgs ? import { }, + hdf5 ? false, + mpi ? false, +}: + +let + name = "adios2"; + version = "2.10.2"; +in +pkgs.stdenv.mkDerivation { + pname = "${name}${if hdf5 then "-hdf5" else ""}${if mpi then "-mpi" else ""}"; + version = "${version}"; + src = pkgs.fetchgit { + url = "https://github.com/ornladios/ADIOS2/"; + rev = "v${version}"; + sha256 = "sha256-NVyw7xoPutXeUS87jjVv1YxJnwNGZAT4QfkBLzvQbwg="; + }; + + nativeBuildInputs = + with pkgs; + [ + cmake + libgcc + perl + breakpointHook + ] + ++ (if mpi then [ openmpi ] else [ ]); + + buildInputs = if hdf5 then (if mpi then [ pkgs.hdf5-mpi ] else [ pkgs.hdf5 ]) else [ ]; + + configurePhase = '' + cmake -B build $src \ + -D CMAKE_CXX_STANDARD=17 \ + -D CMAKE_CXX_EXTENSIONS=OFF \ + -D CMAKE_POSITION_INDEPENDENT_CODE=TRUE \ + -D BUILD_SHARED_LIBS=ON \ + -D ADIOS2_USE_HDF5=${if hdf5 then "ON" else "OFF"} \ + -D ADIOS2_USE_Python=OFF \ + -D ADIOS2_USE_Fortran=OFF \ + -D ADIOS2_USE_ZeroMQ=OFF \ + -D BUILD_TESTING=OFF \ + -D ADIOS2_BUILD_EXAMPLES=OFF \ + -D ADIOS2_USE_MPI=${if mpi then "ON" else "OFF"} \ + -D ADIOS2_HAVE_HDF5_VOL=OFF \ + -D CMAKE_BUILD_TYPE=Release + ''; + + buildPhase = '' + cmake --build build -j + ''; + + installPhase = '' + sed -i '/if(CMAKE_INSTALL_COMPONENT/,/^[[:space:]]&endif()$/d' build/cmake/install/post/cmake_install.cmake + cmake --install build --prefix $out + chmod +x build/cmake/install/post/generate-adios2-config.sh + sh build/cmake/install/post/generate-adios2-config.sh $out + ''; + + enableParallelBuilding = true; +} diff --git a/dev/nix/shell.nix b/dev/nix/shell.nix new file mode 100644 index 000000000..22358a837 --- /dev/null +++ b/dev/nix/shell.nix @@ -0,0 +1,56 @@ +{ + pkgs ? import { }, + mpi ? false, + hdf5 ? false, +}: + +let + name = "entity-dev"; + compilerPkg = pkgs.gcc13; + compilerCXX = "g++"; + compilerCC = "gcc"; + adios2Pkg = (pkgs.callPackage ./adios2.nix { inherit pkgs mpi hdf5; }); +in +pkgs.mkShell { + name = "${name}-env"; + nativeBuildInputs = + with pkgs; + [ + zlib + cmake + + compilerPkg + + clang-tools + + adios2Pkg + python312 + python312Packages.jupyter + + cmake-format + neocmakelsp + black + pyright + taplo + vscode-langservers-extracted + ] + ++ (if mpi then [ pkgs.openmpi ] else [ ]) + ++ (if hdf5 then (if mpi then [ pkgs.hdf5-mpi ] else [ pkgs.hdf5 ]) else [ ]); + + LD_LIBRARY_PATH = pkgs.lib.makeLibraryPath ([ + pkgs.clang19Stdenv.cc.cc + pkgs.zlib + ]); + + shellHook = '' + BLUE='\033[0;34m' + NC='\033[0m' + export CC=$(which ${compilerCC}) + export CXX=$(which ${compilerCXX}) + export CMAKE_CXX_COMPILER=$(which ${compilerCXX}) + export CMAKE_C_COMPILER=$(which ${compilerCC}) + + echo "" + echo -e "${name} nix-shell activated: ''\${BLUE}$(which ${compilerCXX})''\${NC}" + ''; +} From 5d1d8f71bcc24b7a48bfb1d8928b6355be027b3c Mon Sep 17 00:00:00 2001 From: haykh Date: Wed, 22 Jan 2025 15:23:57 -0500 Subject: [PATCH 233/773] comment --- src/framework/domain/comm_mpi.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/framework/domain/comm_mpi.hpp b/src/framework/domain/comm_mpi.hpp index 370c02b18..eb77ecbb3 100644 --- a/src/framework/domain/comm_mpi.hpp +++ b/src/framework/domain/comm_mpi.hpp @@ -345,6 +345,8 @@ namespace comm { auto& this_weight = species.weight; auto& this_tag = species.tag; + // @TODO_1.2.0: communicate payloads + // number of arrays of each type to send/recv const unsigned short NREALS = 4 + static_cast( D == Dim::_2D and C != Coord::Cart); From 179928f6f99a5bcb4c4aa1cd37795a9e66c9a6cb Mon Sep 17 00:00:00 2001 From: haykh Date: Thu, 23 Jan 2025 09:12:58 -0500 Subject: [PATCH 234/773] plds are now 2d array --- src/checkpoint/reader.cpp | 38 ++++-- src/checkpoint/reader.h | 8 ++ src/checkpoint/tests/CMakeLists.txt | 2 +- src/checkpoint/tests/checkpoint-mpi.cpp | 149 ++++++++++++++++-------- src/checkpoint/writer.cpp | 33 +++++- src/checkpoint/writer.h | 8 ++ src/framework/containers/particles.cpp | 102 +++++----------- src/framework/containers/particles.h | 35 ++---- src/framework/domain/checkpoint.cpp | 32 ++--- src/framework/domain/comm_mpi.hpp | 1 + src/framework/tests/particles.cpp | 8 +- src/global/arch/mpi_tags.h | 13 ++- 12 files changed, 250 insertions(+), 179 deletions(-) diff --git a/src/checkpoint/reader.cpp b/src/checkpoint/reader.cpp index e89b7d384..208972561 100644 --- a/src/checkpoint/reader.cpp +++ b/src/checkpoint/reader.cpp @@ -35,16 +35,17 @@ namespace checkpoint { reader.Get(field_var, array_h.data(), adios2::Mode::Sync); Kokkos::deep_copy(array, array_h); } else { - raise::Error(fmt::format("Field variable: %s not found", field.c_str()), HERE); + raise::Error(fmt::format("Field variable: %s not found", field.c_str()), + HERE); } } - auto ReadParticleCount(adios2::IO& io, - adios2::Engine& reader, - unsigned short s, - std::size_t local_dom, - std::size_t ndomains) - -> std::pair { + auto ReadParticleCount( + adios2::IO& io, + adios2::Engine& reader, + unsigned short s, + std::size_t local_dom, + std::size_t ndomains) -> std::pair { logger::Checkpoint(fmt::format("Reading particle count for: %d", s + 1), HERE); auto npart_var = io.InquireVariable( fmt::format("s%d_npart", s + 1)); @@ -109,6 +110,29 @@ namespace checkpoint { } } + void ReadParticlePayloads(adios2::IO& io, + adios2::Engine& reader, + unsigned short s, + array_t& array, + std::size_t nplds, + std::size_t count, + std::size_t offset) { + logger::Checkpoint(fmt::format("Reading quantity: s%d_plds", s + 1), HERE); + auto var = io.InquireVariable(fmt::format("s%d_plds", s + 1)); + if (var) { + var.SetSelection(adios2::Box({ offset, 0 }, { count, nplds })); + const auto slice = std::pair { 0, count }; + auto array_h = Kokkos::create_mirror_view(array); + reader.Get(var, + Kokkos::subview(array_h, slice, range_tuple_t(0, nplds)).data(), + adios2::Mode::Sync); + Kokkos::deep_copy(Kokkos::subview(array, slice, range_tuple_t(0, nplds)), + Kokkos::subview(array_h, slice, range_tuple_t(0, nplds))); + } else { + raise::Error(fmt::format("Variable: s%d_plds not found", s + 1), HERE); + } + } + template void ReadFields(adios2::IO&, adios2::Engine&, const std::string&, diff --git a/src/checkpoint/reader.h b/src/checkpoint/reader.h index 2ea11bdb1..e5a91ab75 100644 --- a/src/checkpoint/reader.h +++ b/src/checkpoint/reader.h @@ -45,6 +45,14 @@ namespace checkpoint { std::size_t, std::size_t); + void ReadParticlePayloads(adios2::IO&, + adios2::Engine&, + unsigned short, + array_t&, + std::size_t, + std::size_t, + std::size_t); + } // namespace checkpoint #endif // CHECKPOINT_READER_H diff --git a/src/checkpoint/tests/CMakeLists.txt b/src/checkpoint/tests/CMakeLists.txt index 10836554b..54400652e 100644 --- a/src/checkpoint/tests/CMakeLists.txt +++ b/src/checkpoint/tests/CMakeLists.txt @@ -25,5 +25,5 @@ endfunction() if(NOT ${mpi}) gen_test(checkpoint-nompi) else() - # gen_test(checkpoint-mpi) + gen_test(checkpoint-mpi) endif() diff --git a/src/checkpoint/tests/checkpoint-mpi.cpp b/src/checkpoint/tests/checkpoint-mpi.cpp index 3ce4bab14..f97202ab1 100644 --- a/src/checkpoint/tests/checkpoint-mpi.cpp +++ b/src/checkpoint/tests/checkpoint-mpi.cpp @@ -39,36 +39,53 @@ auto main(int argc, char* argv[]) -> int { // | | | // | 0 | 1 | // |------|------| - constexpr auto g_nx1 = 20; - constexpr auto g_nx2 = 15; - constexpr auto g_nx1_gh = g_nx1 + 4 * N_GHOSTS; - constexpr auto g_nx2_gh = g_nx2 + 4 * N_GHOSTS; + const std::size_t g_nx1 = 20; + const std::size_t g_nx2 = 15; + const std::size_t g_nx1_gh = g_nx1 + 4 * N_GHOSTS; + const std::size_t g_nx2_gh = g_nx2 + 4 * N_GHOSTS; - constexpr auto l_nx1 = 10; - constexpr auto l_nx2 = (rank < 2) ? 10 : 5; + const std::size_t l_nx1 = 10; + const std::size_t l_nx2 = (rank < 2) ? 10 : 5; - constexpr auto l_nx1_gh = l_nx1 + 2 * N_GHOSTS; - constexpr auto l_nx2_gh = l_nx2 + 2 * N_GHOSTS; + const std::size_t l_nx1_gh = l_nx1 + 2 * N_GHOSTS; + const std::size_t l_nx2_gh = l_nx2 + 2 * N_GHOSTS; - constexpr auto l_corner_x1 = (rank % 2) * l_nx1; - constexpr auto l_corner_x2 = (rank / 2) * l_nx2; + const std::size_t l_corner_x1 = (rank % 2 == 0) ? 0 : l_nx1_gh; + const std::size_t l_corner_x2 = (rank < 2) ? 0 : l_nx2_gh; - constexpr auto i1min = N_GHOSTS; - constexpr auto i2min = N_GHOSTS; - constexpr auto i1max = l_nx1 + N_GHOSTS; - constexpr auto i2max = l_nx2 + N_GHOSTS; + const std::size_t i1min = N_GHOSTS; + const std::size_t i2min = N_GHOSTS; + const std::size_t i1max = l_nx1 + N_GHOSTS; + const std::size_t i2max = l_nx2 + N_GHOSTS; - constexpr auto npart1 = (rank % 2 + rank) * 23 + 100; - constexpr auto npart2 = (rank % 2 + rank) * 37 + 100; + const std::size_t npart1 = (rank % 2 + rank) * 23 + 100; + const std::size_t npart2 = (rank % 2 + rank) * 37 + 100; + + std::size_t npart1_offset = 0; + std::size_t npart2_offset = 0; + + std::size_t npart1_globtot = 0; + std::size_t npart2_globtot = 0; + + for (auto r = 0; r < rank - 1; ++r) { + npart1_offset += (r % 2 + r) * 23 + 100; + npart2_offset += (r % 2 + r) * 37 + 100; + } + + for (auto r = 0; r < size; ++r) { + npart1_globtot += (r % 2 + r) * 23 + 100; + npart2_globtot += (r % 2 + r) * 37 + 100; + } // init data ndfield_t field1 { "fld1", l_nx1_gh, l_nx2_gh }; ndfield_t field2 { "fld2", l_nx1_gh, l_nx2_gh }; - array_t i1 { "i_1", npart1 }; - array_t u1 { "u_1", npart1 }; - array_t i2 { "i_2", npart2 }; - array_t u2 { "u_2", npart2 }; + array_t i1 { "i_1", npart1 }; + array_t u1 { "u_1", npart1 }; + array_t i2 { "i_2", npart2 }; + array_t u2 { "u_2", npart2 }; + array_t plds1 { "plds_1", npart1, 3 }; { // fill data @@ -93,8 +110,11 @@ auto main(int argc, char* argv[]) -> int { "fillPrtl1", npart1, Lambda(index_t p) { - u1(p) = static_cast(p); - i1(p) = static_cast(p); + u1(p) = static_cast(p); + i1(p) = static_cast(p); + plds1(p, 0) = static_cast(p); + plds1(p, 1) = static_cast(p * p); + plds1(p, 2) = static_cast(p * p * p); }); Kokkos::parallel_for( "fillPrtl2", @@ -115,8 +135,9 @@ auto main(int argc, char* argv[]) -> int { writer.defineFieldVariables(SimEngine::GRPIC, { g_nx1_gh, g_nx2_gh }, { l_corner_x1, l_corner_x2 }, - { l_nx1, l_nx2 }); - writer.defineParticleVariables(Coord::Sph, Dim::_2D, 2, { 0, 0 }); + { l_nx1_gh, l_nx2_gh }); + + writer.defineParticleVariables(Coord::Sph, Dim::_2D, 2, { 3, 0 }); writer.beginSaving(0, 0.0); @@ -126,41 +147,66 @@ auto main(int argc, char* argv[]) -> int { writer.savePerDomainVariable("s1_npart", 1, 0, npart1); writer.savePerDomainVariable("s2_npart", 1, 0, npart2); - writer.saveParticleQuantity("s1_i1", npart1, 0, npart1, i1); - writer.saveParticleQuantity("s1_ux1", npart1, 0, npart1, u1); - writer.saveParticleQuantity("s2_i1", npart2, 0, npart2, i2); - writer.saveParticleQuantity("s2_ux1", npart2, 0, npart2, u2); + writer.saveParticleQuantity("s1_i1", + npart1_globtot, + npart1_offset, + npart1, + i1); + writer.saveParticleQuantity("s1_ux1", + npart1_globtot, + npart1_offset, + npart1, + u1); + writer.saveParticleQuantity("s2_i1", + npart2_globtot, + npart2_offset, + npart2, + i2); + writer.saveParticleQuantity("s2_ux1", + npart2_globtot, + npart2_offset, + npart2, + u2); + + writer.saveParticlePayloads("s1_plds", + 3, + npart1_globtot, + npart1_offset, + npart1, + plds1); writer.endSaving(); } { // read checkpoint - ndfield_t field1_read { "fld1_read", nx1_gh, nx2_gh, nx3_gh }; - ndfield_t field2_read { "fld2_read", nx1_gh, nx2_gh, nx3_gh }; + ndfield_t field1_read { "fld1_read", l_nx1_gh, l_nx2_gh }; + ndfield_t field2_read { "fld2_read", l_nx1_gh, l_nx2_gh }; - array_t i1_read { "i_1", npart1 }; - array_t u1_read { "u_1", npart1 }; - array_t i2_read { "i_2", npart2 }; - array_t u2_read { "u_2", npart2 }; + array_t i1_read { "i_1", npart1 }; + array_t u1_read { "u_1", npart1 }; + array_t i2_read { "i_2", npart2 }; + array_t u2_read { "u_2", npart2 }; + array_t plds1_read { "plds_1", npart1, 3 }; adios2::IO io = adios.DeclareIO("checkpointRead"); adios2::Engine reader = io.Open("checkpoints/step-00000000.bp", adios2::Mode::Read); reader.BeginStep(); - auto fieldRange = adios2::Box({ 0, 0, 0, 0 }, - { nx1_gh, nx2_gh, nx3_gh, 6 }); - ReadFields(io, reader, "em", fieldRange, field1_read); - ReadFields(io, reader, "em0", fieldRange, field2_read); + auto fieldRange = adios2::Box({ l_corner_x1, l_corner_x2, 0 }, + { l_nx1_gh, l_nx2_gh, 6 }); + ReadFields(io, reader, "em", fieldRange, field1_read); + ReadFields(io, reader, "em0", fieldRange, field2_read); - auto [nprtl1, noff1] = ReadParticleCount(io, reader, 0, 0, 1); - auto [nprtl2, noff2] = ReadParticleCount(io, reader, 1, 0, 1); + auto [nprtl1, noff1] = ReadParticleCount(io, reader, 0, rank, size); + auto [nprtl2, noff2] = ReadParticleCount(io, reader, 1, rank, size); ReadParticleData(io, reader, "ux1", 0, u1_read, nprtl1, noff1); ReadParticleData(io, reader, "ux1", 1, u2_read, nprtl2, noff2); ReadParticleData(io, reader, "i1", 0, i1_read, nprtl1, noff1); ReadParticleData(io, reader, "i1", 1, i2_read, nprtl2, noff2); + ReadParticlePayloads(io, reader, 0, plds1_read, 3, nprtl1, noff1); reader.EndStep(); reader.Close(); @@ -168,15 +214,13 @@ auto main(int argc, char* argv[]) -> int { // check the validity Kokkos::parallel_for( "checkFields", - CreateRangePolicy({ 0, 0, 0 }, { nx1_gh, nx2_gh, nx3_gh }), - Lambda(index_t i1, index_t i2, index_t i3) { + CreateRangePolicy({ 0, 0 }, { l_nx1_gh, l_nx2_gh }), + Lambda(index_t i1, index_t i2) { for (int i = 0; i < 6; ++i) { - if (not cmp::AlmostEqual(field1(i1, i2, i3, i), - field1_read(i1, i2, i3, i))) { + if (not cmp::AlmostEqual(field1(i1, i2, i), field1_read(i1, i2, i))) { raise::KernelError(HERE, "Field1 read failed"); } - if (not cmp::AlmostEqual(field2(i1, i2, i3, i), - field2_read(i1, i2, i3, i))) { + if (not cmp::AlmostEqual(field2(i1, i2, i), field2_read(i1, i2, i))) { raise::KernelError(HERE, "Field2 read failed"); } } @@ -184,12 +228,12 @@ auto main(int argc, char* argv[]) -> int { raise::ErrorIf(npart1 != nprtl1, "Particle count 1 mismatch", HERE); raise::ErrorIf(npart2 != nprtl2, "Particle count 2 mismatch", HERE); - raise::ErrorIf(noff1 != 0, "Particle offset 1 mismatch", HERE); - raise::ErrorIf(noff2 != 0, "Particle offset 2 mismatch", HERE); + raise::ErrorIf(noff1 != npart1_offset, "Particle offset 1 mismatch", HERE); + raise::ErrorIf(noff2 != npart2_offset, "Particle offset 2 mismatch", HERE); Kokkos::parallel_for( "checkPrtl1", - npart1, + nprtl1, Lambda(index_t p) { if (not cmp::AlmostEqual(u1(p), u1_read(p))) { raise::KernelError(HERE, "u1 read failed"); @@ -197,10 +241,15 @@ auto main(int argc, char* argv[]) -> int { if (i1(p) != i1_read(p)) { raise::KernelError(HERE, "i1 read failed"); } + for (auto l = 0; l < 3; ++l) { + if (not cmp::AlmostEqual(plds1(p, l), plds1_read(p, l))) { + raise::KernelError(HERE, "plds1 read failed"); + } + } }); Kokkos::parallel_for( "checkPrtl2", - npart2, + nprtl2, Lambda(index_t p) { if (not cmp::AlmostEqual(u2(p), u2_read(p))) { raise::KernelError(HERE, "u2 read failed"); diff --git a/src/checkpoint/writer.cpp b/src/checkpoint/writer.cpp index 9ef0b51c7..a12e3ef26 100644 --- a/src/checkpoint/writer.cpp +++ b/src/checkpoint/writer.cpp @@ -84,6 +84,7 @@ namespace checkpoint { { adios2::UnknownDim }, { adios2::UnknownDim }, { adios2::UnknownDim }); + for (auto d { 0u }; d < dim; ++d) { m_io.DefineVariable(fmt::format("s%d_i%d", s + 1, d + 1), { adios2::UnknownDim }, @@ -102,18 +103,21 @@ namespace checkpoint { { adios2::UnknownDim }, { adios2::UnknownDim }); } + if (dim == Dim::_2D and C != ntt::Coord::Cart) { m_io.DefineVariable(fmt::format("s%d_phi", s + 1), { adios2::UnknownDim }, { adios2::UnknownDim }, { adios2::UnknownDim }); } + for (auto d { 0u }; d < 3; ++d) { m_io.DefineVariable(fmt::format("s%d_ux%d", s + 1, d + 1), { adios2::UnknownDim }, { adios2::UnknownDim }, { adios2::UnknownDim }); } + m_io.DefineVariable(fmt::format("s%d_tag", s + 1), { adios2::UnknownDim }, { adios2::UnknownDim }, @@ -122,11 +126,11 @@ namespace checkpoint { { adios2::UnknownDim }, { adios2::UnknownDim }, { adios2::UnknownDim }); - for (auto p { 0u }; p < nplds[s]; ++p) { - m_io.DefineVariable(fmt::format("s%d_pld%d", s + 1, p + 1), - { adios2::UnknownDim }, - { adios2::UnknownDim }, - { adios2::UnknownDim }); + if (nplds[s] > 0) { + m_io.DefineVariable(fmt::format("s%d_plds", s + 1), + { adios2::UnknownDim, nplds[s] }, + { adios2::UnknownDim, 0 }, + { adios2::UnknownDim, nplds[s] }); } } } @@ -238,6 +242,25 @@ namespace checkpoint { m_writer.Put(var, data_sub.data(), adios2::Mode::Sync); } + void Writer::saveParticlePayloads(const std::string& quantity, + std::size_t nplds, + std::size_t glob_total, + std::size_t loc_offset, + std::size_t loc_size, + const array_t& data) { + const auto slice = range_tuple_t(0, loc_size); + auto var = m_io.InquireVariable(quantity); + + var.SetShape({ glob_total, nplds }); + var.SetSelection( + adios2::Box({ loc_offset, 0 }, { loc_size, nplds })); + + auto data_h = Kokkos::create_mirror_view(data); + Kokkos::deep_copy(data_h, data); + auto data_sub = Kokkos::subview(data_h, slice, range_tuple_t(0, nplds)); + m_writer.Put(var, data_sub.data(), adios2::Mode::Sync); + } + template void Writer::savePerDomainVariable(const std::string&, std::size_t, std::size_t, diff --git a/src/checkpoint/writer.h b/src/checkpoint/writer.h index 34b5f043f..346bee24a 100644 --- a/src/checkpoint/writer.h +++ b/src/checkpoint/writer.h @@ -69,10 +69,18 @@ namespace checkpoint { std::size_t, const array_t&); + void saveParticlePayloads(const std::string&, + std::size_t, + std::size_t, + std::size_t, + std::size_t, + const array_t&); + void defineFieldVariables(const ntt::SimEngine&, const std::vector&, const std::vector&, const std::vector&); + void defineParticleVariables(const ntt::Coord&, Dimension, std::size_t, diff --git a/src/framework/containers/particles.cpp b/src/framework/containers/particles.cpp index 758118d6c..fc8214824 100644 --- a/src/framework/containers/particles.cpp +++ b/src/framework/containers/particles.cpp @@ -28,55 +28,43 @@ namespace ntt { const Cooling& cooling, unsigned short npld) : ParticleSpecies(index, label, m, ch, maxnpart, pusher, use_gca, cooling, npld) { - i1 = array_t { label + "_i1", maxnpart }; - i1_h = Kokkos::create_mirror_view(i1); - dx1 = array_t { label + "_dx1", maxnpart }; - dx1_h = Kokkos::create_mirror_view(dx1); - - i1_prev = array_t { label + "_i1_prev", maxnpart }; - dx1_prev = array_t { label + "_dx1_prev", maxnpart }; - - ux1 = array_t { label + "_ux1", maxnpart }; - ux1_h = Kokkos::create_mirror_view(ux1); - ux2 = array_t { label + "_ux2", maxnpart }; - ux2_h = Kokkos::create_mirror_view(ux2); - ux3 = array_t { label + "_ux3", maxnpart }; - ux3_h = Kokkos::create_mirror_view(ux3); - - weight = array_t { label + "_w", maxnpart }; - weight_h = Kokkos::create_mirror_view(weight); - - tag = array_t { label + "_tag", maxnpart }; - tag_h = Kokkos::create_mirror_view(tag); - - for (unsigned short n { 0 }; n < npld; ++n) { - pld.push_back(array_t("pld", maxnpart)); - pld_h.push_back(Kokkos::create_mirror_view(pld[n])); - } - if constexpr ((D == Dim::_2D) || (D == Dim::_3D)) { - i2 = array_t { label + "_i2", maxnpart }; - i2_h = Kokkos::create_mirror_view(i2); - dx2 = array_t { label + "_dx2", maxnpart }; - dx2_h = Kokkos::create_mirror_view(dx2); + if constexpr (D == Dim::_1D or D == Dim::_2D or D == Dim::_3D) { + i1 = array_t { label + "_i1", maxnpart }; + dx1 = array_t { label + "_dx1", maxnpart }; + i1_prev = array_t { label + "_i1_prev", maxnpart }; + dx1_prev = array_t { label + "_dx1_prev", maxnpart }; + } + if constexpr (D == Dim::_2D or D == Dim::_3D) { + i2 = array_t { label + "_i2", maxnpart }; + dx2 = array_t { label + "_dx2", maxnpart }; i2_prev = array_t { label + "_i2_prev", maxnpart }; dx2_prev = array_t { label + "_dx2_prev", maxnpart }; } - if ((D == Dim::_2D) && (C != Coord::Cart)) { - phi = array_t { label + "_phi", maxnpart }; - phi_h = Kokkos::create_mirror_view(phi); - } if constexpr (D == Dim::_3D) { - i3 = array_t { label + "_i3", maxnpart }; - i3_h = Kokkos::create_mirror_view(i3); - dx3 = array_t { label + "_dx3", maxnpart }; - dx3_h = Kokkos::create_mirror_view(dx3); - + i3 = array_t { label + "_i3", maxnpart }; + dx3 = array_t { label + "_dx3", maxnpart }; i3_prev = array_t { label + "_i3_prev", maxnpart }; dx3_prev = array_t { label + "_dx3_prev", maxnpart }; } + + ux1 = array_t { label + "_ux1", maxnpart }; + ux2 = array_t { label + "_ux2", maxnpart }; + ux3 = array_t { label + "_ux3", maxnpart }; + + weight = array_t { label + "_w", maxnpart }; + + tag = array_t { label + "_tag", maxnpart }; + + if (npld > 0) { + pld = array_t { label + "_pld", maxnpart, npld }; + } + + if ((D == Dim::_2D) && (C != Coord::Cart)) { + phi = array_t { label + "_phi", maxnpart }; + } } template @@ -205,9 +193,10 @@ namespace ntt { RemoveDeadInArray(phi, indices_alive); } - for (auto& payload : pld) { - RemoveDeadInArray(payload, indices_alive); - } + // for (auto& payload : pld) { + // // @TODO_1.2.0: fix + // RemoveDeadInArray(payload, indices_alive); + // } Kokkos::Experimental::fill( "TagAliveParticles", @@ -226,35 +215,6 @@ namespace ntt { m_is_sorted = true; } - template - void Particles::SyncHostDevice() { - Kokkos::deep_copy(i1_h, i1); - Kokkos::deep_copy(dx1_h, dx1); - Kokkos::deep_copy(ux1_h, ux1); - Kokkos::deep_copy(ux2_h, ux2); - Kokkos::deep_copy(ux3_h, ux3); - - Kokkos::deep_copy(tag_h, tag); - Kokkos::deep_copy(weight_h, weight); - - for (auto n { 0 }; n < npld(); ++n) { - Kokkos::deep_copy(pld_h[n], pld[n]); - } - - if constexpr ((D == Dim::_2D) || (D == Dim::_3D)) { - Kokkos::deep_copy(i2_h, i2); - Kokkos::deep_copy(dx2_h, dx2); - } - if constexpr (D == Dim::_3D) { - Kokkos::deep_copy(i3_h, i3); - Kokkos::deep_copy(dx3_h, dx3); - } - - if ((D == Dim::_2D) && (C != Coord::Cart)) { - Kokkos::deep_copy(phi_h, phi); - } - } - template struct Particles; template struct Particles; template struct Particles; diff --git a/src/framework/containers/particles.h b/src/framework/containers/particles.h index 3ae68b402..9024fef1e 100644 --- a/src/framework/containers/particles.h +++ b/src/framework/containers/particles.h @@ -48,31 +48,22 @@ namespace ntt { public: // Cell indices of the current particle - array_t i1, i2, i3; + array_t i1, i2, i3; // Displacement of a particle within the cell - array_t dx1, dx2, dx3; + array_t dx1, dx2, dx3; // Three spatial components of the covariant 4-velocity (physical units) - array_t ux1, ux2, ux3; + array_t ux1, ux2, ux3; // Particle weights. - array_t weight; + array_t weight; // Previous timestep coordinates - array_t i1_prev, i2_prev, i3_prev; - array_t dx1_prev, dx2_prev, dx3_prev; + array_t i1_prev, i2_prev, i3_prev; + array_t dx1_prev, dx2_prev, dx3_prev; // Array to tag the particles - array_t tag; - // Array to store the particle load - std::vector> pld; + array_t tag; + // Array to store the particle payloads + array_t pld; // phi coordinate (for axisymmetry) - array_t phi; - - // host mirrors - array_mirror_t i1_h, i2_h, i3_h; - array_mirror_t dx1_h, dx2_h, dx3_h; - array_mirror_t ux1_h, ux2_h, ux3_h; - array_mirror_t weight_h; - array_mirror_t phi_h; - array_mirror_t tag_h; - std::vector> pld_h; + array_t phi; // for empty allocation Particles() {} @@ -178,10 +169,8 @@ namespace ntt { footprint += sizeof(prtldx_t) * dx2_prev.extent(0); footprint += sizeof(prtldx_t) * dx3_prev.extent(0); footprint += sizeof(short) * tag.extent(0); - for (auto& p : pld) { - footprint += sizeof(real_t) * p.extent(0); - } - footprint += sizeof(real_t) * phi.extent(0); + footprint += sizeof(real_t) * pld.extent(0) * pld.extent(1); + footprint += sizeof(real_t) * phi.extent(0); return footprint; } diff --git a/src/framework/domain/checkpoint.cpp b/src/framework/domain/checkpoint.cpp index 3d309c090..6dfb137db 100644 --- a/src/framework/domain/checkpoint.cpp +++ b/src/framework/domain/checkpoint.cpp @@ -242,13 +242,13 @@ namespace ntt { local_domain->species[s].weight); auto nplds = local_domain->species[s].npld(); - for (auto p { 0u }; p < nplds; ++p) { - g_checkpoint_writer.saveParticleQuantity( - fmt::format("s%d_pld%d", s + 1, p + 1), - glob_tot, - offset, - npart, - local_domain->species[s].pld[p]); + if (nplds > 0) { + g_checkpoint_writer.saveParticlePayloads(fmt::format("s%d_plds", s + 1), + nplds, + glob_tot, + offset, + npart, + local_domain->species[s].pld); } } } @@ -451,14 +451,16 @@ namespace ntt { domain.species[s].weight, loc_npart, offset_npart); - for (auto p { 0u }; p < domain.species[s].npld(); ++p) { - checkpoint::ReadParticleData(io, - reader, - fmt::format("pld%d", p + 1), - s, - domain.species[s].pld[p], - loc_npart, - offset_npart); + + const auto nplds = domain.species[s].npld(); + if (nplds > 0) { + checkpoint::ReadParticlePayloads(io, + reader, + s, + domain.species[s].pld, + nplds, + loc_npart, + offset_npart); } domain.species[s].set_npart(loc_npart); } // species loop diff --git a/src/framework/domain/comm_mpi.hpp b/src/framework/domain/comm_mpi.hpp index eb77ecbb3..4f6e04eec 100644 --- a/src/framework/domain/comm_mpi.hpp +++ b/src/framework/domain/comm_mpi.hpp @@ -17,6 +17,7 @@ #include "arch/directions.h" #include "arch/kokkos_aliases.h" #include "arch/mpi_aliases.h" +#include "arch/mpi_tags.h" #include "utils/error.h" #include "framework/containers/particles.h" diff --git a/src/framework/tests/particles.cpp b/src/framework/tests/particles.cpp index dabcc062f..535198286 100644 --- a/src/framework/tests/particles.cpp +++ b/src/framework/tests/particles.cpp @@ -46,10 +46,8 @@ void testParticles(const int& index, raise::ErrorIf(p.tag.extent(0) != maxnpart, "tag incorrectly allocated", HERE); raise::ErrorIf(p.weight.extent(0) != maxnpart, "weight incorrectly allocated", HERE); - raise::ErrorIf(p.pld.size() != npld, "Number of payloads mismatch", HERE); - for (unsigned short n { 0 }; n < npld; ++n) { - raise::ErrorIf(p.pld[n].extent(0) != maxnpart, "pld incorrectly allocated", HERE); - } + raise::ErrorIf(p.pld.extent(1) != npld, "pld incorrectly allocated", HERE); + raise::ErrorIf(p.pld.extent(0) != maxnpart, "pld incorrectly allocated", HERE); if constexpr ((D == Dim::_2D) || (D == Dim::_3D)) { raise::ErrorIf(p.i2.extent(0) != maxnpart, "i2 incorrectly allocated", HERE); @@ -139,4 +137,4 @@ auto main(int argc, char** argv) -> int { } Kokkos::finalize(); return 0; -} \ No newline at end of file +} diff --git a/src/global/arch/mpi_tags.h b/src/global/arch/mpi_tags.h index 0916542d4..aaf38a8f4 100644 --- a/src/global/arch/mpi_tags.h +++ b/src/global/arch/mpi_tags.h @@ -7,6 +7,8 @@ * @namespaces: * - mpi:: */ +#ifndef GLOBAL_ARCH_MPI_TAGS_H +#define GLOBAL_ARCH_MPI_TAGS_H #include "global.h" @@ -188,8 +190,13 @@ namespace mpi { tag; } - Inline auto SendTag(short tag, bool im1, bool ip1, bool jm1, bool jp1, bool km1, bool kp1) - -> short { + Inline auto SendTag(short tag, + bool im1, + bool ip1, + bool jm1, + bool jp1, + bool km1, + bool kp1) -> short { return ((im1 && jm1 && km1) * (PrtlSendTag::im1_jm1_km1 - 1) + (im1 && jm1 && kp1) * (PrtlSendTag::im1_jm1_kp1 - 1) + (im1 && jp1 && km1) * (PrtlSendTag::im1_jp1_km1 - 1) + @@ -226,3 +233,5 @@ namespace mpi { tag; } } // namespace mpi + +#endif // GLOBAL_ARCH_MPI_TAGS_H From ad026630c8814cff062683a9c6e27b693ac26e57 Mon Sep 17 00:00:00 2001 From: haykh Date: Thu, 23 Jan 2025 14:52:57 -0500 Subject: [PATCH 235/773] comm kernels --- src/framework/domain/comm_mpi.hpp | 145 ++++------- src/framework/domain/communications.cpp | 55 ++--- src/kernels/comm.hpp | 309 ++++++++++++++++++++++++ 3 files changed, 369 insertions(+), 140 deletions(-) create mode 100644 src/kernels/comm.hpp diff --git a/src/framework/domain/comm_mpi.hpp b/src/framework/domain/comm_mpi.hpp index 4f6e04eec..ff4984fa3 100644 --- a/src/framework/domain/comm_mpi.hpp +++ b/src/framework/domain/comm_mpi.hpp @@ -22,6 +22,8 @@ #include "framework/containers/particles.h" +#include "kernels/comm.hpp" + #include #include @@ -318,34 +320,14 @@ namespace comm { } template - void CommunicateParticles(Particles& species, - Kokkos::View outgoing_indices, - Kokkos::View tag_offsets, - std::vector npptag_vec, - std::vector npptag_recv_vec, - std::vector send_ranks, - std::vector recv_ranks, - const dir::dirs_t& dirs_to_comm) { - // Pointers to the particle data arrays - auto& this_i1 = species.i1; - auto& this_i1_prev = species.i1_prev; - auto& this_i2 = species.i2; - auto& this_i2_prev = species.i2_prev; - auto& this_i3 = species.i3; - auto& this_i3_prev = species.i3_prev; - auto& this_dx1 = species.dx1; - auto& this_dx1_prev = species.dx1_prev; - auto& this_dx2 = species.dx2; - auto& this_dx2_prev = species.dx2_prev; - auto& this_dx3 = species.dx3; - auto& this_dx3_prev = species.dx3_prev; - auto& this_phi = species.phi; - auto& this_ux1 = species.ux1; - auto& this_ux2 = species.ux2; - auto& this_ux3 = species.ux3; - auto& this_weight = species.weight; - auto& this_tag = species.tag; - + void CommunicateParticles(Particles& species, + array_t outgoing_indices, + array_t tag_offsets, + std::vector npptag_vec, + std::vector npptag_recv_vec, + std::vector send_ranks, + std::vector recv_ranks, + const dir::dirs_t& dirs_to_comm) { // @TODO_1.2.0: communicate payloads // number of arrays of each type to send/recv @@ -365,10 +347,9 @@ namespace comm { npptag_recv_vec.end(), static_cast(0)); - Kokkos::View recv_buff_int { "recv_buff_int", npart_recv * NINTS }; - Kokkos::View recv_buff_real { "recv_buff_real", npart_recv * NREALS }; - Kokkos::View recv_buff_prtldx { "recv_buff_prtldx", - npart_recv * NPRTLDX }; + array_t recv_buff_int { "recv_buff_int", npart_recv * NINTS }; + array_t recv_buff_real { "recv_buff_real", npart_recv * NREALS }; + array_t recv_buff_prtldx { "recv_buff_prtldx", npart_recv * NPRTLDX }; auto iteration = 0; auto current_received = 0; @@ -383,44 +364,26 @@ namespace comm { if (send_rank < 0 and recv_rank < 0) { continue; } - Kokkos::View send_buff_int { "send_buff_int", npart_send_in * NINTS }; - Kokkos::View send_buff_real { "send_buff_real", - npart_send_in * NREALS }; - Kokkos::View send_buff_prtldx { "send_buff_prtldx", - npart_send_in * NPRTLDX }; + array_t send_buff_int { "send_buff_int", npart_send_in * NINTS }; + array_t send_buff_real { "send_buff_real", npart_send_in * NREALS }; + array_t send_buff_prtldx { "send_buff_prtldx", + npart_send_in * NPRTLDX }; + // clang-format off Kokkos::parallel_for( "PopulateSendBuffer", npart_send_in, - Lambda(index_t p) { - const auto idx = outgoing_indices( - (tag_send > 2 ? tag_offsets(tag_send - 3) : 0) + npart_dead + p); - if constexpr (D == Dim::_1D or D == Dim::_2D or D == Dim::_3D) { - send_buff_int(NINTS * p + 0) = this_i1(idx); - send_buff_int(NINTS * p + 1) = this_i1_prev(idx); - send_buff_prtldx(NPRTLDX * p + 0) = this_dx1(idx); - send_buff_prtldx(NPRTLDX * p + 1) = this_dx1_prev(idx); - } - if constexpr (D == Dim::_2D or D == Dim::_3D) { - send_buff_int(NINTS * p + 2) = this_i2(idx); - send_buff_int(NINTS * p + 3) = this_i2_prev(idx); - send_buff_prtldx(NPRTLDX * p + 2) = this_dx2(idx); - send_buff_prtldx(NPRTLDX * p + 3) = this_dx2_prev(idx); - } - if constexpr (D == Dim::_3D) { - send_buff_int(NINTS * p + 4) = this_i3(idx); - send_buff_int(NINTS * p + 5) = this_i3_prev(idx); - send_buff_prtldx(NPRTLDX * p + 4) = this_dx3(idx); - send_buff_prtldx(NPRTLDX * p + 5) = this_dx3_prev(idx); - } - send_buff_real(NREALS * p + 0) = this_ux1(idx); - send_buff_real(NREALS * p + 1) = this_ux2(idx); - send_buff_real(NREALS * p + 2) = this_ux3(idx); - send_buff_real(NREALS * p + 3) = this_weight(idx); - if constexpr (D == Dim::_2D and C != Coord::Cart) { - send_buff_real(NREALS * p + 4) = this_phi(idx); - } - this_tag(idx) = ParticleTag::dead; - }); + kernel::comm::PopulatePrtlSendBuffer_kernel( + send_buff_int, send_buff_real, send_buff_prtldx, + NINTS, NREALS, NPRTLDX, + (tag_send > 2 ? tag_offsets(tag_send - 3) : 0) + npart_dead, + species.i1, species.i1_prev, species.dx1, species.dx1_prev, + species.i2, species.i2_prev, species.dx2, species.dx2_prev, + species.i3, species.i3_prev, species.dx3, species.dx3_prev, + species.ux1, species.ux2, species.ux3, + species.weight, species.phi, species.tag, + outgoing_indices, tag_offsets) + ); + // clang-format on const auto recv_offset_int = current_received * NINTS; const auto recv_offset_real = current_received * NREALS; @@ -519,43 +482,25 @@ namespace comm { } // end direction loop - const auto npart = species.npart(); - const auto npart_holes = outgoing_indices.extent(0); - + // clang-format off Kokkos::parallel_for( "PopulateFromRecvBuffer", npart_recv, - Lambda(const std::size_t p) { - const auto idx = (p >= npart_holes ? npart + p - npart_holes - : outgoing_indices(p)); - if constexpr (D == Dim::_1D or D == Dim::_2D or D == Dim::_3D) { - this_i1(idx) = recv_buff_int(NINTS * p + 0); - this_i1_prev(idx) = recv_buff_int(NINTS * p + 1); - this_dx1(idx) = recv_buff_prtldx(NPRTLDX * p + 0); - this_dx1_prev(idx) = recv_buff_prtldx(NPRTLDX * p + 1); - } - if constexpr (D == Dim::_2D or D == Dim::_3D) { - this_i2(idx) = recv_buff_int(NINTS * p + 2); - this_i2_prev(idx) = recv_buff_int(NINTS * p + 3); - this_dx2(idx) = recv_buff_prtldx(NPRTLDX * p + 2); - this_dx2_prev(idx) = recv_buff_prtldx(NPRTLDX * p + 3); - } - if constexpr (D == Dim::_3D) { - this_i3(idx) = recv_buff_int(NINTS * p + 4); - this_i3_prev(idx) = recv_buff_int(NINTS * p + 5); - this_dx3(idx) = recv_buff_prtldx(NPRTLDX * p + 4); - this_dx3_prev(idx) = recv_buff_prtldx(NPRTLDX * p + 5); - } - this_ux1(idx) = recv_buff_real(NREALS * p + 0); - this_ux2(idx) = recv_buff_real(NREALS * p + 1); - this_ux3(idx) = recv_buff_real(NREALS * p + 2); - this_weight(idx) = recv_buff_real(NREALS * p + 3); - if constexpr (D == Dim::_2D and C != Coord::Cart) { - this_phi(idx) = recv_buff_real(NREALS * p + 4); - } - this_tag(idx) = ParticleTag::alive; - }); + kernel::comm::ExtractReceivedPrtls_kernel( + recv_buff_int, recv_buff_real, recv_buff_prtldx, + NINTS, NREALS, NPRTLDX, + species.npart(), + species.i1, species.i1_prev, species.dx1, species.dx1_prev, + species.i2, species.i2_prev, species.dx2, species.dx2_prev, + species.i3, species.i3_prev, species.dx3, species.dx3_prev, + species.ux1, species.ux2, species.ux3, + species.weight, species.phi, species.tag, + outgoing_indices) + ); + // clang-format on + const auto npart = species.npart(); + const auto npart_holes = outgoing_indices.extent(0); if (npart_recv > npart_holes) { species.set_npart(npart + npart_recv - npart_holes); } diff --git a/src/framework/domain/communications.cpp b/src/framework/domain/communications.cpp index 6175cc4bb..fc065ab9d 100644 --- a/src/framework/domain/communications.cpp +++ b/src/framework/domain/communications.cpp @@ -20,6 +20,7 @@ #include "arch/mpi_tags.h" #include "framework/domain/comm_mpi.hpp" + #include "kernels/comm.hpp" #else #include "framework/domain/comm_nompi.hpp" #endif @@ -601,50 +602,24 @@ namespace ntt { } } // end directions loop - auto& this_tag = species.tag; - auto& this_i1 = species.i1; - auto& this_i1_prev = species.i1_prev; - auto& this_i2 = species.i2; - auto& this_i2_prev = species.i2_prev; - auto& this_i3 = species.i3; - auto& this_i3_prev = species.i3_prev; + array_t outgoing_indices { "outgoing_indices", + npart - npart_alive }; - array_t outgoing_indices("outgoing_indices", - npart - npart_alive); - - array_t current_offset("current_offset", ntags); + // clang-format off Kokkos::parallel_for( "OutgoingIndicesAndDisplace", species.rangeActiveParticles(), - Lambda(index_t p) { - if (this_tag(p) != ParticleTag::alive) { - // dead or to-be-sent - const auto idx_for_tag = - Kokkos::atomic_fetch_add(¤t_offset(this_tag(p)), 1) + - (this_tag(p) != ParticleTag::dead ? npart_dead : 0) + - (this_tag(p) > 2 ? tag_offsets(this_tag(p) - 3) : 0); - if (idx_for_tag >= npart - npart_alive) { - raise::KernelError(HERE, - "Outgoing indices idx exceeds the array size"); - } - outgoing_indices(idx_for_tag) = p; - // apply offsets - if (this_tag(p) != ParticleTag::dead) { - if constexpr (D == Dim::_1D or D == Dim::_2D or D == Dim::_3D) { - this_i1(p) += shifts_in_x1(this_tag(p) - 2); - this_i1_prev(p) += shifts_in_x1(this_tag(p) - 2); - } - if constexpr (D == Dim::_2D or D == Dim::_3D) { - this_i2(p) += shifts_in_x2(this_tag(p) - 2); - this_i2_prev(p) += shifts_in_x2(this_tag(p) - 2); - } - if constexpr (D == Dim::_3D) { - this_i3(p) += shifts_in_x3(this_tag(p) - 2); - this_i3_prev(p) += shifts_in_x3(this_tag(p) - 2); - } - } - } - }); + kernel::comm::PrepareOutgoingPrtls_kernel( + shifts_in_x1, shifts_in_x2, shifts_in_x3, + outgoing_indices, + npart, npart_alive, npart_dead, ntags, + species.i1, species.i1_prev, + species.i2, species.i2_prev, + species.i3, species.i3_prev, + species.tag, tag_offsets) + ); + // clang-format on + comm::CommunicateParticles(species, outgoing_indices, tag_offsets, diff --git a/src/kernels/comm.hpp b/src/kernels/comm.hpp new file mode 100644 index 000000000..c470cd4f6 --- /dev/null +++ b/src/kernels/comm.hpp @@ -0,0 +1,309 @@ +/** + * @file kernels/comm.hpp + * @brief Kernels used during communications + * @implements + * - kernel::comm::PrepareOutgoingPrtls_kernel<> + * - kernel::comm::PopulatePrtlSendBuffer_kernel<> + * - kernel::comm::ExtractReceivedPrtls_kernel<> + * @namespaces: + * - kernel::comm:: + */ + +#ifndef KERNELS_COMM_HPP +#define KERNELS_COMM_HPP + +#include "enums.h" +#include "global.h" + +#include "arch/kokkos_aliases.h" + +#include + +namespace kernel::comm { + using namespace ntt; + + template + class PrepareOutgoingPrtls_kernel { + const array_t shifts_in_x1, shifts_in_x2, shifts_in_x3; + array_t outgoing_indices; + + const std::size_t npart, npart_alive, npart_dead, ntags; + + array_t i1, i1_prev, i2, i2_prev, i3, i3_prev; + const array_t tag; + + const array_t tag_offsets; + + array_t current_offset; + + public: + PrepareOutgoingPrtls_kernel(const array_t& shifts_in_x1, + const array_t& shifts_in_x2, + const array_t& shifts_in_x3, + array_t& outgoing_indices, + std::size_t npart, + std::size_t npart_alive, + std::size_t npart_dead, + std::size_t ntags, + array_t& i1, + array_t& i1_prev, + array_t& i2, + array_t& i2_prev, + array_t& i3, + array_t& i3_prev, + const array_t& tag, + const array_t& tag_offsets) + : shifts_in_x1 { shifts_in_x1 } + , shifts_in_x2 { shifts_in_x2 } + , shifts_in_x3 { shifts_in_x3 } + , outgoing_indices { outgoing_indices } + , npart { npart } + , npart_alive { npart_alive } + , npart_dead { npart_dead } + , ntags { ntags } + , i1 { i1 } + , i1_prev { i1_prev } + , i2 { i2 } + , i2_prev { i2_prev } + , i3 { i3 } + , i3_prev { i3_prev } + , tag { tag } + , tag_offsets { tag_offsets } + , current_offset { "current_offset", ntags } {} + + Inline void operator()(index_t p) const { + if (tag(p) != ParticleTag::alive) { + // dead or to-be-sent + const auto idx_for_tag = Kokkos::atomic_fetch_add(¤t_offset(tag(p)), + 1) + + (tag(p) != ParticleTag::dead ? npart_dead : 0) + + (tag(p) > 2 ? tag_offsets(tag(p) - 3) : 0); + if (idx_for_tag >= npart - npart_alive) { + raise::KernelError(HERE, "Outgoing indices idx exceeds the array size"); + } + outgoing_indices(idx_for_tag) = p; + // apply offsets + if (tag(p) != ParticleTag::dead) { + if constexpr (D == Dim::_1D or D == Dim::_2D or D == Dim::_3D) { + i1(p) += shifts_in_x1(tag(p) - 2); + i1_prev(p) += shifts_in_x1(tag(p) - 2); + } + if constexpr (D == Dim::_2D or D == Dim::_3D) { + i2(p) += shifts_in_x2(tag(p) - 2); + i2_prev(p) += shifts_in_x2(tag(p) - 2); + } + if constexpr (D == Dim::_3D) { + i3(p) += shifts_in_x3(tag(p) - 2); + i3_prev(p) += shifts_in_x3(tag(p) - 2); + } + } + } + } + }; + + template + class PopulatePrtlSendBuffer_kernel { + array_t send_buff_int; + array_t send_buff_real; + array_t send_buff_prtldx; + + const unsigned short NINTS, NREALS, NPRTLDX; + const std::size_t idx_offset; + + const array_t i1, i1_prev, i2, i2_prev, i3, i3_prev; + const array_t ux1, ux2, ux3, weight, phi; + const array_t dx1, dx1_prev, dx2, dx2_prev, dx3, dx3_prev; + array_t tag; + const array_t outgoing_indices, tag_offsets; + + public: + PopulatePrtlSendBuffer_kernel(array_t& send_buff_int, + array_t& send_buff_real, + array_t& send_buff_prtldx, + unsigned short NINTS, + unsigned short NREALS, + unsigned short NPRTLDX, + std::size_t idx_offset, + const array_t& i1, + const array_t& i1_prev, + const array_t& dx1, + const array_t& dx1_prev, + const array_t& i2, + const array_t& i2_prev, + const array_t& dx2, + const array_t& dx2_prev, + const array_t& i3, + const array_t& i3_prev, + const array_t& dx3, + const array_t& dx3_prev, + const array_t& ux1, + const array_t& ux2, + const array_t& ux3, + const array_t& weight, + const array_t& phi, + array_t& tag, + const array_t& outgoing_indices, + const array_t& tag_offsets) + : send_buff_int { send_buff_int } + , send_buff_real { send_buff_real } + , send_buff_prtldx { send_buff_prtldx } + , NINTS { NINTS } + , NREALS { NREALS } + , NPRTLDX { NPRTLDX } + , idx_offset { idx_offset } + , i1 { i1 } + , i1_prev { i1_prev } + , dx1 { dx1 } + , dx1_prev { dx1_prev } + , i2 { i2 } + , i2_prev { i2_prev } + , dx2 { dx2 } + , dx2_prev { dx2_prev } + , i3 { i3 } + , i3_prev { i3_prev } + , dx3 { dx3 } + , dx3_prev { dx3_prev } + , ux1 { ux1 } + , ux2 { ux2 } + , ux3 { ux3 } + , weight { weight } + , phi { phi } + , tag { tag } + , outgoing_indices { outgoing_indices } + , tag_offsets { tag_offsets } {} + + Inline void operator()(index_t p) const { + const auto idx = outgoing_indices(idx_offset + p); + if constexpr (D == Dim::_1D or D == Dim::_2D or D == Dim::_3D) { + send_buff_int(NINTS * p + 0) = i1(idx); + send_buff_int(NINTS * p + 1) = i1_prev(idx); + send_buff_prtldx(NPRTLDX * p + 0) = dx1(idx); + send_buff_prtldx(NPRTLDX * p + 1) = dx1_prev(idx); + } + if constexpr (D == Dim::_2D or D == Dim::_3D) { + send_buff_int(NINTS * p + 2) = i2(idx); + send_buff_int(NINTS * p + 3) = i2_prev(idx); + send_buff_prtldx(NPRTLDX * p + 2) = dx2(idx); + send_buff_prtldx(NPRTLDX * p + 3) = dx2_prev(idx); + } + if constexpr (D == Dim::_3D) { + send_buff_int(NINTS * p + 4) = i3(idx); + send_buff_int(NINTS * p + 5) = i3_prev(idx); + send_buff_prtldx(NPRTLDX * p + 4) = dx3(idx); + send_buff_prtldx(NPRTLDX * p + 5) = dx3_prev(idx); + } + send_buff_real(NREALS * p + 0) = ux1(idx); + send_buff_real(NREALS * p + 1) = ux2(idx); + send_buff_real(NREALS * p + 2) = ux3(idx); + send_buff_real(NREALS * p + 3) = weight(idx); + if constexpr (D == Dim::_2D and C != Coord::Cart) { + send_buff_real(NREALS * p + 4) = phi(idx); + } + tag(idx) = ParticleTag::dead; + } + }; + + template + class ExtractReceivedPrtls_kernel { + const array_t recv_buff_int; + const array_t recv_buff_real; + const array_t recv_buff_prtldx; + + const unsigned short NINTS, NREALS, NPRTLDX; + const std::size_t npart, npart_holes; + + array_t i1, i1_prev, i2, i2_prev, i3, i3_prev; + array_t ux1, ux2, ux3, weight, phi; + array_t dx1, dx1_prev, dx2, dx2_prev, dx3, dx3_prev; + array_t tag; + const array_t outgoing_indices; + + public: + ExtractReceivedPrtls_kernel(const array_t& recv_buff_int, + const array_t& recv_buff_real, + const array_t& recv_buff_prtldx, + unsigned short NINTS, + unsigned short NREALS, + unsigned short NPRTLDX, + std::size_t npart, + array_t& i1, + array_t& i1_prev, + array_t& dx1, + array_t& dx1_prev, + array_t& i2, + array_t& i2_prev, + array_t& dx2, + array_t& dx2_prev, + array_t& i3, + array_t& i3_prev, + array_t& dx3, + array_t& dx3_prev, + array_t& ux1, + array_t& ux2, + array_t& ux3, + array_t& weight, + array_t& phi, + array_t& tag, + const array_t& outgoing_indices) + : recv_buff_int { recv_buff_int } + , recv_buff_real { recv_buff_real } + , recv_buff_prtldx { recv_buff_prtldx } + , NINTS { NINTS } + , NREALS { NREALS } + , NPRTLDX { NPRTLDX } + , npart { npart } + , npart_holes { outgoing_indices.extent(0) } + , i1 { i1 } + , i1_prev { i1_prev } + , dx1 { dx1 } + , dx1_prev { dx1_prev } + , i2 { i2 } + , i2_prev { i2_prev } + , dx2 { dx2 } + , dx2_prev { dx2_prev } + , i3 { i3 } + , i3_prev { i3_prev } + , dx3 { dx3 } + , dx3_prev { dx3_prev } + , ux1 { ux1 } + , ux2 { ux2 } + , ux3 { ux3 } + , weight { weight } + , phi { phi } + , tag { tag } {} + + Inline void operator()(index_t p) const { + const auto idx = (p >= npart_holes ? npart + p - npart_holes + : outgoing_indices(p)); + if constexpr (D == Dim::_1D or D == Dim::_2D or D == Dim::_3D) { + i1(idx) = recv_buff_int(NINTS * p + 0); + i1_prev(idx) = recv_buff_int(NINTS * p + 1); + dx1(idx) = recv_buff_prtldx(NPRTLDX * p + 0); + dx1_prev(idx) = recv_buff_prtldx(NPRTLDX * p + 1); + } + if constexpr (D == Dim::_2D or D == Dim::_3D) { + i2(idx) = recv_buff_int(NINTS * p + 2); + i2_prev(idx) = recv_buff_int(NINTS * p + 3); + dx2(idx) = recv_buff_prtldx(NPRTLDX * p + 2); + dx2_prev(idx) = recv_buff_prtldx(NPRTLDX * p + 3); + } + if constexpr (D == Dim::_3D) { + i3(idx) = recv_buff_int(NINTS * p + 4); + i3_prev(idx) = recv_buff_int(NINTS * p + 5); + dx3(idx) = recv_buff_prtldx(NPRTLDX * p + 4); + dx3_prev(idx) = recv_buff_prtldx(NPRTLDX * p + 5); + } + ux1(idx) = recv_buff_real(NREALS * p + 0); + ux2(idx) = recv_buff_real(NREALS * p + 1); + ux3(idx) = recv_buff_real(NREALS * p + 2); + weight(idx) = recv_buff_real(NREALS * p + 3); + if constexpr (D == Dim::_2D and C != Coord::Cart) { + phi(idx) = recv_buff_real(NREALS * p + 4); + } + tag(idx) = ParticleTag::alive; + } + }; + +} // namespace kernel::comm + +#endif // KERNELS_COMM_HPP From ea4366bc69ef3ca366368ead9c200b28b9d5c502 Mon Sep 17 00:00:00 2001 From: haykh Date: Thu, 23 Jan 2025 15:20:50 -0500 Subject: [PATCH 236/773] minor fix in tags --- src/framework/domain/comm_mpi.hpp | 2 +- src/kernels/comm.hpp | 21 ++++++++++++--------- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/src/framework/domain/comm_mpi.hpp b/src/framework/domain/comm_mpi.hpp index ff4984fa3..70c175972 100644 --- a/src/framework/domain/comm_mpi.hpp +++ b/src/framework/domain/comm_mpi.hpp @@ -381,7 +381,7 @@ namespace comm { species.i3, species.i3_prev, species.dx3, species.dx3_prev, species.ux1, species.ux2, species.ux3, species.weight, species.phi, species.tag, - outgoing_indices, tag_offsets) + outgoing_indices) ); // clang-format on diff --git a/src/kernels/comm.hpp b/src/kernels/comm.hpp index c470cd4f6..7446d285a 100644 --- a/src/kernels/comm.hpp +++ b/src/kernels/comm.hpp @@ -74,10 +74,15 @@ namespace kernel::comm { Inline void operator()(index_t p) const { if (tag(p) != ParticleTag::alive) { // dead or to-be-sent - const auto idx_for_tag = Kokkos::atomic_fetch_add(¤t_offset(tag(p)), - 1) + - (tag(p) != ParticleTag::dead ? npart_dead : 0) + - (tag(p) > 2 ? tag_offsets(tag(p) - 3) : 0); + auto idx_for_tag = Kokkos::atomic_fetch_add(¤t_offset(tag(p)), 1); + if (tag(p) != ParticleTag::dead) { + idx_for_tag += npart_dead; + } + if (tag(p) > 2) { + idx_for_tag += tag_offsets(tag(p) - 3); + } + // (tag(p) != ParticleTag::dead ? npart_dead : 0) + + // (tag(p) > 2 ? tag_offsets(tag(p) - 3) : 0); if (idx_for_tag >= npart - npart_alive) { raise::KernelError(HERE, "Outgoing indices idx exceeds the array size"); } @@ -114,7 +119,7 @@ namespace kernel::comm { const array_t ux1, ux2, ux3, weight, phi; const array_t dx1, dx1_prev, dx2, dx2_prev, dx3, dx3_prev; array_t tag; - const array_t outgoing_indices, tag_offsets; + const array_t outgoing_indices; public: PopulatePrtlSendBuffer_kernel(array_t& send_buff_int, @@ -142,8 +147,7 @@ namespace kernel::comm { const array_t& weight, const array_t& phi, array_t& tag, - const array_t& outgoing_indices, - const array_t& tag_offsets) + const array_t& outgoing_indices) : send_buff_int { send_buff_int } , send_buff_real { send_buff_real } , send_buff_prtldx { send_buff_prtldx } @@ -169,8 +173,7 @@ namespace kernel::comm { , weight { weight } , phi { phi } , tag { tag } - , outgoing_indices { outgoing_indices } - , tag_offsets { tag_offsets } {} + , outgoing_indices { outgoing_indices } {} Inline void operator()(index_t p) const { const auto idx = outgoing_indices(idx_offset + p); From 29ef300bd920a7f3e6285e6697f73105d7321416 Mon Sep 17 00:00:00 2001 From: haykh Date: Thu, 23 Jan 2025 15:44:41 -0500 Subject: [PATCH 237/773] proper tag_offsets access --- dev/nix/shell.nix | 2 +- src/framework/containers/particles.cpp | 13 +++++++------ src/framework/domain/comm_mpi.hpp | 8 ++++++-- 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/dev/nix/shell.nix b/dev/nix/shell.nix index 22358a837..f9d48fbfd 100644 --- a/dev/nix/shell.nix +++ b/dev/nix/shell.nix @@ -38,7 +38,7 @@ pkgs.mkShell { ++ (if hdf5 then (if mpi then [ pkgs.hdf5-mpi ] else [ pkgs.hdf5 ]) else [ ]); LD_LIBRARY_PATH = pkgs.lib.makeLibraryPath ([ - pkgs.clang19Stdenv.cc.cc + pkgs.stdenv.cc.cc pkgs.zlib ]); diff --git a/src/framework/containers/particles.cpp b/src/framework/containers/particles.cpp index fc8214824..235358760 100644 --- a/src/framework/containers/particles.cpp +++ b/src/framework/containers/particles.cpp @@ -97,15 +97,16 @@ namespace ntt { } // count the offsets on the host and copy to device - array_t tag_offset("tag_offset", num_tags - 3); - auto tag_offset_h = Kokkos::create_mirror_view(tag_offset); + array_t tag_offsets("tag_offsets", num_tags - 3); + auto tag_offsets_h = Kokkos::create_mirror_view(tag_offsets); - for (auto t { 0u }; t < num_tags - 3; ++t) { - tag_offset_h(t) = npptag_vec[t + 2] + (t > 0u ? tag_offset_h(t - 1) : 0); + tag_offsets_h(0) = npptag_vec[2]; + for (auto t { 1u }; t < num_tags - 3; ++t) { + tag_offsets_h(t) = npptag_vec[t + 2] + tag_offsets_h(t - 1); } - Kokkos::deep_copy(tag_offset, tag_offset_h); + Kokkos::deep_copy(tag_offsets, tag_offsets_h); - return { npptag_vec, tag_offset }; + return { npptag_vec, tag_offsets }; } template diff --git a/src/framework/domain/comm_mpi.hpp b/src/framework/domain/comm_mpi.hpp index 70c175972..68248db13 100644 --- a/src/framework/domain/comm_mpi.hpp +++ b/src/framework/domain/comm_mpi.hpp @@ -368,14 +368,18 @@ namespace comm { array_t send_buff_real { "send_buff_real", npart_send_in * NREALS }; array_t send_buff_prtldx { "send_buff_prtldx", npart_send_in * NPRTLDX }; + + std::size_t idx_offset = npart_dead; + if (tag_send > 2) { + idx_offset += tag_offsets(tag_send - 3); + } // clang-format off Kokkos::parallel_for( "PopulateSendBuffer", npart_send_in, kernel::comm::PopulatePrtlSendBuffer_kernel( send_buff_int, send_buff_real, send_buff_prtldx, - NINTS, NREALS, NPRTLDX, - (tag_send > 2 ? tag_offsets(tag_send - 3) : 0) + npart_dead, + NINTS, NREALS, NPRTLDX, idx_offset, species.i1, species.i1_prev, species.dx1, species.dx1_prev, species.i2, species.i2_prev, species.dx2, species.dx2_prev, species.i3, species.i3_prev, species.dx3, species.dx3_prev, From 3c8536392f38325df4338509b5ebb7838a884cc2 Mon Sep 17 00:00:00 2001 From: haykh Date: Thu, 23 Jan 2025 17:39:41 -0500 Subject: [PATCH 238/773] minor --- src/framework/domain/comm_mpi.hpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/framework/domain/comm_mpi.hpp b/src/framework/domain/comm_mpi.hpp index 68248db13..24f17015f 100644 --- a/src/framework/domain/comm_mpi.hpp +++ b/src/framework/domain/comm_mpi.hpp @@ -320,14 +320,14 @@ namespace comm { } template - void CommunicateParticles(Particles& species, - array_t outgoing_indices, - array_t tag_offsets, - std::vector npptag_vec, - std::vector npptag_recv_vec, - std::vector send_ranks, - std::vector recv_ranks, - const dir::dirs_t& dirs_to_comm) { + void CommunicateParticles(Particles& species, + const array_t& outgoing_indices, + const array_t& tag_offsets, + const std::vector& npptag_vec, + const std::vector& npptag_recv_vec, + const std::vector& send_ranks, + const std::vector& recv_ranks, + const dir::dirs_t& dirs_to_comm) { // @TODO_1.2.0: communicate payloads // number of arrays of each type to send/recv From d376b6e6fb84b795dd1b94a58f0da41e715d4be7 Mon Sep 17 00:00:00 2001 From: hayk Date: Thu, 23 Jan 2025 17:54:38 -0500 Subject: [PATCH 239/773] minor bug: tag access --- src/framework/domain/comm_mpi.hpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/framework/domain/comm_mpi.hpp b/src/framework/domain/comm_mpi.hpp index 24f17015f..f001738cf 100644 --- a/src/framework/domain/comm_mpi.hpp +++ b/src/framework/domain/comm_mpi.hpp @@ -369,9 +369,12 @@ namespace comm { array_t send_buff_prtldx { "send_buff_prtldx", npart_send_in * NPRTLDX }; + auto tag_offsets_h = Kokkos::create_mirror_view(tag_offsets); + Kokkos::deep_copy(tag_offsets_h, tag_offsets); + std::size_t idx_offset = npart_dead; if (tag_send > 2) { - idx_offset += tag_offsets(tag_send - 3); + idx_offset += tag_offsets_h(tag_send - 3); } // clang-format off Kokkos::parallel_for( From f7ec06e55f202efb0c11c21eb3c3bd809e9e2329 Mon Sep 17 00:00:00 2001 From: haykh Date: Thu, 23 Jan 2025 19:38:03 -0500 Subject: [PATCH 240/773] inline if patched --- extern/Kokkos | 2 +- extern/adios2 | 2 +- extern/plog | 2 +- src/kernels/comm.hpp | 8 ++++++-- 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/extern/Kokkos b/extern/Kokkos index eb11070f6..abaec2e5d 160000 --- a/extern/Kokkos +++ b/extern/Kokkos @@ -1 +1 @@ -Subproject commit eb11070f67565b2e660659f5207f0363bdf3b882 +Subproject commit abaec2e5da1e15e367e48d2a3aa649770e8bcc72 diff --git a/extern/adios2 b/extern/adios2 index f80ad829d..b574cc9c2 160000 --- a/extern/adios2 +++ b/extern/adios2 @@ -1 +1 @@ -Subproject commit f80ad829d751241140c40923503e1888e27e22e1 +Subproject commit b574cc9c29b19448ed9f279c4966c97740328441 diff --git a/extern/plog b/extern/plog index 85a871b13..94899e0b9 160000 --- a/extern/plog +++ b/extern/plog @@ -1 +1 @@ -Subproject commit 85a871b13be0bd1a9e0110744fa60cc9bd1e8380 +Subproject commit 94899e0b926ac1b0f4750bfbd495167b4a6ae9ef diff --git a/src/kernels/comm.hpp b/src/kernels/comm.hpp index 7446d285a..a24ee897e 100644 --- a/src/kernels/comm.hpp +++ b/src/kernels/comm.hpp @@ -276,8 +276,12 @@ namespace kernel::comm { , tag { tag } {} Inline void operator()(index_t p) const { - const auto idx = (p >= npart_holes ? npart + p - npart_holes - : outgoing_indices(p)); + std::size_t idx; + if (p >= npart_holes) { + idx = npart + p - npart_holes; + } else { + idx = outgoing_indices(p); + } if constexpr (D == Dim::_1D or D == Dim::_2D or D == Dim::_3D) { i1(idx) = recv_buff_int(NINTS * p + 0); i1_prev(idx) = recv_buff_int(NINTS * p + 1); From fed4e62803ada0d808ba012d1772b37425a3c546 Mon Sep 17 00:00:00 2001 From: hayk Date: Fri, 24 Jan 2025 13:28:12 -0500 Subject: [PATCH 241/773] bug on gpus fixed --- setups/srpic/blob/pgen.hpp | 49 ++++++++-------- src/framework/containers/particles.cpp | 63 ++++++++++++++++++++- src/framework/containers/particles.h | 2 + src/framework/domain/comm_mpi.hpp | 75 +++++++++++++------------ src/framework/domain/communications.cpp | 43 +++++++------- src/kernels/comm.hpp | 8 ++- 6 files changed, 153 insertions(+), 87 deletions(-) diff --git a/setups/srpic/blob/pgen.hpp b/setups/srpic/blob/pgen.hpp index 38b3db1c5..f7b7d71b5 100644 --- a/setups/srpic/blob/pgen.hpp +++ b/setups/srpic/blob/pgen.hpp @@ -21,17 +21,17 @@ namespace user { CounterstreamEnergyDist(const M& metric, real_t v_max) : arch::EnergyDistribution { metric } , v_max { v_max } {} - + Inline void operator()(const coord_t& x_Ph, vec_t& v, unsigned short sp) const override { v[0] = v_max; } - + private: const real_t v_max; }; - + template struct GaussianDist : public arch::SpatialDistribution { GaussianDist(const M& metric, real_t x1c, real_t x2c, real_t dr) @@ -39,20 +39,20 @@ namespace user { , x1c { x1c } , x2c { x2c } , dr { dr } {} - + // to properly scale the number density, the probability should be normalized to 1 Inline auto operator()(const coord_t& x_Ph) const -> real_t override { - if (math::abs(x_Ph[0] - x1c) < dr && math::abs(x_Ph[1] - x2c) < dr){ - return 1.0; - }else{ - return 0.0; - } + if (math::abs(x_Ph[0] - x1c) < dr && math::abs(x_Ph[1] - x2c) < dr) { + return 1.0; + } else { + return 0.0; + } } private: const real_t x1c, x2c, dr; }; - + template struct PGen : public arch::ProblemGenerator { @@ -78,24 +78,23 @@ namespace user { , dr { p.template get("setup.dr") } {} inline void InitPrtls(Domain& local_domain) { - const auto energy_dist = CounterstreamEnergyDist( - local_domain.mesh.metric, - v_max); + const auto energy_dist = CounterstreamEnergyDist(local_domain.mesh.metric, + v_max); const auto spatial_dist = GaussianDist(local_domain.mesh.metric, - x1c, - x2c, - dr); - const auto injector = - arch::NonUniformInjector( - energy_dist, - spatial_dist, - { 1, 2 }); + x1c, + x2c, + dr); + const auto injector = + arch::NonUniformInjector( + energy_dist, + spatial_dist, + { 1, 2 }); arch::InjectNonUniform>( - params, - local_domain, - injector, - 1.0); + params, + local_domain, + injector, + 1.0); } }; diff --git a/src/framework/containers/particles.cpp b/src/framework/containers/particles.cpp index 235358760..d2eed1b81 100644 --- a/src/framework/containers/particles.cpp +++ b/src/framework/containers/particles.cpp @@ -4,6 +4,7 @@ #include "global.h" #include "arch/kokkos_aliases.h" +#include "utils/numeric.h" #include "utils/sorting.h" #include "framework/containers/species.h" @@ -12,6 +13,8 @@ #include #include +#include +#include #include #include #include @@ -72,7 +75,7 @@ namespace ntt { -> std::pair, array_t> { auto this_tag = tag; const auto num_tags = ntags(); - array_t npptag("nparts_per_tag", ntags()); + array_t npptag { "nparts_per_tag", ntags() }; // count # of particles per each tag auto npptag_scat = Kokkos::Experimental::create_scatter_view(npptag); @@ -100,7 +103,7 @@ namespace ntt { array_t tag_offsets("tag_offsets", num_tags - 3); auto tag_offsets_h = Kokkos::create_mirror_view(tag_offsets); - tag_offsets_h(0) = npptag_vec[2]; + tag_offsets_h(0) = npptag_vec[2]; // offset for tag = 3 for (auto t { 1u }; t < num_tags - 3; ++t) { tag_offsets_h(t) = npptag_vec[t + 2] + tag_offsets_h(t - 1); } @@ -133,7 +136,7 @@ namespace ntt { Kokkos::parallel_reduce( "CountDeadAlive", rangeActiveParticles(), - Lambda(index_t p, std::size_t & nalive, std::size_t & ndead) { + Lambda(index_t p, std::size_t& nalive, std::size_t& ndead) { nalive += (this_tag(p) == ParticleTag::alive); ndead += (this_tag(p) == ParticleTag::dead); if (this_tag(p) != ParticleTag::alive and this_tag(p) != ParticleTag::dead) { @@ -216,6 +219,60 @@ namespace ntt { m_is_sorted = true; } + // template + // void Particles::PrintTags() { + // auto tag_h = Kokkos::create_mirror_view(tag); + // Kokkos::deep_copy(tag_h, tag); + // auto i1_h = Kokkos::create_mirror_view(i1); + // Kokkos::deep_copy(i1_h, i1); + // auto dx1_h = Kokkos::create_mirror_view(dx1); + // Kokkos::deep_copy(dx1_h, dx1); + // std::cout << "species " << label() << " [npart = " << npart() << "]" + // << std::endl; + // std::cout << "idxs: "; + // for (auto i = 0; i < IMIN(tag_h.extent(0), 30); ++i) { + // std::cout << std::setw(3) << i << " "; + // if (i == npart() - 1) { + // std::cout << "| "; + // } + // } + // if (tag_h.extent(0) > 30) { + // std::cout << "... " << std::setw(3) << tag_h.extent(0) - 1; + // } + // std::cout << std::endl << "tags: "; + // for (auto i = 0; i < IMIN(tag_h.extent(0), 30); ++i) { + // std::cout << std::setw(3) << (short)tag_h(i) << " "; + // if (i == npart() - 1) { + // std::cout << "| "; + // } + // } + // if (tag_h.extent(0) > 30) { + // std::cout << "..." << std::setw(3) << (short)tag_h(tag_h.extent(0) - 1); + // } + // std::cout << std::endl << "i1s : "; + // for (auto i = 0; i < IMIN(i1_h.extent(0), 30); ++i) { + // std::cout << std::setw(3) << i1_h(i) << " "; + // if (i == npart() - 1) { + // std::cout << "| "; + // } + // } + // if (i1_h.extent(0) > 30) { + // std::cout << "..." << std::setw(3) << i1_h(i1_h.extent(0) - 1); + // } + // std::cout << std::endl << "dx1s : "; + // for (auto i = 0; i < IMIN(dx1_h.extent(0), 30); ++i) { + // std::cout << std::setprecision(2) << std::setw(3) << dx1_h(i) << " "; + // if (i == npart() - 1) { + // std::cout << "| "; + // } + // } + // if (dx1_h.extent(0) > 30) { + // std::cout << "..." << std::setprecision(2) << std::setw(3) + // << dx1_h(dx1_h.extent(0) - 1); + // } + // std::cout << std::endl; + // } + template struct Particles; template struct Particles; template struct Particles; diff --git a/src/framework/containers/particles.h b/src/framework/containers/particles.h index 9024fef1e..d84bd0cc9 100644 --- a/src/framework/containers/particles.h +++ b/src/framework/containers/particles.h @@ -219,6 +219,8 @@ namespace ntt { * @brief Copy particle data from device to host. */ void SyncHostDevice(); + + // void PrintTags(); }; } // namespace ntt diff --git a/src/framework/domain/comm_mpi.hpp b/src/framework/domain/comm_mpi.hpp index f001738cf..b477e47f7 100644 --- a/src/framework/domain/comm_mpi.hpp +++ b/src/framework/domain/comm_mpi.hpp @@ -340,13 +340,12 @@ namespace comm { MPI_Comm_rank(MPI_COMM_WORLD, &rank); // buffers to store recv data - const auto npart_alive = npptag_vec[ParticleTag::alive]; - const auto npart_dead = npptag_vec[ParticleTag::dead]; - const auto npart_send = outgoing_indices.extent(0) - npart_dead; - const auto npart_recv = std::accumulate(npptag_recv_vec.begin(), + const auto npart_alive = npptag_vec[ParticleTag::alive]; + const auto npart_dead = npptag_vec[ParticleTag::dead]; + const auto npart_send = outgoing_indices.extent(0) - npart_dead; + const auto npart_recv = std::accumulate(npptag_recv_vec.begin(), npptag_recv_vec.end(), static_cast(0)); - array_t recv_buff_int { "recv_buff_int", npart_recv * NINTS }; array_t recv_buff_real { "recv_buff_real", npart_recv * NREALS }; array_t recv_buff_prtldx { "recv_buff_prtldx", npart_recv * NPRTLDX }; @@ -376,21 +375,23 @@ namespace comm { if (tag_send > 2) { idx_offset += tag_offsets_h(tag_send - 3); } - // clang-format off - Kokkos::parallel_for( - "PopulateSendBuffer", - npart_send_in, - kernel::comm::PopulatePrtlSendBuffer_kernel( - send_buff_int, send_buff_real, send_buff_prtldx, - NINTS, NREALS, NPRTLDX, idx_offset, - species.i1, species.i1_prev, species.dx1, species.dx1_prev, - species.i2, species.i2_prev, species.dx2, species.dx2_prev, - species.i3, species.i3_prev, species.dx3, species.dx3_prev, - species.ux1, species.ux2, species.ux3, - species.weight, species.phi, species.tag, - outgoing_indices) - ); - // clang-format on + if (npart_send_in > 0) { + // clang-format off + Kokkos::parallel_for( + "PopulatePrtlSendBuffer", + npart_send_in, + kernel::comm::PopulatePrtlSendBuffer_kernel( + send_buff_int, send_buff_real, send_buff_prtldx, + NINTS, NREALS, NPRTLDX, idx_offset, + species.i1, species.i1_prev, species.dx1, species.dx1_prev, + species.i2, species.i2_prev, species.dx2, species.dx2_prev, + species.i3, species.i3_prev, species.dx3, species.dx3_prev, + species.ux1, species.ux2, species.ux3, + species.weight, species.phi, species.tag, + outgoing_indices) + ); + // clang-format on + } const auto recv_offset_int = current_received * NINTS; const auto recv_offset_real = current_received * NREALS; @@ -489,22 +490,24 @@ namespace comm { } // end direction loop - // clang-format off - Kokkos::parallel_for( - "PopulateFromRecvBuffer", - npart_recv, - kernel::comm::ExtractReceivedPrtls_kernel( - recv_buff_int, recv_buff_real, recv_buff_prtldx, - NINTS, NREALS, NPRTLDX, - species.npart(), - species.i1, species.i1_prev, species.dx1, species.dx1_prev, - species.i2, species.i2_prev, species.dx2, species.dx2_prev, - species.i3, species.i3_prev, species.dx3, species.dx3_prev, - species.ux1, species.ux2, species.ux3, - species.weight, species.phi, species.tag, - outgoing_indices) - ); - // clang-format on + if (npart_recv > 0) { + // clang-format off + Kokkos::parallel_for( + "ExtractReceivedPrtls", + npart_recv, + kernel::comm::ExtractReceivedPrtls_kernel( + recv_buff_int, recv_buff_real, recv_buff_prtldx, + NINTS, NREALS, NPRTLDX, + species.npart(), species.maxnpart(), + species.i1, species.i1_prev, species.dx1, species.dx1_prev, + species.i2, species.i2_prev, species.dx2, species.dx2_prev, + species.i3, species.i3_prev, species.dx3, species.dx3_prev, + species.ux1, species.ux2, species.ux3, + species.weight, species.phi, species.tag, + outgoing_indices) + ); + // clang-format on + } const auto npart = species.npart(); const auto npart_holes = outgoing_indices.extent(0); diff --git a/src/framework/domain/communications.cpp b/src/framework/domain/communications.cpp index fc065ab9d..7dc5d285a 100644 --- a/src/framework/domain/communications.cpp +++ b/src/framework/domain/communications.cpp @@ -36,10 +36,10 @@ namespace ntt { using comm_params_t = std::pair>; template - auto GetSendRecvRanks( - Metadomain* metadomain, - Domain& domain, - dir::direction_t direction) -> std::pair { + auto GetSendRecvRanks(Metadomain* metadomain, + Domain& domain, + dir::direction_t direction) + -> std::pair { Domain* send_to_nghbr_ptr = nullptr; Domain* recv_from_nghbr_ptr = nullptr; // set pointers to the correct send/recv domains @@ -119,11 +119,11 @@ namespace ntt { } template - auto GetSendRecvParams( - Metadomain* metadomain, - Domain& domain, - dir::direction_t direction, - bool synchronize) -> std::pair { + auto GetSendRecvParams(Metadomain* metadomain, + Domain& domain, + dir::direction_t direction, + bool synchronize) + -> std::pair { const auto [send_indrank, recv_indrank] = GetSendRecvRanks(metadomain, domain, direction); const auto [send_ind, send_rank] = send_indrank; @@ -512,11 +512,15 @@ namespace ntt { // # of particles to receive per each tag (direction) std::vector npptag_recv_vec(ntags - 2, 0); // coordinate shifts per each direction - array_t shifts_in_x1("shifts_in_x1", ntags - 2); - array_t shifts_in_x2("shifts_in_x2", ntags - 2); - array_t shifts_in_x3("shifts_in_x3", ntags - 2); + array_t shifts_in_x1 { "shifts_in_x1", ntags - 2 }; + array_t shifts_in_x2 { "shifts_in_x2", ntags - 2 }; + array_t shifts_in_x3 { "shifts_in_x3", ntags - 2 }; + auto shifts_in_x1_h = Kokkos::create_mirror_view(shifts_in_x1); + auto shifts_in_x2_h = Kokkos::create_mirror_view(shifts_in_x2); + auto shifts_in_x3_h = Kokkos::create_mirror_view(shifts_in_x3); + // all directions requiring communication - dir::dirs_t dirs_to_comm; + dir::dirs_t dirs_to_comm; // ranks & indices of meshblock to send/recv from std::vector send_ranks, send_inds; @@ -568,7 +572,6 @@ namespace ntt { // ... tag_send - 2: because we only shift tags > 2 (i.e. no dead/alive) if (is_sending) { if constexpr (D == Dim::_1D || D == Dim::_2D || D == Dim::_3D) { - auto shifts_in_x1_h = Kokkos::create_mirror_view(shifts_in_x1); if (direction[0] == -1) { // sending backwards in x1 (add sx1 of target meshblock) shifts_in_x1_h(tag_send - 2) = subdomain(send_ind).mesh.n_active( @@ -577,37 +580,35 @@ namespace ntt { // sending forward in x1 (subtract sx1 of source meshblock) shifts_in_x1_h(tag_send - 2) = -domain.mesh.n_active(in::x1); } - Kokkos::deep_copy(shifts_in_x1, shifts_in_x1_h); } if constexpr (D == Dim::_2D || D == Dim::_3D) { - auto shifts_in_x2_h = Kokkos::create_mirror_view(shifts_in_x2); if (direction[1] == -1) { shifts_in_x2_h(tag_send - 2) = subdomain(send_ind).mesh.n_active( in::x2); } else if (direction[1] == 1) { shifts_in_x2_h(tag_send - 2) = -domain.mesh.n_active(in::x2); } - Kokkos::deep_copy(shifts_in_x2, shifts_in_x2_h); } if constexpr (D == Dim::_3D) { - auto shifts_in_x3_h = Kokkos::create_mirror_view(shifts_in_x3); if (direction[2] == -1) { shifts_in_x3_h(tag_send - 2) = subdomain(send_ind).mesh.n_active( in::x3); } else if (direction[2] == 1) { shifts_in_x3_h(tag_send - 2) = -domain.mesh.n_active(in::x3); } - Kokkos::deep_copy(shifts_in_x3, shifts_in_x3_h); } } } // end directions loop + Kokkos::deep_copy(shifts_in_x1, shifts_in_x1_h); + Kokkos::deep_copy(shifts_in_x2, shifts_in_x2_h); + Kokkos::deep_copy(shifts_in_x3, shifts_in_x3_h); + array_t outgoing_indices { "outgoing_indices", npart - npart_alive }; - // clang-format off Kokkos::parallel_for( - "OutgoingIndicesAndDisplace", + "PrepareOutgoingPrtls", species.rangeActiveParticles(), kernel::comm::PrepareOutgoingPrtls_kernel( shifts_in_x1, shifts_in_x2, shifts_in_x3, diff --git a/src/kernels/comm.hpp b/src/kernels/comm.hpp index a24ee897e..eea79b08b 100644 --- a/src/kernels/comm.hpp +++ b/src/kernels/comm.hpp @@ -81,8 +81,6 @@ namespace kernel::comm { if (tag(p) > 2) { idx_for_tag += tag_offsets(tag(p) - 3); } - // (tag(p) != ParticleTag::dead ? npart_dead : 0) + - // (tag(p) > 2 ? tag_offsets(tag(p) - 3) : 0); if (idx_for_tag >= npart - npart_alive) { raise::KernelError(HERE, "Outgoing indices idx exceeds the array size"); } @@ -214,6 +212,7 @@ namespace kernel::comm { const unsigned short NINTS, NREALS, NPRTLDX; const std::size_t npart, npart_holes; + const std::size_t maxnpart; array_t i1, i1_prev, i2, i2_prev, i3, i3_prev; array_t ux1, ux2, ux3, weight, phi; @@ -229,6 +228,7 @@ namespace kernel::comm { unsigned short NREALS, unsigned short NPRTLDX, std::size_t npart, + std::size_t maxnpart, array_t& i1, array_t& i1_prev, array_t& dx1, @@ -255,6 +255,7 @@ namespace kernel::comm { , NREALS { NREALS } , NPRTLDX { NPRTLDX } , npart { npart } + , maxnpart { maxnpart } , npart_holes { outgoing_indices.extent(0) } , i1 { i1 } , i1_prev { i1_prev } @@ -282,6 +283,9 @@ namespace kernel::comm { } else { idx = outgoing_indices(p); } + if (idx >= maxnpart) { + raise::KernelError(HERE, "Received particle index exceeds the array size"); + } if constexpr (D == Dim::_1D or D == Dim::_2D or D == Dim::_3D) { i1(idx) = recv_buff_int(NINTS * p + 0); i1_prev(idx) = recv_buff_int(NINTS * p + 1); From 7388d8e7f805910b1ec53c2f829ecd7aeb9a4e9d Mon Sep 17 00:00:00 2001 From: haykh Date: Fri, 24 Jan 2025 16:28:48 -0500 Subject: [PATCH 242/773] pld comm --- src/framework/domain/comm_mpi.hpp | 57 ++++++++++++++++++++++++++----- src/kernels/comm.hpp | 45 +++++++++++++++++------- 2 files changed, 81 insertions(+), 21 deletions(-) diff --git a/src/framework/domain/comm_mpi.hpp b/src/framework/domain/comm_mpi.hpp index f001738cf..dec321883 100644 --- a/src/framework/domain/comm_mpi.hpp +++ b/src/framework/domain/comm_mpi.hpp @@ -335,9 +335,7 @@ namespace comm { D == Dim::_2D and C != Coord::Cart); const unsigned short NINTS = 2 * static_cast(D); const unsigned short NPRTLDX = 2 * static_cast(D); - const unsigned short NPLD = species.npld(); - int rank; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); + const unsigned short NPLDS = species.npld(); // buffers to store recv data const auto npart_alive = npptag_vec[ParticleTag::alive]; @@ -350,6 +348,11 @@ namespace comm { array_t recv_buff_int { "recv_buff_int", npart_recv * NINTS }; array_t recv_buff_real { "recv_buff_real", npart_recv * NREALS }; array_t recv_buff_prtldx { "recv_buff_prtldx", npart_recv * NPRTLDX }; + array_t recv_buff_pld; + + if (NPLDS > 0) { + recv_buff_pld = array_t { "recv_buff_pld", npart_recv * NPLDS }; + } auto iteration = 0; auto current_received = 0; @@ -368,6 +371,10 @@ namespace comm { array_t send_buff_real { "send_buff_real", npart_send_in * NREALS }; array_t send_buff_prtldx { "send_buff_prtldx", npart_send_in * NPRTLDX }; + array_t send_buff_pld; + if (NPLDS > 0) { + send_buff_pld = array_t { "send_buff_pld", npart_send_in * NPLDS }; + } auto tag_offsets_h = Kokkos::create_mirror_view(tag_offsets); Kokkos::deep_copy(tag_offsets_h, tag_offsets); @@ -381,13 +388,13 @@ namespace comm { "PopulateSendBuffer", npart_send_in, kernel::comm::PopulatePrtlSendBuffer_kernel( - send_buff_int, send_buff_real, send_buff_prtldx, - NINTS, NREALS, NPRTLDX, idx_offset, + send_buff_int, send_buff_real, send_buff_prtldx, send_buff_pld, + NINTS, NREALS, NPRTLDX, NPLDS, idx_offset, species.i1, species.i1_prev, species.dx1, species.dx1_prev, species.i2, species.i2_prev, species.dx2, species.dx2_prev, species.i3, species.i3_prev, species.dx3, species.dx3_prev, species.ux1, species.ux2, species.ux3, - species.weight, species.phi, species.tag, + species.weight, species.phi, species.pld, species.tag, outgoing_indices) ); // clang-format on @@ -395,6 +402,7 @@ namespace comm { const auto recv_offset_int = current_received * NINTS; const auto recv_offset_real = current_received * NREALS; const auto recv_offset_prtldx = current_received * NPRTLDX; + const auto recv_offset_pld = current_received * NPLDS; if ((send_rank >= 0) and (recv_rank >= 0) and (npart_send_in > 0) and (npart_recv_in > 0)) { @@ -438,6 +446,20 @@ namespace comm { 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + if (NPLDS > 0) { + MPI_Sendrecv(send_buff_pld.data(), + npart_send_in * NPLDS, + mpi::get_type(), + send_rank, + 0, + recv_buff_pld.data() + recv_offset_pld, + npart_recv_in * NPLDS, + mpi::get_type(), + recv_rank, + 0, + MPI_COMM_WORLD, + MPI_STATUS_IGNORE); + } } else if ((send_rank >= 0) and (npart_send_in > 0)) { MPI_Send(send_buff_int.data(), npart_send_in * NINTS, @@ -457,6 +479,14 @@ namespace comm { send_rank, 0, MPI_COMM_WORLD); + if (NPLDS > 0) { + MPI_Send(send_buff_pld.data(), + npart_send_in * NPLDS, + mpi::get_type(), + send_rank, + 0, + MPI_COMM_WORLD); + } } else if ((recv_rank >= 0) and (npart_recv_in > 0)) { raise::ErrorIf(recv_offset_int + npart_recv_in * NINTS > recv_buff_int.extent(0), @@ -483,6 +513,15 @@ namespace comm { 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + if (NPLDS > 0) { + MPI_Recv(recv_buff_pld.data() + recv_offset_pld, + npart_recv_in * NPLDS, + mpi::get_type(), + recv_rank, + 0, + MPI_COMM_WORLD, + MPI_STATUS_IGNORE); + } } current_received += npart_recv_in; iteration++; @@ -494,14 +533,14 @@ namespace comm { "PopulateFromRecvBuffer", npart_recv, kernel::comm::ExtractReceivedPrtls_kernel( - recv_buff_int, recv_buff_real, recv_buff_prtldx, - NINTS, NREALS, NPRTLDX, + recv_buff_int, recv_buff_real, recv_buff_prtldx, recv_buff_pld, + NINTS, NREALS, NPRTLDX, NPLDS, species.npart(), species.i1, species.i1_prev, species.dx1, species.dx1_prev, species.i2, species.i2_prev, species.dx2, species.dx2_prev, species.i3, species.i3_prev, species.dx3, species.dx3_prev, species.ux1, species.ux2, species.ux3, - species.weight, species.phi, species.tag, + species.weight, species.phi, species.pld, species.tag, outgoing_indices) ); // clang-format on diff --git a/src/kernels/comm.hpp b/src/kernels/comm.hpp index a24ee897e..e8fe96fb0 100644 --- a/src/kernels/comm.hpp +++ b/src/kernels/comm.hpp @@ -111,13 +111,15 @@ namespace kernel::comm { array_t send_buff_int; array_t send_buff_real; array_t send_buff_prtldx; + array_t send_buff_pld; - const unsigned short NINTS, NREALS, NPRTLDX; + const unsigned short NINTS, NREALS, NPRTLDX, NPLDS; const std::size_t idx_offset; const array_t i1, i1_prev, i2, i2_prev, i3, i3_prev; - const array_t ux1, ux2, ux3, weight, phi; const array_t dx1, dx1_prev, dx2, dx2_prev, dx3, dx3_prev; + const array_t ux1, ux2, ux3, weight, phi; + const array_t pld; array_t tag; const array_t outgoing_indices; @@ -125,9 +127,11 @@ namespace kernel::comm { PopulatePrtlSendBuffer_kernel(array_t& send_buff_int, array_t& send_buff_real, array_t& send_buff_prtldx, + array_t& send_buff_pld, unsigned short NINTS, unsigned short NREALS, unsigned short NPRTLDX, + unsigned short NPLDS, std::size_t idx_offset, const array_t& i1, const array_t& i1_prev, @@ -146,25 +150,28 @@ namespace kernel::comm { const array_t& ux3, const array_t& weight, const array_t& phi, + const array_t& pld, array_t& tag, const array_t& outgoing_indices) : send_buff_int { send_buff_int } , send_buff_real { send_buff_real } , send_buff_prtldx { send_buff_prtldx } + , send_buff_pld { send_buff_pld } , NINTS { NINTS } , NREALS { NREALS } , NPRTLDX { NPRTLDX } + , NPLDS { NPLDS } , idx_offset { idx_offset } , i1 { i1 } , i1_prev { i1_prev } - , dx1 { dx1 } - , dx1_prev { dx1_prev } , i2 { i2 } , i2_prev { i2_prev } - , dx2 { dx2 } - , dx2_prev { dx2_prev } , i3 { i3 } , i3_prev { i3_prev } + , dx1 { dx1 } + , dx1_prev { dx1_prev } + , dx2 { dx2 } + , dx2_prev { dx2_prev } , dx3 { dx3 } , dx3_prev { dx3_prev } , ux1 { ux1 } @@ -172,6 +179,7 @@ namespace kernel::comm { , ux3 { ux3 } , weight { weight } , phi { phi } + , pld { pld } , tag { tag } , outgoing_indices { outgoing_indices } {} @@ -202,6 +210,11 @@ namespace kernel::comm { if constexpr (D == Dim::_2D and C != Coord::Cart) { send_buff_real(NREALS * p + 4) = phi(idx); } + if (NPLD > 0) { + for (auto l { 0u }; l < NPLD; ++l) { + send_buff_pld(NPLDS * p + l) = pld(idx, l); + } + } tag(idx) = ParticleTag::dead; } }; @@ -211,13 +224,15 @@ namespace kernel::comm { const array_t recv_buff_int; const array_t recv_buff_real; const array_t recv_buff_prtldx; + const array_t recv_buff_pld; - const unsigned short NINTS, NREALS, NPRTLDX; + const unsigned short NINTS, NREALS, NPRTLDX, NPLDS; const std::size_t npart, npart_holes; array_t i1, i1_prev, i2, i2_prev, i3, i3_prev; - array_t ux1, ux2, ux3, weight, phi; array_t dx1, dx1_prev, dx2, dx2_prev, dx3, dx3_prev; + array_t ux1, ux2, ux3, weight, phi; + array_t pld; array_t tag; const array_t outgoing_indices; @@ -225,9 +240,11 @@ namespace kernel::comm { ExtractReceivedPrtls_kernel(const array_t& recv_buff_int, const array_t& recv_buff_real, const array_t& recv_buff_prtldx, + const array_t& recv_buff_pld, unsigned short NINTS, unsigned short NREALS, unsigned short NPRTLDX, + unsigned short NPLDS, std::size_t npart, array_t& i1, array_t& i1_prev, @@ -246,26 +263,29 @@ namespace kernel::comm { array_t& ux3, array_t& weight, array_t& phi, + array_t& pld, array_t& tag, const array_t& outgoing_indices) : recv_buff_int { recv_buff_int } , recv_buff_real { recv_buff_real } , recv_buff_prtldx { recv_buff_prtldx } + , recv_buff_pld { recv_buff_pld } , NINTS { NINTS } , NREALS { NREALS } , NPRTLDX { NPRTLDX } + , NPLDS { NPLDS } , npart { npart } , npart_holes { outgoing_indices.extent(0) } , i1 { i1 } , i1_prev { i1_prev } - , dx1 { dx1 } - , dx1_prev { dx1_prev } , i2 { i2 } , i2_prev { i2_prev } - , dx2 { dx2 } - , dx2_prev { dx2_prev } , i3 { i3 } , i3_prev { i3_prev } + , dx1 { dx1 } + , dx1_prev { dx1_prev } + , dx2 { dx2 } + , dx2_prev { dx2_prev } , dx3 { dx3 } , dx3_prev { dx3_prev } , ux1 { ux1 } @@ -273,6 +293,7 @@ namespace kernel::comm { , ux3 { ux3 } , weight { weight } , phi { phi } + , pld { pld } , tag { tag } {} Inline void operator()(index_t p) const { From 6aa7a8099d30e0e950d3f026d18578d4da71c728 Mon Sep 17 00:00:00 2001 From: haykh Date: Tue, 28 Jan 2025 15:15:17 -0500 Subject: [PATCH 243/773] minor bug fixed in kernel --- src/kernels/comm.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/kernels/comm.hpp b/src/kernels/comm.hpp index d33e2e006..b280ce38b 100644 --- a/src/kernels/comm.hpp +++ b/src/kernels/comm.hpp @@ -292,7 +292,8 @@ namespace kernel::comm { , weight { weight } , phi { phi } , pld { pld } - , tag { tag } {} + , tag { tag } + , outgoing_indices { outgoing_indices } {} Inline void operator()(index_t p) const { std::size_t idx; From 3071251053b08a42ee852f1e98a6553ad5030dc5 Mon Sep 17 00:00:00 2001 From: haykh Date: Wed, 29 Jan 2025 10:20:47 -0500 Subject: [PATCH 244/773] nix devshell --- dev/nix/adios2.nix | 69 ++++++++++++++++++++++++++++++---------------- dev/nix/kokkos.nix | 64 ++++++++++++++++++++++++++++++++++++++++++ dev/nix/shell.nix | 54 ++++++++++++++++-------------------- 3 files changed, 133 insertions(+), 54 deletions(-) create mode 100644 dev/nix/kokkos.nix diff --git a/dev/nix/adios2.nix b/dev/nix/adios2.nix index 19c706aa4..f2cd4ca43 100644 --- a/dev/nix/adios2.nix +++ b/dev/nix/adios2.nix @@ -7,6 +7,20 @@ let name = "adios2"; version = "2.10.2"; + cmakeFlags = { + CMAKE_CXX_STANDARD = "17"; + CMAKE_CXX_EXTENSIONS = "OFF"; + CMAKE_POSITION_INDEPENDENT_CODE = "TRUE"; + BUILD_SHARED_LIBS = "ON"; + ADIOS2_USE_HDF5 = if hdf5 then "ON" else "OFF"; + ADIOS2_USE_Python = "OFF"; + ADIOS2_USE_Fortran = "OFF"; + ADIOS2_USE_ZeroMQ = "OFF"; + BUILD_TESTING = "OFF"; + ADIOS2_BUILD_EXAMPLES = "OFF"; + ADIOS2_USE_MPI = if mpi then "ON" else "OFF"; + CMAKE_BUILD_TYPE = "Release"; + } // (if !mpi then { ADIOS2_HAVE_HDF5_VOL = "OFF"; } else { }); in pkgs.stdenv.mkDerivation { pname = "${name}${if hdf5 then "-hdf5" else ""}${if mpi then "-mpi" else ""}"; @@ -17,35 +31,44 @@ pkgs.stdenv.mkDerivation { sha256 = "sha256-NVyw7xoPutXeUS87jjVv1YxJnwNGZAT4QfkBLzvQbwg="; }; - nativeBuildInputs = - with pkgs; + nativeBuildInputs = with pkgs; [ + cmake + perl + ]; + + propagatedBuildInputs = [ - cmake - libgcc - perl - breakpointHook + pkgs.gcc13 ] - ++ (if mpi then [ openmpi ] else [ ]); - - buildInputs = if hdf5 then (if mpi then [ pkgs.hdf5-mpi ] else [ pkgs.hdf5 ]) else [ ]; + ++ (if hdf5 then (if mpi then [ pkgs.hdf5-mpi ] else [ pkgs.hdf5 ]) else [ ]) + ++ (if mpi then [ pkgs.openmpi ] else [ ]); configurePhase = '' - cmake -B build $src \ - -D CMAKE_CXX_STANDARD=17 \ - -D CMAKE_CXX_EXTENSIONS=OFF \ - -D CMAKE_POSITION_INDEPENDENT_CODE=TRUE \ - -D BUILD_SHARED_LIBS=ON \ - -D ADIOS2_USE_HDF5=${if hdf5 then "ON" else "OFF"} \ - -D ADIOS2_USE_Python=OFF \ - -D ADIOS2_USE_Fortran=OFF \ - -D ADIOS2_USE_ZeroMQ=OFF \ - -D BUILD_TESTING=OFF \ - -D ADIOS2_BUILD_EXAMPLES=OFF \ - -D ADIOS2_USE_MPI=${if mpi then "ON" else "OFF"} \ - -D ADIOS2_HAVE_HDF5_VOL=OFF \ - -D CMAKE_BUILD_TYPE=Release + cmake -B build $src ${ + pkgs.lib.attrsets.foldlAttrs ( + acc: key: value: + acc + " -D ${key}=${value}" + ) "" cmakeFlags + } ''; + # configurePhase = + # '' + # cmake -B build $src \ + # -D CMAKE_CXX_STANDARD=17 \ + # -D CMAKE_CXX_EXTENSIONS=OFF \ + # -D CMAKE_POSITION_INDEPENDENT_CODE=TRUE \ + # -D BUILD_SHARED_LIBS=ON \ + # -D ADIOS2_USE_HDF5=${if hdf5 then "ON" else "OFF"} \ + # -D ADIOS2_USE_Python=OFF \ + # -D ADIOS2_USE_Fortran=OFF \ + # -D ADIOS2_USE_ZeroMQ=OFF \ + # -D BUILD_TESTING=OFF \ + # -D ADIOS2_BUILD_EXAMPLES=OFF \ + # -D ADIOS2_USE_MPI=${if mpi then "ON" else "OFF"} \ + # -D CMAKE_BUILD_TYPE=Release + # '' + buildPhase = '' cmake --build build -j ''; diff --git a/dev/nix/kokkos.nix b/dev/nix/kokkos.nix new file mode 100644 index 000000000..cfe583c7a --- /dev/null +++ b/dev/nix/kokkos.nix @@ -0,0 +1,64 @@ +{ + pkgs ? import { }, + arch ? "native", + gpu ? "none", +}: + +let + gpuUpper = pkgs.lib.toUpper gpu; + name = "kokkos"; + version = "4.5.01"; + compilerPkgs = { + "HIP" = with pkgs.rocmPackages; [ + rocm-core + clr + rocthrust + rocprim + rocminfo + rocm-smi + ]; + "NONE" = [ + pkgs.gcc13 + ]; + }; + cmakeFlags = { + "HIP" = [ + "-D CMAKE_C_COMPILER=hipcc" + "-D CMAKE_CXX_COMPILER=hipcc" + ]; + "NONE" = [ ]; + }; + getArch = + _: + if gpu != "none" && arch == "native" then + throw "Please specify an architecture when the GPU support is enabled. Available architectures: https://kokkos.org/kokkos-core-wiki/keywords.html#architectures" + else + pkgs.lib.toUpper arch; + +in +pkgs.stdenv.mkDerivation { + pname = "${name}"; + version = "${version}"; + src = pkgs.fetchgit { + url = "https://github.com/kokkos/kokkos/"; + rev = "v${version}"; + sha256 = "sha256-cI2p+6J+8BRV5fXTDxxHTfh6P5PeeLUiF73o5zVysHQ="; + }; + + nativeBuildInputs = with pkgs; [ + cmake + ]; + + propagatedBuildInputs = compilerPkgs.${gpuUpper}; + + cmakeFlags = [ + "-D CMAKE_CXX_STANDARD=17" + "-D CMAKE_CXX_EXTENSIONS=OFF" + "-D CMAKE_POSITION_INDEPENDENT_CODE=TRUE" + "-D Kokkos_ARCH_${getArch { }}=ON" + (if gpu != "none" then "-D Kokkos_ENABLE_${gpuUpper}=ON" else "") + "-D CMAKE_BUILD_TYPE=Release" + ] ++ cmakeFlags.${gpuUpper}; + + enableParallelBuilding = true; +} diff --git a/dev/nix/shell.nix b/dev/nix/shell.nix index f9d48fbfd..219da0038 100644 --- a/dev/nix/shell.nix +++ b/dev/nix/shell.nix @@ -2,40 +2,36 @@ pkgs ? import { }, mpi ? false, hdf5 ? false, + gpu ? "none", + arch ? "native", }: let name = "entity-dev"; - compilerPkg = pkgs.gcc13; - compilerCXX = "g++"; - compilerCC = "gcc"; adios2Pkg = (pkgs.callPackage ./adios2.nix { inherit pkgs mpi hdf5; }); + kokkosPkg = (pkgs.callPackage ./kokkos.nix { inherit pkgs arch gpu; }); in pkgs.mkShell { name = "${name}-env"; - nativeBuildInputs = - with pkgs; - [ - zlib - cmake - - compilerPkg - - clang-tools - - adios2Pkg - python312 - python312Packages.jupyter - - cmake-format - neocmakelsp - black - pyright - taplo - vscode-langservers-extracted - ] - ++ (if mpi then [ pkgs.openmpi ] else [ ]) - ++ (if hdf5 then (if mpi then [ pkgs.hdf5-mpi ] else [ pkgs.hdf5 ]) else [ ]); + nativeBuildInputs = with pkgs; [ + zlib + cmake + + clang-tools + + adios2Pkg + kokkosPkg + + python312 + python312Packages.jupyter + + cmake-format + neocmakelsp + black + pyright + taplo + vscode-langservers-extracted + ]; LD_LIBRARY_PATH = pkgs.lib.makeLibraryPath ([ pkgs.stdenv.cc.cc @@ -45,12 +41,8 @@ pkgs.mkShell { shellHook = '' BLUE='\033[0;34m' NC='\033[0m' - export CC=$(which ${compilerCC}) - export CXX=$(which ${compilerCXX}) - export CMAKE_CXX_COMPILER=$(which ${compilerCXX}) - export CMAKE_C_COMPILER=$(which ${compilerCC}) echo "" - echo -e "${name} nix-shell activated: ''\${BLUE}$(which ${compilerCXX})''\${NC}" + echo -e "${name} nix-shell activated" ''; } From 6aa045a4947854913112858fdfed36ca7100a144 Mon Sep 17 00:00:00 2001 From: haykh Date: Wed, 29 Jan 2025 10:51:45 -0500 Subject: [PATCH 245/773] pld reading in checkpoint fixed --- src/checkpoint/reader.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/checkpoint/reader.cpp b/src/checkpoint/reader.cpp index 208972561..9fc2d2640 100644 --- a/src/checkpoint/reader.cpp +++ b/src/checkpoint/reader.cpp @@ -98,7 +98,7 @@ namespace checkpoint { fmt::format("s%d_%s", s + 1, quantity.c_str())); if (var) { var.SetSelection(adios2::Box({ offset }, { count })); - const auto slice = std::pair { 0, count }; + const auto slice = range_tuple_t(0, count); auto array_h = Kokkos::create_mirror_view(array); reader.Get(var, Kokkos::subview(array_h, slice).data(), adios2::Mode::Sync); Kokkos::deep_copy(Kokkos::subview(array, slice), @@ -121,13 +121,12 @@ namespace checkpoint { auto var = io.InquireVariable(fmt::format("s%d_plds", s + 1)); if (var) { var.SetSelection(adios2::Box({ offset, 0 }, { count, nplds })); - const auto slice = std::pair { 0, count }; + const auto slice = range_tuple_t(0, count); auto array_h = Kokkos::create_mirror_view(array); reader.Get(var, Kokkos::subview(array_h, slice, range_tuple_t(0, nplds)).data(), adios2::Mode::Sync); - Kokkos::deep_copy(Kokkos::subview(array, slice, range_tuple_t(0, nplds)), - Kokkos::subview(array_h, slice, range_tuple_t(0, nplds))); + Kokkos::deep_copy(array, array_h); } else { raise::Error(fmt::format("Variable: s%d_plds not found", s + 1), HERE); } From 649e3285796f107a2699c38e3c740cf1c998d895 Mon Sep 17 00:00:00 2001 From: haykh Date: Wed, 29 Jan 2025 10:54:43 -0500 Subject: [PATCH 246/773] clean benchmark --- benchmark/benchmark.cpp | 274 ++-------------------------------------- legacy/benchmark.cpp | 273 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 282 insertions(+), 265 deletions(-) create mode 100644 legacy/benchmark.cpp diff --git a/benchmark/benchmark.cpp b/benchmark/benchmark.cpp index 54fc17cf9..98306c92b 100644 --- a/benchmark/benchmark.cpp +++ b/benchmark/benchmark.cpp @@ -1,273 +1,17 @@ -#include "enums.h" #include "global.h" -#include "utils/error.h" - -#include "metrics/metric_base.h" -#include "metrics/minkowski.h" - -#include "framework/containers/species.h" -#include "framework/domain/domain.h" -#include "framework/domain/metadomain.h" - -#include - -#include "framework/domain/communications.cpp" -#include "mpi.h" -#include "mpi-ext.h" - -#define TIMER_START(label) \ - Kokkos::fence(); \ - auto start_##label = std::chrono::high_resolution_clock::now(); - -#define TIMER_STOP(label) \ - Kokkos::fence(); \ - auto stop_##label = std::chrono::high_resolution_clock::now(); \ - auto duration_##label = std::chrono::duration_cast( \ - stop_##label - start_##label) \ - .count(); \ - std::cout << "Timer [" #label "]: " << duration_##label << " microseconds" \ - << std::endl; - -/* - Test to check the performance of the new particle allocation scheme - - Create a metadomain object main() - - Set npart + initialize tags InitializeParticleArrays() - - 'Push' the particles by randomly updating the tags PushParticles() - - Communicate particles to neighbors and time the communication - - Compute the time taken for best of N iterations for the communication - */ -using namespace ntt; - -// Set npart and set the particle tags to alive -template -void InitializeParticleArrays(Domain& domain, const int npart) { - raise::ErrorIf(npart > domain.species[0].maxnpart(), - "Npart cannot be greater than maxnpart", - HERE); - const auto nspecies = domain.species.size(); - for (int i_spec = 0; i_spec < nspecies; i_spec++) { - domain.species[i_spec].set_npart(npart); - domain.species[i_spec].SyncHostDevice(); - auto& this_tag = domain.species[i_spec].tag; - Kokkos::parallel_for( - "Initialize particles", - npart, - Lambda(const std::size_t i) { this_tag(i) = ParticleTag::alive; }); - } - return; -} - -// Randomly reassign tags to particles for a fraction of particles -template -void PushParticles(Domain& domain, - const double send_frac, - const int seed_ind, - const int seed_tag) { - raise::ErrorIf(send_frac > 1.0, "send_frac cannot be greater than 1.0", HERE); - const auto nspecies = domain.species.size(); - for (int i_spec = 0; i_spec < nspecies; i_spec++) { - domain.species[i_spec].set_unsorted(); - const auto nparticles = domain.species[i_spec].npart(); - const auto nparticles_to_send = static_cast(send_frac * nparticles); - // Generate random indices to send - // Kokkos::Random_XorShift64_Pool<> random_pool(seed_ind); - Kokkos::View indices_to_send("indices_to_send", nparticles_to_send); - Kokkos::fill_random(indices_to_send, domain.random_pool, 0, nparticles); - // Generate random tags to send - // Kokkos::Random_XorShift64_Pool<> random_pool_tag(seed_tag); - Kokkos::View tags_to_send("tags_to_send", nparticles_to_send); - Kokkos::fill_random(tags_to_send, - domain.random_pool, - 0, - domain.species[i_spec].ntags()); - auto& this_tag = domain.species[i_spec].tag; - Kokkos::parallel_for( - "Push particles", - nparticles_to_send, - Lambda(const std::size_t i) { - auto prtl_to_send = indices_to_send(i); - auto tag_to_send = tags_to_send(i); - this_tag(prtl_to_send) = tag_to_send; - }); - domain.species[i_spec].npart_per_tag(); - domain.species[i_spec].SyncHostDevice(); - } - return; -} +#include +#include auto main(int argc, char* argv[]) -> int { - GlobalInitialize(argc, argv); - { - /* - MPI checks - */ - printf("Compile time check:\n"); -#if defined(MPIX_CUDA_AWARE_SUPPORT) && MPIX_CUDA_AWARE_SUPPORT - printf("This MPI library has CUDA-aware support.\n", MPIX_CUDA_AWARE_SUPPORT); -#elif defined(MPIX_CUDA_AWARE_SUPPORT) && !MPIX_CUDA_AWARE_SUPPORT - printf("This MPI library does not have CUDA-aware support.\n"); -#else - printf("This MPI library cannot determine if there is CUDA-aware support.\n"); -#endif /* MPIX_CUDA_AWARE_SUPPORT */ -printf("Run time check:\n"); -#if defined(MPIX_CUDA_AWARE_SUPPORT) - if (1 == MPIX_Query_cuda_support()) { - printf("This MPI library has CUDA-aware support.\n"); - } else { - printf("This MPI library does not have CUDA-aware support.\n"); - } -#else /* !defined(MPIX_CUDA_AWARE_SUPPORT) */ - printf("This MPI library cannot determine if there is CUDA-aware support.\n"); -#endif /* MPIX_CUDA_AWARE_SUPPORT */ - - /* - Test to send and receive Kokkos arrays - */ - int sender_rank; - MPI_Comm_rank(MPI_COMM_WORLD, &sender_rank); - - int neighbor_rank = 0; - if (sender_rank == 0) { - neighbor_rank = 1; - } - else if (sender_rank == 1) { - neighbor_rank = 0; - } - else { - raise::Error("This test is only for 2 ranks", HERE); - } - Kokkos::View send_array("send_array", 10); - Kokkos::View recv_array("recv_array", 10); - if (sender_rank == 0) { - Kokkos::deep_copy(send_array, 10); - } - else { - Kokkos::deep_copy(send_array, 20); - } - - auto send_array_host = Kokkos::create_mirror_view(send_array); - Kokkos::deep_copy(send_array_host, send_array); - auto host_recv_array = Kokkos::create_mirror_view(recv_array); - - MPI_Sendrecv(send_array.data(), send_array.extent(0), MPI_INT, neighbor_rank, 0, - recv_array.data(), recv_array.extent(0), MPI_INT, neighbor_rank, 0, - MPI_COMM_WORLD, MPI_STATUS_IGNORE); - - // Print the received array - Kokkos::deep_copy(host_recv_array, recv_array); - for (int i = 0; i < 10; ++i) { - printf("Rank %d: Received %d\n", sender_rank, host_recv_array(i)); - } - - - std::cout << "Constructing the domain" << std::endl; - // Create a Metadomain object - const unsigned int ndomains = 2; - const std::vector global_decomposition = { - {-1, -1, -1} - }; - const std::vector global_ncells = { 32, 32, 32 }; - const boundaries_t global_extent = { - {0.0, 3.0}, - {0.0, 3.0}, - {0.0, 3.0} - }; - const boundaries_t global_flds_bc = { - {FldsBC::PERIODIC, FldsBC::PERIODIC}, - {FldsBC::PERIODIC, FldsBC::PERIODIC}, - {FldsBC::PERIODIC, FldsBC::PERIODIC} - }; - const boundaries_t global_prtl_bc = { - {PrtlBC::PERIODIC, PrtlBC::PERIODIC}, - {PrtlBC::PERIODIC, PrtlBC::PERIODIC}, - {PrtlBC::PERIODIC, PrtlBC::PERIODIC} - }; - const std::map metric_params = {}; - const int maxnpart = argc > 1 ? std::stoi(argv[1]) : 1000; - const double npart_to_send_frac = 0.01; - const int npart = static_cast(maxnpart * (1 - 2 * npart_to_send_frac)); - auto species = ntt::ParticleSpecies(1u, - "test_e", - 1.0f, - 1.0f, - maxnpart, - ntt::PrtlPusher::BORIS, - false, - ntt::Cooling::NONE); - auto metadomain = Metadomain>( - ndomains, - global_decomposition, - global_ncells, - global_extent, - global_flds_bc, - global_prtl_bc, - metric_params, - { species }); - - const auto local_subdomain_idx = metadomain.l_subdomain_indices()[0]; - auto local_domain = metadomain.subdomain_ptr(local_subdomain_idx); - auto timers = timer::Timers { { "Communication" }, nullptr, false }; - InitializeParticleArrays(*local_domain, npart); - // Timers for both the communication routines - auto total_time_elapsed_old = 0; - auto total_time_elapsed_new = 0; - - int seed_ind = 0; - int seed_tag = 1; - Kokkos::fence(); - - for (int i = 0; i < 10; ++i) { - { - // Push - seed_ind += 2; - seed_tag += 3; - PushParticles(*local_domain, npart_to_send_frac, seed_ind, seed_tag); - // Sort new - Kokkos::fence(); - auto start_new = std::chrono::high_resolution_clock::now(); - metadomain.CommunicateParticlesBuffer(*local_domain, &timers); - auto stop_new = std::chrono::high_resolution_clock::now(); - auto duration_new = std::chrono::duration_cast( - stop_new - start_new) - .count(); - total_time_elapsed_new += duration_new; - Kokkos::fence(); - } - { - // Push - seed_ind += 2; - seed_tag += 3; - PushParticles(*local_domain, npart_to_send_frac, seed_ind, seed_tag); - // Sort old - Kokkos::fence(); - auto start_old = std::chrono::high_resolution_clock::now(); - metadomain.CommunicateParticles(*local_domain, &timers); - auto stop_old = std::chrono::high_resolution_clock::now(); - auto duration_old = std::chrono::duration_cast( - stop_old - start_old) - .count(); - total_time_elapsed_old += duration_old; - Kokkos::fence(); - } - } - printf("Total time elapsed for old: %f us : %f us/prtl\n", - total_time_elapsed_old / 10.0, - total_time_elapsed_old / 10.0 * 1000 / npart); - printf("Total time elapsed for new: %f us : %f us/prtl\n", - total_time_elapsed_new / 10.0, - total_time_elapsed_new / 10.0 * 1000 / npart); + ntt::GlobalInitialize(argc, argv); + try { + // ... + } catch (const std::exception& e) { + std::cerr << "Error: " << e.what() << std::endl; + GlobalFinalize(); + return 1; } GlobalFinalize(); return 0; } - -/* - Buggy behavior: - Consider a single domain with a single mpi rank - Particle tag arrays is set to [0, 0, 1, 1, 2, 3, ...] for a single domain - CommunicateParticles() discounts all the dead particles and reassigns the - other tags to alive - CommunicateParticlesBuffer() only keeps the ParticleTag::Alive particles - and discounts the rest -*/ diff --git a/legacy/benchmark.cpp b/legacy/benchmark.cpp new file mode 100644 index 000000000..54fc17cf9 --- /dev/null +++ b/legacy/benchmark.cpp @@ -0,0 +1,273 @@ +#include "enums.h" +#include "global.h" + +#include "utils/error.h" + +#include "metrics/metric_base.h" +#include "metrics/minkowski.h" + +#include "framework/containers/species.h" +#include "framework/domain/domain.h" +#include "framework/domain/metadomain.h" + +#include + +#include "framework/domain/communications.cpp" +#include "mpi.h" +#include "mpi-ext.h" + +#define TIMER_START(label) \ + Kokkos::fence(); \ + auto start_##label = std::chrono::high_resolution_clock::now(); + +#define TIMER_STOP(label) \ + Kokkos::fence(); \ + auto stop_##label = std::chrono::high_resolution_clock::now(); \ + auto duration_##label = std::chrono::duration_cast( \ + stop_##label - start_##label) \ + .count(); \ + std::cout << "Timer [" #label "]: " << duration_##label << " microseconds" \ + << std::endl; + +/* + Test to check the performance of the new particle allocation scheme + - Create a metadomain object main() + - Set npart + initialize tags InitializeParticleArrays() + - 'Push' the particles by randomly updating the tags PushParticles() + - Communicate particles to neighbors and time the communication + - Compute the time taken for best of N iterations for the communication + */ +using namespace ntt; + +// Set npart and set the particle tags to alive +template +void InitializeParticleArrays(Domain& domain, const int npart) { + raise::ErrorIf(npart > domain.species[0].maxnpart(), + "Npart cannot be greater than maxnpart", + HERE); + const auto nspecies = domain.species.size(); + for (int i_spec = 0; i_spec < nspecies; i_spec++) { + domain.species[i_spec].set_npart(npart); + domain.species[i_spec].SyncHostDevice(); + auto& this_tag = domain.species[i_spec].tag; + Kokkos::parallel_for( + "Initialize particles", + npart, + Lambda(const std::size_t i) { this_tag(i) = ParticleTag::alive; }); + } + return; +} + +// Randomly reassign tags to particles for a fraction of particles +template +void PushParticles(Domain& domain, + const double send_frac, + const int seed_ind, + const int seed_tag) { + raise::ErrorIf(send_frac > 1.0, "send_frac cannot be greater than 1.0", HERE); + const auto nspecies = domain.species.size(); + for (int i_spec = 0; i_spec < nspecies; i_spec++) { + domain.species[i_spec].set_unsorted(); + const auto nparticles = domain.species[i_spec].npart(); + const auto nparticles_to_send = static_cast(send_frac * nparticles); + // Generate random indices to send + // Kokkos::Random_XorShift64_Pool<> random_pool(seed_ind); + Kokkos::View indices_to_send("indices_to_send", nparticles_to_send); + Kokkos::fill_random(indices_to_send, domain.random_pool, 0, nparticles); + // Generate random tags to send + // Kokkos::Random_XorShift64_Pool<> random_pool_tag(seed_tag); + Kokkos::View tags_to_send("tags_to_send", nparticles_to_send); + Kokkos::fill_random(tags_to_send, + domain.random_pool, + 0, + domain.species[i_spec].ntags()); + auto& this_tag = domain.species[i_spec].tag; + Kokkos::parallel_for( + "Push particles", + nparticles_to_send, + Lambda(const std::size_t i) { + auto prtl_to_send = indices_to_send(i); + auto tag_to_send = tags_to_send(i); + this_tag(prtl_to_send) = tag_to_send; + }); + domain.species[i_spec].npart_per_tag(); + domain.species[i_spec].SyncHostDevice(); + } + return; +} + +auto main(int argc, char* argv[]) -> int { + GlobalInitialize(argc, argv); + { + /* + MPI checks + */ + printf("Compile time check:\n"); +#if defined(MPIX_CUDA_AWARE_SUPPORT) && MPIX_CUDA_AWARE_SUPPORT + printf("This MPI library has CUDA-aware support.\n", MPIX_CUDA_AWARE_SUPPORT); +#elif defined(MPIX_CUDA_AWARE_SUPPORT) && !MPIX_CUDA_AWARE_SUPPORT + printf("This MPI library does not have CUDA-aware support.\n"); +#else + printf("This MPI library cannot determine if there is CUDA-aware support.\n"); +#endif /* MPIX_CUDA_AWARE_SUPPORT */ +printf("Run time check:\n"); +#if defined(MPIX_CUDA_AWARE_SUPPORT) + if (1 == MPIX_Query_cuda_support()) { + printf("This MPI library has CUDA-aware support.\n"); + } else { + printf("This MPI library does not have CUDA-aware support.\n"); + } +#else /* !defined(MPIX_CUDA_AWARE_SUPPORT) */ + printf("This MPI library cannot determine if there is CUDA-aware support.\n"); +#endif /* MPIX_CUDA_AWARE_SUPPORT */ + + /* + Test to send and receive Kokkos arrays + */ + int sender_rank; + MPI_Comm_rank(MPI_COMM_WORLD, &sender_rank); + + int neighbor_rank = 0; + if (sender_rank == 0) { + neighbor_rank = 1; + } + else if (sender_rank == 1) { + neighbor_rank = 0; + } + else { + raise::Error("This test is only for 2 ranks", HERE); + } + Kokkos::View send_array("send_array", 10); + Kokkos::View recv_array("recv_array", 10); + if (sender_rank == 0) { + Kokkos::deep_copy(send_array, 10); + } + else { + Kokkos::deep_copy(send_array, 20); + } + + auto send_array_host = Kokkos::create_mirror_view(send_array); + Kokkos::deep_copy(send_array_host, send_array); + auto host_recv_array = Kokkos::create_mirror_view(recv_array); + + MPI_Sendrecv(send_array.data(), send_array.extent(0), MPI_INT, neighbor_rank, 0, + recv_array.data(), recv_array.extent(0), MPI_INT, neighbor_rank, 0, + MPI_COMM_WORLD, MPI_STATUS_IGNORE); + + // Print the received array + Kokkos::deep_copy(host_recv_array, recv_array); + for (int i = 0; i < 10; ++i) { + printf("Rank %d: Received %d\n", sender_rank, host_recv_array(i)); + } + + + std::cout << "Constructing the domain" << std::endl; + // Create a Metadomain object + const unsigned int ndomains = 2; + const std::vector global_decomposition = { + {-1, -1, -1} + }; + const std::vector global_ncells = { 32, 32, 32 }; + const boundaries_t global_extent = { + {0.0, 3.0}, + {0.0, 3.0}, + {0.0, 3.0} + }; + const boundaries_t global_flds_bc = { + {FldsBC::PERIODIC, FldsBC::PERIODIC}, + {FldsBC::PERIODIC, FldsBC::PERIODIC}, + {FldsBC::PERIODIC, FldsBC::PERIODIC} + }; + const boundaries_t global_prtl_bc = { + {PrtlBC::PERIODIC, PrtlBC::PERIODIC}, + {PrtlBC::PERIODIC, PrtlBC::PERIODIC}, + {PrtlBC::PERIODIC, PrtlBC::PERIODIC} + }; + const std::map metric_params = {}; + const int maxnpart = argc > 1 ? std::stoi(argv[1]) : 1000; + const double npart_to_send_frac = 0.01; + const int npart = static_cast(maxnpart * (1 - 2 * npart_to_send_frac)); + auto species = ntt::ParticleSpecies(1u, + "test_e", + 1.0f, + 1.0f, + maxnpart, + ntt::PrtlPusher::BORIS, + false, + ntt::Cooling::NONE); + auto metadomain = Metadomain>( + ndomains, + global_decomposition, + global_ncells, + global_extent, + global_flds_bc, + global_prtl_bc, + metric_params, + { species }); + + const auto local_subdomain_idx = metadomain.l_subdomain_indices()[0]; + auto local_domain = metadomain.subdomain_ptr(local_subdomain_idx); + auto timers = timer::Timers { { "Communication" }, nullptr, false }; + InitializeParticleArrays(*local_domain, npart); + // Timers for both the communication routines + auto total_time_elapsed_old = 0; + auto total_time_elapsed_new = 0; + + int seed_ind = 0; + int seed_tag = 1; + Kokkos::fence(); + + for (int i = 0; i < 10; ++i) { + { + // Push + seed_ind += 2; + seed_tag += 3; + PushParticles(*local_domain, npart_to_send_frac, seed_ind, seed_tag); + // Sort new + Kokkos::fence(); + auto start_new = std::chrono::high_resolution_clock::now(); + metadomain.CommunicateParticlesBuffer(*local_domain, &timers); + auto stop_new = std::chrono::high_resolution_clock::now(); + auto duration_new = std::chrono::duration_cast( + stop_new - start_new) + .count(); + total_time_elapsed_new += duration_new; + Kokkos::fence(); + } + { + // Push + seed_ind += 2; + seed_tag += 3; + PushParticles(*local_domain, npart_to_send_frac, seed_ind, seed_tag); + // Sort old + Kokkos::fence(); + auto start_old = std::chrono::high_resolution_clock::now(); + metadomain.CommunicateParticles(*local_domain, &timers); + auto stop_old = std::chrono::high_resolution_clock::now(); + auto duration_old = std::chrono::duration_cast( + stop_old - start_old) + .count(); + total_time_elapsed_old += duration_old; + Kokkos::fence(); + } + } + printf("Total time elapsed for old: %f us : %f us/prtl\n", + total_time_elapsed_old / 10.0, + total_time_elapsed_old / 10.0 * 1000 / npart); + printf("Total time elapsed for new: %f us : %f us/prtl\n", + total_time_elapsed_new / 10.0, + total_time_elapsed_new / 10.0 * 1000 / npart); + } + GlobalFinalize(); + return 0; +} + +/* + Buggy behavior: + Consider a single domain with a single mpi rank + Particle tag arrays is set to [0, 0, 1, 1, 2, 3, ...] for a single domain + CommunicateParticles() discounts all the dead particles and reassigns the + other tags to alive + CommunicateParticlesBuffer() only keeps the ParticleTag::Alive particles + and discounts the rest +*/ From 3f2674c23088ca344a9e61135f79815672d610ad Mon Sep 17 00:00:00 2001 From: haykh Date: Wed, 29 Jan 2025 11:05:27 -0500 Subject: [PATCH 247/773] cleanup prep for release --- dev/nix/adios2.nix | 17 ---- setups/srpic/blob/blob.toml | 66 ------------- setups/srpic/blob/pgen.hpp | 103 -------------------- setups/{srpic => tests}/blob/blob.py | 0 setups/tests/blob/blob.toml | 76 +++++++-------- setups/{srpic => tests}/blob/nparts.py | 0 setups/tests/blob/pgen.hpp | 126 +++++++++++-------------- src/framework/containers/particles.cpp | 54 ----------- 8 files changed, 92 insertions(+), 350 deletions(-) delete mode 100644 setups/srpic/blob/blob.toml delete mode 100644 setups/srpic/blob/pgen.hpp rename setups/{srpic => tests}/blob/blob.py (100%) rename setups/{srpic => tests}/blob/nparts.py (100%) diff --git a/dev/nix/adios2.nix b/dev/nix/adios2.nix index f2cd4ca43..8ec1fd36c 100644 --- a/dev/nix/adios2.nix +++ b/dev/nix/adios2.nix @@ -52,23 +52,6 @@ pkgs.stdenv.mkDerivation { } ''; - # configurePhase = - # '' - # cmake -B build $src \ - # -D CMAKE_CXX_STANDARD=17 \ - # -D CMAKE_CXX_EXTENSIONS=OFF \ - # -D CMAKE_POSITION_INDEPENDENT_CODE=TRUE \ - # -D BUILD_SHARED_LIBS=ON \ - # -D ADIOS2_USE_HDF5=${if hdf5 then "ON" else "OFF"} \ - # -D ADIOS2_USE_Python=OFF \ - # -D ADIOS2_USE_Fortran=OFF \ - # -D ADIOS2_USE_ZeroMQ=OFF \ - # -D BUILD_TESTING=OFF \ - # -D ADIOS2_BUILD_EXAMPLES=OFF \ - # -D ADIOS2_USE_MPI=${if mpi then "ON" else "OFF"} \ - # -D CMAKE_BUILD_TYPE=Release - # '' - buildPhase = '' cmake --build build -j ''; diff --git a/setups/srpic/blob/blob.toml b/setups/srpic/blob/blob.toml deleted file mode 100644 index 7a047f348..000000000 --- a/setups/srpic/blob/blob.toml +++ /dev/null @@ -1,66 +0,0 @@ -[simulation] - name = "blob" - engine = "srpic" - runtime = 100.0 - - [simulation.domain] - decomposition = [2, 1, 1] - -[grid] - resolution = [1024, 1024] - extent = [[-10.0, 10.0], [-10.0, 10.0]] - - [grid.metric] - metric = "minkowski" - - [grid.boundaries] - fields = [["PERIODIC"], ["PERIODIC"]] - particles = [["PERIODIC"], ["PERIODIC"]] - -[scales] - larmor0 = 1.0 - skindepth0 = 1.0 - -[algorithms] - current_filters = 4 - - [algorithms.timestep] - CFL = 0.5 - -[particles] - ppc0 = 16.0 - - [[particles.species]] - label = "e-_p" - mass = 1.0 - charge = -1.0 - maxnpart = 1e7 - - [[particles.species]] - label = "e+_p" - mass = 1.0 - charge = 1.0 - maxnpart = 1e7 - -[setup] - temp_1 = 1e-4 - x1c = -5.0 - x2c = 0.0 - v_max = 50.0 - dr = 1.0 - -[output] - format = "hdf5" - interval_time = 1.0 - - [output.fields] - quantities = ["N_1", "N_2", "B", "E"] - - [output.particles] - enable = false - - [output.spectra] - enable = false - -[diagnostics] - colored_stdout = false diff --git a/setups/srpic/blob/pgen.hpp b/setups/srpic/blob/pgen.hpp deleted file mode 100644 index f7b7d71b5..000000000 --- a/setups/srpic/blob/pgen.hpp +++ /dev/null @@ -1,103 +0,0 @@ -#ifndef PROBLEM_GENERATOR_H -#define PROBLEM_GENERATOR_H - -#include "enums.h" -#include "global.h" - -#include "arch/kokkos_aliases.h" -#include "arch/traits.h" - -#include "archetypes/energy_dist.h" -#include "archetypes/particle_injector.h" -#include "archetypes/problem_generator.h" -#include "framework/domain/domain.h" -#include "framework/domain/metadomain.h" - -namespace user { - using namespace ntt; - - template - struct CounterstreamEnergyDist : public arch::EnergyDistribution { - CounterstreamEnergyDist(const M& metric, real_t v_max) - : arch::EnergyDistribution { metric } - , v_max { v_max } {} - - Inline void operator()(const coord_t& x_Ph, - vec_t& v, - unsigned short sp) const override { - v[0] = v_max; - } - - private: - const real_t v_max; - }; - - template - struct GaussianDist : public arch::SpatialDistribution { - GaussianDist(const M& metric, real_t x1c, real_t x2c, real_t dr) - : arch::SpatialDistribution { metric } - , x1c { x1c } - , x2c { x2c } - , dr { dr } {} - - // to properly scale the number density, the probability should be normalized to 1 - Inline auto operator()(const coord_t& x_Ph) const -> real_t override { - if (math::abs(x_Ph[0] - x1c) < dr && math::abs(x_Ph[1] - x2c) < dr) { - return 1.0; - } else { - return 0.0; - } - } - - private: - const real_t x1c, x2c, dr; - }; - - template - struct PGen : public arch::ProblemGenerator { - - // compatibility traits for the problem generator - static constexpr auto engines = traits::compatible_with::value; - static constexpr auto metrics = traits::compatible_with::value; - static constexpr auto dimensions = - traits::compatible_with::value; - - // for easy access to variables in the child class - using arch::ProblemGenerator::D; - using arch::ProblemGenerator::C; - using arch::ProblemGenerator::params; - - const real_t temp_1, x1c, x2c, dr, v_max; - - inline PGen(const SimulationParams& p, const Metadomain& global_domain) - : arch::ProblemGenerator { p } - , temp_1 { p.template get("setup.temp_1") } - , x1c { p.template get("setup.x1c") } - , x2c { p.template get("setup.x2c") } - , v_max { p.template get("setup.v_max") } - , dr { p.template get("setup.dr") } {} - - inline void InitPrtls(Domain& local_domain) { - const auto energy_dist = CounterstreamEnergyDist(local_domain.mesh.metric, - v_max); - const auto spatial_dist = GaussianDist(local_domain.mesh.metric, - x1c, - x2c, - dr); - const auto injector = - arch::NonUniformInjector( - energy_dist, - spatial_dist, - { 1, 2 }); - - arch::InjectNonUniform>( - params, - local_domain, - injector, - 1.0); - } - }; - -} // namespace user - -#endif diff --git a/setups/srpic/blob/blob.py b/setups/tests/blob/blob.py similarity index 100% rename from setups/srpic/blob/blob.py rename to setups/tests/blob/blob.py diff --git a/setups/tests/blob/blob.toml b/setups/tests/blob/blob.toml index fffa5fff1..7a047f348 100644 --- a/setups/tests/blob/blob.toml +++ b/setups/tests/blob/blob.toml @@ -1,32 +1,25 @@ [simulation] - name = "blob-1x1x2" - engine = "srpic" - runtime = 5.0 + name = "blob" + engine = "srpic" + runtime = 100.0 [simulation.domain] - decomposition = [1, 1, 2] + decomposition = [2, 1, 1] [grid] - resolution = [128, 192, 64] - # extent = [[1.0, 10.0]] - extent = [[-2.0, 2.0], [-3.0, 3.0], [-1.0, 1.0]] + resolution = [1024, 1024] + extent = [[-10.0, 10.0], [-10.0, 10.0]] [grid.metric] - # metric = "qspherical" metric = "minkowski" [grid.boundaries] - # fields = [["ATMOSPHERE", "ABSORB"]] - # particles = [["ATMOSPHERE", "ABSORB"]] - fields = [["PERIODIC"], ["PERIODIC"], ["PERIODIC"]] - particles = [["PERIODIC"], ["PERIODIC"], ["PERIODIC"]] - - # [grid.boundaries.absorb] - # ds = 1.0 - + fields = [["PERIODIC"], ["PERIODIC"]] + particles = [["PERIODIC"], ["PERIODIC"]] + [scales] - larmor0 = 2e-5 - skindepth0 = 0.01 + larmor0 = 1.0 + skindepth0 = 1.0 [algorithms] current_filters = 4 @@ -35,32 +28,39 @@ CFL = 0.5 [particles] - ppc0 = 20.0 - # use_weights = true + ppc0 = 16.0 [[particles.species]] - label = "e-" - mass = 1.0 - charge = -1.0 - maxnpart = 1e7 - pusher = "Boris" + label = "e-_p" + mass = 1.0 + charge = -1.0 + maxnpart = 1e7 [[particles.species]] - label = "e+" - mass = 1.0 - charge = 1.0 - maxnpart = 1e7 - pusher = "Boris" + label = "e+_p" + mass = 1.0 + charge = 1.0 + maxnpart = 1e7 [setup] - xi_min = [0.55, 1.85, -0.25] - xi_max = [0.65, 2.3, -0.1] - v1 = [0.25, -0.55, 0.0] - v2 = [-0.75, -0.15, 0.0] - + temp_1 = 1e-4 + x1c = -5.0 + x2c = 0.0 + v_max = 50.0 + dr = 1.0 + [output] - format = "hdf5" - interval_time = 0.02 + format = "hdf5" + interval_time = 1.0 [output.fields] - quantities = ["Nppc_1", "Nppc_2", "E", "B", "J"] + quantities = ["N_1", "N_2", "B", "E"] + + [output.particles] + enable = false + + [output.spectra] + enable = false + +[diagnostics] + colored_stdout = false diff --git a/setups/srpic/blob/nparts.py b/setups/tests/blob/nparts.py similarity index 100% rename from setups/srpic/blob/nparts.py rename to setups/tests/blob/nparts.py diff --git a/setups/tests/blob/pgen.hpp b/setups/tests/blob/pgen.hpp index d07240bfd..f7b7d71b5 100644 --- a/setups/tests/blob/pgen.hpp +++ b/setups/tests/blob/pgen.hpp @@ -10,107 +10,89 @@ #include "archetypes/energy_dist.h" #include "archetypes/particle_injector.h" #include "archetypes/problem_generator.h" -#include "archetypes/spatial_dist.h" +#include "framework/domain/domain.h" #include "framework/domain/metadomain.h" -#include - namespace user { using namespace ntt; template - struct Beam : public arch::EnergyDistribution { - Beam(const M& metric, - const std::vector& v1_vec, - const std::vector& v2_vec) - : arch::EnergyDistribution { metric } { - std::copy(v1_vec.begin(), v1_vec.end(), v1); - std::copy(v2_vec.begin(), v2_vec.end(), v2); - } - - Inline void operator()(const coord_t&, - vec_t& v_Ph, - unsigned short sp) const override { - if (sp == 1) { - v_Ph[0] = v1[0]; - v_Ph[1] = v1[1]; - v_Ph[2] = v1[2]; - } else { - v_Ph[0] = v2[0]; - v_Ph[1] = v2[1]; - v_Ph[2] = v2[2]; - } + struct CounterstreamEnergyDist : public arch::EnergyDistribution { + CounterstreamEnergyDist(const M& metric, real_t v_max) + : arch::EnergyDistribution { metric } + , v_max { v_max } {} + + Inline void operator()(const coord_t& x_Ph, + vec_t& v, + unsigned short sp) const override { + v[0] = v_max; } private: - vec_t v1; - vec_t v2; + const real_t v_max; }; template - struct PointDistribution : public arch::SpatialDistribution { - PointDistribution(const M& metric, - const std::vector& xi_min, - const std::vector& xi_max) - : arch::SpatialDistribution { metric } { - std::copy(xi_min.begin(), xi_min.end(), x_min); - std::copy(xi_max.begin(), xi_max.end(), x_max); - } - + struct GaussianDist : public arch::SpatialDistribution { + GaussianDist(const M& metric, real_t x1c, real_t x2c, real_t dr) + : arch::SpatialDistribution { metric } + , x1c { x1c } + , x2c { x2c } + , dr { dr } {} + + // to properly scale the number density, the probability should be normalized to 1 Inline auto operator()(const coord_t& x_Ph) const -> real_t override { - auto fill = true; - for (auto d = 0u; d < M::Dim; ++d) { - fill &= x_Ph[d] > x_min[d] and x_Ph[d] < x_max[d]; + if (math::abs(x_Ph[0] - x1c) < dr && math::abs(x_Ph[1] - x2c) < dr) { + return 1.0; + } else { + return 0.0; } - return fill ? ONE : ZERO; } private: - tuple_t x_min; - tuple_t x_max; + const real_t x1c, x2c, dr; }; template struct PGen : public arch::ProblemGenerator { + // compatibility traits for the problem generator - static constexpr auto engines { traits::compatible_with::value }; - static constexpr auto metrics { - traits::compatible_with::value - }; - static constexpr auto dimensions { - traits::compatible_with::value - }; + static constexpr auto engines = traits::compatible_with::value; + static constexpr auto metrics = traits::compatible_with::value; + static constexpr auto dimensions = + traits::compatible_with::value; // for easy access to variables in the child class using arch::ProblemGenerator::D; using arch::ProblemGenerator::C; using arch::ProblemGenerator::params; - const std::vector xi_min; - const std::vector xi_max; - const std::vector v1; - const std::vector v2; - - inline PGen(const SimulationParams& p, const Metadomain& m) - : arch::ProblemGenerator(p) - , xi_min { p.template get>("setup.xi_min") } - , xi_max { p.template get>("setup.xi_max") } - , v1 { p.template get>("setup.v1") } - , v2 { p.template get>("setup.v2") } {} - - inline void InitPrtls(Domain& domain) { - const auto energy_dist = Beam(domain.mesh.metric, v1, v2); - const auto spatial_dist = PointDistribution(domain.mesh.metric, - xi_min, - xi_max); - const auto injector = arch::NonUniformInjector( - energy_dist, - spatial_dist, - { 1, 2 }); - - arch::InjectNonUniform>( + const real_t temp_1, x1c, x2c, dr, v_max; + + inline PGen(const SimulationParams& p, const Metadomain& global_domain) + : arch::ProblemGenerator { p } + , temp_1 { p.template get("setup.temp_1") } + , x1c { p.template get("setup.x1c") } + , x2c { p.template get("setup.x2c") } + , v_max { p.template get("setup.v_max") } + , dr { p.template get("setup.dr") } {} + + inline void InitPrtls(Domain& local_domain) { + const auto energy_dist = CounterstreamEnergyDist(local_domain.mesh.metric, + v_max); + const auto spatial_dist = GaussianDist(local_domain.mesh.metric, + x1c, + x2c, + dr); + const auto injector = + arch::NonUniformInjector( + energy_dist, + spatial_dist, + { 1, 2 }); + + arch::InjectNonUniform>( params, - domain, + local_domain, injector, 1.0); } diff --git a/src/framework/containers/particles.cpp b/src/framework/containers/particles.cpp index 50b410270..d78055824 100644 --- a/src/framework/containers/particles.cpp +++ b/src/framework/containers/particles.cpp @@ -235,60 +235,6 @@ namespace ntt { m_is_sorted = true; } - // template - // void Particles::PrintTags() { - // auto tag_h = Kokkos::create_mirror_view(tag); - // Kokkos::deep_copy(tag_h, tag); - // auto i1_h = Kokkos::create_mirror_view(i1); - // Kokkos::deep_copy(i1_h, i1); - // auto dx1_h = Kokkos::create_mirror_view(dx1); - // Kokkos::deep_copy(dx1_h, dx1); - // std::cout << "species " << label() << " [npart = " << npart() << "]" - // << std::endl; - // std::cout << "idxs: "; - // for (auto i = 0; i < IMIN(tag_h.extent(0), 30); ++i) { - // std::cout << std::setw(3) << i << " "; - // if (i == npart() - 1) { - // std::cout << "| "; - // } - // } - // if (tag_h.extent(0) > 30) { - // std::cout << "... " << std::setw(3) << tag_h.extent(0) - 1; - // } - // std::cout << std::endl << "tags: "; - // for (auto i = 0; i < IMIN(tag_h.extent(0), 30); ++i) { - // std::cout << std::setw(3) << (short)tag_h(i) << " "; - // if (i == npart() - 1) { - // std::cout << "| "; - // } - // } - // if (tag_h.extent(0) > 30) { - // std::cout << "..." << std::setw(3) << (short)tag_h(tag_h.extent(0) - 1); - // } - // std::cout << std::endl << "i1s : "; - // for (auto i = 0; i < IMIN(i1_h.extent(0), 30); ++i) { - // std::cout << std::setw(3) << i1_h(i) << " "; - // if (i == npart() - 1) { - // std::cout << "| "; - // } - // } - // if (i1_h.extent(0) > 30) { - // std::cout << "..." << std::setw(3) << i1_h(i1_h.extent(0) - 1); - // } - // std::cout << std::endl << "dx1s : "; - // for (auto i = 0; i < IMIN(dx1_h.extent(0), 30); ++i) { - // std::cout << std::setprecision(2) << std::setw(3) << dx1_h(i) << " "; - // if (i == npart() - 1) { - // std::cout << "| "; - // } - // } - // if (dx1_h.extent(0) > 30) { - // std::cout << "..." << std::setprecision(2) << std::setw(3) - // << dx1_h(dx1_h.extent(0) - 1); - // } - // std::cout << std::endl; - // } - template struct Particles; template struct Particles; template struct Particles; From 2b6ef3c5542c53225c60e5bd21585cc105fbca58 Mon Sep 17 00:00:00 2001 From: haykh Date: Wed, 29 Jan 2025 12:04:54 -0500 Subject: [PATCH 248/773] tested with/without mpi cpu+hip --- src/framework/tests/particles.cpp | 12 +++-- src/global/tests/kokkos_aliases.cpp | 6 +-- src/kernels/particle_pusher_sr.hpp | 70 ++++++++++++++--------------- src/kernels/tests/deposit.cpp | 40 ++++++----------- src/kernels/tests/prtl_bc.cpp | 18 ++++---- 5 files changed, 68 insertions(+), 78 deletions(-) diff --git a/src/framework/tests/particles.cpp b/src/framework/tests/particles.cpp index 535198286..6c4c227b5 100644 --- a/src/framework/tests/particles.cpp +++ b/src/framework/tests/particles.cpp @@ -46,8 +46,10 @@ void testParticles(const int& index, raise::ErrorIf(p.tag.extent(0) != maxnpart, "tag incorrectly allocated", HERE); raise::ErrorIf(p.weight.extent(0) != maxnpart, "weight incorrectly allocated", HERE); - raise::ErrorIf(p.pld.extent(1) != npld, "pld incorrectly allocated", HERE); - raise::ErrorIf(p.pld.extent(0) != maxnpart, "pld incorrectly allocated", HERE); + if (npld > 0) { + raise::ErrorIf(p.pld.extent(0) != maxnpart, "pld incorrectly allocated", HERE); + raise::ErrorIf(p.pld.extent(1) != npld, "pld incorrectly allocated", HERE); + } if constexpr ((D == Dim::_2D) || (D == Dim::_3D)) { raise::ErrorIf(p.i2.extent(0) != maxnpart, "i2 incorrectly allocated", HERE); @@ -115,7 +117,8 @@ auto main(int argc, char** argv) -> int { 0.0, 100, PrtlPusher::PHOTON, - Cooling::NONE); + Cooling::NONE, + 5); testParticles(4, "e+", 1.0, @@ -129,7 +132,8 @@ auto main(int argc, char** argv) -> int { 1.0, 100, PrtlPusher::BORIS, - Cooling::NONE); + Cooling::NONE, + 1); } catch (const std::exception& e) { std::cerr << "Error: " << e.what() << std::endl; Kokkos::finalize(); diff --git a/src/global/tests/kokkos_aliases.cpp b/src/global/tests/kokkos_aliases.cpp index 56a17c50f..909b6b30c 100644 --- a/src/global/tests/kokkos_aliases.cpp +++ b/src/global/tests/kokkos_aliases.cpp @@ -3,6 +3,7 @@ #include "global.h" #include +#include #include #include @@ -44,8 +45,7 @@ auto main(int argc, char* argv[]) -> int { { // scatter arrays & ranges array_t a { "a", 100 }; - scatter_array_t a_scatter = Kokkos::Experimental::create_scatter_view( - a); + auto a_scatter = Kokkos::Experimental::create_scatter_view(a); Kokkos::parallel_for( // range_t({ 0 }, { 100 }), CreateRangePolicy({ 0 }, { 100 }), @@ -87,4 +87,4 @@ auto main(int argc, char* argv[]) -> int { Kokkos::finalize(); return 0; -} \ No newline at end of file +} diff --git a/src/kernels/particle_pusher_sr.hpp b/src/kernels/particle_pusher_sr.hpp index b4808f12a..2e8a5f652 100644 --- a/src/kernels/particle_pusher_sr.hpp +++ b/src/kernels/particle_pusher_sr.hpp @@ -227,41 +227,41 @@ namespace kernel::sr { const real_t coeff_sync; public: - Pusher_kernel(const PrtlPusher::type& pusher, - bool GCA, - bool ext_force, - CoolingTags cooling, - const ndfield_t& EB, - unsigned short sp, - array_t& i1, - array_t& i2, - array_t& i3, - array_t& i1_prev, - array_t& i2_prev, - array_t& i3_prev, - array_t& dx1, - array_t& dx2, - array_t& dx3, - array_t& dx1_prev, - array_t& dx2_prev, - array_t& dx3_prev, - array_t& ux1, - array_t& ux2, - array_t& ux3, - array_t& phi, - array_t& tag, - const M& metric, - const F& force, - real_t time, - real_t coeff, - real_t dt, - int ni1, - int ni2, - int ni3, - const boundaries_t& boundaries, - real_t gca_larmor_max, - real_t gca_eovrb_max, - real_t coeff_sync) + Pusher_kernel(const PrtlPusher::type& pusher, + bool GCA, + bool ext_force, + CoolingTags cooling, + const randacc_ndfield_t& EB, + unsigned short sp, + array_t& i1, + array_t& i2, + array_t& i3, + array_t& i1_prev, + array_t& i2_prev, + array_t& i3_prev, + array_t& dx1, + array_t& dx2, + array_t& dx3, + array_t& dx1_prev, + array_t& dx2_prev, + array_t& dx3_prev, + array_t& ux1, + array_t& ux2, + array_t& ux3, + array_t& phi, + array_t& tag, + const M& metric, + const F& force, + real_t time, + real_t coeff, + real_t dt, + int ni1, + int ni2, + int ni3, + const boundaries_t& boundaries, + real_t gca_larmor_max, + real_t gca_eovrb_max, + real_t coeff_sync) : pusher { pusher } , GCA { GCA } , ext_force { ext_force } diff --git a/src/kernels/tests/deposit.cpp b/src/kernels/tests/deposit.cpp index 9a8ae1cc6..ec364a313 100644 --- a/src/kernels/tests/deposit.cpp +++ b/src/kernels/tests/deposit.cpp @@ -29,8 +29,7 @@ void errorIf(bool condition, const std::string& message) { inline static constexpr auto epsilon = std::numeric_limits::epsilon(); -Inline auto equal(real_t a, real_t b, const char* msg = "", real_t acc = ONE) - -> bool { +Inline auto equal(real_t a, real_t b, const char* msg = "", real_t acc = ONE) -> bool { const auto eps = epsilon * acc; if (not cmp::AlmostEqual(a, b, eps)) { printf("%.12e != %.12e %s\n", a, b, msg); @@ -81,8 +80,6 @@ void testDeposit(const std::vector& res, array_t tag { "tag", 10 }; const real_t charge { 1.0 }, inv_dt { 1.0 }; - auto J_scat = Kokkos::Experimental::create_scatter_view(J); - const int i0 = 4, j0 = 4; const prtldx_t dxi = 0.53, dxf = 0.47; @@ -122,30 +119,19 @@ void testDeposit(const std::vector& res, put_value(weight, 1.0, 0); put_value(tag, ParticleTag::alive, 0); - Kokkos::parallel_for("CurrentsDeposit", - 10, + auto J_scat = Kokkos::Experimental::create_scatter_view(J); + + // clang-format off + Kokkos::parallel_for("CurrentsDeposit", 10, kernel::DepositCurrents_kernel(J_scat, - i1, - i2, - i3, - i1_prev, - i2_prev, - i3_prev, - dx1, - dx2, - dx3, - dx1_prev, - dx2_prev, - dx3_prev, - ux1, - ux2, - ux3, - phi, - weight, - tag, - metric, - charge, - inv_dt)); + i1, i2, i3, + i1_prev, i2_prev, i3_prev, + dx1, dx2, dx3, + dx1_prev, dx2_prev, dx3_prev, + ux1, ux2, ux3, + phi, weight, tag, + metric, charge, inv_dt)); + // clang-format on Kokkos::Experimental::contribute(J, J_scat); diff --git a/src/kernels/tests/prtl_bc.cpp b/src/kernels/tests/prtl_bc.cpp index c8f9eae04..14c1a9f54 100644 --- a/src/kernels/tests/prtl_bc.cpp +++ b/src/kernels/tests/prtl_bc.cpp @@ -201,9 +201,9 @@ void testPeriodicBC(const std::vector& res, // Particle boundaries auto boundaries = boundaries_t {}; boundaries = { - {PrtlBC::PERIODIC, PrtlBC::PERIODIC}, - {PrtlBC::PERIODIC, PrtlBC::PERIODIC}, - {PrtlBC::PERIODIC, PrtlBC::PERIODIC} + { PrtlBC::PERIODIC, PrtlBC::PERIODIC }, + { PrtlBC::PERIODIC, PrtlBC::PERIODIC }, + { PrtlBC::PERIODIC, PrtlBC::PERIODIC } }; real_t time = ZERO; @@ -343,18 +343,18 @@ auto main(int argc, char* argv[]) -> int { const std::vector res1d { 50 }; const boundaries_t ext1d { - {0.0, 1000.0}, + { 0.0, 1000.0 }, }; const std::vector res2d { 30, 20 }; const boundaries_t ext2d { - {-15.0, 15.0}, - {-10.0, 10.0}, + { -15.0, 15.0 }, + { -10.0, 10.0 }, }; const std::vector res3d { 10, 10, 10 }; const boundaries_t ext3d { - {0.0, 1.0}, - {0.0, 1.0}, - {0.0, 1.0} + { 0.0, 1.0 }, + { 0.0, 1.0 }, + { 0.0, 1.0 } }; testPeriodicBC>(res1d, ext1d, {}); testPeriodicBC>(res2d, ext2d, {}); From 08bc485edcf98f0948fe92b0b60b0127799fdda1 Mon Sep 17 00:00:00 2001 From: hayk Date: Wed, 29 Jan 2025 14:16:29 -0500 Subject: [PATCH 249/773] rm conflicting file --- src/engines/engine_step_report.cpp | 293 ----------------------------- 1 file changed, 293 deletions(-) delete mode 100644 src/engines/engine_step_report.cpp diff --git a/src/engines/engine_step_report.cpp b/src/engines/engine_step_report.cpp deleted file mode 100644 index 1681aabcc..000000000 --- a/src/engines/engine_step_report.cpp +++ /dev/null @@ -1,293 +0,0 @@ -#include "enums.h" -#include "global.h" - -#include "arch/mpi_aliases.h" -#include "utils/colors.h" -#include "utils/formatting.h" -#include "utils/progressbar.h" -#include "utils/timer.h" - -#include "metrics/kerr_schild.h" -#include "metrics/kerr_schild_0.h" -#include "metrics/minkowski.h" -#include "metrics/qkerr_schild.h" -#include "metrics/qspherical.h" -#include "metrics/spherical.h" - -#include "engines/engine.hpp" - -#include -#include - -namespace ntt { - namespace {} // namespace - - template - void print_particles(const Metadomain&, - unsigned short, - DiagFlags, - std::ostream& = std::cout); - - template - void Engine::print_step_report(timer::Timers& timers, - pbar::DurationHistory& time_history, - bool print_output, - bool print_sorting) const { - DiagFlags diag_flags = Diag::Default; - TimerFlags timer_flags = Timer::Default; - if (not m_params.get("diagnostics.colored_stdout")) { - diag_flags ^= Diag::Colorful; - timer_flags ^= Timer::Colorful; - } - if (m_params.get("particles.nspec") == 0) { - diag_flags ^= Diag::Species; - } - if (print_output) { - timer_flags |= Timer::PrintOutput; - } - if (print_sorting) { - timer_flags |= Timer::PrintSorting; - } - CallOnce( - [diag_flags](auto& time, auto& step, auto& max_steps, auto& dt) { - const auto c_bgreen = color::get_color("bgreen", - diag_flags & Diag::Colorful); - const auto c_bblack = color::get_color("bblack", - diag_flags & Diag::Colorful); - const auto c_reset = color::get_color("reset", diag_flags & Diag::Colorful); - std::cout << fmt::format("Step:%s %-8d%s %s[of %d]%s\n", - c_bgreen.c_str(), - step, - c_reset.c_str(), - c_bblack.c_str(), - max_steps, - c_reset.c_str()); - std::cout << fmt::format("Time:%s %-8.4f%s %s[Δt = %.4f]%s\n", - c_bgreen.c_str(), - (double)time, - c_reset.c_str(), - c_bblack.c_str(), - (double)dt, - c_reset.c_str()) - << std::endl; - }, - time, - step, - max_steps, - dt); - if (diag_flags & Diag::Timers) { - timers.printAll(timer_flags, std::cout); - } - CallOnce([]() { - std::cout << std::endl; - }); - if (diag_flags & Diag::Species) { - CallOnce([diag_flags]() { - std::cout << color::get_color("bblack", diag_flags & Diag::Colorful); -#if defined(MPI_ENABLED) - std::cout << "Particle count:" << std::setw(22) << std::right << "[TOT]" - << std::setw(20) << std::right << "[MIN (%)]" << std::setw(20) - << std::right << "[MAX (%)]"; -#else - std::cout << "Particle count:" << std::setw(25) << std::right - << "[TOT (%)]"; -#endif - std::cout << color::get_color("reset", diag_flags & Diag::Colorful) - << std::endl; - }); - for (std::size_t sp { 0 }; sp < m_metadomain.species_params().size(); ++sp) { - print_particles(m_metadomain, sp, diag_flags, std::cout); - } - CallOnce([]() { - std::cout << std::endl; - }); - } - if (diag_flags & Diag::Progress) { - pbar::ProgressBar(time_history, step, max_steps, diag_flags, std::cout); - } - CallOnce([]() { - std::cout << std::setw(80) << std::setfill('.') << "" << std::endl - << std::endl; - }); - } - - template - void print_particles(const Metadomain& md, - unsigned short sp, - DiagFlags flags, - std::ostream& os) { - - static_assert(M::is_metric, "template arg for Engine class has to be a metric"); - std::size_t npart { 0 }; - std::size_t maxnpart { 0 }; - std::string species_label; - int species_index; - // sum npart & maxnpart over all subdomains on the current rank - md.runOnLocalDomainsConst( - [&npart, &maxnpart, &species_label, &species_index, sp](auto& dom) { - npart += dom.species[sp].npart(); - maxnpart += dom.species[sp].maxnpart(); - species_label = dom.species[sp].label(); - species_index = dom.species[sp].index(); - }); -#if defined(MPI_ENABLED) - int rank, size; - MPI_Comm_rank(MPI_COMM_WORLD, &rank); - MPI_Comm_size(MPI_COMM_WORLD, &size); - std::vector mpi_npart(size, 0); - std::vector mpi_maxnpart(size, 0); - MPI_Gather(&npart, - 1, - mpi::get_type(), - mpi_npart.data(), - 1, - mpi::get_type(), - MPI_ROOT_RANK, - MPI_COMM_WORLD); - MPI_Gather(&maxnpart, - 1, - mpi::get_type(), - mpi_maxnpart.data(), - 1, - mpi::get_type(), - MPI_ROOT_RANK, - MPI_COMM_WORLD); - if (rank != MPI_ROOT_RANK) { - return; - } - auto tot_npart = std::accumulate(mpi_npart.begin(), mpi_npart.end(), 0); - std::size_t npart_max = *std::max_element(mpi_npart.begin(), mpi_npart.end()); - std::size_t npart_min = *std::min_element(mpi_npart.begin(), mpi_npart.end()); - std::vector mpi_load(size, 0.0); - for (auto r { 0 }; r < size; ++r) { - mpi_load[r] = 100.0 * (double)(mpi_npart[r]) / (double)(mpi_maxnpart[r]); - } - double load_max = *std::max_element(mpi_load.begin(), mpi_load.end()); - double load_min = *std::min_element(mpi_load.begin(), mpi_load.end()); - auto npart_min_str = npart_min > 9999 - ? fmt::format("%.2Le", (long double)npart_min) - : std::to_string(npart_min); - auto tot_npart_str = tot_npart > 9999 - ? fmt::format("%.2Le", (long double)tot_npart) - : std::to_string(tot_npart); - auto npart_max_str = npart_max > 9999 - ? fmt::format("%.2Le", (long double)npart_max) - : std::to_string(npart_max); - os << " species " << fmt::format("%2d", species_index) << " (" - << species_label << ")"; - - const auto c_bblack = color::get_color("bblack", flags & Diag::Colorful); - const auto c_red = color::get_color("red", flags & Diag::Colorful); - const auto c_yellow = color::get_color("yellow", flags & Diag::Colorful); - const auto c_green = color::get_color("green", flags & Diag::Colorful); - const auto c_reset = color::get_color("reset", flags & Diag::Colorful); - auto c_loadmin = (load_min > 80) ? c_red - : ((load_min > 50) ? c_yellow : c_green); - auto c_loadmax = (load_max > 80) ? c_red - : ((load_max > 50) ? c_yellow : c_green); - const auto raw1 = fmt::format("%s (%4.1f%%)", npart_min_str.c_str(), load_min); - const auto raw2 = fmt::format("%s (%4.1f%%)", npart_max_str.c_str(), load_max); - os << c_bblack - << fmt::pad(tot_npart_str, 20, '.', false).substr(0, 20 - tot_npart_str.size()) - << c_reset << tot_npart_str; - os << fmt::pad(raw1, 20, ' ', false).substr(0, 20 - raw1.size()) - << fmt::format("%s (%s%4.1f%%%s)", - npart_min_str.c_str(), - c_loadmin.c_str(), - load_min, - c_reset.c_str()); - os << fmt::pad(raw2, 20, ' ', false).substr(0, 20 - raw2.size()) - << fmt::format("%s (%s%4.1f%%%s)", - npart_max_str.c_str(), - c_loadmax.c_str(), - load_max, - c_reset.c_str()); -#else // not MPI_ENABLED - auto load = 100.0 * (double)(npart) / (double)(maxnpart); - auto npart_str = npart > 9999 ? fmt::format("%.2Le", (long double)npart) - : std::to_string(npart); - const auto c_bblack = color::get_color("bblack", flags & Diag::Colorful); - const auto c_red = color::get_color("red", flags & Diag::Colorful); - const auto c_yellow = color::get_color("yellow", flags & Diag::Colorful); - const auto c_green = color::get_color("green", flags & Diag::Colorful); - const auto c_reset = color::get_color("reset", flags & Diag::Colorful); - const auto c_load = (load > 80) - ? c_red.c_str() - : ((load > 50) ? c_yellow.c_str() : c_green.c_str()); - os << " species " << species_index << " (" << species_label << ")"; - const auto raw = fmt::format("%s (%4.1f%%)", npart_str.c_str(), load); - os << c_bblack << fmt::pad(raw, 24, '.').substr(0, 24 - raw.size()) << c_reset; - os << fmt::format("%s (%s%4.1f%%%s)", - npart_str.c_str(), - c_load, - load, - c_reset.c_str()); -#endif - os << std::endl; - } - - template void Engine>::print_step_report(timer::Timers&,pbar::DurationHistory&,bool,bool) const; - template void Engine>::print_step_report(timer::Timers&,pbar::DurationHistory&,bool,bool) const; - template void Engine>::print_step_report(timer::Timers&,pbar::DurationHistory&,bool,bool) const; - template void Engine>::print_step_report(timer::Timers&,pbar::DurationHistory&,bool,bool) const; - template void Engine>::print_step_report(timer::Timers&,pbar::DurationHistory&,bool,bool) const; - template void Engine>::print_step_report(timer::Timers&,pbar::DurationHistory&,bool,bool) const; - template void Engine>::print_step_report(timer::Timers&,pbar::DurationHistory&,bool,bool) const; - template void Engine>::print_step_report(timer::Timers&,pbar::DurationHistory&,bool,bool) const; -} // namespace ntt - -// template -// auto Simulation::PrintDiagnostics(const std::size_t& step, -// const real_t& time, -// const timer::Timers& timers, -// std::vector& tstep_durations, -// const DiagFlags diag_flags, -// std::ostream& os) -> void { -// if (tstep_durations.size() > m_params.diagMaxnForPbar()) { -// tstep_durations.erase(tstep_durations.begin()); -// } -// tstep_durations.push_back(timers.get("Total")); -// if (step % m_params.diagInterval() == 0) { -// auto& mblock = this->meshblock; -// const auto title { -// fmt::format("Time = %f : step = %d : Δt = %f", time, step, mblock.timestep()) -// }; -// PrintOnce( -// [](std::ostream& os, std::string title) { -// os << title << std::endl; -// }, -// os, -// title); -// if (diag_flags & DiagFlags_Timers) { -// timers.printAll("", timer::TimerFlags_Default, os); -// } -// if (diag_flags & DiagFlags_Species) { -// auto header = fmt::format("%s %27s", "[SPECIES]", "[TOT]"); -// #if defined(MPI_ENABLED) -// header += fmt::format("%17s %s", "[MIN (%) :", "MAX (%)]"); -// #endif -// PrintOnce( -// [](std::ostream& os, std::string header) { -// os << header << std::endl; -// }, -// os, -// header); -// for (const auto& species : meshblock.particles) { -// species.PrintParticleCounts(os); -// } -// } -// if (diag_flags & DiagFlags_Progress) { -// PrintOnce( -// [](std::ostream& os) { -// os << std::setw(65) << std::setfill('-') << "" << std::endl; -// }, -// os); -// ProgressBar(tstep_durations, time, m_params.totalRuntime(), os); -// } -// PrintOnce( -// [](std::ostream& os) { -// os << std::setw(65) << std::setfill('=') << "" << std::endl; -// }, -// os); -// } -// } From c9b4591f03601c2e8bf472e68435d7eacc59e063 Mon Sep 17 00:00:00 2001 From: haykh Date: Wed, 29 Jan 2025 14:26:20 -0500 Subject: [PATCH 250/773] nix-shell upd --- dev/nix/shell.nix | 49 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 dev/nix/shell.nix diff --git a/dev/nix/shell.nix b/dev/nix/shell.nix new file mode 100644 index 000000000..1f21e82b0 --- /dev/null +++ b/dev/nix/shell.nix @@ -0,0 +1,49 @@ +{ + pkgs ? import { }, + mpi ? false, + hdf5 ? false, + gpu ? "none", + arch ? "native", +}: + +let + name = "entity-dev"; + adios2Pkg = (pkgs.callPackage ./adios2.nix { inherit pkgs mpi hdf5; }); + kokkosPkg = (pkgs.callPackage ./kokkos.nix { inherit pkgs arch gpu; }); +in +pkgs.mkShell { + name = "${name}-env"; + nativeBuildInputs = with pkgs; [ + zlib + cmake + + clang-tools + + adios2Pkg + kokkosPkg + + python312 + python312Packages.jupyter + + cmake-format + cmake-lint + neocmakelsp + black + pyright + taplo + vscode-langservers-extracted + ]; + + LD_LIBRARY_PATH = pkgs.lib.makeLibraryPath ([ + pkgs.stdenv.cc.cc + pkgs.zlib + ]); + + shellHook = '' + BLUE='\033[0;34m' + NC='\033[0m' + + echo "" + echo -e "${name} nix-shell activated" + ''; +} From c89ea772902c0c427774250001f4da4a81892c88 Mon Sep 17 00:00:00 2001 From: haykh Date: Wed, 29 Jan 2025 14:37:07 -0500 Subject: [PATCH 251/773] kokkos v4.5.01 fixed --- extern/Kokkos | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extern/Kokkos b/extern/Kokkos index 5fc08a9a7..175257a51 160000 --- a/extern/Kokkos +++ b/extern/Kokkos @@ -1 +1 @@ -Subproject commit 5fc08a9a7da14d8530f8c7035d008ef63ddb4e5c +Subproject commit 175257a51ff29a0059ec48bcd233ee096b2c0438 From e1d7d522ad22e00175721332d85b6a1f63689d69 Mon Sep 17 00:00:00 2001 From: haykh Date: Wed, 29 Jan 2025 14:37:45 -0500 Subject: [PATCH 252/773] adios v2.10.2 fixed --- extern/adios2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extern/adios2 b/extern/adios2 index a6e8314cc..a19dad6ce 160000 --- a/extern/adios2 +++ b/extern/adios2 @@ -1 +1 @@ -Subproject commit a6e8314cc3c0b28d496b44dcd4f15685013b887b +Subproject commit a19dad6cecb00319825f20fd9f455ebbab903d34 From 3e6a01e83bb370e006f9feacbe344618ed5f32d7 Mon Sep 17 00:00:00 2001 From: haykh Date: Wed, 29 Jan 2025 14:38:32 -0500 Subject: [PATCH 253/773] plog v1.1.10 fixed --- extern/plog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extern/plog b/extern/plog index 85a871b13..e21baecd4 160000 --- a/extern/plog +++ b/extern/plog @@ -1 +1 @@ -Subproject commit 85a871b13be0bd1a9e0110744fa60cc9bd1e8380 +Subproject commit e21baecd4753f14da64ede979c5a19302618b752 From e99bf5d04087acea3807757a713189c5246e4a67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20B=C3=B6ss?= Date: Wed, 13 Nov 2024 14:25:01 -0600 Subject: [PATCH 254/773] fix bug in Bfield setup --- setups/srpic/shock/pgen.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setups/srpic/shock/pgen.hpp b/setups/srpic/shock/pgen.hpp index 1eedb3a01..55dffb5d9 100644 --- a/setups/srpic/shock/pgen.hpp +++ b/setups/srpic/shock/pgen.hpp @@ -28,7 +28,7 @@ namespace user { @param drift_ux: drift velocity in the x direction */ InitFields(real_t bmag, real_t btheta, real_t bphi, real_t drift_ux) - : Bmag { bmag * static_cast(convert::deg2rad) } + : Bmag { bmag } , Btheta { btheta * static_cast(convert::deg2rad) } , Bphi { bphi * static_cast(convert::deg2rad) } , Vx { drift_ux } {} From 4374f94f6e0bc684f3f7ac63328cfdbb29461135 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20B=C3=B6ss?= Date: Wed, 13 Nov 2024 14:56:50 -0600 Subject: [PATCH 255/773] switch BCs to be consistent with Tristan --- setups/srpic/shock/shock.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setups/srpic/shock/shock.toml b/setups/srpic/shock/shock.toml index c8a6f7c9d..4ed3a2b9e 100644 --- a/setups/srpic/shock/shock.toml +++ b/setups/srpic/shock/shock.toml @@ -11,7 +11,7 @@ metric = "minkowski" [grid.boundaries] - fields = [["FIXED", "ABSORB"], ["PERIODIC"]] + fields = [["ABSORB", "FIXED"], ["PERIODIC"]] particles = [["REFLECT", "ABSORB"], ["PERIODIC"]] [scales] From 2fbf906457e6e8e2bde54ff6ed7116d277581067 Mon Sep 17 00:00:00 2001 From: haykh Date: Wed, 29 Jan 2025 14:48:25 -0500 Subject: [PATCH 256/773] rebase --- input.example.toml | 20 +- setups/srpic/shock/pgen.hpp | 19 +- setups/wip/magpump/pgen.hpp | 170 +++++++++ src/engines/srpic.hpp | 186 +++++---- src/framework/parameters.cpp | 50 ++- src/global/arch/traits.h | 19 +- src/global/defaults.h | 6 +- src/global/enums.h | 8 +- src/global/global.h | 13 + src/global/tests/enums.cpp | 2 +- src/kernels/fields_bcs.hpp | 715 +++++++++++++++++++++++++---------- 11 files changed, 889 insertions(+), 319 deletions(-) create mode 100644 setups/wip/magpump/pgen.hpp diff --git a/input.example.toml b/input.example.toml index c5622d65a..3f367995a 100644 --- a/input.example.toml +++ b/input.example.toml @@ -90,11 +90,11 @@ # Boundary conditions for fields: # @required # @type: 1/2/3-size array of string tuples, each of size 1 or 2 - # @valid: "PERIODIC", "ABSORB", "FIXED", "ATMOSPHERE", "CUSTOM", "HORIZON" - # @example: [["CUSTOM", "ABSORB"]] (for 2D spherical [[rmin, rmax]]) + # @valid: "PERIODIC", "MATCH", "FIXED", "ATMOSPHERE", "CUSTOM", "HORIZON" + # @example: [["CUSTOM", "MATCH"]] (for 2D spherical [[rmin, rmax]]) # @note: When periodic in any of the directions, you should only set one value: [..., ["PERIODIC"], ...] - # @note: In spherical, bondaries in theta/phi are set automatically (only specify bc @ [rmin, rmax]): [["ATMOSPHERE", "ABSORB"]] - # @note: In GR, the horizon boundary is set automatically (only specify bc @ rmax): [["ABSORB"]] + # @note: In spherical, bondaries in theta/phi are set automatically (only specify bc @ [rmin, rmax]): [["ATMOSPHERE", "match"]] + # @note: In GR, the horizon boundary is set automatically (only specify bc @ rmax): [["match"]] fields = "" # Boundary conditions for fields: # @required @@ -106,8 +106,8 @@ # @note: In GR, the horizon boundary is set automatically (only specify bc @ rmax): [["ABSORB"]] particles = "" - [grid.boundaries.absorb] - # Size of the absorption layer in physical (code) units: + [grid.boundaries.match] + # Size of the matching layer for fields in physical (code) units: # @type: float # @default: 1% of the domain size (in shortest dimension) # @note: In spherical, this is the size of the layer in r from the outer wall @@ -118,6 +118,14 @@ # @default: 1.0 coeff = "" + [grid.boundaries.absorb] + # Size of the absorption layer for particles in physical (code) units: + # @type: float + # @default: 1% of the domain size (in shortest dimension) + # @note: In spherical, this is the size of the layer in r from the outer wall + # @note: In cartesian, this is the same for all dimensions where applicable + ds = "" + [grid.boundaries.atmosphere] # @required: if ATMOSPHERE is one of the boundaries # Temperature of the atmosphere in units of m0 c^2 diff --git a/setups/srpic/shock/pgen.hpp b/setups/srpic/shock/pgen.hpp index 55dffb5d9..b8f169521 100644 --- a/setups/srpic/shock/pgen.hpp +++ b/setups/srpic/shock/pgen.hpp @@ -13,6 +13,8 @@ #include "archetypes/problem_generator.h" #include "framework/domain/metadomain.h" +#include + namespace user { using namespace ntt; @@ -93,20 +95,21 @@ namespace user { inline PGen() {} - auto FixField(const em& comp) const -> real_t { + auto FixFieldsConst(const bc_in&, const em& comp) const + -> std::pair { if (comp == em::ex2) { - return init_flds.ex2({ ZERO }); + return { init_flds.ex2({ ZERO }), true }; } else if (comp == em::ex3) { - return init_flds.ex3({ ZERO }); - } else if (comp == em::bx1) { - return init_flds.bx1({ ZERO }); + return { init_flds.ex3({ ZERO }), true }; } else { - raise::Error("Other components should not be requested when BC is in X", - HERE); - return ZERO; + return { ZERO, false }; } } + auto MatchFields(real_t time) const -> InitFields { + return init_flds; + } + inline void InitPrtls(Domain& local_domain) { const auto energy_dist = arch::Maxwellian(local_domain.mesh.metric, local_domain.random_pool, diff --git a/setups/wip/magpump/pgen.hpp b/setups/wip/magpump/pgen.hpp new file mode 100644 index 000000000..21d4c8882 --- /dev/null +++ b/setups/wip/magpump/pgen.hpp @@ -0,0 +1,170 @@ +#ifndef PROBLEM_GENERATOR_H +#define PROBLEM_GENERATOR_H + +#include "enums.h" +#include "global.h" + +#include "arch/traits.h" + +#include "archetypes/particle_injector.h" +#include "archetypes/problem_generator.h" +#include "framework/domain/metadomain.h" + +#include + +namespace user { + using namespace ntt; + + template + struct InitFields { + InitFields(real_t bsurf, real_t rstar) : Bsurf { bsurf }, Rstar { rstar } {} + + Inline auto bx1(const coord_t& x_Ph) const -> real_t { + return Bsurf * math::cos(x_Ph[1]) / CUBE(x_Ph[0] / Rstar); + } + + Inline auto bx2(const coord_t& x_Ph) const -> real_t { + return Bsurf * HALF * math::sin(x_Ph[1]) / CUBE(x_Ph[0] / Rstar); + } + + private: + const real_t Bsurf, Rstar; + }; + + template + struct DriveFields : public InitFields { + DriveFields(real_t time, real_t bsurf, real_t rstar) + : InitFields { bsurf, rstar } + , time { time } {} + + using InitFields::bx1; + using InitFields::bx2; + + Inline auto bx3(const coord_t&) const -> real_t { + return ZERO; + } + + Inline auto ex1(const coord_t&) const -> real_t { + return ZERO; + } + + Inline auto ex2(const coord_t& x_Ph) const -> real_t { + return ZERO; + } + + Inline auto ex3(const coord_t&) const -> real_t { + return ZERO; + } + + private: + const real_t time; + }; + + template + struct Inflow : public arch::EnergyDistribution { + Inflow(const M& metric, real_t vin) + : arch::EnergyDistribution { metric } + , vin { vin } {} + + Inline void operator()(const coord_t&, + vec_t& v_Ph, + unsigned short) const override { + v_Ph[0] = -vin; + } + + private: + const real_t vin; + }; + + template + struct Sphere : public arch::SpatialDistribution { + Sphere(const M& metric, real_t r0, real_t dr) + : arch::SpatialDistribution { metric } + , r0 { r0 } + , dr { dr } {} + + Inline auto operator()(const coord_t& x_Ph) const -> real_t override { + return math::exp(-SQR((x_Ph[0] - r0) / dr)) * + (x_Ph[1] > 0.25 && x_Ph[1] < constant::PI - 0.25); + } + + private: + const real_t r0, dr; + }; + + template + struct PGen : public arch::ProblemGenerator { + static constexpr auto engines { traits::compatible_with::value }; + static constexpr auto metrics { + traits::compatible_with::value + }; + static constexpr auto dimensions { traits::compatible_with::value }; + + using arch::ProblemGenerator::D; + using arch::ProblemGenerator::C; + using arch::ProblemGenerator::params; + + const real_t Bsurf, pump_period, pump_ampl, pump_radius, Rstar; + const real_t vin, drinj; + InitFields init_flds; + + inline PGen(const SimulationParams& p, const Metadomain& m) + : arch::ProblemGenerator { p } + , Bsurf { p.template get("setup.Bsurf", ONE) } + , pump_period { p.template get("setup.pump_period") } + , pump_ampl { p.template get("setup.pump_ampl") } + , pump_radius { p.template get("setup.pump_radius") } + , Rstar { m.mesh().extent(in::x1).first } + , vin { p.template get("setup.vin") } + , drinj { p.template get("setup.drinj") } + , init_flds { Bsurf, Rstar } {} + + auto FieldDriver(real_t time) const -> DriveFields { + return DriveFields { time, Bsurf, Rstar }; + } + + void CustomPostStep(std::size_t, long double time, Domain& domain) { + const real_t radius = pump_radius + + pump_ampl * + math::sin(time * constant::TWO_PI / pump_period); + const real_t dr = 1.0; + const auto& metric = domain.mesh.metric; + auto EM = domain.fields.em; + Kokkos::parallel_for( + "outerBC", + domain.mesh.rangeActiveCells(), + Lambda(index_t i1, index_t i2) { + const auto i1_ = COORD(i1), i2_ = COORD(i2); + const auto r = metric.template convert<1, Crd::Cd, Crd::Ph>(i1_); + if (r > radius - 5 * dr) { + const auto smooth = HALF * (ONE - math::tanh((r - radius) / dr)); + EM(i1, i2, em::ex1) = smooth * EM(i1, i2, em::ex1); + EM(i1, i2, em::ex2) = smooth * EM(i1, i2, em::ex2); + EM(i1, i2, em::ex3) = smooth * EM(i1, i2, em::ex3); + EM(i1, i2, em::bx1) = smooth * EM(i1, i2, em::bx1); + EM(i1, i2, em::bx2) = smooth * EM(i1, i2, em::bx2); + EM(i1, i2, em::bx3) = smooth * EM(i1, i2, em::bx3); + } + }); + + if (time < pump_period * 0.25) { + const auto energy_dist = Inflow(domain.mesh.metric, vin); + const auto spatial_dist = Sphere(domain.mesh.metric, radius, drinj); + const auto injector = arch::NonUniformInjector( + energy_dist, + spatial_dist, + { 1, 2 }); + + arch::InjectNonUniform>( + params, + domain, + injector, + ONE, + true); + } + } + }; + +} // namespace user + +#endif diff --git a/src/engines/srpic.hpp b/src/engines/srpic.hpp index d8cb1e64c..c44f7641c 100644 --- a/src/engines/srpic.hpp +++ b/src/engines/srpic.hpp @@ -584,8 +584,8 @@ namespace ntt { void FieldBoundaries(domain_t& domain, BCTags tags) { for (auto& direction : dir::Directions::orth) { - if (m_metadomain.mesh().flds_bc_in(direction) == FldsBC::ABSORB) { - AbsorbFieldsIn(direction, domain, tags); + if (m_metadomain.mesh().flds_bc_in(direction) == FldsBC::MATCH) { + MatchFieldsIn(direction, domain, tags); } else if (m_metadomain.mesh().flds_bc_in(direction) == FldsBC::AXIS) { if (domain.mesh.flds_bc_in(direction) == FldsBC::AXIS) { AxisFieldsIn(direction, domain, tags); @@ -606,14 +606,13 @@ namespace ntt { } // loop over directions } - void AbsorbFieldsIn(dir::direction_t direction, - domain_t& domain, - BCTags tags) { + void MatchFieldsIn(dir::direction_t direction, + domain_t& domain, + BCTags tags) { /** - * absorbing boundaries + * matching boundaries */ - const auto ds = m_params.template get( - "grid.boundaries.absorb.ds"); + const auto ds = m_params.template get("grid.boundaries.match.ds"); const auto dim = direction.get_dim(); real_t xg_min, xg_max, xg_edge; auto sign = direction.get_sign(); @@ -652,40 +651,49 @@ namespace ntt { range_min[d] = intersect_range[d].first; range_max[d] = intersect_range[d].second; } - if (dim == in::x1) { - Kokkos::parallel_for( - "AbsorbFields", - CreateRangePolicy(range_min, range_max), - kernel::AbsorbBoundaries_kernel(domain.fields.em, - domain.mesh.metric, - xg_edge, - ds, - tags)); - } else if (dim == in::x2) { - if constexpr (M::Dim == Dim::_2D or M::Dim == Dim::_3D) { - Kokkos::parallel_for( - "AbsorbFields", - CreateRangePolicy(range_min, range_max), - kernel::AbsorbBoundaries_kernel(domain.fields.em, - domain.mesh.metric, - xg_edge, - ds, - tags)); - } else { - raise::Error("Invalid dimension", HERE); - } - } else if (dim == in::x3) { - if constexpr (M::Dim == Dim::_3D) { + if constexpr (traits::has_member::value) { + auto match_fields = m_pgen.MatchFields(time); + if (dim == in::x1) { Kokkos::parallel_for( - "AbsorbFields", + "MatchFields", CreateRangePolicy(range_min, range_max), - kernel::AbsorbBoundaries_kernel(domain.fields.em, - domain.mesh.metric, - xg_edge, - ds, - tags)); - } else { - raise::Error("Invalid dimension", HERE); + kernel::MatchBoundaries_kernel( + domain.fields.em, + match_fields, + domain.mesh.metric, + xg_edge, + ds, + tags)); + } else if (dim == in::x2) { + if constexpr (M::Dim == Dim::_2D or M::Dim == Dim::_3D) { + Kokkos::parallel_for( + "MatchFields", + CreateRangePolicy(range_min, range_max), + kernel::MatchBoundaries_kernel( + domain.fields.em, + match_fields, + domain.mesh.metric, + xg_edge, + ds, + tags)); + } else { + raise::Error("Invalid dimension", HERE); + } + } else if (dim == in::x3) { + if constexpr (M::Dim == Dim::_3D) { + Kokkos::parallel_for( + "MatchFields", + CreateRangePolicy(range_min, range_max), + kernel::MatchBoundaries_kernel( + domain.fields.em, + match_fields, + domain.mesh.metric, + xg_edge, + ds, + tags)); + } else { + raise::Error("Invalid dimension", HERE); + } } } } @@ -774,40 +782,51 @@ namespace ntt { if (tags & BC::B) { comps.push_back(normal_b_comp); } - if constexpr (traits::has_member::value) { - raise::Error("Field driver for fixed fields not implemented", HERE); - } else { - // if field driver not present, set fields to fixed values + if constexpr (traits::has_member::value) { + raise::Error("Non-const fixed fields not implemented", HERE); + } else if constexpr ( + traits::has_member::value) { for (const auto& comp : comps) { - auto value = ZERO; + auto value = ZERO; + bool shouldset = false; if constexpr ( - traits::has_member::value) { + traits::has_member::value) { // if fix field function present, read from it - value = m_pgen.FixField((em)comp); + const auto newset = m_pgen.FixFieldsConst( + (bc_in)(sign * ((short)dim + 1)), + (em)comp); + value = newset.first; + shouldset = newset.second; } - if constexpr (M::Dim == Dim::_1D) { - Kokkos::deep_copy(Kokkos::subview(domain.fields.em, - std::make_pair(xi_min[0], xi_max[0]), - comp), - value); - } else if constexpr (M::Dim == Dim::_2D) { - Kokkos::deep_copy(Kokkos::subview(domain.fields.em, - std::make_pair(xi_min[0], xi_max[0]), - std::make_pair(xi_min[1], xi_max[1]), - comp), - value); - } else if constexpr (M::Dim == Dim::_3D) { - Kokkos::deep_copy( - Kokkos::subview(domain.fields.em, - std::make_pair(xi_min[0], xi_max[0]), - std::make_pair(xi_min[1], xi_max[1]), - std::make_pair(xi_min[2], xi_max[2]), - comp), - value); - } else { - raise::Error("Invalid dimension", HERE); + if (shouldset) { + if constexpr (M::Dim == Dim::_1D) { + Kokkos::deep_copy( + Kokkos::subview(domain.fields.em, + std::make_pair(xi_min[0], xi_max[0]), + comp), + value); + } else if constexpr (M::Dim == Dim::_2D) { + Kokkos::deep_copy( + Kokkos::subview(domain.fields.em, + std::make_pair(xi_min[0], xi_max[0]), + std::make_pair(xi_min[1], xi_max[1]), + comp), + value); + } else if constexpr (M::Dim == Dim::_3D) { + Kokkos::deep_copy( + Kokkos::subview(domain.fields.em, + std::make_pair(xi_min[0], xi_max[0]), + std::make_pair(xi_min[1], xi_max[1]), + std::make_pair(xi_min[2], xi_max[2]), + comp), + value); + } else { + raise::Error("Invalid dimension", HERE); + } } } + } else { + raise::Error("Fixed fields not present (both const and non-const)", HERE); } } @@ -817,7 +836,7 @@ namespace ntt { /** * atmosphere field boundaries */ - if constexpr (traits::has_member::value) { + if constexpr (traits::has_member::value) { const auto [sign, dim, xg_min, xg_max] = get_atm_extent(direction); const auto dd = static_cast(dim); boundaries_t box; @@ -846,7 +865,7 @@ namespace ntt { range_min[d] = intersect_range[d].first; range_max[d] = intersect_range[d].second; } - auto field_driver = m_pgen.FieldDriver(time); + auto atm_fields = m_pgen.AtmFields(time); std::size_t il_edge; if (sign > 0) { il_edge = range_min[dd] - N_GHOSTS; @@ -859,9 +878,9 @@ namespace ntt { Kokkos::parallel_for( "AtmosphereBCFields", range, - kernel::EnforcedBoundaries_kernel( + kernel::EnforcedBoundaries_kernel( domain.fields.em, - field_driver, + atm_fields, domain.mesh.metric, il_edge, tags)); @@ -869,9 +888,9 @@ namespace ntt { Kokkos::parallel_for( "AtmosphereBCFields", range, - kernel::EnforcedBoundaries_kernel( + kernel::EnforcedBoundaries_kernel( domain.fields.em, - field_driver, + atm_fields, domain.mesh.metric, il_edge, tags)); @@ -882,9 +901,9 @@ namespace ntt { Kokkos::parallel_for( "AtmosphereBCFields", range, - kernel::EnforcedBoundaries_kernel( + kernel::EnforcedBoundaries_kernel( domain.fields.em, - field_driver, + atm_fields, domain.mesh.metric, il_edge, tags)); @@ -892,9 +911,9 @@ namespace ntt { Kokkos::parallel_for( "AtmosphereBCFields", range, - kernel::EnforcedBoundaries_kernel( + kernel::EnforcedBoundaries_kernel( domain.fields.em, - field_driver, + atm_fields, domain.mesh.metric, il_edge, tags)); @@ -908,9 +927,9 @@ namespace ntt { Kokkos::parallel_for( "AtmosphereBCFields", range, - kernel::EnforcedBoundaries_kernel( + kernel::EnforcedBoundaries_kernel( domain.fields.em, - field_driver, + atm_fields, domain.mesh.metric, il_edge, tags)); @@ -918,9 +937,9 @@ namespace ntt { Kokkos::parallel_for( "AtmosphereBCFields", range, - kernel::EnforcedBoundaries_kernel( + kernel::EnforcedBoundaries_kernel( domain.fields.em, - field_driver, + atm_fields, domain.mesh.metric, il_edge, tags)); @@ -932,8 +951,7 @@ namespace ntt { raise::Error("Invalid dimension", HERE); } } else { - raise::Error("Field driver not implemented in PGEN for atmosphere BCs", - HERE); + raise::Error("Atm fields not implemented in PGEN for atmosphere BCs", HERE); } } diff --git a/src/framework/parameters.cpp b/src/framework/parameters.cpp index 0a605651c..4a9b3056a 100644 --- a/src/framework/parameters.cpp +++ b/src/framework/parameters.cpp @@ -47,7 +47,7 @@ namespace ntt { /* * . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . - * Parameters that must not be changed during after the checkpoint restart + * Parameters that must not be changed during the checkpoint restart * . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ void SimulationParams::setImmutableParams(const toml::value& toml_data) { @@ -322,7 +322,7 @@ namespace ntt { /* * . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . - * Parameters that may be changed during after the checkpoint restart + * Parameters that may be changed during the checkpoint restart * . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . */ void SimulationParams::setMutableParams(const toml::value& toml_data) { @@ -351,9 +351,9 @@ namespace ntt { auto atm_defined = false; for (const auto& bcs : flds_bc) { for (const auto& bc : bcs) { - if (fmt::toLower(bc) == "absorb") { - promiseToDefine("grid.boundaries.absorb.ds"); - promiseToDefine("grid.boundaries.absorb.coeff"); + if (fmt::toLower(bc) == "match") { + promiseToDefine("grid.boundaries.match.ds"); + promiseToDefine("grid.boundaries.match.coeff"); } if (fmt::toLower(bc) == "atmosphere") { raise::ErrorIf(atm_defined, @@ -386,7 +386,6 @@ namespace ntt { for (const auto& bc : bcs) { if (fmt::toLower(bc) == "absorb") { promiseToDefine("grid.boundaries.absorb.ds"); - promiseToDefine("grid.boundaries.absorb.coeff"); } if (fmt::toLower(bc) == "atmosphere") { raise::ErrorIf(atm_defined, @@ -731,6 +730,38 @@ namespace ntt { set("grid.boundaries.fields", flds_bc_pairwise); set("grid.boundaries.particles", prtl_bc_pairwise); + if (isPromised("grid.boundaries.match.ds")) { + if (coord_enum == Coord::Cart) { + auto min_extent = std::numeric_limits::max(); + for (const auto& e : extent_pairwise) { + min_extent = std::min(min_extent, e.second - e.first); + } + set("grid.boundaries.match.ds", + toml::find_or(toml_data, + "grid", + "boundaries", + "match", + "ds", + min_extent * defaults::bc::match::ds_frac)); + } else { + auto r_extent = extent_pairwise[0].second - extent_pairwise[0].first; + set("grid.boundaries.match.ds", + toml::find_or(toml_data, + "grid", + "boundaries", + "match", + "ds", + r_extent * defaults::bc::match::ds_frac)); + } + set("grid.boundaries.match.coeff", + toml::find_or(toml_data, + "grid", + "boundaries", + "match", + "coeff", + defaults::bc::match::coeff)); + } + if (isPromised("grid.boundaries.absorb.ds")) { if (coord_enum == Coord::Cart) { auto min_extent = std::numeric_limits::max(); @@ -754,13 +785,6 @@ namespace ntt { "ds", r_extent * defaults::bc::absorb::ds_frac)); } - set("grid.boundaries.absorb.coeff", - toml::find_or(toml_data, - "grid", - "boundaries", - "absorb", - "coeff", - defaults::bc::absorb::coeff)); } if (isPromised("grid.boundaries.atmosphere.temperature")) { diff --git a/src/global/arch/traits.h b/src/global/arch/traits.h index 9fd40e201..4cde4fca5 100644 --- a/src/global/arch/traits.h +++ b/src/global/arch/traits.h @@ -10,7 +10,11 @@ * - traits::run_t, traits::to_string_t * - traits::pgen::init_flds_t * - traits::pgen::ext_force_t - * - traits::pgen::field_driver_t + * - traits::pgen::atm_fields_t + * - traits::pgen::match_fields_const_t + * - traits::pgen::match_fields_t + * - traits::pgen::fix_fields_const_t + * - traits::pgen::fix_fields_t * - traits::pgen::init_prtls_t * - traits::pgen::custom_fields_t * - traits::pgen::custom_field_output_t @@ -94,10 +98,19 @@ namespace traits { using ext_force_t = decltype(&T::ext_force); template - using field_driver_t = decltype(&T::FieldDriver); + using atm_fields_t = decltype(&T::AtmFields); template - using fix_field_t = decltype(&T::FixField); + using match_fields_t = decltype(&T::MatchFields); + + template + using match_fields_const_t = decltype(&T::MatchFieldsConst); + + template + using fix_fields_t = decltype(&T::FixFields); + + template + using fix_fields_const_t = decltype(&T::FixFieldsConst); template using custom_fields_t = decltype(&T::CustomFields); diff --git a/src/global/defaults.h b/src/global/defaults.h index b7b0107e7..f44fd1844 100644 --- a/src/global/defaults.h +++ b/src/global/defaults.h @@ -41,9 +41,13 @@ namespace ntt::defaults { } // namespace gr namespace bc { - namespace absorb { + namespace match { const real_t ds_frac = 0.01; const real_t coeff = 1.0; + } // namespace match + + namespace absorb { + const real_t ds_frac = 0.01; } // namespace absorb } // namespace bc diff --git a/src/global/enums.h b/src/global/enums.h index 283cb456d..8f2495c13 100644 --- a/src/global/enums.h +++ b/src/global/enums.h @@ -8,7 +8,7 @@ * - enum ntt::SimEngine // SRPIC, GRPIC * - enum ntt::PrtlBC // periodic, absorb, atmosphere, custom, * reflect, horizon, axis, sync - * - enum ntt::FldsBC // periodic, absorb, fixed, atmosphere, + * - enum ntt::FldsBC // periodic, match, fixed, atmosphere, * custom, horizon, axis, sync * - enum ntt::PrtlPusher // boris, vay, photon, none * - enum ntt::Cooling // synchrotron, none @@ -215,7 +215,7 @@ namespace ntt { enum type : uint8_t { INVALID = 0, PERIODIC = 1, - ABSORB = 2, + MATCH = 2, FIXED = 3, ATMOSPHERE = 4, CUSTOM = 5, @@ -226,9 +226,9 @@ namespace ntt { constexpr FldsBC(uint8_t c) : enums_hidden::BaseEnum { c } {} - static constexpr type variants[] = { PERIODIC, ABSORB, FIXED, ATMOSPHERE, + static constexpr type variants[] = { PERIODIC, MATCH, FIXED, ATMOSPHERE, CUSTOM, HORIZON, AXIS, SYNC }; - static constexpr const char* lookup[] = { "periodic", "absorb", "fixed", + static constexpr const char* lookup[] = { "periodic", "match", "fixed", "atmosphere", "custom", "horizon", "axis", "sync" }; static constexpr std::size_t total = sizeof(variants) / sizeof(variants[0]); diff --git a/src/global/global.h b/src/global/global.h index 6669981b6..77fa8c51c 100644 --- a/src/global/global.h +++ b/src/global/global.h @@ -13,6 +13,10 @@ * - enum PrepareOutput * - enum CellLayer // allLayer, activeLayer, minGhostLayer, * minActiveLayer, maxActiveLayer, maxGhostLayer + * - enum Idx // U, D, T, XYZ, Sph, PU, PD + * - enum Crd // Cd, Ph, XYZ, Sph + * - enum in // x1, x2, x3 + * - enum bc_in // Px1, Mx1, Px2, Mx2, Px3, Mx3 * - type box_region_t * - files::LogFile, files::ErrFile, files::InfoFile * - type prtldx_t @@ -184,6 +188,15 @@ enum class in : unsigned short { x3 = 2, }; +enum class bc_in : short { + Mx1 = -1, + Px1 = 1, + Mx2 = -2, + Px2 = 2, + Mx3 = -3, + Px3 = 3, +}; + template using box_region_t = CellLayer[D]; diff --git a/src/global/tests/enums.cpp b/src/global/tests/enums.cpp index 4d678e85e..7785ec1a3 100644 --- a/src/global/tests/enums.cpp +++ b/src/global/tests/enums.cpp @@ -61,7 +61,7 @@ auto main() -> int { enum_str_t all_simulation_engines = { "srpic", "grpic" }; enum_str_t all_particle_bcs = { "periodic", "absorb", "atmosphere", "custom", "reflect", "horizon", "axis", "sync" }; - enum_str_t all_fields_bcs = { "periodic", "absorb", "fixed", "atmosphere", + enum_str_t all_fields_bcs = { "periodic", "match", "fixed", "atmosphere", "custom", "horizon", "axis", "sync" }; enum_str_t all_particle_pushers = { "boris", "vay", "photon", "none" }; enum_str_t all_coolings = { "synchrotron", "none" }; diff --git a/src/kernels/fields_bcs.hpp b/src/kernels/fields_bcs.hpp index 2f2a458bb..4d52dd207 100644 --- a/src/kernels/fields_bcs.hpp +++ b/src/kernels/fields_bcs.hpp @@ -15,61 +15,133 @@ namespace kernel { using namespace ntt; - template - struct AbsorbBoundaries_kernel { + template + struct MatchBoundaries_kernel { static_assert(M::is_metric, "M must be a metric class"); - static_assert(i <= static_cast(M::Dim), + static_assert(static_cast(o) < + static_cast(M::Dim), "Invalid component index"); + static constexpr idx_t i = static_cast(o) + 1u; + static constexpr bool defines_dx1 = traits::has_method::value; + static constexpr bool defines_dx2 = traits::has_method::value; + static constexpr bool defines_dx3 = traits::has_method::value; + static constexpr bool defines_ex1 = traits::has_method::value; + static constexpr bool defines_ex2 = traits::has_method::value; + static constexpr bool defines_ex3 = traits::has_method::value; + static constexpr bool defines_bx1 = traits::has_method::value; + static constexpr bool defines_bx2 = traits::has_method::value; + static constexpr bool defines_bx3 = traits::has_method::value; ndfield_t Fld; + const I fset; const M metric; const real_t xg_edge; const real_t dx_abs; const BCTags tags; - AbsorbBoundaries_kernel(ndfield_t Fld, - const M& metric, - real_t xg_edge, - real_t dx_abs, - BCTags tags) + MatchBoundaries_kernel(ndfield_t Fld, + const I& fset, + const M& metric, + real_t xg_edge, + real_t dx_abs, + BCTags tags) : Fld { Fld } + , fset { fset } , metric { metric } , xg_edge { xg_edge } , dx_abs { dx_abs } , tags { tags } {} + Inline auto shape(const real_t& dx) const -> real_t { + return math::tanh(dx * FOUR / dx_abs); + } + Inline void operator()(index_t i1) const { if constexpr (M::Dim == Dim::_1D) { const auto i1_ = COORD(i1); - for (const auto comp : - { em::ex1, em::ex2, em::ex3, em::bx1, em::bx2, em::bx3 }) { - if ((comp == em::ex1) and not(tags & BC::Ex1)) { - continue; - } else if ((comp == em::ex2) and not(tags & BC::Ex2)) { - continue; - } else if ((comp == em::ex3) and not(tags & BC::Ex3)) { - continue; - } else if ((comp == em::bx1) and not(tags & BC::Bx1)) { - continue; - } else if ((comp == em::bx2) and not(tags & BC::Bx2)) { - continue; - } else if ((comp == em::bx3) and not(tags & BC::Bx3)) { - continue; - } - coord_t x_Cd { ZERO }; - if (comp == em::ex1 or comp == em::bx2 or comp == em::bx3) { - x_Cd[0] = i1_ + HALF; - } else if (comp == em::ex2 or comp == em::bx1 or comp == em::ex3) { - x_Cd[0] = i1_; - } - const auto dx = math::abs( - metric.template convert(x_Cd[i - 1]) - xg_edge); - Fld(i1, comp) *= math::tanh(dx / (INV_4 * dx_abs)); + + coord_t x_Ph_0 { ZERO }; + coord_t x_Ph_H { ZERO }; + metric.template convert({ i1_ }, x_Ph_0); + metric.template convert({ i1_ + HALF }, x_Ph_H); + + if constexpr (S == SimEngine::SRPIC) { + // SRPIC + auto ex1_U { ZERO }, ex2_U { ZERO }, ex3_U { ZERO }, bx1_U { ZERO }, + bx2_U { ZERO }, bx3_U { ZERO }; + if (tags & BC::E) { + if constexpr (defines_ex1) { + ex1_U = metric.template transform<1, Idx::T, Idx::U>( + { i1_ + HALF }, + fset.ex1(x_Ph_H)); + } + if constexpr (defines_ex2) { + ex2_U = metric.template transform<2, Idx::T, Idx::U>( + { i1_ }, + fset.ex2(x_Ph_0)); + } + if constexpr (defines_ex3) { + ex3_U = metric.template transform<3, Idx::T, Idx::U>( + { i1_ }, + fset.ex3(x_Ph_0)); + } + } + if (tags & BC::B) { + if constexpr (defines_bx1) { + bx1_U = metric.template transform<1, Idx::T, Idx::U>( + { i1_ }, + fset.bx1(x_Ph_0)); + } + if constexpr (defines_bx2) { + bx2_U = metric.template transform<2, Idx::T, Idx::U>( + { i1_ + HALF }, + fset.bx2(x_Ph_H)); + } + if constexpr (defines_bx3) { + bx3_U = metric.template transform<3, Idx::T, Idx::U>( + { i1_ + HALF }, + fset.bx3(x_Ph_H)); + } + } + + { + const auto dx = math::abs( + metric.template convert(i1_ + HALF) - xg_edge); + const auto s = shape(dx); + if (tags & BC::E) { + // ex1 + Fld(i1, em::ex1) = s * Fld(i1, em::ex1) + (ONE - s) * ex1_U; + } + if (tags & BC::B) { + // bx2 + Fld(i1, em::bx2) = s * Fld(i1, em::bx2) + (ONE - s) * bx2_U; + // bx3 + Fld(i1, em::bx3) = s * Fld(i1, em::bx3) + (ONE - s) * bx3_U; + } + } + { + const auto dx = math::abs( + metric.template convert(i1_) - xg_edge); + const auto s = shape(dx); + if (tags & BC::B) { + // bx1 + Fld(i1, em::bx1) = s * Fld(i1, em::bx1) + (ONE - s) * bx1_U; + } + if (tags & BC::E) { + // ex2 + Fld(i1, em::ex2) = s * Fld(i1, em::ex2) + (ONE - s) * ex2_U; + // ex3 + Fld(i1, em::ex3) = s * Fld(i1, em::ex3) + (ONE - s) * ex3_U; + } + } + } else { + // GRPIC + raise::KernelError(HERE, "1D GRPIC not implemented"); } } else { raise::KernelError( HERE, - "AbsorbFields_kernel: 1D implementation called for D != 1"); + "MatchBoundaries_kernel: 1D implementation called for D != 1"); } } @@ -77,43 +149,130 @@ namespace kernel { if constexpr (M::Dim == Dim::_2D) { const auto i1_ = COORD(i1); const auto i2_ = COORD(i2); - for (const auto comp : - { em::ex1, em::ex2, em::ex3, em::bx1, em::bx2, em::bx3 }) { - if ((comp == em::ex1) and not(tags & BC::Ex1)) { - continue; - } else if ((comp == em::ex2) and not(tags & BC::Ex2)) { - continue; - } else if ((comp == em::ex3) and not(tags & BC::Ex3)) { - continue; - } else if ((comp == em::bx1) and not(tags & BC::Bx1)) { - continue; - } else if ((comp == em::bx2) and not(tags & BC::Bx2)) { - continue; - } else if ((comp == em::bx3) and not(tags & BC::Bx3)) { - continue; - } - coord_t x_Cd { ZERO }; - if (comp == em::ex1 or comp == em::bx2) { - x_Cd[0] = i1_ + HALF; - x_Cd[1] = i2_; - } else if (comp == em::ex2 or comp == em::bx1) { - x_Cd[0] = i1_; - x_Cd[1] = i2_ + HALF; - } else if (comp == em::ex3) { - x_Cd[0] = i1_; - x_Cd[1] = i2_; - } else if (comp == em::bx3) { - x_Cd[0] = i1_ + HALF; - x_Cd[1] = i2_ + HALF; - } - const auto dx = math::abs( - metric.template convert(x_Cd[i - 1]) - xg_edge); - Fld(i1, i2, comp) *= math::tanh(dx / (INV_4 * dx_abs)); + + if constexpr (S == SimEngine::SRPIC) { + // SRPIC + { + coord_t x_Ph_H0 { ZERO }; + metric.template convert({ i1_ + HALF, i2_ }, x_Ph_H0); + // i1 + 1/2, i2 + real_t xi_Cd; + if constexpr (o == in::x1) { + xi_Cd = i1_ + HALF; + } else { + xi_Cd = i2_; + } + const auto dx = math::abs( + metric.template convert(xi_Cd) - xg_edge); + const auto s = shape(dx); + if (tags & BC::E) { + auto ex1_U { ZERO }; + if constexpr (defines_ex1) { + ex1_U = metric.template transform<1, Idx::T, Idx::U>( + { i1_ + HALF, i2_ }, + fset.ex1(x_Ph_H0)); + } + // ex1 + Fld(i1, i2, em::ex1) = s * Fld(i1, i2, em::ex1) + (ONE - s) * ex1_U; + } + if (tags & BC::B) { + auto bx2_U { ZERO }; + if constexpr (defines_bx2) { + bx2_U = metric.template transform<2, Idx::T, Idx::U>( + { i1_ + HALF, i2_ }, + fset.bx2(x_Ph_H0)); + } + // bx2 + Fld(i1, i2, em::bx2) = s * Fld(i1, i2, em::bx2) + (ONE - s) * bx2_U; + } + } + { + coord_t x_Ph_0H { ZERO }; + metric.template convert({ i1_, i2_ + HALF }, x_Ph_0H); + // i1, i2 + 1/2 + real_t xi_Cd; + if constexpr (o == in::x1) { + xi_Cd = i1_; + } else { + xi_Cd = i2_ + HALF; + } + const auto dx = math::abs( + metric.template convert(xi_Cd) - xg_edge); + const auto s = shape(dx); + if (tags & BC::E) { + auto ex2_U { ZERO }; + if constexpr (defines_ex2) { + ex2_U = metric.template transform<2, Idx::T, Idx::U>( + { i1_, i2_ + HALF }, + fset.ex2(x_Ph_0H)); + } + // ex2 + Fld(i1, i2, em::ex2) = s * Fld(i1, i2, em::ex2) + (ONE - s) * ex2_U; + } + if (tags & BC::B) { + auto bx1_U { ZERO }; + if constexpr (defines_bx1) { + bx1_U = metric.template transform<1, Idx::T, Idx::U>( + { i1_, i2_ + HALF }, + fset.bx1(x_Ph_0H)); + } + // bx1 + Fld(i1, i2, em::bx1) = s * Fld(i1, i2, em::bx1) + (ONE - s) * bx1_U; + } + } + if (tags & BC::E) { + auto ex3_U { ZERO }; + if constexpr (defines_ex3) { + coord_t x_Ph_00 { ZERO }; + metric.template convert({ i1_, i2_ }, x_Ph_00); + ex3_U = metric.template transform<3, Idx::T, Idx::U>( + { i1_, i2_ }, + fset.ex3(x_Ph_00)); + } + // i1, i2 + real_t xi_Cd; + if constexpr (o == in::x1) { + xi_Cd = i1_; + } else { + xi_Cd = i2_; + } + const auto dx = math::abs( + metric.template convert(xi_Cd) - xg_edge); + const auto s = shape(dx); + // ex3 + Fld(i1, i2, em::ex3) = s * Fld(i1, i2, em::ex3) + (ONE - s) * ex3_U; + } + if (tags & BC::B) { + auto bx3_U { ZERO }; + if constexpr (defines_bx3) { + coord_t x_Ph_HH { ZERO }; + metric.template convert({ i1_ + HALF, i2_ + HALF }, + x_Ph_HH); + bx3_U = metric.template transform<3, Idx::T, Idx::U>( + { i1_ + HALF, i2_ + HALF }, + fset.bx3(x_Ph_HH)); + } + // i1 + 1/2, i2 + 1/2 + real_t xi_Cd; + if constexpr (o == in::x1) { + xi_Cd = i1_ + HALF; + } else { + xi_Cd = i2_ + HALF; + } + const auto dx = math::abs( + metric.template convert(xi_Cd) - xg_edge); + const auto s = shape(dx); + // bx3 + Fld(i1, i2, em::bx3) = s * Fld(i1, i2, em::bx3) + (ONE - s) * bx3_U; + } + } else { + // GRPIC + raise::KernelError(HERE, "GRPIC not implemented"); } } else { raise::KernelError( HERE, - "AbsorbFields_kernel: 2D implementation called for D != 2"); + "MatchBoundaries_kernel: 2D implementation called for D != 2"); } } @@ -122,55 +281,180 @@ namespace kernel { const auto i1_ = COORD(i1); const auto i2_ = COORD(i2); const auto i3_ = COORD(i3); - for (const auto comp : - { em::ex1, em::ex2, em::ex3, em::bx1, em::bx2, em::bx3 }) { - if ((comp == em::ex1) and not(tags & BC::Ex1)) { - continue; - } else if ((comp == em::ex2) and not(tags & BC::Ex2)) { - continue; - } else if ((comp == em::ex3) and not(tags & BC::Ex3)) { - continue; - } else if ((comp == em::bx1) and not(tags & BC::Bx1)) { - continue; - } else if ((comp == em::bx2) and not(tags & BC::Bx2)) { - continue; - } else if ((comp == em::bx3) and not(tags & BC::Bx3)) { - continue; - } - coord_t x_Cd { ZERO }; - if (comp == em::ex1) { - x_Cd[0] = i1_ + HALF; - x_Cd[1] = i2_; - x_Cd[2] = i3_; - } else if (comp == em::ex2) { - x_Cd[0] = i1_; - x_Cd[1] = i2_ + HALF; - x_Cd[2] = i3_; - } else if (comp == em::ex3) { - x_Cd[0] = i1_; - x_Cd[1] = i2_; - x_Cd[2] = i3_ + HALF; - } else if (comp == em::bx1) { - x_Cd[0] = i1_; - x_Cd[1] = i2_ + HALF; - x_Cd[2] = i3_ + HALF; - } else if (comp == em::bx2) { - x_Cd[0] = i1_ + HALF; - x_Cd[1] = i2_; - x_Cd[2] = i3_ + HALF; - } else if (comp == em::bx3) { - x_Cd[0] = i1_ + HALF; - x_Cd[1] = i2_ + HALF; - x_Cd[2] = i3_; - } - const auto dx = math::abs( - metric.template convert(x_Cd[i - 1]) - xg_edge); - Fld(i1, i2, i3, comp) *= math::tanh(dx / (INV_4 * dx_abs)); + + if constexpr (S == SimEngine::SRPIC) { + // SRPIC + if (tags & BC::E) { + { + // i1 + 1/2, i2, i3 + real_t xi_Cd; + if constexpr (o == in::x1) { + xi_Cd = i1_ + HALF; + } else if constexpr (o == in::x2) { + xi_Cd = i2_; + } else { + xi_Cd = i3_; + } + const auto dx = math::abs( + metric.template convert(xi_Cd) - xg_edge); + const auto s = shape(dx); + auto ex1_U { ZERO }; + if constexpr (defines_ex1) { + coord_t x_Ph_H00 { ZERO }; + metric.template convert({ i1_ + HALF, i2_, i3_ }, + x_Ph_H00); + ex1_U = metric.template transform<1, Idx::T, Idx::U>( + { i1_ + HALF, i2_, i3_ }, + fset.ex1(x_Ph_H00)); + } + // ex1 + Fld(i1, i2, i3, em::ex1) = s * Fld(i1, i2, i3, em::ex1) + + (ONE - s) * ex1_U; + } + { + // i1, i2 + 1/2, i3 + real_t xi_Cd; + if constexpr (o == in::x1) { + xi_Cd = i1_; + } else if constexpr (o == in::x2) { + xi_Cd = i2_ + HALF; + } else { + xi_Cd = i3_; + } + const auto dx = math::abs( + metric.template convert(xi_Cd) - xg_edge); + const auto s = shape(dx); + auto ex2_U { ZERO }; + if constexpr (defines_ex2) { + coord_t x_Ph_0H0 { ZERO }; + metric.template convert({ i1_, i2_ + HALF, i3_ }, + x_Ph_0H0); + ex2_U = metric.template transform<2, Idx::T, Idx::U>( + { i1_, i2_ + HALF, i3_ }, + fset.ex2(x_Ph_0H0)); + } + // ex2 + Fld(i1, i2, i3, em::ex2) = s * Fld(i1, i2, i3, em::ex2) + + (ONE - s) * ex2_U; + } + { + // i1, i2, i3 + 1/2 + real_t xi_Cd; + if constexpr (o == in::x1) { + xi_Cd = i1_; + } else if constexpr (o == in::x2) { + xi_Cd = i2_; + } else { + xi_Cd = i3_ + HALF; + } + const auto dx = math::abs( + metric.template convert(xi_Cd) - xg_edge); + const auto s = shape(dx); + auto ex3_U { ZERO }; + if constexpr (defines_ex3) { + coord_t x_Ph_00H { ZERO }; + metric.template convert({ i1_, i2_, i3_ + HALF }, + x_Ph_00H); + ex3_U = metric.template transform<3, Idx::T, Idx::U>( + { i1_, i2_, i3_ + HALF }, + fset.ex3(x_Ph_00H)); + } + // ex3 + Fld(i1, i2, i3, em::ex3) = s * Fld(i1, i2, i3, em::ex3) + + (ONE - s) * ex3_U; + } + } + if (tags & BC::B) { + { + // i1, i2 + 1/2, i3 + 1/2 + real_t xi_Cd; + if constexpr (o == in::x1) { + xi_Cd = i1_; + } else if constexpr (o == in::x2) { + xi_Cd = i2_ + HALF; + } else { + xi_Cd = i3_ + HALF; + } + const auto dx = math::abs( + metric.template convert(xi_Cd) - xg_edge); + const auto s = shape(dx); + auto bx1_U { ZERO }; + if constexpr (defines_bx1) { + coord_t x_Ph_0HH { ZERO }; + metric.template convert( + { i1_, i2_ + HALF, i3_ + HALF }, + x_Ph_0HH); + bx1_U = metric.template transform<1, Idx::T, Idx::U>( + { i1_, i2_ + HALF, i3_ + HALF }, + fset.bx1(x_Ph_0HH)); + } + // bx1 + Fld(i1, i2, i3, em::bx1) = s * Fld(i1, i2, i3, em::bx1) + + (ONE - s) * bx1_U; + } + { + // i1 + 1/2, i2, i3 + 1/2 + real_t xi_Cd; + if constexpr (o == in::x1) { + xi_Cd = i1_ + HALF; + } else if constexpr (o == in::x2) { + xi_Cd = i2_; + } else { + xi_Cd = i3_ + HALF; + } + const auto dx = math::abs( + metric.template convert(xi_Cd) - xg_edge); + const auto s = shape(dx); + auto bx2_U { ZERO }; + if constexpr (defines_bx2) { + coord_t x_Ph_H0H { ZERO }; + metric.template convert( + { i1_ + HALF, i2_, i3_ + HALF }, + x_Ph_H0H); + bx2_U = metric.template transform<2, Idx::T, Idx::U>( + { i1_ + HALF, i2_, i3_ + HALF }, + fset.bx2(x_Ph_H0H)); + } + // bx2 + Fld(i1, i2, i3, em::bx2) = s * Fld(i1, i2, i3, em::bx2) + + (ONE - s) * bx2_U; + } + { + // i1 + 1/2, i2 + 1/2, i3 + real_t xi_Cd; + if constexpr (o == in::x1) { + xi_Cd = i1_ + HALF; + } else if constexpr (o == in::x2) { + xi_Cd = i2_ + HALF; + } else { + xi_Cd = i3_; + } + const auto dx = math::abs( + metric.template convert(xi_Cd) - xg_edge); + const auto s = shape(dx); + auto bx3_U { ZERO }; + if constexpr (defines_bx3) { + coord_t x_Ph_HH0 { ZERO }; + metric.template convert( + { i1_ + HALF, i2_ + HALF, i3_ }, + x_Ph_HH0); + bx3_U = metric.template transform<3, Idx::T, Idx::U>( + { i1_ + HALF, i2_ + HALF, i3_ }, + fset.bx3(x_Ph_HH0)); + } + // bx3 + Fld(i1, i2, i3, em::bx3) = s * Fld(i1, i2, i3, em::bx3) + + (ONE - s) * bx3_U; + } + } + } else { + // GRPIC + raise::KernelError(HERE, "GRPIC not implemented"); } } else { raise::KernelError( HERE, - "AbsorbFields_kernel: 3D implementation called for D != 3"); + "MatchBoundaries_kernel: 3D implementation called for D != 3"); } } }; @@ -226,31 +510,28 @@ namespace kernel { static constexpr bool defines_bx2 = traits::has_method::value; static constexpr bool defines_bx3 = traits::has_method::value; - static_assert(defines_ex1 and defines_ex2 and defines_ex3 and - defines_bx1 and defines_bx2 and defines_bx3, - "not all components of E or B are specified in PGEN"); + static_assert(defines_ex1 or defines_ex2 or defines_ex3 or defines_bx1 or + defines_bx2 or defines_bx3, + "none of the components of E or B are specified in PGEN"); static_assert(M::is_metric, "M must be a metric class"); static_assert(static_cast(O) < static_cast(M::Dim), "Invalid Orientation"); ndfield_t Fld; - const I finit; + const I fset; const M metric; const std::size_t i_edge; - const bool setE, setB; EnforcedBoundaries_kernel(ndfield_t& Fld, - const I& finit, + const I& fset, const M& metric, std::size_t i_edge, BCTags tags) : Fld { Fld } - , finit { finit } + , fset { fset } , metric { metric } - , i_edge { i_edge + N_GHOSTS } - , setE { tags & BC::Ex1 or tags & BC::Ex2 or tags & BC::Ex3 } - , setB { tags & BC::Bx1 or tags & BC::Bx2 or tags & BC::Bx3 } {} + , i_edge { i_edge + N_GHOSTS } {} Inline void operator()(index_t i1) const { if constexpr (D == Dim::_1D) { @@ -259,8 +540,8 @@ namespace kernel { coord_t x_Ph_H { ZERO }; metric.template convert({ i1_ }, x_Ph_0); metric.template convert({ i1_ + HALF }, x_Ph_H); - bool setEx1 = setE, setEx2 = setE, setEx3 = setE, setBx1 = setB, - setBx2 = setB, setBx3 = setB; + bool setEx1 = defines_ex1, setEx2 = defines_ex2, setEx3 = defines_ex3, + setBx1 = defines_bx1, setBx2 = defines_bx2, setBx3 = defines_bx3; if constexpr (O == in::x1) { // x1 -- normal // x2,x3 -- tangential @@ -276,35 +557,47 @@ namespace kernel { } else { raise::KernelError(HERE, "Invalid Orientation"); } - if (setEx1) { - Fld(i1, em::ex1) = metric.template transform<1, Idx::T, Idx::U>( - { i1_ + HALF }, - finit.ex1(x_Ph_H)); + if constexpr (defines_ex1) { + if (setEx1) { + Fld(i1, em::ex1) = metric.template transform<1, Idx::T, Idx::U>( + { i1_ + HALF }, + fset.ex1(x_Ph_H)); + } } - if (setEx2) { - Fld(i1, em::ex2) = metric.template transform<2, Idx::T, Idx::U>( - { i1_ }, - finit.ex2(x_Ph_0)); + if constexpr (defines_ex2) { + if (setEx2) { + Fld(i1, em::ex2) = metric.template transform<2, Idx::T, Idx::U>( + { i1_ }, + fset.ex2(x_Ph_0)); + } } - if (setEx3) { - Fld(i1, em::ex3) = metric.template transform<3, Idx::T, Idx::U>( - { i1_ }, - finit.ex3(x_Ph_0)); + if constexpr (defines_ex3) { + if (setEx3) { + Fld(i1, em::ex3) = metric.template transform<3, Idx::T, Idx::U>( + { i1_ }, + fset.ex3(x_Ph_0)); + } } - if (setBx1) { - Fld(i1, em::bx1) = metric.template transform<1, Idx::T, Idx::U>( - { i1_ }, - finit.bx1(x_Ph_0)); + if constexpr (defines_bx1) { + if (setBx1) { + Fld(i1, em::bx1) = metric.template transform<1, Idx::T, Idx::U>( + { i1_ }, + fset.bx1(x_Ph_0)); + } } - if (setBx2) { - Fld(i1, em::bx2) = metric.template transform<2, Idx::T, Idx::U>( - { i1_ + HALF }, - finit.bx2(x_Ph_H)); + if constexpr (defines_bx2) { + if (setBx2) { + Fld(i1, em::bx2) = metric.template transform<2, Idx::T, Idx::U>( + { i1_ + HALF }, + fset.bx2(x_Ph_H)); + } } - if (setBx3) { - Fld(i1, em::bx3) = metric.template transform<3, Idx::T, Idx::U>( - { i1_ + HALF }, - finit.bx3(x_Ph_H)); + if constexpr (defines_bx3) { + if (setBx3) { + Fld(i1, em::bx3) = metric.template transform<3, Idx::T, Idx::U>( + { i1_ + HALF }, + fset.bx3(x_Ph_H)); + } } } else { raise::KernelError(HERE, "Invalid Dimension"); @@ -324,8 +617,8 @@ namespace kernel { metric.template convert({ i1_ + HALF, i2_ }, x_Ph_H0); metric.template convert({ i1_ + HALF, i2_ + HALF }, x_Ph_HH); - bool setEx1 = setE, setEx2 = setE, setEx3 = setE, setBx1 = setB, - setBx2 = setB, setBx3 = setB; + bool setEx1 = defines_ex1, setEx2 = defines_ex2, setEx3 = defines_ex3, + setBx1 = defines_bx1, setBx2 = defines_bx2, setBx3 = defines_bx3; if constexpr (O == in::x1) { // x1 -- normal // x2,x3 -- tangential @@ -353,35 +646,47 @@ namespace kernel { } else { raise::KernelError(HERE, "Invalid Orientation"); } - if (setEx1) { - Fld(i1, i2, em::ex1) = metric.template transform<1, Idx::T, Idx::U>( - { i1_ + HALF, i2_ }, - finit.ex1(x_Ph_H0)); + if constexpr (defines_ex1) { + if (setEx1) { + Fld(i1, i2, em::ex1) = metric.template transform<1, Idx::T, Idx::U>( + { i1_ + HALF, i2_ }, + fset.ex1(x_Ph_H0)); + } } - if (setEx2) { - Fld(i1, i2, em::ex2) = metric.template transform<2, Idx::T, Idx::U>( - { i1_, i2_ + HALF }, - finit.ex2(x_Ph_0H)); + if constexpr (defines_ex2) { + if (setEx2) { + Fld(i1, i2, em::ex2) = metric.template transform<2, Idx::T, Idx::U>( + { i1_, i2_ + HALF }, + fset.ex2(x_Ph_0H)); + } } - if (setEx3) { - Fld(i1, i2, em::ex3) = metric.template transform<3, Idx::T, Idx::U>( - { i1_, i2_ }, - finit.ex3(x_Ph_00)); + if constexpr (defines_ex3) { + if (setEx3) { + Fld(i1, i2, em::ex3) = metric.template transform<3, Idx::T, Idx::U>( + { i1_, i2_ }, + fset.ex3(x_Ph_00)); + } } - if (setBx1) { - Fld(i1, i2, em::bx1) = metric.template transform<1, Idx::T, Idx::U>( - { i1_, i2_ + HALF }, - finit.bx1(x_Ph_0H)); + if constexpr (defines_bx1) { + if (setBx1) { + Fld(i1, i2, em::bx1) = metric.template transform<1, Idx::T, Idx::U>( + { i1_, i2_ + HALF }, + fset.bx1(x_Ph_0H)); + } } - if (setBx2) { - Fld(i1, i2, em::bx2) = metric.template transform<2, Idx::T, Idx::U>( - { i1_ + HALF, i2_ }, - finit.bx2(x_Ph_H0)); + if constexpr (defines_bx2) { + if (setBx2) { + Fld(i1, i2, em::bx2) = metric.template transform<2, Idx::T, Idx::U>( + { i1_ + HALF, i2_ }, + fset.bx2(x_Ph_H0)); + } } - if (setBx3) { - Fld(i1, i2, em::bx3) = metric.template transform<3, Idx::T, Idx::U>( - { i1_ + HALF, i2_ + HALF }, - finit.bx3(x_Ph_HH)); + if constexpr (defines_bx3) { + if (setBx3) { + Fld(i1, i2, em::bx3) = metric.template transform<3, Idx::T, Idx::U>( + { i1_ + HALF, i2_ + HALF }, + fset.bx3(x_Ph_HH)); + } } } else { raise::KernelError(HERE, "Invalid Dimension"); @@ -412,8 +717,8 @@ namespace kernel { x_Ph_H0H); metric.template convert({ i1_, i2_ + HALF, i3_ + HALF }, x_Ph_0HH); - bool setEx1 = setE, setEx2 = setE, setEx3 = setE, setBx1 = setB, - setBx2 = setB, setBx3 = setB; + bool setEx1 = defines_ex1, setEx2 = defines_ex2, setEx3 = defines_ex3, + setBx1 = defines_bx1, setBx2 = defines_bx2, setBx3 = defines_bx3; if constexpr (O == in::x1) { // x1 -- normal // x2,x3 -- tangential @@ -453,35 +758,47 @@ namespace kernel { } else { raise::KernelError(HERE, "Invalid Orientation"); } - if (setEx1) { - Fld(i1, i2, i3, em::ex1) = metric.template transform<1, Idx::T, Idx::U>( - { i1_ + HALF, i2_, i3_ }, - finit.ex1(x_Ph_H00)); + if constexpr (defines_ex1) { + if (setEx1) { + Fld(i1, i2, i3, em::ex1) = metric.template transform<1, Idx::T, Idx::U>( + { i1_ + HALF, i2_, i3_ }, + fset.ex1(x_Ph_H00)); + } } - if (setEx2) { - Fld(i1, i2, i3, em::ex2) = metric.template transform<2, Idx::T, Idx::U>( - { i1_, i2_ + HALF, i3_ }, - finit.ex2(x_Ph_0H0)); + if constexpr (defines_ex2) { + if (setEx2) { + Fld(i1, i2, i3, em::ex2) = metric.template transform<2, Idx::T, Idx::U>( + { i1_, i2_ + HALF, i3_ }, + fset.ex2(x_Ph_0H0)); + } } - if (setEx3) { - Fld(i1, i2, i3, em::ex3) = metric.template transform<3, Idx::T, Idx::U>( - { i1_, i2_, i3_ + HALF }, - finit.ex3(x_Ph_00H)); + if constexpr (defines_ex3) { + if (setEx3) { + Fld(i1, i2, i3, em::ex3) = metric.template transform<3, Idx::T, Idx::U>( + { i1_, i2_, i3_ + HALF }, + fset.ex3(x_Ph_00H)); + } } - if (setBx1) { - Fld(i1, i2, i3, em::bx1) = metric.template transform<1, Idx::T, Idx::U>( - { i1_, i2_ + HALF, i3_ + HALF }, - finit.bx1(x_Ph_0HH)); + if constexpr (defines_bx1) { + if (setBx1) { + Fld(i1, i2, i3, em::bx1) = metric.template transform<1, Idx::T, Idx::U>( + { i1_, i2_ + HALF, i3_ + HALF }, + fset.bx1(x_Ph_0HH)); + } } - if (setBx2) { - Fld(i1, i2, i3, em::bx2) = metric.template transform<2, Idx::T, Idx::U>( - { i1_ + HALF, i2_, i3_ + HALF }, - finit.bx2(x_Ph_H0H)); + if constexpr (defines_bx2) { + if (setBx2) { + Fld(i1, i2, i3, em::bx2) = metric.template transform<2, Idx::T, Idx::U>( + { i1_ + HALF, i2_, i3_ + HALF }, + fset.bx2(x_Ph_H0H)); + } } - if (setBx3) { - Fld(i1, i2, i3, em::bx3) = metric.template transform<3, Idx::T, Idx::U>( - { i1_ + HALF, i2_ + HALF, i3_ }, - finit.bx3(x_Ph_HH0)); + if constexpr (defines_bx3) { + if (setBx3) { + Fld(i1, i2, i3, em::bx3) = metric.template transform<3, Idx::T, Idx::U>( + { i1_ + HALF, i2_ + HALF, i3_ }, + fset.bx3(x_Ph_HH0)); + } } } else { raise::KernelError(HERE, "Invalid Dimension"); From 77e89e54503350720e7e05df91232595a4607058 Mon Sep 17 00:00:00 2001 From: haykh Date: Wed, 29 Jan 2025 15:18:24 -0500 Subject: [PATCH 257/773] bcs cleared --- src/engines/srpic.hpp | 26 ++- src/kernels/fields_bcs.hpp | 429 ++++++++++++++++++++----------------- 2 files changed, 249 insertions(+), 206 deletions(-) diff --git a/src/engines/srpic.hpp b/src/engines/srpic.hpp index c44f7641c..9f5e4551f 100644 --- a/src/engines/srpic.hpp +++ b/src/engines/srpic.hpp @@ -657,7 +657,7 @@ namespace ntt { Kokkos::parallel_for( "MatchFields", CreateRangePolicy(range_min, range_max), - kernel::MatchBoundaries_kernel( + kernel::bc::MatchBoundaries_kernel( domain.fields.em, match_fields, domain.mesh.metric, @@ -669,7 +669,7 @@ namespace ntt { Kokkos::parallel_for( "MatchFields", CreateRangePolicy(range_min, range_max), - kernel::MatchBoundaries_kernel( + kernel::bc::MatchBoundaries_kernel( domain.fields.em, match_fields, domain.mesh.metric, @@ -684,7 +684,7 @@ namespace ntt { Kokkos::parallel_for( "MatchFields", CreateRangePolicy(range_min, range_max), - kernel::MatchBoundaries_kernel( + kernel::bc::MatchBoundaries_kernel( domain.fields.em, match_fields, domain.mesh.metric, @@ -716,12 +716,16 @@ namespace ntt { Kokkos::parallel_for( "AxisBCFields", domain.mesh.n_all(in::x1), - kernel::AxisBoundaries_kernel(domain.fields.em, i2_min, tags)); + kernel::bc::AxisBoundaries_kernel(domain.fields.em, + i2_min, + tags)); } else { Kokkos::parallel_for( "AxisBCFields", domain.mesh.n_all(in::x1), - kernel::AxisBoundaries_kernel(domain.fields.em, i2_max, tags)); + kernel::bc::AxisBoundaries_kernel(domain.fields.em, + i2_max, + tags)); } } @@ -878,7 +882,7 @@ namespace ntt { Kokkos::parallel_for( "AtmosphereBCFields", range, - kernel::EnforcedBoundaries_kernel( + kernel::bc::EnforcedBoundaries_kernel( domain.fields.em, atm_fields, domain.mesh.metric, @@ -888,7 +892,7 @@ namespace ntt { Kokkos::parallel_for( "AtmosphereBCFields", range, - kernel::EnforcedBoundaries_kernel( + kernel::bc::EnforcedBoundaries_kernel( domain.fields.em, atm_fields, domain.mesh.metric, @@ -901,7 +905,7 @@ namespace ntt { Kokkos::parallel_for( "AtmosphereBCFields", range, - kernel::EnforcedBoundaries_kernel( + kernel::bc::EnforcedBoundaries_kernel( domain.fields.em, atm_fields, domain.mesh.metric, @@ -911,7 +915,7 @@ namespace ntt { Kokkos::parallel_for( "AtmosphereBCFields", range, - kernel::EnforcedBoundaries_kernel( + kernel::bc::EnforcedBoundaries_kernel( domain.fields.em, atm_fields, domain.mesh.metric, @@ -927,7 +931,7 @@ namespace ntt { Kokkos::parallel_for( "AtmosphereBCFields", range, - kernel::EnforcedBoundaries_kernel( + kernel::bc::EnforcedBoundaries_kernel( domain.fields.em, atm_fields, domain.mesh.metric, @@ -937,7 +941,7 @@ namespace ntt { Kokkos::parallel_for( "AtmosphereBCFields", range, - kernel::EnforcedBoundaries_kernel( + kernel::bc::EnforcedBoundaries_kernel( domain.fields.em, atm_fields, domain.mesh.metric, diff --git a/src/kernels/fields_bcs.hpp b/src/kernels/fields_bcs.hpp index 4d52dd207..6fa5d6d68 100644 --- a/src/kernels/fields_bcs.hpp +++ b/src/kernels/fields_bcs.hpp @@ -1,5 +1,12 @@ /** - * @brief: kernels/fields_bcs.hpp + * @file kernels/fields_bcs.hpp + * @brief Kernels used for field boundary conditions + * @implements + * - kernel::bc::MatchBoundaries_kernel<> + * - kernel::bc::AxisBoundaries_kernel<> + * - kernel::bc::EnforcedBoundaries_kernel<> + * @namespaces: + * - kernel::bc:: */ #ifndef KERNELS_FIELDS_BCS_HPP @@ -12,9 +19,18 @@ #include "utils/error.h" #include "utils/numeric.h" -namespace kernel { +namespace kernel::bc { using namespace ntt; + /* + * @tparam S: Simulation Engine + * @tparam I: Field Setter class + * @tparam M: Metric + * @tparam o: Orientation + * + * @brief Applies matching boundary conditions (with a smooth profile) in a specific direction. + * @note If a component is not specified in the field setter, it is ignored. + */ template struct MatchBoundaries_kernel { static_assert(M::is_metric, "M must be a metric class"); @@ -31,6 +47,12 @@ namespace kernel { static constexpr bool defines_bx1 = traits::has_method::value; static constexpr bool defines_bx2 = traits::has_method::value; static constexpr bool defines_bx3 = traits::has_method::value; + static_assert( + (S == SimEngine::SRPIC and (defines_ex1 or defines_ex2 or defines_ex3 or + defines_bx1 or defines_bx2 or defines_bx3)) or + ((S == SimEngine::GRPIC) and (defines_dx1 or defines_dx2 or defines_dx3 or + defines_bx1 or defines_bx2 or defines_bx3)), + "none of the components of E/D or B are specified in PGEN"); ndfield_t Fld; const I fset; @@ -60,12 +82,12 @@ namespace kernel { if constexpr (M::Dim == Dim::_1D) { const auto i1_ = COORD(i1); - coord_t x_Ph_0 { ZERO }; - coord_t x_Ph_H { ZERO }; - metric.template convert({ i1_ }, x_Ph_0); - metric.template convert({ i1_ + HALF }, x_Ph_H); - if constexpr (S == SimEngine::SRPIC) { + coord_t x_Ph_0 { ZERO }; + coord_t x_Ph_H { ZERO }; + metric.template convert({ i1_ }, x_Ph_0); + metric.template convert({ i1_ + HALF }, x_Ph_H); + // SRPIC auto ex1_U { ZERO }, ex2_U { ZERO }, ex3_U { ZERO }, bx1_U { ZERO }, bx2_U { ZERO }, bx3_U { ZERO }; @@ -104,34 +126,44 @@ namespace kernel { } } - { + if constexpr (defines_ex1 or defines_bx2 or defines_bx3) { const auto dx = math::abs( metric.template convert(i1_ + HALF) - xg_edge); const auto s = shape(dx); - if (tags & BC::E) { - // ex1 - Fld(i1, em::ex1) = s * Fld(i1, em::ex1) + (ONE - s) * ex1_U; + if constexpr (defines_ex1) { + if (tags & BC::E) { + Fld(i1, em::ex1) = s * Fld(i1, em::ex1) + (ONE - s) * ex1_U; + } } - if (tags & BC::B) { - // bx2 - Fld(i1, em::bx2) = s * Fld(i1, em::bx2) + (ONE - s) * bx2_U; - // bx3 - Fld(i1, em::bx3) = s * Fld(i1, em::bx3) + (ONE - s) * bx3_U; + if constexpr (defines_bx2 or defines_bx3) { + if (tags & BC::B) { + if constexpr (defines_bx2) { + Fld(i1, em::bx2) = s * Fld(i1, em::bx2) + (ONE - s) * bx2_U; + } + if constexpr (defines_bx3) { + Fld(i1, em::bx3) = s * Fld(i1, em::bx3) + (ONE - s) * bx3_U; + } + } } } - { + if constexpr (defines_bx1 or defines_ex2 or defines_ex3) { const auto dx = math::abs( metric.template convert(i1_) - xg_edge); const auto s = shape(dx); - if (tags & BC::B) { - // bx1 - Fld(i1, em::bx1) = s * Fld(i1, em::bx1) + (ONE - s) * bx1_U; + if constexpr (defines_bx1) { + if (tags & BC::B) { + Fld(i1, em::bx1) = s * Fld(i1, em::bx1) + (ONE - s) * bx1_U; + } } - if (tags & BC::E) { - // ex2 - Fld(i1, em::ex2) = s * Fld(i1, em::ex2) + (ONE - s) * ex2_U; - // ex3 - Fld(i1, em::ex3) = s * Fld(i1, em::ex3) + (ONE - s) * ex3_U; + if constexpr (defines_ex2 or defines_ex3) { + if (tags & BC::E) { + if constexpr (defines_ex2) { + Fld(i1, em::ex2) = s * Fld(i1, em::ex2) + (ONE - s) * ex2_U; + } + if constexpr (defines_ex3) { + Fld(i1, em::ex3) = s * Fld(i1, em::ex3) + (ONE - s) * ex3_U; + } + } } } } else { @@ -152,7 +184,7 @@ namespace kernel { if constexpr (S == SimEngine::SRPIC) { // SRPIC - { + if constexpr (defines_ex1 or defines_bx2) { coord_t x_Ph_H0 { ZERO }; metric.template convert({ i1_ + HALF, i2_ }, x_Ph_H0); // i1 + 1/2, i2 @@ -162,31 +194,30 @@ namespace kernel { } else { xi_Cd = i2_; } + const auto dx = math::abs( metric.template convert(xi_Cd) - xg_edge); const auto s = shape(dx); - if (tags & BC::E) { - auto ex1_U { ZERO }; - if constexpr (defines_ex1) { - ex1_U = metric.template transform<1, Idx::T, Idx::U>( + + if constexpr (defines_ex1) { + if (tags & BC::E) { + const auto ex1_U = metric.template transform<1, Idx::T, Idx::U>( { i1_ + HALF, i2_ }, fset.ex1(x_Ph_H0)); + Fld(i1, i2, em::ex1) = s * Fld(i1, i2, em::ex1) + (ONE - s) * ex1_U; } - // ex1 - Fld(i1, i2, em::ex1) = s * Fld(i1, i2, em::ex1) + (ONE - s) * ex1_U; } - if (tags & BC::B) { - auto bx2_U { ZERO }; - if constexpr (defines_bx2) { - bx2_U = metric.template transform<2, Idx::T, Idx::U>( + if constexpr (defines_bx2) { + if (tags & BC::B) { + const auto bx2_U = metric.template transform<2, Idx::T, Idx::U>( { i1_ + HALF, i2_ }, fset.bx2(x_Ph_H0)); + Fld(i1, i2, em::bx2) = s * Fld(i1, i2, em::bx2) + (ONE - s) * bx2_U; } - // bx2 - Fld(i1, i2, em::bx2) = s * Fld(i1, i2, em::bx2) + (ONE - s) * bx2_U; } } - { + + if constexpr (defines_ex2 or defines_bx1) { coord_t x_Ph_0H { ZERO }; metric.template convert({ i1_, i2_ + HALF }, x_Ph_0H); // i1, i2 + 1/2 @@ -196,74 +227,74 @@ namespace kernel { } else { xi_Cd = i2_ + HALF; } + const auto dx = math::abs( metric.template convert(xi_Cd) - xg_edge); const auto s = shape(dx); - if (tags & BC::E) { - auto ex2_U { ZERO }; - if constexpr (defines_ex2) { + if constexpr (defines_ex2) { + if (tags & BC::E) { + auto ex2_U { ZERO }; ex2_U = metric.template transform<2, Idx::T, Idx::U>( { i1_, i2_ + HALF }, fset.ex2(x_Ph_0H)); + Fld(i1, i2, em::ex2) = s * Fld(i1, i2, em::ex2) + (ONE - s) * ex2_U; } - // ex2 - Fld(i1, i2, em::ex2) = s * Fld(i1, i2, em::ex2) + (ONE - s) * ex2_U; } - if (tags & BC::B) { - auto bx1_U { ZERO }; - if constexpr (defines_bx1) { + if constexpr (defines_bx1) { + if (tags & BC::B) { + auto bx1_U { ZERO }; bx1_U = metric.template transform<1, Idx::T, Idx::U>( { i1_, i2_ + HALF }, fset.bx1(x_Ph_0H)); + Fld(i1, i2, em::bx1) = s * Fld(i1, i2, em::bx1) + (ONE - s) * bx1_U; } - // bx1 - Fld(i1, i2, em::bx1) = s * Fld(i1, i2, em::bx1) + (ONE - s) * bx1_U; } } - if (tags & BC::E) { - auto ex3_U { ZERO }; - if constexpr (defines_ex3) { + + if constexpr (defines_ex3) { + if (tags & BC::E) { + auto ex3_U { ZERO }; coord_t x_Ph_00 { ZERO }; metric.template convert({ i1_, i2_ }, x_Ph_00); ex3_U = metric.template transform<3, Idx::T, Idx::U>( { i1_, i2_ }, fset.ex3(x_Ph_00)); + // i1, i2 + real_t xi_Cd; + if constexpr (o == in::x1) { + xi_Cd = i1_; + } else { + xi_Cd = i2_; + } + const auto dx = math::abs( + metric.template convert(xi_Cd) - xg_edge); + const auto s = shape(dx); + Fld(i1, i2, em::ex3) = s * Fld(i1, i2, em::ex3) + (ONE - s) * ex3_U; } - // i1, i2 - real_t xi_Cd; - if constexpr (o == in::x1) { - xi_Cd = i1_; - } else { - xi_Cd = i2_; - } - const auto dx = math::abs( - metric.template convert(xi_Cd) - xg_edge); - const auto s = shape(dx); - // ex3 - Fld(i1, i2, em::ex3) = s * Fld(i1, i2, em::ex3) + (ONE - s) * ex3_U; } - if (tags & BC::B) { - auto bx3_U { ZERO }; - if constexpr (defines_bx3) { + + if constexpr (defines_bx3) { + if (tags & BC::B) { + auto bx3_U { ZERO }; coord_t x_Ph_HH { ZERO }; metric.template convert({ i1_ + HALF, i2_ + HALF }, x_Ph_HH); bx3_U = metric.template transform<3, Idx::T, Idx::U>( { i1_ + HALF, i2_ + HALF }, fset.bx3(x_Ph_HH)); + // i1 + 1/2, i2 + 1/2 + real_t xi_Cd; + if constexpr (o == in::x1) { + xi_Cd = i1_ + HALF; + } else { + xi_Cd = i2_ + HALF; + } + const auto dx = math::abs( + metric.template convert(xi_Cd) - xg_edge); + const auto s = shape(dx); + // bx3 + Fld(i1, i2, em::bx3) = s * Fld(i1, i2, em::bx3) + (ONE - s) * bx3_U; } - // i1 + 1/2, i2 + 1/2 - real_t xi_Cd; - if constexpr (o == in::x1) { - xi_Cd = i1_ + HALF; - } else { - xi_Cd = i2_ + HALF; - } - const auto dx = math::abs( - metric.template convert(xi_Cd) - xg_edge); - const auto s = shape(dx); - // bx3 - Fld(i1, i2, em::bx3) = s * Fld(i1, i2, em::bx3) + (ONE - s) * bx3_U; } } else { // GRPIC @@ -284,129 +315,126 @@ namespace kernel { if constexpr (S == SimEngine::SRPIC) { // SRPIC - if (tags & BC::E) { - { - // i1 + 1/2, i2, i3 - real_t xi_Cd; - if constexpr (o == in::x1) { - xi_Cd = i1_ + HALF; - } else if constexpr (o == in::x2) { - xi_Cd = i2_; - } else { - xi_Cd = i3_; - } - const auto dx = math::abs( - metric.template convert(xi_Cd) - xg_edge); - const auto s = shape(dx); - auto ex1_U { ZERO }; + if constexpr (defines_ex1 or defines_ex2 or defines_ex3) { + if (tags & BC::E) { if constexpr (defines_ex1) { + // i1 + 1/2, i2, i3 + real_t xi_Cd; + if constexpr (o == in::x1) { + xi_Cd = i1_ + HALF; + } else if constexpr (o == in::x2) { + xi_Cd = i2_; + } else { + xi_Cd = i3_; + } + const auto dx = math::abs( + metric.template convert(xi_Cd) - xg_edge); + const auto s = shape(dx); + auto ex1_U { ZERO }; coord_t x_Ph_H00 { ZERO }; metric.template convert({ i1_ + HALF, i2_, i3_ }, x_Ph_H00); ex1_U = metric.template transform<1, Idx::T, Idx::U>( { i1_ + HALF, i2_, i3_ }, fset.ex1(x_Ph_H00)); + Fld(i1, i2, i3, em::ex1) = s * Fld(i1, i2, i3, em::ex1) + + (ONE - s) * ex1_U; } - // ex1 - Fld(i1, i2, i3, em::ex1) = s * Fld(i1, i2, i3, em::ex1) + - (ONE - s) * ex1_U; - } - { - // i1, i2 + 1/2, i3 - real_t xi_Cd; - if constexpr (o == in::x1) { - xi_Cd = i1_; - } else if constexpr (o == in::x2) { - xi_Cd = i2_ + HALF; - } else { - xi_Cd = i3_; - } - const auto dx = math::abs( - metric.template convert(xi_Cd) - xg_edge); - const auto s = shape(dx); - auto ex2_U { ZERO }; + if constexpr (defines_ex2) { + // i1, i2 + 1/2, i3 + real_t xi_Cd; + if constexpr (o == in::x1) { + xi_Cd = i1_; + } else if constexpr (o == in::x2) { + xi_Cd = i2_ + HALF; + } else { + xi_Cd = i3_; + } + const auto dx = math::abs( + metric.template convert(xi_Cd) - xg_edge); + const auto s = shape(dx); + auto ex2_U { ZERO }; coord_t x_Ph_0H0 { ZERO }; metric.template convert({ i1_, i2_ + HALF, i3_ }, x_Ph_0H0); ex2_U = metric.template transform<2, Idx::T, Idx::U>( { i1_, i2_ + HALF, i3_ }, fset.ex2(x_Ph_0H0)); + Fld(i1, i2, i3, em::ex2) = s * Fld(i1, i2, i3, em::ex2) + + (ONE - s) * ex2_U; } - // ex2 - Fld(i1, i2, i3, em::ex2) = s * Fld(i1, i2, i3, em::ex2) + - (ONE - s) * ex2_U; - } - { - // i1, i2, i3 + 1/2 - real_t xi_Cd; - if constexpr (o == in::x1) { - xi_Cd = i1_; - } else if constexpr (o == in::x2) { - xi_Cd = i2_; - } else { - xi_Cd = i3_ + HALF; - } - const auto dx = math::abs( - metric.template convert(xi_Cd) - xg_edge); - const auto s = shape(dx); - auto ex3_U { ZERO }; + if constexpr (defines_ex3) { + // i1, i2, i3 + 1/2 + real_t xi_Cd; + if constexpr (o == in::x1) { + xi_Cd = i1_; + } else if constexpr (o == in::x2) { + xi_Cd = i2_; + } else { + xi_Cd = i3_ + HALF; + } + const auto dx = math::abs( + metric.template convert(xi_Cd) - xg_edge); + const auto s = shape(dx); + auto ex3_U { ZERO }; coord_t x_Ph_00H { ZERO }; metric.template convert({ i1_, i2_, i3_ + HALF }, x_Ph_00H); ex3_U = metric.template transform<3, Idx::T, Idx::U>( { i1_, i2_, i3_ + HALF }, fset.ex3(x_Ph_00H)); + Fld(i1, i2, i3, em::ex3) = s * Fld(i1, i2, i3, em::ex3) + + (ONE - s) * ex3_U; } - // ex3 - Fld(i1, i2, i3, em::ex3) = s * Fld(i1, i2, i3, em::ex3) + - (ONE - s) * ex3_U; } } - if (tags & BC::B) { - { - // i1, i2 + 1/2, i3 + 1/2 - real_t xi_Cd; - if constexpr (o == in::x1) { - xi_Cd = i1_; - } else if constexpr (o == in::x2) { - xi_Cd = i2_ + HALF; - } else { - xi_Cd = i3_ + HALF; - } - const auto dx = math::abs( - metric.template convert(xi_Cd) - xg_edge); - const auto s = shape(dx); - auto bx1_U { ZERO }; + + if constexpr (defines_bx1 or defines_bx2 or defines_bx3) { + if (tags & BC::B) { if constexpr (defines_bx1) { - coord_t x_Ph_0HH { ZERO }; - metric.template convert( - { i1_, i2_ + HALF, i3_ + HALF }, - x_Ph_0HH); - bx1_U = metric.template transform<1, Idx::T, Idx::U>( - { i1_, i2_ + HALF, i3_ + HALF }, - fset.bx1(x_Ph_0HH)); + // i1, i2 + 1/2, i3 + 1/2 + real_t xi_Cd; + if constexpr (o == in::x1) { + xi_Cd = i1_; + } else if constexpr (o == in::x2) { + xi_Cd = i2_ + HALF; + } else { + xi_Cd = i3_ + HALF; + } + const auto dx = math::abs( + metric.template convert(xi_Cd) - xg_edge); + const auto s = shape(dx); + auto bx1_U { ZERO }; + if constexpr (defines_bx1) { + coord_t x_Ph_0HH { ZERO }; + metric.template convert( + { i1_, i2_ + HALF, i3_ + HALF }, + x_Ph_0HH); + bx1_U = metric.template transform<1, Idx::T, Idx::U>( + { i1_, i2_ + HALF, i3_ + HALF }, + fset.bx1(x_Ph_0HH)); + } + // bx1 + Fld(i1, i2, i3, em::bx1) = s * Fld(i1, i2, i3, em::bx1) + + (ONE - s) * bx1_U; } - // bx1 - Fld(i1, i2, i3, em::bx1) = s * Fld(i1, i2, i3, em::bx1) + - (ONE - s) * bx1_U; - } - { - // i1 + 1/2, i2, i3 + 1/2 - real_t xi_Cd; - if constexpr (o == in::x1) { - xi_Cd = i1_ + HALF; - } else if constexpr (o == in::x2) { - xi_Cd = i2_; - } else { - xi_Cd = i3_ + HALF; - } - const auto dx = math::abs( - metric.template convert(xi_Cd) - xg_edge); - const auto s = shape(dx); - auto bx2_U { ZERO }; + if constexpr (defines_bx2) { + // i1 + 1/2, i2, i3 + 1/2 + real_t xi_Cd; + if constexpr (o == in::x1) { + xi_Cd = i1_ + HALF; + } else if constexpr (o == in::x2) { + xi_Cd = i2_; + } else { + xi_Cd = i3_ + HALF; + } + const auto dx = math::abs( + metric.template convert(xi_Cd) - xg_edge); + const auto s = shape(dx); + auto bx2_U { ZERO }; coord_t x_Ph_H0H { ZERO }; metric.template convert( { i1_ + HALF, i2_, i3_ + HALF }, @@ -414,26 +442,24 @@ namespace kernel { bx2_U = metric.template transform<2, Idx::T, Idx::U>( { i1_ + HALF, i2_, i3_ + HALF }, fset.bx2(x_Ph_H0H)); + Fld(i1, i2, i3, em::bx2) = s * Fld(i1, i2, i3, em::bx2) + + (ONE - s) * bx2_U; } - // bx2 - Fld(i1, i2, i3, em::bx2) = s * Fld(i1, i2, i3, em::bx2) + - (ONE - s) * bx2_U; - } - { - // i1 + 1/2, i2 + 1/2, i3 - real_t xi_Cd; - if constexpr (o == in::x1) { - xi_Cd = i1_ + HALF; - } else if constexpr (o == in::x2) { - xi_Cd = i2_ + HALF; - } else { - xi_Cd = i3_; - } - const auto dx = math::abs( - metric.template convert(xi_Cd) - xg_edge); - const auto s = shape(dx); - auto bx3_U { ZERO }; + if constexpr (defines_bx3) { + // i1 + 1/2, i2 + 1/2, i3 + real_t xi_Cd; + if constexpr (o == in::x1) { + xi_Cd = i1_ + HALF; + } else if constexpr (o == in::x2) { + xi_Cd = i2_ + HALF; + } else { + xi_Cd = i3_; + } + const auto dx = math::abs( + metric.template convert(xi_Cd) - xg_edge); + const auto s = shape(dx); + auto bx3_U { ZERO }; coord_t x_Ph_HH0 { ZERO }; metric.template convert( { i1_ + HALF, i2_ + HALF, i3_ }, @@ -441,10 +467,9 @@ namespace kernel { bx3_U = metric.template transform<3, Idx::T, Idx::U>( { i1_ + HALF, i2_ + HALF, i3_ }, fset.bx3(x_Ph_HH0)); + Fld(i1, i2, i3, em::bx3) = s * Fld(i1, i2, i3, em::bx3) + + (ONE - s) * bx3_U; } - // bx3 - Fld(i1, i2, i3, em::bx3) = s * Fld(i1, i2, i3, em::bx3) + - (ONE - s) * bx3_U; } } } else { @@ -459,6 +484,12 @@ namespace kernel { } }; + /* + * @tparam D: Dimension + * @tparam P: Positive/Negative direction + * + * @brief Applies boundary conditions near the polar axis + */ template struct AxisBoundaries_kernel { ndfield_t Fld; @@ -500,6 +531,14 @@ namespace kernel { } }; + /* + * @tparam I: Field Setter class + * @tparam M: Metric + * @tparam P: Positive/Negative direction + * @tparam O: Orientation + * + * @brief Applies enforced boundary conditions (fixed value) + */ template struct EnforcedBoundaries_kernel { static constexpr Dimension D = M::Dim; @@ -806,6 +845,6 @@ namespace kernel { } }; -} // namespace kernel +} // namespace kernel::bc #endif // KERNELS_FIELDS_BCS_HPP From c7c96965947d06d4415328b4b4d7b39d044664e5 Mon Sep 17 00:00:00 2001 From: haykh Date: Wed, 29 Jan 2025 16:00:40 -0500 Subject: [PATCH 258/773] old tests passing --- src/framework/tests/parameters.cpp | 38 +++++++++++++++--------------- src/output/tests/writer-nompi.cpp | 10 ++++---- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/src/framework/tests/parameters.cpp b/src/framework/tests/parameters.cpp index 1a4228642..7cd5ce46a 100644 --- a/src/framework/tests/parameters.cpp +++ b/src/framework/tests/parameters.cpp @@ -32,7 +32,7 @@ const auto mink_1d = u8R"( fields = [["PERIODIC"]] particles = [["ABSORB", "ABSORB"]] - [grid.boundaries.absorb] + [grid.boundaries.match] coeff = 10.0 ds = 0.025 @@ -101,10 +101,10 @@ const auto sph_2d = u8R"( metric = "spherical" [grid.boundaries] - fields = [["ATMOSPHERE", "ABSORB"]] + fields = [["ATMOSPHERE", "MATCH"]] particles = [["ATMOSPHERE", "ABSORB"]] - [grid.boundaries.absorb] + [grid.boundaries.match] coeff = 10.0 [grid.boundaries.atmosphere] @@ -180,7 +180,7 @@ const auto qks_2d = u8R"( ks_a = 0.99 [grid.boundaries] - fields = [["ABSORB"]] + fields = [["MATCH"]] particles = [["ABSORB"]] [scales] @@ -345,8 +345,8 @@ auto main(int argc, char* argv[]) -> int { "simulation.engine"); boundaries_t fbc = { - { FldsBC::ATMOSPHERE, FldsBC::ABSORB }, - { FldsBC::AXIS, FldsBC::AXIS } + { FldsBC::ATMOSPHERE, FldsBC::MATCH }, + { FldsBC::AXIS, FldsBC::AXIS } }; assert_equal(params_sph_2d.get("scales.B0"), @@ -381,16 +381,16 @@ auto main(int argc, char* argv[]) -> int { fbc.size(), "grid.boundaries.fields.size()"); - // absorb coeffs + // match coeffs assert_equal( - params_sph_2d.get("grid.boundaries.absorb.ds"), - (real_t)(defaults::bc::absorb::ds_frac * 19.0), - "grid.boundaries.absorb.ds"); + params_sph_2d.get("grid.boundaries.match.ds"), + (real_t)(defaults::bc::match::ds_frac * 19.0), + "grid.boundaries.match.ds"); assert_equal( - params_sph_2d.get("grid.boundaries.absorb.coeff"), + params_sph_2d.get("grid.boundaries.match.coeff"), (real_t)10.0, - "grid.boundaries.absorb.coeff"); + "grid.boundaries.match.coeff"); assert_equal(params_sph_2d.get("particles.use_weights"), true, @@ -537,16 +537,16 @@ auto main(int argc, char* argv[]) -> int { pbc.size(), "grid.boundaries.particles.size()"); - // absorb coeffs + // match coeffs assert_equal( - params_qks_2d.get("grid.boundaries.absorb.ds"), - (real_t)(defaults::bc::absorb::ds_frac * (100.0 - 0.8)), - "grid.boundaries.absorb.ds"); + params_qks_2d.get("grid.boundaries.match.ds"), + (real_t)(defaults::bc::match::ds_frac * (100.0 - 0.8)), + "grid.boundaries.match.ds"); assert_equal( - params_qks_2d.get("grid.boundaries.absorb.coeff"), - defaults::bc::absorb::coeff, - "grid.boundaries.absorb.coeff"); + params_qks_2d.get("grid.boundaries.match.coeff"), + defaults::bc::match::coeff, + "grid.boundaries.match.coeff"); const auto species = params_qks_2d.get>( "particles.species"); diff --git a/src/output/tests/writer-nompi.cpp b/src/output/tests/writer-nompi.cpp index 08200d804..8fb2ac026 100644 --- a/src/output/tests/writer-nompi.cpp +++ b/src/output/tests/writer-nompi.cpp @@ -70,7 +70,7 @@ auto main(int argc, char* argv[]) -> int { { // write auto writer = out::Writer(); - writer.init(&adios, "hdf5", "test"); + writer.init(&adios, "hdf5", "test", false); writer.defineMeshLayout({ nx1, nx2, nx3 }, { 0, 0, 0 }, { nx1, nx2, nx3 }, @@ -84,13 +84,13 @@ auto main(int argc, char* argv[]) -> int { field_names.push_back(writer.fieldWriters()[0].name(i)); addresses.push_back(i); } - writer.beginWriting(10, 123.0); + writer.beginWriting(WriteMode::Fields, 10, 123.0); writer.writeField(field_names, field, addresses); - writer.endWriting(); + writer.endWriting(WriteMode::Fields); - writer.beginWriting(20, 123.4); + writer.beginWriting(WriteMode::Fields, 20, 123.4); writer.writeField(field_names, field, addresses); - writer.endWriting(); + writer.endWriting(WriteMode::Fields); } adios.FlushAll(); From f61d1b827f18df7cb31d8ed4230ef71625055206 Mon Sep 17 00:00:00 2001 From: haykh Date: Wed, 29 Jan 2025 18:22:37 -0500 Subject: [PATCH 259/773] match field test --- src/kernels/fields_bcs.hpp | 1 + src/kernels/tests/CMakeLists.txt | 1 + src/kernels/tests/flds_bc.cpp | 210 +++++++++++++++++++++++++++++++ 3 files changed, 212 insertions(+) create mode 100644 src/kernels/tests/flds_bc.cpp diff --git a/src/kernels/fields_bcs.hpp b/src/kernels/fields_bcs.hpp index 6fa5d6d68..363ff3ad2 100644 --- a/src/kernels/fields_bcs.hpp +++ b/src/kernels/fields_bcs.hpp @@ -30,6 +30,7 @@ namespace kernel::bc { * * @brief Applies matching boundary conditions (with a smooth profile) in a specific direction. * @note If a component is not specified in the field setter, it is ignored. + * @note It is supposed to only be called on the active side of the absorbing edge (so sign is not needed). */ template struct MatchBoundaries_kernel { diff --git a/src/kernels/tests/CMakeLists.txt b/src/kernels/tests/CMakeLists.txt index 10e8bb944..a41ea43ef 100644 --- a/src/kernels/tests/CMakeLists.txt +++ b/src/kernels/tests/CMakeLists.txt @@ -31,3 +31,4 @@ gen_test(fields_to_phys) gen_test(prtls_to_phys) gen_test(gca_pusher) gen_test(prtl_bc) +gen_test(flds_bc) diff --git a/src/kernels/tests/flds_bc.cpp b/src/kernels/tests/flds_bc.cpp new file mode 100644 index 000000000..aba829e8b --- /dev/null +++ b/src/kernels/tests/flds_bc.cpp @@ -0,0 +1,210 @@ +#include "enums.h" +#include "global.h" + +#include "arch/kokkos_aliases.h" +#include "utils/comparators.h" +#include "utils/error.h" + +#include "metrics/minkowski.h" + +#include "kernels/fields_bcs.hpp" + +#include + +#include +#include +#include + +using namespace ntt; +using namespace kernel::bc; +using namespace metric; + +void errorIf(bool condition, const std::string& message) { + if (condition) { + throw std::runtime_error(message); + } +} + +template +struct DummyFieldsBCs { + DummyFieldsBCs() {} + + Inline auto ex1(const coord_t&) const -> real_t { + return TWO; + } + + Inline auto ex2(const coord_t&) const -> real_t { + return THREE; + } + + Inline auto bx2(const coord_t&) const -> real_t { + return FOUR; + } + + Inline auto bx3(const coord_t&) const -> real_t { + return FIVE; + } +}; + +Inline auto equal(real_t a, real_t b, const char* msg, real_t acc) -> bool { + if (not(math::abs(a - b) < acc)) { + printf("%.12e != %.12e [%.12e] %s\n", a, b, math::abs(a - b), msg); + return false; + } + return true; +} + +template +void testFldsBCs(const std::vector& res) { + errorIf(res.size() != (unsigned short)D, "res.size() != D"); + boundaries_t sx; + for (const auto& r : res) { + sx.emplace_back(ZERO, r); + } + const auto metric = Minkowski { res, sx }; + auto fset = DummyFieldsBCs {}; + ndfield_t flds; + if constexpr (D == Dim::_1D) { + flds = ndfield_t { "flds", res[0] + 2 * N_GHOSTS }; + } else if constexpr (D == Dim::_2D) { + flds = ndfield_t { "flds", res[0] + 2 * N_GHOSTS, res[1] + 2 * N_GHOSTS }; + } else if constexpr (D == Dim::_3D) { + flds = ndfield_t { "flds", + res[0] + 2 * N_GHOSTS, + res[1] + 2 * N_GHOSTS, + res[2] + 2 * N_GHOSTS }; + } + + range_t range; + + if constexpr (D == Dim::_1D) { + range = CreateRangePolicy({ res[0] / 2 + N_GHOSTS }, + { res[0] + 2 * N_GHOSTS }); + } else if constexpr (D == Dim::_2D) { + range = CreateRangePolicy({ res[0] / 2 + N_GHOSTS, 0 }, + { res[0] + 2 * N_GHOSTS, res[1] + N_GHOSTS }); + } else if constexpr (D == Dim::_3D) { + range = CreateRangePolicy( + { res[0] / 2 + N_GHOSTS, 0, 0 }, + { res[0] + 2 * N_GHOSTS, res[1] + N_GHOSTS, res[2] + N_GHOSTS }); + } + + const auto xg_edge = (real_t)(sx[0].second); + const auto dx_abs = (real_t)(res[0] / 10.0); + + Kokkos::parallel_for( + "MatchBoundaries_kernel", + range, + MatchBoundaries_kernel( + flds, + fset, + metric, + xg_edge, + dx_abs, + BC::E | BC::B)); + + if constexpr (D == Dim::_1D) { + Kokkos::parallel_for( + "MatchBoundaries_kernel", + CreateRangePolicy({ N_GHOSTS }, { res[0] + N_GHOSTS }), + Lambda(index_t i1) { + const auto x = static_cast(i1 - N_GHOSTS); + const auto factor1 = math::tanh( + FOUR * math::abs(x + HALF - xg_edge) / dx_abs); + const auto factor2 = math::tanh(FOUR * math::abs(x - xg_edge) / dx_abs); + if (not cmp::AlmostEqual(flds(i1, em::ex1), TWO * (ONE - factor1))) { + printf("%f != %f\n", flds(i1, em::ex1), TWO * (ONE - factor1)); + raise::KernelError(HERE, "incorrect ex1"); + } + if (not cmp::AlmostEqual(flds(i1, em::ex2), THREE * (ONE - factor2))) { + printf("%f != %f\n", flds(i1, em::ex2), THREE * (ONE - factor2)); + raise::KernelError(HERE, "incorrect ex2"); + } + if (not cmp::AlmostEqual(flds(i1, em::bx2), FOUR * (ONE - factor1))) { + printf("%f != %f\n", flds(i1, em::bx2), FOUR * (ONE - factor1)); + raise::KernelError(HERE, "incorrect bx2"); + } + if (not cmp::AlmostEqual(flds(i1, em::bx3), FIVE * (ONE - factor1))) { + printf("%f != %f\n", flds(i1, em::bx3), FIVE * (ONE - factor1)); + raise::KernelError(HERE, "incorrect bx3"); + } + }); + } else if constexpr (D == Dim::_2D) { + Kokkos::parallel_for( + "MatchBoundaries_kernel", + CreateRangePolicy({ N_GHOSTS, N_GHOSTS }, + { res[0] + N_GHOSTS, res[1] + N_GHOSTS }), + Lambda(index_t i1, index_t i2) { + const auto x = static_cast(i1 - N_GHOSTS); + const auto factor1 = math::tanh( + FOUR * math::abs(x + HALF - xg_edge) / dx_abs); + const auto factor2 = math::tanh(FOUR * math::abs(x - xg_edge) / dx_abs); + if (not cmp::AlmostEqual(flds(i1, i2, em::ex1), TWO * (ONE - factor1))) { + printf("%f != %f\n", flds(i1, i2, em::ex1), TWO * (ONE - factor1)); + raise::KernelError(HERE, "incorrect ex1"); + } + if (not cmp::AlmostEqual(flds(i1, i2, em::ex2), THREE * (ONE - factor2))) { + printf("%f != %f\n", flds(i1, i2, em::ex2), THREE * (ONE - factor2)); + raise::KernelError(HERE, "incorrect ex2"); + } + if (not cmp::AlmostEqual(flds(i1, i2, em::bx2), FOUR * (ONE - factor1))) { + printf("%f != %f\n", flds(i1, i2, em::bx2), FOUR * (ONE - factor1)); + raise::KernelError(HERE, "incorrect bx2"); + } + if (not cmp::AlmostEqual(flds(i1, i2, em::bx3), FIVE * (ONE - factor1))) { + printf("%f != %f\n", flds(i1, i2, em::bx3), FIVE * (ONE - factor1)); + raise::KernelError(HERE, "incorrect bx3"); + } + }); + } else if constexpr (D == Dim::_3D) { + Kokkos::parallel_for( + "MatchBoundaries_kernel", + CreateRangePolicy( + { N_GHOSTS, N_GHOSTS, N_GHOSTS }, + { res[0] + N_GHOSTS, res[1] + N_GHOSTS, res[2] + N_GHOSTS }), + Lambda(index_t i1, index_t i2, index_t i3) { + const auto x = static_cast(i1 - N_GHOSTS); + const auto factor1 = math::tanh( + FOUR * math::abs(x + HALF - xg_edge) / dx_abs); + const auto factor2 = math::tanh(FOUR * math::abs(x - xg_edge) / dx_abs); + if (not cmp::AlmostEqual(flds(i1, i2, i3, em::ex1), TWO * (ONE - factor1))) { + printf("%f != %f\n", flds(i1, i2, i3, em::ex1), TWO * (ONE - factor1)); + raise::KernelError(HERE, "incorrect ex1"); + } + if (not cmp::AlmostEqual(flds(i1, i2, i3, em::ex2), + THREE * (ONE - factor2))) { + printf("%f != %f\n", flds(i1, i2, i3, em::ex2), THREE * (ONE - factor2)); + raise::KernelError(HERE, "incorrect ex2"); + } + if (not cmp::AlmostEqual(flds(i1, i2, i3, em::bx2), + FOUR * (ONE - factor1))) { + printf("%f != %f\n", flds(i1, i2, i3, em::bx2), FOUR * (ONE - factor1)); + raise::KernelError(HERE, "incorrect bx2"); + } + if (not cmp::AlmostEqual(flds(i1, i2, i3, em::bx3), + FIVE * (ONE - factor1))) { + printf("%f != %f\n", flds(i1, i2, i3, em::bx3), FIVE * (ONE - factor1)); + raise::KernelError(HERE, "incorrect bx3"); + } + }); + } +} + +auto main(int argc, char* argv[]) -> int { + Kokkos::initialize(argc, argv); + + try { + using namespace ntt; + + testFldsBCs({ 24 }); + testFldsBCs({ 64, 32 }); + testFldsBCs({ 14, 22, 15 }); + + } catch (std::exception& e) { + std::cerr << e.what() << std::endl; + Kokkos::finalize(); + return 1; + } + Kokkos::finalize(); + return 0; +} From df3be98ec134a27374c4b116504bb1fdde34b585 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Thu, 30 Jan 2025 10:30:17 -0500 Subject: [PATCH 260/773] updated deposit setup --- setups/grpic/deposit/deposit.toml | 60 +++++++++++++++++++------------ 1 file changed, 37 insertions(+), 23 deletions(-) diff --git a/setups/grpic/deposit/deposit.toml b/setups/grpic/deposit/deposit.toml index c577f9c68..66c848de9 100644 --- a/setups/grpic/deposit/deposit.toml +++ b/setups/grpic/deposit/deposit.toml @@ -1,17 +1,17 @@ [simulation] name = "deposit" engine = "grpic" - runtime = 50.0 + runtime = 500.0 [grid] - resolution = [512,512] - extent = [[1.2, 20.0]] + resolution = [256,256] + extent = [[0.8, 20.0]] [grid.metric] - metric = "kerr_schild" + metric = "qkerr_schild" qsph_r0 = 0.0 qsph_h = 0.0 - ks_a = 0.0 + ks_a = 0.95 [grid.boundaries] fields = [["ABSORB"]] @@ -29,7 +29,7 @@ [algorithms.gr] pusher_niter = 10 - pusher_eps = 1e-6 + pusher_eps = 1e-2 [algorithms.timestep] CFL = 0.5 @@ -45,41 +45,55 @@ label = "e-" mass = 1.0 charge = -1.0 - maxnpart = 1e0 + maxnpart = 5e0 [[particles.species]] label = "e+" mass = 1.0 charge = 1.0 - maxnpart = 1e0 + maxnpart = 5e0 [setup] - x1s = [17.00000] - y1s = [1.570796] - z1s = [0.000000] - ux1s = [5.000000] - uy1s = [0.000000] - uz1s = [0.000000] - - x2s = [17.00000] - y2s = [1.570796] - z2s = [0.000000] - ux2s = [-5.000000] - uy2s = [0.000000] - uz2s = [0.000000] + x1s = [5.000, 15.0, 17.0, 4.0, 12.0] + y1s = [1.5707963268, 0.7853981634, 2.3561944902, 0.1, 3.0415926536] + z1s = [0.0, 0.0, 0.0, 0.0, 0.0] + ux1s = [5.0, 5.0, 5.0, 5.0, 5.0] + uy1s = [4.0, 7.0, 4.0, -5.0, 9.0] + uz1s = [2.0, 1.0, 0.5, 3.0, 2.4] + + x2s = [5.000, 15.0, 17.0, 4.0, 12.0] + y2s = [1.5707963268, 0.7853981634, 2.3561944902, 0.1, 3.0415926536] + z2s = [0.0, 0.0, 0.0, 0.0, 0.0] + ux2s = [-5.0, -5.0, -5.0, -5.0, -5.0] + uy2s = [4.0, 7.0, 4.0, -5.0, 9.0] + uz2s = [2.0, 1.0, 0.5, 3.0, 2.4] + + #x1s = [17.00000] + #y1s = [1.570796] + #z1s = [0.000000] + #ux1s = [5.000000] + #uy1s = [0.000000] + #uz1s = [0.000000] + + #x2s = [17.00000] + #y2s = [1.570796] + #z2s = [0.000000] + #ux2s = [-5.000000] + #uy2s = [0.000000] + #uz2s = [0.000000] [output] format = "hdf5" [output.fields] enable = true - interval_time = 0.5 + interval_time = 1.0 quantities = ["D"] [output.particles] enable = true stride = 1 - interval_time = 0.5 + interval_time = 1.0 species = [] [output.spectra] From a9f25d28eb92c86883416d2057b18436892af38c Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Thu, 30 Jan 2025 10:32:00 -0500 Subject: [PATCH 261/773] engines/grpic: minor updates --- src/engines/grpic.hpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index d6a45c953..275743df0 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -916,18 +916,16 @@ namespace ntt { void AmpereCurrents(domain_t& domain, const gr_ampere& g) { logger::Checkpoint("Launching Ampere kernel for adding currents", HERE); const auto q0 = m_params.template get("scales.q0"); - // const auto n0 = m_params.template get("scales.n0"); const auto B0 = m_params.template get("scales.B0"); const auto coeff = -dt * q0 / B0; - // auto range = range_with_axis_BCs(domain); auto range = CreateRangePolicy( { domain.mesh.i_min(in::x1), domain.mesh.i_min(in::x2)}, { domain.mesh.i_max(in::x1), domain.mesh.i_max(in::x2) + 1}); const auto ni2 = domain.mesh.n_active(in::x2); if (g == gr_ampere::aux) { - // Updates D0 with J. - Kokkos::parallel_for("Ampere-1", + // Updates D0 with J: D0(n-1/2) -> (J(n)) -> D0(n+1/2) + Kokkos::parallel_for("AmpereCurrentsAux", range, kernel::gr::CurrentsAmpere_kernel(domain.fields.em0, domain.fields.cur, @@ -936,8 +934,8 @@ namespace ntt { ni2, domain.mesh.flds_bc())); } else if (g == gr_ampere::main) { - // Updates D0 with J0. - Kokkos::parallel_for("Ampere-2", + // Updates D0 with J0: D0(n) -> (J0(n+1/2)) -> D0(n+1) + Kokkos::parallel_for("mpereCurrentsMain", range, kernel::gr::CurrentsAmpere_kernel(domain.fields.em0, domain.fields.cur0, From f81a9a5e2928a0037759302fe6a3fb366db8a745 Mon Sep 17 00:00:00 2001 From: haykh Date: Thu, 30 Jan 2025 14:44:22 -0500 Subject: [PATCH 262/773] minor --- dev/nix/shell.nix | 3 --- input.example.toml | 4 ++-- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/dev/nix/shell.nix b/dev/nix/shell.nix index 13509dac2..1f21e82b0 100644 --- a/dev/nix/shell.nix +++ b/dev/nix/shell.nix @@ -26,10 +26,7 @@ pkgs.mkShell { python312Packages.jupyter cmake-format -<<<<<<< HEAD cmake-lint -======= ->>>>>>> 8b0f205a866f7f7534d8190e3ebee580ea09f7d8 neocmakelsp black pyright diff --git a/input.example.toml b/input.example.toml index 3f367995a..788c30685 100644 --- a/input.example.toml +++ b/input.example.toml @@ -93,8 +93,8 @@ # @valid: "PERIODIC", "MATCH", "FIXED", "ATMOSPHERE", "CUSTOM", "HORIZON" # @example: [["CUSTOM", "MATCH"]] (for 2D spherical [[rmin, rmax]]) # @note: When periodic in any of the directions, you should only set one value: [..., ["PERIODIC"], ...] - # @note: In spherical, bondaries in theta/phi are set automatically (only specify bc @ [rmin, rmax]): [["ATMOSPHERE", "match"]] - # @note: In GR, the horizon boundary is set automatically (only specify bc @ rmax): [["match"]] + # @note: In spherical, bondaries in theta/phi are set automatically (only specify bc @ [rmin, rmax]): [["ATMOSPHERE", "MATCH"]] + # @note: In GR, the horizon boundary is set automatically (only specify bc @ rmax): [["MATCH"]] fields = "" # Boundary conditions for fields: # @required From 05b9b86aab9c86f1dc6b605a02f2d09f3ab3ea36 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova Date: Tue, 24 Sep 2024 12:20:06 -0400 Subject: [PATCH 263/773] compilable example for grpic --- setups/grpic/pgen_grpic_example.hpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/setups/grpic/pgen_grpic_example.hpp b/setups/grpic/pgen_grpic_example.hpp index f553ae849..3374a12d7 100644 --- a/setups/grpic/pgen_grpic_example.hpp +++ b/setups/grpic/pgen_grpic_example.hpp @@ -12,7 +12,7 @@ namespace user { using namespace ntt; template - struct PGen : public ProblemGenerator { + struct PGen : public arch::ProblemGenerator { // compatibility traits for the problem generator static constexpr auto engines { traits::compatible_with::value }; static constexpr auto metrics { @@ -21,13 +21,12 @@ namespace user { static constexpr auto dimensions { traits::compatible_with::value }; // for easy access to variables in the child class - using ProblemGenerator::D; - using ProblemGenerator::C; - using ProblemGenerator::params; - using ProblemGenerator::domain; + using arch::ProblemGenerator::D; + using arch::ProblemGenerator::C; + using arch::ProblemGenerator::params; inline PGen(SimulationParams& p, const Metadomain&) : - ProblemGenerator(p) {} + arch::ProblemGenerator(p) {} inline PGen() {} }; From 010d04115a1ecb5084ab6751087ddfc81f5f8bcf Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Tue, 24 Sep 2024 12:48:33 -0400 Subject: [PATCH 264/773] starting a test pgen --- setups/grpic/wald/pgen.hpp | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 setups/grpic/wald/pgen.hpp diff --git a/setups/grpic/wald/pgen.hpp b/setups/grpic/wald/pgen.hpp new file mode 100644 index 000000000..3374a12d7 --- /dev/null +++ b/setups/grpic/wald/pgen.hpp @@ -0,0 +1,36 @@ +#ifndef PROBLEM_GENERATOR_H +#define PROBLEM_GENERATOR_H + +#include "enums.h" +#include "global.h" + +#include "arch/traits.h" + +#include "archetypes/problem_generator.h" + +namespace user { + using namespace ntt; + + template + struct PGen : public arch::ProblemGenerator { + // compatibility traits for the problem generator + static constexpr auto engines { traits::compatible_with::value }; + static constexpr auto metrics { + traits::compatible_with::value + }; + static constexpr auto dimensions { traits::compatible_with::value }; + + // for easy access to variables in the child class + using arch::ProblemGenerator::D; + using arch::ProblemGenerator::C; + using arch::ProblemGenerator::params; + + inline PGen(SimulationParams& p, const Metadomain&) : + arch::ProblemGenerator(p) {} + + inline PGen() {} + }; + +} // namespace user + +#endif From 5efd5565d23d1ae5b45093d5b7d1b7959a24038e Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Tue, 24 Sep 2024 13:46:21 -0400 Subject: [PATCH 265/773] engines/grpic: added relevant libraries --- src/engines/grpic.hpp | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index d082d617f..f36b27758 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -13,15 +13,38 @@ #define ENGINES_GRPIC_GRPIC_H #include "enums.h" +#include "global.h" +#include "arch/kokkos_aliases.h" +#include "arch/traits.h" +#include "utils/log.h" +#include "utils/numeric.h" #include "utils/timer.h" #include "utils/toml.h" +#include "archetypes/particle_injector.h" #include "framework/domain/domain.h" #include "framework/parameters.h" #include "engines/engine.hpp" +#include "kernels/ampere_gr.hpp" +#include "kernels/aux_fields_gr.hpp" +#include "kernels/currents_deposit.hpp" +#include "kernels/digital_filter.hpp" +#include "kernels/faraday_gr.hpp" +#include "kernels/fields_bcs.hpp" +#include "kernels/particle_moments.hpp" +#include "kernels/particle_pusher_gr.hpp" + +#include "pgen.hpp" + +#include +#include + +#include +#include + namespace ntt { template @@ -31,6 +54,7 @@ namespace ntt { using Engine::m_params; using Engine::m_metadomain; + public: static constexpr auto S { SimEngine::SRPIC }; From 397a27fa1690cd9639f00ff4f3ef3ab51c50d629 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Tue, 24 Sep 2024 13:58:39 -0400 Subject: [PATCH 266/773] kernels/ampere_gr: fixed dublicate ErrorIF --- src/kernels/ampere_gr.hpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/kernels/ampere_gr.hpp b/src/kernels/ampere_gr.hpp index 5af0fa4ef..045eb1729 100644 --- a/src/kernels/ampere_gr.hpp +++ b/src/kernels/ampere_gr.hpp @@ -57,9 +57,6 @@ namespace kernel::gr { , coeff { coeff } { if constexpr ((D == Dim::_2D) || (D == Dim::_3D)) { raise::ErrorIf(boundaries.size() < 2, "boundaries defined incorrectly", HERE); - raise::ErrorIf(boundaries[1].size() < 2, - "boundaries defined incorrectly", - HERE); is_axis_i2min = (boundaries[1].first == FldsBC::AXIS); is_axis_i2max = (boundaries[1].second == FldsBC::AXIS); } From 86b5a61557458a5fefc907043de39fd1835469a5 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Tue, 24 Sep 2024 14:21:40 -0400 Subject: [PATCH 267/773] engines/grpic: minor syntax adustments to match engines/srpic --- src/engines/grpic.hpp | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index f36b27758..3a223cc79 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -4,7 +4,7 @@ * @implements * - ntt::GRPICEngine<> : ntt::Engine<> * @cpp: - * - srpic.cpp + * - grpic.cpp * @namespaces: * - ntt:: */ @@ -27,7 +27,6 @@ #include "framework/parameters.h" #include "engines/engine.hpp" - #include "kernels/ampere_gr.hpp" #include "kernels/aux_fields_gr.hpp" #include "kernels/currents_deposit.hpp" @@ -36,7 +35,6 @@ #include "kernels/fields_bcs.hpp" #include "kernels/particle_moments.hpp" #include "kernels/particle_pusher_gr.hpp" - #include "pgen.hpp" #include @@ -49,20 +47,32 @@ namespace ntt { template class GRPICEngine : public Engine { - using base_t = Engine; - - using Engine::m_params; - using Engine::m_metadomain; - + using base_t = Engine; + using pgen_t = user::PGen; + using domain_t = Domain; + // constexprs + using base_t::pgen_is_ok; + // contents + using base_t::m_metadomain; + using base_t::m_params; + using base_t::m_pgen; + // methods + using base_t::init; + // variables + using base_t::dt; + using base_t::max_steps; + using base_t::runtime; + using base_t::step; + using base_t::time; public: - static constexpr auto S { SimEngine::SRPIC }; + static constexpr auto S { SimEngine::GRPIC }; - GRPICEngine(const SimulationParams& params) : base_t { params } {} + GRPICEngine(SimulationParams& params) : base_t { params } {} ~GRPICEngine() = default; - void step_forward(timer::Timers&, Domain&) override {} + void step_forward(timer::Timers& timers, domain_t& dom) override {} }; } // namespace ntt From 48095eed5ddd41606bc1ab8b403bd2a2382a2190 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Tue, 24 Sep 2024 17:06:01 -0400 Subject: [PATCH 268/773] engines/grpic: added initialisation of fields and boundary conditions --- src/engines/grpic.hpp | 184 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 182 insertions(+), 2 deletions(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index 3a223cc79..dbc421d96 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -72,9 +72,189 @@ namespace ntt { ~GRPICEngine() = default; - void step_forward(timer::Timers& timers, domain_t& dom) override {} - }; + void step_forward(timer::Timers& timers, domain_t& dom) override { + const auto fieldsolver_enabled = m_params.template get( + "algorithms.toggles.fieldsolver"); + const auto deposit_enabled = m_params.template get( + "algorithms.toggles.deposit"); + const auto sort_interval = m_params.template get( + "particles.sort_interval"); + + if (step == 0) { + // communicate fields and apply BCs on the first timestep + /** + * Initially: em0::B -- + * em0::D -- + * em::B at -1/2 + * em::D at -1/2 + * + * cur0::J -- + * cur::J -- + * + * aux::E -- + * aux::H -- + * + * x_prtl at -1/2 + * u_prtl at -1/2 + */ + + /** + * em0::D, em::D, em0::B, em::B <- boundary conditions + */ + m_metadomain.CommunicateFields(dom, Comm::B | Comm::B0 | Comm::D | Comm::D0); + FieldBoundaries(dom, BC::B | BC::D); + + } + } + + void FieldBoundaries(domain_t& domain, BCTags tags) { + for (auto& direction : dir::Directions::orth) { + if (m_metadomain.mesh().flds_bc_in(direction) == FldsBC::ABSORB) { + AbsorbFieldsIn(direction, domain, tags); + } else if (m_metadomain.mesh().flds_bc_in(direction) == FldsBC::AXIS) { + if (domain.mesh.flds_bc_in(direction) == FldsBC::AXIS) { + AxisFieldsIn(direction, domain, tags); + } + } else if (m_metadomain.mesh().flds_bc_in(direction) == FldsBC::CUSTOM) { + if (domain.mesh.flds_bc_in(direction) == FldsBC::CUSTOM) { + CustomFieldsIn(direction, domain, tags); + } + } else if (m_metadomain.mesh().flds_bc_in(direction) == FldsBC::HORIZON) { + raise::Error("HORIZON BCs only applicable for GR", HERE); + } + } // loop over directions + } + void AbsorbFieldsIn(dir::direction_t direction, + domain_t& domain, + BCTags tags) { + /** + * absorbing boundaries + */ + const auto ds = m_params.template get( + "grid.boundaries.absorb.ds"); + const auto dim = direction.get_dim(); + real_t xg_min, xg_max, xg_edge; + auto sign = direction.get_sign(); + if (sign > 0) { // + direction + xg_max = m_metadomain.mesh().extent(dim).second; + xg_min = xg_max - ds; + xg_edge = xg_max; + } else { // - direction + xg_min = m_metadomain.mesh().extent(dim).first; + xg_max = xg_min + ds; + xg_edge = xg_min; + } + boundaries_t box; + boundaries_t incl_ghosts; + for (unsigned short d { 0 }; d < M::Dim; ++d) { + if (d == static_cast(dim)) { + box.push_back({ xg_min, xg_max }); + if (sign > 0) { + incl_ghosts.push_back({ false, true }); + } else { + incl_ghosts.push_back({ true, false }); + } + } else { + box.push_back(Range::All); + incl_ghosts.push_back({ true, true }); + } + } + if (not domain.mesh.Intersects(box)) { + return; + } + const auto intersect_range = domain.mesh.ExtentToRange(box, incl_ghosts); + tuple_t range_min { 0 }; + tuple_t range_max { 0 }; + + for (unsigned short d { 0 }; d < M::Dim; ++d) { + range_min[d] = intersect_range[d].first; + range_max[d] = intersect_range[d].second; + } + if (dim == in::x1) { + Kokkos::parallel_for( + "AbsorbFields", + CreateRangePolicy(range_min, range_max), + kernel::AbsorbBoundaries_kernel(domain.fields.em, + domain.mesh.metric, + xg_edge, + ds, + tags)); + } else if (dim == in::x2) { + if constexpr (M::Dim == Dim::_2D or M::Dim == Dim::_3D) { + Kokkos::parallel_for( + "AbsorbFields", + CreateRangePolicy(range_min, range_max), + kernel::AbsorbBoundaries_kernel(domain.fields.em, + domain.mesh.metric, + xg_edge, + ds, + tags)); + } else { + raise::Error("Invalid dimension", HERE); + } + } else if (dim == in::x3) { + if constexpr (M::Dim == Dim::_3D) { + Kokkos::parallel_for( + "AbsorbFields", + CreateRangePolicy(range_min, range_max), + kernel::AbsorbBoundaries_kernel(domain.fields.em, + domain.mesh.metric, + xg_edge, + ds, + tags)); + } else { + raise::Error("Invalid dimension", HERE); + } + } + } + + void AxisFieldsIn(dir::direction_t direction, + domain_t& domain, + BCTags tags) { + /** + * axis boundaries + */ + raise::ErrorIf(M::CoordType == Coord::Cart, + "Invalid coordinate type for axis BCs", + HERE); + raise::ErrorIf(direction.get_dim() != in::x2, + "Invalid axis direction, should be x2", + HERE); + const auto i2_min = domain.mesh.i_min(in::x2); + const auto i2_max = domain.mesh.i_max(in::x2); + if (direction.get_sign() < 0) { + Kokkos::parallel_for( + "AxisBCFields", + domain.mesh.n_all(in::x1), + kernel::AxisBoundaries_kernel(domain.fields.em, i2_min, tags)); + } else { + Kokkos::parallel_for( + "AxisBCFields", + domain.mesh.n_all(in::x1), + kernel::AxisBoundaries_kernel(domain.fields.em, i2_max, tags)); + } + } + + void CustomFieldsIn(dir::direction_t direction, + domain_t& domain, + BCTags tags) { + (void)direction; + (void)domain; + (void)tags; + raise::Error("Custom boundaries not implemented", HERE); + // if constexpr ( + // traits::has_member::value) { + // const auto [box, custom_fields] = m_pgen.CustomFields(time); + // if (domain.mesh.Intersects(box)) { + // } + // + // } else { + // raise::Error("Custom boundaries not implemented", HERE); + // } + } + + }; } // namespace ntt #endif // ENGINES_GRPIC_GRPIC_H From 95efa492085d35c89be07dc566c322b47496d0da Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Wed, 25 Sep 2024 12:55:12 -0400 Subject: [PATCH 269/773] engines/grpic: added cope of em field into em0 --- src/engines/grpic.hpp | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index dbc421d96..61c1fcbec 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -104,6 +104,13 @@ namespace ntt { m_metadomain.CommunicateFields(dom, Comm::B | Comm::B0 | Comm::D | Comm::D0); FieldBoundaries(dom, BC::B | BC::D); + /** + * em0::B <- em::B + * em0::D <- em::D + * + * Now: em0::B & em0::D at -1/2 + */ + CopyFields(dom); } } @@ -254,6 +261,22 @@ namespace ntt { // } } + /** + * @brief Swaps em and em0 fields, cur and cur0 currents. + */ + // void SwapFields() { + // auto& mblock = this->meshblock; + // std::swap(mblock.em, mblock.em0); + // std::swap(mblock.cur, mblock.cur0); + // } + + /** + * @brief Copies em fields into em0 + */ + void CopyFields(domain_t& domain) { + Kokkos::deep_copy(domain.fields.em0, domain.fields.em); + } + }; } // namespace ntt From efcb68f614616ccc4e124d8129620dea4ac672e4 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Wed, 25 Sep 2024 15:00:21 -0400 Subject: [PATCH 270/773] engines/grpic: added computation of aux fields --- src/engines/grpic.hpp | 82 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 81 insertions(+), 1 deletion(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index 61c1fcbec..4fc72a2c2 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -45,6 +45,15 @@ namespace ntt { + enum class gr_getE { + D0_B, + D_B0 + }; + enum class gr_getH { + D_B0, + D0_B0 + }; + template class GRPICEngine : public Engine { using base_t = Engine; @@ -111,6 +120,15 @@ namespace ntt { * Now: em0::B & em0::D at -1/2 */ CopyFields(dom); + + /** + * aux::E <- alpha * em::D + beta x em0::B + * aux::H <- alpha * em::B0 - beta x em::D + * + * Now: aux::E & aux::H at -1/2 + */ + ComputeAuxE(dom, gr_getE::D0_B); + ComputeAuxH(dom, gr_getH::D_B0); } } @@ -273,10 +291,72 @@ namespace ntt { /** * @brief Copies em fields into em0 */ - void CopyFields(domain_t& domain) { + void CopyFields(domain_t& domain) { Kokkos::deep_copy(domain.fields.em0, domain.fields.em); } + void ComputeAuxE(domain_t& domain, const gr_getE& g) { + auto range = range_with_axis_BCs(domain); + if (g == gr_getE::D0_B) { + Kokkos::parallel_for("ComputeAuxE", + range, + kernel::gr::ComputeAuxE_kernel(domain.fields.em0, + domain.fields.em, + domain.fields.em, + domain.mesh.metric)); + } else if (g == gr_getE::D_B0) { + Kokkos::parallel_for("ComputeAuxE", + range, + kernel::gr::ComputeAuxE_kernel(domain.fields.em, + domain.fields.em0, + domain.fields.em, + domain.mesh.metric)); + } else { + raise::Error("Wrong option for `g`", HERE); + } + } + + void ComputeAuxH(domain_t& domain, const gr_getH& g) { + auto range = range_with_axis_BCs(domain); + if (g == gr_getH::D_B0) { + Kokkos::parallel_for("ComputeAuxH", + range, + kernel::gr::ComputeAuxH_kernel(domain.fields.em, + domain.fields.em0, + domain.fields.em, + domain.mesh.metric)); + } else if (g == gr_getH::D0_B0) { + Kokkos::parallel_for("ComputeAuxH", + range, + kernel::gr::ComputeAuxH_kernel(domain.fields.em0, + domain.fields.em0, + domain.fields.em, + domain.mesh.metric)); + } else { + raise::Error("Wrong option for `g`", HERE); + } + } + + auto range_with_axis_BCs(const domain_t& domain) -> range_t { + auto range = domain.mesh.rangeActiveCells(); + if constexpr (M::CoordType != Coord::Cart) { + /** + * @brief taking one extra cell in the x1 and x2 directions if AXIS BCs + */ + if constexpr (M::Dim == Dim::_2D) { + if (domain.mesh.flds_bc_in({ 0, +1 }) == FldsBC::AXIS) { + range = CreateRangePolicy( + { domain.mesh.i_min(in::x1) - 1, domain.mesh.i_min(in::x2) }, + { domain.mesh.i_max(in::x1), domain.mesh.i_max(in::x2) + 1 }); + } + } else if constexpr (M::Dim == Dim::_3D) { + raise::Error("Invalid dimension", HERE); + } + } + return range; + } + + }; } // namespace ntt From 365d03b0309537f37fe045dd3ec5cd71a64700b2 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Wed, 25 Sep 2024 16:21:32 -0400 Subject: [PATCH 271/773] engines/grpis: fixed "aux" for passing to aux kernels, added Faraday function --- src/engines/grpic.hpp | 52 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 50 insertions(+), 2 deletions(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index 4fc72a2c2..f67e0aa24 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -53,6 +53,15 @@ namespace ntt { D_B0, D0_B0 }; + enum class gr_faraday { + aux, + main + }; + enum class gr_ampere { + init, + aux, + main + }; template class GRPICEngine : public Engine { @@ -129,9 +138,17 @@ namespace ntt { */ ComputeAuxE(dom, gr_getE::D0_B); ComputeAuxH(dom, gr_getH::D_B0); + + /** + * aux::E, aux::H <- boundary conditions + */ + // ?? aux field boundaries ?? + + Faraday(dom, gr_faraday::aux, HALF); } } +/* algorithm substeps --------------------------------------------------- */ void FieldBoundaries(domain_t& domain, BCTags tags) { for (auto& direction : dir::Directions::orth) { if (m_metadomain.mesh().flds_bc_in(direction) == FldsBC::ABSORB) { @@ -323,14 +340,14 @@ namespace ntt { range, kernel::gr::ComputeAuxH_kernel(domain.fields.em, domain.fields.em0, - domain.fields.em, + domain.fields.aux, domain.mesh.metric)); } else if (g == gr_getH::D0_B0) { Kokkos::parallel_for("ComputeAuxH", range, kernel::gr::ComputeAuxH_kernel(domain.fields.em0, domain.fields.em0, - domain.fields.em, + domain.fields.aux, domain.mesh.metric)); } else { raise::Error("Wrong option for `g`", HERE); @@ -356,6 +373,37 @@ namespace ntt { return range; } + void Faraday(domain_t& domain, const gr_faraday& g, real_t fraction = ONE) { + logger::Checkpoint("Launching Faraday kernel", HERE); + const auto dT = fraction * + m_params.template get( + "algorithms.timestep.correction") * + dt; + if (g == gr_faraday::aux) { + Kokkos::parallel_for("Faraday", + domain.mesh.rangeActiveCells(), + kernel::gr::Faraday_kernel(domain.fields.em0, + domain.fields.em0, + domain.fields.aux, + domain.mesh.metric, + dT, + domain.mesh.i_max(in::x2), + domain.mesh.flds_bc())); + } else if (g == gr_faraday::main) { + Kokkos::parallel_for("Faraday", + domain.mesh.rangeActiveCells(), + kernel::gr::Faraday_kernel(domain.fields.em0, + domain.fields.em0, + domain.fields.aux, + domain.mesh.metric, + dT, + domain.mesh.i_max(in::x2), + domain.mesh.flds_bc())); + + } else { + raise::Error("Wrong option for `g`", HERE); + } + } }; } // namespace ntt From 22262de0af08c6b8ad47135fe4b64c75a62b077a Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Wed, 25 Sep 2024 16:55:27 -0400 Subject: [PATCH 272/773] minor: added a comment on Faraday step --- src/engines/grpic.hpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index f67e0aa24..3578b4d79 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -144,6 +144,11 @@ namespace ntt { */ // ?? aux field boundaries ?? + /** + * em0::B <- (em0::B) <- -curl aux::E + * + * Now: em0::B at 0 + */ Faraday(dom, gr_faraday::aux, HALF); } } From 9912542a50e9f10afedbb132876521d4681842c2 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Wed, 25 Sep 2024 17:00:41 -0400 Subject: [PATCH 273/773] engines/grpic: bc for B&B0 --- src/engines/grpic.hpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index 3578b4d79..0047d9a00 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -150,6 +150,12 @@ namespace ntt { * Now: em0::B at 0 */ Faraday(dom, gr_faraday::aux, HALF); + + /** + * em0::B, em::B <- boundary conditions + */ + m_metadomain.CommunicateFields(dom, Comm::B | Comm::B0); + FieldBoundaries(dom, BC::B); } } From 50dcef88d578e957e499eb2c281908da50f3e6c3 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Wed, 25 Sep 2024 17:21:12 -0400 Subject: [PATCH 274/773] engine/grpic: fixed passing ni2 to faraday kernel. prep for ampere kernel --- src/engines/grpic.hpp | 35 +++++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index 0047d9a00..28d0f8c13 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -156,6 +156,13 @@ namespace ntt { */ m_metadomain.CommunicateFields(dom, Comm::B | Comm::B0); FieldBoundaries(dom, BC::B); + + /** + * em::D <- (em0::D) <- curl aux::H + * + * Now: em::D at 0 + */ + Ampere(dom, gr_ampere::init, HALF); } } @@ -398,7 +405,7 @@ namespace ntt { domain.fields.aux, domain.mesh.metric, dT, - domain.mesh.i_max(in::x2), + domain.mesh.n_active(in::x2), domain.mesh.flds_bc())); } else if (g == gr_faraday::main) { Kokkos::parallel_for("Faraday", @@ -408,13 +415,37 @@ namespace ntt { domain.fields.aux, domain.mesh.metric, dT, - domain.mesh.i_max(in::x2), + domain.mesh.n_active(in::x2), domain.mesh.flds_bc())); } else { raise::Error("Wrong option for `g`", HERE); } } + + void Ampere(domain_t& domain, const gr_ampere& g, real_t fraction = ONE) { + logger::Checkpoint("Launching Ampere kernel", HERE); + const auto dT = fraction * + m_params.template get( + "algorithms.timestep.correction") * + dt; + auto range = CreateRangePolicy( + { domain.mesh.i_min(in::x1), domain.mesh.i_min(in::x2) + 1}, + { domain.mesh.i_max(in::x1), domain.mesh.i_max(in::x2)}); + auto range_pole = CreateRangePolicy( + { domain.mesh.i_min(in::x1)}, + { domain.mesh.i_max(in::x1)}); + const auto ni2 = domain.mesh.n_active(in::x2); + Kokkos::parallel_for("Ampere", + range, + kernel::gr::Ampere_kernel(domain.fields.em, + domain.fields.em, + domain.fields.em, + domain.mesh.metric, + dT, + ni2, + domain.mesh.flds_bc())); + } }; } // namespace ntt From 215f3c54759bca4b93f18f39eb62fc1be79fbc0d Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Wed, 25 Sep 2024 17:51:47 -0400 Subject: [PATCH 275/773] engines/grpic: added ampere and subsequent BC --- src/engines/grpic.hpp | 140 +++++++++++++++++++++++++----------------- 1 file changed, 85 insertions(+), 55 deletions(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index 28d0f8c13..14d99003f 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -101,25 +101,26 @@ namespace ntt { if (step == 0) { // communicate fields and apply BCs on the first timestep /** - * Initially: em0::B -- - * em0::D -- - * em::B at -1/2 - * em::D at -1/2 - * - * cur0::J -- - * cur::J -- - * - * aux::E -- - * aux::H -- - * - * x_prtl at -1/2 - * u_prtl at -1/2 - */ + * Initially: em0::B -- + * em0::D -- + * em::B at -1/2 + * em::D at -1/2 + * + * cur0::J -- + * cur::J -- + * + * aux::E -- + * aux::H -- + * + * x_prtl at -1/2 + * u_prtl at -1/2 + */ /** - * em0::D, em::D, em0::B, em::B <- boundary conditions - */ - m_metadomain.CommunicateFields(dom, Comm::B | Comm::B0 | Comm::D | Comm::D0); + * em0::D, em::D, em0::B, em::B <- boundary conditions + */ + m_metadomain.CommunicateFields(dom, + Comm::B | Comm::B0 | Comm::D | Comm::D0); FieldBoundaries(dom, BC::B | BC::D); /** @@ -166,7 +167,7 @@ namespace ntt { } } -/* algorithm substeps --------------------------------------------------- */ + /* algorithm substeps --------------------------------------------------- */ void FieldBoundaries(domain_t& domain, BCTags tags) { for (auto& direction : dir::Directions::orth) { if (m_metadomain.mesh().flds_bc_in(direction) == FldsBC::ABSORB) { @@ -360,7 +361,7 @@ namespace ntt { domain.fields.em0, domain.fields.aux, domain.mesh.metric)); - } else if (g == gr_getH::D0_B0) { + } else if (g == gr_getH::D0_B0) { Kokkos::parallel_for("ComputeAuxH", range, kernel::gr::ComputeAuxH_kernel(domain.fields.em0, @@ -398,31 +399,33 @@ namespace ntt { "algorithms.timestep.correction") * dt; if (g == gr_faraday::aux) { - Kokkos::parallel_for("Faraday", - domain.mesh.rangeActiveCells(), - kernel::gr::Faraday_kernel(domain.fields.em0, - domain.fields.em0, - domain.fields.aux, - domain.mesh.metric, - dT, - domain.mesh.n_active(in::x2), - domain.mesh.flds_bc())); + Kokkos::parallel_for( + "Faraday", + domain.mesh.rangeActiveCells(), + kernel::gr::Faraday_kernel(domain.fields.em0, + domain.fields.em0, + domain.fields.aux, + domain.mesh.metric, + dT, + domain.mesh.n_active(in::x2), + domain.mesh.flds_bc())); } else if (g == gr_faraday::main) { - Kokkos::parallel_for("Faraday", - domain.mesh.rangeActiveCells(), - kernel::gr::Faraday_kernel(domain.fields.em0, - domain.fields.em0, - domain.fields.aux, - domain.mesh.metric, - dT, - domain.mesh.n_active(in::x2), - domain.mesh.flds_bc())); + Kokkos::parallel_for( + "Faraday", + domain.mesh.rangeActiveCells(), + kernel::gr::Faraday_kernel(domain.fields.em0, + domain.fields.em0, + domain.fields.aux, + domain.mesh.metric, + dT, + domain.mesh.n_active(in::x2), + domain.mesh.flds_bc())); } else { - raise::Error("Wrong option for `g`", HERE); - } + raise::Error("Wrong option for `g`", HERE); + } } - + void Ampere(domain_t& domain, const gr_ampere& g, real_t fraction = ONE) { logger::Checkpoint("Launching Ampere kernel", HERE); const auto dT = fraction * @@ -430,23 +433,50 @@ namespace ntt { "algorithms.timestep.correction") * dt; auto range = CreateRangePolicy( - { domain.mesh.i_min(in::x1), domain.mesh.i_min(in::x2) + 1}, - { domain.mesh.i_max(in::x1), domain.mesh.i_max(in::x2)}); - auto range_pole = CreateRangePolicy( - { domain.mesh.i_min(in::x1)}, - { domain.mesh.i_max(in::x1)}); + { domain.mesh.i_min(in::x1), domain.mesh.i_min(in::x2) + 1 }, + { domain.mesh.i_max(in::x1), domain.mesh.i_max(in::x2) }); + auto range_pole = CreateRangePolicy({ domain.mesh.i_min(in::x1) }, + { domain.mesh.i_max(in::x1) }); const auto ni2 = domain.mesh.n_active(in::x2); - Kokkos::parallel_for("Ampere", - range, - kernel::gr::Ampere_kernel(domain.fields.em, - domain.fields.em, - domain.fields.em, - domain.mesh.metric, - dT, - ni2, - domain.mesh.flds_bc())); - } + if (g == gr_ampere::aux) { + // First push, updates D0 with J. + Kokkos::parallel_for("Ampere-1", + range, + kernel::gr::Ampere_kernel(domain.fields.em, // has to be zeros + domain.fields.em0, + domain.fields.aux, + domain.mesh.metric, + dT, + ni2, + domain.mesh.flds_bc())); + } else if (g == gr_ampere::main) { + // Second push, updates D with J0 but assigns it to D0. + Kokkos::parallel_for("Ampere-2", + range, + kernel::gr::Ampere_kernel(domain.fields.em, + domain.fields.em0, + domain.fields.aux, + domain.mesh.metric, + dT, + ni2, + domain.mesh.flds_bc())); + } else if (g == gr_ampere::init) { + // Second push, updates D with J0 and assigns it to D. + Kokkos::parallel_for("Ampere-3", + range, + kernel::gr::Ampere_kernel(domain.fields.em, //has to be zeros + domain.fields.em, + domain.fields.aux, + domain.mesh.metric, + dT, + ni2, + domain.mesh.flds_bc())); + } else { + raise::Error("Wrong option for `g`", HERE); + } + + } }; } // namespace ntt From afc162014101938e0050cb405ee95223e8d7b87b Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Thu, 26 Sep 2024 15:25:56 -0400 Subject: [PATCH 276/773] engine/grpic: added everything for initial step, except BC for aux --- src/engines/grpic.hpp | 102 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 97 insertions(+), 5 deletions(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index 14d99003f..0e89ff400 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -164,6 +164,99 @@ namespace ntt { * Now: em::D at 0 */ Ampere(dom, gr_ampere::init, HALF); + + /** + * em0::D, em::D <- boundary conditions + */ + m_metadomain.CommunicateFields(dom, Comm::D | Comm::D0); + FieldBoundaries(dom, BC::D); + + /** + * aux::E <- alpha * em::D + beta x em0::B + * aux::H <- alpha * em0::B - beta x em::D + * + * Now: aux::E & aux::H at 0 + */ + ComputeAuxE(dom, gr_getE::D_B0); + ComputeAuxH(dom, gr_getH::D_B0); + + /** + * aux::E, aux::H <- boundary conditions + */ + // ?? aux field boundaries ?? + + // !ADD: GR -- particles? + + /** + * em0::B <- (em::B) <- -curl aux::E + * + * Now: em0::B at 1/2 + */ + Faraday(dom, gr_faraday::main, ONE); + /** + * em0::B, em::B <- boundary conditions + */ + m_metadomain.CommunicateFields(dom, Comm::B | Comm::B0); + FieldBoundaries(dom, BC::B); + + /** + * em0::D <- (em0::D) <- curl aux::H + * + * Now: em0::D at 1/2 + */ + Ampere(dom, gr_ampere::aux, ONE); + /** + * em0::D, em::D <- boundary conditions + */ + m_metadomain.CommunicateFields(dom, Comm::D | Comm::D0); + FieldBoundaries(dom, BC::D); + + /** + * aux::H <- alpha * em0::B - beta x em0::D + * + * Now: aux::H at 1/2 + */ + ComputeAuxH(dom, gr_getH::D0_B0); + /** + * aux::H <- boundary conditions + */ + // ?? aux field boundaries ?? + + /** + * em0::D <- (em::D) <- curl aux::H + * + * Now: em0::D at 1 + * em::D at 0 + */ + Ampere(dom, gr_ampere::main, ONE); + /** + * em0::D, em::D <- boundary conditions + */ + m_metadomain.CommunicateFields(dom, Comm::D | Comm::D0); + FieldBoundaries(dom, BC::D); + + /** + * em::D <-> em0::D + * em::B <-> em0::B + * em::J <-> em0::J + */ + SwapFields(dom); + /** + * Finally: em0::B at -1/2 + * em0::D at 0 + * em::B at 1/2 + * em::D at 1 + * + * cur0::J -- + * cur::J -- + * + * aux::E -- + * aux::H -- + * + * x_prtl at 1 + * u_prtl at 1/2 + */ + } } @@ -318,11 +411,10 @@ namespace ntt { /** * @brief Swaps em and em0 fields, cur and cur0 currents. */ - // void SwapFields() { - // auto& mblock = this->meshblock; - // std::swap(mblock.em, mblock.em0); - // std::swap(mblock.cur, mblock.cur0); - // } + void SwapFields(domain_t& domain) { + std::swap(domain.fields.em, domain.fields.em0); + std::swap(domain.fields.cur, domain.fields.cur0); + } /** * @brief Copies em fields into em0 From f3496b9f66ded703bd80003e700a8fda7b3984f0 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Fri, 27 Sep 2024 13:26:17 -0400 Subject: [PATCH 277/773] engines/grpis: minor update to first aux step for consistency --- src/engines/grpic.hpp | 51 +++++++++++++++++++++++++------------------ 1 file changed, 30 insertions(+), 21 deletions(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index 0e89ff400..a5f64a1e3 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -119,8 +119,7 @@ namespace ntt { /** * em0::D, em::D, em0::B, em::B <- boundary conditions */ - m_metadomain.CommunicateFields(dom, - Comm::B | Comm::B0 | Comm::D | Comm::D0); + m_metadomain.CommunicateFields(dom, Comm::B | Comm::B0 | Comm::D | Comm::D0); FieldBoundaries(dom, BC::B | BC::D); /** @@ -137,7 +136,7 @@ namespace ntt { * * Now: aux::E & aux::H at -1/2 */ - ComputeAuxE(dom, gr_getE::D0_B); + ComputeAuxE(dom, gr_getE::D_B0); ComputeAuxH(dom, gr_getH::D_B0); /** @@ -258,6 +257,20 @@ namespace ntt { */ } + + if (fieldsolver_enabled) { + + } + + { + + + } + + if (fieldsolver_enabled) { + + } + } /* algorithm substeps --------------------------------------------------- */ @@ -467,19 +480,17 @@ namespace ntt { auto range_with_axis_BCs(const domain_t& domain) -> range_t { auto range = domain.mesh.rangeActiveCells(); - if constexpr (M::CoordType != Coord::Cart) { - /** - * @brief taking one extra cell in the x1 and x2 directions if AXIS BCs - */ - if constexpr (M::Dim == Dim::_2D) { - if (domain.mesh.flds_bc_in({ 0, +1 }) == FldsBC::AXIS) { - range = CreateRangePolicy( - { domain.mesh.i_min(in::x1) - 1, domain.mesh.i_min(in::x2) }, - { domain.mesh.i_max(in::x1), domain.mesh.i_max(in::x2) + 1 }); - } - } else if constexpr (M::Dim == Dim::_3D) { - raise::Error("Invalid dimension", HERE); + /** + * @brief taking one extra cell in the x1 and x2 directions if AXIS BCs + */ + if constexpr (M::Dim == Dim::_2D) { + if (domain.mesh.flds_bc_in({ 0, +1 }) == FldsBC::AXIS) { + range = CreateRangePolicy( + { domain.mesh.i_min(in::x1) - 1, domain.mesh.i_min(in::x2) }, + { domain.mesh.i_max(in::x1), domain.mesh.i_max(in::x2) + 1 }); } + } else if constexpr (M::Dim == Dim::_3D) { + raise::Error("Invalid dimension", HERE); } return range; } @@ -525,17 +536,15 @@ namespace ntt { "algorithms.timestep.correction") * dt; auto range = CreateRangePolicy( - { domain.mesh.i_min(in::x1), domain.mesh.i_min(in::x2) + 1 }, - { domain.mesh.i_max(in::x1), domain.mesh.i_max(in::x2) }); - auto range_pole = CreateRangePolicy({ domain.mesh.i_min(in::x1) }, - { domain.mesh.i_max(in::x1) }); + { domain.mesh.i_min(in::x1), domain.mesh.i_min(in::x2)}, + { domain.mesh.i_max(in::x1), domain.mesh.i_max(in::x2) + 1}); const auto ni2 = domain.mesh.n_active(in::x2); if (g == gr_ampere::aux) { // First push, updates D0 with J. Kokkos::parallel_for("Ampere-1", range, - kernel::gr::Ampere_kernel(domain.fields.em, // has to be zeros + kernel::gr::Ampere_kernel(domain.fields.em, domain.fields.em0, domain.fields.aux, domain.mesh.metric, @@ -557,7 +566,7 @@ namespace ntt { // Second push, updates D with J0 and assigns it to D. Kokkos::parallel_for("Ampere-3", range, - kernel::gr::Ampere_kernel(domain.fields.em, //has to be zeros + kernel::gr::Ampere_kernel(domain.fields.em, domain.fields.em, domain.fields.aux, domain.mesh.metric, From 2eaba26ac55c28eaa075e15c3138ed6e952f14d7 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Fri, 27 Sep 2024 13:28:35 -0400 Subject: [PATCH 278/773] engines/grpic: fixed ComputeAuxE function --- src/engines/grpic.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index a5f64a1e3..5a41c4724 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -443,14 +443,14 @@ namespace ntt { range, kernel::gr::ComputeAuxE_kernel(domain.fields.em0, domain.fields.em, - domain.fields.em, + domain.fields.aux, domain.mesh.metric)); } else if (g == gr_getE::D_B0) { Kokkos::parallel_for("ComputeAuxE", range, kernel::gr::ComputeAuxE_kernel(domain.fields.em, domain.fields.em0, - domain.fields.em, + domain.fields.aux, domain.mesh.metric)); } else { raise::Error("Wrong option for `g`", HERE); From 7adc70906f1ffadb0a616710514e7a2dd1b78824 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Fri, 27 Sep 2024 13:30:28 -0400 Subject: [PATCH 279/773] engines/grpic: fixed Faraday function --- src/engines/grpic.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index 5a41c4724..ff1187353 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -516,7 +516,7 @@ namespace ntt { Kokkos::parallel_for( "Faraday", domain.mesh.rangeActiveCells(), - kernel::gr::Faraday_kernel(domain.fields.em0, + kernel::gr::Faraday_kernel(domain.fields.em, domain.fields.em0, domain.fields.aux, domain.mesh.metric, From 8c4451d021ef98a6b4b833a8fa5eeb1df8e61cc1 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Fri, 27 Sep 2024 13:32:17 -0400 Subject: [PATCH 280/773] engines/grpis: fixed Ampere function --- src/engines/grpic.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index ff1187353..51ff5fbfe 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -544,7 +544,7 @@ namespace ntt { // First push, updates D0 with J. Kokkos::parallel_for("Ampere-1", range, - kernel::gr::Ampere_kernel(domain.fields.em, + kernel::gr::Ampere_kernel(domain.fields.em0, domain.fields.em0, domain.fields.aux, domain.mesh.metric, From b4619ded7a40f630e3b626a11d47b43423fba339 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Fri, 27 Sep 2024 13:45:25 -0400 Subject: [PATCH 281/773] engines/grpic: added a class for field_bc to accomodate passing em, em0, aux to BC kernels --- src/engines/grpic.hpp | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index 51ff5fbfe..02ad93959 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -62,6 +62,11 @@ namespace ntt { aux, main }; + enum class gr_bc { + main, + main0, + aux + }; template class GRPICEngine : public Engine { @@ -274,17 +279,17 @@ namespace ntt { } /* algorithm substeps --------------------------------------------------- */ - void FieldBoundaries(domain_t& domain, BCTags tags) { + void FieldBoundaries(domain_t& domain, BCTags tags, const gr_bc& g) { for (auto& direction : dir::Directions::orth) { if (m_metadomain.mesh().flds_bc_in(direction) == FldsBC::ABSORB) { - AbsorbFieldsIn(direction, domain, tags); + AbsorbFieldsIn(direction, domain, tags, g); } else if (m_metadomain.mesh().flds_bc_in(direction) == FldsBC::AXIS) { if (domain.mesh.flds_bc_in(direction) == FldsBC::AXIS) { - AxisFieldsIn(direction, domain, tags); + AxisFieldsIn(direction, domain, tags, g); } } else if (m_metadomain.mesh().flds_bc_in(direction) == FldsBC::CUSTOM) { if (domain.mesh.flds_bc_in(direction) == FldsBC::CUSTOM) { - CustomFieldsIn(direction, domain, tags); + CustomFieldsIn(direction, domain, tags, g); } } else if (m_metadomain.mesh().flds_bc_in(direction) == FldsBC::HORIZON) { raise::Error("HORIZON BCs only applicable for GR", HERE); @@ -294,7 +299,8 @@ namespace ntt { void AbsorbFieldsIn(dir::direction_t direction, domain_t& domain, - BCTags tags) { + BCTags tags + const gr_getE& g) { /** * absorbing boundaries */ @@ -378,7 +384,8 @@ namespace ntt { void AxisFieldsIn(dir::direction_t direction, domain_t& domain, - BCTags tags) { + BCTags tags + const gr_getE& g) { /** * axis boundaries */ @@ -405,7 +412,8 @@ namespace ntt { void CustomFieldsIn(dir::direction_t direction, domain_t& domain, - BCTags tags) { + BCTags tags + const gr_getE& g) { (void)direction; (void)domain; (void)tags; From 01c9d0dcafe898f836ec275d6029a402dc893a68 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Fri, 27 Sep 2024 14:06:50 -0400 Subject: [PATCH 282/773] engines/grpic: cut out 3d from absorb BCs --- src/engines/grpic.hpp | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index 02ad93959..ff43eba71 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -354,7 +354,7 @@ namespace ntt { ds, tags)); } else if (dim == in::x2) { - if constexpr (M::Dim == Dim::_2D or M::Dim == Dim::_3D) { + if constexpr (M::Dim == Dim::_2D) { Kokkos::parallel_for( "AbsorbFields", CreateRangePolicy(range_min, range_max), @@ -366,19 +366,8 @@ namespace ntt { } else { raise::Error("Invalid dimension", HERE); } - } else if (dim == in::x3) { - if constexpr (M::Dim == Dim::_3D) { - Kokkos::parallel_for( - "AbsorbFields", - CreateRangePolicy(range_min, range_max), - kernel::AbsorbBoundaries_kernel(domain.fields.em, - domain.mesh.metric, - xg_edge, - ds, - tags)); - } else { + } else { raise::Error("Invalid dimension", HERE); - } } } From d1fce86c9a678de4005b1e6deb23bbdf5e00a54a Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Fri, 27 Sep 2024 14:10:10 -0400 Subject: [PATCH 283/773] minot: fix syntax --- src/engines/grpic.hpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index ff43eba71..d53969b54 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -299,8 +299,8 @@ namespace ntt { void AbsorbFieldsIn(dir::direction_t direction, domain_t& domain, - BCTags tags - const gr_getE& g) { + BCTags tags, + const gr_bc& g) { /** * absorbing boundaries */ @@ -373,8 +373,8 @@ namespace ntt { void AxisFieldsIn(dir::direction_t direction, domain_t& domain, - BCTags tags - const gr_getE& g) { + BCTags tags, + const gr_bc& g) { /** * axis boundaries */ @@ -401,8 +401,8 @@ namespace ntt { void CustomFieldsIn(dir::direction_t direction, domain_t& domain, - BCTags tags - const gr_getE& g) { + BCTags tags, + const gr_bc& g) { (void)direction; (void)domain; (void)tags; From 8d410ad6f02477995b772f6f0f96e79b90f22fc0 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Fri, 27 Sep 2024 14:10:44 -0400 Subject: [PATCH 284/773] minor: cut out options from gr_bc class --- src/engines/grpic.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index d53969b54..82e06cc59 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -64,7 +64,6 @@ namespace ntt { }; enum class gr_bc { main, - main0, aux }; From 38931ab08d7b649aabf8bc6de410f8661f51825c Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Fri, 27 Sep 2024 14:12:48 -0400 Subject: [PATCH 285/773] minor: cut out gr_bc from most bc functions since only horizon bc needs aux fields; em and em0 are always set together --- src/engines/grpic.hpp | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index 82e06cc59..0538d2936 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -281,14 +281,14 @@ namespace ntt { void FieldBoundaries(domain_t& domain, BCTags tags, const gr_bc& g) { for (auto& direction : dir::Directions::orth) { if (m_metadomain.mesh().flds_bc_in(direction) == FldsBC::ABSORB) { - AbsorbFieldsIn(direction, domain, tags, g); + AbsorbFieldsIn(direction, domain, tags); } else if (m_metadomain.mesh().flds_bc_in(direction) == FldsBC::AXIS) { if (domain.mesh.flds_bc_in(direction) == FldsBC::AXIS) { - AxisFieldsIn(direction, domain, tags, g); + AxisFieldsIn(direction, domain, tags); } } else if (m_metadomain.mesh().flds_bc_in(direction) == FldsBC::CUSTOM) { if (domain.mesh.flds_bc_in(direction) == FldsBC::CUSTOM) { - CustomFieldsIn(direction, domain, tags, g); + CustomFieldsIn(direction, domain, tags); } } else if (m_metadomain.mesh().flds_bc_in(direction) == FldsBC::HORIZON) { raise::Error("HORIZON BCs only applicable for GR", HERE); @@ -298,8 +298,7 @@ namespace ntt { void AbsorbFieldsIn(dir::direction_t direction, domain_t& domain, - BCTags tags, - const gr_bc& g) { + BCTags tags) { /** * absorbing boundaries */ @@ -372,8 +371,7 @@ namespace ntt { void AxisFieldsIn(dir::direction_t direction, domain_t& domain, - BCTags tags, - const gr_bc& g) { + BCTags tags) { /** * axis boundaries */ From de10607153d62a3897a8c08ee81e550e0cdc97a5 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Fri, 27 Sep 2024 14:15:03 -0400 Subject: [PATCH 286/773] engines/grpic: added gr_bc into step=0 functions --- src/engines/grpic.hpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index 0538d2936..4a48e0b33 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -124,7 +124,7 @@ namespace ntt { * em0::D, em::D, em0::B, em::B <- boundary conditions */ m_metadomain.CommunicateFields(dom, Comm::B | Comm::B0 | Comm::D | Comm::D0); - FieldBoundaries(dom, BC::B | BC::D); + FieldBoundaries(dom, BC::B | BC::D, gr_bc::main); /** * em0::B <- em::B @@ -159,7 +159,7 @@ namespace ntt { * em0::B, em::B <- boundary conditions */ m_metadomain.CommunicateFields(dom, Comm::B | Comm::B0); - FieldBoundaries(dom, BC::B); + FieldBoundaries(dom, BC::B, gr_bc::main); /** * em::D <- (em0::D) <- curl aux::H @@ -172,7 +172,7 @@ namespace ntt { * em0::D, em::D <- boundary conditions */ m_metadomain.CommunicateFields(dom, Comm::D | Comm::D0); - FieldBoundaries(dom, BC::D); + FieldBoundaries(dom, BC::D, gr_bc::main); /** * aux::E <- alpha * em::D + beta x em0::B @@ -200,7 +200,7 @@ namespace ntt { * em0::B, em::B <- boundary conditions */ m_metadomain.CommunicateFields(dom, Comm::B | Comm::B0); - FieldBoundaries(dom, BC::B); + FieldBoundaries(dom, BC::B, gr_bc::main); /** * em0::D <- (em0::D) <- curl aux::H @@ -212,7 +212,7 @@ namespace ntt { * em0::D, em::D <- boundary conditions */ m_metadomain.CommunicateFields(dom, Comm::D | Comm::D0); - FieldBoundaries(dom, BC::D); + FieldBoundaries(dom, BC::D, gr_bc::main); /** * aux::H <- alpha * em0::B - beta x em0::D @@ -236,7 +236,7 @@ namespace ntt { * em0::D, em::D <- boundary conditions */ m_metadomain.CommunicateFields(dom, Comm::D | Comm::D0); - FieldBoundaries(dom, BC::D); + FieldBoundaries(dom, BC::D, gr_bc::main); /** * em::D <-> em0::D From c4649f405ce38957d438a1bc54f6aebaf72ce7f3 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Fri, 27 Sep 2024 14:22:49 -0400 Subject: [PATCH 287/773] engines/grpic: added BC for em0 --- src/engines/grpic.hpp | 56 +++++++++++++++++++++++++++++++++---------- 1 file changed, 44 insertions(+), 12 deletions(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index 4a48e0b33..68ba6edf7 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -279,21 +279,29 @@ namespace ntt { /* algorithm substeps --------------------------------------------------- */ void FieldBoundaries(domain_t& domain, BCTags tags, const gr_bc& g) { - for (auto& direction : dir::Directions::orth) { - if (m_metadomain.mesh().flds_bc_in(direction) == FldsBC::ABSORB) { - AbsorbFieldsIn(direction, domain, tags); - } else if (m_metadomain.mesh().flds_bc_in(direction) == FldsBC::AXIS) { - if (domain.mesh.flds_bc_in(direction) == FldsBC::AXIS) { - AxisFieldsIn(direction, domain, tags); + if (g == gr_bc::main) { + for (auto& direction : dir::Directions::orth) { + if (m_metadomain.mesh().flds_bc_in(direction) == FldsBC::ABSORB) { + AbsorbFieldsIn(direction, domain, tags); + } else if (m_metadomain.mesh().flds_bc_in(direction) == FldsBC::AXIS) { + if (domain.mesh.flds_bc_in(direction) == FldsBC::AXIS) { + AxisFieldsIn(direction, domain, tags); + } + } else if (m_metadomain.mesh().flds_bc_in(direction) == FldsBC::CUSTOM) { + if (domain.mesh.flds_bc_in(direction) == FldsBC::CUSTOM) { + CustomFieldsIn(direction, domain, tags, g); + } + } else if (m_metadomain.mesh().flds_bc_in(direction) == FldsBC::HORIZON) { + raise::Error("HORIZON BCs only applicable for GR", HERE); } - } else if (m_metadomain.mesh().flds_bc_in(direction) == FldsBC::CUSTOM) { - if (domain.mesh.flds_bc_in(direction) == FldsBC::CUSTOM) { - CustomFieldsIn(direction, domain, tags); + } // loop over directions + } else if (g == gr_bc::aux) { + for (auto& direction : dir::Directions::orth) { + if (m_metadomain.mesh().flds_bc_in(direction) == FldsBC::HORIZON) { + raise::Error("HORIZON BCs only applicable for GR", HERE); } - } else if (m_metadomain.mesh().flds_bc_in(direction) == FldsBC::HORIZON) { - raise::Error("HORIZON BCs only applicable for GR", HERE); } - } // loop over directions + } } void AbsorbFieldsIn(dir::direction_t direction, @@ -351,6 +359,14 @@ namespace ntt { xg_edge, ds, tags)); + Kokkos::parallel_for( + "AbsorbFields", + CreateRangePolicy(range_min, range_max), + kernel::AbsorbBoundaries_kernel(domain.fields.em0, + domain.mesh.metric, + xg_edge, + ds, + tags)); } else if (dim == in::x2) { if constexpr (M::Dim == Dim::_2D) { Kokkos::parallel_for( @@ -361,6 +377,14 @@ namespace ntt { xg_edge, ds, tags)); + Kokkos::parallel_for( + "AbsorbFields", + CreateRangePolicy(range_min, range_max), + kernel::AbsorbBoundaries_kernel(domain.fields.em0, + domain.mesh.metric, + xg_edge, + ds, + tags)); } else { raise::Error("Invalid dimension", HERE); } @@ -388,11 +412,19 @@ namespace ntt { "AxisBCFields", domain.mesh.n_all(in::x1), kernel::AxisBoundaries_kernel(domain.fields.em, i2_min, tags)); + Kokkos::parallel_for( + "AxisBCFields", + domain.mesh.n_all(in::x1), + kernel::AxisBoundaries_kernel(domain.fields.em0, i2_min, tags)); } else { Kokkos::parallel_for( "AxisBCFields", domain.mesh.n_all(in::x1), kernel::AxisBoundaries_kernel(domain.fields.em, i2_max, tags)); + Kokkos::parallel_for( + "AxisBCFields", + domain.mesh.n_all(in::x1), + kernel::AxisBoundaries_kernel(domain.fields.em0, i2_max, tags)); } } From bb7afaf2e59e457a1f38058a45f71e11fb851e8e Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Fri, 27 Sep 2024 16:07:17 -0400 Subject: [PATCH 288/773] added a kernel for OpenBoundaries --- src/kernels/fields_bcs.hpp | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/src/kernels/fields_bcs.hpp b/src/kernels/fields_bcs.hpp index 363ff3ad2..68514222b 100644 --- a/src/kernels/fields_bcs.hpp +++ b/src/kernels/fields_bcs.hpp @@ -846,6 +846,40 @@ namespace kernel::bc { } }; + template + struct OpenBoundaries_kernel { + ndfield_t Fld; + const std::size_t i1_min; + const bool setE, setB; + + OpenBoundaries_kernel(ndfield_t Fld, BCTags tags) + : Fld { Fld } + , i1_min { i1_min } + , setE { tags & BC::Ex1 or tags & BC::Ex2 or tags & BC::Ex3 } + , setB { tags & BC::Bx1 or tags & BC::Bx2 or tags & BC::Bx3 } {} + + Inline void operator()(index_t i2) const { + if constexpr (M::Dim == Dim::_2D) { + if (setE) { + Fld(i1_min - 1, i2, em::ex1) = Fld(i1_min, i2, em::ex1); + Fld(i1_min, i2, em::ex2) = Fld(i1_min + 1, i2, em::ex2); + Fld(i1_min - 1, i2, em::ex2) = Fld(i1_min, i2, em::ex2); + Fld(i1_min, i2, em::ex3) = Fld(i1_min + 1, i2, em::ex3); + Fld(i1_min - 1, i2, em::ex3) = Fld(i1_min, i2, em::ex3); + } else if (setB) { + Fld(i1_min, i2, em::bx1) = Fld(i1_min + 1, i2, em::bx1); + Fld(i1_min - 1, i2, em::bx1) = Fld(i1_min, i2, em::bx1); + Fld(i1_min - 1, i2, em::bx2) = Fld(i1_min, i2, em::bx2); + Fld(i1_min - 1, i2, em::bx3) = Fld(i1_min, i2, em::bx3); + } + } else { + raise::KernelError( + HERE, + "AbsorbFields_kernel: 2D implementation called for D != 2"); + } + } + }; + } // namespace kernel::bc #endif // KERNELS_FIELDS_BCS_HPP From 2a73574b5dd4220a9772f45f4826514881a75dc8 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Mon, 30 Sep 2024 15:48:22 -0400 Subject: [PATCH 289/773] engines/grpic: implemented function to call for OpenBoundaries_kernel kernels/fields_bcs: fixed parameter passing in OpenBoundaries_kernel --- src/engines/grpic.hpp | 35 +++++++++++++++++++++++++++++++++-- src/kernels/fields_bcs.hpp | 2 +- 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index 68ba6edf7..5f4a5e7a5 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -292,13 +292,13 @@ namespace ntt { CustomFieldsIn(direction, domain, tags, g); } } else if (m_metadomain.mesh().flds_bc_in(direction) == FldsBC::HORIZON) { - raise::Error("HORIZON BCs only applicable for GR", HERE); + OpenFieldsIn(direction, domain, tags); } } // loop over directions } else if (g == gr_bc::aux) { for (auto& direction : dir::Directions::orth) { if (m_metadomain.mesh().flds_bc_in(direction) == FldsBC::HORIZON) { - raise::Error("HORIZON BCs only applicable for GR", HERE); + OpenFieldsIn(direction, domain, tags); } } } @@ -393,6 +393,37 @@ namespace ntt { } } + void OpenFieldsIn(dir::direction_t direction, + domain_t& domain, + BCTags tags, + const gr_bc& g) { + /** + * open boundaries + */ + raise::ErrorIf(M::CoordType == Coord::Cart, + "Invalid coordinate type for axis BCs", + HERE); + raise::ErrorIf(direction.get_dim() != in::x1, + "Invalid axis direction, should be x2", + HERE); + const auto i1_min = domain.mesh.i_min(in::x1); + if (g == gr_bc::main) { + Kokkos::parallel_for( + "OpenBCFields", + domain.mesh.n_all(in::x1), + kernel::OpenBoundaries_kernel(domain.fields.em, i1_min, tags)); + Kokkos::parallel_for( + "OpenBCFields", + domain.mesh.n_all(in::x1), + kernel::AxisBoundaries_kernel(domain.fields.em0, i1_min, tags)); + } else if (g == gr_bc::aux) { + Kokkos::parallel_for( + "OpenBCFields", + domain.mesh.n_all(in::x1), + kernel::OpenBoundaries_kernel(domain.fields.aux, i1_min, tags)); + } + } + void AxisFieldsIn(dir::direction_t direction, domain_t& domain, BCTags tags) { diff --git a/src/kernels/fields_bcs.hpp b/src/kernels/fields_bcs.hpp index 68514222b..7c574f058 100644 --- a/src/kernels/fields_bcs.hpp +++ b/src/kernels/fields_bcs.hpp @@ -852,7 +852,7 @@ namespace kernel::bc { const std::size_t i1_min; const bool setE, setB; - OpenBoundaries_kernel(ndfield_t Fld, BCTags tags) + OpenBoundaries_kernel(ndfield_t Fld, std::size_t i1_min, BCTags tags) : Fld { Fld } , i1_min { i1_min } , setE { tags & BC::Ex1 or tags & BC::Ex2 or tags & BC::Ex3 } From 37a34eacdcc0397bf5182271c50f1d32bd6afbec Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Mon, 30 Sep 2024 15:54:30 -0400 Subject: [PATCH 290/773] enginesgrpic: added aux field boundaries calls to initial step --- src/engines/grpic.hpp | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index 5f4a5e7a5..2ceca46ee 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -146,7 +146,7 @@ namespace ntt { /** * aux::E, aux::H <- boundary conditions */ - // ?? aux field boundaries ?? + FieldBoundaries(dom, BC::B | BC::D, gr_bc::aux); /** * em0::B <- (em0::B) <- -curl aux::E @@ -186,7 +186,7 @@ namespace ntt { /** * aux::E, aux::H <- boundary conditions */ - // ?? aux field boundaries ?? + FieldBoundaries(dom, BC::B | BC::D, gr_bc::aux); // !ADD: GR -- particles? @@ -223,7 +223,7 @@ namespace ntt { /** * aux::H <- boundary conditions */ - // ?? aux field boundaries ?? + FieldBoundaries(dom, BC::B, gr_bc::aux); /** * em0::D <- (em::D) <- curl aux::H @@ -259,7 +259,6 @@ namespace ntt { * x_prtl at 1 * u_prtl at 1/2 */ - } if (fieldsolver_enabled) { @@ -292,13 +291,13 @@ namespace ntt { CustomFieldsIn(direction, domain, tags, g); } } else if (m_metadomain.mesh().flds_bc_in(direction) == FldsBC::HORIZON) { - OpenFieldsIn(direction, domain, tags); + OpenFieldsIn(direction, domain, tags, g); } } // loop over directions } else if (g == gr_bc::aux) { for (auto& direction : dir::Directions::orth) { if (m_metadomain.mesh().flds_bc_in(direction) == FldsBC::HORIZON) { - OpenFieldsIn(direction, domain, tags); + OpenFieldsIn(direction, domain, tags, g); } } } @@ -410,16 +409,16 @@ namespace ntt { if (g == gr_bc::main) { Kokkos::parallel_for( "OpenBCFields", - domain.mesh.n_all(in::x1), + domain.mesh.n_all(in::x2), kernel::OpenBoundaries_kernel(domain.fields.em, i1_min, tags)); Kokkos::parallel_for( "OpenBCFields", - domain.mesh.n_all(in::x1), - kernel::AxisBoundaries_kernel(domain.fields.em0, i1_min, tags)); + domain.mesh.n_all(in::x2), + kernel::OpenBoundaries_kernel(domain.fields.em0, i1_min, tags)); } else if (g == gr_bc::aux) { Kokkos::parallel_for( "OpenBCFields", - domain.mesh.n_all(in::x1), + domain.mesh.n_all(in::x2), kernel::OpenBoundaries_kernel(domain.fields.aux, i1_min, tags)); } } From 454b590ab45c1b2f3c9e40af354bdada3f2a23fc Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Mon, 30 Sep 2024 16:16:18 -0400 Subject: [PATCH 291/773] added TimeAverageDB() and kernel for it in kernels/aux --- src/engines/grpic.hpp | 34 ++++++++++++++++++++++++++++++- src/kernels/aux_fields_gr.hpp | 38 +++++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+), 1 deletion(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index 2ceca46ee..8097e1fb1 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -261,8 +261,31 @@ namespace ntt { */ } - if (fieldsolver_enabled) { + /** + * Initially: em0::B at n-3/2 + * em0::D at n-1 + * em::B at n-1/2 + * em::D at n + * + * cur0::J -- + * cur::J at n-1/2 + * + * aux::E -- + * aux::H -- + * + * x_prtl at n + * u_prtl at n-1/2 + */ + if (fieldsolver_enabled) { + /** + * em0::D <- (em0::D + em::D) / 2 + * em0::B <- (em0::B + em::B) / 2 + * + * Now: em0::D at n-1/2 + * em0::B at n-1 + */ + TimeAverageDB(dom); } { @@ -634,6 +657,15 @@ namespace ntt { } } + + void TimeAverageDB(domain_t& domain) { + auto range = range_with_axis_BCs(domain); + Kokkos::parallel_for("TimeAverageDB", + range, + kernel::gr::TimeAverageDB_kernel(domain.fields.em, + domain.fields.em0, + domain.mesh.metric)); + } }; } // namespace ntt diff --git a/src/kernels/aux_fields_gr.hpp b/src/kernels/aux_fields_gr.hpp index 5744c3092..4f87ba1f2 100644 --- a/src/kernels/aux_fields_gr.hpp +++ b/src/kernels/aux_fields_gr.hpp @@ -230,6 +230,44 @@ namespace kernel::gr { } } }; + + /** + * @brief Kernel for computing time average of B and D + * @tparam M Metric + */ + template + class TimeAverageDB_kernel { + static_assert(M::is_metric, "M must be a metric class"); + static constexpr auto D = M::Dim; + + const ndfield_t BDf; + ndfield_t BDf0; + const M metric; + + public: + TimeAverageDB_kernel(const ndfield_t& BDf, + const ndfield_t& BDf0, + const M& metric) + : BDf { BDf } + , BDf0 { BDf0 } + , metric { metric } {} + + Inline void operator()(index_t i1, index_t i2) const { + if constexpr (D == Dim::_2D) { + BDf0(i1, i2, em::bx1) = HALF * (BDf0(i1, i2, em::bx1) + BDf(i1, i2, em::bx1)); + BDf0(i1, i2, em::bx2) = HALF * (BDf0(i1, i2, em::bx2) + BDf(i1, i2, em::bx2)); + BDf0(i1, i2, em::bx3) = HALF * (BDf0(i1, i2, em::bx3) + BDf(i1, i2, em::bx3)); + BDf0(i1, i2, em::ex1) = HALF * (BDf0(i1, i2, em::bx1) + BDf(i1, i2, em::ex1)); + BDf0(i1, i2, em::ex2) = HALF * (BDf0(i1, i2, em::bx2) + BDf(i1, i2, em::ex2)); + BDf0(i1, i2, em::ex3) = HALF * (BDf0(i1, i2, em::bx3) + BDf(i1, i2, em::ex3)); + } else { + raise::KernelError( + HERE, + "ComputeAuxH_kernel: 2D implementation called for D != 2"); + } + } + + }; } // namespace kernel::gr #endif // KERNELS_AUX_FIELDS_GR_HPP From fd5d1b4f6710858646d23e0dd58d97cc18014065 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Mon, 30 Sep 2024 16:26:17 -0400 Subject: [PATCH 292/773] engines/grpic: first half of the main step for field solver --- src/engines/grpic.hpp | 42 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index 8097e1fb1..db984049e 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -286,15 +286,53 @@ namespace ntt { * em0::B at n-1 */ TimeAverageDB(dom); + /** + * aux::E <- alpha * em0::D + beta x em::B + * + * Now: aux::E at n-1/2 + */ + ComputeAuxE(dom, gr_getE::D0_B); + /** + * aux::E <- boundary conditions + */ + FieldBoundaries(dom, BC::D, gr_bc::aux); + /** + * em0::B <- (em0::B) <- -curl aux::E + * + * Now: em0::B at n + */ + Faraday(dom, gr_faraday::aux, ONE); + + + /** + * em0::B, em::B <- boundary conditions + */ + FieldBoundaries(dom, BC::B, gr_bc::main); + m_metadomain.CommunicateFields(dom, Comm::B | Comm::B0); + + + /** + * aux::H <- alpha * em0::B - beta x em::D + * + * Now: aux::H at n + */ + ComputeAuxH(dom, gr_getH::D_B0); + /** + * aux::H <- boundary conditions + */ + FieldBoundaries(dom, BC::B, gr_bc::aux); } { - + /** + * particle pusher goes here + * + */ } if (fieldsolver_enabled) { - + } } From 5aba20a14f61c665423e9fa2eb9e68f84f74b59a Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Mon, 30 Sep 2024 16:36:45 -0400 Subject: [PATCH 293/773] added TimeAverageJ() and its kernel in kernels/aux --- src/engines/grpic.hpp | 11 ++++++++++- src/kernels/aux_fields_gr.hpp | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index db984049e..4043968ff 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -332,7 +332,7 @@ namespace ntt { } if (fieldsolver_enabled) { - + TimeAverageJ(dom); } } @@ -704,6 +704,15 @@ namespace ntt { domain.fields.em0, domain.mesh.metric)); } + + void TimeAverageJ(domain_t& domain) { + auto range = range_with_axis_BCs(domain); + Kokkos::parallel_for("TimeAverageJ", + range, + kernel::gr::TimeAverageJ_kernel(domain.fields.cur, + domain.fields.cur0, + domain.mesh.metric)); + } }; } // namespace ntt diff --git a/src/kernels/aux_fields_gr.hpp b/src/kernels/aux_fields_gr.hpp index 4f87ba1f2..b56a819f9 100644 --- a/src/kernels/aux_fields_gr.hpp +++ b/src/kernels/aux_fields_gr.hpp @@ -266,7 +266,40 @@ namespace kernel::gr { "ComputeAuxH_kernel: 2D implementation called for D != 2"); } } + }; + /** + * @brief Kernel for computing time average of J + * @tparam M Metric + */ + template + class TimeAverageJ_kernel { + static_assert(M::is_metric, "M must be a metric class"); + static constexpr auto D = M::Dim; + + const ndfield_t Jf; + ndfield_t Jf0; + const M metric; + + public: + TimeAverageJ_kernel(const ndfield_t& Jf, + const ndfield_t& Jf0, + const M& metric) + : Jf { Jf } + , Jf0 { Jf0 } + , metric { metric } {} + + Inline void operator()(index_t i1, index_t i2) const { + if constexpr (D == Dim::_2D) { + Jf0(i1, i2, cur::jx1) = HALF * (Jf0(i1, i2, cur::jx1) + Jf(i1, i2, cur::jx1)); + Jf0(i1, i2, cur::jx2) = HALF * (Jf0(i1, i2, cur::jx2) + Jf(i1, i2, cur::jx2)); + Jf0(i1, i2, cur::jx3) = HALF * (Jf0(i1, i2, cur::jx3) + Jf(i1, i2, cur::jx3)); + } else { + raise::KernelError( + HERE, + "ComputeAuxH_kernel: 2D implementation called for D != 2"); + } + } }; } // namespace kernel::gr From b5207e366085203951057a8c22fc322a3170f7a9 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Mon, 30 Sep 2024 16:50:56 -0400 Subject: [PATCH 294/773] engines/grpic: added all steps relevant to field solver --- src/engines/grpic.hpp | 109 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 108 insertions(+), 1 deletion(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index 4043968ff..1e4f873f9 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -332,9 +332,116 @@ namespace ntt { } if (fieldsolver_enabled) { + /** + * cur::J <- (cur0::J + cur::J) / 2 + * + * Now: cur::J at n + */ TimeAverageJ(dom); - } + + /** + * aux::Е <- alpha * em::D + beta x em0::B + * + * Now: aux::Е at n + */ + ComputeAuxE(dom, gr_getE::D_B0); + /** + * aux::Е <- boundary conditions + */ + FieldBoundaries(dom, BC::D, gr_bc::aux); + /** + * em0::B <- (em::B) <- -curl aux::E + * + * Now: em0::B at n+1/2 + * em::B at n-1/2 + */ + Faraday(dom, gr_faraday::main, ONE); + + /** + * em0::B, em::B <- boundary conditions + */ + m_metadomain.CommunicateFields(dom, Comm::B | Comm::B0); + FieldBoundaries(dom, BC::B, gr_bc::main); + + + /** + * em0::D <- (em0::D) <- curl aux::H + * + * Now: em0::D at n+1/2 + */ + Ampere(dom, gr_ampere::aux, ONE); + + + if (deposit_enabled) { + /** + * em0::D <- (em0::D) <- cur::J + * + * Now: em0::D at n+1/2 + */ + // AmpereCurrents(gr_ampere::aux); + } + + /** + * em0::D, em::D <- boundary conditions + */ + m_metadomain.CommunicateFields(dom, Comm::D | Comm::D0); + FieldBoundaries(dom, BC::D, gr_bc::main); + + /** + * aux::H <- alpha * em0::B - beta x em0::D + * + * Now: aux::H at n+1/2 + */ + ComputeAuxH(dom, gr_getH::D0_B0); + /** + * aux::H <- boundary conditions + */ + FieldBoundaries(dom, BC::B, gr_bc::aux); + /** + * em0::D <- (em::D) <- curl aux::H + * + * Now: em0::D at n+1 + * em::D at n + */ + Ampere(dom, gr_ampere::main, ONE); + if (deposit_enabled) { + /** + * em0::D <- (em0::D) <- cur0::J + * + * Now: em0::D at n+1 + */ + // AmpereCurrents(gr_ampere::main); + } + /** + * em::D <-> em0::D + * em::B <-> em0::B + * cur::J <-> cur0::J + */ + SwapFields(dom); + + + /** + * em0::D, em::D <- boundary conditions + */ + m_metadomain.CommunicateFields(dom, Comm::D | Comm::D0); + FieldBoundaries(dom, BC::D, gr_bc::main); + } + /** + * Finally: em0::B at n-1/2 + * em0::D at n + * em::B at n+1/2 + * em::D at n+1 + * + * cur0::J (at n) + * cur::J at n+1/2 + * + * aux::E (at n+1/2) + * aux::H (at n) + * + * x_prtl at n+1 + * u_prtl at n+1/2 + */ } /* algorithm substeps --------------------------------------------------- */ From 4d1d0b0b4b9bb882daa04559a720827dc42f8135 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Mon, 30 Sep 2024 17:09:21 -0400 Subject: [PATCH 295/773] engines/grpic: added function for Ampere currents --- src/engines/grpic.hpp | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index 1e4f873f9..c5a946b00 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -800,6 +800,40 @@ namespace ntt { } else { raise::Error("Wrong option for `g`", HERE); } + } + + void AmpereCurrents(domain_t& domain, const gr_ampere& g) { + logger::Checkpoint("Launching Ampere kernel for adding currents", HERE); + const auto q0 = m_params.template get("scales.q0"); + const auto n0 = m_params.template get("scales.n0"); + const auto B0 = m_params.template get("scales.B0"); + const auto coeff = -dt * q0 * n0 / B0; + auto range = range_with_axis_BCs(domain); + const auto ni2 = domain.mesh.n_active(in::x2); + + if (g == gr_ampere::aux) { + // Updates D0 with J. + Kokkos::parallel_for("Ampere-1", + range, + kernel::gr::CurrentsAmpere_kernel(domain.fields.em0, + domain.fields.cur, + domain.mesh.metric, + coeff, + ni2, + domain.mesh.flds_bc())); + } else if (g == gr_ampere::main) { + // Updates D0 with J0. + Kokkos::parallel_for("Ampere-2", + range, + kernel::gr::CurrentsAmpere_kernel(domain.fields.em0, + domain.fields.cur0, + domain.mesh.metric, + coeff, + ni2, + domain.mesh.flds_bc())); + } else { + raise::Error("Wrong option for `g`", HERE); + } } From 04201cee737f4f77dee85f9954a39deb3b40ecba Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Mon, 30 Sep 2024 17:14:21 -0400 Subject: [PATCH 296/773] see below -- added call from the time step --- src/engines/grpic.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index c5a946b00..30f9e35ad 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -378,7 +378,7 @@ namespace ntt { * * Now: em0::D at n+1/2 */ - // AmpereCurrents(gr_ampere::aux); + AmpereCurrents(dom, gr_ampere::aux); } /** @@ -411,7 +411,7 @@ namespace ntt { * * Now: em0::D at n+1 */ - // AmpereCurrents(gr_ampere::main); + AmpereCurrents(dom, gr_ampere::main); } /** * em::D <-> em0::D From a67362130655f140f6235e60b0ffcec9cb609e4c Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Tue, 1 Oct 2024 12:16:48 -0400 Subject: [PATCH 297/773] engines/grpic: started ParticlePush --- src/engines/grpic.hpp | 154 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 152 insertions(+), 2 deletions(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index 30f9e35ad..d8b38208e 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -325,10 +325,44 @@ namespace ntt { { /** - * particle pusher goes here - * + * x_prtl, u_prtl <- em::D, em0::B + * + * Now: x_prtl at n + 1, u_prtl at n + 1/2 */ + timers.start("ParticlePusher"); + ParticlePush(dom); + timers.stop("ParticlePusher"); + + /** + * cur0::J <- current deposition + * + * Now: cur0::J at n+1/2 + */ + if (deposit_enabled) { + timers.start("CurrentDeposit"); + Kokkos::deep_copy(dom.fields.cur, ZERO); + CurrentsDeposit(dom); + timers.stop("CurrentDeposit"); + + timers.start("Communications"); + m_metadomain.SynchronizeFields(dom, Comm::J); + m_metadomain.CommunicateFields(dom, Comm::J); + timers.stop("Communications"); + + // timers.start("FieldBoundaries"); + // CurrentsBoundaryConditions(); + // timers.stop("FieldBoundaries"); + + timers.start("CurrentFiltering"); + CurrentsFilter(dom); + timers.stop("CurrentFiltering"); + } + timers.start("Communications"); + if ((sort_interval > 0) and (step % sort_interval == 0)) { + m_metadomain.CommunicateParticles(dom, &timers); + } + timers.stop("Communications"); } if (fieldsolver_enabled) { @@ -854,6 +888,122 @@ namespace ntt { domain.fields.cur0, domain.mesh.metric)); } + + void CurrentsDeposit(domain_t& domain) { + auto scatter_cur = Kokkos::Experimental::create_scatter_view( + domain.fields.cur); + for (auto& species : domain.species) { + logger::Checkpoint( + fmt::format("Launching currents deposit kernel for %d [%s] : %lu %f", + species.index(), + species.label().c_str(), + species.npart(), + (double)species.charge()), + HERE); + if (species.npart() == 0 || cmp::AlmostZero(species.charge())) { + continue; + } + Kokkos::parallel_for("CurrentsDeposit", + species.rangeActiveParticles(), + kernel::DepositCurrents_kernel( + scatter_cur, + species.i1, + species.i2, + species.i3, + species.i1_prev, + species.i2_prev, + species.i3_prev, + species.dx1, + species.dx2, + species.dx3, + species.dx1_prev, + species.dx2_prev, + species.dx3_prev, + species.ux1, + species.ux2, + species.ux3, + species.phi, + species.weight, + species.tag, + domain.mesh.metric, + (real_t)(species.charge()), + dt)); + } + Kokkos::Experimental::contribute(domain.fields.cur, scatter_cur); + } + + void CurrentsFilter(domain_t& domain) { + logger::Checkpoint("Launching currents filtering kernels", HERE); + auto range = range_with_axis_BCs(domain); + const auto nfilter = m_params.template get( + "algorithms.current_filters"); + tuple_t size; + if constexpr (M::Dim == Dim::_1D || M::Dim == Dim::_2D || M::Dim == Dim::_3D) { + size[0] = domain.mesh.n_active(in::x1); + } + if constexpr (M::Dim == Dim::_2D || M::Dim == Dim::_3D) { + size[1] = domain.mesh.n_active(in::x2); + } + if constexpr (M::Dim == Dim::_3D) { + size[2] = domain.mesh.n_active(in::x3); + } + // !TODO: this needs to be done more efficiently + for (unsigned short i = 0; i < nfilter; ++i) { + Kokkos::deep_copy(domain.fields.buff, domain.fields.cur); + Kokkos::parallel_for("CurrentsFilter", + range, + kernel::DigitalFilter_kernel( + domain.fields.cur, + domain.fields.buff, + size, + domain.mesh.flds_bc())); + m_metadomain.CommunicateFields(domain, Comm::J); + } + } + + void ParticlePush(domain_t& domain) { + for (auto& species : domain.species) { + species.set_unsorted(); + logger::Checkpoint( + fmt::format("Launching particle pusher kernel for %d [%s] : %lu", + species.index(), + species.label().c_str(), + species.npart()), + HERE); + if (species.npart() == 0) { + continue; + } + const auto q_ovr_m = species.mass() > ZERO + ? species.charge() / species.mass() + : ZERO; + // coeff = q / m (dt / 2) omegaB0 + const auto coeff = q_ovr_m * HALF * dt * + m_params.template get("scales.omegaB0"); + // clang-format off + Kokkos::parallel_for( + "ParticlePusher", + species.rangeActiveParticles(), + kernel::gr::Pusher_kernel( + domain.fields.em, + domain.fields.em0, + species.i1, species.i2, species.i3, + species.i1_prev, species.i2_prev, species.i3_prev, + species.dx1, species.dx2, species.dx3, + species.dx1_prev, species.dx2_prev, species.dx3_prev, + species.ux1, species.ux2, species.ux3, + species.phi, species.tag, + domain.mesh.metric, + coeff, dt, + domain.mesh.n_active(in::x1), + domain.mesh.n_active(in::x2), + domain.mesh.n_active(in::x3), + m_params.template get("algorithms.gr.pusher_eps"), m_params.template get("algorithms.gr.pusher_niter"), + domain.mesh.prtl_bc() + )); + // clang-format on + } + } + }; } // namespace ntt From 76f4e81830570b6ceccc5a4bfdc430349e9a0fdd Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Tue, 1 Oct 2024 12:21:25 -0400 Subject: [PATCH 298/773] see below --- src/engines/grpic.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index d8b38208e..9b71977cd 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -330,7 +330,7 @@ namespace ntt { * Now: x_prtl at n + 1, u_prtl at n + 1/2 */ timers.start("ParticlePusher"); - ParticlePush(dom); + // ParticlePush(dom); timers.stop("ParticlePusher"); /** From 1d53dc9b13b52f13ffef9e25cd1d42f71115417d Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Tue, 1 Oct 2024 12:32:47 -0400 Subject: [PATCH 299/773] engines/grpic: added timers --- src/engines/grpic.hpp | 65 +++++++++++++++++++++++++++++++++++++------ 1 file changed, 56 insertions(+), 9 deletions(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index 9b71977cd..c6e7b657f 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -278,6 +278,7 @@ namespace ntt { */ if (fieldsolver_enabled) { + timers.start("FieldSolver"); /** * em0::D <- (em0::D + em::D) / 2 * em0::B <- (em0::B + em::B) / 2 @@ -292,35 +293,49 @@ namespace ntt { * Now: aux::E at n-1/2 */ ComputeAuxE(dom, gr_getE::D0_B); + timers.stop("FieldSolver"); + + timers.start("FieldBoundaries"); /** * aux::E <- boundary conditions */ FieldBoundaries(dom, BC::D, gr_bc::aux); + timers.stop("FieldBoundaries"); + + timers.start("FieldSolver"); /** * em0::B <- (em0::B) <- -curl aux::E * * Now: em0::B at n */ Faraday(dom, gr_faraday::aux, ONE); - + timers.stop("FieldSolver"); /** * em0::B, em::B <- boundary conditions */ + timers.start("FieldBoundaries"); FieldBoundaries(dom, BC::B, gr_bc::main); + timers.stop("FieldBoundaries"); + timers.start("Communications"); m_metadomain.CommunicateFields(dom, Comm::B | Comm::B0); + timers.stop("Communications"); - + timers.start("FieldSolver"); /** * aux::H <- alpha * em0::B - beta x em::D * * Now: aux::H at n */ ComputeAuxH(dom, gr_getH::D_B0); + timers.stop("FieldSolver"); + + timers.start("FieldBoundaries"); /** * aux::H <- boundary conditions */ FieldBoundaries(dom, BC::B, gr_bc::aux); + timers.stop("FieldBoundaries"); } { @@ -366,23 +381,29 @@ namespace ntt { } if (fieldsolver_enabled) { + timers.start("FieldSolver"); /** * cur::J <- (cur0::J + cur::J) / 2 * * Now: cur::J at n */ TimeAverageJ(dom); - /** * aux::Е <- alpha * em::D + beta x em0::B * * Now: aux::Е at n */ ComputeAuxE(dom, gr_getE::D_B0); + timers.stop("FieldSolver"); + + timers.start("FieldBoundaries"); /** * aux::Е <- boundary conditions */ FieldBoundaries(dom, BC::D, gr_bc::aux); + timers.stop("FieldBoundaries"); + + timers.start("FieldSolver"); /** * em0::B <- (em::B) <- -curl aux::E * @@ -390,48 +411,65 @@ namespace ntt { * em::B at n-1/2 */ Faraday(dom, gr_faraday::main, ONE); - + timers.stop("FieldSolver"); + /** * em0::B, em::B <- boundary conditions */ + timers.start("Communications"); m_metadomain.CommunicateFields(dom, Comm::B | Comm::B0); + timers.stop("Communications"); + timers.start("FieldBoundaries"); FieldBoundaries(dom, BC::B, gr_bc::main); + timers.stop("FieldBoundaries"); - + timers.start("FieldSolver"); /** * em0::D <- (em0::D) <- curl aux::H * * Now: em0::D at n+1/2 */ Ampere(dom, gr_ampere::aux, ONE); - + timers.stop("FieldSolver"); if (deposit_enabled) { + timers.start("FieldSolver"); /** * em0::D <- (em0::D) <- cur::J * * Now: em0::D at n+1/2 */ AmpereCurrents(dom, gr_ampere::aux); + timers.stop("FieldSolver"); } - + /** * em0::D, em::D <- boundary conditions */ + timers.start("Communications"); m_metadomain.CommunicateFields(dom, Comm::D | Comm::D0); + timers.stop("Communications"); + timers.start("FieldBoundaries"); FieldBoundaries(dom, BC::D, gr_bc::main); - + timers.stop("FieldBoundaries"); + timers.start("FieldSolver"); /** * aux::H <- alpha * em0::B - beta x em0::D * * Now: aux::H at n+1/2 */ ComputeAuxH(dom, gr_getH::D0_B0); + timers.stop("FieldSolver"); + + timers.start("FieldBoundaries"); /** * aux::H <- boundary conditions */ FieldBoundaries(dom, BC::B, gr_bc::aux); + timers.stop("FieldBoundaries"); + + timers.start("FieldSolver"); /** * em0::D <- (em::D) <- curl aux::H * @@ -439,27 +477,36 @@ namespace ntt { * em::D at n */ Ampere(dom, gr_ampere::main, ONE); + timers.stop("FieldSolver"); + if (deposit_enabled) { + timers.start("FieldSolver"); /** * em0::D <- (em0::D) <- cur0::J * * Now: em0::D at n+1 */ AmpereCurrents(dom, gr_ampere::main); + timers.stop("FieldSolver"); } + timers.start("FieldSolver"); /** * em::D <-> em0::D * em::B <-> em0::B * cur::J <-> cur0::J */ SwapFields(dom); - + timers.stop("FieldSolver"); /** * em0::D, em::D <- boundary conditions */ + timers.start("Communications"); m_metadomain.CommunicateFields(dom, Comm::D | Comm::D0); + timers.stop("Communications"); + timers.start("FieldBoundaries"); FieldBoundaries(dom, BC::D, gr_bc::main); + timers.stop("FieldBoundaries"); } /** * Finally: em0::B at n-1/2 From 77b162f697edb8fc9bfc0f176a027a1622be9824 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Tue, 1 Oct 2024 14:00:57 -0400 Subject: [PATCH 300/773] parameters: changed to requiring n=2 for GRPIC --- src/framework/parameters.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/framework/parameters.cpp b/src/framework/parameters.cpp index 4a9b3056a..f86b5042f 100644 --- a/src/framework/parameters.cpp +++ b/src/framework/parameters.cpp @@ -686,10 +686,10 @@ namespace ntt { prtl_bc_enum.push_back({ PrtlBC::PERIODIC, PrtlBC::PERIODIC }); } } else { - raise::ErrorIf(flds_bc[0].size() != 1, + raise::ErrorIf(flds_bc[0].size() != 2, "invalid `grid.boundaries.fields`", HERE); - raise::ErrorIf(prtl_bc[0].size() != 1, + raise::ErrorIf(prtl_bc[0].size() != 2, "invalid `grid.boundaries.particles`", HERE); flds_bc_enum.push_back( From 717672742db6d44645c9074d7c27149e815c7a32 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Tue, 1 Oct 2024 15:27:17 -0400 Subject: [PATCH 301/773] minor: fixed description for qkerr metric for h_tilde --- src/metrics/qkerr_schild.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/metrics/qkerr_schild.h b/src/metrics/qkerr_schild.h index d531b8b3b..85507c6e1 100644 --- a/src/metrics/qkerr_schild.h +++ b/src/metrics/qkerr_schild.h @@ -265,7 +265,7 @@ namespace metric { } /** - * sqrt(det(h_ij)) + * sqrt(det(h_ij)) divided by sin(theta). * @param x coordinate array in code units */ Inline auto sqrt_det_h_tilde(const coord_t& x) const -> real_t { From df2a47dc6b8e9c8a6194f7152f9a3e32751dc65f Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Tue, 1 Oct 2024 17:37:59 -0400 Subject: [PATCH 302/773] parameters: restored !=1 --- src/framework/parameters.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/framework/parameters.cpp b/src/framework/parameters.cpp index f86b5042f..4a9b3056a 100644 --- a/src/framework/parameters.cpp +++ b/src/framework/parameters.cpp @@ -686,10 +686,10 @@ namespace ntt { prtl_bc_enum.push_back({ PrtlBC::PERIODIC, PrtlBC::PERIODIC }); } } else { - raise::ErrorIf(flds_bc[0].size() != 2, + raise::ErrorIf(flds_bc[0].size() != 1, "invalid `grid.boundaries.fields`", HERE); - raise::ErrorIf(prtl_bc[0].size() != 2, + raise::ErrorIf(prtl_bc[0].size() != 1, "invalid `grid.boundaries.particles`", HERE); flds_bc_enum.push_back( From baafca9853357fdf6069ce98a7288ebb58e32194 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Wed, 2 Oct 2024 16:42:43 -0400 Subject: [PATCH 303/773] archetypes/field_setter: fixed wrong conversion of theta and call for d() [instead of b] in 3D grpic --- src/archetypes/field_setter.h | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/archetypes/field_setter.h b/src/archetypes/field_setter.h index 281c28df6..171e9f8a8 100644 --- a/src/archetypes/field_setter.h +++ b/src/archetypes/field_setter.h @@ -202,13 +202,13 @@ namespace arch { const real_t x1_0 { metric.template convert<1, Crd::Cd, Crd::Ph>(i1_) }; const real_t x1_H { metric.template convert<1, Crd::Cd, Crd::Ph>( i1_ + HALF) }; - const real_t x2_0 { metric.template convert<1, Crd::Cd, Crd::Ph>(i2_) }; - const real_t x2_H { metric.template convert<1, Crd::Cd, Crd::Ph>( + const real_t x2_0 { metric.template convert<2, Crd::Cd, Crd::Ph>(i2_) }; + const real_t x2_H { metric.template convert<2, Crd::Cd, Crd::Ph>( i2_ + HALF) }; { // bx1 - vec_t b_PU { finit.dx1({ x1_0, x2_H }), - finit.dx2({ x1_0, x2_H }), - finit.dx3({ x1_0, x2_H }) }; + vec_t b_PU { finit.bx1({ x1_0, x2_H }), + finit.bx2({ x1_0, x2_H }), + finit.bx3({ x1_0, x2_H }) }; vec_t b_U { ZERO }; metric.template transform({ i1_, i2_ + HALF }, b_PU, @@ -216,9 +216,9 @@ namespace arch { EM(i1, i2, em::bx1) = b_U[0]; } { // bx2 - vec_t b_PU { finit.dx1({ x1_H, x2_0 }), - finit.dx2({ x1_H, x2_0 }), - finit.dx3({ x1_H, x2_0 }) }; + vec_t b_PU { finit.bx1({ x1_H, x2_0 }), + finit.bx2({ x1_H, x2_0 }), + finit.bx3({ x1_H, x2_0 }) }; vec_t b_U { ZERO }; metric.template transform({ i1_ + HALF, i2_ }, b_PU, @@ -226,9 +226,9 @@ namespace arch { EM(i1, i2, em::bx2) = b_U[1]; } { // bx3 - vec_t b_PU { finit.dx1({ x1_H, x2_H }), - finit.dx2({ x1_H, x2_H }), - finit.dx3({ x1_H, x2_H }) }; + vec_t b_PU { finit.bx1({ x1_H, x2_H }), + finit.bx2({ x1_H, x2_H }), + finit.bx3({ x1_H, x2_H }) }; vec_t b_U { ZERO }; metric.template transform({ i1_ + HALF, i2_ + HALF }, b_PU, From c660f8a7cd4b1667cfe8251d547311a6ab91a4b0 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Wed, 2 Oct 2024 17:14:11 -0400 Subject: [PATCH 304/773] kernels/fields_bc: fixed if statement for open BC --- src/kernels/fields_bcs.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/kernels/fields_bcs.hpp b/src/kernels/fields_bcs.hpp index 7c574f058..50fc27dd5 100644 --- a/src/kernels/fields_bcs.hpp +++ b/src/kernels/fields_bcs.hpp @@ -866,7 +866,8 @@ namespace kernel::bc { Fld(i1_min - 1, i2, em::ex2) = Fld(i1_min, i2, em::ex2); Fld(i1_min, i2, em::ex3) = Fld(i1_min + 1, i2, em::ex3); Fld(i1_min - 1, i2, em::ex3) = Fld(i1_min, i2, em::ex3); - } else if (setB) { + } + if (setB) { Fld(i1_min, i2, em::bx1) = Fld(i1_min + 1, i2, em::bx1); Fld(i1_min - 1, i2, em::bx1) = Fld(i1_min, i2, em::bx1); Fld(i1_min - 1, i2, em::bx2) = Fld(i1_min, i2, em::bx2); From 896c7f7bfccfe181985ccc3b3540db4b1f473639 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Wed, 2 Oct 2024 17:46:55 -0400 Subject: [PATCH 305/773] kernels/fields_bc: added a separate kernel for aux fields --- src/kernels/fields_bcs.hpp | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/kernels/fields_bcs.hpp b/src/kernels/fields_bcs.hpp index 50fc27dd5..59cbbd76a 100644 --- a/src/kernels/fields_bcs.hpp +++ b/src/kernels/fields_bcs.hpp @@ -881,6 +881,38 @@ namespace kernel::bc { } }; + template + struct OpenBoundariesAux_kernel { + ndfield_t Fld; + const std::size_t i1_min; + const bool setE, setB; + + OpenBoundariesAux_kernel(ndfield_t Fld, std::size_t i1_min, BCTags tags) + : Fld { Fld } + , i1_min { i1_min } + , setE { tags & BC::Ex1 or tags & BC::Ex2 or tags & BC::Ex3 } + , setB { tags & BC::Bx1 or tags & BC::Bx2 or tags & BC::Bx3 } {} + + Inline void operator()(index_t i2) const { + if constexpr (M::Dim == Dim::_2D) { + if (setE) { + Fld(i1_min - 1, i2, em::ex1) = Fld(i1_min, i2, em::ex1); + Fld(i1_min - 1, i2, em::ex2) = Fld(i1_min, i2, em::ex2); + Fld(i1_min - 1, i2, em::ex3) = Fld(i1_min, i2, em::ex3); + } + if (setB) { + Fld(i1_min - 1, i2, em::bx1) = Fld(i1_min, i2, em::bx1); + Fld(i1_min - 1, i2, em::bx2) = Fld(i1_min, i2, em::bx2); + Fld(i1_min - 1, i2, em::bx3) = Fld(i1_min, i2, em::bx3); + } + } else { + raise::KernelError( + HERE, + "AbsorbFields_kernel: 2D implementation called for D != 2"); + } + } + }; + } // namespace kernel::bc #endif // KERNELS_FIELDS_BCS_HPP From cfa70037303f64f58a9be6b02f5e2fa3e0ca93ea Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Wed, 2 Oct 2024 17:47:57 -0400 Subject: [PATCH 306/773] see below --- src/engines/grpic.hpp | 30 ++++++------------------------ 1 file changed, 6 insertions(+), 24 deletions(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index c6e7b657f..97aea35f7 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -615,27 +615,6 @@ namespace ntt { xg_edge, ds, tags)); - } else if (dim == in::x2) { - if constexpr (M::Dim == Dim::_2D) { - Kokkos::parallel_for( - "AbsorbFields", - CreateRangePolicy(range_min, range_max), - kernel::AbsorbBoundaries_kernel(domain.fields.em, - domain.mesh.metric, - xg_edge, - ds, - tags)); - Kokkos::parallel_for( - "AbsorbFields", - CreateRangePolicy(range_min, range_max), - kernel::AbsorbBoundaries_kernel(domain.fields.em0, - domain.mesh.metric, - xg_edge, - ds, - tags)); - } else { - raise::Error("Invalid dimension", HERE); - } } else { raise::Error("Invalid dimension", HERE); } @@ -655,10 +634,13 @@ namespace ntt { "Invalid axis direction, should be x2", HERE); const auto i1_min = domain.mesh.i_min(in::x1); + auto range = CreateRangePolicy( + {domain.mesh.i_min(in::x2)}, + {domain.mesh.i_max(in::x2) + 1}); if (g == gr_bc::main) { Kokkos::parallel_for( "OpenBCFields", - domain.mesh.n_all(in::x2), + range, kernel::OpenBoundaries_kernel(domain.fields.em, i1_min, tags)); Kokkos::parallel_for( "OpenBCFields", @@ -667,8 +649,8 @@ namespace ntt { } else if (g == gr_bc::aux) { Kokkos::parallel_for( "OpenBCFields", - domain.mesh.n_all(in::x2), - kernel::OpenBoundaries_kernel(domain.fields.aux, i1_min, tags)); + range, + kernel::OpenBoundariesAux_kernel(domain.fields.aux, i1_min, tags)); } } From e2e91d20f1aa0608f7a89512193d49384d7018d5 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Wed, 2 Oct 2024 17:51:13 -0400 Subject: [PATCH 307/773] engines/grpic: also changed range for axis BC in this commit and commit below --- src/engines/grpic.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index 97aea35f7..cce672747 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -644,7 +644,7 @@ namespace ntt { kernel::OpenBoundaries_kernel(domain.fields.em, i1_min, tags)); Kokkos::parallel_for( "OpenBCFields", - domain.mesh.n_all(in::x2), + range, kernel::OpenBoundaries_kernel(domain.fields.em0, i1_min, tags)); } else if (g == gr_bc::aux) { Kokkos::parallel_for( From f277b2ad6a9598c2234e221453729efc4253406b Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Wed, 2 Oct 2024 18:04:58 -0400 Subject: [PATCH 308/773] engines/grpic: changed range for axis BC --- src/engines/grpic.hpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index cce672747..cb1ec1e85 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -668,23 +668,26 @@ namespace ntt { HERE); const auto i2_min = domain.mesh.i_min(in::x2); const auto i2_max = domain.mesh.i_max(in::x2); + auto range = CreateRangePolicy( + {domain.mesh.i_min(in::x1) - 1}, + {domain.mesh.i_max(in::x1)}); if (direction.get_sign() < 0) { Kokkos::parallel_for( "AxisBCFields", - domain.mesh.n_all(in::x1), + range, kernel::AxisBoundaries_kernel(domain.fields.em, i2_min, tags)); Kokkos::parallel_for( "AxisBCFields", - domain.mesh.n_all(in::x1), + range, kernel::AxisBoundaries_kernel(domain.fields.em0, i2_min, tags)); } else { Kokkos::parallel_for( "AxisBCFields", - domain.mesh.n_all(in::x1), + range, kernel::AxisBoundaries_kernel(domain.fields.em, i2_max, tags)); Kokkos::parallel_for( "AxisBCFields", - domain.mesh.n_all(in::x1), + range, kernel::AxisBoundaries_kernel(domain.fields.em0, i2_max, tags)); } } From fce3b6ea44b1c2bef79e97808282138547c7bc69 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Thu, 3 Oct 2024 18:30:39 -0400 Subject: [PATCH 309/773] updated pgen for wald --- setups/grpic/wald/pgen.hpp | 47 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 45 insertions(+), 2 deletions(-) diff --git a/setups/grpic/wald/pgen.hpp b/setups/grpic/wald/pgen.hpp index 3374a12d7..efb9c78e7 100644 --- a/setups/grpic/wald/pgen.hpp +++ b/setups/grpic/wald/pgen.hpp @@ -4,13 +4,51 @@ #include "enums.h" #include "global.h" +#include "arch/kokkos_aliases.h" #include "arch/traits.h" #include "archetypes/problem_generator.h" +#include "framework/domain/metadomain.h" namespace user { using namespace ntt; + template + struct InitFields { + InitFields() {} + + Inline auto VerticalPotential(const coord_t& x_Ph) const -> real_t { + return HALF * SQR(x_Ph[0]) * SQR(math::sin(x_Ph[1])); + } + + Inline auto bx1(const coord_t& x_Ph) const -> real_t { + return x_Ph[0] * math::cos(x_Ph[1]); + } + + Inline auto bx2(const coord_t& x_Ph) const -> real_t { + return -x_Ph[0] * math::sin(x_Ph[1]); + } + + Inline auto bx3(const coord_t& x_Ph) const -> real_t { + return ZERO; + } + + Inline auto dx1(const coord_t& x_Ph) const -> real_t { + return ZERO; + } + + Inline auto dx2(const coord_t& x_Ph) const -> real_t { + return ZERO; + } + + Inline auto dx3(const coord_t& x_Ph) const -> real_t { + return ZERO; + } + + private: + // const real_t Bsurf, Rstar; + }; + template struct PGen : public arch::ProblemGenerator { // compatibility traits for the problem generator @@ -24,13 +62,18 @@ namespace user { using arch::ProblemGenerator::D; using arch::ProblemGenerator::C; using arch::ProblemGenerator::params; + + InitFields init_flds; - inline PGen(SimulationParams& p, const Metadomain&) : - arch::ProblemGenerator(p) {} + inline PGen(SimulationParams& p, const Metadomain& m) : + arch::ProblemGenerator(p) + // , init_flds { } + {} inline PGen() {} }; + } // namespace user #endif From b1e4146fde3686e8132f86e28bbea39aebe99c93 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Thu, 3 Oct 2024 19:12:38 -0400 Subject: [PATCH 310/773] engines/grpic: adjusted ranges for all kernels --- src/engines/grpic.hpp | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index cb1ec1e85..78aac20af 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -675,20 +675,20 @@ namespace ntt { Kokkos::parallel_for( "AxisBCFields", range, - kernel::AxisBoundaries_kernel(domain.fields.em, i2_min, tags)); + kernel::AxisBoundariesGR_kernel(domain.fields.em, i2_min, tags)); Kokkos::parallel_for( "AxisBCFields", range, - kernel::AxisBoundaries_kernel(domain.fields.em0, i2_min, tags)); + kernel::AxisBoundariesGR_kernel(domain.fields.em0, i2_min, tags)); } else { Kokkos::parallel_for( "AxisBCFields", range, - kernel::AxisBoundaries_kernel(domain.fields.em, i2_max, tags)); + kernel::AxisBoundariesGR_kernel(domain.fields.em, i2_max, tags)); Kokkos::parallel_for( "AxisBCFields", range, - kernel::AxisBoundaries_kernel(domain.fields.em0, i2_max, tags)); + kernel::AxisBoundariesGR_kernel(domain.fields.em0, i2_max, tags)); } } @@ -826,8 +826,8 @@ namespace ntt { "algorithms.timestep.correction") * dt; auto range = CreateRangePolicy( - { domain.mesh.i_min(in::x1), domain.mesh.i_min(in::x2)}, - { domain.mesh.i_max(in::x1), domain.mesh.i_max(in::x2) + 1}); + { domain.mesh.i_min(in::x1), domain.mesh.i_min(in::x2) + 1}, + { domain.mesh.i_max(in::x1), domain.mesh.i_max(in::x2)}); const auto ni2 = domain.mesh.n_active(in::x2); if (g == gr_ampere::aux) { @@ -874,7 +874,10 @@ namespace ntt { const auto n0 = m_params.template get("scales.n0"); const auto B0 = m_params.template get("scales.B0"); const auto coeff = -dt * q0 * n0 / B0; - auto range = range_with_axis_BCs(domain); + // auto range = range_with_axis_BCs(domain); + auto range = CreateRangePolicy( + { domain.mesh.i_min(in::x1), domain.mesh.i_min(in::x2) + 1}, + { domain.mesh.i_max(in::x1), domain.mesh.i_max(in::x2)}); const auto ni2 = domain.mesh.n_active(in::x2); if (g == gr_ampere::aux) { @@ -904,18 +907,16 @@ namespace ntt { } void TimeAverageDB(domain_t& domain) { - auto range = range_with_axis_BCs(domain); Kokkos::parallel_for("TimeAverageDB", - range, + domain.mesh.rangeActiveCells(), kernel::gr::TimeAverageDB_kernel(domain.fields.em, domain.fields.em0, domain.mesh.metric)); } void TimeAverageJ(domain_t& domain) { - auto range = range_with_axis_BCs(domain); Kokkos::parallel_for("TimeAverageJ", - range, + domain.mesh.rangeActiveCells(), kernel::gr::TimeAverageJ_kernel(domain.fields.cur, domain.fields.cur0, domain.mesh.metric)); From c2b00e05c5d272e9ba236d2679dc935a1034e24a Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Thu, 3 Oct 2024 19:13:28 -0400 Subject: [PATCH 311/773] minor changes to kernels/fields_bc gr-specific --- src/kernels/fields_bcs.hpp | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/kernels/fields_bcs.hpp b/src/kernels/fields_bcs.hpp index 59cbbd76a..9df53e3e7 100644 --- a/src/kernels/fields_bcs.hpp +++ b/src/kernels/fields_bcs.hpp @@ -540,6 +540,29 @@ namespace kernel::bc { * * @brief Applies enforced boundary conditions (fixed value) */ + template + struct AxisBoundariesGR_kernel { + ndfield_t Fld; + const std::size_t i_edge; + const bool setE, setB; + + AxisBoundariesGR_kernel(ndfield_t Fld, std::size_t i_edge, BCTags tags) + : Fld { Fld } + , i_edge { i_edge } + , setE { tags & BC::Ex1 or tags & BC::Ex2 or tags & BC::Ex3 } + , setB { tags & BC::Bx1 or tags & BC::Bx2 or tags & BC::Bx3 } {} + + Inline void operator()(index_t i1) const { + if constexpr (D == Dim::_2D) { + if (setB) { + Fld(i1, i_edge, em::bx2) = ZERO; + } + } else { + raise::KernelError(HERE, "AxisBoundaries_kernel: D != 2"); + } + } + }; + template struct EnforcedBoundaries_kernel { static constexpr Dimension D = M::Dim; From 693d67cf8adb616308fd5a5a728313e28873362d Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Fri, 4 Oct 2024 14:50:26 -0400 Subject: [PATCH 312/773] wald: vertical potential setup --- setups/grpic/wald/pgen.hpp | 44 +++++++++++++++++++++++++++----------- 1 file changed, 31 insertions(+), 13 deletions(-) diff --git a/setups/grpic/wald/pgen.hpp b/setups/grpic/wald/pgen.hpp index efb9c78e7..a5f8f503e 100644 --- a/setups/grpic/wald/pgen.hpp +++ b/setups/grpic/wald/pgen.hpp @@ -13,20 +13,40 @@ namespace user { using namespace ntt; - template + template struct InitFields { - InitFields() {} + InitFields(M metric_) : metric { metric_ } {} - Inline auto VerticalPotential(const coord_t& x_Ph) const -> real_t { + Inline auto VerticalPotential(const coord_t& x_Cd) const -> real_t { + coord_t x_Ph { ZERO }; + metric.template convert(x_Cd, x_Ph); return HALF * SQR(x_Ph[0]) * SQR(math::sin(x_Ph[1])); } Inline auto bx1(const coord_t& x_Ph) const -> real_t { - return x_Ph[0] * math::cos(x_Ph[1]); + coord_t xi {ZERO}, x0m { ZERO }, x0p { ZERO }; + metric.template convert(x_Ph, xi); + + x0m[0] = xi[0]; + x0m[1] = xi[1] - HALF; + x0p[0] = xi[0]; + x0p[1] = xi[1] + HALF; + + real_t inv_sqrt_detH_ijP { ONE / metric.sqrt_det_h({ xi[0], xi[1] }) }; + return (VerticalPotential(x0p) - VerticalPotential(x0m)) * inv_sqrt_detH_ijP; } Inline auto bx2(const coord_t& x_Ph) const -> real_t { - return -x_Ph[0] * math::sin(x_Ph[1]); + coord_t xi {ZERO}, x0m { ZERO }, x0p { ZERO }; + metric.template convert(x_Ph, xi); + + x0m[0] = xi[0] + HALF - HALF; + x0m[1] = xi[1]; + x0p[0] = xi[0] + HALF + HALF; + x0p[1] = xi[1]; + + real_t inv_sqrt_detH_ijP { ONE / metric.sqrt_det_h({ xi[0], xi[1] }) }; + return -(VerticalPotential(x0p) - VerticalPotential(x0m)) * inv_sqrt_detH_ijP; } Inline auto bx3(const coord_t& x_Ph) const -> real_t { @@ -46,7 +66,7 @@ namespace user { } private: - // const real_t Bsurf, Rstar; + const M metric; }; template @@ -62,18 +82,16 @@ namespace user { using arch::ProblemGenerator::D; using arch::ProblemGenerator::C; using arch::ProblemGenerator::params; - - InitFields init_flds; - inline PGen(SimulationParams& p, const Metadomain& m) : - arch::ProblemGenerator(p) - // , init_flds { } - {} + InitFields init_flds; + + inline PGen(SimulationParams& p, const Metadomain& m) + : arch::ProblemGenerator(p) + , init_flds { m.mesh().metric } {} inline PGen() {} }; - } // namespace user #endif From 7aea0ad1250f51cdbea1c83e1c4896c7bf553611 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Fri, 4 Oct 2024 18:25:02 -0400 Subject: [PATCH 313/773] kernel/ampere_gr: bug for theta=0 --- src/kernels/ampere_gr.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/kernels/ampere_gr.hpp b/src/kernels/ampere_gr.hpp index 045eb1729..46b950796 100644 --- a/src/kernels/ampere_gr.hpp +++ b/src/kernels/ampere_gr.hpp @@ -74,6 +74,8 @@ namespace kernel::gr { if ((i2 == i2min) && is_axis_i2min) { // theta = 0 const real_t inv_polar_area_pH { ONE / metric.polar_area(i1_ + HALF) }; + const real_t inv_sqrt_detH_0pH { ONE / + metric.sqrt_det_h({ i1_, HALF }) }; Dout(i1, i2, em::dx1) = Din(i1, i2, em::dx1) + inv_polar_area_pH * coeff * H(i1, i2, em::hx3); Dout(i1, i2, em::dx2) = Din(i1, i2, em::dx2) + From 0d011a1716177a9171340873d62dd493e7f9aa46 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Fri, 4 Oct 2024 18:47:18 -0400 Subject: [PATCH 314/773] kernels/faraday_gr: bug at i2min --- src/kernels/faraday_gr.hpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/kernels/faraday_gr.hpp b/src/kernels/faraday_gr.hpp index 19eede5f2..5f6e5590b 100644 --- a/src/kernels/faraday_gr.hpp +++ b/src/kernels/faraday_gr.hpp @@ -73,7 +73,9 @@ namespace kernel::gr { Bout(i1, i2, em::bx1) = Bin(i1, i2, em::bx1) + coeff * inv_sqrt_detH_0pH * (E(i1, i2, em::ex3) - E(i1, i2 + 1, em::ex3)); - if ((i2 != i2min) || !is_axis_i2min) { + if ((i2 == i2min) && is_axis_i2min) { + Bout(i1, i2, em::bx2) = ZERO; + } else { const real_t inv_sqrt_detH_pH0 { ONE / metric.sqrt_det_h( { i1_ + HALF, i2_ }) }; Bout(i1, i2, em::bx2) = Bin(i1, i2, em::bx2) + From 159543217c244c6107c7bfd84476a4ff1ed60de9 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Fri, 4 Oct 2024 19:03:04 -0400 Subject: [PATCH 315/773] kernels/aux: bugs in time averaging --- src/kernels/aux_fields_gr.hpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/kernels/aux_fields_gr.hpp b/src/kernels/aux_fields_gr.hpp index b56a819f9..c739cffbd 100644 --- a/src/kernels/aux_fields_gr.hpp +++ b/src/kernels/aux_fields_gr.hpp @@ -257,9 +257,9 @@ namespace kernel::gr { BDf0(i1, i2, em::bx1) = HALF * (BDf0(i1, i2, em::bx1) + BDf(i1, i2, em::bx1)); BDf0(i1, i2, em::bx2) = HALF * (BDf0(i1, i2, em::bx2) + BDf(i1, i2, em::bx2)); BDf0(i1, i2, em::bx3) = HALF * (BDf0(i1, i2, em::bx3) + BDf(i1, i2, em::bx3)); - BDf0(i1, i2, em::ex1) = HALF * (BDf0(i1, i2, em::bx1) + BDf(i1, i2, em::ex1)); - BDf0(i1, i2, em::ex2) = HALF * (BDf0(i1, i2, em::bx2) + BDf(i1, i2, em::ex2)); - BDf0(i1, i2, em::ex3) = HALF * (BDf0(i1, i2, em::bx3) + BDf(i1, i2, em::ex3)); + BDf0(i1, i2, em::ex1) = HALF * (BDf0(i1, i2, em::ex1) + BDf(i1, i2, em::ex1)); + BDf0(i1, i2, em::ex2) = HALF * (BDf0(i1, i2, em::ex2) + BDf(i1, i2, em::ex2)); + BDf0(i1, i2, em::ex3) = HALF * (BDf0(i1, i2, em::ex3) + BDf(i1, i2, em::ex3)); } else { raise::KernelError( HERE, @@ -291,9 +291,9 @@ namespace kernel::gr { Inline void operator()(index_t i1, index_t i2) const { if constexpr (D == Dim::_2D) { - Jf0(i1, i2, cur::jx1) = HALF * (Jf0(i1, i2, cur::jx1) + Jf(i1, i2, cur::jx1)); - Jf0(i1, i2, cur::jx2) = HALF * (Jf0(i1, i2, cur::jx2) + Jf(i1, i2, cur::jx2)); - Jf0(i1, i2, cur::jx3) = HALF * (Jf0(i1, i2, cur::jx3) + Jf(i1, i2, cur::jx3)); + Jf(i1, i2, cur::jx1) = HALF * (Jf0(i1, i2, cur::jx1) + Jf(i1, i2, cur::jx1)); + Jf(i1, i2, cur::jx2) = HALF * (Jf0(i1, i2, cur::jx2) + Jf(i1, i2, cur::jx2)); + Jf(i1, i2, cur::jx3) = HALF * (Jf0(i1, i2, cur::jx3) + Jf(i1, i2, cur::jx3)); } else { raise::KernelError( HERE, From c15b6cfb4dfe4cfd6be9ea7084a883fd88a8c06e Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Fri, 4 Oct 2024 20:13:52 -0400 Subject: [PATCH 316/773] metric: kerr-schild a=0 minor fixes --- src/metrics/kerr_schild_0.h | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/metrics/kerr_schild_0.h b/src/metrics/kerr_schild_0.h index 70689f4f0..31080ed4c 100644 --- a/src/metrics/kerr_schild_0.h +++ b/src/metrics/kerr_schild_0.h @@ -36,6 +36,7 @@ namespace metric { private: const real_t dr, dtheta, dphi; const real_t dr_inv, dtheta_inv, dphi_inv; + const real_t a, rg_, rh_; public: static constexpr const char* Label { "kerr_schild_0" }; @@ -57,6 +58,9 @@ namespace metric { boundaries_t ext, const std::map& = {}) : MetricBase { res, ext } + , a { ZERO } + , rg_ { ONE } + , rh_ { TWO } , dr { (x1_max - x1_min) / nx1 } , dtheta { (x2_max - x2_min) / nx2 } , dphi { (x3_max - x3_min) / nx3 } @@ -70,17 +74,17 @@ namespace metric { [[nodiscard]] Inline auto spin() const -> const real_t& { - return ZERO; + return a; } [[nodiscard]] Inline auto rhorizon() const -> const real_t& { - return ZERO; + return rh_; } [[nodiscard]] Inline auto rg() const -> const real_t& { - return ZERO; + return rg_; } /** From 5a81f695280b9458942b08efddfa097bc3cd1440 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Fri, 18 Oct 2024 17:15:06 -0400 Subject: [PATCH 317/773] minor kernels/aux_gr --- src/kernels/aux_fields_gr.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/kernels/aux_fields_gr.hpp b/src/kernels/aux_fields_gr.hpp index c739cffbd..0983b6b7e 100644 --- a/src/kernels/aux_fields_gr.hpp +++ b/src/kernels/aux_fields_gr.hpp @@ -277,8 +277,8 @@ namespace kernel::gr { static_assert(M::is_metric, "M must be a metric class"); static constexpr auto D = M::Dim; - const ndfield_t Jf; - ndfield_t Jf0; + ndfield_t Jf; + const ndfield_t Jf0; const M metric; public: From fb952096c3f7b04b5684dffc8edc6a06a84a48aa Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Fri, 18 Oct 2024 17:17:40 -0400 Subject: [PATCH 318/773] engines/grpic: parameters for field boundaries --- src/engines/grpic.hpp | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index 78aac20af..f4cc46b1b 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -124,7 +124,7 @@ namespace ntt { * em0::D, em::D, em0::B, em::B <- boundary conditions */ m_metadomain.CommunicateFields(dom, Comm::B | Comm::B0 | Comm::D | Comm::D0); - FieldBoundaries(dom, BC::B | BC::D, gr_bc::main); + FieldBoundaries(dom, BC::B | BC::E, gr_bc::main); /** * em0::B <- em::B @@ -146,7 +146,7 @@ namespace ntt { /** * aux::E, aux::H <- boundary conditions */ - FieldBoundaries(dom, BC::B | BC::D, gr_bc::aux); + FieldBoundaries(dom, BC::B | BC::E, gr_bc::aux); /** * em0::B <- (em0::B) <- -curl aux::E @@ -172,7 +172,7 @@ namespace ntt { * em0::D, em::D <- boundary conditions */ m_metadomain.CommunicateFields(dom, Comm::D | Comm::D0); - FieldBoundaries(dom, BC::D, gr_bc::main); + FieldBoundaries(dom, BC::E, gr_bc::main); /** * aux::E <- alpha * em::D + beta x em0::B @@ -186,7 +186,7 @@ namespace ntt { /** * aux::E, aux::H <- boundary conditions */ - FieldBoundaries(dom, BC::B | BC::D, gr_bc::aux); + FieldBoundaries(dom, BC::B | BC::E, gr_bc::aux); // !ADD: GR -- particles? @@ -212,7 +212,7 @@ namespace ntt { * em0::D, em::D <- boundary conditions */ m_metadomain.CommunicateFields(dom, Comm::D | Comm::D0); - FieldBoundaries(dom, BC::D, gr_bc::main); + FieldBoundaries(dom, BC::E, gr_bc::main); /** * aux::H <- alpha * em0::B - beta x em0::D @@ -236,7 +236,7 @@ namespace ntt { * em0::D, em::D <- boundary conditions */ m_metadomain.CommunicateFields(dom, Comm::D | Comm::D0); - FieldBoundaries(dom, BC::D, gr_bc::main); + FieldBoundaries(dom, BC::E, gr_bc::main); /** * em::D <-> em0::D @@ -299,7 +299,7 @@ namespace ntt { /** * aux::E <- boundary conditions */ - FieldBoundaries(dom, BC::D, gr_bc::aux); + FieldBoundaries(dom, BC::E, gr_bc::aux); timers.stop("FieldBoundaries"); timers.start("FieldSolver"); @@ -400,7 +400,7 @@ namespace ntt { /** * aux::Е <- boundary conditions */ - FieldBoundaries(dom, BC::D, gr_bc::aux); + FieldBoundaries(dom, BC::E, gr_bc::aux); timers.stop("FieldBoundaries"); timers.start("FieldSolver"); @@ -450,7 +450,7 @@ namespace ntt { m_metadomain.CommunicateFields(dom, Comm::D | Comm::D0); timers.stop("Communications"); timers.start("FieldBoundaries"); - FieldBoundaries(dom, BC::D, gr_bc::main); + FieldBoundaries(dom, BC::E, gr_bc::main); timers.stop("FieldBoundaries"); timers.start("FieldSolver"); @@ -505,7 +505,7 @@ namespace ntt { m_metadomain.CommunicateFields(dom, Comm::D | Comm::D0); timers.stop("Communications"); timers.start("FieldBoundaries"); - FieldBoundaries(dom, BC::D, gr_bc::main); + FieldBoundaries(dom, BC::E, gr_bc::main); timers.stop("FieldBoundaries"); } /** @@ -834,7 +834,7 @@ namespace ntt { // First push, updates D0 with J. Kokkos::parallel_for("Ampere-1", range, - kernel::gr::Ampere_kernel(domain.fields.em0, + kernel::gr::Ampere_kernel(domain.fields.em0, // Din, Dout, aux domain.fields.em0, domain.fields.aux, domain.mesh.metric, From ee2bd29754613c057e184932232ad3b6020e767c Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Mon, 21 Oct 2024 19:05:10 -0400 Subject: [PATCH 319/773] minor notes --- src/engines/grpic.hpp | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index f4cc46b1b..c5d99b302 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -731,9 +731,9 @@ namespace ntt { if (g == gr_getE::D0_B) { Kokkos::parallel_for("ComputeAuxE", range, - kernel::gr::ComputeAuxE_kernel(domain.fields.em0, - domain.fields.em, - domain.fields.aux, + kernel::gr::ComputeAuxE_kernel(domain.fields.em0, // D + domain.fields.em, // B + domain.fields.aux, // E domain.mesh.metric)); } else if (g == gr_getE::D_B0) { Kokkos::parallel_for("ComputeAuxE", @@ -752,9 +752,9 @@ namespace ntt { if (g == gr_getH::D_B0) { Kokkos::parallel_for("ComputeAuxH", range, - kernel::gr::ComputeAuxH_kernel(domain.fields.em, - domain.fields.em0, - domain.fields.aux, + kernel::gr::ComputeAuxH_kernel(domain.fields.em, // D + domain.fields.em0, // B + domain.fields.aux, // H domain.mesh.metric)); } else if (g == gr_getH::D0_B0) { Kokkos::parallel_for("ComputeAuxH", @@ -795,9 +795,9 @@ namespace ntt { Kokkos::parallel_for( "Faraday", domain.mesh.rangeActiveCells(), - kernel::gr::Faraday_kernel(domain.fields.em0, - domain.fields.em0, - domain.fields.aux, + kernel::gr::Faraday_kernel(domain.fields.em0, // Bin + domain.fields.em0, // Bout + domain.fields.aux, // E domain.mesh.metric, dT, domain.mesh.n_active(in::x2), @@ -826,16 +826,16 @@ namespace ntt { "algorithms.timestep.correction") * dt; auto range = CreateRangePolicy( - { domain.mesh.i_min(in::x1), domain.mesh.i_min(in::x2) + 1}, - { domain.mesh.i_max(in::x1), domain.mesh.i_max(in::x2)}); + { domain.mesh.i_min(in::x1), domain.mesh.i_min(in::x2)}, + { domain.mesh.i_max(in::x1), domain.mesh.i_max(in::x2) + 1}); const auto ni2 = domain.mesh.n_active(in::x2); if (g == gr_ampere::aux) { // First push, updates D0 with J. Kokkos::parallel_for("Ampere-1", range, - kernel::gr::Ampere_kernel(domain.fields.em0, // Din, Dout, aux - domain.fields.em0, + kernel::gr::Ampere_kernel(domain.fields.em0, // Din + domain.fields.em0, // Dout domain.fields.aux, domain.mesh.metric, dT, From dd7277c7c63bf8f8d408cc9de8538ba1409cd23a Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Wed, 23 Oct 2024 17:27:09 -0400 Subject: [PATCH 320/773] implemented absorbing boundaries for gr --- src/engines/grpic.hpp | 25 ++++------- src/kernels/fields_bcs.hpp | 92 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 101 insertions(+), 16 deletions(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index c5d99b302..375916c41 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -563,25 +563,16 @@ namespace ntt { const auto dim = direction.get_dim(); real_t xg_min, xg_max, xg_edge; auto sign = direction.get_sign(); - if (sign > 0) { // + direction - xg_max = m_metadomain.mesh().extent(dim).second; - xg_min = xg_max - ds; - xg_edge = xg_max; - } else { // - direction - xg_min = m_metadomain.mesh().extent(dim).first; - xg_max = xg_min + ds; - xg_edge = xg_min; - } + xg_max = m_metadomain.mesh().extent(dim).second; + xg_min = xg_max - ds; + xg_edge = xg_max; + boundaries_t box; boundaries_t incl_ghosts; for (unsigned short d { 0 }; d < M::Dim; ++d) { if (d == static_cast(dim)) { box.push_back({ xg_min, xg_max }); - if (sign > 0) { - incl_ghosts.push_back({ false, true }); - } else { - incl_ghosts.push_back({ true, false }); - } + incl_ghosts.push_back({ false, true }); } else { box.push_back(Range::All); incl_ghosts.push_back({ true, true }); @@ -602,7 +593,8 @@ namespace ntt { Kokkos::parallel_for( "AbsorbFields", CreateRangePolicy(range_min, range_max), - kernel::AbsorbBoundaries_kernel(domain.fields.em, + kernel::AbsorbBoundariesGR_kernel(domain.fields.em, + m_pgen.init_flds, domain.mesh.metric, xg_edge, ds, @@ -610,7 +602,8 @@ namespace ntt { Kokkos::parallel_for( "AbsorbFields", CreateRangePolicy(range_min, range_max), - kernel::AbsorbBoundaries_kernel(domain.fields.em0, + kernel::AbsorbBoundariesGR_kernel(domain.fields.em0, + m_pgen.init_flds, domain.mesh.metric, xg_edge, ds, diff --git a/src/kernels/fields_bcs.hpp b/src/kernels/fields_bcs.hpp index 9df53e3e7..9d9db5488 100644 --- a/src/kernels/fields_bcs.hpp +++ b/src/kernels/fields_bcs.hpp @@ -936,6 +936,98 @@ namespace kernel::bc { } }; + template + struct AbsorbBoundariesGR_kernel { + static_assert(M::is_metric, "M must be a metric class"); + static_assert(i <= static_cast(M::Dim), + "Invalid component index"); + + ndfield_t Fld; + const I finit; + const M metric; + const real_t xg_edge; + const real_t dx_abs; + const BCTags tags; + + AbsorbBoundariesGR_kernel(ndfield_t Fld, + const I& finit, + const M& metric, + real_t xg_edge, + real_t dx_abs, + BCTags tags) + : Fld { Fld } + , finit { finit } + , metric { metric } + , xg_edge { xg_edge } + , dx_abs { dx_abs } + , tags { tags } {} + + Inline void operator()(index_t i1, index_t i2) const { + if constexpr (M::Dim == Dim::_2D) { + const auto i1_ = COORD(i1); + const auto i2_ = COORD(i2); + for (const auto comp : + { em::ex1, em::ex2, em::ex3, em::bx1, em::bx2, em::bx3 }) { + if ((comp == em::ex1) and not(tags & BC::Ex1)) { + continue; + } else if ((comp == em::ex2) and not(tags & BC::Ex2)) { + continue; + } else if ((comp == em::ex3) and not(tags & BC::Ex3)) { + continue; + } else if ((comp == em::bx1) and not(tags & BC::Bx1)) { + continue; + } else if ((comp == em::bx2) and not(tags & BC::Bx2)) { + continue; + } else if ((comp == em::bx3) and not(tags & BC::Bx3)) { + continue; + } + coord_t x_Cd { ZERO }; + if (comp == em::ex1 or comp == em::bx2 or comp == em::bx3) { + x_Cd[0] = i1_ + HALF; + x_Cd[1] = i2_; + } else if (comp == em::ex2 or comp == em::ex3 or comp == em::bx1) { + x_Cd[0] = i1_; + x_Cd[1] = i2_; + } + + const auto dx = math::abs( + metric.template convert(x_Cd[i - 1]) - xg_edge); + Fld(i1, i2, comp) *= math::tanh(dx / (INV_4 * dx_abs)); + + if (comp == em::bx1) { + const real_t x1_0 { metric.template convert<1, Crd::Cd, Crd::Ph>(i1_) }; + const real_t x2_H { metric.template convert<2, Crd::Cd, Crd::Ph>( + i2_ + HALF) }; + + vec_t b_PU { finit.bx1({ x1_0, x2_H }), + finit.bx2({ x1_0, x2_H }), + finit.bx3({ x1_0, x2_H }) }; + vec_t b_U { ZERO }; + metric.template transform({ i1_, i2_ + HALF }, b_PU, b_U); + Fld(i1, i2, comp) += (ONE - math::tanh(dx / (INV_4 * dx_abs))) * + b_U[0]; + } else if (comp == em::bx2) { + const real_t x1_H { metric.template convert<1, Crd::Cd, Crd::Ph>( + i1_ + HALF) }; + const real_t x2_0 { metric.template convert<2, Crd::Cd, Crd::Ph>(i2_) }; + + vec_t b_PU { finit.bx1({ x1_H, x2_0 }), + finit.bx2({ x1_H, x2_0 }), + finit.bx3({ x1_H, x2_0 }) }; + vec_t b_U { ZERO }; + metric.template transform({ i1_ + HALF, i2_ }, b_PU, b_U); + Fld(i1, i2, comp) += (ONE - math::tanh(dx / (INV_4 * dx_abs))) * + b_U[1]; + } + } + } else { + raise::KernelError( + HERE, + "AbsorbFields_kernel: 2D implementation called for D != 2"); + } + } + }; + } // namespace kernel::bc #endif // KERNELS_FIELDS_BCS_HPP From 7aad0cc7a85dec44fe72d4db8906bcfd32105b8f Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Thu, 31 Oct 2024 15:49:40 -0400 Subject: [PATCH 321/773] working EM solver fully implemented --- setups/grpic/wald/pgen.hpp | 41 +++++++++++++++++++-- setups/grpic/wald/wald.toml | 72 +++++++++++++++++++++++++++++++++++++ 2 files changed, 110 insertions(+), 3 deletions(-) create mode 100644 setups/grpic/wald/wald.toml diff --git a/setups/grpic/wald/pgen.hpp b/setups/grpic/wald/pgen.hpp index a5f8f503e..51636314b 100644 --- a/setups/grpic/wald/pgen.hpp +++ b/setups/grpic/wald/pgen.hpp @@ -17,12 +17,30 @@ namespace user { struct InitFields { InitFields(M metric_) : metric { metric_ } {} - Inline auto VerticalPotential(const coord_t& x_Cd) const -> real_t { + Inline auto A_3(const coord_t& x_Cd) const -> real_t { + // return HALF * (metric.template h_<3, 3>(x_Cd) ); + // + TWO * metric.spin() * metric.template h_<1, 3>(x_Cd) * metric.beta1(x_Cd) + // ); + coord_t x_Ph { ZERO }; metric.template convert(x_Cd, x_Ph); return HALF * SQR(x_Ph[0]) * SQR(math::sin(x_Ph[1])); } + Inline auto A_1(const coord_t& x_Cd) const -> real_t { + return HALF * (metric.template h_<1, 3>(x_Cd) + + TWO * metric.spin() * metric.template h_<1, 1>(x_Cd) * metric.beta1(x_Cd) + ); + } + + Inline auto A_0(const coord_t& x_Cd) const -> real_t { + real_t g_00 { -metric.alpha(x_Cd) * metric.alpha(x_Cd) + + metric.template h_<1, 1>(x_Cd) * metric.beta1(x_Cd) * metric.beta1(x_Cd) + }; + return HALF * (metric.template h_<1, 3>(x_Cd) * metric.beta1(x_Cd) + + TWO * metric.spin() * g_00); + } + Inline auto bx1(const coord_t& x_Ph) const -> real_t { coord_t xi {ZERO}, x0m { ZERO }, x0p { ZERO }; metric.template convert(x_Ph, xi); @@ -33,7 +51,11 @@ namespace user { x0p[1] = xi[1] + HALF; real_t inv_sqrt_detH_ijP { ONE / metric.sqrt_det_h({ xi[0], xi[1] }) }; - return (VerticalPotential(x0p) - VerticalPotential(x0m)) * inv_sqrt_detH_ijP; + + if (cmp::AlmostZero(x_Ph[1])) + return ONE; + else + return (A_3(x0p) - A_3(x0m)) * inv_sqrt_detH_ijP; } Inline auto bx2(const coord_t& x_Ph) const -> real_t { @@ -46,10 +68,23 @@ namespace user { x0p[1] = xi[1]; real_t inv_sqrt_detH_ijP { ONE / metric.sqrt_det_h({ xi[0], xi[1] }) }; - return -(VerticalPotential(x0p) - VerticalPotential(x0m)) * inv_sqrt_detH_ijP; + if (cmp::AlmostZero(x_Ph[1])) + return ZERO; + else + return -(A_3(x0p) - A_3(x0m)) * inv_sqrt_detH_ijP; } Inline auto bx3(const coord_t& x_Ph) const -> real_t { + // coord_t xi {ZERO}, x0m { ZERO }, x0p { ZERO }; + // metric.template convert(x_Ph, xi); + + // x0m[0] = xi[0] + HALF - HALF; + // x0m[1] = xi[1]; + // x0p[0] = xi[0] + HALF + HALF; + // x0p[1] = xi[1]; + + // real_t inv_sqrt_detH_ijP { ONE / metric.sqrt_det_h({ xi[0], xi[1] }) }; + // return -(A_1(x0p) - A_1(x0m)) * inv_sqrt_detH_ijP; return ZERO; } diff --git a/setups/grpic/wald/wald.toml b/setups/grpic/wald/wald.toml new file mode 100644 index 000000000..36c746ae5 --- /dev/null +++ b/setups/grpic/wald/wald.toml @@ -0,0 +1,72 @@ +[simulation] + name = "wald" + engine = "grpic" + runtime = 500.0 + +[grid] + resolution = [128,128] + extent = [[1.2, 8.0]] + + [grid.metric] + metric = "qkerr_schild" + qsph_r0 = 0.0 + qsph_h = 0.0 + ks_a = 0.95 + + [grid.boundaries] + fields = [["ABSORB"]] + particles = [["ABSORB"]] + + [grid.boundaries.absorb] + ds = 0.5 + +[scales] + larmor0 = 1.0 + skindepth0 = 1.0 + +[algorithms] + current_filters = 4 + + [algorithms.timestep] + CFL = 0.5 + + [algorithms.toggles] + deposit = false + fieldsolver = true + +[particles] + ppc0 = 8.0 + use_weights = true + sort_interval = 100 + +# [[particles.species]] +# label = "e-" +# mass = 1.0 +# charge = -1.0 +# maxnpart = 2e6 +# pusher = "Boris" +# +# [[particles.species]] +# label = "e+" +# mass = 1.0 +# charge = 1.0 +# maxnpart = 2e6 +# pusher = "Boris" + +[setup] + +[output] + format = "hdf5" + + [output.fields] + interval_time = 1.0 + quantities = ["D", "H", "B", "J", "A"] + + [output.particles] + enable = false + + [output.spectra] + enable = false + +[diagnostics] + interval = 1 From e7615254fe962e55ba12f64e670854e3b41f341f Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Tue, 5 Nov 2024 17:52:11 -0500 Subject: [PATCH 322/773] compilible pusher in gr --- src/engines/grpic.hpp | 41 ++++++++++++++++++-- src/kernels/particle_pusher_gr.hpp | 61 +++++++++++++++--------------- 2 files changed, 69 insertions(+), 33 deletions(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index 375916c41..333742eaf 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -345,7 +345,7 @@ namespace ntt { * Now: x_prtl at n + 1, u_prtl at n + 1/2 */ timers.start("ParticlePusher"); - // ParticlePush(dom); + ParticlePush(dom); timers.stop("ParticlePusher"); /** @@ -1005,10 +1005,16 @@ namespace ntt { // coeff = q / m (dt / 2) omegaB0 const auto coeff = q_ovr_m * HALF * dt * m_params.template get("scales.omegaB0"); + // clang-format off + + if (species.pusher() == PrtlPusher::PHOTON) { + auto range_policy = Kokkos::RangePolicy( + 0, + species.npart()); Kokkos::parallel_for( "ParticlePusher", - species.rangeActiveParticles(), + range_policy, kernel::gr::Pusher_kernel( domain.fields.em, domain.fields.em0, @@ -1023,9 +1029,38 @@ namespace ntt { domain.mesh.n_active(in::x1), domain.mesh.n_active(in::x2), domain.mesh.n_active(in::x3), - m_params.template get("algorithms.gr.pusher_eps"), m_params.template get("algorithms.gr.pusher_niter"), + m_params.template get("algorithms.gr.pusher_eps"), m_params.template get("algorithms.gr.pusher_niter"), domain.mesh.prtl_bc() )); + } else if (species.pusher() == PrtlPusher::BORIS) { + auto range_policy = Kokkos::RangePolicy( + 0, + species.npart()); + Kokkos::parallel_for( + "ParticlePusher", + range_policy, + kernel::gr::Pusher_kernel( + domain.fields.em, + domain.fields.em0, + species.i1, species.i2, species.i3, + species.i1_prev, species.i2_prev, species.i3_prev, + species.dx1, species.dx2, species.dx3, + species.dx1_prev, species.dx2_prev, species.dx3_prev, + species.ux1, species.ux2, species.ux3, + species.phi, species.tag, + domain.mesh.metric, + coeff, dt, + domain.mesh.n_active(in::x1), + domain.mesh.n_active(in::x2), + domain.mesh.n_active(in::x3), + m_params.template get("algorithms.gr.pusher_eps"), m_params.template get("algorithms.gr.pusher_niter"), + domain.mesh.prtl_bc() + )); + } else if (species.pusher() == PrtlPusher::NONE) { + // do nothing + } else { + raise::Error("not implemented", HERE); + } // clang-format on } } diff --git a/src/kernels/particle_pusher_gr.hpp b/src/kernels/particle_pusher_gr.hpp index 547463fa7..fd6246217 100644 --- a/src/kernels/particle_pusher_gr.hpp +++ b/src/kernels/particle_pusher_gr.hpp @@ -65,6 +65,7 @@ namespace kernel::gr { static_assert(M::is_metric, "M must be a metric class"); static constexpr auto D = M::Dim; + private: const randacc_ndfield_t DB; const randacc_ndfield_t DB0; array_t i1, i2, i3; @@ -86,34 +87,34 @@ namespace kernel::gr { bool is_absorb_i1min { false }, is_absorb_i1max { false }; public: - Pusher_kernel(const ndfield_t& DB, - const ndfield_t& DB0, - const array_t& i1, - const array_t& i2, - const array_t& i3, - const array_t& i1_prev, - const array_t& i2_prev, - const array_t& i3_prev, - const array_t& dx1, - const array_t& dx2, - const array_t& dx3, - const array_t& dx1_prev, - const array_t& dx2_prev, - const array_t& dx3_prev, - const array_t& ux1, - const array_t& ux2, - const array_t& ux3, - const array_t& phi, - const array_t& tag, - const M& metric, - const real_t& coeff, - const real_t& dt, - const int& ni1, - const int& ni2, - const int& ni3, - const real_t& epsilon, - const int& niter, - const boundaries_t& boundaries) + Pusher_kernel(const ndfield_t& DB, + const ndfield_t& DB0, + array_t& i1, + array_t& i2, + array_t& i3, + array_t& i1_prev, + array_t& i2_prev, + array_t& i3_prev, + array_t& dx1, + array_t& dx2, + array_t& dx3, + array_t& dx1_prev, + array_t& dx2_prev, + array_t& dx3_prev, + array_t& ux1, + array_t& ux2, + array_t& ux3, + array_t& phi, + array_t& tag, + const M& metric, + real_t coeff, + real_t dt, + int ni1, + int ni2, + int ni3, + const real_t& epsilon, + const int& niter, + const boundaries_t& boundaries) : DB { DB } , DB0 { DB0 } , i1 { i1 } @@ -351,8 +352,8 @@ namespace kernel::gr { vp_upd[1] = vp[1] + dt * - (-metric.alpha(xp) * u0 * DERIVATIVE_IN_TH(alpha, xp) + - vp_mid[1] * DERIVATIVE_IN_TH(beta1, xp) - + (-metric.alpha(xp) * u0 * DERIVATIVE_IN_TH(metric.alpha, xp) + + vp_mid[1] * DERIVATIVE_IN_TH(metric.beta1, xp) - (HALF / u0) * (DERIVATIVE_IN_TH((metric.template h<1, 1>), xp) * SQR(vp_mid[0]) + DERIVATIVE_IN_TH((metric.template h<2, 2>), xp) * SQR(vp_mid[1]) + From 3fc4497633b958eca5fd81e6205218e971428fa0 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Wed, 6 Nov 2024 14:58:22 -0500 Subject: [PATCH 323/773] consistent type for pusher_niter --- src/engines/grpic.hpp | 4 ++-- src/kernels/particle_pusher_gr.hpp | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index 333742eaf..67ef1ef46 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -1029,7 +1029,7 @@ namespace ntt { domain.mesh.n_active(in::x1), domain.mesh.n_active(in::x2), domain.mesh.n_active(in::x3), - m_params.template get("algorithms.gr.pusher_eps"), m_params.template get("algorithms.gr.pusher_niter"), + m_params.template get("algorithms.gr.pusher_eps"), m_params.template get("algorithms.gr.pusher_niter"), domain.mesh.prtl_bc() )); } else if (species.pusher() == PrtlPusher::BORIS) { @@ -1053,7 +1053,7 @@ namespace ntt { domain.mesh.n_active(in::x1), domain.mesh.n_active(in::x2), domain.mesh.n_active(in::x3), - m_params.template get("algorithms.gr.pusher_eps"), m_params.template get("algorithms.gr.pusher_niter"), + m_params.template get("algorithms.gr.pusher_eps"), m_params.template get("algorithms.gr.pusher_niter"), domain.mesh.prtl_bc() )); } else if (species.pusher() == PrtlPusher::NONE) { diff --git a/src/kernels/particle_pusher_gr.hpp b/src/kernels/particle_pusher_gr.hpp index fd6246217..fba40890f 100644 --- a/src/kernels/particle_pusher_gr.hpp +++ b/src/kernels/particle_pusher_gr.hpp @@ -77,11 +77,11 @@ namespace kernel::gr { array_t tag; const M metric; - const real_t coeff, dt; - const int ni1, ni2, ni3; - const real_t epsilon; - const int niter; - const int i1_absorb; + const real_t coeff, dt; + const int ni1, ni2, ni3; + const real_t epsilon; + const unsigned short niter; + const int i1_absorb; bool is_axis_i2min { false }, is_axis_i2max { false }; bool is_absorb_i1min { false }, is_absorb_i1max { false }; @@ -113,7 +113,7 @@ namespace kernel::gr { int ni2, int ni3, const real_t& epsilon, - const int& niter, + const unsigned short& niter, const boundaries_t& boundaries) : DB { DB } , DB0 { DB0 } From c7d78cda1b9ac2ce16ec4bf33c0c7607b3554cdd Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Thu, 7 Nov 2024 10:14:22 -0500 Subject: [PATCH 324/773] cleaned up an unused var --- src/engines/grpic.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index 67ef1ef46..745503793 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -562,7 +562,6 @@ namespace ntt { "grid.boundaries.absorb.ds"); const auto dim = direction.get_dim(); real_t xg_min, xg_max, xg_edge; - auto sign = direction.get_sign(); xg_max = m_metadomain.mesh().extent(dim).second; xg_min = xg_max - ds; xg_edge = xg_max; From 8cc33c7cd26a54eabf96400a4a008f73a3b5be9a Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Thu, 7 Nov 2024 16:01:16 -0500 Subject: [PATCH 325/773] fixed bug in output for dimensions of coordinates of particles in GR --- src/framework/domain/output.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/framework/domain/output.cpp b/src/framework/domain/output.cpp index 6961d2826..ae138bac1 100644 --- a/src/framework/domain/output.cpp +++ b/src/framework/domain/output.cpp @@ -87,7 +87,13 @@ namespace ntt { const auto species_to_write = params.template get>( "output.particles.species"); g_writer.defineFieldOutputs(S, all_fields_to_write); - g_writer.defineParticleOutputs(M::PrtlDim, species_to_write); + + Dimension dim = M::PrtlDim; + if constexpr (M::CoordType != Coord::Cart) { + dim = Dim::_3D; + } + g_writer.defineParticleOutputs(dim, species_to_write); + // spectra write all particle species std::vector spectra_species {}; for (const auto& sp : species_params()) { From 470f733932b5b3952c7dbcecfb26791c07eeaffa Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Fri, 8 Nov 2024 16:08:26 -0500 Subject: [PATCH 326/773] fixed coordinate transformation for a global injector. When we inject a small amount of particles with given velocities, this is usually in physical coordinates rather than tetrads as in injection for a given energy distribution --- src/kernels/injectors.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/kernels/injectors.hpp b/src/kernels/injectors.hpp index 9d3fd7d81..dd5e2d21d 100644 --- a/src/kernels/injectors.hpp +++ b/src/kernels/injectors.hpp @@ -335,7 +335,7 @@ namespace kernel { if constexpr (S == SimEngine::SRPIC) { global_metric.template transform_xyz(x_Cd_, u_Ph, u_Cd); } else if constexpr (S == SimEngine::GRPIC) { - global_metric.template transform(x_Cd, u_Ph, u_Cd); + global_metric.template transform(x_Cd, u_Ph, u_Cd); } else { raise::KernelError(HERE, "Unknown simulation engine"); } @@ -380,7 +380,7 @@ namespace kernel { if constexpr (S == SimEngine::SRPIC) { global_metric.template transform_xyz(x_Cd, u_Ph, u_Cd); } else if constexpr (S == SimEngine::GRPIC) { - global_metric.template transform(x_Cd, u_Ph, u_Cd); + global_metric.template transform(x_Cd, u_Ph, u_Cd); } else { raise::KernelError(HERE, "Unknown simulation engine"); } From 37c4b0d622845683e6c04e283a421f83cb5c2167 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Fri, 8 Nov 2024 16:11:23 -0500 Subject: [PATCH 327/773] minor consistensy with sr --- src/kernels/particle_pusher_gr.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/kernels/particle_pusher_gr.hpp b/src/kernels/particle_pusher_gr.hpp index fba40890f..2e9ddbde2 100644 --- a/src/kernels/particle_pusher_gr.hpp +++ b/src/kernels/particle_pusher_gr.hpp @@ -29,7 +29,7 @@ /* Local macros */ /* -------------------------------------------------------------------------- */ #define from_Xi_to_i(XI, I) \ - { I = static_cast((XI)); } + { I = static_cast((XI + 1)) - 1; } #define from_Xi_to_i_di(XI, I, DI) \ { \ From 2b2e6a9f6ace65b4fa430b432a71fb026fc42896 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Tue, 3 Dec 2024 10:18:51 -0500 Subject: [PATCH 328/773] kernels/particle_pusher_gr: 1. derivatives of the metric in geodesic pusher now use their functional form. Saved numerical derivatives for future testing 2. Added placeholders for storing previous coordinate 3. Fixed bug in geodesic pusher in updating utheta 4. Changes to boundary conditions at the axis --- src/kernels/particle_pusher_gr.hpp | 62 ++++++++++++++++++++++-------- 1 file changed, 46 insertions(+), 16 deletions(-) diff --git a/src/kernels/particle_pusher_gr.hpp b/src/kernels/particle_pusher_gr.hpp index 2e9ddbde2..306f19013 100644 --- a/src/kernels/particle_pusher_gr.hpp +++ b/src/kernels/particle_pusher_gr.hpp @@ -334,31 +334,53 @@ namespace kernel::gr { // find contravariant midpoint velocity metric.template transform(xp, vp_mid, vp_mid_cntrv); - // find Gamma / alpha at midpoint + // find Gamma / alpha at midpointы real_t u0 { computeGamma(T {}, vp_mid, vp_mid_cntrv) / metric.alpha(xp) }; // find updated velocity + // vp_upd[0] = + // vp[0] + + // dt * + // (-metric.alpha(xp) * u0 * DERIVATIVE_IN_R(metric.alpha, xp) + + // vp_mid[0] * DERIVATIVE_IN_R(metric.beta1, xp) - + // (HALF / u0) * + // (DERIVATIVE_IN_R((metric.template h<1, 1>), xp) * SQR(vp_mid[0]) + + // DERIVATIVE_IN_R((metric.template h<2, 2>), xp) * SQR(vp_mid[1]) + + // DERIVATIVE_IN_R((metric.template h<3, 3>), xp) * SQR(vp_mid[2]) + + // TWO * DERIVATIVE_IN_R((metric.template h<1, 3>), xp) * + // vp_mid[0] * vp_mid[2])); + // vp_upd[1] = + // vp[1] + + // dt * + // (-metric.alpha(xp) * u0 * DERIVATIVE_IN_TH(metric.alpha, xp) + + // vp_mid[0] * DERIVATIVE_IN_TH(metric.beta1, xp) - + // (HALF / u0) * + // (DERIVATIVE_IN_TH((metric.template h<1, 1>), xp) * SQR(vp_mid[0]) + + // DERIVATIVE_IN_TH((metric.template h<2, 2>), xp) * SQR(vp_mid[1]) + + // DERIVATIVE_IN_TH((metric.template h<3, 3>), xp) * SQR(vp_mid[2]) + + // TWO * DERIVATIVE_IN_TH((metric.template h<1, 3>), xp) * + // vp_mid[0] * vp_mid[2])); vp_upd[0] = vp[0] + dt * - (-metric.alpha(xp) * u0 * DERIVATIVE_IN_R(metric.alpha, xp) + - vp_mid[0] * DERIVATIVE_IN_R(metric.beta1, xp) - + (-metric.alpha(xp) * u0 * metric.dr_alpha(xp) + + vp_mid[0] * metric.dr_beta1(xp) - (HALF / u0) * - (DERIVATIVE_IN_R((metric.template h<1, 1>), xp) * SQR(vp_mid[0]) + - DERIVATIVE_IN_R((metric.template h<2, 2>), xp) * SQR(vp_mid[1]) + - DERIVATIVE_IN_R((metric.template h<3, 3>), xp) * SQR(vp_mid[2]) + - TWO * DERIVATIVE_IN_R((metric.template h<1, 3>), xp) * + (metric.dr_h11(xp) * SQR(vp_mid[0]) + + metric.dr_h22(xp) * SQR(vp_mid[1]) + + metric.dr_h33(xp) * SQR(vp_mid[2]) + + TWO * metric.dr_h13(xp) * vp_mid[0] * vp_mid[2])); vp_upd[1] = vp[1] + dt * - (-metric.alpha(xp) * u0 * DERIVATIVE_IN_TH(metric.alpha, xp) + - vp_mid[1] * DERIVATIVE_IN_TH(metric.beta1, xp) - + (-metric.alpha(xp) * u0 * metric.dt_alpha(xp) + + vp_mid[0] * metric.dt_beta1(xp) - (HALF / u0) * - (DERIVATIVE_IN_TH((metric.template h<1, 1>), xp) * SQR(vp_mid[0]) + - DERIVATIVE_IN_TH((metric.template h<2, 2>), xp) * SQR(vp_mid[1]) + - DERIVATIVE_IN_TH((metric.template h<3, 3>), xp) * SQR(vp_mid[2]) + - TWO * DERIVATIVE_IN_TH((metric.template h<1, 3>), xp) * + (metric.dt_h11(xp) * SQR(vp_mid[0]) + + metric.dt_h22(xp) * SQR(vp_mid[1]) + + metric.dt_h33(xp) * SQR(vp_mid[2]) + + TWO * metric.dt_h13(xp) * vp_mid[0] * vp_mid[2])); } } else if constexpr (D == Dim::_3D) { @@ -656,9 +678,13 @@ namespace kernel::gr { dx2_prev(p) = dx2(p); coord_t xp { ZERO }; + coord_t xp_prev { ZERO }; xp[0] = i_di_to_Xi(i1(p), dx1(p)); xp[1] = i_di_to_Xi(i2(p), dx2(p)); + + xp_prev[0] = i_di_to_Xi(i1_prev(p), dx1_prev(p)); + xp_prev[1] = i_di_to_Xi(i2_prev(p), dx2_prev(p)); vec_t Dp_cntrv { ZERO }, Bp_cntrv { ZERO }, Dp_hat { ZERO }, Bp_hat { ZERO }; @@ -692,7 +718,7 @@ namespace kernel::gr { { (xp[0] + xp_upd[0]) * HALF, (xp[1] + xp_upd[1]) * HALF }, vp_upd, phi(p)); - + // update coordinate int i1_, i2_; prtldx_t dx1_, dx2_; @@ -726,12 +752,16 @@ namespace kernel::gr { } } if constexpr (D == Dim::_2D || D == Dim::_3D) { - if (i2(p) < 1) { + if (i2(p) < 0) { if (is_axis_i2min) { + i2(p) = 0; + dx2(p) = ONE - dx2(p); ux2(p) = -ux2(p); } - } else if (i2(p) >= ni2 - 1) { + } else if (i2(p) >= ni2) { if (is_axis_i2min) { + i2(p) = ni2 - 1; + dx2(p) = ONE - dx2(p); ux2(p) = -ux2(p); } } From e69021ab474577c837dd74dff375af33ed48494b Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Tue, 3 Dec 2024 10:22:49 -0500 Subject: [PATCH 329/773] metrics: all gr metrics now have functional form of derivatives of the metric componets --- src/metrics/kerr_schild.h | 163 +++++++++++++++++++++++++++++ src/metrics/kerr_schild_0.h | 102 ++++++++++++++++++ src/metrics/qkerr_schild.h | 201 ++++++++++++++++++++++++++++++++++++ 3 files changed, 466 insertions(+) diff --git a/src/metrics/kerr_schild.h b/src/metrics/kerr_schild.h index 5a60def53..9ec6f7c98 100644 --- a/src/metrics/kerr_schild.h +++ b/src/metrics/kerr_schild.h @@ -17,6 +17,7 @@ #include "arch/kokkos_aliases.h" #include "utils/numeric.h" +#include "utils/comparators.h" #include "metrics/metric_base.h" @@ -216,6 +217,28 @@ namespace metric { return ONE / math::sqrt(ONE + z(r, theta)); } + /** + * dr derivative of lapse function + * @param x coordinate array in code units + */ + Inline auto dr_alpha(const coord_t& x) const -> real_t { + const real_t r {x[0] * dr + x1_min}; + const real_t theta {x[1] * dtheta + x2_min}; + const real_t dr_Sigma {TWO * r * dr}; + + return - (dr * Sigma(r, theta) - r * dr_Sigma) * CUBE(alpha(x)) / SQR(Sigma(r, theta)); + } + + /** + * dtheta derivative of lapse function + * @param x coordinate array in code units + */ + Inline auto dt_alpha(const coord_t& x) const -> real_t { + const real_t r {x[0] * dr + x1_min}; + const real_t theta {x[1] * dtheta + x2_min}; + return CUBE(alpha(x)) * r * dt_Sigma(theta) / SQR(Sigma(r, theta)); + } + /** * radial component of shift vector * @param x coordinate array in code units @@ -225,6 +248,146 @@ namespace metric { return dr_inv * z_ / (ONE + z_); } + /** + * dr derivative of radial component of shift vector + * @param x coordinate array in code units + */ + Inline auto dr_beta1(const coord_t& x) const -> real_t { + const real_t r {x[0] * dr + x1_min}; + const real_t theta {x[1] * dtheta + x2_min}; + const real_t dr_Sigma {TWO * r * dr}; + + return dr_inv * TWO * (dr * Sigma(r, theta) - r * dr_Sigma) / SQR(Sigma(r, theta) + TWO * r); + } + + /** + * dtheta derivative of radial component of shift vector + * @param x coordinate array in code units + */ + Inline auto dt_beta1(const coord_t& x) const -> real_t { + const real_t r {x[0] * dr + x1_min}; + const real_t theta {x[1] * dtheta + x2_min}; + return - dr_inv * TWO * r * dt_Sigma(theta) / SQR(Sigma(r, theta) * (ONE + z(r, theta))); + } + + /** + * dr derivative of h^11 + * @param x coordinate array in code units + */ + Inline auto dr_h11(const coord_t& x) const -> real_t { + const real_t r {x[0] * dr + x1_min}; + const real_t theta {x[1] * dtheta + x2_min}; + const real_t dr_Sigma {TWO * r * dr}; + const real_t dr_Delta {TWO * dr * (r - ONE)}; + const real_t dr_A {FOUR * r * dr * (SQR(r) + SQR(a)) - SQR(a) * SQR(math::sin(theta)) * dr_Delta}; + + return (Sigma(r, theta) * (Sigma(r, theta) + TWO * r) * dr_A + - TWO * A(r, theta) * (r * dr_Sigma + Sigma(r, theta) * (dr_Sigma + dr))) + / (SQR(Sigma(r, theta) * (Sigma(r, theta) + TWO * r))) * SQR(dr_inv); + } + + /** + * dr derivative of h^22 + * @param x coordinate array in code units + */ + Inline auto dr_h22(const coord_t& x) const -> real_t { + const real_t r {x[0] * dr + x1_min}; + const real_t theta {x[1] * dtheta + x2_min}; + const real_t dr_Sigma {TWO * r * dr}; + + return - dr_Sigma / SQR(Sigma(r, theta)) * SQR(dtheta_inv); + } + + /** + * dr derivative of h^33 + * @param x coordinate array in code units + */ + Inline auto dr_h33(const coord_t& x) const -> real_t { + const real_t r {x[0] * dr + x1_min}; + const real_t theta {x[1] * dtheta + x2_min}; + const real_t dr_Sigma {TWO * r * dr}; + + return - dr_Sigma / SQR(Sigma(r, theta)) / SQR(math::sin(theta)); + } + + /** + * dr derivative of h^13 + * @param x coordinate array in code units + */ + Inline auto dr_h13(const coord_t& x) const -> real_t { + const real_t r {x[0] * dr + x1_min}; + const real_t theta {x[1] * dtheta + x2_min}; + const real_t dr_Sigma {TWO * r * dr}; + + return - a * dr_Sigma / SQR(Sigma(r, theta)) * dr_inv; + } + + /** + * dtheta derivative of Sigma + * @param x coordinate array in code units + */ + Inline auto dt_Sigma(const real_t& theta) const -> real_t { + const real_t dt_Sigma {- TWO * SQR(a) * math::sin(theta) * math::cos(theta) * dtheta}; + if (cmp::AlmostZero(dt_Sigma)) + return ZERO; + else + return dt_Sigma; + } + + /** + * dtheta derivative of A + * @param x coordinate array in code units + */ + Inline auto dt_A(const real_t& r, const real_t& theta) const -> real_t { + const real_t dt_A {- TWO * SQR(a) * math::sin(theta) * math::cos(theta) * Delta(r) * dtheta}; + if (cmp::AlmostZero(dt_A)) + return ZERO; + else + return dt_A; + } + + /** + * dtheta derivative of h^11 + * @param x coordinate array in code units + */ + Inline auto dt_h11(const coord_t& x) const -> real_t { + const real_t r {x[0] * dr + x1_min}; + const real_t theta {x[1] * dtheta + x2_min}; + return (Sigma(r, theta) * (Sigma(r, theta) + TWO * r) * dt_A(r, theta) + - TWO * A(r, theta) * dt_Sigma(theta) * (r + Sigma(r, theta))) + / (SQR(Sigma(r, theta) * (Sigma(r, theta) + TWO * r))) * SQR(dr_inv); + } + + /** + * dtheta derivative of h^22 + * @param x coordinate array in code units + */ + Inline auto dt_h22(const coord_t& x) const -> real_t { + const real_t r {x[0] * dr + x1_min}; + const real_t theta {x[1] * dtheta + x2_min}; + return - dt_Sigma(theta) / SQR(Sigma(r, theta)) * SQR(dtheta_inv); + } + + /** + * dtheta derivative of h^33 + * @param x coordinate array in code units + */ + Inline auto dt_h33(const coord_t& x) const -> real_t { + const real_t r {x[0] * dr + x1_min}; + const real_t theta {x[1] * dtheta + x2_min}; + return - TWO * dtheta * math::cos(theta) * (Sigma(r, theta) - SQR(a) * SQR(math::sin(theta))) / CUBE(math::sin(theta)) / SQR(Sigma(r, theta)); + } + + /** + * dtheta derivative of h^13 + * @param x coordinate array in code units + */ + Inline auto dt_h13(const coord_t& x) const -> real_t { + const real_t r {x[0] * dr + x1_min}; + const real_t theta {x[1] * dtheta + x2_min}; + return - a * dt_Sigma(theta) / SQR(Sigma(r, theta)) * dr_inv; + } + /** * sqrt(det(h_ij)) * @param x coordinate array in code units diff --git a/src/metrics/kerr_schild_0.h b/src/metrics/kerr_schild_0.h index 31080ed4c..baea9b4c1 100644 --- a/src/metrics/kerr_schild_0.h +++ b/src/metrics/kerr_schild_0.h @@ -171,6 +171,22 @@ namespace metric { return ONE; } + /** + * dr derivative of lapse function + * @param x coordinate array in code units + */ + Inline auto dr_alpha(const coord_t& x) const -> real_t { + return ZERO; + } + + /** + * dtheta derivative of lapse function + * @param x coordinate array in code units + */ + Inline auto dt_alpha(const coord_t& x) const -> real_t { + return ZERO; + } + /** * radial component of shift vector * @param x coordinate array in code units @@ -179,6 +195,92 @@ namespace metric { return ZERO; } + /** + * dr derivative of radial component of shift vector + * @param x coordinate array in code units + */ + Inline auto dr_beta1(const coord_t& x) const -> real_t { + return ZERO; + } + + /** + * dtheta derivative of radial component of shift vector + * @param x coordinate array in code units + */ + Inline auto dt_beta1(const coord_t& x) const -> real_t { + return ZERO; + } + + /** + * dr derivative of h^11 + * @param x coordinate array in code units + */ + Inline auto dr_h11(const coord_t& x) const -> real_t { + return ZERO; + } + + /** + * dr derivative of h^22 + * @param x coordinate array in code units + */ + Inline auto dr_h22(const coord_t& x) const -> real_t { + const real_t r {x[0] * dr + x1_min}; + const real_t theta {x[1] * dtheta + x2_min}; + return - TWO / CUBE(r) * SQR(dtheta_inv) * dr; + } + + /** + * dr derivative of h^33 + * @param x coordinate array in code units + */ + Inline auto dr_h33(const coord_t& x) const -> real_t { + const real_t r {x[0] * dr + x1_min}; + const real_t theta {x[1] * dtheta + x2_min}; + return - TWO / CUBE(r) / SQR(math::sin(theta)) * dr; + } + + /** + * dr derivative of h^13 + * @param x coordinate array in code units + */ + Inline auto dr_h13(const coord_t& x) const -> real_t { + return ZERO; + } + + /** + * dtheta derivative of h^11 + * @param x coordinate array in code units + */ + Inline auto dt_h11(const coord_t& x) const -> real_t { + return ZERO; + } + + /** + * dtheta derivative of h^22 + * @param x coordinate array in code units + */ + Inline auto dt_h22(const coord_t& x) const -> real_t { + return ZERO; + } + + /** + * dtheta derivative of h^33 + * @param x coordinate array in code units + */ + Inline auto dt_h33(const coord_t& x) const -> real_t { + const real_t r {x[0] * dr + x1_min}; + const real_t theta {x[1] * dtheta + x2_min}; + return - TWO * math::cos(theta) / SQR(r) / CUBE(math::sin(theta)) * dtheta; + } + + /** + * dtheta derivative of h^13 + * @param x coordinate array in code units + */ + Inline auto dt_h13(const coord_t& x) const -> real_t { + return ZERO; + } + /** * sqrt(det(h_ij)) * @param x coordinate array in code units diff --git a/src/metrics/qkerr_schild.h b/src/metrics/qkerr_schild.h index 85507c6e1..e45376a24 100644 --- a/src/metrics/qkerr_schild.h +++ b/src/metrics/qkerr_schild.h @@ -234,6 +234,33 @@ namespace metric { return ONE / math::sqrt(ONE + z(r, theta)); } + /** + * dr derivative of lapse function + * @param x coordinate array in code units + */ + Inline auto dr_alpha(const coord_t& x) const -> real_t { + const real_t r { r0 + math::exp(x[0] * dchi + chi_min) }; + const real_t theta { eta2theta(x[1] * deta + eta_min) }; + const real_t dx_r {dchi * math::exp(x[0] * dchi + chi_min)}; + const real_t dr_Sigma {TWO * r * dx_r}; + + return - (dx_r * Sigma(r, theta) - r * dr_Sigma) * CUBE(alpha(x)) / SQR(Sigma(r, theta)); + } + + /** + * dtheta derivative of lapse function + * @param x coordinate array in code units + */ + Inline auto dt_alpha(const coord_t& x) const -> real_t { + const real_t r { r0 + math::exp(x[0] * dchi + chi_min) }; + const real_t eta {x[1] * deta + eta_min }; + const real_t theta { eta2theta(eta) }; + const real_t dx_dt {deta * (ONE + TWO * h0 * constant::INV_PI_SQR * (TWO * THREE * SQR(eta) - TWO * THREE * constant::PI * eta + constant::PI_SQR)) }; + const real_t dt_Sigma {- TWO * SQR(a) * math::sin(theta) * math::cos(theta) * dx_dt}; + + return r * dt_Sigma * CUBE(alpha(x)) / SQR(Sigma(r, theta)); + } + /** * radial component of shift vector * @param x coordinate array in code units @@ -246,6 +273,167 @@ namespace metric { return math::exp(-chi) * dchi_inv * z_ / (ONE + z_); } + /** + * dr derivative of radial component of shift vector + * @param x coordinate array in code units + */ + Inline auto dr_beta1(const coord_t& x) const -> real_t { + const real_t chi { x[0] * dchi + chi_min }; + const real_t r { r0 + math::exp(chi) }; + const real_t theta { eta2theta(x[1] * deta + eta_min) }; + const real_t z_ { z(r, theta) }; + const real_t dx_r {dchi * math::exp(x[0] * dchi + chi_min)}; + const real_t dr_Sigma {TWO * r * dx_r}; + + return math::exp(-chi) * dchi_inv * TWO * (dx_r * Sigma(r, theta) - r * dr_Sigma) / SQR(Sigma(r, theta) + TWO * r) + - dchi * math::exp(-chi) * dchi_inv * z_ / (ONE + z_); + } + + /** + * dr derivative of radial component of shift vector + * @param x coordinate array in code units + */ + Inline auto dt_beta1(const coord_t& x) const -> real_t { + const real_t chi { x[0] * dchi + chi_min }; + const real_t r { r0 + math::exp(chi) }; + const real_t eta {x[1] * deta + eta_min }; + const real_t theta { eta2theta(eta) }; + return - math::exp(-chi) * dchi_inv * TWO * r * dt_Sigma(eta) / SQR(Sigma(r, theta) * (ONE + z(r, theta))); + } + + /** + * dr derivative of h^11 + * @param x coordinate array in code units + */ + Inline auto dr_h11(const coord_t& x) const -> real_t { + const real_t r { r0 + math::exp(x[0] * dchi + chi_min) }; + const real_t theta { eta2theta(x[1] * deta + eta_min) }; + + const real_t dx_r {dchi * math::exp(x[0] * dchi + chi_min)}; + const real_t dr_Sigma {TWO * r * dx_r}; + const real_t dr_Delta {TWO * dx_r * (r - ONE)}; + const real_t dr_A {FOUR * r * dx_r * (SQR(r) + SQR(a)) - SQR(a) * SQR(math::sin(theta)) * dr_Delta}; + + return (math::exp(-TWO * (x[0] * dchi + chi_min)) / SQR(dchi) + * (Sigma(r, theta) * (Sigma(r, theta) + TWO * r) * dr_A + - TWO * A(r, theta) * (r * dr_Sigma + Sigma(r, theta) * (dr_Sigma + dx_r))) + / (SQR(Sigma(r, theta) * (Sigma(r, theta) + TWO * r))) ) + -TWO * dchi * math::exp(-TWO * (x[0] * dchi + chi_min)) / SQR(dchi) * A(r, theta) / (Sigma(r, theta) * (Sigma(r, theta) + TWO * r)); + } + + /** + * dr derivative of h^22 + * @param x coordinate array in code units + */ + Inline auto dr_h22(const coord_t& x) const -> real_t { + const real_t r { r0 + math::exp(x[0] * dchi + chi_min) }; + const real_t theta { eta2theta(x[1] * deta + eta_min) }; + const real_t dx_r {dchi * math::exp(x[0] * dchi + chi_min)}; + const real_t dr_Sigma {TWO * r * dx_r}; + + return - dr_Sigma / SQR(Sigma(r, theta)) / SQR(deta); + } + + /** + * dr derivative of h^33 + * @param x coordinate array in code units + */ + Inline auto dr_h33(const coord_t& x) const -> real_t { + const real_t r { r0 + math::exp(x[0] * dchi + chi_min) }; + const real_t theta { eta2theta(x[1] * deta + eta_min) }; + const real_t dx_r {dchi * math::exp(x[0] * dchi + chi_min)}; + const real_t dr_Sigma {TWO * r * dx_r}; + + return - dr_Sigma / SQR(Sigma(r, theta)) / SQR(math::sin(theta)); + } + + /** + * dr derivative of h^13 + * @param x coordinate array in code units + */ + Inline auto dr_h13(const coord_t& x) const -> real_t { + const real_t r { r0 + math::exp(x[0] * dchi + chi_min) }; + const real_t theta { eta2theta(x[1] * deta + eta_min) }; + const real_t dx_r {dchi * math::exp(x[0] * dchi + chi_min)}; + const real_t dr_Sigma {TWO * r * dx_r}; + + return - a * dr_Sigma / SQR(Sigma(r, theta)) * (math::exp(-(x[0] * dchi + chi_min)) * dchi_inv) + - dchi * (math::exp(-(x[0] * dchi + chi_min)) * dchi_inv) * a / Sigma(r, theta); + } + + /** + * dtheta derivative of Sigma + * @param x coordinate array in code units + */ + Inline auto dt_Sigma(const real_t& eta) const -> real_t { + const real_t theta { eta2theta(eta) }; + const real_t dt_Sigma {- TWO * SQR(a) * math::sin(theta) * math::cos(theta) * dx_dt(eta)}; + if (cmp::AlmostZero(dt_Sigma)) + return ZERO; + else + return dt_Sigma; + } + + /** + * dtheta derivative of A + * @param x coordinate array in code units + */ + Inline auto dt_A(const real_t& r, const real_t& eta) const -> real_t { + const real_t theta { eta2theta(eta) }; + const real_t dt_A {- TWO * SQR(a) * math::sin(theta) * math::cos(theta) * Delta(r) * dx_dt(eta)}; + if (cmp::AlmostZero(dt_A)) + return ZERO; + else + return dt_A; + } + + /** + * dtheta derivative of h^11 + * @param x coordinate array in code units + */ + Inline auto dt_h11(const coord_t& x) const -> real_t { + const real_t r { r0 + math::exp(x[0] * dchi + chi_min) }; + const real_t eta {x[1] * deta + eta_min }; + const real_t theta { eta2theta(eta) }; + return math::exp(-TWO * (x[0] * dchi + chi_min)) / SQR(dchi) + * (Sigma(r, theta) * (Sigma(r, theta) + TWO * r) * dt_A(r, eta) + - TWO * A(r, theta) * dt_Sigma(eta) * (r + Sigma(r, theta))) + / (SQR(Sigma(r, theta) * (Sigma(r, theta) + TWO * r))); + } + + /** + * dtheta derivative of h^22 + * @param x coordinate array in code units + */ + Inline auto dt_h22(const coord_t& x) const -> real_t { + const real_t r { r0 + math::exp(x[0] * dchi + chi_min) }; + const real_t eta {x[1] * deta + eta_min }; + const real_t theta { eta2theta(eta) }; + return - dt_Sigma(eta) / SQR(Sigma(r, theta)) / SQR(deta); + } + + /** + * dtheta derivative of h^33 + * @param x coordinate array in code units + */ + Inline auto dt_h33(const coord_t& x) const -> real_t { + const real_t r { r0 + math::exp(x[0] * dchi + chi_min) }; + const real_t eta {x[1] * deta + eta_min }; + const real_t theta { eta2theta(eta) }; + return - (dt_Sigma(eta) + TWO * math::cos(theta) / math::sin(theta) * Sigma(r, theta) * dx_dt(eta)) / SQR(Sigma(r, theta) * math::sin(theta)); + } + + /** + * dtheta derivative of h^13 + * @param x coordinate array in code units + */ + Inline auto dt_h13(const coord_t& x) const -> real_t { + const real_t r { r0 + math::exp(x[0] * dchi + chi_min) }; + const real_t eta {x[1] * deta + eta_min }; + const real_t theta { eta2theta(eta) }; + return - a * dt_Sigma(eta) / SQR(Sigma(r, theta)) * (math::exp(-(x[0] * dchi + chi_min)) * dchi_inv); + } + /** * sqrt(det(h_ij)) * @param x coordinate array in code units @@ -456,6 +644,19 @@ namespace metric { } } + /** + * @brief quasi-spherical eta to spherical theta + */ + Inline auto dx_dt(const real_t& eta) const -> real_t { + if (cmp::AlmostZero(h0)) { + return deta; + } else { + return deta * (ONE + + TWO * h0 * constant::INV_PI_SQR * + (TWO * THREE * SQR(eta) - TWO * THREE * constant::PI * eta + constant::PI_SQR)); + } + } + /** * @brief spherical theta to quasi-spherical eta */ From 05b30f827f2371ae15361ee619872134ca742e1f Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Tue, 3 Dec 2024 10:24:38 -0500 Subject: [PATCH 330/773] setups/grpic/pusher: pgen and inputs for pusher tests --- setups/grpic/pusher/boris.toml | 97 +++++++++ setups/grpic/pusher/massive_gravity_3d.toml | 84 ++++++++ setups/grpic/pusher/massive_gravity_a0.toml | 93 +++++++++ .../grpic/pusher/massive_gravity_a0995.toml | 93 +++++++++ setups/grpic/pusher/pgen.hpp | 184 ++++++++++++++++++ 5 files changed, 551 insertions(+) create mode 100644 setups/grpic/pusher/boris.toml create mode 100644 setups/grpic/pusher/massive_gravity_3d.toml create mode 100644 setups/grpic/pusher/massive_gravity_a0.toml create mode 100644 setups/grpic/pusher/massive_gravity_a0995.toml create mode 100644 setups/grpic/pusher/pgen.hpp diff --git a/setups/grpic/pusher/boris.toml b/setups/grpic/pusher/boris.toml new file mode 100644 index 000000000..6483eb2c6 --- /dev/null +++ b/setups/grpic/pusher/boris.toml @@ -0,0 +1,97 @@ +[simulation] + name = "boris_a0" + engine = "grpic" + runtime = 100.0 + +[grid] + resolution = [128,128] + extent = [[0.9, 20.0]] + + [grid.metric] + metric = "qkerr_schild" + qsph_r0 = 0.0 + qsph_h = 0.0 + ks_a = 0.0 + + [grid.boundaries] + fields = [["ABSORB"]] + particles = [["ABSORB"]] + + [grid.boundaries.absorb] + ds = 0.5 + +[scales] + larmor0 = 5.0 + skindepth0 = 1e-3 + +[algorithms] + current_filters = 4 + + [algorithms.gr] + pusher_niter = 10 + pusher_eps = 1e-6 + + [algorithms.timestep] + CFL = 0.1 + + [algorithms.toggles] + deposit = false + fieldsolver = false + +[particles] + ppc0 = 1.0 + + [[particles.species]] + label = "e-" + mass = 1.0 + charge = -1.0 + maxnpart = 1e0 + + [[particles.species]] + label = "e+" + mass = 1.0 + charge = -1.0 + maxnpart = 1e1 + +[setup] + x1s = [5.77] + y1s = [1.570796] + z1s = [0.000000] + ux1s = [0.4376657824933686] + uy1s = [0.000000] + uz1s = [4.0] +# x1s = [10.0] +# y1s = [1.570796] +# z1s = [0.000000] +# ux1s = [0.0] +# uy1s = [0.000000] +# uz1s = [10.00000] + + #x2s = [7.5] + #y2s = [0.15745454545454546] + #z2s = [0.000000] + #ux2s = [0.029637] + #uy2s = [0.000000] + #uz2s = [3.75] + +[output] + format = "hdf5" + + [output.fields] + enable = true + interval_time = 1.0 + quantities = ["D", "B"] + + [output.particles] + enable = true + stride = 1 + interval_time = 0.2 + species = [] + + [output.spectra] + enable = false + +[diagnostics] + interval = 10 + colored_stdout = true + blocking_timers = true diff --git a/setups/grpic/pusher/massive_gravity_3d.toml b/setups/grpic/pusher/massive_gravity_3d.toml new file mode 100644 index 000000000..5b87554b2 --- /dev/null +++ b/setups/grpic/pusher/massive_gravity_3d.toml @@ -0,0 +1,84 @@ +[simulation] + name = "massive_3d" + engine = "grpic" + runtime = 1000.0 + +[grid] + resolution = [128, 128] + extent = [[0.1, 15.0]] + + [grid.metric] + metric = "qkerr_schild" + qsph_r0 = 0.0 + qsph_h = 0.0 + ks_a = 0.995 + + [grid.boundaries] + fields = [["ABSORB"]] + particles = [["ABSORB"]] + + [grid.boundaries.absorb] + ds = 0.5 + +[scales] + larmor0 = 2e-3 + skindepth0 = 0.1 + +[algorithms] + current_filters = 4 + + [algorithms.gr] + pusher_niter = 20 + pusher_eps = 1e-3 + + [algorithms.timestep] + CFL = 0.8 + + [algorithms.toggles] + deposit = false + fieldsolver = false + +[particles] + ppc0 = 4.0 + + [[particles.species]] + label = "e-" + mass = 1.0 + charge = 0.0 + maxnpart = 1e1 + + [[particles.species]] + label = "e+" + mass = 1.0 + charge = 0.0 + maxnpart = 1e1 + +[setup] + x1s = [10.00000] + y1s = [1.570796] + z1s = [0.000000] + ux1s = [0.2181435531189523] + uy1s = [2.89] + uz1s = [1.05769] + +[output] + format = "hdf5" + + [output.fields] + enable = true + interval_time = 5.0 + quantities = ["D", "B"] + + [output.particles] + enable = true + stride = 1 + interval_time = 0.5 + species = [] + + [output.spectra] + enable = false + +[diagnostics] + interval = 10 + colored_stdout = true + blocking_timers = true diff --git a/setups/grpic/pusher/massive_gravity_a0.toml b/setups/grpic/pusher/massive_gravity_a0.toml new file mode 100644 index 000000000..08b607d4b --- /dev/null +++ b/setups/grpic/pusher/massive_gravity_a0.toml @@ -0,0 +1,93 @@ +[simulation] + name = "massive_a0" + engine = "grpic" + runtime = 500.0 + +[grid] + resolution = [256,256] + extent = [[1.2, 15.0]] + + [grid.metric] + metric = "qkerr_schild" + qsph_r0 = 0.0 + qsph_h = 0.0 + ks_a = 0.0 + + [grid.boundaries] + fields = [["ABSORB"]] + particles = [["ABSORB"]] + + [grid.boundaries.absorb] + ds = 0.5 + +[scales] + larmor0 = 2e-3 + skindepth0 = 0.1 + +[algorithms] + current_filters = 4 + + [algorithms.gr] + pusher_niter = 10 + pusher_eps = 1e-3 + + [algorithms.timestep] + CFL = 0.8 + + [algorithms.toggles] + deposit = false + fieldsolver = false + +[particles] + ppc0 = 4.0 + + [[particles.species]] + label = "e-" + mass = 1.0 + charge = 0.0 + maxnpart = 1e1 + + [[particles.species]] + label = "e+" + mass = 1.0 + charge = 0.0 + maxnpart = 1e1 + +[setup] + # (1,2,0) from Levin&Perez-Giz (2008) + x1s = [9.85180645] + y1s = [1.570796] + z1s = [0.5235987755982988] + ux1s = [0.24159816] + uy1s = [3.535534] + uz1s = [0.000000] + + # (4,1,1) from Levin&Perez-Giz (2008) + x2s = [68.600387] + y2s = [1.570796] + z2s = [0.000000] + ux2s = [0.029637] + uy2s = [0.000000] + uz2s = [3.900000] + +[output] + format = "hdf5" + + [output.fields] + enable = true + interval_time = 1.0 + quantities = ["D", "B"] + + [output.particles] + enable = true + stride = 1 + interval_time = 1.0 + species = [] + + [output.spectra] + enable = false + +[diagnostics] + interval = 10 + colored_stdout = true + blocking_timers = true diff --git a/setups/grpic/pusher/massive_gravity_a0995.toml b/setups/grpic/pusher/massive_gravity_a0995.toml new file mode 100644 index 000000000..b04538e10 --- /dev/null +++ b/setups/grpic/pusher/massive_gravity_a0995.toml @@ -0,0 +1,93 @@ +[simulation] + name = "massive_a0995" + engine = "grpic" + runtime = 2000.0 + +[grid] + resolution = [512, 512] + extent = [[0.9, 15.0]] + + [grid.metric] + metric = "kerr_schild" + qsph_r0 = 0.0 + qsph_h = 0.0 + ks_a = 0.0 + + [grid.boundaries] + fields = [["ABSORB"]] + particles = [["ABSORB"]] + + [grid.boundaries.absorb] + ds = 0.5 + +[scales] + larmor0 = 2e-3 + skindepth0 = 0.1 + +[algorithms] + current_filters = 4 + + [algorithms.gr] + pusher_niter = 10 + pusher_eps = 1e-10 + + [algorithms.timestep] + CFL = 6.0 + + [algorithms.toggles] + deposit = false + fieldsolver = false + +[particles] + ppc0 = 4.0 + + [[particles.species]] + label = "e-" + mass = 1.0 + charge = 0.0 + maxnpart = 1e1 + + [[particles.species]] + label = "e+" + mass = 1.0 + charge = 0.0 + maxnpart = 1e1 + +[setup] + # (2,3,1) from Levin&Perez-Giz (2008) + x1s = [10.343515586064923] + y1s = [1.570796] + z1s = [0.000000] + ux1s = [0.19483849893499136] + uy1s = [0.000000] + uz1s = [2.000000] + + # (~1000, 3, ~671) from Levin&Perez-Giz (2008) + x2s = [10.64975354] + y2s = [1.570796] + z2s = [0.000000] + ux2s = [0.18914503] + uy2s = [0.000000] + uz2s = [2.000000] + +[output] + format = "hdf5" + + [output.fields] + enable = true + interval_time = 5.0 + quantities = ["D", "B"] + + [output.particles] + enable = true + stride = 1 + interval_time = 2.0 + species = [] + + [output.spectra] + enable = false + +[diagnostics] + interval = 10 + colored_stdout = true + blocking_timers = true diff --git a/setups/grpic/pusher/pgen.hpp b/setups/grpic/pusher/pgen.hpp new file mode 100644 index 000000000..d6a29a185 --- /dev/null +++ b/setups/grpic/pusher/pgen.hpp @@ -0,0 +1,184 @@ +#ifndef PROBLEM_GENERATOR_H +#define PROBLEM_GENERATOR_H + +#include "enums.h" +#include "global.h" + +#include "arch/kokkos_aliases.h" +#include "arch/traits.h" +#include "utils/comparators.h" +#include "utils/formatting.h" +#include "utils/log.h" +#include "utils/numeric.h" + +#include "archetypes/problem_generator.h" +#include "framework/domain/metadomain.h" +#include "framework/domain/domain.h" +#include "archetypes/energy_dist.h" +#include "archetypes/particle_injector.h" + +#include + +namespace user { + using namespace ntt; + + template + struct InitFields { + InitFields(M metric_) : metric { metric_ } {} + + Inline auto A_3(const coord_t& x_Cd) const -> real_t { + // return HALF * (metric.template h_<3, 3>(x_Cd) ); + // + TWO * metric.spin() * metric.template h_<1, 3>(x_Cd) * metric.beta1(x_Cd) + // ); + coord_t x_Ph { ZERO }; + metric.template convert(x_Cd, x_Ph); + return HALF * SQR(x_Ph[0]) * SQR(math::sin(x_Ph[1])); + } + + Inline auto A_1(const coord_t& x_Cd) const -> real_t { + return HALF * (metric.template h_<1, 3>(x_Cd) + + TWO * metric.spin() * metric.template h_<1, 1>(x_Cd) * metric.beta1(x_Cd) + ); + } + + Inline auto A_0(const coord_t& x_Cd) const -> real_t { + real_t g_00 { -metric.alpha(x_Cd) * metric.alpha(x_Cd) + + metric.template h_<1, 1>(x_Cd) * metric.beta1(x_Cd) * metric.beta1(x_Cd) + }; + return HALF * (metric.template h_<1, 3>(x_Cd) * metric.beta1(x_Cd) + + TWO * metric.spin() * g_00); + } + + Inline auto bx1(const coord_t& x_Ph) const -> real_t { + coord_t xi {ZERO}, x0m { ZERO }, x0p { ZERO }; + metric.template convert(x_Ph, xi); + + x0m[0] = xi[0]; + x0m[1] = xi[1] - HALF; + x0p[0] = xi[0]; + x0p[1] = xi[1] + HALF; + + real_t inv_sqrt_detH_ijP { ONE / metric.sqrt_det_h({ xi[0], xi[1] }) }; + + if (cmp::AlmostZero(x_Ph[1])) + return ONE; + else + return (A_3(x0p) - A_3(x0m)) * inv_sqrt_detH_ijP; + // return ZERO; + } + + Inline auto bx2(const coord_t& x_Ph) const -> real_t { + coord_t xi {ZERO}, x0m { ZERO }, x0p { ZERO }; + metric.template convert(x_Ph, xi); + + x0m[0] = xi[0] + HALF - HALF; + x0m[1] = xi[1]; + x0p[0] = xi[0] + HALF + HALF; + x0p[1] = xi[1]; + + real_t inv_sqrt_detH_ijP { ONE / metric.sqrt_det_h({ xi[0], xi[1] }) }; + if (cmp::AlmostZero(x_Ph[1])) + return ZERO; + else + return -(A_3(x0p) - A_3(x0m)) * inv_sqrt_detH_ijP; + // return ZERO; + } + + Inline auto bx3(const coord_t& x_Ph) const -> real_t { + // coord_t xi {ZERO}, x0m { ZERO }, x0p { ZERO }; + // metric.template convert(x_Ph, xi); + + // x0m[0] = xi[0] + HALF - HALF; + // x0m[1] = xi[1]; + // x0p[0] = xi[0] + HALF + HALF; + // x0p[1] = xi[1]; + + // real_t inv_sqrt_detH_ijP { ONE / metric.sqrt_det_h({ xi[0], xi[1] }) }; + // return -(A_1(x0p) - A_1(x0m)) * inv_sqrt_detH_ijP; + return ZERO; + } + + Inline auto dx1(const coord_t& x_Ph) const -> real_t { + return ZERO; + } + + Inline auto dx2(const coord_t& x_Ph) const -> real_t { + return ZERO; + } + + Inline auto dx3(const coord_t& x_Ph) const -> real_t { + return ZERO; + } + + private: + const M metric; + }; + + template + struct PGen : public arch::ProblemGenerator { + // compatibility traits for the problem generator + static constexpr auto engines { traits::compatible_with::value }; + static constexpr auto metrics { + traits::compatible_with::value + }; + static constexpr auto dimensions { traits::compatible_with::value }; + + // for easy access to variables in the child class + using arch::ProblemGenerator::D; + using arch::ProblemGenerator::C; + using arch::ProblemGenerator::params; + + InitFields init_flds; + const Metadomain& global_domain; + inline PGen(const SimulationParams& p, const Metadomain& m) + : arch::ProblemGenerator { p } + , global_domain { m } + , init_flds { m.mesh().metric } {} + + inline void InitPrtls(Domain& local_domain) { + const auto empty = std::vector {}; + const auto x1s = params.template get>("setup.x1s", empty); + const auto y1s = params.template get>("setup.y1s", empty); + const auto z1s = params.template get>("setup.z1s", empty); + const auto ux1s = params.template get>("setup.ux1s", + empty); + const auto uy1s = params.template get>("setup.uy1s", + empty); + const auto uz1s = params.template get>("setup.uz1s", + empty); + + const auto x2s = params.template get>("setup.x2s", empty); + const auto y2s = params.template get>("setup.y2s", empty); + const auto z2s = params.template get>("setup.z2s", empty); + const auto ux2s = params.template get>("setup.ux2s", + empty); + const auto uy2s = params.template get>("setup.uy2s", + empty); + const auto uz2s = params.template get>("setup.uz2s", + empty); + const std::map> data_1 { + { "x1", x1s}, + { "x2", y1s}, + { "phi", z1s}, + {"ux1", ux1s}, + {"ux2", uy1s}, + {"ux3", uz1s} + }; + const std::map> data_2 { + { "x1", x2s}, + { "x2", y2s}, + { "phi", z2s}, + {"ux1", ux2s}, + {"ux2", uy2s}, + {"ux3", uz2s} + }; + + arch::InjectGlobally(global_domain, local_domain, (arch::spidx_t)1, data_1); + arch::InjectGlobally(global_domain, local_domain, (arch::spidx_t)2, data_2); + } + // inline PGen() {} + }; + +} // namespace user + +#endif From 048dd573aae7662b6d77f3e821dbf7d9e7f347d7 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Tue, 3 Dec 2024 12:28:14 -0500 Subject: [PATCH 331/773] engines/grpic: added timestep correction for gr pusher --- src/engines/grpic.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index 745503793..785e6df97 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -1002,9 +1002,9 @@ namespace ntt { ? species.charge() / species.mass() : ZERO; // coeff = q / m (dt / 2) omegaB0 - const auto coeff = q_ovr_m * HALF * dt * - m_params.template get("scales.omegaB0"); - + const auto coeff = q_ovr_m * HALF * dt * m_params.template get( + "algorithms.timestep.correction") * + m_params.template get("scales.omegaB0"); // clang-format off if (species.pusher() == PrtlPusher::PHOTON) { From a86182c766af5b7e19189ec7b1c9aba63793958a Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Wed, 4 Dec 2024 14:58:18 -0500 Subject: [PATCH 332/773] erased stretching of initial field --- src/archetypes/field_setter.h | 52 ++++------------------------------- src/kernels/fields_bcs.hpp | 16 ++--------- 2 files changed, 8 insertions(+), 60 deletions(-) diff --git a/src/archetypes/field_setter.h b/src/archetypes/field_setter.h index 171e9f8a8..5c5c4dbe4 100644 --- a/src/archetypes/field_setter.h +++ b/src/archetypes/field_setter.h @@ -170,32 +170,13 @@ namespace arch { const real_t x2_H { metric.template convert<2, Crd::Cd, Crd::Ph>( i2_ + HALF) }; { // dx1 - vec_t d_PU { finit.dx1({ x1_H, x2_0 }), - finit.dx2({ x1_H, x2_0 }), - finit.dx3({ x1_H, x2_0 }) }; - vec_t d_U { ZERO }; - metric.template transform({ i1_ + HALF, i2_ }, - d_PU, - d_U); - EM(i1, i2, em::dx1) = d_U[0]; + EM(i1, i2, em::dx1) = finit.dx1({ x1_H, x2_0 }); } { // dx2 - vec_t d_PU { finit.dx1({ x1_0, x2_H }), - finit.dx2({ x1_0, x2_H }), - finit.dx3({ x1_0, x2_H }) }; - vec_t d_U { ZERO }; - metric.template transform({ i1_, i2_ + HALF }, - d_PU, - d_U); - EM(i1, i2, em::dx2) = d_U[1]; + EM(i1, i2, em::dx2) = finit.dx2({ x1_0, x2_H }); } { // dx3 - vec_t d_PU { finit.dx1({ x1_0, x2_0 }), - finit.dx2({ x1_0, x2_0 }), - finit.dx3({ x1_0, x2_0 }) }; - vec_t d_U { ZERO }; - metric.template transform({ i1_, i2_ }, d_PU, d_U); - EM(i1, i2, em::dx3) = d_U[2]; + EM(i1, i2, em::dx3) = finit.dx3({ x1_0, x2_0 }); } } if constexpr (defines_bx1 && defines_bx2 && defines_bx3) { @@ -206,34 +187,13 @@ namespace arch { const real_t x2_H { metric.template convert<2, Crd::Cd, Crd::Ph>( i2_ + HALF) }; { // bx1 - vec_t b_PU { finit.bx1({ x1_0, x2_H }), - finit.bx2({ x1_0, x2_H }), - finit.bx3({ x1_0, x2_H }) }; - vec_t b_U { ZERO }; - metric.template transform({ i1_, i2_ + HALF }, - b_PU, - b_U); - EM(i1, i2, em::bx1) = b_U[0]; + EM(i1, i2, em::bx1) = finit.bx1({ x1_0, x2_H }); } { // bx2 - vec_t b_PU { finit.bx1({ x1_H, x2_0 }), - finit.bx2({ x1_H, x2_0 }), - finit.bx3({ x1_H, x2_0 }) }; - vec_t b_U { ZERO }; - metric.template transform({ i1_ + HALF, i2_ }, - b_PU, - b_U); - EM(i1, i2, em::bx2) = b_U[1]; + EM(i1, i2, em::bx2) = finit.bx2({ x1_H, x2_0 }); } { // bx3 - vec_t b_PU { finit.bx1({ x1_H, x2_H }), - finit.bx2({ x1_H, x2_H }), - finit.bx3({ x1_H, x2_H }) }; - vec_t b_U { ZERO }; - metric.template transform({ i1_ + HALF, i2_ + HALF }, - b_PU, - b_U); - EM(i1, i2, em::bx3) = b_U[2]; + EM(i1, i2, em::bx3) = finit.bx3({ x1_H, x2_H }); } } } else { diff --git a/src/kernels/fields_bcs.hpp b/src/kernels/fields_bcs.hpp index 9d9db5488..73b169a71 100644 --- a/src/kernels/fields_bcs.hpp +++ b/src/kernels/fields_bcs.hpp @@ -998,26 +998,14 @@ namespace kernel::bc { const real_t x1_0 { metric.template convert<1, Crd::Cd, Crd::Ph>(i1_) }; const real_t x2_H { metric.template convert<2, Crd::Cd, Crd::Ph>( i2_ + HALF) }; - - vec_t b_PU { finit.bx1({ x1_0, x2_H }), - finit.bx2({ x1_0, x2_H }), - finit.bx3({ x1_0, x2_H }) }; - vec_t b_U { ZERO }; - metric.template transform({ i1_, i2_ + HALF }, b_PU, b_U); Fld(i1, i2, comp) += (ONE - math::tanh(dx / (INV_4 * dx_abs))) * - b_U[0]; + finit.bx1({ x1_0, x2_H }); } else if (comp == em::bx2) { const real_t x1_H { metric.template convert<1, Crd::Cd, Crd::Ph>( i1_ + HALF) }; const real_t x2_0 { metric.template convert<2, Crd::Cd, Crd::Ph>(i2_) }; - - vec_t b_PU { finit.bx1({ x1_H, x2_0 }), - finit.bx2({ x1_H, x2_0 }), - finit.bx3({ x1_H, x2_0 }) }; - vec_t b_U { ZERO }; - metric.template transform({ i1_ + HALF, i2_ }, b_PU, b_U); Fld(i1, i2, comp) += (ONE - math::tanh(dx / (INV_4 * dx_abs))) * - b_U[1]; + finit.bx2({ x1_H, x2_0 }); } } } else { From c1ed57712790dbfa5a08deb94b250f550d433787 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Wed, 4 Dec 2024 18:06:57 -0500 Subject: [PATCH 333/773] engines/grpic: updated routines for current (cur --> cur0) and added BC for currents --- src/engines/grpic.hpp | 74 +++++++++++++++++++++++++++++++++---------- 1 file changed, 57 insertions(+), 17 deletions(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index 785e6df97..1bab9bc39 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -355,7 +355,7 @@ namespace ntt { */ if (deposit_enabled) { timers.start("CurrentDeposit"); - Kokkos::deep_copy(dom.fields.cur, ZERO); + Kokkos::deep_copy(dom.fields.cur0, ZERO); CurrentsDeposit(dom); timers.stop("CurrentDeposit"); @@ -612,6 +612,50 @@ namespace ntt { } } + void CurrentsBoundaryConditions(domain_t& domain) { + /** + * absorbing boundaries + */ + const auto ds = m_params.template get( + "grid.boundaries.absorb.ds"); + const auto dim = in::x1; + real_t xg_min, xg_max, xg_edge; + xg_max = m_metadomain.mesh().extent(dim).second; + xg_min = xg_max - ds; + xg_edge = xg_max; + + boundaries_t box; + boundaries_t incl_ghosts; + for (unsigned short d { 0 }; d < M::Dim; ++d) { + if (d == static_cast(dim)) { + box.push_back({ xg_min, xg_max }); + incl_ghosts.push_back({ false, true }); + } else { + box.push_back(Range::All); + incl_ghosts.push_back({ true, true }); + } + } + if (not domain.mesh.Intersects(box)) { + return; + } + const auto intersect_range = domain.mesh.ExtentToRange(box, incl_ghosts); + tuple_t range_min { 0 }; + tuple_t range_max { 0 }; + + for (unsigned short d { 0 }; d < M::Dim; ++d) { + range_min[d] = intersect_range[d].first; + range_max[d] = intersect_range[d].second; + } + Kokkos::parallel_for( + "AbsorbCurrent", + CreateRangePolicy(range_min, range_max), + kernel::AbsorbCurrentGR_kernel(domain.fields.cur0, + domain.mesh.metric, + xg_edge, + ds, + tags)); + } + void OpenFieldsIn(dir::direction_t direction, domain_t& domain, BCTags tags, @@ -868,8 +912,8 @@ namespace ntt { const auto coeff = -dt * q0 * n0 / B0; // auto range = range_with_axis_BCs(domain); auto range = CreateRangePolicy( - { domain.mesh.i_min(in::x1), domain.mesh.i_min(in::x2) + 1}, - { domain.mesh.i_max(in::x1), domain.mesh.i_max(in::x2)}); + { domain.mesh.i_min(in::x1), domain.mesh.i_min(in::x2)}, + { domain.mesh.i_max(in::x1), domain.mesh.i_max(in::x2) + 1}); const auto ni2 = domain.mesh.n_active(in::x2); if (g == gr_ampere::aux) { @@ -916,7 +960,7 @@ namespace ntt { void CurrentsDeposit(domain_t& domain) { auto scatter_cur = Kokkos::Experimental::create_scatter_view( - domain.fields.cur); + domain.fields.cur0); for (auto& species : domain.species) { logger::Checkpoint( fmt::format("Launching currents deposit kernel for %d [%s] : %lu %f", @@ -954,31 +998,27 @@ namespace ntt { (real_t)(species.charge()), dt)); } - Kokkos::Experimental::contribute(domain.fields.cur, scatter_cur); + Kokkos::Experimental::contribute(domain.fields.cur0, scatter_cur); } void CurrentsFilter(domain_t& domain) { logger::Checkpoint("Launching currents filtering kernels", HERE); - auto range = range_with_axis_BCs(domain); + auto range = CreateRangePolicy( + { domain.mesh.i_min(in::x1), domain.mesh.i_min(in::x2)}, + { domain.mesh.i_max(in::x1), domain.mesh.i_max(in::x2) + 1}); const auto nfilter = m_params.template get( "algorithms.current_filters"); tuple_t size; - if constexpr (M::Dim == Dim::_1D || M::Dim == Dim::_2D || M::Dim == Dim::_3D) { - size[0] = domain.mesh.n_active(in::x1); - } - if constexpr (M::Dim == Dim::_2D || M::Dim == Dim::_3D) { - size[1] = domain.mesh.n_active(in::x2); - } - if constexpr (M::Dim == Dim::_3D) { - size[2] = domain.mesh.n_active(in::x3); - } + size[0] = domain.mesh.n_active(in::x1); + size[1] = domain.mesh.n_active(in::x2); + // !TODO: this needs to be done more efficiently for (unsigned short i = 0; i < nfilter; ++i) { - Kokkos::deep_copy(domain.fields.buff, domain.fields.cur); + Kokkos::deep_copy(domain.fields.buff, domain.fields.cur0); Kokkos::parallel_for("CurrentsFilter", range, kernel::DigitalFilter_kernel( - domain.fields.cur, + domain.fields.cur0, domain.fields.buff, size, domain.mesh.flds_bc())); From 062a8b8ca3d1f165ab4da16f6a22ab05e0e820d6 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Wed, 4 Dec 2024 18:25:27 -0500 Subject: [PATCH 334/773] BC for currents --- src/engines/grpic.hpp | 3 +-- src/kernels/fields_bcs.hpp | 43 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 2 deletions(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index 1bab9bc39..271017917 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -652,8 +652,7 @@ namespace ntt { kernel::AbsorbCurrentGR_kernel(domain.fields.cur0, domain.mesh.metric, xg_edge, - ds, - tags)); + ds)); } void OpenFieldsIn(dir::direction_t direction, diff --git a/src/kernels/fields_bcs.hpp b/src/kernels/fields_bcs.hpp index 73b169a71..3a949671a 100644 --- a/src/kernels/fields_bcs.hpp +++ b/src/kernels/fields_bcs.hpp @@ -1016,6 +1016,49 @@ namespace kernel::bc { } }; + template + struct AbsorbCurrentGR_kernel { + static_assert(M::is_metric, "M must be a metric class"); + static_assert(i <= static_cast(M::Dim), + "Invalid component index"); + + ndfield_t J; + const M metric; + const real_t xg_edge; + const real_t dx_abs; + const BCTags tags; + + AbsorbCurrentGR_kernel(ndfield_t J, + const M& metric, + real_t xg_edge, + real_t dx_abs, + BCTags tags) + : J { J } + , metric { metric } + , xg_edge { xg_edge } + , dx_abs { dx_abs } + , tags { tags } {} + + Inline void operator()(index_t i1, index_t i2) const { + if constexpr (M::Dim == Dim::_2D) { + const auto i1_ = COORD(i1); + const auto i2_ = COORD(i2); + coord_t x_Cd { ZERO }; + x_Cd[0] = i1_; + x_Cd[1] = i2_; + const auto dx = math::abs( + metric.template convert(x_Cd[i - 1]) - xg_edge); + J(i1, i2) *= math::tanh(dx / (INV_4 * dx_abs)); + + } else { + raise::KernelError( + HERE, + "AbsorbFields_kernel: 2D implementation called for D != 2"); + } + } + }; + } // namespace kernel::bc +>>>>>>> 794beaab (BC for currents) #endif // KERNELS_FIELDS_BCS_HPP From ca04d9686e965b1c452b6d759ca51a55ec82e700 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Fri, 6 Dec 2024 11:22:07 -0500 Subject: [PATCH 335/773] engines/grpic: discard first step if fieldsolver = false --- src/engines/grpic.hpp | 292 ++++++++++++++++++++++-------------------- 1 file changed, 151 insertions(+), 141 deletions(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index 271017917..74ae4049e 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -101,164 +101,174 @@ namespace ntt { "algorithms.toggles.deposit"); const auto sort_interval = m_params.template get( "particles.sort_interval"); - + if (step == 0) { - // communicate fields and apply BCs on the first timestep - /** - * Initially: em0::B -- - * em0::D -- - * em::B at -1/2 - * em::D at -1/2 - * - * cur0::J -- - * cur::J -- - * - * aux::E -- - * aux::H -- - * - * x_prtl at -1/2 - * u_prtl at -1/2 - */ + if (fieldsolver_enabled) { + // communicate fields and apply BCs on the first timestep + /** + * Initially: em0::B -- + * em0::D -- + * em::B at -1/2 + * em::D at -1/2 + * + * cur0::J -- + * cur::J -- + * + * aux::E -- + * aux::H -- + * + * x_prtl at -1/2 + * u_prtl at -1/2 + */ - /** - * em0::D, em::D, em0::B, em::B <- boundary conditions - */ - m_metadomain.CommunicateFields(dom, Comm::B | Comm::B0 | Comm::D | Comm::D0); - FieldBoundaries(dom, BC::B | BC::E, gr_bc::main); + /** + * em0::D, em::D, em0::B, em::B <- boundary conditions + */ + m_metadomain.CommunicateFields(dom, Comm::B | Comm::B0 | Comm::D | Comm::D0); + FieldBoundaries(dom, BC::B | BC::E, gr_bc::main); - /** - * em0::B <- em::B - * em0::D <- em::D - * - * Now: em0::B & em0::D at -1/2 - */ - CopyFields(dom); + /** + * em0::B <- em::B + * em0::D <- em::D + * + * Now: em0::B & em0::D at -1/2 + */ + CopyFields(dom); - /** - * aux::E <- alpha * em::D + beta x em0::B - * aux::H <- alpha * em::B0 - beta x em::D - * - * Now: aux::E & aux::H at -1/2 - */ - ComputeAuxE(dom, gr_getE::D_B0); - ComputeAuxH(dom, gr_getH::D_B0); + /** + * aux::E <- alpha * em::D + beta x em0::B + * aux::H <- alpha * em::B0 - beta x em::D + * + * Now: aux::E & aux::H at -1/2 + */ + ComputeAuxE(dom, gr_getE::D_B0); + ComputeAuxH(dom, gr_getH::D_B0); - /** - * aux::E, aux::H <- boundary conditions - */ - FieldBoundaries(dom, BC::B | BC::E, gr_bc::aux); + /** + * aux::E, aux::H <- boundary conditions + */ + FieldBoundaries(dom, BC::B | BC::E, gr_bc::aux); - /** - * em0::B <- (em0::B) <- -curl aux::E - * - * Now: em0::B at 0 - */ - Faraday(dom, gr_faraday::aux, HALF); + /** + * em0::B <- (em0::B) <- -curl aux::E + * + * Now: em0::B at 0 + */ + Faraday(dom, gr_faraday::aux, HALF); - /** - * em0::B, em::B <- boundary conditions - */ - m_metadomain.CommunicateFields(dom, Comm::B | Comm::B0); - FieldBoundaries(dom, BC::B, gr_bc::main); + /** + * em0::B, em::B <- boundary conditions + */ + m_metadomain.CommunicateFields(dom, Comm::B | Comm::B0); + FieldBoundaries(dom, BC::B, gr_bc::main); - /** - * em::D <- (em0::D) <- curl aux::H - * - * Now: em::D at 0 - */ - Ampere(dom, gr_ampere::init, HALF); + /** + * em::D <- (em0::D) <- curl aux::H + * + * Now: em::D at 0 + */ + Ampere(dom, gr_ampere::init, HALF); - /** - * em0::D, em::D <- boundary conditions - */ - m_metadomain.CommunicateFields(dom, Comm::D | Comm::D0); - FieldBoundaries(dom, BC::E, gr_bc::main); + /** + * em0::D, em::D <- boundary conditions + */ + m_metadomain.CommunicateFields(dom, Comm::D | Comm::D0); + FieldBoundaries(dom, BC::E, gr_bc::main); - /** - * aux::E <- alpha * em::D + beta x em0::B - * aux::H <- alpha * em0::B - beta x em::D - * - * Now: aux::E & aux::H at 0 - */ - ComputeAuxE(dom, gr_getE::D_B0); - ComputeAuxH(dom, gr_getH::D_B0); + /** + * aux::E <- alpha * em::D + beta x em0::B + * aux::H <- alpha * em0::B - beta x em::D + * + * Now: aux::E & aux::H at 0 + */ + ComputeAuxE(dom, gr_getE::D_B0); + ComputeAuxH(dom, gr_getH::D_B0); - /** - * aux::E, aux::H <- boundary conditions - */ - FieldBoundaries(dom, BC::B | BC::E, gr_bc::aux); + /** + * aux::E, aux::H <- boundary conditions + */ + FieldBoundaries(dom, BC::B | BC::E, gr_bc::aux); - // !ADD: GR -- particles? + // !ADD: GR -- particles? - /** - * em0::B <- (em::B) <- -curl aux::E - * - * Now: em0::B at 1/2 - */ - Faraday(dom, gr_faraday::main, ONE); - /** - * em0::B, em::B <- boundary conditions - */ - m_metadomain.CommunicateFields(dom, Comm::B | Comm::B0); - FieldBoundaries(dom, BC::B, gr_bc::main); + /** + * em0::B <- (em::B) <- -curl aux::E + * + * Now: em0::B at 1/2 + */ + Faraday(dom, gr_faraday::main, ONE); + /** + * em0::B, em::B <- boundary conditions + */ + m_metadomain.CommunicateFields(dom, Comm::B | Comm::B0); + FieldBoundaries(dom, BC::B, gr_bc::main); - /** - * em0::D <- (em0::D) <- curl aux::H - * - * Now: em0::D at 1/2 - */ - Ampere(dom, gr_ampere::aux, ONE); - /** - * em0::D, em::D <- boundary conditions - */ - m_metadomain.CommunicateFields(dom, Comm::D | Comm::D0); - FieldBoundaries(dom, BC::E, gr_bc::main); + /** + * em0::D <- (em0::D) <- curl aux::H + * + * Now: em0::D at 1/2 + */ + Ampere(dom, gr_ampere::aux, ONE); + /** + * em0::D, em::D <- boundary conditions + */ + m_metadomain.CommunicateFields(dom, Comm::D | Comm::D0); + FieldBoundaries(dom, BC::E, gr_bc::main); - /** - * aux::H <- alpha * em0::B - beta x em0::D - * - * Now: aux::H at 1/2 - */ - ComputeAuxH(dom, gr_getH::D0_B0); - /** - * aux::H <- boundary conditions - */ - FieldBoundaries(dom, BC::B, gr_bc::aux); + /** + * aux::H <- alpha * em0::B - beta x em0::D + * + * Now: aux::H at 1/2 + */ + ComputeAuxH(dom, gr_getH::D0_B0); + /** + * aux::H <- boundary conditions + */ + FieldBoundaries(dom, BC::B, gr_bc::aux); - /** - * em0::D <- (em::D) <- curl aux::H - * - * Now: em0::D at 1 - * em::D at 0 - */ - Ampere(dom, gr_ampere::main, ONE); - /** - * em0::D, em::D <- boundary conditions - */ - m_metadomain.CommunicateFields(dom, Comm::D | Comm::D0); - FieldBoundaries(dom, BC::E, gr_bc::main); + /** + * em0::D <- (em::D) <- curl aux::H + * + * Now: em0::D at 1 + * em::D at 0 + */ + Ampere(dom, gr_ampere::main, ONE); + /** + * em0::D, em::D <- boundary conditions + */ + m_metadomain.CommunicateFields(dom, Comm::D | Comm::D0); + FieldBoundaries(dom, BC::E, gr_bc::main); - /** - * em::D <-> em0::D - * em::B <-> em0::B - * em::J <-> em0::J - */ - SwapFields(dom); - /** - * Finally: em0::B at -1/2 - * em0::D at 0 - * em::B at 1/2 - * em::D at 1 - * - * cur0::J -- - * cur::J -- - * - * aux::E -- - * aux::H -- - * - * x_prtl at 1 - * u_prtl at 1/2 - */ + /** + * em::D <-> em0::D + * em::B <-> em0::B + * em::J <-> em0::J + */ + SwapFields(dom); + /** + * Finally: em0::B at -1/2 + * em0::D at 0 + * em::B at 1/2 + * em::D at 1 + * + * cur0::J -- + * cur::J -- + * + * aux::E -- + * aux::H -- + * + * x_prtl at 1 + * u_prtl at 1/2 + */ + } + } else { + /** + * em0::B <- em::B + * em0::D <- em::D + * + * Now: em0::B & em0::D at -1/2 + */ + CopyFields(dom); } /** From 30f87f49c905559ab4b059ae0909f5e44f68c97f Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Fri, 6 Dec 2024 13:58:38 -0500 Subject: [PATCH 336/773] GeodesicFullPush bug for utheta --- src/kernels/particle_pusher_gr.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/kernels/particle_pusher_gr.hpp b/src/kernels/particle_pusher_gr.hpp index 306f19013..4b5432891 100644 --- a/src/kernels/particle_pusher_gr.hpp +++ b/src/kernels/particle_pusher_gr.hpp @@ -478,7 +478,7 @@ namespace kernel::gr { dt * (-metric.alpha(xp_mid) * u0 * DERIVATIVE_IN_TH(metric.alpha, xp_mid) + - vp_mid[1] * DERIVATIVE_IN_TH(metric.beta1, xp_mid) - + vp_mid[0] * DERIVATIVE_IN_TH(metric.beta1, xp_mid) - (HALF / u0) * (DERIVATIVE_IN_TH((metric.template h<1, 1>), xp_mid) * SQR(vp_mid[0]) + From 1fd9cc2dbbb7d8297704c00ff5b4150d2ae95f9b Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Wed, 11 Dec 2024 16:36:19 -0500 Subject: [PATCH 337/773] minor gr pusher --- src/kernels/particle_pusher_gr.hpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/kernels/particle_pusher_gr.hpp b/src/kernels/particle_pusher_gr.hpp index 4b5432891..e220239bf 100644 --- a/src/kernels/particle_pusher_gr.hpp +++ b/src/kernels/particle_pusher_gr.hpp @@ -678,13 +678,9 @@ namespace kernel::gr { dx2_prev(p) = dx2(p); coord_t xp { ZERO }; - coord_t xp_prev { ZERO }; xp[0] = i_di_to_Xi(i1(p), dx1(p)); xp[1] = i_di_to_Xi(i2(p), dx2(p)); - - xp_prev[0] = i_di_to_Xi(i1_prev(p), dx1_prev(p)); - xp_prev[1] = i_di_to_Xi(i2_prev(p), dx2_prev(p)); vec_t Dp_cntrv { ZERO }, Bp_cntrv { ZERO }, Dp_hat { ZERO }, Bp_hat { ZERO }; From cd11618a646d6aac17e1ce73defa64284d562780 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Wed, 11 Dec 2024 18:20:10 -0500 Subject: [PATCH 338/773] pgen and inputs for pusher debugging updated --- setups/grpic/pusher/boris.toml | 52 ++++---- setups/grpic/pusher/massive_gravity_a0.toml | 4 +- .../grpic/pusher/massive_gravity_a0995.toml | 4 +- setups/grpic/pusher/pgen.hpp | 124 +++++++++++++----- 4 files changed, 122 insertions(+), 62 deletions(-) diff --git a/setups/grpic/pusher/boris.toml b/setups/grpic/pusher/boris.toml index 6483eb2c6..5d4d92a9d 100644 --- a/setups/grpic/pusher/boris.toml +++ b/setups/grpic/pusher/boris.toml @@ -1,14 +1,14 @@ [simulation] name = "boris_a0" engine = "grpic" - runtime = 100.0 + runtime = 500.0 [grid] resolution = [128,128] - extent = [[0.9, 20.0]] + extent = [[1.2, 20.0]] [grid.metric] - metric = "qkerr_schild" + metric = "kerr_schild" qsph_r0 = 0.0 qsph_h = 0.0 ks_a = 0.0 @@ -22,7 +22,7 @@ [scales] larmor0 = 5.0 - skindepth0 = 1e-3 + skindepth0 = 1e0 [algorithms] current_filters = 4 @@ -32,7 +32,7 @@ pusher_eps = 1e-6 [algorithms.timestep] - CFL = 0.1 + CFL = 1.0 [algorithms.toggles] deposit = false @@ -42,37 +42,33 @@ ppc0 = 1.0 [[particles.species]] - label = "e-" + label = "e+" mass = 1.0 - charge = -1.0 + charge = 1.0 maxnpart = 1e0 [[particles.species]] - label = "e+" + label = "e-" mass = 1.0 charge = -1.0 - maxnpart = 1e1 + maxnpart = 1e0 [setup] - x1s = [5.77] - y1s = [1.570796] - z1s = [0.000000] - ux1s = [0.4376657824933686] - uy1s = [0.000000] - uz1s = [4.0] -# x1s = [10.0] -# y1s = [1.570796] -# z1s = [0.000000] -# ux1s = [0.0] -# uy1s = [0.000000] -# uz1s = [10.00000] - - #x2s = [7.5] - #y2s = [0.15745454545454546] - #z2s = [0.000000] - #ux2s = [0.029637] - #uy2s = [0.000000] - #uz2s = [3.75] + # Fig. 6.4 from Kolos, Stuchlik and Tursunov (2015) + x1s = [5.77] + y1s = [1.5707963267948966] + z1s = [0.000000] + ux1s = [0.43766578249336874] + uy1s = [0.000000] + uz1s = [1.1707100000000000] + + # Fig. 5.3 from Kolos, Stuchlik and Tursunov (2015) + x2s = [6.79] + y2s = [1.5707963267948966] + z2s = [0.000000] + ux2s = [0.7398747390396659] + uy2s = [0.000000] + uz2s = [12.610410000000002] [output] format = "hdf5" diff --git a/setups/grpic/pusher/massive_gravity_a0.toml b/setups/grpic/pusher/massive_gravity_a0.toml index 08b607d4b..8179432da 100644 --- a/setups/grpic/pusher/massive_gravity_a0.toml +++ b/setups/grpic/pusher/massive_gravity_a0.toml @@ -56,7 +56,7 @@ [setup] # (1,2,0) from Levin&Perez-Giz (2008) x1s = [9.85180645] - y1s = [1.570796] + y1s = [1.5707963267948966] z1s = [0.5235987755982988] ux1s = [0.24159816] uy1s = [3.535534] @@ -64,7 +64,7 @@ # (4,1,1) from Levin&Perez-Giz (2008) x2s = [68.600387] - y2s = [1.570796] + y2s = [1.5707963267948966] z2s = [0.000000] ux2s = [0.029637] uy2s = [0.000000] diff --git a/setups/grpic/pusher/massive_gravity_a0995.toml b/setups/grpic/pusher/massive_gravity_a0995.toml index b04538e10..3b64d2066 100644 --- a/setups/grpic/pusher/massive_gravity_a0995.toml +++ b/setups/grpic/pusher/massive_gravity_a0995.toml @@ -56,7 +56,7 @@ [setup] # (2,3,1) from Levin&Perez-Giz (2008) x1s = [10.343515586064923] - y1s = [1.570796] + y1s = [1.5707963267948966] z1s = [0.000000] ux1s = [0.19483849893499136] uy1s = [0.000000] @@ -64,7 +64,7 @@ # (~1000, 3, ~671) from Levin&Perez-Giz (2008) x2s = [10.64975354] - y2s = [1.570796] + y2s = [1.5707963267948966] z2s = [0.000000] ux2s = [0.18914503] uy2s = [0.000000] diff --git a/setups/grpic/pusher/pgen.hpp b/setups/grpic/pusher/pgen.hpp index d6a29a185..8f60b1515 100644 --- a/setups/grpic/pusher/pgen.hpp +++ b/setups/grpic/pusher/pgen.hpp @@ -27,12 +27,12 @@ namespace user { InitFields(M metric_) : metric { metric_ } {} Inline auto A_3(const coord_t& x_Cd) const -> real_t { - // return HALF * (metric.template h_<3, 3>(x_Cd) ); - // + TWO * metric.spin() * metric.template h_<1, 3>(x_Cd) * metric.beta1(x_Cd) - // ); - coord_t x_Ph { ZERO }; - metric.template convert(x_Cd, x_Ph); - return HALF * SQR(x_Ph[0]) * SQR(math::sin(x_Ph[1])); + return HALF * (metric.template h_<3, 3>(x_Cd) + + TWO * metric.spin() * metric.template h_<1, 3>(x_Cd) * metric.beta1(x_Cd) + ); + // coord_t x_Ph { ZERO }; + // metric.template convert(x_Cd, x_Ph); + // return HALF * SQR(x_Ph[0]) * SQR(math::sin(x_Ph[1])); } Inline auto A_1(const coord_t& x_Cd) const -> real_t { @@ -49,7 +49,7 @@ namespace user { + TWO * metric.spin() * g_00); } - Inline auto bx1(const coord_t& x_Ph) const -> real_t { + Inline auto bx1(const coord_t& x_Ph) const -> real_t { // at ( i , j + HALF ) coord_t xi {ZERO}, x0m { ZERO }, x0p { ZERO }; metric.template convert(x_Ph, xi); @@ -64,50 +64,114 @@ namespace user { return ONE; else return (A_3(x0p) - A_3(x0m)) * inv_sqrt_detH_ijP; - // return ZERO; } - Inline auto bx2(const coord_t& x_Ph) const -> real_t { + Inline auto bx2(const coord_t& x_Ph) const -> real_t { // at ( i + HALF , j ) coord_t xi {ZERO}, x0m { ZERO }, x0p { ZERO }; metric.template convert(x_Ph, xi); - x0m[0] = xi[0] + HALF - HALF; + x0m[0] = xi[0] - HALF; x0m[1] = xi[1]; - x0p[0] = xi[0] + HALF + HALF; + x0p[0] = xi[0] + HALF; x0p[1] = xi[1]; - real_t inv_sqrt_detH_ijP { ONE / metric.sqrt_det_h({ xi[0], xi[1] }) }; + real_t inv_sqrt_detH_iPj { ONE / metric.sqrt_det_h({ xi[0], xi[1] }) }; if (cmp::AlmostZero(x_Ph[1])) return ZERO; else - return -(A_3(x0p) - A_3(x0m)) * inv_sqrt_detH_ijP; - // return ZERO; + return -(A_3(x0p) - A_3(x0m)) * inv_sqrt_detH_iPj; } - Inline auto bx3(const coord_t& x_Ph) const -> real_t { - // coord_t xi {ZERO}, x0m { ZERO }, x0p { ZERO }; - // metric.template convert(x_Ph, xi); + Inline auto bx3(const coord_t& x_Ph) const -> real_t { // at ( i + HALF , j + HALF ) + coord_t xi {ZERO}, x0m { ZERO }, x0p { ZERO }; + metric.template convert(x_Ph, xi); - // x0m[0] = xi[0] + HALF - HALF; - // x0m[1] = xi[1]; - // x0p[0] = xi[0] + HALF + HALF; - // x0p[1] = xi[1]; + x0m[0] = xi[0]; + x0m[1] = xi[1] - HALF; + x0p[0] = xi[0]; + x0p[1] = xi[1] + HALF; - // real_t inv_sqrt_detH_ijP { ONE / metric.sqrt_det_h({ xi[0], xi[1] }) }; - // return -(A_1(x0p) - A_1(x0m)) * inv_sqrt_detH_ijP; - return ZERO; + real_t inv_sqrt_detH_iPjP { ONE / metric.sqrt_det_h({ xi[0], xi[1]}) }; + return -(A_1(x0p) - A_1(x0m)) * inv_sqrt_detH_iPjP; } - Inline auto dx1(const coord_t& x_Ph) const -> real_t { - return ZERO; + Inline auto dx1(const coord_t& x_Ph) const -> real_t { // at ( i + HALF , j ) + coord_t xi {ZERO}, x0m { ZERO }, x0p { ZERO }; + metric.template convert(x_Ph, xi); + + real_t alpha_iPj { metric.alpha({ xi[0], xi[1] }) }; + real_t inv_sqrt_detH_ij { ONE / metric.sqrt_det_h({ xi[0] - HALF, xi[1] }) }; + real_t sqrt_detH_ij { metric.sqrt_det_h({ xi[0] - HALF, xi[1] }) }; + real_t beta_ij { metric.beta1({ xi[0] - HALF, xi[1]}) }; + real_t alpha_ij { metric.alpha({ xi[0] - HALF, xi[1]}) }; + + // D1 at ( i + HALF , j ) + x0m[0] = xi[0] - HALF; + x0m[1] = xi[1]; + x0p[0] = xi[0] + HALF; + x0p[1] = xi[1]; + real_t E1d { (A_0(x0p) - A_0(x0m)) }; + real_t D1d { E1d / alpha_iPj }; + + // D3 at ( i , j ) + x0m[0] = xi[0] - HALF - HALF; + x0m[1] = xi[1]; + x0p[0] = xi[0] - HALF + HALF; + x0p[1] = xi[1]; + real_t B2_aux { -(A_3(x0p) - A_3(x0m)) * inv_sqrt_detH_ij }; + real_t D3d { -sqrt_detH_ij * beta_ij * B2_aux / alpha_ij }; + + real_t D1u { metric.template h<1, 1>({ xi[0], xi[1] }) * D1d + metric.template h<1, 3>({ xi[0], xi[1] }) * D3d }; + + return D1u; } - Inline auto dx2(const coord_t& x_Ph) const -> real_t { - return ZERO; + Inline auto dx2(const coord_t& x_Ph) const -> real_t { // at ( i , j + HALF ) + coord_t xi {ZERO}, x0m { ZERO }, x0p { ZERO }; + metric.template convert(x_Ph, xi); + x0m[0] = xi[0]; + x0m[1] = xi[1] - HALF; + x0p[0] = xi[0]; + x0p[1] = xi[1] + HALF; + real_t inv_sqrt_detH_ijP { ONE / metric.sqrt_det_h({ xi[0], xi[1] }) }; + real_t sqrt_detH_ijP { metric.sqrt_det_h({ xi[0], xi[1] }) }; + real_t alpha_ijP { metric.alpha({ xi[0], xi[1] }) }; + real_t beta_ijP { metric.beta1({ xi[0], xi[1] }) }; + + real_t E2d { (A_0(x0p) - A_0(x0m)) }; + real_t B3_aux { -(A_1(x0p) - A_1(x0m)) * inv_sqrt_detH_ijP }; + real_t D2d { E2d / alpha_ijP + sqrt_detH_ijP * beta_ijP * B3_aux / alpha_ijP }; + real_t D2u { metric.template h<2, 2>({ xi[0], xi[1] }) * D2d }; + + return D2u; } - Inline auto dx3(const coord_t& x_Ph) const -> real_t { - return ZERO; + Inline auto dx3(const coord_t& x_Ph) const -> real_t { // at ( i , j ) + coord_t xi {ZERO}, x0m { ZERO }, x0p { ZERO }; + metric.template convert(x_Ph, xi); + real_t inv_sqrt_detH_ij { ONE / metric.sqrt_det_h({ xi[0], xi[1] }) }; + real_t sqrt_detH_ij { metric.sqrt_det_h({ xi[0], xi[1] }) }; + real_t beta_ij { metric.beta1({ xi[0], xi[1] }) }; + real_t alpha_ij { metric.alpha({ xi[0], xi[1] }) }; + real_t alpha_iPj { metric.alpha({ xi[0] + HALF, xi[1] }) }; + + // D3 at ( i , j ) + x0m[0] = xi[0] - HALF; + x0m[1] = xi[1]; + x0p[0] = xi[0] + HALF; + x0p[1] = xi[1]; + real_t B2_aux { -(A_3(x0p) - A_3(x0m)) * inv_sqrt_detH_ij}; + real_t D3d { -sqrt_detH_ij * beta_ij * B2_aux / alpha_ij }; + + // D1 at ( i + HALF , j ) + x0m[0] = xi[0] + HALF - HALF; + x0m[1] = xi[1]; + x0p[0] = xi[0] + HALF + HALF; + x0p[1] = xi[1]; + real_t E1d { (A_0(x0p) - A_0(x0m)) }; + real_t D1d { E1d / alpha_iPj }; + + return metric.template h<3, 3>({ xi[0], xi[1] }) * D3d + metric.template h<1, 3>({ xi[0], xi[1] }) * D1d; } private: From 9e3c47f0ae155c168af9c8301a5ac6dbb0bdd0e1 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Mon, 16 Dec 2024 15:38:24 -0500 Subject: [PATCH 339/773] boris tests with non-zero spin --- setups/grpic/pusher/boris_a09.toml | 85 ++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 setups/grpic/pusher/boris_a09.toml diff --git a/setups/grpic/pusher/boris_a09.toml b/setups/grpic/pusher/boris_a09.toml new file mode 100644 index 000000000..379e9c323 --- /dev/null +++ b/setups/grpic/pusher/boris_a09.toml @@ -0,0 +1,85 @@ +[simulation] + name = "boris_a09" + engine = "grpic" + runtime = 500.0 + +[grid] + resolution = [128,128] + extent = [[1.2, 20.0]] + + [grid.metric] + metric = "kerr_schild" + qsph_r0 = 0.0 + qsph_h = 0.0 + ks_a = 0.9 + + [grid.boundaries] + fields = [["ABSORB"]] + particles = [["ABSORB"]] + + [grid.boundaries.absorb] + ds = 0.5 + +[scales] + larmor0 = 0.5 + skindepth0 = 1e0 + +[algorithms] + current_filters = 4 + + [algorithms.gr] + pusher_niter = 10 + pusher_eps = 1e-6 + + [algorithms.timestep] + CFL = 1.0 + + [algorithms.toggles] + deposit = false + fieldsolver = false + +[particles] + ppc0 = 1.0 + + [[particles.species]] + label = "e+" + mass = 1.0 + charge = 1.0 + maxnpart = 1e0 + + [[particles.species]] + label = "e-" + mass = 1.0 + charge = -1.0 + maxnpart = 1e0 + +[setup] + # Stuchlik and Kolos (2015) Fig.11 ~ RKA3 from Bacchini et al + x1s = [4.000000] + y1s = [1.3707963268] + z1s = [0.000000] + ux1s = [0.625666] + uy1s = [0.000000] + uz1s = [1.580567] + +[output] + format = "hdf5" + + [output.fields] + enable = true + interval_time = 1.0 + quantities = ["D", "B"] + + [output.particles] + enable = true + stride = 1 + interval_time = 0.2 + species = [] + + [output.spectra] + enable = false + +[diagnostics] + interval = 10 + colored_stdout = true + blocking_timers = true From d0349bf87b83aec3e8b2f204afcbc11758f64ff6 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Tue, 17 Dec 2024 15:22:31 -0500 Subject: [PATCH 340/773] updated setups --- setups/grpic/orbits/orbits.toml | 73 ++++++++++++++++ setups/grpic/orbits/pgen.hpp | 132 ++++++++++++++++++++++++++++ setups/grpic/pusher/deposit.toml | 91 +++++++++++++++++++ setups/grpic/vacuum/pgen.hpp | 146 +++++++++++++++++++++++++++++++ setups/grpic/vacuum/wald.toml | 93 ++++++++++++++++++++ setups/grpic/wald/pgen.hpp | 26 ++++-- setups/grpic/wald/wald.toml | 48 +++++----- 7 files changed, 583 insertions(+), 26 deletions(-) create mode 100644 setups/grpic/orbits/orbits.toml create mode 100644 setups/grpic/orbits/pgen.hpp create mode 100644 setups/grpic/pusher/deposit.toml create mode 100644 setups/grpic/vacuum/pgen.hpp create mode 100644 setups/grpic/vacuum/wald.toml diff --git a/setups/grpic/orbits/orbits.toml b/setups/grpic/orbits/orbits.toml new file mode 100644 index 000000000..ab8f2bef5 --- /dev/null +++ b/setups/grpic/orbits/orbits.toml @@ -0,0 +1,73 @@ +[simulation] + name = "wald" + engine = "grpic" + runtime = 110.0 + +[grid] + resolution = [128,128] + extent = [[1.2, 8.0]] + + [grid.metric] + metric = "kerr_schild" + qsph_r0 = 0.0 + qsph_h = 0.0 + ks_a = 0.95 + + [grid.boundaries] + fields = [["ABSORB"]] + particles = [["ABSORB"]] + + [grid.boundaries.absorb] + ds = 0.5 + +[scales] + larmor0 = 1.0 + skindepth0 = 1.0 + +[algorithms] + current_filters = 4 + + [algorithms.timestep] + CFL = 0.5 + + [algorithms.toggles] + deposit = false + fieldsolver = true + +[particles] + ppc0 = 8.0 + use_weights = true + sort_interval = 100 + +# [[particles.species]] +# label = "e-" +# mass = 1.0 +# charge = -1.0 +# maxnpart = 2e6 +# pusher = "Boris" +# +# [[particles.species]] +# label = "e+" +# mass = 1.0 +# charge = 1.0 +# maxnpart = 2e6 +# pusher = "Boris" + +[setup] + +[output] + format = "hdf5" + + [output.fields] + interval_time = 1.0 + quantities = ["D", "H", "B", "J"] + + [output.particles] + interval_time = 1.0 + quantities = ["X", "U"] + + [output.spectra] + enable = false + +[diagnostics] + interval = 1 diff --git a/setups/grpic/orbits/pgen.hpp b/setups/grpic/orbits/pgen.hpp new file mode 100644 index 000000000..54965b1ee --- /dev/null +++ b/setups/grpic/orbits/pgen.hpp @@ -0,0 +1,132 @@ +#ifndef PROBLEM_GENERATOR_H +#define PROBLEM_GENERATOR_H + +#include "enums.h" +#include "global.h" + +#include "arch/kokkos_aliases.h" +#include "arch/traits.h" + +#include "archetypes/problem_generator.h" +#include "framework/domain/metadomain.h" + +namespace user { + using namespace ntt; + + template + struct InitFields { + InitFields(M metric_) : metric { metric_ } {} + + Inline auto A_3(const coord_t& x_Cd) const -> real_t { + // return HALF * (metric.template h_<3, 3>(x_Cd) ); + // + TWO * metric.spin() * metric.template h_<1, 3>(x_Cd) * metric.beta1(x_Cd) + // ); + + coord_t x_Ph { ZERO }; + metric.template convert(x_Cd, x_Ph); + return HALF * SQR(x_Ph[0]) * SQR(math::sin(x_Ph[1])); + } + + Inline auto A_1(const coord_t& x_Cd) const -> real_t { + return HALF * (metric.template h_<1, 3>(x_Cd) + + TWO * metric.spin() * metric.template h_<1, 1>(x_Cd) * metric.beta1(x_Cd) + ); + } + + Inline auto A_0(const coord_t& x_Cd) const -> real_t { + real_t g_00 { -metric.alpha(x_Cd) * metric.alpha(x_Cd) + + metric.template h_<1, 1>(x_Cd) * metric.beta1(x_Cd) * metric.beta1(x_Cd) + }; + return HALF * (metric.template h_<1, 3>(x_Cd) * metric.beta1(x_Cd) + + TWO * metric.spin() * g_00); + } + + Inline auto bx1(const coord_t& x_Ph) const -> real_t { + coord_t xi {ZERO}, x0m { ZERO }, x0p { ZERO }; + metric.template convert(x_Ph, xi); + + x0m[0] = xi[0]; + x0m[1] = xi[1] - HALF; + x0p[0] = xi[0]; + x0p[1] = xi[1] + HALF; + + real_t inv_sqrt_detH_ijP { ONE / metric.sqrt_det_h({ xi[0], xi[1] }) }; + + if (cmp::AlmostZero(x_Ph[1])) + return ONE; + else + return (A_3(x0p) - A_3(x0m)) * inv_sqrt_detH_ijP; + } + + Inline auto bx2(const coord_t& x_Ph) const -> real_t { + coord_t xi {ZERO}, x0m { ZERO }, x0p { ZERO }; + metric.template convert(x_Ph, xi); + + x0m[0] = xi[0] + HALF - HALF; + x0m[1] = xi[1]; + x0p[0] = xi[0] + HALF + HALF; + x0p[1] = xi[1]; + + real_t inv_sqrt_detH_ijP { ONE / metric.sqrt_det_h({ xi[0], xi[1] }) }; + if (cmp::AlmostZero(x_Ph[1])) + return ZERO; + else + return -(A_3(x0p) - A_3(x0m)) * inv_sqrt_detH_ijP; + } + + Inline auto bx3(const coord_t& x_Ph) const -> real_t { + coord_t xi {ZERO}, x0m { ZERO }, x0p { ZERO }; + metric.template convert(x_Ph, xi); + + x0m[0] = xi[0] + HALF - HALF; + x0m[1] = xi[1]; + x0p[0] = xi[0] + HALF + HALF; + x0p[1] = xi[1]; + + real_t inv_sqrt_detH_ijP { ONE / metric.sqrt_det_h({ xi[0], xi[1] }) }; + return -(A_1(x0p) - A_1(x0m)) * inv_sqrt_detH_ijP; + // return ZERO; + } + + Inline auto dx1(const coord_t& x_Ph) const -> real_t { + return ZERO; + } + + Inline auto dx2(const coord_t& x_Ph) const -> real_t { + return ZERO; + } + + Inline auto dx3(const coord_t& x_Ph) const -> real_t { + return ZERO; + } + + private: + const M metric; + }; + + template + struct PGen : public arch::ProblemGenerator { + // compatibility traits for the problem generator + static constexpr auto engines { traits::compatible_with::value }; + static constexpr auto metrics { + traits::compatible_with::value + }; + static constexpr auto dimensions { traits::compatible_with::value }; + + // for easy access to variables in the child class + using arch::ProblemGenerator::D; + using arch::ProblemGenerator::C; + using arch::ProblemGenerator::params; + + InitFields init_flds; + + inline PGen(SimulationParams& p, const Metadomain& m) + : arch::ProblemGenerator(p) + , init_flds { m.mesh().metric } {} + + inline PGen() {} + }; + +} // namespace user + +#endif diff --git a/setups/grpic/pusher/deposit.toml b/setups/grpic/pusher/deposit.toml new file mode 100644 index 000000000..359d4eaa7 --- /dev/null +++ b/setups/grpic/pusher/deposit.toml @@ -0,0 +1,91 @@ +[simulation] + name = "deposit" + engine = "grpic" + runtime = 10.0 + +[grid] + resolution = [512,512] + extent = [[1.2, 20.0]] + + [grid.metric] + metric = "kerr_schild" + qsph_r0 = 0.0 + qsph_h = 0.0 + ks_a = 0.0 + + [grid.boundaries] + fields = [["ABSORB"]] + particles = [["ABSORB"]] + + [grid.boundaries.absorb] + ds = 2.0 + +[scales] + larmor0 = 2.0 + skindepth0 = 2.0 + +[algorithms] + current_filters = 4 + + [algorithms.gr] + pusher_niter = 10 + pusher_eps = 1e-6 + + [algorithms.timestep] + CFL = 0.5 + + [algorithms.toggles] + deposit = true + fieldsolver = true + +[particles] + ppc0 = 1.0 + + [[particles.species]] + label = "e-" + mass = 1.0 + charge = -1.0 + maxnpart = 1e0 + + [[particles.species]] + label = "e+" + mass = 1.0 + charge = 1.0 + maxnpart = 1e0 + +[setup] + x1s = [17.00000] + y1s = [1.570796] + z1s = [0.000000] + ux1s = [8.000000] + uy1s = [0.000000] + uz1s = [0.000000] + + x2s = [17.00000] + y2s = [1.570796] + z2s = [0.000000] + ux2s = [-8.000000] + uy2s = [0.000000] + uz2s = [0.000000] + +[output] + format = "hdf5" + + [output.fields] + enable = true + interval_time = 0.5 + quantities = ["D", "B"] + + [output.particles] + enable = true + stride = 1 + interval_time = 0.5 + species = [] + + [output.spectra] + enable = false + +[diagnostics] + interval = 10 + colored_stdout = true + blocking_timers = true diff --git a/setups/grpic/vacuum/pgen.hpp b/setups/grpic/vacuum/pgen.hpp new file mode 100644 index 000000000..c02c198e8 --- /dev/null +++ b/setups/grpic/vacuum/pgen.hpp @@ -0,0 +1,146 @@ +#ifndef PROBLEM_GENERATOR_H +#define PROBLEM_GENERATOR_H + +#include "enums.h" +#include "global.h" + +#include "arch/kokkos_aliases.h" +#include "arch/traits.h" +#include "utils/comparators.h" +#include "utils/formatting.h" +#include "utils/log.h" +#include "utils/numeric.h" + +#include "archetypes/problem_generator.h" +#include "framework/domain/metadomain.h" +#include "framework/domain/domain.h" +#include "archetypes/energy_dist.h" +#include "archetypes/particle_injector.h" + +#include + +namespace user { + using namespace ntt; + + template + struct InitFields { + InitFields(M metric_) : metric { metric_ } {} + + Inline auto A_3(const coord_t& x_Cd) const -> real_t { + return HALF * (metric.template h_<3, 3>(x_Cd) ); + // + TWO * metric.spin() * metric.template h_<1, 3>(x_Cd) * metric.beta1(x_Cd) + // ); + coord_t x_Ph { ZERO }; + metric.template convert(x_Cd, x_Ph); + return HALF * SQR(x_Ph[0]) * SQR(math::sin(x_Ph[1])); + } + + Inline auto A_1(const coord_t& x_Cd) const -> real_t { + return HALF * (metric.template h_<1, 3>(x_Cd) + + TWO * metric.spin() * metric.template h_<1, 1>(x_Cd) * metric.beta1(x_Cd) + ); + } + + Inline auto A_0(const coord_t& x_Cd) const -> real_t { + real_t g_00 { -metric.alpha(x_Cd) * metric.alpha(x_Cd) + + metric.template h_<1, 1>(x_Cd) * metric.beta1(x_Cd) * metric.beta1(x_Cd) + }; + return HALF * (metric.template h_<1, 3>(x_Cd) * metric.beta1(x_Cd) + + TWO * metric.spin() * g_00); + } + + Inline auto bx1(const coord_t& x_Ph) const -> real_t { + coord_t xi {ZERO}, x0m { ZERO }, x0p { ZERO }; + metric.template convert(x_Ph, xi); + + x0m[0] = xi[0]; + x0m[1] = xi[1] - HALF; + x0p[0] = xi[0]; + x0p[1] = xi[1] + HALF; + + real_t inv_sqrt_detH_ijP { ONE / metric.sqrt_det_h({ xi[0], xi[1] }) }; + + if (cmp::AlmostZero(x_Ph[1])) + return ONE; + else + return (A_3(x0p) - A_3(x0m)) * inv_sqrt_detH_ijP; + } + + Inline auto bx2(const coord_t& x_Ph) const -> real_t { + coord_t xi {ZERO}, x0m { ZERO }, x0p { ZERO }; + metric.template convert(x_Ph, xi); + + x0m[0] = xi[0] + HALF - HALF; + x0m[1] = xi[1]; + x0p[0] = xi[0] + HALF + HALF; + x0p[1] = xi[1]; + + real_t inv_sqrt_detH_ijP { ONE / metric.sqrt_det_h({ xi[0], xi[1] }) }; + if (cmp::AlmostZero(x_Ph[1])) + return ZERO; + else + return -(A_3(x0p) - A_3(x0m)) * inv_sqrt_detH_ijP; + } + + Inline auto bx3(const coord_t& x_Ph) const -> real_t { + // coord_t xi {ZERO}, x0m { ZERO }, x0p { ZERO }; + // metric.template convert(x_Ph, xi); + + // x0m[0] = xi[0] + HALF - HALF; + // x0m[1] = xi[1]; + // x0p[0] = xi[0] + HALF + HALF; + // x0p[1] = xi[1]; + + // real_t inv_sqrt_detH_ijP { ONE / metric.sqrt_det_h({ xi[0], xi[1] }) }; + // return -(A_1(x0p) - A_1(x0m)) * inv_sqrt_detH_ijP; + return ZERO; + } + + Inline auto dx1(const coord_t& x_Ph) const -> real_t { + return ZERO; + } + + Inline auto dx2(const coord_t& x_Ph) const -> real_t { + return ZERO; + } + + Inline auto dx3(const coord_t& x_Ph) const -> real_t { + return ZERO; + } + + private: + const M metric; + }; + + template + struct PGen : public arch::ProblemGenerator { + // compatibility traits for the problem generator + static constexpr auto engines { traits::compatible_with::value }; + static constexpr auto metrics { + traits::compatible_with::value + }; + static constexpr auto dimensions { traits::compatible_with::value }; + + // for easy access to variables in the child class + using arch::ProblemGenerator::D; + using arch::ProblemGenerator::C; + using arch::ProblemGenerator::params; + + InitFields init_flds; + const Metadomain& global_domain; + inline PGen(const SimulationParams& p, const Metadomain& m) + : arch::ProblemGenerator { p } + , global_domain { m } + , init_flds { m.mesh().metric } {} + + // inline void InitPrtls(Domain& local_domain) { + + // arch::InjectGlobally(global_domain, local_domain, (arch::spidx_t)1, data_1); + // arch::InjectGlobally(global_domain, local_domain, (arch::spidx_t)2, data_2); + // } + // inline PGen() {} + }; + +} // namespace user + +#endif diff --git a/setups/grpic/vacuum/wald.toml b/setups/grpic/vacuum/wald.toml new file mode 100644 index 000000000..6864efb17 --- /dev/null +++ b/setups/grpic/vacuum/wald.toml @@ -0,0 +1,93 @@ +[simulation] + name = "wald" + engine = "grpic" + runtime = 5000.0 + +[grid] + resolution = [128,128] + extent = [[1.2, 100.0]] + + [grid.metric] + metric = "qkerr_schild" + qsph_r0 = 0.0 + qsph_h = 0.0 + ks_a = 0.0 + + [grid.boundaries] + fields = [["ABSORB"]] + particles = [["ABSORB"]] + + [grid.boundaries.absorb] + ds = 0.5 + +[scales] + larmor0 = 2e-3 + skindepth0 = 0.1 + +[algorithms] + current_filters = 4 + + [algorithms.gr] + pusher_niter = 10 + pusher_eps = 1e-2 + + [algorithms.timestep] + CFL = 10.0 + + [algorithms.toggles] + deposit = false + fieldsolver = false + +[particles] + ppc0 = 4.0 + + [[particles.species]] + label = "e-" + mass = 1.0 + charge = 0.0 + maxnpart = 1e1 + + [[particles.species]] + label = "e+" + mass = 1.0 + charge = -1.0 + maxnpart = 1e1 + +[setup] + # (1,1,0) from Levin&Perez-Giz (2008) + x1s = [59.921203] + y1s = [1.570796] + z1s = [0.000000] + ux1s = [0.034020] + uy1s = [0.000000] + uz1s = [3.900000] + + # (4,1,1) from Levin&Perez-Giz (2008) + x2s = [68.600387] + y2s = [1.570796] + z2s = [0.000000] + ux2s = [0.029637] + uy2s = [0.000000] + uz2s = [3.900000] + +[output] + format = "hdf5" + + [output.fields] + enable = true + interval_time = 1.0 + quantities = ["D", "B"] + + [output.particles] + enable = true + stride = 1 + interval_time = 10.0 + species = [] + + [output.spectra] + enable = false + +[diagnostics] + interval = 10 + colored_stdout = true + blocking_timers = true diff --git a/setups/grpic/wald/pgen.hpp b/setups/grpic/wald/pgen.hpp index 51636314b..8dd1a6e4e 100644 --- a/setups/grpic/wald/pgen.hpp +++ b/setups/grpic/wald/pgen.hpp @@ -18,10 +18,9 @@ namespace user { InitFields(M metric_) : metric { metric_ } {} Inline auto A_3(const coord_t& x_Cd) const -> real_t { - // return HALF * (metric.template h_<3, 3>(x_Cd) ); - // + TWO * metric.spin() * metric.template h_<1, 3>(x_Cd) * metric.beta1(x_Cd) + // return HALF * (metric.template h_<3, 3>(x_Cd) + // + TWO * metric.spin() * metric.template h_<1, 3>(x_Cd) * metric.beta1(x_Cd) // ); - coord_t x_Ph { ZERO }; metric.template convert(x_Cd, x_Ph); return HALF * SQR(x_Ph[0]) * SQR(math::sin(x_Ph[1])); @@ -122,9 +121,26 @@ namespace user { inline PGen(SimulationParams& p, const Metadomain& m) : arch::ProblemGenerator(p) + // , xi_min { p.template get>("setup.inj_rmin") } + // , xi_max { p.template get>("setup.inj_rmax") } , init_flds { m.mesh().metric } {} - - inline PGen() {} + + // inline void InitPrtls(Domain& local_domain) { + // const auto energy_dist = arch::ColdDist(local_domain.mesh.metric); + // const auto spatial_dist = PointDistribution(domain.mesh.metric, + // xi_min, + // xi_max); + // const auto injector = arch::NonUniformInjector( + // energy_dist, + // spatial_dist, + // { 1, 2 }); + // arch::InjectNonUniform>(params, + // local_domain, + // injector, + // 1.0); + // } + + // inline PGen() {} }; } // namespace user diff --git a/setups/grpic/wald/wald.toml b/setups/grpic/wald/wald.toml index 36c746ae5..44d1c8a24 100644 --- a/setups/grpic/wald/wald.toml +++ b/setups/grpic/wald/wald.toml @@ -1,17 +1,17 @@ [simulation] name = "wald" engine = "grpic" - runtime = 500.0 + runtime = 110.0 [grid] resolution = [128,128] - extent = [[1.2, 8.0]] + extent = [[2.0, 8.0]] [grid.metric] metric = "qkerr_schild" qsph_r0 = 0.0 qsph_h = 0.0 - ks_a = 0.95 + ks_a = 0.0 [grid.boundaries] fields = [["ABSORB"]] @@ -21,14 +21,14 @@ ds = 0.5 [scales] - larmor0 = 1.0 - skindepth0 = 1.0 + larmor0 = 1.0 #0.0025 + skindepth0 = 1.0 #0.05 [algorithms] current_filters = 4 [algorithms.timestep] - CFL = 0.5 + CFL = 0.3 [algorithms.toggles] deposit = false @@ -39,28 +39,32 @@ use_weights = true sort_interval = 100 -# [[particles.species]] -# label = "e-" -# mass = 1.0 -# charge = -1.0 -# maxnpart = 2e6 -# pusher = "Boris" -# -# [[particles.species]] -# label = "e+" -# mass = 1.0 -# charge = 1.0 -# maxnpart = 2e6 -# pusher = "Boris" + #[[particles.species]] + #label = "e-" + #mass = 1.0 + #charge = -1.0 + #maxnpart = 1e6 + #pusher = "Boris" + # + #[[particles.species]] + #label = "e+" + #mass = 1.0 + #charge = 1.0 + #maxnpart = 1e6 + #pusher = "Boris" [setup] + #multiplicity = 1.0 + #sigma_max = 1000.0 + #inj_rmin = 1.2 + #inj_rmax = 7.5 [output] format = "hdf5" [output.fields] interval_time = 1.0 - quantities = ["D", "H", "B", "J", "A"] + quantities = ["D", "H", "B", "J"] [output.particles] enable = false @@ -69,4 +73,6 @@ enable = false [diagnostics] - interval = 1 + interval = 2 + colored_stdout = true + blocking_timers = true From 1e1c50b3d9c2fdc5243e99752639d1c7c2a7d0bf Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Wed, 18 Dec 2024 10:59:29 -0500 Subject: [PATCH 341/773] engines/grpic: fixed the bug i introduced --- src/engines/grpic.hpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index 74ae4049e..a4bffadf2 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -260,15 +260,15 @@ namespace ntt { * x_prtl at 1 * u_prtl at 1/2 */ + } else { + /** + * em0::B <- em::B + * em0::D <- em::D + * + * Now: em0::B & em0::D at -1/2 + */ + CopyFields(dom); } - } else { - /** - * em0::B <- em::B - * em0::D <- em::D - * - * Now: em0::B & em0::D at -1/2 - */ - CopyFields(dom); } /** From 1aefb656081e5fc76e9f77153a4ffa55e698c80a Mon Sep 17 00:00:00 2001 From: alisagk <55898700+alisagk@users.noreply.github.com> Date: Wed, 18 Dec 2024 11:10:37 -0500 Subject: [PATCH 342/773] Delete setups/grpic/orbits directory --- setups/grpic/orbits/orbits.toml | 73 ------------------ setups/grpic/orbits/pgen.hpp | 132 -------------------------------- 2 files changed, 205 deletions(-) delete mode 100644 setups/grpic/orbits/orbits.toml delete mode 100644 setups/grpic/orbits/pgen.hpp diff --git a/setups/grpic/orbits/orbits.toml b/setups/grpic/orbits/orbits.toml deleted file mode 100644 index ab8f2bef5..000000000 --- a/setups/grpic/orbits/orbits.toml +++ /dev/null @@ -1,73 +0,0 @@ -[simulation] - name = "wald" - engine = "grpic" - runtime = 110.0 - -[grid] - resolution = [128,128] - extent = [[1.2, 8.0]] - - [grid.metric] - metric = "kerr_schild" - qsph_r0 = 0.0 - qsph_h = 0.0 - ks_a = 0.95 - - [grid.boundaries] - fields = [["ABSORB"]] - particles = [["ABSORB"]] - - [grid.boundaries.absorb] - ds = 0.5 - -[scales] - larmor0 = 1.0 - skindepth0 = 1.0 - -[algorithms] - current_filters = 4 - - [algorithms.timestep] - CFL = 0.5 - - [algorithms.toggles] - deposit = false - fieldsolver = true - -[particles] - ppc0 = 8.0 - use_weights = true - sort_interval = 100 - -# [[particles.species]] -# label = "e-" -# mass = 1.0 -# charge = -1.0 -# maxnpart = 2e6 -# pusher = "Boris" -# -# [[particles.species]] -# label = "e+" -# mass = 1.0 -# charge = 1.0 -# maxnpart = 2e6 -# pusher = "Boris" - -[setup] - -[output] - format = "hdf5" - - [output.fields] - interval_time = 1.0 - quantities = ["D", "H", "B", "J"] - - [output.particles] - interval_time = 1.0 - quantities = ["X", "U"] - - [output.spectra] - enable = false - -[diagnostics] - interval = 1 diff --git a/setups/grpic/orbits/pgen.hpp b/setups/grpic/orbits/pgen.hpp deleted file mode 100644 index 54965b1ee..000000000 --- a/setups/grpic/orbits/pgen.hpp +++ /dev/null @@ -1,132 +0,0 @@ -#ifndef PROBLEM_GENERATOR_H -#define PROBLEM_GENERATOR_H - -#include "enums.h" -#include "global.h" - -#include "arch/kokkos_aliases.h" -#include "arch/traits.h" - -#include "archetypes/problem_generator.h" -#include "framework/domain/metadomain.h" - -namespace user { - using namespace ntt; - - template - struct InitFields { - InitFields(M metric_) : metric { metric_ } {} - - Inline auto A_3(const coord_t& x_Cd) const -> real_t { - // return HALF * (metric.template h_<3, 3>(x_Cd) ); - // + TWO * metric.spin() * metric.template h_<1, 3>(x_Cd) * metric.beta1(x_Cd) - // ); - - coord_t x_Ph { ZERO }; - metric.template convert(x_Cd, x_Ph); - return HALF * SQR(x_Ph[0]) * SQR(math::sin(x_Ph[1])); - } - - Inline auto A_1(const coord_t& x_Cd) const -> real_t { - return HALF * (metric.template h_<1, 3>(x_Cd) - + TWO * metric.spin() * metric.template h_<1, 1>(x_Cd) * metric.beta1(x_Cd) - ); - } - - Inline auto A_0(const coord_t& x_Cd) const -> real_t { - real_t g_00 { -metric.alpha(x_Cd) * metric.alpha(x_Cd) - + metric.template h_<1, 1>(x_Cd) * metric.beta1(x_Cd) * metric.beta1(x_Cd) - }; - return HALF * (metric.template h_<1, 3>(x_Cd) * metric.beta1(x_Cd) - + TWO * metric.spin() * g_00); - } - - Inline auto bx1(const coord_t& x_Ph) const -> real_t { - coord_t xi {ZERO}, x0m { ZERO }, x0p { ZERO }; - metric.template convert(x_Ph, xi); - - x0m[0] = xi[0]; - x0m[1] = xi[1] - HALF; - x0p[0] = xi[0]; - x0p[1] = xi[1] + HALF; - - real_t inv_sqrt_detH_ijP { ONE / metric.sqrt_det_h({ xi[0], xi[1] }) }; - - if (cmp::AlmostZero(x_Ph[1])) - return ONE; - else - return (A_3(x0p) - A_3(x0m)) * inv_sqrt_detH_ijP; - } - - Inline auto bx2(const coord_t& x_Ph) const -> real_t { - coord_t xi {ZERO}, x0m { ZERO }, x0p { ZERO }; - metric.template convert(x_Ph, xi); - - x0m[0] = xi[0] + HALF - HALF; - x0m[1] = xi[1]; - x0p[0] = xi[0] + HALF + HALF; - x0p[1] = xi[1]; - - real_t inv_sqrt_detH_ijP { ONE / metric.sqrt_det_h({ xi[0], xi[1] }) }; - if (cmp::AlmostZero(x_Ph[1])) - return ZERO; - else - return -(A_3(x0p) - A_3(x0m)) * inv_sqrt_detH_ijP; - } - - Inline auto bx3(const coord_t& x_Ph) const -> real_t { - coord_t xi {ZERO}, x0m { ZERO }, x0p { ZERO }; - metric.template convert(x_Ph, xi); - - x0m[0] = xi[0] + HALF - HALF; - x0m[1] = xi[1]; - x0p[0] = xi[0] + HALF + HALF; - x0p[1] = xi[1]; - - real_t inv_sqrt_detH_ijP { ONE / metric.sqrt_det_h({ xi[0], xi[1] }) }; - return -(A_1(x0p) - A_1(x0m)) * inv_sqrt_detH_ijP; - // return ZERO; - } - - Inline auto dx1(const coord_t& x_Ph) const -> real_t { - return ZERO; - } - - Inline auto dx2(const coord_t& x_Ph) const -> real_t { - return ZERO; - } - - Inline auto dx3(const coord_t& x_Ph) const -> real_t { - return ZERO; - } - - private: - const M metric; - }; - - template - struct PGen : public arch::ProblemGenerator { - // compatibility traits for the problem generator - static constexpr auto engines { traits::compatible_with::value }; - static constexpr auto metrics { - traits::compatible_with::value - }; - static constexpr auto dimensions { traits::compatible_with::value }; - - // for easy access to variables in the child class - using arch::ProblemGenerator::D; - using arch::ProblemGenerator::C; - using arch::ProblemGenerator::params; - - InitFields init_flds; - - inline PGen(SimulationParams& p, const Metadomain& m) - : arch::ProblemGenerator(p) - , init_flds { m.mesh().metric } {} - - inline PGen() {} - }; - -} // namespace user - -#endif From 755aaa82c8d033e9c3222adbf1fb7e2595563ced Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Wed, 18 Dec 2024 11:08:29 -0500 Subject: [PATCH 343/773] setups/grpic: updated setup for vacuum --- setups/grpic/vacuum/pgen.hpp | 37 +--------------- setups/grpic/vacuum/vacuum.toml | 78 +++++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+), 35 deletions(-) create mode 100644 setups/grpic/vacuum/vacuum.toml diff --git a/setups/grpic/vacuum/pgen.hpp b/setups/grpic/vacuum/pgen.hpp index c02c198e8..6d5e5fba5 100644 --- a/setups/grpic/vacuum/pgen.hpp +++ b/setups/grpic/vacuum/pgen.hpp @@ -27,28 +27,11 @@ namespace user { InitFields(M metric_) : metric { metric_ } {} Inline auto A_3(const coord_t& x_Cd) const -> real_t { - return HALF * (metric.template h_<3, 3>(x_Cd) ); - // + TWO * metric.spin() * metric.template h_<1, 3>(x_Cd) * metric.beta1(x_Cd) - // ); coord_t x_Ph { ZERO }; metric.template convert(x_Cd, x_Ph); return HALF * SQR(x_Ph[0]) * SQR(math::sin(x_Ph[1])); } - Inline auto A_1(const coord_t& x_Cd) const -> real_t { - return HALF * (metric.template h_<1, 3>(x_Cd) - + TWO * metric.spin() * metric.template h_<1, 1>(x_Cd) * metric.beta1(x_Cd) - ); - } - - Inline auto A_0(const coord_t& x_Cd) const -> real_t { - real_t g_00 { -metric.alpha(x_Cd) * metric.alpha(x_Cd) - + metric.template h_<1, 1>(x_Cd) * metric.beta1(x_Cd) * metric.beta1(x_Cd) - }; - return HALF * (metric.template h_<1, 3>(x_Cd) * metric.beta1(x_Cd) - + TWO * metric.spin() * g_00); - } - Inline auto bx1(const coord_t& x_Ph) const -> real_t { coord_t xi {ZERO}, x0m { ZERO }, x0p { ZERO }; metric.template convert(x_Ph, xi); @@ -70,9 +53,9 @@ namespace user { coord_t xi {ZERO}, x0m { ZERO }, x0p { ZERO }; metric.template convert(x_Ph, xi); - x0m[0] = xi[0] + HALF - HALF; + x0m[0] = xi[0] - HALF; x0m[1] = xi[1]; - x0p[0] = xi[0] + HALF + HALF; + x0p[0] = xi[0] + HALF; x0p[1] = xi[1]; real_t inv_sqrt_detH_ijP { ONE / metric.sqrt_det_h({ xi[0], xi[1] }) }; @@ -83,16 +66,6 @@ namespace user { } Inline auto bx3(const coord_t& x_Ph) const -> real_t { - // coord_t xi {ZERO}, x0m { ZERO }, x0p { ZERO }; - // metric.template convert(x_Ph, xi); - - // x0m[0] = xi[0] + HALF - HALF; - // x0m[1] = xi[1]; - // x0p[0] = xi[0] + HALF + HALF; - // x0p[1] = xi[1]; - - // real_t inv_sqrt_detH_ijP { ONE / metric.sqrt_det_h({ xi[0], xi[1] }) }; - // return -(A_1(x0p) - A_1(x0m)) * inv_sqrt_detH_ijP; return ZERO; } @@ -132,13 +105,7 @@ namespace user { : arch::ProblemGenerator { p } , global_domain { m } , init_flds { m.mesh().metric } {} - - // inline void InitPrtls(Domain& local_domain) { - // arch::InjectGlobally(global_domain, local_domain, (arch::spidx_t)1, data_1); - // arch::InjectGlobally(global_domain, local_domain, (arch::spidx_t)2, data_2); - // } - // inline PGen() {} }; } // namespace user diff --git a/setups/grpic/vacuum/vacuum.toml b/setups/grpic/vacuum/vacuum.toml new file mode 100644 index 000000000..3992b9f12 --- /dev/null +++ b/setups/grpic/vacuum/vacuum.toml @@ -0,0 +1,78 @@ +[simulation] + name = "wald" + engine = "grpic" + runtime = 500.0 + +[grid] + resolution = [128,128] + extent = [[2.0, 8.0]] + + [grid.metric] + metric = "qkerr_schild" + qsph_r0 = 0.0 + qsph_h = 0.0 + ks_a = 0.0 + + [grid.boundaries] + fields = [["ABSORB"]] + particles = [["ABSORB"]] + + [grid.boundaries.absorb] + ds = 0.5 + +[scales] + larmor0 = 0.0025 + skindepth0 = 0.05 + +[algorithms] + current_filters = 4 + + [algorithms.timestep] + CFL = 0.5 + + [algorithms.toggles] + deposit = false + fieldsolver = true + +[particles] + ppc0 = 8.0 + use_weights = true + sort_interval = 100 + + #[[particles.species]] + #label = "e-" + #mass = 1.0 + #charge = -1.0 + #maxnpart = 1e6 + #pusher = "Boris" + # + #[[particles.species]] + #label = "e+" + #mass = 1.0 + #charge = 1.0 + #maxnpart = 1e6 + #pusher = "Boris" + +[setup] + #multiplicity = 1.0 + #sigma_max = 1000.0 + inj_rmin = 1.2 + inj_rmax = 7.5 + +[output] + format = "hdf5" + + [output.fields] + interval_time = 1.0 + quantities = ["D", "H", "B", "J"] + + [output.particles] + enable = false + + [output.spectra] + enable = false + +[diagnostics] + interval = 2 + colored_stdout = true + blocking_timers = true From ba72d3ba16bae7c5165dfa66999d60a27d50d7d3 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Wed, 18 Dec 2024 11:15:32 -0500 Subject: [PATCH 344/773] updated setups --- setups/grpic/vacuum/wald.toml | 93 ----------------------------------- setups/grpic/wald/pgen.hpp | 4 +- setups/grpic/wald/wald.toml | 12 ++--- 3 files changed, 8 insertions(+), 101 deletions(-) delete mode 100644 setups/grpic/vacuum/wald.toml diff --git a/setups/grpic/vacuum/wald.toml b/setups/grpic/vacuum/wald.toml deleted file mode 100644 index 6864efb17..000000000 --- a/setups/grpic/vacuum/wald.toml +++ /dev/null @@ -1,93 +0,0 @@ -[simulation] - name = "wald" - engine = "grpic" - runtime = 5000.0 - -[grid] - resolution = [128,128] - extent = [[1.2, 100.0]] - - [grid.metric] - metric = "qkerr_schild" - qsph_r0 = 0.0 - qsph_h = 0.0 - ks_a = 0.0 - - [grid.boundaries] - fields = [["ABSORB"]] - particles = [["ABSORB"]] - - [grid.boundaries.absorb] - ds = 0.5 - -[scales] - larmor0 = 2e-3 - skindepth0 = 0.1 - -[algorithms] - current_filters = 4 - - [algorithms.gr] - pusher_niter = 10 - pusher_eps = 1e-2 - - [algorithms.timestep] - CFL = 10.0 - - [algorithms.toggles] - deposit = false - fieldsolver = false - -[particles] - ppc0 = 4.0 - - [[particles.species]] - label = "e-" - mass = 1.0 - charge = 0.0 - maxnpart = 1e1 - - [[particles.species]] - label = "e+" - mass = 1.0 - charge = -1.0 - maxnpart = 1e1 - -[setup] - # (1,1,0) from Levin&Perez-Giz (2008) - x1s = [59.921203] - y1s = [1.570796] - z1s = [0.000000] - ux1s = [0.034020] - uy1s = [0.000000] - uz1s = [3.900000] - - # (4,1,1) from Levin&Perez-Giz (2008) - x2s = [68.600387] - y2s = [1.570796] - z2s = [0.000000] - ux2s = [0.029637] - uy2s = [0.000000] - uz2s = [3.900000] - -[output] - format = "hdf5" - - [output.fields] - enable = true - interval_time = 1.0 - quantities = ["D", "B"] - - [output.particles] - enable = true - stride = 1 - interval_time = 10.0 - species = [] - - [output.spectra] - enable = false - -[diagnostics] - interval = 10 - colored_stdout = true - blocking_timers = true diff --git a/setups/grpic/wald/pgen.hpp b/setups/grpic/wald/pgen.hpp index 8dd1a6e4e..b87d25ed2 100644 --- a/setups/grpic/wald/pgen.hpp +++ b/setups/grpic/wald/pgen.hpp @@ -61,9 +61,9 @@ namespace user { coord_t xi {ZERO}, x0m { ZERO }, x0p { ZERO }; metric.template convert(x_Ph, xi); - x0m[0] = xi[0] + HALF - HALF; + x0m[0] = xi[0] - HALF; x0m[1] = xi[1]; - x0p[0] = xi[0] + HALF + HALF; + x0p[0] = xi[0] + HALF; x0p[1] = xi[1]; real_t inv_sqrt_detH_ijP { ONE / metric.sqrt_det_h({ xi[0], xi[1] }) }; diff --git a/setups/grpic/wald/wald.toml b/setups/grpic/wald/wald.toml index 44d1c8a24..6e68d4324 100644 --- a/setups/grpic/wald/wald.toml +++ b/setups/grpic/wald/wald.toml @@ -1,7 +1,7 @@ [simulation] name = "wald" engine = "grpic" - runtime = 110.0 + runtime = 510.0 [grid] resolution = [128,128] @@ -21,14 +21,14 @@ ds = 0.5 [scales] - larmor0 = 1.0 #0.0025 - skindepth0 = 1.0 #0.05 + larmor0 = 0.0025 + skindepth0 = 0.05 [algorithms] current_filters = 4 [algorithms.timestep] - CFL = 0.3 + CFL = 0.5 [algorithms.toggles] deposit = false @@ -56,8 +56,8 @@ [setup] #multiplicity = 1.0 #sigma_max = 1000.0 - #inj_rmin = 1.2 - #inj_rmax = 7.5 + inj_rmin = 1.2 + inj_rmax = 7.5 [output] format = "hdf5" From 70edd434022261a954cdf7f44e83f0ba707975e2 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Wed, 18 Dec 2024 13:55:24 -0500 Subject: [PATCH 345/773] added separate setup for deposit debugging --- setups/grpic/deposit/deposit.toml | 91 ++++++++++++++++++++++++ setups/grpic/deposit/pgen.hpp | 113 ++++++++++++++++++++++++++++++ 2 files changed, 204 insertions(+) create mode 100644 setups/grpic/deposit/deposit.toml create mode 100644 setups/grpic/deposit/pgen.hpp diff --git a/setups/grpic/deposit/deposit.toml b/setups/grpic/deposit/deposit.toml new file mode 100644 index 000000000..359d4eaa7 --- /dev/null +++ b/setups/grpic/deposit/deposit.toml @@ -0,0 +1,91 @@ +[simulation] + name = "deposit" + engine = "grpic" + runtime = 10.0 + +[grid] + resolution = [512,512] + extent = [[1.2, 20.0]] + + [grid.metric] + metric = "kerr_schild" + qsph_r0 = 0.0 + qsph_h = 0.0 + ks_a = 0.0 + + [grid.boundaries] + fields = [["ABSORB"]] + particles = [["ABSORB"]] + + [grid.boundaries.absorb] + ds = 2.0 + +[scales] + larmor0 = 2.0 + skindepth0 = 2.0 + +[algorithms] + current_filters = 4 + + [algorithms.gr] + pusher_niter = 10 + pusher_eps = 1e-6 + + [algorithms.timestep] + CFL = 0.5 + + [algorithms.toggles] + deposit = true + fieldsolver = true + +[particles] + ppc0 = 1.0 + + [[particles.species]] + label = "e-" + mass = 1.0 + charge = -1.0 + maxnpart = 1e0 + + [[particles.species]] + label = "e+" + mass = 1.0 + charge = 1.0 + maxnpart = 1e0 + +[setup] + x1s = [17.00000] + y1s = [1.570796] + z1s = [0.000000] + ux1s = [8.000000] + uy1s = [0.000000] + uz1s = [0.000000] + + x2s = [17.00000] + y2s = [1.570796] + z2s = [0.000000] + ux2s = [-8.000000] + uy2s = [0.000000] + uz2s = [0.000000] + +[output] + format = "hdf5" + + [output.fields] + enable = true + interval_time = 0.5 + quantities = ["D", "B"] + + [output.particles] + enable = true + stride = 1 + interval_time = 0.5 + species = [] + + [output.spectra] + enable = false + +[diagnostics] + interval = 10 + colored_stdout = true + blocking_timers = true diff --git a/setups/grpic/deposit/pgen.hpp b/setups/grpic/deposit/pgen.hpp new file mode 100644 index 000000000..6d5e5fba5 --- /dev/null +++ b/setups/grpic/deposit/pgen.hpp @@ -0,0 +1,113 @@ +#ifndef PROBLEM_GENERATOR_H +#define PROBLEM_GENERATOR_H + +#include "enums.h" +#include "global.h" + +#include "arch/kokkos_aliases.h" +#include "arch/traits.h" +#include "utils/comparators.h" +#include "utils/formatting.h" +#include "utils/log.h" +#include "utils/numeric.h" + +#include "archetypes/problem_generator.h" +#include "framework/domain/metadomain.h" +#include "framework/domain/domain.h" +#include "archetypes/energy_dist.h" +#include "archetypes/particle_injector.h" + +#include + +namespace user { + using namespace ntt; + + template + struct InitFields { + InitFields(M metric_) : metric { metric_ } {} + + Inline auto A_3(const coord_t& x_Cd) const -> real_t { + coord_t x_Ph { ZERO }; + metric.template convert(x_Cd, x_Ph); + return HALF * SQR(x_Ph[0]) * SQR(math::sin(x_Ph[1])); + } + + Inline auto bx1(const coord_t& x_Ph) const -> real_t { + coord_t xi {ZERO}, x0m { ZERO }, x0p { ZERO }; + metric.template convert(x_Ph, xi); + + x0m[0] = xi[0]; + x0m[1] = xi[1] - HALF; + x0p[0] = xi[0]; + x0p[1] = xi[1] + HALF; + + real_t inv_sqrt_detH_ijP { ONE / metric.sqrt_det_h({ xi[0], xi[1] }) }; + + if (cmp::AlmostZero(x_Ph[1])) + return ONE; + else + return (A_3(x0p) - A_3(x0m)) * inv_sqrt_detH_ijP; + } + + Inline auto bx2(const coord_t& x_Ph) const -> real_t { + coord_t xi {ZERO}, x0m { ZERO }, x0p { ZERO }; + metric.template convert(x_Ph, xi); + + x0m[0] = xi[0] - HALF; + x0m[1] = xi[1]; + x0p[0] = xi[0] + HALF; + x0p[1] = xi[1]; + + real_t inv_sqrt_detH_ijP { ONE / metric.sqrt_det_h({ xi[0], xi[1] }) }; + if (cmp::AlmostZero(x_Ph[1])) + return ZERO; + else + return -(A_3(x0p) - A_3(x0m)) * inv_sqrt_detH_ijP; + } + + Inline auto bx3(const coord_t& x_Ph) const -> real_t { + return ZERO; + } + + Inline auto dx1(const coord_t& x_Ph) const -> real_t { + return ZERO; + } + + Inline auto dx2(const coord_t& x_Ph) const -> real_t { + return ZERO; + } + + Inline auto dx3(const coord_t& x_Ph) const -> real_t { + return ZERO; + } + + private: + const M metric; + }; + + template + struct PGen : public arch::ProblemGenerator { + // compatibility traits for the problem generator + static constexpr auto engines { traits::compatible_with::value }; + static constexpr auto metrics { + traits::compatible_with::value + }; + static constexpr auto dimensions { traits::compatible_with::value }; + + // for easy access to variables in the child class + using arch::ProblemGenerator::D; + using arch::ProblemGenerator::C; + using arch::ProblemGenerator::params; + + InitFields init_flds; + const Metadomain& global_domain; + inline PGen(const SimulationParams& p, const Metadomain& m) + : arch::ProblemGenerator { p } + , global_domain { m } + , init_flds { m.mesh().metric } {} + + }; + +} // namespace user + +#endif From 50818fc1fb0e5805528a3c424eb3441e58326de5 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Wed, 18 Dec 2024 13:57:33 -0500 Subject: [PATCH 346/773] deleted deposit test from pusher tests --- setups/grpic/pusher/deposit.toml | 91 -------------------------------- 1 file changed, 91 deletions(-) delete mode 100644 setups/grpic/pusher/deposit.toml diff --git a/setups/grpic/pusher/deposit.toml b/setups/grpic/pusher/deposit.toml deleted file mode 100644 index 359d4eaa7..000000000 --- a/setups/grpic/pusher/deposit.toml +++ /dev/null @@ -1,91 +0,0 @@ -[simulation] - name = "deposit" - engine = "grpic" - runtime = 10.0 - -[grid] - resolution = [512,512] - extent = [[1.2, 20.0]] - - [grid.metric] - metric = "kerr_schild" - qsph_r0 = 0.0 - qsph_h = 0.0 - ks_a = 0.0 - - [grid.boundaries] - fields = [["ABSORB"]] - particles = [["ABSORB"]] - - [grid.boundaries.absorb] - ds = 2.0 - -[scales] - larmor0 = 2.0 - skindepth0 = 2.0 - -[algorithms] - current_filters = 4 - - [algorithms.gr] - pusher_niter = 10 - pusher_eps = 1e-6 - - [algorithms.timestep] - CFL = 0.5 - - [algorithms.toggles] - deposit = true - fieldsolver = true - -[particles] - ppc0 = 1.0 - - [[particles.species]] - label = "e-" - mass = 1.0 - charge = -1.0 - maxnpart = 1e0 - - [[particles.species]] - label = "e+" - mass = 1.0 - charge = 1.0 - maxnpart = 1e0 - -[setup] - x1s = [17.00000] - y1s = [1.570796] - z1s = [0.000000] - ux1s = [8.000000] - uy1s = [0.000000] - uz1s = [0.000000] - - x2s = [17.00000] - y2s = [1.570796] - z2s = [0.000000] - ux2s = [-8.000000] - uy2s = [0.000000] - uz2s = [0.000000] - -[output] - format = "hdf5" - - [output.fields] - enable = true - interval_time = 0.5 - quantities = ["D", "B"] - - [output.particles] - enable = true - stride = 1 - interval_time = 0.5 - species = [] - - [output.spectra] - enable = false - -[diagnostics] - interval = 10 - colored_stdout = true - blocking_timers = true From 8e04145ed37722b1d77c67f815a82ad6a48235e8 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Wed, 18 Dec 2024 15:58:12 -0500 Subject: [PATCH 347/773] communication should be for j0 for GRPIC --- src/framework/domain/communications.cpp | 73 ++++++++++++++++++------- 1 file changed, 54 insertions(+), 19 deletions(-) diff --git a/src/framework/domain/communications.cpp b/src/framework/domain/communications.cpp index 7dc5d285a..728d8fba2 100644 --- a/src/framework/domain/communications.cpp +++ b/src/framework/domain/communications.cpp @@ -303,11 +303,10 @@ namespace ntt { comp_range_fld, false); } - } - if (comm_j) { + if (comm_j) { comm::CommunicateField(domain.index(), - domain.fields.cur, - domain.fields.cur, + domain.fields.cur0, + domain.fields.cur0, send_ind, recv_ind, send_rank, @@ -316,6 +315,21 @@ namespace ntt { recv_slice, comp_range_cur, false); + } + } else { + if (comm_j) { + comm::CommunicateField(domain.index(), + domain.fields.cur, + domain.fields.cur, + send_ind, + recv_ind, + send_rank, + recv_rank, + send_slice, + recv_slice, + comp_range_cur, + false); + } } } } @@ -435,17 +449,31 @@ namespace ntt { continue; } if (comm_j) { - comm::CommunicateField(domain.index(), - domain.fields.cur, - domain.fields.buff, - send_ind, - recv_ind, - send_rank, - recv_rank, - send_slice, - recv_slice, - comp_range_cur, - synchronize); + if constexpr (S == SimEngine::GRPIC) { + comm::CommunicateField(domain.index(), + domain.fields.cur0, + domain.fields.buff, + send_ind, + recv_ind, + send_rank, + recv_rank, + send_slice, + recv_slice, + comp_range_cur, + synchronize); + } else { + comm::CommunicateField(domain.index(), + domain.fields.cur, + domain.fields.buff, + send_ind, + recv_ind, + send_rank, + recv_rank, + send_slice, + recv_slice, + comp_range_cur, + synchronize); + } } if (comm_bckp) { comm::CommunicateField(domain.index(), @@ -475,10 +503,17 @@ namespace ntt { } } if (comm_j) { - AddBufferedFields(domain.fields.cur, - domain.fields.buff, - domain.mesh.rangeActiveCells(), - comp_range_cur); + if constexpr (S == SimEngine::GRPIC) { + AddBufferedFields(domain.fields.cur0, + domain.fields.buff, + domain.mesh.rangeActiveCells(), + comp_range_cur); + } else { + AddBufferedFields(domain.fields.cur, + domain.fields.buff, + domain.mesh.rangeActiveCells(), + comp_range_cur); + } } if (comm_bckp) { AddBufferedFields(domain.fields.bckp, From 277bccf6aaf29f088c4f9ea83c4bd41a72e1a190 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Wed, 18 Dec 2024 15:59:21 -0500 Subject: [PATCH 348/773] 1. implemented working boundary conditions for currents, 2. fixed normaliation for AmpereCurrents -- currents should not be normilized as they are used repeatedl3. minor style --- src/engines/grpic.hpp | 22 +++++++++++----------- src/kernels/fields_bcs.hpp | 12 +++++------- 2 files changed, 16 insertions(+), 18 deletions(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index a4bffadf2..10ea9258a 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -374,9 +374,9 @@ namespace ntt { m_metadomain.CommunicateFields(dom, Comm::J); timers.stop("Communications"); - // timers.start("FieldBoundaries"); - // CurrentsBoundaryConditions(); - // timers.stop("FieldBoundaries"); + timers.start("FieldBoundaries"); + CurrentsBoundaryConditions(dom); + timers.stop("FieldBoundaries"); timers.start("CurrentFiltering"); CurrentsFilter(dom); @@ -660,9 +660,9 @@ namespace ntt { "AbsorbCurrent", CreateRangePolicy(range_min, range_max), kernel::AbsorbCurrentGR_kernel(domain.fields.cur0, - domain.mesh.metric, - xg_edge, - ds)); + domain.mesh.metric, + xg_edge, + ds)); } void OpenFieldsIn(dir::direction_t direction, @@ -918,7 +918,7 @@ namespace ntt { const auto q0 = m_params.template get("scales.q0"); const auto n0 = m_params.template get("scales.n0"); const auto B0 = m_params.template get("scales.B0"); - const auto coeff = -dt * q0 * n0 / B0; + const auto coeff = -dt * q0 / B0; // auto range = range_with_axis_BCs(domain); auto range = CreateRangePolicy( { domain.mesh.i_min(in::x1), domain.mesh.i_min(in::x2)}, @@ -968,7 +968,7 @@ namespace ntt { } void CurrentsDeposit(domain_t& domain) { - auto scatter_cur = Kokkos::Experimental::create_scatter_view( + auto scatter_cur0 = Kokkos::Experimental::create_scatter_view( domain.fields.cur0); for (auto& species : domain.species) { logger::Checkpoint( @@ -984,7 +984,7 @@ namespace ntt { Kokkos::parallel_for("CurrentsDeposit", species.rangeActiveParticles(), kernel::DepositCurrents_kernel( - scatter_cur, + scatter_cur0, species.i1, species.i2, species.i3, @@ -1007,7 +1007,7 @@ namespace ntt { (real_t)(species.charge()), dt)); } - Kokkos::Experimental::contribute(domain.fields.cur0, scatter_cur); + Kokkos::Experimental::contribute(domain.fields.cur0, scatter_cur0); } void CurrentsFilter(domain_t& domain) { @@ -1031,7 +1031,7 @@ namespace ntt { domain.fields.buff, size, domain.mesh.flds_bc())); - m_metadomain.CommunicateFields(domain, Comm::J); + m_metadomain.CommunicateFields(domain, Comm::J); //J0 } } diff --git a/src/kernels/fields_bcs.hpp b/src/kernels/fields_bcs.hpp index 3a949671a..ee6604577 100644 --- a/src/kernels/fields_bcs.hpp +++ b/src/kernels/fields_bcs.hpp @@ -1026,18 +1026,15 @@ namespace kernel::bc { const M metric; const real_t xg_edge; const real_t dx_abs; - const BCTags tags; AbsorbCurrentGR_kernel(ndfield_t J, const M& metric, real_t xg_edge, - real_t dx_abs, - BCTags tags) + real_t dx_abs) : J { J } , metric { metric } , xg_edge { xg_edge } - , dx_abs { dx_abs } - , tags { tags } {} + , dx_abs { dx_abs } {} Inline void operator()(index_t i1, index_t i2) const { if constexpr (M::Dim == Dim::_2D) { @@ -1048,8 +1045,9 @@ namespace kernel::bc { x_Cd[1] = i2_; const auto dx = math::abs( metric.template convert(x_Cd[i - 1]) - xg_edge); - J(i1, i2) *= math::tanh(dx / (INV_4 * dx_abs)); - + J(i1, i2, cur::jx1) *= math::tanh(dx / (INV_4 * dx_abs)); + J(i1, i2, cur::jx2) *= math::tanh(dx / (INV_4 * dx_abs)); + J(i1, i2, cur::jx3) *= math::tanh(dx / (INV_4 * dx_abs)); } else { raise::KernelError( HERE, From cc07d4501aad8200fc3cd23286b5d1e7202b739d Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Wed, 18 Dec 2024 16:03:25 -0500 Subject: [PATCH 349/773] improved setup for deposit testing --- setups/grpic/deposit/deposit.py | 53 +++++++++++++++++++++ setups/grpic/deposit/deposit.toml | 12 ++--- setups/grpic/deposit/pgen.hpp | 79 ++++++++++++++++++------------- 3 files changed, 104 insertions(+), 40 deletions(-) create mode 100644 setups/grpic/deposit/deposit.py diff --git a/setups/grpic/deposit/deposit.py b/setups/grpic/deposit/deposit.py new file mode 100644 index 000000000..e3aa97dfc --- /dev/null +++ b/setups/grpic/deposit/deposit.py @@ -0,0 +1,53 @@ +import nt2.read as nt2r +import matplotlib as mpl +import matplotlib.pyplot as plt +import numpy as np + +data = nt2r.Data("deposit.h5") +def frame(ti): + t0 = data.t.isel(t=ti).values[()] + vmax = 1e-5 + fig, ax = plt.subplots(figsize=(6, 8), dpi=150) + data.Dr.isel(t=ti).polar.pcolor( + ax=ax, + norm=mpl.colors.SymLogNorm( + vmin=-vmax, vmax=vmax, linthresh=vmax / 1e3, linscale=1 + ), + cmap="RdBu_r", + ) + x1, x2 = data.particles[1].isel(t=ti).r * np.sin( + data.particles[1].isel(t=ti).th + ), data.particles[1].isel(t=ti).r * np.cos(data.particles[1].isel(t=ti).th) + ax.scatter(x1, x2, s=5, c="b", ec="w", lw=0.5) + x1, x2 = data.particles[2].isel(t=ti).r * np.sin( + data.particles[2].isel(t=ti).th + ), data.particles[2].isel(t=ti).r * np.cos(data.particles[2].isel(t=ti).th) + ax.scatter(x1, x2, s=5, c="r", ec="w", lw=0.5) + ax.add_artist( + mpl.patches.Arc( + (0, 0), + 2 * 10, + 2 * 10, + fill=False, + ec="k", + ls=":", + lw=0.5, + theta1=-90, + theta2=90, + ) + ) + axins = ax.inset_axes([0.4, 0.8, 0.6 - 0.025, 0.2 - 0.01]) + ( + data.Dr.sel(t=slice(data.t.min(), t0)).sel(r=10, method="nearest") + * np.sin(data.th) + ).sum(dim="th").plot(ax=axins) + axins.set( + ylim=(-3 * vmax, 3 * vmax), + xlim=(data.t.min(), data.t.max()), + title="", + ylabel=rf"$\int D_r d\Omega$ @ (r = 10)", + ) + axins.axvline(t0, color="b", lw=0.5, ls=":") + axins.axhline(0, color="r", lw=0.5, ls="--") + +frame(30) \ No newline at end of file diff --git a/setups/grpic/deposit/deposit.toml b/setups/grpic/deposit/deposit.toml index 359d4eaa7..c577f9c68 100644 --- a/setups/grpic/deposit/deposit.toml +++ b/setups/grpic/deposit/deposit.toml @@ -1,7 +1,7 @@ [simulation] name = "deposit" engine = "grpic" - runtime = 10.0 + runtime = 50.0 [grid] resolution = [512,512] @@ -21,8 +21,8 @@ ds = 2.0 [scales] - larmor0 = 2.0 - skindepth0 = 2.0 + larmor0 = 2e-3 + skindepth0 = 0.1 [algorithms] current_filters = 4 @@ -57,14 +57,14 @@ x1s = [17.00000] y1s = [1.570796] z1s = [0.000000] - ux1s = [8.000000] + ux1s = [5.000000] uy1s = [0.000000] uz1s = [0.000000] x2s = [17.00000] y2s = [1.570796] z2s = [0.000000] - ux2s = [-8.000000] + ux2s = [-5.000000] uy2s = [0.000000] uz2s = [0.000000] @@ -74,7 +74,7 @@ [output.fields] enable = true interval_time = 0.5 - quantities = ["D", "B"] + quantities = ["D"] [output.particles] enable = true diff --git a/setups/grpic/deposit/pgen.hpp b/setups/grpic/deposit/pgen.hpp index 6d5e5fba5..8ff89fa92 100644 --- a/setups/grpic/deposit/pgen.hpp +++ b/setups/grpic/deposit/pgen.hpp @@ -26,43 +26,12 @@ namespace user { struct InitFields { InitFields(M metric_) : metric { metric_ } {} - Inline auto A_3(const coord_t& x_Cd) const -> real_t { - coord_t x_Ph { ZERO }; - metric.template convert(x_Cd, x_Ph); - return HALF * SQR(x_Ph[0]) * SQR(math::sin(x_Ph[1])); - } - Inline auto bx1(const coord_t& x_Ph) const -> real_t { - coord_t xi {ZERO}, x0m { ZERO }, x0p { ZERO }; - metric.template convert(x_Ph, xi); - - x0m[0] = xi[0]; - x0m[1] = xi[1] - HALF; - x0p[0] = xi[0]; - x0p[1] = xi[1] + HALF; - - real_t inv_sqrt_detH_ijP { ONE / metric.sqrt_det_h({ xi[0], xi[1] }) }; - - if (cmp::AlmostZero(x_Ph[1])) - return ONE; - else - return (A_3(x0p) - A_3(x0m)) * inv_sqrt_detH_ijP; + return ZERO; } Inline auto bx2(const coord_t& x_Ph) const -> real_t { - coord_t xi {ZERO}, x0m { ZERO }, x0p { ZERO }; - metric.template convert(x_Ph, xi); - - x0m[0] = xi[0] - HALF; - x0m[1] = xi[1]; - x0p[0] = xi[0] + HALF; - x0p[1] = xi[1]; - - real_t inv_sqrt_detH_ijP { ONE / metric.sqrt_det_h({ xi[0], xi[1] }) }; - if (cmp::AlmostZero(x_Ph[1])) - return ZERO; - else - return -(A_3(x0p) - A_3(x0m)) * inv_sqrt_detH_ijP; + return ZERO; } Inline auto bx3(const coord_t& x_Ph) const -> real_t { @@ -105,7 +74,49 @@ namespace user { : arch::ProblemGenerator { p } , global_domain { m } , init_flds { m.mesh().metric } {} - + + inline void InitPrtls(Domain& local_domain) { + const auto empty = std::vector {}; + const auto x1s = params.template get>("setup.x1s", empty); + const auto y1s = params.template get>("setup.y1s", empty); + const auto z1s = params.template get>("setup.z1s", empty); + const auto ux1s = params.template get>("setup.ux1s", + empty); + const auto uy1s = params.template get>("setup.uy1s", + empty); + const auto uz1s = params.template get>("setup.uz1s", + empty); + + const auto x2s = params.template get>("setup.x2s", empty); + const auto y2s = params.template get>("setup.y2s", empty); + const auto z2s = params.template get>("setup.z2s", empty); + const auto ux2s = params.template get>("setup.ux2s", + empty); + const auto uy2s = params.template get>("setup.uy2s", + empty); + const auto uz2s = params.template get>("setup.uz2s", + empty); + const std::map> data_1 { + { "x1", x1s}, + { "x2", y1s}, + { "phi", z1s}, + {"ux1", ux1s}, + {"ux2", uy1s}, + {"ux3", uz1s} + }; + const std::map> data_2 { + { "x1", x2s}, + { "x2", y2s}, + { "phi", z2s}, + {"ux1", ux2s}, + {"ux2", uy2s}, + {"ux3", uz2s} + }; + + arch::InjectGlobally(global_domain, local_domain, (arch::spidx_t)1, data_1); + arch::InjectGlobally(global_domain, local_domain, (arch::spidx_t)2, data_2); + } + // inline PGen() {} }; } // namespace user From d2df46782211630b9ab56f345d8a150692a28f6d Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Thu, 2 Jan 2025 15:33:52 -0500 Subject: [PATCH 350/773] minor fix for qks --- src/metrics/qkerr_schild.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/metrics/qkerr_schild.h b/src/metrics/qkerr_schild.h index e45376a24..e3d849952 100644 --- a/src/metrics/qkerr_schild.h +++ b/src/metrics/qkerr_schild.h @@ -255,7 +255,7 @@ namespace metric { const real_t r { r0 + math::exp(x[0] * dchi + chi_min) }; const real_t eta {x[1] * deta + eta_min }; const real_t theta { eta2theta(eta) }; - const real_t dx_dt {deta * (ONE + TWO * h0 * constant::INV_PI_SQR * (TWO * THREE * SQR(eta) - TWO * THREE * constant::PI * eta + constant::PI_SQR)) }; + const real_t dx_dt {deta * (ONE + TWO * h0 * static_cast(constant::INV_PI_SQR) * (TWO * THREE * SQR(eta) - TWO * THREE * static_cast(constant::PI) * eta + static_cast(constant::PI_SQR))) }; const real_t dt_Sigma {- TWO * SQR(a) * math::sin(theta) * math::cos(theta) * dx_dt}; return r * dt_Sigma * CUBE(alpha(x)) / SQR(Sigma(r, theta)); From 68aeddc8e8431256b66335db3eb837647206d8fc Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Thu, 2 Jan 2025 15:52:50 -0500 Subject: [PATCH 351/773] minor for engines/grpic --- src/engines/grpic.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index 10ea9258a..18ba4db0b 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -744,6 +744,7 @@ namespace ntt { (void)direction; (void)domain; (void)tags; + (void)g; raise::Error("Custom boundaries not implemented", HERE); // if constexpr ( // traits::has_member::value) { @@ -916,7 +917,7 @@ namespace ntt { void AmpereCurrents(domain_t& domain, const gr_ampere& g) { logger::Checkpoint("Launching Ampere kernel for adding currents", HERE); const auto q0 = m_params.template get("scales.q0"); - const auto n0 = m_params.template get("scales.n0"); + // const auto n0 = m_params.template get("scales.n0"); const auto B0 = m_params.template get("scales.B0"); const auto coeff = -dt * q0 / B0; // auto range = range_with_axis_BCs(domain); From 4e873ffde63da1965dfb4a7bb3c21f326b92a9ce Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Fri, 3 Jan 2025 15:01:25 -0500 Subject: [PATCH 352/773] implementing threshold-dependent injection is in progress --- setups/grpic/wald/pgen.hpp | 211 ++++++++++++++++++++++++++++-------- setups/grpic/wald/wald.toml | 48 ++++---- 2 files changed, 188 insertions(+), 71 deletions(-) diff --git a/setups/grpic/wald/pgen.hpp b/setups/grpic/wald/pgen.hpp index b87d25ed2..457c24107 100644 --- a/setups/grpic/wald/pgen.hpp +++ b/setups/grpic/wald/pgen.hpp @@ -7,8 +7,13 @@ #include "arch/kokkos_aliases.h" #include "arch/traits.h" +#include "archetypes/energy_dist.h" +#include "archetypes/spatial_dist.h" +#include "archetypes/particle_injector.h" #include "archetypes/problem_generator.h" #include "framework/domain/metadomain.h" +#include "kernels/particle_moments.hpp" +#include "utils/numeric.h" namespace user { using namespace ntt; @@ -18,26 +23,12 @@ namespace user { InitFields(M metric_) : metric { metric_ } {} Inline auto A_3(const coord_t& x_Cd) const -> real_t { - // return HALF * (metric.template h_<3, 3>(x_Cd) - // + TWO * metric.spin() * metric.template h_<1, 3>(x_Cd) * metric.beta1(x_Cd) - // ); - coord_t x_Ph { ZERO }; - metric.template convert(x_Cd, x_Ph); - return HALF * SQR(x_Ph[0]) * SQR(math::sin(x_Ph[1])); - } - - Inline auto A_1(const coord_t& x_Cd) const -> real_t { - return HALF * (metric.template h_<1, 3>(x_Cd) - + TWO * metric.spin() * metric.template h_<1, 1>(x_Cd) * metric.beta1(x_Cd) + return HALF * (metric.template h_<3, 3>(x_Cd) + + TWO * metric.spin() * metric.template h_<1, 3>(x_Cd) * metric.beta1(x_Cd) ); - } - - Inline auto A_0(const coord_t& x_Cd) const -> real_t { - real_t g_00 { -metric.alpha(x_Cd) * metric.alpha(x_Cd) - + metric.template h_<1, 1>(x_Cd) * metric.beta1(x_Cd) * metric.beta1(x_Cd) - }; - return HALF * (metric.template h_<1, 3>(x_Cd) * metric.beta1(x_Cd) - + TWO * metric.spin() * g_00); + // coord_t x_Ph { ZERO }; + // metric.template convert(x_Cd, x_Ph); + // return HALF * SQR(x_Ph[0]) * SQR(math::sin(x_Ph[1])); } Inline auto bx1(const coord_t& x_Ph) const -> real_t { @@ -74,16 +65,6 @@ namespace user { } Inline auto bx3(const coord_t& x_Ph) const -> real_t { - // coord_t xi {ZERO}, x0m { ZERO }, x0p { ZERO }; - // metric.template convert(x_Ph, xi); - - // x0m[0] = xi[0] + HALF - HALF; - // x0m[1] = xi[1]; - // x0p[0] = xi[0] + HALF + HALF; - // x0p[1] = xi[1]; - - // real_t inv_sqrt_detH_ijP { ONE / metric.sqrt_det_h({ xi[0], xi[1] }) }; - // return -(A_1(x0p) - A_1(x0m)) * inv_sqrt_detH_ijP; return ZERO; } @@ -103,6 +84,105 @@ namespace user { const M metric; }; + template + struct PointDistribution : public arch::SpatialDistribution { + PointDistribution(const std::vector& xi_min, + const std::vector& xi_max, + const real_t sigma_thr, + const real_t dens_thr, + long double time, + const SimulationParams& params, + Domain* domain_ptr + ) + : arch::SpatialDistribution { domain_ptr->mesh.metric } + , metric { domain_ptr->mesh.metric } + , EM { domain_ptr->fields.em } + , sigma_thr {sigma_thr} + , dens_thr {dens_thr} + , time {time} { + std::copy(xi_min.begin(), xi_min.end(), x_min); + std::copy(xi_max.begin(), xi_max.end(), x_max); + + std::vector specs {}; + for (auto& sp : domain_ptr->species) { + if (sp.mass() > 0) { + specs.push_back(sp.index()); + } + } + + auto scatter_buff = Kokkos::Experimental::create_scatter_view(domain_ptr->fields.buff); + printf("%f\n", domain_ptr->fields.buff(10, 10, 0)); + // some parameters + auto& mesh = domain_ptr->mesh; + const auto use_weights = params.template get("particles.use_weights"); + const auto ni2 = mesh.n_active(in::x2); + const auto inv_n0 = ONE / params.template get("scales.n0"); + + for (const auto& sp : specs) { + auto& prtl_spec = domain_ptr->species[sp - 1]; + // clang-format off + Kokkos::parallel_for( + "ComputeMoments", + prtl_spec.rangeActiveParticles(), + kernel::ParticleMoments_kernel({}, scatter_buff, 0u, + prtl_spec.i1, prtl_spec.i2, prtl_spec.i3, + prtl_spec.dx1, prtl_spec.dx2, prtl_spec.dx3, + prtl_spec.ux1, prtl_spec.ux2, prtl_spec.ux3, + prtl_spec.phi, prtl_spec.weight, prtl_spec.tag, + prtl_spec.mass(), prtl_spec.charge(), + use_weights, + metric, mesh.flds_bc(), + ni2, inv_n0, 0)); + // clang-format on + } + Kokkos::Experimental::contribute(domain_ptr->fields.buff, scatter_buff); + // auto density = domain_ptr->fields.buff; + auto density = Kokkos::create_mirror_view(domain_ptr->fields.buff); + Kokkos::deep_copy(density, domain_ptr->fields.buff); + } + + Inline auto sigma_crit(const coord_t& x_Ph) const -> real_t { + coord_t xi {ZERO}; + if constexpr (M::Dim == Dim::_2D) { + metric.template convert(x_Ph, xi); + const auto i1 = static_cast(xi[0]) + static_cast(N_GHOSTS); + const auto i2 = static_cast(xi[1]) + static_cast(N_GHOSTS); + // printf("%f %f\n", xi[0], xi[1]); + const vec_t B_cntrv { EM(i1, i2, em::bx1), EM(i1, i2, em::bx2), EM(i1, i2, em::bx3) }; + vec_t B_cov { ZERO }; + metric.template transform(xi, B_cntrv, B_cov); + const auto bsqr = DOT(B_cntrv[0], B_cntrv[1], B_cntrv[2], B_cov[0], B_cov[1], B_cov[2]); + const auto dens = density(i1, i2, 0); + // printf("%f\n", domain_ptr->fields.buff(10, 10, 0)); + // return (bsqr / dens > sigma_thr) || (dens < dens_thr); + return 2.0; + } + return ZERO; + } + + Inline auto operator()(const coord_t& x_Ph) const -> real_t override { + auto fill = true; + for (auto d = 0u; d < M::Dim; ++d) { + fill &= x_Ph[d] > x_min[d] and x_Ph[d] < x_max[d]; + } + if (time > ZERO) { + fill &= sigma_crit(x_Ph) > ONE; + } + return fill ? ONE : ZERO; + } + + private: + tuple_t x_min; + tuple_t x_max; + const real_t sigma_thr; + const real_t dens_thr; + long double time, + Domain* domain_ptr; + ndfield_t density; + ndfield_t EM; + const M metric; + }; + template struct PGen : public arch::ProblemGenerator { // compatibility traits for the problem generator @@ -117,30 +197,67 @@ namespace user { using arch::ProblemGenerator::C; using arch::ProblemGenerator::params; + const std::vector xi_min; + const std::vector xi_max; + const real_t sigma0, sigma_max, multiplicity, nGJ; + InitFields init_flds; inline PGen(SimulationParams& p, const Metadomain& m) : arch::ProblemGenerator(p) - // , xi_min { p.template get>("setup.inj_rmin") } - // , xi_max { p.template get>("setup.inj_rmax") } + , xi_min { p.template get>("setup.xi_min") } + , xi_max { p.template get>("setup.xi_max") } + , sigma_max { p.template get("setup.sigma_max") } + , sigma0 { p.template get("scales.sigma0") } + , multiplicity { p.template get("setup.multiplicity") } + , nGJ { p.template get("scales.B0") * SQR(p.template get("scales.skindepth0")) } //m.mesh().metric.spin() * , init_flds { m.mesh().metric } {} - // inline void InitPrtls(Domain& local_domain) { - // const auto energy_dist = arch::ColdDist(local_domain.mesh.metric); - // const auto spatial_dist = PointDistribution(domain.mesh.metric, - // xi_min, - // xi_max); - // const auto injector = arch::NonUniformInjector( - // energy_dist, - // spatial_dist, - // { 1, 2 }); - // arch::InjectNonUniform>(params, - // local_domain, - // injector, - // 1.0); - // } - - // inline PGen() {} + inline void InitPrtls(Domain& local_domain) { + const auto energy_dist = arch::ColdDist(local_domain.mesh.metric); + const auto spatial_dist = PointDistribution(xi_min, + xi_max, + sigma_max / sigma0, + multiplicity * nGJ, + ZERO, + params, + &local_domain + ); + + const auto injector = arch::NonUniformInjector( + energy_dist, + spatial_dist, + { 1, 2 }); + arch::InjectNonUniform(params, + local_domain, + injector, + 1.0, + true); + } + + void CustomPostStep(std::size_t, long double time, Domain& local_domain) { + // const auto energy_dist = arch::ColdDist(local_domain.mesh.metric); + // const auto spatial_dist = PointDistribution(local_domain.mesh.metric, + // xi_min, + // xi_max); + + // const auto spatial_dist = ReplenishDist(local_domain.mesh.metric, + // const ndfield_t& density, + // unsigned short idx, + // const T& target_density, + // real_t target_max_density) + + // const auto injector = arch::NonUniformInjector( + // energy_dist, + // spatial_dist, + // { 1, 2 }); + // arch::InjectNonUniform(params, + // local_domain, + // injector, + // 1.0, + // true); + } + }; } // namespace user diff --git a/setups/grpic/wald/wald.toml b/setups/grpic/wald/wald.toml index 6e68d4324..2f12705de 100644 --- a/setups/grpic/wald/wald.toml +++ b/setups/grpic/wald/wald.toml @@ -1,17 +1,17 @@ [simulation] name = "wald" engine = "grpic" - runtime = 510.0 + runtime = 100.0 [grid] - resolution = [128,128] - extent = [[2.0, 8.0]] + resolution = [256,256] + extent = [[0.8, 8.0]] [grid.metric] metric = "qkerr_schild" qsph_r0 = 0.0 qsph_h = 0.0 - ks_a = 0.0 + ks_a = 0.95 [grid.boundaries] fields = [["ABSORB"]] @@ -31,7 +31,7 @@ CFL = 0.5 [algorithms.toggles] - deposit = false + deposit = true fieldsolver = true [particles] @@ -39,33 +39,33 @@ use_weights = true sort_interval = 100 - #[[particles.species]] - #label = "e-" - #mass = 1.0 - #charge = -1.0 - #maxnpart = 1e6 - #pusher = "Boris" - # - #[[particles.species]] - #label = "e+" - #mass = 1.0 - #charge = 1.0 - #maxnpart = 1e6 - #pusher = "Boris" + [[particles.species]] + label = "e-" + mass = 1.0 + charge = -1.0 + maxnpart = 1e6 + pusher = "Boris" + + [[particles.species]] + label = "e+" + mass = 1.0 + charge = 1.0 + maxnpart = 1e6 + pusher = "Boris" [setup] - #multiplicity = 1.0 - #sigma_max = 1000.0 - inj_rmin = 1.2 - inj_rmax = 7.5 + multiplicity = 1.0 + sigma_max = 10.0 + xi_min = [1.2, 0.1] + xi_max = [7.5, 3.04159265] [output] format = "hdf5" [output.fields] interval_time = 1.0 - quantities = ["D", "H", "B", "J"] - + quantities = ["D", "B", "J", "N_1", "N_2", "Nppc_1", "Nppc_2"] + [output.particles] enable = false From 32fcfaf9dfa4ce45f4af7202de814881f0a17a39 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Fri, 3 Jan 2025 16:57:41 -0500 Subject: [PATCH 353/773] updated pgen --- setups/grpic/wald/pgen.hpp | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/setups/grpic/wald/pgen.hpp b/setups/grpic/wald/pgen.hpp index 457c24107..78f922700 100644 --- a/setups/grpic/wald/pgen.hpp +++ b/setups/grpic/wald/pgen.hpp @@ -90,7 +90,6 @@ namespace user { const std::vector& xi_max, const real_t sigma_thr, const real_t dens_thr, - long double time, const SimulationParams& params, Domain* domain_ptr ) @@ -98,8 +97,7 @@ namespace user { , metric { domain_ptr->mesh.metric } , EM { domain_ptr->fields.em } , sigma_thr {sigma_thr} - , dens_thr {dens_thr} - , time {time} { + , dens_thr {dens_thr} { std::copy(xi_min.begin(), xi_min.end(), x_min); std::copy(xi_max.begin(), xi_max.end(), x_max); @@ -136,7 +134,6 @@ namespace user { // clang-format on } Kokkos::Experimental::contribute(domain_ptr->fields.buff, scatter_buff); - // auto density = domain_ptr->fields.buff; auto density = Kokkos::create_mirror_view(domain_ptr->fields.buff); Kokkos::deep_copy(density, domain_ptr->fields.buff); } @@ -147,7 +144,6 @@ namespace user { metric.template convert(x_Ph, xi); const auto i1 = static_cast(xi[0]) + static_cast(N_GHOSTS); const auto i2 = static_cast(xi[1]) + static_cast(N_GHOSTS); - // printf("%f %f\n", xi[0], xi[1]); const vec_t B_cntrv { EM(i1, i2, em::bx1), EM(i1, i2, em::bx2), EM(i1, i2, em::bx3) }; vec_t B_cov { ZERO }; metric.template transform(xi, B_cntrv, B_cov); @@ -163,10 +159,7 @@ namespace user { Inline auto operator()(const coord_t& x_Ph) const -> real_t override { auto fill = true; for (auto d = 0u; d < M::Dim; ++d) { - fill &= x_Ph[d] > x_min[d] and x_Ph[d] < x_max[d]; - } - if (time > ZERO) { - fill &= sigma_crit(x_Ph) > ONE; + fill &= x_Ph[d] > x_min[d] and x_Ph[d] < x_max[d] and sigma_crit(x_Ph) > ONE; } return fill ? ONE : ZERO; } @@ -176,7 +169,6 @@ namespace user { tuple_t x_max; const real_t sigma_thr; const real_t dens_thr; - long double time, Domain* domain_ptr; ndfield_t density; ndfield_t EM; @@ -219,7 +211,6 @@ namespace user { xi_max, sigma_max / sigma0, multiplicity * nGJ, - ZERO, params, &local_domain ); From 5ba83978500f092cd2ad9c433dfc8ddbab900a7d Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Fri, 3 Jan 2025 17:19:57 -0500 Subject: [PATCH 354/773] minor --- setups/grpic/wald/pgen.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/setups/grpic/wald/pgen.hpp b/setups/grpic/wald/pgen.hpp index 78f922700..41d9a2462 100644 --- a/setups/grpic/wald/pgen.hpp +++ b/setups/grpic/wald/pgen.hpp @@ -108,6 +108,7 @@ namespace user { } } + Kokkos::deep_copy(domain_ptr->fields.buff, ZERO); auto scatter_buff = Kokkos::Experimental::create_scatter_view(domain_ptr->fields.buff); printf("%f\n", domain_ptr->fields.buff(10, 10, 0)); // some parameters From fdf2e738cd0dc769628602125c17f8baa75ec816 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Wed, 8 Jan 2025 19:14:18 -0500 Subject: [PATCH 355/773] implemented output of Aph for 2d GRPIC --- src/framework/domain/output.cpp | 44 +++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/src/framework/domain/output.cpp b/src/framework/domain/output.cpp index ae138bac1..c13e354b3 100644 --- a/src/framework/domain/output.cpp +++ b/src/framework/domain/output.cpp @@ -185,6 +185,39 @@ namespace ntt { } } + template + void ComputeVectorPotential(ndfield_t& buffer, + ndfield_t& EM, + unsigned short buff_idx, + const Mesh mesh) { + if constexpr (M::Dim == Dim::_2D) { + const auto i2_min = mesh.i_min(in::x2); + // !TODO: this is quite slow + Kokkos::parallel_for( + "ComputeVectorPotential", + mesh.rangeActiveCells(), + Lambda(index_t i, index_t j) { + const real_t i_ { static_cast(static_cast(i) - (N_GHOSTS)) }; + const auto k_min = (i2_min - (N_GHOSTS)) + 1; + const auto k_max = (j - (N_GHOSTS)); + real_t A3 = ZERO; + for (auto k { k_min }; k <= k_max; ++k) { + real_t k_ = static_cast(k); + real_t sqrt_detH_ij1 { mesh.metric.sqrt_det_h({ i_, k_ - HALF }) }; + real_t sqrt_detH_ij2 { mesh.metric.sqrt_det_h({ i_, k_ + HALF }) }; + auto k1 { k + N_GHOSTS }; + A3 += HALF * (sqrt_detH_ij1 * EM(i, k1 - 1, em::bx1) + + sqrt_detH_ij2 * EM(i, k1, em::bx1)); + } + buffer(i, j, buff_idx) = A3; + }); + } else { + raise::KernelError( + HERE, + "ComputeVectorPotential: 2D implementation called for D != 2"); + } + } + template auto Metadomain::Write( const SimulationParams& params, @@ -347,6 +380,17 @@ namespace ntt { raise::Error("Custom output requested but no function provided", HERE); } + } else if (fld.is_vpotential()) { + if (S == SimEngine::GRPIC && M::Dim == Dim::_2D) { + const auto c = static_cast(addresses.back()); + ComputeVectorPotential(local_domain->fields.bckp, + local_domain->fields.em, + c, + local_domain->mesh); + } else { + raise::Error("Vector potential can only be computed for GRPIC in 2D", + HERE); + } } else { raise::Error("Wrong # of components requested for " "non-moment/non-custom output", From 1d11b58bfdb2bc0dec3376f9a6453f62ea626ef6 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Wed, 8 Jan 2025 19:17:43 -0500 Subject: [PATCH 356/773] updated pgen for wald solution with plasma --- setups/grpic/wald/pgen.hpp | 76 ++++++++++++++++++------------------- setups/grpic/wald/wald.toml | 17 +++++---- 2 files changed, 45 insertions(+), 48 deletions(-) diff --git a/setups/grpic/wald/pgen.hpp b/setups/grpic/wald/pgen.hpp index 41d9a2462..7e8eea216 100644 --- a/setups/grpic/wald/pgen.hpp +++ b/setups/grpic/wald/pgen.hpp @@ -26,9 +26,6 @@ namespace user { return HALF * (metric.template h_<3, 3>(x_Cd) + TWO * metric.spin() * metric.template h_<1, 3>(x_Cd) * metric.beta1(x_Cd) ); - // coord_t x_Ph { ZERO }; - // metric.template convert(x_Cd, x_Ph); - // return HALF * SQR(x_Ph[0]) * SQR(math::sin(x_Ph[1])); } Inline auto bx1(const coord_t& x_Ph) const -> real_t { @@ -96,6 +93,7 @@ namespace user { : arch::SpatialDistribution { domain_ptr->mesh.metric } , metric { domain_ptr->mesh.metric } , EM { domain_ptr->fields.em } + , density { domain_ptr->fields.buff } , sigma_thr {sigma_thr} , dens_thr {dens_thr} { std::copy(xi_min.begin(), xi_min.end(), x_min); @@ -108,9 +106,8 @@ namespace user { } } - Kokkos::deep_copy(domain_ptr->fields.buff, ZERO); - auto scatter_buff = Kokkos::Experimental::create_scatter_view(domain_ptr->fields.buff); - printf("%f\n", domain_ptr->fields.buff(10, 10, 0)); + Kokkos::deep_copy(density, ZERO); + auto scatter_buff = Kokkos::Experimental::create_scatter_view(density); // some parameters auto& mesh = domain_ptr->mesh; const auto use_weights = params.template get("particles.use_weights"); @@ -131,15 +128,13 @@ namespace user { prtl_spec.mass(), prtl_spec.charge(), use_weights, metric, mesh.flds_bc(), - ni2, inv_n0, 0)); + ni2, inv_n0, ZERO)); // clang-format on } - Kokkos::Experimental::contribute(domain_ptr->fields.buff, scatter_buff); - auto density = Kokkos::create_mirror_view(domain_ptr->fields.buff); - Kokkos::deep_copy(density, domain_ptr->fields.buff); + Kokkos::Experimental::contribute(density, scatter_buff); } - Inline auto sigma_crit(const coord_t& x_Ph) const -> real_t { + Inline auto sigma_crit(const coord_t& x_Ph) const -> bool { coord_t xi {ZERO}; if constexpr (M::Dim == Dim::_2D) { metric.template convert(x_Ph, xi); @@ -150,17 +145,15 @@ namespace user { metric.template transform(xi, B_cntrv, B_cov); const auto bsqr = DOT(B_cntrv[0], B_cntrv[1], B_cntrv[2], B_cov[0], B_cov[1], B_cov[2]); const auto dens = density(i1, i2, 0); - // printf("%f\n", domain_ptr->fields.buff(10, 10, 0)); - // return (bsqr / dens > sigma_thr) || (dens < dens_thr); - return 2.0; + return (bsqr > sigma_thr * dens) || (dens < dens_thr); } - return ZERO; + return false; } Inline auto operator()(const coord_t& x_Ph) const -> real_t override { auto fill = true; for (auto d = 0u; d < M::Dim; ++d) { - fill &= x_Ph[d] > x_min[d] and x_Ph[d] < x_max[d] and sigma_crit(x_Ph) > ONE; + fill &= x_Ph[d] > x_min[d] and x_Ph[d] < x_max[d] and sigma_crit(x_Ph); } return fill ? ONE : ZERO; } @@ -192,7 +185,7 @@ namespace user { const std::vector xi_min; const std::vector xi_max; - const real_t sigma0, sigma_max, multiplicity, nGJ; + const real_t sigma0, sigma_max, multiplicity, nGJ, temperature; InitFields init_flds; @@ -203,11 +196,14 @@ namespace user { , sigma_max { p.template get("setup.sigma_max") } , sigma0 { p.template get("scales.sigma0") } , multiplicity { p.template get("setup.multiplicity") } - , nGJ { p.template get("scales.B0") * SQR(p.template get("scales.skindepth0")) } //m.mesh().metric.spin() * + , nGJ { p.template get("scales.B0") * SQR(p.template get("scales.skindepth0")) } + , temperature { p.template get("setup.temperature") } , init_flds { m.mesh().metric } {} inline void InitPrtls(Domain& local_domain) { - const auto energy_dist = arch::ColdDist(local_domain.mesh.metric); + const auto energy_dist = arch::Maxwellian(local_domain.mesh.metric, + local_domain.random_pool, + temperature); const auto spatial_dist = PointDistribution(xi_min, xi_max, sigma_max / sigma0, @@ -216,7 +212,7 @@ namespace user { &local_domain ); - const auto injector = arch::NonUniformInjector( + const auto injector = arch::NonUniformInjector( energy_dist, spatial_dist, { 1, 2 }); @@ -228,26 +224,26 @@ namespace user { } void CustomPostStep(std::size_t, long double time, Domain& local_domain) { - // const auto energy_dist = arch::ColdDist(local_domain.mesh.metric); - // const auto spatial_dist = PointDistribution(local_domain.mesh.metric, - // xi_min, - // xi_max); - - // const auto spatial_dist = ReplenishDist(local_domain.mesh.metric, - // const ndfield_t& density, - // unsigned short idx, - // const T& target_density, - // real_t target_max_density) - - // const auto injector = arch::NonUniformInjector( - // energy_dist, - // spatial_dist, - // { 1, 2 }); - // arch::InjectNonUniform(params, - // local_domain, - // injector, - // 1.0, - // true); + const auto energy_dist = arch::Maxwellian(local_domain.mesh.metric, + local_domain.random_pool, + temperature); + const auto spatial_dist = PointDistribution(xi_min, + xi_max, + sigma_max / sigma0, + multiplicity * nGJ, + params, + &local_domain + ); + + const auto injector = arch::NonUniformInjector( + energy_dist, + spatial_dist, + { 1, 2 }); + arch::InjectNonUniform(params, + local_domain, + injector, + 1.0, + true); } }; diff --git a/setups/grpic/wald/wald.toml b/setups/grpic/wald/wald.toml index 2f12705de..3bf243afc 100644 --- a/setups/grpic/wald/wald.toml +++ b/setups/grpic/wald/wald.toml @@ -4,8 +4,8 @@ runtime = 100.0 [grid] - resolution = [256,256] - extent = [[0.8, 8.0]] + resolution = [512, 512] + extent = [[1.22, 6.0]] [grid.metric] metric = "qkerr_schild" @@ -43,28 +43,29 @@ label = "e-" mass = 1.0 charge = -1.0 - maxnpart = 1e6 + maxnpart = 2e8 pusher = "Boris" [[particles.species]] label = "e+" mass = 1.0 charge = 1.0 - maxnpart = 1e6 + maxnpart = 2e8 pusher = "Boris" [setup] multiplicity = 1.0 - sigma_max = 10.0 - xi_min = [1.2, 0.1] - xi_max = [7.5, 3.04159265] + sigma_max = 1000.0 + temperature = 0.01 + xi_min = [1.32, 0.1] + xi_max = [4.0, 3.04159265] [output] format = "hdf5" [output.fields] interval_time = 1.0 - quantities = ["D", "B", "J", "N_1", "N_2", "Nppc_1", "Nppc_2"] + quantities = ["D", "B", "J", "N_1", "N_2", "A"] [output.particles] enable = false From 5a72128e7bd703afcf675ebf92ba11f0627a078c Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Tue, 14 Jan 2025 17:19:13 -0500 Subject: [PATCH 357/773] added an option for controlling initial B-field discretisation --- setups/grpic/wald/pgen.hpp | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/setups/grpic/wald/pgen.hpp b/setups/grpic/wald/pgen.hpp index 7e8eea216..b27dd370e 100644 --- a/setups/grpic/wald/pgen.hpp +++ b/setups/grpic/wald/pgen.hpp @@ -20,7 +20,7 @@ namespace user { template struct InitFields { - InitFields(M metric_) : metric { metric_ } {} + InitFields(M metric_, real_t m_eps) : metric { metric_ }, m_eps { m_eps } {} Inline auto A_3(const coord_t& x_Cd) const -> real_t { return HALF * (metric.template h_<3, 3>(x_Cd) @@ -28,37 +28,37 @@ namespace user { ); } - Inline auto bx1(const coord_t& x_Ph) const -> real_t { + Inline auto bx1(const coord_t& x_Ph) const -> real_t { // at ( i , j + HALF ) coord_t xi {ZERO}, x0m { ZERO }, x0p { ZERO }; metric.template convert(x_Ph, xi); x0m[0] = xi[0]; - x0m[1] = xi[1] - HALF; + x0m[1] = xi[1] - HALF * m_eps; x0p[0] = xi[0]; - x0p[1] = xi[1] + HALF; + x0p[1] = xi[1] + HALF * m_eps; real_t inv_sqrt_detH_ijP { ONE / metric.sqrt_det_h({ xi[0], xi[1] }) }; if (cmp::AlmostZero(x_Ph[1])) return ONE; else - return (A_3(x0p) - A_3(x0m)) * inv_sqrt_detH_ijP; + return (A_3(x0p) - A_3(x0m)) * inv_sqrt_detH_ijP / m_eps; } - Inline auto bx2(const coord_t& x_Ph) const -> real_t { + Inline auto bx2(const coord_t& x_Ph) const -> real_t { // at ( i + HALF , j ) coord_t xi {ZERO}, x0m { ZERO }, x0p { ZERO }; metric.template convert(x_Ph, xi); - x0m[0] = xi[0] - HALF; + x0m[0] = xi[0] - HALF * m_eps; x0m[1] = xi[1]; - x0p[0] = xi[0] + HALF; + x0p[0] = xi[0] + HALF * m_eps; x0p[1] = xi[1]; - real_t inv_sqrt_detH_ijP { ONE / metric.sqrt_det_h({ xi[0], xi[1] }) }; + real_t inv_sqrt_detH_ijP { ONE / metric.sqrt_det_h({ xi[0] , xi[1] }) }; if (cmp::AlmostZero(x_Ph[1])) return ZERO; else - return -(A_3(x0p) - A_3(x0m)) * inv_sqrt_detH_ijP; + return -(A_3(x0p) - A_3(x0m)) * inv_sqrt_detH_ijP / m_eps; } Inline auto bx3(const coord_t& x_Ph) const -> real_t { @@ -79,6 +79,7 @@ namespace user { private: const M metric; + const real_t m_eps; }; template @@ -185,7 +186,7 @@ namespace user { const std::vector xi_min; const std::vector xi_max; - const real_t sigma0, sigma_max, multiplicity, nGJ, temperature; + const real_t sigma0, sigma_max, multiplicity, nGJ, temperature, m_eps; InitFields init_flds; @@ -198,7 +199,8 @@ namespace user { , multiplicity { p.template get("setup.multiplicity") } , nGJ { p.template get("scales.B0") * SQR(p.template get("scales.skindepth0")) } , temperature { p.template get("setup.temperature") } - , init_flds { m.mesh().metric } {} + , m_eps { p.template get("setup.m_eps") } + , init_flds { m.mesh().metric, m_eps } {} inline void InitPrtls(Domain& local_domain) { const auto energy_dist = arch::Maxwellian(local_domain.mesh.metric, From 9bc2f6d0d380f263cfd6c447814323aca97d8994 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Wed, 15 Jan 2025 15:36:42 -0500 Subject: [PATCH 358/773] grpic vacuum wald test improved --- setups/grpic/vacuum/pgen.hpp | 116 ++++++++++++++++++++++++++++---- setups/grpic/vacuum/vacuum.toml | 38 +++-------- 2 files changed, 112 insertions(+), 42 deletions(-) diff --git a/setups/grpic/vacuum/pgen.hpp b/setups/grpic/vacuum/pgen.hpp index 6d5e5fba5..60a2bfe05 100644 --- a/setups/grpic/vacuum/pgen.hpp +++ b/setups/grpic/vacuum/pgen.hpp @@ -27,12 +27,26 @@ namespace user { InitFields(M metric_) : metric { metric_ } {} Inline auto A_3(const coord_t& x_Cd) const -> real_t { - coord_t x_Ph { ZERO }; - metric.template convert(x_Cd, x_Ph); - return HALF * SQR(x_Ph[0]) * SQR(math::sin(x_Ph[1])); + return HALF * (metric.template h_<3, 3>(x_Cd) + + TWO * metric.spin() * metric.template h_<1, 3>(x_Cd) * metric.beta1(x_Cd) + ); } - Inline auto bx1(const coord_t& x_Ph) const -> real_t { + Inline auto A_1(const coord_t& x_Cd) const -> real_t { + return HALF * (metric.template h_<1, 3>(x_Cd) + + TWO * metric.spin() * metric.template h_<1, 1>(x_Cd) * metric.beta1(x_Cd) + ); + } + + Inline auto A_0(const coord_t& x_Cd) const -> real_t { + real_t g_00 { -metric.alpha(x_Cd) * metric.alpha(x_Cd) + + metric.template h_<1, 1>(x_Cd) * metric.beta1(x_Cd) * metric.beta1(x_Cd) + }; + return HALF * (metric.template h_<1, 3>(x_Cd) * metric.beta1(x_Cd) + + TWO * metric.spin() * g_00); + } + + Inline auto bx1(const coord_t& x_Ph) const -> real_t { // at ( i , j + HALF ) coord_t xi {ZERO}, x0m { ZERO }, x0p { ZERO }; metric.template convert(x_Ph, xi); @@ -49,7 +63,7 @@ namespace user { return (A_3(x0p) - A_3(x0m)) * inv_sqrt_detH_ijP; } - Inline auto bx2(const coord_t& x_Ph) const -> real_t { + Inline auto bx2(const coord_t& x_Ph) const -> real_t { // at ( i + HALF , j ) coord_t xi {ZERO}, x0m { ZERO }, x0p { ZERO }; metric.template convert(x_Ph, xi); @@ -65,20 +79,96 @@ namespace user { return -(A_3(x0p) - A_3(x0m)) * inv_sqrt_detH_ijP; } - Inline auto bx3(const coord_t& x_Ph) const -> real_t { - return ZERO; + Inline auto bx3(const coord_t& x_Ph) const -> real_t { // at ( i + HALF , j + HALF ) + coord_t xi {ZERO}, x0m { ZERO }, x0p { ZERO }; + metric.template convert(x_Ph, xi); + + x0m[0] = xi[0]; + x0m[1] = xi[1] - HALF; + x0p[0] = xi[0]; + x0p[1] = xi[1] + HALF; + + real_t inv_sqrt_detH_iPjP { ONE / metric.sqrt_det_h({ xi[0], xi[1]}) }; + return -(A_1(x0p) - A_1(x0m)) * inv_sqrt_detH_iPjP; } - Inline auto dx1(const coord_t& x_Ph) const -> real_t { - return ZERO; + Inline auto dx1(const coord_t& x_Ph) const -> real_t { // at ( i + HALF , j ) + coord_t xi {ZERO}, x0m { ZERO }, x0p { ZERO }; + metric.template convert(x_Ph, xi); + + real_t alpha_iPj { metric.alpha({ xi[0], xi[1] }) }; + real_t inv_sqrt_detH_ij { ONE / metric.sqrt_det_h({ xi[0] - HALF, xi[1] }) }; + real_t sqrt_detH_ij { metric.sqrt_det_h({ xi[0] - HALF, xi[1] }) }; + real_t beta_ij { metric.beta1({ xi[0] - HALF, xi[1]}) }; + real_t alpha_ij { metric.alpha({ xi[0] - HALF, xi[1]}) }; + + // D1 at ( i + HALF , j ) + x0m[0] = xi[0] - HALF; + x0m[1] = xi[1]; + x0p[0] = xi[0] + HALF; + x0p[1] = xi[1]; + real_t E1d { (A_0(x0p) - A_0(x0m)) }; + real_t D1d { E1d / alpha_iPj }; + + // D3 at ( i , j ) + x0m[0] = xi[0] - HALF - HALF; + x0m[1] = xi[1]; + x0p[0] = xi[0] - HALF + HALF; + x0p[1] = xi[1]; + real_t D3d { (A_3(x0p) - A_3(x0m)) * beta_ij / alpha_ij }; + + real_t D1u { metric.template h<1, 1>({ xi[0], xi[1] }) * D1d + metric.template h<1, 3>({ xi[0], xi[1] }) * D3d }; + + return D1u; } - Inline auto dx2(const coord_t& x_Ph) const -> real_t { - return ZERO; + Inline auto dx2(const coord_t& x_Ph) const -> real_t { // at ( i , j + HALF ) + coord_t xi {ZERO}, x0m { ZERO }, x0p { ZERO }; + metric.template convert(x_Ph, xi); + x0m[0] = xi[0]; + x0m[1] = xi[1] - HALF; + x0p[0] = xi[0]; + x0p[1] = xi[1] + HALF; + real_t inv_sqrt_detH_ijP { ONE / metric.sqrt_det_h({ xi[0], xi[1] }) }; + real_t sqrt_detH_ijP { metric.sqrt_det_h({ xi[0], xi[1] }) }; + real_t alpha_ijP { metric.alpha({ xi[0], xi[1] }) }; + real_t beta_ijP { metric.beta1({ xi[0], xi[1] }) }; + + real_t E2d { (A_0(x0p) - A_0(x0m)) }; + real_t D2d { E2d / alpha_ijP - (A_1(x0p) - A_1(x0m)) * beta_ijP / alpha_ijP }; + real_t D2u { metric.template h<2, 2>({ xi[0], xi[1] }) * D2d }; + + return D2u; } - Inline auto dx3(const coord_t& x_Ph) const -> real_t { - return ZERO; + Inline auto dx3(const coord_t& x_Ph) const -> real_t { // at ( i , j ) + coord_t xi {ZERO}, x0m { ZERO }, x0p { ZERO }; + metric.template convert(x_Ph, xi); + real_t inv_sqrt_detH_ij { ONE / metric.sqrt_det_h({ xi[0], xi[1] }) }; + real_t sqrt_detH_ij { metric.sqrt_det_h({ xi[0], xi[1] }) }; + real_t beta_ij { metric.beta1({ xi[0], xi[1] }) }; + real_t alpha_ij { metric.alpha({ xi[0], xi[1] }) }; + real_t alpha_iPj { metric.alpha({ xi[0] + HALF, xi[1] }) }; + + // D3 at ( i , j ) + x0m[0] = xi[0] - HALF; + x0m[1] = xi[1]; + x0p[0] = xi[0] + HALF; + x0p[1] = xi[1]; + real_t D3d { (A_3(x0p) - A_3(x0m)) * beta_ij / alpha_ij }; + + // D1 at ( i + HALF , j ) + x0m[0] = xi[0] + HALF - HALF; + x0m[1] = xi[1]; + x0p[0] = xi[0] + HALF + HALF; + x0p[1] = xi[1]; + real_t E1d { (A_0(x0p) - A_0(x0m)) }; + real_t D1d { E1d / alpha_iPj }; + + if (cmp::AlmostZero(x_Ph[1])) + return metric.template h<1, 3>({ xi[0], xi[1] }) * D1d; + else + return metric.template h<3, 3>({ xi[0], xi[1] }) * D3d + metric.template h<1, 3>({ xi[0], xi[1] }) * D1d; } private: diff --git a/setups/grpic/vacuum/vacuum.toml b/setups/grpic/vacuum/vacuum.toml index 3992b9f12..621f5d127 100644 --- a/setups/grpic/vacuum/vacuum.toml +++ b/setups/grpic/vacuum/vacuum.toml @@ -1,31 +1,31 @@ [simulation] - name = "wald" + name = "wald_Dph_abs_a95" engine = "grpic" - runtime = 500.0 + runtime = 1.0 [grid] resolution = [128,128] - extent = [[2.0, 8.0]] + extent = [[1.0, 10.0]] [grid.metric] - metric = "qkerr_schild" + metric = "kerr_schild" qsph_r0 = 0.0 qsph_h = 0.0 - ks_a = 0.0 + ks_a = 0.95 [grid.boundaries] fields = [["ABSORB"]] particles = [["ABSORB"]] [grid.boundaries.absorb] - ds = 0.5 + ds = 1.0 [scales] larmor0 = 0.0025 skindepth0 = 0.05 [algorithms] - current_filters = 4 + current_filters = 0 [algorithms.timestep] CFL = 0.5 @@ -35,36 +35,16 @@ fieldsolver = true [particles] - ppc0 = 8.0 - use_weights = true - sort_interval = 100 - - #[[particles.species]] - #label = "e-" - #mass = 1.0 - #charge = -1.0 - #maxnpart = 1e6 - #pusher = "Boris" - # - #[[particles.species]] - #label = "e+" - #mass = 1.0 - #charge = 1.0 - #maxnpart = 1e6 - #pusher = "Boris" + ppc0 = 2.0 [setup] - #multiplicity = 1.0 - #sigma_max = 1000.0 - inj_rmin = 1.2 - inj_rmax = 7.5 [output] format = "hdf5" [output.fields] interval_time = 1.0 - quantities = ["D", "H", "B", "J"] + quantities = ["D", "H", "B", "A"] [output.particles] enable = false From 65054962e6613c154f7e458dfa3f3d7a239f7a79 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Wed, 15 Jan 2025 15:37:20 -0500 Subject: [PATCH 359/773] kernels: all fields are absorbed in GR BC --- src/kernels/fields_bcs.hpp | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/src/kernels/fields_bcs.hpp b/src/kernels/fields_bcs.hpp index ee6604577..c528a79f9 100644 --- a/src/kernels/fields_bcs.hpp +++ b/src/kernels/fields_bcs.hpp @@ -1006,6 +1006,30 @@ namespace kernel::bc { const real_t x2_0 { metric.template convert<2, Crd::Cd, Crd::Ph>(i2_) }; Fld(i1, i2, comp) += (ONE - math::tanh(dx / (INV_4 * dx_abs))) * finit.bx2({ x1_H, x2_0 }); + } else if (comp == em::bx3) { + const real_t x1_H { metric.template convert<1, Crd::Cd, Crd::Ph>( + i1_ + HALF) }; + const real_t x2_H { metric.template convert<2, Crd::Cd, Crd::Ph>( + i2_ + HALF) }; + Fld(i1, i2, comp) += (ONE - math::tanh(dx / (INV_4 * dx_abs))) * + finit.bx3({ x1_H, x2_H }); + } else if (comp == em::ex1) { + const real_t x1_H { metric.template convert<1, Crd::Cd, Crd::Ph>( + i1_ + HALF) }; + const real_t x2_0 { metric.template convert<2, Crd::Cd, Crd::Ph>(i2_) }; + Fld(i1, i2, comp) += (ONE - math::tanh(dx / (INV_4 * dx_abs))) * + finit.dx1({ x1_H, x2_0 }); + } else if (comp == em::ex2) { + const real_t x1_0 { metric.template convert<1, Crd::Cd, Crd::Ph>(i1_) }; + const real_t x2_H { metric.template convert<2, Crd::Cd, Crd::Ph>( + i2_ + HALF) }; + Fld(i1, i2, comp) += (ONE - math::tanh(dx / (INV_4 * dx_abs))) * + finit.dx2({ x1_0, x2_H }); + } else if (comp == em::ex3) { + const real_t x1_0 { metric.template convert<1, Crd::Cd, Crd::Ph>(i1_) }; + const real_t x2_0 { metric.template convert<2, Crd::Cd, Crd::Ph>(i2_) }; + Fld(i1, i2, comp) += (ONE - math::tanh(dx / (INV_4 * dx_abs))) * + finit.dx3({ x1_0, x2_0 }); } } } else { @@ -1057,6 +1081,5 @@ namespace kernel::bc { }; } // namespace kernel::bc ->>>>>>> 794beaab (BC for currents) #endif // KERNELS_FIELDS_BCS_HPP From 9ce606cd91f66d7111570756e183cb463f59b885 Mon Sep 17 00:00:00 2001 From: haykh Date: Thu, 30 Jan 2025 16:07:12 -0500 Subject: [PATCH 360/773] changed bc in setups --- .../_monopole}/monopole.toml | 0 .../monopole => legacy/_monopole}/pgen.hpp | 2 +- setups/srpic/magnetar/pgen.hpp | 321 +++++++++--------- setups/srpic/magnetosphere/pgen.hpp | 6 +- 4 files changed, 167 insertions(+), 162 deletions(-) rename {setups/srpic/monopole => legacy/_monopole}/monopole.toml (100%) rename {setups/srpic/monopole => legacy/_monopole}/pgen.hpp (97%) diff --git a/setups/srpic/monopole/monopole.toml b/legacy/_monopole/monopole.toml similarity index 100% rename from setups/srpic/monopole/monopole.toml rename to legacy/_monopole/monopole.toml diff --git a/setups/srpic/monopole/pgen.hpp b/legacy/_monopole/pgen.hpp similarity index 97% rename from setups/srpic/monopole/pgen.hpp rename to legacy/_monopole/pgen.hpp index 389a6c6f7..ed8877b71 100644 --- a/setups/srpic/monopole/pgen.hpp +++ b/legacy/_monopole/pgen.hpp @@ -86,7 +86,7 @@ namespace user { inline PGen() {} - auto FieldDriver(real_t time) const -> DriveFields { + auto AtmFields(real_t time) const -> DriveFields { return DriveFields { time, Bsurf, Rstar, Omega }; } }; diff --git a/setups/srpic/magnetar/pgen.hpp b/setups/srpic/magnetar/pgen.hpp index cacbb7c9a..10f98ea5d 100644 --- a/setups/srpic/magnetar/pgen.hpp +++ b/setups/srpic/magnetar/pgen.hpp @@ -85,7 +85,7 @@ namespace user { const real_t Bsurf, Rstar, Omega, gamma_pairs, pp_thres; InitFields init_flds; - + inline PGen(const SimulationParams& p, const Metadomain& m) : arch::ProblemGenerator(p) , global_domain { m } @@ -94,12 +94,11 @@ namespace user { , Omega { p.template get("setup.omega") } , pp_thres { p.template get("setup.pp_thres") } , gamma_pairs { p.template get("setup.gamma_pairs") } - , init_flds { Bsurf, Rstar } { - } + , init_flds { Bsurf, Rstar } {} inline PGen() {} - auto FieldDriver(real_t time) const -> DriveFields { + auto AtmFields(real_t time) const -> DriveFields { const real_t omega_t = Omega * ((ONE - math::tanh((static_cast(5.0) - time) * HALF)) * @@ -109,170 +108,172 @@ namespace user { return DriveFields { time, Bsurf, Rstar, omega_t }; } - void CustomPostStep(std::size_t , long double, Domain& domain) { - - // Ad-hoc PP kernel - { - - auto& species2_e = domain.species[2]; - auto& species2_p = domain.species[3]; - auto& species3_e = domain.species[4]; - auto& species3_p = domain.species[5]; - auto metric = domain.mesh.metric; - auto pp_thres_ = this->pp_thres; - auto gamma_pairs_ = this->gamma_pairs; - - for (std::size_t s { 0 }; s < 6; ++s) { - if (s == 1) { - continue; - } - - array_t elec_ind("elec_ind"); - array_t pos_ind("pos_ind"); - - auto offset_e = species3_e.npart(); - auto offset_p = species3_p.npart(); - - auto ux1_e = species3_e.ux1; - auto ux2_e = species3_e.ux2; - auto ux3_e = species3_e.ux3; - auto i1_e = species3_e.i1; - auto i2_e = species3_e.i2; - auto dx1_e = species3_e.dx1; - auto dx2_e = species3_e.dx2; - auto phi_e = species3_e.phi; - auto weight_e = species3_e.weight; - auto tag_e = species3_e.tag; - - auto ux1_p = species3_p.ux1; - auto ux2_p = species3_p.ux2; - auto ux3_p = species3_p.ux3; - auto i1_p = species3_p.i1; - auto i2_p = species3_p.i2; - auto dx1_p = species3_p.dx1; - auto dx2_p = species3_p.dx2; - auto phi_p = species3_p.phi; - auto weight_p = species3_p.weight; - auto tag_p = species3_p.tag; - - if (s == 0) { - - offset_e = species2_e.npart(); - offset_p = species2_p.npart(); - - ux1_e = species2_e.ux1; - ux2_e = species2_e.ux2; - ux3_e = species2_e.ux3; - i1_e = species2_e.i1; - i2_e = species2_e.i2; - dx1_e = species2_e.dx1; - dx2_e = species2_e.dx2; - phi_e = species2_e.phi; - weight_e = species2_e.weight; - tag_e = species2_e.tag; - - ux1_p = species2_p.ux1; - ux2_p = species2_p.ux2; - ux3_p = species2_p.ux3; - i1_p = species2_p.i1; - i2_p = species2_p.i2; - dx1_p = species2_p.dx1; - dx2_p = species2_p.dx2; - phi_p = species2_p.phi; - weight_p = species2_p.weight; - tag_p = species2_p.tag; - - } - - auto& species = domain.species[s]; - auto ux1 = species.ux1; - auto ux2 = species.ux2; - auto ux3 = species.ux3; - auto i1 = species.i1; - auto i2 = species.i2; - auto dx1 = species.dx1; - auto dx2 = species.dx2; - auto phi = species.phi; - auto weight = species.weight; - auto tag = species.tag; - - Kokkos::parallel_for( - "InjectPairs", species.rangeActiveParticles(), Lambda(index_t p) { - if (tag(p) == ParticleTag::dead) { - return; - } + auto MatchFields(real_t) const -> InitFields { + return InitFields { Bsurf, Rstar }; + } - auto px = ux1(p); - auto py = ux2(p); - auto pz = ux3(p); - auto gamma = math::sqrt(ONE + SQR(px) + SQR(py) + SQR(pz)); - - const coord_t xCd{ - static_cast(i1(p)) + dx1(p), - static_cast(i2(p)) + dx2(p)}; - - coord_t xPh { ZERO }; - metric.template convert(xCd, xPh); - - if ((gamma > pp_thres_) && (math::sin(xPh[1]) > 0.1)) { - - auto new_gamma = gamma - 2.0 * gamma_pairs_; - auto new_fac = math::sqrt(SQR(new_gamma) - 1.0) / math::sqrt(SQR(gamma) - 1.0); - auto pair_fac = math::sqrt(SQR(gamma_pairs_) - 1.0) / math::sqrt(SQR(gamma) - 1.0); - - auto elec_p = Kokkos::atomic_fetch_add(&elec_ind(), 1); - auto pos_p = Kokkos::atomic_fetch_add(&pos_ind(), 1); - - i1_e(elec_p + offset_e) = i1(p); - dx1_e(elec_p + offset_e) = dx1(p); - i2_e(elec_p + offset_e) = i2(p); - dx2_e(elec_p + offset_e) = dx2(p); - phi_e(elec_p + offset_e) = phi(p); - ux1_e(elec_p + offset_e) = px * pair_fac; - ux2_e(elec_p + offset_e) = py * pair_fac; - ux3_e(elec_p + offset_e) = pz * pair_fac; - weight_e(elec_p + offset_e) = weight(p); - tag_e(elec_p + offset_e) = ParticleTag::alive; - - i1_p(pos_p + offset_p) = i1(p); - dx1_p(pos_p + offset_p) = dx1(p); - i2_p(pos_p + offset_p) = i2(p); - dx2_p(pos_p + offset_p) = dx2(p); - phi_p(pos_p + offset_p) = phi(p); - ux1_p(pos_p + offset_p) = px * pair_fac; - ux2_p(pos_p + offset_p) = py * pair_fac; - ux3_p(pos_p + offset_p) = pz * pair_fac; - weight_p(pos_p + offset_p) = weight(p); - tag_p(pos_p + offset_p) = ParticleTag::alive; - - ux1(p) *= new_fac; - ux2(p) *= new_fac; - ux3(p) *= new_fac; - } + void CustomPostStep(std::size_t, long double, Domain& domain) { - }); + // Ad-hoc PP kernel + { - auto elec_ind_h = Kokkos::create_mirror(elec_ind); - Kokkos::deep_copy(elec_ind_h, elec_ind); - if (s == 0) { - species2_e.set_npart(offset_e + elec_ind_h()); - } else { - species3_e.set_npart(offset_e + elec_ind_h()); - } + auto& species2_e = domain.species[2]; + auto& species2_p = domain.species[3]; + auto& species3_e = domain.species[4]; + auto& species3_p = domain.species[5]; + auto metric = domain.mesh.metric; + auto pp_thres_ = this->pp_thres; + auto gamma_pairs_ = this->gamma_pairs; - auto pos_ind_h = Kokkos::create_mirror(pos_ind); - Kokkos::deep_copy(pos_ind_h, pos_ind); - if (s == 0) { - species2_p.set_npart(offset_p + pos_ind_h()); - } else { - species3_p.set_npart(offset_p + pos_ind_h()); - } + for (std::size_t s { 0 }; s < 6; ++s) { + if (s == 1) { + continue; + } + array_t elec_ind("elec_ind"); + array_t pos_ind("pos_ind"); + + auto offset_e = species3_e.npart(); + auto offset_p = species3_p.npart(); + + auto ux1_e = species3_e.ux1; + auto ux2_e = species3_e.ux2; + auto ux3_e = species3_e.ux3; + auto i1_e = species3_e.i1; + auto i2_e = species3_e.i2; + auto dx1_e = species3_e.dx1; + auto dx2_e = species3_e.dx2; + auto phi_e = species3_e.phi; + auto weight_e = species3_e.weight; + auto tag_e = species3_e.tag; + + auto ux1_p = species3_p.ux1; + auto ux2_p = species3_p.ux2; + auto ux3_p = species3_p.ux3; + auto i1_p = species3_p.i1; + auto i2_p = species3_p.i2; + auto dx1_p = species3_p.dx1; + auto dx2_p = species3_p.dx2; + auto phi_p = species3_p.phi; + auto weight_p = species3_p.weight; + auto tag_p = species3_p.tag; + + if (s == 0) { + + offset_e = species2_e.npart(); + offset_p = species2_p.npart(); + + ux1_e = species2_e.ux1; + ux2_e = species2_e.ux2; + ux3_e = species2_e.ux3; + i1_e = species2_e.i1; + i2_e = species2_e.i2; + dx1_e = species2_e.dx1; + dx2_e = species2_e.dx2; + phi_e = species2_e.phi; + weight_e = species2_e.weight; + tag_e = species2_e.tag; + + ux1_p = species2_p.ux1; + ux2_p = species2_p.ux2; + ux3_p = species2_p.ux3; + i1_p = species2_p.i1; + i2_p = species2_p.i2; + dx1_p = species2_p.dx1; + dx2_p = species2_p.dx2; + phi_p = species2_p.phi; + weight_p = species2_p.weight; + tag_p = species2_p.tag; + } + + auto& species = domain.species[s]; + auto ux1 = species.ux1; + auto ux2 = species.ux2; + auto ux3 = species.ux3; + auto i1 = species.i1; + auto i2 = species.i2; + auto dx1 = species.dx1; + auto dx2 = species.dx2; + auto phi = species.phi; + auto weight = species.weight; + auto tag = species.tag; + + Kokkos::parallel_for( + "InjectPairs", + species.rangeActiveParticles(), + Lambda(index_t p) { + if (tag(p) == ParticleTag::dead) { + return; + } + + auto px = ux1(p); + auto py = ux2(p); + auto pz = ux3(p); + auto gamma = math::sqrt(ONE + SQR(px) + SQR(py) + SQR(pz)); + + const coord_t xCd { static_cast(i1(p)) + dx1(p), + static_cast(i2(p)) + dx2(p) }; + + coord_t xPh { ZERO }; + metric.template convert(xCd, xPh); + + if ((gamma > pp_thres_) && (math::sin(xPh[1]) > 0.1)) { + + auto new_gamma = gamma - 2.0 * gamma_pairs_; + auto new_fac = math::sqrt(SQR(new_gamma) - 1.0) / + math::sqrt(SQR(gamma) - 1.0); + auto pair_fac = math::sqrt(SQR(gamma_pairs_) - 1.0) / + math::sqrt(SQR(gamma) - 1.0); + + auto elec_p = Kokkos::atomic_fetch_add(&elec_ind(), 1); + auto pos_p = Kokkos::atomic_fetch_add(&pos_ind(), 1); + + i1_e(elec_p + offset_e) = i1(p); + dx1_e(elec_p + offset_e) = dx1(p); + i2_e(elec_p + offset_e) = i2(p); + dx2_e(elec_p + offset_e) = dx2(p); + phi_e(elec_p + offset_e) = phi(p); + ux1_e(elec_p + offset_e) = px * pair_fac; + ux2_e(elec_p + offset_e) = py * pair_fac; + ux3_e(elec_p + offset_e) = pz * pair_fac; + weight_e(elec_p + offset_e) = weight(p); + tag_e(elec_p + offset_e) = ParticleTag::alive; + + i1_p(pos_p + offset_p) = i1(p); + dx1_p(pos_p + offset_p) = dx1(p); + i2_p(pos_p + offset_p) = i2(p); + dx2_p(pos_p + offset_p) = dx2(p); + phi_p(pos_p + offset_p) = phi(p); + ux1_p(pos_p + offset_p) = px * pair_fac; + ux2_p(pos_p + offset_p) = py * pair_fac; + ux3_p(pos_p + offset_p) = pz * pair_fac; + weight_p(pos_p + offset_p) = weight(p); + tag_p(pos_p + offset_p) = ParticleTag::alive; + + ux1(p) *= new_fac; + ux2(p) *= new_fac; + ux3(p) *= new_fac; + } + }); + + auto elec_ind_h = Kokkos::create_mirror(elec_ind); + Kokkos::deep_copy(elec_ind_h, elec_ind); + if (s == 0) { + species2_e.set_npart(offset_e + elec_ind_h()); + } else { + species3_e.set_npart(offset_e + elec_ind_h()); + } + auto pos_ind_h = Kokkos::create_mirror(pos_ind); + Kokkos::deep_copy(pos_ind_h, pos_ind); + if (s == 0) { + species2_p.set_npart(offset_p + pos_ind_h()); + } else { + species3_p.set_npart(offset_p + pos_ind_h()); } - } // Ad-hoc PP kernel } - + } // Ad-hoc PP kernel + } }; } // namespace user diff --git a/setups/srpic/magnetosphere/pgen.hpp b/setups/srpic/magnetosphere/pgen.hpp index 681c4d6d1..64fe13cfe 100644 --- a/setups/srpic/magnetosphere/pgen.hpp +++ b/setups/srpic/magnetosphere/pgen.hpp @@ -86,9 +86,13 @@ namespace user { inline PGen() {} - auto FieldDriver(real_t time) const -> DriveFields { + auto AtmFields(real_t time) const -> DriveFields { return DriveFields { time, Bsurf, Rstar, Omega }; } + + auto MatchFields(real_t) const -> InitFields { + return InitFields { Bsurf, Rstar }; + } }; } // namespace user From 6dcb21a23a9c1aaae6be18436b80e2ef4667a45c Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Thu, 30 Jan 2025 17:02:48 -0500 Subject: [PATCH 361/773] gr pusher: particles are deleted under the horizon when they reach N_GHOSTS --- src/kernels/particle_pusher_gr.hpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/kernels/particle_pusher_gr.hpp b/src/kernels/particle_pusher_gr.hpp index e220239bf..71cfae3b4 100644 --- a/src/kernels/particle_pusher_gr.hpp +++ b/src/kernels/particle_pusher_gr.hpp @@ -142,9 +142,7 @@ namespace kernel::gr { , ni3 { ni3 } , epsilon { epsilon } , niter { niter } - , i1_absorb { static_cast(metric.template convert<1, Crd::Ph, Crd::Cd>( - metric.rhorizon())) - - 5 } { + , i1_absorb {N_GHOSTS} { raise::ErrorIf(boundaries.size() < 2, "boundaries defined incorrectly", HERE); is_absorb_i1min = (boundaries[0].first == PrtlBC::ABSORB) || @@ -706,6 +704,9 @@ namespace kernel::gr { EMHalfPush(xp, vp, Dp_hat, Bp_hat, vp_upd); /* x^i(n) -> x^i(n + 1) */ coord_t xp_upd { ZERO }; + if (i1(p) < 15 && is_absorb_i1min) { + vp_upd[0] = -10.0; + } GeodesicCoordinatePush(Massive_t {}, xp, vp_upd, xp_upd); // update phi From 4a1883317d45fb30a8a89504abe08729b685f2f5 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Thu, 30 Jan 2025 18:31:04 -0500 Subject: [PATCH 362/773] engines/grpic: adjustments after merging --- src/engines/grpic.hpp | 40 ++++++++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index 9050d2ff1..6a1575a5a 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -99,8 +99,8 @@ namespace ntt { "algorithms.toggles.fieldsolver"); const auto deposit_enabled = m_params.template get( "algorithms.toggles.deposit"); - const auto sort_interval = m_params.template get( - "particles.sort_interval"); + const auto clear_interval = m_params.template get( + "particles.clear_interval"); if (step == 0) { if (fieldsolver_enabled) { @@ -384,9 +384,10 @@ namespace ntt { } timers.start("Communications"); - if ((sort_interval > 0) and (step % sort_interval == 0)) { - m_metadomain.CommunicateParticles(dom, &timers); - } + // if ((sort_interval > 0) and (step % sort_interval == 0)) { + // m_metadomain.CommunicateParticles(dom, &timers); + // } + m_metadomain.CommunicateParticles(dom); timers.stop("Communications"); } @@ -518,6 +519,13 @@ namespace ntt { FieldBoundaries(dom, BC::E, gr_bc::main); timers.stop("FieldBoundaries"); } + + if (clear_interval > 0 and step % clear_interval == 0 and step > 0) { + timers.start("PrtlClear"); + m_metadomain.RemoveDeadParticles(dom); + timers.stop("PrtlClear"); + } + /** * Finally: em0::B at n-1/2 * em0::D at n @@ -539,7 +547,7 @@ namespace ntt { void FieldBoundaries(domain_t& domain, BCTags tags, const gr_bc& g) { if (g == gr_bc::main) { for (auto& direction : dir::Directions::orth) { - if (m_metadomain.mesh().flds_bc_in(direction) == FldsBC::ABSORB) { + if (m_metadomain.mesh().flds_bc_in(direction) == FldsBC::MATCH) { AbsorbFieldsIn(direction, domain, tags); } else if (m_metadomain.mesh().flds_bc_in(direction) == FldsBC::AXIS) { if (domain.mesh.flds_bc_in(direction) == FldsBC::AXIS) { @@ -602,7 +610,7 @@ namespace ntt { Kokkos::parallel_for( "AbsorbFields", CreateRangePolicy(range_min, range_max), - kernel::AbsorbBoundariesGR_kernel(domain.fields.em, + kernel::bc::AbsorbBoundariesGR_kernel(domain.fields.em, m_pgen.init_flds, domain.mesh.metric, xg_edge, @@ -611,7 +619,7 @@ namespace ntt { Kokkos::parallel_for( "AbsorbFields", CreateRangePolicy(range_min, range_max), - kernel::AbsorbBoundariesGR_kernel(domain.fields.em0, + kernel::bc::AbsorbBoundariesGR_kernel(domain.fields.em0, m_pgen.init_flds, domain.mesh.metric, xg_edge, @@ -659,7 +667,7 @@ namespace ntt { Kokkos::parallel_for( "AbsorbCurrent", CreateRangePolicy(range_min, range_max), - kernel::AbsorbCurrentGR_kernel(domain.fields.cur0, + kernel::bc::AbsorbCurrentGR_kernel(domain.fields.cur0, domain.mesh.metric, xg_edge, ds)); @@ -686,16 +694,16 @@ namespace ntt { Kokkos::parallel_for( "OpenBCFields", range, - kernel::OpenBoundaries_kernel(domain.fields.em, i1_min, tags)); + kernel::bc::OpenBoundaries_kernel(domain.fields.em, i1_min, tags)); Kokkos::parallel_for( "OpenBCFields", range, - kernel::OpenBoundaries_kernel(domain.fields.em0, i1_min, tags)); + kernel::bc::OpenBoundaries_kernel(domain.fields.em0, i1_min, tags)); } else if (g == gr_bc::aux) { Kokkos::parallel_for( "OpenBCFields", range, - kernel::OpenBoundariesAux_kernel(domain.fields.aux, i1_min, tags)); + kernel::bc::OpenBoundariesAux_kernel(domain.fields.aux, i1_min, tags)); } } @@ -720,20 +728,20 @@ namespace ntt { Kokkos::parallel_for( "AxisBCFields", range, - kernel::AxisBoundariesGR_kernel(domain.fields.em, i2_min, tags)); + kernel::bc::AxisBoundariesGR_kernel(domain.fields.em, i2_min, tags)); Kokkos::parallel_for( "AxisBCFields", range, - kernel::AxisBoundariesGR_kernel(domain.fields.em0, i2_min, tags)); + kernel::bc::AxisBoundariesGR_kernel(domain.fields.em0, i2_min, tags)); } else { Kokkos::parallel_for( "AxisBCFields", range, - kernel::AxisBoundariesGR_kernel(domain.fields.em, i2_max, tags)); + kernel::bc::AxisBoundariesGR_kernel(domain.fields.em, i2_max, tags)); Kokkos::parallel_for( "AxisBCFields", range, - kernel::AxisBoundariesGR_kernel(domain.fields.em0, i2_max, tags)); + kernel::bc::AxisBoundariesGR_kernel(domain.fields.em0, i2_max, tags)); } } From a243e75c64a87bfa470c51d19e43a6b3cf6a3862 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Fri, 31 Jan 2025 12:31:26 -0500 Subject: [PATCH 363/773] gr absorb BC for fields: minor, tanh is computed only once now --- src/kernels/fields_bcs.hpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/kernels/fields_bcs.hpp b/src/kernels/fields_bcs.hpp index 45336830e..fcd0e46de 100644 --- a/src/kernels/fields_bcs.hpp +++ b/src/kernels/fields_bcs.hpp @@ -992,43 +992,44 @@ namespace kernel::bc { const auto dx = math::abs( metric.template convert(x_Cd[i - 1]) - xg_edge); - Fld(i1, i2, comp) *= math::tanh(dx / (INV_4 * dx_abs)); + const auto tanh = math::tanh(dx / (INV_4 * dx_abs)); + Fld(i1, i2, comp) *= tanh; if (comp == em::bx1) { const real_t x1_0 { metric.template convert<1, Crd::Cd, Crd::Ph>(i1_) }; const real_t x2_H { metric.template convert<2, Crd::Cd, Crd::Ph>( i2_ + HALF) }; - Fld(i1, i2, comp) += (ONE - math::tanh(dx / (INV_4 * dx_abs))) * + Fld(i1, i2, comp) += (ONE - tanh) * finit.bx1({ x1_0, x2_H }); } else if (comp == em::bx2) { const real_t x1_H { metric.template convert<1, Crd::Cd, Crd::Ph>( i1_ + HALF) }; const real_t x2_0 { metric.template convert<2, Crd::Cd, Crd::Ph>(i2_) }; - Fld(i1, i2, comp) += (ONE - math::tanh(dx / (INV_4 * dx_abs))) * + Fld(i1, i2, comp) += (ONE - tanh) * finit.bx2({ x1_H, x2_0 }); } else if (comp == em::bx3) { const real_t x1_H { metric.template convert<1, Crd::Cd, Crd::Ph>( i1_ + HALF) }; const real_t x2_H { metric.template convert<2, Crd::Cd, Crd::Ph>( i2_ + HALF) }; - Fld(i1, i2, comp) += (ONE - math::tanh(dx / (INV_4 * dx_abs))) * + Fld(i1, i2, comp) += (ONE - tanh) * finit.bx3({ x1_H, x2_H }); } else if (comp == em::ex1) { const real_t x1_H { metric.template convert<1, Crd::Cd, Crd::Ph>( i1_ + HALF) }; const real_t x2_0 { metric.template convert<2, Crd::Cd, Crd::Ph>(i2_) }; - Fld(i1, i2, comp) += (ONE - math::tanh(dx / (INV_4 * dx_abs))) * + Fld(i1, i2, comp) += (ONE - tanh) * finit.dx1({ x1_H, x2_0 }); } else if (comp == em::ex2) { const real_t x1_0 { metric.template convert<1, Crd::Cd, Crd::Ph>(i1_) }; const real_t x2_H { metric.template convert<2, Crd::Cd, Crd::Ph>( i2_ + HALF) }; - Fld(i1, i2, comp) += (ONE - math::tanh(dx / (INV_4 * dx_abs))) * + Fld(i1, i2, comp) += (ONE - tanh) * finit.dx2({ x1_0, x2_H }); } else if (comp == em::ex3) { const real_t x1_0 { metric.template convert<1, Crd::Cd, Crd::Ph>(i1_) }; const real_t x2_0 { metric.template convert<2, Crd::Cd, Crd::Ph>(i2_) }; - Fld(i1, i2, comp) += (ONE - math::tanh(dx / (INV_4 * dx_abs))) * + Fld(i1, i2, comp) += (ONE - tanh) * finit.dx3({ x1_0, x2_0 }); } } From 6c0ae144be546154d57320c8f22e84d045a7ddb4 Mon Sep 17 00:00:00 2001 From: haykh Date: Fri, 31 Jan 2025 13:26:59 -0500 Subject: [PATCH 364/773] dxmin compare between meshblocks --- src/framework/domain/metadomain.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/framework/domain/metadomain.cpp b/src/framework/domain/metadomain.cpp index ed4373df2..a1daaa07d 100644 --- a/src/framework/domain/metadomain.cpp +++ b/src/framework/domain/metadomain.cpp @@ -392,9 +392,10 @@ namespace ntt { mpi::get_type(), MPI_COMM_WORLD); for (const auto& dx : dx_mins) { - raise::ErrorIf(!cmp::AlmostEqual(dx, dx_min), - "dx_min is not the same across all MPI ranks", - HERE); + raise::ErrorIf( + !cmp::AlmostEqual(dx, dx_min, std::numeric_limits::epsilon()), + "dx_min is not the same across all MPI ranks", + HERE); } #endif } From fb0d7066253d3f81c21bcfe971e18ed44ebca5f9 Mon Sep 17 00:00:00 2001 From: haykh Date: Fri, 31 Jan 2025 13:28:18 -0500 Subject: [PATCH 365/773] dxmin compare between meshblocks (smaller precision) --- src/framework/domain/metadomain.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/framework/domain/metadomain.cpp b/src/framework/domain/metadomain.cpp index a1daaa07d..4f0d0d805 100644 --- a/src/framework/domain/metadomain.cpp +++ b/src/framework/domain/metadomain.cpp @@ -392,10 +392,12 @@ namespace ntt { mpi::get_type(), MPI_COMM_WORLD); for (const auto& dx : dx_mins) { - raise::ErrorIf( - !cmp::AlmostEqual(dx, dx_min, std::numeric_limits::epsilon()), - "dx_min is not the same across all MPI ranks", - HERE); + raise::ErrorIf(!cmp::AlmostEqual(dx, + dx_min, + std::numeric_limits::epsilon() * + static_cast(10.0)), + "dx_min is not the same across all MPI ranks", + HERE); } #endif } From 6cc29ac78cf261d0dfd3ac8e86136ebf024a5873 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Fri, 31 Jan 2025 15:00:05 -0500 Subject: [PATCH 366/773] bug in gr pusher -- BC at one of the axes --- src/kernels/particle_pusher_gr.hpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/kernels/particle_pusher_gr.hpp b/src/kernels/particle_pusher_gr.hpp index 71cfae3b4..c80fe188e 100644 --- a/src/kernels/particle_pusher_gr.hpp +++ b/src/kernels/particle_pusher_gr.hpp @@ -704,9 +704,6 @@ namespace kernel::gr { EMHalfPush(xp, vp, Dp_hat, Bp_hat, vp_upd); /* x^i(n) -> x^i(n + 1) */ coord_t xp_upd { ZERO }; - if (i1(p) < 15 && is_absorb_i1min) { - vp_upd[0] = -10.0; - } GeodesicCoordinatePush(Massive_t {}, xp, vp_upd, xp_upd); // update phi @@ -756,7 +753,7 @@ namespace kernel::gr { ux2(p) = -ux2(p); } } else if (i2(p) >= ni2) { - if (is_axis_i2min) { + if (is_axis_i2max) { i2(p) = ni2 - 1; dx2(p) = ONE - dx2(p); ux2(p) = -ux2(p); From f861da44441feeac63ceff71b3a8f4f73d90f89e Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Fri, 31 Jan 2025 15:03:04 -0500 Subject: [PATCH 367/773] vacuum wald setup updated after merging --- setups/grpic/vacuum/vacuum.toml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/setups/grpic/vacuum/vacuum.toml b/setups/grpic/vacuum/vacuum.toml index 621f5d127..e6aecef58 100644 --- a/setups/grpic/vacuum/vacuum.toml +++ b/setups/grpic/vacuum/vacuum.toml @@ -1,10 +1,10 @@ [simulation] - name = "wald_Dph_abs_a95" + name = "vacuum" engine = "grpic" - runtime = 1.0 + runtime = 100.0 [grid] - resolution = [128,128] + resolution = [128, 128] extent = [[1.0, 10.0]] [grid.metric] @@ -14,7 +14,7 @@ ks_a = 0.95 [grid.boundaries] - fields = [["ABSORB"]] + fields = [["MATCH"]] particles = [["ABSORB"]] [grid.boundaries.absorb] @@ -41,6 +41,7 @@ [output] format = "hdf5" + separate_files = false [output.fields] interval_time = 1.0 From 2e4df9a57c51e22c53bd45bab1328aec474835b8 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Fri, 31 Jan 2025 15:06:13 -0500 Subject: [PATCH 368/773] updated input for wald after merging --- setups/grpic/wald/wald.toml | 33 ++++++++++++++++++++------------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/setups/grpic/wald/wald.toml b/setups/grpic/wald/wald.toml index 3bf243afc..c515ae024 100644 --- a/setups/grpic/wald/wald.toml +++ b/setups/grpic/wald/wald.toml @@ -1,43 +1,48 @@ [simulation] name = "wald" engine = "grpic" - runtime = 100.0 + runtime = 500.0 [grid] - resolution = [512, 512] - extent = [[1.22, 6.0]] + resolution = [256, 256] + extent = [[1.0, 6.0]] [grid.metric] metric = "qkerr_schild" - qsph_r0 = 0.0 + qsph_r0 = 0.0 qsph_h = 0.0 ks_a = 0.95 [grid.boundaries] - fields = [["ABSORB"]] + fields = [["MATCH"]] particles = [["ABSORB"]] [grid.boundaries.absorb] - ds = 0.5 + ds = 1.0 [scales] - larmor0 = 0.0025 - skindepth0 = 0.05 + larmor0 = 0.025 + skindepth0 = 0.5 [algorithms] current_filters = 4 + [algorithms.gr] + pusher_niter = 10 + pusher_eps = 1e-2 + [algorithms.timestep] CFL = 0.5 + correction = 1.0 [algorithms.toggles] deposit = true fieldsolver = true [particles] - ppc0 = 8.0 + ppc0 = 4.0 use_weights = true - sort_interval = 100 + clear_interval = 100 [[particles.species]] label = "e-" @@ -57,15 +62,17 @@ multiplicity = 1.0 sigma_max = 1000.0 temperature = 0.01 - xi_min = [1.32, 0.1] - xi_max = [4.0, 3.04159265] + xi_min = [1.5, 0.0] + xi_max = [4.0, 3.14159265] + m_eps = 1.0 [output] format = "hdf5" + separate_files = false [output.fields] interval_time = 1.0 - quantities = ["D", "B", "J", "N_1", "N_2", "A"] + quantities = ["D", "B", "N_1", "N_2", "A"] [output.particles] enable = false From 146056912a7be95f86afc1d3b10f7983ab8c6cc4 Mon Sep 17 00:00:00 2001 From: haykh Date: Fri, 31 Jan 2025 15:08:15 -0500 Subject: [PATCH 369/773] BCs for GR same as SR --- setups/grpic/wald/pgen.hpp | 126 ++--- src/engines/grpic.hpp | 301 ++++++------ src/framework/domain/metadomain.cpp | 9 +- src/global/global.h | 4 + src/kernels/fields_bcs.hpp | 696 +++++++++++++--------------- 5 files changed, 562 insertions(+), 574 deletions(-) diff --git a/setups/grpic/wald/pgen.hpp b/setups/grpic/wald/pgen.hpp index b27dd370e..7f8146bb9 100644 --- a/setups/grpic/wald/pgen.hpp +++ b/setups/grpic/wald/pgen.hpp @@ -6,14 +6,15 @@ #include "arch/kokkos_aliases.h" #include "arch/traits.h" +#include "utils/numeric.h" #include "archetypes/energy_dist.h" -#include "archetypes/spatial_dist.h" #include "archetypes/particle_injector.h" #include "archetypes/problem_generator.h" +#include "archetypes/spatial_dist.h" #include "framework/domain/metadomain.h" + #include "kernels/particle_moments.hpp" -#include "utils/numeric.h" namespace user { using namespace ntt; @@ -23,30 +24,31 @@ namespace user { InitFields(M metric_, real_t m_eps) : metric { metric_ }, m_eps { m_eps } {} Inline auto A_3(const coord_t& x_Cd) const -> real_t { - return HALF * (metric.template h_<3, 3>(x_Cd) - + TWO * metric.spin() * metric.template h_<1, 3>(x_Cd) * metric.beta1(x_Cd) - ); + return HALF * (metric.template h_<3, 3>(x_Cd) + + TWO * metric.spin() * metric.template h_<1, 3>(x_Cd) * + metric.beta1(x_Cd)); } Inline auto bx1(const coord_t& x_Ph) const -> real_t { // at ( i , j + HALF ) - coord_t xi {ZERO}, x0m { ZERO }, x0p { ZERO }; + coord_t xi { ZERO }, x0m { ZERO }, x0p { ZERO }; metric.template convert(x_Ph, xi); x0m[0] = xi[0]; x0m[1] = xi[1] - HALF * m_eps; x0p[0] = xi[0]; x0p[1] = xi[1] + HALF * m_eps; - + real_t inv_sqrt_detH_ijP { ONE / metric.sqrt_det_h({ xi[0], xi[1] }) }; - if (cmp::AlmostZero(x_Ph[1])) + if (cmp::AlmostZero(x_Ph[1])) { return ONE; - else + } else { return (A_3(x0p) - A_3(x0m)) * inv_sqrt_detH_ijP / m_eps; + } } Inline auto bx2(const coord_t& x_Ph) const -> real_t { // at ( i + HALF , j ) - coord_t xi {ZERO}, x0m { ZERO }, x0p { ZERO }; + coord_t xi { ZERO }, x0m { ZERO }, x0p { ZERO }; metric.template convert(x_Ph, xi); x0m[0] = xi[0] - HALF * m_eps; @@ -54,11 +56,12 @@ namespace user { x0p[0] = xi[0] + HALF * m_eps; x0p[1] = xi[1]; - real_t inv_sqrt_detH_ijP { ONE / metric.sqrt_det_h({ xi[0] , xi[1] }) }; - if (cmp::AlmostZero(x_Ph[1])) + real_t inv_sqrt_detH_ijP { ONE / metric.sqrt_det_h({ xi[0], xi[1] }) }; + if (cmp::AlmostZero(x_Ph[1])) { return ZERO; - else + } else { return -(A_3(x0p) - A_3(x0m)) * inv_sqrt_detH_ijP / m_eps; + } } Inline auto bx3(const coord_t& x_Ph) const -> real_t { @@ -78,7 +81,7 @@ namespace user { } private: - const M metric; + const M metric; const real_t m_eps; }; @@ -89,14 +92,13 @@ namespace user { const real_t sigma_thr, const real_t dens_thr, const SimulationParams& params, - Domain* domain_ptr - ) - : arch::SpatialDistribution { domain_ptr->mesh.metric } + Domain* domain_ptr) + : arch::SpatialDistribution { domain_ptr->mesh.metric } , metric { domain_ptr->mesh.metric } - , EM { domain_ptr->fields.em } + , EM { domain_ptr->fields.em } , density { domain_ptr->fields.buff } - , sigma_thr {sigma_thr} - , dens_thr {dens_thr} { + , sigma_thr { sigma_thr } + , dens_thr { dens_thr } { std::copy(xi_min.begin(), xi_min.end(), x_min); std::copy(xi_max.begin(), xi_max.end(), x_max); @@ -108,12 +110,13 @@ namespace user { } Kokkos::deep_copy(density, ZERO); - auto scatter_buff = Kokkos::Experimental::create_scatter_view(density); + auto scatter_buff = Kokkos::Experimental::create_scatter_view(density); // some parameters - auto& mesh = domain_ptr->mesh; - const auto use_weights = params.template get("particles.use_weights"); - const auto ni2 = mesh.n_active(in::x2); - const auto inv_n0 = ONE / params.template get("scales.n0"); + auto& mesh = domain_ptr->mesh; + const auto use_weights = params.template get( + "particles.use_weights"); + const auto ni2 = mesh.n_active(in::x2); + const auto inv_n0 = ONE / params.template get("scales.n0"); for (const auto& sp : specs) { auto& prtl_spec = domain_ptr->species[sp - 1]; @@ -136,15 +139,18 @@ namespace user { } Inline auto sigma_crit(const coord_t& x_Ph) const -> bool { - coord_t xi {ZERO}; + coord_t xi { ZERO }; if constexpr (M::Dim == Dim::_2D) { metric.template convert(x_Ph, xi); const auto i1 = static_cast(xi[0]) + static_cast(N_GHOSTS); const auto i2 = static_cast(xi[1]) + static_cast(N_GHOSTS); - const vec_t B_cntrv { EM(i1, i2, em::bx1), EM(i1, i2, em::bx2), EM(i1, i2, em::bx3) }; - vec_t B_cov { ZERO }; + const vec_t B_cntrv { EM(i1, i2, em::bx1), + EM(i1, i2, em::bx2), + EM(i1, i2, em::bx3) }; + vec_t B_cov { ZERO }; metric.template transform(xi, B_cntrv, B_cov); - const auto bsqr = DOT(B_cntrv[0], B_cntrv[1], B_cntrv[2], B_cov[0], B_cov[1], B_cov[2]); + const auto bsqr = + DOT(B_cntrv[0], B_cntrv[1], B_cntrv[2], B_cov[0], B_cov[1], B_cov[2]); const auto dens = density(i1, i2, 0); return (bsqr > sigma_thr * dens) || (dens < dens_thr); } @@ -162,12 +168,12 @@ namespace user { private: tuple_t x_min; tuple_t x_max; - const real_t sigma_thr; - const real_t dens_thr; - Domain* domain_ptr; - ndfield_t density; - ndfield_t EM; - const M metric; + const real_t sigma_thr; + const real_t dens_thr; + Domain* domain_ptr; + ndfield_t density; + ndfield_t EM; + const M metric; }; template @@ -197,13 +203,14 @@ namespace user { , sigma_max { p.template get("setup.sigma_max") } , sigma0 { p.template get("scales.sigma0") } , multiplicity { p.template get("setup.multiplicity") } - , nGJ { p.template get("scales.B0") * SQR(p.template get("scales.skindepth0")) } + , nGJ { p.template get("scales.B0") * + SQR(p.template get("scales.skindepth0")) } , temperature { p.template get("setup.temperature") } , m_eps { p.template get("setup.m_eps") } , init_flds { m.mesh().metric, m_eps } {} - + inline void InitPrtls(Domain& local_domain) { - const auto energy_dist = arch::Maxwellian(local_domain.mesh.metric, + const auto energy_dist = arch::Maxwellian(local_domain.mesh.metric, local_domain.random_pool, temperature); const auto spatial_dist = PointDistribution(xi_min, @@ -211,22 +218,22 @@ namespace user { sigma_max / sigma0, multiplicity * nGJ, params, - &local_domain - ); + &local_domain); - const auto injector = arch::NonUniformInjector( - energy_dist, - spatial_dist, - { 1, 2 }); + const auto injector = + arch::NonUniformInjector( + energy_dist, + spatial_dist, + { 1, 2 }); arch::InjectNonUniform(params, - local_domain, - injector, - 1.0, - true); + local_domain, + injector, + 1.0, + true); } void CustomPostStep(std::size_t, long double time, Domain& local_domain) { - const auto energy_dist = arch::Maxwellian(local_domain.mesh.metric, + const auto energy_dist = arch::Maxwellian(local_domain.mesh.metric, local_domain.random_pool, temperature); const auto spatial_dist = PointDistribution(xi_min, @@ -234,20 +241,19 @@ namespace user { sigma_max / sigma0, multiplicity * nGJ, params, - &local_domain - ); + &local_domain); - const auto injector = arch::NonUniformInjector( - energy_dist, - spatial_dist, - { 1, 2 }); + const auto injector = + arch::NonUniformInjector( + energy_dist, + spatial_dist, + { 1, 2 }); arch::InjectNonUniform(params, - local_domain, - injector, - 1.0, - true); + local_domain, + injector, + 1.0, + true); } - }; } // namespace user diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index 6a1575a5a..d6a40bbc4 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -101,7 +101,7 @@ namespace ntt { "algorithms.toggles.deposit"); const auto clear_interval = m_params.template get( "particles.clear_interval"); - + if (step == 0) { if (fieldsolver_enabled) { // communicate fields and apply BCs on the first timestep @@ -124,8 +124,9 @@ namespace ntt { /** * em0::D, em::D, em0::B, em::B <- boundary conditions */ - m_metadomain.CommunicateFields(dom, Comm::B | Comm::B0 | Comm::D | Comm::D0); - FieldBoundaries(dom, BC::B | BC::E, gr_bc::main); + m_metadomain.CommunicateFields(dom, + Comm::B | Comm::B0 | Comm::D | Comm::D0); + FieldBoundaries(dom, BC::B | BC::D, gr_bc::main); /** * em0::B <- em::B @@ -147,7 +148,7 @@ namespace ntt { /** * aux::E, aux::H <- boundary conditions */ - FieldBoundaries(dom, BC::B | BC::E, gr_bc::aux); + FieldBoundaries(dom, BC::H | BC::E, gr_bc::aux); /** * em0::B <- (em0::B) <- -curl aux::E @@ -173,7 +174,7 @@ namespace ntt { * em0::D, em::D <- boundary conditions */ m_metadomain.CommunicateFields(dom, Comm::D | Comm::D0); - FieldBoundaries(dom, BC::E, gr_bc::main); + FieldBoundaries(dom, BC::D, gr_bc::main); /** * aux::E <- alpha * em::D + beta x em0::B @@ -187,7 +188,7 @@ namespace ntt { /** * aux::E, aux::H <- boundary conditions */ - FieldBoundaries(dom, BC::B | BC::E, gr_bc::aux); + FieldBoundaries(dom, BC::H | BC::E, gr_bc::aux); // !ADD: GR -- particles? @@ -213,7 +214,7 @@ namespace ntt { * em0::D, em::D <- boundary conditions */ m_metadomain.CommunicateFields(dom, Comm::D | Comm::D0); - FieldBoundaries(dom, BC::E, gr_bc::main); + FieldBoundaries(dom, BC::D, gr_bc::main); /** * aux::H <- alpha * em0::B - beta x em0::D @@ -224,7 +225,7 @@ namespace ntt { /** * aux::H <- boundary conditions */ - FieldBoundaries(dom, BC::B, gr_bc::aux); + FieldBoundaries(dom, BC::H, gr_bc::aux); /** * em0::D <- (em::D) <- curl aux::H @@ -237,7 +238,7 @@ namespace ntt { * em0::D, em::D <- boundary conditions */ m_metadomain.CommunicateFields(dom, Comm::D | Comm::D0); - FieldBoundaries(dom, BC::E, gr_bc::main); + FieldBoundaries(dom, BC::D, gr_bc::main); /** * em::D <-> em0::D @@ -261,31 +262,31 @@ namespace ntt { * u_prtl at 1/2 */ } else { - /** - * em0::B <- em::B - * em0::D <- em::D - * - * Now: em0::B & em0::D at -1/2 - */ - CopyFields(dom); + /** + * em0::B <- em::B + * em0::D <- em::D + * + * Now: em0::B & em0::D at -1/2 + */ + CopyFields(dom); } } - /** - * Initially: em0::B at n-3/2 - * em0::D at n-1 - * em::B at n-1/2 - * em::D at n - * - * cur0::J -- - * cur::J at n-1/2 - * - * aux::E -- - * aux::H -- - * - * x_prtl at n - * u_prtl at n-1/2 - */ + /** + * Initially: em0::B at n-3/2 + * em0::D at n-1 + * em::B at n-1/2 + * em::D at n + * + * cur0::J -- + * cur::J at n-1/2 + * + * aux::E -- + * aux::H -- + * + * x_prtl at n + * u_prtl at n-1/2 + */ if (fieldsolver_enabled) { timers.start("FieldSolver"); @@ -304,14 +305,14 @@ namespace ntt { */ ComputeAuxE(dom, gr_getE::D0_B); timers.stop("FieldSolver"); - + timers.start("FieldBoundaries"); /** * aux::E <- boundary conditions */ FieldBoundaries(dom, BC::E, gr_bc::aux); timers.stop("FieldBoundaries"); - + timers.start("FieldSolver"); /** * em0::B <- (em0::B) <- -curl aux::E @@ -344,7 +345,7 @@ namespace ntt { /** * aux::H <- boundary conditions */ - FieldBoundaries(dom, BC::B, gr_bc::aux); + FieldBoundaries(dom, BC::H, gr_bc::aux); timers.stop("FieldBoundaries"); } @@ -384,9 +385,6 @@ namespace ntt { } timers.start("Communications"); - // if ((sort_interval > 0) and (step % sort_interval == 0)) { - // m_metadomain.CommunicateParticles(dom, &timers); - // } m_metadomain.CommunicateParticles(dom); timers.stop("Communications"); } @@ -423,7 +421,7 @@ namespace ntt { */ Faraday(dom, gr_faraday::main, ONE); timers.stop("FieldSolver"); - + /** * em0::B, em::B <- boundary conditions */ @@ -453,7 +451,7 @@ namespace ntt { AmpereCurrents(dom, gr_ampere::aux); timers.stop("FieldSolver"); } - + /** * em0::D, em::D <- boundary conditions */ @@ -461,7 +459,7 @@ namespace ntt { m_metadomain.CommunicateFields(dom, Comm::D | Comm::D0); timers.stop("Communications"); timers.start("FieldBoundaries"); - FieldBoundaries(dom, BC::E, gr_bc::main); + FieldBoundaries(dom, BC::D, gr_bc::main); timers.stop("FieldBoundaries"); timers.start("FieldSolver"); @@ -516,7 +514,7 @@ namespace ntt { m_metadomain.CommunicateFields(dom, Comm::D | Comm::D0); timers.stop("Communications"); timers.start("FieldBoundaries"); - FieldBoundaries(dom, BC::E, gr_bc::main); + FieldBoundaries(dom, BC::D, gr_bc::main); timers.stop("FieldBoundaries"); } @@ -548,7 +546,7 @@ namespace ntt { if (g == gr_bc::main) { for (auto& direction : dir::Directions::orth) { if (m_metadomain.mesh().flds_bc_in(direction) == FldsBC::MATCH) { - AbsorbFieldsIn(direction, domain, tags); + MatchFieldsIn(direction, domain, tags); } else if (m_metadomain.mesh().flds_bc_in(direction) == FldsBC::AXIS) { if (domain.mesh.flds_bc_in(direction) == FldsBC::AXIS) { AxisFieldsIn(direction, domain, tags); @@ -558,26 +556,25 @@ namespace ntt { CustomFieldsIn(direction, domain, tags, g); } } else if (m_metadomain.mesh().flds_bc_in(direction) == FldsBC::HORIZON) { - OpenFieldsIn(direction, domain, tags, g); + HorizonFieldsIn(direction, domain, tags, g); } } // loop over directions } else if (g == gr_bc::aux) { for (auto& direction : dir::Directions::orth) { if (m_metadomain.mesh().flds_bc_in(direction) == FldsBC::HORIZON) { - OpenFieldsIn(direction, domain, tags, g); + HorizonFieldsIn(direction, domain, tags, g); } } } } - void AbsorbFieldsIn(dir::direction_t direction, - domain_t& domain, - BCTags tags) { + void MatchFieldsIn(dir::direction_t direction, + domain_t& domain, + BCTags tags) { /** - * absorbing boundaries + * match boundaries */ - const auto ds = m_params.template get( - "grid.boundaries.absorb.ds"); + const auto ds = m_params.template get("grid.boundaries.match.ds"); const auto dim = direction.get_dim(); real_t xg_min, xg_max, xg_edge; xg_max = m_metadomain.mesh().extent(dim).second; @@ -608,34 +605,35 @@ namespace ntt { } if (dim == in::x1) { Kokkos::parallel_for( - "AbsorbFields", + "MatchBoundaries", CreateRangePolicy(range_min, range_max), - kernel::bc::AbsorbBoundariesGR_kernel(domain.fields.em, - m_pgen.init_flds, - domain.mesh.metric, - xg_edge, - ds, - tags)); + kernel::bc::MatchBoundaries_kernel( + domain.fields.em, + m_pgen.init_flds, + domain.mesh.metric, + xg_edge, + ds, + tags)); Kokkos::parallel_for( - "AbsorbFields", + "MatchBoundaries", CreateRangePolicy(range_min, range_max), - kernel::bc::AbsorbBoundariesGR_kernel(domain.fields.em0, - m_pgen.init_flds, - domain.mesh.metric, - xg_edge, - ds, - tags)); + kernel::bc::MatchBoundaries_kernel( + domain.fields.em0, + m_pgen.init_flds, + domain.mesh.metric, + xg_edge, + ds, + tags)); } else { - raise::Error("Invalid dimension", HERE); + raise::Error("Invalid dimension", HERE); } } void CurrentsBoundaryConditions(domain_t& domain) { /** - * absorbing boundaries + * match boundaries */ - const auto ds = m_params.template get( - "grid.boundaries.absorb.ds"); + const auto ds = m_params.template get("grid.boundaries.match.ds"); const auto dim = in::x1; real_t xg_min, xg_max, xg_edge; xg_max = m_metadomain.mesh().extent(dim).second; @@ -665,18 +663,18 @@ namespace ntt { range_max[d] = intersect_range[d].second; } Kokkos::parallel_for( - "AbsorbCurrent", - CreateRangePolicy(range_min, range_max), - kernel::bc::AbsorbCurrentGR_kernel(domain.fields.cur0, - domain.mesh.metric, - xg_edge, - ds)); + "AbsorbCurrentsGR", + CreateRangePolicy(range_min, range_max), + kernel::bc::AbsorbCurrentsGR_kernel(domain.fields.cur0, + domain.mesh.metric, + xg_edge, + ds)); } - void OpenFieldsIn(dir::direction_t direction, - domain_t& domain, - BCTags tags, - const gr_bc& g) { + void HorizonFieldsIn(dir::direction_t direction, + domain_t& domain, + BCTags tags, + const gr_bc& g) { /** * open boundaries */ @@ -687,23 +685,28 @@ namespace ntt { "Invalid axis direction, should be x2", HERE); const auto i1_min = domain.mesh.i_min(in::x1); - auto range = CreateRangePolicy( - {domain.mesh.i_min(in::x2)}, - {domain.mesh.i_max(in::x2) + 1}); + auto range = CreateRangePolicy({ domain.mesh.i_min(in::x2) }, + { domain.mesh.i_max(in::x2) + 1 }); if (g == gr_bc::main) { Kokkos::parallel_for( "OpenBCFields", range, - kernel::bc::OpenBoundaries_kernel(domain.fields.em, i1_min, tags)); + kernel::bc::HorizonBoundaries_kernel(domain.fields.em, + i1_min, + tags)); Kokkos::parallel_for( "OpenBCFields", - range, - kernel::bc::OpenBoundaries_kernel(domain.fields.em0, i1_min, tags)); + range, + kernel::bc::HorizonBoundaries_kernel(domain.fields.em0, + i1_min, + tags)); } else if (g == gr_bc::aux) { Kokkos::parallel_for( "OpenBCFields", range, - kernel::bc::OpenBoundariesAux_kernel(domain.fields.aux, i1_min, tags)); + kernel::bc::HorizonBoundaries_kernel(domain.fields.aux, + i1_min, + tags)); } } @@ -721,27 +724,34 @@ namespace ntt { HERE); const auto i2_min = domain.mesh.i_min(in::x2); const auto i2_max = domain.mesh.i_max(in::x2); - auto range = CreateRangePolicy( - {domain.mesh.i_min(in::x1) - 1}, - {domain.mesh.i_max(in::x1)}); + auto range = CreateRangePolicy({ domain.mesh.i_min(in::x1) - 1 }, + { domain.mesh.i_max(in::x1) }); if (direction.get_sign() < 0) { Kokkos::parallel_for( "AxisBCFields", range, - kernel::bc::AxisBoundariesGR_kernel(domain.fields.em, i2_min, tags)); + kernel::bc::AxisBoundariesGR_kernel(domain.fields.em, + i2_min, + tags)); Kokkos::parallel_for( "AxisBCFields", range, - kernel::bc::AxisBoundariesGR_kernel(domain.fields.em0, i2_min, tags)); + kernel::bc::AxisBoundariesGR_kernel(domain.fields.em0, + i2_min, + tags)); } else { Kokkos::parallel_for( "AxisBCFields", range, - kernel::bc::AxisBoundariesGR_kernel(domain.fields.em, i2_max, tags)); + kernel::bc::AxisBoundariesGR_kernel(domain.fields.em, + i2_max, + tags)); Kokkos::parallel_for( "AxisBCFields", range, - kernel::bc::AxisBoundariesGR_kernel(domain.fields.em0, i2_max, tags)); + kernel::bc::AxisBoundariesGR_kernel(domain.fields.em0, + i2_max, + tags)); } } @@ -783,12 +793,13 @@ namespace ntt { void ComputeAuxE(domain_t& domain, const gr_getE& g) { auto range = range_with_axis_BCs(domain); if (g == gr_getE::D0_B) { - Kokkos::parallel_for("ComputeAuxE", - range, - kernel::gr::ComputeAuxE_kernel(domain.fields.em0, // D - domain.fields.em, // B - domain.fields.aux, // E - domain.mesh.metric)); + Kokkos::parallel_for( + "ComputeAuxE", + range, + kernel::gr::ComputeAuxE_kernel(domain.fields.em0, // D + domain.fields.em, // B + domain.fields.aux, // E + domain.mesh.metric)); } else if (g == gr_getE::D_B0) { Kokkos::parallel_for("ComputeAuxE", range, @@ -804,12 +815,13 @@ namespace ntt { void ComputeAuxH(domain_t& domain, const gr_getH& g) { auto range = range_with_axis_BCs(domain); if (g == gr_getH::D_B0) { - Kokkos::parallel_for("ComputeAuxH", - range, - kernel::gr::ComputeAuxH_kernel(domain.fields.em, // D - domain.fields.em0, // B - domain.fields.aux, // H - domain.mesh.metric)); + Kokkos::parallel_for( + "ComputeAuxH", + range, + kernel::gr::ComputeAuxH_kernel(domain.fields.em, // D + domain.fields.em0, // B + domain.fields.aux, // H + domain.mesh.metric)); } else if (g == gr_getH::D0_B0) { Kokkos::parallel_for("ComputeAuxH", range, @@ -880,8 +892,8 @@ namespace ntt { "algorithms.timestep.correction") * dt; auto range = CreateRangePolicy( - { domain.mesh.i_min(in::x1), domain.mesh.i_min(in::x2)}, - { domain.mesh.i_max(in::x1), domain.mesh.i_max(in::x2) + 1}); + { domain.mesh.i_min(in::x1), domain.mesh.i_min(in::x2) }, + { domain.mesh.i_max(in::x1), domain.mesh.i_max(in::x2) + 1 }); const auto ni2 = domain.mesh.n_active(in::x2); if (g == gr_ampere::aux) { @@ -927,51 +939,52 @@ namespace ntt { const auto q0 = m_params.template get("scales.q0"); const auto B0 = m_params.template get("scales.B0"); const auto coeff = -dt * q0 / B0; - auto range = CreateRangePolicy( - { domain.mesh.i_min(in::x1), domain.mesh.i_min(in::x2)}, - { domain.mesh.i_max(in::x1), domain.mesh.i_max(in::x2) + 1}); - const auto ni2 = domain.mesh.n_active(in::x2); + auto range = CreateRangePolicy( + { domain.mesh.i_min(in::x1), domain.mesh.i_min(in::x2) }, + { domain.mesh.i_max(in::x1), domain.mesh.i_max(in::x2) + 1 }); + const auto ni2 = domain.mesh.n_active(in::x2); if (g == gr_ampere::aux) { // Updates D0 with J: D0(n-1/2) -> (J(n)) -> D0(n+1/2) - Kokkos::parallel_for("AmpereCurrentsAux", - range, - kernel::gr::CurrentsAmpere_kernel(domain.fields.em0, - domain.fields.cur, - domain.mesh.metric, - coeff, - ni2, - domain.mesh.flds_bc())); + Kokkos::parallel_for( + "AmpereCurrentsAux", + range, + kernel::gr::CurrentsAmpere_kernel(domain.fields.em0, + domain.fields.cur, + domain.mesh.metric, + coeff, + ni2, + domain.mesh.flds_bc())); } else if (g == gr_ampere::main) { // Updates D0 with J0: D0(n) -> (J0(n+1/2)) -> D0(n+1) - Kokkos::parallel_for("mpereCurrentsMain", - range, - kernel::gr::CurrentsAmpere_kernel(domain.fields.em0, - domain.fields.cur0, - domain.mesh.metric, - coeff, - ni2, - domain.mesh.flds_bc())); + Kokkos::parallel_for( + "AmpereCurrentsMain", + range, + kernel::gr::CurrentsAmpere_kernel(domain.fields.em0, + domain.fields.cur0, + domain.mesh.metric, + coeff, + ni2, + domain.mesh.flds_bc())); } else { raise::Error("Wrong option for `g`", HERE); } - } 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, + domain.mesh.metric)); } 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, + domain.mesh.metric)); } void CurrentsDeposit(domain_t& domain) { @@ -1020,8 +1033,8 @@ namespace ntt { void CurrentsFilter(domain_t& domain) { logger::Checkpoint("Launching currents filtering kernels", HERE); auto range = CreateRangePolicy( - { domain.mesh.i_min(in::x1), domain.mesh.i_min(in::x2)}, - { domain.mesh.i_max(in::x1), domain.mesh.i_max(in::x2) + 1}); + { domain.mesh.i_min(in::x1), domain.mesh.i_min(in::x2) }, + { domain.mesh.i_max(in::x1), domain.mesh.i_max(in::x2) + 1 }); const auto nfilter = m_params.template get( "algorithms.current_filters"); tuple_t size; @@ -1038,7 +1051,7 @@ namespace ntt { domain.fields.buff, size, domain.mesh.flds_bc())); - m_metadomain.CommunicateFields(domain, Comm::J); //J0 + m_metadomain.CommunicateFields(domain, Comm::J); // J0 } } @@ -1058,9 +1071,10 @@ namespace ntt { ? species.charge() / species.mass() : ZERO; // coeff = q / m (dt / 2) omegaB0 - const auto coeff = q_ovr_m * HALF * dt * m_params.template get( - "algorithms.timestep.correction") * - m_params.template get("scales.omegaB0"); + const auto coeff = q_ovr_m * HALF * dt * + m_params.template get( + "algorithms.timestep.correction") * + m_params.template get("scales.omegaB0"); // clang-format off if (species.pusher() == PrtlPusher::PHOTON) { @@ -1119,7 +1133,6 @@ namespace ntt { // clang-format on } } - }; } // namespace ntt diff --git a/src/framework/domain/metadomain.cpp b/src/framework/domain/metadomain.cpp index 4f0d0d805..101bf2144 100644 --- a/src/framework/domain/metadomain.cpp +++ b/src/framework/domain/metadomain.cpp @@ -369,6 +369,8 @@ namespace ntt { template void Metadomain::metricCompatibilityCheck() const { + const auto epsilon = std::numeric_limits::epsilon() * + static_cast(100.0); const auto dx_min = g_mesh.metric.dxMin(); auto dx_min_from_domains = std::numeric_limits::infinity(); for (unsigned int idx { 0 }; idx < g_ndomains; ++idx) { @@ -377,7 +379,7 @@ namespace ntt { dx_min_from_domains = std::min(dx_min_from_domains, current_dx_min); } raise::ErrorIf( - not cmp::AlmostEqual(dx_min, dx_min_from_domains), + not cmp::AlmostEqual(dx_min / dx_min_from_domains, ONE, epsilon), "dx_min is not the same across all domains: " + std::to_string(dx_min) + " " + std::to_string(dx_min_from_domains), HERE); @@ -392,10 +394,7 @@ namespace ntt { mpi::get_type(), MPI_COMM_WORLD); for (const auto& dx : dx_mins) { - raise::ErrorIf(!cmp::AlmostEqual(dx, - dx_min, - std::numeric_limits::epsilon() * - static_cast(10.0)), + raise::ErrorIf(not cmp::AlmostEqual(dx / dx_min, ONE, epsilon), "dx_min is not the same across all MPI ranks", HERE); } diff --git a/src/global/global.h b/src/global/global.h index 77fa8c51c..3f63eafbe 100644 --- a/src/global/global.h +++ b/src/global/global.h @@ -285,9 +285,13 @@ namespace BC { Dx1 = 1 << 0, Dx2 = 1 << 1, Dx3 = 1 << 2, + Hx1 = 1 << 3, + Hx2 = 1 << 4, + Hx3 = 1 << 5, B = Bx1 | Bx2 | Bx3, E = Ex1 | Ex2 | Ex3, D = Dx1 | Dx2 | Dx3, + H = Hx1 | Hx2 | Hx3, }; } // namespace BC diff --git a/src/kernels/fields_bcs.hpp b/src/kernels/fields_bcs.hpp index fcd0e46de..6c3bd2760 100644 --- a/src/kernels/fields_bcs.hpp +++ b/src/kernels/fields_bcs.hpp @@ -4,7 +4,10 @@ * @implements * - kernel::bc::MatchBoundaries_kernel<> * - kernel::bc::AxisBoundaries_kernel<> + * - kernel::bc::AxisBoundariesGR_kernel<> + * - kernel::bc::AbsorbCurrentsGR_kernel<> * - kernel::bc::EnforcedBoundaries_kernel<> + * - kernel::bc::HorizonBoundaries_kernel<> * @namespaces: * - kernel::bc:: */ @@ -89,80 +92,64 @@ namespace kernel::bc { metric.template convert({ i1_ }, x_Ph_0); metric.template convert({ i1_ + HALF }, x_Ph_H); - // SRPIC - auto ex1_U { ZERO }, ex2_U { ZERO }, ex3_U { ZERO }, bx1_U { ZERO }, - bx2_U { ZERO }, bx3_U { ZERO }; - if (tags & BC::E) { - if constexpr (defines_ex1) { - ex1_U = metric.template transform<1, Idx::T, Idx::U>( - { i1_ + HALF }, - fset.ex1(x_Ph_H)); - } - if constexpr (defines_ex2) { - ex2_U = metric.template transform<2, Idx::T, Idx::U>( - { i1_ }, - fset.ex2(x_Ph_0)); - } - if constexpr (defines_ex3) { - ex3_U = metric.template transform<3, Idx::T, Idx::U>( - { i1_ }, - fset.ex3(x_Ph_0)); - } - } - if (tags & BC::B) { - if constexpr (defines_bx1) { - bx1_U = metric.template transform<1, Idx::T, Idx::U>( - { i1_ }, - fset.bx1(x_Ph_0)); - } - if constexpr (defines_bx2) { - bx2_U = metric.template transform<2, Idx::T, Idx::U>( - { i1_ + HALF }, - fset.bx2(x_Ph_H)); - } - if constexpr (defines_bx3) { - bx3_U = metric.template transform<3, Idx::T, Idx::U>( - { i1_ + HALF }, - fset.bx3(x_Ph_H)); - } - } - if constexpr (defines_ex1 or defines_bx2 or defines_bx3) { - const auto dx = math::abs( - metric.template convert(i1_ + HALF) - xg_edge); - const auto s = shape(dx); + const auto s = shape(math::abs( + metric.template convert(i1_ + HALF) - xg_edge)); if constexpr (defines_ex1) { if (tags & BC::E) { - Fld(i1, em::ex1) = s * Fld(i1, em::ex1) + (ONE - s) * ex1_U; + Fld(i1, em::ex1) = s * Fld(i1, em::ex1) + + (ONE - s) * + metric.template transform<1, Idx::T, Idx::U>( + { i1_ + HALF }, + fset.ex1(x_Ph_H)); } } if constexpr (defines_bx2 or defines_bx3) { if (tags & BC::B) { if constexpr (defines_bx2) { - Fld(i1, em::bx2) = s * Fld(i1, em::bx2) + (ONE - s) * bx2_U; + Fld(i1, em::bx2) = s * Fld(i1, em::bx2) + + (ONE - s) * + metric.template transform<2, Idx::T, Idx::U>( + { i1_ + HALF }, + fset.bx2(x_Ph_H)); } if constexpr (defines_bx3) { - Fld(i1, em::bx3) = s * Fld(i1, em::bx3) + (ONE - s) * bx3_U; + Fld(i1, em::bx3) = s * Fld(i1, em::bx3) + + (ONE - s) * + metric.template transform<3, Idx::T, Idx::U>( + { i1_ + HALF }, + fset.bx3(x_Ph_H)); } } } } if constexpr (defines_bx1 or defines_ex2 or defines_ex3) { - const auto dx = math::abs( - metric.template convert(i1_) - xg_edge); - const auto s = shape(dx); + const auto s = shape(math::abs( + metric.template convert(i1_) - xg_edge)); if constexpr (defines_bx1) { if (tags & BC::B) { - Fld(i1, em::bx1) = s * Fld(i1, em::bx1) + (ONE - s) * bx1_U; + Fld(i1, em::bx1) = s * Fld(i1, em::bx1) + + (ONE - s) * + metric.template transform<1, Idx::T, Idx::U>( + { i1_ }, + fset.bx1(x_Ph_0)); } } if constexpr (defines_ex2 or defines_ex3) { if (tags & BC::E) { if constexpr (defines_ex2) { - Fld(i1, em::ex2) = s * Fld(i1, em::ex2) + (ONE - s) * ex2_U; + Fld(i1, em::ex2) = s * Fld(i1, em::ex2) + + (ONE - s) * + metric.template transform<2, Idx::T, Idx::U>( + { i1_ }, + fset.ex2(x_Ph_0)); } if constexpr (defines_ex3) { - Fld(i1, em::ex3) = s * Fld(i1, em::ex3) + (ONE - s) * ex3_U; + Fld(i1, em::ex3) = s * Fld(i1, em::ex3) + + (ONE - s) * + metric.template transform<3, Idx::T, Idx::U>( + { i1_ }, + fset.ex3(x_Ph_0)); } } } @@ -183,123 +170,156 @@ namespace kernel::bc { const auto i1_ = COORD(i1); const auto i2_ = COORD(i2); - if constexpr (S == SimEngine::SRPIC) { - // SRPIC - if constexpr (defines_ex1 or defines_bx2) { - coord_t x_Ph_H0 { ZERO }; - metric.template convert({ i1_ + HALF, i2_ }, x_Ph_H0); - // i1 + 1/2, i2 - real_t xi_Cd; - if constexpr (o == in::x1) { - xi_Cd = i1_ + HALF; - } else { - xi_Cd = i2_; + // SRPIC + if constexpr (defines_ex1 or defines_dx1 or defines_bx2) { + // i1 + 1/2, i2 + real_t xi_Cd; + if constexpr (o == in::x1) { + xi_Cd = i1_ + HALF; + } else { + xi_Cd = i2_; + } + + const auto s = shape(math::abs( + metric.template convert(xi_Cd) - xg_edge)); + + coord_t x_Ph_H0 { ZERO }; + metric.template convert({ i1_ + HALF, i2_ }, x_Ph_H0); + + if constexpr (defines_ex1 or defines_dx1) { + if ((tags & BC::E) or (tags & BC::D)) { + if constexpr (defines_ex1 and S == SimEngine::SRPIC) { + Fld(i1, i2, em::ex1) = s * Fld(i1, i2, em::ex1) + + (ONE - s) * + metric.template transform<1, Idx::T, Idx::U>( + { i1_ + HALF, i2_ }, + fset.ex1(x_Ph_H0)); + } else if constexpr (defines_dx1 and S == SimEngine::GRPIC) { + Fld(i1, i2, em::dx1) = s * Fld(i1, i2, em::dx1) + + (ONE - s) * fset.dx1(x_Ph_H0); + } } + } - const auto dx = math::abs( - metric.template convert(xi_Cd) - xg_edge); - const auto s = shape(dx); + if constexpr (defines_bx2) { + if (tags & BC::B) { + if constexpr (S == SimEngine::SRPIC) { + Fld(i1, i2, em::bx2) = s * Fld(i1, i2, em::bx2) + + (ONE - s) * + metric.template transform<2, Idx::T, Idx::U>( + { i1_ + HALF, i2_ }, + fset.bx2(x_Ph_H0)); + } else if constexpr (S == SimEngine::GRPIC) { + Fld(i1, i2, em::bx2) = s * Fld(i1, i2, em::bx2) + + (ONE - s) * fset.bx2(x_Ph_H0); + } + } + } + } - if constexpr (defines_ex1) { - if (tags & BC::E) { - const auto ex1_U = metric.template transform<1, Idx::T, Idx::U>( - { i1_ + HALF, i2_ }, - fset.ex1(x_Ph_H0)); - Fld(i1, i2, em::ex1) = s * Fld(i1, i2, em::ex1) + (ONE - s) * ex1_U; + if constexpr (defines_ex2 or defines_dx2 or defines_bx1) { + // i1, i2 + 1/2 + real_t xi_Cd; + if constexpr (o == in::x1) { + xi_Cd = i1_; + } else { + xi_Cd = i2_ + HALF; + } + + const auto s = shape(math::abs( + metric.template convert(xi_Cd) - xg_edge)); + + coord_t x_Ph_0H { ZERO }; + metric.template convert({ i1_, i2_ + HALF }, x_Ph_0H); + + if constexpr (defines_ex2 or defines_dx2) { + if ((tags & BC::E) or (tags & BC::D)) { + if constexpr (defines_ex2 and S == SimEngine::SRPIC) { + Fld(i1, i2, em::ex2) = s * Fld(i1, i2, em::ex2) + + (ONE - s) * + metric.template transform<2, Idx::T, Idx::U>( + { i1_, i2_ + HALF }, + fset.ex2(x_Ph_0H)); + } else if constexpr (defines_dx2 and S == SimEngine::GRPIC) { + Fld(i1, i2, em::dx2) = s * Fld(i1, i2, em::dx2) + + (ONE - s) * fset.dx2(x_Ph_0H); } } - if constexpr (defines_bx2) { - if (tags & BC::B) { - const auto bx2_U = metric.template transform<2, Idx::T, Idx::U>( - { i1_ + HALF, i2_ }, - fset.bx2(x_Ph_H0)); - Fld(i1, i2, em::bx2) = s * Fld(i1, i2, em::bx2) + (ONE - s) * bx2_U; + } + + if constexpr (defines_bx1) { + if (tags & BC::B) { + if constexpr (S == SimEngine::SRPIC) { + Fld(i1, i2, em::bx1) = s * Fld(i1, i2, em::bx1) + + (ONE - s) * + metric.template transform<1, Idx::T, Idx::U>( + { i1_, i2_ + HALF }, + fset.bx1(x_Ph_0H)); + } else if constexpr (S == SimEngine::GRPIC) { + Fld(i1, i2, em::bx1) = s * Fld(i1, i2, em::bx1) + + (ONE - s) * fset.bx1(x_Ph_0H); } } } + } - if constexpr (defines_ex2 or defines_bx1) { - coord_t x_Ph_0H { ZERO }; - metric.template convert({ i1_, i2_ + HALF }, x_Ph_0H); - // i1, i2 + 1/2 + if constexpr (defines_ex3 or defines_dx3) { + if (tags & BC::E) { + // i1, i2 real_t xi_Cd; if constexpr (o == in::x1) { xi_Cd = i1_; } else { - xi_Cd = i2_ + HALF; + xi_Cd = i2_; } - const auto dx = math::abs( - metric.template convert(xi_Cd) - xg_edge); - const auto s = shape(dx); - if constexpr (defines_ex2) { - if (tags & BC::E) { - auto ex2_U { ZERO }; - ex2_U = metric.template transform<2, Idx::T, Idx::U>( - { i1_, i2_ + HALF }, - fset.ex2(x_Ph_0H)); - Fld(i1, i2, em::ex2) = s * Fld(i1, i2, em::ex2) + (ONE - s) * ex2_U; - } - } - if constexpr (defines_bx1) { - if (tags & BC::B) { - auto bx1_U { ZERO }; - bx1_U = metric.template transform<1, Idx::T, Idx::U>( - { i1_, i2_ + HALF }, - fset.bx1(x_Ph_0H)); - Fld(i1, i2, em::bx1) = s * Fld(i1, i2, em::bx1) + (ONE - s) * bx1_U; - } + const auto s = shape(math::abs( + metric.template convert(xi_Cd) - xg_edge)); + + coord_t x_Ph_00 { ZERO }; + metric.template convert({ i1_, i2_ }, x_Ph_00); + + if constexpr (defines_ex3 and S == SimEngine::SRPIC) { + Fld(i1, i2, em::ex3) = s * Fld(i1, i2, em::ex3) + + (ONE - s) * + metric.template transform<3, Idx::T, Idx::U>( + { i1_, i2_ }, + fset.ex3(x_Ph_00)); + } else if constexpr (defines_dx3 and S == SimEngine::GRPIC) { + Fld(i1, i2, em::dx3) = s * Fld(i1, i2, em::dx3) + + (ONE - s) * fset.dx3(x_Ph_00); } } + } - if constexpr (defines_ex3) { - if (tags & BC::E) { - auto ex3_U { ZERO }; - coord_t x_Ph_00 { ZERO }; - metric.template convert({ i1_, i2_ }, x_Ph_00); - ex3_U = metric.template transform<3, Idx::T, Idx::U>( - { i1_, i2_ }, - fset.ex3(x_Ph_00)); - // i1, i2 - real_t xi_Cd; - if constexpr (o == in::x1) { - xi_Cd = i1_; - } else { - xi_Cd = i2_; - } - const auto dx = math::abs( - metric.template convert(xi_Cd) - xg_edge); - const auto s = shape(dx); - Fld(i1, i2, em::ex3) = s * Fld(i1, i2, em::ex3) + (ONE - s) * ex3_U; + if constexpr (defines_bx3) { + if (tags & BC::B) { + // i1 + 1/2, i2 + 1/2 + real_t xi_Cd; + if constexpr (o == in::x1) { + xi_Cd = i1_ + HALF; + } else { + xi_Cd = i2_ + HALF; } - } - if constexpr (defines_bx3) { - if (tags & BC::B) { - auto bx3_U { ZERO }; - coord_t x_Ph_HH { ZERO }; - metric.template convert({ i1_ + HALF, i2_ + HALF }, - x_Ph_HH); - bx3_U = metric.template transform<3, Idx::T, Idx::U>( - { i1_ + HALF, i2_ + HALF }, - fset.bx3(x_Ph_HH)); - // i1 + 1/2, i2 + 1/2 - real_t xi_Cd; - if constexpr (o == in::x1) { - xi_Cd = i1_ + HALF; - } else { - xi_Cd = i2_ + HALF; - } - const auto dx = math::abs( - metric.template convert(xi_Cd) - xg_edge); - const auto s = shape(dx); - // bx3 - Fld(i1, i2, em::bx3) = s * Fld(i1, i2, em::bx3) + (ONE - s) * bx3_U; + const auto s = shape(math::abs( + metric.template convert(xi_Cd) - xg_edge)); + + coord_t x_Ph_HH { ZERO }; + metric.template convert({ i1_ + HALF, i2_ + HALF }, + x_Ph_HH); + + if constexpr (S == SimEngine::SRPIC) { + Fld(i1, i2, em::bx3) = s * Fld(i1, i2, em::bx3) + + (ONE - s) * + metric.template transform<3, Idx::T, Idx::U>( + { i1_ + HALF, i2_ + HALF }, + fset.bx3(x_Ph_HH)); + } else if constexpr (S == SimEngine::GRPIC) { + Fld(i1, i2, em::bx3) = s * Fld(i1, i2, em::bx3) + + (ONE - s) * fset.bx3(x_Ph_HH); } } - } else { - // GRPIC - raise::KernelError(HERE, "GRPIC not implemented"); } } else { raise::KernelError( @@ -328,18 +348,18 @@ namespace kernel::bc { } else { xi_Cd = i3_; } - const auto dx = math::abs( - metric.template convert(xi_Cd) - xg_edge); - const auto s = shape(dx); - auto ex1_U { ZERO }; + const auto s = shape(math::abs( + metric.template convert(xi_Cd) - xg_edge)); + coord_t x_Ph_H00 { ZERO }; metric.template convert({ i1_ + HALF, i2_, i3_ }, x_Ph_H00); - ex1_U = metric.template transform<1, Idx::T, Idx::U>( - { i1_ + HALF, i2_, i3_ }, - fset.ex1(x_Ph_H00)); - Fld(i1, i2, i3, em::ex1) = s * Fld(i1, i2, i3, em::ex1) + - (ONE - s) * ex1_U; + + Fld(i1, i2, i3, em::ex1) = + s * Fld(i1, i2, i3, em::ex1) + + (ONE - s) * metric.template transform<1, Idx::T, Idx::U>( + { i1_ + HALF, i2_, i3_ }, + fset.ex1(x_Ph_H00)); } if constexpr (defines_ex2) { @@ -352,18 +372,18 @@ namespace kernel::bc { } else { xi_Cd = i3_; } - const auto dx = math::abs( - metric.template convert(xi_Cd) - xg_edge); - const auto s = shape(dx); - auto ex2_U { ZERO }; + const auto s = shape(math::abs( + metric.template convert(xi_Cd) - xg_edge)); + coord_t x_Ph_0H0 { ZERO }; metric.template convert({ i1_, i2_ + HALF, i3_ }, x_Ph_0H0); - ex2_U = metric.template transform<2, Idx::T, Idx::U>( - { i1_, i2_ + HALF, i3_ }, - fset.ex2(x_Ph_0H0)); - Fld(i1, i2, i3, em::ex2) = s * Fld(i1, i2, i3, em::ex2) + - (ONE - s) * ex2_U; + + Fld(i1, i2, i3, em::ex2) = + s * Fld(i1, i2, i3, em::ex2) + + (ONE - s) * metric.template transform<2, Idx::T, Idx::U>( + { i1_, i2_ + HALF, i3_ }, + fset.ex2(x_Ph_0H0)); } if constexpr (defines_ex3) { @@ -376,18 +396,17 @@ namespace kernel::bc { } else { xi_Cd = i3_ + HALF; } - const auto dx = math::abs( - metric.template convert(xi_Cd) - xg_edge); - const auto s = shape(dx); - auto ex3_U { ZERO }; + const auto s = shape(math::abs( + metric.template convert(xi_Cd) - xg_edge)); + coord_t x_Ph_00H { ZERO }; metric.template convert({ i1_, i2_, i3_ + HALF }, x_Ph_00H); - ex3_U = metric.template transform<3, Idx::T, Idx::U>( - { i1_, i2_, i3_ + HALF }, - fset.ex3(x_Ph_00H)); - Fld(i1, i2, i3, em::ex3) = s * Fld(i1, i2, i3, em::ex3) + - (ONE - s) * ex3_U; + Fld(i1, i2, i3, em::ex3) = + s * Fld(i1, i2, i3, em::ex3) + + (ONE - s) * metric.template transform<3, Idx::T, Idx::U>( + { i1_, i2_, i3_ + HALF }, + fset.ex3(x_Ph_00H)); } } } @@ -404,22 +423,19 @@ namespace kernel::bc { } else { xi_Cd = i3_ + HALF; } - const auto dx = math::abs( - metric.template convert(xi_Cd) - xg_edge); - const auto s = shape(dx); - auto bx1_U { ZERO }; - if constexpr (defines_bx1) { - coord_t x_Ph_0HH { ZERO }; - metric.template convert( - { i1_, i2_ + HALF, i3_ + HALF }, - x_Ph_0HH); - bx1_U = metric.template transform<1, Idx::T, Idx::U>( - { i1_, i2_ + HALF, i3_ + HALF }, - fset.bx1(x_Ph_0HH)); - } - // bx1 - Fld(i1, i2, i3, em::bx1) = s * Fld(i1, i2, i3, em::bx1) + - (ONE - s) * bx1_U; + const auto s = shape(math::abs( + metric.template convert(xi_Cd) - xg_edge)); + + coord_t x_Ph_0HH { ZERO }; + metric.template convert( + { i1_, i2_ + HALF, i3_ + HALF }, + x_Ph_0HH); + + Fld(i1, i2, i3, em::bx1) = + s * Fld(i1, i2, i3, em::bx1) + + (ONE - s) * metric.template transform<1, Idx::T, Idx::U>( + { i1_, i2_ + HALF, i3_ + HALF }, + fset.bx1(x_Ph_0HH)); } if constexpr (defines_bx2) { @@ -432,19 +448,19 @@ namespace kernel::bc { } else { xi_Cd = i3_ + HALF; } - const auto dx = math::abs( - metric.template convert(xi_Cd) - xg_edge); - const auto s = shape(dx); - auto bx2_U { ZERO }; + const auto s = shape(math::abs( + metric.template convert(xi_Cd) - xg_edge)); + coord_t x_Ph_H0H { ZERO }; metric.template convert( { i1_ + HALF, i2_, i3_ + HALF }, x_Ph_H0H); - bx2_U = metric.template transform<2, Idx::T, Idx::U>( - { i1_ + HALF, i2_, i3_ + HALF }, - fset.bx2(x_Ph_H0H)); - Fld(i1, i2, i3, em::bx2) = s * Fld(i1, i2, i3, em::bx2) + - (ONE - s) * bx2_U; + + Fld(i1, i2, i3, em::bx2) = + s * Fld(i1, i2, i3, em::bx2) + + (ONE - s) * metric.template transform<2, Idx::T, Idx::U>( + { i1_ + HALF, i2_, i3_ + HALF }, + fset.bx2(x_Ph_H0H)); } if constexpr (defines_bx3) { @@ -457,19 +473,20 @@ namespace kernel::bc { } else { xi_Cd = i3_; } - const auto dx = math::abs( - metric.template convert(xi_Cd) - xg_edge); - const auto s = shape(dx); - auto bx3_U { ZERO }; + + const auto s = shape(math::abs( + metric.template convert(xi_Cd) - xg_edge)); + coord_t x_Ph_HH0 { ZERO }; metric.template convert( { i1_ + HALF, i2_ + HALF, i3_ }, x_Ph_HH0); - bx3_U = metric.template transform<3, Idx::T, Idx::U>( - { i1_ + HALF, i2_ + HALF, i3_ }, - fset.bx3(x_Ph_HH0)); - Fld(i1, i2, i3, em::bx3) = s * Fld(i1, i2, i3, em::bx3) + - (ONE - s) * bx3_U; + + Fld(i1, i2, i3, em::bx3) = + s * Fld(i1, i2, i3, em::bx3) + + (ONE - s) * metric.template transform<3, Idx::T, Idx::U>( + { i1_ + HALF, i2_ + HALF, i3_ }, + fset.bx3(x_Ph_HH0)); } } } @@ -558,7 +575,7 @@ namespace kernel::bc { Fld(i1, i_edge, em::bx2) = ZERO; } } else { - raise::KernelError(HERE, "AxisBoundaries_kernel: D != 2"); + raise::KernelError(HERE, "AxisBoundariesGR_kernel: D != 2"); } } }; @@ -869,180 +886,129 @@ namespace kernel::bc { } }; - template - struct OpenBoundaries_kernel { + template + struct HorizonBoundaries_kernel { ndfield_t Fld; const std::size_t i1_min; const bool setE, setB; - OpenBoundaries_kernel(ndfield_t Fld, std::size_t i1_min, BCTags tags) + HorizonBoundaries_kernel(ndfield_t Fld, std::size_t i1_min, BCTags tags) : Fld { Fld } , i1_min { i1_min } - , setE { tags & BC::Ex1 or tags & BC::Ex2 or tags & BC::Ex3 } - , setB { tags & BC::Bx1 or tags & BC::Bx2 or tags & BC::Bx3 } {} + , setE { (tags & BC::Ex1 or tags & BC::Ex2 or tags & BC::Ex3) or + (tags & BC::Dx1 or tags & BC::Dx2 or tags & BC::Dx3) } + , setB { (tags & BC::Bx1 or tags & BC::Bx2 or tags & BC::Bx3) or + (tags & BC::Hx1 or tags & BC::Hx2 or tags & BC::Hx3) } {} Inline void operator()(index_t i2) const { if constexpr (M::Dim == Dim::_2D) { - if (setE) { - Fld(i1_min - 1, i2, em::ex1) = Fld(i1_min, i2, em::ex1); - Fld(i1_min, i2, em::ex2) = Fld(i1_min + 1, i2, em::ex2); - Fld(i1_min - 1, i2, em::ex2) = Fld(i1_min, i2, em::ex2); - Fld(i1_min, i2, em::ex3) = Fld(i1_min + 1, i2, em::ex3); - Fld(i1_min - 1, i2, em::ex3) = Fld(i1_min, i2, em::ex3); - } - if (setB) { - Fld(i1_min, i2, em::bx1) = Fld(i1_min + 1, i2, em::bx1); - Fld(i1_min - 1, i2, em::bx1) = Fld(i1_min, i2, em::bx1); - Fld(i1_min - 1, i2, em::bx2) = Fld(i1_min, i2, em::bx2); - Fld(i1_min - 1, i2, em::bx3) = Fld(i1_min, i2, em::bx3); - } - } else { - raise::KernelError( - HERE, - "AbsorbFields_kernel: 2D implementation called for D != 2"); - } - } - }; - - template - struct OpenBoundariesAux_kernel { - ndfield_t Fld; - const std::size_t i1_min; - const bool setE, setB; - - OpenBoundariesAux_kernel(ndfield_t Fld, std::size_t i1_min, BCTags tags) - : Fld { Fld } - , i1_min { i1_min } - , setE { tags & BC::Ex1 or tags & BC::Ex2 or tags & BC::Ex3 } - , setB { tags & BC::Bx1 or tags & BC::Bx2 or tags & BC::Bx3 } {} - - Inline void operator()(index_t i2) const { - if constexpr (M::Dim == Dim::_2D) { - if (setE) { - Fld(i1_min - 1, i2, em::ex1) = Fld(i1_min, i2, em::ex1); - Fld(i1_min - 1, i2, em::ex2) = Fld(i1_min, i2, em::ex2); - Fld(i1_min - 1, i2, em::ex3) = Fld(i1_min, i2, em::ex3); - } - if (setB) { - Fld(i1_min - 1, i2, em::bx1) = Fld(i1_min, i2, em::bx1); - Fld(i1_min - 1, i2, em::bx2) = Fld(i1_min, i2, em::bx2); - Fld(i1_min - 1, i2, em::bx3) = Fld(i1_min, i2, em::bx3); - } - } else { - raise::KernelError( - HERE, - "AbsorbFields_kernel: 2D implementation called for D != 2"); - } - } - }; - - template - struct AbsorbBoundariesGR_kernel { - static_assert(M::is_metric, "M must be a metric class"); - static_assert(i <= static_cast(M::Dim), - "Invalid component index"); - - ndfield_t Fld; - const I finit; - const M metric; - const real_t xg_edge; - const real_t dx_abs; - const BCTags tags; - - AbsorbBoundariesGR_kernel(ndfield_t Fld, - const I& finit, - const M& metric, - real_t xg_edge, - real_t dx_abs, - BCTags tags) - : Fld { Fld } - , finit { finit } - , metric { metric } - , xg_edge { xg_edge } - , dx_abs { dx_abs } - , tags { tags } {} - - Inline void operator()(index_t i1, index_t i2) const { - if constexpr (M::Dim == Dim::_2D) { - const auto i1_ = COORD(i1); - const auto i2_ = COORD(i2); - for (const auto comp : - { em::ex1, em::ex2, em::ex3, em::bx1, em::bx2, em::bx3 }) { - if ((comp == em::ex1) and not(tags & BC::Ex1)) { - continue; - } else if ((comp == em::ex2) and not(tags & BC::Ex2)) { - continue; - } else if ((comp == em::ex3) and not(tags & BC::Ex3)) { - continue; - } else if ((comp == em::bx1) and not(tags & BC::Bx1)) { - continue; - } else if ((comp == em::bx2) and not(tags & BC::Bx2)) { - continue; - } else if ((comp == em::bx3) and not(tags & BC::Bx3)) { - continue; + if constexpr (not IsAux) { + if (setE) { + Fld(i1_min - 1, i2, em::dx1) = Fld(i1_min, i2, em::dx1); + Fld(i1_min, i2, em::dx2) = Fld(i1_min + 1, i2, em::dx2); + Fld(i1_min - 1, i2, em::dx2) = Fld(i1_min, i2, em::dx2); + Fld(i1_min, i2, em::dx3) = Fld(i1_min + 1, i2, em::dx3); + Fld(i1_min - 1, i2, em::dx3) = Fld(i1_min, i2, em::dx3); } - coord_t x_Cd { ZERO }; - if (comp == em::ex1 or comp == em::bx2 or comp == em::bx3) { - x_Cd[0] = i1_ + HALF; - x_Cd[1] = i2_; - } else if (comp == em::ex2 or comp == em::ex3 or comp == em::bx1) { - x_Cd[0] = i1_; - x_Cd[1] = i2_; + if (setB) { + Fld(i1_min, i2, em::bx1) = Fld(i1_min + 1, i2, em::bx1); + Fld(i1_min - 1, i2, em::bx1) = Fld(i1_min, i2, em::bx1); + Fld(i1_min - 1, i2, em::bx2) = Fld(i1_min, i2, em::bx2); + Fld(i1_min - 1, i2, em::bx3) = Fld(i1_min, i2, em::bx3); } - - const auto dx = math::abs( - metric.template convert(x_Cd[i - 1]) - xg_edge); - const auto tanh = math::tanh(dx / (INV_4 * dx_abs)); - Fld(i1, i2, comp) *= tanh; - - if (comp == em::bx1) { - const real_t x1_0 { metric.template convert<1, Crd::Cd, Crd::Ph>(i1_) }; - const real_t x2_H { metric.template convert<2, Crd::Cd, Crd::Ph>( - i2_ + HALF) }; - Fld(i1, i2, comp) += (ONE - tanh) * - finit.bx1({ x1_0, x2_H }); - } else if (comp == em::bx2) { - const real_t x1_H { metric.template convert<1, Crd::Cd, Crd::Ph>( - i1_ + HALF) }; - const real_t x2_0 { metric.template convert<2, Crd::Cd, Crd::Ph>(i2_) }; - Fld(i1, i2, comp) += (ONE - tanh) * - finit.bx2({ x1_H, x2_0 }); - } else if (comp == em::bx3) { - const real_t x1_H { metric.template convert<1, Crd::Cd, Crd::Ph>( - i1_ + HALF) }; - const real_t x2_H { metric.template convert<2, Crd::Cd, Crd::Ph>( - i2_ + HALF) }; - Fld(i1, i2, comp) += (ONE - tanh) * - finit.bx3({ x1_H, x2_H }); - } else if (comp == em::ex1) { - const real_t x1_H { metric.template convert<1, Crd::Cd, Crd::Ph>( - i1_ + HALF) }; - const real_t x2_0 { metric.template convert<2, Crd::Cd, Crd::Ph>(i2_) }; - Fld(i1, i2, comp) += (ONE - tanh) * - finit.dx1({ x1_H, x2_0 }); - } else if (comp == em::ex2) { - const real_t x1_0 { metric.template convert<1, Crd::Cd, Crd::Ph>(i1_) }; - const real_t x2_H { metric.template convert<2, Crd::Cd, Crd::Ph>( - i2_ + HALF) }; - Fld(i1, i2, comp) += (ONE - tanh) * - finit.dx2({ x1_0, x2_H }); - } else if (comp == em::ex3) { - const real_t x1_0 { metric.template convert<1, Crd::Cd, Crd::Ph>(i1_) }; - const real_t x2_0 { metric.template convert<2, Crd::Cd, Crd::Ph>(i2_) }; - Fld(i1, i2, comp) += (ONE - tanh) * - finit.dx3({ x1_0, x2_0 }); + } else { + if (setE) { + Fld(i1_min - 1, i2, em::ex1) = Fld(i1_min, i2, em::ex1); + Fld(i1_min - 1, i2, em::ex2) = Fld(i1_min, i2, em::ex2); + Fld(i1_min - 1, i2, em::ex3) = Fld(i1_min, i2, em::ex3); + } + if (setB) { + Fld(i1_min - 1, i2, em::hx1) = Fld(i1_min, i2, em::hx1); + Fld(i1_min - 1, i2, em::hx2) = Fld(i1_min, i2, em::hx2); + Fld(i1_min - 1, i2, em::hx3) = Fld(i1_min, i2, em::hx3); } } } else { raise::KernelError( HERE, - "AbsorbFields_kernel: 2D implementation called for D != 2"); + "HorizonBoundaries_kernel: 2D implementation called for D != 2"); } } }; + // template + // struct OpenBoundariesAux_kernel { + // ndfield_t Fld; + // const std::size_t i1_min; + // const bool setE, setB; + // + // OpenBoundariesAux_kernel(ndfield_t Fld, std::size_t i1_min, BCTags tags) + // : Fld { Fld } + // , i1_min { i1_min } + // , setE { tags & BC::Ex1 or tags & BC::Ex2 or tags & BC::Ex3 } + // , setB { tags & BC::Bx1 or tags & BC::Bx2 or tags & BC::Bx3 } {} + // + // Inline void operator()(index_t i2) const { + // if constexpr (M::Dim == Dim::_2D) { + // if (setE) { + // Fld(i1_min - 1, i2, em::ex1) = Fld(i1_min, i2, em::ex1); + // Fld(i1_min - 1, i2, em::ex2) = Fld(i1_min, i2, em::ex2); + // Fld(i1_min - 1, i2, em::ex3) = Fld(i1_min, i2, em::ex3); + // } + // if (setB) { + // Fld(i1_min - 1, i2, em::bx1) = Fld(i1_min, i2, em::bx1); + // Fld(i1_min - 1, i2, em::bx2) = Fld(i1_min, i2, em::bx2); + // Fld(i1_min - 1, i2, em::bx3) = Fld(i1_min, i2, em::bx3); + // } + // } else { + // raise::KernelError( + // HERE, + // "AbsorbFields_kernel: 2D implementation called for D != 2"); + // } + // } + // }; + // + // template + // struct AbsorbBoundariesGR_kernel { + // static_assert(M::is_metric, "M must be a metric class"); + // static_assert(i <= static_cast(M::Dim), + // "Invalid component index"); + // + // ndfield_t Fld; + // const I finit; + // const M metric; + // const real_t xg_edge; + // const real_t dx_abs; + // const BCTags tags; + // + // AbsorbBoundariesGR_kernel(ndfield_t Fld, + // const I& finit, + // const M& metric, + // real_t xg_edge, + // real_t dx_abs, + // BCTags tags) + // : Fld { Fld } + // , finit { finit } + // , metric { metric } + // , xg_edge { xg_edge } + // , dx_abs { dx_abs } + // , tags { tags } {} + // + // Inline void operator()(index_t i1, index_t i2) const { + // if constexpr (M::Dim == Dim::_2D) { + // } + // } + // + // else { + // raise::KernelError( + // HERE, + // "AbsorbFields_kernel: 2D implementation called for D != 2"); + // } + // } + // }; + template - struct AbsorbCurrentGR_kernel { + struct AbsorbCurrentsGR_kernel { static_assert(M::is_metric, "M must be a metric class"); static_assert(i <= static_cast(M::Dim), "Invalid component index"); @@ -1052,10 +1018,10 @@ namespace kernel::bc { const real_t xg_edge; const real_t dx_abs; - AbsorbCurrentGR_kernel(ndfield_t J, - const M& metric, - real_t xg_edge, - real_t dx_abs) + AbsorbCurrentsGR_kernel(ndfield_t J, + const M& metric, + real_t xg_edge, + real_t dx_abs) : J { J } , metric { metric } , xg_edge { xg_edge } @@ -1077,7 +1043,7 @@ namespace kernel::bc { } else { raise::KernelError( HERE, - "AbsorbFields_kernel: 2D implementation called for D != 2"); + "AbsorbCurrentsGR_kernel: 2D implementation called for D != 2"); } } }; From 043a1bea263b4c7b64e20136fa0cd1d124ee5647 Mon Sep 17 00:00:00 2001 From: haykh Date: Fri, 31 Jan 2025 18:21:37 -0500 Subject: [PATCH 370/773] temporary hack for aux BCs (need to be done carefully) --- src/engines/grpic.hpp | 36 ++++++++------ src/framework/domain/communications.cpp | 62 +++++++++++++++---------- src/global/utils/plog.h | 2 +- 3 files changed, 61 insertions(+), 39 deletions(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index d6a40bbc4..2de876891 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -391,12 +391,14 @@ namespace ntt { if (fieldsolver_enabled) { timers.start("FieldSolver"); - /** - * cur::J <- (cur0::J + cur::J) / 2 - * - * Now: cur::J at n - */ - TimeAverageJ(dom); + if (deposit_enabled) { + /** + * cur::J <- (cur0::J + cur::J) / 2 + * + * Now: cur::J at n + */ + TimeAverageJ(dom); + } /** * aux::Е <- alpha * em::D + beta x em0::B * @@ -556,13 +558,17 @@ namespace ntt { CustomFieldsIn(direction, domain, tags, g); } } else if (m_metadomain.mesh().flds_bc_in(direction) == FldsBC::HORIZON) { - HorizonFieldsIn(direction, domain, tags, g); + if (domain.mesh.flds_bc_in(direction) == FldsBC::HORIZON) { + HorizonFieldsIn(direction, domain, tags, g); + } } } // loop over directions } else if (g == gr_bc::aux) { for (auto& direction : dir::Directions::orth) { if (m_metadomain.mesh().flds_bc_in(direction) == FldsBC::HORIZON) { - HorizonFieldsIn(direction, domain, tags, g); + if (domain.mesh.flds_bc_in(direction) == FldsBC::HORIZON) { + HorizonFieldsIn(direction, domain, tags, g); + } } } } @@ -679,10 +685,10 @@ namespace ntt { * open boundaries */ raise::ErrorIf(M::CoordType == Coord::Cart, - "Invalid coordinate type for axis BCs", + "Invalid coordinate type for horizon BCs", HERE); raise::ErrorIf(direction.get_dim() != in::x1, - "Invalid axis direction, should be x2", + "Invalid horizon direction, should be x1", HERE); const auto i1_min = domain.mesh.i_min(in::x1); auto range = CreateRangePolicy({ domain.mesh.i_min(in::x2) }, @@ -1075,12 +1081,16 @@ namespace ntt { m_params.template get( "algorithms.timestep.correction") * m_params.template get("scales.omegaB0"); + const auto eps = m_params.template get( + "algorithms.gr.pusher_eps"); + const auto niter = m_params.template get( + "algorithms.gr.pusher_niter"); // clang-format off - if (species.pusher() == PrtlPusher::PHOTON) { auto range_policy = Kokkos::RangePolicy( 0, species.npart()); + Kokkos::parallel_for( "ParticlePusher", range_policy, @@ -1098,7 +1108,7 @@ namespace ntt { domain.mesh.n_active(in::x1), domain.mesh.n_active(in::x2), domain.mesh.n_active(in::x3), - m_params.template get("algorithms.gr.pusher_eps"), m_params.template get("algorithms.gr.pusher_niter"), + eps, niter, domain.mesh.prtl_bc() )); } else if (species.pusher() == PrtlPusher::BORIS) { @@ -1122,7 +1132,7 @@ namespace ntt { domain.mesh.n_active(in::x1), domain.mesh.n_active(in::x2), domain.mesh.n_active(in::x3), - m_params.template get("algorithms.gr.pusher_eps"), m_params.template get("algorithms.gr.pusher_niter"), + eps, niter, domain.mesh.prtl_bc() )); } else if (species.pusher() == PrtlPusher::NONE) { diff --git a/src/framework/domain/communications.cpp b/src/framework/domain/communications.cpp index 728d8fba2..e8ef8e219 100644 --- a/src/framework/domain/communications.cpp +++ b/src/framework/domain/communications.cpp @@ -36,10 +36,10 @@ namespace ntt { using comm_params_t = std::pair>; template - auto GetSendRecvRanks(Metadomain* metadomain, - Domain& domain, - dir::direction_t direction) - -> std::pair { + auto GetSendRecvRanks( + Metadomain* metadomain, + Domain& domain, + dir::direction_t direction) -> std::pair { Domain* send_to_nghbr_ptr = nullptr; Domain* recv_from_nghbr_ptr = nullptr; // set pointers to the correct send/recv domains @@ -119,11 +119,11 @@ namespace ntt { } template - auto GetSendRecvParams(Metadomain* metadomain, - Domain& domain, - dir::direction_t direction, - bool synchronize) - -> std::pair { + auto GetSendRecvParams( + Metadomain* metadomain, + Domain& domain, + dir::direction_t direction, + bool synchronize) -> std::pair { const auto [send_indrank, recv_indrank] = GetSendRecvRanks(metadomain, domain, direction); const auto [send_ind, send_rank] = send_indrank; @@ -206,11 +206,11 @@ namespace ntt { template void Metadomain::CommunicateFields(Domain& domain, CommTags tags) { - const auto comm_fields = (tags & Comm::E) || (tags & Comm::B) || - (tags & Comm::J) || (tags & Comm::D) || - (tags & Comm::D0) || (tags & Comm::B0); - const bool comm_em = (tags & Comm::E) || (tags & Comm::B) || (tags & Comm::D); - const bool comm_em0 = (tags & Comm::B0) || (tags & Comm::D0); + const auto comm_fields = (tags & Comm::E) or (tags & Comm::B) or + (tags & Comm::J) or (tags & Comm::D) or + (tags & Comm::D0) or (tags & Comm::B0); + const bool comm_em = (tags & Comm::E) or (tags & Comm::B) || (tags & Comm::D); + const bool comm_em0 = (tags & Comm::B0) or (tags & Comm::D0); const bool comm_j = (tags & Comm::J); raise::ErrorIf(not comm_fields, "CommunicateFields called with no task", HERE); @@ -302,19 +302,31 @@ namespace ntt { recv_slice, comp_range_fld, false); + // @HACK_GR_1.2.0 -- this has to be done carefully + comm::CommunicateField(domain.index(), + domain.fields.aux, + domain.fields.aux, + send_ind, + recv_ind, + send_rank, + recv_rank, + send_slice, + recv_slice, + comp_range_fld, + false); } if (comm_j) { - comm::CommunicateField(domain.index(), - domain.fields.cur0, - domain.fields.cur0, - send_ind, - recv_ind, - send_rank, - recv_rank, - send_slice, - recv_slice, - comp_range_cur, - false); + comm::CommunicateField(domain.index(), + domain.fields.cur0, + domain.fields.cur0, + send_ind, + recv_ind, + send_rank, + recv_rank, + send_slice, + recv_slice, + comp_range_cur, + false); } } else { if (comm_j) { diff --git a/src/global/utils/plog.h b/src/global/utils/plog.h index 03dc19319..ce6475c36 100644 --- a/src/global/utils/plog.h +++ b/src/global/utils/plog.h @@ -93,4 +93,4 @@ namespace logger { } // namespace logger -#endif // GLOBAL_UTILS_PLOG_H \ No newline at end of file +#endif // GLOBAL_UTILS_PLOG_H From 65e6d7794db0f70b01fd9a3045dcf8b5d735feab Mon Sep 17 00:00:00 2001 From: hayk Date: Tue, 4 Feb 2025 08:48:55 -0500 Subject: [PATCH 371/773] added siddhant --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 26ca92072..e0d1fe016 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,8 @@ Our [detailed documentation](https://entity-toolkit.github.io/) includes everyth 🍵 __Benjamin Crinquand__ {[@bcrinquand](https://github.com/bcrinquand): GRPIC, cubed-sphere} +:radio: __Siddhant Solanki__ {[@sidruns30](https://github.com/sidruns30): framework} + 🤷 __Arno Vanthieghem__ {[@vanthieg](https://github.com/vanthieg): framework, PIC} 😺 __Muni Zhou__ {[@munizhou](https://github.com/munizhou): PIC} From 888c7dea5aa259b6f8799f914e9cc57b0477a9e0 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Tue, 18 Feb 2025 11:21:27 -0500 Subject: [PATCH 372/773] changed BC flag to MATCH everywhere --- setups/grpic/deposit/deposit.toml | 2 +- setups/grpic/pusher/massive_gravity_a0995.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/setups/grpic/deposit/deposit.toml b/setups/grpic/deposit/deposit.toml index 66c848de9..438caef88 100644 --- a/setups/grpic/deposit/deposit.toml +++ b/setups/grpic/deposit/deposit.toml @@ -14,7 +14,7 @@ ks_a = 0.95 [grid.boundaries] - fields = [["ABSORB"]] + fields = [["MATCH"]] particles = [["ABSORB"]] [grid.boundaries.absorb] diff --git a/setups/grpic/pusher/massive_gravity_a0995.toml b/setups/grpic/pusher/massive_gravity_a0995.toml index 3b64d2066..55b3f96ad 100644 --- a/setups/grpic/pusher/massive_gravity_a0995.toml +++ b/setups/grpic/pusher/massive_gravity_a0995.toml @@ -14,7 +14,7 @@ ks_a = 0.0 [grid.boundaries] - fields = [["ABSORB"]] + fields = [["MATCH"]] particles = [["ABSORB"]] [grid.boundaries.absorb] From 61d735cc477bd20b8e41bb4b38bfb02bdf7187c9 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Tue, 18 Feb 2025 11:22:51 -0500 Subject: [PATCH 373/773] MATCH BCs --- setups/grpic/pusher/boris.toml | 2 +- setups/grpic/pusher/boris_a09.toml | 2 +- setups/grpic/pusher/massive_gravity_3d.toml | 2 +- setups/grpic/pusher/massive_gravity_a0.toml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/setups/grpic/pusher/boris.toml b/setups/grpic/pusher/boris.toml index 5d4d92a9d..698ee6cb3 100644 --- a/setups/grpic/pusher/boris.toml +++ b/setups/grpic/pusher/boris.toml @@ -14,7 +14,7 @@ ks_a = 0.0 [grid.boundaries] - fields = [["ABSORB"]] + fields = [["MATCH"]] particles = [["ABSORB"]] [grid.boundaries.absorb] diff --git a/setups/grpic/pusher/boris_a09.toml b/setups/grpic/pusher/boris_a09.toml index 379e9c323..09cad8e76 100644 --- a/setups/grpic/pusher/boris_a09.toml +++ b/setups/grpic/pusher/boris_a09.toml @@ -14,7 +14,7 @@ ks_a = 0.9 [grid.boundaries] - fields = [["ABSORB"]] + fields = [["MATCH"]] particles = [["ABSORB"]] [grid.boundaries.absorb] diff --git a/setups/grpic/pusher/massive_gravity_3d.toml b/setups/grpic/pusher/massive_gravity_3d.toml index 5b87554b2..142db7743 100644 --- a/setups/grpic/pusher/massive_gravity_3d.toml +++ b/setups/grpic/pusher/massive_gravity_3d.toml @@ -14,7 +14,7 @@ ks_a = 0.995 [grid.boundaries] - fields = [["ABSORB"]] + fields = [["MATCH"]] particles = [["ABSORB"]] [grid.boundaries.absorb] diff --git a/setups/grpic/pusher/massive_gravity_a0.toml b/setups/grpic/pusher/massive_gravity_a0.toml index 8179432da..bdb8c802b 100644 --- a/setups/grpic/pusher/massive_gravity_a0.toml +++ b/setups/grpic/pusher/massive_gravity_a0.toml @@ -14,7 +14,7 @@ ks_a = 0.0 [grid.boundaries] - fields = [["ABSORB"]] + fields = [["MATCH"]] particles = [["ABSORB"]] [grid.boundaries.absorb] From 3e1848aaba12da9b4c2844f0c2aba95d2102a47b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20B=C3=B6ss?= Date: Fri, 21 Feb 2025 10:43:05 -0600 Subject: [PATCH 374/773] prep for conductor boundaries --- src/global/arch/traits.h | 12 ++++++++++++ src/global/enums.h | 7 ++++--- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/global/arch/traits.h b/src/global/arch/traits.h index 4cde4fca5..65cc63cf8 100644 --- a/src/global/arch/traits.h +++ b/src/global/arch/traits.h @@ -112,6 +112,18 @@ namespace traits { template using fix_fields_const_t = decltype(&T::FixFieldsConst); + template + using perfect_conductor_fields_t = decltype(&T::PerfectConductorFields); + + template + using perfect_conductor_fields_const_t = decltype(&T::PerfectConductorFieldsConst); + + template + using perfect_conductor_currents_t = decltype(&T::PerfectConductorCurrents); + + template + using perfect_conductor_currents_const_t = decltype(&T::PerfectConductorCurrentsConst); + template using custom_fields_t = decltype(&T::CustomFields); diff --git a/src/global/enums.h b/src/global/enums.h index 8f2495c13..2b3bf5936 100644 --- a/src/global/enums.h +++ b/src/global/enums.h @@ -222,15 +222,16 @@ namespace ntt { HORIZON = 6, AXIS = 7, SYNC = 8, // <- SYNC means synchronization with other domains + CONDUCTOR = 9 }; constexpr FldsBC(uint8_t c) : enums_hidden::BaseEnum { c } {} - static constexpr type variants[] = { PERIODIC, MATCH, FIXED, ATMOSPHERE, - CUSTOM, HORIZON, AXIS, SYNC }; + static constexpr type variants[] = { PERIODIC, MATCH, FIXED, ATMOSPHERE, + CUSTOM, HORIZON, AXIS, SYNC, CONDUCTOR }; static constexpr const char* lookup[] = { "periodic", "match", "fixed", "atmosphere", "custom", "horizon", - "axis", "sync" }; + "axis", "sync", "conductor"}; static constexpr std::size_t total = sizeof(variants) / sizeof(variants[0]); }; From bacbe24117dff5ebb832465aa9c539c9e0231900 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20B=C3=B6ss?= Date: Fri, 21 Feb 2025 10:43:32 -0600 Subject: [PATCH 375/773] first stubborn attempt at conductor boundaries (broken) --- setups/srpic/shock/pgen.hpp | 46 +++++++++++++ src/engines/srpic.hpp | 133 ++++++++++++++++++++++++++++++++++++ 2 files changed, 179 insertions(+) diff --git a/setups/srpic/shock/pgen.hpp b/setups/srpic/shock/pgen.hpp index b8f169521..59c5590c9 100644 --- a/setups/srpic/shock/pgen.hpp +++ b/setups/srpic/shock/pgen.hpp @@ -106,6 +106,52 @@ namespace user { } } + + auto PerfectConductorFieldsConst(const bc_in&, const em& comp) const -> real_t{ + + // electric field components + if (comp == em::ex1) { + return ONE; + } else if (comp == em::ex2) { + return -ONE; + } else if (comp == em::ex3) { + return -ONE; } + // magentic field components + else if (comp == em::bx1) { + return -ONE; + } else if (comp == em::bx2) { + return ONE; + } else if (comp == em::bx3) { + return ONE;} + // should never be the case + else + { + return ZERO; + } + } + + // auto PerfectConductorCurrentsConst(const bc_in &, const cur &comp) const + // -> std::pair + // { + // // ToDo + // if (comp == cur::jx1) + // { + // return ZERO; + // } + // else if (comp == cur::jx2) + // { + // return ZERO; + // } + // else if (comp == cur::jx3) + // { + // return ZERO; + // } + // else + // { + // return ZERO; + // } + // } + auto MatchFields(real_t time) const -> InitFields { return init_flds; } diff --git a/src/engines/srpic.hpp b/src/engines/srpic.hpp index 9f5e4551f..4fca96674 100644 --- a/src/engines/srpic.hpp +++ b/src/engines/srpic.hpp @@ -596,6 +596,10 @@ namespace ntt { if (domain.mesh.flds_bc_in(direction) == FldsBC::FIXED) { FixedFieldsIn(direction, domain, tags); } + } else if (m_metadomain.mesh().flds_bc_in(direction) == FldsBC::CONDUCTOR) { + if (domain.mesh.flds_bc_in(direction) == FldsBC::CONDUCTOR) { + PerfectConductorFieldsIn(direction, domain, tags); + } } else if (m_metadomain.mesh().flds_bc_in(direction) == FldsBC::CUSTOM) { if (domain.mesh.flds_bc_in(direction) == FldsBC::CUSTOM) { CustomFieldsIn(direction, domain, tags); @@ -834,6 +838,135 @@ namespace ntt { } } + void PerfectConductorFieldsIn(dir::direction_t direction, + domain_t& domain, + BCTags tags) { + /** + * perfect conductor field boundaries + */ + const auto sign = direction.get_sign(); + const auto dim = direction.get_dim(); + raise::ErrorIf(dim != in::x1 and M::CoordType != Coord::Cart, + "Perfect conductor BCs only implemented for x1 in " + "non-cartesian coordinates", + HERE); + + // magnetic and electron field components + em normal_b_comp, tang_b_comp1, tang_b_comp2, + normal_e_comp, tang_e_comp1, tang_e_comp2; + + // current components + // cur normal_j_comp, tang_j_comp1, tang_j_comp2; + + if (dim == in::x1) { + normal_b_comp = em::bx1; + tang_b_comp1 = em::bx2; + tang_b_comp2 = em::bx3; + + normal_e_comp = em::ex1; + tang_e_comp1 = em::ex2; + tang_e_comp2 = em::ex3; + } else if (dim == in::x2) { + normal_b_comp = em::bx2; + tang_b_comp1 = em::bx1; + tang_b_comp2 = em::bx3; + + normal_e_comp = em::ex2; + tang_e_comp1 = em::ex1; + tang_e_comp2 = em::ex3; + } else if (dim == in::x3) { + normal_b_comp = em::bx3; + tang_b_comp1 = em::bx1; + tang_b_comp2 = em::bx2; + + normal_e_comp = em::ex3; + tang_e_comp1 = em::ex1; + tang_e_comp2 = em::ex2; + } else { + raise::Error("Invalid dimension", HERE); + } + + std::vector origin_xi_min, origin_xi_max, + target_xi_min, target_xi_max; + const std::vector all_dirs { in::x1, in::x2, in::x3 }; + + for (unsigned short d { 0 }; d < static_cast(M::Dim); ++d) { + const auto dd = all_dirs[d]; + if (dim == dd) { + // origin: right side of boundary + origin_xi_min.push_back(N_GHOSTS+1); + origin_xi_max.push_back(2*N_GHOSTS); + // target: left side of boundary + target_xi_min.push_back(0); + target_xi_max.push_back(N_GHOSTS); + + } else { + origin_xi_min.push_back(0); + origin_xi_max.push_back(domain.mesh.n_all(dd)); + + target_xi_min.push_back(0); + target_xi_max.push_back(domain.mesh.n_all(dd)); + } + } + raise::ErrorIf(target_xi_min.size() != origin_xi_min.size() or + origin_xi_min.size() != static_cast(M::Dim), + "Invalid range size", + HERE); + + std::vector comps; + if (tags & BC::E) { + comps.push_back(normal_e_comp); + comps.push_back(tang_e_comp1); + comps.push_back(tang_e_comp2); + } + if (tags & BC::B) { + comps.push_back(normal_b_comp); + comps.push_back(tang_b_comp1); + comps.push_back(tang_b_comp2); + } + + // ToDo: smarter loop/views + auto EB = domain.fields.em; + + // loop over all components + for (const auto& comp : comps) { + + // store sign of component behind boundary + auto new_sign = m_pgen.PerfectConductorFieldsConst( + (bc_in)(sign * ((short)dim + 1)), + (em)comp); + // to do: Kokkos::parallel_for + for (int i = 0; i < N_GHOSTS; i++) + { + if constexpr (M::Dim == Dim::_1D) { + // multiply with correct sign + EB(target_xi_min[0]+i, comp) = new_sign * EB(origin_xi_max[0]-i, comp); + + } else if constexpr (M::Dim == Dim::_2D) { + for (int j = 0; j < domain.mesh.n_all(in::x2); j++) + { + EB(target_xi_min[0]+i, j, comp) = + new_sign * EB(origin_xi_max[0]-i, j, comp); + } + } else if constexpr (M::Dim == Dim::_3D) { + for (int j = 0; j < domain.mesh.n_all(in::x2); j++) + { + for (int k = 0; k < domain.mesh.n_all(in::x3); k++) + { + EB(target_xi_min[0]+i, j, k, comp) = + new_sign * EB(origin_xi_max[0]-i, j, k, comp); + } + } + } else { + raise::Error("Invalid dimension", HERE); + } + } + + // ToDo: set zero at boundary + } + } + + void AtmosphereFieldsIn(dir::direction_t direction, domain_t& domain, BCTags tags) { From 2081a39b3aea9b4c9fc5d9c122bd168879781aca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20B=C3=B6ss?= Date: Fri, 21 Feb 2025 16:41:20 -0600 Subject: [PATCH 376/773] first attempt at ConductorBoundaries_kernel --- src/kernels/fields_bcs.hpp | 107 +++++++++++++++++++++++++++++++++++++ 1 file changed, 107 insertions(+) diff --git a/src/kernels/fields_bcs.hpp b/src/kernels/fields_bcs.hpp index 363ff3ad2..fa0b7ec0d 100644 --- a/src/kernels/fields_bcs.hpp +++ b/src/kernels/fields_bcs.hpp @@ -485,6 +485,113 @@ namespace kernel::bc { } }; + template + struct ConductorBoundaries_kernel { + static_assert(M::is_metric, "M must be a metric class"); + static_assert(static_cast(o) < + static_cast(M::Dim), + "Invalid component index"); + static constexpr idx_t i = static_cast(o) + 1u; + + ndfield_t Fld; + const I fset; + const M metric; + const BCTags tags; + + ConductorBoundaries_kernel(ndfield_t Fld, + BCTags tags) + : Fld { Fld } + , tags { tags } {} + + Inline void operator()(index_t i1) const { + if constexpr (M::Dim == Dim::_1D) { + + if constexpr (S == SimEngine::SRPIC) { + + if (tags & BC::E) { + Fld((N_GHOSTS-1)-i1, em::ex1) = Fld(N_GHOSTS+i1, em::ex1); + Fld((N_GHOSTS-1)-i1, em::ex2) = -Fld(N_GHOSTS+i1, em::ex2); + Fld((N_GHOSTS-1)-i1, em::ex3) = -Fld(N_GHOSTS+i1, em::ex3); + } + + if (tags & BC::B) + { + Fld((N_GHOSTS-1)-i1, em::bx1) = -Fld(N_GHOSTS+i1, em::bx1); + Fld((N_GHOSTS-1)-i1, em::bx1) = Fld(N_GHOSTS+i1, em::bx1); + Fld((N_GHOSTS-1)-i1, em::bx1) = Fld(N_GHOSTS+i1, em::bx1); + } + + } else { + // GRPIC + raise::KernelError(HERE, "1D GRPIC not implemented"); + } + } else { + raise::KernelError( + HERE, + "ConductorBoundaries_kernel: 1D implementation called for D != 1"); + } + } + + Inline void operator()(index_t i1, index_t i2) const { + if constexpr (M::Dim == Dim::_2D) { + + if constexpr (S == SimEngine::SRPIC) { + // SRPIC + if (tags & BC::E) { + Fld((N_GHOSTS-1)-i1, i2, em::ex1) = Fld(N_GHOSTS+i1, i2, em::ex1); + Fld((N_GHOSTS-1)-i1, i2, em::ex2) = -Fld(N_GHOSTS+i1, i2, em::ex2); + Fld((N_GHOSTS-1)-i1, i2, em::ex3) = -Fld(N_GHOSTS+i1, i2, em::ex3); + } + + if (tags & BC::B) + { + Fld((N_GHOSTS-1)-i1, i2, em::bx1) = -Fld(N_GHOSTS+i1, i2, em::bx1); + Fld((N_GHOSTS-1)-i1, i2, em::bx2) = Fld(N_GHOSTS+i1, i2, em::bx2); + Fld((N_GHOSTS-1)-i1, i2, em::bx3) = Fld(N_GHOSTS+i1, i2, em::bx3); + } + } else { + // GRPIC + raise::KernelError(HERE, "2D GRPIC not implemented"); + } + } else { + raise::KernelError( + HERE, + "ConductorBoundaries_kernel: 2D implementation called for D != 2"); + } + } + + Inline void operator()(index_t i1, index_t i2, index_t i3) const { + if constexpr (M::Dim == Dim::_3D) { + const auto i1_ = COORD(i1); + const auto i2_ = COORD(i2); + const auto i3_ = COORD(i3); + + if constexpr (S == SimEngine::SRPIC) { + // SRPIC + if (tags & BC::E) { + Fld((N_GHOSTS-1)-i1, i2, i3, em::ex1) = Fld(N_GHOSTS+i1, i2, i3, em::ex1); + Fld((N_GHOSTS-1)-i1, i2, i3, em::ex2) = -Fld(N_GHOSTS+i1, i2, i3, em::ex2); + Fld((N_GHOSTS-1)-i1, i2, i3, em::ex3) = -Fld(N_GHOSTS+i1, i2, i3, em::ex3); + } + + if (tags & BC::B) + { + Fld((N_GHOSTS-1)-i1, i2, i3, em::bx1) = -Fld(N_GHOSTS+i1, i2, i3, em::bx1); + Fld((N_GHOSTS-1)-i1, i2, i3, em::bx2) = Fld(N_GHOSTS+i1, i2, i3, em::bx2); + Fld((N_GHOSTS-1)-i1, i2, i3, em::bx3) = Fld(N_GHOSTS+i1, i2, i3, em::bx3); + } + } else { + // GRPIC + raise::KernelError(HERE, "3D GRPIC not implemented"); + } + } else { + raise::KernelError( + HERE, + "ConductorBoundaries_kernel: 3D implementation called for D != 3"); + } + } + }; + /* * @tparam D: Dimension * @tparam P: Positive/Negative direction From b7a863c6de52fe5e32bdc0fa89010e07237f5be7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20B=C3=B6ss?= Date: Fri, 21 Feb 2025 16:55:21 -0600 Subject: [PATCH 377/773] bugfix --- src/kernels/fields_bcs.hpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/kernels/fields_bcs.hpp b/src/kernels/fields_bcs.hpp index fa0b7ec0d..3a253820a 100644 --- a/src/kernels/fields_bcs.hpp +++ b/src/kernels/fields_bcs.hpp @@ -485,7 +485,7 @@ namespace kernel::bc { } }; - template + template struct ConductorBoundaries_kernel { static_assert(M::is_metric, "M must be a metric class"); static_assert(static_cast(o) < @@ -494,7 +494,6 @@ namespace kernel::bc { static constexpr idx_t i = static_cast(o) + 1u; ndfield_t Fld; - const I fset; const M metric; const BCTags tags; @@ -562,13 +561,10 @@ namespace kernel::bc { Inline void operator()(index_t i1, index_t i2, index_t i3) const { if constexpr (M::Dim == Dim::_3D) { - const auto i1_ = COORD(i1); - const auto i2_ = COORD(i2); - const auto i3_ = COORD(i3); if constexpr (S == SimEngine::SRPIC) { // SRPIC - if (tags & BC::E) { + if (tags & BC::E) { Fld((N_GHOSTS-1)-i1, i2, i3, em::ex1) = Fld(N_GHOSTS+i1, i2, i3, em::ex1); Fld((N_GHOSTS-1)-i1, i2, i3, em::ex2) = -Fld(N_GHOSTS+i1, i2, i3, em::ex2); Fld((N_GHOSTS-1)-i1, i2, i3, em::ex3) = -Fld(N_GHOSTS+i1, i2, i3, em::ex3); From f383e492633417d53f7ddd266b29fe07004f03d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20B=C3=B6ss?= Date: Fri, 21 Feb 2025 17:02:04 -0600 Subject: [PATCH 378/773] first attempt at Kokkos::parallel_for loop (broken) --- src/engines/srpic.hpp | 117 ++++++------------------------------------ 1 file changed, 17 insertions(+), 100 deletions(-) diff --git a/src/engines/srpic.hpp b/src/engines/srpic.hpp index 4fca96674..4198c9531 100644 --- a/src/engines/srpic.hpp +++ b/src/engines/srpic.hpp @@ -851,122 +851,39 @@ namespace ntt { "non-cartesian coordinates", HERE); - // magnetic and electron field components - em normal_b_comp, tang_b_comp1, tang_b_comp2, - normal_e_comp, tang_e_comp1, tang_e_comp2; - // current components - // cur normal_j_comp, tang_j_comp1, tang_j_comp2; - - if (dim == in::x1) { - normal_b_comp = em::bx1; - tang_b_comp1 = em::bx2; - tang_b_comp2 = em::bx3; - - normal_e_comp = em::ex1; - tang_e_comp1 = em::ex2; - tang_e_comp2 = em::ex3; - } else if (dim == in::x2) { - normal_b_comp = em::bx2; - tang_b_comp1 = em::bx1; - tang_b_comp2 = em::bx3; - - normal_e_comp = em::ex2; - tang_e_comp1 = em::ex1; - tang_e_comp2 = em::ex3; - } else if (dim == in::x3) { - normal_b_comp = em::bx3; - tang_b_comp1 = em::bx1; - tang_b_comp2 = em::bx2; - - normal_e_comp = em::ex3; - tang_e_comp1 = em::ex1; - tang_e_comp2 = em::ex2; - } else { - raise::Error("Invalid dimension", HERE); - } + std::vector xi_min, xi_max; - std::vector origin_xi_min, origin_xi_max, - target_xi_min, target_xi_max; const std::vector all_dirs { in::x1, in::x2, in::x3 }; for (unsigned short d { 0 }; d < static_cast(M::Dim); ++d) { const auto dd = all_dirs[d]; if (dim == dd) { - // origin: right side of boundary - origin_xi_min.push_back(N_GHOSTS+1); - origin_xi_max.push_back(2*N_GHOSTS); - // target: left side of boundary - target_xi_min.push_back(0); - target_xi_max.push_back(N_GHOSTS); - + xi_min.push_back(0); + xi_max.push_back(N_GHOSTS); } else { - origin_xi_min.push_back(0); - origin_xi_max.push_back(domain.mesh.n_all(dd)); - - target_xi_min.push_back(0); - target_xi_max.push_back(domain.mesh.n_all(dd)); + xi_min.push_back(0); + xi_max.push_back(domain.mesh.n_all(dd)); } } - raise::ErrorIf(target_xi_min.size() != origin_xi_min.size() or - origin_xi_min.size() != static_cast(M::Dim), + raise::ErrorIf(xi_min.size() != xi_max.size() or + xi_min.size() != static_cast(M::Dim), "Invalid range size", HERE); - std::vector comps; - if (tags & BC::E) { - comps.push_back(normal_e_comp); - comps.push_back(tang_e_comp1); - comps.push_back(tang_e_comp2); - } - if (tags & BC::B) { - comps.push_back(normal_b_comp); - comps.push_back(tang_b_comp1); - comps.push_back(tang_b_comp2); - } - - // ToDo: smarter loop/views - auto EB = domain.fields.em; - - // loop over all components - for (const auto& comp : comps) { - - // store sign of component behind boundary - auto new_sign = m_pgen.PerfectConductorFieldsConst( - (bc_in)(sign * ((short)dim + 1)), - (em)comp); - // to do: Kokkos::parallel_for - for (int i = 0; i < N_GHOSTS; i++) - { - if constexpr (M::Dim == Dim::_1D) { - // multiply with correct sign - EB(target_xi_min[0]+i, comp) = new_sign * EB(origin_xi_max[0]-i, comp); - - } else if constexpr (M::Dim == Dim::_2D) { - for (int j = 0; j < domain.mesh.n_all(in::x2); j++) - { - EB(target_xi_min[0]+i, j, comp) = - new_sign * EB(origin_xi_max[0]-i, j, comp); - } - } else if constexpr (M::Dim == Dim::_3D) { - for (int j = 0; j < domain.mesh.n_all(in::x2); j++) - { - for (int k = 0; k < domain.mesh.n_all(in::x3); k++) - { - EB(target_xi_min[0]+i, j, k, comp) = - new_sign * EB(origin_xi_max[0]-i, j, k, comp); - } - } - } else { - raise::Error("Invalid dimension", HERE); - } - } - - // ToDo: set zero at boundary + if (dim == in::x1) + { + Kokkos::parallel_for( + "MatchFields", + CreateRangePolicy(xi_min, xi_max), + kernel::bc::ConductorBoundaries_kernel( + domain.fields.em, + tags)); } + + } - void AtmosphereFieldsIn(dir::direction_t direction, domain_t& domain, BCTags tags) { From 7666918b4117ab726422a6440fcf0135aa39cb05 Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Fri, 21 Feb 2025 22:12:56 -0500 Subject: [PATCH 379/773] Ongoing. --- src/engines/srpic.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/engines/srpic.hpp b/src/engines/srpic.hpp index 4198c9531..fadb55087 100644 --- a/src/engines/srpic.hpp +++ b/src/engines/srpic.hpp @@ -871,11 +871,11 @@ namespace ntt { "Invalid range size", HERE); - if (dim == in::x1) + if constexpr (M::Dim == Dim::_1D) { { Kokkos::parallel_for( "MatchFields", - CreateRangePolicy(xi_min, xi_max), + CreateRangePolicy(xi_min[0], xi_max[0]), kernel::bc::ConductorBoundaries_kernel( domain.fields.em, tags)); From af065442ded1c0fa3ada6ab01398ec522cde1e16 Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Fri, 21 Feb 2025 22:16:54 -0500 Subject: [PATCH 380/773] Ongoing. --- src/engines/srpic.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engines/srpic.hpp b/src/engines/srpic.hpp index fadb55087..da111256a 100644 --- a/src/engines/srpic.hpp +++ b/src/engines/srpic.hpp @@ -871,7 +871,7 @@ namespace ntt { "Invalid range size", HERE); - if constexpr (M::Dim == Dim::_1D) { + if constexpr (M::Dim == Dim::_1D) { Kokkos::parallel_for( "MatchFields", From 0d3cc1cf90ce489d23f918c1b657b98d8b44e0fe Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Fri, 21 Feb 2025 22:19:01 -0500 Subject: [PATCH 381/773] Ongoing. --- src/engines/srpic.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engines/srpic.hpp b/src/engines/srpic.hpp index da111256a..7f38d567a 100644 --- a/src/engines/srpic.hpp +++ b/src/engines/srpic.hpp @@ -875,7 +875,7 @@ namespace ntt { { Kokkos::parallel_for( "MatchFields", - CreateRangePolicy(xi_min[0], xi_max[0]), + CreateRangePolicy( { xi_min[0] } , { xi_max[0] } ), kernel::bc::ConductorBoundaries_kernel( domain.fields.em, tags)); From 4a57c38538916967860bdbbbfe34e452ed785942 Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Fri, 21 Feb 2025 22:35:06 -0500 Subject: [PATCH 382/773] Ongoing. --- src/engines/srpic.hpp | 2 +- src/kernels/fields_bcs.hpp | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/engines/srpic.hpp b/src/engines/srpic.hpp index 7f38d567a..6e4f51945 100644 --- a/src/engines/srpic.hpp +++ b/src/engines/srpic.hpp @@ -876,7 +876,7 @@ namespace ntt { Kokkos::parallel_for( "MatchFields", CreateRangePolicy( { xi_min[0] } , { xi_max[0] } ), - kernel::bc::ConductorBoundaries_kernel( + kernel::bc::ConductorBoundaries_kernel( domain.fields.em, tags)); } diff --git a/src/kernels/fields_bcs.hpp b/src/kernels/fields_bcs.hpp index 3a253820a..48f2aa7d3 100644 --- a/src/kernels/fields_bcs.hpp +++ b/src/kernels/fields_bcs.hpp @@ -494,7 +494,6 @@ namespace kernel::bc { static constexpr idx_t i = static_cast(o) + 1u; ndfield_t Fld; - const M metric; const BCTags tags; ConductorBoundaries_kernel(ndfield_t Fld, From ff5a3ee8dbb2ca2bc60279f8885918497a1acb5a Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Fri, 21 Feb 2025 22:35:54 -0500 Subject: [PATCH 383/773] Ongoing. --- src/engines/srpic.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engines/srpic.hpp b/src/engines/srpic.hpp index 6e4f51945..7f38d567a 100644 --- a/src/engines/srpic.hpp +++ b/src/engines/srpic.hpp @@ -876,7 +876,7 @@ namespace ntt { Kokkos::parallel_for( "MatchFields", CreateRangePolicy( { xi_min[0] } , { xi_max[0] } ), - kernel::bc::ConductorBoundaries_kernel( + kernel::bc::ConductorBoundaries_kernel( domain.fields.em, tags)); } From d6b2b1c266a127763a60ee6706f59f64214f7795 Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Sat, 22 Feb 2025 11:16:58 -0500 Subject: [PATCH 384/773] Ongoing. --- setups/srpic/shocktest/pgen.hpp | 179 ++++++++++++++++++++++++++++++ setups/srpic/shocktest/shock.py | 75 +++++++++++++ setups/srpic/shocktest/shock.toml | 56 ++++++++++ 3 files changed, 310 insertions(+) create mode 100644 setups/srpic/shocktest/pgen.hpp create mode 100644 setups/srpic/shocktest/shock.py create mode 100644 setups/srpic/shocktest/shock.toml diff --git a/setups/srpic/shocktest/pgen.hpp b/setups/srpic/shocktest/pgen.hpp new file mode 100644 index 000000000..83f19df52 --- /dev/null +++ b/setups/srpic/shocktest/pgen.hpp @@ -0,0 +1,179 @@ +#ifndef PROBLEM_GENERATOR_H +#define PROBLEM_GENERATOR_H + +#include "enums.h" +#include "global.h" + +#include "arch/traits.h" +#include "utils/error.h" +#include "utils/numeric.h" + +#include "archetypes/energy_dist.h" +#include "archetypes/particle_injector.h" +#include "archetypes/problem_generator.h" +#include "framework/domain/metadomain.h" + +#include + +namespace user { + using namespace ntt; + + template + struct InitFields { + /* + Sets up magnetic and electric field components for the simulation. + Must satisfy E = -v x B for Lorentz Force to be zero. + + @param bmag: magnetic field scaling + @param btheta: magnetic field polar angle + @param bphi: magnetic field azimuthal angle + @param drift_ux: drift velocity in the x direction + */ + InitFields(real_t bmag, real_t btheta, real_t bphi, real_t drift_ux) + : Bmag { bmag } + , Btheta { btheta * static_cast(convert::deg2rad) } + , Bphi { bphi * static_cast(convert::deg2rad) } + , Vx { drift_ux } {} + + // magnetic field components + Inline auto bx1(const coord_t& x_Ph) const -> real_t { + return x_Ph[0]; + } + + Inline auto bx2(const coord_t&) const -> real_t { + return x_Ph[0]; + } + + Inline auto bx3(const coord_t&) const -> real_t { + return x_Ph[0]; + } + + // electric field components + Inline auto ex1(const coord_t&) const -> real_t { + return x_Ph[0]; + } + + Inline auto ex2(const coord_t&) const -> real_t { + return x_Ph[0]; + } + + Inline auto ex3(const coord_t&) const -> real_t { + return x_Ph[0]; + } + + private: + const real_t Btheta, Bphi, Vx, Bmag; + }; + + template + struct PGen : public arch::ProblemGenerator { + // compatibility traits for the problem generator + static constexpr auto engines { traits::compatible_with::value }; + static constexpr auto metrics { traits::compatible_with::value }; + static constexpr auto dimensions { + traits::compatible_with::value + }; + + // for easy access to variables in the child class + using arch::ProblemGenerator::D; + using arch::ProblemGenerator::C; + using arch::ProblemGenerator::params; + + const real_t drift_ux, temperature; + + const real_t Btheta, Bphi, Bmag; + InitFields init_flds; + + inline PGen(const SimulationParams& p, const Metadomain& m) + : arch::ProblemGenerator { p } + , drift_ux { p.template get("setup.drift_ux") } + , temperature { p.template get("setup.temperature") } + , Bmag { p.template get("setup.Bmag", ZERO) } + , Btheta { p.template get("setup.Btheta", ZERO) } + , Bphi { p.template get("setup.Bphi", ZERO) } + , init_flds { Bmag, Btheta, Bphi, drift_ux } {} + + inline PGen() {} + + auto FixFieldsConst(const bc_in&, const em& comp) const + -> std::pair { + if (comp == em::ex2) { + return { init_flds.ex2({ ZERO }), true }; + } else if (comp == em::ex3) { + return { init_flds.ex3({ ZERO }), true }; + } else { + return { ZERO, false }; + } + } + + + auto PerfectConductorFieldsConst(const bc_in&, const em& comp) const -> real_t{ + + // electric field components + if (comp == em::ex1) { + return ONE; + } else if (comp == em::ex2) { + return -ONE; + } else if (comp == em::ex3) { + return -ONE; } + // magentic field components + else if (comp == em::bx1) { + return -ONE; + } else if (comp == em::bx2) { + return ONE; + } else if (comp == em::bx3) { + return ONE;} + // should never be the case + else + { + return ZERO; + } + } + + // auto PerfectConductorCurrentsConst(const bc_in &, const cur &comp) const + // -> std::pair + // { + // // ToDo + // if (comp == cur::jx1) + // { + // return ZERO; + // } + // else if (comp == cur::jx2) + // { + // return ZERO; + // } + // else if (comp == cur::jx3) + // { + // return ZERO; + // } + // else + // { + // return ZERO; + // } + // } + + auto MatchFields(real_t time) const -> InitFields { + return init_flds; + } + + inline void InitPrtls(Domain& local_domain) { + const auto energy_dist = arch::Maxwellian(local_domain.mesh.metric, + local_domain.random_pool, + temperature, + -drift_ux, + in::x1); + + const auto injector = arch::UniformInjector( + energy_dist, + { 1, 2 }); + // arch::InjectUniform>( + // params, + // local_domain, + // injector, + // 1.0); + } + }; + +} // namespace user + +#endif diff --git a/setups/srpic/shocktest/shock.py b/setups/srpic/shocktest/shock.py new file mode 100644 index 000000000..dc1565572 --- /dev/null +++ b/setups/srpic/shocktest/shock.py @@ -0,0 +1,75 @@ +import nt2.read as nt2r +import matplotlib.pyplot as plt +import matplotlib as mpl + +data = nt2r.Data("shock.h5") + + +def frame(ti, f): + quantities = [ + { + "name": "density", + "compute": lambda f: f.N_2 + f.N_1, + "cmap": "inferno", + "norm": mpl.colors.Normalize(0, 5), + }, + { + "name": r"$E_x$", + "compute": lambda f: f.Ex, + "cmap": "RdBu_r", + "norm": mpl.colors.Normalize(-0.05, 0.05), + }, + { + "name": r"$E_y$", + "compute": lambda f: f.Ey, + "cmap": "RdBu_r", + "norm": mpl.colors.Normalize(-0.05, 0.05), + }, + { + "name": r"$E_z$", + "compute": lambda f: f.Ez, + "cmap": "RdBu_r", + "norm": mpl.colors.Normalize(-0.05, 0.05), + }, + { + "name": r"$B_x$", + "compute": lambda f: f.Bx, + "cmap": "BrBG", + "norm": mpl.colors.Normalize(-0.05, 0.05), + }, + { + "name": r"$B_y$", + "compute": lambda f: f.By, + "cmap": "BrBG", + "norm": mpl.colors.Normalize(-0.05, 0.05), + }, + { + "name": r"$B_z$", + "compute": lambda f: f.Bz, + "cmap": "BrBG", + "norm": mpl.colors.Normalize(-0.05, 0.05), + }, + ] + fig = plt.figure(figsize=(12, 5.5), dpi=300) + gs = fig.add_gridspec(len(quantities), 1, hspace=0.02) + axs = [fig.add_subplot(gs[i]) for i in range(len(quantities))] + + for ax, q in zip(axs, quantities): + q["compute"](f.isel(t=ti)).plot( + ax=ax, + cmap=q["cmap"], + norm=q["norm"], + cbar_kwargs={"label": q["name"], "shrink": 0.8, "aspect": 10, "pad": 0.005}, + ) + for i, ax in enumerate(axs): + ax.set(aspect=1) + if i != 0: + ax.set(title=None) + if i != len(axs) - 1: + ax.set( + xticks=[], + xticklabels=[], + xlabel=None, + title=ax.get_title().split(",")[0], + ) + return fig diff --git a/setups/srpic/shocktest/shock.toml b/setups/srpic/shocktest/shock.toml new file mode 100644 index 000000000..fdbc44465 --- /dev/null +++ b/setups/srpic/shocktest/shock.toml @@ -0,0 +1,56 @@ +[simulation] + name = "shock" + engine = "srpic" + runtime = 50.0 + +[grid] + resolution = [2048, 128] + extent = [[0.0, 10.0], [-0.3125, 0.3125]] + + [grid.metric] + metric = "minkowski" + + [grid.boundaries] + fields = [["CONDUCTOR", "FIXED"], ["PERIODIC"]] + particles = [["REFLECT", "ABSORB"], ["PERIODIC"]] + +[scales] + larmor0 = 1e-2 + skindepth0 = 1e-2 + +[algorithms] + current_filters = 8 + fieldsolver = "false" + deposit = "false" + + [algorithms.timestep] + CFL = 0.5 + +[particles] + ppc0 = 16.0 + + [[particles.species]] + label = "e-" + mass = 1.0 + charge = -1.0 + maxnpart = 1e8 + + [[particles.species]] + label = "e+" + mass = 1.0 + charge = 1.0 + maxnpart = 1e8 + +[setup] + drift_ux = 0.1 + temperature = 1e-3 + Bmag = 1.0 + Btheta = 0.0 + Bphi = 0.0 + +[output] + interval = 1 + format = "hdf5" + + [output.fields] + quantities = ["N_1", "N_2", "E", "B", "T0i_1", "T0i_2", "J"] From f0ed6c7ba59988ecb52de96760643a3d34d513bf Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Sat, 22 Feb 2025 11:20:28 -0500 Subject: [PATCH 385/773] Ongoing. --- setups/srpic/shocktest/shock.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/setups/srpic/shocktest/shock.toml b/setups/srpic/shocktest/shock.toml index fdbc44465..a77f5c2e9 100644 --- a/setups/srpic/shocktest/shock.toml +++ b/setups/srpic/shocktest/shock.toml @@ -54,3 +54,6 @@ [output.fields] quantities = ["N_1", "N_2", "E", "B", "T0i_1", "T0i_2", "J"] + + [output.debug] + ghosts = true From 79d323741ef5eeeaf939ee502a56629842baeac1 Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Sat, 22 Feb 2025 14:01:06 -0500 Subject: [PATCH 386/773] Ongoing. --- setups/srpic/shocktest/pgen.hpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/setups/srpic/shocktest/pgen.hpp b/setups/srpic/shocktest/pgen.hpp index 83f19df52..7724893a1 100644 --- a/setups/srpic/shocktest/pgen.hpp +++ b/setups/srpic/shocktest/pgen.hpp @@ -40,24 +40,24 @@ namespace user { return x_Ph[0]; } - Inline auto bx2(const coord_t&) const -> real_t { + Inline auto bx2(const coord_t& x_Ph) const -> real_t { return x_Ph[0]; } - Inline auto bx3(const coord_t&) const -> real_t { + Inline auto bx3(const coord_t& x_Ph) const -> real_t { return x_Ph[0]; } // electric field components - Inline auto ex1(const coord_t&) const -> real_t { + Inline auto ex1(const coord_t& x_Ph) const -> real_t { return x_Ph[0]; } - Inline auto ex2(const coord_t&) const -> real_t { + Inline auto ex2(const coord_t& x_Ph) const -> real_t { return x_Ph[0]; } - Inline auto ex3(const coord_t&) const -> real_t { + Inline auto ex3(const coord_t& x_Ph) const -> real_t { return x_Ph[0]; } From 17b469bfa3137317145a50853271773e3ec0c8b2 Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Sat, 22 Feb 2025 17:15:38 -0500 Subject: [PATCH 387/773] Ongoing. --- src/kernels/fields_bcs.hpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/kernels/fields_bcs.hpp b/src/kernels/fields_bcs.hpp index 48f2aa7d3..8eda1b34a 100644 --- a/src/kernels/fields_bcs.hpp +++ b/src/kernels/fields_bcs.hpp @@ -543,9 +543,12 @@ namespace kernel::bc { if (tags & BC::B) { - Fld((N_GHOSTS-1)-i1, i2, em::bx1) = -Fld(N_GHOSTS+i1, i2, em::bx1); - Fld((N_GHOSTS-1)-i1, i2, em::bx2) = Fld(N_GHOSTS+i1, i2, em::bx2); - Fld((N_GHOSTS-1)-i1, i2, em::bx3) = Fld(N_GHOSTS+i1, i2, em::bx3); + // Fld((N_GHOSTS-1)-i1, i2, em::bx1) = -Fld(N_GHOSTS+i1, i2, em::bx1); + // Fld((N_GHOSTS-1)-i1, i2, em::bx2) = Fld(N_GHOSTS+i1, i2, em::bx2); + // Fld((N_GHOSTS-1)-i1, i2, em::bx3) = Fld(N_GHOSTS+i1, i2, em::bx3); + Fld((N_GHOSTS-1)-i1, i2, em::bx1) = 1.0; + Fld((N_GHOSTS-1)-i1, i2, em::bx2) = 2.0; + Fld((N_GHOSTS-1)-i1, i2, em::bx3) = 3.0; } } else { // GRPIC From e234173bd8688c8585f4ef6d51c1cc721ff49e38 Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Sat, 22 Feb 2025 17:21:07 -0500 Subject: [PATCH 388/773] Ongoing. --- setups/srpic/shocktest/pgen.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setups/srpic/shocktest/pgen.hpp b/setups/srpic/shocktest/pgen.hpp index 7724893a1..0dc91d3e2 100644 --- a/setups/srpic/shocktest/pgen.hpp +++ b/setups/srpic/shocktest/pgen.hpp @@ -41,7 +41,7 @@ namespace user { } Inline auto bx2(const coord_t& x_Ph) const -> real_t { - return x_Ph[0]; + return -x_Ph[0]; } Inline auto bx3(const coord_t& x_Ph) const -> real_t { From de510ea1abdc4e7381f5705e38fbe33510e3bc9a Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Sat, 22 Feb 2025 18:50:58 -0500 Subject: [PATCH 389/773] Ongoing. --- src/engines/srpic.hpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/engines/srpic.hpp b/src/engines/srpic.hpp index 7f38d567a..90aa271a3 100644 --- a/src/engines/srpic.hpp +++ b/src/engines/srpic.hpp @@ -880,6 +880,16 @@ namespace ntt { domain.fields.em, tags)); } + + if constexpr (M::Dim == Dim::_2D) + { + Kokkos::parallel_for( + "MatchFields", + CreateRangePolicy( { xi_min[0], xi_min[1] } , { xi_max[0], xi_max[1] } ), + kernel::bc::ConductorBoundaries_kernel( + domain.fields.em, + tags)); + } } From 0524d782381c66c6fcf291027e85009ccdfa8cd6 Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Sat, 22 Feb 2025 19:05:19 -0500 Subject: [PATCH 390/773] Ongoing. --- src/kernels/fields_bcs.hpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/kernels/fields_bcs.hpp b/src/kernels/fields_bcs.hpp index 8eda1b34a..490042304 100644 --- a/src/kernels/fields_bcs.hpp +++ b/src/kernels/fields_bcs.hpp @@ -543,12 +543,12 @@ namespace kernel::bc { if (tags & BC::B) { - // Fld((N_GHOSTS-1)-i1, i2, em::bx1) = -Fld(N_GHOSTS+i1, i2, em::bx1); - // Fld((N_GHOSTS-1)-i1, i2, em::bx2) = Fld(N_GHOSTS+i1, i2, em::bx2); - // Fld((N_GHOSTS-1)-i1, i2, em::bx3) = Fld(N_GHOSTS+i1, i2, em::bx3); - Fld((N_GHOSTS-1)-i1, i2, em::bx1) = 1.0; - Fld((N_GHOSTS-1)-i1, i2, em::bx2) = 2.0; - Fld((N_GHOSTS-1)-i1, i2, em::bx3) = 3.0; + Fld((N_GHOSTS-1)-i1, i2, em::bx1) = Fld(N_GHOSTS+i1, i2, em::bx1); + Fld((N_GHOSTS-1)-i1, i2, em::bx2) = Fld(N_GHOSTS+i1, i2, em::bx2); + Fld((N_GHOSTS-1)-i1, i2, em::bx3) = Fld(N_GHOSTS+i1, i2, em::bx3); + // Fld((N_GHOSTS-1)-i1, i2, em::bx1) = 1.0; + // Fld((N_GHOSTS-1)-i1, i2, em::bx2) = 2.0; + // Fld((N_GHOSTS-1)-i1, i2, em::bx3) = 3.0; } } else { // GRPIC From 9d78b9e2a43740cc1a1fb7d2faffc6871c8ba0b1 Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Sat, 22 Feb 2025 19:10:18 -0500 Subject: [PATCH 391/773] Ongoing. --- src/kernels/fields_bcs.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/kernels/fields_bcs.hpp b/src/kernels/fields_bcs.hpp index 490042304..33f2813ca 100644 --- a/src/kernels/fields_bcs.hpp +++ b/src/kernels/fields_bcs.hpp @@ -543,9 +543,9 @@ namespace kernel::bc { if (tags & BC::B) { - Fld((N_GHOSTS-1)-i1, i2, em::bx1) = Fld(N_GHOSTS+i1, i2, em::bx1); - Fld((N_GHOSTS-1)-i1, i2, em::bx2) = Fld(N_GHOSTS+i1, i2, em::bx2); - Fld((N_GHOSTS-1)-i1, i2, em::bx3) = Fld(N_GHOSTS+i1, i2, em::bx3); + Fld((N_GHOSTS-1)-i1, i2, em::bx1) = - Fld(N_GHOSTS+i1, i2, em::bx1); + Fld((N_GHOSTS-1)-i1, i2, em::bx2) = - Fld(N_GHOSTS+i1, i2, em::bx2); + Fld((N_GHOSTS-1)-i1, i2, em::bx3) = - Fld(N_GHOSTS+i1, i2, em::bx3); // Fld((N_GHOSTS-1)-i1, i2, em::bx1) = 1.0; // Fld((N_GHOSTS-1)-i1, i2, em::bx2) = 2.0; // Fld((N_GHOSTS-1)-i1, i2, em::bx3) = 3.0; From cec22b04960cad3889473c956a17b4e270ef83c0 Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Sat, 22 Feb 2025 20:01:27 -0500 Subject: [PATCH 392/773] Ongoing. --- src/kernels/fields_bcs.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/kernels/fields_bcs.hpp b/src/kernels/fields_bcs.hpp index 33f2813ca..aebe35794 100644 --- a/src/kernels/fields_bcs.hpp +++ b/src/kernels/fields_bcs.hpp @@ -543,9 +543,9 @@ namespace kernel::bc { if (tags & BC::B) { - Fld((N_GHOSTS-1)-i1, i2, em::bx1) = - Fld(N_GHOSTS+i1, i2, em::bx1); - Fld((N_GHOSTS-1)-i1, i2, em::bx2) = - Fld(N_GHOSTS+i1, i2, em::bx2); - Fld((N_GHOSTS-1)-i1, i2, em::bx3) = - Fld(N_GHOSTS+i1, i2, em::bx3); + Fld((N_GHOSTS)-i1, i2, em::bx1) = - Fld(N_GHOSTS+1+i1, i2, em::bx1); + Fld((N_GHOSTS)-i1, i2, em::bx2) = - Fld(N_GHOSTS+1+i1, i2, em::bx2); + Fld((N_GHOSTS)-i1, i2, em::bx3) = - Fld(N_GHOSTS+1+i1, i2, em::bx3); // Fld((N_GHOSTS-1)-i1, i2, em::bx1) = 1.0; // Fld((N_GHOSTS-1)-i1, i2, em::bx2) = 2.0; // Fld((N_GHOSTS-1)-i1, i2, em::bx3) = 3.0; From b3754e29a4bf20ea04a11e494866dd7c5323d59c Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Sat, 22 Feb 2025 20:54:37 -0500 Subject: [PATCH 393/773] Ongoing. --- src/kernels/fields_bcs.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/kernels/fields_bcs.hpp b/src/kernels/fields_bcs.hpp index aebe35794..33f2813ca 100644 --- a/src/kernels/fields_bcs.hpp +++ b/src/kernels/fields_bcs.hpp @@ -543,9 +543,9 @@ namespace kernel::bc { if (tags & BC::B) { - Fld((N_GHOSTS)-i1, i2, em::bx1) = - Fld(N_GHOSTS+1+i1, i2, em::bx1); - Fld((N_GHOSTS)-i1, i2, em::bx2) = - Fld(N_GHOSTS+1+i1, i2, em::bx2); - Fld((N_GHOSTS)-i1, i2, em::bx3) = - Fld(N_GHOSTS+1+i1, i2, em::bx3); + Fld((N_GHOSTS-1)-i1, i2, em::bx1) = - Fld(N_GHOSTS+i1, i2, em::bx1); + Fld((N_GHOSTS-1)-i1, i2, em::bx2) = - Fld(N_GHOSTS+i1, i2, em::bx2); + Fld((N_GHOSTS-1)-i1, i2, em::bx3) = - Fld(N_GHOSTS+i1, i2, em::bx3); // Fld((N_GHOSTS-1)-i1, i2, em::bx1) = 1.0; // Fld((N_GHOSTS-1)-i1, i2, em::bx2) = 2.0; // Fld((N_GHOSTS-1)-i1, i2, em::bx3) = 3.0; From 83dba373e226994a77d5845b574b12c43e69e947 Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Sat, 22 Feb 2025 21:02:54 -0500 Subject: [PATCH 394/773] Ongoing. --- src/kernels/fields_bcs.hpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/kernels/fields_bcs.hpp b/src/kernels/fields_bcs.hpp index 33f2813ca..3e6458877 100644 --- a/src/kernels/fields_bcs.hpp +++ b/src/kernels/fields_bcs.hpp @@ -543,12 +543,12 @@ namespace kernel::bc { if (tags & BC::B) { - Fld((N_GHOSTS-1)-i1, i2, em::bx1) = - Fld(N_GHOSTS+i1, i2, em::bx1); - Fld((N_GHOSTS-1)-i1, i2, em::bx2) = - Fld(N_GHOSTS+i1, i2, em::bx2); - Fld((N_GHOSTS-1)-i1, i2, em::bx3) = - Fld(N_GHOSTS+i1, i2, em::bx3); - // Fld((N_GHOSTS-1)-i1, i2, em::bx1) = 1.0; - // Fld((N_GHOSTS-1)-i1, i2, em::bx2) = 2.0; - // Fld((N_GHOSTS-1)-i1, i2, em::bx3) = 3.0; + // Fld((N_GHOSTS-1)-i1, i2, em::bx1) = - Fld(N_GHOSTS+i1, i2, em::bx1); + // Fld((N_GHOSTS-1)-i1, i2, em::bx2) = - Fld(N_GHOSTS+i1, i2, em::bx2); + // Fld((N_GHOSTS-1)-i1, i2, em::bx3) = - Fld(N_GHOSTS+i1, i2, em::bx3); + Fld((N_GHOSTS-1)-i1, i2, em::bx1) = 1.0; + Fld((N_GHOSTS-1)-i1, i2, em::bx2) = 2.0; + Fld((N_GHOSTS-1)-i1, i2, em::bx3) = 3.0; } } else { // GRPIC From a7ef051440b5695e3c30bc88dc63bba7865abf2c Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Sat, 22 Feb 2025 21:13:50 -0500 Subject: [PATCH 395/773] Ongoing. --- src/kernels/fields_bcs.hpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/kernels/fields_bcs.hpp b/src/kernels/fields_bcs.hpp index 3e6458877..082d06329 100644 --- a/src/kernels/fields_bcs.hpp +++ b/src/kernels/fields_bcs.hpp @@ -543,12 +543,12 @@ namespace kernel::bc { if (tags & BC::B) { - // Fld((N_GHOSTS-1)-i1, i2, em::bx1) = - Fld(N_GHOSTS+i1, i2, em::bx1); - // Fld((N_GHOSTS-1)-i1, i2, em::bx2) = - Fld(N_GHOSTS+i1, i2, em::bx2); - // Fld((N_GHOSTS-1)-i1, i2, em::bx3) = - Fld(N_GHOSTS+i1, i2, em::bx3); - Fld((N_GHOSTS-1)-i1, i2, em::bx1) = 1.0; - Fld((N_GHOSTS-1)-i1, i2, em::bx2) = 2.0; - Fld((N_GHOSTS-1)-i1, i2, em::bx3) = 3.0; + Fld((N_GHOSTS-1)-i1, i2, em::bx1) = - Fld(N_GHOSTS+1+i1, i2, em::bx1); + Fld((N_GHOSTS-1)-i1, i2, em::bx2) = - Fld(N_GHOSTS+i1, i2, em::bx2); + Fld((N_GHOSTS-1)-i1, i2, em::bx3) = - Fld(N_GHOSTS+i1, i2, em::bx3); + // Fld((N_GHOSTS-1)-i1, i2, em::bx1) = 1.0; + // Fld((N_GHOSTS-1)-i1, i2, em::bx2) = 2.0; + // Fld((N_GHOSTS-1)-i1, i2, em::bx3) = 3.0; } } else { // GRPIC From d219fc43854fcaafc099d3889587403f1b2d1a38 Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Sat, 22 Feb 2025 21:43:02 -0500 Subject: [PATCH 396/773] Ongoing. --- setups/srpic/shocktest/pgen.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setups/srpic/shocktest/pgen.hpp b/setups/srpic/shocktest/pgen.hpp index 0dc91d3e2..685521f09 100644 --- a/setups/srpic/shocktest/pgen.hpp +++ b/setups/srpic/shocktest/pgen.hpp @@ -45,7 +45,7 @@ namespace user { } Inline auto bx3(const coord_t& x_Ph) const -> real_t { - return x_Ph[0]; + return ONE; } // electric field components From 044ccea51284764cc110069d64d6702f2c028913 Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Sat, 22 Feb 2025 22:06:25 -0500 Subject: [PATCH 397/773] Ongoing. --- setups/srpic/shocktest/pgen.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setups/srpic/shocktest/pgen.hpp b/setups/srpic/shocktest/pgen.hpp index 685521f09..0dc91d3e2 100644 --- a/setups/srpic/shocktest/pgen.hpp +++ b/setups/srpic/shocktest/pgen.hpp @@ -45,7 +45,7 @@ namespace user { } Inline auto bx3(const coord_t& x_Ph) const -> real_t { - return ONE; + return x_Ph[0]; } // electric field components From 2af41d83e01527f3bdbb2548e95ab7d098648b25 Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Sat, 22 Feb 2025 22:16:17 -0500 Subject: [PATCH 398/773] Ongoing. --- setups/srpic/shocktest/pgen.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/setups/srpic/shocktest/pgen.hpp b/setups/srpic/shocktest/pgen.hpp index 0dc91d3e2..f8bf67dab 100644 --- a/setups/srpic/shocktest/pgen.hpp +++ b/setups/srpic/shocktest/pgen.hpp @@ -37,7 +37,7 @@ namespace user { // magnetic field components Inline auto bx1(const coord_t& x_Ph) const -> real_t { - return x_Ph[0]; + return ZERO; } Inline auto bx2(const coord_t& x_Ph) const -> real_t { @@ -50,15 +50,15 @@ namespace user { // electric field components Inline auto ex1(const coord_t& x_Ph) const -> real_t { - return x_Ph[0]; + return ZERO; } Inline auto ex2(const coord_t& x_Ph) const -> real_t { - return x_Ph[0]; + return ZERO; } Inline auto ex3(const coord_t& x_Ph) const -> real_t { - return x_Ph[0]; + return ZERO; } private: From 056c6294df2c23d568805e402eb28a1ae9952fb7 Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Sat, 22 Feb 2025 22:34:56 -0500 Subject: [PATCH 399/773] Ongoing. --- setups/srpic/shocktest/pgen.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setups/srpic/shocktest/pgen.hpp b/setups/srpic/shocktest/pgen.hpp index f8bf67dab..39ce8ea03 100644 --- a/setups/srpic/shocktest/pgen.hpp +++ b/setups/srpic/shocktest/pgen.hpp @@ -45,7 +45,7 @@ namespace user { } Inline auto bx3(const coord_t& x_Ph) const -> real_t { - return x_Ph[0]; + return -x_Ph[0]; } // electric field components From 7d9a1a39d75d239bb8ff387bc47cee4c5305f333 Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Sat, 22 Feb 2025 22:58:19 -0500 Subject: [PATCH 400/773] Ongoing. --- src/kernels/fields_bcs.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/kernels/fields_bcs.hpp b/src/kernels/fields_bcs.hpp index 082d06329..fe5ae4122 100644 --- a/src/kernels/fields_bcs.hpp +++ b/src/kernels/fields_bcs.hpp @@ -536,9 +536,9 @@ namespace kernel::bc { if constexpr (S == SimEngine::SRPIC) { // SRPIC if (tags & BC::E) { - Fld((N_GHOSTS-1)-i1, i2, em::ex1) = Fld(N_GHOSTS+i1, i2, em::ex1); - Fld((N_GHOSTS-1)-i1, i2, em::ex2) = -Fld(N_GHOSTS+i1, i2, em::ex2); - Fld((N_GHOSTS-1)-i1, i2, em::ex3) = -Fld(N_GHOSTS+i1, i2, em::ex3); + Fld((N_GHOSTS-1)-i1, i2, em::ex1) = - Fld(N_GHOSTS+i1, i2, em::ex1); + Fld((N_GHOSTS-1)-i1, i2, em::ex2) = - Fld(N_GHOSTS+1+i1, i2, em::ex2); + Fld((N_GHOSTS-1)-i1, i2, em::ex3) = - Fld(N_GHOSTS+1+i1, i2, em::ex3); } if (tags & BC::B) From d8abf1b2688f61636fb604b017e5c7a85073c0df Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Tue, 25 Feb 2025 23:51:36 -0500 Subject: [PATCH 401/773] Ongoing. --- setups/srpic/shocktest/pgen.hpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/setups/srpic/shocktest/pgen.hpp b/setups/srpic/shocktest/pgen.hpp index 39ce8ea03..2cb66539f 100644 --- a/setups/srpic/shocktest/pgen.hpp +++ b/setups/srpic/shocktest/pgen.hpp @@ -36,16 +36,16 @@ namespace user { , Vx { drift_ux } {} // magnetic field components - Inline auto bx1(const coord_t& x_Ph) const -> real_t { - return ZERO; + Inline auto bx1(const coord_t&) const -> real_t { + return Bmag * math::cos(Btheta); } - Inline auto bx2(const coord_t& x_Ph) const -> real_t { - return -x_Ph[0]; + Inline auto bx2(const coord_t&) const -> real_t { + return Bmag * math::sin(Btheta) * math::sin(Bphi); } - Inline auto bx3(const coord_t& x_Ph) const -> real_t { - return -x_Ph[0]; + Inline auto bx3(const coord_t&) const -> real_t { + return Bmag * math::sin(Btheta) * math::cos(Bphi); } // electric field components From a17db6280545241cd28c85936d772314369606e6 Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Tue, 25 Feb 2025 23:59:44 -0500 Subject: [PATCH 402/773] Ongoing. --- setups/srpic/shocktest/pgen.hpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/setups/srpic/shocktest/pgen.hpp b/setups/srpic/shocktest/pgen.hpp index 2cb66539f..b77583ccb 100644 --- a/setups/srpic/shocktest/pgen.hpp +++ b/setups/srpic/shocktest/pgen.hpp @@ -49,16 +49,16 @@ namespace user { } // electric field components - Inline auto ex1(const coord_t& x_Ph) const -> real_t { + Inline auto ex1(const coord_t&) const -> real_t { return ZERO; } - Inline auto ex2(const coord_t& x_Ph) const -> real_t { - return ZERO; + Inline auto ex2(const coord_t&) const -> real_t { + return -Vx * Bmag * math::sin(Btheta) * math::cos(Bphi); } - Inline auto ex3(const coord_t& x_Ph) const -> real_t { - return ZERO; + Inline auto ex3(const coord_t&) const -> real_t { + return Vx * Bmag * math::sin(Btheta) * math::sin(Bphi); } private: From 1d109a062753f09885239f289c4c0cf2280320a7 Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Thu, 27 Feb 2025 11:42:46 -0500 Subject: [PATCH 403/773] Ongoing. --- setups/srpic/shocktest/pgen.hpp | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/setups/srpic/shocktest/pgen.hpp b/setups/srpic/shocktest/pgen.hpp index b77583ccb..f92086528 100644 --- a/setups/srpic/shocktest/pgen.hpp +++ b/setups/srpic/shocktest/pgen.hpp @@ -36,29 +36,34 @@ namespace user { , Vx { drift_ux } {} // magnetic field components - Inline auto bx1(const coord_t&) const -> real_t { - return Bmag * math::cos(Btheta); + Inline auto bx1(const coord_t& x_ph) const -> real_t { + // return Bmag * math::cos(Btheta); + return ZERO; } - Inline auto bx2(const coord_t&) const -> real_t { - return Bmag * math::sin(Btheta) * math::sin(Bphi); + Inline auto bx2(const coord_t& x_ph) const -> real_t { + // return Bmag * math::sin(Btheta) * math::sin(Bphi); + return ZERO; } - Inline auto bx3(const coord_t&) const -> real_t { - return Bmag * math::sin(Btheta) * math::cos(Bphi); + Inline auto bx3(const coord_t& x_ph) const -> real_t { + // return Bmag * math::sin(Btheta) * math::cos(Bphi); + return ONE + 0.01 * (ONE - math::tanh(20.*(-1.5 + x))*math::tanh(20.*(-0.5 + x)))/2.0 * math::sin(4.0 * constant::PI * x_ph[0]); } // electric field components - Inline auto ex1(const coord_t&) const -> real_t { + Inline auto ex1(const coord_t& x_ph) const -> real_t { return ZERO; } - Inline auto ex2(const coord_t&) const -> real_t { - return -Vx * Bmag * math::sin(Btheta) * math::cos(Bphi); + Inline auto ex2(const coord_t& x_ph) const -> real_t { + // return -Vx * Bmag * math::sin(Btheta) * math::cos(Bphi); + return ZERO + 0.01 * (ONE - math::tanh(20.*(-1.5 + x))*math::tanh(20.*(-0.5 + x)))/2.0 * math::sin(4.0 * constant::PI * x_ph[0]); } - Inline auto ex3(const coord_t&) const -> real_t { - return Vx * Bmag * math::sin(Btheta) * math::sin(Bphi); + Inline auto ex3(const coord_t& x_ph) const -> real_t { + // return Vx * Bmag * math::sin(Btheta) * math::sin(Bphi); + return ZERO; } private: From bee7530bf59a8386b14799114a393a015105f7f7 Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Thu, 27 Feb 2025 12:01:42 -0500 Subject: [PATCH 404/773] Ongoing. --- setups/srpic/shocktest/pgen.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setups/srpic/shocktest/pgen.hpp b/setups/srpic/shocktest/pgen.hpp index f92086528..c43688d02 100644 --- a/setups/srpic/shocktest/pgen.hpp +++ b/setups/srpic/shocktest/pgen.hpp @@ -48,7 +48,7 @@ namespace user { Inline auto bx3(const coord_t& x_ph) const -> real_t { // return Bmag * math::sin(Btheta) * math::cos(Bphi); - return ONE + 0.01 * (ONE - math::tanh(20.*(-1.5 + x))*math::tanh(20.*(-0.5 + x)))/2.0 * math::sin(4.0 * constant::PI * x_ph[0]); + return ONE + 0.01 * (ONE - math::tanh(20.*(-1.5 + x_ph[0]))*math::tanh(20.*(-0.5 + x_ph[0])))/2.0 * math::sin(4.0 * constant::PI * x_ph[0]); } // electric field components @@ -58,7 +58,7 @@ namespace user { Inline auto ex2(const coord_t& x_ph) const -> real_t { // return -Vx * Bmag * math::sin(Btheta) * math::cos(Bphi); - return ZERO + 0.01 * (ONE - math::tanh(20.*(-1.5 + x))*math::tanh(20.*(-0.5 + x)))/2.0 * math::sin(4.0 * constant::PI * x_ph[0]); + return ZERO + 0.01 * (ONE - math::tanh(20.*(-1.5 + x_ph[0]))*math::tanh(20.*(-0.5 + x_ph[0])))/2.0 * math::sin(4.0 * constant::PI * x_ph[0]); } Inline auto ex3(const coord_t& x_ph) const -> real_t { From 2a269fde2d70d3e2b05b7627b30eaa4484ac83f6 Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Thu, 27 Feb 2025 13:13:12 -0500 Subject: [PATCH 405/773] Ongoing. --- src/kernels/fields_bcs.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/kernels/fields_bcs.hpp b/src/kernels/fields_bcs.hpp index fe5ae4122..f201d7cc8 100644 --- a/src/kernels/fields_bcs.hpp +++ b/src/kernels/fields_bcs.hpp @@ -536,7 +536,7 @@ namespace kernel::bc { if constexpr (S == SimEngine::SRPIC) { // SRPIC if (tags & BC::E) { - Fld((N_GHOSTS-1)-i1, i2, em::ex1) = - Fld(N_GHOSTS+i1, i2, em::ex1); + Fld((N_GHOSTS-1)-i1, i2, em::ex1) = Fld(N_GHOSTS+i1, i2, em::ex1); Fld((N_GHOSTS-1)-i1, i2, em::ex2) = - Fld(N_GHOSTS+1+i1, i2, em::ex2); Fld((N_GHOSTS-1)-i1, i2, em::ex3) = - Fld(N_GHOSTS+1+i1, i2, em::ex3); } @@ -544,8 +544,8 @@ namespace kernel::bc { if (tags & BC::B) { Fld((N_GHOSTS-1)-i1, i2, em::bx1) = - Fld(N_GHOSTS+1+i1, i2, em::bx1); - Fld((N_GHOSTS-1)-i1, i2, em::bx2) = - Fld(N_GHOSTS+i1, i2, em::bx2); - Fld((N_GHOSTS-1)-i1, i2, em::bx3) = - Fld(N_GHOSTS+i1, i2, em::bx3); + Fld((N_GHOSTS-1)-i1, i2, em::bx2) = Fld(N_GHOSTS+i1, i2, em::bx2); + Fld((N_GHOSTS-1)-i1, i2, em::bx3) = Fld(N_GHOSTS+i1, i2, em::bx3); // Fld((N_GHOSTS-1)-i1, i2, em::bx1) = 1.0; // Fld((N_GHOSTS-1)-i1, i2, em::bx2) = 2.0; // Fld((N_GHOSTS-1)-i1, i2, em::bx3) = 3.0; From 49820ff2a0d67ea68b7b3cbee687e1531df96641 Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Thu, 27 Feb 2025 13:18:43 -0500 Subject: [PATCH 406/773] Ongoing. --- setups/srpic/shocktest/pgen.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setups/srpic/shocktest/pgen.hpp b/setups/srpic/shocktest/pgen.hpp index c43688d02..10d4c6b59 100644 --- a/setups/srpic/shocktest/pgen.hpp +++ b/setups/srpic/shocktest/pgen.hpp @@ -58,7 +58,7 @@ namespace user { Inline auto ex2(const coord_t& x_ph) const -> real_t { // return -Vx * Bmag * math::sin(Btheta) * math::cos(Bphi); - return ZERO + 0.01 * (ONE - math::tanh(20.*(-1.5 + x_ph[0]))*math::tanh(20.*(-0.5 + x_ph[0])))/2.0 * math::sin(4.0 * constant::PI * x_ph[0]); + return ZERO - 0.01 * (ONE - math::tanh(20.*(-1.5 + x_ph[0]))*math::tanh(20.*(-0.5 + x_ph[0])))/2.0 * math::sin(4.0 * constant::PI * x_ph[0]); } Inline auto ex3(const coord_t& x_ph) const -> real_t { From d2167da1bc2c1c0a88ba94f2dfb4b80ca363447f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20B=C3=B6ss?= Date: Thu, 27 Feb 2025 18:04:22 -0600 Subject: [PATCH 407/773] first attempt at single particle injection --- setups/srpic/shocktest/pgen.hpp | 164 ++++++++++++++++++++------------ src/kernels/fields_bcs.hpp | 27 +++--- 2 files changed, 116 insertions(+), 75 deletions(-) diff --git a/setups/srpic/shocktest/pgen.hpp b/setups/srpic/shocktest/pgen.hpp index 10d4c6b59..4d4b1cb37 100644 --- a/setups/srpic/shocktest/pgen.hpp +++ b/setups/srpic/shocktest/pgen.hpp @@ -111,72 +111,116 @@ namespace user { } } - - auto PerfectConductorFieldsConst(const bc_in&, const em& comp) const -> real_t{ - - // electric field components - if (comp == em::ex1) { - return ONE; - } else if (comp == em::ex2) { - return -ONE; - } else if (comp == em::ex3) { - return -ONE; } - // magentic field components - else if (comp == em::bx1) { - return -ONE; - } else if (comp == em::bx2) { - return ONE; - } else if (comp == em::bx3) { - return ONE;} - // should never be the case - else - { - return ZERO; - } - } - - // auto PerfectConductorCurrentsConst(const bc_in &, const cur &comp) const - // -> std::pair - // { - // // ToDo - // if (comp == cur::jx1) - // { - // return ZERO; - // } - // else if (comp == cur::jx2) - // { - // return ZERO; - // } - // else if (comp == cur::jx3) - // { - // return ZERO; - // } - // else - // { - // return ZERO; - // } - // } auto MatchFields(real_t time) const -> InitFields { return init_flds; } - inline void InitPrtls(Domain& local_domain) { - const auto energy_dist = arch::Maxwellian(local_domain.mesh.metric, - local_domain.random_pool, - temperature, - -drift_ux, - in::x1); - - const auto injector = arch::UniformInjector( - energy_dist, - { 1, 2 }); - // arch::InjectUniform>( - // params, - // local_domain, - // injector, - // 1.0); + inline void InitPrtls(Domain& domain) { + + auto& species_e = domain.species[0]; + auto& species_p = domain.species[1]; + auto metric = domain.mesh.metric; + auto m = domain.mesh.metric; + + array_t elec_ind("elec_ind"); + array_t pos_ind("pos_ind"); + + auto offset_e = species_e.npart(); + auto offset_p = species_p.npart(); + + auto ux1_e = species_e.ux1; + auto ux2_e = species_e.ux2; + auto ux3_e = species_e.ux3; + auto i1_e = species_e.i1; + auto i2_e = species_e.i2; + auto dx1_e = species_e.dx1; + auto dx2_e = species_e.dx2; + auto phi_e = species_e.phi; + auto weight_e = species_e.weight; + auto tag_e = species_e.tag; + + auto ux1_p = species_p.ux1; + auto ux2_p = species_p.ux2; + auto ux3_p = species_p.ux3; + auto i1_p = species_p.i1; + auto i2_p = species_p.i2; + auto dx1_p = species_p.dx1; + auto dx2_p = species_p.dx2; + auto phi_p = species_p.phi; + auto weight_p = species_p.weight; + auto tag_p = species_p.tag; + + int nseed = 1; + auto dseed = HALF * constant::PI / static_cast(nseed); + + Kokkos::parallel_for("init_particles", nseed, KOKKOS_LAMBDA(const int& s) { + + // ToDo: fix this + auto i1_ = ONE; + auto i2_ = ONE; + auto dx1_ = ONE - HALF; + auto dx2_ = ONE - HALF; + + + auto elec_p = Kokkos::atomic_fetch_add(&elec_ind(), 1); + auto pos_p = Kokkos::atomic_fetch_add(&pos_ind(), 1); + + i1_e(elec_p + offset_e) = i1_; + dx1_e(elec_p + offset_e) = dx1_; + i2_e(elec_p + offset_e) = i2_; + dx2_e(elec_p + offset_e) = dx2_; + phi_e(elec_p + offset_e) = ZERO; + ux1_e(elec_p + offset_e) = -drift_ux; + ux2_e(elec_p + offset_e) = -drift_ux; + ux3_e(elec_p + offset_e) = ZERO; + weight_e(elec_p + offset_e) = ONE; + tag_e(elec_p + offset_e) = ParticleTag::alive; + + i1_p(pos_p + offset_p) = i1_; + dx1_p(pos_p + offset_p) = dx1_; + i2_p(pos_p + offset_p) = i2_; + dx2_p(pos_p + offset_p) = dx2_; + phi_p(pos_p + offset_p) = ZERO; + ux1_p(pos_p + offset_p) = -drift_ux; + ux2_p(pos_p + offset_p) = drift_ux; + ux3_p(pos_p + offset_p) = ZERO; + weight_p(pos_p + offset_p) = ONE; + tag_p(pos_p + offset_p) = ParticleTag::alive; + + + }); + + + auto elec_ind_h = Kokkos::create_mirror(elec_ind); + Kokkos::deep_copy(elec_ind_h, elec_ind); + species_e.set_npart(offset_e + elec_ind_h()); + + auto pos_ind_h = Kokkos::create_mirror(pos_ind); + Kokkos::deep_copy(pos_ind_h, pos_ind); + species_p.set_npart(offset_p + pos_ind_h()); + + } + + + // inline void InitPrtls(Domain& local_domain) { + // const auto energy_dist = arch::Maxwellian(local_domain.mesh.metric, + // local_domain.random_pool, + // temperature, + // -drift_ux, + // in::x1); + + // const auto injector = arch::UniformInjector( + // energy_dist, + // { 1, 2 }); + // arch::InjectUniform>( + // params, + // local_domain, + // injector, + // 1.0); + // } + }; } // namespace user diff --git a/src/kernels/fields_bcs.hpp b/src/kernels/fields_bcs.hpp index f201d7cc8..39dfaf5dc 100644 --- a/src/kernels/fields_bcs.hpp +++ b/src/kernels/fields_bcs.hpp @@ -506,19 +506,19 @@ namespace kernel::bc { if constexpr (S == SimEngine::SRPIC) { - if (tags & BC::E) { - Fld((N_GHOSTS-1)-i1, em::ex1) = Fld(N_GHOSTS+i1, em::ex1); - Fld((N_GHOSTS-1)-i1, em::ex2) = -Fld(N_GHOSTS+i1, em::ex2); - Fld((N_GHOSTS-1)-i1, em::ex3) = -Fld(N_GHOSTS+i1, em::ex3); - } - - if (tags & BC::B) - { - Fld((N_GHOSTS-1)-i1, em::bx1) = -Fld(N_GHOSTS+i1, em::bx1); - Fld((N_GHOSTS-1)-i1, em::bx1) = Fld(N_GHOSTS+i1, em::bx1); - Fld((N_GHOSTS-1)-i1, em::bx1) = Fld(N_GHOSTS+i1, em::bx1); - } + if (tags & BC::E) + { + Fld((N_GHOSTS - 1) - i1, em::ex1) = Fld(N_GHOSTS + i1, em::ex1); + Fld((N_GHOSTS - 1) - i1, em::ex2) = -Fld(N_GHOSTS + 1 + i1, em::ex2); + Fld((N_GHOSTS - 1) - i1, em::ex3) = -Fld(N_GHOSTS + 1 + i1, em::ex3); + } + if (tags & BC::B) + { + Fld((N_GHOSTS - 1) - i1, em::bx1) = -Fld(N_GHOSTS + 1 + i1, em::bx1); + Fld((N_GHOSTS - 1) - i1, em::bx2) = Fld(N_GHOSTS + i1, em::bx2); + Fld((N_GHOSTS - 1) - i1, em::bx3) = Fld(N_GHOSTS + i1, em::bx3); + } } else { // GRPIC raise::KernelError(HERE, "1D GRPIC not implemented"); @@ -546,9 +546,6 @@ namespace kernel::bc { Fld((N_GHOSTS-1)-i1, i2, em::bx1) = - Fld(N_GHOSTS+1+i1, i2, em::bx1); Fld((N_GHOSTS-1)-i1, i2, em::bx2) = Fld(N_GHOSTS+i1, i2, em::bx2); Fld((N_GHOSTS-1)-i1, i2, em::bx3) = Fld(N_GHOSTS+i1, i2, em::bx3); - // Fld((N_GHOSTS-1)-i1, i2, em::bx1) = 1.0; - // Fld((N_GHOSTS-1)-i1, i2, em::bx2) = 2.0; - // Fld((N_GHOSTS-1)-i1, i2, em::bx3) = 3.0; } } else { // GRPIC From fc3e647f62b596501107776847a9f6a9019bfb65 Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Fri, 28 Feb 2025 07:44:22 -0500 Subject: [PATCH 408/773] Ongoing. --- setups/srpic/shocktest/pgen.hpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/setups/srpic/shocktest/pgen.hpp b/setups/srpic/shocktest/pgen.hpp index 4d4b1cb37..14c2006e9 100644 --- a/setups/srpic/shocktest/pgen.hpp +++ b/setups/srpic/shocktest/pgen.hpp @@ -48,7 +48,8 @@ namespace user { Inline auto bx3(const coord_t& x_ph) const -> real_t { // return Bmag * math::sin(Btheta) * math::cos(Bphi); - return ONE + 0.01 * (ONE - math::tanh(20.*(-1.5 + x_ph[0]))*math::tanh(20.*(-0.5 + x_ph[0])))/2.0 * math::sin(4.0 * constant::PI * x_ph[0]); + // return ONE + 0.01 * (ONE - math::tanh(20.*(-1.5 + x_ph[0]))*math::tanh(20.*(-0.5 + x_ph[0])))/2.0 * math::sin(4.0 * constant::PI * x_ph[0]); + return ZERO; } // electric field components @@ -58,7 +59,8 @@ namespace user { Inline auto ex2(const coord_t& x_ph) const -> real_t { // return -Vx * Bmag * math::sin(Btheta) * math::cos(Bphi); - return ZERO - 0.01 * (ONE - math::tanh(20.*(-1.5 + x_ph[0]))*math::tanh(20.*(-0.5 + x_ph[0])))/2.0 * math::sin(4.0 * constant::PI * x_ph[0]); + // return ZERO - 0.01 * (ONE - math::tanh(20.*(-1.5 + x_ph[0]))*math::tanh(20.*(-0.5 + x_ph[0])))/2.0 * math::sin(4.0 * constant::PI * x_ph[0]); + return ZERO; } Inline auto ex3(const coord_t& x_ph) const -> real_t { @@ -120,8 +122,6 @@ namespace user { auto& species_e = domain.species[0]; auto& species_p = domain.species[1]; - auto metric = domain.mesh.metric; - auto m = domain.mesh.metric; array_t elec_ind("elec_ind"); array_t pos_ind("pos_ind"); @@ -152,15 +152,14 @@ namespace user { auto tag_p = species_p.tag; int nseed = 1; - auto dseed = HALF * constant::PI / static_cast(nseed); Kokkos::parallel_for("init_particles", nseed, KOKKOS_LAMBDA(const int& s) { // ToDo: fix this auto i1_ = ONE; auto i2_ = ONE; - auto dx1_ = ONE - HALF; - auto dx2_ = ONE - HALF; + auto dx1_ = HALF; + auto dx2_ = HALF; auto elec_p = Kokkos::atomic_fetch_add(&elec_ind(), 1); From 83c144f4f99960c3c381e2945d1b319ecf15ef04 Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Fri, 28 Feb 2025 07:47:32 -0500 Subject: [PATCH 409/773] Ongoing. --- setups/srpic/shocktest/pgen.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setups/srpic/shocktest/pgen.hpp b/setups/srpic/shocktest/pgen.hpp index 14c2006e9..85d08214a 100644 --- a/setups/srpic/shocktest/pgen.hpp +++ b/setups/srpic/shocktest/pgen.hpp @@ -156,8 +156,8 @@ namespace user { Kokkos::parallel_for("init_particles", nseed, KOKKOS_LAMBDA(const int& s) { // ToDo: fix this - auto i1_ = ONE; - auto i2_ = ONE; + auto i1_ = 100; + auto i2_ = 100; auto dx1_ = HALF; auto dx2_ = HALF; From 7c7c3f9cecd887948c9b42e73f01cfb83da17056 Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Fri, 28 Feb 2025 09:42:48 -0500 Subject: [PATCH 410/773] Ongoing. --- setups/srpic/shocktest/pgen.hpp | 90 ++++++++++++++++----------------- 1 file changed, 45 insertions(+), 45 deletions(-) diff --git a/setups/srpic/shocktest/pgen.hpp b/setups/srpic/shocktest/pgen.hpp index 85d08214a..b682cd621 100644 --- a/setups/srpic/shocktest/pgen.hpp +++ b/setups/srpic/shocktest/pgen.hpp @@ -153,51 +153,51 @@ namespace user { int nseed = 1; - Kokkos::parallel_for("init_particles", nseed, KOKKOS_LAMBDA(const int& s) { - - // ToDo: fix this - auto i1_ = 100; - auto i2_ = 100; - auto dx1_ = HALF; - auto dx2_ = HALF; - - - auto elec_p = Kokkos::atomic_fetch_add(&elec_ind(), 1); - auto pos_p = Kokkos::atomic_fetch_add(&pos_ind(), 1); - - i1_e(elec_p + offset_e) = i1_; - dx1_e(elec_p + offset_e) = dx1_; - i2_e(elec_p + offset_e) = i2_; - dx2_e(elec_p + offset_e) = dx2_; - phi_e(elec_p + offset_e) = ZERO; - ux1_e(elec_p + offset_e) = -drift_ux; - ux2_e(elec_p + offset_e) = -drift_ux; - ux3_e(elec_p + offset_e) = ZERO; - weight_e(elec_p + offset_e) = ONE; - tag_e(elec_p + offset_e) = ParticleTag::alive; - - i1_p(pos_p + offset_p) = i1_; - dx1_p(pos_p + offset_p) = dx1_; - i2_p(pos_p + offset_p) = i2_; - dx2_p(pos_p + offset_p) = dx2_; - phi_p(pos_p + offset_p) = ZERO; - ux1_p(pos_p + offset_p) = -drift_ux; - ux2_p(pos_p + offset_p) = drift_ux; - ux3_p(pos_p + offset_p) = ZERO; - weight_p(pos_p + offset_p) = ONE; - tag_p(pos_p + offset_p) = ParticleTag::alive; - - - }); - - - auto elec_ind_h = Kokkos::create_mirror(elec_ind); - Kokkos::deep_copy(elec_ind_h, elec_ind); - species_e.set_npart(offset_e + elec_ind_h()); - - auto pos_ind_h = Kokkos::create_mirror(pos_ind); - Kokkos::deep_copy(pos_ind_h, pos_ind); - species_p.set_npart(offset_p + pos_ind_h()); + // Kokkos::parallel_for("init_particles", nseed, KOKKOS_LAMBDA(const int& s) { + + // // ToDo: fix this + // auto i1_ = 100; + // auto i2_ = 100; + // auto dx1_ = HALF; + // auto dx2_ = HALF; + + + // auto elec_p = Kokkos::atomic_fetch_add(&elec_ind(), 1); + // auto pos_p = Kokkos::atomic_fetch_add(&pos_ind(), 1); + + // i1_e(elec_p + offset_e) = i1_; + // dx1_e(elec_p + offset_e) = dx1_; + // i2_e(elec_p + offset_e) = i2_; + // dx2_e(elec_p + offset_e) = dx2_; + // phi_e(elec_p + offset_e) = ZERO; + // ux1_e(elec_p + offset_e) = -drift_ux; + // ux2_e(elec_p + offset_e) = -drift_ux; + // ux3_e(elec_p + offset_e) = ZERO; + // weight_e(elec_p + offset_e) = ONE; + // tag_e(elec_p + offset_e) = ParticleTag::alive; + + // i1_p(pos_p + offset_p) = i1_; + // dx1_p(pos_p + offset_p) = dx1_; + // i2_p(pos_p + offset_p) = i2_; + // dx2_p(pos_p + offset_p) = dx2_; + // phi_p(pos_p + offset_p) = ZERO; + // ux1_p(pos_p + offset_p) = -drift_ux; + // ux2_p(pos_p + offset_p) = drift_ux; + // ux3_p(pos_p + offset_p) = ZERO; + // weight_p(pos_p + offset_p) = ONE; + // tag_p(pos_p + offset_p) = ParticleTag::alive; + + + // }); + + + // auto elec_ind_h = Kokkos::create_mirror(elec_ind); + // Kokkos::deep_copy(elec_ind_h, elec_ind); + // species_e.set_npart(offset_e + elec_ind_h()); + + // auto pos_ind_h = Kokkos::create_mirror(pos_ind); + // Kokkos::deep_copy(pos_ind_h, pos_ind); + // species_p.set_npart(offset_p + pos_ind_h()); } From 939369eb65a4aa66e6335054451d816a09ac63f6 Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Fri, 28 Feb 2025 09:51:22 -0500 Subject: [PATCH 411/773] Ongoing. --- setups/srpic/shocktest/pgen.hpp | 70 ++++++++++++++++----------------- 1 file changed, 34 insertions(+), 36 deletions(-) diff --git a/setups/srpic/shocktest/pgen.hpp b/setups/srpic/shocktest/pgen.hpp index b682cd621..f74e45080 100644 --- a/setups/srpic/shocktest/pgen.hpp +++ b/setups/srpic/shocktest/pgen.hpp @@ -151,53 +151,51 @@ namespace user { auto weight_p = species_p.weight; auto tag_p = species_p.tag; - int nseed = 1; + int nseed = 10; - // Kokkos::parallel_for("init_particles", nseed, KOKKOS_LAMBDA(const int& s) { + Kokkos::parallel_for("init_particles", nseed, KOKKOS_LAMBDA(const int& s) { - // // ToDo: fix this - // auto i1_ = 100; - // auto i2_ = 100; - // auto dx1_ = HALF; - // auto dx2_ = HALF; + // ToDo: fix this + auto i1_ = math::floor(100); + auto i2_ = math::floor(64); + auto dx1_ = HALF; + auto dx2_ = HALF; - // auto elec_p = Kokkos::atomic_fetch_add(&elec_ind(), 1); - // auto pos_p = Kokkos::atomic_fetch_add(&pos_ind(), 1); + auto elec_p = Kokkos::atomic_fetch_add(&elec_ind(), 1); + auto pos_p = Kokkos::atomic_fetch_add(&pos_ind(), 1); - // i1_e(elec_p + offset_e) = i1_; - // dx1_e(elec_p + offset_e) = dx1_; - // i2_e(elec_p + offset_e) = i2_; - // dx2_e(elec_p + offset_e) = dx2_; - // phi_e(elec_p + offset_e) = ZERO; - // ux1_e(elec_p + offset_e) = -drift_ux; - // ux2_e(elec_p + offset_e) = -drift_ux; - // ux3_e(elec_p + offset_e) = ZERO; - // weight_e(elec_p + offset_e) = ONE; - // tag_e(elec_p + offset_e) = ParticleTag::alive; + i1_e(elec_p + offset_e) = i1_; + dx1_e(elec_p + offset_e) = dx1_; + i2_e(elec_p + offset_e) = i2_; + dx2_e(elec_p + offset_e) = dx2_; + ux1_e(elec_p + offset_e) = ZERO; + ux2_e(elec_p + offset_e) = ZERO; + ux3_e(elec_p + offset_e) = ZERO; + weight_e(elec_p + offset_e) = ONE; + tag_e(elec_p + offset_e) = ParticleTag::alive; - // i1_p(pos_p + offset_p) = i1_; - // dx1_p(pos_p + offset_p) = dx1_; - // i2_p(pos_p + offset_p) = i2_; - // dx2_p(pos_p + offset_p) = dx2_; - // phi_p(pos_p + offset_p) = ZERO; - // ux1_p(pos_p + offset_p) = -drift_ux; - // ux2_p(pos_p + offset_p) = drift_ux; - // ux3_p(pos_p + offset_p) = ZERO; - // weight_p(pos_p + offset_p) = ONE; - // tag_p(pos_p + offset_p) = ParticleTag::alive; + i1_p(pos_p + offset_p) = i1_; + dx1_p(pos_p + offset_p) = dx1_; + i2_p(pos_p + offset_p) = i2_; + dx2_p(pos_p + offset_p) = dx2_; + ux1_p(pos_p + offset_p) = ZERO; + ux2_p(pos_p + offset_p) = ZERO; + ux3_p(pos_p + offset_p) = ZERO; + weight_p(pos_p + offset_p) = ONE; + tag_p(pos_p + offset_p) = ParticleTag::alive; - // }); + }); - // auto elec_ind_h = Kokkos::create_mirror(elec_ind); - // Kokkos::deep_copy(elec_ind_h, elec_ind); - // species_e.set_npart(offset_e + elec_ind_h()); + auto elec_ind_h = Kokkos::create_mirror(elec_ind); + Kokkos::deep_copy(elec_ind_h, elec_ind); + species_e.set_npart(offset_e + elec_ind_h()); - // auto pos_ind_h = Kokkos::create_mirror(pos_ind); - // Kokkos::deep_copy(pos_ind_h, pos_ind); - // species_p.set_npart(offset_p + pos_ind_h()); + auto pos_ind_h = Kokkos::create_mirror(pos_ind); + Kokkos::deep_copy(pos_ind_h, pos_ind); + species_p.set_npart(offset_p + pos_ind_h()); } From fa5a38fe127df07335793ea0433e9e4e95d9ae76 Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Fri, 28 Feb 2025 09:56:29 -0500 Subject: [PATCH 412/773] Ongoing. --- setups/srpic/shocktest/pgen.hpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/setups/srpic/shocktest/pgen.hpp b/setups/srpic/shocktest/pgen.hpp index f74e45080..a835b7990 100644 --- a/setups/srpic/shocktest/pgen.hpp +++ b/setups/srpic/shocktest/pgen.hpp @@ -151,7 +151,7 @@ namespace user { auto weight_p = species_p.weight; auto tag_p = species_p.tag; - int nseed = 10; + int nseed = 1; Kokkos::parallel_for("init_particles", nseed, KOKKOS_LAMBDA(const int& s) { @@ -169,8 +169,8 @@ namespace user { dx1_e(elec_p + offset_e) = dx1_; i2_e(elec_p + offset_e) = i2_; dx2_e(elec_p + offset_e) = dx2_; - ux1_e(elec_p + offset_e) = ZERO; - ux2_e(elec_p + offset_e) = ZERO; + ux1_e(elec_p + offset_e) = -drift_ux; + ux2_e(elec_p + offset_e) = drift_ux; ux3_e(elec_p + offset_e) = ZERO; weight_e(elec_p + offset_e) = ONE; tag_e(elec_p + offset_e) = ParticleTag::alive; @@ -179,8 +179,8 @@ namespace user { dx1_p(pos_p + offset_p) = dx1_; i2_p(pos_p + offset_p) = i2_; dx2_p(pos_p + offset_p) = dx2_; - ux1_p(pos_p + offset_p) = ZERO; - ux2_p(pos_p + offset_p) = ZERO; + ux1_p(pos_p + offset_p) = -drift_ux; + ux2_p(pos_p + offset_p) = drift_ux; ux3_p(pos_p + offset_p) = ZERO; weight_p(pos_p + offset_p) = ONE; tag_p(pos_p + offset_p) = ParticleTag::alive; From eeca02d46f7d63575fa923b23b16a003d2fac936 Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Fri, 28 Feb 2025 09:58:00 -0500 Subject: [PATCH 413/773] Ongoing. --- setups/srpic/shocktest/pgen.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/setups/srpic/shocktest/pgen.hpp b/setups/srpic/shocktest/pgen.hpp index a835b7990..9711646e3 100644 --- a/setups/srpic/shocktest/pgen.hpp +++ b/setups/srpic/shocktest/pgen.hpp @@ -169,8 +169,8 @@ namespace user { dx1_e(elec_p + offset_e) = dx1_; i2_e(elec_p + offset_e) = i2_; dx2_e(elec_p + offset_e) = dx2_; - ux1_e(elec_p + offset_e) = -drift_ux; - ux2_e(elec_p + offset_e) = drift_ux; + ux1_e(elec_p + offset_e) = -0.5; + ux2_e(elec_p + offset_e) = 0.5; ux3_e(elec_p + offset_e) = ZERO; weight_e(elec_p + offset_e) = ONE; tag_e(elec_p + offset_e) = ParticleTag::alive; @@ -179,8 +179,8 @@ namespace user { dx1_p(pos_p + offset_p) = dx1_; i2_p(pos_p + offset_p) = i2_; dx2_p(pos_p + offset_p) = dx2_; - ux1_p(pos_p + offset_p) = -drift_ux; - ux2_p(pos_p + offset_p) = drift_ux; + ux1_p(pos_p + offset_p) = -0.5; + ux2_p(pos_p + offset_p) = 0.5; ux3_p(pos_p + offset_p) = ZERO; weight_p(pos_p + offset_p) = ONE; tag_p(pos_p + offset_p) = ParticleTag::alive; From c18840ca3a1f4ccab2992c320ff1f2a0d61fce03 Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Fri, 28 Feb 2025 11:05:00 -0500 Subject: [PATCH 414/773] Ongoing. --- setups/srpic/shocktest/pgen.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setups/srpic/shocktest/pgen.hpp b/setups/srpic/shocktest/pgen.hpp index 9711646e3..4cf89ac69 100644 --- a/setups/srpic/shocktest/pgen.hpp +++ b/setups/srpic/shocktest/pgen.hpp @@ -156,7 +156,7 @@ namespace user { Kokkos::parallel_for("init_particles", nseed, KOKKOS_LAMBDA(const int& s) { // ToDo: fix this - auto i1_ = math::floor(100); + auto i1_ = math::floor(10); auto i2_ = math::floor(64); auto dx1_ = HALF; auto dx2_ = HALF; From 9085afd497f0535126f75ecf353d289c6a248682 Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Fri, 28 Feb 2025 11:18:31 -0500 Subject: [PATCH 415/773] Ongoing. --- setups/srpic/shocktest/pgen.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setups/srpic/shocktest/pgen.hpp b/setups/srpic/shocktest/pgen.hpp index 4cf89ac69..a1ce9a1a9 100644 --- a/setups/srpic/shocktest/pgen.hpp +++ b/setups/srpic/shocktest/pgen.hpp @@ -179,8 +179,8 @@ namespace user { dx1_p(pos_p + offset_p) = dx1_; i2_p(pos_p + offset_p) = i2_; dx2_p(pos_p + offset_p) = dx2_; - ux1_p(pos_p + offset_p) = -0.5; - ux2_p(pos_p + offset_p) = 0.5; + ux1_p(pos_p + offset_p) = 0.5; + ux2_p(pos_p + offset_p) = -0.5; ux3_p(pos_p + offset_p) = ZERO; weight_p(pos_p + offset_p) = ONE; tag_p(pos_p + offset_p) = ParticleTag::alive; From 87b37beb08e476081bcc4e601f16d2281549d62c Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Fri, 28 Feb 2025 13:20:21 -0500 Subject: [PATCH 416/773] Ongoing. --- src/kernels/fields_bcs.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/kernels/fields_bcs.hpp b/src/kernels/fields_bcs.hpp index 39dfaf5dc..e477c4eb1 100644 --- a/src/kernels/fields_bcs.hpp +++ b/src/kernels/fields_bcs.hpp @@ -537,13 +537,13 @@ namespace kernel::bc { // SRPIC if (tags & BC::E) { Fld((N_GHOSTS-1)-i1, i2, em::ex1) = Fld(N_GHOSTS+i1, i2, em::ex1); - Fld((N_GHOSTS-1)-i1, i2, em::ex2) = - Fld(N_GHOSTS+1+i1, i2, em::ex2); - Fld((N_GHOSTS-1)-i1, i2, em::ex3) = - Fld(N_GHOSTS+1+i1, i2, em::ex3); + Fld((N_GHOSTS-1)-i1, i2, em::ex2) = - Fld(N_GHOSTS+i1, i2, em::ex2); + Fld((N_GHOSTS-1)-i1, i2, em::ex3) = - Fld(N_GHOSTS+i1, i2, em::ex3); } if (tags & BC::B) { - Fld((N_GHOSTS-1)-i1, i2, em::bx1) = - Fld(N_GHOSTS+1+i1, i2, em::bx1); + Fld((N_GHOSTS-1)-i1, i2, em::bx1) = - Fld(N_GHOSTS+i1, i2, em::bx1); Fld((N_GHOSTS-1)-i1, i2, em::bx2) = Fld(N_GHOSTS+i1, i2, em::bx2); Fld((N_GHOSTS-1)-i1, i2, em::bx3) = Fld(N_GHOSTS+i1, i2, em::bx3); } From 5712e3bd4bb628fa9df2480e2e31e9a0f885995c Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Fri, 28 Feb 2025 13:34:59 -0500 Subject: [PATCH 417/773] Ongoing. --- src/kernels/fields_bcs.hpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/kernels/fields_bcs.hpp b/src/kernels/fields_bcs.hpp index e477c4eb1..115aa3415 100644 --- a/src/kernels/fields_bcs.hpp +++ b/src/kernels/fields_bcs.hpp @@ -536,16 +536,19 @@ namespace kernel::bc { if constexpr (S == SimEngine::SRPIC) { // SRPIC if (tags & BC::E) { - Fld((N_GHOSTS-1)-i1, i2, em::ex1) = Fld(N_GHOSTS+i1, i2, em::ex1); - Fld((N_GHOSTS-1)-i1, i2, em::ex2) = - Fld(N_GHOSTS+i1, i2, em::ex2); - Fld((N_GHOSTS-1)-i1, i2, em::ex3) = - Fld(N_GHOSTS+i1, i2, em::ex3); + // Fld((N_GHOSTS-1)-i1, i2, em::ex1) = Fld(N_GHOSTS+i1, i2, em::ex1); + // Fld((N_GHOSTS-1)-i1, i2, em::ex2) = - Fld(N_GHOSTS+1+i1, i2, em::ex2); + // Fld((N_GHOSTS-1)-i1, i2, em::ex3) = - Fld(N_GHOSTS+1+i1, i2, em::ex3); + Fld((N_GHOSTS-1)-i1, i2, em::ex1) = ZERO; + Fld((N_GHOSTS-1)-i1, i2, em::ex2) = ZERO; + Fld((N_GHOSTS-1)-i1, i2, em::ex3) = ZERO; } if (tags & BC::B) { - Fld((N_GHOSTS-1)-i1, i2, em::bx1) = - Fld(N_GHOSTS+i1, i2, em::bx1); - Fld((N_GHOSTS-1)-i1, i2, em::bx2) = Fld(N_GHOSTS+i1, i2, em::bx2); - Fld((N_GHOSTS-1)-i1, i2, em::bx3) = Fld(N_GHOSTS+i1, i2, em::bx3); + Fld((N_GHOSTS-1)-i1, i2, em::bx1) = ZERO; + Fld((N_GHOSTS-1)-i1, i2, em::bx2) = ZERO; + Fld((N_GHOSTS-1)-i1, i2, em::bx3) = ZERO; } } else { // GRPIC From af258c6c91d800977523f6d26ad25c423be84b5b Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Fri, 28 Feb 2025 13:36:55 -0500 Subject: [PATCH 418/773] Ongoing. --- src/kernels/fields_bcs.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/kernels/fields_bcs.hpp b/src/kernels/fields_bcs.hpp index 115aa3415..b15a16546 100644 --- a/src/kernels/fields_bcs.hpp +++ b/src/kernels/fields_bcs.hpp @@ -542,6 +542,8 @@ namespace kernel::bc { Fld((N_GHOSTS-1)-i1, i2, em::ex1) = ZERO; Fld((N_GHOSTS-1)-i1, i2, em::ex2) = ZERO; Fld((N_GHOSTS-1)-i1, i2, em::ex3) = ZERO; + Fld((N_GHOSTS), i2, em::ex2) = ZERO; + Fld((N_GHOSTS), i2, em::ex3) = ZERO; } if (tags & BC::B) From 86f05972d2623612b13e9d51b814b0b715e5f566 Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Fri, 28 Feb 2025 14:53:48 -0500 Subject: [PATCH 419/773] Ongoing. --- setups/srpic/shocktest/pgen.hpp | 156 ++++++++++++++++---------------- 1 file changed, 78 insertions(+), 78 deletions(-) diff --git a/setups/srpic/shocktest/pgen.hpp b/setups/srpic/shocktest/pgen.hpp index a1ce9a1a9..1b8926c67 100644 --- a/setups/srpic/shocktest/pgen.hpp +++ b/setups/srpic/shocktest/pgen.hpp @@ -48,8 +48,8 @@ namespace user { Inline auto bx3(const coord_t& x_ph) const -> real_t { // return Bmag * math::sin(Btheta) * math::cos(Bphi); - // return ONE + 0.01 * (ONE - math::tanh(20.*(-1.5 + x_ph[0]))*math::tanh(20.*(-0.5 + x_ph[0])))/2.0 * math::sin(4.0 * constant::PI * x_ph[0]); - return ZERO; + return ONE + 0.01 * (ONE - math::tanh(20.*(-1.5 + x_ph[0]))*math::tanh(20.*(-0.5 + x_ph[0])))/2.0 * math::sin(4.0 * constant::PI * x_ph[0]); + // return ZERO; } // electric field components @@ -59,8 +59,8 @@ namespace user { Inline auto ex2(const coord_t& x_ph) const -> real_t { // return -Vx * Bmag * math::sin(Btheta) * math::cos(Bphi); - // return ZERO - 0.01 * (ONE - math::tanh(20.*(-1.5 + x_ph[0]))*math::tanh(20.*(-0.5 + x_ph[0])))/2.0 * math::sin(4.0 * constant::PI * x_ph[0]); - return ZERO; + return ZERO - 0.01 * (ONE - math::tanh(20.*(-1.5 + x_ph[0]))*math::tanh(20.*(-0.5 + x_ph[0])))/2.0 * math::sin(4.0 * constant::PI * x_ph[0]); + // return ZERO; } Inline auto ex3(const coord_t& x_ph) const -> real_t { @@ -120,82 +120,82 @@ namespace user { inline void InitPrtls(Domain& domain) { - auto& species_e = domain.species[0]; - auto& species_p = domain.species[1]; + // auto& species_e = domain.species[0]; + // auto& species_p = domain.species[1]; - array_t elec_ind("elec_ind"); - array_t pos_ind("pos_ind"); + // array_t elec_ind("elec_ind"); + // array_t pos_ind("pos_ind"); - auto offset_e = species_e.npart(); - auto offset_p = species_p.npart(); - - auto ux1_e = species_e.ux1; - auto ux2_e = species_e.ux2; - auto ux3_e = species_e.ux3; - auto i1_e = species_e.i1; - auto i2_e = species_e.i2; - auto dx1_e = species_e.dx1; - auto dx2_e = species_e.dx2; - auto phi_e = species_e.phi; - auto weight_e = species_e.weight; - auto tag_e = species_e.tag; - - auto ux1_p = species_p.ux1; - auto ux2_p = species_p.ux2; - auto ux3_p = species_p.ux3; - auto i1_p = species_p.i1; - auto i2_p = species_p.i2; - auto dx1_p = species_p.dx1; - auto dx2_p = species_p.dx2; - auto phi_p = species_p.phi; - auto weight_p = species_p.weight; - auto tag_p = species_p.tag; - - int nseed = 1; - - Kokkos::parallel_for("init_particles", nseed, KOKKOS_LAMBDA(const int& s) { - - // ToDo: fix this - auto i1_ = math::floor(10); - auto i2_ = math::floor(64); - auto dx1_ = HALF; - auto dx2_ = HALF; - - - auto elec_p = Kokkos::atomic_fetch_add(&elec_ind(), 1); - auto pos_p = Kokkos::atomic_fetch_add(&pos_ind(), 1); - - i1_e(elec_p + offset_e) = i1_; - dx1_e(elec_p + offset_e) = dx1_; - i2_e(elec_p + offset_e) = i2_; - dx2_e(elec_p + offset_e) = dx2_; - ux1_e(elec_p + offset_e) = -0.5; - ux2_e(elec_p + offset_e) = 0.5; - ux3_e(elec_p + offset_e) = ZERO; - weight_e(elec_p + offset_e) = ONE; - tag_e(elec_p + offset_e) = ParticleTag::alive; - - i1_p(pos_p + offset_p) = i1_; - dx1_p(pos_p + offset_p) = dx1_; - i2_p(pos_p + offset_p) = i2_; - dx2_p(pos_p + offset_p) = dx2_; - ux1_p(pos_p + offset_p) = 0.5; - ux2_p(pos_p + offset_p) = -0.5; - ux3_p(pos_p + offset_p) = ZERO; - weight_p(pos_p + offset_p) = ONE; - tag_p(pos_p + offset_p) = ParticleTag::alive; - - - }); - - - auto elec_ind_h = Kokkos::create_mirror(elec_ind); - Kokkos::deep_copy(elec_ind_h, elec_ind); - species_e.set_npart(offset_e + elec_ind_h()); - - auto pos_ind_h = Kokkos::create_mirror(pos_ind); - Kokkos::deep_copy(pos_ind_h, pos_ind); - species_p.set_npart(offset_p + pos_ind_h()); + // auto offset_e = species_e.npart(); + // auto offset_p = species_p.npart(); + + // auto ux1_e = species_e.ux1; + // auto ux2_e = species_e.ux2; + // auto ux3_e = species_e.ux3; + // auto i1_e = species_e.i1; + // auto i2_e = species_e.i2; + // auto dx1_e = species_e.dx1; + // auto dx2_e = species_e.dx2; + // auto phi_e = species_e.phi; + // auto weight_e = species_e.weight; + // auto tag_e = species_e.tag; + + // auto ux1_p = species_p.ux1; + // auto ux2_p = species_p.ux2; + // auto ux3_p = species_p.ux3; + // auto i1_p = species_p.i1; + // auto i2_p = species_p.i2; + // auto dx1_p = species_p.dx1; + // auto dx2_p = species_p.dx2; + // auto phi_p = species_p.phi; + // auto weight_p = species_p.weight; + // auto tag_p = species_p.tag; + + // int nseed = 1; + + // Kokkos::parallel_for("init_particles", nseed, KOKKOS_LAMBDA(const int& s) { + + // // ToDo: fix this + // auto i1_ = math::floor(10); + // auto i2_ = math::floor(64); + // auto dx1_ = HALF; + // auto dx2_ = HALF; + + + // auto elec_p = Kokkos::atomic_fetch_add(&elec_ind(), 1); + // auto pos_p = Kokkos::atomic_fetch_add(&pos_ind(), 1); + + // i1_e(elec_p + offset_e) = i1_; + // dx1_e(elec_p + offset_e) = dx1_; + // i2_e(elec_p + offset_e) = i2_; + // dx2_e(elec_p + offset_e) = dx2_; + // ux1_e(elec_p + offset_e) = -0.5; + // ux2_e(elec_p + offset_e) = 0.5; + // ux3_e(elec_p + offset_e) = ZERO; + // weight_e(elec_p + offset_e) = ONE; + // tag_e(elec_p + offset_e) = ParticleTag::alive; + + // i1_p(pos_p + offset_p) = i1_; + // dx1_p(pos_p + offset_p) = dx1_; + // i2_p(pos_p + offset_p) = i2_; + // dx2_p(pos_p + offset_p) = dx2_; + // ux1_p(pos_p + offset_p) = 0.5; + // ux2_p(pos_p + offset_p) = -0.5; + // ux3_p(pos_p + offset_p) = ZERO; + // weight_p(pos_p + offset_p) = ONE; + // tag_p(pos_p + offset_p) = ParticleTag::alive; + + + // }); + + + // auto elec_ind_h = Kokkos::create_mirror(elec_ind); + // Kokkos::deep_copy(elec_ind_h, elec_ind); + // species_e.set_npart(offset_e + elec_ind_h()); + + // auto pos_ind_h = Kokkos::create_mirror(pos_ind); + // Kokkos::deep_copy(pos_ind_h, pos_ind); + // species_p.set_npart(offset_p + pos_ind_h()); } From d0ce7c8e64caab5fe200a85b4479dd07d21b5657 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20B=C3=B6ss?= Date: Mon, 3 Mar 2025 13:11:03 -0600 Subject: [PATCH 420/773] cleanup of conductor BCs --- src/kernels/fields_bcs.hpp | 101 ++++++++++++++++++++----------------- 1 file changed, 56 insertions(+), 45 deletions(-) diff --git a/src/kernels/fields_bcs.hpp b/src/kernels/fields_bcs.hpp index b15a16546..720408d05 100644 --- a/src/kernels/fields_bcs.hpp +++ b/src/kernels/fields_bcs.hpp @@ -506,19 +506,19 @@ namespace kernel::bc { if constexpr (S == SimEngine::SRPIC) { - if (tags & BC::E) - { - Fld((N_GHOSTS - 1) - i1, em::ex1) = Fld(N_GHOSTS + i1, em::ex1); - Fld((N_GHOSTS - 1) - i1, em::ex2) = -Fld(N_GHOSTS + 1 + i1, em::ex2); - Fld((N_GHOSTS - 1) - i1, em::ex3) = -Fld(N_GHOSTS + 1 + i1, em::ex3); - } + if (tags & BC::E) { + Fld((N_GHOSTS-1)-i1, em::ex1) = Fld(N_GHOSTS+i1, em::ex1); + Fld((N_GHOSTS-1)-i1, em::ex2) = -Fld(N_GHOSTS+i1+1, em::ex2); + Fld((N_GHOSTS-1)-i1, em::ex3) = -Fld(N_GHOSTS+i1+1, em::ex3); + } + + if (tags & BC::B) + { + Fld((N_GHOSTS-1)-i1, em::bx1) = -Fld(N_GHOSTS+i1+1, em::bx1); + Fld((N_GHOSTS-1)-i1, em::bx1) = Fld(N_GHOSTS+i1, em::bx1); + Fld((N_GHOSTS-1)-i1, em::bx1) = Fld(N_GHOSTS+i1, em::bx1); + } - if (tags & BC::B) - { - Fld((N_GHOSTS - 1) - i1, em::bx1) = -Fld(N_GHOSTS + 1 + i1, em::bx1); - Fld((N_GHOSTS - 1) - i1, em::bx2) = Fld(N_GHOSTS + i1, em::bx2); - Fld((N_GHOSTS - 1) - i1, em::bx3) = Fld(N_GHOSTS + i1, em::bx3); - } } else { // GRPIC raise::KernelError(HERE, "1D GRPIC not implemented"); @@ -530,64 +530,75 @@ namespace kernel::bc { } } - Inline void operator()(index_t i1, index_t i2) const { - if constexpr (M::Dim == Dim::_2D) { + Inline void operator()(index_t i1, index_t i2) const + { + if constexpr (M::Dim == Dim::_2D) + { - if constexpr (S == SimEngine::SRPIC) { + if constexpr (S == SimEngine::SRPIC) + { // SRPIC - if (tags & BC::E) { - // Fld((N_GHOSTS-1)-i1, i2, em::ex1) = Fld(N_GHOSTS+i1, i2, em::ex1); - // Fld((N_GHOSTS-1)-i1, i2, em::ex2) = - Fld(N_GHOSTS+1+i1, i2, em::ex2); - // Fld((N_GHOSTS-1)-i1, i2, em::ex3) = - Fld(N_GHOSTS+1+i1, i2, em::ex3); - Fld((N_GHOSTS-1)-i1, i2, em::ex1) = ZERO; - Fld((N_GHOSTS-1)-i1, i2, em::ex2) = ZERO; - Fld((N_GHOSTS-1)-i1, i2, em::ex3) = ZERO; - Fld((N_GHOSTS), i2, em::ex2) = ZERO; - Fld((N_GHOSTS), i2, em::ex3) = ZERO; + if (tags & BC::E) + { + Fld((N_GHOSTS - 1) - i1, i2, em::ex1) = Fld(N_GHOSTS + i1, i2, em::ex1); + Fld((N_GHOSTS - 1) - i1, i2, em::ex2) = -Fld(N_GHOSTS + 1 + i1, i2, em::ex2); + Fld((N_GHOSTS - 1) - i1, i2, em::ex3) = -Fld(N_GHOSTS + 1 + i1, i2, em::ex3); } if (tags & BC::B) { - Fld((N_GHOSTS-1)-i1, i2, em::bx1) = ZERO; - Fld((N_GHOSTS-1)-i1, i2, em::bx2) = ZERO; - Fld((N_GHOSTS-1)-i1, i2, em::bx3) = ZERO; + Fld((N_GHOSTS - 1) - i1, i2, em::bx1) = -Fld(N_GHOSTS + 1 + i1, i2, em::bx1); + Fld((N_GHOSTS - 1) - i1, i2, em::bx2) = Fld(N_GHOSTS + i1, i2, em::bx2); + Fld((N_GHOSTS - 1) - i1, i2, em::bx3) = Fld(N_GHOSTS + i1, i2, em::bx3); } - } else { + } + else + { // GRPIC raise::KernelError(HERE, "2D GRPIC not implemented"); } - } else { + } + else + { raise::KernelError( - HERE, - "ConductorBoundaries_kernel: 2D implementation called for D != 2"); + HERE, + "ConductorBoundaries_kernel: 2D implementation called for D != 2"); } } - Inline void operator()(index_t i1, index_t i2, index_t i3) const { - if constexpr (M::Dim == Dim::_3D) { + Inline void operator()(index_t i1, index_t i2, index_t i3) const + { + if constexpr (M::Dim == Dim::_3D) + { - if constexpr (S == SimEngine::SRPIC) { + if constexpr (S == SimEngine::SRPIC) + { // SRPIC - if (tags & BC::E) { - Fld((N_GHOSTS-1)-i1, i2, i3, em::ex1) = Fld(N_GHOSTS+i1, i2, i3, em::ex1); - Fld((N_GHOSTS-1)-i1, i2, i3, em::ex2) = -Fld(N_GHOSTS+i1, i2, i3, em::ex2); - Fld((N_GHOSTS-1)-i1, i2, i3, em::ex3) = -Fld(N_GHOSTS+i1, i2, i3, em::ex3); + if (tags & BC::E) + { + Fld((N_GHOSTS - 1) - i1, i2, i3, em::ex1) = Fld(N_GHOSTS + i1, i2, i3, em::ex1); + Fld((N_GHOSTS - 1) - i1, i2, i3, em::ex2) = -Fld(N_GHOSTS + i1 + 1, i2, i3, em::ex2); + Fld((N_GHOSTS - 1) - i1, i2, i3, em::ex3) = -Fld(N_GHOSTS + i1 + 1, i2, i3, em::ex3); } if (tags & BC::B) { - Fld((N_GHOSTS-1)-i1, i2, i3, em::bx1) = -Fld(N_GHOSTS+i1, i2, i3, em::bx1); - Fld((N_GHOSTS-1)-i1, i2, i3, em::bx2) = Fld(N_GHOSTS+i1, i2, i3, em::bx2); - Fld((N_GHOSTS-1)-i1, i2, i3, em::bx3) = Fld(N_GHOSTS+i1, i2, i3, em::bx3); + Fld((N_GHOSTS - 1) - i1, i2, i3, em::bx1) = -Fld(N_GHOSTS + i1 + 1, i2, i3, em::bx1); + Fld((N_GHOSTS - 1) - i1, i2, i3, em::bx2) = Fld(N_GHOSTS + i1, i2, i3, em::bx2); + Fld((N_GHOSTS - 1) - i1, i2, i3, em::bx3) = Fld(N_GHOSTS + i1, i2, i3, em::bx3); } - } else { + } + else + { // GRPIC raise::KernelError(HERE, "3D GRPIC not implemented"); } - } else { + } + else + { raise::KernelError( - HERE, - "ConductorBoundaries_kernel: 3D implementation called for D != 3"); + HERE, + "ConductorBoundaries_kernel: 3D implementation called for D != 3"); } } }; From 0fd05b9ea515024beb64ed7ddf9b92d941d09949 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20B=C3=B6ss?= Date: Mon, 3 Mar 2025 13:11:50 -0600 Subject: [PATCH 421/773] add 3D case and set correct boundary cells to zero --- src/engines/srpic.hpp | 963 ++++++++++++++++++++++++------------------ 1 file changed, 547 insertions(+), 416 deletions(-) diff --git a/src/engines/srpic.hpp b/src/engines/srpic.hpp index 90aa271a3..1c7ffa869 100644 --- a/src/engines/srpic.hpp +++ b/src/engines/srpic.hpp @@ -871,225 +871,321 @@ namespace ntt { "Invalid range size", HERE); + if constexpr (M::Dim == Dim::_1D) { - Kokkos::parallel_for( - "MatchFields", - CreateRangePolicy( { xi_min[0] } , { xi_max[0] } ), - kernel::bc::ConductorBoundaries_kernel( - domain.fields.em, - tags)); + Kokkos::parallel_for( + "MatchFields", + CreateRangePolicy({xi_min[0]}, {xi_max[0]}), + kernel::bc::ConductorBoundaries_kernel( + domain.fields.em, + tags)); } if constexpr (M::Dim == Dim::_2D) { - Kokkos::parallel_for( - "MatchFields", - CreateRangePolicy( { xi_min[0], xi_min[1] } , { xi_max[0], xi_max[1] } ), - kernel::bc::ConductorBoundaries_kernel( - domain.fields.em, - tags)); + Kokkos::parallel_for( + "MatchFields", + CreateRangePolicy({xi_min[0], xi_min[1]}, {xi_max[0], xi_max[1]}), + kernel::bc::ConductorBoundaries_kernel( + domain.fields.em, + tags)); } - - - } - void AtmosphereFieldsIn(dir::direction_t direction, - domain_t& domain, - BCTags tags) { - /** - * atmosphere field boundaries - */ - if constexpr (traits::has_member::value) { - const auto [sign, dim, xg_min, xg_max] = get_atm_extent(direction); - const auto dd = static_cast(dim); - boundaries_t box; - boundaries_t incl_ghosts; - for (unsigned short d { 0 }; d < M::Dim; ++d) { - if (d == dd) { - box.push_back({ xg_min, xg_max }); - if (sign > 0) { - incl_ghosts.push_back({ false, true }); - } else { - incl_ghosts.push_back({ true, false }); - } - } else { - box.push_back(Range::All); - incl_ghosts.push_back({ true, true }); - } - } - if (not domain.mesh.Intersects(box)) { - return; - } - const auto intersect_range = domain.mesh.ExtentToRange(box, incl_ghosts); - tuple_t range_min { 0 }; - tuple_t range_max { 0 }; + if constexpr (M::Dim == Dim::_3D) + { + Kokkos::parallel_for( + "MatchFields", + CreateRangePolicy({xi_min[0], xi_min[1], xi_min[2]}, {xi_max[0], xi_max[1], xi_max[2]}), + kernel::bc::ConductorBoundaries_kernel( + domain.fields.em, + tags)); + } - for (unsigned short d { 0 }; d < M::Dim; ++d) { - range_min[d] = intersect_range[d].first; - range_max[d] = intersect_range[d].second; + // these components need to be set to zero at the boundary + std::vector comps = {em::ex2, em::ex3, em::bx1}; + for (const auto &comp : comps) + { + if constexpr (M::Dim == Dim::_1D) + { + Kokkos::deep_copy( + Kokkos::subview(domain.fields.em, + std::make_pair(N_GHOSTS, N_GHOSTS), + comp), + ZERO); } - auto atm_fields = m_pgen.AtmFields(time); - std::size_t il_edge; - if (sign > 0) { - il_edge = range_min[dd] - N_GHOSTS; - } else { - il_edge = range_max[dd] - 1 - N_GHOSTS; + else if constexpr (M::Dim == Dim::_2D) + { + Kokkos::deep_copy( + Kokkos::subview(domain.fields.em, + std::make_pair(N_GHOSTS, N_GHOSTS), + std::make_pair(xi_min[1], xi_max[1]), + comp), + ZERO); } - const auto range = CreateRangePolicy(range_min, range_max); - if (dim == in::x1) { - if (sign > 0) { - Kokkos::parallel_for( - "AtmosphereBCFields", - range, - kernel::bc::EnforcedBoundaries_kernel( - domain.fields.em, - atm_fields, - domain.mesh.metric, - il_edge, - tags)); - } else { - Kokkos::parallel_for( - "AtmosphereBCFields", - range, - kernel::bc::EnforcedBoundaries_kernel( - domain.fields.em, - atm_fields, - domain.mesh.metric, - il_edge, - tags)); - } - } else if (dim == in::x2) { - if constexpr (M::Dim == Dim::_2D or M::Dim == Dim::_3D) { - if (sign > 0) { - Kokkos::parallel_for( - "AtmosphereBCFields", - range, - kernel::bc::EnforcedBoundaries_kernel( - domain.fields.em, - atm_fields, - domain.mesh.metric, - il_edge, - tags)); - } else { - Kokkos::parallel_for( - "AtmosphereBCFields", - range, - kernel::bc::EnforcedBoundaries_kernel( - domain.fields.em, - atm_fields, - domain.mesh.metric, - il_edge, - tags)); - } - } else { - raise::Error("Invalid dimension", HERE); - } - } else if (dim == in::x3) { - if constexpr (M::Dim == Dim::_3D) { - if (sign > 0) { - Kokkos::parallel_for( - "AtmosphereBCFields", - range, - kernel::bc::EnforcedBoundaries_kernel( - domain.fields.em, - atm_fields, - domain.mesh.metric, - il_edge, - tags)); - } else { - Kokkos::parallel_for( - "AtmosphereBCFields", - range, - kernel::bc::EnforcedBoundaries_kernel( - domain.fields.em, - atm_fields, - domain.mesh.metric, - il_edge, - tags)); - } - } else { - raise::Error("Invalid dimension", HERE); - } - } else { + else if constexpr (M::Dim == Dim::_3D) + { + Kokkos::deep_copy( + Kokkos::subview(domain.fields.em, + std::make_pair(N_GHOSTS, N_GHOSTS), + std::make_pair(xi_min[1], xi_max[1]), + std::make_pair(xi_min[2], xi_max[2]), + comp), + ZERO); + } + else + { raise::Error("Invalid dimension", HERE); } - } else { - raise::Error("Atm fields not implemented in PGEN for atmosphere BCs", HERE); } } - void CustomFieldsIn(dir::direction_t direction, - domain_t& domain, - BCTags tags) { - (void)direction; - (void)domain; - (void)tags; - raise::Error("Custom boundaries not implemented", HERE); - // if constexpr ( - // traits::has_member::value) { - // const auto [box, custom_fields] = m_pgen.CustomFields(time); - // if (domain.mesh.Intersects(box)) { - // } - // - // } else { - // raise::Error("Custom boundaries not implemented", HERE); - // } - } + void AtmosphereFieldsIn(dir::direction_t direction, + domain_t & domain, + BCTags tags) + { + /** + * atmosphere field boundaries + */ + if constexpr (traits::has_member::value) + { + const auto [sign, dim, xg_min, xg_max] = get_atm_extent(direction); + const auto dd = static_cast(dim); + boundaries_t box; + boundaries_t incl_ghosts; + for (unsigned short d{0}; d < M::Dim; ++d) + { + if (d == dd) + { + box.push_back({xg_min, xg_max}); + if (sign > 0) + { + incl_ghosts.push_back({false, true}); + } + else + { + incl_ghosts.push_back({true, false}); + } + } + else + { + box.push_back(Range::All); + incl_ghosts.push_back({true, true}); + } + } + if (not domain.mesh.Intersects(box)) + { + return; + } + const auto intersect_range = domain.mesh.ExtentToRange(box, incl_ghosts); + tuple_t range_min{0}; + tuple_t range_max{0}; + + for (unsigned short d{0}; d < M::Dim; ++d) + { + range_min[d] = intersect_range[d].first; + range_max[d] = intersect_range[d].second; + } + auto atm_fields = m_pgen.AtmFields(time); + std::size_t il_edge; + if (sign > 0) + { + il_edge = range_min[dd] - N_GHOSTS; + } + else + { + il_edge = range_max[dd] - 1 - N_GHOSTS; + } + const auto range = CreateRangePolicy(range_min, range_max); + if (dim == in::x1) + { + if (sign > 0) + { + Kokkos::parallel_for( + "AtmosphereBCFields", + range, + kernel::bc::EnforcedBoundaries_kernel( + domain.fields.em, + atm_fields, + domain.mesh.metric, + il_edge, + tags)); + } + else + { + Kokkos::parallel_for( + "AtmosphereBCFields", + range, + kernel::bc::EnforcedBoundaries_kernel( + domain.fields.em, + atm_fields, + domain.mesh.metric, + il_edge, + tags)); + } + } + else if (dim == in::x2) + { + if constexpr (M::Dim == Dim::_2D or M::Dim == Dim::_3D) + { + if (sign > 0) + { + Kokkos::parallel_for( + "AtmosphereBCFields", + range, + kernel::bc::EnforcedBoundaries_kernel( + domain.fields.em, + atm_fields, + domain.mesh.metric, + il_edge, + tags)); + } + else + { + Kokkos::parallel_for( + "AtmosphereBCFields", + range, + kernel::bc::EnforcedBoundaries_kernel( + domain.fields.em, + atm_fields, + domain.mesh.metric, + il_edge, + tags)); + } + } + else + { + raise::Error("Invalid dimension", HERE); + } + } + else if (dim == in::x3) + { + if constexpr (M::Dim == Dim::_3D) + { + if (sign > 0) + { + Kokkos::parallel_for( + "AtmosphereBCFields", + range, + kernel::bc::EnforcedBoundaries_kernel( + domain.fields.em, + atm_fields, + domain.mesh.metric, + il_edge, + tags)); + } + else + { + Kokkos::parallel_for( + "AtmosphereBCFields", + range, + kernel::bc::EnforcedBoundaries_kernel( + domain.fields.em, + atm_fields, + domain.mesh.metric, + il_edge, + tags)); + } + } + else + { + raise::Error("Invalid dimension", HERE); + } + } + else + { + raise::Error("Invalid dimension", HERE); + } + } + else + { + raise::Error("Atm fields not implemented in PGEN for atmosphere BCs", HERE); + } + } - void AtmosphereParticlesIn(const dir::direction_t& direction, - domain_t& domain, - InjTags tags) { - const auto [sign, dim, xg_min, xg_max] = get_atm_extent(direction); - - const auto x_surf = sign > 0 ? xg_min : xg_max; - const auto ds = m_params.template get( - "grid.boundaries.atmosphere.ds"); - const auto temp = m_params.template get( - "grid.boundaries.atmosphere.temperature"); - const auto height = m_params.template get( - "grid.boundaries.atmosphere.height"); - const auto species = - m_params.template get>( - "grid.boundaries.atmosphere.species"); - const auto nmax = m_params.template get( - "grid.boundaries.atmosphere.density"); - - Kokkos::deep_copy(domain.fields.bckp, ZERO); - auto scatter_bckp = Kokkos::Experimental::create_scatter_view( - domain.fields.bckp); - const auto use_weights = M::CoordType != Coord::Cart; - const auto ni2 = domain.mesh.n_active(in::x2); - const auto inv_n0 = ONE / m_params.template get("scales.n0"); - - // compute the density of the two species - if (tags & Inj::AssumeEmpty) { - if constexpr (M::Dim == Dim::_1D) { - Kokkos::deep_copy( - Kokkos::subview(domain.fields.bckp, Kokkos::ALL, std::make_pair(0, 1)), - ZERO); - } else if constexpr (M::Dim == Dim::_2D) { - Kokkos::deep_copy(Kokkos::subview(domain.fields.bckp, - Kokkos::ALL, - Kokkos::ALL, - std::make_pair(0, 1)), - ZERO); - } else if constexpr (M::Dim == Dim::_3D) { - Kokkos::deep_copy(Kokkos::subview(domain.fields.bckp, - Kokkos::ALL, - Kokkos::ALL, - Kokkos::ALL, - std::make_pair(0, 1)), - ZERO); + void CustomFieldsIn(dir::direction_t direction, + domain_t & domain, + BCTags tags) + { + (void)direction; + (void)domain; + (void)tags; + raise::Error("Custom boundaries not implemented", HERE); + // if constexpr ( + // traits::has_member::value) { + // const auto [box, custom_fields] = m_pgen.CustomFields(time); + // if (domain.mesh.Intersects(box)) { + // } + // + // } else { + // raise::Error("Custom boundaries not implemented", HERE); + // } } - } else { - for (const auto& sp : - std::vector({ species.first, species.second })) { - auto& prtl_spec = domain.species[sp - 1]; - if (prtl_spec.npart() == 0) { - continue; + + void AtmosphereParticlesIn(const dir::direction_t &direction, + domain_t &domain, + InjTags tags) + { + const auto [sign, dim, xg_min, xg_max] = get_atm_extent(direction); + + const auto x_surf = sign > 0 ? xg_min : xg_max; + const auto ds = m_params.template get( + "grid.boundaries.atmosphere.ds"); + const auto temp = m_params.template get( + "grid.boundaries.atmosphere.temperature"); + const auto height = m_params.template get( + "grid.boundaries.atmosphere.height"); + const auto species = + m_params.template get>( + "grid.boundaries.atmosphere.species"); + const auto nmax = m_params.template get( + "grid.boundaries.atmosphere.density"); + + Kokkos::deep_copy(domain.fields.bckp, ZERO); + auto scatter_bckp = Kokkos::Experimental::create_scatter_view( + domain.fields.bckp); + const auto use_weights = M::CoordType != Coord::Cart; + const auto ni2 = domain.mesh.n_active(in::x2); + const auto inv_n0 = ONE / m_params.template get("scales.n0"); + + // compute the density of the two species + if (tags & Inj::AssumeEmpty) + { + if constexpr (M::Dim == Dim::_1D) + { + Kokkos::deep_copy( + Kokkos::subview(domain.fields.bckp, Kokkos::ALL, std::make_pair(0, 1)), + ZERO); + } + else if constexpr (M::Dim == Dim::_2D) + { + Kokkos::deep_copy(Kokkos::subview(domain.fields.bckp, + Kokkos::ALL, + Kokkos::ALL, + std::make_pair(0, 1)), + ZERO); + } + else if constexpr (M::Dim == Dim::_3D) + { + Kokkos::deep_copy(Kokkos::subview(domain.fields.bckp, + Kokkos::ALL, + Kokkos::ALL, + Kokkos::ALL, + std::make_pair(0, 1)), + ZERO); + } } - // clang-format off + else + { + for (const auto &sp : + std::vector({species.first, species.second})) + { + auto &prtl_spec = domain.species[sp - 1]; + if (prtl_spec.npart() == 0) + { + continue; + } + // clang-format off Kokkos::parallel_for( "ComputeMoments", prtl_spec.rangeActiveParticles(), @@ -1103,230 +1199,265 @@ namespace ntt { use_weights, domain.mesh.metric, domain.mesh.flds_bc(), ni2, inv_n0, 0)); - // clang-format on - prtl_spec.set_unsorted(); - } - Kokkos::Experimental::contribute(domain.fields.bckp, scatter_bckp); - m_metadomain.SynchronizeFields(domain, Comm::Bckp, { 0, 1 }); - } - - if (dim == in::x1) { - if (sign > 0) { - const auto atm_injector = - arch::AtmosphereInjector { - domain.mesh.metric, - domain.fields.bckp, - nmax, - height, - x_surf, - ds, - temp, - domain.random_pool, - species - }; - arch::InjectNonUniform(m_params, - domain, - atm_injector, - nmax, - use_weights); - } else { - const auto atm_injector = - arch::AtmosphereInjector { - domain.mesh.metric, - domain.fields.bckp, - nmax, - height, - x_surf, - ds, - temp, - domain.random_pool, - species - }; - arch::InjectNonUniform(m_params, - domain, - atm_injector, - nmax, - use_weights); - } - } else if (dim == in::x2) { - if (sign > 0) { - const auto atm_injector = - arch::AtmosphereInjector { - domain.mesh.metric, - domain.fields.bckp, - nmax, - height, - x_surf, - ds, - temp, - domain.random_pool, - species - }; - arch::InjectNonUniform(m_params, - domain, - atm_injector, - nmax, - use_weights); - } else { - const auto atm_injector = - arch::AtmosphereInjector { - domain.mesh.metric, - domain.fields.bckp, - nmax, - height, - x_surf, - ds, - temp, - domain.random_pool, - species - }; - arch::InjectNonUniform(m_params, - domain, - atm_injector, - nmax, - use_weights); - } - } else if (dim == in::x3) { - if (sign > 0) { - const auto atm_injector = - arch::AtmosphereInjector { - domain.mesh.metric, - domain.fields.bckp, - nmax, - height, - x_surf, - ds, - temp, - domain.random_pool, - species - }; - arch::InjectNonUniform(m_params, - domain, - atm_injector, - nmax, - use_weights); - } else { - const auto atm_injector = - arch::AtmosphereInjector { - domain.mesh.metric, - domain.fields.bckp, - nmax, - height, - x_surf, - ds, - temp, - domain.random_pool, - species - }; - arch::InjectNonUniform(m_params, - domain, - atm_injector, - nmax, - use_weights); - } - } else { - raise::Error("Invalid dimension", HERE); - } - return; - } - - private: - /** - * @brief Get the buffer region of the atmosphere and the direction - * @param direction direction in which the atmosphere is applied - * @return tuple: [sign of the direction, the direction (as in::), the min and max extent - * @note xg_min and xg_max are the extents where the fields are set, not the atmosphere itself - * @note i.e. - * - * fields set particles injected - * ghost zone | | - * v v v - * |....|...........|*******************..... -> x1 - * ^ ^ - * xg_min xg_max - * | | | - * |<-- buffer -->|<-- atmosphere -->| - * - * in this case the function returns { -1, in::x1, xg_min, xg_max } - */ - auto get_atm_extent(dir::direction_t direction) const - -> std::tuple { - const auto sign = direction.get_sign(); - const auto dim = direction.get_dim(); - const auto min_buff = m_params.template get( - "algorithms.current_filters") + - 2; - const auto buffer_ncells = min_buff > 5 ? min_buff : 5; - if (M::CoordType != Coord::Cart and (dim != in::x1 or sign > 0)) { - raise::Error("For non-cartesian coordinates atmosphere BCs is " - "possible only in -x1 (@ rmin)", - HERE); - } - real_t xg_min { ZERO }, xg_max { ZERO }; - std::size_t ig_min, ig_max; - if (sign > 0) { // + direction - ig_min = m_metadomain.mesh().n_active(dim) - buffer_ncells; - ig_max = m_metadomain.mesh().n_active(dim); - } else { // - direction - ig_min = 0; - ig_max = buffer_ncells; - } + // clang-format on + prtl_spec.set_unsorted(); + } + Kokkos::Experimental::contribute(domain.fields.bckp, scatter_bckp); + m_metadomain.SynchronizeFields(domain, Comm::Bckp, {0, 1}); + } - if (dim == in::x1) { - xg_min = m_metadomain.mesh().metric.template convert<1, Crd::Cd, Crd::Ph>( - static_cast(ig_min)); - xg_max = m_metadomain.mesh().metric.template convert<1, Crd::Cd, Crd::Ph>( - static_cast(ig_max)); - } else if (dim == in::x2) { - if constexpr (M::Dim == Dim::_2D or M::Dim == Dim::_3D) { - xg_min = m_metadomain.mesh().metric.template convert<2, Crd::Cd, Crd::Ph>( - static_cast(ig_min)); - xg_max = m_metadomain.mesh().metric.template convert<2, Crd::Cd, Crd::Ph>( - static_cast(ig_max)); - } else { - raise::Error("Invalid dimension", HERE); - } - } else if (dim == in::x3) { - if constexpr (M::Dim == Dim::_3D) { - xg_min = m_metadomain.mesh().metric.template convert<3, Crd::Cd, Crd::Ph>( - static_cast(ig_min)); - xg_max = m_metadomain.mesh().metric.template convert<3, Crd::Cd, Crd::Ph>( - static_cast(ig_max)); - } else { - raise::Error("Invalid dimension", HERE); + if (dim == in::x1) + { + if (sign > 0) + { + const auto atm_injector = + arch::AtmosphereInjector{ + domain.mesh.metric, + domain.fields.bckp, + nmax, + height, + x_surf, + ds, + temp, + domain.random_pool, + species}; + arch::InjectNonUniform(m_params, + domain, + atm_injector, + nmax, + use_weights); + } + else + { + const auto atm_injector = + arch::AtmosphereInjector{ + domain.mesh.metric, + domain.fields.bckp, + nmax, + height, + x_surf, + ds, + temp, + domain.random_pool, + species}; + arch::InjectNonUniform(m_params, + domain, + atm_injector, + nmax, + use_weights); + } + } + else if (dim == in::x2) + { + if (sign > 0) + { + const auto atm_injector = + arch::AtmosphereInjector{ + domain.mesh.metric, + domain.fields.bckp, + nmax, + height, + x_surf, + ds, + temp, + domain.random_pool, + species}; + arch::InjectNonUniform(m_params, + domain, + atm_injector, + nmax, + use_weights); + } + else + { + const auto atm_injector = + arch::AtmosphereInjector{ + domain.mesh.metric, + domain.fields.bckp, + nmax, + height, + x_surf, + ds, + temp, + domain.random_pool, + species}; + arch::InjectNonUniform(m_params, + domain, + atm_injector, + nmax, + use_weights); + } + } + else if (dim == in::x3) + { + if (sign > 0) + { + const auto atm_injector = + arch::AtmosphereInjector{ + domain.mesh.metric, + domain.fields.bckp, + nmax, + height, + x_surf, + ds, + temp, + domain.random_pool, + species}; + arch::InjectNonUniform(m_params, + domain, + atm_injector, + nmax, + use_weights); + } + else + { + const auto atm_injector = + arch::AtmosphereInjector{ + domain.mesh.metric, + domain.fields.bckp, + nmax, + height, + x_surf, + ds, + temp, + domain.random_pool, + species}; + arch::InjectNonUniform(m_params, + domain, + atm_injector, + nmax, + use_weights); + } + } + else + { + raise::Error("Invalid dimension", HERE); + } + return; } - } else { - raise::Error("Invalid dimension", HERE); - } - return { sign, dim, xg_min, xg_max }; - } - auto range_with_axis_BCs(const domain_t& domain) -> range_t { - auto range = domain.mesh.rangeActiveCells(); - if constexpr (M::CoordType != Coord::Cart) { + private: /** - * @brief taking one extra cell in the x2 direction if AXIS BCs + * @brief Get the buffer region of the atmosphere and the direction + * @param direction direction in which the atmosphere is applied + * @return tuple: [sign of the direction, the direction (as in::), the min and max extent + * @note xg_min and xg_max are the extents where the fields are set, not the atmosphere itself + * @note i.e. + * + * fields set particles injected + * ghost zone | | + * v v v + * |....|...........|*******************..... -> x1 + * ^ ^ + * xg_min xg_max + * | | | + * |<-- buffer -->|<-- atmosphere -->| + * + * in this case the function returns { -1, in::x1, xg_min, xg_max } */ - if constexpr (M::Dim == Dim::_2D) { - if (domain.mesh.flds_bc_in({ 0, +1 }) == FldsBC::AXIS) { - range = CreateRangePolicy( - { domain.mesh.i_min(in::x1), domain.mesh.i_min(in::x2) }, - { domain.mesh.i_max(in::x1), domain.mesh.i_max(in::x2) + 1 }); + auto get_atm_extent(dir::direction_t direction) const + -> std::tuple + { + const auto sign = direction.get_sign(); + const auto dim = direction.get_dim(); + const auto min_buff = m_params.template get( + "algorithms.current_filters") + + 2; + const auto buffer_ncells = min_buff > 5 ? min_buff : 5; + if (M::CoordType != Coord::Cart and (dim != in::x1 or sign > 0)) + { + raise::Error("For non-cartesian coordinates atmosphere BCs is " + "possible only in -x1 (@ rmin)", + HERE); + } + real_t xg_min{ZERO}, xg_max{ZERO}; + std::size_t ig_min, ig_max; + if (sign > 0) + { // + direction + ig_min = m_metadomain.mesh().n_active(dim) - buffer_ncells; + ig_max = m_metadomain.mesh().n_active(dim); + } + else + { // - direction + ig_min = 0; + ig_max = buffer_ncells; + } + + if (dim == in::x1) + { + xg_min = m_metadomain.mesh().metric.template convert<1, Crd::Cd, Crd::Ph>( + static_cast(ig_min)); + xg_max = m_metadomain.mesh().metric.template convert<1, Crd::Cd, Crd::Ph>( + static_cast(ig_max)); } - } else if constexpr (M::Dim == Dim::_3D) { - if (domain.mesh.flds_bc_in({ 0, +1, 0 }) == FldsBC::AXIS) { - range = CreateRangePolicy({ domain.mesh.i_min(in::x1), - domain.mesh.i_min(in::x2), - domain.mesh.i_min(in::x3) }, - { domain.mesh.i_max(in::x1), - domain.mesh.i_max(in::x2) + 1, - domain.mesh.i_max(in::x3) }); + else if (dim == in::x2) + { + if constexpr (M::Dim == Dim::_2D or M::Dim == Dim::_3D) + { + xg_min = m_metadomain.mesh().metric.template convert<2, Crd::Cd, Crd::Ph>( + static_cast(ig_min)); + xg_max = m_metadomain.mesh().metric.template convert<2, Crd::Cd, Crd::Ph>( + static_cast(ig_max)); + } + else + { + raise::Error("Invalid dimension", HERE); + } } + else if (dim == in::x3) + { + if constexpr (M::Dim == Dim::_3D) + { + xg_min = m_metadomain.mesh().metric.template convert<3, Crd::Cd, Crd::Ph>( + static_cast(ig_min)); + xg_max = m_metadomain.mesh().metric.template convert<3, Crd::Cd, Crd::Ph>( + static_cast(ig_max)); + } + else + { + raise::Error("Invalid dimension", HERE); + } + } + else + { + raise::Error("Invalid dimension", HERE); + } + return {sign, dim, xg_min, xg_max}; } - } - return range; - } - }; + + auto range_with_axis_BCs(const domain_t &domain) -> range_t + { + auto range = domain.mesh.rangeActiveCells(); + if constexpr (M::CoordType != Coord::Cart) + { + /** + * @brief taking one extra cell in the x2 direction if AXIS BCs + */ + if constexpr (M::Dim == Dim::_2D) + { + if (domain.mesh.flds_bc_in({0, +1}) == FldsBC::AXIS) + { + range = CreateRangePolicy( + {domain.mesh.i_min(in::x1), domain.mesh.i_min(in::x2)}, + {domain.mesh.i_max(in::x1), domain.mesh.i_max(in::x2) + 1}); + } + } + else if constexpr (M::Dim == Dim::_3D) + { + if (domain.mesh.flds_bc_in({0, +1, 0}) == FldsBC::AXIS) + { + range = CreateRangePolicy({domain.mesh.i_min(in::x1), + domain.mesh.i_min(in::x2), + domain.mesh.i_min(in::x3)}, + {domain.mesh.i_max(in::x1), + domain.mesh.i_max(in::x2) + 1, + domain.mesh.i_max(in::x3)}); + } + } + } + return range; + } + }; } // namespace ntt From 425abe5fcfbb040127e531c7e9d47efd6a6a7657 Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Tue, 4 Mar 2025 13:22:38 -0600 Subject: [PATCH 422/773] Ongoing --- setups/srpic/shocktest/pgen.hpp | 156 ++++++++++++++++---------------- 1 file changed, 78 insertions(+), 78 deletions(-) diff --git a/setups/srpic/shocktest/pgen.hpp b/setups/srpic/shocktest/pgen.hpp index 1b8926c67..a1ce9a1a9 100644 --- a/setups/srpic/shocktest/pgen.hpp +++ b/setups/srpic/shocktest/pgen.hpp @@ -48,8 +48,8 @@ namespace user { Inline auto bx3(const coord_t& x_ph) const -> real_t { // return Bmag * math::sin(Btheta) * math::cos(Bphi); - return ONE + 0.01 * (ONE - math::tanh(20.*(-1.5 + x_ph[0]))*math::tanh(20.*(-0.5 + x_ph[0])))/2.0 * math::sin(4.0 * constant::PI * x_ph[0]); - // return ZERO; + // return ONE + 0.01 * (ONE - math::tanh(20.*(-1.5 + x_ph[0]))*math::tanh(20.*(-0.5 + x_ph[0])))/2.0 * math::sin(4.0 * constant::PI * x_ph[0]); + return ZERO; } // electric field components @@ -59,8 +59,8 @@ namespace user { Inline auto ex2(const coord_t& x_ph) const -> real_t { // return -Vx * Bmag * math::sin(Btheta) * math::cos(Bphi); - return ZERO - 0.01 * (ONE - math::tanh(20.*(-1.5 + x_ph[0]))*math::tanh(20.*(-0.5 + x_ph[0])))/2.0 * math::sin(4.0 * constant::PI * x_ph[0]); - // return ZERO; + // return ZERO - 0.01 * (ONE - math::tanh(20.*(-1.5 + x_ph[0]))*math::tanh(20.*(-0.5 + x_ph[0])))/2.0 * math::sin(4.0 * constant::PI * x_ph[0]); + return ZERO; } Inline auto ex3(const coord_t& x_ph) const -> real_t { @@ -120,82 +120,82 @@ namespace user { inline void InitPrtls(Domain& domain) { - // auto& species_e = domain.species[0]; - // auto& species_p = domain.species[1]; + auto& species_e = domain.species[0]; + auto& species_p = domain.species[1]; - // array_t elec_ind("elec_ind"); - // array_t pos_ind("pos_ind"); + array_t elec_ind("elec_ind"); + array_t pos_ind("pos_ind"); - // auto offset_e = species_e.npart(); - // auto offset_p = species_p.npart(); - - // auto ux1_e = species_e.ux1; - // auto ux2_e = species_e.ux2; - // auto ux3_e = species_e.ux3; - // auto i1_e = species_e.i1; - // auto i2_e = species_e.i2; - // auto dx1_e = species_e.dx1; - // auto dx2_e = species_e.dx2; - // auto phi_e = species_e.phi; - // auto weight_e = species_e.weight; - // auto tag_e = species_e.tag; - - // auto ux1_p = species_p.ux1; - // auto ux2_p = species_p.ux2; - // auto ux3_p = species_p.ux3; - // auto i1_p = species_p.i1; - // auto i2_p = species_p.i2; - // auto dx1_p = species_p.dx1; - // auto dx2_p = species_p.dx2; - // auto phi_p = species_p.phi; - // auto weight_p = species_p.weight; - // auto tag_p = species_p.tag; - - // int nseed = 1; - - // Kokkos::parallel_for("init_particles", nseed, KOKKOS_LAMBDA(const int& s) { - - // // ToDo: fix this - // auto i1_ = math::floor(10); - // auto i2_ = math::floor(64); - // auto dx1_ = HALF; - // auto dx2_ = HALF; - - - // auto elec_p = Kokkos::atomic_fetch_add(&elec_ind(), 1); - // auto pos_p = Kokkos::atomic_fetch_add(&pos_ind(), 1); - - // i1_e(elec_p + offset_e) = i1_; - // dx1_e(elec_p + offset_e) = dx1_; - // i2_e(elec_p + offset_e) = i2_; - // dx2_e(elec_p + offset_e) = dx2_; - // ux1_e(elec_p + offset_e) = -0.5; - // ux2_e(elec_p + offset_e) = 0.5; - // ux3_e(elec_p + offset_e) = ZERO; - // weight_e(elec_p + offset_e) = ONE; - // tag_e(elec_p + offset_e) = ParticleTag::alive; - - // i1_p(pos_p + offset_p) = i1_; - // dx1_p(pos_p + offset_p) = dx1_; - // i2_p(pos_p + offset_p) = i2_; - // dx2_p(pos_p + offset_p) = dx2_; - // ux1_p(pos_p + offset_p) = 0.5; - // ux2_p(pos_p + offset_p) = -0.5; - // ux3_p(pos_p + offset_p) = ZERO; - // weight_p(pos_p + offset_p) = ONE; - // tag_p(pos_p + offset_p) = ParticleTag::alive; - - - // }); - - - // auto elec_ind_h = Kokkos::create_mirror(elec_ind); - // Kokkos::deep_copy(elec_ind_h, elec_ind); - // species_e.set_npart(offset_e + elec_ind_h()); - - // auto pos_ind_h = Kokkos::create_mirror(pos_ind); - // Kokkos::deep_copy(pos_ind_h, pos_ind); - // species_p.set_npart(offset_p + pos_ind_h()); + auto offset_e = species_e.npart(); + auto offset_p = species_p.npart(); + + auto ux1_e = species_e.ux1; + auto ux2_e = species_e.ux2; + auto ux3_e = species_e.ux3; + auto i1_e = species_e.i1; + auto i2_e = species_e.i2; + auto dx1_e = species_e.dx1; + auto dx2_e = species_e.dx2; + auto phi_e = species_e.phi; + auto weight_e = species_e.weight; + auto tag_e = species_e.tag; + + auto ux1_p = species_p.ux1; + auto ux2_p = species_p.ux2; + auto ux3_p = species_p.ux3; + auto i1_p = species_p.i1; + auto i2_p = species_p.i2; + auto dx1_p = species_p.dx1; + auto dx2_p = species_p.dx2; + auto phi_p = species_p.phi; + auto weight_p = species_p.weight; + auto tag_p = species_p.tag; + + int nseed = 1; + + Kokkos::parallel_for("init_particles", nseed, KOKKOS_LAMBDA(const int& s) { + + // ToDo: fix this + auto i1_ = math::floor(10); + auto i2_ = math::floor(64); + auto dx1_ = HALF; + auto dx2_ = HALF; + + + auto elec_p = Kokkos::atomic_fetch_add(&elec_ind(), 1); + auto pos_p = Kokkos::atomic_fetch_add(&pos_ind(), 1); + + i1_e(elec_p + offset_e) = i1_; + dx1_e(elec_p + offset_e) = dx1_; + i2_e(elec_p + offset_e) = i2_; + dx2_e(elec_p + offset_e) = dx2_; + ux1_e(elec_p + offset_e) = -0.5; + ux2_e(elec_p + offset_e) = 0.5; + ux3_e(elec_p + offset_e) = ZERO; + weight_e(elec_p + offset_e) = ONE; + tag_e(elec_p + offset_e) = ParticleTag::alive; + + i1_p(pos_p + offset_p) = i1_; + dx1_p(pos_p + offset_p) = dx1_; + i2_p(pos_p + offset_p) = i2_; + dx2_p(pos_p + offset_p) = dx2_; + ux1_p(pos_p + offset_p) = 0.5; + ux2_p(pos_p + offset_p) = -0.5; + ux3_p(pos_p + offset_p) = ZERO; + weight_p(pos_p + offset_p) = ONE; + tag_p(pos_p + offset_p) = ParticleTag::alive; + + + }); + + + auto elec_ind_h = Kokkos::create_mirror(elec_ind); + Kokkos::deep_copy(elec_ind_h, elec_ind); + species_e.set_npart(offset_e + elec_ind_h()); + + auto pos_ind_h = Kokkos::create_mirror(pos_ind); + Kokkos::deep_copy(pos_ind_h, pos_ind); + species_p.set_npart(offset_p + pos_ind_h()); } From cfee51ecac9150e9c6c43668a83ed097f98a64ff Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Tue, 4 Mar 2025 15:06:18 -0600 Subject: [PATCH 423/773] Ongoing --- src/engines/srpic.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engines/srpic.hpp b/src/engines/srpic.hpp index 1c7ffa869..21a44373d 100644 --- a/src/engines/srpic.hpp +++ b/src/engines/srpic.hpp @@ -918,7 +918,7 @@ namespace ntt { { Kokkos::deep_copy( Kokkos::subview(domain.fields.em, - std::make_pair(N_GHOSTS, N_GHOSTS), + std::make_pair(N_GHOSTS+1, N_GHOSTS+1), std::make_pair(xi_min[1], xi_max[1]), comp), ZERO); From 7d317e6bf1db35098a153bc8bccd5a5f90630500 Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Tue, 4 Mar 2025 15:40:21 -0600 Subject: [PATCH 424/773] Ongoing --- src/engines/srpic.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engines/srpic.hpp b/src/engines/srpic.hpp index 21a44373d..1c7ffa869 100644 --- a/src/engines/srpic.hpp +++ b/src/engines/srpic.hpp @@ -918,7 +918,7 @@ namespace ntt { { Kokkos::deep_copy( Kokkos::subview(domain.fields.em, - std::make_pair(N_GHOSTS+1, N_GHOSTS+1), + std::make_pair(N_GHOSTS, N_GHOSTS), std::make_pair(xi_min[1], xi_max[1]), comp), ZERO); From 21d99374744e333e5a6400058acab22347e0ecdd Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Tue, 4 Mar 2025 15:53:24 -0600 Subject: [PATCH 425/773] Ongoing --- src/engines/srpic.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engines/srpic.hpp b/src/engines/srpic.hpp index 1c7ffa869..12872bf4e 100644 --- a/src/engines/srpic.hpp +++ b/src/engines/srpic.hpp @@ -918,7 +918,7 @@ namespace ntt { { Kokkos::deep_copy( Kokkos::subview(domain.fields.em, - std::make_pair(N_GHOSTS, N_GHOSTS), + std::make_pair(N_GHOSTS, N_GHOSTS+1), std::make_pair(xi_min[1], xi_max[1]), comp), ZERO); From 4a4f858c8c3a57a099881e61188a4f086815f2ec Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Thu, 6 Mar 2025 14:38:44 -0500 Subject: [PATCH 426/773] kernels/faraday_gr: bug -- set ghost cells between mesh boundaries --- src/kernels/faraday_gr.hpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/kernels/faraday_gr.hpp b/src/kernels/faraday_gr.hpp index 5f6e5590b..241fa35dc 100644 --- a/src/kernels/faraday_gr.hpp +++ b/src/kernels/faraday_gr.hpp @@ -73,8 +73,10 @@ namespace kernel::gr { Bout(i1, i2, em::bx1) = Bin(i1, i2, em::bx1) + coeff * inv_sqrt_detH_0pH * (E(i1, i2, em::ex3) - E(i1, i2 + 1, em::ex3)); - if ((i2 == i2min) && is_axis_i2min) { - Bout(i1, i2, em::bx2) = ZERO; + if (i2 == i2min) { + if (is_axis_i2min) { + Bout(i1, i2, em::bx2) = ZERO; + } } else { const real_t inv_sqrt_detH_pH0 { ONE / metric.sqrt_det_h( { i1_ + HALF, i2_ }) }; From bd723f3905bd3356b30faf6a8380106a1a890a9e Mon Sep 17 00:00:00 2001 From: hayk Date: Fri, 7 Mar 2025 11:30:47 -0500 Subject: [PATCH 427/773] minor reformatting of conductor BC --- input.example.toml | 2 +- setups/srpic/shocktest/pgen.hpp | 149 ++-- setups/srpic/shocktest/shock.toml | 26 +- src/engines/srpic.hpp | 1044 +++++++++++++---------------- src/global/enums.h | 19 +- src/global/tests/enums.cpp | 5 +- src/kernels/fields_bcs.hpp | 157 +++-- 7 files changed, 622 insertions(+), 780 deletions(-) diff --git a/input.example.toml b/input.example.toml index 788c30685..b327df54d 100644 --- a/input.example.toml +++ b/input.example.toml @@ -90,7 +90,7 @@ # Boundary conditions for fields: # @required # @type: 1/2/3-size array of string tuples, each of size 1 or 2 - # @valid: "PERIODIC", "MATCH", "FIXED", "ATMOSPHERE", "CUSTOM", "HORIZON" + # @valid: "PERIODIC", "MATCH", "FIXED", "ATMOSPHERE", "CUSTOM", "HORIZON", "CONDUCTOR" # @example: [["CUSTOM", "MATCH"]] (for 2D spherical [[rmin, rmax]]) # @note: When periodic in any of the directions, you should only set one value: [..., ["PERIODIC"], ...] # @note: In spherical, bondaries in theta/phi are set automatically (only specify bc @ [rmin, rmax]): [["ATMOSPHERE", "MATCH"]] diff --git a/setups/srpic/shocktest/pgen.hpp b/setups/srpic/shocktest/pgen.hpp index a1ce9a1a9..4f6decc76 100644 --- a/setups/srpic/shocktest/pgen.hpp +++ b/setups/srpic/shocktest/pgen.hpp @@ -14,6 +14,7 @@ #include "framework/domain/metadomain.h" #include +#include namespace user { using namespace ntt; @@ -48,7 +49,8 @@ namespace user { Inline auto bx3(const coord_t& x_ph) const -> real_t { // return Bmag * math::sin(Btheta) * math::cos(Bphi); - // return ONE + 0.01 * (ONE - math::tanh(20.*(-1.5 + x_ph[0]))*math::tanh(20.*(-0.5 + x_ph[0])))/2.0 * math::sin(4.0 * constant::PI * x_ph[0]); + // return ONE + 0.01 * (ONE - math::tanh(20.*(-1.5 + x_ph[0]))*math::tanh(20.*(-0.5 + // + x_ph[0])))/2.0 * math::sin(4.0 * constant::PI * x_ph[0]); return ZERO; } @@ -59,7 +61,8 @@ namespace user { Inline auto ex2(const coord_t& x_ph) const -> real_t { // return -Vx * Bmag * math::sin(Btheta) * math::cos(Bphi); - // return ZERO - 0.01 * (ONE - math::tanh(20.*(-1.5 + x_ph[0]))*math::tanh(20.*(-0.5 + x_ph[0])))/2.0 * math::sin(4.0 * constant::PI * x_ph[0]); + // return ZERO - 0.01 * (ONE - math::tanh(20.*(-1.5 + x_ph[0]))*math::tanh(20.*(-0.5 + // + x_ph[0])))/2.0 * math::sin(4.0 * constant::PI * x_ph[0]); return ZERO; } @@ -88,17 +91,32 @@ namespace user { const real_t drift_ux, temperature; - const real_t Btheta, Bphi, Bmag; - InitFields init_flds; + const std::vector x1arr_e, x2arr_e, ux1arr_e, ux2arr_e, ux3arr_e; + const std::vector x1arr_i, x2arr_i, ux1arr_i, ux2arr_i, ux3arr_i; + + const real_t Btheta, Bphi, Bmag; + InitFields init_flds; + const Metadomain* metadomain; inline PGen(const SimulationParams& p, const Metadomain& m) : arch::ProblemGenerator { p } , drift_ux { p.template get("setup.drift_ux") } , temperature { p.template get("setup.temperature") } - , Bmag { p.template get("setup.Bmag", ZERO) } + , x1arr_e { p.template get>("setup.x_e") } + , x2arr_e { p.template get>("setup.y_e") } + , ux1arr_e { p.template get>("setup.ux_e") } + , ux2arr_e { p.template get>("setup.uy_e") } + , ux3arr_e { p.template get>("setup.uz_e") } + , x1arr_i { p.template get>("setup.x_i") } + , x2arr_i { p.template get>("setup.y_i") } + , ux1arr_i { p.template get>("setup.ux_i") } + , ux2arr_i { p.template get>("setup.uy_i") } + , ux3arr_i { p.template get>("setup.uz_i") } , Btheta { p.template get("setup.Btheta", ZERO) } + , Bmag { p.template get("setup.Bmag", ZERO) } , Bphi { p.template get("setup.Bphi", ZERO) } - , init_flds { Bmag, Btheta, Bphi, drift_ux } {} + , init_flds { Bmag, Btheta, Bphi, drift_ux } + , metadomain { &m } {} inline PGen() {} @@ -113,111 +131,32 @@ namespace user { } } - auto MatchFields(real_t time) const -> InitFields { return init_flds; } inline void InitPrtls(Domain& domain) { - - auto& species_e = domain.species[0]; - auto& species_p = domain.species[1]; - - array_t elec_ind("elec_ind"); - array_t pos_ind("pos_ind"); - - auto offset_e = species_e.npart(); - auto offset_p = species_p.npart(); - - auto ux1_e = species_e.ux1; - auto ux2_e = species_e.ux2; - auto ux3_e = species_e.ux3; - auto i1_e = species_e.i1; - auto i2_e = species_e.i2; - auto dx1_e = species_e.dx1; - auto dx2_e = species_e.dx2; - auto phi_e = species_e.phi; - auto weight_e = species_e.weight; - auto tag_e = species_e.tag; - - auto ux1_p = species_p.ux1; - auto ux2_p = species_p.ux2; - auto ux3_p = species_p.ux3; - auto i1_p = species_p.i1; - auto i2_p = species_p.i2; - auto dx1_p = species_p.dx1; - auto dx2_p = species_p.dx2; - auto phi_p = species_p.phi; - auto weight_p = species_p.weight; - auto tag_p = species_p.tag; - - int nseed = 1; - - Kokkos::parallel_for("init_particles", nseed, KOKKOS_LAMBDA(const int& s) { - - // ToDo: fix this - auto i1_ = math::floor(10); - auto i2_ = math::floor(64); - auto dx1_ = HALF; - auto dx2_ = HALF; - - - auto elec_p = Kokkos::atomic_fetch_add(&elec_ind(), 1); - auto pos_p = Kokkos::atomic_fetch_add(&pos_ind(), 1); - - i1_e(elec_p + offset_e) = i1_; - dx1_e(elec_p + offset_e) = dx1_; - i2_e(elec_p + offset_e) = i2_; - dx2_e(elec_p + offset_e) = dx2_; - ux1_e(elec_p + offset_e) = -0.5; - ux2_e(elec_p + offset_e) = 0.5; - ux3_e(elec_p + offset_e) = ZERO; - weight_e(elec_p + offset_e) = ONE; - tag_e(elec_p + offset_e) = ParticleTag::alive; - - i1_p(pos_p + offset_p) = i1_; - dx1_p(pos_p + offset_p) = dx1_; - i2_p(pos_p + offset_p) = i2_; - dx2_p(pos_p + offset_p) = dx2_; - ux1_p(pos_p + offset_p) = 0.5; - ux2_p(pos_p + offset_p) = -0.5; - ux3_p(pos_p + offset_p) = ZERO; - weight_p(pos_p + offset_p) = ONE; - tag_p(pos_p + offset_p) = ParticleTag::alive; - - - }); - - - auto elec_ind_h = Kokkos::create_mirror(elec_ind); - Kokkos::deep_copy(elec_ind_h, elec_ind); - species_e.set_npart(offset_e + elec_ind_h()); - - auto pos_ind_h = Kokkos::create_mirror(pos_ind); - Kokkos::deep_copy(pos_ind_h, pos_ind); - species_p.set_npart(offset_p + pos_ind_h()); - - + arch::InjectGlobally(*metadomain, + domain, + 1, + { + { "x1", x1arr_e }, + { "x2", x2arr_e }, + { "ux1", ux1arr_e }, + { "ux2", ux1arr_e }, + { "ux3", ux3arr_e } + }); + arch::InjectGlobally(*metadomain, + domain, + 2, + { + { "x1", x1arr_i }, + { "x2", x2arr_i }, + { "ux1", ux1arr_i }, + { "ux2", ux1arr_i }, + { "ux3", ux3arr_i } + }); } - - - // inline void InitPrtls(Domain& local_domain) { - // const auto energy_dist = arch::Maxwellian(local_domain.mesh.metric, - // local_domain.random_pool, - // temperature, - // -drift_ux, - // in::x1); - - // const auto injector = arch::UniformInjector( - // energy_dist, - // { 1, 2 }); - // arch::InjectUniform>( - // params, - // local_domain, - // injector, - // 1.0); - // } - }; } // namespace user diff --git a/setups/srpic/shocktest/shock.toml b/setups/srpic/shocktest/shock.toml index a77f5c2e9..6c0c9a3a0 100644 --- a/setups/srpic/shocktest/shock.toml +++ b/setups/srpic/shocktest/shock.toml @@ -11,7 +11,7 @@ metric = "minkowski" [grid.boundaries] - fields = [["CONDUCTOR", "FIXED"], ["PERIODIC"]] + fields = [["CONDUCTOR", "FIXED"], ["PERIODIC"]] particles = [["REFLECT", "ABSORB"], ["PERIODIC"]] [scales] @@ -20,8 +20,8 @@ [algorithms] current_filters = 8 - fieldsolver = "false" - deposit = "false" + fieldsolver = "false" + deposit = "false" [algorithms.timestep] CFL = 0.5 @@ -44,13 +44,23 @@ [setup] drift_ux = 0.1 temperature = 1e-3 - Bmag = 1.0 - Btheta = 0.0 - Bphi = 0.0 + Bmag = 1.0 + Btheta = 0.0 + Bphi = 0.0 + x_e = [0.05] + y_e = [0.0] + ux_e = [-0.01] + uy_e = [0.01] + uz_e = [0.001] + x_i = [0.05] + y_i = [0.0] + ux_i = [0.01] + uy_i = [-0.01] + uz_i = [-0.001] [output] - interval = 1 - format = "hdf5" + interval = 1 + format = "hdf5" [output.fields] quantities = ["N_1", "N_2", "E", "B", "T0i_1", "T0i_2", "J"] diff --git a/src/engines/srpic.hpp b/src/engines/srpic.hpp index 12872bf4e..dd2f5ccec 100644 --- a/src/engines/srpic.hpp +++ b/src/engines/srpic.hpp @@ -839,353 +839,284 @@ namespace ntt { } void PerfectConductorFieldsIn(dir::direction_t direction, - domain_t& domain, - BCTags tags) { + domain_t& domain, + BCTags tags) { /** * perfect conductor field boundaries */ - const auto sign = direction.get_sign(); - const auto dim = direction.get_dim(); - raise::ErrorIf(dim != in::x1 and M::CoordType != Coord::Cart, - "Perfect conductor BCs only implemented for x1 in " - "non-cartesian coordinates", - HERE); + if constexpr (M::CoordType != Coord::Cart) { + (void)direction; + (void)domain; + (void)tags; + raise::Error( + "Perfect conductor BCs only applicable to cartesian coordinates", + HERE); + } else { + const auto sign = direction.get_sign(); + const auto dim = direction.get_dim(); + raise::ErrorIf(dim != in::x1, + "Perfect conductor BCs only implemented for x1", + HERE); + std::vector xi_min, xi_max; - std::vector xi_min, xi_max; + const std::vector all_dirs { in::x1, in::x2, in::x3 }; - const std::vector all_dirs { in::x1, in::x2, in::x3 }; - - for (unsigned short d { 0 }; d < static_cast(M::Dim); ++d) { - const auto dd = all_dirs[d]; - if (dim == dd) { + for (unsigned short d { 0 }; d < static_cast(M::Dim); ++d) { + const auto dd = all_dirs[d]; + if (dim == dd) { xi_min.push_back(0); - xi_max.push_back(N_GHOSTS); + xi_max.push_back(N_GHOSTS + 1); + } else { + xi_min.push_back(0); + xi_max.push_back(domain.mesh.n_all(dd)); + } + } + raise::ErrorIf(xi_min.size() != xi_max.size() or + xi_min.size() != static_cast(M::Dim), + "Invalid range size", + HERE); + + range_t range; + if constexpr (M::Dim == Dim::_1D) { + range = CreateRangePolicy({ xi_min[0] }, { xi_max[0] }); + } else if constexpr (M::Dim == Dim::_2D) { + range = CreateRangePolicy({ xi_min[0], xi_min[1] }, + { xi_max[0], xi_max[1] }); + } else if constexpr (M::Dim == Dim::_3D) { + range = CreateRangePolicy({ xi_min[0], xi_min[1], xi_min[2] }, + { xi_max[0], xi_max[1], xi_max[2] }); } else { - xi_min.push_back(0); - xi_max.push_back(domain.mesh.n_all(dd)); + raise::Error("Invalid dimension", HERE); } - } - raise::ErrorIf(xi_min.size() != xi_max.size() or - xi_min.size() != static_cast(M::Dim), - "Invalid range size", - HERE); - - - if constexpr (M::Dim == Dim::_1D) - { Kokkos::parallel_for( - "MatchFields", - CreateRangePolicy({xi_min[0]}, {xi_max[0]}), - kernel::bc::ConductorBoundaries_kernel( - domain.fields.em, - tags)); + "MatchFields", + range, + kernel::bc::ConductorBoundaries_kernel(domain.fields.em, + tags)); + + // if constexpr (M::Dim == Dim::_1D) { + // Kokkos::parallel_for( + // "MatchFields", + // CreateRangePolicy({ xi_min[0] }, { xi_max[0] }), + // kernel::bc::ConductorBoundaries_kernel(domain.fields.em, + // tags)); + // } else if constexpr (M::Dim == Dim::_2D) { + // Kokkos::parallel_for( + // "MatchFields", + // CreateRangePolicy({ xi_min[0], xi_min[1] }, + // { xi_max[0], xi_max[1] }), + // kernel::bc::ConductorBoundaries_kernel(domain.fields.em, + // tags)); + // } else if constexpr (M::Dim == Dim::_3D) { + // Kokkos::parallel_for( + // "MatchFields", + // CreateRangePolicy({ xi_min[0], xi_min[1], xi_min[2] }, + // { xi_max[0], xi_max[1], xi_max[2] }), + // kernel::bc::ConductorBoundaries_kernel(domain.fields.em, + // tags)); + // } else { + // raise::Error("Invalid dimension", HERE); + // } } + } - if constexpr (M::Dim == Dim::_2D) - { - Kokkos::parallel_for( - "MatchFields", - CreateRangePolicy({xi_min[0], xi_min[1]}, {xi_max[0], xi_max[1]}), - kernel::bc::ConductorBoundaries_kernel( + void AtmosphereFieldsIn(dir::direction_t direction, + domain_t& domain, + BCTags tags) { + /** + * atmosphere field boundaries + */ + if constexpr (traits::has_member::value) { + const auto [sign, dim, xg_min, xg_max] = get_atm_extent(direction); + const auto dd = static_cast(dim); + boundaries_t box; + boundaries_t incl_ghosts; + for (unsigned short d { 0 }; d < M::Dim; ++d) { + if (d == dd) { + box.push_back({ xg_min, xg_max }); + if (sign > 0) { + incl_ghosts.push_back({ false, true }); + } else { + incl_ghosts.push_back({ true, false }); + } + } else { + box.push_back(Range::All); + incl_ghosts.push_back({ true, true }); + } + } + if (not domain.mesh.Intersects(box)) { + return; + } + const auto intersect_range = domain.mesh.ExtentToRange(box, incl_ghosts); + tuple_t range_min { 0 }; + tuple_t range_max { 0 }; + + for (unsigned short d { 0 }; d < M::Dim; ++d) { + range_min[d] = intersect_range[d].first; + range_max[d] = intersect_range[d].second; + } + auto atm_fields = m_pgen.AtmFields(time); + std::size_t il_edge; + if (sign > 0) { + il_edge = range_min[dd] - N_GHOSTS; + } else { + il_edge = range_max[dd] - 1 - N_GHOSTS; + } + const auto range = CreateRangePolicy(range_min, range_max); + if (dim == in::x1) { + if (sign > 0) { + Kokkos::parallel_for( + "AtmosphereBCFields", + range, + kernel::bc::EnforcedBoundaries_kernel( domain.fields.em, + atm_fields, + domain.mesh.metric, + il_edge, tags)); - } - - if constexpr (M::Dim == Dim::_3D) - { - Kokkos::parallel_for( - "MatchFields", - CreateRangePolicy({xi_min[0], xi_min[1], xi_min[2]}, {xi_max[0], xi_max[1], xi_max[2]}), - kernel::bc::ConductorBoundaries_kernel( + } else { + Kokkos::parallel_for( + "AtmosphereBCFields", + range, + kernel::bc::EnforcedBoundaries_kernel( domain.fields.em, + atm_fields, + domain.mesh.metric, + il_edge, tags)); - } - - // these components need to be set to zero at the boundary - std::vector comps = {em::ex2, em::ex3, em::bx1}; - for (const auto &comp : comps) - { - if constexpr (M::Dim == Dim::_1D) - { - Kokkos::deep_copy( - Kokkos::subview(domain.fields.em, - std::make_pair(N_GHOSTS, N_GHOSTS), - comp), - ZERO); - } - else if constexpr (M::Dim == Dim::_2D) - { - Kokkos::deep_copy( - Kokkos::subview(domain.fields.em, - std::make_pair(N_GHOSTS, N_GHOSTS+1), - std::make_pair(xi_min[1], xi_max[1]), - comp), - ZERO); - } - else if constexpr (M::Dim == Dim::_3D) - { - Kokkos::deep_copy( - Kokkos::subview(domain.fields.em, - std::make_pair(N_GHOSTS, N_GHOSTS), - std::make_pair(xi_min[1], xi_max[1]), - std::make_pair(xi_min[2], xi_max[2]), - comp), - ZERO); - } - else - { + } + } else if (dim == in::x2) { + if constexpr (M::Dim == Dim::_2D or M::Dim == Dim::_3D) { + if (sign > 0) { + Kokkos::parallel_for( + "AtmosphereBCFields", + range, + kernel::bc::EnforcedBoundaries_kernel( + domain.fields.em, + atm_fields, + domain.mesh.metric, + il_edge, + tags)); + } else { + Kokkos::parallel_for( + "AtmosphereBCFields", + range, + kernel::bc::EnforcedBoundaries_kernel( + domain.fields.em, + atm_fields, + domain.mesh.metric, + il_edge, + tags)); + } + } else { + raise::Error("Invalid dimension", HERE); + } + } else if (dim == in::x3) { + if constexpr (M::Dim == Dim::_3D) { + if (sign > 0) { + Kokkos::parallel_for( + "AtmosphereBCFields", + range, + kernel::bc::EnforcedBoundaries_kernel( + domain.fields.em, + atm_fields, + domain.mesh.metric, + il_edge, + tags)); + } else { + Kokkos::parallel_for( + "AtmosphereBCFields", + range, + kernel::bc::EnforcedBoundaries_kernel( + domain.fields.em, + atm_fields, + domain.mesh.metric, + il_edge, + tags)); + } + } else { + raise::Error("Invalid dimension", HERE); + } + } else { raise::Error("Invalid dimension", HERE); } + } else { + raise::Error("Atm fields not implemented in PGEN for atmosphere BCs", HERE); } } - void AtmosphereFieldsIn(dir::direction_t direction, - domain_t & domain, - BCTags tags) - { - /** - * atmosphere field boundaries - */ - if constexpr (traits::has_member::value) - { - const auto [sign, dim, xg_min, xg_max] = get_atm_extent(direction); - const auto dd = static_cast(dim); - boundaries_t box; - boundaries_t incl_ghosts; - for (unsigned short d{0}; d < M::Dim; ++d) - { - if (d == dd) - { - box.push_back({xg_min, xg_max}); - if (sign > 0) - { - incl_ghosts.push_back({false, true}); - } - else - { - incl_ghosts.push_back({true, false}); - } - } - else - { - box.push_back(Range::All); - incl_ghosts.push_back({true, true}); - } - } - if (not domain.mesh.Intersects(box)) - { - return; - } - const auto intersect_range = domain.mesh.ExtentToRange(box, incl_ghosts); - tuple_t range_min{0}; - tuple_t range_max{0}; - - for (unsigned short d{0}; d < M::Dim; ++d) - { - range_min[d] = intersect_range[d].first; - range_max[d] = intersect_range[d].second; - } - auto atm_fields = m_pgen.AtmFields(time); - std::size_t il_edge; - if (sign > 0) - { - il_edge = range_min[dd] - N_GHOSTS; - } - else - { - il_edge = range_max[dd] - 1 - N_GHOSTS; - } - const auto range = CreateRangePolicy(range_min, range_max); - if (dim == in::x1) - { - if (sign > 0) - { - Kokkos::parallel_for( - "AtmosphereBCFields", - range, - kernel::bc::EnforcedBoundaries_kernel( - domain.fields.em, - atm_fields, - domain.mesh.metric, - il_edge, - tags)); - } - else - { - Kokkos::parallel_for( - "AtmosphereBCFields", - range, - kernel::bc::EnforcedBoundaries_kernel( - domain.fields.em, - atm_fields, - domain.mesh.metric, - il_edge, - tags)); - } - } - else if (dim == in::x2) - { - if constexpr (M::Dim == Dim::_2D or M::Dim == Dim::_3D) - { - if (sign > 0) - { - Kokkos::parallel_for( - "AtmosphereBCFields", - range, - kernel::bc::EnforcedBoundaries_kernel( - domain.fields.em, - atm_fields, - domain.mesh.metric, - il_edge, - tags)); - } - else - { - Kokkos::parallel_for( - "AtmosphereBCFields", - range, - kernel::bc::EnforcedBoundaries_kernel( - domain.fields.em, - atm_fields, - domain.mesh.metric, - il_edge, - tags)); - } - } - else - { - raise::Error("Invalid dimension", HERE); - } - } - else if (dim == in::x3) - { - if constexpr (M::Dim == Dim::_3D) - { - if (sign > 0) - { - Kokkos::parallel_for( - "AtmosphereBCFields", - range, - kernel::bc::EnforcedBoundaries_kernel( - domain.fields.em, - atm_fields, - domain.mesh.metric, - il_edge, - tags)); - } - else - { - Kokkos::parallel_for( - "AtmosphereBCFields", - range, - kernel::bc::EnforcedBoundaries_kernel( - domain.fields.em, - atm_fields, - domain.mesh.metric, - il_edge, - tags)); - } - } - else - { - raise::Error("Invalid dimension", HERE); - } - } - else - { - raise::Error("Invalid dimension", HERE); - } - } - else - { - raise::Error("Atm fields not implemented in PGEN for atmosphere BCs", HERE); - } - } + void CustomFieldsIn(dir::direction_t direction, + domain_t& domain, + BCTags tags) { + (void)direction; + (void)domain; + (void)tags; + raise::Error("Custom boundaries not implemented", HERE); + // if constexpr ( + // traits::has_member::value) { + // const auto [box, custom_fields] = m_pgen.CustomFields(time); + // if (domain.mesh.Intersects(box)) { + // } + // + // } else { + // raise::Error("Custom boundaries not implemented", HERE); + // } + } - void CustomFieldsIn(dir::direction_t direction, - domain_t & domain, - BCTags tags) - { - (void)direction; - (void)domain; - (void)tags; - raise::Error("Custom boundaries not implemented", HERE); - // if constexpr ( - // traits::has_member::value) { - // const auto [box, custom_fields] = m_pgen.CustomFields(time); - // if (domain.mesh.Intersects(box)) { - // } - // - // } else { - // raise::Error("Custom boundaries not implemented", HERE); - // } + void AtmosphereParticlesIn(const dir::direction_t& direction, + domain_t& domain, + InjTags tags) { + const auto [sign, dim, xg_min, xg_max] = get_atm_extent(direction); + + const auto x_surf = sign > 0 ? xg_min : xg_max; + const auto ds = m_params.template get( + "grid.boundaries.atmosphere.ds"); + const auto temp = m_params.template get( + "grid.boundaries.atmosphere.temperature"); + const auto height = m_params.template get( + "grid.boundaries.atmosphere.height"); + const auto species = + m_params.template get>( + "grid.boundaries.atmosphere.species"); + const auto nmax = m_params.template get( + "grid.boundaries.atmosphere.density"); + + Kokkos::deep_copy(domain.fields.bckp, ZERO); + auto scatter_bckp = Kokkos::Experimental::create_scatter_view( + domain.fields.bckp); + const auto use_weights = M::CoordType != Coord::Cart; + const auto ni2 = domain.mesh.n_active(in::x2); + const auto inv_n0 = ONE / m_params.template get("scales.n0"); + + // compute the density of the two species + if (tags & Inj::AssumeEmpty) { + if constexpr (M::Dim == Dim::_1D) { + Kokkos::deep_copy( + Kokkos::subview(domain.fields.bckp, Kokkos::ALL, std::make_pair(0, 1)), + ZERO); + } else if constexpr (M::Dim == Dim::_2D) { + Kokkos::deep_copy(Kokkos::subview(domain.fields.bckp, + Kokkos::ALL, + Kokkos::ALL, + std::make_pair(0, 1)), + ZERO); + } else if constexpr (M::Dim == Dim::_3D) { + Kokkos::deep_copy(Kokkos::subview(domain.fields.bckp, + Kokkos::ALL, + Kokkos::ALL, + Kokkos::ALL, + std::make_pair(0, 1)), + ZERO); } - - void AtmosphereParticlesIn(const dir::direction_t &direction, - domain_t &domain, - InjTags tags) - { - const auto [sign, dim, xg_min, xg_max] = get_atm_extent(direction); - - const auto x_surf = sign > 0 ? xg_min : xg_max; - const auto ds = m_params.template get( - "grid.boundaries.atmosphere.ds"); - const auto temp = m_params.template get( - "grid.boundaries.atmosphere.temperature"); - const auto height = m_params.template get( - "grid.boundaries.atmosphere.height"); - const auto species = - m_params.template get>( - "grid.boundaries.atmosphere.species"); - const auto nmax = m_params.template get( - "grid.boundaries.atmosphere.density"); - - Kokkos::deep_copy(domain.fields.bckp, ZERO); - auto scatter_bckp = Kokkos::Experimental::create_scatter_view( - domain.fields.bckp); - const auto use_weights = M::CoordType != Coord::Cart; - const auto ni2 = domain.mesh.n_active(in::x2); - const auto inv_n0 = ONE / m_params.template get("scales.n0"); - - // compute the density of the two species - if (tags & Inj::AssumeEmpty) - { - if constexpr (M::Dim == Dim::_1D) - { - Kokkos::deep_copy( - Kokkos::subview(domain.fields.bckp, Kokkos::ALL, std::make_pair(0, 1)), - ZERO); - } - else if constexpr (M::Dim == Dim::_2D) - { - Kokkos::deep_copy(Kokkos::subview(domain.fields.bckp, - Kokkos::ALL, - Kokkos::ALL, - std::make_pair(0, 1)), - ZERO); - } - else if constexpr (M::Dim == Dim::_3D) - { - Kokkos::deep_copy(Kokkos::subview(domain.fields.bckp, - Kokkos::ALL, - Kokkos::ALL, - Kokkos::ALL, - std::make_pair(0, 1)), - ZERO); - } + } else { + for (const auto& sp : + std::vector({ species.first, species.second })) { + auto& prtl_spec = domain.species[sp - 1]; + if (prtl_spec.npart() == 0) { + continue; } - else - { - for (const auto &sp : - std::vector({species.first, species.second})) - { - auto &prtl_spec = domain.species[sp - 1]; - if (prtl_spec.npart() == 0) - { - continue; - } - // clang-format off + // clang-format off Kokkos::parallel_for( "ComputeMoments", prtl_spec.rangeActiveParticles(), @@ -1199,265 +1130,230 @@ namespace ntt { use_weights, domain.mesh.metric, domain.mesh.flds_bc(), ni2, inv_n0, 0)); - // clang-format on - prtl_spec.set_unsorted(); - } - Kokkos::Experimental::contribute(domain.fields.bckp, scatter_bckp); - m_metadomain.SynchronizeFields(domain, Comm::Bckp, {0, 1}); - } + // clang-format on + prtl_spec.set_unsorted(); + } + Kokkos::Experimental::contribute(domain.fields.bckp, scatter_bckp); + m_metadomain.SynchronizeFields(domain, Comm::Bckp, { 0, 1 }); + } - if (dim == in::x1) - { - if (sign > 0) - { - const auto atm_injector = - arch::AtmosphereInjector{ - domain.mesh.metric, - domain.fields.bckp, - nmax, - height, - x_surf, - ds, - temp, - domain.random_pool, - species}; - arch::InjectNonUniform(m_params, - domain, - atm_injector, - nmax, - use_weights); - } - else - { - const auto atm_injector = - arch::AtmosphereInjector{ - domain.mesh.metric, - domain.fields.bckp, - nmax, - height, - x_surf, - ds, - temp, - domain.random_pool, - species}; - arch::InjectNonUniform(m_params, - domain, - atm_injector, - nmax, - use_weights); - } - } - else if (dim == in::x2) - { - if (sign > 0) - { - const auto atm_injector = - arch::AtmosphereInjector{ - domain.mesh.metric, - domain.fields.bckp, - nmax, - height, - x_surf, - ds, - temp, - domain.random_pool, - species}; - arch::InjectNonUniform(m_params, - domain, - atm_injector, - nmax, - use_weights); - } - else - { - const auto atm_injector = - arch::AtmosphereInjector{ - domain.mesh.metric, - domain.fields.bckp, - nmax, - height, - x_surf, - ds, - temp, - domain.random_pool, - species}; - arch::InjectNonUniform(m_params, - domain, - atm_injector, - nmax, - use_weights); - } - } - else if (dim == in::x3) - { - if (sign > 0) - { - const auto atm_injector = - arch::AtmosphereInjector{ - domain.mesh.metric, - domain.fields.bckp, - nmax, - height, - x_surf, - ds, - temp, - domain.random_pool, - species}; - arch::InjectNonUniform(m_params, - domain, - atm_injector, - nmax, - use_weights); - } - else - { - const auto atm_injector = - arch::AtmosphereInjector{ - domain.mesh.metric, - domain.fields.bckp, - nmax, - height, - x_surf, - ds, - temp, - domain.random_pool, - species}; - arch::InjectNonUniform(m_params, - domain, - atm_injector, - nmax, - use_weights); - } - } - else - { - raise::Error("Invalid dimension", HERE); - } - return; + if (dim == in::x1) { + if (sign > 0) { + const auto atm_injector = + arch::AtmosphereInjector { + domain.mesh.metric, + domain.fields.bckp, + nmax, + height, + x_surf, + ds, + temp, + domain.random_pool, + species + }; + arch::InjectNonUniform(m_params, + domain, + atm_injector, + nmax, + use_weights); + } else { + const auto atm_injector = + arch::AtmosphereInjector { + domain.mesh.metric, + domain.fields.bckp, + nmax, + height, + x_surf, + ds, + temp, + domain.random_pool, + species + }; + arch::InjectNonUniform(m_params, + domain, + atm_injector, + nmax, + use_weights); } + } else if (dim == in::x2) { + if (sign > 0) { + const auto atm_injector = + arch::AtmosphereInjector { + domain.mesh.metric, + domain.fields.bckp, + nmax, + height, + x_surf, + ds, + temp, + domain.random_pool, + species + }; + arch::InjectNonUniform(m_params, + domain, + atm_injector, + nmax, + use_weights); + } else { + const auto atm_injector = + arch::AtmosphereInjector { + domain.mesh.metric, + domain.fields.bckp, + nmax, + height, + x_surf, + ds, + temp, + domain.random_pool, + species + }; + arch::InjectNonUniform(m_params, + domain, + atm_injector, + nmax, + use_weights); + } + } else if (dim == in::x3) { + if (sign > 0) { + const auto atm_injector = + arch::AtmosphereInjector { + domain.mesh.metric, + domain.fields.bckp, + nmax, + height, + x_surf, + ds, + temp, + domain.random_pool, + species + }; + arch::InjectNonUniform(m_params, + domain, + atm_injector, + nmax, + use_weights); + } else { + const auto atm_injector = + arch::AtmosphereInjector { + domain.mesh.metric, + domain.fields.bckp, + nmax, + height, + x_surf, + ds, + temp, + domain.random_pool, + species + }; + arch::InjectNonUniform(m_params, + domain, + atm_injector, + nmax, + use_weights); + } + } else { + raise::Error("Invalid dimension", HERE); + } + return; + } - private: - /** - * @brief Get the buffer region of the atmosphere and the direction - * @param direction direction in which the atmosphere is applied - * @return tuple: [sign of the direction, the direction (as in::), the min and max extent - * @note xg_min and xg_max are the extents where the fields are set, not the atmosphere itself - * @note i.e. - * - * fields set particles injected - * ghost zone | | - * v v v - * |....|...........|*******************..... -> x1 - * ^ ^ - * xg_min xg_max - * | | | - * |<-- buffer -->|<-- atmosphere -->| - * - * in this case the function returns { -1, in::x1, xg_min, xg_max } - */ - auto get_atm_extent(dir::direction_t direction) const - -> std::tuple - { - const auto sign = direction.get_sign(); - const auto dim = direction.get_dim(); - const auto min_buff = m_params.template get( - "algorithms.current_filters") + - 2; - const auto buffer_ncells = min_buff > 5 ? min_buff : 5; - if (M::CoordType != Coord::Cart and (dim != in::x1 or sign > 0)) - { - raise::Error("For non-cartesian coordinates atmosphere BCs is " - "possible only in -x1 (@ rmin)", - HERE); - } - real_t xg_min{ZERO}, xg_max{ZERO}; - std::size_t ig_min, ig_max; - if (sign > 0) - { // + direction - ig_min = m_metadomain.mesh().n_active(dim) - buffer_ncells; - ig_max = m_metadomain.mesh().n_active(dim); - } - else - { // - direction - ig_min = 0; - ig_max = buffer_ncells; - } + private: + /** + * @brief Get the buffer region of the atmosphere and the direction + * @param direction direction in which the atmosphere is applied + * @return tuple: [sign of the direction, the direction (as in::), the min and max extent + * @note xg_min and xg_max are the extents where the fields are set, not the atmosphere itself + * @note i.e. + * + * fields set particles injected + * ghost zone | | + * v v v + * |....|...........|*******************..... -> x1 + * ^ ^ + * xg_min xg_max + * | | | + * |<-- buffer -->|<-- atmosphere -->| + * + * in this case the function returns { -1, in::x1, xg_min, xg_max } + */ + auto get_atm_extent(dir::direction_t direction) const + -> std::tuple { + const auto sign = direction.get_sign(); + const auto dim = direction.get_dim(); + const auto min_buff = m_params.template get( + "algorithms.current_filters") + + 2; + const auto buffer_ncells = min_buff > 5 ? min_buff : 5; + if (M::CoordType != Coord::Cart and (dim != in::x1 or sign > 0)) { + raise::Error("For non-cartesian coordinates atmosphere BCs is " + "possible only in -x1 (@ rmin)", + HERE); + } + real_t xg_min { ZERO }, xg_max { ZERO }; + std::size_t ig_min, ig_max; + if (sign > 0) { // + direction + ig_min = m_metadomain.mesh().n_active(dim) - buffer_ncells; + ig_max = m_metadomain.mesh().n_active(dim); + } else { // - direction + ig_min = 0; + ig_max = buffer_ncells; + } - if (dim == in::x1) - { - xg_min = m_metadomain.mesh().metric.template convert<1, Crd::Cd, Crd::Ph>( - static_cast(ig_min)); - xg_max = m_metadomain.mesh().metric.template convert<1, Crd::Cd, Crd::Ph>( - static_cast(ig_max)); - } - else if (dim == in::x2) - { - if constexpr (M::Dim == Dim::_2D or M::Dim == Dim::_3D) - { - xg_min = m_metadomain.mesh().metric.template convert<2, Crd::Cd, Crd::Ph>( - static_cast(ig_min)); - xg_max = m_metadomain.mesh().metric.template convert<2, Crd::Cd, Crd::Ph>( - static_cast(ig_max)); - } - else - { - raise::Error("Invalid dimension", HERE); - } - } - else if (dim == in::x3) - { - if constexpr (M::Dim == Dim::_3D) - { - xg_min = m_metadomain.mesh().metric.template convert<3, Crd::Cd, Crd::Ph>( - static_cast(ig_min)); - xg_max = m_metadomain.mesh().metric.template convert<3, Crd::Cd, Crd::Ph>( - static_cast(ig_max)); - } - else - { - raise::Error("Invalid dimension", HERE); - } - } - else - { - raise::Error("Invalid dimension", HERE); - } - return {sign, dim, xg_min, xg_max}; + if (dim == in::x1) { + xg_min = m_metadomain.mesh().metric.template convert<1, Crd::Cd, Crd::Ph>( + static_cast(ig_min)); + xg_max = m_metadomain.mesh().metric.template convert<1, Crd::Cd, Crd::Ph>( + static_cast(ig_max)); + } else if (dim == in::x2) { + if constexpr (M::Dim == Dim::_2D or M::Dim == Dim::_3D) { + xg_min = m_metadomain.mesh().metric.template convert<2, Crd::Cd, Crd::Ph>( + static_cast(ig_min)); + xg_max = m_metadomain.mesh().metric.template convert<2, Crd::Cd, Crd::Ph>( + static_cast(ig_max)); + } else { + raise::Error("Invalid dimension", HERE); + } + } else if (dim == in::x3) { + if constexpr (M::Dim == Dim::_3D) { + xg_min = m_metadomain.mesh().metric.template convert<3, Crd::Cd, Crd::Ph>( + static_cast(ig_min)); + xg_max = m_metadomain.mesh().metric.template convert<3, Crd::Cd, Crd::Ph>( + static_cast(ig_max)); + } else { + raise::Error("Invalid dimension", HERE); } + } else { + raise::Error("Invalid dimension", HERE); + } + return { sign, dim, xg_min, xg_max }; + } - auto range_with_axis_BCs(const domain_t &domain) -> range_t - { - auto range = domain.mesh.rangeActiveCells(); - if constexpr (M::CoordType != Coord::Cart) - { - /** - * @brief taking one extra cell in the x2 direction if AXIS BCs - */ - if constexpr (M::Dim == Dim::_2D) - { - if (domain.mesh.flds_bc_in({0, +1}) == FldsBC::AXIS) - { - range = CreateRangePolicy( - {domain.mesh.i_min(in::x1), domain.mesh.i_min(in::x2)}, - {domain.mesh.i_max(in::x1), domain.mesh.i_max(in::x2) + 1}); - } - } - else if constexpr (M::Dim == Dim::_3D) - { - if (domain.mesh.flds_bc_in({0, +1, 0}) == FldsBC::AXIS) - { - range = CreateRangePolicy({domain.mesh.i_min(in::x1), - domain.mesh.i_min(in::x2), - domain.mesh.i_min(in::x3)}, - {domain.mesh.i_max(in::x1), - domain.mesh.i_max(in::x2) + 1, - domain.mesh.i_max(in::x3)}); - } - } + auto range_with_axis_BCs(const domain_t& domain) -> range_t { + auto range = domain.mesh.rangeActiveCells(); + if constexpr (M::CoordType != Coord::Cart) { + /** + * @brief taking one extra cell in the x2 direction if AXIS BCs + */ + if constexpr (M::Dim == Dim::_2D) { + if (domain.mesh.flds_bc_in({ 0, +1 }) == FldsBC::AXIS) { + range = CreateRangePolicy( + { domain.mesh.i_min(in::x1), domain.mesh.i_min(in::x2) }, + { domain.mesh.i_max(in::x1), domain.mesh.i_max(in::x2) + 1 }); + } + } else if constexpr (M::Dim == Dim::_3D) { + if (domain.mesh.flds_bc_in({ 0, +1, 0 }) == FldsBC::AXIS) { + range = CreateRangePolicy({ domain.mesh.i_min(in::x1), + domain.mesh.i_min(in::x2), + domain.mesh.i_min(in::x3) }, + { domain.mesh.i_max(in::x1), + domain.mesh.i_max(in::x2) + 1, + domain.mesh.i_max(in::x3) }); } - return range; } - }; + } + return range; + } + }; } // namespace ntt diff --git a/src/global/enums.h b/src/global/enums.h index 2b3bf5936..32ef17157 100644 --- a/src/global/enums.h +++ b/src/global/enums.h @@ -9,7 +9,7 @@ * - enum ntt::PrtlBC // periodic, absorb, atmosphere, custom, * reflect, horizon, axis, sync * - enum ntt::FldsBC // periodic, match, fixed, atmosphere, - * custom, horizon, axis, sync + * custom, horizon, axis, conductor, sync * - enum ntt::PrtlPusher // boris, vay, photon, none * - enum ntt::Cooling // synchrotron, none * - enum ntt::FldsID // e, dive, d, divd, b, h, j, @@ -221,17 +221,20 @@ namespace ntt { CUSTOM = 5, HORIZON = 6, AXIS = 7, - SYNC = 8, // <- SYNC means synchronization with other domains - CONDUCTOR = 9 + CONDUCTOR = 8, + SYNC = 9 // <- SYNC means synchronization with other domains }; constexpr FldsBC(uint8_t c) : enums_hidden::BaseEnum { c } {} - static constexpr type variants[] = { PERIODIC, MATCH, FIXED, ATMOSPHERE, - CUSTOM, HORIZON, AXIS, SYNC, CONDUCTOR }; - static constexpr const char* lookup[] = { "periodic", "match", "fixed", - "atmosphere", "custom", "horizon", - "axis", "sync", "conductor"}; + static constexpr type variants[] = { + PERIODIC, MATCH, FIXED, ATMOSPHERE, CUSTOM, + HORIZON, AXIS, CONDUCTOR, SYNC, + }; + static constexpr const char* lookup[] = { + "periodic", "match", "fixed", "atmosphere", "custom", + "horizon", "axis", "conductor", "sync" + }; static constexpr std::size_t total = sizeof(variants) / sizeof(variants[0]); }; diff --git a/src/global/tests/enums.cpp b/src/global/tests/enums.cpp index 7785ec1a3..b26a2050f 100644 --- a/src/global/tests/enums.cpp +++ b/src/global/tests/enums.cpp @@ -61,8 +61,9 @@ auto main() -> int { enum_str_t all_simulation_engines = { "srpic", "grpic" }; enum_str_t all_particle_bcs = { "periodic", "absorb", "atmosphere", "custom", "reflect", "horizon", "axis", "sync" }; - enum_str_t all_fields_bcs = { "periodic", "match", "fixed", "atmosphere", - "custom", "horizon", "axis", "sync" }; + enum_str_t all_fields_bcs = { "periodic", "match", "fixed", + "atmosphere", "custom", "horizon", + "axis", "conductor", "sync" }; enum_str_t all_particle_pushers = { "boris", "vay", "photon", "none" }; enum_str_t all_coolings = { "synchrotron", "none" }; diff --git a/src/kernels/fields_bcs.hpp b/src/kernels/fields_bcs.hpp index 720408d05..9d8e9c74e 100644 --- a/src/kernels/fields_bcs.hpp +++ b/src/kernels/fields_bcs.hpp @@ -5,6 +5,7 @@ * - kernel::bc::MatchBoundaries_kernel<> * - kernel::bc::AxisBoundaries_kernel<> * - kernel::bc::EnforcedBoundaries_kernel<> + * - kernel::bc::ConductorBoundaries_kernel<> * @namespaces: * - kernel::bc:: */ @@ -485,43 +486,40 @@ namespace kernel::bc { } }; - template + template struct ConductorBoundaries_kernel { - static_assert(M::is_metric, "M must be a metric class"); - static_assert(static_cast(o) < - static_cast(M::Dim), + static_assert(static_cast(o) < static_cast(D), "Invalid component index"); - static constexpr idx_t i = static_cast(o) + 1u; + // static constexpr idx_t i = static_cast(o) + 1u; - ndfield_t Fld; - const BCTags tags; + ndfield_t Fld; + const BCTags tags; - ConductorBoundaries_kernel(ndfield_t Fld, - BCTags tags) + ConductorBoundaries_kernel(ndfield_t Fld, BCTags tags) : Fld { Fld } , tags { tags } {} Inline void operator()(index_t i1) const { - if constexpr (M::Dim == Dim::_1D) { - - if constexpr (S == SimEngine::SRPIC) { - + if constexpr (D == Dim::_1D) { if (tags & BC::E) { - Fld((N_GHOSTS-1)-i1, em::ex1) = Fld(N_GHOSTS+i1, em::ex1); - Fld((N_GHOSTS-1)-i1, em::ex2) = -Fld(N_GHOSTS+i1+1, em::ex2); - Fld((N_GHOSTS-1)-i1, em::ex3) = -Fld(N_GHOSTS+i1+1, em::ex3); - } - - if (tags & BC::B) - { - Fld((N_GHOSTS-1)-i1, em::bx1) = -Fld(N_GHOSTS+i1+1, em::bx1); - Fld((N_GHOSTS-1)-i1, em::bx1) = Fld(N_GHOSTS+i1, em::bx1); - Fld((N_GHOSTS-1)-i1, em::bx1) = Fld(N_GHOSTS+i1, em::bx1); + if (i1 == 0) { + Fld(N_GHOSTS, em::ex2) = ZERO; + Fld(N_GHOSTS, em::ex3) = ZERO; + } else { + Fld(N_GHOSTS - i1, em::ex1) = Fld(N_GHOSTS + i1 - 1, em::ex1); + Fld(N_GHOSTS - i1, em::ex2) = -Fld(N_GHOSTS + i1, em::ex2); + Fld(N_GHOSTS - i1, em::ex3) = -Fld(N_GHOSTS + i1, em::ex3); + } } - } else { - // GRPIC - raise::KernelError(HERE, "1D GRPIC not implemented"); + if (tags & BC::B) { + if (i1 == 0) { + Fld(N_GHOSTS, em::bx1) = ZERO; + } else { + Fld(N_GHOSTS - i1, em::bx1) = -Fld(N_GHOSTS + i1, em::bx1); + Fld(N_GHOSTS - i1, em::bx2) = Fld(N_GHOSTS + i1 - 1, em::bx2); + Fld(N_GHOSTS - i1, em::bx3) = Fld(N_GHOSTS + i1 - 1, em::bx3); + } } } else { raise::KernelError( @@ -530,75 +528,70 @@ namespace kernel::bc { } } - Inline void operator()(index_t i1, index_t i2) const - { - if constexpr (M::Dim == Dim::_2D) - { - - if constexpr (S == SimEngine::SRPIC) - { - // SRPIC - if (tags & BC::E) - { - Fld((N_GHOSTS - 1) - i1, i2, em::ex1) = Fld(N_GHOSTS + i1, i2, em::ex1); - Fld((N_GHOSTS - 1) - i1, i2, em::ex2) = -Fld(N_GHOSTS + 1 + i1, i2, em::ex2); - Fld((N_GHOSTS - 1) - i1, i2, em::ex3) = -Fld(N_GHOSTS + 1 + i1, i2, em::ex3); + Inline void operator()(index_t i1, index_t i2) const { + if constexpr (D == Dim::_2D) { + if (tags & BC::E) { + if (i1 == 0) { + Fld(N_GHOSTS, i2, em::ex2) = ZERO; + Fld(N_GHOSTS, i2, em::ex3) = ZERO; + } else { + Fld(N_GHOSTS - i1, i2, em::ex1) = Fld(N_GHOSTS + i1 - 1, i2, em::ex1); + Fld(N_GHOSTS - i1, i2, em::ex2) = -Fld(N_GHOSTS + i1, i2, em::ex2); + Fld(N_GHOSTS - i1, i2, em::ex3) = -Fld(N_GHOSTS + i1, i2, em::ex3); } + } - if (tags & BC::B) - { - Fld((N_GHOSTS - 1) - i1, i2, em::bx1) = -Fld(N_GHOSTS + 1 + i1, i2, em::bx1); - Fld((N_GHOSTS - 1) - i1, i2, em::bx2) = Fld(N_GHOSTS + i1, i2, em::bx2); - Fld((N_GHOSTS - 1) - i1, i2, em::bx3) = Fld(N_GHOSTS + i1, i2, em::bx3); + if (tags & BC::B) { + if (i1 == 0) { + Fld(N_GHOSTS, i2, em::bx1) = ZERO; + } else { + Fld(N_GHOSTS - i1, i2, em::bx1) = -Fld(N_GHOSTS + i1, i2, em::bx1); + Fld(N_GHOSTS - i1, i2, em::bx2) = Fld(N_GHOSTS + i1 - 1, i2, em::bx2); + Fld(N_GHOSTS - i1, i2, em::bx3) = Fld(N_GHOSTS + i1 - 1, i2, em::bx3); } } - else - { - // GRPIC - raise::KernelError(HERE, "2D GRPIC not implemented"); - } - } - else - { + } else { raise::KernelError( - HERE, - "ConductorBoundaries_kernel: 2D implementation called for D != 2"); + HERE, + "ConductorBoundaries_kernel: 2D implementation called for D != 2"); } } - Inline void operator()(index_t i1, index_t i2, index_t i3) const - { - if constexpr (M::Dim == Dim::_3D) - { - - if constexpr (S == SimEngine::SRPIC) - { - // SRPIC - if (tags & BC::E) - { - Fld((N_GHOSTS - 1) - i1, i2, i3, em::ex1) = Fld(N_GHOSTS + i1, i2, i3, em::ex1); - Fld((N_GHOSTS - 1) - i1, i2, i3, em::ex2) = -Fld(N_GHOSTS + i1 + 1, i2, i3, em::ex2); - Fld((N_GHOSTS - 1) - i1, i2, i3, em::ex3) = -Fld(N_GHOSTS + i1 + 1, i2, i3, em::ex3); + Inline void operator()(index_t i1, index_t i2, index_t i3) const { + if constexpr (D == Dim::_3D) { + if (tags & BC::E) { + if (i1 == 0) { + Fld(N_GHOSTS, i2, i3, em::ex2) = ZERO; + Fld(N_GHOSTS, i2, i3, em::ex3) = ZERO; + } else { + Fld(N_GHOSTS - i1, i2, i3, em::ex1) = Fld(N_GHOSTS + i1 - 1, + i2, + i3, + em::ex1); + Fld(N_GHOSTS - i1, i2, i3, em::ex2) = -Fld(N_GHOSTS + i1, i2, i3, em::ex2); + Fld(N_GHOSTS - i1, i2, i3, em::ex3) = -Fld(N_GHOSTS + i1, i2, i3, em::ex3); } + } - if (tags & BC::B) - { - Fld((N_GHOSTS - 1) - i1, i2, i3, em::bx1) = -Fld(N_GHOSTS + i1 + 1, i2, i3, em::bx1); - Fld((N_GHOSTS - 1) - i1, i2, i3, em::bx2) = Fld(N_GHOSTS + i1, i2, i3, em::bx2); - Fld((N_GHOSTS - 1) - i1, i2, i3, em::bx3) = Fld(N_GHOSTS + i1, i2, i3, em::bx3); + if (tags & BC::B) { + if (i1 == 0) { + Fld(N_GHOSTS, i2, i3, em::bx1) = ZERO; + } else { + Fld(N_GHOSTS - i1, i2, i3, em::bx1) = -Fld(N_GHOSTS + i1, i2, i3, em::bx1); + Fld(N_GHOSTS - i1, i2, i3, em::bx2) = Fld(N_GHOSTS + i1 - 1, + i2, + i3, + em::bx2); + Fld(N_GHOSTS - i1, i2, i3, em::bx3) = Fld(N_GHOSTS + i1 - 1, + i2, + i3, + em::bx3); } } - else - { - // GRPIC - raise::KernelError(HERE, "3D GRPIC not implemented"); - } - } - else - { + } else { raise::KernelError( - HERE, - "ConductorBoundaries_kernel: 3D implementation called for D != 3"); + HERE, + "ConductorBoundaries_kernel: 3D implementation called for D != 3"); } } }; From 28a02f13191464de82b09fc6959390a08511e71f Mon Sep 17 00:00:00 2001 From: hayk Date: Fri, 7 Mar 2025 12:11:31 -0500 Subject: [PATCH 428/773] filters adapted for conducting BCs --- src/kernels/digital_filter.hpp | 132 +++++++++++++++++++++------------ 1 file changed, 86 insertions(+), 46 deletions(-) diff --git a/src/kernels/digital_filter.hpp b/src/kernels/digital_filter.hpp index 5d05fad2d..6a4599d35 100644 --- a/src/kernels/digital_filter.hpp +++ b/src/kernels/digital_filter.hpp @@ -17,9 +17,13 @@ #include "utils/error.h" #include "utils/numeric.h" -#define FILTER_IN_I1(ARR, COMP, I, J) \ +#define FILTER2D_IN_I1(ARR, COMP, I, J) \ INV_2*(ARR)((I), (J), (COMP)) + \ - INV_4*((ARR)((I)-1, (J), (COMP)) + (ARR)((I) + 1, (J), (COMP))) + INV_4*((ARR)((I) - 1, (J), (COMP)) + (ARR)((I) + 1, (J), (COMP))) + +#define FILTER2D_IN_I2(ARR, COMP, I, J) \ + INV_2*(ARR)((I), (J), (COMP)) + \ + INV_4*((ARR)((I), (J) - 1, (COMP)) + (ARR)((I), (J) + 1, (COMP))) namespace kernel { using namespace ntt; @@ -28,8 +32,9 @@ namespace kernel { class DigitalFilter_kernel { ndfield_t array; const ndfield_t buffer; - bool is_axis_i2min { false }, is_axis_i2max { false }; - static constexpr auto i2_min = N_GHOSTS; + const bool is_axis_i2min, is_axis_i2max; + const bool is_conductor_i1min; + static constexpr auto i1_min = N_GHOSTS, i2_min = N_GHOSTS; const std::size_t i2_max; public: @@ -39,20 +44,31 @@ namespace kernel { const boundaries_t& boundaries) : array { array } , buffer { buffer } - , i2_max { (short)D > 1 ? size_[1] + N_GHOSTS : 0 } { - if constexpr ((C != Coord::Cart) && (D != Dim::_1D)) { - raise::ErrorIf(boundaries.size() < 2, "boundaries defined incorrectly", HERE); - is_axis_i2min = (boundaries[1].first == FldsBC::AXIS); - is_axis_i2max = (boundaries[1].second == FldsBC::AXIS); - } - } + , is_axis_i2min { (D == Dim::_2D) and (boundaries[1].first == FldsBC::AXIS) } + , is_axis_i2max { (D == Dim::_2D) and (boundaries[1].second == FldsBC::AXIS) } + , is_conductor_i1min { boundaries[0].first == FldsBC::CONDUCTOR } + , i2_max { (short)D > 1 ? size_[1] + N_GHOSTS : 0 } {} Inline void operator()(index_t i1) const { if constexpr ((D == Dim::_1D) && (C == Coord::Cart)) { + if (is_conductor_i1min and i1 == i1_min) { + array(i1, cur::jx1) = (THREE * INV_4) * buffer(i1, cur::jx1) + + (INV_4)*buffer(i1 + 1, cur::jx1); + } else if (is_conductor_i1min and i1 == i1_min + 1) { + array(i1, cur::jx1) = INV_2 * buffer(i1, cur::jx1) + + INV_4 * (buffer(i1 - 1, cur::jx1) + + buffer(i1 + 1, cur::jx1)); + array(i1, cur::jx2) = (INV_2)*buffer(i1, cur::jx2) + + (INV_4)*buffer(i1 + 1, cur::jx2); + array(i1, cur::jx3) = (INV_2)*buffer(i1, cur::jx3) + + (INV_4)*buffer(i1 + 1, cur::jx3); + } else { #pragma unroll - for (const auto& comp : { cur::jx1, cur::jx2, cur::jx3 }) { - array(i1, comp) = INV_2 * buffer(i1, comp) + - INV_4 * (buffer(i1 - 1, comp) + buffer(i1 + 1, comp)); + for (const auto& comp : { cur::jx1, cur::jx2, cur::jx3 }) { + array(i1, comp) = INV_2 * buffer(i1, comp) + + INV_4 * + (buffer(i1 - 1, comp) + buffer(i1 + 1, comp)); + } } } else { raise::KernelError(HERE, "DigitalFilter_kernel: 1D implementation called for D != 1 or for non-Cartesian metric"); @@ -62,25 +78,49 @@ namespace kernel { Inline void operator()(index_t i1, index_t i2) const { if constexpr (D == Dim::_2D) { if constexpr (C == Coord::Cart) { + if (is_conductor_i1min and i1 == i1_min) { + array(i1, i2, cur::jx1) = + (THREE * INV_4) * (FILTER2D_IN_I2(buffer, cur::jx1, i1, i2)) + + (INV_4) * (FILTER2D_IN_I2(buffer, cur::jx1, i1 + 1, i2)); + } else if (is_conductor_i1min and i1 == i1_min + 1) { + array(i1, + i2, + cur::jx1) = INV_2 * (FILTER2D_IN_I2(buffer, cur::jx1, i1, i2)) + + INV_4 * + ((FILTER2D_IN_I2(buffer, cur::jx1, i1 - 1, i2)) + + (FILTER2D_IN_I2(buffer, cur::jx1, i1 + 1, i2))); + array(i1, + i2, + cur::jx2) = INV_2 * (FILTER2D_IN_I2(buffer, cur::jx2, i1, i2)) + + INV_4 * + (FILTER2D_IN_I2(buffer, cur::jx2, i1 + 1, i2)); + array(i1, + i2, + cur::jx3) = INV_2 * (FILTER2D_IN_I2(buffer, cur::jx3, i1, i2)) + + INV_4 * + (FILTER2D_IN_I2(buffer, cur::jx3, i1 + 1, i2)); + } else { #pragma unroll - for (const auto comp : { cur::jx1, cur::jx2, cur::jx3 }) { - array(i1, i2, comp) = INV_4 * buffer(i1, i2, comp) + - INV_8 * (buffer(i1 - 1, i2, comp) + - buffer(i1 + 1, i2, comp) + - buffer(i1, i2 - 1, comp) + - buffer(i1, i2 + 1, comp)) + - INV_16 * (buffer(i1 - 1, i2 - 1, comp) + - buffer(i1 + 1, i2 + 1, comp) + - buffer(i1 - 1, i2 + 1, comp) + - buffer(i1 + 1, i2 - 1, comp)); + for (const auto comp : { cur::jx1, cur::jx2, cur::jx3 }) { + array(i1, i2, comp) = INV_4 * buffer(i1, i2, comp) + + INV_8 * (buffer(i1 - 1, i2, comp) + + buffer(i1 + 1, i2, comp) + + buffer(i1, i2 - 1, comp) + + buffer(i1, i2 + 1, comp)) + + INV_16 * (buffer(i1 - 1, i2 - 1, comp) + + buffer(i1 + 1, i2 + 1, comp) + + buffer(i1 - 1, i2 + 1, comp) + + buffer(i1 + 1, i2 - 1, comp)); + } } } else { // spherical + // @TODO: get rid of temporary variables real_t cur_00, cur_0p1, cur_0m1; if (is_axis_i2min && (i2 == i2_min)) { /* --------------------------------- r, phi --------------------------------- */ // ... filter in r - cur_00 = FILTER_IN_I1(buffer, cur::jx1, i1, i2); - cur_0p1 = FILTER_IN_I1(buffer, cur::jx1, i1, i2 + 1); + cur_00 = FILTER2D_IN_I1(buffer, cur::jx1, i1, i2); + cur_0p1 = FILTER2D_IN_I1(buffer, cur::jx1, i1, i2 + 1); // ... filter in theta array(i1, i2, cur::jx1) = INV_2 * cur_00 + INV_2 * cur_0p1; @@ -88,58 +128,58 @@ namespace kernel { /* ---------------------------------- theta --------------------------------- */ // ... filter in r - cur_00 = FILTER_IN_I1(buffer, cur::jx2, i1, i2); - cur_0p1 = FILTER_IN_I1(buffer, cur::jx2, i1, i2 + 1); + cur_00 = FILTER2D_IN_I1(buffer, cur::jx2, i1, i2); + cur_0p1 = FILTER2D_IN_I1(buffer, cur::jx2, i1, i2 + 1); // ... filter in theta array(i1, i2, cur::jx2) = INV_4 * (cur_00 + cur_0p1); } else if (is_axis_i2min && (i2 == i2_min + 1)) { /* --------------------------------- r, phi --------------------------------- */ // ... filter in r - cur_00 = FILTER_IN_I1(buffer, cur::jx1, i1, i2); - cur_0p1 = FILTER_IN_I1(buffer, cur::jx1, i1, i2 + 1); - cur_0m1 = FILTER_IN_I1(buffer, cur::jx1, i1, i2 - 1); + cur_00 = FILTER2D_IN_I1(buffer, cur::jx1, i1, i2); + cur_0p1 = FILTER2D_IN_I1(buffer, cur::jx1, i1, i2 + 1); + cur_0m1 = FILTER2D_IN_I1(buffer, cur::jx1, i1, i2 - 1); // ... filter in theta array(i1, i2, cur::jx1) = INV_2 * cur_00 + INV_4 * (cur_0p1 + cur_0m1); // ... filter in r - cur_00 = FILTER_IN_I1(buffer, cur::jx3, i1, i2); - cur_0p1 = FILTER_IN_I1(buffer, cur::jx3, i1, i2 + 1); + cur_00 = FILTER2D_IN_I1(buffer, cur::jx3, i1, i2); + cur_0p1 = FILTER2D_IN_I1(buffer, cur::jx3, i1, i2 + 1); // ... filter in theta array(i1, i2, cur::jx3) = INV_2 * cur_00 + INV_4 * cur_0p1; /* ---------------------------------- theta --------------------------------- */ // ... filter in r - cur_00 = FILTER_IN_I1(buffer, cur::jx2, i1, i2); - cur_0p1 = FILTER_IN_I1(buffer, cur::jx2, i1, i2 + 1); - cur_0m1 = FILTER_IN_I1(buffer, cur::jx2, i1, i2 - 1); + cur_00 = FILTER2D_IN_I1(buffer, cur::jx2, i1, i2); + cur_0p1 = FILTER2D_IN_I1(buffer, cur::jx2, i1, i2 + 1); + cur_0m1 = FILTER2D_IN_I1(buffer, cur::jx2, i1, i2 - 1); // ... filter in theta array(i1, i2, cur::jx2) = INV_2 * cur_00 + INV_4 * (cur_0m1 + cur_0p1); } else if (is_axis_i2max && (i2 == i2_max - 1)) { /* --------------------------------- r, phi --------------------------------- */ // ... filter in r - cur_00 = FILTER_IN_I1(buffer, cur::jx1, i1, i2); - cur_0p1 = FILTER_IN_I1(buffer, cur::jx1, i1, i2 + 1); - cur_0m1 = FILTER_IN_I1(buffer, cur::jx1, i1, i2 - 1); + cur_00 = FILTER2D_IN_I1(buffer, cur::jx1, i1, i2); + cur_0p1 = FILTER2D_IN_I1(buffer, cur::jx1, i1, i2 + 1); + cur_0m1 = FILTER2D_IN_I1(buffer, cur::jx1, i1, i2 - 1); // ... filter in theta array(i1, i2, cur::jx1) = INV_2 * cur_00 + INV_4 * (cur_0m1 + cur_0p1); // ... filter in r - cur_00 = FILTER_IN_I1(buffer, cur::jx3, i1, i2); - cur_0m1 = FILTER_IN_I1(buffer, cur::jx3, i1, i2 - 1); + cur_00 = FILTER2D_IN_I1(buffer, cur::jx3, i1, i2); + cur_0m1 = FILTER2D_IN_I1(buffer, cur::jx3, i1, i2 - 1); // ... filter in theta array(i1, i2, cur::jx3) = INV_2 * cur_00 + INV_4 * cur_0m1; /* ---------------------------------- theta --------------------------------- */ // ... filter in r - cur_00 = FILTER_IN_I1(buffer, cur::jx2, i1, i2); - cur_0m1 = FILTER_IN_I1(buffer, cur::jx2, i1, i2 - 1); + cur_00 = FILTER2D_IN_I1(buffer, cur::jx2, i1, i2); + cur_0m1 = FILTER2D_IN_I1(buffer, cur::jx2, i1, i2 - 1); // ... filter in theta array(i1, i2, cur::jx2) = INV_4 * (cur_00 + cur_0m1); } else if (is_axis_i2max && (i2 == i2_max)) { /* --------------------------------- r, phi --------------------------------- */ // ... filter in r - cur_00 = FILTER_IN_I1(buffer, cur::jx1, i1, i2); - cur_0m1 = FILTER_IN_I1(buffer, cur::jx1, i1, i2 - 1); + cur_00 = FILTER2D_IN_I1(buffer, cur::jx1, i1, i2); + cur_0m1 = FILTER2D_IN_I1(buffer, cur::jx1, i1, i2 - 1); // ... filter in theta array(i1, i2, cur::jx1) = INV_2 * cur_00 + INV_2 * cur_0m1; @@ -210,6 +250,6 @@ namespace kernel { } // namespace kernel -#undef FILTER_IN_I1 +#undef FILTER2D_IN_I1 #endif // DIGITAL_FILTER_HPP From b800b615ef1e0c1388ae629856a7e5a86e9531ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20B=C3=B6ss?= Date: Fri, 7 Mar 2025 20:26:49 -0600 Subject: [PATCH 429/773] revert to old pgen for testing --- setups/srpic/shocktest/pgen.hpp | 171 +++++++++++++++++++++++--------- 1 file changed, 125 insertions(+), 46 deletions(-) diff --git a/setups/srpic/shocktest/pgen.hpp b/setups/srpic/shocktest/pgen.hpp index 4f6decc76..ff54923d1 100644 --- a/setups/srpic/shocktest/pgen.hpp +++ b/setups/srpic/shocktest/pgen.hpp @@ -38,20 +38,15 @@ namespace user { // magnetic field components Inline auto bx1(const coord_t& x_ph) const -> real_t { - // return Bmag * math::cos(Btheta); - return ZERO; + return Bmag * math::cos(Btheta); } Inline auto bx2(const coord_t& x_ph) const -> real_t { - // return Bmag * math::sin(Btheta) * math::sin(Bphi); - return ZERO; + return Bmag * math::sin(Btheta) * math::sin(Bphi); } Inline auto bx3(const coord_t& x_ph) const -> real_t { - // return Bmag * math::sin(Btheta) * math::cos(Bphi); - // return ONE + 0.01 * (ONE - math::tanh(20.*(-1.5 + x_ph[0]))*math::tanh(20.*(-0.5 - // + x_ph[0])))/2.0 * math::sin(4.0 * constant::PI * x_ph[0]); - return ZERO; + return Bmag * math::sin(Btheta) * math::cos(Bphi); } // electric field components @@ -60,15 +55,11 @@ namespace user { } Inline auto ex2(const coord_t& x_ph) const -> real_t { - // return -Vx * Bmag * math::sin(Btheta) * math::cos(Bphi); - // return ZERO - 0.01 * (ONE - math::tanh(20.*(-1.5 + x_ph[0]))*math::tanh(20.*(-0.5 - // + x_ph[0])))/2.0 * math::sin(4.0 * constant::PI * x_ph[0]); - return ZERO; + return -Vx * Bmag * math::sin(Btheta) * math::cos(Bphi); } Inline auto ex3(const coord_t& x_ph) const -> real_t { - // return Vx * Bmag * math::sin(Btheta) * math::sin(Bphi); - return ZERO; + return Vx * Bmag * math::sin(Btheta) * math::sin(Bphi); } private: @@ -102,16 +93,16 @@ namespace user { : arch::ProblemGenerator { p } , drift_ux { p.template get("setup.drift_ux") } , temperature { p.template get("setup.temperature") } - , x1arr_e { p.template get>("setup.x_e") } - , x2arr_e { p.template get>("setup.y_e") } - , ux1arr_e { p.template get>("setup.ux_e") } - , ux2arr_e { p.template get>("setup.uy_e") } - , ux3arr_e { p.template get>("setup.uz_e") } - , x1arr_i { p.template get>("setup.x_i") } - , x2arr_i { p.template get>("setup.y_i") } - , ux1arr_i { p.template get>("setup.ux_i") } - , ux2arr_i { p.template get>("setup.uy_i") } - , ux3arr_i { p.template get>("setup.uz_i") } + // , x1arr_e { p.template get>("setup.x_e") } + // , x2arr_e { p.template get>("setup.y_e") } + // , ux1arr_e { p.template get>("setup.ux_e") } + // , ux2arr_e { p.template get>("setup.uy_e") } + // , ux3arr_e { p.template get>("setup.uz_e") } + // , x1arr_i { p.template get>("setup.x_i") } + // , x2arr_i { p.template get>("setup.y_i") } + // , ux1arr_i { p.template get>("setup.ux_i") } + // , ux2arr_i { p.template get>("setup.uy_i") } + // , ux3arr_i { p.template get>("setup.uz_i") } , Btheta { p.template get("setup.Btheta", ZERO) } , Bmag { p.template get("setup.Bmag", ZERO) } , Bphi { p.template get("setup.Bphi", ZERO) } @@ -135,28 +126,116 @@ namespace user { return init_flds; } - inline void InitPrtls(Domain& domain) { - arch::InjectGlobally(*metadomain, - domain, - 1, - { - { "x1", x1arr_e }, - { "x2", x2arr_e }, - { "ux1", ux1arr_e }, - { "ux2", ux1arr_e }, - { "ux3", ux3arr_e } - }); - arch::InjectGlobally(*metadomain, - domain, - 2, - { - { "x1", x1arr_i }, - { "x2", x2arr_i }, - { "ux1", ux1arr_i }, - { "ux2", ux1arr_i }, - { "ux3", ux3arr_i } - }); - } + // inline void InitPrtls(Domain& domain) { + // arch::InjectGlobally(*metadomain, + // domain, + // 1, + // { + // { "x1", x1arr_e }, + // { "x2", x2arr_e }, + // { "ux1", ux1arr_e }, + // { "ux2", ux1arr_e }, + // { "ux3", ux3arr_e } + // }); + // arch::InjectGlobally(*metadomain, + // domain, + // 2, + // { + // { "x1", x1arr_i }, + // { "x2", x2arr_i }, + // { "ux1", ux1arr_i }, + // { "ux2", ux1arr_i }, + // { "ux3", ux3arr_i } + // }); + // } + + inline void InitPrtls(Domain& domain) { + + // auto& species_e = domain.species[0]; + // auto& species_p = domain.species[1]; + auto& species_e = domain.species[0]; + auto& species_p = domain.species[1]; + + // array_t elec_ind("elec_ind"); + // array_t pos_ind("pos_ind"); + array_t elec_ind("elec_ind"); + array_t pos_ind("pos_ind"); + + auto offset_e = species_e.npart(); + auto offset_p = species_p.npart(); + + auto ux1_e = species_e.ux1; + auto ux2_e = species_e.ux2; + auto ux3_e = species_e.ux3; + auto i1_e = species_e.i1; + auto i2_e = species_e.i2; + auto dx1_e = species_e.dx1; + auto dx2_e = species_e.dx2; + auto phi_e = species_e.phi; + auto weight_e = species_e.weight; + auto tag_e = species_e.tag; + + auto ux1_p = species_p.ux1; + auto ux2_p = species_p.ux2; + auto ux3_p = species_p.ux3; + auto i1_p = species_p.i1; + auto i2_p = species_p.i2; + auto dx1_p = species_p.dx1; + auto dx2_p = species_p.dx2; + auto phi_p = species_p.phi; + auto weight_p = species_p.weight; + auto tag_p = species_p.tag; + + int nseed = 1; + + Kokkos::parallel_for("init_particles", nseed, KOKKOS_LAMBDA(const int& s) { + + // ToDo: fix this + auto i1_ = math::floor(10); + auto i2_ = math::floor(64); + auto dx1_ = HALF; + auto dx2_ = HALF; + + + auto elec_p = Kokkos::atomic_fetch_add(&elec_ind(), 1); + auto pos_p = Kokkos::atomic_fetch_add(&pos_ind(), 1); + + i1_e(elec_p + offset_e) = i1_; + dx1_e(elec_p + offset_e) = dx1_; + i2_e(elec_p + offset_e) = i2_; + dx2_e(elec_p + offset_e) = 2*dx2_; + // ux1_e(elec_p + offset_e) = -0.5; + // ux2_e(elec_p + offset_e) = 0.5; + ux1_e(elec_p + offset_e) = -drift_ux; + ux2_e(elec_p + offset_e) = ZERO; + ux3_e(elec_p + offset_e) = ZERO; + weight_e(elec_p + offset_e) = ONE; + tag_e(elec_p + offset_e) = ParticleTag::alive; + + i1_p(pos_p + offset_p) = i1_; + dx1_p(pos_p + offset_p) = dx1_; + i2_p(pos_p + offset_p) = i2_; + dx2_p(pos_p + offset_p) = -2*dx2_; + // ux1_p(pos_p + offset_p) = 0.5; + // ux2_p(pos_p + offset_p) = -0.5; + ux1_p(pos_p + offset_p) = -drift_ux; + ux2_p(pos_p + offset_p) = ZERO; + ux3_p(pos_p + offset_p) = ZERO; + weight_p(pos_p + offset_p) = ONE; + tag_p(pos_p + offset_p) = ParticleTag::alive; + + + }); + + + auto elec_ind_h = Kokkos::create_mirror(elec_ind); + Kokkos::deep_copy(elec_ind_h, elec_ind); + species_e.set_npart(offset_e + elec_ind_h()); + + auto pos_ind_h = Kokkos::create_mirror(pos_ind); + Kokkos::deep_copy(pos_ind_h, pos_ind); + species_p.set_npart(offset_p + pos_ind_h()); + } }; } // namespace user From 2b269f399782c7fab69c67ee589e4b274f9265f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20B=C3=B6ss?= Date: Fri, 7 Mar 2025 21:26:16 -0600 Subject: [PATCH 430/773] enforce B0/E0 at boundary --- src/engines/srpic.hpp | 8 +++++--- src/kernels/fields_bcs.hpp | 33 +++++++++++++++++++++------------ 2 files changed, 26 insertions(+), 15 deletions(-) diff --git a/src/engines/srpic.hpp b/src/engines/srpic.hpp index dd2f5ccec..891336309 100644 --- a/src/engines/srpic.hpp +++ b/src/engines/srpic.hpp @@ -889,11 +889,13 @@ namespace ntt { } else { raise::Error("Invalid dimension", HERE); } + + auto match_fields = m_pgen.MatchFields(time); Kokkos::parallel_for( - "MatchFields", + "ConductorFields", range, - kernel::bc::ConductorBoundaries_kernel(domain.fields.em, - tags)); + kernel::bc::ConductorBoundaries_kernel(domain.fields.em, + match_fields, tags)); // if constexpr (M::Dim == Dim::_1D) { // Kokkos::parallel_for( diff --git a/src/kernels/fields_bcs.hpp b/src/kernels/fields_bcs.hpp index 9d8e9c74e..4d6be9380 100644 --- a/src/kernels/fields_bcs.hpp +++ b/src/kernels/fields_bcs.hpp @@ -486,25 +486,32 @@ namespace kernel::bc { } }; - template + template struct ConductorBoundaries_kernel { static_assert(static_cast(o) < static_cast(D), "Invalid component index"); - // static constexpr idx_t i = static_cast(o) + 1u; + static constexpr bool defines_ex2 = traits::has_method::value; + static constexpr bool defines_ex3 = traits::has_method::value; + static constexpr bool defines_bx1 = traits::has_method::value; + static_assert(( defines_ex2 or defines_ex3 or defines_bx1), + "none of the components of E or B are specified in PGEN"); ndfield_t Fld; + const I fset; const BCTags tags; - ConductorBoundaries_kernel(ndfield_t Fld, BCTags tags) + ConductorBoundaries_kernel(ndfield_t Fld, const I& fset, BCTags tags) : Fld { Fld } + , fset { fset } , tags { tags } {} Inline void operator()(index_t i1) const { if constexpr (D == Dim::_1D) { + coord_t x_Ph_H { ZERO }; if (tags & BC::E) { if (i1 == 0) { - Fld(N_GHOSTS, em::ex2) = ZERO; - Fld(N_GHOSTS, em::ex3) = ZERO; + Fld(N_GHOSTS, em::ex2) = fset.ex2(x_Ph_H); + Fld(N_GHOSTS, em::ex3) = fset.ex3(x_Ph_H); } else { Fld(N_GHOSTS - i1, em::ex1) = Fld(N_GHOSTS + i1 - 1, em::ex1); Fld(N_GHOSTS - i1, em::ex2) = -Fld(N_GHOSTS + i1, em::ex2); @@ -514,7 +521,7 @@ namespace kernel::bc { if (tags & BC::B) { if (i1 == 0) { - Fld(N_GHOSTS, em::bx1) = ZERO; + Fld(N_GHOSTS, em::bx1) = fset.bx1(x_Ph_H); } else { Fld(N_GHOSTS - i1, em::bx1) = -Fld(N_GHOSTS + i1, em::bx1); Fld(N_GHOSTS - i1, em::bx2) = Fld(N_GHOSTS + i1 - 1, em::bx2); @@ -530,10 +537,11 @@ namespace kernel::bc { Inline void operator()(index_t i1, index_t i2) const { if constexpr (D == Dim::_2D) { + coord_t x_Ph_H { ZERO }; if (tags & BC::E) { if (i1 == 0) { - Fld(N_GHOSTS, i2, em::ex2) = ZERO; - Fld(N_GHOSTS, i2, em::ex3) = ZERO; + Fld(N_GHOSTS, i2, em::ex2) = fset.ex2(x_Ph_H); + Fld(N_GHOSTS, i2, em::ex3) = fset.ex3(x_Ph_H); } else { Fld(N_GHOSTS - i1, i2, em::ex1) = Fld(N_GHOSTS + i1 - 1, i2, em::ex1); Fld(N_GHOSTS - i1, i2, em::ex2) = -Fld(N_GHOSTS + i1, i2, em::ex2); @@ -543,7 +551,7 @@ namespace kernel::bc { if (tags & BC::B) { if (i1 == 0) { - Fld(N_GHOSTS, i2, em::bx1) = ZERO; + Fld(N_GHOSTS, i2, em::bx1) = fset.bx1(x_Ph_H); } else { Fld(N_GHOSTS - i1, i2, em::bx1) = -Fld(N_GHOSTS + i1, i2, em::bx1); Fld(N_GHOSTS - i1, i2, em::bx2) = Fld(N_GHOSTS + i1 - 1, i2, em::bx2); @@ -559,10 +567,11 @@ namespace kernel::bc { Inline void operator()(index_t i1, index_t i2, index_t i3) const { if constexpr (D == Dim::_3D) { + coord_t x_Ph_H { ZERO }; if (tags & BC::E) { if (i1 == 0) { - Fld(N_GHOSTS, i2, i3, em::ex2) = ZERO; - Fld(N_GHOSTS, i2, i3, em::ex3) = ZERO; + Fld(N_GHOSTS, i2, i3, em::ex2) = fset.ex2(x_Ph_H); + Fld(N_GHOSTS, i2, i3, em::ex3) = fset.ex3(x_Ph_H); } else { Fld(N_GHOSTS - i1, i2, i3, em::ex1) = Fld(N_GHOSTS + i1 - 1, i2, @@ -575,7 +584,7 @@ namespace kernel::bc { if (tags & BC::B) { if (i1 == 0) { - Fld(N_GHOSTS, i2, i3, em::bx1) = ZERO; + Fld(N_GHOSTS, i2, i3, em::bx1) = fset.bx1(x_Ph_H); } else { Fld(N_GHOSTS - i1, i2, i3, em::bx1) = -Fld(N_GHOSTS + i1, i2, i3, em::bx1); Fld(N_GHOSTS - i1, i2, i3, em::bx2) = Fld(N_GHOSTS + i1 - 1, From 9b237323a2f43fea4f1ea1c25fe3d1466f8d3415 Mon Sep 17 00:00:00 2001 From: hayk Date: Sat, 8 Mar 2025 16:16:31 -0500 Subject: [PATCH 431/773] filter test fixed --- src/kernels/tests/digital_filter.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/kernels/tests/digital_filter.cpp b/src/kernels/tests/digital_filter.cpp index e0cc352f5..03a63753b 100644 --- a/src/kernels/tests/digital_filter.cpp +++ b/src/kernels/tests/digital_filter.cpp @@ -40,8 +40,13 @@ void testFilter(const std::vector& res, auto boundaries = boundaries_t {}; if constexpr (M::CoordType != Coord::Cart) { boundaries = { - {FldsBC::CUSTOM, FldsBC::CUSTOM}, - { FldsBC::AXIS, FldsBC::AXIS} + { FldsBC::CUSTOM, FldsBC::CUSTOM }, + { FldsBC::AXIS, FldsBC::AXIS } + }; + } else { + boundaries = { + { FldsBC::PERIODIC, FldsBC::PERIODIC }, + { FldsBC::PERIODIC, FldsBC::PERIODIC } }; } @@ -183,4 +188,4 @@ auto main(int argc, char* argv[]) -> int { } Kokkos::finalize(); return 0; -} \ No newline at end of file +} From 179fafee756f0a921e84f62f53e2c0ef27aaff75 Mon Sep 17 00:00:00 2001 From: hayk Date: Sun, 9 Mar 2025 01:59:57 -0500 Subject: [PATCH 432/773] removed extra kokkos flags --- cmake/kokkosConfig.cmake | 35 ----------------- legacy/tests/kernels-sr.cpp | 10 ++--- src/framework/containers/particles.cpp | 4 +- src/framework/domain/comm_mpi.hpp | 12 +++--- src/framework/domain/comm_nompi.hpp | 6 +-- src/global/arch/kokkos_aliases.cpp | 54 +++++++++++++------------- src/global/arch/kokkos_aliases.h | 18 ++++----- src/kernels/tests/prtls_to_phys.cpp | 45 ++++++++++----------- 8 files changed, 76 insertions(+), 108 deletions(-) diff --git a/cmake/kokkosConfig.cmake b/cmake/kokkosConfig.cmake index 63c32622d..8800f21a0 100644 --- a/cmake/kokkosConfig.cmake +++ b/cmake/kokkosConfig.cmake @@ -37,41 +37,6 @@ set(Kokkos_ENABLE_OPENMP ${default_KOKKOS_ENABLE_OPENMP} CACHE BOOL "Enable OpenMP") -# set memory space -if(${Kokkos_ENABLE_CUDA}) - add_compile_definitions(CUDA_ENABLED) - set(ACC_MEM_SPACE Kokkos::CudaSpace) -elseif(${Kokkos_ENABLE_HIP}) - add_compile_definitions(HIP_ENABLED) - set(ACC_MEM_SPACE Kokkos::HIPSpace) -else() - set(ACC_MEM_SPACE Kokkos::HostSpace) -endif() - -set(HOST_MEM_SPACE Kokkos::HostSpace) - -# set execution space -if(${Kokkos_ENABLE_CUDA}) - set(ACC_EXE_SPACE Kokkos::Cuda) -elseif(${Kokkos_ENABLE_HIP}) - set(ACC_EXE_SPACE Kokkos::HIP) -elseif(${Kokkos_ENABLE_OPENMP}) - set(ACC_EXE_SPACE Kokkos::OpenMP) -else() - set(ACC_EXE_SPACE Kokkos::Serial) -endif() - -if(${Kokkos_ENABLE_OPENMP}) - set(HOST_EXE_SPACE Kokkos::OpenMP) -else() - set(HOST_EXE_SPACE Kokkos::Serial) -endif() - -add_compile_options("-D AccelExeSpace=${ACC_EXE_SPACE}") -add_compile_options("-D AccelMemSpace=${ACC_MEM_SPACE}") -add_compile_options("-D HostExeSpace=${HOST_EXE_SPACE}") -add_compile_options("-D HostMemSpace=${HOST_MEM_SPACE}") - if(${BUILD_TESTING} STREQUAL "OFF") set(Kokkos_ENABLE_TESTS OFF diff --git a/legacy/tests/kernels-sr.cpp b/legacy/tests/kernels-sr.cpp index 59ce0646b..d765799e3 100644 --- a/legacy/tests/kernels-sr.cpp +++ b/legacy/tests/kernels-sr.cpp @@ -1,17 +1,17 @@ -#include "wrapper.h" - #include #include #include +#include "wrapper.h" + #include METRIC_HEADER #include PGEN_HEADER -#include "particle_macros.h" - #include "kernels/particle_pusher_sr.hpp" +#include "particle_macros.h" + template void put_value(ntt::array_t& arr, T value, int i) { auto arr_h = Kokkos::create_mirror_view(arr); @@ -221,4 +221,4 @@ auto main(int argc, char* argv[]) -> int { ntt::GlobalFinalize(); return 0; -} \ No newline at end of file +} diff --git a/src/framework/containers/particles.cpp b/src/framework/containers/particles.cpp index d78055824..d165f6233 100644 --- a/src/framework/containers/particles.cpp +++ b/src/framework/containers/particles.cpp @@ -220,14 +220,14 @@ namespace ntt { Kokkos::Experimental::fill( "TagAliveParticles", - AccelExeSpace(), + Kokkos::DefaultExecutionSpace(), Kokkos::subview(this_tag, std::make_pair(static_cast(0), n_alive)), ParticleTag::alive); Kokkos::Experimental::fill( "TagDeadParticles", - AccelExeSpace(), + Kokkos::DefaultExecutionSpace(), Kokkos::subview(this_tag, std::make_pair(n_alive, n_alive + n_dead)), ParticleTag::dead); diff --git a/src/framework/domain/comm_mpi.hpp b/src/framework/domain/comm_mpi.hpp index e5bc2d21e..d4f8b5651 100644 --- a/src/framework/domain/comm_mpi.hpp +++ b/src/framework/domain/comm_mpi.hpp @@ -83,7 +83,7 @@ namespace comm { (long int)(send_slice[0].first); Kokkos::parallel_for( "CommunicateField-extract", - Kokkos::MDRangePolicy, AccelExeSpace>( + Kokkos::MDRangePolicy, Kokkos::DefaultExecutionSpace>( { recv_slice[0].first, comps.first }, { recv_slice[0].second, comps.second }), Lambda(index_t i1, index_t ci) { @@ -96,7 +96,7 @@ namespace comm { (long int)(send_slice[1].first); Kokkos::parallel_for( "CommunicateField-extract", - Kokkos::MDRangePolicy, AccelExeSpace>( + Kokkos::MDRangePolicy, Kokkos::DefaultExecutionSpace>( { recv_slice[0].first, recv_slice[1].first, comps.first }, { recv_slice[0].second, recv_slice[1].second, comps.second }), Lambda(index_t i1, index_t i2, index_t ci) { @@ -111,7 +111,7 @@ namespace comm { (long int)(send_slice[2].first); Kokkos::parallel_for( "CommunicateField-extract", - Kokkos::MDRangePolicy, AccelExeSpace>( + Kokkos::MDRangePolicy, Kokkos::DefaultExecutionSpace>( { recv_slice[0].first, recv_slice[1].first, recv_slice[2].first, @@ -239,7 +239,7 @@ namespace comm { const auto offset_c = comps.first; Kokkos::parallel_for( "CommunicateField-extract", - Kokkos::MDRangePolicy, AccelExeSpace>( + Kokkos::MDRangePolicy, Kokkos::DefaultExecutionSpace>( { recv_slice[0].first, comps.first }, { recv_slice[0].second, comps.second }), Lambda(index_t i1, index_t ci) { @@ -251,7 +251,7 @@ namespace comm { const auto offset_c = comps.first; Kokkos::parallel_for( "CommunicateField-extract", - Kokkos::MDRangePolicy, AccelExeSpace>( + Kokkos::MDRangePolicy, Kokkos::DefaultExecutionSpace>( { recv_slice[0].first, recv_slice[1].first, comps.first }, { recv_slice[0].second, recv_slice[1].second, comps.second }), Lambda(index_t i1, index_t i2, index_t ci) { @@ -266,7 +266,7 @@ namespace comm { const auto offset_c = comps.first; Kokkos::parallel_for( "CommunicateField-extract", - Kokkos::MDRangePolicy, AccelExeSpace>( + Kokkos::MDRangePolicy, Kokkos::DefaultExecutionSpace>( { recv_slice[0].first, recv_slice[1].first, recv_slice[2].first, diff --git a/src/framework/domain/comm_nompi.hpp b/src/framework/domain/comm_nompi.hpp index 197d336fa..b477ac176 100644 --- a/src/framework/domain/comm_nompi.hpp +++ b/src/framework/domain/comm_nompi.hpp @@ -70,7 +70,7 @@ namespace comm { (long int)(send_slice[0].first); Kokkos::parallel_for( "CommunicateField-extract", - Kokkos::MDRangePolicy, AccelExeSpace>( + Kokkos::MDRangePolicy, Kokkos::DefaultExecutionSpace>( { recv_slice[0].first, comps.first }, { recv_slice[0].second, comps.second }), Lambda(index_t i1, index_t ci) { @@ -83,7 +83,7 @@ namespace comm { (long int)(send_slice[1].first); Kokkos::parallel_for( "CommunicateField-extract", - Kokkos::MDRangePolicy, AccelExeSpace>( + Kokkos::MDRangePolicy, Kokkos::DefaultExecutionSpace>( { recv_slice[0].first, recv_slice[1].first, comps.first }, { recv_slice[0].second, recv_slice[1].second, comps.second }), Lambda(index_t i1, index_t i2, index_t ci) { @@ -98,7 +98,7 @@ namespace comm { (long int)(send_slice[2].first); Kokkos::parallel_for( "CommunicateField-extract", - Kokkos::MDRangePolicy, AccelExeSpace>( + Kokkos::MDRangePolicy, Kokkos::DefaultExecutionSpace>( { recv_slice[0].first, recv_slice[1].first, recv_slice[2].first, diff --git a/src/global/arch/kokkos_aliases.cpp b/src/global/arch/kokkos_aliases.cpp index 6c15e3d52..73bc364d1 100644 --- a/src/global/arch/kokkos_aliases.cpp +++ b/src/global/arch/kokkos_aliases.cpp @@ -5,73 +5,75 @@ #include template <> -auto CreateRangePolicy( - const tuple_t& i1, - const tuple_t& i2) -> range_t { +auto CreateRangePolicy(const tuple_t& i1, + const tuple_t& i2) + -> range_t { index_t i1min = i1[0]; index_t i1max = i2[0]; - return Kokkos::RangePolicy(i1min, i1max); + return Kokkos::RangePolicy(i1min, i1max); } template <> -auto CreateRangePolicy( - const tuple_t& i1, - const tuple_t& i2) -> range_t { +auto CreateRangePolicy(const tuple_t& i1, + const tuple_t& i2) + -> range_t { index_t i1min = i1[0]; index_t i1max = i2[0]; index_t i2min = i1[1]; index_t i2max = i2[1]; - return Kokkos::MDRangePolicy, AccelExeSpace>({ i1min, i2min }, - { i1max, i2max }); + return Kokkos::MDRangePolicy, Kokkos::DefaultExecutionSpace>( + { i1min, i2min }, + { i1max, i2max }); } template <> -auto CreateRangePolicy( - const tuple_t& i1, - const tuple_t& i2) -> range_t { +auto CreateRangePolicy(const tuple_t& i1, + const tuple_t& i2) + -> range_t { index_t i1min = i1[0]; index_t i1max = i2[0]; index_t i2min = i1[1]; index_t i2max = i2[1]; index_t i3min = i1[2]; index_t i3max = i2[2]; - return Kokkos::MDRangePolicy, AccelExeSpace>( + return Kokkos::MDRangePolicy, Kokkos::DefaultExecutionSpace>( { i1min, i2min, i3min }, { i1max, i2max, i3max }); } template <> -auto CreateRangePolicyOnHost( - const tuple_t& i1, - const tuple_t& i2) -> range_h_t { +auto CreateRangePolicyOnHost(const tuple_t& i1, + const tuple_t& i2) + -> range_h_t { index_t i1min = i1[0]; index_t i1max = i2[0]; - return Kokkos::RangePolicy(i1min, i1max); + return Kokkos::RangePolicy(i1min, i1max); } template <> -auto CreateRangePolicyOnHost( - const tuple_t& i1, - const tuple_t& i2) -> range_h_t { +auto CreateRangePolicyOnHost(const tuple_t& i1, + const tuple_t& i2) + -> range_h_t { index_t i1min = i1[0]; index_t i1max = i2[0]; index_t i2min = i1[1]; index_t i2max = i2[1]; - return Kokkos::MDRangePolicy, HostExeSpace>({ i1min, i2min }, - { i1max, i2max }); + return Kokkos::MDRangePolicy, Kokkos::DefaultHostExecutionSpace>( + { i1min, i2min }, + { i1max, i2max }); } template <> -auto CreateRangePolicyOnHost( - const tuple_t& i1, - const tuple_t& i2) -> range_h_t { +auto CreateRangePolicyOnHost(const tuple_t& i1, + const tuple_t& i2) + -> range_h_t { index_t i1min = i1[0]; index_t i1max = i2[0]; index_t i2min = i1[1]; index_t i2max = i2[1]; index_t i3min = i1[2]; index_t i3max = i2[2]; - return Kokkos::MDRangePolicy, HostExeSpace>( + return Kokkos::MDRangePolicy, Kokkos::DefaultHostExecutionSpace>( { i1min, i2min, i3min }, { i1max, i2max, i3max }); } diff --git a/src/global/arch/kokkos_aliases.h b/src/global/arch/kokkos_aliases.h index f9aac9685..c20738f11 100644 --- a/src/global/arch/kokkos_aliases.h +++ b/src/global/arch/kokkos_aliases.h @@ -34,7 +34,7 @@ namespace math = Kokkos; template -using array_t = Kokkos::View; +using array_t = Kokkos::View; // Array mirror alias of arbitrary type template @@ -174,17 +174,17 @@ namespace kokkos_aliases_hidden { template <> struct range_impl { - using type = Kokkos::RangePolicy; + using type = Kokkos::RangePolicy; }; template <> struct range_impl { - using type = Kokkos::MDRangePolicy, AccelExeSpace>; + using type = Kokkos::MDRangePolicy, Kokkos::DefaultExecutionSpace>; }; template <> struct range_impl { - using type = Kokkos::MDRangePolicy, AccelExeSpace>; + using type = Kokkos::MDRangePolicy, Kokkos::DefaultExecutionSpace>; }; } // namespace kokkos_aliases_hidden @@ -201,17 +201,17 @@ namespace kokkos_aliases_hidden { template <> struct range_h_impl { - using type = Kokkos::RangePolicy; + using type = Kokkos::RangePolicy; }; template <> struct range_h_impl { - using type = Kokkos::MDRangePolicy, HostExeSpace>; + using type = Kokkos::MDRangePolicy, Kokkos::DefaultHostExecutionSpace>; }; template <> struct range_h_impl { - using type = Kokkos::MDRangePolicy, HostExeSpace>; + using type = Kokkos::MDRangePolicy, Kokkos::DefaultHostExecutionSpace>; }; } // namespace kokkos_aliases_hidden @@ -242,8 +242,8 @@ auto CreateRangePolicyOnHost(const tuple_t&, const tuple_t&) -> range_h_t; // Random number pool/generator type alias -using random_number_pool_t = Kokkos::Random_XorShift1024_Pool; -using random_generator_t = typename random_number_pool_t::generator_type; +using random_number_pool_t = Kokkos::Random_XorShift1024_Pool; +using random_generator_t = typename random_number_pool_t::generator_type; // Random number generator functions template diff --git a/src/kernels/tests/prtls_to_phys.cpp b/src/kernels/tests/prtls_to_phys.cpp index 4719fe6a1..0ceb88cd1 100644 --- a/src/kernels/tests/prtls_to_phys.cpp +++ b/src/kernels/tests/prtls_to_phys.cpp @@ -177,28 +177,29 @@ void testPrtl2PhysSR(const std::vector& res, array_t buff_ux3 { "buff_ux3", nprtl / stride }; array_t buff_wei { "buff_wei", nprtl / stride }; - Kokkos::parallel_for("Init", - Kokkos::RangePolicy(0, nprtl / stride), - kernel::PrtlToPhys_kernel(stride, - buff_x1, - buff_x2, - buff_x3, - buff_ux1, - buff_ux2, - buff_ux3, - buff_wei, - i1, - i2, - i3, - dx1, - dx2, - dx3, - ux1, - ux2, - ux3, - phi, - weight, - metric)); + Kokkos::parallel_for( + "Init", + Kokkos::RangePolicy(0, nprtl / stride), + kernel::PrtlToPhys_kernel(stride, + buff_x1, + buff_x2, + buff_x3, + buff_ux1, + buff_ux2, + buff_ux3, + buff_wei, + i1, + i2, + i3, + dx1, + dx2, + dx3, + ux1, + ux2, + ux3, + phi, + weight, + metric)); Kokkos::parallel_for("Check", nprtl / stride, Checker(metric, From e644b65600747323d108e88d8ed488ad5f74ad2b Mon Sep 17 00:00:00 2001 From: haykh Date: Sun, 9 Mar 2025 10:24:03 -0400 Subject: [PATCH 433/773] nix cfgs --- dev/nix/adios2.nix | 4 +-- dev/nix/kokkos.nix | 17 ++++++------ dev/nix/shell.nix | 66 +++++++++++++++++++++++++++++++++++++++------- 3 files changed, 66 insertions(+), 21 deletions(-) diff --git a/dev/nix/adios2.nix b/dev/nix/adios2.nix index 8ec1fd36c..7218f894f 100644 --- a/dev/nix/adios2.nix +++ b/dev/nix/adios2.nix @@ -1,7 +1,7 @@ { pkgs ? import { }, - hdf5 ? false, - mpi ? false, + hdf5, + mpi, }: let diff --git a/dev/nix/kokkos.nix b/dev/nix/kokkos.nix index cfe583c7a..6271604c5 100644 --- a/dev/nix/kokkos.nix +++ b/dev/nix/kokkos.nix @@ -1,11 +1,10 @@ { pkgs ? import { }, - arch ? "native", - gpu ? "none", + arch, + gpu, }: let - gpuUpper = pkgs.lib.toUpper gpu; name = "kokkos"; version = "4.5.01"; compilerPkgs = { @@ -30,10 +29,10 @@ let }; getArch = _: - if gpu != "none" && arch == "native" then + if gpu != "NONE" && arch == "NATIVE" then throw "Please specify an architecture when the GPU support is enabled. Available architectures: https://kokkos.org/kokkos-core-wiki/keywords.html#architectures" else - pkgs.lib.toUpper arch; + arch; in pkgs.stdenv.mkDerivation { @@ -41,7 +40,7 @@ pkgs.stdenv.mkDerivation { version = "${version}"; src = pkgs.fetchgit { url = "https://github.com/kokkos/kokkos/"; - rev = "v${version}"; + rev = "${version}"; sha256 = "sha256-cI2p+6J+8BRV5fXTDxxHTfh6P5PeeLUiF73o5zVysHQ="; }; @@ -49,16 +48,16 @@ pkgs.stdenv.mkDerivation { cmake ]; - propagatedBuildInputs = compilerPkgs.${gpuUpper}; + propagatedBuildInputs = compilerPkgs.${gpu}; cmakeFlags = [ "-D CMAKE_CXX_STANDARD=17" "-D CMAKE_CXX_EXTENSIONS=OFF" "-D CMAKE_POSITION_INDEPENDENT_CODE=TRUE" "-D Kokkos_ARCH_${getArch { }}=ON" - (if gpu != "none" then "-D Kokkos_ENABLE_${gpuUpper}=ON" else "") + (if gpu != "none" then "-D Kokkos_ENABLE_${gpu}=ON" else "") "-D CMAKE_BUILD_TYPE=Release" - ] ++ cmakeFlags.${gpuUpper}; + ] ++ cmakeFlags.${gpu}; enableParallelBuilding = true; } diff --git a/dev/nix/shell.nix b/dev/nix/shell.nix index 1f21e82b0..01d80298b 100644 --- a/dev/nix/shell.nix +++ b/dev/nix/shell.nix @@ -1,15 +1,45 @@ { pkgs ? import { }, + gpu ? "NONE", + arch ? "NATIVE", + hdf5 ? true, mpi ? false, - hdf5 ? false, - gpu ? "none", - arch ? "native", }: let + gpuUpper = pkgs.lib.toUpper gpu; + archUpper = pkgs.lib.toUpper arch; name = "entity-dev"; adios2Pkg = (pkgs.callPackage ./adios2.nix { inherit pkgs mpi hdf5; }); - kokkosPkg = (pkgs.callPackage ./kokkos.nix { inherit pkgs arch gpu; }); + kokkosPkg = ( + pkgs.callPackage ./kokkos.nix { + inherit pkgs; + arch = archUpper; + gpu = gpuUpper; + } + ); + envVars = { + compiler = rec { + NONE = { + CXX = "g++"; + CC = "gcc"; + }; + HIP = { + CXX = "hipcc"; + CC = "hipcc"; + }; + CUDA = NONE; + }; + kokkos = { + HIP = { + Kokkos_ENABLE_HIP = "ON"; + }; + CUDA = { + Kokkos_ENABLE_CUDA = "ON"; + }; + NONE = { }; + }; + }; in pkgs.mkShell { name = "${name}-env"; @@ -39,11 +69,27 @@ pkgs.mkShell { pkgs.zlib ]); - shellHook = '' - BLUE='\033[0;34m' - NC='\033[0m' + shellHook = + '' + BLUE='\033[0;34m' + NC='\033[0m' + + echo "following environment variables are set:" + '' + + pkgs.lib.concatStringsSep "" ( + pkgs.lib.mapAttrsToList ( + category: vars: + pkgs.lib.concatStringsSep "" ( + pkgs.lib.mapAttrsToList (name: value: '' + export ${name}=${value} + echo -e " ''\${BLUE}${name}''\${NC}=${value}" + '') vars.${gpuUpper} + ) + ) envVars + ) + + '' + echo "" + echo -e "${name} nix-shell activated" + ''; - echo "" - echo -e "${name} nix-shell activated" - ''; } From 158c385c2e69351ad228eace4862aca425061ec6 Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Wed, 21 Aug 2024 20:15:11 -0400 Subject: [PATCH 434/773] Add bulk velocity as moment output. --- src/framework/domain/output.cpp | 8 ++++ src/global/enums.h | 5 ++- src/global/tests/enums.cpp | 2 +- src/kernels/particle_moments.hpp | 65 +++++++++++++++++++++++++++++++- src/output/fields.cpp | 3 ++ src/output/fields.h | 4 +- 6 files changed, 81 insertions(+), 6 deletions(-) diff --git a/src/framework/domain/output.cpp b/src/framework/domain/output.cpp index 6961d2826..8283be825 100644 --- a/src/framework/domain/output.cpp +++ b/src/framework/domain/output.cpp @@ -328,6 +328,14 @@ namespace ntt { {}, local_domain->fields.bckp, c); + } else if (fld.id() == FldsID::V) { + ComputeMoments(params, + local_domain->mesh, + local_domain->species, + fld.species, + fld.comp[0], + local_domain->fields.bckp, + c); } else { raise::Error("Wrong moment requested for output", HERE); } diff --git a/src/global/enums.h b/src/global/enums.h index 8f2495c13..4d2348244 100644 --- a/src/global/enums.h +++ b/src/global/enums.h @@ -288,16 +288,17 @@ namespace ntt { N = 12, Nppc = 13, Custom = 14, + V = 15, }; constexpr FldsID(uint8_t c) : enums_hidden::BaseEnum { c } {} static constexpr type variants[] = { E, divE, D, divD, B, H, J, - A, T, Rho, Charge, N, Nppc, Custom }; + A, T, Rho, Charge, N, Nppc, Custom , V}; static constexpr const char* lookup[] = { "e", "dive", "d", "divd", "b", "h", "j", "a", "t", "rho", "charge", "n", - "nppc", "custom" }; + "nppc", "custom", "v" }; static constexpr std::size_t total = sizeof(variants) / sizeof(variants[0]); }; diff --git a/src/global/tests/enums.cpp b/src/global/tests/enums.cpp index 7785ec1a3..d5eeb76e2 100644 --- a/src/global/tests/enums.cpp +++ b/src/global/tests/enums.cpp @@ -68,7 +68,7 @@ auto main() -> int { enum_str_t all_out_flds = { "e", "dive", "d", "divd", "b", "h", "j", "a", "t", "rho", - "charge", "n", "nppc", "custom" }; + "charge", "n", "nppc", "custom" , "v"}; checkEnum(all_coords); checkEnum(all_metrics); diff --git a/src/kernels/particle_moments.hpp b/src/kernels/particle_moments.hpp index 0621646ad..3c6cd37c9 100644 --- a/src/kernels/particle_moments.hpp +++ b/src/kernels/particle_moments.hpp @@ -41,7 +41,7 @@ namespace kernel { static constexpr auto D = M::Dim; static_assert((F == FldsID::Rho) || (F == FldsID::Charge) || - (F == FldsID::N) || (F == FldsID::Nppc) || (F == FldsID::T), + (F == FldsID::N) || (F == FldsID::Nppc) || (F == FldsID::T) || (F == FldsID::V), "Invalid field ID"); const unsigned short c1, c2; @@ -89,7 +89,7 @@ namespace kernel { std::size_t ni2, real_t inv_n0, unsigned short window) - : c1 { (components.size() == 2) ? components[0] + : c1 { (components.size() > 0) ? components[0] : static_cast(0) } , c2 { (components.size() == 2) ? components[1] : static_cast(0) } @@ -205,6 +205,67 @@ namespace kernel { coeff = contrib; } + if constexpr (F == FldsID::V) { + real_t gamma { ZERO }; + // for stress-energy tensor + vec_t u_Phys { ZERO }; + if constexpr (S == SimEngine::SRPIC) { + // SR + // stress-energy tensor for SR is computed in the tetrad (hatted) basis + if constexpr (M::CoordType == Coord::Cart) { + u_Phys[0] = ux1(p); + u_Phys[1] = ux2(p); + u_Phys[2] = ux3(p); + } else { + static_assert(D != Dim::_1D, "non-Cartesian SRPIC 1D"); + coord_t x_Code { ZERO }; + x_Code[0] = static_cast(i1(p)) + static_cast(dx1(p)); + x_Code[1] = static_cast(i2(p)) + static_cast(dx2(p)); + if constexpr (D == Dim::_3D) { + x_Code[2] = static_cast(i3(p)) + static_cast(dx3(p)); + } else { + x_Code[2] = phi(p); + } + metric.template transform_xyz( + x_Code, + { ux1(p), ux2(p), ux3(p) }, + u_Phys); + } + if (mass == ZERO) { + gamma = NORM(u_Phys[0], u_Phys[1], u_Phys[2]); + } else { + gamma = math::sqrt(ONE + NORM_SQR(u_Phys[0], u_Phys[1], u_Phys[2])); + } + } else { + // GR + // stress-energy tensor for GR is computed in contravariant basis + static_assert(D != Dim::_1D, "GRPIC 1D"); + coord_t x_Code { ZERO }; + x_Code[0] = static_cast(i1(p)) + static_cast(dx1(p)); + x_Code[1] = static_cast(i2(p)) + static_cast(dx2(p)); + if constexpr (D == Dim::_3D) { + x_Code[2] = static_cast(i3(p)) + static_cast(dx3(p)); + } + vec_t u_Cntrv { ZERO }; + // compute u_i u^i for energy + metric.template transform(x_Code, + { ux1(p), ux2(p), ux3(p) }, + u_Cntrv); + gamma = u_Cntrv[0] * ux1(p) + u_Cntrv[1] * ux2(p) + u_Cntrv[2] * ux3(p); + if (mass == ZERO) { + gamma = math::sqrt(gamma); + } else { + gamma = math::sqrt(ONE + gamma); + } + metric.template transform(x_Code, u_Cntrv, u_Phys); + } + // compute the corresponding moment + coeff = u_Phys[c1 - 1] / gamma; + } else { + // for other cases, use the `contrib` defined above + coeff = contrib; + } + if constexpr (F != FldsID::Nppc) { // for nppc calculation ... // ... do not take volume, weights or smoothing into account diff --git a/src/output/fields.cpp b/src/output/fields.cpp index aa5a752d4..0c2ea5e50 100644 --- a/src/output/fields.cpp +++ b/src/output/fields.cpp @@ -44,6 +44,9 @@ namespace out { } else if (id() == FldsID::T) { // energy-momentum tensor comp = InterpretComponents({ name.substr(1, 1), name.substr(2, 1) }); + } else if (id() == FldsID::V) { + // energy-momentum tensor + comp = InterpretComponents({ name.substr(1, 1) }); } else { // scalar (Rho, divE, Custom, etc.) comp = {}; diff --git a/src/output/fields.h b/src/output/fields.h index a520a246d..4fde18ed2 100644 --- a/src/output/fields.h +++ b/src/output/fields.h @@ -43,7 +43,7 @@ namespace out { [[nodiscard]] auto is_moment() const -> bool { return (id() == FldsID::T || id() == FldsID::Rho || id() == FldsID::Nppc || - id() == FldsID::N || id() == FldsID::Charge); + id() == FldsID::N || id() == FldsID::Charge || id() == FldsID::V); } [[nodiscard]] @@ -94,6 +94,8 @@ namespace out { tmp += m_name.substr(1, 2); } else if (id() == FldsID::A) { tmp += "3"; + } else if (id() == FldsID::V) { + tmp += m_name.substr(1, 1); } else if (is_field()) { tmp += "i"; } From 334a8b18de7341586321e0989ffa565852e87ba7 Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Mon, 26 Aug 2024 11:46:57 -0400 Subject: [PATCH 435/773] Update input. --- input.example.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/input.example.toml b/input.example.toml index 788c30685..a49067811 100644 --- a/input.example.toml +++ b/input.example.toml @@ -340,7 +340,7 @@ # Field quantities to output: # @type: array of strings # @valid: fields: "E", "B", "J", "divE" - # @valid: moments: "Rho", "Charge", "N", "Nppc", "T0i", "Tij" + # @valid: moments: "Rho", "Charge", "N", "Nppc", "T0i", "Tij", "Vi" # @valid: for GR: "D", "H", "divD", "A" # @default: [] # @note: For T, you can use unspecified indices, e.g., Tij, T0i, or specific ones, e.g., Ttt, T00, T02, T23 From d0c98aede75239499743b63c409572cb1cc50d16 Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Wed, 16 Oct 2024 08:53:39 -0400 Subject: [PATCH 436/773] Bugfix in moment calculation. --- src/kernels/particle_moments.hpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/kernels/particle_moments.hpp b/src/kernels/particle_moments.hpp index 3c6cd37c9..368873cde 100644 --- a/src/kernels/particle_moments.hpp +++ b/src/kernels/particle_moments.hpp @@ -261,10 +261,7 @@ namespace kernel { } // compute the corresponding moment coeff = u_Phys[c1 - 1] / gamma; - } else { - // for other cases, use the `contrib` defined above - coeff = contrib; - } + } if constexpr (F != FldsID::Nppc) { // for nppc calculation ... From e7976ca49c5f3f2e00f4c7316efba5517b5840b0 Mon Sep 17 00:00:00 2001 From: haykh Date: Sun, 9 Mar 2025 10:57:45 -0400 Subject: [PATCH 437/773] minor bookkeeping for 3vel output --- src/framework/domain/output.cpp | 12 ++++++------ src/global/enums.h | 19 ++++++++++--------- src/global/tests/enums.cpp | 6 +++--- src/output/fields.cpp | 17 ++++++++++++----- src/output/fields.h | 4 +--- 5 files changed, 32 insertions(+), 26 deletions(-) diff --git a/src/framework/domain/output.cpp b/src/framework/domain/output.cpp index 8283be825..40871dd2a 100644 --- a/src/framework/domain/output.cpp +++ b/src/framework/domain/output.cpp @@ -330,12 +330,12 @@ namespace ntt { c); } else if (fld.id() == FldsID::V) { ComputeMoments(params, - local_domain->mesh, - local_domain->species, - fld.species, - fld.comp[0], - local_domain->fields.bckp, - c); + local_domain->mesh, + local_domain->species, + fld.species, + fld.comp[0], + local_domain->fields.bckp, + c); } else { raise::Error("Wrong moment requested for output", HERE); } diff --git a/src/global/enums.h b/src/global/enums.h index 4d2348244..6c6a4ec8f 100644 --- a/src/global/enums.h +++ b/src/global/enums.h @@ -13,7 +13,7 @@ * - enum ntt::PrtlPusher // boris, vay, photon, none * - enum ntt::Cooling // synchrotron, none * - enum ntt::FldsID // e, dive, d, divd, b, h, j, - * a, t, rho, charge, n, nppc, custom + * a, t, rho, charge, n, nppc, v, custom * @namespaces: * - ntt:: * @note Enums of the same type can be compared with each other and with strings @@ -287,18 +287,19 @@ namespace ntt { Charge = 11, N = 12, Nppc = 13, - Custom = 14, - V = 15, + V = 14, + Custom = 15, }; constexpr FldsID(uint8_t c) : enums_hidden::BaseEnum { c } {} - static constexpr type variants[] = { E, divE, D, divD, B, H, J, - A, T, Rho, Charge, N, Nppc, Custom , V}; - static constexpr const char* lookup[] = { "e", "dive", "d", "divd", - "b", "h", "j", "a", - "t", "rho", "charge", "n", - "nppc", "custom", "v" }; + static constexpr type variants[] = { E, divE, D, divD, B, + H, J, A, T, Rho, + Charge, N, Nppc, V, Custom }; + static constexpr const char* lookup[] = { "e", "dive", "d", "divd", + "b", "h", "j", "a", + "t", "rho", "charge", "n", + "nppc", "v", "custom" }; static constexpr std::size_t total = sizeof(variants) / sizeof(variants[0]); }; diff --git a/src/global/tests/enums.cpp b/src/global/tests/enums.cpp index d5eeb76e2..673efaf34 100644 --- a/src/global/tests/enums.cpp +++ b/src/global/tests/enums.cpp @@ -66,9 +66,9 @@ auto main() -> int { enum_str_t all_particle_pushers = { "boris", "vay", "photon", "none" }; enum_str_t all_coolings = { "synchrotron", "none" }; - enum_str_t all_out_flds = { "e", "dive", "d", "divd", "b", - "h", "j", "a", "t", "rho", - "charge", "n", "nppc", "custom" , "v"}; + enum_str_t all_out_flds = { "e", "dive", "d", "divd", "b", + "h", "j", "a", "t", "rho", + "charge", "n", "nppc", "v", "custom" }; checkEnum(all_coords); checkEnum(all_metrics); diff --git a/src/output/fields.cpp b/src/output/fields.cpp index 0c2ea5e50..678ca20f6 100644 --- a/src/output/fields.cpp +++ b/src/output/fields.cpp @@ -29,14 +29,24 @@ namespace out { } else { m_id = FldsID::Custom; } + // check compatibility + raise::ErrorIf(is_gr_aux_field() and S != SimEngine::GRPIC, + "GR auxiliary field output not supported for non-GRPIC", + HERE); + raise::ErrorIf(id() == FldsID::A and S != SimEngine::GRPIC, + "Output of A_phi not supported for non-GRPIC", + HERE); + raise::ErrorIf(id() == FldsID::V and S == SimEngine::GRPIC, + "Output of bulk 3-vel not supported for GRPIC", + HERE); // determine the species and components to output if (is_moment()) { species = InterpretSpecies(name); } else { species = {}; } - if (is_field() || is_current()) { - // always write all the field/current components + if (is_field() || is_current() || id() == FldsID::V) { + // always write all the field/current/bulk vel components comp = { { 1 }, { 2 }, { 3 } }; } else if (id() == FldsID::A) { // only write A3 @@ -44,9 +54,6 @@ namespace out { } else if (id() == FldsID::T) { // energy-momentum tensor comp = InterpretComponents({ name.substr(1, 1), name.substr(2, 1) }); - } else if (id() == FldsID::V) { - // energy-momentum tensor - comp = InterpretComponents({ name.substr(1, 1) }); } else { // scalar (Rho, divE, Custom, etc.) comp = {}; diff --git a/src/output/fields.h b/src/output/fields.h index 4fde18ed2..0e8e31d08 100644 --- a/src/output/fields.h +++ b/src/output/fields.h @@ -94,9 +94,7 @@ namespace out { tmp += m_name.substr(1, 2); } else if (id() == FldsID::A) { tmp += "3"; - } else if (id() == FldsID::V) { - tmp += m_name.substr(1, 1); - } else if (is_field()) { + } else if (is_field() || id() == FldsID::V) { tmp += "i"; } if (species.size() > 0) { From c9d69ce682e660e7ed0f3c43d414856717094550 Mon Sep 17 00:00:00 2001 From: haykh Date: Sun, 9 Mar 2025 14:26:41 -0400 Subject: [PATCH 438/773] implemented and tested bulk V output --- src/framework/domain/output.cpp | 69 ++++++++++---- src/kernels/particle_moments.hpp | 154 ++++++++++++++++++++----------- src/output/fields.cpp | 3 - 3 files changed, 151 insertions(+), 75 deletions(-) diff --git a/src/framework/domain/output.cpp b/src/framework/domain/output.cpp index 40871dd2a..685099e55 100644 --- a/src/framework/domain/output.cpp +++ b/src/framework/domain/output.cpp @@ -328,14 +328,6 @@ namespace ntt { {}, local_domain->fields.bckp, c); - } else if (fld.id() == FldsID::V) { - ComputeMoments(params, - local_domain->mesh, - local_domain->species, - fld.species, - fld.comp[0], - local_domain->fields.bckp, - c); } else { raise::Error("Wrong moment requested for output", HERE); } @@ -365,16 +357,35 @@ namespace ntt { if (fld.is_moment()) { for (auto i = 0; i < 3; ++i) { const auto c = static_cast(addresses[i]); - raise::ErrorIf(fld.comp[i].size() != 2, - "Wrong # of components requested for moment", - HERE); - ComputeMoments(params, - local_domain->mesh, - local_domain->species, - fld.species, - fld.comp[i], - local_domain->fields.bckp, - c); + if (fld.id() == FldsID::T) { + raise::ErrorIf(fld.comp[i].size() != 2, + "Wrong # of components requested for moment", + HERE); + ComputeMoments(params, + local_domain->mesh, + local_domain->species, + fld.species, + fld.comp[i], + local_domain->fields.bckp, + c); + } else if (fld.id() == FldsID::V) { + raise::ErrorIf(fld.comp[i].size() != 1, + "Wrong # of components requested for 3vel", + HERE); + if constexpr (S == SimEngine::SRPIC) { + ComputeMoments(params, + local_domain->mesh, + local_domain->species, + fld.species, + fld.comp[i], + local_domain->fields.bckp, + c); + } else { + raise::Error("Bulk velocity not supported for GRPIC", HERE); + } + } else { + raise::Error("Wrong moment requested for output", HERE); + } } raise::ErrorIf(addresses[1] - addresses[0] != addresses[2] - addresses[1], @@ -383,6 +394,28 @@ namespace ntt { SynchronizeFields(*local_domain, Comm::Bckp, { addresses[0], addresses[2] + 1 }); + if constexpr (S == SimEngine::SRPIC) { + if (fld.id() == FldsID::V) { + // normalize 3vel * rho (combuted above) by rho + ComputeMoments(params, + local_domain->mesh, + local_domain->species, + fld.species, + {}, + local_domain->fields.bckp, + 0u); + SynchronizeFields(*local_domain, Comm::Bckp, { 0, 1 }); + Kokkos::parallel_for("NormalizeVectorByRho", + local_domain->mesh.rangeActiveCells(), + kernel::NormalizeVectorByRho_kernel( + local_domain->fields.bckp, + local_domain->fields.bckp, + 0, + addresses[0], + addresses[1], + addresses[2])); + } + } } else { // copy fields to bckp (:, 0, 1, 2) // if as-is specified ==> copy directly to 3, 4, 5 diff --git a/src/kernels/particle_moments.hpp b/src/kernels/particle_moments.hpp index 368873cde..e52c68486 100644 --- a/src/kernels/particle_moments.hpp +++ b/src/kernels/particle_moments.hpp @@ -14,6 +14,7 @@ #include "global.h" #include "arch/kokkos_aliases.h" +#include "utils/comparators.h" #include "utils/error.h" #include "utils/numeric.h" @@ -40,8 +41,10 @@ namespace kernel { static_assert(M::is_metric, "M must be a metric class"); static constexpr auto D = M::Dim; - static_assert((F == FldsID::Rho) || (F == FldsID::Charge) || - (F == FldsID::N) || (F == FldsID::Nppc) || (F == FldsID::T) || (F == FldsID::V), + static_assert(!((S == SimEngine::GRPIC) && (F == FldsID::V)), + "Bulk velocity not supported for GRPIC"); + static_assert((F == FldsID::Rho) || (F == FldsID::Charge) || (F == FldsID::N) || + (F == FldsID::Nppc) || (F == FldsID::T) || (F == FldsID::V), "Invalid field ID"); const unsigned short c1, c2; @@ -90,7 +93,7 @@ namespace kernel { real_t inv_n0, unsigned short window) : c1 { (components.size() > 0) ? components[0] - : static_cast(0) } + : static_cast(0) } , c2 { (components.size() == 2) ? components[1] : static_cast(0) } , Buff { scatter_buff } @@ -200,68 +203,38 @@ namespace kernel { coeff *= u_Phys[c - 1]; } } - } else { - // for other cases, use the `contrib` defined above - coeff = contrib; - } - - if constexpr (F == FldsID::V) { + } else if constexpr (F == FldsID::V) { real_t gamma { ZERO }; - // for stress-energy tensor + // for bulk 3vel (tetrad basis) vec_t u_Phys { ZERO }; - if constexpr (S == SimEngine::SRPIC) { - // SR - // stress-energy tensor for SR is computed in the tetrad (hatted) basis - if constexpr (M::CoordType == Coord::Cart) { - u_Phys[0] = ux1(p); - u_Phys[1] = ux2(p); - u_Phys[2] = ux3(p); - } else { - static_assert(D != Dim::_1D, "non-Cartesian SRPIC 1D"); - coord_t x_Code { ZERO }; - x_Code[0] = static_cast(i1(p)) + static_cast(dx1(p)); - x_Code[1] = static_cast(i2(p)) + static_cast(dx2(p)); - if constexpr (D == Dim::_3D) { - x_Code[2] = static_cast(i3(p)) + static_cast(dx3(p)); - } else { - x_Code[2] = phi(p); - } - metric.template transform_xyz( - x_Code, - { ux1(p), ux2(p), ux3(p) }, - u_Phys); - } - if (mass == ZERO) { - gamma = NORM(u_Phys[0], u_Phys[1], u_Phys[2]); - } else { - gamma = math::sqrt(ONE + NORM_SQR(u_Phys[0], u_Phys[1], u_Phys[2])); - } + if constexpr (M::CoordType == Coord::Cart) { + u_Phys[0] = ux1(p); + u_Phys[1] = ux2(p); + u_Phys[2] = ux3(p); } else { - // GR - // stress-energy tensor for GR is computed in contravariant basis - static_assert(D != Dim::_1D, "GRPIC 1D"); - coord_t x_Code { ZERO }; + coord_t x_Code { ZERO }; x_Code[0] = static_cast(i1(p)) + static_cast(dx1(p)); x_Code[1] = static_cast(i2(p)) + static_cast(dx2(p)); if constexpr (D == Dim::_3D) { x_Code[2] = static_cast(i3(p)) + static_cast(dx3(p)); - } - vec_t u_Cntrv { ZERO }; - // compute u_i u^i for energy - metric.template transform(x_Code, - { ux1(p), ux2(p), ux3(p) }, - u_Cntrv); - gamma = u_Cntrv[0] * ux1(p) + u_Cntrv[1] * ux2(p) + u_Cntrv[2] * ux3(p); - if (mass == ZERO) { - gamma = math::sqrt(gamma); } else { - gamma = math::sqrt(ONE + gamma); + x_Code[2] = phi(p); } - metric.template transform(x_Code, u_Cntrv, u_Phys); + metric.template transform_xyz(x_Code, + { ux1(p), ux2(p), ux3(p) }, + u_Phys); + } + if (mass == ZERO) { + gamma = NORM(u_Phys[0], u_Phys[1], u_Phys[2]); + } else { + gamma = math::sqrt(ONE + NORM_SQR(u_Phys[0], u_Phys[1], u_Phys[2])); } // compute the corresponding moment - coeff = u_Phys[c1 - 1] / gamma; - } + coeff = (mass == ZERO ? ONE : mass) * u_Phys[c1 - 1] / gamma; + } else { + // for other cases, use the `contrib` defined above + coeff = contrib; + } if constexpr (F != FldsID::Nppc) { // for nppc calculation ... @@ -346,6 +319,79 @@ namespace kernel { } }; + template + class NormalizeVectorByRho_kernel { + const ndfield_t Rho; + ndfield_t Vector; + const unsigned short c_rho, c_v1, c_v2, c_v3; + + public: + NormalizeVectorByRho_kernel(const ndfield_t& rho, + const ndfield_t& vector, + unsigned short crho, + unsigned short cv1, + unsigned short cv2, + unsigned short cv3) + : Rho { rho } + , Vector { vector } + , c_rho { crho } + , c_v1 { cv1 } + , c_v2 { cv2 } + , c_v3 { cv3 } { + raise::ErrorIf(c_rho >= N or c_v1 >= N or c_v2 >= N or c_v3 >= N, + "Invalid component index", + HERE); + raise::ErrorIf(c_rho == c_v1 or c_rho == c_v2 or c_rho == c_v3, + "Invalid component index", + HERE); + raise::ErrorIf(c_v1 == c_v2 or c_v1 == c_v3 or c_v2 == c_v3, + "Invalid component index", + HERE); + } + + Inline void operator()(index_t i1) const { + if constexpr (D == Dim::_1D) { + if (not cmp::AlmostZero(Rho(i1, c_rho))) { + Vector(i1, c_v1) /= Rho(i1, c_rho); + Vector(i1, c_v2) /= Rho(i1, c_rho); + Vector(i1, c_v3) /= Rho(i1, c_rho); + } + } else { + raise::KernelError( + HERE, + "1D implementation of NormalizeVectorByRho_kernel called for non-1D"); + } + } + + Inline void operator()(index_t i1, index_t i2) const { + if constexpr (D == Dim::_2D) { + if (not cmp::AlmostZero(Rho(i1, i2, c_rho))) { + Vector(i1, i2, c_v1) /= Rho(i1, i2, c_rho); + Vector(i1, i2, c_v2) /= Rho(i1, i2, c_rho); + Vector(i1, i2, c_v3) /= Rho(i1, i2, c_rho); + } + } else { + raise::KernelError( + HERE, + "2D implementation of NormalizeVectorByRho_kernel called for non-2D"); + } + } + + Inline void operator()(index_t i1, index_t i2, index_t i3) const { + if constexpr (D == Dim::_3D) { + if (not cmp::AlmostZero(Rho(i1, i2, i3, c_rho))) { + Vector(i1, i2, i3, c_v1) /= Rho(i1, i2, i3, c_rho); + Vector(i1, i2, i3, c_v2) /= Rho(i1, i2, i3, c_rho); + Vector(i1, i2, i3, c_v3) /= Rho(i1, i2, i3, c_rho); + } + } else { + raise::KernelError( + HERE, + "3D implementation of NormalizeVectorByRho_kernel called for non-3D"); + } + } + }; + } // namespace kernel #endif // KERNELS_PARTICLE_MOMENTS_HPP diff --git a/src/output/fields.cpp b/src/output/fields.cpp index 678ca20f6..091f04cd9 100644 --- a/src/output/fields.cpp +++ b/src/output/fields.cpp @@ -30,9 +30,6 @@ namespace out { m_id = FldsID::Custom; } // check compatibility - raise::ErrorIf(is_gr_aux_field() and S != SimEngine::GRPIC, - "GR auxiliary field output not supported for non-GRPIC", - HERE); raise::ErrorIf(id() == FldsID::A and S != SimEngine::GRPIC, "Output of A_phi not supported for non-GRPIC", HERE); From b6fe114ab719e45d58ebb6a4241cac3407df5040 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20B=C3=B6ss?= Date: Mon, 10 Mar 2025 12:00:38 -0500 Subject: [PATCH 439/773] revert to zero at boundary --- src/engines/srpic.hpp | 28 +----------------------- src/kernels/fields_bcs.hpp | 44 ++++++++++++-------------------------- 2 files changed, 15 insertions(+), 57 deletions(-) diff --git a/src/engines/srpic.hpp b/src/engines/srpic.hpp index 891336309..96747e429 100644 --- a/src/engines/srpic.hpp +++ b/src/engines/srpic.hpp @@ -890,36 +890,10 @@ namespace ntt { raise::Error("Invalid dimension", HERE); } - auto match_fields = m_pgen.MatchFields(time); Kokkos::parallel_for( "ConductorFields", range, - kernel::bc::ConductorBoundaries_kernel(domain.fields.em, - match_fields, tags)); - - // if constexpr (M::Dim == Dim::_1D) { - // Kokkos::parallel_for( - // "MatchFields", - // CreateRangePolicy({ xi_min[0] }, { xi_max[0] }), - // kernel::bc::ConductorBoundaries_kernel(domain.fields.em, - // tags)); - // } else if constexpr (M::Dim == Dim::_2D) { - // Kokkos::parallel_for( - // "MatchFields", - // CreateRangePolicy({ xi_min[0], xi_min[1] }, - // { xi_max[0], xi_max[1] }), - // kernel::bc::ConductorBoundaries_kernel(domain.fields.em, - // tags)); - // } else if constexpr (M::Dim == Dim::_3D) { - // Kokkos::parallel_for( - // "MatchFields", - // CreateRangePolicy({ xi_min[0], xi_min[1], xi_min[2] }, - // { xi_max[0], xi_max[1], xi_max[2] }), - // kernel::bc::ConductorBoundaries_kernel(domain.fields.em, - // tags)); - // } else { - // raise::Error("Invalid dimension", HERE); - // } + kernel::bc::ConductorBoundaries_kernel(domain.fields.em, tags)); } } diff --git a/src/kernels/fields_bcs.hpp b/src/kernels/fields_bcs.hpp index 4d6be9380..b1ee999d3 100644 --- a/src/kernels/fields_bcs.hpp +++ b/src/kernels/fields_bcs.hpp @@ -486,32 +486,24 @@ namespace kernel::bc { } }; - template + template struct ConductorBoundaries_kernel { static_assert(static_cast(o) < static_cast(D), "Invalid component index"); - static constexpr bool defines_ex2 = traits::has_method::value; - static constexpr bool defines_ex3 = traits::has_method::value; - static constexpr bool defines_bx1 = traits::has_method::value; - static_assert(( defines_ex2 or defines_ex3 or defines_bx1), - "none of the components of E or B are specified in PGEN"); ndfield_t Fld; - const I fset; const BCTags tags; - ConductorBoundaries_kernel(ndfield_t Fld, const I& fset, BCTags tags) + ConductorBoundaries_kernel(ndfield_t Fld, BCTags tags) : Fld { Fld } - , fset { fset } , tags { tags } {} Inline void operator()(index_t i1) const { if constexpr (D == Dim::_1D) { - coord_t x_Ph_H { ZERO }; if (tags & BC::E) { if (i1 == 0) { - Fld(N_GHOSTS, em::ex2) = fset.ex2(x_Ph_H); - Fld(N_GHOSTS, em::ex3) = fset.ex3(x_Ph_H); + Fld(N_GHOSTS, em::ex2) = ZERO; + Fld(N_GHOSTS, em::ex3) = ZERO; } else { Fld(N_GHOSTS - i1, em::ex1) = Fld(N_GHOSTS + i1 - 1, em::ex1); Fld(N_GHOSTS - i1, em::ex2) = -Fld(N_GHOSTS + i1, em::ex2); @@ -521,7 +513,7 @@ namespace kernel::bc { if (tags & BC::B) { if (i1 == 0) { - Fld(N_GHOSTS, em::bx1) = fset.bx1(x_Ph_H); + Fld(N_GHOSTS, em::bx1) = ZERO; } else { Fld(N_GHOSTS - i1, em::bx1) = -Fld(N_GHOSTS + i1, em::bx1); Fld(N_GHOSTS - i1, em::bx2) = Fld(N_GHOSTS + i1 - 1, em::bx2); @@ -537,11 +529,10 @@ namespace kernel::bc { Inline void operator()(index_t i1, index_t i2) const { if constexpr (D == Dim::_2D) { - coord_t x_Ph_H { ZERO }; if (tags & BC::E) { if (i1 == 0) { - Fld(N_GHOSTS, i2, em::ex2) = fset.ex2(x_Ph_H); - Fld(N_GHOSTS, i2, em::ex3) = fset.ex3(x_Ph_H); + Fld(N_GHOSTS, i2, em::ex2) = ZERO; + Fld(N_GHOSTS, i2, em::ex3) = ZERO; } else { Fld(N_GHOSTS - i1, i2, em::ex1) = Fld(N_GHOSTS + i1 - 1, i2, em::ex1); Fld(N_GHOSTS - i1, i2, em::ex2) = -Fld(N_GHOSTS + i1, i2, em::ex2); @@ -551,7 +542,7 @@ namespace kernel::bc { if (tags & BC::B) { if (i1 == 0) { - Fld(N_GHOSTS, i2, em::bx1) = fset.bx1(x_Ph_H); + Fld(N_GHOSTS, i2, em::bx1) = ZERO; } else { Fld(N_GHOSTS - i1, i2, em::bx1) = -Fld(N_GHOSTS + i1, i2, em::bx1); Fld(N_GHOSTS - i1, i2, em::bx2) = Fld(N_GHOSTS + i1 - 1, i2, em::bx2); @@ -567,16 +558,13 @@ namespace kernel::bc { Inline void operator()(index_t i1, index_t i2, index_t i3) const { if constexpr (D == Dim::_3D) { - coord_t x_Ph_H { ZERO }; if (tags & BC::E) { if (i1 == 0) { - Fld(N_GHOSTS, i2, i3, em::ex2) = fset.ex2(x_Ph_H); - Fld(N_GHOSTS, i2, i3, em::ex3) = fset.ex3(x_Ph_H); + Fld(N_GHOSTS, i2, i3, em::ex2) = ZERO; + Fld(N_GHOSTS, i2, i3, em::ex3) = ZERO; } else { Fld(N_GHOSTS - i1, i2, i3, em::ex1) = Fld(N_GHOSTS + i1 - 1, - i2, - i3, - em::ex1); + i2, i3, em::ex1); Fld(N_GHOSTS - i1, i2, i3, em::ex2) = -Fld(N_GHOSTS + i1, i2, i3, em::ex2); Fld(N_GHOSTS - i1, i2, i3, em::ex3) = -Fld(N_GHOSTS + i1, i2, i3, em::ex3); } @@ -584,17 +572,13 @@ namespace kernel::bc { if (tags & BC::B) { if (i1 == 0) { - Fld(N_GHOSTS, i2, i3, em::bx1) = fset.bx1(x_Ph_H); + Fld(N_GHOSTS, i2, i3, em::bx1) = ZERO; } else { Fld(N_GHOSTS - i1, i2, i3, em::bx1) = -Fld(N_GHOSTS + i1, i2, i3, em::bx1); Fld(N_GHOSTS - i1, i2, i3, em::bx2) = Fld(N_GHOSTS + i1 - 1, - i2, - i3, - em::bx2); + i2, i3, em::bx2); Fld(N_GHOSTS - i1, i2, i3, em::bx3) = Fld(N_GHOSTS + i1 - 1, - i2, - i3, - em::bx3); + i2, i3, em::bx3); } } } else { From 01aa65ab0e29c39cd37adffe48f7c7b15d943dc9 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Mon, 10 Mar 2025 15:11:24 -0400 Subject: [PATCH 440/773] restored faraday_gr at i2=i2min because it was correct --- src/kernels/faraday_gr.hpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/kernels/faraday_gr.hpp b/src/kernels/faraday_gr.hpp index 241fa35dc..5f6e5590b 100644 --- a/src/kernels/faraday_gr.hpp +++ b/src/kernels/faraday_gr.hpp @@ -73,10 +73,8 @@ namespace kernel::gr { Bout(i1, i2, em::bx1) = Bin(i1, i2, em::bx1) + coeff * inv_sqrt_detH_0pH * (E(i1, i2, em::ex3) - E(i1, i2 + 1, em::ex3)); - if (i2 == i2min) { - if (is_axis_i2min) { - Bout(i1, i2, em::bx2) = ZERO; - } + if ((i2 == i2min) && is_axis_i2min) { + Bout(i1, i2, em::bx2) = ZERO; } else { const real_t inv_sqrt_detH_pH0 { ONE / metric.sqrt_det_h( { i1_ + HALF, i2_ }) }; From 2cee034e501817ef0e1d97f1ae4921497f035bdf Mon Sep 17 00:00:00 2001 From: haykh Date: Wed, 12 Mar 2025 14:56:57 -0400 Subject: [PATCH 441/773] inj fixed --- dev/nix/kokkos.nix | 2 +- setups/grpic/wald/pgen.hpp | 187 ++++++++++++++++++++++------------- src/archetypes/energy_dist.h | 27 +---- src/kernels/injectors.hpp | 24 ++--- 4 files changed, 134 insertions(+), 106 deletions(-) diff --git a/dev/nix/kokkos.nix b/dev/nix/kokkos.nix index cfe583c7a..48e5d8c71 100644 --- a/dev/nix/kokkos.nix +++ b/dev/nix/kokkos.nix @@ -41,7 +41,7 @@ pkgs.stdenv.mkDerivation { version = "${version}"; src = pkgs.fetchgit { url = "https://github.com/kokkos/kokkos/"; - rev = "v${version}"; + rev = "${version}"; sha256 = "sha256-cI2p+6J+8BRV5fXTDxxHTfh6P5PeeLUiF73o5zVysHQ="; }; diff --git a/setups/grpic/wald/pgen.hpp b/setups/grpic/wald/pgen.hpp index 7f8146bb9..236d361a6 100644 --- a/setups/grpic/wald/pgen.hpp +++ b/setups/grpic/wald/pgen.hpp @@ -30,38 +30,40 @@ namespace user { } Inline auto bx1(const coord_t& x_Ph) const -> real_t { // at ( i , j + HALF ) - coord_t xi { ZERO }, x0m { ZERO }, x0p { ZERO }; - metric.template convert(x_Ph, xi); + // coord_t xi { ZERO }, x0m { ZERO }, x0p { ZERO }; + // metric.template convert(x_Ph, xi); - x0m[0] = xi[0]; - x0m[1] = xi[1] - HALF * m_eps; - x0p[0] = xi[0]; - x0p[1] = xi[1] + HALF * m_eps; + // x0m[0] = xi[0]; + // x0m[1] = xi[1] - HALF * m_eps; + // x0p[0] = xi[0]; + // x0p[1] = xi[1] + HALF * m_eps; - real_t inv_sqrt_detH_ijP { ONE / metric.sqrt_det_h({ xi[0], xi[1] }) }; + // real_t inv_sqrt_detH_ijP { ONE / metric.sqrt_det_h({ xi[0], xi[1] }) }; - if (cmp::AlmostZero(x_Ph[1])) { - return ONE; - } else { - return (A_3(x0p) - A_3(x0m)) * inv_sqrt_detH_ijP / m_eps; - } + // if (cmp::AlmostZero(x_Ph[1])) { + // return ONE; + // } else { + // return (A_3(x0p) - A_3(x0m)) * inv_sqrt_detH_ijP / m_eps; + // } + return ZERO; } Inline auto bx2(const coord_t& x_Ph) const -> real_t { // at ( i + HALF , j ) - coord_t xi { ZERO }, x0m { ZERO }, x0p { ZERO }; - metric.template convert(x_Ph, xi); - - x0m[0] = xi[0] - HALF * m_eps; - x0m[1] = xi[1]; - x0p[0] = xi[0] + HALF * m_eps; - x0p[1] = xi[1]; - - real_t inv_sqrt_detH_ijP { ONE / metric.sqrt_det_h({ xi[0], xi[1] }) }; - if (cmp::AlmostZero(x_Ph[1])) { - return ZERO; - } else { - return -(A_3(x0p) - A_3(x0m)) * inv_sqrt_detH_ijP / m_eps; - } + // coord_t xi { ZERO }, x0m { ZERO }, x0p { ZERO }; + // metric.template convert(x_Ph, xi); + + // x0m[0] = xi[0] - HALF * m_eps; + // x0m[1] = xi[1]; + // x0p[0] = xi[0] + HALF * m_eps; + // x0p[1] = xi[1]; + + // real_t inv_sqrt_detH_ijP { ONE / metric.sqrt_det_h({ xi[0], xi[1] }) }; + // if (cmp::AlmostZero(x_Ph[1])) { + // return ZERO; + // } else { + // return -(A_3(x0p) - A_3(x0m)) * inv_sqrt_detH_ijP / m_eps; + // } + return ZERO; } Inline auto bx3(const coord_t& x_Ph) const -> real_t { @@ -147,12 +149,18 @@ namespace user { const vec_t B_cntrv { EM(i1, i2, em::bx1), EM(i1, i2, em::bx2), EM(i1, i2, em::bx3) }; + const vec_t D_cntrv { EM(i1, i2, em::dx1), + EM(i1, i2, em::dx2), + EM(i1, i2, em::dx3) }; vec_t B_cov { ZERO }; metric.template transform(xi, B_cntrv, B_cov); const auto bsqr = DOT(B_cntrv[0], B_cntrv[1], B_cntrv[2], B_cov[0], B_cov[1], B_cov[2]); + const auto DdotB = + DOT(D_cntrv[0], D_cntrv[1], D_cntrv[2], B_cov[0], B_cov[1], B_cov[2]); const auto dens = density(i1, i2, 0); - return (bsqr > sigma_thr * dens) || (dens < dens_thr); + // return (bsqr > sigma_thr * dens) || (dens < dens_thr); + return (DdotB / bsqr > 0.001) || (bsqr > sigma_thr * dens); } return false; } @@ -194,7 +202,8 @@ namespace user { const std::vector xi_max; const real_t sigma0, sigma_max, multiplicity, nGJ, temperature, m_eps; - InitFields init_flds; + InitFields init_flds; + const Metadomain* metadomain; inline PGen(SimulationParams& p, const Metadomain& m) : arch::ProblemGenerator(p) @@ -207,52 +216,90 @@ namespace user { SQR(p.template get("scales.skindepth0")) } , temperature { p.template get("setup.temperature") } , m_eps { p.template get("setup.m_eps") } - , init_flds { m.mesh().metric, m_eps } {} - - inline void InitPrtls(Domain& local_domain) { - const auto energy_dist = arch::Maxwellian(local_domain.mesh.metric, - local_domain.random_pool, + , init_flds { m.mesh().metric, m_eps } + , metadomain { &m } {} + + inline void InitPrtls(Domain& domain) { + // arch::InjectGlobally(*metadomain, + // domain, + // 1, + // { + // { "x1", { 3.2 } }, + // { "x2", { 1.2 } }, + // { "phi", { 0.0 } }, + // { "ux1", { 0.0 } }, + // { "ux2", { -1.0 } }, + // { "ux3", { 0.5 } } + // }); + // arch::InjectGlobally(*metadomain, + // domain, + // 2, + // { + // { "x1", { 2.05 } }, + // { "x2", { 2.3 } }, + // { "phi", { 0.0 } }, + // { "ux1", { 0.5 } }, + // { "ux2", { -0.5 } }, + // { "ux3", { -0.5 } } + // }); + const auto energy_dist = arch::Maxwellian(domain.mesh.metric, + domain.random_pool, temperature); - const auto spatial_dist = PointDistribution(xi_min, - xi_max, - sigma_max / sigma0, - multiplicity * nGJ, - params, - &local_domain); - - const auto injector = - arch::NonUniformInjector( - energy_dist, - spatial_dist, - { 1, 2 }); - arch::InjectNonUniform(params, - local_domain, - injector, - 1.0, - true); + // const auto npart0 = domain.species[0].npart(); + // auto& ux3_0 = domain.species[0].ux3; + // auto& ux3_1 = domain.species[1].ux3; + // Kokkos::parallel_for( + // "zero", + // npart0, + // Lambda(index_t p) { + // ux3_0(p) = ZERO; + // ux3_1(p) = ZERO; + // }); + // const auto spatial_dist = PointDistribution(xi_min, + // xi_max, + // sigma_max / sigma0, + // multiplicity * nGJ, + // params, + // &local_domain); + + // const auto injector = + // arch::NonUniformInjector( + // energy_dist, + // spatial_dist, + // { 1, 2 }); + // arch::InjectNonUniform(params, + // local_domain, + // injector, + // 1.0, + // true); + // const auto energy_dist = arch::Cold(local_domain.mesh.metric); + const auto injector = arch::UniformInjector( + energy_dist, + { 1, 2 }); + arch::InjectUniform(params, domain, injector, 1.0, true); } void CustomPostStep(std::size_t, long double time, Domain& local_domain) { - const auto energy_dist = arch::Maxwellian(local_domain.mesh.metric, - local_domain.random_pool, - temperature); - const auto spatial_dist = PointDistribution(xi_min, - xi_max, - sigma_max / sigma0, - multiplicity * nGJ, - params, - &local_domain); - - const auto injector = - arch::NonUniformInjector( - energy_dist, - spatial_dist, - { 1, 2 }); - arch::InjectNonUniform(params, - local_domain, - injector, - 1.0, - true); + // const auto energy_dist = arch::Maxwellian(local_domain.mesh.metric, + // local_domain.random_pool, + // temperature); + // const auto spatial_dist = PointDistribution(xi_min, + // xi_max, + // sigma_max / sigma0, + // multiplicity * nGJ, + // params, + // &local_domain); + + // const auto injector = + // arch::NonUniformInjector( + // energy_dist, + // spatial_dist, + // { 1, 2 }); + // arch::InjectNonUniform(params, + // local_domain, + // injector, + // 1.0, + // true); } }; diff --git a/src/archetypes/energy_dist.h b/src/archetypes/energy_dist.h index e9bc9051a..1cd9d63a4 100644 --- a/src/archetypes/energy_dist.h +++ b/src/archetypes/energy_dist.h @@ -83,9 +83,7 @@ namespace arch { , g_max { g_max } , pl_ind { pl_ind } {} - Inline void operator()(const coord_t& x_Code, - vec_t& v, - unsigned short sp = 0) const override { + Inline void operator()(vec_t& v, unsigned short sp = 0) const override { auto rand_gen = pool.get_state(); auto rand_X1 = Random(rand_gen); auto rand_gam = ONE; @@ -108,15 +106,6 @@ namespace arch { v[1] = v[2] * math::cos(constant::TWO_PI * rand_X3); v[2] = v[2] * math::sin(constant::TWO_PI * rand_X3); - if constexpr (S == SimEngine::GRPIC) { - // convert from the tetrad basis to covariant - vec_t v_Hat; - v_Hat[0] = v[0]; - v_Hat[1] = v[1]; - v_Hat[2] = v[2]; - metric.template transform(x_Code, v_Hat, v); - } - pool.free_state(rand_gen); } @@ -223,9 +212,9 @@ namespace arch { (v[boost_dir] + boost_beta * gamma); } - Inline void operator()(const coord_t& x_Code, - vec_t& v, - unsigned short s = 0) const override { + Inline void operator()(const coord_t&, + vec_t& v, + unsigned short s = 0) const override { if (cmp::AlmostZero(temperature)) { v[0] = ZERO; v[1] = ZERO; @@ -233,14 +222,6 @@ namespace arch { } else { JS(v, temperature); } - if constexpr (S == SimEngine::GRPIC) { - // convert from the tetrad basis to covariant - vec_t v_Hat; - v_Hat[0] = v[0]; - v_Hat[1] = v[1]; - v_Hat[2] = v[2]; - metric.template transform(x_Code, v_Hat, v); - } if constexpr (M::CoordType == Coord::Cart) { // boost only when using cartesian coordinates if (not cmp::AlmostZero(boost_velocity)) { diff --git a/src/kernels/injectors.hpp b/src/kernels/injectors.hpp index dd5e2d21d..8cab09019 100644 --- a/src/kernels/injectors.hpp +++ b/src/kernels/injectors.hpp @@ -118,26 +118,26 @@ namespace kernel { metric.template convert(x_Cd, x_Ph); if constexpr (M::CoordType == Coord::Cart) { vec_t v_Ph { ZERO }; - energy_dist(x_Ph, v_Ph, spidx1); - metric.template transform_xyz(x_Ph, v_Ph, v1); - energy_dist(x_Ph, v_Ph, spidx2); - metric.template transform_xyz(x_Ph, v_Ph, v2); + energy_dist(x_Cd, v_Ph, spidx1); + metric.template transform_xyz(x_Cd, v_Ph, v1); + energy_dist(x_Cd, v_Ph, spidx2); + metric.template transform_xyz(x_Cd, v_Ph, v2); } else if constexpr (S == SimEngine::SRPIC) { - coord_t x_Ph_ { ZERO }; - x_Ph_[0] = x_Ph[0]; - x_Ph_[1] = x_Ph[1]; - x_Ph_[2] = ZERO; // phi = 0 + coord_t x_Cd_ { ZERO }; + x_Cd_[0] = x_Cd[0]; + x_Cd_[1] = x_Cd[1]; + x_Cd_[2] = ZERO; // phi = 0 vec_t v_Ph { ZERO }; energy_dist(x_Ph, v_Ph, spidx1); - metric.template transform_xyz(x_Ph_, v_Ph, v1); + metric.template transform_xyz(x_Cd_, v_Ph, v1); energy_dist(x_Ph, v_Ph, spidx2); - metric.template transform_xyz(x_Ph_, v_Ph, v2); + metric.template transform_xyz(x_Cd_, v_Ph, v2); } else if constexpr (S == SimEngine::GRPIC) { vec_t v_Ph { ZERO }; energy_dist(x_Ph, v_Ph, spidx1); - metric.template transform(x_Ph, v_Ph, v1); + metric.template transform(x_Cd, v_Ph, v1); energy_dist(x_Ph, v_Ph, spidx2); - metric.template transform(x_Ph, v_Ph, v2); + metric.template transform(x_Cd, v_Ph, v2); } else { raise::KernelError(HERE, "Unknown simulation engine"); } From 15ffa1b7a86d9e562d226320788882939b9a8758 Mon Sep 17 00:00:00 2001 From: haykh Date: Thu, 13 Mar 2025 01:56:06 -0400 Subject: [PATCH 442/773] types made uniform --- src/archetypes/energy_dist.h | 10 +- src/archetypes/particle_injector.h | 6 +- src/archetypes/spatial_dist.h | 12 +-- src/checkpoint/reader.cpp | 50 +++++----- src/checkpoint/reader.h | 12 +-- src/checkpoint/writer.cpp | 80 ++++++++-------- src/checkpoint/writer.h | 24 ++--- src/engines/engine.hpp | 27 +++--- src/engines/engine_init.cpp | 2 +- src/engines/engine_printer.cpp | 15 ++- src/engines/engine_run.cpp | 6 +- src/engines/srpic.hpp | 24 ++--- src/framework/containers/fields.cpp | 6 +- src/framework/containers/fields.h | 2 +- src/framework/containers/particles.cpp | 49 +++++----- src/framework/containers/particles.h | 18 ++-- src/framework/containers/species.h | 6 +- src/framework/domain/checkpoint.cpp | 30 +++--- src/framework/domain/comm_mpi.hpp | 38 ++++---- src/framework/domain/communications.cpp | 35 ++++--- src/framework/domain/domain.h | 12 +-- src/framework/domain/grid.cpp | 14 +-- src/framework/domain/grid.h | 20 ++-- src/framework/domain/mesh.h | 40 ++++---- src/framework/domain/metadomain.cpp | 18 ++-- src/framework/domain/metadomain.h | 18 ++-- src/framework/domain/output.cpp | 40 ++++---- src/framework/parameters.cpp | 46 +++++----- src/framework/parameters.h | 2 +- src/framework/simulation.cpp | 16 ++-- src/framework/tests/comm_mpi.cpp | 4 +- src/framework/tests/metadomain.cpp | 30 +++--- src/global/arch/directions.h | 10 +- src/global/arch/kokkos_aliases.cpp | 28 +++--- src/global/arch/kokkos_aliases.h | 23 +++-- src/global/defaults.h | 12 +-- src/global/enums.h | 4 +- src/global/global.h | 14 ++- src/global/utils/diag.cpp | 34 +++---- src/global/utils/diag.h | 14 +-- src/global/utils/param_container.cpp | 74 ++++++++------- src/global/utils/progressbar.cpp | 39 ++++---- src/global/utils/progressbar.h | 19 ++-- src/global/utils/timer.cpp | 24 ++--- src/global/utils/timer.h | 26 +++--- src/global/utils/tools.h | 58 ++++++------ src/kernels/ampere_gr.hpp | 20 ++-- src/kernels/ampere_sr.hpp | 40 ++++---- src/kernels/comm.hpp | 117 ++++++++++++------------ src/kernels/digital_filter.hpp | 6 +- src/kernels/faraday_gr.hpp | 2 +- src/kernels/faraday_sr.hpp | 6 +- src/kernels/fields_bcs.hpp | 18 ++-- src/kernels/injectors.hpp | 65 +++++++------ src/kernels/particle_moments.hpp | 2 +- src/kernels/prtls_to_phys.hpp | 4 +- src/metrics/kerr_schild.h | 2 +- src/metrics/kerr_schild_0.h | 4 +- src/metrics/metric_base.h | 2 +- src/metrics/minkowski.h | 7 +- src/metrics/qkerr_schild.h | 2 +- src/metrics/qspherical.h | 5 +- src/metrics/spherical.h | 7 +- src/output/fields.h | 2 +- src/output/tests/writer-nompi.cpp | 21 ++--- src/output/utils/attr_writer.h | 10 +- src/output/writer.cpp | 73 ++++++++------- src/output/writer.h | 24 ++--- 68 files changed, 779 insertions(+), 751 deletions(-) diff --git a/src/archetypes/energy_dist.h b/src/archetypes/energy_dist.h index e9bc9051a..231ea5b0b 100644 --- a/src/archetypes/energy_dist.h +++ b/src/archetypes/energy_dist.h @@ -78,14 +78,14 @@ namespace arch { real_t g_max, real_t pl_ind) : EnergyDistribution { metric } - , pool { pool } , g_min { g_min } , g_max { g_max } - , pl_ind { pl_ind } {} + , pl_ind { pl_ind } + , pool { pool } {} Inline void operator()(const coord_t& x_Code, vec_t& v, - unsigned short sp = 0) const override { + unsigned short = 0) const override { auto rand_gen = pool.get_state(); auto rand_X1 = Random(rand_gen); auto rand_gam = ONE; @@ -225,7 +225,7 @@ namespace arch { Inline void operator()(const coord_t& x_Code, vec_t& v, - unsigned short s = 0) const override { + unsigned short sp = 0) const override { if (cmp::AlmostZero(temperature)) { v[0] = ZERO; v[1] = ZERO; @@ -245,7 +245,7 @@ namespace arch { // boost only when using cartesian coordinates if (not cmp::AlmostZero(boost_velocity)) { boost(v); - if (not zero_current and s % 2 == 0) { + if (not zero_current and sp % 2 == 0) { v[0] = -v[0]; v[1] = -v[1]; v[2] = -v[2]; diff --git a/src/archetypes/particle_injector.h b/src/archetypes/particle_injector.h index cbcbbd389..3884e6ced 100644 --- a/src/archetypes/particle_injector.h +++ b/src/archetypes/particle_injector.h @@ -208,13 +208,13 @@ namespace arch { auto ppc0 = params.template get("particles.ppc0"); array_t ni { "ni", M::Dim }; auto ni_h = Kokkos::create_mirror_view(ni); - std::size_t ncells = 1; + ncells_t ncells = 1; for (auto d = 0; d < M::Dim; ++d) { ni_h(d) = domain.mesh.n_active()[d]; ncells *= domain.mesh.n_active()[d]; } Kokkos::deep_copy(ni, ni_h); - const auto nparticles = static_cast( + const auto nparticles = static_cast( (long double)(ppc0 * number_density * 0.5) * (long double)(ncells)); Kokkos::parallel_for( @@ -320,7 +320,7 @@ namespace arch { incl_ghosts.push_back({ false, false }); } const auto extent = domain.mesh.ExtentToRange(box, incl_ghosts); - tuple_t x_min { 0 }, x_max { 0 }; + tuple_t x_min { 0 }, x_max { 0 }; for (auto d = 0; d < M::Dim; ++d) { x_min[d] = extent[d].first; x_max[d] = extent[d].second; diff --git a/src/archetypes/spatial_dist.h b/src/archetypes/spatial_dist.h index be2836da2..d036c0166 100644 --- a/src/archetypes/spatial_dist.h +++ b/src/archetypes/spatial_dist.h @@ -74,15 +74,15 @@ namespace arch { metric.template convert(x_Ph, x_Cd); real_t dens { ZERO }; if constexpr (M::Dim == Dim::_1D) { - dens = density(static_cast(x_Cd[0]) + N_GHOSTS, idx); + dens = density(static_cast(x_Cd[0]) + N_GHOSTS, idx); } else if constexpr (M::Dim == Dim::_2D) { - dens = density(static_cast(x_Cd[0]) + N_GHOSTS, - static_cast(x_Cd[1]) + N_GHOSTS, + dens = density(static_cast(x_Cd[0]) + N_GHOSTS, + static_cast(x_Cd[1]) + N_GHOSTS, idx); } else if constexpr (M::Dim == Dim::_3D) { - dens = density(static_cast(x_Cd[0]) + N_GHOSTS, - static_cast(x_Cd[1]) + N_GHOSTS, - static_cast(x_Cd[2]) + N_GHOSTS, + dens = density(static_cast(x_Cd[0]) + N_GHOSTS, + static_cast(x_Cd[1]) + N_GHOSTS, + static_cast(x_Cd[2]) + N_GHOSTS, idx); } else { raise::KernelError(HERE, "Invalid dimension"); diff --git a/src/checkpoint/reader.cpp b/src/checkpoint/reader.cpp index 9fc2d2640..6e32cb3b9 100644 --- a/src/checkpoint/reader.cpp +++ b/src/checkpoint/reader.cpp @@ -40,15 +40,13 @@ namespace checkpoint { } } - auto ReadParticleCount( - adios2::IO& io, - adios2::Engine& reader, - unsigned short s, - std::size_t local_dom, - std::size_t ndomains) -> std::pair { + auto ReadParticleCount(adios2::IO& io, + adios2::Engine& reader, + unsigned short s, + std::size_t local_dom, + std::size_t ndomains) -> std::pair { logger::Checkpoint(fmt::format("Reading particle count for: %d", s + 1), HERE); - auto npart_var = io.InquireVariable( - fmt::format("s%d_npart", s + 1)); + auto npart_var = io.InquireVariable(fmt::format("s%d_npart", s + 1)); if (npart_var) { raise::ErrorIf(npart_var.Shape()[0] != ndomains, "npart_var.Shape()[0] != ndomains", @@ -57,21 +55,21 @@ namespace checkpoint { "npart_var.Shape().size() != 1", HERE); npart_var.SetSelection(adios2::Box({ local_dom }, { 1 })); - std::size_t npart; + npart_t npart; reader.Get(npart_var, &npart, adios2::Mode::Sync); const auto loc_npart = npart; #if !defined(MPI_ENABLED) - std::size_t offset_npart = 0; + npart_t offset_npart = 0; #else - std::vector glob_nparts(ndomains); + std::vector glob_nparts(ndomains); MPI_Allgather(&loc_npart, 1, - mpi::get_type(), + mpi::get_type(), glob_nparts.data(), 1, - mpi::get_type(), + mpi::get_type(), MPI_COMM_WORLD); - std::size_t offset_npart = 0; + npart_t offset_npart = 0; for (auto d { 0u }; d < local_dom; ++d) { offset_npart += glob_nparts[d]; } @@ -89,8 +87,8 @@ namespace checkpoint { const std::string& quantity, unsigned short s, array_t& array, - std::size_t count, - std::size_t offset) { + npart_t count, + npart_t offset) { logger::Checkpoint( fmt::format("Reading quantity: s%d_%s", s + 1, quantity.c_str()), HERE); @@ -115,8 +113,8 @@ namespace checkpoint { unsigned short s, array_t& array, std::size_t nplds, - std::size_t count, - std::size_t offset) { + npart_t count, + npart_t offset) { logger::Checkpoint(fmt::format("Reading quantity: s%d_plds", s + 1), HERE); auto var = io.InquireVariable(fmt::format("s%d_plds", s + 1)); if (var) { @@ -168,28 +166,28 @@ namespace checkpoint { const std::string&, unsigned short, array_t&, - std::size_t, - std::size_t); + npart_t, + npart_t); template void ReadParticleData(adios2::IO&, adios2::Engine&, const std::string&, unsigned short, array_t&, - std::size_t, - std::size_t); + npart_t, + npart_t); template void ReadParticleData(adios2::IO&, adios2::Engine&, const std::string&, unsigned short, array_t&, - std::size_t, - std::size_t); + npart_t, + npart_t); template void ReadParticleData(adios2::IO&, adios2::Engine&, const std::string&, unsigned short, array_t&, - std::size_t, - std::size_t); + npart_t, + npart_t); } // namespace checkpoint diff --git a/src/checkpoint/reader.h b/src/checkpoint/reader.h index e5a91ab75..883a1d125 100644 --- a/src/checkpoint/reader.h +++ b/src/checkpoint/reader.h @@ -4,7 +4,7 @@ * @implements * - checkpoint::ReadFields -> void * - checkpoint::ReadParticleData -> void - * - checkpoint::ReadParticleCount -> std::pair + * - checkpoint::ReadParticleCount -> std::pair * @cpp: * - reader.cpp * @namespaces: @@ -34,7 +34,7 @@ namespace checkpoint { adios2::Engine&, unsigned short, std::size_t, - std::size_t) -> std::pair; + std::size_t) -> std::pair; template void ReadParticleData(adios2::IO&, @@ -42,16 +42,16 @@ namespace checkpoint { const std::string&, unsigned short, array_t&, - std::size_t, - std::size_t); + npart_t, + npart_t); void ReadParticlePayloads(adios2::IO&, adios2::Engine&, unsigned short, array_t&, std::size_t, - std::size_t, - std::size_t); + npart_t, + npart_t); } // namespace checkpoint diff --git a/src/checkpoint/writer.cpp b/src/checkpoint/writer.cpp index a12e3ef26..c5f7e5181 100644 --- a/src/checkpoint/writer.cpp +++ b/src/checkpoint/writer.cpp @@ -21,8 +21,8 @@ namespace checkpoint { void Writer::init(adios2::ADIOS* ptr_adios, - std::size_t interval, - long double interval_time, + timestep_t interval, + simtime_t interval_time, int keep) { m_keep = keep; m_enabled = keep != 0; @@ -36,8 +36,8 @@ namespace checkpoint { m_io = p_adios->DeclareIO("Entity::Checkpoint"); m_io.SetEngine("BPFile"); - m_io.DefineVariable("Step"); - m_io.DefineVariable("Time"); + m_io.DefineVariable("Step"); + m_io.DefineVariable("Time"); m_io.DefineAttribute("NGhosts", ntt::N_GHOSTS); CallOnce([]() { @@ -48,13 +48,13 @@ namespace checkpoint { }); } - void Writer::defineFieldVariables(const ntt::SimEngine& S, - const std::vector& glob_shape, - const std::vector& loc_corner, - const std::vector& loc_shape) { - auto gs6 = std::vector(glob_shape.begin(), glob_shape.end()); - auto lc6 = std::vector(loc_corner.begin(), loc_corner.end()); - auto ls6 = std::vector(loc_shape.begin(), loc_shape.end()); + void Writer::defineFieldVariables(const ntt::SimEngine& S, + const std::vector& glob_shape, + const std::vector& loc_corner, + const std::vector& loc_shape) { + auto gs6 = std::vector(glob_shape.begin(), glob_shape.end()); + auto lc6 = std::vector(loc_corner.begin(), loc_corner.end()); + auto ls6 = std::vector(loc_shape.begin(), loc_shape.end()); gs6.push_back(6); lc6.push_back(0); ls6.push_back(6); @@ -62,9 +62,9 @@ namespace checkpoint { m_io.DefineVariable("em", gs6, lc6, ls6); if (S == ntt::SimEngine::GRPIC) { m_io.DefineVariable("em0", gs6, lc6, ls6); - auto gs3 = std::vector(glob_shape.begin(), glob_shape.end()); - auto lc3 = std::vector(loc_corner.begin(), loc_corner.end()); - auto ls3 = std::vector(loc_shape.begin(), loc_shape.end()); + auto gs3 = std::vector(glob_shape.begin(), glob_shape.end()); + auto lc3 = std::vector(loc_corner.begin(), loc_corner.end()); + auto ls3 = std::vector(loc_shape.begin(), loc_shape.end()); gs3.push_back(3); lc3.push_back(0); ls3.push_back(3); @@ -80,10 +80,10 @@ namespace checkpoint { "Number of payloads does not match the number of species", HERE); for (auto s { 0u }; s < nspec; ++s) { - m_io.DefineVariable(fmt::format("s%d_npart", s + 1), - { adios2::UnknownDim }, - { adios2::UnknownDim }, - { adios2::UnknownDim }); + m_io.DefineVariable(fmt::format("s%d_npart", s + 1), + { adios2::UnknownDim }, + { adios2::UnknownDim }, + { adios2::UnknownDim }); for (auto d { 0u }; d < dim; ++d) { m_io.DefineVariable(fmt::format("s%d_i%d", s + 1, d + 1), @@ -135,11 +135,11 @@ namespace checkpoint { } } - auto Writer::shouldSave(std::size_t step, long double time) -> bool { + auto Writer::shouldSave(timestep_t step, simtime_t time) -> bool { return m_enabled and m_tracker.shouldWrite(step, time); } - void Writer::beginSaving(std::size_t step, long double time) { + void Writer::beginSaving(timestep_t step, simtime_t time) { raise::ErrorIf(!m_enabled, "Checkpoint is not enabled", HERE); raise::ErrorIf(p_adios == nullptr, "ADIOS pointer is null", HERE); if (m_writing_mode) { @@ -160,8 +160,8 @@ namespace checkpoint { } m_writer.BeginStep(); - m_writer.Put(m_io.InquireVariable("Step"), &step); - m_writer.Put(m_io.InquireVariable("Time"), &time); + m_writer.Put(m_io.InquireVariable("Step"), &step); + m_writer.Put(m_io.InquireVariable("Time"), &time); } void Writer::endSaving() { @@ -226,9 +226,9 @@ namespace checkpoint { template void Writer::saveParticleQuantity(const std::string& quantity, - std::size_t glob_total, - std::size_t loc_offset, - std::size_t loc_size, + npart_t glob_total, + npart_t loc_offset, + npart_t loc_size, const array_t& data) { const auto slice = range_tuple_t(0, loc_size); auto var = m_io.InquireVariable(quantity); @@ -244,9 +244,9 @@ namespace checkpoint { void Writer::saveParticlePayloads(const std::string& quantity, std::size_t nplds, - std::size_t glob_total, - std::size_t loc_offset, - std::size_t loc_size, + npart_t glob_total, + npart_t loc_offset, + npart_t loc_size, const array_t& data) { const auto slice = range_tuple_t(0, loc_size); auto var = m_io.InquireVariable(quantity); @@ -292,23 +292,23 @@ namespace checkpoint { const ndfield_t&); template void Writer::saveParticleQuantity(const std::string&, - std::size_t, - std::size_t, - std::size_t, + npart_t, + npart_t, + npart_t, const array_t&); template void Writer::saveParticleQuantity(const std::string&, - std::size_t, - std::size_t, - std::size_t, + npart_t, + npart_t, + npart_t, const array_t&); template void Writer::saveParticleQuantity(const std::string&, - std::size_t, - std::size_t, - std::size_t, + npart_t, + npart_t, + npart_t, const array_t&); template void Writer::saveParticleQuantity(const std::string&, - std::size_t, - std::size_t, - std::size_t, + npart_t, + npart_t, + npart_t, const array_t&); } // namespace checkpoint diff --git a/src/checkpoint/writer.h b/src/checkpoint/writer.h index 346bee24a..992c54c96 100644 --- a/src/checkpoint/writer.h +++ b/src/checkpoint/writer.h @@ -47,11 +47,11 @@ namespace checkpoint { ~Writer() = default; - void init(adios2::ADIOS*, std::size_t, long double, int); + void init(adios2::ADIOS*, timestep_t, simtime_t, int); - auto shouldSave(std::size_t, long double) -> bool; + auto shouldSave(timestep_t, simtime_t) -> bool; - void beginSaving(std::size_t, long double); + void beginSaving(timestep_t, simtime_t); void endSaving(); void saveAttrs(const ntt::SimulationParams&, long double); @@ -64,22 +64,22 @@ namespace checkpoint { template void saveParticleQuantity(const std::string&, - std::size_t, - std::size_t, - std::size_t, + npart_t, + npart_t, + npart_t, const array_t&); void saveParticlePayloads(const std::string&, std::size_t, - std::size_t, - std::size_t, - std::size_t, + npart_t, + npart_t, + npart_t, const array_t&); void defineFieldVariables(const ntt::SimEngine&, - const std::vector&, - const std::vector&, - const std::vector&); + const std::vector&, + const std::vector&, + const std::vector&); void defineParticleVariables(const ntt::Coord&, Dimension, diff --git a/src/engines/engine.hpp b/src/engines/engine.hpp index dac553dcd..9525874a6 100644 --- a/src/engines/engine.hpp +++ b/src/engines/engine.hpp @@ -67,14 +67,14 @@ namespace ntt { Metadomain m_metadomain; user::PGen m_pgen; - const bool is_resuming; - const long double runtime; - const real_t dt; - const std::size_t max_steps; - const std::size_t start_step; - const long double start_time; - long double time; - std::size_t step; + const bool is_resuming; + const simtime_t runtime; + const real_t dt; + const timestep_t max_steps; + const timestep_t start_step; + const simtime_t start_time; + simtime_t time; + timestep_t step; public: static constexpr bool pgen_is_ok { @@ -91,8 +91,7 @@ namespace ntt { , m_metadomain { m_params.get("simulation.domain.number"), m_params.get>( "simulation.domain.decomposition"), - m_params.get>( - "grid.resolution"), + m_params.get>("grid.resolution"), m_params.get>("grid.extent"), m_params.get>( "grid.boundaries.fields"), @@ -104,11 +103,11 @@ namespace ntt { "particles.species") } , m_pgen { m_params, m_metadomain } , is_resuming { m_params.get("checkpoint.is_resuming") } - , runtime { m_params.get("simulation.runtime") } + , runtime { m_params.get("simulation.runtime") } , dt { m_params.get("algorithms.timestep.dt") } - , max_steps { static_cast(runtime / dt) } - , start_step { m_params.get("checkpoint.start_step") } - , start_time { m_params.get("checkpoint.start_time") } + , max_steps { static_cast(runtime / dt) } + , start_step { m_params.get("checkpoint.start_step") } + , start_time { m_params.get("checkpoint.start_time") } , time { start_time } , step { start_step } { raise::ErrorIf(not pgen_is_ok, "Problem generator is not compatible with the picked engine/metric/dimension", HERE); diff --git a/src/engines/engine_init.cpp b/src/engines/engine_init.cpp index 0239724e1..7ce242bc6 100644 --- a/src/engines/engine_init.cpp +++ b/src/engines/engine_init.cpp @@ -53,7 +53,7 @@ namespace ntt { #if defined(OUTPUT_ENABLED) // read simulation data from the checkpoint raise::ErrorIf( - m_params.template get("checkpoint.start_step") == 0, + m_params.template get("checkpoint.start_step") == 0, "Resuming simulation from a checkpoint requires a valid start_step", HERE); logger::Checkpoint("Resuming simulation from a checkpoint", HERE); diff --git a/src/engines/engine_printer.cpp b/src/engines/engine_printer.cpp index 2a7ee4405..c1a36a323 100644 --- a/src/engines/engine_printer.cpp +++ b/src/engines/engine_printer.cpp @@ -38,7 +38,7 @@ namespace ntt { color::BRIGHT_BLACK, fmt::repeat("═", 58).c_str(), color::RESET); - for (std::size_t i { 0 }; i < lines.size(); ++i) { + for (auto i { 0u }; i < lines.size(); ++i) { report += fmt::format("%s║%s %s%s%s%s%s║%s\n", color::BRIGHT_BLACK, color::RESET, @@ -108,7 +108,7 @@ namespace ntt { auto bytes_to_human_readable( std::size_t bytes) -> std::pair { const std::vector units { "B", "KB", "MB", "GB", "TB" }; - std::size_t unit_idx = 0; + idx_t unit_idx = 0; auto size = static_cast(bytes); while ((size >= 1024) && (unit_idx < units.size() - 1)) { size /= 1024; @@ -236,12 +236,11 @@ namespace ntt { add_param(report, 4, "Runtime", "%.3Le [%d steps]", runtime, max_steps); report += "\n"; add_category(report, 4, "Global domain"); - add_param( - report, - 4, - "Resolution", - "%s", - params.template stringize("grid.resolution").c_str()); + add_param(report, + 4, + "Resolution", + "%s", + params.template stringize("grid.resolution").c_str()); add_param(report, 4, "Extent", diff --git a/src/engines/engine_run.cpp b/src/engines/engine_run.cpp index 506fd121d..2d4b0d5ed 100644 --- a/src/engines/engine_run.cpp +++ b/src/engines/engine_run.cpp @@ -34,11 +34,11 @@ namespace ntt { }, m_params.get("diagnostics.blocking_timers") }; - const auto diag_interval = m_params.get( + const auto diag_interval = m_params.get( "diagnostics.interval"); auto time_history = pbar::DurationHistory { 1000 }; - const auto clear_interval = m_params.template get( + const auto clear_interval = m_params.template get( "particles.clear_interval"); // main algorithm loop @@ -71,7 +71,7 @@ namespace ntt { traits::has_method::value) { auto lambda_custom_field_output = [&](const std::string& name, ndfield_t& buff, - std::size_t idx, + index_t idx, const Domain& dom) { m_pgen.CustomFieldOutput(name, buff, idx, dom); }; diff --git a/src/engines/srpic.hpp b/src/engines/srpic.hpp index 9f5e4551f..0a9cc311b 100644 --- a/src/engines/srpic.hpp +++ b/src/engines/srpic.hpp @@ -79,7 +79,7 @@ namespace ntt { "algorithms.toggles.fieldsolver"); const auto deposit_enabled = m_params.template get( "algorithms.toggles.deposit"); - const auto clear_interval = m_params.template get( + const auto clear_interval = m_params.template get( "particles.clear_interval"); if (step == 0) { @@ -558,7 +558,7 @@ namespace ntt { auto range = range_with_axis_BCs(domain); const auto nfilter = m_params.template get( "algorithms.current_filters"); - tuple_t size; + tuple_t size; if constexpr (M::Dim == Dim::_1D || M::Dim == Dim::_2D || M::Dim == Dim::_3D) { size[0] = domain.mesh.n_active(in::x1); } @@ -644,8 +644,8 @@ namespace ntt { return; } const auto intersect_range = domain.mesh.ExtentToRange(box, incl_ghosts); - tuple_t range_min { 0 }; - tuple_t range_max { 0 }; + tuple_t range_min { 0 }; + tuple_t range_max { 0 }; for (unsigned short d { 0 }; d < M::Dim; ++d) { range_min[d] = intersect_range[d].first; @@ -757,8 +757,8 @@ namespace ntt { } else { raise::Error("Invalid dimension", HERE); } - std::vector xi_min, xi_max; - const std::vector all_dirs { in::x1, in::x2, in::x3 }; + std::vector xi_min, xi_max; + const std::vector all_dirs { in::x1, in::x2, in::x3 }; for (unsigned short d { 0 }; d < static_cast(M::Dim); ++d) { const auto dd = all_dirs[d]; if (dim == dd) { @@ -862,15 +862,15 @@ namespace ntt { return; } const auto intersect_range = domain.mesh.ExtentToRange(box, incl_ghosts); - tuple_t range_min { 0 }; - tuple_t range_max { 0 }; + tuple_t range_min { 0 }; + tuple_t range_max { 0 }; for (unsigned short d { 0 }; d < M::Dim; ++d) { range_min[d] = intersect_range[d].first; range_max[d] = intersect_range[d].second; } - auto atm_fields = m_pgen.AtmFields(time); - std::size_t il_edge; + auto atm_fields = m_pgen.AtmFields(time); + ncells_t il_edge; if (sign > 0) { il_edge = range_min[dd] - N_GHOSTS; } else { @@ -1202,8 +1202,8 @@ namespace ntt { "possible only in -x1 (@ rmin)", HERE); } - real_t xg_min { ZERO }, xg_max { ZERO }; - std::size_t ig_min, ig_max; + real_t xg_min { ZERO }, xg_max { ZERO }; + ncells_t ig_min, ig_max; if (sign > 0) { // + direction ig_min = m_metadomain.mesh().n_active(dim) - buffer_ncells; ig_max = m_metadomain.mesh().n_active(dim); diff --git a/src/framework/containers/fields.cpp b/src/framework/containers/fields.cpp index a62886b06..7202ff282 100644 --- a/src/framework/containers/fields.cpp +++ b/src/framework/containers/fields.cpp @@ -8,8 +8,8 @@ namespace ntt { template - Fields::Fields(const std::vector& res) { - std::size_t nx1, nx2, nx3; + Fields::Fields(const std::vector& res) { + ncells_t nx1, nx2, nx3; nx1 = res[0] + 2 * N_GHOSTS; if constexpr ((D == Dim::_3D) || (D == Dim::_2D)) { nx2 = res[1] + 2 * N_GHOSTS; @@ -52,4 +52,4 @@ namespace ntt { template struct Fields; template struct Fields; -} // namespace ntt \ No newline at end of file +} // namespace ntt diff --git a/src/framework/containers/fields.h b/src/framework/containers/fields.h index d0bd7d020..ee9d656d6 100644 --- a/src/framework/containers/fields.h +++ b/src/framework/containers/fields.h @@ -109,7 +109,7 @@ namespace ntt { */ Fields() {} - Fields(const std::vector& res); + Fields(const std::vector& res); Fields(Fields&& other) noexcept : em { std::move(other.em) } diff --git a/src/framework/containers/particles.cpp b/src/framework/containers/particles.cpp index d78055824..048d57cde 100644 --- a/src/framework/containers/particles.cpp +++ b/src/framework/containers/particles.cpp @@ -25,7 +25,7 @@ namespace ntt { const std::string& label, float m, float ch, - std::size_t maxnpart, + npart_t maxnpart, const PrtlPusher& pusher, bool use_gca, const Cooling& cooling, @@ -72,10 +72,10 @@ namespace ntt { template auto Particles::NpartsPerTagAndOffsets() const - -> std::pair, array_t> { - auto this_tag = tag; - const auto num_tags = ntags(); - array_t npptag { "nparts_per_tag", ntags() }; + -> std::pair, array_t> { + auto this_tag = tag; + const auto num_tags = ntags(); + array_t npptag { "nparts_per_tag", ntags() }; // count # of particles per each tag auto npptag_scat = Kokkos::Experimental::create_scatter_view(npptag); @@ -94,14 +94,14 @@ namespace ntt { // copy the count to a vector on the host auto npptag_h = Kokkos::create_mirror_view(npptag); Kokkos::deep_copy(npptag_h, npptag); - std::vector npptag_vec(num_tags); + std::vector npptag_vec(num_tags); for (auto t { 0u }; t < num_tags; ++t) { npptag_vec[t] = npptag_h(t); } // count the offsets on the host and copy to device - array_t tag_offsets("tag_offsets", num_tags - 3); - auto tag_offsets_h = Kokkos::create_mirror_view(tag_offsets); + array_t tag_offsets("tag_offsets", num_tags - 3); + auto tag_offsets_h = Kokkos::create_mirror_view(tag_offsets); tag_offsets_h(0) = npptag_vec[2]; // offset for tag = 3 for (auto t { 1u }; t < num_tags - 3; ++t) { @@ -113,25 +113,23 @@ namespace ntt { } template - void RemoveDeadInArray(array_t& arr, - const array_t& indices_alive) { - auto n_alive = indices_alive.extent(0); - auto buffer = Kokkos::View("buffer", n_alive); + void RemoveDeadInArray(array_t& arr, const array_t& indices_alive) { + npart_t n_alive = indices_alive.extent(0); + auto buffer = Kokkos::View("buffer", n_alive); Kokkos::parallel_for( "PopulateBufferAlive", n_alive, Lambda(index_t p) { buffer(p) = arr(indices_alive(p)); }); Kokkos::deep_copy( - Kokkos::subview(arr, std::make_pair(static_cast(0), n_alive)), + Kokkos::subview(arr, std::make_pair(static_cast(0), n_alive)), buffer); } template - void RemoveDeadInArray(array_t& arr, - const array_t& indices_alive) { - auto n_alive = indices_alive.extent(0); - auto buffer = array_t { "buffer", n_alive, arr.extent(1) }; + void RemoveDeadInArray(array_t& arr, const array_t& indices_alive) { + npart_t n_alive = indices_alive.extent(0); + auto buffer = array_t { "buffer", n_alive, arr.extent(1) }; Kokkos::parallel_for( "PopulateBufferAlive", CreateRangePolicy({ 0, 0 }, { n_alive, arr.extent(1) }), @@ -139,21 +137,21 @@ namespace ntt { Kokkos::deep_copy( Kokkos::subview(arr, - std::make_pair(static_cast(0), n_alive), + std::make_pair(static_cast(0), n_alive), Kokkos::ALL), buffer); } template void Particles::RemoveDead() { - const auto n_part = npart(); - std::size_t n_alive = 0, n_dead = 0; - auto& this_tag = tag; + const auto n_part = npart(); + npart_t n_alive = 0, n_dead = 0; + auto& this_tag = tag; Kokkos::parallel_reduce( "CountDeadAlive", rangeActiveParticles(), - Lambda(index_t p, std::size_t & nalive, std::size_t & ndead) { + Lambda(index_t p, npart_t & nalive, npart_t & ndead) { nalive += (this_tag(p) == ParticleTag::alive); ndead += (this_tag(p) == ParticleTag::dead); if (this_tag(p) != ParticleTag::alive and this_tag(p) != ParticleTag::dead) { @@ -163,8 +161,8 @@ namespace ntt { n_alive, n_dead); - array_t indices_alive { "indices_alive", n_alive }; - array_t alive_counter { "counter_alive", 1 }; + array_t indices_alive { "indices_alive", n_alive }; + array_t alive_counter { "counter_alive", 1 }; Kokkos::parallel_for( "AliveIndices", @@ -221,8 +219,7 @@ namespace ntt { Kokkos::Experimental::fill( "TagAliveParticles", AccelExeSpace(), - Kokkos::subview(this_tag, - std::make_pair(static_cast(0), n_alive)), + Kokkos::subview(this_tag, std::make_pair(static_cast(0), n_alive)), ParticleTag::alive); Kokkos::Experimental::fill( diff --git a/src/framework/containers/particles.h b/src/framework/containers/particles.h index d84bd0cc9..5241822e2 100644 --- a/src/framework/containers/particles.h +++ b/src/framework/containers/particles.h @@ -37,8 +37,8 @@ namespace ntt { struct Particles : public ParticleSpecies { private: // Number of currently active (used) particles - std::size_t m_npart { 0 }; - bool m_is_sorted { false }; + npart_t m_npart { 0 }; + bool m_is_sorted { false }; #if !defined(MPI_ENABLED) const std::size_t m_ntags { 2 }; @@ -84,7 +84,7 @@ namespace ntt { const std::string& label, float m, float ch, - std::size_t maxnpart, + npart_t maxnpart, const PrtlPusher& pusher, bool use_gca, const Cooling& cooling, @@ -116,7 +116,7 @@ namespace ntt { * @returns A 1D Kokkos range policy of size of `npart` */ inline auto rangeActiveParticles() const -> range_t { - return CreateRangePolicy({ 0 }, { npart() }); + return CreateParticleRangePolicy(0u, npart()); } /** @@ -124,7 +124,7 @@ namespace ntt { * @returns A 1D Kokkos range policy of size of `npart` */ inline auto rangeAllParticles() const -> range_t { - return CreateRangePolicy({ 0 }, { maxnpart() }); + return CreateParticleRangePolicy(0u, maxnpart()); } /* getters -------------------------------------------------------------- */ @@ -132,7 +132,7 @@ namespace ntt { * @brief Get the number of active particles */ [[nodiscard]] - auto npart() const -> std::size_t { + auto npart() const -> npart_t { return m_npart; } @@ -188,14 +188,14 @@ namespace ntt { * ... etc. */ auto NpartsPerTagAndOffsets() const - -> std::pair, array_t>; + -> std::pair, array_t>; /* setters -------------------------------------------------------------- */ /** * @brief Set the number of particles - * @param npart The number of particles as a std::size_t + * @param npart The number of particles as a npart_t */ - void set_npart(std::size_t n) { + void set_npart(npart_t n) { raise::ErrorIf( n > maxnpart(), fmt::format( diff --git a/src/framework/containers/species.h b/src/framework/containers/species.h index 1f52733aa..6dd437819 100644 --- a/src/framework/containers/species.h +++ b/src/framework/containers/species.h @@ -28,7 +28,7 @@ namespace ntt { // Species charge in units of q0 const float m_charge; // Max number of allocated particles for the species - std::size_t m_maxnpart; + npart_t m_maxnpart; // Pusher assigned for the species const PrtlPusher m_pusher; @@ -68,7 +68,7 @@ namespace ntt { const std::string& label, float m, float ch, - std::size_t maxnpart, + npart_t maxnpart, const PrtlPusher& pusher, bool use_gca, const Cooling& cooling, @@ -111,7 +111,7 @@ namespace ntt { } [[nodiscard]] - auto maxnpart() const -> std::size_t { + auto maxnpart() const -> npart_t { return m_maxnpart; } diff --git a/src/framework/domain/checkpoint.cpp b/src/framework/domain/checkpoint.cpp index 6dfb137db..978a1ad10 100644 --- a/src/framework/domain/checkpoint.cpp +++ b/src/framework/domain/checkpoint.cpp @@ -32,7 +32,7 @@ namespace ntt { "local_domain is a placeholder", HERE); - std::vector glob_shape_with_ghosts, off_ncells_with_ghosts; + std::vector glob_shape_with_ghosts, off_ncells_with_ghosts; for (auto d { 0u }; d < M::Dim; ++d) { off_ncells_with_ghosts.push_back( local_domain->offset_ncells()[d] + @@ -49,8 +49,8 @@ namespace ntt { g_checkpoint_writer.init( ptr_adios, - params.template get("checkpoint.interval"), - params.template get("checkpoint.interval_time"), + params.template get("checkpoint.interval"), + params.template get("checkpoint.interval_time"), params.template get("checkpoint.keep")); if (g_checkpoint_writer.enabled()) { g_checkpoint_writer.defineFieldVariables(S, @@ -66,10 +66,10 @@ namespace ntt { template auto Metadomain::WriteCheckpoint(const SimulationParams& params, - std::size_t current_step, - std::size_t finished_step, - long double current_time, - long double finished_time) -> bool { + timestep_t current_step, + timestep_t finished_step, + simtime_t current_time, + simtime_t finished_time) -> bool { raise::ErrorIf( l_subdomain_indices().size() != 1, "Checkpointing for now is only supported for one subdomain per rank", @@ -98,17 +98,17 @@ namespace ntt { #endif // MPI_ENABLED for (auto s { 0u }; s < local_domain->species.size(); ++s) { - auto npart = local_domain->species[s].npart(); - std::size_t offset = 0; - auto glob_tot = npart; + auto npart = local_domain->species[s].npart(); + npart_t offset = 0; + auto glob_tot = npart; #if defined(MPI_ENABLED) - auto glob_npart = std::vector(g_ndomains); + auto glob_npart = std::vector(g_ndomains); MPI_Allgather(&npart, 1, - mpi::get_type(), + mpi::get_type(), glob_npart.data(), 1, - mpi::get_type(), + mpi::get_type(), MPI_COMM_WORLD); glob_tot = 0; for (auto r = 0; r < g_mpi_size; ++r) { @@ -118,7 +118,7 @@ namespace ntt { glob_tot += glob_npart[r]; } #endif // MPI_ENABLED - g_checkpoint_writer.savePerDomainVariable( + g_checkpoint_writer.savePerDomainVariable( fmt::format("s%d_npart", s + 1), dom_tot, dom_offset, @@ -263,7 +263,7 @@ namespace ntt { raise::ErrorIf(ptr_adios == nullptr, "adios == nullptr", HERE); auto fname = fmt::format( "checkpoints/step-%08lu.bp", - params.template get("checkpoint.start_step")); + params.template get("checkpoint.start_step")); logger::Checkpoint(fmt::format("Reading checkpoint from %s", fname.c_str()), HERE); diff --git a/src/framework/domain/comm_mpi.hpp b/src/framework/domain/comm_mpi.hpp index e5bc2d21e..8c6e532de 100644 --- a/src/framework/domain/comm_mpi.hpp +++ b/src/framework/domain/comm_mpi.hpp @@ -129,7 +129,7 @@ namespace comm { } } } else { - std::size_t nsend { comps.second - comps.first }, + ncells_t nsend { comps.second - comps.first }, nrecv { comps.second - comps.first }; ndarray_t(D) + 1> send_fld, recv_fld; @@ -287,29 +287,29 @@ namespace comm { } } - void ParticleSendRecvCount(int send_rank, - int recv_rank, - std::size_t send_count, - std::size_t& recv_count) { + void ParticleSendRecvCount(int send_rank, + int recv_rank, + npart_t send_count, + npart_t& recv_count) { if ((send_rank >= 0) && (recv_rank >= 0)) { MPI_Sendrecv(&send_count, 1, - mpi::get_type(), + mpi::get_type(), send_rank, 0, &recv_count, 1, - mpi::get_type(), + mpi::get_type(), recv_rank, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE); } else if (send_rank >= 0) { - MPI_Send(&send_count, 1, mpi::get_type(), send_rank, 0, MPI_COMM_WORLD); + MPI_Send(&send_count, 1, mpi::get_type(), send_rank, 0, MPI_COMM_WORLD); } else if (recv_rank >= 0) { MPI_Recv(&recv_count, 1, - mpi::get_type(), + mpi::get_type(), recv_rank, 0, MPI_COMM_WORLD, @@ -320,14 +320,14 @@ namespace comm { } template - void CommunicateParticles(Particles& species, - const array_t& outgoing_indices, - const array_t& tag_offsets, - const std::vector& npptag_vec, - const std::vector& npptag_recv_vec, - const std::vector& send_ranks, - const std::vector& recv_ranks, - const dir::dirs_t& dirs_to_comm) { + void CommunicateParticles(Particles& species, + const array_t& outgoing_indices, + const array_t& tag_offsets, + const std::vector& npptag_vec, + const std::vector& npptag_recv_vec, + const std::vector& send_ranks, + const std::vector& recv_ranks, + const dir::dirs_t& dirs_to_comm) { // number of arrays of each type to send/recv const unsigned short NREALS = 4 + static_cast( D == Dim::_2D and C != Coord::Cart); @@ -341,7 +341,7 @@ namespace comm { const auto npart_send = outgoing_indices.extent(0) - npart_dead; const auto npart_recv = std::accumulate(npptag_recv_vec.begin(), npptag_recv_vec.end(), - static_cast(0)); + static_cast(0)); array_t recv_buff_int { "recv_buff_int", npart_recv * NINTS }; array_t recv_buff_real { "recv_buff_real", npart_recv * NREALS }; array_t recv_buff_prtldx { "recv_buff_prtldx", npart_recv * NPRTLDX }; @@ -376,7 +376,7 @@ namespace comm { auto tag_offsets_h = Kokkos::create_mirror_view(tag_offsets); Kokkos::deep_copy(tag_offsets_h, tag_offsets); - std::size_t idx_offset = npart_dead; + npart_t idx_offset = npart_dead; if (tag_send > 2) { idx_offset += tag_offsets_h(tag_send - 3); } diff --git a/src/framework/domain/communications.cpp b/src/framework/domain/communications.cpp index 7dc5d285a..946756f49 100644 --- a/src/framework/domain/communications.cpp +++ b/src/framework/domain/communications.cpp @@ -36,10 +36,10 @@ namespace ntt { using comm_params_t = std::pair>; template - auto GetSendRecvRanks(Metadomain* metadomain, - Domain& domain, - dir::direction_t direction) - -> std::pair { + auto GetSendRecvRanks( + Metadomain* metadomain, + Domain& domain, + dir::direction_t direction) -> std::pair { Domain* send_to_nghbr_ptr = nullptr; Domain* recv_from_nghbr_ptr = nullptr; // set pointers to the correct send/recv domains @@ -119,11 +119,11 @@ namespace ntt { } template - auto GetSendRecvParams(Metadomain* metadomain, - Domain& domain, - dir::direction_t direction, - bool synchronize) - -> std::pair { + auto GetSendRecvParams( + Metadomain* metadomain, + Domain& domain, + dir::direction_t direction, + bool synchronize) -> std::pair { const auto [send_indrank, recv_indrank] = GetSendRecvRanks(metadomain, domain, direction); const auto [send_ind, send_rank] = send_indrank; @@ -140,7 +140,7 @@ namespace ntt { auto recv_slice = std::vector {}; const in components[] = { in::x1, in::x2, in::x3 }; // find the field components and indices to be sent/received - for (std::size_t d { 0 }; d < direction.size(); ++d) { + for (auto d { 0u }; d < direction.size(); ++d) { const auto c = components[d]; const auto dir = direction[d]; if (not synchronize) { @@ -510,11 +510,11 @@ namespace ntt { const auto npart_holes = npart - npart_alive; // # of particles to receive per each tag (direction) - std::vector npptag_recv_vec(ntags - 2, 0); + std::vector npptag_recv_vec(ntags - 2, 0); // coordinate shifts per each direction - array_t shifts_in_x1 { "shifts_in_x1", ntags - 2 }; - array_t shifts_in_x2 { "shifts_in_x2", ntags - 2 }; - array_t shifts_in_x3 { "shifts_in_x3", ntags - 2 }; + array_t shifts_in_x1 { "shifts_in_x1", ntags - 2 }; + array_t shifts_in_x2 { "shifts_in_x2", ntags - 2 }; + array_t shifts_in_x3 { "shifts_in_x3", ntags - 2 }; auto shifts_in_x1_h = Kokkos::create_mirror_view(shifts_in_x1); auto shifts_in_x2_h = Kokkos::create_mirror_view(shifts_in_x2); auto shifts_in_x3_h = Kokkos::create_mirror_view(shifts_in_x3); @@ -527,7 +527,7 @@ namespace ntt { std::vector recv_ranks, recv_inds; // total # of reaceived particles from all directions - std::size_t npart_recv = 0u; + npart_t npart_recv = 0u; for (const auto& direction : dir::Directions::all) { // tags corresponding to the direction (both send & recv) @@ -559,7 +559,7 @@ namespace ntt { // request the # of particles to-be-received ... // ... and send the # of particles to-be-sent - std::size_t nrecv = 0; + npart_t nrecv = 0; comm::ParticleSendRecvCount(send_rank, recv_rank, nsend, nrecv); npart_recv += nrecv; npptag_recv_vec[tag_recv - 2] = nrecv; @@ -604,8 +604,7 @@ namespace ntt { Kokkos::deep_copy(shifts_in_x2, shifts_in_x2_h); Kokkos::deep_copy(shifts_in_x3, shifts_in_x3_h); - array_t outgoing_indices { "outgoing_indices", - npart - npart_alive }; + array_t outgoing_indices { "outgoing_indices", npart - npart_alive }; // clang-format off Kokkos::parallel_for( "PrepareOutgoingPrtls", diff --git a/src/framework/domain/domain.h b/src/framework/domain/domain.h index bc7c6e4b5..7966cdb54 100644 --- a/src/framework/domain/domain.h +++ b/src/framework/domain/domain.h @@ -73,8 +73,8 @@ namespace ntt { Domain(bool, unsigned int index, const std::vector& offset_ndomains, - const std::vector& offset_ncells, - const std::vector& ncells, + const std::vector& offset_ncells, + const std::vector& ncells, const boundaries_t& extent, const std::map& metric_params, const std::vector&) @@ -88,8 +88,8 @@ namespace ntt { Domain(unsigned int index, const std::vector& offset_ndomains, - const std::vector& offset_ncells, - const std::vector& ncells, + const std::vector& offset_ncells, + const std::vector& ncells, const boundaries_t& extent, const std::map& metric_params, const std::vector& species_params) @@ -124,7 +124,7 @@ namespace ntt { } [[nodiscard]] - auto offset_ncells() const -> std::vector { + auto offset_ncells() const -> std::vector { return m_offset_ncells; } @@ -156,7 +156,7 @@ namespace ntt { // offset of the domain in # of domains std::vector m_offset_ndomains; // offset of the domain in cells (# of cells in each dimension) - std::vector m_offset_ncells; + std::vector m_offset_ncells; // neighboring domain indices dir::map_t m_neighbor_idx; // MPI rank of the domain (used only when MPI enabled) diff --git a/src/framework/domain/grid.cpp b/src/framework/domain/grid.cpp index 9302386e1..baa23fb5c 100644 --- a/src/framework/domain/grid.cpp +++ b/src/framework/domain/grid.cpp @@ -50,7 +50,7 @@ namespace ntt { template auto Grid::rangeCells(const box_region_t& region) const -> range_t { - tuple_t imin, imax; + tuple_t imin, imax; for (unsigned short i = 0; i < (unsigned short)D; i++) { switch (region[i]) { case CellLayer::allLayer: @@ -87,9 +87,9 @@ namespace ntt { // !TODO: too ugly, implement a better solution (combine with device) template - auto Grid::rangeCellsOnHost(const box_region_t& region) const - -> range_h_t { - tuple_t imin, imax; + auto Grid::rangeCellsOnHost( + const box_region_t& region) const -> range_h_t { + tuple_t imin, imax; for (unsigned short i = 0; i < (unsigned short)D; i++) { switch (region[i]) { case CellLayer::allLayer: @@ -164,9 +164,9 @@ namespace ntt { } template - auto Grid::rangeCells(const tuple_t, D>& ranges) const - -> range_t { - tuple_t imin, imax; + auto Grid::rangeCells( + const tuple_t, D>& ranges) const -> range_t { + tuple_t imin, imax; for (unsigned short i = 0; i < (unsigned short)D; i++) { raise::ErrorIf((ranges[i][0] < -(int)N_GHOSTS) || (ranges[i][1] > (int)N_GHOSTS), diff --git a/src/framework/domain/grid.h b/src/framework/domain/grid.h index 97a939117..af5b6c8d5 100644 --- a/src/framework/domain/grid.h +++ b/src/framework/domain/grid.h @@ -73,7 +73,7 @@ namespace ntt { template struct Grid { - Grid(const std::vector& res) : m_resolution { res } { + Grid(const std::vector& res) : m_resolution { res } { raise::ErrorIf(m_resolution.size() != D, "invalid dimension", HERE); } @@ -81,7 +81,7 @@ namespace ntt { /* getters -------------------------------------------------------------- */ [[nodiscard]] - auto i_min(in i) const -> std::size_t { + auto i_min(in i) const -> ncells_t { switch (i) { case in::x1: return (m_resolution.size() > 0) ? N_GHOSTS : 0; @@ -96,7 +96,7 @@ namespace ntt { } [[nodiscard]] - auto i_max(in i) const -> std::size_t { + auto i_max(in i) const -> ncells_t { switch (i) { case in::x1: return (m_resolution.size() > 0) ? (m_resolution[0] + N_GHOSTS) : 1; @@ -111,7 +111,7 @@ namespace ntt { } [[nodiscard]] - auto n_active(in i) const -> std::size_t { + auto n_active(in i) const -> ncells_t { switch (i) { case in::x1: return (m_resolution.size() > 0) ? m_resolution[0] : 1; @@ -126,12 +126,12 @@ namespace ntt { } [[nodiscard]] - auto n_active() const -> std::vector { + auto n_active() const -> std::vector { return m_resolution; } [[nodiscard]] - auto n_all(in i) const -> std::size_t { + auto n_all(in i) const -> ncells_t { switch (i) { case in::x1: return (m_resolution.size() > 0) ? (m_resolution[0] + 2 * N_GHOSTS) : 1; @@ -146,9 +146,9 @@ namespace ntt { } [[nodiscard]] - auto n_all() const -> std::vector { - std::vector nall; - for (std::size_t i = 0; i < D; ++i) { + auto n_all() const -> std::vector { + std::vector nall; + for (auto i = 0u; i < D; ++i) { nall.push_back(m_resolution[i] + 2 * N_GHOSTS); } return nall; @@ -204,7 +204,7 @@ namespace ntt { auto rangeCellsOnHost(const box_region_t&) const -> range_h_t; protected: - std::vector m_resolution; + std::vector m_resolution; }; } // namespace ntt diff --git a/src/framework/domain/mesh.h b/src/framework/domain/mesh.h index b0bd1a567..98fe68895 100644 --- a/src/framework/domain/mesh.h +++ b/src/framework/domain/mesh.h @@ -38,14 +38,14 @@ namespace ntt { M metric; - Mesh(const std::vector& res, + Mesh(const std::vector& res, const boundaries_t& ext, const std::map& metric_params) : Grid { res } , metric { res, ext, metric_params } , m_extent { ext } {} - Mesh(const std::vector& res, + Mesh(const std::vector& res, const boundaries_t& ext, const std::map& metric_params, const boundaries_t& flds_bc, @@ -131,15 +131,15 @@ namespace ntt { * @note indices are already shifted by N_GHOSTS (i.e. they start at N_GHOSTS not 0) */ [[nodiscard]] - auto ExtentToRange(boundaries_t box, boundaries_t incl_ghosts) - -> boundaries_t { + auto ExtentToRange(boundaries_t box, + boundaries_t incl_ghosts) -> boundaries_t { raise::ErrorIf(box.size() != M::Dim, "Invalid box dimension", HERE); raise::ErrorIf(incl_ghosts.size() != M::Dim, "Invalid incl_ghosts dimension", HERE); - boundaries_t range; + boundaries_t range; if (not Intersects(box)) { - for (std::size_t i { 0 }; i < box.size(); ++i) { + for (auto i { 0u }; i < box.size(); ++i) { range.push_back({ 0, 0 }); } return range; @@ -184,9 +184,9 @@ namespace ntt { raise::Error("invalid dimension", HERE); throw; } - range.push_back({ static_cast(xi_min_Cd) + + range.push_back({ static_cast(xi_min_Cd) + (incl_ghosts[d].first ? 0 : N_GHOSTS), - static_cast(xi_max_Cd) + + static_cast(xi_max_Cd) + (incl_ghosts[d].second ? 2 * N_GHOSTS : N_GHOSTS) }); } ++d; @@ -222,18 +222,18 @@ namespace ntt { auto flds_bc() const -> boundaries_t { if constexpr (D == Dim::_1D) { return { - {flds_bc_in({ -1 }), flds_bc_in({ -1 })} + { flds_bc_in({ -1 }), flds_bc_in({ -1 }) } }; } else if constexpr (D == Dim::_2D) { return { - {flds_bc_in({ -1, 0 }), flds_bc_in({ 1, 0 })}, - {flds_bc_in({ 0, -1 }), flds_bc_in({ 0, 1 })} + { flds_bc_in({ -1, 0 }), flds_bc_in({ 1, 0 }) }, + { flds_bc_in({ 0, -1 }), flds_bc_in({ 0, 1 }) } }; } else if constexpr (D == Dim::_3D) { return { - {flds_bc_in({ -1, 0, 0 }), flds_bc_in({ 1, 0, 0 })}, - {flds_bc_in({ 0, -1, 0 }), flds_bc_in({ 0, 1, 0 })}, - {flds_bc_in({ 0, 0, -1 }), flds_bc_in({ 0, 0, 1 })} + { flds_bc_in({ -1, 0, 0 }), flds_bc_in({ 1, 0, 0 }) }, + { flds_bc_in({ 0, -1, 0 }), flds_bc_in({ 0, 1, 0 }) }, + { flds_bc_in({ 0, 0, -1 }), flds_bc_in({ 0, 0, 1 }) } }; } else { raise::Error("invalid dimension", HERE); @@ -245,18 +245,18 @@ namespace ntt { auto prtl_bc() const -> boundaries_t { if constexpr (D == Dim::_1D) { return { - {prtl_bc_in({ -1 }), prtl_bc_in({ -1 })} + { prtl_bc_in({ -1 }), prtl_bc_in({ -1 }) } }; } else if constexpr (D == Dim::_2D) { return { - {prtl_bc_in({ -1, 0 }), prtl_bc_in({ 1, 0 })}, - {prtl_bc_in({ 0, -1 }), prtl_bc_in({ 0, 1 })} + { prtl_bc_in({ -1, 0 }), prtl_bc_in({ 1, 0 }) }, + { prtl_bc_in({ 0, -1 }), prtl_bc_in({ 0, 1 }) } }; } else if constexpr (D == Dim::_3D) { return { - {prtl_bc_in({ -1, 0, 0 }), prtl_bc_in({ 1, 0, 0 })}, - {prtl_bc_in({ 0, -1, 0 }), prtl_bc_in({ 0, 1, 0 })}, - {prtl_bc_in({ 0, 0, -1 }), prtl_bc_in({ 0, 0, 1 })} + { prtl_bc_in({ -1, 0, 0 }), prtl_bc_in({ 1, 0, 0 }) }, + { prtl_bc_in({ 0, -1, 0 }), prtl_bc_in({ 0, 1, 0 }) }, + { prtl_bc_in({ 0, 0, -1 }), prtl_bc_in({ 0, 0, 1 }) } }; } else { raise::Error("invalid dimension", HERE); diff --git a/src/framework/domain/metadomain.cpp b/src/framework/domain/metadomain.cpp index ed4373df2..dd0d6ffe7 100644 --- a/src/framework/domain/metadomain.cpp +++ b/src/framework/domain/metadomain.cpp @@ -32,10 +32,10 @@ namespace ntt { template Metadomain::Metadomain(unsigned int global_ndomains, const std::vector& global_decomposition, - const std::vector& global_ncells, - const boundaries_t& global_extent, - const boundaries_t& global_flds_bc, - const boundaries_t& global_prtl_bc, + const std::vector& global_ncells, + const boundaries_t& global_extent, + const boundaries_t& global_flds_bc, + const boundaries_t& global_prtl_bc, const std::map& metric_params, const std::vector& species_params) : g_ndomains { global_ndomains } @@ -104,13 +104,13 @@ namespace ntt { raise::ErrorIf(d_ncells.size() != (std::size_t)D, "Invalid number of dimensions received", HERE); - auto d_offset_ncells = std::vector> {}; + auto d_offset_ncells = std::vector> {}; auto d_offset_ndoms = std::vector> {}; for (auto& d : d_ncells) { g_ndomains_per_dim.push_back(d.size()); - auto offset_ncell = std::vector { 0 }; + auto offset_ncell = std::vector { 0 }; auto offset_ndom = std::vector { 0 }; - for (std::size_t i { 1 }; i < d.size(); ++i) { + for (auto i { 1u }; i < d.size(); ++i) { auto di = d[i - 1]; offset_ncell.push_back(offset_ncell.back() + di); offset_ndom.push_back(offset_ndom.back() + 1); @@ -121,8 +121,8 @@ namespace ntt { /* compute tensor products of the domain decompositions --------------- */ // works similar to np.meshgrid() - const auto domain_ncells = tools::TensorProduct(d_ncells); - const auto domain_offset_ncells = tools::TensorProduct( + const auto domain_ncells = tools::TensorProduct(d_ncells); + const auto domain_offset_ncells = tools::TensorProduct( d_offset_ncells); const auto domain_offset_ndoms = tools::TensorProduct( d_offset_ndoms); diff --git a/src/framework/domain/metadomain.h b/src/framework/domain/metadomain.h index 5177571d0..e7e1340e2 100644 --- a/src/framework/domain/metadomain.h +++ b/src/framework/domain/metadomain.h @@ -103,7 +103,7 @@ namespace ntt { */ Metadomain(unsigned int, const std::vector&, - const std::vector&, + const std::vector&, const boundaries_t&, const boundaries_t&, const boundaries_t&, @@ -118,20 +118,20 @@ namespace ntt { #if defined(OUTPUT_ENABLED) void InitWriter(adios2::ADIOS*, const SimulationParams&, bool is_resuming); auto Write(const SimulationParams&, - std::size_t, - std::size_t, - long double, - long double, + timestep_t, + timestep_t, + simtime_t, + simtime_t, std::function&, std::size_t, const Domain&)> = {}) -> bool; void InitCheckpointWriter(adios2::ADIOS*, const SimulationParams&); auto WriteCheckpoint(const SimulationParams&, - std::size_t, - std::size_t, - long double, - long double) -> bool; + timestep_t, + timestep_t, + simtime_t, + simtime_t) -> bool; void ContinueFromCheckpoint(adios2::ADIOS*, const SimulationParams&); #endif diff --git a/src/framework/domain/output.cpp b/src/framework/domain/output.cpp index 6961d2826..1b29dcf7d 100644 --- a/src/framework/domain/output.cpp +++ b/src/framework/domain/output.cpp @@ -96,9 +96,9 @@ namespace ntt { g_writer.defineSpectraOutputs(spectra_species); for (const auto& type : { "fields", "particles", "spectra" }) { g_writer.addTracker(type, - params.template get( + params.template get( "output." + std::string(type) + ".interval"), - params.template get( + params.template get( "output." + std::string(type) + ".interval_time")); } if (is_resuming and std::filesystem::exists(g_writer.fname())) { @@ -182,10 +182,10 @@ namespace ntt { template auto Metadomain::Write( const SimulationParams& params, - std::size_t current_step, - std::size_t finished_step, - long double current_time, - long double finished_time, + timestep_t current_step, + timestep_t finished_step, + simtime_t current_time, + simtime_t finished_time, std::function< void(const std::string&, ndfield_t&, std::size_t, const Domain&)> CustomFieldOutput) -> bool { @@ -234,8 +234,8 @@ namespace ntt { const double l = l_offset; const double f = math::ceil(l / d) * d - l; - const auto first_cell = static_cast(f); - const auto l_size_dwn = static_cast(math::ceil((n - f) / d)); + const auto first_cell = static_cast(f); + const auto l_size_dwn = static_cast(math::ceil((n - f) / d)); const auto is_last = l_offset + l_size == g_size; @@ -472,19 +472,19 @@ namespace ntt { if (write_particles) { g_writer.beginWriting(WriteMode::Particles, current_step, current_time); - const auto prtl_stride = params.template get( + const auto prtl_stride = params.template get( "output.particles.stride"); for (const auto& prtl : g_writer.speciesWriters()) { auto& species = local_domain->species[prtl.species() - 1]; if (not species.is_sorted()) { species.RemoveDead(); } - const std::size_t nout = species.npart() / prtl_stride; - array_t buff_x1, buff_x2, buff_x3; - array_t buff_ux1 { "u1", nout }; - array_t buff_ux2 { "ux2", nout }; - array_t buff_ux3 { "ux3", nout }; - array_t buff_wei { "w", nout }; + const npart_t nout = species.npart() / prtl_stride; + array_t buff_x1, buff_x2, buff_x3; + array_t buff_ux1 { "u1", nout }; + array_t buff_ux2 { "ux2", nout }; + array_t buff_ux3 { "ux3", nout }; + array_t buff_wei { "w", nout }; if constexpr (M::Dim == Dim::_1D or M::Dim == Dim::_2D or M::Dim == Dim::_3D) { buff_x1 = array_t { "x1", nout }; @@ -512,16 +512,16 @@ namespace ntt { local_domain->mesh.metric)); // clang-format on } - std::size_t offset = 0; - std::size_t glob_tot = nout; + npart_t offset = 0; + npart_t glob_tot = nout; #if defined(MPI_ENABLED) - auto glob_nout = std::vector(g_ndomains); + auto glob_nout = std::vector(g_ndomains); MPI_Allgather(&nout, 1, - mpi::get_type(), + mpi::get_type(), glob_nout.data(), 1, - mpi::get_type(), + mpi::get_type(), MPI_COMM_WORLD); glob_tot = 0; for (auto r = 0; r < g_mpi_size; ++r) { diff --git a/src/framework/parameters.cpp b/src/framework/parameters.cpp index 4a9b3056a..e3bddfd70 100644 --- a/src/framework/parameters.cpp +++ b/src/framework/parameters.cpp @@ -32,7 +32,7 @@ namespace ntt { template auto get_dx0_V0( - const std::vector& resolution, + const std::vector& resolution, const boundaries_t& extent, const std::map& params) -> std::pair { const auto metric = M(resolution, extent, params); @@ -78,9 +78,9 @@ namespace ntt { promiseToDefine("simulation.domain.decomposition"); /* [grid] --------------------------------------------------------------- */ - const auto res = toml::find>(toml_data, - "grid", - "resolution"); + const auto res = toml::find>(toml_data, + "grid", + "resolution"); raise::ErrorIf(res.size() < 1 || res.size() > 3, "invalid `grid.resolution`", HERE); @@ -198,7 +198,7 @@ namespace ntt { const auto def_pusher = (is_massless ? defaults::ph_pusher : defaults::em_pusher); const auto maxnpart_real = toml::find(sp, "maxnpart"); - const auto maxnpart = static_cast(maxnpart_real); + const auto maxnpart = static_cast(maxnpart_real); auto pusher = toml::find_or(sp, "pusher", std::string(def_pusher)); const auto npayloads = toml::find_or(sp, "n_payloads", @@ -335,7 +335,7 @@ namespace ntt { set("simulation.name", toml::find(toml_data, "simulation", "name")); set("simulation.runtime", - toml::find(toml_data, "simulation", "runtime")); + toml::find(toml_data, "simulation", "runtime")); /* [grid.boundaraies] --------------------------------------------------- */ auto flds_bc = toml::find>>( @@ -454,7 +454,7 @@ namespace ntt { set("output.interval", toml::find_or(toml_data, "output", "interval", defaults::output::interval)); set("output.interval_time", - toml::find_or(toml_data, "output", "interval_time", -1.0)); + toml::find_or(toml_data, "output", "interval_time", -1.0)); set("output.separate_files", toml::find_or(toml_data, "output", "separate_files", true)); @@ -542,23 +542,23 @@ namespace ntt { // intervals for (const auto& type : { "fields", "particles", "spectra" }) { - const auto q_int = toml::find_or(toml_data, - "output", - std::string(type), - "interval", - 0); - const auto q_int_time = toml::find_or(toml_data, - "output", - std::string(type), - "interval_time", - -1.0); + const auto q_int = toml::find_or(toml_data, + "output", + std::string(type), + "interval", + 0); + const auto q_int_time = toml::find_or(toml_data, + "output", + std::string(type), + "interval_time", + -1.0); set("output." + std::string(type) + ".enable", toml::find_or(toml_data, "output", std::string(type), "enable", true)); if (q_int == 0 && q_int_time == -1.0) { set("output." + std::string(type) + ".interval", - get("output.interval")); + get("output.interval")); set("output." + std::string(type) + ".interval_time", - get("output.interval_time")); + get("output.interval_time")); } else { set("output." + std::string(type) + ".interval", q_int); set("output." + std::string(type) + ".interval_time", q_int_time); @@ -590,7 +590,7 @@ namespace ntt { "interval", defaults::checkpoint::interval)); set("checkpoint.interval_time", - toml::find_or(toml_data, "checkpoint", "interval_time", -1.0)); + toml::find_or(toml_data, "checkpoint", "interval_time", -1.0)); set("checkpoint.keep", toml::find_or(toml_data, "checkpoint", "keep", defaults::checkpoint::keep)); @@ -888,9 +888,9 @@ namespace ntt { } } - void SimulationParams::setCheckpointParams(bool is_resuming, - std::size_t start_step, - long double start_time) { + void SimulationParams::setCheckpointParams(bool is_resuming, + timestep_t start_step, + simtime_t start_time) { set("checkpoint.is_resuming", is_resuming); set("checkpoint.start_step", start_step); set("checkpoint.start_time", start_time); diff --git a/src/framework/parameters.h b/src/framework/parameters.h index 0f9e29370..83192f447 100644 --- a/src/framework/parameters.h +++ b/src/framework/parameters.h @@ -37,7 +37,7 @@ namespace ntt { void setImmutableParams(const toml::value&); void setMutableParams(const toml::value&); - void setCheckpointParams(bool, std::size_t, long double); + void setCheckpointParams(bool, timestep_t, simtime_t); void setSetupParams(const toml::value&); void checkPromises() const; diff --git a/src/framework/simulation.cpp b/src/framework/simulation.cpp index 9961eb3eb..bea50ff09 100644 --- a/src/framework/simulation.cpp +++ b/src/framework/simulation.cpp @@ -40,9 +40,9 @@ namespace ntt { fmt::toLower(toml::find(raw_params, "grid", "metric", "metric")) .c_str()); - const auto res = toml::find>(raw_params, - "grid", - "resolution"); + const auto res = toml::find>(raw_params, + "grid", + "resolution"); raise::ErrorIf(res.size() < 1 || res.size() > 3, "invalid `grid.resolution`", HERE); @@ -51,7 +51,7 @@ namespace ntt { // !TODO: when mixing checkpoint metadata with input, // ... need to properly take care of the diffs m_params.setRawData(raw_params); - std::size_t checkpoint_step = 0; + timestep_t checkpoint_step = 0; if (is_resuming) { logger::Checkpoint("Reading params from a checkpoint", HERE); if (not std::filesystem::exists("checkpoints")) { @@ -61,7 +61,7 @@ namespace ntt { std::filesystem::directory_iterator("checkpoints")) { const auto fname = entry.path().filename().string(); if (fname.find("step-") == 0) { - const std::size_t step = std::stoi(fname.substr(5, fname.size() - 5 - 3)); + const timestep_t step = std::stoi(fname.substr(5, fname.size() - 5 - 3)); if (step > checkpoint_step) { checkpoint_step = step; } @@ -78,9 +78,9 @@ namespace ntt { } logger::Checkpoint(fmt::format("Using %08lu", checkpoint_step), HERE); const auto raw_checkpoint_params = toml::parse(checkpoint_inputfname); - const auto start_time = toml::find(raw_checkpoint_params, - "metadata", - "time"); + const auto start_time = toml::find(raw_checkpoint_params, + "metadata", + "time"); m_params.setImmutableParams(raw_checkpoint_params); m_params.setMutableParams(raw_params); m_params.setCheckpointParams(true, checkpoint_step, start_time); diff --git a/src/framework/tests/comm_mpi.cpp b/src/framework/tests/comm_mpi.cpp index 2f65defd6..5d2c8d4f0 100644 --- a/src/framework/tests/comm_mpi.cpp +++ b/src/framework/tests/comm_mpi.cpp @@ -15,7 +15,7 @@ auto main(int argc, char* argv[]) -> int { Kokkos::initialize(argc, argv); try { - const std::size_t nx1 = 15, nx2 = 15; + const ncells_t nx1 = 15, nx2 = 15; ndfield_t fld_b1 { "fld", nx1 + 2 * N_GHOSTS, nx2 + 2 * N_GHOSTS }; ndfield_t fld_b2 { "fld", nx1 + 2 * N_GHOSTS, nx2 + 2 * N_GHOSTS }; @@ -58,4 +58,4 @@ auto main(int argc, char* argv[]) -> int { Kokkos::finalize(); return 0; -} \ No newline at end of file +} diff --git a/src/framework/tests/metadomain.cpp b/src/framework/tests/metadomain.cpp index 8f5865499..829a2b82f 100644 --- a/src/framework/tests/metadomain.cpp +++ b/src/framework/tests/metadomain.cpp @@ -22,31 +22,31 @@ auto main(int argc, char* argv[]) -> int { using namespace ntt; using namespace metric; { - const std::vector res { 64, 32 }; - const boundaries_t extent { - {1.0, 10.0}, - {0.0, constant::PI} + const std::vector res { 64, 32 }; + const boundaries_t extent { + { 1.0, 10.0 }, + { 0.0, constant::PI } }; const boundaries_t fldsbc { - {FldsBC::ATMOSPHERE, FldsBC::ABSORB}, - { FldsBC::AXIS, FldsBC::AXIS} + { FldsBC::ATMOSPHERE, FldsBC::MATCH }, + { FldsBC::AXIS, FldsBC::AXIS } }; const boundaries_t prtlbc { - {PrtlBC::ATMOSPHERE, PrtlBC::ABSORB}, - { PrtlBC::AXIS, PrtlBC::AXIS} + { PrtlBC::ATMOSPHERE, PrtlBC::ABSORB }, + { PrtlBC::AXIS, PrtlBC::AXIS } }; const std::map params { - {"r0", -ONE}, - { "h", (real_t)0.25} + { "r0", -ONE }, + { "h", (real_t)0.25 } }; #if defined(OUTPUT_ENABLED) Metadomain> metadomain { - 4, { -1, -1 }, - res, extent, fldsbc, prtlbc, params, {}, "disabled" + 4u, { -1, -1 }, + res, extent, fldsbc, prtlbc, params, {} }; #else Metadomain> metadomain { - 4, { -1, -1 }, + 4u, { -1, -1 }, res, extent, fldsbc, prtlbc, params, {} }; #endif @@ -132,7 +132,7 @@ auto main(int argc, char* argv[]) -> int { raise::ErrorIf(self.offset_ndomains()[0] != 1, "Domain::offset_ndomains() failed", HERE); - raise::ErrorIf(self.mesh.flds_bc_in({ +1, 0 }) != FldsBC::ABSORB, + raise::ErrorIf(self.mesh.flds_bc_in({ +1, 0 }) != FldsBC::MATCH, "Mesh::flds_bc_in() failed", HERE); raise::ErrorIf(self.mesh.prtl_bc_in({ +1, 0 }) != PrtlBC::ABSORB, @@ -203,4 +203,4 @@ auto main(int argc, char* argv[]) -> int { } Kokkos::finalize(); return 0; -} \ No newline at end of file +} diff --git a/src/global/arch/directions.h b/src/global/arch/directions.h index ccd4e67b0..2ea009814 100644 --- a/src/global/arch/directions.h +++ b/src/global/arch/directions.h @@ -50,14 +50,14 @@ namespace dir { auto operator-() const -> direction_t { auto result = direction_t {}; - for (std::size_t i = 0; i < (short)D; ++i) { + for (auto i = 0u; i < (unsigned short)D; ++i) { result[i] = -(*this)[i]; } return result; } auto operator==(const direction_t& other) const -> bool { - for (std::size_t i = 0; i < (short)D; ++i) { + for (auto i = 0u; i < (unsigned short)D; ++i) { if ((*this)[i] != other[i]) { return false; } @@ -79,7 +79,7 @@ namespace dir { */ auto get_assoc_orth() const -> std::vector { auto result = std::vector {}; - for (std::size_t i = 0; i < this->size(); ++i) { + for (auto i = 0u; i < this->size(); ++i) { if ((*this)[i] != 0) { direction_t dir; dir[i] = (*this)[i]; @@ -91,7 +91,7 @@ namespace dir { auto get_sign() const -> short { short sign = 0; - for (std::size_t i = 0; i < this->size(); ++i) { + for (auto i = 0u; i < this->size(); ++i) { if ((*this)[i] != 0) { raise::ErrorIf(sign != 0, "Undefined signature for non-orth direction", @@ -105,7 +105,7 @@ namespace dir { auto get_dim() const -> in { short dir = -1; - for (std::size_t i = 0; i < this->size(); ++i) { + for (auto i = 0u; i < this->size(); ++i) { if ((*this)[i] != 0) { raise::ErrorIf(dir > 0, "Undefined dim for non-orth direction", HERE); dir = i; diff --git a/src/global/arch/kokkos_aliases.cpp b/src/global/arch/kokkos_aliases.cpp index 6c15e3d52..d6622b0e5 100644 --- a/src/global/arch/kokkos_aliases.cpp +++ b/src/global/arch/kokkos_aliases.cpp @@ -4,10 +4,14 @@ #include +auto CreateParticleRangePolicy(npart_t p1, npart_t p2) -> range_t { + return Kokkos::RangePolicy(p1, p2); +} + template <> auto CreateRangePolicy( - const tuple_t& i1, - const tuple_t& i2) -> range_t { + const tuple_t& i1, + const tuple_t& i2) -> range_t { index_t i1min = i1[0]; index_t i1max = i2[0]; return Kokkos::RangePolicy(i1min, i1max); @@ -15,8 +19,8 @@ auto CreateRangePolicy( template <> auto CreateRangePolicy( - const tuple_t& i1, - const tuple_t& i2) -> range_t { + const tuple_t& i1, + const tuple_t& i2) -> range_t { index_t i1min = i1[0]; index_t i1max = i2[0]; index_t i2min = i1[1]; @@ -27,8 +31,8 @@ auto CreateRangePolicy( template <> auto CreateRangePolicy( - const tuple_t& i1, - const tuple_t& i2) -> range_t { + const tuple_t& i1, + const tuple_t& i2) -> range_t { index_t i1min = i1[0]; index_t i1max = i2[0]; index_t i2min = i1[1]; @@ -42,8 +46,8 @@ auto CreateRangePolicy( template <> auto CreateRangePolicyOnHost( - const tuple_t& i1, - const tuple_t& i2) -> range_h_t { + const tuple_t& i1, + const tuple_t& i2) -> range_h_t { index_t i1min = i1[0]; index_t i1max = i2[0]; return Kokkos::RangePolicy(i1min, i1max); @@ -51,8 +55,8 @@ auto CreateRangePolicyOnHost( template <> auto CreateRangePolicyOnHost( - const tuple_t& i1, - const tuple_t& i2) -> range_h_t { + const tuple_t& i1, + const tuple_t& i2) -> range_h_t { index_t i1min = i1[0]; index_t i1max = i2[0]; index_t i2min = i1[1]; @@ -63,8 +67,8 @@ auto CreateRangePolicyOnHost( template <> auto CreateRangePolicyOnHost( - const tuple_t& i1, - const tuple_t& i2) -> range_h_t { + const tuple_t& i1, + const tuple_t& i2) -> range_h_t { index_t i1min = i1[0]; index_t i1max = i2[0]; index_t i2min = i1[1]; diff --git a/src/global/arch/kokkos_aliases.h b/src/global/arch/kokkos_aliases.h index f9aac9685..e1a759bed 100644 --- a/src/global/arch/kokkos_aliases.h +++ b/src/global/arch/kokkos_aliases.h @@ -219,27 +219,34 @@ namespace kokkos_aliases_hidden { template using range_h_t = typename kokkos_aliases_hidden::range_h_impl::type; +/** + * @brief Function template for generating 1D Kokkos range policy for particles. + * @param p1 `npart_t`: min. + * @param p2 `npart_t`: max. + */ +auto CreateParticleRangePolicy(npart_t, npart_t) -> range_t; + /** * @brief Function template for generating ND Kokkos range policy. * @tparam D Dimension - * @param i1 array of size D `std::size_t`: { min }. - * @param i2 array of size D `std::size_t`: { max }. + * @param i1 array of size D `ncells_t`: { min }. + * @param i2 array of size D `ncells_t`: { max }. * @returns Kokkos::RangePolicy or Kokkos::MDRangePolicy in the accelerator execution space. */ template -auto CreateRangePolicy(const tuple_t&, - const tuple_t&) -> range_t; +auto CreateRangePolicy(const tuple_t&, + const tuple_t&) -> range_t; /** * @brief Function template for generating ND Kokkos range policy on the host. * @tparam D Dimension - * @param i1 array of size D `std::size_t`: { min }. - * @param i2 array of size D `std::size_t`: { max }. + * @param i1 array of size D `ncells_t`: { min }. + * @param i2 array of size D `ncells_t`: { max }. * @returns Kokkos::RangePolicy or Kokkos::MDRangePolicy in the host execution space. */ template -auto CreateRangePolicyOnHost(const tuple_t&, - const tuple_t&) -> range_h_t; +auto CreateRangePolicyOnHost(const tuple_t&, + const tuple_t&) -> range_h_t; // Random number pool/generator type alias using random_number_pool_t = Kokkos::Random_XorShift1024_Pool; diff --git a/src/global/defaults.h b/src/global/defaults.h index f44fd1844..b81369022 100644 --- a/src/global/defaults.h +++ b/src/global/defaults.h @@ -24,7 +24,7 @@ namespace ntt::defaults { const std::string em_pusher = "Boris"; const std::string ph_pusher = "Photon"; - const std::size_t clear_interval = 100; + const timestep_t clear_interval = 100; namespace qsph { const real_t r0 = 0.0; @@ -53,9 +53,9 @@ namespace ntt::defaults { namespace output { const std::string format = "hdf5"; - const std::size_t interval = 100; + const timestep_t interval = 100; const unsigned short mom_smooth = 0; - const std::size_t prtl_stride = 100; + const npart_t prtl_stride = 100; const real_t spec_emin = 1e-3; const real_t spec_emax = 1e3; const bool spec_log = true; @@ -63,12 +63,12 @@ namespace ntt::defaults { } // namespace output namespace checkpoint { - const std::size_t interval = 1000; - const int keep = 2; + const timestep_t interval = 1000; + const int keep = 2; } // namespace checkpoint namespace diag { - const std::size_t interval = 1; + const timestep_t interval = 1; } // namespace diag namespace gca { diff --git a/src/global/enums.h b/src/global/enums.h index 8f2495c13..5860f8346 100644 --- a/src/global/enums.h +++ b/src/global/enums.h @@ -56,7 +56,7 @@ namespace ntt { const char* const* arr_c, const std::size_t n, const char* elem) -> T { - for (std::size_t i = 0; i < n; ++i) { + for (auto i = 0u; i < n; ++i) { if (strcmp(arr_c[i], elem) == 0) { return (T)(arr[i]); } @@ -70,7 +70,7 @@ namespace ntt { constexpr auto baseContains(const char* const* arr_c, const std::size_t n, const char* elem) -> bool { - for (std::size_t i = 0; i < n; ++i) { + for (auto i = 0u; i < n; ++i) { if (strcmp(arr_c[i], elem) == 0) { return true; } diff --git a/src/global/global.h b/src/global/global.h index 77fa8c51c..577b13f1a 100644 --- a/src/global/global.h +++ b/src/global/global.h @@ -92,6 +92,7 @@ #ifndef GLOBAL_GLOBAL_H #define GLOBAL_GLOBAL_H +#include #include #include #include @@ -111,7 +112,7 @@ namespace files { namespace ntt { - inline constexpr unsigned int N_GHOSTS = 2; + inline constexpr std::size_t N_GHOSTS = 2; // Coordinate shift to account for ghost cells #define COORD(I) \ (static_cast(static_cast((I)) - static_cast(N_GHOSTS))) @@ -339,10 +340,19 @@ using coord_t = tuple_t; template using vec_t = tuple_t; +// time/duration +using timestamp_t = std::chrono::time_point; +using duration_t = double; +using simtime_t = double; +using timestep_t = std::size_t; +using ncells_t = std::size_t; +using npart_t = unsigned long long int; + +// index/number using index_t = const std::size_t; using idx_t = unsigned short; -using range_tuple_t = std::pair; +using range_tuple_t = std::pair; template using boundaries_t = std::vector>; diff --git a/src/global/utils/diag.cpp b/src/global/utils/diag.cpp index c053cdacf..fbd0c4215 100644 --- a/src/global/utils/diag.cpp +++ b/src/global/utils/diag.cpp @@ -22,9 +22,9 @@ namespace diag { auto npart_stats( - std::size_t npart, - std::size_t maxnpart) -> std::vector> { - auto stats = std::vector>(); + npart_t npart, + npart_t maxnpart) -> std::vector> { + auto stats = std::vector>(); #if !defined(MPI_ENABLED) stats.push_back( { npart, @@ -34,22 +34,22 @@ namespace diag { int rank, size; MPI_Comm_rank(MPI_COMM_WORLD, &rank); MPI_Comm_size(MPI_COMM_WORLD, &size); - std::vector mpi_npart(size, 0); - std::vector mpi_maxnpart(size, 0); + std::vector mpi_npart(size, 0); + std::vector mpi_maxnpart(size, 0); MPI_Gather(&npart, 1, - mpi::get_type(), + mpi::get_type(), mpi_npart.data(), 1, - mpi::get_type(), + mpi::get_type(), MPI_ROOT_RANK, MPI_COMM_WORLD); MPI_Gather(&maxnpart, 1, - mpi::get_type(), + mpi::get_type(), mpi_maxnpart.data(), 1, - mpi::get_type(), + mpi::get_type(), MPI_ROOT_RANK, MPI_COMM_WORLD); if (rank != MPI_ROOT_RANK) { @@ -75,16 +75,16 @@ namespace diag { return stats; } - void printDiagnostics(std::size_t step, - std::size_t tot_steps, - long double time, - long double dt, + void printDiagnostics(timestep_t step, + timestep_t tot_steps, + simtime_t time, + simtime_t dt, timer::Timers& timers, pbar::DurationHistory& time_history, - std::size_t ncells, + ncells_t ncells, const std::vector& species_labels, - const std::vector& species_npart, - const std::vector& species_maxnpart, + const std::vector& species_npart, + const std::vector& species_maxnpart, bool print_prtl_clear, bool print_output, bool print_checkpoint, @@ -168,7 +168,7 @@ namespace diag { c_reset); }); #endif - for (std::size_t i = 0; i < species_labels.size(); ++i) { + for (auto i = 0u; i < species_labels.size(); ++i) { const auto part_stats = npart_stats(species_npart[i], species_maxnpart[i]); if (part_stats.size() == 0) { continue; diff --git a/src/global/utils/diag.h b/src/global/utils/diag.h index 30cca5705..6d3c5937d 100644 --- a/src/global/utils/diag.h +++ b/src/global/utils/diag.h @@ -39,16 +39,16 @@ namespace diag { * @param checkpoint (if true, checkpoint was written) * @param colorful_print (if true, print with colors) */ - void printDiagnostics(std::size_t, - std::size_t, - long double, - long double, + void printDiagnostics(timestep_t, + timestep_t, + simtime_t, + simtime_t, timer::Timers&, pbar::DurationHistory&, - std::size_t, + ncells_t, const std::vector&, - const std::vector&, - const std::vector&, + const std::vector&, + const std::vector&, bool, bool, bool, diff --git a/src/global/utils/param_container.cpp b/src/global/utils/param_container.cpp index 6e4f5e0f4..e1dd57c9e 100644 --- a/src/global/utils/param_container.cpp +++ b/src/global/utils/param_container.cpp @@ -32,8 +32,8 @@ namespace prm { } template - auto write(adios2::IO& io, const std::string& name, T var) - -> decltype(void(T()), void()) { + auto write(adios2::IO& io, const std::string& name, T var) -> decltype(void(T()), + void()) { io.DefineAttribute(name, var); } @@ -48,8 +48,8 @@ namespace prm { } template - auto write_pair(adios2::IO& io, const std::string& name, std::pair var) - -> typename std::enable_if::value, void>::type { + auto write_pair(adios2::IO& io, const std::string& name, std::pair var) -> + typename std::enable_if::value, void>::type { std::vector var_str; var_str.push_back(var.first.to_string()); var_str.push_back(var.second.to_string()); @@ -57,8 +57,9 @@ namespace prm { } template - auto write_pair(adios2::IO& io, const std::string& name, std::pair var) - -> decltype(void(T()), void()) { + auto write_pair(adios2::IO& io, + const std::string& name, + std::pair var) -> decltype(void(T()), void()) { std::vector var_vec; var_vec.push_back(var.first); var_vec.push_back(var.second); @@ -76,8 +77,9 @@ namespace prm { } template - auto write_vec(adios2::IO& io, const std::string& name, std::vector var) - -> decltype(void(T()), void()) { + auto write_vec(adios2::IO& io, + const std::string& name, + std::vector var) -> decltype(void(T()), void()) { io.DefineAttribute(name, var.data(), var.size()); } @@ -97,8 +99,8 @@ namespace prm { template auto write_vec_pair(adios2::IO& io, const std::string& name, - std::vector> var) - -> decltype(void(T()), void()) { + std::vector> var) -> decltype(void(T()), + void()) { std::vector var_vec; for (const auto& v : var) { var_vec.push_back(v.first); @@ -124,8 +126,8 @@ namespace prm { template auto write_vec_vec(adios2::IO& io, const std::string& name, - std::vector> var) - -> decltype(void(T()), void()) { + std::vector> var) -> decltype(void(T()), + void()) { std::vector var_vec; for (const auto& vec : var) { for (const auto& v : vec) { @@ -215,34 +217,36 @@ namespace prm { } void Parameters::write(adios2::IO& io) const { - register_write_function(); + register_write_function(); register_write_function(); + register_write_function(); + register_write_function(); register_write_function(); - register_write_function(); register_write_function(); register_write_function(); - register_write_function(); register_write_function(); + register_write_function(); + register_write_function(); register_write_function(); - register_write_function(); register_write_function(); + register_write_function(); + register_write_function(); register_write_function(); register_write_function(); register_write_function(); register_write_function(); register_write_function(); register_write_function(); - register_write_function(); - register_write_function(); - register_write_function_for_pair(); register_write_function_for_pair(); + register_write_function_for_pair(); + register_write_function_for_pair(); register_write_function_for_pair(); - register_write_function_for_pair(); register_write_function_for_pair(); register_write_function_for_pair(); - register_write_function_for_pair(); register_write_function_for_pair(); + register_write_function_for_pair(); + register_write_function_for_pair(); register_write_function_for_pair(); register_write_function_for_pair(); register_write_function_for_pair(); @@ -253,14 +257,15 @@ namespace prm { register_write_function_for_pair(); register_write_function_for_pair(); - register_write_function_for_vector(); register_write_function_for_vector(); + register_write_function_for_vector(); + register_write_function_for_vector(); register_write_function_for_vector(); - register_write_function_for_vector(); register_write_function_for_vector(); register_write_function_for_vector(); - register_write_function_for_vector(); register_write_function_for_vector(); + register_write_function_for_vector(); + register_write_function_for_vector(); register_write_function_for_vector(); register_write_function_for_vector(); register_write_function_for_vector(); @@ -271,14 +276,15 @@ namespace prm { register_write_function_for_vector(); register_write_function_for_vector(); - register_write_function_for_vector_of_pair(); register_write_function_for_vector_of_pair(); + register_write_function_for_vector_of_pair(); + register_write_function_for_vector_of_pair(); register_write_function_for_vector_of_pair(); - register_write_function_for_vector_of_pair(); register_write_function_for_vector_of_pair(); register_write_function_for_vector_of_pair(); - register_write_function_for_vector_of_pair(); register_write_function_for_vector_of_pair(); + register_write_function_for_vector_of_pair(); + register_write_function_for_vector_of_pair(); register_write_function_for_vector_of_pair(); register_write_function_for_vector_of_pair(); register_write_function_for_vector_of_pair(); @@ -289,14 +295,15 @@ namespace prm { register_write_function_for_vector_of_pair(); register_write_function_for_vector_of_pair(); - register_write_function_for_vector_of_vector(); register_write_function_for_vector_of_vector(); + register_write_function_for_vector_of_vector(); + register_write_function_for_vector_of_vector(); register_write_function_for_vector_of_vector(); - register_write_function_for_vector_of_vector(); register_write_function_for_vector_of_vector(); register_write_function_for_vector_of_vector(); - register_write_function_for_vector_of_vector(); register_write_function_for_vector_of_vector(); + register_write_function_for_vector_of_vector(); + register_write_function_for_vector_of_vector(); register_write_function_for_vector_of_vector(); register_write_function_for_vector_of_vector(); register_write_function_for_vector_of_vector(); @@ -307,14 +314,15 @@ namespace prm { register_write_function_for_vector_of_vector(); register_write_function_for_vector_of_vector(); - register_write_function_for_dict(); register_write_function_for_dict(); + register_write_function_for_dict(); + register_write_function_for_dict(); register_write_function_for_dict(); - register_write_function_for_dict(); register_write_function_for_dict(); register_write_function_for_dict(); - register_write_function_for_dict(); register_write_function_for_dict(); + register_write_function_for_dict(); + register_write_function_for_dict(); register_write_function_for_dict(); register_write_function_for_dict(); register_write_function_for_dict(); diff --git a/src/global/utils/progressbar.cpp b/src/global/utils/progressbar.cpp index 74f952382..eaa8118fc 100644 --- a/src/global/utils/progressbar.cpp +++ b/src/global/utils/progressbar.cpp @@ -1,5 +1,7 @@ #include "utils/progressbar.h" +#include "global.h" + #include "utils/error.h" #include "utils/formatting.h" @@ -19,14 +21,15 @@ namespace pbar { - auto normalize_duration_fmt(long double t, const std::string& u) - -> std::pair { - const std::vector> units { - {"µs", 1e0}, - { "ms", 1e3}, - { "s", 1e6}, - {"min", 6e7}, - { "hr", 3.6e9} + auto normalize_duration_fmt( + duration_t t, + const std::string& u) -> std::pair { + const std::vector> units { + { "µs", 1e0 }, + { "ms", 1e3 }, + { "s", 1e6 }, + { "min", 6e7 }, + { "hr", 3.6e9 } }; auto it = std::find_if(units.begin(), units.end(), [&u](const auto& pr) { return pr.first == u; @@ -51,17 +54,17 @@ namespace pbar { units[newu_idx].first }; } - auto to_human_readable(long double t, const std::string& u) -> std::string { + auto to_human_readable(duration_t t, const std::string& u) -> std::string { const auto [tt, tu] = normalize_duration_fmt(t, u); const auto t1 = static_cast(tt); - const auto t2 = tt - static_cast(t1); + const auto t2 = tt - static_cast(t1); const auto [tt2, tu2] = normalize_duration_fmt(t2, tu); return fmt::format("%d%s %d%s", t1, tu.c_str(), static_cast(tt2), tu2.c_str()); } auto ProgressBar(const DurationHistory& history, - std::size_t step, - std::size_t max_steps, + timestep_t step, + timestep_t max_steps, DiagFlags& flags) -> std::string { auto avg_duration = history.average(); @@ -69,13 +72,13 @@ namespace pbar { int rank, size; MPI_Comm_rank(MPI_COMM_WORLD, &rank); MPI_Comm_size(MPI_COMM_WORLD, &size); - std::vector mpi_avg_durations(size, 0.0); + std::vector mpi_avg_durations(size, 0.0); MPI_Gather(&avg_duration, 1, - mpi::get_type(), + mpi::get_type(), mpi_avg_durations.data(), 1, - mpi::get_type(), + mpi::get_type(), MPI_ROOT_RANK, MPI_COMM_WORLD); if (rank != MPI_ROOT_RANK) { @@ -88,11 +91,11 @@ namespace pbar { const auto avg = to_human_readable(avg_duration, "µs"); const auto elapsed = to_human_readable(history.elapsed(), "µs"); const auto remain = to_human_readable( - static_cast(max_steps - step) * avg_duration, + static_cast(max_steps - step) * avg_duration, "µs"); - const auto pct = static_cast(step) / - static_cast(max_steps); + const auto pct = static_cast(step) / + static_cast(max_steps); const int nfilled = std::min(static_cast(pct * params::width), params::width); const int nempty = params::width - nfilled; diff --git a/src/global/utils/progressbar.h b/src/global/utils/progressbar.h index f218bc3f4..588413cb4 100644 --- a/src/global/utils/progressbar.h +++ b/src/global/utils/progressbar.h @@ -38,7 +38,7 @@ namespace pbar { class DurationHistory { std::size_t capacity; - std::vector durations; + std::vector durations; const std::chrono::time_point start; std::chrono::time_point prev_start; @@ -60,30 +60,31 @@ namespace pbar { prev_start = now; } - auto average() const -> long double { + auto average() const -> duration_t { if (durations.size() > 0) { return std::accumulate(durations.begin(), durations.end(), 0.0) / - static_cast(durations.size()); + static_cast(durations.size()); } else { return 0.0; } } - auto elapsed() const -> long double { + auto elapsed() const -> duration_t { return std::chrono::duration_cast( std::chrono::system_clock::now() - start) .count(); } }; - auto normalize_duration_fmt(long double t, const std::string& u) - -> std::pair; + auto normalize_duration_fmt( + duration_t t, + const std::string& u) -> std::pair; - auto to_human_readable(long double t, const std::string& u) -> std::string; + auto to_human_readable(duration_t t, const std::string& u) -> std::string; auto ProgressBar(const DurationHistory& history, - std::size_t step, - std::size_t max_steps, + timestep_t step, + timestep_t max_steps, DiagFlags& flags) -> std::string; } // namespace pbar diff --git a/src/global/utils/timer.cpp b/src/global/utils/timer.cpp index a12d79b96..d3c14d05e 100644 --- a/src/global/utils/timer.cpp +++ b/src/global/utils/timer.cpp @@ -1,5 +1,7 @@ #include "utils/timer.h" +#include "global.h" + #include "utils/colors.h" #include "utils/formatting.h" @@ -18,8 +20,8 @@ namespace timer { auto Timers::gather(const std::vector& ignore_in_tot, - std::size_t npart, - std::size_t ncells) const + npart_t npart, + ncells_t ncells) const -> std::map> { auto timer_stats = std::map< @@ -44,22 +46,22 @@ namespace timer { MPI_COMM_WORLD); } // accumulate nparts and ncells from MPI blocks - auto all_nparts = std::vector(size, 0); - auto all_ncells = std::vector(size, 0); + auto all_nparts = std::vector(size, 0); + auto all_ncells = std::vector(size, 0); MPI_Gather(&npart, 1, - mpi::get_type(), + mpi::get_type(), all_nparts.data(), 1, - mpi::get_type(), + mpi::get_type(), MPI_ROOT_RANK, MPI_COMM_WORLD); MPI_Gather(&ncells, 1, - mpi::get_type(), + mpi::get_type(), all_ncells.data(), 1, - mpi::get_type(), + mpi::get_type(), MPI_ROOT_RANK, MPI_COMM_WORLD); if (rank != MPI_ROOT_RANK) { @@ -128,9 +130,9 @@ namespace timer { return timer_stats; } - auto Timers::printAll(TimerFlags flags, - std::size_t npart, - std::size_t ncells) const -> std::string { + auto Timers::printAll(TimerFlags flags, + npart_t npart, + ncells_t ncells) const -> std::string { const std::vector extras { "PrtlClear", "Output", "Checkpoint" }; const auto stats = gather(extras, npart, ncells); if (stats.empty()) { diff --git a/src/global/utils/timer.h b/src/global/utils/timer.h index 3e9c1433e..8abe8ab0a 100644 --- a/src/global/utils/timer.h +++ b/src/global/utils/timer.h @@ -41,8 +41,6 @@ #include namespace timer { - using timestamp = std::chrono::time_point; - using duration_t = long double; inline void convertTime(duration_t& value, std::string& units) { if (value > 1e6) { @@ -58,10 +56,10 @@ namespace timer { } class Timers { - std::map> m_timers; - std::vector m_names; - const bool m_blocking; - const std::function m_synchronize; + std::map> m_timers; + std::vector m_names; + const bool m_blocking; + const std::function m_synchronize; public: Timers(std::initializer_list names, @@ -75,7 +73,7 @@ namespace timer { for (const auto& name : names) { m_timers.insert({ name, - {std::chrono::system_clock::now(), 0.0} + { std::chrono::system_clock::now(), 0.0 } }); m_names.push_back(name); } @@ -89,7 +87,9 @@ namespace timer { void stop(const std::string& name) { if (m_blocking) { - m_synchronize(); + if (m_synchronize != nullptr) { + m_synchronize(); + } #if defined(MPI_ENABLED) MPI_Barrier(MPI_COMM_WORLD); #endif @@ -139,15 +139,15 @@ namespace timer { */ [[nodiscard]] auto gather(const std::vector& ignore_in_tot, - std::size_t npart, - std::size_t ncells) const + npart_t npart, + ncells_t ncells) const -> std::map>; [[nodiscard]] - auto printAll(TimerFlags flags = Timer::Default, - std::size_t npart = 0, - std::size_t ncells = 0) const -> std::string; + auto printAll(TimerFlags flags = Timer::Default, + npart_t npart = 0, + ncells_t ncells = 0) const -> std::string; }; } // namespace timer diff --git a/src/global/utils/tools.h b/src/global/utils/tools.h index 30687d01b..95765e2de 100644 --- a/src/global/utils/tools.h +++ b/src/global/utils/tools.h @@ -4,10 +4,10 @@ * @implements * - tools::ArrayImbalance -> unsigned short * - tools::TensorProduct<> -> boundaries_t - * - tools::decompose1D -> std::vector + * - tools::decompose1D -> std::vector * - tools::divideInProportions2D -> std::tuple * - tools::divideInProportions3D -> std::tuple - * - tools::Decompose -> std::vector> + * - tools::Decompose -> std::vector> * - tools::Tracker * @namespaces: * - tools:: @@ -60,8 +60,8 @@ namespace tools { * @return Tensor product of list */ template - inline auto TensorProduct(const std::vector>& list) - -> std::vector> { + inline auto TensorProduct( + const std::vector>& list) -> std::vector> { std::vector> result = { {} }; for (const auto& sublist : list) { std::vector> temp; @@ -81,16 +81,16 @@ namespace tools { * @param ndomains Number of domains * @param ncells Number of cells */ - inline auto decompose1D(unsigned int ndomains, std::size_t ncells) - -> std::vector { - auto size = (std::size_t)((double)ncells / (double)ndomains); - auto ncells_domain = std::vector(ndomains, size); - for (std::size_t i { 0 }; i < ncells - size * ndomains; ++i) { + inline auto decompose1D(unsigned int ndomains, + ncells_t ncells) -> std::vector { + auto size = (ncells_t)((double)ncells / (double)ndomains); + auto ncells_domain = std::vector(ndomains, size); + for (auto i { 0u }; i < ncells - size * ndomains; ++i) { ncells_domain[i] += 1; } auto sum = std::accumulate(ncells_domain.begin(), ncells_domain.end(), - (std::size_t)0); + (ncells_t)0); raise::ErrorIf(sum != ncells, "Decomposition error: sum != ncells", HERE); raise::ErrorIf(ncells_domain.size() != (std::size_t)ndomains, "Decomposition error: size != ndomains", @@ -107,8 +107,10 @@ namespace tools { * @param s1 Proportion of the first dimension * @param s2 Proportion of the second dimension */ - inline auto divideInProportions2D(unsigned int ntot, unsigned int s1, unsigned int s2) - -> std::tuple { + inline auto divideInProportions2D( + unsigned int ntot, + unsigned int s1, + unsigned int s2) -> std::tuple { auto n1 = (unsigned int)(std::sqrt((double)ntot * (double)s1 / (double)s2)); if (n1 == 0) { return { 1, ntot }; @@ -130,11 +132,11 @@ namespace tools { * @param s2 Proportion of the second dimension * @param s3 Proportion of the third dimension */ - inline auto divideInProportions3D(unsigned int ntot, - unsigned int s1, - unsigned int s2, - unsigned int s3) - -> std::tuple { + inline auto divideInProportions3D( + unsigned int ntot, + unsigned int s1, + unsigned int s2, + unsigned int s3) -> std::tuple { auto n1 = (unsigned int)(std::cbrt( (double)ntot * (double)(SQR(s1)) / (double)(s2 * s3))); if (n1 > ntot) { @@ -163,10 +165,10 @@ namespace tools { * * @note If decomposition has -1, it will be calculated automatically */ - inline auto Decompose(unsigned int ndomains, - const std::vector& ncells, - const std::vector& decomposition) - -> std::vector> { + inline auto Decompose( + unsigned int ndomains, + const std::vector& ncells, + const std::vector& decomposition) -> std::vector> { const auto dimension = ncells.size(); raise::ErrorIf(dimension != decomposition.size(), "Decomposition error: dimension != decomposition.size", @@ -277,16 +279,16 @@ namespace tools { bool m_initialized { false }; std::string m_type; - std::size_t m_interval; - long double m_interval_time; + timestep_t m_interval; + simtime_t m_interval_time; bool m_use_time; - long double m_last_output_time { -1.0 }; + simtime_t m_last_output_time { -1.0 }; public: Tracker() = default; - Tracker(const std::string& type, std::size_t interval, long double interval_time) + Tracker(const std::string& type, timestep_t interval, simtime_t interval_time) : m_initialized { true } , m_type { type } , m_interval { interval } @@ -295,9 +297,7 @@ namespace tools { ~Tracker() = default; - void init(const std::string& type, - std::size_t interval, - long double interval_time) { + void init(const std::string& type, timestep_t interval, simtime_t interval_time) { m_type = type; m_interval = interval; m_interval_time = interval_time; @@ -305,7 +305,7 @@ namespace tools { m_initialized = true; } - auto shouldWrite(std::size_t step, long double time) -> bool { + auto shouldWrite(timestep_t step, simtime_t time) -> bool { raise::ErrorIf(!m_initialized, "Tracker not initialized", HERE); if (m_use_time) { if ((m_last_output_time < 0) or diff --git a/src/kernels/ampere_gr.hpp b/src/kernels/ampere_gr.hpp index 5af0fa4ef..782dece0d 100644 --- a/src/kernels/ampere_gr.hpp +++ b/src/kernels/ampere_gr.hpp @@ -37,7 +37,7 @@ namespace kernel::gr { ndfield_t Dout; const ndfield_t H; const M metric; - const std::size_t i2max; + const ncells_t i2max; const real_t coeff; bool is_axis_i2min { false }, is_axis_i2max { false }; @@ -47,7 +47,7 @@ namespace kernel::gr { const ndfield_t& H, const M& metric, real_t coeff, - std::size_t ni2, + ncells_t ni2, const boundaries_t& boundaries) : Din { Din } , Dout { Dout } @@ -67,9 +67,9 @@ namespace kernel::gr { Inline void operator()(index_t i1, index_t i2) const { if constexpr (D == Dim::_2D) { - constexpr std::size_t i2min { N_GHOSTS }; - const real_t i1_ { COORD(i1) }; - const real_t i2_ { COORD(i2) }; + constexpr ncells_t i2min { N_GHOSTS }; + const real_t i1_ { COORD(i1) }; + const real_t i2_ { COORD(i2) }; const real_t inv_sqrt_detH_0pH { ONE / metric.sqrt_det_h({ i1_, i2_ + HALF }) }; @@ -118,7 +118,7 @@ namespace kernel::gr { ndfield_t Df; const ndfield_t J; const M metric; - const std::size_t i2max; + const ncells_t i2max; const real_t coeff; bool is_axis_i2min { false }; bool is_axis_i2max { false }; @@ -132,7 +132,7 @@ namespace kernel::gr { const ndfield_t& J, const M& metric, real_t coeff, - std::size_t ni2, + ncells_t ni2, const boundaries_t& boundaries) : Df { Df } , J { J } @@ -148,9 +148,9 @@ namespace kernel::gr { Inline void operator()(index_t i1, index_t i2) const { if constexpr (D == Dim::_2D) { - constexpr std::size_t i2min { N_GHOSTS }; - const real_t i1_ { COORD(i1) }; - const real_t i2_ { COORD(i2) }; + constexpr ncells_t i2min { N_GHOSTS }; + const real_t i1_ { COORD(i1) }; + const real_t i2_ { COORD(i2) }; const real_t inv_sqrt_detH_0pH { ONE / metric.sqrt_det_h({ i1_, i2_ + HALF }) }; diff --git a/src/kernels/ampere_sr.hpp b/src/kernels/ampere_sr.hpp index e4faec6ce..dbe9d3dbf 100644 --- a/src/kernels/ampere_sr.hpp +++ b/src/kernels/ampere_sr.hpp @@ -32,17 +32,17 @@ namespace kernel::sr { static_assert(M::is_metric, "M must be a metric class"); static constexpr auto D = M::Dim; - ndfield_t EB; - const M metric; - const std::size_t i2max; - const real_t coeff; - bool is_axis_i2min { false }, is_axis_i2max { false }; + ndfield_t EB; + const M metric; + const ncells_t i2max; + const real_t coeff; + bool is_axis_i2min { false }, is_axis_i2max { false }; public: Ampere_kernel(const ndfield_t& EB, const M& metric, real_t coeff, - std::size_t ni2, + ncells_t ni2, const boundaries_t& boundaries) : EB { EB } , metric { metric } @@ -57,9 +57,9 @@ namespace kernel::sr { Inline void operator()(index_t i1, index_t i2) const { if constexpr (D == Dim::_2D) { - constexpr std::size_t i2min { N_GHOSTS }; - const real_t i1_ { COORD(i1) }; - const real_t i2_ { COORD(i2) }; + constexpr ncells_t i2min { N_GHOSTS }; + const real_t i1_ { COORD(i1) }; + const real_t i2_ { COORD(i2) }; const real_t inv_sqrt_detH_0pH { ONE / metric.sqrt_det_h({ i1_, i2_ + HALF }) }; @@ -122,18 +122,18 @@ namespace kernel::sr { */ template class CurrentsAmpere_kernel { - static constexpr auto D = M::Dim; - static constexpr std::size_t i2min = N_GHOSTS; + static constexpr auto D = M::Dim; + static constexpr ncells_t i2min = N_GHOSTS; - ndfield_t E; - ndfield_t J; - const M metric; - const std::size_t i2max; + ndfield_t E; + ndfield_t J; + const M metric; + const ncells_t i2max; // coeff = -dt * q0 * n0 / B0 - const real_t coeff; - const real_t inv_n0; - bool is_axis_i2min { false }; - bool is_axis_i2max { false }; + const real_t coeff; + const real_t inv_n0; + bool is_axis_i2min { false }; + bool is_axis_i2max { false }; public: /** @@ -145,7 +145,7 @@ namespace kernel::sr { const M& metric, real_t coeff, real_t inv_n0, - std::size_t ni2, + ncells_t ni2, const boundaries_t& boundaries) : E { E } , J { J } diff --git a/src/kernels/comm.hpp b/src/kernels/comm.hpp index b280ce38b..7873870b1 100644 --- a/src/kernels/comm.hpp +++ b/src/kernels/comm.hpp @@ -24,35 +24,36 @@ namespace kernel::comm { template class PrepareOutgoingPrtls_kernel { - const array_t shifts_in_x1, shifts_in_x2, shifts_in_x3; - array_t outgoing_indices; + const array_t shifts_in_x1, shifts_in_x2, shifts_in_x3; + array_t outgoing_indices; - const std::size_t npart, npart_alive, npart_dead, ntags; + const npart_t npart, npart_alive, npart_dead; + const std::size_t ntags; array_t i1, i1_prev, i2, i2_prev, i3, i3_prev; const array_t tag; - const array_t tag_offsets; + const array_t tag_offsets; - array_t current_offset; + array_t current_offset; public: - PrepareOutgoingPrtls_kernel(const array_t& shifts_in_x1, - const array_t& shifts_in_x2, - const array_t& shifts_in_x3, - array_t& outgoing_indices, - std::size_t npart, - std::size_t npart_alive, - std::size_t npart_dead, - std::size_t ntags, - array_t& i1, - array_t& i1_prev, - array_t& i2, - array_t& i2_prev, - array_t& i3, - array_t& i3_prev, - const array_t& tag, - const array_t& tag_offsets) + PrepareOutgoingPrtls_kernel(const array_t& shifts_in_x1, + const array_t& shifts_in_x2, + const array_t& shifts_in_x3, + array_t& outgoing_indices, + npart_t npart, + npart_t npart_alive, + npart_t npart_dead, + std::size_t ntags, + array_t& i1, + array_t& i1_prev, + array_t& i2, + array_t& i2_prev, + array_t& i3, + array_t& i3_prev, + const array_t& tag, + const array_t& tag_offsets) : shifts_in_x1 { shifts_in_x1 } , shifts_in_x2 { shifts_in_x2 } , shifts_in_x3 { shifts_in_x3 } @@ -225,45 +226,45 @@ namespace kernel::comm { const array_t recv_buff_pld; const unsigned short NINTS, NREALS, NPRTLDX, NPLDS; - const std::size_t npart, npart_holes; + const npart_t npart, npart_holes; - array_t i1, i1_prev, i2, i2_prev, i3, i3_prev; - array_t dx1, dx1_prev, dx2, dx2_prev, dx3, dx3_prev; - array_t ux1, ux2, ux3, weight, phi; - array_t pld; - array_t tag; - const array_t outgoing_indices; + array_t i1, i1_prev, i2, i2_prev, i3, i3_prev; + array_t dx1, dx1_prev, dx2, dx2_prev, dx3, dx3_prev; + array_t ux1, ux2, ux3, weight, phi; + array_t pld; + array_t tag; + const array_t outgoing_indices; public: - ExtractReceivedPrtls_kernel(const array_t& recv_buff_int, - const array_t& recv_buff_real, - const array_t& recv_buff_prtldx, - const array_t& recv_buff_pld, - unsigned short NINTS, - unsigned short NREALS, - unsigned short NPRTLDX, - unsigned short NPLDS, - std::size_t npart, - array_t& i1, - array_t& i1_prev, - array_t& dx1, - array_t& dx1_prev, - array_t& i2, - array_t& i2_prev, - array_t& dx2, - array_t& dx2_prev, - array_t& i3, - array_t& i3_prev, - array_t& dx3, - array_t& dx3_prev, - array_t& ux1, - array_t& ux2, - array_t& ux3, - array_t& weight, - array_t& phi, - array_t& pld, - array_t& tag, - const array_t& outgoing_indices) + ExtractReceivedPrtls_kernel(const array_t& recv_buff_int, + const array_t& recv_buff_real, + const array_t& recv_buff_prtldx, + const array_t& recv_buff_pld, + unsigned short NINTS, + unsigned short NREALS, + unsigned short NPRTLDX, + unsigned short NPLDS, + npart_t npart, + array_t& i1, + array_t& i1_prev, + array_t& dx1, + array_t& dx1_prev, + array_t& i2, + array_t& i2_prev, + array_t& dx2, + array_t& dx2_prev, + array_t& i3, + array_t& i3_prev, + array_t& dx3, + array_t& dx3_prev, + array_t& ux1, + array_t& ux2, + array_t& ux3, + array_t& weight, + array_t& phi, + array_t& pld, + array_t& tag, + const array_t& outgoing_indices) : recv_buff_int { recv_buff_int } , recv_buff_real { recv_buff_real } , recv_buff_prtldx { recv_buff_prtldx } @@ -296,7 +297,7 @@ namespace kernel::comm { , outgoing_indices { outgoing_indices } {} Inline void operator()(index_t p) const { - std::size_t idx; + npart_t idx; if (p >= npart_holes) { idx = npart + p - npart_holes; } else { diff --git a/src/kernels/digital_filter.hpp b/src/kernels/digital_filter.hpp index 5d05fad2d..f01eb0fb8 100644 --- a/src/kernels/digital_filter.hpp +++ b/src/kernels/digital_filter.hpp @@ -19,7 +19,7 @@ #define FILTER_IN_I1(ARR, COMP, I, J) \ INV_2*(ARR)((I), (J), (COMP)) + \ - INV_4*((ARR)((I)-1, (J), (COMP)) + (ARR)((I) + 1, (J), (COMP))) + INV_4*((ARR)((I) - 1, (J), (COMP)) + (ARR)((I) + 1, (J), (COMP))) namespace kernel { using namespace ntt; @@ -30,12 +30,12 @@ namespace kernel { const ndfield_t buffer; bool is_axis_i2min { false }, is_axis_i2max { false }; static constexpr auto i2_min = N_GHOSTS; - const std::size_t i2_max; + const ncells_t i2_max; public: DigitalFilter_kernel(ndfield_t& array, const ndfield_t& buffer, - const std::size_t (&size_)[D], + const ncells_t (&size_)[D], const boundaries_t& boundaries) : array { array } , buffer { buffer } diff --git a/src/kernels/faraday_gr.hpp b/src/kernels/faraday_gr.hpp index 19eede5f2..7fb327e61 100644 --- a/src/kernels/faraday_gr.hpp +++ b/src/kernels/faraday_gr.hpp @@ -36,7 +36,7 @@ namespace kernel::gr { ndfield_t Bout; const ndfield_t E; const M metric; - const std::size_t i2max; + const ncells_t i2max; const real_t coeff; bool is_axis_i2min { false }; diff --git a/src/kernels/faraday_sr.hpp b/src/kernels/faraday_sr.hpp index 727974248..be3e60dd0 100644 --- a/src/kernels/faraday_sr.hpp +++ b/src/kernels/faraday_sr.hpp @@ -52,9 +52,9 @@ namespace kernel::sr { Inline void operator()(index_t i1, index_t i2) const { if constexpr (D == Dim::_2D) { - constexpr std::size_t i2min { N_GHOSTS }; - const real_t i1_ { COORD(i1) }; - const real_t i2_ { COORD(i2) }; + constexpr ncells_t i2min { N_GHOSTS }; + const real_t i1_ { COORD(i1) }; + const real_t i2_ { COORD(i2) }; const real_t inv_sqrt_detH_0pH { ONE / metric.sqrt_det_h({ i1_, i2_ + HALF }) }; diff --git a/src/kernels/fields_bcs.hpp b/src/kernels/fields_bcs.hpp index 363ff3ad2..dbb47f42c 100644 --- a/src/kernels/fields_bcs.hpp +++ b/src/kernels/fields_bcs.hpp @@ -493,11 +493,11 @@ namespace kernel::bc { */ template struct AxisBoundaries_kernel { - ndfield_t Fld; - const std::size_t i_edge; - const bool setE, setB; + ndfield_t Fld; + const ncells_t i_edge; + const bool setE, setB; - AxisBoundaries_kernel(ndfield_t Fld, std::size_t i_edge, BCTags tags) + AxisBoundaries_kernel(ndfield_t Fld, ncells_t i_edge, BCTags tags) : Fld { Fld } , i_edge { i_edge } , setE { tags & BC::Ex1 or tags & BC::Ex2 or tags & BC::Ex3 } @@ -558,15 +558,15 @@ namespace kernel::bc { static_cast(M::Dim), "Invalid Orientation"); - ndfield_t Fld; - const I fset; - const M metric; - const std::size_t i_edge; + ndfield_t Fld; + const I fset; + const M metric; + const ncells_t i_edge; EnforcedBoundaries_kernel(ndfield_t& Fld, const I& fset, const M& metric, - std::size_t i_edge, + ncells_t i_edge, BCTags tags) : Fld { Fld } , fset { fset } diff --git a/src/kernels/injectors.hpp b/src/kernels/injectors.hpp index 9d3fd7d81..09bc7a180 100644 --- a/src/kernels/injectors.hpp +++ b/src/kernels/injectors.hpp @@ -47,7 +47,7 @@ namespace kernel { array_t weights_2; array_t tags_2; - std::size_t offset1, offset2; + npart_t offset1, offset2; const M metric; const array_t ni; const ED energy_dist; @@ -58,8 +58,8 @@ namespace kernel { spidx_t spidx2, Particles& species1, Particles& species2, - std::size_t offset1, - std::size_t offset2, + npart_t offset1, + npart_t offset2, const M& metric, const array_t& ni, const ED& energy_dist, @@ -201,20 +201,20 @@ namespace kernel { array_t in_phi; array_t in_wei; - array_t idx { "idx" }; - array_t i1s, i2s, i3s; - array_t dx1s, dx2s, dx3s; - array_t ux1s, ux2s, ux3s; - array_t phis; - array_t weights; - array_t tags; + array_t idx { "idx" }; + array_t i1s, i2s, i3s; + array_t dx1s, dx2s, dx3s; + array_t ux1s, ux2s, ux3s; + array_t phis; + array_t weights; + array_t tags; - const std::size_t offset; + const npart_t offset; M global_metric; - real_t x1_min, x1_max, x2_min, x2_max, x3_min, x3_max; - std::size_t i1_offset, i2_offset, i3_offset; + real_t x1_min, x1_max, x2_min, x2_max, x3_min, x3_max; + ncells_t i1_offset, i2_offset, i3_offset; GlobalInjector_kernel(Particles& species, const M& global_metric, @@ -269,18 +269,18 @@ namespace kernel { void copy_from_vector(const std::string& name, array_t& arr, const std::map>& data, - std::size_t n_inject) { + npart_t n_inject) { raise::ErrorIf(data.find(name) == data.end(), name + " not found in data", HERE); raise::ErrorIf(data.at(name).size() != n_inject, "Inconsistent data size", HERE); arr = array_t { name, n_inject }; auto arr_h = Kokkos::create_mirror_view(arr); - for (std::size_t i = 0; i < data.at(name).size(); ++i) { + for (auto i = 0u; i < data.at(name).size(); ++i) { arr_h(i) = data.at(name)[i]; } Kokkos::deep_copy(arr, arr_h); } - auto number_injected() const -> std::size_t { + auto number_injected() const -> npart_t { auto idx_h = Kokkos::create_mirror_view(idx); Kokkos::deep_copy(idx_h, idx); return idx_h(); @@ -298,7 +298,7 @@ namespace kernel { global_metric.template transform_xyz(x_Cd, u_Ph, u_XYZ); const auto i1 = static_cast( - static_cast(x_Cd[0]) - i1_offset); + static_cast(x_Cd[0]) - i1_offset); const auto dx1 = static_cast( x_Cd[0] - static_cast(i1 + i1_offset)); @@ -322,9 +322,8 @@ namespace kernel { vec_t u_Ph { in_ux1(p), in_ux2(p), in_ux3(p) }; coord_t x_Cd_ { ZERO }; - auto index { - offset + Kokkos::atomic_fetch_add(&idx(), static_cast(1)) - }; + auto index { offset + + Kokkos::atomic_fetch_add(&idx(), static_cast(1)) }; global_metric.template convert({ in_x1(p), in_x2(p) }, x_Cd); x_Cd_[0] = x_Cd[0]; @@ -340,11 +339,11 @@ namespace kernel { raise::KernelError(HERE, "Unknown simulation engine"); } const auto i1 = static_cast( - static_cast(x_Cd[0]) - i1_offset); + static_cast(x_Cd[0]) - i1_offset); const auto dx1 = static_cast( x_Cd[0] - static_cast(i1 + i1_offset)); const auto i2 = static_cast( - static_cast(x_Cd[1]) - i2_offset); + static_cast(x_Cd[1]) - i2_offset); const auto dx2 = static_cast( x_Cd[1] - static_cast(i2 + i2_offset)); @@ -385,15 +384,15 @@ namespace kernel { raise::KernelError(HERE, "Unknown simulation engine"); } const auto i1 = static_cast( - static_cast(x_Cd[0]) - i1_offset); + static_cast(x_Cd[0]) - i1_offset); const auto dx1 = static_cast( x_Cd[0] - static_cast(i1 + i1_offset)); const auto i2 = static_cast( - static_cast(x_Cd[1]) - i2_offset); + static_cast(x_Cd[1]) - i2_offset); const auto dx2 = static_cast( x_Cd[1] - static_cast(i2 + i2_offset)); const auto i3 = static_cast( - static_cast(x_Cd[2]) - i3_offset); + static_cast(x_Cd[2]) - i3_offset); const auto dx3 = static_cast( x_Cd[2] - static_cast(i3 + i3_offset)); @@ -440,9 +439,9 @@ namespace kernel { array_t weights_2; array_t tags_2; - array_t idx { "idx" }; + array_t idx { "idx" }; - std::size_t offset1, offset2; + npart_t offset1, offset2; M metric; const ED energy_dist; const SD spatial_dist; @@ -454,8 +453,8 @@ namespace kernel { spidx_t spidx2, Particles& species1, Particles& species2, - std::size_t offset1, - std::size_t offset2, + npart_t offset1, + npart_t offset2, const M& metric, const ED& energy_dist, const SD& spatial_dist, @@ -496,7 +495,7 @@ namespace kernel { , inv_V0 { inv_V0 } , random_pool { random_pool } {} - auto number_injected() const -> std::size_t { + auto number_injected() const -> npart_t { auto idx_h = Kokkos::create_mirror_view(idx); Kokkos::deep_copy(idx_h, idx); return idx_h(); @@ -508,7 +507,7 @@ namespace kernel { coord_t x_Cd { i1_ + HALF }; coord_t x_Ph { ZERO }; metric.template convert(x_Cd, x_Ph); - const auto ppc = static_cast(ppc0 * spatial_dist(x_Ph)); + const auto ppc = static_cast(ppc0 * spatial_dist(x_Ph)); if (ppc == 0) { return; } @@ -564,7 +563,7 @@ namespace kernel { x_Cd_[2] = ZERO; } metric.template convert(x_Cd, x_Ph); - const auto ppc = static_cast(ppc0 * spatial_dist(x_Ph)); + const auto ppc = static_cast(ppc0 * spatial_dist(x_Ph)); if (ppc == 0) { return; } @@ -631,7 +630,7 @@ namespace kernel { coord_t x_Cd { i1_ + HALF, i2_ + HALF, i3_ + HALF }; coord_t x_Ph { ZERO }; metric.template convert(x_Cd, x_Ph); - const auto ppc = static_cast(ppc0 * spatial_dist(x_Ph)); + const auto ppc = static_cast(ppc0 * spatial_dist(x_Ph)); if (ppc == 0) { return; } diff --git a/src/kernels/particle_moments.hpp b/src/kernels/particle_moments.hpp index 0621646ad..948e46e1e 100644 --- a/src/kernels/particle_moments.hpp +++ b/src/kernels/particle_moments.hpp @@ -86,7 +86,7 @@ namespace kernel { bool use_weights, const M& metric, const boundaries_t& boundaries, - std::size_t ni2, + ncells_t ni2, real_t inv_n0, unsigned short window) : c1 { (components.size() == 2) ? components[0] diff --git a/src/kernels/prtls_to_phys.hpp b/src/kernels/prtls_to_phys.hpp index f12eefc95..4dd7d88b0 100644 --- a/src/kernels/prtls_to_phys.hpp +++ b/src/kernels/prtls_to_phys.hpp @@ -31,7 +31,7 @@ namespace kernel { static constexpr Dimension D = M::Dim; protected: - const std::size_t stride; + const npart_t stride; array_t buff_x1; array_t buff_x2; array_t buff_x3; @@ -47,7 +47,7 @@ namespace kernel { const M metric; public: - PrtlToPhys_kernel(std::size_t stride, + PrtlToPhys_kernel(npart_t stride, array_t& buff_x1, array_t& buff_x2, array_t& buff_x3, diff --git a/src/metrics/kerr_schild.h b/src/metrics/kerr_schild.h index 5a60def53..13294dd7d 100644 --- a/src/metrics/kerr_schild.h +++ b/src/metrics/kerr_schild.h @@ -72,7 +72,7 @@ namespace metric { using MetricBase::nx3; using MetricBase::set_dxMin; - KerrSchild(std::vector res, + KerrSchild(std::vector res, boundaries_t ext, const std::map& params) : MetricBase { res, ext } diff --git a/src/metrics/kerr_schild_0.h b/src/metrics/kerr_schild_0.h index 70689f4f0..fdd2fd847 100644 --- a/src/metrics/kerr_schild_0.h +++ b/src/metrics/kerr_schild_0.h @@ -53,8 +53,8 @@ namespace metric { using MetricBase::nx3; using MetricBase::set_dxMin; - KerrSchild0(std::vector res, - boundaries_t ext, + KerrSchild0(std::vector res, + boundaries_t ext, const std::map& = {}) : MetricBase { res, ext } , dr { (x1_max - x1_min) / nx1 } diff --git a/src/metrics/metric_base.h b/src/metrics/metric_base.h index 321d39bbd..66cc28918 100644 --- a/src/metrics/metric_base.h +++ b/src/metrics/metric_base.h @@ -61,7 +61,7 @@ namespace metric { static constexpr bool is_metric { true }; static constexpr Dimension Dim { D }; - MetricBase(std::vector res, boundaries_t ext) + MetricBase(std::vector res, boundaries_t ext) : nx1 { res.size() > 0 ? (real_t)(res[0]) : ONE } , nx2 { res.size() > 1 ? (real_t)(res[1]) : ONE } , nx3 { res.size() > 2 ? (real_t)(res[2]) : ONE } diff --git a/src/metrics/minkowski.h b/src/metrics/minkowski.h index c22ac1ad9..367689e0f 100644 --- a/src/metrics/minkowski.h +++ b/src/metrics/minkowski.h @@ -47,8 +47,8 @@ namespace metric { using MetricBase::nx3; using MetricBase::set_dxMin; - Minkowski(std::vector res, - boundaries_t ext, + Minkowski(std::vector res, + boundaries_t ext, const std::map& = {}) : MetricBase { res, ext } , dx { (x1_max - x1_min) / nx1 } @@ -240,8 +240,7 @@ namespace metric { * @note tetrad/cart <-> cntrv <-> cov */ template - Inline auto transform(const coord_t& xi, const real_t& v_in) const - -> real_t { + Inline auto transform(const coord_t& xi, const real_t& v_in) const -> real_t { static_assert(i > 0 && i <= 3, "Invalid index i"); static_assert(in != out, "Invalid vector transformation"); if constexpr (i > static_cast(D)) { diff --git a/src/metrics/qkerr_schild.h b/src/metrics/qkerr_schild.h index d531b8b3b..d64fe05da 100644 --- a/src/metrics/qkerr_schild.h +++ b/src/metrics/qkerr_schild.h @@ -72,7 +72,7 @@ namespace metric { using MetricBase::nx3; using MetricBase::set_dxMin; - QKerrSchild(std::vector res, + QKerrSchild(std::vector res, boundaries_t ext, const std::map& params) : MetricBase { res, ext } diff --git a/src/metrics/qspherical.h b/src/metrics/qspherical.h index 8062f7589..4df5db866 100644 --- a/src/metrics/qspherical.h +++ b/src/metrics/qspherical.h @@ -55,7 +55,7 @@ namespace metric { using MetricBase::nx3; using MetricBase::set_dxMin; - QSpherical(std::vector res, + QSpherical(std::vector res, boundaries_t ext, const std::map& params) : MetricBase { res, ext } @@ -284,8 +284,7 @@ namespace metric { * @note tetrad/sph <-> cntrv <-> cov */ template - Inline auto transform(const coord_t& xi, const real_t& v_in) const - -> real_t { + Inline auto transform(const coord_t& xi, const real_t& v_in) const -> real_t { static_assert(i > 0 && i <= 3, "Invalid index i"); static_assert(in != out, "Invalid vector transformation"); if constexpr ((in == Idx::T && out == Idx::Sph) || diff --git a/src/metrics/spherical.h b/src/metrics/spherical.h index f4bbe2eea..54e12367d 100644 --- a/src/metrics/spherical.h +++ b/src/metrics/spherical.h @@ -50,8 +50,8 @@ namespace metric { using MetricBase::nx3; using MetricBase::set_dxMin; - Spherical(std::vector res, - boundaries_t ext, + Spherical(std::vector res, + boundaries_t ext, const std::map& = {}) : MetricBase { res, ext } , dr((x1_max - x1_min) / nx1) @@ -252,8 +252,7 @@ namespace metric { * @note tetrad/sph <-> cntrv <-> cov */ template - Inline auto transform(const coord_t& xi, const real_t& v_in) const - -> real_t { + Inline auto transform(const coord_t& xi, const real_t& v_in) const -> real_t { static_assert(i > 0 && i <= 3, "Invalid index i"); static_assert(in != out, "Invalid vector transformation"); if constexpr ((in == Idx::T && out == Idx::Sph) || diff --git a/src/output/fields.h b/src/output/fields.h index a520a246d..811c5adc2 100644 --- a/src/output/fields.h +++ b/src/output/fields.h @@ -112,7 +112,7 @@ namespace out { } [[nodiscard]] - inline auto name(const std::size_t& ci) const -> std::string { + inline auto name(std::size_t ci) const -> std::string { raise::ErrorIf( comp.size() == 0, "OutputField::name(ci) called but no components were available", diff --git a/src/output/tests/writer-nompi.cpp b/src/output/tests/writer-nompi.cpp index 8fb2ac026..b063539ca 100644 --- a/src/output/tests/writer-nompi.cpp +++ b/src/output/tests/writer-nompi.cpp @@ -103,22 +103,21 @@ auto main(int argc, char* argv[]) -> int { const auto layoutRight = io.InquireAttribute("LayoutRight").Data()[0] == 1; - raise::ErrorIf(io.InquireAttribute("NGhosts").Data()[0] != 0, + raise::ErrorIf(io.InquireAttribute("NGhosts").Data()[0] != 0, "NGhosts is not correct", HERE); raise::ErrorIf(io.InquireAttribute("Dimension").Data()[0] != 3, "Dimension is not correct", HERE); - for (std::size_t step = 0; reader.BeginStep() == adios2::StepStatus::OK; - ++step) { - std::size_t step_read; - long double time_read; + for (auto step = 0u; reader.BeginStep() == adios2::StepStatus::OK; ++step) { + timestep_t step_read; + simtime_t time_read; - reader.Get(io.InquireVariable("Step"), + reader.Get(io.InquireVariable("Step"), &step_read, adios2::Mode::Sync); - reader.Get(io.InquireVariable("Time"), + reader.Get(io.InquireVariable("Time"), &time_read, adios2::Mode::Sync); raise::ErrorIf(step_read != (step + 1) * 10, "Step is not correct", HERE); @@ -136,10 +135,10 @@ auto main(int argc, char* argv[]) -> int { fmt::format("%s is not 3D", name.c_str()), HERE); - auto dims = fieldVar.Shape(); - std::size_t nx1_r = dims[0]; - std::size_t nx2_r = dims[1]; - std::size_t nx3_r = dims[2]; + auto dims = fieldVar.Shape(); + ncells_t nx1_r = dims[0]; + ncells_t nx2_r = dims[1]; + ncells_t nx3_r = dims[2]; if (!layoutRight) { std::swap(nx1_r, nx3_r); } diff --git a/src/output/utils/attr_writer.h b/src/output/utils/attr_writer.h index 47f269d55..c8b21e4c2 100644 --- a/src/output/utils/attr_writer.h +++ b/src/output/utils/attr_writer.h @@ -40,7 +40,10 @@ namespace out { {typeid(int), defineAttribute}, {typeid(short), defineAttribute}, {typeid(unsigned int), defineAttribute}, - {typeid(std::size_t), defineAttribute}, + {typeid(long int), defineAttribute}, + {typeid(unsigned long int), defineAttribute}, + {typeid(long long int), defineAttribute}, + {typeid(unsigned long long int), defineAttribute}, {typeid(unsigned short), defineAttribute}, {typeid(float), defineAttribute}, {typeid(double), defineAttribute}, @@ -49,7 +52,10 @@ namespace out { {typeid(std::vector), defineAttribute>}, {typeid(std::vector), defineAttribute>}, {typeid(std::vector), defineAttribute>}, - {typeid(std::vector), defineAttribute>}, + {typeid(std::vector), defineAttribute>}, + {typeid(std::vector), defineAttribute>}, + {typeid(std::vector), defineAttribute>}, + {typeid(std::vector), defineAttribute>}, {typeid(std::vector), defineAttribute>}, {typeid(std::vector), defineAttribute>}, {typeid(std::vector), defineAttribute>}, diff --git a/src/output/writer.cpp b/src/output/writer.cpp index 95965c864..4350e8442 100644 --- a/src/output/writer.cpp +++ b/src/output/writer.cpp @@ -37,20 +37,20 @@ namespace out { m_io = p_adios->DeclareIO("Entity::Output"); m_io.SetEngine(engine); - m_io.DefineVariable("Step"); - m_io.DefineVariable("Time"); + m_io.DefineVariable("Step"); + m_io.DefineVariable("Time"); m_fname = title; } void Writer::addTracker(const std::string& type, - std::size_t interval, - long double interval_time) { + timestep_t interval, + simtime_t interval_time) { m_trackers.insert({ type, tools::Tracker(type, interval, interval_time) }); } auto Writer::shouldWrite(const std::string& type, - std::size_t step, - long double time) -> bool { + timestep_t step, + simtime_t time) -> bool { if (m_trackers.find(type) != m_trackers.end()) { return m_trackers.at(type).shouldWrite(step, time); } else { @@ -63,9 +63,9 @@ namespace out { m_mode = mode; } - void Writer::defineMeshLayout(const std::vector& glob_shape, - const std::vector& loc_corner, - const std::vector& loc_shape, + void Writer::defineMeshLayout(const std::vector& glob_shape, + const std::vector& loc_corner, + const std::vector& loc_shape, const std::vector& dwn, bool incl_ghosts, Coord coords) { @@ -76,7 +76,7 @@ namespace out { m_flds_l_corner = loc_corner; m_flds_l_shape = loc_shape; - for (std::size_t i { 0 }; i < glob_shape.size(); ++i) { + for (auto i { 0u }; i < glob_shape.size(); ++i) { raise::ErrorIf(dwn[i] != 1 && incl_ghosts, "Downsampling with ghosts not supported", HERE); @@ -86,18 +86,17 @@ namespace out { const double l = loc_corner[i]; const double n = loc_shape[i]; const double f = math::ceil(l / d) * d - l; - m_flds_g_shape_dwn.push_back(static_cast(math::ceil(g / d))); - m_flds_l_corner_dwn.push_back(static_cast(math::ceil(l / d))); - m_flds_l_first.push_back(static_cast(f)); - m_flds_l_shape_dwn.push_back( - static_cast(math::ceil((n - f) / d))); + m_flds_g_shape_dwn.push_back(static_cast(math::ceil(g / d))); + m_flds_l_corner_dwn.push_back(static_cast(math::ceil(l / d))); + m_flds_l_first.push_back(static_cast(f)); + m_flds_l_shape_dwn.push_back(static_cast(math::ceil((n - f) / d))); } m_io.DefineAttribute("NGhosts", incl_ghosts ? N_GHOSTS : 0); m_io.DefineAttribute("Dimension", m_flds_g_shape.size()); m_io.DefineAttribute("Coordinates", std::string(coords.to_string())); - for (std::size_t i { 0 }; i < m_flds_g_shape.size(); ++i) { + for (auto i { 0u }; i < m_flds_g_shape.size(); ++i) { // cell-centers adios2::Dims g_shape = { m_flds_g_shape_dwn[i] }; adios2::Dims l_corner = { m_flds_l_corner_dwn[i] }; @@ -151,7 +150,7 @@ namespace out { adios2::ConstantDims); } else { // vector or tensor - for (std::size_t i { 0 }; i < fld.comp.size(); ++i) { + for (auto i { 0u }; i < fld.comp.size(); ++i) { m_io.DefineVariable(fld.name(i), m_flds_g_shape_dwn, m_flds_l_corner_dwn, @@ -210,7 +209,7 @@ namespace out { const ndfield_t& field, std::size_t comp, std::vector dwn, - std::vector first_cell, + std::vector first_cell, bool ghosts) { // when dwn != 1 in any direction, it is assumed that ghosts == false auto var = io.InquireVariable(varname); @@ -230,7 +229,7 @@ namespace out { const double nx1_full = field.extent(0) - 2 * N_GHOSTS; const auto first_cell1 = first_cell[0]; - const auto nx1_dwn = static_cast( + const auto nx1_dwn = static_cast( math::ceil((nx1_full - first_cell1_d) / dwn1)); output_field = array_t { "output_field", nx1_dwn }; @@ -260,9 +259,9 @@ namespace out { const auto first_cell1 = first_cell[0]; const auto first_cell2 = first_cell[1]; - const auto nx1_dwn = static_cast( + const auto nx1_dwn = static_cast( math::ceil((nx1_full - first_cell1_d) / dwn1)); - const auto nx2_dwn = static_cast( + const auto nx2_dwn = static_cast( math::ceil((nx2_full - first_cell2_d) / dwn2)); output_field = array_t { "output_field", nx1_dwn, nx2_dwn }; Kokkos::parallel_for( @@ -299,11 +298,11 @@ namespace out { const auto first_cell2 = first_cell[1]; const auto first_cell3 = first_cell[2]; - const auto nx1_dwn = static_cast( + const auto nx1_dwn = static_cast( math::ceil((nx1_full - first_cell1_d) / dwn1)); - const auto nx2_dwn = static_cast( + const auto nx2_dwn = static_cast( math::ceil((nx2_full - first_cell2_d) / dwn2)); - const auto nx3_dwn = static_cast( + const auto nx3_dwn = static_cast( math::ceil((nx3_full - first_cell3_d) / dwn3)); output_field = array_t { "output_field", nx1_dwn, nx2_dwn, nx3_dwn }; @@ -333,7 +332,7 @@ namespace out { raise::ErrorIf(names.size() != addresses.size(), "# of names != # of addresses ", HERE); - for (std::size_t i { 0 }; i < addresses.size(); ++i) { + for (auto i { 0u }; i < addresses.size(); ++i) { WriteField(m_io, m_writer, names[i], @@ -346,8 +345,8 @@ namespace out { } void Writer::writeParticleQuantity(const array_t& array, - std::size_t glob_total, - std::size_t loc_offset, + npart_t glob_total, + npart_t loc_offset, const std::string& varname) { auto var = m_io.InquireVariable(varname); var.SetShape({ glob_total }); @@ -416,8 +415,8 @@ namespace out { } void Writer::beginWriting(WriteModeTags write_mode, - std::size_t tstep, - long double time) { + timestep_t tstep, + simtime_t time) { raise::ErrorIf(write_mode == WriteMode::None, "None is not a valid mode", HERE); raise::ErrorIf(p_adios == nullptr, "ADIOS pointer is null", HERE); if (m_active_mode != WriteMode::None) { @@ -468,8 +467,8 @@ namespace out { raise::Fatal(e.what(), HERE); } m_writer.BeginStep(); - m_writer.Put(m_io.InquireVariable("Step"), &tstep); - m_writer.Put(m_io.InquireVariable("Time"), &time); + m_writer.Put(m_io.InquireVariable("Step"), &tstep); + m_writer.Put(m_io.InquireVariable("Time"), &time); } void Writer::endWriting(WriteModeTags write_mode) { @@ -511,7 +510,7 @@ namespace out { const ndfield_t&, std::size_t, std::vector, - std::vector, + std::vector, bool); template void WriteField(adios2::IO&, adios2::Engine&, @@ -519,7 +518,7 @@ namespace out { const ndfield_t&, std::size_t, std::vector, - std::vector, + std::vector, bool); template void WriteField(adios2::IO&, adios2::Engine&, @@ -527,7 +526,7 @@ namespace out { const ndfield_t&, std::size_t, std::vector, - std::vector, + std::vector, bool); template void WriteField(adios2::IO&, adios2::Engine&, @@ -535,7 +534,7 @@ namespace out { const ndfield_t&, std::size_t, std::vector, - std::vector, + std::vector, bool); template void WriteField(adios2::IO&, adios2::Engine&, @@ -543,7 +542,7 @@ namespace out { const ndfield_t&, std::size_t, std::vector, - std::vector, + std::vector, bool); template void WriteField(adios2::IO&, adios2::Engine&, @@ -551,7 +550,7 @@ namespace out { const ndfield_t&, std::size_t, std::vector, - std::vector, + std::vector, bool); } // namespace out diff --git a/src/output/writer.h b/src/output/writer.h index a8abf4b12..5484aa6d7 100644 --- a/src/output/writer.h +++ b/src/output/writer.h @@ -39,16 +39,16 @@ namespace out { bool m_separate_files; // global shape of the fields array to output - std::vector m_flds_g_shape; + std::vector m_flds_g_shape; // local corner of the fields array to output - std::vector m_flds_l_corner; + std::vector m_flds_l_corner; // local shape of the fields array to output - std::vector m_flds_l_shape; + std::vector m_flds_l_shape; // downsampling factors for each dimension std::vector m_dwn; // starting cell in each dimension (not including ghosts) - std::vector m_flds_l_first; + std::vector m_flds_l_first; // same but downsampled adios2::Dims m_flds_g_shape_dwn; @@ -78,14 +78,14 @@ namespace out { void setMode(adios2::Mode); - void addTracker(const std::string&, std::size_t, long double); - auto shouldWrite(const std::string&, std::size_t, long double) -> bool; + void addTracker(const std::string&, timestep_t, simtime_t); + auto shouldWrite(const std::string&, timestep_t, simtime_t) -> bool; void writeAttrs(const prm::Parameters&); - void defineMeshLayout(const std::vector&, - const std::vector&, - const std::vector&, + void defineMeshLayout(const std::vector&, + const std::vector&, + const std::vector&, const std::vector&, bool, Coord); @@ -102,13 +102,13 @@ namespace out { const std::vector&); void writeParticleQuantity(const array_t&, - std::size_t, - std::size_t, + npart_t, + npart_t, const std::string&); void writeSpectrum(const array_t&, const std::string&); void writeSpectrumBins(const array_t&, const std::string&); - void beginWriting(WriteModeTags, std::size_t, long double); + void beginWriting(WriteModeTags, timestep_t, simtime_t); void endWriting(WriteModeTags); /* getters -------------------------------------------------------------- */ From 85811c9bdd670dd44d8c50123240881dc2407293 Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Thu, 13 Mar 2025 10:09:36 -0400 Subject: [PATCH 443/773] Minor fixes of npart_t --- src/checkpoint/writer.cpp | 4 ++-- src/framework/domain/metadomain.h | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/checkpoint/writer.cpp b/src/checkpoint/writer.cpp index c5f7e5181..a70d8de09 100644 --- a/src/checkpoint/writer.cpp +++ b/src/checkpoint/writer.cpp @@ -273,10 +273,10 @@ namespace checkpoint { std::size_t, std::size_t, double); - template void Writer::savePerDomainVariable(const std::string&, + template void Writer::savePerDomainVariable(const std::string&, std::size_t, std::size_t, - std::size_t); + npart_t); template void Writer::saveField(const std::string&, const ndfield_t&); diff --git a/src/framework/domain/metadomain.h b/src/framework/domain/metadomain.h index e7e1340e2..80f546664 100644 --- a/src/framework/domain/metadomain.h +++ b/src/framework/domain/metadomain.h @@ -177,8 +177,8 @@ namespace ntt { } [[nodiscard]] - auto l_npart_perspec() const -> std::vector { - std::vector npart(g_species_params.size(), 0); + auto l_npart_perspec() const -> std::vector { + std::vector npart(g_species_params.size(), 0); for (const auto& ldidx : l_subdomain_indices()) { for (std::size_t i = 0; i < g_species_params.size(); ++i) { npart[i] += g_subdomains[ldidx].species[i].npart(); @@ -188,8 +188,8 @@ namespace ntt { } [[nodiscard]] - auto l_maxnpart_perspec() const -> std::vector { - std::vector maxnpart(g_species_params.size(), 0); + auto l_maxnpart_perspec() const -> std::vector { + std::vector maxnpart(g_species_params.size(), 0); for (const auto& ldidx : l_subdomain_indices()) { for (std::size_t i = 0; i < g_species_params.size(); ++i) { maxnpart[i] += g_subdomains[ldidx].species[i].maxnpart(); From 777d1fbff3cf66a7b0e5e49260cb1acb954d5761 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20B=C3=B6ss?= Date: Thu, 13 Mar 2025 10:00:56 -0500 Subject: [PATCH 444/773] cleanup of pgen --- setups/srpic/shock/pgen.hpp | 46 ------------------------------------- 1 file changed, 46 deletions(-) diff --git a/setups/srpic/shock/pgen.hpp b/setups/srpic/shock/pgen.hpp index 59c5590c9..b8f169521 100644 --- a/setups/srpic/shock/pgen.hpp +++ b/setups/srpic/shock/pgen.hpp @@ -106,52 +106,6 @@ namespace user { } } - - auto PerfectConductorFieldsConst(const bc_in&, const em& comp) const -> real_t{ - - // electric field components - if (comp == em::ex1) { - return ONE; - } else if (comp == em::ex2) { - return -ONE; - } else if (comp == em::ex3) { - return -ONE; } - // magentic field components - else if (comp == em::bx1) { - return -ONE; - } else if (comp == em::bx2) { - return ONE; - } else if (comp == em::bx3) { - return ONE;} - // should never be the case - else - { - return ZERO; - } - } - - // auto PerfectConductorCurrentsConst(const bc_in &, const cur &comp) const - // -> std::pair - // { - // // ToDo - // if (comp == cur::jx1) - // { - // return ZERO; - // } - // else if (comp == cur::jx2) - // { - // return ZERO; - // } - // else if (comp == cur::jx3) - // { - // return ZERO; - // } - // else - // { - // return ZERO; - // } - // } - auto MatchFields(real_t time) const -> InitFields { return init_flds; } From ef5c85409d3422f1cb71337166c719f8b5e76ed2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20B=C3=B6ss?= Date: Thu, 13 Mar 2025 11:03:56 -0500 Subject: [PATCH 445/773] update example parameter file --- setups/srpic/shock/shock.toml | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/setups/srpic/shock/shock.toml b/setups/srpic/shock/shock.toml index 4ed3a2b9e..4e03721f7 100644 --- a/setups/srpic/shock/shock.toml +++ b/setups/srpic/shock/shock.toml @@ -1,22 +1,22 @@ [simulation] name = "shock" engine = "srpic" - runtime = 50.0 + runtime = 30000.0 [grid] - resolution = [2048, 128] - extent = [[0.0, 10.0], [-0.3125, 0.3125]] + resolution = [16384, 128] + extent = [[0.0, 8000.0], [-31.25, 31.25]] [grid.metric] metric = "minkowski" [grid.boundaries] - fields = [["ABSORB", "FIXED"], ["PERIODIC"]] + fields = [["CONDUCTOR", "MATCH"], ["PERIODIC"]] particles = [["REFLECT", "ABSORB"], ["PERIODIC"]] - + [scales] - larmor0 = 1e-2 - skindepth0 = 1e-2 + larmor0 = 100.0 + skindepth0 = 1.0 [algorithms] current_filters = 8 @@ -25,7 +25,7 @@ CFL = 0.5 [particles] - ppc0 = 16.0 + ppc0 = 8.0 [[particles.species]] label = "e-" @@ -34,21 +34,29 @@ maxnpart = 1e8 [[particles.species]] - label = "e+" + label = "p+" mass = 1.0 charge = 1.0 maxnpart = 1e8 [setup] drift_ux = 0.1 - temperature = 1e-3 + temperature = 1e-4 Bmag = 1.0 Btheta = 0.0 Bphi = 0.0 [output] - interval_time = 0.1 + interval_time = 500.0 format = "hdf5" - + [output.fields] - quantities = ["N_1", "N_2", "E", "B", "T0i_1", "T0i_2", "J"] + quantities = ["N_1", "N_2", "B", "E"] + + [output.particles] + enable = true + stride = 10 + + [output.spectra] + enable = false + From 66cb136a4f3fa46cca535befce004d1102b4a17d Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Thu, 13 Mar 2025 15:35:15 -0400 Subject: [PATCH 446/773] Minor fixes of npart_t --- src/kernels/comm.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/kernels/comm.hpp b/src/kernels/comm.hpp index 7873870b1..6a47e56b4 100644 --- a/src/kernels/comm.hpp +++ b/src/kernels/comm.hpp @@ -113,14 +113,14 @@ namespace kernel::comm { array_t send_buff_pld; const unsigned short NINTS, NREALS, NPRTLDX, NPLDS; - const std::size_t idx_offset; + const npart_t idx_offset; const array_t i1, i1_prev, i2, i2_prev, i3, i3_prev; const array_t dx1, dx1_prev, dx2, dx2_prev, dx3, dx3_prev; const array_t ux1, ux2, ux3, weight, phi; const array_t pld; array_t tag; - const array_t outgoing_indices; + const array_t outgoing_indices; public: PopulatePrtlSendBuffer_kernel(array_t& send_buff_int, @@ -131,7 +131,7 @@ namespace kernel::comm { unsigned short NREALS, unsigned short NPRTLDX, unsigned short NPLDS, - std::size_t idx_offset, + npart_t idx_offset, const array_t& i1, const array_t& i1_prev, const array_t& dx1, @@ -151,7 +151,7 @@ namespace kernel::comm { const array_t& phi, const array_t& pld, array_t& tag, - const array_t& outgoing_indices) + const array_t& outgoing_indices) : send_buff_int { send_buff_int } , send_buff_real { send_buff_real } , send_buff_prtldx { send_buff_prtldx } From 38e76bd7763d00743f547a07b5ed2682dc70ea22 Mon Sep 17 00:00:00 2001 From: haykh Date: Thu, 13 Mar 2025 19:25:55 -0400 Subject: [PATCH 447/773] minor bugfix dx_min comparison + nonexistent species --- src/framework/domain/metadomain.cpp | 4 +++- src/framework/domain/output.cpp | 5 +++++ src/framework/tests/comm_mpi.cpp | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/framework/domain/metadomain.cpp b/src/framework/domain/metadomain.cpp index ed4373df2..57b2ece17 100644 --- a/src/framework/domain/metadomain.cpp +++ b/src/framework/domain/metadomain.cpp @@ -369,6 +369,8 @@ namespace ntt { template void Metadomain::metricCompatibilityCheck() const { + const auto epsilon = std::numeric_limits::epsilon() * + static_cast(100.0); const auto dx_min = g_mesh.metric.dxMin(); auto dx_min_from_domains = std::numeric_limits::infinity(); for (unsigned int idx { 0 }; idx < g_ndomains; ++idx) { @@ -377,7 +379,7 @@ namespace ntt { dx_min_from_domains = std::min(dx_min_from_domains, current_dx_min); } raise::ErrorIf( - not cmp::AlmostEqual(dx_min, dx_min_from_domains), + not cmp::AlmostEqual(dx_min / dx_min_from_domains, ONE, epsilon), "dx_min is not the same across all domains: " + std::to_string(dx_min) + " " + std::to_string(dx_min_from_domains), HERE); diff --git a/src/framework/domain/output.cpp b/src/framework/domain/output.cpp index 6961d2826..3dc95c18a 100644 --- a/src/framework/domain/output.cpp +++ b/src/framework/domain/output.cpp @@ -125,6 +125,11 @@ namespace ntt { } } } + for (const auto& sp : specs) { + raise::ErrorIf((sp > prtl_species.size()) or (sp == 0), + "Invalid species index " + std::to_string(sp), + HERE); + } auto scatter_buff = Kokkos::Experimental::create_scatter_view(buffer); // some parameters diff --git a/src/framework/tests/comm_mpi.cpp b/src/framework/tests/comm_mpi.cpp index 2f65defd6..157a9692b 100644 --- a/src/framework/tests/comm_mpi.cpp +++ b/src/framework/tests/comm_mpi.cpp @@ -58,4 +58,4 @@ auto main(int argc, char* argv[]) -> int { Kokkos::finalize(); return 0; -} \ No newline at end of file +} From 2d4e2bfda13a700283e5b8712c894c3fa158938f Mon Sep 17 00:00:00 2001 From: haykh Date: Thu, 13 Mar 2025 19:26:07 -0400 Subject: [PATCH 448/773] bugfix in mpihdf5 test --- src/output/tests/writer-mpi.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/output/tests/writer-mpi.cpp b/src/output/tests/writer-mpi.cpp index 6ab16305f..f6d3ee88a 100644 --- a/src/output/tests/writer-mpi.cpp +++ b/src/output/tests/writer-mpi.cpp @@ -60,7 +60,7 @@ auto main(int argc, char* argv[]) -> int { { // write auto writer = out::Writer(); - writer.init(&adios, "hdf5", "test"); + writer.init(&adios, "hdf5", "test", false); writer.defineMeshLayout({ static_cast(mpi_size) * nx1 }, { static_cast(mpi_rank) * nx1 }, { nx1 }, @@ -74,13 +74,13 @@ auto main(int argc, char* argv[]) -> int { field_names.push_back(writer.fieldWriters()[0].name(i)); addresses.push_back(i); } - writer.beginWriting(0, 0.0); + writer.beginWriting(WriteMode::Fields, 0, 0.0); writer.writeField(field_names, field, addresses); - writer.endWriting(); + writer.endWriting(WriteMode::Fields); - writer.beginWriting(1, 0.1); + writer.beginWriting(WriteMode::Fields, 1, 0.1); writer.writeField(field_names, field, addresses); - writer.endWriting(); + writer.endWriting(WriteMode::Fields); adios.ExitComputationBlock(); } From 58ca99f9c57cd85fcb8a97bb094b481dd35522db Mon Sep 17 00:00:00 2001 From: haykh Date: Sat, 15 Mar 2025 14:42:26 -0400 Subject: [PATCH 449/773] deposit test pgens --- setups/tests/deposit/deposit-gr.toml | 53 +++++++++++ setups/tests/deposit/deposit-mink.toml | 69 +++++++++++++++ setups/tests/deposit/deposit-sr.toml | 53 +++++++++++ setups/tests/deposit/pgen.hpp | 116 +++++++++---------------- 4 files changed, 218 insertions(+), 73 deletions(-) create mode 100644 setups/tests/deposit/deposit-gr.toml create mode 100644 setups/tests/deposit/deposit-mink.toml create mode 100644 setups/tests/deposit/deposit-sr.toml diff --git a/setups/tests/deposit/deposit-gr.toml b/setups/tests/deposit/deposit-gr.toml new file mode 100644 index 000000000..077e3e59a --- /dev/null +++ b/setups/tests/deposit/deposit-gr.toml @@ -0,0 +1,53 @@ +[simulation] + name = "deposit-test" + engine = "srpic" + runtime = 10.0 + +[grid] + resolution = [256, 256] + extent = [[0.0, 1.0], [0.0, 1.0]] + + [grid.metric] + metric = "minkowski" + + [grid.boundaries] + fields = [["PERIODIC"], ["PERIODIC"]] + particles = [["PERIODIC"], ["PERIODIC"]] + +[scales] + larmor0 = 0.1 + skindepth0 = 0.1 + +[algorithms] + current_filters = 4 + + [algorithms.timestep] + CFL = 0.5 + +[particles] + ppc0 = 10.0 + + [[particles.species]] + label = "e-" + mass = 1.0 + charge = -1.0 + maxnpart = 1e2 + + [[particles.species]] + label = "e+" + mass = 1.0 + charge = 1.0 + maxnpart = 1e2 + +[setup] + +[output] + format = "hdf5" + interval_time = 0.01 + + [output.quantities] + quantities = ["N_1", "N_2", "E", "B", "J"] + +[diagnostics] + colored_stdout = true + blocking_timers = true diff --git a/setups/tests/deposit/deposit-mink.toml b/setups/tests/deposit/deposit-mink.toml new file mode 100644 index 000000000..df70f7552 --- /dev/null +++ b/setups/tests/deposit/deposit-mink.toml @@ -0,0 +1,69 @@ +[simulation] + name = "deposit-test-mink" + engine = "srpic" + runtime = 10.0 + +[grid] + resolution = [512, 512] + extent = [[0.0, 1.0], [0.0, 1.0]] + + [grid.metric] + metric = "minkowski" + + [grid.boundaries] + fields = [["PERIODIC"], ["PERIODIC"]] + particles = [["PERIODIC"], ["PERIODIC"]] + +[scales] + larmor0 = 0.1 + skindepth0 = 0.1 + +[algorithms] + current_filters = 4 + + [algorithms.timestep] + CFL = 0.5 + +[particles] + ppc0 = 10.0 + + [[particles.species]] + label = "e-" + mass = 1.0 + charge = -1.0 + maxnpart = 1e2 + + [[particles.species]] + label = "e+" + mass = 1.0 + charge = 1.0 + maxnpart = 1e2 + +[setup] + x1s = [0.25] + y1s = [0.85] + z1s = [0.33] + ux1s = [0.6] + uy1s = [-0.3] + uz1s = [-0.2] + + x2s = [0.25] + y2s = [0.85] + z2s = [0.33] + ux2s = [-0.2] + uy2s = [-0.2] + uz2s = [0.1] + +[output] + format = "hdf5" + interval_time = 0.01 + + [output.fields] + quantities = ["N_1", "N_2", "E", "B", "J"] + +[checkpoint] + keep = 0 + +[diagnostics] + colored_stdout = true + blocking_timers = true diff --git a/setups/tests/deposit/deposit-sr.toml b/setups/tests/deposit/deposit-sr.toml new file mode 100644 index 000000000..077e3e59a --- /dev/null +++ b/setups/tests/deposit/deposit-sr.toml @@ -0,0 +1,53 @@ +[simulation] + name = "deposit-test" + engine = "srpic" + runtime = 10.0 + +[grid] + resolution = [256, 256] + extent = [[0.0, 1.0], [0.0, 1.0]] + + [grid.metric] + metric = "minkowski" + + [grid.boundaries] + fields = [["PERIODIC"], ["PERIODIC"]] + particles = [["PERIODIC"], ["PERIODIC"]] + +[scales] + larmor0 = 0.1 + skindepth0 = 0.1 + +[algorithms] + current_filters = 4 + + [algorithms.timestep] + CFL = 0.5 + +[particles] + ppc0 = 10.0 + + [[particles.species]] + label = "e-" + mass = 1.0 + charge = -1.0 + maxnpart = 1e2 + + [[particles.species]] + label = "e+" + mass = 1.0 + charge = 1.0 + maxnpart = 1e2 + +[setup] + +[output] + format = "hdf5" + interval_time = 0.01 + + [output.quantities] + quantities = ["N_1", "N_2", "E", "B", "J"] + +[diagnostics] + colored_stdout = true + blocking_timers = true diff --git a/setups/tests/deposit/pgen.hpp b/setups/tests/deposit/pgen.hpp index fd9a41c2e..1be4deb69 100644 --- a/setups/tests/deposit/pgen.hpp +++ b/setups/tests/deposit/pgen.hpp @@ -4,14 +4,8 @@ #include "enums.h" #include "global.h" -#include "arch/kokkos_aliases.h" #include "arch/traits.h" -#include "utils/comparators.h" -#include "utils/formatting.h" -#include "utils/log.h" -#include "utils/numeric.h" -#include "archetypes/energy_dist.h" #include "archetypes/particle_injector.h" #include "archetypes/problem_generator.h" #include "framework/domain/domain.h" @@ -26,10 +20,20 @@ namespace user { struct PGen : public arch::ProblemGenerator { // compatibility traits for the problem generator - static constexpr auto engines = traits::compatible_with::value; - static constexpr auto metrics = traits::compatible_with::value; - static constexpr auto dimensions = - traits::compatible_with::value; + static constexpr auto engines { + traits::compatible_with::value + }; + static constexpr auto metrics { + traits::compatible_with::value + }; + static constexpr auto dimensions { + traits::compatible_with::value + }; // for easy access to variables in the child class using arch::ProblemGenerator::D; @@ -47,85 +51,51 @@ namespace user { const auto x1s = params.template get>("setup.x1s", empty); const auto y1s = params.template get>("setup.y1s", empty); const auto z1s = params.template get>("setup.z1s", empty); - const auto ux1s = params.template get>("setup.ux1s", + const auto phi1s = params.template get>("setup.phi1s", + empty); + const auto ux1s = params.template get>("setup.ux1s", empty); - const auto uy1s = params.template get>("setup.uy1s", + const auto uy1s = params.template get>("setup.uy1s", empty); - const auto uz1s = params.template get>("setup.uz1s", + const auto uz1s = params.template get>("setup.uz1s", empty); const auto x2s = params.template get>("setup.x2s", empty); const auto y2s = params.template get>("setup.y2s", empty); const auto z2s = params.template get>("setup.z2s", empty); - const auto ux2s = params.template get>("setup.ux2s", + const auto ux2s = params.template get>("setup.ux2s", empty); - const auto uy2s = params.template get>("setup.uy2s", + const auto uy2s = params.template get>("setup.uy2s", empty); - const auto uz2s = params.template get>("setup.uz2s", + const auto uz2s = params.template get>("setup.uz2s", empty); - // std::vector x, y, z, ux_1, uy_1, uz_1, ux_2, uy_2, uz_2; - // x.push_back(0.85); - // x.push_back(0.123); - // if constexpr (D == Dim::_2D || D == Dim::_3D) { - // y.push_back(0.32); - // y.push_back(0.321); - // } - // if constexpr (D == Dim::_3D) { - // z.push_back(0.231); - // z.push_back(0.687); - // } - // ux_1.push_back(1.0); - // uy_1.push_back(-1.0); - // uz_1.push_back(0.0); - // ux_1.push_back(1.0); - // uy_1.push_back(-2.0); - // uz_1.push_back(1.0); - // - // ux_2.push_back(1.0); - // uy_2.push_back(1.0); - // uz_2.push_back(0.0); - // ux_2.push_back(-2.0); - // uy_2.push_back(3.0); - // uz_2.push_back(-1.0); - // - const std::map> data_1 { - { "x1", x1s}, - { "x2", y1s}, - { "x3", z1s}, - {"ux1", ux1s}, - {"ux2", uy1s}, - {"ux3", uz1s} + const auto phi2s = params.template get>("setup.phi2s", + empty); + std::map> data_1 { + { "x1", x1s }, + { "x2", y1s }, + { "ux1", ux1s }, + { "ux2", uy1s }, + { "ux3", uz1s } }; - const std::map> data_2 { - { "x1", x2s}, - { "x2", y2s}, - { "x3", z2s}, - {"ux1", ux2s}, - {"ux2", uy2s}, - {"ux3", uz2s} + std::map> data_2 { + { "x1", x2s }, + { "x2", y2s }, + { "ux1", ux2s }, + { "ux2", uy2s }, + { "ux3", uz2s } }; + if constexpr (M::CoordType == Coord::Cart or D == Dim::_3D) { + data_1["x3"] = z1s; + data_2["x3"] = z2s; + } else if constexpr (D == Dim::_2D) { + data_1["phi"] = phi1s; + data_2["phi"] = phi2s; + } arch::InjectGlobally(global_domain, local_domain, (arch::spidx_t)1, data_1); arch::InjectGlobally(global_domain, local_domain, (arch::spidx_t)2, data_2); } - - // void CustomPostStep(std::size_t, long double time, Domain& domain) { - // if (time >= 0.1) { - // for (auto& species : domain.species) { - // auto ux1 = species.ux1; - // auto ux2 = species.ux2; - // auto ux3 = species.ux3; - // Kokkos::parallel_for( - // "Stop", - // species.rangeActiveParticles(), - // Lambda(index_t p) { - // ux1(p) = ZERO; - // ux2(p) = ZERO; - // ux3(p) = ZERO; - // }); - // } - // } - // } }; } // namespace user From 9fcca0b05f4b6378509cc268131a7bdd20c92bbb Mon Sep 17 00:00:00 2001 From: haykh Date: Sat, 15 Mar 2025 14:43:12 -0400 Subject: [PATCH 450/773] output domain shapes --- src/framework/domain/communications.cpp | 18 +++++----- src/framework/domain/output.cpp | 18 +++++++++- src/output/tests/writer-mpi.cpp | 1 + src/output/tests/writer-nompi.cpp | 1 + src/output/writer.cpp | 48 ++++++++++++++----------- src/output/writer.h | 6 +++- 6 files changed, 60 insertions(+), 32 deletions(-) diff --git a/src/framework/domain/communications.cpp b/src/framework/domain/communications.cpp index 7dc5d285a..0bd06b82e 100644 --- a/src/framework/domain/communications.cpp +++ b/src/framework/domain/communications.cpp @@ -36,10 +36,10 @@ namespace ntt { using comm_params_t = std::pair>; template - auto GetSendRecvRanks(Metadomain* metadomain, - Domain& domain, - dir::direction_t direction) - -> std::pair { + auto GetSendRecvRanks( + Metadomain* metadomain, + Domain& domain, + dir::direction_t direction) -> std::pair { Domain* send_to_nghbr_ptr = nullptr; Domain* recv_from_nghbr_ptr = nullptr; // set pointers to the correct send/recv domains @@ -119,11 +119,11 @@ namespace ntt { } template - auto GetSendRecvParams(Metadomain* metadomain, - Domain& domain, - dir::direction_t direction, - bool synchronize) - -> std::pair { + auto GetSendRecvParams( + Metadomain* metadomain, + Domain& domain, + dir::direction_t direction, + bool synchronize) -> std::pair { const auto [send_indrank, recv_indrank] = GetSendRecvRanks(metadomain, domain, direction); const auto [send_ind, send_rank] = send_indrank; diff --git a/src/framework/domain/output.cpp b/src/framework/domain/output.cpp index 3dc95c18a..c51894e55 100644 --- a/src/framework/domain/output.cpp +++ b/src/framework/domain/output.cpp @@ -70,6 +70,7 @@ namespace ntt { g_writer.defineMeshLayout(glob_shape_with_ghosts, off_ncells_with_ghosts, loc_shape_with_ghosts, + { local_domain->index(), ndomains() }, params.template get>( "output.fields.downsampling"), incl_ghosts, @@ -227,6 +228,17 @@ namespace ntt { const auto dwn = params.template get>( "output.fields.downsampling"); + auto off_ncells_with_ghosts = local_domain->offset_ncells(); + auto loc_shape_with_ghosts = local_domain->mesh.n_active(); + { // compute positions/sizes of meshblocks in cells in all dimensions + const auto off_ndomains = local_domain->offset_ndomains(); + if (incl_ghosts) { + for (auto d { 0 }; d <= M::Dim; ++d) { + off_ncells_with_ghosts[d] += 2 * N_GHOSTS * off_ndomains[d]; + loc_shape_with_ghosts[d] += 2 * N_GHOSTS; + } + } + } for (unsigned short dim = 0; dim < M::Dim; ++dim) { const auto l_size = local_domain->mesh.n_active()[dim]; const auto l_offset = local_domain->offset_ncells()[dim]; @@ -275,7 +287,11 @@ namespace ntt { xe(offset + i_dwn + 1) = x_Ph[dim]; } }); - g_writer.writeMesh(dim, xc, xe); + g_writer.writeMesh( + dim, + xc, + xe, + { off_ncells_with_ghosts[dim], loc_shape_with_ghosts[dim] }); } const auto output_asis = params.template get("output.debug.as_is"); // !TODO: this can probably be optimized to dump things at once diff --git a/src/output/tests/writer-mpi.cpp b/src/output/tests/writer-mpi.cpp index f6d3ee88a..4ec6941ac 100644 --- a/src/output/tests/writer-mpi.cpp +++ b/src/output/tests/writer-mpi.cpp @@ -64,6 +64,7 @@ auto main(int argc, char* argv[]) -> int { writer.defineMeshLayout({ static_cast(mpi_size) * nx1 }, { static_cast(mpi_rank) * nx1 }, { nx1 }, + { mpi_rank, mpi_size }, { dwn1 }, false, Coord::Cart); diff --git a/src/output/tests/writer-nompi.cpp b/src/output/tests/writer-nompi.cpp index 8fb2ac026..7e795c2a9 100644 --- a/src/output/tests/writer-nompi.cpp +++ b/src/output/tests/writer-nompi.cpp @@ -74,6 +74,7 @@ auto main(int argc, char* argv[]) -> int { writer.defineMeshLayout({ nx1, nx2, nx3 }, { 0, 0, 0 }, { nx1, nx2, nx3 }, + { 0, 1 }, { dwn1, dwn2, dwn3 }, false, Coord::Cart); diff --git a/src/output/writer.cpp b/src/output/writer.cpp index 95965c864..e2e094535 100644 --- a/src/output/writer.cpp +++ b/src/output/writer.cpp @@ -63,12 +63,14 @@ namespace out { m_mode = mode; } - void Writer::defineMeshLayout(const std::vector& glob_shape, - const std::vector& loc_corner, - const std::vector& loc_shape, - const std::vector& dwn, - bool incl_ghosts, - Coord coords) { + void Writer::defineMeshLayout( + const std::vector& glob_shape, + const std::vector& loc_corner, + const std::vector& loc_shape, + const std::pair& domain_idx, + const std::vector& dwn, + bool incl_ghosts, + Coord coords) { m_flds_ghosts = incl_ghosts; m_dwn = dwn; @@ -99,24 +101,24 @@ namespace out { for (std::size_t i { 0 }; i < m_flds_g_shape.size(); ++i) { // cell-centers - adios2::Dims g_shape = { m_flds_g_shape_dwn[i] }; - adios2::Dims l_corner = { m_flds_l_corner_dwn[i] }; - adios2::Dims l_shape = { m_flds_l_shape_dwn[i] }; m_io.DefineVariable("X" + std::to_string(i + 1), - g_shape, - l_corner, - l_shape, + { m_flds_g_shape_dwn[i] }, + { m_flds_l_corner_dwn[i] }, + { m_flds_l_shape_dwn[i] }, adios2::ConstantDims); // cell-edges - const auto is_last = (m_flds_l_corner[i] + m_flds_l_shape[i] == + const auto is_last = (m_flds_l_corner[i] + m_flds_l_shape[i] == m_flds_g_shape[i]); - adios2::Dims g_shape1 = { m_flds_g_shape_dwn[i] + 1 }; - adios2::Dims l_shape1 = { m_flds_l_shape_dwn[i] + (is_last ? 1 : 0) }; m_io.DefineVariable("X" + std::to_string(i + 1) + "e", - g_shape1, - l_corner, - l_shape1, + { m_flds_g_shape_dwn[i] + 1 }, + { m_flds_l_corner_dwn[i] }, + { m_flds_l_shape_dwn[i] + (is_last ? 1 : 0) }, adios2::ConstantDims); + m_io.DefineVariable("N" + std::to_string(i + 1) + "l", + { 2 * domain_idx.second }, + { 2 * domain_idx.first }, + { 2 }, + adios2::ConstantDims); } if constexpr (std::is_same::array_layout, @@ -402,9 +404,10 @@ namespace out { m_writer.Put(var, e_bins_h); } - void Writer::writeMesh(unsigned short dim, - const array_t& xc, - const array_t& xe) { + void Writer::writeMesh(unsigned short dim, + const array_t& xc, + const array_t& xe, + const std::vector& loc_off_sz) { auto varc = m_io.InquireVariable("X" + std::to_string(dim + 1)); auto vare = m_io.InquireVariable("X" + std::to_string(dim + 1) + "e"); auto xc_h = Kokkos::create_mirror_view(xc); @@ -413,6 +416,9 @@ namespace out { Kokkos::deep_copy(xe_h, xe); m_writer.Put(varc, xc_h); m_writer.Put(vare, xe_h); + auto vard = m_io.InquireVariable( + "N" + std::to_string(dim + 1) + "l"); + m_writer.Put(vard, loc_off_sz.data()); } void Writer::beginWriting(WriteModeTags write_mode, diff --git a/src/output/writer.h b/src/output/writer.h index a8abf4b12..0b95dfb0e 100644 --- a/src/output/writer.h +++ b/src/output/writer.h @@ -86,6 +86,7 @@ namespace out { void defineMeshLayout(const std::vector&, const std::vector&, const std::vector&, + const std::pair&, const std::vector&, bool, Coord); @@ -94,7 +95,10 @@ namespace out { void defineParticleOutputs(Dimension, const std::vector&); void defineSpectraOutputs(const std::vector&); - void writeMesh(unsigned short, const array_t&, const array_t&); + void writeMesh(unsigned short, + const array_t&, + const array_t&, + const std::vector&); template void writeField(const std::vector&, From 84e047c0f741d3886cc7fcdf94c1addc36d6e0aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20B=C3=B6ss?= Date: Wed, 19 Mar 2025 15:40:05 -0500 Subject: [PATCH 451/773] revert to cleaner injector for shocktest --- setups/srpic/shocktest/pgen.hpp | 152 +++++++------------------------- 1 file changed, 32 insertions(+), 120 deletions(-) diff --git a/setups/srpic/shocktest/pgen.hpp b/setups/srpic/shocktest/pgen.hpp index ff54923d1..a7bcf5c3d 100644 --- a/setups/srpic/shocktest/pgen.hpp +++ b/setups/srpic/shocktest/pgen.hpp @@ -93,16 +93,16 @@ namespace user { : arch::ProblemGenerator { p } , drift_ux { p.template get("setup.drift_ux") } , temperature { p.template get("setup.temperature") } - // , x1arr_e { p.template get>("setup.x_e") } - // , x2arr_e { p.template get>("setup.y_e") } - // , ux1arr_e { p.template get>("setup.ux_e") } - // , ux2arr_e { p.template get>("setup.uy_e") } - // , ux3arr_e { p.template get>("setup.uz_e") } - // , x1arr_i { p.template get>("setup.x_i") } - // , x2arr_i { p.template get>("setup.y_i") } - // , ux1arr_i { p.template get>("setup.ux_i") } - // , ux2arr_i { p.template get>("setup.uy_i") } - // , ux3arr_i { p.template get>("setup.uz_i") } + , x1arr_e { p.template get>("setup.x_e") } + , x2arr_e { p.template get>("setup.y_e") } + , ux1arr_e { p.template get>("setup.ux_e") } + , ux2arr_e { p.template get>("setup.uy_e") } + , ux3arr_e { p.template get>("setup.uz_e") } + , x1arr_i { p.template get>("setup.x_i") } + , x2arr_i { p.template get>("setup.y_i") } + , ux1arr_i { p.template get>("setup.ux_i") } + , ux2arr_i { p.template get>("setup.uy_i") } + , ux3arr_i { p.template get>("setup.uz_i") } , Btheta { p.template get("setup.Btheta", ZERO) } , Bmag { p.template get("setup.Bmag", ZERO) } , Bphi { p.template get("setup.Bphi", ZERO) } @@ -126,116 +126,28 @@ namespace user { return init_flds; } - // inline void InitPrtls(Domain& domain) { - // arch::InjectGlobally(*metadomain, - // domain, - // 1, - // { - // { "x1", x1arr_e }, - // { "x2", x2arr_e }, - // { "ux1", ux1arr_e }, - // { "ux2", ux1arr_e }, - // { "ux3", ux3arr_e } - // }); - // arch::InjectGlobally(*metadomain, - // domain, - // 2, - // { - // { "x1", x1arr_i }, - // { "x2", x2arr_i }, - // { "ux1", ux1arr_i }, - // { "ux2", ux1arr_i }, - // { "ux3", ux3arr_i } - // }); - // } - - inline void InitPrtls(Domain& domain) { - - // auto& species_e = domain.species[0]; - // auto& species_p = domain.species[1]; - auto& species_e = domain.species[0]; - auto& species_p = domain.species[1]; - - // array_t elec_ind("elec_ind"); - // array_t pos_ind("pos_ind"); - array_t elec_ind("elec_ind"); - array_t pos_ind("pos_ind"); - - auto offset_e = species_e.npart(); - auto offset_p = species_p.npart(); - - auto ux1_e = species_e.ux1; - auto ux2_e = species_e.ux2; - auto ux3_e = species_e.ux3; - auto i1_e = species_e.i1; - auto i2_e = species_e.i2; - auto dx1_e = species_e.dx1; - auto dx2_e = species_e.dx2; - auto phi_e = species_e.phi; - auto weight_e = species_e.weight; - auto tag_e = species_e.tag; - - auto ux1_p = species_p.ux1; - auto ux2_p = species_p.ux2; - auto ux3_p = species_p.ux3; - auto i1_p = species_p.i1; - auto i2_p = species_p.i2; - auto dx1_p = species_p.dx1; - auto dx2_p = species_p.dx2; - auto phi_p = species_p.phi; - auto weight_p = species_p.weight; - auto tag_p = species_p.tag; - - int nseed = 1; - - Kokkos::parallel_for("init_particles", nseed, KOKKOS_LAMBDA(const int& s) { - - // ToDo: fix this - auto i1_ = math::floor(10); - auto i2_ = math::floor(64); - auto dx1_ = HALF; - auto dx2_ = HALF; - - - auto elec_p = Kokkos::atomic_fetch_add(&elec_ind(), 1); - auto pos_p = Kokkos::atomic_fetch_add(&pos_ind(), 1); - - i1_e(elec_p + offset_e) = i1_; - dx1_e(elec_p + offset_e) = dx1_; - i2_e(elec_p + offset_e) = i2_; - dx2_e(elec_p + offset_e) = 2*dx2_; - // ux1_e(elec_p + offset_e) = -0.5; - // ux2_e(elec_p + offset_e) = 0.5; - ux1_e(elec_p + offset_e) = -drift_ux; - ux2_e(elec_p + offset_e) = ZERO; - ux3_e(elec_p + offset_e) = ZERO; - weight_e(elec_p + offset_e) = ONE; - tag_e(elec_p + offset_e) = ParticleTag::alive; - - i1_p(pos_p + offset_p) = i1_; - dx1_p(pos_p + offset_p) = dx1_; - i2_p(pos_p + offset_p) = i2_; - dx2_p(pos_p + offset_p) = -2*dx2_; - // ux1_p(pos_p + offset_p) = 0.5; - // ux2_p(pos_p + offset_p) = -0.5; - ux1_p(pos_p + offset_p) = -drift_ux; - ux2_p(pos_p + offset_p) = ZERO; - ux3_p(pos_p + offset_p) = ZERO; - weight_p(pos_p + offset_p) = ONE; - tag_p(pos_p + offset_p) = ParticleTag::alive; - - - }); - - - auto elec_ind_h = Kokkos::create_mirror(elec_ind); - Kokkos::deep_copy(elec_ind_h, elec_ind); - species_e.set_npart(offset_e + elec_ind_h()); - - auto pos_ind_h = Kokkos::create_mirror(pos_ind); - Kokkos::deep_copy(pos_ind_h, pos_ind); - species_p.set_npart(offset_p + pos_ind_h()); - } + inline void InitPrtls(Domain& domain) { + arch::InjectGlobally(*metadomain, + domain, + 1, + { + { "x1", x1arr_e }, + { "x2", x2arr_e }, + { "ux1", ux1arr_e }, + { "ux2", ux1arr_e }, + { "ux3", ux3arr_e } + }); + arch::InjectGlobally(*metadomain, + domain, + 2, + { + { "x1", x1arr_i }, + { "x2", x2arr_i }, + { "ux1", ux1arr_i }, + { "ux2", ux1arr_i }, + { "ux3", ux3arr_i } + }); + } }; } // namespace user From 69d4a0d180f3ae3b18600981e87a49b66929c495 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20B=C3=B6ss?= Date: Thu, 20 Mar 2025 17:06:25 -0500 Subject: [PATCH 452/773] implemented new `arch::Piston` spatial distribution to set up shock partially filled with plasma --- setups/srpic/shock/pgen.hpp | 59 ++++++++++++++++++++++------------- setups/srpic/shock/shock.toml | 11 ++++--- src/archetypes/spatial_dist.h | 30 ++++++++++++++++++ 3 files changed, 74 insertions(+), 26 deletions(-) diff --git a/setups/srpic/shock/pgen.hpp b/setups/srpic/shock/pgen.hpp index b8f169521..9bf51b866 100644 --- a/setups/srpic/shock/pgen.hpp +++ b/setups/srpic/shock/pgen.hpp @@ -79,7 +79,7 @@ namespace user { using arch::ProblemGenerator::C; using arch::ProblemGenerator::params; - const real_t drift_ux, temperature; + const real_t drift_ux, temperature, filling_fraction; const real_t Btheta, Bphi, Bmag; InitFields init_flds; @@ -91,40 +91,57 @@ namespace user { , Bmag { p.template get("setup.Bmag", ZERO) } , Btheta { p.template get("setup.Btheta", ZERO) } , Bphi { p.template get("setup.Bphi", ZERO) } - , init_flds { Bmag, Btheta, Bphi, drift_ux } {} + , init_flds { Bmag, Btheta, Bphi, drift_ux } + , filling_fraction { params.template get("setup.filling_fraction", 1.0) }{} inline PGen() {} - auto FixFieldsConst(const bc_in&, const em& comp) const - -> std::pair { - if (comp == em::ex2) { - return { init_flds.ex2({ ZERO }), true }; - } else if (comp == em::ex3) { - return { init_flds.ex3({ ZERO }), true }; - } else { - return { ZERO, false }; - } - } - auto MatchFields(real_t time) const -> InitFields { return init_flds; } inline void InitPrtls(Domain& local_domain) { + + // minimum and maximum position of particles + real_t xg_min = local_domain.mesh.extent(in::x1).first; + real_t xg_max = local_domain.mesh.extent(in::x1).second * filling_fraction; + + // define box to inject into + boundaries_t box; + // loop over all dimensions + for (unsigned short d { 0 }; d < static_cast(M::Dim); ++d) { + // compute the range for the x-direction + if (d == static_cast(in::x1)) { + box.push_back({xg_min, xg_max}); + } else { + // inject into full range in other directions + box.push_back(Range::All); + } + } + + // spatial distribution of the particles + // -> hack to use the uniform distribution in NonUniformInjector + const auto spatial_dist = arch::Piston(local_domain.mesh.metric, xg_min, xg_max, in::x1); + + // energy distribution of the particles const auto energy_dist = arch::Maxwellian(local_domain.mesh.metric, local_domain.random_pool, temperature, -drift_ux, in::x1); - const auto injector = arch::UniformInjector( - energy_dist, - { 1, 2 }); - arch::InjectUniform>( - params, - local_domain, - injector, - 1.0); + const auto injector = arch::NonUniformInjector( + energy_dist, + spatial_dist, + {1, 2}); + + arch::InjectNonUniform>( + params, + local_domain, + injector, + 1.0, // target density + false, // no weights + box); } }; diff --git a/setups/srpic/shock/shock.toml b/setups/srpic/shock/shock.toml index 4e03721f7..f954345c2 100644 --- a/setups/srpic/shock/shock.toml +++ b/setups/srpic/shock/shock.toml @@ -40,11 +40,12 @@ maxnpart = 1e8 [setup] - drift_ux = 0.1 - temperature = 1e-4 - Bmag = 1.0 - Btheta = 0.0 - Bphi = 0.0 + drift_ux = 0.1 # speed towards the wall [c] + temperature = 1e-4 # temeperature of maxwell distribution [m_e c^2] + Bmag = 1.0 # magnetic field strength as fraction of magnetisation + Btheta = 0.0 # magnetic field angle in the plane + Bphi = 0.0 # magnetic field angle out of plane + filling_fraction = 1.0 # fraction of the shock piston filled with plasma [output] interval_time = 500.0 diff --git a/src/archetypes/spatial_dist.h b/src/archetypes/spatial_dist.h index be2836da2..098e1c5bb 100644 --- a/src/archetypes/spatial_dist.h +++ b/src/archetypes/spatial_dist.h @@ -4,6 +4,7 @@ * @implements * - arch::SpatialDistribution<> * - arch::Uniform<> : arch::SpatialDistribution<> + * - arch::Piston<> : arch::SpatialDistribution<> * - arch::Replenish<> : arch::SpatialDistribution<> * @namespace * - arch:: @@ -49,6 +50,35 @@ namespace arch { } }; + template + struct Piston : public arch::SpatialDistribution + { + Piston(const M &metric, real_t xmin, real_t xmax, in piston_direction = in::x1) + : arch::SpatialDistribution{metric} + , xmin {xmin} + , xmax {xmax} + , piston_direction {piston_direction} {} + + Inline auto operator()(const coord_t &x_Ph) const -> real_t override + { + // dimentsion to fill + const auto fill_dim = static_cast(piston_direction); + + if (x_Ph[fill_dim] < xmin || x_Ph[fill_dim] > xmax) + { + return 0.0; + } + else + { + return 1.0; + } + } + + private: + real_t xmin, xmax; + in piston_direction; + }; + template struct Replenish : public SpatialDistribution { using SpatialDistribution::metric; From e4d597968bc3411d20696ef3ca15890e06eeed7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20B=C3=B6ss?= Date: Thu, 20 Mar 2025 17:43:25 -0500 Subject: [PATCH 453/773] fix inconsistency in return type --- src/archetypes/spatial_dist.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/archetypes/spatial_dist.h b/src/archetypes/spatial_dist.h index 098e1c5bb..3731922de 100644 --- a/src/archetypes/spatial_dist.h +++ b/src/archetypes/spatial_dist.h @@ -66,11 +66,11 @@ namespace arch { if (x_Ph[fill_dim] < xmin || x_Ph[fill_dim] > xmax) { - return 0.0; + return ZERO; } else { - return 1.0; + return ONE; } } From cbc20219b85a340644cc836be2cdb3a8d608f05b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20B=C3=B6ss?= Date: Fri, 21 Mar 2025 16:24:35 -0500 Subject: [PATCH 454/773] Added `MovingInjector` (wip) --- src/archetypes/particle_injector.h | 69 ++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/src/archetypes/particle_injector.h b/src/archetypes/particle_injector.h index cbcbbd389..4a6e72526 100644 --- a/src/archetypes/particle_injector.h +++ b/src/archetypes/particle_injector.h @@ -170,6 +170,75 @@ namespace arch { ~AtmosphereInjector() = default; }; + template + struct MovingInjector + { + struct TargetDensityProfile + { + const real_t nmax, xinj, xdrift; + + TargetDensityProfile(real_t xinj, real_t xdrift, real_t nmax) + : xinj{xinj}, xdrift{xdrift}, nmax{nmax} {} + + Inline auto operator()(const coord_t &x_Ph) const -> real_t + { + if constexpr ((O == in::x1) or + (O == in::x2 and (M::Dim == Dim::_2D or M::Dim == Dim::_3D)) or + (O == in::x3 and M::Dim == Dim::_3D)) + { + const auto xi = x_Ph[static_cast(O)]; + // + direction + if (xi < xinj - xdrift or xi >= xinj) + { + return ZERO; + } + else + { + if constexpr (M::CoordType == Coord::Cart) + { + return nmax; + } + else + { + raise::KernelError( + HERE, + "Moving injector in +x cannot be applied for non-cartesian"); + return ZERO; + } + } + } + else + { + raise::KernelError(HERE, "Wrong direction"); + return ZERO; + } + } + }; + using energy_dist_t = Maxwellian; + using spatial_dist_t = Replenish; + static_assert(M::is_metric, "M must be a metric class"); + static constexpr bool is_nonuniform_injector{true}; + static constexpr Dimension D{M::Dim}; + static constexpr Coord C{M::CoordType}; + + const energy_dist_t energy_dist; + const TargetDensityProfile target_density; + const spatial_dist_t spatial_dist; + const std::pair species; + + MovingInjector(const M &metric, + const ndfield_t &density, + const energy_dist_t &energy_dist, + real_t xinj, + real_t xdrift, + real_t nmax, + const std::pair &species) + : energy_dist{energy_dist}, + target_density{xinj, xdrift, nmax}, spatial_dist{metric, density, 0, target_density, nmax}, species{species} {} + + ~MovingInjector() = default; + }; + /** * @brief Injects uniform number density of particles everywhere in the domain * @param domain Domain object From 70ea9af6342afc63e25464369c68aac71dada3fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20B=C3=B6ss?= Date: Fri, 21 Mar 2025 16:25:10 -0500 Subject: [PATCH 455/773] Added `CustomPostStep` for shock pgen to continually inject particles (wip) --- setups/srpic/shock/pgen.hpp | 78 ++++++++++++++++++++++++++++++++++- setups/srpic/shock/shock.toml | 4 +- src/engines/engine_run.cpp | 2 +- 3 files changed, 79 insertions(+), 5 deletions(-) diff --git a/setups/srpic/shock/pgen.hpp b/setups/srpic/shock/pgen.hpp index 9bf51b866..7c0d750e3 100644 --- a/setups/srpic/shock/pgen.hpp +++ b/setups/srpic/shock/pgen.hpp @@ -79,7 +79,7 @@ namespace user { using arch::ProblemGenerator::C; using arch::ProblemGenerator::params; - const real_t drift_ux, temperature, filling_fraction; + const real_t drift_ux, temperature, filling_fraction, injection_rate; const real_t Btheta, Bphi, Bmag; InitFields init_flds; @@ -92,7 +92,8 @@ namespace user { , Btheta { p.template get("setup.Btheta", ZERO) } , Bphi { p.template get("setup.Bphi", ZERO) } , init_flds { Bmag, Btheta, Bphi, drift_ux } - , filling_fraction { params.template get("setup.filling_fraction", 1.0) }{} + , filling_fraction { params.template get("setup.filling_fraction", 1.0) } + , injection_rate { params.template get("setup.injection_rate", 1.0) } {} inline PGen() {} @@ -100,6 +101,11 @@ namespace user { return init_flds; } + // Inline auto TargetDensity(const coord_t &x_Ph) const -> real_t + // { + // return ONE; + // } + inline void InitPrtls(Domain& local_domain) { // minimum and maximum position of particles @@ -143,6 +149,74 @@ namespace user { false, // no weights box); } + + void CustomPostStep(std::size_t, long double time, real_t dt, Domain &domain) + { + /* + Moving injector for the particles + */ + + // energy distribution of the particles + const auto energy_dist = arch::Maxwellian(domain.mesh.metric, + domain.random_pool, + temperature, + -drift_ux, + in::x1); + + // minimum and maximum position of particles + // ToDo: Add time offset for start of movement? + real_t xg_min = domain.mesh.extent(in::x1).second * filling_fraction + + injection_rate * time - drift_ux * dt; + real_t xg_max = domain.mesh.extent(in::x1).second * filling_fraction + + injection_rate * time; + + + /* + I thought this option would be better, but I can't get it to work + */ + + // // define box to inject into + // boundaries_t box; + // // loop over all dimensions + // for (unsigned short d{0}; d < static_cast(M::Dim); ++d) + // { + // // compute the range for the x-direction + // if (d == static_cast(in::x1)) + // { + // box.push_back({xg_min, xg_max}); + // } else { + // // inject into full range in other directions + // box.push_back(Range::All); + // } + // } + + // const auto spatial_dist = arch::Replenish(domain.mesh.metric, + // domain.fields.bckp, + // box, + // TargetDensity, + // 1.0); + + // const auto injector = arch::NonUniformInjector( + // energy_dist, + // spatial_dist, + // {1, 2}); + + const auto injector = arch::MovingInjector{ + domain.mesh.metric, + domain.fields.bckp, + energy_dist, + xg_max, + xg_min, + 1.0, + {1, 2}}; + + arch::InjectNonUniform( + params, + domain, + injector, + 1.0, // target density + false); + } }; } // namespace user diff --git a/setups/srpic/shock/shock.toml b/setups/srpic/shock/shock.toml index f954345c2..772b452c9 100644 --- a/setups/srpic/shock/shock.toml +++ b/setups/srpic/shock/shock.toml @@ -45,10 +45,10 @@ Bmag = 1.0 # magnetic field strength as fraction of magnetisation Btheta = 0.0 # magnetic field angle in the plane Bphi = 0.0 # magnetic field angle out of plane - filling_fraction = 1.0 # fraction of the shock piston filled with plasma + filling_fraction = 0.1 # fraction of the shock piston filled with plasma [output] - interval_time = 500.0 + interval_time = 10.0 format = "hdf5" [output.fields] diff --git a/src/engines/engine_run.cpp b/src/engines/engine_run.cpp index 506fd121d..3ace709e9 100644 --- a/src/engines/engine_run.cpp +++ b/src/engines/engine_run.cpp @@ -52,7 +52,7 @@ namespace ntt { traits::has_method::value) { timers.start("Custom"); m_metadomain.runOnLocalDomains([&timers, this](auto& dom) { - m_pgen.CustomPostStep(step, time, dom); + m_pgen.CustomPostStep(step, time, dt, dom); }); timers.stop("Custom"); } From 972750763f79a15c5f4cb764b9e7f4901e394fe9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20B=C3=B6ss?= Date: Sat, 22 Mar 2025 11:42:48 -0500 Subject: [PATCH 456/773] bugfix --- src/archetypes/particle_injector.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/archetypes/particle_injector.h b/src/archetypes/particle_injector.h index 4a6e72526..967a77c75 100644 --- a/src/archetypes/particle_injector.h +++ b/src/archetypes/particle_injector.h @@ -188,7 +188,7 @@ namespace arch { { const auto xi = x_Ph[static_cast(O)]; // + direction - if (xi < xinj - xdrift or xi >= xinj) + if (xi < xdrift or xi >= xinj) { return ZERO; } From d7d12a31742c3303cda25a354fd724d99b9c3f5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20B=C3=B6ss?= Date: Sat, 22 Mar 2025 11:56:32 -0500 Subject: [PATCH 457/773] added start time of injection and explicitly enforce injection region (wip) --- setups/srpic/shock/pgen.hpp | 102 +++++++++++++++++----------------- setups/srpic/shock/shock.toml | 2 + 2 files changed, 54 insertions(+), 50 deletions(-) diff --git a/setups/srpic/shock/pgen.hpp b/setups/srpic/shock/pgen.hpp index 7c0d750e3..04de58406 100644 --- a/setups/srpic/shock/pgen.hpp +++ b/setups/srpic/shock/pgen.hpp @@ -79,7 +79,8 @@ namespace user { using arch::ProblemGenerator::C; using arch::ProblemGenerator::params; - const real_t drift_ux, temperature, filling_fraction, injection_rate; + const real_t drift_ux, temperature, filling_fraction, + injector_velocity, injection_start; const real_t Btheta, Bphi, Bmag; InitFields init_flds; @@ -93,7 +94,8 @@ namespace user { , Bphi { p.template get("setup.Bphi", ZERO) } , init_flds { Bmag, Btheta, Bphi, drift_ux } , filling_fraction { params.template get("setup.filling_fraction", 1.0) } - , injection_rate { params.template get("setup.injection_rate", 1.0) } {} + , injector_velocity { params.template get("setup.injector_velocity", 1.0) } + , injection_start { params.template get("setup.injection_start", 0.0) } {} inline PGen() {} @@ -164,58 +166,58 @@ namespace user { in::x1); // minimum and maximum position of particles - // ToDo: Add time offset for start of movement? - real_t xg_min = domain.mesh.extent(in::x1).second * filling_fraction + - injection_rate * time - drift_ux * dt; + real_t xg_min = domain.mesh.extent(in::x1).second * filling_fraction + + injector_velocity * (time - injection_start) + - drift_ux; // distance particles have moved in the last time step real_t xg_max = domain.mesh.extent(in::x1).second * filling_fraction + - injection_rate * time; + injector_velocity * (time - injection_start); + /* + I thought this option would be better, but I can't get it to work + */ - /* - I thought this option would be better, but I can't get it to work - */ - - // // define box to inject into - // boundaries_t box; - // // loop over all dimensions - // for (unsigned short d{0}; d < static_cast(M::Dim); ++d) - // { - // // compute the range for the x-direction - // if (d == static_cast(in::x1)) - // { - // box.push_back({xg_min, xg_max}); - // } else { - // // inject into full range in other directions - // box.push_back(Range::All); - // } - // } - - // const auto spatial_dist = arch::Replenish(domain.mesh.metric, - // domain.fields.bckp, - // box, - // TargetDensity, - // 1.0); - - // const auto injector = arch::NonUniformInjector( - // energy_dist, - // spatial_dist, - // {1, 2}); - - const auto injector = arch::MovingInjector{ - domain.mesh.metric, - domain.fields.bckp, - energy_dist, - xg_max, - xg_min, - 1.0, - {1, 2}}; + // define box to inject into + boundaries_t box; + // loop over all dimensions + for (unsigned short d{0}; d < static_cast(M::Dim); ++d) + { + // compute the range for the x-direction + if (d == static_cast(in::x1)) + { + box.push_back({xg_min, xg_max}); + } else { + // inject into full range in other directions + box.push_back(Range::All); + } + } - arch::InjectNonUniform( - params, - domain, - injector, - 1.0, // target density - false); + // const auto spatial_dist = arch::Replenish(domain.mesh.metric, + // domain.fields.bckp, + // box, + // TargetDensity, + // 1.0); + + // const auto injector = arch::NonUniformInjector( + // energy_dist, + // spatial_dist, + // {1, 2}); + + const auto injector = arch::MovingInjector{ + domain.mesh.metric, + domain.fields.bckp, + energy_dist, + xg_max, + xg_min, + 1.0, + {1, 2}}; + + arch::InjectNonUniform( + params, + domain, + injector, + 1.0, // target density + false, + box); } }; diff --git a/setups/srpic/shock/shock.toml b/setups/srpic/shock/shock.toml index 772b452c9..43da87d99 100644 --- a/setups/srpic/shock/shock.toml +++ b/setups/srpic/shock/shock.toml @@ -46,6 +46,8 @@ Btheta = 0.0 # magnetic field angle in the plane Bphi = 0.0 # magnetic field angle out of plane filling_fraction = 0.1 # fraction of the shock piston filled with plasma + injector_velocity = 1.0 # speed of injector [c] + injection_start = 0.0 # start time of moving injector [output] interval_time = 10.0 From 6cf0dc8e5eb44528d049b31111ff7ff81bb52bc3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20B=C3=B6ss?= Date: Sat, 22 Mar 2025 12:12:00 -0500 Subject: [PATCH 458/773] small bugfix --- setups/srpic/shock/pgen.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setups/srpic/shock/pgen.hpp b/setups/srpic/shock/pgen.hpp index 04de58406..1c9c9a4d3 100644 --- a/setups/srpic/shock/pgen.hpp +++ b/setups/srpic/shock/pgen.hpp @@ -167,8 +167,8 @@ namespace user { // minimum and maximum position of particles real_t xg_min = domain.mesh.extent(in::x1).second * filling_fraction - + injector_velocity * (time - injection_start) - - drift_ux; // distance particles have moved in the last time step + + injector_velocity * (time - injection_start - dt) + - drift_ux * dt; // distance particles have moved in the last time step real_t xg_max = domain.mesh.extent(in::x1).second * filling_fraction + injector_velocity * (time - injection_start); From 22a0479855dad05a77b5d139e6c2d0c692dd2ead Mon Sep 17 00:00:00 2001 From: hayk Date: Mon, 24 Mar 2025 13:14:51 -0400 Subject: [PATCH 459/773] shock pgen changed --- setups/srpic/shock/pgen.hpp | 200 ++++++++++++++++++++-------------- src/archetypes/spatial_dist.h | 39 +++---- src/engines/engine_run.cpp | 2 +- 3 files changed, 134 insertions(+), 107 deletions(-) diff --git a/setups/srpic/shock/pgen.hpp b/setups/srpic/shock/pgen.hpp index 1c9c9a4d3..cc6f1b812 100644 --- a/setups/srpic/shock/pgen.hpp +++ b/setups/srpic/shock/pgen.hpp @@ -18,6 +18,16 @@ namespace user { using namespace ntt; + template + struct SpatialUniform : public arch::SpatialDistribution { + SpatialUniform(const M& metric) + : arch::SpatialDistribution { metric } {} + + Inline auto operator()(const coord_t&) const -> real_t override { + return ONE; + } + }; + template struct InitFields { /* @@ -79,8 +89,8 @@ namespace user { using arch::ProblemGenerator::C; using arch::ProblemGenerator::params; - const real_t drift_ux, temperature, filling_fraction, - injector_velocity, injection_start; + const real_t drift_ux, temperature, filling_fraction, injector_velocity, + injection_start, dt; const real_t Btheta, Bphi, Bmag; InitFields init_flds; @@ -92,10 +102,14 @@ namespace user { , Bmag { p.template get("setup.Bmag", ZERO) } , Btheta { p.template get("setup.Btheta", ZERO) } , Bphi { p.template get("setup.Bphi", ZERO) } - , init_flds { Bmag, Btheta, Bphi, drift_ux } - , filling_fraction { params.template get("setup.filling_fraction", 1.0) } - , injector_velocity { params.template get("setup.injector_velocity", 1.0) } - , injection_start { params.template get("setup.injection_start", 0.0) } {} + , init_flds { Bmag, Btheta, Bphi, drift_ux } + , filling_fraction { params.template get("setup.filling_fraction", + 1.0) } + , injector_velocity { params.template get( + "setup.injector_velocity", + 1.0) } + , injection_start { params.template get("setup.injection_start", 0.0) } + , dt { params.template get("algorithms.timestep.dt") } {} inline PGen() {} @@ -109,7 +123,7 @@ namespace user { // } inline void InitPrtls(Domain& local_domain) { - + // minimum and maximum position of particles real_t xg_min = local_domain.mesh.extent(in::x1).first; real_t xg_max = local_domain.mesh.extent(in::x1).second * filling_fraction; @@ -120,16 +134,19 @@ namespace user { for (unsigned short d { 0 }; d < static_cast(M::Dim); ++d) { // compute the range for the x-direction if (d == static_cast(in::x1)) { - box.push_back({xg_min, xg_max}); + box.push_back({ xg_min, xg_max }); } else { // inject into full range in other directions box.push_back(Range::All); } } - // spatial distribution of the particles + // spatial distribution of the particles // -> hack to use the uniform distribution in NonUniformInjector - const auto spatial_dist = arch::Piston(local_domain.mesh.metric, xg_min, xg_max, in::x1); + const auto spatial_dist = arch::Piston(local_domain.mesh.metric, + xg_min, + xg_max, + in::x1); // energy distribution of the particles const auto energy_dist = arch::Maxwellian(local_domain.mesh.metric, @@ -139,85 +156,100 @@ namespace user { in::x1); const auto injector = arch::NonUniformInjector( - energy_dist, - spatial_dist, - {1, 2}); + energy_dist, + spatial_dist, + { 1, 2 }); arch::InjectNonUniform>( - params, - local_domain, - injector, - 1.0, // target density - false, // no weights - box); + params, + local_domain, + injector, + 1.0, // target density + false, // no weights + box); } - void CustomPostStep(std::size_t, long double time, real_t dt, Domain &domain) - { - /* - Moving injector for the particles - */ - - // energy distribution of the particles - const auto energy_dist = arch::Maxwellian(domain.mesh.metric, - domain.random_pool, - temperature, - -drift_ux, - in::x1); - - // minimum and maximum position of particles - real_t xg_min = domain.mesh.extent(in::x1).second * filling_fraction - + injector_velocity * (time - injection_start - dt) - - drift_ux * dt; // distance particles have moved in the last time step - real_t xg_max = domain.mesh.extent(in::x1).second * filling_fraction + - injector_velocity * (time - injection_start); - - /* - I thought this option would be better, but I can't get it to work - */ - - // define box to inject into - boundaries_t box; - // loop over all dimensions - for (unsigned short d{0}; d < static_cast(M::Dim); ++d) - { - // compute the range for the x-direction - if (d == static_cast(in::x1)) - { - box.push_back({xg_min, xg_max}); - } else { - // inject into full range in other directions - box.push_back(Range::All); - } - } + void CustomPostStep(std::size_t, long double time, Domain& domain) { + const auto energy_dist = arch::Maxwellian(domain.mesh.metric, + domain.random_pool, + temperature, + -drift_ux, + in::x1); + const auto spatial_dist = SpatialUniform(domain.mesh.metric); + const auto injector = arch::NonUniformInjector( + energy_dist, + spatial_dist, + { 1, 2 }); + + boundaries_t box; + + const auto x_init = domain.mesh.extent(in::x1).first + + filling_fraction * (domain.mesh.extent(in::x1).second - + domain.mesh.extent(in::x1).first); + + box[0].first = x_init + injector_velocity * (time - injection_start); + box[0].second = x_init + injector_velocity * (time - injection_start + dt) - + drift_ux / math::sqrt(1 + SQR(drift_ux)) * dt; + for (auto d = 1u; d < M::Dim; ++d) { + box[d] = Range::All; + } - // const auto spatial_dist = arch::Replenish(domain.mesh.metric, - // domain.fields.bckp, - // box, - // TargetDensity, - // 1.0); - - // const auto injector = arch::NonUniformInjector( - // energy_dist, - // spatial_dist, - // {1, 2}); - - const auto injector = arch::MovingInjector{ - domain.mesh.metric, - domain.fields.bckp, - energy_dist, - xg_max, - xg_min, - 1.0, - {1, 2}}; - - arch::InjectNonUniform( - params, - domain, - injector, - 1.0, // target density - false, - box); + arch::InjectNonUniform(params, + domain, + injector, + ONE, + false, + box); + + // /* + // Moving injector for the particles + // */ + // + // // minimum and maximum position of particles + // real_t xg_min = domain.mesh.extent(in::x1).second * filling_fraction + + // injector_velocity * (time - injection_start - dt) - + // drift_ux * + // dt; // distance particles have moved in the last time step + // real_t xg_max = domain.mesh.extent(in::x1).second * filling_fraction + + // injector_velocity * (time - injection_start); + // + // /* + // I thought this option would be better, but I can't get it to work + // */ + // + // // define box to inject into + // // loop over all dimensions + // for (unsigned short d { 0 }; d < static_cast(M::Dim); ++d) { + // // compute the range for the x-direction + // if (d == static_cast(in::x1)) { + // box.push_back({ xg_min, xg_max }); + // } else { + // // inject into full range in other directions + // box.push_back(Range::All); + // } + // } + + // const auto spatial_dist = arch::Replenish(domain.mesh.metric, + // domain.fields.bckp, + // box, + // TargetDensity, + // 1.0); + + // const auto injector = arch::NonUniformInjector( + // energy_dist, + // spatial_dist, + // {1, 2}); + + // const auto injector = arch::MovingInjector { + // domain.mesh.metric, + // domain.fields.bckp, + // energy_dist, + // xg_max, + // xg_min, + // 1.0, + // { 1, 2 } + // }; } }; diff --git a/src/archetypes/spatial_dist.h b/src/archetypes/spatial_dist.h index 3731922de..3555aaca5 100644 --- a/src/archetypes/spatial_dist.h +++ b/src/archetypes/spatial_dist.h @@ -51,32 +51,27 @@ namespace arch { }; template - struct Piston : public arch::SpatialDistribution - { - Piston(const M &metric, real_t xmin, real_t xmax, in piston_direction = in::x1) - : arch::SpatialDistribution{metric} - , xmin {xmin} - , xmax {xmax} - , piston_direction {piston_direction} {} - - Inline auto operator()(const coord_t &x_Ph) const -> real_t override - { - // dimentsion to fill - const auto fill_dim = static_cast(piston_direction); - - if (x_Ph[fill_dim] < xmin || x_Ph[fill_dim] > xmax) - { - return ZERO; - } - else - { - return ONE; - } + struct Piston : public arch::SpatialDistribution { + Piston(const M& metric, real_t xmin, real_t xmax, in piston_direction = in::x1) + : arch::SpatialDistribution { metric } + , xmin { xmin } + , xmax { xmax } + , piston_direction { piston_direction } {} + + Inline auto operator()(const coord_t& x_Ph) const -> real_t override { + // dimentsion to fill + const auto fill_dim = static_cast(piston_direction); + + if (x_Ph[fill_dim] < xmin || x_Ph[fill_dim] > xmax) { + return ZERO; + } else { + return ONE; } + } private: real_t xmin, xmax; - in piston_direction; + in piston_direction; }; template diff --git a/src/engines/engine_run.cpp b/src/engines/engine_run.cpp index 3ace709e9..506fd121d 100644 --- a/src/engines/engine_run.cpp +++ b/src/engines/engine_run.cpp @@ -52,7 +52,7 @@ namespace ntt { traits::has_method::value) { timers.start("Custom"); m_metadomain.runOnLocalDomains([&timers, this](auto& dom) { - m_pgen.CustomPostStep(step, time, dt, dom); + m_pgen.CustomPostStep(step, time, dom); }); timers.stop("Custom"); } From 13da0dda1a67d2fba6c7e6d7111965b75f0f0ce0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20B=C3=B6ss?= Date: Mon, 24 Mar 2025 15:31:41 -0500 Subject: [PATCH 460/773] reduce resolution for faster test --- setups/srpic/shock/shock.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setups/srpic/shock/shock.toml b/setups/srpic/shock/shock.toml index 43da87d99..ca19a4078 100644 --- a/setups/srpic/shock/shock.toml +++ b/setups/srpic/shock/shock.toml @@ -4,8 +4,8 @@ runtime = 30000.0 [grid] - resolution = [16384, 128] - extent = [[0.0, 8000.0], [-31.25, 31.25]] + resolution = [4096, 128] + extent = [[0.0, 2000.0], [-31.25, 31.25]] [grid.metric] metric = "minkowski" From 54f083fe77d849e0c9658ab5714f10dd38915926 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20B=C3=B6ss?= Date: Mon, 24 Mar 2025 15:31:52 -0500 Subject: [PATCH 461/773] cleanup and bugfix --- setups/srpic/shock/pgen.hpp | 195 +++++++++++++++++------------------- 1 file changed, 92 insertions(+), 103 deletions(-) diff --git a/setups/srpic/shock/pgen.hpp b/setups/srpic/shock/pgen.hpp index cc6f1b812..2454c9037 100644 --- a/setups/srpic/shock/pgen.hpp +++ b/setups/srpic/shock/pgen.hpp @@ -18,16 +18,6 @@ namespace user { using namespace ntt; - template - struct SpatialUniform : public arch::SpatialDistribution { - SpatialUniform(const M& metric) - : arch::SpatialDistribution { metric } {} - - Inline auto operator()(const coord_t&) const -> real_t override { - return ONE; - } - }; - template struct InitFields { /* @@ -89,10 +79,13 @@ namespace user { using arch::ProblemGenerator::C; using arch::ProblemGenerator::params; - const real_t drift_ux, temperature, filling_fraction, injector_velocity, - injection_start, dt; + // gas properties + const real_t drift_ux, temperature, filling_fraction; + // injector properties + const real_t injector_velocity, injection_start, dt; + const bool injection_on; - const real_t Btheta, Bphi, Bmag; + real_t Btheta, Bphi, Bmag; InitFields init_flds; inline PGen(const SimulationParams& p, const Metadomain& m) @@ -103,13 +96,11 @@ namespace user { , Btheta { p.template get("setup.Btheta", ZERO) } , Bphi { p.template get("setup.Bphi", ZERO) } , init_flds { Bmag, Btheta, Bphi, drift_ux } - , filling_fraction { params.template get("setup.filling_fraction", - 1.0) } - , injector_velocity { params.template get( - "setup.injector_velocity", - 1.0) } - , injection_start { params.template get("setup.injection_start", 0.0) } - , dt { params.template get("algorithms.timestep.dt") } {} + , filling_fraction { p.template get("setup.filling_fraction", 1.0) } + , injector_velocity { p.template get("setup.injector_velocity", 1.0) } + , injection_start { p.template get("setup.injection_start", 0.0) } + , injection_on { p.template get("setup.continuous_injection", true) } + , dt { p.template get("algorithms.timestep.dt") } {} inline PGen() {} @@ -117,16 +108,13 @@ namespace user { return init_flds; } - // Inline auto TargetDensity(const coord_t &x_Ph) const -> real_t - // { - // return ONE; - // } - inline void InitPrtls(Domain& local_domain) { // minimum and maximum position of particles real_t xg_min = local_domain.mesh.extent(in::x1).first; - real_t xg_max = local_domain.mesh.extent(in::x1).second * filling_fraction; + real_t xg_max = local_domain.mesh.extent(in::x1).first + + filling_fraction * (local_domain.mesh.extent(in::x1).second - + local_domain.mesh.extent(in::x1).first); // define box to inject into boundaries_t box; @@ -170,86 +158,87 @@ namespace user { } void CustomPostStep(std::size_t, long double time, Domain& domain) { - const auto energy_dist = arch::Maxwellian(domain.mesh.metric, - domain.random_pool, - temperature, - -drift_ux, - in::x1); - const auto spatial_dist = SpatialUniform(domain.mesh.metric); - const auto injector = arch::NonUniformInjector( - energy_dist, - spatial_dist, - { 1, 2 }); - boundaries_t box; - - const auto x_init = domain.mesh.extent(in::x1).first + - filling_fraction * (domain.mesh.extent(in::x1).second - - domain.mesh.extent(in::x1).first); + // ToDo: more performant version? + if (injection_on) { + // same maxwell distribution as above + const auto energy_dist = arch::Maxwellian(domain.mesh.metric, + domain.random_pool, + temperature, + -drift_ux, + in::x1); + + // initial position of injector + const auto x_init = domain.mesh.extent(in::x1).first + + filling_fraction * (domain.mesh.extent(in::x1).second - + domain.mesh.extent(in::x1).first); + + // check if injector is supposed to start moving already + const auto dt_inj = time - injection_start > ZERO ? time - injection_start + : ZERO; + + // define box to inject into + boundaries_t box; + + // loop over all dimension + for (auto d = 0u; d < M::Dim; ++d) { + if (d == 0) { + box.push_back({ x_init + injector_velocity * (dt_inj)-drift_ux / + math::sqrt(1 + SQR(drift_ux)) * dt, + x_init + injector_velocity * (dt_inj + dt) }); + } else { + box.push_back(Range::All); + } + } - box[0].first = x_init + injector_velocity * (time - injection_start); - box[0].second = x_init + injector_velocity * (time - injection_start + dt) - - drift_ux / math::sqrt(1 + SQR(drift_ux)) * dt; - for (auto d = 1u; d < M::Dim; ++d) { - box[d] = Range::All; + // spatial distribution of the particles + // -> hack to use the uniform distribution in NonUniformInjector + const auto spatial_dist = arch::Piston(domain.mesh.metric, + box[0].first, + box[0].second, + in::x1); + + // ToDo: extend Replenish to replace the current injector + const auto injector = + arch::NonUniformInjector( + energy_dist, + spatial_dist, + { 1, 2 }); + + // inject non-uniformly within the defined box + arch::InjectNonUniform(params, + domain, + injector, + ONE, + false, + box); + + /* + I thought this option would be better, but I can't get it to work + */ + + // const auto spatial_dist = arch::Replenish(domain.mesh.metric, + // domain.fields.bckp, + // box, + // TargetDensity, + // 1.0); + + // const auto injector = arch::NonUniformInjector( + // energy_dist, + // spatial_dist, + // {1, 2}); + + // const auto injector = arch::MovingInjector { + // domain.mesh.metric, + // domain.fields.bckp, + // energy_dist, + // box[0].first, + // box[0].second, + // 1.0, + // { 1, 2 } + // }; } - - arch::InjectNonUniform(params, - domain, - injector, - ONE, - false, - box); - - // /* - // Moving injector for the particles - // */ - // - // // minimum and maximum position of particles - // real_t xg_min = domain.mesh.extent(in::x1).second * filling_fraction + - // injector_velocity * (time - injection_start - dt) - - // drift_ux * - // dt; // distance particles have moved in the last time step - // real_t xg_max = domain.mesh.extent(in::x1).second * filling_fraction + - // injector_velocity * (time - injection_start); - // - // /* - // I thought this option would be better, but I can't get it to work - // */ - // - // // define box to inject into - // // loop over all dimensions - // for (unsigned short d { 0 }; d < static_cast(M::Dim); ++d) { - // // compute the range for the x-direction - // if (d == static_cast(in::x1)) { - // box.push_back({ xg_min, xg_max }); - // } else { - // // inject into full range in other directions - // box.push_back(Range::All); - // } - // } - - // const auto spatial_dist = arch::Replenish(domain.mesh.metric, - // domain.fields.bckp, - // box, - // TargetDensity, - // 1.0); - - // const auto injector = arch::NonUniformInjector( - // energy_dist, - // spatial_dist, - // {1, 2}); - - // const auto injector = arch::MovingInjector { - // domain.mesh.metric, - // domain.fields.bckp, - // energy_dist, - // xg_max, - // xg_min, - // 1.0, - // { 1, 2 } - // }; } }; From 9f45d04b528ff15f850a86584a58287e52631748 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20B=C3=B6ss?= Date: Mon, 24 Mar 2025 15:45:43 -0500 Subject: [PATCH 462/773] removed unnecessary parameter --- setups/srpic/shock/pgen.hpp | 156 +++++++++++++++++------------------- 1 file changed, 75 insertions(+), 81 deletions(-) diff --git a/setups/srpic/shock/pgen.hpp b/setups/srpic/shock/pgen.hpp index 2454c9037..30ab01538 100644 --- a/setups/srpic/shock/pgen.hpp +++ b/setups/srpic/shock/pgen.hpp @@ -83,8 +83,7 @@ namespace user { const real_t drift_ux, temperature, filling_fraction; // injector properties const real_t injector_velocity, injection_start, dt; - const bool injection_on; - + // magnetic field properties real_t Btheta, Bphi, Bmag; InitFields init_flds; @@ -99,7 +98,6 @@ namespace user { , filling_fraction { p.template get("setup.filling_fraction", 1.0) } , injector_velocity { p.template get("setup.injector_velocity", 1.0) } , injection_start { p.template get("setup.injection_start", 0.0) } - , injection_on { p.template get("setup.continuous_injection", true) } , dt { p.template get("algorithms.timestep.dt") } {} inline PGen() {} @@ -159,86 +157,82 @@ namespace user { void CustomPostStep(std::size_t, long double time, Domain& domain) { - // ToDo: more performant version? - if (injection_on) { - // same maxwell distribution as above - const auto energy_dist = arch::Maxwellian(domain.mesh.metric, - domain.random_pool, - temperature, - -drift_ux, - in::x1); - - // initial position of injector - const auto x_init = domain.mesh.extent(in::x1).first + - filling_fraction * (domain.mesh.extent(in::x1).second - - domain.mesh.extent(in::x1).first); - - // check if injector is supposed to start moving already - const auto dt_inj = time - injection_start > ZERO ? time - injection_start - : ZERO; - - // define box to inject into - boundaries_t box; - - // loop over all dimension - for (auto d = 0u; d < M::Dim; ++d) { - if (d == 0) { - box.push_back({ x_init + injector_velocity * (dt_inj)-drift_ux / - math::sqrt(1 + SQR(drift_ux)) * dt, - x_init + injector_velocity * (dt_inj + dt) }); - } else { - box.push_back(Range::All); - } - } + // same maxwell distribution as above + const auto energy_dist = arch::Maxwellian(domain.mesh.metric, + domain.random_pool, + temperature, + -drift_ux, + in::x1); + + // initial position of injector + const auto x_init = domain.mesh.extent(in::x1).first + + filling_fraction * (domain.mesh.extent(in::x1).second - + domain.mesh.extent(in::x1).first); - // spatial distribution of the particles - // -> hack to use the uniform distribution in NonUniformInjector - const auto spatial_dist = arch::Piston(domain.mesh.metric, - box[0].first, - box[0].second, - in::x1); - - // ToDo: extend Replenish to replace the current injector - const auto injector = - arch::NonUniformInjector( - energy_dist, - spatial_dist, - { 1, 2 }); - - // inject non-uniformly within the defined box - arch::InjectNonUniform(params, - domain, - injector, - ONE, - false, - box); - - /* - I thought this option would be better, but I can't get it to work - */ - - // const auto spatial_dist = arch::Replenish(domain.mesh.metric, - // domain.fields.bckp, - // box, - // TargetDensity, - // 1.0); - - // const auto injector = arch::NonUniformInjector( - // energy_dist, - // spatial_dist, - // {1, 2}); - - // const auto injector = arch::MovingInjector { - // domain.mesh.metric, - // domain.fields.bckp, - // energy_dist, - // box[0].first, - // box[0].second, - // 1.0, - // { 1, 2 } - // }; + // check if injector is supposed to start moving already + const auto dt_inj = time - injection_start > ZERO ? + time - injection_start : ZERO; + + // define box to inject into + boundaries_t box; + + // loop over all dimension + for (auto d = 0u; d < M::Dim; ++d) { + if (d == 0) { + box.push_back({ x_init + injector_velocity * dt_inj - + drift_ux / math::sqrt(1 + SQR(drift_ux)) * dt, + x_init + injector_velocity * (dt_inj + dt) }); + } else { + box.push_back(Range::All); + } } + + // spatial distribution of the particles + // -> hack to use the uniform distribution in NonUniformInjector + const auto spatial_dist = arch::Piston(domain.mesh.metric, + box[0].first, + box[0].second, + in::x1); + + // ToDo: extend Replenish to replace the current injector + const auto injector = arch::NonUniformInjector( + energy_dist, + spatial_dist, + { 1, 2 }); + + // inject non-uniformly within the defined box + arch::InjectNonUniform(params, + domain, + injector, + ONE, + false, + box); + + /* + I thought this option would be better, but I can't get it to work + */ + + // const auto spatial_dist = arch::Replenish(domain.mesh.metric, + // domain.fields.bckp, + // box, + // TargetDensity, + // 1.0); + + // const auto injector = arch::NonUniformInjector( + // energy_dist, + // spatial_dist, + // {1, 2}); + + // const auto injector = arch::MovingInjector { + // domain.mesh.metric, + // domain.fields.bckp, + // energy_dist, + // box[0].first, + // box[0].second, + // 1.0, + // { 1, 2 } + // }; } }; From aa8b8e7f10edc6316476b37297d8b980bb5c79d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20B=C3=B6ss?= Date: Mon, 24 Mar 2025 16:06:42 -0500 Subject: [PATCH 463/773] applied formatting to `MovingInjector` --- src/archetypes/particle_injector.h | 123 ++++++++++++++--------------- 1 file changed, 58 insertions(+), 65 deletions(-) diff --git a/src/archetypes/particle_injector.h b/src/archetypes/particle_injector.h index 967a77c75..818ab5bf5 100644 --- a/src/archetypes/particle_injector.h +++ b/src/archetypes/particle_injector.h @@ -171,72 +171,65 @@ namespace arch { }; template - struct MovingInjector - { - struct TargetDensityProfile - { - const real_t nmax, xinj, xdrift; - - TargetDensityProfile(real_t xinj, real_t xdrift, real_t nmax) - : xinj{xinj}, xdrift{xdrift}, nmax{nmax} {} - - Inline auto operator()(const coord_t &x_Ph) const -> real_t - { - if constexpr ((O == in::x1) or - (O == in::x2 and (M::Dim == Dim::_2D or M::Dim == Dim::_3D)) or - (O == in::x3 and M::Dim == Dim::_3D)) - { - const auto xi = x_Ph[static_cast(O)]; - // + direction - if (xi < xdrift or xi >= xinj) - { - return ZERO; - } - else - { - if constexpr (M::CoordType == Coord::Cart) - { - return nmax; - } - else - { - raise::KernelError( - HERE, - "Moving injector in +x cannot be applied for non-cartesian"); - return ZERO; - } - } - } - else - { - raise::KernelError(HERE, "Wrong direction"); - return ZERO; - } + struct MovingInjector { + struct TargetDensityProfile { + const real_t nmax, xinj, xdrift; + + TargetDensityProfile(real_t xinj, real_t xdrift, real_t nmax) + : xinj { xinj } + , xdrift { xdrift } + , nmax { nmax } {} + + Inline auto operator()(const coord_t& x_Ph) const -> real_t { + if constexpr ((O == in::x1) or + (O == in::x2 and (M::Dim == Dim::_2D or M::Dim == Dim::_3D)) or + (O == in::x3 and M::Dim == Dim::_3D)) { + const auto xi = x_Ph[static_cast(O)]; + // + direction + if (xi < xdrift or xi >= xinj) { + return ZERO; + } else { + if constexpr (M::CoordType == Coord::Cart) { + return nmax; + } else { + raise::KernelError( + HERE, + "Moving injector in +x cannot be applied for non-cartesian"); + return ZERO; } - }; - using energy_dist_t = Maxwellian; - using spatial_dist_t = Replenish; - static_assert(M::is_metric, "M must be a metric class"); - static constexpr bool is_nonuniform_injector{true}; - static constexpr Dimension D{M::Dim}; - static constexpr Coord C{M::CoordType}; - - const energy_dist_t energy_dist; - const TargetDensityProfile target_density; - const spatial_dist_t spatial_dist; - const std::pair species; - - MovingInjector(const M &metric, - const ndfield_t &density, - const energy_dist_t &energy_dist, - real_t xinj, - real_t xdrift, - real_t nmax, - const std::pair &species) - : energy_dist{energy_dist}, - target_density{xinj, xdrift, nmax}, spatial_dist{metric, density, 0, target_density, nmax}, species{species} {} - - ~MovingInjector() = default; + } + } else { + raise::KernelError(HERE, "Wrong direction"); + return ZERO; + } + } + }; + + using energy_dist_t = Maxwellian; + using spatial_dist_t = Replenish; + static_assert(M::is_metric, "M must be a metric class"); + static constexpr bool is_nonuniform_injector { true }; + static constexpr Dimension D { M::Dim }; + static constexpr Coord C { M::CoordType }; + + const energy_dist_t energy_dist; + const TargetDensityProfile target_density; + const spatial_dist_t spatial_dist; + const std::pair species; + + MovingInjector(const M& metric, + const ndfield_t& density, + const energy_dist_t& energy_dist, + real_t xinj, + real_t xdrift, + real_t nmax, + const std::pair& species) + : energy_dist { energy_dist } + , target_density { xinj, xdrift, nmax } + , spatial_dist { metric, density, 0, target_density, nmax } + , species { species } {} + + ~MovingInjector() = default; }; /** From 1e18874d3c870198ba1c74ead9ab59c1f0eca51b Mon Sep 17 00:00:00 2001 From: haykh Date: Thu, 27 Mar 2025 17:45:57 -0400 Subject: [PATCH 464/773] i+di coord push for cart --- src/kernels/particle_pusher_sr.hpp | 112 +++++++++++++++++++---------- 1 file changed, 76 insertions(+), 36 deletions(-) diff --git a/src/kernels/particle_pusher_sr.hpp b/src/kernels/particle_pusher_sr.hpp index 2e8a5f652..50fbec5b0 100644 --- a/src/kernels/particle_pusher_sr.hpp +++ b/src/kernels/particle_pusher_sr.hpp @@ -562,45 +562,85 @@ namespace kernel::sr { Inline void posUpd(bool massive, index_t& p, coord_t& xp) const { // get cartesian velocity - const real_t inv_energy { - massive ? ONE / math::sqrt(ONE + SQR(ux1(p)) + SQR(ux2(p)) + SQR(ux3(p))) - : ONE / math::sqrt(SQR(ux1(p)) + SQR(ux2(p)) + SQR(ux3(p))) - }; - vec_t vp_Cart { ux1(p) * inv_energy, - ux2(p) * inv_energy, - ux3(p) * inv_energy }; - // get cartesian position - coord_t xp_Cart { ZERO }; - metric.template convert_xyz(xp, xp_Cart); - // update cartesian position - for (auto d = 0u; d < M::PrtlDim; ++d) { - xp_Cart[d] += vp_Cart[d] * dt; - } - // transform back to code - metric.template convert_xyz(xp_Cart, xp); - - // update x1 - if constexpr (D == Dim::_1D || D == Dim::_2D || D == Dim::_3D) { - i1_prev(p) = i1(p); - dx1_prev(p) = dx1(p); - from_Xi_to_i_di(xp[0], i1(p), dx1(p)); - } + if constexpr (M::CoordType == Coord::Cart) { + // i+di push for Cartesian basis + const real_t dt_inv_energy { + massive + ? (dt / math::sqrt(ONE + SQR(ux1(p)) + SQR(ux2(p)) + SQR(ux3(p)))) + : (dt / math::sqrt(SQR(ux1(p)) + SQR(ux2(p)) + SQR(ux3(p)))) + }; + if constexpr (D == Dim::_1D || D == Dim::_2D || D == Dim::_3D) { + i1_prev(p) = i1(p); + dx1_prev(p) = dx1(p); + dx1(p) += metric.template transform<1, Idx::XYZ, Idx::U>(xp, ux1(p)) * + dt_inv_energy; + i1(p) += static_cast(dx1(p) >= ONE) - + static_cast(dx1(p) < ZERO); + dx1(p) -= (dx1(p) >= ONE); + dx1(p) += (dx1(p) < ZERO); + } + if constexpr (D == Dim::_2D || D == Dim::_3D) { + i2_prev(p) = i2(p); + dx2_prev(p) = dx2(p); + dx2(p) += metric.template transform<2, Idx::XYZ, Idx::U>(xp, ux2(p)) * + dt_inv_energy; + i2(p) += static_cast(dx2(p) >= ONE) - + static_cast(dx2(p) < ZERO); + dx2(p) -= (dx2(p) >= ONE); + dx2(p) += (dx2(p) < ZERO); + } + if constexpr (D == Dim::_3D) { + i3_prev(p) = i3(p); + dx3_prev(p) = dx3(p); + dx3(p) += metric.template transform<3, Idx::XYZ, Idx::U>(xp, ux3(p)) * + dt_inv_energy; + i3(p) += static_cast(dx3(p) >= ONE) - + static_cast(dx3(p) < ZERO); + dx3(p) -= (dx3(p) >= ONE); + dx3(p) += (dx3(p) < ZERO); + } + } else { + // full Cartesian coordinate push in non-Cartesian basis + const real_t inv_energy { + massive ? ONE / math::sqrt(ONE + SQR(ux1(p)) + SQR(ux2(p)) + SQR(ux3(p))) + : ONE / math::sqrt(SQR(ux1(p)) + SQR(ux2(p)) + SQR(ux3(p))) + }; + vec_t vp_Cart { ux1(p) * inv_energy, + ux2(p) * inv_energy, + ux3(p) * inv_energy }; + // get cartesian position + coord_t xp_Cart { ZERO }; + metric.template convert_xyz(xp, xp_Cart); + // update cartesian position + for (auto d = 0u; d < M::PrtlDim; ++d) { + xp_Cart[d] += vp_Cart[d] * dt; + } + // transform back to code + metric.template convert_xyz(xp_Cart, xp); + + // update x1 + if constexpr (D == Dim::_1D || D == Dim::_2D || D == Dim::_3D) { + i1_prev(p) = i1(p); + dx1_prev(p) = dx1(p); + from_Xi_to_i_di(xp[0], i1(p), dx1(p)); + } - // update x2 & phi - if constexpr (D == Dim::_2D || D == Dim::_3D) { - i2_prev(p) = i2(p); - dx2_prev(p) = dx2(p); - from_Xi_to_i_di(xp[1], i2(p), dx2(p)); - if constexpr (D == Dim::_2D && M::PrtlDim == Dim::_3D) { - phi(p) = xp[2]; + // update x2 & phi + if constexpr (D == Dim::_2D || D == Dim::_3D) { + i2_prev(p) = i2(p); + dx2_prev(p) = dx2(p); + from_Xi_to_i_di(xp[1], i2(p), dx2(p)); + if constexpr (D == Dim::_2D && M::PrtlDim == Dim::_3D) { + phi(p) = xp[2]; + } } - } - // update x3 - if constexpr (D == Dim::_3D) { - i3_prev(p) = i3(p); - dx3_prev(p) = dx3(p); - from_Xi_to_i_di(xp[2], i3(p), dx3(p)); + // update x3 + if constexpr (D == Dim::_3D) { + i3_prev(p) = i3(p); + dx3_prev(p) = dx3(p); + from_Xi_to_i_di(xp[2], i3(p), dx3(p)); + } } boundaryConditions(p, xp); } From d0fb4ca29ece804e9acfb3e0bc2d2438342b6267 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20B=C3=B6ss?= Date: Mon, 31 Mar 2025 11:03:57 -0500 Subject: [PATCH 465/773] first attempt at moving-window injection --- setups/srpic/shock/pgen.hpp | 123 +++++++++++++++++++++++++++++++++--- 1 file changed, 114 insertions(+), 9 deletions(-) diff --git a/setups/srpic/shock/pgen.hpp b/setups/srpic/shock/pgen.hpp index 30ab01538..9568767ff 100644 --- a/setups/srpic/shock/pgen.hpp +++ b/setups/srpic/shock/pgen.hpp @@ -83,6 +83,7 @@ namespace user { const real_t drift_ux, temperature, filling_fraction; // injector properties const real_t injector_velocity, injection_start, dt; + const int injection_frequency; // magnetic field properties real_t Btheta, Bphi, Bmag; InitFields init_flds; @@ -98,6 +99,7 @@ namespace user { , filling_fraction { p.template get("setup.filling_fraction", 1.0) } , injector_velocity { p.template get("setup.injector_velocity", 1.0) } , injection_start { p.template get("setup.injection_start", 0.0) } + , injection_frequency { p.template get("setup.injection_frequency", 100) } , dt { p.template get("algorithms.timestep.dt") } {} inline PGen() {} @@ -106,6 +108,25 @@ namespace user { return init_flds; } + auto ResetFields(const em& comp) const -> real_t { + if (comp == em::ex1) { + return init_flds.ex1({ ZERO }); + } else if (comp == em::ex2) { + return init_flds.ex2({ ZERO }); + } else if (comp == em::ex3) { + return init_flds.ex3({ ZERO }); + } else if (comp == em::bx1) { + return init_flds.bx1({ ZERO }); + } else if (comp == em::bx2) { + return init_flds.bx2({ ZERO }); + } else if (comp == em::bx3) { + return init_flds.bx3({ ZERO }); + } else { + raise::Error("Invalid component", HERE); + return ZERO; + } + } + inline void InitPrtls(Domain& local_domain) { // minimum and maximum position of particles @@ -155,14 +176,12 @@ namespace user { box); } - void CustomPostStep(std::size_t, long double time, Domain& domain) { + void CustomPostStep(std::size_t step, long double time, Domain& domain) { - // same maxwell distribution as above - const auto energy_dist = arch::Maxwellian(domain.mesh.metric, - domain.random_pool, - temperature, - -drift_ux, - in::x1); + // check if the injector should be active + if (step % injection_frequency != 0) { + return; + } // initial position of injector const auto x_init = domain.mesh.extent(in::x1).first + @@ -180,13 +199,99 @@ namespace user { for (auto d = 0u; d < M::Dim; ++d) { if (d == 0) { box.push_back({ x_init + injector_velocity * dt_inj - - drift_ux / math::sqrt(1 + SQR(drift_ux)) * dt, + drift_ux / math::sqrt(1 + SQR(drift_ux)) * dt - + 1.5 * injection_frequency * dt, x_init + injector_velocity * (dt_inj + dt) }); } else { box.push_back(Range::All); } } + // define indice range to reset fields + boundaries_t incl_ghosts; + for (auto d = 0; d < M::Dim; ++d) { + incl_ghosts.push_back({ true, true }); + } + const auto extent = domain.mesh.ExtentToRange(box, incl_ghosts); + tuple_t x_min { 0 }, x_max { 0 }; + for (auto d = 0; d < M::Dim; ++d) { + x_min[d] = extent[d].first; + x_max[d] = extent[d].second; + } + + // reset fields + std::vector comps = { em::ex1, em::ex2, em::ex3, + em::bx1, em::bx2, em::bx3 }; + + // loop over all components + for (const auto& comp : comps) { + auto value = ResetFields((em)comp); + + if constexpr (M::Dim == Dim::_1D) { + Kokkos::deep_copy(Kokkos::subview(domain.fields.em, + std::make_pair(x_min[0], x_max[0]), + comp), + value); + } else if constexpr (M::Dim == Dim::_2D) { + Kokkos::deep_copy(Kokkos::subview(domain.fields.em, + std::make_pair(x_min[0], x_max[0]), + std::make_pair(x_min[1], x_max[1]), + comp), + value); + } else if constexpr (M::Dim == Dim::_3D) { + Kokkos::deep_copy(Kokkos::subview(domain.fields.em, + std::make_pair(x_min[0], x_max[0]), + std::make_pair(x_min[1], x_max[1]), + std::make_pair(x_min[2], x_max[2]), + comp), + value); + } else { + raise::Error("Invalid dimension", HERE); + } + } + + /* + tag particles inside the injection zone as dead + */ + + // loop over particle species + for (std::size_t s { 0 }; s < 2; ++s) { + + // get particle properties + auto& species = domain.species[s]; + auto i1 = species.i1; + auto tag = species.tag; + + + // tag all particles with x > box[0].first as dead + Kokkos::parallel_for( + "RemoveParticles", + species.rangeActiveParticles(), + Lambda(index_t p) { + // check if the particle is already dead + if (tag(p) == ParticleTag::dead) { + return; + } + // select the x-coordinate index + auto x_i1 = i1(p); + // check if the particle is inside the box of new plasma + if (x_i1 > x_min[0]) { + tag(p) = ParticleTag::dead; + } + } + ); + } + + /* + Inject piston of fresh plasma + */ + + // same maxwell distribution as above + const auto energy_dist = arch::Maxwellian(domain.mesh.metric, + domain.random_pool, + temperature, + -drift_ux, + in::x1); // spatial distribution of the particles // -> hack to use the uniform distribution in NonUniformInjector const auto spatial_dist = arch::Piston(domain.mesh.metric, @@ -194,7 +299,7 @@ namespace user { box[0].second, in::x1); - // ToDo: extend Replenish to replace the current injector + // inject piston of fresh plasma const auto injector = arch::NonUniformInjector( energy_dist, spatial_dist, From 4bcb1a2ebf6ba5d100b1cc0961b2102bc305b8eb Mon Sep 17 00:00:00 2001 From: LudwigBoess Date: Mon, 31 Mar 2025 21:52:04 -0500 Subject: [PATCH 466/773] extended field reset box to the right to squash waves propagating into the empty box --- setups/srpic/shock/pgen.hpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/setups/srpic/shock/pgen.hpp b/setups/srpic/shock/pgen.hpp index 9568767ff..a25c3891a 100644 --- a/setups/srpic/shock/pgen.hpp +++ b/setups/srpic/shock/pgen.hpp @@ -190,17 +190,16 @@ namespace user { // check if injector is supposed to start moving already const auto dt_inj = time - injection_start > ZERO ? - time - injection_start : ZERO; + time - injection_start : ZERO; // define box to inject into boundaries_t box; - // loop over all dimension for (auto d = 0u; d < M::Dim; ++d) { if (d == 0) { box.push_back({ x_init + injector_velocity * dt_inj - drift_ux / math::sqrt(1 + SQR(drift_ux)) * dt - - 1.5 * injection_frequency * dt, + injection_frequency * dt, x_init + injector_velocity * (dt_inj + dt) }); } else { box.push_back(Range::All); @@ -212,7 +211,9 @@ namespace user { for (auto d = 0; d < M::Dim; ++d) { incl_ghosts.push_back({ true, true }); } - const auto extent = domain.mesh.ExtentToRange(box, incl_ghosts); + auto fields_box = box; + fields_box[0].second += injection_frequency * dt; + const auto extent = domain.mesh.ExtentToRange(fields_box, incl_ghosts); tuple_t x_min { 0 }, x_max { 0 }; for (auto d = 0; d < M::Dim; ++d) { x_min[d] = extent[d].first; @@ -220,11 +221,13 @@ namespace user { } // reset fields - std::vector comps = { em::ex1, em::ex2, em::ex3, - em::bx1, em::bx2, em::bx3 }; + std::vector comps = { em::bx1, em::bx2, em::bx3, + em::ex1, em::ex2, em::ex3 }; // loop over all components for (const auto& comp : comps) { + + // get initial field value of component auto value = ResetFields((em)comp); if constexpr (M::Dim == Dim::_1D) { @@ -262,7 +265,6 @@ namespace user { auto i1 = species.i1; auto tag = species.tag; - // tag all particles with x > box[0].first as dead Kokkos::parallel_for( "RemoveParticles", From ebe60809b3ab5021dd690f97f6a94ef6bdfd0d41 Mon Sep 17 00:00:00 2001 From: hayk Date: Tue, 1 Apr 2025 13:34:59 -0400 Subject: [PATCH 467/773] contribs --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index e0d1fe016..7287d52db 100644 --- a/README.md +++ b/README.md @@ -24,10 +24,14 @@ Our [detailed documentation](https://entity-toolkit.github.io/) includes everyth ## Contributors (alphabetical) +🎸 __Ludwig Böss__ {[@LudwigBoess](https://github.com/LudwigBoess): PIC, framework} + 👀 __Yangyang Cai__ {[@StaticObserver](https://github.com/StaticObserver): GRPIC} 🍵 __Benjamin Crinquand__ {[@bcrinquand](https://github.com/bcrinquand): GRPIC, cubed-sphere} +🚂 __Evgeny Gorbunov__ {[@Alcauchy](https://github.com/Alcauchy): PIC, framework} + :radio: __Siddhant Solanki__ {[@sidruns30](https://github.com/sidruns30): framework} 🤷 __Arno Vanthieghem__ {[@vanthieg](https://github.com/vanthieg): framework, PIC} From 08de6896e6af7761a2ed31f0979cf373435825b9 Mon Sep 17 00:00:00 2001 From: hayk Date: Tue, 1 Apr 2025 13:36:29 -0400 Subject: [PATCH 468/773] rm tasks (RUNTEST) --- TASKLIST.md | 9 --------- 1 file changed, 9 deletions(-) delete mode 100644 TASKLIST.md diff --git a/TASKLIST.md b/TASKLIST.md deleted file mode 100644 index c12f60f4c..000000000 --- a/TASKLIST.md +++ /dev/null @@ -1,9 +0,0 @@ -### Performance improvements to try - -- [ ] removing temporary variables in interpolation -- [ ] passing by value vs const ref in metric -- [ ] return physical coords one-by-one instead of by passing full vector - -### Things to look into - -1. _h fields in mpi communication From 2132b3333bbc3168d31b5559b52626ead96d66b9 Mon Sep 17 00:00:00 2001 From: hayk Date: Tue, 1 Apr 2025 13:42:15 -0400 Subject: [PATCH 469/773] bulk grpic prohibit (RUNTEST) --- src/framework/domain/output.cpp | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/framework/domain/output.cpp b/src/framework/domain/output.cpp index 9cca7cf11..8fb756130 100644 --- a/src/framework/domain/output.cpp +++ b/src/framework/domain/output.cpp @@ -329,13 +329,17 @@ namespace ntt { local_domain->fields.bckp, c); } else if (fld.id() == FldsID::V) { - ComputeMoments(params, - local_domain->mesh, - local_domain->species, - fld.species, - fld.comp[0], - local_domain->fields.bckp, - c); + if constexpr (S != SimEngine::GRPIC) { + ComputeMoments(params, + local_domain->mesh, + local_domain->species, + fld.species, + fld.comp[0], + local_domain->fields.bckp, + c); + } else { + raise::Error("Bulk velocity not supported for GRPIC", HERE); + } } else { raise::Error("Wrong moment requested for output", HERE); } From 0f2c91ea3a5b7b9ed5f6b6134f830e21956c9122 Mon Sep 17 00:00:00 2001 From: hayk Date: Tue, 1 Apr 2025 13:45:30 -0400 Subject: [PATCH 470/773] minor bug in tests (RUNTEST) --- src/output/tests/writer-mpi.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/output/tests/writer-mpi.cpp b/src/output/tests/writer-mpi.cpp index 6ab16305f..0c3000f3a 100644 --- a/src/output/tests/writer-mpi.cpp +++ b/src/output/tests/writer-mpi.cpp @@ -60,7 +60,7 @@ auto main(int argc, char* argv[]) -> int { { // write auto writer = out::Writer(); - writer.init(&adios, "hdf5", "test"); + writer.init(&adios, "hdf5", "test", false); writer.defineMeshLayout({ static_cast(mpi_size) * nx1 }, { static_cast(mpi_rank) * nx1 }, { nx1 }, From a22cd9684f722a1daf83469c454c46af9a98525e Mon Sep 17 00:00:00 2001 From: hayk Date: Tue, 1 Apr 2025 13:48:10 -0400 Subject: [PATCH 471/773] minor bug in mpi-output tests (RUNTEST) --- src/output/tests/writer-mpi.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/output/tests/writer-mpi.cpp b/src/output/tests/writer-mpi.cpp index 0c3000f3a..f6d3ee88a 100644 --- a/src/output/tests/writer-mpi.cpp +++ b/src/output/tests/writer-mpi.cpp @@ -74,13 +74,13 @@ auto main(int argc, char* argv[]) -> int { field_names.push_back(writer.fieldWriters()[0].name(i)); addresses.push_back(i); } - writer.beginWriting(0, 0.0); + writer.beginWriting(WriteMode::Fields, 0, 0.0); writer.writeField(field_names, field, addresses); - writer.endWriting(); + writer.endWriting(WriteMode::Fields); - writer.beginWriting(1, 0.1); + writer.beginWriting(WriteMode::Fields, 1, 0.1); writer.writeField(field_names, field, addresses); - writer.endWriting(); + writer.endWriting(WriteMode::Fields); adios.ExitComputationBlock(); } From 420f36f86b41a8315bc200c0fadd09d4a98a857f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20B=C3=B6ss?= Date: Tue, 1 Apr 2025 15:32:04 -0500 Subject: [PATCH 472/773] bugfix: added check to truncate the injection box at the end of the domain --- setups/srpic/shock/pgen.hpp | 48 ++++++++++++++++++++++--------------- 1 file changed, 29 insertions(+), 19 deletions(-) diff --git a/setups/srpic/shock/pgen.hpp b/setups/srpic/shock/pgen.hpp index a25c3891a..cf58b94c6 100644 --- a/setups/srpic/shock/pgen.hpp +++ b/setups/srpic/shock/pgen.hpp @@ -80,10 +80,10 @@ namespace user { using arch::ProblemGenerator::params; // gas properties - const real_t drift_ux, temperature, filling_fraction; + const real_t drift_ux, temperature, filling_fraction; // injector properties - const real_t injector_velocity, injection_start, dt; - const int injection_frequency; + const real_t injector_velocity, injection_start, dt; + const int injection_frequency; // magnetic field properties real_t Btheta, Bphi, Bmag; InitFields init_flds; @@ -189,18 +189,23 @@ namespace user { domain.mesh.extent(in::x1).first); // check if injector is supposed to start moving already - const auto dt_inj = time - injection_start > ZERO ? - time - injection_start : ZERO; + const auto dt_inj = time - injection_start > ZERO ? time - injection_start + : ZERO; + + // compute the position of the injector + auto xmax = x_init + injector_velocity * (dt_inj + dt); + if (xmax >= domain.mesh.extent(in::x1).second) { + xmax = domain.mesh.extent(in::x1).second; + } // define box to inject into boundaries_t box; // loop over all dimension for (auto d = 0u; d < M::Dim; ++d) { if (d == 0) { - box.push_back({ x_init + injector_velocity * dt_inj - - drift_ux / math::sqrt(1 + SQR(drift_ux)) * dt - - injection_frequency * dt, - x_init + injector_velocity * (dt_inj + dt) }); + box.push_back({ xmax - drift_ux / math::sqrt(1 + SQR(drift_ux)) * dt - + injection_frequency * dt, + xmax }); } else { box.push_back(Range::All); } @@ -212,7 +217,13 @@ namespace user { incl_ghosts.push_back({ true, true }); } auto fields_box = box; - fields_box[0].second += injection_frequency * dt; + // check if the box is still inside the domain + if (xmax + injection_frequency * dt < domain.mesh.extent(in::x1).second) { + fields_box[0].second += injection_frequency * dt; + } else { + // if right side of the box is outside of the domain -> truncate box + fields_box[0].second = domain.mesh.extent(in::x1).second; + } const auto extent = domain.mesh.ExtentToRange(fields_box, incl_ghosts); tuple_t x_min { 0 }, x_max { 0 }; for (auto d = 0; d < M::Dim; ++d) { @@ -221,7 +232,7 @@ namespace user { } // reset fields - std::vector comps = { em::bx1, em::bx2, em::bx3, + std::vector comps = { em::bx1, em::bx2, em::bx3, em::ex1, em::ex2, em::ex3 }; // loop over all components @@ -253,8 +264,8 @@ namespace user { } } - /* - tag particles inside the injection zone as dead + /* + tag particles inside the injection zone as dead */ // loop over particle species @@ -262,8 +273,8 @@ namespace user { // get particle properties auto& species = domain.species[s]; - auto i1 = species.i1; - auto tag = species.tag; + auto i1 = species.i1; + auto tag = species.tag; // tag all particles with x > box[0].first as dead Kokkos::parallel_for( @@ -277,14 +288,13 @@ namespace user { // select the x-coordinate index auto x_i1 = i1(p); // check if the particle is inside the box of new plasma - if (x_i1 > x_min[0]) { + if (x_i1 >= x_min[0]) { tag(p) = ParticleTag::dead; } - } - ); + }); } - /* + /* Inject piston of fresh plasma */ From 76867488994438bf98d4b41a2b9209d4764d9de9 Mon Sep 17 00:00:00 2001 From: hayk Date: Tue, 1 Apr 2025 17:31:28 -0400 Subject: [PATCH 473/773] Lf -> f in fmt --- src/engines/engine_printer.cpp | 8 ++++---- src/global/utils/diag.cpp | 7 +++---- src/global/utils/timer.cpp | 34 ++++++++++++++++------------------ 3 files changed, 23 insertions(+), 26 deletions(-) diff --git a/src/engines/engine_printer.cpp b/src/engines/engine_printer.cpp index c1a36a323..f94715d09 100644 --- a/src/engines/engine_printer.cpp +++ b/src/engines/engine_printer.cpp @@ -105,8 +105,8 @@ namespace ntt { color::RESET); } - auto bytes_to_human_readable( - std::size_t bytes) -> std::pair { + auto bytes_to_human_readable(std::size_t bytes) + -> std::pair { const std::vector units { "B", "KB", "MB", "GB", "TB" }; idx_t unit_idx = 0; auto size = static_cast(bytes); @@ -391,7 +391,7 @@ namespace ntt { add_subcategory(report, 6, "Memory footprint"); auto flds_footprint = domain.fields.memory_footprint(); auto [flds_size, flds_unit] = bytes_to_human_readable(flds_footprint); - add_param(report, 8, "Fields", "%.2Lf %s", flds_size, flds_unit.c_str()); + add_param(report, 8, "Fields", "%.2f %s", flds_size, flds_unit.c_str()); if (domain.species.size() > 0) { add_subcategory(report, 8, "Particles"); } @@ -400,7 +400,7 @@ namespace ntt { species.index(), species.label().c_str()); auto [size, unit] = bytes_to_human_readable(species.memory_footprint()); - add_param(report, 10, str.c_str(), "%.2Lf %s", size, unit.c_str()); + add_param(report, 10, str.c_str(), "%.2f %s", size, unit.c_str()); } report.pop_back(); if (idx == m_metadomain.ndomains() - 1) { diff --git a/src/global/utils/diag.cpp b/src/global/utils/diag.cpp index fbd0c4215..9a35e30c9 100644 --- a/src/global/utils/diag.cpp +++ b/src/global/utils/diag.cpp @@ -21,9 +21,8 @@ #include namespace diag { - auto npart_stats( - npart_t npart, - npart_t maxnpart) -> std::vector> { + auto npart_stats(npart_t npart, npart_t maxnpart) + -> std::vector> { auto stats = std::vector>(); #if !defined(MPI_ENABLED) stats.push_back( @@ -127,7 +126,7 @@ namespace diag { c_reset); ss << fmt::alignedTable( - { "Time:", fmt::format("%.4Lf", time), fmt::format("[Δt = %.4Lf]", dt) }, + { "Time:", fmt::format("%.4f", time), fmt::format("[Δt = %.4f]", dt) }, { c_reset, c_bgreen, c_bblack }, { 0, -6, -15 }, { ' ', ' ', ' ' }, diff --git a/src/global/utils/timer.cpp b/src/global/utils/timer.cpp index d3c14d05e..bc133b4b7 100644 --- a/src/global/utils/timer.cpp +++ b/src/global/utils/timer.cpp @@ -130,9 +130,8 @@ namespace timer { return timer_stats; } - auto Timers::printAll(TimerFlags flags, - npart_t npart, - ncells_t ncells) const -> std::string { + auto Timers::printAll(TimerFlags flags, npart_t npart, ncells_t ncells) const + -> std::string { const std::vector extras { "PrtlClear", "Output", "Checkpoint" }; const auto stats = gather(extras, npart, ncells); if (stats.empty()) { @@ -192,11 +191,11 @@ namespace timer { if (multi_rank) { ss << fmt::alignedTable( { name, - fmt::format("%.2Lf", time) + " " + units, + fmt::format("%.2f", time) + " " + units, std::to_string(tot_pct) + "%", std::to_string(var_pct) + "%", - fmt::format("%.2Lf", per_npart) + " " + units_npart, - fmt::format("%.2Lf", per_ncells) + " " + units_ncells }, + fmt::format("%.2f", per_npart) + " " + units_npart, + fmt::format("%.2f", per_ncells) + " " + units_ncells }, { c_reset, c_yellow, ((tot_pct > 60) ? c_red : ((tot_pct > 40) ? c_yellow : c_green)), @@ -210,10 +209,10 @@ namespace timer { } else { ss << fmt::alignedTable( { name, - fmt::format("%.2Lf", time) + " " + units, + fmt::format("%.2f", time) + " " + units, std::to_string(tot_pct) + "%", - fmt::format("%.2Lf", per_npart) + " " + units_npart, - fmt::format("%.2Lf", per_ncells) + " " + units_ncells }, + fmt::format("%.2f", per_npart) + " " + units_npart, + fmt::format("%.2f", per_ncells) + " " + units_ncells }, { c_reset, c_yellow, ((tot_pct > 60) ? c_red : ((tot_pct > 40) ? c_yellow : c_green)), @@ -237,7 +236,7 @@ namespace timer { if (multi_rank) { ss << fmt::alignedTable( { "Total", - fmt::format("%.2Lf", time) + " " + units, + fmt::format("%.2f", time) + " " + units, std::to_string(var_pct) + "%" }, { c_reset, c_blue, @@ -247,13 +246,12 @@ namespace timer { c_bblack, c_reset); } else { - ss << fmt::alignedTable( - { "Total", fmt::format("%.2Lf", time) + " " + units }, - { c_reset, c_blue }, - { 0, 37 }, - { ' ', ' ' }, - c_bblack, - c_reset); + ss << fmt::alignedTable({ "Total", fmt::format("%.2f", time) + " " + units }, + { c_reset, c_blue }, + { 0, 37 }, + { ' ', ' ' }, + c_bblack, + c_reset); } } @@ -271,7 +269,7 @@ namespace timer { convertTime(time, units); } ss << fmt::alignedTable({ name, - fmt::format("%.2Lf", time) + " " + units, + fmt::format("%.2f", time) + " " + units, std::to_string(tot_pct) + "%" }, { (active ? c_reset : c_bblack), (active ? c_byellow : c_bblack), From 4ee44eca54a4eba205d160176043f0ea16a75cbe Mon Sep 17 00:00:00 2001 From: hayk Date: Tue, 1 Apr 2025 17:38:48 -0400 Subject: [PATCH 474/773] dx_min between domains *10 acc --- src/framework/domain/metadomain.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/framework/domain/metadomain.cpp b/src/framework/domain/metadomain.cpp index dd0d6ffe7..a4ff1a905 100644 --- a/src/framework/domain/metadomain.cpp +++ b/src/framework/domain/metadomain.cpp @@ -392,7 +392,10 @@ namespace ntt { mpi::get_type(), MPI_COMM_WORLD); for (const auto& dx : dx_mins) { - raise::ErrorIf(!cmp::AlmostEqual(dx, dx_min), + raise::ErrorIf(!cmp::AlmostEqual(dx, + dx_min, + std::numeric_limits::epsilon() * + static_cast(10.0)), "dx_min is not the same across all MPI ranks", HERE); } From df3fca1be70472e981340eba78c8dc0eeae80cd3 Mon Sep 17 00:00:00 2001 From: hayk Date: Tue, 1 Apr 2025 18:56:07 -0400 Subject: [PATCH 475/773] exespace/memspace -> kokkos default + cmake flags changed --- CMakeLists.txt | 23 +++--- cmake/MPIConfig.cmake | 4 -- cmake/adios2Config.cmake | 2 - cmake/defaults.cmake | 36 ---------- cmake/dependencies.cmake | 11 ++- cmake/kokkosConfig.cmake | 45 ------------ legacy/src/pic/particles/particle_pusher.hpp | 73 ++++++++++---------- legacy/tests/kernels-gr.cpp | 17 ++--- legacy/tests/kernels-sr.cpp | 17 ++--- src/CMakeLists.txt | 1 - src/checkpoint/tests/checkpoint-mpi.cpp | 4 +- src/checkpoint/tests/checkpoint-nompi.cpp | 4 +- src/checkpoint/writer.cpp | 6 +- src/engines/CMakeLists.txt | 1 - src/framework/CMakeLists.txt | 1 - src/framework/containers/particles.cpp | 4 +- src/framework/domain/comm_mpi.hpp | 12 ++-- src/framework/domain/comm_nompi.hpp | 6 +- src/framework/tests/CMakeLists.txt | 1 - src/global/arch/kokkos_aliases.cpp | 54 ++++++++------- src/global/arch/kokkos_aliases.h | 22 +++--- src/kernels/tests/prtls_to_phys.cpp | 47 +++++++------ 22 files changed, 158 insertions(+), 233 deletions(-) delete mode 100644 cmake/MPIConfig.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index dd22b9308..0409c4107 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -79,11 +79,10 @@ set(BUILD_TESTING CACHE BOOL "Build tests") # ------------------------ Third-party dependencies ------------------------ # -include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/kokkosConfig.cmake) include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/dependencies.cmake) -find_or_fetch_dependency(Kokkos FALSE) -find_or_fetch_dependency(plog TRUE) +find_or_fetch_dependency(Kokkos FALSE QUIET) +find_or_fetch_dependency(plog TRUE QUIET) set(DEPENDENCIES Kokkos::kokkos) include_directories(${plog_SRC}/include) @@ -92,14 +91,15 @@ set_precision(${precision}) # MPI if(${mpi}) - include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/MPIConfig.cmake) + find_or_fetch_dependency(MPI FALSE REQUIRED) + include_directories(${MPI_CXX_INCLUDE_PATH}) + add_compile_options("-D MPI_ENABLED") set(DEPENDENCIES ${DEPENDENCIES} MPI::MPI_CXX) endif() # Output if(${output}) - include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/adios2Config.cmake) - find_or_fetch_dependency(adios2 FALSE) + find_or_fetch_dependency(adios2 FALSE QUIET) if(NOT DEFINED ENV{HDF5_ROOT}) if(DEFINED ENV{CONDA_PREFIX}) execute_process(COMMAND bash -c "conda list | grep \"hdf5\" -q" @@ -110,7 +110,7 @@ if(${output}) endif() endif() find_package(HDF5 REQUIRED) - + add_compile_options("-D OUTPUT_ENABLED") if(${mpi}) set(DEPENDENCIES ${DEPENDENCIES} adios2::cxx11_mpi) else() @@ -120,6 +120,13 @@ endif() link_libraries(${DEPENDENCIES}) +get_cmake_property(all_vars VARIABLES) +foreach(_var ${all_vars}) + if(_var MATCHES "^Kokkos_.*") + message(STATUS "PRINTING ${_var}=${${_var}}") + endif() +endforeach() + if(TESTS) # ---------------------------------- Tests --------------------------------- # include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/tests.cmake) @@ -129,7 +136,7 @@ elseif(BENCHMARK) else() # ----------------------------------- GUI ---------------------------------- # if(${gui}) - find_or_fetch_dependency(nttiny FALSE) + find_or_fetch_dependency(nttiny FALSE QUIET) endif() # ------------------------------- Main source ------------------------------ # diff --git a/cmake/MPIConfig.cmake b/cmake/MPIConfig.cmake deleted file mode 100644 index d1bfeaab2..000000000 --- a/cmake/MPIConfig.cmake +++ /dev/null @@ -1,4 +0,0 @@ -find_package(MPI REQUIRED) -include_directories(${MPI_CXX_INCLUDE_PATH}) -add_compile_options("-D MPI_ENABLED") - diff --git a/cmake/adios2Config.cmake b/cmake/adios2Config.cmake index 5c480f3d8..7e0951949 100644 --- a/cmake/adios2Config.cmake +++ b/cmake/adios2Config.cmake @@ -23,5 +23,3 @@ set(ADIOS2_USE_MPI set(ADIOS2_USE_CUDA OFF CACHE BOOL "Use CUDA for ADIOS2") - -add_compile_options("-D OUTPUT_ENABLED") diff --git a/cmake/defaults.cmake b/cmake/defaults.cmake index 46b4609c5..78e8230c7 100644 --- a/cmake/defaults.cmake +++ b/cmake/defaults.cmake @@ -51,42 +51,6 @@ endif() set_property(CACHE default_gui PROPERTY TYPE BOOL) -if(DEFINED ENV{Kokkos_ENABLE_CUDA}) - set(default_KOKKOS_ENABLE_CUDA - $ENV{Kokkos_ENABLE_CUDA} - CACHE INTERNAL "Default flag for CUDA") -else() - set(default_KOKKOS_ENABLE_CUDA - OFF - CACHE INTERNAL "Default flag for CUDA") -endif() - -set_property(CACHE default_KOKKOS_ENABLE_CUDA PROPERTY TYPE BOOL) - -if(DEFINED ENV{Kokkos_ENABLE_HIP}) - set(default_KOKKOS_ENABLE_HIP - $ENV{Kokkos_ENABLE_HIP} - CACHE INTERNAL "Default flag for HIP") -else() - set(default_KOKKOS_ENABLE_HIP - OFF - CACHE INTERNAL "Default flag for HIP") -endif() - -set_property(CACHE default_KOKKOS_ENABLE_HIP PROPERTY TYPE BOOL) - -if(DEFINED ENV{Kokkos_ENABLE_OPENMP}) - set(default_KOKKOS_ENABLE_OPENMP - $ENV{Kokkos_ENABLE_OPENMP} - CACHE INTERNAL "Default flag for OpenMP") -else() - set(default_KOKKOS_ENABLE_OPENMP - OFF - CACHE INTERNAL "Default flag for OpenMP") -endif() - -set_property(CACHE default_KOKKOS_ENABLE_OPENMP PROPERTY TYPE BOOL) - if(DEFINED ENV{Entity_ENABLE_MPI}) set(default_mpi $ENV{Entity_ENABLE_MPI} diff --git a/cmake/dependencies.cmake b/cmake/dependencies.cmake index 06a3e6a1f..a6712feb2 100644 --- a/cmake/dependencies.cmake +++ b/cmake/dependencies.cmake @@ -34,12 +34,17 @@ function(check_internet_connection) endif() endfunction() -function(find_or_fetch_dependency package_name header_only) +function(find_or_fetch_dependency package_name header_only mode) if(NOT header_only) - find_package(${package_name} QUIET) + find_package(${package_name} ${mode}) endif() if(NOT ${package_name}_FOUND) + if (${package_name} STREQUAL "Kokkos") + include(${CMAKE_CURRENT_SOURCE_DIR}/kokkosConfig.cmake) + elseif(${package_name} STREQUAL "adios2") + include(${CMAKE_CURRENT_SOURCE_DIR}/adios2Config.cmake) + endif() if(DEFINED ${package_name}_REPOSITORY AND NOT FETCHCONTENT_FULLY_DISCONNECTED) # fetching package @@ -52,7 +57,7 @@ function(find_or_fetch_dependency package_name header_only) FetchContent_Declare( ${package_name} GIT_REPOSITORY ${${package_name}_REPOSITORY} - GIT_TAG 4.3.00) + GIT_TAG 4.5.01) else() FetchContent_Declare(${package_name} GIT_REPOSITORY ${${package_name}_REPOSITORY}) diff --git a/cmake/kokkosConfig.cmake b/cmake/kokkosConfig.cmake index 63c32622d..3d038cc19 100644 --- a/cmake/kokkosConfig.cmake +++ b/cmake/kokkosConfig.cmake @@ -27,51 +27,6 @@ else() CACHE BOOL "Kokkos debug bounds check") endif() -set(Kokkos_ENABLE_HIP - ${default_KOKKOS_ENABLE_HIP} - CACHE BOOL "Enable HIP") -set(Kokkos_ENABLE_CUDA - ${default_KOKKOS_ENABLE_CUDA} - CACHE BOOL "Enable CUDA") -set(Kokkos_ENABLE_OPENMP - ${default_KOKKOS_ENABLE_OPENMP} - CACHE BOOL "Enable OpenMP") - -# set memory space -if(${Kokkos_ENABLE_CUDA}) - add_compile_definitions(CUDA_ENABLED) - set(ACC_MEM_SPACE Kokkos::CudaSpace) -elseif(${Kokkos_ENABLE_HIP}) - add_compile_definitions(HIP_ENABLED) - set(ACC_MEM_SPACE Kokkos::HIPSpace) -else() - set(ACC_MEM_SPACE Kokkos::HostSpace) -endif() - -set(HOST_MEM_SPACE Kokkos::HostSpace) - -# set execution space -if(${Kokkos_ENABLE_CUDA}) - set(ACC_EXE_SPACE Kokkos::Cuda) -elseif(${Kokkos_ENABLE_HIP}) - set(ACC_EXE_SPACE Kokkos::HIP) -elseif(${Kokkos_ENABLE_OPENMP}) - set(ACC_EXE_SPACE Kokkos::OpenMP) -else() - set(ACC_EXE_SPACE Kokkos::Serial) -endif() - -if(${Kokkos_ENABLE_OPENMP}) - set(HOST_EXE_SPACE Kokkos::OpenMP) -else() - set(HOST_EXE_SPACE Kokkos::Serial) -endif() - -add_compile_options("-D AccelExeSpace=${ACC_EXE_SPACE}") -add_compile_options("-D AccelMemSpace=${ACC_MEM_SPACE}") -add_compile_options("-D HostExeSpace=${HOST_EXE_SPACE}") -add_compile_options("-D HostMemSpace=${HOST_MEM_SPACE}") - if(${BUILD_TESTING} STREQUAL "OFF") set(Kokkos_ENABLE_TESTS OFF diff --git a/legacy/src/pic/particles/particle_pusher.hpp b/legacy/src/pic/particles/particle_pusher.hpp index 4c0ec639a..7991a95a4 100644 --- a/legacy/src/pic/particles/particle_pusher.hpp +++ b/legacy/src/pic/particles/particle_pusher.hpp @@ -1,14 +1,13 @@ #ifndef PIC_PARTICLE_PUSHER_H #define PIC_PARTICLE_PUSHER_H -#include "wrapper.h" - -#include "pic.h" +#include "utils/qmath.h" #include "io/output.h" #include "meshblock/meshblock.h" #include "meshblock/particles.h" -#include "utils/qmath.h" +#include "pic.h" +#include "wrapper.h" #include METRIC_HEADER #include @@ -73,35 +72,34 @@ namespace ntt { real_t time, real_t coeff, real_t dt, - ProblemGenerator& pgen) : - EB { mblock.em }, - i1 { particles.i1 }, - i2 { particles.i2 }, - i3 { particles.i3 }, - i1_prev { particles.i1_prev }, - i2_prev { particles.i2_prev }, - i3_prev { particles.i3_prev }, - dx1 { particles.dx1 }, - dx2 { particles.dx2 }, - dx3 { particles.dx3 }, - dx1_prev { particles.dx1_prev }, - dx2_prev { particles.dx2_prev }, - dx3_prev { particles.dx3_prev }, - ux1 { particles.ux1 }, - ux2 { particles.ux2 }, - ux3 { particles.ux3 }, - phi { particles.phi }, - tag { particles.tag }, - metric { mblock.metric }, - time { time }, - coeff { coeff }, - dt { dt }, - ni1 { (int)mblock.Ni1() }, - ni2 { (int)mblock.Ni2() }, - ni3 { (int)mblock.Ni3() } + ProblemGenerator& pgen) + : EB { mblock.em } + , i1 { particles.i1 } + , i2 { particles.i2 } + , i3 { particles.i3 } + , i1_prev { particles.i1_prev } + , i2_prev { particles.i2_prev } + , i3_prev { particles.i3_prev } + , dx1 { particles.dx1 } + , dx2 { particles.dx2 } + , dx3 { particles.dx3 } + , dx1_prev { particles.dx1_prev } + , dx2_prev { particles.dx2_prev } + , dx3_prev { particles.dx3_prev } + , ux1 { particles.ux1 } + , ux2 { particles.ux2 } + , ux3 { particles.ux3 } + , phi { particles.phi } + , tag { particles.tag } + , metric { mblock.metric } + , time { time } + , coeff { coeff } + , dt { dt } + , ni1 { (int)mblock.Ni1() } + , ni2 { (int)mblock.Ni2() } + , ni3 { (int)mblock.Ni3() } #ifdef EXTERNAL_FORCE - , - pgen { pgen } + , pgen { pgen } #endif { (void)pgen; @@ -237,7 +235,7 @@ namespace ntt { const auto coeff = charge_ovr_mass * HALF * dt * params.B0(); Kokkos::parallel_for( "ParticlesPush", - Kokkos::RangePolicy(0, particles.npart()), + Kokkos::RangePolicy(0, particles.npart()), Pusher_kernel(mblock, particles, time, coeff, dt, pgen)); } @@ -638,9 +636,9 @@ namespace ntt { template template Inline void Pusher_kernel::get3VelCntrv(T, - index_t& p, + index_t& p, vec_t& xp, - vec_t& v) const { + vec_t& v) const { metric.v3_Cart2Cntrv(xp, { ux1(p), ux2(p), ux3(p) }, v); auto inv_energy { ONE / getEnergy(T {}, p) }; v[0] *= inv_energy; @@ -666,7 +664,8 @@ namespace ntt { } template <> - Inline void Pusher_kernel::getPrtlPos(index_t& p, coord_t& xp) const { + Inline void Pusher_kernel::getPrtlPos(index_t& p, + coord_t& xp) const { xp[0] = static_cast(i1(p)) + static_cast(dx1(p)); xp[1] = static_cast(i2(p)) + static_cast(dx2(p)); xp[2] = phi(p); @@ -1066,7 +1065,7 @@ namespace ntt { #else template Inline void Pusher_kernel::initForce(coord_t& xp, - vec_t& force_Cart) const { + vec_t& force_Cart) const { coord_t xp_Ph { ZERO }; coord_t xp_Code { ZERO }; for (short d { 0 }; d < static_cast(PrtlCoordD); ++d) { diff --git a/legacy/tests/kernels-gr.cpp b/legacy/tests/kernels-gr.cpp index 84a0c952b..6962f7c9f 100644 --- a/legacy/tests/kernels-gr.cpp +++ b/legacy/tests/kernels-gr.cpp @@ -1,16 +1,16 @@ -#include "wrapper.h" - #include #include #include -#include METRIC_HEADER +#include "wrapper.h" -#include "particle_macros.h" +#include METRIC_HEADER #include "kernels/particle_pusher_gr.hpp" +#include "particle_macros.h" + template void put_value(ntt::array_t& arr, T value, int i) { auto arr_h = Kokkos::create_mirror_view(arr); @@ -154,9 +154,10 @@ auto main(int argc, char* argv[]) -> int { static_cast(1.0e-5), 10, boundaries); - Kokkos::parallel_for("ParticlesPush", - Kokkos::RangePolicy(0, 1), - kernel); + Kokkos::parallel_for( + "ParticlesPush", + Kokkos::RangePolicy(0, 1), + kernel); auto [ra, tha] = get_physical_coord(0, i1, i2, dx1, dx2, metric); const real_t pha = get_value(phi, 0); @@ -207,4 +208,4 @@ auto main(int argc, char* argv[]) -> int { ntt::GlobalFinalize(); return 0; -} \ No newline at end of file +} diff --git a/legacy/tests/kernels-sr.cpp b/legacy/tests/kernels-sr.cpp index 59ce0646b..3f64122cd 100644 --- a/legacy/tests/kernels-sr.cpp +++ b/legacy/tests/kernels-sr.cpp @@ -1,17 +1,17 @@ -#include "wrapper.h" - #include #include #include +#include "wrapper.h" + #include METRIC_HEADER #include PGEN_HEADER -#include "particle_macros.h" - #include "kernels/particle_pusher_sr.hpp" +#include "particle_macros.h" + template void put_value(ntt::array_t& arr, T value, int i) { auto arr_h = Kokkos::create_mirror_view(arr); @@ -181,9 +181,10 @@ auto main(int argc, char* argv[]) -> int { ZERO, ZERO, ZERO); - Kokkos::parallel_for("ParticlesPush", - Kokkos::RangePolicy(0, 1), - kernel); + Kokkos::parallel_for( + "ParticlesPush", + Kokkos::RangePolicy(0, 1), + kernel); auto [xa, ya] = get_cartesian_coord(0, i1, i2, dx1, dx2, phi, metric); if (!ntt::AlmostEqual(xa, @@ -221,4 +222,4 @@ auto main(int argc, char* argv[]) -> int { ntt::GlobalFinalize(); return 0; -} \ No newline at end of file +} diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a41b84900..db2ab4c92 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -17,7 +17,6 @@ # # * kokkos [required] # * plog [required] -# * toml11 [required] # * ADIOS2 [optional] # * mpi [optional] # ------------------------------ diff --git a/src/checkpoint/tests/checkpoint-mpi.cpp b/src/checkpoint/tests/checkpoint-mpi.cpp index f97202ab1..bc6d6038a 100644 --- a/src/checkpoint/tests/checkpoint-mpi.cpp +++ b/src/checkpoint/tests/checkpoint-mpi.cpp @@ -144,8 +144,8 @@ auto main(int argc, char* argv[]) -> int { writer.saveField("em", field1); writer.saveField("em0", field2); - writer.savePerDomainVariable("s1_npart", 1, 0, npart1); - writer.savePerDomainVariable("s2_npart", 1, 0, npart2); + writer.savePerDomainVariable("s1_npart", 1, 0, npart1); + writer.savePerDomainVariable("s2_npart", 1, 0, npart2); writer.saveParticleQuantity("s1_i1", npart1_globtot, diff --git a/src/checkpoint/tests/checkpoint-nompi.cpp b/src/checkpoint/tests/checkpoint-nompi.cpp index 23dbd8871..be5e97e24 100644 --- a/src/checkpoint/tests/checkpoint-nompi.cpp +++ b/src/checkpoint/tests/checkpoint-nompi.cpp @@ -105,8 +105,8 @@ auto main(int argc, char* argv[]) -> int { writer.saveField("em", field1); writer.saveField("em0", field2); - writer.savePerDomainVariable("s1_npart", 1, 0, npart1); - writer.savePerDomainVariable("s2_npart", 1, 0, npart2); + writer.savePerDomainVariable("s1_npart", 1, 0, npart1); + writer.savePerDomainVariable("s2_npart", 1, 0, npart2); writer.saveParticleQuantity("s1_i1", npart1, 0, npart1, i1); writer.saveParticleQuantity("s1_ux1", npart1, 0, npart1, u1); diff --git a/src/checkpoint/writer.cpp b/src/checkpoint/writer.cpp index a70d8de09..fe77d3b56 100644 --- a/src/checkpoint/writer.cpp +++ b/src/checkpoint/writer.cpp @@ -274,9 +274,9 @@ namespace checkpoint { std::size_t, double); template void Writer::savePerDomainVariable(const std::string&, - std::size_t, - std::size_t, - npart_t); + std::size_t, + std::size_t, + npart_t); template void Writer::saveField(const std::string&, const ndfield_t&); diff --git a/src/engines/CMakeLists.txt b/src/engines/CMakeLists.txt index 6da2f4efd..9e51330ec 100644 --- a/src/engines/CMakeLists.txt +++ b/src/engines/CMakeLists.txt @@ -25,7 +25,6 @@ # # * kokkos [required] # * plog [required] -# * toml11 [required] # * adios2 [optional] # * hdf5 [optional] # * mpi [optional] diff --git a/src/framework/CMakeLists.txt b/src/framework/CMakeLists.txt index 8802f696b..d3b68084c 100644 --- a/src/framework/CMakeLists.txt +++ b/src/framework/CMakeLists.txt @@ -28,7 +28,6 @@ # # * kokkos [required] # * plog [required] -# * toml11 [required] # * ADIOS2 [optional] # * mpi [optional] # ------------------------------ diff --git a/src/framework/containers/particles.cpp b/src/framework/containers/particles.cpp index 048d57cde..9ec8810dc 100644 --- a/src/framework/containers/particles.cpp +++ b/src/framework/containers/particles.cpp @@ -218,13 +218,13 @@ namespace ntt { Kokkos::Experimental::fill( "TagAliveParticles", - AccelExeSpace(), + Kokkos::DefaultExecutionSpace(), Kokkos::subview(this_tag, std::make_pair(static_cast(0), n_alive)), ParticleTag::alive); Kokkos::Experimental::fill( "TagDeadParticles", - AccelExeSpace(), + Kokkos::DefaultExecutionSpace(), Kokkos::subview(this_tag, std::make_pair(n_alive, n_alive + n_dead)), ParticleTag::dead); diff --git a/src/framework/domain/comm_mpi.hpp b/src/framework/domain/comm_mpi.hpp index 8c6e532de..4f382be4a 100644 --- a/src/framework/domain/comm_mpi.hpp +++ b/src/framework/domain/comm_mpi.hpp @@ -83,7 +83,7 @@ namespace comm { (long int)(send_slice[0].first); Kokkos::parallel_for( "CommunicateField-extract", - Kokkos::MDRangePolicy, AccelExeSpace>( + Kokkos::MDRangePolicy, Kokkos::DefaultExecutionSpace>( { recv_slice[0].first, comps.first }, { recv_slice[0].second, comps.second }), Lambda(index_t i1, index_t ci) { @@ -96,7 +96,7 @@ namespace comm { (long int)(send_slice[1].first); Kokkos::parallel_for( "CommunicateField-extract", - Kokkos::MDRangePolicy, AccelExeSpace>( + Kokkos::MDRangePolicy, Kokkos::DefaultExecutionSpace>( { recv_slice[0].first, recv_slice[1].first, comps.first }, { recv_slice[0].second, recv_slice[1].second, comps.second }), Lambda(index_t i1, index_t i2, index_t ci) { @@ -111,7 +111,7 @@ namespace comm { (long int)(send_slice[2].first); Kokkos::parallel_for( "CommunicateField-extract", - Kokkos::MDRangePolicy, AccelExeSpace>( + Kokkos::MDRangePolicy, Kokkos::DefaultExecutionSpace>( { recv_slice[0].first, recv_slice[1].first, recv_slice[2].first, @@ -239,7 +239,7 @@ namespace comm { const auto offset_c = comps.first; Kokkos::parallel_for( "CommunicateField-extract", - Kokkos::MDRangePolicy, AccelExeSpace>( + Kokkos::MDRangePolicy, Kokkos::DefaultExecutionSpace>( { recv_slice[0].first, comps.first }, { recv_slice[0].second, comps.second }), Lambda(index_t i1, index_t ci) { @@ -251,7 +251,7 @@ namespace comm { const auto offset_c = comps.first; Kokkos::parallel_for( "CommunicateField-extract", - Kokkos::MDRangePolicy, AccelExeSpace>( + Kokkos::MDRangePolicy, Kokkos::DefaultExecutionSpace>( { recv_slice[0].first, recv_slice[1].first, comps.first }, { recv_slice[0].second, recv_slice[1].second, comps.second }), Lambda(index_t i1, index_t i2, index_t ci) { @@ -266,7 +266,7 @@ namespace comm { const auto offset_c = comps.first; Kokkos::parallel_for( "CommunicateField-extract", - Kokkos::MDRangePolicy, AccelExeSpace>( + Kokkos::MDRangePolicy, Kokkos::DefaultExecutionSpace>( { recv_slice[0].first, recv_slice[1].first, recv_slice[2].first, diff --git a/src/framework/domain/comm_nompi.hpp b/src/framework/domain/comm_nompi.hpp index 197d336fa..b477ac176 100644 --- a/src/framework/domain/comm_nompi.hpp +++ b/src/framework/domain/comm_nompi.hpp @@ -70,7 +70,7 @@ namespace comm { (long int)(send_slice[0].first); Kokkos::parallel_for( "CommunicateField-extract", - Kokkos::MDRangePolicy, AccelExeSpace>( + Kokkos::MDRangePolicy, Kokkos::DefaultExecutionSpace>( { recv_slice[0].first, comps.first }, { recv_slice[0].second, comps.second }), Lambda(index_t i1, index_t ci) { @@ -83,7 +83,7 @@ namespace comm { (long int)(send_slice[1].first); Kokkos::parallel_for( "CommunicateField-extract", - Kokkos::MDRangePolicy, AccelExeSpace>( + Kokkos::MDRangePolicy, Kokkos::DefaultExecutionSpace>( { recv_slice[0].first, recv_slice[1].first, comps.first }, { recv_slice[0].second, recv_slice[1].second, comps.second }), Lambda(index_t i1, index_t i2, index_t ci) { @@ -98,7 +98,7 @@ namespace comm { (long int)(send_slice[2].first); Kokkos::parallel_for( "CommunicateField-extract", - Kokkos::MDRangePolicy, AccelExeSpace>( + Kokkos::MDRangePolicy, Kokkos::DefaultExecutionSpace>( { recv_slice[0].first, recv_slice[1].first, recv_slice[2].first, diff --git a/src/framework/tests/CMakeLists.txt b/src/framework/tests/CMakeLists.txt index ce188e9f1..27c456610 100644 --- a/src/framework/tests/CMakeLists.txt +++ b/src/framework/tests/CMakeLists.txt @@ -5,7 +5,6 @@ # # * kokkos [required] # * plog [required] -# * toml11 [required] # * mpi [optional] # * adios2 [optional] # diff --git a/src/global/arch/kokkos_aliases.cpp b/src/global/arch/kokkos_aliases.cpp index d6622b0e5..25397af8e 100644 --- a/src/global/arch/kokkos_aliases.cpp +++ b/src/global/arch/kokkos_aliases.cpp @@ -9,73 +9,75 @@ auto CreateParticleRangePolicy(npart_t p1, npart_t p2) -> range_t { } template <> -auto CreateRangePolicy( - const tuple_t& i1, - const tuple_t& i2) -> range_t { +auto CreateRangePolicy(const tuple_t& i1, + const tuple_t& i2) + -> range_t { index_t i1min = i1[0]; index_t i1max = i2[0]; - return Kokkos::RangePolicy(i1min, i1max); + return Kokkos::RangePolicy(i1min, i1max); } template <> -auto CreateRangePolicy( - const tuple_t& i1, - const tuple_t& i2) -> range_t { +auto CreateRangePolicy(const tuple_t& i1, + const tuple_t& i2) + -> range_t { index_t i1min = i1[0]; index_t i1max = i2[0]; index_t i2min = i1[1]; index_t i2max = i2[1]; - return Kokkos::MDRangePolicy, AccelExeSpace>({ i1min, i2min }, - { i1max, i2max }); + return Kokkos::MDRangePolicy, Kokkos::DefaultExecutionSpace>( + { i1min, i2min }, + { i1max, i2max }); } template <> -auto CreateRangePolicy( - const tuple_t& i1, - const tuple_t& i2) -> range_t { +auto CreateRangePolicy(const tuple_t& i1, + const tuple_t& i2) + -> range_t { index_t i1min = i1[0]; index_t i1max = i2[0]; index_t i2min = i1[1]; index_t i2max = i2[1]; index_t i3min = i1[2]; index_t i3max = i2[2]; - return Kokkos::MDRangePolicy, AccelExeSpace>( + return Kokkos::MDRangePolicy, Kokkos::DefaultExecutionSpace>( { i1min, i2min, i3min }, { i1max, i2max, i3max }); } template <> -auto CreateRangePolicyOnHost( - const tuple_t& i1, - const tuple_t& i2) -> range_h_t { +auto CreateRangePolicyOnHost(const tuple_t& i1, + const tuple_t& i2) + -> range_h_t { index_t i1min = i1[0]; index_t i1max = i2[0]; - return Kokkos::RangePolicy(i1min, i1max); + return Kokkos::RangePolicy(i1min, i1max); } template <> -auto CreateRangePolicyOnHost( - const tuple_t& i1, - const tuple_t& i2) -> range_h_t { +auto CreateRangePolicyOnHost(const tuple_t& i1, + const tuple_t& i2) + -> range_h_t { index_t i1min = i1[0]; index_t i1max = i2[0]; index_t i2min = i1[1]; index_t i2max = i2[1]; - return Kokkos::MDRangePolicy, HostExeSpace>({ i1min, i2min }, - { i1max, i2max }); + return Kokkos::MDRangePolicy, Kokkos::DefaultHostExecutionSpace>( + { i1min, i2min }, + { i1max, i2max }); } template <> -auto CreateRangePolicyOnHost( - const tuple_t& i1, - const tuple_t& i2) -> range_h_t { +auto CreateRangePolicyOnHost(const tuple_t& i1, + const tuple_t& i2) + -> range_h_t { index_t i1min = i1[0]; index_t i1max = i2[0]; index_t i2min = i1[1]; index_t i2max = i2[1]; index_t i3min = i1[2]; index_t i3max = i2[2]; - return Kokkos::MDRangePolicy, HostExeSpace>( + return Kokkos::MDRangePolicy, Kokkos::DefaultHostExecutionSpace>( { i1min, i2min, i3min }, { i1max, i2max, i3max }); } diff --git a/src/global/arch/kokkos_aliases.h b/src/global/arch/kokkos_aliases.h index e1a759bed..712fc6eff 100644 --- a/src/global/arch/kokkos_aliases.h +++ b/src/global/arch/kokkos_aliases.h @@ -34,7 +34,7 @@ namespace math = Kokkos; template -using array_t = Kokkos::View; +using array_t = Kokkos::View; // Array mirror alias of arbitrary type template @@ -174,17 +174,17 @@ namespace kokkos_aliases_hidden { template <> struct range_impl { - using type = Kokkos::RangePolicy; + using type = Kokkos::RangePolicy; }; template <> struct range_impl { - using type = Kokkos::MDRangePolicy, AccelExeSpace>; + using type = Kokkos::MDRangePolicy, Kokkos::DefaultExecutionSpace>; }; template <> struct range_impl { - using type = Kokkos::MDRangePolicy, AccelExeSpace>; + using type = Kokkos::MDRangePolicy, Kokkos::DefaultExecutionSpace>; }; } // namespace kokkos_aliases_hidden @@ -201,17 +201,17 @@ namespace kokkos_aliases_hidden { template <> struct range_h_impl { - using type = Kokkos::RangePolicy; + using type = Kokkos::RangePolicy; }; template <> struct range_h_impl { - using type = Kokkos::MDRangePolicy, HostExeSpace>; + using type = Kokkos::MDRangePolicy, Kokkos::DefaultHostExecutionSpace>; }; template <> struct range_h_impl { - using type = Kokkos::MDRangePolicy, HostExeSpace>; + using type = Kokkos::MDRangePolicy, Kokkos::DefaultHostExecutionSpace>; }; } // namespace kokkos_aliases_hidden @@ -234,8 +234,8 @@ auto CreateParticleRangePolicy(npart_t, npart_t) -> range_t; * @returns Kokkos::RangePolicy or Kokkos::MDRangePolicy in the accelerator execution space. */ template -auto CreateRangePolicy(const tuple_t&, - const tuple_t&) -> range_t; +auto CreateRangePolicy(const tuple_t&, const tuple_t&) + -> range_t; /** * @brief Function template for generating ND Kokkos range policy on the host. @@ -249,8 +249,8 @@ auto CreateRangePolicyOnHost(const tuple_t&, const tuple_t&) -> range_h_t; // Random number pool/generator type alias -using random_number_pool_t = Kokkos::Random_XorShift1024_Pool; -using random_generator_t = typename random_number_pool_t::generator_type; +using random_number_pool_t = Kokkos::Random_XorShift1024_Pool; +using random_generator_t = typename random_number_pool_t::generator_type; // Random number generator functions template diff --git a/src/kernels/tests/prtls_to_phys.cpp b/src/kernels/tests/prtls_to_phys.cpp index 4719fe6a1..962c21b5c 100644 --- a/src/kernels/tests/prtls_to_phys.cpp +++ b/src/kernels/tests/prtls_to_phys.cpp @@ -132,7 +132,7 @@ void testPrtl2PhysSR(const std::vector& res, extent = { ext[0], - {ZERO, constant::PI} + { ZERO, constant::PI } }; const M metric { res, extent, params }; @@ -177,28 +177,29 @@ void testPrtl2PhysSR(const std::vector& res, array_t buff_ux3 { "buff_ux3", nprtl / stride }; array_t buff_wei { "buff_wei", nprtl / stride }; - Kokkos::parallel_for("Init", - Kokkos::RangePolicy(0, nprtl / stride), - kernel::PrtlToPhys_kernel(stride, - buff_x1, - buff_x2, - buff_x3, - buff_ux1, - buff_ux2, - buff_ux3, - buff_wei, - i1, - i2, - i3, - dx1, - dx2, - dx3, - ux1, - ux2, - ux3, - phi, - weight, - metric)); + Kokkos::parallel_for( + "Init", + Kokkos::RangePolicy(0, nprtl / stride), + kernel::PrtlToPhys_kernel(stride, + buff_x1, + buff_x2, + buff_x3, + buff_ux1, + buff_ux2, + buff_ux3, + buff_wei, + i1, + i2, + i3, + dx1, + dx2, + dx3, + ux1, + ux2, + ux3, + phi, + weight, + metric)); Kokkos::parallel_for("Check", nprtl / stride, Checker(metric, From 18f02f64fc353752bc70d90d1d5ad31cc99e9d8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20B=C3=B6ss?= Date: Tue, 1 Apr 2025 19:46:46 -0500 Subject: [PATCH 476/773] fix unit conversion bug in field reset --- setups/srpic/shock/pgen.hpp | 40 ++++++++----------------------------- 1 file changed, 8 insertions(+), 32 deletions(-) diff --git a/setups/srpic/shock/pgen.hpp b/setups/srpic/shock/pgen.hpp index cf58b94c6..ad260bda0 100644 --- a/setups/srpic/shock/pgen.hpp +++ b/setups/srpic/shock/pgen.hpp @@ -9,6 +9,7 @@ #include "utils/numeric.h" #include "archetypes/energy_dist.h" +#include "archetypes/field_setter.h" #include "archetypes/particle_injector.h" #include "archetypes/problem_generator.h" #include "framework/domain/metadomain.h" @@ -231,38 +232,13 @@ namespace user { x_max[d] = extent[d].second; } - // reset fields - std::vector comps = { em::bx1, em::bx2, em::bx3, - em::ex1, em::ex2, em::ex3 }; - - // loop over all components - for (const auto& comp : comps) { - - // get initial field value of component - auto value = ResetFields((em)comp); - - if constexpr (M::Dim == Dim::_1D) { - Kokkos::deep_copy(Kokkos::subview(domain.fields.em, - std::make_pair(x_min[0], x_max[0]), - comp), - value); - } else if constexpr (M::Dim == Dim::_2D) { - Kokkos::deep_copy(Kokkos::subview(domain.fields.em, - std::make_pair(x_min[0], x_max[0]), - std::make_pair(x_min[1], x_max[1]), - comp), - value); - } else if constexpr (M::Dim == Dim::_3D) { - Kokkos::deep_copy(Kokkos::subview(domain.fields.em, - std::make_pair(x_min[0], x_max[0]), - std::make_pair(x_min[1], x_max[1]), - std::make_pair(x_min[2], x_max[2]), - comp), - value); - } else { - raise::Error("Invalid dimension", HERE); - } - } + Kokkos::parallel_for("ResetFields", + CreateRangePolicy(x_min, x_max), + arch::SetEMFields_kernel { + domain.fields.em, + init_flds, + domain.mesh.metric }); + /* tag particles inside the injection zone as dead From 3ccdd4db96ec7b248d21e7febb79d99c260031b8 Mon Sep 17 00:00:00 2001 From: hayk Date: Wed, 2 Apr 2025 01:27:21 -0400 Subject: [PATCH 477/773] improved report + fetch adios2 + rm hdf5 dependency --- .gitmodules | 1 - CMakeLists.txt | 17 -- cmake/adios2Config.cmake | 10 +- cmake/config.cmake | 9 +- cmake/defaults.cmake | 2 +- cmake/dependencies.cmake | 31 ++- cmake/report.cmake | 366 +++++++++------------------------ cmake/styling.cmake | 140 +++++++++++-- src/engines/CMakeLists.txt | 2 +- src/engines/engine_printer.cpp | 9 - 10 files changed, 259 insertions(+), 328 deletions(-) diff --git a/.gitmodules b/.gitmodules index e06c332fe..577d08ea6 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,7 +4,6 @@ [submodule "extern/adios2"] path = extern/adios2 url = https://github.com/ornladios/ADIOS2.git - branch = master [submodule "extern/Kokkos"] path = extern/Kokkos url = https://github.com/kokkos/kokkos.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 0409c4107..22d1e64b5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -100,16 +100,6 @@ endif() # Output if(${output}) find_or_fetch_dependency(adios2 FALSE QUIET) - if(NOT DEFINED ENV{HDF5_ROOT}) - if(DEFINED ENV{CONDA_PREFIX}) - execute_process(COMMAND bash -c "conda list | grep \"hdf5\" -q" - RESULT_VARIABLE HDF5_INSTALLED) - if(HDF5_INSTALLED EQUAL 0) - set(HDF5_ROOT $ENV{CONDA_PREFIX}) - endif() - endif() - endif() - find_package(HDF5 REQUIRED) add_compile_options("-D OUTPUT_ENABLED") if(${mpi}) set(DEPENDENCIES ${DEPENDENCIES} adios2::cxx11_mpi) @@ -120,13 +110,6 @@ endif() link_libraries(${DEPENDENCIES}) -get_cmake_property(all_vars VARIABLES) -foreach(_var ${all_vars}) - if(_var MATCHES "^Kokkos_.*") - message(STATUS "PRINTING ${_var}=${${_var}}") - endif() -endforeach() - if(TESTS) # ---------------------------------- Tests --------------------------------- # include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/tests.cmake) diff --git a/cmake/adios2Config.cmake b/cmake/adios2Config.cmake index 7e0951949..a4ce46179 100644 --- a/cmake/adios2Config.cmake +++ b/cmake/adios2Config.cmake @@ -12,14 +12,18 @@ set(ADIOS2_USE_Fortran CACHE BOOL "Use Fortran for ADIOS2") # Format/compression support -set(ADIOS2_USE_ZeroMQ - OFF - CACHE BOOL "Use ZeroMQ for ADIOS2") +set(ADIOS2_USE_HDF5 + ON + CACHE BOOL "Use HDF5 for ADIOS2") set(ADIOS2_USE_MPI ${mpi} CACHE BOOL "Use MPI for ADIOS2") +set(ADIOS2_USE_ZeroMQ + OFF + CACHE BOOL "Use ZeroMQ for ADIOS2") + set(ADIOS2_USE_CUDA OFF CACHE BOOL "Use CUDA for ADIOS2") diff --git a/cmake/config.cmake b/cmake/config.cmake index 58dd467e9..ab54717f1 100644 --- a/cmake/config.cmake +++ b/cmake/config.cmake @@ -34,13 +34,10 @@ function(set_problem_generator pgen_name) ) endif() set(PGEN - ${pgen_name} - PARENT_SCOPE) + ${pgen_name} PARENT_SCOPE) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/setups/${pgen_name}) set(PGEN_FOUND - TRUE - PARENT_SCOPE) + TRUE PARENT_SCOPE) set(problem_generators - ${PGEN_NAMES} - PARENT_SCOPE) + ${PGEN_NAMES} PARENT_SCOPE) endfunction() diff --git a/cmake/defaults.cmake b/cmake/defaults.cmake index 78e8230c7..2c72f5d7d 100644 --- a/cmake/defaults.cmake +++ b/cmake/defaults.cmake @@ -33,7 +33,7 @@ if(DEFINED ENV{Entity_ENABLE_OUTPUT}) CACHE INTERNAL "Default flag for output") else() set(default_output - OFF + ON CACHE INTERNAL "Default flag for output") endif() diff --git a/cmake/dependencies.cmake b/cmake/dependencies.cmake index a6712feb2..a31dfdea5 100644 --- a/cmake/dependencies.cmake +++ b/cmake/dependencies.cmake @@ -4,9 +4,10 @@ set(Kokkos_REPOSITORY set(plog_REPOSITORY https://github.com/SergiusTheBest/plog.git CACHE STRING "plog repository") +set (adios2_REPOSITORY + https://github.com/ornladios/ADIOS2.git + CACHE STRING "ADIOS2 repository") -# set (adios2_REPOSITORY https://github.com/ornladios/ADIOS2.git CACHE STRING -# "ADIOS2 repository") function(check_internet_connection) if(OFFLINE STREQUAL "ON") set(FETCHCONTENT_FULLY_DISCONNECTED @@ -41,9 +42,9 @@ function(find_or_fetch_dependency package_name header_only mode) if(NOT ${package_name}_FOUND) if (${package_name} STREQUAL "Kokkos") - include(${CMAKE_CURRENT_SOURCE_DIR}/kokkosConfig.cmake) + include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/kokkosConfig.cmake) elseif(${package_name} STREQUAL "adios2") - include(${CMAKE_CURRENT_SOURCE_DIR}/adios2Config.cmake) + include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/adios2Config.cmake) endif() if(DEFINED ${package_name}_REPOSITORY AND NOT FETCHCONTENT_FULLY_DISCONNECTED) @@ -70,6 +71,9 @@ function(find_or_fetch_dependency package_name header_only mode) set(${package_name}_SRC ${CMAKE_CURRENT_BINARY_DIR}/_deps/${lower_pckg_name}-src CACHE PATH "Path to ${package_name} src") + set(${package_name}_BUILD_DIR + ${CMAKE_CURRENT_BINARY_DIR}/_deps/${lower_pckg_name}-build + CACHE PATH "Path to ${package_name} build") set(${package_name}_FETCHED TRUE CACHE BOOL "Whether ${package_name} was fetched") @@ -96,7 +100,7 @@ function(find_or_fetch_dependency package_name header_only mode) endif() add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/extern/${package_name} - extern/${package_name}) + extern/${package_name}) set(${package_name}_SRC ${CMAKE_CURRENT_SOURCE_DIR}/extern/${package_name} CACHE PATH "Path to ${package_name} src") @@ -132,7 +136,24 @@ function(find_or_fetch_dependency package_name header_only mode) ${Kokkos_VERSION} CACHE INTERNAL "Kokkos version") endif() + if(NOT DEFINED Kokkos_ARCH OR Kokkos_ARCH STREQUAL "" + OR NOT DEFINED Kokkos_DEVICES OR Kokkos_DEVICES STREQUAL "") + if(${Kokkos_FOUND}) + include(${Kokkos_DIR}/KokkosConfigCommon.cmake) + elseif(NOT ${Kokkos_BUILD_DIR} STREQUAL "") + include(${Kokkos_BUILD_DIR}/KokkosConfigCommon.cmake) + else() + message(STATUS "${Red}Kokkos_DIR and Kokkos_BUILD_DIR not set.${ColorReset}") + endif() + endif() + set(Kokkos_ARCH + ${Kokkos_ARCH} PARENT_SCOPE) + set(Kokkos_DEVICES + ${Kokkos_DEVICES} PARENT_SCOPE) endif() + set(${package_name}_FOUND ${${package_name}_FOUND} PARENT_SCOPE) + set(${package_name}_FETCHED ${${package_name}_FETCHED} PARENT_SCOPE) + set(${package_name}_BUILD_DIR ${${package_name}_BUILD_DIR} PARENT_SCOPE) endfunction() check_internet_connection() diff --git a/cmake/report.cmake b/cmake/report.cmake index 13dde63f7..60d846144 100644 --- a/cmake/report.cmake +++ b/cmake/report.cmake @@ -1,95 +1,3 @@ -function(PadTo Text Padding Target Result) - set(rt ${Text}) - string(FIND ${rt} "${Magenta}" mg_fnd) - - if(mg_fnd GREATER -1) - string(REGEX REPLACE "${Esc}\\[35m" "" rt ${rt}) - endif() - - string(LENGTH "${rt}" TextLength) - math(EXPR PaddingNeeded "${Target} - ${TextLength}") - set(rt ${Text}) - - if(PaddingNeeded GREATER 0) - foreach(i RANGE 0 ${PaddingNeeded}) - set(rt "${rt}${Padding}") - endforeach() - else() - set(${rt} "${rt}") - endif() - - set(${Result} - "${rt}" - PARENT_SCOPE) -endfunction() - -function( - PrintChoices - Label - Flag - Choices - Value - Default - Color - OutputString - Multiline - Padding) - list(LENGTH "${Choices}" nchoices) - set(rstring "") - set(counter 0) - - foreach(ch ${Choices}) - if(${counter} EQUAL 0) - set(rstring_i "- ${Label}") - - if(NOT "${Flag}" STREQUAL "") - set(rstring_i "${rstring_i} [${Magenta}${Flag}${ColorReset}]") - endif() - - set(rstring_i "${rstring_i}:") - padto("${rstring_i}" " " ${Padding} rstring_i) - else() - set(rstring_i "") - - if(NOT ${counter} EQUAL ${nchoices}) - if(${Multiline} EQUAL 1) - set(rstring_i "${rstring_i}\n") - padto("${rstring_i}" " " ${Padding} rstring_i) - else() - set(rstring_i "${rstring_i}/") - endif() - endif() - endif() - - if(${ch} STREQUAL ${Value}) - if(${ch} STREQUAL "ON") - set(col ${Green}) - elseif(${ch} STREQUAL "OFF") - set(col ${Red}) - else() - set(col ${Color}) - endif() - else() - set(col ${Dim}) - endif() - - if(${ch} STREQUAL ${Default}) - set(col ${Underline}${col}) - endif() - - set(rstring_i "${rstring_i}${col}${ch}${ColorReset}") - math(EXPR counter "${counter} + 1") - set(rstring "${rstring}${rstring_i}") - set(rstring_i "") - endforeach() - - set(${OutputString} - "${rstring}" - PARENT_SCOPE) -endfunction() - -set(ON_OFF_VALUES "ON" "OFF") - if(${PGEN_FOUND}) printchoices( "Problem generator" @@ -99,8 +7,7 @@ if(${PGEN_FOUND}) ${default_pgen} "${Blue}" PGEN_REPORT - 1 - 36) + 0) endif() printchoices( @@ -111,7 +18,6 @@ printchoices( ${default_precision} "${Blue}" PRECISION_REPORT - 1 36) printchoices( "Output" @@ -121,17 +27,6 @@ printchoices( ${default_output} "${Green}" OUTPUT_REPORT - 0 - 36) -printchoices( - "GUI" - "gui" - "${ON_OFF_VALUES}" - ${gui} - ${default_gui} - "${Green}" - GUI_REPORT - 0 36) printchoices( "MPI" @@ -141,8 +36,7 @@ printchoices( OFF "${Green}" MPI_REPORT - 0 - 42) + 36) printchoices( "Debug mode" "DEBUG" @@ -151,131 +45,7 @@ printchoices( OFF "${Green}" DEBUG_REPORT - 0 - 42) - -printchoices( - "CUDA" - "Kokkos_ENABLE_CUDA" - "${ON_OFF_VALUES}" - ${Kokkos_ENABLE_CUDA} - "OFF" - "${Green}" - CUDA_REPORT - 0 - 42) -printchoices( - "HIP" - "Kokkos_ENABLE_HIP" - "${ON_OFF_VALUES}" - ${Kokkos_ENABLE_HIP} - "OFF" - "${Green}" - HIP_REPORT - 0 - 42) -printchoices( - "OpenMP" - "Kokkos_ENABLE_OPENMP" - "${ON_OFF_VALUES}" - ${Kokkos_ENABLE_OPENMP} - "OFF" - "${Green}" - OPENMP_REPORT - 0 - 42) - -printchoices( - "C++ compiler" - "CMAKE_CXX_COMPILER" - "${CMAKE_CXX_COMPILER} v${CMAKE_CXX_COMPILER_VERSION}" - "${CMAKE_CXX_COMPILER} v${CMAKE_CXX_COMPILER_VERSION}" - "N/A" - "${ColorReset}" - CXX_COMPILER_REPORT - 0 - 42) - -printchoices( - "C compiler" - "CMAKE_C_COMPILER" - "${CMAKE_C_COMPILER} v${CMAKE_C_COMPILER_VERSION}" - "${CMAKE_C_COMPILER} v${CMAKE_C_COMPILER_VERSION}" - "N/A" - "${ColorReset}" - C_COMPILER_REPORT - 0 - 42) - -get_cmake_property(_variableNames VARIABLES) -foreach(_variableName ${_variableNames}) - string(REGEX MATCH "Kokkos_ARCH_*" _isMatched ${_variableName}) - if(_isMatched) - get_property( - isSet - CACHE ${_variableName} - PROPERTY VALUE) - if(isSet STREQUAL "ON") - string(REGEX REPLACE "Kokkos_ARCH_" "" ARCH ${_variableName}) - break() - endif() - endif() -endforeach() -printchoices( - "Architecture" - "Kokkos_ARCH_*" - "${ARCH}" - "${ARCH}" - "N/A" - "${ColorReset}" - ARCH_REPORT - 0 - 42) - -if(${Kokkos_ENABLE_CUDA}) - if("${CMAKE_CUDA_COMPILER}" STREQUAL "") - execute_process(COMMAND which nvcc OUTPUT_VARIABLE CUDACOMP) - else() - set(CUDACOMP ${CMAKE_CUDA_COMPILER}) - endif() - - string(STRIP ${CUDACOMP} CUDACOMP) - - message(STATUS "CUDA compiler: ${CUDACOMP}") - execute_process( - COMMAND - bash -c - "${CUDACOMP} --version | grep release | sed -e 's/.*release //' -e 's/,.*//'" - OUTPUT_VARIABLE CUDACOMP_VERSION - OUTPUT_STRIP_TRAILING_WHITESPACE) - - printchoices( - "CUDA compiler" - "CMAKE_CUDA_COMPILER" - "${CUDACOMP}" - "${CUDACOMP}" - "N/A" - "${ColorReset}" - CUDA_COMPILER_REPORT - 0 - 42) -endif() - -if(${Kokkos_ENABLE_HIP}) - execute_process( - COMMAND bash -c "hipcc --version | grep HIP | cut -d ':' -f 2 | tr -d ' '" - OUTPUT_VARIABLE ROCM_VERSION - OUTPUT_STRIP_TRAILING_WHITESPACE) -endif() - -set(DOT_SYMBOL "${ColorReset}.") -set(DOTTED_LINE_SYMBOL - "${ColorReset}. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . " -) - -set(DASHED_LINE_SYMBOL - "${ColorReset}....................................................................... " -) + 36) if(NOT ${PROJECT_VERSION_TWEAK} EQUAL 0) set(VERSION_SYMBOL @@ -287,7 +57,7 @@ else() ) endif() -message( +set(REPORT_TEXT "${Blue} __ __ /\\ \\__ __/\\ \\__ __ ___\\ \\ _\\/\\_\\ \\ _\\ __ __ @@ -296,55 +66,107 @@ message( \\ \\____\\ \\_\\ \\_\\ \\__\\\\ \\_\\ \\__\\\\ \\____ \\/\\_\\ \\/____/\\/_/\\/_/\\/__/ \\/_/\\/__/ \\/___/ \\/_/ /\\___/ -Entity ${VERSION_SYMBOL}\t\t \\/__/") -message("${DASHED_LINE_SYMBOL} -Main configurations") +Entity ${VERSION_SYMBOL}\t\t \\/__/" +) +string(APPEND REPORT_TEXT + ${ColorReset} "\n" +) + +string(APPEND REPORT_TEXT + ${DASHED_LINE_SYMBOL} "\n" + "Configurations" "\n" +) if(${PGEN_FOUND}) - message(" ${PGEN_REPORT}") + string(APPEND REPORT_TEXT + " " ${PGEN_REPORT} "\n" + ) endif() -message(" ${PRECISION_REPORT}") -message(" ${OUTPUT_REPORT}") -message("${DASHED_LINE_SYMBOL}\nCompile configurations") +string(APPEND REPORT_TEXT + " " ${PRECISION_REPORT} "\n" + " " ${OUTPUT_REPORT} "\n" +) -if(NOT "${ARCH_REPORT}" STREQUAL "") - message(" ${ARCH_REPORT}") -endif() -message(" ${CUDA_REPORT}") -message(" ${HIP_REPORT}") -message(" ${OPENMP_REPORT}") +string(REPLACE ";" "+" Kokkos_ARCH "${Kokkos_ARCH}") +string(REPLACE ";" "+" Kokkos_DEVICES "${Kokkos_DEVICES}") -message(" ${C_COMPILER_REPORT}") +string(APPEND REPORT_TEXT + " - ARCH [${Magenta}Kokkos_ARCH_***${ColorReset}]: ${Kokkos_ARCH}" "\n" + " - DEVICES [${Magenta}Kokkos_ENABLE_***${ColorReset}]: ${Kokkos_DEVICES}" "\n" + " " ${MPI_REPORT} "\n" + " " ${DEBUG_REPORT} "\n" + ${DASHED_LINE_SYMBOL} "\n" + "Compilers & dependencies" "\n" +) -message(" ${CXX_COMPILER_REPORT}") +string(APPEND REPORT_TEXT + " - C compiler [${Magenta}CMAKE_C_COMPILER${ColorReset}]: v" ${CMAKE_C_COMPILER_VERSION} "\n" + " ${Dim}" ${CMAKE_C_COMPILER} "${ColorReset}\n" + " - C++ compiler [${Magenta}CMAKE_CXX_COMPILER${ColorReset}]: v" ${CMAKE_CXX_COMPILER_VERSION} "\n" + " ${Dim}" ${CMAKE_CXX_COMPILER} "${ColorReset}\n" +) -if(NOT "${CUDA_COMPILER_REPORT}" STREQUAL "") - message(" ${CUDA_COMPILER_REPORT}") +if(${Kokkos_DEVICES} MATCHES "CUDA") + if("${CMAKE_CUDA_COMPILER}" STREQUAL "") + execute_process(COMMAND which nvcc OUTPUT_VARIABLE CUDACOMP) + else() + set(CUDACOMP ${CMAKE_CUDA_COMPILER}) + endif() + string(STRIP ${CUDACOMP} CUDACOMP) + execute_process( + COMMAND + bash -c + "${CUDACOMP} --version | grep release | sed -e 's/.*release //' -e 's/,.*//'" + OUTPUT_VARIABLE CUDACOMP_VERSION + OUTPUT_STRIP_TRAILING_WHITESPACE) + string(APPEND REPORT_TEXT + " - CUDA compiler: v" ${CUDACOMP_VERSION} "\n" + " ${Dim}" ${CUDACOMP} "${ColorReset}\n" + ) +elseif(${Kokkos_DEVICES} MATCHES "HIP") + execute_process( + COMMAND bash -c "hipcc --version | grep HIP | cut -d ':' -f 2 | tr -d ' '" + OUTPUT_VARIABLE ROCM_VERSION + OUTPUT_STRIP_TRAILING_WHITESPACE) + string(APPEND REPORT_TEXT + " - ROCm: v" ${ROCM_VERSION} "\n" + ) endif() -message(" ${MPI_REPORT}") - -message(" ${DEBUG_REPORT}") - -message("${DASHED_LINE_SYMBOL}\nDependencies") - -if(NOT "${CUDACOMP_VERSION}" STREQUAL "") - message(" - CUDA:\tv${CUDACOMP_VERSION}") -elseif(NOT "${ROCM_VERSION}" STREQUAL "") - message(" - ROCm:\tv${ROCM_VERSION}") +string(APPEND REPORT_TEXT + " - Kokkos: v" ${Kokkos_VERSION} "\n" +) +if(${Kokkos_FOUND}) + string(APPEND REPORT_TEXT + " " ${Kokkos_DIR} "\n" + ) +else() + string(APPEND REPORT_TEXT + " " ${Kokkos_BUILD_DIR} "\n" + ) endif() -message(" - Kokkos:\tv${Kokkos_VERSION}") + if(${output}) - message(" - ADIOS2:\tv${adios2_VERSION}") -endif() -if(${HDF5_FOUND}) - message(" - HDF5:\tv${HDF5_VERSION}") + string(APPEND REPORT_TEXT + " - ADIOS2: v" ${adios2_VERSION} "\n" + ) + if(${adios2_FOUND}) + string(APPEND REPORT_TEXT + " " ${adios2_DIR} "\n" + ) + else() + string(APPEND REPORT_TEXT + " " ${adios2_BUILD_DIR} "\n" + ) + endif() endif() -message( - "${DASHED_LINE_SYMBOL} -Notes - ${Dim}: Set flags with `cmake ... -D ${Magenta}${ColorReset}${Dim}=`, the ${Underline}default${ColorReset}${Dim} value - : will be used unless the variable is explicitly set.${ColorReset} -") +string(APPEND REPORT_TEXT + ${DASHED_LINE_SYMBOL} "\n" + "Notes" "\n" + " ${Dim}: Set flags with `cmake ... -D ${Magenta}${ColorReset}${Dim}=`, the ${Underline}default${ColorReset}${Dim} value" "\n" + " : will be used unless the variable is explicitly set.${ColorReset}" "\n" +) + +message(${REPORT_TEXT}) diff --git a/cmake/styling.cmake b/cmake/styling.cmake index 70c448fff..0da4b3519 100644 --- a/cmake/styling.cmake +++ b/cmake/styling.cmake @@ -23,17 +23,131 @@ if(NOT WIN32) set(StrikeEnd "${Esc}[0m") endif() -# message("This is normal") message("${Red}This is Red${ColorReset}") -# message("${Green}This is Green${ColorReset}") message("${Yellow}This is -# Yellow${ColorReset}") message("${Blue}This is Blue${ColorReset}") -# message("${Magenta}This is Magenta${ColorReset}") message("${Cyan}This is -# Cyan${ColorReset}") message("${White}This is White${ColorReset}") -# message("${BoldRed}This is BoldRed${ColorReset}") message("${BoldGreen}This is -# BoldGreen${ColorReset}") message("${BoldYellow}This is -# BoldYellow${ColorReset}") message("${BoldBlue}This is BoldBlue${ColorReset}") -# message("${BoldMagenta}This is BoldMagenta${ColorReset}") -# message("${BoldCyan}This is BoldCyan${ColorReset}") message("${BoldWhite}This -# is BoldWhite\n\n${ColorReset}") - -# message() +set(DOTTED_LINE_SYMBOL + "${ColorReset}. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . " +) +set(DASHED_LINE_SYMBOL + "${ColorReset}....................................................................... " +) + +set(ON_OFF_VALUES "ON" "OFF") + +function(PureLength Text Result) + set(rt ${Text}) + string(FIND ${rt} "${Magenta}" mg_fnd) + + if(mg_fnd GREATER -1) + string(REGEX REPLACE "${Esc}\\[35m" "" rt ${rt}) + endif() + + string(LENGTH "${rt}" TextLength) + set(${Result} + "${TextLength}" + PARENT_SCOPE) +endfunction() + +function(PadTo Text Padding Target Result) + purelength("${Text}" TextLength) + math(EXPR PaddingNeeded "${Target} - ${TextLength}") + set(rt ${Text}) + + if(PaddingNeeded GREATER 0) + foreach(i RANGE 0 ${PaddingNeeded}) + set(rt "${rt}${Padding}") + endforeach() + else() + set(rt "${rt}") + endif() + + set(${Result} + "${rt}" + PARENT_SCOPE) +endfunction() + +function( + PrintChoices + Label + Flag + Choices + Value + Default + Color + OutputString + Padding) + set(rstring "- ${Label}") + + if(NOT "${Flag}" STREQUAL "") + string(APPEND rstring " [${Magenta}${Flag}${ColorReset}]") + endif() + + string(APPEND rstring ":") + + if(${Padding} EQUAL 0) + list(LENGTH "${Choices}" nchoices) + math(EXPR lastchoice "${nchoices} - 1") + set(ncols 4) + math(EXPR lastcol "${ncols} - 1") + + set(longest 0) + foreach(ch IN LISTS Choices) + string(LENGTH ${ch} clen) + if(clen GREATER longest) + set(longest ${clen}) + endif() + endforeach() + + set(counter 0) + foreach(ch IN LISTS Choices) + if(${ch} STREQUAL ${Value}) + set(col ${Color}) + else() + set(col ${Dim}) + endif() + + if(${ch} STREQUAL ${Default}) + set(col ${Underline}${col}) + endif() + + string(LENGTH "${ch}" clen) + math(EXPR PaddingNeeded "${longest} - ${clen} + 4") + + if(counter EQUAL ${lastcol} AND NOT ${counter} EQUAL ${lastchoice}) + string(APPEND rstring "${col}~ ${ch}${ColorReset}") + else() + if(counter EQUAL 0) + string(APPEND rstring "\n ") + endif() + string(APPEND rstring "${col}~ ${ch}${ColorReset}") + foreach(i RANGE 0 ${PaddingNeeded}) + string(APPEND rstring " ") + endforeach() + endif() + + math(EXPR counter "(${counter} + 1) % ${ncols}") + endforeach() + else() + padto("${rstring}" " " ${Padding} rstring) + + set(new_choices ${Choices}) + foreach(ch IN LISTS new_choices) + string(REPLACE ${ch} "${Dim}${ch}${ColorReset}" new_choices "${new_choices}") + endforeach() + set(Choices ${new_choices}) + if(${Value} STREQUAL "ON") + set(col ${Green}) + elseif(${Value} STREQUAL "OFF") + set(col ${Red}) + else() + set(col ${Color}) + endif() + string(REPLACE ${Value} "${col}${Value}${ColorReset}" Choices "${Choices}") + string(REPLACE ${Default} "${Underline}${Default}${ColorReset}" Choices "${Choices}") + string(REPLACE ";" "/" Choices "${Choices}") + string(APPEND rstring "${Choices}") + endif() + + set(${OutputString} + "${rstring}" + PARENT_SCOPE) +endfunction() diff --git a/src/engines/CMakeLists.txt b/src/engines/CMakeLists.txt index 9e51330ec..d5b6b0664 100644 --- a/src/engines/CMakeLists.txt +++ b/src/engines/CMakeLists.txt @@ -38,7 +38,7 @@ add_library(ntt_engines ${SOURCES}) set(libs ntt_global ntt_framework ntt_metrics ntt_archetypes ntt_kernels ntt_pgen) if(${output}) - list(APPEND libs ntt_output hdf5::hdf5) + list(APPEND libs ntt_output) endif() add_dependencies(ntt_engines ${libs}) target_link_libraries(ntt_engines PUBLIC ${libs}) diff --git a/src/engines/engine_printer.cpp b/src/engines/engine_printer.cpp index f94715d09..eb8ff402d 100644 --- a/src/engines/engine_printer.cpp +++ b/src/engines/engine_printer.cpp @@ -20,7 +20,6 @@ #endif #if defined(OUTPUT_ENABLED) - #include #include #endif @@ -188,18 +187,11 @@ namespace ntt { KOKKOS_VERSION % 100); #if defined(OUTPUT_ENABLED) - unsigned h5_major, h5_minor, h5_release; - H5get_libversion(&h5_major, &h5_minor, &h5_release); - const std::string hdf5_version = fmt::format("%d.%d.%d", - h5_major, - h5_minor, - h5_release); const std::string adios2_version = fmt::format("%d.%d.%d", ADIOS2_VERSION / 10000, ADIOS2_VERSION / 100 % 100, ADIOS2_VERSION % 100); #else // not OUTPUT_ENABLED - const std::string hdf5_version = "OFF"; const std::string adios2_version = "OFF"; #endif @@ -217,7 +209,6 @@ namespace ntt { add_param(report, 4, "CXX", "%s [%s]", ccx.c_str(), cpp_standard.c_str()); add_param(report, 4, "CUDA", "%s", cuda_version.c_str()); add_param(report, 4, "MPI", "%s", mpi_version.c_str()); - add_param(report, 4, "HDF5", "%s", hdf5_version.c_str()); add_param(report, 4, "Kokkos", "%s", kokkos_version.c_str()); add_param(report, 4, "ADIOS2", "%s", adios2_version.c_str()); add_param(report, 4, "Precision", "%s", precision); From 6967490da6c062a660c6579113e2e82ee69e60fd Mon Sep 17 00:00:00 2001 From: hayk Date: Thu, 3 Apr 2025 16:53:54 -0400 Subject: [PATCH 478/773] match.ds is now array --- input.example.toml | 8 +- src/engines/srpic.hpp | 145 ++++++++++++++++++++--------- src/framework/parameters.cpp | 76 +++++++++++---- src/framework/tests/parameters.cpp | 18 +++- 4 files changed, 176 insertions(+), 71 deletions(-) diff --git a/input.example.toml b/input.example.toml index a49067811..5f32599d3 100644 --- a/input.example.toml +++ b/input.example.toml @@ -107,11 +107,13 @@ particles = "" [grid.boundaries.match] - # Size of the matching layer for fields in physical (code) units: - # @type: float + # Size of the matching layer in each direction for fields in physical (code) units: + # @type: float or array of tuples # @default: 1% of the domain size (in shortest dimension) # @note: In spherical, this is the size of the layer in r from the outer wall - # @note: In cartesian, this is the same for all dimensions where applicable + # @example: ds = 1.5 (will set the same for all directions) + # @example: ds = [[1.5], [2.0, 1.0], [1.1]] (will duplicate 1.5 for +/- x1 and 1.1 for +/- x3) + # @example: ds = [[], [1.5], []] (will only set for x2) ds = "" # Absorption coefficient for fields: # @type: float: -inf < ... < inf, != 0 diff --git a/src/engines/srpic.hpp b/src/engines/srpic.hpp index 0a9cc311b..22434ef6b 100644 --- a/src/engines/srpic.hpp +++ b/src/engines/srpic.hpp @@ -79,7 +79,7 @@ namespace ntt { "algorithms.toggles.fieldsolver"); const auto deposit_enabled = m_params.template get( "algorithms.toggles.deposit"); - const auto clear_interval = m_params.template get( + const auto clear_interval = m_params.template get( "particles.clear_interval"); if (step == 0) { @@ -612,15 +612,19 @@ namespace ntt { /** * matching boundaries */ - const auto ds = m_params.template get("grid.boundaries.match.ds"); + const auto ds_array = m_params.template get>( + "grid.boundaries.match.ds"); const auto dim = direction.get_dim(); real_t xg_min, xg_max, xg_edge; auto sign = direction.get_sign(); + real_t ds; if (sign > 0) { // + direction + ds = ds_array[(short)dim].second; xg_max = m_metadomain.mesh().extent(dim).second; xg_min = xg_max - ds; xg_edge = xg_max; } else { // - direction + ds = ds_array[(short)dim].first; xg_min = m_metadomain.mesh().extent(dim).first; xg_max = xg_min + ds; xg_edge = xg_min; @@ -651,50 +655,81 @@ namespace ntt { range_min[d] = intersect_range[d].first; range_max[d] = intersect_range[d].second; } - if constexpr (traits::has_member::value) { - auto match_fields = m_pgen.MatchFields(time); - if (dim == in::x1) { - Kokkos::parallel_for( - "MatchFields", - CreateRangePolicy(range_min, range_max), - kernel::bc::MatchBoundaries_kernel( - domain.fields.em, - match_fields, - domain.mesh.metric, - xg_edge, - ds, - tags)); - } else if (dim == in::x2) { - if constexpr (M::Dim == Dim::_2D or M::Dim == Dim::_3D) { - Kokkos::parallel_for( - "MatchFields", - CreateRangePolicy(range_min, range_max), - kernel::bc::MatchBoundaries_kernel( - domain.fields.em, - match_fields, - domain.mesh.metric, - xg_edge, - ds, - tags)); - } else { - raise::Error("Invalid dimension", HERE); - } - } else if (dim == in::x3) { - if constexpr (M::Dim == Dim::_3D) { - Kokkos::parallel_for( - "MatchFields", - CreateRangePolicy(range_min, range_max), - kernel::bc::MatchBoundaries_kernel( - domain.fields.em, - match_fields, - domain.mesh.metric, - xg_edge, - ds, - tags)); - } else { - raise::Error("Invalid dimension", HERE); - } + + if (dim == in::x1) { + if constexpr ( + traits::has_member::value) { + auto match_fields = m_pgen.MatchFields(time); + call_match_fields(domain.fields.em, + match_fields, + domain.mesh.metric, + xg_edge, + ds, + tags, + range_min, + range_max); + } else if constexpr ( + traits::has_member::value) { + auto match_fields = m_pgen.MatchFieldsInX1(time); + call_match_fields(domain.fields.em, + match_fields, + domain.mesh.metric, + xg_edge, + ds, + tags, + range_min, + range_max); } + } else if (dim == in::x2) { + if constexpr ( + traits::has_member::value) { + auto match_fields = m_pgen.MatchFields(time); + call_match_fields(domain.fields.em, + match_fields, + domain.mesh.metric, + xg_edge, + ds, + tags, + range_min, + range_max); + } else if constexpr ( + traits::has_member::value) { + auto match_fields = m_pgen.MatchFieldsInX2(time); + call_match_fields(domain.fields.em, + match_fields, + domain.mesh.metric, + xg_edge, + ds, + tags, + range_min, + range_max); + } + } else if (dim == in::x3) { + if constexpr ( + traits::has_member::value) { + auto match_fields = m_pgen.MatchFields(time); + call_match_fields(domain.fields.em, + match_fields, + domain.mesh.metric, + xg_edge, + ds, + tags, + range_min, + range_max); + } else if constexpr ( + traits::has_member::value) { + auto match_fields = m_pgen.MatchFieldsInX3(time); + call_match_fields(domain.fields.em, + match_fields, + domain.mesh.metric, + xg_edge, + ds, + tags, + range_min, + range_max); + } + } else { + raise::Error("Invalid dimension", HERE); } } @@ -1266,6 +1301,26 @@ namespace ntt { } return range; } + + template + void call_match_fields(ndfield_t& fields, + const T& match_fields, + const M& metric, + real_t xg_edge, + real_t ds, + BCTags tags, + tuple_t& range_min, + tuple_t& range_max) { + Kokkos::parallel_for( + "MatchFields", + CreateRangePolicy(range_min, range_max), + kernel::bc::MatchBoundaries_kernel(fields, + match_fields, + metric, + xg_edge, + ds, + tags)); + } }; } // namespace ntt diff --git a/src/framework/parameters.cpp b/src/framework/parameters.cpp index e3bddfd70..32f19a8fa 100644 --- a/src/framework/parameters.cpp +++ b/src/framework/parameters.cpp @@ -31,10 +31,10 @@ namespace ntt { template - auto get_dx0_V0( - const std::vector& resolution, - const boundaries_t& extent, - const std::map& params) -> std::pair { + auto get_dx0_V0(const std::vector& resolution, + const boundaries_t& extent, + const std::map& params) + -> std::pair { const auto metric = M(resolution, extent, params); const auto dx0 = metric.dxMin(); coord_t x_corner { ZERO }; @@ -736,23 +736,63 @@ namespace ntt { for (const auto& e : extent_pairwise) { min_extent = std::min(min_extent, e.second - e.first); } - set("grid.boundaries.match.ds", - toml::find_or(toml_data, - "grid", - "boundaries", - "match", - "ds", - min_extent * defaults::bc::match::ds_frac)); + const auto default_ds = min_extent * defaults::bc::match::ds_frac; + std::size_t n_match_bcs { 0u }; + for (const auto& bcs : flds_bc_pairwise) { + if (bcs.first == FldsBC::MATCH or bcs.second == FldsBC::MATCH) { + n_match_bcs += 1; + } + } + boundaries_t ds_array; + try { + auto ds = toml::find(toml_data, "grid", "boundaries", "match", "ds"); + for (auto d = 0u; d < dim; ++d) { + ds_array.push_back({ ds, ds }); + } + } catch (const toml::type_error&) { + try { + const auto ds = toml::find>>( + toml_data, + "grid", + "boundaries", + "match", + "ds"); + raise::ErrorIf(ds.size() != dim, + "invalid # in `grid.boundaries.match.ds`", + HERE); + for (auto d = 0u; d < dim; ++d) { + if (ds[d].size() == 1) { + ds_array.push_back({ ds[d][0], ds[d][0] }); + } else if (ds[d].size() == 2) { + ds_array.push_back({ ds[d][0], ds[d][1] }); + } else if (ds[d].size() == 0) { + ds_array.push_back({}); + } else { + raise::Error("invalid `grid.boundaries.match.ds`", HERE); + } + } + } catch (...) { + for (auto d = 0u; d < dim; ++d) { + ds_array.push_back({ default_ds, default_ds }); + } + } + } + set("grid.boundaries.match.ds", ds_array); } else { auto r_extent = extent_pairwise[0].second - extent_pairwise[0].first; - set("grid.boundaries.match.ds", - toml::find_or(toml_data, - "grid", - "boundaries", - "match", - "ds", - r_extent * defaults::bc::match::ds_frac)); + const auto ds = toml::find_or( + toml_data, + "grid", + "boundaries", + "match", + "ds", + r_extent * defaults::bc::match::ds_frac); + boundaries_t ds_array { + { ds, ds } + }; + set("grid.boundaries.match.ds", ds_array); } + set("grid.boundaries.match.coeff", toml::find_or(toml_data, "grid", diff --git a/src/framework/tests/parameters.cpp b/src/framework/tests/parameters.cpp index 7cd5ce46a..c4d1f0e7b 100644 --- a/src/framework/tests/parameters.cpp +++ b/src/framework/tests/parameters.cpp @@ -29,12 +29,12 @@ const auto mink_1d = u8R"( metric = "minkowski" [grid.boundaries] - fields = [["PERIODIC"]] + fields = [["MATCH", "MATCH"]] particles = [["ABSORB", "ABSORB"]] [grid.boundaries.match] coeff = 10.0 - ds = 0.025 + ds = [[0.025, 0.1]] [scales] larmor0 = 0.1 @@ -269,7 +269,7 @@ auto main(int argc, char* argv[]) -> int { (real_t)0.0078125, "scales.V0"); boundaries_t fbc = { - { FldsBC::PERIODIC, FldsBC::PERIODIC } + { FldsBC::MATCH, FldsBC::MATCH } }; assert_equal( params_mink_1d.get>("grid.boundaries.fields")[0].first, @@ -283,6 +283,14 @@ auto main(int argc, char* argv[]) -> int { params_mink_1d.get>("grid.boundaries.fields").size(), fbc.size(), "grid.boundaries.fields.size()"); + assert_equal( + params_mink_1d.get>("grid.boundaries.match.ds")[0].first, + (real_t)0.025, + "grid.boundaries.match.ds[0].first"); + assert_equal( + params_mink_1d.get>("grid.boundaries.match.ds")[0].second, + (real_t)0.1, + "grid.boundaries.match.ds[0].first"); const auto species = params_mink_1d.get>( "particles.species"); @@ -383,7 +391,7 @@ auto main(int argc, char* argv[]) -> int { // match coeffs assert_equal( - params_sph_2d.get("grid.boundaries.match.ds"), + params_sph_2d.get>("grid.boundaries.match.ds")[0].second, (real_t)(defaults::bc::match::ds_frac * 19.0), "grid.boundaries.match.ds"); @@ -539,7 +547,7 @@ auto main(int argc, char* argv[]) -> int { // match coeffs assert_equal( - params_qks_2d.get("grid.boundaries.match.ds"), + params_qks_2d.get>("grid.boundaries.match.ds")[0].second, (real_t)(defaults::bc::match::ds_frac * (100.0 - 0.8)), "grid.boundaries.match.ds"); From e75f7e0c34a670e850cdc4228c3b15008559fa4c Mon Sep 17 00:00:00 2001 From: hayk Date: Thu, 3 Apr 2025 16:54:56 -0400 Subject: [PATCH 479/773] generalized uniform injector --- src/archetypes/particle_injector.h | 128 +++++++++++++++++++++++------ src/kernels/injectors.hpp | 14 ++-- 2 files changed, 110 insertions(+), 32 deletions(-) diff --git a/src/archetypes/particle_injector.h b/src/archetypes/particle_injector.h index 3884e6ced..4e776b132 100644 --- a/src/archetypes/particle_injector.h +++ b/src/archetypes/particle_injector.h @@ -32,6 +32,7 @@ #include #include +#include #include #include @@ -58,14 +59,79 @@ namespace arch { , species { species } {} ~UniformInjector() = default; + + auto ComputeNumInject(const Domain& domain, + real_t ppc0, + real_t number_density, + const boundaries_t& box) const + -> std::tuple, array_t> { + auto i_min = array_t { "i_min", M::Dim }; + auto i_max = array_t { "i_max", M::Dim }; + + if (not domain.mesh.Intersects(box)) { + return { false, (npart_t)0, i_min, i_max }; + } + tuple_t range_min { 0 }; + tuple_t range_max { 0 }; + + boundaries_t incl_ghosts; + for (auto d { 0u }; d < M::Dim; ++d) { + incl_ghosts.push_back({ false, false }); + } + const auto intersect_range = domain.mesh.ExtentToRange(box, incl_ghosts); + + for (auto d { 0u }; d < M::Dim; ++d) { + range_min[d] = intersect_range[d].first; + range_max[d] = intersect_range[d].second; + } + ncells_t ncells = 1; + for (auto d = 0u; d < M::Dim; ++d) { + ncells *= (range_max[d] - range_min[d]); + } + const auto nparticles = static_cast( + (long double)(ppc0 * number_density * 0.5) * (long double)(ncells)); + + auto i_min_h = Kokkos::create_mirror_view(i_min); + auto i_max_h = Kokkos::create_mirror_view(i_max); + for (auto d = 0u; d < M::Dim; ++d) { + i_min_h(d) = (real_t)(range_min[d]); + i_max_h(d) = (real_t)(range_max[d]); + } + Kokkos::deep_copy(i_min, i_min_h); + Kokkos::deep_copy(i_max, i_max_h); + return { true, nparticles, i_min, i_max }; + } + }; + + template class ED> + struct KeepConstantInjector : UniformInjector { + using energy_dist_t = ED; + using UniformInjector::D; + using UniformInjector::C; + + const boundaries_t probe_box; + + KeepConstantInjector(const energy_dist_t& energy_dist, + const std::pair& species, + boundaries_t probe_box = {}) + : UniformInjector(energy_dist, species) + , probe_box { probe_box } {} + + ~KeepConstantInjector() = default; + + auto ComputeNumInject(const Domain& domain, + real_t ppc0, + real_t number_density, + const boundaries_t& box) const + -> std::tuple, array_t> { + ... + } }; template - class ED, - template - class SD> + template class ED, + template class SD> struct NonUniformInjector { using energy_dist_t = ED; using spatial_dist_t = SD; @@ -181,11 +247,12 @@ namespace arch { * @tparam I Injector type */ template - inline void InjectUniform(const SimulationParams& params, - Domain& domain, - const I& injector, - real_t number_density, - bool use_weights = false) { + inline void InjectUniform(const SimulationParams& params, + Domain& domain, + const I& injector, + 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(I::is_uniform_injector, "I must be a uniform injector class"); raise::ErrorIf((M::CoordType != Coord::Cart) && (not use_weights), @@ -205,17 +272,25 @@ namespace arch { } { - auto ppc0 = params.template get("particles.ppc0"); - array_t ni { "ni", M::Dim }; - auto ni_h = Kokkos::create_mirror_view(ni); - ncells_t ncells = 1; - for (auto d = 0; d < M::Dim; ++d) { - ni_h(d) = domain.mesh.n_active()[d]; - ncells *= domain.mesh.n_active()[d]; + boundaries_t nonempty_box; + for (auto d { 0u }; d < M::Dim; ++d) { + if (d < box.size()) { + nonempty_box.push_back({ box[d].first, box[d].second }); + } else { + nonempty_box.push_back(Range::All); + } } - Kokkos::deep_copy(ni, ni_h); - const auto nparticles = static_cast( - (long double)(ppc0 * number_density * 0.5) * (long double)(ncells)); + auto ppc0 = params.template get("particles.ppc0"); + const auto result = injector.ComputeNumInject(domain, + ppc0, + number_density, + nonempty_box); + if (not std::get<0>(result)) { + return; + } + const auto nparticles = std::get<1>(result); + const auto i_min = std::get<2>(result); + const auto i_max = std::get<3>(result); Kokkos::parallel_for( "InjectUniform", @@ -228,7 +303,8 @@ namespace arch { domain.species[injector.species.first - 1].npart(), domain.species[injector.species.second - 1].npart(), domain.mesh.metric, - ni, + i_min, + i_max, injector.energy_dist, ONE / params.template get("scales.V0"), domain.random_pool)); @@ -279,12 +355,12 @@ namespace arch { * @param box Region to inject the particles in */ template - inline void InjectNonUniform(const SimulationParams& params, - Domain& domain, - const I& injector, - real_t number_density, - bool use_weights = false, - boundaries_t box = {}) { + inline void InjectNonUniform(const SimulationParams& params, + Domain& domain, + const I& injector, + 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(I::is_nonuniform_injector, "I must be a nonuniform injector class"); diff --git a/src/kernels/injectors.hpp b/src/kernels/injectors.hpp index 09bc7a180..7dcd017a3 100644 --- a/src/kernels/injectors.hpp +++ b/src/kernels/injectors.hpp @@ -49,7 +49,7 @@ namespace kernel { npart_t offset1, offset2; const M metric; - const array_t ni; + const array_t i_min, i_max; const ED energy_dist; const real_t inv_V0; random_number_pool_t random_pool; @@ -61,7 +61,8 @@ namespace kernel { npart_t offset1, npart_t offset2, const M& metric, - const array_t& ni, + const array_t& i_min, + const array_t& i_max, const ED& energy_dist, real_t inv_V0, random_number_pool_t& random_pool) @@ -94,7 +95,8 @@ namespace kernel { , offset1 { offset1 } , offset2 { offset2 } , metric { metric } - , ni { ni } + , i_min { i_min } + , i_max { i_max } , energy_dist { energy_dist } , inv_V0 { inv_V0 } , random_pool { random_pool } {} @@ -104,12 +106,12 @@ namespace kernel { vec_t v1 { ZERO }, v2 { ZERO }; { // generate a random coordinate auto rand_gen = random_pool.get_state(); - x_Cd[0] = Random(rand_gen) * ni(0); + x_Cd[0] = i_min(0) + Random(rand_gen) * (i_max(0) - i_min(0)); if constexpr (M::Dim == Dim::_2D or M::Dim == Dim::_3D) { - x_Cd[1] = Random(rand_gen) * ni(1); + x_Cd[1] = i_min(1) + Random(rand_gen) * (i_max(1) - i_min(1)); } if constexpr (M::Dim == Dim::_3D) { - x_Cd[2] = Random(rand_gen) * ni(2); + x_Cd[2] = i_min(2) + Random(rand_gen) * (i_max(2) - i_min(2)); } random_pool.free_state(rand_gen); } From c3402009465dc0d181dcc7afc158ace2e8e6d95b Mon Sep 17 00:00:00 2001 From: hayk Date: Thu, 3 Apr 2025 16:56:02 -0400 Subject: [PATCH 480/773] diff match boundaries in diff directions --- setups/wip/reconnection/pgen.hpp | 292 +++++++++++++++++----- setups/wip/reconnection/reconnection.toml | 40 +-- src/global/arch/traits.h | 9 + 3 files changed, 261 insertions(+), 80 deletions(-) diff --git a/setups/wip/reconnection/pgen.hpp b/setups/wip/reconnection/pgen.hpp index e97bc518a..34314ca68 100644 --- a/setups/wip/reconnection/pgen.hpp +++ b/setups/wip/reconnection/pgen.hpp @@ -15,41 +15,136 @@ #include "archetypes/spatial_dist.h" #include "framework/domain/metadomain.h" +#include "kernels/particle_moments.hpp" + namespace user { using namespace ntt; template struct CurrentLayer : public arch::SpatialDistribution { - CurrentLayer(const M& metric, real_t width, real_t yi) + CurrentLayer(const M& metric, real_t cs_width, real_t cs_y) : arch::SpatialDistribution { metric } - , width { width } - , yi { yi } {} + , cs_width { cs_width } + , cs_y { cs_y } {} Inline auto operator()(const coord_t& x_Ph) const -> real_t override { - return ONE / SQR(math::cosh((x_Ph[1] - yi) / width)); + return ONE / SQR(math::cosh((x_Ph[1] - cs_y) / cs_width)); } private: - const real_t yi, width; + const real_t cs_y, cs_width; }; + // field initializer template struct InitFields { - InitFields(real_t Bmag, real_t width, real_t y1, real_t y2) - : Bmag { Bmag } - , width { width } - , y1 { y1 } - , y2 { y2 } {} + InitFields(real_t bg_B, real_t bg_Bguide, real_t cs_width, real_t cs_y) + : bg_B { bg_B } + , bg_Bguide { bg_Bguide } + , cs_width { cs_width } + , cs_y { cs_y } {} Inline auto bx1(const coord_t& x_Ph) const -> real_t { - return Bmag * (math::tanh((x_Ph[1] - y1) / width) - - math::tanh((x_Ph[1] - y2) / width) - 1); + return bg_B * (math::tanh((x_Ph[1] - cs_y) / cs_width)); + } + + Inline auto bx3(const coord_t&) const -> real_t { + return bg_Bguide; } private: - const real_t Bmag, width, y1, y2; + const real_t bg_B, bg_Bguide, cs_width, cs_y; }; + template + struct BoundaryFieldsInX1 { + BoundaryFieldsInX1(real_t bg_B, + real_t bg_Bguide, + real_t beta_rec, + real_t cs_width, + real_t cs_x, + real_t cs_y) + : bg_B { bg_B } + , bg_Bguide { bg_Bguide } + , beta_rec { beta_rec } + , cs_width { cs_width } + , cs_x { cs_x } + , cs_y { cs_y } {} + + Inline auto bx1(const coord_t& x_Ph) const -> real_t { + return bg_B * (math::tanh((x_Ph[1] - cs_y) / cs_width)); + } + + Inline auto bx2(const coord_t& x_Ph) const -> real_t { + return beta_rec * bg_B * (math::tanh((x_Ph[0] - cs_x) / cs_width)); + } + + Inline auto bx3(const coord_t&) const -> real_t { + return bg_Bguide; + } + + Inline auto ex1(const coord_t& x_Ph) const -> real_t { + return beta_rec * bg_Bguide * math::tanh((x_Ph[1] - cs_y) / cs_width); + } + + Inline auto ex2(const coord_t&) const -> real_t { + return ZERO; + } + + Inline auto ex3(const coord_t&) const -> real_t { + return -beta_rec * bg_B; + } + + private: + const real_t bg_B, bg_Bguide, beta_rec, cs_width, cs_x, cs_y; + }; + + template + struct BoundaryFieldsInX2 { + BoundaryFieldsInX2(real_t bg_B, real_t bg_Bguide, real_t cs_width, real_t cs_y) + : bg_B { bg_B } + , bg_Bguide { bg_Bguide } + , cs_width { cs_width } + , cs_y { cs_y } {} + + Inline auto bx1(const coord_t& x_Ph) const -> real_t { + return bg_B * (math::tanh((x_Ph[1] - cs_y) / cs_width)); + } + + Inline auto bx2(const coord_t&) const -> real_t { + return ZERO; + } + + Inline auto bx3(const coord_t&) const -> real_t { + return bg_Bguide; + } + + Inline auto ex1(const coord_t&) const -> real_t { + return ZERO; + } + + Inline auto ex2(const coord_t&) const -> real_t { + return ZERO; + } + + Inline auto ex3(const coord_t&) const -> real_t { + return ZERO; + } + + private: + const real_t bg_B, bg_Bguide, cs_width, cs_y; + }; + + // constant particle density for particle boundaries + template + struct ConstDens { + Inline auto operator()(const coord_t& x_Ph) const -> real_t { + return ONE; + } + }; + template + using spatial_dist_t = arch::Replenish>; + template struct PGen : public arch::ProblemGenerator { // compatibility traits for the problem generator @@ -64,30 +159,42 @@ namespace user { using arch::ProblemGenerator::C; using arch::ProblemGenerator::params; - const real_t Bmag, width, overdensity, y1, y2, bg_temp; + const real_t bg_B, bg_Bguide, bg_temperature; + const real_t cs_width, cs_overdensity, cs_x, cs_y; + InitFields init_flds; inline PGen(const SimulationParams& p, const Metadomain& m) : arch::ProblemGenerator(p) - , Bmag { p.template get("setup.Bmag", 1.0) } - , width { p.template get("setup.width") } - , overdensity { p.template get("setup.overdensity") } - , y1 { m.mesh().extent(in::x2).first + - INV_4 * - (m.mesh().extent(in::x2).second - m.mesh().extent(in::x2).first) } - , y2 { m.mesh().extent(in::x2).first + - 3 * INV_4 * - (m.mesh().extent(in::x2).second - m.mesh().extent(in::x2).first) } - , init_flds { Bmag, width, y1, y2 } - , bg_temp { p.template get("setup.bg_temp") } {} + , bg_B { p.template get("setup.bg_B", 1.0) } + , bg_Bguide { p.template get("setup.bg_Bguide", 0.0) } + , bg_temperature { p.template get("setup.bg_temperature", 0.001) } + , cs_width { p.template get("setup.cs_width") } + , cs_overdensity { p.template get("setup.cs_overdensity") } + , cs_x { m.mesh().extent(in::x1).first + + INV_2 * (m.mesh().extent(in::x1).second - + m.mesh().extent(in::x1).first) } + , cs_y { m.mesh().extent(in::x2).first + + INV_2 * (m.mesh().extent(in::x2).second - + m.mesh().extent(in::x2).first) } + , init_flds { bg_B, bg_Bguide, cs_width, cs_y } {} inline PGen() {} + auto MatchFieldsInX1(simtime_t) const -> BoundaryFieldsInX1 { + return BoundaryFieldsInX1 { bg_B, bg_Bguide, (real_t)0.1, + cs_width, cs_x, cs_y }; + } + + auto MatchFieldsInX2(simtime_t) const -> BoundaryFieldsInX2 { + return BoundaryFieldsInX2 { bg_B, bg_Bguide, cs_width, cs_y }; + } + inline void InitPrtls(Domain& local_domain) { // background const auto energy_dist = arch::Maxwellian(local_domain.mesh.metric, local_domain.random_pool, - bg_temp); + bg_temperature); const auto injector = arch::UniformInjector( energy_dist, { 1, 2 }); @@ -95,46 +202,111 @@ namespace user { params, local_domain, injector, - HALF); + ONE); const auto sigma = params.template get("scales.sigma0"); const auto c_omp = params.template get("scales.skindepth0"); - const auto cs_drift_beta = math::sqrt(sigma) * c_omp / (width * overdensity); + const auto cs_drift_beta = math::sqrt(sigma) * c_omp / + (cs_width * cs_overdensity); const auto cs_drift_gamma = ONE / math::sqrt(ONE - SQR(cs_drift_beta)); const auto cs_drift_u = cs_drift_beta * cs_drift_gamma; - const auto cs_temp = HALF * sigma / overdensity; - // current layer #1 - auto edist_cs_1 = arch::Maxwellian(local_domain.mesh.metric, - local_domain.random_pool, - cs_temp, - cs_drift_u, - in::x3, - false); - const auto sdist_cs_1 = CurrentLayer(local_domain.mesh.metric, width, y1); - const auto inj_cs_1 = arch::NonUniformInjector( - edist_cs_1, - sdist_cs_1, - { 1, 2 }); - arch::InjectNonUniform(params, - local_domain, - inj_cs_1, - overdensity); - // current layer #2 - const auto edist_cs_2 = arch::Maxwellian(local_domain.mesh.metric, - local_domain.random_pool, - cs_temp, - -cs_drift_u, - in::x3, - false); - const auto sdist_cs_2 = CurrentLayer(local_domain.mesh.metric, width, y2); - const auto inj_cs_2 = arch::NonUniformInjector( - edist_cs_2, - sdist_cs_2, + const auto cs_temperature = HALF * sigma / cs_overdensity; + + // current layer + auto edist_cs = arch::Maxwellian(local_domain.mesh.metric, + local_domain.random_pool, + cs_temperature, + cs_drift_u, + in::x3, + false); + const auto sdist_cs = CurrentLayer(local_domain.mesh.metric, + cs_width, + cs_y); + const auto inj_cs = arch::NonUniformInjector( + edist_cs, + sdist_cs, { 1, 2 }); - arch::InjectNonUniform(params, - local_domain, - inj_cs_2, - overdensity); + arch::InjectNonUniform(params, + local_domain, + inj_cs, + cs_overdensity); + } + + void CustomPostStep(std::size_t step, long double time, Domain& domain) { + // // 0. define target density profile and box where it has to be + // reached + // // 1. compute density + // // 2. define spatial distribution + // // 3. define energy distribution + // // 4. define particle injector + // // 5. inject particles + // + // // step 0. + // // defining the regions of interest (lower and upper + // y-boundaries) boundaries_t box_upper, box_lower; const + // auto [xmin, xmax] = domain.mesh.extent(in::x1); const auto [ymin, + // ymax] = domain.mesh.extent(in::x2); box_upper.push_back({ xmin, + // xmax }); box_lower.push_back({ xmin, xmax }); + // + // box_upper.push_back({ ymax - dy, ymax }); + // box_lower.push_back({ ymin, ymin + dy }); + // + // if constexpr (M::Dim == Dim::_3D) { + // const auto [zmin, zmax] = domain.mesh.extent(in::x3); + // box_upper.push_back({ zmin, zmax }); + // box_lower.push_back({ zmin, zmax }); + // } + // + // const auto const_dens = ConstDens(); + // const auto inv_n0 = ONE / n0; + // + // // step 1 compute density + // auto scatter_bckp = Kokkos::Experimental::create_scatter_view( + // domain.fields.bckp); + // for (auto& prtl_spec : domain.species) { + // // clang-format off + // Kokkos::parallel_for( + // "ComputeMoments", + // prtl_spec.rangeActiveParticles(), + // kernel::ParticleMoments_kernel({}, + // scatter_bckp, 0, + // prtl_spec.i1, + // prtl_spec.i2, + // prtl_spec.i3, prtl_spec.dx1, + // prtl_spec.dx2, + // prtl_spec.dx3, prtl_spec.ux1, + // prtl_spec.ux2, + // prtl_spec.ux3, prtl_spec.phi, + // prtl_spec.weight, + // prtl_spec.tag, prtl_spec.mass(), + // prtl_spec.charge(), + // false, + // domain.mesh.metric, + // domain.mesh.flds_bc(), + // 0, inv_n0, 0)); + // } + // Kokkos::Experimental::contribute(domain.fields.bckp, scatter_bckp); + // + // + // //step 2. define spatial distribution + // // const auto spatial_dist = arch::Replenish>(domain.mesh.metric, domain.fields.bckp, 0, + // const_dens, ONE); + // const auto spatial_dist = spatial_dist_t(domain.mesh.metric, + // domain.fields.bckp,0,const_dens,ONE); + // //step 3. define energy distribution + // const auto energy_dist = arch::Maxwellian(domain.mesh.metric, + // domain.random_pool, up_temperature); + // //step 4. define particle injector + // const auto injector = arch::NonUniformInjector(energy_dist, spatial_dist, {1,2}); + // //step 5. inject particles + // arch::InjectNonUniform(params, domain, + // injector, ONE, false, box_upper); //upper boudary arch::InjectNonUniform(params, domain, injector, ONE, false, + // box_lower); //lower boundary + // + // } }; diff --git a/setups/wip/reconnection/reconnection.toml b/setups/wip/reconnection/reconnection.toml index fa7b049f4..db3dbde72 100644 --- a/setups/wip/reconnection/reconnection.toml +++ b/setups/wip/reconnection/reconnection.toml @@ -1,21 +1,21 @@ [simulation] - name = "reconnection" - engine = "srpic" + name = "reconnection" + engine = "srpic" runtime = 10.0 [grid] - resolution = [1024, 2048] - extent = [[-1.0, 1.0], [-2.0, 2.0]] + resolution = [1024, 512] + extent = [[-1.0, 1.0], [-0.5, 0.5]] [grid.metric] metric = "minkowski" [grid.boundaries] - fields = [["PERIODIC"], ["PERIODIC"]] - particles = [["PERIODIC"], ["PERIODIC"]] - + fields = [["MATCH", "MATCH"], ["MATCH", "MATCH"], ["PERIODIC"]] + particles = [["ABSORB", "ABSORB"], ["ABSORB", "ABSORB"], ["PERIODIC"]] + [scales] - larmor0 = 2e-4 + larmor0 = 2e-4 skindepth0 = 2e-3 [algorithms] @@ -25,28 +25,28 @@ CFL = 0.5 [particles] - ppc0 = 8.0 + ppc0 = 2.0 [[particles.species]] - label = "e-" - mass = 1.0 - charge = -1.0 + label = "e-" + mass = 1.0 + charge = -1.0 maxnpart = 1e7 [[particles.species]] - label = "e+" - mass = 1.0 - charge = 1.0 + label = "e+" + mass = 1.0 + charge = 1.0 maxnpart = 1e7 [setup] - Bmag = 1.0 - width = 0.01 - bg_temp = 1e-4 + Bmag = 1.0 + width = 0.01 + bg_temp = 1e-4 overdensity = 3.0 - + [output] - format = "hdf5" + format = "hdf5" interval_time = 0.1 [output.fields] diff --git a/src/global/arch/traits.h b/src/global/arch/traits.h index 4cde4fca5..5527d570f 100644 --- a/src/global/arch/traits.h +++ b/src/global/arch/traits.h @@ -103,6 +103,15 @@ namespace traits { template using match_fields_t = decltype(&T::MatchFields); + template + using match_fields_in_x1_t = decltype(&T::MatchFieldsInX1); + + template + using match_fields_in_x2_t = decltype(&T::MatchFieldsInX2); + + template + using match_fields_in_x3_t = decltype(&T::MatchFieldsInX3); + template using match_fields_const_t = decltype(&T::MatchFieldsConst); From a3ed0512b907371a5c0d93fc6296af71df7fb467 Mon Sep 17 00:00:00 2001 From: hayk Date: Thu, 3 Apr 2025 16:56:24 -0400 Subject: [PATCH 481/773] const specifier added to mesh methods --- src/framework/domain/mesh.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/framework/domain/mesh.h b/src/framework/domain/mesh.h index 98fe68895..e4f2cba6d 100644 --- a/src/framework/domain/mesh.h +++ b/src/framework/domain/mesh.h @@ -74,7 +74,7 @@ namespace ntt { * @note pass Range::All to select the entire dimension */ [[nodiscard]] - auto Intersection(boundaries_t box) -> boundaries_t { + auto Intersection(boundaries_t box) const -> boundaries_t { raise::ErrorIf(box.size() != M::Dim, "Invalid box dimension", HERE); boundaries_t intersection; auto d = 0; @@ -109,7 +109,7 @@ namespace ntt { * @note pass Range::All to select the entire dimension */ [[nodiscard]] - auto Intersects(boundaries_t box) -> bool { + auto Intersects(boundaries_t box) const -> bool { raise::ErrorIf(box.size() != M::Dim, "Invalid box dimension", HERE); const auto intersection = Intersection(box); for (const auto& i : intersection) { @@ -131,8 +131,8 @@ namespace ntt { * @note indices are already shifted by N_GHOSTS (i.e. they start at N_GHOSTS not 0) */ [[nodiscard]] - auto ExtentToRange(boundaries_t box, - boundaries_t incl_ghosts) -> boundaries_t { + auto ExtentToRange(boundaries_t box, boundaries_t incl_ghosts) const + -> boundaries_t { raise::ErrorIf(box.size() != M::Dim, "Invalid box dimension", HERE); raise::ErrorIf(incl_ghosts.size() != M::Dim, "Invalid incl_ghosts dimension", From d1d999cc9209edf1c592988df8306796f807440e Mon Sep 17 00:00:00 2001 From: haykh Date: Thu, 3 Apr 2025 19:25:25 -0400 Subject: [PATCH 482/773] int type issues in mpi writer test --- src/output/tests/writer-mpi.cpp | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/output/tests/writer-mpi.cpp b/src/output/tests/writer-mpi.cpp index f6d3ee88a..cc9208889 100644 --- a/src/output/tests/writer-mpi.cpp +++ b/src/output/tests/writer-mpi.cpp @@ -61,8 +61,8 @@ auto main(int argc, char* argv[]) -> int { // write auto writer = out::Writer(); writer.init(&adios, "hdf5", "test", false); - writer.defineMeshLayout({ static_cast(mpi_size) * nx1 }, - { static_cast(mpi_rank) * nx1 }, + writer.defineMeshLayout({ static_cast(mpi_size) * nx1 }, + { static_cast(mpi_rank) * nx1 }, { nx1 }, { dwn1 }, false, @@ -89,9 +89,9 @@ auto main(int argc, char* argv[]) -> int { { // read adios2::IO io = adios.DeclareIO("read-test"); - io.SetEngine("hdf5"); - adios2::Engine reader = io.Open("test.h5", adios2::Mode::Read, MPI_COMM_SELF); - raise::ErrorIf(io.InquireAttribute("NGhosts").Data()[0] != 0, + io.SetEngine("HDF5"); + adios2::Engine reader = io.Open("test.h5", adios2::Mode::Read); + raise::ErrorIf(io.InquireAttribute("NGhosts").Data()[0] != 0, "NGhosts is not correct", HERE); raise::ErrorIf(io.InquireAttribute("Dimension").Data()[0] != 1, @@ -99,13 +99,13 @@ auto main(int argc, char* argv[]) -> int { HERE); for (std::size_t step = 0; reader.BeginStep() == adios2::StepStatus::OK; ++step) { - std::size_t step_read; - long double time_read; + timestep_t step_read; + simtime_t time_read; - reader.Get(io.InquireVariable("Step"), + reader.Get(io.InquireVariable("Step"), &step_read, adios2::Mode::Sync); - reader.Get(io.InquireVariable("Time"), + reader.Get(io.InquireVariable("Time"), &time_read, adios2::Mode::Sync); raise::ErrorIf(step_read != step, "Step is not correct", HERE); @@ -122,9 +122,9 @@ auto main(int argc, char* argv[]) -> int { const double l = l_offset; const double f = math::ceil(l / d) * d - l; - const auto first_cell = static_cast(f); - const auto l_size_dwn = static_cast(math::ceil((n - f) / d)); - const auto l_corner_dwn = static_cast(math::ceil(l / d)); + const auto first_cell = static_cast(f); + const auto l_size_dwn = static_cast(math::ceil((n - f) / d)); + const auto l_corner_dwn = static_cast(math::ceil(l / d)); array_t field_read {}; int cntr = 0; From 4708d81a3ce1ecf38e1584e80ad8ee1075cf21c0 Mon Sep 17 00:00:00 2001 From: haykh Date: Thu, 3 Apr 2025 20:33:03 -0400 Subject: [PATCH 483/773] cmake prints report with TESTS --- CMakeLists.txt | 3 +- cmake/report.cmake | 170 ++++++++++++++++++++++++++++---------------- cmake/styling.cmake | 31 +++++--- cmake/tests.cmake | 50 ++++++------- 4 files changed, 153 insertions(+), 101 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 22d1e64b5..4791ea55b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -125,5 +125,6 @@ else() # ------------------------------- Main source ------------------------------ # set_problem_generator(${pgen}) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/src src) - include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/report.cmake) endif() + +include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/report.cmake) diff --git a/cmake/report.cmake b/cmake/report.cmake index 60d846144..21064cdf9 100644 --- a/cmake/report.cmake +++ b/cmake/report.cmake @@ -8,6 +8,24 @@ if(${PGEN_FOUND}) "${Blue}" PGEN_REPORT 0) +elseif(${TESTS}) + set(TEST_NAMES "") + foreach(test_dir IN LISTS TEST_DIRECTORIES) + get_property( + LOCAL_TEST_NAMES + DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${test_dir}/tests + PROPERTY TESTS) + list(APPEND TEST_NAMES ${LOCAL_TEST_NAMES}) + endforeach() + printchoices( + "Test cases" + "" + "${TEST_NAMES}" + "" + "${ColorReset}" + "" + TESTS_REPORT + 0) endif() printchoices( @@ -58,7 +76,7 @@ else() endif() set(REPORT_TEXT - "${Blue} __ __ + "${Blue} __ __ /\\ \\__ __/\\ \\__ __ ___\\ \\ _\\/\\_\\ \\ _\\ __ __ / __ \\ / __ \\ \\ \\/\\/\\ \\ \\ \\/ /\\ \\/\\ \\ @@ -66,46 +84,63 @@ set(REPORT_TEXT \\ \\____\\ \\_\\ \\_\\ \\__\\\\ \\_\\ \\__\\\\ \\____ \\/\\_\\ \\/____/\\/_/\\/_/\\/__/ \\/_/\\/__/ \\/___/ \\/_/ /\\___/ -Entity ${VERSION_SYMBOL}\t\t \\/__/" -) -string(APPEND REPORT_TEXT - ${ColorReset} "\n" -) +Entity ${VERSION_SYMBOL}\t\t \\/__/") +string(APPEND REPORT_TEXT ${ColorReset} "\n") -string(APPEND REPORT_TEXT - ${DASHED_LINE_SYMBOL} "\n" - "Configurations" "\n" -) +string(APPEND REPORT_TEXT ${DASHED_LINE_SYMBOL} "\n" "Configurations" "\n") if(${PGEN_FOUND}) - string(APPEND REPORT_TEXT - " " ${PGEN_REPORT} "\n" - ) + string(APPEND REPORT_TEXT " " ${PGEN_REPORT} "\n") +elseif(${TESTS}) + string(APPEND REPORT_TEXT " " ${TESTS_REPORT} "\n") endif() -string(APPEND REPORT_TEXT - " " ${PRECISION_REPORT} "\n" - " " ${OUTPUT_REPORT} "\n" -) +string( + APPEND + REPORT_TEXT + " " + ${PRECISION_REPORT} + "\n" + " " + ${OUTPUT_REPORT} + "\n") string(REPLACE ";" "+" Kokkos_ARCH "${Kokkos_ARCH}") string(REPLACE ";" "+" Kokkos_DEVICES "${Kokkos_DEVICES}") -string(APPEND REPORT_TEXT - " - ARCH [${Magenta}Kokkos_ARCH_***${ColorReset}]: ${Kokkos_ARCH}" "\n" - " - DEVICES [${Magenta}Kokkos_ENABLE_***${ColorReset}]: ${Kokkos_DEVICES}" "\n" - " " ${MPI_REPORT} "\n" - " " ${DEBUG_REPORT} "\n" - ${DASHED_LINE_SYMBOL} "\n" - "Compilers & dependencies" "\n" -) - -string(APPEND REPORT_TEXT - " - C compiler [${Magenta}CMAKE_C_COMPILER${ColorReset}]: v" ${CMAKE_C_COMPILER_VERSION} "\n" - " ${Dim}" ${CMAKE_C_COMPILER} "${ColorReset}\n" - " - C++ compiler [${Magenta}CMAKE_CXX_COMPILER${ColorReset}]: v" ${CMAKE_CXX_COMPILER_VERSION} "\n" - " ${Dim}" ${CMAKE_CXX_COMPILER} "${ColorReset}\n" -) +string( + APPEND + REPORT_TEXT + " - ARCH [${Magenta}Kokkos_ARCH_***${ColorReset}]: ${Kokkos_ARCH}" + "\n" + " - DEVICES [${Magenta}Kokkos_ENABLE_***${ColorReset}]: ${Kokkos_DEVICES}" + "\n" + " " + ${MPI_REPORT} + "\n" + " " + ${DEBUG_REPORT} + "\n" + ${DASHED_LINE_SYMBOL} + "\n" + "Compilers & dependencies" + "\n") + +string( + APPEND + REPORT_TEXT + " - C compiler [${Magenta}CMAKE_C_COMPILER${ColorReset}]: v" + ${CMAKE_C_COMPILER_VERSION} + "\n" + " ${Dim}" + ${CMAKE_C_COMPILER} + "${ColorReset}\n" + " - C++ compiler [${Magenta}CMAKE_CXX_COMPILER${ColorReset}]: v" + ${CMAKE_CXX_COMPILER_VERSION} + "\n" + " ${Dim}" + ${CMAKE_CXX_COMPILER} + "${ColorReset}\n") if(${Kokkos_DEVICES} MATCHES "CUDA") if("${CMAKE_CUDA_COMPILER}" STREQUAL "") @@ -120,53 +155,62 @@ if(${Kokkos_DEVICES} MATCHES "CUDA") "${CUDACOMP} --version | grep release | sed -e 's/.*release //' -e 's/,.*//'" OUTPUT_VARIABLE CUDACOMP_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE) - string(APPEND REPORT_TEXT - " - CUDA compiler: v" ${CUDACOMP_VERSION} "\n" - " ${Dim}" ${CUDACOMP} "${ColorReset}\n" - ) + string( + APPEND + REPORT_TEXT + " - CUDA compiler: v" + ${CUDACOMP_VERSION} + "\n" + " ${Dim}" + ${CUDACOMP} + "${ColorReset}\n") elseif(${Kokkos_DEVICES} MATCHES "HIP") execute_process( COMMAND bash -c "hipcc --version | grep HIP | cut -d ':' -f 2 | tr -d ' '" OUTPUT_VARIABLE ROCM_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE) - string(APPEND REPORT_TEXT - " - ROCm: v" ${ROCM_VERSION} "\n" - ) + string(APPEND REPORT_TEXT " - ROCm: v" ${ROCM_VERSION} "\n") endif() -string(APPEND REPORT_TEXT - " - Kokkos: v" ${Kokkos_VERSION} "\n" -) +string(APPEND REPORT_TEXT " - Kokkos: v" ${Kokkos_VERSION} "\n") if(${Kokkos_FOUND}) - string(APPEND REPORT_TEXT - " " ${Kokkos_DIR} "\n" - ) + string(APPEND REPORT_TEXT " " ${Dim}${Kokkos_DIR}${ColorReset} "\n") else() - string(APPEND REPORT_TEXT - " " ${Kokkos_BUILD_DIR} "\n" - ) + string(APPEND REPORT_TEXT " " ${Dim}${Kokkos_BUILD_DIR}${ColorReset} "\n") endif() if(${output}) - string(APPEND REPORT_TEXT - " - ADIOS2: v" ${adios2_VERSION} "\n" - ) + string(APPEND REPORT_TEXT " - ADIOS2: v" ${adios2_VERSION} "\n") if(${adios2_FOUND}) - string(APPEND REPORT_TEXT - " " ${adios2_DIR} "\n" - ) + string(APPEND REPORT_TEXT " " "${Dim}${adios2_DIR}${ColorReset}" "\n") else() - string(APPEND REPORT_TEXT - " " ${adios2_BUILD_DIR} "\n" - ) + string(APPEND REPORT_TEXT " " "${Dim}${adios2_BUILD_DIR}${ColorReset}" + "\n") endif() endif() -string(APPEND REPORT_TEXT - ${DASHED_LINE_SYMBOL} "\n" - "Notes" "\n" - " ${Dim}: Set flags with `cmake ... -D ${Magenta}${ColorReset}${Dim}=`, the ${Underline}default${ColorReset}${Dim} value" "\n" - " : will be used unless the variable is explicitly set.${ColorReset}" "\n" -) +string( + APPEND + REPORT_TEXT + ${DASHED_LINE_SYMBOL} + "\n" + "Notes" + "\n" + " ${Dim}: Set flags with `cmake ... -D ${Magenta}${ColorReset}${Dim}=`, the ${Underline}default${ColorReset}${Dim} value" + "\n" + " : will be used unless the variable is explicitly set.${ColorReset}") + +if(${TESTS}) + string( + APPEND + REPORT_TEXT + "\n" + " ${Dim}: Run the tests with the following command:" + "\n" + " : ctest --test-dir ${CMAKE_CURRENT_BINARY_DIR}${ColorReset}" + "\n") +endif() + +string(APPEND REPORT_TEXT "\n") message(${REPORT_TEXT}) diff --git a/cmake/styling.cmake b/cmake/styling.cmake index 0da4b3519..b9b72abcb 100644 --- a/cmake/styling.cmake +++ b/cmake/styling.cmake @@ -43,8 +43,8 @@ function(PureLength Text Result) string(LENGTH "${rt}" TextLength) set(${Result} - "${TextLength}" - PARENT_SCOPE) + "${TextLength}" + PARENT_SCOPE) endfunction() function(PadTo Text Padding Target Result) @@ -99,14 +99,20 @@ function( set(counter 0) foreach(ch IN LISTS Choices) - if(${ch} STREQUAL ${Value}) - set(col ${Color}) + if(NOT ${Value} STREQUAL "") + if(${ch} STREQUAL ${Value}) + set(col ${Color}) + else() + set(col ${Dim}) + endif() else() set(col ${Dim}) endif() - if(${ch} STREQUAL ${Default}) - set(col ${Underline}${col}) + if(NOT ${Default} STREQUAL "") + if(${ch} STREQUAL ${Default}) + set(col ${Underline}${col}) + endif() endif() string(LENGTH "${ch}" clen) @@ -131,7 +137,8 @@ function( set(new_choices ${Choices}) foreach(ch IN LISTS new_choices) - string(REPLACE ${ch} "${Dim}${ch}${ColorReset}" new_choices "${new_choices}") + string(REPLACE ${ch} "${Dim}${ch}${ColorReset}" new_choices + "${new_choices}") endforeach() set(Choices ${new_choices}) if(${Value} STREQUAL "ON") @@ -141,8 +148,14 @@ function( else() set(col ${Color}) endif() - string(REPLACE ${Value} "${col}${Value}${ColorReset}" Choices "${Choices}") - string(REPLACE ${Default} "${Underline}${Default}${ColorReset}" Choices "${Choices}") + if(NOT "${Value}" STREQUAL "") + string(REPLACE ${Value} "${col}${Value}${ColorReset}" Choices + "${Choices}") + endif() + if(NOT "${Default}" STREQUAL "") + string(REPLACE ${Default} "${Underline}${Default}${ColorReset}" Choices + "${Choices}") + endif() string(REPLACE ";" "/" Choices "${Choices}") string(APPEND rstring "${Choices}") endif() diff --git a/cmake/tests.cmake b/cmake/tests.cmake index ca8ee69c4..e2d92a343 100644 --- a/cmake/tests.cmake +++ b/cmake/tests.cmake @@ -13,32 +13,26 @@ if(${output}) add_subdirectory(${SRC_DIR}/checkpoint ${CMAKE_CURRENT_BINARY_DIR}/checkpoint) endif() -if(${mpi}) - # tests with mpi - if(${output}) - add_subdirectory(${SRC_DIR}/output/tests - ${CMAKE_CURRENT_BINARY_DIR}/output/tests) - add_subdirectory(${SRC_DIR}/checkpoint/tests - ${CMAKE_CURRENT_BINARY_DIR}/checkpoint/tests) - add_subdirectory(${SRC_DIR}/framework/tests - ${CMAKE_CURRENT_BINARY_DIR}/framework/tests) - endif() -else() - # tests without mpi - add_subdirectory(${SRC_DIR}/global/tests - ${CMAKE_CURRENT_BINARY_DIR}/global/tests) - add_subdirectory(${SRC_DIR}/metrics/tests - ${CMAKE_CURRENT_BINARY_DIR}/metrics/tests) - add_subdirectory(${SRC_DIR}/kernels/tests - ${CMAKE_CURRENT_BINARY_DIR}/kernels/tests) - add_subdirectory(${SRC_DIR}/archetypes/tests - ${CMAKE_CURRENT_BINARY_DIR}/archetypes/tests) - add_subdirectory(${SRC_DIR}/framework/tests - ${CMAKE_CURRENT_BINARY_DIR}/framework/tests) - if(${output}) - add_subdirectory(${SRC_DIR}/output/tests - ${CMAKE_CURRENT_BINARY_DIR}/output/tests) - add_subdirectory(${SRC_DIR}/checkpoint/tests - ${CMAKE_CURRENT_BINARY_DIR}/checkpoint/tests) - endif() +set(TEST_DIRECTORIES + "" + PARENT_SCOPE) + +if(NOT ${mpi}) + list(APPEND TEST_DIRECTORIES global) + list(APPEND TEST_DIRECTORIES metrics) + list(APPEND TEST_DIRECTORIES kernels) + list(APPEND TEST_DIRECTORIES archetypes) + list(APPEND TEST_DIRECTORIES framework) +elseif(${mpi} AND ${output}) + list(APPEND TEST_DIRECTORIES framework) endif() + +if(${output}) + list(APPEND TEST_DIRECTORIES output) + list(APPEND TEST_DIRECTORIES checkpoint) +endif() + +foreach(test_dir IN LISTS TEST_DIRECTORIES) + add_subdirectory(${SRC_DIR}/${test_dir}/tests + ${CMAKE_CURRENT_BINARY_DIR}/${test_dir}/tests) +endforeach() From 4d7528783d501b653bd227ad842fa012f2be0bde Mon Sep 17 00:00:00 2001 From: haykh Date: Thu, 3 Apr 2025 20:33:26 -0400 Subject: [PATCH 484/773] type+unused warnings fixed --- src/framework/containers/particles.cpp | 7 +++---- src/kernels/fields_bcs.hpp | 28 +++++++++++++++++++------- src/metrics/tests/ks-qks.cpp | 1 + src/output/tests/writer-nompi.cpp | 3 ++- 4 files changed, 27 insertions(+), 12 deletions(-) diff --git a/src/framework/containers/particles.cpp b/src/framework/containers/particles.cpp index 9ec8810dc..2f59a004d 100644 --- a/src/framework/containers/particles.cpp +++ b/src/framework/containers/particles.cpp @@ -84,7 +84,7 @@ namespace ntt { rangeActiveParticles(), Lambda(index_t p) { auto npptag_acc = npptag_scat.access(); - if (this_tag(p) < 0 || this_tag(p) >= num_tags) { + if (this_tag(p) < 0 || this_tag(p) >= static_cast(num_tags)) { raise::KernelError(HERE, "Invalid tag value"); } npptag_acc(this_tag(p)) += 1; @@ -144,9 +144,8 @@ namespace ntt { template void Particles::RemoveDead() { - const auto n_part = npart(); - npart_t n_alive = 0, n_dead = 0; - auto& this_tag = tag; + npart_t n_alive = 0, n_dead = 0; + auto& this_tag = tag; Kokkos::parallel_reduce( "CountDeadAlive", diff --git a/src/kernels/fields_bcs.hpp b/src/kernels/fields_bcs.hpp index dbb47f42c..ecdba8eb1 100644 --- a/src/kernels/fields_bcs.hpp +++ b/src/kernels/fields_bcs.hpp @@ -562,6 +562,7 @@ namespace kernel::bc { const I fset; const M metric; const ncells_t i_edge; + const BCTags tags; EnforcedBoundaries_kernel(ndfield_t& Fld, const I& fset, @@ -571,7 +572,8 @@ namespace kernel::bc { : Fld { Fld } , fset { fset } , metric { metric } - , i_edge { i_edge + N_GHOSTS } {} + , i_edge { i_edge + N_GHOSTS } + , tags { tags } {} Inline void operator()(index_t i1) const { if constexpr (D == Dim::_1D) { @@ -580,8 +582,12 @@ namespace kernel::bc { coord_t x_Ph_H { ZERO }; metric.template convert({ i1_ }, x_Ph_0); metric.template convert({ i1_ + HALF }, x_Ph_H); - bool setEx1 = defines_ex1, setEx2 = defines_ex2, setEx3 = defines_ex3, - setBx1 = defines_bx1, setBx2 = defines_bx2, setBx3 = defines_bx3; + bool setEx1 = defines_ex1 and (tags & BC::E), + setEx2 = defines_ex2 and (tags & BC::E), + setEx3 = defines_ex3 and (tags & BC::E), + setBx1 = defines_bx1 and (tags & BC::B), + setBx2 = defines_bx2 and (tags & BC::B), + setBx3 = defines_bx3 and (tags & BC::B); if constexpr (O == in::x1) { // x1 -- normal // x2,x3 -- tangential @@ -657,8 +663,12 @@ namespace kernel::bc { metric.template convert({ i1_ + HALF, i2_ }, x_Ph_H0); metric.template convert({ i1_ + HALF, i2_ + HALF }, x_Ph_HH); - bool setEx1 = defines_ex1, setEx2 = defines_ex2, setEx3 = defines_ex3, - setBx1 = defines_bx1, setBx2 = defines_bx2, setBx3 = defines_bx3; + bool setEx1 = defines_ex1 and (tags & BC::E), + setEx2 = defines_ex2 and (tags & BC::E), + setEx3 = defines_ex3 and (tags & BC::E), + setBx1 = defines_bx1 and (tags & BC::B), + setBx2 = defines_bx2 and (tags & BC::B), + setBx3 = defines_bx3 and (tags & BC::B); if constexpr (O == in::x1) { // x1 -- normal // x2,x3 -- tangential @@ -757,8 +767,12 @@ namespace kernel::bc { x_Ph_H0H); metric.template convert({ i1_, i2_ + HALF, i3_ + HALF }, x_Ph_0HH); - bool setEx1 = defines_ex1, setEx2 = defines_ex2, setEx3 = defines_ex3, - setBx1 = defines_bx1, setBx2 = defines_bx2, setBx3 = defines_bx3; + bool setEx1 = defines_ex1 and (tags & BC::E), + setEx2 = defines_ex2 and (tags & BC::E), + setEx3 = defines_ex3 and (tags & BC::E), + setBx1 = defines_bx1 and (tags & BC::B), + setBx2 = defines_bx2 and (tags & BC::B), + setBx3 = defines_bx3 and (tags & BC::B); if constexpr (O == in::x1) { // x1 -- normal // x2,x3 -- tangential diff --git a/src/metrics/tests/ks-qks.cpp b/src/metrics/tests/ks-qks.cpp index bed051e16..167f564ee 100644 --- a/src/metrics/tests/ks-qks.cpp +++ b/src/metrics/tests/ks-qks.cpp @@ -27,6 +27,7 @@ Inline auto equal(const vec_t& a, const auto eps = epsilon * acc; for (unsigned short d = 0; d < D; ++d) { if (not cmp::AlmostEqual(a[d], b[d], eps)) { + printf("%s: %.12e : %.12e\n", msg, a[d], b[d]); return false; } } diff --git a/src/output/tests/writer-nompi.cpp b/src/output/tests/writer-nompi.cpp index b063539ca..593f37f92 100644 --- a/src/output/tests/writer-nompi.cpp +++ b/src/output/tests/writer-nompi.cpp @@ -23,7 +23,8 @@ void cleanup() { } #define CEILDIV(a, b) \ - (static_cast(math::ceil(static_cast(a) / static_cast(b)))) + (static_cast( \ + math::ceil(static_cast(a) / static_cast(b)))) auto main(int argc, char* argv[]) -> int { Kokkos::initialize(argc, argv); From 518071b1d3f0fcb30d5bcbef3cede5f6dc334a4b Mon Sep 17 00:00:00 2001 From: hayk Date: Fri, 4 Apr 2025 02:43:00 -0400 Subject: [PATCH 485/773] warnings in cmake + nullptr --- CMakeLists.txt | 13 ++++----- cmake/benchmark.cmake | 2 ++ cmake/config.cmake | 17 +++++++----- cmake/defaults.cmake | 2 ++ cmake/dependencies.cmake | 41 ++++++++++++++++++----------- cmake/kokkosConfig.cmake | 2 ++ cmake/report.cmake | 26 ++++++++++-------- cmake/styling.cmake | 12 ++++----- cmake/tests.cmake | 4 +-- src/CMakeLists.txt | 1 + src/archetypes/CMakeLists.txt | 2 +- src/archetypes/tests/CMakeLists.txt | 1 + src/checkpoint/CMakeLists.txt | 1 + src/checkpoint/tests/CMakeLists.txt | 1 + src/engines/CMakeLists.txt | 1 + src/framework/CMakeLists.txt | 1 + src/framework/parameters.cpp | 10 +++---- src/framework/tests/CMakeLists.txt | 1 + src/global/CMakeLists.txt | 1 + src/global/tests/CMakeLists.txt | 1 + src/kernels/CMakeLists.txt | 2 +- src/kernels/tests/CMakeLists.txt | 1 + src/metrics/CMakeLists.txt | 2 +- src/metrics/tests/CMakeLists.txt | 2 +- src/output/CMakeLists.txt | 1 + src/output/tests/CMakeLists.txt | 1 + 26 files changed, 92 insertions(+), 57 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4791ea55b..f83e6637c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,3 +1,5 @@ +# cmake-lint: disable=C0103,C0111,E1120,R0913,R0915 + cmake_minimum_required(VERSION 3.16) cmake_policy(SET CMP0110 NEW) @@ -8,10 +10,10 @@ project( VERSION 1.2.0 LANGUAGES CXX C) add_compile_options("-D ENTITY_VERSION=\"${PROJECT_VERSION}\"") +set(hash_cmd "git diff --quiet src/ && echo $(git rev-parse HEAD) ") +string(APPEND hash_cmd "|| echo $(git rev-parse HEAD)-mod") execute_process( - COMMAND - bash -c - "git diff --quiet src/ && echo $(git rev-parse HEAD) || echo $(git rev-parse HEAD)-mod" + COMMAND bash -c ${hash_cmd} WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" OUTPUT_VARIABLE GIT_HASH ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) @@ -55,9 +57,8 @@ if(${DEBUG} STREQUAL "OFF") set(CMAKE_BUILD_TYPE Release CACHE STRING "CMake build type") - set(CMAKE_CXX_FLAGS - "${CMAKE_CXX_FLAGS} -DNDEBUG -Wno-unused-local-typedefs -Wno-unknown-cuda-version" - ) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DNDEBUG " + "-Wno-unused-local-typedefs -Wno-unknown-cuda-version") else() set(CMAKE_BUILD_TYPE Debug diff --git a/cmake/benchmark.cmake b/cmake/benchmark.cmake index d2e8ca47c..39b075716 100644 --- a/cmake/benchmark.cmake +++ b/cmake/benchmark.cmake @@ -1,3 +1,5 @@ +# cmake-lint: disable=C0103 + set(SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src) add_subdirectory(${SRC_DIR}/global ${CMAKE_CURRENT_BINARY_DIR}/global) diff --git a/cmake/config.cmake b/cmake/config.cmake index ab54717f1..7214812cd 100644 --- a/cmake/config.cmake +++ b/cmake/config.cmake @@ -1,3 +1,5 @@ +# cmake-lint: disable=C0103 + # -------------------------------- Precision ------------------------------- # function(set_precision precision_name) list(FIND precisions ${precision_name} PRECISION_FOUND) @@ -28,16 +30,17 @@ function(set_problem_generator pgen_name) endforeach() list(FIND PGEN_NAMES ${pgen_name} PGEN_FOUND) if(NOT ${pgen_name} STREQUAL "." AND ${PGEN_FOUND} EQUAL -1) - message( - FATAL_ERROR - "Invalid problem generator: ${pgen_name}\nValid options are: ${PGEN_NAMES}" - ) + message(FATAL_ERROR "Invalid problem generator: " + "${pgen_name}\nValid options are: ${PGEN_NAMES}") endif() set(PGEN - ${pgen_name} PARENT_SCOPE) + ${pgen_name} + PARENT_SCOPE) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/setups/${pgen_name}) set(PGEN_FOUND - TRUE PARENT_SCOPE) + TRUE + PARENT_SCOPE) set(problem_generators - ${PGEN_NAMES} PARENT_SCOPE) + ${PGEN_NAMES} + PARENT_SCOPE) endfunction() diff --git a/cmake/defaults.cmake b/cmake/defaults.cmake index 2c72f5d7d..30e605a5c 100644 --- a/cmake/defaults.cmake +++ b/cmake/defaults.cmake @@ -1,3 +1,5 @@ +# cmake-lint: disable=C0103 + # ----------------------------- Defaults ---------------------------------- # if(DEFINED ENV{Entity_ENABLE_DEBUG}) set(default_debug diff --git a/cmake/dependencies.cmake b/cmake/dependencies.cmake index a31dfdea5..a21ea00e8 100644 --- a/cmake/dependencies.cmake +++ b/cmake/dependencies.cmake @@ -1,10 +1,12 @@ +# cmake-lint: disable=C0103,C0111,R0915,R0912 + set(Kokkos_REPOSITORY https://github.com/kokkos/kokkos.git CACHE STRING "Kokkos repository") set(plog_REPOSITORY https://github.com/SergiusTheBest/plog.git CACHE STRING "plog repository") -set (adios2_REPOSITORY +set(adios2_REPOSITORY https://github.com/ornladios/ADIOS2.git CACHE STRING "ADIOS2 repository") @@ -41,7 +43,7 @@ function(find_or_fetch_dependency package_name header_only mode) endif() if(NOT ${package_name}_FOUND) - if (${package_name} STREQUAL "Kokkos") + if(${package_name} STREQUAL "Kokkos") include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/kokkosConfig.cmake) elseif(${package_name} STREQUAL "adios2") include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/adios2Config.cmake) @@ -49,10 +51,8 @@ function(find_or_fetch_dependency package_name header_only mode) if(DEFINED ${package_name}_REPOSITORY AND NOT FETCHCONTENT_FULLY_DISCONNECTED) # fetching package - message( - STATUS - "${Blue}${package_name} not found. Fetching from ${${package_name}_REPOSITORY}${ColorReset}" - ) + message(STATUS "${Blue}${package_name} not found. " + "Fetching from ${${package_name}_REPOSITORY}${ColorReset}") include(FetchContent) if(${package_name} STREQUAL "Kokkos") FetchContent_Declare( @@ -100,7 +100,7 @@ function(find_or_fetch_dependency package_name header_only mode) endif() add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/extern/${package_name} - extern/${package_name}) + extern/${package_name}) set(${package_name}_SRC ${CMAKE_CURRENT_SOURCE_DIR}/extern/${package_name} CACHE PATH "Path to ${package_name} src") @@ -136,24 +136,35 @@ function(find_or_fetch_dependency package_name header_only mode) ${Kokkos_VERSION} CACHE INTERNAL "Kokkos version") endif() - if(NOT DEFINED Kokkos_ARCH OR Kokkos_ARCH STREQUAL "" - OR NOT DEFINED Kokkos_DEVICES OR Kokkos_DEVICES STREQUAL "") + if(NOT DEFINED Kokkos_ARCH + OR Kokkos_ARCH STREQUAL "" + OR NOT DEFINED Kokkos_DEVICES + OR Kokkos_DEVICES STREQUAL "") if(${Kokkos_FOUND}) include(${Kokkos_DIR}/KokkosConfigCommon.cmake) elseif(NOT ${Kokkos_BUILD_DIR} STREQUAL "") include(${Kokkos_BUILD_DIR}/KokkosConfigCommon.cmake) else() - message(STATUS "${Red}Kokkos_DIR and Kokkos_BUILD_DIR not set.${ColorReset}") + message( + STATUS "${Red}Kokkos_DIR and Kokkos_BUILD_DIR not set.${ColorReset}") endif() endif() set(Kokkos_ARCH - ${Kokkos_ARCH} PARENT_SCOPE) + ${Kokkos_ARCH} + PARENT_SCOPE) set(Kokkos_DEVICES - ${Kokkos_DEVICES} PARENT_SCOPE) + ${Kokkos_DEVICES} + PARENT_SCOPE) endif() - set(${package_name}_FOUND ${${package_name}_FOUND} PARENT_SCOPE) - set(${package_name}_FETCHED ${${package_name}_FETCHED} PARENT_SCOPE) - set(${package_name}_BUILD_DIR ${${package_name}_BUILD_DIR} PARENT_SCOPE) + set(${package_name}_FOUND + ${${package_name}_FOUND} + PARENT_SCOPE) + set(${package_name}_FETCHED + ${${package_name}_FETCHED} + PARENT_SCOPE) + set(${package_name}_BUILD_DIR + ${${package_name}_BUILD_DIR} + PARENT_SCOPE) endfunction() check_internet_connection() diff --git a/cmake/kokkosConfig.cmake b/cmake/kokkosConfig.cmake index 3d038cc19..f1a1cf207 100644 --- a/cmake/kokkosConfig.cmake +++ b/cmake/kokkosConfig.cmake @@ -1,3 +1,5 @@ +# cmake-lint: disable=C0103 + # ----------------------------- Kokkos settings ---------------------------- # if(${DEBUG} STREQUAL "OFF") set(Kokkos_ENABLE_AGGRESSIVE_VECTORIZATION diff --git a/cmake/report.cmake b/cmake/report.cmake index 21064cdf9..5a38b0dd5 100644 --- a/cmake/report.cmake +++ b/cmake/report.cmake @@ -66,13 +66,13 @@ printchoices( 36) if(NOT ${PROJECT_VERSION_TWEAK} EQUAL 0) - set(VERSION_SYMBOL - "v${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}-rc${PROJECT_VERSION_TWEAK}" - ) + set(VERSION_SYMBOL "v${PROJECT_VERSION_MAJOR}." "${PROJECT_VERSION_MINOR}.") + string(APPEND VERSION_SYMBOL + "${PROJECT_VERSION_PATCH}-rc${PROJECT_VERSION_TWEAK}") else() - set(VERSION_SYMBOL - "v${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH} " - ) + set(VERSION_SYMBOL "v${PROJECT_VERSION_MAJOR}.") + string(APPEND VERSION_SYMBOL + "${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH} ") endif() set(REPORT_TEXT @@ -149,12 +149,13 @@ if(${Kokkos_DEVICES} MATCHES "CUDA") set(CUDACOMP ${CMAKE_CUDA_COMPILER}) endif() string(STRIP ${CUDACOMP} CUDACOMP) + set(cmd "${CUDACOMP} --version |") + string(APPEND cmd " grep release | sed -e 's/.*release //' -e 's/,.*//'") execute_process( - COMMAND - bash -c - "${CUDACOMP} --version | grep release | sed -e 's/.*release //' -e 's/,.*//'" + COMMAND bash -c ${cmd} OUTPUT_VARIABLE CUDACOMP_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE) + message(STATUS "CUDACOMP: ${CUDACOMP_VERSION}") string( APPEND REPORT_TEXT @@ -165,8 +166,9 @@ if(${Kokkos_DEVICES} MATCHES "CUDA") ${CUDACOMP} "${ColorReset}\n") elseif(${Kokkos_DEVICES} MATCHES "HIP") + set(cmd "hipcc --version | grep HIP | cut -d ':' -f 2 | tr -d ' '") execute_process( - COMMAND bash -c "hipcc --version | grep HIP | cut -d ':' -f 2 | tr -d ' '" + COMMAND bash -c ${cmd} OUTPUT_VARIABLE ROCM_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE) string(APPEND REPORT_TEXT " - ROCm: v" ${ROCM_VERSION} "\n") @@ -196,7 +198,9 @@ string( "\n" "Notes" "\n" - " ${Dim}: Set flags with `cmake ... -D ${Magenta}${ColorReset}${Dim}=`, the ${Underline}default${ColorReset}${Dim} value" + " ${Dim}: Set flags with `cmake ... -D " + "${Magenta}${ColorReset}${Dim}=`, " + "the ${Underline}default${ColorReset}${Dim} value" "\n" " : will be used unless the variable is explicitly set.${ColorReset}") diff --git a/cmake/styling.cmake b/cmake/styling.cmake index b9b72abcb..878cb44a4 100644 --- a/cmake/styling.cmake +++ b/cmake/styling.cmake @@ -1,3 +1,5 @@ +# cmake-lint: disable=C0103,C0301,C0111,E1120,R0913,R0915 + if(NOT WIN32) string(ASCII 27 Esc) set(ColorReset "${Esc}[m") @@ -23,13 +25,11 @@ if(NOT WIN32) set(StrikeEnd "${Esc}[0m") endif() -set(DOTTED_LINE_SYMBOL - "${ColorReset}. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . " -) +set(DOTTED_LINE_SYMBOL "${ColorReset}. . . . . . . . . . . . . . . .") +string(APPEND DOTTED_LINE_SYMBOL " . . . . . . . . . . . . . . . . . . . . ") -set(DASHED_LINE_SYMBOL - "${ColorReset}....................................................................... " -) +set(DASHED_LINE_SYMBOL "${ColorReset}.................................") +string(APPEND DASHED_LINE_SYMBOL "...................................... ") set(ON_OFF_VALUES "ON" "OFF") diff --git a/cmake/tests.cmake b/cmake/tests.cmake index e2d92a343..0e108d365 100644 --- a/cmake/tests.cmake +++ b/cmake/tests.cmake @@ -13,9 +13,7 @@ if(${output}) add_subdirectory(${SRC_DIR}/checkpoint ${CMAKE_CURRENT_BINARY_DIR}/checkpoint) endif() -set(TEST_DIRECTORIES - "" - PARENT_SCOPE) +set(TEST_DIRECTORIES "") if(NOT ${mpi}) list(APPEND TEST_DIRECTORIES global) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index db2ab4c92..f9d921df0 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,3 +1,4 @@ +# cmake-lint: disable=C0103 # ------------------------------ # @defines: entity [STATIC/SHARED] # diff --git a/src/archetypes/CMakeLists.txt b/src/archetypes/CMakeLists.txt index 8e2f325af..93f8baaaa 100644 --- a/src/archetypes/CMakeLists.txt +++ b/src/archetypes/CMakeLists.txt @@ -1,3 +1,4 @@ +# cmake-lint: disable=C0103 # ------------------------------ # @defines: ntt_archetypes [INTERFACE] # @@ -24,4 +25,3 @@ target_link_libraries(ntt_archetypes INTERFACE ${libs}) target_include_directories(ntt_archetypes INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/../) - diff --git a/src/archetypes/tests/CMakeLists.txt b/src/archetypes/tests/CMakeLists.txt index 694a6b4f9..9419847c5 100644 --- a/src/archetypes/tests/CMakeLists.txt +++ b/src/archetypes/tests/CMakeLists.txt @@ -1,3 +1,4 @@ +# cmake-lint: disable=C0103,C0111 # ------------------------------ # @brief: Generates tests for the `ntt_archetypes` module # diff --git a/src/checkpoint/CMakeLists.txt b/src/checkpoint/CMakeLists.txt index fa641bfb5..096aad690 100644 --- a/src/checkpoint/CMakeLists.txt +++ b/src/checkpoint/CMakeLists.txt @@ -1,3 +1,4 @@ +# cmake-lint: disable=C0103 # ------------------------------ # @defines: ntt_checkpoint [STATIC/SHARED] # diff --git a/src/checkpoint/tests/CMakeLists.txt b/src/checkpoint/tests/CMakeLists.txt index 54400652e..cbfd63aa9 100644 --- a/src/checkpoint/tests/CMakeLists.txt +++ b/src/checkpoint/tests/CMakeLists.txt @@ -1,3 +1,4 @@ +# cmake-lint: disable=C0103,C0111 # ------------------------------ # @brief: Generates tests for the `ntt_checkpoint` module # diff --git a/src/engines/CMakeLists.txt b/src/engines/CMakeLists.txt index d5b6b0664..4cef18630 100644 --- a/src/engines/CMakeLists.txt +++ b/src/engines/CMakeLists.txt @@ -1,3 +1,4 @@ +# cmake-lint: disable=C0103 # ------------------------------ # @defines: ntt_engines [STATIC/SHARED] # diff --git a/src/framework/CMakeLists.txt b/src/framework/CMakeLists.txt index d3b68084c..4c407fb0c 100644 --- a/src/framework/CMakeLists.txt +++ b/src/framework/CMakeLists.txt @@ -1,3 +1,4 @@ +# cmake-lint: disable=C0103 # ------------------------------ # @defines: ntt_framework [STATIC/SHARED] # diff --git a/src/framework/parameters.cpp b/src/framework/parameters.cpp index e3bddfd70..5848b1c01 100644 --- a/src/framework/parameters.cpp +++ b/src/framework/parameters.cpp @@ -31,10 +31,10 @@ namespace ntt { template - auto get_dx0_V0( - const std::vector& resolution, - const boundaries_t& extent, - const std::map& params) -> std::pair { + auto get_dx0_V0(const std::vector& resolution, + const boundaries_t& extent, + const std::map& params) + -> std::pair { const auto metric = M(resolution, extent, params); const auto dx0 = metric.dxMin(); coord_t x_corner { ZERO }; @@ -839,7 +839,7 @@ namespace ntt { void SimulationParams::setSetupParams(const toml::value& toml_data) { /* [setup] -------------------------------------------------------------- */ - const auto& setup = toml::find_or(toml_data, "setup", toml::table {}); + const auto setup = toml::find_or(toml_data, "setup", toml::table {}); for (const auto& [key, val] : setup) { if (val.is_boolean()) { set("setup." + key, (bool)(val.as_boolean())); diff --git a/src/framework/tests/CMakeLists.txt b/src/framework/tests/CMakeLists.txt index 27c456610..92e327d80 100644 --- a/src/framework/tests/CMakeLists.txt +++ b/src/framework/tests/CMakeLists.txt @@ -1,3 +1,4 @@ +# cmake-lint: disable=C0103,C0111 # ------------------------------ # @brief: Generates tests for the `ntt_framework` module # diff --git a/src/global/CMakeLists.txt b/src/global/CMakeLists.txt index 97946f059..7546b6a98 100644 --- a/src/global/CMakeLists.txt +++ b/src/global/CMakeLists.txt @@ -1,3 +1,4 @@ +# cmake-lint: disable=C0103 # ------------------------------ # @defines: ntt_global [STATIC/SHARED] # diff --git a/src/global/tests/CMakeLists.txt b/src/global/tests/CMakeLists.txt index e30da20a0..c206f85b0 100644 --- a/src/global/tests/CMakeLists.txt +++ b/src/global/tests/CMakeLists.txt @@ -1,3 +1,4 @@ +# cmake-lint: disable=C0103,C0111 # ------------------------------ # @brief: Generates tests for the `ntt_global` module # diff --git a/src/kernels/CMakeLists.txt b/src/kernels/CMakeLists.txt index c8a1f409f..60eda24cb 100644 --- a/src/kernels/CMakeLists.txt +++ b/src/kernels/CMakeLists.txt @@ -1,3 +1,4 @@ +# cmake-lint: disable=C0103 # ------------------------------ # @defines: ntt_kernels [INTERFACE] # @@ -24,4 +25,3 @@ target_link_libraries(ntt_kernels INTERFACE ${libs}) target_include_directories(ntt_kernels INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/../) - diff --git a/src/kernels/tests/CMakeLists.txt b/src/kernels/tests/CMakeLists.txt index a41ea43ef..7579eb6d3 100644 --- a/src/kernels/tests/CMakeLists.txt +++ b/src/kernels/tests/CMakeLists.txt @@ -1,3 +1,4 @@ +# cmake-lint: disable=C0103,C0111 # ------------------------------ # @brief: Generates tests for the `ntt_kernels` module # diff --git a/src/metrics/CMakeLists.txt b/src/metrics/CMakeLists.txt index e053bb61c..0bb5b977c 100644 --- a/src/metrics/CMakeLists.txt +++ b/src/metrics/CMakeLists.txt @@ -1,3 +1,4 @@ +# cmake-lint: disable=C0103 # ------------------------------ # @defines: ntt_metrics [INTERFACE] # @@ -22,4 +23,3 @@ target_link_libraries(ntt_metrics INTERFACE ${libs}) target_include_directories(ntt_metrics INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/../) - diff --git a/src/metrics/tests/CMakeLists.txt b/src/metrics/tests/CMakeLists.txt index c997ab079..0d661c318 100644 --- a/src/metrics/tests/CMakeLists.txt +++ b/src/metrics/tests/CMakeLists.txt @@ -1,3 +1,4 @@ +# cmake-lint: disable=C0103,C0111 # ------------------------------ # @brief: Generates tests for the `ntt_metrics` module # @@ -28,4 +29,3 @@ gen_test(coord_trans) gen_test(sph-qsph) gen_test(ks-qks) gen_test(sr-cart-sph) - diff --git a/src/output/CMakeLists.txt b/src/output/CMakeLists.txt index 81333e9ff..8a2ea0f16 100644 --- a/src/output/CMakeLists.txt +++ b/src/output/CMakeLists.txt @@ -1,3 +1,4 @@ +# cmake-lint: disable=C0103 # ------------------------------ # @defines: ntt_output [STATIC/SHARED] # diff --git a/src/output/tests/CMakeLists.txt b/src/output/tests/CMakeLists.txt index afc7950c4..835bb532f 100644 --- a/src/output/tests/CMakeLists.txt +++ b/src/output/tests/CMakeLists.txt @@ -1,3 +1,4 @@ +# cmake-lint: disable=C0103,C0111 # ------------------------------ # @brief: Generates tests for the `ntt_output` module # From 195de49511ae1b7e7233338903095ab5af57a50b Mon Sep 17 00:00:00 2001 From: hayk Date: Fri, 4 Apr 2025 03:12:26 -0400 Subject: [PATCH 486/773] log level controlled from input --- input.example.toml | 6 ++++++ src/framework/parameters.cpp | 2 ++ src/framework/simulation.cpp | 7 ++++++- src/global/defaults.h | 3 ++- src/global/utils/formatting.h | 2 +- src/global/utils/plog.h | 14 +++++++++++--- 6 files changed, 28 insertions(+), 6 deletions(-) diff --git a/input.example.toml b/input.example.toml index a49067811..982e4d1f2 100644 --- a/input.example.toml +++ b/input.example.toml @@ -478,3 +478,9 @@ # @type: bool # @default: true colored_stdout = "" + # Specify the log level: + # @type: string + # @valid: "VERBOSE", "WARNING", "ERROR" + # @default: "VERBOSE" + # @note: VERBOSE prints all messages, WARNING prints only warnings and errors, ERROR prints only errors + log_level = "" diff --git a/src/framework/parameters.cpp b/src/framework/parameters.cpp index 5848b1c01..556d9f547 100644 --- a/src/framework/parameters.cpp +++ b/src/framework/parameters.cpp @@ -601,6 +601,8 @@ namespace ntt { toml::find_or(toml_data, "diagnostics", "blocking_timers", false)); set("diagnostics.colored_stdout", toml::find_or(toml_data, "diagnostics", "colored_stdout", false)); + set("diagnostics.log_level", + toml::find_or(toml_data, "diagnostics", "log_level", defaults::diag::log_level)); /* inferred variables --------------------------------------------------- */ // fields/particle boundaries diff --git a/src/framework/simulation.cpp b/src/framework/simulation.cpp index bea50ff09..a36d5cf52 100644 --- a/src/framework/simulation.cpp +++ b/src/framework/simulation.cpp @@ -32,7 +32,12 @@ namespace ntt { const auto raw_params = toml::parse(inputfname); const auto sim_name = toml::find(raw_params, "simulation", "name"); - logger::initPlog(sim_name); + const auto log_level = toml::find_or(raw_params, + "diagnostics", + "log_level", + defaults::diag::log_level); + logger::initPlog(sim_name, + log_level); m_requested_engine = SimEngine::pick( fmt::toLower(toml::find(raw_params, "simulation", "engine")).c_str()); diff --git a/src/global/defaults.h b/src/global/defaults.h index b81369022..d17647ccd 100644 --- a/src/global/defaults.h +++ b/src/global/defaults.h @@ -68,7 +68,8 @@ namespace ntt::defaults { } // namespace checkpoint namespace diag { - const timestep_t interval = 1; + const timestep_t interval = 1; + const std::string log_level = "VERBOSE"; } // namespace diag namespace gca { diff --git a/src/global/utils/formatting.h b/src/global/utils/formatting.h index 8dc7b6ba8..c8c236cab 100644 --- a/src/global/utils/formatting.h +++ b/src/global/utils/formatting.h @@ -171,7 +171,7 @@ namespace fmt { std::size_t cntr { 0 }; for (auto i { 0u }; i < columns.size(); ++i) { const auto anch { static_cast(anchors[i] < 0 ? -anchors[i] - : anchors[i]) }; + : anchors[i]) }; const auto leftalign { anchors[i] <= 0 }; const auto cmn { columns[i] }; const auto cmn_len { strlenUTF8(cmn) }; diff --git a/src/global/utils/plog.h b/src/global/utils/plog.h index 03dc19319..2422c7cf9 100644 --- a/src/global/utils/plog.h +++ b/src/global/utils/plog.h @@ -13,6 +13,8 @@ #ifndef GLOBAL_UTILS_PLOG_H #define GLOBAL_UTILS_PLOG_H +#include "utils/formatting.h" + #include #include #include @@ -57,7 +59,7 @@ namespace plog { namespace logger { template - inline void initPlog(const std::string& fname) { + inline void initPlog(const std::string& fname, const std::string& log_level) { // setup logging const auto logfile_name = fname + ".log"; const auto infofile_name = fname + ".info"; @@ -77,7 +79,13 @@ namespace logger { infofile_name.c_str()); static plog::RollingFileAppender errfileAppender( errfile_name.c_str()); - plog::init(plog::verbose, &logfileAppender); + auto log_severity = plog::verbose; + if (fmt::toLower(log_level) == "WARNING") { + log_severity = plog::warning; + } else if (fmt::toLower(log_level) == "ERROR") { + log_severity = plog::error; + } + plog::init(log_severity, &logfileAppender); plog::init(plog::verbose, &infofileAppender); plog::init(plog::verbose, &errfileAppender); @@ -93,4 +101,4 @@ namespace logger { } // namespace logger -#endif // GLOBAL_UTILS_PLOG_H \ No newline at end of file +#endif // GLOBAL_UTILS_PLOG_H From 83dad1963799a76c96fa9b78adf128d326bd3724 Mon Sep 17 00:00:00 2001 From: hayk Date: Thu, 3 Apr 2025 16:53:54 -0400 Subject: [PATCH 487/773] match.ds is now array --- input.example.toml | 8 +- src/engines/srpic.hpp | 145 ++++++++++++++++++++--------- src/framework/parameters.cpp | 68 +++++++++++--- src/framework/tests/parameters.cpp | 18 +++- 4 files changed, 172 insertions(+), 67 deletions(-) diff --git a/input.example.toml b/input.example.toml index 982e4d1f2..7004fe504 100644 --- a/input.example.toml +++ b/input.example.toml @@ -107,11 +107,13 @@ particles = "" [grid.boundaries.match] - # Size of the matching layer for fields in physical (code) units: - # @type: float + # Size of the matching layer in each direction for fields in physical (code) units: + # @type: float or array of tuples # @default: 1% of the domain size (in shortest dimension) # @note: In spherical, this is the size of the layer in r from the outer wall - # @note: In cartesian, this is the same for all dimensions where applicable + # @example: ds = 1.5 (will set the same for all directions) + # @example: ds = [[1.5], [2.0, 1.0], [1.1]] (will duplicate 1.5 for +/- x1 and 1.1 for +/- x3) + # @example: ds = [[], [1.5], []] (will only set for x2) ds = "" # Absorption coefficient for fields: # @type: float: -inf < ... < inf, != 0 diff --git a/src/engines/srpic.hpp b/src/engines/srpic.hpp index 0a9cc311b..22434ef6b 100644 --- a/src/engines/srpic.hpp +++ b/src/engines/srpic.hpp @@ -79,7 +79,7 @@ namespace ntt { "algorithms.toggles.fieldsolver"); const auto deposit_enabled = m_params.template get( "algorithms.toggles.deposit"); - const auto clear_interval = m_params.template get( + const auto clear_interval = m_params.template get( "particles.clear_interval"); if (step == 0) { @@ -612,15 +612,19 @@ namespace ntt { /** * matching boundaries */ - const auto ds = m_params.template get("grid.boundaries.match.ds"); + const auto ds_array = m_params.template get>( + "grid.boundaries.match.ds"); const auto dim = direction.get_dim(); real_t xg_min, xg_max, xg_edge; auto sign = direction.get_sign(); + real_t ds; if (sign > 0) { // + direction + ds = ds_array[(short)dim].second; xg_max = m_metadomain.mesh().extent(dim).second; xg_min = xg_max - ds; xg_edge = xg_max; } else { // - direction + ds = ds_array[(short)dim].first; xg_min = m_metadomain.mesh().extent(dim).first; xg_max = xg_min + ds; xg_edge = xg_min; @@ -651,50 +655,81 @@ namespace ntt { range_min[d] = intersect_range[d].first; range_max[d] = intersect_range[d].second; } - if constexpr (traits::has_member::value) { - auto match_fields = m_pgen.MatchFields(time); - if (dim == in::x1) { - Kokkos::parallel_for( - "MatchFields", - CreateRangePolicy(range_min, range_max), - kernel::bc::MatchBoundaries_kernel( - domain.fields.em, - match_fields, - domain.mesh.metric, - xg_edge, - ds, - tags)); - } else if (dim == in::x2) { - if constexpr (M::Dim == Dim::_2D or M::Dim == Dim::_3D) { - Kokkos::parallel_for( - "MatchFields", - CreateRangePolicy(range_min, range_max), - kernel::bc::MatchBoundaries_kernel( - domain.fields.em, - match_fields, - domain.mesh.metric, - xg_edge, - ds, - tags)); - } else { - raise::Error("Invalid dimension", HERE); - } - } else if (dim == in::x3) { - if constexpr (M::Dim == Dim::_3D) { - Kokkos::parallel_for( - "MatchFields", - CreateRangePolicy(range_min, range_max), - kernel::bc::MatchBoundaries_kernel( - domain.fields.em, - match_fields, - domain.mesh.metric, - xg_edge, - ds, - tags)); - } else { - raise::Error("Invalid dimension", HERE); - } + + if (dim == in::x1) { + if constexpr ( + traits::has_member::value) { + auto match_fields = m_pgen.MatchFields(time); + call_match_fields(domain.fields.em, + match_fields, + domain.mesh.metric, + xg_edge, + ds, + tags, + range_min, + range_max); + } else if constexpr ( + traits::has_member::value) { + auto match_fields = m_pgen.MatchFieldsInX1(time); + call_match_fields(domain.fields.em, + match_fields, + domain.mesh.metric, + xg_edge, + ds, + tags, + range_min, + range_max); } + } else if (dim == in::x2) { + if constexpr ( + traits::has_member::value) { + auto match_fields = m_pgen.MatchFields(time); + call_match_fields(domain.fields.em, + match_fields, + domain.mesh.metric, + xg_edge, + ds, + tags, + range_min, + range_max); + } else if constexpr ( + traits::has_member::value) { + auto match_fields = m_pgen.MatchFieldsInX2(time); + call_match_fields(domain.fields.em, + match_fields, + domain.mesh.metric, + xg_edge, + ds, + tags, + range_min, + range_max); + } + } else if (dim == in::x3) { + if constexpr ( + traits::has_member::value) { + auto match_fields = m_pgen.MatchFields(time); + call_match_fields(domain.fields.em, + match_fields, + domain.mesh.metric, + xg_edge, + ds, + tags, + range_min, + range_max); + } else if constexpr ( + traits::has_member::value) { + auto match_fields = m_pgen.MatchFieldsInX3(time); + call_match_fields(domain.fields.em, + match_fields, + domain.mesh.metric, + xg_edge, + ds, + tags, + range_min, + range_max); + } + } else { + raise::Error("Invalid dimension", HERE); } } @@ -1266,6 +1301,26 @@ namespace ntt { } return range; } + + template + void call_match_fields(ndfield_t& fields, + const T& match_fields, + const M& metric, + real_t xg_edge, + real_t ds, + BCTags tags, + tuple_t& range_min, + tuple_t& range_max) { + Kokkos::parallel_for( + "MatchFields", + CreateRangePolicy(range_min, range_max), + kernel::bc::MatchBoundaries_kernel(fields, + match_fields, + metric, + xg_edge, + ds, + tags)); + } }; } // namespace ntt diff --git a/src/framework/parameters.cpp b/src/framework/parameters.cpp index 556d9f547..cd6edc929 100644 --- a/src/framework/parameters.cpp +++ b/src/framework/parameters.cpp @@ -738,23 +738,63 @@ namespace ntt { for (const auto& e : extent_pairwise) { min_extent = std::min(min_extent, e.second - e.first); } - set("grid.boundaries.match.ds", - toml::find_or(toml_data, - "grid", - "boundaries", - "match", - "ds", - min_extent * defaults::bc::match::ds_frac)); + const auto default_ds = min_extent * defaults::bc::match::ds_frac; + std::size_t n_match_bcs { 0u }; + for (const auto& bcs : flds_bc_pairwise) { + if (bcs.first == FldsBC::MATCH or bcs.second == FldsBC::MATCH) { + n_match_bcs += 1; + } + } + boundaries_t ds_array; + try { + auto ds = toml::find(toml_data, "grid", "boundaries", "match", "ds"); + for (auto d = 0u; d < dim; ++d) { + ds_array.push_back({ ds, ds }); + } + } catch (const toml::type_error&) { + try { + const auto ds = toml::find>>( + toml_data, + "grid", + "boundaries", + "match", + "ds"); + raise::ErrorIf(ds.size() != dim, + "invalid # in `grid.boundaries.match.ds`", + HERE); + for (auto d = 0u; d < dim; ++d) { + if (ds[d].size() == 1) { + ds_array.push_back({ ds[d][0], ds[d][0] }); + } else if (ds[d].size() == 2) { + ds_array.push_back({ ds[d][0], ds[d][1] }); + } else if (ds[d].size() == 0) { + ds_array.push_back({}); + } else { + raise::Error("invalid `grid.boundaries.match.ds`", HERE); + } + } + } catch (...) { + for (auto d = 0u; d < dim; ++d) { + ds_array.push_back({ default_ds, default_ds }); + } + } + } + set("grid.boundaries.match.ds", ds_array); } else { auto r_extent = extent_pairwise[0].second - extent_pairwise[0].first; - set("grid.boundaries.match.ds", - toml::find_or(toml_data, - "grid", - "boundaries", - "match", - "ds", - r_extent * defaults::bc::match::ds_frac)); + const auto ds = toml::find_or( + toml_data, + "grid", + "boundaries", + "match", + "ds", + r_extent * defaults::bc::match::ds_frac); + boundaries_t ds_array { + { ds, ds } + }; + set("grid.boundaries.match.ds", ds_array); } + set("grid.boundaries.match.coeff", toml::find_or(toml_data, "grid", diff --git a/src/framework/tests/parameters.cpp b/src/framework/tests/parameters.cpp index 7cd5ce46a..c4d1f0e7b 100644 --- a/src/framework/tests/parameters.cpp +++ b/src/framework/tests/parameters.cpp @@ -29,12 +29,12 @@ const auto mink_1d = u8R"( metric = "minkowski" [grid.boundaries] - fields = [["PERIODIC"]] + fields = [["MATCH", "MATCH"]] particles = [["ABSORB", "ABSORB"]] [grid.boundaries.match] coeff = 10.0 - ds = 0.025 + ds = [[0.025, 0.1]] [scales] larmor0 = 0.1 @@ -269,7 +269,7 @@ auto main(int argc, char* argv[]) -> int { (real_t)0.0078125, "scales.V0"); boundaries_t fbc = { - { FldsBC::PERIODIC, FldsBC::PERIODIC } + { FldsBC::MATCH, FldsBC::MATCH } }; assert_equal( params_mink_1d.get>("grid.boundaries.fields")[0].first, @@ -283,6 +283,14 @@ auto main(int argc, char* argv[]) -> int { params_mink_1d.get>("grid.boundaries.fields").size(), fbc.size(), "grid.boundaries.fields.size()"); + assert_equal( + params_mink_1d.get>("grid.boundaries.match.ds")[0].first, + (real_t)0.025, + "grid.boundaries.match.ds[0].first"); + assert_equal( + params_mink_1d.get>("grid.boundaries.match.ds")[0].second, + (real_t)0.1, + "grid.boundaries.match.ds[0].first"); const auto species = params_mink_1d.get>( "particles.species"); @@ -383,7 +391,7 @@ auto main(int argc, char* argv[]) -> int { // match coeffs assert_equal( - params_sph_2d.get("grid.boundaries.match.ds"), + params_sph_2d.get>("grid.boundaries.match.ds")[0].second, (real_t)(defaults::bc::match::ds_frac * 19.0), "grid.boundaries.match.ds"); @@ -539,7 +547,7 @@ auto main(int argc, char* argv[]) -> int { // match coeffs assert_equal( - params_qks_2d.get("grid.boundaries.match.ds"), + params_qks_2d.get>("grid.boundaries.match.ds")[0].second, (real_t)(defaults::bc::match::ds_frac * (100.0 - 0.8)), "grid.boundaries.match.ds"); From 62759fb19d773d9fc76d87760bc08f345784c480 Mon Sep 17 00:00:00 2001 From: hayk Date: Thu, 3 Apr 2025 16:54:56 -0400 Subject: [PATCH 488/773] generalized uniform injector --- src/archetypes/particle_injector.h | 128 +++++++++++++++++++++++------ src/kernels/injectors.hpp | 14 ++-- 2 files changed, 110 insertions(+), 32 deletions(-) diff --git a/src/archetypes/particle_injector.h b/src/archetypes/particle_injector.h index 3884e6ced..4e776b132 100644 --- a/src/archetypes/particle_injector.h +++ b/src/archetypes/particle_injector.h @@ -32,6 +32,7 @@ #include #include +#include #include #include @@ -58,14 +59,79 @@ namespace arch { , species { species } {} ~UniformInjector() = default; + + auto ComputeNumInject(const Domain& domain, + real_t ppc0, + real_t number_density, + const boundaries_t& box) const + -> std::tuple, array_t> { + auto i_min = array_t { "i_min", M::Dim }; + auto i_max = array_t { "i_max", M::Dim }; + + if (not domain.mesh.Intersects(box)) { + return { false, (npart_t)0, i_min, i_max }; + } + tuple_t range_min { 0 }; + tuple_t range_max { 0 }; + + boundaries_t incl_ghosts; + for (auto d { 0u }; d < M::Dim; ++d) { + incl_ghosts.push_back({ false, false }); + } + const auto intersect_range = domain.mesh.ExtentToRange(box, incl_ghosts); + + for (auto d { 0u }; d < M::Dim; ++d) { + range_min[d] = intersect_range[d].first; + range_max[d] = intersect_range[d].second; + } + ncells_t ncells = 1; + for (auto d = 0u; d < M::Dim; ++d) { + ncells *= (range_max[d] - range_min[d]); + } + const auto nparticles = static_cast( + (long double)(ppc0 * number_density * 0.5) * (long double)(ncells)); + + auto i_min_h = Kokkos::create_mirror_view(i_min); + auto i_max_h = Kokkos::create_mirror_view(i_max); + for (auto d = 0u; d < M::Dim; ++d) { + i_min_h(d) = (real_t)(range_min[d]); + i_max_h(d) = (real_t)(range_max[d]); + } + Kokkos::deep_copy(i_min, i_min_h); + Kokkos::deep_copy(i_max, i_max_h); + return { true, nparticles, i_min, i_max }; + } + }; + + template class ED> + struct KeepConstantInjector : UniformInjector { + using energy_dist_t = ED; + using UniformInjector::D; + using UniformInjector::C; + + const boundaries_t probe_box; + + KeepConstantInjector(const energy_dist_t& energy_dist, + const std::pair& species, + boundaries_t probe_box = {}) + : UniformInjector(energy_dist, species) + , probe_box { probe_box } {} + + ~KeepConstantInjector() = default; + + auto ComputeNumInject(const Domain& domain, + real_t ppc0, + real_t number_density, + const boundaries_t& box) const + -> std::tuple, array_t> { + ... + } }; template - class ED, - template - class SD> + template class ED, + template class SD> struct NonUniformInjector { using energy_dist_t = ED; using spatial_dist_t = SD; @@ -181,11 +247,12 @@ namespace arch { * @tparam I Injector type */ template - inline void InjectUniform(const SimulationParams& params, - Domain& domain, - const I& injector, - real_t number_density, - bool use_weights = false) { + inline void InjectUniform(const SimulationParams& params, + Domain& domain, + const I& injector, + 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(I::is_uniform_injector, "I must be a uniform injector class"); raise::ErrorIf((M::CoordType != Coord::Cart) && (not use_weights), @@ -205,17 +272,25 @@ namespace arch { } { - auto ppc0 = params.template get("particles.ppc0"); - array_t ni { "ni", M::Dim }; - auto ni_h = Kokkos::create_mirror_view(ni); - ncells_t ncells = 1; - for (auto d = 0; d < M::Dim; ++d) { - ni_h(d) = domain.mesh.n_active()[d]; - ncells *= domain.mesh.n_active()[d]; + boundaries_t nonempty_box; + for (auto d { 0u }; d < M::Dim; ++d) { + if (d < box.size()) { + nonempty_box.push_back({ box[d].first, box[d].second }); + } else { + nonempty_box.push_back(Range::All); + } } - Kokkos::deep_copy(ni, ni_h); - const auto nparticles = static_cast( - (long double)(ppc0 * number_density * 0.5) * (long double)(ncells)); + auto ppc0 = params.template get("particles.ppc0"); + const auto result = injector.ComputeNumInject(domain, + ppc0, + number_density, + nonempty_box); + if (not std::get<0>(result)) { + return; + } + const auto nparticles = std::get<1>(result); + const auto i_min = std::get<2>(result); + const auto i_max = std::get<3>(result); Kokkos::parallel_for( "InjectUniform", @@ -228,7 +303,8 @@ namespace arch { domain.species[injector.species.first - 1].npart(), domain.species[injector.species.second - 1].npart(), domain.mesh.metric, - ni, + i_min, + i_max, injector.energy_dist, ONE / params.template get("scales.V0"), domain.random_pool)); @@ -279,12 +355,12 @@ namespace arch { * @param box Region to inject the particles in */ template - inline void InjectNonUniform(const SimulationParams& params, - Domain& domain, - const I& injector, - real_t number_density, - bool use_weights = false, - boundaries_t box = {}) { + inline void InjectNonUniform(const SimulationParams& params, + Domain& domain, + const I& injector, + 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(I::is_nonuniform_injector, "I must be a nonuniform injector class"); diff --git a/src/kernels/injectors.hpp b/src/kernels/injectors.hpp index 09bc7a180..7dcd017a3 100644 --- a/src/kernels/injectors.hpp +++ b/src/kernels/injectors.hpp @@ -49,7 +49,7 @@ namespace kernel { npart_t offset1, offset2; const M metric; - const array_t ni; + const array_t i_min, i_max; const ED energy_dist; const real_t inv_V0; random_number_pool_t random_pool; @@ -61,7 +61,8 @@ namespace kernel { npart_t offset1, npart_t offset2, const M& metric, - const array_t& ni, + const array_t& i_min, + const array_t& i_max, const ED& energy_dist, real_t inv_V0, random_number_pool_t& random_pool) @@ -94,7 +95,8 @@ namespace kernel { , offset1 { offset1 } , offset2 { offset2 } , metric { metric } - , ni { ni } + , i_min { i_min } + , i_max { i_max } , energy_dist { energy_dist } , inv_V0 { inv_V0 } , random_pool { random_pool } {} @@ -104,12 +106,12 @@ namespace kernel { vec_t v1 { ZERO }, v2 { ZERO }; { // generate a random coordinate auto rand_gen = random_pool.get_state(); - x_Cd[0] = Random(rand_gen) * ni(0); + x_Cd[0] = i_min(0) + Random(rand_gen) * (i_max(0) - i_min(0)); if constexpr (M::Dim == Dim::_2D or M::Dim == Dim::_3D) { - x_Cd[1] = Random(rand_gen) * ni(1); + x_Cd[1] = i_min(1) + Random(rand_gen) * (i_max(1) - i_min(1)); } if constexpr (M::Dim == Dim::_3D) { - x_Cd[2] = Random(rand_gen) * ni(2); + x_Cd[2] = i_min(2) + Random(rand_gen) * (i_max(2) - i_min(2)); } random_pool.free_state(rand_gen); } From 395e670f1f01fadafac15b75f946e2336a6835d9 Mon Sep 17 00:00:00 2001 From: hayk Date: Thu, 3 Apr 2025 16:56:02 -0400 Subject: [PATCH 489/773] diff match boundaries in diff directions --- setups/wip/reconnection/pgen.hpp | 292 +++++++++++++++++----- setups/wip/reconnection/reconnection.toml | 40 +-- src/global/arch/traits.h | 9 + 3 files changed, 261 insertions(+), 80 deletions(-) diff --git a/setups/wip/reconnection/pgen.hpp b/setups/wip/reconnection/pgen.hpp index e97bc518a..34314ca68 100644 --- a/setups/wip/reconnection/pgen.hpp +++ b/setups/wip/reconnection/pgen.hpp @@ -15,41 +15,136 @@ #include "archetypes/spatial_dist.h" #include "framework/domain/metadomain.h" +#include "kernels/particle_moments.hpp" + namespace user { using namespace ntt; template struct CurrentLayer : public arch::SpatialDistribution { - CurrentLayer(const M& metric, real_t width, real_t yi) + CurrentLayer(const M& metric, real_t cs_width, real_t cs_y) : arch::SpatialDistribution { metric } - , width { width } - , yi { yi } {} + , cs_width { cs_width } + , cs_y { cs_y } {} Inline auto operator()(const coord_t& x_Ph) const -> real_t override { - return ONE / SQR(math::cosh((x_Ph[1] - yi) / width)); + return ONE / SQR(math::cosh((x_Ph[1] - cs_y) / cs_width)); } private: - const real_t yi, width; + const real_t cs_y, cs_width; }; + // field initializer template struct InitFields { - InitFields(real_t Bmag, real_t width, real_t y1, real_t y2) - : Bmag { Bmag } - , width { width } - , y1 { y1 } - , y2 { y2 } {} + InitFields(real_t bg_B, real_t bg_Bguide, real_t cs_width, real_t cs_y) + : bg_B { bg_B } + , bg_Bguide { bg_Bguide } + , cs_width { cs_width } + , cs_y { cs_y } {} Inline auto bx1(const coord_t& x_Ph) const -> real_t { - return Bmag * (math::tanh((x_Ph[1] - y1) / width) - - math::tanh((x_Ph[1] - y2) / width) - 1); + return bg_B * (math::tanh((x_Ph[1] - cs_y) / cs_width)); + } + + Inline auto bx3(const coord_t&) const -> real_t { + return bg_Bguide; } private: - const real_t Bmag, width, y1, y2; + const real_t bg_B, bg_Bguide, cs_width, cs_y; }; + template + struct BoundaryFieldsInX1 { + BoundaryFieldsInX1(real_t bg_B, + real_t bg_Bguide, + real_t beta_rec, + real_t cs_width, + real_t cs_x, + real_t cs_y) + : bg_B { bg_B } + , bg_Bguide { bg_Bguide } + , beta_rec { beta_rec } + , cs_width { cs_width } + , cs_x { cs_x } + , cs_y { cs_y } {} + + Inline auto bx1(const coord_t& x_Ph) const -> real_t { + return bg_B * (math::tanh((x_Ph[1] - cs_y) / cs_width)); + } + + Inline auto bx2(const coord_t& x_Ph) const -> real_t { + return beta_rec * bg_B * (math::tanh((x_Ph[0] - cs_x) / cs_width)); + } + + Inline auto bx3(const coord_t&) const -> real_t { + return bg_Bguide; + } + + Inline auto ex1(const coord_t& x_Ph) const -> real_t { + return beta_rec * bg_Bguide * math::tanh((x_Ph[1] - cs_y) / cs_width); + } + + Inline auto ex2(const coord_t&) const -> real_t { + return ZERO; + } + + Inline auto ex3(const coord_t&) const -> real_t { + return -beta_rec * bg_B; + } + + private: + const real_t bg_B, bg_Bguide, beta_rec, cs_width, cs_x, cs_y; + }; + + template + struct BoundaryFieldsInX2 { + BoundaryFieldsInX2(real_t bg_B, real_t bg_Bguide, real_t cs_width, real_t cs_y) + : bg_B { bg_B } + , bg_Bguide { bg_Bguide } + , cs_width { cs_width } + , cs_y { cs_y } {} + + Inline auto bx1(const coord_t& x_Ph) const -> real_t { + return bg_B * (math::tanh((x_Ph[1] - cs_y) / cs_width)); + } + + Inline auto bx2(const coord_t&) const -> real_t { + return ZERO; + } + + Inline auto bx3(const coord_t&) const -> real_t { + return bg_Bguide; + } + + Inline auto ex1(const coord_t&) const -> real_t { + return ZERO; + } + + Inline auto ex2(const coord_t&) const -> real_t { + return ZERO; + } + + Inline auto ex3(const coord_t&) const -> real_t { + return ZERO; + } + + private: + const real_t bg_B, bg_Bguide, cs_width, cs_y; + }; + + // constant particle density for particle boundaries + template + struct ConstDens { + Inline auto operator()(const coord_t& x_Ph) const -> real_t { + return ONE; + } + }; + template + using spatial_dist_t = arch::Replenish>; + template struct PGen : public arch::ProblemGenerator { // compatibility traits for the problem generator @@ -64,30 +159,42 @@ namespace user { using arch::ProblemGenerator::C; using arch::ProblemGenerator::params; - const real_t Bmag, width, overdensity, y1, y2, bg_temp; + const real_t bg_B, bg_Bguide, bg_temperature; + const real_t cs_width, cs_overdensity, cs_x, cs_y; + InitFields init_flds; inline PGen(const SimulationParams& p, const Metadomain& m) : arch::ProblemGenerator(p) - , Bmag { p.template get("setup.Bmag", 1.0) } - , width { p.template get("setup.width") } - , overdensity { p.template get("setup.overdensity") } - , y1 { m.mesh().extent(in::x2).first + - INV_4 * - (m.mesh().extent(in::x2).second - m.mesh().extent(in::x2).first) } - , y2 { m.mesh().extent(in::x2).first + - 3 * INV_4 * - (m.mesh().extent(in::x2).second - m.mesh().extent(in::x2).first) } - , init_flds { Bmag, width, y1, y2 } - , bg_temp { p.template get("setup.bg_temp") } {} + , bg_B { p.template get("setup.bg_B", 1.0) } + , bg_Bguide { p.template get("setup.bg_Bguide", 0.0) } + , bg_temperature { p.template get("setup.bg_temperature", 0.001) } + , cs_width { p.template get("setup.cs_width") } + , cs_overdensity { p.template get("setup.cs_overdensity") } + , cs_x { m.mesh().extent(in::x1).first + + INV_2 * (m.mesh().extent(in::x1).second - + m.mesh().extent(in::x1).first) } + , cs_y { m.mesh().extent(in::x2).first + + INV_2 * (m.mesh().extent(in::x2).second - + m.mesh().extent(in::x2).first) } + , init_flds { bg_B, bg_Bguide, cs_width, cs_y } {} inline PGen() {} + auto MatchFieldsInX1(simtime_t) const -> BoundaryFieldsInX1 { + return BoundaryFieldsInX1 { bg_B, bg_Bguide, (real_t)0.1, + cs_width, cs_x, cs_y }; + } + + auto MatchFieldsInX2(simtime_t) const -> BoundaryFieldsInX2 { + return BoundaryFieldsInX2 { bg_B, bg_Bguide, cs_width, cs_y }; + } + inline void InitPrtls(Domain& local_domain) { // background const auto energy_dist = arch::Maxwellian(local_domain.mesh.metric, local_domain.random_pool, - bg_temp); + bg_temperature); const auto injector = arch::UniformInjector( energy_dist, { 1, 2 }); @@ -95,46 +202,111 @@ namespace user { params, local_domain, injector, - HALF); + ONE); const auto sigma = params.template get("scales.sigma0"); const auto c_omp = params.template get("scales.skindepth0"); - const auto cs_drift_beta = math::sqrt(sigma) * c_omp / (width * overdensity); + const auto cs_drift_beta = math::sqrt(sigma) * c_omp / + (cs_width * cs_overdensity); const auto cs_drift_gamma = ONE / math::sqrt(ONE - SQR(cs_drift_beta)); const auto cs_drift_u = cs_drift_beta * cs_drift_gamma; - const auto cs_temp = HALF * sigma / overdensity; - // current layer #1 - auto edist_cs_1 = arch::Maxwellian(local_domain.mesh.metric, - local_domain.random_pool, - cs_temp, - cs_drift_u, - in::x3, - false); - const auto sdist_cs_1 = CurrentLayer(local_domain.mesh.metric, width, y1); - const auto inj_cs_1 = arch::NonUniformInjector( - edist_cs_1, - sdist_cs_1, - { 1, 2 }); - arch::InjectNonUniform(params, - local_domain, - inj_cs_1, - overdensity); - // current layer #2 - const auto edist_cs_2 = arch::Maxwellian(local_domain.mesh.metric, - local_domain.random_pool, - cs_temp, - -cs_drift_u, - in::x3, - false); - const auto sdist_cs_2 = CurrentLayer(local_domain.mesh.metric, width, y2); - const auto inj_cs_2 = arch::NonUniformInjector( - edist_cs_2, - sdist_cs_2, + const auto cs_temperature = HALF * sigma / cs_overdensity; + + // current layer + auto edist_cs = arch::Maxwellian(local_domain.mesh.metric, + local_domain.random_pool, + cs_temperature, + cs_drift_u, + in::x3, + false); + const auto sdist_cs = CurrentLayer(local_domain.mesh.metric, + cs_width, + cs_y); + const auto inj_cs = arch::NonUniformInjector( + edist_cs, + sdist_cs, { 1, 2 }); - arch::InjectNonUniform(params, - local_domain, - inj_cs_2, - overdensity); + arch::InjectNonUniform(params, + local_domain, + inj_cs, + cs_overdensity); + } + + void CustomPostStep(std::size_t step, long double time, Domain& domain) { + // // 0. define target density profile and box where it has to be + // reached + // // 1. compute density + // // 2. define spatial distribution + // // 3. define energy distribution + // // 4. define particle injector + // // 5. inject particles + // + // // step 0. + // // defining the regions of interest (lower and upper + // y-boundaries) boundaries_t box_upper, box_lower; const + // auto [xmin, xmax] = domain.mesh.extent(in::x1); const auto [ymin, + // ymax] = domain.mesh.extent(in::x2); box_upper.push_back({ xmin, + // xmax }); box_lower.push_back({ xmin, xmax }); + // + // box_upper.push_back({ ymax - dy, ymax }); + // box_lower.push_back({ ymin, ymin + dy }); + // + // if constexpr (M::Dim == Dim::_3D) { + // const auto [zmin, zmax] = domain.mesh.extent(in::x3); + // box_upper.push_back({ zmin, zmax }); + // box_lower.push_back({ zmin, zmax }); + // } + // + // const auto const_dens = ConstDens(); + // const auto inv_n0 = ONE / n0; + // + // // step 1 compute density + // auto scatter_bckp = Kokkos::Experimental::create_scatter_view( + // domain.fields.bckp); + // for (auto& prtl_spec : domain.species) { + // // clang-format off + // Kokkos::parallel_for( + // "ComputeMoments", + // prtl_spec.rangeActiveParticles(), + // kernel::ParticleMoments_kernel({}, + // scatter_bckp, 0, + // prtl_spec.i1, + // prtl_spec.i2, + // prtl_spec.i3, prtl_spec.dx1, + // prtl_spec.dx2, + // prtl_spec.dx3, prtl_spec.ux1, + // prtl_spec.ux2, + // prtl_spec.ux3, prtl_spec.phi, + // prtl_spec.weight, + // prtl_spec.tag, prtl_spec.mass(), + // prtl_spec.charge(), + // false, + // domain.mesh.metric, + // domain.mesh.flds_bc(), + // 0, inv_n0, 0)); + // } + // Kokkos::Experimental::contribute(domain.fields.bckp, scatter_bckp); + // + // + // //step 2. define spatial distribution + // // const auto spatial_dist = arch::Replenish>(domain.mesh.metric, domain.fields.bckp, 0, + // const_dens, ONE); + // const auto spatial_dist = spatial_dist_t(domain.mesh.metric, + // domain.fields.bckp,0,const_dens,ONE); + // //step 3. define energy distribution + // const auto energy_dist = arch::Maxwellian(domain.mesh.metric, + // domain.random_pool, up_temperature); + // //step 4. define particle injector + // const auto injector = arch::NonUniformInjector(energy_dist, spatial_dist, {1,2}); + // //step 5. inject particles + // arch::InjectNonUniform(params, domain, + // injector, ONE, false, box_upper); //upper boudary arch::InjectNonUniform(params, domain, injector, ONE, false, + // box_lower); //lower boundary + // + // } }; diff --git a/setups/wip/reconnection/reconnection.toml b/setups/wip/reconnection/reconnection.toml index fa7b049f4..db3dbde72 100644 --- a/setups/wip/reconnection/reconnection.toml +++ b/setups/wip/reconnection/reconnection.toml @@ -1,21 +1,21 @@ [simulation] - name = "reconnection" - engine = "srpic" + name = "reconnection" + engine = "srpic" runtime = 10.0 [grid] - resolution = [1024, 2048] - extent = [[-1.0, 1.0], [-2.0, 2.0]] + resolution = [1024, 512] + extent = [[-1.0, 1.0], [-0.5, 0.5]] [grid.metric] metric = "minkowski" [grid.boundaries] - fields = [["PERIODIC"], ["PERIODIC"]] - particles = [["PERIODIC"], ["PERIODIC"]] - + fields = [["MATCH", "MATCH"], ["MATCH", "MATCH"], ["PERIODIC"]] + particles = [["ABSORB", "ABSORB"], ["ABSORB", "ABSORB"], ["PERIODIC"]] + [scales] - larmor0 = 2e-4 + larmor0 = 2e-4 skindepth0 = 2e-3 [algorithms] @@ -25,28 +25,28 @@ CFL = 0.5 [particles] - ppc0 = 8.0 + ppc0 = 2.0 [[particles.species]] - label = "e-" - mass = 1.0 - charge = -1.0 + label = "e-" + mass = 1.0 + charge = -1.0 maxnpart = 1e7 [[particles.species]] - label = "e+" - mass = 1.0 - charge = 1.0 + label = "e+" + mass = 1.0 + charge = 1.0 maxnpart = 1e7 [setup] - Bmag = 1.0 - width = 0.01 - bg_temp = 1e-4 + Bmag = 1.0 + width = 0.01 + bg_temp = 1e-4 overdensity = 3.0 - + [output] - format = "hdf5" + format = "hdf5" interval_time = 0.1 [output.fields] diff --git a/src/global/arch/traits.h b/src/global/arch/traits.h index 4cde4fca5..5527d570f 100644 --- a/src/global/arch/traits.h +++ b/src/global/arch/traits.h @@ -103,6 +103,15 @@ namespace traits { template using match_fields_t = decltype(&T::MatchFields); + template + using match_fields_in_x1_t = decltype(&T::MatchFieldsInX1); + + template + using match_fields_in_x2_t = decltype(&T::MatchFieldsInX2); + + template + using match_fields_in_x3_t = decltype(&T::MatchFieldsInX3); + template using match_fields_const_t = decltype(&T::MatchFieldsConst); From e5353652c39c1269a9ed74afcccdd2ce3bc034bb Mon Sep 17 00:00:00 2001 From: hayk Date: Thu, 3 Apr 2025 16:56:24 -0400 Subject: [PATCH 490/773] const specifier added to mesh methods --- src/framework/domain/mesh.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/framework/domain/mesh.h b/src/framework/domain/mesh.h index 98fe68895..e4f2cba6d 100644 --- a/src/framework/domain/mesh.h +++ b/src/framework/domain/mesh.h @@ -74,7 +74,7 @@ namespace ntt { * @note pass Range::All to select the entire dimension */ [[nodiscard]] - auto Intersection(boundaries_t box) -> boundaries_t { + auto Intersection(boundaries_t box) const -> boundaries_t { raise::ErrorIf(box.size() != M::Dim, "Invalid box dimension", HERE); boundaries_t intersection; auto d = 0; @@ -109,7 +109,7 @@ namespace ntt { * @note pass Range::All to select the entire dimension */ [[nodiscard]] - auto Intersects(boundaries_t box) -> bool { + auto Intersects(boundaries_t box) const -> bool { raise::ErrorIf(box.size() != M::Dim, "Invalid box dimension", HERE); const auto intersection = Intersection(box); for (const auto& i : intersection) { @@ -131,8 +131,8 @@ namespace ntt { * @note indices are already shifted by N_GHOSTS (i.e. they start at N_GHOSTS not 0) */ [[nodiscard]] - auto ExtentToRange(boundaries_t box, - boundaries_t incl_ghosts) -> boundaries_t { + auto ExtentToRange(boundaries_t box, boundaries_t incl_ghosts) const + -> boundaries_t { raise::ErrorIf(box.size() != M::Dim, "Invalid box dimension", HERE); raise::ErrorIf(incl_ghosts.size() != M::Dim, "Invalid incl_ghosts dimension", From 98f5626a1c358f854b335353d76430b7efd1d51e Mon Sep 17 00:00:00 2001 From: hayk Date: Fri, 4 Apr 2025 14:18:51 -0400 Subject: [PATCH 491/773] more general uniforminject class --- src/archetypes/particle_injector.h | 56 +++++++++++++++++++++++++----- 1 file changed, 47 insertions(+), 9 deletions(-) diff --git a/src/archetypes/particle_injector.h b/src/archetypes/particle_injector.h index 4e776b132..9112a3c41 100644 --- a/src/archetypes/particle_injector.h +++ b/src/archetypes/particle_injector.h @@ -60,17 +60,16 @@ namespace arch { ~UniformInjector() = default; - auto ComputeNumInject(const Domain& domain, - real_t ppc0, - real_t number_density, - const boundaries_t& box) const - -> std::tuple, array_t> { + auto DeduceInjectRegion(const Domain& domain, + const boundaries_t& box) const + -> std::tuple, array_t> { auto i_min = array_t { "i_min", M::Dim }; auto i_max = array_t { "i_max", M::Dim }; if (not domain.mesh.Intersects(box)) { - return { false, (npart_t)0, i_min, i_max }; + return { false, (ncells_t)0, i_min, i_max }; } + tuple_t range_min { 0 }; tuple_t range_max { 0 }; @@ -84,12 +83,11 @@ namespace arch { range_min[d] = intersect_range[d].first; range_max[d] = intersect_range[d].second; } + ncells_t ncells = 1; for (auto d = 0u; d < M::Dim; ++d) { ncells *= (range_max[d] - range_min[d]); } - const auto nparticles = static_cast( - (long double)(ppc0 * number_density * 0.5) * (long double)(ncells)); auto i_min_h = Kokkos::create_mirror_view(i_min); auto i_max_h = Kokkos::create_mirror_view(i_max); @@ -97,8 +95,30 @@ namespace arch { i_min_h(d) = (real_t)(range_min[d]); i_max_h(d) = (real_t)(range_max[d]); } + Kokkos::deep_copy(i_min, i_min_h); Kokkos::deep_copy(i_max, i_max_h); + return { true, ncells, i_min, i_max }; + } + + auto ComputeNumInject(const Domain& domain, + real_t ppc0, + real_t number_density, + const boundaries_t& box) const + -> std::tuple, array_t> { + const auto result = DeduceInjectRegion(domain, box); + const auto should_inject = std::get<0>(result); + auto i_min = std::get<2>(result); + auto i_max = std::get<3>(result); + + if (not shoult_inject) { + return { false, (npart_t)0, i_min, i_max }; + } + const auto ncells = std::get<1>(result); + + const auto nparticles = static_cast( + (long double)(ppc0 * number_density * 0.5) * (long double)(ncells)); + return { true, nparticles, i_min, i_max }; } }; @@ -124,7 +144,24 @@ namespace arch { real_t number_density, const boundaries_t& box) const -> std::tuple, array_t> { - ... + const auto result = DeduceInjectRegion(domain, box); + const auto should_inject = std::get<0>(result); + auto i_min = std::get<2>(result); + auto i_max = std::get<3>(result); + + if (not shoult_inject) { + return { false, (npart_t)0, i_min, i_max }; + } + const auto ncells = std::get<1>(result); + + // @TODO + const auto computed_avg_density = ONE; + + const auto nparticles = static_cast( + (long double)(ppc0 * (number_density - computed_avg_density) * 0.5) * + (long double)(ncells)); + + return { true, nparticles, i_min, i_max }; } }; @@ -242,6 +279,7 @@ namespace arch { * @param injector Uniform injector object * @param number_density Total number density (in units of n0) * @param use_weights Use weights + * @param box Region to inject the particles in global coords * @tparam S Simulation engine type * @tparam M Metric type * @tparam I Injector type From 27e190eb4c8e9e17a5ee878e7cdbc6c2ce42b39e Mon Sep 17 00:00:00 2001 From: LudwigBoess Date: Fri, 4 Apr 2025 13:59:41 -0500 Subject: [PATCH 492/773] change to Kokkos::printf for SYCL compatability --- src/global/utils/error.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/global/utils/error.h b/src/global/utils/error.h index 9d5afed29..078f3a0fe 100644 --- a/src/global/utils/error.h +++ b/src/global/utils/error.h @@ -100,12 +100,12 @@ namespace raise { const char* func, int line, const char* msg) { - printf("\n%s:%d @ %s\nError: %s", file, line, func, msg); + Kokkos::printf("\n%s:%d @ %s\nError: %s", file, line, func, msg); Kokkos::abort("kernel error"); } Inline void KernelNotImplementedError(const char* file, const char* func, int line) { - printf("\n%s:%d @ %s\n", file, line, func); + Kokkos::printf("\n%s:%d @ %s\n", file, line, func); Kokkos::abort("kernel not implemented"); } From a3850ae4635705bbf9b6645ba9bf6e457a2035c0 Mon Sep 17 00:00:00 2001 From: LudwigBoess Date: Fri, 4 Apr 2025 13:59:54 -0500 Subject: [PATCH 493/773] removed virtual functions for SYCL compatability --- src/archetypes/energy_dist.h | 17 +++-------------- src/archetypes/spatial_dist.h | 8 ++------ 2 files changed, 5 insertions(+), 20 deletions(-) diff --git a/src/archetypes/energy_dist.h b/src/archetypes/energy_dist.h index 231ea5b0b..314d54055 100644 --- a/src/archetypes/energy_dist.h +++ b/src/archetypes/energy_dist.h @@ -40,17 +40,6 @@ namespace arch { EnergyDistribution(const M& metric) : metric { metric } {} - // Takes the physical coordinate of the particle and returns - // the velocity in tetrad basis - // last argument -- is the species index (1, ..., nspec) - Inline virtual void operator()(const coord_t&, - vec_t& v, - unsigned short = 0) const { - v[0] = ZERO; - v[1] = ZERO; - v[2] = ZERO; - } - protected: const M metric; }; @@ -61,7 +50,7 @@ namespace arch { Inline void operator()(const coord_t&, vec_t& v, - unsigned short = 0) const override { + unsigned short = 0) const { v[0] = ZERO; v[1] = ZERO; v[2] = ZERO; @@ -85,7 +74,7 @@ namespace arch { Inline void operator()(const coord_t& x_Code, vec_t& v, - unsigned short = 0) const override { + unsigned short = 0) const { auto rand_gen = pool.get_state(); auto rand_X1 = Random(rand_gen); auto rand_gam = ONE; @@ -225,7 +214,7 @@ namespace arch { Inline void operator()(const coord_t& x_Code, vec_t& v, - unsigned short sp = 0) const override { + unsigned short sp = 0) const { if (cmp::AlmostZero(temperature)) { v[0] = ZERO; v[1] = ZERO; diff --git a/src/archetypes/spatial_dist.h b/src/archetypes/spatial_dist.h index d036c0166..d1c874798 100644 --- a/src/archetypes/spatial_dist.h +++ b/src/archetypes/spatial_dist.h @@ -32,10 +32,6 @@ namespace arch { SpatialDistribution(const M& metric) : metric { metric } {} - Inline virtual auto operator()(const coord_t&) const -> real_t { - return ONE; - } - protected: const M metric; }; @@ -44,7 +40,7 @@ namespace arch { struct Uniform : public SpatialDistribution { Uniform(const M& metric) : SpatialDistribution { metric } {} - Inline auto operator()(const coord_t&) const -> real_t override { + Inline auto operator()(const coord_t&) const -> real_t { return ONE; } }; @@ -69,7 +65,7 @@ namespace arch { , target_density { target_density } , target_max_density { target_max_density } {} - Inline auto operator()(const coord_t& x_Ph) const -> real_t override { + Inline auto operator()(const coord_t& x_Ph) const -> real_t { coord_t x_Cd { ZERO }; metric.template convert(x_Ph, x_Cd); real_t dens { ZERO }; From e96a2d38d8bace74a06d170bb3254fadc23b3c3a Mon Sep 17 00:00:00 2001 From: hayk Date: Fri, 4 Apr 2025 15:40:17 -0400 Subject: [PATCH 494/773] conductor in all directions --- src/engines/srpic.hpp | 58 ++++++-- src/kernels/fields_bcs.hpp | 288 ++++++++++++++++++++++++++++++------- 2 files changed, 290 insertions(+), 56 deletions(-) diff --git a/src/engines/srpic.hpp b/src/engines/srpic.hpp index 96747e429..a1228acda 100644 --- a/src/engines/srpic.hpp +++ b/src/engines/srpic.hpp @@ -854,9 +854,6 @@ namespace ntt { } else { const auto sign = direction.get_sign(); const auto dim = direction.get_dim(); - raise::ErrorIf(dim != in::x1, - "Perfect conductor BCs only implemented for x1", - HERE); std::vector xi_min, xi_max; @@ -866,7 +863,7 @@ namespace ntt { const auto dd = all_dirs[d]; if (dim == dd) { xi_min.push_back(0); - xi_max.push_back(N_GHOSTS + 1); + xi_max.push_back((sign < 0) ? (N_GHOSTS + 1) : N_GHOSTS); } else { xi_min.push_back(0); xi_max.push_back(domain.mesh.n_all(dd)); @@ -890,10 +887,55 @@ namespace ntt { raise::Error("Invalid dimension", HERE); } - Kokkos::parallel_for( - "ConductorFields", - range, - kernel::bc::ConductorBoundaries_kernel(domain.fields.em, tags)); + if (dim == in::x1) { + if (sign > 0) { + Kokkos::parallel_for( + "ConductorFields", + range, + kernel::bc::ConductorBoundaries_kernel( + domain.fields.em, + tags)); + } else { + Kokkos::parallel_for( + "ConductorFields", + range, + kernel::bc::ConductorBoundaries_kernel( + domain.fields.em, + tags)); + } + } else if (dim == in::x2) { + if (sign > 0) { + Kokkos::parallel_for( + "ConductorFields", + range, + kernel::bc::ConductorBoundaries_kernel( + domain.fields.em, + tags)); + } else { + Kokkos::parallel_for( + "ConductorFields", + range, + kernel::bc::ConductorBoundaries_kernel( + domain.fields.em, + tags)); + } + } else { + if (sign > 0) { + Kokkos::parallel_for( + "ConductorFields", + range, + kernel::bc::ConductorBoundaries_kernel( + domain.fields.em, + tags)); + } else { + Kokkos::parallel_for( + "ConductorFields", + range, + kernel::bc::ConductorBoundaries_kernel( + domain.fields.em, + tags)); + } + } } } diff --git a/src/kernels/fields_bcs.hpp b/src/kernels/fields_bcs.hpp index b1ee999d3..a69193d42 100644 --- a/src/kernels/fields_bcs.hpp +++ b/src/kernels/fields_bcs.hpp @@ -486,38 +486,52 @@ namespace kernel::bc { } }; - template + template struct ConductorBoundaries_kernel { static_assert(static_cast(o) < static_cast(D), "Invalid component index"); - ndfield_t Fld; - const BCTags tags; + ndfield_t Fld; + const BCTags tags; + const std::size_t i_edge; - ConductorBoundaries_kernel(ndfield_t Fld, BCTags tags) + ConductorBoundaries_kernel(ndfield_t Fld, std::size_t i_edge, BCTags tags) : Fld { Fld } + , i_edge { i_edge } , tags { tags } {} Inline void operator()(index_t i1) const { if constexpr (D == Dim::_1D) { if (tags & BC::E) { if (i1 == 0) { - Fld(N_GHOSTS, em::ex2) = ZERO; - Fld(N_GHOSTS, em::ex3) = ZERO; + Fld(i_edge, em::ex2) = ZERO; + Fld(i_edge, em::ex3) = ZERO; } else { - Fld(N_GHOSTS - i1, em::ex1) = Fld(N_GHOSTS + i1 - 1, em::ex1); - Fld(N_GHOSTS - i1, em::ex2) = -Fld(N_GHOSTS + i1, em::ex2); - Fld(N_GHOSTS - i1, em::ex3) = -Fld(N_GHOSTS + i1, em::ex3); + if constexpr (not P) { + Fld(i_edge - i1, em::ex1) = Fld(i_edge + i1 - 1, em::ex1); + Fld(i_edge - i1, em::ex2) = -Fld(i_edge + i1, em::ex2); + Fld(i_edge - i1, em::ex3) = -Fld(i_edge + i1, em::ex3); + } else { + Fld(i_edge + i1 - 1, em::ex1) = Fld(i_edge - i1, em::ex1); + Fld(i_edge + i1, em::ex2) = -Fld(i_edge - i1, em::ex2); + Fld(i_edge + i1, em::ex3) = -Fld(i_edge - i1, em::ex3); + } } } if (tags & BC::B) { if (i1 == 0) { - Fld(N_GHOSTS, em::bx1) = ZERO; + Fld(i_edge, em::bx1) = ZERO; } else { - Fld(N_GHOSTS - i1, em::bx1) = -Fld(N_GHOSTS + i1, em::bx1); - Fld(N_GHOSTS - i1, em::bx2) = Fld(N_GHOSTS + i1 - 1, em::bx2); - Fld(N_GHOSTS - i1, em::bx3) = Fld(N_GHOSTS + i1 - 1, em::bx3); + if constexpr (not P) { + Fld(i_edge - i1, em::bx1) = -Fld(i_edge + i1, em::bx1); + Fld(i_edge - i1, em::bx2) = Fld(i_edge + i1 - 1, em::bx2); + Fld(i_edge - i1, em::bx3) = Fld(i_edge + i1 - 1, em::bx3); + } else { + Fld(i_edge + i1, em::bx1) = -Fld(i_edge - i1, em::bx1); + Fld(i_edge + i1 - 1, em::bx2) = Fld(i_edge - i1, em::bx2); + Fld(i_edge + i1 - 1, em::bx3) = Fld(i_edge - i1, em::bx3); + } } } } else { @@ -529,24 +543,71 @@ namespace kernel::bc { Inline void operator()(index_t i1, index_t i2) const { if constexpr (D == Dim::_2D) { - if (tags & BC::E) { - if (i1 == 0) { - Fld(N_GHOSTS, i2, em::ex2) = ZERO; - Fld(N_GHOSTS, i2, em::ex3) = ZERO; - } else { - Fld(N_GHOSTS - i1, i2, em::ex1) = Fld(N_GHOSTS + i1 - 1, i2, em::ex1); - Fld(N_GHOSTS - i1, i2, em::ex2) = -Fld(N_GHOSTS + i1, i2, em::ex2); - Fld(N_GHOSTS - i1, i2, em::ex3) = -Fld(N_GHOSTS + i1, i2, em::ex3); + if constexpr (o == in::x1) { + if (tags & BC::E) { + if (i1 == 0) { + Fld(i_edge, i2, em::ex2) = ZERO; + Fld(i_edge, i2, em::ex3) = ZERO; + } else { + if constexpr (not P) { + Fld(i_edge - i1, i2, em::ex1) = Fld(i_edge + i1 - 1, i2, em::ex1); + Fld(i_edge - i1, i2, em::ex2) = -Fld(i_edge + i1, i2, em::ex2); + Fld(i_edge - i1, i2, em::ex3) = -Fld(i_edge + i1, i2, em::ex3); + } else { + Fld(i_edge + i1 - 1, i2, em::ex1) = Fld(i_edge - i1, i2, em::ex1); + Fld(i_edge + i1, i2, em::ex2) = -Fld(i_edge - i1, i2, em::ex2); + Fld(i_edge + i1, i2, em::ex3) = -Fld(i_edge - i1, i2, em::ex3); + } + } } - } - if (tags & BC::B) { - if (i1 == 0) { - Fld(N_GHOSTS, i2, em::bx1) = ZERO; - } else { - Fld(N_GHOSTS - i1, i2, em::bx1) = -Fld(N_GHOSTS + i1, i2, em::bx1); - Fld(N_GHOSTS - i1, i2, em::bx2) = Fld(N_GHOSTS + i1 - 1, i2, em::bx2); - Fld(N_GHOSTS - i1, i2, em::bx3) = Fld(N_GHOSTS + i1 - 1, i2, em::bx3); + if (tags & BC::B) { + if (i1 == 0) { + Fld(i_edge, i2, em::bx1) = ZERO; + } else { + if constexpr (not P) { + Fld(i_edge - i1, i2, em::bx1) = -Fld(i_edge + i1, i2, em::bx1); + Fld(i_edge - i1, i2, em::bx2) = Fld(i_edge + i1 - 1, i2, em::bx2); + Fld(i_edge - i1, i2, em::bx3) = Fld(i_edge + i1 - 1, i2, em::bx3); + } else { + Fld(i_edge + i1, i2, em::bx1) = -Fld(i_edge - i1, i2, em::bx1); + Fld(i_edge + i1 - 1, i2, em::bx2) = Fld(i_edge - i1, i2, em::bx2); + Fld(i_edge + i1 - 1, i2, em::bx3) = Fld(i_edge - i1, i2, em::bx3); + } + } + } + } else { + if (tags & BC::E) { + if (i2 == 0) { + Fld(i1, i_edge, em::ex1) = ZERO; + Fld(i1, i_edge, em::ex3) = ZERO; + } else { + if constexpr (not P) { + Fld(i1, i_edge - i2, em::ex1) = -Fld(i1, i_edge + i2, em::ex1); + Fld(i1, i_edge - i2, em::ex2) = Fld(i1, i_edge + i2 - 1, em::ex2); + Fld(i1, i_edge - i2, em::ex3) = -Fld(i1, i_edge + i2, em::ex3); + } else { + Fld(i1, i_edge + i2, em::ex1) = -Fld(i1, i_edge - i2, em::ex1); + Fld(i1, i_edge + i2 - 1, em::ex2) = Fld(i1, i_edge - i2, em::ex2); + Fld(i1, i_edge + i2, em::ex3) = -Fld(i1, i_edge - i2, em::ex3); + } + } + } + + if (tags & BC::B) { + if (i2 == 0) { + Fld(i1, i_edge, em::bx2) = ZERO; + } else { + if constexpr (not P) { + Fld(i1, i_edge - i2, em::bx1) = Fld(i1, i_edge + i2 - 1, em::bx1); + Fld(i1, i_edge - i2, em::bx2) = -Fld(i1, i_edge + i2, em::bx2); + Fld(i1, i_edge - i2, em::bx3) = Fld(i1, i_edge + i2 - 1, em::bx3); + } else { + Fld(i1, i_edge + i2 - 1, em::bx1) = Fld(i1, i_edge - i2, em::bx1); + Fld(i1, i_edge + i2, em::bx2) = -Fld(i1, i_edge - i2, em::bx2); + Fld(i1, i_edge + i2 - 1, em::bx3) = Fld(i1, i_edge - i2, em::bx3); + } + } } } } else { @@ -558,27 +619,158 @@ namespace kernel::bc { Inline void operator()(index_t i1, index_t i2, index_t i3) const { if constexpr (D == Dim::_3D) { - if (tags & BC::E) { - if (i1 == 0) { - Fld(N_GHOSTS, i2, i3, em::ex2) = ZERO; - Fld(N_GHOSTS, i2, i3, em::ex3) = ZERO; - } else { - Fld(N_GHOSTS - i1, i2, i3, em::ex1) = Fld(N_GHOSTS + i1 - 1, - i2, i3, em::ex1); - Fld(N_GHOSTS - i1, i2, i3, em::ex2) = -Fld(N_GHOSTS + i1, i2, i3, em::ex2); - Fld(N_GHOSTS - i1, i2, i3, em::ex3) = -Fld(N_GHOSTS + i1, i2, i3, em::ex3); + if constexpr (o == in::x1) { + if (tags & BC::E) { + if (i1 == 0) { + Fld(i_edge, i2, i3, em::ex2) = ZERO; + Fld(i_edge, i2, i3, em::ex3) = ZERO; + } else { + if constexpr (not P) { + Fld(i_edge - i1, i2, i3, em::ex1) = Fld(i_edge + i1 - 1, + i2, + i3, + em::ex1); + Fld(i_edge - i1, i2, i3, em::ex2) = -Fld(i_edge + i1, i2, i3, em::ex2); + Fld(i_edge - i1, i2, i3, em::ex3) = -Fld(i_edge + i1, i2, i3, em::ex3); + } else { + Fld(i_edge + i1 - 1, i2, i3, em::ex1) = Fld(i_edge - i1, + i2, + i3, + em::ex1); + Fld(i_edge + i1, i2, i3, em::ex2) = -Fld(i_edge - i1, i2, i3, em::ex2); + Fld(i_edge + i1, i2, i3, em::ex3) = -Fld(i_edge - i1, i2, i3, em::ex3); + } + } } - } - if (tags & BC::B) { - if (i1 == 0) { - Fld(N_GHOSTS, i2, i3, em::bx1) = ZERO; - } else { - Fld(N_GHOSTS - i1, i2, i3, em::bx1) = -Fld(N_GHOSTS + i1, i2, i3, em::bx1); - Fld(N_GHOSTS - i1, i2, i3, em::bx2) = Fld(N_GHOSTS + i1 - 1, - i2, i3, em::bx2); - Fld(N_GHOSTS - i1, i2, i3, em::bx3) = Fld(N_GHOSTS + i1 - 1, - i2, i3, em::bx3); + if (tags & BC::B) { + if (i1 == 0) { + Fld(i_edge, i2, i3, em::bx1) = ZERO; + } else { + if constexpr (not P) { + Fld(i_edge - i1, i2, i3, em::bx1) = -Fld(i_edge + i1, i2, i3, em::bx1); + Fld(i_edge - i1, i2, i3, em::bx2) = Fld(i_edge + i1 - 1, + i2, + i3, + em::bx2); + Fld(i_edge - i1, i2, i3, em::bx3) = Fld(i_edge + i1 - 1, + i2, + i3, + em::bx3); + } else { + Fld(i_edge + i1, i2, i3, em::bx1) = -Fld(i_edge - i1, i2, i3, em::bx1); + Fld(i_edge + i1 - 1, i2, i3, em::bx2) = Fld(i_edge - i1, + i2, + i3, + em::bx2); + Fld(i_edge + i1 - 1, i2, i3, em::bx3) = Fld(i_edge - i1, + i2, + i3, + em::bx3); + } + } + } + } else if (o == in::x2) { + if (tags & BC::E) { + if (i2 == 0) { + Fld(i1, i_edge, i3, em::ex1) = ZERO; + Fld(i1, i_edge, i3, em::ex3) = ZERO; + } else { + if constexpr (not P) { + Fld(i1, i_edge - i2, i3, em::ex1) = -Fld(i1, i_edge + i2, i3, em::ex1); + Fld(i1, i_edge - i2, i3, em::ex2) = Fld(i1, + i_edge + i2 - 1, + i3, + em::ex2); + Fld(i1, i_edge - i2, i3, em::ex3) = -Fld(i1, i_edge + i2, i3, em::ex3); + } else { + Fld(i1, i_edge + i2, i3, em::ex1) = -Fld(i1, i_edge - i2, i3, em::ex1); + Fld(i1, i_edge + i2 - 1, i3, em::ex2) = Fld(i1, + i_edge - i2, + i3, + em::ex2); + Fld(i1, i_edge + i2, i3, em::ex3) = -Fld(i1, i_edge - i2, i3, em::ex3); + } + } + } + + if (tags & BC::B) { + if (i2 == 0) { + Fld(i1, i_edge, i3, em::bx2) = ZERO; + } else { + if constexpr (not P) { + Fld(i1, i_edge - i2, i3, em::bx1) = Fld(i1, + i_edge + i2 - 1, + i3, + em::bx1); + Fld(i1, i_edge - i2, i3, em::bx2) = -Fld(i1, i_edge + i2, i3, em::bx2); + Fld(i1, i_edge - i2, i3, em::bx3) = Fld(i1, + i_edge + i2 - 1, + i3, + em::bx3); + } else { + Fld(i1, i_edge + i2 - 1, i3, em::bx1) = Fld(i1, + i_edge - i2, + i3, + em::bx1); + Fld(i1, i_edge + i2, i3, em::bx2) = -Fld(i1, i_edge - i2, i3, em::bx2); + Fld(i1, i_edge + i2 - 1, i3, em::bx3) = Fld(i1, + i_edge - i2, + i3, + em::bx3); + } + } + } + } else { + if (tags & BC::E) { + if (i3 == 0) { + Fld(i1, i2, i_edge, em::ex1) = ZERO; + Fld(i1, i2, i_edge, em::ex2) = ZERO; + } else { + if constexpr (not P) { + Fld(i1, i2, i_edge - i3, em::ex1) = -Fld(i1, i2, i_edge + i3, em::ex1); + Fld(i1, i2, i_edge - i3, em::ex2) = -Fld(i1, i2, i_edge + i3, em::ex2); + Fld(i1, i2, i_edge - i3, em::ex3) = Fld(i1, + i2, + i_edge + i3 - 1, + em::ex3); + } else { + Fld(i1, i2, i_edge + i3, em::ex1) = -Fld(i1, i2, i_edge - i3, em::ex1); + Fld(i1, i2, i_edge + i3, em::ex2) = -Fld(i1, i2, i_edge - i3, em::ex2); + Fld(i1, i2, i_edge + i3 - 1, em::ex3) = Fld(i1, + i2, + i_edge - i3, + em::ex3); + } + } + } + + if (tags & BC::B) { + if (i3 == 0) { + Fld(i1, i2, i_edge, em::bx3) = ZERO; + } else { + if constexpr (not P) { + Fld(i1, i2, i_edge - i3, em::bx1) = Fld(i1, + i2, + i_edge + i3 - 1, + em::bx1); + Fld(i1, i2, i_edge - i3, em::bx2) = Fld(i1, + i2, + i_edge + i3 - 1, + em::bx2); + Fld(i1, i2, i_edge - i3, em::bx3) = -Fld(i1, i2, i_edge + i3, em::bx3); + } else { + Fld(i1, i2, i_edge + i3 - 1, em::bx1) = Fld(i1, + i2, + i_edge - i3, + em::bx1); + Fld(i1, i2, i_edge + i3 - 1, em::bx2) = Fld(i1, + i2, + i_edge - i3, + em::bx2); + Fld(i1, i2, i_edge + i3, em::bx3) = -Fld(i1, i2, i_edge - i3, em::bx3); + } + } } } } else { From af420129db2c35dd87b9e3ad0ea3a5249a305495 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20B=C3=B6ss?= Date: Fri, 21 Feb 2025 10:43:05 -0600 Subject: [PATCH 495/773] prep for conductor boundaries --- src/global/arch/traits.h | 12 ++++++++++++ src/global/enums.h | 7 ++++--- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/global/arch/traits.h b/src/global/arch/traits.h index 4cde4fca5..65cc63cf8 100644 --- a/src/global/arch/traits.h +++ b/src/global/arch/traits.h @@ -112,6 +112,18 @@ namespace traits { template using fix_fields_const_t = decltype(&T::FixFieldsConst); + template + using perfect_conductor_fields_t = decltype(&T::PerfectConductorFields); + + template + using perfect_conductor_fields_const_t = decltype(&T::PerfectConductorFieldsConst); + + template + using perfect_conductor_currents_t = decltype(&T::PerfectConductorCurrents); + + template + using perfect_conductor_currents_const_t = decltype(&T::PerfectConductorCurrentsConst); + template using custom_fields_t = decltype(&T::CustomFields); diff --git a/src/global/enums.h b/src/global/enums.h index 3afa0497a..8407d0b66 100644 --- a/src/global/enums.h +++ b/src/global/enums.h @@ -222,15 +222,16 @@ namespace ntt { HORIZON = 6, AXIS = 7, SYNC = 8, // <- SYNC means synchronization with other domains + CONDUCTOR = 9 }; constexpr FldsBC(uint8_t c) : enums_hidden::BaseEnum { c } {} - static constexpr type variants[] = { PERIODIC, MATCH, FIXED, ATMOSPHERE, - CUSTOM, HORIZON, AXIS, SYNC }; + static constexpr type variants[] = { PERIODIC, MATCH, FIXED, ATMOSPHERE, + CUSTOM, HORIZON, AXIS, SYNC, CONDUCTOR }; static constexpr const char* lookup[] = { "periodic", "match", "fixed", "atmosphere", "custom", "horizon", - "axis", "sync" }; + "axis", "sync", "conductor"}; static constexpr std::size_t total = sizeof(variants) / sizeof(variants[0]); }; From 7c6ddf46887ee75b87a291a4444c07a06da8691e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20B=C3=B6ss?= Date: Fri, 21 Feb 2025 10:43:32 -0600 Subject: [PATCH 496/773] first stubborn attempt at conductor boundaries (broken) --- setups/srpic/shock/pgen.hpp | 46 +++++++++++++ src/engines/srpic.hpp | 133 ++++++++++++++++++++++++++++++++++++ 2 files changed, 179 insertions(+) diff --git a/setups/srpic/shock/pgen.hpp b/setups/srpic/shock/pgen.hpp index b8f169521..59c5590c9 100644 --- a/setups/srpic/shock/pgen.hpp +++ b/setups/srpic/shock/pgen.hpp @@ -106,6 +106,52 @@ namespace user { } } + + auto PerfectConductorFieldsConst(const bc_in&, const em& comp) const -> real_t{ + + // electric field components + if (comp == em::ex1) { + return ONE; + } else if (comp == em::ex2) { + return -ONE; + } else if (comp == em::ex3) { + return -ONE; } + // magentic field components + else if (comp == em::bx1) { + return -ONE; + } else if (comp == em::bx2) { + return ONE; + } else if (comp == em::bx3) { + return ONE;} + // should never be the case + else + { + return ZERO; + } + } + + // auto PerfectConductorCurrentsConst(const bc_in &, const cur &comp) const + // -> std::pair + // { + // // ToDo + // if (comp == cur::jx1) + // { + // return ZERO; + // } + // else if (comp == cur::jx2) + // { + // return ZERO; + // } + // else if (comp == cur::jx3) + // { + // return ZERO; + // } + // else + // { + // return ZERO; + // } + // } + auto MatchFields(real_t time) const -> InitFields { return init_flds; } diff --git a/src/engines/srpic.hpp b/src/engines/srpic.hpp index 0a9cc311b..c5b48310e 100644 --- a/src/engines/srpic.hpp +++ b/src/engines/srpic.hpp @@ -596,6 +596,10 @@ namespace ntt { if (domain.mesh.flds_bc_in(direction) == FldsBC::FIXED) { FixedFieldsIn(direction, domain, tags); } + } else if (m_metadomain.mesh().flds_bc_in(direction) == FldsBC::CONDUCTOR) { + if (domain.mesh.flds_bc_in(direction) == FldsBC::CONDUCTOR) { + PerfectConductorFieldsIn(direction, domain, tags); + } } else if (m_metadomain.mesh().flds_bc_in(direction) == FldsBC::CUSTOM) { if (domain.mesh.flds_bc_in(direction) == FldsBC::CUSTOM) { CustomFieldsIn(direction, domain, tags); @@ -834,6 +838,135 @@ namespace ntt { } } + void PerfectConductorFieldsIn(dir::direction_t direction, + domain_t& domain, + BCTags tags) { + /** + * perfect conductor field boundaries + */ + const auto sign = direction.get_sign(); + const auto dim = direction.get_dim(); + raise::ErrorIf(dim != in::x1 and M::CoordType != Coord::Cart, + "Perfect conductor BCs only implemented for x1 in " + "non-cartesian coordinates", + HERE); + + // magnetic and electron field components + em normal_b_comp, tang_b_comp1, tang_b_comp2, + normal_e_comp, tang_e_comp1, tang_e_comp2; + + // current components + // cur normal_j_comp, tang_j_comp1, tang_j_comp2; + + if (dim == in::x1) { + normal_b_comp = em::bx1; + tang_b_comp1 = em::bx2; + tang_b_comp2 = em::bx3; + + normal_e_comp = em::ex1; + tang_e_comp1 = em::ex2; + tang_e_comp2 = em::ex3; + } else if (dim == in::x2) { + normal_b_comp = em::bx2; + tang_b_comp1 = em::bx1; + tang_b_comp2 = em::bx3; + + normal_e_comp = em::ex2; + tang_e_comp1 = em::ex1; + tang_e_comp2 = em::ex3; + } else if (dim == in::x3) { + normal_b_comp = em::bx3; + tang_b_comp1 = em::bx1; + tang_b_comp2 = em::bx2; + + normal_e_comp = em::ex3; + tang_e_comp1 = em::ex1; + tang_e_comp2 = em::ex2; + } else { + raise::Error("Invalid dimension", HERE); + } + + std::vector origin_xi_min, origin_xi_max, + target_xi_min, target_xi_max; + const std::vector all_dirs { in::x1, in::x2, in::x3 }; + + for (unsigned short d { 0 }; d < static_cast(M::Dim); ++d) { + const auto dd = all_dirs[d]; + if (dim == dd) { + // origin: right side of boundary + origin_xi_min.push_back(N_GHOSTS+1); + origin_xi_max.push_back(2*N_GHOSTS); + // target: left side of boundary + target_xi_min.push_back(0); + target_xi_max.push_back(N_GHOSTS); + + } else { + origin_xi_min.push_back(0); + origin_xi_max.push_back(domain.mesh.n_all(dd)); + + target_xi_min.push_back(0); + target_xi_max.push_back(domain.mesh.n_all(dd)); + } + } + raise::ErrorIf(target_xi_min.size() != origin_xi_min.size() or + origin_xi_min.size() != static_cast(M::Dim), + "Invalid range size", + HERE); + + std::vector comps; + if (tags & BC::E) { + comps.push_back(normal_e_comp); + comps.push_back(tang_e_comp1); + comps.push_back(tang_e_comp2); + } + if (tags & BC::B) { + comps.push_back(normal_b_comp); + comps.push_back(tang_b_comp1); + comps.push_back(tang_b_comp2); + } + + // ToDo: smarter loop/views + auto EB = domain.fields.em; + + // loop over all components + for (const auto& comp : comps) { + + // store sign of component behind boundary + auto new_sign = m_pgen.PerfectConductorFieldsConst( + (bc_in)(sign * ((short)dim + 1)), + (em)comp); + // to do: Kokkos::parallel_for + for (int i = 0; i < N_GHOSTS; i++) + { + if constexpr (M::Dim == Dim::_1D) { + // multiply with correct sign + EB(target_xi_min[0]+i, comp) = new_sign * EB(origin_xi_max[0]-i, comp); + + } else if constexpr (M::Dim == Dim::_2D) { + for (int j = 0; j < domain.mesh.n_all(in::x2); j++) + { + EB(target_xi_min[0]+i, j, comp) = + new_sign * EB(origin_xi_max[0]-i, j, comp); + } + } else if constexpr (M::Dim == Dim::_3D) { + for (int j = 0; j < domain.mesh.n_all(in::x2); j++) + { + for (int k = 0; k < domain.mesh.n_all(in::x3); k++) + { + EB(target_xi_min[0]+i, j, k, comp) = + new_sign * EB(origin_xi_max[0]-i, j, k, comp); + } + } + } else { + raise::Error("Invalid dimension", HERE); + } + } + + // ToDo: set zero at boundary + } + } + + void AtmosphereFieldsIn(dir::direction_t direction, domain_t& domain, BCTags tags) { From 9333b76b33cc08dbcc5427331ec37b202bda963f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20B=C3=B6ss?= Date: Fri, 21 Feb 2025 16:41:20 -0600 Subject: [PATCH 497/773] first attempt at ConductorBoundaries_kernel --- src/kernels/fields_bcs.hpp | 107 +++++++++++++++++++++++++++++++++++++ 1 file changed, 107 insertions(+) diff --git a/src/kernels/fields_bcs.hpp b/src/kernels/fields_bcs.hpp index dbb47f42c..cadc9cfda 100644 --- a/src/kernels/fields_bcs.hpp +++ b/src/kernels/fields_bcs.hpp @@ -485,6 +485,113 @@ namespace kernel::bc { } }; + template + struct ConductorBoundaries_kernel { + static_assert(M::is_metric, "M must be a metric class"); + static_assert(static_cast(o) < + static_cast(M::Dim), + "Invalid component index"); + static constexpr idx_t i = static_cast(o) + 1u; + + ndfield_t Fld; + const I fset; + const M metric; + const BCTags tags; + + ConductorBoundaries_kernel(ndfield_t Fld, + BCTags tags) + : Fld { Fld } + , tags { tags } {} + + Inline void operator()(index_t i1) const { + if constexpr (M::Dim == Dim::_1D) { + + if constexpr (S == SimEngine::SRPIC) { + + if (tags & BC::E) { + Fld((N_GHOSTS-1)-i1, em::ex1) = Fld(N_GHOSTS+i1, em::ex1); + Fld((N_GHOSTS-1)-i1, em::ex2) = -Fld(N_GHOSTS+i1, em::ex2); + Fld((N_GHOSTS-1)-i1, em::ex3) = -Fld(N_GHOSTS+i1, em::ex3); + } + + if (tags & BC::B) + { + Fld((N_GHOSTS-1)-i1, em::bx1) = -Fld(N_GHOSTS+i1, em::bx1); + Fld((N_GHOSTS-1)-i1, em::bx1) = Fld(N_GHOSTS+i1, em::bx1); + Fld((N_GHOSTS-1)-i1, em::bx1) = Fld(N_GHOSTS+i1, em::bx1); + } + + } else { + // GRPIC + raise::KernelError(HERE, "1D GRPIC not implemented"); + } + } else { + raise::KernelError( + HERE, + "ConductorBoundaries_kernel: 1D implementation called for D != 1"); + } + } + + Inline void operator()(index_t i1, index_t i2) const { + if constexpr (M::Dim == Dim::_2D) { + + if constexpr (S == SimEngine::SRPIC) { + // SRPIC + if (tags & BC::E) { + Fld((N_GHOSTS-1)-i1, i2, em::ex1) = Fld(N_GHOSTS+i1, i2, em::ex1); + Fld((N_GHOSTS-1)-i1, i2, em::ex2) = -Fld(N_GHOSTS+i1, i2, em::ex2); + Fld((N_GHOSTS-1)-i1, i2, em::ex3) = -Fld(N_GHOSTS+i1, i2, em::ex3); + } + + if (tags & BC::B) + { + Fld((N_GHOSTS-1)-i1, i2, em::bx1) = -Fld(N_GHOSTS+i1, i2, em::bx1); + Fld((N_GHOSTS-1)-i1, i2, em::bx2) = Fld(N_GHOSTS+i1, i2, em::bx2); + Fld((N_GHOSTS-1)-i1, i2, em::bx3) = Fld(N_GHOSTS+i1, i2, em::bx3); + } + } else { + // GRPIC + raise::KernelError(HERE, "2D GRPIC not implemented"); + } + } else { + raise::KernelError( + HERE, + "ConductorBoundaries_kernel: 2D implementation called for D != 2"); + } + } + + Inline void operator()(index_t i1, index_t i2, index_t i3) const { + if constexpr (M::Dim == Dim::_3D) { + const auto i1_ = COORD(i1); + const auto i2_ = COORD(i2); + const auto i3_ = COORD(i3); + + if constexpr (S == SimEngine::SRPIC) { + // SRPIC + if (tags & BC::E) { + Fld((N_GHOSTS-1)-i1, i2, i3, em::ex1) = Fld(N_GHOSTS+i1, i2, i3, em::ex1); + Fld((N_GHOSTS-1)-i1, i2, i3, em::ex2) = -Fld(N_GHOSTS+i1, i2, i3, em::ex2); + Fld((N_GHOSTS-1)-i1, i2, i3, em::ex3) = -Fld(N_GHOSTS+i1, i2, i3, em::ex3); + } + + if (tags & BC::B) + { + Fld((N_GHOSTS-1)-i1, i2, i3, em::bx1) = -Fld(N_GHOSTS+i1, i2, i3, em::bx1); + Fld((N_GHOSTS-1)-i1, i2, i3, em::bx2) = Fld(N_GHOSTS+i1, i2, i3, em::bx2); + Fld((N_GHOSTS-1)-i1, i2, i3, em::bx3) = Fld(N_GHOSTS+i1, i2, i3, em::bx3); + } + } else { + // GRPIC + raise::KernelError(HERE, "3D GRPIC not implemented"); + } + } else { + raise::KernelError( + HERE, + "ConductorBoundaries_kernel: 3D implementation called for D != 3"); + } + } + }; + /* * @tparam D: Dimension * @tparam P: Positive/Negative direction From 156507077a91473816ba5b3503c2f4b09bd20a15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20B=C3=B6ss?= Date: Fri, 21 Feb 2025 16:55:21 -0600 Subject: [PATCH 498/773] bugfix --- src/kernels/fields_bcs.hpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/kernels/fields_bcs.hpp b/src/kernels/fields_bcs.hpp index cadc9cfda..95c32d894 100644 --- a/src/kernels/fields_bcs.hpp +++ b/src/kernels/fields_bcs.hpp @@ -485,7 +485,7 @@ namespace kernel::bc { } }; - template + template struct ConductorBoundaries_kernel { static_assert(M::is_metric, "M must be a metric class"); static_assert(static_cast(o) < @@ -494,7 +494,6 @@ namespace kernel::bc { static constexpr idx_t i = static_cast(o) + 1u; ndfield_t Fld; - const I fset; const M metric; const BCTags tags; @@ -562,13 +561,10 @@ namespace kernel::bc { Inline void operator()(index_t i1, index_t i2, index_t i3) const { if constexpr (M::Dim == Dim::_3D) { - const auto i1_ = COORD(i1); - const auto i2_ = COORD(i2); - const auto i3_ = COORD(i3); if constexpr (S == SimEngine::SRPIC) { // SRPIC - if (tags & BC::E) { + if (tags & BC::E) { Fld((N_GHOSTS-1)-i1, i2, i3, em::ex1) = Fld(N_GHOSTS+i1, i2, i3, em::ex1); Fld((N_GHOSTS-1)-i1, i2, i3, em::ex2) = -Fld(N_GHOSTS+i1, i2, i3, em::ex2); Fld((N_GHOSTS-1)-i1, i2, i3, em::ex3) = -Fld(N_GHOSTS+i1, i2, i3, em::ex3); From 6a136fbda06f66448bd2e29791cb46ca18b98948 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20B=C3=B6ss?= Date: Fri, 21 Feb 2025 17:02:04 -0600 Subject: [PATCH 499/773] first attempt at Kokkos::parallel_for loop (broken) --- src/engines/srpic.hpp | 117 ++++++------------------------------------ 1 file changed, 17 insertions(+), 100 deletions(-) diff --git a/src/engines/srpic.hpp b/src/engines/srpic.hpp index c5b48310e..0a2ae360b 100644 --- a/src/engines/srpic.hpp +++ b/src/engines/srpic.hpp @@ -851,122 +851,39 @@ namespace ntt { "non-cartesian coordinates", HERE); - // magnetic and electron field components - em normal_b_comp, tang_b_comp1, tang_b_comp2, - normal_e_comp, tang_e_comp1, tang_e_comp2; - // current components - // cur normal_j_comp, tang_j_comp1, tang_j_comp2; + std::vector xi_min, xi_max; - if (dim == in::x1) { - normal_b_comp = em::bx1; - tang_b_comp1 = em::bx2; - tang_b_comp2 = em::bx3; - - normal_e_comp = em::ex1; - tang_e_comp1 = em::ex2; - tang_e_comp2 = em::ex3; - } else if (dim == in::x2) { - normal_b_comp = em::bx2; - tang_b_comp1 = em::bx1; - tang_b_comp2 = em::bx3; - - normal_e_comp = em::ex2; - tang_e_comp1 = em::ex1; - tang_e_comp2 = em::ex3; - } else if (dim == in::x3) { - normal_b_comp = em::bx3; - tang_b_comp1 = em::bx1; - tang_b_comp2 = em::bx2; - - normal_e_comp = em::ex3; - tang_e_comp1 = em::ex1; - tang_e_comp2 = em::ex2; - } else { - raise::Error("Invalid dimension", HERE); - } - - std::vector origin_xi_min, origin_xi_max, - target_xi_min, target_xi_max; const std::vector all_dirs { in::x1, in::x2, in::x3 }; for (unsigned short d { 0 }; d < static_cast(M::Dim); ++d) { const auto dd = all_dirs[d]; if (dim == dd) { - // origin: right side of boundary - origin_xi_min.push_back(N_GHOSTS+1); - origin_xi_max.push_back(2*N_GHOSTS); - // target: left side of boundary - target_xi_min.push_back(0); - target_xi_max.push_back(N_GHOSTS); - + xi_min.push_back(0); + xi_max.push_back(N_GHOSTS); } else { - origin_xi_min.push_back(0); - origin_xi_max.push_back(domain.mesh.n_all(dd)); - - target_xi_min.push_back(0); - target_xi_max.push_back(domain.mesh.n_all(dd)); + xi_min.push_back(0); + xi_max.push_back(domain.mesh.n_all(dd)); } } - raise::ErrorIf(target_xi_min.size() != origin_xi_min.size() or - origin_xi_min.size() != static_cast(M::Dim), + raise::ErrorIf(xi_min.size() != xi_max.size() or + xi_min.size() != static_cast(M::Dim), "Invalid range size", HERE); - std::vector comps; - if (tags & BC::E) { - comps.push_back(normal_e_comp); - comps.push_back(tang_e_comp1); - comps.push_back(tang_e_comp2); - } - if (tags & BC::B) { - comps.push_back(normal_b_comp); - comps.push_back(tang_b_comp1); - comps.push_back(tang_b_comp2); - } - - // ToDo: smarter loop/views - auto EB = domain.fields.em; - - // loop over all components - for (const auto& comp : comps) { - - // store sign of component behind boundary - auto new_sign = m_pgen.PerfectConductorFieldsConst( - (bc_in)(sign * ((short)dim + 1)), - (em)comp); - // to do: Kokkos::parallel_for - for (int i = 0; i < N_GHOSTS; i++) - { - if constexpr (M::Dim == Dim::_1D) { - // multiply with correct sign - EB(target_xi_min[0]+i, comp) = new_sign * EB(origin_xi_max[0]-i, comp); - - } else if constexpr (M::Dim == Dim::_2D) { - for (int j = 0; j < domain.mesh.n_all(in::x2); j++) - { - EB(target_xi_min[0]+i, j, comp) = - new_sign * EB(origin_xi_max[0]-i, j, comp); - } - } else if constexpr (M::Dim == Dim::_3D) { - for (int j = 0; j < domain.mesh.n_all(in::x2); j++) - { - for (int k = 0; k < domain.mesh.n_all(in::x3); k++) - { - EB(target_xi_min[0]+i, j, k, comp) = - new_sign * EB(origin_xi_max[0]-i, j, k, comp); - } - } - } else { - raise::Error("Invalid dimension", HERE); - } - } - - // ToDo: set zero at boundary + if (dim == in::x1) + { + Kokkos::parallel_for( + "MatchFields", + CreateRangePolicy(xi_min, xi_max), + kernel::bc::ConductorBoundaries_kernel( + domain.fields.em, + tags)); } + + } - void AtmosphereFieldsIn(dir::direction_t direction, domain_t& domain, BCTags tags) { From 861e78345702dd606f9a16161ed78306fd5834ea Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Fri, 21 Feb 2025 22:12:56 -0500 Subject: [PATCH 500/773] Ongoing. --- src/engines/srpic.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/engines/srpic.hpp b/src/engines/srpic.hpp index 0a2ae360b..a317aa7ea 100644 --- a/src/engines/srpic.hpp +++ b/src/engines/srpic.hpp @@ -871,11 +871,11 @@ namespace ntt { "Invalid range size", HERE); - if (dim == in::x1) + if constexpr (M::Dim == Dim::_1D) { { Kokkos::parallel_for( "MatchFields", - CreateRangePolicy(xi_min, xi_max), + CreateRangePolicy(xi_min[0], xi_max[0]), kernel::bc::ConductorBoundaries_kernel( domain.fields.em, tags)); From cd81a5b467bee1ea8379cf90764a78af51ec3006 Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Fri, 21 Feb 2025 22:16:54 -0500 Subject: [PATCH 501/773] Ongoing. --- src/engines/srpic.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engines/srpic.hpp b/src/engines/srpic.hpp index a317aa7ea..9d015aa7e 100644 --- a/src/engines/srpic.hpp +++ b/src/engines/srpic.hpp @@ -871,7 +871,7 @@ namespace ntt { "Invalid range size", HERE); - if constexpr (M::Dim == Dim::_1D) { + if constexpr (M::Dim == Dim::_1D) { Kokkos::parallel_for( "MatchFields", From aec0d414a13ee09f92afc6c701782a265b8c8faf Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Fri, 21 Feb 2025 22:19:01 -0500 Subject: [PATCH 502/773] Ongoing. --- src/engines/srpic.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engines/srpic.hpp b/src/engines/srpic.hpp index 9d015aa7e..c997f026a 100644 --- a/src/engines/srpic.hpp +++ b/src/engines/srpic.hpp @@ -875,7 +875,7 @@ namespace ntt { { Kokkos::parallel_for( "MatchFields", - CreateRangePolicy(xi_min[0], xi_max[0]), + CreateRangePolicy( { xi_min[0] } , { xi_max[0] } ), kernel::bc::ConductorBoundaries_kernel( domain.fields.em, tags)); From 1c7105bb47d3dbcc9eb66d9ea30920d7627fde40 Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Fri, 21 Feb 2025 22:35:06 -0500 Subject: [PATCH 503/773] Ongoing. --- src/engines/srpic.hpp | 2 +- src/kernels/fields_bcs.hpp | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/engines/srpic.hpp b/src/engines/srpic.hpp index c997f026a..4bc16d273 100644 --- a/src/engines/srpic.hpp +++ b/src/engines/srpic.hpp @@ -876,7 +876,7 @@ namespace ntt { Kokkos::parallel_for( "MatchFields", CreateRangePolicy( { xi_min[0] } , { xi_max[0] } ), - kernel::bc::ConductorBoundaries_kernel( + kernel::bc::ConductorBoundaries_kernel( domain.fields.em, tags)); } diff --git a/src/kernels/fields_bcs.hpp b/src/kernels/fields_bcs.hpp index 95c32d894..bb851b45f 100644 --- a/src/kernels/fields_bcs.hpp +++ b/src/kernels/fields_bcs.hpp @@ -494,7 +494,6 @@ namespace kernel::bc { static constexpr idx_t i = static_cast(o) + 1u; ndfield_t Fld; - const M metric; const BCTags tags; ConductorBoundaries_kernel(ndfield_t Fld, From de66f25dc33795fcf7412bce377176e2863d5898 Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Fri, 21 Feb 2025 22:35:54 -0500 Subject: [PATCH 504/773] Ongoing. --- src/engines/srpic.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engines/srpic.hpp b/src/engines/srpic.hpp index 4bc16d273..c997f026a 100644 --- a/src/engines/srpic.hpp +++ b/src/engines/srpic.hpp @@ -876,7 +876,7 @@ namespace ntt { Kokkos::parallel_for( "MatchFields", CreateRangePolicy( { xi_min[0] } , { xi_max[0] } ), - kernel::bc::ConductorBoundaries_kernel( + kernel::bc::ConductorBoundaries_kernel( domain.fields.em, tags)); } From 2f8a01e374665c89d89b7e8deea6e8b235deac32 Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Sat, 22 Feb 2025 11:16:58 -0500 Subject: [PATCH 505/773] Ongoing. --- setups/srpic/shocktest/pgen.hpp | 179 ++++++++++++++++++++++++++++++ setups/srpic/shocktest/shock.py | 75 +++++++++++++ setups/srpic/shocktest/shock.toml | 56 ++++++++++ 3 files changed, 310 insertions(+) create mode 100644 setups/srpic/shocktest/pgen.hpp create mode 100644 setups/srpic/shocktest/shock.py create mode 100644 setups/srpic/shocktest/shock.toml diff --git a/setups/srpic/shocktest/pgen.hpp b/setups/srpic/shocktest/pgen.hpp new file mode 100644 index 000000000..83f19df52 --- /dev/null +++ b/setups/srpic/shocktest/pgen.hpp @@ -0,0 +1,179 @@ +#ifndef PROBLEM_GENERATOR_H +#define PROBLEM_GENERATOR_H + +#include "enums.h" +#include "global.h" + +#include "arch/traits.h" +#include "utils/error.h" +#include "utils/numeric.h" + +#include "archetypes/energy_dist.h" +#include "archetypes/particle_injector.h" +#include "archetypes/problem_generator.h" +#include "framework/domain/metadomain.h" + +#include + +namespace user { + using namespace ntt; + + template + struct InitFields { + /* + Sets up magnetic and electric field components for the simulation. + Must satisfy E = -v x B for Lorentz Force to be zero. + + @param bmag: magnetic field scaling + @param btheta: magnetic field polar angle + @param bphi: magnetic field azimuthal angle + @param drift_ux: drift velocity in the x direction + */ + InitFields(real_t bmag, real_t btheta, real_t bphi, real_t drift_ux) + : Bmag { bmag } + , Btheta { btheta * static_cast(convert::deg2rad) } + , Bphi { bphi * static_cast(convert::deg2rad) } + , Vx { drift_ux } {} + + // magnetic field components + Inline auto bx1(const coord_t& x_Ph) const -> real_t { + return x_Ph[0]; + } + + Inline auto bx2(const coord_t&) const -> real_t { + return x_Ph[0]; + } + + Inline auto bx3(const coord_t&) const -> real_t { + return x_Ph[0]; + } + + // electric field components + Inline auto ex1(const coord_t&) const -> real_t { + return x_Ph[0]; + } + + Inline auto ex2(const coord_t&) const -> real_t { + return x_Ph[0]; + } + + Inline auto ex3(const coord_t&) const -> real_t { + return x_Ph[0]; + } + + private: + const real_t Btheta, Bphi, Vx, Bmag; + }; + + template + struct PGen : public arch::ProblemGenerator { + // compatibility traits for the problem generator + static constexpr auto engines { traits::compatible_with::value }; + static constexpr auto metrics { traits::compatible_with::value }; + static constexpr auto dimensions { + traits::compatible_with::value + }; + + // for easy access to variables in the child class + using arch::ProblemGenerator::D; + using arch::ProblemGenerator::C; + using arch::ProblemGenerator::params; + + const real_t drift_ux, temperature; + + const real_t Btheta, Bphi, Bmag; + InitFields init_flds; + + inline PGen(const SimulationParams& p, const Metadomain& m) + : arch::ProblemGenerator { p } + , drift_ux { p.template get("setup.drift_ux") } + , temperature { p.template get("setup.temperature") } + , Bmag { p.template get("setup.Bmag", ZERO) } + , Btheta { p.template get("setup.Btheta", ZERO) } + , Bphi { p.template get("setup.Bphi", ZERO) } + , init_flds { Bmag, Btheta, Bphi, drift_ux } {} + + inline PGen() {} + + auto FixFieldsConst(const bc_in&, const em& comp) const + -> std::pair { + if (comp == em::ex2) { + return { init_flds.ex2({ ZERO }), true }; + } else if (comp == em::ex3) { + return { init_flds.ex3({ ZERO }), true }; + } else { + return { ZERO, false }; + } + } + + + auto PerfectConductorFieldsConst(const bc_in&, const em& comp) const -> real_t{ + + // electric field components + if (comp == em::ex1) { + return ONE; + } else if (comp == em::ex2) { + return -ONE; + } else if (comp == em::ex3) { + return -ONE; } + // magentic field components + else if (comp == em::bx1) { + return -ONE; + } else if (comp == em::bx2) { + return ONE; + } else if (comp == em::bx3) { + return ONE;} + // should never be the case + else + { + return ZERO; + } + } + + // auto PerfectConductorCurrentsConst(const bc_in &, const cur &comp) const + // -> std::pair + // { + // // ToDo + // if (comp == cur::jx1) + // { + // return ZERO; + // } + // else if (comp == cur::jx2) + // { + // return ZERO; + // } + // else if (comp == cur::jx3) + // { + // return ZERO; + // } + // else + // { + // return ZERO; + // } + // } + + auto MatchFields(real_t time) const -> InitFields { + return init_flds; + } + + inline void InitPrtls(Domain& local_domain) { + const auto energy_dist = arch::Maxwellian(local_domain.mesh.metric, + local_domain.random_pool, + temperature, + -drift_ux, + in::x1); + + const auto injector = arch::UniformInjector( + energy_dist, + { 1, 2 }); + // arch::InjectUniform>( + // params, + // local_domain, + // injector, + // 1.0); + } + }; + +} // namespace user + +#endif diff --git a/setups/srpic/shocktest/shock.py b/setups/srpic/shocktest/shock.py new file mode 100644 index 000000000..dc1565572 --- /dev/null +++ b/setups/srpic/shocktest/shock.py @@ -0,0 +1,75 @@ +import nt2.read as nt2r +import matplotlib.pyplot as plt +import matplotlib as mpl + +data = nt2r.Data("shock.h5") + + +def frame(ti, f): + quantities = [ + { + "name": "density", + "compute": lambda f: f.N_2 + f.N_1, + "cmap": "inferno", + "norm": mpl.colors.Normalize(0, 5), + }, + { + "name": r"$E_x$", + "compute": lambda f: f.Ex, + "cmap": "RdBu_r", + "norm": mpl.colors.Normalize(-0.05, 0.05), + }, + { + "name": r"$E_y$", + "compute": lambda f: f.Ey, + "cmap": "RdBu_r", + "norm": mpl.colors.Normalize(-0.05, 0.05), + }, + { + "name": r"$E_z$", + "compute": lambda f: f.Ez, + "cmap": "RdBu_r", + "norm": mpl.colors.Normalize(-0.05, 0.05), + }, + { + "name": r"$B_x$", + "compute": lambda f: f.Bx, + "cmap": "BrBG", + "norm": mpl.colors.Normalize(-0.05, 0.05), + }, + { + "name": r"$B_y$", + "compute": lambda f: f.By, + "cmap": "BrBG", + "norm": mpl.colors.Normalize(-0.05, 0.05), + }, + { + "name": r"$B_z$", + "compute": lambda f: f.Bz, + "cmap": "BrBG", + "norm": mpl.colors.Normalize(-0.05, 0.05), + }, + ] + fig = plt.figure(figsize=(12, 5.5), dpi=300) + gs = fig.add_gridspec(len(quantities), 1, hspace=0.02) + axs = [fig.add_subplot(gs[i]) for i in range(len(quantities))] + + for ax, q in zip(axs, quantities): + q["compute"](f.isel(t=ti)).plot( + ax=ax, + cmap=q["cmap"], + norm=q["norm"], + cbar_kwargs={"label": q["name"], "shrink": 0.8, "aspect": 10, "pad": 0.005}, + ) + for i, ax in enumerate(axs): + ax.set(aspect=1) + if i != 0: + ax.set(title=None) + if i != len(axs) - 1: + ax.set( + xticks=[], + xticklabels=[], + xlabel=None, + title=ax.get_title().split(",")[0], + ) + return fig diff --git a/setups/srpic/shocktest/shock.toml b/setups/srpic/shocktest/shock.toml new file mode 100644 index 000000000..fdbc44465 --- /dev/null +++ b/setups/srpic/shocktest/shock.toml @@ -0,0 +1,56 @@ +[simulation] + name = "shock" + engine = "srpic" + runtime = 50.0 + +[grid] + resolution = [2048, 128] + extent = [[0.0, 10.0], [-0.3125, 0.3125]] + + [grid.metric] + metric = "minkowski" + + [grid.boundaries] + fields = [["CONDUCTOR", "FIXED"], ["PERIODIC"]] + particles = [["REFLECT", "ABSORB"], ["PERIODIC"]] + +[scales] + larmor0 = 1e-2 + skindepth0 = 1e-2 + +[algorithms] + current_filters = 8 + fieldsolver = "false" + deposit = "false" + + [algorithms.timestep] + CFL = 0.5 + +[particles] + ppc0 = 16.0 + + [[particles.species]] + label = "e-" + mass = 1.0 + charge = -1.0 + maxnpart = 1e8 + + [[particles.species]] + label = "e+" + mass = 1.0 + charge = 1.0 + maxnpart = 1e8 + +[setup] + drift_ux = 0.1 + temperature = 1e-3 + Bmag = 1.0 + Btheta = 0.0 + Bphi = 0.0 + +[output] + interval = 1 + format = "hdf5" + + [output.fields] + quantities = ["N_1", "N_2", "E", "B", "T0i_1", "T0i_2", "J"] From 2c7019b58b1d717e4a126a75382274be29aa63a4 Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Sat, 22 Feb 2025 11:20:28 -0500 Subject: [PATCH 506/773] Ongoing. --- setups/srpic/shocktest/shock.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/setups/srpic/shocktest/shock.toml b/setups/srpic/shocktest/shock.toml index fdbc44465..a77f5c2e9 100644 --- a/setups/srpic/shocktest/shock.toml +++ b/setups/srpic/shocktest/shock.toml @@ -54,3 +54,6 @@ [output.fields] quantities = ["N_1", "N_2", "E", "B", "T0i_1", "T0i_2", "J"] + + [output.debug] + ghosts = true From c0414671c6986b015f589c5832dd83fa7432a1c0 Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Sat, 22 Feb 2025 14:01:06 -0500 Subject: [PATCH 507/773] Ongoing. --- setups/srpic/shocktest/pgen.hpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/setups/srpic/shocktest/pgen.hpp b/setups/srpic/shocktest/pgen.hpp index 83f19df52..7724893a1 100644 --- a/setups/srpic/shocktest/pgen.hpp +++ b/setups/srpic/shocktest/pgen.hpp @@ -40,24 +40,24 @@ namespace user { return x_Ph[0]; } - Inline auto bx2(const coord_t&) const -> real_t { + Inline auto bx2(const coord_t& x_Ph) const -> real_t { return x_Ph[0]; } - Inline auto bx3(const coord_t&) const -> real_t { + Inline auto bx3(const coord_t& x_Ph) const -> real_t { return x_Ph[0]; } // electric field components - Inline auto ex1(const coord_t&) const -> real_t { + Inline auto ex1(const coord_t& x_Ph) const -> real_t { return x_Ph[0]; } - Inline auto ex2(const coord_t&) const -> real_t { + Inline auto ex2(const coord_t& x_Ph) const -> real_t { return x_Ph[0]; } - Inline auto ex3(const coord_t&) const -> real_t { + Inline auto ex3(const coord_t& x_Ph) const -> real_t { return x_Ph[0]; } From b85346ebc97ff7a5f59e17248187e8df71704528 Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Sat, 22 Feb 2025 17:15:38 -0500 Subject: [PATCH 508/773] Ongoing. --- src/kernels/fields_bcs.hpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/kernels/fields_bcs.hpp b/src/kernels/fields_bcs.hpp index bb851b45f..e8993907c 100644 --- a/src/kernels/fields_bcs.hpp +++ b/src/kernels/fields_bcs.hpp @@ -543,9 +543,12 @@ namespace kernel::bc { if (tags & BC::B) { - Fld((N_GHOSTS-1)-i1, i2, em::bx1) = -Fld(N_GHOSTS+i1, i2, em::bx1); - Fld((N_GHOSTS-1)-i1, i2, em::bx2) = Fld(N_GHOSTS+i1, i2, em::bx2); - Fld((N_GHOSTS-1)-i1, i2, em::bx3) = Fld(N_GHOSTS+i1, i2, em::bx3); + // Fld((N_GHOSTS-1)-i1, i2, em::bx1) = -Fld(N_GHOSTS+i1, i2, em::bx1); + // Fld((N_GHOSTS-1)-i1, i2, em::bx2) = Fld(N_GHOSTS+i1, i2, em::bx2); + // Fld((N_GHOSTS-1)-i1, i2, em::bx3) = Fld(N_GHOSTS+i1, i2, em::bx3); + Fld((N_GHOSTS-1)-i1, i2, em::bx1) = 1.0; + Fld((N_GHOSTS-1)-i1, i2, em::bx2) = 2.0; + Fld((N_GHOSTS-1)-i1, i2, em::bx3) = 3.0; } } else { // GRPIC From b51a8bb69e885b2281e1b563254fd293289a7e8a Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Sat, 22 Feb 2025 17:21:07 -0500 Subject: [PATCH 509/773] Ongoing. --- setups/srpic/shocktest/pgen.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setups/srpic/shocktest/pgen.hpp b/setups/srpic/shocktest/pgen.hpp index 7724893a1..0dc91d3e2 100644 --- a/setups/srpic/shocktest/pgen.hpp +++ b/setups/srpic/shocktest/pgen.hpp @@ -41,7 +41,7 @@ namespace user { } Inline auto bx2(const coord_t& x_Ph) const -> real_t { - return x_Ph[0]; + return -x_Ph[0]; } Inline auto bx3(const coord_t& x_Ph) const -> real_t { From f94e0fb79c268a20bfdba1c5d4161142ba5ce17a Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Sat, 22 Feb 2025 18:50:58 -0500 Subject: [PATCH 510/773] Ongoing. --- src/engines/srpic.hpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/engines/srpic.hpp b/src/engines/srpic.hpp index c997f026a..86b85de32 100644 --- a/src/engines/srpic.hpp +++ b/src/engines/srpic.hpp @@ -880,6 +880,16 @@ namespace ntt { domain.fields.em, tags)); } + + if constexpr (M::Dim == Dim::_2D) + { + Kokkos::parallel_for( + "MatchFields", + CreateRangePolicy( { xi_min[0], xi_min[1] } , { xi_max[0], xi_max[1] } ), + kernel::bc::ConductorBoundaries_kernel( + domain.fields.em, + tags)); + } } From 7536825ef6942ff41e85c01abfe9ce7db19c1947 Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Sat, 22 Feb 2025 19:05:19 -0500 Subject: [PATCH 511/773] Ongoing. --- src/kernels/fields_bcs.hpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/kernels/fields_bcs.hpp b/src/kernels/fields_bcs.hpp index e8993907c..c85115f12 100644 --- a/src/kernels/fields_bcs.hpp +++ b/src/kernels/fields_bcs.hpp @@ -543,12 +543,12 @@ namespace kernel::bc { if (tags & BC::B) { - // Fld((N_GHOSTS-1)-i1, i2, em::bx1) = -Fld(N_GHOSTS+i1, i2, em::bx1); - // Fld((N_GHOSTS-1)-i1, i2, em::bx2) = Fld(N_GHOSTS+i1, i2, em::bx2); - // Fld((N_GHOSTS-1)-i1, i2, em::bx3) = Fld(N_GHOSTS+i1, i2, em::bx3); - Fld((N_GHOSTS-1)-i1, i2, em::bx1) = 1.0; - Fld((N_GHOSTS-1)-i1, i2, em::bx2) = 2.0; - Fld((N_GHOSTS-1)-i1, i2, em::bx3) = 3.0; + Fld((N_GHOSTS-1)-i1, i2, em::bx1) = Fld(N_GHOSTS+i1, i2, em::bx1); + Fld((N_GHOSTS-1)-i1, i2, em::bx2) = Fld(N_GHOSTS+i1, i2, em::bx2); + Fld((N_GHOSTS-1)-i1, i2, em::bx3) = Fld(N_GHOSTS+i1, i2, em::bx3); + // Fld((N_GHOSTS-1)-i1, i2, em::bx1) = 1.0; + // Fld((N_GHOSTS-1)-i1, i2, em::bx2) = 2.0; + // Fld((N_GHOSTS-1)-i1, i2, em::bx3) = 3.0; } } else { // GRPIC From f313624b9171651d79eb888435106edfba028000 Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Sat, 22 Feb 2025 19:10:18 -0500 Subject: [PATCH 512/773] Ongoing. --- src/kernels/fields_bcs.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/kernels/fields_bcs.hpp b/src/kernels/fields_bcs.hpp index c85115f12..da6e88dbd 100644 --- a/src/kernels/fields_bcs.hpp +++ b/src/kernels/fields_bcs.hpp @@ -543,9 +543,9 @@ namespace kernel::bc { if (tags & BC::B) { - Fld((N_GHOSTS-1)-i1, i2, em::bx1) = Fld(N_GHOSTS+i1, i2, em::bx1); - Fld((N_GHOSTS-1)-i1, i2, em::bx2) = Fld(N_GHOSTS+i1, i2, em::bx2); - Fld((N_GHOSTS-1)-i1, i2, em::bx3) = Fld(N_GHOSTS+i1, i2, em::bx3); + Fld((N_GHOSTS-1)-i1, i2, em::bx1) = - Fld(N_GHOSTS+i1, i2, em::bx1); + Fld((N_GHOSTS-1)-i1, i2, em::bx2) = - Fld(N_GHOSTS+i1, i2, em::bx2); + Fld((N_GHOSTS-1)-i1, i2, em::bx3) = - Fld(N_GHOSTS+i1, i2, em::bx3); // Fld((N_GHOSTS-1)-i1, i2, em::bx1) = 1.0; // Fld((N_GHOSTS-1)-i1, i2, em::bx2) = 2.0; // Fld((N_GHOSTS-1)-i1, i2, em::bx3) = 3.0; From dd6056edef8e71ed274ea78879028d03a07ec4d7 Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Sat, 22 Feb 2025 20:01:27 -0500 Subject: [PATCH 513/773] Ongoing. --- src/kernels/fields_bcs.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/kernels/fields_bcs.hpp b/src/kernels/fields_bcs.hpp index da6e88dbd..58e5af4b4 100644 --- a/src/kernels/fields_bcs.hpp +++ b/src/kernels/fields_bcs.hpp @@ -543,9 +543,9 @@ namespace kernel::bc { if (tags & BC::B) { - Fld((N_GHOSTS-1)-i1, i2, em::bx1) = - Fld(N_GHOSTS+i1, i2, em::bx1); - Fld((N_GHOSTS-1)-i1, i2, em::bx2) = - Fld(N_GHOSTS+i1, i2, em::bx2); - Fld((N_GHOSTS-1)-i1, i2, em::bx3) = - Fld(N_GHOSTS+i1, i2, em::bx3); + Fld((N_GHOSTS)-i1, i2, em::bx1) = - Fld(N_GHOSTS+1+i1, i2, em::bx1); + Fld((N_GHOSTS)-i1, i2, em::bx2) = - Fld(N_GHOSTS+1+i1, i2, em::bx2); + Fld((N_GHOSTS)-i1, i2, em::bx3) = - Fld(N_GHOSTS+1+i1, i2, em::bx3); // Fld((N_GHOSTS-1)-i1, i2, em::bx1) = 1.0; // Fld((N_GHOSTS-1)-i1, i2, em::bx2) = 2.0; // Fld((N_GHOSTS-1)-i1, i2, em::bx3) = 3.0; From 67a6a191ec16043c14e5079da2942b2f431e446b Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Sat, 22 Feb 2025 20:54:37 -0500 Subject: [PATCH 514/773] Ongoing. --- src/kernels/fields_bcs.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/kernels/fields_bcs.hpp b/src/kernels/fields_bcs.hpp index 58e5af4b4..da6e88dbd 100644 --- a/src/kernels/fields_bcs.hpp +++ b/src/kernels/fields_bcs.hpp @@ -543,9 +543,9 @@ namespace kernel::bc { if (tags & BC::B) { - Fld((N_GHOSTS)-i1, i2, em::bx1) = - Fld(N_GHOSTS+1+i1, i2, em::bx1); - Fld((N_GHOSTS)-i1, i2, em::bx2) = - Fld(N_GHOSTS+1+i1, i2, em::bx2); - Fld((N_GHOSTS)-i1, i2, em::bx3) = - Fld(N_GHOSTS+1+i1, i2, em::bx3); + Fld((N_GHOSTS-1)-i1, i2, em::bx1) = - Fld(N_GHOSTS+i1, i2, em::bx1); + Fld((N_GHOSTS-1)-i1, i2, em::bx2) = - Fld(N_GHOSTS+i1, i2, em::bx2); + Fld((N_GHOSTS-1)-i1, i2, em::bx3) = - Fld(N_GHOSTS+i1, i2, em::bx3); // Fld((N_GHOSTS-1)-i1, i2, em::bx1) = 1.0; // Fld((N_GHOSTS-1)-i1, i2, em::bx2) = 2.0; // Fld((N_GHOSTS-1)-i1, i2, em::bx3) = 3.0; From 679d0374d52ea2a1d56cffb4fe8d72514ed1c4de Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Sat, 22 Feb 2025 21:02:54 -0500 Subject: [PATCH 515/773] Ongoing. --- src/kernels/fields_bcs.hpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/kernels/fields_bcs.hpp b/src/kernels/fields_bcs.hpp index da6e88dbd..31cc55268 100644 --- a/src/kernels/fields_bcs.hpp +++ b/src/kernels/fields_bcs.hpp @@ -543,12 +543,12 @@ namespace kernel::bc { if (tags & BC::B) { - Fld((N_GHOSTS-1)-i1, i2, em::bx1) = - Fld(N_GHOSTS+i1, i2, em::bx1); - Fld((N_GHOSTS-1)-i1, i2, em::bx2) = - Fld(N_GHOSTS+i1, i2, em::bx2); - Fld((N_GHOSTS-1)-i1, i2, em::bx3) = - Fld(N_GHOSTS+i1, i2, em::bx3); - // Fld((N_GHOSTS-1)-i1, i2, em::bx1) = 1.0; - // Fld((N_GHOSTS-1)-i1, i2, em::bx2) = 2.0; - // Fld((N_GHOSTS-1)-i1, i2, em::bx3) = 3.0; + // Fld((N_GHOSTS-1)-i1, i2, em::bx1) = - Fld(N_GHOSTS+i1, i2, em::bx1); + // Fld((N_GHOSTS-1)-i1, i2, em::bx2) = - Fld(N_GHOSTS+i1, i2, em::bx2); + // Fld((N_GHOSTS-1)-i1, i2, em::bx3) = - Fld(N_GHOSTS+i1, i2, em::bx3); + Fld((N_GHOSTS-1)-i1, i2, em::bx1) = 1.0; + Fld((N_GHOSTS-1)-i1, i2, em::bx2) = 2.0; + Fld((N_GHOSTS-1)-i1, i2, em::bx3) = 3.0; } } else { // GRPIC From 80043ef77450790525d694ffe204b826fabf3f0a Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Sat, 22 Feb 2025 21:13:50 -0500 Subject: [PATCH 516/773] Ongoing. --- src/kernels/fields_bcs.hpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/kernels/fields_bcs.hpp b/src/kernels/fields_bcs.hpp index 31cc55268..0c6d0782c 100644 --- a/src/kernels/fields_bcs.hpp +++ b/src/kernels/fields_bcs.hpp @@ -543,12 +543,12 @@ namespace kernel::bc { if (tags & BC::B) { - // Fld((N_GHOSTS-1)-i1, i2, em::bx1) = - Fld(N_GHOSTS+i1, i2, em::bx1); - // Fld((N_GHOSTS-1)-i1, i2, em::bx2) = - Fld(N_GHOSTS+i1, i2, em::bx2); - // Fld((N_GHOSTS-1)-i1, i2, em::bx3) = - Fld(N_GHOSTS+i1, i2, em::bx3); - Fld((N_GHOSTS-1)-i1, i2, em::bx1) = 1.0; - Fld((N_GHOSTS-1)-i1, i2, em::bx2) = 2.0; - Fld((N_GHOSTS-1)-i1, i2, em::bx3) = 3.0; + Fld((N_GHOSTS-1)-i1, i2, em::bx1) = - Fld(N_GHOSTS+1+i1, i2, em::bx1); + Fld((N_GHOSTS-1)-i1, i2, em::bx2) = - Fld(N_GHOSTS+i1, i2, em::bx2); + Fld((N_GHOSTS-1)-i1, i2, em::bx3) = - Fld(N_GHOSTS+i1, i2, em::bx3); + // Fld((N_GHOSTS-1)-i1, i2, em::bx1) = 1.0; + // Fld((N_GHOSTS-1)-i1, i2, em::bx2) = 2.0; + // Fld((N_GHOSTS-1)-i1, i2, em::bx3) = 3.0; } } else { // GRPIC From aff570eec4c46872be891aa87a02d972d0235973 Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Sat, 22 Feb 2025 21:43:02 -0500 Subject: [PATCH 517/773] Ongoing. --- setups/srpic/shocktest/pgen.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setups/srpic/shocktest/pgen.hpp b/setups/srpic/shocktest/pgen.hpp index 0dc91d3e2..685521f09 100644 --- a/setups/srpic/shocktest/pgen.hpp +++ b/setups/srpic/shocktest/pgen.hpp @@ -45,7 +45,7 @@ namespace user { } Inline auto bx3(const coord_t& x_Ph) const -> real_t { - return x_Ph[0]; + return ONE; } // electric field components From 6d4eb13bed081dd157c0527e65ef3461572f7ec9 Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Sat, 22 Feb 2025 22:06:25 -0500 Subject: [PATCH 518/773] Ongoing. --- setups/srpic/shocktest/pgen.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setups/srpic/shocktest/pgen.hpp b/setups/srpic/shocktest/pgen.hpp index 685521f09..0dc91d3e2 100644 --- a/setups/srpic/shocktest/pgen.hpp +++ b/setups/srpic/shocktest/pgen.hpp @@ -45,7 +45,7 @@ namespace user { } Inline auto bx3(const coord_t& x_Ph) const -> real_t { - return ONE; + return x_Ph[0]; } // electric field components From c3aa545c58fb323651a03999298131fd28fc94b0 Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Sat, 22 Feb 2025 22:16:17 -0500 Subject: [PATCH 519/773] Ongoing. --- setups/srpic/shocktest/pgen.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/setups/srpic/shocktest/pgen.hpp b/setups/srpic/shocktest/pgen.hpp index 0dc91d3e2..f8bf67dab 100644 --- a/setups/srpic/shocktest/pgen.hpp +++ b/setups/srpic/shocktest/pgen.hpp @@ -37,7 +37,7 @@ namespace user { // magnetic field components Inline auto bx1(const coord_t& x_Ph) const -> real_t { - return x_Ph[0]; + return ZERO; } Inline auto bx2(const coord_t& x_Ph) const -> real_t { @@ -50,15 +50,15 @@ namespace user { // electric field components Inline auto ex1(const coord_t& x_Ph) const -> real_t { - return x_Ph[0]; + return ZERO; } Inline auto ex2(const coord_t& x_Ph) const -> real_t { - return x_Ph[0]; + return ZERO; } Inline auto ex3(const coord_t& x_Ph) const -> real_t { - return x_Ph[0]; + return ZERO; } private: From f5d9bec2182ded70cee21ec9db214f74c2f75951 Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Sat, 22 Feb 2025 22:34:56 -0500 Subject: [PATCH 520/773] Ongoing. --- setups/srpic/shocktest/pgen.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setups/srpic/shocktest/pgen.hpp b/setups/srpic/shocktest/pgen.hpp index f8bf67dab..39ce8ea03 100644 --- a/setups/srpic/shocktest/pgen.hpp +++ b/setups/srpic/shocktest/pgen.hpp @@ -45,7 +45,7 @@ namespace user { } Inline auto bx3(const coord_t& x_Ph) const -> real_t { - return x_Ph[0]; + return -x_Ph[0]; } // electric field components From 2c2d595947601bba212ea37432f911ff304089e2 Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Sat, 22 Feb 2025 22:58:19 -0500 Subject: [PATCH 521/773] Ongoing. --- src/kernels/fields_bcs.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/kernels/fields_bcs.hpp b/src/kernels/fields_bcs.hpp index 0c6d0782c..7f9a054a5 100644 --- a/src/kernels/fields_bcs.hpp +++ b/src/kernels/fields_bcs.hpp @@ -536,9 +536,9 @@ namespace kernel::bc { if constexpr (S == SimEngine::SRPIC) { // SRPIC if (tags & BC::E) { - Fld((N_GHOSTS-1)-i1, i2, em::ex1) = Fld(N_GHOSTS+i1, i2, em::ex1); - Fld((N_GHOSTS-1)-i1, i2, em::ex2) = -Fld(N_GHOSTS+i1, i2, em::ex2); - Fld((N_GHOSTS-1)-i1, i2, em::ex3) = -Fld(N_GHOSTS+i1, i2, em::ex3); + Fld((N_GHOSTS-1)-i1, i2, em::ex1) = - Fld(N_GHOSTS+i1, i2, em::ex1); + Fld((N_GHOSTS-1)-i1, i2, em::ex2) = - Fld(N_GHOSTS+1+i1, i2, em::ex2); + Fld((N_GHOSTS-1)-i1, i2, em::ex3) = - Fld(N_GHOSTS+1+i1, i2, em::ex3); } if (tags & BC::B) From 54b02223075e7bb01204c31e76967e96a9aed182 Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Tue, 25 Feb 2025 23:51:36 -0500 Subject: [PATCH 522/773] Ongoing. --- setups/srpic/shocktest/pgen.hpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/setups/srpic/shocktest/pgen.hpp b/setups/srpic/shocktest/pgen.hpp index 39ce8ea03..2cb66539f 100644 --- a/setups/srpic/shocktest/pgen.hpp +++ b/setups/srpic/shocktest/pgen.hpp @@ -36,16 +36,16 @@ namespace user { , Vx { drift_ux } {} // magnetic field components - Inline auto bx1(const coord_t& x_Ph) const -> real_t { - return ZERO; + Inline auto bx1(const coord_t&) const -> real_t { + return Bmag * math::cos(Btheta); } - Inline auto bx2(const coord_t& x_Ph) const -> real_t { - return -x_Ph[0]; + Inline auto bx2(const coord_t&) const -> real_t { + return Bmag * math::sin(Btheta) * math::sin(Bphi); } - Inline auto bx3(const coord_t& x_Ph) const -> real_t { - return -x_Ph[0]; + Inline auto bx3(const coord_t&) const -> real_t { + return Bmag * math::sin(Btheta) * math::cos(Bphi); } // electric field components From e023e37ff798d0838d09d343b9fde596e1bd2056 Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Tue, 25 Feb 2025 23:59:44 -0500 Subject: [PATCH 523/773] Ongoing. --- setups/srpic/shocktest/pgen.hpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/setups/srpic/shocktest/pgen.hpp b/setups/srpic/shocktest/pgen.hpp index 2cb66539f..b77583ccb 100644 --- a/setups/srpic/shocktest/pgen.hpp +++ b/setups/srpic/shocktest/pgen.hpp @@ -49,16 +49,16 @@ namespace user { } // electric field components - Inline auto ex1(const coord_t& x_Ph) const -> real_t { + Inline auto ex1(const coord_t&) const -> real_t { return ZERO; } - Inline auto ex2(const coord_t& x_Ph) const -> real_t { - return ZERO; + Inline auto ex2(const coord_t&) const -> real_t { + return -Vx * Bmag * math::sin(Btheta) * math::cos(Bphi); } - Inline auto ex3(const coord_t& x_Ph) const -> real_t { - return ZERO; + Inline auto ex3(const coord_t&) const -> real_t { + return Vx * Bmag * math::sin(Btheta) * math::sin(Bphi); } private: From 42549067c3744a0c43aef401c5c09f821ed0b344 Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Thu, 27 Feb 2025 11:42:46 -0500 Subject: [PATCH 524/773] Ongoing. --- setups/srpic/shocktest/pgen.hpp | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/setups/srpic/shocktest/pgen.hpp b/setups/srpic/shocktest/pgen.hpp index b77583ccb..f92086528 100644 --- a/setups/srpic/shocktest/pgen.hpp +++ b/setups/srpic/shocktest/pgen.hpp @@ -36,29 +36,34 @@ namespace user { , Vx { drift_ux } {} // magnetic field components - Inline auto bx1(const coord_t&) const -> real_t { - return Bmag * math::cos(Btheta); + Inline auto bx1(const coord_t& x_ph) const -> real_t { + // return Bmag * math::cos(Btheta); + return ZERO; } - Inline auto bx2(const coord_t&) const -> real_t { - return Bmag * math::sin(Btheta) * math::sin(Bphi); + Inline auto bx2(const coord_t& x_ph) const -> real_t { + // return Bmag * math::sin(Btheta) * math::sin(Bphi); + return ZERO; } - Inline auto bx3(const coord_t&) const -> real_t { - return Bmag * math::sin(Btheta) * math::cos(Bphi); + Inline auto bx3(const coord_t& x_ph) const -> real_t { + // return Bmag * math::sin(Btheta) * math::cos(Bphi); + return ONE + 0.01 * (ONE - math::tanh(20.*(-1.5 + x))*math::tanh(20.*(-0.5 + x)))/2.0 * math::sin(4.0 * constant::PI * x_ph[0]); } // electric field components - Inline auto ex1(const coord_t&) const -> real_t { + Inline auto ex1(const coord_t& x_ph) const -> real_t { return ZERO; } - Inline auto ex2(const coord_t&) const -> real_t { - return -Vx * Bmag * math::sin(Btheta) * math::cos(Bphi); + Inline auto ex2(const coord_t& x_ph) const -> real_t { + // return -Vx * Bmag * math::sin(Btheta) * math::cos(Bphi); + return ZERO + 0.01 * (ONE - math::tanh(20.*(-1.5 + x))*math::tanh(20.*(-0.5 + x)))/2.0 * math::sin(4.0 * constant::PI * x_ph[0]); } - Inline auto ex3(const coord_t&) const -> real_t { - return Vx * Bmag * math::sin(Btheta) * math::sin(Bphi); + Inline auto ex3(const coord_t& x_ph) const -> real_t { + // return Vx * Bmag * math::sin(Btheta) * math::sin(Bphi); + return ZERO; } private: From 20ae9a4f73aef85be0c8ce588d17cb1e562ed8e3 Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Thu, 27 Feb 2025 12:01:42 -0500 Subject: [PATCH 525/773] Ongoing. --- setups/srpic/shocktest/pgen.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setups/srpic/shocktest/pgen.hpp b/setups/srpic/shocktest/pgen.hpp index f92086528..c43688d02 100644 --- a/setups/srpic/shocktest/pgen.hpp +++ b/setups/srpic/shocktest/pgen.hpp @@ -48,7 +48,7 @@ namespace user { Inline auto bx3(const coord_t& x_ph) const -> real_t { // return Bmag * math::sin(Btheta) * math::cos(Bphi); - return ONE + 0.01 * (ONE - math::tanh(20.*(-1.5 + x))*math::tanh(20.*(-0.5 + x)))/2.0 * math::sin(4.0 * constant::PI * x_ph[0]); + return ONE + 0.01 * (ONE - math::tanh(20.*(-1.5 + x_ph[0]))*math::tanh(20.*(-0.5 + x_ph[0])))/2.0 * math::sin(4.0 * constant::PI * x_ph[0]); } // electric field components @@ -58,7 +58,7 @@ namespace user { Inline auto ex2(const coord_t& x_ph) const -> real_t { // return -Vx * Bmag * math::sin(Btheta) * math::cos(Bphi); - return ZERO + 0.01 * (ONE - math::tanh(20.*(-1.5 + x))*math::tanh(20.*(-0.5 + x)))/2.0 * math::sin(4.0 * constant::PI * x_ph[0]); + return ZERO + 0.01 * (ONE - math::tanh(20.*(-1.5 + x_ph[0]))*math::tanh(20.*(-0.5 + x_ph[0])))/2.0 * math::sin(4.0 * constant::PI * x_ph[0]); } Inline auto ex3(const coord_t& x_ph) const -> real_t { From 9facba71628d0b8295b06710ac8d6519c606652d Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Thu, 27 Feb 2025 13:13:12 -0500 Subject: [PATCH 526/773] Ongoing. --- src/kernels/fields_bcs.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/kernels/fields_bcs.hpp b/src/kernels/fields_bcs.hpp index 7f9a054a5..77497114c 100644 --- a/src/kernels/fields_bcs.hpp +++ b/src/kernels/fields_bcs.hpp @@ -536,7 +536,7 @@ namespace kernel::bc { if constexpr (S == SimEngine::SRPIC) { // SRPIC if (tags & BC::E) { - Fld((N_GHOSTS-1)-i1, i2, em::ex1) = - Fld(N_GHOSTS+i1, i2, em::ex1); + Fld((N_GHOSTS-1)-i1, i2, em::ex1) = Fld(N_GHOSTS+i1, i2, em::ex1); Fld((N_GHOSTS-1)-i1, i2, em::ex2) = - Fld(N_GHOSTS+1+i1, i2, em::ex2); Fld((N_GHOSTS-1)-i1, i2, em::ex3) = - Fld(N_GHOSTS+1+i1, i2, em::ex3); } @@ -544,8 +544,8 @@ namespace kernel::bc { if (tags & BC::B) { Fld((N_GHOSTS-1)-i1, i2, em::bx1) = - Fld(N_GHOSTS+1+i1, i2, em::bx1); - Fld((N_GHOSTS-1)-i1, i2, em::bx2) = - Fld(N_GHOSTS+i1, i2, em::bx2); - Fld((N_GHOSTS-1)-i1, i2, em::bx3) = - Fld(N_GHOSTS+i1, i2, em::bx3); + Fld((N_GHOSTS-1)-i1, i2, em::bx2) = Fld(N_GHOSTS+i1, i2, em::bx2); + Fld((N_GHOSTS-1)-i1, i2, em::bx3) = Fld(N_GHOSTS+i1, i2, em::bx3); // Fld((N_GHOSTS-1)-i1, i2, em::bx1) = 1.0; // Fld((N_GHOSTS-1)-i1, i2, em::bx2) = 2.0; // Fld((N_GHOSTS-1)-i1, i2, em::bx3) = 3.0; From 8f0e72c1bacd22ba022645bd8de1052ed6c8af92 Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Thu, 27 Feb 2025 13:18:43 -0500 Subject: [PATCH 527/773] Ongoing. --- setups/srpic/shocktest/pgen.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setups/srpic/shocktest/pgen.hpp b/setups/srpic/shocktest/pgen.hpp index c43688d02..10d4c6b59 100644 --- a/setups/srpic/shocktest/pgen.hpp +++ b/setups/srpic/shocktest/pgen.hpp @@ -58,7 +58,7 @@ namespace user { Inline auto ex2(const coord_t& x_ph) const -> real_t { // return -Vx * Bmag * math::sin(Btheta) * math::cos(Bphi); - return ZERO + 0.01 * (ONE - math::tanh(20.*(-1.5 + x_ph[0]))*math::tanh(20.*(-0.5 + x_ph[0])))/2.0 * math::sin(4.0 * constant::PI * x_ph[0]); + return ZERO - 0.01 * (ONE - math::tanh(20.*(-1.5 + x_ph[0]))*math::tanh(20.*(-0.5 + x_ph[0])))/2.0 * math::sin(4.0 * constant::PI * x_ph[0]); } Inline auto ex3(const coord_t& x_ph) const -> real_t { From cedf47a613ee4eb2e5edb31ccdbba9d36c54cad5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20B=C3=B6ss?= Date: Thu, 27 Feb 2025 18:04:22 -0600 Subject: [PATCH 528/773] first attempt at single particle injection --- setups/srpic/shocktest/pgen.hpp | 164 ++++++++++++++++++++------------ src/kernels/fields_bcs.hpp | 27 +++--- 2 files changed, 116 insertions(+), 75 deletions(-) diff --git a/setups/srpic/shocktest/pgen.hpp b/setups/srpic/shocktest/pgen.hpp index 10d4c6b59..4d4b1cb37 100644 --- a/setups/srpic/shocktest/pgen.hpp +++ b/setups/srpic/shocktest/pgen.hpp @@ -111,72 +111,116 @@ namespace user { } } - - auto PerfectConductorFieldsConst(const bc_in&, const em& comp) const -> real_t{ - - // electric field components - if (comp == em::ex1) { - return ONE; - } else if (comp == em::ex2) { - return -ONE; - } else if (comp == em::ex3) { - return -ONE; } - // magentic field components - else if (comp == em::bx1) { - return -ONE; - } else if (comp == em::bx2) { - return ONE; - } else if (comp == em::bx3) { - return ONE;} - // should never be the case - else - { - return ZERO; - } - } - - // auto PerfectConductorCurrentsConst(const bc_in &, const cur &comp) const - // -> std::pair - // { - // // ToDo - // if (comp == cur::jx1) - // { - // return ZERO; - // } - // else if (comp == cur::jx2) - // { - // return ZERO; - // } - // else if (comp == cur::jx3) - // { - // return ZERO; - // } - // else - // { - // return ZERO; - // } - // } auto MatchFields(real_t time) const -> InitFields { return init_flds; } - inline void InitPrtls(Domain& local_domain) { - const auto energy_dist = arch::Maxwellian(local_domain.mesh.metric, - local_domain.random_pool, - temperature, - -drift_ux, - in::x1); - - const auto injector = arch::UniformInjector( - energy_dist, - { 1, 2 }); - // arch::InjectUniform>( - // params, - // local_domain, - // injector, - // 1.0); + inline void InitPrtls(Domain& domain) { + + auto& species_e = domain.species[0]; + auto& species_p = domain.species[1]; + auto metric = domain.mesh.metric; + auto m = domain.mesh.metric; + + array_t elec_ind("elec_ind"); + array_t pos_ind("pos_ind"); + + auto offset_e = species_e.npart(); + auto offset_p = species_p.npart(); + + auto ux1_e = species_e.ux1; + auto ux2_e = species_e.ux2; + auto ux3_e = species_e.ux3; + auto i1_e = species_e.i1; + auto i2_e = species_e.i2; + auto dx1_e = species_e.dx1; + auto dx2_e = species_e.dx2; + auto phi_e = species_e.phi; + auto weight_e = species_e.weight; + auto tag_e = species_e.tag; + + auto ux1_p = species_p.ux1; + auto ux2_p = species_p.ux2; + auto ux3_p = species_p.ux3; + auto i1_p = species_p.i1; + auto i2_p = species_p.i2; + auto dx1_p = species_p.dx1; + auto dx2_p = species_p.dx2; + auto phi_p = species_p.phi; + auto weight_p = species_p.weight; + auto tag_p = species_p.tag; + + int nseed = 1; + auto dseed = HALF * constant::PI / static_cast(nseed); + + Kokkos::parallel_for("init_particles", nseed, KOKKOS_LAMBDA(const int& s) { + + // ToDo: fix this + auto i1_ = ONE; + auto i2_ = ONE; + auto dx1_ = ONE - HALF; + auto dx2_ = ONE - HALF; + + + auto elec_p = Kokkos::atomic_fetch_add(&elec_ind(), 1); + auto pos_p = Kokkos::atomic_fetch_add(&pos_ind(), 1); + + i1_e(elec_p + offset_e) = i1_; + dx1_e(elec_p + offset_e) = dx1_; + i2_e(elec_p + offset_e) = i2_; + dx2_e(elec_p + offset_e) = dx2_; + phi_e(elec_p + offset_e) = ZERO; + ux1_e(elec_p + offset_e) = -drift_ux; + ux2_e(elec_p + offset_e) = -drift_ux; + ux3_e(elec_p + offset_e) = ZERO; + weight_e(elec_p + offset_e) = ONE; + tag_e(elec_p + offset_e) = ParticleTag::alive; + + i1_p(pos_p + offset_p) = i1_; + dx1_p(pos_p + offset_p) = dx1_; + i2_p(pos_p + offset_p) = i2_; + dx2_p(pos_p + offset_p) = dx2_; + phi_p(pos_p + offset_p) = ZERO; + ux1_p(pos_p + offset_p) = -drift_ux; + ux2_p(pos_p + offset_p) = drift_ux; + ux3_p(pos_p + offset_p) = ZERO; + weight_p(pos_p + offset_p) = ONE; + tag_p(pos_p + offset_p) = ParticleTag::alive; + + + }); + + + auto elec_ind_h = Kokkos::create_mirror(elec_ind); + Kokkos::deep_copy(elec_ind_h, elec_ind); + species_e.set_npart(offset_e + elec_ind_h()); + + auto pos_ind_h = Kokkos::create_mirror(pos_ind); + Kokkos::deep_copy(pos_ind_h, pos_ind); + species_p.set_npart(offset_p + pos_ind_h()); + + } + + + // inline void InitPrtls(Domain& local_domain) { + // const auto energy_dist = arch::Maxwellian(local_domain.mesh.metric, + // local_domain.random_pool, + // temperature, + // -drift_ux, + // in::x1); + + // const auto injector = arch::UniformInjector( + // energy_dist, + // { 1, 2 }); + // arch::InjectUniform>( + // params, + // local_domain, + // injector, + // 1.0); + // } + }; } // namespace user diff --git a/src/kernels/fields_bcs.hpp b/src/kernels/fields_bcs.hpp index 77497114c..e3fe4f2ba 100644 --- a/src/kernels/fields_bcs.hpp +++ b/src/kernels/fields_bcs.hpp @@ -506,19 +506,19 @@ namespace kernel::bc { if constexpr (S == SimEngine::SRPIC) { - if (tags & BC::E) { - Fld((N_GHOSTS-1)-i1, em::ex1) = Fld(N_GHOSTS+i1, em::ex1); - Fld((N_GHOSTS-1)-i1, em::ex2) = -Fld(N_GHOSTS+i1, em::ex2); - Fld((N_GHOSTS-1)-i1, em::ex3) = -Fld(N_GHOSTS+i1, em::ex3); - } - - if (tags & BC::B) - { - Fld((N_GHOSTS-1)-i1, em::bx1) = -Fld(N_GHOSTS+i1, em::bx1); - Fld((N_GHOSTS-1)-i1, em::bx1) = Fld(N_GHOSTS+i1, em::bx1); - Fld((N_GHOSTS-1)-i1, em::bx1) = Fld(N_GHOSTS+i1, em::bx1); - } + if (tags & BC::E) + { + Fld((N_GHOSTS - 1) - i1, em::ex1) = Fld(N_GHOSTS + i1, em::ex1); + Fld((N_GHOSTS - 1) - i1, em::ex2) = -Fld(N_GHOSTS + 1 + i1, em::ex2); + Fld((N_GHOSTS - 1) - i1, em::ex3) = -Fld(N_GHOSTS + 1 + i1, em::ex3); + } + if (tags & BC::B) + { + Fld((N_GHOSTS - 1) - i1, em::bx1) = -Fld(N_GHOSTS + 1 + i1, em::bx1); + Fld((N_GHOSTS - 1) - i1, em::bx2) = Fld(N_GHOSTS + i1, em::bx2); + Fld((N_GHOSTS - 1) - i1, em::bx3) = Fld(N_GHOSTS + i1, em::bx3); + } } else { // GRPIC raise::KernelError(HERE, "1D GRPIC not implemented"); @@ -546,9 +546,6 @@ namespace kernel::bc { Fld((N_GHOSTS-1)-i1, i2, em::bx1) = - Fld(N_GHOSTS+1+i1, i2, em::bx1); Fld((N_GHOSTS-1)-i1, i2, em::bx2) = Fld(N_GHOSTS+i1, i2, em::bx2); Fld((N_GHOSTS-1)-i1, i2, em::bx3) = Fld(N_GHOSTS+i1, i2, em::bx3); - // Fld((N_GHOSTS-1)-i1, i2, em::bx1) = 1.0; - // Fld((N_GHOSTS-1)-i1, i2, em::bx2) = 2.0; - // Fld((N_GHOSTS-1)-i1, i2, em::bx3) = 3.0; } } else { // GRPIC From 77dc646323348d720c9e8348c458aba78808b58e Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Fri, 28 Feb 2025 07:44:22 -0500 Subject: [PATCH 529/773] Ongoing. --- setups/srpic/shocktest/pgen.hpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/setups/srpic/shocktest/pgen.hpp b/setups/srpic/shocktest/pgen.hpp index 4d4b1cb37..14c2006e9 100644 --- a/setups/srpic/shocktest/pgen.hpp +++ b/setups/srpic/shocktest/pgen.hpp @@ -48,7 +48,8 @@ namespace user { Inline auto bx3(const coord_t& x_ph) const -> real_t { // return Bmag * math::sin(Btheta) * math::cos(Bphi); - return ONE + 0.01 * (ONE - math::tanh(20.*(-1.5 + x_ph[0]))*math::tanh(20.*(-0.5 + x_ph[0])))/2.0 * math::sin(4.0 * constant::PI * x_ph[0]); + // return ONE + 0.01 * (ONE - math::tanh(20.*(-1.5 + x_ph[0]))*math::tanh(20.*(-0.5 + x_ph[0])))/2.0 * math::sin(4.0 * constant::PI * x_ph[0]); + return ZERO; } // electric field components @@ -58,7 +59,8 @@ namespace user { Inline auto ex2(const coord_t& x_ph) const -> real_t { // return -Vx * Bmag * math::sin(Btheta) * math::cos(Bphi); - return ZERO - 0.01 * (ONE - math::tanh(20.*(-1.5 + x_ph[0]))*math::tanh(20.*(-0.5 + x_ph[0])))/2.0 * math::sin(4.0 * constant::PI * x_ph[0]); + // return ZERO - 0.01 * (ONE - math::tanh(20.*(-1.5 + x_ph[0]))*math::tanh(20.*(-0.5 + x_ph[0])))/2.0 * math::sin(4.0 * constant::PI * x_ph[0]); + return ZERO; } Inline auto ex3(const coord_t& x_ph) const -> real_t { @@ -120,8 +122,6 @@ namespace user { auto& species_e = domain.species[0]; auto& species_p = domain.species[1]; - auto metric = domain.mesh.metric; - auto m = domain.mesh.metric; array_t elec_ind("elec_ind"); array_t pos_ind("pos_ind"); @@ -152,15 +152,14 @@ namespace user { auto tag_p = species_p.tag; int nseed = 1; - auto dseed = HALF * constant::PI / static_cast(nseed); Kokkos::parallel_for("init_particles", nseed, KOKKOS_LAMBDA(const int& s) { // ToDo: fix this auto i1_ = ONE; auto i2_ = ONE; - auto dx1_ = ONE - HALF; - auto dx2_ = ONE - HALF; + auto dx1_ = HALF; + auto dx2_ = HALF; auto elec_p = Kokkos::atomic_fetch_add(&elec_ind(), 1); From afc0fe976718d89ca5e8b7dbbfd630410564ebe1 Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Fri, 28 Feb 2025 07:47:32 -0500 Subject: [PATCH 530/773] Ongoing. --- setups/srpic/shocktest/pgen.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setups/srpic/shocktest/pgen.hpp b/setups/srpic/shocktest/pgen.hpp index 14c2006e9..85d08214a 100644 --- a/setups/srpic/shocktest/pgen.hpp +++ b/setups/srpic/shocktest/pgen.hpp @@ -156,8 +156,8 @@ namespace user { Kokkos::parallel_for("init_particles", nseed, KOKKOS_LAMBDA(const int& s) { // ToDo: fix this - auto i1_ = ONE; - auto i2_ = ONE; + auto i1_ = 100; + auto i2_ = 100; auto dx1_ = HALF; auto dx2_ = HALF; From c6a01f8546df922a91afccd662075e704a2436e8 Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Fri, 28 Feb 2025 09:42:48 -0500 Subject: [PATCH 531/773] Ongoing. --- setups/srpic/shocktest/pgen.hpp | 90 ++++++++++++++++----------------- 1 file changed, 45 insertions(+), 45 deletions(-) diff --git a/setups/srpic/shocktest/pgen.hpp b/setups/srpic/shocktest/pgen.hpp index 85d08214a..b682cd621 100644 --- a/setups/srpic/shocktest/pgen.hpp +++ b/setups/srpic/shocktest/pgen.hpp @@ -153,51 +153,51 @@ namespace user { int nseed = 1; - Kokkos::parallel_for("init_particles", nseed, KOKKOS_LAMBDA(const int& s) { - - // ToDo: fix this - auto i1_ = 100; - auto i2_ = 100; - auto dx1_ = HALF; - auto dx2_ = HALF; - - - auto elec_p = Kokkos::atomic_fetch_add(&elec_ind(), 1); - auto pos_p = Kokkos::atomic_fetch_add(&pos_ind(), 1); - - i1_e(elec_p + offset_e) = i1_; - dx1_e(elec_p + offset_e) = dx1_; - i2_e(elec_p + offset_e) = i2_; - dx2_e(elec_p + offset_e) = dx2_; - phi_e(elec_p + offset_e) = ZERO; - ux1_e(elec_p + offset_e) = -drift_ux; - ux2_e(elec_p + offset_e) = -drift_ux; - ux3_e(elec_p + offset_e) = ZERO; - weight_e(elec_p + offset_e) = ONE; - tag_e(elec_p + offset_e) = ParticleTag::alive; - - i1_p(pos_p + offset_p) = i1_; - dx1_p(pos_p + offset_p) = dx1_; - i2_p(pos_p + offset_p) = i2_; - dx2_p(pos_p + offset_p) = dx2_; - phi_p(pos_p + offset_p) = ZERO; - ux1_p(pos_p + offset_p) = -drift_ux; - ux2_p(pos_p + offset_p) = drift_ux; - ux3_p(pos_p + offset_p) = ZERO; - weight_p(pos_p + offset_p) = ONE; - tag_p(pos_p + offset_p) = ParticleTag::alive; - - - }); - - - auto elec_ind_h = Kokkos::create_mirror(elec_ind); - Kokkos::deep_copy(elec_ind_h, elec_ind); - species_e.set_npart(offset_e + elec_ind_h()); - - auto pos_ind_h = Kokkos::create_mirror(pos_ind); - Kokkos::deep_copy(pos_ind_h, pos_ind); - species_p.set_npart(offset_p + pos_ind_h()); + // Kokkos::parallel_for("init_particles", nseed, KOKKOS_LAMBDA(const int& s) { + + // // ToDo: fix this + // auto i1_ = 100; + // auto i2_ = 100; + // auto dx1_ = HALF; + // auto dx2_ = HALF; + + + // auto elec_p = Kokkos::atomic_fetch_add(&elec_ind(), 1); + // auto pos_p = Kokkos::atomic_fetch_add(&pos_ind(), 1); + + // i1_e(elec_p + offset_e) = i1_; + // dx1_e(elec_p + offset_e) = dx1_; + // i2_e(elec_p + offset_e) = i2_; + // dx2_e(elec_p + offset_e) = dx2_; + // phi_e(elec_p + offset_e) = ZERO; + // ux1_e(elec_p + offset_e) = -drift_ux; + // ux2_e(elec_p + offset_e) = -drift_ux; + // ux3_e(elec_p + offset_e) = ZERO; + // weight_e(elec_p + offset_e) = ONE; + // tag_e(elec_p + offset_e) = ParticleTag::alive; + + // i1_p(pos_p + offset_p) = i1_; + // dx1_p(pos_p + offset_p) = dx1_; + // i2_p(pos_p + offset_p) = i2_; + // dx2_p(pos_p + offset_p) = dx2_; + // phi_p(pos_p + offset_p) = ZERO; + // ux1_p(pos_p + offset_p) = -drift_ux; + // ux2_p(pos_p + offset_p) = drift_ux; + // ux3_p(pos_p + offset_p) = ZERO; + // weight_p(pos_p + offset_p) = ONE; + // tag_p(pos_p + offset_p) = ParticleTag::alive; + + + // }); + + + // auto elec_ind_h = Kokkos::create_mirror(elec_ind); + // Kokkos::deep_copy(elec_ind_h, elec_ind); + // species_e.set_npart(offset_e + elec_ind_h()); + + // auto pos_ind_h = Kokkos::create_mirror(pos_ind); + // Kokkos::deep_copy(pos_ind_h, pos_ind); + // species_p.set_npart(offset_p + pos_ind_h()); } From 4f3d261f6bb7e40544f97bddc6753059ddeac54b Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Fri, 28 Feb 2025 09:51:22 -0500 Subject: [PATCH 532/773] Ongoing. --- setups/srpic/shocktest/pgen.hpp | 70 ++++++++++++++++----------------- 1 file changed, 34 insertions(+), 36 deletions(-) diff --git a/setups/srpic/shocktest/pgen.hpp b/setups/srpic/shocktest/pgen.hpp index b682cd621..f74e45080 100644 --- a/setups/srpic/shocktest/pgen.hpp +++ b/setups/srpic/shocktest/pgen.hpp @@ -151,53 +151,51 @@ namespace user { auto weight_p = species_p.weight; auto tag_p = species_p.tag; - int nseed = 1; + int nseed = 10; - // Kokkos::parallel_for("init_particles", nseed, KOKKOS_LAMBDA(const int& s) { + Kokkos::parallel_for("init_particles", nseed, KOKKOS_LAMBDA(const int& s) { - // // ToDo: fix this - // auto i1_ = 100; - // auto i2_ = 100; - // auto dx1_ = HALF; - // auto dx2_ = HALF; + // ToDo: fix this + auto i1_ = math::floor(100); + auto i2_ = math::floor(64); + auto dx1_ = HALF; + auto dx2_ = HALF; - // auto elec_p = Kokkos::atomic_fetch_add(&elec_ind(), 1); - // auto pos_p = Kokkos::atomic_fetch_add(&pos_ind(), 1); + auto elec_p = Kokkos::atomic_fetch_add(&elec_ind(), 1); + auto pos_p = Kokkos::atomic_fetch_add(&pos_ind(), 1); - // i1_e(elec_p + offset_e) = i1_; - // dx1_e(elec_p + offset_e) = dx1_; - // i2_e(elec_p + offset_e) = i2_; - // dx2_e(elec_p + offset_e) = dx2_; - // phi_e(elec_p + offset_e) = ZERO; - // ux1_e(elec_p + offset_e) = -drift_ux; - // ux2_e(elec_p + offset_e) = -drift_ux; - // ux3_e(elec_p + offset_e) = ZERO; - // weight_e(elec_p + offset_e) = ONE; - // tag_e(elec_p + offset_e) = ParticleTag::alive; + i1_e(elec_p + offset_e) = i1_; + dx1_e(elec_p + offset_e) = dx1_; + i2_e(elec_p + offset_e) = i2_; + dx2_e(elec_p + offset_e) = dx2_; + ux1_e(elec_p + offset_e) = ZERO; + ux2_e(elec_p + offset_e) = ZERO; + ux3_e(elec_p + offset_e) = ZERO; + weight_e(elec_p + offset_e) = ONE; + tag_e(elec_p + offset_e) = ParticleTag::alive; - // i1_p(pos_p + offset_p) = i1_; - // dx1_p(pos_p + offset_p) = dx1_; - // i2_p(pos_p + offset_p) = i2_; - // dx2_p(pos_p + offset_p) = dx2_; - // phi_p(pos_p + offset_p) = ZERO; - // ux1_p(pos_p + offset_p) = -drift_ux; - // ux2_p(pos_p + offset_p) = drift_ux; - // ux3_p(pos_p + offset_p) = ZERO; - // weight_p(pos_p + offset_p) = ONE; - // tag_p(pos_p + offset_p) = ParticleTag::alive; + i1_p(pos_p + offset_p) = i1_; + dx1_p(pos_p + offset_p) = dx1_; + i2_p(pos_p + offset_p) = i2_; + dx2_p(pos_p + offset_p) = dx2_; + ux1_p(pos_p + offset_p) = ZERO; + ux2_p(pos_p + offset_p) = ZERO; + ux3_p(pos_p + offset_p) = ZERO; + weight_p(pos_p + offset_p) = ONE; + tag_p(pos_p + offset_p) = ParticleTag::alive; - // }); + }); - // auto elec_ind_h = Kokkos::create_mirror(elec_ind); - // Kokkos::deep_copy(elec_ind_h, elec_ind); - // species_e.set_npart(offset_e + elec_ind_h()); + auto elec_ind_h = Kokkos::create_mirror(elec_ind); + Kokkos::deep_copy(elec_ind_h, elec_ind); + species_e.set_npart(offset_e + elec_ind_h()); - // auto pos_ind_h = Kokkos::create_mirror(pos_ind); - // Kokkos::deep_copy(pos_ind_h, pos_ind); - // species_p.set_npart(offset_p + pos_ind_h()); + auto pos_ind_h = Kokkos::create_mirror(pos_ind); + Kokkos::deep_copy(pos_ind_h, pos_ind); + species_p.set_npart(offset_p + pos_ind_h()); } From bec35fd8c64cbb39a78252410646a566ec9a5118 Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Fri, 28 Feb 2025 09:56:29 -0500 Subject: [PATCH 533/773] Ongoing. --- setups/srpic/shocktest/pgen.hpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/setups/srpic/shocktest/pgen.hpp b/setups/srpic/shocktest/pgen.hpp index f74e45080..a835b7990 100644 --- a/setups/srpic/shocktest/pgen.hpp +++ b/setups/srpic/shocktest/pgen.hpp @@ -151,7 +151,7 @@ namespace user { auto weight_p = species_p.weight; auto tag_p = species_p.tag; - int nseed = 10; + int nseed = 1; Kokkos::parallel_for("init_particles", nseed, KOKKOS_LAMBDA(const int& s) { @@ -169,8 +169,8 @@ namespace user { dx1_e(elec_p + offset_e) = dx1_; i2_e(elec_p + offset_e) = i2_; dx2_e(elec_p + offset_e) = dx2_; - ux1_e(elec_p + offset_e) = ZERO; - ux2_e(elec_p + offset_e) = ZERO; + ux1_e(elec_p + offset_e) = -drift_ux; + ux2_e(elec_p + offset_e) = drift_ux; ux3_e(elec_p + offset_e) = ZERO; weight_e(elec_p + offset_e) = ONE; tag_e(elec_p + offset_e) = ParticleTag::alive; @@ -179,8 +179,8 @@ namespace user { dx1_p(pos_p + offset_p) = dx1_; i2_p(pos_p + offset_p) = i2_; dx2_p(pos_p + offset_p) = dx2_; - ux1_p(pos_p + offset_p) = ZERO; - ux2_p(pos_p + offset_p) = ZERO; + ux1_p(pos_p + offset_p) = -drift_ux; + ux2_p(pos_p + offset_p) = drift_ux; ux3_p(pos_p + offset_p) = ZERO; weight_p(pos_p + offset_p) = ONE; tag_p(pos_p + offset_p) = ParticleTag::alive; From 400feb03cd2482abae63bf20ba3fe00916ab553b Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Fri, 28 Feb 2025 09:58:00 -0500 Subject: [PATCH 534/773] Ongoing. --- setups/srpic/shocktest/pgen.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/setups/srpic/shocktest/pgen.hpp b/setups/srpic/shocktest/pgen.hpp index a835b7990..9711646e3 100644 --- a/setups/srpic/shocktest/pgen.hpp +++ b/setups/srpic/shocktest/pgen.hpp @@ -169,8 +169,8 @@ namespace user { dx1_e(elec_p + offset_e) = dx1_; i2_e(elec_p + offset_e) = i2_; dx2_e(elec_p + offset_e) = dx2_; - ux1_e(elec_p + offset_e) = -drift_ux; - ux2_e(elec_p + offset_e) = drift_ux; + ux1_e(elec_p + offset_e) = -0.5; + ux2_e(elec_p + offset_e) = 0.5; ux3_e(elec_p + offset_e) = ZERO; weight_e(elec_p + offset_e) = ONE; tag_e(elec_p + offset_e) = ParticleTag::alive; @@ -179,8 +179,8 @@ namespace user { dx1_p(pos_p + offset_p) = dx1_; i2_p(pos_p + offset_p) = i2_; dx2_p(pos_p + offset_p) = dx2_; - ux1_p(pos_p + offset_p) = -drift_ux; - ux2_p(pos_p + offset_p) = drift_ux; + ux1_p(pos_p + offset_p) = -0.5; + ux2_p(pos_p + offset_p) = 0.5; ux3_p(pos_p + offset_p) = ZERO; weight_p(pos_p + offset_p) = ONE; tag_p(pos_p + offset_p) = ParticleTag::alive; From 906d2766a8a21e24b438967151f1f2115f701a7c Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Fri, 28 Feb 2025 11:05:00 -0500 Subject: [PATCH 535/773] Ongoing. --- setups/srpic/shocktest/pgen.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setups/srpic/shocktest/pgen.hpp b/setups/srpic/shocktest/pgen.hpp index 9711646e3..4cf89ac69 100644 --- a/setups/srpic/shocktest/pgen.hpp +++ b/setups/srpic/shocktest/pgen.hpp @@ -156,7 +156,7 @@ namespace user { Kokkos::parallel_for("init_particles", nseed, KOKKOS_LAMBDA(const int& s) { // ToDo: fix this - auto i1_ = math::floor(100); + auto i1_ = math::floor(10); auto i2_ = math::floor(64); auto dx1_ = HALF; auto dx2_ = HALF; From 8bf2718953707cab4241aa152cc1b1734beb9659 Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Fri, 28 Feb 2025 11:18:31 -0500 Subject: [PATCH 536/773] Ongoing. --- setups/srpic/shocktest/pgen.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setups/srpic/shocktest/pgen.hpp b/setups/srpic/shocktest/pgen.hpp index 4cf89ac69..a1ce9a1a9 100644 --- a/setups/srpic/shocktest/pgen.hpp +++ b/setups/srpic/shocktest/pgen.hpp @@ -179,8 +179,8 @@ namespace user { dx1_p(pos_p + offset_p) = dx1_; i2_p(pos_p + offset_p) = i2_; dx2_p(pos_p + offset_p) = dx2_; - ux1_p(pos_p + offset_p) = -0.5; - ux2_p(pos_p + offset_p) = 0.5; + ux1_p(pos_p + offset_p) = 0.5; + ux2_p(pos_p + offset_p) = -0.5; ux3_p(pos_p + offset_p) = ZERO; weight_p(pos_p + offset_p) = ONE; tag_p(pos_p + offset_p) = ParticleTag::alive; From 5534983abaf90b99e7f076ac7ad80815e78cd67f Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Fri, 28 Feb 2025 13:20:21 -0500 Subject: [PATCH 537/773] Ongoing. --- src/kernels/fields_bcs.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/kernels/fields_bcs.hpp b/src/kernels/fields_bcs.hpp index e3fe4f2ba..6f157c4aa 100644 --- a/src/kernels/fields_bcs.hpp +++ b/src/kernels/fields_bcs.hpp @@ -537,13 +537,13 @@ namespace kernel::bc { // SRPIC if (tags & BC::E) { Fld((N_GHOSTS-1)-i1, i2, em::ex1) = Fld(N_GHOSTS+i1, i2, em::ex1); - Fld((N_GHOSTS-1)-i1, i2, em::ex2) = - Fld(N_GHOSTS+1+i1, i2, em::ex2); - Fld((N_GHOSTS-1)-i1, i2, em::ex3) = - Fld(N_GHOSTS+1+i1, i2, em::ex3); + Fld((N_GHOSTS-1)-i1, i2, em::ex2) = - Fld(N_GHOSTS+i1, i2, em::ex2); + Fld((N_GHOSTS-1)-i1, i2, em::ex3) = - Fld(N_GHOSTS+i1, i2, em::ex3); } if (tags & BC::B) { - Fld((N_GHOSTS-1)-i1, i2, em::bx1) = - Fld(N_GHOSTS+1+i1, i2, em::bx1); + Fld((N_GHOSTS-1)-i1, i2, em::bx1) = - Fld(N_GHOSTS+i1, i2, em::bx1); Fld((N_GHOSTS-1)-i1, i2, em::bx2) = Fld(N_GHOSTS+i1, i2, em::bx2); Fld((N_GHOSTS-1)-i1, i2, em::bx3) = Fld(N_GHOSTS+i1, i2, em::bx3); } From 1a60a7aa64c26fd14984788c68268b7ca9ce46d0 Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Fri, 28 Feb 2025 13:34:59 -0500 Subject: [PATCH 538/773] Ongoing. --- src/kernels/fields_bcs.hpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/kernels/fields_bcs.hpp b/src/kernels/fields_bcs.hpp index 6f157c4aa..12dbe45ed 100644 --- a/src/kernels/fields_bcs.hpp +++ b/src/kernels/fields_bcs.hpp @@ -536,16 +536,19 @@ namespace kernel::bc { if constexpr (S == SimEngine::SRPIC) { // SRPIC if (tags & BC::E) { - Fld((N_GHOSTS-1)-i1, i2, em::ex1) = Fld(N_GHOSTS+i1, i2, em::ex1); - Fld((N_GHOSTS-1)-i1, i2, em::ex2) = - Fld(N_GHOSTS+i1, i2, em::ex2); - Fld((N_GHOSTS-1)-i1, i2, em::ex3) = - Fld(N_GHOSTS+i1, i2, em::ex3); + // Fld((N_GHOSTS-1)-i1, i2, em::ex1) = Fld(N_GHOSTS+i1, i2, em::ex1); + // Fld((N_GHOSTS-1)-i1, i2, em::ex2) = - Fld(N_GHOSTS+1+i1, i2, em::ex2); + // Fld((N_GHOSTS-1)-i1, i2, em::ex3) = - Fld(N_GHOSTS+1+i1, i2, em::ex3); + Fld((N_GHOSTS-1)-i1, i2, em::ex1) = ZERO; + Fld((N_GHOSTS-1)-i1, i2, em::ex2) = ZERO; + Fld((N_GHOSTS-1)-i1, i2, em::ex3) = ZERO; } if (tags & BC::B) { - Fld((N_GHOSTS-1)-i1, i2, em::bx1) = - Fld(N_GHOSTS+i1, i2, em::bx1); - Fld((N_GHOSTS-1)-i1, i2, em::bx2) = Fld(N_GHOSTS+i1, i2, em::bx2); - Fld((N_GHOSTS-1)-i1, i2, em::bx3) = Fld(N_GHOSTS+i1, i2, em::bx3); + Fld((N_GHOSTS-1)-i1, i2, em::bx1) = ZERO; + Fld((N_GHOSTS-1)-i1, i2, em::bx2) = ZERO; + Fld((N_GHOSTS-1)-i1, i2, em::bx3) = ZERO; } } else { // GRPIC From d50abcdbef8bcf9949aa5c7564745f21f6e231e6 Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Fri, 28 Feb 2025 13:36:55 -0500 Subject: [PATCH 539/773] Ongoing. --- src/kernels/fields_bcs.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/kernels/fields_bcs.hpp b/src/kernels/fields_bcs.hpp index 12dbe45ed..def4668c6 100644 --- a/src/kernels/fields_bcs.hpp +++ b/src/kernels/fields_bcs.hpp @@ -542,6 +542,8 @@ namespace kernel::bc { Fld((N_GHOSTS-1)-i1, i2, em::ex1) = ZERO; Fld((N_GHOSTS-1)-i1, i2, em::ex2) = ZERO; Fld((N_GHOSTS-1)-i1, i2, em::ex3) = ZERO; + Fld((N_GHOSTS), i2, em::ex2) = ZERO; + Fld((N_GHOSTS), i2, em::ex3) = ZERO; } if (tags & BC::B) From fbdfb920b2df113f5c380ad55f31e30bf4d21d93 Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Fri, 28 Feb 2025 14:53:48 -0500 Subject: [PATCH 540/773] Ongoing. --- setups/srpic/shocktest/pgen.hpp | 156 ++++++++++++++++---------------- 1 file changed, 78 insertions(+), 78 deletions(-) diff --git a/setups/srpic/shocktest/pgen.hpp b/setups/srpic/shocktest/pgen.hpp index a1ce9a1a9..1b8926c67 100644 --- a/setups/srpic/shocktest/pgen.hpp +++ b/setups/srpic/shocktest/pgen.hpp @@ -48,8 +48,8 @@ namespace user { Inline auto bx3(const coord_t& x_ph) const -> real_t { // return Bmag * math::sin(Btheta) * math::cos(Bphi); - // return ONE + 0.01 * (ONE - math::tanh(20.*(-1.5 + x_ph[0]))*math::tanh(20.*(-0.5 + x_ph[0])))/2.0 * math::sin(4.0 * constant::PI * x_ph[0]); - return ZERO; + return ONE + 0.01 * (ONE - math::tanh(20.*(-1.5 + x_ph[0]))*math::tanh(20.*(-0.5 + x_ph[0])))/2.0 * math::sin(4.0 * constant::PI * x_ph[0]); + // return ZERO; } // electric field components @@ -59,8 +59,8 @@ namespace user { Inline auto ex2(const coord_t& x_ph) const -> real_t { // return -Vx * Bmag * math::sin(Btheta) * math::cos(Bphi); - // return ZERO - 0.01 * (ONE - math::tanh(20.*(-1.5 + x_ph[0]))*math::tanh(20.*(-0.5 + x_ph[0])))/2.0 * math::sin(4.0 * constant::PI * x_ph[0]); - return ZERO; + return ZERO - 0.01 * (ONE - math::tanh(20.*(-1.5 + x_ph[0]))*math::tanh(20.*(-0.5 + x_ph[0])))/2.0 * math::sin(4.0 * constant::PI * x_ph[0]); + // return ZERO; } Inline auto ex3(const coord_t& x_ph) const -> real_t { @@ -120,82 +120,82 @@ namespace user { inline void InitPrtls(Domain& domain) { - auto& species_e = domain.species[0]; - auto& species_p = domain.species[1]; + // auto& species_e = domain.species[0]; + // auto& species_p = domain.species[1]; - array_t elec_ind("elec_ind"); - array_t pos_ind("pos_ind"); + // array_t elec_ind("elec_ind"); + // array_t pos_ind("pos_ind"); - auto offset_e = species_e.npart(); - auto offset_p = species_p.npart(); - - auto ux1_e = species_e.ux1; - auto ux2_e = species_e.ux2; - auto ux3_e = species_e.ux3; - auto i1_e = species_e.i1; - auto i2_e = species_e.i2; - auto dx1_e = species_e.dx1; - auto dx2_e = species_e.dx2; - auto phi_e = species_e.phi; - auto weight_e = species_e.weight; - auto tag_e = species_e.tag; - - auto ux1_p = species_p.ux1; - auto ux2_p = species_p.ux2; - auto ux3_p = species_p.ux3; - auto i1_p = species_p.i1; - auto i2_p = species_p.i2; - auto dx1_p = species_p.dx1; - auto dx2_p = species_p.dx2; - auto phi_p = species_p.phi; - auto weight_p = species_p.weight; - auto tag_p = species_p.tag; - - int nseed = 1; - - Kokkos::parallel_for("init_particles", nseed, KOKKOS_LAMBDA(const int& s) { - - // ToDo: fix this - auto i1_ = math::floor(10); - auto i2_ = math::floor(64); - auto dx1_ = HALF; - auto dx2_ = HALF; - - - auto elec_p = Kokkos::atomic_fetch_add(&elec_ind(), 1); - auto pos_p = Kokkos::atomic_fetch_add(&pos_ind(), 1); - - i1_e(elec_p + offset_e) = i1_; - dx1_e(elec_p + offset_e) = dx1_; - i2_e(elec_p + offset_e) = i2_; - dx2_e(elec_p + offset_e) = dx2_; - ux1_e(elec_p + offset_e) = -0.5; - ux2_e(elec_p + offset_e) = 0.5; - ux3_e(elec_p + offset_e) = ZERO; - weight_e(elec_p + offset_e) = ONE; - tag_e(elec_p + offset_e) = ParticleTag::alive; - - i1_p(pos_p + offset_p) = i1_; - dx1_p(pos_p + offset_p) = dx1_; - i2_p(pos_p + offset_p) = i2_; - dx2_p(pos_p + offset_p) = dx2_; - ux1_p(pos_p + offset_p) = 0.5; - ux2_p(pos_p + offset_p) = -0.5; - ux3_p(pos_p + offset_p) = ZERO; - weight_p(pos_p + offset_p) = ONE; - tag_p(pos_p + offset_p) = ParticleTag::alive; - - - }); - - - auto elec_ind_h = Kokkos::create_mirror(elec_ind); - Kokkos::deep_copy(elec_ind_h, elec_ind); - species_e.set_npart(offset_e + elec_ind_h()); - - auto pos_ind_h = Kokkos::create_mirror(pos_ind); - Kokkos::deep_copy(pos_ind_h, pos_ind); - species_p.set_npart(offset_p + pos_ind_h()); + // auto offset_e = species_e.npart(); + // auto offset_p = species_p.npart(); + + // auto ux1_e = species_e.ux1; + // auto ux2_e = species_e.ux2; + // auto ux3_e = species_e.ux3; + // auto i1_e = species_e.i1; + // auto i2_e = species_e.i2; + // auto dx1_e = species_e.dx1; + // auto dx2_e = species_e.dx2; + // auto phi_e = species_e.phi; + // auto weight_e = species_e.weight; + // auto tag_e = species_e.tag; + + // auto ux1_p = species_p.ux1; + // auto ux2_p = species_p.ux2; + // auto ux3_p = species_p.ux3; + // auto i1_p = species_p.i1; + // auto i2_p = species_p.i2; + // auto dx1_p = species_p.dx1; + // auto dx2_p = species_p.dx2; + // auto phi_p = species_p.phi; + // auto weight_p = species_p.weight; + // auto tag_p = species_p.tag; + + // int nseed = 1; + + // Kokkos::parallel_for("init_particles", nseed, KOKKOS_LAMBDA(const int& s) { + + // // ToDo: fix this + // auto i1_ = math::floor(10); + // auto i2_ = math::floor(64); + // auto dx1_ = HALF; + // auto dx2_ = HALF; + + + // auto elec_p = Kokkos::atomic_fetch_add(&elec_ind(), 1); + // auto pos_p = Kokkos::atomic_fetch_add(&pos_ind(), 1); + + // i1_e(elec_p + offset_e) = i1_; + // dx1_e(elec_p + offset_e) = dx1_; + // i2_e(elec_p + offset_e) = i2_; + // dx2_e(elec_p + offset_e) = dx2_; + // ux1_e(elec_p + offset_e) = -0.5; + // ux2_e(elec_p + offset_e) = 0.5; + // ux3_e(elec_p + offset_e) = ZERO; + // weight_e(elec_p + offset_e) = ONE; + // tag_e(elec_p + offset_e) = ParticleTag::alive; + + // i1_p(pos_p + offset_p) = i1_; + // dx1_p(pos_p + offset_p) = dx1_; + // i2_p(pos_p + offset_p) = i2_; + // dx2_p(pos_p + offset_p) = dx2_; + // ux1_p(pos_p + offset_p) = 0.5; + // ux2_p(pos_p + offset_p) = -0.5; + // ux3_p(pos_p + offset_p) = ZERO; + // weight_p(pos_p + offset_p) = ONE; + // tag_p(pos_p + offset_p) = ParticleTag::alive; + + + // }); + + + // auto elec_ind_h = Kokkos::create_mirror(elec_ind); + // Kokkos::deep_copy(elec_ind_h, elec_ind); + // species_e.set_npart(offset_e + elec_ind_h()); + + // auto pos_ind_h = Kokkos::create_mirror(pos_ind); + // Kokkos::deep_copy(pos_ind_h, pos_ind); + // species_p.set_npart(offset_p + pos_ind_h()); } From b7bed425e6ba920ae46cf63fd1cc6a55cc94e894 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20B=C3=B6ss?= Date: Mon, 3 Mar 2025 13:11:03 -0600 Subject: [PATCH 541/773] cleanup of conductor BCs --- src/kernels/fields_bcs.hpp | 101 ++++++++++++++++++++----------------- 1 file changed, 56 insertions(+), 45 deletions(-) diff --git a/src/kernels/fields_bcs.hpp b/src/kernels/fields_bcs.hpp index def4668c6..7a499210f 100644 --- a/src/kernels/fields_bcs.hpp +++ b/src/kernels/fields_bcs.hpp @@ -506,19 +506,19 @@ namespace kernel::bc { if constexpr (S == SimEngine::SRPIC) { - if (tags & BC::E) - { - Fld((N_GHOSTS - 1) - i1, em::ex1) = Fld(N_GHOSTS + i1, em::ex1); - Fld((N_GHOSTS - 1) - i1, em::ex2) = -Fld(N_GHOSTS + 1 + i1, em::ex2); - Fld((N_GHOSTS - 1) - i1, em::ex3) = -Fld(N_GHOSTS + 1 + i1, em::ex3); - } + if (tags & BC::E) { + Fld((N_GHOSTS-1)-i1, em::ex1) = Fld(N_GHOSTS+i1, em::ex1); + Fld((N_GHOSTS-1)-i1, em::ex2) = -Fld(N_GHOSTS+i1+1, em::ex2); + Fld((N_GHOSTS-1)-i1, em::ex3) = -Fld(N_GHOSTS+i1+1, em::ex3); + } + + if (tags & BC::B) + { + Fld((N_GHOSTS-1)-i1, em::bx1) = -Fld(N_GHOSTS+i1+1, em::bx1); + Fld((N_GHOSTS-1)-i1, em::bx1) = Fld(N_GHOSTS+i1, em::bx1); + Fld((N_GHOSTS-1)-i1, em::bx1) = Fld(N_GHOSTS+i1, em::bx1); + } - if (tags & BC::B) - { - Fld((N_GHOSTS - 1) - i1, em::bx1) = -Fld(N_GHOSTS + 1 + i1, em::bx1); - Fld((N_GHOSTS - 1) - i1, em::bx2) = Fld(N_GHOSTS + i1, em::bx2); - Fld((N_GHOSTS - 1) - i1, em::bx3) = Fld(N_GHOSTS + i1, em::bx3); - } } else { // GRPIC raise::KernelError(HERE, "1D GRPIC not implemented"); @@ -530,64 +530,75 @@ namespace kernel::bc { } } - Inline void operator()(index_t i1, index_t i2) const { - if constexpr (M::Dim == Dim::_2D) { + Inline void operator()(index_t i1, index_t i2) const + { + if constexpr (M::Dim == Dim::_2D) + { - if constexpr (S == SimEngine::SRPIC) { + if constexpr (S == SimEngine::SRPIC) + { // SRPIC - if (tags & BC::E) { - // Fld((N_GHOSTS-1)-i1, i2, em::ex1) = Fld(N_GHOSTS+i1, i2, em::ex1); - // Fld((N_GHOSTS-1)-i1, i2, em::ex2) = - Fld(N_GHOSTS+1+i1, i2, em::ex2); - // Fld((N_GHOSTS-1)-i1, i2, em::ex3) = - Fld(N_GHOSTS+1+i1, i2, em::ex3); - Fld((N_GHOSTS-1)-i1, i2, em::ex1) = ZERO; - Fld((N_GHOSTS-1)-i1, i2, em::ex2) = ZERO; - Fld((N_GHOSTS-1)-i1, i2, em::ex3) = ZERO; - Fld((N_GHOSTS), i2, em::ex2) = ZERO; - Fld((N_GHOSTS), i2, em::ex3) = ZERO; + if (tags & BC::E) + { + Fld((N_GHOSTS - 1) - i1, i2, em::ex1) = Fld(N_GHOSTS + i1, i2, em::ex1); + Fld((N_GHOSTS - 1) - i1, i2, em::ex2) = -Fld(N_GHOSTS + 1 + i1, i2, em::ex2); + Fld((N_GHOSTS - 1) - i1, i2, em::ex3) = -Fld(N_GHOSTS + 1 + i1, i2, em::ex3); } if (tags & BC::B) { - Fld((N_GHOSTS-1)-i1, i2, em::bx1) = ZERO; - Fld((N_GHOSTS-1)-i1, i2, em::bx2) = ZERO; - Fld((N_GHOSTS-1)-i1, i2, em::bx3) = ZERO; + Fld((N_GHOSTS - 1) - i1, i2, em::bx1) = -Fld(N_GHOSTS + 1 + i1, i2, em::bx1); + Fld((N_GHOSTS - 1) - i1, i2, em::bx2) = Fld(N_GHOSTS + i1, i2, em::bx2); + Fld((N_GHOSTS - 1) - i1, i2, em::bx3) = Fld(N_GHOSTS + i1, i2, em::bx3); } - } else { + } + else + { // GRPIC raise::KernelError(HERE, "2D GRPIC not implemented"); } - } else { + } + else + { raise::KernelError( - HERE, - "ConductorBoundaries_kernel: 2D implementation called for D != 2"); + HERE, + "ConductorBoundaries_kernel: 2D implementation called for D != 2"); } } - Inline void operator()(index_t i1, index_t i2, index_t i3) const { - if constexpr (M::Dim == Dim::_3D) { + Inline void operator()(index_t i1, index_t i2, index_t i3) const + { + if constexpr (M::Dim == Dim::_3D) + { - if constexpr (S == SimEngine::SRPIC) { + if constexpr (S == SimEngine::SRPIC) + { // SRPIC - if (tags & BC::E) { - Fld((N_GHOSTS-1)-i1, i2, i3, em::ex1) = Fld(N_GHOSTS+i1, i2, i3, em::ex1); - Fld((N_GHOSTS-1)-i1, i2, i3, em::ex2) = -Fld(N_GHOSTS+i1, i2, i3, em::ex2); - Fld((N_GHOSTS-1)-i1, i2, i3, em::ex3) = -Fld(N_GHOSTS+i1, i2, i3, em::ex3); + if (tags & BC::E) + { + Fld((N_GHOSTS - 1) - i1, i2, i3, em::ex1) = Fld(N_GHOSTS + i1, i2, i3, em::ex1); + Fld((N_GHOSTS - 1) - i1, i2, i3, em::ex2) = -Fld(N_GHOSTS + i1 + 1, i2, i3, em::ex2); + Fld((N_GHOSTS - 1) - i1, i2, i3, em::ex3) = -Fld(N_GHOSTS + i1 + 1, i2, i3, em::ex3); } if (tags & BC::B) { - Fld((N_GHOSTS-1)-i1, i2, i3, em::bx1) = -Fld(N_GHOSTS+i1, i2, i3, em::bx1); - Fld((N_GHOSTS-1)-i1, i2, i3, em::bx2) = Fld(N_GHOSTS+i1, i2, i3, em::bx2); - Fld((N_GHOSTS-1)-i1, i2, i3, em::bx3) = Fld(N_GHOSTS+i1, i2, i3, em::bx3); + Fld((N_GHOSTS - 1) - i1, i2, i3, em::bx1) = -Fld(N_GHOSTS + i1 + 1, i2, i3, em::bx1); + Fld((N_GHOSTS - 1) - i1, i2, i3, em::bx2) = Fld(N_GHOSTS + i1, i2, i3, em::bx2); + Fld((N_GHOSTS - 1) - i1, i2, i3, em::bx3) = Fld(N_GHOSTS + i1, i2, i3, em::bx3); } - } else { + } + else + { // GRPIC raise::KernelError(HERE, "3D GRPIC not implemented"); } - } else { + } + else + { raise::KernelError( - HERE, - "ConductorBoundaries_kernel: 3D implementation called for D != 3"); + HERE, + "ConductorBoundaries_kernel: 3D implementation called for D != 3"); } } }; From 624991803f2d9a520fdb0cd3770806d18f4b9dd7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20B=C3=B6ss?= Date: Mon, 3 Mar 2025 13:11:50 -0600 Subject: [PATCH 542/773] add 3D case and set correct boundary cells to zero --- src/engines/srpic.hpp | 137 ++++++++++++++++++++++++++++-------------- 1 file changed, 91 insertions(+), 46 deletions(-) diff --git a/src/engines/srpic.hpp b/src/engines/srpic.hpp index 86b85de32..b1fca46da 100644 --- a/src/engines/srpic.hpp +++ b/src/engines/srpic.hpp @@ -839,59 +839,104 @@ namespace ntt { } void PerfectConductorFieldsIn(dir::direction_t direction, - domain_t& domain, - BCTags tags) { + domain_t& domain, + BCTags tags) { /** * perfect conductor field boundaries */ - const auto sign = direction.get_sign(); - const auto dim = direction.get_dim(); - raise::ErrorIf(dim != in::x1 and M::CoordType != Coord::Cart, - "Perfect conductor BCs only implemented for x1 in " - "non-cartesian coordinates", - HERE); + if constexpr (M::CoordType != Coord::Cart) { + (void)direction; + (void)domain; + (void)tags; + raise::Error( + "Perfect conductor BCs only applicable to cartesian coordinates", + HERE); + } else { + const auto sign = direction.get_sign(); + const auto dim = direction.get_dim(); + std::vector xi_min, xi_max; - std::vector xi_min, xi_max; + const std::vector all_dirs { in::x1, in::x2, in::x3 }; - const std::vector all_dirs { in::x1, in::x2, in::x3 }; - - for (unsigned short d { 0 }; d < static_cast(M::Dim); ++d) { - const auto dd = all_dirs[d]; - if (dim == dd) { + for (unsigned short d { 0 }; d < static_cast(M::Dim); ++d) { + const auto dd = all_dirs[d]; + if (dim == dd) { xi_min.push_back(0); - xi_max.push_back(N_GHOSTS); - } else { - xi_min.push_back(0); - xi_max.push_back(domain.mesh.n_all(dd)); + xi_max.push_back((sign < 0) ? (N_GHOSTS + 1) : N_GHOSTS); + } else { + xi_min.push_back(0); + xi_max.push_back(domain.mesh.n_all(dd)); + } } - } - raise::ErrorIf(xi_min.size() != xi_max.size() or - xi_min.size() != static_cast(M::Dim), - "Invalid range size", - HERE); + raise::ErrorIf(xi_min.size() != xi_max.size() or + xi_min.size() != static_cast(M::Dim), + "Invalid range size", + HERE); - if constexpr (M::Dim == Dim::_1D) - { - Kokkos::parallel_for( - "MatchFields", - CreateRangePolicy( { xi_min[0] } , { xi_max[0] } ), - kernel::bc::ConductorBoundaries_kernel( - domain.fields.em, - tags)); - } + range_t range; + if constexpr (M::Dim == Dim::_1D) { + range = CreateRangePolicy({ xi_min[0] }, { xi_max[0] }); + } else if constexpr (M::Dim == Dim::_2D) { + range = CreateRangePolicy({ xi_min[0], xi_min[1] }, + { xi_max[0], xi_max[1] }); + } else if constexpr (M::Dim == Dim::_3D) { + range = CreateRangePolicy({ xi_min[0], xi_min[1], xi_min[2] }, + { xi_max[0], xi_max[1], xi_max[2] }); + } else { + raise::Error("Invalid dimension", HERE); + } - if constexpr (M::Dim == Dim::_2D) - { - Kokkos::parallel_for( - "MatchFields", - CreateRangePolicy( { xi_min[0], xi_min[1] } , { xi_max[0], xi_max[1] } ), - kernel::bc::ConductorBoundaries_kernel( - domain.fields.em, - tags)); + if (dim == in::x1) { + if (sign > 0) { + Kokkos::parallel_for( + "ConductorFields", + range, + kernel::bc::ConductorBoundaries_kernel( + domain.fields.em, + tags)); + } else { + Kokkos::parallel_for( + "ConductorFields", + range, + kernel::bc::ConductorBoundaries_kernel( + domain.fields.em, + tags)); + } + } else if (dim == in::x2) { + if (sign > 0) { + Kokkos::parallel_for( + "ConductorFields", + range, + kernel::bc::ConductorBoundaries_kernel( + domain.fields.em, + tags)); + } else { + Kokkos::parallel_for( + "ConductorFields", + range, + kernel::bc::ConductorBoundaries_kernel( + domain.fields.em, + tags)); + } + } else { + if (sign > 0) { + Kokkos::parallel_for( + "ConductorFields", + range, + kernel::bc::ConductorBoundaries_kernel( + domain.fields.em, + tags)); + } else { + Kokkos::parallel_for( + "ConductorFields", + range, + kernel::bc::ConductorBoundaries_kernel( + domain.fields.em, + tags)); + } + } } - - } void AtmosphereFieldsIn(dir::direction_t direction, @@ -922,15 +967,15 @@ namespace ntt { return; } const auto intersect_range = domain.mesh.ExtentToRange(box, incl_ghosts); - tuple_t range_min { 0 }; - tuple_t range_max { 0 }; + tuple_t range_min { 0 }; + tuple_t range_max { 0 }; for (unsigned short d { 0 }; d < M::Dim; ++d) { range_min[d] = intersect_range[d].first; range_max[d] = intersect_range[d].second; } - auto atm_fields = m_pgen.AtmFields(time); - ncells_t il_edge; + auto atm_fields = m_pgen.AtmFields(time); + std::size_t il_edge; if (sign > 0) { il_edge = range_min[dd] - N_GHOSTS; } else { From 268f35afd100d05d34603cfa9cdd8d292e8d0380 Mon Sep 17 00:00:00 2001 From: jmahlmann Date: Tue, 4 Mar 2025 13:22:38 -0600 Subject: [PATCH 543/773] Ongoing --- setups/srpic/shocktest/pgen.hpp | 156 ++++++++++++++++---------------- 1 file changed, 78 insertions(+), 78 deletions(-) diff --git a/setups/srpic/shocktest/pgen.hpp b/setups/srpic/shocktest/pgen.hpp index 1b8926c67..a1ce9a1a9 100644 --- a/setups/srpic/shocktest/pgen.hpp +++ b/setups/srpic/shocktest/pgen.hpp @@ -48,8 +48,8 @@ namespace user { Inline auto bx3(const coord_t& x_ph) const -> real_t { // return Bmag * math::sin(Btheta) * math::cos(Bphi); - return ONE + 0.01 * (ONE - math::tanh(20.*(-1.5 + x_ph[0]))*math::tanh(20.*(-0.5 + x_ph[0])))/2.0 * math::sin(4.0 * constant::PI * x_ph[0]); - // return ZERO; + // return ONE + 0.01 * (ONE - math::tanh(20.*(-1.5 + x_ph[0]))*math::tanh(20.*(-0.5 + x_ph[0])))/2.0 * math::sin(4.0 * constant::PI * x_ph[0]); + return ZERO; } // electric field components @@ -59,8 +59,8 @@ namespace user { Inline auto ex2(const coord_t& x_ph) const -> real_t { // return -Vx * Bmag * math::sin(Btheta) * math::cos(Bphi); - return ZERO - 0.01 * (ONE - math::tanh(20.*(-1.5 + x_ph[0]))*math::tanh(20.*(-0.5 + x_ph[0])))/2.0 * math::sin(4.0 * constant::PI * x_ph[0]); - // return ZERO; + // return ZERO - 0.01 * (ONE - math::tanh(20.*(-1.5 + x_ph[0]))*math::tanh(20.*(-0.5 + x_ph[0])))/2.0 * math::sin(4.0 * constant::PI * x_ph[0]); + return ZERO; } Inline auto ex3(const coord_t& x_ph) const -> real_t { @@ -120,82 +120,82 @@ namespace user { inline void InitPrtls(Domain& domain) { - // auto& species_e = domain.species[0]; - // auto& species_p = domain.species[1]; + auto& species_e = domain.species[0]; + auto& species_p = domain.species[1]; - // array_t elec_ind("elec_ind"); - // array_t pos_ind("pos_ind"); + array_t elec_ind("elec_ind"); + array_t pos_ind("pos_ind"); - // auto offset_e = species_e.npart(); - // auto offset_p = species_p.npart(); - - // auto ux1_e = species_e.ux1; - // auto ux2_e = species_e.ux2; - // auto ux3_e = species_e.ux3; - // auto i1_e = species_e.i1; - // auto i2_e = species_e.i2; - // auto dx1_e = species_e.dx1; - // auto dx2_e = species_e.dx2; - // auto phi_e = species_e.phi; - // auto weight_e = species_e.weight; - // auto tag_e = species_e.tag; - - // auto ux1_p = species_p.ux1; - // auto ux2_p = species_p.ux2; - // auto ux3_p = species_p.ux3; - // auto i1_p = species_p.i1; - // auto i2_p = species_p.i2; - // auto dx1_p = species_p.dx1; - // auto dx2_p = species_p.dx2; - // auto phi_p = species_p.phi; - // auto weight_p = species_p.weight; - // auto tag_p = species_p.tag; - - // int nseed = 1; - - // Kokkos::parallel_for("init_particles", nseed, KOKKOS_LAMBDA(const int& s) { - - // // ToDo: fix this - // auto i1_ = math::floor(10); - // auto i2_ = math::floor(64); - // auto dx1_ = HALF; - // auto dx2_ = HALF; - - - // auto elec_p = Kokkos::atomic_fetch_add(&elec_ind(), 1); - // auto pos_p = Kokkos::atomic_fetch_add(&pos_ind(), 1); - - // i1_e(elec_p + offset_e) = i1_; - // dx1_e(elec_p + offset_e) = dx1_; - // i2_e(elec_p + offset_e) = i2_; - // dx2_e(elec_p + offset_e) = dx2_; - // ux1_e(elec_p + offset_e) = -0.5; - // ux2_e(elec_p + offset_e) = 0.5; - // ux3_e(elec_p + offset_e) = ZERO; - // weight_e(elec_p + offset_e) = ONE; - // tag_e(elec_p + offset_e) = ParticleTag::alive; - - // i1_p(pos_p + offset_p) = i1_; - // dx1_p(pos_p + offset_p) = dx1_; - // i2_p(pos_p + offset_p) = i2_; - // dx2_p(pos_p + offset_p) = dx2_; - // ux1_p(pos_p + offset_p) = 0.5; - // ux2_p(pos_p + offset_p) = -0.5; - // ux3_p(pos_p + offset_p) = ZERO; - // weight_p(pos_p + offset_p) = ONE; - // tag_p(pos_p + offset_p) = ParticleTag::alive; - - - // }); - - - // auto elec_ind_h = Kokkos::create_mirror(elec_ind); - // Kokkos::deep_copy(elec_ind_h, elec_ind); - // species_e.set_npart(offset_e + elec_ind_h()); - - // auto pos_ind_h = Kokkos::create_mirror(pos_ind); - // Kokkos::deep_copy(pos_ind_h, pos_ind); - // species_p.set_npart(offset_p + pos_ind_h()); + auto offset_e = species_e.npart(); + auto offset_p = species_p.npart(); + + auto ux1_e = species_e.ux1; + auto ux2_e = species_e.ux2; + auto ux3_e = species_e.ux3; + auto i1_e = species_e.i1; + auto i2_e = species_e.i2; + auto dx1_e = species_e.dx1; + auto dx2_e = species_e.dx2; + auto phi_e = species_e.phi; + auto weight_e = species_e.weight; + auto tag_e = species_e.tag; + + auto ux1_p = species_p.ux1; + auto ux2_p = species_p.ux2; + auto ux3_p = species_p.ux3; + auto i1_p = species_p.i1; + auto i2_p = species_p.i2; + auto dx1_p = species_p.dx1; + auto dx2_p = species_p.dx2; + auto phi_p = species_p.phi; + auto weight_p = species_p.weight; + auto tag_p = species_p.tag; + + int nseed = 1; + + Kokkos::parallel_for("init_particles", nseed, KOKKOS_LAMBDA(const int& s) { + + // ToDo: fix this + auto i1_ = math::floor(10); + auto i2_ = math::floor(64); + auto dx1_ = HALF; + auto dx2_ = HALF; + + + auto elec_p = Kokkos::atomic_fetch_add(&elec_ind(), 1); + auto pos_p = Kokkos::atomic_fetch_add(&pos_ind(), 1); + + i1_e(elec_p + offset_e) = i1_; + dx1_e(elec_p + offset_e) = dx1_; + i2_e(elec_p + offset_e) = i2_; + dx2_e(elec_p + offset_e) = dx2_; + ux1_e(elec_p + offset_e) = -0.5; + ux2_e(elec_p + offset_e) = 0.5; + ux3_e(elec_p + offset_e) = ZERO; + weight_e(elec_p + offset_e) = ONE; + tag_e(elec_p + offset_e) = ParticleTag::alive; + + i1_p(pos_p + offset_p) = i1_; + dx1_p(pos_p + offset_p) = dx1_; + i2_p(pos_p + offset_p) = i2_; + dx2_p(pos_p + offset_p) = dx2_; + ux1_p(pos_p + offset_p) = 0.5; + ux2_p(pos_p + offset_p) = -0.5; + ux3_p(pos_p + offset_p) = ZERO; + weight_p(pos_p + offset_p) = ONE; + tag_p(pos_p + offset_p) = ParticleTag::alive; + + + }); + + + auto elec_ind_h = Kokkos::create_mirror(elec_ind); + Kokkos::deep_copy(elec_ind_h, elec_ind); + species_e.set_npart(offset_e + elec_ind_h()); + + auto pos_ind_h = Kokkos::create_mirror(pos_ind); + Kokkos::deep_copy(pos_ind_h, pos_ind); + species_p.set_npart(offset_p + pos_ind_h()); } From c4325e70b9bf4b15004f2b0b56b54dea58badf3e Mon Sep 17 00:00:00 2001 From: hayk Date: Fri, 7 Mar 2025 11:30:47 -0500 Subject: [PATCH 544/773] minor reformatting of conductor BC --- input.example.toml | 2 +- setups/srpic/shocktest/pgen.hpp | 149 +++++++++------------------- setups/srpic/shocktest/shock.toml | 26 +++-- src/engines/srpic.hpp | 52 ++++++++++ src/global/enums.h | 19 ++-- src/global/tests/enums.cpp | 5 +- src/kernels/fields_bcs.hpp | 157 ++++++++++++++---------------- 7 files changed, 204 insertions(+), 206 deletions(-) diff --git a/input.example.toml b/input.example.toml index a49067811..c71049b84 100644 --- a/input.example.toml +++ b/input.example.toml @@ -90,7 +90,7 @@ # Boundary conditions for fields: # @required # @type: 1/2/3-size array of string tuples, each of size 1 or 2 - # @valid: "PERIODIC", "MATCH", "FIXED", "ATMOSPHERE", "CUSTOM", "HORIZON" + # @valid: "PERIODIC", "MATCH", "FIXED", "ATMOSPHERE", "CUSTOM", "HORIZON", "CONDUCTOR" # @example: [["CUSTOM", "MATCH"]] (for 2D spherical [[rmin, rmax]]) # @note: When periodic in any of the directions, you should only set one value: [..., ["PERIODIC"], ...] # @note: In spherical, bondaries in theta/phi are set automatically (only specify bc @ [rmin, rmax]): [["ATMOSPHERE", "MATCH"]] diff --git a/setups/srpic/shocktest/pgen.hpp b/setups/srpic/shocktest/pgen.hpp index a1ce9a1a9..4f6decc76 100644 --- a/setups/srpic/shocktest/pgen.hpp +++ b/setups/srpic/shocktest/pgen.hpp @@ -14,6 +14,7 @@ #include "framework/domain/metadomain.h" #include +#include namespace user { using namespace ntt; @@ -48,7 +49,8 @@ namespace user { Inline auto bx3(const coord_t& x_ph) const -> real_t { // return Bmag * math::sin(Btheta) * math::cos(Bphi); - // return ONE + 0.01 * (ONE - math::tanh(20.*(-1.5 + x_ph[0]))*math::tanh(20.*(-0.5 + x_ph[0])))/2.0 * math::sin(4.0 * constant::PI * x_ph[0]); + // return ONE + 0.01 * (ONE - math::tanh(20.*(-1.5 + x_ph[0]))*math::tanh(20.*(-0.5 + // + x_ph[0])))/2.0 * math::sin(4.0 * constant::PI * x_ph[0]); return ZERO; } @@ -59,7 +61,8 @@ namespace user { Inline auto ex2(const coord_t& x_ph) const -> real_t { // return -Vx * Bmag * math::sin(Btheta) * math::cos(Bphi); - // return ZERO - 0.01 * (ONE - math::tanh(20.*(-1.5 + x_ph[0]))*math::tanh(20.*(-0.5 + x_ph[0])))/2.0 * math::sin(4.0 * constant::PI * x_ph[0]); + // return ZERO - 0.01 * (ONE - math::tanh(20.*(-1.5 + x_ph[0]))*math::tanh(20.*(-0.5 + // + x_ph[0])))/2.0 * math::sin(4.0 * constant::PI * x_ph[0]); return ZERO; } @@ -88,17 +91,32 @@ namespace user { const real_t drift_ux, temperature; - const real_t Btheta, Bphi, Bmag; - InitFields init_flds; + const std::vector x1arr_e, x2arr_e, ux1arr_e, ux2arr_e, ux3arr_e; + const std::vector x1arr_i, x2arr_i, ux1arr_i, ux2arr_i, ux3arr_i; + + const real_t Btheta, Bphi, Bmag; + InitFields init_flds; + const Metadomain* metadomain; inline PGen(const SimulationParams& p, const Metadomain& m) : arch::ProblemGenerator { p } , drift_ux { p.template get("setup.drift_ux") } , temperature { p.template get("setup.temperature") } - , Bmag { p.template get("setup.Bmag", ZERO) } + , x1arr_e { p.template get>("setup.x_e") } + , x2arr_e { p.template get>("setup.y_e") } + , ux1arr_e { p.template get>("setup.ux_e") } + , ux2arr_e { p.template get>("setup.uy_e") } + , ux3arr_e { p.template get>("setup.uz_e") } + , x1arr_i { p.template get>("setup.x_i") } + , x2arr_i { p.template get>("setup.y_i") } + , ux1arr_i { p.template get>("setup.ux_i") } + , ux2arr_i { p.template get>("setup.uy_i") } + , ux3arr_i { p.template get>("setup.uz_i") } , Btheta { p.template get("setup.Btheta", ZERO) } + , Bmag { p.template get("setup.Bmag", ZERO) } , Bphi { p.template get("setup.Bphi", ZERO) } - , init_flds { Bmag, Btheta, Bphi, drift_ux } {} + , init_flds { Bmag, Btheta, Bphi, drift_ux } + , metadomain { &m } {} inline PGen() {} @@ -113,111 +131,32 @@ namespace user { } } - auto MatchFields(real_t time) const -> InitFields { return init_flds; } inline void InitPrtls(Domain& domain) { - - auto& species_e = domain.species[0]; - auto& species_p = domain.species[1]; - - array_t elec_ind("elec_ind"); - array_t pos_ind("pos_ind"); - - auto offset_e = species_e.npart(); - auto offset_p = species_p.npart(); - - auto ux1_e = species_e.ux1; - auto ux2_e = species_e.ux2; - auto ux3_e = species_e.ux3; - auto i1_e = species_e.i1; - auto i2_e = species_e.i2; - auto dx1_e = species_e.dx1; - auto dx2_e = species_e.dx2; - auto phi_e = species_e.phi; - auto weight_e = species_e.weight; - auto tag_e = species_e.tag; - - auto ux1_p = species_p.ux1; - auto ux2_p = species_p.ux2; - auto ux3_p = species_p.ux3; - auto i1_p = species_p.i1; - auto i2_p = species_p.i2; - auto dx1_p = species_p.dx1; - auto dx2_p = species_p.dx2; - auto phi_p = species_p.phi; - auto weight_p = species_p.weight; - auto tag_p = species_p.tag; - - int nseed = 1; - - Kokkos::parallel_for("init_particles", nseed, KOKKOS_LAMBDA(const int& s) { - - // ToDo: fix this - auto i1_ = math::floor(10); - auto i2_ = math::floor(64); - auto dx1_ = HALF; - auto dx2_ = HALF; - - - auto elec_p = Kokkos::atomic_fetch_add(&elec_ind(), 1); - auto pos_p = Kokkos::atomic_fetch_add(&pos_ind(), 1); - - i1_e(elec_p + offset_e) = i1_; - dx1_e(elec_p + offset_e) = dx1_; - i2_e(elec_p + offset_e) = i2_; - dx2_e(elec_p + offset_e) = dx2_; - ux1_e(elec_p + offset_e) = -0.5; - ux2_e(elec_p + offset_e) = 0.5; - ux3_e(elec_p + offset_e) = ZERO; - weight_e(elec_p + offset_e) = ONE; - tag_e(elec_p + offset_e) = ParticleTag::alive; - - i1_p(pos_p + offset_p) = i1_; - dx1_p(pos_p + offset_p) = dx1_; - i2_p(pos_p + offset_p) = i2_; - dx2_p(pos_p + offset_p) = dx2_; - ux1_p(pos_p + offset_p) = 0.5; - ux2_p(pos_p + offset_p) = -0.5; - ux3_p(pos_p + offset_p) = ZERO; - weight_p(pos_p + offset_p) = ONE; - tag_p(pos_p + offset_p) = ParticleTag::alive; - - - }); - - - auto elec_ind_h = Kokkos::create_mirror(elec_ind); - Kokkos::deep_copy(elec_ind_h, elec_ind); - species_e.set_npart(offset_e + elec_ind_h()); - - auto pos_ind_h = Kokkos::create_mirror(pos_ind); - Kokkos::deep_copy(pos_ind_h, pos_ind); - species_p.set_npart(offset_p + pos_ind_h()); - - + arch::InjectGlobally(*metadomain, + domain, + 1, + { + { "x1", x1arr_e }, + { "x2", x2arr_e }, + { "ux1", ux1arr_e }, + { "ux2", ux1arr_e }, + { "ux3", ux3arr_e } + }); + arch::InjectGlobally(*metadomain, + domain, + 2, + { + { "x1", x1arr_i }, + { "x2", x2arr_i }, + { "ux1", ux1arr_i }, + { "ux2", ux1arr_i }, + { "ux3", ux3arr_i } + }); } - - - // inline void InitPrtls(Domain& local_domain) { - // const auto energy_dist = arch::Maxwellian(local_domain.mesh.metric, - // local_domain.random_pool, - // temperature, - // -drift_ux, - // in::x1); - - // const auto injector = arch::UniformInjector( - // energy_dist, - // { 1, 2 }); - // arch::InjectUniform>( - // params, - // local_domain, - // injector, - // 1.0); - // } - }; } // namespace user diff --git a/setups/srpic/shocktest/shock.toml b/setups/srpic/shocktest/shock.toml index a77f5c2e9..6c0c9a3a0 100644 --- a/setups/srpic/shocktest/shock.toml +++ b/setups/srpic/shocktest/shock.toml @@ -11,7 +11,7 @@ metric = "minkowski" [grid.boundaries] - fields = [["CONDUCTOR", "FIXED"], ["PERIODIC"]] + fields = [["CONDUCTOR", "FIXED"], ["PERIODIC"]] particles = [["REFLECT", "ABSORB"], ["PERIODIC"]] [scales] @@ -20,8 +20,8 @@ [algorithms] current_filters = 8 - fieldsolver = "false" - deposit = "false" + fieldsolver = "false" + deposit = "false" [algorithms.timestep] CFL = 0.5 @@ -44,13 +44,23 @@ [setup] drift_ux = 0.1 temperature = 1e-3 - Bmag = 1.0 - Btheta = 0.0 - Bphi = 0.0 + Bmag = 1.0 + Btheta = 0.0 + Bphi = 0.0 + x_e = [0.05] + y_e = [0.0] + ux_e = [-0.01] + uy_e = [0.01] + uz_e = [0.001] + x_i = [0.05] + y_i = [0.0] + ux_i = [0.01] + uy_i = [-0.01] + uz_i = [-0.001] [output] - interval = 1 - format = "hdf5" + interval = 1 + format = "hdf5" [output.fields] quantities = ["N_1", "N_2", "E", "B", "T0i_1", "T0i_2", "J"] diff --git a/src/engines/srpic.hpp b/src/engines/srpic.hpp index b1fca46da..f75989739 100644 --- a/src/engines/srpic.hpp +++ b/src/engines/srpic.hpp @@ -854,6 +854,19 @@ namespace ntt { } else { const auto sign = direction.get_sign(); const auto dim = direction.get_dim(); +<<<<<<< HEAD +||||||| parent of bd723f39 (minor reformatting of conductor BC) + const auto sign = direction.get_sign(); + const auto dim = direction.get_dim(); + raise::ErrorIf(dim != in::x1 and M::CoordType != Coord::Cart, + "Perfect conductor BCs only implemented for x1 in " + "non-cartesian coordinates", + HERE); +======= + raise::ErrorIf(dim != in::x1, + "Perfect conductor BCs only implemented for x1", + HERE); +>>>>>>> bd723f39 (minor reformatting of conductor BC) std::vector xi_min, xi_max; @@ -863,7 +876,13 @@ namespace ntt { const auto dd = all_dirs[d]; if (dim == dd) { xi_min.push_back(0); +<<<<<<< HEAD xi_max.push_back((sign < 0) ? (N_GHOSTS + 1) : N_GHOSTS); +||||||| parent of bd723f39 (minor reformatting of conductor BC) + xi_max.push_back(N_GHOSTS); +======= + xi_max.push_back(N_GHOSTS + 1); +>>>>>>> bd723f39 (minor reformatting of conductor BC) } else { xi_min.push_back(0); xi_max.push_back(domain.mesh.n_all(dd)); @@ -886,6 +905,7 @@ namespace ntt { } else { raise::Error("Invalid dimension", HERE); } +<<<<<<< HEAD if (dim == in::x1) { if (sign > 0) { @@ -936,6 +956,38 @@ namespace ntt { tags)); } } +||||||| parent of bd723f39 (minor reformatting of conductor BC) +======= + Kokkos::parallel_for( + "MatchFields", + range, + kernel::bc::ConductorBoundaries_kernel(domain.fields.em, + tags)); + + // if constexpr (M::Dim == Dim::_1D) { + // Kokkos::parallel_for( + // "MatchFields", + // CreateRangePolicy({ xi_min[0] }, { xi_max[0] }), + // kernel::bc::ConductorBoundaries_kernel(domain.fields.em, + // tags)); + // } else if constexpr (M::Dim == Dim::_2D) { + // Kokkos::parallel_for( + // "MatchFields", + // CreateRangePolicy({ xi_min[0], xi_min[1] }, + // { xi_max[0], xi_max[1] }), + // kernel::bc::ConductorBoundaries_kernel(domain.fields.em, + // tags)); + // } else if constexpr (M::Dim == Dim::_3D) { + // Kokkos::parallel_for( + // "MatchFields", + // CreateRangePolicy({ xi_min[0], xi_min[1], xi_min[2] }, + // { xi_max[0], xi_max[1], xi_max[2] }), + // kernel::bc::ConductorBoundaries_kernel(domain.fields.em, + // tags)); + // } else { + // raise::Error("Invalid dimension", HERE); + // } +>>>>>>> bd723f39 (minor reformatting of conductor BC) } } diff --git a/src/global/enums.h b/src/global/enums.h index 8407d0b66..d80297d8d 100644 --- a/src/global/enums.h +++ b/src/global/enums.h @@ -9,7 +9,7 @@ * - enum ntt::PrtlBC // periodic, absorb, atmosphere, custom, * reflect, horizon, axis, sync * - enum ntt::FldsBC // periodic, match, fixed, atmosphere, - * custom, horizon, axis, sync + * custom, horizon, axis, conductor, sync * - enum ntt::PrtlPusher // boris, vay, photon, none * - enum ntt::Cooling // synchrotron, none * - enum ntt::FldsID // e, dive, d, divd, b, h, j, @@ -221,17 +221,20 @@ namespace ntt { CUSTOM = 5, HORIZON = 6, AXIS = 7, - SYNC = 8, // <- SYNC means synchronization with other domains - CONDUCTOR = 9 + CONDUCTOR = 8, + SYNC = 9 // <- SYNC means synchronization with other domains }; constexpr FldsBC(uint8_t c) : enums_hidden::BaseEnum { c } {} - static constexpr type variants[] = { PERIODIC, MATCH, FIXED, ATMOSPHERE, - CUSTOM, HORIZON, AXIS, SYNC, CONDUCTOR }; - static constexpr const char* lookup[] = { "periodic", "match", "fixed", - "atmosphere", "custom", "horizon", - "axis", "sync", "conductor"}; + static constexpr type variants[] = { + PERIODIC, MATCH, FIXED, ATMOSPHERE, CUSTOM, + HORIZON, AXIS, CONDUCTOR, SYNC, + }; + static constexpr const char* lookup[] = { + "periodic", "match", "fixed", "atmosphere", "custom", + "horizon", "axis", "conductor", "sync" + }; static constexpr std::size_t total = sizeof(variants) / sizeof(variants[0]); }; diff --git a/src/global/tests/enums.cpp b/src/global/tests/enums.cpp index 673efaf34..ebc074b72 100644 --- a/src/global/tests/enums.cpp +++ b/src/global/tests/enums.cpp @@ -61,8 +61,9 @@ auto main() -> int { enum_str_t all_simulation_engines = { "srpic", "grpic" }; enum_str_t all_particle_bcs = { "periodic", "absorb", "atmosphere", "custom", "reflect", "horizon", "axis", "sync" }; - enum_str_t all_fields_bcs = { "periodic", "match", "fixed", "atmosphere", - "custom", "horizon", "axis", "sync" }; + enum_str_t all_fields_bcs = { "periodic", "match", "fixed", + "atmosphere", "custom", "horizon", + "axis", "conductor", "sync" }; enum_str_t all_particle_pushers = { "boris", "vay", "photon", "none" }; enum_str_t all_coolings = { "synchrotron", "none" }; diff --git a/src/kernels/fields_bcs.hpp b/src/kernels/fields_bcs.hpp index 7a499210f..901f8e02a 100644 --- a/src/kernels/fields_bcs.hpp +++ b/src/kernels/fields_bcs.hpp @@ -5,6 +5,7 @@ * - kernel::bc::MatchBoundaries_kernel<> * - kernel::bc::AxisBoundaries_kernel<> * - kernel::bc::EnforcedBoundaries_kernel<> + * - kernel::bc::ConductorBoundaries_kernel<> * @namespaces: * - kernel::bc:: */ @@ -485,43 +486,40 @@ namespace kernel::bc { } }; - template + template struct ConductorBoundaries_kernel { - static_assert(M::is_metric, "M must be a metric class"); - static_assert(static_cast(o) < - static_cast(M::Dim), + static_assert(static_cast(o) < static_cast(D), "Invalid component index"); - static constexpr idx_t i = static_cast(o) + 1u; + // static constexpr idx_t i = static_cast(o) + 1u; - ndfield_t Fld; - const BCTags tags; + ndfield_t Fld; + const BCTags tags; - ConductorBoundaries_kernel(ndfield_t Fld, - BCTags tags) + ConductorBoundaries_kernel(ndfield_t Fld, BCTags tags) : Fld { Fld } , tags { tags } {} Inline void operator()(index_t i1) const { - if constexpr (M::Dim == Dim::_1D) { - - if constexpr (S == SimEngine::SRPIC) { - + if constexpr (D == Dim::_1D) { if (tags & BC::E) { - Fld((N_GHOSTS-1)-i1, em::ex1) = Fld(N_GHOSTS+i1, em::ex1); - Fld((N_GHOSTS-1)-i1, em::ex2) = -Fld(N_GHOSTS+i1+1, em::ex2); - Fld((N_GHOSTS-1)-i1, em::ex3) = -Fld(N_GHOSTS+i1+1, em::ex3); - } - - if (tags & BC::B) - { - Fld((N_GHOSTS-1)-i1, em::bx1) = -Fld(N_GHOSTS+i1+1, em::bx1); - Fld((N_GHOSTS-1)-i1, em::bx1) = Fld(N_GHOSTS+i1, em::bx1); - Fld((N_GHOSTS-1)-i1, em::bx1) = Fld(N_GHOSTS+i1, em::bx1); + if (i1 == 0) { + Fld(N_GHOSTS, em::ex2) = ZERO; + Fld(N_GHOSTS, em::ex3) = ZERO; + } else { + Fld(N_GHOSTS - i1, em::ex1) = Fld(N_GHOSTS + i1 - 1, em::ex1); + Fld(N_GHOSTS - i1, em::ex2) = -Fld(N_GHOSTS + i1, em::ex2); + Fld(N_GHOSTS - i1, em::ex3) = -Fld(N_GHOSTS + i1, em::ex3); + } } - } else { - // GRPIC - raise::KernelError(HERE, "1D GRPIC not implemented"); + if (tags & BC::B) { + if (i1 == 0) { + Fld(N_GHOSTS, em::bx1) = ZERO; + } else { + Fld(N_GHOSTS - i1, em::bx1) = -Fld(N_GHOSTS + i1, em::bx1); + Fld(N_GHOSTS - i1, em::bx2) = Fld(N_GHOSTS + i1 - 1, em::bx2); + Fld(N_GHOSTS - i1, em::bx3) = Fld(N_GHOSTS + i1 - 1, em::bx3); + } } } else { raise::KernelError( @@ -530,75 +528,70 @@ namespace kernel::bc { } } - Inline void operator()(index_t i1, index_t i2) const - { - if constexpr (M::Dim == Dim::_2D) - { - - if constexpr (S == SimEngine::SRPIC) - { - // SRPIC - if (tags & BC::E) - { - Fld((N_GHOSTS - 1) - i1, i2, em::ex1) = Fld(N_GHOSTS + i1, i2, em::ex1); - Fld((N_GHOSTS - 1) - i1, i2, em::ex2) = -Fld(N_GHOSTS + 1 + i1, i2, em::ex2); - Fld((N_GHOSTS - 1) - i1, i2, em::ex3) = -Fld(N_GHOSTS + 1 + i1, i2, em::ex3); + Inline void operator()(index_t i1, index_t i2) const { + if constexpr (D == Dim::_2D) { + if (tags & BC::E) { + if (i1 == 0) { + Fld(N_GHOSTS, i2, em::ex2) = ZERO; + Fld(N_GHOSTS, i2, em::ex3) = ZERO; + } else { + Fld(N_GHOSTS - i1, i2, em::ex1) = Fld(N_GHOSTS + i1 - 1, i2, em::ex1); + Fld(N_GHOSTS - i1, i2, em::ex2) = -Fld(N_GHOSTS + i1, i2, em::ex2); + Fld(N_GHOSTS - i1, i2, em::ex3) = -Fld(N_GHOSTS + i1, i2, em::ex3); } + } - if (tags & BC::B) - { - Fld((N_GHOSTS - 1) - i1, i2, em::bx1) = -Fld(N_GHOSTS + 1 + i1, i2, em::bx1); - Fld((N_GHOSTS - 1) - i1, i2, em::bx2) = Fld(N_GHOSTS + i1, i2, em::bx2); - Fld((N_GHOSTS - 1) - i1, i2, em::bx3) = Fld(N_GHOSTS + i1, i2, em::bx3); + if (tags & BC::B) { + if (i1 == 0) { + Fld(N_GHOSTS, i2, em::bx1) = ZERO; + } else { + Fld(N_GHOSTS - i1, i2, em::bx1) = -Fld(N_GHOSTS + i1, i2, em::bx1); + Fld(N_GHOSTS - i1, i2, em::bx2) = Fld(N_GHOSTS + i1 - 1, i2, em::bx2); + Fld(N_GHOSTS - i1, i2, em::bx3) = Fld(N_GHOSTS + i1 - 1, i2, em::bx3); } } - else - { - // GRPIC - raise::KernelError(HERE, "2D GRPIC not implemented"); - } - } - else - { + } else { raise::KernelError( - HERE, - "ConductorBoundaries_kernel: 2D implementation called for D != 2"); + HERE, + "ConductorBoundaries_kernel: 2D implementation called for D != 2"); } } - Inline void operator()(index_t i1, index_t i2, index_t i3) const - { - if constexpr (M::Dim == Dim::_3D) - { - - if constexpr (S == SimEngine::SRPIC) - { - // SRPIC - if (tags & BC::E) - { - Fld((N_GHOSTS - 1) - i1, i2, i3, em::ex1) = Fld(N_GHOSTS + i1, i2, i3, em::ex1); - Fld((N_GHOSTS - 1) - i1, i2, i3, em::ex2) = -Fld(N_GHOSTS + i1 + 1, i2, i3, em::ex2); - Fld((N_GHOSTS - 1) - i1, i2, i3, em::ex3) = -Fld(N_GHOSTS + i1 + 1, i2, i3, em::ex3); + Inline void operator()(index_t i1, index_t i2, index_t i3) const { + if constexpr (D == Dim::_3D) { + if (tags & BC::E) { + if (i1 == 0) { + Fld(N_GHOSTS, i2, i3, em::ex2) = ZERO; + Fld(N_GHOSTS, i2, i3, em::ex3) = ZERO; + } else { + Fld(N_GHOSTS - i1, i2, i3, em::ex1) = Fld(N_GHOSTS + i1 - 1, + i2, + i3, + em::ex1); + Fld(N_GHOSTS - i1, i2, i3, em::ex2) = -Fld(N_GHOSTS + i1, i2, i3, em::ex2); + Fld(N_GHOSTS - i1, i2, i3, em::ex3) = -Fld(N_GHOSTS + i1, i2, i3, em::ex3); } + } - if (tags & BC::B) - { - Fld((N_GHOSTS - 1) - i1, i2, i3, em::bx1) = -Fld(N_GHOSTS + i1 + 1, i2, i3, em::bx1); - Fld((N_GHOSTS - 1) - i1, i2, i3, em::bx2) = Fld(N_GHOSTS + i1, i2, i3, em::bx2); - Fld((N_GHOSTS - 1) - i1, i2, i3, em::bx3) = Fld(N_GHOSTS + i1, i2, i3, em::bx3); + if (tags & BC::B) { + if (i1 == 0) { + Fld(N_GHOSTS, i2, i3, em::bx1) = ZERO; + } else { + Fld(N_GHOSTS - i1, i2, i3, em::bx1) = -Fld(N_GHOSTS + i1, i2, i3, em::bx1); + Fld(N_GHOSTS - i1, i2, i3, em::bx2) = Fld(N_GHOSTS + i1 - 1, + i2, + i3, + em::bx2); + Fld(N_GHOSTS - i1, i2, i3, em::bx3) = Fld(N_GHOSTS + i1 - 1, + i2, + i3, + em::bx3); } } - else - { - // GRPIC - raise::KernelError(HERE, "3D GRPIC not implemented"); - } - } - else - { + } else { raise::KernelError( - HERE, - "ConductorBoundaries_kernel: 3D implementation called for D != 3"); + HERE, + "ConductorBoundaries_kernel: 3D implementation called for D != 3"); } } }; From 6e66aa27097095bea992672762b20a7a9093f865 Mon Sep 17 00:00:00 2001 From: hayk Date: Fri, 7 Mar 2025 12:11:31 -0500 Subject: [PATCH 545/773] filters adapted for conducting BCs --- src/kernels/digital_filter.hpp | 129 ++++++++++++++++++++++----------- 1 file changed, 86 insertions(+), 43 deletions(-) diff --git a/src/kernels/digital_filter.hpp b/src/kernels/digital_filter.hpp index f01eb0fb8..0ec6dcdbc 100644 --- a/src/kernels/digital_filter.hpp +++ b/src/kernels/digital_filter.hpp @@ -17,10 +17,14 @@ #include "utils/error.h" #include "utils/numeric.h" -#define FILTER_IN_I1(ARR, COMP, I, J) \ +#define FILTER2D_IN_I1(ARR, COMP, I, J) \ INV_2*(ARR)((I), (J), (COMP)) + \ INV_4*((ARR)((I) - 1, (J), (COMP)) + (ARR)((I) + 1, (J), (COMP))) +#define FILTER2D_IN_I2(ARR, COMP, I, J) \ + INV_2*(ARR)((I), (J), (COMP)) + \ + INV_4*((ARR)((I), (J) - 1, (COMP)) + (ARR)((I), (J) + 1, (COMP))) + namespace kernel { using namespace ntt; @@ -31,6 +35,10 @@ namespace kernel { bool is_axis_i2min { false }, is_axis_i2max { false }; static constexpr auto i2_min = N_GHOSTS; const ncells_t i2_max; + const bool is_axis_i2min, is_axis_i2max; + const bool is_conductor_i1min; + static constexpr auto i1_min = N_GHOSTS, i2_min = N_GHOSTS; + const std::size_t i2_max; public: DigitalFilter_kernel(ndfield_t& array, @@ -39,20 +47,31 @@ namespace kernel { const boundaries_t& boundaries) : array { array } , buffer { buffer } - , i2_max { (short)D > 1 ? size_[1] + N_GHOSTS : 0 } { - if constexpr ((C != Coord::Cart) && (D != Dim::_1D)) { - raise::ErrorIf(boundaries.size() < 2, "boundaries defined incorrectly", HERE); - is_axis_i2min = (boundaries[1].first == FldsBC::AXIS); - is_axis_i2max = (boundaries[1].second == FldsBC::AXIS); - } - } + , is_axis_i2min { (D == Dim::_2D) and (boundaries[1].first == FldsBC::AXIS) } + , is_axis_i2max { (D == Dim::_2D) and (boundaries[1].second == FldsBC::AXIS) } + , is_conductor_i1min { boundaries[0].first == FldsBC::CONDUCTOR } + , i2_max { (short)D > 1 ? size_[1] + N_GHOSTS : 0 } {} Inline void operator()(index_t i1) const { if constexpr ((D == Dim::_1D) && (C == Coord::Cart)) { + if (is_conductor_i1min and i1 == i1_min) { + array(i1, cur::jx1) = (THREE * INV_4) * buffer(i1, cur::jx1) + + (INV_4)*buffer(i1 + 1, cur::jx1); + } else if (is_conductor_i1min and i1 == i1_min + 1) { + array(i1, cur::jx1) = INV_2 * buffer(i1, cur::jx1) + + INV_4 * (buffer(i1 - 1, cur::jx1) + + buffer(i1 + 1, cur::jx1)); + array(i1, cur::jx2) = (INV_2)*buffer(i1, cur::jx2) + + (INV_4)*buffer(i1 + 1, cur::jx2); + array(i1, cur::jx3) = (INV_2)*buffer(i1, cur::jx3) + + (INV_4)*buffer(i1 + 1, cur::jx3); + } else { #pragma unroll - for (const auto& comp : { cur::jx1, cur::jx2, cur::jx3 }) { - array(i1, comp) = INV_2 * buffer(i1, comp) + - INV_4 * (buffer(i1 - 1, comp) + buffer(i1 + 1, comp)); + for (const auto& comp : { cur::jx1, cur::jx2, cur::jx3 }) { + array(i1, comp) = INV_2 * buffer(i1, comp) + + INV_4 * + (buffer(i1 - 1, comp) + buffer(i1 + 1, comp)); + } } } else { raise::KernelError(HERE, "DigitalFilter_kernel: 1D implementation called for D != 1 or for non-Cartesian metric"); @@ -62,25 +81,49 @@ namespace kernel { Inline void operator()(index_t i1, index_t i2) const { if constexpr (D == Dim::_2D) { if constexpr (C == Coord::Cart) { + if (is_conductor_i1min and i1 == i1_min) { + array(i1, i2, cur::jx1) = + (THREE * INV_4) * (FILTER2D_IN_I2(buffer, cur::jx1, i1, i2)) + + (INV_4) * (FILTER2D_IN_I2(buffer, cur::jx1, i1 + 1, i2)); + } else if (is_conductor_i1min and i1 == i1_min + 1) { + array(i1, + i2, + cur::jx1) = INV_2 * (FILTER2D_IN_I2(buffer, cur::jx1, i1, i2)) + + INV_4 * + ((FILTER2D_IN_I2(buffer, cur::jx1, i1 - 1, i2)) + + (FILTER2D_IN_I2(buffer, cur::jx1, i1 + 1, i2))); + array(i1, + i2, + cur::jx2) = INV_2 * (FILTER2D_IN_I2(buffer, cur::jx2, i1, i2)) + + INV_4 * + (FILTER2D_IN_I2(buffer, cur::jx2, i1 + 1, i2)); + array(i1, + i2, + cur::jx3) = INV_2 * (FILTER2D_IN_I2(buffer, cur::jx3, i1, i2)) + + INV_4 * + (FILTER2D_IN_I2(buffer, cur::jx3, i1 + 1, i2)); + } else { #pragma unroll - for (const auto comp : { cur::jx1, cur::jx2, cur::jx3 }) { - array(i1, i2, comp) = INV_4 * buffer(i1, i2, comp) + - INV_8 * (buffer(i1 - 1, i2, comp) + - buffer(i1 + 1, i2, comp) + - buffer(i1, i2 - 1, comp) + - buffer(i1, i2 + 1, comp)) + - INV_16 * (buffer(i1 - 1, i2 - 1, comp) + - buffer(i1 + 1, i2 + 1, comp) + - buffer(i1 - 1, i2 + 1, comp) + - buffer(i1 + 1, i2 - 1, comp)); + for (const auto comp : { cur::jx1, cur::jx2, cur::jx3 }) { + array(i1, i2, comp) = INV_4 * buffer(i1, i2, comp) + + INV_8 * (buffer(i1 - 1, i2, comp) + + buffer(i1 + 1, i2, comp) + + buffer(i1, i2 - 1, comp) + + buffer(i1, i2 + 1, comp)) + + INV_16 * (buffer(i1 - 1, i2 - 1, comp) + + buffer(i1 + 1, i2 + 1, comp) + + buffer(i1 - 1, i2 + 1, comp) + + buffer(i1 + 1, i2 - 1, comp)); + } } } else { // spherical + // @TODO: get rid of temporary variables real_t cur_00, cur_0p1, cur_0m1; if (is_axis_i2min && (i2 == i2_min)) { /* --------------------------------- r, phi --------------------------------- */ // ... filter in r - cur_00 = FILTER_IN_I1(buffer, cur::jx1, i1, i2); - cur_0p1 = FILTER_IN_I1(buffer, cur::jx1, i1, i2 + 1); + cur_00 = FILTER2D_IN_I1(buffer, cur::jx1, i1, i2); + cur_0p1 = FILTER2D_IN_I1(buffer, cur::jx1, i1, i2 + 1); // ... filter in theta array(i1, i2, cur::jx1) = INV_2 * cur_00 + INV_2 * cur_0p1; @@ -88,58 +131,58 @@ namespace kernel { /* ---------------------------------- theta --------------------------------- */ // ... filter in r - cur_00 = FILTER_IN_I1(buffer, cur::jx2, i1, i2); - cur_0p1 = FILTER_IN_I1(buffer, cur::jx2, i1, i2 + 1); + cur_00 = FILTER2D_IN_I1(buffer, cur::jx2, i1, i2); + cur_0p1 = FILTER2D_IN_I1(buffer, cur::jx2, i1, i2 + 1); // ... filter in theta array(i1, i2, cur::jx2) = INV_4 * (cur_00 + cur_0p1); } else if (is_axis_i2min && (i2 == i2_min + 1)) { /* --------------------------------- r, phi --------------------------------- */ // ... filter in r - cur_00 = FILTER_IN_I1(buffer, cur::jx1, i1, i2); - cur_0p1 = FILTER_IN_I1(buffer, cur::jx1, i1, i2 + 1); - cur_0m1 = FILTER_IN_I1(buffer, cur::jx1, i1, i2 - 1); + cur_00 = FILTER2D_IN_I1(buffer, cur::jx1, i1, i2); + cur_0p1 = FILTER2D_IN_I1(buffer, cur::jx1, i1, i2 + 1); + cur_0m1 = FILTER2D_IN_I1(buffer, cur::jx1, i1, i2 - 1); // ... filter in theta array(i1, i2, cur::jx1) = INV_2 * cur_00 + INV_4 * (cur_0p1 + cur_0m1); // ... filter in r - cur_00 = FILTER_IN_I1(buffer, cur::jx3, i1, i2); - cur_0p1 = FILTER_IN_I1(buffer, cur::jx3, i1, i2 + 1); + cur_00 = FILTER2D_IN_I1(buffer, cur::jx3, i1, i2); + cur_0p1 = FILTER2D_IN_I1(buffer, cur::jx3, i1, i2 + 1); // ... filter in theta array(i1, i2, cur::jx3) = INV_2 * cur_00 + INV_4 * cur_0p1; /* ---------------------------------- theta --------------------------------- */ // ... filter in r - cur_00 = FILTER_IN_I1(buffer, cur::jx2, i1, i2); - cur_0p1 = FILTER_IN_I1(buffer, cur::jx2, i1, i2 + 1); - cur_0m1 = FILTER_IN_I1(buffer, cur::jx2, i1, i2 - 1); + cur_00 = FILTER2D_IN_I1(buffer, cur::jx2, i1, i2); + cur_0p1 = FILTER2D_IN_I1(buffer, cur::jx2, i1, i2 + 1); + cur_0m1 = FILTER2D_IN_I1(buffer, cur::jx2, i1, i2 - 1); // ... filter in theta array(i1, i2, cur::jx2) = INV_2 * cur_00 + INV_4 * (cur_0m1 + cur_0p1); } else if (is_axis_i2max && (i2 == i2_max - 1)) { /* --------------------------------- r, phi --------------------------------- */ // ... filter in r - cur_00 = FILTER_IN_I1(buffer, cur::jx1, i1, i2); - cur_0p1 = FILTER_IN_I1(buffer, cur::jx1, i1, i2 + 1); - cur_0m1 = FILTER_IN_I1(buffer, cur::jx1, i1, i2 - 1); + cur_00 = FILTER2D_IN_I1(buffer, cur::jx1, i1, i2); + cur_0p1 = FILTER2D_IN_I1(buffer, cur::jx1, i1, i2 + 1); + cur_0m1 = FILTER2D_IN_I1(buffer, cur::jx1, i1, i2 - 1); // ... filter in theta array(i1, i2, cur::jx1) = INV_2 * cur_00 + INV_4 * (cur_0m1 + cur_0p1); // ... filter in r - cur_00 = FILTER_IN_I1(buffer, cur::jx3, i1, i2); - cur_0m1 = FILTER_IN_I1(buffer, cur::jx3, i1, i2 - 1); + cur_00 = FILTER2D_IN_I1(buffer, cur::jx3, i1, i2); + cur_0m1 = FILTER2D_IN_I1(buffer, cur::jx3, i1, i2 - 1); // ... filter in theta array(i1, i2, cur::jx3) = INV_2 * cur_00 + INV_4 * cur_0m1; /* ---------------------------------- theta --------------------------------- */ // ... filter in r - cur_00 = FILTER_IN_I1(buffer, cur::jx2, i1, i2); - cur_0m1 = FILTER_IN_I1(buffer, cur::jx2, i1, i2 - 1); + cur_00 = FILTER2D_IN_I1(buffer, cur::jx2, i1, i2); + cur_0m1 = FILTER2D_IN_I1(buffer, cur::jx2, i1, i2 - 1); // ... filter in theta array(i1, i2, cur::jx2) = INV_4 * (cur_00 + cur_0m1); } else if (is_axis_i2max && (i2 == i2_max)) { /* --------------------------------- r, phi --------------------------------- */ // ... filter in r - cur_00 = FILTER_IN_I1(buffer, cur::jx1, i1, i2); - cur_0m1 = FILTER_IN_I1(buffer, cur::jx1, i1, i2 - 1); + cur_00 = FILTER2D_IN_I1(buffer, cur::jx1, i1, i2); + cur_0m1 = FILTER2D_IN_I1(buffer, cur::jx1, i1, i2 - 1); // ... filter in theta array(i1, i2, cur::jx1) = INV_2 * cur_00 + INV_2 * cur_0m1; @@ -210,6 +253,6 @@ namespace kernel { } // namespace kernel -#undef FILTER_IN_I1 +#undef FILTER2D_IN_I1 #endif // DIGITAL_FILTER_HPP From 81d51f99f1c7d1b1b293ddbeda575f03c45e5aeb Mon Sep 17 00:00:00 2001 From: hayk Date: Sat, 8 Mar 2025 16:16:31 -0500 Subject: [PATCH 546/773] filter test fixed --- src/kernels/tests/digital_filter.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/kernels/tests/digital_filter.cpp b/src/kernels/tests/digital_filter.cpp index e0cc352f5..03a63753b 100644 --- a/src/kernels/tests/digital_filter.cpp +++ b/src/kernels/tests/digital_filter.cpp @@ -40,8 +40,13 @@ void testFilter(const std::vector& res, auto boundaries = boundaries_t {}; if constexpr (M::CoordType != Coord::Cart) { boundaries = { - {FldsBC::CUSTOM, FldsBC::CUSTOM}, - { FldsBC::AXIS, FldsBC::AXIS} + { FldsBC::CUSTOM, FldsBC::CUSTOM }, + { FldsBC::AXIS, FldsBC::AXIS } + }; + } else { + boundaries = { + { FldsBC::PERIODIC, FldsBC::PERIODIC }, + { FldsBC::PERIODIC, FldsBC::PERIODIC } }; } @@ -183,4 +188,4 @@ auto main(int argc, char* argv[]) -> int { } Kokkos::finalize(); return 0; -} \ No newline at end of file +} From 8bb8428204469b52823347b3ab84aed2254475b3 Mon Sep 17 00:00:00 2001 From: hayk Date: Sun, 9 Mar 2025 01:59:57 -0500 Subject: [PATCH 547/773] removed extra kokkos flags --- cmake/kokkosConfig.cmake | 35 ----------------- legacy/tests/kernels-sr.cpp | 10 ++--- src/framework/containers/particles.cpp | 2 +- src/framework/domain/comm_mpi.hpp | 12 +++--- src/framework/domain/comm_nompi.hpp | 6 +-- src/global/arch/kokkos_aliases.cpp | 54 +++++++++++++------------- src/global/arch/kokkos_aliases.h | 18 ++++----- src/kernels/tests/prtls_to_phys.cpp | 45 ++++++++++----------- 8 files changed, 75 insertions(+), 107 deletions(-) diff --git a/cmake/kokkosConfig.cmake b/cmake/kokkosConfig.cmake index 63c32622d..8800f21a0 100644 --- a/cmake/kokkosConfig.cmake +++ b/cmake/kokkosConfig.cmake @@ -37,41 +37,6 @@ set(Kokkos_ENABLE_OPENMP ${default_KOKKOS_ENABLE_OPENMP} CACHE BOOL "Enable OpenMP") -# set memory space -if(${Kokkos_ENABLE_CUDA}) - add_compile_definitions(CUDA_ENABLED) - set(ACC_MEM_SPACE Kokkos::CudaSpace) -elseif(${Kokkos_ENABLE_HIP}) - add_compile_definitions(HIP_ENABLED) - set(ACC_MEM_SPACE Kokkos::HIPSpace) -else() - set(ACC_MEM_SPACE Kokkos::HostSpace) -endif() - -set(HOST_MEM_SPACE Kokkos::HostSpace) - -# set execution space -if(${Kokkos_ENABLE_CUDA}) - set(ACC_EXE_SPACE Kokkos::Cuda) -elseif(${Kokkos_ENABLE_HIP}) - set(ACC_EXE_SPACE Kokkos::HIP) -elseif(${Kokkos_ENABLE_OPENMP}) - set(ACC_EXE_SPACE Kokkos::OpenMP) -else() - set(ACC_EXE_SPACE Kokkos::Serial) -endif() - -if(${Kokkos_ENABLE_OPENMP}) - set(HOST_EXE_SPACE Kokkos::OpenMP) -else() - set(HOST_EXE_SPACE Kokkos::Serial) -endif() - -add_compile_options("-D AccelExeSpace=${ACC_EXE_SPACE}") -add_compile_options("-D AccelMemSpace=${ACC_MEM_SPACE}") -add_compile_options("-D HostExeSpace=${HOST_EXE_SPACE}") -add_compile_options("-D HostMemSpace=${HOST_MEM_SPACE}") - if(${BUILD_TESTING} STREQUAL "OFF") set(Kokkos_ENABLE_TESTS OFF diff --git a/legacy/tests/kernels-sr.cpp b/legacy/tests/kernels-sr.cpp index 59ce0646b..d765799e3 100644 --- a/legacy/tests/kernels-sr.cpp +++ b/legacy/tests/kernels-sr.cpp @@ -1,17 +1,17 @@ -#include "wrapper.h" - #include #include #include +#include "wrapper.h" + #include METRIC_HEADER #include PGEN_HEADER -#include "particle_macros.h" - #include "kernels/particle_pusher_sr.hpp" +#include "particle_macros.h" + template void put_value(ntt::array_t& arr, T value, int i) { auto arr_h = Kokkos::create_mirror_view(arr); @@ -221,4 +221,4 @@ auto main(int argc, char* argv[]) -> int { ntt::GlobalFinalize(); return 0; -} \ No newline at end of file +} diff --git a/src/framework/containers/particles.cpp b/src/framework/containers/particles.cpp index 048d57cde..634a34862 100644 --- a/src/framework/containers/particles.cpp +++ b/src/framework/containers/particles.cpp @@ -224,7 +224,7 @@ namespace ntt { Kokkos::Experimental::fill( "TagDeadParticles", - AccelExeSpace(), + Kokkos::DefaultExecutionSpace(), Kokkos::subview(this_tag, std::make_pair(n_alive, n_alive + n_dead)), ParticleTag::dead); diff --git a/src/framework/domain/comm_mpi.hpp b/src/framework/domain/comm_mpi.hpp index 8c6e532de..4f382be4a 100644 --- a/src/framework/domain/comm_mpi.hpp +++ b/src/framework/domain/comm_mpi.hpp @@ -83,7 +83,7 @@ namespace comm { (long int)(send_slice[0].first); Kokkos::parallel_for( "CommunicateField-extract", - Kokkos::MDRangePolicy, AccelExeSpace>( + Kokkos::MDRangePolicy, Kokkos::DefaultExecutionSpace>( { recv_slice[0].first, comps.first }, { recv_slice[0].second, comps.second }), Lambda(index_t i1, index_t ci) { @@ -96,7 +96,7 @@ namespace comm { (long int)(send_slice[1].first); Kokkos::parallel_for( "CommunicateField-extract", - Kokkos::MDRangePolicy, AccelExeSpace>( + Kokkos::MDRangePolicy, Kokkos::DefaultExecutionSpace>( { recv_slice[0].first, recv_slice[1].first, comps.first }, { recv_slice[0].second, recv_slice[1].second, comps.second }), Lambda(index_t i1, index_t i2, index_t ci) { @@ -111,7 +111,7 @@ namespace comm { (long int)(send_slice[2].first); Kokkos::parallel_for( "CommunicateField-extract", - Kokkos::MDRangePolicy, AccelExeSpace>( + Kokkos::MDRangePolicy, Kokkos::DefaultExecutionSpace>( { recv_slice[0].first, recv_slice[1].first, recv_slice[2].first, @@ -239,7 +239,7 @@ namespace comm { const auto offset_c = comps.first; Kokkos::parallel_for( "CommunicateField-extract", - Kokkos::MDRangePolicy, AccelExeSpace>( + Kokkos::MDRangePolicy, Kokkos::DefaultExecutionSpace>( { recv_slice[0].first, comps.first }, { recv_slice[0].second, comps.second }), Lambda(index_t i1, index_t ci) { @@ -251,7 +251,7 @@ namespace comm { const auto offset_c = comps.first; Kokkos::parallel_for( "CommunicateField-extract", - Kokkos::MDRangePolicy, AccelExeSpace>( + Kokkos::MDRangePolicy, Kokkos::DefaultExecutionSpace>( { recv_slice[0].first, recv_slice[1].first, comps.first }, { recv_slice[0].second, recv_slice[1].second, comps.second }), Lambda(index_t i1, index_t i2, index_t ci) { @@ -266,7 +266,7 @@ namespace comm { const auto offset_c = comps.first; Kokkos::parallel_for( "CommunicateField-extract", - Kokkos::MDRangePolicy, AccelExeSpace>( + Kokkos::MDRangePolicy, Kokkos::DefaultExecutionSpace>( { recv_slice[0].first, recv_slice[1].first, recv_slice[2].first, diff --git a/src/framework/domain/comm_nompi.hpp b/src/framework/domain/comm_nompi.hpp index 197d336fa..b477ac176 100644 --- a/src/framework/domain/comm_nompi.hpp +++ b/src/framework/domain/comm_nompi.hpp @@ -70,7 +70,7 @@ namespace comm { (long int)(send_slice[0].first); Kokkos::parallel_for( "CommunicateField-extract", - Kokkos::MDRangePolicy, AccelExeSpace>( + Kokkos::MDRangePolicy, Kokkos::DefaultExecutionSpace>( { recv_slice[0].first, comps.first }, { recv_slice[0].second, comps.second }), Lambda(index_t i1, index_t ci) { @@ -83,7 +83,7 @@ namespace comm { (long int)(send_slice[1].first); Kokkos::parallel_for( "CommunicateField-extract", - Kokkos::MDRangePolicy, AccelExeSpace>( + Kokkos::MDRangePolicy, Kokkos::DefaultExecutionSpace>( { recv_slice[0].first, recv_slice[1].first, comps.first }, { recv_slice[0].second, recv_slice[1].second, comps.second }), Lambda(index_t i1, index_t i2, index_t ci) { @@ -98,7 +98,7 @@ namespace comm { (long int)(send_slice[2].first); Kokkos::parallel_for( "CommunicateField-extract", - Kokkos::MDRangePolicy, AccelExeSpace>( + Kokkos::MDRangePolicy, Kokkos::DefaultExecutionSpace>( { recv_slice[0].first, recv_slice[1].first, recv_slice[2].first, diff --git a/src/global/arch/kokkos_aliases.cpp b/src/global/arch/kokkos_aliases.cpp index d6622b0e5..25397af8e 100644 --- a/src/global/arch/kokkos_aliases.cpp +++ b/src/global/arch/kokkos_aliases.cpp @@ -9,73 +9,75 @@ auto CreateParticleRangePolicy(npart_t p1, npart_t p2) -> range_t { } template <> -auto CreateRangePolicy( - const tuple_t& i1, - const tuple_t& i2) -> range_t { +auto CreateRangePolicy(const tuple_t& i1, + const tuple_t& i2) + -> range_t { index_t i1min = i1[0]; index_t i1max = i2[0]; - return Kokkos::RangePolicy(i1min, i1max); + return Kokkos::RangePolicy(i1min, i1max); } template <> -auto CreateRangePolicy( - const tuple_t& i1, - const tuple_t& i2) -> range_t { +auto CreateRangePolicy(const tuple_t& i1, + const tuple_t& i2) + -> range_t { index_t i1min = i1[0]; index_t i1max = i2[0]; index_t i2min = i1[1]; index_t i2max = i2[1]; - return Kokkos::MDRangePolicy, AccelExeSpace>({ i1min, i2min }, - { i1max, i2max }); + return Kokkos::MDRangePolicy, Kokkos::DefaultExecutionSpace>( + { i1min, i2min }, + { i1max, i2max }); } template <> -auto CreateRangePolicy( - const tuple_t& i1, - const tuple_t& i2) -> range_t { +auto CreateRangePolicy(const tuple_t& i1, + const tuple_t& i2) + -> range_t { index_t i1min = i1[0]; index_t i1max = i2[0]; index_t i2min = i1[1]; index_t i2max = i2[1]; index_t i3min = i1[2]; index_t i3max = i2[2]; - return Kokkos::MDRangePolicy, AccelExeSpace>( + return Kokkos::MDRangePolicy, Kokkos::DefaultExecutionSpace>( { i1min, i2min, i3min }, { i1max, i2max, i3max }); } template <> -auto CreateRangePolicyOnHost( - const tuple_t& i1, - const tuple_t& i2) -> range_h_t { +auto CreateRangePolicyOnHost(const tuple_t& i1, + const tuple_t& i2) + -> range_h_t { index_t i1min = i1[0]; index_t i1max = i2[0]; - return Kokkos::RangePolicy(i1min, i1max); + return Kokkos::RangePolicy(i1min, i1max); } template <> -auto CreateRangePolicyOnHost( - const tuple_t& i1, - const tuple_t& i2) -> range_h_t { +auto CreateRangePolicyOnHost(const tuple_t& i1, + const tuple_t& i2) + -> range_h_t { index_t i1min = i1[0]; index_t i1max = i2[0]; index_t i2min = i1[1]; index_t i2max = i2[1]; - return Kokkos::MDRangePolicy, HostExeSpace>({ i1min, i2min }, - { i1max, i2max }); + return Kokkos::MDRangePolicy, Kokkos::DefaultHostExecutionSpace>( + { i1min, i2min }, + { i1max, i2max }); } template <> -auto CreateRangePolicyOnHost( - const tuple_t& i1, - const tuple_t& i2) -> range_h_t { +auto CreateRangePolicyOnHost(const tuple_t& i1, + const tuple_t& i2) + -> range_h_t { index_t i1min = i1[0]; index_t i1max = i2[0]; index_t i2min = i1[1]; index_t i2max = i2[1]; index_t i3min = i1[2]; index_t i3max = i2[2]; - return Kokkos::MDRangePolicy, HostExeSpace>( + return Kokkos::MDRangePolicy, Kokkos::DefaultHostExecutionSpace>( { i1min, i2min, i3min }, { i1max, i2max, i3max }); } diff --git a/src/global/arch/kokkos_aliases.h b/src/global/arch/kokkos_aliases.h index e1a759bed..adb0b6451 100644 --- a/src/global/arch/kokkos_aliases.h +++ b/src/global/arch/kokkos_aliases.h @@ -34,7 +34,7 @@ namespace math = Kokkos; template -using array_t = Kokkos::View; +using array_t = Kokkos::View; // Array mirror alias of arbitrary type template @@ -174,17 +174,17 @@ namespace kokkos_aliases_hidden { template <> struct range_impl { - using type = Kokkos::RangePolicy; + using type = Kokkos::RangePolicy; }; template <> struct range_impl { - using type = Kokkos::MDRangePolicy, AccelExeSpace>; + using type = Kokkos::MDRangePolicy, Kokkos::DefaultExecutionSpace>; }; template <> struct range_impl { - using type = Kokkos::MDRangePolicy, AccelExeSpace>; + using type = Kokkos::MDRangePolicy, Kokkos::DefaultExecutionSpace>; }; } // namespace kokkos_aliases_hidden @@ -201,17 +201,17 @@ namespace kokkos_aliases_hidden { template <> struct range_h_impl { - using type = Kokkos::RangePolicy; + using type = Kokkos::RangePolicy; }; template <> struct range_h_impl { - using type = Kokkos::MDRangePolicy, HostExeSpace>; + using type = Kokkos::MDRangePolicy, Kokkos::DefaultHostExecutionSpace>; }; template <> struct range_h_impl { - using type = Kokkos::MDRangePolicy, HostExeSpace>; + using type = Kokkos::MDRangePolicy, Kokkos::DefaultHostExecutionSpace>; }; } // namespace kokkos_aliases_hidden @@ -249,8 +249,8 @@ auto CreateRangePolicyOnHost(const tuple_t&, const tuple_t&) -> range_h_t; // Random number pool/generator type alias -using random_number_pool_t = Kokkos::Random_XorShift1024_Pool; -using random_generator_t = typename random_number_pool_t::generator_type; +using random_number_pool_t = Kokkos::Random_XorShift1024_Pool; +using random_generator_t = typename random_number_pool_t::generator_type; // Random number generator functions template diff --git a/src/kernels/tests/prtls_to_phys.cpp b/src/kernels/tests/prtls_to_phys.cpp index 4719fe6a1..0ceb88cd1 100644 --- a/src/kernels/tests/prtls_to_phys.cpp +++ b/src/kernels/tests/prtls_to_phys.cpp @@ -177,28 +177,29 @@ void testPrtl2PhysSR(const std::vector& res, array_t buff_ux3 { "buff_ux3", nprtl / stride }; array_t buff_wei { "buff_wei", nprtl / stride }; - Kokkos::parallel_for("Init", - Kokkos::RangePolicy(0, nprtl / stride), - kernel::PrtlToPhys_kernel(stride, - buff_x1, - buff_x2, - buff_x3, - buff_ux1, - buff_ux2, - buff_ux3, - buff_wei, - i1, - i2, - i3, - dx1, - dx2, - dx3, - ux1, - ux2, - ux3, - phi, - weight, - metric)); + Kokkos::parallel_for( + "Init", + Kokkos::RangePolicy(0, nprtl / stride), + kernel::PrtlToPhys_kernel(stride, + buff_x1, + buff_x2, + buff_x3, + buff_ux1, + buff_ux2, + buff_ux3, + buff_wei, + i1, + i2, + i3, + dx1, + dx2, + dx3, + ux1, + ux2, + ux3, + phi, + weight, + metric)); Kokkos::parallel_for("Check", nprtl / stride, Checker(metric, From b167d373c568f8e66597bac3b97a6d68061f345a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20B=C3=B6ss?= Date: Fri, 7 Mar 2025 20:26:49 -0600 Subject: [PATCH 548/773] revert to old pgen for testing --- setups/srpic/shocktest/pgen.hpp | 171 +++++++++++++++++++++++--------- 1 file changed, 125 insertions(+), 46 deletions(-) diff --git a/setups/srpic/shocktest/pgen.hpp b/setups/srpic/shocktest/pgen.hpp index 4f6decc76..ff54923d1 100644 --- a/setups/srpic/shocktest/pgen.hpp +++ b/setups/srpic/shocktest/pgen.hpp @@ -38,20 +38,15 @@ namespace user { // magnetic field components Inline auto bx1(const coord_t& x_ph) const -> real_t { - // return Bmag * math::cos(Btheta); - return ZERO; + return Bmag * math::cos(Btheta); } Inline auto bx2(const coord_t& x_ph) const -> real_t { - // return Bmag * math::sin(Btheta) * math::sin(Bphi); - return ZERO; + return Bmag * math::sin(Btheta) * math::sin(Bphi); } Inline auto bx3(const coord_t& x_ph) const -> real_t { - // return Bmag * math::sin(Btheta) * math::cos(Bphi); - // return ONE + 0.01 * (ONE - math::tanh(20.*(-1.5 + x_ph[0]))*math::tanh(20.*(-0.5 - // + x_ph[0])))/2.0 * math::sin(4.0 * constant::PI * x_ph[0]); - return ZERO; + return Bmag * math::sin(Btheta) * math::cos(Bphi); } // electric field components @@ -60,15 +55,11 @@ namespace user { } Inline auto ex2(const coord_t& x_ph) const -> real_t { - // return -Vx * Bmag * math::sin(Btheta) * math::cos(Bphi); - // return ZERO - 0.01 * (ONE - math::tanh(20.*(-1.5 + x_ph[0]))*math::tanh(20.*(-0.5 - // + x_ph[0])))/2.0 * math::sin(4.0 * constant::PI * x_ph[0]); - return ZERO; + return -Vx * Bmag * math::sin(Btheta) * math::cos(Bphi); } Inline auto ex3(const coord_t& x_ph) const -> real_t { - // return Vx * Bmag * math::sin(Btheta) * math::sin(Bphi); - return ZERO; + return Vx * Bmag * math::sin(Btheta) * math::sin(Bphi); } private: @@ -102,16 +93,16 @@ namespace user { : arch::ProblemGenerator { p } , drift_ux { p.template get("setup.drift_ux") } , temperature { p.template get("setup.temperature") } - , x1arr_e { p.template get>("setup.x_e") } - , x2arr_e { p.template get>("setup.y_e") } - , ux1arr_e { p.template get>("setup.ux_e") } - , ux2arr_e { p.template get>("setup.uy_e") } - , ux3arr_e { p.template get>("setup.uz_e") } - , x1arr_i { p.template get>("setup.x_i") } - , x2arr_i { p.template get>("setup.y_i") } - , ux1arr_i { p.template get>("setup.ux_i") } - , ux2arr_i { p.template get>("setup.uy_i") } - , ux3arr_i { p.template get>("setup.uz_i") } + // , x1arr_e { p.template get>("setup.x_e") } + // , x2arr_e { p.template get>("setup.y_e") } + // , ux1arr_e { p.template get>("setup.ux_e") } + // , ux2arr_e { p.template get>("setup.uy_e") } + // , ux3arr_e { p.template get>("setup.uz_e") } + // , x1arr_i { p.template get>("setup.x_i") } + // , x2arr_i { p.template get>("setup.y_i") } + // , ux1arr_i { p.template get>("setup.ux_i") } + // , ux2arr_i { p.template get>("setup.uy_i") } + // , ux3arr_i { p.template get>("setup.uz_i") } , Btheta { p.template get("setup.Btheta", ZERO) } , Bmag { p.template get("setup.Bmag", ZERO) } , Bphi { p.template get("setup.Bphi", ZERO) } @@ -135,28 +126,116 @@ namespace user { return init_flds; } - inline void InitPrtls(Domain& domain) { - arch::InjectGlobally(*metadomain, - domain, - 1, - { - { "x1", x1arr_e }, - { "x2", x2arr_e }, - { "ux1", ux1arr_e }, - { "ux2", ux1arr_e }, - { "ux3", ux3arr_e } - }); - arch::InjectGlobally(*metadomain, - domain, - 2, - { - { "x1", x1arr_i }, - { "x2", x2arr_i }, - { "ux1", ux1arr_i }, - { "ux2", ux1arr_i }, - { "ux3", ux3arr_i } - }); - } + // inline void InitPrtls(Domain& domain) { + // arch::InjectGlobally(*metadomain, + // domain, + // 1, + // { + // { "x1", x1arr_e }, + // { "x2", x2arr_e }, + // { "ux1", ux1arr_e }, + // { "ux2", ux1arr_e }, + // { "ux3", ux3arr_e } + // }); + // arch::InjectGlobally(*metadomain, + // domain, + // 2, + // { + // { "x1", x1arr_i }, + // { "x2", x2arr_i }, + // { "ux1", ux1arr_i }, + // { "ux2", ux1arr_i }, + // { "ux3", ux3arr_i } + // }); + // } + + inline void InitPrtls(Domain& domain) { + + // auto& species_e = domain.species[0]; + // auto& species_p = domain.species[1]; + auto& species_e = domain.species[0]; + auto& species_p = domain.species[1]; + + // array_t elec_ind("elec_ind"); + // array_t pos_ind("pos_ind"); + array_t elec_ind("elec_ind"); + array_t pos_ind("pos_ind"); + + auto offset_e = species_e.npart(); + auto offset_p = species_p.npart(); + + auto ux1_e = species_e.ux1; + auto ux2_e = species_e.ux2; + auto ux3_e = species_e.ux3; + auto i1_e = species_e.i1; + auto i2_e = species_e.i2; + auto dx1_e = species_e.dx1; + auto dx2_e = species_e.dx2; + auto phi_e = species_e.phi; + auto weight_e = species_e.weight; + auto tag_e = species_e.tag; + + auto ux1_p = species_p.ux1; + auto ux2_p = species_p.ux2; + auto ux3_p = species_p.ux3; + auto i1_p = species_p.i1; + auto i2_p = species_p.i2; + auto dx1_p = species_p.dx1; + auto dx2_p = species_p.dx2; + auto phi_p = species_p.phi; + auto weight_p = species_p.weight; + auto tag_p = species_p.tag; + + int nseed = 1; + + Kokkos::parallel_for("init_particles", nseed, KOKKOS_LAMBDA(const int& s) { + + // ToDo: fix this + auto i1_ = math::floor(10); + auto i2_ = math::floor(64); + auto dx1_ = HALF; + auto dx2_ = HALF; + + + auto elec_p = Kokkos::atomic_fetch_add(&elec_ind(), 1); + auto pos_p = Kokkos::atomic_fetch_add(&pos_ind(), 1); + + i1_e(elec_p + offset_e) = i1_; + dx1_e(elec_p + offset_e) = dx1_; + i2_e(elec_p + offset_e) = i2_; + dx2_e(elec_p + offset_e) = 2*dx2_; + // ux1_e(elec_p + offset_e) = -0.5; + // ux2_e(elec_p + offset_e) = 0.5; + ux1_e(elec_p + offset_e) = -drift_ux; + ux2_e(elec_p + offset_e) = ZERO; + ux3_e(elec_p + offset_e) = ZERO; + weight_e(elec_p + offset_e) = ONE; + tag_e(elec_p + offset_e) = ParticleTag::alive; + + i1_p(pos_p + offset_p) = i1_; + dx1_p(pos_p + offset_p) = dx1_; + i2_p(pos_p + offset_p) = i2_; + dx2_p(pos_p + offset_p) = -2*dx2_; + // ux1_p(pos_p + offset_p) = 0.5; + // ux2_p(pos_p + offset_p) = -0.5; + ux1_p(pos_p + offset_p) = -drift_ux; + ux2_p(pos_p + offset_p) = ZERO; + ux3_p(pos_p + offset_p) = ZERO; + weight_p(pos_p + offset_p) = ONE; + tag_p(pos_p + offset_p) = ParticleTag::alive; + + + }); + + + auto elec_ind_h = Kokkos::create_mirror(elec_ind); + Kokkos::deep_copy(elec_ind_h, elec_ind); + species_e.set_npart(offset_e + elec_ind_h()); + + auto pos_ind_h = Kokkos::create_mirror(pos_ind); + Kokkos::deep_copy(pos_ind_h, pos_ind); + species_p.set_npart(offset_p + pos_ind_h()); + } }; } // namespace user From ec88a4fa8f0e16118cfd08bdcab9dd80546a15f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20B=C3=B6ss?= Date: Fri, 7 Mar 2025 21:26:16 -0600 Subject: [PATCH 549/773] enforce B0/E0 at boundary --- src/engines/srpic.hpp | 52 -------------------------------------- src/kernels/fields_bcs.hpp | 33 +++++++++++++++--------- 2 files changed, 21 insertions(+), 64 deletions(-) diff --git a/src/engines/srpic.hpp b/src/engines/srpic.hpp index f75989739..b1fca46da 100644 --- a/src/engines/srpic.hpp +++ b/src/engines/srpic.hpp @@ -854,19 +854,6 @@ namespace ntt { } else { const auto sign = direction.get_sign(); const auto dim = direction.get_dim(); -<<<<<<< HEAD -||||||| parent of bd723f39 (minor reformatting of conductor BC) - const auto sign = direction.get_sign(); - const auto dim = direction.get_dim(); - raise::ErrorIf(dim != in::x1 and M::CoordType != Coord::Cart, - "Perfect conductor BCs only implemented for x1 in " - "non-cartesian coordinates", - HERE); -======= - raise::ErrorIf(dim != in::x1, - "Perfect conductor BCs only implemented for x1", - HERE); ->>>>>>> bd723f39 (minor reformatting of conductor BC) std::vector xi_min, xi_max; @@ -876,13 +863,7 @@ namespace ntt { const auto dd = all_dirs[d]; if (dim == dd) { xi_min.push_back(0); -<<<<<<< HEAD xi_max.push_back((sign < 0) ? (N_GHOSTS + 1) : N_GHOSTS); -||||||| parent of bd723f39 (minor reformatting of conductor BC) - xi_max.push_back(N_GHOSTS); -======= - xi_max.push_back(N_GHOSTS + 1); ->>>>>>> bd723f39 (minor reformatting of conductor BC) } else { xi_min.push_back(0); xi_max.push_back(domain.mesh.n_all(dd)); @@ -905,7 +886,6 @@ namespace ntt { } else { raise::Error("Invalid dimension", HERE); } -<<<<<<< HEAD if (dim == in::x1) { if (sign > 0) { @@ -956,38 +936,6 @@ namespace ntt { tags)); } } -||||||| parent of bd723f39 (minor reformatting of conductor BC) -======= - Kokkos::parallel_for( - "MatchFields", - range, - kernel::bc::ConductorBoundaries_kernel(domain.fields.em, - tags)); - - // if constexpr (M::Dim == Dim::_1D) { - // Kokkos::parallel_for( - // "MatchFields", - // CreateRangePolicy({ xi_min[0] }, { xi_max[0] }), - // kernel::bc::ConductorBoundaries_kernel(domain.fields.em, - // tags)); - // } else if constexpr (M::Dim == Dim::_2D) { - // Kokkos::parallel_for( - // "MatchFields", - // CreateRangePolicy({ xi_min[0], xi_min[1] }, - // { xi_max[0], xi_max[1] }), - // kernel::bc::ConductorBoundaries_kernel(domain.fields.em, - // tags)); - // } else if constexpr (M::Dim == Dim::_3D) { - // Kokkos::parallel_for( - // "MatchFields", - // CreateRangePolicy({ xi_min[0], xi_min[1], xi_min[2] }, - // { xi_max[0], xi_max[1], xi_max[2] }), - // kernel::bc::ConductorBoundaries_kernel(domain.fields.em, - // tags)); - // } else { - // raise::Error("Invalid dimension", HERE); - // } ->>>>>>> bd723f39 (minor reformatting of conductor BC) } } diff --git a/src/kernels/fields_bcs.hpp b/src/kernels/fields_bcs.hpp index 901f8e02a..dd926580d 100644 --- a/src/kernels/fields_bcs.hpp +++ b/src/kernels/fields_bcs.hpp @@ -486,25 +486,32 @@ namespace kernel::bc { } }; - template + template struct ConductorBoundaries_kernel { static_assert(static_cast(o) < static_cast(D), "Invalid component index"); - // static constexpr idx_t i = static_cast(o) + 1u; + static constexpr bool defines_ex2 = traits::has_method::value; + static constexpr bool defines_ex3 = traits::has_method::value; + static constexpr bool defines_bx1 = traits::has_method::value; + static_assert(( defines_ex2 or defines_ex3 or defines_bx1), + "none of the components of E or B are specified in PGEN"); ndfield_t Fld; + const I fset; const BCTags tags; - ConductorBoundaries_kernel(ndfield_t Fld, BCTags tags) + ConductorBoundaries_kernel(ndfield_t Fld, const I& fset, BCTags tags) : Fld { Fld } + , fset { fset } , tags { tags } {} Inline void operator()(index_t i1) const { if constexpr (D == Dim::_1D) { + coord_t x_Ph_H { ZERO }; if (tags & BC::E) { if (i1 == 0) { - Fld(N_GHOSTS, em::ex2) = ZERO; - Fld(N_GHOSTS, em::ex3) = ZERO; + Fld(N_GHOSTS, em::ex2) = fset.ex2(x_Ph_H); + Fld(N_GHOSTS, em::ex3) = fset.ex3(x_Ph_H); } else { Fld(N_GHOSTS - i1, em::ex1) = Fld(N_GHOSTS + i1 - 1, em::ex1); Fld(N_GHOSTS - i1, em::ex2) = -Fld(N_GHOSTS + i1, em::ex2); @@ -514,7 +521,7 @@ namespace kernel::bc { if (tags & BC::B) { if (i1 == 0) { - Fld(N_GHOSTS, em::bx1) = ZERO; + Fld(N_GHOSTS, em::bx1) = fset.bx1(x_Ph_H); } else { Fld(N_GHOSTS - i1, em::bx1) = -Fld(N_GHOSTS + i1, em::bx1); Fld(N_GHOSTS - i1, em::bx2) = Fld(N_GHOSTS + i1 - 1, em::bx2); @@ -530,10 +537,11 @@ namespace kernel::bc { Inline void operator()(index_t i1, index_t i2) const { if constexpr (D == Dim::_2D) { + coord_t x_Ph_H { ZERO }; if (tags & BC::E) { if (i1 == 0) { - Fld(N_GHOSTS, i2, em::ex2) = ZERO; - Fld(N_GHOSTS, i2, em::ex3) = ZERO; + Fld(N_GHOSTS, i2, em::ex2) = fset.ex2(x_Ph_H); + Fld(N_GHOSTS, i2, em::ex3) = fset.ex3(x_Ph_H); } else { Fld(N_GHOSTS - i1, i2, em::ex1) = Fld(N_GHOSTS + i1 - 1, i2, em::ex1); Fld(N_GHOSTS - i1, i2, em::ex2) = -Fld(N_GHOSTS + i1, i2, em::ex2); @@ -543,7 +551,7 @@ namespace kernel::bc { if (tags & BC::B) { if (i1 == 0) { - Fld(N_GHOSTS, i2, em::bx1) = ZERO; + Fld(N_GHOSTS, i2, em::bx1) = fset.bx1(x_Ph_H); } else { Fld(N_GHOSTS - i1, i2, em::bx1) = -Fld(N_GHOSTS + i1, i2, em::bx1); Fld(N_GHOSTS - i1, i2, em::bx2) = Fld(N_GHOSTS + i1 - 1, i2, em::bx2); @@ -559,10 +567,11 @@ namespace kernel::bc { Inline void operator()(index_t i1, index_t i2, index_t i3) const { if constexpr (D == Dim::_3D) { + coord_t x_Ph_H { ZERO }; if (tags & BC::E) { if (i1 == 0) { - Fld(N_GHOSTS, i2, i3, em::ex2) = ZERO; - Fld(N_GHOSTS, i2, i3, em::ex3) = ZERO; + Fld(N_GHOSTS, i2, i3, em::ex2) = fset.ex2(x_Ph_H); + Fld(N_GHOSTS, i2, i3, em::ex3) = fset.ex3(x_Ph_H); } else { Fld(N_GHOSTS - i1, i2, i3, em::ex1) = Fld(N_GHOSTS + i1 - 1, i2, @@ -575,7 +584,7 @@ namespace kernel::bc { if (tags & BC::B) { if (i1 == 0) { - Fld(N_GHOSTS, i2, i3, em::bx1) = ZERO; + Fld(N_GHOSTS, i2, i3, em::bx1) = fset.bx1(x_Ph_H); } else { Fld(N_GHOSTS - i1, i2, i3, em::bx1) = -Fld(N_GHOSTS + i1, i2, i3, em::bx1); Fld(N_GHOSTS - i1, i2, i3, em::bx2) = Fld(N_GHOSTS + i1 - 1, From 680b950db0a8bdaf88d75c405296024daf116790 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20B=C3=B6ss?= Date: Mon, 10 Mar 2025 12:00:38 -0500 Subject: [PATCH 550/773] revert to zero at boundary --- src/kernels/fields_bcs.hpp | 44 ++++++++++++-------------------------- 1 file changed, 14 insertions(+), 30 deletions(-) diff --git a/src/kernels/fields_bcs.hpp b/src/kernels/fields_bcs.hpp index dd926580d..8ea6b72d8 100644 --- a/src/kernels/fields_bcs.hpp +++ b/src/kernels/fields_bcs.hpp @@ -486,32 +486,24 @@ namespace kernel::bc { } }; - template + template struct ConductorBoundaries_kernel { static_assert(static_cast(o) < static_cast(D), "Invalid component index"); - static constexpr bool defines_ex2 = traits::has_method::value; - static constexpr bool defines_ex3 = traits::has_method::value; - static constexpr bool defines_bx1 = traits::has_method::value; - static_assert(( defines_ex2 or defines_ex3 or defines_bx1), - "none of the components of E or B are specified in PGEN"); ndfield_t Fld; - const I fset; const BCTags tags; - ConductorBoundaries_kernel(ndfield_t Fld, const I& fset, BCTags tags) + ConductorBoundaries_kernel(ndfield_t Fld, BCTags tags) : Fld { Fld } - , fset { fset } , tags { tags } {} Inline void operator()(index_t i1) const { if constexpr (D == Dim::_1D) { - coord_t x_Ph_H { ZERO }; if (tags & BC::E) { if (i1 == 0) { - Fld(N_GHOSTS, em::ex2) = fset.ex2(x_Ph_H); - Fld(N_GHOSTS, em::ex3) = fset.ex3(x_Ph_H); + Fld(N_GHOSTS, em::ex2) = ZERO; + Fld(N_GHOSTS, em::ex3) = ZERO; } else { Fld(N_GHOSTS - i1, em::ex1) = Fld(N_GHOSTS + i1 - 1, em::ex1); Fld(N_GHOSTS - i1, em::ex2) = -Fld(N_GHOSTS + i1, em::ex2); @@ -521,7 +513,7 @@ namespace kernel::bc { if (tags & BC::B) { if (i1 == 0) { - Fld(N_GHOSTS, em::bx1) = fset.bx1(x_Ph_H); + Fld(N_GHOSTS, em::bx1) = ZERO; } else { Fld(N_GHOSTS - i1, em::bx1) = -Fld(N_GHOSTS + i1, em::bx1); Fld(N_GHOSTS - i1, em::bx2) = Fld(N_GHOSTS + i1 - 1, em::bx2); @@ -537,11 +529,10 @@ namespace kernel::bc { Inline void operator()(index_t i1, index_t i2) const { if constexpr (D == Dim::_2D) { - coord_t x_Ph_H { ZERO }; if (tags & BC::E) { if (i1 == 0) { - Fld(N_GHOSTS, i2, em::ex2) = fset.ex2(x_Ph_H); - Fld(N_GHOSTS, i2, em::ex3) = fset.ex3(x_Ph_H); + Fld(N_GHOSTS, i2, em::ex2) = ZERO; + Fld(N_GHOSTS, i2, em::ex3) = ZERO; } else { Fld(N_GHOSTS - i1, i2, em::ex1) = Fld(N_GHOSTS + i1 - 1, i2, em::ex1); Fld(N_GHOSTS - i1, i2, em::ex2) = -Fld(N_GHOSTS + i1, i2, em::ex2); @@ -551,7 +542,7 @@ namespace kernel::bc { if (tags & BC::B) { if (i1 == 0) { - Fld(N_GHOSTS, i2, em::bx1) = fset.bx1(x_Ph_H); + Fld(N_GHOSTS, i2, em::bx1) = ZERO; } else { Fld(N_GHOSTS - i1, i2, em::bx1) = -Fld(N_GHOSTS + i1, i2, em::bx1); Fld(N_GHOSTS - i1, i2, em::bx2) = Fld(N_GHOSTS + i1 - 1, i2, em::bx2); @@ -567,16 +558,13 @@ namespace kernel::bc { Inline void operator()(index_t i1, index_t i2, index_t i3) const { if constexpr (D == Dim::_3D) { - coord_t x_Ph_H { ZERO }; if (tags & BC::E) { if (i1 == 0) { - Fld(N_GHOSTS, i2, i3, em::ex2) = fset.ex2(x_Ph_H); - Fld(N_GHOSTS, i2, i3, em::ex3) = fset.ex3(x_Ph_H); + Fld(N_GHOSTS, i2, i3, em::ex2) = ZERO; + Fld(N_GHOSTS, i2, i3, em::ex3) = ZERO; } else { Fld(N_GHOSTS - i1, i2, i3, em::ex1) = Fld(N_GHOSTS + i1 - 1, - i2, - i3, - em::ex1); + i2, i3, em::ex1); Fld(N_GHOSTS - i1, i2, i3, em::ex2) = -Fld(N_GHOSTS + i1, i2, i3, em::ex2); Fld(N_GHOSTS - i1, i2, i3, em::ex3) = -Fld(N_GHOSTS + i1, i2, i3, em::ex3); } @@ -584,17 +572,13 @@ namespace kernel::bc { if (tags & BC::B) { if (i1 == 0) { - Fld(N_GHOSTS, i2, i3, em::bx1) = fset.bx1(x_Ph_H); + Fld(N_GHOSTS, i2, i3, em::bx1) = ZERO; } else { Fld(N_GHOSTS - i1, i2, i3, em::bx1) = -Fld(N_GHOSTS + i1, i2, i3, em::bx1); Fld(N_GHOSTS - i1, i2, i3, em::bx2) = Fld(N_GHOSTS + i1 - 1, - i2, - i3, - em::bx2); + i2, i3, em::bx2); Fld(N_GHOSTS - i1, i2, i3, em::bx3) = Fld(N_GHOSTS + i1 - 1, - i2, - i3, - em::bx3); + i2, i3, em::bx3); } } } else { From de24703779b97f928042853abfcbbf211666b08a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20B=C3=B6ss?= Date: Thu, 13 Mar 2025 10:00:56 -0500 Subject: [PATCH 551/773] cleanup of pgen --- setups/srpic/shock/pgen.hpp | 46 ------------------------------------- 1 file changed, 46 deletions(-) diff --git a/setups/srpic/shock/pgen.hpp b/setups/srpic/shock/pgen.hpp index 59c5590c9..b8f169521 100644 --- a/setups/srpic/shock/pgen.hpp +++ b/setups/srpic/shock/pgen.hpp @@ -106,52 +106,6 @@ namespace user { } } - - auto PerfectConductorFieldsConst(const bc_in&, const em& comp) const -> real_t{ - - // electric field components - if (comp == em::ex1) { - return ONE; - } else if (comp == em::ex2) { - return -ONE; - } else if (comp == em::ex3) { - return -ONE; } - // magentic field components - else if (comp == em::bx1) { - return -ONE; - } else if (comp == em::bx2) { - return ONE; - } else if (comp == em::bx3) { - return ONE;} - // should never be the case - else - { - return ZERO; - } - } - - // auto PerfectConductorCurrentsConst(const bc_in &, const cur &comp) const - // -> std::pair - // { - // // ToDo - // if (comp == cur::jx1) - // { - // return ZERO; - // } - // else if (comp == cur::jx2) - // { - // return ZERO; - // } - // else if (comp == cur::jx3) - // { - // return ZERO; - // } - // else - // { - // return ZERO; - // } - // } - auto MatchFields(real_t time) const -> InitFields { return init_flds; } From a41bbe2b726d2d785f0e48ccd82686f1d20aba77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20B=C3=B6ss?= Date: Thu, 13 Mar 2025 11:03:56 -0500 Subject: [PATCH 552/773] update example parameter file --- setups/srpic/shock/shock.toml | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/setups/srpic/shock/shock.toml b/setups/srpic/shock/shock.toml index 4ed3a2b9e..4e03721f7 100644 --- a/setups/srpic/shock/shock.toml +++ b/setups/srpic/shock/shock.toml @@ -1,22 +1,22 @@ [simulation] name = "shock" engine = "srpic" - runtime = 50.0 + runtime = 30000.0 [grid] - resolution = [2048, 128] - extent = [[0.0, 10.0], [-0.3125, 0.3125]] + resolution = [16384, 128] + extent = [[0.0, 8000.0], [-31.25, 31.25]] [grid.metric] metric = "minkowski" [grid.boundaries] - fields = [["ABSORB", "FIXED"], ["PERIODIC"]] + fields = [["CONDUCTOR", "MATCH"], ["PERIODIC"]] particles = [["REFLECT", "ABSORB"], ["PERIODIC"]] - + [scales] - larmor0 = 1e-2 - skindepth0 = 1e-2 + larmor0 = 100.0 + skindepth0 = 1.0 [algorithms] current_filters = 8 @@ -25,7 +25,7 @@ CFL = 0.5 [particles] - ppc0 = 16.0 + ppc0 = 8.0 [[particles.species]] label = "e-" @@ -34,21 +34,29 @@ maxnpart = 1e8 [[particles.species]] - label = "e+" + label = "p+" mass = 1.0 charge = 1.0 maxnpart = 1e8 [setup] drift_ux = 0.1 - temperature = 1e-3 + temperature = 1e-4 Bmag = 1.0 Btheta = 0.0 Bphi = 0.0 [output] - interval_time = 0.1 + interval_time = 500.0 format = "hdf5" - + [output.fields] - quantities = ["N_1", "N_2", "E", "B", "T0i_1", "T0i_2", "J"] + quantities = ["N_1", "N_2", "B", "E"] + + [output.particles] + enable = true + stride = 10 + + [output.spectra] + enable = false + From 5d9fe735066c5a0e3cb33d2b67c215475f1a02fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20B=C3=B6ss?= Date: Wed, 19 Mar 2025 15:40:05 -0500 Subject: [PATCH 553/773] revert to cleaner injector for shocktest --- setups/srpic/shocktest/pgen.hpp | 152 +++++++------------------------- 1 file changed, 32 insertions(+), 120 deletions(-) diff --git a/setups/srpic/shocktest/pgen.hpp b/setups/srpic/shocktest/pgen.hpp index ff54923d1..a7bcf5c3d 100644 --- a/setups/srpic/shocktest/pgen.hpp +++ b/setups/srpic/shocktest/pgen.hpp @@ -93,16 +93,16 @@ namespace user { : arch::ProblemGenerator { p } , drift_ux { p.template get("setup.drift_ux") } , temperature { p.template get("setup.temperature") } - // , x1arr_e { p.template get>("setup.x_e") } - // , x2arr_e { p.template get>("setup.y_e") } - // , ux1arr_e { p.template get>("setup.ux_e") } - // , ux2arr_e { p.template get>("setup.uy_e") } - // , ux3arr_e { p.template get>("setup.uz_e") } - // , x1arr_i { p.template get>("setup.x_i") } - // , x2arr_i { p.template get>("setup.y_i") } - // , ux1arr_i { p.template get>("setup.ux_i") } - // , ux2arr_i { p.template get>("setup.uy_i") } - // , ux3arr_i { p.template get>("setup.uz_i") } + , x1arr_e { p.template get>("setup.x_e") } + , x2arr_e { p.template get>("setup.y_e") } + , ux1arr_e { p.template get>("setup.ux_e") } + , ux2arr_e { p.template get>("setup.uy_e") } + , ux3arr_e { p.template get>("setup.uz_e") } + , x1arr_i { p.template get>("setup.x_i") } + , x2arr_i { p.template get>("setup.y_i") } + , ux1arr_i { p.template get>("setup.ux_i") } + , ux2arr_i { p.template get>("setup.uy_i") } + , ux3arr_i { p.template get>("setup.uz_i") } , Btheta { p.template get("setup.Btheta", ZERO) } , Bmag { p.template get("setup.Bmag", ZERO) } , Bphi { p.template get("setup.Bphi", ZERO) } @@ -126,116 +126,28 @@ namespace user { return init_flds; } - // inline void InitPrtls(Domain& domain) { - // arch::InjectGlobally(*metadomain, - // domain, - // 1, - // { - // { "x1", x1arr_e }, - // { "x2", x2arr_e }, - // { "ux1", ux1arr_e }, - // { "ux2", ux1arr_e }, - // { "ux3", ux3arr_e } - // }); - // arch::InjectGlobally(*metadomain, - // domain, - // 2, - // { - // { "x1", x1arr_i }, - // { "x2", x2arr_i }, - // { "ux1", ux1arr_i }, - // { "ux2", ux1arr_i }, - // { "ux3", ux3arr_i } - // }); - // } - - inline void InitPrtls(Domain& domain) { - - // auto& species_e = domain.species[0]; - // auto& species_p = domain.species[1]; - auto& species_e = domain.species[0]; - auto& species_p = domain.species[1]; - - // array_t elec_ind("elec_ind"); - // array_t pos_ind("pos_ind"); - array_t elec_ind("elec_ind"); - array_t pos_ind("pos_ind"); - - auto offset_e = species_e.npart(); - auto offset_p = species_p.npart(); - - auto ux1_e = species_e.ux1; - auto ux2_e = species_e.ux2; - auto ux3_e = species_e.ux3; - auto i1_e = species_e.i1; - auto i2_e = species_e.i2; - auto dx1_e = species_e.dx1; - auto dx2_e = species_e.dx2; - auto phi_e = species_e.phi; - auto weight_e = species_e.weight; - auto tag_e = species_e.tag; - - auto ux1_p = species_p.ux1; - auto ux2_p = species_p.ux2; - auto ux3_p = species_p.ux3; - auto i1_p = species_p.i1; - auto i2_p = species_p.i2; - auto dx1_p = species_p.dx1; - auto dx2_p = species_p.dx2; - auto phi_p = species_p.phi; - auto weight_p = species_p.weight; - auto tag_p = species_p.tag; - - int nseed = 1; - - Kokkos::parallel_for("init_particles", nseed, KOKKOS_LAMBDA(const int& s) { - - // ToDo: fix this - auto i1_ = math::floor(10); - auto i2_ = math::floor(64); - auto dx1_ = HALF; - auto dx2_ = HALF; - - - auto elec_p = Kokkos::atomic_fetch_add(&elec_ind(), 1); - auto pos_p = Kokkos::atomic_fetch_add(&pos_ind(), 1); - - i1_e(elec_p + offset_e) = i1_; - dx1_e(elec_p + offset_e) = dx1_; - i2_e(elec_p + offset_e) = i2_; - dx2_e(elec_p + offset_e) = 2*dx2_; - // ux1_e(elec_p + offset_e) = -0.5; - // ux2_e(elec_p + offset_e) = 0.5; - ux1_e(elec_p + offset_e) = -drift_ux; - ux2_e(elec_p + offset_e) = ZERO; - ux3_e(elec_p + offset_e) = ZERO; - weight_e(elec_p + offset_e) = ONE; - tag_e(elec_p + offset_e) = ParticleTag::alive; - - i1_p(pos_p + offset_p) = i1_; - dx1_p(pos_p + offset_p) = dx1_; - i2_p(pos_p + offset_p) = i2_; - dx2_p(pos_p + offset_p) = -2*dx2_; - // ux1_p(pos_p + offset_p) = 0.5; - // ux2_p(pos_p + offset_p) = -0.5; - ux1_p(pos_p + offset_p) = -drift_ux; - ux2_p(pos_p + offset_p) = ZERO; - ux3_p(pos_p + offset_p) = ZERO; - weight_p(pos_p + offset_p) = ONE; - tag_p(pos_p + offset_p) = ParticleTag::alive; - - - }); - - - auto elec_ind_h = Kokkos::create_mirror(elec_ind); - Kokkos::deep_copy(elec_ind_h, elec_ind); - species_e.set_npart(offset_e + elec_ind_h()); - - auto pos_ind_h = Kokkos::create_mirror(pos_ind); - Kokkos::deep_copy(pos_ind_h, pos_ind); - species_p.set_npart(offset_p + pos_ind_h()); - } + inline void InitPrtls(Domain& domain) { + arch::InjectGlobally(*metadomain, + domain, + 1, + { + { "x1", x1arr_e }, + { "x2", x2arr_e }, + { "ux1", ux1arr_e }, + { "ux2", ux1arr_e }, + { "ux3", ux3arr_e } + }); + arch::InjectGlobally(*metadomain, + domain, + 2, + { + { "x1", x1arr_i }, + { "x2", x2arr_i }, + { "ux1", ux1arr_i }, + { "ux2", ux1arr_i }, + { "ux3", ux3arr_i } + }); + } }; } // namespace user From 6d43018085d3923ab7aae5d25b9917d2e690321f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20B=C3=B6ss?= Date: Thu, 20 Mar 2025 17:06:25 -0500 Subject: [PATCH 554/773] implemented new `arch::Piston` spatial distribution to set up shock partially filled with plasma --- setups/srpic/shock/pgen.hpp | 59 ++++++++++++++++++++++------------- setups/srpic/shock/shock.toml | 11 ++++--- src/archetypes/spatial_dist.h | 30 ++++++++++++++++++ 3 files changed, 74 insertions(+), 26 deletions(-) diff --git a/setups/srpic/shock/pgen.hpp b/setups/srpic/shock/pgen.hpp index b8f169521..9bf51b866 100644 --- a/setups/srpic/shock/pgen.hpp +++ b/setups/srpic/shock/pgen.hpp @@ -79,7 +79,7 @@ namespace user { using arch::ProblemGenerator::C; using arch::ProblemGenerator::params; - const real_t drift_ux, temperature; + const real_t drift_ux, temperature, filling_fraction; const real_t Btheta, Bphi, Bmag; InitFields init_flds; @@ -91,40 +91,57 @@ namespace user { , Bmag { p.template get("setup.Bmag", ZERO) } , Btheta { p.template get("setup.Btheta", ZERO) } , Bphi { p.template get("setup.Bphi", ZERO) } - , init_flds { Bmag, Btheta, Bphi, drift_ux } {} + , init_flds { Bmag, Btheta, Bphi, drift_ux } + , filling_fraction { params.template get("setup.filling_fraction", 1.0) }{} inline PGen() {} - auto FixFieldsConst(const bc_in&, const em& comp) const - -> std::pair { - if (comp == em::ex2) { - return { init_flds.ex2({ ZERO }), true }; - } else if (comp == em::ex3) { - return { init_flds.ex3({ ZERO }), true }; - } else { - return { ZERO, false }; - } - } - auto MatchFields(real_t time) const -> InitFields { return init_flds; } inline void InitPrtls(Domain& local_domain) { + + // minimum and maximum position of particles + real_t xg_min = local_domain.mesh.extent(in::x1).first; + real_t xg_max = local_domain.mesh.extent(in::x1).second * filling_fraction; + + // define box to inject into + boundaries_t box; + // loop over all dimensions + for (unsigned short d { 0 }; d < static_cast(M::Dim); ++d) { + // compute the range for the x-direction + if (d == static_cast(in::x1)) { + box.push_back({xg_min, xg_max}); + } else { + // inject into full range in other directions + box.push_back(Range::All); + } + } + + // spatial distribution of the particles + // -> hack to use the uniform distribution in NonUniformInjector + const auto spatial_dist = arch::Piston(local_domain.mesh.metric, xg_min, xg_max, in::x1); + + // energy distribution of the particles const auto energy_dist = arch::Maxwellian(local_domain.mesh.metric, local_domain.random_pool, temperature, -drift_ux, in::x1); - const auto injector = arch::UniformInjector( - energy_dist, - { 1, 2 }); - arch::InjectUniform>( - params, - local_domain, - injector, - 1.0); + const auto injector = arch::NonUniformInjector( + energy_dist, + spatial_dist, + {1, 2}); + + arch::InjectNonUniform>( + params, + local_domain, + injector, + 1.0, // target density + false, // no weights + box); } }; diff --git a/setups/srpic/shock/shock.toml b/setups/srpic/shock/shock.toml index 4e03721f7..f954345c2 100644 --- a/setups/srpic/shock/shock.toml +++ b/setups/srpic/shock/shock.toml @@ -40,11 +40,12 @@ maxnpart = 1e8 [setup] - drift_ux = 0.1 - temperature = 1e-4 - Bmag = 1.0 - Btheta = 0.0 - Bphi = 0.0 + drift_ux = 0.1 # speed towards the wall [c] + temperature = 1e-4 # temeperature of maxwell distribution [m_e c^2] + Bmag = 1.0 # magnetic field strength as fraction of magnetisation + Btheta = 0.0 # magnetic field angle in the plane + Bphi = 0.0 # magnetic field angle out of plane + filling_fraction = 1.0 # fraction of the shock piston filled with plasma [output] interval_time = 500.0 diff --git a/src/archetypes/spatial_dist.h b/src/archetypes/spatial_dist.h index d036c0166..2407d98cd 100644 --- a/src/archetypes/spatial_dist.h +++ b/src/archetypes/spatial_dist.h @@ -4,6 +4,7 @@ * @implements * - arch::SpatialDistribution<> * - arch::Uniform<> : arch::SpatialDistribution<> + * - arch::Piston<> : arch::SpatialDistribution<> * - arch::Replenish<> : arch::SpatialDistribution<> * @namespace * - arch:: @@ -49,6 +50,35 @@ namespace arch { } }; + template + struct Piston : public arch::SpatialDistribution + { + Piston(const M &metric, real_t xmin, real_t xmax, in piston_direction = in::x1) + : arch::SpatialDistribution{metric} + , xmin {xmin} + , xmax {xmax} + , piston_direction {piston_direction} {} + + Inline auto operator()(const coord_t &x_Ph) const -> real_t override + { + // dimentsion to fill + const auto fill_dim = static_cast(piston_direction); + + if (x_Ph[fill_dim] < xmin || x_Ph[fill_dim] > xmax) + { + return 0.0; + } + else + { + return 1.0; + } + } + + private: + real_t xmin, xmax; + in piston_direction; + }; + template struct Replenish : public SpatialDistribution { using SpatialDistribution::metric; From 4f5b1d87e3b6f5321e3c51e53bfc1de6bd45dc6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20B=C3=B6ss?= Date: Thu, 20 Mar 2025 17:43:25 -0500 Subject: [PATCH 555/773] fix inconsistency in return type --- src/archetypes/spatial_dist.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/archetypes/spatial_dist.h b/src/archetypes/spatial_dist.h index 2407d98cd..2edbf5b1d 100644 --- a/src/archetypes/spatial_dist.h +++ b/src/archetypes/spatial_dist.h @@ -66,11 +66,11 @@ namespace arch { if (x_Ph[fill_dim] < xmin || x_Ph[fill_dim] > xmax) { - return 0.0; + return ZERO; } else { - return 1.0; + return ONE; } } From 3e9c4acc7236a4c912e507708657e491f34c25fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20B=C3=B6ss?= Date: Fri, 21 Mar 2025 16:24:35 -0500 Subject: [PATCH 556/773] Added `MovingInjector` (wip) --- src/archetypes/particle_injector.h | 69 ++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/src/archetypes/particle_injector.h b/src/archetypes/particle_injector.h index 3884e6ced..daa41506c 100644 --- a/src/archetypes/particle_injector.h +++ b/src/archetypes/particle_injector.h @@ -170,6 +170,75 @@ namespace arch { ~AtmosphereInjector() = default; }; + template + struct MovingInjector + { + struct TargetDensityProfile + { + const real_t nmax, xinj, xdrift; + + TargetDensityProfile(real_t xinj, real_t xdrift, real_t nmax) + : xinj{xinj}, xdrift{xdrift}, nmax{nmax} {} + + Inline auto operator()(const coord_t &x_Ph) const -> real_t + { + if constexpr ((O == in::x1) or + (O == in::x2 and (M::Dim == Dim::_2D or M::Dim == Dim::_3D)) or + (O == in::x3 and M::Dim == Dim::_3D)) + { + const auto xi = x_Ph[static_cast(O)]; + // + direction + if (xi < xinj - xdrift or xi >= xinj) + { + return ZERO; + } + else + { + if constexpr (M::CoordType == Coord::Cart) + { + return nmax; + } + else + { + raise::KernelError( + HERE, + "Moving injector in +x cannot be applied for non-cartesian"); + return ZERO; + } + } + } + else + { + raise::KernelError(HERE, "Wrong direction"); + return ZERO; + } + } + }; + using energy_dist_t = Maxwellian; + using spatial_dist_t = Replenish; + static_assert(M::is_metric, "M must be a metric class"); + static constexpr bool is_nonuniform_injector{true}; + static constexpr Dimension D{M::Dim}; + static constexpr Coord C{M::CoordType}; + + const energy_dist_t energy_dist; + const TargetDensityProfile target_density; + const spatial_dist_t spatial_dist; + const std::pair species; + + MovingInjector(const M &metric, + const ndfield_t &density, + const energy_dist_t &energy_dist, + real_t xinj, + real_t xdrift, + real_t nmax, + const std::pair &species) + : energy_dist{energy_dist}, + target_density{xinj, xdrift, nmax}, spatial_dist{metric, density, 0, target_density, nmax}, species{species} {} + + ~MovingInjector() = default; + }; + /** * @brief Injects uniform number density of particles everywhere in the domain * @param domain Domain object From e724b506f2acef8869c1a92bb476ff4c7065ac1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20B=C3=B6ss?= Date: Fri, 21 Mar 2025 16:25:10 -0500 Subject: [PATCH 557/773] Added `CustomPostStep` for shock pgen to continually inject particles (wip) --- setups/srpic/shock/pgen.hpp | 78 ++++++++++++++++++++++++++++++++++- setups/srpic/shock/shock.toml | 4 +- src/engines/engine_run.cpp | 2 +- 3 files changed, 79 insertions(+), 5 deletions(-) diff --git a/setups/srpic/shock/pgen.hpp b/setups/srpic/shock/pgen.hpp index 9bf51b866..7c0d750e3 100644 --- a/setups/srpic/shock/pgen.hpp +++ b/setups/srpic/shock/pgen.hpp @@ -79,7 +79,7 @@ namespace user { using arch::ProblemGenerator::C; using arch::ProblemGenerator::params; - const real_t drift_ux, temperature, filling_fraction; + const real_t drift_ux, temperature, filling_fraction, injection_rate; const real_t Btheta, Bphi, Bmag; InitFields init_flds; @@ -92,7 +92,8 @@ namespace user { , Btheta { p.template get("setup.Btheta", ZERO) } , Bphi { p.template get("setup.Bphi", ZERO) } , init_flds { Bmag, Btheta, Bphi, drift_ux } - , filling_fraction { params.template get("setup.filling_fraction", 1.0) }{} + , filling_fraction { params.template get("setup.filling_fraction", 1.0) } + , injection_rate { params.template get("setup.injection_rate", 1.0) } {} inline PGen() {} @@ -100,6 +101,11 @@ namespace user { return init_flds; } + // Inline auto TargetDensity(const coord_t &x_Ph) const -> real_t + // { + // return ONE; + // } + inline void InitPrtls(Domain& local_domain) { // minimum and maximum position of particles @@ -143,6 +149,74 @@ namespace user { false, // no weights box); } + + void CustomPostStep(std::size_t, long double time, real_t dt, Domain &domain) + { + /* + Moving injector for the particles + */ + + // energy distribution of the particles + const auto energy_dist = arch::Maxwellian(domain.mesh.metric, + domain.random_pool, + temperature, + -drift_ux, + in::x1); + + // minimum and maximum position of particles + // ToDo: Add time offset for start of movement? + real_t xg_min = domain.mesh.extent(in::x1).second * filling_fraction + + injection_rate * time - drift_ux * dt; + real_t xg_max = domain.mesh.extent(in::x1).second * filling_fraction + + injection_rate * time; + + + /* + I thought this option would be better, but I can't get it to work + */ + + // // define box to inject into + // boundaries_t box; + // // loop over all dimensions + // for (unsigned short d{0}; d < static_cast(M::Dim); ++d) + // { + // // compute the range for the x-direction + // if (d == static_cast(in::x1)) + // { + // box.push_back({xg_min, xg_max}); + // } else { + // // inject into full range in other directions + // box.push_back(Range::All); + // } + // } + + // const auto spatial_dist = arch::Replenish(domain.mesh.metric, + // domain.fields.bckp, + // box, + // TargetDensity, + // 1.0); + + // const auto injector = arch::NonUniformInjector( + // energy_dist, + // spatial_dist, + // {1, 2}); + + const auto injector = arch::MovingInjector{ + domain.mesh.metric, + domain.fields.bckp, + energy_dist, + xg_max, + xg_min, + 1.0, + {1, 2}}; + + arch::InjectNonUniform( + params, + domain, + injector, + 1.0, // target density + false); + } }; } // namespace user diff --git a/setups/srpic/shock/shock.toml b/setups/srpic/shock/shock.toml index f954345c2..772b452c9 100644 --- a/setups/srpic/shock/shock.toml +++ b/setups/srpic/shock/shock.toml @@ -45,10 +45,10 @@ Bmag = 1.0 # magnetic field strength as fraction of magnetisation Btheta = 0.0 # magnetic field angle in the plane Bphi = 0.0 # magnetic field angle out of plane - filling_fraction = 1.0 # fraction of the shock piston filled with plasma + filling_fraction = 0.1 # fraction of the shock piston filled with plasma [output] - interval_time = 500.0 + interval_time = 10.0 format = "hdf5" [output.fields] diff --git a/src/engines/engine_run.cpp b/src/engines/engine_run.cpp index 2d4b0d5ed..a3ae21ccb 100644 --- a/src/engines/engine_run.cpp +++ b/src/engines/engine_run.cpp @@ -52,7 +52,7 @@ namespace ntt { traits::has_method::value) { timers.start("Custom"); m_metadomain.runOnLocalDomains([&timers, this](auto& dom) { - m_pgen.CustomPostStep(step, time, dom); + m_pgen.CustomPostStep(step, time, dt, dom); }); timers.stop("Custom"); } From 236060b4b9b092c5e568b5691a76ac2f76772fce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20B=C3=B6ss?= Date: Sat, 22 Mar 2025 11:42:48 -0500 Subject: [PATCH 558/773] bugfix --- src/archetypes/particle_injector.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/archetypes/particle_injector.h b/src/archetypes/particle_injector.h index daa41506c..676cf2857 100644 --- a/src/archetypes/particle_injector.h +++ b/src/archetypes/particle_injector.h @@ -188,7 +188,7 @@ namespace arch { { const auto xi = x_Ph[static_cast(O)]; // + direction - if (xi < xinj - xdrift or xi >= xinj) + if (xi < xdrift or xi >= xinj) { return ZERO; } From 2391bee2aad7d3d22427fe3481675aab9ebf4d3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20B=C3=B6ss?= Date: Sat, 22 Mar 2025 11:56:32 -0500 Subject: [PATCH 559/773] added start time of injection and explicitly enforce injection region (wip) --- setups/srpic/shock/pgen.hpp | 102 +++++++++++++++++----------------- setups/srpic/shock/shock.toml | 2 + 2 files changed, 54 insertions(+), 50 deletions(-) diff --git a/setups/srpic/shock/pgen.hpp b/setups/srpic/shock/pgen.hpp index 7c0d750e3..04de58406 100644 --- a/setups/srpic/shock/pgen.hpp +++ b/setups/srpic/shock/pgen.hpp @@ -79,7 +79,8 @@ namespace user { using arch::ProblemGenerator::C; using arch::ProblemGenerator::params; - const real_t drift_ux, temperature, filling_fraction, injection_rate; + const real_t drift_ux, temperature, filling_fraction, + injector_velocity, injection_start; const real_t Btheta, Bphi, Bmag; InitFields init_flds; @@ -93,7 +94,8 @@ namespace user { , Bphi { p.template get("setup.Bphi", ZERO) } , init_flds { Bmag, Btheta, Bphi, drift_ux } , filling_fraction { params.template get("setup.filling_fraction", 1.0) } - , injection_rate { params.template get("setup.injection_rate", 1.0) } {} + , injector_velocity { params.template get("setup.injector_velocity", 1.0) } + , injection_start { params.template get("setup.injection_start", 0.0) } {} inline PGen() {} @@ -164,58 +166,58 @@ namespace user { in::x1); // minimum and maximum position of particles - // ToDo: Add time offset for start of movement? - real_t xg_min = domain.mesh.extent(in::x1).second * filling_fraction + - injection_rate * time - drift_ux * dt; + real_t xg_min = domain.mesh.extent(in::x1).second * filling_fraction + + injector_velocity * (time - injection_start) + - drift_ux; // distance particles have moved in the last time step real_t xg_max = domain.mesh.extent(in::x1).second * filling_fraction + - injection_rate * time; + injector_velocity * (time - injection_start); + /* + I thought this option would be better, but I can't get it to work + */ - /* - I thought this option would be better, but I can't get it to work - */ - - // // define box to inject into - // boundaries_t box; - // // loop over all dimensions - // for (unsigned short d{0}; d < static_cast(M::Dim); ++d) - // { - // // compute the range for the x-direction - // if (d == static_cast(in::x1)) - // { - // box.push_back({xg_min, xg_max}); - // } else { - // // inject into full range in other directions - // box.push_back(Range::All); - // } - // } - - // const auto spatial_dist = arch::Replenish(domain.mesh.metric, - // domain.fields.bckp, - // box, - // TargetDensity, - // 1.0); - - // const auto injector = arch::NonUniformInjector( - // energy_dist, - // spatial_dist, - // {1, 2}); - - const auto injector = arch::MovingInjector{ - domain.mesh.metric, - domain.fields.bckp, - energy_dist, - xg_max, - xg_min, - 1.0, - {1, 2}}; + // define box to inject into + boundaries_t box; + // loop over all dimensions + for (unsigned short d{0}; d < static_cast(M::Dim); ++d) + { + // compute the range for the x-direction + if (d == static_cast(in::x1)) + { + box.push_back({xg_min, xg_max}); + } else { + // inject into full range in other directions + box.push_back(Range::All); + } + } - arch::InjectNonUniform( - params, - domain, - injector, - 1.0, // target density - false); + // const auto spatial_dist = arch::Replenish(domain.mesh.metric, + // domain.fields.bckp, + // box, + // TargetDensity, + // 1.0); + + // const auto injector = arch::NonUniformInjector( + // energy_dist, + // spatial_dist, + // {1, 2}); + + const auto injector = arch::MovingInjector{ + domain.mesh.metric, + domain.fields.bckp, + energy_dist, + xg_max, + xg_min, + 1.0, + {1, 2}}; + + arch::InjectNonUniform( + params, + domain, + injector, + 1.0, // target density + false, + box); } }; diff --git a/setups/srpic/shock/shock.toml b/setups/srpic/shock/shock.toml index 772b452c9..43da87d99 100644 --- a/setups/srpic/shock/shock.toml +++ b/setups/srpic/shock/shock.toml @@ -46,6 +46,8 @@ Btheta = 0.0 # magnetic field angle in the plane Bphi = 0.0 # magnetic field angle out of plane filling_fraction = 0.1 # fraction of the shock piston filled with plasma + injector_velocity = 1.0 # speed of injector [c] + injection_start = 0.0 # start time of moving injector [output] interval_time = 10.0 From d67f6c746e360b6e27aa7aabdb97d314e9c5d467 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20B=C3=B6ss?= Date: Sat, 22 Mar 2025 12:12:00 -0500 Subject: [PATCH 560/773] small bugfix --- setups/srpic/shock/pgen.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setups/srpic/shock/pgen.hpp b/setups/srpic/shock/pgen.hpp index 04de58406..1c9c9a4d3 100644 --- a/setups/srpic/shock/pgen.hpp +++ b/setups/srpic/shock/pgen.hpp @@ -167,8 +167,8 @@ namespace user { // minimum and maximum position of particles real_t xg_min = domain.mesh.extent(in::x1).second * filling_fraction - + injector_velocity * (time - injection_start) - - drift_ux; // distance particles have moved in the last time step + + injector_velocity * (time - injection_start - dt) + - drift_ux * dt; // distance particles have moved in the last time step real_t xg_max = domain.mesh.extent(in::x1).second * filling_fraction + injector_velocity * (time - injection_start); From bb8e30810d140863dcbbad1def9ce1b1ae5da202 Mon Sep 17 00:00:00 2001 From: hayk Date: Mon, 24 Mar 2025 13:14:51 -0400 Subject: [PATCH 561/773] shock pgen changed --- setups/srpic/shock/pgen.hpp | 200 ++++++++++++++++++++-------------- src/archetypes/spatial_dist.h | 39 +++---- src/engines/engine_run.cpp | 2 +- 3 files changed, 134 insertions(+), 107 deletions(-) diff --git a/setups/srpic/shock/pgen.hpp b/setups/srpic/shock/pgen.hpp index 1c9c9a4d3..cc6f1b812 100644 --- a/setups/srpic/shock/pgen.hpp +++ b/setups/srpic/shock/pgen.hpp @@ -18,6 +18,16 @@ namespace user { using namespace ntt; + template + struct SpatialUniform : public arch::SpatialDistribution { + SpatialUniform(const M& metric) + : arch::SpatialDistribution { metric } {} + + Inline auto operator()(const coord_t&) const -> real_t override { + return ONE; + } + }; + template struct InitFields { /* @@ -79,8 +89,8 @@ namespace user { using arch::ProblemGenerator::C; using arch::ProblemGenerator::params; - const real_t drift_ux, temperature, filling_fraction, - injector_velocity, injection_start; + const real_t drift_ux, temperature, filling_fraction, injector_velocity, + injection_start, dt; const real_t Btheta, Bphi, Bmag; InitFields init_flds; @@ -92,10 +102,14 @@ namespace user { , Bmag { p.template get("setup.Bmag", ZERO) } , Btheta { p.template get("setup.Btheta", ZERO) } , Bphi { p.template get("setup.Bphi", ZERO) } - , init_flds { Bmag, Btheta, Bphi, drift_ux } - , filling_fraction { params.template get("setup.filling_fraction", 1.0) } - , injector_velocity { params.template get("setup.injector_velocity", 1.0) } - , injection_start { params.template get("setup.injection_start", 0.0) } {} + , init_flds { Bmag, Btheta, Bphi, drift_ux } + , filling_fraction { params.template get("setup.filling_fraction", + 1.0) } + , injector_velocity { params.template get( + "setup.injector_velocity", + 1.0) } + , injection_start { params.template get("setup.injection_start", 0.0) } + , dt { params.template get("algorithms.timestep.dt") } {} inline PGen() {} @@ -109,7 +123,7 @@ namespace user { // } inline void InitPrtls(Domain& local_domain) { - + // minimum and maximum position of particles real_t xg_min = local_domain.mesh.extent(in::x1).first; real_t xg_max = local_domain.mesh.extent(in::x1).second * filling_fraction; @@ -120,16 +134,19 @@ namespace user { for (unsigned short d { 0 }; d < static_cast(M::Dim); ++d) { // compute the range for the x-direction if (d == static_cast(in::x1)) { - box.push_back({xg_min, xg_max}); + box.push_back({ xg_min, xg_max }); } else { // inject into full range in other directions box.push_back(Range::All); } } - // spatial distribution of the particles + // spatial distribution of the particles // -> hack to use the uniform distribution in NonUniformInjector - const auto spatial_dist = arch::Piston(local_domain.mesh.metric, xg_min, xg_max, in::x1); + const auto spatial_dist = arch::Piston(local_domain.mesh.metric, + xg_min, + xg_max, + in::x1); // energy distribution of the particles const auto energy_dist = arch::Maxwellian(local_domain.mesh.metric, @@ -139,85 +156,100 @@ namespace user { in::x1); const auto injector = arch::NonUniformInjector( - energy_dist, - spatial_dist, - {1, 2}); + energy_dist, + spatial_dist, + { 1, 2 }); arch::InjectNonUniform>( - params, - local_domain, - injector, - 1.0, // target density - false, // no weights - box); + params, + local_domain, + injector, + 1.0, // target density + false, // no weights + box); } - void CustomPostStep(std::size_t, long double time, real_t dt, Domain &domain) - { - /* - Moving injector for the particles - */ - - // energy distribution of the particles - const auto energy_dist = arch::Maxwellian(domain.mesh.metric, - domain.random_pool, - temperature, - -drift_ux, - in::x1); - - // minimum and maximum position of particles - real_t xg_min = domain.mesh.extent(in::x1).second * filling_fraction - + injector_velocity * (time - injection_start - dt) - - drift_ux * dt; // distance particles have moved in the last time step - real_t xg_max = domain.mesh.extent(in::x1).second * filling_fraction + - injector_velocity * (time - injection_start); - - /* - I thought this option would be better, but I can't get it to work - */ - - // define box to inject into - boundaries_t box; - // loop over all dimensions - for (unsigned short d{0}; d < static_cast(M::Dim); ++d) - { - // compute the range for the x-direction - if (d == static_cast(in::x1)) - { - box.push_back({xg_min, xg_max}); - } else { - // inject into full range in other directions - box.push_back(Range::All); - } - } + void CustomPostStep(std::size_t, long double time, Domain& domain) { + const auto energy_dist = arch::Maxwellian(domain.mesh.metric, + domain.random_pool, + temperature, + -drift_ux, + in::x1); + const auto spatial_dist = SpatialUniform(domain.mesh.metric); + const auto injector = arch::NonUniformInjector( + energy_dist, + spatial_dist, + { 1, 2 }); + + boundaries_t box; + + const auto x_init = domain.mesh.extent(in::x1).first + + filling_fraction * (domain.mesh.extent(in::x1).second - + domain.mesh.extent(in::x1).first); + + box[0].first = x_init + injector_velocity * (time - injection_start); + box[0].second = x_init + injector_velocity * (time - injection_start + dt) - + drift_ux / math::sqrt(1 + SQR(drift_ux)) * dt; + for (auto d = 1u; d < M::Dim; ++d) { + box[d] = Range::All; + } - // const auto spatial_dist = arch::Replenish(domain.mesh.metric, - // domain.fields.bckp, - // box, - // TargetDensity, - // 1.0); - - // const auto injector = arch::NonUniformInjector( - // energy_dist, - // spatial_dist, - // {1, 2}); - - const auto injector = arch::MovingInjector{ - domain.mesh.metric, - domain.fields.bckp, - energy_dist, - xg_max, - xg_min, - 1.0, - {1, 2}}; - - arch::InjectNonUniform( - params, - domain, - injector, - 1.0, // target density - false, - box); + arch::InjectNonUniform(params, + domain, + injector, + ONE, + false, + box); + + // /* + // Moving injector for the particles + // */ + // + // // minimum and maximum position of particles + // real_t xg_min = domain.mesh.extent(in::x1).second * filling_fraction + + // injector_velocity * (time - injection_start - dt) - + // drift_ux * + // dt; // distance particles have moved in the last time step + // real_t xg_max = domain.mesh.extent(in::x1).second * filling_fraction + + // injector_velocity * (time - injection_start); + // + // /* + // I thought this option would be better, but I can't get it to work + // */ + // + // // define box to inject into + // // loop over all dimensions + // for (unsigned short d { 0 }; d < static_cast(M::Dim); ++d) { + // // compute the range for the x-direction + // if (d == static_cast(in::x1)) { + // box.push_back({ xg_min, xg_max }); + // } else { + // // inject into full range in other directions + // box.push_back(Range::All); + // } + // } + + // const auto spatial_dist = arch::Replenish(domain.mesh.metric, + // domain.fields.bckp, + // box, + // TargetDensity, + // 1.0); + + // const auto injector = arch::NonUniformInjector( + // energy_dist, + // spatial_dist, + // {1, 2}); + + // const auto injector = arch::MovingInjector { + // domain.mesh.metric, + // domain.fields.bckp, + // energy_dist, + // xg_max, + // xg_min, + // 1.0, + // { 1, 2 } + // }; } }; diff --git a/src/archetypes/spatial_dist.h b/src/archetypes/spatial_dist.h index 2edbf5b1d..ad9404ea3 100644 --- a/src/archetypes/spatial_dist.h +++ b/src/archetypes/spatial_dist.h @@ -51,32 +51,27 @@ namespace arch { }; template - struct Piston : public arch::SpatialDistribution - { - Piston(const M &metric, real_t xmin, real_t xmax, in piston_direction = in::x1) - : arch::SpatialDistribution{metric} - , xmin {xmin} - , xmax {xmax} - , piston_direction {piston_direction} {} - - Inline auto operator()(const coord_t &x_Ph) const -> real_t override - { - // dimentsion to fill - const auto fill_dim = static_cast(piston_direction); - - if (x_Ph[fill_dim] < xmin || x_Ph[fill_dim] > xmax) - { - return ZERO; - } - else - { - return ONE; - } + struct Piston : public arch::SpatialDistribution { + Piston(const M& metric, real_t xmin, real_t xmax, in piston_direction = in::x1) + : arch::SpatialDistribution { metric } + , xmin { xmin } + , xmax { xmax } + , piston_direction { piston_direction } {} + + Inline auto operator()(const coord_t& x_Ph) const -> real_t override { + // dimentsion to fill + const auto fill_dim = static_cast(piston_direction); + + if (x_Ph[fill_dim] < xmin || x_Ph[fill_dim] > xmax) { + return ZERO; + } else { + return ONE; } + } private: real_t xmin, xmax; - in piston_direction; + in piston_direction; }; template diff --git a/src/engines/engine_run.cpp b/src/engines/engine_run.cpp index a3ae21ccb..2d4b0d5ed 100644 --- a/src/engines/engine_run.cpp +++ b/src/engines/engine_run.cpp @@ -52,7 +52,7 @@ namespace ntt { traits::has_method::value) { timers.start("Custom"); m_metadomain.runOnLocalDomains([&timers, this](auto& dom) { - m_pgen.CustomPostStep(step, time, dt, dom); + m_pgen.CustomPostStep(step, time, dom); }); timers.stop("Custom"); } From 31ef1000e7e814e06cd027b79104bc8be6cdba9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20B=C3=B6ss?= Date: Mon, 24 Mar 2025 15:31:41 -0500 Subject: [PATCH 562/773] reduce resolution for faster test --- setups/srpic/shock/shock.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setups/srpic/shock/shock.toml b/setups/srpic/shock/shock.toml index 43da87d99..ca19a4078 100644 --- a/setups/srpic/shock/shock.toml +++ b/setups/srpic/shock/shock.toml @@ -4,8 +4,8 @@ runtime = 30000.0 [grid] - resolution = [16384, 128] - extent = [[0.0, 8000.0], [-31.25, 31.25]] + resolution = [4096, 128] + extent = [[0.0, 2000.0], [-31.25, 31.25]] [grid.metric] metric = "minkowski" From b32468754eaf799e94da7d3a531a2926afc9d5c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20B=C3=B6ss?= Date: Mon, 24 Mar 2025 15:31:52 -0500 Subject: [PATCH 563/773] cleanup and bugfix --- setups/srpic/shock/pgen.hpp | 195 +++++++++++++++++------------------- 1 file changed, 92 insertions(+), 103 deletions(-) diff --git a/setups/srpic/shock/pgen.hpp b/setups/srpic/shock/pgen.hpp index cc6f1b812..2454c9037 100644 --- a/setups/srpic/shock/pgen.hpp +++ b/setups/srpic/shock/pgen.hpp @@ -18,16 +18,6 @@ namespace user { using namespace ntt; - template - struct SpatialUniform : public arch::SpatialDistribution { - SpatialUniform(const M& metric) - : arch::SpatialDistribution { metric } {} - - Inline auto operator()(const coord_t&) const -> real_t override { - return ONE; - } - }; - template struct InitFields { /* @@ -89,10 +79,13 @@ namespace user { using arch::ProblemGenerator::C; using arch::ProblemGenerator::params; - const real_t drift_ux, temperature, filling_fraction, injector_velocity, - injection_start, dt; + // gas properties + const real_t drift_ux, temperature, filling_fraction; + // injector properties + const real_t injector_velocity, injection_start, dt; + const bool injection_on; - const real_t Btheta, Bphi, Bmag; + real_t Btheta, Bphi, Bmag; InitFields init_flds; inline PGen(const SimulationParams& p, const Metadomain& m) @@ -103,13 +96,11 @@ namespace user { , Btheta { p.template get("setup.Btheta", ZERO) } , Bphi { p.template get("setup.Bphi", ZERO) } , init_flds { Bmag, Btheta, Bphi, drift_ux } - , filling_fraction { params.template get("setup.filling_fraction", - 1.0) } - , injector_velocity { params.template get( - "setup.injector_velocity", - 1.0) } - , injection_start { params.template get("setup.injection_start", 0.0) } - , dt { params.template get("algorithms.timestep.dt") } {} + , filling_fraction { p.template get("setup.filling_fraction", 1.0) } + , injector_velocity { p.template get("setup.injector_velocity", 1.0) } + , injection_start { p.template get("setup.injection_start", 0.0) } + , injection_on { p.template get("setup.continuous_injection", true) } + , dt { p.template get("algorithms.timestep.dt") } {} inline PGen() {} @@ -117,16 +108,13 @@ namespace user { return init_flds; } - // Inline auto TargetDensity(const coord_t &x_Ph) const -> real_t - // { - // return ONE; - // } - inline void InitPrtls(Domain& local_domain) { // minimum and maximum position of particles real_t xg_min = local_domain.mesh.extent(in::x1).first; - real_t xg_max = local_domain.mesh.extent(in::x1).second * filling_fraction; + real_t xg_max = local_domain.mesh.extent(in::x1).first + + filling_fraction * (local_domain.mesh.extent(in::x1).second - + local_domain.mesh.extent(in::x1).first); // define box to inject into boundaries_t box; @@ -170,86 +158,87 @@ namespace user { } void CustomPostStep(std::size_t, long double time, Domain& domain) { - const auto energy_dist = arch::Maxwellian(domain.mesh.metric, - domain.random_pool, - temperature, - -drift_ux, - in::x1); - const auto spatial_dist = SpatialUniform(domain.mesh.metric); - const auto injector = arch::NonUniformInjector( - energy_dist, - spatial_dist, - { 1, 2 }); - boundaries_t box; - - const auto x_init = domain.mesh.extent(in::x1).first + - filling_fraction * (domain.mesh.extent(in::x1).second - - domain.mesh.extent(in::x1).first); + // ToDo: more performant version? + if (injection_on) { + // same maxwell distribution as above + const auto energy_dist = arch::Maxwellian(domain.mesh.metric, + domain.random_pool, + temperature, + -drift_ux, + in::x1); + + // initial position of injector + const auto x_init = domain.mesh.extent(in::x1).first + + filling_fraction * (domain.mesh.extent(in::x1).second - + domain.mesh.extent(in::x1).first); + + // check if injector is supposed to start moving already + const auto dt_inj = time - injection_start > ZERO ? time - injection_start + : ZERO; + + // define box to inject into + boundaries_t box; + + // loop over all dimension + for (auto d = 0u; d < M::Dim; ++d) { + if (d == 0) { + box.push_back({ x_init + injector_velocity * (dt_inj)-drift_ux / + math::sqrt(1 + SQR(drift_ux)) * dt, + x_init + injector_velocity * (dt_inj + dt) }); + } else { + box.push_back(Range::All); + } + } - box[0].first = x_init + injector_velocity * (time - injection_start); - box[0].second = x_init + injector_velocity * (time - injection_start + dt) - - drift_ux / math::sqrt(1 + SQR(drift_ux)) * dt; - for (auto d = 1u; d < M::Dim; ++d) { - box[d] = Range::All; + // spatial distribution of the particles + // -> hack to use the uniform distribution in NonUniformInjector + const auto spatial_dist = arch::Piston(domain.mesh.metric, + box[0].first, + box[0].second, + in::x1); + + // ToDo: extend Replenish to replace the current injector + const auto injector = + arch::NonUniformInjector( + energy_dist, + spatial_dist, + { 1, 2 }); + + // inject non-uniformly within the defined box + arch::InjectNonUniform(params, + domain, + injector, + ONE, + false, + box); + + /* + I thought this option would be better, but I can't get it to work + */ + + // const auto spatial_dist = arch::Replenish(domain.mesh.metric, + // domain.fields.bckp, + // box, + // TargetDensity, + // 1.0); + + // const auto injector = arch::NonUniformInjector( + // energy_dist, + // spatial_dist, + // {1, 2}); + + // const auto injector = arch::MovingInjector { + // domain.mesh.metric, + // domain.fields.bckp, + // energy_dist, + // box[0].first, + // box[0].second, + // 1.0, + // { 1, 2 } + // }; } - - arch::InjectNonUniform(params, - domain, - injector, - ONE, - false, - box); - - // /* - // Moving injector for the particles - // */ - // - // // minimum and maximum position of particles - // real_t xg_min = domain.mesh.extent(in::x1).second * filling_fraction + - // injector_velocity * (time - injection_start - dt) - - // drift_ux * - // dt; // distance particles have moved in the last time step - // real_t xg_max = domain.mesh.extent(in::x1).second * filling_fraction + - // injector_velocity * (time - injection_start); - // - // /* - // I thought this option would be better, but I can't get it to work - // */ - // - // // define box to inject into - // // loop over all dimensions - // for (unsigned short d { 0 }; d < static_cast(M::Dim); ++d) { - // // compute the range for the x-direction - // if (d == static_cast(in::x1)) { - // box.push_back({ xg_min, xg_max }); - // } else { - // // inject into full range in other directions - // box.push_back(Range::All); - // } - // } - - // const auto spatial_dist = arch::Replenish(domain.mesh.metric, - // domain.fields.bckp, - // box, - // TargetDensity, - // 1.0); - - // const auto injector = arch::NonUniformInjector( - // energy_dist, - // spatial_dist, - // {1, 2}); - - // const auto injector = arch::MovingInjector { - // domain.mesh.metric, - // domain.fields.bckp, - // energy_dist, - // xg_max, - // xg_min, - // 1.0, - // { 1, 2 } - // }; } }; From 2d1a45436cd677560cd93bab56c255eea251db43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20B=C3=B6ss?= Date: Mon, 24 Mar 2025 15:45:43 -0500 Subject: [PATCH 564/773] removed unnecessary parameter --- setups/srpic/shock/pgen.hpp | 156 +++++++++++++++++------------------- 1 file changed, 75 insertions(+), 81 deletions(-) diff --git a/setups/srpic/shock/pgen.hpp b/setups/srpic/shock/pgen.hpp index 2454c9037..30ab01538 100644 --- a/setups/srpic/shock/pgen.hpp +++ b/setups/srpic/shock/pgen.hpp @@ -83,8 +83,7 @@ namespace user { const real_t drift_ux, temperature, filling_fraction; // injector properties const real_t injector_velocity, injection_start, dt; - const bool injection_on; - + // magnetic field properties real_t Btheta, Bphi, Bmag; InitFields init_flds; @@ -99,7 +98,6 @@ namespace user { , filling_fraction { p.template get("setup.filling_fraction", 1.0) } , injector_velocity { p.template get("setup.injector_velocity", 1.0) } , injection_start { p.template get("setup.injection_start", 0.0) } - , injection_on { p.template get("setup.continuous_injection", true) } , dt { p.template get("algorithms.timestep.dt") } {} inline PGen() {} @@ -159,86 +157,82 @@ namespace user { void CustomPostStep(std::size_t, long double time, Domain& domain) { - // ToDo: more performant version? - if (injection_on) { - // same maxwell distribution as above - const auto energy_dist = arch::Maxwellian(domain.mesh.metric, - domain.random_pool, - temperature, - -drift_ux, - in::x1); - - // initial position of injector - const auto x_init = domain.mesh.extent(in::x1).first + - filling_fraction * (domain.mesh.extent(in::x1).second - - domain.mesh.extent(in::x1).first); - - // check if injector is supposed to start moving already - const auto dt_inj = time - injection_start > ZERO ? time - injection_start - : ZERO; - - // define box to inject into - boundaries_t box; - - // loop over all dimension - for (auto d = 0u; d < M::Dim; ++d) { - if (d == 0) { - box.push_back({ x_init + injector_velocity * (dt_inj)-drift_ux / - math::sqrt(1 + SQR(drift_ux)) * dt, - x_init + injector_velocity * (dt_inj + dt) }); - } else { - box.push_back(Range::All); - } - } + // same maxwell distribution as above + const auto energy_dist = arch::Maxwellian(domain.mesh.metric, + domain.random_pool, + temperature, + -drift_ux, + in::x1); + + // initial position of injector + const auto x_init = domain.mesh.extent(in::x1).first + + filling_fraction * (domain.mesh.extent(in::x1).second - + domain.mesh.extent(in::x1).first); - // spatial distribution of the particles - // -> hack to use the uniform distribution in NonUniformInjector - const auto spatial_dist = arch::Piston(domain.mesh.metric, - box[0].first, - box[0].second, - in::x1); - - // ToDo: extend Replenish to replace the current injector - const auto injector = - arch::NonUniformInjector( - energy_dist, - spatial_dist, - { 1, 2 }); - - // inject non-uniformly within the defined box - arch::InjectNonUniform(params, - domain, - injector, - ONE, - false, - box); - - /* - I thought this option would be better, but I can't get it to work - */ - - // const auto spatial_dist = arch::Replenish(domain.mesh.metric, - // domain.fields.bckp, - // box, - // TargetDensity, - // 1.0); - - // const auto injector = arch::NonUniformInjector( - // energy_dist, - // spatial_dist, - // {1, 2}); - - // const auto injector = arch::MovingInjector { - // domain.mesh.metric, - // domain.fields.bckp, - // energy_dist, - // box[0].first, - // box[0].second, - // 1.0, - // { 1, 2 } - // }; + // check if injector is supposed to start moving already + const auto dt_inj = time - injection_start > ZERO ? + time - injection_start : ZERO; + + // define box to inject into + boundaries_t box; + + // loop over all dimension + for (auto d = 0u; d < M::Dim; ++d) { + if (d == 0) { + box.push_back({ x_init + injector_velocity * dt_inj - + drift_ux / math::sqrt(1 + SQR(drift_ux)) * dt, + x_init + injector_velocity * (dt_inj + dt) }); + } else { + box.push_back(Range::All); + } } + + // spatial distribution of the particles + // -> hack to use the uniform distribution in NonUniformInjector + const auto spatial_dist = arch::Piston(domain.mesh.metric, + box[0].first, + box[0].second, + in::x1); + + // ToDo: extend Replenish to replace the current injector + const auto injector = arch::NonUniformInjector( + energy_dist, + spatial_dist, + { 1, 2 }); + + // inject non-uniformly within the defined box + arch::InjectNonUniform(params, + domain, + injector, + ONE, + false, + box); + + /* + I thought this option would be better, but I can't get it to work + */ + + // const auto spatial_dist = arch::Replenish(domain.mesh.metric, + // domain.fields.bckp, + // box, + // TargetDensity, + // 1.0); + + // const auto injector = arch::NonUniformInjector( + // energy_dist, + // spatial_dist, + // {1, 2}); + + // const auto injector = arch::MovingInjector { + // domain.mesh.metric, + // domain.fields.bckp, + // energy_dist, + // box[0].first, + // box[0].second, + // 1.0, + // { 1, 2 } + // }; } }; From b3ee77b9714c2e83fb1b3be6caf397cf30255fbe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20B=C3=B6ss?= Date: Mon, 24 Mar 2025 16:06:42 -0500 Subject: [PATCH 565/773] applied formatting to `MovingInjector` --- src/archetypes/particle_injector.h | 123 ++++++++++++++--------------- 1 file changed, 58 insertions(+), 65 deletions(-) diff --git a/src/archetypes/particle_injector.h b/src/archetypes/particle_injector.h index 676cf2857..62b9249c3 100644 --- a/src/archetypes/particle_injector.h +++ b/src/archetypes/particle_injector.h @@ -171,72 +171,65 @@ namespace arch { }; template - struct MovingInjector - { - struct TargetDensityProfile - { - const real_t nmax, xinj, xdrift; - - TargetDensityProfile(real_t xinj, real_t xdrift, real_t nmax) - : xinj{xinj}, xdrift{xdrift}, nmax{nmax} {} - - Inline auto operator()(const coord_t &x_Ph) const -> real_t - { - if constexpr ((O == in::x1) or - (O == in::x2 and (M::Dim == Dim::_2D or M::Dim == Dim::_3D)) or - (O == in::x3 and M::Dim == Dim::_3D)) - { - const auto xi = x_Ph[static_cast(O)]; - // + direction - if (xi < xdrift or xi >= xinj) - { - return ZERO; - } - else - { - if constexpr (M::CoordType == Coord::Cart) - { - return nmax; - } - else - { - raise::KernelError( - HERE, - "Moving injector in +x cannot be applied for non-cartesian"); - return ZERO; - } - } - } - else - { - raise::KernelError(HERE, "Wrong direction"); - return ZERO; - } + struct MovingInjector { + struct TargetDensityProfile { + const real_t nmax, xinj, xdrift; + + TargetDensityProfile(real_t xinj, real_t xdrift, real_t nmax) + : xinj { xinj } + , xdrift { xdrift } + , nmax { nmax } {} + + Inline auto operator()(const coord_t& x_Ph) const -> real_t { + if constexpr ((O == in::x1) or + (O == in::x2 and (M::Dim == Dim::_2D or M::Dim == Dim::_3D)) or + (O == in::x3 and M::Dim == Dim::_3D)) { + const auto xi = x_Ph[static_cast(O)]; + // + direction + if (xi < xdrift or xi >= xinj) { + return ZERO; + } else { + if constexpr (M::CoordType == Coord::Cart) { + return nmax; + } else { + raise::KernelError( + HERE, + "Moving injector in +x cannot be applied for non-cartesian"); + return ZERO; } - }; - using energy_dist_t = Maxwellian; - using spatial_dist_t = Replenish; - static_assert(M::is_metric, "M must be a metric class"); - static constexpr bool is_nonuniform_injector{true}; - static constexpr Dimension D{M::Dim}; - static constexpr Coord C{M::CoordType}; - - const energy_dist_t energy_dist; - const TargetDensityProfile target_density; - const spatial_dist_t spatial_dist; - const std::pair species; - - MovingInjector(const M &metric, - const ndfield_t &density, - const energy_dist_t &energy_dist, - real_t xinj, - real_t xdrift, - real_t nmax, - const std::pair &species) - : energy_dist{energy_dist}, - target_density{xinj, xdrift, nmax}, spatial_dist{metric, density, 0, target_density, nmax}, species{species} {} - - ~MovingInjector() = default; + } + } else { + raise::KernelError(HERE, "Wrong direction"); + return ZERO; + } + } + }; + + using energy_dist_t = Maxwellian; + using spatial_dist_t = Replenish; + static_assert(M::is_metric, "M must be a metric class"); + static constexpr bool is_nonuniform_injector { true }; + static constexpr Dimension D { M::Dim }; + static constexpr Coord C { M::CoordType }; + + const energy_dist_t energy_dist; + const TargetDensityProfile target_density; + const spatial_dist_t spatial_dist; + const std::pair species; + + MovingInjector(const M& metric, + const ndfield_t& density, + const energy_dist_t& energy_dist, + real_t xinj, + real_t xdrift, + real_t nmax, + const std::pair& species) + : energy_dist { energy_dist } + , target_density { xinj, xdrift, nmax } + , spatial_dist { metric, density, 0, target_density, nmax } + , species { species } {} + + ~MovingInjector() = default; }; /** From 8d61ce85a70cc3fed3b4a57db2f84a4c7bccad45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20B=C3=B6ss?= Date: Mon, 31 Mar 2025 11:03:57 -0500 Subject: [PATCH 566/773] first attempt at moving-window injection --- setups/srpic/shock/pgen.hpp | 123 +++++++++++++++++++++++++++++++++--- 1 file changed, 114 insertions(+), 9 deletions(-) diff --git a/setups/srpic/shock/pgen.hpp b/setups/srpic/shock/pgen.hpp index 30ab01538..9568767ff 100644 --- a/setups/srpic/shock/pgen.hpp +++ b/setups/srpic/shock/pgen.hpp @@ -83,6 +83,7 @@ namespace user { const real_t drift_ux, temperature, filling_fraction; // injector properties const real_t injector_velocity, injection_start, dt; + const int injection_frequency; // magnetic field properties real_t Btheta, Bphi, Bmag; InitFields init_flds; @@ -98,6 +99,7 @@ namespace user { , filling_fraction { p.template get("setup.filling_fraction", 1.0) } , injector_velocity { p.template get("setup.injector_velocity", 1.0) } , injection_start { p.template get("setup.injection_start", 0.0) } + , injection_frequency { p.template get("setup.injection_frequency", 100) } , dt { p.template get("algorithms.timestep.dt") } {} inline PGen() {} @@ -106,6 +108,25 @@ namespace user { return init_flds; } + auto ResetFields(const em& comp) const -> real_t { + if (comp == em::ex1) { + return init_flds.ex1({ ZERO }); + } else if (comp == em::ex2) { + return init_flds.ex2({ ZERO }); + } else if (comp == em::ex3) { + return init_flds.ex3({ ZERO }); + } else if (comp == em::bx1) { + return init_flds.bx1({ ZERO }); + } else if (comp == em::bx2) { + return init_flds.bx2({ ZERO }); + } else if (comp == em::bx3) { + return init_flds.bx3({ ZERO }); + } else { + raise::Error("Invalid component", HERE); + return ZERO; + } + } + inline void InitPrtls(Domain& local_domain) { // minimum and maximum position of particles @@ -155,14 +176,12 @@ namespace user { box); } - void CustomPostStep(std::size_t, long double time, Domain& domain) { + void CustomPostStep(std::size_t step, long double time, Domain& domain) { - // same maxwell distribution as above - const auto energy_dist = arch::Maxwellian(domain.mesh.metric, - domain.random_pool, - temperature, - -drift_ux, - in::x1); + // check if the injector should be active + if (step % injection_frequency != 0) { + return; + } // initial position of injector const auto x_init = domain.mesh.extent(in::x1).first + @@ -180,13 +199,99 @@ namespace user { for (auto d = 0u; d < M::Dim; ++d) { if (d == 0) { box.push_back({ x_init + injector_velocity * dt_inj - - drift_ux / math::sqrt(1 + SQR(drift_ux)) * dt, + drift_ux / math::sqrt(1 + SQR(drift_ux)) * dt - + 1.5 * injection_frequency * dt, x_init + injector_velocity * (dt_inj + dt) }); } else { box.push_back(Range::All); } } + // define indice range to reset fields + boundaries_t incl_ghosts; + for (auto d = 0; d < M::Dim; ++d) { + incl_ghosts.push_back({ true, true }); + } + const auto extent = domain.mesh.ExtentToRange(box, incl_ghosts); + tuple_t x_min { 0 }, x_max { 0 }; + for (auto d = 0; d < M::Dim; ++d) { + x_min[d] = extent[d].first; + x_max[d] = extent[d].second; + } + + // reset fields + std::vector comps = { em::ex1, em::ex2, em::ex3, + em::bx1, em::bx2, em::bx3 }; + + // loop over all components + for (const auto& comp : comps) { + auto value = ResetFields((em)comp); + + if constexpr (M::Dim == Dim::_1D) { + Kokkos::deep_copy(Kokkos::subview(domain.fields.em, + std::make_pair(x_min[0], x_max[0]), + comp), + value); + } else if constexpr (M::Dim == Dim::_2D) { + Kokkos::deep_copy(Kokkos::subview(domain.fields.em, + std::make_pair(x_min[0], x_max[0]), + std::make_pair(x_min[1], x_max[1]), + comp), + value); + } else if constexpr (M::Dim == Dim::_3D) { + Kokkos::deep_copy(Kokkos::subview(domain.fields.em, + std::make_pair(x_min[0], x_max[0]), + std::make_pair(x_min[1], x_max[1]), + std::make_pair(x_min[2], x_max[2]), + comp), + value); + } else { + raise::Error("Invalid dimension", HERE); + } + } + + /* + tag particles inside the injection zone as dead + */ + + // loop over particle species + for (std::size_t s { 0 }; s < 2; ++s) { + + // get particle properties + auto& species = domain.species[s]; + auto i1 = species.i1; + auto tag = species.tag; + + + // tag all particles with x > box[0].first as dead + Kokkos::parallel_for( + "RemoveParticles", + species.rangeActiveParticles(), + Lambda(index_t p) { + // check if the particle is already dead + if (tag(p) == ParticleTag::dead) { + return; + } + // select the x-coordinate index + auto x_i1 = i1(p); + // check if the particle is inside the box of new plasma + if (x_i1 > x_min[0]) { + tag(p) = ParticleTag::dead; + } + } + ); + } + + /* + Inject piston of fresh plasma + */ + + // same maxwell distribution as above + const auto energy_dist = arch::Maxwellian(domain.mesh.metric, + domain.random_pool, + temperature, + -drift_ux, + in::x1); // spatial distribution of the particles // -> hack to use the uniform distribution in NonUniformInjector const auto spatial_dist = arch::Piston(domain.mesh.metric, @@ -194,7 +299,7 @@ namespace user { box[0].second, in::x1); - // ToDo: extend Replenish to replace the current injector + // inject piston of fresh plasma const auto injector = arch::NonUniformInjector( energy_dist, spatial_dist, From b2c738af48dce1d73b7021ae3fbf401c96984817 Mon Sep 17 00:00:00 2001 From: LudwigBoess Date: Mon, 31 Mar 2025 21:52:04 -0500 Subject: [PATCH 567/773] extended field reset box to the right to squash waves propagating into the empty box --- setups/srpic/shock/pgen.hpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/setups/srpic/shock/pgen.hpp b/setups/srpic/shock/pgen.hpp index 9568767ff..a25c3891a 100644 --- a/setups/srpic/shock/pgen.hpp +++ b/setups/srpic/shock/pgen.hpp @@ -190,17 +190,16 @@ namespace user { // check if injector is supposed to start moving already const auto dt_inj = time - injection_start > ZERO ? - time - injection_start : ZERO; + time - injection_start : ZERO; // define box to inject into boundaries_t box; - // loop over all dimension for (auto d = 0u; d < M::Dim; ++d) { if (d == 0) { box.push_back({ x_init + injector_velocity * dt_inj - drift_ux / math::sqrt(1 + SQR(drift_ux)) * dt - - 1.5 * injection_frequency * dt, + injection_frequency * dt, x_init + injector_velocity * (dt_inj + dt) }); } else { box.push_back(Range::All); @@ -212,7 +211,9 @@ namespace user { for (auto d = 0; d < M::Dim; ++d) { incl_ghosts.push_back({ true, true }); } - const auto extent = domain.mesh.ExtentToRange(box, incl_ghosts); + auto fields_box = box; + fields_box[0].second += injection_frequency * dt; + const auto extent = domain.mesh.ExtentToRange(fields_box, incl_ghosts); tuple_t x_min { 0 }, x_max { 0 }; for (auto d = 0; d < M::Dim; ++d) { x_min[d] = extent[d].first; @@ -220,11 +221,13 @@ namespace user { } // reset fields - std::vector comps = { em::ex1, em::ex2, em::ex3, - em::bx1, em::bx2, em::bx3 }; + std::vector comps = { em::bx1, em::bx2, em::bx3, + em::ex1, em::ex2, em::ex3 }; // loop over all components for (const auto& comp : comps) { + + // get initial field value of component auto value = ResetFields((em)comp); if constexpr (M::Dim == Dim::_1D) { @@ -262,7 +265,6 @@ namespace user { auto i1 = species.i1; auto tag = species.tag; - // tag all particles with x > box[0].first as dead Kokkos::parallel_for( "RemoveParticles", From fb1692875ad050ba73dee745d0800dd356d9f8bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20B=C3=B6ss?= Date: Tue, 1 Apr 2025 15:32:04 -0500 Subject: [PATCH 568/773] bugfix: added check to truncate the injection box at the end of the domain --- setups/srpic/shock/pgen.hpp | 48 ++++++++++++++++++++++--------------- 1 file changed, 29 insertions(+), 19 deletions(-) diff --git a/setups/srpic/shock/pgen.hpp b/setups/srpic/shock/pgen.hpp index a25c3891a..cf58b94c6 100644 --- a/setups/srpic/shock/pgen.hpp +++ b/setups/srpic/shock/pgen.hpp @@ -80,10 +80,10 @@ namespace user { using arch::ProblemGenerator::params; // gas properties - const real_t drift_ux, temperature, filling_fraction; + const real_t drift_ux, temperature, filling_fraction; // injector properties - const real_t injector_velocity, injection_start, dt; - const int injection_frequency; + const real_t injector_velocity, injection_start, dt; + const int injection_frequency; // magnetic field properties real_t Btheta, Bphi, Bmag; InitFields init_flds; @@ -189,18 +189,23 @@ namespace user { domain.mesh.extent(in::x1).first); // check if injector is supposed to start moving already - const auto dt_inj = time - injection_start > ZERO ? - time - injection_start : ZERO; + const auto dt_inj = time - injection_start > ZERO ? time - injection_start + : ZERO; + + // compute the position of the injector + auto xmax = x_init + injector_velocity * (dt_inj + dt); + if (xmax >= domain.mesh.extent(in::x1).second) { + xmax = domain.mesh.extent(in::x1).second; + } // define box to inject into boundaries_t box; // loop over all dimension for (auto d = 0u; d < M::Dim; ++d) { if (d == 0) { - box.push_back({ x_init + injector_velocity * dt_inj - - drift_ux / math::sqrt(1 + SQR(drift_ux)) * dt - - injection_frequency * dt, - x_init + injector_velocity * (dt_inj + dt) }); + box.push_back({ xmax - drift_ux / math::sqrt(1 + SQR(drift_ux)) * dt - + injection_frequency * dt, + xmax }); } else { box.push_back(Range::All); } @@ -212,7 +217,13 @@ namespace user { incl_ghosts.push_back({ true, true }); } auto fields_box = box; - fields_box[0].second += injection_frequency * dt; + // check if the box is still inside the domain + if (xmax + injection_frequency * dt < domain.mesh.extent(in::x1).second) { + fields_box[0].second += injection_frequency * dt; + } else { + // if right side of the box is outside of the domain -> truncate box + fields_box[0].second = domain.mesh.extent(in::x1).second; + } const auto extent = domain.mesh.ExtentToRange(fields_box, incl_ghosts); tuple_t x_min { 0 }, x_max { 0 }; for (auto d = 0; d < M::Dim; ++d) { @@ -221,7 +232,7 @@ namespace user { } // reset fields - std::vector comps = { em::bx1, em::bx2, em::bx3, + std::vector comps = { em::bx1, em::bx2, em::bx3, em::ex1, em::ex2, em::ex3 }; // loop over all components @@ -253,8 +264,8 @@ namespace user { } } - /* - tag particles inside the injection zone as dead + /* + tag particles inside the injection zone as dead */ // loop over particle species @@ -262,8 +273,8 @@ namespace user { // get particle properties auto& species = domain.species[s]; - auto i1 = species.i1; - auto tag = species.tag; + auto i1 = species.i1; + auto tag = species.tag; // tag all particles with x > box[0].first as dead Kokkos::parallel_for( @@ -277,14 +288,13 @@ namespace user { // select the x-coordinate index auto x_i1 = i1(p); // check if the particle is inside the box of new plasma - if (x_i1 > x_min[0]) { + if (x_i1 >= x_min[0]) { tag(p) = ParticleTag::dead; } - } - ); + }); } - /* + /* Inject piston of fresh plasma */ From 884a1571f2c12f096fe966b81bf066294e499f03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20B=C3=B6ss?= Date: Tue, 1 Apr 2025 19:46:46 -0500 Subject: [PATCH 569/773] fix unit conversion bug in field reset --- setups/srpic/shock/pgen.hpp | 40 ++++++++----------------------------- 1 file changed, 8 insertions(+), 32 deletions(-) diff --git a/setups/srpic/shock/pgen.hpp b/setups/srpic/shock/pgen.hpp index cf58b94c6..ad260bda0 100644 --- a/setups/srpic/shock/pgen.hpp +++ b/setups/srpic/shock/pgen.hpp @@ -9,6 +9,7 @@ #include "utils/numeric.h" #include "archetypes/energy_dist.h" +#include "archetypes/field_setter.h" #include "archetypes/particle_injector.h" #include "archetypes/problem_generator.h" #include "framework/domain/metadomain.h" @@ -231,38 +232,13 @@ namespace user { x_max[d] = extent[d].second; } - // reset fields - std::vector comps = { em::bx1, em::bx2, em::bx3, - em::ex1, em::ex2, em::ex3 }; - - // loop over all components - for (const auto& comp : comps) { - - // get initial field value of component - auto value = ResetFields((em)comp); - - if constexpr (M::Dim == Dim::_1D) { - Kokkos::deep_copy(Kokkos::subview(domain.fields.em, - std::make_pair(x_min[0], x_max[0]), - comp), - value); - } else if constexpr (M::Dim == Dim::_2D) { - Kokkos::deep_copy(Kokkos::subview(domain.fields.em, - std::make_pair(x_min[0], x_max[0]), - std::make_pair(x_min[1], x_max[1]), - comp), - value); - } else if constexpr (M::Dim == Dim::_3D) { - Kokkos::deep_copy(Kokkos::subview(domain.fields.em, - std::make_pair(x_min[0], x_max[0]), - std::make_pair(x_min[1], x_max[1]), - std::make_pair(x_min[2], x_max[2]), - comp), - value); - } else { - raise::Error("Invalid dimension", HERE); - } - } + Kokkos::parallel_for("ResetFields", + CreateRangePolicy(x_min, x_max), + arch::SetEMFields_kernel { + domain.fields.em, + init_flds, + domain.mesh.metric }); + /* tag particles inside the injection zone as dead From 3f4c5659a95c2d30af22530a8198676de6d44e9c Mon Sep 17 00:00:00 2001 From: hayk Date: Fri, 4 Apr 2025 15:40:17 -0400 Subject: [PATCH 570/773] conductor in all directions --- src/kernels/fields_bcs.hpp | 288 ++++++++++++++++++++++++++++++------- 1 file changed, 240 insertions(+), 48 deletions(-) diff --git a/src/kernels/fields_bcs.hpp b/src/kernels/fields_bcs.hpp index 8ea6b72d8..970ab559e 100644 --- a/src/kernels/fields_bcs.hpp +++ b/src/kernels/fields_bcs.hpp @@ -486,38 +486,52 @@ namespace kernel::bc { } }; - template + template struct ConductorBoundaries_kernel { static_assert(static_cast(o) < static_cast(D), "Invalid component index"); - ndfield_t Fld; - const BCTags tags; + ndfield_t Fld; + const BCTags tags; + const std::size_t i_edge; - ConductorBoundaries_kernel(ndfield_t Fld, BCTags tags) + ConductorBoundaries_kernel(ndfield_t Fld, std::size_t i_edge, BCTags tags) : Fld { Fld } + , i_edge { i_edge } , tags { tags } {} Inline void operator()(index_t i1) const { if constexpr (D == Dim::_1D) { if (tags & BC::E) { if (i1 == 0) { - Fld(N_GHOSTS, em::ex2) = ZERO; - Fld(N_GHOSTS, em::ex3) = ZERO; + Fld(i_edge, em::ex2) = ZERO; + Fld(i_edge, em::ex3) = ZERO; } else { - Fld(N_GHOSTS - i1, em::ex1) = Fld(N_GHOSTS + i1 - 1, em::ex1); - Fld(N_GHOSTS - i1, em::ex2) = -Fld(N_GHOSTS + i1, em::ex2); - Fld(N_GHOSTS - i1, em::ex3) = -Fld(N_GHOSTS + i1, em::ex3); + if constexpr (not P) { + Fld(i_edge - i1, em::ex1) = Fld(i_edge + i1 - 1, em::ex1); + Fld(i_edge - i1, em::ex2) = -Fld(i_edge + i1, em::ex2); + Fld(i_edge - i1, em::ex3) = -Fld(i_edge + i1, em::ex3); + } else { + Fld(i_edge + i1 - 1, em::ex1) = Fld(i_edge - i1, em::ex1); + Fld(i_edge + i1, em::ex2) = -Fld(i_edge - i1, em::ex2); + Fld(i_edge + i1, em::ex3) = -Fld(i_edge - i1, em::ex3); + } } } if (tags & BC::B) { if (i1 == 0) { - Fld(N_GHOSTS, em::bx1) = ZERO; + Fld(i_edge, em::bx1) = ZERO; } else { - Fld(N_GHOSTS - i1, em::bx1) = -Fld(N_GHOSTS + i1, em::bx1); - Fld(N_GHOSTS - i1, em::bx2) = Fld(N_GHOSTS + i1 - 1, em::bx2); - Fld(N_GHOSTS - i1, em::bx3) = Fld(N_GHOSTS + i1 - 1, em::bx3); + if constexpr (not P) { + Fld(i_edge - i1, em::bx1) = -Fld(i_edge + i1, em::bx1); + Fld(i_edge - i1, em::bx2) = Fld(i_edge + i1 - 1, em::bx2); + Fld(i_edge - i1, em::bx3) = Fld(i_edge + i1 - 1, em::bx3); + } else { + Fld(i_edge + i1, em::bx1) = -Fld(i_edge - i1, em::bx1); + Fld(i_edge + i1 - 1, em::bx2) = Fld(i_edge - i1, em::bx2); + Fld(i_edge + i1 - 1, em::bx3) = Fld(i_edge - i1, em::bx3); + } } } } else { @@ -529,24 +543,71 @@ namespace kernel::bc { Inline void operator()(index_t i1, index_t i2) const { if constexpr (D == Dim::_2D) { - if (tags & BC::E) { - if (i1 == 0) { - Fld(N_GHOSTS, i2, em::ex2) = ZERO; - Fld(N_GHOSTS, i2, em::ex3) = ZERO; - } else { - Fld(N_GHOSTS - i1, i2, em::ex1) = Fld(N_GHOSTS + i1 - 1, i2, em::ex1); - Fld(N_GHOSTS - i1, i2, em::ex2) = -Fld(N_GHOSTS + i1, i2, em::ex2); - Fld(N_GHOSTS - i1, i2, em::ex3) = -Fld(N_GHOSTS + i1, i2, em::ex3); + if constexpr (o == in::x1) { + if (tags & BC::E) { + if (i1 == 0) { + Fld(i_edge, i2, em::ex2) = ZERO; + Fld(i_edge, i2, em::ex3) = ZERO; + } else { + if constexpr (not P) { + Fld(i_edge - i1, i2, em::ex1) = Fld(i_edge + i1 - 1, i2, em::ex1); + Fld(i_edge - i1, i2, em::ex2) = -Fld(i_edge + i1, i2, em::ex2); + Fld(i_edge - i1, i2, em::ex3) = -Fld(i_edge + i1, i2, em::ex3); + } else { + Fld(i_edge + i1 - 1, i2, em::ex1) = Fld(i_edge - i1, i2, em::ex1); + Fld(i_edge + i1, i2, em::ex2) = -Fld(i_edge - i1, i2, em::ex2); + Fld(i_edge + i1, i2, em::ex3) = -Fld(i_edge - i1, i2, em::ex3); + } + } } - } - if (tags & BC::B) { - if (i1 == 0) { - Fld(N_GHOSTS, i2, em::bx1) = ZERO; - } else { - Fld(N_GHOSTS - i1, i2, em::bx1) = -Fld(N_GHOSTS + i1, i2, em::bx1); - Fld(N_GHOSTS - i1, i2, em::bx2) = Fld(N_GHOSTS + i1 - 1, i2, em::bx2); - Fld(N_GHOSTS - i1, i2, em::bx3) = Fld(N_GHOSTS + i1 - 1, i2, em::bx3); + if (tags & BC::B) { + if (i1 == 0) { + Fld(i_edge, i2, em::bx1) = ZERO; + } else { + if constexpr (not P) { + Fld(i_edge - i1, i2, em::bx1) = -Fld(i_edge + i1, i2, em::bx1); + Fld(i_edge - i1, i2, em::bx2) = Fld(i_edge + i1 - 1, i2, em::bx2); + Fld(i_edge - i1, i2, em::bx3) = Fld(i_edge + i1 - 1, i2, em::bx3); + } else { + Fld(i_edge + i1, i2, em::bx1) = -Fld(i_edge - i1, i2, em::bx1); + Fld(i_edge + i1 - 1, i2, em::bx2) = Fld(i_edge - i1, i2, em::bx2); + Fld(i_edge + i1 - 1, i2, em::bx3) = Fld(i_edge - i1, i2, em::bx3); + } + } + } + } else { + if (tags & BC::E) { + if (i2 == 0) { + Fld(i1, i_edge, em::ex1) = ZERO; + Fld(i1, i_edge, em::ex3) = ZERO; + } else { + if constexpr (not P) { + Fld(i1, i_edge - i2, em::ex1) = -Fld(i1, i_edge + i2, em::ex1); + Fld(i1, i_edge - i2, em::ex2) = Fld(i1, i_edge + i2 - 1, em::ex2); + Fld(i1, i_edge - i2, em::ex3) = -Fld(i1, i_edge + i2, em::ex3); + } else { + Fld(i1, i_edge + i2, em::ex1) = -Fld(i1, i_edge - i2, em::ex1); + Fld(i1, i_edge + i2 - 1, em::ex2) = Fld(i1, i_edge - i2, em::ex2); + Fld(i1, i_edge + i2, em::ex3) = -Fld(i1, i_edge - i2, em::ex3); + } + } + } + + if (tags & BC::B) { + if (i2 == 0) { + Fld(i1, i_edge, em::bx2) = ZERO; + } else { + if constexpr (not P) { + Fld(i1, i_edge - i2, em::bx1) = Fld(i1, i_edge + i2 - 1, em::bx1); + Fld(i1, i_edge - i2, em::bx2) = -Fld(i1, i_edge + i2, em::bx2); + Fld(i1, i_edge - i2, em::bx3) = Fld(i1, i_edge + i2 - 1, em::bx3); + } else { + Fld(i1, i_edge + i2 - 1, em::bx1) = Fld(i1, i_edge - i2, em::bx1); + Fld(i1, i_edge + i2, em::bx2) = -Fld(i1, i_edge - i2, em::bx2); + Fld(i1, i_edge + i2 - 1, em::bx3) = Fld(i1, i_edge - i2, em::bx3); + } + } } } } else { @@ -558,27 +619,158 @@ namespace kernel::bc { Inline void operator()(index_t i1, index_t i2, index_t i3) const { if constexpr (D == Dim::_3D) { - if (tags & BC::E) { - if (i1 == 0) { - Fld(N_GHOSTS, i2, i3, em::ex2) = ZERO; - Fld(N_GHOSTS, i2, i3, em::ex3) = ZERO; - } else { - Fld(N_GHOSTS - i1, i2, i3, em::ex1) = Fld(N_GHOSTS + i1 - 1, - i2, i3, em::ex1); - Fld(N_GHOSTS - i1, i2, i3, em::ex2) = -Fld(N_GHOSTS + i1, i2, i3, em::ex2); - Fld(N_GHOSTS - i1, i2, i3, em::ex3) = -Fld(N_GHOSTS + i1, i2, i3, em::ex3); + if constexpr (o == in::x1) { + if (tags & BC::E) { + if (i1 == 0) { + Fld(i_edge, i2, i3, em::ex2) = ZERO; + Fld(i_edge, i2, i3, em::ex3) = ZERO; + } else { + if constexpr (not P) { + Fld(i_edge - i1, i2, i3, em::ex1) = Fld(i_edge + i1 - 1, + i2, + i3, + em::ex1); + Fld(i_edge - i1, i2, i3, em::ex2) = -Fld(i_edge + i1, i2, i3, em::ex2); + Fld(i_edge - i1, i2, i3, em::ex3) = -Fld(i_edge + i1, i2, i3, em::ex3); + } else { + Fld(i_edge + i1 - 1, i2, i3, em::ex1) = Fld(i_edge - i1, + i2, + i3, + em::ex1); + Fld(i_edge + i1, i2, i3, em::ex2) = -Fld(i_edge - i1, i2, i3, em::ex2); + Fld(i_edge + i1, i2, i3, em::ex3) = -Fld(i_edge - i1, i2, i3, em::ex3); + } + } } - } - if (tags & BC::B) { - if (i1 == 0) { - Fld(N_GHOSTS, i2, i3, em::bx1) = ZERO; - } else { - Fld(N_GHOSTS - i1, i2, i3, em::bx1) = -Fld(N_GHOSTS + i1, i2, i3, em::bx1); - Fld(N_GHOSTS - i1, i2, i3, em::bx2) = Fld(N_GHOSTS + i1 - 1, - i2, i3, em::bx2); - Fld(N_GHOSTS - i1, i2, i3, em::bx3) = Fld(N_GHOSTS + i1 - 1, - i2, i3, em::bx3); + if (tags & BC::B) { + if (i1 == 0) { + Fld(i_edge, i2, i3, em::bx1) = ZERO; + } else { + if constexpr (not P) { + Fld(i_edge - i1, i2, i3, em::bx1) = -Fld(i_edge + i1, i2, i3, em::bx1); + Fld(i_edge - i1, i2, i3, em::bx2) = Fld(i_edge + i1 - 1, + i2, + i3, + em::bx2); + Fld(i_edge - i1, i2, i3, em::bx3) = Fld(i_edge + i1 - 1, + i2, + i3, + em::bx3); + } else { + Fld(i_edge + i1, i2, i3, em::bx1) = -Fld(i_edge - i1, i2, i3, em::bx1); + Fld(i_edge + i1 - 1, i2, i3, em::bx2) = Fld(i_edge - i1, + i2, + i3, + em::bx2); + Fld(i_edge + i1 - 1, i2, i3, em::bx3) = Fld(i_edge - i1, + i2, + i3, + em::bx3); + } + } + } + } else if (o == in::x2) { + if (tags & BC::E) { + if (i2 == 0) { + Fld(i1, i_edge, i3, em::ex1) = ZERO; + Fld(i1, i_edge, i3, em::ex3) = ZERO; + } else { + if constexpr (not P) { + Fld(i1, i_edge - i2, i3, em::ex1) = -Fld(i1, i_edge + i2, i3, em::ex1); + Fld(i1, i_edge - i2, i3, em::ex2) = Fld(i1, + i_edge + i2 - 1, + i3, + em::ex2); + Fld(i1, i_edge - i2, i3, em::ex3) = -Fld(i1, i_edge + i2, i3, em::ex3); + } else { + Fld(i1, i_edge + i2, i3, em::ex1) = -Fld(i1, i_edge - i2, i3, em::ex1); + Fld(i1, i_edge + i2 - 1, i3, em::ex2) = Fld(i1, + i_edge - i2, + i3, + em::ex2); + Fld(i1, i_edge + i2, i3, em::ex3) = -Fld(i1, i_edge - i2, i3, em::ex3); + } + } + } + + if (tags & BC::B) { + if (i2 == 0) { + Fld(i1, i_edge, i3, em::bx2) = ZERO; + } else { + if constexpr (not P) { + Fld(i1, i_edge - i2, i3, em::bx1) = Fld(i1, + i_edge + i2 - 1, + i3, + em::bx1); + Fld(i1, i_edge - i2, i3, em::bx2) = -Fld(i1, i_edge + i2, i3, em::bx2); + Fld(i1, i_edge - i2, i3, em::bx3) = Fld(i1, + i_edge + i2 - 1, + i3, + em::bx3); + } else { + Fld(i1, i_edge + i2 - 1, i3, em::bx1) = Fld(i1, + i_edge - i2, + i3, + em::bx1); + Fld(i1, i_edge + i2, i3, em::bx2) = -Fld(i1, i_edge - i2, i3, em::bx2); + Fld(i1, i_edge + i2 - 1, i3, em::bx3) = Fld(i1, + i_edge - i2, + i3, + em::bx3); + } + } + } + } else { + if (tags & BC::E) { + if (i3 == 0) { + Fld(i1, i2, i_edge, em::ex1) = ZERO; + Fld(i1, i2, i_edge, em::ex2) = ZERO; + } else { + if constexpr (not P) { + Fld(i1, i2, i_edge - i3, em::ex1) = -Fld(i1, i2, i_edge + i3, em::ex1); + Fld(i1, i2, i_edge - i3, em::ex2) = -Fld(i1, i2, i_edge + i3, em::ex2); + Fld(i1, i2, i_edge - i3, em::ex3) = Fld(i1, + i2, + i_edge + i3 - 1, + em::ex3); + } else { + Fld(i1, i2, i_edge + i3, em::ex1) = -Fld(i1, i2, i_edge - i3, em::ex1); + Fld(i1, i2, i_edge + i3, em::ex2) = -Fld(i1, i2, i_edge - i3, em::ex2); + Fld(i1, i2, i_edge + i3 - 1, em::ex3) = Fld(i1, + i2, + i_edge - i3, + em::ex3); + } + } + } + + if (tags & BC::B) { + if (i3 == 0) { + Fld(i1, i2, i_edge, em::bx3) = ZERO; + } else { + if constexpr (not P) { + Fld(i1, i2, i_edge - i3, em::bx1) = Fld(i1, + i2, + i_edge + i3 - 1, + em::bx1); + Fld(i1, i2, i_edge - i3, em::bx2) = Fld(i1, + i2, + i_edge + i3 - 1, + em::bx2); + Fld(i1, i2, i_edge - i3, em::bx3) = -Fld(i1, i2, i_edge + i3, em::bx3); + } else { + Fld(i1, i2, i_edge + i3 - 1, em::bx1) = Fld(i1, + i2, + i_edge - i3, + em::bx1); + Fld(i1, i2, i_edge + i3 - 1, em::bx2) = Fld(i1, + i2, + i_edge - i3, + em::bx2); + Fld(i1, i2, i_edge + i3, em::bx3) = -Fld(i1, i2, i_edge - i3, em::bx3); + } + } } } } else { From 6ae91c91fc8176b01964589caffaab8e8225cb73 Mon Sep 17 00:00:00 2001 From: hayk Date: Fri, 4 Apr 2025 15:44:54 -0400 Subject: [PATCH 571/773] minor formatting --- src/engines/srpic.hpp | 72 ++++++++++++++++++++++++------------------- 1 file changed, 41 insertions(+), 31 deletions(-) diff --git a/src/engines/srpic.hpp b/src/engines/srpic.hpp index b1fca46da..3684fb573 100644 --- a/src/engines/srpic.hpp +++ b/src/engines/srpic.hpp @@ -651,7 +651,7 @@ namespace ntt { tuple_t range_min { 0 }; tuple_t range_max { 0 }; - for (unsigned short d { 0 }; d < M::Dim; ++d) { + for (auto d { 0u }; d < M::Dim; ++d) { range_min[d] = intersect_range[d].first; range_max[d] = intersect_range[d].second; } @@ -708,28 +708,32 @@ namespace ntt { /** * axis boundaries */ - raise::ErrorIf(M::CoordType == Coord::Cart, - "Invalid coordinate type for axis BCs", - HERE); - raise::ErrorIf(direction.get_dim() != in::x2, - "Invalid axis direction, should be x2", - HERE); - const auto i2_min = domain.mesh.i_min(in::x2); - const auto i2_max = domain.mesh.i_max(in::x2); - if (direction.get_sign() < 0) { - Kokkos::parallel_for( - "AxisBCFields", - domain.mesh.n_all(in::x1), - kernel::bc::AxisBoundaries_kernel(domain.fields.em, - i2_min, - tags)); + if constexpr (M::CoordType != Coord::Cart) { + raise::ErrorIf(direction.get_dim() != in::x2, + "Invalid axis direction, should be x2", + HERE); + const auto i2_min = domain.mesh.i_min(in::x2); + const auto i2_max = domain.mesh.i_max(in::x2); + if (direction.get_sign() < 0) { + Kokkos::parallel_for( + "AxisBCFields", + domain.mesh.n_all(in::x1), + kernel::bc::AxisBoundaries_kernel(domain.fields.em, + i2_min, + tags)); + } else { + Kokkos::parallel_for( + "AxisBCFields", + domain.mesh.n_all(in::x1), + kernel::bc::AxisBoundaries_kernel(domain.fields.em, + i2_max, + tags)); + } } else { - Kokkos::parallel_for( - "AxisBCFields", - domain.mesh.n_all(in::x1), - kernel::bc::AxisBoundaries_kernel(domain.fields.em, - i2_max, - tags)); + (void)direction; + (void)domain; + (void)tags; + raise::Error("Invalid coordinate type for axis BCs", HERE); } } @@ -834,6 +838,9 @@ namespace ntt { } } } else { + (void)direction; + (void)domain; + (void)tags; raise::Error("Fixed fields not present (both const and non-const)", HERE); } } @@ -844,14 +851,7 @@ namespace ntt { /** * perfect conductor field boundaries */ - if constexpr (M::CoordType != Coord::Cart) { - (void)direction; - (void)domain; - (void)tags; - raise::Error( - "Perfect conductor BCs only applicable to cartesian coordinates", - HERE); - } else { + if constexpr (M::CoordType == Coord::Cart) { const auto sign = direction.get_sign(); const auto dim = direction.get_dim(); @@ -859,7 +859,7 @@ namespace ntt { const std::vector all_dirs { in::x1, in::x2, in::x3 }; - for (unsigned short d { 0 }; d < static_cast(M::Dim); ++d) { + for (auto d { 0u }; d < static_cast(M::Dim); ++d) { const auto dd = all_dirs[d]; if (dim == dd) { xi_min.push_back(0); @@ -936,6 +936,13 @@ namespace ntt { tags)); } } + } else { + (void)direction; + (void)domain; + (void)tags; + raise::Error( + "Perfect conductor BCs only applicable to cartesian coordinates", + HERE); } } @@ -1060,6 +1067,9 @@ namespace ntt { raise::Error("Invalid dimension", HERE); } } else { + (void)direction; + (void)domain; + (void)tags; raise::Error("Atm fields not implemented in PGEN for atmosphere BCs", HERE); } } From a31c9c72dd36e6fec2e5428c81eb1e18bb6cbc93 Mon Sep 17 00:00:00 2001 From: hayk Date: Fri, 4 Apr 2025 16:50:03 -0400 Subject: [PATCH 572/773] rm TODOs --- src/framework/domain/comm_mpi.hpp | 1 - src/framework/domain/grid.cpp | 1 - src/framework/domain/metadomain.cpp | 1 - src/framework/simulation.cpp | 2 -- 4 files changed, 5 deletions(-) diff --git a/src/framework/domain/comm_mpi.hpp b/src/framework/domain/comm_mpi.hpp index 4f382be4a..159502e7a 100644 --- a/src/framework/domain/comm_mpi.hpp +++ b/src/framework/domain/comm_mpi.hpp @@ -220,7 +220,6 @@ namespace comm { if (recv_rank >= 0) { - // !TODO: perhaps directly recv to the fld? if (not additive) { if constexpr (D == Dim::_1D) { Kokkos::deep_copy(Kokkos::subview(fld, recv_slice[0], comps), recv_fld); diff --git a/src/framework/domain/grid.cpp b/src/framework/domain/grid.cpp index baa23fb5c..c022184b1 100644 --- a/src/framework/domain/grid.cpp +++ b/src/framework/domain/grid.cpp @@ -85,7 +85,6 @@ namespace ntt { return CreateRangePolicy(imin, imax); } - // !TODO: too ugly, implement a better solution (combine with device) template auto Grid::rangeCellsOnHost( const box_region_t& region) const -> range_h_t { diff --git a/src/framework/domain/metadomain.cpp b/src/framework/domain/metadomain.cpp index 10e3e4fb0..eec6c8fa0 100644 --- a/src/framework/domain/metadomain.cpp +++ b/src/framework/domain/metadomain.cpp @@ -234,7 +234,6 @@ namespace ntt { template void Metadomain::redefineBoundaries() { - // !TODO: not setting CommBC for now for (unsigned int idx { 0 }; idx < g_ndomains; ++idx) { // offset of the subdomain[idx] auto& current_domain = g_subdomains[idx]; diff --git a/src/framework/simulation.cpp b/src/framework/simulation.cpp index bea50ff09..560539c25 100644 --- a/src/framework/simulation.cpp +++ b/src/framework/simulation.cpp @@ -48,8 +48,6 @@ namespace ntt { HERE); m_requested_dimension = static_cast(res.size()); - // !TODO: when mixing checkpoint metadata with input, - // ... need to properly take care of the diffs m_params.setRawData(raw_params); timestep_t checkpoint_step = 0; if (is_resuming) { From 58a6214d728ad779b6809754856a7b286a223749 Mon Sep 17 00:00:00 2001 From: hayk Date: Fri, 4 Apr 2025 16:50:21 -0400 Subject: [PATCH 573/773] conductor filters in full 3D --- src/kernels/digital_filter.hpp | 225 +++++++++++++++++++++++++++------ 1 file changed, 185 insertions(+), 40 deletions(-) diff --git a/src/kernels/digital_filter.hpp b/src/kernels/digital_filter.hpp index 0ec6dcdbc..4f1385c16 100644 --- a/src/kernels/digital_filter.hpp +++ b/src/kernels/digital_filter.hpp @@ -25,6 +25,33 @@ INV_2*(ARR)((I), (J), (COMP)) + \ INV_4*((ARR)((I), (J) - 1, (COMP)) + (ARR)((I), (J) + 1, (COMP))) +#define FILTER3D_IN_I1_I2(ARR, COMP, I, J, K) \ + INV_4*(ARR)(I, J, K, (COMP)) + \ + INV_8*((ARR)((I) - 1, (J), (K), (COMP)) + (ARR)((I) + 1, (J), (K), (COMP)) + \ + (ARR)((I), (J) - 1, (K), (COMP)) + (ARR)((I), (J) + 1, (K), (COMP))) + \ + INV_16*((ARR)((I) - 1, (J) - 1, (K), (COMP)) + \ + (ARR)((I) + 1, (J) + 1, (K), (COMP)) + \ + (ARR)((I) - 1, (J) + 1, (K), (COMP)) + \ + (ARR)((I) + 1, (J) - 1, (K), (COMP))) + +#define FILTER3D_IN_I2_I3(ARR, COMP, I, J, K) \ + INV_4*(ARR)(I, J, K, (COMP)) + \ + INV_8*((ARR)((I), (J) - 1, (K), (COMP)) + (ARR)((I), (J) + 1, (K), (COMP)) + \ + (ARR)((I), (J), (K) - 1, (COMP)) + (ARR)((I), (J), (K) + 1, (COMP))) + \ + INV_16*((ARR)((I), (J) - 1, (K) - 1, (COMP)) + \ + (ARR)((I), (J) + 1, (K) + 1, (COMP)) + \ + (ARR)((I), (J) - 1, (K) + 1, (COMP)) + \ + (ARR)((I), (J) + 1, (K) - 1, (COMP))) + +#define FILTER3D_IN_I1_I3(ARR, COMP, I, J, K) \ + INV_4*(ARR)(I, J, K, (COMP)) + \ + INV_8*((ARR)((I) - 1, (J), (K), (COMP)) + (ARR)((I) + 1, (J), (K), (COMP)) + \ + (ARR)((I), (J), (K) - 1, (COMP)) + (ARR)((I), (J), (K) + 1, (COMP))) + \ + INV_16*((ARR)((I) - 1, (J), (K) - 1, (COMP)) + \ + (ARR)((I) + 1, (J), (K) + 1, (COMP)) + \ + (ARR)((I) - 1, (J), (K) + 1, (COMP)) + \ + (ARR)((I) + 1, (J), (K) - 1, (COMP))) + namespace kernel { using namespace ntt; @@ -36,9 +63,14 @@ namespace kernel { static constexpr auto i2_min = N_GHOSTS; const ncells_t i2_max; const bool is_axis_i2min, is_axis_i2max; - const bool is_conductor_i1min; - static constexpr auto i1_min = N_GHOSTS, i2_min = N_GHOSTS; - const std::size_t i2_max; + const bool is_conductor_i1min, is_conductor_i1max; + const bool is_conductor_i2min, is_conductor_i2max; + const bool is_conductor_i3min, is_conductor_i3max; + static constexpr auto i1_min = N_GHOSTS, i2_min = N_GHOSTS, i3_min = N_GHOSTS; + const std::size_t i1_max, i2_max, i3_max; + + // @TODO: Current implementation might have issues + // ... at the corners between two conductors public: DigitalFilter_kernel(ndfield_t& array, @@ -50,21 +82,40 @@ namespace kernel { , is_axis_i2min { (D == Dim::_2D) and (boundaries[1].first == FldsBC::AXIS) } , is_axis_i2max { (D == Dim::_2D) and (boundaries[1].second == FldsBC::AXIS) } , is_conductor_i1min { boundaries[0].first == FldsBC::CONDUCTOR } - , i2_max { (short)D > 1 ? size_[1] + N_GHOSTS : 0 } {} + , is_conductor_i1max { boundaries[0].second == FldsBC::CONDUCTOR } + , is_conductor_i2min { (short)D > 1 + ? (boundaries[1].first == FldsBC::CONDUCTOR) + : false } + , is_conductor_i2max { (short)D > 1 + ? (boundaries[1].second == FldsBC::CONDUCTOR) + : false } + , is_conductor_i3min { (short)D > 2 + ? (boundaries[2].first == FldsBC::CONDUCTOR) + : false } + , is_conductor_i3max { (short)D > 2 + ? (boundaries[2].second == FldsBC::CONDUCTOR) + : false } + , i1_max { size_[0] + N_GHOSTS } + , i2_max { (short)D > 1 ? (size_[1] + N_GHOSTS) : 0 } + , i3_max { (short)D > 2 ? (size_[2] + N_GHOSTS) : 0 } {} Inline void operator()(index_t i1) const { if constexpr ((D == Dim::_1D) && (C == Coord::Cart)) { - if (is_conductor_i1min and i1 == i1_min) { + if ((is_conductor_i1min and i1 == i1_min) or + (is_conductor_i1max and i1 == i1_max - 1)) { + const auto i1side = is_conductor_i1min ? (i1 + 1) : (i1 - 1); array(i1, cur::jx1) = (THREE * INV_4) * buffer(i1, cur::jx1) + - (INV_4)*buffer(i1 + 1, cur::jx1); - } else if (is_conductor_i1min and i1 == i1_min + 1) { + (INV_4)*buffer(i1side, cur::jx1); + } else if ((is_conductor_i1min and i1 == i1_min + 1) or + (is_conductor_i1max and i1 == i1_max - 2)) { + const auto i1side = is_conductor_i1min ? (i1 + 1) : (i1 - 1); array(i1, cur::jx1) = INV_2 * buffer(i1, cur::jx1) + INV_4 * (buffer(i1 - 1, cur::jx1) + buffer(i1 + 1, cur::jx1)); array(i1, cur::jx2) = (INV_2)*buffer(i1, cur::jx2) + - (INV_4)*buffer(i1 + 1, cur::jx2); + (INV_4)*buffer(i1side, cur::jx2); array(i1, cur::jx3) = (INV_2)*buffer(i1, cur::jx3) + - (INV_4)*buffer(i1 + 1, cur::jx3); + (INV_4)*buffer(i1side, cur::jx3); } else { #pragma unroll for (const auto& comp : { cur::jx1, cur::jx2, cur::jx3 }) { @@ -81,11 +132,15 @@ namespace kernel { Inline void operator()(index_t i1, index_t i2) const { if constexpr (D == Dim::_2D) { if constexpr (C == Coord::Cart) { - if (is_conductor_i1min and i1 == i1_min) { + if ((is_conductor_i1min and i1 == i1_min) or + (is_conductor_i1max and i1 == i1_max - 1)) { + const auto i1side = is_conductor_i1min ? (i1 + 1) : (i1 - 1); array(i1, i2, cur::jx1) = (THREE * INV_4) * (FILTER2D_IN_I2(buffer, cur::jx1, i1, i2)) + - (INV_4) * (FILTER2D_IN_I2(buffer, cur::jx1, i1 + 1, i2)); - } else if (is_conductor_i1min and i1 == i1_min + 1) { + (INV_4) * (FILTER2D_IN_I2(buffer, cur::jx1, i1side, i2)); + } else if ((is_conductor_i1min and i1 == i1_min + 1) or + (is_conductor_i1max and i1 == i1_max - 2)) { + const auto i1side = is_conductor_i1min ? (i1 + 1) : (i1 - 1); array(i1, i2, cur::jx1) = INV_2 * (FILTER2D_IN_I2(buffer, cur::jx1, i1, i2)) + @@ -96,12 +151,37 @@ namespace kernel { i2, cur::jx2) = INV_2 * (FILTER2D_IN_I2(buffer, cur::jx2, i1, i2)) + INV_4 * - (FILTER2D_IN_I2(buffer, cur::jx2, i1 + 1, i2)); + (FILTER2D_IN_I2(buffer, cur::jx2, i1side, i2)); array(i1, i2, cur::jx3) = INV_2 * (FILTER2D_IN_I2(buffer, cur::jx3, i1, i2)) + INV_4 * - (FILTER2D_IN_I2(buffer, cur::jx3, i1 + 1, i2)); + (FILTER2D_IN_I2(buffer, cur::jx3, i1side, i2)); + } else if ((is_conductor_i2min and i2 == i2_min) or + (is_conductor_i2max and i2 == i2_max - 1)) { + const auto i2side = is_conductor_i2min ? (i2 + 1) : (i2 - 1); + array(i1, i2, cur::jx2) = + (THREE * INV_4) * (FILTER2D_IN_I1(buffer, cur::jx2, i1, i2)) + + (INV_4) * (FILTER2D_IN_I1(buffer, cur::jx2, i1, i2side)); + } else if ((is_conductor_i2min and i2 == i2_min + 1) or + (is_conductor_i2max and i2 == i2_max - 2)) { + const auto i2side = is_conductor_i2min ? (i2 + 1) : (i2 - 1); + array(i1, + i2, + cur::jx1) = INV_2 * (FILTER2D_IN_I1(buffer, cur::jx1, i1, i2)) + + INV_4 * + (FILTER2D_IN_I1(buffer, cur::jx1, i1, i2side)); + array(i1, + i2, + cur::jx2) = INV_2 * (FILTER2D_IN_I1(buffer, cur::jx2, i1, i2)) + + INV_4 * + ((FILTER2D_IN_I1(buffer, cur::jx2, i1, i2 - 1)) + + (FILTER2D_IN_I1(buffer, cur::jx2, i1, i2 + 1))); + array(i1, + i2, + cur::jx3) = INV_2 * (FILTER2D_IN_I1(buffer, cur::jx3, i1, i2)) + + INV_4 * + (FILTER2D_IN_I1(buffer, cur::jx3, i1, i2side)); } else { #pragma unroll for (const auto comp : { cur::jx1, cur::jx2, cur::jx3 }) { @@ -212,33 +292,93 @@ namespace kernel { Inline void operator()(index_t i1, index_t i2, index_t i3) const { if constexpr (D == Dim::_3D) { if constexpr (C == Coord::Cart) { + if ((is_conductor_i1min and i1 == i1_min) or + (is_conductor_i1max and i1 == i1_max - 1)) { + const auto i1side = is_conductor_i1min ? (i1 + 1) : (i1 - 1); + array(i1, i2, i3, cur::jx1) = + (THREE * INV_4) * (FILTER3D_IN_I2_I3(buffer, cur::jx1, i1, i2, i3)) + + (INV_4) * (FILTER3D_IN_I2_I3(buffer, cur::jx1, i1side, i2, i3)); + } else if ((is_conductor_i1min and i1 == i1_min + 1) or + (is_conductor_i1max and i1 == i1_max - 2)) { + const auto i1side = is_conductor_i1min ? (i1 + 1) : (i1 - 1); + array(i1, i2, i3, cur::jx1) = + INV_2 * (FILTER3D_IN_I2_I3(buffer, cur::jx1, i1, i2, i3)) + + INV_4 * ((FILTER3D_IN_I2_I3(buffer, cur::jx1, i1 - 1, i2, i3)) + + (FILTER3D_IN_I2_I3(buffer, cur::jx1, i1 + 1, i2, i3))); + array(i1, i2, i3, cur::jx2) = + INV_2 * (FILTER3D_IN_I2_I3(buffer, cur::jx2, i1, i2, i3)) + + INV_4 * (FILTER3D_IN_I2_I3(buffer, cur::jx2, i1side, i2, i3)); + array(i1, i2, i3, cur::jx3) = + INV_2 * (FILTER3D_IN_I2_I3(buffer, cur::jx3, i1, i2, i3)) + + INV_4 * (FILTER3D_IN_I2_I3(buffer, cur::jx3, i1side, i2, i3)); + } else if ((is_conductor_i2min and i2 == i2_min) or + (is_conductor_i2max and i2 == i2_max - 1)) { + const auto i2side = is_conductor_i2min ? (i2 + 1) : (i2 - 1); + array(i1, i2, i3, cur::jx2) = + (THREE * INV_4) * (FILTER3D_IN_I1_I3(buffer, cur::jx2, i1, i2, i3)) + + (INV_4) * (FILTER3D_IN_I1_I3(buffer, cur::jx2, i1, i2side, i3)); + } else if ((is_conductor_i2min and i2 == i2_min + 1) or + (is_conductor_i2max and i2 == i2_max - 2)) { + const auto i2side = is_conductor_i2min ? (i2 + 1) : (i2 - 1); + array(i1, i2, i3, cur::jx1) = + INV_2 * (FILTER3D_IN_I1_I3(buffer, cur::jx1, i1, i2, i3)) + + INV_4 * (FILTER3D_IN_I1_I3(buffer, cur::jx1, i1, i2side, i3)); + array(i1, i2, i3, cur::jx2) = + INV_2 * (FILTER3D_IN_I1_I3(buffer, cur::jx2, i1, i2, i3)) + + INV_4 * ((FILTER3D_IN_I1_I3(buffer, cur::jx2, i1, i2 - 1, i3)) + + (FILTER3D_IN_I1_I3(buffer, cur::jx2, i1, i2 + 1, i3))); + array(i1, i2, i3, cur::jx3) = + INV_2 * (FILTER3D_IN_I1_I3(buffer, cur::jx3, i1, i2, i3)) + + INV_4 * (FILTER3D_IN_I1_I3(buffer, cur::jx3, i1, i2side, i3)); + } else if ((is_conductor_i3min and i3 == i3_min) or + (is_conductor_i3max and i3 == i3_max - 1)) { + const auto i3side = is_conductor_i3min ? (i3 + 1) : (i3 - 1); + array(i1, i2, i3, cur::jx3) = + (THREE * INV_4) * (FILTER3D_IN_I1_I2(buffer, cur::jx3, i1, i2, i3)) + + (INV_4) * (FILTER3D_IN_I1_I2(buffer, cur::jx3, i1, i2, i3side)); + } else if ((is_conductor_i3min and i3 == i3_min + 1) or + (is_conductor_i3max and i3 == i3_max - 2)) { + const auto i3side = is_conductor_i3min ? (i3 + 1) : (i3 - 1); + array(i1, i2, i3, cur::jx1) = + INV_2 * (FILTER3D_IN_I1_I2(buffer, cur::jx1, i1, i2, i3)) + + INV_4 * (FILTER3D_IN_I1_I2(buffer, cur::jx1, i1, i2, i3side)); + array(i1, i2, i3, cur::jx2) = + INV_2 * (FILTER3D_IN_I1_I2(buffer, cur::jx2, i1, i2, i3)) + + INV_4 * (FILTER3D_IN_I1_I2(buffer, cur::jx2, i1, i2, i3side)); + array(i1, i2, i3, cur::jx3) = + INV_2 * (FILTER3D_IN_I1_I2(buffer, cur::jx3, i1, i2, i3)) + + INV_4 * ((FILTER3D_IN_I1_I2(buffer, cur::jx3, i1, i2, i3 - 1)) + + (FILTER3D_IN_I1_I2(buffer, cur::jx3, i1, i2, i3 + 1))); + } else { #pragma unroll - for (auto& comp : { cur::jx1, cur::jx2, cur::jx3 }) { - array(i1, i2, i3, comp) = - INV_8 * buffer(i1, i2, i3, comp) + - INV_16 * - (buffer(i1 - 1, i2, i3, comp) + buffer(i1 + 1, i2, i3, comp) + - buffer(i1, i2 - 1, i3, comp) + buffer(i1, i2 + 1, i3, comp) + - buffer(i1, i2, i3 - 1, comp) + buffer(i1, i2, i3 + 1, comp)) + - INV_32 * - (buffer(i1 - 1, i2 - 1, i3, comp) + - buffer(i1 + 1, i2 + 1, i3, comp) + - buffer(i1 - 1, i2 + 1, i3, comp) + - buffer(i1 + 1, i2 - 1, i3, comp) + - buffer(i1, i2 - 1, i3 - 1, comp) + - buffer(i1, i2 + 1, i3 + 1, comp) + buffer(i1, i2, i3 - 1, comp) + - buffer(i1, i2, i3 + 1, comp) + buffer(i1 - 1, i2, i3 - 1, comp) + - buffer(i1 + 1, i2, i3 + 1, comp) + - buffer(i1 - 1, i2, i3 + 1, comp) + - buffer(i1 + 1, i2, i3 - 1, comp)) + - INV_64 * (buffer(i1 - 1, i2 - 1, i3 - 1, comp) + - buffer(i1 + 1, i2 + 1, i3 + 1, comp) + - buffer(i1 - 1, i2 + 1, i3 + 1, comp) + - buffer(i1 + 1, i2 - 1, i3 - 1, comp) + - buffer(i1 - 1, i2 - 1, i3 + 1, comp) + - buffer(i1 + 1, i2 + 1, i3 - 1, comp) + - buffer(i1 - 1, i2 + 1, i3 - 1, comp) + - buffer(i1 + 1, i2 - 1, i3 + 1, comp)); + for (auto& comp : { cur::jx1, cur::jx2, cur::jx3 }) { + array(i1, i2, i3, comp) = + INV_8 * buffer(i1, i2, i3, comp) + + INV_16 * + (buffer(i1 - 1, i2, i3, comp) + buffer(i1 + 1, i2, i3, comp) + + buffer(i1, i2 - 1, i3, comp) + buffer(i1, i2 + 1, i3, comp) + + buffer(i1, i2, i3 - 1, comp) + buffer(i1, i2, i3 + 1, comp)) + + INV_32 * + (buffer(i1 - 1, i2 - 1, i3, comp) + + buffer(i1 + 1, i2 + 1, i3, comp) + + buffer(i1 - 1, i2 + 1, i3, comp) + + buffer(i1 + 1, i2 - 1, i3, comp) + + buffer(i1, i2 - 1, i3 - 1, comp) + + buffer(i1, i2 + 1, i3 + 1, comp) + + buffer(i1, i2, i3 - 1, comp) + buffer(i1, i2, i3 + 1, comp) + + buffer(i1 - 1, i2, i3 - 1, comp) + + buffer(i1 + 1, i2, i3 + 1, comp) + + buffer(i1 - 1, i2, i3 + 1, comp) + + buffer(i1 + 1, i2, i3 - 1, comp)) + + INV_64 * (buffer(i1 - 1, i2 - 1, i3 - 1, comp) + + buffer(i1 + 1, i2 + 1, i3 + 1, comp) + + buffer(i1 - 1, i2 + 1, i3 + 1, comp) + + buffer(i1 + 1, i2 - 1, i3 - 1, comp) + + buffer(i1 - 1, i2 - 1, i3 + 1, comp) + + buffer(i1 + 1, i2 + 1, i3 - 1, comp) + + buffer(i1 - 1, i2 + 1, i3 - 1, comp) + + buffer(i1 + 1, i2 - 1, i3 + 1, comp)); + } } } else { raise::KernelNotImplementedError(HERE); @@ -253,6 +393,11 @@ namespace kernel { } // namespace kernel +#undef FILTER3D_IN_I1_I3 +#undef FILTER3D_IN_I2_I3 +#undef FILTER3D_IN_I1_I2 + +#undef FILTER2D_IN_I2 #undef FILTER2D_IN_I1 #endif // DIGITAL_FILTER_HPP From 0303acf48d29e64faeb982b0106fc37f08db2d0c Mon Sep 17 00:00:00 2001 From: hayk Date: Fri, 4 Apr 2025 17:26:12 -0400 Subject: [PATCH 574/773] rebase to 1.2.0rc --- src/checkpoint/tests/checkpoint-nompi.cpp | 4 ++-- src/framework/containers/particles.cpp | 2 +- src/kernels/digital_filter.hpp | 5 +---- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/checkpoint/tests/checkpoint-nompi.cpp b/src/checkpoint/tests/checkpoint-nompi.cpp index 23dbd8871..be5e97e24 100644 --- a/src/checkpoint/tests/checkpoint-nompi.cpp +++ b/src/checkpoint/tests/checkpoint-nompi.cpp @@ -105,8 +105,8 @@ auto main(int argc, char* argv[]) -> int { writer.saveField("em", field1); writer.saveField("em0", field2); - writer.savePerDomainVariable("s1_npart", 1, 0, npart1); - writer.savePerDomainVariable("s2_npart", 1, 0, npart2); + writer.savePerDomainVariable("s1_npart", 1, 0, npart1); + writer.savePerDomainVariable("s2_npart", 1, 0, npart2); writer.saveParticleQuantity("s1_i1", npart1, 0, npart1, i1); writer.saveParticleQuantity("s1_ux1", npart1, 0, npart1, u1); diff --git a/src/framework/containers/particles.cpp b/src/framework/containers/particles.cpp index 634a34862..9ec8810dc 100644 --- a/src/framework/containers/particles.cpp +++ b/src/framework/containers/particles.cpp @@ -218,7 +218,7 @@ namespace ntt { Kokkos::Experimental::fill( "TagAliveParticles", - AccelExeSpace(), + Kokkos::DefaultExecutionSpace(), Kokkos::subview(this_tag, std::make_pair(static_cast(0), n_alive)), ParticleTag::alive); diff --git a/src/kernels/digital_filter.hpp b/src/kernels/digital_filter.hpp index 4f1385c16..5ac60327d 100644 --- a/src/kernels/digital_filter.hpp +++ b/src/kernels/digital_filter.hpp @@ -59,15 +59,12 @@ namespace kernel { class DigitalFilter_kernel { ndfield_t array; const ndfield_t buffer; - bool is_axis_i2min { false }, is_axis_i2max { false }; - static constexpr auto i2_min = N_GHOSTS; - const ncells_t i2_max; const bool is_axis_i2min, is_axis_i2max; const bool is_conductor_i1min, is_conductor_i1max; const bool is_conductor_i2min, is_conductor_i2max; const bool is_conductor_i3min, is_conductor_i3max; static constexpr auto i1_min = N_GHOSTS, i2_min = N_GHOSTS, i3_min = N_GHOSTS; - const std::size_t i1_max, i2_max, i3_max; + const ncells_t i1_max, i2_max, i3_max; // @TODO: Current implementation might have issues // ... at the corners between two conductors From dd8a35b9ccf419bccbfdbb0c6e7f7a7890364b96 Mon Sep 17 00:00:00 2001 From: hayk Date: Fri, 4 Apr 2025 17:35:17 -0400 Subject: [PATCH 575/773] (RUNTEST) From cb34e94bb928c2e7b8df3cb8d191d3628377eefc Mon Sep 17 00:00:00 2001 From: hayk Date: Fri, 4 Apr 2025 17:50:03 -0400 Subject: [PATCH 576/773] mpi tests fixed (RUNTEST) --- src/checkpoint/tests/checkpoint-mpi.cpp | 4 ++-- src/output/tests/writer-mpi.cpp | 24 ++++++++++++------------ 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/checkpoint/tests/checkpoint-mpi.cpp b/src/checkpoint/tests/checkpoint-mpi.cpp index f97202ab1..bc6d6038a 100644 --- a/src/checkpoint/tests/checkpoint-mpi.cpp +++ b/src/checkpoint/tests/checkpoint-mpi.cpp @@ -144,8 +144,8 @@ auto main(int argc, char* argv[]) -> int { writer.saveField("em", field1); writer.saveField("em0", field2); - writer.savePerDomainVariable("s1_npart", 1, 0, npart1); - writer.savePerDomainVariable("s2_npart", 1, 0, npart2); + writer.savePerDomainVariable("s1_npart", 1, 0, npart1); + writer.savePerDomainVariable("s2_npart", 1, 0, npart2); writer.saveParticleQuantity("s1_i1", npart1_globtot, diff --git a/src/output/tests/writer-mpi.cpp b/src/output/tests/writer-mpi.cpp index f6d3ee88a..cc9208889 100644 --- a/src/output/tests/writer-mpi.cpp +++ b/src/output/tests/writer-mpi.cpp @@ -61,8 +61,8 @@ auto main(int argc, char* argv[]) -> int { // write auto writer = out::Writer(); writer.init(&adios, "hdf5", "test", false); - writer.defineMeshLayout({ static_cast(mpi_size) * nx1 }, - { static_cast(mpi_rank) * nx1 }, + writer.defineMeshLayout({ static_cast(mpi_size) * nx1 }, + { static_cast(mpi_rank) * nx1 }, { nx1 }, { dwn1 }, false, @@ -89,9 +89,9 @@ auto main(int argc, char* argv[]) -> int { { // read adios2::IO io = adios.DeclareIO("read-test"); - io.SetEngine("hdf5"); - adios2::Engine reader = io.Open("test.h5", adios2::Mode::Read, MPI_COMM_SELF); - raise::ErrorIf(io.InquireAttribute("NGhosts").Data()[0] != 0, + io.SetEngine("HDF5"); + adios2::Engine reader = io.Open("test.h5", adios2::Mode::Read); + raise::ErrorIf(io.InquireAttribute("NGhosts").Data()[0] != 0, "NGhosts is not correct", HERE); raise::ErrorIf(io.InquireAttribute("Dimension").Data()[0] != 1, @@ -99,13 +99,13 @@ auto main(int argc, char* argv[]) -> int { HERE); for (std::size_t step = 0; reader.BeginStep() == adios2::StepStatus::OK; ++step) { - std::size_t step_read; - long double time_read; + timestep_t step_read; + simtime_t time_read; - reader.Get(io.InquireVariable("Step"), + reader.Get(io.InquireVariable("Step"), &step_read, adios2::Mode::Sync); - reader.Get(io.InquireVariable("Time"), + reader.Get(io.InquireVariable("Time"), &time_read, adios2::Mode::Sync); raise::ErrorIf(step_read != step, "Step is not correct", HERE); @@ -122,9 +122,9 @@ auto main(int argc, char* argv[]) -> int { const double l = l_offset; const double f = math::ceil(l / d) * d - l; - const auto first_cell = static_cast(f); - const auto l_size_dwn = static_cast(math::ceil((n - f) / d)); - const auto l_corner_dwn = static_cast(math::ceil(l / d)); + const auto first_cell = static_cast(f); + const auto l_size_dwn = static_cast(math::ceil((n - f) / d)); + const auto l_corner_dwn = static_cast(math::ceil(l / d)); array_t field_read {}; int cntr = 0; From 0bc510f7c03c3897ec29249f3c8486005e3af125 Mon Sep 17 00:00:00 2001 From: hayk Date: Fri, 4 Apr 2025 17:56:58 -0400 Subject: [PATCH 577/773] added non-mpi cpu test action (RUNTEST) --- .github/workflows/actions.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/actions.yml b/.github/workflows/actions.yml index f60ee9061..a5c546328 100644 --- a/.github/workflows/actions.yml +++ b/.github/workflows/actions.yml @@ -27,9 +27,14 @@ jobs: matrix: device: [cpu, amd-gpu, nvidia-gpu] precision: [double, single] + mpi: [serial, parallel] exclude: # my AMD GPU doesn't support fp64 atomics : ( - device: amd-gpu precision: double + - device: amd-gpu + mpi: parallel + - device: nvidia-gpu + mpi: parallel runs-on: [self-hosted, "${{ matrix.device }}"] steps: - name: Checkout @@ -47,7 +52,7 @@ jobs: fi elif [ "${{ matrix.device }}" = "amd-gpu" ]; then FLAGS="-D Kokkos_ENABLE_HIP=ON -D Kokkos_ARCH_AMD_GFX1100=ON" - elif [ "${{ matrix.device }}" = "cpu" ]; then + elif [ "${{ matrix.mpi }}" = "parallel" ]; then FLAGS="-D mpi=ON" fi cmake -B build -D TESTS=ON -D output=ON -D precision=${{ matrix.precision }} $FLAGS From 6643066318a7174c707bada0dd26c7073df559c3 Mon Sep 17 00:00:00 2001 From: hayk Date: Tue, 1 Apr 2025 18:56:07 -0400 Subject: [PATCH 578/773] exespace/memspace -> kokkos default + cmake flags changed --- CMakeLists.txt | 23 +++--- cmake/MPIConfig.cmake | 4 -- cmake/adios2Config.cmake | 2 - cmake/defaults.cmake | 36 ---------- cmake/dependencies.cmake | 11 ++- cmake/kokkosConfig.cmake | 10 --- legacy/src/pic/particles/particle_pusher.hpp | 73 ++++++++++---------- legacy/tests/kernels-gr.cpp | 17 ++--- legacy/tests/kernels-sr.cpp | 7 +- src/CMakeLists.txt | 1 - src/checkpoint/writer.cpp | 6 +- src/engines/CMakeLists.txt | 1 - src/framework/CMakeLists.txt | 1 - src/framework/tests/CMakeLists.txt | 1 - src/global/arch/kokkos_aliases.h | 4 +- src/kernels/tests/prtls_to_phys.cpp | 2 +- 16 files changed, 78 insertions(+), 121 deletions(-) delete mode 100644 cmake/MPIConfig.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index dd22b9308..0409c4107 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -79,11 +79,10 @@ set(BUILD_TESTING CACHE BOOL "Build tests") # ------------------------ Third-party dependencies ------------------------ # -include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/kokkosConfig.cmake) include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/dependencies.cmake) -find_or_fetch_dependency(Kokkos FALSE) -find_or_fetch_dependency(plog TRUE) +find_or_fetch_dependency(Kokkos FALSE QUIET) +find_or_fetch_dependency(plog TRUE QUIET) set(DEPENDENCIES Kokkos::kokkos) include_directories(${plog_SRC}/include) @@ -92,14 +91,15 @@ set_precision(${precision}) # MPI if(${mpi}) - include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/MPIConfig.cmake) + find_or_fetch_dependency(MPI FALSE REQUIRED) + include_directories(${MPI_CXX_INCLUDE_PATH}) + add_compile_options("-D MPI_ENABLED") set(DEPENDENCIES ${DEPENDENCIES} MPI::MPI_CXX) endif() # Output if(${output}) - include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/adios2Config.cmake) - find_or_fetch_dependency(adios2 FALSE) + find_or_fetch_dependency(adios2 FALSE QUIET) if(NOT DEFINED ENV{HDF5_ROOT}) if(DEFINED ENV{CONDA_PREFIX}) execute_process(COMMAND bash -c "conda list | grep \"hdf5\" -q" @@ -110,7 +110,7 @@ if(${output}) endif() endif() find_package(HDF5 REQUIRED) - + add_compile_options("-D OUTPUT_ENABLED") if(${mpi}) set(DEPENDENCIES ${DEPENDENCIES} adios2::cxx11_mpi) else() @@ -120,6 +120,13 @@ endif() link_libraries(${DEPENDENCIES}) +get_cmake_property(all_vars VARIABLES) +foreach(_var ${all_vars}) + if(_var MATCHES "^Kokkos_.*") + message(STATUS "PRINTING ${_var}=${${_var}}") + endif() +endforeach() + if(TESTS) # ---------------------------------- Tests --------------------------------- # include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/tests.cmake) @@ -129,7 +136,7 @@ elseif(BENCHMARK) else() # ----------------------------------- GUI ---------------------------------- # if(${gui}) - find_or_fetch_dependency(nttiny FALSE) + find_or_fetch_dependency(nttiny FALSE QUIET) endif() # ------------------------------- Main source ------------------------------ # diff --git a/cmake/MPIConfig.cmake b/cmake/MPIConfig.cmake deleted file mode 100644 index d1bfeaab2..000000000 --- a/cmake/MPIConfig.cmake +++ /dev/null @@ -1,4 +0,0 @@ -find_package(MPI REQUIRED) -include_directories(${MPI_CXX_INCLUDE_PATH}) -add_compile_options("-D MPI_ENABLED") - diff --git a/cmake/adios2Config.cmake b/cmake/adios2Config.cmake index 5c480f3d8..7e0951949 100644 --- a/cmake/adios2Config.cmake +++ b/cmake/adios2Config.cmake @@ -23,5 +23,3 @@ set(ADIOS2_USE_MPI set(ADIOS2_USE_CUDA OFF CACHE BOOL "Use CUDA for ADIOS2") - -add_compile_options("-D OUTPUT_ENABLED") diff --git a/cmake/defaults.cmake b/cmake/defaults.cmake index 46b4609c5..78e8230c7 100644 --- a/cmake/defaults.cmake +++ b/cmake/defaults.cmake @@ -51,42 +51,6 @@ endif() set_property(CACHE default_gui PROPERTY TYPE BOOL) -if(DEFINED ENV{Kokkos_ENABLE_CUDA}) - set(default_KOKKOS_ENABLE_CUDA - $ENV{Kokkos_ENABLE_CUDA} - CACHE INTERNAL "Default flag for CUDA") -else() - set(default_KOKKOS_ENABLE_CUDA - OFF - CACHE INTERNAL "Default flag for CUDA") -endif() - -set_property(CACHE default_KOKKOS_ENABLE_CUDA PROPERTY TYPE BOOL) - -if(DEFINED ENV{Kokkos_ENABLE_HIP}) - set(default_KOKKOS_ENABLE_HIP - $ENV{Kokkos_ENABLE_HIP} - CACHE INTERNAL "Default flag for HIP") -else() - set(default_KOKKOS_ENABLE_HIP - OFF - CACHE INTERNAL "Default flag for HIP") -endif() - -set_property(CACHE default_KOKKOS_ENABLE_HIP PROPERTY TYPE BOOL) - -if(DEFINED ENV{Kokkos_ENABLE_OPENMP}) - set(default_KOKKOS_ENABLE_OPENMP - $ENV{Kokkos_ENABLE_OPENMP} - CACHE INTERNAL "Default flag for OpenMP") -else() - set(default_KOKKOS_ENABLE_OPENMP - OFF - CACHE INTERNAL "Default flag for OpenMP") -endif() - -set_property(CACHE default_KOKKOS_ENABLE_OPENMP PROPERTY TYPE BOOL) - if(DEFINED ENV{Entity_ENABLE_MPI}) set(default_mpi $ENV{Entity_ENABLE_MPI} diff --git a/cmake/dependencies.cmake b/cmake/dependencies.cmake index 06a3e6a1f..a6712feb2 100644 --- a/cmake/dependencies.cmake +++ b/cmake/dependencies.cmake @@ -34,12 +34,17 @@ function(check_internet_connection) endif() endfunction() -function(find_or_fetch_dependency package_name header_only) +function(find_or_fetch_dependency package_name header_only mode) if(NOT header_only) - find_package(${package_name} QUIET) + find_package(${package_name} ${mode}) endif() if(NOT ${package_name}_FOUND) + if (${package_name} STREQUAL "Kokkos") + include(${CMAKE_CURRENT_SOURCE_DIR}/kokkosConfig.cmake) + elseif(${package_name} STREQUAL "adios2") + include(${CMAKE_CURRENT_SOURCE_DIR}/adios2Config.cmake) + endif() if(DEFINED ${package_name}_REPOSITORY AND NOT FETCHCONTENT_FULLY_DISCONNECTED) # fetching package @@ -52,7 +57,7 @@ function(find_or_fetch_dependency package_name header_only) FetchContent_Declare( ${package_name} GIT_REPOSITORY ${${package_name}_REPOSITORY} - GIT_TAG 4.3.00) + GIT_TAG 4.5.01) else() FetchContent_Declare(${package_name} GIT_REPOSITORY ${${package_name}_REPOSITORY}) diff --git a/cmake/kokkosConfig.cmake b/cmake/kokkosConfig.cmake index 8800f21a0..3d038cc19 100644 --- a/cmake/kokkosConfig.cmake +++ b/cmake/kokkosConfig.cmake @@ -27,16 +27,6 @@ else() CACHE BOOL "Kokkos debug bounds check") endif() -set(Kokkos_ENABLE_HIP - ${default_KOKKOS_ENABLE_HIP} - CACHE BOOL "Enable HIP") -set(Kokkos_ENABLE_CUDA - ${default_KOKKOS_ENABLE_CUDA} - CACHE BOOL "Enable CUDA") -set(Kokkos_ENABLE_OPENMP - ${default_KOKKOS_ENABLE_OPENMP} - CACHE BOOL "Enable OpenMP") - if(${BUILD_TESTING} STREQUAL "OFF") set(Kokkos_ENABLE_TESTS OFF diff --git a/legacy/src/pic/particles/particle_pusher.hpp b/legacy/src/pic/particles/particle_pusher.hpp index 4c0ec639a..7991a95a4 100644 --- a/legacy/src/pic/particles/particle_pusher.hpp +++ b/legacy/src/pic/particles/particle_pusher.hpp @@ -1,14 +1,13 @@ #ifndef PIC_PARTICLE_PUSHER_H #define PIC_PARTICLE_PUSHER_H -#include "wrapper.h" - -#include "pic.h" +#include "utils/qmath.h" #include "io/output.h" #include "meshblock/meshblock.h" #include "meshblock/particles.h" -#include "utils/qmath.h" +#include "pic.h" +#include "wrapper.h" #include METRIC_HEADER #include @@ -73,35 +72,34 @@ namespace ntt { real_t time, real_t coeff, real_t dt, - ProblemGenerator& pgen) : - EB { mblock.em }, - i1 { particles.i1 }, - i2 { particles.i2 }, - i3 { particles.i3 }, - i1_prev { particles.i1_prev }, - i2_prev { particles.i2_prev }, - i3_prev { particles.i3_prev }, - dx1 { particles.dx1 }, - dx2 { particles.dx2 }, - dx3 { particles.dx3 }, - dx1_prev { particles.dx1_prev }, - dx2_prev { particles.dx2_prev }, - dx3_prev { particles.dx3_prev }, - ux1 { particles.ux1 }, - ux2 { particles.ux2 }, - ux3 { particles.ux3 }, - phi { particles.phi }, - tag { particles.tag }, - metric { mblock.metric }, - time { time }, - coeff { coeff }, - dt { dt }, - ni1 { (int)mblock.Ni1() }, - ni2 { (int)mblock.Ni2() }, - ni3 { (int)mblock.Ni3() } + ProblemGenerator& pgen) + : EB { mblock.em } + , i1 { particles.i1 } + , i2 { particles.i2 } + , i3 { particles.i3 } + , i1_prev { particles.i1_prev } + , i2_prev { particles.i2_prev } + , i3_prev { particles.i3_prev } + , dx1 { particles.dx1 } + , dx2 { particles.dx2 } + , dx3 { particles.dx3 } + , dx1_prev { particles.dx1_prev } + , dx2_prev { particles.dx2_prev } + , dx3_prev { particles.dx3_prev } + , ux1 { particles.ux1 } + , ux2 { particles.ux2 } + , ux3 { particles.ux3 } + , phi { particles.phi } + , tag { particles.tag } + , metric { mblock.metric } + , time { time } + , coeff { coeff } + , dt { dt } + , ni1 { (int)mblock.Ni1() } + , ni2 { (int)mblock.Ni2() } + , ni3 { (int)mblock.Ni3() } #ifdef EXTERNAL_FORCE - , - pgen { pgen } + , pgen { pgen } #endif { (void)pgen; @@ -237,7 +235,7 @@ namespace ntt { const auto coeff = charge_ovr_mass * HALF * dt * params.B0(); Kokkos::parallel_for( "ParticlesPush", - Kokkos::RangePolicy(0, particles.npart()), + Kokkos::RangePolicy(0, particles.npart()), Pusher_kernel(mblock, particles, time, coeff, dt, pgen)); } @@ -638,9 +636,9 @@ namespace ntt { template template Inline void Pusher_kernel::get3VelCntrv(T, - index_t& p, + index_t& p, vec_t& xp, - vec_t& v) const { + vec_t& v) const { metric.v3_Cart2Cntrv(xp, { ux1(p), ux2(p), ux3(p) }, v); auto inv_energy { ONE / getEnergy(T {}, p) }; v[0] *= inv_energy; @@ -666,7 +664,8 @@ namespace ntt { } template <> - Inline void Pusher_kernel::getPrtlPos(index_t& p, coord_t& xp) const { + Inline void Pusher_kernel::getPrtlPos(index_t& p, + coord_t& xp) const { xp[0] = static_cast(i1(p)) + static_cast(dx1(p)); xp[1] = static_cast(i2(p)) + static_cast(dx2(p)); xp[2] = phi(p); @@ -1066,7 +1065,7 @@ namespace ntt { #else template Inline void Pusher_kernel::initForce(coord_t& xp, - vec_t& force_Cart) const { + vec_t& force_Cart) const { coord_t xp_Ph { ZERO }; coord_t xp_Code { ZERO }; for (short d { 0 }; d < static_cast(PrtlCoordD); ++d) { diff --git a/legacy/tests/kernels-gr.cpp b/legacy/tests/kernels-gr.cpp index 84a0c952b..6962f7c9f 100644 --- a/legacy/tests/kernels-gr.cpp +++ b/legacy/tests/kernels-gr.cpp @@ -1,16 +1,16 @@ -#include "wrapper.h" - #include #include #include -#include METRIC_HEADER +#include "wrapper.h" -#include "particle_macros.h" +#include METRIC_HEADER #include "kernels/particle_pusher_gr.hpp" +#include "particle_macros.h" + template void put_value(ntt::array_t& arr, T value, int i) { auto arr_h = Kokkos::create_mirror_view(arr); @@ -154,9 +154,10 @@ auto main(int argc, char* argv[]) -> int { static_cast(1.0e-5), 10, boundaries); - Kokkos::parallel_for("ParticlesPush", - Kokkos::RangePolicy(0, 1), - kernel); + Kokkos::parallel_for( + "ParticlesPush", + Kokkos::RangePolicy(0, 1), + kernel); auto [ra, tha] = get_physical_coord(0, i1, i2, dx1, dx2, metric); const real_t pha = get_value(phi, 0); @@ -207,4 +208,4 @@ auto main(int argc, char* argv[]) -> int { ntt::GlobalFinalize(); return 0; -} \ No newline at end of file +} diff --git a/legacy/tests/kernels-sr.cpp b/legacy/tests/kernels-sr.cpp index d765799e3..3f64122cd 100644 --- a/legacy/tests/kernels-sr.cpp +++ b/legacy/tests/kernels-sr.cpp @@ -181,9 +181,10 @@ auto main(int argc, char* argv[]) -> int { ZERO, ZERO, ZERO); - Kokkos::parallel_for("ParticlesPush", - Kokkos::RangePolicy(0, 1), - kernel); + Kokkos::parallel_for( + "ParticlesPush", + Kokkos::RangePolicy(0, 1), + kernel); auto [xa, ya] = get_cartesian_coord(0, i1, i2, dx1, dx2, phi, metric); if (!ntt::AlmostEqual(xa, diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a41b84900..db2ab4c92 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -17,7 +17,6 @@ # # * kokkos [required] # * plog [required] -# * toml11 [required] # * ADIOS2 [optional] # * mpi [optional] # ------------------------------ diff --git a/src/checkpoint/writer.cpp b/src/checkpoint/writer.cpp index a70d8de09..fe77d3b56 100644 --- a/src/checkpoint/writer.cpp +++ b/src/checkpoint/writer.cpp @@ -274,9 +274,9 @@ namespace checkpoint { std::size_t, double); template void Writer::savePerDomainVariable(const std::string&, - std::size_t, - std::size_t, - npart_t); + std::size_t, + std::size_t, + npart_t); template void Writer::saveField(const std::string&, const ndfield_t&); diff --git a/src/engines/CMakeLists.txt b/src/engines/CMakeLists.txt index 6da2f4efd..9e51330ec 100644 --- a/src/engines/CMakeLists.txt +++ b/src/engines/CMakeLists.txt @@ -25,7 +25,6 @@ # # * kokkos [required] # * plog [required] -# * toml11 [required] # * adios2 [optional] # * hdf5 [optional] # * mpi [optional] diff --git a/src/framework/CMakeLists.txt b/src/framework/CMakeLists.txt index 8802f696b..d3b68084c 100644 --- a/src/framework/CMakeLists.txt +++ b/src/framework/CMakeLists.txt @@ -28,7 +28,6 @@ # # * kokkos [required] # * plog [required] -# * toml11 [required] # * ADIOS2 [optional] # * mpi [optional] # ------------------------------ diff --git a/src/framework/tests/CMakeLists.txt b/src/framework/tests/CMakeLists.txt index ce188e9f1..27c456610 100644 --- a/src/framework/tests/CMakeLists.txt +++ b/src/framework/tests/CMakeLists.txt @@ -5,7 +5,6 @@ # # * kokkos [required] # * plog [required] -# * toml11 [required] # * mpi [optional] # * adios2 [optional] # diff --git a/src/global/arch/kokkos_aliases.h b/src/global/arch/kokkos_aliases.h index adb0b6451..712fc6eff 100644 --- a/src/global/arch/kokkos_aliases.h +++ b/src/global/arch/kokkos_aliases.h @@ -234,8 +234,8 @@ auto CreateParticleRangePolicy(npart_t, npart_t) -> range_t; * @returns Kokkos::RangePolicy or Kokkos::MDRangePolicy in the accelerator execution space. */ template -auto CreateRangePolicy(const tuple_t&, - const tuple_t&) -> range_t; +auto CreateRangePolicy(const tuple_t&, const tuple_t&) + -> range_t; /** * @brief Function template for generating ND Kokkos range policy on the host. diff --git a/src/kernels/tests/prtls_to_phys.cpp b/src/kernels/tests/prtls_to_phys.cpp index 0ceb88cd1..962c21b5c 100644 --- a/src/kernels/tests/prtls_to_phys.cpp +++ b/src/kernels/tests/prtls_to_phys.cpp @@ -132,7 +132,7 @@ void testPrtl2PhysSR(const std::vector& res, extent = { ext[0], - {ZERO, constant::PI} + { ZERO, constant::PI } }; const M metric { res, extent, params }; From 908c08aaa8bec4de1ebbb22d3764307a06683164 Mon Sep 17 00:00:00 2001 From: hayk Date: Wed, 2 Apr 2025 01:27:21 -0400 Subject: [PATCH 579/773] improved report + fetch adios2 + rm hdf5 dependency --- .gitmodules | 1 - CMakeLists.txt | 17 -- cmake/adios2Config.cmake | 10 +- cmake/config.cmake | 9 +- cmake/defaults.cmake | 2 +- cmake/dependencies.cmake | 31 ++- cmake/report.cmake | 366 +++++++++------------------------ cmake/styling.cmake | 140 +++++++++++-- src/engines/CMakeLists.txt | 2 +- src/engines/engine_printer.cpp | 9 - 10 files changed, 259 insertions(+), 328 deletions(-) diff --git a/.gitmodules b/.gitmodules index e06c332fe..577d08ea6 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,7 +4,6 @@ [submodule "extern/adios2"] path = extern/adios2 url = https://github.com/ornladios/ADIOS2.git - branch = master [submodule "extern/Kokkos"] path = extern/Kokkos url = https://github.com/kokkos/kokkos.git diff --git a/CMakeLists.txt b/CMakeLists.txt index 0409c4107..22d1e64b5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -100,16 +100,6 @@ endif() # Output if(${output}) find_or_fetch_dependency(adios2 FALSE QUIET) - if(NOT DEFINED ENV{HDF5_ROOT}) - if(DEFINED ENV{CONDA_PREFIX}) - execute_process(COMMAND bash -c "conda list | grep \"hdf5\" -q" - RESULT_VARIABLE HDF5_INSTALLED) - if(HDF5_INSTALLED EQUAL 0) - set(HDF5_ROOT $ENV{CONDA_PREFIX}) - endif() - endif() - endif() - find_package(HDF5 REQUIRED) add_compile_options("-D OUTPUT_ENABLED") if(${mpi}) set(DEPENDENCIES ${DEPENDENCIES} adios2::cxx11_mpi) @@ -120,13 +110,6 @@ endif() link_libraries(${DEPENDENCIES}) -get_cmake_property(all_vars VARIABLES) -foreach(_var ${all_vars}) - if(_var MATCHES "^Kokkos_.*") - message(STATUS "PRINTING ${_var}=${${_var}}") - endif() -endforeach() - if(TESTS) # ---------------------------------- Tests --------------------------------- # include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/tests.cmake) diff --git a/cmake/adios2Config.cmake b/cmake/adios2Config.cmake index 7e0951949..a4ce46179 100644 --- a/cmake/adios2Config.cmake +++ b/cmake/adios2Config.cmake @@ -12,14 +12,18 @@ set(ADIOS2_USE_Fortran CACHE BOOL "Use Fortran for ADIOS2") # Format/compression support -set(ADIOS2_USE_ZeroMQ - OFF - CACHE BOOL "Use ZeroMQ for ADIOS2") +set(ADIOS2_USE_HDF5 + ON + CACHE BOOL "Use HDF5 for ADIOS2") set(ADIOS2_USE_MPI ${mpi} CACHE BOOL "Use MPI for ADIOS2") +set(ADIOS2_USE_ZeroMQ + OFF + CACHE BOOL "Use ZeroMQ for ADIOS2") + set(ADIOS2_USE_CUDA OFF CACHE BOOL "Use CUDA for ADIOS2") diff --git a/cmake/config.cmake b/cmake/config.cmake index 58dd467e9..ab54717f1 100644 --- a/cmake/config.cmake +++ b/cmake/config.cmake @@ -34,13 +34,10 @@ function(set_problem_generator pgen_name) ) endif() set(PGEN - ${pgen_name} - PARENT_SCOPE) + ${pgen_name} PARENT_SCOPE) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/setups/${pgen_name}) set(PGEN_FOUND - TRUE - PARENT_SCOPE) + TRUE PARENT_SCOPE) set(problem_generators - ${PGEN_NAMES} - PARENT_SCOPE) + ${PGEN_NAMES} PARENT_SCOPE) endfunction() diff --git a/cmake/defaults.cmake b/cmake/defaults.cmake index 78e8230c7..2c72f5d7d 100644 --- a/cmake/defaults.cmake +++ b/cmake/defaults.cmake @@ -33,7 +33,7 @@ if(DEFINED ENV{Entity_ENABLE_OUTPUT}) CACHE INTERNAL "Default flag for output") else() set(default_output - OFF + ON CACHE INTERNAL "Default flag for output") endif() diff --git a/cmake/dependencies.cmake b/cmake/dependencies.cmake index a6712feb2..a31dfdea5 100644 --- a/cmake/dependencies.cmake +++ b/cmake/dependencies.cmake @@ -4,9 +4,10 @@ set(Kokkos_REPOSITORY set(plog_REPOSITORY https://github.com/SergiusTheBest/plog.git CACHE STRING "plog repository") +set (adios2_REPOSITORY + https://github.com/ornladios/ADIOS2.git + CACHE STRING "ADIOS2 repository") -# set (adios2_REPOSITORY https://github.com/ornladios/ADIOS2.git CACHE STRING -# "ADIOS2 repository") function(check_internet_connection) if(OFFLINE STREQUAL "ON") set(FETCHCONTENT_FULLY_DISCONNECTED @@ -41,9 +42,9 @@ function(find_or_fetch_dependency package_name header_only mode) if(NOT ${package_name}_FOUND) if (${package_name} STREQUAL "Kokkos") - include(${CMAKE_CURRENT_SOURCE_DIR}/kokkosConfig.cmake) + include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/kokkosConfig.cmake) elseif(${package_name} STREQUAL "adios2") - include(${CMAKE_CURRENT_SOURCE_DIR}/adios2Config.cmake) + include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/adios2Config.cmake) endif() if(DEFINED ${package_name}_REPOSITORY AND NOT FETCHCONTENT_FULLY_DISCONNECTED) @@ -70,6 +71,9 @@ function(find_or_fetch_dependency package_name header_only mode) set(${package_name}_SRC ${CMAKE_CURRENT_BINARY_DIR}/_deps/${lower_pckg_name}-src CACHE PATH "Path to ${package_name} src") + set(${package_name}_BUILD_DIR + ${CMAKE_CURRENT_BINARY_DIR}/_deps/${lower_pckg_name}-build + CACHE PATH "Path to ${package_name} build") set(${package_name}_FETCHED TRUE CACHE BOOL "Whether ${package_name} was fetched") @@ -96,7 +100,7 @@ function(find_or_fetch_dependency package_name header_only mode) endif() add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/extern/${package_name} - extern/${package_name}) + extern/${package_name}) set(${package_name}_SRC ${CMAKE_CURRENT_SOURCE_DIR}/extern/${package_name} CACHE PATH "Path to ${package_name} src") @@ -132,7 +136,24 @@ function(find_or_fetch_dependency package_name header_only mode) ${Kokkos_VERSION} CACHE INTERNAL "Kokkos version") endif() + if(NOT DEFINED Kokkos_ARCH OR Kokkos_ARCH STREQUAL "" + OR NOT DEFINED Kokkos_DEVICES OR Kokkos_DEVICES STREQUAL "") + if(${Kokkos_FOUND}) + include(${Kokkos_DIR}/KokkosConfigCommon.cmake) + elseif(NOT ${Kokkos_BUILD_DIR} STREQUAL "") + include(${Kokkos_BUILD_DIR}/KokkosConfigCommon.cmake) + else() + message(STATUS "${Red}Kokkos_DIR and Kokkos_BUILD_DIR not set.${ColorReset}") + endif() + endif() + set(Kokkos_ARCH + ${Kokkos_ARCH} PARENT_SCOPE) + set(Kokkos_DEVICES + ${Kokkos_DEVICES} PARENT_SCOPE) endif() + set(${package_name}_FOUND ${${package_name}_FOUND} PARENT_SCOPE) + set(${package_name}_FETCHED ${${package_name}_FETCHED} PARENT_SCOPE) + set(${package_name}_BUILD_DIR ${${package_name}_BUILD_DIR} PARENT_SCOPE) endfunction() check_internet_connection() diff --git a/cmake/report.cmake b/cmake/report.cmake index 13dde63f7..60d846144 100644 --- a/cmake/report.cmake +++ b/cmake/report.cmake @@ -1,95 +1,3 @@ -function(PadTo Text Padding Target Result) - set(rt ${Text}) - string(FIND ${rt} "${Magenta}" mg_fnd) - - if(mg_fnd GREATER -1) - string(REGEX REPLACE "${Esc}\\[35m" "" rt ${rt}) - endif() - - string(LENGTH "${rt}" TextLength) - math(EXPR PaddingNeeded "${Target} - ${TextLength}") - set(rt ${Text}) - - if(PaddingNeeded GREATER 0) - foreach(i RANGE 0 ${PaddingNeeded}) - set(rt "${rt}${Padding}") - endforeach() - else() - set(${rt} "${rt}") - endif() - - set(${Result} - "${rt}" - PARENT_SCOPE) -endfunction() - -function( - PrintChoices - Label - Flag - Choices - Value - Default - Color - OutputString - Multiline - Padding) - list(LENGTH "${Choices}" nchoices) - set(rstring "") - set(counter 0) - - foreach(ch ${Choices}) - if(${counter} EQUAL 0) - set(rstring_i "- ${Label}") - - if(NOT "${Flag}" STREQUAL "") - set(rstring_i "${rstring_i} [${Magenta}${Flag}${ColorReset}]") - endif() - - set(rstring_i "${rstring_i}:") - padto("${rstring_i}" " " ${Padding} rstring_i) - else() - set(rstring_i "") - - if(NOT ${counter} EQUAL ${nchoices}) - if(${Multiline} EQUAL 1) - set(rstring_i "${rstring_i}\n") - padto("${rstring_i}" " " ${Padding} rstring_i) - else() - set(rstring_i "${rstring_i}/") - endif() - endif() - endif() - - if(${ch} STREQUAL ${Value}) - if(${ch} STREQUAL "ON") - set(col ${Green}) - elseif(${ch} STREQUAL "OFF") - set(col ${Red}) - else() - set(col ${Color}) - endif() - else() - set(col ${Dim}) - endif() - - if(${ch} STREQUAL ${Default}) - set(col ${Underline}${col}) - endif() - - set(rstring_i "${rstring_i}${col}${ch}${ColorReset}") - math(EXPR counter "${counter} + 1") - set(rstring "${rstring}${rstring_i}") - set(rstring_i "") - endforeach() - - set(${OutputString} - "${rstring}" - PARENT_SCOPE) -endfunction() - -set(ON_OFF_VALUES "ON" "OFF") - if(${PGEN_FOUND}) printchoices( "Problem generator" @@ -99,8 +7,7 @@ if(${PGEN_FOUND}) ${default_pgen} "${Blue}" PGEN_REPORT - 1 - 36) + 0) endif() printchoices( @@ -111,7 +18,6 @@ printchoices( ${default_precision} "${Blue}" PRECISION_REPORT - 1 36) printchoices( "Output" @@ -121,17 +27,6 @@ printchoices( ${default_output} "${Green}" OUTPUT_REPORT - 0 - 36) -printchoices( - "GUI" - "gui" - "${ON_OFF_VALUES}" - ${gui} - ${default_gui} - "${Green}" - GUI_REPORT - 0 36) printchoices( "MPI" @@ -141,8 +36,7 @@ printchoices( OFF "${Green}" MPI_REPORT - 0 - 42) + 36) printchoices( "Debug mode" "DEBUG" @@ -151,131 +45,7 @@ printchoices( OFF "${Green}" DEBUG_REPORT - 0 - 42) - -printchoices( - "CUDA" - "Kokkos_ENABLE_CUDA" - "${ON_OFF_VALUES}" - ${Kokkos_ENABLE_CUDA} - "OFF" - "${Green}" - CUDA_REPORT - 0 - 42) -printchoices( - "HIP" - "Kokkos_ENABLE_HIP" - "${ON_OFF_VALUES}" - ${Kokkos_ENABLE_HIP} - "OFF" - "${Green}" - HIP_REPORT - 0 - 42) -printchoices( - "OpenMP" - "Kokkos_ENABLE_OPENMP" - "${ON_OFF_VALUES}" - ${Kokkos_ENABLE_OPENMP} - "OFF" - "${Green}" - OPENMP_REPORT - 0 - 42) - -printchoices( - "C++ compiler" - "CMAKE_CXX_COMPILER" - "${CMAKE_CXX_COMPILER} v${CMAKE_CXX_COMPILER_VERSION}" - "${CMAKE_CXX_COMPILER} v${CMAKE_CXX_COMPILER_VERSION}" - "N/A" - "${ColorReset}" - CXX_COMPILER_REPORT - 0 - 42) - -printchoices( - "C compiler" - "CMAKE_C_COMPILER" - "${CMAKE_C_COMPILER} v${CMAKE_C_COMPILER_VERSION}" - "${CMAKE_C_COMPILER} v${CMAKE_C_COMPILER_VERSION}" - "N/A" - "${ColorReset}" - C_COMPILER_REPORT - 0 - 42) - -get_cmake_property(_variableNames VARIABLES) -foreach(_variableName ${_variableNames}) - string(REGEX MATCH "Kokkos_ARCH_*" _isMatched ${_variableName}) - if(_isMatched) - get_property( - isSet - CACHE ${_variableName} - PROPERTY VALUE) - if(isSet STREQUAL "ON") - string(REGEX REPLACE "Kokkos_ARCH_" "" ARCH ${_variableName}) - break() - endif() - endif() -endforeach() -printchoices( - "Architecture" - "Kokkos_ARCH_*" - "${ARCH}" - "${ARCH}" - "N/A" - "${ColorReset}" - ARCH_REPORT - 0 - 42) - -if(${Kokkos_ENABLE_CUDA}) - if("${CMAKE_CUDA_COMPILER}" STREQUAL "") - execute_process(COMMAND which nvcc OUTPUT_VARIABLE CUDACOMP) - else() - set(CUDACOMP ${CMAKE_CUDA_COMPILER}) - endif() - - string(STRIP ${CUDACOMP} CUDACOMP) - - message(STATUS "CUDA compiler: ${CUDACOMP}") - execute_process( - COMMAND - bash -c - "${CUDACOMP} --version | grep release | sed -e 's/.*release //' -e 's/,.*//'" - OUTPUT_VARIABLE CUDACOMP_VERSION - OUTPUT_STRIP_TRAILING_WHITESPACE) - - printchoices( - "CUDA compiler" - "CMAKE_CUDA_COMPILER" - "${CUDACOMP}" - "${CUDACOMP}" - "N/A" - "${ColorReset}" - CUDA_COMPILER_REPORT - 0 - 42) -endif() - -if(${Kokkos_ENABLE_HIP}) - execute_process( - COMMAND bash -c "hipcc --version | grep HIP | cut -d ':' -f 2 | tr -d ' '" - OUTPUT_VARIABLE ROCM_VERSION - OUTPUT_STRIP_TRAILING_WHITESPACE) -endif() - -set(DOT_SYMBOL "${ColorReset}.") -set(DOTTED_LINE_SYMBOL - "${ColorReset}. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . " -) - -set(DASHED_LINE_SYMBOL - "${ColorReset}....................................................................... " -) + 36) if(NOT ${PROJECT_VERSION_TWEAK} EQUAL 0) set(VERSION_SYMBOL @@ -287,7 +57,7 @@ else() ) endif() -message( +set(REPORT_TEXT "${Blue} __ __ /\\ \\__ __/\\ \\__ __ ___\\ \\ _\\/\\_\\ \\ _\\ __ __ @@ -296,55 +66,107 @@ message( \\ \\____\\ \\_\\ \\_\\ \\__\\\\ \\_\\ \\__\\\\ \\____ \\/\\_\\ \\/____/\\/_/\\/_/\\/__/ \\/_/\\/__/ \\/___/ \\/_/ /\\___/ -Entity ${VERSION_SYMBOL}\t\t \\/__/") -message("${DASHED_LINE_SYMBOL} -Main configurations") +Entity ${VERSION_SYMBOL}\t\t \\/__/" +) +string(APPEND REPORT_TEXT + ${ColorReset} "\n" +) + +string(APPEND REPORT_TEXT + ${DASHED_LINE_SYMBOL} "\n" + "Configurations" "\n" +) if(${PGEN_FOUND}) - message(" ${PGEN_REPORT}") + string(APPEND REPORT_TEXT + " " ${PGEN_REPORT} "\n" + ) endif() -message(" ${PRECISION_REPORT}") -message(" ${OUTPUT_REPORT}") -message("${DASHED_LINE_SYMBOL}\nCompile configurations") +string(APPEND REPORT_TEXT + " " ${PRECISION_REPORT} "\n" + " " ${OUTPUT_REPORT} "\n" +) -if(NOT "${ARCH_REPORT}" STREQUAL "") - message(" ${ARCH_REPORT}") -endif() -message(" ${CUDA_REPORT}") -message(" ${HIP_REPORT}") -message(" ${OPENMP_REPORT}") +string(REPLACE ";" "+" Kokkos_ARCH "${Kokkos_ARCH}") +string(REPLACE ";" "+" Kokkos_DEVICES "${Kokkos_DEVICES}") -message(" ${C_COMPILER_REPORT}") +string(APPEND REPORT_TEXT + " - ARCH [${Magenta}Kokkos_ARCH_***${ColorReset}]: ${Kokkos_ARCH}" "\n" + " - DEVICES [${Magenta}Kokkos_ENABLE_***${ColorReset}]: ${Kokkos_DEVICES}" "\n" + " " ${MPI_REPORT} "\n" + " " ${DEBUG_REPORT} "\n" + ${DASHED_LINE_SYMBOL} "\n" + "Compilers & dependencies" "\n" +) -message(" ${CXX_COMPILER_REPORT}") +string(APPEND REPORT_TEXT + " - C compiler [${Magenta}CMAKE_C_COMPILER${ColorReset}]: v" ${CMAKE_C_COMPILER_VERSION} "\n" + " ${Dim}" ${CMAKE_C_COMPILER} "${ColorReset}\n" + " - C++ compiler [${Magenta}CMAKE_CXX_COMPILER${ColorReset}]: v" ${CMAKE_CXX_COMPILER_VERSION} "\n" + " ${Dim}" ${CMAKE_CXX_COMPILER} "${ColorReset}\n" +) -if(NOT "${CUDA_COMPILER_REPORT}" STREQUAL "") - message(" ${CUDA_COMPILER_REPORT}") +if(${Kokkos_DEVICES} MATCHES "CUDA") + if("${CMAKE_CUDA_COMPILER}" STREQUAL "") + execute_process(COMMAND which nvcc OUTPUT_VARIABLE CUDACOMP) + else() + set(CUDACOMP ${CMAKE_CUDA_COMPILER}) + endif() + string(STRIP ${CUDACOMP} CUDACOMP) + execute_process( + COMMAND + bash -c + "${CUDACOMP} --version | grep release | sed -e 's/.*release //' -e 's/,.*//'" + OUTPUT_VARIABLE CUDACOMP_VERSION + OUTPUT_STRIP_TRAILING_WHITESPACE) + string(APPEND REPORT_TEXT + " - CUDA compiler: v" ${CUDACOMP_VERSION} "\n" + " ${Dim}" ${CUDACOMP} "${ColorReset}\n" + ) +elseif(${Kokkos_DEVICES} MATCHES "HIP") + execute_process( + COMMAND bash -c "hipcc --version | grep HIP | cut -d ':' -f 2 | tr -d ' '" + OUTPUT_VARIABLE ROCM_VERSION + OUTPUT_STRIP_TRAILING_WHITESPACE) + string(APPEND REPORT_TEXT + " - ROCm: v" ${ROCM_VERSION} "\n" + ) endif() -message(" ${MPI_REPORT}") - -message(" ${DEBUG_REPORT}") - -message("${DASHED_LINE_SYMBOL}\nDependencies") - -if(NOT "${CUDACOMP_VERSION}" STREQUAL "") - message(" - CUDA:\tv${CUDACOMP_VERSION}") -elseif(NOT "${ROCM_VERSION}" STREQUAL "") - message(" - ROCm:\tv${ROCM_VERSION}") +string(APPEND REPORT_TEXT + " - Kokkos: v" ${Kokkos_VERSION} "\n" +) +if(${Kokkos_FOUND}) + string(APPEND REPORT_TEXT + " " ${Kokkos_DIR} "\n" + ) +else() + string(APPEND REPORT_TEXT + " " ${Kokkos_BUILD_DIR} "\n" + ) endif() -message(" - Kokkos:\tv${Kokkos_VERSION}") + if(${output}) - message(" - ADIOS2:\tv${adios2_VERSION}") -endif() -if(${HDF5_FOUND}) - message(" - HDF5:\tv${HDF5_VERSION}") + string(APPEND REPORT_TEXT + " - ADIOS2: v" ${adios2_VERSION} "\n" + ) + if(${adios2_FOUND}) + string(APPEND REPORT_TEXT + " " ${adios2_DIR} "\n" + ) + else() + string(APPEND REPORT_TEXT + " " ${adios2_BUILD_DIR} "\n" + ) + endif() endif() -message( - "${DASHED_LINE_SYMBOL} -Notes - ${Dim}: Set flags with `cmake ... -D ${Magenta}${ColorReset}${Dim}=`, the ${Underline}default${ColorReset}${Dim} value - : will be used unless the variable is explicitly set.${ColorReset} -") +string(APPEND REPORT_TEXT + ${DASHED_LINE_SYMBOL} "\n" + "Notes" "\n" + " ${Dim}: Set flags with `cmake ... -D ${Magenta}${ColorReset}${Dim}=`, the ${Underline}default${ColorReset}${Dim} value" "\n" + " : will be used unless the variable is explicitly set.${ColorReset}" "\n" +) + +message(${REPORT_TEXT}) diff --git a/cmake/styling.cmake b/cmake/styling.cmake index 70c448fff..0da4b3519 100644 --- a/cmake/styling.cmake +++ b/cmake/styling.cmake @@ -23,17 +23,131 @@ if(NOT WIN32) set(StrikeEnd "${Esc}[0m") endif() -# message("This is normal") message("${Red}This is Red${ColorReset}") -# message("${Green}This is Green${ColorReset}") message("${Yellow}This is -# Yellow${ColorReset}") message("${Blue}This is Blue${ColorReset}") -# message("${Magenta}This is Magenta${ColorReset}") message("${Cyan}This is -# Cyan${ColorReset}") message("${White}This is White${ColorReset}") -# message("${BoldRed}This is BoldRed${ColorReset}") message("${BoldGreen}This is -# BoldGreen${ColorReset}") message("${BoldYellow}This is -# BoldYellow${ColorReset}") message("${BoldBlue}This is BoldBlue${ColorReset}") -# message("${BoldMagenta}This is BoldMagenta${ColorReset}") -# message("${BoldCyan}This is BoldCyan${ColorReset}") message("${BoldWhite}This -# is BoldWhite\n\n${ColorReset}") - -# message() +set(DOTTED_LINE_SYMBOL + "${ColorReset}. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . " +) +set(DASHED_LINE_SYMBOL + "${ColorReset}....................................................................... " +) + +set(ON_OFF_VALUES "ON" "OFF") + +function(PureLength Text Result) + set(rt ${Text}) + string(FIND ${rt} "${Magenta}" mg_fnd) + + if(mg_fnd GREATER -1) + string(REGEX REPLACE "${Esc}\\[35m" "" rt ${rt}) + endif() + + string(LENGTH "${rt}" TextLength) + set(${Result} + "${TextLength}" + PARENT_SCOPE) +endfunction() + +function(PadTo Text Padding Target Result) + purelength("${Text}" TextLength) + math(EXPR PaddingNeeded "${Target} - ${TextLength}") + set(rt ${Text}) + + if(PaddingNeeded GREATER 0) + foreach(i RANGE 0 ${PaddingNeeded}) + set(rt "${rt}${Padding}") + endforeach() + else() + set(rt "${rt}") + endif() + + set(${Result} + "${rt}" + PARENT_SCOPE) +endfunction() + +function( + PrintChoices + Label + Flag + Choices + Value + Default + Color + OutputString + Padding) + set(rstring "- ${Label}") + + if(NOT "${Flag}" STREQUAL "") + string(APPEND rstring " [${Magenta}${Flag}${ColorReset}]") + endif() + + string(APPEND rstring ":") + + if(${Padding} EQUAL 0) + list(LENGTH "${Choices}" nchoices) + math(EXPR lastchoice "${nchoices} - 1") + set(ncols 4) + math(EXPR lastcol "${ncols} - 1") + + set(longest 0) + foreach(ch IN LISTS Choices) + string(LENGTH ${ch} clen) + if(clen GREATER longest) + set(longest ${clen}) + endif() + endforeach() + + set(counter 0) + foreach(ch IN LISTS Choices) + if(${ch} STREQUAL ${Value}) + set(col ${Color}) + else() + set(col ${Dim}) + endif() + + if(${ch} STREQUAL ${Default}) + set(col ${Underline}${col}) + endif() + + string(LENGTH "${ch}" clen) + math(EXPR PaddingNeeded "${longest} - ${clen} + 4") + + if(counter EQUAL ${lastcol} AND NOT ${counter} EQUAL ${lastchoice}) + string(APPEND rstring "${col}~ ${ch}${ColorReset}") + else() + if(counter EQUAL 0) + string(APPEND rstring "\n ") + endif() + string(APPEND rstring "${col}~ ${ch}${ColorReset}") + foreach(i RANGE 0 ${PaddingNeeded}) + string(APPEND rstring " ") + endforeach() + endif() + + math(EXPR counter "(${counter} + 1) % ${ncols}") + endforeach() + else() + padto("${rstring}" " " ${Padding} rstring) + + set(new_choices ${Choices}) + foreach(ch IN LISTS new_choices) + string(REPLACE ${ch} "${Dim}${ch}${ColorReset}" new_choices "${new_choices}") + endforeach() + set(Choices ${new_choices}) + if(${Value} STREQUAL "ON") + set(col ${Green}) + elseif(${Value} STREQUAL "OFF") + set(col ${Red}) + else() + set(col ${Color}) + endif() + string(REPLACE ${Value} "${col}${Value}${ColorReset}" Choices "${Choices}") + string(REPLACE ${Default} "${Underline}${Default}${ColorReset}" Choices "${Choices}") + string(REPLACE ";" "/" Choices "${Choices}") + string(APPEND rstring "${Choices}") + endif() + + set(${OutputString} + "${rstring}" + PARENT_SCOPE) +endfunction() diff --git a/src/engines/CMakeLists.txt b/src/engines/CMakeLists.txt index 9e51330ec..d5b6b0664 100644 --- a/src/engines/CMakeLists.txt +++ b/src/engines/CMakeLists.txt @@ -38,7 +38,7 @@ add_library(ntt_engines ${SOURCES}) set(libs ntt_global ntt_framework ntt_metrics ntt_archetypes ntt_kernels ntt_pgen) if(${output}) - list(APPEND libs ntt_output hdf5::hdf5) + list(APPEND libs ntt_output) endif() add_dependencies(ntt_engines ${libs}) target_link_libraries(ntt_engines PUBLIC ${libs}) diff --git a/src/engines/engine_printer.cpp b/src/engines/engine_printer.cpp index f94715d09..eb8ff402d 100644 --- a/src/engines/engine_printer.cpp +++ b/src/engines/engine_printer.cpp @@ -20,7 +20,6 @@ #endif #if defined(OUTPUT_ENABLED) - #include #include #endif @@ -188,18 +187,11 @@ namespace ntt { KOKKOS_VERSION % 100); #if defined(OUTPUT_ENABLED) - unsigned h5_major, h5_minor, h5_release; - H5get_libversion(&h5_major, &h5_minor, &h5_release); - const std::string hdf5_version = fmt::format("%d.%d.%d", - h5_major, - h5_minor, - h5_release); const std::string adios2_version = fmt::format("%d.%d.%d", ADIOS2_VERSION / 10000, ADIOS2_VERSION / 100 % 100, ADIOS2_VERSION % 100); #else // not OUTPUT_ENABLED - const std::string hdf5_version = "OFF"; const std::string adios2_version = "OFF"; #endif @@ -217,7 +209,6 @@ namespace ntt { add_param(report, 4, "CXX", "%s [%s]", ccx.c_str(), cpp_standard.c_str()); add_param(report, 4, "CUDA", "%s", cuda_version.c_str()); add_param(report, 4, "MPI", "%s", mpi_version.c_str()); - add_param(report, 4, "HDF5", "%s", hdf5_version.c_str()); add_param(report, 4, "Kokkos", "%s", kokkos_version.c_str()); add_param(report, 4, "ADIOS2", "%s", adios2_version.c_str()); add_param(report, 4, "Precision", "%s", precision); From 9e22301345e5bc865231b5d75c8d1114409c1067 Mon Sep 17 00:00:00 2001 From: haykh Date: Thu, 3 Apr 2025 20:33:03 -0400 Subject: [PATCH 580/773] cmake prints report with TESTS --- CMakeLists.txt | 3 +- cmake/report.cmake | 170 ++++++++++++++++++++++++++++---------------- cmake/styling.cmake | 31 +++++--- cmake/tests.cmake | 50 ++++++------- 4 files changed, 153 insertions(+), 101 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 22d1e64b5..4791ea55b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -125,5 +125,6 @@ else() # ------------------------------- Main source ------------------------------ # set_problem_generator(${pgen}) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/src src) - include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/report.cmake) endif() + +include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/report.cmake) diff --git a/cmake/report.cmake b/cmake/report.cmake index 60d846144..21064cdf9 100644 --- a/cmake/report.cmake +++ b/cmake/report.cmake @@ -8,6 +8,24 @@ if(${PGEN_FOUND}) "${Blue}" PGEN_REPORT 0) +elseif(${TESTS}) + set(TEST_NAMES "") + foreach(test_dir IN LISTS TEST_DIRECTORIES) + get_property( + LOCAL_TEST_NAMES + DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${test_dir}/tests + PROPERTY TESTS) + list(APPEND TEST_NAMES ${LOCAL_TEST_NAMES}) + endforeach() + printchoices( + "Test cases" + "" + "${TEST_NAMES}" + "" + "${ColorReset}" + "" + TESTS_REPORT + 0) endif() printchoices( @@ -58,7 +76,7 @@ else() endif() set(REPORT_TEXT - "${Blue} __ __ + "${Blue} __ __ /\\ \\__ __/\\ \\__ __ ___\\ \\ _\\/\\_\\ \\ _\\ __ __ / __ \\ / __ \\ \\ \\/\\/\\ \\ \\ \\/ /\\ \\/\\ \\ @@ -66,46 +84,63 @@ set(REPORT_TEXT \\ \\____\\ \\_\\ \\_\\ \\__\\\\ \\_\\ \\__\\\\ \\____ \\/\\_\\ \\/____/\\/_/\\/_/\\/__/ \\/_/\\/__/ \\/___/ \\/_/ /\\___/ -Entity ${VERSION_SYMBOL}\t\t \\/__/" -) -string(APPEND REPORT_TEXT - ${ColorReset} "\n" -) +Entity ${VERSION_SYMBOL}\t\t \\/__/") +string(APPEND REPORT_TEXT ${ColorReset} "\n") -string(APPEND REPORT_TEXT - ${DASHED_LINE_SYMBOL} "\n" - "Configurations" "\n" -) +string(APPEND REPORT_TEXT ${DASHED_LINE_SYMBOL} "\n" "Configurations" "\n") if(${PGEN_FOUND}) - string(APPEND REPORT_TEXT - " " ${PGEN_REPORT} "\n" - ) + string(APPEND REPORT_TEXT " " ${PGEN_REPORT} "\n") +elseif(${TESTS}) + string(APPEND REPORT_TEXT " " ${TESTS_REPORT} "\n") endif() -string(APPEND REPORT_TEXT - " " ${PRECISION_REPORT} "\n" - " " ${OUTPUT_REPORT} "\n" -) +string( + APPEND + REPORT_TEXT + " " + ${PRECISION_REPORT} + "\n" + " " + ${OUTPUT_REPORT} + "\n") string(REPLACE ";" "+" Kokkos_ARCH "${Kokkos_ARCH}") string(REPLACE ";" "+" Kokkos_DEVICES "${Kokkos_DEVICES}") -string(APPEND REPORT_TEXT - " - ARCH [${Magenta}Kokkos_ARCH_***${ColorReset}]: ${Kokkos_ARCH}" "\n" - " - DEVICES [${Magenta}Kokkos_ENABLE_***${ColorReset}]: ${Kokkos_DEVICES}" "\n" - " " ${MPI_REPORT} "\n" - " " ${DEBUG_REPORT} "\n" - ${DASHED_LINE_SYMBOL} "\n" - "Compilers & dependencies" "\n" -) - -string(APPEND REPORT_TEXT - " - C compiler [${Magenta}CMAKE_C_COMPILER${ColorReset}]: v" ${CMAKE_C_COMPILER_VERSION} "\n" - " ${Dim}" ${CMAKE_C_COMPILER} "${ColorReset}\n" - " - C++ compiler [${Magenta}CMAKE_CXX_COMPILER${ColorReset}]: v" ${CMAKE_CXX_COMPILER_VERSION} "\n" - " ${Dim}" ${CMAKE_CXX_COMPILER} "${ColorReset}\n" -) +string( + APPEND + REPORT_TEXT + " - ARCH [${Magenta}Kokkos_ARCH_***${ColorReset}]: ${Kokkos_ARCH}" + "\n" + " - DEVICES [${Magenta}Kokkos_ENABLE_***${ColorReset}]: ${Kokkos_DEVICES}" + "\n" + " " + ${MPI_REPORT} + "\n" + " " + ${DEBUG_REPORT} + "\n" + ${DASHED_LINE_SYMBOL} + "\n" + "Compilers & dependencies" + "\n") + +string( + APPEND + REPORT_TEXT + " - C compiler [${Magenta}CMAKE_C_COMPILER${ColorReset}]: v" + ${CMAKE_C_COMPILER_VERSION} + "\n" + " ${Dim}" + ${CMAKE_C_COMPILER} + "${ColorReset}\n" + " - C++ compiler [${Magenta}CMAKE_CXX_COMPILER${ColorReset}]: v" + ${CMAKE_CXX_COMPILER_VERSION} + "\n" + " ${Dim}" + ${CMAKE_CXX_COMPILER} + "${ColorReset}\n") if(${Kokkos_DEVICES} MATCHES "CUDA") if("${CMAKE_CUDA_COMPILER}" STREQUAL "") @@ -120,53 +155,62 @@ if(${Kokkos_DEVICES} MATCHES "CUDA") "${CUDACOMP} --version | grep release | sed -e 's/.*release //' -e 's/,.*//'" OUTPUT_VARIABLE CUDACOMP_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE) - string(APPEND REPORT_TEXT - " - CUDA compiler: v" ${CUDACOMP_VERSION} "\n" - " ${Dim}" ${CUDACOMP} "${ColorReset}\n" - ) + string( + APPEND + REPORT_TEXT + " - CUDA compiler: v" + ${CUDACOMP_VERSION} + "\n" + " ${Dim}" + ${CUDACOMP} + "${ColorReset}\n") elseif(${Kokkos_DEVICES} MATCHES "HIP") execute_process( COMMAND bash -c "hipcc --version | grep HIP | cut -d ':' -f 2 | tr -d ' '" OUTPUT_VARIABLE ROCM_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE) - string(APPEND REPORT_TEXT - " - ROCm: v" ${ROCM_VERSION} "\n" - ) + string(APPEND REPORT_TEXT " - ROCm: v" ${ROCM_VERSION} "\n") endif() -string(APPEND REPORT_TEXT - " - Kokkos: v" ${Kokkos_VERSION} "\n" -) +string(APPEND REPORT_TEXT " - Kokkos: v" ${Kokkos_VERSION} "\n") if(${Kokkos_FOUND}) - string(APPEND REPORT_TEXT - " " ${Kokkos_DIR} "\n" - ) + string(APPEND REPORT_TEXT " " ${Dim}${Kokkos_DIR}${ColorReset} "\n") else() - string(APPEND REPORT_TEXT - " " ${Kokkos_BUILD_DIR} "\n" - ) + string(APPEND REPORT_TEXT " " ${Dim}${Kokkos_BUILD_DIR}${ColorReset} "\n") endif() if(${output}) - string(APPEND REPORT_TEXT - " - ADIOS2: v" ${adios2_VERSION} "\n" - ) + string(APPEND REPORT_TEXT " - ADIOS2: v" ${adios2_VERSION} "\n") if(${adios2_FOUND}) - string(APPEND REPORT_TEXT - " " ${adios2_DIR} "\n" - ) + string(APPEND REPORT_TEXT " " "${Dim}${adios2_DIR}${ColorReset}" "\n") else() - string(APPEND REPORT_TEXT - " " ${adios2_BUILD_DIR} "\n" - ) + string(APPEND REPORT_TEXT " " "${Dim}${adios2_BUILD_DIR}${ColorReset}" + "\n") endif() endif() -string(APPEND REPORT_TEXT - ${DASHED_LINE_SYMBOL} "\n" - "Notes" "\n" - " ${Dim}: Set flags with `cmake ... -D ${Magenta}${ColorReset}${Dim}=`, the ${Underline}default${ColorReset}${Dim} value" "\n" - " : will be used unless the variable is explicitly set.${ColorReset}" "\n" -) +string( + APPEND + REPORT_TEXT + ${DASHED_LINE_SYMBOL} + "\n" + "Notes" + "\n" + " ${Dim}: Set flags with `cmake ... -D ${Magenta}${ColorReset}${Dim}=`, the ${Underline}default${ColorReset}${Dim} value" + "\n" + " : will be used unless the variable is explicitly set.${ColorReset}") + +if(${TESTS}) + string( + APPEND + REPORT_TEXT + "\n" + " ${Dim}: Run the tests with the following command:" + "\n" + " : ctest --test-dir ${CMAKE_CURRENT_BINARY_DIR}${ColorReset}" + "\n") +endif() + +string(APPEND REPORT_TEXT "\n") message(${REPORT_TEXT}) diff --git a/cmake/styling.cmake b/cmake/styling.cmake index 0da4b3519..b9b72abcb 100644 --- a/cmake/styling.cmake +++ b/cmake/styling.cmake @@ -43,8 +43,8 @@ function(PureLength Text Result) string(LENGTH "${rt}" TextLength) set(${Result} - "${TextLength}" - PARENT_SCOPE) + "${TextLength}" + PARENT_SCOPE) endfunction() function(PadTo Text Padding Target Result) @@ -99,14 +99,20 @@ function( set(counter 0) foreach(ch IN LISTS Choices) - if(${ch} STREQUAL ${Value}) - set(col ${Color}) + if(NOT ${Value} STREQUAL "") + if(${ch} STREQUAL ${Value}) + set(col ${Color}) + else() + set(col ${Dim}) + endif() else() set(col ${Dim}) endif() - if(${ch} STREQUAL ${Default}) - set(col ${Underline}${col}) + if(NOT ${Default} STREQUAL "") + if(${ch} STREQUAL ${Default}) + set(col ${Underline}${col}) + endif() endif() string(LENGTH "${ch}" clen) @@ -131,7 +137,8 @@ function( set(new_choices ${Choices}) foreach(ch IN LISTS new_choices) - string(REPLACE ${ch} "${Dim}${ch}${ColorReset}" new_choices "${new_choices}") + string(REPLACE ${ch} "${Dim}${ch}${ColorReset}" new_choices + "${new_choices}") endforeach() set(Choices ${new_choices}) if(${Value} STREQUAL "ON") @@ -141,8 +148,14 @@ function( else() set(col ${Color}) endif() - string(REPLACE ${Value} "${col}${Value}${ColorReset}" Choices "${Choices}") - string(REPLACE ${Default} "${Underline}${Default}${ColorReset}" Choices "${Choices}") + if(NOT "${Value}" STREQUAL "") + string(REPLACE ${Value} "${col}${Value}${ColorReset}" Choices + "${Choices}") + endif() + if(NOT "${Default}" STREQUAL "") + string(REPLACE ${Default} "${Underline}${Default}${ColorReset}" Choices + "${Choices}") + endif() string(REPLACE ";" "/" Choices "${Choices}") string(APPEND rstring "${Choices}") endif() diff --git a/cmake/tests.cmake b/cmake/tests.cmake index ca8ee69c4..e2d92a343 100644 --- a/cmake/tests.cmake +++ b/cmake/tests.cmake @@ -13,32 +13,26 @@ if(${output}) add_subdirectory(${SRC_DIR}/checkpoint ${CMAKE_CURRENT_BINARY_DIR}/checkpoint) endif() -if(${mpi}) - # tests with mpi - if(${output}) - add_subdirectory(${SRC_DIR}/output/tests - ${CMAKE_CURRENT_BINARY_DIR}/output/tests) - add_subdirectory(${SRC_DIR}/checkpoint/tests - ${CMAKE_CURRENT_BINARY_DIR}/checkpoint/tests) - add_subdirectory(${SRC_DIR}/framework/tests - ${CMAKE_CURRENT_BINARY_DIR}/framework/tests) - endif() -else() - # tests without mpi - add_subdirectory(${SRC_DIR}/global/tests - ${CMAKE_CURRENT_BINARY_DIR}/global/tests) - add_subdirectory(${SRC_DIR}/metrics/tests - ${CMAKE_CURRENT_BINARY_DIR}/metrics/tests) - add_subdirectory(${SRC_DIR}/kernels/tests - ${CMAKE_CURRENT_BINARY_DIR}/kernels/tests) - add_subdirectory(${SRC_DIR}/archetypes/tests - ${CMAKE_CURRENT_BINARY_DIR}/archetypes/tests) - add_subdirectory(${SRC_DIR}/framework/tests - ${CMAKE_CURRENT_BINARY_DIR}/framework/tests) - if(${output}) - add_subdirectory(${SRC_DIR}/output/tests - ${CMAKE_CURRENT_BINARY_DIR}/output/tests) - add_subdirectory(${SRC_DIR}/checkpoint/tests - ${CMAKE_CURRENT_BINARY_DIR}/checkpoint/tests) - endif() +set(TEST_DIRECTORIES + "" + PARENT_SCOPE) + +if(NOT ${mpi}) + list(APPEND TEST_DIRECTORIES global) + list(APPEND TEST_DIRECTORIES metrics) + list(APPEND TEST_DIRECTORIES kernels) + list(APPEND TEST_DIRECTORIES archetypes) + list(APPEND TEST_DIRECTORIES framework) +elseif(${mpi} AND ${output}) + list(APPEND TEST_DIRECTORIES framework) endif() + +if(${output}) + list(APPEND TEST_DIRECTORIES output) + list(APPEND TEST_DIRECTORIES checkpoint) +endif() + +foreach(test_dir IN LISTS TEST_DIRECTORIES) + add_subdirectory(${SRC_DIR}/${test_dir}/tests + ${CMAKE_CURRENT_BINARY_DIR}/${test_dir}/tests) +endforeach() From 004c6e953dee1286c9d363924b02f9245916eda7 Mon Sep 17 00:00:00 2001 From: haykh Date: Thu, 3 Apr 2025 20:33:26 -0400 Subject: [PATCH 581/773] type+unused warnings fixed --- src/framework/containers/particles.cpp | 7 +++---- src/kernels/fields_bcs.hpp | 28 +++++++++++++++++++------- src/metrics/tests/ks-qks.cpp | 1 + src/output/tests/writer-nompi.cpp | 3 ++- 4 files changed, 27 insertions(+), 12 deletions(-) diff --git a/src/framework/containers/particles.cpp b/src/framework/containers/particles.cpp index 9ec8810dc..2f59a004d 100644 --- a/src/framework/containers/particles.cpp +++ b/src/framework/containers/particles.cpp @@ -84,7 +84,7 @@ namespace ntt { rangeActiveParticles(), Lambda(index_t p) { auto npptag_acc = npptag_scat.access(); - if (this_tag(p) < 0 || this_tag(p) >= num_tags) { + if (this_tag(p) < 0 || this_tag(p) >= static_cast(num_tags)) { raise::KernelError(HERE, "Invalid tag value"); } npptag_acc(this_tag(p)) += 1; @@ -144,9 +144,8 @@ namespace ntt { template void Particles::RemoveDead() { - const auto n_part = npart(); - npart_t n_alive = 0, n_dead = 0; - auto& this_tag = tag; + npart_t n_alive = 0, n_dead = 0; + auto& this_tag = tag; Kokkos::parallel_reduce( "CountDeadAlive", diff --git a/src/kernels/fields_bcs.hpp b/src/kernels/fields_bcs.hpp index 970ab559e..782200e29 100644 --- a/src/kernels/fields_bcs.hpp +++ b/src/kernels/fields_bcs.hpp @@ -858,6 +858,7 @@ namespace kernel::bc { const I fset; const M metric; const ncells_t i_edge; + const BCTags tags; EnforcedBoundaries_kernel(ndfield_t& Fld, const I& fset, @@ -867,7 +868,8 @@ namespace kernel::bc { : Fld { Fld } , fset { fset } , metric { metric } - , i_edge { i_edge + N_GHOSTS } {} + , i_edge { i_edge + N_GHOSTS } + , tags { tags } {} Inline void operator()(index_t i1) const { if constexpr (D == Dim::_1D) { @@ -876,8 +878,12 @@ namespace kernel::bc { coord_t x_Ph_H { ZERO }; metric.template convert({ i1_ }, x_Ph_0); metric.template convert({ i1_ + HALF }, x_Ph_H); - bool setEx1 = defines_ex1, setEx2 = defines_ex2, setEx3 = defines_ex3, - setBx1 = defines_bx1, setBx2 = defines_bx2, setBx3 = defines_bx3; + bool setEx1 = defines_ex1 and (tags & BC::E), + setEx2 = defines_ex2 and (tags & BC::E), + setEx3 = defines_ex3 and (tags & BC::E), + setBx1 = defines_bx1 and (tags & BC::B), + setBx2 = defines_bx2 and (tags & BC::B), + setBx3 = defines_bx3 and (tags & BC::B); if constexpr (O == in::x1) { // x1 -- normal // x2,x3 -- tangential @@ -953,8 +959,12 @@ namespace kernel::bc { metric.template convert({ i1_ + HALF, i2_ }, x_Ph_H0); metric.template convert({ i1_ + HALF, i2_ + HALF }, x_Ph_HH); - bool setEx1 = defines_ex1, setEx2 = defines_ex2, setEx3 = defines_ex3, - setBx1 = defines_bx1, setBx2 = defines_bx2, setBx3 = defines_bx3; + bool setEx1 = defines_ex1 and (tags & BC::E), + setEx2 = defines_ex2 and (tags & BC::E), + setEx3 = defines_ex3 and (tags & BC::E), + setBx1 = defines_bx1 and (tags & BC::B), + setBx2 = defines_bx2 and (tags & BC::B), + setBx3 = defines_bx3 and (tags & BC::B); if constexpr (O == in::x1) { // x1 -- normal // x2,x3 -- tangential @@ -1053,8 +1063,12 @@ namespace kernel::bc { x_Ph_H0H); metric.template convert({ i1_, i2_ + HALF, i3_ + HALF }, x_Ph_0HH); - bool setEx1 = defines_ex1, setEx2 = defines_ex2, setEx3 = defines_ex3, - setBx1 = defines_bx1, setBx2 = defines_bx2, setBx3 = defines_bx3; + bool setEx1 = defines_ex1 and (tags & BC::E), + setEx2 = defines_ex2 and (tags & BC::E), + setEx3 = defines_ex3 and (tags & BC::E), + setBx1 = defines_bx1 and (tags & BC::B), + setBx2 = defines_bx2 and (tags & BC::B), + setBx3 = defines_bx3 and (tags & BC::B); if constexpr (O == in::x1) { // x1 -- normal // x2,x3 -- tangential diff --git a/src/metrics/tests/ks-qks.cpp b/src/metrics/tests/ks-qks.cpp index bed051e16..167f564ee 100644 --- a/src/metrics/tests/ks-qks.cpp +++ b/src/metrics/tests/ks-qks.cpp @@ -27,6 +27,7 @@ Inline auto equal(const vec_t& a, const auto eps = epsilon * acc; for (unsigned short d = 0; d < D; ++d) { if (not cmp::AlmostEqual(a[d], b[d], eps)) { + printf("%s: %.12e : %.12e\n", msg, a[d], b[d]); return false; } } diff --git a/src/output/tests/writer-nompi.cpp b/src/output/tests/writer-nompi.cpp index b063539ca..593f37f92 100644 --- a/src/output/tests/writer-nompi.cpp +++ b/src/output/tests/writer-nompi.cpp @@ -23,7 +23,8 @@ void cleanup() { } #define CEILDIV(a, b) \ - (static_cast(math::ceil(static_cast(a) / static_cast(b)))) + (static_cast( \ + math::ceil(static_cast(a) / static_cast(b)))) auto main(int argc, char* argv[]) -> int { Kokkos::initialize(argc, argv); From b539a91fb5b53766d3a3e620b509802c8fc1d9bb Mon Sep 17 00:00:00 2001 From: hayk Date: Fri, 4 Apr 2025 02:43:00 -0400 Subject: [PATCH 582/773] warnings in cmake + nullptr --- CMakeLists.txt | 13 ++++----- cmake/benchmark.cmake | 2 ++ cmake/config.cmake | 17 +++++++----- cmake/defaults.cmake | 2 ++ cmake/dependencies.cmake | 41 ++++++++++++++++++----------- cmake/kokkosConfig.cmake | 2 ++ cmake/report.cmake | 26 ++++++++++-------- cmake/styling.cmake | 12 ++++----- cmake/tests.cmake | 4 +-- src/CMakeLists.txt | 1 + src/archetypes/CMakeLists.txt | 2 +- src/archetypes/tests/CMakeLists.txt | 1 + src/checkpoint/CMakeLists.txt | 1 + src/checkpoint/tests/CMakeLists.txt | 1 + src/engines/CMakeLists.txt | 1 + src/framework/CMakeLists.txt | 1 + src/framework/parameters.cpp | 10 +++---- src/framework/tests/CMakeLists.txt | 1 + src/global/CMakeLists.txt | 1 + src/global/tests/CMakeLists.txt | 1 + src/kernels/CMakeLists.txt | 2 +- src/kernels/tests/CMakeLists.txt | 1 + src/metrics/CMakeLists.txt | 2 +- src/metrics/tests/CMakeLists.txt | 2 +- src/output/CMakeLists.txt | 1 + src/output/tests/CMakeLists.txt | 1 + 26 files changed, 92 insertions(+), 57 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4791ea55b..f83e6637c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,3 +1,5 @@ +# cmake-lint: disable=C0103,C0111,E1120,R0913,R0915 + cmake_minimum_required(VERSION 3.16) cmake_policy(SET CMP0110 NEW) @@ -8,10 +10,10 @@ project( VERSION 1.2.0 LANGUAGES CXX C) add_compile_options("-D ENTITY_VERSION=\"${PROJECT_VERSION}\"") +set(hash_cmd "git diff --quiet src/ && echo $(git rev-parse HEAD) ") +string(APPEND hash_cmd "|| echo $(git rev-parse HEAD)-mod") execute_process( - COMMAND - bash -c - "git diff --quiet src/ && echo $(git rev-parse HEAD) || echo $(git rev-parse HEAD)-mod" + COMMAND bash -c ${hash_cmd} WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" OUTPUT_VARIABLE GIT_HASH ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) @@ -55,9 +57,8 @@ if(${DEBUG} STREQUAL "OFF") set(CMAKE_BUILD_TYPE Release CACHE STRING "CMake build type") - set(CMAKE_CXX_FLAGS - "${CMAKE_CXX_FLAGS} -DNDEBUG -Wno-unused-local-typedefs -Wno-unknown-cuda-version" - ) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DNDEBUG " + "-Wno-unused-local-typedefs -Wno-unknown-cuda-version") else() set(CMAKE_BUILD_TYPE Debug diff --git a/cmake/benchmark.cmake b/cmake/benchmark.cmake index d2e8ca47c..39b075716 100644 --- a/cmake/benchmark.cmake +++ b/cmake/benchmark.cmake @@ -1,3 +1,5 @@ +# cmake-lint: disable=C0103 + set(SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src) add_subdirectory(${SRC_DIR}/global ${CMAKE_CURRENT_BINARY_DIR}/global) diff --git a/cmake/config.cmake b/cmake/config.cmake index ab54717f1..7214812cd 100644 --- a/cmake/config.cmake +++ b/cmake/config.cmake @@ -1,3 +1,5 @@ +# cmake-lint: disable=C0103 + # -------------------------------- Precision ------------------------------- # function(set_precision precision_name) list(FIND precisions ${precision_name} PRECISION_FOUND) @@ -28,16 +30,17 @@ function(set_problem_generator pgen_name) endforeach() list(FIND PGEN_NAMES ${pgen_name} PGEN_FOUND) if(NOT ${pgen_name} STREQUAL "." AND ${PGEN_FOUND} EQUAL -1) - message( - FATAL_ERROR - "Invalid problem generator: ${pgen_name}\nValid options are: ${PGEN_NAMES}" - ) + message(FATAL_ERROR "Invalid problem generator: " + "${pgen_name}\nValid options are: ${PGEN_NAMES}") endif() set(PGEN - ${pgen_name} PARENT_SCOPE) + ${pgen_name} + PARENT_SCOPE) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/setups/${pgen_name}) set(PGEN_FOUND - TRUE PARENT_SCOPE) + TRUE + PARENT_SCOPE) set(problem_generators - ${PGEN_NAMES} PARENT_SCOPE) + ${PGEN_NAMES} + PARENT_SCOPE) endfunction() diff --git a/cmake/defaults.cmake b/cmake/defaults.cmake index 2c72f5d7d..30e605a5c 100644 --- a/cmake/defaults.cmake +++ b/cmake/defaults.cmake @@ -1,3 +1,5 @@ +# cmake-lint: disable=C0103 + # ----------------------------- Defaults ---------------------------------- # if(DEFINED ENV{Entity_ENABLE_DEBUG}) set(default_debug diff --git a/cmake/dependencies.cmake b/cmake/dependencies.cmake index a31dfdea5..a21ea00e8 100644 --- a/cmake/dependencies.cmake +++ b/cmake/dependencies.cmake @@ -1,10 +1,12 @@ +# cmake-lint: disable=C0103,C0111,R0915,R0912 + set(Kokkos_REPOSITORY https://github.com/kokkos/kokkos.git CACHE STRING "Kokkos repository") set(plog_REPOSITORY https://github.com/SergiusTheBest/plog.git CACHE STRING "plog repository") -set (adios2_REPOSITORY +set(adios2_REPOSITORY https://github.com/ornladios/ADIOS2.git CACHE STRING "ADIOS2 repository") @@ -41,7 +43,7 @@ function(find_or_fetch_dependency package_name header_only mode) endif() if(NOT ${package_name}_FOUND) - if (${package_name} STREQUAL "Kokkos") + if(${package_name} STREQUAL "Kokkos") include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/kokkosConfig.cmake) elseif(${package_name} STREQUAL "adios2") include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/adios2Config.cmake) @@ -49,10 +51,8 @@ function(find_or_fetch_dependency package_name header_only mode) if(DEFINED ${package_name}_REPOSITORY AND NOT FETCHCONTENT_FULLY_DISCONNECTED) # fetching package - message( - STATUS - "${Blue}${package_name} not found. Fetching from ${${package_name}_REPOSITORY}${ColorReset}" - ) + message(STATUS "${Blue}${package_name} not found. " + "Fetching from ${${package_name}_REPOSITORY}${ColorReset}") include(FetchContent) if(${package_name} STREQUAL "Kokkos") FetchContent_Declare( @@ -100,7 +100,7 @@ function(find_or_fetch_dependency package_name header_only mode) endif() add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/extern/${package_name} - extern/${package_name}) + extern/${package_name}) set(${package_name}_SRC ${CMAKE_CURRENT_SOURCE_DIR}/extern/${package_name} CACHE PATH "Path to ${package_name} src") @@ -136,24 +136,35 @@ function(find_or_fetch_dependency package_name header_only mode) ${Kokkos_VERSION} CACHE INTERNAL "Kokkos version") endif() - if(NOT DEFINED Kokkos_ARCH OR Kokkos_ARCH STREQUAL "" - OR NOT DEFINED Kokkos_DEVICES OR Kokkos_DEVICES STREQUAL "") + if(NOT DEFINED Kokkos_ARCH + OR Kokkos_ARCH STREQUAL "" + OR NOT DEFINED Kokkos_DEVICES + OR Kokkos_DEVICES STREQUAL "") if(${Kokkos_FOUND}) include(${Kokkos_DIR}/KokkosConfigCommon.cmake) elseif(NOT ${Kokkos_BUILD_DIR} STREQUAL "") include(${Kokkos_BUILD_DIR}/KokkosConfigCommon.cmake) else() - message(STATUS "${Red}Kokkos_DIR and Kokkos_BUILD_DIR not set.${ColorReset}") + message( + STATUS "${Red}Kokkos_DIR and Kokkos_BUILD_DIR not set.${ColorReset}") endif() endif() set(Kokkos_ARCH - ${Kokkos_ARCH} PARENT_SCOPE) + ${Kokkos_ARCH} + PARENT_SCOPE) set(Kokkos_DEVICES - ${Kokkos_DEVICES} PARENT_SCOPE) + ${Kokkos_DEVICES} + PARENT_SCOPE) endif() - set(${package_name}_FOUND ${${package_name}_FOUND} PARENT_SCOPE) - set(${package_name}_FETCHED ${${package_name}_FETCHED} PARENT_SCOPE) - set(${package_name}_BUILD_DIR ${${package_name}_BUILD_DIR} PARENT_SCOPE) + set(${package_name}_FOUND + ${${package_name}_FOUND} + PARENT_SCOPE) + set(${package_name}_FETCHED + ${${package_name}_FETCHED} + PARENT_SCOPE) + set(${package_name}_BUILD_DIR + ${${package_name}_BUILD_DIR} + PARENT_SCOPE) endfunction() check_internet_connection() diff --git a/cmake/kokkosConfig.cmake b/cmake/kokkosConfig.cmake index 3d038cc19..f1a1cf207 100644 --- a/cmake/kokkosConfig.cmake +++ b/cmake/kokkosConfig.cmake @@ -1,3 +1,5 @@ +# cmake-lint: disable=C0103 + # ----------------------------- Kokkos settings ---------------------------- # if(${DEBUG} STREQUAL "OFF") set(Kokkos_ENABLE_AGGRESSIVE_VECTORIZATION diff --git a/cmake/report.cmake b/cmake/report.cmake index 21064cdf9..5a38b0dd5 100644 --- a/cmake/report.cmake +++ b/cmake/report.cmake @@ -66,13 +66,13 @@ printchoices( 36) if(NOT ${PROJECT_VERSION_TWEAK} EQUAL 0) - set(VERSION_SYMBOL - "v${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}-rc${PROJECT_VERSION_TWEAK}" - ) + set(VERSION_SYMBOL "v${PROJECT_VERSION_MAJOR}." "${PROJECT_VERSION_MINOR}.") + string(APPEND VERSION_SYMBOL + "${PROJECT_VERSION_PATCH}-rc${PROJECT_VERSION_TWEAK}") else() - set(VERSION_SYMBOL - "v${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH} " - ) + set(VERSION_SYMBOL "v${PROJECT_VERSION_MAJOR}.") + string(APPEND VERSION_SYMBOL + "${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH} ") endif() set(REPORT_TEXT @@ -149,12 +149,13 @@ if(${Kokkos_DEVICES} MATCHES "CUDA") set(CUDACOMP ${CMAKE_CUDA_COMPILER}) endif() string(STRIP ${CUDACOMP} CUDACOMP) + set(cmd "${CUDACOMP} --version |") + string(APPEND cmd " grep release | sed -e 's/.*release //' -e 's/,.*//'") execute_process( - COMMAND - bash -c - "${CUDACOMP} --version | grep release | sed -e 's/.*release //' -e 's/,.*//'" + COMMAND bash -c ${cmd} OUTPUT_VARIABLE CUDACOMP_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE) + message(STATUS "CUDACOMP: ${CUDACOMP_VERSION}") string( APPEND REPORT_TEXT @@ -165,8 +166,9 @@ if(${Kokkos_DEVICES} MATCHES "CUDA") ${CUDACOMP} "${ColorReset}\n") elseif(${Kokkos_DEVICES} MATCHES "HIP") + set(cmd "hipcc --version | grep HIP | cut -d ':' -f 2 | tr -d ' '") execute_process( - COMMAND bash -c "hipcc --version | grep HIP | cut -d ':' -f 2 | tr -d ' '" + COMMAND bash -c ${cmd} OUTPUT_VARIABLE ROCM_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE) string(APPEND REPORT_TEXT " - ROCm: v" ${ROCM_VERSION} "\n") @@ -196,7 +198,9 @@ string( "\n" "Notes" "\n" - " ${Dim}: Set flags with `cmake ... -D ${Magenta}${ColorReset}${Dim}=`, the ${Underline}default${ColorReset}${Dim} value" + " ${Dim}: Set flags with `cmake ... -D " + "${Magenta}${ColorReset}${Dim}=`, " + "the ${Underline}default${ColorReset}${Dim} value" "\n" " : will be used unless the variable is explicitly set.${ColorReset}") diff --git a/cmake/styling.cmake b/cmake/styling.cmake index b9b72abcb..878cb44a4 100644 --- a/cmake/styling.cmake +++ b/cmake/styling.cmake @@ -1,3 +1,5 @@ +# cmake-lint: disable=C0103,C0301,C0111,E1120,R0913,R0915 + if(NOT WIN32) string(ASCII 27 Esc) set(ColorReset "${Esc}[m") @@ -23,13 +25,11 @@ if(NOT WIN32) set(StrikeEnd "${Esc}[0m") endif() -set(DOTTED_LINE_SYMBOL - "${ColorReset}. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . " -) +set(DOTTED_LINE_SYMBOL "${ColorReset}. . . . . . . . . . . . . . . .") +string(APPEND DOTTED_LINE_SYMBOL " . . . . . . . . . . . . . . . . . . . . ") -set(DASHED_LINE_SYMBOL - "${ColorReset}....................................................................... " -) +set(DASHED_LINE_SYMBOL "${ColorReset}.................................") +string(APPEND DASHED_LINE_SYMBOL "...................................... ") set(ON_OFF_VALUES "ON" "OFF") diff --git a/cmake/tests.cmake b/cmake/tests.cmake index e2d92a343..0e108d365 100644 --- a/cmake/tests.cmake +++ b/cmake/tests.cmake @@ -13,9 +13,7 @@ if(${output}) add_subdirectory(${SRC_DIR}/checkpoint ${CMAKE_CURRENT_BINARY_DIR}/checkpoint) endif() -set(TEST_DIRECTORIES - "" - PARENT_SCOPE) +set(TEST_DIRECTORIES "") if(NOT ${mpi}) list(APPEND TEST_DIRECTORIES global) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index db2ab4c92..f9d921df0 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,3 +1,4 @@ +# cmake-lint: disable=C0103 # ------------------------------ # @defines: entity [STATIC/SHARED] # diff --git a/src/archetypes/CMakeLists.txt b/src/archetypes/CMakeLists.txt index 8e2f325af..93f8baaaa 100644 --- a/src/archetypes/CMakeLists.txt +++ b/src/archetypes/CMakeLists.txt @@ -1,3 +1,4 @@ +# cmake-lint: disable=C0103 # ------------------------------ # @defines: ntt_archetypes [INTERFACE] # @@ -24,4 +25,3 @@ target_link_libraries(ntt_archetypes INTERFACE ${libs}) target_include_directories(ntt_archetypes INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/../) - diff --git a/src/archetypes/tests/CMakeLists.txt b/src/archetypes/tests/CMakeLists.txt index 694a6b4f9..9419847c5 100644 --- a/src/archetypes/tests/CMakeLists.txt +++ b/src/archetypes/tests/CMakeLists.txt @@ -1,3 +1,4 @@ +# cmake-lint: disable=C0103,C0111 # ------------------------------ # @brief: Generates tests for the `ntt_archetypes` module # diff --git a/src/checkpoint/CMakeLists.txt b/src/checkpoint/CMakeLists.txt index fa641bfb5..096aad690 100644 --- a/src/checkpoint/CMakeLists.txt +++ b/src/checkpoint/CMakeLists.txt @@ -1,3 +1,4 @@ +# cmake-lint: disable=C0103 # ------------------------------ # @defines: ntt_checkpoint [STATIC/SHARED] # diff --git a/src/checkpoint/tests/CMakeLists.txt b/src/checkpoint/tests/CMakeLists.txt index 54400652e..cbfd63aa9 100644 --- a/src/checkpoint/tests/CMakeLists.txt +++ b/src/checkpoint/tests/CMakeLists.txt @@ -1,3 +1,4 @@ +# cmake-lint: disable=C0103,C0111 # ------------------------------ # @brief: Generates tests for the `ntt_checkpoint` module # diff --git a/src/engines/CMakeLists.txt b/src/engines/CMakeLists.txt index d5b6b0664..4cef18630 100644 --- a/src/engines/CMakeLists.txt +++ b/src/engines/CMakeLists.txt @@ -1,3 +1,4 @@ +# cmake-lint: disable=C0103 # ------------------------------ # @defines: ntt_engines [STATIC/SHARED] # diff --git a/src/framework/CMakeLists.txt b/src/framework/CMakeLists.txt index d3b68084c..4c407fb0c 100644 --- a/src/framework/CMakeLists.txt +++ b/src/framework/CMakeLists.txt @@ -1,3 +1,4 @@ +# cmake-lint: disable=C0103 # ------------------------------ # @defines: ntt_framework [STATIC/SHARED] # diff --git a/src/framework/parameters.cpp b/src/framework/parameters.cpp index e3bddfd70..5848b1c01 100644 --- a/src/framework/parameters.cpp +++ b/src/framework/parameters.cpp @@ -31,10 +31,10 @@ namespace ntt { template - auto get_dx0_V0( - const std::vector& resolution, - const boundaries_t& extent, - const std::map& params) -> std::pair { + auto get_dx0_V0(const std::vector& resolution, + const boundaries_t& extent, + const std::map& params) + -> std::pair { const auto metric = M(resolution, extent, params); const auto dx0 = metric.dxMin(); coord_t x_corner { ZERO }; @@ -839,7 +839,7 @@ namespace ntt { void SimulationParams::setSetupParams(const toml::value& toml_data) { /* [setup] -------------------------------------------------------------- */ - const auto& setup = toml::find_or(toml_data, "setup", toml::table {}); + const auto setup = toml::find_or(toml_data, "setup", toml::table {}); for (const auto& [key, val] : setup) { if (val.is_boolean()) { set("setup." + key, (bool)(val.as_boolean())); diff --git a/src/framework/tests/CMakeLists.txt b/src/framework/tests/CMakeLists.txt index 27c456610..92e327d80 100644 --- a/src/framework/tests/CMakeLists.txt +++ b/src/framework/tests/CMakeLists.txt @@ -1,3 +1,4 @@ +# cmake-lint: disable=C0103,C0111 # ------------------------------ # @brief: Generates tests for the `ntt_framework` module # diff --git a/src/global/CMakeLists.txt b/src/global/CMakeLists.txt index 97946f059..7546b6a98 100644 --- a/src/global/CMakeLists.txt +++ b/src/global/CMakeLists.txt @@ -1,3 +1,4 @@ +# cmake-lint: disable=C0103 # ------------------------------ # @defines: ntt_global [STATIC/SHARED] # diff --git a/src/global/tests/CMakeLists.txt b/src/global/tests/CMakeLists.txt index e30da20a0..c206f85b0 100644 --- a/src/global/tests/CMakeLists.txt +++ b/src/global/tests/CMakeLists.txt @@ -1,3 +1,4 @@ +# cmake-lint: disable=C0103,C0111 # ------------------------------ # @brief: Generates tests for the `ntt_global` module # diff --git a/src/kernels/CMakeLists.txt b/src/kernels/CMakeLists.txt index c8a1f409f..60eda24cb 100644 --- a/src/kernels/CMakeLists.txt +++ b/src/kernels/CMakeLists.txt @@ -1,3 +1,4 @@ +# cmake-lint: disable=C0103 # ------------------------------ # @defines: ntt_kernels [INTERFACE] # @@ -24,4 +25,3 @@ target_link_libraries(ntt_kernels INTERFACE ${libs}) target_include_directories(ntt_kernels INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/../) - diff --git a/src/kernels/tests/CMakeLists.txt b/src/kernels/tests/CMakeLists.txt index a41ea43ef..7579eb6d3 100644 --- a/src/kernels/tests/CMakeLists.txt +++ b/src/kernels/tests/CMakeLists.txt @@ -1,3 +1,4 @@ +# cmake-lint: disable=C0103,C0111 # ------------------------------ # @brief: Generates tests for the `ntt_kernels` module # diff --git a/src/metrics/CMakeLists.txt b/src/metrics/CMakeLists.txt index e053bb61c..0bb5b977c 100644 --- a/src/metrics/CMakeLists.txt +++ b/src/metrics/CMakeLists.txt @@ -1,3 +1,4 @@ +# cmake-lint: disable=C0103 # ------------------------------ # @defines: ntt_metrics [INTERFACE] # @@ -22,4 +23,3 @@ target_link_libraries(ntt_metrics INTERFACE ${libs}) target_include_directories(ntt_metrics INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/../) - diff --git a/src/metrics/tests/CMakeLists.txt b/src/metrics/tests/CMakeLists.txt index c997ab079..0d661c318 100644 --- a/src/metrics/tests/CMakeLists.txt +++ b/src/metrics/tests/CMakeLists.txt @@ -1,3 +1,4 @@ +# cmake-lint: disable=C0103,C0111 # ------------------------------ # @brief: Generates tests for the `ntt_metrics` module # @@ -28,4 +29,3 @@ gen_test(coord_trans) gen_test(sph-qsph) gen_test(ks-qks) gen_test(sr-cart-sph) - diff --git a/src/output/CMakeLists.txt b/src/output/CMakeLists.txt index 81333e9ff..8a2ea0f16 100644 --- a/src/output/CMakeLists.txt +++ b/src/output/CMakeLists.txt @@ -1,3 +1,4 @@ +# cmake-lint: disable=C0103 # ------------------------------ # @defines: ntt_output [STATIC/SHARED] # diff --git a/src/output/tests/CMakeLists.txt b/src/output/tests/CMakeLists.txt index afc7950c4..835bb532f 100644 --- a/src/output/tests/CMakeLists.txt +++ b/src/output/tests/CMakeLists.txt @@ -1,3 +1,4 @@ +# cmake-lint: disable=C0103,C0111 # ------------------------------ # @brief: Generates tests for the `ntt_output` module # From ec7ff77c6cb3b1fd93701047acd67fbca9425048 Mon Sep 17 00:00:00 2001 From: hayk Date: Fri, 4 Apr 2025 03:12:26 -0400 Subject: [PATCH 583/773] log level controlled from input --- input.example.toml | 6 ++++++ src/framework/parameters.cpp | 2 ++ src/framework/simulation.cpp | 7 ++++++- src/global/defaults.h | 3 ++- src/global/utils/formatting.h | 2 +- src/global/utils/plog.h | 14 +++++++++++--- 6 files changed, 28 insertions(+), 6 deletions(-) diff --git a/input.example.toml b/input.example.toml index c71049b84..f519a2799 100644 --- a/input.example.toml +++ b/input.example.toml @@ -478,3 +478,9 @@ # @type: bool # @default: true colored_stdout = "" + # Specify the log level: + # @type: string + # @valid: "VERBOSE", "WARNING", "ERROR" + # @default: "VERBOSE" + # @note: VERBOSE prints all messages, WARNING prints only warnings and errors, ERROR prints only errors + log_level = "" diff --git a/src/framework/parameters.cpp b/src/framework/parameters.cpp index 5848b1c01..556d9f547 100644 --- a/src/framework/parameters.cpp +++ b/src/framework/parameters.cpp @@ -601,6 +601,8 @@ namespace ntt { toml::find_or(toml_data, "diagnostics", "blocking_timers", false)); set("diagnostics.colored_stdout", toml::find_or(toml_data, "diagnostics", "colored_stdout", false)); + set("diagnostics.log_level", + toml::find_or(toml_data, "diagnostics", "log_level", defaults::diag::log_level)); /* inferred variables --------------------------------------------------- */ // fields/particle boundaries diff --git a/src/framework/simulation.cpp b/src/framework/simulation.cpp index 560539c25..6865140c9 100644 --- a/src/framework/simulation.cpp +++ b/src/framework/simulation.cpp @@ -32,7 +32,12 @@ namespace ntt { const auto raw_params = toml::parse(inputfname); const auto sim_name = toml::find(raw_params, "simulation", "name"); - logger::initPlog(sim_name); + const auto log_level = toml::find_or(raw_params, + "diagnostics", + "log_level", + defaults::diag::log_level); + logger::initPlog(sim_name, + log_level); m_requested_engine = SimEngine::pick( fmt::toLower(toml::find(raw_params, "simulation", "engine")).c_str()); diff --git a/src/global/defaults.h b/src/global/defaults.h index b81369022..d17647ccd 100644 --- a/src/global/defaults.h +++ b/src/global/defaults.h @@ -68,7 +68,8 @@ namespace ntt::defaults { } // namespace checkpoint namespace diag { - const timestep_t interval = 1; + const timestep_t interval = 1; + const std::string log_level = "VERBOSE"; } // namespace diag namespace gca { diff --git a/src/global/utils/formatting.h b/src/global/utils/formatting.h index 8dc7b6ba8..c8c236cab 100644 --- a/src/global/utils/formatting.h +++ b/src/global/utils/formatting.h @@ -171,7 +171,7 @@ namespace fmt { std::size_t cntr { 0 }; for (auto i { 0u }; i < columns.size(); ++i) { const auto anch { static_cast(anchors[i] < 0 ? -anchors[i] - : anchors[i]) }; + : anchors[i]) }; const auto leftalign { anchors[i] <= 0 }; const auto cmn { columns[i] }; const auto cmn_len { strlenUTF8(cmn) }; diff --git a/src/global/utils/plog.h b/src/global/utils/plog.h index 03dc19319..2422c7cf9 100644 --- a/src/global/utils/plog.h +++ b/src/global/utils/plog.h @@ -13,6 +13,8 @@ #ifndef GLOBAL_UTILS_PLOG_H #define GLOBAL_UTILS_PLOG_H +#include "utils/formatting.h" + #include #include #include @@ -57,7 +59,7 @@ namespace plog { namespace logger { template - inline void initPlog(const std::string& fname) { + inline void initPlog(const std::string& fname, const std::string& log_level) { // setup logging const auto logfile_name = fname + ".log"; const auto infofile_name = fname + ".info"; @@ -77,7 +79,13 @@ namespace logger { infofile_name.c_str()); static plog::RollingFileAppender errfileAppender( errfile_name.c_str()); - plog::init(plog::verbose, &logfileAppender); + auto log_severity = plog::verbose; + if (fmt::toLower(log_level) == "WARNING") { + log_severity = plog::warning; + } else if (fmt::toLower(log_level) == "ERROR") { + log_severity = plog::error; + } + plog::init(log_severity, &logfileAppender); plog::init(plog::verbose, &infofileAppender); plog::init(plog::verbose, &errfileAppender); @@ -93,4 +101,4 @@ namespace logger { } // namespace logger -#endif // GLOBAL_UTILS_PLOG_H \ No newline at end of file +#endif // GLOBAL_UTILS_PLOG_H From 8850ab9d05b641378b1c1699dea1f0376cb671e4 Mon Sep 17 00:00:00 2001 From: hayk Date: Sat, 5 Apr 2025 06:58:40 -0400 Subject: [PATCH 584/773] warnings fixed --- src/framework/domain/comm_mpi.hpp | 6 ++---- src/framework/domain/communications.cpp | 21 ++++++++++----------- src/framework/domain/metadomain.cpp | 2 +- src/global/utils/timer.cpp | 2 +- src/output/tests/writer-mpi.cpp | 4 ++-- 5 files changed, 16 insertions(+), 19 deletions(-) diff --git a/src/framework/domain/comm_mpi.hpp b/src/framework/domain/comm_mpi.hpp index 159502e7a..d9783bdb6 100644 --- a/src/framework/domain/comm_mpi.hpp +++ b/src/framework/domain/comm_mpi.hpp @@ -335,10 +335,8 @@ namespace comm { const unsigned short NPLDS = species.npld(); // buffers to store recv data - const auto npart_alive = npptag_vec[ParticleTag::alive]; - const auto npart_dead = npptag_vec[ParticleTag::dead]; - const auto npart_send = outgoing_indices.extent(0) - npart_dead; - const auto npart_recv = std::accumulate(npptag_recv_vec.begin(), + const auto npart_dead = npptag_vec[ParticleTag::dead]; + const auto npart_recv = std::accumulate(npptag_recv_vec.begin(), npptag_recv_vec.end(), static_cast(0)); array_t recv_buff_int { "recv_buff_int", npart_recv * NINTS }; diff --git a/src/framework/domain/communications.cpp b/src/framework/domain/communications.cpp index 946756f49..cf7e04974 100644 --- a/src/framework/domain/communications.cpp +++ b/src/framework/domain/communications.cpp @@ -36,10 +36,10 @@ namespace ntt { using comm_params_t = std::pair>; template - auto GetSendRecvRanks( - Metadomain* metadomain, - Domain& domain, - dir::direction_t direction) -> std::pair { + auto GetSendRecvRanks(Metadomain* metadomain, + Domain& domain, + dir::direction_t direction) + -> std::pair { Domain* send_to_nghbr_ptr = nullptr; Domain* recv_from_nghbr_ptr = nullptr; // set pointers to the correct send/recv domains @@ -119,11 +119,11 @@ namespace ntt { } template - auto GetSendRecvParams( - Metadomain* metadomain, - Domain& domain, - dir::direction_t direction, - bool synchronize) -> std::pair { + auto GetSendRecvParams(Metadomain* metadomain, + Domain& domain, + dir::direction_t direction, + bool synchronize) + -> std::pair { const auto [send_indrank, recv_indrank] = GetSendRecvRanks(metadomain, domain, direction); const auto [send_ind, send_rank] = send_indrank; @@ -506,8 +506,7 @@ namespace ntt { const auto npart_dead = npptag_vec[ParticleTag::dead]; const auto npart_alive = npptag_vec[ParticleTag::alive]; - const auto npart = species.npart(); - const auto npart_holes = npart - npart_alive; + const auto npart = species.npart(); // # of particles to receive per each tag (direction) std::vector npptag_recv_vec(ntags - 2, 0); diff --git a/src/framework/domain/metadomain.cpp b/src/framework/domain/metadomain.cpp index eec6c8fa0..8952d417d 100644 --- a/src/framework/domain/metadomain.cpp +++ b/src/framework/domain/metadomain.cpp @@ -46,7 +46,7 @@ namespace ntt { #if defined(MPI_ENABLED) MPI_Comm_size(MPI_COMM_WORLD, &g_mpi_size); MPI_Comm_rank(MPI_COMM_WORLD, &g_mpi_rank); - raise::ErrorIf(global_ndomains != g_mpi_size, + raise::ErrorIf(global_ndomains != (unsigned int)g_mpi_size, "Exactly 1 domain per MPI rank is allowed", HERE); #endif diff --git a/src/global/utils/timer.cpp b/src/global/utils/timer.cpp index bc133b4b7..3cca1b365 100644 --- a/src/global/utils/timer.cpp +++ b/src/global/utils/timer.cpp @@ -68,7 +68,7 @@ namespace timer { return {}; } std::vector all_totals(size, 0.0); - for (auto i { 0u }; i < size; ++i) { + for (auto i { 0 }; i < size; ++i) { for (auto& [name, timer] : m_timers) { if (std::find(ignore_in_tot.begin(), ignore_in_tot.end(), name) == ignore_in_tot.end()) { diff --git a/src/output/tests/writer-mpi.cpp b/src/output/tests/writer-mpi.cpp index cc9208889..af8a38ef1 100644 --- a/src/output/tests/writer-mpi.cpp +++ b/src/output/tests/writer-mpi.cpp @@ -22,7 +22,8 @@ void cleanup() { } #define CEILDIV(a, b) \ - (static_cast(math::ceil(static_cast(a) / static_cast(b)))) + (static_cast( \ + math::ceil(static_cast(a) / static_cast(b)))) auto main(int argc, char* argv[]) -> int { Kokkos::initialize(argc, argv); @@ -115,7 +116,6 @@ auto main(int argc, char* argv[]) -> int { const auto l_size = nx1; const auto l_offset = nx1 * mpi_rank; - const auto g_size = nx1 * mpi_size; const double n = l_size; const double d = dwn1; From eab6f78920c5e1532f32900eecac0c34de95ffc6 Mon Sep 17 00:00:00 2001 From: hayk Date: Thu, 3 Apr 2025 16:53:54 -0400 Subject: [PATCH 585/773] match.ds is now array --- input.example.toml | 8 +- src/engines/srpic.hpp | 145 ++++++++++++++++++++--------- src/framework/parameters.cpp | 68 +++++++++++--- src/framework/tests/parameters.cpp | 18 +++- 4 files changed, 172 insertions(+), 67 deletions(-) diff --git a/input.example.toml b/input.example.toml index f519a2799..e4501f0a0 100644 --- a/input.example.toml +++ b/input.example.toml @@ -107,11 +107,13 @@ particles = "" [grid.boundaries.match] - # Size of the matching layer for fields in physical (code) units: - # @type: float + # Size of the matching layer in each direction for fields in physical (code) units: + # @type: float or array of tuples # @default: 1% of the domain size (in shortest dimension) # @note: In spherical, this is the size of the layer in r from the outer wall - # @note: In cartesian, this is the same for all dimensions where applicable + # @example: ds = 1.5 (will set the same for all directions) + # @example: ds = [[1.5], [2.0, 1.0], [1.1]] (will duplicate 1.5 for +/- x1 and 1.1 for +/- x3) + # @example: ds = [[], [1.5], []] (will only set for x2) ds = "" # Absorption coefficient for fields: # @type: float: -inf < ... < inf, != 0 diff --git a/src/engines/srpic.hpp b/src/engines/srpic.hpp index 62cd23ad9..c38fe2261 100644 --- a/src/engines/srpic.hpp +++ b/src/engines/srpic.hpp @@ -79,7 +79,7 @@ namespace ntt { "algorithms.toggles.fieldsolver"); const auto deposit_enabled = m_params.template get( "algorithms.toggles.deposit"); - const auto clear_interval = m_params.template get( + const auto clear_interval = m_params.template get( "particles.clear_interval"); if (step == 0) { @@ -616,15 +616,19 @@ namespace ntt { /** * matching boundaries */ - const auto ds = m_params.template get("grid.boundaries.match.ds"); + const auto ds_array = m_params.template get>( + "grid.boundaries.match.ds"); const auto dim = direction.get_dim(); real_t xg_min, xg_max, xg_edge; auto sign = direction.get_sign(); + real_t ds; if (sign > 0) { // + direction + ds = ds_array[(short)dim].second; xg_max = m_metadomain.mesh().extent(dim).second; xg_min = xg_max - ds; xg_edge = xg_max; } else { // - direction + ds = ds_array[(short)dim].first; xg_min = m_metadomain.mesh().extent(dim).first; xg_max = xg_min + ds; xg_edge = xg_min; @@ -655,50 +659,81 @@ namespace ntt { range_min[d] = intersect_range[d].first; range_max[d] = intersect_range[d].second; } - if constexpr (traits::has_member::value) { - auto match_fields = m_pgen.MatchFields(time); - if (dim == in::x1) { - Kokkos::parallel_for( - "MatchFields", - CreateRangePolicy(range_min, range_max), - kernel::bc::MatchBoundaries_kernel( - domain.fields.em, - match_fields, - domain.mesh.metric, - xg_edge, - ds, - tags)); - } else if (dim == in::x2) { - if constexpr (M::Dim == Dim::_2D or M::Dim == Dim::_3D) { - Kokkos::parallel_for( - "MatchFields", - CreateRangePolicy(range_min, range_max), - kernel::bc::MatchBoundaries_kernel( - domain.fields.em, - match_fields, - domain.mesh.metric, - xg_edge, - ds, - tags)); - } else { - raise::Error("Invalid dimension", HERE); - } - } else if (dim == in::x3) { - if constexpr (M::Dim == Dim::_3D) { - Kokkos::parallel_for( - "MatchFields", - CreateRangePolicy(range_min, range_max), - kernel::bc::MatchBoundaries_kernel( - domain.fields.em, - match_fields, - domain.mesh.metric, - xg_edge, - ds, - tags)); - } else { - raise::Error("Invalid dimension", HERE); - } + + if (dim == in::x1) { + if constexpr ( + traits::has_member::value) { + auto match_fields = m_pgen.MatchFields(time); + call_match_fields(domain.fields.em, + match_fields, + domain.mesh.metric, + xg_edge, + ds, + tags, + range_min, + range_max); + } else if constexpr ( + traits::has_member::value) { + auto match_fields = m_pgen.MatchFieldsInX1(time); + call_match_fields(domain.fields.em, + match_fields, + domain.mesh.metric, + xg_edge, + ds, + tags, + range_min, + range_max); } + } else if (dim == in::x2) { + if constexpr ( + traits::has_member::value) { + auto match_fields = m_pgen.MatchFields(time); + call_match_fields(domain.fields.em, + match_fields, + domain.mesh.metric, + xg_edge, + ds, + tags, + range_min, + range_max); + } else if constexpr ( + traits::has_member::value) { + auto match_fields = m_pgen.MatchFieldsInX2(time); + call_match_fields(domain.fields.em, + match_fields, + domain.mesh.metric, + xg_edge, + ds, + tags, + range_min, + range_max); + } + } else if (dim == in::x3) { + if constexpr ( + traits::has_member::value) { + auto match_fields = m_pgen.MatchFields(time); + call_match_fields(domain.fields.em, + match_fields, + domain.mesh.metric, + xg_edge, + ds, + tags, + range_min, + range_max); + } else if constexpr ( + traits::has_member::value) { + auto match_fields = m_pgen.MatchFieldsInX3(time); + call_match_fields(domain.fields.em, + match_fields, + domain.mesh.metric, + xg_edge, + ds, + tags, + range_min, + range_max); + } + } else { + raise::Error("Invalid dimension", HERE); } } @@ -1381,6 +1416,26 @@ namespace ntt { } return range; } + + template + void call_match_fields(ndfield_t& fields, + const T& match_fields, + const M& metric, + real_t xg_edge, + real_t ds, + BCTags tags, + tuple_t& range_min, + tuple_t& range_max) { + Kokkos::parallel_for( + "MatchFields", + CreateRangePolicy(range_min, range_max), + kernel::bc::MatchBoundaries_kernel(fields, + match_fields, + metric, + xg_edge, + ds, + tags)); + } }; } // namespace ntt diff --git a/src/framework/parameters.cpp b/src/framework/parameters.cpp index 556d9f547..cd6edc929 100644 --- a/src/framework/parameters.cpp +++ b/src/framework/parameters.cpp @@ -738,23 +738,63 @@ namespace ntt { for (const auto& e : extent_pairwise) { min_extent = std::min(min_extent, e.second - e.first); } - set("grid.boundaries.match.ds", - toml::find_or(toml_data, - "grid", - "boundaries", - "match", - "ds", - min_extent * defaults::bc::match::ds_frac)); + const auto default_ds = min_extent * defaults::bc::match::ds_frac; + std::size_t n_match_bcs { 0u }; + for (const auto& bcs : flds_bc_pairwise) { + if (bcs.first == FldsBC::MATCH or bcs.second == FldsBC::MATCH) { + n_match_bcs += 1; + } + } + boundaries_t ds_array; + try { + auto ds = toml::find(toml_data, "grid", "boundaries", "match", "ds"); + for (auto d = 0u; d < dim; ++d) { + ds_array.push_back({ ds, ds }); + } + } catch (const toml::type_error&) { + try { + const auto ds = toml::find>>( + toml_data, + "grid", + "boundaries", + "match", + "ds"); + raise::ErrorIf(ds.size() != dim, + "invalid # in `grid.boundaries.match.ds`", + HERE); + for (auto d = 0u; d < dim; ++d) { + if (ds[d].size() == 1) { + ds_array.push_back({ ds[d][0], ds[d][0] }); + } else if (ds[d].size() == 2) { + ds_array.push_back({ ds[d][0], ds[d][1] }); + } else if (ds[d].size() == 0) { + ds_array.push_back({}); + } else { + raise::Error("invalid `grid.boundaries.match.ds`", HERE); + } + } + } catch (...) { + for (auto d = 0u; d < dim; ++d) { + ds_array.push_back({ default_ds, default_ds }); + } + } + } + set("grid.boundaries.match.ds", ds_array); } else { auto r_extent = extent_pairwise[0].second - extent_pairwise[0].first; - set("grid.boundaries.match.ds", - toml::find_or(toml_data, - "grid", - "boundaries", - "match", - "ds", - r_extent * defaults::bc::match::ds_frac)); + const auto ds = toml::find_or( + toml_data, + "grid", + "boundaries", + "match", + "ds", + r_extent * defaults::bc::match::ds_frac); + boundaries_t ds_array { + { ds, ds } + }; + set("grid.boundaries.match.ds", ds_array); } + set("grid.boundaries.match.coeff", toml::find_or(toml_data, "grid", diff --git a/src/framework/tests/parameters.cpp b/src/framework/tests/parameters.cpp index 7cd5ce46a..c4d1f0e7b 100644 --- a/src/framework/tests/parameters.cpp +++ b/src/framework/tests/parameters.cpp @@ -29,12 +29,12 @@ const auto mink_1d = u8R"( metric = "minkowski" [grid.boundaries] - fields = [["PERIODIC"]] + fields = [["MATCH", "MATCH"]] particles = [["ABSORB", "ABSORB"]] [grid.boundaries.match] coeff = 10.0 - ds = 0.025 + ds = [[0.025, 0.1]] [scales] larmor0 = 0.1 @@ -269,7 +269,7 @@ auto main(int argc, char* argv[]) -> int { (real_t)0.0078125, "scales.V0"); boundaries_t fbc = { - { FldsBC::PERIODIC, FldsBC::PERIODIC } + { FldsBC::MATCH, FldsBC::MATCH } }; assert_equal( params_mink_1d.get>("grid.boundaries.fields")[0].first, @@ -283,6 +283,14 @@ auto main(int argc, char* argv[]) -> int { params_mink_1d.get>("grid.boundaries.fields").size(), fbc.size(), "grid.boundaries.fields.size()"); + assert_equal( + params_mink_1d.get>("grid.boundaries.match.ds")[0].first, + (real_t)0.025, + "grid.boundaries.match.ds[0].first"); + assert_equal( + params_mink_1d.get>("grid.boundaries.match.ds")[0].second, + (real_t)0.1, + "grid.boundaries.match.ds[0].first"); const auto species = params_mink_1d.get>( "particles.species"); @@ -383,7 +391,7 @@ auto main(int argc, char* argv[]) -> int { // match coeffs assert_equal( - params_sph_2d.get("grid.boundaries.match.ds"), + params_sph_2d.get>("grid.boundaries.match.ds")[0].second, (real_t)(defaults::bc::match::ds_frac * 19.0), "grid.boundaries.match.ds"); @@ -539,7 +547,7 @@ auto main(int argc, char* argv[]) -> int { // match coeffs assert_equal( - params_qks_2d.get("grid.boundaries.match.ds"), + params_qks_2d.get>("grid.boundaries.match.ds")[0].second, (real_t)(defaults::bc::match::ds_frac * (100.0 - 0.8)), "grid.boundaries.match.ds"); From b91268fa054af992684c2a03698fad16c75f5b86 Mon Sep 17 00:00:00 2001 From: hayk Date: Thu, 3 Apr 2025 16:54:56 -0400 Subject: [PATCH 586/773] generalized uniform injector --- src/archetypes/particle_injector.h | 128 +++++++++++++++++++++++------ src/kernels/injectors.hpp | 14 ++-- 2 files changed, 110 insertions(+), 32 deletions(-) diff --git a/src/archetypes/particle_injector.h b/src/archetypes/particle_injector.h index 62b9249c3..a235ecf57 100644 --- a/src/archetypes/particle_injector.h +++ b/src/archetypes/particle_injector.h @@ -32,6 +32,7 @@ #include #include +#include #include #include @@ -58,14 +59,79 @@ namespace arch { , species { species } {} ~UniformInjector() = default; + + auto ComputeNumInject(const Domain& domain, + real_t ppc0, + real_t number_density, + const boundaries_t& box) const + -> std::tuple, array_t> { + auto i_min = array_t { "i_min", M::Dim }; + auto i_max = array_t { "i_max", M::Dim }; + + if (not domain.mesh.Intersects(box)) { + return { false, (npart_t)0, i_min, i_max }; + } + tuple_t range_min { 0 }; + tuple_t range_max { 0 }; + + boundaries_t incl_ghosts; + for (auto d { 0u }; d < M::Dim; ++d) { + incl_ghosts.push_back({ false, false }); + } + const auto intersect_range = domain.mesh.ExtentToRange(box, incl_ghosts); + + for (auto d { 0u }; d < M::Dim; ++d) { + range_min[d] = intersect_range[d].first; + range_max[d] = intersect_range[d].second; + } + ncells_t ncells = 1; + for (auto d = 0u; d < M::Dim; ++d) { + ncells *= (range_max[d] - range_min[d]); + } + const auto nparticles = static_cast( + (long double)(ppc0 * number_density * 0.5) * (long double)(ncells)); + + auto i_min_h = Kokkos::create_mirror_view(i_min); + auto i_max_h = Kokkos::create_mirror_view(i_max); + for (auto d = 0u; d < M::Dim; ++d) { + i_min_h(d) = (real_t)(range_min[d]); + i_max_h(d) = (real_t)(range_max[d]); + } + Kokkos::deep_copy(i_min, i_min_h); + Kokkos::deep_copy(i_max, i_max_h); + return { true, nparticles, i_min, i_max }; + } + }; + + template class ED> + struct KeepConstantInjector : UniformInjector { + using energy_dist_t = ED; + using UniformInjector::D; + using UniformInjector::C; + + const boundaries_t probe_box; + + KeepConstantInjector(const energy_dist_t& energy_dist, + const std::pair& species, + boundaries_t probe_box = {}) + : UniformInjector(energy_dist, species) + , probe_box { probe_box } {} + + ~KeepConstantInjector() = default; + + auto ComputeNumInject(const Domain& domain, + real_t ppc0, + real_t number_density, + const boundaries_t& box) const + -> std::tuple, array_t> { + ... + } }; template - class ED, - template - class SD> + template class ED, + template class SD> struct NonUniformInjector { using energy_dist_t = ED; using spatial_dist_t = SD; @@ -243,11 +309,12 @@ namespace arch { * @tparam I Injector type */ template - inline void InjectUniform(const SimulationParams& params, - Domain& domain, - const I& injector, - real_t number_density, - bool use_weights = false) { + inline void InjectUniform(const SimulationParams& params, + Domain& domain, + const I& injector, + 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(I::is_uniform_injector, "I must be a uniform injector class"); raise::ErrorIf((M::CoordType != Coord::Cart) && (not use_weights), @@ -267,17 +334,25 @@ namespace arch { } { - auto ppc0 = params.template get("particles.ppc0"); - array_t ni { "ni", M::Dim }; - auto ni_h = Kokkos::create_mirror_view(ni); - ncells_t ncells = 1; - for (auto d = 0; d < M::Dim; ++d) { - ni_h(d) = domain.mesh.n_active()[d]; - ncells *= domain.mesh.n_active()[d]; + boundaries_t nonempty_box; + for (auto d { 0u }; d < M::Dim; ++d) { + if (d < box.size()) { + nonempty_box.push_back({ box[d].first, box[d].second }); + } else { + nonempty_box.push_back(Range::All); + } } - Kokkos::deep_copy(ni, ni_h); - const auto nparticles = static_cast( - (long double)(ppc0 * number_density * 0.5) * (long double)(ncells)); + auto ppc0 = params.template get("particles.ppc0"); + const auto result = injector.ComputeNumInject(domain, + ppc0, + number_density, + nonempty_box); + if (not std::get<0>(result)) { + return; + } + const auto nparticles = std::get<1>(result); + const auto i_min = std::get<2>(result); + const auto i_max = std::get<3>(result); Kokkos::parallel_for( "InjectUniform", @@ -290,7 +365,8 @@ namespace arch { domain.species[injector.species.first - 1].npart(), domain.species[injector.species.second - 1].npart(), domain.mesh.metric, - ni, + i_min, + i_max, injector.energy_dist, ONE / params.template get("scales.V0"), domain.random_pool)); @@ -341,12 +417,12 @@ namespace arch { * @param box Region to inject the particles in */ template - inline void InjectNonUniform(const SimulationParams& params, - Domain& domain, - const I& injector, - real_t number_density, - bool use_weights = false, - boundaries_t box = {}) { + inline void InjectNonUniform(const SimulationParams& params, + Domain& domain, + const I& injector, + 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(I::is_nonuniform_injector, "I must be a nonuniform injector class"); diff --git a/src/kernels/injectors.hpp b/src/kernels/injectors.hpp index 09bc7a180..7dcd017a3 100644 --- a/src/kernels/injectors.hpp +++ b/src/kernels/injectors.hpp @@ -49,7 +49,7 @@ namespace kernel { npart_t offset1, offset2; const M metric; - const array_t ni; + const array_t i_min, i_max; const ED energy_dist; const real_t inv_V0; random_number_pool_t random_pool; @@ -61,7 +61,8 @@ namespace kernel { npart_t offset1, npart_t offset2, const M& metric, - const array_t& ni, + const array_t& i_min, + const array_t& i_max, const ED& energy_dist, real_t inv_V0, random_number_pool_t& random_pool) @@ -94,7 +95,8 @@ namespace kernel { , offset1 { offset1 } , offset2 { offset2 } , metric { metric } - , ni { ni } + , i_min { i_min } + , i_max { i_max } , energy_dist { energy_dist } , inv_V0 { inv_V0 } , random_pool { random_pool } {} @@ -104,12 +106,12 @@ namespace kernel { vec_t v1 { ZERO }, v2 { ZERO }; { // generate a random coordinate auto rand_gen = random_pool.get_state(); - x_Cd[0] = Random(rand_gen) * ni(0); + x_Cd[0] = i_min(0) + Random(rand_gen) * (i_max(0) - i_min(0)); if constexpr (M::Dim == Dim::_2D or M::Dim == Dim::_3D) { - x_Cd[1] = Random(rand_gen) * ni(1); + x_Cd[1] = i_min(1) + Random(rand_gen) * (i_max(1) - i_min(1)); } if constexpr (M::Dim == Dim::_3D) { - x_Cd[2] = Random(rand_gen) * ni(2); + x_Cd[2] = i_min(2) + Random(rand_gen) * (i_max(2) - i_min(2)); } random_pool.free_state(rand_gen); } From aaba83c1a614152fb7a524ef411e1495d19bc495 Mon Sep 17 00:00:00 2001 From: hayk Date: Thu, 3 Apr 2025 16:56:02 -0400 Subject: [PATCH 587/773] diff match boundaries in diff directions --- setups/wip/reconnection/pgen.hpp | 292 +++++++++++++++++----- setups/wip/reconnection/reconnection.toml | 40 +-- src/global/arch/traits.h | 9 + 3 files changed, 261 insertions(+), 80 deletions(-) diff --git a/setups/wip/reconnection/pgen.hpp b/setups/wip/reconnection/pgen.hpp index e97bc518a..34314ca68 100644 --- a/setups/wip/reconnection/pgen.hpp +++ b/setups/wip/reconnection/pgen.hpp @@ -15,41 +15,136 @@ #include "archetypes/spatial_dist.h" #include "framework/domain/metadomain.h" +#include "kernels/particle_moments.hpp" + namespace user { using namespace ntt; template struct CurrentLayer : public arch::SpatialDistribution { - CurrentLayer(const M& metric, real_t width, real_t yi) + CurrentLayer(const M& metric, real_t cs_width, real_t cs_y) : arch::SpatialDistribution { metric } - , width { width } - , yi { yi } {} + , cs_width { cs_width } + , cs_y { cs_y } {} Inline auto operator()(const coord_t& x_Ph) const -> real_t override { - return ONE / SQR(math::cosh((x_Ph[1] - yi) / width)); + return ONE / SQR(math::cosh((x_Ph[1] - cs_y) / cs_width)); } private: - const real_t yi, width; + const real_t cs_y, cs_width; }; + // field initializer template struct InitFields { - InitFields(real_t Bmag, real_t width, real_t y1, real_t y2) - : Bmag { Bmag } - , width { width } - , y1 { y1 } - , y2 { y2 } {} + InitFields(real_t bg_B, real_t bg_Bguide, real_t cs_width, real_t cs_y) + : bg_B { bg_B } + , bg_Bguide { bg_Bguide } + , cs_width { cs_width } + , cs_y { cs_y } {} Inline auto bx1(const coord_t& x_Ph) const -> real_t { - return Bmag * (math::tanh((x_Ph[1] - y1) / width) - - math::tanh((x_Ph[1] - y2) / width) - 1); + return bg_B * (math::tanh((x_Ph[1] - cs_y) / cs_width)); + } + + Inline auto bx3(const coord_t&) const -> real_t { + return bg_Bguide; } private: - const real_t Bmag, width, y1, y2; + const real_t bg_B, bg_Bguide, cs_width, cs_y; }; + template + struct BoundaryFieldsInX1 { + BoundaryFieldsInX1(real_t bg_B, + real_t bg_Bguide, + real_t beta_rec, + real_t cs_width, + real_t cs_x, + real_t cs_y) + : bg_B { bg_B } + , bg_Bguide { bg_Bguide } + , beta_rec { beta_rec } + , cs_width { cs_width } + , cs_x { cs_x } + , cs_y { cs_y } {} + + Inline auto bx1(const coord_t& x_Ph) const -> real_t { + return bg_B * (math::tanh((x_Ph[1] - cs_y) / cs_width)); + } + + Inline auto bx2(const coord_t& x_Ph) const -> real_t { + return beta_rec * bg_B * (math::tanh((x_Ph[0] - cs_x) / cs_width)); + } + + Inline auto bx3(const coord_t&) const -> real_t { + return bg_Bguide; + } + + Inline auto ex1(const coord_t& x_Ph) const -> real_t { + return beta_rec * bg_Bguide * math::tanh((x_Ph[1] - cs_y) / cs_width); + } + + Inline auto ex2(const coord_t&) const -> real_t { + return ZERO; + } + + Inline auto ex3(const coord_t&) const -> real_t { + return -beta_rec * bg_B; + } + + private: + const real_t bg_B, bg_Bguide, beta_rec, cs_width, cs_x, cs_y; + }; + + template + struct BoundaryFieldsInX2 { + BoundaryFieldsInX2(real_t bg_B, real_t bg_Bguide, real_t cs_width, real_t cs_y) + : bg_B { bg_B } + , bg_Bguide { bg_Bguide } + , cs_width { cs_width } + , cs_y { cs_y } {} + + Inline auto bx1(const coord_t& x_Ph) const -> real_t { + return bg_B * (math::tanh((x_Ph[1] - cs_y) / cs_width)); + } + + Inline auto bx2(const coord_t&) const -> real_t { + return ZERO; + } + + Inline auto bx3(const coord_t&) const -> real_t { + return bg_Bguide; + } + + Inline auto ex1(const coord_t&) const -> real_t { + return ZERO; + } + + Inline auto ex2(const coord_t&) const -> real_t { + return ZERO; + } + + Inline auto ex3(const coord_t&) const -> real_t { + return ZERO; + } + + private: + const real_t bg_B, bg_Bguide, cs_width, cs_y; + }; + + // constant particle density for particle boundaries + template + struct ConstDens { + Inline auto operator()(const coord_t& x_Ph) const -> real_t { + return ONE; + } + }; + template + using spatial_dist_t = arch::Replenish>; + template struct PGen : public arch::ProblemGenerator { // compatibility traits for the problem generator @@ -64,30 +159,42 @@ namespace user { using arch::ProblemGenerator::C; using arch::ProblemGenerator::params; - const real_t Bmag, width, overdensity, y1, y2, bg_temp; + const real_t bg_B, bg_Bguide, bg_temperature; + const real_t cs_width, cs_overdensity, cs_x, cs_y; + InitFields init_flds; inline PGen(const SimulationParams& p, const Metadomain& m) : arch::ProblemGenerator(p) - , Bmag { p.template get("setup.Bmag", 1.0) } - , width { p.template get("setup.width") } - , overdensity { p.template get("setup.overdensity") } - , y1 { m.mesh().extent(in::x2).first + - INV_4 * - (m.mesh().extent(in::x2).second - m.mesh().extent(in::x2).first) } - , y2 { m.mesh().extent(in::x2).first + - 3 * INV_4 * - (m.mesh().extent(in::x2).second - m.mesh().extent(in::x2).first) } - , init_flds { Bmag, width, y1, y2 } - , bg_temp { p.template get("setup.bg_temp") } {} + , bg_B { p.template get("setup.bg_B", 1.0) } + , bg_Bguide { p.template get("setup.bg_Bguide", 0.0) } + , bg_temperature { p.template get("setup.bg_temperature", 0.001) } + , cs_width { p.template get("setup.cs_width") } + , cs_overdensity { p.template get("setup.cs_overdensity") } + , cs_x { m.mesh().extent(in::x1).first + + INV_2 * (m.mesh().extent(in::x1).second - + m.mesh().extent(in::x1).first) } + , cs_y { m.mesh().extent(in::x2).first + + INV_2 * (m.mesh().extent(in::x2).second - + m.mesh().extent(in::x2).first) } + , init_flds { bg_B, bg_Bguide, cs_width, cs_y } {} inline PGen() {} + auto MatchFieldsInX1(simtime_t) const -> BoundaryFieldsInX1 { + return BoundaryFieldsInX1 { bg_B, bg_Bguide, (real_t)0.1, + cs_width, cs_x, cs_y }; + } + + auto MatchFieldsInX2(simtime_t) const -> BoundaryFieldsInX2 { + return BoundaryFieldsInX2 { bg_B, bg_Bguide, cs_width, cs_y }; + } + inline void InitPrtls(Domain& local_domain) { // background const auto energy_dist = arch::Maxwellian(local_domain.mesh.metric, local_domain.random_pool, - bg_temp); + bg_temperature); const auto injector = arch::UniformInjector( energy_dist, { 1, 2 }); @@ -95,46 +202,111 @@ namespace user { params, local_domain, injector, - HALF); + ONE); const auto sigma = params.template get("scales.sigma0"); const auto c_omp = params.template get("scales.skindepth0"); - const auto cs_drift_beta = math::sqrt(sigma) * c_omp / (width * overdensity); + const auto cs_drift_beta = math::sqrt(sigma) * c_omp / + (cs_width * cs_overdensity); const auto cs_drift_gamma = ONE / math::sqrt(ONE - SQR(cs_drift_beta)); const auto cs_drift_u = cs_drift_beta * cs_drift_gamma; - const auto cs_temp = HALF * sigma / overdensity; - // current layer #1 - auto edist_cs_1 = arch::Maxwellian(local_domain.mesh.metric, - local_domain.random_pool, - cs_temp, - cs_drift_u, - in::x3, - false); - const auto sdist_cs_1 = CurrentLayer(local_domain.mesh.metric, width, y1); - const auto inj_cs_1 = arch::NonUniformInjector( - edist_cs_1, - sdist_cs_1, - { 1, 2 }); - arch::InjectNonUniform(params, - local_domain, - inj_cs_1, - overdensity); - // current layer #2 - const auto edist_cs_2 = arch::Maxwellian(local_domain.mesh.metric, - local_domain.random_pool, - cs_temp, - -cs_drift_u, - in::x3, - false); - const auto sdist_cs_2 = CurrentLayer(local_domain.mesh.metric, width, y2); - const auto inj_cs_2 = arch::NonUniformInjector( - edist_cs_2, - sdist_cs_2, + const auto cs_temperature = HALF * sigma / cs_overdensity; + + // current layer + auto edist_cs = arch::Maxwellian(local_domain.mesh.metric, + local_domain.random_pool, + cs_temperature, + cs_drift_u, + in::x3, + false); + const auto sdist_cs = CurrentLayer(local_domain.mesh.metric, + cs_width, + cs_y); + const auto inj_cs = arch::NonUniformInjector( + edist_cs, + sdist_cs, { 1, 2 }); - arch::InjectNonUniform(params, - local_domain, - inj_cs_2, - overdensity); + arch::InjectNonUniform(params, + local_domain, + inj_cs, + cs_overdensity); + } + + void CustomPostStep(std::size_t step, long double time, Domain& domain) { + // // 0. define target density profile and box where it has to be + // reached + // // 1. compute density + // // 2. define spatial distribution + // // 3. define energy distribution + // // 4. define particle injector + // // 5. inject particles + // + // // step 0. + // // defining the regions of interest (lower and upper + // y-boundaries) boundaries_t box_upper, box_lower; const + // auto [xmin, xmax] = domain.mesh.extent(in::x1); const auto [ymin, + // ymax] = domain.mesh.extent(in::x2); box_upper.push_back({ xmin, + // xmax }); box_lower.push_back({ xmin, xmax }); + // + // box_upper.push_back({ ymax - dy, ymax }); + // box_lower.push_back({ ymin, ymin + dy }); + // + // if constexpr (M::Dim == Dim::_3D) { + // const auto [zmin, zmax] = domain.mesh.extent(in::x3); + // box_upper.push_back({ zmin, zmax }); + // box_lower.push_back({ zmin, zmax }); + // } + // + // const auto const_dens = ConstDens(); + // const auto inv_n0 = ONE / n0; + // + // // step 1 compute density + // auto scatter_bckp = Kokkos::Experimental::create_scatter_view( + // domain.fields.bckp); + // for (auto& prtl_spec : domain.species) { + // // clang-format off + // Kokkos::parallel_for( + // "ComputeMoments", + // prtl_spec.rangeActiveParticles(), + // kernel::ParticleMoments_kernel({}, + // scatter_bckp, 0, + // prtl_spec.i1, + // prtl_spec.i2, + // prtl_spec.i3, prtl_spec.dx1, + // prtl_spec.dx2, + // prtl_spec.dx3, prtl_spec.ux1, + // prtl_spec.ux2, + // prtl_spec.ux3, prtl_spec.phi, + // prtl_spec.weight, + // prtl_spec.tag, prtl_spec.mass(), + // prtl_spec.charge(), + // false, + // domain.mesh.metric, + // domain.mesh.flds_bc(), + // 0, inv_n0, 0)); + // } + // Kokkos::Experimental::contribute(domain.fields.bckp, scatter_bckp); + // + // + // //step 2. define spatial distribution + // // const auto spatial_dist = arch::Replenish>(domain.mesh.metric, domain.fields.bckp, 0, + // const_dens, ONE); + // const auto spatial_dist = spatial_dist_t(domain.mesh.metric, + // domain.fields.bckp,0,const_dens,ONE); + // //step 3. define energy distribution + // const auto energy_dist = arch::Maxwellian(domain.mesh.metric, + // domain.random_pool, up_temperature); + // //step 4. define particle injector + // const auto injector = arch::NonUniformInjector(energy_dist, spatial_dist, {1,2}); + // //step 5. inject particles + // arch::InjectNonUniform(params, domain, + // injector, ONE, false, box_upper); //upper boudary arch::InjectNonUniform(params, domain, injector, ONE, false, + // box_lower); //lower boundary + // + // } }; diff --git a/setups/wip/reconnection/reconnection.toml b/setups/wip/reconnection/reconnection.toml index fa7b049f4..db3dbde72 100644 --- a/setups/wip/reconnection/reconnection.toml +++ b/setups/wip/reconnection/reconnection.toml @@ -1,21 +1,21 @@ [simulation] - name = "reconnection" - engine = "srpic" + name = "reconnection" + engine = "srpic" runtime = 10.0 [grid] - resolution = [1024, 2048] - extent = [[-1.0, 1.0], [-2.0, 2.0]] + resolution = [1024, 512] + extent = [[-1.0, 1.0], [-0.5, 0.5]] [grid.metric] metric = "minkowski" [grid.boundaries] - fields = [["PERIODIC"], ["PERIODIC"]] - particles = [["PERIODIC"], ["PERIODIC"]] - + fields = [["MATCH", "MATCH"], ["MATCH", "MATCH"], ["PERIODIC"]] + particles = [["ABSORB", "ABSORB"], ["ABSORB", "ABSORB"], ["PERIODIC"]] + [scales] - larmor0 = 2e-4 + larmor0 = 2e-4 skindepth0 = 2e-3 [algorithms] @@ -25,28 +25,28 @@ CFL = 0.5 [particles] - ppc0 = 8.0 + ppc0 = 2.0 [[particles.species]] - label = "e-" - mass = 1.0 - charge = -1.0 + label = "e-" + mass = 1.0 + charge = -1.0 maxnpart = 1e7 [[particles.species]] - label = "e+" - mass = 1.0 - charge = 1.0 + label = "e+" + mass = 1.0 + charge = 1.0 maxnpart = 1e7 [setup] - Bmag = 1.0 - width = 0.01 - bg_temp = 1e-4 + Bmag = 1.0 + width = 0.01 + bg_temp = 1e-4 overdensity = 3.0 - + [output] - format = "hdf5" + format = "hdf5" interval_time = 0.1 [output.fields] diff --git a/src/global/arch/traits.h b/src/global/arch/traits.h index 65cc63cf8..127218090 100644 --- a/src/global/arch/traits.h +++ b/src/global/arch/traits.h @@ -103,6 +103,15 @@ namespace traits { template using match_fields_t = decltype(&T::MatchFields); + template + using match_fields_in_x1_t = decltype(&T::MatchFieldsInX1); + + template + using match_fields_in_x2_t = decltype(&T::MatchFieldsInX2); + + template + using match_fields_in_x3_t = decltype(&T::MatchFieldsInX3); + template using match_fields_const_t = decltype(&T::MatchFieldsConst); From b4a79b7b90f6188e21d101002b568d03fca12d44 Mon Sep 17 00:00:00 2001 From: hayk Date: Thu, 3 Apr 2025 16:56:24 -0400 Subject: [PATCH 588/773] const specifier added to mesh methods --- src/framework/domain/mesh.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/framework/domain/mesh.h b/src/framework/domain/mesh.h index 98fe68895..e4f2cba6d 100644 --- a/src/framework/domain/mesh.h +++ b/src/framework/domain/mesh.h @@ -74,7 +74,7 @@ namespace ntt { * @note pass Range::All to select the entire dimension */ [[nodiscard]] - auto Intersection(boundaries_t box) -> boundaries_t { + auto Intersection(boundaries_t box) const -> boundaries_t { raise::ErrorIf(box.size() != M::Dim, "Invalid box dimension", HERE); boundaries_t intersection; auto d = 0; @@ -109,7 +109,7 @@ namespace ntt { * @note pass Range::All to select the entire dimension */ [[nodiscard]] - auto Intersects(boundaries_t box) -> bool { + auto Intersects(boundaries_t box) const -> bool { raise::ErrorIf(box.size() != M::Dim, "Invalid box dimension", HERE); const auto intersection = Intersection(box); for (const auto& i : intersection) { @@ -131,8 +131,8 @@ namespace ntt { * @note indices are already shifted by N_GHOSTS (i.e. they start at N_GHOSTS not 0) */ [[nodiscard]] - auto ExtentToRange(boundaries_t box, - boundaries_t incl_ghosts) -> boundaries_t { + auto ExtentToRange(boundaries_t box, boundaries_t incl_ghosts) const + -> boundaries_t { raise::ErrorIf(box.size() != M::Dim, "Invalid box dimension", HERE); raise::ErrorIf(incl_ghosts.size() != M::Dim, "Invalid incl_ghosts dimension", From e879ca54c1ef5a71fdef139d26d4bf5765741f6c Mon Sep 17 00:00:00 2001 From: hayk Date: Fri, 4 Apr 2025 14:18:51 -0400 Subject: [PATCH 589/773] more general uniforminject class --- src/archetypes/particle_injector.h | 56 +++++++++++++++++++++++++----- 1 file changed, 47 insertions(+), 9 deletions(-) diff --git a/src/archetypes/particle_injector.h b/src/archetypes/particle_injector.h index a235ecf57..597f3caf8 100644 --- a/src/archetypes/particle_injector.h +++ b/src/archetypes/particle_injector.h @@ -60,17 +60,16 @@ namespace arch { ~UniformInjector() = default; - auto ComputeNumInject(const Domain& domain, - real_t ppc0, - real_t number_density, - const boundaries_t& box) const - -> std::tuple, array_t> { + auto DeduceInjectRegion(const Domain& domain, + const boundaries_t& box) const + -> std::tuple, array_t> { auto i_min = array_t { "i_min", M::Dim }; auto i_max = array_t { "i_max", M::Dim }; if (not domain.mesh.Intersects(box)) { - return { false, (npart_t)0, i_min, i_max }; + return { false, (ncells_t)0, i_min, i_max }; } + tuple_t range_min { 0 }; tuple_t range_max { 0 }; @@ -84,12 +83,11 @@ namespace arch { range_min[d] = intersect_range[d].first; range_max[d] = intersect_range[d].second; } + ncells_t ncells = 1; for (auto d = 0u; d < M::Dim; ++d) { ncells *= (range_max[d] - range_min[d]); } - const auto nparticles = static_cast( - (long double)(ppc0 * number_density * 0.5) * (long double)(ncells)); auto i_min_h = Kokkos::create_mirror_view(i_min); auto i_max_h = Kokkos::create_mirror_view(i_max); @@ -97,8 +95,30 @@ namespace arch { i_min_h(d) = (real_t)(range_min[d]); i_max_h(d) = (real_t)(range_max[d]); } + Kokkos::deep_copy(i_min, i_min_h); Kokkos::deep_copy(i_max, i_max_h); + return { true, ncells, i_min, i_max }; + } + + auto ComputeNumInject(const Domain& domain, + real_t ppc0, + real_t number_density, + const boundaries_t& box) const + -> std::tuple, array_t> { + const auto result = DeduceInjectRegion(domain, box); + const auto should_inject = std::get<0>(result); + auto i_min = std::get<2>(result); + auto i_max = std::get<3>(result); + + if (not shoult_inject) { + return { false, (npart_t)0, i_min, i_max }; + } + const auto ncells = std::get<1>(result); + + const auto nparticles = static_cast( + (long double)(ppc0 * number_density * 0.5) * (long double)(ncells)); + return { true, nparticles, i_min, i_max }; } }; @@ -124,7 +144,24 @@ namespace arch { real_t number_density, const boundaries_t& box) const -> std::tuple, array_t> { - ... + const auto result = DeduceInjectRegion(domain, box); + const auto should_inject = std::get<0>(result); + auto i_min = std::get<2>(result); + auto i_max = std::get<3>(result); + + if (not shoult_inject) { + return { false, (npart_t)0, i_min, i_max }; + } + const auto ncells = std::get<1>(result); + + // @TODO + const auto computed_avg_density = ONE; + + const auto nparticles = static_cast( + (long double)(ppc0 * (number_density - computed_avg_density) * 0.5) * + (long double)(ncells)); + + return { true, nparticles, i_min, i_max }; } }; @@ -304,6 +341,7 @@ namespace arch { * @param injector Uniform injector object * @param number_density Total number density (in units of n0) * @param use_weights Use weights + * @param box Region to inject the particles in global coords * @tparam S Simulation engine type * @tparam M Metric type * @tparam I Injector type From 0feb1dba08a74c31a876fb9fe0b54b3bf449df2b Mon Sep 17 00:00:00 2001 From: hayk Date: Thu, 3 Apr 2025 16:54:56 -0400 Subject: [PATCH 590/773] generalized uniform injector --- src/archetypes/particle_injector.h | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/archetypes/particle_injector.h b/src/archetypes/particle_injector.h index 597f3caf8..8b38addaf 100644 --- a/src/archetypes/particle_injector.h +++ b/src/archetypes/particle_injector.h @@ -165,6 +165,31 @@ namespace arch { } }; + template class ED> + struct KeepConstantInjector : UniformInjector { + using energy_dist_t = ED; + using UniformInjector::D; + using UniformInjector::C; + + const boundaries_t probe_box; + + KeepConstantInjector(const energy_dist_t& energy_dist, + const std::pair& species, + boundaries_t probe_box = {}) + : UniformInjector(energy_dist, species) + , probe_box { probe_box } {} + + ~KeepConstantInjector() = default; + + auto ComputeNumInject(const Domain& domain, + real_t ppc0, + real_t number_density, + const boundaries_t& box) const + -> std::tuple, array_t> { + // ... + } + }; + template class ED, From 85ae1d8c79d1a5c7bf3de28d7b0a491f594b08a4 Mon Sep 17 00:00:00 2001 From: hayk Date: Sat, 5 Apr 2025 07:58:58 -0400 Subject: [PATCH 591/773] keepconst injector ready (untested) --- src/archetypes/particle_injector.h | 129 +++++++++++++++++++++++------ src/kernels/particle_moments.hpp | 2 - src/kernels/utils.hpp | 65 +++++++++++++++ 3 files changed, 170 insertions(+), 26 deletions(-) create mode 100644 src/kernels/utils.hpp diff --git a/src/archetypes/particle_injector.h b/src/archetypes/particle_injector.h index 597f3caf8..48df77351 100644 --- a/src/archetypes/particle_injector.h +++ b/src/archetypes/particle_injector.h @@ -28,9 +28,15 @@ #include "framework/domain/metadomain.h" #include "kernels/injectors.hpp" +#include "kernels/particle_moments.hpp" +#include "kernels/utils.hpp" #include +#if defined(MPI_ENABLED) + #include +#endif + #include #include #include @@ -101,21 +107,21 @@ namespace arch { return { true, ncells, i_min, i_max }; } - auto ComputeNumInject(const Domain& domain, - real_t ppc0, + auto ComputeNumInject(const SimulationParams& params, + const Domain& domain, real_t number_density, const boundaries_t& box) const -> std::tuple, array_t> { - const auto result = DeduceInjectRegion(domain, box); - const auto should_inject = std::get<0>(result); - auto i_min = std::get<2>(result); - auto i_max = std::get<3>(result); + const auto result = DeduceInjectRegion(domain, box); + const auto i_min = std::get<2>(result); + const auto i_max = std::get<3>(result); - if (not shoult_inject) { + if (not std::get<0>(result)) { return { false, (npart_t)0, i_min, i_max }; } const auto ncells = std::get<1>(result); + const auto ppc0 = params.template get("particles.ppc0"); const auto nparticles = static_cast( (long double)(ppc0 * number_density * 0.5) * (long double)(ncells)); @@ -129,34 +135,110 @@ namespace arch { using UniformInjector::D; using UniformInjector::C; - const boundaries_t probe_box; + boundaries_t probe_box; KeepConstantInjector(const energy_dist_t& energy_dist, const std::pair& species, - boundaries_t probe_box = {}) - : UniformInjector(energy_dist, species) - , probe_box { probe_box } {} + boundaries_t box = {}) + : UniformInjector { energy_dist, species } { + for (auto d { 0u }; d < M::Dim; ++d) { + if (d < box.size()) { + probe_box.push_back({ box[d].first, box[d].second }); + } else { + probe_box.push_back(Range::All); + } + } + } ~KeepConstantInjector() = default; - auto ComputeNumInject(const Domain& domain, - real_t ppc0, + auto ComputeAvgDensity(const SimulationParams& params, + const Domain& domain, + boundaries_t box) const -> real_t { + const auto use_weights = params.template get( + "particles.use_weights"); + const auto ni2 = domain.mesh.n_active(in::x2); + const auto inv_n0 = ONE / params.template get("scales.n0"); + + auto scatter_buff = Kokkos::Experimental::create_scatter_view( + domain.fields.buff); + + for (const auto& sp : { this->species.first, this->species.second }) { + raise::ErrorIf(sp >= domain.species.size(), + "Species index out of bounds", + HERE); + const auto& prtl_spec = domain.species[sp - 1]; + Kokkos::deep_copy(domain.fields.buff, ZERO); + // clang-format off + Kokkos::parallel_for( + "ComputeMoments", + prtl_spec.rangeActiveParticles(), + kernel::ParticleMoments_kernel({}, scatter_buff, 0, + prtl_spec.i1, prtl_spec.i2, prtl_spec.i3, + prtl_spec.dx1, prtl_spec.dx2, prtl_spec.dx3, + prtl_spec.ux1, prtl_spec.ux2, prtl_spec.ux3, + prtl_spec.phi, prtl_spec.weight, prtl_spec.tag, + prtl_spec.mass(), prtl_spec.charge(), + use_weights, + domain.mesh.metric, domain.mesh.flds_bc(), + ni2, inv_n0, 0)); + // clang-format on + } + Kokkos::Experimental::contribute(domain.fields.buff, scatter_buff); + + real_t dens { ZERO }; + + const auto result = DeduceInjectRegion(domain, box); + const auto should_probe = std::get<0>(result); + const auto ncells = std::get<1>(result); + const auto i_min = std::get<2>(result); + const auto i_max = std::get<3>(result); + + if (should_probe) { + range_t probe_range = CreateRangePolicy(i_min, i_max); + Kokkos::parallel_reduce( + "AvgDensity", + probe_range, + kernel::ComputeSum_kernel(domain.fields.buff, 0), + dens); + } +#if defined(MPI_ENABLED) + real_t tot_dens { ZERO }; + ncells_t tot_ncells { 0 }; + MPI_Allreduce(dens, &tot_dens, 1, mpi::get_type(), MPI_SUM, MPI_COMM_WORLD); + MPI_Allreduce(ncells, + &tot_ncells, + 1, + mpi::get_type(), + MPI_SUM, + MPI_COMM_WORLD); + dens = tot_dens; + ncells = tot_ncells; +#endif + if (ncells > 0) { + return dens / (real_t)(ncells); + } else { + return ZERO; + } + } + + auto ComputeNumInject(const SimulationParams& params, + const Domain& domain, real_t number_density, const boundaries_t& box) const -> std::tuple, array_t> { - const auto result = DeduceInjectRegion(domain, box); - const auto should_inject = std::get<0>(result); - auto i_min = std::get<2>(result); - auto i_max = std::get<3>(result); + const auto computed_avg_density = ComputeAvgDensity(params, domain); + + const auto result = DeduceInjectRegion(domain, box); + const auto i_min = std::get<2>(result); + const auto i_max = std::get<3>(result); - if (not shoult_inject) { + if (not std::get<0>(result)) { return { false, (npart_t)0, i_min, i_max }; } const auto ncells = std::get<1>(result); - // @TODO - const auto computed_avg_density = ONE; - + const auto ppc0 = params.template get("particles.ppc0"); const auto nparticles = static_cast( (long double)(ppc0 * (number_density - computed_avg_density) * 0.5) * (long double)(ncells)); @@ -380,9 +462,8 @@ namespace arch { nonempty_box.push_back(Range::All); } } - auto ppc0 = params.template get("particles.ppc0"); - const auto result = injector.ComputeNumInject(domain, - ppc0, + const auto result = injector.ComputeNumInject(params, + domain, number_density, nonempty_box); if (not std::get<0>(result)) { diff --git a/src/kernels/particle_moments.hpp b/src/kernels/particle_moments.hpp index 18540a771..070a85062 100644 --- a/src/kernels/particle_moments.hpp +++ b/src/kernels/particle_moments.hpp @@ -18,8 +18,6 @@ #include "utils/error.h" #include "utils/numeric.h" -#include - #include namespace kernel { diff --git a/src/kernels/utils.hpp b/src/kernels/utils.hpp new file mode 100644 index 000000000..307ff7290 --- /dev/null +++ b/src/kernels/utils.hpp @@ -0,0 +1,65 @@ +/** + * @file kernels/utils.hpp + * @brief Commonly used generic kernels + * @implements + * - kernel::ComputeSum_kernel<> + * @namespaces: + * - kernel:: + */ + +#ifndef KERNELS_UTILS_HPP +#define KERNELS_UTILS_HPP + +#include "global.h" + +#include "arch/kokkos_aliases.h" +#include "utils/error.h" + +namespace kernel { + + template + class ComputeSum_kernel { + const ndfield_t buff; + const unsigned short buff_idx; + + public: + ComputeSum_kernel(const ndfield_t& buff, unsigned short buff_idx) + : buff { buff } + , buff_idx { buff_idx } { + raise::ErrorIf(buff_idx >= N, "Invalid component index", HERE); + } + + Inline void operator()(index_t i1, real_t& lsum) const { + if constexpr (D == Dim::_1D) { + lsum += buff(i1, buff_idx); + } else { + raise::KernelError( + HERE, + "1D implementation of ComputeSum_kernel called for non-1D"); + } + } + + Inline void operator()(index_t i1, index_t i2, real_t& lsum) const { + if (D == Dim::_2D) { + lsum += buff(i1, i2, buff_idx); + } else { + raise::KernelError( + HERE, + "2D implementation of ComputeSum_kernel called for non-2D"); + } + } + + Inline void operator()(index_t i1, index_t i2, index_t i3, real_t& lsum) const { + if (D == Dim::_3D) { + lsum += buff(i1, i2, i3, buff_idx); + } else { + raise::KernelError( + HERE, + "3D implementation of ComputeSum_kernel called for non-3D"); + } + } + }; + +} // namespace kernel + +#endif // KERNELS_UTILS_HPP From ddb706f1d13205213e5f9a654f1d52ae784f34b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20B=C3=B6ss?= Date: Sun, 6 Apr 2025 16:23:26 -0500 Subject: [PATCH 592/773] removed redundant piston distribution --- src/archetypes/spatial_dist.h | 25 ------------------------- 1 file changed, 25 deletions(-) diff --git a/src/archetypes/spatial_dist.h b/src/archetypes/spatial_dist.h index ad9404ea3..d036c0166 100644 --- a/src/archetypes/spatial_dist.h +++ b/src/archetypes/spatial_dist.h @@ -4,7 +4,6 @@ * @implements * - arch::SpatialDistribution<> * - arch::Uniform<> : arch::SpatialDistribution<> - * - arch::Piston<> : arch::SpatialDistribution<> * - arch::Replenish<> : arch::SpatialDistribution<> * @namespace * - arch:: @@ -50,30 +49,6 @@ namespace arch { } }; - template - struct Piston : public arch::SpatialDistribution { - Piston(const M& metric, real_t xmin, real_t xmax, in piston_direction = in::x1) - : arch::SpatialDistribution { metric } - , xmin { xmin } - , xmax { xmax } - , piston_direction { piston_direction } {} - - Inline auto operator()(const coord_t& x_Ph) const -> real_t override { - // dimentsion to fill - const auto fill_dim = static_cast(piston_direction); - - if (x_Ph[fill_dim] < xmin || x_Ph[fill_dim] > xmax) { - return ZERO; - } else { - return ONE; - } - } - - private: - real_t xmin, xmax; - in piston_direction; - }; - template struct Replenish : public SpatialDistribution { using SpatialDistribution::metric; From 895ead3dabb5291d350539fc8ab92f2b7d4cde7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20B=C3=B6ss?= Date: Sun, 6 Apr 2025 16:24:31 -0500 Subject: [PATCH 593/773] updated injection to new UniformInjector behavior and use global domain for box definition --- setups/srpic/shock/pgen.hpp | 101 ++++++++++++------------------------ 1 file changed, 32 insertions(+), 69 deletions(-) diff --git a/setups/srpic/shock/pgen.hpp b/setups/srpic/shock/pgen.hpp index ad260bda0..33e628a0a 100644 --- a/setups/srpic/shock/pgen.hpp +++ b/setups/srpic/shock/pgen.hpp @@ -80,6 +80,8 @@ namespace user { using arch::ProblemGenerator::C; using arch::ProblemGenerator::params; + // domain properties + const real_t domain_xmin, domain_xmax; // gas properties const real_t drift_ux, temperature, filling_fraction; // injector properties @@ -91,6 +93,8 @@ namespace user { inline PGen(const SimulationParams& p, const Metadomain& m) : arch::ProblemGenerator { p } + , domain_xmin { m.mesh.extent(in::x1).first } + , domain_xmax { m.mesh.extent(in::x1).second } , drift_ux { p.template get("setup.drift_ux") } , temperature { p.template get("setup.temperature") } , Bmag { p.template get("setup.Bmag", ZERO) } @@ -131,10 +135,8 @@ namespace user { inline void InitPrtls(Domain& local_domain) { // minimum and maximum position of particles - real_t xg_min = local_domain.mesh.extent(in::x1).first; - real_t xg_max = local_domain.mesh.extent(in::x1).first + - filling_fraction * (local_domain.mesh.extent(in::x1).second - - local_domain.mesh.extent(in::x1).first); + real_t xg_min = domain_xmin; + real_t xg_max = domain_xmin + filling_fraction * (domain_xmax - domain_xmin); // define box to inject into boundaries_t box; @@ -149,13 +151,6 @@ namespace user { } } - // spatial distribution of the particles - // -> hack to use the uniform distribution in NonUniformInjector - const auto spatial_dist = arch::Piston(local_domain.mesh.metric, - xg_min, - xg_max, - in::x1); - // energy distribution of the particles const auto energy_dist = arch::Maxwellian(local_domain.mesh.metric, local_domain.random_pool, @@ -163,12 +158,13 @@ namespace user { -drift_ux, in::x1); - const auto injector = arch::NonUniformInjector( + // we want to set up a uniform density distribution + const auto injector = arch::UniformInjector( energy_dist, - spatial_dist, { 1, 2 }); - arch::InjectNonUniform>( + // inject uniformly within the defined box + arch::InjectUniform>( params, local_domain, injector, @@ -185,18 +181,17 @@ namespace user { } // initial position of injector - const auto x_init = domain.mesh.extent(in::x1).first + - filling_fraction * (domain.mesh.extent(in::x1).second - - domain.mesh.extent(in::x1).first); + const auto x_init = domain_xmin + + filling_fraction * (domain_xmax - domain_xmin); // check if injector is supposed to start moving already - const auto dt_inj = time - injection_start > ZERO ? time - injection_start - : ZERO; + const auto dt_inj = time - injection_start > ZERO ? + time - injection_start : ZERO; // compute the position of the injector auto xmax = x_init + injector_velocity * (dt_inj + dt); - if (xmax >= domain.mesh.extent(in::x1).second) { - xmax = domain.mesh.extent(in::x1).second; + if (xmax >= domain_xmax) { + xmax = domain_xmax; } // define box to inject into @@ -219,11 +214,11 @@ namespace user { } auto fields_box = box; // check if the box is still inside the domain - if (xmax + injection_frequency * dt < domain.mesh.extent(in::x1).second) { + if (xmax + injection_frequency * dt < domain_xmax) { fields_box[0].second += injection_frequency * dt; - } else { + } else { // if right side of the box is outside of the domain -> truncate box - fields_box[0].second = domain.mesh.extent(in::x1).second; + fields_box[0].second = domain_xmax; } const auto extent = domain.mesh.ExtentToRange(fields_box, incl_ghosts); tuple_t x_min { 0 }, x_max { 0 }; @@ -239,7 +234,6 @@ namespace user { init_flds, domain.mesh.metric }); - /* tag particles inside the injection zone as dead */ @@ -271,7 +265,7 @@ namespace user { } /* - Inject piston of fresh plasma + Inject slab of fresh plasma */ // same maxwell distribution as above @@ -280,53 +274,22 @@ namespace user { temperature, -drift_ux, in::x1); - // spatial distribution of the particles - // -> hack to use the uniform distribution in NonUniformInjector - const auto spatial_dist = arch::Piston(domain.mesh.metric, - box[0].first, - box[0].second, - in::x1); - - // inject piston of fresh plasma - const auto injector = arch::NonUniformInjector( + + // we want to set up a uniform density distribution + const auto injector = arch::UniformInjector( energy_dist, - spatial_dist, { 1, 2 }); - // inject non-uniformly within the defined box - arch::InjectNonUniform(params, - domain, - injector, - ONE, - false, - box); - - /* - I thought this option would be better, but I can't get it to work - */ - - // const auto spatial_dist = arch::Replenish(domain.mesh.metric, - // domain.fields.bckp, - // box, - // TargetDensity, - // 1.0); - - // const auto injector = arch::NonUniformInjector( - // energy_dist, - // spatial_dist, - // {1, 2}); - - // const auto injector = arch::MovingInjector { - // domain.mesh.metric, - // domain.fields.bckp, - // energy_dist, - // box[0].first, - // box[0].second, - // 1.0, - // { 1, 2 } - // }; + // inject uniformly within the defined box + arch::InjectUniform>( + params, + domain, + injector, + 1.0, // target density + false, // no weights + box); } + }; } // namespace user From 877f459c52cfd204abc2c842f3753b7656bd1953 Mon Sep 17 00:00:00 2001 From: hayk Date: Sun, 6 Apr 2025 21:01:42 -0400 Subject: [PATCH 594/773] minor problem with flags --- CMakeLists.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f83e6637c..bee7a3a7c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -57,8 +57,7 @@ if(${DEBUG} STREQUAL "OFF") set(CMAKE_BUILD_TYPE Release CACHE STRING "CMake build type") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DNDEBUG " - "-Wno-unused-local-typedefs -Wno-unknown-cuda-version") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DNDEBUG") else() set(CMAKE_BUILD_TYPE Debug From 45a1df0bbd8f6cb49f55a2ae0800e39603da1405 Mon Sep 17 00:00:00 2001 From: hayk Date: Sun, 6 Apr 2025 21:02:14 -0400 Subject: [PATCH 595/773] i_edge passed in conduct BC --- src/archetypes/particle_injector.h | 3 +- src/engines/srpic.hpp | 72 +++++++++++++++++++----------- 2 files changed, 48 insertions(+), 27 deletions(-) diff --git a/src/archetypes/particle_injector.h b/src/archetypes/particle_injector.h index 48df77351..62cbc264c 100644 --- a/src/archetypes/particle_injector.h +++ b/src/archetypes/particle_injector.h @@ -163,7 +163,8 @@ namespace arch { auto scatter_buff = Kokkos::Experimental::create_scatter_view( domain.fields.buff); - for (const auto& sp : { this->species.first, this->species.second }) { + for (const auto& sp : std::vector { this->species.first, + this->species.second }) { raise::ErrorIf(sp >= domain.species.size(), "Species index out of bounds", HERE); diff --git a/src/engines/srpic.hpp b/src/engines/srpic.hpp index c38fe2261..8c21fed05 100644 --- a/src/engines/srpic.hpp +++ b/src/engines/srpic.hpp @@ -928,6 +928,12 @@ namespace ntt { } else { raise::Error("Invalid dimension", HERE); } + std::size_t i_edge; + if (sign > 0) { + i_edge = domain.mesh.i_max(dim); + } else { + i_edge = domain.mesh.i_min(dim); + } if (dim == in::x1) { if (sign > 0) { @@ -936,6 +942,7 @@ namespace ntt { range, kernel::bc::ConductorBoundaries_kernel( domain.fields.em, + i_edge, tags)); } else { Kokkos::parallel_for( @@ -943,39 +950,52 @@ namespace ntt { range, kernel::bc::ConductorBoundaries_kernel( domain.fields.em, + i_edge, tags)); } } else if (dim == in::x2) { - if (sign > 0) { - Kokkos::parallel_for( - "ConductorFields", - range, - kernel::bc::ConductorBoundaries_kernel( - domain.fields.em, - tags)); + if constexpr (M::Dim == Dim::_2D or M::Dim == Dim::_3D) { + if (sign > 0) { + Kokkos::parallel_for( + "ConductorFields", + range, + kernel::bc::ConductorBoundaries_kernel( + domain.fields.em, + i_edge, + tags)); + } else { + Kokkos::parallel_for( + "ConductorFields", + range, + kernel::bc::ConductorBoundaries_kernel( + domain.fields.em, + i_edge, + tags)); + } } else { - Kokkos::parallel_for( - "ConductorFields", - range, - kernel::bc::ConductorBoundaries_kernel( - domain.fields.em, - tags)); + raise::Error("Invalid dimension", HERE); } } else { - if (sign > 0) { - Kokkos::parallel_for( - "ConductorFields", - range, - kernel::bc::ConductorBoundaries_kernel( - domain.fields.em, - tags)); + if constexpr (M::Dim == Dim::_3D) { + if (sign > 0) { + Kokkos::parallel_for( + "ConductorFields", + range, + kernel::bc::ConductorBoundaries_kernel( + domain.fields.em, + i_edge, + tags)); + } else { + Kokkos::parallel_for( + "ConductorFields", + range, + kernel::bc::ConductorBoundaries_kernel( + domain.fields.em, + i_edge, + tags)); + } } else { - Kokkos::parallel_for( - "ConductorFields", - range, - kernel::bc::ConductorBoundaries_kernel( - domain.fields.em, - tags)); + raise::Error("Invalid dimension", HERE); } } } From 8fb4b9f0861f279f8930ff944b05f1a078c3e588 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20B=C3=B6ss?= Date: Mon, 7 Apr 2025 10:08:03 -0500 Subject: [PATCH 596/773] fix global extent access --- setups/srpic/shock/pgen.hpp | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/setups/srpic/shock/pgen.hpp b/setups/srpic/shock/pgen.hpp index 33e628a0a..99b3ca11e 100644 --- a/setups/srpic/shock/pgen.hpp +++ b/setups/srpic/shock/pgen.hpp @@ -81,7 +81,7 @@ namespace user { using arch::ProblemGenerator::params; // domain properties - const real_t domain_xmin, domain_xmax; + const real_t global_xmin, global_xmax; // gas properties const real_t drift_ux, temperature, filling_fraction; // injector properties @@ -91,10 +91,10 @@ namespace user { real_t Btheta, Bphi, Bmag; InitFields init_flds; - inline PGen(const SimulationParams& p, const Metadomain& m) + inline PGen(const SimulationParams& p, const Metadomain& global_domain) : arch::ProblemGenerator { p } - , domain_xmin { m.mesh.extent(in::x1).first } - , domain_xmax { m.mesh.extent(in::x1).second } + , global_xmin { global_domain.mesh().extent(in::x1).first } + , global_xmax { global_domain.mesh().extent(in::x1).second } , drift_ux { p.template get("setup.drift_ux") } , temperature { p.template get("setup.temperature") } , Bmag { p.template get("setup.Bmag", ZERO) } @@ -135,8 +135,8 @@ namespace user { inline void InitPrtls(Domain& local_domain) { // minimum and maximum position of particles - real_t xg_min = domain_xmin; - real_t xg_max = domain_xmin + filling_fraction * (domain_xmax - domain_xmin); + real_t xg_min = global_xmin; + real_t xg_max = global_xmin + filling_fraction * (global_xmax - global_xmin); // define box to inject into boundaries_t box; @@ -181,8 +181,8 @@ namespace user { } // initial position of injector - const auto x_init = domain_xmin + - filling_fraction * (domain_xmax - domain_xmin); + const auto x_init = global_xmin + + filling_fraction * (global_xmax - global_xmin); // check if injector is supposed to start moving already const auto dt_inj = time - injection_start > ZERO ? @@ -190,8 +190,8 @@ namespace user { // compute the position of the injector auto xmax = x_init + injector_velocity * (dt_inj + dt); - if (xmax >= domain_xmax) { - xmax = domain_xmax; + if (xmax >= global_xmax) { + xmax = global_xmax; } // define box to inject into @@ -214,11 +214,11 @@ namespace user { } auto fields_box = box; // check if the box is still inside the domain - if (xmax + injection_frequency * dt < domain_xmax) { + if (xmax + injection_frequency * dt < global_xmax) { fields_box[0].second += injection_frequency * dt; } else { // if right side of the box is outside of the domain -> truncate box - fields_box[0].second = domain_xmax; + fields_box[0].second = global_xmax; } const auto extent = domain.mesh.ExtentToRange(fields_box, incl_ghosts); tuple_t x_min { 0 }, x_max { 0 }; From 8e0747b477e281c2ab4b78e126393af9028eb48e Mon Sep 17 00:00:00 2001 From: hayk Date: Mon, 7 Apr 2025 11:46:30 -0400 Subject: [PATCH 597/773] mpi fixed --- src/archetypes/particle_injector.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/archetypes/particle_injector.h b/src/archetypes/particle_injector.h index 62cbc264c..39c588519 100644 --- a/src/archetypes/particle_injector.h +++ b/src/archetypes/particle_injector.h @@ -206,8 +206,8 @@ namespace arch { #if defined(MPI_ENABLED) real_t tot_dens { ZERO }; ncells_t tot_ncells { 0 }; - MPI_Allreduce(dens, &tot_dens, 1, mpi::get_type(), MPI_SUM, MPI_COMM_WORLD); - MPI_Allreduce(ncells, + MPI_Allreduce(&dens, &tot_dens, 1, mpi::get_type(), MPI_SUM, MPI_COMM_WORLD); + MPI_Allreduce(&ncells, &tot_ncells, 1, mpi::get_type(), From 2e3ae6bb371fb0c6b30700c28b24b17005132137 Mon Sep 17 00:00:00 2001 From: hayk Date: Mon, 7 Apr 2025 11:46:42 -0400 Subject: [PATCH 598/773] safeguards for Dim --- src/engines/srpic.hpp | 94 +++++++++++++++++++++++-------------------- 1 file changed, 50 insertions(+), 44 deletions(-) diff --git a/src/engines/srpic.hpp b/src/engines/srpic.hpp index 8c21fed05..a25df3fab 100644 --- a/src/engines/srpic.hpp +++ b/src/engines/srpic.hpp @@ -685,52 +685,58 @@ namespace ntt { range_max); } } else if (dim == in::x2) { - if constexpr ( - traits::has_member::value) { - auto match_fields = m_pgen.MatchFields(time); - call_match_fields(domain.fields.em, - match_fields, - domain.mesh.metric, - xg_edge, - ds, - tags, - range_min, - range_max); - } else if constexpr ( - traits::has_member::value) { - auto match_fields = m_pgen.MatchFieldsInX2(time); - call_match_fields(domain.fields.em, - match_fields, - domain.mesh.metric, - xg_edge, - ds, - tags, - range_min, - range_max); + if constexpr (M::Dim == Dim::_2D or M::Dim == Dim::_3D) { + if constexpr ( + traits::has_member::value) { + auto match_fields = m_pgen.MatchFields(time); + call_match_fields(domain.fields.em, + match_fields, + domain.mesh.metric, + xg_edge, + ds, + tags, + range_min, + range_max); + } else if constexpr ( + traits::has_member::value) { + auto match_fields = m_pgen.MatchFieldsInX2(time); + call_match_fields(domain.fields.em, + match_fields, + domain.mesh.metric, + xg_edge, + ds, + tags, + range_min, + range_max); + } + } else { + raise::Error("Invalid dimension", HERE); } } else if (dim == in::x3) { - if constexpr ( - traits::has_member::value) { - auto match_fields = m_pgen.MatchFields(time); - call_match_fields(domain.fields.em, - match_fields, - domain.mesh.metric, - xg_edge, - ds, - tags, - range_min, - range_max); - } else if constexpr ( - traits::has_member::value) { - auto match_fields = m_pgen.MatchFieldsInX3(time); - call_match_fields(domain.fields.em, - match_fields, - domain.mesh.metric, - xg_edge, - ds, - tags, - range_min, - range_max); + if constexpr (M::Dim == Dim::_3D) { + if constexpr ( + traits::has_member::value) { + auto match_fields = m_pgen.MatchFields(time); + call_match_fields(domain.fields.em, + match_fields, + domain.mesh.metric, + xg_edge, + ds, + tags, + range_min, + range_max); + } else if constexpr ( + traits::has_member::value) { + auto match_fields = m_pgen.MatchFieldsInX3(time); + call_match_fields(domain.fields.em, + match_fields, + domain.mesh.metric, + xg_edge, + ds, + tags, + range_min, + range_max); + } } } else { raise::Error("Invalid dimension", HERE); From b2322653d05a9e8ce1a8ad421ba4bb5afdd440fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20B=C3=B6ss?= Date: Mon, 7 Apr 2025 12:23:06 -0500 Subject: [PATCH 599/773] fix bug in reading BC selection --- src/framework/parameters.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/framework/parameters.cpp b/src/framework/parameters.cpp index cd6edc929..79f8e333e 100644 --- a/src/framework/parameters.cpp +++ b/src/framework/parameters.cpp @@ -751,7 +751,7 @@ namespace ntt { for (auto d = 0u; d < dim; ++d) { ds_array.push_back({ ds, ds }); } - } catch (const toml::type_error&) { + } catch (...) { try { const auto ds = toml::find>>( toml_data, From 26ea9a3806d96f565d170b41af12dbbd72cf8289 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Tue, 8 Apr 2025 18:47:54 -0400 Subject: [PATCH 600/773] bug in polar_area qks --- src/metrics/qkerr_schild.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/metrics/qkerr_schild.h b/src/metrics/qkerr_schild.h index e3d849952..5e6a8c977 100644 --- a/src/metrics/qkerr_schild.h +++ b/src/metrics/qkerr_schild.h @@ -480,7 +480,7 @@ namespace metric { math::sqrt( ONE + TWO * (r0 + math::exp(x1 * dchi + chi_min)) / (SQR(r0 + math::exp(x1 * dchi + chi_min)) + SQR(a))) * - (ONE - math::cos(eta2theta(HALF * deta + eta_min))); + (ONE - math::cos(eta2theta(HALF * deta))); } /** From f4c9a6cd59769d03712c42feb7bba2e9ca44e193 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Tue, 8 Apr 2025 18:48:55 -0400 Subject: [PATCH 601/773] axis boundary conditions now match SRPIC --- src/kernels/fields_bcs.hpp | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/src/kernels/fields_bcs.hpp b/src/kernels/fields_bcs.hpp index 6c3bd2760..30009b7b9 100644 --- a/src/kernels/fields_bcs.hpp +++ b/src/kernels/fields_bcs.hpp @@ -565,14 +565,36 @@ namespace kernel::bc { AxisBoundariesGR_kernel(ndfield_t Fld, std::size_t i_edge, BCTags tags) : Fld { Fld } - , i_edge { i_edge } + // , i_edge { i_edge } + , i_edge { P ? (i_edge + 1) : i_edge } , setE { tags & BC::Ex1 or tags & BC::Ex2 or tags & BC::Ex3 } , setB { tags & BC::Bx1 or tags & BC::Bx2 or tags & BC::Bx3 } {} Inline void operator()(index_t i1) const { if constexpr (D == Dim::_2D) { - if (setB) { - Fld(i1, i_edge, em::bx2) = ZERO; + // if (setB) { + // Fld(i1, i_edge, em::bx2) = ZERO; + // } + if constexpr (not P) { + if (setE) { + Fld(i1, i_edge - 1, em::ex2) = -Fld(i1, i_edge, em::ex2); + Fld(i1, i_edge, em::ex3) = ZERO; + } + if (setB) { + Fld(i1, i_edge - 1, em::bx1) = Fld(i1, i_edge, em::bx1); + Fld(i1, i_edge, em::bx2) = ZERO; + Fld(i1, i_edge - 1, em::bx3) = Fld(i1, i_edge, em::bx3); + } + } else { + if (setE) { + Fld(i1, i_edge + 1, em::ex2) = -Fld(i1, i_edge, em::ex2); + Fld(i1, i_edge + 1, em::ex3) = ZERO; + } + if (setB) { + Fld(i1, i_edge + 1, em::bx1) = Fld(i1, i_edge, em::bx1); + Fld(i1, i_edge + 1, em::bx2) = ZERO; + Fld(i1, i_edge + 1, em::bx3) = Fld(i1, i_edge, em::bx3); + } } } else { raise::KernelError(HERE, "AxisBoundariesGR_kernel: D != 2"); From 0ee06ce516691783e22527ec296231cf56e617f9 Mon Sep 17 00:00:00 2001 From: haykh Date: Wed, 9 Apr 2025 07:43:26 -0400 Subject: [PATCH 602/773] new deposit scheme --- src/framework/parameters.cpp | 16 +- src/kernels/currents_deposit.hpp | 460 +++++++++++++++---------------- 2 files changed, 220 insertions(+), 256 deletions(-) diff --git a/src/framework/parameters.cpp b/src/framework/parameters.cpp index 79f8e333e..e4a40522b 100644 --- a/src/framework/parameters.cpp +++ b/src/framework/parameters.cpp @@ -31,10 +31,10 @@ namespace ntt { template - auto get_dx0_V0(const std::vector& resolution, - const boundaries_t& extent, - const std::map& params) - -> std::pair { + auto get_dx0_V0( + const std::vector& resolution, + const boundaries_t& extent, + const std::map& params) -> std::pair { const auto metric = M(resolution, extent, params); const auto dx0 = metric.dxMin(); coord_t x_corner { ZERO }; @@ -738,13 +738,7 @@ namespace ntt { for (const auto& e : extent_pairwise) { min_extent = std::min(min_extent, e.second - e.first); } - const auto default_ds = min_extent * defaults::bc::match::ds_frac; - std::size_t n_match_bcs { 0u }; - for (const auto& bcs : flds_bc_pairwise) { - if (bcs.first == FldsBC::MATCH or bcs.second == FldsBC::MATCH) { - n_match_bcs += 1; - } - } + const auto default_ds = min_extent * defaults::bc::match::ds_frac; boundaries_t ds_array; try { auto ds = toml::find(toml_data, "grid", "boundaries", "match", "ds"); diff --git a/src/kernels/currents_deposit.hpp b/src/kernels/currents_deposit.hpp index ca9a94878..98d00a9b0 100644 --- a/src/kernels/currents_deposit.hpp +++ b/src/kernels/currents_deposit.hpp @@ -67,8 +67,8 @@ namespace kernel { const array_t& weight, const array_t& tag, const M& metric, - const real_t& charge, - const real_t& dt) + real_t charge, + real_t dt) : J { scatter_cur } , i1 { i1 } , i2 { i2 } @@ -100,45 +100,70 @@ namespace kernel { if (tag(p) == ParticleTag::dead) { return; } - // _f = final, _i = initial - tuple_t Ip_f, Ip_i; - coord_t xp_f, xp_i, xp_r; + // recover particle velocity to deposit in unsimulated direction vec_t vp { ZERO }; + { + coord_t xp { ZERO }; + if constexpr (D == Dim::_1D) { + xp[0] = i_di_to_Xi(i1(p), dx1(p)); + } else if constexpr (D == Dim::_2D) { + if constexpr (M::PrtlDim == Dim::_3D) { + xp[0] = i_di_to_Xi(i1(p), dx1(p)); + xp[1] = i_di_to_Xi(i2(p), dx2(p)); + xp[2] = phi(p); + } else { + xp[0] = i_di_to_Xi(i1(p), dx1(p)); + xp[1] = i_di_to_Xi(i2(p), dx2(p)); + } + } else { + xp[0] = i_di_to_Xi(i1(p), dx1(p)); + xp[1] = i_di_to_Xi(i2(p), dx2(p)); + xp[2] = i_di_to_Xi(i3(p), dx3(p)); + } + auto inv_energy { ZERO }; + if constexpr (S == SimEngine::SRPIC) { + metric.template transform_xyz(xp, + { ux1(p), ux2(p), ux3(p) }, + vp); + inv_energy = ONE / math::sqrt(ONE + NORM_SQR(ux1(p), ux2(p), ux3(p))); + } else { + metric.template transform(xp, + { ux1(p), ux2(p), ux3(p) }, + vp); + inv_energy = ONE / math::sqrt(ONE + ux1(p) * vp[0] + ux2(p) * vp[1] + + ux3(p) * vp[2]); + } + if (Kokkos::isnan(vp[2]) || Kokkos::isinf(vp[2])) { + vp[2] = ZERO; + } + vp[0] *= inv_energy; + vp[1] *= inv_energy; + vp[2] *= inv_energy; + } - // get [i, di]_init and [i, di]_final (per dimension) - getDepositInterval(p, Ip_f, Ip_i, xp_f, xp_i, xp_r); - // recover particle velocity to deposit in unsimulated direction - getPrtl3Vel(p, vp); const real_t coeff { weight(p) * charge }; - depositCurrentsFromParticle(coeff, vp, Ip_f, Ip_i, xp_f, xp_i, xp_r); - } - /** - * @brief Deposit currents from a single particle. - * @param[in] coeff Particle weight x charge. - * @param[in] vp Particle 3-velocity. - * @param[in] Ip_f Final position of the particle (cell index). - * @param[in] Ip_i Initial position of the particle (cell index). - * @param[in] xp_f Final position. - * @param[in] xp_i Previous step position. - * @param[in] xp_r Intermediate point used in zig-zag deposit. - */ - Inline auto depositCurrentsFromParticle(const real_t& coeff, - const vec_t& vp, - const tuple_t& Ip_f, - const tuple_t& Ip_i, - const coord_t& xp_f, - const coord_t& xp_i, - const coord_t& xp_r) const -> void { - const real_t Wx1_1 { HALF * (xp_i[0] + xp_r[0]) - - static_cast(Ip_i[0]) }; - const real_t Wx1_2 { HALF * (xp_f[0] + xp_r[0]) - - static_cast(Ip_f[0]) }; - const real_t Fx1_1 { (xp_r[0] - xp_i[0]) * coeff * inv_dt }; - const real_t Fx1_2 { (xp_f[0] - xp_r[0]) * coeff * inv_dt }; + const auto dxp_r_1 { static_cast(i1(p) == i1_prev(p)) * + (dx1(p) + dx1_prev(p)) * static_cast(INV_2) }; + + const real_t Wx1_1 { INV_2 * (dxp_r_1 + dx1_prev(p) + + static_cast(i1(p) > i1_prev(p))) }; + const real_t Wx1_2 { INV_2 * (dx1(p) + dxp_r_1 + + static_cast( + static_cast(i1(p) > i1_prev(p)) + + i1_prev(p) - i1(p))) }; + const real_t Fx1_1 { (static_cast(i1(p) > i1_prev(p)) + dxp_r_1 - + dx1_prev(p)) * + coeff * inv_dt }; + const real_t Fx1_2 { (static_cast( + i1(p) - i1_prev(p) - + static_cast(i1(p) > i1_prev(p))) + + dx1(p) - dxp_r_1) * + coeff * inv_dt }; auto J_acc = J.access(); + // tuple_t dxp_r; if constexpr (D == Dim::_1D) { const real_t Fx2_1 { HALF * vp[1] * coeff }; const real_t Fx2_2 { HALF * vp[1] * coeff }; @@ -146,265 +171,210 @@ namespace kernel { const real_t Fx3_1 { HALF * vp[2] * coeff }; const real_t Fx3_2 { HALF * vp[2] * coeff }; - J_acc(Ip_i[0] + N_GHOSTS, cur::jx1) += Fx1_1; - J_acc(Ip_f[0] + N_GHOSTS, cur::jx1) += Fx1_2; + J_acc(i1_prev(p) + N_GHOSTS, cur::jx1) += Fx1_1; + J_acc(i1(p) + N_GHOSTS, cur::jx1) += Fx1_2; - J_acc(Ip_i[0] + N_GHOSTS, cur::jx2) += Fx2_1 * (ONE - Wx1_1); - J_acc(Ip_i[0] + N_GHOSTS + 1, cur::jx2) += Fx2_1 * Wx1_1; - J_acc(Ip_f[0] + N_GHOSTS, cur::jx2) += Fx2_2 * (ONE - Wx1_2); - J_acc(Ip_f[0] + N_GHOSTS + 1, cur::jx2) += Fx2_2 * Wx1_2; + J_acc(i1_prev(p) + N_GHOSTS, cur::jx2) += Fx2_1 * (ONE - Wx1_1); + J_acc(i1_prev(p) + N_GHOSTS + 1, cur::jx2) += Fx2_1 * Wx1_1; + J_acc(i1(p) + N_GHOSTS, cur::jx2) += Fx2_2 * (ONE - Wx1_2); + J_acc(i1(p) + N_GHOSTS + 1, cur::jx2) += Fx2_2 * Wx1_2; - J_acc(Ip_i[0] + N_GHOSTS, cur::jx3) += Fx3_1 * (ONE - Wx1_1); - J_acc(Ip_i[0] + N_GHOSTS + 1, cur::jx3) += Fx3_1 * Wx1_1; - J_acc(Ip_f[0] + N_GHOSTS, cur::jx3) += Fx3_2 * (ONE - Wx1_2); - J_acc(Ip_f[0] + N_GHOSTS + 1, cur::jx3) += Fx3_2 * Wx1_2; + J_acc(i1_prev(p) + N_GHOSTS, cur::jx3) += Fx3_1 * (ONE - Wx1_1); + J_acc(i1_prev(p) + N_GHOSTS + 1, cur::jx3) += Fx3_1 * Wx1_1; + J_acc(i1(p) + N_GHOSTS, cur::jx3) += Fx3_2 * (ONE - Wx1_2); + J_acc(i1(p) + N_GHOSTS + 1, cur::jx3) += Fx3_2 * Wx1_2; } else if constexpr (D == Dim::_2D || D == Dim::_3D) { - const real_t Wx2_1 { HALF * (xp_i[1] + xp_r[1]) - - static_cast(Ip_i[1]) }; - const real_t Wx2_2 { HALF * (xp_f[1] + xp_r[1]) - - static_cast(Ip_f[1]) }; - const real_t Fx2_1 { (xp_r[1] - xp_i[1]) * coeff * inv_dt }; - const real_t Fx2_2 { (xp_f[1] - xp_r[1]) * coeff * inv_dt }; + const auto dxp_r_2 { static_cast(i2(p) == i2_prev(p)) * + (dx2(p) + dx2_prev(p)) * + static_cast(INV_2) }; + + const real_t Wx2_1 { INV_2 * (dxp_r_2 + dx2_prev(p) + + static_cast(i2(p) > i2_prev(p))) }; + const real_t Wx2_2 { INV_2 * (dx2(p) + dxp_r_2 + + static_cast( + static_cast(i2(p) > i2_prev(p)) + + i2_prev(p) - i2(p))) }; + const real_t Fx2_1 { (static_cast(i2(p) > i2_prev(p)) + + dxp_r_2 - dx2_prev(p)) * + coeff * inv_dt }; + const real_t Fx2_2 { (static_cast( + i2(p) - i2_prev(p) - + static_cast(i2(p) > i2_prev(p))) + + dx2(p) - dxp_r_2) * + coeff * inv_dt }; if constexpr (D == Dim::_2D) { const real_t Fx3_1 { HALF * vp[2] * coeff }; const real_t Fx3_2 { HALF * vp[2] * coeff }; - J_acc(Ip_i[0] + N_GHOSTS, Ip_i[1] + N_GHOSTS, cur::jx1) += Fx1_1 * - (ONE - Wx2_1); - J_acc(Ip_i[0] + N_GHOSTS, Ip_i[1] + N_GHOSTS + 1, cur::jx1) += Fx1_1 * - Wx2_1; - J_acc(Ip_f[0] + N_GHOSTS, Ip_f[1] + N_GHOSTS, cur::jx1) += Fx1_2 * - (ONE - Wx2_2); - J_acc(Ip_f[0] + N_GHOSTS, Ip_f[1] + N_GHOSTS + 1, cur::jx1) += Fx1_2 * - Wx2_2; - - J_acc(Ip_i[0] + N_GHOSTS, Ip_i[1] + N_GHOSTS, cur::jx2) += Fx2_1 * - (ONE - Wx1_1); - J_acc(Ip_i[0] + N_GHOSTS + 1, Ip_i[1] + N_GHOSTS, cur::jx2) += Fx2_1 * - Wx1_1; - J_acc(Ip_f[0] + N_GHOSTS, Ip_f[1] + N_GHOSTS, cur::jx2) += Fx2_2 * - (ONE - Wx1_2); - J_acc(Ip_f[0] + N_GHOSTS + 1, Ip_f[1] + N_GHOSTS, cur::jx2) += Fx2_2 * - Wx1_2; - - J_acc(Ip_i[0] + N_GHOSTS, - Ip_i[1] + N_GHOSTS, + J_acc(i1_prev(p) + N_GHOSTS, + i2_prev(p) + N_GHOSTS, + cur::jx1) += Fx1_1 * (ONE - Wx2_1); + J_acc(i1_prev(p) + N_GHOSTS, + i2_prev(p) + N_GHOSTS + 1, + cur::jx1) += Fx1_1 * Wx2_1; + J_acc(i1(p) + N_GHOSTS, i2(p) + N_GHOSTS, cur::jx1) += Fx1_2 * + (ONE - Wx2_2); + J_acc(i1(p) + N_GHOSTS, i2(p) + N_GHOSTS + 1, cur::jx1) += Fx1_2 * Wx2_2; + + J_acc(i1_prev(p) + N_GHOSTS, + i2_prev(p) + N_GHOSTS, + cur::jx2) += Fx2_1 * (ONE - Wx1_1); + J_acc(i1_prev(p) + N_GHOSTS + 1, + i2_prev(p) + N_GHOSTS, + cur::jx2) += Fx2_1 * Wx1_1; + J_acc(i1(p) + N_GHOSTS, i2(p) + N_GHOSTS, cur::jx2) += Fx2_2 * + (ONE - Wx1_2); + J_acc(i1(p) + N_GHOSTS + 1, i2(p) + N_GHOSTS, cur::jx2) += Fx2_2 * Wx1_2; + + J_acc(i1_prev(p) + N_GHOSTS, + i2_prev(p) + N_GHOSTS, cur::jx3) += Fx3_1 * (ONE - Wx1_1) * (ONE - Wx2_1); - J_acc(Ip_i[0] + N_GHOSTS + 1, - Ip_i[1] + N_GHOSTS, + J_acc(i1_prev(p) + N_GHOSTS + 1, + i2_prev(p) + N_GHOSTS, cur::jx3) += Fx3_1 * Wx1_2 * (ONE - Wx2_1); - J_acc(Ip_i[0] + N_GHOSTS, - Ip_i[1] + N_GHOSTS + 1, + J_acc(i1_prev(p) + N_GHOSTS, + i2_prev(p) + N_GHOSTS + 1, cur::jx3) += Fx3_1 * (ONE - Wx1_1) * Wx2_1; - J_acc(Ip_i[0] + N_GHOSTS + 1, - Ip_i[1] + N_GHOSTS + 1, + J_acc(i1_prev(p) + N_GHOSTS + 1, + i2_prev(p) + N_GHOSTS + 1, cur::jx3) += Fx3_1 * Wx1_1 * Wx2_1; - J_acc(Ip_f[0] + N_GHOSTS, - Ip_f[1] + N_GHOSTS, - cur::jx3) += Fx3_2 * (ONE - Wx1_2) * (ONE - Wx2_2); - J_acc(Ip_f[0] + N_GHOSTS + 1, - Ip_f[1] + N_GHOSTS, + J_acc(i1(p) + N_GHOSTS, i2(p) + N_GHOSTS, cur::jx3) += Fx3_2 * + (ONE - Wx1_2) * + (ONE - Wx2_2); + J_acc(i1(p) + N_GHOSTS + 1, + i2(p) + N_GHOSTS, cur::jx3) += Fx3_2 * Wx1_2 * (ONE - Wx2_2); - J_acc(Ip_f[0] + N_GHOSTS, - Ip_f[1] + N_GHOSTS + 1, + J_acc(i1(p) + N_GHOSTS, + i2(p) + N_GHOSTS + 1, cur::jx3) += Fx3_2 * (ONE - Wx1_2) * Wx2_2; - J_acc(Ip_f[0] + N_GHOSTS + 1, - Ip_f[1] + N_GHOSTS + 1, - cur::jx3) += Fx3_2 * Wx1_2 * Wx2_2; + J_acc(i1(p) + N_GHOSTS + 1, i2(p) + N_GHOSTS + 1, cur::jx3) += Fx3_2 * + Wx1_2 * + Wx2_2; } else { - const real_t Wx3_1 { HALF * (xp_i[2] + xp_r[2]) - - static_cast(Ip_i[2]) }; - const real_t Wx3_2 { HALF * (xp_f[2] + xp_r[2]) - - static_cast(Ip_f[2]) }; - const real_t Fx3_1 { (xp_r[2] - xp_i[2]) * coeff * inv_dt }; - const real_t Fx3_2 { (xp_f[2] - xp_r[2]) * coeff * inv_dt }; - - J_acc(Ip_i[0] + N_GHOSTS, - Ip_i[1] + N_GHOSTS, - Ip_i[2] + N_GHOSTS, + const auto dxp_r_3 { static_cast(i3(p) == i3_prev(p)) * + (dx3(p) + dx3_prev(p)) * + static_cast(INV_2) }; + const real_t Wx3_1 { INV_2 * (dxp_r_3 + dx3_prev(p) + + static_cast(i3(p) > i3_prev(p))) }; + const real_t Wx3_2 { INV_2 * (dx3(p) + dxp_r_3 + + static_cast( + static_cast(i3(p) > i3_prev(p)) + + i3_prev(p) - i3(p))) }; + const real_t Fx3_1 { (static_cast(i3(p) > i3_prev(p)) + + dxp_r_3 - dx3_prev(p)) * + coeff * inv_dt }; + const real_t Fx3_2 { (static_cast( + i3(p) - i3_prev(p) - + static_cast(i3(p) > i3_prev(p))) + + dx3(p) - dxp_r_3) * + coeff * inv_dt }; + + J_acc(i1_prev(p) + N_GHOSTS, + i2_prev(p) + N_GHOSTS, + i3_prev(p) + N_GHOSTS, cur::jx1) += Fx1_1 * (ONE - Wx2_1) * (ONE - Wx3_1); - J_acc(Ip_i[0] + N_GHOSTS, - Ip_i[1] + N_GHOSTS + 1, - Ip_i[2] + N_GHOSTS, + J_acc(i1_prev(p) + N_GHOSTS, + i2_prev(p) + N_GHOSTS + 1, + i3_prev(p) + N_GHOSTS, cur::jx1) += Fx1_1 * Wx2_1 * (ONE - Wx3_1); - J_acc(Ip_i[0] + N_GHOSTS, - Ip_i[1] + N_GHOSTS, - Ip_i[2] + N_GHOSTS + 1, + J_acc(i1_prev(p) + N_GHOSTS, + i2_prev(p) + N_GHOSTS, + i3_prev(p) + N_GHOSTS + 1, cur::jx1) += Fx1_1 * (ONE - Wx2_1) * Wx3_1; - J_acc(Ip_i[0] + N_GHOSTS, - Ip_i[1] + N_GHOSTS + 1, - Ip_i[2] + N_GHOSTS + 1, + J_acc(i1_prev(p) + N_GHOSTS, + i2_prev(p) + N_GHOSTS + 1, + i3_prev(p) + N_GHOSTS + 1, cur::jx1) += Fx1_1 * Wx2_1 * Wx3_1; - J_acc(Ip_f[0] + N_GHOSTS, - Ip_f[1] + N_GHOSTS, - Ip_f[2] + N_GHOSTS, + J_acc(i1(p) + N_GHOSTS, + i2(p) + N_GHOSTS, + i3(p) + N_GHOSTS, cur::jx1) += Fx1_2 * (ONE - Wx2_2) * (ONE - Wx3_2); - J_acc(Ip_f[0] + N_GHOSTS, - Ip_f[1] + N_GHOSTS + 1, - Ip_f[2] + N_GHOSTS, + J_acc(i1(p) + N_GHOSTS, + i2(p) + N_GHOSTS + 1, + i3(p) + N_GHOSTS, cur::jx1) += Fx1_2 * Wx2_2 * (ONE - Wx3_2); - J_acc(Ip_f[0] + N_GHOSTS, - Ip_f[1] + N_GHOSTS, - Ip_f[2] + N_GHOSTS + 1, + J_acc(i1(p) + N_GHOSTS, + i2(p) + N_GHOSTS, + i3(p) + N_GHOSTS + 1, cur::jx1) += Fx1_2 * (ONE - Wx2_2) * Wx3_2; - J_acc(Ip_f[0] + N_GHOSTS, - Ip_f[1] + N_GHOSTS + 1, - Ip_f[2] + N_GHOSTS + 1, + J_acc(i1(p) + N_GHOSTS, + i2(p) + N_GHOSTS + 1, + i3(p) + N_GHOSTS + 1, cur::jx1) += Fx1_2 * Wx2_2 * Wx3_2; - J_acc(Ip_i[0] + N_GHOSTS, - Ip_i[1] + N_GHOSTS, - Ip_i[2] + N_GHOSTS, + J_acc(i1_prev(p) + N_GHOSTS, + i2_prev(p) + N_GHOSTS, + i3_prev(p) + N_GHOSTS, cur::jx2) += Fx2_1 * (ONE - Wx1_1) * (ONE - Wx3_1); - J_acc(Ip_i[0] + N_GHOSTS + 1, - Ip_i[1] + N_GHOSTS, - Ip_i[2] + N_GHOSTS, + J_acc(i1_prev(p) + N_GHOSTS + 1, + i2_prev(p) + N_GHOSTS, + i3_prev(p) + N_GHOSTS, cur::jx2) += Fx2_1 * Wx1_1 * (ONE - Wx3_1); - J_acc(Ip_i[0] + N_GHOSTS, - Ip_i[1] + N_GHOSTS, - Ip_i[2] + N_GHOSTS + 1, + J_acc(i1_prev(p) + N_GHOSTS, + i2_prev(p) + N_GHOSTS, + i3_prev(p) + N_GHOSTS + 1, cur::jx2) += Fx2_1 * (ONE - Wx1_1) * Wx3_1; - J_acc(Ip_i[0] + N_GHOSTS + 1, - Ip_i[1] + N_GHOSTS, - Ip_i[2] + N_GHOSTS + 1, + J_acc(i1_prev(p) + N_GHOSTS + 1, + i2_prev(p) + N_GHOSTS, + i3_prev(p) + N_GHOSTS + 1, cur::jx2) += Fx2_1 * Wx1_1 * Wx3_1; - J_acc(Ip_f[0] + N_GHOSTS, - Ip_f[1] + N_GHOSTS, - Ip_f[2] + N_GHOSTS, + J_acc(i1(p) + N_GHOSTS, + i2(p) + N_GHOSTS, + i3(p) + N_GHOSTS, cur::jx2) += Fx2_2 * (ONE - Wx1_2) * (ONE - Wx3_2); - J_acc(Ip_f[0] + N_GHOSTS + 1, - Ip_f[1] + N_GHOSTS, - Ip_f[2] + N_GHOSTS, + J_acc(i1(p) + N_GHOSTS + 1, + i2(p) + N_GHOSTS, + i3(p) + N_GHOSTS, cur::jx2) += Fx2_2 * Wx1_2 * (ONE - Wx3_2); - J_acc(Ip_f[0] + N_GHOSTS, - Ip_f[1] + N_GHOSTS, - Ip_f[2] + N_GHOSTS + 1, + J_acc(i1(p) + N_GHOSTS, + i2(p) + N_GHOSTS, + i3(p) + N_GHOSTS + 1, cur::jx2) += Fx2_2 * (ONE - Wx1_2) * Wx3_2; - J_acc(Ip_f[0] + N_GHOSTS + 1, - Ip_f[1] + N_GHOSTS, - Ip_f[2] + N_GHOSTS + 1, + J_acc(i1(p) + N_GHOSTS + 1, + i2(p) + N_GHOSTS, + i3(p) + N_GHOSTS + 1, cur::jx2) += Fx2_2 * Wx1_2 * Wx3_2; - J_acc(Ip_i[0] + N_GHOSTS, - Ip_i[1] + N_GHOSTS, - Ip_i[2] + N_GHOSTS, + J_acc(i1_prev(p) + N_GHOSTS, + i2_prev(p) + N_GHOSTS, + i3_prev(p) + N_GHOSTS, cur::jx3) += Fx3_1 * (ONE - Wx1_1) * (ONE - Wx2_1); - J_acc(Ip_i[0] + N_GHOSTS + 1, - Ip_i[1] + N_GHOSTS, - Ip_i[2] + N_GHOSTS, + J_acc(i1_prev(p) + N_GHOSTS + 1, + i2_prev(p) + N_GHOSTS, + i3_prev(p) + N_GHOSTS, cur::jx3) += Fx3_1 * Wx1_1 * (ONE - Wx2_1); - J_acc(Ip_i[0] + N_GHOSTS, - Ip_i[1] + N_GHOSTS + 1, - Ip_i[2] + N_GHOSTS, + J_acc(i1_prev(p) + N_GHOSTS, + i2_prev(p) + N_GHOSTS + 1, + i3_prev(p) + N_GHOSTS, cur::jx3) += Fx3_1 * (ONE - Wx1_1) * Wx2_1; - J_acc(Ip_i[0] + N_GHOSTS + 1, - Ip_i[1] + N_GHOSTS + 1, - Ip_i[2] + N_GHOSTS, + J_acc(i1_prev(p) + N_GHOSTS + 1, + i2_prev(p) + N_GHOSTS + 1, + i3_prev(p) + N_GHOSTS, cur::jx3) += Fx3_1 * Wx1_1 * Wx2_1; - J_acc(Ip_f[0] + N_GHOSTS, - Ip_f[1] + N_GHOSTS, - Ip_f[2] + N_GHOSTS, + J_acc(i1(p) + N_GHOSTS, + i2(p) + N_GHOSTS, + i3(p) + N_GHOSTS, cur::jx3) += Fx3_2 * (ONE - Wx1_2) * (ONE - Wx2_2); - J_acc(Ip_f[0] + N_GHOSTS + 1, - Ip_f[1] + N_GHOSTS, - Ip_f[2] + N_GHOSTS, + J_acc(i1(p) + N_GHOSTS + 1, + i2(p) + N_GHOSTS, + i3(p) + N_GHOSTS, cur::jx3) += Fx3_2 * Wx1_2 * (ONE - Wx2_2); - J_acc(Ip_f[0] + N_GHOSTS, - Ip_f[1] + N_GHOSTS + 1, - Ip_f[2] + N_GHOSTS, + J_acc(i1(p) + N_GHOSTS, + i2(p) + N_GHOSTS + 1, + i3(p) + N_GHOSTS, cur::jx3) += Fx3_2 * (ONE - Wx1_2) * Wx2_2; - J_acc(Ip_f[0] + N_GHOSTS + 1, - Ip_f[1] + N_GHOSTS + 1, - Ip_f[2] + N_GHOSTS, + J_acc(i1(p) + N_GHOSTS + 1, + i2(p) + N_GHOSTS + 1, + i3(p) + N_GHOSTS, cur::jx3) += Fx3_2 * Wx1_2 * Wx2_2; } } } - - /** - * @brief Get particle position in `coord_t` form. - * @param[in] p Index of particle. - * @param[out] Ip_f Final position of the particle (cell index). - * @param[out] Ip_i Initial position of the particle (cell index). - * @param[out] xp_f Final position. - * @param[out] xp_i Previous step position. - * @param[out] xp_r Intermediate point used in zig-zag deposit. - */ - Inline auto getDepositInterval(index_t& p, - tuple_t& Ip_f, - tuple_t& Ip_i, - coord_t& xp_f, - coord_t& xp_i, - coord_t& xp_r) const -> void { - Ip_f[0] = i1(p); - Ip_i[0] = i1_prev(p); - xp_f[0] = i_di_to_Xi(Ip_f[0], dx1(p)); - xp_i[0] = i_di_to_Xi(Ip_i[0], dx1_prev(p)); - if constexpr (D == Dim::_2D || D == Dim::_3D) { - Ip_f[1] = i2(p); - Ip_i[1] = i2_prev(p); - xp_f[1] = i_di_to_Xi(Ip_f[1], dx2(p)); - xp_i[1] = i_di_to_Xi(Ip_i[1], dx2_prev(p)); - } - if constexpr (D == Dim::_3D) { - Ip_f[2] = i3(p); - Ip_i[2] = i3_prev(p); - xp_f[2] = i_di_to_Xi(Ip_f[2], dx3(p)); - xp_i[2] = i_di_to_Xi(Ip_i[2], dx3_prev(p)); - } - for (auto i = 0u; i < D; ++i) { - xp_r[i] = math::fmin(static_cast(IMIN(Ip_i[i], Ip_f[i]) + 1), - math::fmax(static_cast(IMAX(Ip_i[i], Ip_f[i])), - HALF * (xp_i[i] + xp_f[i]))); - } - } - - // Getters - Inline void getPrtlPos(index_t& p, coord_t& xp) const { - if constexpr (D == Dim::_1D) { - xp[0] = i_di_to_Xi(i1(p), dx1(p)); - } else if constexpr (D == Dim::_2D) { - if constexpr (M::PrtlDim == Dim::_3D) { - xp[0] = i_di_to_Xi(i1(p), dx1(p)); - xp[1] = i_di_to_Xi(i2(p), dx2(p)); - xp[2] = phi(p); - } else { - xp[0] = i_di_to_Xi(i1(p), dx1(p)); - xp[1] = i_di_to_Xi(i2(p), dx2(p)); - } - } else { - xp[0] = i_di_to_Xi(i1(p), dx1(p)); - xp[1] = i_di_to_Xi(i2(p), dx2(p)); - xp[2] = i_di_to_Xi(i3(p), dx3(p)); - } - } - - Inline void getPrtl3Vel(index_t& p, vec_t& vp) const { - coord_t xp { ZERO }; - getPrtlPos(p, xp); - auto inv_energy { ZERO }; - if constexpr (S == SimEngine::SRPIC) { - metric.template transform_xyz(xp, - { ux1(p), ux2(p), ux3(p) }, - vp); - inv_energy = ONE / math::sqrt(ONE + NORM_SQR(ux1(p), ux2(p), ux3(p))); - } else { - metric.template transform(xp, { ux1(p), ux2(p), ux3(p) }, vp); - inv_energy = ONE / math::sqrt(ONE + ux1(p) * vp[0] + ux2(p) * vp[1] + - ux3(p) * vp[2]); - } - if (Kokkos::isnan(vp[2]) || Kokkos::isinf(vp[2])) { - vp[2] = ZERO; - } - vp[0] *= inv_energy; - vp[1] *= inv_energy; - vp[2] *= inv_energy; - } }; } // namespace kernel From 9a17030497bddee6ce0b9bcce93ecf00f9f17036 Mon Sep 17 00:00:00 2001 From: hayk Date: Wed, 9 Apr 2025 15:58:31 -0400 Subject: [PATCH 603/773] keepconstinjector works --- setups/wip/reconnection/pgen.hpp | 159 +++++++++++----------- src/archetypes/particle_injector.h | 209 +++++++++++++++-------------- src/kernels/injectors.hpp | 16 +-- 3 files changed, 197 insertions(+), 187 deletions(-) diff --git a/setups/wip/reconnection/pgen.hpp b/setups/wip/reconnection/pgen.hpp index 34314ca68..7ae550756 100644 --- a/setups/wip/reconnection/pgen.hpp +++ b/setups/wip/reconnection/pgen.hpp @@ -159,8 +159,9 @@ namespace user { using arch::ProblemGenerator::C; using arch::ProblemGenerator::params; - const real_t bg_B, bg_Bguide, bg_temperature; + const real_t bg_B, bg_Bguide, bg_temperature, inj_ypad; const real_t cs_width, cs_overdensity, cs_x, cs_y; + const real_t ymin, ymax; InitFields init_flds; @@ -169,6 +170,7 @@ namespace user { , bg_B { p.template get("setup.bg_B", 1.0) } , bg_Bguide { p.template get("setup.bg_Bguide", 0.0) } , bg_temperature { p.template get("setup.bg_temperature", 0.001) } + , inj_ypad { p.template get("setup.inj_ypad", (real_t)0.05) } , cs_width { p.template get("setup.cs_width") } , cs_overdensity { p.template get("setup.cs_overdensity") } , cs_x { m.mesh().extent(in::x1).first + @@ -177,6 +179,8 @@ namespace user { , cs_y { m.mesh().extent(in::x2).first + INV_2 * (m.mesh().extent(in::x2).second - m.mesh().extent(in::x2).first) } + , ymin { m.mesh().extent(in::x2).first } + , ymax { m.mesh().extent(in::x2).second } , init_flds { bg_B, bg_Bguide, cs_width, cs_y } {} inline PGen() {} @@ -232,81 +236,84 @@ namespace user { cs_overdensity); } - void CustomPostStep(std::size_t step, long double time, Domain& domain) { - // // 0. define target density profile and box where it has to be - // reached - // // 1. compute density - // // 2. define spatial distribution - // // 3. define energy distribution - // // 4. define particle injector - // // 5. inject particles - // - // // step 0. - // // defining the regions of interest (lower and upper - // y-boundaries) boundaries_t box_upper, box_lower; const - // auto [xmin, xmax] = domain.mesh.extent(in::x1); const auto [ymin, - // ymax] = domain.mesh.extent(in::x2); box_upper.push_back({ xmin, - // xmax }); box_lower.push_back({ xmin, xmax }); - // - // box_upper.push_back({ ymax - dy, ymax }); - // box_lower.push_back({ ymin, ymin + dy }); - // - // if constexpr (M::Dim == Dim::_3D) { - // const auto [zmin, zmax] = domain.mesh.extent(in::x3); - // box_upper.push_back({ zmin, zmax }); - // box_lower.push_back({ zmin, zmax }); - // } - // - // const auto const_dens = ConstDens(); - // const auto inv_n0 = ONE / n0; - // - // // step 1 compute density - // auto scatter_bckp = Kokkos::Experimental::create_scatter_view( - // domain.fields.bckp); - // for (auto& prtl_spec : domain.species) { - // // clang-format off - // Kokkos::parallel_for( - // "ComputeMoments", - // prtl_spec.rangeActiveParticles(), - // kernel::ParticleMoments_kernel({}, - // scatter_bckp, 0, - // prtl_spec.i1, - // prtl_spec.i2, - // prtl_spec.i3, prtl_spec.dx1, - // prtl_spec.dx2, - // prtl_spec.dx3, prtl_spec.ux1, - // prtl_spec.ux2, - // prtl_spec.ux3, prtl_spec.phi, - // prtl_spec.weight, - // prtl_spec.tag, prtl_spec.mass(), - // prtl_spec.charge(), - // false, - // domain.mesh.metric, - // domain.mesh.flds_bc(), - // 0, inv_n0, 0)); - // } - // Kokkos::Experimental::contribute(domain.fields.bckp, scatter_bckp); - // - // - // //step 2. define spatial distribution - // // const auto spatial_dist = arch::Replenish>(domain.mesh.metric, domain.fields.bckp, 0, - // const_dens, ONE); - // const auto spatial_dist = spatial_dist_t(domain.mesh.metric, - // domain.fields.bckp,0,const_dens,ONE); - // //step 3. define energy distribution - // const auto energy_dist = arch::Maxwellian(domain.mesh.metric, - // domain.random_pool, up_temperature); - // //step 4. define particle injector - // const auto injector = arch::NonUniformInjector(energy_dist, spatial_dist, {1,2}); - // //step 5. inject particles - // arch::InjectNonUniform(params, domain, - // injector, ONE, false, box_upper); //upper boudary arch::InjectNonUniform(params, domain, injector, ONE, false, - // box_lower); //lower boundary - // - // + void CustomPostStep(timestep_t, simtime_t, Domain& domain) { + const auto energy_dist = arch::Maxwellian(domain.mesh.metric, + domain.random_pool, + bg_temperature); + + const auto dx = domain.mesh.metric.template sqrt_h_<1, 1>({}); + + boundaries_t inj_box_up, inj_box_down; + boundaries_t probe_box_up, probe_box_down; + inj_box_up.push_back(Range::All); + inj_box_down.push_back(Range::All); + probe_box_up.push_back(Range::All); + probe_box_down.push_back(Range::All); + inj_box_up.push_back({ ymax - inj_ypad - 10 * dx, ymax - inj_ypad }); + inj_box_down.push_back({ ymin + inj_ypad, ymin + inj_ypad + 10 * dx }); + probe_box_up.push_back({ ymax - inj_ypad - 10 * dx, ymax - inj_ypad }); + probe_box_down.push_back({ ymin + inj_ypad, ymin + inj_ypad + 10 * dx }); + + if constexpr (M::Dim == Dim::_3D) { + inj_box_up.push_back(Range::All); + inj_box_down.push_back(Range::All); + } + + { + // compute density of species #1 and #2 + const auto use_weights = params.template get( + "particles.use_weights"); + const auto ni2 = domain.mesh.n_active(in::x2); + const auto inv_n0 = ONE / params.template get("scales.n0"); + + auto scatter_buff = Kokkos::Experimental::create_scatter_view( + domain.fields.buff); + Kokkos::deep_copy(domain.fields.buff, ZERO); + for (const auto sp : std::vector { 1, 2 }) { + const auto& prtl_spec = domain.species[sp - 1]; + // clang-format off + Kokkos::parallel_for( + "ComputeMoments", + prtl_spec.rangeActiveParticles(), + kernel::ParticleMoments_kernel({}, scatter_buff, 0u, + prtl_spec.i1, prtl_spec.i2, prtl_spec.i3, + prtl_spec.dx1, prtl_spec.dx2, prtl_spec.dx3, + prtl_spec.ux1, prtl_spec.ux2, prtl_spec.ux3, + prtl_spec.phi, prtl_spec.weight, prtl_spec.tag, + prtl_spec.mass(), prtl_spec.charge(), + use_weights, + domain.mesh.metric, domain.mesh.flds_bc(), + ni2, inv_n0, 0u)); + // clang-format on + } + Kokkos::Experimental::contribute(domain.fields.buff, scatter_buff); + } + + const auto injector_up = arch::KeepConstantInjector( + energy_dist, + { 1, 2 }, + 0u, + probe_box_up); + const auto injector_down = arch::KeepConstantInjector( + energy_dist, + { 1, 2 }, + 0u, + probe_box_down); + + arch::InjectUniform( + params, + domain, + injector_up, + ONE, + params.template get("particles.use_weights"), + inj_box_up); + arch::InjectUniform( + params, + domain, + injector_down, + ONE, + params.template get("particles.use_weights"), + inj_box_down); } }; diff --git a/src/archetypes/particle_injector.h b/src/archetypes/particle_injector.h index 39c588519..88b0db58b 100644 --- a/src/archetypes/particle_injector.h +++ b/src/archetypes/particle_injector.h @@ -66,45 +66,43 @@ namespace arch { ~UniformInjector() = default; - auto DeduceInjectRegion(const Domain& domain, - const boundaries_t& box) const - -> std::tuple, array_t> { - auto i_min = array_t { "i_min", M::Dim }; - auto i_max = array_t { "i_max", M::Dim }; - + auto DeduceRegion(const Domain& domain, const boundaries_t& box) const + -> std::tuple, array_t> { if (not domain.mesh.Intersects(box)) { - return { false, (ncells_t)0, i_min, i_max }; + return { false, array_t {}, array_t {} }; } + coord_t xCorner_min_Ph { ZERO }; + coord_t xCorner_max_Ph { ZERO }; + coord_t xCorner_min_Cd { ZERO }; + coord_t xCorner_max_Cd { ZERO }; - tuple_t range_min { 0 }; - tuple_t range_max { 0 }; - - boundaries_t incl_ghosts; for (auto d { 0u }; d < M::Dim; ++d) { - incl_ghosts.push_back({ false, false }); + const auto local_xi_min = domain.mesh.extent(static_cast(d)).first; + const auto local_xi_max = domain.mesh.extent(static_cast(d)).second; + const auto extent_min = std::min(std::max(local_xi_min, box[d].first), + local_xi_max); + const auto extent_max = std::max(std::min(local_xi_max, box[d].second), + local_xi_min); + xCorner_min_Ph[d] = extent_min; + xCorner_max_Ph[d] = extent_max; } - const auto intersect_range = domain.mesh.ExtentToRange(box, incl_ghosts); + domain.mesh.metric.template convert(xCorner_min_Ph, + xCorner_min_Cd); + domain.mesh.metric.template convert(xCorner_max_Ph, + xCorner_max_Cd); - for (auto d { 0u }; d < M::Dim; ++d) { - range_min[d] = intersect_range[d].first; - range_max[d] = intersect_range[d].second; - } + array_t xi_min { "xi_min", M::Dim }, xi_max { "xi_max", M::Dim }; - ncells_t ncells = 1; - for (auto d = 0u; d < M::Dim; ++d) { - ncells *= (range_max[d] - range_min[d]); - } - - auto i_min_h = Kokkos::create_mirror_view(i_min); - auto i_max_h = Kokkos::create_mirror_view(i_max); - for (auto d = 0u; d < M::Dim; ++d) { - i_min_h(d) = (real_t)(range_min[d]); - i_max_h(d) = (real_t)(range_max[d]); + auto xi_min_h = Kokkos::create_mirror_view(xi_min); + auto xi_max_h = Kokkos::create_mirror_view(xi_max); + for (auto d { 0u }; d < M::Dim; ++d) { + xi_min_h(d) = xCorner_min_Cd[d]; + xi_max_h(d) = xCorner_max_Cd[d]; } + Kokkos::deep_copy(xi_min, xi_min_h); + Kokkos::deep_copy(xi_max, xi_max_h); - Kokkos::deep_copy(i_min, i_min_h); - Kokkos::deep_copy(i_max, i_max_h); - return { true, ncells, i_min, i_max }; + return { true, xi_min, xi_max }; } auto ComputeNumInject(const SimulationParams& params, @@ -112,20 +110,28 @@ namespace arch { real_t number_density, const boundaries_t& box) const -> std::tuple, array_t> { - const auto result = DeduceInjectRegion(domain, box); - const auto i_min = std::get<2>(result); - const auto i_max = std::get<3>(result); - + const auto result = DeduceRegion(domain, box); if (not std::get<0>(result)) { - return { false, (npart_t)0, i_min, i_max }; + return { false, (npart_t)0, array_t {}, array_t {} }; + } + const auto xi_min = std::get<1>(result); + const auto xi_max = std::get<2>(result); + auto xi_min_h = Kokkos::create_mirror_view(xi_min); + auto xi_max_h = Kokkos::create_mirror_view(xi_max); + Kokkos::deep_copy(xi_min_h, xi_min); + Kokkos::deep_copy(xi_max_h, xi_max); + + long double num_cells { 1.0 }; + for (auto d { 0u }; d < M::Dim; ++d) { + num_cells *= static_cast(xi_max_h(d)) - + static_cast(xi_min_h(d)); } - const auto ncells = std::get<1>(result); const auto ppc0 = params.template get("particles.ppc0"); const auto nparticles = static_cast( - (long double)(ppc0 * number_density * 0.5) * (long double)(ncells)); + (long double)(ppc0 * number_density * 0.5) * num_cells); - return { true, nparticles, i_min, i_max }; + return { true, nparticles, xi_min, xi_max }; } }; @@ -135,12 +141,15 @@ namespace arch { using UniformInjector::D; using UniformInjector::C; + const unsigned short density_buff_idx; boundaries_t probe_box; KeepConstantInjector(const energy_dist_t& energy_dist, const std::pair& species, + unsigned short density_buff_idx, boundaries_t box = {}) - : UniformInjector { energy_dist, species } { + : UniformInjector { energy_dist, species } + , density_buff_idx { density_buff_idx } { for (auto d { 0u }; d < M::Dim; ++d) { if (d < box.size()) { probe_box.push_back({ box[d].first, box[d].second }); @@ -153,98 +162,92 @@ namespace arch { ~KeepConstantInjector() = default; auto ComputeAvgDensity(const SimulationParams& params, - const Domain& domain, - boundaries_t box) const -> real_t { - const auto use_weights = params.template get( - "particles.use_weights"); - const auto ni2 = domain.mesh.n_active(in::x2); - const auto inv_n0 = ONE / params.template get("scales.n0"); - - auto scatter_buff = Kokkos::Experimental::create_scatter_view( - domain.fields.buff); - - for (const auto& sp : std::vector { this->species.first, - this->species.second }) { - raise::ErrorIf(sp >= domain.species.size(), - "Species index out of bounds", - HERE); - const auto& prtl_spec = domain.species[sp - 1]; - Kokkos::deep_copy(domain.fields.buff, ZERO); - // clang-format off - Kokkos::parallel_for( - "ComputeMoments", - prtl_spec.rangeActiveParticles(), - kernel::ParticleMoments_kernel({}, scatter_buff, 0, - prtl_spec.i1, prtl_spec.i2, prtl_spec.i3, - prtl_spec.dx1, prtl_spec.dx2, prtl_spec.dx3, - prtl_spec.ux1, prtl_spec.ux2, prtl_spec.ux3, - prtl_spec.phi, prtl_spec.weight, prtl_spec.tag, - prtl_spec.mass(), prtl_spec.charge(), - use_weights, - domain.mesh.metric, domain.mesh.flds_bc(), - ni2, inv_n0, 0)); - // clang-format on + Domain& domain) const -> real_t { + const auto result = this->DeduceRegion(domain, probe_box); + const auto should_probe = std::get<0>(result); + if (not should_probe) { + return ZERO; } - Kokkos::Experimental::contribute(domain.fields.buff, scatter_buff); + const auto xi_min_arr = std::get<1>(result); + const auto xi_max_arr = std::get<2>(result); - real_t dens { ZERO }; + tuple_t i_min { 0 }; + tuple_t i_max { 0 }; - const auto result = DeduceInjectRegion(domain, box); - const auto should_probe = std::get<0>(result); - const auto ncells = std::get<1>(result); - const auto i_min = std::get<2>(result); - const auto i_max = std::get<3>(result); + auto xi_min_h = Kokkos::create_mirror_view(xi_min_arr); + auto xi_max_h = Kokkos::create_mirror_view(xi_max_arr); + Kokkos::deep_copy(xi_min_h, xi_min_arr); + Kokkos::deep_copy(xi_max_h, xi_max_arr); + + ncells_t num_cells = 1u; + for (auto d { 0u }; d < M::Dim; ++d) { + i_min[d] = std::floor(xi_min_h(d)) + N_GHOSTS; + i_max[d] = std::ceil(xi_max_h(d)) + N_GHOSTS; + num_cells *= (i_max[d] - i_min[d]); + } + real_t dens { ZERO }; if (should_probe) { - range_t probe_range = CreateRangePolicy(i_min, i_max); Kokkos::parallel_reduce( "AvgDensity", - probe_range, - kernel::ComputeSum_kernel(domain.fields.buff, 0), + CreateRangePolicy(i_min, i_max), + kernel::ComputeSum_kernel(domain.fields.buff, density_buff_idx), dens); } #if defined(MPI_ENABLED) real_t tot_dens { ZERO }; - ncells_t tot_ncells { 0 }; + ncells_t tot_num_cells { 0 }; MPI_Allreduce(&dens, &tot_dens, 1, mpi::get_type(), MPI_SUM, MPI_COMM_WORLD); - MPI_Allreduce(&ncells, - &tot_ncells, + MPI_Allreduce(&num_cells, + &tot_num_cells, 1, mpi::get_type(), MPI_SUM, MPI_COMM_WORLD); - dens = tot_dens; - ncells = tot_ncells; + dens = tot_dens; + num_cells = tot_num_cells; #endif - if (ncells > 0) { - return dens / (real_t)(ncells); + if (num_cells > 0) { + return dens / (real_t)(num_cells); } else { return ZERO; } } auto ComputeNumInject(const SimulationParams& params, - const Domain& domain, + Domain& domain, real_t number_density, const boundaries_t& box) const -> std::tuple, array_t> { const auto computed_avg_density = ComputeAvgDensity(params, domain); - const auto result = DeduceInjectRegion(domain, box); - const auto i_min = std::get<2>(result); - const auto i_max = std::get<3>(result); - + const auto result = this->DeduceRegion(domain, box); if (not std::get<0>(result)) { - return { false, (npart_t)0, i_min, i_max }; + return { false, (npart_t)0, array_t {}, array_t {} }; } - const auto ncells = std::get<1>(result); - const auto ppc0 = params.template get("particles.ppc0"); - const auto nparticles = static_cast( - (long double)(ppc0 * (number_density - computed_avg_density) * 0.5) * - (long double)(ncells)); + const auto xi_min = std::get<1>(result); + const auto xi_max = std::get<2>(result); + auto xi_min_h = Kokkos::create_mirror_view(xi_min); + auto xi_max_h = Kokkos::create_mirror_view(xi_max); + Kokkos::deep_copy(xi_min_h, xi_min); + Kokkos::deep_copy(xi_max_h, xi_max); + + long double num_cells { 1.0 }; + for (auto d { 0u }; d < M::Dim; ++d) { + num_cells *= static_cast(xi_max_h(d)) - + static_cast(xi_min_h(d)); + } + + const auto ppc0 = params.template get("particles.ppc0"); + npart_t nparticles { 0u }; + if (number_density > computed_avg_density) { + nparticles = static_cast( + (long double)(ppc0 * (number_density - computed_avg_density) * 0.5) * + num_cells); + } - return { true, nparticles, i_min, i_max }; + return { nparticles != 0u, nparticles, xi_min, xi_max }; } }; @@ -471,8 +474,8 @@ namespace arch { return; } const auto nparticles = std::get<1>(result); - const auto i_min = std::get<2>(result); - const auto i_max = std::get<3>(result); + const auto xi_min = std::get<2>(result); + const auto xi_max = std::get<3>(result); Kokkos::parallel_for( "InjectUniform", @@ -485,8 +488,8 @@ namespace arch { domain.species[injector.species.first - 1].npart(), domain.species[injector.species.second - 1].npart(), domain.mesh.metric, - i_min, - i_max, + xi_min, + xi_max, injector.energy_dist, ONE / params.template get("scales.V0"), domain.random_pool)); diff --git a/src/kernels/injectors.hpp b/src/kernels/injectors.hpp index 7dcd017a3..d50b5c24c 100644 --- a/src/kernels/injectors.hpp +++ b/src/kernels/injectors.hpp @@ -49,7 +49,7 @@ namespace kernel { npart_t offset1, offset2; const M metric; - const array_t i_min, i_max; + const array_t xi_min, xi_max; const ED energy_dist; const real_t inv_V0; random_number_pool_t random_pool; @@ -61,8 +61,8 @@ namespace kernel { npart_t offset1, npart_t offset2, const M& metric, - const array_t& i_min, - const array_t& i_max, + const array_t& xi_min, + const array_t& xi_max, const ED& energy_dist, real_t inv_V0, random_number_pool_t& random_pool) @@ -95,8 +95,8 @@ namespace kernel { , offset1 { offset1 } , offset2 { offset2 } , metric { metric } - , i_min { i_min } - , i_max { i_max } + , xi_min { xi_min } + , xi_max { xi_max } , energy_dist { energy_dist } , inv_V0 { inv_V0 } , random_pool { random_pool } {} @@ -106,12 +106,12 @@ namespace kernel { vec_t v1 { ZERO }, v2 { ZERO }; { // generate a random coordinate auto rand_gen = random_pool.get_state(); - x_Cd[0] = i_min(0) + Random(rand_gen) * (i_max(0) - i_min(0)); + x_Cd[0] = xi_min(0) + Random(rand_gen) * (xi_max(0) - xi_min(0)); if constexpr (M::Dim == Dim::_2D or M::Dim == Dim::_3D) { - x_Cd[1] = i_min(1) + Random(rand_gen) * (i_max(1) - i_min(1)); + x_Cd[1] = xi_min(1) + Random(rand_gen) * (xi_max(1) - xi_min(1)); } if constexpr (M::Dim == Dim::_3D) { - x_Cd[2] = i_min(2) + Random(rand_gen) * (i_max(2) - i_min(2)); + x_Cd[2] = xi_min(2) + Random(rand_gen) * (xi_max(2) - xi_min(2)); } random_pool.free_state(rand_gen); } From 7674780fa82b9d4bbfd5213161aa1e8ad31815c0 Mon Sep 17 00:00:00 2001 From: hayk Date: Wed, 9 Apr 2025 15:58:31 -0400 Subject: [PATCH 604/773] keepconstinjector works --- setups/wip/reconnection/pgen.hpp | 159 +++++++++++----------- src/archetypes/particle_injector.h | 209 +++++++++++++++-------------- src/kernels/injectors.hpp | 16 +-- 3 files changed, 197 insertions(+), 187 deletions(-) diff --git a/setups/wip/reconnection/pgen.hpp b/setups/wip/reconnection/pgen.hpp index 34314ca68..7ae550756 100644 --- a/setups/wip/reconnection/pgen.hpp +++ b/setups/wip/reconnection/pgen.hpp @@ -159,8 +159,9 @@ namespace user { using arch::ProblemGenerator::C; using arch::ProblemGenerator::params; - const real_t bg_B, bg_Bguide, bg_temperature; + const real_t bg_B, bg_Bguide, bg_temperature, inj_ypad; const real_t cs_width, cs_overdensity, cs_x, cs_y; + const real_t ymin, ymax; InitFields init_flds; @@ -169,6 +170,7 @@ namespace user { , bg_B { p.template get("setup.bg_B", 1.0) } , bg_Bguide { p.template get("setup.bg_Bguide", 0.0) } , bg_temperature { p.template get("setup.bg_temperature", 0.001) } + , inj_ypad { p.template get("setup.inj_ypad", (real_t)0.05) } , cs_width { p.template get("setup.cs_width") } , cs_overdensity { p.template get("setup.cs_overdensity") } , cs_x { m.mesh().extent(in::x1).first + @@ -177,6 +179,8 @@ namespace user { , cs_y { m.mesh().extent(in::x2).first + INV_2 * (m.mesh().extent(in::x2).second - m.mesh().extent(in::x2).first) } + , ymin { m.mesh().extent(in::x2).first } + , ymax { m.mesh().extent(in::x2).second } , init_flds { bg_B, bg_Bguide, cs_width, cs_y } {} inline PGen() {} @@ -232,81 +236,84 @@ namespace user { cs_overdensity); } - void CustomPostStep(std::size_t step, long double time, Domain& domain) { - // // 0. define target density profile and box where it has to be - // reached - // // 1. compute density - // // 2. define spatial distribution - // // 3. define energy distribution - // // 4. define particle injector - // // 5. inject particles - // - // // step 0. - // // defining the regions of interest (lower and upper - // y-boundaries) boundaries_t box_upper, box_lower; const - // auto [xmin, xmax] = domain.mesh.extent(in::x1); const auto [ymin, - // ymax] = domain.mesh.extent(in::x2); box_upper.push_back({ xmin, - // xmax }); box_lower.push_back({ xmin, xmax }); - // - // box_upper.push_back({ ymax - dy, ymax }); - // box_lower.push_back({ ymin, ymin + dy }); - // - // if constexpr (M::Dim == Dim::_3D) { - // const auto [zmin, zmax] = domain.mesh.extent(in::x3); - // box_upper.push_back({ zmin, zmax }); - // box_lower.push_back({ zmin, zmax }); - // } - // - // const auto const_dens = ConstDens(); - // const auto inv_n0 = ONE / n0; - // - // // step 1 compute density - // auto scatter_bckp = Kokkos::Experimental::create_scatter_view( - // domain.fields.bckp); - // for (auto& prtl_spec : domain.species) { - // // clang-format off - // Kokkos::parallel_for( - // "ComputeMoments", - // prtl_spec.rangeActiveParticles(), - // kernel::ParticleMoments_kernel({}, - // scatter_bckp, 0, - // prtl_spec.i1, - // prtl_spec.i2, - // prtl_spec.i3, prtl_spec.dx1, - // prtl_spec.dx2, - // prtl_spec.dx3, prtl_spec.ux1, - // prtl_spec.ux2, - // prtl_spec.ux3, prtl_spec.phi, - // prtl_spec.weight, - // prtl_spec.tag, prtl_spec.mass(), - // prtl_spec.charge(), - // false, - // domain.mesh.metric, - // domain.mesh.flds_bc(), - // 0, inv_n0, 0)); - // } - // Kokkos::Experimental::contribute(domain.fields.bckp, scatter_bckp); - // - // - // //step 2. define spatial distribution - // // const auto spatial_dist = arch::Replenish>(domain.mesh.metric, domain.fields.bckp, 0, - // const_dens, ONE); - // const auto spatial_dist = spatial_dist_t(domain.mesh.metric, - // domain.fields.bckp,0,const_dens,ONE); - // //step 3. define energy distribution - // const auto energy_dist = arch::Maxwellian(domain.mesh.metric, - // domain.random_pool, up_temperature); - // //step 4. define particle injector - // const auto injector = arch::NonUniformInjector(energy_dist, spatial_dist, {1,2}); - // //step 5. inject particles - // arch::InjectNonUniform(params, domain, - // injector, ONE, false, box_upper); //upper boudary arch::InjectNonUniform(params, domain, injector, ONE, false, - // box_lower); //lower boundary - // - // + void CustomPostStep(timestep_t, simtime_t, Domain& domain) { + const auto energy_dist = arch::Maxwellian(domain.mesh.metric, + domain.random_pool, + bg_temperature); + + const auto dx = domain.mesh.metric.template sqrt_h_<1, 1>({}); + + boundaries_t inj_box_up, inj_box_down; + boundaries_t probe_box_up, probe_box_down; + inj_box_up.push_back(Range::All); + inj_box_down.push_back(Range::All); + probe_box_up.push_back(Range::All); + probe_box_down.push_back(Range::All); + inj_box_up.push_back({ ymax - inj_ypad - 10 * dx, ymax - inj_ypad }); + inj_box_down.push_back({ ymin + inj_ypad, ymin + inj_ypad + 10 * dx }); + probe_box_up.push_back({ ymax - inj_ypad - 10 * dx, ymax - inj_ypad }); + probe_box_down.push_back({ ymin + inj_ypad, ymin + inj_ypad + 10 * dx }); + + if constexpr (M::Dim == Dim::_3D) { + inj_box_up.push_back(Range::All); + inj_box_down.push_back(Range::All); + } + + { + // compute density of species #1 and #2 + const auto use_weights = params.template get( + "particles.use_weights"); + const auto ni2 = domain.mesh.n_active(in::x2); + const auto inv_n0 = ONE / params.template get("scales.n0"); + + auto scatter_buff = Kokkos::Experimental::create_scatter_view( + domain.fields.buff); + Kokkos::deep_copy(domain.fields.buff, ZERO); + for (const auto sp : std::vector { 1, 2 }) { + const auto& prtl_spec = domain.species[sp - 1]; + // clang-format off + Kokkos::parallel_for( + "ComputeMoments", + prtl_spec.rangeActiveParticles(), + kernel::ParticleMoments_kernel({}, scatter_buff, 0u, + prtl_spec.i1, prtl_spec.i2, prtl_spec.i3, + prtl_spec.dx1, prtl_spec.dx2, prtl_spec.dx3, + prtl_spec.ux1, prtl_spec.ux2, prtl_spec.ux3, + prtl_spec.phi, prtl_spec.weight, prtl_spec.tag, + prtl_spec.mass(), prtl_spec.charge(), + use_weights, + domain.mesh.metric, domain.mesh.flds_bc(), + ni2, inv_n0, 0u)); + // clang-format on + } + Kokkos::Experimental::contribute(domain.fields.buff, scatter_buff); + } + + const auto injector_up = arch::KeepConstantInjector( + energy_dist, + { 1, 2 }, + 0u, + probe_box_up); + const auto injector_down = arch::KeepConstantInjector( + energy_dist, + { 1, 2 }, + 0u, + probe_box_down); + + arch::InjectUniform( + params, + domain, + injector_up, + ONE, + params.template get("particles.use_weights"), + inj_box_up); + arch::InjectUniform( + params, + domain, + injector_down, + ONE, + params.template get("particles.use_weights"), + inj_box_down); } }; diff --git a/src/archetypes/particle_injector.h b/src/archetypes/particle_injector.h index 39c588519..88b0db58b 100644 --- a/src/archetypes/particle_injector.h +++ b/src/archetypes/particle_injector.h @@ -66,45 +66,43 @@ namespace arch { ~UniformInjector() = default; - auto DeduceInjectRegion(const Domain& domain, - const boundaries_t& box) const - -> std::tuple, array_t> { - auto i_min = array_t { "i_min", M::Dim }; - auto i_max = array_t { "i_max", M::Dim }; - + auto DeduceRegion(const Domain& domain, const boundaries_t& box) const + -> std::tuple, array_t> { if (not domain.mesh.Intersects(box)) { - return { false, (ncells_t)0, i_min, i_max }; + return { false, array_t {}, array_t {} }; } + coord_t xCorner_min_Ph { ZERO }; + coord_t xCorner_max_Ph { ZERO }; + coord_t xCorner_min_Cd { ZERO }; + coord_t xCorner_max_Cd { ZERO }; - tuple_t range_min { 0 }; - tuple_t range_max { 0 }; - - boundaries_t incl_ghosts; for (auto d { 0u }; d < M::Dim; ++d) { - incl_ghosts.push_back({ false, false }); + const auto local_xi_min = domain.mesh.extent(static_cast(d)).first; + const auto local_xi_max = domain.mesh.extent(static_cast(d)).second; + const auto extent_min = std::min(std::max(local_xi_min, box[d].first), + local_xi_max); + const auto extent_max = std::max(std::min(local_xi_max, box[d].second), + local_xi_min); + xCorner_min_Ph[d] = extent_min; + xCorner_max_Ph[d] = extent_max; } - const auto intersect_range = domain.mesh.ExtentToRange(box, incl_ghosts); + domain.mesh.metric.template convert(xCorner_min_Ph, + xCorner_min_Cd); + domain.mesh.metric.template convert(xCorner_max_Ph, + xCorner_max_Cd); - for (auto d { 0u }; d < M::Dim; ++d) { - range_min[d] = intersect_range[d].first; - range_max[d] = intersect_range[d].second; - } + array_t xi_min { "xi_min", M::Dim }, xi_max { "xi_max", M::Dim }; - ncells_t ncells = 1; - for (auto d = 0u; d < M::Dim; ++d) { - ncells *= (range_max[d] - range_min[d]); - } - - auto i_min_h = Kokkos::create_mirror_view(i_min); - auto i_max_h = Kokkos::create_mirror_view(i_max); - for (auto d = 0u; d < M::Dim; ++d) { - i_min_h(d) = (real_t)(range_min[d]); - i_max_h(d) = (real_t)(range_max[d]); + auto xi_min_h = Kokkos::create_mirror_view(xi_min); + auto xi_max_h = Kokkos::create_mirror_view(xi_max); + for (auto d { 0u }; d < M::Dim; ++d) { + xi_min_h(d) = xCorner_min_Cd[d]; + xi_max_h(d) = xCorner_max_Cd[d]; } + Kokkos::deep_copy(xi_min, xi_min_h); + Kokkos::deep_copy(xi_max, xi_max_h); - Kokkos::deep_copy(i_min, i_min_h); - Kokkos::deep_copy(i_max, i_max_h); - return { true, ncells, i_min, i_max }; + return { true, xi_min, xi_max }; } auto ComputeNumInject(const SimulationParams& params, @@ -112,20 +110,28 @@ namespace arch { real_t number_density, const boundaries_t& box) const -> std::tuple, array_t> { - const auto result = DeduceInjectRegion(domain, box); - const auto i_min = std::get<2>(result); - const auto i_max = std::get<3>(result); - + const auto result = DeduceRegion(domain, box); if (not std::get<0>(result)) { - return { false, (npart_t)0, i_min, i_max }; + return { false, (npart_t)0, array_t {}, array_t {} }; + } + const auto xi_min = std::get<1>(result); + const auto xi_max = std::get<2>(result); + auto xi_min_h = Kokkos::create_mirror_view(xi_min); + auto xi_max_h = Kokkos::create_mirror_view(xi_max); + Kokkos::deep_copy(xi_min_h, xi_min); + Kokkos::deep_copy(xi_max_h, xi_max); + + long double num_cells { 1.0 }; + for (auto d { 0u }; d < M::Dim; ++d) { + num_cells *= static_cast(xi_max_h(d)) - + static_cast(xi_min_h(d)); } - const auto ncells = std::get<1>(result); const auto ppc0 = params.template get("particles.ppc0"); const auto nparticles = static_cast( - (long double)(ppc0 * number_density * 0.5) * (long double)(ncells)); + (long double)(ppc0 * number_density * 0.5) * num_cells); - return { true, nparticles, i_min, i_max }; + return { true, nparticles, xi_min, xi_max }; } }; @@ -135,12 +141,15 @@ namespace arch { using UniformInjector::D; using UniformInjector::C; + const unsigned short density_buff_idx; boundaries_t probe_box; KeepConstantInjector(const energy_dist_t& energy_dist, const std::pair& species, + unsigned short density_buff_idx, boundaries_t box = {}) - : UniformInjector { energy_dist, species } { + : UniformInjector { energy_dist, species } + , density_buff_idx { density_buff_idx } { for (auto d { 0u }; d < M::Dim; ++d) { if (d < box.size()) { probe_box.push_back({ box[d].first, box[d].second }); @@ -153,98 +162,92 @@ namespace arch { ~KeepConstantInjector() = default; auto ComputeAvgDensity(const SimulationParams& params, - const Domain& domain, - boundaries_t box) const -> real_t { - const auto use_weights = params.template get( - "particles.use_weights"); - const auto ni2 = domain.mesh.n_active(in::x2); - const auto inv_n0 = ONE / params.template get("scales.n0"); - - auto scatter_buff = Kokkos::Experimental::create_scatter_view( - domain.fields.buff); - - for (const auto& sp : std::vector { this->species.first, - this->species.second }) { - raise::ErrorIf(sp >= domain.species.size(), - "Species index out of bounds", - HERE); - const auto& prtl_spec = domain.species[sp - 1]; - Kokkos::deep_copy(domain.fields.buff, ZERO); - // clang-format off - Kokkos::parallel_for( - "ComputeMoments", - prtl_spec.rangeActiveParticles(), - kernel::ParticleMoments_kernel({}, scatter_buff, 0, - prtl_spec.i1, prtl_spec.i2, prtl_spec.i3, - prtl_spec.dx1, prtl_spec.dx2, prtl_spec.dx3, - prtl_spec.ux1, prtl_spec.ux2, prtl_spec.ux3, - prtl_spec.phi, prtl_spec.weight, prtl_spec.tag, - prtl_spec.mass(), prtl_spec.charge(), - use_weights, - domain.mesh.metric, domain.mesh.flds_bc(), - ni2, inv_n0, 0)); - // clang-format on + Domain& domain) const -> real_t { + const auto result = this->DeduceRegion(domain, probe_box); + const auto should_probe = std::get<0>(result); + if (not should_probe) { + return ZERO; } - Kokkos::Experimental::contribute(domain.fields.buff, scatter_buff); + const auto xi_min_arr = std::get<1>(result); + const auto xi_max_arr = std::get<2>(result); - real_t dens { ZERO }; + tuple_t i_min { 0 }; + tuple_t i_max { 0 }; - const auto result = DeduceInjectRegion(domain, box); - const auto should_probe = std::get<0>(result); - const auto ncells = std::get<1>(result); - const auto i_min = std::get<2>(result); - const auto i_max = std::get<3>(result); + auto xi_min_h = Kokkos::create_mirror_view(xi_min_arr); + auto xi_max_h = Kokkos::create_mirror_view(xi_max_arr); + Kokkos::deep_copy(xi_min_h, xi_min_arr); + Kokkos::deep_copy(xi_max_h, xi_max_arr); + + ncells_t num_cells = 1u; + for (auto d { 0u }; d < M::Dim; ++d) { + i_min[d] = std::floor(xi_min_h(d)) + N_GHOSTS; + i_max[d] = std::ceil(xi_max_h(d)) + N_GHOSTS; + num_cells *= (i_max[d] - i_min[d]); + } + real_t dens { ZERO }; if (should_probe) { - range_t probe_range = CreateRangePolicy(i_min, i_max); Kokkos::parallel_reduce( "AvgDensity", - probe_range, - kernel::ComputeSum_kernel(domain.fields.buff, 0), + CreateRangePolicy(i_min, i_max), + kernel::ComputeSum_kernel(domain.fields.buff, density_buff_idx), dens); } #if defined(MPI_ENABLED) real_t tot_dens { ZERO }; - ncells_t tot_ncells { 0 }; + ncells_t tot_num_cells { 0 }; MPI_Allreduce(&dens, &tot_dens, 1, mpi::get_type(), MPI_SUM, MPI_COMM_WORLD); - MPI_Allreduce(&ncells, - &tot_ncells, + MPI_Allreduce(&num_cells, + &tot_num_cells, 1, mpi::get_type(), MPI_SUM, MPI_COMM_WORLD); - dens = tot_dens; - ncells = tot_ncells; + dens = tot_dens; + num_cells = tot_num_cells; #endif - if (ncells > 0) { - return dens / (real_t)(ncells); + if (num_cells > 0) { + return dens / (real_t)(num_cells); } else { return ZERO; } } auto ComputeNumInject(const SimulationParams& params, - const Domain& domain, + Domain& domain, real_t number_density, const boundaries_t& box) const -> std::tuple, array_t> { const auto computed_avg_density = ComputeAvgDensity(params, domain); - const auto result = DeduceInjectRegion(domain, box); - const auto i_min = std::get<2>(result); - const auto i_max = std::get<3>(result); - + const auto result = this->DeduceRegion(domain, box); if (not std::get<0>(result)) { - return { false, (npart_t)0, i_min, i_max }; + return { false, (npart_t)0, array_t {}, array_t {} }; } - const auto ncells = std::get<1>(result); - const auto ppc0 = params.template get("particles.ppc0"); - const auto nparticles = static_cast( - (long double)(ppc0 * (number_density - computed_avg_density) * 0.5) * - (long double)(ncells)); + const auto xi_min = std::get<1>(result); + const auto xi_max = std::get<2>(result); + auto xi_min_h = Kokkos::create_mirror_view(xi_min); + auto xi_max_h = Kokkos::create_mirror_view(xi_max); + Kokkos::deep_copy(xi_min_h, xi_min); + Kokkos::deep_copy(xi_max_h, xi_max); + + long double num_cells { 1.0 }; + for (auto d { 0u }; d < M::Dim; ++d) { + num_cells *= static_cast(xi_max_h(d)) - + static_cast(xi_min_h(d)); + } + + const auto ppc0 = params.template get("particles.ppc0"); + npart_t nparticles { 0u }; + if (number_density > computed_avg_density) { + nparticles = static_cast( + (long double)(ppc0 * (number_density - computed_avg_density) * 0.5) * + num_cells); + } - return { true, nparticles, i_min, i_max }; + return { nparticles != 0u, nparticles, xi_min, xi_max }; } }; @@ -471,8 +474,8 @@ namespace arch { return; } const auto nparticles = std::get<1>(result); - const auto i_min = std::get<2>(result); - const auto i_max = std::get<3>(result); + const auto xi_min = std::get<2>(result); + const auto xi_max = std::get<3>(result); Kokkos::parallel_for( "InjectUniform", @@ -485,8 +488,8 @@ namespace arch { domain.species[injector.species.first - 1].npart(), domain.species[injector.species.second - 1].npart(), domain.mesh.metric, - i_min, - i_max, + xi_min, + xi_max, injector.energy_dist, ONE / params.template get("scales.V0"), domain.random_pool)); diff --git a/src/kernels/injectors.hpp b/src/kernels/injectors.hpp index 7dcd017a3..d50b5c24c 100644 --- a/src/kernels/injectors.hpp +++ b/src/kernels/injectors.hpp @@ -49,7 +49,7 @@ namespace kernel { npart_t offset1, offset2; const M metric; - const array_t i_min, i_max; + const array_t xi_min, xi_max; const ED energy_dist; const real_t inv_V0; random_number_pool_t random_pool; @@ -61,8 +61,8 @@ namespace kernel { npart_t offset1, npart_t offset2, const M& metric, - const array_t& i_min, - const array_t& i_max, + const array_t& xi_min, + const array_t& xi_max, const ED& energy_dist, real_t inv_V0, random_number_pool_t& random_pool) @@ -95,8 +95,8 @@ namespace kernel { , offset1 { offset1 } , offset2 { offset2 } , metric { metric } - , i_min { i_min } - , i_max { i_max } + , xi_min { xi_min } + , xi_max { xi_max } , energy_dist { energy_dist } , inv_V0 { inv_V0 } , random_pool { random_pool } {} @@ -106,12 +106,12 @@ namespace kernel { vec_t v1 { ZERO }, v2 { ZERO }; { // generate a random coordinate auto rand_gen = random_pool.get_state(); - x_Cd[0] = i_min(0) + Random(rand_gen) * (i_max(0) - i_min(0)); + x_Cd[0] = xi_min(0) + Random(rand_gen) * (xi_max(0) - xi_min(0)); if constexpr (M::Dim == Dim::_2D or M::Dim == Dim::_3D) { - x_Cd[1] = i_min(1) + Random(rand_gen) * (i_max(1) - i_min(1)); + x_Cd[1] = xi_min(1) + Random(rand_gen) * (xi_max(1) - xi_min(1)); } if constexpr (M::Dim == Dim::_3D) { - x_Cd[2] = i_min(2) + Random(rand_gen) * (i_max(2) - i_min(2)); + x_Cd[2] = xi_min(2) + Random(rand_gen) * (xi_max(2) - xi_min(2)); } random_pool.free_state(rand_gen); } From 6bb457b7b70ca43879aa59f78e5a0f5292863ba5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20B=C3=B6ss?= Date: Wed, 9 Apr 2025 19:56:04 -0500 Subject: [PATCH 605/773] cleanup before refactor --- setups/srpic/shock/pgen.hpp | 78 ++++++++++++++++++++----------------- 1 file changed, 42 insertions(+), 36 deletions(-) diff --git a/setups/srpic/shock/pgen.hpp b/setups/srpic/shock/pgen.hpp index 99b3ca11e..21da63b2e 100644 --- a/setups/srpic/shock/pgen.hpp +++ b/setups/srpic/shock/pgen.hpp @@ -113,22 +113,23 @@ namespace user { return init_flds; } - auto ResetFields(const em& comp) const -> real_t { + auto FixFieldsConst(const bc_in&, const em& comp) const + -> std::pair { if (comp == em::ex1) { - return init_flds.ex1({ ZERO }); + return { init_flds.ex1({ ZERO }), true }; } else if (comp == em::ex2) { - return init_flds.ex2({ ZERO }); + return { ZERO, true }; } else if (comp == em::ex3) { - return init_flds.ex3({ ZERO }); + return { ZERO, true }; } else if (comp == em::bx1) { - return init_flds.bx1({ ZERO }); + return { init_flds.bx1({ ZERO }), true }; } else if (comp == em::bx2) { - return init_flds.bx2({ ZERO }); + return { init_flds.bx2({ ZERO }), true }; } else if (comp == em::bx3) { - return init_flds.bx3({ ZERO }); + return { init_flds.bx3({ ZERO }), true }; } else { raise::Error("Invalid component", HERE); - return ZERO; + return { ZERO, false }; } } @@ -185,48 +186,45 @@ namespace user { filling_fraction * (global_xmax - global_xmin); // check if injector is supposed to start moving already - const auto dt_inj = time - injection_start > ZERO ? - time - injection_start : ZERO; + const auto dt_inj = time - injection_start > ZERO ? time - injection_start + : ZERO; - // compute the position of the injector + // compute the position of the injector after the current timestep auto xmax = x_init + injector_velocity * (dt_inj + dt); if (xmax >= global_xmax) { xmax = global_xmax; } - // define box to inject into - boundaries_t box; - // loop over all dimension - for (auto d = 0u; d < M::Dim; ++d) { - if (d == 0) { - box.push_back({ xmax - drift_ux / math::sqrt(1 + SQR(drift_ux)) * dt - - injection_frequency * dt, - xmax }); - } else { - box.push_back(Range::All); - } - } + // compute the beginning of the injected region + const auto xmin = xmax - drift_ux / math::sqrt(1 + SQR(drift_ux)) * dt - + injection_frequency * dt; + // define indice range to reset fields boundaries_t incl_ghosts; for (auto d = 0; d < M::Dim; ++d) { incl_ghosts.push_back({ true, true }); } - auto fields_box = box; - // check if the box is still inside the domain - if (xmax + injection_frequency * dt < global_xmax) { - fields_box[0].second += injection_frequency * dt; - } else { - // if right side of the box is outside of the domain -> truncate box - fields_box[0].second = global_xmax; + + // define box to reset fields + boundaries_t purge_box; + // loop over all dimension + for (auto d = 0u; d < M::Dim; ++d) { + if (d == 0) { + purge_box.push_back({ xmin, global_xmax }); + } else { + purge_box.push_back(Range::All); + } } - const auto extent = domain.mesh.ExtentToRange(fields_box, incl_ghosts); + + const auto extent = domain.mesh.ExtentToRange(purge_box, incl_ghosts); tuple_t x_min { 0 }, x_max { 0 }; for (auto d = 0; d < M::Dim; ++d) { x_min[d] = extent[d].first; x_max[d] = extent[d].second; } + Kokkos::parallel_for("ResetFields", CreateRangePolicy(x_min, x_max), arch::SetEMFields_kernel { @@ -268,8 +266,19 @@ namespace user { Inject slab of fresh plasma */ + // define box to inject into + boundaries_t inj_box; + // loop over all dimension + for (auto d = 0u; d < M::Dim; ++d) { + if (d == 0) { + inj_box.push_back({ xmin, xmax }); + } else { + inj_box.push_back(Range::All); + } + } + // same maxwell distribution as above - const auto energy_dist = arch::Maxwellian(domain.mesh.metric, + const auto energy_dist = arch::Maxwellian(domain.mesh.metric, domain.random_pool, temperature, -drift_ux, @@ -287,11 +296,8 @@ namespace user { injector, 1.0, // target density false, // no weights - box); + inj_box); } - }; - } // namespace user - #endif From b43010738a70012a2cc94d79c8d6db64fad7823c Mon Sep 17 00:00:00 2001 From: haykh Date: Thu, 10 Apr 2025 14:16:36 -0400 Subject: [PATCH 606/773] comm aux --- src/engines/grpic.hpp | 16 ++++++ src/framework/domain/communications.cpp | 73 +++++++++++++++++++------ 2 files changed, 72 insertions(+), 17 deletions(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index 2de876891..42fcfe74c 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -313,6 +313,10 @@ namespace ntt { FieldBoundaries(dom, BC::E, gr_bc::aux); timers.stop("FieldBoundaries"); + timers.start("Communications"); + m_metadomain.CommunicateFields(dom, Comm::E); + timers.stop("Communications"); + timers.start("FieldSolver"); /** * em0::B <- (em0::B) <- -curl aux::E @@ -347,6 +351,10 @@ namespace ntt { */ FieldBoundaries(dom, BC::H, gr_bc::aux); timers.stop("FieldBoundaries"); + + timers.start("Communications"); + m_metadomain.CommunicateFields(dom, Comm::H); + timers.stop("Communications"); } { @@ -414,6 +422,10 @@ namespace ntt { FieldBoundaries(dom, BC::E, gr_bc::aux); timers.stop("FieldBoundaries"); + timers.start("Communications"); + m_metadomain.CommunicateFields(dom, Comm::E); + timers.stop("Communications"); + timers.start("FieldSolver"); /** * em0::B <- (em::B) <- -curl aux::E @@ -480,6 +492,10 @@ namespace ntt { FieldBoundaries(dom, BC::B, gr_bc::aux); timers.stop("FieldBoundaries"); + timers.start("Communications"); + m_metadomain.CommunicateFields(dom, Comm::H); + timers.stop("Communications"); + timers.start("FieldSolver"); /** * em0::D <- (em::D) <- curl aux::H diff --git a/src/framework/domain/communications.cpp b/src/framework/domain/communications.cpp index e8ef8e219..11225071d 100644 --- a/src/framework/domain/communications.cpp +++ b/src/framework/domain/communications.cpp @@ -206,13 +206,22 @@ namespace ntt { template 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 - (tags & Comm::D0) or (tags & Comm::B0); - const bool comm_em = (tags & Comm::E) or (tags & Comm::B) || (tags & Comm::D); - const bool comm_em0 = (tags & Comm::B0) or (tags & Comm::D0); + // const auto comm_fields = (tags & Comm::E) or (tags & Comm::B) or + // (tags & Comm::J) or (tags & Comm::D) or + // (tags & Comm::D0) or (tags & Comm::B0) or + // (tags & Comm::H); + const auto comm_em = ((S == SimEngine::SRPIC) and + ((tags & Comm::E) or (tags & Comm::B))) or + ((S == SimEngine::GRPIC) and + ((tags & Comm::D) or (tags & Comm::B))); + const bool comm_em0 = (S == SimEngine::GRPIC) and + ((tags & Comm::B0) or (tags & Comm::D0)); const bool comm_j = (tags & Comm::J); - raise::ErrorIf(not comm_fields, "CommunicateFields called with no task", HERE); + const bool comm_aux = (S == SimEngine::GRPIC) and + ((tags & Comm::E) or (tags & Comm::H)); + raise::ErrorIf(not(comm_em or comm_em0 or comm_j or comm_aux), + "CommunicateFields called with no task", + HERE); std::string comms = ""; if (tags & Comm::E) { @@ -227,6 +236,9 @@ namespace ntt { if (tags & Comm::D) { comms += "D "; } + if (tags & Comm::H) { + comms += "H "; + } if (tags & Comm::D0) { comms += "D0 "; } @@ -243,16 +255,17 @@ namespace ntt { auto comp_range_fld = range_tuple_t {}; auto comp_range_cur = range_tuple_t {}; if constexpr (S == SimEngine::GRPIC) { - if (((tags & Comm::D) && (tags & Comm::B)) || - ((tags & Comm::D0) && (tags & Comm::B0))) { + if (((tags & Comm::D) and (tags & Comm::B)) or + ((tags & Comm::D0) and (tags & Comm::B0)) or + ((tags & Comm::E) and (tags & Comm::H))) { comp_range_fld = range_tuple_t(em::dx1, em::bx3 + 1); - } else if ((tags & Comm::D) || (tags & Comm::D0)) { + } else if ((tags & Comm::D) or (tags & Comm::D0) or (tags & Comm::E)) { comp_range_fld = range_tuple_t(em::dx1, em::dx3 + 1); - } else if ((tags & Comm::B) || (tags & Comm::B0)) { + } else if ((tags & Comm::B) or (tags & Comm::B0) or (tags & Comm::H)) { comp_range_fld = range_tuple_t(em::bx1, em::bx3 + 1); } } else if constexpr (S == SimEngine::SRPIC) { - if ((tags & Comm::E) && (tags & Comm::B)) { + if ((tags & Comm::E) and (tags & Comm::B)) { comp_range_fld = range_tuple_t(em::ex1, em::bx3 + 1); } else if (tags & Comm::E) { comp_range_fld = range_tuple_t(em::ex1, em::ex3 + 1); @@ -290,10 +303,10 @@ namespace ntt { false); } if constexpr (S == SimEngine::GRPIC) { - if (comm_em0) { + if (comm_aux) { comm::CommunicateField(domain.index(), - domain.fields.em0, - domain.fields.em0, + domain.fields.aux, + domain.fields.aux, send_ind, recv_ind, send_rank, @@ -302,10 +315,11 @@ namespace ntt { recv_slice, comp_range_fld, false); - // @HACK_GR_1.2.0 -- this has to be done carefully + } + if (comm_em0) { comm::CommunicateField(domain.index(), - domain.fields.aux, - domain.fields.aux, + domain.fields.em0, + domain.fields.em0, send_ind, recv_ind, send_rank, @@ -314,6 +328,18 @@ namespace ntt { recv_slice, comp_range_fld, false); + // @HACK_GR_1.2.0 -- this has to be done carefully + // comm::CommunicateField(domain.index(), + // domain.fields.aux, + // domain.fields.aux, + // send_ind, + // recv_ind, + // send_rank, + // recv_rank, + // send_slice, + // recv_slice, + // comp_range_fld, + // false); } if (comm_j) { comm::CommunicateField(domain.index(), @@ -329,6 +355,19 @@ namespace ntt { false); } } else { + if (comm_em) { + comm::CommunicateField(domain.index(), + domain.fields.em, + domain.fields.em, + send_ind, + recv_ind, + send_rank, + recv_rank, + send_slice, + recv_slice, + comp_range_fld, + false); + } if (comm_j) { comm::CommunicateField(domain.index(), domain.fields.cur, From fbd6c26150bbb659764d08fcfc587d187f3cc542 Mon Sep 17 00:00:00 2001 From: haykh Date: Thu, 10 Apr 2025 14:41:00 -0400 Subject: [PATCH 607/773] proper ordering of comm vs flds --- src/engines/grpic.hpp | 37 ++++++++++++++++++------------------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index 42fcfe74c..a5046242f 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -148,6 +148,7 @@ namespace ntt { /** * aux::E, aux::H <- boundary conditions */ + m_metadomain.CommunicateFields(dom, Comm::H | Comm::E); FieldBoundaries(dom, BC::H | BC::E, gr_bc::aux); /** @@ -188,6 +189,7 @@ namespace ntt { /** * aux::E, aux::H <- boundary conditions */ + m_metadomain.CommunicateFields(dom, Comm::H | Comm::E); FieldBoundaries(dom, BC::H | BC::E, gr_bc::aux); // !ADD: GR -- particles? @@ -225,6 +227,7 @@ namespace ntt { /** * aux::H <- boundary conditions */ + m_metadomain.CommunicateFields(dom, Comm::H); FieldBoundaries(dom, BC::H, gr_bc::aux); /** @@ -306,6 +309,9 @@ namespace ntt { ComputeAuxE(dom, gr_getE::D0_B); timers.stop("FieldSolver"); + timers.start("Communications"); + m_metadomain.CommunicateFields(dom, Comm::E); + timers.stop("Communications"); timers.start("FieldBoundaries"); /** * aux::E <- boundary conditions @@ -313,10 +319,6 @@ namespace ntt { FieldBoundaries(dom, BC::E, gr_bc::aux); timers.stop("FieldBoundaries"); - timers.start("Communications"); - m_metadomain.CommunicateFields(dom, Comm::E); - timers.stop("Communications"); - timers.start("FieldSolver"); /** * em0::B <- (em0::B) <- -curl aux::E @@ -326,15 +328,15 @@ namespace ntt { Faraday(dom, gr_faraday::aux, ONE); timers.stop("FieldSolver"); + timers.start("Communications"); + m_metadomain.CommunicateFields(dom, Comm::B | Comm::B0); + timers.stop("Communications"); /** * em0::B, em::B <- boundary conditions */ timers.start("FieldBoundaries"); FieldBoundaries(dom, BC::B, gr_bc::main); timers.stop("FieldBoundaries"); - timers.start("Communications"); - m_metadomain.CommunicateFields(dom, Comm::B | Comm::B0); - timers.stop("Communications"); timers.start("FieldSolver"); /** @@ -345,16 +347,15 @@ namespace ntt { ComputeAuxH(dom, gr_getH::D_B0); timers.stop("FieldSolver"); + timers.start("Communications"); + m_metadomain.CommunicateFields(dom, Comm::H); + timers.stop("Communications"); timers.start("FieldBoundaries"); /** * aux::H <- boundary conditions */ FieldBoundaries(dom, BC::H, gr_bc::aux); timers.stop("FieldBoundaries"); - - timers.start("Communications"); - m_metadomain.CommunicateFields(dom, Comm::H); - timers.stop("Communications"); } { @@ -415,6 +416,9 @@ namespace ntt { ComputeAuxE(dom, gr_getE::D_B0); timers.stop("FieldSolver"); + timers.start("Communications"); + m_metadomain.CommunicateFields(dom, Comm::E); + timers.stop("Communications"); timers.start("FieldBoundaries"); /** * aux::Е <- boundary conditions @@ -422,10 +426,6 @@ namespace ntt { FieldBoundaries(dom, BC::E, gr_bc::aux); timers.stop("FieldBoundaries"); - timers.start("Communications"); - m_metadomain.CommunicateFields(dom, Comm::E); - timers.stop("Communications"); - timers.start("FieldSolver"); /** * em0::B <- (em::B) <- -curl aux::E @@ -485,6 +485,9 @@ namespace ntt { ComputeAuxH(dom, gr_getH::D0_B0); timers.stop("FieldSolver"); + timers.start("Communications"); + m_metadomain.CommunicateFields(dom, Comm::H); + timers.stop("Communications"); timers.start("FieldBoundaries"); /** * aux::H <- boundary conditions @@ -492,10 +495,6 @@ namespace ntt { FieldBoundaries(dom, BC::B, gr_bc::aux); timers.stop("FieldBoundaries"); - timers.start("Communications"); - m_metadomain.CommunicateFields(dom, Comm::H); - timers.stop("Communications"); - timers.start("FieldSolver"); /** * em0::D <- (em::D) <- curl aux::H From 4fc9809b413b70ab665a86c99ada6fd56e318ed1 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Fri, 11 Apr 2025 12:35:06 -0400 Subject: [PATCH 608/773] updated wald setup --- setups/grpic/wald/pgen.hpp | 193 ++++++++++++++++-------------------- setups/grpic/wald/wald.toml | 1 - 2 files changed, 83 insertions(+), 111 deletions(-) diff --git a/setups/grpic/wald/pgen.hpp b/setups/grpic/wald/pgen.hpp index 236d361a6..7d101b376 100644 --- a/setups/grpic/wald/pgen.hpp +++ b/setups/grpic/wald/pgen.hpp @@ -29,41 +29,53 @@ namespace user { metric.beta1(x_Cd)); } + Inline auto A_1(const coord_t& x_Cd) const -> real_t { + return HALF * (metric.template h_<1, 3>(x_Cd) + + TWO * metric.spin() * metric.template h_<1, 1>(x_Cd) * metric.beta1(x_Cd) + ); + } + + Inline auto A_0(const coord_t& x_Cd) const -> real_t { + real_t g_00 { -metric.alpha(x_Cd) * metric.alpha(x_Cd) + + metric.template h_<1, 1>(x_Cd) * metric.beta1(x_Cd) * metric.beta1(x_Cd) + }; + return HALF * (metric.template h_<1, 3>(x_Cd) * metric.beta1(x_Cd) + + TWO * metric.spin() * g_00); + } + Inline auto bx1(const coord_t& x_Ph) const -> real_t { // at ( i , j + HALF ) - // coord_t xi { ZERO }, x0m { ZERO }, x0p { ZERO }; - // metric.template convert(x_Ph, xi); + coord_t xi { ZERO }, x0m { ZERO }, x0p { ZERO }; + metric.template convert(x_Ph, xi); - // x0m[0] = xi[0]; - // x0m[1] = xi[1] - HALF * m_eps; - // x0p[0] = xi[0]; - // x0p[1] = xi[1] + HALF * m_eps; + x0m[0] = xi[0]; + x0m[1] = xi[1] - HALF * m_eps; + x0p[0] = xi[0]; + x0p[1] = xi[1] + HALF * m_eps; - // real_t inv_sqrt_detH_ijP { ONE / metric.sqrt_det_h({ xi[0], xi[1] }) }; + real_t inv_sqrt_detH_ijP { ONE / metric.sqrt_det_h({ xi[0], xi[1] }) }; - // if (cmp::AlmostZero(x_Ph[1])) { - // return ONE; - // } else { - // return (A_3(x0p) - A_3(x0m)) * inv_sqrt_detH_ijP / m_eps; - // } - return ZERO; + if (cmp::AlmostZero(x_Ph[1])) { + return ONE; + } else { + return (A_3(x0p) - A_3(x0m)) * inv_sqrt_detH_ijP / m_eps; + } } Inline auto bx2(const coord_t& x_Ph) const -> real_t { // at ( i + HALF , j ) - // coord_t xi { ZERO }, x0m { ZERO }, x0p { ZERO }; - // metric.template convert(x_Ph, xi); - - // x0m[0] = xi[0] - HALF * m_eps; - // x0m[1] = xi[1]; - // x0p[0] = xi[0] + HALF * m_eps; - // x0p[1] = xi[1]; - - // real_t inv_sqrt_detH_ijP { ONE / metric.sqrt_det_h({ xi[0], xi[1] }) }; - // if (cmp::AlmostZero(x_Ph[1])) { - // return ZERO; - // } else { - // return -(A_3(x0p) - A_3(x0m)) * inv_sqrt_detH_ijP / m_eps; - // } - return ZERO; + coord_t xi { ZERO }, x0m { ZERO }, x0p { ZERO }; + metric.template convert(x_Ph, xi); + + x0m[0] = xi[0] - HALF * m_eps; + x0m[1] = xi[1]; + x0p[0] = xi[0] + HALF * m_eps; + x0p[1] = xi[1]; + + real_t inv_sqrt_detH_ijP { ONE / metric.sqrt_det_h({ xi[0], xi[1] }) }; + if (cmp::AlmostZero(x_Ph[1])) { + return ZERO; + } else { + return -(A_3(x0p) - A_3(x0m)) * inv_sqrt_detH_ijP / m_eps; + } } Inline auto bx3(const coord_t& x_Ph) const -> real_t { @@ -100,6 +112,7 @@ namespace user { , EM { domain_ptr->fields.em } , density { domain_ptr->fields.buff } , sigma_thr { sigma_thr } + , inv_n0 { ONE / params.template get("scales.n0") } , dens_thr { dens_thr } { std::copy(xi_min.begin(), xi_min.end(), x_min); std::copy(xi_max.begin(), xi_max.end(), x_max); @@ -118,7 +131,6 @@ namespace user { const auto use_weights = params.template get( "particles.use_weights"); const auto ni2 = mesh.n_active(in::x2); - const auto inv_n0 = ONE / params.template get("scales.n0"); for (const auto& sp : specs) { auto& prtl_spec = domain_ptr->species[sp - 1]; @@ -156,11 +168,8 @@ namespace user { metric.template transform(xi, B_cntrv, B_cov); const auto bsqr = DOT(B_cntrv[0], B_cntrv[1], B_cntrv[2], B_cov[0], B_cov[1], B_cov[2]); - const auto DdotB = - DOT(D_cntrv[0], D_cntrv[1], D_cntrv[2], B_cov[0], B_cov[1], B_cov[2]); const auto dens = density(i1, i2, 0); - // return (bsqr > sigma_thr * dens) || (dens < dens_thr); - return (DdotB / bsqr > 0.001) || (bsqr > sigma_thr * dens); + return (bsqr > sigma_thr * dens) || (dens < dens_thr); } return false; } @@ -178,6 +187,7 @@ namespace user { tuple_t x_max; const real_t sigma_thr; const real_t dens_thr; + const real_t inv_n0; Domain* domain_ptr; ndfield_t density; ndfield_t EM; @@ -219,87 +229,50 @@ namespace user { , init_flds { m.mesh().metric, m_eps } , metadomain { &m } {} - inline void InitPrtls(Domain& domain) { - // arch::InjectGlobally(*metadomain, - // domain, - // 1, - // { - // { "x1", { 3.2 } }, - // { "x2", { 1.2 } }, - // { "phi", { 0.0 } }, - // { "ux1", { 0.0 } }, - // { "ux2", { -1.0 } }, - // { "ux3", { 0.5 } } - // }); - // arch::InjectGlobally(*metadomain, - // domain, - // 2, - // { - // { "x1", { 2.05 } }, - // { "x2", { 2.3 } }, - // { "phi", { 0.0 } }, - // { "ux1", { 0.5 } }, - // { "ux2", { -0.5 } }, - // { "ux3", { -0.5 } } - // }); - const auto energy_dist = arch::Maxwellian(domain.mesh.metric, - domain.random_pool, + inline void InitPrtls(Domain& local_domain) { + const auto energy_dist = arch::Maxwellian(local_domain.mesh.metric, + local_domain.random_pool, temperature); - // const auto npart0 = domain.species[0].npart(); - // auto& ux3_0 = domain.species[0].ux3; - // auto& ux3_1 = domain.species[1].ux3; - // Kokkos::parallel_for( - // "zero", - // npart0, - // Lambda(index_t p) { - // ux3_0(p) = ZERO; - // ux3_1(p) = ZERO; - // }); - // const auto spatial_dist = PointDistribution(xi_min, - // xi_max, - // sigma_max / sigma0, - // multiplicity * nGJ, - // params, - // &local_domain); - - // const auto injector = - // arch::NonUniformInjector( - // energy_dist, - // spatial_dist, - // { 1, 2 }); - // arch::InjectNonUniform(params, - // local_domain, - // injector, - // 1.0, - // true); - // const auto energy_dist = arch::Cold(local_domain.mesh.metric); - const auto injector = arch::UniformInjector( - energy_dist, - { 1, 2 }); - arch::InjectUniform(params, domain, injector, 1.0, true); + const auto spatial_dist = PointDistribution(xi_min, + xi_max, + sigma_max / sigma0, + multiplicity * nGJ, + params, + &local_domain); + + const auto injector = + arch::NonUniformInjector( + energy_dist, + spatial_dist, + { 1, 2 }); + arch::InjectNonUniform(params, + local_domain, + injector, + 1.0, + true); } void CustomPostStep(std::size_t, long double time, Domain& local_domain) { - // const auto energy_dist = arch::Maxwellian(local_domain.mesh.metric, - // local_domain.random_pool, - // temperature); - // const auto spatial_dist = PointDistribution(xi_min, - // xi_max, - // sigma_max / sigma0, - // multiplicity * nGJ, - // params, - // &local_domain); - - // const auto injector = - // arch::NonUniformInjector( - // energy_dist, - // spatial_dist, - // { 1, 2 }); - // arch::InjectNonUniform(params, - // local_domain, - // injector, - // 1.0, - // true); + const auto energy_dist = arch::Maxwellian(local_domain.mesh.metric, + local_domain.random_pool, + temperature); + const auto spatial_dist = PointDistribution(xi_min, + xi_max, + sigma_max / sigma0, + multiplicity * nGJ, + params, + &local_domain); + + const auto injector = + arch::NonUniformInjector( + energy_dist, + spatial_dist, + { 1, 2 }); + arch::InjectNonUniform(params, + local_domain, + injector, + 1.0, + true); } }; diff --git a/setups/grpic/wald/wald.toml b/setups/grpic/wald/wald.toml index c515ae024..61d1a4697 100644 --- a/setups/grpic/wald/wald.toml +++ b/setups/grpic/wald/wald.toml @@ -68,7 +68,6 @@ [output] format = "hdf5" - separate_files = false [output.fields] interval_time = 1.0 From 5cf30afae826430c04a827e5831308bbf08cf28e Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Fri, 11 Apr 2025 12:38:57 -0400 Subject: [PATCH 609/773] dxdydz in minkowski are now compared with prec*100 --- src/metrics/minkowski.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/metrics/minkowski.h b/src/metrics/minkowski.h index 367689e0f..244ce9f25 100644 --- a/src/metrics/minkowski.h +++ b/src/metrics/minkowski.h @@ -54,13 +54,15 @@ namespace metric { , dx { (x1_max - x1_min) / nx1 } , dx_inv { ONE / dx } { set_dxMin(find_dxMin()); + const auto epsilon = std::numeric_limits::epsilon() * + static_cast(100.0); if constexpr (D != Dim::_1D) { - raise::ErrorIf(not cmp::AlmostEqual((x2_max - x2_min) / (real_t)(nx2), dx), + raise::ErrorIf(not cmp::AlmostEqual((x2_max - x2_min) / (real_t)(nx2), dx, epsilon), "dx2 must be equal to dx1 in 2D", HERE); } if constexpr (D == Dim::_3D) { - raise::ErrorIf(not cmp::AlmostEqual((x3_max - x3_min) / (real_t)(nx3), dx), + raise::ErrorIf(not cmp::AlmostEqual((x3_max - x3_min) / (real_t)(nx3), dx, epsilon), "dx3 must be equal to dx1 in 3D", HERE); } From 1eb1e26115102dd406e9739875913110923f1a63 Mon Sep 17 00:00:00 2001 From: hayk Date: Fri, 11 Apr 2025 20:10:11 -0400 Subject: [PATCH 610/773] consistent type spidx_t & idx_t & dim_t --- setups/srpic/example/pgen.hpp | 20 ++--- setups/srpic/langmuir/pgen.hpp | 2 +- setups/srpic/shock/pgen.hpp | 8 +- setups/srpic/turbulence/pgen.hpp | 39 ++++----- setups/tests/blob/pgen.hpp | 2 +- setups/tests/injector/pgen.hpp | 2 +- setups/wip/magpump/pgen.hpp | 2 +- setups/wip/rec-gravity/pgen.hpp | 111 ++++++++---------------- setups/wip/rec-gravity/rec-gravity.toml | 36 ++++---- setups/wip/reconnection/pgen.hpp | 2 +- src/archetypes/energy_dist.h | 10 +-- src/archetypes/particle_injector.h | 9 +- src/archetypes/spatial_dist.h | 4 +- src/archetypes/tests/energy_dist.cpp | 8 +- src/archetypes/tests/powerlaw.cpp | 8 +- src/archetypes/tests/spatial_dist.cpp | 10 +-- src/checkpoint/reader.cpp | 14 +-- src/checkpoint/reader.h | 6 +- src/engines/srpic.hpp | 23 +++-- src/framework/containers/particles.cpp | 2 +- src/framework/containers/particles.h | 2 +- src/framework/containers/species.h | 16 ++-- src/framework/domain/checkpoint.cpp | 2 +- src/framework/domain/comm_mpi.hpp | 2 +- src/framework/domain/grid.cpp | 14 +-- src/framework/domain/metadomain.cpp | 2 +- src/framework/domain/output.cpp | 24 ++--- src/framework/parameters.cpp | 16 ++-- src/framework/tests/grid_mesh.cpp | 23 +++-- src/global/arch/directions.h | 8 +- src/global/global.h | 2 + src/kernels/fields_bcs.hpp | 8 +- src/kernels/injectors.hpp | 1 - src/kernels/particle_moments.hpp | 4 +- src/kernels/particle_pusher_sr.hpp | 34 ++++---- src/kernels/tests/flds_bc.cpp | 2 +- src/kernels/utils.hpp | 4 +- src/metrics/tests/coord_trans.cpp | 46 +++++----- src/metrics/tests/ks-qks.cpp | 6 +- src/metrics/tests/minkowski.cpp | 2 +- src/metrics/tests/sph-qsph.cpp | 6 +- src/metrics/tests/sr-cart-sph.cpp | 8 +- src/metrics/tests/vec_trans.cpp | 48 +++++----- src/output/fields.h | 2 +- src/output/particles.h | 8 +- src/output/spectra.h | 8 +- src/output/tests/fields.cpp | 2 +- src/output/utils/interpret_prompt.cpp | 6 +- src/output/utils/interpret_prompt.h | 6 +- src/output/writer.cpp | 13 ++- src/output/writer.h | 6 +- 51 files changed, 305 insertions(+), 344 deletions(-) diff --git a/setups/srpic/example/pgen.hpp b/setups/srpic/example/pgen.hpp index 3739243cd..cf6c12b7a 100644 --- a/setups/srpic/example/pgen.hpp +++ b/setups/srpic/example/pgen.hpp @@ -44,31 +44,31 @@ namespace user { template struct ExtForce { - const std::vector species { 1, 2 }; + const std::vector species { 1, 2 }; ExtForce() = default; - Inline auto fx1(const unsigned short& sp, - const real_t& time, - const coord_t& x_Ph) const -> real_t { + Inline auto fx1(const spidx_t& sp, + const simtime_t& time, + const coord_t& x_Ph) const -> real_t { (void)sp; (void)time; (void)x_Ph; return ZERO; } - Inline auto fx2(const unsigned short& sp, - const real_t& time, - const coord_t& x_Ph) const -> real_t { + Inline auto fx2(const spidx_t& sp, + const simtime_t& time, + const coord_t& x_Ph) const -> real_t { (void)sp; (void)time; (void)x_Ph; return ZERO; } - Inline auto fx3(const unsigned short& sp, - const real_t& time, - const coord_t& x_Ph) const -> real_t { + Inline auto fx3(const spidx_t& sp, + const simtime_t& time, + const coord_t& x_Ph) const -> real_t { (void)sp; (void)time; (void)x_Ph; diff --git a/setups/srpic/langmuir/pgen.hpp b/setups/srpic/langmuir/pgen.hpp index 2a23b17f7..28dbd24c5 100644 --- a/setups/srpic/langmuir/pgen.hpp +++ b/setups/srpic/langmuir/pgen.hpp @@ -37,7 +37,7 @@ namespace user { Inline void operator()(const coord_t& x_Ph, vec_t& v, - unsigned short sp) const override { + spidx_t sp) const override { if (sp == 1) { const auto k = math::sqrt(SQR(kx1) + SQR(kx2) + SQR(kx3)); if constexpr (M::Dim == Dim::_1D) { diff --git a/setups/srpic/shock/pgen.hpp b/setups/srpic/shock/pgen.hpp index 21da63b2e..a5c05b6c6 100644 --- a/setups/srpic/shock/pgen.hpp +++ b/setups/srpic/shock/pgen.hpp @@ -142,9 +142,9 @@ namespace user { // define box to inject into boundaries_t box; // loop over all dimensions - for (unsigned short d { 0 }; d < static_cast(M::Dim); ++d) { + for (auto d { 0u }; d < (unsigned int)M::Dim; ++d) { // compute the range for the x-direction - if (d == static_cast(in::x1)) { + if (d == static_cast(in::x1)) { box.push_back({ xg_min, xg_max }); } else { // inject into full range in other directions @@ -197,8 +197,7 @@ namespace user { // compute the beginning of the injected region const auto xmin = xmax - drift_ux / math::sqrt(1 + SQR(drift_ux)) * dt - - injection_frequency * dt; - + injection_frequency * dt; // define indice range to reset fields boundaries_t incl_ghosts; @@ -224,7 +223,6 @@ namespace user { x_max[d] = extent[d].second; } - Kokkos::parallel_for("ResetFields", CreateRangePolicy(x_min, x_max), arch::SetEMFields_kernel { diff --git a/setups/srpic/turbulence/pgen.hpp b/setups/srpic/turbulence/pgen.hpp index bbd61cc3a..874369306 100644 --- a/setups/srpic/turbulence/pgen.hpp +++ b/setups/srpic/turbulence/pgen.hpp @@ -32,13 +32,12 @@ namespace user { , sx2 { SX2 } , sx3 { SX3 } {} - const std::vector species { 1, 2 }; + const std::vector species { 1, 2 }; ExtForce() = default; - Inline auto fx1(const unsigned short&, - const real_t&, - const coord_t& x_Ph) const -> real_t { + Inline auto fx1(const spidx_t&, const simtime_t&, const coord_t& x_Ph) const + -> real_t { real_t k01 = ONE * constant::TWO_PI / sx1; real_t k02 = ZERO * constant::TWO_PI / sx2; real_t k03 = ZERO * constant::TWO_PI / sx3; @@ -64,9 +63,8 @@ namespace user { math::sin(k21 * x_Ph[0] + k22 * x_Ph[1] + k23 * x_Ph[2])); } - Inline auto fx2(const unsigned short&, - const real_t&, - const coord_t& x_Ph) const -> real_t { + Inline auto fx2(const spidx_t&, const simtime_t&, const coord_t& x_Ph) const + -> real_t { real_t k01 = ONE * constant::TWO_PI / sx1; real_t k02 = ZERO * constant::TWO_PI / sx2; real_t k03 = ZERO * constant::TWO_PI / sx3; @@ -90,9 +88,8 @@ namespace user { // return ZERO; } - Inline auto fx3(const unsigned short&, - const real_t&, - const coord_t& x_Ph) const -> real_t { + Inline auto fx3(const spidx_t&, const simtime_t&, const coord_t& x_Ph) const + -> real_t { real_t k01 = ONE * constant::TWO_PI / sx1; real_t k02 = ZERO * constant::TWO_PI / sx2; real_t k03 = ZERO * constant::TWO_PI / sx3; @@ -148,10 +145,9 @@ namespace user { , SX2 { global_domain.mesh().extent(in::x2).second - global_domain.mesh().extent(in::x2).first } , SX3 { global_domain.mesh().extent(in::x3).second - - global_domain.mesh().extent(in::x3).first } - // , SX1 { 2.0 } - // , SX2 { 2.0 } - // , SX3 { 2.0 } + global_domain.mesh().extent(in::x3).first } // , SX1 { 2.0 } + // , SX2 { 2.0 } + // , SX3 { 2.0 } , temperature { params.template get("problem.temperature", 0.1) } , machno { params.template get("problem.machno", 0.1) } , nmodes { params.template get("setup.nmodes", 6) } @@ -194,8 +190,10 @@ namespace user { { const auto energy_dist = arch::PowerlawDist(local_domain.mesh.metric, - local_domain.random_pool, - 0.1, 100.0, -3.0); + local_domain.random_pool, + 0.1, + 100.0, + -3.0); const auto injector = arch::UniformInjector( energy_dist, { 1, 2 }); @@ -282,9 +280,9 @@ namespace user { // myfile.close(); // if constexpr (D == Dim::_3D) { - + // auto metric = domain.mesh.metric; - + // auto benrg_total = ZERO; // auto EB = domain.fields.em; // Kokkos::parallel_reduce( @@ -323,12 +321,11 @@ namespace user { // vec_t e_XYZ; // metric.template transform(x_Cd, // e_Cntrv, - // e_XYZ); + // e_XYZ); // eenrg += (SQR(e_XYZ[0]) + SQR(e_XYZ[1]) + SQR(e_XYZ[2])); // }, // eenrg_total); // eenrg_total *= params.template get("scales.sigma0") * HALF; - // if (time == 0) { // myfile.open("esqenrg.txt"); @@ -343,4 +340,4 @@ namespace user { } // namespace user -#endif \ No newline at end of file +#endif diff --git a/setups/tests/blob/pgen.hpp b/setups/tests/blob/pgen.hpp index f7b7d71b5..9120e244f 100644 --- a/setups/tests/blob/pgen.hpp +++ b/setups/tests/blob/pgen.hpp @@ -24,7 +24,7 @@ namespace user { Inline void operator()(const coord_t& x_Ph, vec_t& v, - unsigned short sp) const override { + spidx_t sp) const override { v[0] = v_max; } diff --git a/setups/tests/injector/pgen.hpp b/setups/tests/injector/pgen.hpp index 17d7f9398..0b4a34a07 100644 --- a/setups/tests/injector/pgen.hpp +++ b/setups/tests/injector/pgen.hpp @@ -27,7 +27,7 @@ namespace user { Inline void operator()(const coord_t&, vec_t& v_Ph, - unsigned short) const override { + spidx_t) const override { v_Ph[0] = vmax * math::cos(phase); v_Ph[1] = vmax * math::sin(phase); } diff --git a/setups/wip/magpump/pgen.hpp b/setups/wip/magpump/pgen.hpp index 21d4c8882..045552aff 100644 --- a/setups/wip/magpump/pgen.hpp +++ b/setups/wip/magpump/pgen.hpp @@ -68,7 +68,7 @@ namespace user { Inline void operator()(const coord_t&, vec_t& v_Ph, - unsigned short) const override { + spidx_t) const override { v_Ph[0] = -vin; } diff --git a/setups/wip/rec-gravity/pgen.hpp b/setups/wip/rec-gravity/pgen.hpp index a4f927113..e8c461418 100644 --- a/setups/wip/rec-gravity/pgen.hpp +++ b/setups/wip/rec-gravity/pgen.hpp @@ -20,30 +20,30 @@ namespace user { template struct Gravity { - const std::vector species { 1, 2 }; + const std::vector species { 1, 2 }; Gravity(real_t f, real_t tscale, real_t ymid) : force { f } , tscale { tscale } , ymid { ymid } {} - Inline auto fx1(const unsigned short&, const real_t&, const coord_t&) const + Inline auto fx1(const spidx_t&, const simtime_t&, const coord_t&) const -> real_t { return ZERO; } - Inline auto fx2(const unsigned short&, - const real_t& t, - const coord_t& x_Ph) const -> real_t { - const auto sign = (x_Ph[1] < ymid) ? ONE : -ONE; - if (t > tscale) { + Inline auto fx2(const spidx_t&, const simtime_t& t, const coord_t& x_Ph) const + -> real_t { + const auto sign { (x_Ph[1] < ymid) ? ONE : -ONE }; + const auto t_ { static_cast(t) }; + if (t_ > tscale) { return sign * force; } else { - return sign * force * (ONE - math::cos(constant::PI * t / tscale)) / TWO; + return sign * force * (ONE - math::cos(constant::PI * t_ / tscale)) / TWO; } } - Inline auto fx3(const unsigned short&, const real_t&, const coord_t&) const + Inline auto fx3(const spidx_t&, const simtime_t&, const coord_t&) const -> real_t { return ZERO; } @@ -69,27 +69,19 @@ namespace user { template struct InitFields { - InitFields(real_t Bmag, real_t width, real_t angle, real_t y1, real_t y2) + InitFields(real_t Bmag, real_t width, real_t y1, real_t y2) : Bmag { Bmag } , width { width } - , angle { angle } , y1 { y1 } , y2 { y2 } {} - Inline auto bx1(const coord_t& x_Ph) const -> real_t { - return Bmag * math::cos(angle) * - (math::tanh((x_Ph[1] - y1) / width) - - math::tanh((x_Ph[1] - y2) / width) - 1); - } - Inline auto bx3(const coord_t& x_Ph) const -> real_t { - return Bmag * math::sin(angle) * - (math::tanh((x_Ph[1] - y1) / width) - - math::tanh((x_Ph[1] - y2) / width) - 1); + return Bmag * (math::tanh((x_Ph[1] - y1) / width) - + math::tanh((x_Ph[1] - y2) / width) - 1); } private: - const real_t Bmag, width, angle, y1, y2; + const real_t Bmag, width, y1, y2; }; template @@ -106,7 +98,7 @@ namespace user { using arch::ProblemGenerator::C; using arch::ProblemGenerator::params; - const real_t Bmag, width, angle, overdensity, y1, y2, bg_temp; + const real_t Bmag, width, overdensity, y1, y2, bg_temp; InitFields init_flds; Gravity ext_force; @@ -115,18 +107,18 @@ namespace user { : arch::ProblemGenerator(p) , Bmag { p.template get("setup.Bmag", 1.0) } , width { p.template get("setup.width") } - , angle { p.template get("setup.angle") } , overdensity { p.template get("setup.overdensity") } + , bg_temp { p.template get("setup.bg_temp") } , y1 { m.mesh().extent(in::x2).first + INV_4 * (m.mesh().extent(in::x2).second - m.mesh().extent(in::x2).first) } , y2 { m.mesh().extent(in::x2).first + 3 * INV_4 * (m.mesh().extent(in::x2).second - m.mesh().extent(in::x2).first) } - , init_flds { Bmag, width, angle, y1, y2 } - , bg_temp { p.template get("setup.bg_temp") } + , init_flds { Bmag, width, y1, y2 } , ext_force { - p.template get("setup.fmag", 0.1), + p.template get("setup.fmag", 0.1) * + p.template get("scales.omegaB0"), (m.mesh().extent(in::x1).second - m.mesh().extent(in::x1).first), INV_2 * (m.mesh().extent(in::x2).second + m.mesh().extent(in::x2).first) } {} @@ -144,65 +136,36 @@ namespace user { arch::InjectUniform(params, local_domain, injector, - HALF); - // record npart - const auto npart1 = local_domain.species[0].npart(); - const auto npart2 = local_domain.species[1].npart(); - + ONE); + // current layers const auto sigma = params.template get("scales.sigma0"); const auto c_omp = params.template get("scales.skindepth0"); const auto cs_drift_beta = math::sqrt(sigma) * c_omp / (width * overdensity); const auto cs_drift_gamma = ONE / math::sqrt(ONE - SQR(cs_drift_beta)); const auto cs_drift_u = cs_drift_beta * cs_drift_gamma; const auto cs_temp = HALF * sigma / overdensity; - // current layer #1 - auto edist_cs_1 = arch::Maxwellian(local_domain.mesh.metric, + + for (auto i = 0; i < 2; ++i) { + const auto drift_vel = (i == 0) ? cs_drift_u : -cs_drift_u; + const auto y_cs = (i == 0) ? y1 : y2; + auto edist_cs = arch::Maxwellian(local_domain.mesh.metric, local_domain.random_pool, cs_temp, - cs_drift_u, - in::x3, + drift_vel, + in::x1, false); - const auto sdist_cs_1 = CurrentLayer(local_domain.mesh.metric, width, y1); - const auto inj_cs_1 = arch::NonUniformInjector( - edist_cs_1, - sdist_cs_1, - { 1, 2 }); - arch::InjectNonUniform(params, - local_domain, - inj_cs_1, - overdensity); - // current layer #2 - const auto edist_cs_2 = arch::Maxwellian(local_domain.mesh.metric, - local_domain.random_pool, - cs_temp, - -cs_drift_u, - in::x3, - false); - const auto sdist_cs_2 = CurrentLayer(local_domain.mesh.metric, width, y2); - const auto inj_cs_2 = arch::NonUniformInjector( - edist_cs_2, - sdist_cs_2, - { 1, 2 }); - arch::InjectNonUniform(params, + const auto sdist_cs = CurrentLayer(local_domain.mesh.metric, + width, + y_cs); + const auto inj_cs = arch::NonUniformInjector( + edist_cs, + sdist_cs, + { 1, 2 }); + arch::InjectNonUniform(params, local_domain, - inj_cs_2, + inj_cs, overdensity); - auto ux1_1 = local_domain.species[0].ux1; - auto ux3_1 = local_domain.species[0].ux3; - auto ux1_2 = local_domain.species[1].ux1; - auto ux3_2 = local_domain.species[1].ux3; - Kokkos::parallel_for( - "TurnParticles", - CreateRangePolicy({ npart1 }, { local_domain.species[0].npart() }), - ClassLambda(index_t p) { - auto ux1_ = ux1_1(p), ux3_ = ux3_1(p); - ux1_1(p) = math::cos(angle) * ux1_ - math::sin(angle) * ux3_; - ux3_1(p) = math::sin(angle) * ux1_ + math::cos(angle) * ux3_; - - ux1_ = ux1_2(p), ux3_ = ux3_2(p); - ux1_2(p) = math::cos(angle) * ux1_ - math::sin(angle) * ux3_; - ux3_2(p) = math::sin(angle) * ux1_ + math::cos(angle) * ux3_; - }); + } } // namespace user }; diff --git a/setups/wip/rec-gravity/rec-gravity.toml b/setups/wip/rec-gravity/rec-gravity.toml index f8d5b94ee..f29b090e3 100644 --- a/setups/wip/rec-gravity/rec-gravity.toml +++ b/setups/wip/rec-gravity/rec-gravity.toml @@ -1,21 +1,21 @@ [simulation] - name = "rec-gravity" - engine = "srpic" + name = "rec-gravity" + engine = "srpic" runtime = 20.0 [grid] resolution = [2000, 4000] - extent = [[-0.5, 0.5], [-1.0, 1.0]] + extent = [[-0.5, 0.5], [-1.0, 1.0]] [grid.metric] metric = "minkowski" [grid.boundaries] - fields = [["PERIODIC"], ["PERIODIC"]] + fields = [["PERIODIC"], ["PERIODIC"]] particles = [["PERIODIC"], ["PERIODIC"]] - + [scales] - larmor0 = 3.1e-4 + larmor0 = 3.1e-4 skindepth0 = 1e-3 [algorithms] @@ -28,26 +28,26 @@ ppc0 = 8.0 [[particles.species]] - label = "e-" - mass = 1.0 - charge = -1.0 + label = "e-" + mass = 1.0 + charge = -1.0 maxnpart = 1e8 [[particles.species]] - label = "e+" - mass = 1.0 - charge = 1.0 + label = "e+" + mass = 1.0 + charge = 1.0 maxnpart = 1e8 [setup] - Bmag = 1.0 - width = 0.04 - bg_temp = 1e-4 + Bmag = 1.0 + width = 0.04 + bg_temp = 1e-4 overdensity = 3.0 - angle = 0.0 - + angle = 0.0 + [output] - format = "hdf5" + format = "hdf5" interval_time = 0.36 [output.fields] diff --git a/setups/wip/reconnection/pgen.hpp b/setups/wip/reconnection/pgen.hpp index 7ae550756..70bab7b32 100644 --- a/setups/wip/reconnection/pgen.hpp +++ b/setups/wip/reconnection/pgen.hpp @@ -269,7 +269,7 @@ namespace user { auto scatter_buff = Kokkos::Experimental::create_scatter_view( domain.fields.buff); Kokkos::deep_copy(domain.fields.buff, ZERO); - for (const auto sp : std::vector { 1, 2 }) { + for (const auto sp : std::vector { 1, 2 }) { const auto& prtl_spec = domain.species[sp - 1]; // clang-format off Kokkos::parallel_for( diff --git a/src/archetypes/energy_dist.h b/src/archetypes/energy_dist.h index 231ea5b0b..40e4a432f 100644 --- a/src/archetypes/energy_dist.h +++ b/src/archetypes/energy_dist.h @@ -45,7 +45,7 @@ namespace arch { // last argument -- is the species index (1, ..., nspec) Inline virtual void operator()(const coord_t&, vec_t& v, - unsigned short = 0) const { + spidx_t = 0) const { v[0] = ZERO; v[1] = ZERO; v[2] = ZERO; @@ -61,7 +61,7 @@ namespace arch { Inline void operator()(const coord_t&, vec_t& v, - unsigned short = 0) const override { + spidx_t = 0) const override { v[0] = ZERO; v[1] = ZERO; v[2] = ZERO; @@ -85,7 +85,7 @@ namespace arch { Inline void operator()(const coord_t& x_Code, vec_t& v, - unsigned short = 0) const override { + spidx_t = 0) const override { auto rand_gen = pool.get_state(); auto rand_X1 = Random(rand_gen); auto rand_gam = ONE; @@ -210,7 +210,7 @@ namespace arch { // Boost a symmetric distribution to a relativistic speed using flipping // method https://arxiv.org/pdf/1504.03910.pdf Inline void boost(vec_t& v) const { - const auto boost_dir = static_cast(boost_direction); + const auto boost_dir = static_cast(boost_direction); const auto boost_beta { boost_velocity / math::sqrt(ONE + SQR(boost_velocity)) }; const auto gamma { U2GAMMA(v[0], v[1], v[2]) }; @@ -225,7 +225,7 @@ namespace arch { Inline void operator()(const coord_t& x_Code, vec_t& v, - unsigned short sp = 0) const override { + spidx_t sp = 0) const override { if (cmp::AlmostZero(temperature)) { v[0] = ZERO; v[1] = ZERO; diff --git a/src/archetypes/particle_injector.h b/src/archetypes/particle_injector.h index 88b0db58b..aaccaeecf 100644 --- a/src/archetypes/particle_injector.h +++ b/src/archetypes/particle_injector.h @@ -44,7 +44,6 @@ namespace arch { using namespace ntt; - using spidx_t = unsigned short; template class ED> struct UniformInjector { @@ -141,12 +140,12 @@ namespace arch { using UniformInjector::D; using UniformInjector::C; - const unsigned short density_buff_idx; + const idx_t density_buff_idx; boundaries_t probe_box; KeepConstantInjector(const energy_dist_t& energy_dist, const std::pair& species, - unsigned short density_buff_idx, + idx_t density_buff_idx, boundaries_t box = {}) : UniformInjector { energy_dist, species } , density_buff_idx { density_buff_idx } { @@ -296,7 +295,7 @@ namespace arch { if constexpr ((O == in::x1) or (O == in::x2 and (M::Dim == Dim::_2D or M::Dim == Dim::_3D)) or (O == in::x3 and M::Dim == Dim::_3D)) { - const auto xi = x_Ph[static_cast(O)]; + const auto xi = x_Ph[static_cast(O)]; if constexpr (P) { // + direction if (xi < xsurf - ds or xi >= xsurf) { @@ -373,7 +372,7 @@ namespace arch { if constexpr ((O == in::x1) or (O == in::x2 and (M::Dim == Dim::_2D or M::Dim == Dim::_3D)) or (O == in::x3 and M::Dim == Dim::_3D)) { - const auto xi = x_Ph[static_cast(O)]; + const auto xi = x_Ph[static_cast(O)]; // + direction if (xi < xdrift or xi >= xinj) { return ZERO; diff --git a/src/archetypes/spatial_dist.h b/src/archetypes/spatial_dist.h index d036c0166..225c66eb5 100644 --- a/src/archetypes/spatial_dist.h +++ b/src/archetypes/spatial_dist.h @@ -53,14 +53,14 @@ namespace arch { struct Replenish : public SpatialDistribution { using SpatialDistribution::metric; const ndfield_t density; - const unsigned short idx; + const idx_t idx; const T target_density; const real_t target_max_density; Replenish(const M& metric, const ndfield_t& density, - unsigned short idx, + idx_t idx, const T& target_density, real_t target_max_density) : SpatialDistribution { metric } diff --git a/src/archetypes/tests/energy_dist.cpp b/src/archetypes/tests/energy_dist.cpp index bad1d0eb9..0d3fc8023 100644 --- a/src/archetypes/tests/energy_dist.cpp +++ b/src/archetypes/tests/energy_dist.cpp @@ -27,7 +27,7 @@ struct Caller { Inline void operator()(index_t) const { vec_t vp { ZERO }; coord_t xp { ZERO }; - for (unsigned short d = 0; d < D; ++d) { + for (dim_t d { 0u }; d < D; ++d) { xp[d] = 5.0; } dist(xp, vp); @@ -54,13 +54,13 @@ void testEnergyDist(const std::vector& res, if constexpr (M::Dim == Dim::_2D) { extent = { ext[0], - {ZERO, constant::PI} + { ZERO, constant::PI } }; } else if constexpr (M::Dim == Dim::_3D) { extent = { ext[0], - {ZERO, constant::PI}, - {ZERO, constant::TWO_PI} + { ZERO, constant::PI }, + { ZERO, constant::TWO_PI } }; } } diff --git a/src/archetypes/tests/powerlaw.cpp b/src/archetypes/tests/powerlaw.cpp index dfcb6b247..58df1f4cf 100644 --- a/src/archetypes/tests/powerlaw.cpp +++ b/src/archetypes/tests/powerlaw.cpp @@ -31,7 +31,7 @@ struct Caller { Inline void operator()(index_t) const { vec_t vp { ZERO }; coord_t xp { ZERO }; - for (unsigned short d = 0; d < D; ++d) { + for (dim_t d { 0u }; d < D; ++d) { xp[d] = 2.0; } dist(xp, vp); @@ -73,13 +73,13 @@ void testEnergyDist(const std::vector& res, if constexpr (M::Dim == Dim::_2D) { extent = { ext[0], - {ZERO, constant::PI} + { ZERO, constant::PI } }; } else if constexpr (M::Dim == Dim::_3D) { extent = { ext[0], - {ZERO, constant::PI}, - {ZERO, constant::TWO_PI} + { ZERO, constant::PI }, + { ZERO, constant::TWO_PI } }; } } diff --git a/src/archetypes/tests/spatial_dist.cpp b/src/archetypes/tests/spatial_dist.cpp index 5ab64a156..232ab1eb7 100644 --- a/src/archetypes/tests/spatial_dist.cpp +++ b/src/archetypes/tests/spatial_dist.cpp @@ -80,7 +80,7 @@ struct RadialDist : public SpatialDistribution { coord_t x_Sph { ZERO }; metric.template convert(x_Code, x_Sph); auto r { ZERO }; - for (unsigned short d = 0; d < M::Dim; ++d) { + for (dim_t d { 0u }; d < M::Dim; ++d) { r += SQR(x_Sph[d]); } return math::sqrt(r); @@ -91,14 +91,14 @@ auto main(int argc, char* argv[]) -> int { Kokkos::initialize(argc, argv); try { Minkowski m1 { - { 10, 10}, - {{ -10.0, 55.0 }, { -10.0, 55.0 }} + { 10, 10 }, + { { -10.0, 55.0 }, { -10.0, 55.0 } } }; RadialDist> r1 { m1 }; Minkowski m2 { - { 10, 10, 30}, - {{ -1.0, 1.0 }, { -1.0, 1.0 }, { -3.0, 3.0 }} + { 10, 10, 30 }, + { { -1.0, 1.0 }, { -1.0, 1.0 }, { -3.0, 3.0 } } }; RadialDist> r2 { m2 }; diff --git a/src/checkpoint/reader.cpp b/src/checkpoint/reader.cpp index 6e32cb3b9..24aa0f079 100644 --- a/src/checkpoint/reader.cpp +++ b/src/checkpoint/reader.cpp @@ -42,7 +42,7 @@ namespace checkpoint { auto ReadParticleCount(adios2::IO& io, adios2::Engine& reader, - unsigned short s, + spidx_t s, std::size_t local_dom, std::size_t ndomains) -> std::pair { logger::Checkpoint(fmt::format("Reading particle count for: %d", s + 1), HERE); @@ -85,7 +85,7 @@ namespace checkpoint { void ReadParticleData(adios2::IO& io, adios2::Engine& reader, const std::string& quantity, - unsigned short s, + spidx_t s, array_t& array, npart_t count, npart_t offset) { @@ -110,7 +110,7 @@ namespace checkpoint { void ReadParticlePayloads(adios2::IO& io, adios2::Engine& reader, - unsigned short s, + spidx_t s, array_t& array, std::size_t nplds, npart_t count, @@ -164,28 +164,28 @@ namespace checkpoint { template void ReadParticleData(adios2::IO&, adios2::Engine&, const std::string&, - unsigned short, + spidx_t, array_t&, npart_t, npart_t); template void ReadParticleData(adios2::IO&, adios2::Engine&, const std::string&, - unsigned short, + spidx_t, array_t&, npart_t, npart_t); template void ReadParticleData(adios2::IO&, adios2::Engine&, const std::string&, - unsigned short, + spidx_t, array_t&, npart_t, npart_t); template void ReadParticleData(adios2::IO&, adios2::Engine&, const std::string&, - unsigned short, + spidx_t, array_t&, npart_t, npart_t); diff --git a/src/checkpoint/reader.h b/src/checkpoint/reader.h index 883a1d125..7939ba82b 100644 --- a/src/checkpoint/reader.h +++ b/src/checkpoint/reader.h @@ -32,7 +32,7 @@ namespace checkpoint { auto ReadParticleCount(adios2::IO&, adios2::Engine&, - unsigned short, + spidx_t, std::size_t, std::size_t) -> std::pair; @@ -40,14 +40,14 @@ namespace checkpoint { void ReadParticleData(adios2::IO&, adios2::Engine&, const std::string&, - unsigned short, + spidx_t, array_t&, npart_t, npart_t); void ReadParticlePayloads(adios2::IO&, adios2::Engine&, - unsigned short, + spidx_t, array_t&, std::size_t, npart_t, diff --git a/src/engines/srpic.hpp b/src/engines/srpic.hpp index a25df3fab..cd8952b42 100644 --- a/src/engines/srpic.hpp +++ b/src/engines/srpic.hpp @@ -569,7 +569,7 @@ namespace ntt { size[2] = domain.mesh.n_active(in::x3); } // !TODO: this needs to be done more efficiently - for (unsigned short i = 0; i < nfilter; ++i) { + for (auto i { 0u }; i < nfilter; ++i) { Kokkos::deep_copy(domain.fields.buff, domain.fields.cur); Kokkos::parallel_for("CurrentsFilter", range, @@ -635,8 +635,8 @@ namespace ntt { } boundaries_t box; boundaries_t incl_ghosts; - for (unsigned short d { 0 }; d < M::Dim; ++d) { - if (d == static_cast(dim)) { + for (dim_t d { 0 }; d < M::Dim; ++d) { + if (d == static_cast(dim)) { box.push_back({ xg_min, xg_max }); if (sign > 0) { incl_ghosts.push_back({ false, true }); @@ -808,7 +808,7 @@ namespace ntt { } std::vector xi_min, xi_max; const std::vector all_dirs { in::x1, in::x2, in::x3 }; - for (unsigned short d { 0 }; d < static_cast(M::Dim); ++d) { + for (dim_t d { 0u }; d < M::Dim; ++d) { const auto dd = all_dirs[d]; if (dim == dd) { if (sign > 0) { // + direction @@ -907,7 +907,7 @@ namespace ntt { const std::vector all_dirs { in::x1, in::x2, in::x3 }; - for (unsigned short d { 0 }; d < static_cast(M::Dim); ++d) { + for (auto d { 0u }; d < M::Dim; ++d) { const auto dd = all_dirs[d]; if (dim == dd) { xi_min.push_back(0); @@ -1015,10 +1015,10 @@ namespace ntt { */ if constexpr (traits::has_member::value) { const auto [sign, dim, xg_min, xg_max] = get_atm_extent(direction); - const auto dd = static_cast(dim); + const auto dd = static_cast(dim); boundaries_t box; boundaries_t incl_ghosts; - for (unsigned short d { 0 }; d < M::Dim; ++d) { + for (auto d { 0u }; d < M::Dim; ++d) { if (d == dd) { box.push_back({ xg_min, xg_max }); if (sign > 0) { @@ -1038,7 +1038,7 @@ namespace ntt { tuple_t range_min { 0 }; tuple_t range_max { 0 }; - for (unsigned short d { 0 }; d < M::Dim; ++d) { + for (auto d { 0u }; d < M::Dim; ++d) { range_min[d] = intersect_range[d].first; range_max[d] = intersect_range[d].second; } @@ -1165,9 +1165,8 @@ namespace ntt { "grid.boundaries.atmosphere.temperature"); const auto height = m_params.template get( "grid.boundaries.atmosphere.height"); - const auto species = - m_params.template get>( - "grid.boundaries.atmosphere.species"); + const auto species = m_params.template get>( + "grid.boundaries.atmosphere.species"); const auto nmax = m_params.template get( "grid.boundaries.atmosphere.density"); @@ -1200,7 +1199,7 @@ namespace ntt { } } else { for (const auto& sp : - std::vector({ species.first, species.second })) { + std::vector { species.first, species.second }) { auto& prtl_spec = domain.species[sp - 1]; if (prtl_spec.npart() == 0) { continue; diff --git a/src/framework/containers/particles.cpp b/src/framework/containers/particles.cpp index 2f59a004d..b69e48de4 100644 --- a/src/framework/containers/particles.cpp +++ b/src/framework/containers/particles.cpp @@ -21,7 +21,7 @@ namespace ntt { template - Particles::Particles(unsigned short index, + Particles::Particles(spidx_t index, const std::string& label, float m, float ch, diff --git a/src/framework/containers/particles.h b/src/framework/containers/particles.h index 5241822e2..8ff74be33 100644 --- a/src/framework/containers/particles.h +++ b/src/framework/containers/particles.h @@ -80,7 +80,7 @@ namespace ntt { * @param cooling The cooling mechanism assigned for the species * @param npld The number of payloads for the species */ - Particles(unsigned short index, + Particles(spidx_t index, const std::string& label, float m, float ch, diff --git a/src/framework/containers/species.h b/src/framework/containers/species.h index 6dd437819..ada0282e2 100644 --- a/src/framework/containers/species.h +++ b/src/framework/containers/species.h @@ -20,15 +20,15 @@ namespace ntt { class ParticleSpecies { protected: // Species index - const unsigned short m_index; + const spidx_t m_index; // Species label - const std::string m_label; + const std::string m_label; // Species mass in units of m0 - const float m_mass; + const float m_mass; // Species charge in units of q0 - const float m_charge; + const float m_charge; // Max number of allocated particles for the species - npart_t m_maxnpart; + npart_t m_maxnpart; // Pusher assigned for the species const PrtlPusher m_pusher; @@ -44,7 +44,7 @@ namespace ntt { public: ParticleSpecies() - : m_index { 0 } + : m_index { 0u } , m_label { "" } , m_mass { 0.0 } , m_charge { 0.0 } @@ -64,7 +64,7 @@ namespace ntt { * @param maxnpart The maximum number of allocated particles for the species. * @param pusher The pusher assigned for the species. */ - ParticleSpecies(unsigned short index, + ParticleSpecies(spidx_t index, const std::string& label, float m, float ch, @@ -91,7 +91,7 @@ namespace ntt { ~ParticleSpecies() = default; [[nodiscard]] - auto index() const -> unsigned short { + auto index() const -> spidx_t { return m_index; } diff --git a/src/framework/domain/checkpoint.cpp b/src/framework/domain/checkpoint.cpp index 978a1ad10..656ff57d0 100644 --- a/src/framework/domain/checkpoint.cpp +++ b/src/framework/domain/checkpoint.cpp @@ -307,7 +307,7 @@ namespace ntt { range3, domain.fields.cur0); } - for (auto s { 0u }; s < (unsigned short)(domain.species.size()); ++s) { + for (auto s { 0u }; s < domain.species.size(); ++s) { const auto [loc_npart, offset_npart] = checkpoint::ReadParticleCount(io, reader, s, ldidx, ndomains()); raise::ErrorIf(loc_npart > domain.species[s].maxnpart(), diff --git a/src/framework/domain/comm_mpi.hpp b/src/framework/domain/comm_mpi.hpp index d9783bdb6..fbeb7ecde 100644 --- a/src/framework/domain/comm_mpi.hpp +++ b/src/framework/domain/comm_mpi.hpp @@ -131,7 +131,7 @@ namespace comm { } else { ncells_t nsend { comps.second - comps.first }, nrecv { comps.second - comps.first }; - ndarray_t(D) + 1> send_fld, recv_fld; + ndarray_t(D) + 1> send_fld, recv_fld; for (short d { 0 }; d < (short)D; ++d) { if (send_rank >= 0) { diff --git a/src/framework/domain/grid.cpp b/src/framework/domain/grid.cpp index c022184b1..ddbfc38f0 100644 --- a/src/framework/domain/grid.cpp +++ b/src/framework/domain/grid.cpp @@ -51,7 +51,7 @@ namespace ntt { template auto Grid::rangeCells(const box_region_t& region) const -> range_t { tuple_t imin, imax; - for (unsigned short i = 0; i < (unsigned short)D; i++) { + for (auto i { 0u }; i < D; i++) { switch (region[i]) { case CellLayer::allLayer: imin[i] = 0; @@ -86,10 +86,10 @@ namespace ntt { } template - auto Grid::rangeCellsOnHost( - const box_region_t& region) const -> range_h_t { + auto Grid::rangeCellsOnHost(const box_region_t& region) const + -> range_h_t { tuple_t imin, imax; - for (unsigned short i = 0; i < (unsigned short)D; i++) { + for (auto i { 0u }; i < D; i++) { switch (region[i]) { case CellLayer::allLayer: imin[i] = 0; @@ -163,10 +163,10 @@ namespace ntt { } template - auto Grid::rangeCells( - const tuple_t, D>& ranges) const -> range_t { + auto Grid::rangeCells(const tuple_t, D>& ranges) const + -> range_t { tuple_t imin, imax; - for (unsigned short i = 0; i < (unsigned short)D; i++) { + for (auto i { 0u }; i < D; i++) { raise::ErrorIf((ranges[i][0] < -(int)N_GHOSTS) || (ranges[i][1] > (int)N_GHOSTS), "Invalid cell layer picked", diff --git a/src/framework/domain/metadomain.cpp b/src/framework/domain/metadomain.cpp index 8952d417d..fc3c59d4c 100644 --- a/src/framework/domain/metadomain.cpp +++ b/src/framework/domain/metadomain.cpp @@ -140,7 +140,7 @@ namespace ntt { boundaries_t l_extent; coord_t low_corner_Code { ZERO }, up_corner_Code { ZERO }; coord_t low_corner_Phys { ZERO }, up_corner_Phys { ZERO }; - for (unsigned short d { 0 }; d < (unsigned short)D; ++d) { + for (auto d { 0u }; d < D; d++) { low_corner_Code[d] = (real_t)l_offset_ncells[d]; up_corner_Code[d] = (real_t)(l_offset_ncells[d] + l_ncells[d]); } diff --git a/src/framework/domain/output.cpp b/src/framework/domain/output.cpp index 071618860..36ea4249b 100644 --- a/src/framework/domain/output.cpp +++ b/src/framework/domain/output.cpp @@ -84,12 +84,12 @@ namespace ntt { custom_fields_to_write.begin(), custom_fields_to_write.end(), std::back_inserter(all_fields_to_write)); - const auto species_to_write = params.template get>( + const auto species_to_write = params.template get>( "output.particles.species"); g_writer.defineFieldOutputs(S, all_fields_to_write); g_writer.defineParticleOutputs(M::PrtlDim, species_to_write); // spectra write all particle species - std::vector spectra_species {}; + std::vector spectra_species {}; for (const auto& sp : species_params()) { spectra_species.push_back(sp.index()); } @@ -112,11 +112,11 @@ namespace ntt { void ComputeMoments(const SimulationParams& params, const Mesh& mesh, const std::vector>& prtl_species, - const std::vector& species, + const std::vector& species, const std::vector& components, ndfield_t& buffer, - unsigned short buff_idx) { - std::vector specs = species; + idx_t buff_idx) { + std::vector specs = species; if (specs.size() == 0) { // if no species specified, take all massive species for (auto& sp : prtl_species) { @@ -164,7 +164,7 @@ namespace ntt { ndfield_t& fld_to, const range_tuple_t& from, const range_tuple_t& to) { - for (unsigned short d = 0; d < D; ++d) { + for (auto d { 0u }; d < D; ++d) { raise::ErrorIf(fld_from.extent(d) != fld_to.extent(d), "Fields have different sizes " + std::to_string(fld_from.extent(d)) + @@ -227,7 +227,7 @@ namespace ntt { const auto dwn = params.template get>( "output.fields.downsampling"); - for (unsigned short dim = 0; dim < M::Dim; ++dim) { + for (auto dim { 0u }; dim < M::Dim; ++dim) { const auto l_size = local_domain->mesh.n_active()[dim]; const auto l_offset = local_domain->offset_ncells()[dim]; const auto g_size = mesh().n_active()[dim]; @@ -289,7 +289,7 @@ namespace ntt { if (fld.is_moment()) { // output a particle distribution moment (single component) // this includes T, Rho, Charge, N, Nppc - const auto c = static_cast(addresses.back()); + const auto c = static_cast(addresses.back()); if (fld.id() == FldsID::T) { raise::ErrorIf(fld.comp.size() != 1, "Wrong # of components requested for T output", @@ -373,7 +373,7 @@ namespace ntt { } if (fld.is_moment()) { for (auto i = 0; i < 3; ++i) { - const auto c = static_cast(addresses[i]); + const auto c = static_cast(addresses[i]); if (fld.id() == FldsID::T) { raise::ErrorIf(fld.comp[i].size() != 2, "Wrong # of components requested for moment", @@ -481,8 +481,8 @@ namespace ntt { if (not output_asis) { // copy fields from bckp(:, 0, 1, 2) -> bckp(:, 3, 4, 5) // converting to proper basis and properly interpolating - list_t comp_from = { 0, 1, 2 }; - list_t comp_to = { 3, 4, 5 }; + list_t comp_from = { 0, 1, 2 }; + list_t comp_to = { 3, 4, 5 }; DeepCopyFields(local_domain->fields.bckp, local_domain->fields.bckp, { 0, 3 }, @@ -505,7 +505,7 @@ namespace ntt { for (auto i = 0; i < 6; ++i) { names.push_back(fld.name(i)); addresses.push_back(i); - const auto c = static_cast(addresses.back()); + const auto c = static_cast(addresses.back()); raise::ErrorIf(fld.comp[i].size() != 2, "Wrong # of components requested for moment", HERE); diff --git a/src/framework/parameters.cpp b/src/framework/parameters.cpp index 79f8e333e..7c53d82a5 100644 --- a/src/framework/parameters.cpp +++ b/src/framework/parameters.cpp @@ -38,7 +38,7 @@ namespace ntt { const auto metric = M(resolution, extent, params); const auto dx0 = metric.dxMin(); coord_t x_corner { ZERO }; - for (unsigned short d { 0 }; d < (unsigned short)(M::Dim); ++d) { + for (auto d { 0u }; d < M::Dim; ++d) { x_corner[d] = HALF; } const auto V0 = metric.sqrt_det_h(x_corner); @@ -184,7 +184,7 @@ namespace ntt { toml::array {}); set("particles.nspec", species_tab.size()); - unsigned short idx = 1; + spidx_t idx = 1; for (const auto& sp : species_tab) { const auto label = toml::find_or(sp, "label", @@ -265,7 +265,7 @@ namespace ntt { } raise::ErrorIf(extent.size() != dim, "invalid inferred `grid.extent`", HERE); boundaries_t extent_pairwise; - for (unsigned short d = 0; d < (unsigned short)dim; ++d) { + for (auto d { 0u }; d < (dim_t)dim; ++d) { raise::ErrorIf(extent[d].size() != 2, fmt::format("invalid inferred `grid.extent[%d]`", d), HERE); @@ -504,10 +504,10 @@ namespace ntt { set("output.fields.downsampling", field_dwn); // particles - auto all_specs = std::vector {}; + auto all_specs = std::vector {}; const auto nspec = get("particles.nspec"); for (auto i = 0u; i < nspec; ++i) { - all_specs.push_back(static_cast(i + 1)); + all_specs.push_back(static_cast(i + 1)); } const auto prtl_out = toml::find_or(toml_data, "output", @@ -615,7 +615,7 @@ namespace ntt { raise::ErrorIf(prtl_bc.size() != (std::size_t)dim, "invalid `grid.boundaries.particles`", HERE); - for (unsigned short d = 0; d < (unsigned short)dim; ++d) { + for (auto d { 0u }; d < (dim_t)dim; ++d) { flds_bc_enum.push_back({}); prtl_bc_enum.push_back({}); const auto fbc = flds_bc[d]; @@ -717,7 +717,7 @@ namespace ntt { HERE); boundaries_t flds_bc_pairwise; boundaries_t prtl_bc_pairwise; - for (unsigned short d = 0; d < (unsigned short)dim; ++d) { + for (auto d { 0u }; d < (dim_t)dim; ++d) { raise::ErrorIf( flds_bc_enum[d].size() != 2, fmt::format("invalid inferred `grid.boundaries.fields[%d]`", d), @@ -847,7 +847,7 @@ namespace ntt { toml::find_or(toml_data, "grid", "boundaries", "atmosphere", "ds", ZERO)); set("grid.boundaries.atmosphere.height", atm_h); set("grid.boundaries.atmosphere.g", atm_T / atm_h); - const auto atm_species = toml::find>( + const auto atm_species = toml::find>( toml_data, "grid", "boundaries", diff --git a/src/framework/tests/grid_mesh.cpp b/src/framework/tests/grid_mesh.cpp index 4dea275ce..952d9874d 100644 --- a/src/framework/tests/grid_mesh.cpp +++ b/src/framework/tests/grid_mesh.cpp @@ -21,27 +21,26 @@ auto main(int argc, char* argv[]) -> int { using namespace metric; const auto res = std::vector { 10, 10, 10 }; const auto ext = boundaries_t { - {-1.0, 1.0}, - {-1.0, 1.0}, - {-1.0, 1.0} + { -1.0, 1.0 }, + { -1.0, 1.0 }, + { -1.0, 1.0 } }; auto mesh = Mesh>(res, ext, {}); for (const auto& d : { in::x1, in::x2, in::x3 }) { raise::ErrorIf(mesh.i_min(d) != N_GHOSTS, "i_min != N_GHOSTS", HERE); - raise::ErrorIf(mesh.i_max(d) != res[(unsigned short)d] + N_GHOSTS, + raise::ErrorIf(mesh.i_max(d) != res[(dim_t)d] + N_GHOSTS, "i_max != res+N_GHOSTS", HERE); - raise::ErrorIf(mesh.n_active(d) != res[(unsigned short)d], - "n_active != res", - HERE); - raise::ErrorIf(mesh.n_all(d) != res[(unsigned short)d] + 2 * N_GHOSTS, + raise::ErrorIf(mesh.n_active(d) != res[(dim_t)d], "n_active != res", HERE); + raise::ErrorIf(mesh.n_all(d) != res[(dim_t)d] + 2 * N_GHOSTS, "n_all != res+2*N_GHOSTS", HERE); - raise::ErrorIf(mesh.extent(d) != ext[(unsigned short)d], "extent != ext", HERE); + raise::ErrorIf(mesh.extent(d) != ext[(dim_t)d], "extent != ext", HERE); } - raise::ErrorIf(not cmp::AlmostEqual(mesh.metric.dxMin(), (real_t)(0.2 / std::sqrt(3.0))), - "dxMin wrong", - HERE); + raise::ErrorIf( + not cmp::AlmostEqual(mesh.metric.dxMin(), (real_t)(0.2 / std::sqrt(3.0))), + "dxMin wrong", + HERE); } catch (const std::exception& e) { std::cerr << e.what() << std::endl; Kokkos::finalize(); diff --git a/src/global/arch/directions.h b/src/global/arch/directions.h index 2ea009814..5f8281ed3 100644 --- a/src/global/arch/directions.h +++ b/src/global/arch/directions.h @@ -50,14 +50,14 @@ namespace dir { auto operator-() const -> direction_t { auto result = direction_t {}; - for (auto i = 0u; i < (unsigned short)D; ++i) { + for (auto i { 0u }; i < D; ++i) { result[i] = -(*this)[i]; } return result; } auto operator==(const direction_t& other) const -> bool { - for (auto i = 0u; i < (unsigned short)D; ++i) { + for (auto i { 0u }; i < D; ++i) { if ((*this)[i] != other[i]) { return false; } @@ -132,8 +132,8 @@ namespace dir { using dirs_t = std::vector>; template - inline auto operator<<(std::ostream& os, - const direction_t& dir) -> std::ostream& { + inline auto operator<<(std::ostream& os, const direction_t& dir) + -> std::ostream& { for (auto& d : dir) { os << std::setw(2) << std::left; if (d > 0) { diff --git a/src/global/global.h b/src/global/global.h index 577b13f1a..5296d8ac7 100644 --- a/src/global/global.h +++ b/src/global/global.h @@ -351,6 +351,8 @@ using npart_t = unsigned long long int; // index/number using index_t = const std::size_t; using idx_t = unsigned short; +using spidx_t = unsigned short; +using dim_t = unsigned short; using range_tuple_t = std::pair; diff --git a/src/kernels/fields_bcs.hpp b/src/kernels/fields_bcs.hpp index 782200e29..0a5dc6168 100644 --- a/src/kernels/fields_bcs.hpp +++ b/src/kernels/fields_bcs.hpp @@ -36,8 +36,7 @@ namespace kernel::bc { template struct MatchBoundaries_kernel { static_assert(M::is_metric, "M must be a metric class"); - static_assert(static_cast(o) < - static_cast(M::Dim), + static_assert(static_cast(o) < static_cast(M::Dim), "Invalid component index"); static constexpr idx_t i = static_cast(o) + 1u; static constexpr bool defines_dx1 = traits::has_method::value; @@ -488,7 +487,7 @@ namespace kernel::bc { template struct ConductorBoundaries_kernel { - static_assert(static_cast(o) < static_cast(D), + static_assert(static_cast(o) < static_cast(D), "Invalid component index"); ndfield_t Fld; @@ -850,8 +849,7 @@ namespace kernel::bc { defines_bx2 or defines_bx3, "none of the components of E or B are specified in PGEN"); static_assert(M::is_metric, "M must be a metric class"); - static_assert(static_cast(O) < - static_cast(M::Dim), + static_assert(static_cast(O) < static_cast(M::Dim), "Invalid Orientation"); ndfield_t Fld; diff --git a/src/kernels/injectors.hpp b/src/kernels/injectors.hpp index d50b5c24c..0449ed441 100644 --- a/src/kernels/injectors.hpp +++ b/src/kernels/injectors.hpp @@ -24,7 +24,6 @@ namespace kernel { using namespace ntt; - using spidx_t = unsigned short; template struct UniformInjector_kernel { diff --git a/src/kernels/particle_moments.hpp b/src/kernels/particle_moments.hpp index 070a85062..8be68f5d2 100644 --- a/src/kernels/particle_moments.hpp +++ b/src/kernels/particle_moments.hpp @@ -47,7 +47,7 @@ namespace kernel { const unsigned short c1, c2; scatter_ndfield_t Buff; - const unsigned short buff_idx; + const idx_t buff_idx; const array_t i1, i2, i3; const array_t dx1, dx2, dx3; const array_t ux1, ux2, ux3; @@ -69,7 +69,7 @@ namespace kernel { public: ParticleMoments_kernel(const std::vector& components, const scatter_ndfield_t& scatter_buff, - unsigned short buff_idx, + idx_t buff_idx, const array_t& i1, const array_t& i2, const array_t& i3, diff --git a/src/kernels/particle_pusher_sr.hpp b/src/kernels/particle_pusher_sr.hpp index 2e8a5f652..fa4a18845 100644 --- a/src/kernels/particle_pusher_sr.hpp +++ b/src/kernels/particle_pusher_sr.hpp @@ -30,7 +30,9 @@ /* Local macros */ /* -------------------------------------------------------------------------- */ #define from_Xi_to_i(XI, I) \ - { I = static_cast((XI + 1)) - 1; } + { \ + I = static_cast((XI + 1)) - 1; \ + } #define from_Xi_to_i_di(XI, I, DI) \ { \ @@ -102,10 +104,10 @@ namespace kernel::sr { raise::ErrorIf(ExtForce, "External force not provided", HERE); } - Inline auto fx1(const unsigned short& sp, - const real_t& time, - bool ext_force, - const coord_t& x_Ph) const -> real_t { + Inline auto fx1(const spidx_t& sp, + const simtime_t& time, + bool ext_force, + const coord_t& x_Ph) const -> real_t { real_t f_x1 = ZERO; if constexpr (ExtForce) { if (ext_force) { @@ -128,10 +130,10 @@ namespace kernel::sr { return f_x1; } - Inline auto fx2(const unsigned short& sp, - const real_t& time, - bool ext_force, - const coord_t& x_Ph) const -> real_t { + Inline auto fx2(const spidx_t& sp, + const simtime_t& time, + bool ext_force, + const coord_t& x_Ph) const -> real_t { real_t f_x2 = ZERO; if constexpr (ExtForce) { if (ext_force) { @@ -154,10 +156,10 @@ namespace kernel::sr { return f_x2; } - Inline auto fx3(const unsigned short& sp, - const real_t& time, - bool ext_force, - const coord_t& x_Ph) const -> real_t { + Inline auto fx3(const spidx_t& sp, + const simtime_t& time, + bool ext_force, + const coord_t& x_Ph) const -> real_t { real_t f_x3 = ZERO; if constexpr (ExtForce) { if (ext_force) { @@ -198,7 +200,7 @@ namespace kernel::sr { const CoolingTags cooling; const randacc_ndfield_t EB; - const unsigned short sp; + const spidx_t sp; array_t i1, i2, i3; array_t i1_prev, i2_prev, i3_prev; array_t dx1, dx2, dx3; @@ -232,7 +234,7 @@ namespace kernel::sr { bool ext_force, CoolingTags cooling, const randacc_ndfield_t& EB, - unsigned short sp, + spidx_t sp, array_t& i1, array_t& i2, array_t& i3, @@ -355,7 +357,7 @@ namespace kernel::sr { array_t& phi, array_t& tag, const M& metric, - real_t time, + simtime_t time, real_t coeff, real_t dt, int ni1, diff --git a/src/kernels/tests/flds_bc.cpp b/src/kernels/tests/flds_bc.cpp index aba829e8b..c5675cdec 100644 --- a/src/kernels/tests/flds_bc.cpp +++ b/src/kernels/tests/flds_bc.cpp @@ -56,7 +56,7 @@ Inline auto equal(real_t a, real_t b, const char* msg, real_t acc) -> bool { template void testFldsBCs(const std::vector& res) { - errorIf(res.size() != (unsigned short)D, "res.size() != D"); + errorIf(res.size() != (dim_t)D, "res.size() != D"); boundaries_t sx; for (const auto& r : res) { sx.emplace_back(ZERO, r); diff --git a/src/kernels/utils.hpp b/src/kernels/utils.hpp index 307ff7290..ce20af82a 100644 --- a/src/kernels/utils.hpp +++ b/src/kernels/utils.hpp @@ -20,10 +20,10 @@ namespace kernel { template class ComputeSum_kernel { const ndfield_t buff; - const unsigned short buff_idx; + const idx_t buff_idx; public: - ComputeSum_kernel(const ndfield_t& buff, unsigned short buff_idx) + ComputeSum_kernel(const ndfield_t& buff, idx_t buff_idx) : buff { buff } , buff_idx { buff_idx } { raise::ErrorIf(buff_idx >= N, "Invalid component index", HERE); diff --git a/src/metrics/tests/coord_trans.cpp b/src/metrics/tests/coord_trans.cpp index f3779a852..1e9a634fe 100644 --- a/src/metrics/tests/coord_trans.cpp +++ b/src/metrics/tests/coord_trans.cpp @@ -31,7 +31,7 @@ Inline auto equal(const coord_t& a, const char* msg, real_t acc = ONE) -> bool { const auto eps = epsilon * acc; - for (unsigned short d = 0; d < D; ++d) { + for (auto d { 0u }; d < D; ++d) { if (not cmp::AlmostEqual(a[d], b[d], eps)) { printf("%d : %.12e != %.12e %s\n", d, a[d], b[d], msg); return false; @@ -44,7 +44,7 @@ template Inline void unravel(std::size_t idx, tuple_t& ijk, const tuple_t& res) { - for (unsigned short d = 0; d < D; ++d) { + for (auto d { 0u }; d < D; ++d) { ijk[d] = idx % res[d]; idx /= res[d]; } @@ -82,7 +82,7 @@ void testMetric(const std::vector& res, coord_t x_Code_2 { ZERO }; coord_t x_Phys_1 { ZERO }; coord_t x_Sph_1 { ZERO }; - for (unsigned short d = 0; d < M::Dim; ++d) { + for (auto d { 0u }; d < D; ++d) { x_Code_1[d] = (real_t)(idx[d]) + HALF; } metric.template convert(x_Code_1, x_Phys_1); @@ -127,24 +127,24 @@ auto main(int argc, char* argv[]) -> int { const auto res2d = std::vector { 64, 32 }; const auto res3d = std::vector { 64, 32, 16 }; const auto ext1dcart = boundaries_t { - {10.0, 20.0} + { 10.0, 20.0 } }; const auto ext2dcart = boundaries_t { - {0.0, 20.0}, - {0.0, 10.0} + { 0.0, 20.0 }, + { 0.0, 10.0 } }; const auto ext3dcart = boundaries_t { - {-2.0, 2.0}, - {-1.0, 1.0}, - {-0.5, 0.5} + { -2.0, 2.0 }, + { -1.0, 1.0 }, + { -0.5, 0.5 } }; const auto extsph = boundaries_t { - {1.0, 10.0}, - {0.0, constant::PI} + { 1.0, 10.0 }, + { 0.0, constant::PI } }; const auto params = std::map { - {"r0", -ONE}, - { "h", (real_t)0.25} + { "r0", -ONE }, + { "h", (real_t)0.25 } }; testMetric>({ 128 }, ext1dcart); @@ -155,30 +155,30 @@ auto main(int argc, char* argv[]) -> int { const auto resks = std::vector { 64, 54 }; const auto extsks = boundaries_t { - {0.8, 50.0}, - {0.0, constant::PI} + { 0.8, 50.0 }, + { 0.0, constant::PI } }; const auto paramsks = std::map { - {"a", (real_t)0.95} + { "a", (real_t)0.95 } }; testMetric>(resks, extsks, 150, paramsks); const auto resqks = std::vector { 64, 42 }; const auto extqks = boundaries_t { - {0.8, 10.0}, - {0.0, constant::PI} + { 0.8, 10.0 }, + { 0.0, constant::PI } }; const auto paramsqks = std::map { - {"r0", -TWO}, - { "h", ZERO}, - { "a", (real_t)0.8} + { "r0", -TWO }, + { "h", ZERO }, + { "a", (real_t)0.8 } }; testMetric>(resqks, extqks, 500, paramsqks); const auto resks0 = std::vector { 64, 54 }; const auto extks0 = boundaries_t { - {0.5, 20.0}, - {0.0, constant::PI} + { 0.5, 20.0 }, + { 0.0, constant::PI } }; testMetric>(resks0, extks0, 150); diff --git a/src/metrics/tests/ks-qks.cpp b/src/metrics/tests/ks-qks.cpp index 167f564ee..fce9004d1 100644 --- a/src/metrics/tests/ks-qks.cpp +++ b/src/metrics/tests/ks-qks.cpp @@ -25,7 +25,7 @@ Inline auto equal(const vec_t& a, const char* msg, real_t acc = ONE) -> bool { const auto eps = epsilon * acc; - for (unsigned short d = 0; d < D; ++d) { + for (auto d { 0u }; d < D; ++d) { if (not cmp::AlmostEqual(a[d], b[d], eps)) { printf("%s: %.12e : %.12e\n", msg, a[d], b[d]); return false; @@ -38,7 +38,7 @@ template Inline void unravel(std::size_t idx, tuple_t& ijk, const tuple_t& res) { - for (unsigned short d = 0; d < D; ++d) { + for (auto d { 0u }; d < D; ++d) { ijk[d] = idx % res[d]; idx /= res[d]; } @@ -75,7 +75,7 @@ void testMetric(const std::vector& res, coord_t x_Code { ZERO }; coord_t x_Phys { ZERO }; - for (unsigned short d = 0; d < M::Dim; ++d) { + for (auto d { 0u }; d < M::Dim; ++d) { x_Code[d] = (real_t)(idx[d]) + HALF; } diff --git a/src/metrics/tests/minkowski.cpp b/src/metrics/tests/minkowski.cpp index 1ef27b4fa..6073b810d 100644 --- a/src/metrics/tests/minkowski.cpp +++ b/src/metrics/tests/minkowski.cpp @@ -21,7 +21,7 @@ inline static constexpr auto epsilon = std::numeric_limits::epsilon(); template Inline auto equal(const coord_t& a, const coord_t& b, real_t acc = ONE) -> bool { - for (unsigned short d = 0; d < D; ++d) { + for (auto d { 0u }; d < D; ++d) { if (not cmp::AlmostEqual(a[d], b[d], epsilon * acc)) { printf("%d : %.12f != %.12f\n", d, a[d], b[d]); return false; diff --git a/src/metrics/tests/sph-qsph.cpp b/src/metrics/tests/sph-qsph.cpp index 230a763e1..2ad802c20 100644 --- a/src/metrics/tests/sph-qsph.cpp +++ b/src/metrics/tests/sph-qsph.cpp @@ -25,7 +25,7 @@ Inline auto equal(const vec_t& a, const char* msg, real_t acc = ONE) -> bool { const auto eps = epsilon * acc; - for (unsigned short d = 0; d < D; ++d) { + for (auto d { 0u }; d < D; ++d) { if (not cmp::AlmostEqual(a[d], b[d], eps)) { printf("%d : %.12e != %.12e %s\n", d, a[d], b[d], msg); return false; @@ -38,7 +38,7 @@ template Inline void unravel(std::size_t idx, tuple_t& ijk, const tuple_t& res) { - for (unsigned short d = 0; d < D; ++d) { + for (auto d { 0u }; d < D; ++d) { ijk[d] = idx % res[d]; idx /= res[d]; } @@ -74,7 +74,7 @@ void testMetric(const std::vector& res, coord_t x_Code { ZERO }; coord_t x_Phys { ZERO }; - for (unsigned short d = 0; d < M::Dim; ++d) { + for (auto d { 0u }; d < M::Dim; ++d) { x_Code[d] = (real_t)(idx[d]) + HALF; } diff --git a/src/metrics/tests/sr-cart-sph.cpp b/src/metrics/tests/sr-cart-sph.cpp index 42aa5d639..b3e4e163f 100644 --- a/src/metrics/tests/sr-cart-sph.cpp +++ b/src/metrics/tests/sr-cart-sph.cpp @@ -28,7 +28,7 @@ Inline auto equal(const coord_t& a, const char* msg, real_t acc = ONE) -> bool { const auto eps = epsilon * acc; - for (unsigned short d = 0; d < D; ++d) { + for (auto d { 0u }; d < D; ++d) { if (not cmp::AlmostEqual(a[d], b[d], eps)) { printf("%d : %.12e != %.12e %s\n", d, a[d], b[d], msg); return false; @@ -41,7 +41,7 @@ template Inline void unravel(std::size_t idx, tuple_t& ijk, const tuple_t& res) { - for (unsigned short d = 0; d < D; ++d) { + for (auto d { 0u }; d < D; ++d) { ijk[d] = idx % res[d]; idx /= res[d]; } @@ -81,7 +81,7 @@ void testMetric(const std::vector& res, coord_t x_Code_2 { ZERO }; coord_t x_Cart { ZERO }; - for (unsigned short d = 0; d < M::Dim; ++d) { + for (auto d { 0u }; d < M::Dim; ++d) { x_Code_1[d] = (real_t)(idx[d]) + HALF; } metric.template convert_xyz(x_Code_1, x_Cart); @@ -95,7 +95,7 @@ void testMetric(const std::vector& res, coord_t x_Code_r1 { ZERO }; coord_t x_Code_r2 { ZERO }; coord_t x_Sph { ZERO }; - for (unsigned short d = 0; d < M::Dim; ++d) { + for (auto d { 0u }; d < M::Dim; ++d) { x_Code_r1[d] = x_Code_1[d]; } metric.template convert(x_Code_r1, x_Sph); diff --git a/src/metrics/tests/vec_trans.cpp b/src/metrics/tests/vec_trans.cpp index 31015115c..af7c08813 100644 --- a/src/metrics/tests/vec_trans.cpp +++ b/src/metrics/tests/vec_trans.cpp @@ -31,7 +31,7 @@ Inline auto equal(const vec_t& a, const char* msg, real_t acc = ONE) -> bool { const auto eps = epsilon * acc; - for (unsigned short d = 0; d < D; ++d) { + for (auto d { 0u }; d < D; ++d) { if (not cmp::AlmostEqual(a[d], b[d], eps)) { printf("%d : %.12e != %.12e %s\n", d, a[d], b[d], msg); return false; @@ -44,7 +44,7 @@ template Inline void unravel(std::size_t idx, tuple_t& ijk, const tuple_t& res) { - for (unsigned short d = 0; d < D; ++d) { + for (auto d { 0u }; d < D; ++d) { ijk[d] = idx % res[d]; idx /= res[d]; } @@ -79,7 +79,7 @@ void testMetric(const std::vector& res, tuple_t idx; unravel(n, idx, res_tup); coord_t x_Code { ZERO }; - for (unsigned short d = 0; d < M::Dim; ++d) { + for (auto d { 0u }; d < M::Dim; ++d) { x_Code[d] = (real_t)(idx[d]) + HALF; } vec_t v_Hat_1 { ZERO }; @@ -94,7 +94,7 @@ void testMetric(const std::vector& res, vec_t v_PhysCov_2 { ZERO }; // init - for (unsigned short d = 0; d < Dim::_3D; ++d) { + for (auto d { 0u }; d < 3u; ++d) { v_Hat_1[d] += ONE; v_PhysCntrv_1[d] += ONE; v_PhysCov_1[d] += ONE; @@ -102,12 +102,12 @@ void testMetric(const std::vector& res, // hat <-> cntrv metric.template transform(x_Code, v_Hat_1, v_Cntrv_1); - for (unsigned short d = 0; d < Dim::_3D; ++d) { + for (auto d { 0u }; d < 3u; ++d) { vec_t e_d { ZERO }; vec_t v_Cntrv_temp { ZERO }; e_d[d] = ONE; metric.template transform(x_Code, e_d, v_Cntrv_temp); - for (unsigned short d = 0; d < Dim::_3D; ++d) { + for (auto d { 0u }; d < 3u; ++d) { v_Cntrv_2[d] += v_Cntrv_temp[d]; } } @@ -123,15 +123,15 @@ void testMetric(const std::vector& res, v_Cov_2, "cntrv->cov is equal to hat->cov", acc); - for (unsigned short d = 0; d < Dim::_3D; ++d) { + for (auto d { 0u }; d < 3u; ++d) { v_Cov_2[d] = ZERO; } - for (unsigned short d = 0; d < Dim::_3D; ++d) { + for (auto d { 0u }; d < 3u; ++d) { vec_t e_d { ZERO }; vec_t v_Cov_temp { ZERO }; e_d[d] = ONE; metric.template transform(x_Code, e_d, v_Cov_temp); - for (unsigned short d = 0; d < Dim::_3D; ++d) { + for (auto d { 0u }; d < 3u; ++d) { v_Cov_2[d] += v_Cov_temp[d]; } } @@ -179,24 +179,24 @@ auto main(int argc, char* argv[]) -> int { const auto res2d = std::vector { 64, 32 }; const auto res3d = std::vector { 64, 32, 16 }; const auto ext1dcart = boundaries_t { - {10.0, 20.0} + { 10.0, 20.0 } }; const auto ext2dcart = boundaries_t { - {0.0, 20.0}, - {0.0, 10.0} + { 0.0, 20.0 }, + { 0.0, 10.0 } }; const auto ext3dcart = boundaries_t { - {-2.0, 2.0}, - {-1.0, 1.0}, - {-0.5, 0.5} + { -2.0, 2.0 }, + { -1.0, 1.0 }, + { -0.5, 0.5 } }; const auto extsph = boundaries_t { - {1.0, 10.0}, - {0.0, constant::PI} + { 1.0, 10.0 }, + { 0.0, constant::PI } }; const auto params = std::map { - {"r0", -ONE}, - { "h", (real_t)0.25} + { "r0", -ONE }, + { "h", (real_t)0.25 } }; // testMetric>({ 128 }, ext1dcart); @@ -219,13 +219,13 @@ auto main(int argc, char* argv[]) -> int { // const auto resqks = std::vector { 64, 42 }; const auto extqks = boundaries_t { - {0.8, 10.0}, - {0.0, constant::PI} + { 0.8, 10.0 }, + { 0.0, constant::PI } }; const auto paramsqks = std::map { - {"r0", -TWO}, - { "h", ZERO}, - { "a", (real_t)0.8} + { "r0", -TWO }, + { "h", ZERO }, + { "a", (real_t)0.8 } }; testMetric>(resqks, extqks, 500, paramsqks); // diff --git a/src/output/fields.h b/src/output/fields.h index cdfda9272..fedadc6f8 100644 --- a/src/output/fields.h +++ b/src/output/fields.h @@ -34,7 +34,7 @@ namespace out { PrepareOutputFlags interp_flag { PrepareOutput::None }; std::vector> comp {}; - std::vector species {}; + std::vector species {}; OutputField(const SimEngine& S, const std::string&); diff --git a/src/output/particles.h b/src/output/particles.h index fb05fec7d..0936e66f9 100644 --- a/src/output/particles.h +++ b/src/output/particles.h @@ -8,20 +8,22 @@ #ifndef OUTPUT_PARTICLES_H #define OUTPUT_PARTICLES_H +#include "global.h" + #include namespace out { class OutputSpecies { - const unsigned short m_sp; + const spidx_t m_sp; public: - OutputSpecies(unsigned short sp) : m_sp { sp } {} + OutputSpecies(spidx_t sp) : m_sp { sp } {} ~OutputSpecies() = default; [[nodiscard]] - auto species() const -> unsigned short { + auto species() const -> spidx_t { return m_sp; } diff --git a/src/output/spectra.h b/src/output/spectra.h index 119495cd3..c3e5d13d7 100644 --- a/src/output/spectra.h +++ b/src/output/spectra.h @@ -8,20 +8,22 @@ #ifndef OUTPUT_SPECTRA_H #define OUTPUT_SPECTRA_H +#include "global.h" + #include namespace out { class OutputSpectra { - const unsigned short m_sp; + const spidx_t m_sp; public: - OutputSpectra(unsigned short sp) : m_sp { sp } {} + OutputSpectra(spidx_t sp) : m_sp { sp } {} ~OutputSpectra() = default; [[nodiscard]] - auto species() const -> unsigned short { + auto species() const -> spidx_t { return m_sp; } diff --git a/src/output/tests/fields.cpp b/src/output/tests/fields.cpp index e09bed142..e33fd59ec 100644 --- a/src/output/tests/fields.cpp +++ b/src/output/tests/fields.cpp @@ -45,7 +45,7 @@ auto main() -> int { raise::ErrorIf(rho.interp_flag != PrepareOutput::None, "Rho should not have any interp flags", HERE); - raise::ErrorIf(not(rho.species == std::vector { 1, 3 }), + raise::ErrorIf(not(rho.species == std::vector { 1, 3 }), "Rho should have species 1 and 3", HERE); } diff --git a/src/output/utils/interpret_prompt.cpp b/src/output/utils/interpret_prompt.cpp index 7e6d92971..8506b29ff 100644 --- a/src/output/utils/interpret_prompt.cpp +++ b/src/output/utils/interpret_prompt.cpp @@ -10,12 +10,12 @@ namespace out { - auto InterpretSpecies(const std::string& in) -> std::vector { - std::vector species; + auto InterpretSpecies(const std::string& in) -> std::vector { + std::vector species; if (in.find("_") < in.size()) { auto species_str = fmt::splitString(in.substr(in.find("_") + 1), "_"); for (const auto& specie : species_str) { - species.push_back((unsigned short)(std::stoi(specie))); + species.push_back((spidx_t)(std::stoi(specie))); } } return species; diff --git a/src/output/utils/interpret_prompt.h b/src/output/utils/interpret_prompt.h index ebacaa980..488d81101 100644 --- a/src/output/utils/interpret_prompt.h +++ b/src/output/utils/interpret_prompt.h @@ -4,7 +4,7 @@ * Defines the function that interprets ... * ... the user-defined species, e.g. when computing moments * @implements - * - out::InterpretSpecies -> std::vector + * - out::InterpretSpecies -> std::vector * - out::InterpretComponents -> std::vector> * @cpp: * - interpret_prompt.cpp @@ -17,12 +17,14 @@ #ifndef OUTPUT_UTILS_INTERPRET_PROMPT_H #define OUTPUT_UTILS_INTERPRET_PROMPT_H +#include "global.h" + #include #include namespace out { - auto InterpretSpecies(const std::string&) -> std::vector; + auto InterpretSpecies(const std::string&) -> std::vector; auto InterpretComponents(const std::vector&) -> std::vector>; diff --git a/src/output/writer.cpp b/src/output/writer.cpp index 4350e8442..cb30b2d1f 100644 --- a/src/output/writer.cpp +++ b/src/output/writer.cpp @@ -48,9 +48,8 @@ namespace out { m_trackers.insert({ type, tools::Tracker(type, interval, interval_time) }); } - auto Writer::shouldWrite(const std::string& type, - timestep_t step, - simtime_t time) -> bool { + auto Writer::shouldWrite(const std::string& type, timestep_t step, simtime_t time) + -> bool { if (m_trackers.find(type) != m_trackers.end()) { return m_trackers.at(type).shouldWrite(step, time); } else { @@ -161,8 +160,8 @@ namespace out { } } - void Writer::defineParticleOutputs(Dimension dim, - const std::vector& specs) { + void Writer::defineParticleOutputs(Dimension dim, + const std::vector& specs) { m_prtl_writers.clear(); for (const auto& s : specs) { m_prtl_writers.emplace_back(s); @@ -187,7 +186,7 @@ namespace out { } } - void Writer::defineSpectraOutputs(const std::vector& specs) { + void Writer::defineSpectraOutputs(const std::vector& specs) { m_spectra_writers.clear(); for (const auto& s : specs) { m_spectra_writers.emplace_back(s); @@ -401,7 +400,7 @@ namespace out { m_writer.Put(var, e_bins_h); } - void Writer::writeMesh(unsigned short dim, + void Writer::writeMesh(dim_t dim, const array_t& xc, const array_t& xe) { auto varc = m_io.InquireVariable("X" + std::to_string(dim + 1)); diff --git a/src/output/writer.h b/src/output/writer.h index 5484aa6d7..4e66274ef 100644 --- a/src/output/writer.h +++ b/src/output/writer.h @@ -91,10 +91,10 @@ namespace out { Coord); void defineFieldOutputs(const SimEngine&, const std::vector&); - void defineParticleOutputs(Dimension, const std::vector&); - void defineSpectraOutputs(const std::vector&); + void defineParticleOutputs(Dimension, const std::vector&); + void defineSpectraOutputs(const std::vector&); - void writeMesh(unsigned short, const array_t&, const array_t&); + void writeMesh(dim_t, const array_t&, const array_t&); template void writeField(const std::vector&, From 3529036a949993f61e9d6411a1c7f5c5616f2548 Mon Sep 17 00:00:00 2001 From: hayk Date: Sat, 12 Apr 2025 02:53:22 -0400 Subject: [PATCH 611/773] better tests for pushers + extforce --- src/framework/parameters.cpp | 8 +- src/kernels/particle_pusher_sr.hpp | 2 +- src/kernels/tests/CMakeLists.txt | 2 + src/kernels/tests/ext_force.cpp | 287 +++++++++++++++++++++++++++++ src/kernels/tests/gca_pusher.cpp | 246 +++++++++++-------------- src/kernels/tests/pusher.cpp | 274 +++++++++++++++++++++++++++ src/metrics/tests/coord_trans.cpp | 2 +- 7 files changed, 677 insertions(+), 144 deletions(-) create mode 100644 src/kernels/tests/ext_force.cpp create mode 100644 src/kernels/tests/pusher.cpp diff --git a/src/framework/parameters.cpp b/src/framework/parameters.cpp index 7c53d82a5..56345d9f4 100644 --- a/src/framework/parameters.cpp +++ b/src/framework/parameters.cpp @@ -738,13 +738,7 @@ namespace ntt { for (const auto& e : extent_pairwise) { min_extent = std::min(min_extent, e.second - e.first); } - const auto default_ds = min_extent * defaults::bc::match::ds_frac; - std::size_t n_match_bcs { 0u }; - for (const auto& bcs : flds_bc_pairwise) { - if (bcs.first == FldsBC::MATCH or bcs.second == FldsBC::MATCH) { - n_match_bcs += 1; - } - } + const auto default_ds = min_extent * defaults::bc::match::ds_frac; boundaries_t ds_array; try { auto ds = toml::find(toml_data, "grid", "boundaries", "match", "ds"); diff --git a/src/kernels/particle_pusher_sr.hpp b/src/kernels/particle_pusher_sr.hpp index fa4a18845..8fb8500c1 100644 --- a/src/kernels/particle_pusher_sr.hpp +++ b/src/kernels/particle_pusher_sr.hpp @@ -338,7 +338,7 @@ namespace kernel::sr { bool ext_force, CoolingTags cooling, const ndfield_t& EB, - unsigned short sp, + spidx_t sp, array_t& i1, array_t& i2, array_t& i3, diff --git a/src/kernels/tests/CMakeLists.txt b/src/kernels/tests/CMakeLists.txt index 7579eb6d3..551f9012f 100644 --- a/src/kernels/tests/CMakeLists.txt +++ b/src/kernels/tests/CMakeLists.txt @@ -33,3 +33,5 @@ gen_test(prtls_to_phys) gen_test(gca_pusher) gen_test(prtl_bc) gen_test(flds_bc) +gen_test(pusher) +gen_test(ext_force) diff --git a/src/kernels/tests/ext_force.cpp b/src/kernels/tests/ext_force.cpp new file mode 100644 index 000000000..7f760e939 --- /dev/null +++ b/src/kernels/tests/ext_force.cpp @@ -0,0 +1,287 @@ +#include "enums.h" +#include "global.h" + +#include "arch/kokkos_aliases.h" +#include "utils/error.h" +#include "utils/numeric.h" +#include "utils/plog.h" + +#include "metrics/minkowski.h" + +#include "kernels/particle_pusher_sr.hpp" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +using namespace ntt; +using namespace metric; + +void check_value(unsigned int t, + real_t target, + real_t value, + real_t eps, + const std::string& msg) { + const auto msg_ = fmt::format("%s: %e != %e @ %u", msg.c_str(), target, value, t); + const auto diff = math::abs(target - value); + const auto sum = HALF * (math::abs(target) + math::abs(value)); + raise::ErrorIf(((sum > eps) and (diff / sum > eps)) or + ((sum <= eps) and (diff > eps / 10.0)), + msg_ + " " + fmt::format("%.12e, %.12e", diff, sum), + HERE); +} + +template +void put_value(array_t& arr, T v, index_t p) { + auto h = Kokkos::create_mirror_view(arr); + Kokkos::deep_copy(h, arr); + h(p) = v; + Kokkos::deep_copy(arr, h); +} + +struct Force { + const std::vector species { 1 }; + + Force(real_t force) : force { force } {} + + Inline auto fx1(const spidx_t&, const simtime_t&, const coord_t&) const + -> real_t { + return force * math::sin(ONE) * math::sin(ONE); + } + + Inline auto fx2(const spidx_t&, const simtime_t&, const coord_t&) const + -> real_t { + return force * math::sin(ONE) * math::cos(ONE); + } + + Inline auto fx3(const spidx_t&, const simtime_t&, const coord_t&) const + -> real_t { + return force * math::cos(ONE); + } + +private: + const real_t force; +}; + +template +void testPusher(const std::vector& res) { + static_assert(M::Dim == 3); + raise::ErrorIf(res.size() != M::Dim, "res.size() != M::Dim", HERE); + + M metric { + res, + { { 0.0, (real_t)(res[0]) }, { 0.0, (real_t)(res[1]) }, { 0.0, (real_t)(res[2]) } }, + {} + }; + + const int nx1 = res[0]; + const int nx2 = res[1]; + const int nx3 = res[2]; + + const auto range_ext = CreateRangePolicy( + { 0, 0, 0 }, + { res[0] + 2 * N_GHOSTS, res[1] + 2 * N_GHOSTS, res[2] + 2 * N_GHOSTS }); + + auto emfield = ndfield_t { "emfield", + res[0] + 2 * N_GHOSTS, + res[1] + 2 * N_GHOSTS, + res[2] + 2 * N_GHOSTS }; + + const real_t x1_0 = 1.15, x2_0 = 1.85, x3_0 = 1.25; + const real_t ux1_0 = 0.02, ux2_0 = -0.2, ux3_0 = 0.1; + // const real_t gamma_0 = math::sqrt(ONE + NORM_SQR(ux1_0, ux2_0, ux3_0)); + const real_t omegaB0 = 1.0; + const real_t dt = 0.01; + const real_t f_mag = 0.01; + + Kokkos::parallel_for( + "init 3D", + range_ext, + Lambda(index_t i1, index_t i2, index_t i3) { + emfield(i1, i2, i3, em::ex1) = ZERO; + emfield(i1, i2, i3, em::ex2) = ZERO; + emfield(i1, i2, i3, em::ex3) = ZERO; + emfield(i1, i2, i3, em::bx1) = ZERO; + emfield(i1, i2, i3, em::bx2) = ZERO; + emfield(i1, i2, i3, em::bx3) = ZERO; + }); + + array_t i1 { "i1", 2 }; + array_t i2 { "i2", 2 }; + array_t i3 { "i3", 2 }; + array_t i1_prev { "i1_prev", 2 }; + array_t i2_prev { "i2_prev", 2 }; + array_t i3_prev { "i3_prev", 2 }; + array_t dx1 { "dx1", 2 }; + array_t dx2 { "dx2", 2 }; + array_t dx3 { "dx3", 2 }; + array_t dx1_prev { "dx1_prev", 2 }; + array_t dx2_prev { "dx2_prev", 2 }; + array_t dx3_prev { "dx3_prev", 2 }; + array_t ux1 { "ux1", 2 }; + array_t ux2 { "ux2", 2 }; + array_t ux3 { "ux3", 2 }; + array_t phi { "phi", 2 }; + array_t weight { "weight", 2 }; + array_t tag { "tag", 2 }; + + put_value(i1, (int)(x1_0), 0); + put_value(i2, (int)(x2_0), 0); + put_value(i3, (int)(x3_0), 0); + put_value(dx1, (prtldx_t)(x1_0 - (int)(x1_0)), 0); + put_value(dx2, (prtldx_t)(x2_0 - (int)(x2_0)), 0); + put_value(dx3, (prtldx_t)(x3_0 - (int)(x3_0)), 0); + put_value(ux1, ux1_0, 0); + put_value(ux2, ux2_0, 0); + put_value(ux3, ux3_0, 0); + put_value(tag, ParticleTag::alive, 0); + + put_value(i1, (int)(x1_0), 1); + put_value(i2, (int)(x2_0), 1); + put_value(i3, (int)(x3_0), 1); + put_value(dx1, (prtldx_t)(x1_0 - (int)(x1_0)), 1); + put_value(dx2, (prtldx_t)(x2_0 - (int)(x2_0)), 1); + put_value(dx3, (prtldx_t)(x3_0 - (int)(x3_0)), 1); + put_value(ux1, -ux1_0, 1); + put_value(ux2, -ux2_0, 1); + put_value(ux3, -ux3_0, 1); + put_value(tag, ParticleTag::alive, 1); + + // Particle boundaries + auto boundaries = boundaries_t {}; + boundaries = { + { PrtlBC::PERIODIC, PrtlBC::PERIODIC }, + { PrtlBC::PERIODIC, PrtlBC::PERIODIC }, + { PrtlBC::PERIODIC, PrtlBC::PERIODIC } + }; + + const spidx_t sp { 1u }; + + const real_t coeff = HALF * dt * omegaB0; + + const real_t eps = std::is_same_v ? 1e-4 : 1e-6; + + const auto ext_force = Force { f_mag }; + const auto force = + kernel::sr::Force { ext_force }; + + static plog::RollingFileAppender file_appender( + "pusher_log.csv"); + plog::init(plog::verbose, &file_appender); + PLOGD << "t,i1,i2,i3,dx1,dx2,dx3,ux1,ux2,ux3"; + + for (auto t { 0u }; t < 100; ++t) { + const real_t time = t * dt; + + // clang-format off + Kokkos::parallel_for( + "pusher", + CreateRangePolicy({0}, {2}), + kernel::sr::Pusher_kernel, decltype(force)>(PrtlPusher::BORIS, + false, true, kernel::sr::Cooling::None, + emfield, + sp, + i1, i2, i3, + i1_prev, i2_prev, i3_prev, + dx1, dx2, dx3, + dx1_prev, dx2_prev, dx3_prev, + ux1, ux2, ux3, + phi, tag, + metric, force, + (simtime_t)time, coeff, dt, + nx1, nx2, nx3, + boundaries, + ZERO, ZERO, ZERO)); + + auto i1_prev_ = Kokkos::create_mirror_view(i1_prev); + auto i2_prev_ = Kokkos::create_mirror_view(i2_prev); + auto i3_prev_ = Kokkos::create_mirror_view(i3_prev); + auto i1_ = Kokkos::create_mirror_view(i1); + auto i2_ = Kokkos::create_mirror_view(i2); + auto i3_ = Kokkos::create_mirror_view(i3); + Kokkos::deep_copy(i1_prev_, i1_prev); + Kokkos::deep_copy(i2_prev_, i2_prev); + Kokkos::deep_copy(i3_prev_, i3_prev); + Kokkos::deep_copy(i1_, i1); + Kokkos::deep_copy(i2_, i2); + Kokkos::deep_copy(i3_, i3); + + auto dx1_prev_ = Kokkos::create_mirror_view(dx1_prev); + auto dx2_prev_ = Kokkos::create_mirror_view(dx2_prev); + auto dx3_prev_ = Kokkos::create_mirror_view(dx3_prev); + auto dx1_ = Kokkos::create_mirror_view(dx1); + auto dx2_ = Kokkos::create_mirror_view(dx2); + auto dx3_ = Kokkos::create_mirror_view(dx3); + auto ux1_ = Kokkos::create_mirror_view(ux1); + auto ux2_ = Kokkos::create_mirror_view(ux2); + auto ux3_ = Kokkos::create_mirror_view(ux3); + Kokkos::deep_copy(dx1_prev_, dx1_prev); + Kokkos::deep_copy(dx2_prev_, dx2_prev); + Kokkos::deep_copy(dx3_prev_, dx3_prev); + Kokkos::deep_copy(dx1_, dx1); + Kokkos::deep_copy(dx2_, dx2); + Kokkos::deep_copy(dx3_, dx3); + Kokkos::deep_copy(ux1_, ux1); + Kokkos::deep_copy(ux2_, ux2); + Kokkos::deep_copy(ux3_, ux3); + + PLOGD.printf("%e,%d,%d,%d,%e,%e,%e,%e,%e,%e", + time, + i1_(1), + i2_(1), + i3_(1), + dx1_( 1), + dx2_( 1), + dx3_( 1), + ux1_( 1), + ux2_( 1), + ux3_( 1)); + + { + const real_t ux1_expect = ux1_0 + (time + dt) * f_mag * std::sin(ONE) * std::sin(ONE); + const real_t ux2_expect = ux2_0 + (time + dt) * f_mag * std::sin(ONE) * std::cos(ONE); + const real_t ux3_expect = ux3_0 + (time + dt) * f_mag * std::cos(ONE); + + check_value(t, ux1_(0), ux1_expect, eps, "Particle #1 ux1"); + check_value(t, ux2_(0), ux2_expect, eps, "Particle #1 ux2"); + check_value(t, ux3_(0), ux3_expect, eps, "Particle #1 ux3"); + } + + { + const real_t ux1_expect = -ux1_0 + (time + dt) * f_mag * std::sin(ONE) * std::sin(ONE); + const real_t ux2_expect = -ux2_0 + (time + dt) * f_mag * std::sin(ONE) * std::cos(ONE); + const real_t ux3_expect = -ux3_0 + (time + dt) * f_mag * std::cos(ONE); + + check_value(t, ux1_(1), ux1_expect, eps, "Particle #2 ux1"); + check_value(t, ux2_(1), ux2_expect, eps, "Particle #2 ux2"); + check_value(t, ux3_(1), ux3_expect, eps, "Particle #2 ux3"); + } + + } +} + +auto main(int argc, char* argv[]) -> int { + Kokkos::initialize(argc, argv); + + try { + using namespace ntt; + + testPusher>({ 10, 10, 10 }); + + } catch (std::exception& e) { + std::cerr << e.what() << std::endl; + Kokkos::finalize(); + return 1; + } + Kokkos::finalize(); + return 0; +} diff --git a/src/kernels/tests/gca_pusher.cpp b/src/kernels/tests/gca_pusher.cpp index c96ce3d66..5630de414 100644 --- a/src/kernels/tests/gca_pusher.cpp +++ b/src/kernels/tests/gca_pusher.cpp @@ -2,6 +2,7 @@ #include "global.h" #include "arch/kokkos_aliases.h" +#include "utils/error.h" #include "utils/numeric.h" #include "metrics/minkowski.h" @@ -10,20 +11,35 @@ #include #include +#include +#include +#include +#include +#include #include -#include -#include #include #include using namespace ntt; using namespace metric; -void errorIf(bool condition, const std::string& message) { - if (condition) { - throw std::runtime_error(message); - } +void check_value(unsigned int t, + real_t target, + real_t value, + real_t eps, + const std::string& msg) { + const auto msg_ = fmt::format("%s: %.12e != %.12e @ %u", + msg.c_str(), + target, + value, + t); + const auto diff = math::abs(target - value); + const auto sum = HALF * (math::abs(target) + math::abs(value)); + raise::ErrorIf(((sum > eps) and (diff / sum > eps)) or + ((sum <= eps) and (diff > eps / 10.0)), + msg_ + " " + fmt::format("%.12e, %.12e", diff, sum), + HERE); } template @@ -35,24 +51,20 @@ void put_value(array_t& arr, T v, index_t p) { } template -void testGCAPusher(const std::vector& res, - const boundaries_t& ext, - const std::map& params = {}) { +void testPusher(const std::vector& res) { static_assert(M::Dim == 3); - errorIf(res.size() != M::Dim, "res.size() != M::Dim"); - - boundaries_t extent; - extent = ext; + raise::ErrorIf(res.size() != M::Dim, "res.size() != M::Dim", HERE); - M metric { res, extent, params }; + M metric { + res, + { { 0.0, (real_t)(res[0]) }, { 0.0, (real_t)(res[1]) }, { 0.0, (real_t)(res[2]) } }, + {} + }; const int nx1 = res[0]; const int nx2 = res[1]; const int nx3 = res[2]; - auto coeff = real_t { 1.0 }; - auto dt = real_t { 0.01 }; - const auto range_ext = CreateRangePolicy( { 0, 0, 0 }, { res[0] + 2 * N_GHOSTS, res[1] + 2 * N_GHOSTS, res[2] + 2 * N_GHOSTS }); @@ -62,16 +74,29 @@ void testGCAPusher(const std::vector& res, res[1] + 2 * N_GHOSTS, res[2] + 2 * N_GHOSTS }; + const real_t bx1 = 0.66, bx2 = 0.55, bx3 = 0.44; + const real_t x1_0 = 1.15, x2_0 = 1.85, x3_0 = 1.25; + const real_t ux1_0 = 1.0, ux2_0 = -2.0, ux3_0 = 0.1; + const real_t omegaB0 = 0.2; + const real_t dt = 0.01; + + const real_t b_mag = math::sqrt(NORM_SQR(bx1, bx2, bx3)); + const real_t upar_0 = DOT(ux1_0, ux2_0, ux3_0, bx1, bx2, bx3) / b_mag; + + const real_t ux1_expect = bx1 * upar_0 / (b_mag); + const real_t ux2_expect = bx2 * upar_0 / (b_mag); + const real_t ux3_expect = bx3 * upar_0 / (b_mag); + Kokkos::parallel_for( "init 3D", range_ext, Lambda(index_t i1, index_t i2, index_t i3) { - emfield(i1, i2, i3, em::ex1) = 0.0; - emfield(i1, i2, i3, em::ex2) = 0.0; - emfield(i1, i2, i3, em::ex3) = 0.0; - emfield(i1, i2, i3, em::bx1) = 0.22; - emfield(i1, i2, i3, em::bx2) = 0.44; - emfield(i1, i2, i3, em::bx3) = 0.66; + emfield(i1, i2, i3, em::ex1) = ZERO; + emfield(i1, i2, i3, em::ex2) = ZERO; + emfield(i1, i2, i3, em::ex3) = ZERO; + emfield(i1, i2, i3, em::bx1) = bx1; + emfield(i1, i2, i3, em::bx2) = bx2; + emfield(i1, i2, i3, em::bx3) = bx3; }); array_t i1 { "i1", 2 }; @@ -93,119 +118,77 @@ void testGCAPusher(const std::vector& res, array_t weight { "weight", 2 }; array_t tag { "tag", 2 }; - put_value(i1, 5, 0); - put_value(i2, 5, 0); - put_value(i3, 5, 0); - put_value(dx1, (prtldx_t)(0.15), 0); - put_value(dx2, (prtldx_t)(0.85), 0); - put_value(dx3, (prtldx_t)(0.25), 0); - put_value(ux1, (real_t)(1.0), 0); - put_value(ux2, (real_t)(-2.0), 0); - put_value(ux3, (real_t)(0.1), 0); + put_value(i1, (int)(x1_0), 0); + put_value(i2, (int)(x2_0), 0); + put_value(i3, (int)(x3_0), 0); + put_value(dx1, (prtldx_t)(x1_0 - (int)(x1_0)), 0); + put_value(dx2, (prtldx_t)(x2_0 - (int)(x2_0)), 0); + put_value(dx3, (prtldx_t)(x3_0 - (int)(x3_0)), 0); + put_value(ux1, ux1_0, 0); + put_value(ux2, ux2_0, 0); + put_value(ux3, ux3_0, 0); put_value(tag, ParticleTag::alive, 0); - put_value(i1, 5, 1); - put_value(i2, 5, 1); - put_value(i3, 5, 1); - put_value(dx1, (prtldx_t)(0.15), 1); - put_value(dx2, (prtldx_t)(0.85), 1); - put_value(dx3, (prtldx_t)(0.25), 1); - put_value(ux1, (real_t)(1.0), 1); - put_value(ux2, (real_t)(-2.0), 1); - put_value(ux3, (real_t)(0.1), 1); + put_value(i1, (int)(x1_0), 1); + put_value(i2, (int)(x2_0), 1); + put_value(i3, (int)(x3_0), 1); + put_value(dx1, (prtldx_t)(x1_0 - (int)(x1_0)), 1); + put_value(dx2, (prtldx_t)(x2_0 - (int)(x2_0)), 1); + put_value(dx3, (prtldx_t)(x3_0 - (int)(x3_0)), 1); + put_value(ux1, -ux1_0, 1); + put_value(ux2, -ux2_0, 1); + put_value(ux3, -ux3_0, 1); put_value(tag, ParticleTag::alive, 1); // Particle boundaries auto boundaries = boundaries_t {}; boundaries = { - {PrtlBC::PERIODIC, PrtlBC::PERIODIC}, - {PrtlBC::PERIODIC, PrtlBC::PERIODIC}, - {PrtlBC::PERIODIC, PrtlBC::PERIODIC} + { PrtlBC::PERIODIC, PrtlBC::PERIODIC }, + { PrtlBC::PERIODIC, PrtlBC::PERIODIC }, + { PrtlBC::PERIODIC, PrtlBC::PERIODIC } }; - // clang-format off - Kokkos::parallel_for( - "pusher", - 1, - kernel::sr::Pusher_kernel>(PrtlPusher::BORIS, - true, false, kernel::sr::Cooling::None, - emfield, - 1, - i1, i2, i3, - i1_prev, i2_prev, i3_prev, - dx1, dx2, dx3, - dx1_prev, dx2_prev, dx3_prev, - ux1, ux2, ux3, - phi, tag, - metric, - ZERO, coeff, dt, - nx1, nx2, nx3, - boundaries, - (real_t)100000.0, (real_t)1.0, ZERO)); - - Kokkos::parallel_for( - "pusher", - CreateRangePolicy({ 0 }, { 1 }), - kernel::sr::Pusher_kernel>(PrtlPusher::BORIS, - true, false, kernel::sr::Cooling::None, - emfield, - 1, - i1, i2, i3, - i1_prev, i2_prev, i3_prev, - dx1, dx2, dx3, - dx1_prev, dx2_prev, dx3_prev, - ux1, ux2, ux3, - phi, tag, - metric, - ZERO, -coeff, dt, - nx1, nx2, nx3, - boundaries, - (real_t)100000.0, (real_t)1.0, ZERO)); - // clang-format on - - auto i1_prev_ = Kokkos::create_mirror_view(i1_prev); - auto i2_prev_ = Kokkos::create_mirror_view(i2_prev); - auto i3_prev_ = Kokkos::create_mirror_view(i3_prev); - auto i1_ = Kokkos::create_mirror_view(i1); - auto i2_ = Kokkos::create_mirror_view(i2); - auto i3_ = Kokkos::create_mirror_view(i3); - Kokkos::deep_copy(i1_prev_, i1_prev); - Kokkos::deep_copy(i2_prev_, i2_prev); - Kokkos::deep_copy(i3_prev_, i3_prev); - Kokkos::deep_copy(i1_, i1); - Kokkos::deep_copy(i2_, i2); - Kokkos::deep_copy(i3_, i3); - - auto dx1_prev_ = Kokkos::create_mirror_view(dx1_prev); - auto dx2_prev_ = Kokkos::create_mirror_view(dx2_prev); - auto dx3_prev_ = Kokkos::create_mirror_view(dx3_prev); - auto dx1_ = Kokkos::create_mirror_view(dx1); - auto dx2_ = Kokkos::create_mirror_view(dx2); - auto dx3_ = Kokkos::create_mirror_view(dx3); - Kokkos::deep_copy(dx1_prev_, dx1_prev); - Kokkos::deep_copy(dx2_prev_, dx2_prev); - Kokkos::deep_copy(dx3_prev_, dx3_prev); - Kokkos::deep_copy(dx1_, dx1); - Kokkos::deep_copy(dx2_, dx2); - Kokkos::deep_copy(dx3_, dx3); - - auto disx = i1_[0] + dx1_[0] - i1_prev_[0] - dx1_prev_[0]; - auto disy = i2_[0] + dx2_[0] - i2_prev_[0] - dx2_prev_[0]; - auto disz = i3_[0] + dx3_[0] - i3_prev_[0] - dx3_prev_[0]; - - auto disdotB = (disx * 0.22 + disy * 0.44 + disz * 0.66) / - (0.823165 * math::sqrt(SQR(disx) + SQR(disy) + SQR(disz))); - - printf("%.12e \n", (1 - math::abs(disdotB))); - - disx = i1_[1] + dx1_[1] - i1_prev_[1] - dx1_prev_[1]; - disy = i2_[1] + dx2_[1] - i2_prev_[1] - dx2_prev_[1]; - disz = i3_[1] + dx3_[1] - i3_prev_[1] - dx3_prev_[1]; - - disdotB = (disx * 0.22 + disy * 0.44 + disz * 0.66) / - (0.823165 * math::sqrt(SQR(disx) + SQR(disy) + SQR(disz))); - - printf("%.12e \n", (1 - math::abs(disdotB))); + const spidx_t sp { 1u }; + + const real_t coeff = HALF * dt * omegaB0; + + const real_t eps = std::is_same_v ? 1e-3 : 1e-6; + + for (auto t { 0u }; t < 2000; ++t) { + // clang-format off + Kokkos::parallel_for( + "pusher", + CreateRangePolicy({0}, {2}), + kernel::sr::Pusher_kernel>(PrtlPusher::BORIS, + true, false, kernel::sr::Cooling::None, + emfield, + sp, + i1, i2, i3, + i1_prev, i2_prev, i3_prev, + dx1, dx2, dx3, + dx1_prev, dx2_prev, dx3_prev, + ux1, ux2, ux3, + phi, tag, + metric, + ZERO, coeff, dt, + nx1, nx2, nx3, + boundaries, + (real_t)10000.0, ONE, ZERO)); + + auto ux1_ = Kokkos::create_mirror_view(ux1); + auto ux2_ = Kokkos::create_mirror_view(ux2); + auto ux3_ = Kokkos::create_mirror_view(ux3); + Kokkos::deep_copy(ux1_, ux1); + Kokkos::deep_copy(ux2_, ux2); + Kokkos::deep_copy(ux3_, ux3); + + check_value(t, ux1_(0), ux1_expect, eps, "Particle #1 ux1"); + check_value(t, ux2_(0), ux2_expect, eps, "Particle #1 ux2"); + check_value(t, ux3_(0), ux3_expect, eps, "Particle #1 ux3"); + check_value(t, ux1_(1), -ux1_expect, eps, "Particle #2 ux1"); + check_value(t, ux2_(1), -ux2_expect, eps, "Particle #2 ux2"); + check_value(t, ux3_(1), -ux3_expect, eps, "Particle #2 ux3"); + } } auto main(int argc, char* argv[]) -> int { @@ -214,14 +197,7 @@ auto main(int argc, char* argv[]) -> int { try { using namespace ntt; - testGCAPusher>( - { - 10, - 10, - 10 - }, - { { 0.0, 10.0 }, { 0.0, 10.0 }, { 0.0, 10.0 } }, - {}); + testPusher>({ 10, 10, 10 }); } catch (std::exception& e) { std::cerr << e.what() << std::endl; diff --git a/src/kernels/tests/pusher.cpp b/src/kernels/tests/pusher.cpp new file mode 100644 index 000000000..be2154f71 --- /dev/null +++ b/src/kernels/tests/pusher.cpp @@ -0,0 +1,274 @@ +#include "enums.h" +#include "global.h" + +#include "arch/kokkos_aliases.h" +#include "utils/error.h" +#include "utils/numeric.h" + +#include "metrics/minkowski.h" + +#include "kernels/particle_pusher_sr.hpp" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +using namespace ntt; +using namespace metric; + +void check_value(unsigned int t, + real_t target, + real_t value, + real_t eps, + const std::string& msg) { + const auto msg_ = fmt::format("%s: %.12e != %.12e @ %u", + msg.c_str(), + target, + value, + t); + const auto diff = math::abs(target - value); + const auto sum = HALF * (math::abs(target) + math::abs(value)); + raise::ErrorIf(((sum > eps) and (diff / sum > eps)) or + ((sum <= eps) and (diff > eps / 10.0)), + msg_ + " " + fmt::format("%.12e, %.12e", diff, sum), + HERE); +} + +template +void put_value(array_t& arr, T v, index_t p) { + auto h = Kokkos::create_mirror_view(arr); + Kokkos::deep_copy(h, arr); + h(p) = v; + Kokkos::deep_copy(arr, h); +} + +template +void testPusher(const std::vector& res) { + static_assert(M::Dim == 3); + raise::ErrorIf(res.size() != M::Dim, "res.size() != M::Dim", HERE); + + M metric { + res, + { { 0.0, (real_t)(res[0]) }, { 0.0, (real_t)(res[1]) }, { 0.0, (real_t)(res[2]) } }, + {} + }; + + const int nx1 = res[0]; + const int nx2 = res[1]; + const int nx3 = res[2]; + + const auto range_ext = CreateRangePolicy( + { 0, 0, 0 }, + { res[0] + 2 * N_GHOSTS, res[1] + 2 * N_GHOSTS, res[2] + 2 * N_GHOSTS }); + + auto emfield = ndfield_t { "emfield", + res[0] + 2 * N_GHOSTS, + res[1] + 2 * N_GHOSTS, + res[2] + 2 * N_GHOSTS }; + + const real_t bx1 = 0.66, bx2 = 0.55, bx3 = 0.44; + const real_t b_mag = math::sqrt(NORM_SQR(bx1, bx2, bx3)); + const real_t x1_0 = 1.15, x2_0 = 1.85, x3_0 = 1.25; + const real_t ux1_0 = 1.0, ux2_0 = -2.0, ux3_0 = 0.1; + const real_t gamma_0 = math::sqrt(ONE + NORM_SQR(ux1_0, ux2_0, ux3_0)); + const real_t omegaB0 = 0.2; + const real_t dt = 0.01; + + Kokkos::parallel_for( + "init 3D", + range_ext, + Lambda(index_t i1, index_t i2, index_t i3) { + emfield(i1, i2, i3, em::ex1) = ZERO; + emfield(i1, i2, i3, em::ex2) = ZERO; + emfield(i1, i2, i3, em::ex3) = ZERO; + emfield(i1, i2, i3, em::bx1) = bx1; + emfield(i1, i2, i3, em::bx2) = bx2; + emfield(i1, i2, i3, em::bx3) = bx3; + }); + + array_t i1 { "i1", 2 }; + array_t i2 { "i2", 2 }; + array_t i3 { "i3", 2 }; + array_t i1_prev { "i1_prev", 2 }; + array_t i2_prev { "i2_prev", 2 }; + array_t i3_prev { "i3_prev", 2 }; + array_t dx1 { "dx1", 2 }; + array_t dx2 { "dx2", 2 }; + array_t dx3 { "dx3", 2 }; + array_t dx1_prev { "dx1_prev", 2 }; + array_t dx2_prev { "dx2_prev", 2 }; + array_t dx3_prev { "dx3_prev", 2 }; + array_t ux1 { "ux1", 2 }; + array_t ux2 { "ux2", 2 }; + array_t ux3 { "ux3", 2 }; + array_t phi { "phi", 2 }; + array_t weight { "weight", 2 }; + array_t tag { "tag", 2 }; + + put_value(i1, (int)(x1_0), 0); + put_value(i2, (int)(x2_0), 0); + put_value(i3, (int)(x3_0), 0); + put_value(dx1, (prtldx_t)(x1_0 - (int)(x1_0)), 0); + put_value(dx2, (prtldx_t)(x2_0 - (int)(x2_0)), 0); + put_value(dx3, (prtldx_t)(x3_0 - (int)(x3_0)), 0); + put_value(ux1, ux1_0, 0); + put_value(ux2, ux2_0, 0); + put_value(ux3, ux3_0, 0); + put_value(tag, ParticleTag::alive, 0); + + put_value(i1, (int)(x1_0), 1); + put_value(i2, (int)(x2_0), 1); + put_value(i3, (int)(x3_0), 1); + put_value(dx1, (prtldx_t)(x1_0 - (int)(x1_0)), 1); + put_value(dx2, (prtldx_t)(x2_0 - (int)(x2_0)), 1); + put_value(dx3, (prtldx_t)(x3_0 - (int)(x3_0)), 1); + put_value(ux1, ux1_0, 1); + put_value(ux2, ux2_0, 1); + put_value(ux3, ux3_0, 1); + put_value(tag, ParticleTag::alive, 1); + + // Particle boundaries + auto boundaries = boundaries_t {}; + boundaries = { + { PrtlBC::PERIODIC, PrtlBC::PERIODIC }, + { PrtlBC::PERIODIC, PrtlBC::PERIODIC }, + { PrtlBC::PERIODIC, PrtlBC::PERIODIC } + }; + + const spidx_t sp { 1u }; + + const real_t coeff = HALF * dt * omegaB0; + + const auto u0_dot_b = (ux1_0 * bx1 + ux2_0 * bx2 + ux3_0 * bx3) / b_mag; + const auto u0_cross_b_x1 = (ux2_0 * bx3 - ux3_0 * bx2) / b_mag; + const auto u0_cross_b_x2 = (ux3_0 * bx1 - ux1_0 * bx3) / b_mag; + const auto u0_cross_b_x3 = (ux1_0 * bx2 - ux2_0 * bx1) / b_mag; + + const real_t eps = std::is_same_v ? 1e-2 : 1e-4; + + for (auto t { 0u }; t < 2000; ++t) { + const real_t time = t * dt; + + // clang-format off + Kokkos::parallel_for( + "pusher", + CreateRangePolicy({0}, {1}), + kernel::sr::Pusher_kernel>(PrtlPusher::BORIS, + false, false, kernel::sr::Cooling::None, + emfield, + sp, + i1, i2, i3, + i1_prev, i2_prev, i3_prev, + dx1, dx2, dx3, + dx1_prev, dx2_prev, dx3_prev, + ux1, ux2, ux3, + phi, tag, + metric, + ZERO, coeff, dt, + nx1, nx2, nx3, + boundaries, + ZERO, ZERO, ZERO)); + + Kokkos::parallel_for( + "pusher", + CreateRangePolicy({1}, {2}), + kernel::sr::Pusher_kernel>(PrtlPusher::VAY, + false, false, kernel::sr::Cooling::None, + emfield, + sp, + i1, i2, i3, + i1_prev, i2_prev, i3_prev, + dx1, dx2, dx3, + dx1_prev, dx2_prev, dx3_prev, + ux1, ux2, ux3, + phi, tag, + metric, + ZERO, coeff, dt, + nx1, nx2, nx3, + boundaries, + ZERO, ZERO, ZERO)); + + auto i1_prev_ = Kokkos::create_mirror_view(i1_prev); + auto i2_prev_ = Kokkos::create_mirror_view(i2_prev); + auto i3_prev_ = Kokkos::create_mirror_view(i3_prev); + auto i1_ = Kokkos::create_mirror_view(i1); + auto i2_ = Kokkos::create_mirror_view(i2); + auto i3_ = Kokkos::create_mirror_view(i3); + Kokkos::deep_copy(i1_prev_, i1_prev); + Kokkos::deep_copy(i2_prev_, i2_prev); + Kokkos::deep_copy(i3_prev_, i3_prev); + Kokkos::deep_copy(i1_, i1); + Kokkos::deep_copy(i2_, i2); + Kokkos::deep_copy(i3_, i3); + + auto dx1_prev_ = Kokkos::create_mirror_view(dx1_prev); + auto dx2_prev_ = Kokkos::create_mirror_view(dx2_prev); + auto dx3_prev_ = Kokkos::create_mirror_view(dx3_prev); + auto dx1_ = Kokkos::create_mirror_view(dx1); + auto dx2_ = Kokkos::create_mirror_view(dx2); + auto dx3_ = Kokkos::create_mirror_view(dx3); + auto ux1_ = Kokkos::create_mirror_view(ux1); + auto ux2_ = Kokkos::create_mirror_view(ux2); + auto ux3_ = Kokkos::create_mirror_view(ux3); + Kokkos::deep_copy(dx1_prev_, dx1_prev); + Kokkos::deep_copy(dx2_prev_, dx2_prev); + Kokkos::deep_copy(dx3_prev_, dx3_prev); + Kokkos::deep_copy(dx1_, dx1); + Kokkos::deep_copy(dx2_, dx2); + Kokkos::deep_copy(dx3_, dx3); + Kokkos::deep_copy(ux1_, ux1); + Kokkos::deep_copy(ux2_, ux2); + Kokkos::deep_copy(ux3_, ux3); + + const real_t gamma1 = math::sqrt(ONE + NORM_SQR(ux1_(0), ux2_(0), ux3_(0))); + const real_t gamma2 = math::sqrt(ONE + NORM_SQR(ux1_(1), ux2_(1), ux3_(1))); + + check_value(t, gamma1, gamma_0, eps, "Particle #1 Lorentz factor"); + check_value(t, gamma2, gamma_0, eps, "Particle #2 Lorentz factor"); + + const real_t arg = (b_mag * omegaB0 * (time + dt)) / gamma_0; + const real_t ux1_expect = (bx1 / b_mag) * u0_dot_b + + (-(bx1 / b_mag) * u0_dot_b + ux1_0) * math::cos(arg) + + u0_cross_b_x1 * math::sin(arg); + const real_t ux2_expect = (bx2 / b_mag) * u0_dot_b + + (-(bx2 / b_mag) * u0_dot_b + ux2_0) * math::cos(arg) + + u0_cross_b_x2 * math::sin(arg); + const real_t ux3_expect = (bx3 / b_mag) * u0_dot_b + + (-(bx3 / b_mag) * u0_dot_b + ux3_0) * math::cos(arg) + + u0_cross_b_x3 * math::sin(arg); + + check_value(t, ux1_(0), ux1_expect, eps, "Particle #1 ux1"); + check_value(t, ux2_(0), ux2_expect, eps, "Particle #1 ux2"); + check_value(t, ux3_(0), ux3_expect, eps, "Particle #1 ux3"); + + check_value(t, ux1_(1), ux1_expect, eps, "Particle #2 ux1"); + check_value(t, ux2_(1), ux2_expect, eps, "Particle #2 ux2"); + check_value(t, ux3_(1), ux3_expect, eps, "Particle #2 ux3"); + + } +} + +auto main(int argc, char* argv[]) -> int { + Kokkos::initialize(argc, argv); + + try { + using namespace ntt; + + testPusher>({ 10, 10, 10 }); + + } catch (std::exception& e) { + std::cerr << e.what() << std::endl; + Kokkos::finalize(); + return 1; + } + Kokkos::finalize(); + return 0; +} diff --git a/src/metrics/tests/coord_trans.cpp b/src/metrics/tests/coord_trans.cpp index 1e9a634fe..67dcdda53 100644 --- a/src/metrics/tests/coord_trans.cpp +++ b/src/metrics/tests/coord_trans.cpp @@ -82,7 +82,7 @@ void testMetric(const std::vector& res, coord_t x_Code_2 { ZERO }; coord_t x_Phys_1 { ZERO }; coord_t x_Sph_1 { ZERO }; - for (auto d { 0u }; d < D; ++d) { + for (auto d { 0u }; d < M::Dim; ++d) { x_Code_1[d] = (real_t)(idx[d]) + HALF; } metric.template convert(x_Code_1, x_Phys_1); From 28f9d18128ac45bf2a4be78b91b052b529338067 Mon Sep 17 00:00:00 2001 From: hayk Date: Mon, 14 Apr 2025 10:17:15 -0400 Subject: [PATCH 612/773] device compile flag passed + accuracy in pusher test --- CMakeLists.txt | 7 +++++++ cmake/styling.cmake | 9 +++++++-- src/kernels/tests/pusher.cpp | 2 +- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index bee7a3a7c..c328e8b84 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -88,6 +88,13 @@ include_directories(${plog_SRC}/include) # -------------------------------- Main code ------------------------------- # set_precision(${precision}) +if("${Kokkos_DEVICES}" MATCHES "CUDA") + add_compile_options("-D CUDA_ENABLED") +elseif("${Kokkos_DEVICES}" MATCHES "HIP") + add_compile_options("-D HIP_ENABLED") +elseif("${Kokkos_DEVICES}" MATCHES "SYCL") + add_compile_options("-D SYCL_ENABLED") +endif() # MPI if(${mpi}) diff --git a/cmake/styling.cmake b/cmake/styling.cmake index 878cb44a4..5f1e4a7ad 100644 --- a/cmake/styling.cmake +++ b/cmake/styling.cmake @@ -86,8 +86,6 @@ function( if(${Padding} EQUAL 0) list(LENGTH "${Choices}" nchoices) math(EXPR lastchoice "${nchoices} - 1") - set(ncols 4) - math(EXPR lastcol "${ncols} - 1") set(longest 0) foreach(ch IN LISTS Choices) @@ -97,6 +95,13 @@ function( endif() endforeach() + if(longest GREATER 20) + set(ncols 3) + else() + set(ncols 4) + endif() + math(EXPR lastcol "${ncols} - 1") + set(counter 0) foreach(ch IN LISTS Choices) if(NOT ${Value} STREQUAL "") diff --git a/src/kernels/tests/pusher.cpp b/src/kernels/tests/pusher.cpp index be2154f71..8496b592d 100644 --- a/src/kernels/tests/pusher.cpp +++ b/src/kernels/tests/pusher.cpp @@ -152,7 +152,7 @@ void testPusher(const std::vector& res) { const auto u0_cross_b_x2 = (ux3_0 * bx1 - ux1_0 * bx3) / b_mag; const auto u0_cross_b_x3 = (ux1_0 * bx2 - ux2_0 * bx1) / b_mag; - const real_t eps = std::is_same_v ? 1e-2 : 1e-4; + const real_t eps = std::is_same_v ? 1e-2 : 1e-3; for (auto t { 0u }; t < 2000; ++t) { const real_t time = t * dt; From a4ff0940c3913e7da31a87628b5cd6fdc0cee206 Mon Sep 17 00:00:00 2001 From: hayk Date: Mon, 14 Apr 2025 10:19:25 -0400 Subject: [PATCH 613/773] (RUNTEST) --- dev/runners/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/dev/runners/README.md b/dev/runners/README.md index 957898fa7..0aac76e2d 100644 --- a/dev/runners/README.md +++ b/dev/runners/README.md @@ -24,4 +24,5 @@ docker run -e TOKEN= -e LABEL=amd-gpu --device=/dev/kfd --device=/dev/dri ```sh docker build -t ghrunner:cpu -f Dockerfile.runner.cpu . +docker run -e TOKEN= -e LABEL=cpu -dt ghrunner:cpu ``` From 63b848c06a770e841e07ff85468b22609d04d2b4 Mon Sep 17 00:00:00 2001 From: haykh Date: Mon, 14 Apr 2025 11:07:35 -0400 Subject: [PATCH 614/773] ROCm version in engine printer --- src/engines/engine_printer.cpp | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/src/engines/engine_printer.cpp b/src/engines/engine_printer.cpp index eb8ff402d..66725fd5d 100644 --- a/src/engines/engine_printer.cpp +++ b/src/engines/engine_printer.cpp @@ -17,6 +17,8 @@ #if defined(CUDA_ENABLED) #include +#elif defined(HIP_ENABLED) + #include #endif #if defined(OUTPUT_ENABLED) @@ -104,8 +106,8 @@ namespace ntt { color::RESET); } - auto bytes_to_human_readable(std::size_t bytes) - -> std::pair { + auto bytes_to_human_readable( + std::size_t bytes) -> std::pair { const std::vector units { "B", "KB", "MB", "GB", "TB" }; idx_t unit_idx = 0; auto size = static_cast(bytes); @@ -177,8 +179,16 @@ namespace ntt { const auto minor { cuda_v % 1000 / 10 }; const auto patch { cuda_v % 10 }; const auto cuda_version = fmt::format("%d.%d.%d", major, minor, patch); -#else // not CUDA_ENABLED - const std::string cuda_version = "OFF"; +#elif defined(HIP_ENABLED) + int hip_v; + auto status = hipDriverGetVersion(&hip_v); + raise::ErrorIf(status != hipSuccess, + "hipDriverGetVersion failed with error code %d", + HERE); + const auto major { hip_v / 10000000 }; + const auto minor { (hip_v % 10000000) / 100000 }; + const auto patch { hip_v % 100000 }; + const auto hip_version = fmt::format("%d.%d.%d", major, minor, patch); #endif const auto kokkos_version = fmt::format("%d.%d.%d", @@ -207,7 +217,11 @@ namespace ntt { add_category(report, 4, "Backend"); add_param(report, 4, "Build hash", "%s", hash.c_str()); add_param(report, 4, "CXX", "%s [%s]", ccx.c_str(), cpp_standard.c_str()); +#if defined(CUDA_ENABLED) add_param(report, 4, "CUDA", "%s", cuda_version.c_str()); +#elif defined(HIP_VERSION) + add_param(report, 4, "HIP", "%s", hip_version.c_str()); +#endif add_param(report, 4, "MPI", "%s", mpi_version.c_str()); add_param(report, 4, "Kokkos", "%s", kokkos_version.c_str()); add_param(report, 4, "ADIOS2", "%s", adios2_version.c_str()); @@ -224,7 +238,7 @@ namespace ntt { add_param(report, 4, "Engine", "%s", SimEngine(S).to_string()); add_param(report, 4, "Metric", "%s", Metric(M::MetricType).to_string()); add_param(report, 4, "Timestep [dt]", "%.3e", dt); - add_param(report, 4, "Runtime", "%.3Le [%d steps]", runtime, max_steps); + add_param(report, 4, "Runtime", "%.3e [%d steps]", runtime, max_steps); report += "\n"; add_category(report, 4, "Global domain"); add_param(report, From 88800e295a1592e5ffb5eb06a2730f16c4b019cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20B=C3=B6ss?= Date: Mon, 14 Apr 2025 11:06:03 -0500 Subject: [PATCH 615/773] alternative BC fields for testing --- setups/srpic/shock/pgen.hpp | 58 +++++++++++++++++++++++++++++++++---- 1 file changed, 52 insertions(+), 6 deletions(-) diff --git a/setups/srpic/shock/pgen.hpp b/setups/srpic/shock/pgen.hpp index a5c05b6c6..2ca20741b 100644 --- a/setups/srpic/shock/pgen.hpp +++ b/setups/srpic/shock/pgen.hpp @@ -66,6 +66,45 @@ namespace user { const real_t Btheta, Bphi, Vx, Bmag; }; + template + struct BCFields { + + BCFields(real_t bmag, real_t btheta, real_t bphi, real_t drift_ux) + : Bmag { bmag } + , Btheta { btheta * static_cast(convert::deg2rad) } + , Bphi { bphi * static_cast(convert::deg2rad) } + , Vx { drift_ux } {} + + // magnetic field components + Inline auto bx1(const coord_t&) const -> real_t { + return Bmag * math::cos(ZERO); + } + + Inline auto bx2(const coord_t&) const -> real_t { + return Bmag * math::sin(ZERO) * math::sin(ZERO); + } + + Inline auto bx3(const coord_t&) const -> real_t { + return Bmag * math::sin(ZERO) * math::cos(ZERO); + } + + // electric field components + Inline auto ex1(const coord_t&) const -> real_t { + return ZERO; + } + + Inline auto ex2(const coord_t&) const -> real_t { + return -Vx * Bmag * math::sin(ZERO) * math::cos(ZERO); + } + + Inline auto ex3(const coord_t&) const -> real_t { + return Vx * Bmag * math::sin(ZERO) * math::sin(ZERO); + } + + private: + const real_t Btheta, Bphi, Vx, Bmag; + }; + template struct PGen : public arch::ProblemGenerator { // compatibility traits for the problem generator @@ -90,6 +129,7 @@ namespace user { // magnetic field properties real_t Btheta, Bphi, Bmag; InitFields init_flds; + BCFields bc_flds; inline PGen(const SimulationParams& p, const Metadomain& global_domain) : arch::ProblemGenerator { p } @@ -101,6 +141,7 @@ namespace user { , Btheta { p.template get("setup.Btheta", ZERO) } , Bphi { p.template get("setup.Bphi", ZERO) } , init_flds { Bmag, Btheta, Bphi, drift_ux } + , bc_flds { Bmag, Btheta, Bphi, drift_ux } , filling_fraction { p.template get("setup.filling_fraction", 1.0) } , injector_velocity { p.template get("setup.injector_velocity", 1.0) } , injection_start { p.template get("setup.injection_start", 0.0) } @@ -109,8 +150,8 @@ namespace user { inline PGen() {} - auto MatchFields(real_t time) const -> InitFields { - return init_flds; + auto MatchFields(real_t time) const -> BCFields { + return bc_flds; } auto FixFieldsConst(const bc_in&, const em& comp) const @@ -196,13 +237,16 @@ namespace user { } // compute the beginning of the injected region - const auto xmin = xmax - drift_ux / math::sqrt(1 + SQR(drift_ux)) * dt - - injection_frequency * dt; + auto xmin = xmax - drift_ux / math::sqrt(1 + SQR(drift_ux)) * dt - + injection_frequency * dt; + if (xmin <= global_xmin) { + xmin = global_xmin; + } // define indice range to reset fields boundaries_t incl_ghosts; for (auto d = 0; d < M::Dim; ++d) { - incl_ghosts.push_back({ true, true }); + incl_ghosts.push_back({ false, false }); } // define box to reset fields @@ -240,6 +284,7 @@ namespace user { // get particle properties auto& species = domain.species[s]; auto i1 = species.i1; + auto dx1 = species.dx1; auto tag = species.tag; // tag all particles with x > box[0].first as dead @@ -252,7 +297,8 @@ namespace user { return; } // select the x-coordinate index - auto x_i1 = i1(p); + auto x_i1 = static_cast(i1(p)) + dx1(p) + N_GHOSTS; + // check if the particle is inside the box of new plasma if (x_i1 >= x_min[0]) { tag(p) = ParticleTag::dead; From 124923e8a2d9cad93e53c255245934c23fd6e125 Mon Sep 17 00:00:00 2001 From: hayk Date: Wed, 16 Apr 2025 14:02:48 -0400 Subject: [PATCH 616/773] README contribs --- README.md | 37 ++++++++++++------------------------- 1 file changed, 12 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index 7287d52db..915a5b358 100644 --- a/README.md +++ b/README.md @@ -10,33 +10,20 @@ Our [detailed documentation](https://entity-toolkit.github.io/) includes everyth [![License](https://img.shields.io/badge/License-BSD%203--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause) -## Lead developers - -☕ __Hayk Hakobyan__ {[@haykh](https://github.com/haykh)} - -🥔 __Jens Mahlmann__ {[@jmahlmann](https://github.com/jmahlmann)} - -💁‍♂️ __Alexander Chernoglazov__ {[@SChernoglazov](https://github.com/SChernoglazov)} - -🧋 __Alisa Galishnikova__ {[@alisagk](https://github.com/alisagk)} - -🐬 __Sasha Philippov__ {[@sashaph](https://github.com/sashaph)} - ## Contributors (alphabetical) -🎸 __Ludwig Böss__ {[@LudwigBoess](https://github.com/LudwigBoess): PIC, framework} - -👀 __Yangyang Cai__ {[@StaticObserver](https://github.com/StaticObserver): GRPIC} - -🍵 __Benjamin Crinquand__ {[@bcrinquand](https://github.com/bcrinquand): GRPIC, cubed-sphere} - -🚂 __Evgeny Gorbunov__ {[@Alcauchy](https://github.com/Alcauchy): PIC, framework} - -:radio: __Siddhant Solanki__ {[@sidruns30](https://github.com/sidruns30): framework} - -🤷 __Arno Vanthieghem__ {[@vanthieg](https://github.com/vanthieg): framework, PIC} - -😺 __Muni Zhou__ {[@munizhou](https://github.com/munizhou): PIC} +* :guitar: Ludwig Böss {[@LudwigBoess](https://github.com/LudwigBoess)} +* :eyes: Yangyang Cai {[@StaticObserver](https://github.com/StaticObserver)} +* :person_tipping_hand: Alexander Chernoglazov {[@SChernoglazov](https://github.com/SChernoglazov)} +* :tea: Benjamin Crinquand {[@bcrinquand](https://github.com/bcrinquand)} +* :bubble_tea: Alisa Galishnikova {[@alisagk](https://github.com/alisagk)} +* :locomotive: Evgeny Gorbunov {[@Alcauchy](https://github.com/Alcauchy)} +* :coffee: Hayk Hakobyan {[@haykh](https://github.com/haykh)} +* :potato: Jens Mahlmann {[@jmahlmann](https://github.com/jmahlmann)} +* :dolphin: Sasha Philippov {[@sashaph](https://github.com/sashaph)} +* :radio: Siddhant Solanki {[@sidruns30](https://github.com/sidruns30)} +* :shrug: Arno Vanthieghem {[@vanthieg](https://github.com/vanthieg)} +* :cat: Muni Zhou {[@munizhou](https://github.com/munizhou)} ## Branch policy From ffe70459634932da6f4621ef3cf44b3c6fd42a3e Mon Sep 17 00:00:00 2001 From: gorbunove Date: Wed, 16 Apr 2025 13:04:15 -0500 Subject: [PATCH 617/773] turbulence setup --- setups/wip/turbulence/pgen.hpp | 250 ++++++++++++++++++++++++++ setups/wip/turbulence/turbulence.toml | 60 +++++++ src/engines/srpic.hpp | 35 +++- src/global/arch/traits.h | 4 + src/kernels/ampere_mink.hpp | 60 ++++++- 5 files changed, 396 insertions(+), 13 deletions(-) create mode 100644 setups/wip/turbulence/pgen.hpp create mode 100644 setups/wip/turbulence/turbulence.toml diff --git a/setups/wip/turbulence/pgen.hpp b/setups/wip/turbulence/pgen.hpp new file mode 100644 index 000000000..14097e966 --- /dev/null +++ b/setups/wip/turbulence/pgen.hpp @@ -0,0 +1,250 @@ +#ifndef PROBLEM_GENERATOR_H +#define PROBLEM_GENERATOR_H + +#include "enums.h" +#include "global.h" + +#include "arch/kokkos_aliases.h" +#include "arch/traits.h" + +#include "archetypes/energy_dist.h" +#include "archetypes/particle_injector.h" +#include "archetypes/problem_generator.h" +#include "framework/domain/domain.h" +#include "framework/domain/metadomain.h" + +namespace user { + using namespace ntt; + + //external current definition + template + struct ExternalCurrent{ + ExternalCurrent(real_t dB, real_t om0, real_t g0, std::vector< std::vector >& wavenumbers, random_number_pool_t& random_pool, real_t Lx, real_t Ly, real_t Lz) + : dB { dB } + , omega_0 { om0 } + , gamma_0 { g0 } + , wavenumbers { wavenumbers } + , n_modes {wavenumbers.size()} + , Lx { Lx } + , Ly { Ly } + , Lz { Lz } + , k { "wavevector", 2, wavenumbers.size() } + , u_imag { "u imaginary", wavenumbers.size() } + , u_real { "u_real", wavenumbers.size() } + , a_real { "a_real", wavenumbers.size() } + , a_imag { "a_imag", wavenumbers.size() } + , a_real_inv { "a_real", wavenumbers.size() } + , a_imag_inv { "a_imag", wavenumbers.size() } + + , A0 {"A0", wavenumbers.size()} + { + // initializing wavevectors + auto k_host = Kokkos::create_mirror_view(k); + for (auto i = 0; i < n_modes; i++){ + for(size_t j = 0; j < 2; j++){ + k_host(j,i) = constant::TWO_PI * wavenumbers[i][j] / Lx; + } + printf("k(%d) = (%f, %f)\n", i,k_host(0,i), k_host(1,i)); + } + + + // initializing initial complex amplitudes + auto a_real_host = Kokkos::create_mirror_view(a_real); + auto a_imag_host = Kokkos::create_mirror_view(a_imag); + auto A0_host = Kokkos::create_mirror_view(A0); + for (auto i = 0; i < n_modes; i++){ + auto k_perp = math::sqrt(k_host(0,i) * k_host(0,i) + k_host(1,i) * k_host(1,i)); + auto phase = constant::TWO_PI / 6.; + A0_host(i) = dB / math::sqrt((real_t) n_modes) / k_perp; + a_real_host(i) = A0_host(i) * math::cos(phase); + a_imag_host(i) = A0_host(i) * math::sin(phase); + printf("A0(%d) = %f\n", i,A0_host(i)); + printf("a_real(%d) = %f\n", i,a_real_host(i)); + printf("a_imag(%d) = %f\n", i,a_imag_host(i)); + + + } + + Kokkos::deep_copy(a_real, a_real_host); + Kokkos::deep_copy(a_imag, a_imag_host); + Kokkos::deep_copy(a_real_inv, a_real_host); + Kokkos::deep_copy(a_imag_inv, a_imag_host); + + Kokkos::deep_copy(A0, A0_host); + Kokkos::deep_copy(k, k_host); + // Kokkos::parallel_for( "Generate random ", wavenumbers.size(), Lambda (int const i){ + // auto generator = random_pool.get_state(); + // a_real(i) = generator.frand(0.0, 1.0); + // a_imag(i) = generator.frand(0.0, 1.0); + // printf(" Initial amplitudes (%i) a_real= %f, a_imag= %f\n",i + // , a_real(i) + // , a_imag(i)); + // random_pool.free_state(generator); + // }); + }; + + + Inline auto jx3(const coord_t& x_Ph) const -> real_t { + if constexpr(D == Dim::_2D){ + real_t jx3_ant = ZERO; + for (size_t i=0; i < n_modes; i++){ + //k(i,0) + k(i,1); + auto k_perp_sq = k(0,i) * k(0,i) + k(1,i) * k(1,i); + auto k_dot_r = k(0,i) * x_Ph[0] + k(1,i) * x_Ph[1]; + jx3_ant -= TWO * k_perp_sq * (a_real(i) * math::cos(k_dot_r) + - a_imag(i) * math::sin(k_dot_r)); + jx3_ant -= TWO * k_perp_sq * (a_real_inv(i) * math::cos(k_dot_r) + - a_imag_inv(i) * math::sin(k_dot_r)); + + } + return jx3_ant; + } + if constexpr(D == Dim::_3D){ + real_t jx3_ant = ZERO; + for (size_t i=0; i < n_modes; i++){ +// k_perp_sq = k[i][0] + k[i][1]; +// jx3_ant -= TWO * k_perp_sq * (ONE * math::cos(k[i][0] * x_Ph[0] + k[i][1] * x_Ph[1] + k[i][2] * x_Ph[2]) +// + ONE * math::sin(k[i][0] * x_Ph[0] + k[i][1] * x_Ph[1] + k[i][2] * x_Ph[2])); + } + return jx3_ant; + } +// printf("jz_ant = %f\n", jx3_ant); + + } + Inline auto jx2(const coord_t& x_Ph) const -> real_t { + if constexpr(D == Dim::_2D){ + return ZERO; + } + if constexpr(D == Dim::_3D){ + return ZERO; + } + } + Inline auto jx1(const coord_t& x_Ph) const -> real_t { + if constexpr(D == Dim::_2D){ + return ZERO; + } + if constexpr(D == Dim::_3D){ + return ZERO; + } + } + + const real_t dB, omega_0, gamma_0, Lx, Ly, Lz; + const size_t n_modes; + array_t k; + array_t A0; + public: + array_t a_real; + array_t a_imag; + array_t u_imag; + array_t a_real_inv; + array_t a_imag_inv; + array_t u_real; + const std::vector< std::vector > wavenumbers; + }; + + template + struct PGen : public arch::ProblemGenerator { + + // compatibility traits for the problem generator + static constexpr auto engines = traits::compatible_with::value; + static constexpr auto metrics = traits::compatible_with::value; + static constexpr auto dimensions = + traits::compatible_with::value; + + // for easy access to variables in the child class + using arch::ProblemGenerator::D; + using arch::ProblemGenerator::C; + using arch::ProblemGenerator::params; + + const real_t temperature, dB, omega_0, gamma_0, Lx, Ly, Lz, dt; + std::vector< std::vector > wavenumbers; + random_number_pool_t random_pool; + + + ExternalCurrent ExternalCurrent; + + inline PGen(const SimulationParams& p, const Metadomain& global_domain) + : arch::ProblemGenerator { p } + , temperature { p.template get("setup.temperature") } + , dB { p.template get("setup.dB", 1.) } + , omega_0 { p.template get("setup.omega_0", 0.5) } + , gamma_0 { p.template get("setup.gamma_0", 0.25) } + , wavenumbers { { { 1, 0, 1 }, + { 0, 1, 1 }, + { 1, 1, 1 }, + { -1, 1, 1 }} } + , random_pool{ 0 } + , Lx { global_domain.mesh().extent(in::x1).second - global_domain.mesh().extent(in::x1).first } + , Ly { global_domain.mesh().extent(in::x2).second - global_domain.mesh().extent(in::x2).first } + , Lz { global_domain.mesh().extent(in::x3).second - global_domain.mesh().extent(in::x3).first } + , dt { params.template get("algorithms.timestep.dt") } + , ExternalCurrent { dB, omega_0, gamma_0, wavenumbers, random_pool, Lx, Ly, Lz }{} + + inline PGen() {} + + inline void InitPrtls(Domain& local_domain) { + const auto energy_dist = arch::Maxwellian(local_domain.mesh.metric, + local_domain.random_pool, + temperature, + ZERO); + const auto spatial_dist = arch::UniformInjector( + energy_dist, + { 1, 2 }); + arch::InjectUniform>( + params, + local_domain, + spatial_dist, + ONE); + + } + + void CustomPostStep(timestep_t, simtime_t time, Domain& domain){ + + //generate white noise +// Kokkos::parallel_for( "Generate random ", wavenumbers.size(), ClassLambda (int const i){ +// auto generator = random_pool.get_state(); +// this->ExternalCurrent.u_real(i) = generator.frand(-0.5, 0.5); +// this->ExternalCurrent.u_imag(i) = generator.frand(-0.5, 0.5); +// printf(" %i) u_real= %f, u_imag= %f\n",i +// , this->ExternalCurrent.u_real(i) +// , this->ExternalCurrent.u_imag(i)); +// random_pool.free_state(generator); +// }); + + // update amplitudes of antenna + Kokkos::parallel_for( " Antenna amplitudes ", wavenumbers.size(), Lambda (int const i){ + auto generator = random_pool.get_state(); + const auto u_imag = generator.frand(-0.5, 0.5); + const auto u_real = generator.frand(-0.5, 0.5); + const auto u_real_inv = generator.frand(-0.5,0.5); + const auto u_imag_inv = generator.frand(-0.5,0.5); + printf(" %i) u_real= %f, u_imag= %f, u_real_inv = %f, u_imag_inv = %f\n",i + , u_real + , u_imag + , u_real_inv + , u_imag_inv); + random_pool.free_state(generator); + random_pool.free_state(generator); + auto a_real_prev = this->ExternalCurrent.a_real(i); + auto a_imag_prev = this->ExternalCurrent.a_imag(i); + auto a_real_inv_prev = this->ExternalCurrent.a_real_inv(i); + auto a_imag_inv_prev = this->ExternalCurrent.a_imag_inv(i); + + printf(" %i) a_real= %f, a_imag= %f\n",i + , this->ExternalCurrent.a_real(i) + , this->ExternalCurrent.a_imag(i)); + this->ExternalCurrent.a_real(i) = (a_real_prev * math::cos(this->ExternalCurrent.omega_0 * time) - a_imag_prev * math::sin(this->ExternalCurrent.omega_0 * time)) * math::exp(-this->ExternalCurrent.gamma_0 * time) + this->ExternalCurrent.A0(i) * math::sqrt(12.0 * this->ExternalCurrent.gamma_0 / this->dt ) * u_real * this->dt; + + this->ExternalCurrent.a_imag(i) = (a_imag_prev * math::cos(this->ExternalCurrent.omega_0 * time) + a_real_prev * math::sin(this->ExternalCurrent.omega_0 * time)) * math::exp(-this->ExternalCurrent.gamma_0 * time) + this->ExternalCurrent.A0(i) * math::sqrt(12.0 * this->ExternalCurrent.gamma_0 / this->dt ) * u_imag * this->dt; + + this->ExternalCurrent.a_real_inv(i) = (a_real_inv_prev * math::cos(-this->ExternalCurrent.omega_0 * time) - a_imag_inv_prev * math::sin(-this->ExternalCurrent.omega_0 * time)) * math::exp(-this->ExternalCurrent.gamma_0 * time) + this->ExternalCurrent.A0(i) * math::sqrt(12.0 * this->ExternalCurrent.gamma_0 / this->dt ) * u_real_inv * this->dt; + + this->ExternalCurrent.a_imag_inv(i) = (a_imag_inv_prev * math::cos(-this->ExternalCurrent.omega_0 * time) + a_real_inv_prev * math::sin(-this->ExternalCurrent.omega_0 * time)) * math::exp(-this->ExternalCurrent.gamma_0 * time) + this->ExternalCurrent.A0(i) * math::sqrt(12.0 * this->ExternalCurrent.gamma_0 / this->dt ) * u_imag_inv * this->dt; + }); + + } + }; + +} // namespace user + +#endif diff --git a/setups/wip/turbulence/turbulence.toml b/setups/wip/turbulence/turbulence.toml new file mode 100644 index 000000000..b66da04df --- /dev/null +++ b/setups/wip/turbulence/turbulence.toml @@ -0,0 +1,60 @@ +[simulation] + name = "weibel" + engine = "srpic" + runtime = 100.0 + +[grid] + resolution = [512, 512] + extent = [[-10.0, 10.0], [-10.0, 10.0]] + + [grid.metric] + metric = "minkowski" + + [grid.boundaries] + fields = [["PERIODIC"], ["PERIODIC"]] + particles = [["PERIODIC"], ["PERIODIC"]] + +[scales] + larmor0 = 1.0 + skindepth0 = 1.0 + +[algorithms] + current_filters = 4 + + [algorithms.timestep] + CFL = 0.5 + +[particles] + ppc0 = 16.0 + + [[particles.species]] + label = "e-_p" + mass = 1.0 + charge = -1.0 + maxnpart = 1e7 + + [[particles.species]] + label = "e+_p" + mass = 1.0 + charge = 1.0 + maxnpart = 1e7 + +[setup] + temperature = 1e-4 + dB = 1.0 + +[output] + format = "hdf5" + interval_time = 0.25 + + [output.fields] + quantities = ["N_1_2", "J", "B", "E", "T0i_1", "T0i_3"] + + [output.particles] + enable = false + + [output.spectra] + enable = false + +[diagnostics] + colored_stdout = true diff --git a/src/engines/srpic.hpp b/src/engines/srpic.hpp index a25df3fab..93363054a 100644 --- a/src/engines/srpic.hpp +++ b/src/engines/srpic.hpp @@ -529,14 +529,33 @@ namespace ntt { if constexpr (M::CoordType == Coord::Cart) { // minkowski case const auto V0 = m_params.template get("scales.V0"); - - Kokkos::parallel_for( - "Ampere", - domain.mesh.rangeActiveCells(), - kernel::mink::CurrentsAmpere_kernel(domain.fields.em, - domain.fields.cur, - coeff / V0, - ONE / n0)); + if constexpr(traits::has_member::value){ + const std::vector xmin {domain.mesh.extent(in::x1).first, + domain.mesh.extent(in::x2).first, + domain.mesh.extent(in::x3).first}; + const auto ext_current = m_pgen.ExternalCurrent; + const auto dx = domain.mesh.metric.template sqrt_h_<1, 1>({}); + Kokkos::parallel_for( + "Ampere", + domain.mesh.rangeActiveCells(), + kernel::mink::CurrentsAmpere_kernel(domain.fields.em, + domain.fields.cur, + coeff / V0, + ONE / n0, + ext_current, + xmin, + dx)); + } + else{ + Kokkos::parallel_for( + "Ampere", + domain.mesh.rangeActiveCells(), + kernel::mink::CurrentsAmpere_kernel(domain.fields.em, + domain.fields.cur, + coeff / V0, + ONE / n0)); + + } } else { auto range = range_with_axis_BCs(domain); const auto ni2 = domain.mesh.n_active(in::x2); diff --git a/src/global/arch/traits.h b/src/global/arch/traits.h index 127218090..d086d41bc 100644 --- a/src/global/arch/traits.h +++ b/src/global/arch/traits.h @@ -10,6 +10,7 @@ * - traits::run_t, traits::to_string_t * - traits::pgen::init_flds_t * - traits::pgen::ext_force_t + * - traits::pgen::ext_current_t * - traits::pgen::atm_fields_t * - traits::pgen::match_fields_const_t * - traits::pgen::match_fields_t @@ -97,6 +98,9 @@ namespace traits { template using ext_force_t = decltype(&T::ext_force); + template + using ext_current_t = decltype(&T::ExternalCurrent); + template using atm_fields_t = decltype(&T::AtmFields); diff --git a/src/kernels/ampere_mink.hpp b/src/kernels/ampere_mink.hpp index 16ed1655a..4b0480482 100644 --- a/src/kernels/ampere_mink.hpp +++ b/src/kernels/ampere_mink.hpp @@ -18,7 +18,9 @@ namespace kernel::mink { using namespace ntt; - + struct NoCurrent_t{ + NoCurrent_t(){} + }; /** * @brief Algorithm for the Ampere's law: `dE/dt = curl B` in Minkowski space. * @tparam D Dimension. @@ -88,30 +90,63 @@ namespace kernel::mink { * @brief `coeff` includes metric coefficient. * @tparam D Dimension. */ - template + template class CurrentsAmpere_kernel { + static constexpr auto ExtCurrent = not std::is_same::value; ndfield_t E; ndfield_t J; // coeff = -dt * q0 * n0 / (B0 * V0) const real_t coeff; const real_t inv_n0; + const C ext_current; + real_t x1min {ZERO}; + real_t x2min {ZERO}; + real_t x3min {ZERO}; + real_t dx; public: CurrentsAmpere_kernel(const ndfield_t& E, const ndfield_t J, real_t coeff, - real_t inv_n0) + real_t inv_n0, + const C& ext_current, + const std::vector xmin, + real_t dx) : E { E } , J { J } , coeff { coeff } - , inv_n0 { inv_n0 } {} + , inv_n0 { inv_n0 } + , ext_current { ext_current } + , x1min { xmin.size() > 0 ? xmin[0] : ZERO } + , x2min { xmin.size() > 1 ? xmin[1] : ZERO } + , x3min { xmin.size() > 2 ? xmin[2] : ZERO } + , dx { dx }{} + + CurrentsAmpere_kernel(const ndfield_t& E, + const ndfield_t J, + real_t coeff, + real_t inv_n0): + CurrentsAmpere_kernel{E, + J, + coeff, + inv_n0, + NoCurrent_t{}, + {}, + ZERO}{} Inline void operator()(index_t i1) const { if constexpr (D == Dim::_1D) { + if constexpr (ExtCurrent){ + const auto i1_ = COORD(i1); + J(i1, cur::jx1) += ext_current.jx1({(i1_ + HALF) * dx + x1min}); + J(i1, cur::jx2) += ext_current.jx2({i1_ * dx + x1min}); + J(i1, cur::jx3) += ext_current.jx3({i1_ * dx + x1min}); + + } J(i1, cur::jx1) *= inv_n0; J(i1, cur::jx2) *= inv_n0; J(i1, cur::jx3) *= inv_n0; - + E(i1, em::ex1) += J(i1, cur::jx1) * coeff; E(i1, em::ex2) += J(i1, cur::jx2) * coeff; E(i1, em::ex3) += J(i1, cur::jx3) * coeff; @@ -124,6 +159,13 @@ namespace kernel::mink { Inline void operator()(index_t i1, index_t i2) const { if constexpr (D == Dim::_2D) { + if constexpr (ExtCurrent){ + const auto i1_ = COORD(i1); + const auto i2_ = COORD(i2); + J(i1, i2, cur::jx1) += ext_current.jx1({(i1_ + HALF) * dx + x1min , i2_ * dx + x2min } ); + J(i1, i2, cur::jx2) += ext_current.jx2({i1_ * dx + x1min, (i2_ + HALF) * dx + x2min}); + J(i1, i2, cur::jx3) += ext_current.jx3({i1_ * dx + x1min, i2_ * dx + x2min}); + } J(i1, i2, cur::jx1) *= inv_n0; J(i1, i2, cur::jx2) *= inv_n0; J(i1, i2, cur::jx3) *= inv_n0; @@ -141,6 +183,14 @@ namespace kernel::mink { Inline void operator()(index_t i1, index_t i2, index_t i3) const { if constexpr (D == Dim::_3D) { + if constexpr (ExtCurrent){ + const auto i1_ = COORD(i1); + const auto i2_ = COORD(i2); + const auto i3_ = COORD(i3); + J(i1, i2, i3, cur::jx1) += ext_current.jx1({(i1_ + HALF) * dx + x1min , i2_ * dx + x2min, i3_ * dx + x3min }); + J(i1, i2, i3, cur::jx2) += ext_current.jx2({i1_ * dx + x1min, (i2_ + HALF) * dx + x2min, i3_ * dx + x3min }); + J(i1, i2, i3, cur::jx3) += ext_current.jx3({i1_ * dx + x1min, i2_ * dx + x2min, (i3_ + HALF) * dx + x3min }); + } J(i1, i2, i3, cur::jx1) *= inv_n0; J(i1, i2, i3, cur::jx2) *= inv_n0; J(i1, i2, i3, cur::jx3) *= inv_n0; From bf730086156ff36a49ec5708e36b1c90ce74cf76 Mon Sep 17 00:00:00 2001 From: hayk Date: Wed, 16 Apr 2025 14:53:02 -0400 Subject: [PATCH 618/773] deposit with ext curr + fix bug in current output --- src/engines/srpic.hpp | 64 ++++++++--------- src/kernels/ampere_mink.hpp | 138 +++++++++++++++++++----------------- 2 files changed, 105 insertions(+), 97 deletions(-) diff --git a/src/engines/srpic.hpp b/src/engines/srpic.hpp index 95f933ff4..fc27337cb 100644 --- a/src/engines/srpic.hpp +++ b/src/engines/srpic.hpp @@ -522,41 +522,41 @@ namespace ntt { void CurrentsAmpere(domain_t& domain) { logger::Checkpoint("Launching Ampere kernel for adding currents", HERE); - const auto q0 = m_params.template get("scales.q0"); - const auto n0 = m_params.template get("scales.n0"); - const auto B0 = m_params.template get("scales.B0"); - const auto coeff = -dt * q0 * n0 / B0; + const auto q0 = m_params.template get("scales.q0"); + const auto n0 = m_params.template get("scales.n0"); + const auto B0 = m_params.template get("scales.B0"); if constexpr (M::CoordType == Coord::Cart) { + const auto ppc0 = m_params.template get("particles.ppc0"); + const auto coeff = -dt * q0 / (B0 * V0); // minkowski case - const auto V0 = m_params.template get("scales.V0"); - if constexpr(traits::has_member::value){ - const std::vector xmin {domain.mesh.extent(in::x1).first, - domain.mesh.extent(in::x2).first, - domain.mesh.extent(in::x3).first}; - const auto ext_current = m_pgen.ExternalCurrent; - const auto dx = domain.mesh.metric.template sqrt_h_<1, 1>({}); - Kokkos::parallel_for( - "Ampere", - domain.mesh.rangeActiveCells(), - kernel::mink::CurrentsAmpere_kernel(domain.fields.em, - domain.fields.cur, - coeff / V0, - ONE / n0, - ext_current, - xmin, - dx)); - } - else{ - Kokkos::parallel_for( - "Ampere", - domain.mesh.rangeActiveCells(), - kernel::mink::CurrentsAmpere_kernel(domain.fields.em, - domain.fields.cur, - coeff / V0, - ONE / n0)); - - } + const auto V0 = m_params.template get("scales.V0"); + if constexpr ( + traits::has_member::value) { + const std::vector xmin { domain.mesh.extent(in::x1).first, + domain.mesh.extent(in::x2).first, + domain.mesh.extent(in::x3).first }; + const auto ext_current = m_pgen.ExternalCurrent; + const auto dx = domain.mesh.metric.template sqrt_h_<1, 1>({}); + // clang-format off + Kokkos::parallel_for( + "Ampere", + domain.mesh.rangeActiveCells(), + kernel::mink::CurrentsAmpere_kernel( + domain.fields.em, domain.fields.cur, + coeff, ppc0, ext_current, xmin, dx)); + // clang-format on + } else { + Kokkos::parallel_for( + "Ampere", + domain.mesh.rangeActiveCells(), + kernel::mink::CurrentsAmpere_kernel(domain.fields.em, + domain.fields.cur, + coeff, + ppc0)); + } } else { + // non-minkowski + const auto coeff = -dt * q0 * n0 / B0; auto range = range_with_axis_BCs(domain); const auto ni2 = domain.mesh.n_active(in::x2); Kokkos::parallel_for( diff --git a/src/kernels/ampere_mink.hpp b/src/kernels/ampere_mink.hpp index 4b0480482..32f6805e7 100644 --- a/src/kernels/ampere_mink.hpp +++ b/src/kernels/ampere_mink.hpp @@ -18,9 +18,11 @@ namespace kernel::mink { using namespace ntt; - struct NoCurrent_t{ - NoCurrent_t(){} + + struct NoCurrent_t { + NoCurrent_t() {} }; + /** * @brief Algorithm for the Ampere's law: `dE/dt = curl B` in Minkowski space. * @tparam D Dimension. @@ -92,64 +94,58 @@ namespace kernel::mink { */ template class CurrentsAmpere_kernel { - static constexpr auto ExtCurrent = not std::is_same::value; - ndfield_t E; - ndfield_t J; - // coeff = -dt * q0 * n0 / (B0 * V0) - const real_t coeff; - const real_t inv_n0; - const C ext_current; - real_t x1min {ZERO}; - real_t x2min {ZERO}; - real_t x3min {ZERO}; - real_t dx; + static constexpr auto ExtCurrent = not std::is_same::value; + ndfield_t E; + ndfield_t J; + // coeff = -dt * q0 / (B0 * V0) + const real_t coeff; + const real_t ppc0; + const C ext_current; + real_t x1min { ZERO }; + real_t x2min { ZERO }; + real_t x3min { ZERO }; + real_t dx; public: - CurrentsAmpere_kernel(const ndfield_t& E, - const ndfield_t J, - real_t coeff, - real_t inv_n0, - const C& ext_current, - const std::vector xmin, - real_t dx) + CurrentsAmpere_kernel(const ndfield_t& E, + const ndfield_t J, + real_t coeff, + real_t ppc0, + const C& ext_current, + const std::vector xmin, + real_t dx) : E { E } , J { J } , coeff { coeff } - , inv_n0 { inv_n0 } + , ppc0 { ppc0 } + , inv_ppc0 { inv_ppc0 } , ext_current { ext_current } - , x1min { xmin.size() > 0 ? xmin[0] : ZERO } + , x1min { xmin.size() > 0 ? xmin[0] : ZERO } , x2min { xmin.size() > 1 ? xmin[1] : ZERO } , x3min { xmin.size() > 2 ? xmin[2] : ZERO } - , dx { dx }{} + , dx { dx } {} CurrentsAmpere_kernel(const ndfield_t& E, const ndfield_t J, real_t coeff, - real_t inv_n0): - CurrentsAmpere_kernel{E, - J, - coeff, - inv_n0, - NoCurrent_t{}, - {}, - ZERO}{} + real_t inv_n0) + : CurrentsAmpere_kernel { E, J, coeff, inv_n0, NoCurrent_t {}, {}, ZERO } {} Inline void operator()(index_t i1) const { if constexpr (D == Dim::_1D) { - if constexpr (ExtCurrent){ - const auto i1_ = COORD(i1); - J(i1, cur::jx1) += ext_current.jx1({(i1_ + HALF) * dx + x1min}); - J(i1, cur::jx2) += ext_current.jx2({i1_ * dx + x1min}); - J(i1, cur::jx3) += ext_current.jx3({i1_ * dx + x1min}); - - } - J(i1, cur::jx1) *= inv_n0; - J(i1, cur::jx2) *= inv_n0; - J(i1, cur::jx3) *= inv_n0; - + if constexpr (ExtCurrent) { + const auto i1_ = COORD(i1); + J(i1, cur::jx1) += ppc0 * ext_current.jx1({ (i1_ + HALF) * dx + x1min }); + J(i1, cur::jx2) += ppc0 * ext_current.jx2({ i1_ * dx + x1min }); + J(i1, cur::jx3) += ppc0 * ext_current.jx3({ i1_ * dx + x1min }); + } E(i1, em::ex1) += J(i1, cur::jx1) * coeff; E(i1, em::ex2) += J(i1, cur::jx2) * coeff; E(i1, em::ex3) += J(i1, cur::jx3) * coeff; + + J(i1, cur::jx1) /= ppc0; + J(i1, cur::jx2) /= ppc0; + J(i1, cur::jx3) /= ppc0; } else { raise::KernelError( HERE, @@ -159,21 +155,24 @@ namespace kernel::mink { Inline void operator()(index_t i1, index_t i2) const { if constexpr (D == Dim::_2D) { - if constexpr (ExtCurrent){ - const auto i1_ = COORD(i1); - const auto i2_ = COORD(i2); - J(i1, i2, cur::jx1) += ext_current.jx1({(i1_ + HALF) * dx + x1min , i2_ * dx + x2min } ); - J(i1, i2, cur::jx2) += ext_current.jx2({i1_ * dx + x1min, (i2_ + HALF) * dx + x2min}); - J(i1, i2, cur::jx3) += ext_current.jx3({i1_ * dx + x1min, i2_ * dx + x2min}); - } - J(i1, i2, cur::jx1) *= inv_n0; - J(i1, i2, cur::jx2) *= inv_n0; - J(i1, i2, cur::jx3) *= inv_n0; - + if constexpr (ExtCurrent) { + const auto i1_ = COORD(i1); + const auto i2_ = COORD(i2); + J(i1, i2, cur::jx1) += ppc0 * ext_current.jx1({ (i1_ + HALF) * dx + x1min, + i2_ * dx + x2min }); + J(i1, i2, cur::jx2) += ppc0 * + ext_current.jx2({ i1_ * dx + x1min, + (i2_ + HALF) * dx + x2min }); + J(i1, i2, cur::jx3) += ppc0 * ext_current.jx3({ i1_ * dx + x1min, + i2_ * dx + x2min }); + } E(i1, i2, em::ex1) += J(i1, i2, cur::jx1) * coeff; E(i1, i2, em::ex2) += J(i1, i2, cur::jx2) * coeff; E(i1, i2, em::ex3) += J(i1, i2, cur::jx3) * coeff; + J(i1, i2, cur::jx1) /= ppc0; + J(i1, i2, cur::jx2) /= ppc0; + J(i1, i2, cur::jx3) /= ppc0; } else { raise::KernelError( HERE, @@ -183,21 +182,30 @@ namespace kernel::mink { Inline void operator()(index_t i1, index_t i2, index_t i3) const { if constexpr (D == Dim::_3D) { - if constexpr (ExtCurrent){ - const auto i1_ = COORD(i1); - const auto i2_ = COORD(i2); - const auto i3_ = COORD(i3); - J(i1, i2, i3, cur::jx1) += ext_current.jx1({(i1_ + HALF) * dx + x1min , i2_ * dx + x2min, i3_ * dx + x3min }); - J(i1, i2, i3, cur::jx2) += ext_current.jx2({i1_ * dx + x1min, (i2_ + HALF) * dx + x2min, i3_ * dx + x3min }); - J(i1, i2, i3, cur::jx3) += ext_current.jx3({i1_ * dx + x1min, i2_ * dx + x2min, (i3_ + HALF) * dx + x3min }); - } - J(i1, i2, i3, cur::jx1) *= inv_n0; - J(i1, i2, i3, cur::jx2) *= inv_n0; - J(i1, i2, i3, cur::jx3) *= inv_n0; - + if constexpr (ExtCurrent) { + const auto i1_ = COORD(i1); + const auto i2_ = COORD(i2); + const auto i3_ = COORD(i3); + J(i1, i2, i3, cur::jx1) += ppc0 * + ext_current.jx1({ (i1_ + HALF) * dx + x1min, + i2_ * dx + x2min, + i3_ * dx + x3min }); + J(i1, i2, i3, cur::jx2) += ppc0 * + ext_current.jx2({ i1_ * dx + x1min, + (i2_ + HALF) * dx + x2min, + i3_ * dx + x3min }); + J(i1, i2, i3, cur::jx3) += ppc0 * ext_current.jx3( + { i1_ * dx + x1min, + i2_ * dx + x2min, + (i3_ + HALF) * dx + x3min }); + } E(i1, i2, i3, em::ex1) += J(i1, i2, i3, cur::jx1) * coeff; E(i1, i2, i3, em::ex2) += J(i1, i2, i3, cur::jx2) * coeff; E(i1, i2, i3, em::ex3) += J(i1, i2, i3, cur::jx3) * coeff; + + J(i1, i2, i3, cur::jx1) /= ppc0; + J(i1, i2, i3, cur::jx2) /= ppc0; + J(i1, i2, i3, cur::jx3) /= ppc0; } else { raise::KernelError( HERE, From 2aabb1d4103dcf9bddc1f2b9ff9f346aaa48211b Mon Sep 17 00:00:00 2001 From: hayk Date: Wed, 16 Apr 2025 14:55:26 -0400 Subject: [PATCH 619/773] minor fix --- src/engines/srpic.hpp | 4 ++-- src/kernels/ampere_mink.hpp | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/engines/srpic.hpp b/src/engines/srpic.hpp index fc27337cb..a10070c34 100644 --- a/src/engines/srpic.hpp +++ b/src/engines/srpic.hpp @@ -526,10 +526,10 @@ namespace ntt { const auto n0 = m_params.template get("scales.n0"); const auto B0 = m_params.template get("scales.B0"); if constexpr (M::CoordType == Coord::Cart) { - const auto ppc0 = m_params.template get("particles.ppc0"); - const auto coeff = -dt * q0 / (B0 * V0); // minkowski case 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) { const std::vector xmin { domain.mesh.extent(in::x1).first, diff --git a/src/kernels/ampere_mink.hpp b/src/kernels/ampere_mink.hpp index 32f6805e7..632d7c5a1 100644 --- a/src/kernels/ampere_mink.hpp +++ b/src/kernels/ampere_mink.hpp @@ -118,7 +118,6 @@ namespace kernel::mink { , J { J } , coeff { coeff } , ppc0 { ppc0 } - , inv_ppc0 { inv_ppc0 } , ext_current { ext_current } , x1min { xmin.size() > 0 ? xmin[0] : ZERO } , x2min { xmin.size() > 1 ? xmin[1] : ZERO } From fdb07fd3ea78f0333973d76eddace1a55a517bf5 Mon Sep 17 00:00:00 2001 From: haykh Date: Thu, 17 Apr 2025 17:13:47 -0400 Subject: [PATCH 620/773] shock --- setups/srpic/shock/pgen.hpp | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/setups/srpic/shock/pgen.hpp b/setups/srpic/shock/pgen.hpp index 2ca20741b..adce3466f 100644 --- a/setups/srpic/shock/pgen.hpp +++ b/setups/srpic/shock/pgen.hpp @@ -215,7 +215,17 @@ namespace user { box); } - void CustomPostStep(std::size_t step, long double time, Domain& domain) { + void CustomPostStep(timestep_t step, simtime_t time, Domain& domain) { + + /* + * + * global_xmin global_xmax + * | | + * V V + * |..................|......|......| + * ^ xmin xmax + * x_init + */ // check if the injector should be active if (step % injection_frequency != 0) { @@ -226,19 +236,14 @@ namespace user { const auto x_init = global_xmin + filling_fraction * (global_xmax - global_xmin); - // check if injector is supposed to start moving already - const auto dt_inj = time - injection_start > ZERO ? time - injection_start - : ZERO; - // compute the position of the injector after the current timestep - auto xmax = x_init + injector_velocity * (dt_inj + dt); + auto xmax = x_init + injector_velocity * (math::max(time - injector_start, ZERO) + dt); if (xmax >= global_xmax) { xmax = global_xmax; } // compute the beginning of the injected region - auto xmin = xmax - drift_ux / math::sqrt(1 + SQR(drift_ux)) * dt - - injection_frequency * dt; + auto xmin = xmax - injection_frequency * dt; if (xmin <= global_xmin) { xmin = global_xmin; } @@ -279,15 +284,13 @@ namespace user { */ // loop over particle species - for (std::size_t s { 0 }; s < 2; ++s) { - + for (auto s { 0u }; s < 2; ++s) { // get particle properties auto& species = domain.species[s]; auto i1 = species.i1; auto dx1 = species.dx1; auto tag = species.tag; - // tag all particles with x > box[0].first as dead Kokkos::parallel_for( "RemoveParticles", species.rangeActiveParticles(), @@ -296,11 +299,9 @@ namespace user { if (tag(p) == ParticleTag::dead) { return; } - // select the x-coordinate index - auto x_i1 = static_cast(i1(p)) + dx1(p) + N_GHOSTS; - - // check if the particle is inside the box of new plasma - if (x_i1 >= x_min[0]) { + const auto x_Cd = static_cast(i1(p)) + static_cast(dx1(p)); + const auto x_Ph = domain.mesh.metric.template convert(x_Cd); + if (x_Ph > xmin) { tag(p) = ParticleTag::dead; } }); From 7244912729401a621af38918085dbb1f1d31ab26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20B=C3=B6ss?= Date: Thu, 17 Apr 2025 16:47:45 -0500 Subject: [PATCH 621/773] bugfixes + ASCII comments --- setups/srpic/shock/pgen.hpp | 43 +++++++++++++++++++++++++++++-------- 1 file changed, 34 insertions(+), 9 deletions(-) diff --git a/setups/srpic/shock/pgen.hpp b/setups/srpic/shock/pgen.hpp index adce3466f..aacb6b5d0 100644 --- a/setups/srpic/shock/pgen.hpp +++ b/setups/srpic/shock/pgen.hpp @@ -14,6 +14,7 @@ #include "archetypes/problem_generator.h" #include "framework/domain/metadomain.h" +#include #include namespace user { @@ -176,6 +177,20 @@ namespace user { inline void InitPrtls(Domain& local_domain) { + /* + * Plasma setup as partially filled box + * + * Plasma setup: + * + * global_xmin global_xmax + * | | + * V V + * |:::::::::::|..........................| + * ^ + * | + * filling_fraction + */ + // minimum and maximum position of particles real_t xg_min = global_xmin; real_t xg_max = global_xmin + filling_fraction * (global_xmax - global_xmin); @@ -218,13 +233,18 @@ namespace user { void CustomPostStep(timestep_t step, simtime_t time, Domain& domain) { /* + * Replenish plasma in a moving injector + * + * Injector setup: * - * global_xmin global_xmax - * | | - * V V - * |..................|......|......| - * ^ xmin xmax - * x_init + * global_xmin purge/replenish global_xmax + * | x_init | | + * V v V V + * |:::::::::::;::::::::::|\\\\\\\\|......| + * xmin xmax + * ^ + * | + * moving injector */ // check if the injector should be active @@ -237,7 +257,8 @@ namespace user { filling_fraction * (global_xmax - global_xmin); // compute the position of the injector after the current timestep - auto xmax = x_init + injector_velocity * (math::max(time - injector_start, ZERO) + dt); + auto xmax = x_init + injector_velocity * + (std::max(time - injection_start, ZERO) + dt); if (xmax >= global_xmax) { xmax = global_xmax; } @@ -282,6 +303,7 @@ namespace user { /* tag particles inside the injection zone as dead */ + const auto& mesh = domain.mesh; // loop over particle species for (auto s { 0u }; s < 2; ++s) { @@ -299,8 +321,11 @@ namespace user { if (tag(p) == ParticleTag::dead) { return; } - const auto x_Cd = static_cast(i1(p)) + static_cast(dx1(p)); - const auto x_Ph = domain.mesh.metric.template convert(x_Cd); + const auto x_Cd = static_cast(i1(p)) + + static_cast(dx1(p)); + const auto x_Ph = mesh.metric.template + convert<1, Crd::Cd, Crd::XYZ>(x_Cd); + if (x_Ph > xmin) { tag(p) = ParticleTag::dead; } From 503d46c89bc5818dba1f6e34b7f21a9081078c8b Mon Sep 17 00:00:00 2001 From: hayk Date: Fri, 18 Apr 2025 16:57:49 -0400 Subject: [PATCH 622/773] 2temp maxwellian --- src/archetypes/energy_dist.h | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/src/archetypes/energy_dist.h b/src/archetypes/energy_dist.h index 40e4a432f..2ea8d39b6 100644 --- a/src/archetypes/energy_dist.h +++ b/src/archetypes/energy_dist.h @@ -136,8 +136,23 @@ namespace arch { in boost_direction = in::x1, bool zero_current = true) : EnergyDistribution { metric } + , Maxwellian(metric, + pool, + { temperature, temperature }, + boost_vel, + boost_direction, + zero_current) {} + + Maxwellian(const M& metric, + random_number_pool_t& pool, + std::pair temperatures, + real_t boost_vel = ZERO, + in boost_direction = in::x1, + bool zero_current = true) + : EnergyDistribution { metric } , pool { pool } - , temperature { temperature } + , temperature_1 { temperatures.first } + , temperature_2 { temperatures.second } , boost_velocity { boost_vel } , boost_direction { boost_direction } , zero_current { zero_current } { @@ -226,6 +241,7 @@ namespace arch { Inline void operator()(const coord_t& x_Code, vec_t& v, spidx_t sp = 0) const override { + const auto temperature = (sp % 2 == 0) ? temperature_1 : temperature_2; if (cmp::AlmostZero(temperature)) { v[0] = ZERO; v[1] = ZERO; @@ -245,7 +261,7 @@ namespace arch { // boost only when using cartesian coordinates if (not cmp::AlmostZero(boost_velocity)) { boost(v); - if (not zero_current and sp % 2 == 0) { + if (not zero_current and (sp % 2 == 0)) { v[0] = -v[0]; v[1] = -v[1]; v[2] = -v[2]; @@ -257,7 +273,7 @@ namespace arch { private: random_number_pool_t pool; - const real_t temperature; + const real_t temperature_1, temperature_2; const real_t boost_velocity; const in boost_direction; const bool zero_current; From 7be845ccc030c1ffefab5c3ffd3904a2fe20e0fa Mon Sep 17 00:00:00 2001 From: hayk Date: Fri, 18 Apr 2025 18:07:38 -0400 Subject: [PATCH 623/773] 2temp maxwellian (fixed) --- setups/srpic/shock/pgen.hpp | 43 +++--- src/archetypes/energy_dist.h | 272 +++++++++++++++++++++-------------- 2 files changed, 192 insertions(+), 123 deletions(-) diff --git a/setups/srpic/shock/pgen.hpp b/setups/srpic/shock/pgen.hpp index aacb6b5d0..733976d20 100644 --- a/setups/srpic/shock/pgen.hpp +++ b/setups/srpic/shock/pgen.hpp @@ -208,20 +208,27 @@ namespace user { } } + // species #1 -> e^- + // species #2 -> protons + // energy distribution of the particles - const auto energy_dist = arch::Maxwellian(local_domain.mesh.metric, - local_domain.random_pool, - temperature, - -drift_ux, - in::x1); + const auto energy_dist = arch::TwoTemperatureMaxwellian( + local_domain.mesh.metric, + local_domain.random_pool, + std::pair { temperature * (local_domain.species[2].mass() / + local_domain.species[1].mass()), + temperature }, + std::pair { 1, 2 }, + -drift_ux, + in::x1); // we want to set up a uniform density distribution - const auto injector = arch::UniformInjector( + const auto injector = arch::UniformInjector( energy_dist, { 1, 2 }); // inject uniformly within the defined box - arch::InjectUniform>( + arch::InjectUniform>( params, local_domain, injector, @@ -323,8 +330,8 @@ namespace user { } const auto x_Cd = static_cast(i1(p)) + static_cast(dx1(p)); - const auto x_Ph = mesh.metric.template - convert<1, Crd::Cd, Crd::XYZ>(x_Cd); + const auto x_Ph = mesh.metric.template convert<1, Crd::Cd, Crd::XYZ>( + x_Cd); if (x_Ph > xmin) { tag(p) = ParticleTag::dead; @@ -348,19 +355,23 @@ namespace user { } // same maxwell distribution as above - const auto energy_dist = arch::Maxwellian(domain.mesh.metric, - domain.random_pool, - temperature, - -drift_ux, - in::x1); + const auto energy_dist = arch::TwoTemperatureMaxwellian( + domain.mesh.metric, + domain.random_pool, + std::pair { + temperature * (domain.species[2].mass() / domain.species[1].mass()), + temperature }, + std::pair { 1, 2 }, + -drift_ux, + in::x1); // we want to set up a uniform density distribution - const auto injector = arch::UniformInjector( + const auto injector = arch::UniformInjector( energy_dist, { 1, 2 }); // inject uniformly within the defined box - arch::InjectUniform>( + arch::InjectUniform>( params, domain, injector, diff --git a/src/archetypes/energy_dist.h b/src/archetypes/energy_dist.h index 2ea8d39b6..a108e97a0 100644 --- a/src/archetypes/energy_dist.h +++ b/src/archetypes/energy_dist.h @@ -125,6 +125,103 @@ namespace arch { random_number_pool_t pool; }; + Inline void JuttnerSinge(vec_t& v, + const real_t& temp, + const random_number_pool_t& pool) { + auto rand_gen = pool.get_state(); + real_t randX1, randX2; + if (temp < static_cast(0.5)) { + // Juttner-Synge distribution using the Box-Muller method - non-relativistic + randX1 = Random(rand_gen); + while (cmp::AlmostZero(randX1)) { + randX1 = Random(rand_gen); + } + randX1 = math::sqrt(-TWO * math::log(randX1)); + randX2 = constant::TWO_PI * Random(rand_gen); + v[0] = randX1 * math::cos(randX2) * math::sqrt(temp); + + randX1 = Random(rand_gen); + while (cmp::AlmostZero(randX1)) { + randX1 = Random(rand_gen); + } + randX1 = math::sqrt(-TWO * math::log(randX1)); + randX2 = constant::TWO_PI * Random(rand_gen); + v[1] = randX1 * math::cos(randX2) * math::sqrt(temp); + + randX1 = Random(rand_gen); + while (cmp::AlmostZero(randX1)) { + randX1 = Random(rand_gen); + } + randX1 = math::sqrt(-TWO * math::log(randX1)); + randX2 = constant::TWO_PI * Random(rand_gen); + v[2] = randX1 * math::cos(randX2) * math::sqrt(temp); + } else { + // Juttner-Synge distribution using the Sobol method - relativistic + auto randu = ONE; + auto randeta = Random(rand_gen); + while (SQR(randeta) <= SQR(randu) + ONE) { + randX1 = Random(rand_gen) * Random(rand_gen) * + Random(rand_gen); + while (cmp::AlmostZero(randX1)) { + randX1 = Random(rand_gen) * Random(rand_gen) * + Random(rand_gen); + } + randu = -temp * math::log(randX1); + randX2 = Random(rand_gen); + while (cmp::AlmostZero(randX2)) { + randX2 = Random(rand_gen); + } + randeta = -temp * math::log(randX1 * randX2); + } + randX1 = Random(rand_gen); + randX2 = Random(rand_gen); + v[0] = randu * (TWO * randX1 - ONE); + v[2] = TWO * randu * math::sqrt(randX1 * (ONE - randX1)); + v[1] = v[2] * math::cos(constant::TWO_PI * randX2); + v[2] = v[2] * math::sin(constant::TWO_PI * randX2); + } + pool.free_state(rand_gen); + } + + template + Inline void SampleFromMaxwellian(vec_t& v, + const real_t& temperature, + const real_t& boost_velocity, + const in& boost_direction, + bool flip_velocity, + const random_number_pool_t& pool) { + if (cmp::AlmostZero(temperature)) { + v[0] = ZERO; + v[1] = ZERO; + v[2] = ZERO; + } else { + JuttnerSinge(v, temperature, pool); + } + if constexpr (CanBoost) { + // Boost a symmetric distribution to a relativistic speed using flipping + // method https://arxiv.org/pdf/1504.03910.pdf + // @note: boost only when using cartesian coordinates + if (not cmp::AlmostZero(boost_velocity)) { + const auto boost_dir = static_cast(boost_direction); + const auto boost_beta { boost_velocity / + math::sqrt(ONE + SQR(boost_velocity)) }; + const auto gamma { U2GAMMA(v[0], v[1], v[2]) }; + auto rand_gen = pool.get_state(); + if (-boost_beta * v[boost_dir] > gamma * Random(rand_gen)) { + v[boost_dir] = -v[boost_dir]; + } + pool.free_state(rand_gen); + v[boost_dir] = math::sqrt(ONE + SQR(boost_velocity)) * + (v[boost_dir] + boost_beta * gamma); + if (flip_velocity) { + v[0] = -v[0]; + v[1] = -v[1]; + v[2] = -v[2]; + } + } + } + } + template struct Maxwellian : public EnergyDistribution { using EnergyDistribution::metric; @@ -136,23 +233,8 @@ namespace arch { in boost_direction = in::x1, bool zero_current = true) : EnergyDistribution { metric } - , Maxwellian(metric, - pool, - { temperature, temperature }, - boost_vel, - boost_direction, - zero_current) {} - - Maxwellian(const M& metric, - random_number_pool_t& pool, - std::pair temperatures, - real_t boost_vel = ZERO, - in boost_direction = in::x1, - bool zero_current = true) - : EnergyDistribution { metric } , pool { pool } - , temperature_1 { temperatures.first } - , temperature_2 { temperatures.second } + , temperature { temperature } , boost_velocity { boost_vel } , boost_direction { boost_direction } , zero_current { zero_current } { @@ -165,90 +247,76 @@ namespace arch { HERE); } - // Juttner-Synge distribution - Inline void JS(vec_t& v, const real_t& temp) const { - auto rand_gen = pool.get_state(); - real_t randX1, randX2; - if (temp < static_cast(0.5)) { - // Juttner-Synge distribution using the Box-Muller method - non-relativistic - randX1 = Random(rand_gen); - while (cmp::AlmostZero(randX1)) { - randX1 = Random(rand_gen); - } - randX1 = math::sqrt(-TWO * math::log(randX1)); - randX2 = constant::TWO_PI * Random(rand_gen); - v[0] = randX1 * math::cos(randX2) * math::sqrt(temp); - - randX1 = Random(rand_gen); - while (cmp::AlmostZero(randX1)) { - randX1 = Random(rand_gen); - } - randX1 = math::sqrt(-TWO * math::log(randX1)); - randX2 = constant::TWO_PI * Random(rand_gen); - v[1] = randX1 * math::cos(randX2) * math::sqrt(temp); - - randX1 = Random(rand_gen); - while (cmp::AlmostZero(randX1)) { - randX1 = Random(rand_gen); - } - randX1 = math::sqrt(-TWO * math::log(randX1)); - randX2 = constant::TWO_PI * Random(rand_gen); - v[2] = randX1 * math::cos(randX2) * math::sqrt(temp); - } else { - // Juttner-Synge distribution using the Sobol method - relativistic - auto randu = ONE; - auto randeta = Random(rand_gen); - while (SQR(randeta) <= SQR(randu) + ONE) { - randX1 = Random(rand_gen) * Random(rand_gen) * - Random(rand_gen); - while (cmp::AlmostZero(randX1)) { - randX1 = Random(rand_gen) * Random(rand_gen) * - Random(rand_gen); - } - randu = -temp * math::log(randX1); - randX2 = Random(rand_gen); - while (cmp::AlmostZero(randX2)) { - randX2 = Random(rand_gen); - } - randeta = -temp * math::log(randX1 * randX2); - } - randX1 = Random(rand_gen); - randX2 = Random(rand_gen); - v[0] = randu * (TWO * randX1 - ONE); - v[2] = TWO * randu * math::sqrt(randX1 * (ONE - randX1)); - v[1] = v[2] * math::cos(constant::TWO_PI * randX2); - v[2] = v[2] * math::sin(constant::TWO_PI * randX2); + Inline void operator()(const coord_t& x_Code, + vec_t& v, + spidx_t sp = 0) const override { + SampleFromMaxwellian(v, + temperature, + boost_velocity, + boost_direction, + not zero_current and + sp % 2 == 0, + pool); + if constexpr (S == SimEngine::GRPIC) { + // convert from the tetrad basis to covariant + vec_t v_Hat; + v_Hat[0] = v[0]; + v_Hat[1] = v[1]; + v_Hat[2] = v[2]; + metric.template transform(x_Code, v_Hat, v); } - pool.free_state(rand_gen); } - // Boost a symmetric distribution to a relativistic speed using flipping - // method https://arxiv.org/pdf/1504.03910.pdf - Inline void boost(vec_t& v) const { - const auto boost_dir = static_cast(boost_direction); - const auto boost_beta { boost_velocity / - math::sqrt(ONE + SQR(boost_velocity)) }; - const auto gamma { U2GAMMA(v[0], v[1], v[2]) }; - auto rand_gen = pool.get_state(); - if (-boost_beta * v[boost_dir] > gamma * Random(rand_gen)) { - v[boost_dir] = -v[boost_dir]; - } - pool.free_state(rand_gen); - v[boost_dir] = math::sqrt(ONE + SQR(boost_velocity)) * - (v[boost_dir] + boost_beta * gamma); + private: + random_number_pool_t pool; + + const real_t temperature; + const real_t boost_velocity; + const in boost_direction; + const bool zero_current; + }; + + template + struct TwoTemperatureMaxwellian : public EnergyDistribution { + using EnergyDistribution::metric; + + TwoTemperatureMaxwellian(const M& metric, + random_number_pool_t& pool, + const std::pair& temperatures, + const std::pair& species, + real_t boost_vel = ZERO, + in boost_direction = in::x1, + bool zero_current = true) + : EnergyDistribution { metric } + , pool { pool } + , temperature_1 { temperatures.first } + , temperature_2 { temperatures.second } + , sp_1 { species.first } + , sp_2 { species.second } + , boost_velocity { boost_vel } + , boost_direction { boost_direction } + , zero_current { zero_current } { + raise::ErrorIf( + (temperature_1 < ZERO) or (temperature_2 < ZERO), + "TwoTemperatureMaxwellian: Temperature must be non-negative", + HERE); + raise::ErrorIf((not cmp::AlmostZero(boost_vel, ZERO)) && + (M::CoordType != Coord::Cart), + "TwoTemperatureMaxwellian: Boosting is only supported in " + "Cartesian coordinates", + HERE); } Inline void operator()(const coord_t& x_Code, vec_t& v, spidx_t sp = 0) const override { - const auto temperature = (sp % 2 == 0) ? temperature_1 : temperature_2; - if (cmp::AlmostZero(temperature)) { - v[0] = ZERO; - v[1] = ZERO; - v[2] = ZERO; - } else { - JS(v, temperature); - } + SampleFromMaxwellian( + v, + (sp == sp_1) ? temperature_1 : temperature_2, + boost_velocity, + boost_direction, + not zero_current and sp == sp_1, + pool); if constexpr (S == SimEngine::GRPIC) { // convert from the tetrad basis to covariant vec_t v_Hat; @@ -257,26 +325,16 @@ namespace arch { v_Hat[2] = v[2]; metric.template transform(x_Code, v_Hat, v); } - if constexpr (M::CoordType == Coord::Cart) { - // boost only when using cartesian coordinates - if (not cmp::AlmostZero(boost_velocity)) { - boost(v); - if (not zero_current and (sp % 2 == 0)) { - v[0] = -v[0]; - v[1] = -v[1]; - v[2] = -v[2]; - } - } - } } private: random_number_pool_t pool; - const real_t temperature_1, temperature_2; - const real_t boost_velocity; - const in boost_direction; - const bool zero_current; + const real_t temperature_1, temperature_2; + const spidx_t sp_1, sp_2; + const real_t boost_velocity; + const in boost_direction; + const bool zero_current; }; } // namespace arch From 5148488f7ac0a620052cf2e33ec2d21eb8b0f37b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20B=C3=B6ss?= Date: Fri, 18 Apr 2025 17:34:05 -0500 Subject: [PATCH 624/773] added option for temperature ratio between electrons and protons --- setups/srpic/shock/pgen.hpp | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/setups/srpic/shock/pgen.hpp b/setups/srpic/shock/pgen.hpp index 733976d20..646c2cc35 100644 --- a/setups/srpic/shock/pgen.hpp +++ b/setups/srpic/shock/pgen.hpp @@ -123,7 +123,7 @@ namespace user { // domain properties const real_t global_xmin, global_xmax; // gas properties - const real_t drift_ux, temperature, filling_fraction; + const real_t drift_ux, temperature, temperature_ratio, filling_fraction; // injector properties const real_t injector_velocity, injection_start, dt; const int injection_frequency; @@ -138,6 +138,7 @@ namespace user { , global_xmax { global_domain.mesh().extent(in::x1).second } , drift_ux { p.template get("setup.drift_ux") } , temperature { p.template get("setup.temperature") } + , temperature_ratio { p.template get("setup.temperature_ratio") } , Bmag { p.template get("setup.Bmag", ZERO) } , Btheta { p.template get("setup.Btheta", ZERO) } , Bphi { p.template get("setup.Bphi", ZERO) } @@ -215,10 +216,10 @@ namespace user { const auto energy_dist = arch::TwoTemperatureMaxwellian( local_domain.mesh.metric, local_domain.random_pool, - std::pair { temperature * (local_domain.species[2].mass() / - local_domain.species[1].mass()), - temperature }, - std::pair { 1, 2 }, + { temperature_ratio * temperature * + (local_domain.species[2].mass() / local_domain.species[1].mass()), + temperature }, + { 1, 2 }, -drift_ux, in::x1); @@ -358,10 +359,10 @@ namespace user { const auto energy_dist = arch::TwoTemperatureMaxwellian( domain.mesh.metric, domain.random_pool, - std::pair { - temperature * (domain.species[2].mass() / domain.species[1].mass()), + { temperature_ratio * temperature * + (domain.species[2].mass() / domain.species[1].mass()), temperature }, - std::pair { 1, 2 }, + { 1, 2 }, -drift_ux, in::x1); From 28ccd7d7c5dbf353566c78f1b275f9439fb446a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20B=C3=B6ss?= Date: Fri, 18 Apr 2025 17:34:51 -0500 Subject: [PATCH 625/773] updated example shock parameters --- setups/srpic/shock/shock.toml | 41 ++++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/setups/srpic/shock/shock.toml b/setups/srpic/shock/shock.toml index ca19a4078..90678488a 100644 --- a/setups/srpic/shock/shock.toml +++ b/setups/srpic/shock/shock.toml @@ -1,11 +1,14 @@ [simulation] - name = "shock" + name = "shock_perp" engine = "srpic" - runtime = 30000.0 + runtime = 50.0 + + [simulation.domain] + decomposition = [1,-1] [grid] resolution = [4096, 128] - extent = [[0.0, 2000.0], [-31.25, 31.25]] + extent = [[0.0, 4.096], [-0.064, 0.064]] [grid.metric] metric = "minkowski" @@ -13,10 +16,11 @@ [grid.boundaries] fields = [["CONDUCTOR", "MATCH"], ["PERIODIC"]] particles = [["REFLECT", "ABSORB"], ["PERIODIC"]] + [scales] - larmor0 = 100.0 - skindepth0 = 1.0 + larmor0 = 0.057735 + skindepth0 = 0.01 [algorithms] current_filters = 8 @@ -31,26 +35,28 @@ label = "e-" mass = 1.0 charge = -1.0 - maxnpart = 1e8 + maxnpart = 8e7 [[particles.species]] label = "p+" - mass = 1.0 + mass = 100.0 charge = 1.0 - maxnpart = 1e8 + maxnpart = 8e7 [setup] - drift_ux = 0.1 # speed towards the wall [c] - temperature = 1e-4 # temeperature of maxwell distribution [m_e c^2] - Bmag = 1.0 # magnetic field strength as fraction of magnetisation - Btheta = 0.0 # magnetic field angle in the plane - Bphi = 0.0 # magnetic field angle out of plane - filling_fraction = 0.1 # fraction of the shock piston filled with plasma - injector_velocity = 1.0 # speed of injector [c] - injection_start = 0.0 # start time of moving injector + drift_ux = 0.15 # speed towards the wall [c] + temperature = 0.001683 # temperature of maxwell distribution [kB T / (m_i c^2)] + temperature_ratio = 1.0 # temperature ratio of electrons to protons + Bmag = 1.0 # magnetic field strength as fraction of magnetisation + Btheta = 63.0 # magnetic field angle in the plane + Bphi = 0.0 # magnetic field angle out of plane + filling_fraction = 0.1 # fraction of the shock piston filled with plasma + injector_velocity = 0.2 # speed of injector [c] + injection_start = 0.0 # start time of moving injector + injection_frequency = 100 # inject particles every 100 timesteps [output] - interval_time = 10.0 + interval_time = 0.1 format = "hdf5" [output.fields] @@ -62,4 +68,3 @@ [output.spectra] enable = false - From ec09669043796534d0c3dd448c6933a5f7fc3091 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20B=C3=B6ss?= Date: Fri, 18 Apr 2025 17:35:47 -0500 Subject: [PATCH 626/773] removed redundant BC fields --- setups/srpic/shock/pgen.hpp | 40 +------------------------------------ 1 file changed, 1 insertion(+), 39 deletions(-) diff --git a/setups/srpic/shock/pgen.hpp b/setups/srpic/shock/pgen.hpp index 646c2cc35..738072f27 100644 --- a/setups/srpic/shock/pgen.hpp +++ b/setups/srpic/shock/pgen.hpp @@ -67,44 +67,6 @@ namespace user { const real_t Btheta, Bphi, Vx, Bmag; }; - template - struct BCFields { - - BCFields(real_t bmag, real_t btheta, real_t bphi, real_t drift_ux) - : Bmag { bmag } - , Btheta { btheta * static_cast(convert::deg2rad) } - , Bphi { bphi * static_cast(convert::deg2rad) } - , Vx { drift_ux } {} - - // magnetic field components - Inline auto bx1(const coord_t&) const -> real_t { - return Bmag * math::cos(ZERO); - } - - Inline auto bx2(const coord_t&) const -> real_t { - return Bmag * math::sin(ZERO) * math::sin(ZERO); - } - - Inline auto bx3(const coord_t&) const -> real_t { - return Bmag * math::sin(ZERO) * math::cos(ZERO); - } - - // electric field components - Inline auto ex1(const coord_t&) const -> real_t { - return ZERO; - } - - Inline auto ex2(const coord_t&) const -> real_t { - return -Vx * Bmag * math::sin(ZERO) * math::cos(ZERO); - } - - Inline auto ex3(const coord_t&) const -> real_t { - return Vx * Bmag * math::sin(ZERO) * math::sin(ZERO); - } - - private: - const real_t Btheta, Bphi, Vx, Bmag; - }; template struct PGen : public arch::ProblemGenerator { @@ -153,7 +115,7 @@ namespace user { inline PGen() {} auto MatchFields(real_t time) const -> BCFields { - return bc_flds; + return init_flds; } auto FixFieldsConst(const bc_in&, const em& comp) const From d9a39a623a083b927aab67bec76c2b8aebea07ae Mon Sep 17 00:00:00 2001 From: hayk Date: Sat, 19 Apr 2025 04:48:08 -0400 Subject: [PATCH 627/773] stats output (kernels not finished) --- cmake/tests.cmake | 5 +- input.example.toml | 22 ++++ src/CMakeLists.txt | 9 +- src/engines/engine_init.cpp | 1 + src/engines/engine_run.cpp | 5 + src/framework/CMakeLists.txt | 7 +- src/framework/domain/metadomain.h | 9 +- src/framework/domain/output.cpp | 15 ++- src/framework/domain/stats.cpp | 204 ++++++++++++++++++++++++++++++ src/framework/parameters.cpp | 21 ++- src/global/defaults.h | 21 +-- src/global/enums.h | 26 ++++ src/global/global.h | 3 +- src/global/tests/enums.cpp | 4 + src/kernels/ampere_mink.hpp | 1 + src/kernels/divergences.hpp | 123 ++++++++++++++++++ src/kernels/utils.hpp | 1 + src/output/CMakeLists.txt | 11 +- src/output/fields.cpp | 7 +- src/output/fields.h | 8 ++ src/output/stats.cpp | 132 +++++++++++++++++++ src/output/stats.h | 156 +++++++++++++++++++++++ src/output/tests/CMakeLists.txt | 14 +- src/output/tests/fields.cpp | 19 +++ src/output/tests/stats.cpp | 102 +++++++++++++++ src/output/writer.cpp | 4 +- 26 files changed, 893 insertions(+), 37 deletions(-) create mode 100644 src/framework/domain/stats.cpp create mode 100644 src/kernels/divergences.hpp create mode 100644 src/output/stats.cpp create mode 100644 src/output/stats.h create mode 100644 src/output/tests/stats.cpp diff --git a/cmake/tests.cmake b/cmake/tests.cmake index 0e108d365..189cc2cc4 100644 --- a/cmake/tests.cmake +++ b/cmake/tests.cmake @@ -8,8 +8,8 @@ add_subdirectory(${SRC_DIR}/metrics ${CMAKE_CURRENT_BINARY_DIR}/metrics) add_subdirectory(${SRC_DIR}/kernels ${CMAKE_CURRENT_BINARY_DIR}/kernels) add_subdirectory(${SRC_DIR}/archetypes ${CMAKE_CURRENT_BINARY_DIR}/archetypes) add_subdirectory(${SRC_DIR}/framework ${CMAKE_CURRENT_BINARY_DIR}/framework) +add_subdirectory(${SRC_DIR}/output ${CMAKE_CURRENT_BINARY_DIR}/output) if(${output}) - add_subdirectory(${SRC_DIR}/output ${CMAKE_CURRENT_BINARY_DIR}/output) add_subdirectory(${SRC_DIR}/checkpoint ${CMAKE_CURRENT_BINARY_DIR}/checkpoint) endif() @@ -25,8 +25,9 @@ elseif(${mpi} AND ${output}) list(APPEND TEST_DIRECTORIES framework) endif() +list(APPEND TEST_DIRECTORIES output) + if(${output}) - list(APPEND TEST_DIRECTORIES output) list(APPEND TEST_DIRECTORIES checkpoint) endif() diff --git a/input.example.toml b/input.example.toml index e4501f0a0..bd5d52b06 100644 --- a/input.example.toml +++ b/input.example.toml @@ -436,6 +436,28 @@ # @default: false ghosts = "" + [output.stats] + # Toggle for the stats output: + # @type: bool + # @default: true + enable = "" + # Number of timesteps between stat outputs (overriden if `output.stats.interval_time != -1`): + # @type: unsigned int: > 0 + # @default: 100 + interval = "" + # Physical (code) time interval between stat outputs: + # @type: float + # @default: -1.0 (use `output.stats.interval_time`) + # @note: When `interval_time` < 0, the output is controlled by `interval`, otherwise by `interval_time` + interval_time = "" + # Field quantities to output: + # @type: array of strings + # @valid: fields: "B^2", "E^2", "ExB" + # @valid: moments: "N", "Charge", "Rho", "T00", "T0i", "Tij" + # @default: ["B^2", "E^2", "ExB", "Rho", "T00"] + # @note: Same notation as for `output.fields.quantities` + quantities = "" + [checkpoint] # Number of timesteps between checkpoints: # @type: unsigned int: > 0 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f9d921df0..715183b64 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -22,10 +22,7 @@ # * mpi [optional] # ------------------------------ -set(ENTITY ${PROJECT_NAME}.xc) set(SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}) -set(SOURCES ${SRC_DIR}/entity.cpp) -add_executable(${ENTITY} entity.cpp) # dependencies add_subdirectory(${SRC_DIR}/global ${CMAKE_CURRENT_BINARY_DIR}/global) @@ -34,14 +31,18 @@ add_subdirectory(${SRC_DIR}/kernels ${CMAKE_CURRENT_BINARY_DIR}/kernels) add_subdirectory(${SRC_DIR}/archetypes ${CMAKE_CURRENT_BINARY_DIR}/archetypes) add_subdirectory(${SRC_DIR}/framework ${CMAKE_CURRENT_BINARY_DIR}/framework) add_subdirectory(${SRC_DIR}/engines ${CMAKE_CURRENT_BINARY_DIR}/engines) +add_subdirectory(${SRC_DIR}/output ${CMAKE_CURRENT_BINARY_DIR}/output) if(${output}) - add_subdirectory(${SRC_DIR}/output ${CMAKE_CURRENT_BINARY_DIR}/output) add_subdirectory(${SRC_DIR}/checkpoint ${CMAKE_CURRENT_BINARY_DIR}/checkpoint) endif() add_subdirectory(${SRC_DIR}/../setups ${CMAKE_CURRENT_BINARY_DIR}/setups) +set(ENTITY ${PROJECT_NAME}.xc) +set(SOURCES ${SRC_DIR}/entity.cpp) + +add_executable(${ENTITY} ${SOURCES}) set(libs ntt_global ntt_framework ntt_metrics ntt_engines ntt_pgen) add_dependencies(${ENTITY} ${libs}) target_link_libraries(${ENTITY} PUBLIC ${libs}) diff --git a/src/engines/engine_init.cpp b/src/engines/engine_init.cpp index 7ce242bc6..833a7771f 100644 --- a/src/engines/engine_init.cpp +++ b/src/engines/engine_init.cpp @@ -21,6 +21,7 @@ namespace ntt { template void Engine::init() { if constexpr (pgen_is_ok) { + m_metadomain.InitStatsWriter(m_params, is_resuming); #if defined(OUTPUT_ENABLED) m_metadomain.InitWriter(&m_adios, m_params, is_resuming); m_metadomain.InitCheckpointWriter(&m_adios, m_params); diff --git a/src/engines/engine_run.cpp b/src/engines/engine_run.cpp index 2d4b0d5ed..472acae46 100644 --- a/src/engines/engine_run.cpp +++ b/src/engines/engine_run.cpp @@ -84,6 +84,11 @@ namespace ntt { } else { print_output = m_metadomain.Write(m_params, step, step - 1, time, time - dt); } + print_output &= m_metadomain.WriteStats(m_params, + step, + step - 1, + time, + time - dt); timers.stop("Output"); timers.start("Checkpoint"); diff --git a/src/framework/CMakeLists.txt b/src/framework/CMakeLists.txt index 4c407fb0c..b74d11bec 100644 --- a/src/framework/CMakeLists.txt +++ b/src/framework/CMakeLists.txt @@ -12,6 +12,7 @@ # * domain/checkpoint.cpp # * containers/particles.cpp # * containers/fields.cpp +# * domain/stats.cpp # * domain/output.cpp # # @includes: @@ -23,7 +24,7 @@ # * ntt_global [required] # * ntt_metrics [required] # * ntt_kernels [required] -# * ntt_output [optional] +# * ntt_output [required] # # @uses: # @@ -40,6 +41,7 @@ set(SOURCES ${SRC_DIR}/domain/grid.cpp ${SRC_DIR}/domain/metadomain.cpp ${SRC_DIR}/domain/communications.cpp + ${SRC_DIR}/domain/stats.cpp ${SRC_DIR}/containers/particles.cpp ${SRC_DIR}/containers/fields.cpp) if(${output}) @@ -48,9 +50,8 @@ if(${output}) endif() add_library(ntt_framework ${SOURCES}) -set(libs ntt_global ntt_metrics ntt_kernels) +set(libs ntt_global ntt_metrics ntt_kernels ntt_output) if(${output}) - list(APPEND libs ntt_output) list(APPEND libs ntt_checkpoint) endif() add_dependencies(ntt_framework ${libs}) diff --git a/src/framework/domain/metadomain.h b/src/framework/domain/metadomain.h index 80f546664..1728fbd65 100644 --- a/src/framework/domain/metadomain.h +++ b/src/framework/domain/metadomain.h @@ -25,6 +25,7 @@ #include "framework/domain/domain.h" #include "framework/domain/mesh.h" #include "framework/parameters.h" +#include "output/stats.h" #if defined(MPI_ENABLED) #include @@ -116,7 +117,7 @@ namespace ntt { ~Metadomain() = default; #if defined(OUTPUT_ENABLED) - void InitWriter(adios2::ADIOS*, const SimulationParams&, bool is_resuming); + void InitWriter(adios2::ADIOS*, const SimulationParams&, bool); auto Write(const SimulationParams&, timestep_t, timestep_t, @@ -136,6 +137,10 @@ namespace ntt { void ContinueFromCheckpoint(adios2::ADIOS*, const SimulationParams&); #endif + void InitStatsWriter(const SimulationParams&, bool); + auto WriteStats(const SimulationParams&, timestep_t, timestep_t, simtime_t, simtime_t) + -> bool; + /* setters -------------------------------------------------------------- */ /* getters -------------------------------------------------------------- */ @@ -242,6 +247,8 @@ namespace ntt { const std::map g_metric_params; const std::vector g_species_params; + stats::Writer g_stats_writer; + #if defined(OUTPUT_ENABLED) out::Writer g_writer; checkpoint::Writer g_checkpoint_writer; diff --git a/src/framework/domain/output.cpp b/src/framework/domain/output.cpp index 36ea4249b..5c7932ea7 100644 --- a/src/framework/domain/output.cpp +++ b/src/framework/domain/output.cpp @@ -18,6 +18,7 @@ #include "framework/domain/metadomain.h" #include "framework/parameters.h" +#include "kernels/divergences.hpp" #include "kernels/fields_to_phys.hpp" #include "kernels/particle_moments.hpp" #include "kernels/prtls_to_phys.hpp" @@ -213,7 +214,9 @@ namespace ntt { g_writer.shouldWrite("spectra", finished_step, finished_time); - if (not(write_fields or write_particles or write_spectra)) { + const auto extension = params.template get("output.format"); + if (not(write_fields or write_particles or write_spectra) and + extension != "disabled") { return false; } auto local_domain = subdomain_ptr(l_subdomain_indices()[0]); @@ -348,6 +351,16 @@ namespace ntt { } else { raise::Error("Wrong moment requested for output", HERE); } + } else if (fld.is_divergence()) { + // @TODO: is this correct for GR too? not em0? + const auto c = static_cast(addresses.back()); + Kokkos::parallel_for( + "ComputeDivergence", + local_domain->mesh.rangeActiveCells(), + kernel::ComputeDivergence_kernel(local_domain->mesh.metric, + local_domain->fields.em, + local_domain->fields.bckp, + c)); } else if (fld.is_custom()) { if (CustomFieldOutput) { CustomFieldOutput(fld.name().substr(1), diff --git a/src/framework/domain/stats.cpp b/src/framework/domain/stats.cpp new file mode 100644 index 000000000..60acd64a9 --- /dev/null +++ b/src/framework/domain/stats.cpp @@ -0,0 +1,204 @@ +#include "enums.h" +#include "global.h" + +#include "arch/kokkos_aliases.h" +#include "utils/error.h" +#include "utils/log.h" +#include "utils/numeric.h" + +#include "metrics/kerr_schild.h" +#include "metrics/kerr_schild_0.h" +#include "metrics/minkowski.h" +#include "metrics/qkerr_schild.h" +#include "metrics/qspherical.h" +#include "metrics/spherical.h" + +#include "framework/containers/particles.h" +#include "framework/domain/domain.h" +#include "framework/domain/metadomain.h" +#include "framework/parameters.h" + +#include +#include +#include + +#include + +namespace ntt { + + template + void Metadomain::InitStatsWriter(const SimulationParams& params, + bool is_resuming) { + raise::ErrorIf( + l_subdomain_indices().size() != 1, + "StatsWriter for now is only supported for one subdomain per rank", + HERE); + auto local_domain = subdomain_ptr(l_subdomain_indices()[0]); + raise::ErrorIf(local_domain->is_placeholder(), + "local_domain is a placeholder", + HERE); + const auto filename = params.template get("simulation.name") + + "_stats.csv"; + const auto enable_stats = params.template get("output.stats.enable"); + if (enable_stats and (not is_resuming)) { + CallOnce( + [](auto& filename) { + if (std::filesystem::exists(filename)) { + std::filesystem::remove(filename); + } + }, + filename); + } + const auto stats_to_write = params.template get>( + "output.stats.quantities"); + g_stats_writer.init( + params.template get("output.stats.interval"), + params.template get("output.stats.interval_time")); + g_stats_writer.defineStatsFilename(filename); + g_stats_writer.defineStatsOutputs(stats_to_write); + + if (not std::filesystem::exists(filename)) { + g_stats_writer.writeHeader(); + } + } + + template + auto ComputeMoments(const SimulationParams& params, + const Mesh& mesh, + const std::vector>& prtl_species, + const std::vector& species, + const std::vector& components) -> T { + std::vector specs = species; + if (specs.size() == 0) { + // if no species specified, take all massive species + for (auto& sp : prtl_species) { + if (sp.mass() > 0) { + specs.push_back(sp.index()); + } + } + } + for (const auto& sp : specs) { + raise::ErrorIf((sp > prtl_species.size()) or (sp == 0), + "Invalid species index " + std::to_string(sp), + HERE); + } + // some parameters + const auto use_weights = params.template get("particles.use_weights"); + const auto inv_n0 = ONE / params.template get("scales.n0"); + + T buffer = static_cast(0); + for (const auto& sp : specs) { + auto& prtl_spec = prtl_species[sp - 1]; + // Kokkos::parallel_reduce( + // "ComputeMoments", + // prtl_spec.rangeActiveParticles(), + // // clang-format off + // kernel::ReducedParticleMoments_kernel(components, + // prtl_spec.i1, prtl_spec.i2, prtl_spec.i3, + // prtl_spec.dx1, prtl_spec.dx2, prtl_spec.dx3, + // prtl_spec.ux1, prtl_spec.ux2, prtl_spec.ux3, + // prtl_spec.phi, prtl_spec.weight, prtl_spec.tag, + // prtl_spec.mass(), prtl_spec.charge(), + // use_weights, mesh.metric, mesh.flds_bc(), inv_n0), + // // clang-format on + // buffer); + } + return buffer; + } + + template + auto ComputeFields(Domain* domain, + const std::vector& components) -> real_t { + auto buffer { ZERO }; + // Kokkos::parallel_reduce( + // "ComputeMoments", + // prtl_spec.rangeActiveParticles(), + // kernel::ReducedFields_kernel(components, + // domain->fields.em, + // domain->fields.cur, + // domain->mesh.metric), + // buffer); + return buffer; + } + + template + auto Metadomain::WriteStats(const SimulationParams& params, + timestep_t current_step, + timestep_t finished_step, + simtime_t current_time, + simtime_t finished_time) -> bool { + if (not(params.template get("output.stats.enable") and + g_stats_writer.shouldWrite(finished_step, finished_time))) { + return false; + } + auto local_domain = subdomain_ptr(l_subdomain_indices()[0]); + logger::Checkpoint("Writing stats", HERE); + g_stats_writer.write(current_step); + g_stats_writer.write(current_time); + for (const auto& stat : g_stats_writer.statsWriters()) { + if (stat.id() == StatsID::N) { + g_stats_writer.write( + ComputeMoments(params, + local_domain->mesh, + local_domain->species, + stat.species, + {})); + } else if (stat.id() == StatsID::Npart) { + g_stats_writer.write( + ComputeMoments(params, + local_domain->mesh, + local_domain->species, + stat.species, + {})); + } else if (stat.id() == StatsID::Rho) { + g_stats_writer.write( + ComputeMoments(params, + local_domain->mesh, + local_domain->species, + stat.species, + {})); + } else if (stat.id() == StatsID::Charge) { + g_stats_writer.write( + ComputeMoments(params, + local_domain->mesh, + local_domain->species, + stat.species, + {})); + } else if (stat.id() == StatsID::T) { + for (const auto& comp : stat.comp) { + g_stats_writer.write( + ComputeMoments(params, + local_domain->mesh, + local_domain->species, + stat.species, + comp)); + } + } else if (stat.id() == StatsID::JdotE) { + g_stats_writer.write(ComputeFields(local_domain, {})); + } else if (stat.id() == StatsID::E2) { + g_stats_writer.write(ComputeFields(local_domain, {})); + } else if (stat.id() == StatsID::B2) { + g_stats_writer.write(ComputeFields(local_domain, {})); + } else if (stat.id() == StatsID::ExB) { + for (const auto& comp : stat.comp) { + g_stats_writer.write( + ComputeFields(local_domain, comp)); + } + } else { + raise::Error("Unrecognized stats ID " + stat.name(), HERE); + } + } + g_stats_writer.endWriting(); + return true; + } + + template struct Metadomain>; + template struct Metadomain>; + template struct Metadomain>; + template struct Metadomain>; + template struct Metadomain>; + template struct Metadomain>; + template struct Metadomain>; + template struct Metadomain>; + +} // namespace ntt diff --git a/src/framework/parameters.cpp b/src/framework/parameters.cpp index 56345d9f4..26f542956 100644 --- a/src/framework/parameters.cpp +++ b/src/framework/parameters.cpp @@ -458,15 +458,18 @@ namespace ntt { set("output.separate_files", toml::find_or(toml_data, "output", "separate_files", true)); + promiseToDefine("output.fields.enable"); promiseToDefine("output.fields.interval"); promiseToDefine("output.fields.interval_time"); - promiseToDefine("output.fields.enable"); + promiseToDefine("output.particles.enable"); promiseToDefine("output.particles.interval"); promiseToDefine("output.particles.interval_time"); - promiseToDefine("output.particles.enable"); + promiseToDefine("output.spectra.enable"); promiseToDefine("output.spectra.interval"); promiseToDefine("output.spectra.interval_time"); - promiseToDefine("output.spectra.enable"); + promiseToDefine("output.stats.enable"); + promiseToDefine("output.stats.interval"); + promiseToDefine("output.stats.interval_time"); const auto flds_out = toml::find_or(toml_data, "output", @@ -540,8 +543,16 @@ namespace ntt { "n_bins", defaults::output::spec_nbins)); + // stats + set("output.stats.quantities", + toml::find_or(toml_data, + "output", + "stats", + "quantities", + defaults::output::stats_quantities)); + // intervals - for (const auto& type : { "fields", "particles", "spectra" }) { + for (const auto& type : { "fields", "particles", "spectra", "stats" }) { const auto q_int = toml::find_or(toml_data, "output", std::string(type), @@ -554,7 +565,7 @@ namespace ntt { -1.0); set("output." + std::string(type) + ".enable", toml::find_or(toml_data, "output", std::string(type), "enable", true)); - if (q_int == 0 && q_int_time == -1.0) { + if ((q_int == 0) and (q_int_time == -1.0)) { set("output." + std::string(type) + ".interval", get("output.interval")); set("output." + std::string(type) + ".interval_time", diff --git a/src/global/defaults.h b/src/global/defaults.h index d17647ccd..e44103ed0 100644 --- a/src/global/defaults.h +++ b/src/global/defaults.h @@ -52,14 +52,19 @@ namespace ntt::defaults { } // namespace bc namespace output { - const std::string format = "hdf5"; - const timestep_t interval = 100; - const unsigned short mom_smooth = 0; - const npart_t prtl_stride = 100; - const real_t spec_emin = 1e-3; - const real_t spec_emax = 1e3; - const bool spec_log = true; - const std::size_t spec_nbins = 200; + const std::string format = "hdf5"; + const timestep_t interval = 100; + const unsigned short mom_smooth = 0; + const npart_t prtl_stride = 100; + const real_t spec_emin = 1e-3; + const real_t spec_emax = 1e3; + const bool spec_log = true; + const std::size_t spec_nbins = 200; + const std::vector stats_quantities = { "B^2", + "E^2", + "ExB", + "Rho", + "T00" }; } // namespace output namespace checkpoint { diff --git a/src/global/enums.h b/src/global/enums.h index d80297d8d..7e06d4a8d 100644 --- a/src/global/enums.h +++ b/src/global/enums.h @@ -307,6 +307,32 @@ namespace ntt { static constexpr std::size_t total = sizeof(variants) / sizeof(variants[0]); }; + struct StatsID : public enums_hidden::BaseEnum { + static constexpr const char* label = "out_stats"; + + enum type : uint8_t { + INVALID = 0, + B2 = 1, + E2 = 2, + ExB = 3, + JdotE = 4, + T = 5, + Rho = 6, + Charge = 7, + N = 8, + Npart = 9, + }; + + constexpr StatsID(uint8_t c) : enums_hidden::BaseEnum { c } {} + + static constexpr type variants[] = { B2, E2, ExB, JdotE, T, + Rho, Charge, N, Npart }; + static constexpr const char* lookup[] = { "b^2", "e^2", "exb", + "j.e", "t", "rho", + "charge", "n", "npart" }; + static constexpr std::size_t total = sizeof(variants) / sizeof(variants[0]); + }; + } // namespace ntt #endif // GLOBAL_ENUMS_H diff --git a/src/global/global.h b/src/global/global.h index 5296d8ac7..42114a1da 100644 --- a/src/global/global.h +++ b/src/global/global.h @@ -269,6 +269,7 @@ namespace WriteMode { Fields = 1 << 0, Particles = 1 << 1, Spectra = 1 << 2, + Stats = 1 << 3, }; } // namespace WriteMode @@ -346,7 +347,7 @@ using duration_t = double; using simtime_t = double; using timestep_t = std::size_t; using ncells_t = std::size_t; -using npart_t = unsigned long long int; +using npart_t = unsigned long int; // index/number using index_t = const std::size_t; diff --git a/src/global/tests/enums.cpp b/src/global/tests/enums.cpp index ebc074b72..9208ed8d3 100644 --- a/src/global/tests/enums.cpp +++ b/src/global/tests/enums.cpp @@ -71,6 +71,9 @@ auto main() -> int { "h", "j", "a", "t", "rho", "charge", "n", "nppc", "v", "custom" }; + enum_str_t all_out_stats = { "b^2", "e^2", "exb", "j.e", "t", + "rho", "charge", "n", "npart", "v" }; + checkEnum(all_coords); checkEnum(all_metrics); checkEnum(all_simulation_engines); @@ -79,6 +82,7 @@ auto main() -> int { checkEnum(all_particle_pushers); checkEnum(all_coolings); checkEnum(all_out_flds); + checkEnum(all_out_stats); return 0; } diff --git a/src/kernels/ampere_mink.hpp b/src/kernels/ampere_mink.hpp index 632d7c5a1..45773ead3 100644 --- a/src/kernels/ampere_mink.hpp +++ b/src/kernels/ampere_mink.hpp @@ -15,6 +15,7 @@ #include "arch/kokkos_aliases.h" #include "utils/error.h" +#include "utils/numeric.h" namespace kernel::mink { using namespace ntt; diff --git a/src/kernels/divergences.hpp b/src/kernels/divergences.hpp new file mode 100644 index 000000000..c60be564b --- /dev/null +++ b/src/kernels/divergences.hpp @@ -0,0 +1,123 @@ +/** + * @file kernels/divergences.hpp + * @brief Compute covariant divergences of fields + * @implements + * - kernel::ComputeDivergence_kernel<> + * @namespaces: + * - kernel:: + */ + +#ifndef KERNELS_DIVERGENCES_HPP +#define KERNELS_DIVERGENCES_HPP + +#include "global.h" + +#include "arch/kokkos_aliases.h" +#include "utils/error.h" + +namespace kernel { + using namespace ntt; + + // @TODO: take care of boundaries + template + class ComputeDivergence_kernel { + const M metric; + + const ndfield_t fields; + ndfield_t buff; + const idx_t buff_idx; + + public: + ComputeDivergence_kernel(const M& metric, + const ndfield_t& fields, + ndfield_t& buff, + idx_t buff_idx) + : metric { metric } + , fields { fields } + , buff { buff } + , buff_idx { buff_idx } { + raise::ErrorIf(buff_idx >= N, "Invalid component index", HERE); + } + + Inline void operator()(index_t i1) const { + if constexpr (M::Dim == Dim::_1D) { + if constexpr (M::CoordType == Coord::Cart) { + buff(i1, buff_idx) = fields(i1, em::ex1) - fields(i1 - 1, em::ex1); + } else { + const auto i1_ = COORD(i1); + buff(i1, buff_idx) = (fields(i1, em::ex1) * + metric.sqrt_det_h({ i1_ + HALF }) - + fields(i1 - 1, em::ex1) * + metric.sqrt_det_h({ i1_ - HALF })) / + metric.sqrt_det_h({ i1_ }); + } + } else { + raise::KernelError( + HERE, + "1D implementation of ComputeDivergence_kernel called for non-1D"); + } + } + + Inline void operator()(index_t i1, index_t i2) const { + if constexpr (M::Dim == Dim::_2D) { + if constexpr (M::CoordType == Coord::Cart) { + buff(i1, i2, buff_idx) = fields(i1, i2, em::ex1) - + fields(i1 - 1, i2, em::ex1) + + fields(i1, i2, em::ex2) - + fields(i1, i2 - 1, em::ex2); + } else { + const auto i1_ = COORD(i1); + const auto i2_ = COORD(i2); + buff(i1, i2, buff_idx) = + (fields(i1, i2, em::ex1) * metric.sqrt_det_h({ i1_ + HALF, i2_ }) - + fields(i1 - 1, i2, em::ex1) * metric.sqrt_det_h({ i1_ - HALF, i2_ }) + + fields(i1, i2, em::ex2) * metric.sqrt_det_h({ i1_, i2_ + HALF }) - + fields(i1, i2 - 1, em::ex2) * metric.sqrt_det_h({ i1_, i2_ - HALF })) / + metric.sqrt_det_h({ i1_ + HALF, i2_ + HALF }); + } + } else { + raise::KernelError( + HERE, + "2D implementation of ComputeDivergence_kernel called for non-2D"); + } + } + + Inline void operator()(index_t i1, index_t i2, index_t i3) const { + if constexpr (M::Dim == Dim::_3D) { + if constexpr (M::CoordType == Coord::Cart) { + buff(i1, i2, i3, buff_idx) = fields(i1, i2, i3, em::ex1) - + fields(i1 - 1, i2, i3, em::ex1) + + fields(i1, i2, i3, em::ex2) - + fields(i1, i2 - 1, i3, em::ex2) + + fields(i1, i2, i3, em::ex3) - + fields(i1, i2, i3 - 1, em::ex3); + } else { + const auto i1_ = COORD(i1); + const auto i2_ = COORD(i2); + const auto i3_ = COORD(i3); + buff(i1, i2, i3, buff_idx) = + (fields(i1, i2, i3, em::ex1) * + metric.sqrt_det_h({ i1_ + HALF, i2_, i3_ }) - + fields(i1 - 1, i2, i3, em::ex1) * + metric.sqrt_det_h({ i1_ - HALF, i2_, i3_ }) + + fields(i1, i2, i3, em::ex2) * + metric.sqrt_det_h({ i1_, i2_ + HALF, i3_ }) - + fields(i1, i2 - 1, i3, em::ex2) * + metric.sqrt_det_h({ i1_, i2_ - HALF, i3_ }) + + fields(i1, i2, i3, em::ex3) * + metric.sqrt_det_h({ i1_, i2_, i3_ + HALF }) - + fields(i1, i2, i3 - 1, em::ex3) * + metric.sqrt_det_h({ i1_, i2_, i3_ - HALF })) / + metric.sqrt_det_h({ i1_ + HALF, i2_ + HALF, i3_ + HALF }); + } + } else { + raise::KernelError( + HERE, + "3D implementation of ComputeDivergence_kernel called for non-3D"); + } + } + }; + +} // namespace kernel + +#endif // KERNELS_DIVERGENCES_HPP diff --git a/src/kernels/utils.hpp b/src/kernels/utils.hpp index ce20af82a..628ed267f 100644 --- a/src/kernels/utils.hpp +++ b/src/kernels/utils.hpp @@ -3,6 +3,7 @@ * @brief Commonly used generic kernels * @implements * - kernel::ComputeSum_kernel<> + * - kernel::ComputeDivergence_kernel<> * @namespaces: * - kernel:: */ diff --git a/src/output/CMakeLists.txt b/src/output/CMakeLists.txt index 8a2ea0f16..bd207d45a 100644 --- a/src/output/CMakeLists.txt +++ b/src/output/CMakeLists.txt @@ -6,6 +6,7 @@ # # * writer.cpp # * fields.cpp +# * stats.cpp # * utils/interpret_prompt.cpp # # @includes: @@ -19,13 +20,17 @@ # @uses: # # * kokkos [required] -# * ADIOS2 [required] +# * ADIOS2 [optional] # * mpi [optional] # ------------------------------ set(SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}) -set(SOURCES ${SRC_DIR}/writer.cpp ${SRC_DIR}/fields.cpp - ${SRC_DIR}/utils/interpret_prompt.cpp) + +set(SOURCES ${SRC_DIR}/stats.cpp) +if(${output}) + list(APPEND SOURCES ${SRC_DIR}/writer.cpp ${SRC_DIR}/fields.cpp + ${SRC_DIR}/utils/interpret_prompt.cpp) +endif() add_library(ntt_output ${SOURCES}) set(libs ntt_global) diff --git a/src/output/fields.cpp b/src/output/fields.cpp index 25267bdee..e6b86296f 100644 --- a/src/output/fields.cpp +++ b/src/output/fields.cpp @@ -23,7 +23,10 @@ namespace out { // determine the field ID const auto pos = name.find("_"); auto name_raw = (pos == std::string::npos) ? name : name.substr(0, pos); - name_raw = name_raw.substr(0, name_raw.find_first_of("0123ijxyzt")); + if ((fmt::toLower(name_raw) != "dive") and + (fmt::toLower(name_raw) != "divd")) { + name_raw = name_raw.substr(0, name_raw.find_first_of("0123ijxyzt")); + } if (FldsID::contains(fmt::toLower(name_raw).c_str())) { m_id = FldsID::pick(fmt::toLower(name_raw).c_str()); } else { @@ -59,7 +62,7 @@ namespace out { comp = {}; } // data preparation flags - if (not is_moment() && not is_custom()) { + if (not(is_moment() or is_custom() or is_divergence())) { if (S == SimEngine::SRPIC) { prepare_flag = PrepareOutput::ConvertToHat; } else { diff --git a/src/output/fields.h b/src/output/fields.h index fedadc6f8..bc1271084 100644 --- a/src/output/fields.h +++ b/src/output/fields.h @@ -105,6 +105,10 @@ namespace out { } tmp.pop_back(); } + if (tmp == "dive" || tmp == "divd") { + // capitalize E/D + tmp[3] = std::toupper(tmp[3]); + } // capitalize the first letter tmp[0] = std::toupper(tmp[0]); } @@ -138,6 +142,10 @@ namespace out { } tmp.pop_back(); } + if (tmp == "dive" || tmp == "divd") { + // capitalize E/D + tmp[3] = std::toupper(tmp[3]); + } // capitalize the first letter tmp[0] = std::toupper(tmp[0]); return "f" + tmp; diff --git a/src/output/stats.cpp b/src/output/stats.cpp new file mode 100644 index 000000000..2dfac5c9b --- /dev/null +++ b/src/output/stats.cpp @@ -0,0 +1,132 @@ +#include "output/stats.h" + +#include "enums.h" +#include "global.h" + +#include "arch/mpi_aliases.h" +#include "utils/error.h" +#include "utils/formatting.h" + +#include "output/utils/interpret_prompt.h" + +#include + +#include +#include +#include +#include + +using namespace ntt; +using namespace out; + +namespace stats { + + OutputStats::OutputStats(const std::string& name) : m_name { name } { + // determine the stats ID + const auto pos = name.find("_"); + auto name_raw = (pos == std::string::npos) ? name : name.substr(0, pos); + if ((name_raw[0] != 'E') and (name_raw[0] != 'B') and (name_raw[0] != 'J')) { + name_raw = name_raw.substr(0, name_raw.find_first_of("0123ijxyzt")); + } + if (StatsID::contains(fmt::toLower(name_raw).c_str())) { + m_id = StatsID::pick(fmt::toLower(name_raw).c_str()); + } else { + raise::Error("Unrecognized stats ID " + fmt::toLower(name_raw), HERE); + } + // determine the species and components to output + if (is_moment()) { + species = InterpretSpecies(name); + } else { + species = {}; + } + if (is_vector()) { + // always write all the ExB and V components + comp = { { 1 }, { 2 }, { 3 } }; + } else if (id() == StatsID::T) { + // energy-momentum tensor + comp = InterpretComponents({ name.substr(1, 1), name.substr(2, 1) }); + } else { + // scalar (e.g., Rho, E^2, etc.) + comp = {}; + } + } + + void Writer::init(timestep_t interval, simtime_t interval_time) { + m_tracker = tools::Tracker("stats", interval, interval_time); + } + + auto Writer::shouldWrite(timestep_t step, simtime_t time) -> bool { + return m_tracker.shouldWrite(step, time); + } + + void Writer::defineStatsFilename(const std::string& filename) { + m_fname = filename; + } + + void Writer::defineStatsOutputs(const std::vector& stats_to_write) { + for (const auto& stat : stats_to_write) { + m_stat_writers.emplace_back(stat); + } + } + + void Writer::writeHeader() { + CallOnce( + [](auto& fname, auto& stat_writers) { + std::fstream StatsOut(fname, std::fstream::out | std::fstream::app); + StatsOut << "step,time,"; + for (const auto& stat : stat_writers) { + if (stat.is_vector()) { + for (auto i { 0u }; i < stat.comp.size(); ++i) { + StatsOut << stat.name(i) << ","; + } + } else { + StatsOut << stat.name() << ","; + } + } + StatsOut << std::endl; + StatsOut.close(); + }, + m_fname, + m_stat_writers); + } + + template + void Writer::write(const T& value) { +#if defined(MPI_ENABLED) + // @TODO: reduce +#endif + CallOnce( + [](auto& fname, auto& value) { + std::fstream StatsOut(fname, std::fstream::out | std::fstream::app); + StatsOut << value << ","; + StatsOut.close(); + }, + m_fname, + value); + } + + void Writer::endWriting() { + CallOnce( + [](auto& fname) { + std::fstream StatsOut(fname, std::fstream::out | std::fstream::app); + StatsOut << std::endl; + StatsOut.close(); + }, + m_fname); + } + + template void Writer::write(const char&); + template void Writer::write(const std::string&); + template void Writer::write(const float&); + template void Writer::write(const double&); + template void Writer::write(const int&); + template void Writer::write(const unsigned int&); + template void Writer::write(const short&); + template void Writer::write(const unsigned short&); + template void Writer::write(const long int&); + template void Writer::write(const unsigned long int&); + template void Writer::write(const long long int&); + template void Writer::write( + const unsigned long long int&); + +} // namespace stats diff --git a/src/output/stats.h b/src/output/stats.h new file mode 100644 index 000000000..dbc874bda --- /dev/null +++ b/src/output/stats.h @@ -0,0 +1,156 @@ +/** + * @file output/stats.h + * @brief Class defining the metadata necessary to prepare the stats for output + * @implements + * - out::OutputStats + * @cpp: + * - stats.cpp + * @namespaces: + * - out:: + */ + +#ifndef OUTPUT_STATS_H +#define OUTPUT_STATS_H + +#include "enums.h" +#include "global.h" + +#include "utils/error.h" +#include "utils/tools.h" + +#include +#include + +using namespace ntt; + +namespace stats { + + class OutputStats { + const std::string m_name; + StatsID m_id { StatsID::INVALID }; + + public: + std::vector> comp {}; + std::vector species {}; + + OutputStats(const std::string&); + + ~OutputStats() = default; + + [[nodiscard]] + auto is_moment() const -> bool { + return (id() == StatsID::T || id() == StatsID::Rho || id() == StatsID::Npart || + id() == StatsID::N || id() == StatsID::Charge); + } + + [[nodiscard]] + auto is_vector() const -> bool { + return id() == StatsID::ExB; + } + + [[nodiscard]] + inline auto name() const -> std::string { + // generate the name + std::string tmp = std::string(id().to_string()); + if (tmp == "exb") { + tmp = "ExB"; + } else if (tmp == "j.e") { + tmp = "J.E"; + } else { + // capitalize the first letter + tmp[0] = std::toupper(tmp[0]); + } + if (id() == StatsID::T) { + tmp += m_name.substr(1, 2); + } else if (is_vector()) { + tmp += "i"; + } + if (species.size() > 0) { + tmp += "_"; + for (auto& s : species) { + tmp += std::to_string(s); + tmp += "_"; + } + tmp.pop_back(); + } + return tmp; + } + + [[nodiscard]] + inline auto name(std::size_t ci) const -> std::string { + raise::ErrorIf( + comp.size() == 0, + "OutputField::name(ci) called but no components were available", + HERE); + raise::ErrorIf( + ci >= comp.size(), + "OutputField::name(ci) called with an invalid component index", + HERE); + raise::ErrorIf( + comp[ci].size() == 0, + "OutputField::name(ci) called but no components were available", + HERE); + // generate the name + auto tmp = std::string(id().to_string()); + // capitalize the first letter + if (tmp == "exb") { + tmp = "ExB"; + } else { + // capitalize the first letter + tmp[0] = std::toupper(tmp[0]); + } + for (auto& c : comp[ci]) { + tmp += std::to_string(c); + } + if (species.size() > 0) { + tmp += "_"; + for (auto& s : species) { + tmp += std::to_string(s); + tmp += "_"; + } + tmp.pop_back(); + } + return tmp; + } + + [[nodiscard]] + auto id() const -> StatsID { + return m_id; + } + }; + + class Writer { + std::string m_fname; + std::vector m_stat_writers; + tools::Tracker m_tracker; + + public: + Writer() {} + + ~Writer() = default; + + Writer(Writer&&) = default; + + void init(timestep_t, simtime_t); + void defineStatsFilename(const std::string&); + void defineStatsOutputs(const std::vector&); + + void writeHeader(); + + [[nodiscard]] + auto shouldWrite(timestep_t, simtime_t) -> bool; + + template + void write(const T&); + + void endWriting(); + + [[nodiscard]] + auto statsWriters() const -> const std::vector& { + return m_stat_writers; + } + }; + +} // namespace stats + +#endif // OUTPUT_STATS_H diff --git a/src/output/tests/CMakeLists.txt b/src/output/tests/CMakeLists.txt index 835bb532f..f6f460ae9 100644 --- a/src/output/tests/CMakeLists.txt +++ b/src/output/tests/CMakeLists.txt @@ -29,9 +29,13 @@ function(gen_test title is_parallel) endif() endfunction() -if(NOT ${mpi}) - gen_test(fields false) - gen_test(writer-nompi false) -else() - gen_test(writer-mpi true) +gen_test(stats false) + +if(${output}) + if(NOT ${mpi}) + gen_test(fields false) + gen_test(writer-nompi false) + else() + gen_test(writer-mpi true) + endif() endif() diff --git a/src/output/tests/fields.cpp b/src/output/tests/fields.cpp index e33fd59ec..de86af2f4 100644 --- a/src/output/tests/fields.cpp +++ b/src/output/tests/fields.cpp @@ -50,6 +50,25 @@ auto main() -> int { HERE); } + { + const auto dive = OutputField(SimEngine::SRPIC, "divE"); + raise::ErrorIf(dive.is_moment(), "divE should not be a moment", HERE); + raise::ErrorIf(dive.is_field(), "divE should not be a field", HERE); + raise::ErrorIf(not dive.is_divergence(), "divE should be a divergence", HERE); + raise::ErrorIf(dive.id() != FldsID::divE, + "divE should have ID FldsID::divE", + HERE); + raise::ErrorIf(dive.name() != "fDivE", "divE should have name `fDivE`", HERE); + raise::ErrorIf(dive.comp.size() != 0, "divE should have 0 components", HERE); + raise::ErrorIf(dive.species.size() != 0, "divE should have no species", HERE); + raise::ErrorIf(dive.prepare_flag != PrepareOutput::None, + "divE should not have any prepare flags", + HERE); + raise::ErrorIf(dive.interp_flag != PrepareOutput::None, + "divE should not have any interp flags", + HERE); + } + { const auto t = OutputField(SimEngine::GRPIC, "Tti_2_3"); raise::ErrorIf(not t.is_moment(), "T should be a moment", HERE); diff --git a/src/output/tests/stats.cpp b/src/output/tests/stats.cpp new file mode 100644 index 000000000..db6730a89 --- /dev/null +++ b/src/output/tests/stats.cpp @@ -0,0 +1,102 @@ +#include "output/stats.h" + +#include "enums.h" + +#include "utils/error.h" + +#include +#include +#include + +auto main() -> int { + using namespace stats; + using namespace ntt; + try { + { + const auto e = OutputStats("E^2"); + raise::ErrorIf(e.is_vector(), "E^2 should not be a vector quantity", HERE); + raise::ErrorIf(e.is_moment(), "E^2 should not be a moment", HERE); + raise::ErrorIf(e.id() != StatsID::E2, "E^2 should have ID StatsID::E2", HERE); + raise::ErrorIf(e.species.size() != 0, "E^2 should have no species", HERE); + raise::ErrorIf(e.comp.size() != 0, "E^2 should have no components", HERE); + raise::ErrorIf(e.name() != "E^2", "E^2 should have name `E^2`", HERE); + } + + { + const auto e = OutputStats("ExB"); + raise::ErrorIf(not e.is_vector(), "ExB should be a vector quantity", HERE); + raise::ErrorIf(e.is_moment(), "ExB should not be a moment", HERE); + raise::ErrorIf(e.id() != StatsID::ExB, "ExB should have ID StatsID::ExB", HERE); + raise::ErrorIf(e.species.size() != 0, "ExB should have no species", HERE); + raise::ErrorIf(e.comp.size() != 3, "ExB should have 3 components", HERE); + raise::ErrorIf(e.name() != "ExBi", "ExB should have name `ExBi`", HERE); + } + + { + const auto e = OutputStats("J.E"); + raise::ErrorIf(e.is_vector(), "J.E should not be a vector quantity", HERE); + raise::ErrorIf(e.is_moment(), "J.E should not be a moment", HERE); + raise::ErrorIf(e.id() != StatsID::JdotE, + "J.E should have ID StatsID::JdotE", + HERE); + raise::ErrorIf(e.species.size() != 0, "J.E should have no species", HERE); + raise::ErrorIf(e.comp.size() != 0, "J.E should have no components", HERE); + raise::ErrorIf(e.name() != "J.E", "J.E should have name `J.E`", HERE); + } + + { + const auto rho = OutputStats("Rho_1_3"); + raise::ErrorIf(not rho.is_moment(), "Rho should be a moment", HERE); + raise::ErrorIf(rho.id() != StatsID::Rho, + "Rho should have ID StatsID::Rho", + HERE); + raise::ErrorIf(rho.name() != "Rho_1_3", "Rho should have name `Rho_1_3`", HERE); + raise::ErrorIf(rho.comp.size() != 0, "Rho should have 0 components", HERE); + raise::ErrorIf(not(rho.species == std::vector { 1, 3 }), + "Rho should have species 1 and 3", + HERE); + } + + { + const auto t = OutputStats("Tti_2_3"); + raise::ErrorIf(not t.is_moment(), "T should be a moment", HERE); + raise::ErrorIf(t.is_vector(), "T should not be a vector quantity", HERE); + raise::ErrorIf(t.id() != StatsID::T, "T should have ID StatsID::T", HERE); + raise::ErrorIf(t.name() != "Tti_2_3", "T should have name `Tti_2_3`", HERE); + raise::ErrorIf(t.name(0) != "T01_2_3", "T should have name `T01_2_3`", HERE); + raise::ErrorIf(t.name(1) != "T02_2_3", "T should have name `T02_2_3`", HERE); + raise::ErrorIf(t.name(2) != "T03_2_3", "T should have name `T03_2_3`", HERE); + raise::ErrorIf(t.comp.size() != 3, "T should have 3 component", HERE); + raise::ErrorIf(t.comp[0].size() != 2, + "T.comp[0] should have 2 components", + HERE); + raise::ErrorIf(t.comp[1].size() != 2, + "T.comp[1] should have 2 components", + HERE); + raise::ErrorIf(t.comp[2].size() != 2, + "T.comp[2] should have 2 components", + HERE); + raise::ErrorIf(t.comp[0] != std::vector { 0, 1 }, + "T.comp[0] should be {0, 1}", + HERE); + raise::ErrorIf(t.comp[1] != std::vector { 0, 2 }, + "T.comp[1] should be {0, 2}", + HERE); + raise::ErrorIf(t.comp[2] != std::vector { 0, 3 }, + "T.comp[2] should be {0, 3}", + HERE); + raise::ErrorIf(t.species.size() != 2, "T should have 2 species", HERE); + raise::ErrorIf(t.species[0] != 2, "T should have specie 2", HERE); + raise::ErrorIf(t.species[1] != 3, "T should have specie 3", HERE); + } + + { + const auto t = OutputStats("Tij"); + raise::ErrorIf(t.comp.size() != 6, "T should have 6 component", HERE); + } + } catch (const std::exception& e) { + std::cerr << e.what() << std::endl; + return 1; + } + return 0; +} diff --git a/src/output/writer.cpp b/src/output/writer.cpp index cb30b2d1f..dfc1074ff 100644 --- a/src/output/writer.cpp +++ b/src/output/writer.cpp @@ -29,7 +29,7 @@ namespace out { const std::string& title, bool use_separate_files) { m_separate_files = use_separate_files; - m_engine = engine; + m_engine = fmt::toLower(engine); p_adios = ptr_adios; raise::ErrorIf(p_adios == nullptr, "ADIOS pointer is null", HERE); @@ -424,7 +424,7 @@ namespace out { m_active_mode = write_mode; try { std::string filename; - const std::string ext = m_engine == "hdf5" ? "h5" : "bp"; + const std::string ext = (m_engine == "hdf5") ? "h5" : "bp"; if (m_separate_files) { std::string mode_str; if (m_active_mode == WriteMode::Fields) { From c2d44a22bf93b2a28bda391798100a02a79ac026 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20B=C3=B6ss?= Date: Sat, 19 Apr 2025 10:03:37 -0500 Subject: [PATCH 628/773] bugfixes --- setups/srpic/shock/pgen.hpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/setups/srpic/shock/pgen.hpp b/setups/srpic/shock/pgen.hpp index 738072f27..e354262b7 100644 --- a/setups/srpic/shock/pgen.hpp +++ b/setups/srpic/shock/pgen.hpp @@ -92,7 +92,6 @@ namespace user { // magnetic field properties real_t Btheta, Bphi, Bmag; InitFields init_flds; - BCFields bc_flds; inline PGen(const SimulationParams& p, const Metadomain& global_domain) : arch::ProblemGenerator { p } @@ -105,7 +104,6 @@ namespace user { , Btheta { p.template get("setup.Btheta", ZERO) } , Bphi { p.template get("setup.Bphi", ZERO) } , init_flds { Bmag, Btheta, Bphi, drift_ux } - , bc_flds { Bmag, Btheta, Bphi, drift_ux } , filling_fraction { p.template get("setup.filling_fraction", 1.0) } , injector_velocity { p.template get("setup.injector_velocity", 1.0) } , injection_start { p.template get("setup.injection_start", 0.0) } @@ -114,7 +112,7 @@ namespace user { inline PGen() {} - auto MatchFields(real_t time) const -> BCFields { + auto MatchFields(real_t time) const -> InitFields { return init_flds; } From a8a32061cde710cde30a39d54f4400db71d53d5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20B=C3=B6ss?= Date: Sat, 19 Apr 2025 10:44:57 -0500 Subject: [PATCH 629/773] bugfix in temp calculation --- setups/srpic/shock/pgen.hpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/setups/srpic/shock/pgen.hpp b/setups/srpic/shock/pgen.hpp index e354262b7..6bd6f21a9 100644 --- a/setups/srpic/shock/pgen.hpp +++ b/setups/srpic/shock/pgen.hpp @@ -176,8 +176,7 @@ namespace user { const auto energy_dist = arch::TwoTemperatureMaxwellian( local_domain.mesh.metric, local_domain.random_pool, - { temperature_ratio * temperature * - (local_domain.species[2].mass() / local_domain.species[1].mass()), + { temperature_ratio * temperature * local_domain.species[1].mass() , temperature }, { 1, 2 }, -drift_ux, @@ -319,8 +318,7 @@ namespace user { const auto energy_dist = arch::TwoTemperatureMaxwellian( domain.mesh.metric, domain.random_pool, - { temperature_ratio * temperature * - (domain.species[2].mass() / domain.species[1].mass()), + { temperature_ratio * temperature * domain.species[1].mass(), temperature }, { 1, 2 }, -drift_ux, From 62d1ce432c8344507ddfd84c2339034e24c7a6e5 Mon Sep 17 00:00:00 2001 From: hayk Date: Sat, 19 Apr 2025 20:55:13 -0400 Subject: [PATCH 630/773] change BCs routine --- src/framework/domain/domain.h | 24 ++--- src/framework/domain/metadomain.cpp | 136 ++++++++++++++++++++++++++++ src/framework/domain/metadomain.h | 2 + 3 files changed, 147 insertions(+), 15 deletions(-) diff --git a/src/framework/domain/domain.h b/src/framework/domain/domain.h index 7966cdb54..c26f5995f 100644 --- a/src/framework/domain/domain.h +++ b/src/framework/domain/domain.h @@ -146,7 +146,8 @@ namespace ntt { } /* setters -------------------------------------------------------------- */ - auto set_neighbor_idx(const dir::direction_t& dir, unsigned int idx) -> void { + auto set_neighbor_idx(const dir::direction_t& dir, unsigned int idx) + -> void { m_neighbor_idx[dir] = idx; } @@ -164,8 +165,8 @@ namespace ntt { }; template - inline auto operator<<(std::ostream& os, - const Domain& domain) -> std::ostream& { + inline auto operator<<(std::ostream& os, const Domain& domain) + -> std::ostream& { os << "Domain #" << domain.index(); #if defined(MPI_ENABLED) os << " [MPI rank: " << domain.mpi_rank() << "]"; @@ -184,23 +185,16 @@ namespace ntt { } os << "\n"; os << std::setw(19) << std::left << " physical extent: "; - for (auto dim = 0; dim < M::Dim; ++dim) { + for (auto dim { 0u }; dim < M::Dim; ++dim) { os << std::setw(15) << std::left << fmt::format("{%.2f; %.2f}", - domain.mesh.extent(dim).first, - domain.mesh.extent(dim).second); + domain.mesh.extent(static_cast(dim)).first, + domain.mesh.extent(static_cast(dim)).second); } os << "\n neighbors:\n"; for (auto& direction : dir::Directions::all) { - auto neighbor = domain.neighbor_in(direction); - os << " " << direction; - if (neighbor != nullptr) { - os << " -> #" << neighbor->index() << "\n"; - } else { - os << " -> " - << "N/A" - << "\n"; - } + auto neighbor_idx = domain.neighbor_idx_in(direction); + os << " " << direction << " -> #" << neighbor_idx << "\n"; } os << " field boundaries:\n"; for (auto& direction : dir::Directions::orth) { diff --git a/src/framework/domain/metadomain.cpp b/src/framework/domain/metadomain.cpp index fc3c59d4c..4b9057e23 100644 --- a/src/framework/domain/metadomain.cpp +++ b/src/framework/domain/metadomain.cpp @@ -403,6 +403,142 @@ namespace ntt { #endif } + template + void Metadomain::setFldsBC(const bc_in& dir, const FldsBC& new_bcs) { + if (dir == bc_in::Mx1) { + if constexpr (M::Dim == Dim::_1D) { + g_mesh.set_flds_bc({ -1 }, new_bcs); + } else if constexpr (M::Dim == Dim::_2D) { + g_mesh.set_flds_bc({ -1, 0 }, new_bcs); + } else if constexpr (M::Dim == Dim::_3D) { + g_mesh.set_flds_bc({ -1, 0, 0 }, new_bcs); + } else { + raise::Error("Invalid dimension", HERE); + } + } else if (dir == bc_in::Px1) { + if constexpr (M::Dim == Dim::_1D) { + g_mesh.set_flds_bc({ +1 }, new_bcs); + } else if constexpr (M::Dim == Dim::_2D) { + g_mesh.set_flds_bc({ +1, 0 }, new_bcs); + } else if constexpr (M::Dim == Dim::_3D) { + g_mesh.set_flds_bc({ +1, 0, 0 }, new_bcs); + } else { + raise::Error("Invalid dimension", HERE); + } + } else if (dir == bc_in::Mx2) { + if constexpr (M::Dim == Dim::_1D) { + raise::Error("Cannot set -x2 BCs for 1D", HERE); + } else if constexpr (M::Dim == Dim::_2D) { + g_mesh.set_flds_bc({ -1, 0 }, new_bcs); + } else if constexpr (M::Dim == Dim::_3D) { + g_mesh.set_flds_bc({ -1, 0, 0 }, new_bcs); + } else { + raise::Error("Invalid dimension", HERE); + } + } else if (dir == bc_in::Px2) { + if constexpr (M::Dim == Dim::_1D) { + raise::Error("Cannot set +x2 BCs for 1D", HERE); + } else if constexpr (M::Dim == Dim::_2D) { + g_mesh.set_flds_bc({ +1, 0 }, new_bcs); + } else if constexpr (M::Dim == Dim::_3D) { + g_mesh.set_flds_bc({ +1, 0, 0 }, new_bcs); + } else { + raise::Error("Invalid dimension", HERE); + } + } else if (dir == bc_in::Mx3) { + if constexpr (M::Dim == Dim::_1D) { + raise::Error("Cannot set -x3 BCs for 1D", HERE); + } else if constexpr (M::Dim == Dim::_2D) { + raise::Error("Cannot set -x3 BCs for 2D", HERE); + } else if constexpr (M::Dim == Dim::_3D) { + g_mesh.set_flds_bc({ 0, 0, -1 }, new_bcs); + } else { + raise::Error("Invalid dimension", HERE); + } + } else if (dir == bc_in::Px3) { + if constexpr (M::Dim == Dim::_1D) { + raise::Error("Cannot set +x3 BCs for 1D", HERE); + } else if constexpr (M::Dim == Dim::_2D) { + raise::Error("Cannot set +x3 BCs for 2D", HERE); + } else if constexpr (M::Dim == Dim::_3D) { + g_mesh.set_flds_bc({ 0, 0, +1 }, new_bcs); + } else { + raise::Error("Invalid dimension", HERE); + } + } else { + raise::Error("Invalid direction", HERE); + } + redefineBoundaries(); + } + + template + void Metadomain::setPrtlBC(const bc_in& dir, const PrtlBC& new_bcs) { + if (dir == bc_in::Mx1) { + if constexpr (M::Dim == Dim::_1D) { + g_mesh.set_prtl_bc({ -1 }, new_bcs); + } else if constexpr (M::Dim == Dim::_2D) { + g_mesh.set_prtl_bc({ -1, 0 }, new_bcs); + } else if constexpr (M::Dim == Dim::_3D) { + g_mesh.set_prtl_bc({ -1, 0, 0 }, new_bcs); + } else { + raise::Error("Invalid dimension", HERE); + } + } else if (dir == bc_in::Px1) { + if constexpr (M::Dim == Dim::_1D) { + g_mesh.set_prtl_bc({ +1 }, new_bcs); + } else if constexpr (M::Dim == Dim::_2D) { + g_mesh.set_prtl_bc({ +1, 0 }, new_bcs); + } else if constexpr (M::Dim == Dim::_3D) { + g_mesh.set_prtl_bc({ +1, 0, 0 }, new_bcs); + } else { + raise::Error("Invalid dimension", HERE); + } + } else if (dir == bc_in::Mx2) { + if constexpr (M::Dim == Dim::_1D) { + raise::Error("Cannot set -x2 BCs for 1D", HERE); + } else if constexpr (M::Dim == Dim::_2D) { + g_mesh.set_prtl_bc({ -1, 0 }, new_bcs); + } else if constexpr (M::Dim == Dim::_3D) { + g_mesh.set_prtl_bc({ -1, 0, 0 }, new_bcs); + } else { + raise::Error("Invalid dimension", HERE); + } + } else if (dir == bc_in::Px2) { + if constexpr (M::Dim == Dim::_1D) { + raise::Error("Cannot set +x2 BCs for 1D", HERE); + } else if constexpr (M::Dim == Dim::_2D) { + g_mesh.set_prtl_bc({ +1, 0 }, new_bcs); + } else if constexpr (M::Dim == Dim::_3D) { + g_mesh.set_prtl_bc({ +1, 0, 0 }, new_bcs); + } else { + raise::Error("Invalid dimension", HERE); + } + } else if (dir == bc_in::Mx3) { + if constexpr (M::Dim == Dim::_1D) { + raise::Error("Cannot set -x3 BCs for 1D", HERE); + } else if constexpr (M::Dim == Dim::_2D) { + raise::Error("Cannot set -x3 BCs for 2D", HERE); + } else if constexpr (M::Dim == Dim::_3D) { + g_mesh.set_prtl_bc({ 0, 0, -1 }, new_bcs); + } else { + raise::Error("Invalid dimension", HERE); + } + } else if (dir == bc_in::Px3) { + if constexpr (M::Dim == Dim::_1D) { + raise::Error("Cannot set +x3 BCs for 1D", HERE); + } else if constexpr (M::Dim == Dim::_2D) { + raise::Error("Cannot set +x3 BCs for 2D", HERE); + } else if constexpr (M::Dim == Dim::_3D) { + g_mesh.set_prtl_bc({ 0, 0, +1 }, new_bcs); + } else { + raise::Error("Invalid dimension", HERE); + } + } else { + raise::Error("Invalid direction", HERE); + } + redefineBoundaries(); + } + template struct Metadomain>; template struct Metadomain>; template struct Metadomain>; diff --git a/src/framework/domain/metadomain.h b/src/framework/domain/metadomain.h index 1728fbd65..1fb6ce007 100644 --- a/src/framework/domain/metadomain.h +++ b/src/framework/domain/metadomain.h @@ -142,6 +142,8 @@ namespace ntt { -> bool; /* setters -------------------------------------------------------------- */ + void setFldsBC(const bc_in&, const FldsBC&); + void setPrtlBC(const bc_in&, const PrtlBC&); /* getters -------------------------------------------------------------- */ [[nodiscard]] From e0a7b18ee9a66ce56394fc01a07189bd58b1b8b8 Mon Sep 17 00:00:00 2001 From: hayk Date: Mon, 21 Apr 2025 06:35:19 -0400 Subject: [PATCH 631/773] rec setup BC + tested with MPI --- setups/wip/reconnection/pgen.hpp | 71 ++++++++++++++++++++------------ 1 file changed, 45 insertions(+), 26 deletions(-) diff --git a/setups/wip/reconnection/pgen.hpp b/setups/wip/reconnection/pgen.hpp index 70bab7b32..e92de5847 100644 --- a/setups/wip/reconnection/pgen.hpp +++ b/setups/wip/reconnection/pgen.hpp @@ -22,17 +22,19 @@ namespace user { template struct CurrentLayer : public arch::SpatialDistribution { - CurrentLayer(const M& metric, real_t cs_width, real_t cs_y) + CurrentLayer(const M& metric, real_t cs_width, real_t center_x, real_t cs_y) : arch::SpatialDistribution { metric } , cs_width { cs_width } + , center_x { center_x } , cs_y { cs_y } {} Inline auto operator()(const coord_t& x_Ph) const -> real_t override { - return ONE / SQR(math::cosh((x_Ph[1] - cs_y) / cs_width)); + return ONE / SQR(math::cosh((x_Ph[1] - cs_y) / cs_width)) * + (ONE - math::exp(-SQR((x_Ph[0] - center_x) / cs_width))); } private: - const real_t cs_y, cs_width; + const real_t cs_width, center_x, cs_y; }; // field initializer @@ -159,13 +161,17 @@ namespace user { using arch::ProblemGenerator::C; using arch::ProblemGenerator::params; - const real_t bg_B, bg_Bguide, bg_temperature, inj_ypad; - const real_t cs_width, cs_overdensity, cs_x, cs_y; - const real_t ymin, ymax; + const real_t bg_B, bg_Bguide, bg_temperature, inj_ypad; + const real_t cs_width, cs_overdensity, cs_x, cs_y; + const real_t ymin, ymax; + const simtime_t t_open; + bool bc_opened { false }; + + Metadomain& metadomain; InitFields init_flds; - inline PGen(const SimulationParams& p, const Metadomain& m) + inline PGen(const SimulationParams& p, Metadomain& m) : arch::ProblemGenerator(p) , bg_B { p.template get("setup.bg_B", 1.0) } , bg_Bguide { p.template get("setup.bg_Bguide", 0.0) } @@ -173,14 +179,17 @@ namespace user { , inj_ypad { p.template get("setup.inj_ypad", (real_t)0.05) } , cs_width { p.template get("setup.cs_width") } , cs_overdensity { p.template get("setup.cs_overdensity") } - , cs_x { m.mesh().extent(in::x1).first + - INV_2 * (m.mesh().extent(in::x1).second - - m.mesh().extent(in::x1).first) } - , cs_y { m.mesh().extent(in::x2).first + - INV_2 * (m.mesh().extent(in::x2).second - - m.mesh().extent(in::x2).first) } + , cs_x { INV_2 * + (m.mesh().extent(in::x1).second + m.mesh().extent(in::x1).first) } + , cs_y { INV_2 * + (m.mesh().extent(in::x2).second + m.mesh().extent(in::x2).first) } , ymin { m.mesh().extent(in::x2).first } , ymax { m.mesh().extent(in::x2).second } + , t_open { p.template get( + "setup.t_open", + 1.5 * HALF * + (m.mesh().extent(in::x1).second - m.mesh().extent(in::x1).first)) } + , metadomain { m } , init_flds { bg_B, bg_Bguide, cs_width, cs_y } {} inline PGen() {} @@ -225,6 +234,7 @@ namespace user { false); const auto sdist_cs = CurrentLayer(local_domain.mesh.metric, cs_width, + cs_x, cs_y); const auto inj_cs = arch::NonUniformInjector( edist_cs, @@ -236,7 +246,16 @@ namespace user { cs_overdensity); } - void CustomPostStep(timestep_t, simtime_t, Domain& domain) { + void CustomPostStep(timestep_t, simtime_t time, Domain& domain) { + // open boundaries if not yet opened at time = t_open + if ((t_open > 0.0) and (not bc_opened) and (time > t_open)) { + bc_opened = true; + metadomain.setFldsBC(bc_in::Mx1, FldsBC::MATCH); + metadomain.setPrtlBC(bc_in::Mx1, PrtlBC::ABSORB); + metadomain.setFldsBC(bc_in::Px1, FldsBC::MATCH); + metadomain.setPrtlBC(bc_in::Px1, PrtlBC::ABSORB); + } + const auto energy_dist = arch::Maxwellian(domain.mesh.metric, domain.random_pool, bg_temperature); @@ -272,18 +291,18 @@ namespace user { for (const auto sp : std::vector { 1, 2 }) { const auto& prtl_spec = domain.species[sp - 1]; // clang-format off - Kokkos::parallel_for( - "ComputeMoments", - prtl_spec.rangeActiveParticles(), - kernel::ParticleMoments_kernel({}, scatter_buff, 0u, - prtl_spec.i1, prtl_spec.i2, prtl_spec.i3, - prtl_spec.dx1, prtl_spec.dx2, prtl_spec.dx3, - prtl_spec.ux1, prtl_spec.ux2, prtl_spec.ux3, - prtl_spec.phi, prtl_spec.weight, prtl_spec.tag, - prtl_spec.mass(), prtl_spec.charge(), - use_weights, - domain.mesh.metric, domain.mesh.flds_bc(), - ni2, inv_n0, 0u)); + Kokkos::parallel_for( + "ComputeMoments", + prtl_spec.rangeActiveParticles(), + kernel::ParticleMoments_kernel({}, scatter_buff, 0u, + prtl_spec.i1, prtl_spec.i2, prtl_spec.i3, + prtl_spec.dx1, prtl_spec.dx2, prtl_spec.dx3, + prtl_spec.ux1, prtl_spec.ux2, prtl_spec.ux3, + prtl_spec.phi, prtl_spec.weight, prtl_spec.tag, + prtl_spec.mass(), prtl_spec.charge(), + use_weights, + domain.mesh.metric, domain.mesh.flds_bc(), + ni2, inv_n0, 0u)); // clang-format on } Kokkos::Experimental::contribute(domain.fields.buff, scatter_buff); From ec5c65ce51a799689ebe79e55024d6cdfac50fb1 Mon Sep 17 00:00:00 2001 From: hayk Date: Mon, 21 Apr 2025 06:35:37 -0400 Subject: [PATCH 632/773] inlined writer --- src/output/stats.cpp | 31 ------------------------------- src/output/stats.h | 16 +++++++++++++++- 2 files changed, 15 insertions(+), 32 deletions(-) diff --git a/src/output/stats.cpp b/src/output/stats.cpp index 2dfac5c9b..ba3e85c40 100644 --- a/src/output/stats.cpp +++ b/src/output/stats.cpp @@ -11,8 +11,6 @@ #include -#include -#include #include #include @@ -90,21 +88,6 @@ namespace stats { m_stat_writers); } - template - void Writer::write(const T& value) { -#if defined(MPI_ENABLED) - // @TODO: reduce -#endif - CallOnce( - [](auto& fname, auto& value) { - std::fstream StatsOut(fname, std::fstream::out | std::fstream::app); - StatsOut << value << ","; - StatsOut.close(); - }, - m_fname, - value); - } - void Writer::endWriting() { CallOnce( [](auto& fname) { @@ -115,18 +98,4 @@ namespace stats { m_fname); } - template void Writer::write(const char&); - template void Writer::write(const std::string&); - template void Writer::write(const float&); - template void Writer::write(const double&); - template void Writer::write(const int&); - template void Writer::write(const unsigned int&); - template void Writer::write(const short&); - template void Writer::write(const unsigned short&); - template void Writer::write(const long int&); - template void Writer::write(const unsigned long int&); - template void Writer::write(const long long int&); - template void Writer::write( - const unsigned long long int&); - } // namespace stats diff --git a/src/output/stats.h b/src/output/stats.h index dbc874bda..c81b9b7b3 100644 --- a/src/output/stats.h +++ b/src/output/stats.h @@ -18,6 +18,8 @@ #include "utils/error.h" #include "utils/tools.h" +#include +#include #include #include @@ -141,7 +143,19 @@ namespace stats { auto shouldWrite(timestep_t, simtime_t) -> bool; template - void write(const T&); + inline void write(const T& value) const { +#if defined(MPI_ENABLED) + // @TODO: reduce +#endif + CallOnce( + [](auto& fname, auto& value) { + std::fstream StatsOut(fname, std::fstream::out | std::fstream::app); + StatsOut << value << ","; + StatsOut.close(); + }, + m_fname, + value); + } void endWriting(); From 1f8db6ca0c3d453b5ff60909cccec701b0465fbe Mon Sep 17 00:00:00 2001 From: hayk Date: Mon, 21 Apr 2025 06:35:48 -0400 Subject: [PATCH 633/773] minor print rm --- cmake/report.cmake | 1 - 1 file changed, 1 deletion(-) diff --git a/cmake/report.cmake b/cmake/report.cmake index 5a38b0dd5..626de15a2 100644 --- a/cmake/report.cmake +++ b/cmake/report.cmake @@ -155,7 +155,6 @@ if(${Kokkos_DEVICES} MATCHES "CUDA") COMMAND bash -c ${cmd} OUTPUT_VARIABLE CUDACOMP_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE) - message(STATUS "CUDACOMP: ${CUDACOMP_VERSION}") string( APPEND REPORT_TEXT From f82b681c571c33c41229b30839f0101b099824d5 Mon Sep 17 00:00:00 2001 From: haykh Date: Wed, 9 Apr 2025 07:43:26 -0400 Subject: [PATCH 634/773] new deposit scheme --- src/framework/parameters.cpp | 8 +- src/kernels/currents_deposit.hpp | 460 +++++++++++++++---------------- 2 files changed, 219 insertions(+), 249 deletions(-) diff --git a/src/framework/parameters.cpp b/src/framework/parameters.cpp index 26f542956..8a30f52d9 100644 --- a/src/framework/parameters.cpp +++ b/src/framework/parameters.cpp @@ -31,10 +31,10 @@ namespace ntt { template - auto get_dx0_V0(const std::vector& resolution, - const boundaries_t& extent, - const std::map& params) - -> std::pair { + auto get_dx0_V0( + const std::vector& resolution, + const boundaries_t& extent, + const std::map& params) -> std::pair { const auto metric = M(resolution, extent, params); const auto dx0 = metric.dxMin(); coord_t x_corner { ZERO }; diff --git a/src/kernels/currents_deposit.hpp b/src/kernels/currents_deposit.hpp index ca9a94878..98d00a9b0 100644 --- a/src/kernels/currents_deposit.hpp +++ b/src/kernels/currents_deposit.hpp @@ -67,8 +67,8 @@ namespace kernel { const array_t& weight, const array_t& tag, const M& metric, - const real_t& charge, - const real_t& dt) + real_t charge, + real_t dt) : J { scatter_cur } , i1 { i1 } , i2 { i2 } @@ -100,45 +100,70 @@ namespace kernel { if (tag(p) == ParticleTag::dead) { return; } - // _f = final, _i = initial - tuple_t Ip_f, Ip_i; - coord_t xp_f, xp_i, xp_r; + // recover particle velocity to deposit in unsimulated direction vec_t vp { ZERO }; + { + coord_t xp { ZERO }; + if constexpr (D == Dim::_1D) { + xp[0] = i_di_to_Xi(i1(p), dx1(p)); + } else if constexpr (D == Dim::_2D) { + if constexpr (M::PrtlDim == Dim::_3D) { + xp[0] = i_di_to_Xi(i1(p), dx1(p)); + xp[1] = i_di_to_Xi(i2(p), dx2(p)); + xp[2] = phi(p); + } else { + xp[0] = i_di_to_Xi(i1(p), dx1(p)); + xp[1] = i_di_to_Xi(i2(p), dx2(p)); + } + } else { + xp[0] = i_di_to_Xi(i1(p), dx1(p)); + xp[1] = i_di_to_Xi(i2(p), dx2(p)); + xp[2] = i_di_to_Xi(i3(p), dx3(p)); + } + auto inv_energy { ZERO }; + if constexpr (S == SimEngine::SRPIC) { + metric.template transform_xyz(xp, + { ux1(p), ux2(p), ux3(p) }, + vp); + inv_energy = ONE / math::sqrt(ONE + NORM_SQR(ux1(p), ux2(p), ux3(p))); + } else { + metric.template transform(xp, + { ux1(p), ux2(p), ux3(p) }, + vp); + inv_energy = ONE / math::sqrt(ONE + ux1(p) * vp[0] + ux2(p) * vp[1] + + ux3(p) * vp[2]); + } + if (Kokkos::isnan(vp[2]) || Kokkos::isinf(vp[2])) { + vp[2] = ZERO; + } + vp[0] *= inv_energy; + vp[1] *= inv_energy; + vp[2] *= inv_energy; + } - // get [i, di]_init and [i, di]_final (per dimension) - getDepositInterval(p, Ip_f, Ip_i, xp_f, xp_i, xp_r); - // recover particle velocity to deposit in unsimulated direction - getPrtl3Vel(p, vp); const real_t coeff { weight(p) * charge }; - depositCurrentsFromParticle(coeff, vp, Ip_f, Ip_i, xp_f, xp_i, xp_r); - } - /** - * @brief Deposit currents from a single particle. - * @param[in] coeff Particle weight x charge. - * @param[in] vp Particle 3-velocity. - * @param[in] Ip_f Final position of the particle (cell index). - * @param[in] Ip_i Initial position of the particle (cell index). - * @param[in] xp_f Final position. - * @param[in] xp_i Previous step position. - * @param[in] xp_r Intermediate point used in zig-zag deposit. - */ - Inline auto depositCurrentsFromParticle(const real_t& coeff, - const vec_t& vp, - const tuple_t& Ip_f, - const tuple_t& Ip_i, - const coord_t& xp_f, - const coord_t& xp_i, - const coord_t& xp_r) const -> void { - const real_t Wx1_1 { HALF * (xp_i[0] + xp_r[0]) - - static_cast(Ip_i[0]) }; - const real_t Wx1_2 { HALF * (xp_f[0] + xp_r[0]) - - static_cast(Ip_f[0]) }; - const real_t Fx1_1 { (xp_r[0] - xp_i[0]) * coeff * inv_dt }; - const real_t Fx1_2 { (xp_f[0] - xp_r[0]) * coeff * inv_dt }; + const auto dxp_r_1 { static_cast(i1(p) == i1_prev(p)) * + (dx1(p) + dx1_prev(p)) * static_cast(INV_2) }; + + const real_t Wx1_1 { INV_2 * (dxp_r_1 + dx1_prev(p) + + static_cast(i1(p) > i1_prev(p))) }; + const real_t Wx1_2 { INV_2 * (dx1(p) + dxp_r_1 + + static_cast( + static_cast(i1(p) > i1_prev(p)) + + i1_prev(p) - i1(p))) }; + const real_t Fx1_1 { (static_cast(i1(p) > i1_prev(p)) + dxp_r_1 - + dx1_prev(p)) * + coeff * inv_dt }; + const real_t Fx1_2 { (static_cast( + i1(p) - i1_prev(p) - + static_cast(i1(p) > i1_prev(p))) + + dx1(p) - dxp_r_1) * + coeff * inv_dt }; auto J_acc = J.access(); + // tuple_t dxp_r; if constexpr (D == Dim::_1D) { const real_t Fx2_1 { HALF * vp[1] * coeff }; const real_t Fx2_2 { HALF * vp[1] * coeff }; @@ -146,265 +171,210 @@ namespace kernel { const real_t Fx3_1 { HALF * vp[2] * coeff }; const real_t Fx3_2 { HALF * vp[2] * coeff }; - J_acc(Ip_i[0] + N_GHOSTS, cur::jx1) += Fx1_1; - J_acc(Ip_f[0] + N_GHOSTS, cur::jx1) += Fx1_2; + J_acc(i1_prev(p) + N_GHOSTS, cur::jx1) += Fx1_1; + J_acc(i1(p) + N_GHOSTS, cur::jx1) += Fx1_2; - J_acc(Ip_i[0] + N_GHOSTS, cur::jx2) += Fx2_1 * (ONE - Wx1_1); - J_acc(Ip_i[0] + N_GHOSTS + 1, cur::jx2) += Fx2_1 * Wx1_1; - J_acc(Ip_f[0] + N_GHOSTS, cur::jx2) += Fx2_2 * (ONE - Wx1_2); - J_acc(Ip_f[0] + N_GHOSTS + 1, cur::jx2) += Fx2_2 * Wx1_2; + J_acc(i1_prev(p) + N_GHOSTS, cur::jx2) += Fx2_1 * (ONE - Wx1_1); + J_acc(i1_prev(p) + N_GHOSTS + 1, cur::jx2) += Fx2_1 * Wx1_1; + J_acc(i1(p) + N_GHOSTS, cur::jx2) += Fx2_2 * (ONE - Wx1_2); + J_acc(i1(p) + N_GHOSTS + 1, cur::jx2) += Fx2_2 * Wx1_2; - J_acc(Ip_i[0] + N_GHOSTS, cur::jx3) += Fx3_1 * (ONE - Wx1_1); - J_acc(Ip_i[0] + N_GHOSTS + 1, cur::jx3) += Fx3_1 * Wx1_1; - J_acc(Ip_f[0] + N_GHOSTS, cur::jx3) += Fx3_2 * (ONE - Wx1_2); - J_acc(Ip_f[0] + N_GHOSTS + 1, cur::jx3) += Fx3_2 * Wx1_2; + J_acc(i1_prev(p) + N_GHOSTS, cur::jx3) += Fx3_1 * (ONE - Wx1_1); + J_acc(i1_prev(p) + N_GHOSTS + 1, cur::jx3) += Fx3_1 * Wx1_1; + J_acc(i1(p) + N_GHOSTS, cur::jx3) += Fx3_2 * (ONE - Wx1_2); + J_acc(i1(p) + N_GHOSTS + 1, cur::jx3) += Fx3_2 * Wx1_2; } else if constexpr (D == Dim::_2D || D == Dim::_3D) { - const real_t Wx2_1 { HALF * (xp_i[1] + xp_r[1]) - - static_cast(Ip_i[1]) }; - const real_t Wx2_2 { HALF * (xp_f[1] + xp_r[1]) - - static_cast(Ip_f[1]) }; - const real_t Fx2_1 { (xp_r[1] - xp_i[1]) * coeff * inv_dt }; - const real_t Fx2_2 { (xp_f[1] - xp_r[1]) * coeff * inv_dt }; + const auto dxp_r_2 { static_cast(i2(p) == i2_prev(p)) * + (dx2(p) + dx2_prev(p)) * + static_cast(INV_2) }; + + const real_t Wx2_1 { INV_2 * (dxp_r_2 + dx2_prev(p) + + static_cast(i2(p) > i2_prev(p))) }; + const real_t Wx2_2 { INV_2 * (dx2(p) + dxp_r_2 + + static_cast( + static_cast(i2(p) > i2_prev(p)) + + i2_prev(p) - i2(p))) }; + const real_t Fx2_1 { (static_cast(i2(p) > i2_prev(p)) + + dxp_r_2 - dx2_prev(p)) * + coeff * inv_dt }; + const real_t Fx2_2 { (static_cast( + i2(p) - i2_prev(p) - + static_cast(i2(p) > i2_prev(p))) + + dx2(p) - dxp_r_2) * + coeff * inv_dt }; if constexpr (D == Dim::_2D) { const real_t Fx3_1 { HALF * vp[2] * coeff }; const real_t Fx3_2 { HALF * vp[2] * coeff }; - J_acc(Ip_i[0] + N_GHOSTS, Ip_i[1] + N_GHOSTS, cur::jx1) += Fx1_1 * - (ONE - Wx2_1); - J_acc(Ip_i[0] + N_GHOSTS, Ip_i[1] + N_GHOSTS + 1, cur::jx1) += Fx1_1 * - Wx2_1; - J_acc(Ip_f[0] + N_GHOSTS, Ip_f[1] + N_GHOSTS, cur::jx1) += Fx1_2 * - (ONE - Wx2_2); - J_acc(Ip_f[0] + N_GHOSTS, Ip_f[1] + N_GHOSTS + 1, cur::jx1) += Fx1_2 * - Wx2_2; - - J_acc(Ip_i[0] + N_GHOSTS, Ip_i[1] + N_GHOSTS, cur::jx2) += Fx2_1 * - (ONE - Wx1_1); - J_acc(Ip_i[0] + N_GHOSTS + 1, Ip_i[1] + N_GHOSTS, cur::jx2) += Fx2_1 * - Wx1_1; - J_acc(Ip_f[0] + N_GHOSTS, Ip_f[1] + N_GHOSTS, cur::jx2) += Fx2_2 * - (ONE - Wx1_2); - J_acc(Ip_f[0] + N_GHOSTS + 1, Ip_f[1] + N_GHOSTS, cur::jx2) += Fx2_2 * - Wx1_2; - - J_acc(Ip_i[0] + N_GHOSTS, - Ip_i[1] + N_GHOSTS, + J_acc(i1_prev(p) + N_GHOSTS, + i2_prev(p) + N_GHOSTS, + cur::jx1) += Fx1_1 * (ONE - Wx2_1); + J_acc(i1_prev(p) + N_GHOSTS, + i2_prev(p) + N_GHOSTS + 1, + cur::jx1) += Fx1_1 * Wx2_1; + J_acc(i1(p) + N_GHOSTS, i2(p) + N_GHOSTS, cur::jx1) += Fx1_2 * + (ONE - Wx2_2); + J_acc(i1(p) + N_GHOSTS, i2(p) + N_GHOSTS + 1, cur::jx1) += Fx1_2 * Wx2_2; + + J_acc(i1_prev(p) + N_GHOSTS, + i2_prev(p) + N_GHOSTS, + cur::jx2) += Fx2_1 * (ONE - Wx1_1); + J_acc(i1_prev(p) + N_GHOSTS + 1, + i2_prev(p) + N_GHOSTS, + cur::jx2) += Fx2_1 * Wx1_1; + J_acc(i1(p) + N_GHOSTS, i2(p) + N_GHOSTS, cur::jx2) += Fx2_2 * + (ONE - Wx1_2); + J_acc(i1(p) + N_GHOSTS + 1, i2(p) + N_GHOSTS, cur::jx2) += Fx2_2 * Wx1_2; + + J_acc(i1_prev(p) + N_GHOSTS, + i2_prev(p) + N_GHOSTS, cur::jx3) += Fx3_1 * (ONE - Wx1_1) * (ONE - Wx2_1); - J_acc(Ip_i[0] + N_GHOSTS + 1, - Ip_i[1] + N_GHOSTS, + J_acc(i1_prev(p) + N_GHOSTS + 1, + i2_prev(p) + N_GHOSTS, cur::jx3) += Fx3_1 * Wx1_2 * (ONE - Wx2_1); - J_acc(Ip_i[0] + N_GHOSTS, - Ip_i[1] + N_GHOSTS + 1, + J_acc(i1_prev(p) + N_GHOSTS, + i2_prev(p) + N_GHOSTS + 1, cur::jx3) += Fx3_1 * (ONE - Wx1_1) * Wx2_1; - J_acc(Ip_i[0] + N_GHOSTS + 1, - Ip_i[1] + N_GHOSTS + 1, + J_acc(i1_prev(p) + N_GHOSTS + 1, + i2_prev(p) + N_GHOSTS + 1, cur::jx3) += Fx3_1 * Wx1_1 * Wx2_1; - J_acc(Ip_f[0] + N_GHOSTS, - Ip_f[1] + N_GHOSTS, - cur::jx3) += Fx3_2 * (ONE - Wx1_2) * (ONE - Wx2_2); - J_acc(Ip_f[0] + N_GHOSTS + 1, - Ip_f[1] + N_GHOSTS, + J_acc(i1(p) + N_GHOSTS, i2(p) + N_GHOSTS, cur::jx3) += Fx3_2 * + (ONE - Wx1_2) * + (ONE - Wx2_2); + J_acc(i1(p) + N_GHOSTS + 1, + i2(p) + N_GHOSTS, cur::jx3) += Fx3_2 * Wx1_2 * (ONE - Wx2_2); - J_acc(Ip_f[0] + N_GHOSTS, - Ip_f[1] + N_GHOSTS + 1, + J_acc(i1(p) + N_GHOSTS, + i2(p) + N_GHOSTS + 1, cur::jx3) += Fx3_2 * (ONE - Wx1_2) * Wx2_2; - J_acc(Ip_f[0] + N_GHOSTS + 1, - Ip_f[1] + N_GHOSTS + 1, - cur::jx3) += Fx3_2 * Wx1_2 * Wx2_2; + J_acc(i1(p) + N_GHOSTS + 1, i2(p) + N_GHOSTS + 1, cur::jx3) += Fx3_2 * + Wx1_2 * + Wx2_2; } else { - const real_t Wx3_1 { HALF * (xp_i[2] + xp_r[2]) - - static_cast(Ip_i[2]) }; - const real_t Wx3_2 { HALF * (xp_f[2] + xp_r[2]) - - static_cast(Ip_f[2]) }; - const real_t Fx3_1 { (xp_r[2] - xp_i[2]) * coeff * inv_dt }; - const real_t Fx3_2 { (xp_f[2] - xp_r[2]) * coeff * inv_dt }; - - J_acc(Ip_i[0] + N_GHOSTS, - Ip_i[1] + N_GHOSTS, - Ip_i[2] + N_GHOSTS, + const auto dxp_r_3 { static_cast(i3(p) == i3_prev(p)) * + (dx3(p) + dx3_prev(p)) * + static_cast(INV_2) }; + const real_t Wx3_1 { INV_2 * (dxp_r_3 + dx3_prev(p) + + static_cast(i3(p) > i3_prev(p))) }; + const real_t Wx3_2 { INV_2 * (dx3(p) + dxp_r_3 + + static_cast( + static_cast(i3(p) > i3_prev(p)) + + i3_prev(p) - i3(p))) }; + const real_t Fx3_1 { (static_cast(i3(p) > i3_prev(p)) + + dxp_r_3 - dx3_prev(p)) * + coeff * inv_dt }; + const real_t Fx3_2 { (static_cast( + i3(p) - i3_prev(p) - + static_cast(i3(p) > i3_prev(p))) + + dx3(p) - dxp_r_3) * + coeff * inv_dt }; + + J_acc(i1_prev(p) + N_GHOSTS, + i2_prev(p) + N_GHOSTS, + i3_prev(p) + N_GHOSTS, cur::jx1) += Fx1_1 * (ONE - Wx2_1) * (ONE - Wx3_1); - J_acc(Ip_i[0] + N_GHOSTS, - Ip_i[1] + N_GHOSTS + 1, - Ip_i[2] + N_GHOSTS, + J_acc(i1_prev(p) + N_GHOSTS, + i2_prev(p) + N_GHOSTS + 1, + i3_prev(p) + N_GHOSTS, cur::jx1) += Fx1_1 * Wx2_1 * (ONE - Wx3_1); - J_acc(Ip_i[0] + N_GHOSTS, - Ip_i[1] + N_GHOSTS, - Ip_i[2] + N_GHOSTS + 1, + J_acc(i1_prev(p) + N_GHOSTS, + i2_prev(p) + N_GHOSTS, + i3_prev(p) + N_GHOSTS + 1, cur::jx1) += Fx1_1 * (ONE - Wx2_1) * Wx3_1; - J_acc(Ip_i[0] + N_GHOSTS, - Ip_i[1] + N_GHOSTS + 1, - Ip_i[2] + N_GHOSTS + 1, + J_acc(i1_prev(p) + N_GHOSTS, + i2_prev(p) + N_GHOSTS + 1, + i3_prev(p) + N_GHOSTS + 1, cur::jx1) += Fx1_1 * Wx2_1 * Wx3_1; - J_acc(Ip_f[0] + N_GHOSTS, - Ip_f[1] + N_GHOSTS, - Ip_f[2] + N_GHOSTS, + J_acc(i1(p) + N_GHOSTS, + i2(p) + N_GHOSTS, + i3(p) + N_GHOSTS, cur::jx1) += Fx1_2 * (ONE - Wx2_2) * (ONE - Wx3_2); - J_acc(Ip_f[0] + N_GHOSTS, - Ip_f[1] + N_GHOSTS + 1, - Ip_f[2] + N_GHOSTS, + J_acc(i1(p) + N_GHOSTS, + i2(p) + N_GHOSTS + 1, + i3(p) + N_GHOSTS, cur::jx1) += Fx1_2 * Wx2_2 * (ONE - Wx3_2); - J_acc(Ip_f[0] + N_GHOSTS, - Ip_f[1] + N_GHOSTS, - Ip_f[2] + N_GHOSTS + 1, + J_acc(i1(p) + N_GHOSTS, + i2(p) + N_GHOSTS, + i3(p) + N_GHOSTS + 1, cur::jx1) += Fx1_2 * (ONE - Wx2_2) * Wx3_2; - J_acc(Ip_f[0] + N_GHOSTS, - Ip_f[1] + N_GHOSTS + 1, - Ip_f[2] + N_GHOSTS + 1, + J_acc(i1(p) + N_GHOSTS, + i2(p) + N_GHOSTS + 1, + i3(p) + N_GHOSTS + 1, cur::jx1) += Fx1_2 * Wx2_2 * Wx3_2; - J_acc(Ip_i[0] + N_GHOSTS, - Ip_i[1] + N_GHOSTS, - Ip_i[2] + N_GHOSTS, + J_acc(i1_prev(p) + N_GHOSTS, + i2_prev(p) + N_GHOSTS, + i3_prev(p) + N_GHOSTS, cur::jx2) += Fx2_1 * (ONE - Wx1_1) * (ONE - Wx3_1); - J_acc(Ip_i[0] + N_GHOSTS + 1, - Ip_i[1] + N_GHOSTS, - Ip_i[2] + N_GHOSTS, + J_acc(i1_prev(p) + N_GHOSTS + 1, + i2_prev(p) + N_GHOSTS, + i3_prev(p) + N_GHOSTS, cur::jx2) += Fx2_1 * Wx1_1 * (ONE - Wx3_1); - J_acc(Ip_i[0] + N_GHOSTS, - Ip_i[1] + N_GHOSTS, - Ip_i[2] + N_GHOSTS + 1, + J_acc(i1_prev(p) + N_GHOSTS, + i2_prev(p) + N_GHOSTS, + i3_prev(p) + N_GHOSTS + 1, cur::jx2) += Fx2_1 * (ONE - Wx1_1) * Wx3_1; - J_acc(Ip_i[0] + N_GHOSTS + 1, - Ip_i[1] + N_GHOSTS, - Ip_i[2] + N_GHOSTS + 1, + J_acc(i1_prev(p) + N_GHOSTS + 1, + i2_prev(p) + N_GHOSTS, + i3_prev(p) + N_GHOSTS + 1, cur::jx2) += Fx2_1 * Wx1_1 * Wx3_1; - J_acc(Ip_f[0] + N_GHOSTS, - Ip_f[1] + N_GHOSTS, - Ip_f[2] + N_GHOSTS, + J_acc(i1(p) + N_GHOSTS, + i2(p) + N_GHOSTS, + i3(p) + N_GHOSTS, cur::jx2) += Fx2_2 * (ONE - Wx1_2) * (ONE - Wx3_2); - J_acc(Ip_f[0] + N_GHOSTS + 1, - Ip_f[1] + N_GHOSTS, - Ip_f[2] + N_GHOSTS, + J_acc(i1(p) + N_GHOSTS + 1, + i2(p) + N_GHOSTS, + i3(p) + N_GHOSTS, cur::jx2) += Fx2_2 * Wx1_2 * (ONE - Wx3_2); - J_acc(Ip_f[0] + N_GHOSTS, - Ip_f[1] + N_GHOSTS, - Ip_f[2] + N_GHOSTS + 1, + J_acc(i1(p) + N_GHOSTS, + i2(p) + N_GHOSTS, + i3(p) + N_GHOSTS + 1, cur::jx2) += Fx2_2 * (ONE - Wx1_2) * Wx3_2; - J_acc(Ip_f[0] + N_GHOSTS + 1, - Ip_f[1] + N_GHOSTS, - Ip_f[2] + N_GHOSTS + 1, + J_acc(i1(p) + N_GHOSTS + 1, + i2(p) + N_GHOSTS, + i3(p) + N_GHOSTS + 1, cur::jx2) += Fx2_2 * Wx1_2 * Wx3_2; - J_acc(Ip_i[0] + N_GHOSTS, - Ip_i[1] + N_GHOSTS, - Ip_i[2] + N_GHOSTS, + J_acc(i1_prev(p) + N_GHOSTS, + i2_prev(p) + N_GHOSTS, + i3_prev(p) + N_GHOSTS, cur::jx3) += Fx3_1 * (ONE - Wx1_1) * (ONE - Wx2_1); - J_acc(Ip_i[0] + N_GHOSTS + 1, - Ip_i[1] + N_GHOSTS, - Ip_i[2] + N_GHOSTS, + J_acc(i1_prev(p) + N_GHOSTS + 1, + i2_prev(p) + N_GHOSTS, + i3_prev(p) + N_GHOSTS, cur::jx3) += Fx3_1 * Wx1_1 * (ONE - Wx2_1); - J_acc(Ip_i[0] + N_GHOSTS, - Ip_i[1] + N_GHOSTS + 1, - Ip_i[2] + N_GHOSTS, + J_acc(i1_prev(p) + N_GHOSTS, + i2_prev(p) + N_GHOSTS + 1, + i3_prev(p) + N_GHOSTS, cur::jx3) += Fx3_1 * (ONE - Wx1_1) * Wx2_1; - J_acc(Ip_i[0] + N_GHOSTS + 1, - Ip_i[1] + N_GHOSTS + 1, - Ip_i[2] + N_GHOSTS, + J_acc(i1_prev(p) + N_GHOSTS + 1, + i2_prev(p) + N_GHOSTS + 1, + i3_prev(p) + N_GHOSTS, cur::jx3) += Fx3_1 * Wx1_1 * Wx2_1; - J_acc(Ip_f[0] + N_GHOSTS, - Ip_f[1] + N_GHOSTS, - Ip_f[2] + N_GHOSTS, + J_acc(i1(p) + N_GHOSTS, + i2(p) + N_GHOSTS, + i3(p) + N_GHOSTS, cur::jx3) += Fx3_2 * (ONE - Wx1_2) * (ONE - Wx2_2); - J_acc(Ip_f[0] + N_GHOSTS + 1, - Ip_f[1] + N_GHOSTS, - Ip_f[2] + N_GHOSTS, + J_acc(i1(p) + N_GHOSTS + 1, + i2(p) + N_GHOSTS, + i3(p) + N_GHOSTS, cur::jx3) += Fx3_2 * Wx1_2 * (ONE - Wx2_2); - J_acc(Ip_f[0] + N_GHOSTS, - Ip_f[1] + N_GHOSTS + 1, - Ip_f[2] + N_GHOSTS, + J_acc(i1(p) + N_GHOSTS, + i2(p) + N_GHOSTS + 1, + i3(p) + N_GHOSTS, cur::jx3) += Fx3_2 * (ONE - Wx1_2) * Wx2_2; - J_acc(Ip_f[0] + N_GHOSTS + 1, - Ip_f[1] + N_GHOSTS + 1, - Ip_f[2] + N_GHOSTS, + J_acc(i1(p) + N_GHOSTS + 1, + i2(p) + N_GHOSTS + 1, + i3(p) + N_GHOSTS, cur::jx3) += Fx3_2 * Wx1_2 * Wx2_2; } } } - - /** - * @brief Get particle position in `coord_t` form. - * @param[in] p Index of particle. - * @param[out] Ip_f Final position of the particle (cell index). - * @param[out] Ip_i Initial position of the particle (cell index). - * @param[out] xp_f Final position. - * @param[out] xp_i Previous step position. - * @param[out] xp_r Intermediate point used in zig-zag deposit. - */ - Inline auto getDepositInterval(index_t& p, - tuple_t& Ip_f, - tuple_t& Ip_i, - coord_t& xp_f, - coord_t& xp_i, - coord_t& xp_r) const -> void { - Ip_f[0] = i1(p); - Ip_i[0] = i1_prev(p); - xp_f[0] = i_di_to_Xi(Ip_f[0], dx1(p)); - xp_i[0] = i_di_to_Xi(Ip_i[0], dx1_prev(p)); - if constexpr (D == Dim::_2D || D == Dim::_3D) { - Ip_f[1] = i2(p); - Ip_i[1] = i2_prev(p); - xp_f[1] = i_di_to_Xi(Ip_f[1], dx2(p)); - xp_i[1] = i_di_to_Xi(Ip_i[1], dx2_prev(p)); - } - if constexpr (D == Dim::_3D) { - Ip_f[2] = i3(p); - Ip_i[2] = i3_prev(p); - xp_f[2] = i_di_to_Xi(Ip_f[2], dx3(p)); - xp_i[2] = i_di_to_Xi(Ip_i[2], dx3_prev(p)); - } - for (auto i = 0u; i < D; ++i) { - xp_r[i] = math::fmin(static_cast(IMIN(Ip_i[i], Ip_f[i]) + 1), - math::fmax(static_cast(IMAX(Ip_i[i], Ip_f[i])), - HALF * (xp_i[i] + xp_f[i]))); - } - } - - // Getters - Inline void getPrtlPos(index_t& p, coord_t& xp) const { - if constexpr (D == Dim::_1D) { - xp[0] = i_di_to_Xi(i1(p), dx1(p)); - } else if constexpr (D == Dim::_2D) { - if constexpr (M::PrtlDim == Dim::_3D) { - xp[0] = i_di_to_Xi(i1(p), dx1(p)); - xp[1] = i_di_to_Xi(i2(p), dx2(p)); - xp[2] = phi(p); - } else { - xp[0] = i_di_to_Xi(i1(p), dx1(p)); - xp[1] = i_di_to_Xi(i2(p), dx2(p)); - } - } else { - xp[0] = i_di_to_Xi(i1(p), dx1(p)); - xp[1] = i_di_to_Xi(i2(p), dx2(p)); - xp[2] = i_di_to_Xi(i3(p), dx3(p)); - } - } - - Inline void getPrtl3Vel(index_t& p, vec_t& vp) const { - coord_t xp { ZERO }; - getPrtlPos(p, xp); - auto inv_energy { ZERO }; - if constexpr (S == SimEngine::SRPIC) { - metric.template transform_xyz(xp, - { ux1(p), ux2(p), ux3(p) }, - vp); - inv_energy = ONE / math::sqrt(ONE + NORM_SQR(ux1(p), ux2(p), ux3(p))); - } else { - metric.template transform(xp, { ux1(p), ux2(p), ux3(p) }, vp); - inv_energy = ONE / math::sqrt(ONE + ux1(p) * vp[0] + ux2(p) * vp[1] + - ux3(p) * vp[2]); - } - if (Kokkos::isnan(vp[2]) || Kokkos::isinf(vp[2])) { - vp[2] = ZERO; - } - vp[0] *= inv_energy; - vp[1] *= inv_energy; - vp[2] *= inv_energy; - } }; } // namespace kernel From 9b1d03ed3624ab42c3eacb439b7f7be332daf7e2 Mon Sep 17 00:00:00 2001 From: gorbunove Date: Mon, 21 Apr 2025 09:25:03 -0500 Subject: [PATCH 635/773] 2D turb almost done --- setups/wip/turbulence/pgen.hpp | 145 ++++++++++++++++++-------- setups/wip/turbulence/turbulence.toml | 25 +++-- 2 files changed, 115 insertions(+), 55 deletions(-) diff --git a/setups/wip/turbulence/pgen.hpp b/setups/wip/turbulence/pgen.hpp index 14097e966..fc840fb24 100644 --- a/setups/wip/turbulence/pgen.hpp +++ b/setups/wip/turbulence/pgen.hpp @@ -15,7 +15,50 @@ namespace user { using namespace ntt; - + template + struct InitFields { + InitFields(array_t& k, array_t& a_real, array_t& a_imag, array_t& a_real_inv, array_t& a_imag_inv ) + : k { k } + , a_real { a_real } + , a_imag { a_imag } + , a_real_inv { a_real_inv } + , a_imag_inv { a_imag_inv } + , n_modes {a_real.size() } {}; + + Inline auto bx1(const coord_t& x_Ph) const -> real_t { + auto bx1_0 = ZERO; + for (auto i = 0; i < n_modes; i++){ + auto k_dot_r = k(0,i) * x_Ph[0] + k(1,i) * x_Ph[1]; + bx1_0 -= TWO * k(1,i) * (a_real(i) * math::sin(k_dot_r) + a_imag(i) * math::cos( k_dot_r )); + bx1_0 -= TWO * k(1,i) * (a_real_inv(i) * math::sin(k_dot_r) + a_imag_inv(i) * math::cos( k_dot_r )); + + } + return bx1_0; + } + + Inline auto bx2(const coord_t& x_Ph) const -> real_t { + auto bx2_0 = ZERO; + for (auto i = 0; i < n_modes; i++){ + auto k_dot_r = k(0,i) * x_Ph[0] + k(1,i) * x_Ph[1]; + bx2_0 += TWO * k(0,i) * (a_real(i) * math::sin(k_dot_r) + a_imag(i) * math::cos( k_dot_r )); + bx2_0 += TWO * k(0,i) * (a_real_inv(i) * math::sin(k_dot_r) + a_imag_inv(i) * math::cos( k_dot_r )); + + } + return bx2_0; + } + + Inline auto bx3(const coord_t& x_Ph) const -> real_t { + return ONE; + } + + array_t k; + array_t a_real; + array_t a_imag; + array_t a_real_inv; + array_t a_imag_inv; + size_t n_modes; + }; + //external current definition template struct ExternalCurrent{ @@ -33,8 +76,8 @@ namespace user { , u_real { "u_real", wavenumbers.size() } , a_real { "a_real", wavenumbers.size() } , a_imag { "a_imag", wavenumbers.size() } - , a_real_inv { "a_real", wavenumbers.size() } - , a_imag_inv { "a_imag", wavenumbers.size() } + , a_real_inv { "a_real_inv", wavenumbers.size() } + , a_imag_inv { "a_imag_inv", wavenumbers.size() } , A0 {"A0", wavenumbers.size()} { @@ -50,14 +93,19 @@ namespace user { // initializing initial complex amplitudes auto a_real_host = Kokkos::create_mirror_view(a_real); - auto a_imag_host = Kokkos::create_mirror_view(a_imag); + auto a_imag_host = Kokkos::create_mirror_view(a_imag); + auto a_real_inv_host = Kokkos::create_mirror_view(a_real_inv); + auto a_imag_inv_host = Kokkos::create_mirror_view(a_imag_inv); auto A0_host = Kokkos::create_mirror_view(A0); for (auto i = 0; i < n_modes; i++){ auto k_perp = math::sqrt(k_host(0,i) * k_host(0,i) + k_host(1,i) * k_host(1,i)); auto phase = constant::TWO_PI / 6.; - A0_host(i) = dB / math::sqrt((real_t) n_modes) / k_perp; + A0_host(i) = dB / math::sqrt((real_t) n_modes) / k_perp * HALF; //HALF = 1/sqrt(twice modes due to reality condition * twice the frequencies due to sign change) a_real_host(i) = A0_host(i) * math::cos(phase); a_imag_host(i) = A0_host(i) * math::sin(phase); + phase = constant::TWO_PI / 3; + a_imag_inv_host(i) = A0_host(i) * math::cos(phase); + a_real_inv_host(i) = A0_host(i) * math::sin(phase); printf("A0(%d) = %f\n", i,A0_host(i)); printf("a_real(%d) = %f\n", i,a_real_host(i)); printf("a_imag(%d) = %f\n", i,a_imag_host(i)); @@ -67,20 +115,10 @@ namespace user { Kokkos::deep_copy(a_real, a_real_host); Kokkos::deep_copy(a_imag, a_imag_host); - Kokkos::deep_copy(a_real_inv, a_real_host); - Kokkos::deep_copy(a_imag_inv, a_imag_host); - + Kokkos::deep_copy(a_real_inv, a_real_inv_host); + Kokkos::deep_copy(a_imag_inv, a_imag_inv_host); Kokkos::deep_copy(A0, A0_host); Kokkos::deep_copy(k, k_host); - // Kokkos::parallel_for( "Generate random ", wavenumbers.size(), Lambda (int const i){ - // auto generator = random_pool.get_state(); - // a_real(i) = generator.frand(0.0, 1.0); - // a_imag(i) = generator.frand(0.0, 1.0); - // printf(" Initial amplitudes (%i) a_real= %f, a_imag= %f\n",i - // , a_real(i) - // , a_imag(i)); - // random_pool.free_state(generator); - // }); }; @@ -91,9 +129,9 @@ namespace user { //k(i,0) + k(i,1); auto k_perp_sq = k(0,i) * k(0,i) + k(1,i) * k(1,i); auto k_dot_r = k(0,i) * x_Ph[0] + k(1,i) * x_Ph[1]; - jx3_ant -= TWO * k_perp_sq * (a_real(i) * math::cos(k_dot_r) + jx3_ant += TWO * k_perp_sq * (a_real(i) * math::cos(k_dot_r) - a_imag(i) * math::sin(k_dot_r)); - jx3_ant -= TWO * k_perp_sq * (a_real_inv(i) * math::cos(k_dot_r) + jx3_ant += TWO * k_perp_sq * (a_real_inv(i) * math::cos(k_dot_r) - a_imag_inv(i) * math::sin(k_dot_r)); } @@ -108,8 +146,6 @@ namespace user { } return jx3_ant; } -// printf("jz_ant = %f\n", jx3_ant); - } Inline auto jx2(const coord_t& x_Ph) const -> real_t { if constexpr(D == Dim::_2D){ @@ -160,8 +196,13 @@ namespace user { std::vector< std::vector > wavenumbers; random_number_pool_t random_pool; - + // debugging, will delete later + real_t total_sum = 0.0; + real_t total_sum_inv = 0.0; + real_t number_of_timesteps = 0.0; + ExternalCurrent ExternalCurrent; + InitFields init_flds; inline PGen(const SimulationParams& p, const Metadomain& global_domain) : arch::ProblemGenerator { p } @@ -178,7 +219,8 @@ namespace user { , Ly { global_domain.mesh().extent(in::x2).second - global_domain.mesh().extent(in::x2).first } , Lz { global_domain.mesh().extent(in::x3).second - global_domain.mesh().extent(in::x3).first } , dt { params.template get("algorithms.timestep.dt") } - , ExternalCurrent { dB, omega_0, gamma_0, wavenumbers, random_pool, Lx, Ly, Lz }{} + , ExternalCurrent { dB, omega_0, gamma_0, wavenumbers, random_pool, Lx, Ly, Lz } + , init_flds(ExternalCurrent.k, ExternalCurrent.a_real, ExternalCurrent.a_imag, ExternalCurrent.a_real_inv, ExternalCurrent.a_imag_inv) {} inline PGen() {} @@ -196,21 +238,10 @@ namespace user { spatial_dist, ONE); - } + }; void CustomPostStep(timestep_t, simtime_t time, Domain& domain){ - //generate white noise -// Kokkos::parallel_for( "Generate random ", wavenumbers.size(), ClassLambda (int const i){ -// auto generator = random_pool.get_state(); -// this->ExternalCurrent.u_real(i) = generator.frand(-0.5, 0.5); -// this->ExternalCurrent.u_imag(i) = generator.frand(-0.5, 0.5); -// printf(" %i) u_real= %f, u_imag= %f\n",i -// , this->ExternalCurrent.u_real(i) -// , this->ExternalCurrent.u_imag(i)); -// random_pool.free_state(generator); -// }); - // update amplitudes of antenna Kokkos::parallel_for( " Antenna amplitudes ", wavenumbers.size(), Lambda (int const i){ auto generator = random_pool.get_state(); @@ -224,27 +255,53 @@ namespace user { , u_real_inv , u_imag_inv); random_pool.free_state(generator); - random_pool.free_state(generator); auto a_real_prev = this->ExternalCurrent.a_real(i); auto a_imag_prev = this->ExternalCurrent.a_imag(i); auto a_real_inv_prev = this->ExternalCurrent.a_real_inv(i); auto a_imag_inv_prev = this->ExternalCurrent.a_imag_inv(i); - - printf(" %i) a_real= %f, a_imag= %f\n",i + auto dt = this->dt; + printf(" %i) a_real= %f, a_imag= %f, a_real_inv= %f, a_imag_inv=%f \n",i , this->ExternalCurrent.a_real(i) - , this->ExternalCurrent.a_imag(i)); - this->ExternalCurrent.a_real(i) = (a_real_prev * math::cos(this->ExternalCurrent.omega_0 * time) - a_imag_prev * math::sin(this->ExternalCurrent.omega_0 * time)) * math::exp(-this->ExternalCurrent.gamma_0 * time) + this->ExternalCurrent.A0(i) * math::sqrt(12.0 * this->ExternalCurrent.gamma_0 / this->dt ) * u_real * this->dt; + , this->ExternalCurrent.a_imag(i) + , this->ExternalCurrent.a_real_inv(i) + , this->ExternalCurrent.a_imag_inv(i)); + this->ExternalCurrent.a_real(i) = (a_real_prev * math::cos(this->ExternalCurrent.omega_0 * dt) + a_imag_prev * math::sin(this->ExternalCurrent.omega_0 * dt)) * math::exp(-this->ExternalCurrent.gamma_0 * dt) + this->ExternalCurrent.A0(i) * math::sqrt(12.0 * this->ExternalCurrent.gamma_0 / dt) * u_real * dt; - this->ExternalCurrent.a_imag(i) = (a_imag_prev * math::cos(this->ExternalCurrent.omega_0 * time) + a_real_prev * math::sin(this->ExternalCurrent.omega_0 * time)) * math::exp(-this->ExternalCurrent.gamma_0 * time) + this->ExternalCurrent.A0(i) * math::sqrt(12.0 * this->ExternalCurrent.gamma_0 / this->dt ) * u_imag * this->dt; + this->ExternalCurrent.a_imag(i) = (a_imag_prev * math::cos(this->ExternalCurrent.omega_0 * dt) - a_real_prev * math::sin(this->ExternalCurrent.omega_0 * dt)) * math::exp(-this->ExternalCurrent.gamma_0 * dt) + this->ExternalCurrent.A0(i) * math::sqrt(12.0 * this->ExternalCurrent.gamma_0 / dt) * u_imag * dt; - this->ExternalCurrent.a_real_inv(i) = (a_real_inv_prev * math::cos(-this->ExternalCurrent.omega_0 * time) - a_imag_inv_prev * math::sin(-this->ExternalCurrent.omega_0 * time)) * math::exp(-this->ExternalCurrent.gamma_0 * time) + this->ExternalCurrent.A0(i) * math::sqrt(12.0 * this->ExternalCurrent.gamma_0 / this->dt ) * u_real_inv * this->dt; + this->ExternalCurrent.a_real_inv(i) = (a_real_inv_prev * math::cos(-this->ExternalCurrent.omega_0 * dt) + a_imag_inv_prev * math::sin(-this->ExternalCurrent.omega_0 * dt)) * math::exp(-this->ExternalCurrent.gamma_0 * dt) + this->ExternalCurrent.A0(i) * math::sqrt(12.0 * this->ExternalCurrent.gamma_0 / dt) * u_real_inv * dt; - this->ExternalCurrent.a_imag_inv(i) = (a_imag_inv_prev * math::cos(-this->ExternalCurrent.omega_0 * time) + a_real_inv_prev * math::sin(-this->ExternalCurrent.omega_0 * time)) * math::exp(-this->ExternalCurrent.gamma_0 * time) + this->ExternalCurrent.A0(i) * math::sqrt(12.0 * this->ExternalCurrent.gamma_0 / this->dt ) * u_imag_inv * this->dt; + this->ExternalCurrent.a_imag_inv(i) = (a_imag_inv_prev * math::cos(-this->ExternalCurrent.omega_0 * dt) - a_real_inv_prev * math::sin(-this->ExternalCurrent.omega_0 * dt)) * math::exp(-this->ExternalCurrent.gamma_0 * dt) + this->ExternalCurrent.A0(i) * math::sqrt(12.0 * this->ExternalCurrent.gamma_0 / dt ) * u_imag_inv * dt; }); +// real_t sum = 0.0; +// // KOKKOS_LAMBDA macro includes capture-by-value specifier [=]. +// Kokkos::parallel_reduce ("Reduction", wavenumbers.size(), Lambda (const int i, real_t& update) { +// auto a_real = this->ExternalCurrent.a_real(i); +// auto a_imag = this->ExternalCurrent.a_imag(i); +// auto k_perp = this->ExternalCurrent.k(0,i)*this->ExternalCurrent.k(0,i) + this->ExternalCurrent.k(1,i)*this->ExternalCurrent.k(1,i); +// update += (a_real * a_real + a_imag * a_imag) ; +// }, sum); +// total_sum +=sum; +// number_of_timesteps +=1.0; +// printf(" = %f, ", sum); +// printf("total = %f\n", total_sum/number_of_timesteps); +// +// real_t sum_inv = 0.0; +// // KOKKOS_LAMBDA macro includes capture-by-value specifier [=]. +// Kokkos::parallel_reduce ("Reduction", wavenumbers.size(), Lambda (const int i, real_t& update) { +// auto a_real = this->ExternalCurrent.a_real_inv(i); +// auto a_imag = this->ExternalCurrent.a_imag_inv(i); +// auto k_perp = this->ExternalCurrent.k(0,i)*this->ExternalCurrent.k(0,i) + this->ExternalCurrent.k(1,i)*this->ExternalCurrent.k(1,i); +// update += (a_real * a_real + a_imag * a_imag) ; +// }, sum_inv); +// total_sum_inv +=sum_inv; +// printf(" = %f, ", sum_inv); +// printf("total = %f\n", total_sum_inv/number_of_timesteps); + + } }; - } // namespace user #endif diff --git a/setups/wip/turbulence/turbulence.toml b/setups/wip/turbulence/turbulence.toml index b66da04df..78a7b9172 100644 --- a/setups/wip/turbulence/turbulence.toml +++ b/setups/wip/turbulence/turbulence.toml @@ -1,11 +1,11 @@ [simulation] - name = "weibel" + name = "turbulence" engine = "srpic" - runtime = 100.0 + runtime = 1200.0 [grid] - resolution = [512, 512] - extent = [[-10.0, 10.0], [-10.0, 10.0]] + resolution = [2048, 2048] + extent = [[-128.0, 128.0], [-128.0, 128.0]] [grid.metric] metric = "minkowski" @@ -25,30 +25,33 @@ CFL = 0.5 [particles] - ppc0 = 16.0 + ppc0 = 32.0 [[particles.species]] label = "e-_p" mass = 1.0 charge = -1.0 - maxnpart = 1e7 + maxnpart = 8e7 [[particles.species]] label = "e+_p" mass = 1.0 charge = 1.0 - maxnpart = 1e7 + maxnpart = 8e7 [setup] - temperature = 1e-4 - dB = 1.0 + temperature = 1e0 + dB = 1.0 + omega_0 = 0.0156 + gamma_0 = 0.0078 + [output] format = "hdf5" - interval_time = 0.25 + interval_time = 12.0 [output.fields] - quantities = ["N_1_2", "J", "B", "E", "T0i_1", "T0i_3"] + quantities = ["N_1_2", "J", "B", "E"] [output.particles] enable = false From 67db7c4cd7f830471f8701c2dc8dbd3f1bd40dc1 Mon Sep 17 00:00:00 2001 From: gorbunove Date: Mon, 21 Apr 2025 09:28:02 -0500 Subject: [PATCH 636/773] 2D turb almost done --- src/global/global.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/global/global.h b/src/global/global.h index 5296d8ac7..18c73c32e 100644 --- a/src/global/global.h +++ b/src/global/global.h @@ -346,7 +346,7 @@ using duration_t = double; using simtime_t = double; using timestep_t = std::size_t; using ncells_t = std::size_t; -using npart_t = unsigned long long int; +using npart_t = unsigned long int; // index/number using index_t = const std::size_t; From d66c2b5ef730fc5b78b1909308f1b49dbff8e541 Mon Sep 17 00:00:00 2001 From: hayk Date: Mon, 21 Apr 2025 11:48:21 -0400 Subject: [PATCH 637/773] (RUNTEST) From 9bc0f2c66067badccd73625e310fc844b764280f Mon Sep 17 00:00:00 2001 From: hayk Date: Mon, 21 Apr 2025 11:54:17 -0400 Subject: [PATCH 638/773] minor bug in enum test (RUNTEST) --- src/global/tests/enums.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/global/tests/enums.cpp b/src/global/tests/enums.cpp index 9208ed8d3..1190417ef 100644 --- a/src/global/tests/enums.cpp +++ b/src/global/tests/enums.cpp @@ -71,8 +71,8 @@ auto main() -> int { "h", "j", "a", "t", "rho", "charge", "n", "nppc", "v", "custom" }; - enum_str_t all_out_stats = { "b^2", "e^2", "exb", "j.e", "t", - "rho", "charge", "n", "npart", "v" }; + enum_str_t all_out_stats = { "b^2", "e^2", "exb", "j.e", "t", + "rho", "charge", "n", "npart" }; checkEnum(all_coords); checkEnum(all_metrics); From 9c58aa4eafdfaf039b7cb0a79a3cb2957d79bfe0 Mon Sep 17 00:00:00 2001 From: hayk Date: Mon, 21 Apr 2025 11:58:45 -0400 Subject: [PATCH 639/773] accuracy in deposit test (RUNTEST) --- src/kernels/tests/deposit.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/kernels/tests/deposit.cpp b/src/kernels/tests/deposit.cpp index ec364a313..63d65a619 100644 --- a/src/kernels/tests/deposit.cpp +++ b/src/kernels/tests/deposit.cpp @@ -29,7 +29,8 @@ void errorIf(bool condition, const std::string& message) { inline static constexpr auto epsilon = std::numeric_limits::epsilon(); -Inline auto equal(real_t a, real_t b, const char* msg = "", real_t acc = ONE) -> bool { +Inline auto equal(real_t a, real_t b, const char* msg = "", real_t acc = ONE) + -> bool { const auto eps = epsilon * acc; if (not cmp::AlmostEqual(a, b, eps)) { printf("%.12e != %.12e %s\n", a, b, msg); @@ -176,7 +177,7 @@ auto main(int argc, char* argv[]) -> int { }, { { 0.0, 55.0 }, { 0.0, 55.0 } }, {}, - 30); + 100); testDeposit, SimEngine::SRPIC>( { @@ -185,7 +186,7 @@ auto main(int argc, char* argv[]) -> int { }, { { 1.0, 100.0 } }, {}, - 30); + 100); testDeposit, SimEngine::SRPIC>( { @@ -194,7 +195,7 @@ auto main(int argc, char* argv[]) -> int { }, { { 1.0, 100.0 } }, { { "r0", 0.0 }, { "h", 0.25 } }, - 30); + 100); testDeposit, SimEngine::GRPIC>( { @@ -203,7 +204,7 @@ auto main(int argc, char* argv[]) -> int { }, { { 1.0, 100.0 } }, { { "a", 0.9 } }, - 30); + 100); testDeposit, SimEngine::GRPIC>( { @@ -212,7 +213,7 @@ auto main(int argc, char* argv[]) -> int { }, { { 1.0, 100.0 } }, { { "r0", 0.0 }, { "h", 0.25 }, { "a", 0.9 } }, - 30); + 100); testDeposit, SimEngine::GRPIC>( { @@ -221,7 +222,7 @@ auto main(int argc, char* argv[]) -> int { }, { { 1.0, 100.0 } }, { { "a", 0.9 } }, - 30); + 100); } catch (std::exception& e) { std::cerr << e.what() << std::endl; From 479425489a01054d13aadff6927028d990a3dc47 Mon Sep 17 00:00:00 2001 From: hayk Date: Mon, 21 Apr 2025 13:27:48 -0400 Subject: [PATCH 640/773] long double -> simtime_t --- src/checkpoint/writer.cpp | 2 +- src/checkpoint/writer.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/checkpoint/writer.cpp b/src/checkpoint/writer.cpp index fe77d3b56..b8571c246 100644 --- a/src/checkpoint/writer.cpp +++ b/src/checkpoint/writer.cpp @@ -200,7 +200,7 @@ namespace checkpoint { m_writer.Put(var, &data); } - void Writer::saveAttrs(const ntt::SimulationParams& params, long double time) { + void Writer::saveAttrs(const ntt::SimulationParams& params, simtime_t time) { CallOnce([&]() { std::ofstream metadata; if (m_written.empty()) { diff --git a/src/checkpoint/writer.h b/src/checkpoint/writer.h index 992c54c96..91c9d7a41 100644 --- a/src/checkpoint/writer.h +++ b/src/checkpoint/writer.h @@ -54,7 +54,7 @@ namespace checkpoint { void beginSaving(timestep_t, simtime_t); void endSaving(); - void saveAttrs(const ntt::SimulationParams&, long double); + void saveAttrs(const ntt::SimulationParams&, simtime_t); template void savePerDomainVariable(const std::string&, std::size_t, std::size_t, T); From e1ae5989e1b1015d4e307b0cf38c3d0c61358486 Mon Sep 17 00:00:00 2001 From: hayk Date: Mon, 21 Apr 2025 13:28:23 -0400 Subject: [PATCH 641/773] acc in dep test --- src/kernels/tests/deposit.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/kernels/tests/deposit.cpp b/src/kernels/tests/deposit.cpp index 63d65a619..e6967eb14 100644 --- a/src/kernels/tests/deposit.cpp +++ b/src/kernels/tests/deposit.cpp @@ -177,7 +177,7 @@ auto main(int argc, char* argv[]) -> int { }, { { 0.0, 55.0 }, { 0.0, 55.0 } }, {}, - 100); + 500); testDeposit, SimEngine::SRPIC>( { @@ -186,7 +186,7 @@ auto main(int argc, char* argv[]) -> int { }, { { 1.0, 100.0 } }, {}, - 100); + 500); testDeposit, SimEngine::SRPIC>( { @@ -195,7 +195,7 @@ auto main(int argc, char* argv[]) -> int { }, { { 1.0, 100.0 } }, { { "r0", 0.0 }, { "h", 0.25 } }, - 100); + 500); testDeposit, SimEngine::GRPIC>( { @@ -204,7 +204,7 @@ auto main(int argc, char* argv[]) -> int { }, { { 1.0, 100.0 } }, { { "a", 0.9 } }, - 100); + 500); testDeposit, SimEngine::GRPIC>( { @@ -213,7 +213,7 @@ auto main(int argc, char* argv[]) -> int { }, { { 1.0, 100.0 } }, { { "r0", 0.0 }, { "h", 0.25 }, { "a", 0.9 } }, - 100); + 500); testDeposit, SimEngine::GRPIC>( { @@ -222,7 +222,7 @@ auto main(int argc, char* argv[]) -> int { }, { { 1.0, 100.0 } }, { { "a", 0.9 } }, - 100); + 500); } catch (std::exception& e) { std::cerr << e.what() << std::endl; From ab854542327fc0f6670256307c1e336852fda843 Mon Sep 17 00:00:00 2001 From: hayk Date: Mon, 21 Apr 2025 13:28:32 -0400 Subject: [PATCH 642/773] (RUNTEST) From f609fb236cacef34a6ae6451eeecf7dac6f2527a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20B=C3=B6ss?= Date: Mon, 21 Apr 2025 14:22:53 -0500 Subject: [PATCH 643/773] explicitly copying mpi buffers from GPU to CPU to solve GPU pinning issue on DeltaAI --- src/framework/domain/comm_mpi.hpp | 89 ++++++++++++++++++++++++------- 1 file changed, 69 insertions(+), 20 deletions(-) diff --git a/src/framework/domain/comm_mpi.hpp b/src/framework/domain/comm_mpi.hpp index fbeb7ecde..5e91fff98 100644 --- a/src/framework/domain/comm_mpi.hpp +++ b/src/framework/domain/comm_mpi.hpp @@ -186,34 +186,42 @@ namespace comm { } if (send_rank >= 0 && recv_rank >= 0) { - MPI_Sendrecv(send_fld.data(), + auto send_fld_h = Kokkos::create_mirror_view(send_fld); + auto recv_fld_h = Kokkos::create_mirror_view(recv_fld); + Kokkos::deep_copy(send_fld_h, send_fld); + MPI_Sendrecv(send_fld_h.data(), nsend, mpi::get_type(), send_rank, 0, - recv_fld.data(), + recv_fld_h.data(), nrecv, mpi::get_type(), recv_rank, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + Kokkos::deep_copy(recv_fld, recv_fld_h); } else if (send_rank >= 0) { - MPI_Send(send_fld.data(), + auto send_fld_h = Kokkos::create_mirror_view(send_fld); + Kokkos::deep_copy(send_fld_h, send_fld); + MPI_Send(send_fld_h.data(), nsend, mpi::get_type(), send_rank, 0, MPI_COMM_WORLD); - } else if (recv_rank >= 0) { - MPI_Recv(recv_fld.data(), + auto recv_fld_h = Kokkos::create_mirror_view(recv_fld); + Kokkos::deep_copy(recv_fld_h, recv_fld); + MPI_Recv(recv_fld_h.data(), nrecv, mpi::get_type(), recv_rank, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + Kokkos::deep_copy(recv_fld, recv_fld_h); } else { raise::Error("CommunicateField called with negative ranks", HERE); } @@ -404,77 +412,106 @@ namespace comm { recv_buff_int.extent(0), "incorrect # of recv particles", HERE); - MPI_Sendrecv(send_buff_int.data(), + auto send_buff_int_h = Kokkos::create_mirror_view(send_buff_int); + auto recv_buff_int_h = Kokkos::create_mirror_view(recv_buff_int); + Kokkos::deep_copy(send_buff_int_h, send_buff_int); + MPI_Sendrecv(send_buff_int_h.data(), npart_send_in * NINTS, mpi::get_type(), send_rank, 0, - recv_buff_int.data() + recv_offset_int, + recv_buff_int_h.data() + recv_offset_int, npart_recv_in * NINTS, mpi::get_type(), recv_rank, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE); - MPI_Sendrecv(send_buff_real.data(), + Kokkos::deep_copy(recv_buff_int, recv_buff_int_h); + + auto send_buff_real_h = Kokkos::create_mirror_view(send_buff_real); + auto recv_buff_real_h = Kokkos::create_mirror_view(recv_buff_real); + Kokkos::deep_copy(send_buff_real_h, send_buff_real); + MPI_Sendrecv(send_buff_real_h.data(), npart_send_in * NREALS, mpi::get_type(), send_rank, 0, - recv_buff_real.data() + recv_offset_real, + recv_buff_real_h.data() + recv_offset_real, npart_recv_in * NREALS, mpi::get_type(), recv_rank, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE); - MPI_Sendrecv(send_buff_prtldx.data(), + Kokkos::deep_copy(recv_buff_real, recv_buff_real_h); + + auto send_buff_prtldx_h = Kokkos::create_mirror_view(send_buff_prtldx); + auto recv_buff_prtldx_h = Kokkos::create_mirror_view(recv_buff_prtldx); + Kokkos::deep_copy(send_buff_prtldx_h, send_buff_prtldx); + MPI_Sendrecv(send_buff_prtldx_h.data(), npart_send_in * NPRTLDX, mpi::get_type(), send_rank, 0, - recv_buff_prtldx.data() + recv_offset_prtldx, + recv_buff_prtldx_h.data() + recv_offset_prtldx, npart_recv_in * NPRTLDX, mpi::get_type(), recv_rank, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + Kokkos::deep_copy(recv_buff_prtldx, recv_buff_prtldx_h); + if (NPLDS > 0) { - MPI_Sendrecv(send_buff_pld.data(), + auto send_buff_pld_h = Kokkos::create_mirror_view(send_buff_pld); + auto recv_buff_pld_h = Kokkos::create_mirror_view(recv_buff_pld); + Kokkos::deep_copy(send_buff_pld_h, send_buff_pld); + MPI_Sendrecv(send_buff_pld_h.data(), npart_send_in * NPLDS, mpi::get_type(), send_rank, 0, - recv_buff_pld.data() + recv_offset_pld, + recv_buff_pld_h.data() + recv_offset_pld, npart_recv_in * NPLDS, mpi::get_type(), recv_rank, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + Kokkos::deep_copy(recv_buff_pld, recv_buff_pld_h); } } else if ((send_rank >= 0) and (npart_send_in > 0)) { - MPI_Send(send_buff_int.data(), + auto send_buff_int_h = Kokkos::create_mirror_view(send_buff_int); + Kokkos::deep_copy(send_buff_int_h, send_buff_int); + MPI_Send(send_buff_int_h.data(), npart_send_in * NINTS, mpi::get_type(), send_rank, 0, MPI_COMM_WORLD); + + auto send_buff_real_h = Kokkos::create_mirror_view(send_buff_real); + Kokkos::deep_copy(send_buff_real_h, send_buff_real); MPI_Send(send_buff_real.data(), npart_send_in * NREALS, mpi::get_type(), send_rank, 0, MPI_COMM_WORLD); - MPI_Send(send_buff_prtldx.data(), + + auto send_buff_prtldx_h = Kokkos::create_mirror_view(send_buff_prtldx); + Kokkos::deep_copy(send_buff_prtldx_h, send_buff_prtldx); + MPI_Send(send_buff_prtldx_h.data(), npart_send_in * NPRTLDX, mpi::get_type(), send_rank, 0, MPI_COMM_WORLD); if (NPLDS > 0) { - MPI_Send(send_buff_pld.data(), + auto send_buff_pld_h = Kokkos::create_mirror_view(send_buff_pld); + Kokkos::deep_copy(send_buff_pld_h, send_buff_pld); + MPI_Send(send_buff_pld_h.data(), npart_send_in * NPLDS, mpi::get_type(), send_rank, @@ -486,35 +523,47 @@ namespace comm { recv_buff_int.extent(0), "incorrect # of recv particles", HERE); - MPI_Recv(recv_buff_int.data() + recv_offset_int, + + auto recv_buff_int_h = Kokkos::create_mirror_view(recv_buff_int); + MPI_Recv(recv_buff_int_h.data() + recv_offset_int, npart_recv_in * NINTS, mpi::get_type(), recv_rank, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE); - MPI_Recv(recv_buff_real.data() + recv_offset_real, + Kokkos::deep_copy(recv_buff_int, recv_buff_int_h); + + auto recv_buff_real_h = Kokkos::create_mirror_view(recv_buff_real); + MPI_Recv(recv_buff_real_h.data() + recv_offset_real, npart_recv_in * NREALS, mpi::get_type(), recv_rank, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE); - MPI_Recv(recv_buff_prtldx.data() + recv_offset_prtldx, + Kokkos::deep_copy(recv_buff_real, recv_buff_real_h); + + auto recv_buff_prtldx_h = Kokkos::create_mirror_view(recv_buff_prtldx); + MPI_Recv(recv_buff_prtldx_h.data() + recv_offset_prtldx, npart_recv_in * NPRTLDX, mpi::get_type(), recv_rank, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + Kokkos::deep_copy(recv_buff_prtldx, recv_buff_prtldx_h); + if (NPLDS > 0) { - MPI_Recv(recv_buff_pld.data() + recv_offset_pld, + auto rrecv_buff_pld_h = Kokkos::create_mirror_view(recv_buff_pld); + MPI_Recv(rrecv_buff_pld_h.data() + recv_offset_pld, npart_recv_in * NPLDS, mpi::get_type(), recv_rank, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE); + Kokkos::deep_copy(recv_buff_pld, rrecv_buff_pld_h); } } current_received += npart_recv_in; From d9a2e7f45e163fdef9f620a9bf45954cf8289cca Mon Sep 17 00:00:00 2001 From: gorbunove Date: Mon, 21 Apr 2025 17:12:31 -0500 Subject: [PATCH 644/773] turb done fully --- setups/wip/turbulence/pgen.hpp | 107 ++++++++++++++++++++------ setups/wip/turbulence/turbulence.toml | 8 +- 2 files changed, 87 insertions(+), 28 deletions(-) diff --git a/setups/wip/turbulence/pgen.hpp b/setups/wip/turbulence/pgen.hpp index fc840fb24..cbd281905 100644 --- a/setups/wip/turbulence/pgen.hpp +++ b/setups/wip/turbulence/pgen.hpp @@ -13,8 +13,14 @@ #include "framework/domain/domain.h" #include "framework/domain/metadomain.h" +#if defined(MPI_ENABLED) +#include +#endif //MPI_ENABLED + namespace user { using namespace ntt; + + // initializing guide field and curl(B) = J_ext at the initial time step template struct InitFields { InitFields(array_t& k, array_t& a_real, array_t& a_imag, array_t& a_real_inv, array_t& a_imag_inv ) @@ -71,36 +77,49 @@ namespace user { , Lx { Lx } , Ly { Ly } , Lz { Lz } - , k { "wavevector", 2, wavenumbers.size() } + , k { "wavevector", D, wavenumbers.size() } , u_imag { "u imaginary", wavenumbers.size() } , u_real { "u_real", wavenumbers.size() } , a_real { "a_real", wavenumbers.size() } , a_imag { "a_imag", wavenumbers.size() } , a_real_inv { "a_real_inv", wavenumbers.size() } , a_imag_inv { "a_imag_inv", wavenumbers.size() } - , A0 {"A0", wavenumbers.size()} { // initializing wavevectors auto k_host = Kokkos::create_mirror_view(k); - for (auto i = 0; i < n_modes; i++){ - for(size_t j = 0; j < 2; j++){ - k_host(j,i) = constant::TWO_PI * wavenumbers[i][j] / Lx; + if constexpr(D == Dim::_2D){ + for (auto i = 0; i < n_modes; i++){ + k_host(0,i) = constant::TWO_PI * wavenumbers[i][0] / Lx; + k_host(1,i) = constant::TWO_PI * wavenumbers[i][1] / Ly; + printf("k(%d) = (%f, %f)\n", i,k_host(0,i), k_host(1,i)); + } + } + if constexpr(D == Dim::_3D){ + for (auto i = 0; i < n_modes; i++){ + k_host(0,i) = constant::TWO_PI * wavenumbers[i][0] / Lx; + k_host(1,i) = constant::TWO_PI * wavenumbers[i][1] / Ly; + k_host(2,i) = constant::TWO_PI * wavenumbers[i][2] / Lz; + printf("k(%d) = (%f, %f, %f)\n", i,k_host(0,i), k_host(1,i), k_host(2,i)); } - printf("k(%d) = (%f, %f)\n", i,k_host(0,i), k_host(1,i)); } - - // initializing initial complex amplitudes auto a_real_host = Kokkos::create_mirror_view(a_real); auto a_imag_host = Kokkos::create_mirror_view(a_imag); auto a_real_inv_host = Kokkos::create_mirror_view(a_real_inv); auto a_imag_inv_host = Kokkos::create_mirror_view(a_imag_inv); - auto A0_host = Kokkos::create_mirror_view(A0); + auto A0_host = Kokkos::create_mirror_view(A0); + real_t prefac; + if constexpr(D == Dim::_2D){ + real_t prefac = HALF; //HALF = 1/sqrt(twice modes due to reality condition * twice the frequencies due to sign change) + } + if constexpr(D == Dim::_3D){ + real_t prefac = ONE/math::sqrt(TWO); //1/sqrt(2) = 1/sqrt(twice modes due to reality condition) + } for (auto i = 0; i < n_modes; i++){ auto k_perp = math::sqrt(k_host(0,i) * k_host(0,i) + k_host(1,i) * k_host(1,i)); auto phase = constant::TWO_PI / 6.; - A0_host(i) = dB / math::sqrt((real_t) n_modes) / k_perp * HALF; //HALF = 1/sqrt(twice modes due to reality condition * twice the frequencies due to sign change) + A0_host(i) = dB / math::sqrt((real_t) n_modes) / k_perp * prefac; a_real_host(i) = A0_host(i) * math::cos(phase); a_imag_host(i) = A0_host(i) * math::sin(phase); phase = constant::TWO_PI / 3; @@ -126,7 +145,6 @@ namespace user { if constexpr(D == Dim::_2D){ real_t jx3_ant = ZERO; for (size_t i=0; i < n_modes; i++){ - //k(i,0) + k(i,1); auto k_perp_sq = k(0,i) * k(0,i) + k(1,i) * k(1,i); auto k_dot_r = k(0,i) * x_Ph[0] + k(1,i) * x_Ph[1]; jx3_ant += TWO * k_perp_sq * (a_real(i) * math::cos(k_dot_r) @@ -140,9 +158,10 @@ namespace user { if constexpr(D == Dim::_3D){ real_t jx3_ant = ZERO; for (size_t i=0; i < n_modes; i++){ -// k_perp_sq = k[i][0] + k[i][1]; -// jx3_ant -= TWO * k_perp_sq * (ONE * math::cos(k[i][0] * x_Ph[0] + k[i][1] * x_Ph[1] + k[i][2] * x_Ph[2]) -// + ONE * math::sin(k[i][0] * x_Ph[0] + k[i][1] * x_Ph[1] + k[i][2] * x_Ph[2])); + auto k_perp_sq = k(0,i) * k(0,i) + k(1,i) * k(1,i); + auto k_dot_r = k(0,i) * x_Ph[0] + k(1,i) * x_Ph[1] + k(2,i) * x_Ph[2]; + jx3_ant += TWO * k_perp_sq * (a_real_inv(i) * math::cos(k_dot_r) + - a_imag_inv(i) * math::sin(k_dot_r)); } return jx3_ant; } @@ -152,7 +171,14 @@ namespace user { return ZERO; } if constexpr(D == Dim::_3D){ - return ZERO; + real_t jx2_ant = ZERO; + for (size_t i = 0; i < n_modes; i++){ + auto k_dot_r = k(0,i) * x_Ph[0] + k(1,i) * x_Ph[1] + k(2,i) * x_Ph[2]; + jx2_ant -= TWO * k(1,i) * k(2,i) * (a_real_inv(i) * math::cos(k_dot_r) + - a_imag_inv(i) * math::sin(k_dot_r)); + + } + return jx2_ant; } } Inline auto jx1(const coord_t& x_Ph) const -> real_t { @@ -160,7 +186,14 @@ namespace user { return ZERO; } if constexpr(D == Dim::_3D){ - return ZERO; + real_t jx1_ant = ZERO; + for (size_t i = 0; i < n_modes; i++){ + auto k_dot_r = k(0,i) * x_Ph[0] + k(1,i) * x_Ph[1] + k(2,i) * x_Ph[2]; + jx1_ant -= TWO * k(0,i) * k(2,i) * (a_real_inv(i) * math::cos(k_dot_r) + - a_imag_inv(i) * math::sin(k_dot_r)); + + } + return jx1_ant; } } @@ -193,6 +226,7 @@ namespace user { using arch::ProblemGenerator::params; const real_t temperature, dB, omega_0, gamma_0, Lx, Ly, Lz, dt; + const int random_seed; std::vector< std::vector > wavenumbers; random_number_pool_t random_pool; @@ -204,23 +238,46 @@ namespace user { ExternalCurrent ExternalCurrent; InitFields init_flds; + inline static std::vector> init_wavenumbers(){ + if constexpr( D == Dim::_2D){ + return { { 1, 0 }, { 0, 1 }, { 1, 1 }, { -1, 1 } }; + } + if constexpr (D== Dim::_3D){ + return { { 1, 0, 1 }, { 0, 1, 1 }, { -1, 0, 1 }, { 0, -1, 1 } }; + + } + } + + inline static unsigned int init_pool(const int seed) { + if (seed == -1){ +#if defined(MPI_ENABLED) + unsigned int new_seed = rand(); + MPI_Bcast(&new_seed, 1, MPI_UNSIGNED, MPI_ROOT_RANK, MPI_COMM_WORLD); + return new_seed; +#else + return {}; +#endif //MPI_ENABLED + } + else{ + return seed; + } + } + inline PGen(const SimulationParams& p, const Metadomain& global_domain) : arch::ProblemGenerator { p } , temperature { p.template get("setup.temperature") } , dB { p.template get("setup.dB", 1.) } - , omega_0 { p.template get("setup.omega_0", 0.5) } - , gamma_0 { p.template get("setup.gamma_0", 0.25) } - , wavenumbers { { { 1, 0, 1 }, - { 0, 1, 1 }, - { 1, 1, 1 }, - { -1, 1, 1 }} } - , random_pool{ 0 } + , omega_0 { p.template get("setup.omega_0") } + , gamma_0 { p.template get("setup.gamma_0") } + , wavenumbers { init_wavenumbers() } + , random_seed { p.template get("setup.seed", -1) } + , random_pool { init_pool(random_seed) } , Lx { global_domain.mesh().extent(in::x1).second - global_domain.mesh().extent(in::x1).first } , Ly { global_domain.mesh().extent(in::x2).second - global_domain.mesh().extent(in::x2).first } , Lz { global_domain.mesh().extent(in::x3).second - global_domain.mesh().extent(in::x3).first } , dt { params.template get("algorithms.timestep.dt") } - , ExternalCurrent { dB, omega_0, gamma_0, wavenumbers, random_pool, Lx, Ly, Lz } - , init_flds(ExternalCurrent.k, ExternalCurrent.a_real, ExternalCurrent.a_imag, ExternalCurrent.a_real_inv, ExternalCurrent.a_imag_inv) {} + , ExternalCurrent { dB, omega_0, gamma_0, wavenumbers, random_pool, Lx, Ly, Lz } + , init_flds(ExternalCurrent.k, ExternalCurrent.a_real, ExternalCurrent.a_imag, ExternalCurrent.a_real_inv, ExternalCurrent.a_imag_inv) {}; inline PGen() {} diff --git a/setups/wip/turbulence/turbulence.toml b/setups/wip/turbulence/turbulence.toml index 78a7b9172..79cc641ef 100644 --- a/setups/wip/turbulence/turbulence.toml +++ b/setups/wip/turbulence/turbulence.toml @@ -4,7 +4,7 @@ runtime = 1200.0 [grid] - resolution = [2048, 2048] + resolution = [1024, 1024] extent = [[-128.0, 128.0], [-128.0, 128.0]] [grid.metric] @@ -31,13 +31,13 @@ label = "e-_p" mass = 1.0 charge = -1.0 - maxnpart = 8e7 + maxnpart = 2e7 [[particles.species]] label = "e+_p" mass = 1.0 charge = 1.0 - maxnpart = 8e7 + maxnpart = 2e7 [setup] temperature = 1e0 @@ -58,6 +58,8 @@ [output.spectra] enable = false + [output.stats] + enable = false [diagnostics] colored_stdout = true From d64dceebeb5069d9754c921c368695348ad502c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20B=C3=B6ss?= Date: Mon, 21 Apr 2025 18:41:09 -0500 Subject: [PATCH 645/773] bugfix --- src/framework/domain/comm_mpi.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/framework/domain/comm_mpi.hpp b/src/framework/domain/comm_mpi.hpp index 5e91fff98..a2b248dc3 100644 --- a/src/framework/domain/comm_mpi.hpp +++ b/src/framework/domain/comm_mpi.hpp @@ -213,7 +213,6 @@ namespace comm { MPI_COMM_WORLD); } else if (recv_rank >= 0) { auto recv_fld_h = Kokkos::create_mirror_view(recv_fld); - Kokkos::deep_copy(recv_fld_h, recv_fld); MPI_Recv(recv_fld_h.data(), nrecv, mpi::get_type(), From ead3c51875695c5476f93fbbfa0c566012c7f9d1 Mon Sep 17 00:00:00 2001 From: gorbunove Date: Tue, 22 Apr 2025 09:55:14 -0500 Subject: [PATCH 646/773] ExternalCurrent rename to ext_current --- setups/wip/turbulence/pgen.hpp | 30 +++++++++++++++--------------- src/engines/srpic.hpp | 2 +- src/global/arch/traits.h | 2 +- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/setups/wip/turbulence/pgen.hpp b/setups/wip/turbulence/pgen.hpp index cbd281905..f467d8388 100644 --- a/setups/wip/turbulence/pgen.hpp +++ b/setups/wip/turbulence/pgen.hpp @@ -235,7 +235,7 @@ namespace user { real_t total_sum_inv = 0.0; real_t number_of_timesteps = 0.0; - ExternalCurrent ExternalCurrent; + ExternalCurrent ext_current; InitFields init_flds; inline static std::vector> init_wavenumbers(){ @@ -276,8 +276,8 @@ namespace user { , Ly { global_domain.mesh().extent(in::x2).second - global_domain.mesh().extent(in::x2).first } , Lz { global_domain.mesh().extent(in::x3).second - global_domain.mesh().extent(in::x3).first } , dt { params.template get("algorithms.timestep.dt") } - , ExternalCurrent { dB, omega_0, gamma_0, wavenumbers, random_pool, Lx, Ly, Lz } - , init_flds(ExternalCurrent.k, ExternalCurrent.a_real, ExternalCurrent.a_imag, ExternalCurrent.a_real_inv, ExternalCurrent.a_imag_inv) {}; + , ext_current { dB, omega_0, gamma_0, wavenumbers, random_pool, Lx, Ly, Lz } + , init_flds(ext_current.k, ext_current.a_real, ext_current.a_imag, ext_current.a_real_inv, ext_current.a_imag_inv) {}; inline PGen() {} @@ -312,23 +312,23 @@ namespace user { , u_real_inv , u_imag_inv); random_pool.free_state(generator); - auto a_real_prev = this->ExternalCurrent.a_real(i); - auto a_imag_prev = this->ExternalCurrent.a_imag(i); - auto a_real_inv_prev = this->ExternalCurrent.a_real_inv(i); - auto a_imag_inv_prev = this->ExternalCurrent.a_imag_inv(i); + auto a_real_prev = this->ext_current.a_real(i); + auto a_imag_prev = this->ext_current.a_imag(i); + auto a_real_inv_prev = this->ext_current.a_real_inv(i); + auto a_imag_inv_prev = this->ext_current.a_imag_inv(i); auto dt = this->dt; printf(" %i) a_real= %f, a_imag= %f, a_real_inv= %f, a_imag_inv=%f \n",i - , this->ExternalCurrent.a_real(i) - , this->ExternalCurrent.a_imag(i) - , this->ExternalCurrent.a_real_inv(i) - , this->ExternalCurrent.a_imag_inv(i)); - this->ExternalCurrent.a_real(i) = (a_real_prev * math::cos(this->ExternalCurrent.omega_0 * dt) + a_imag_prev * math::sin(this->ExternalCurrent.omega_0 * dt)) * math::exp(-this->ExternalCurrent.gamma_0 * dt) + this->ExternalCurrent.A0(i) * math::sqrt(12.0 * this->ExternalCurrent.gamma_0 / dt) * u_real * dt; + , this->ext_current.a_real(i) + , this->ext_current.a_imag(i) + , this->ext_current.a_real_inv(i) + , this->ext_current.a_imag_inv(i)); + this->ext_current.a_real(i) = (a_real_prev * math::cos(this->ext_current.omega_0 * dt) + a_imag_prev * math::sin(this->ext_current.omega_0 * dt)) * math::exp(-this->ext_current.gamma_0 * dt) + this->ext_current.A0(i) * math::sqrt(12.0 * this->ext_current.gamma_0 / dt) * u_real * dt; - this->ExternalCurrent.a_imag(i) = (a_imag_prev * math::cos(this->ExternalCurrent.omega_0 * dt) - a_real_prev * math::sin(this->ExternalCurrent.omega_0 * dt)) * math::exp(-this->ExternalCurrent.gamma_0 * dt) + this->ExternalCurrent.A0(i) * math::sqrt(12.0 * this->ExternalCurrent.gamma_0 / dt) * u_imag * dt; + this->ext_current.a_imag(i) = (a_imag_prev * math::cos(this->ext_current.omega_0 * dt) - a_real_prev * math::sin(this->ext_current.omega_0 * dt)) * math::exp(-this->ext_current.gamma_0 * dt) + this->ext_current.A0(i) * math::sqrt(12.0 * this->ext_current.gamma_0 / dt) * u_imag * dt; - this->ExternalCurrent.a_real_inv(i) = (a_real_inv_prev * math::cos(-this->ExternalCurrent.omega_0 * dt) + a_imag_inv_prev * math::sin(-this->ExternalCurrent.omega_0 * dt)) * math::exp(-this->ExternalCurrent.gamma_0 * dt) + this->ExternalCurrent.A0(i) * math::sqrt(12.0 * this->ExternalCurrent.gamma_0 / dt) * u_real_inv * dt; + this->ext_current.a_real_inv(i) = (a_real_inv_prev * math::cos(-this->ext_current.omega_0 * dt) + a_imag_inv_prev * math::sin(-this->ext_current.omega_0 * dt)) * math::exp(-this->ext_current.gamma_0 * dt) + this->ext_current.A0(i) * math::sqrt(12.0 * this->ext_current.gamma_0 / dt) * u_real_inv * dt; - this->ExternalCurrent.a_imag_inv(i) = (a_imag_inv_prev * math::cos(-this->ExternalCurrent.omega_0 * dt) - a_real_inv_prev * math::sin(-this->ExternalCurrent.omega_0 * dt)) * math::exp(-this->ExternalCurrent.gamma_0 * dt) + this->ExternalCurrent.A0(i) * math::sqrt(12.0 * this->ExternalCurrent.gamma_0 / dt ) * u_imag_inv * dt; + this->ext_current.a_imag_inv(i) = (a_imag_inv_prev * math::cos(-this->ext_current.omega_0 * dt) - a_real_inv_prev * math::sin(-this->ext_current.omega_0 * dt)) * math::exp(-this->ext_current.gamma_0 * dt) + this->ext_current.A0(i) * math::sqrt(12.0 * this->ext_current.gamma_0 / dt ) * u_imag_inv * dt; }); // real_t sum = 0.0; diff --git a/src/engines/srpic.hpp b/src/engines/srpic.hpp index a10070c34..e9e51ab0b 100644 --- a/src/engines/srpic.hpp +++ b/src/engines/srpic.hpp @@ -535,7 +535,7 @@ namespace ntt { const std::vector xmin { domain.mesh.extent(in::x1).first, domain.mesh.extent(in::x2).first, domain.mesh.extent(in::x3).first }; - const auto ext_current = m_pgen.ExternalCurrent; + const auto ext_current = m_pgen.ext_current; const auto dx = domain.mesh.metric.template sqrt_h_<1, 1>({}); // clang-format off Kokkos::parallel_for( diff --git a/src/global/arch/traits.h b/src/global/arch/traits.h index d086d41bc..6d6c51f73 100644 --- a/src/global/arch/traits.h +++ b/src/global/arch/traits.h @@ -99,7 +99,7 @@ namespace traits { using ext_force_t = decltype(&T::ext_force); template - using ext_current_t = decltype(&T::ExternalCurrent); + using ext_current_t = decltype(&T::ext_current); template using atm_fields_t = decltype(&T::AtmFields); From d5cdbd9656b3d114b4715a4e5f89d1a95fbeaa5c Mon Sep 17 00:00:00 2001 From: hayk Date: Tue, 22 Apr 2025 17:16:49 -0400 Subject: [PATCH 647/773] proper comm test --- src/framework/tests/comm_mpi.cpp | 237 +++++++++++++++++++++++++---- src/framework/tests/comm_nompi.cpp | 10 +- 2 files changed, 216 insertions(+), 31 deletions(-) diff --git a/src/framework/tests/comm_mpi.cpp b/src/framework/tests/comm_mpi.cpp index 5d2c8d4f0..487976f73 100644 --- a/src/framework/tests/comm_mpi.cpp +++ b/src/framework/tests/comm_mpi.cpp @@ -5,6 +5,11 @@ #include "arch/directions.h" #include "arch/kokkos_aliases.h" +#include "utils/error.h" +#include "utils/numeric.h" + +#include +#include #include #include @@ -13,49 +18,227 @@ using namespace ntt; auto main(int argc, char* argv[]) -> int { Kokkos::initialize(argc, argv); + MPI_Init(&argc, &argv); try { - const ncells_t nx1 = 15, nx2 = 15; - ndfield_t fld_b1 { "fld", nx1 + 2 * N_GHOSTS, nx2 + 2 * N_GHOSTS }; - ndfield_t fld_b2 { "fld", nx1 + 2 * N_GHOSTS, nx2 + 2 * N_GHOSTS }; + int rank, size; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Comm_size(MPI_COMM_WORLD, &size); + + const ncells_t nx1 = 11, nx2 = 15; + ndfield_t fld { "fld", nx1 + 2 * N_GHOSTS, nx2 + 2 * N_GHOSTS }; Kokkos::parallel_for( "Fill", CreateRangePolicy({ 0, 0 }, { nx1 + 2 * N_GHOSTS, nx2 + 2 * N_GHOSTS }), Lambda(index_t i1, index_t i2) { - if ((i1 >= 2 * N_GHOSTS) and (i1 < nx1) and (i2 >= 2 * N_GHOSTS) and - (i2 < nx2)) { - fld_b1(i1, i2, 0) = 4.0; - fld_b1(i1, i2, 1) = 12.0; - fld_b1(i1, i2, 2) = 20.0; - fld_b2(i1, i2, 0) = 4.0; - fld_b2(i1, i2, 1) = 12.0; - fld_b2(i1, i2, 2) = 20.0; - } else if ( - ((i1 < 2 * N_GHOSTS or i1 >= nx1) and (i2 >= 2 * N_GHOSTS and i2 < nx2)) or - ((i2 < 2 * N_GHOSTS or i2 >= nx2) and (i1 >= 2 * N_GHOSTS and i1 < nx1))) { - fld_b1(i1, i2, 0) = 2.0; - fld_b1(i1, i2, 1) = 6.0; - fld_b1(i1, i2, 2) = 10.0; - fld_b2(i1, i2, 0) = 2.0; - fld_b2(i1, i2, 1) = 6.0; - fld_b2(i1, i2, 2) = 10.0; - } else { - fld_b1(i1, i2, 0) = 1.0; - fld_b1(i1, i2, 1) = 3.0; - fld_b1(i1, i2, 2) = 5.0; - fld_b2(i1, i2, 0) = 1.0; - fld_b2(i1, i2, 1) = 3.0; - fld_b2(i1, i2, 2) = 5.0; + if ((i1 >= N_GHOSTS) and (i1 < N_GHOSTS + nx1) and (i2 >= N_GHOSTS) and + (i2 < N_GHOSTS + nx2)) { + fld(i1, i2, 0) = static_cast(rank + 1) + 4.0; + fld(i1, i2, 1) = static_cast(rank + 1) + 12.0; + fld(i1, i2, 2) = static_cast(rank + 1) + 20.0; + } + }); + + { + // send right, recv left + const int send_idx = (rank + 1) % size; + const int recv_idx = (rank - 1 + size) % size; + const unsigned int send_rank = (unsigned int)send_idx; + const unsigned int recv_rank = (unsigned int)recv_idx; + + const std::vector send_slice { + { nx1, nx1 + N_GHOSTS }, + { N_GHOSTS, nx2 + N_GHOSTS } + }; + const std::vector recv_slice { + { 0, N_GHOSTS }, + { N_GHOSTS, nx2 + N_GHOSTS } + }; + const range_tuple_t comp_slice { 0, 3 }; + comm::CommunicateField((unsigned int)(rank), + fld, + fld, + send_idx, + recv_idx, + send_rank, + recv_rank, + send_slice, + recv_slice, + comp_slice, + false); + } + { + // recv right, send left + const int send_idx = (rank - 1 + size) % size; + const int recv_idx = (rank + 1) % size; + const unsigned int send_rank = (unsigned int)send_idx; + const unsigned int recv_rank = (unsigned int)recv_idx; + + const std::vector send_slice { + { N_GHOSTS, N_GHOSTS + 2 }, + { N_GHOSTS, nx2 + N_GHOSTS } + }; + const std::vector recv_slice { + { nx1 + N_GHOSTS, nx1 + 2 * N_GHOSTS }, + { N_GHOSTS, nx2 + N_GHOSTS } + }; + const range_tuple_t comp_slice { 0, 3 }; + comm::CommunicateField((unsigned int)(rank), + fld, + fld, + send_idx, + recv_idx, + send_rank, + recv_rank, + send_slice, + recv_slice, + comp_slice, + false); + } + + { + const auto left_expect = static_cast((rank - 1 + size) % size + 1); + const auto right_expect = static_cast((rank + 1) % size + 1); + + Kokkos::parallel_for( + "Check", + CreateRangePolicy({ N_GHOSTS }, { nx2 + N_GHOSTS }), + Lambda(index_t i2) { + for (auto i1 { 0u }; i1 < N_GHOSTS; ++i1) { + if (fld(i1, i2, 0) != left_expect + 4.0) { + raise::KernelError(HERE, "Left boundary not correct for #0"); + } + if (fld(i1, i2, 1) != left_expect + 12.0) { + raise::KernelError(HERE, "Left boundary not correct for #1"); + } + if (fld(i1, i2, 2) != left_expect + 20.0) { + raise::KernelError(HERE, "Left boundary not correct for #2"); + } + } + for (auto i1 { nx1 + N_GHOSTS }; i1 < nx1 + 2 * N_GHOSTS; ++i1) { + if (fld(i1, i2, 0) != right_expect + 4.0) { + raise::KernelError(HERE, "Right boundary not correct for #0"); + } + if (fld(i1, i2, 1) != right_expect + 12.0) { + raise::KernelError(HERE, "Right boundary not correct for #1"); + } + if (fld(i1, i2, 2) != right_expect + 20.0) { + raise::KernelError(HERE, "Right boundary not correct for #2"); + } + } + }); + } + + Kokkos::parallel_for( + "Carve", + CreateRangePolicy({ 0, 0 }, + { nx1 + 2 * N_GHOSTS, nx2 + 2 * N_GHOSTS }), + Lambda(index_t i1, index_t i2) { + if (((i1 >= N_GHOSTS) and (i1 < 2 * N_GHOSTS)) or + ((i1 >= nx1) and (i1 < nx1 + N_GHOSTS))) { + fld(i1, i2, 0) = ZERO; + fld(i1, i2, 1) = ZERO; + fld(i1, i2, 2) = ZERO; } }); + + { + // send right, recv left + const int send_idx = (rank + 1) % size; + const int recv_idx = (rank - 1 + size) % size; + const unsigned int send_rank = (unsigned int)send_idx; + const unsigned int recv_rank = (unsigned int)recv_idx; + + const std::vector send_slice { + { nx1 + N_GHOSTS, nx1 + 2 * N_GHOSTS }, + { N_GHOSTS, nx2 + N_GHOSTS } + }; + const std::vector recv_slice { + { N_GHOSTS, 2 * N_GHOSTS }, + { N_GHOSTS, nx2 + N_GHOSTS } + }; + const range_tuple_t comp_slice { 0, 3 }; + comm::CommunicateField((unsigned int)(rank), + fld, + fld, + send_idx, + recv_idx, + send_rank, + recv_rank, + send_slice, + recv_slice, + comp_slice, + true); + } + { + // recv right, send left + const int send_idx = (rank - 1 + size) % size; + const int recv_idx = (rank + 1) % size; + const unsigned int send_rank = (unsigned int)send_idx; + const unsigned int recv_rank = (unsigned int)recv_idx; + + const std::vector send_slice { + { 0, N_GHOSTS }, + { N_GHOSTS, nx2 + N_GHOSTS } + }; + const std::vector recv_slice { + { nx1, nx1 + N_GHOSTS }, + { N_GHOSTS, nx2 + N_GHOSTS } + }; + const range_tuple_t comp_slice { 0, 3 }; + comm::CommunicateField((unsigned int)(rank), + fld, + fld, + send_idx, + recv_idx, + send_rank, + recv_rank, + send_slice, + recv_slice, + comp_slice, + true); + } + + { + const auto expect = static_cast(rank + 1); + Kokkos::parallel_for( + "Check", + CreateRangePolicy({ N_GHOSTS }, { nx2 + N_GHOSTS }), + Lambda(index_t i2) { + for (auto i1 { N_GHOSTS }; i1 < 2 * N_GHOSTS; ++i1) { + if (fld(i1, i2, 0) != expect + 4.0) { + raise::KernelError(HERE, "Left boundary not correct for #0"); + } + if (fld(i1, i2, 1) != expect + 12.0) { + raise::KernelError(HERE, "Left boundary not correct for #1"); + } + if (fld(i1, i2, 2) != expect + 20.0) { + raise::KernelError(HERE, "Left boundary not correct for #2"); + } + } + for (auto i1 { nx1 }; i1 < nx1 + N_GHOSTS; ++i1) { + if (fld(i1, i2, 0) != expect + 4.0) { + raise::KernelError(HERE, "Right boundary not correct for #0"); + } + if (fld(i1, i2, 1) != expect + 12.0) { + raise::KernelError(HERE, "Right boundary not correct for #1"); + } + if (fld(i1, i2, 2) != expect + 20.0) { + raise::KernelError(HERE, "Right boundary not correct for #2"); + } + } + }); + } } catch (std::exception& e) { std::cerr << "Exception: " << e.what() << std::endl; + MPI_Finalize(); Kokkos::finalize(); return 1; } + MPI_Finalize(); Kokkos::finalize(); return 0; } diff --git a/src/framework/tests/comm_nompi.cpp b/src/framework/tests/comm_nompi.cpp index 05d54d589..f9581c1e1 100644 --- a/src/framework/tests/comm_nompi.cpp +++ b/src/framework/tests/comm_nompi.cpp @@ -7,6 +7,8 @@ #include "arch/kokkos_aliases.h" #include "utils/numeric.h" +#include "framework/domain/comm_mpi.hpp" + #include #include @@ -45,12 +47,12 @@ auto main(int argc, char* argv[]) -> int { Kokkos::deep_copy(buff, ZERO); const auto send_slice = std::vector { - {nx1 + N_GHOSTS, nx1 + 2 * N_GHOSTS}, - {nx2 + N_GHOSTS, nx2 + 2 * N_GHOSTS} + { nx1 + N_GHOSTS, nx1 + 2 * N_GHOSTS }, + { nx2 + N_GHOSTS, nx2 + 2 * N_GHOSTS } }; const auto recv_slice = std::vector { - {N_GHOSTS, 2 * N_GHOSTS}, - {N_GHOSTS, 2 * N_GHOSTS} + { N_GHOSTS, 2 * N_GHOSTS }, + { N_GHOSTS, 2 * N_GHOSTS } }; const auto comp_slice = range_tuple_t(cur::jx1, cur::jx3 + 1); From 9b262e3c4b0c5a4a41a2fe58cebf193bfdebb1d4 Mon Sep 17 00:00:00 2001 From: hayk Date: Wed, 23 Apr 2025 09:47:28 -0400 Subject: [PATCH 648/773] deptest fixed --- setups/tests/deposit/pgen.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setups/tests/deposit/pgen.hpp b/setups/tests/deposit/pgen.hpp index 1be4deb69..dc1bd6380 100644 --- a/setups/tests/deposit/pgen.hpp +++ b/setups/tests/deposit/pgen.hpp @@ -93,8 +93,8 @@ namespace user { data_2["phi"] = phi2s; } - arch::InjectGlobally(global_domain, local_domain, (arch::spidx_t)1, data_1); - arch::InjectGlobally(global_domain, local_domain, (arch::spidx_t)2, data_2); + arch::InjectGlobally(global_domain, local_domain, (spidx_t)1, data_1); + arch::InjectGlobally(global_domain, local_domain, (spidx_t)2, data_2); } }; From 5602adff1b7bff2ae19d761b04412bb6c06f6e60 Mon Sep 17 00:00:00 2001 From: hayk Date: Wed, 23 Apr 2025 14:30:09 -0400 Subject: [PATCH 649/773] turb --- setups/srpic/turbulence/pgen.hpp | 343 -------------- setups/srpic/turbulence/turbulence.toml | 49 -- setups/wip/turbulence/pgen.hpp | 569 ++++++++++++------------ src/global/utils/numeric.h | 2 + 4 files changed, 290 insertions(+), 673 deletions(-) delete mode 100644 setups/srpic/turbulence/pgen.hpp delete mode 100644 setups/srpic/turbulence/turbulence.toml diff --git a/setups/srpic/turbulence/pgen.hpp b/setups/srpic/turbulence/pgen.hpp deleted file mode 100644 index 874369306..000000000 --- a/setups/srpic/turbulence/pgen.hpp +++ /dev/null @@ -1,343 +0,0 @@ -#ifndef PROBLEM_GENERATOR_H -#define PROBLEM_GENERATOR_H - -#include "enums.h" -#include "global.h" - -#include "arch/kokkos_aliases.h" -#include "arch/traits.h" -#include "utils/numeric.h" - -#include "archetypes/energy_dist.h" -#include "archetypes/particle_injector.h" -#include "archetypes/problem_generator.h" -#include "framework/domain/metadomain.h" - -#include -#include - -enum { - REAL = 0, - IMAG = 1 -}; - -namespace user { - using namespace ntt; - - template - struct ExtForce { - ExtForce(array_t amplitudes, real_t SX1, real_t SX2, real_t SX3) - : amps { amplitudes } - , sx1 { SX1 } - , sx2 { SX2 } - , sx3 { SX3 } {} - - const std::vector species { 1, 2 }; - - ExtForce() = default; - - Inline auto fx1(const spidx_t&, const simtime_t&, const coord_t& x_Ph) const - -> real_t { - real_t k01 = ONE * constant::TWO_PI / sx1; - real_t k02 = ZERO * constant::TWO_PI / sx2; - real_t k03 = ZERO * constant::TWO_PI / sx3; - real_t k04 = ONE; - real_t k11 = ZERO * constant::TWO_PI / sx1; - real_t k12 = ONE * constant::TWO_PI / sx2; - real_t k13 = ZERO * constant::TWO_PI / sx3; - real_t k14 = ONE; - real_t k21 = ZERO * constant::TWO_PI / sx1; - real_t k22 = ZERO * constant::TWO_PI / sx2; - real_t k23 = ONE * constant::TWO_PI / sx3; - real_t k24 = ONE; - - // return 0.1 * cos(2.0 * constant::TWO_PI * x_Ph[1]); - - return (k14 * amps(0, REAL) * - math::cos(k11 * x_Ph[0] + k12 * x_Ph[1] + k13 * x_Ph[2]) + - k14 * amps(0, IMAG) * - math::sin(k11 * x_Ph[0] + k12 * x_Ph[1] + k13 * x_Ph[2])) + - (k24 * amps(1, REAL) * - math::cos(k21 * x_Ph[0] + k22 * x_Ph[1] + k23 * x_Ph[2]) + - k24 * amps(1, IMAG) * - math::sin(k21 * x_Ph[0] + k22 * x_Ph[1] + k23 * x_Ph[2])); - } - - Inline auto fx2(const spidx_t&, const simtime_t&, const coord_t& x_Ph) const - -> real_t { - real_t k01 = ONE * constant::TWO_PI / sx1; - real_t k02 = ZERO * constant::TWO_PI / sx2; - real_t k03 = ZERO * constant::TWO_PI / sx3; - real_t k04 = ONE; - real_t k11 = ZERO * constant::TWO_PI / sx1; - real_t k12 = ONE * constant::TWO_PI / sx2; - real_t k13 = ZERO * constant::TWO_PI / sx3; - real_t k14 = ONE; - real_t k21 = ZERO * constant::TWO_PI / sx1; - real_t k22 = ZERO * constant::TWO_PI / sx2; - real_t k23 = ONE * constant::TWO_PI / sx3; - real_t k24 = ONE; - return (k04 * amps(2, REAL) * - math::cos(k01 * x_Ph[0] + k02 * x_Ph[1] + k03 * x_Ph[2]) + - k04 * amps(2, IMAG) * - math::sin(k01 * x_Ph[0] + k02 * x_Ph[1] + k03 * x_Ph[2])) + - (k24 * amps(3, REAL) * - math::cos(k21 * x_Ph[0] + k22 * x_Ph[1] + k23 * x_Ph[2]) + - k24 * amps(3, IMAG) * - math::sin(k21 * x_Ph[0] + k22 * x_Ph[1] + k23 * x_Ph[2])); - // return ZERO; - } - - Inline auto fx3(const spidx_t&, const simtime_t&, const coord_t& x_Ph) const - -> real_t { - real_t k01 = ONE * constant::TWO_PI / sx1; - real_t k02 = ZERO * constant::TWO_PI / sx2; - real_t k03 = ZERO * constant::TWO_PI / sx3; - real_t k04 = ONE; - real_t k11 = ZERO * constant::TWO_PI / sx1; - real_t k12 = ONE * constant::TWO_PI / sx2; - real_t k13 = ZERO * constant::TWO_PI / sx3; - real_t k14 = ONE; - real_t k21 = ZERO * constant::TWO_PI / sx1; - real_t k22 = ZERO * constant::TWO_PI / sx2; - real_t k23 = ONE * constant::TWO_PI / sx3; - real_t k24 = ONE; - return (k04 * amps(4, REAL) * - math::cos(k01 * x_Ph[0] + k02 * x_Ph[1] + k03 * x_Ph[2]) + - k04 * amps(4, IMAG) * - math::sin(k01 * x_Ph[0] + k02 * x_Ph[1] + k03 * x_Ph[2])) + - (k14 * amps(5, REAL) * - math::cos(k11 * x_Ph[0] + k12 * x_Ph[1] + k13 * x_Ph[2]) + - k14 * amps(5, IMAG) * - math::sin(k11 * x_Ph[0] + k12 * x_Ph[1] + k13 * x_Ph[2])); - // return ZERO; - } - - private: - array_t amps; - const real_t sx1, sx2, sx3; - }; - - template - struct PGen : public arch::ProblemGenerator { - // compatibility traits for the problem generator - static constexpr auto engines = traits::compatible_with::value; - static constexpr auto metrics = traits::compatible_with::value; - static constexpr auto dimensions = traits::compatible_with::value; - - // for easy access to variables in the child class - using arch::ProblemGenerator::D; - using arch::ProblemGenerator::C; - using arch::ProblemGenerator::params; - - const real_t SX1, SX2, SX3; - const real_t temperature, machno; - const unsigned int nmodes; - const real_t amp0, phi0; - array_t amplitudes; - ExtForce ext_force; - const real_t dt; - - inline PGen(const SimulationParams& params, const Metadomain& global_domain) - : arch::ProblemGenerator { params } - , SX1 { global_domain.mesh().extent(in::x1).second - - global_domain.mesh().extent(in::x1).first } - , SX2 { global_domain.mesh().extent(in::x2).second - - global_domain.mesh().extent(in::x2).first } - , SX3 { global_domain.mesh().extent(in::x3).second - - global_domain.mesh().extent(in::x3).first } // , SX1 { 2.0 } - // , SX2 { 2.0 } - // , SX3 { 2.0 } - , temperature { params.template get("problem.temperature", 0.1) } - , machno { params.template get("problem.machno", 0.1) } - , nmodes { params.template get("setup.nmodes", 6) } - , amp0 { machno * temperature / static_cast(nmodes) } - , phi0 { INV_4 } // !TODO: randomize - , amplitudes { "DrivingModes", nmodes } - , ext_force { amplitudes, SX1, SX2, SX3 } - , dt { params.template get("algorithms.timestep.dt") } { - Init(); - } - - void Init() { - // initializing amplitudes - auto amplitudes_ = amplitudes; - const auto amp0_ = amp0; - const auto phi0_ = phi0; - Kokkos::parallel_for( - "RandomAmplitudes", - amplitudes.extent(0), - Lambda(index_t i) { - amplitudes_(i, REAL) = amp0_ * math::cos(phi0_); - amplitudes_(i, IMAG) = amp0_ * math::sin(phi0_); - }); - } - - inline void InitPrtls(Domain& local_domain) { - { - const auto energy_dist = arch::Maxwellian(local_domain.mesh.metric, - local_domain.random_pool, - temperature); - const auto injector = arch::UniformInjector( - energy_dist, - { 1, 2 }); - const real_t ndens = 0.9; - arch::InjectUniform(params, - local_domain, - injector, - ndens); - } - - { - const auto energy_dist = arch::PowerlawDist(local_domain.mesh.metric, - local_domain.random_pool, - 0.1, - 100.0, - -3.0); - const auto injector = arch::UniformInjector( - energy_dist, - { 1, 2 }); - const real_t ndens = 0.1; - arch::InjectUniform(params, - local_domain, - injector, - ndens); - } - } - - void CustomPostStep(std::size_t time, long double, Domain& domain) { - auto omega0 = 0.6 * math::sqrt(temperature * machno * constant::TWO_PI / SX1); - auto gamma0 = 0.5 * math::sqrt(temperature * machno * constant::TWO_PI / SX2); - auto sigma0 = amp0 * math::sqrt(static_cast(nmodes) * gamma0); - auto pool = domain.random_pool; - Kokkos::parallel_for( - "RandomAmplitudes", - amplitudes.extent(0), - ClassLambda(index_t i) { - auto rand_gen = pool.get_state(); - const auto unr = Random(rand_gen) - HALF; - const auto uni = Random(rand_gen) - HALF; - pool.free_state(rand_gen); - const auto ampr_prev = amplitudes(i, REAL); - const auto ampi_prev = amplitudes(i, IMAG); - amplitudes(i, REAL) = (ampr_prev * math::cos(omega0 * dt) + - ampi_prev * math::sin(omega0 * dt)) * - math::exp(-gamma0 * dt) + - unr * sigma0; - amplitudes(i, IMAG) = (-ampr_prev * math::sin(omega0 * dt) + - ampi_prev * math::cos(omega0 * dt)) * - math::exp(-gamma0 * dt) + - uni * sigma0; - }); - - // auto fext_en_total = ZERO; - // for (auto& species : domain.species) { - // auto pld = species.pld[0]; - // auto weight = species.weight; - // Kokkos::parallel_reduce( - // "ExtForceEnrg", - // species.rangeActiveParticles(), - // ClassLambda(index_t p, real_t & fext_en) { - // fext_en += pld(p) * weight(p); - // }, - // fext_en_total); - // } - - // auto pkin_en_total = ZERO; - // for (auto& species : domain.species) { - // auto ux1 = species.ux1; - // auto ux2 = species.ux2; - // auto ux3 = species.ux3; - // auto weight = species.weight; - // Kokkos::parallel_reduce( - // "KinEnrg", - // species.rangeActiveParticles(), - // ClassLambda(index_t p, real_t & pkin_en) { - // pkin_en += (math::sqrt(ONE + SQR(ux1(p)) + SQR(ux2(p)) + SQR(ux3(p))) - - // ONE) * - // weight(p); - // }, - // pkin_en_total); - // } - // // Weight the macroparticle integral by sim parameters - // pkin_en_total /= params.template get("scales.n0"); - - // std::ofstream myfile; - // if (time == 0) { - // myfile.open("fextenrg.txt"); - // } else { - // myfile.open("fextenrg.txt", std::ios_base::app); - // } - // myfile << fext_en_total << std::endl; - // myfile.close(); - - // if (time == 0) { - // myfile.open("kenrg.txt"); - // } else { - // myfile.open("kenrg.txt", std::ios_base::app); - // } - // myfile << pkin_en_total << std::endl; - // myfile.close(); - - // if constexpr (D == Dim::_3D) { - - // auto metric = domain.mesh.metric; - - // auto benrg_total = ZERO; - // auto EB = domain.fields.em; - // Kokkos::parallel_reduce( - // "BEnrg", - // domain.mesh.rangeActiveCells(), - // Lambda(index_t i1, index_t i2, index_t i3, real_t & benrg) { - // coord_t x_Cd { ZERO }; - // vec_t b_Cntrv { EB(i1, i2, i3, em::bx1), - // EB(i1, i2, i3, em::bx2), - // EB(i1, i2, i3, em::bx3) }; - // vec_t b_XYZ; - // metric.template transform(x_Cd, - // b_Cntrv, - // b_XYZ); - // benrg += (SQR(b_XYZ[0]) + SQR(b_XYZ[1]) + SQR(b_XYZ[2])); - // }, - // benrg_total); - // benrg_total *= params.template get("scales.sigma0") * HALF; - - // if (time == 0) { - // myfile.open("bsqenrg.txt"); - // } else { - // myfile.open("bsqenrg.txt", std::ios_base::app); - // } - // myfile << benrg_total << std::endl; - // myfile.close(); - // auto eenrg_total = ZERO; - // Kokkos::parallel_reduce( - // "BEnrg", - // domain.mesh.rangeActiveCells(), - // Lambda(index_t i1, index_t i2, index_t i3, real_t & eenrg) { - // coord_t x_Cd { ZERO }; - // vec_t e_Cntrv { EB(i1, i2, i3, em::ex1), - // EB(i1, i2, i3, em::ex2), - // EB(i1, i2, i3, em::ex3) }; - // vec_t e_XYZ; - // metric.template transform(x_Cd, - // e_Cntrv, - // e_XYZ); - // eenrg += (SQR(e_XYZ[0]) + SQR(e_XYZ[1]) + SQR(e_XYZ[2])); - // }, - // eenrg_total); - // eenrg_total *= params.template get("scales.sigma0") * HALF; - - // if (time == 0) { - // myfile.open("esqenrg.txt"); - // } else { - // myfile.open("esqenrg.txt", std::ios_base::app); - // } - // myfile << eenrg_total << std::endl; - // myfile.close(); - // } - } - }; - -} // namespace user - -#endif diff --git a/setups/srpic/turbulence/turbulence.toml b/setups/srpic/turbulence/turbulence.toml deleted file mode 100644 index a1f8e29c1..000000000 --- a/setups/srpic/turbulence/turbulence.toml +++ /dev/null @@ -1,49 +0,0 @@ -[simulation] - name = "turbulence" - engine = "srpic" - runtime = 20.0 - -[grid] - resolution = [184, 184, 184] - extent = [[-1.0, 1.0], [-1.0, 1.0], [-1.0, 1.0]] - - [grid.metric] - metric = "minkowski" - - [grid.boundaries] - fields = [["PERIODIC"], ["PERIODIC"], ["PERIODIC"]] - particles = [["PERIODIC"], ["PERIODIC"], ["PERIODIC"]] - -[scales] - larmor0 = 0.02 - skindepth0 = 0.02 - -[algorithms] - current_filters = 4 - - [algorithms.timestep] - CFL = 0.5 - -[particles] - ppc0 = 32.0 - - [[particles.species]] - label = "e-" - mass = 1.0 - charge = -1.0 - maxnpart = 1e8 - - [[particles.species]] - label = "e+" - mass = 1.0 - charge = 1.0 - maxnpart = 1e8 - -[setup] - -[output] - format = "hdf5" - interval_time = 0.1 - - [output.fields] - quantities = ["N_1", "N_2", "E", "B", "J", "T00_1", "T00_2"] diff --git a/setups/wip/turbulence/pgen.hpp b/setups/wip/turbulence/pgen.hpp index f467d8388..b14842768 100644 --- a/setups/wip/turbulence/pgen.hpp +++ b/setups/wip/turbulence/pgen.hpp @@ -5,7 +5,8 @@ #include "global.h" #include "arch/kokkos_aliases.h" -#include "arch/traits.h" +#include "utils/error.h" +#include "utils/numeric.h" #include "archetypes/energy_dist.h" #include "archetypes/particle_injector.h" @@ -14,8 +15,8 @@ #include "framework/domain/metadomain.h" #if defined(MPI_ENABLED) -#include -#endif //MPI_ENABLED + #include +#endif // MPI_ENABLED namespace user { using namespace ntt; @@ -23,192 +24,234 @@ namespace user { // initializing guide field and curl(B) = J_ext at the initial time step template struct InitFields { - InitFields(array_t& k, array_t& a_real, array_t& a_imag, array_t& a_real_inv, array_t& a_imag_inv ) - : k { k } - , a_real { a_real } - , a_imag { a_imag } - , a_real_inv { a_real_inv } - , a_imag_inv { a_imag_inv } - , n_modes {a_real.size() } {}; + InitFields(array_t& k, + array_t& a_real, + array_t& a_imag, + array_t& a_real_inv, + array_t& a_imag_inv) + : k { k } + , a_real { a_real } + , a_imag { a_imag } + , a_real_inv { a_real_inv } + , a_imag_inv { a_imag_inv } + , n_modes { a_real.size() } {}; Inline auto bx1(const coord_t& x_Ph) const -> real_t { auto bx1_0 = ZERO; - for (auto i = 0; i < n_modes; i++){ - auto k_dot_r = k(0,i) * x_Ph[0] + k(1,i) * x_Ph[1]; - bx1_0 -= TWO * k(1,i) * (a_real(i) * math::sin(k_dot_r) + a_imag(i) * math::cos( k_dot_r )); - bx1_0 -= TWO * k(1,i) * (a_real_inv(i) * math::sin(k_dot_r) + a_imag_inv(i) * math::cos( k_dot_r )); - + for (auto i = 0; i < n_modes; i++) { + auto k_dot_r = k(0, i) * x_Ph[0] + k(1, i) * x_Ph[1]; + bx1_0 -= TWO * k(1, i) * + (a_real(i) * math::sin(k_dot_r) + a_imag(i) * math::cos(k_dot_r)); + bx1_0 -= TWO * k(1, i) * + (a_real_inv(i) * math::sin(k_dot_r) + + a_imag_inv(i) * math::cos(k_dot_r)); } return bx1_0; } - + Inline auto bx2(const coord_t& x_Ph) const -> real_t { auto bx2_0 = ZERO; - for (auto i = 0; i < n_modes; i++){ - auto k_dot_r = k(0,i) * x_Ph[0] + k(1,i) * x_Ph[1]; - bx2_0 += TWO * k(0,i) * (a_real(i) * math::sin(k_dot_r) + a_imag(i) * math::cos( k_dot_r )); - bx2_0 += TWO * k(0,i) * (a_real_inv(i) * math::sin(k_dot_r) + a_imag_inv(i) * math::cos( k_dot_r )); - + for (auto i = 0; i < n_modes; i++) { + auto k_dot_r = k(0, i) * x_Ph[0] + k(1, i) * x_Ph[1]; + bx2_0 += TWO * k(0, i) * + (a_real(i) * math::sin(k_dot_r) + a_imag(i) * math::cos(k_dot_r)); + bx2_0 += TWO * k(0, i) * + (a_real_inv(i) * math::sin(k_dot_r) + + a_imag_inv(i) * math::cos(k_dot_r)); } return bx2_0; } - Inline auto bx3(const coord_t& x_Ph) const -> real_t { + Inline auto bx3(const coord_t&) const -> real_t { return ONE; } array_t k; - array_t a_real; - array_t a_imag; - array_t a_real_inv; - array_t a_imag_inv; - size_t n_modes; + array_t a_real; + array_t a_imag; + array_t a_real_inv; + array_t a_imag_inv; + std::size_t n_modes; }; - - //external current definition + + inline auto init_pool(int seed) -> unsigned int { + if (seed < 0) { + unsigned int new_seed = static_cast(rand()); +#if defined(MPI_ENABLED) + MPI_Bcast(&new_seed, 1, MPI_UNSIGNED, MPI_ROOT_RANK, MPI_COMM_WORLD); +#endif // MPI_ENABLED + return new_seed; + } else { + return static_cast(seed); + } + } + + template + inline auto init_wavenumbers() -> std::vector> { + if constexpr (D == Dim::_2D) { + return { + { 1, 0 }, + { 0, 1 }, + { 1, 1 }, + { -1, 1 } + }; + } else if constexpr (D == Dim::_3D) { + return { + { 1, 0, 1 }, + { 0, 1, 1 }, + { -1, 0, 1 }, + { 0, -1, 1 } + }; + } else { + raise::Error("Invalid dimension", HERE); + return {}; + } + } + + // external current definition template - struct ExternalCurrent{ - ExternalCurrent(real_t dB, real_t om0, real_t g0, std::vector< std::vector >& wavenumbers, random_number_pool_t& random_pool, real_t Lx, real_t Ly, real_t Lz) - : dB { dB } - , omega_0 { om0 } - , gamma_0 { g0 } - , wavenumbers { wavenumbers } - , n_modes {wavenumbers.size()} - , Lx { Lx } - , Ly { Ly } - , Lz { Lz } - , k { "wavevector", D, wavenumbers.size() } - , u_imag { "u imaginary", wavenumbers.size() } - , u_real { "u_real", wavenumbers.size() } - , a_real { "a_real", wavenumbers.size() } - , a_imag { "a_imag", wavenumbers.size() } - , a_real_inv { "a_real_inv", wavenumbers.size() } - , a_imag_inv { "a_imag_inv", wavenumbers.size() } - , A0 {"A0", wavenumbers.size()} - { - // initializing wavevectors - auto k_host = Kokkos::create_mirror_view(k); - if constexpr(D == Dim::_2D){ - for (auto i = 0; i < n_modes; i++){ - k_host(0,i) = constant::TWO_PI * wavenumbers[i][0] / Lx; - k_host(1,i) = constant::TWO_PI * wavenumbers[i][1] / Ly; - printf("k(%d) = (%f, %f)\n", i,k_host(0,i), k_host(1,i)); - } - } - if constexpr(D == Dim::_3D){ - for (auto i = 0; i < n_modes; i++){ - k_host(0,i) = constant::TWO_PI * wavenumbers[i][0] / Lx; - k_host(1,i) = constant::TWO_PI * wavenumbers[i][1] / Ly; - k_host(2,i) = constant::TWO_PI * wavenumbers[i][2] / Lz; - printf("k(%d) = (%f, %f, %f)\n", i,k_host(0,i), k_host(1,i), k_host(2,i)); - } - } - // initializing initial complex amplitudes - auto a_real_host = Kokkos::create_mirror_view(a_real); - auto a_imag_host = Kokkos::create_mirror_view(a_imag); - auto a_real_inv_host = Kokkos::create_mirror_view(a_real_inv); - auto a_imag_inv_host = Kokkos::create_mirror_view(a_imag_inv); - auto A0_host = Kokkos::create_mirror_view(A0); - real_t prefac; - if constexpr(D == Dim::_2D){ - real_t prefac = HALF; //HALF = 1/sqrt(twice modes due to reality condition * twice the frequencies due to sign change) - } - if constexpr(D == Dim::_3D){ - real_t prefac = ONE/math::sqrt(TWO); //1/sqrt(2) = 1/sqrt(twice modes due to reality condition) - } - for (auto i = 0; i < n_modes; i++){ - auto k_perp = math::sqrt(k_host(0,i) * k_host(0,i) + k_host(1,i) * k_host(1,i)); - auto phase = constant::TWO_PI / 6.; - A0_host(i) = dB / math::sqrt((real_t) n_modes) / k_perp * prefac; - a_real_host(i) = A0_host(i) * math::cos(phase); - a_imag_host(i) = A0_host(i) * math::sin(phase); - phase = constant::TWO_PI / 3; - a_imag_inv_host(i) = A0_host(i) * math::cos(phase); - a_real_inv_host(i) = A0_host(i) * math::sin(phase); - printf("A0(%d) = %f\n", i,A0_host(i)); - printf("a_real(%d) = %f\n", i,a_real_host(i)); - printf("a_imag(%d) = %f\n", i,a_imag_host(i)); - - - } - - Kokkos::deep_copy(a_real, a_real_host); - Kokkos::deep_copy(a_imag, a_imag_host); - Kokkos::deep_copy(a_real_inv, a_real_inv_host); - Kokkos::deep_copy(a_imag_inv, a_imag_inv_host); - Kokkos::deep_copy(A0, A0_host); - Kokkos::deep_copy(k, k_host); - }; - - - Inline auto jx3(const coord_t& x_Ph) const -> real_t { - if constexpr(D == Dim::_2D){ - real_t jx3_ant = ZERO; - for (size_t i=0; i < n_modes; i++){ - auto k_perp_sq = k(0,i) * k(0,i) + k(1,i) * k(1,i); - auto k_dot_r = k(0,i) * x_Ph[0] + k(1,i) * x_Ph[1]; - jx3_ant += TWO * k_perp_sq * (a_real(i) * math::cos(k_dot_r) - - a_imag(i) * math::sin(k_dot_r)); - jx3_ant += TWO * k_perp_sq * (a_real_inv(i) * math::cos(k_dot_r) - - a_imag_inv(i) * math::sin(k_dot_r)); - - } - return jx3_ant; - } - if constexpr(D == Dim::_3D){ - real_t jx3_ant = ZERO; - for (size_t i=0; i < n_modes; i++){ - auto k_perp_sq = k(0,i) * k(0,i) + k(1,i) * k(1,i); - auto k_dot_r = k(0,i) * x_Ph[0] + k(1,i) * x_Ph[1] + k(2,i) * x_Ph[2]; - jx3_ant += TWO * k_perp_sq * (a_real_inv(i) * math::cos(k_dot_r) - - a_imag_inv(i) * math::sin(k_dot_r)); - } - return jx3_ant; - } - } - Inline auto jx2(const coord_t& x_Ph) const -> real_t { - if constexpr(D == Dim::_2D){ - return ZERO; - } - if constexpr(D == Dim::_3D){ - real_t jx2_ant = ZERO; - for (size_t i = 0; i < n_modes; i++){ - auto k_dot_r = k(0,i) * x_Ph[0] + k(1,i) * x_Ph[1] + k(2,i) * x_Ph[2]; - jx2_ant -= TWO * k(1,i) * k(2,i) * (a_real_inv(i) * math::cos(k_dot_r) - - a_imag_inv(i) * math::sin(k_dot_r)); - - } - return jx2_ant; - } - } - Inline auto jx1(const coord_t& x_Ph) const -> real_t { - if constexpr(D == Dim::_2D){ - return ZERO; - } - if constexpr(D == Dim::_3D){ - real_t jx1_ant = ZERO; - for (size_t i = 0; i < n_modes; i++){ - auto k_dot_r = k(0,i) * x_Ph[0] + k(1,i) * x_Ph[1] + k(2,i) * x_Ph[2]; - jx1_ant -= TWO * k(0,i) * k(2,i) * (a_real_inv(i) * math::cos(k_dot_r) - - a_imag_inv(i) * math::sin(k_dot_r)); - - } - return jx1_ant; - } - } - - const real_t dB, omega_0, gamma_0, Lx, Ly, Lz; - const size_t n_modes; - array_t k; - array_t A0; - public: - array_t a_real; - array_t a_imag; - array_t u_imag; - array_t a_real_inv; - array_t a_imag_inv; - array_t u_real; - const std::vector< std::vector > wavenumbers; + struct ExternalCurrent { + ExternalCurrent(real_t dB, + real_t om0, + real_t g0, + std::vector>& wavenumbers, + random_number_pool_t& random_pool, + real_t Lx, + real_t Ly, + real_t Lz) + : wavenumbers { wavenumbers } + , n_modes { wavenumbers.size() } + , dB { dB } + , Lx { Lx } + , Ly { Ly } + , Lz { Lz } + , omega_0 { om0 } + , gamma_0 { g0 } + , k { "wavevector", D, n_modes } + , a_real { "a_real", n_modes } + , a_imag { "a_imag", n_modes } + , a_real_inv { "a_real_inv", n_modes } + , a_imag_inv { "a_imag_inv", n_modes } + , A0 { "A0", n_modes } { + // initializing wavevectors + auto k_host = Kokkos::create_mirror_view(k); + if constexpr (D == Dim::_2D) { + for (auto i = 0u; i < n_modes; i++) { + k_host(0, i) = constant::TWO_PI * wavenumbers[i][0] / Lx; + k_host(1, i) = constant::TWO_PI * wavenumbers[i][1] / Ly; + } + } + if constexpr (D == Dim::_3D) { + for (auto i = 0u; i < n_modes; i++) { + k_host(0, i) = constant::TWO_PI * wavenumbers[i][0] / Lx; + k_host(1, i) = constant::TWO_PI * wavenumbers[i][1] / Ly; + k_host(2, i) = constant::TWO_PI * wavenumbers[i][2] / Lz; + } + } + // initializing initial complex amplitudes + auto a_real_host = Kokkos::create_mirror_view(a_real); + auto a_imag_host = Kokkos::create_mirror_view(a_imag); + auto a_real_inv_host = Kokkos::create_mirror_view(a_real_inv); + auto a_imag_inv_host = Kokkos::create_mirror_view(a_imag_inv); + auto A0_host = Kokkos::create_mirror_view(A0); + + real_t prefac { ZERO }; + if constexpr (D == Dim::_2D) { + prefac = HALF; // HALF = 1/sqrt(twice modes due to reality condition * twice the frequencies due to sign change) + } else if constexpr (D == Dim::_3D) { + prefac = constant::SQRT2; // 1/sqrt(2) = 1/sqrt(twice modes due to reality condition) + } + for (auto i = 0u; i < n_modes; i++) { + auto k_perp = math::sqrt( + k_host(0, i) * k_host(0, i) + k_host(1, i) * k_host(1, i)); + auto phase = constant::TWO_PI / 6.; + A0_host(i) = dB / math::sqrt((real_t)n_modes) / k_perp * prefac; + a_real_host(i) = A0_host(i) * math::cos(phase); + a_imag_host(i) = A0_host(i) * math::sin(phase); + phase = constant::TWO_PI / 3; + a_imag_inv_host(i) = A0_host(i) * math::cos(phase); + a_real_inv_host(i) = A0_host(i) * math::sin(phase); + } + + Kokkos::deep_copy(a_real, a_real_host); + Kokkos::deep_copy(a_imag, a_imag_host); + Kokkos::deep_copy(a_real_inv, a_real_inv_host); + Kokkos::deep_copy(a_imag_inv, a_imag_inv_host); + Kokkos::deep_copy(A0, A0_host); + Kokkos::deep_copy(k, k_host); + }; + + Inline auto jx1(const coord_t& x_Ph) const -> real_t { + if constexpr (D == Dim::_2D) { + return ZERO; + } + if constexpr (D == Dim::_3D) { + real_t jx1_ant = ZERO; + for (auto i = 0u; i < n_modes; i++) { + auto k_dot_r = k(0, i) * x_Ph[0] + k(1, i) * x_Ph[1] + k(2, i) * x_Ph[2]; + jx1_ant -= TWO * k(0, i) * k(2, i) * + (a_real_inv(i) * math::cos(k_dot_r) - + a_imag_inv(i) * math::sin(k_dot_r)); + } + return jx1_ant; + } + } + + Inline auto jx2(const coord_t& x_Ph) const -> real_t { + if constexpr (D == Dim::_2D) { + return ZERO; + } else if constexpr (D == Dim::_3D) { + real_t jx2_ant = ZERO; + for (auto i = 0u; i < n_modes; i++) { + auto k_dot_r = k(0, i) * x_Ph[0] + k(1, i) * x_Ph[1] + k(2, i) * x_Ph[2]; + jx2_ant -= TWO * k(1, i) * k(2, i) * + (a_real_inv(i) * math::cos(k_dot_r) - + a_imag_inv(i) * math::sin(k_dot_r)); + } + return jx2_ant; + } + } + + Inline auto jx3(const coord_t& x_Ph) const -> real_t { + if constexpr (D == Dim::_2D) { + real_t jx3_ant = ZERO; + for (auto i = 0u; i < n_modes; i++) { + auto k_perp_sq = k(0, i) * k(0, i) + k(1, i) * k(1, i); + auto k_dot_r = k(0, i) * x_Ph[0] + k(1, i) * x_Ph[1]; + jx3_ant += TWO * k_perp_sq * + (a_real(i) * math::cos(k_dot_r) - + a_imag(i) * math::sin(k_dot_r)); + jx3_ant += TWO * k_perp_sq * + (a_real_inv(i) * math::cos(k_dot_r) - + a_imag_inv(i) * math::sin(k_dot_r)); + } + return jx3_ant; + } else if constexpr (D == Dim::_3D) { + real_t jx3_ant = ZERO; + for (auto i = 0u; i < n_modes; i++) { + auto k_perp_sq = k(0, i) * k(0, i) + k(1, i) * k(1, i); + auto k_dot_r = k(0, i) * x_Ph[0] + k(1, i) * x_Ph[1] + k(2, i) * x_Ph[2]; + jx3_ant += TWO * k_perp_sq * + (a_real_inv(i) * math::cos(k_dot_r) - + a_imag_inv(i) * math::sin(k_dot_r)); + } + return jx3_ant; + } + } + + private: + const std::vector> wavenumbers; + const std::size_t n_modes; + const real_t dB, Lx, Ly, Lz; + + public: + const real_t omega_0, gamma_0; + array_t k; + array_t a_real; + array_t a_imag; + array_t a_real_inv; + array_t a_imag_inv; + array_t A0; }; template @@ -217,75 +260,53 @@ namespace user { // compatibility traits for the problem generator static constexpr auto engines = traits::compatible_with::value; static constexpr auto metrics = traits::compatible_with::value; - static constexpr auto dimensions = - traits::compatible_with::value; + static constexpr auto dimensions = traits::compatible_with::value; // for easy access to variables in the child class using arch::ProblemGenerator::D; using arch::ProblemGenerator::C; using arch::ProblemGenerator::params; - const real_t temperature, dB, omega_0, gamma_0, Lx, Ly, Lz, dt; - const int random_seed; - std::vector< std::vector > wavenumbers; - random_number_pool_t random_pool; + const real_t temperature, dB, omega_0, gamma_0, Lx, Ly, Lz; + const int random_seed; + std::vector> wavenumbers; + random_number_pool_t random_pool; // debugging, will delete later - real_t total_sum = 0.0; - real_t total_sum_inv = 0.0; - real_t number_of_timesteps = 0.0; + real_t total_sum = ZERO; + real_t total_sum_inv = ZERO; + real_t number_of_timesteps = ZERO; ExternalCurrent ext_current; - InitFields init_flds; - - inline static std::vector> init_wavenumbers(){ - if constexpr( D == Dim::_2D){ - return { { 1, 0 }, { 0, 1 }, { 1, 1 }, { -1, 1 } }; - } - if constexpr (D== Dim::_3D){ - return { { 1, 0, 1 }, { 0, 1, 1 }, { -1, 0, 1 }, { 0, -1, 1 } }; - - } - } - - inline static unsigned int init_pool(const int seed) { - if (seed == -1){ -#if defined(MPI_ENABLED) - unsigned int new_seed = rand(); - MPI_Bcast(&new_seed, 1, MPI_UNSIGNED, MPI_ROOT_RANK, MPI_COMM_WORLD); - return new_seed; -#else - return {}; -#endif //MPI_ENABLED - } - else{ - return seed; - } - } + InitFields init_flds; inline PGen(const SimulationParams& p, const Metadomain& global_domain) : arch::ProblemGenerator { p } , temperature { p.template get("setup.temperature") } - , dB { p.template get("setup.dB", 1.) } + , dB { p.template get("setup.dB", ONE) } , omega_0 { p.template get("setup.omega_0") } , gamma_0 { p.template get("setup.gamma_0") } - , wavenumbers { init_wavenumbers() } + , wavenumbers { init_wavenumbers() } , random_seed { p.template get("setup.seed", -1) } , random_pool { init_pool(random_seed) } - , Lx { global_domain.mesh().extent(in::x1).second - global_domain.mesh().extent(in::x1).first } - , Ly { global_domain.mesh().extent(in::x2).second - global_domain.mesh().extent(in::x2).first } - , Lz { global_domain.mesh().extent(in::x3).second - global_domain.mesh().extent(in::x3).first } - , dt { params.template get("algorithms.timestep.dt") } - , ext_current { dB, omega_0, gamma_0, wavenumbers, random_pool, Lx, Ly, Lz } - , init_flds(ext_current.k, ext_current.a_real, ext_current.a_imag, ext_current.a_real_inv, ext_current.a_imag_inv) {}; - - inline PGen() {} + , Lx { global_domain.mesh().extent(in::x1).second - + global_domain.mesh().extent(in::x1).first } + , Ly { global_domain.mesh().extent(in::x2).second - + global_domain.mesh().extent(in::x2).first } + , Lz { global_domain.mesh().extent(in::x3).second - + global_domain.mesh().extent(in::x3).first } + , ext_current { dB, omega_0, gamma_0, wavenumbers, random_pool, Lx, Ly, Lz } + , init_flds { ext_current.k, + ext_current.a_real, + ext_current.a_imag, + ext_current.a_real_inv, + ext_current.a_imag_inv } {} inline void InitPrtls(Domain& local_domain) { - const auto energy_dist = arch::Maxwellian(local_domain.mesh.metric, - local_domain.random_pool, - temperature, - ZERO); + const auto energy_dist = arch::Maxwellian(local_domain.mesh.metric, + local_domain.random_pool, + temperature, + ZERO); const auto spatial_dist = arch::UniformInjector( energy_dist, { 1, 2 }); @@ -294,69 +315,55 @@ namespace user { local_domain, spatial_dist, ONE); - }; - void CustomPostStep(timestep_t, simtime_t time, Domain& domain){ - - // update amplitudes of antenna - Kokkos::parallel_for( " Antenna amplitudes ", wavenumbers.size(), Lambda (int const i){ - auto generator = random_pool.get_state(); - const auto u_imag = generator.frand(-0.5, 0.5); - const auto u_real = generator.frand(-0.5, 0.5); - const auto u_real_inv = generator.frand(-0.5,0.5); - const auto u_imag_inv = generator.frand(-0.5,0.5); - printf(" %i) u_real= %f, u_imag= %f, u_real_inv = %f, u_imag_inv = %f\n",i - , u_real - , u_imag - , u_real_inv - , u_imag_inv); - random_pool.free_state(generator); - auto a_real_prev = this->ext_current.a_real(i); - auto a_imag_prev = this->ext_current.a_imag(i); - auto a_real_inv_prev = this->ext_current.a_real_inv(i); - auto a_imag_inv_prev = this->ext_current.a_imag_inv(i); - auto dt = this->dt; - printf(" %i) a_real= %f, a_imag= %f, a_real_inv= %f, a_imag_inv=%f \n",i - , this->ext_current.a_real(i) - , this->ext_current.a_imag(i) - , this->ext_current.a_real_inv(i) - , this->ext_current.a_imag_inv(i)); - this->ext_current.a_real(i) = (a_real_prev * math::cos(this->ext_current.omega_0 * dt) + a_imag_prev * math::sin(this->ext_current.omega_0 * dt)) * math::exp(-this->ext_current.gamma_0 * dt) + this->ext_current.A0(i) * math::sqrt(12.0 * this->ext_current.gamma_0 / dt) * u_real * dt; - - this->ext_current.a_imag(i) = (a_imag_prev * math::cos(this->ext_current.omega_0 * dt) - a_real_prev * math::sin(this->ext_current.omega_0 * dt)) * math::exp(-this->ext_current.gamma_0 * dt) + this->ext_current.A0(i) * math::sqrt(12.0 * this->ext_current.gamma_0 / dt) * u_imag * dt; - - this->ext_current.a_real_inv(i) = (a_real_inv_prev * math::cos(-this->ext_current.omega_0 * dt) + a_imag_inv_prev * math::sin(-this->ext_current.omega_0 * dt)) * math::exp(-this->ext_current.gamma_0 * dt) + this->ext_current.A0(i) * math::sqrt(12.0 * this->ext_current.gamma_0 / dt) * u_real_inv * dt; - - this->ext_current.a_imag_inv(i) = (a_imag_inv_prev * math::cos(-this->ext_current.omega_0 * dt) - a_real_inv_prev * math::sin(-this->ext_current.omega_0 * dt)) * math::exp(-this->ext_current.gamma_0 * dt) + this->ext_current.A0(i) * math::sqrt(12.0 * this->ext_current.gamma_0 / dt ) * u_imag_inv * dt; - }); - -// real_t sum = 0.0; -// // KOKKOS_LAMBDA macro includes capture-by-value specifier [=]. -// Kokkos::parallel_reduce ("Reduction", wavenumbers.size(), Lambda (const int i, real_t& update) { -// auto a_real = this->ExternalCurrent.a_real(i); -// auto a_imag = this->ExternalCurrent.a_imag(i); -// auto k_perp = this->ExternalCurrent.k(0,i)*this->ExternalCurrent.k(0,i) + this->ExternalCurrent.k(1,i)*this->ExternalCurrent.k(1,i); -// update += (a_real * a_real + a_imag * a_imag) ; -// }, sum); -// total_sum +=sum; -// number_of_timesteps +=1.0; -// printf(" = %f, ", sum); -// printf("total = %f\n", total_sum/number_of_timesteps); -// -// real_t sum_inv = 0.0; -// // KOKKOS_LAMBDA macro includes capture-by-value specifier [=]. -// Kokkos::parallel_reduce ("Reduction", wavenumbers.size(), Lambda (const int i, real_t& update) { -// auto a_real = this->ExternalCurrent.a_real_inv(i); -// auto a_imag = this->ExternalCurrent.a_imag_inv(i); -// auto k_perp = this->ExternalCurrent.k(0,i)*this->ExternalCurrent.k(0,i) + this->ExternalCurrent.k(1,i)*this->ExternalCurrent.k(1,i); -// update += (a_real * a_real + a_imag * a_imag) ; -// }, sum_inv); -// total_sum_inv +=sum_inv; -// printf(" = %f, ", sum_inv); -// printf("total = %f\n", total_sum_inv/number_of_timesteps); - - + void CustomPostStep(timestep_t, simtime_t, Domain&) { + // update amplitudes of antenna + const auto dt = params.template get("algorithms.timestep.dt"); + const auto& ext_curr = ext_current; + Kokkos::parallel_for( + "Antenna amplitudes", + wavenumbers.size(), + ClassLambda(index_t i) { + auto generator = random_pool.get_state(); + const auto u_imag = Random(generator) - HALF; + const auto u_real = Random(generator) - HALF; + const auto u_real_inv = Random(generator) - HALF; + const auto u_imag_inv = Random(generator) - HALF; + random_pool.free_state(generator); + + auto a_real_prev = ext_curr.a_real(i); + auto a_imag_prev = ext_curr.a_imag(i); + auto a_real_inv_prev = ext_curr.a_real_inv(i); + auto a_imag_inv_prev = ext_curr.a_imag_inv(i); + ext_curr.a_real(i) = (a_real_prev * math::cos(ext_curr.omega_0 * dt) + + a_imag_prev * math::sin(ext_curr.omega_0 * dt)) * + math::exp(-ext_curr.gamma_0 * dt) + + ext_curr.A0(i) * + math::sqrt(TWELVE * ext_curr.gamma_0 / dt) * + u_real * dt; + + ext_curr.a_imag(i) = (a_imag_prev * math::cos(ext_curr.omega_0 * dt) - + a_real_prev * math::sin(ext_curr.omega_0 * dt)) * + math::exp(-ext_curr.gamma_0 * dt) + + ext_curr.A0(i) * + math::sqrt(TWELVE * ext_curr.gamma_0 / dt) * + u_imag * dt; + + ext_curr.a_real_inv( + i) = (a_real_inv_prev * math::cos(-ext_curr.omega_0 * dt) + + a_imag_inv_prev * math::sin(-ext_curr.omega_0 * dt)) * + math::exp(-ext_curr.gamma_0 * dt) + + ext_curr.A0(i) * math::sqrt(TWELVE * ext_curr.gamma_0 / dt) * + u_real_inv * dt; + + ext_curr.a_imag_inv( + i) = (a_imag_inv_prev * math::cos(-ext_curr.omega_0 * dt) - + a_real_inv_prev * math::sin(-ext_curr.omega_0 * dt)) * + math::exp(-ext_curr.gamma_0 * dt) + + ext_curr.A0(i) * math::sqrt(TWELVE * ext_curr.gamma_0 / dt) * + u_imag_inv * dt; + }); } }; } // namespace user diff --git a/src/global/utils/numeric.h b/src/global/utils/numeric.h index 719256d1d..cc1191b62 100644 --- a/src/global/utils/numeric.h +++ b/src/global/utils/numeric.h @@ -36,6 +36,7 @@ inline constexpr float TWO = 2.0f; inline constexpr float THREE = 3.0f; inline constexpr float FOUR = 4.0f; inline constexpr float FIVE = 5.0f; +inline constexpr float TWELVE = 12.0f; inline constexpr float ZERO = 0.0f; inline constexpr float HALF = 0.5f; inline constexpr float INV_2 = 0.5f; @@ -50,6 +51,7 @@ inline constexpr double TWO = 2.0; inline constexpr double THREE = 3.0; inline constexpr double FOUR = 4.0; inline constexpr double FIVE = 5.0; +inline constexpr double TWELVE = 12.0; inline constexpr double ZERO = 0.0; inline constexpr double HALF = 0.5; inline constexpr double INV_2 = 0.5; From 561a3ffa9bd02879b94c9f384c08997f55e04d4a Mon Sep 17 00:00:00 2001 From: hayk Date: Wed, 23 Apr 2025 14:55:41 -0400 Subject: [PATCH 650/773] turb escape --- setups/wip/turbulence/pgen.hpp | 49 ++++++++++++++++++++++++++++++---- 1 file changed, 44 insertions(+), 5 deletions(-) diff --git a/setups/wip/turbulence/pgen.hpp b/setups/wip/turbulence/pgen.hpp index b14842768..c056f87fa 100644 --- a/setups/wip/turbulence/pgen.hpp +++ b/setups/wip/turbulence/pgen.hpp @@ -267,8 +267,9 @@ namespace user { using arch::ProblemGenerator::C; using arch::ProblemGenerator::params; - const real_t temperature, dB, omega_0, gamma_0, Lx, Ly, Lz; - const int random_seed; + const real_t temperature, dB, omega_0, gamma_0; + const real_t Lx, Ly, Lz, escape_dist; + const int random_seed; std::vector> wavenumbers; random_number_pool_t random_pool; @@ -295,6 +296,7 @@ namespace user { global_domain.mesh().extent(in::x2).first } , Lz { global_domain.mesh().extent(in::x3).second - global_domain.mesh().extent(in::x3).first } + , escape_dist { p.template get("setup.escape_dist", HALF * Lx) } , ext_current { dB, omega_0, gamma_0, wavenumbers, random_pool, Lx, Ly, Lz } , init_flds { ext_current.k, ext_current.a_real, @@ -305,8 +307,7 @@ namespace user { inline void InitPrtls(Domain& local_domain) { const auto energy_dist = arch::Maxwellian(local_domain.mesh.metric, local_domain.random_pool, - temperature, - ZERO); + temperature); const auto spatial_dist = arch::UniformInjector( energy_dist, { 1, 2 }); @@ -317,7 +318,7 @@ namespace user { ONE); }; - void CustomPostStep(timestep_t, simtime_t, Domain&) { + void CustomPostStep(timestep_t, simtime_t, Domain& domain) { // update amplitudes of antenna const auto dt = params.template get("algorithms.timestep.dt"); const auto& ext_curr = ext_current; @@ -364,6 +365,44 @@ namespace user { ext_curr.A0(i) * math::sqrt(TWELVE * ext_curr.gamma_0 / dt) * u_imag_inv * dt; }); + + // particle escape (resample velocities) + const auto energy_dist = arch::Maxwellian(domain.mesh.metric, + domain.random_pool, + temperature); + for (const auto& sp : { 0, 1 }) { + if (domain.species[sp].npld() > 1) { + const auto& ux1 = domain.species[sp].ux1; + const auto& ux2 = domain.species[sp].ux2; + const auto& ux3 = domain.species[sp].ux3; + const auto& pld = domain.species[sp].pld; + const auto& tag = domain.species[sp].tag; + const auto L = escape_dist; + Kokkos::parallel_for( + "UpdatePld", + domain.species[sp].npart(), + Lambda(index_t p) { + if (tag(p) == ParticleTag::dead) { + return; + } + const auto gamma = math::sqrt( + ONE + ux1(p) * ux1(p) + ux2(p) * ux2(p) + ux3(p) * ux3(p)); + pld(p, 0) += ux1(p) * dt / gamma; + pld(p, 1) += ux2(p) * dt / gamma; + + if ((pld(p, 0) > L) or (pld(p, 1) > L)) { + coord_t x_Ph { ZERO }; + vec_t u_Mxw { ZERO }; + energy_dist(x_Ph, u_Mxw); + ux1(p) = u_Mxw[0]; + ux2(p) = u_Mxw[1]; + ux3(p) = u_Mxw[2]; + pld(p, 0) = ZERO; + pld(p, 1) = ZERO; + } + }); + } + } } }; } // namespace user From e2c2b51356941c1f81787b6e600d1eee768ff492 Mon Sep 17 00:00:00 2001 From: hayk Date: Wed, 23 Apr 2025 15:38:12 -0400 Subject: [PATCH 651/773] compile-time flag: mpi_device_copy --- CMakeLists.txt | 18 ++ cmake/defaults.cmake | 10 + cmake/report.cmake | 34 +++- src/framework/domain/comm_mpi.hpp | 314 +++++++++++++++++------------- 4 files changed, 230 insertions(+), 146 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c328e8b84..20d739786 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -95,6 +95,13 @@ elseif("${Kokkos_DEVICES}" MATCHES "HIP") elseif("${Kokkos_DEVICES}" MATCHES "SYCL") add_compile_options("-D SYCL_ENABLED") endif() +if((${Kokkos_DEVICES} MATCHES "CUDA") + OR (${Kokkos_DEVICES} MATCHES "HIP") + OR (${Kokkos_DEVICES} MATCHES "SYCL")) + set(DEVICE_ENABLED ON) +else() + set(DEVICE_ENABLED OFF) +endif() # MPI if(${mpi}) @@ -102,6 +109,17 @@ if(${mpi}) include_directories(${MPI_CXX_INCLUDE_PATH}) add_compile_options("-D MPI_ENABLED") set(DEPENDENCIES ${DEPENDENCIES} MPI::MPI_CXX) + + if(${DEVICE_ENABLED}) + set(mpi_device_copy + ${default_mpi_device_copy} + CACHE BOOL "Use explicit copy when using MPI + GPU") + add_compile_options("-D MPI_DEVICE_COPY") + else() + set(mpi_device_copy + OFF + CACHE BOOL "Use explicit copy when using MPI + GPU") + endif() endif() # Output diff --git a/cmake/defaults.cmake b/cmake/defaults.cmake index 30e605a5c..9829ea14d 100644 --- a/cmake/defaults.cmake +++ b/cmake/defaults.cmake @@ -63,4 +63,14 @@ else() CACHE INTERNAL "Default flag for MPI") endif() +if(DEFINED ENV{Entity_MPI_DEVICE_COPY}) + set(default_mpi_device_copy + $ENV{Entity_MPI_DEVICE_COPY} + CACHE INTERNAL "Default flag for copying from device to host for MPI") +else() + set(default_mpi_device_copy + ON + CACHE INTERNAL "Default flag for copying from device to host for MPI") +endif() + set_property(CACHE default_mpi PROPERTY TYPE BOOL) diff --git a/cmake/report.cmake b/cmake/report.cmake index 626de15a2..c4958fa3a 100644 --- a/cmake/report.cmake +++ b/cmake/report.cmake @@ -36,7 +36,7 @@ printchoices( ${default_precision} "${Blue}" PRECISION_REPORT - 36) + 46) printchoices( "Output" "output" @@ -45,7 +45,7 @@ printchoices( ${default_output} "${Green}" OUTPUT_REPORT - 36) + 46) printchoices( "MPI" "mpi" @@ -54,7 +54,7 @@ printchoices( OFF "${Green}" MPI_REPORT - 36) + 46) printchoices( "Debug mode" "DEBUG" @@ -63,7 +63,17 @@ printchoices( OFF "${Green}" DEBUG_REPORT - 36) + 46) + +printchoices( + "MPI explicit copy" + "mpi_device_copy" + "${ON_OFF_VALUES}" + ${mpi_device_copy} + OFF + "${Green}" + MPI_DEVICE_COPY_REPORT + 46) if(NOT ${PROJECT_VERSION_TWEAK} EQUAL 0) set(VERSION_SYMBOL "v${PROJECT_VERSION_MAJOR}." "${PROJECT_VERSION_MINOR}.") @@ -111,13 +121,23 @@ string(REPLACE ";" "+" Kokkos_DEVICES "${Kokkos_DEVICES}") string( APPEND REPORT_TEXT - " - ARCH [${Magenta}Kokkos_ARCH_***${ColorReset}]: ${Kokkos_ARCH}" + " - ARCH [${Magenta}Kokkos_ARCH_***${ColorReset}]: " + "${Kokkos_ARCH}" "\n" - " - DEVICES [${Magenta}Kokkos_ENABLE_***${ColorReset}]: ${Kokkos_DEVICES}" + " - DEVICES [${Magenta}Kokkos_ENABLE_***${ColorReset}]: " + "${Kokkos_DEVICES}" "\n" " " ${MPI_REPORT} - "\n" + "\n") + +if(${DEVICE_ENABLED}) + string(APPEND REPORT_TEXT " " ${MPI_DEVICE_COPY_REPORT} "\n") +endif() + +string( + APPEND + REPORT_TEXT " " ${DEBUG_REPORT} "\n" diff --git a/src/framework/domain/comm_mpi.hpp b/src/framework/domain/comm_mpi.hpp index a2b248dc3..f63761afd 100644 --- a/src/framework/domain/comm_mpi.hpp +++ b/src/framework/domain/comm_mpi.hpp @@ -186,6 +186,7 @@ namespace comm { } if (send_rank >= 0 && recv_rank >= 0) { +#if defined(MPI_DEVICE_COPY) auto send_fld_h = Kokkos::create_mirror_view(send_fld); auto recv_fld_h = Kokkos::create_mirror_view(recv_fld); Kokkos::deep_copy(send_fld_h, send_fld); @@ -202,7 +203,22 @@ namespace comm { MPI_COMM_WORLD, MPI_STATUS_IGNORE); Kokkos::deep_copy(recv_fld, recv_fld_h); +#else + MPI_Sendrecv(send_fld.data(), + nsend, + mpi::get_type(), + send_rank, + 0, + recv_fld.data(), + nrecv, + mpi::get_type(), + recv_rank, + 0, + MPI_COMM_WORLD, + MPI_STATUS_IGNORE); +#endif } else if (send_rank >= 0) { +#if defined(MPI_DEVICE_COPY) auto send_fld_h = Kokkos::create_mirror_view(send_fld); Kokkos::deep_copy(send_fld_h, send_fld); MPI_Send(send_fld_h.data(), @@ -211,7 +227,16 @@ namespace comm { send_rank, 0, MPI_COMM_WORLD); +#else + MPI_Send(send_fld.data(), + nsend, + mpi::get_type(), + send_rank, + 0, + MPI_COMM_WORLD); +#endif } else if (recv_rank >= 0) { +#if defined(MPI_DEVICE_COPY) auto recv_fld_h = Kokkos::create_mirror_view(recv_fld); MPI_Recv(recv_fld_h.data(), nrecv, @@ -221,6 +246,15 @@ namespace comm { MPI_COMM_WORLD, MPI_STATUS_IGNORE); Kokkos::deep_copy(recv_fld, recv_fld_h); +#else + MPI_Recv(recv_fld.data(), + nrecv, + mpi::get_type(), + recv_rank, + 0, + MPI_COMM_WORLD, + MPI_STATUS_IGNORE); +#endif } else { raise::Error("CommunicateField called with negative ranks", HERE); } @@ -325,6 +359,101 @@ namespace comm { } } + namespace { + template + void send_recv(const array_t& send_buff, + array_t& recv_buff, + unsigned short Narrs, + npart_t nsend, + npart_t nrecv, + int send_rank, + int recv_rank, + npart_t recv_offset) { +#if defined(MPI_DEVICE_COPY) + auto send_buff_h = Kokkos::create_mirror_view(send_buff); + auto recv_buff_h = Kokkos::create_mirror_view(recv_buff); + Kokkos::deep_copy(send_buff_h, send_buff); + MPI_Sendrecv(send_buff_h.data(), + nsend * Narrs, + mpi::get_type(), + send_rank, + 0, + recv_buff_h.data() + recv_offset, + nrecv * Narrs, + mpi::get_type(), + recv_rank, + 0, + MPI_COMM_WORLD, + MPI_STATUS_IGNORE); + Kokkos::deep_copy(recv_buff, recv_buff_h); +#else + MPI_Sendrecv(send_buff.data(), + nsend * Narrs, + mpi::get_type(), + send_rank, + 0, + recv_buff.data() + recv_offset, + nrecv * Narrs, + mpi::get_type(), + recv_rank, + 0, + MPI_COMM_WORLD, + MPI_STATUS_IGNORE); +#endif + } + + template + void send(const array_t& send_buff, + unsigned short Narrs, + npart_t nsend, + int send_rank) { +#if defined(MPI_DEVICE_COPY) + auto send_buff_h = Kokkos::create_mirror_view(send_buff); + Kokkos::deep_copy(send_buff_h, send_buff); + MPI_Send(send_buff_h.data(), + nsend * Narrs, + mpi::get_type(), + send_rank, + 0, + MPI_COMM_WORLD); +#else + MPI_Send(send_buff.data(), + nsend * Narrs, + mpi::get_type(), + send_rank, + 0, + MPI_COMM_WORLD); +#endif + } + + template + void recv(const array_t& recv_buff, + unsigned short Narrs, + npart_t nrecv, + int recv_rank, + npart_t recv_offset) { +#if defined(MPI_DEVICE_COPY) + auto recv_buff_h = Kokkos::create_mirror_view(recv_buff); + MPI_Recv(recv_buff_h.data() + recv_offset, + nrecv * Narrs, + mpi::get_type(), + recv_rank, + 0, + MPI_COMM_WORLD, + MPI_STATUS_IGNORE); + Kokkos::deep_copy(recv_buff, recv_buff_h); +#else + MPI_Recv(recv_buff.data() + recv_offset, + nrecv * Narrs, + mpi::get_type(), + recv_rank, + 0, + MPI_COMM_WORLD, + MPI_STATUS_IGNORE); +#endif + } + } // namespace + template void CommunicateParticles(Particles& species, const array_t& outgoing_indices, @@ -411,111 +540,49 @@ namespace comm { recv_buff_int.extent(0), "incorrect # of recv particles", HERE); - auto send_buff_int_h = Kokkos::create_mirror_view(send_buff_int); - auto recv_buff_int_h = Kokkos::create_mirror_view(recv_buff_int); - Kokkos::deep_copy(send_buff_int_h, send_buff_int); - MPI_Sendrecv(send_buff_int_h.data(), - npart_send_in * NINTS, - mpi::get_type(), - send_rank, - 0, - recv_buff_int_h.data() + recv_offset_int, - npart_recv_in * NINTS, - mpi::get_type(), - recv_rank, - 0, - MPI_COMM_WORLD, - MPI_STATUS_IGNORE); - Kokkos::deep_copy(recv_buff_int, recv_buff_int_h); - - auto send_buff_real_h = Kokkos::create_mirror_view(send_buff_real); - auto recv_buff_real_h = Kokkos::create_mirror_view(recv_buff_real); - Kokkos::deep_copy(send_buff_real_h, send_buff_real); - MPI_Sendrecv(send_buff_real_h.data(), - npart_send_in * NREALS, - mpi::get_type(), - send_rank, - 0, - recv_buff_real_h.data() + recv_offset_real, - npart_recv_in * NREALS, - mpi::get_type(), - recv_rank, - 0, - MPI_COMM_WORLD, - MPI_STATUS_IGNORE); - Kokkos::deep_copy(recv_buff_real, recv_buff_real_h); - - auto send_buff_prtldx_h = Kokkos::create_mirror_view(send_buff_prtldx); - auto recv_buff_prtldx_h = Kokkos::create_mirror_view(recv_buff_prtldx); - Kokkos::deep_copy(send_buff_prtldx_h, send_buff_prtldx); - MPI_Sendrecv(send_buff_prtldx_h.data(), - npart_send_in * NPRTLDX, - mpi::get_type(), - send_rank, - 0, - recv_buff_prtldx_h.data() + recv_offset_prtldx, - npart_recv_in * NPRTLDX, - mpi::get_type(), - recv_rank, - 0, - MPI_COMM_WORLD, - MPI_STATUS_IGNORE); - Kokkos::deep_copy(recv_buff_prtldx, recv_buff_prtldx_h); - - if (NPLDS > 0) { - auto send_buff_pld_h = Kokkos::create_mirror_view(send_buff_pld); - auto recv_buff_pld_h = Kokkos::create_mirror_view(recv_buff_pld); - Kokkos::deep_copy(send_buff_pld_h, send_buff_pld); - MPI_Sendrecv(send_buff_pld_h.data(), - npart_send_in * NPLDS, - mpi::get_type(), + send_recv(send_buff_int, + recv_buff_int, + NINTS, + npart_send_in, + npart_recv_in, send_rank, - 0, - recv_buff_pld_h.data() + recv_offset_pld, - npart_recv_in * NPLDS, - mpi::get_type(), recv_rank, - 0, - MPI_COMM_WORLD, - MPI_STATUS_IGNORE); - Kokkos::deep_copy(recv_buff_pld, recv_buff_pld_h); + recv_offset_int); + + send_recv(send_buff_real, + recv_buff_real, + NREALS, + npart_send_in, + npart_recv_in, + send_rank, + recv_rank, + recv_offset_real); + + send_recv(send_buff_prtldx, + recv_buff_prtldx, + NPRTLDX, + npart_send_in, + npart_recv_in, + send_rank, + recv_rank, + recv_offset_prtldx); + + if (NPLDS > 0) { + send_recv(send_buff_pld, + recv_buff_pld, + NPLDS, + npart_send_in, + npart_recv_in, + send_rank, + recv_rank, + recv_offset_pld); } } else if ((send_rank >= 0) and (npart_send_in > 0)) { - auto send_buff_int_h = Kokkos::create_mirror_view(send_buff_int); - Kokkos::deep_copy(send_buff_int_h, send_buff_int); - MPI_Send(send_buff_int_h.data(), - npart_send_in * NINTS, - mpi::get_type(), - send_rank, - 0, - MPI_COMM_WORLD); - - auto send_buff_real_h = Kokkos::create_mirror_view(send_buff_real); - Kokkos::deep_copy(send_buff_real_h, send_buff_real); - MPI_Send(send_buff_real.data(), - npart_send_in * NREALS, - mpi::get_type(), - send_rank, - 0, - MPI_COMM_WORLD); - - auto send_buff_prtldx_h = Kokkos::create_mirror_view(send_buff_prtldx); - Kokkos::deep_copy(send_buff_prtldx_h, send_buff_prtldx); - MPI_Send(send_buff_prtldx_h.data(), - npart_send_in * NPRTLDX, - mpi::get_type(), - send_rank, - 0, - MPI_COMM_WORLD); + send(send_buff_int, NINTS, npart_send_in, send_rank); + send(send_buff_real, NREALS, npart_send_in, send_rank); + send(send_buff_prtldx, NPRTLDX, npart_send_in, send_rank); if (NPLDS > 0) { - auto send_buff_pld_h = Kokkos::create_mirror_view(send_buff_pld); - Kokkos::deep_copy(send_buff_pld_h, send_buff_pld); - MPI_Send(send_buff_pld_h.data(), - npart_send_in * NPLDS, - mpi::get_type(), - send_rank, - 0, - MPI_COMM_WORLD); + send(send_buff_pld, NPLDS, npart_send_in, send_rank); } } else if ((recv_rank >= 0) and (npart_recv_in > 0)) { raise::ErrorIf(recv_offset_int + npart_recv_in * NINTS > @@ -523,46 +590,15 @@ namespace comm { "incorrect # of recv particles", HERE); - auto recv_buff_int_h = Kokkos::create_mirror_view(recv_buff_int); - MPI_Recv(recv_buff_int_h.data() + recv_offset_int, - npart_recv_in * NINTS, - mpi::get_type(), - recv_rank, - 0, - MPI_COMM_WORLD, - MPI_STATUS_IGNORE); - Kokkos::deep_copy(recv_buff_int, recv_buff_int_h); - - auto recv_buff_real_h = Kokkos::create_mirror_view(recv_buff_real); - MPI_Recv(recv_buff_real_h.data() + recv_offset_real, - npart_recv_in * NREALS, - mpi::get_type(), - recv_rank, - 0, - MPI_COMM_WORLD, - MPI_STATUS_IGNORE); - Kokkos::deep_copy(recv_buff_real, recv_buff_real_h); - - auto recv_buff_prtldx_h = Kokkos::create_mirror_view(recv_buff_prtldx); - MPI_Recv(recv_buff_prtldx_h.data() + recv_offset_prtldx, - npart_recv_in * NPRTLDX, - mpi::get_type(), - recv_rank, - 0, - MPI_COMM_WORLD, - MPI_STATUS_IGNORE); - Kokkos::deep_copy(recv_buff_prtldx, recv_buff_prtldx_h); - + recv(recv_buff_int, NINTS, npart_recv_in, recv_rank, recv_offset_int); + recv(recv_buff_real, NREALS, npart_recv_in, recv_rank, recv_offset_real); + recv(recv_buff_prtldx, + NPRTLDX, + npart_recv_in, + recv_rank, + recv_offset_prtldx); if (NPLDS > 0) { - auto rrecv_buff_pld_h = Kokkos::create_mirror_view(recv_buff_pld); - MPI_Recv(rrecv_buff_pld_h.data() + recv_offset_pld, - npart_recv_in * NPLDS, - mpi::get_type(), - recv_rank, - 0, - MPI_COMM_WORLD, - MPI_STATUS_IGNORE); - Kokkos::deep_copy(recv_buff_pld, rrecv_buff_pld_h); + recv(recv_buff_pld, NPLDS, npart_recv_in, recv_rank, recv_offset_pld); } } current_received += npart_recv_in; From b1ebdf17180d1aefcf92b257645d4e1b1ebf35b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20B=C3=B6ss?= Date: Wed, 23 Apr 2025 16:15:22 -0500 Subject: [PATCH 652/773] higher order Faraday kernel implemented by @vanthieg --- src/engines/srpic.hpp | 36 +++++++++-- src/framework/parameters.cpp | 63 +++++++++++++++++-- src/global/defaults.h | 14 +++++ src/kernels/faraday_mink.hpp | 119 ++++++++++++++++++++++++++++------- 4 files changed, 200 insertions(+), 32 deletions(-) diff --git a/src/engines/srpic.hpp b/src/engines/srpic.hpp index a10070c34..8f8215f1e 100644 --- a/src/engines/srpic.hpp +++ b/src/engines/srpic.hpp @@ -185,6 +185,24 @@ namespace ntt { if constexpr (M::CoordType == Coord::Cart) { // minkowski case const auto dx = math::sqrt(domain.mesh.metric.template h_<1, 1>({})); + const auto deltax = m_params.template get( + "algorithms.fieldsolver.deltax"); + const auto deltay = m_params.template get( + "algorithms.fieldsolver.deltay"); + const auto betaxy = m_params.template get( + "algorithms.fieldsolver.betaxy"); + const auto betayx = m_params.template get( + "algorithms.fieldsolver.betayx"); + const auto deltaz = m_params.template get( + "algorithms.fieldsolver.deltaz"); + const auto betaxz = m_params.template get( + "algorithms.fieldsolver.betaxz"); + const auto betazx = m_params.template get( + "algorithms.fieldsolver.betazx"); + const auto betayz = m_params.template get( + "algorithms.fieldsolver.betayz"); + const auto betazy = m_params.template get( + "algorithms.fieldsolver.betazy"); real_t coeff1, coeff2; if constexpr (M::Dim == Dim::_2D) { coeff1 = dT / SQR(dx); @@ -193,10 +211,20 @@ namespace ntt { coeff1 = dT / dx; coeff2 = ZERO; } - Kokkos::parallel_for( - "Faraday", - domain.mesh.rangeActiveCells(), - kernel::mink::Faraday_kernel(domain.fields.em, coeff1, coeff2)); + Kokkos::parallel_for("Faraday", + domain.mesh.rangeActiveCells(), + kernel::mink::Faraday_kernel(domain.fields.em, + coeff1, + coeff2, + deltax, + deltay, + betaxy, + betayx, + deltaz, + betaxz, + betazx, + betayz, + betazy)); } else { Kokkos::parallel_for("Faraday", domain.mesh.rangeActiveCells(), diff --git a/src/framework/parameters.cpp b/src/framework/parameters.cpp index 8a30f52d9..42655b207 100644 --- a/src/framework/parameters.cpp +++ b/src/framework/parameters.cpp @@ -31,10 +31,10 @@ namespace ntt { template - auto get_dx0_V0( - const std::vector& resolution, - const boundaries_t& extent, - const std::map& params) -> std::pair { + auto get_dx0_V0(const std::vector& resolution, + const boundaries_t& extent, + const std::map& params) + -> std::pair { const auto metric = M(resolution, extent, params); const auto dx0 = metric.dxMin(); coord_t x_corner { ZERO }; @@ -416,6 +416,61 @@ namespace ntt { set("algorithms.toggles.deposit", toml::find_or(toml_data, "algorithms", "toggles", "deposit", true)); + /* [algorithms.fieldsolver] --------------------------------------------- */ + set("algorithms.fieldsolver.deltax", + toml::find_or(toml_data, + "algorithms", + "fieldsolver", + "deltax", + defaults::fieldsolver::deltax)); + set("algorithms.fieldsolver.deltay", + toml::find_or(toml_data, + "algorithms", + "fieldsolver", + "deltay", + defaults::fieldsolver::deltay)); + set("algorithms.fieldsolver.deltaz", + toml::find_or(toml_data, + "algorithms", + "fieldsolver", + "deltaz", + defaults::fieldsolver::deltaz)); + set("algorithms.fieldsolver.betaxy", + toml::find_or(toml_data, + "algorithms", + "fieldsolver", + "betaxy", + defaults::fieldsolver::betaxy)); + set("algorithms.fieldsolver.betayx", + toml::find_or(toml_data, + "algorithms", + "fieldsolver", + "betayx", + defaults::fieldsolver::betayx)); + set("algorithms.fieldsolver.betaxz", + toml::find_or(toml_data, + "algorithms", + "fieldsolver", + "betaxz", + defaults::fieldsolver::betaxz)); + set("algorithms.fieldsolver.betazx", + toml::find_or(toml_data, + "algorithms", + "fieldsolver", + "betazx", + defaults::fieldsolver::betazx)); + set("algorithms.fieldsolver.betayz", + toml::find_or(toml_data, + "algorithms", + "fieldsolver", + "betayz", + defaults::fieldsolver::betayz)); + set("algorithms.fieldsolver.betazy", + toml::find_or(toml_data, + "algorithms", + "fieldsolver", + "betazy", + defaults::fieldsolver::betazy)); /* [algorithms.timestep] ------------------------------------------------ */ set("algorithms.timestep.CFL", toml::find_or(toml_data, "algorithms", "timestep", "CFL", defaults::cfl)); diff --git a/src/global/defaults.h b/src/global/defaults.h index e44103ed0..b5120d6e4 100644 --- a/src/global/defaults.h +++ b/src/global/defaults.h @@ -26,6 +26,20 @@ namespace ntt::defaults { const std::string ph_pusher = "Photon"; const timestep_t clear_interval = 100; + namespace fieldsolver { + const real_t deltax = 0.0; + + const real_t deltay = 0.0; + const real_t betaxy = 0.0; + const real_t betayx = 0.0; + + const real_t deltaz = 0.0; + const real_t betaxz = 0.0; + const real_t betazx = 0.0; + const real_t betayz = 0.0; + const real_t betazy = 0.0; + } // namespace fieldsolver + namespace qsph { const real_t r0 = 0.0; const real_t h = 0.0; diff --git a/src/kernels/faraday_mink.hpp b/src/kernels/faraday_mink.hpp index 6d249b999..1112e56e7 100644 --- a/src/kernels/faraday_mink.hpp +++ b/src/kernels/faraday_mink.hpp @@ -26,6 +26,15 @@ namespace kernel::mink { ndfield_t EB; const real_t coeff1; const real_t coeff2; + const real_t deltax; + const real_t deltay; + const real_t betaxy; + const real_t betayx; + const real_t deltaz; + const real_t betaxz; + const real_t betazx; + const real_t betayz; + const real_t betazy; public: /** @@ -33,15 +42,34 @@ namespace kernel::mink { * ! 2D: coeff1 = dt / dx^2, coeff2 = dt * ! 3D: coeff1 = dt / dx */ - Faraday_kernel(const ndfield_t& EB, real_t coeff1, real_t coeff2) + Faraday_kernel(const ndfield_t& EB, real_t coeff1, real_t coeff2 + , real_t deltax, real_t deltay, real_t betaxy, real_t betayx + , real_t deltaz, real_t betaxz, real_t betazx, real_t betayz + , real_t betazy) : EB { EB } , coeff1 { coeff1 } - , coeff2 { coeff2 } {} + , coeff2 { coeff2 } + , deltax { deltax } + , deltay { deltay } + , betaxy { betaxy } + , betayx { betayx } + , deltaz { deltaz } + , betaxz { betaxz } + , betazx { betazx } + , betayz { betayz } + , betazy { betazy } {} + + Inline void operator()(index_t i1) const { if constexpr (D == Dim::_1D) { - EB(i1, em::bx2) += coeff1 * (EB(i1 + 1, em::ex3) - EB(i1, em::ex3)); - EB(i1, em::bx3) += coeff1 * (EB(i1, em::ex2) - EB(i1 + 1, em::ex2)); + const auto alphax = ONE - THREE * deltax; + EB(i1, em::bx2) += coeff1 * ( + + alphax * (EB(i1 + 1, em::ex3) - EB(i1 , em::ex3)) + + deltax * (EB(i1 + 2, em::ex3) - EB(i1 - 1, em::ex3))); + EB(i1, em::bx3) += coeff1 * ( + - alphax * (EB(i1 + 1, em::ex2) - EB(i1 , em::ex2)) + - deltax * (EB(i1 + 2, em::ex2) - EB(i1 - 1, em::ex2))); } else { raise::KernelError(HERE, "Faraday_kernel: 1D implementation called for D != 1"); } @@ -49,13 +77,27 @@ namespace kernel::mink { Inline void operator()(index_t i1, index_t i2) const { if constexpr (D == Dim::_2D) { - EB(i1, i2, em::bx1) += coeff1 * - (EB(i1, i2, em::ex3) - EB(i1, i2 + 1, em::ex3)); - EB(i1, i2, em::bx2) += coeff1 * - (EB(i1 + 1, i2, em::ex3) - EB(i1, i2, em::ex3)); - EB(i1, i2, em::bx3) += coeff2 * - (EB(i1, i2 + 1, em::ex1) - EB(i1, i2, em::ex1) + - EB(i1, i2, em::ex2) - EB(i1 + 1, i2, em::ex2)); + const auto alphax = ONE - TWO * betaxy - THREE * deltax; + const auto alphay = ONE - TWO * betayx - THREE * deltay; + EB(i1, i2, em::bx1) += coeff1 * ( + - alphay * (EB(i1 , i2 + 1, em::ex3) - EB(i1 , i2 , em::ex3)) + - deltay * (EB(i1 , i2 + 2, em::ex3) - EB(i1 , i2 - 1, em::ex3)) + - betayx * (EB(i1 + 1, i2 + 1, em::ex3) - EB(i1 + 1, i2 , em::ex3)) + - betayx * (EB(i1 - 1, i2 + 1, em::ex3) - EB(i1 - 1, i2 , em::ex3))); + EB(i1, i2, em::bx2) += coeff1 * ( + + alphax * (EB(i1 + 1, i2 , em::ex3) - EB(i1 , i2 , em::ex3)) + + deltax * (EB(i1 + 2, i2 , em::ex3) - EB(i1 - 1, i2 , em::ex3)) + + betaxy * (EB(i1 + 1, i2 + 1, em::ex3) - EB(i1 , i2 + 1, em::ex3)) + + betaxy * (EB(i1 + 1, i2 - 1, em::ex3) - EB(i1 , i2 - 1, em::ex3))); + EB(i1, i2, em::bx3) += coeff2 * ( + + alphay * (EB(i1 , i2 + 1, em::ex1) - EB(i1 , i2 , em::ex1)) + + deltay * (EB(i1 , i2 + 2, em::ex1) - EB(i1 , i2 - 1, em::ex1)) + + betayx * (EB(i1 + 1, i2 + 1, em::ex1) - EB(i1 + 1, i2 , em::ex1)) + + betayx * (EB(i1 - 1, i2 + 1, em::ex1) - EB(i1 - 1, i2 , em::ex1)) + - alphax * (EB(i1 + 1, i2 , em::ex2) - EB(i1 , i2 , em::ex2)) + - deltax * (EB(i1 + 2, i2 , em::ex2) - EB(i1 - 1, i2 , em::ex2)) + - betaxy * (EB(i1 + 1, i2 + 1, em::ex2) - EB(i1 , i2 + 1, em::ex2)) + - betaxy * (EB(i1 + 1, i2 - 1, em::ex2) - EB(i1 , i2 - 1, em::ex2))); } else { raise::KernelError(HERE, "Faraday_kernel: 2D implementation called for D != 2"); @@ -64,19 +106,48 @@ namespace kernel::mink { Inline void operator()(index_t i1, index_t i2, index_t i3) const { if constexpr (D == Dim::_3D) { - EB(i1, i2, i3, em::bx1) += coeff1 * (EB(i1, i2, i3 + 1, em::ex2) - - EB(i1, i2, i3, em::ex2) + - EB(i1, i2, i3, em::ex3) - - EB(i1, i2 + 1, i3, em::ex3)); - EB(i1, i2, i3, em::bx2) += coeff1 * (EB(i1 + 1, i2, i3, em::ex3) - - EB(i1, i2, i3, em::ex3) + - EB(i1, i2, i3, em::ex1) - - EB(i1, i2, i3 + 1, em::ex1)); - EB(i1, i2, i3, em::bx3) += coeff1 * (EB(i1, i2 + 1, i3, em::ex1) - - EB(i1, i2, i3, em::ex1) + - EB(i1, i2, i3, em::ex2) - - EB(i1 + 1, i2, i3, em::ex2)); - + const auto alphax = ONE - TWO * betaxy - TWO * betaxz - THREE * deltax; + const auto alphay = ONE - TWO * betayx - TWO * betayz - THREE * deltay; + const auto alphaz = ONE - TWO * betazx - TWO * betazy - THREE * deltaz; + EB(i1, i2, i3, em::bx1) += coeff1 * ( + + alphaz * (EB(i1 , i2 , i3 + 1, em::ex2) - EB(i1 , i2 , i3 , em::ex2)) + + deltaz * (EB(i1 , i2 , i3 + 2, em::ex2) - EB(i1 , i2 , i3 - 1, em::ex2)) + + betazx * (EB(i1 + 1, i2 , i3 + 1, em::ex2) - EB(i1 + 1, i2 , i3 , em::ex2)) + + betazx * (EB(i1 - 1, i2 , i3 + 1, em::ex2) - EB(i1 - 1, i2 , i3 , em::ex2)) + + betazy * (EB(i1 , i2 + 1, i3 + 1, em::ex2) - EB(i1 , i2 + 1, i3 , em::ex2)) + + betazy * (EB(i1 , i2 - 1, i3 + 1, em::ex2) - EB(i1 , i2 - 1, i3 , em::ex2)) + - alphay * (EB(i1 , i2 + 1, i3 , em::ex3) - EB(i1 , i2 , i3 , em::ex3)) + - deltay * (EB(i1 , i2 + 2, i3 , em::ex3) - EB(i1 , i2 - 1, i3 , em::ex3)) + - betayx * (EB(i1 + 1, i2 + 1, i3 , em::ex3) - EB(i1 + 1, i2 , i3 , em::ex3)) + - betayx * (EB(i1 - 1, i2 + 1, i3 , em::ex3) - EB(i1 - 1, i2 , i3 , em::ex3)) + - betayz * (EB(i1 , i2 + 1, i3 + 1, em::ex3) - EB(i1 , i2 , i3 + 1, em::ex3)) + - betayz * (EB(i1 , i2 + 1, i3 - 1, em::ex3) - EB(i1 , i2 , i3 - 1, em::ex3))); + EB(i1, i2, i3, em::bx2) += coeff1 * ( + + alphax * (EB(i1 + 1, i2 , i3 , em::ex3) - EB(i1 , i2 , i3 , em::ex3)) + + deltax * (EB(i1 + 2, i2 , i3 , em::ex3) - EB(i1 - 1, i2 , i3 , em::ex3)) + + betaxy * (EB(i1 + 1, i2 + 1, i3 , em::ex3) - EB(i1 , i2 + 1, i3 , em::ex3)) + + betaxy * (EB(i1 + 1, i2 - 1, i3 , em::ex3) - EB(i1 , i2 - 1, i3 , em::ex3)) + + betaxz * (EB(i1 + 1, i2 , i3 + 1, em::ex3) - EB(i1 , i2 , i3 + 1, em::ex3)) + + betaxz * (EB(i1 + 1, i2 , i3 - 1, em::ex3) - EB(i1 , i2 , i3 - 1, em::ex3)) + - alphaz * (EB(i1 , i2 , i3 + 1, em::ex1) - EB(i1 , i2 , i3 , em::ex1)) + - deltaz * (EB(i1 , i2 , i3 + 2, em::ex1) - EB(i1 , i2 , i3 - 1, em::ex1)) + - betazx * (EB(i1 + 1, i2 , i3 + 1, em::ex1) - EB(i1 + 1, i2 , i3 , em::ex1)) + - betazx * (EB(i1 - 1, i2 , i3 + 1, em::ex1) - EB(i1 - 1, i2 , i3 , em::ex1)) + - betazy * (EB(i1 , i2 + 1, i3 + 1, em::ex1) - EB(i1 , i2 + 1, i3 , em::ex1)) + - betazy * (EB(i1 , i2 - 1, i3 + 1, em::ex1) - EB(i1 , i2 - 1, i3 , em::ex1))); + EB(i1, i2, i3, em::bx3) += coeff1 * ( + + alphay * (EB(i1 , i2 + 1, i3 , em::ex1) - EB(i1 , i2 , i3 , em::ex1)) + + deltay * (EB(i1 , i2 + 2, i3 , em::ex1) - EB(i1 , i2 - 1, i3 , em::ex1)) + + betayx * (EB(i1 + 1, i2 + 1, i3 , em::ex1) - EB(i1 + 1, i2 , i3 , em::ex1)) + + betayx * (EB(i1 - 1, i2 + 1, i3 , em::ex1) - EB(i1 - 1, i2 , i3 , em::ex1)) + + betayz * (EB(i1 , i2 + 1, i3 + 1, em::ex1) - EB(i1 , i2 , i3 + 1, em::ex1)) + + betayz * (EB(i1 , i2 + 1, i3 - 1, em::ex1) - EB(i1 , i2 , i3 - 1, em::ex1)) + - alphax * (EB(i1 + 1, i2 , i3 , em::ex2) - EB(i1 , i2 , i3 , em::ex2)) + - deltax * (EB(i1 + 2, i2 , i3 , em::ex2) - EB(i1 - 1, i2 , i3 , em::ex2)) + - betaxy * (EB(i1 + 1, i2 + 1, i3 , em::ex2) - EB(i1 , i2 + 1, i3 , em::ex2)) + - betaxy * (EB(i1 + 1, i2 - 1, i3 , em::ex2) - EB(i1 , i2 - 1, i3 , em::ex2)) + - betaxz * (EB(i1 + 1, i2 , i3 + 1, em::ex2) - EB(i1 , i2 , i3 + 1, em::ex2)) + - betaxz * (EB(i1 + 1, i2 , i3 - 1, em::ex2) - EB(i1 , i2 , i3 - 1, em::ex2))); } else { raise::KernelError(HERE, "Faraday_kernel: 3D implementation called for D != 3"); } From 0515a9d9d7abdecc8ab0ccf8a8b0ba46f0d5bec8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20B=C3=B6ss?= Date: Wed, 23 Apr 2025 16:17:48 -0500 Subject: [PATCH 653/773] example settings for higher order field solver --- input.example.toml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/input.example.toml b/input.example.toml index bd5d52b06..960d4b7b2 100644 --- a/input.example.toml +++ b/input.example.toml @@ -253,6 +253,21 @@ # @type: float: > 0 gamma_rad = "" + [algorithms.fieldsolver] + # Yee - all 0.0 - default + # 1D + deltax = -0.065 + # 2D + deltay = -0.065 + betaxy = -0.065 + betayx = -0.065 + # 3D - not yet tested + deltaz = 0.0 + betaxz = 0.0 + betazx = 0.0 + betayz = 0.0 + betazy = 0.0 + [particles] # Fiducial number of particles per cell: # @required From 4b670b475572f38283ad7e0b6fea031647a200b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20B=C3=B6ss?= Date: Wed, 23 Apr 2025 16:39:29 -0500 Subject: [PATCH 654/773] bugfix --- CMakeLists.txt | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 20d739786..8c9a8c185 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -95,9 +95,12 @@ elseif("${Kokkos_DEVICES}" MATCHES "HIP") elseif("${Kokkos_DEVICES}" MATCHES "SYCL") add_compile_options("-D SYCL_ENABLED") endif() -if((${Kokkos_DEVICES} MATCHES "CUDA") - OR (${Kokkos_DEVICES} MATCHES "HIP") - OR (${Kokkos_DEVICES} MATCHES "SYCL")) + +if("${Kokkos_DEVICES}" MATCHES "CUDA") + set(DEVICE_ENABLED ON) +elseif("${Kokkos_DEVICES}" MATCHES "HIP") + set(DEVICE_ENABLED ON) +elseif("${Kokkos_DEVICES}" MATCHES "SYCL") set(DEVICE_ENABLED ON) else() set(DEVICE_ENABLED OFF) From 88050f2dd2ffcf6674d08f2755df19295332899b Mon Sep 17 00:00:00 2001 From: hayk Date: Thu, 24 Apr 2025 01:08:43 -0400 Subject: [PATCH 655/773] deposit test pgens --- setups/tests/deposit/deposit-gr.toml | 53 ------------------ setups/tests/deposit/deposit-mink.toml | 44 ++++++++------- setups/tests/deposit/deposit-sr.toml | 42 ++++++++++---- setups/tests/deposit/deposit.toml | 53 ------------------ setups/tests/deposit/pgen.hpp | 76 +++++++++++++++----------- setups/tests/deposit/plot-mink.py | 62 +++++++++++++++++++++ setups/tests/deposit/plot-sr.py | 29 ++++++++++ setups/tests/deposit/run-mink.sh | 14 +++++ 8 files changed, 201 insertions(+), 172 deletions(-) delete mode 100644 setups/tests/deposit/deposit-gr.toml delete mode 100644 setups/tests/deposit/deposit.toml create mode 100644 setups/tests/deposit/plot-mink.py create mode 100644 setups/tests/deposit/plot-sr.py create mode 100755 setups/tests/deposit/run-mink.sh diff --git a/setups/tests/deposit/deposit-gr.toml b/setups/tests/deposit/deposit-gr.toml deleted file mode 100644 index 077e3e59a..000000000 --- a/setups/tests/deposit/deposit-gr.toml +++ /dev/null @@ -1,53 +0,0 @@ -[simulation] - name = "deposit-test" - engine = "srpic" - runtime = 10.0 - -[grid] - resolution = [256, 256] - extent = [[0.0, 1.0], [0.0, 1.0]] - - [grid.metric] - metric = "minkowski" - - [grid.boundaries] - fields = [["PERIODIC"], ["PERIODIC"]] - particles = [["PERIODIC"], ["PERIODIC"]] - -[scales] - larmor0 = 0.1 - skindepth0 = 0.1 - -[algorithms] - current_filters = 4 - - [algorithms.timestep] - CFL = 0.5 - -[particles] - ppc0 = 10.0 - - [[particles.species]] - label = "e-" - mass = 1.0 - charge = -1.0 - maxnpart = 1e2 - - [[particles.species]] - label = "e+" - mass = 1.0 - charge = 1.0 - maxnpart = 1e2 - -[setup] - -[output] - format = "hdf5" - interval_time = 0.01 - - [output.quantities] - quantities = ["N_1", "N_2", "E", "B", "J"] - -[diagnostics] - colored_stdout = true - blocking_timers = true diff --git a/setups/tests/deposit/deposit-mink.toml b/setups/tests/deposit/deposit-mink.toml index df70f7552..2dc953896 100644 --- a/setups/tests/deposit/deposit-mink.toml +++ b/setups/tests/deposit/deposit-mink.toml @@ -1,10 +1,10 @@ [simulation] name = "deposit-test-mink" engine = "srpic" - runtime = 10.0 + runtime = 5.0 [grid] - resolution = [512, 512] + resolution = [32, 32] extent = [[0.0, 1.0], [0.0, 1.0]] [grid.metric] @@ -40,30 +40,32 @@ maxnpart = 1e2 [setup] - x1s = [0.25] - y1s = [0.85] - z1s = [0.33] - ux1s = [0.6] - uy1s = [-0.3] - uz1s = [-0.2] - - x2s = [0.25] - y2s = [0.85] - z2s = [0.33] - ux2s = [-0.2] - uy2s = [-0.2] - uz2s = [0.1] + x1_e = [0.25] + x2_e = [0.85] + x3_e = [0.33] + ux1_e = [0.6] + ux2_e = [-0.3] + ux3_e = [-0.2] + + x1_i = [0.25] + x2_i = [0.85] + x3_i = [0.33] + ux1_i = [-0.6] + ux2_i = [0.3] + ux3_i = [0.2] [output] - format = "hdf5" - interval_time = 0.01 + format = "hdf5" + interval = 5 [output.fields] quantities = ["N_1", "N_2", "E", "B", "J"] + [output.particles] + enable = false + + [output.spectra] + enable = false + [checkpoint] keep = 0 - -[diagnostics] - colored_stdout = true - blocking_timers = true diff --git a/setups/tests/deposit/deposit-sr.toml b/setups/tests/deposit/deposit-sr.toml index 077e3e59a..0e1648d12 100644 --- a/setups/tests/deposit/deposit-sr.toml +++ b/setups/tests/deposit/deposit-sr.toml @@ -1,18 +1,18 @@ [simulation] - name = "deposit-test" + name = "deposit-sr" engine = "srpic" runtime = 10.0 [grid] - resolution = [256, 256] - extent = [[0.0, 1.0], [0.0, 1.0]] + resolution = [64, 64] + extent = [[1.0, 5.0]] [grid.metric] - metric = "minkowski" + metric = "qspherical" [grid.boundaries] - fields = [["PERIODIC"], ["PERIODIC"]] - particles = [["PERIODIC"], ["PERIODIC"]] + fields = [["FIXED", "FIXED"]] + particles = [["REFLECT", "REFLECT"]] [scales] larmor0 = 0.1 @@ -40,14 +40,32 @@ maxnpart = 1e2 [setup] + x1_e = [2.25] + x2_e = [1.25] + phi_e = [0.0] + ux1_e = [0.6] + ux2_e = [-0.3] + ux3_e = [-0.2] + + x1_i = [2.25] + x2_i = [1.25] + phi_i = [0.0] + ux1_i = [-0.6] + ux2_i = [0.3] + ux3_i = [0.2] [output] - format = "hdf5" - interval_time = 0.01 + format = "hdf5" + interval = 5 - [output.quantities] + [output.fields] quantities = ["N_1", "N_2", "E", "B", "J"] -[diagnostics] - colored_stdout = true - blocking_timers = true + [output.particles] + enable = false + + [output.spectra] + enable = false + +[checkpoint] + keep = 0 diff --git a/setups/tests/deposit/deposit.toml b/setups/tests/deposit/deposit.toml deleted file mode 100644 index 04c23ce7d..000000000 --- a/setups/tests/deposit/deposit.toml +++ /dev/null @@ -1,53 +0,0 @@ -[simulation] - name = "deposit-test" - engine = "srpic" - runtime = 1.0 - -[grid] - resolution = [256, 256] - extent = [[0.0, 1.0], [0.0, 1.0]] - - [grid.metric] - metric = "minkowski" - - [grid.boundaries] - fields = [["PERIODIC"], ["PERIODIC"]] - particles = [["PERIODIC"], ["PERIODIC"]] - -[scales] - larmor0 = 0.1 - skindepth0 = 0.1 - -[algorithms] - current_filters = 4 - - [algorithms.timestep] - CFL = 0.5 - -[particles] - ppc0 = 10.0 - - [[particles.species]] - label = "e-" - mass = 1.0 - charge = -1.0 - maxnpart = 1e2 - - [[particles.species]] - label = "e+" - mass = 1.0 - charge = 1.0 - maxnpart = 1e2 - -[setup] - -[output] - format = "hdf5" - interval_time = 0.01 - - [output.quantities] - quantities = ["N_1", "N_2", "E", "B", "J"] - -[diagnostics] - colored_stdout = true - blocking_timers = true diff --git a/setups/tests/deposit/pgen.hpp b/setups/tests/deposit/pgen.hpp index dc1bd6380..0080af8fd 100644 --- a/setups/tests/deposit/pgen.hpp +++ b/setups/tests/deposit/pgen.hpp @@ -48,53 +48,63 @@ namespace user { inline void InitPrtls(Domain& local_domain) { const auto empty = std::vector {}; - const auto x1s = params.template get>("setup.x1s", empty); - const auto y1s = params.template get>("setup.y1s", empty); - const auto z1s = params.template get>("setup.z1s", empty); - const auto phi1s = params.template get>("setup.phi1s", - empty); - const auto ux1s = params.template get>("setup.ux1s", + const auto x1_e = params.template get>("setup.x1_e", empty); - const auto uy1s = params.template get>("setup.uy1s", + const auto x2_e = params.template get>("setup.x2_e", empty); - const auto uz1s = params.template get>("setup.uz1s", + const auto x3_e = params.template get>("setup.x3_e", empty); + const auto phi_e = params.template get>("setup.phi_e", + empty); + const auto ux1_e = params.template get>("setup.ux1_e", + empty); + const auto ux2_e = params.template get>("setup.ux2_e", + empty); + const auto ux3_e = params.template get>("setup.ux3_e", + empty); - const auto x2s = params.template get>("setup.x2s", empty); - const auto y2s = params.template get>("setup.y2s", empty); - const auto z2s = params.template get>("setup.z2s", empty); - const auto ux2s = params.template get>("setup.ux2s", + const auto x1_i = params.template get>("setup.x1_i", empty); - const auto uy2s = params.template get>("setup.uy2s", + const auto x2_i = params.template get>("setup.x2_i", empty); - const auto uz2s = params.template get>("setup.uz2s", + const auto x3_i = params.template get>("setup.x3_i", empty); - const auto phi2s = params.template get>("setup.phi2s", + const auto phi_i = params.template get>("setup.phi_i", empty); - std::map> data_1 { - { "x1", x1s }, - { "x2", y1s }, - { "ux1", ux1s }, - { "ux2", uy1s }, - { "ux3", uz1s } + const auto ux1_i = params.template get>("setup.ux1_i", + empty); + const auto ux2_i = params.template get>("setup.ux2_i", + empty); + const auto ux3_i = params.template get>("setup.ux3_i", + empty); + std::map> data_e { + { "x1", x1_e }, + { "x2", x2_e }, + { "ux1", ux1_e }, + { "ux2", ux2_e }, + { "ux3", ux3_e } }; - std::map> data_2 { - { "x1", x2s }, - { "x2", y2s }, - { "ux1", ux2s }, - { "ux2", uy2s }, - { "ux3", uz2s } + std::map> data_i { + { "x1", x1_i }, + { "x2", x2_i }, + { "ux1", ux1_i }, + { "ux2", ux2_i }, + { "ux3", ux3_i } }; if constexpr (M::CoordType == Coord::Cart or D == Dim::_3D) { - data_1["x3"] = z1s; - data_2["x3"] = z2s; + data_e["x3"] = x3_e; + data_i["x3"] = x3_i; } else if constexpr (D == Dim::_2D) { - data_1["phi"] = phi1s; - data_2["phi"] = phi2s; + data_e["phi"] = phi_e; + data_i["phi"] = phi_i; } - arch::InjectGlobally(global_domain, local_domain, (spidx_t)1, data_1); - arch::InjectGlobally(global_domain, local_domain, (spidx_t)2, data_2); + arch::InjectGlobally(global_domain, local_domain, (spidx_t)1, data_e); + arch::InjectGlobally(global_domain, local_domain, (spidx_t)2, data_i); + } + + auto FixFieldsConst(const bc_in&, const em&) const -> std::pair { + return { ZERO, false }; } }; diff --git a/setups/tests/deposit/plot-mink.py b/setups/tests/deposit/plot-mink.py new file mode 100644 index 000000000..9d6760613 --- /dev/null +++ b/setups/tests/deposit/plot-mink.py @@ -0,0 +1,62 @@ +import nt2 +import matplotlib.pyplot as plt +import matplotlib as mpl + +datas = [] +cpus = [1, 2, 3, 4, 5, 6, 8] +for i in cpus: + datas.append(nt2.Data(path=f"mink-np{i}")) + + +def plot(ti): + fig = plt.figure(figsize=(16, 7), dpi=300) + gs = mpl.gridspec.GridSpec(3, 7, figure=fig) + + for p, quant in enumerate(["Jx", "Jy", "Jz"]): + axs = [fig.add_subplot(gs[p, i]) for i in range(7)] + (datas[0].fields[quant]).isel(t=ti).plot( + ax=axs[0], + cmap="seismic", + add_colorbar=False, + norm=mpl.colors.SymLogNorm( + linthresh=1e-5, + linscale=1, + vmin=-1e-2, + vmax=1e-2, + ), + ) + for i, (d, ax) in enumerate(zip(datas[1:], axs[1:])): + (d.fields[quant] - datas[0].fields[quant]).isel(t=ti).plot( + ax=ax, + cmap="seismic", + add_colorbar=False, + norm=mpl.colors.SymLogNorm( + linthresh=1e-10, + linscale=1, + vmin=-1e-7, + vmax=1e-7, + ), + ) + + for i, ax in enumerate(axs): + ax.set_aspect(1) + if i > 0: + if p == 0: + ax.set_title(f"np{cpus[i]} - np1") + else: + ax.set_title(None) + ax.set_yticklabels([]) + ax.set_ylabel(None) + else: + if p == 0: + ax.set_title(f"np1") + else: + ax.set_title(None) + + if p != 2: + ax.set_xticklabels([]) + ax.set_xlabel(None) + + +nt2.export.makeFrames(plot, datas[0].fields.s[::4], "mink-diff", num_cpus=4) +nt2.export.makeMovie(framerate=10, input="mink-diff/", number=5, output="mink-diff.mp4") diff --git a/setups/tests/deposit/plot-sr.py b/setups/tests/deposit/plot-sr.py new file mode 100644 index 000000000..0ba5dff24 --- /dev/null +++ b/setups/tests/deposit/plot-sr.py @@ -0,0 +1,29 @@ +import nt2 +import matplotlib.pyplot as plt +import matplotlib as mpl + +data = nt2.Data(path=f"sr-np8") + + +def plot(ti): + fig = plt.figure(figsize=(9, 6), dpi=300) + gs = mpl.gridspec.GridSpec(1, 3, figure=fig) + axs = [fig.add_subplot(gs[0, i]) for i in range(3)] + for i, (ax, j) in enumerate(zip(axs, ["Jr", "Jth", "Jph"])): + data.fields.isel(t=ti)[j].polar.pcolor( + ax=ax, + cbar_position="top", + cbar_size="2%", + norm=mpl.colors.SymLogNorm(linthresh=1e-8, vmin=-1e-4, vmax=1e-4), + cmap="seismic", + ) + ax.set_title(None) + ax.add_artist(mpl.patches.Circle((0, 0), 1, color="k", alpha=0.2)) + ax.add_artist(mpl.patches.Circle((0, 0), 5, edgecolor="k", facecolor="none")) + if i > 0: + ax.set_yticklabels([]) + ax.set_ylabel(None) + + +nt2.export.makeFrames(plot, data.fields.s, "sr-dep", num_cpus=4) +nt2.export.makeMovie(framerate=10, input="sr-dep/", number=5, output="sr-dep.mp4") diff --git a/setups/tests/deposit/run-mink.sh b/setups/tests/deposit/run-mink.sh new file mode 100755 index 000000000..4b52d6642 --- /dev/null +++ b/setups/tests/deposit/run-mink.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash + +for i in {1..8}; do + if [ $i -eq 7 ]; then + continue + fi + run=$(echo "np${i}") + cp deposit-mink.toml deposit-mink-${run}.toml && \ + sed -i 's/name[[:space:]]*=[[:space:]]*".*\?"/name = "mink-'${run}'"/g' deposit-mink-${run}.toml && \ + mpiexec -np ${i} ./entity.xc -input deposit-mink-${run}.toml && \ + rm deposit-mink-${run}.toml +done + +rm *.info *.err *.log *.csv From 19527083002468889fa967c2eedc041f33e79ace Mon Sep 17 00:00:00 2001 From: hayk Date: Thu, 24 Apr 2025 01:12:35 -0400 Subject: [PATCH 656/773] added quotes --- CMakeLists.txt | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8c9a8c185..cbea5ab55 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -96,11 +96,9 @@ elseif("${Kokkos_DEVICES}" MATCHES "SYCL") add_compile_options("-D SYCL_ENABLED") endif() -if("${Kokkos_DEVICES}" MATCHES "CUDA") - set(DEVICE_ENABLED ON) -elseif("${Kokkos_DEVICES}" MATCHES "HIP") - set(DEVICE_ENABLED ON) -elseif("${Kokkos_DEVICES}" MATCHES "SYCL") +if(("${Kokkos_DEVICES}" MATCHES "CUDA") + OR ("${Kokkos_DEVICES}" MATCHES "HIP") + OR ("${Kokkos_DEVICES}" MATCHES "SYCL")) set(DEVICE_ENABLED ON) else() set(DEVICE_ENABLED OFF) From 30d0afde4f778286bfed12e47af1c63ac880fb77 Mon Sep 17 00:00:00 2001 From: hayk Date: Thu, 24 Apr 2025 01:20:26 -0400 Subject: [PATCH 657/773] mpi_device_copy default to OFF --- cmake/defaults.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/defaults.cmake b/cmake/defaults.cmake index 9829ea14d..d106f420b 100644 --- a/cmake/defaults.cmake +++ b/cmake/defaults.cmake @@ -69,7 +69,7 @@ if(DEFINED ENV{Entity_MPI_DEVICE_COPY}) CACHE INTERNAL "Default flag for copying from device to host for MPI") else() set(default_mpi_device_copy - ON + OFF CACHE INTERNAL "Default flag for copying from device to host for MPI") endif() From d71883c87fcf39a4c764049edaac7522a4a49fdf Mon Sep 17 00:00:00 2001 From: hayk Date: Thu, 24 Apr 2025 02:04:48 -0400 Subject: [PATCH 658/773] rm coeff in match bcs --- input.example.toml | 4 ---- src/framework/parameters.cpp | 9 --------- src/framework/tests/parameters.cpp | 14 -------------- src/global/defaults.h | 1 - 4 files changed, 28 deletions(-) diff --git a/input.example.toml b/input.example.toml index bd5d52b06..4a671fab6 100644 --- a/input.example.toml +++ b/input.example.toml @@ -115,10 +115,6 @@ # @example: ds = [[1.5], [2.0, 1.0], [1.1]] (will duplicate 1.5 for +/- x1 and 1.1 for +/- x3) # @example: ds = [[], [1.5], []] (will only set for x2) ds = "" - # Absorption coefficient for fields: - # @type: float: -inf < ... < inf, != 0 - # @default: 1.0 - coeff = "" [grid.boundaries.absorb] # Size of the absorption layer for particles in physical (code) units: diff --git a/src/framework/parameters.cpp b/src/framework/parameters.cpp index 26f542956..73fdcb2c8 100644 --- a/src/framework/parameters.cpp +++ b/src/framework/parameters.cpp @@ -353,7 +353,6 @@ namespace ntt { for (const auto& bc : bcs) { if (fmt::toLower(bc) == "match") { promiseToDefine("grid.boundaries.match.ds"); - promiseToDefine("grid.boundaries.match.coeff"); } if (fmt::toLower(bc) == "atmosphere") { raise::ErrorIf(atm_defined, @@ -799,14 +798,6 @@ namespace ntt { }; set("grid.boundaries.match.ds", ds_array); } - - set("grid.boundaries.match.coeff", - toml::find_or(toml_data, - "grid", - "boundaries", - "match", - "coeff", - defaults::bc::match::coeff)); } if (isPromised("grid.boundaries.absorb.ds")) { diff --git a/src/framework/tests/parameters.cpp b/src/framework/tests/parameters.cpp index c4d1f0e7b..07b2c11b3 100644 --- a/src/framework/tests/parameters.cpp +++ b/src/framework/tests/parameters.cpp @@ -33,7 +33,6 @@ const auto mink_1d = u8R"( particles = [["ABSORB", "ABSORB"]] [grid.boundaries.match] - coeff = 10.0 ds = [[0.025, 0.1]] [scales] @@ -104,9 +103,6 @@ const auto sph_2d = u8R"( fields = [["ATMOSPHERE", "MATCH"]] particles = [["ATMOSPHERE", "ABSORB"]] - [grid.boundaries.match] - coeff = 10.0 - [grid.boundaries.atmosphere] temperature = 0.1 density = 1.0 @@ -395,11 +391,6 @@ auto main(int argc, char* argv[]) -> int { (real_t)(defaults::bc::match::ds_frac * 19.0), "grid.boundaries.match.ds"); - assert_equal( - params_sph_2d.get("grid.boundaries.match.coeff"), - (real_t)10.0, - "grid.boundaries.match.coeff"); - assert_equal(params_sph_2d.get("particles.use_weights"), true, "particles.use_weights"); @@ -551,11 +542,6 @@ auto main(int argc, char* argv[]) -> int { (real_t)(defaults::bc::match::ds_frac * (100.0 - 0.8)), "grid.boundaries.match.ds"); - assert_equal( - params_qks_2d.get("grid.boundaries.match.coeff"), - defaults::bc::match::coeff, - "grid.boundaries.match.coeff"); - const auto species = params_qks_2d.get>( "particles.species"); assert_equal(species[0].label(), "e-", "species[0].label"); diff --git a/src/global/defaults.h b/src/global/defaults.h index e44103ed0..d673a503c 100644 --- a/src/global/defaults.h +++ b/src/global/defaults.h @@ -43,7 +43,6 @@ namespace ntt::defaults { namespace bc { namespace match { const real_t ds_frac = 0.01; - const real_t coeff = 1.0; } // namespace match namespace absorb { From 5d7c25492358341ab5a604c15b301456f0b37873 Mon Sep 17 00:00:00 2001 From: haykh Date: Thu, 24 Apr 2025 10:47:24 -0400 Subject: [PATCH 659/773] reformat comm --- src/framework/domain/comm_mpi.hpp | 282 +++++++++++------------------- 1 file changed, 99 insertions(+), 183 deletions(-) diff --git a/src/framework/domain/comm_mpi.hpp b/src/framework/domain/comm_mpi.hpp index f63761afd..d6b876a4f 100644 --- a/src/framework/domain/comm_mpi.hpp +++ b/src/framework/domain/comm_mpi.hpp @@ -33,6 +33,86 @@ namespace comm { using namespace ntt; + namespace { + template + void send_recv(const array_t& send_buff, + array_t& recv_buff, + npart_t nsend, + npart_t nrecv, + int send_rank, + int recv_rank, + npart_t recv_offset = 0u) { +#if defined(MPI_DEVICE_COPY) + auto send_buff_h = Kokkos::create_mirror_view(send_buff); + auto recv_buff_h = Kokkos::create_mirror_view(recv_buff); + Kokkos::deep_copy(send_buff_h, send_buff); + MPI_Sendrecv(send_buff_h.data(), + nsend, + mpi::get_type(), + send_rank, + 0, + recv_buff_h.data() + recv_offset, + nrecv, + mpi::get_type(), + recv_rank, + 0, + MPI_COMM_WORLD, + MPI_STATUS_IGNORE); + Kokkos::deep_copy(recv_buff, recv_buff_h); +#else + MPI_Sendrecv(send_buff.data(), + nsend, + mpi::get_type(), + send_rank, + 0, + recv_buff.data() + recv_offset, + nrecv, + mpi::get_type(), + recv_rank, + 0, + MPI_COMM_WORLD, + MPI_STATUS_IGNORE); +#endif + } + + template + void send(const array_t& send_buff, npart_t nsend, int send_rank) { +#if defined(MPI_DEVICE_COPY) + auto send_buff_h = Kokkos::create_mirror_view(send_buff); + Kokkos::deep_copy(send_buff_h, send_buff); + MPI_Send(send_buff_h.data(), nsend, mpi::get_type(), send_rank, 0, MPI_COMM_WORLD); +#else + MPI_Send(send_buff.data(), nsend, mpi::get_type(), send_rank, 0, MPI_COMM_WORLD); +#endif + } + + template + void recv(const array_t& recv_buff, + npart_t nrecv, + int recv_rank, + npart_t recv_offset = 0u) { +#if defined(MPI_DEVICE_COPY) + auto recv_buff_h = Kokkos::create_mirror_view(recv_buff); + MPI_Recv(recv_buff_h.data() + recv_offset, + nrecv, + mpi::get_type(), + recv_rank, + 0, + MPI_COMM_WORLD, + MPI_STATUS_IGNORE); + Kokkos::deep_copy(recv_buff, recv_buff_h); +#else + MPI_Recv(recv_buff.data() + recv_offset, + nrecv, + mpi::get_type(), + recv_rank, + 0, + MPI_COMM_WORLD, + MPI_STATUS_IGNORE); +#endif + } + } // namespace + template inline void CommunicateField(unsigned int idx, ndfield_t& fld, @@ -186,75 +266,11 @@ namespace comm { } if (send_rank >= 0 && recv_rank >= 0) { -#if defined(MPI_DEVICE_COPY) - auto send_fld_h = Kokkos::create_mirror_view(send_fld); - auto recv_fld_h = Kokkos::create_mirror_view(recv_fld); - Kokkos::deep_copy(send_fld_h, send_fld); - MPI_Sendrecv(send_fld_h.data(), - nsend, - mpi::get_type(), - send_rank, - 0, - recv_fld_h.data(), - nrecv, - mpi::get_type(), - recv_rank, - 0, - MPI_COMM_WORLD, - MPI_STATUS_IGNORE); - Kokkos::deep_copy(recv_fld, recv_fld_h); -#else - MPI_Sendrecv(send_fld.data(), - nsend, - mpi::get_type(), - send_rank, - 0, - recv_fld.data(), - nrecv, - mpi::get_type(), - recv_rank, - 0, - MPI_COMM_WORLD, - MPI_STATUS_IGNORE); -#endif + sendrecv(send_fld, recv_fld, nsend, nrecv, send_rank, recv_rank); } else if (send_rank >= 0) { -#if defined(MPI_DEVICE_COPY) - auto send_fld_h = Kokkos::create_mirror_view(send_fld); - Kokkos::deep_copy(send_fld_h, send_fld); - MPI_Send(send_fld_h.data(), - nsend, - mpi::get_type(), - send_rank, - 0, - MPI_COMM_WORLD); -#else - MPI_Send(send_fld.data(), - nsend, - mpi::get_type(), - send_rank, - 0, - MPI_COMM_WORLD); -#endif + send(send_fld, nsend, send_rank); } else if (recv_rank >= 0) { -#if defined(MPI_DEVICE_COPY) - auto recv_fld_h = Kokkos::create_mirror_view(recv_fld); - MPI_Recv(recv_fld_h.data(), - nrecv, - mpi::get_type(), - recv_rank, - 0, - MPI_COMM_WORLD, - MPI_STATUS_IGNORE); - Kokkos::deep_copy(recv_fld, recv_fld_h); -#else - MPI_Recv(recv_fld.data(), - nrecv, - mpi::get_type(), - recv_rank, - 0, - MPI_COMM_WORLD, - MPI_STATUS_IGNORE); -#endif + recv(recv_fld, nrecv, recv_rank); } else { raise::Error("CommunicateField called with negative ranks", HERE); } @@ -359,101 +375,6 @@ namespace comm { } } - namespace { - template - void send_recv(const array_t& send_buff, - array_t& recv_buff, - unsigned short Narrs, - npart_t nsend, - npart_t nrecv, - int send_rank, - int recv_rank, - npart_t recv_offset) { -#if defined(MPI_DEVICE_COPY) - auto send_buff_h = Kokkos::create_mirror_view(send_buff); - auto recv_buff_h = Kokkos::create_mirror_view(recv_buff); - Kokkos::deep_copy(send_buff_h, send_buff); - MPI_Sendrecv(send_buff_h.data(), - nsend * Narrs, - mpi::get_type(), - send_rank, - 0, - recv_buff_h.data() + recv_offset, - nrecv * Narrs, - mpi::get_type(), - recv_rank, - 0, - MPI_COMM_WORLD, - MPI_STATUS_IGNORE); - Kokkos::deep_copy(recv_buff, recv_buff_h); -#else - MPI_Sendrecv(send_buff.data(), - nsend * Narrs, - mpi::get_type(), - send_rank, - 0, - recv_buff.data() + recv_offset, - nrecv * Narrs, - mpi::get_type(), - recv_rank, - 0, - MPI_COMM_WORLD, - MPI_STATUS_IGNORE); -#endif - } - - template - void send(const array_t& send_buff, - unsigned short Narrs, - npart_t nsend, - int send_rank) { -#if defined(MPI_DEVICE_COPY) - auto send_buff_h = Kokkos::create_mirror_view(send_buff); - Kokkos::deep_copy(send_buff_h, send_buff); - MPI_Send(send_buff_h.data(), - nsend * Narrs, - mpi::get_type(), - send_rank, - 0, - MPI_COMM_WORLD); -#else - MPI_Send(send_buff.data(), - nsend * Narrs, - mpi::get_type(), - send_rank, - 0, - MPI_COMM_WORLD); -#endif - } - - template - void recv(const array_t& recv_buff, - unsigned short Narrs, - npart_t nrecv, - int recv_rank, - npart_t recv_offset) { -#if defined(MPI_DEVICE_COPY) - auto recv_buff_h = Kokkos::create_mirror_view(recv_buff); - MPI_Recv(recv_buff_h.data() + recv_offset, - nrecv * Narrs, - mpi::get_type(), - recv_rank, - 0, - MPI_COMM_WORLD, - MPI_STATUS_IGNORE); - Kokkos::deep_copy(recv_buff, recv_buff_h); -#else - MPI_Recv(recv_buff.data() + recv_offset, - nrecv * Narrs, - mpi::get_type(), - recv_rank, - 0, - MPI_COMM_WORLD, - MPI_STATUS_IGNORE); -#endif - } - } // namespace - template void CommunicateParticles(Particles& species, const array_t& outgoing_indices, @@ -542,27 +463,24 @@ namespace comm { HERE); send_recv(send_buff_int, recv_buff_int, - NINTS, - npart_send_in, - npart_recv_in, + NINTS * npart_send_in, + NINTS * npart_recv_in, send_rank, recv_rank, recv_offset_int); send_recv(send_buff_real, recv_buff_real, - NREALS, - npart_send_in, - npart_recv_in, + NREALS * npart_send_in, + NREALS * npart_recv_in, send_rank, recv_rank, recv_offset_real); send_recv(send_buff_prtldx, recv_buff_prtldx, - NPRTLDX, - npart_send_in, - npart_recv_in, + NPRTLDX * npart_send_in, + NPRTLDX * npart_recv_in, send_rank, recv_rank, recv_offset_prtldx); @@ -570,19 +488,18 @@ namespace comm { if (NPLDS > 0) { send_recv(send_buff_pld, recv_buff_pld, - NPLDS, - npart_send_in, - npart_recv_in, + NPLDS * npart_send_in, + NPLDS * npart_recv_in, send_rank, recv_rank, recv_offset_pld); } } else if ((send_rank >= 0) and (npart_send_in > 0)) { - send(send_buff_int, NINTS, npart_send_in, send_rank); - send(send_buff_real, NREALS, npart_send_in, send_rank); - send(send_buff_prtldx, NPRTLDX, npart_send_in, send_rank); + send(send_buff_int, NINTS * npart_send_in, send_rank); + send(send_buff_real, NREALS * npart_send_in, send_rank); + send(send_buff_prtldx, NPRTLDX * npart_send_in, send_rank); if (NPLDS > 0) { - send(send_buff_pld, NPLDS, npart_send_in, send_rank); + send(send_buff_pld, NPLDS * npart_send_in, send_rank); } } else if ((recv_rank >= 0) and (npart_recv_in > 0)) { raise::ErrorIf(recv_offset_int + npart_recv_in * NINTS > @@ -590,15 +507,14 @@ namespace comm { "incorrect # of recv particles", HERE); - recv(recv_buff_int, NINTS, npart_recv_in, recv_rank, recv_offset_int); - recv(recv_buff_real, NREALS, npart_recv_in, recv_rank, recv_offset_real); + recv(recv_buff_int, NINTS * npart_recv_in, recv_rank, recv_offset_int); + recv(recv_buff_real, NREALS * npart_recv_in, recv_rank, recv_offset_real); recv(recv_buff_prtldx, - NPRTLDX, - npart_recv_in, + NPRTLDX * npart_recv_in, recv_rank, recv_offset_prtldx); if (NPLDS > 0) { - recv(recv_buff_pld, NPLDS, npart_recv_in, recv_rank, recv_offset_pld); + recv(recv_buff_pld, NPLDS * npart_recv_in, recv_rank, recv_offset_pld); } } current_received += npart_recv_in; From 1eccfa4a774dc59a7c6bdc2e13f45796a5f38b80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20B=C3=B6ss?= Date: Thu, 24 Apr 2025 12:58:05 -0500 Subject: [PATCH 660/773] Revert "example settings for higher order field solver" This reverts commit 0515a9d9d7abdecc8ab0ccf8a8b0ba46f0d5bec8. --- input.example.toml | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/input.example.toml b/input.example.toml index 960d4b7b2..bd5d52b06 100644 --- a/input.example.toml +++ b/input.example.toml @@ -253,21 +253,6 @@ # @type: float: > 0 gamma_rad = "" - [algorithms.fieldsolver] - # Yee - all 0.0 - default - # 1D - deltax = -0.065 - # 2D - deltay = -0.065 - betaxy = -0.065 - betayx = -0.065 - # 3D - not yet tested - deltaz = 0.0 - betaxz = 0.0 - betazx = 0.0 - betayz = 0.0 - betazy = 0.0 - [particles] # Fiducial number of particles per cell: # @required From 82cf56b3fffe699836cb75b16de7eec0af2cc4ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludwig=20B=C3=B6ss?= Date: Thu, 24 Apr 2025 12:58:30 -0500 Subject: [PATCH 661/773] Revert "higher order Faraday kernel implemented by @vanthieg" This reverts commit b1ebdf17180d1aefcf92b257645d4e1b1ebf35b3. --- src/engines/srpic.hpp | 36 ++--------- src/framework/parameters.cpp | 63 ++----------------- src/global/defaults.h | 14 ----- src/kernels/faraday_mink.hpp | 119 +++++++---------------------------- 4 files changed, 32 insertions(+), 200 deletions(-) diff --git a/src/engines/srpic.hpp b/src/engines/srpic.hpp index 8f8215f1e..a10070c34 100644 --- a/src/engines/srpic.hpp +++ b/src/engines/srpic.hpp @@ -185,24 +185,6 @@ namespace ntt { if constexpr (M::CoordType == Coord::Cart) { // minkowski case const auto dx = math::sqrt(domain.mesh.metric.template h_<1, 1>({})); - const auto deltax = m_params.template get( - "algorithms.fieldsolver.deltax"); - const auto deltay = m_params.template get( - "algorithms.fieldsolver.deltay"); - const auto betaxy = m_params.template get( - "algorithms.fieldsolver.betaxy"); - const auto betayx = m_params.template get( - "algorithms.fieldsolver.betayx"); - const auto deltaz = m_params.template get( - "algorithms.fieldsolver.deltaz"); - const auto betaxz = m_params.template get( - "algorithms.fieldsolver.betaxz"); - const auto betazx = m_params.template get( - "algorithms.fieldsolver.betazx"); - const auto betayz = m_params.template get( - "algorithms.fieldsolver.betayz"); - const auto betazy = m_params.template get( - "algorithms.fieldsolver.betazy"); real_t coeff1, coeff2; if constexpr (M::Dim == Dim::_2D) { coeff1 = dT / SQR(dx); @@ -211,20 +193,10 @@ namespace ntt { coeff1 = dT / dx; coeff2 = ZERO; } - Kokkos::parallel_for("Faraday", - domain.mesh.rangeActiveCells(), - kernel::mink::Faraday_kernel(domain.fields.em, - coeff1, - coeff2, - deltax, - deltay, - betaxy, - betayx, - deltaz, - betaxz, - betazx, - betayz, - betazy)); + Kokkos::parallel_for( + "Faraday", + domain.mesh.rangeActiveCells(), + kernel::mink::Faraday_kernel(domain.fields.em, coeff1, coeff2)); } else { Kokkos::parallel_for("Faraday", domain.mesh.rangeActiveCells(), diff --git a/src/framework/parameters.cpp b/src/framework/parameters.cpp index 42655b207..8a30f52d9 100644 --- a/src/framework/parameters.cpp +++ b/src/framework/parameters.cpp @@ -31,10 +31,10 @@ namespace ntt { template - auto get_dx0_V0(const std::vector& resolution, - const boundaries_t& extent, - const std::map& params) - -> std::pair { + auto get_dx0_V0( + const std::vector& resolution, + const boundaries_t& extent, + const std::map& params) -> std::pair { const auto metric = M(resolution, extent, params); const auto dx0 = metric.dxMin(); coord_t x_corner { ZERO }; @@ -416,61 +416,6 @@ namespace ntt { set("algorithms.toggles.deposit", toml::find_or(toml_data, "algorithms", "toggles", "deposit", true)); - /* [algorithms.fieldsolver] --------------------------------------------- */ - set("algorithms.fieldsolver.deltax", - toml::find_or(toml_data, - "algorithms", - "fieldsolver", - "deltax", - defaults::fieldsolver::deltax)); - set("algorithms.fieldsolver.deltay", - toml::find_or(toml_data, - "algorithms", - "fieldsolver", - "deltay", - defaults::fieldsolver::deltay)); - set("algorithms.fieldsolver.deltaz", - toml::find_or(toml_data, - "algorithms", - "fieldsolver", - "deltaz", - defaults::fieldsolver::deltaz)); - set("algorithms.fieldsolver.betaxy", - toml::find_or(toml_data, - "algorithms", - "fieldsolver", - "betaxy", - defaults::fieldsolver::betaxy)); - set("algorithms.fieldsolver.betayx", - toml::find_or(toml_data, - "algorithms", - "fieldsolver", - "betayx", - defaults::fieldsolver::betayx)); - set("algorithms.fieldsolver.betaxz", - toml::find_or(toml_data, - "algorithms", - "fieldsolver", - "betaxz", - defaults::fieldsolver::betaxz)); - set("algorithms.fieldsolver.betazx", - toml::find_or(toml_data, - "algorithms", - "fieldsolver", - "betazx", - defaults::fieldsolver::betazx)); - set("algorithms.fieldsolver.betayz", - toml::find_or(toml_data, - "algorithms", - "fieldsolver", - "betayz", - defaults::fieldsolver::betayz)); - set("algorithms.fieldsolver.betazy", - toml::find_or(toml_data, - "algorithms", - "fieldsolver", - "betazy", - defaults::fieldsolver::betazy)); /* [algorithms.timestep] ------------------------------------------------ */ set("algorithms.timestep.CFL", toml::find_or(toml_data, "algorithms", "timestep", "CFL", defaults::cfl)); diff --git a/src/global/defaults.h b/src/global/defaults.h index b5120d6e4..e44103ed0 100644 --- a/src/global/defaults.h +++ b/src/global/defaults.h @@ -26,20 +26,6 @@ namespace ntt::defaults { const std::string ph_pusher = "Photon"; const timestep_t clear_interval = 100; - namespace fieldsolver { - const real_t deltax = 0.0; - - const real_t deltay = 0.0; - const real_t betaxy = 0.0; - const real_t betayx = 0.0; - - const real_t deltaz = 0.0; - const real_t betaxz = 0.0; - const real_t betazx = 0.0; - const real_t betayz = 0.0; - const real_t betazy = 0.0; - } // namespace fieldsolver - namespace qsph { const real_t r0 = 0.0; const real_t h = 0.0; diff --git a/src/kernels/faraday_mink.hpp b/src/kernels/faraday_mink.hpp index 1112e56e7..6d249b999 100644 --- a/src/kernels/faraday_mink.hpp +++ b/src/kernels/faraday_mink.hpp @@ -26,15 +26,6 @@ namespace kernel::mink { ndfield_t EB; const real_t coeff1; const real_t coeff2; - const real_t deltax; - const real_t deltay; - const real_t betaxy; - const real_t betayx; - const real_t deltaz; - const real_t betaxz; - const real_t betazx; - const real_t betayz; - const real_t betazy; public: /** @@ -42,34 +33,15 @@ namespace kernel::mink { * ! 2D: coeff1 = dt / dx^2, coeff2 = dt * ! 3D: coeff1 = dt / dx */ - Faraday_kernel(const ndfield_t& EB, real_t coeff1, real_t coeff2 - , real_t deltax, real_t deltay, real_t betaxy, real_t betayx - , real_t deltaz, real_t betaxz, real_t betazx, real_t betayz - , real_t betazy) + Faraday_kernel(const ndfield_t& EB, real_t coeff1, real_t coeff2) : EB { EB } , coeff1 { coeff1 } - , coeff2 { coeff2 } - , deltax { deltax } - , deltay { deltay } - , betaxy { betaxy } - , betayx { betayx } - , deltaz { deltaz } - , betaxz { betaxz } - , betazx { betazx } - , betayz { betayz } - , betazy { betazy } {} - - + , coeff2 { coeff2 } {} Inline void operator()(index_t i1) const { if constexpr (D == Dim::_1D) { - const auto alphax = ONE - THREE * deltax; - EB(i1, em::bx2) += coeff1 * ( - + alphax * (EB(i1 + 1, em::ex3) - EB(i1 , em::ex3)) - + deltax * (EB(i1 + 2, em::ex3) - EB(i1 - 1, em::ex3))); - EB(i1, em::bx3) += coeff1 * ( - - alphax * (EB(i1 + 1, em::ex2) - EB(i1 , em::ex2)) - - deltax * (EB(i1 + 2, em::ex2) - EB(i1 - 1, em::ex2))); + EB(i1, em::bx2) += coeff1 * (EB(i1 + 1, em::ex3) - EB(i1, em::ex3)); + EB(i1, em::bx3) += coeff1 * (EB(i1, em::ex2) - EB(i1 + 1, em::ex2)); } else { raise::KernelError(HERE, "Faraday_kernel: 1D implementation called for D != 1"); } @@ -77,27 +49,13 @@ namespace kernel::mink { Inline void operator()(index_t i1, index_t i2) const { if constexpr (D == Dim::_2D) { - const auto alphax = ONE - TWO * betaxy - THREE * deltax; - const auto alphay = ONE - TWO * betayx - THREE * deltay; - EB(i1, i2, em::bx1) += coeff1 * ( - - alphay * (EB(i1 , i2 + 1, em::ex3) - EB(i1 , i2 , em::ex3)) - - deltay * (EB(i1 , i2 + 2, em::ex3) - EB(i1 , i2 - 1, em::ex3)) - - betayx * (EB(i1 + 1, i2 + 1, em::ex3) - EB(i1 + 1, i2 , em::ex3)) - - betayx * (EB(i1 - 1, i2 + 1, em::ex3) - EB(i1 - 1, i2 , em::ex3))); - EB(i1, i2, em::bx2) += coeff1 * ( - + alphax * (EB(i1 + 1, i2 , em::ex3) - EB(i1 , i2 , em::ex3)) - + deltax * (EB(i1 + 2, i2 , em::ex3) - EB(i1 - 1, i2 , em::ex3)) - + betaxy * (EB(i1 + 1, i2 + 1, em::ex3) - EB(i1 , i2 + 1, em::ex3)) - + betaxy * (EB(i1 + 1, i2 - 1, em::ex3) - EB(i1 , i2 - 1, em::ex3))); - EB(i1, i2, em::bx3) += coeff2 * ( - + alphay * (EB(i1 , i2 + 1, em::ex1) - EB(i1 , i2 , em::ex1)) - + deltay * (EB(i1 , i2 + 2, em::ex1) - EB(i1 , i2 - 1, em::ex1)) - + betayx * (EB(i1 + 1, i2 + 1, em::ex1) - EB(i1 + 1, i2 , em::ex1)) - + betayx * (EB(i1 - 1, i2 + 1, em::ex1) - EB(i1 - 1, i2 , em::ex1)) - - alphax * (EB(i1 + 1, i2 , em::ex2) - EB(i1 , i2 , em::ex2)) - - deltax * (EB(i1 + 2, i2 , em::ex2) - EB(i1 - 1, i2 , em::ex2)) - - betaxy * (EB(i1 + 1, i2 + 1, em::ex2) - EB(i1 , i2 + 1, em::ex2)) - - betaxy * (EB(i1 + 1, i2 - 1, em::ex2) - EB(i1 , i2 - 1, em::ex2))); + EB(i1, i2, em::bx1) += coeff1 * + (EB(i1, i2, em::ex3) - EB(i1, i2 + 1, em::ex3)); + EB(i1, i2, em::bx2) += coeff1 * + (EB(i1 + 1, i2, em::ex3) - EB(i1, i2, em::ex3)); + EB(i1, i2, em::bx3) += coeff2 * + (EB(i1, i2 + 1, em::ex1) - EB(i1, i2, em::ex1) + + EB(i1, i2, em::ex2) - EB(i1 + 1, i2, em::ex2)); } else { raise::KernelError(HERE, "Faraday_kernel: 2D implementation called for D != 2"); @@ -106,48 +64,19 @@ namespace kernel::mink { Inline void operator()(index_t i1, index_t i2, index_t i3) const { if constexpr (D == Dim::_3D) { - const auto alphax = ONE - TWO * betaxy - TWO * betaxz - THREE * deltax; - const auto alphay = ONE - TWO * betayx - TWO * betayz - THREE * deltay; - const auto alphaz = ONE - TWO * betazx - TWO * betazy - THREE * deltaz; - EB(i1, i2, i3, em::bx1) += coeff1 * ( - + alphaz * (EB(i1 , i2 , i3 + 1, em::ex2) - EB(i1 , i2 , i3 , em::ex2)) - + deltaz * (EB(i1 , i2 , i3 + 2, em::ex2) - EB(i1 , i2 , i3 - 1, em::ex2)) - + betazx * (EB(i1 + 1, i2 , i3 + 1, em::ex2) - EB(i1 + 1, i2 , i3 , em::ex2)) - + betazx * (EB(i1 - 1, i2 , i3 + 1, em::ex2) - EB(i1 - 1, i2 , i3 , em::ex2)) - + betazy * (EB(i1 , i2 + 1, i3 + 1, em::ex2) - EB(i1 , i2 + 1, i3 , em::ex2)) - + betazy * (EB(i1 , i2 - 1, i3 + 1, em::ex2) - EB(i1 , i2 - 1, i3 , em::ex2)) - - alphay * (EB(i1 , i2 + 1, i3 , em::ex3) - EB(i1 , i2 , i3 , em::ex3)) - - deltay * (EB(i1 , i2 + 2, i3 , em::ex3) - EB(i1 , i2 - 1, i3 , em::ex3)) - - betayx * (EB(i1 + 1, i2 + 1, i3 , em::ex3) - EB(i1 + 1, i2 , i3 , em::ex3)) - - betayx * (EB(i1 - 1, i2 + 1, i3 , em::ex3) - EB(i1 - 1, i2 , i3 , em::ex3)) - - betayz * (EB(i1 , i2 + 1, i3 + 1, em::ex3) - EB(i1 , i2 , i3 + 1, em::ex3)) - - betayz * (EB(i1 , i2 + 1, i3 - 1, em::ex3) - EB(i1 , i2 , i3 - 1, em::ex3))); - EB(i1, i2, i3, em::bx2) += coeff1 * ( - + alphax * (EB(i1 + 1, i2 , i3 , em::ex3) - EB(i1 , i2 , i3 , em::ex3)) - + deltax * (EB(i1 + 2, i2 , i3 , em::ex3) - EB(i1 - 1, i2 , i3 , em::ex3)) - + betaxy * (EB(i1 + 1, i2 + 1, i3 , em::ex3) - EB(i1 , i2 + 1, i3 , em::ex3)) - + betaxy * (EB(i1 + 1, i2 - 1, i3 , em::ex3) - EB(i1 , i2 - 1, i3 , em::ex3)) - + betaxz * (EB(i1 + 1, i2 , i3 + 1, em::ex3) - EB(i1 , i2 , i3 + 1, em::ex3)) - + betaxz * (EB(i1 + 1, i2 , i3 - 1, em::ex3) - EB(i1 , i2 , i3 - 1, em::ex3)) - - alphaz * (EB(i1 , i2 , i3 + 1, em::ex1) - EB(i1 , i2 , i3 , em::ex1)) - - deltaz * (EB(i1 , i2 , i3 + 2, em::ex1) - EB(i1 , i2 , i3 - 1, em::ex1)) - - betazx * (EB(i1 + 1, i2 , i3 + 1, em::ex1) - EB(i1 + 1, i2 , i3 , em::ex1)) - - betazx * (EB(i1 - 1, i2 , i3 + 1, em::ex1) - EB(i1 - 1, i2 , i3 , em::ex1)) - - betazy * (EB(i1 , i2 + 1, i3 + 1, em::ex1) - EB(i1 , i2 + 1, i3 , em::ex1)) - - betazy * (EB(i1 , i2 - 1, i3 + 1, em::ex1) - EB(i1 , i2 - 1, i3 , em::ex1))); - EB(i1, i2, i3, em::bx3) += coeff1 * ( - + alphay * (EB(i1 , i2 + 1, i3 , em::ex1) - EB(i1 , i2 , i3 , em::ex1)) - + deltay * (EB(i1 , i2 + 2, i3 , em::ex1) - EB(i1 , i2 - 1, i3 , em::ex1)) - + betayx * (EB(i1 + 1, i2 + 1, i3 , em::ex1) - EB(i1 + 1, i2 , i3 , em::ex1)) - + betayx * (EB(i1 - 1, i2 + 1, i3 , em::ex1) - EB(i1 - 1, i2 , i3 , em::ex1)) - + betayz * (EB(i1 , i2 + 1, i3 + 1, em::ex1) - EB(i1 , i2 , i3 + 1, em::ex1)) - + betayz * (EB(i1 , i2 + 1, i3 - 1, em::ex1) - EB(i1 , i2 , i3 - 1, em::ex1)) - - alphax * (EB(i1 + 1, i2 , i3 , em::ex2) - EB(i1 , i2 , i3 , em::ex2)) - - deltax * (EB(i1 + 2, i2 , i3 , em::ex2) - EB(i1 - 1, i2 , i3 , em::ex2)) - - betaxy * (EB(i1 + 1, i2 + 1, i3 , em::ex2) - EB(i1 , i2 + 1, i3 , em::ex2)) - - betaxy * (EB(i1 + 1, i2 - 1, i3 , em::ex2) - EB(i1 , i2 - 1, i3 , em::ex2)) - - betaxz * (EB(i1 + 1, i2 , i3 + 1, em::ex2) - EB(i1 , i2 , i3 + 1, em::ex2)) - - betaxz * (EB(i1 + 1, i2 , i3 - 1, em::ex2) - EB(i1 , i2 , i3 - 1, em::ex2))); + EB(i1, i2, i3, em::bx1) += coeff1 * (EB(i1, i2, i3 + 1, em::ex2) - + EB(i1, i2, i3, em::ex2) + + EB(i1, i2, i3, em::ex3) - + EB(i1, i2 + 1, i3, em::ex3)); + EB(i1, i2, i3, em::bx2) += coeff1 * (EB(i1 + 1, i2, i3, em::ex3) - + EB(i1, i2, i3, em::ex3) + + EB(i1, i2, i3, em::ex1) - + EB(i1, i2, i3 + 1, em::ex1)); + EB(i1, i2, i3, em::bx3) += coeff1 * (EB(i1, i2 + 1, i3, em::ex1) - + EB(i1, i2, i3, em::ex1) + + EB(i1, i2, i3, em::ex2) - + EB(i1 + 1, i2, i3, em::ex2)); + } else { raise::KernelError(HERE, "Faraday_kernel: 3D implementation called for D != 3"); } From d9f96f0f0adaa71d91b7a4c5745dc2ea23c31b35 Mon Sep 17 00:00:00 2001 From: hayk Date: Thu, 24 Apr 2025 17:01:45 -0400 Subject: [PATCH 662/773] return older explicit copy for flds --- src/framework/domain/comm_mpi.hpp | 70 +++++++++++++++++++++++++++++-- 1 file changed, 67 insertions(+), 3 deletions(-) diff --git a/src/framework/domain/comm_mpi.hpp b/src/framework/domain/comm_mpi.hpp index d6b876a4f..eb7781293 100644 --- a/src/framework/domain/comm_mpi.hpp +++ b/src/framework/domain/comm_mpi.hpp @@ -266,11 +266,75 @@ namespace comm { } if (send_rank >= 0 && recv_rank >= 0) { - sendrecv(send_fld, recv_fld, nsend, nrecv, send_rank, recv_rank); +#if defined(MPI_DEVICE_COPY) + auto send_fld_h = Kokkos::create_mirror_view(send_fld); + auto recv_fld_h = Kokkos::create_mirror_view(recv_fld); + Kokkos::deep_copy(send_fld_h, send_fld); + MPI_Sendrecv(send_fld_h.data(), + nsend, + mpi::get_type(), + send_rank, + 0, + recv_fld_h.data(), + nrecv, + mpi::get_type(), + recv_rank, + 0, + MPI_COMM_WORLD, + MPI_STATUS_IGNORE); + Kokkos::deep_copy(recv_fld, recv_fld_h); +#else + MPI_Sendrecv(send_fld.data(), + nsend, + mpi::get_type(), + send_rank, + 0, + recv_fld.data(), + nrecv, + mpi::get_type(), + recv_rank, + 0, + MPI_COMM_WORLD, + MPI_STATUS_IGNORE); +#endif } else if (send_rank >= 0) { - send(send_fld, nsend, send_rank); +#if defined(MPI_DEVICE_COPY) + auto send_fld_h = Kokkos::create_mirror_view(send_fld); + Kokkos::deep_copy(send_fld_h, send_fld); + MPI_Send(send_fld_h.data(), + nsend, + mpi::get_type(), + send_rank, + 0, + MPI_COMM_WORLD); +#else + MPI_Send(send_fld.data(), + nsend, + mpi::get_type(), + send_rank, + 0, + MPI_COMM_WORLD); +#endif } else if (recv_rank >= 0) { - recv(recv_fld, nrecv, recv_rank); +#if defined(MPI_DEVICE_COPY) + auto recv_fld_h = Kokkos::create_mirror_view(recv_fld); + MPI_Recv(recv_fld_h.data(), + nrecv, + mpi::get_type(), + recv_rank, + 0, + MPI_COMM_WORLD, + MPI_STATUS_IGNORE); + Kokkos::deep_copy(recv_fld, recv_fld_h); +#else + MPI_Recv(recv_fld.data(), + nrecv, + mpi::get_type(), + recv_rank, + 0, + MPI_COMM_WORLD, + MPI_STATUS_IGNORE); +#endif } else { raise::Error("CommunicateField called with negative ranks", HERE); } From 2b0c64af1c8549a4b1c5230af7af8229ce71e7d5 Mon Sep 17 00:00:00 2001 From: hayk Date: Thu, 24 Apr 2025 17:49:59 -0400 Subject: [PATCH 663/773] patch for print size --- src/global/utils/diag.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/global/utils/diag.cpp b/src/global/utils/diag.cpp index 9a35e30c9..6764c773f 100644 --- a/src/global/utils/diag.cpp +++ b/src/global/utils/diag.cpp @@ -120,16 +120,16 @@ namespace diag { ss << fmt::alignedTable( { "Step:", fmt::format("%lu", step), fmt::format("[of %lu]", tot_steps) }, { c_reset, c_bgreen, c_bblack }, - { 0, -6, -15 }, - { ' ', ' ', ' ' }, + { 0, -6, -32 }, + { ' ', ' ', '.' }, c_bblack, c_reset); ss << fmt::alignedTable( { "Time:", fmt::format("%.4f", time), fmt::format("[Δt = %.4f]", dt) }, { c_reset, c_bgreen, c_bblack }, - { 0, -6, -15 }, - { ' ', ' ', ' ' }, + { 0, -6, -32 }, + { ' ', ' ', '.' }, c_bblack, c_reset); }); From 802916bd76d241c1b9e42ee36b76e575df0afc99 Mon Sep 17 00:00:00 2001 From: hayk Date: Thu, 24 Apr 2025 18:00:02 -0400 Subject: [PATCH 664/773] mpi flag bug in cmake --- cmake/report.cmake | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/cmake/report.cmake b/cmake/report.cmake index c4958fa3a..6578cfd5e 100644 --- a/cmake/report.cmake +++ b/cmake/report.cmake @@ -65,15 +65,17 @@ printchoices( DEBUG_REPORT 46) -printchoices( - "MPI explicit copy" - "mpi_device_copy" - "${ON_OFF_VALUES}" - ${mpi_device_copy} - OFF - "${Green}" - MPI_DEVICE_COPY_REPORT - 46) +if(${mpi} AND ${DEVICE_ENABLED}) + printchoices( + "MPI explicit copy" + "mpi_device_copy" + "${ON_OFF_VALUES}" + ${mpi_device_copy} + OFF + "${Green}" + MPI_DEVICE_COPY_REPORT + 46) +endif() if(NOT ${PROJECT_VERSION_TWEAK} EQUAL 0) set(VERSION_SYMBOL "v${PROJECT_VERSION_MAJOR}." "${PROJECT_VERSION_MINOR}.") @@ -131,7 +133,7 @@ string( ${MPI_REPORT} "\n") -if(${DEVICE_ENABLED}) +if(${mpi} AND ${DEVICE_ENABLED}) string(APPEND REPORT_TEXT " " ${MPI_DEVICE_COPY_REPORT} "\n") endif() From 4db8033bff3936fdc57bf6b634debf5cb8f8d920 Mon Sep 17 00:00:00 2001 From: haykh Date: Thu, 24 Apr 2025 19:41:28 -0400 Subject: [PATCH 665/773] mv pgens --- setups/{srpic => legacy}/em_vacuum/em_vacuum.py | 0 setups/{srpic => legacy}/em_vacuum/em_vacuum.toml | 0 setups/{srpic => legacy}/em_vacuum/pgen.hpp | 0 setups/{srpic => legacy}/example/pgen.hpp | 0 setups/{srpic => legacy}/langmuir/langmuir.py | 0 setups/{srpic => legacy}/langmuir/langmuir.toml | 0 setups/{srpic => legacy}/langmuir/pgen.hpp | 0 setups/{srpic => legacy}/magnetar/magnetar.py | 0 setups/{srpic => legacy}/magnetar/magnetar.toml | 0 setups/{srpic => legacy}/magnetar/pgen.hpp | 0 setups/{wip => legacy}/magpump/pgen.hpp | 0 setups/{wip => legacy}/rec-gravity/pgen.hpp | 0 setups/{wip => legacy}/rec-gravity/rec-gravity.toml | 0 setups/{srpic => legacy}/shocktest/pgen.hpp | 0 setups/{srpic => legacy}/shocktest/shock.py | 0 setups/{srpic => legacy}/shocktest/shock.toml | 0 setups/{wip => legacy}/spider/pgen.hpp | 0 setups/{wip => srpic}/reconnection/pgen.hpp | 0 setups/{wip => srpic}/reconnection/reconnection.toml | 0 setups/{wip => srpic}/turbulence/pgen.hpp | 0 setups/{wip => srpic}/turbulence/turbulence.toml | 0 21 files changed, 0 insertions(+), 0 deletions(-) rename setups/{srpic => legacy}/em_vacuum/em_vacuum.py (100%) rename setups/{srpic => legacy}/em_vacuum/em_vacuum.toml (100%) rename setups/{srpic => legacy}/em_vacuum/pgen.hpp (100%) rename setups/{srpic => legacy}/example/pgen.hpp (100%) rename setups/{srpic => legacy}/langmuir/langmuir.py (100%) rename setups/{srpic => legacy}/langmuir/langmuir.toml (100%) rename setups/{srpic => legacy}/langmuir/pgen.hpp (100%) rename setups/{srpic => legacy}/magnetar/magnetar.py (100%) rename setups/{srpic => legacy}/magnetar/magnetar.toml (100%) rename setups/{srpic => legacy}/magnetar/pgen.hpp (100%) rename setups/{wip => legacy}/magpump/pgen.hpp (100%) rename setups/{wip => legacy}/rec-gravity/pgen.hpp (100%) rename setups/{wip => legacy}/rec-gravity/rec-gravity.toml (100%) rename setups/{srpic => legacy}/shocktest/pgen.hpp (100%) rename setups/{srpic => legacy}/shocktest/shock.py (100%) rename setups/{srpic => legacy}/shocktest/shock.toml (100%) rename setups/{wip => legacy}/spider/pgen.hpp (100%) rename setups/{wip => srpic}/reconnection/pgen.hpp (100%) rename setups/{wip => srpic}/reconnection/reconnection.toml (100%) rename setups/{wip => srpic}/turbulence/pgen.hpp (100%) rename setups/{wip => srpic}/turbulence/turbulence.toml (100%) diff --git a/setups/srpic/em_vacuum/em_vacuum.py b/setups/legacy/em_vacuum/em_vacuum.py similarity index 100% rename from setups/srpic/em_vacuum/em_vacuum.py rename to setups/legacy/em_vacuum/em_vacuum.py diff --git a/setups/srpic/em_vacuum/em_vacuum.toml b/setups/legacy/em_vacuum/em_vacuum.toml similarity index 100% rename from setups/srpic/em_vacuum/em_vacuum.toml rename to setups/legacy/em_vacuum/em_vacuum.toml diff --git a/setups/srpic/em_vacuum/pgen.hpp b/setups/legacy/em_vacuum/pgen.hpp similarity index 100% rename from setups/srpic/em_vacuum/pgen.hpp rename to setups/legacy/em_vacuum/pgen.hpp diff --git a/setups/srpic/example/pgen.hpp b/setups/legacy/example/pgen.hpp similarity index 100% rename from setups/srpic/example/pgen.hpp rename to setups/legacy/example/pgen.hpp diff --git a/setups/srpic/langmuir/langmuir.py b/setups/legacy/langmuir/langmuir.py similarity index 100% rename from setups/srpic/langmuir/langmuir.py rename to setups/legacy/langmuir/langmuir.py diff --git a/setups/srpic/langmuir/langmuir.toml b/setups/legacy/langmuir/langmuir.toml similarity index 100% rename from setups/srpic/langmuir/langmuir.toml rename to setups/legacy/langmuir/langmuir.toml diff --git a/setups/srpic/langmuir/pgen.hpp b/setups/legacy/langmuir/pgen.hpp similarity index 100% rename from setups/srpic/langmuir/pgen.hpp rename to setups/legacy/langmuir/pgen.hpp diff --git a/setups/srpic/magnetar/magnetar.py b/setups/legacy/magnetar/magnetar.py similarity index 100% rename from setups/srpic/magnetar/magnetar.py rename to setups/legacy/magnetar/magnetar.py diff --git a/setups/srpic/magnetar/magnetar.toml b/setups/legacy/magnetar/magnetar.toml similarity index 100% rename from setups/srpic/magnetar/magnetar.toml rename to setups/legacy/magnetar/magnetar.toml diff --git a/setups/srpic/magnetar/pgen.hpp b/setups/legacy/magnetar/pgen.hpp similarity index 100% rename from setups/srpic/magnetar/pgen.hpp rename to setups/legacy/magnetar/pgen.hpp diff --git a/setups/wip/magpump/pgen.hpp b/setups/legacy/magpump/pgen.hpp similarity index 100% rename from setups/wip/magpump/pgen.hpp rename to setups/legacy/magpump/pgen.hpp diff --git a/setups/wip/rec-gravity/pgen.hpp b/setups/legacy/rec-gravity/pgen.hpp similarity index 100% rename from setups/wip/rec-gravity/pgen.hpp rename to setups/legacy/rec-gravity/pgen.hpp diff --git a/setups/wip/rec-gravity/rec-gravity.toml b/setups/legacy/rec-gravity/rec-gravity.toml similarity index 100% rename from setups/wip/rec-gravity/rec-gravity.toml rename to setups/legacy/rec-gravity/rec-gravity.toml diff --git a/setups/srpic/shocktest/pgen.hpp b/setups/legacy/shocktest/pgen.hpp similarity index 100% rename from setups/srpic/shocktest/pgen.hpp rename to setups/legacy/shocktest/pgen.hpp diff --git a/setups/srpic/shocktest/shock.py b/setups/legacy/shocktest/shock.py similarity index 100% rename from setups/srpic/shocktest/shock.py rename to setups/legacy/shocktest/shock.py diff --git a/setups/srpic/shocktest/shock.toml b/setups/legacy/shocktest/shock.toml similarity index 100% rename from setups/srpic/shocktest/shock.toml rename to setups/legacy/shocktest/shock.toml diff --git a/setups/wip/spider/pgen.hpp b/setups/legacy/spider/pgen.hpp similarity index 100% rename from setups/wip/spider/pgen.hpp rename to setups/legacy/spider/pgen.hpp diff --git a/setups/wip/reconnection/pgen.hpp b/setups/srpic/reconnection/pgen.hpp similarity index 100% rename from setups/wip/reconnection/pgen.hpp rename to setups/srpic/reconnection/pgen.hpp diff --git a/setups/wip/reconnection/reconnection.toml b/setups/srpic/reconnection/reconnection.toml similarity index 100% rename from setups/wip/reconnection/reconnection.toml rename to setups/srpic/reconnection/reconnection.toml diff --git a/setups/wip/turbulence/pgen.hpp b/setups/srpic/turbulence/pgen.hpp similarity index 100% rename from setups/wip/turbulence/pgen.hpp rename to setups/srpic/turbulence/pgen.hpp diff --git a/setups/wip/turbulence/turbulence.toml b/setups/srpic/turbulence/turbulence.toml similarity index 100% rename from setups/wip/turbulence/turbulence.toml rename to setups/srpic/turbulence/turbulence.toml From dd4f7562ce5f243b451d2f1b445e82cd819b9b36 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Fri, 25 Apr 2025 12:32:59 -0400 Subject: [PATCH 666/773] minor change in input --- setups/grpic/pusher/massive_gravity_a0.toml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/setups/grpic/pusher/massive_gravity_a0.toml b/setups/grpic/pusher/massive_gravity_a0.toml index bdb8c802b..02c6062dc 100644 --- a/setups/grpic/pusher/massive_gravity_a0.toml +++ b/setups/grpic/pusher/massive_gravity_a0.toml @@ -72,6 +72,7 @@ [output] format = "hdf5" + separate_files = false [output.fields] enable = true @@ -82,7 +83,7 @@ enable = true stride = 1 interval_time = 1.0 - species = [] + species = [1, 2] [output.spectra] enable = false From 368b5a8bc1fd2b1f6bb2ba77e4c79425c7d8abac Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Fri, 25 Apr 2025 12:34:15 -0400 Subject: [PATCH 667/773] particles are now deleted when they cross ghost zone --- src/kernels/particle_pusher_gr.hpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/kernels/particle_pusher_gr.hpp b/src/kernels/particle_pusher_gr.hpp index c80fe188e..2318d5436 100644 --- a/src/kernels/particle_pusher_gr.hpp +++ b/src/kernels/particle_pusher_gr.hpp @@ -81,7 +81,6 @@ namespace kernel::gr { const int ni1, ni2, ni3; const real_t epsilon; const unsigned short niter; - const int i1_absorb; bool is_axis_i2min { false }, is_axis_i2max { false }; bool is_absorb_i1min { false }, is_absorb_i1max { false }; @@ -141,8 +140,7 @@ namespace kernel::gr { , ni2 { ni2 } , ni3 { ni3 } , epsilon { epsilon } - , niter { niter } - , i1_absorb {N_GHOSTS} { + , niter { niter } { raise::ErrorIf(boundaries.size() < 2, "boundaries defined incorrectly", HERE); is_absorb_i1min = (boundaries[0].first == PrtlBC::ABSORB) || @@ -739,7 +737,7 @@ namespace kernel::gr { template Inline void Pusher_kernel::boundaryConditions(index_t& p) const { if constexpr (D == Dim::_1D || D == Dim::_2D || D == Dim::_3D) { - if (i1(p) < i1_absorb && is_absorb_i1min) { + if (i1(p) < 0 && is_absorb_i1min) { tag(p) = ParticleTag::dead; } else if (i1(p) >= ni1 && is_absorb_i1max) { tag(p) = ParticleTag::dead; From 7e73df901fe9334215529d4db6eaa15c5da511f4 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Fri, 25 Apr 2025 14:04:57 -0400 Subject: [PATCH 668/773] updated horizon boundaries for fields --- src/engines/grpic.hpp | 9 +------- src/kernels/fields_bcs.hpp | 42 ++++++++++++++++++++++++++++++-------- 2 files changed, 34 insertions(+), 17 deletions(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index a5046242f..eb35be4b2 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -721,14 +721,7 @@ namespace ntt { kernel::bc::HorizonBoundaries_kernel(domain.fields.em0, i1_min, tags)); - } else if (g == gr_bc::aux) { - Kokkos::parallel_for( - "OpenBCFields", - range, - kernel::bc::HorizonBoundaries_kernel(domain.fields.aux, - i1_min, - tags)); - } + } } void AxisFieldsIn(dir::direction_t direction, diff --git a/src/kernels/fields_bcs.hpp b/src/kernels/fields_bcs.hpp index 30009b7b9..b3fb1761d 100644 --- a/src/kernels/fields_bcs.hpp +++ b/src/kernels/fields_bcs.hpp @@ -926,17 +926,41 @@ namespace kernel::bc { if constexpr (M::Dim == Dim::_2D) { if constexpr (not IsAux) { if (setE) { - Fld(i1_min - 1, i2, em::dx1) = Fld(i1_min, i2, em::dx1); - Fld(i1_min, i2, em::dx2) = Fld(i1_min + 1, i2, em::dx2); - Fld(i1_min - 1, i2, em::dx2) = Fld(i1_min, i2, em::dx2); - Fld(i1_min, i2, em::dx3) = Fld(i1_min + 1, i2, em::dx3); - Fld(i1_min - 1, i2, em::dx3) = Fld(i1_min, i2, em::dx3); + // Fld(i1_min - 1, i2, em::dx1) = Fld(i1_min, i2, em::dx1); + // Fld(i1_min, i2, em::dx2) = Fld(i1_min + 1, i2, em::dx2); + // Fld(i1_min - 1, i2, em::dx2) = Fld(i1_min, i2, em::dx2); + // Fld(i1_min, i2, em::dx3) = Fld(i1_min + 1, i2, em::dx3); + // Fld(i1_min - 1, i2, em::dx3) = Fld(i1_min, i2, em::dx3); + + Fld(i1_min , i2, em::dx1) = Fld(i1_min + 1, i2, em::dx1); + Fld(i1_min - 1, i2, em::dx1) = Fld(i1_min + 1, i2, em::dx1); + Fld(i1_min - 2, i2, em::dx1) = Fld(i1_min + 1, i2, em::dx1); + + Fld(i1_min , i2, em::dx2) = Fld(i1_min + 1, i2, em::dx2); + Fld(i1_min - 1, i2, em::dx2) = Fld(i1_min + 1, i2, em::dx2); + Fld(i1_min - 2, i2, em::dx2) = Fld(i1_min + 1, i2, em::dx2); + + Fld(i1_min , i2, em::dx3) = Fld(i1_min + 1, i2, em::dx3); + Fld(i1_min - 1, i2, em::dx3) = Fld(i1_min + 1, i2, em::dx3); + Fld(i1_min - 2, i2, em::dx3) = Fld(i1_min + 1, i2, em::dx3); } if (setB) { - Fld(i1_min, i2, em::bx1) = Fld(i1_min + 1, i2, em::bx1); - Fld(i1_min - 1, i2, em::bx1) = Fld(i1_min, i2, em::bx1); - Fld(i1_min - 1, i2, em::bx2) = Fld(i1_min, i2, em::bx2); - Fld(i1_min - 1, i2, em::bx3) = Fld(i1_min, i2, em::bx3); + // Fld(i1_min, i2, em::bx1) = Fld(i1_min + 1, i2, em::bx1); + // Fld(i1_min - 1, i2, em::bx1) = Fld(i1_min, i2, em::bx1); + // Fld(i1_min - 1, i2, em::bx2) = Fld(i1_min, i2, em::bx2); + // Fld(i1_min - 1, i2, em::bx3) = Fld(i1_min, i2, em::bx3); + + Fld(i1_min , i2, em::bx1) = Fld(i1_min + 1, i2, em::bx1); + Fld(i1_min - 1, i2, em::bx1) = Fld(i1_min + 1, i2, em::bx1); + Fld(i1_min - 2, i2, em::bx1) = Fld(i1_min + 1, i2, em::bx1); + + Fld(i1_min , i2, em::bx2) = Fld(i1_min + 1, i2, em::bx2); + Fld(i1_min - 1, i2, em::bx2) = Fld(i1_min + 1, i2, em::bx2); + Fld(i1_min - 2, i2, em::bx2) = Fld(i1_min + 1, i2, em::bx2); + + Fld(i1_min , i2, em::bx3) = Fld(i1_min + 1, i2, em::bx3); + Fld(i1_min - 1, i2, em::bx3) = Fld(i1_min + 1, i2, em::bx3); + Fld(i1_min - 2, i2, em::bx3) = Fld(i1_min + 1, i2, em::bx3); } } else { if (setE) { From d6558e614d1826419087cfa50f19d0ab922591bd Mon Sep 17 00:00:00 2001 From: hayk Date: Mon, 28 Apr 2025 06:58:56 -0400 Subject: [PATCH 669/773] gpu-aware-mpi flag added cmake + comms --- CMakeLists.txt | 21 ++ cmake/defaults.cmake | 12 + cmake/report.cmake | 37 ++- src/engines/engine_printer.cpp | 73 +++++- src/framework/domain/comm_mpi.hpp | 393 ++++++++++++++++++------------ 5 files changed, 377 insertions(+), 159 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c328e8b84..8738afbe3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -48,6 +48,10 @@ set(mpi ${default_mpi} CACHE BOOL "Use MPI") +set(gpu_aware_mpi + ${default_gpu_aware_mpi} + CACHE BOOL "Enable GPU-aware MPI") + # -------------------------- Compilation settings -------------------------- # set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) @@ -90,10 +94,18 @@ include_directories(${plog_SRC}/include) set_precision(${precision}) if("${Kokkos_DEVICES}" MATCHES "CUDA") add_compile_options("-D CUDA_ENABLED") + set(DEVICE_ENABLED ON) + add_compile_options("-D DEVICE_ENABLED") elseif("${Kokkos_DEVICES}" MATCHES "HIP") add_compile_options("-D HIP_ENABLED") + set(DEVICE_ENABLED ON) + add_compile_options("-D DEVICE_ENABLED") elseif("${Kokkos_DEVICES}" MATCHES "SYCL") add_compile_options("-D SYCL_ENABLED") + set(DEVICE_ENABLED ON) + add_compile_options("-D DEVICE_ENABLED") +else() + set(DEVICE_ENABLED OFF) endif() # MPI @@ -102,6 +114,15 @@ if(${mpi}) include_directories(${MPI_CXX_INCLUDE_PATH}) add_compile_options("-D MPI_ENABLED") set(DEPENDENCIES ${DEPENDENCIES} MPI::MPI_CXX) + if(${DEVICE_ENABLED}) + if(${gpu_aware_mpi}) + add_compile_options("-D GPU_AWARE_MPI") + endif() + else() + set(gpu_aware_mpi + OFF + CACHE BOOL "Use explicit copy when using MPI + GPU") + endif() endif() # Output diff --git a/cmake/defaults.cmake b/cmake/defaults.cmake index 30e605a5c..7070644ef 100644 --- a/cmake/defaults.cmake +++ b/cmake/defaults.cmake @@ -64,3 +64,15 @@ else() endif() set_property(CACHE default_mpi PROPERTY TYPE BOOL) + +if(DEFINED ENV{Entity_ENABLE_GPU_AWARE_MPI}) + set(default_gpu_aware_mpi + $ENV{Entity_ENABLE_GPU_AWARE_MPI} + CACHE INTERNAL "Default flag for GPU-aware MPI") +else() + set(default_gpu_aware_mpi + ON + CACHE INTERNAL "Default flag for GPU-aware MPI") +endif() + +set_property(CACHE default_gpu_aware_mpi PROPERTY TYPE BOOL) diff --git a/cmake/report.cmake b/cmake/report.cmake index 626de15a2..5cf6961ae 100644 --- a/cmake/report.cmake +++ b/cmake/report.cmake @@ -36,7 +36,7 @@ printchoices( ${default_precision} "${Blue}" PRECISION_REPORT - 36) + 46) printchoices( "Output" "output" @@ -45,7 +45,7 @@ printchoices( ${default_output} "${Green}" OUTPUT_REPORT - 36) + 46) printchoices( "MPI" "mpi" @@ -54,7 +54,20 @@ printchoices( OFF "${Green}" MPI_REPORT - 36) + 46) + +if(${mpi} AND ${DEVICE_ENABLED}) + printchoices( + "GPU-aware MPI" + "gpu_aware_mpi" + "${ON_OFF_VALUES}" + ${gpu_aware_mpi} + OFF + "${Green}" + GPU_AWARE_MPI_REPORT + 46) +endif() + printchoices( "Debug mode" "DEBUG" @@ -63,7 +76,7 @@ printchoices( OFF "${Green}" DEBUG_REPORT - 36) + 46) if(NOT ${PROJECT_VERSION_TWEAK} EQUAL 0) set(VERSION_SYMBOL "v${PROJECT_VERSION_MAJOR}." "${PROJECT_VERSION_MINOR}.") @@ -111,13 +124,23 @@ string(REPLACE ";" "+" Kokkos_DEVICES "${Kokkos_DEVICES}") string( APPEND REPORT_TEXT - " - ARCH [${Magenta}Kokkos_ARCH_***${ColorReset}]: ${Kokkos_ARCH}" + " - ARCH [${Magenta}Kokkos_ARCH_***${ColorReset}]: " + "${Kokkos_ARCH}" "\n" - " - DEVICES [${Magenta}Kokkos_ENABLE_***${ColorReset}]: ${Kokkos_DEVICES}" + " - DEVICES [${Magenta}Kokkos_ENABLE_***${ColorReset}]: " + "${Kokkos_DEVICES}" "\n" " " ${MPI_REPORT} - "\n" + "\n") + +if(${mpi} AND ${DEVICE_ENABLED}) + string(APPEND REPORT_TEXT " " ${GPU_AWARE_MPI_REPORT} "\n") +endif() + +string( + APPEND + REPORT_TEXT " " ${DEBUG_REPORT} "\n" diff --git a/src/engines/engine_printer.cpp b/src/engines/engine_printer.cpp index 66725fd5d..9d1f74a74 100644 --- a/src/engines/engine_printer.cpp +++ b/src/engines/engine_printer.cpp @@ -106,8 +106,8 @@ namespace ntt { color::RESET); } - auto bytes_to_human_readable( - std::size_t bytes) -> std::pair { + auto bytes_to_human_readable(std::size_t bytes) + -> std::pair { const std::vector units { "B", "KB", "MB", "GB", "TB" }; idx_t unit_idx = 0; auto size = static_cast(bytes); @@ -214,6 +214,10 @@ namespace ntt { report += "\n\n"; add_header(report, { entity_version }, { color::BRIGHT_GREEN }); report += "\n"; + + /* + * Backend + */ add_category(report, 4, "Backend"); add_param(report, 4, "Build hash", "%s", hash.c_str()); add_param(report, 4, "CXX", "%s [%s]", ccx.c_str(), cpp_standard.c_str()); @@ -223,11 +227,76 @@ namespace ntt { add_param(report, 4, "HIP", "%s", hip_version.c_str()); #endif add_param(report, 4, "MPI", "%s", mpi_version.c_str()); +#if defined(MPI_ENABLED) && defined(DEVICE_ENABLED) + #if defined(GPU_AWARE_MPI) + const std::string gpu_aware_mpi = "ON"; + #else + const std::string gpu_aware_mpi = "OFF"; + #endif + add_param(report, 4, "GPU-aware MPI", "%s", gpu_aware_mpi.c_str()); +#endif add_param(report, 4, "Kokkos", "%s", kokkos_version.c_str()); add_param(report, 4, "ADIOS2", "%s", adios2_version.c_str()); add_param(report, 4, "Precision", "%s", precision); add_param(report, 4, "Debug", "%s", dbg.c_str()); report += "\n"; + + /* + * Compilation flags + */ + add_category(report, 4, "Compilation flags"); +#if defined(SINGLE_PRECISION) + add_param(report, 4, "SINGLE_PRECISION", "%s", "ON"); +#else + add_param(report, 4, "SINGLE_PRECISION", "%s", "OFF"); +#endif + +#if defined(OUTPUT_ENABLED) + add_param(report, 4, "OUTPUT_ENABLED", "%s", "ON"); +#else + add_param(report, 4, "OUTPUT_ENABLED", "%s", "OFF"); +#endif + +#if defined(DEBUG) + add_param(report, 4, "DEBUG", "%s", "ON"); +#else + add_param(report, 4, "DEBUG", "%s", "OFF"); +#endif + +#if defined(CUDA_ENABLED) + add_param(report, 4, "CUDA_ENABLED", "%s", "ON"); +#else + add_param(report, 4, "CUDA_ENABLED", "%s", "OFF"); +#endif + +#if defined(HIP_ENABLED) + add_param(report, 4, "HIP_ENABLED", "%s", "ON"); +#else + add_param(report, 4, "HIP_ENABLED", "%s", "OFF"); +#endif + +#if defined(DEVICE_ENABLED) + add_param(report, 4, "DEVICE_ENABLED", "%s", "ON"); +#else + add_param(report, 4, "DEVICE_ENABLED", "%s", "OFF"); +#endif + +#if defined(MPI_ENABLED) + add_param(report, 4, "MPI_ENABLED", "%s", "ON"); +#else + add_param(report, 4, "MPI_ENABLED", "%s", "OFF"); +#endif + +#if defined(GPU_AWARE_MPI) + add_param(report, 4, "GPU_AWARE_MPI", "%s", "ON"); +#else + add_param(report, 4, "GPU_AWARE_MPI", "%s", "OFF"); +#endif + report += "\n"; + + /* + * Simulation configs + */ add_category(report, 4, "Configuration"); add_param(report, 4, diff --git a/src/framework/domain/comm_mpi.hpp b/src/framework/domain/comm_mpi.hpp index fbeb7ecde..e0d0cb4b2 100644 --- a/src/framework/domain/comm_mpi.hpp +++ b/src/framework/domain/comm_mpi.hpp @@ -33,6 +33,214 @@ namespace comm { using namespace ntt; + namespace flds { + template + void send_recv(ndarray_t& send_arr, + ndarray_t& recv_arr, + int send_rank, + int recv_rank, + ncells_t nsend, + ncells_t nrecv) { +#if !defined(DEVICE_ENABLED) || defined(GPU_AWARE_MPI) + MPI_Sendrecv(send_arr.data(), + nsend, + mpi::get_type(), + send_rank, + 0, + recv_arr.data(), + nrecv, + mpi::get_type(), + recv_rank, + 0, + MPI_COMM_WORLD, + MPI_STATUS_IGNORE); +#else + auto send_arr_h = Kokkos::create_mirror_view(send_arr); + auto recv_arr_h = Kokkos::create_mirror_view(recv_arr); + Kokkos::deep_copy(send_arr_h, send_arr); + MPI_Sendrecv(send_arr_h.data(), + nsend, + mpi::get_type(), + send_rank, + 0, + recv_arr_h.data(), + nrecv, + mpi::get_type(), + recv_rank, + 0, + MPI_COMM_WORLD, + MPI_STATUS_IGNORE); + Kokkos::deep_copy(recv_arr, recv_arr_h); +#endif + } + + template + void send(ndarray_t& send_arr, int send_rank, ncells_t nsend) { +#if !defined(DEVICE_ENABLED) || defined(GPU_AWARE_MPI) + MPI_Send(send_arr.data(), nsend, mpi::get_type(), send_rank, 0, MPI_COMM_WORLD); +#else + auto send_arr_h = Kokkos::create_mirror_view(send_arr); + Kokkos::deep_copy(send_arr_h, send_arr); + MPI_Send(send_arr_h.data(), + nsend, + mpi::get_type(), + send_rank, + 0, + MPI_COMM_WORLD); +#endif + } + + template + void recv(ndarray_t& recv_arr, int recv_rank, ncells_t nrecv) { +#if !defined(DEVICE_ENABLED) || defined(GPU_AWARE_MPI) + MPI_Recv(recv_arr.data(), + nrecv, + mpi::get_type(), + recv_rank, + 0, + MPI_COMM_WORLD, + MPI_STATUS_IGNORE); +#else + auto recv_arr_h = Kokkos::create_mirror_view(recv_arr); + MPI_Recv(recv_arr_h.data(), + nrecv, + mpi::get_type(), + recv_rank, + 0, + MPI_COMM_WORLD, + MPI_STATUS_IGNORE); + Kokkos::deep_copy(recv_arr, recv_arr_h); +#endif + } + + template + void communicate(ndarray_t& send_arr, + ndarray_t& recv_arr, + int send_rank, + int recv_rank, + ncells_t nsend, + ncells_t nrecv) { + if (send_rank >= 0 and recv_rank >= 0 and nsend > 0 and nrecv > 0) { + send_recv(send_arr, recv_arr, send_rank, recv_rank, nsend, nrecv); + } else if (send_rank >= 0 and nsend > 0) { + send(send_arr, send_rank, nsend); + } else if (recv_rank >= 0 and nrecv > 0) { + recv(recv_arr, recv_rank, nrecv); + } + } + + } // namespace flds + + namespace prtls { + template + void send_recv(array_t& send_arr, + array_t& recv_arr, + int send_rank, + int recv_rank, + npart_t nsend, + npart_t nrecv, + npart_t offset) { +#if !defined(DEVICE_ENABLED) || defined(GPU_AWARE_MPI) + MPI_Sendrecv(send_arr.data(), + nsend, + mpi::get_type(), + send_rank, + 0, + recv_arr.data() + offset, + nrecv, + mpi::get_type(), + recv_rank, + 0, + MPI_COMM_WORLD, + MPI_STATUS_IGNORE); +#else + const auto slice = std::make_pair(offset, offset + nrecv); + + auto send_arr_h = Kokkos::create_mirror_view(send_arr); + auto recv_arr_h = Kokkos::create_mirror_view( + Kokkos::subview(recv_arr, slice)); + Kokkos::deep_copy(send_arr_h, send_arr); + MPI_Sendrecv(send_arr_h.data(), + nsend, + mpi::get_type(), + send_rank, + 0, + recv_arr_h.data(), + nrecv, + mpi::get_type(), + recv_rank, + 0, + MPI_COMM_WORLD, + MPI_STATUS_IGNORE); + Kokkos::deep_copy(Kokkos::subview(recv_arr, slice), recv_arr_h); +#endif + } + + template + void send(array_t& send_arr, int send_rank, npart_t nsend) { +#if !defined(DEVICE_ENABLED) || defined(GPU_AWARE_MPI) + MPI_Send(send_arr.data(), nsend, mpi::get_type(), send_rank, 0, MPI_COMM_WORLD); +#else + auto send_arr_h = Kokkos::create_mirror_view(send_arr); + Kokkos::deep_copy(send_arr_h, send_arr); + MPI_Send(send_arr_h.data(), nsend, mpi::get_type(), send_rank, 0, MPI_COMM_WORLD); +#endif + } + + template + void recv(array_t& recv_arr, int recv_rank, npart_t nrecv, npart_t offset) { +#if !defined(DEVICE_ENABLED) || defined(GPU_AWARE_MPI) + MPI_Recv(recv_arr.data() + offset, + nrecv, + mpi::get_type(), + recv_rank, + 0, + MPI_COMM_WORLD, + MPI_STATUS_IGNORE); +#else + const auto slice = std::make_pair(offset, offset + nrecv); + + auto recv_arr_h = Kokkos::create_mirror_view( + Kokkos::subview(recv_arr, slice)); + MPI_Recv(recv_arr_h.data(), + nrecv, + mpi::get_type(), + recv_rank, + 0, + MPI_COMM_WORLD, + MPI_STATUS_IGNORE); + Kokkos::deep_copy(Kokkos::subview(recv_arr, slice), recv_arr_h); +#endif + } + + template + void communicate(array_t& send_arr, + array_t& recv_arr, + int send_rank, + int recv_rank, + npart_t nsend, + npart_t nrecv, + npart_t offset) { + if (send_rank >= 0 && recv_rank >= 0) { + raise::ErrorIf( + nrecv + offset > recv_arr.extent(0), + "recv_arr is not large enough to hold the received particles", + HERE); + send_recv(send_arr, recv_arr, send_rank, recv_rank, nsend, nrecv, offset); + } else if (send_rank >= 0) { + send(send_arr, send_rank, nsend); + } else if (recv_rank >= 0) { + raise::ErrorIf( + nrecv + offset > recv_arr.extent(0), + "recv_arr is not large enough to hold the received particles", + HERE); + recv(recv_arr, recv_rank, nrecv, offset); + } else { + raise::Error("CommunicateParticles called with negative ranks", HERE); + } + } + } // namespace prtls + template inline void CommunicateField(unsigned int idx, ndfield_t& fld, @@ -185,38 +393,12 @@ namespace comm { } } - if (send_rank >= 0 && recv_rank >= 0) { - MPI_Sendrecv(send_fld.data(), - nsend, - mpi::get_type(), - send_rank, - 0, - recv_fld.data(), - nrecv, - mpi::get_type(), - recv_rank, - 0, - MPI_COMM_WORLD, - MPI_STATUS_IGNORE); - } else if (send_rank >= 0) { - MPI_Send(send_fld.data(), - nsend, - mpi::get_type(), - send_rank, - 0, - MPI_COMM_WORLD); - - } else if (recv_rank >= 0) { - MPI_Recv(recv_fld.data(), - nrecv, - mpi::get_type(), - recv_rank, - 0, - MPI_COMM_WORLD, - MPI_STATUS_IGNORE); - } else { - raise::Error("CommunicateField called with negative ranks", HERE); - } + flds::communicate(D) + 1>(send_fld, + recv_fld, + send_rank, + recv_rank, + nsend, + nrecv); if (recv_rank >= 0) { @@ -398,124 +580,35 @@ namespace comm { const auto recv_offset_prtldx = current_received * NPRTLDX; const auto recv_offset_pld = current_received * NPLDS; - if ((send_rank >= 0) and (recv_rank >= 0) and (npart_send_in > 0) and - (npart_recv_in > 0)) { - raise::ErrorIf(recv_offset_int + npart_recv_in * NINTS > - recv_buff_int.extent(0), - "incorrect # of recv particles", - HERE); - MPI_Sendrecv(send_buff_int.data(), - npart_send_in * NINTS, - mpi::get_type(), - send_rank, - 0, - recv_buff_int.data() + recv_offset_int, - npart_recv_in * NINTS, - mpi::get_type(), - recv_rank, - 0, - MPI_COMM_WORLD, - MPI_STATUS_IGNORE); - MPI_Sendrecv(send_buff_real.data(), - npart_send_in * NREALS, - mpi::get_type(), - send_rank, - 0, - recv_buff_real.data() + recv_offset_real, - npart_recv_in * NREALS, - mpi::get_type(), - recv_rank, - 0, - MPI_COMM_WORLD, - MPI_STATUS_IGNORE); - MPI_Sendrecv(send_buff_prtldx.data(), - npart_send_in * NPRTLDX, - mpi::get_type(), - send_rank, - 0, - recv_buff_prtldx.data() + recv_offset_prtldx, - npart_recv_in * NPRTLDX, - mpi::get_type(), - recv_rank, - 0, - MPI_COMM_WORLD, - MPI_STATUS_IGNORE); - if (NPLDS > 0) { - MPI_Sendrecv(send_buff_pld.data(), - npart_send_in * NPLDS, - mpi::get_type(), - send_rank, - 0, - recv_buff_pld.data() + recv_offset_pld, - npart_recv_in * NPLDS, - mpi::get_type(), - recv_rank, - 0, - MPI_COMM_WORLD, - MPI_STATUS_IGNORE); - } - } else if ((send_rank >= 0) and (npart_send_in > 0)) { - MPI_Send(send_buff_int.data(), - npart_send_in * NINTS, - mpi::get_type(), - send_rank, - 0, - MPI_COMM_WORLD); - MPI_Send(send_buff_real.data(), - npart_send_in * NREALS, - mpi::get_type(), - send_rank, - 0, - MPI_COMM_WORLD); - MPI_Send(send_buff_prtldx.data(), - npart_send_in * NPRTLDX, - mpi::get_type(), - send_rank, - 0, - MPI_COMM_WORLD); - if (NPLDS > 0) { - MPI_Send(send_buff_pld.data(), - npart_send_in * NPLDS, - mpi::get_type(), - send_rank, - 0, - MPI_COMM_WORLD); - } - } else if ((recv_rank >= 0) and (npart_recv_in > 0)) { - raise::ErrorIf(recv_offset_int + npart_recv_in * NINTS > - recv_buff_int.extent(0), - "incorrect # of recv particles", - HERE); - MPI_Recv(recv_buff_int.data() + recv_offset_int, - npart_recv_in * NINTS, - mpi::get_type(), - recv_rank, - 0, - MPI_COMM_WORLD, - MPI_STATUS_IGNORE); - MPI_Recv(recv_buff_real.data() + recv_offset_real, - npart_recv_in * NREALS, - mpi::get_type(), - recv_rank, - 0, - MPI_COMM_WORLD, - MPI_STATUS_IGNORE); - MPI_Recv(recv_buff_prtldx.data() + recv_offset_prtldx, - npart_recv_in * NPRTLDX, - mpi::get_type(), - recv_rank, - 0, - MPI_COMM_WORLD, - MPI_STATUS_IGNORE); - if (NPLDS > 0) { - MPI_Recv(recv_buff_pld.data() + recv_offset_pld, - npart_recv_in * NPLDS, - mpi::get_type(), - recv_rank, - 0, - MPI_COMM_WORLD, - MPI_STATUS_IGNORE); - } + prtls::communicate(send_buff_int, + recv_buff_int, + send_rank, + recv_rank, + npart_send_in * NINTS, + npart_recv_in * NINTS, + recv_offset_int); + prtls::communicate(send_buff_real, + recv_buff_real, + send_rank, + recv_rank, + npart_send_in * NREALS, + npart_recv_in * NREALS, + recv_offset_real); + prtls::communicate(send_buff_prtldx, + recv_buff_prtldx, + send_rank, + recv_rank, + npart_send_in * NPRTLDX, + npart_recv_in * NPRTLDX, + recv_offset_prtldx); + if (NPLDS > 0) { + prtls::communicate(send_buff_pld, + recv_buff_pld, + send_rank, + recv_rank, + npart_send_in * NPLDS, + npart_recv_in * NPLDS, + recv_offset_pld); } current_received += npart_recv_in; iteration++; From 86ae954b5f13b64df53d236c2e999b4228b00cc0 Mon Sep 17 00:00:00 2001 From: hayk Date: Mon, 28 Apr 2025 11:41:29 -0400 Subject: [PATCH 670/773] weibel->streaming + experimental injector --- setups/srpic/streaming/pgen.hpp | 104 +++++++++++ .../srpic/{weibel => streaming}/weibel.toml | 9 +- setups/srpic/weibel/pgen.hpp | 75 -------- src/archetypes/particle_injector.h | 172 ++++++++++++++--- src/kernels/injectors.hpp | 173 ++++++++++++++++++ 5 files changed, 426 insertions(+), 107 deletions(-) create mode 100644 setups/srpic/streaming/pgen.hpp rename setups/srpic/{weibel => streaming}/weibel.toml (86%) delete mode 100644 setups/srpic/weibel/pgen.hpp diff --git a/setups/srpic/streaming/pgen.hpp b/setups/srpic/streaming/pgen.hpp new file mode 100644 index 000000000..04aa8ea85 --- /dev/null +++ b/setups/srpic/streaming/pgen.hpp @@ -0,0 +1,104 @@ +#ifndef PROBLEM_GENERATOR_H +#define PROBLEM_GENERATOR_H + +#include "enums.h" +#include "global.h" + +#include "arch/kokkos_aliases.h" +#include "arch/traits.h" +#include "utils/error.h" +#include "utils/numeric.h" + +#include "archetypes/energy_dist.h" +#include "archetypes/particle_injector.h" +#include "archetypes/problem_generator.h" +#include "framework/domain/domain.h" +#include "framework/domain/metadomain.h" + +namespace user { + using namespace ntt; + + template + struct PGen : public arch::ProblemGenerator { + + // compatibility traits for the problem generator + static constexpr auto engines = traits::compatible_with::value; + static constexpr auto metrics = traits::compatible_with::value; + static constexpr auto dimensions = + traits::compatible_with::value; + + // for easy access to variables in the child class + using arch::ProblemGenerator::D; + using arch::ProblemGenerator::C; + using arch::ProblemGenerator::params; + + using prmvec_t = std::vector; + + prmvec_t drifts_in_x, drifts_in_y, drifts_in_z; + prmvec_t densities, temperatures; + + inline PGen(const SimulationParams& p, const Metadomain& global_domain) + : arch::ProblemGenerator { p } + , drifts_in_x { p.template get("setup.drifts_in_x", prmvec_t {}) } + , drifts_in_y { p.template get("setup.drifts_in_y", prmvec_t {}) } + , drifts_in_z { p.template get("setup.drifts_in_z", prmvec_t {}) } + , densities { p.template get("setup.densities", prmvec_t {}) } + , temperatures { p.template get("setup.temperatures", prmvec_t {}) } { + const auto nspec = p.template get("particles.nspec"); + raise::ErrorIf(nspec % 2 != 0, + "Number of species must be even for this setup", + HERE); + for (auto n = 0u; n < nspec; n += 2) { + raise::ErrorIf( + global_domain.species_params()[n].charge() != + -global_domain.species_params()[n + 1].charge(), + "Charges of i-th and i+1-th species must be opposite for this setup", + HERE); + } + for (auto* specs : + { &drifts_in_x, &drifts_in_y, &drifts_in_z, &temperatures }) { + if (specs->empty()) { + for (auto n = 0u; n < nspec; ++n) { + specs->push_back(ZERO); + } + } + raise::ErrorIf(specs->size() != nspec, + "Drift vector and/or temperature vector length does " + "not match number of species", + HERE); + } + if (densities.empty()) { + for (auto n = 0u; n < nspec; n += 2) { + densities.push_back(TWO / static_cast(nspec)); + } + } + raise::ErrorIf(densities.size() != nspec / 2, + "Density vector length must be half of the number of " + "species (per each pair of species)", + HERE); + } + + inline void InitPrtls(Domain& domain) { + const auto nspec = domain.species.size(); + for (auto n = 0u; n < nspec; n += 2) { + const auto injector = + arch::experimental::UniformInjector( + arch::Maxwellian(domain.mesh.metric, + domain.random_pool, + temperatures[n]), + arch::Maxwellian(domain.mesh.metric, + domain.random_pool, + temperatures[n + 1]), + { n + 1, n + 2 }); + arch::experimental::InjectUniform( + params, + domain, + injector, + densities[n / 2]); + } + } + }; + +} // namespace user + +#endif diff --git a/setups/srpic/weibel/weibel.toml b/setups/srpic/streaming/weibel.toml similarity index 86% rename from setups/srpic/weibel/weibel.toml rename to setups/srpic/streaming/weibel.toml index 23d119b24..b67cfc448 100644 --- a/setups/srpic/weibel/weibel.toml +++ b/setups/srpic/streaming/weibel.toml @@ -52,17 +52,14 @@ maxnpart = 1e7 [setup] - drift_u_1 = 0.2 - drift_u_2 = 0.2 - temp_1 = 1e-4 - temp_2 = 1e-4 + drifts_in_x = [0.2, 0.2, -0.2, -0.2] + temperatures = [1e-4, 1e-4, 1e-4, 1e-4] [output] - format = "hdf5" interval_time = 0.25 [output.fields] - quantities = ["N_1_2", "N_3_4", "B", "E", "T0i_1", "T0i_3"] + quantities = ["N_1_2", "N_3_4", "E", "B", "T0i_1", "T0i_3"] [output.particles] enable = false diff --git a/setups/srpic/weibel/pgen.hpp b/setups/srpic/weibel/pgen.hpp deleted file mode 100644 index 21acc8032..000000000 --- a/setups/srpic/weibel/pgen.hpp +++ /dev/null @@ -1,75 +0,0 @@ -#ifndef PROBLEM_GENERATOR_H -#define PROBLEM_GENERATOR_H - -#include "enums.h" -#include "global.h" - -#include "arch/kokkos_aliases.h" -#include "arch/traits.h" - -#include "archetypes/energy_dist.h" -#include "archetypes/particle_injector.h" -#include "archetypes/problem_generator.h" -#include "framework/domain/domain.h" -#include "framework/domain/metadomain.h" - -namespace user { - using namespace ntt; - - template - struct PGen : public arch::ProblemGenerator { - - // compatibility traits for the problem generator - static constexpr auto engines = traits::compatible_with::value; - static constexpr auto metrics = traits::compatible_with::value; - static constexpr auto dimensions = - traits::compatible_with::value; - - // for easy access to variables in the child class - using arch::ProblemGenerator::D; - using arch::ProblemGenerator::C; - using arch::ProblemGenerator::params; - - const real_t temp_1, temp_2; - const real_t drift_u_1, drift_u_2; - - inline PGen(const SimulationParams& p, const Metadomain& global_domain) - : arch::ProblemGenerator { p } - , temp_1 { p.template get("setup.temp_1") } - , temp_2 { p.template get("setup.temp_2") } - , drift_u_1 { p.template get("setup.drift_u_1") } - , drift_u_2 { p.template get("setup.drift_u_2") } {} - - inline void InitPrtls(Domain& local_domain) { - const auto energy_dist_1 = arch::Maxwellian(local_domain.mesh.metric, - local_domain.random_pool, - temp_1, - -drift_u_1, - in::x3); - const auto energy_dist_2 = arch::Maxwellian(local_domain.mesh.metric, - local_domain.random_pool, - temp_2, - drift_u_2, - in::x3); - const auto injector_1 = arch::UniformInjector( - energy_dist_1, - { 1, 2 }); - const auto injector_2 = arch::UniformInjector( - energy_dist_2, - { 3, 4 }); - arch::InjectUniform>( - params, - local_domain, - injector_1, - HALF); - arch::InjectUniform>( - params, - local_domain, - injector_2, - HALF); - } - }; - -} // namespace user - -#endif diff --git a/src/archetypes/particle_injector.h b/src/archetypes/particle_injector.h index aaccaeecf..39e457fa8 100644 --- a/src/archetypes/particle_injector.h +++ b/src/archetypes/particle_injector.h @@ -45,27 +45,10 @@ namespace arch { using namespace ntt; - template class ED> - struct UniformInjector { - using energy_dist_t = ED; - static_assert(M::is_metric, "M must be a metric class"); - static_assert(energy_dist_t::is_energy_dist, - "E must be an energy distribution class"); - static constexpr bool is_uniform_injector { true }; - static constexpr Dimension D { M::Dim }; - static constexpr Coord C { M::CoordType }; - - const energy_dist_t energy_dist; - const std::pair species; - - UniformInjector(const energy_dist_t& energy_dist, - const std::pair& species) - : energy_dist { energy_dist } - , species { species } {} - - ~UniformInjector() = default; - - auto DeduceRegion(const Domain& domain, const boundaries_t& box) const + template + struct BaseInjector { + virtual auto DeduceRegion(const Domain& domain, + const boundaries_t& box) const -> std::tuple, array_t> { if (not domain.mesh.Intersects(box)) { return { false, array_t {}, array_t {} }; @@ -104,10 +87,10 @@ namespace arch { return { true, xi_min, xi_max }; } - auto ComputeNumInject(const SimulationParams& params, - const Domain& domain, - real_t number_density, - const boundaries_t& box) const + virtual auto ComputeNumInject(const SimulationParams& params, + const Domain& domain, + real_t number_density, + const boundaries_t& box) const -> std::tuple, array_t> { const auto result = DeduceRegion(domain, box); if (not std::get<0>(result)) { @@ -134,6 +117,27 @@ namespace arch { } }; + template class ED> + struct UniformInjector : BaseInjector { + using energy_dist_t = ED; + static_assert(M::is_metric, "M must be a metric class"); + static_assert(energy_dist_t::is_energy_dist, + "E must be an energy distribution class"); + static constexpr bool is_uniform_injector { true }; + static constexpr Dimension D { M::Dim }; + static constexpr Coord C { M::CoordType }; + + const energy_dist_t energy_dist; + const std::pair species; + + UniformInjector(const energy_dist_t& energy_dist, + const std::pair& species) + : energy_dist { energy_dist } + , species { species } {} + + ~UniformInjector() = default; + }; + template class ED> struct KeepConstantInjector : UniformInjector { using energy_dist_t = ED; @@ -217,7 +221,7 @@ namespace arch { Domain& domain, real_t number_density, const boundaries_t& box) const - -> std::tuple, array_t> { + -> std::tuple, array_t> override { const auto computed_avg_density = ComputeAvgDensity(params, domain); const auto result = this->DeduceRegion(domain, box); @@ -499,6 +503,122 @@ namespace arch { } } + namespace experimental { + + template class ED1, + template class ED2> + struct UniformInjector : BaseInjector { + using energy_dist_1_t = ED1; + using energy_dist_2_t = ED2; + static_assert(M::is_metric, "M must be a metric class"); + static_assert(energy_dist_1_t::is_energy_dist, + "E must be an energy distribution class"); + static_assert(energy_dist_2_t::is_energy_dist, + "E must be an energy distribution class"); + static constexpr bool is_uniform_injector { true }; + static constexpr Dimension D { M::Dim }; + static constexpr Coord C { M::CoordType }; + + const energy_dist_1_t energy_dist_1; + const energy_dist_2_t energy_dist_2; + const std::pair species; + + UniformInjector(const energy_dist_1_t& energy_dist_1, + const energy_dist_2_t& energy_dist_2, + const std::pair& species) + : energy_dist_1 { energy_dist_1 } + , energy_dist_2 { energy_dist_2 } + , species { species } {} + + ~UniformInjector() = default; + }; + + /** + * @brief Injects uniform number density of particles everywhere in the domain + * @param domain Domain object + * @param injector Uniform injector object + * @param number_density Total number density (in units of n0) + * @param use_weights Use weights + * @param box Region to inject the particles in global coords + * @tparam S Simulation engine type + * @tparam M Metric type + * @tparam I Injector type + */ + template + inline void InjectUniform(const SimulationParams& params, + Domain& domain, + const I& injector, + 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(I::is_uniform_injector, "I must be a uniform injector class"); + raise::ErrorIf((M::CoordType != Coord::Cart) && (not use_weights), + "Weights must be used for non-Cartesian coordinates", + HERE); + raise::ErrorIf((M::CoordType == Coord::Cart) && use_weights, + "Weights should not be used for Cartesian coordinates", + HERE); + raise::ErrorIf( + params.template get("particles.use_weights") != use_weights, + "Weights must be enabled from the input file to use them in " + "the injector", + HERE); + if (domain.species[injector.species.first - 1].charge() + + domain.species[injector.species.second - 1].charge() != + 0.0f) { + raise::Warning("Total charge of the injected species is non-zero", HERE); + } + + { + boundaries_t nonempty_box; + for (auto d { 0u }; d < M::Dim; ++d) { + if (d < box.size()) { + nonempty_box.push_back({ box[d].first, box[d].second }); + } else { + nonempty_box.push_back(Range::All); + } + } + const auto result = injector.ComputeNumInject(params, + domain, + number_density, + nonempty_box); + if (not std::get<0>(result)) { + return; + } + const auto nparticles = std::get<1>(result); + const auto xi_min = std::get<2>(result); + const auto xi_max = std::get<3>(result); + + Kokkos::parallel_for( + "InjectUniform", + nparticles, + kernel::experimental:: + UniformInjector_kernel( + injector.species.first, + injector.species.second, + domain.species[injector.species.first - 1], + domain.species[injector.species.second - 1], + domain.species[injector.species.first - 1].npart(), + domain.species[injector.species.second - 1].npart(), + domain.mesh.metric, + xi_min, + xi_max, + injector.energy_dist_1, + injector.energy_dist_2, + ONE / params.template get("scales.V0"), + domain.random_pool)); + domain.species[injector.species.first - 1].set_npart( + domain.species[injector.species.first - 1].npart() + nparticles); + domain.species[injector.species.second - 1].set_npart( + domain.species[injector.species.second - 1].npart() + nparticles); + } + } + + } // namespace experimental + /** * @brief Injects particles from a globally-defined map * @note very inefficient, should only be used for debug purposes diff --git a/src/kernels/injectors.hpp b/src/kernels/injectors.hpp index 0449ed441..8406fc4eb 100644 --- a/src/kernels/injectors.hpp +++ b/src/kernels/injectors.hpp @@ -186,6 +186,179 @@ namespace kernel { } }; // struct UniformInjector_kernel + namespace experimental { + + template + struct UniformInjector_kernel { + 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(M::is_metric, "M must be a metric class"); + + const spidx_t spidx1, spidx2; + + array_t i1s_1, i2s_1, i3s_1; + array_t dx1s_1, dx2s_1, dx3s_1; + array_t ux1s_1, ux2s_1, ux3s_1; + array_t phis_1; + array_t weights_1; + array_t tags_1; + + array_t i1s_2, i2s_2, i3s_2; + array_t dx1s_2, dx2s_2, dx3s_2; + array_t ux1s_2, ux2s_2, ux3s_2; + array_t phis_2; + array_t weights_2; + array_t tags_2; + + npart_t offset1, offset2; + const M metric; + const array_t xi_min, xi_max; + const ED1 energy_dist_1; + const ED2 energy_dist_2; + const real_t inv_V0; + random_number_pool_t random_pool; + + UniformInjector_kernel(spidx_t spidx1, + spidx_t spidx2, + Particles& species1, + Particles& species2, + npart_t offset1, + npart_t offset2, + const M& metric, + const array_t& xi_min, + const array_t& xi_max, + const ED1& energy_dist_1, + const ED2& energy_dist_2, + real_t inv_V0, + random_number_pool_t& random_pool) + : spidx1 { spidx1 } + , spidx2 { spidx2 } + , i1s_1 { species1.i1 } + , i2s_1 { species1.i2 } + , i3s_1 { species1.i3 } + , dx1s_1 { species1.dx1 } + , dx2s_1 { species1.dx2 } + , dx3s_1 { species1.dx3 } + , ux1s_1 { species1.ux1 } + , ux2s_1 { species1.ux2 } + , ux3s_1 { species1.ux3 } + , phis_1 { species1.phi } + , weights_1 { species1.weight } + , tags_1 { species1.tag } + , i1s_2 { species2.i1 } + , i2s_2 { species2.i2 } + , i3s_2 { species2.i3 } + , dx1s_2 { species2.dx1 } + , dx2s_2 { species2.dx2 } + , dx3s_2 { species2.dx3 } + , ux1s_2 { species2.ux1 } + , ux2s_2 { species2.ux2 } + , ux3s_2 { species2.ux3 } + , phis_2 { species2.phi } + , weights_2 { species2.weight } + , tags_2 { species2.tag } + , offset1 { offset1 } + , offset2 { offset2 } + , metric { metric } + , xi_min { xi_min } + , xi_max { xi_max } + , energy_dist_1 { energy_dist_1 } + , energy_dist_2 { energy_dist_2 } + , inv_V0 { inv_V0 } + , random_pool { random_pool } {} + + Inline void operator()(index_t p) const { + coord_t x_Cd { ZERO }; + vec_t v1 { ZERO }, v2 { ZERO }; + { // generate a random coordinate + auto rand_gen = random_pool.get_state(); + x_Cd[0] = xi_min(0) + Random(rand_gen) * (xi_max(0) - xi_min(0)); + if constexpr (M::Dim == Dim::_2D or M::Dim == Dim::_3D) { + x_Cd[1] = xi_min(1) + + Random(rand_gen) * (xi_max(1) - xi_min(1)); + } + if constexpr (M::Dim == Dim::_3D) { + x_Cd[2] = xi_min(2) + + Random(rand_gen) * (xi_max(2) - xi_min(2)); + } + random_pool.free_state(rand_gen); + } + { // generate the velocity + coord_t x_Ph { ZERO }; + metric.template convert(x_Cd, x_Ph); + if constexpr (M::CoordType == Coord::Cart) { + vec_t v_Ph { ZERO }; + energy_dist_1(x_Ph, v_Ph, spidx1); + metric.template transform_xyz(x_Ph, v_Ph, v1); + energy_dist_2(x_Ph, v_Ph, spidx2); + metric.template transform_xyz(x_Ph, v_Ph, v2); + } else if constexpr (S == SimEngine::SRPIC) { + coord_t x_Ph_ { ZERO }; + x_Ph_[0] = x_Ph[0]; + x_Ph_[1] = x_Ph[1]; + x_Ph_[2] = ZERO; // phi = 0 + vec_t v_Ph { ZERO }; + energy_dist_1(x_Ph, v_Ph, spidx1); + metric.template transform_xyz(x_Ph_, v_Ph, v1); + energy_dist_2(x_Ph, v_Ph, spidx2); + metric.template transform_xyz(x_Ph_, v_Ph, v2); + } else if constexpr (S == SimEngine::GRPIC) { + vec_t v_Ph { ZERO }; + energy_dist_1(x_Ph, v_Ph, spidx1); + metric.template transform(x_Ph, v_Ph, v1); + energy_dist_2(x_Ph, v_Ph, spidx2); + metric.template transform(x_Ph, v_Ph, v2); + } else { + raise::KernelError(HERE, "Unknown simulation engine"); + } + } + // inject + i1s_1(p + offset1) = static_cast(x_Cd[0]); + dx1s_1(p + offset1) = static_cast( + x_Cd[0] - static_cast(i1s_1(p + offset1))); + i1s_2(p + offset2) = i1s_1(p + offset1); + dx1s_2(p + offset2) = dx1s_1(p + offset1); + if constexpr (M::Dim == Dim::_2D or M::Dim == Dim::_3D) { + i2s_1(p + offset1) = static_cast(x_Cd[1]); + dx2s_1(p + offset1) = static_cast( + x_Cd[1] - static_cast(i2s_1(p + offset1))); + i2s_2(p + offset2) = i2s_1(p + offset1); + dx2s_2(p + offset2) = dx2s_1(p + offset1); + if constexpr (S == SimEngine::SRPIC && M::CoordType != Coord::Cart) { + phis_1(p + offset1) = ZERO; + phis_2(p + offset2) = ZERO; + } + } + if constexpr (M::Dim == Dim::_3D) { + i3s_1(p + offset1) = static_cast(x_Cd[2]); + dx3s_1(p + offset1) = static_cast( + x_Cd[2] - static_cast(i3s_1(p + offset1))); + i3s_2(p + offset2) = i3s_1(p + offset1); + dx3s_2(p + offset2) = dx3s_1(p + offset1); + } + ux1s_1(p + offset1) = v1[0]; + ux2s_1(p + offset1) = v1[1]; + ux3s_1(p + offset1) = v1[2]; + ux1s_2(p + offset2) = v2[0]; + ux2s_2(p + offset2) = v2[1]; + ux3s_2(p + offset2) = v2[2]; + tags_1(p + offset1) = ParticleTag::alive; + tags_2(p + offset2) = ParticleTag::alive; + if constexpr (M::CoordType == Coord::Cart) { + weights_1(p + offset1) = ONE; + weights_2(p + offset2) = ONE; + } else { + const auto sqrt_det_h = metric.sqrt_det_h(x_Cd); + weights_1(p + offset1) = sqrt_det_h * inv_V0; + weights_2(p + offset2) = sqrt_det_h * inv_V0; + } + } + }; // struct UniformInjector_kernel + + } // namespace experimental + template struct GlobalInjector_kernel { static_assert(M::is_metric, "M must be a metric class"); From 917599417bbab21bea22053a45643e68a2ec7c4c Mon Sep 17 00:00:00 2001 From: hayk Date: Tue, 29 Apr 2025 04:57:59 -0400 Subject: [PATCH 671/773] experimental maxwellian --- setups/srpic/streaming/pgen.hpp | 24 +++-- src/archetypes/energy_dist.h | 135 +++++++++++++++++++++++++++++ src/archetypes/particle_injector.h | 4 +- 3 files changed, 153 insertions(+), 10 deletions(-) diff --git a/setups/srpic/streaming/pgen.hpp b/setups/srpic/streaming/pgen.hpp index 04aa8ea85..ee14712de 100644 --- a/setups/srpic/streaming/pgen.hpp +++ b/setups/srpic/streaming/pgen.hpp @@ -81,14 +81,22 @@ namespace user { inline void InitPrtls(Domain& domain) { const auto nspec = domain.species.size(); for (auto n = 0u; n < nspec; n += 2) { - const auto injector = - arch::experimental::UniformInjector( - arch::Maxwellian(domain.mesh.metric, - domain.random_pool, - temperatures[n]), - arch::Maxwellian(domain.mesh.metric, - domain.random_pool, - temperatures[n + 1]), + const auto drift_1 = prmvec_t { drifts_in_x[n], + drifts_in_y[n], + drifts_in_z[n] }; + const auto drift_2 = prmvec_t { drifts_in_x[n + 1], + drifts_in_y[n + 1], + drifts_in_z[n + 1] }; + const auto injector = arch::experimental:: + UniformInjector( + arch::experimental::Maxwellian(domain.mesh.metric, + domain.random_pool, + temperatures[n], + drift_1), + arch::experimental::Maxwellian(domain.mesh.metric, + domain.random_pool, + temperatures[n + 1], + drift_2), { n + 1, n + 2 }); arch::experimental::InjectUniform( params, diff --git a/src/archetypes/energy_dist.h b/src/archetypes/energy_dist.h index a108e97a0..67f1bdf8a 100644 --- a/src/archetypes/energy_dist.h +++ b/src/archetypes/energy_dist.h @@ -337,6 +337,141 @@ namespace arch { const bool zero_current; }; + namespace experimental { + + template + struct Maxwellian : public EnergyDistribution { + using EnergyDistribution::metric; + + Maxwellian(const M& metric, + random_number_pool_t& pool, + real_t temperature, + const std::vector& drift_four_vel = { ZERO, ZERO, ZERO }) + : EnergyDistribution { metric } + , pool { pool } + , temperature { temperature } { + raise::ErrorIf(drift_four_vel.size() != 3, + "Maxwellian: Drift velocity must be a 3D vector", + HERE); + raise::ErrorIf(temperature < ZERO, + "Maxwellian: Temperature must be non-negative", + HERE); + if constexpr (M::CoordType == Coord::Cart) { + drift_4vel = NORM(drift_four_vel[0], drift_four_vel[1], drift_four_vel[2]); + if (cmp::AlmostZero_host(drift_4vel)) { + drift_dir = 0; + } else { + drift_3vel = drift_4vel / math::sqrt(ONE + SQR(drift_4vel)); + drift_dir_x1 = drift_four_vel[0] / drift_4vel; + drift_dir_x2 = drift_four_vel[1] / drift_4vel; + drift_dir_x3 = drift_four_vel[2] / drift_4vel; + + // assume drift is in an arbitrary direction + drift_dir = 4; + // check whether drift is in one of principal directions + for (auto d { 0u }; d < 3u; ++d) { + const auto dprev = (d + 2) % 3; + const auto dnext = (d + 1) % 3; + if (cmp::AlmostZero_host(drift_four_vel[dprev]) and + cmp::AlmostZero_host(drift_four_vel[dnext])) { + drift_dir = SIGN(drift_four_vel[d]) * (d + 1); + break; + } + } + } + raise::ErrorIf(drift_dir > 3 and drift_dir != 4, + "Maxwellian: Incorrect drift direction", + HERE); + raise::ErrorIf( + drift_dir != 0 and (M::CoordType != Coord::Cart), + "Maxwellian: Boosting is only supported in Cartesian coordinates", + HERE); + } + } + + Inline void operator()(const coord_t& x_Code, + vec_t& v, + spidx_t sp = 0) const override { + if (cmp::AlmostZero(temperature)) { + v[0] = ZERO; + v[1] = ZERO; + v[2] = ZERO; + } else { + JuttnerSinge(v, temperature, pool); + } + // @note: boost only when using cartesian coordinates + if constexpr (M::CoordType == Coord::Cart) { + if (drift_dir != 0) { + // Boost an isotropic Maxwellian with a drift velocity using + // flipping method https://arxiv.org/pdf/1504.03910.pdf + // 1. apply drift in X1 direction + const auto gamma { U2GAMMA(v[0], v[1], v[2]) }; + auto rand_gen = pool.get_state(); + if (-drift_3vel * v[0] > gamma * Random(rand_gen)) { + v[0] = -v[0]; + } + pool.free_state(rand_gen); + v[0] = math::sqrt(ONE + SQR(drift_4vel)) * (v[0] + drift_3vel * gamma); + // 2. rotate to desired orientation + if (drift_dir == -1) { + v[0] = -v[0]; + } else if (drift_dir == 2 || drift_dir == -2) { + const auto tmp = v[1]; + v[1] = drift_dir > 0 ? v[0] : -v[0]; + v[0] = tmp; + } else if (drift_dir == 3 || drift_dir == -3) { + const auto tmp = v[2]; + v[2] = drift_dir > 0 ? v[0] : -v[0]; + v[0] = tmp; + } else if (drift_dir == 4) { + vec_t v_old; + v_old[0] = v[0]; + v_old[1] = v[1]; + v_old[2] = v[2]; + + v[0] = v_old[0] * drift_dir_x1 - v_old[1] * drift_dir_x2 - + v_old[2] * drift_dir_x3; + v[1] = (v_old[0] * drift_dir_x2 * (drift_dir_x1 + ONE) + + v_old[1] * + (SQR(drift_dir_x1) + drift_dir_x1 + SQR(drift_dir_x3)) - + v_old[2] * drift_dir_x2 * drift_dir_x3) / + (drift_dir_x1 + ONE); + v[2] = (v_old[0] * drift_dir_x3 * (drift_dir_x1 + ONE) - + v_old[1] * drift_dir_x2 * drift_dir_x3 - + v_old[2] * (-drift_dir_x1 + SQR(drift_dir_x3) - ONE)) / + (drift_dir_x1 + ONE); + } + } + } else if constexpr (S == SimEngine::GRPIC) { + // convert from the tetrad basis to covariant + vec_t v_Hat; + v_Hat[0] = v[0]; + v_Hat[1] = v[1]; + v_Hat[2] = v[2]; + metric.template transform(x_Code, v_Hat, v); + } + } + + private: + random_number_pool_t pool; + + const real_t temperature; + + real_t drift_3vel { ZERO }, drift_4vel { ZERO }; + // components of the unit vector in the direction of the drift + real_t drift_dir_x1 { ZERO }, drift_dir_x2 { ZERO }, drift_dir_x3 { ZERO }; + + // values of boost_dir: + // 4 -> arbitrary direction + // 0 -> no drift + // +/- 1 -> +/- x1 + // +/- 2 -> +/- x2 + // +/- 3 -> +/- x3 + short drift_dir { 0 }; + }; + + } // namespace experimental + } // namespace arch #endif // ARCHETYPES_ENERGY_DIST_HPP diff --git a/src/archetypes/particle_injector.h b/src/archetypes/particle_injector.h index 39e457fa8..d15036cf5 100644 --- a/src/archetypes/particle_injector.h +++ b/src/archetypes/particle_injector.h @@ -514,9 +514,9 @@ namespace arch { using energy_dist_2_t = ED2; static_assert(M::is_metric, "M must be a metric class"); static_assert(energy_dist_1_t::is_energy_dist, - "E must be an energy distribution class"); + "ED1 must be an energy distribution class"); static_assert(energy_dist_2_t::is_energy_dist, - "E must be an energy distribution class"); + "ED2 must be an energy distribution class"); static constexpr bool is_uniform_injector { true }; static constexpr Dimension D { M::Dim }; static constexpr Coord C { M::CoordType }; From 71e7799550646ab6a063c21c47d3c7ae1005d2ac Mon Sep 17 00:00:00 2001 From: hayk Date: Tue, 29 Apr 2025 05:36:33 -0400 Subject: [PATCH 672/773] weibel toml --- setups/srpic/streaming/weibel.toml | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/setups/srpic/streaming/weibel.toml b/setups/srpic/streaming/weibel.toml index b67cfc448..0d1f15bca 100644 --- a/setups/srpic/streaming/weibel.toml +++ b/setups/srpic/streaming/weibel.toml @@ -4,7 +4,7 @@ runtime = 100.0 [grid] - resolution = [512, 512] + resolution = [1024, 1024] extent = [[-10.0, 10.0], [-10.0, 10.0]] [grid.metric] @@ -52,20 +52,38 @@ maxnpart = 1e7 [setup] - drifts_in_x = [0.2, 0.2, -0.2, -0.2] + # Drift 4-velocities for each species in all 3 directions + # @type: array of floats (length = nspec) + # @default: [ 0.0, ... ] + drifts_in_x = [0.0, 0.0, 0.0, 0.0] + drifts_in_y = [0.0, 0.0, 0.0, 0.0] + drifts_in_z = [0.3, 0.3, -0.3, -0.3] + # Pair-wise species densities in units of n0 + # @type: array of floats (length = nspec/2) + # @default: [ 2 / nspec, ... ] + densities = [0.5, 0.5] + # Species temperatures in units of m0 (c^2) + # @type: array of floats (length = nspec) + # @default: [ 0.0, ... ] temperatures = [1e-4, 1e-4, 1e-4, 1e-4] [output] interval_time = 0.25 [output.fields] - quantities = ["N_1_2", "N_3_4", "E", "B", "T0i_1", "T0i_3"] + quantities = [ + "N_1_2", + "N_3_4", + "E", + "B", + "T0i_1", + "T0i_2", + "T0i_3", + "T0i_4", + ] [output.particles] enable = false [output.spectra] enable = false - -[diagnostics] - colored_stdout = true From 1f5514319b47ea0a897de985c3335290d67492d6 Mon Sep 17 00:00:00 2001 From: hayk Date: Tue, 29 Apr 2025 07:35:22 -0400 Subject: [PATCH 673/773] pusher=none support --- setups/srpic/streaming/twostream.toml | 83 +++++++++++++++++++++++++++ src/engines/srpic.hpp | 13 +++-- 2 files changed, 90 insertions(+), 6 deletions(-) create mode 100644 setups/srpic/streaming/twostream.toml diff --git a/setups/srpic/streaming/twostream.toml b/setups/srpic/streaming/twostream.toml new file mode 100644 index 000000000..1b2334777 --- /dev/null +++ b/setups/srpic/streaming/twostream.toml @@ -0,0 +1,83 @@ +[simulation] + name = "twostream" + engine = "srpic" + runtime = 1000.0 + +[grid] + resolution = [12288] + extent = [[0.0, 100.0]] + + [grid.metric] + metric = "minkowski" + + [grid.boundaries] + fields = [["PERIODIC"]] + particles = [["PERIODIC"]] + +[scales] + larmor0 = 100.0 + skindepth0 = 10.0 + +[algorithms] + current_filters = 4 + + [algorithms.timestep] + CFL = 0.5 + +[particles] + ppc0 = 16.0 + + [[particles.species]] + label = "e-Px" + mass = 1.0 + charge = -1.0 + maxnpart = 1e7 + + [[particles.species]] + label = "e+bg1" + mass = 1.0 + charge = 1.0 + maxnpart = 1e7 + pusher = "None" + + [[particles.species]] + label = "e-Mx" + mass = 1.0 + charge = -1.0 + maxnpart = 1e7 + + [[particles.species]] + label = "e+bg2" + mass = 1.0 + charge = 1.0 + maxnpart = 1e7 + pusher = "None" + +[setup] + # Drift 4-velocities for each species in all 3 directions + # @type: array of floats (length = nspec) + # @default: [ 0.0, ... ] + drifts_in_x = [0.1, 0.0, -0.1, 0.0] + drifts_in_y = [0.0, 0.0, 0.0, 0.0] + drifts_in_z = [0.0, 0.0, 0.0, 0.0] + # Pair-wise species densities in units of n0 + # @type: array of floats (length = nspec/2) + # @default: [ 2 / nspec, ... ] + densities = [0.5, 0.5] + # Species temperatures in units of m0 (c^2) + # @type: array of floats (length = nspec) + # @default: [ 0.0, ... ] + temperatures = [1e-4, 1e-4, 1e-4, 1e-4] + +[output] + interval_time = 2.0 + + [output.fields] + quantities = ["N_1", "N_3", "E", "B", "J", "T0i_1", "T0i_3"] + + [output.particles] + species = [1, 3] + stride = 10 + + [output.spectra] + enable = false diff --git a/src/engines/srpic.hpp b/src/engines/srpic.hpp index e9e51ab0b..0cdedb9b1 100644 --- a/src/engines/srpic.hpp +++ b/src/engines/srpic.hpp @@ -279,6 +279,9 @@ namespace ntt { } } for (auto& species : domain.species) { + if ((species.pusher() == PrtlPusher::NONE) or (species.npart() == 0)) { + continue; + } species.set_unsorted(); logger::Checkpoint( fmt::format("Launching particle pusher kernel for %d [%s] : %lu", @@ -286,9 +289,6 @@ namespace ntt { species.label().c_str(), species.npart()), HERE); - if (species.npart() == 0) { - continue; - } const auto q_ovr_m = species.mass() > ZERO ? species.charge() / species.mass() : ZERO; @@ -481,6 +481,10 @@ namespace ntt { auto scatter_cur = Kokkos::Experimental::create_scatter_view( domain.fields.cur); for (auto& species : domain.species) { + if ((species.pusher() == PrtlPusher::NONE) or (species.npart() == 0) or + cmp::AlmostZero_host(species.charge())) { + continue; + } logger::Checkpoint( fmt::format("Launching currents deposit kernel for %d [%s] : %lu %f", species.index(), @@ -488,9 +492,6 @@ namespace ntt { species.npart(), (double)species.charge()), HERE); - if (species.npart() == 0 || cmp::AlmostZero(species.charge())) { - continue; - } Kokkos::parallel_for("CurrentsDeposit", species.rangeActiveParticles(), kernel::DepositCurrents_kernel( From deaf19a246b035500607982e0ceaa7226dcc32bd Mon Sep 17 00:00:00 2001 From: gorbunove Date: Wed, 30 Apr 2025 11:47:11 -0500 Subject: [PATCH 674/773] turb bug fix --- setups/srpic/turbulence/pgen.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/setups/srpic/turbulence/pgen.hpp b/setups/srpic/turbulence/pgen.hpp index c056f87fa..4725d67db 100644 --- a/setups/srpic/turbulence/pgen.hpp +++ b/setups/srpic/turbulence/pgen.hpp @@ -378,6 +378,7 @@ namespace user { const auto& pld = domain.species[sp].pld; const auto& tag = domain.species[sp].tag; const auto L = escape_dist; + printf("Entering the escape loop %d, L = %f\n", sp, L); Kokkos::parallel_for( "UpdatePld", domain.species[sp].npart(), @@ -390,7 +391,7 @@ namespace user { pld(p, 0) += ux1(p) * dt / gamma; pld(p, 1) += ux2(p) * dt / gamma; - if ((pld(p, 0) > L) or (pld(p, 1) > L)) { + if (math::abs(pld(p, 0) > L) or (math::abs(pld(p,1)) > L)) { coord_t x_Ph { ZERO }; vec_t u_Mxw { ZERO }; energy_dist(x_Ph, u_Mxw); From 82fc5d8d0e08533767b0cf3b5680f2bca0929568 Mon Sep 17 00:00:00 2001 From: haykh Date: Thu, 1 May 2025 02:23:13 -0400 Subject: [PATCH 675/773] mag toml --- setups/srpic/magnetosphere/magnetosphere.toml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/setups/srpic/magnetosphere/magnetosphere.toml b/setups/srpic/magnetosphere/magnetosphere.toml index 4c7c9117d..1a4af8a09 100644 --- a/setups/srpic/magnetosphere/magnetosphere.toml +++ b/setups/srpic/magnetosphere/magnetosphere.toml @@ -11,7 +11,7 @@ metric = "qspherical" [grid.boundaries] - fields = [["ATMOSPHERE", "ABSORB"]] + fields = [["ATMOSPHERE", "MATCH"]] particles = [["ATMOSPHERE", "ABSORB"]] [grid.boundaries.absorb] @@ -39,7 +39,7 @@ larmor_max = 1.0 [particles] - ppc0 = 5.0 + ppc0 = 10.0 use_weights = true clear_interval = 100 @@ -75,5 +75,4 @@ enable = false [diagnostics] - interval = 50 - colored_stdout = true + interval = 50 From 9ae1415543211072db3b85419939d158e025ce61 Mon Sep 17 00:00:00 2001 From: haykh Date: Thu, 1 May 2025 05:20:13 -0400 Subject: [PATCH 676/773] minimal samples added for external lib testing --- minimal/CMakeLists.txt | 44 ++++ minimal/adios2-mpi.cmake | 17 ++ minimal/adios2-nompi.cmake | 14 ++ minimal/adios2.cpp | 426 +++++++++++++++++++++++++++++++++++++ 4 files changed, 501 insertions(+) create mode 100644 minimal/CMakeLists.txt create mode 100644 minimal/adios2-mpi.cmake create mode 100644 minimal/adios2-nompi.cmake create mode 100644 minimal/adios2.cpp diff --git a/minimal/CMakeLists.txt b/minimal/CMakeLists.txt new file mode 100644 index 000000000..0343a8a74 --- /dev/null +++ b/minimal/CMakeLists.txt @@ -0,0 +1,44 @@ +# cmake-lint: disable=C0103,C0111,E1120,R0913,R0915 + +cmake_minimum_required(VERSION 3.16) +cmake_policy(SET CMP0110 NEW) + +set(PROJECT_NAME minimal-test) + +project(${PROJECT_NAME} LANGUAGES CXX C) +set(CMAKE_CXX_EXTENSIONS OFF) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + +if($DEBUG) + set(CMAKE_BUILD_TYPE + Release + CACHE STRING "CMake build type") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DNDEBUG") +else() + set(CMAKE_BUILD_TYPE + Debug + CACHE STRING "CMake build type") + set(CMAKE_CXX_FLAGS + "${CMAKE_CXX_FLAGS} -DDEBUG -Wall -Wextra -Wno-unknown-pragmas") +endif() + +set(BUILD_TESTING + OFF + CACHE BOOL "Build tests") + +set(MODES + "ADIOS2_NOMPI;ADIOS2_MPI" + CACHE STRING "Build modes") + +if("ADIOS2_NOMPI" IN_LIST MODES) + include(adios2-nompi.cmake) +endif() + +if("ADIOS2_MPI" IN_LIST MODES) + include(adios2-mpi.cmake) +endif() + +message(STATUS "Build modes: ${MODES}") diff --git a/minimal/adios2-mpi.cmake b/minimal/adios2-mpi.cmake new file mode 100644 index 000000000..8e5066f68 --- /dev/null +++ b/minimal/adios2-mpi.cmake @@ -0,0 +1,17 @@ +# cmake-lint: disable=C0103 +include(${CMAKE_CURRENT_SOURCE_DIR}/../cmake/dependencies.cmake) + +set(libs stdc++fs) +set(exec adios2-mpi.xc) +set(src ${CMAKE_CURRENT_SOURCE_DIR}/adios2.cpp) + +find_or_fetch_dependency(MPI FALSE REQUIRED) +find_or_fetch_dependency(Kokkos FALSE QUIET) +find_or_fetch_dependency(adios2 FALSE QUIET) +list(APPEND libs MPI::MPI_CXX Kokkos::kokkos adios2::cxx11_mpi) + +add_executable(${exec} ${src}) + +target_include_directories(${exec} PUBLIC ${MPI_CXX_INCLUDE_PATH}) +target_compile_options(${exec} PUBLIC "-D MPI_ENABLED") +target_link_libraries(${exec} ${libs}) diff --git a/minimal/adios2-nompi.cmake b/minimal/adios2-nompi.cmake new file mode 100644 index 000000000..c593d72e0 --- /dev/null +++ b/minimal/adios2-nompi.cmake @@ -0,0 +1,14 @@ +# cmake-lint: disable=C0103 +include(${CMAKE_CURRENT_SOURCE_DIR}/../cmake/dependencies.cmake) + +set(libs stdc++fs) +set(exec adios2-nompi.xc) +set(src ${CMAKE_CURRENT_SOURCE_DIR}/adios2.cpp) + +find_or_fetch_dependency(Kokkos FALSE QUIET) +find_or_fetch_dependency(adios2 FALSE QUIET) +list(APPEND libs Kokkos::kokkos adios2::cxx11) + +add_executable(${exec} ${src}) + +target_link_libraries(${exec} ${libs}) diff --git a/minimal/adios2.cpp b/minimal/adios2.cpp new file mode 100644 index 000000000..5811f64d2 --- /dev/null +++ b/minimal/adios2.cpp @@ -0,0 +1,426 @@ +#include +#include +#include + +#if defined(MPI_ENABLED) + #include + #define MPI_ROOT_RANK 0 +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +auto pad(const std::string&, std::size_t, char, bool = false) -> std::string; + +template +void CallOnce(Func, Args&&...); + +template +auto define_constdim_array(adios2::IO&, + const std::vector&, + const std::vector&, + const std::vector&) -> std::string; + +template +auto define_unknowndim_array(adios2::IO&) -> std::string; + +template +void put_constdim_array(adios2::IO&, adios2::Engine&, const A&, const std::string&); + +template +void put_unknowndim_array(adios2::IO&, + adios2::Engine&, + const Kokkos::View&, + std::size_t, + const std::string&); + +auto main(int argc, char** argv) -> int { + try { + Kokkos::initialize(argc, argv); +#if defined(MPI_ENABLED) + MPI_Init(&argc, &argv); + adios2::ADIOS adios { MPI_COMM_WORLD }; +#else + adios2::ADIOS adios; +#endif + + std::string engine = "hdf5"; + if (argc > 1) { + engine = std::string(argv[1]); + if (engine != "hdf5" && engine != "bp") { + throw std::invalid_argument("Engine must be either 'hdf5' or 'bp'"); + } + } + const std::string format = (engine == "hdf5") ? "h5" : "bp"; + + auto io = adios.DeclareIO("Test::Output"); + io.SetEngine(engine); + + io.DefineAttribute("Attr::Int", 42); + io.DefineAttribute("Attr::Float", 42.0f); + io.DefineAttribute("Attr::Double", 42.0); + io.DefineAttribute("Attr::String", engine); + + io.DefineVariable("Var::Int"); + io.DefineVariable("Var::Size_t"); + + int rank = 0, size = 1; +#if defined(MPI_ENABLED) + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Comm_size(MPI_COMM_WORLD, &size); +#endif + + // global sizes + const std::size_t Sx_1d = (size - 1) * 1000 + 230; + const std::size_t Sx_2d = 100, Sy_2d = (size - 1) * 100 + 23; + const std::size_t Sx_3d = 10, Sy_3d = 10, Sz_3d = (size - 1) * 10 + 3; + + // local sizes + const std::size_t sx_1d = (rank != size - 1) ? 1000 : 230; + const std::size_t sx_2d = 100, sy_2d = (rank != size - 1) ? 100 : 23; + const std::size_t sx_3d = 10, sy_3d = 10, sz_3d = (rank != size - 1) ? 10 : 3; + + // displacements + const std::size_t ox_1d = rank * 1000; + const std::size_t ox_2d = 0, oy_2d = rank * 100; + const std::size_t ox_3d = 0, oy_3d = 0, oz_3d = rank * 10; + + std::vector vars; + + { + vars.push_back( + define_constdim_array(io, { Sx_1d }, { ox_1d }, { sx_1d })); + vars.push_back(define_constdim_array(io, + { Sx_2d, Sy_2d }, + { ox_2d, oy_2d }, + { sx_2d, sy_2d })); + vars.push_back(define_constdim_array(io, + { Sx_3d, Sy_3d, Sz_3d }, + { ox_3d, oy_3d, oz_3d }, + { sx_3d, sy_3d, sz_3d })); + vars.push_back( + define_constdim_array(io, { Sx_1d }, { ox_1d }, { sx_1d })); + vars.push_back(define_constdim_array(io, + { Sx_2d, Sy_2d }, + { ox_2d, oy_2d }, + { sx_2d, sy_2d })); + vars.push_back(define_constdim_array(io, + { Sx_3d, Sy_3d, Sz_3d }, + { ox_3d, oy_3d, oz_3d }, + { sx_3d, sy_3d, sz_3d })); + } + + { + vars.push_back(define_unknowndim_array(io)); + vars.push_back(define_unknowndim_array(io)); + vars.push_back(define_unknowndim_array(io)); + } + + Kokkos::View constdim_1d_f { "constdim_1d_f", sx_1d }; + Kokkos::View constdim_2d_f { "constdim_2d_f", sx_2d, sy_2d }; + Kokkos::View constdim_3d_f { "constdim_3d_f", sx_3d, sy_3d, sz_3d }; + + Kokkos::View constdim_1d_d { "constdim_1d_d", sx_1d }; + Kokkos::View constdim_2d_d { "constdim_2d_d", sx_2d, sy_2d }; + Kokkos::View constdim_3d_d { "constdim_3d_d", sx_3d, sy_3d, sz_3d }; + + { + // fill 1d + Kokkos::parallel_for( + "fill_constdim_1d_f", + Kokkos::RangePolicy<>(0, sx_1d), + KOKKOS_LAMBDA(std::size_t i) { + constdim_1d_f(i) = static_cast(ox_1d + i); + constdim_1d_d(i) = static_cast(ox_1d + i); + }); + + // fill 2d + Kokkos::parallel_for( + "fill_constdim_2d_f", + Kokkos::MDRangePolicy>({ 0, 0 }, { sx_2d, sy_2d }), + KOKKOS_LAMBDA(std::size_t i, std::size_t j) { + constdim_2d_f(i, j) = static_cast(ox_2d + i + (oy_2d + j) * Sx_2d); + constdim_2d_d(i, j) = static_cast(ox_2d + i + (oy_2d + j) * Sx_2d); + }); + + // fill 3d + Kokkos::parallel_for( + "fill_constdim_3d_f", + Kokkos::MDRangePolicy>({ 0, 0, 0 }, { sx_3d, sy_3d, sz_3d }), + KOKKOS_LAMBDA(std::size_t i, std::size_t j, std::size_t k) { + constdim_3d_f(i, j, k) = static_cast( + ox_3d + i + (oy_3d + j + (oz_3d + k) * Sy_3d) * Sx_3d); + constdim_3d_d(i, j, k) = static_cast( + ox_3d + i + (oy_3d + j + (oz_3d + k) * Sy_3d) * Sx_3d); + }); + } + + { + // test multiple file mode + const std::string path = "steps"; + CallOnce( + [](auto&& path) { + const std::filesystem::path parent_path { path }; + if (std::filesystem::exists(parent_path)) { + std::filesystem::remove_all(parent_path); + } + std::filesystem::create_directory(path); + }, + path); + for (auto step { 0u }; step < 5u; ++step) { + const std::string filename = path + "/step_" + + pad(std::to_string(step * 20u), 6, '0') + + "." + format; + auto writer = io.Open(filename, adios2::Mode::Write); + writer.BeginStep(); + + { + // constant dim arrays + put_constdim_array(io, + writer, + constdim_1d_f, + vars[0]); + put_constdim_array(io, + writer, + constdim_2d_f, + vars[1]); + put_constdim_array(io, + writer, + constdim_3d_f, + vars[2]); + put_constdim_array(io, + writer, + constdim_1d_d, + vars[3]); + put_constdim_array(io, + writer, + constdim_2d_d, + vars[4]); + put_constdim_array(io, + writer, + constdim_3d_d, + vars[5]); + } + + { + // unknown dim arrays + const std::size_t nelems = static_cast( + (std::sin((step + 1 + rank) * 0.25) + 2.0) * 1000.0); + + Kokkos::View unknowndim_f { "unknowndim_f", nelems }; + Kokkos::View unknowndim_d { "unknowndim_d", nelems }; + Kokkos::View unknowndim_i { "unknowndim_i", nelems }; + + // fill unknown dim arrays + Kokkos::parallel_for( + "fill_unknowndim", + Kokkos::RangePolicy<>(0, nelems), + KOKKOS_LAMBDA(std::size_t i) { + unknowndim_f(i) = static_cast(i + step * 1000); + unknowndim_d(i) = static_cast(i + step * 1000); + unknowndim_i(i) = static_cast(i + step * 1000); + }); + + put_unknowndim_array(io, writer, unknowndim_f, nelems, vars[6]); + put_unknowndim_array(io, writer, unknowndim_d, nelems, vars[7]); + put_unknowndim_array(io, writer, unknowndim_i, nelems, vars[8]); + } + + writer.EndStep(); + writer.Close(); + } + } + { + // test single file mode + const std::string filename = "allsteps." + format; + adios2::Mode mode = adios2::Mode::Write; + for (auto step { 0u }; step < 5u; ++step) { + auto writer = io.Open(filename, mode); + writer.BeginStep(); + + { + // constant dim arrays + put_constdim_array(io, + writer, + constdim_1d_f, + vars[0]); + put_constdim_array(io, + writer, + constdim_2d_f, + vars[1]); + put_constdim_array(io, + writer, + constdim_3d_f, + vars[2]); + put_constdim_array(io, + writer, + constdim_1d_d, + vars[3]); + put_constdim_array(io, + writer, + constdim_2d_d, + vars[4]); + put_constdim_array(io, + writer, + constdim_3d_d, + vars[5]); + } + + { + // unknown dim arrays + const std::size_t nelems = static_cast( + (std::sin((step + 1 + rank) * 0.25) + 2.0) * 1000.0); + + Kokkos::View unknowndim_f { "unknowndim_f", nelems }; + Kokkos::View unknowndim_d { "unknowndim_d", nelems }; + Kokkos::View unknowndim_i { "unknowndim_i", nelems }; + + // fill unknown dim arrays + Kokkos::parallel_for( + "fill_unknowndim", + Kokkos::RangePolicy<>(0, nelems), + KOKKOS_LAMBDA(std::size_t i) { + unknowndim_f(i) = static_cast(i + step * 1000); + unknowndim_d(i) = static_cast(i + step * 1000); + unknowndim_i(i) = static_cast(i + step * 1000); + }); + + put_unknowndim_array(io, writer, unknowndim_f, nelems, vars[6]); + put_unknowndim_array(io, writer, unknowndim_d, nelems, vars[7]); + put_unknowndim_array(io, writer, unknowndim_i, nelems, vars[8]); + } + + writer.EndStep(); + writer.Close(); + mode = adios2::Mode::Append; + } + } + } catch (const std::exception& e) { +#if defined(MPI_ENABLED) + if (MPI_COMM_WORLD != MPI_COMM_NULL) { + MPI_Finalize(); + } +#endif + if (Kokkos::is_initialized()) { + Kokkos::finalize(); + } + std::cerr << "Error: " << e.what() << std::endl; + return 1; + } + +#if defined(MPI_ENABLED) + MPI_Finalize(); +#endif + Kokkos::finalize(); + return 0; +} + +auto pad(const std::string& str, std::size_t n, char c, bool right) -> std::string { + if (n <= str.size()) { + return str; + } + if (right) { + return str + std::string(n - str.size(), c); + } + return std::string(n - str.size(), c) + str; +} + +#if !defined(MPI_ENABLED) + +template +void CallOnce(Func func, Args&&... args) { + func(std::forward(args)...); +} + +#else + +template +void CallOnce(Func func, Args&&... args) { + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + if (rank == MPI_ROOT_RANK) { + func(std::forward(args)...); + } +} +#endif + +template +auto define_constdim_array(adios2::IO& io, + const std::vector& glob_shape, + const std::vector& loc_corner, + const std::vector& loc_shape) -> std::string { + const std::string arrname = "ConstantDimArr" + + std::to_string(glob_shape.size()) + + "D::" + std::string(typeid(T).name()); + io.DefineVariable(arrname, glob_shape, loc_corner, loc_shape, adios2::ConstantDims); + return arrname; +} + +template +auto define_unknowndim_array(adios2::IO& io) -> std::string { + const std::string arrname = "UnknownDimArr::" + std::string(typeid(T).name()); + io.DefineVariable(arrname, + { adios2::UnknownDim }, + { adios2::UnknownDim }, + { adios2::UnknownDim }); + return arrname; +} + +template +void put_constdim_array(adios2::IO& io, + adios2::Engine& writer, + const A& array, + const std::string& varname) { + auto var = io.InquireVariable(varname); + if (!var) { + throw std::runtime_error("Variable not found: " + varname); + } + auto array_h = Kokkos::create_mirror_view(array); + Kokkos::deep_copy(array_h, array); + writer.Put(var, array_h); +} + +template +void put_unknowndim_array(adios2::IO& io, + adios2::Engine& writer, + const Kokkos::View& array, + std::size_t nelems, + const std::string& varname) { + auto var = io.InquireVariable(varname); + if (!var) { + throw std::runtime_error("Variable not found: " + varname); + } + std::size_t glob_nelems = nelems; + std::size_t offset_nelems = 0u; +#if defined(MPI_ENABLED) + int rank, size; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Comm_size(MPI_COMM_WORLD, &size); + std::vector all_nelems(size); + MPI_Allgather(&nelems, + 1, + MPI_UNSIGNED_LONG, + all_nelems.data(), + 1, + MPI_UNSIGNED_LONG, + MPI_COMM_WORLD); + glob_nelems = 0u; + for (int r = 0; r < size; ++r) { + if (r < rank) { + offset_nelems += all_nelems[r]; + } + glob_nelems += all_nelems[r]; + } +#endif + var.SetShape({ glob_nelems }); + var.SetSelection(adios2::Box({ offset_nelems }, { nelems })); + auto array_h = Kokkos::create_mirror_view(array); + Kokkos::deep_copy(array_h, array); + writer.Put(var, array_h); +} From c7e6405eb63a421077fb8b9644dbef544e56682e Mon Sep 17 00:00:00 2001 From: haykh Date: Thu, 1 May 2025 06:17:32 -0400 Subject: [PATCH 677/773] minimal mpi compile --- minimal/CMakeLists.txt | 4 + minimal/mpi.cmake | 14 +++ minimal/mpi.cpp | 242 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 260 insertions(+) create mode 100644 minimal/mpi.cmake create mode 100644 minimal/mpi.cpp diff --git a/minimal/CMakeLists.txt b/minimal/CMakeLists.txt index 0343a8a74..1d906f40c 100644 --- a/minimal/CMakeLists.txt +++ b/minimal/CMakeLists.txt @@ -41,4 +41,8 @@ if("ADIOS2_MPI" IN_LIST MODES) include(adios2-mpi.cmake) endif() +if("MPI" IN_LIST MODES) + include(mpi.cmake) +endif() + message(STATUS "Build modes: ${MODES}") diff --git a/minimal/mpi.cmake b/minimal/mpi.cmake new file mode 100644 index 000000000..22155bdaa --- /dev/null +++ b/minimal/mpi.cmake @@ -0,0 +1,14 @@ +# cmake-lint: disable=C0103 +include(${CMAKE_CURRENT_SOURCE_DIR}/../cmake/dependencies.cmake) + +set(exec mpi.xc) +set(src ${CMAKE_CURRENT_SOURCE_DIR}/mpi.cpp) + +find_or_fetch_dependency(MPI FALSE REQUIRED) +find_or_fetch_dependency(Kokkos FALSE QUIET) +list(APPEND libs MPI::MPI_CXX Kokkos::kokkos) + +add_executable(${exec} ${src}) + +target_include_directories(${exec} PUBLIC ${MPI_CXX_INCLUDE_PATH}) +target_link_libraries(${exec} ${libs}) diff --git a/minimal/mpi.cpp b/minimal/mpi.cpp new file mode 100644 index 000000000..7c15603bb --- /dev/null +++ b/minimal/mpi.cpp @@ -0,0 +1,242 @@ +#include +#include + +#include +#include +#include +#include +#include + +#define MPI_ROOT_RANK 0 +#define N_GHOSTS 2 + +template +void CallOnce(Func, Args&&...); + +template +using R = std::conditional_t< + D == 1, + T*, + std::conditional_t>>; + +template +void send_recv(int send_to, + int recv_from, + bool sendxmin, + const Kokkos::View[N]>& view, + std::size_t smallsize) { + const auto mpi_type = std::is_same_v ? MPI_FLOAT : MPI_DOUBLE; + std::size_t nsend = 0; + Kokkos::View[N]> send_buffer; + if (send_to == MPI_PROC_NULL) { + nsend = 0; + } else { + std::pair range = { 0, N_GHOSTS }; + if (not sendxmin) { + range = { view.extent(0) - N_GHOSTS, view.extent(0) }; + } + if constexpr (D == 1) { + nsend = N_GHOSTS * N; + send_buffer = Kokkos::View[N]> { + "comm_1d_send_buffer", N_GHOSTS + }; + Kokkos::deep_copy(send_buffer, Kokkos::subview(view, range, Kokkos::ALL)); + } else if constexpr (D == 2) { + nsend = N_GHOSTS * smallsize * N; + send_buffer = Kokkos::View[N]> { + "comm_2d_send_buffer", N_GHOSTS, smallsize + }; + Kokkos::deep_copy(send_buffer, + Kokkos::subview(view, range, Kokkos::ALL, Kokkos::ALL)); + } else if constexpr (D == 3) { + nsend = N_GHOSTS * smallsize * smallsize * N; + send_buffer = Kokkos::View[N]> { + "comm_3d_send_buffer", N_GHOSTS, smallsize, smallsize + }; + Kokkos::deep_copy( + send_buffer, + Kokkos::subview(view, range, Kokkos::ALL, Kokkos::ALL, Kokkos::ALL)); + } + } + + std::size_t nrecv = 0; + Kokkos::View[N]> recv_buffer; + if (recv_from == MPI_PROC_NULL) { + nrecv = 0; + } else { + if constexpr (D == 1) { + nrecv = N_GHOSTS * N; + recv_buffer = Kokkos::View[N]> { + "comm_1d_recv_buffer", N_GHOSTS + }; + } else if constexpr (D == 2) { + nrecv = N_GHOSTS * smallsize * N; + recv_buffer = Kokkos::View[N]> { + "comm_2d_recv_buffer", N_GHOSTS, smallsize + }; + } else if constexpr (D == 3) { + nrecv = N_GHOSTS * smallsize * smallsize * N; + recv_buffer = Kokkos::View[N]> { + "comm_3d_recv_buffer", N_GHOSTS, smallsize, smallsize + }; + } + } + + if (nrecv == 0 and nsend == 0) { + throw std::invalid_argument( + "Both nsend and nrecv are zero, no communication to perform."); + } else if (nrecv > 0 and nsend > 0) { + MPI_Sendrecv(send_buffer.data(), + nsend, + mpi_type, + send_to, + 0, + recv_buffer.data(), + nrecv, + mpi_type, + recv_from, + 0, + MPI_COMM_WORLD, + MPI_STATUS_IGNORE); + } else if (nrecv > 0) { + MPI_Recv(recv_buffer.data(), + nrecv, + mpi_type, + recv_from, + 0, + MPI_COMM_WORLD, + MPI_STATUS_IGNORE); + } else if (nsend > 0) { + MPI_Send(send_buffer.data(), nsend, mpi_type, send_to, 0, MPI_COMM_WORLD); + } + + if (nrecv > 0) { + std::pair range = { view.extent(0) - N_GHOSTS, + view.extent(0) }; + if (not sendxmin) { + range = { 0, N_GHOSTS }; + } + if constexpr (D == 1) { + Kokkos::deep_copy(Kokkos::subview(view, range, Kokkos::ALL), recv_buffer); + } else if constexpr (D == 2) { + Kokkos::deep_copy(Kokkos::subview(view, range, Kokkos::ALL, Kokkos::ALL), + recv_buffer); + } else if constexpr (D == 3) { + Kokkos::deep_copy( + Kokkos::subview(view, range, Kokkos::ALL, Kokkos::ALL, Kokkos::ALL), + recv_buffer); + } + } +} + +template +void comm(int rank, int size, std::size_t bigsize, std::size_t smallsize) { + static_assert(D <= 3 and D != 0, "Only dimensions 1, 2, and 3 are supported."); + static_assert(N == 3 or N == 6, "Only 3 or 6 last indices are supported."); + static_assert(std::is_same_v || std::is_same_v, + "Only float and double types are supported."); + + // smallsize must be the same for all ranks + if (bigsize < 2 * N_GHOSTS) { + throw std::invalid_argument( + "bigsize must be at least 2 * N_GHOSTS for communication to work."); + } + + Kokkos::View[N]> view; + + // define and fill the view + if constexpr (D == 1) { + view = Kokkos::View[N]> { + "comm_1d_view", bigsize + }; + Kokkos::parallel_for( + "fill_comm_1d_view", + Kokkos::MDRangePolicy>({ 0, 0 }, + { view.extent(0), view.extent(1) }), + KOKKOS_LAMBDA(std::size_t i, std::size_t c) { + view(i, c) = static_cast(i * c + rank); + }); + } else if constexpr (D == 2) { + view = Kokkos::View[N]> { + "comm_2d_view", bigsize, smallsize + }; + Kokkos::parallel_for( + "fill_comm_2d_view", + Kokkos::MDRangePolicy>( + { 0, 0, 0 }, + { view.extent(0), view.extent(1), view.extent(2) }), + KOKKOS_LAMBDA(std::size_t i, std::size_t j, std::size_t c) { + view(i, j, c) = static_cast(i * j * c + rank); + }); + } else if constexpr (D == 3) { + view = Kokkos::View[N]> { + "comm_3d_view", bigsize, smallsize, smallsize + }; + Kokkos::parallel_for( + "fill_comm_3d_view", + Kokkos::MDRangePolicy>( + { 0, 0, 0, 0 }, + { view.extent(0), view.extent(1), view.extent(2), view.extent(3) }), + KOKKOS_LAMBDA(std::size_t i, std::size_t j, std::size_t k, std::size_t c) { + view(i, j, k, c) = static_cast(i * j * k * c + rank); + }); + } + + // communicate + const int r_neighbor = (rank != size - 1) ? rank + 1 : MPI_PROC_NULL; + const int l_neighbor = (rank != 0) ? rank - 1 : MPI_PROC_NULL; + + send_recv(r_neighbor, l_neighbor, false, view, smallsize); + send_recv(l_neighbor, r_neighbor, true, view, smallsize); +} + +auto main(int argc, char** argv) -> int { + try { + Kokkos::initialize(argc, argv); + MPI_Init(&argc, &argv); + int rank, size; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Comm_size(MPI_COMM_WORLD, &size); + + const std::size_t bigsize = (std::sin((rank + 1) * 0.25) + 2) * 1e3; + const std::size_t smallsize = 123; + + comm(rank, size, bigsize, smallsize); + comm(rank, size, bigsize, smallsize); + comm(rank, size, bigsize, smallsize); + + comm(rank, size, bigsize, smallsize); + comm(rank, size, bigsize, smallsize); + comm(rank, size, bigsize, smallsize); + + comm(rank, size, bigsize, smallsize); + comm(rank, size, bigsize, smallsize); + comm(rank, size, bigsize, smallsize); + + comm(rank, size, bigsize, smallsize); + comm(rank, size, bigsize, smallsize); + comm(rank, size, bigsize, smallsize); + } catch (const std::exception& e) { + if (MPI_COMM_WORLD != MPI_COMM_NULL) { + MPI_Finalize(); + } + if (Kokkos::is_initialized()) { + Kokkos::finalize(); + } + std::cerr << "Error: " << e.what() << std::endl; + return 1; + } + + MPI_Finalize(); + Kokkos::finalize(); + return 0; +} + +template +void CallOnce(Func func, Args&&... args) { + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + if (rank == MPI_ROOT_RANK) { + func(std::forward(args)...); + } +} From f8550ddf0570d0832f56f3afd753cea96df5b34a Mon Sep 17 00:00:00 2001 From: haykh Date: Thu, 1 May 2025 06:37:07 -0400 Subject: [PATCH 678/773] gpuawarempi added to minimal --- minimal/README.md | 20 +++++++++++++++++ minimal/adios2.cpp | 13 ++++++++++++ minimal/mpi.cmake | 17 +++++++++++++++ minimal/mpi.cpp | 53 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 103 insertions(+) create mode 100644 minimal/README.md diff --git a/minimal/README.md b/minimal/README.md new file mode 100644 index 000000000..8c680c1a5 --- /dev/null +++ b/minimal/README.md @@ -0,0 +1,20 @@ +# Minimal third-party tests + +These minimal tests are designed to test the third-party libraries outside of the `Entity` scope. These tests will show whether there is an issue with the way third-party are installed (or the cluster is set up). + +To compile: + +```sh +cmake -B build -D MODES="MPI;ADIOS2_NOMPI;ADIOS2_MPI" +cmake --build build -j +``` + +This will produce executables, one for each test, in the `build` directory. + +The `MODES` flag determines the tests it will generate and can be a subset of the following (separated with a `;`): + +- `MPI` test of pure MPI + Kokkos (can also add `-D GPU_AWARE_MPI=OFF` to disable the GPU-aware MPI explicitly); +- `ADIOS2_NOMPI` test of ADIOS2 library without MPI; +- `ADIOS2_MPI` same but with MPI. + +All tests also use `Kokkos`. To build `ADIOS2` or `Kokkos` in-tree, you may pass the regular `-D Kokkos_***` and `-D ADIOS2_***` flags to cmake`. diff --git a/minimal/adios2.cpp b/minimal/adios2.cpp index 5811f64d2..8f0fb7240 100644 --- a/minimal/adios2.cpp +++ b/minimal/adios2.cpp @@ -91,6 +91,19 @@ auto main(int argc, char** argv) -> int { const std::size_t ox_2d = 0, oy_2d = rank * 100; const std::size_t ox_3d = 0, oy_3d = 0, oz_3d = rank * 10; + CallOnce( + [](auto&& size, auto&& bigsize, auto&& smallsize) { + std::cout << "Running ADIOS2 test" << std::endl; +#if defined(MPI_ENABLED) + std::cout << "- Number of MPI ranks: " << size << std::endl; +#else + std::cout << "- No MPI" << std::endl; +#endif + }, + size, + bigsize, + smallsize); + std::vector vars; { diff --git a/minimal/mpi.cmake b/minimal/mpi.cmake index 22155bdaa..059f0181f 100644 --- a/minimal/mpi.cmake +++ b/minimal/mpi.cmake @@ -12,3 +12,20 @@ add_executable(${exec} ${src}) target_include_directories(${exec} PUBLIC ${MPI_CXX_INCLUDE_PATH}) target_link_libraries(${exec} ${libs}) + +set(GPU_AWARE_MPI + ON + CACHE BOOL "Enable GPU-aware MPI support") + +if(("${Kokkos_DEVICES}" MATCHES "CUDA") + OR ("${Kokkos_DEVICES}" MATCHES "HIP") + OR ("${Kokkos_DEVICES}" MATCHES "SYCL")) + set(DEVICE_ENABLED ON) + target_copmile_options(${exec} PRIVATE -DDEVICE_ENABLED) +else() + set(DEVICE_ENABLED OFF) +endif() + +if(${GPU_AWARE_MPI}) + target_compile_options(${exec} PRIVATE -DGPU_AWARE_MPI) +endif() diff --git a/minimal/mpi.cpp b/minimal/mpi.cpp index 7c15603bb..022a8a749 100644 --- a/minimal/mpi.cpp +++ b/minimal/mpi.cpp @@ -86,6 +86,7 @@ void send_recv(int send_to, throw std::invalid_argument( "Both nsend and nrecv are zero, no communication to perform."); } else if (nrecv > 0 and nsend > 0) { +#if defined(GPU_AWARE_MPI) || !defined(DEVICE_ENABLED) MPI_Sendrecv(send_buffer.data(), nsend, mpi_type, @@ -98,7 +99,26 @@ void send_recv(int send_to, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE); +#else + auto send_buffer_h = Kokkos::create_mirror_view(send_buffer); + auto recv_buffer_h = Kokkos::create_mirror_view(recv_buffer); + Kokkos::deep_copy(send_buffer_h, send_buffer); + MPI_Sendrecv(send_buffer_h.data(), + nsend, + mpi_type, + send_to, + 0, + recv_buffer_h.data(), + nrecv, + mpi_type, + recv_from, + 0, + MPI_COMM_WORLD, + MPI_STATUS_IGNORE); + Kokkos::deep_copy(recv_buffer, recv_buffer_h); +#endif } else if (nrecv > 0) { +#if defined(GPU_AWARE_MPI) || !defined(DEVICE_ENABLED) MPI_Recv(recv_buffer.data(), nrecv, mpi_type, @@ -106,8 +126,25 @@ void send_recv(int send_to, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE); +#else + auto recv_buffer_h = Kokkos::create_mirror_view(recv_buffer); + MPI_Recv(recv_buffer_h.data(), + nrecv, + mpi_type, + recv_from, + 0, + MPI_COMM_WORLD, + MPI_STATUS_IGNORE); + Kokkos::deep_copy(recv_buffer, recv_buffer_h); +#endif } else if (nsend > 0) { +#if defined(GPU_AWARE_MPI) || !defined(DEVICE_ENABLED) MPI_Send(send_buffer.data(), nsend, mpi_type, send_to, 0, MPI_COMM_WORLD); +#else + auto send_buffer_h = Kokkos::create_mirror_view(send_buffer); + Kokkos::deep_copy(send_buffer_h, send_buffer); + MPI_Send(send_buffer_h.data(), nsend, mpi_type, send_to, 0, MPI_COMM_WORLD); +#endif } if (nrecv > 0) { @@ -201,6 +238,22 @@ auto main(int argc, char** argv) -> int { const std::size_t bigsize = (std::sin((rank + 1) * 0.25) + 2) * 1e3; const std::size_t smallsize = 123; + CallOnce( + [](auto&& size, auto&& bigsize, auto&& smallsize) { + std::cout << "Running the MPI communication test" << std::endl; + std::cout << "- Number of MPI ranks: " << size << std::endl; + std::cout << "- Big size: " << bigsize << std::endl; + std::cout << "- Small size: " << smallsize << std::endl; +#if defined(GPU_AWARE_MPI) && defined(DEVICE_ENABLED) + std::cout << "- GPU-aware MPI is enabled" << std::endl; +#else + std::cout << "- GPU-aware MPI is disabled" << std::endl; +#endif + }, + size, + bigsize, + smallsize); + comm(rank, size, bigsize, smallsize); comm(rank, size, bigsize, smallsize); comm(rank, size, bigsize, smallsize); From a4a3987b1cbce076ad01a979f6694b3a85cb19a4 Mon Sep 17 00:00:00 2001 From: haykh Date: Thu, 1 May 2025 06:38:30 -0400 Subject: [PATCH 679/773] minor bug --- minimal/mpi.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/minimal/mpi.cmake b/minimal/mpi.cmake index 059f0181f..f27195c07 100644 --- a/minimal/mpi.cmake +++ b/minimal/mpi.cmake @@ -21,7 +21,7 @@ if(("${Kokkos_DEVICES}" MATCHES "CUDA") OR ("${Kokkos_DEVICES}" MATCHES "HIP") OR ("${Kokkos_DEVICES}" MATCHES "SYCL")) set(DEVICE_ENABLED ON) - target_copmile_options(${exec} PRIVATE -DDEVICE_ENABLED) + target_compile_options(${exec} PRIVATE -DDEVICE_ENABLED) else() set(DEVICE_ENABLED OFF) endif() From 03d9f2348ca3da1671b2c65d223cf5badb3542f1 Mon Sep 17 00:00:00 2001 From: haykh Date: Thu, 1 May 2025 07:05:18 -0400 Subject: [PATCH 680/773] added simpler mpi test --- minimal/CMakeLists.txt | 4 ++ minimal/README.md | 3 +- minimal/adios2.cpp | 7 ++-- minimal/mpi-simple.cmake | 31 +++++++++++++++ minimal/mpi-simple.cpp | 84 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 124 insertions(+), 5 deletions(-) create mode 100644 minimal/mpi-simple.cmake create mode 100644 minimal/mpi-simple.cpp diff --git a/minimal/CMakeLists.txt b/minimal/CMakeLists.txt index 1d906f40c..58191d97c 100644 --- a/minimal/CMakeLists.txt +++ b/minimal/CMakeLists.txt @@ -45,4 +45,8 @@ if("MPI" IN_LIST MODES) include(mpi.cmake) endif() +if("MPI_SIMPLE" IN_LIST MODES) + include(mpi-simple.cmake) +endif() + message(STATUS "Build modes: ${MODES}") diff --git a/minimal/README.md b/minimal/README.md index 8c680c1a5..b7e5691a2 100644 --- a/minimal/README.md +++ b/minimal/README.md @@ -5,7 +5,7 @@ These minimal tests are designed to test the third-party libraries outside of th To compile: ```sh -cmake -B build -D MODES="MPI;ADIOS2_NOMPI;ADIOS2_MPI" +cmake -B build -D MODES="MPI;MPI_SIMPLE;ADIOS2_NOMPI;ADIOS2_MPI" cmake --build build -j ``` @@ -14,6 +14,7 @@ This will produce executables, one for each test, in the `build` directory. The `MODES` flag determines the tests it will generate and can be a subset of the following (separated with a `;`): - `MPI` test of pure MPI + Kokkos (can also add `-D GPU_AWARE_MPI=OFF` to disable the GPU-aware MPI explicitly); +- `MPI_SIMPLE` a simpler test of pure MPI + Kokkos; - `ADIOS2_NOMPI` test of ADIOS2 library without MPI; - `ADIOS2_MPI` same but with MPI. diff --git a/minimal/adios2.cpp b/minimal/adios2.cpp index 8f0fb7240..cd4ca3d6f 100644 --- a/minimal/adios2.cpp +++ b/minimal/adios2.cpp @@ -92,17 +92,16 @@ auto main(int argc, char** argv) -> int { const std::size_t ox_3d = 0, oy_3d = 0, oz_3d = rank * 10; CallOnce( - [](auto&& size, auto&& bigsize, auto&& smallsize) { + [](auto&& size) { std::cout << "Running ADIOS2 test" << std::endl; #if defined(MPI_ENABLED) std::cout << "- Number of MPI ranks: " << size << std::endl; #else + (void)size; std::cout << "- No MPI" << std::endl; #endif }, - size, - bigsize, - smallsize); + size); std::vector vars; diff --git a/minimal/mpi-simple.cmake b/minimal/mpi-simple.cmake new file mode 100644 index 000000000..136d009c8 --- /dev/null +++ b/minimal/mpi-simple.cmake @@ -0,0 +1,31 @@ +# cmake-lint: disable=C0103 +include(${CMAKE_CURRENT_SOURCE_DIR}/../cmake/dependencies.cmake) + +set(exec mpi-simple.xc) +set(src ${CMAKE_CURRENT_SOURCE_DIR}/mpi-simple.cpp) + +find_or_fetch_dependency(MPI FALSE REQUIRED) +find_or_fetch_dependency(Kokkos FALSE QUIET) +list(APPEND libs MPI::MPI_CXX Kokkos::kokkos) + +add_executable(${exec} ${src}) + +target_include_directories(${exec} PUBLIC ${MPI_CXX_INCLUDE_PATH}) +target_link_libraries(${exec} ${libs}) + +set(GPU_AWARE_MPI + ON + CACHE BOOL "Enable GPU-aware MPI support") + +if(("${Kokkos_DEVICES}" MATCHES "CUDA") + OR ("${Kokkos_DEVICES}" MATCHES "HIP") + OR ("${Kokkos_DEVICES}" MATCHES "SYCL")) + set(DEVICE_ENABLED ON) + target_compile_options(${exec} PRIVATE -DDEVICE_ENABLED) +else() + set(DEVICE_ENABLED OFF) +endif() + +if(${GPU_AWARE_MPI}) + target_compile_options(${exec} PRIVATE -DGPU_AWARE_MPI) +endif() diff --git a/minimal/mpi-simple.cpp b/minimal/mpi-simple.cpp new file mode 100644 index 000000000..4663d73be --- /dev/null +++ b/minimal/mpi-simple.cpp @@ -0,0 +1,84 @@ +#include +#include + +#include +#include +#include + +auto main(int argc, char** argv) -> int { + try { + Kokkos::initialize(argc, argv); + MPI_Init(&argc, &argv); + int rank, size; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + MPI_Comm_size(MPI_COMM_WORLD, &size); + + const auto nelems = 500u; + const auto nsend = 10u; + const auto nrecv = 10u; + + if (rank == 0) { + std::cout << "Running the simple MPI communication test" << std::endl; + std::cout << "- Number of MPI ranks: " << size << std::endl; + std::cout << "- Number elements to send/recv (2D): " << nelems << "x" + << nsend << std::endl; +#if defined(GPU_AWARE_MPI) && defined(DEVICE_ENABLED) + std::cout << "- GPU-aware MPI is enabled" << std::endl; +#else + std::cout << "- GPU-aware MPI is disabled" << std::endl; +#endif + } + + Kokkos::View view("view", nelems, nelems); + Kokkos::View send("send", nsend, nelems); + Kokkos::View recv("recv", nrecv, nelems); + Kokkos::deep_copy( + send, + Kokkos::subview(view, std::make_pair(0u, nsend), Kokkos::ALL)); + +#if defined(GPU_AWARE_MPI) || !defined(DEVICE_ENABLED) + MPI_Sendrecv(send.data(), + nsend * nelems, + MPI_FLOAT, + (rank + 1) % size, + 0, + recv.data(), + nrecv * nelems, + MPI_FLOAT, + (rank - 1 + size) % size, + 0, + MPI_COMM_WORLD, + MPI_STATUS_IGNORE); +#else + auto send_h = Kokkos::create_mirror_view(send); + auto recv_h = Kokkos::create_mirror_view(recv); + Kokkos::deep_copy(send_h, send); + MPI_Sendrecv(send_h.data(), + nsend * nelems, + MPI_FLOAT, + (rank + 1) % size, + 0, + recv_h.data(), + nrecv * nelems, + MPI_FLOAT, + (rank - 1 + size) % size, + 0, + MPI_COMM_WORLD, + MPI_STATUS_IGNORE); + Kokkos::deep_copy(recv, recv_h); +#endif + } catch (const std::exception& e) { + if (MPI_COMM_WORLD != MPI_COMM_NULL) { + MPI_Finalize(); + } + if (Kokkos::is_initialized()) { + Kokkos::finalize(); + } + std::cerr << "Error: " << e.what() << std::endl; + return 1; + } + + MPI_Finalize(); + Kokkos::finalize(); + return 0; +} From 86d18acfb6ee46b1dbafcf9c4f90d32377756da8 Mon Sep 17 00:00:00 2001 From: haykh Date: Thu, 1 May 2025 07:13:24 -0400 Subject: [PATCH 681/773] substep reports in minimal --- minimal/mpi.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/minimal/mpi.cpp b/minimal/mpi.cpp index 022a8a749..821b5fcae 100644 --- a/minimal/mpi.cpp +++ b/minimal/mpi.cpp @@ -225,6 +225,17 @@ void comm(int rank, int size, std::size_t bigsize, std::size_t smallsize) { send_recv(r_neighbor, l_neighbor, false, view, smallsize); send_recv(l_neighbor, r_neighbor, true, view, smallsize); + + MPI_Barrier(MPI_COMM_WORLD); + CallOnce([]() { + std::cout << "Finished " << D << "D "; + if constexpr (std::is_same_v) { + std::cout << "float"; + } else { + std::cout << "double"; + } + std::cout << " communication test" << std::endl; + }); } auto main(int argc, char** argv) -> int { From 1d8c6c2067b3ecb9b9f3658a6abf9feaa384b34e Mon Sep 17 00:00:00 2001 From: hayk Date: Thu, 1 May 2025 07:41:26 -0400 Subject: [PATCH 682/773] minor bug when output=OFF --- src/output/CMakeLists.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/output/CMakeLists.txt b/src/output/CMakeLists.txt index bd207d45a..1b132fb60 100644 --- a/src/output/CMakeLists.txt +++ b/src/output/CMakeLists.txt @@ -26,10 +26,10 @@ set(SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}) -set(SOURCES ${SRC_DIR}/stats.cpp) +set(SOURCES ${SRC_DIR}/stats.cpp ${SRC_DIR}/fields.cpp + ${SRC_DIR}/utils/interpret_prompt.cpp) if(${output}) - list(APPEND SOURCES ${SRC_DIR}/writer.cpp ${SRC_DIR}/fields.cpp - ${SRC_DIR}/utils/interpret_prompt.cpp) + list(APPEND SOURCES ${SRC_DIR}/writer.cpp) endif() add_library(ntt_output ${SOURCES}) From 40224421f9b2b765c770666d07f4d3ca2b1b238e Mon Sep 17 00:00:00 2001 From: LudwigBoess Date: Thu, 1 May 2025 15:13:13 -0500 Subject: [PATCH 683/773] removed `override` to be compatible with SYCL --- src/archetypes/energy_dist.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/archetypes/energy_dist.h b/src/archetypes/energy_dist.h index b29e3a999..ad0a6b4e8 100644 --- a/src/archetypes/energy_dist.h +++ b/src/archetypes/energy_dist.h @@ -240,7 +240,7 @@ namespace arch { Inline void operator()(const coord_t& x_Code, vec_t& v, - spidx_t sp = 0) const override { + spidx_t sp = 0) const { SampleFromMaxwellian(v, temperature, boost_velocity, @@ -382,7 +382,7 @@ namespace arch { Inline void operator()(const coord_t& x_Code, vec_t& v, - spidx_t sp = 0) const override { + spidx_t sp = 0) const { if (cmp::AlmostZero(temperature)) { v[0] = ZERO; v[1] = ZERO; From d79078ab4f17a6b28f1e05046deecbb64f22e2b0 Mon Sep 17 00:00:00 2001 From: haykh Date: Thu, 1 May 2025 21:31:07 -0400 Subject: [PATCH 684/773] stats reduction for flds --- src/engines/engine.hpp | 1 - src/framework/domain/checkpoint.cpp | 106 ++++++- src/framework/domain/communications.cpp | 100 ++++++- src/framework/domain/grid.cpp | 8 +- src/framework/domain/metadomain.cpp | 1 - src/framework/domain/metadomain.h | 8 +- src/framework/domain/output.cpp | 128 +++++++- src/framework/domain/stats.cpp | 181 +++++++++-- src/global/enums.h | 2 + src/kernels/reduced_stats.hpp | 381 ++++++++++++++++++++++++ src/output/stats.cpp | 4 +- src/output/stats.h | 54 +++- 12 files changed, 895 insertions(+), 79 deletions(-) create mode 100644 src/kernels/reduced_stats.hpp diff --git a/src/engines/engine.hpp b/src/engines/engine.hpp index 9525874a6..5956ea5d9 100644 --- a/src/engines/engine.hpp +++ b/src/engines/engine.hpp @@ -23,7 +23,6 @@ #include "arch/traits.h" #include "utils/error.h" -#include "utils/progressbar.h" #include "utils/timer.h" #include "utils/toml.h" diff --git a/src/framework/domain/checkpoint.cpp b/src/framework/domain/checkpoint.cpp index 656ff57d0..25cdcf0f6 100644 --- a/src/framework/domain/checkpoint.cpp +++ b/src/framework/domain/checkpoint.cpp @@ -474,13 +474,103 @@ namespace ntt { HERE); } - template struct Metadomain>; - template struct Metadomain>; - template struct Metadomain>; - template struct Metadomain>; - template struct Metadomain>; - template struct Metadomain>; - template struct Metadomain>; - template struct Metadomain>; + template void Metadomain>::InitCheckpointWriter( + adios2::ADIOS*, + const SimulationParams&); + template void Metadomain>::InitCheckpointWriter( + adios2::ADIOS*, + const SimulationParams&); + template void Metadomain>::InitCheckpointWriter( + adios2::ADIOS*, + const SimulationParams&); + template void Metadomain>::InitCheckpointWriter( + adios2::ADIOS*, + const SimulationParams&); + template void Metadomain>::InitCheckpointWriter( + adios2::ADIOS*, + const SimulationParams&); + template void Metadomain>::InitCheckpointWriter( + adios2::ADIOS*, + const SimulationParams&); + template void Metadomain>::InitCheckpointWriter( + adios2::ADIOS*, + const SimulationParams&); + template void Metadomain>::InitCheckpointWriter( + adios2::ADIOS*, + const SimulationParams&); + + template auto Metadomain>::WriteCheckpoint( + const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t) -> bool; + template auto Metadomain>::WriteCheckpoint( + const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t) -> bool; + template auto Metadomain>::WriteCheckpoint( + const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t) -> bool; + template auto Metadomain>::WriteCheckpoint( + const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t) -> bool; + template auto Metadomain>::WriteCheckpoint( + const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t) -> bool; + template auto Metadomain>::WriteCheckpoint( + const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t) -> bool; + template auto Metadomain>::WriteCheckpoint( + const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t) -> bool; + template auto Metadomain>::WriteCheckpoint( + const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t) -> bool; + + template void Metadomain>::ContinueFromCheckpoint( + adios2::ADIOS*, + const SimulationParams&); + template void Metadomain>::ContinueFromCheckpoint( + adios2::ADIOS*, + const SimulationParams&); + template void Metadomain>::ContinueFromCheckpoint( + adios2::ADIOS*, + const SimulationParams&); + template void Metadomain>::ContinueFromCheckpoint( + adios2::ADIOS*, + const SimulationParams&); + template void Metadomain>::ContinueFromCheckpoint( + adios2::ADIOS*, + const SimulationParams&); + template void Metadomain>::ContinueFromCheckpoint( + adios2::ADIOS*, + const SimulationParams&); + template void Metadomain>::ContinueFromCheckpoint( + adios2::ADIOS*, + const SimulationParams&); + template void Metadomain>::ContinueFromCheckpoint( + adios2::ADIOS*, + const SimulationParams&); } // namespace ntt diff --git a/src/framework/domain/communications.cpp b/src/framework/domain/communications.cpp index 841c9a7da..23bb5b88c 100644 --- a/src/framework/domain/communications.cpp +++ b/src/framework/domain/communications.cpp @@ -641,13 +641,95 @@ namespace ntt { } } - template struct Metadomain>; - template struct Metadomain>; - template struct Metadomain>; - template struct Metadomain>; - template struct Metadomain>; - template struct Metadomain>; - template struct Metadomain>; - template struct Metadomain>; - + template void Metadomain>::CommunicateFields( + Domain>&, + CommTags); + template void Metadomain>::CommunicateFields( + Domain>&, + CommTags); + template void Metadomain>::CommunicateFields( + Domain>&, + CommTags); + template void Metadomain>::CommunicateFields( + Domain>&, + CommTags); + template void Metadomain>::CommunicateFields( + Domain>&, + CommTags); + template void Metadomain>::CommunicateFields( + Domain>&, + CommTags); + template void Metadomain>::CommunicateFields( + Domain>&, + CommTags); + template void Metadomain>::CommunicateFields( + Domain>&, + CommTags); + + template void Metadomain>::SynchronizeFields( + Domain>&, + CommTags, + const range_tuple_t&); + template void Metadomain>::SynchronizeFields( + Domain>&, + CommTags, + const range_tuple_t&); + template void Metadomain>::SynchronizeFields( + Domain>&, + CommTags, + const range_tuple_t&); + template void Metadomain>::SynchronizeFields( + Domain>&, + CommTags, + const range_tuple_t&); + template void Metadomain>::SynchronizeFields( + Domain>&, + CommTags, + const range_tuple_t&); + template void Metadomain>::SynchronizeFields( + Domain>&, + CommTags, + const range_tuple_t&); + template void Metadomain>::SynchronizeFields( + Domain>&, + CommTags, + const range_tuple_t&); + template void Metadomain>::SynchronizeFields( + Domain>&, + CommTags, + const range_tuple_t&); + + template void Metadomain>::CommunicateParticles( + Domain>&); + template void Metadomain>::CommunicateParticles( + Domain>&); + template void Metadomain>::CommunicateParticles( + Domain>&); + template void Metadomain>::CommunicateParticles( + Domain>&); + template void Metadomain>::CommunicateParticles( + Domain>&); + template void Metadomain>::CommunicateParticles( + Domain>&); + template void Metadomain>::CommunicateParticles( + Domain>&); + template void Metadomain>::CommunicateParticles( + Domain>&); + + template void Metadomain>::RemoveDeadParticles( + Domain>&); + template void Metadomain>::RemoveDeadParticles( + Domain>&); + template void Metadomain>::RemoveDeadParticles( + Domain>&); + template void Metadomain>::RemoveDeadParticles( + Domain>&); + template void Metadomain>::RemoveDeadParticles( + Domain>&); + template void Metadomain>::RemoveDeadParticles( + Domain>&); + template void Metadomain>::RemoveDeadParticles( + Domain>&); + template void Metadomain>::RemoveDeadParticles( + Domain>&); } // namespace ntt diff --git a/src/framework/domain/grid.cpp b/src/framework/domain/grid.cpp index ddbfc38f0..f087df6f5 100644 --- a/src/framework/domain/grid.cpp +++ b/src/framework/domain/grid.cpp @@ -86,8 +86,8 @@ namespace ntt { } template - auto Grid::rangeCellsOnHost(const box_region_t& region) const - -> range_h_t { + auto Grid::rangeCellsOnHost( + const box_region_t& region) const -> range_h_t { tuple_t imin, imax; for (auto i { 0u }; i < D; i++) { switch (region[i]) { @@ -163,8 +163,8 @@ namespace ntt { } template - auto Grid::rangeCells(const tuple_t, D>& ranges) const - -> range_t { + auto Grid::rangeCells( + const tuple_t, D>& ranges) const -> range_t { tuple_t imin, imax; for (auto i { 0u }; i < D; i++) { raise::ErrorIf((ranges[i][0] < -(int)N_GHOSTS) || diff --git a/src/framework/domain/metadomain.cpp b/src/framework/domain/metadomain.cpp index 4b9057e23..a0326913b 100644 --- a/src/framework/domain/metadomain.cpp +++ b/src/framework/domain/metadomain.cpp @@ -23,7 +23,6 @@ #include #include -#include #include #include diff --git a/src/framework/domain/metadomain.h b/src/framework/domain/metadomain.h index 1fb6ce007..363b164d3 100644 --- a/src/framework/domain/metadomain.h +++ b/src/framework/domain/metadomain.h @@ -19,7 +19,6 @@ #include "global.h" #include "arch/kokkos_aliases.h" -#include "utils/timer.h" #include "framework/containers/species.h" #include "framework/domain/domain.h" @@ -138,8 +137,11 @@ namespace ntt { #endif void InitStatsWriter(const SimulationParams&, bool); - auto WriteStats(const SimulationParams&, timestep_t, timestep_t, simtime_t, simtime_t) - -> bool; + auto WriteStats(const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t) -> bool; /* setters -------------------------------------------------------------- */ void setFldsBC(const bc_in&, const FldsBC&); diff --git a/src/framework/domain/output.cpp b/src/framework/domain/output.cpp index 6903c7194..99987989e 100644 --- a/src/framework/domain/output.cpp +++ b/src/framework/domain/output.cpp @@ -708,13 +708,125 @@ namespace ntt { return true; } - template struct Metadomain>; - template struct Metadomain>; - template struct Metadomain>; - template struct Metadomain>; - template struct Metadomain>; - template struct Metadomain>; - template struct Metadomain>; - template struct Metadomain>; + template void Metadomain>::InitWriter( + adios2::ADIOS*, + const SimulationParams&, + bool); + template void Metadomain>::InitWriter( + adios2::ADIOS*, + const SimulationParams&, + bool); + template void Metadomain>::InitWriter( + adios2::ADIOS*, + const SimulationParams&, + bool); + template void Metadomain>::InitWriter( + adios2::ADIOS*, + const SimulationParams&, + bool); + template void Metadomain>::InitWriter( + adios2::ADIOS*, + const SimulationParams&, + bool); + template void Metadomain>::InitWriter( + adios2::ADIOS*, + const SimulationParams&, + bool); + template void Metadomain>::InitWriter( + adios2::ADIOS*, + const SimulationParams&, + bool); + template void Metadomain>::InitWriter( + adios2::ADIOS*, + const SimulationParams&, + bool); + template auto Metadomain>::Write( + const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t, + std::function&, + std::size_t, + const Domain>&)>) + -> bool; + template auto Metadomain>::Write( + const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t, + std::function&, + std::size_t, + const Domain>&)>) + -> bool; + template auto Metadomain>::Write( + const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t, + std::function&, + std::size_t, + const Domain>&)>) + -> bool; + template auto Metadomain>::Write( + const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t, + std::function&, + std::size_t, + const Domain>&)>) + -> bool; + template auto Metadomain>::Write( + const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t, + std::function&, + std::size_t, + const Domain>&)>) + -> bool; + template auto Metadomain>::Write( + const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t, + std::function&, + std::size_t, + const Domain>&)>) + -> bool; + template auto Metadomain>::Write( + const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t, + std::function&, + std::size_t, + const Domain>&)>) + -> bool; + template auto Metadomain>::Write( + const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t, + std::function&, + std::size_t, + const Domain>&)>) + -> bool; } // namespace ntt diff --git a/src/framework/domain/stats.cpp b/src/framework/domain/stats.cpp index 60acd64a9..cf7613bdb 100644 --- a/src/framework/domain/stats.cpp +++ b/src/framework/domain/stats.cpp @@ -18,6 +18,8 @@ #include "framework/domain/metadomain.h" #include "framework/parameters.h" +#include "kernels/reduced_stats.hpp" + #include #include #include @@ -107,17 +109,63 @@ namespace ntt { } template - auto ComputeFields(Domain* domain, - const std::vector& components) -> real_t { + auto ReduceFields(Domain* domain, + const std::vector& components) -> real_t { auto buffer { ZERO }; - // Kokkos::parallel_reduce( - // "ComputeMoments", - // prtl_spec.rangeActiveParticles(), - // kernel::ReducedFields_kernel(components, - // domain->fields.em, - // domain->fields.cur, - // domain->mesh.metric), - // buffer); + if constexpr (F == StatsID::JdotE) { + if (components.size() == 0) { + Kokkos::parallel_reduce( + "ReduceFields", + domain->mesh.rangeActiveCells(), + kernel::ReducedFields_kernel(domain->fields.em, + domain->fields.cur, + domain->mesh.metric), + buffer); + } else { + raise::Error("Components not supported for JdotE", HERE); + } + } else if constexpr ( + (S == SimEngine::SRPIC) and + (F == StatsID::B2 or F == StatsID::E2 or F == StatsID::ExB)) { + raise::ErrorIf(components.size() != 1, + "Components must be of size 1 for B2, E2 or ExB stats", + HERE); + const auto comp = components[0]; + if (comp == 1) { + Kokkos::parallel_reduce( + "ReduceFields", + domain->mesh.rangeActiveCells(), + kernel::ReducedFields_kernel(domain->fields.em, + domain->fields.cur, + domain->mesh.metric), + buffer); + } else if (comp == 2) { + Kokkos::parallel_reduce( + "ReduceFields", + domain->mesh.rangeActiveCells(), + kernel::ReducedFields_kernel(domain->fields.em, + domain->fields.cur, + domain->mesh.metric), + buffer); + } else if (comp == 3) { + Kokkos::parallel_reduce( + "ReduceFields", + domain->mesh.rangeActiveCells(), + kernel::ReducedFields_kernel(domain->fields.em, + domain->fields.cur, + domain->mesh.metric), + buffer); + } else { + raise::Error( + "Invalid component for B2, E2 or ExB stats: " + std::to_string(comp), + HERE); + } + } else { + raise::Error("ReduceFields not implemented for this stats ID + SimEngine " + "combination", + HERE); + } + return buffer; } @@ -174,31 +222,108 @@ namespace ntt { comp)); } } else if (stat.id() == StatsID::JdotE) { - g_stats_writer.write(ComputeFields(local_domain, {})); - } else if (stat.id() == StatsID::E2) { - g_stats_writer.write(ComputeFields(local_domain, {})); - } else if (stat.id() == StatsID::B2) { - g_stats_writer.write(ComputeFields(local_domain, {})); - } else if (stat.id() == StatsID::ExB) { - for (const auto& comp : stat.comp) { - g_stats_writer.write( - ComputeFields(local_domain, comp)); + g_stats_writer.write(ReduceFields(local_domain, {})); + } else if (S == SimEngine::SRPIC) { + if (stat.id() == StatsID::E2) { + for (const auto& comp : stat.comp) { + g_stats_writer.write( + ReduceFields(local_domain, comp)); + } + } else if (stat.id() == StatsID::B2) { + for (const auto& comp : stat.comp) { + g_stats_writer.write( + ReduceFields(local_domain, comp)); + } + } else if (stat.id() == StatsID::ExB) { + for (const auto& comp : stat.comp) { + g_stats_writer.write( + ReduceFields(local_domain, comp)); + } + } else { + raise::Error("Unrecognized stats ID " + stat.name(), HERE); } } else { - raise::Error("Unrecognized stats ID " + stat.name(), HERE); + raise::Error("StatsID not implemented for particular SimEngine: " + + std::to_string(static_cast(S)), + HERE); } } g_stats_writer.endWriting(); return true; } - template struct Metadomain>; - template struct Metadomain>; - template struct Metadomain>; - template struct Metadomain>; - template struct Metadomain>; - template struct Metadomain>; - template struct Metadomain>; - template struct Metadomain>; + template void Metadomain>::InitStatsWriter( + const SimulationParams&, + bool); + template void Metadomain>::InitStatsWriter( + const SimulationParams&, + bool); + template void Metadomain>::InitStatsWriter( + const SimulationParams&, + bool); + template void Metadomain>::InitStatsWriter( + const SimulationParams&, + bool); + template void Metadomain>::InitStatsWriter( + const SimulationParams&, + bool); + template void Metadomain>::InitStatsWriter( + const SimulationParams&, + bool); + template void Metadomain>::InitStatsWriter( + const SimulationParams&, + bool); + template void Metadomain>::InitStatsWriter( + const SimulationParams&, + bool); + + template auto Metadomain>::WriteStats( + const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t) -> bool; + template auto Metadomain>::WriteStats( + const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t) -> bool; + template auto Metadomain>::WriteStats( + const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t) -> bool; + template auto Metadomain>::WriteStats( + const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t) -> bool; + template auto Metadomain>::WriteStats( + const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t) -> bool; + template auto Metadomain>::WriteStats( + const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t) -> bool; + template auto Metadomain>::WriteStats( + const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t) -> bool; + template auto Metadomain>::WriteStats( + const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t) -> bool; } // namespace ntt diff --git a/src/global/enums.h b/src/global/enums.h index 7e06d4a8d..8796fe310 100644 --- a/src/global/enums.h +++ b/src/global/enums.h @@ -14,6 +14,8 @@ * - enum ntt::Cooling // synchrotron, none * - enum ntt::FldsID // e, dive, d, divd, b, h, j, * a, t, rho, charge, n, nppc, v, custom + * - enum ntt::StatsID // b^2, e^2, exb, j.e, t, rho, + * charge, n, npart * @namespaces: * - ntt:: * @note Enums of the same type can be compared with each other and with strings diff --git a/src/kernels/reduced_stats.hpp b/src/kernels/reduced_stats.hpp new file mode 100644 index 000000000..373f06eb0 --- /dev/null +++ b/src/kernels/reduced_stats.hpp @@ -0,0 +1,381 @@ +/** + * @file kernels/reduced_stats.hpp + * @brief Compute reduced field/moment quantities for stats output + * @implements + * - kernel::PrtlToPhys_kernel<> + * @namespaces: + * - kernel:: + */ + +#ifndef KERNELS_REDUCED_STATS_HPP +#define KERNELS_REDUCED_STATS_HPP + +#include "enums.h" +#include "global.h" + +#include "arch/kokkos_aliases.h" +#include "utils/numeric.h" + +namespace kernel { + using namespace ntt; + + template + class ReducedFields_kernel { + static_assert(M::is_metric, "M must be a metric class"); + static_assert(I <= 3, + "I must be less than or equal to 3 for ReducedFields_kernel"); + static constexpr auto D = M::Dim; + + ndfield_t EM; + ndfield_t J; + const M metric; + + public: + ReducedFields_kernel(const ndfield_t& EM, + const ndfield_t& J, + const M& metric) + : EM { EM } + , J { J } + , metric { metric } {} + + Inline void operator()(index_t i1, real_t& buff) const { + const auto i1_ = COORD(i1); + if constexpr (F == StatsID::B2) { + if constexpr (I == 1) { + const auto b1_u = EM(i1, em::bx1); + const auto b1_d = metric.template transform<1, Idx::U, Idx::D>({ i1_ }, + b1_u); + buff += b1_u * b1_d; + } else if constexpr (I == 2) { + const auto b2_u = EM(i1, em::bx2); + const auto b2_d = metric.template transform<2, Idx::U, Idx::D>( + { i1_ + HALF }, + b2_u); + buff += b2_u * b2_d; + } else { + const auto b3_u = EM(i1, em::bx3); + const auto b3_d = metric.template transform<3, Idx::U, Idx::D>( + { i1_ + HALF }, + b3_u); + buff += b3_u * b3_d; + } + } else if constexpr (F == StatsID::E2) { + if constexpr (I == 1) { + const auto e1_u = EM(i1, em::ex1); + const auto e1_d = metric.template transform<1, Idx::U, Idx::D>( + { i1_ + HALF }, + e1_u); + buff += e1_u * e1_d; + } else if constexpr (I == 2) { + const auto e2_u = EM(i1, em::ex2); + const auto e2_d = metric.template transform<2, Idx::U, Idx::D>({ i1_ }, + e2_u); + buff += e2_u * e2_d; + } else { + const auto e3_u = EM(i1, em::ex3); + const auto e3_d = metric.template transform<3, Idx::U, Idx::D>({ i1_ }, + e3_u); + buff += e3_u * e3_d; + } + } else if constexpr (F == StatsID::ExB) { + if constexpr (I == 1) { + const auto e2_t = metric.template transform<2, Idx::U, Idx::T>( + { i1_ + HALF }, + HALF * (EM(i1, em::ex2) + EM(i1 + 1, em::ex2))); + const auto e3_t = metric.template transform<3, Idx::U, Idx::T>( + { i1_ + HALF }, + HALF * (EM(i1, em::ex3) + EM(i1 + 1, em::ex3))); + const auto b2_t = metric.template transform<2, Idx::U, Idx::T>( + { i1_ + HALF }, + EM(i1, em::bx2)); + const auto b3_t = metric.template transform<3, Idx::U, Idx::T>( + { i1_ + HALF }, + EM(i1, em::bx3)); + buff += e2_t * b3_t - e3_t * b2_t; + } else if constexpr (I == 2) { + const auto e1_t = metric.template transform<1, Idx::U, Idx::T>( + { i1_ + HALF }, + EM(i1, em::ex1)); + const auto e3_t = metric.template transform<3, Idx::U, Idx::T>( + { i1_ + HALF }, + HALF * (EM(i1, em::ex3) + EM(i1 + 1, em::ex3))); + const auto b1_t = metric.template transform<1, Idx::U, Idx::T>( + { i1_ + HALF }, + HALF * (EM(i1, em::bx1) + EM(i1 + 1, em::bx1))); + const auto b3_t = metric.template transform<3, Idx::U, Idx::T>( + { i1_ + HALF }, + EM(i1, em::bx3)); + buff += e3_t * b1_t - e1_t * b3_t; + } else { + const auto e1_t = metric.template transform<1, Idx::U, Idx::T>( + { i1_ + HALF }, + EM(i1, em::ex1)); + const auto e2_t = metric.template transform<2, Idx::U, Idx::T>( + { i1_ + HALF }, + HALF * (EM(i1, em::ex2) + EM(i1 + 1, em::ex2))); + const auto b1_t = metric.template transform<1, Idx::U, Idx::T>( + { i1_ + HALF }, + HALF * (EM(i1, em::bx1) + EM(i1 + 1, em::bx1))); + const auto b2_t = metric.template transform<2, Idx::U, Idx::T>( + { i1_ + HALF }, + EM(i1, em::bx2)); + buff += e1_t * b2_t - e2_t * b1_t; + } + } else if constexpr (F == StatsID::JdotE) { + vec_t e_t { ZERO }; + vec_t j_t { ZERO }; + metric.template transform( + { i1_ + HALF }, + { EM(i1, em::ex1), + HALF * (EM(i1, em::ex2) + EM(i1 + 1, em::ex2)), + HALF * (EM(i1, em::ex3) + EM(i1 + 1, em::ex3)) }, + e_t); + metric.template transform( + { i1_ + HALF }, + { J(i1, cur::jx1), + HALF * (J(i1, cur::jx2) + J(i1 + 1, cur::jx2)), + HALF * (J(i1, cur::jx3) + J(i1 + 1, cur::jx3)) }, + j_t); + buff += e_t[0] * j_t[0] + e_t[1] * j_t[1] + e_t[2] * j_t[2]; + } + } + + Inline void operator()(index_t i1, index_t i2, real_t& buff) const { + const auto i1_ = COORD(i1); + const auto i2_ = COORD(i2); + if constexpr (F == StatsID::B2) { + if constexpr (I == 1) { + const auto b1_u = EM(i1, i2, em::bx1); + const auto b1_d = metric.template transform<1, Idx::U, Idx::D>( + { i1_, i2_ + HALF }, + b1_u); + buff += b1_u * b1_d; + } else if constexpr (I == 2) { + const auto b2_u = EM(i1, i2, em::bx2); + const auto b2_d = metric.template transform<2, Idx::U, Idx::D>( + { i1_ + HALF, i2_ }, + b2_u); + buff += b2_u * b2_d; + } else { + const auto b3_u = EM(i1, i2, em::bx3); + const auto b3_d = metric.template transform<3, Idx::U, Idx::D>( + { i1_ + HALF, i2_ + HALF }, + b3_u); + buff += b3_u * b3_d; + } + } else if constexpr (F == StatsID::E2) { + if constexpr (I == 1) { + const auto e1_u = EM(i1, i2, em::ex1); + const auto e1_d = metric.template transform<1, Idx::U, Idx::D>( + { i1_ + HALF, i2_ }, + e1_u); + buff += e1_u * e1_d; + } else if constexpr (I == 2) { + const auto e2_u = EM(i1, i2, em::ex2); + const auto e2_d = metric.template transform<2, Idx::U, Idx::D>( + { i1_, i2_ + HALF }, + e2_u); + buff += e2_u * e2_d; + } else { + const auto e3_u = EM(i1, i2, em::ex3); + const auto e3_d = metric.template transform<3, Idx::U, Idx::D>( + { i1_, i2_ }, + e3_u); + buff += e3_u * e3_d; + } + } else if constexpr (F == StatsID::ExB) { + if constexpr (I == 1) { + const auto e2_t = metric.template transform<2, Idx::U, Idx::T>( + { i1_ + HALF, i2_ + HALF }, + HALF * (EM(i1, i2, em::ex2) + EM(i1 + 1, i2, em::ex2))); + const auto e3_t = metric.template transform<3, Idx::U, Idx::T>( + { i1_ + HALF, i2_ + HALF }, + INV_4 * (EM(i1, i2, em::ex3) + EM(i1 + 1, i2, em::ex3) + + EM(i1, i2 + 1, em::ex3) + EM(i1 + 1, i2 + 1, em::ex3))); + const auto b2_t = metric.template transform<2, Idx::U, Idx::T>( + { i1_ + HALF, i2_ + HALF }, + HALF * (EM(i1, i2, em::bx2) + EM(i1, i2 + 1, em::bx2))); + const auto b3_t = metric.template transform<3, Idx::U, Idx::T>( + { i1_ + HALF, i2_ + HALF }, + EM(i1, i2, em::bx3)); + buff += e2_t * b3_t - e3_t * b2_t; + } else if constexpr (I == 2) { + const auto e1_t = metric.template transform<1, Idx::U, Idx::T>( + { i1_ + HALF, i2_ + HALF }, + HALF * (EM(i1, i2, em::ex1) + EM(i1, i2 + 1, em::ex1))); + const auto e3_t = metric.template transform<3, Idx::U, Idx::T>( + { i1_ + HALF, i2_ + HALF }, + INV_4 * (EM(i1, i2, em::ex3) + EM(i1 + 1, i2, em::ex3) + + EM(i1, i2 + 1, em::ex3) + EM(i1 + 1, i2 + 1, em::ex3))); + const auto b1_t = metric.template transform<1, Idx::U, Idx::T>( + { i1_ + HALF, i2_ + HALF }, + HALF * (EM(i1, i2, em::bx1) + EM(i1 + 1, i2, em::bx1))); + const auto b3_t = metric.template transform<3, Idx::U, Idx::T>( + { i1_ + HALF, i2_ + HALF }, + EM(i1, i2, em::bx3)); + buff += e3_t * b1_t - e1_t * b3_t; + } else { + const auto e1_t = metric.template transform<1, Idx::U, Idx::T>( + { i1_ + HALF, i2_ + HALF }, + HALF * (EM(i1, i2, em::ex1) + EM(i1, i2 + 1, em::ex1))); + const auto e2_t = metric.template transform<2, Idx::U, Idx::T>( + { i1_ + HALF, i2_ + HALF }, + HALF * (EM(i1, i2, em::ex2) + EM(i1 + 1, i2, em::ex2))); + const auto b1_t = metric.template transform<1, Idx::U, Idx::T>( + { i1_ + HALF, i2_ + HALF }, + HALF * (EM(i1, i2, em::bx1) + EM(i1 + 1, i2, em::bx1))); + const auto b2_t = metric.template transform<2, Idx::U, Idx::T>( + { i1_ + HALF, i2_ + HALF }, + HALF * (EM(i1, i2, em::bx2) + EM(i1, i2 + 1, em::bx2))); + buff += e1_t * b2_t - e2_t * b1_t; + } + } else if constexpr (F == StatsID::JdotE) { + vec_t e_t { ZERO }; + vec_t j_t { ZERO }; + metric.template transform( + { i1_ + HALF, i2_ + HALF }, + { HALF * (EM(i1, i2, em::ex1) + EM(i1, i2 + 1, em::ex1)), + HALF * (EM(i1, i2, em::ex2) + EM(i1 + 1, i2, em::ex2)), + INV_4 * (EM(i1, i2, em::ex3) + EM(i1 + 1, i2, em::ex3) + + EM(i1, i2 + 1, em::ex3) + EM(i1 + 1, i2 + 1, em::ex3)) }, + e_t); + metric.template transform( + { i1_ + HALF, i2_ + HALF }, + { HALF * (J(i1, i2, cur::jx1) + J(i1, i2 + 1, cur::jx1)), + HALF * (J(i1, i2, cur::jx2) + J(i1 + 1, i2, cur::jx2)), + INV_4 * (J(i1, i2, cur::jx3) + J(i1 + 1, i2, cur::jx3) + + J(i1, i2 + 1, cur::jx3) + J(i1 + 1, i2 + 1, cur::jx3)) }, + j_t); + buff += e_t[0] * j_t[0] + e_t[1] * j_t[1] + e_t[2] * j_t[2]; + } + } + + Inline void operator()(index_t i1, index_t i2, index_t i3, real_t& buff) const { + const auto i1_ = COORD(i1); + const auto i2_ = COORD(i2); + const auto i3_ = COORD(i3); + if constexpr (F == StatsID::B2) { + if constexpr (I == 1) { + const auto b1_u = EM(i1, i2, i3, em::bx1); + const auto b1_d = metric.template transform<1, Idx::U, Idx::D>( + { i1_, i2_ + HALF, i3_ + HALF }, + b1_u); + buff += b1_u * b1_d; + } else if constexpr (I == 2) { + const auto b2_u = EM(i1, i2, i3, em::bx2); + const auto b2_d = metric.template transform<2, Idx::U, Idx::D>( + { i1_ + HALF, i2_, i3_ + HALF }, + b2_u); + buff += b2_u * b2_d; + } else { + const auto b3_u = EM(i1, i2, i3, em::bx3); + const auto b3_d = metric.template transform<3, Idx::U, Idx::D>( + { i1_ + HALF, i2_ + HALF, i3_ }, + b3_u); + buff += b3_u * b3_d; + } + } else if constexpr (F == StatsID::E2) { + if constexpr (I == 1) { + const auto e1_u = EM(i1, i2, i3, em::ex1); + const auto e1_d = metric.template transform<1, Idx::U, Idx::D>( + { i1_ + HALF, i2_, i3_ }, + e1_u); + buff += e1_u * e1_d; + } else if constexpr (I == 2) { + const auto e2_u = EM(i1, i2, i3, em::ex2); + const auto e2_d = metric.template transform<2, Idx::U, Idx::D>( + { i1_, i2_ + HALF, i3_ }, + e2_u); + buff += e2_u * e2_d; + } else { + const auto e3_u = EM(i1, i2, i3, em::ex3); + const auto e3_d = metric.template transform<3, Idx::U, Idx::D>( + { i1_, i2_, i3_ + HALF }, + e3_u); + buff += e3_u * e3_d; + } + } else if constexpr (F == StatsID::ExB) { + if constexpr (I == 1) { + const auto e2_t = metric.template transform<2, Idx::U, Idx::T>( + { i1_ + HALF, i2_ + HALF, i3_ + HALF }, + INV_4 * + (EM(i1, i2, i3, em::ex2) + EM(i1 + 1, i2, i3, em::ex2) + + EM(i1, i2, i3 + 1, em::ex2) + EM(i1 + 1, i2, i3 + 1, em::ex2))); + const auto e3_t = metric.template transform<3, Idx::U, Idx::T>( + { i1_ + HALF, i2_ + HALF, i3_ + HALF }, + INV_4 * + (EM(i1, i2, i3, em::ex3) + EM(i1 + 1, i2, i3, em::ex3) + + EM(i1, i2 + 1, i3, em::ex3) + EM(i1 + 1, i2 + 1, i3, em::ex3))); + const auto b2_t = metric.template transform<2, Idx::U, Idx::T>( + { i1_ + HALF, i2_ + HALF, i3_ + HALF }, + HALF * (EM(i1, i2, i3, em::bx2) + EM(i1, i2 + 1, i3, em::bx2))); + const auto b3_t = metric.template transform<3, Idx::U, Idx::T>( + { i1_ + HALF, i2_ + HALF, i3_ + HALF }, + HALF * (EM(i1, i2, i3, em::bx3) + EM(i1, i2, i3 + 1, em::bx3))); + buff += e2_t * b3_t - e3_t * b2_t; + } else if constexpr (I == 2) { + const auto e1_t = metric.template transform<1, Idx::U, Idx::T>( + { i1_ + HALF, i2_ + HALF, i3_ + HALF }, + INV_4 * + (EM(i1, i2, i3, em::ex1) + EM(i1, i2 + 1, i3, em::ex1) + + EM(i1, i2, i3 + 1, em::ex1) + EM(i1, i2 + 1, i3 + 1, em::ex1))); + const auto e3_t = metric.template transform<3, Idx::U, Idx::T>( + { i1_ + HALF, i2_ + HALF, i3_ + HALF }, + INV_4 * + (EM(i1, i2, i3, em::ex3) + EM(i1 + 1, i2, i3, em::ex3) + + EM(i1, i2 + 1, i3, em::ex3) + EM(i1 + 1, i2 + 1, i3, em::ex3))); + const auto b1_t = metric.template transform<1, Idx::U, Idx::T>( + { i1_ + HALF, i2_ + HALF, i3_ + HALF }, + HALF * (EM(i1, i2, i3, em::bx1) + EM(i1 + 1, i2, i3, em::bx1))); + const auto b3_t = metric.template transform<3, Idx::U, Idx::T>( + { i1_ + HALF, i2_ + HALF, i3_ + HALF }, + HALF * (EM(i1, i2, i3, em::bx3) + EM(i1, i2, i3 + 1, em::bx3))); + buff += e3_t * b1_t - e1_t * b3_t; + } else { + const auto e1_t = metric.template transform<1, Idx::U, Idx::T>( + { i1_ + HALF, i2_ + HALF, i3_ + HALF }, + INV_4 * + (EM(i1, i2, i3, em::ex1) + EM(i1, i2 + 1, i3, em::ex1) + + EM(i1, i2, i3 + 1, em::ex1) + EM(i1, i2 + 1, i3 + 1, em::ex1))); + const auto e2_t = metric.template transform<2, Idx::U, Idx::T>( + { i1_ + HALF, i2_ + HALF, i3_ + HALF }, + INV_4 * + (EM(i1, i2, i3, em::ex2) + EM(i1 + 1, i2, i3, em::ex2) + + EM(i1, i2, i3 + 1, em::ex2) + EM(i1 + 1, i2, i3 + 1, em::ex2))); + const auto b1_t = metric.template transform<1, Idx::U, Idx::T>( + { i1_ + HALF, i2_ + HALF, i3_ + HALF }, + HALF * (EM(i1, i2, i3, em::bx1) + EM(i1 + 1, i2, i3, em::bx1))); + const auto b2_t = metric.template transform<2, Idx::U, Idx::T>( + { i1_ + HALF, i2_ + HALF, i3_ + HALF }, + HALF * (EM(i1, i2, i3, em::bx2) + EM(i1, i2 + 1, i3, em::bx2))); + buff += e1_t * b2_t - e2_t * b1_t; + } + } else if constexpr (F == StatsID::JdotE) { + vec_t e_t { ZERO }; + vec_t j_t { ZERO }; + metric.template transform( + { i1_ + HALF, i2_ + HALF, i3_ + HALF }, + { INV_4 * (EM(i1, i2, i3, em::ex1) + EM(i1, i2 + 1, i3, em::ex1) + + EM(i1, i2, i3 + 1, em::ex1) + EM(i1, i2 + 1, i3 + 1, em::ex1)), + INV_4 * (EM(i1, i2, i3, em::ex2) + EM(i1 + 1, i2, i3, em::ex2) + + EM(i1, i2, i3 + 1, em::ex2) + EM(i1 + 1, i2, i3 + 1, em::ex2)), + INV_4 * (EM(i1, i2, i3, em::ex3) + EM(i1 + 1, i2, i3, em::ex3) + + EM(i1, i2 + 1, i3, em::ex3) + EM(i1 + 1, i2 + 1, i3, em::ex3)) }, + e_t); + metric.template transform( + { i1_ + HALF, i2_ + HALF, i3_ + HALF }, + { INV_4 * (J(i1, i2, i3, cur::jx1) + J(i1, i2 + 1, i3, cur::jx1) + + J(i1, i2, i3 + 1, cur::jx1) + J(i1, i2 + 1, i3 + 1, cur::jx1)), + INV_4 * (J(i1, i2, i3, cur::jx2) + J(i1 + 1, i2, i3, cur::jx2) + + J(i1, i2, i3 + 1, cur::jx2) + J(i1 + 1, i2, i3 + 1, cur::jx2)), + INV_4 * (J(i1, i2, i3, cur::jx3) + J(i1 + 1, i2, i3, cur::jx3) + + J(i1, i2 + 1, i3, cur::jx3) + J(i1 + 1, i2 + 1, i3, cur::jx3)) }, + j_t); + buff += e_t[0] * j_t[0] + e_t[1] * j_t[1] + e_t[2] * j_t[2]; + } + } + }; + +} // namespace kernel + +#endif diff --git a/src/output/stats.cpp b/src/output/stats.cpp index ba3e85c40..68392dc0b 100644 --- a/src/output/stats.cpp +++ b/src/output/stats.cpp @@ -38,13 +38,13 @@ namespace stats { species = {}; } if (is_vector()) { - // always write all the ExB and V components + // always write all the E^2, B^2, ExB components comp = { { 1 }, { 2 }, { 3 } }; } else if (id() == StatsID::T) { // energy-momentum tensor comp = InterpretComponents({ name.substr(1, 1), name.substr(2, 1) }); } else { - // scalar (e.g., Rho, E^2, etc.) + // scalar (e.g., Rho, Npart, etc.) comp = {}; } } diff --git a/src/output/stats.h b/src/output/stats.h index c81b9b7b3..ddea9ad4c 100644 --- a/src/output/stats.h +++ b/src/output/stats.h @@ -3,10 +3,11 @@ * @brief Class defining the metadata necessary to prepare the stats for output * @implements * - out::OutputStats + * - out::Writer * @cpp: * - stats.cpp * @namespaces: - * - out:: + * - stats:: */ #ifndef OUTPUT_STATS_H @@ -16,10 +17,16 @@ #include "global.h" #include "utils/error.h" +#include "utils/formatting.h" #include "utils/tools.h" +#if defined(MPI_ENABLED) + #include "arch/mpi_aliases.h" + + #include +#endif + #include -#include #include #include @@ -47,7 +54,7 @@ namespace stats { [[nodiscard]] auto is_vector() const -> bool { - return id() == StatsID::ExB; + return id() == StatsID::ExB || id() == StatsID::E2 || id() == StatsID::B2; } [[nodiscard]] @@ -65,7 +72,11 @@ namespace stats { if (id() == StatsID::T) { tmp += m_name.substr(1, 2); } else if (is_vector()) { - tmp += "i"; + if (id() == StatsID::E2 || id() == StatsID::B2) { + tmp = fmt::format("%ci^2", tmp[0]); + } else { + tmp += "i"; + } } if (species.size() > 0) { tmp += "_"; @@ -101,16 +112,20 @@ namespace stats { // capitalize the first letter tmp[0] = std::toupper(tmp[0]); } - for (auto& c : comp[ci]) { - tmp += std::to_string(c); - } - if (species.size() > 0) { - tmp += "_"; - for (auto& s : species) { - tmp += std::to_string(s); + if (tmp == "E^2" or tmp == "B^2") { + tmp = fmt::format("%c%d^2", tmp[0], comp[ci][0]); + } else { + for (auto& c : comp[ci]) { + tmp += std::to_string(c); + } + if (species.size() > 0) { tmp += "_"; + for (auto& s : species) { + tmp += std::to_string(s); + tmp += "_"; + } + tmp.pop_back(); } - tmp.pop_back(); } return tmp; } @@ -145,16 +160,25 @@ namespace stats { template inline void write(const T& value) const { #if defined(MPI_ENABLED) - // @TODO: reduce + T tot_value = static_cast(0); + MPI_Reduce(&value, + &tot_value, + 1, + mpi::get_type(), + MPI_SUM, + MPI_ROOT_RANK, + MPI_COMM_WORLD); +#else + tot_value = value; #endif CallOnce( - [](auto& fname, auto& value) { + [](auto&& fname, auto&& value) { std::fstream StatsOut(fname, std::fstream::out | std::fstream::app); StatsOut << value << ","; StatsOut.close(); }, m_fname, - value); + tot_value); } void endWriting(); From bed9c379360d489ffb2a558d74b1420c6e12375b Mon Sep 17 00:00:00 2001 From: haykh Date: Fri, 2 May 2025 14:46:09 +0000 Subject: [PATCH 685/773] dev/nix for cuda --- dev/nix/kokkos.nix | 70 ++++++++++++++++++++++++++++++++++++---------- dev/nix/shell.nix | 19 +++++-------- 2 files changed, 62 insertions(+), 27 deletions(-) diff --git a/dev/nix/kokkos.nix b/dev/nix/kokkos.nix index 6271604c5..c83a489e5 100644 --- a/dev/nix/kokkos.nix +++ b/dev/nix/kokkos.nix @@ -1,12 +1,13 @@ { pkgs ? import { }, + stdenv, arch, gpu, }: let name = "kokkos"; - version = "4.5.01"; + pversion = "4.6.01"; compilerPkgs = { "HIP" = with pkgs.rocmPackages; [ rocm-core @@ -16,15 +17,26 @@ let rocminfo rocm-smi ]; + "CUDA" = with pkgs.cudaPackages; [ + cudatoolkit + cuda_cudart + ]; "NONE" = [ pkgs.gcc13 ]; }; - cmakeFlags = { + cmakeExtraFlags = { "HIP" = [ + "-D Kokkos_ENABLE_HIP=ON" + "-D Kokkos_ARCH_${getArch { }}=ON" "-D CMAKE_C_COMPILER=hipcc" "-D CMAKE_CXX_COMPILER=hipcc" ]; + "CUDA" = [ + "-D Kokkos_ENABLE_CUDA=ON" + "-D Kokkos_ARCH_${getArch { }}=ON" + "-D CMAKE_CXX_COMPILER=$WRAPPER_PATH" + ]; "NONE" = [ ]; }; getArch = @@ -35,13 +47,13 @@ let arch; in -pkgs.stdenv.mkDerivation { +pkgs.stdenv.mkDerivation rec { pname = "${name}"; - version = "${version}"; + version = "${pversion}"; src = pkgs.fetchgit { url = "https://github.com/kokkos/kokkos/"; - rev = "${version}"; - sha256 = "sha256-cI2p+6J+8BRV5fXTDxxHTfh6P5PeeLUiF73o5zVysHQ="; + rev = "${pversion}"; + sha256 = "sha256-+yszUbdHqhIkJZiGLZ9Ln4DYUosuJWKhO8FkbrY0/tY="; }; nativeBuildInputs = with pkgs; [ @@ -50,14 +62,42 @@ pkgs.stdenv.mkDerivation { propagatedBuildInputs = compilerPkgs.${gpu}; - cmakeFlags = [ - "-D CMAKE_CXX_STANDARD=17" - "-D CMAKE_CXX_EXTENSIONS=OFF" - "-D CMAKE_POSITION_INDEPENDENT_CODE=TRUE" - "-D Kokkos_ARCH_${getArch { }}=ON" - (if gpu != "none" then "-D Kokkos_ENABLE_${gpu}=ON" else "") - "-D CMAKE_BUILD_TYPE=Release" - ] ++ cmakeFlags.${gpu}; + patchPhase = + if gpu == "CUDA" then + '' + export WRAPPER_PATH="$(mktemp -d)/nvcc_wrapper" + cp ${src}/bin/nvcc_wrapper $WRAPPER_PATH + substituteInPlace $WRAPPER_PATH --replace-fail "#!/usr/bin/env bash" "#!${stdenv.shell}" + chmod +x "$WRAPPER_PATH" + '' + else + ""; + + configurePhase = '' + cmake -B build -D CMAKE_BUILD_TYPE=Release \ + -D CMAKE_CXX_STANDARD=17 \ + -D CMAKE_CXX_EXTENSIONS=OFF \ + -D CMAKE_POSITION_INDEPENDENT_CODE=TRUE \ + ${pkgs.lib.concatStringsSep " " cmakeExtraFlags.${gpu}} \ + -D CMAKE_INSTALL_PREFIX=$out + ''; + + buildPhase = '' + cmake --build build -j + ''; + + installPhase = '' + cmake --install build + ''; + + # cmakeFlags = [ + # "-D CMAKE_CXX_STANDARD=17" + # "-D CMAKE_CXX_EXTENSIONS=OFF" + # "-D CMAKE_POSITION_INDEPENDENT_CODE=TRUE" + # "-D Kokkos_ARCH_${getArch { }}=ON" + # (if gpu != "none" then "-D Kokkos_ENABLE_${gpu}=ON" else "") + # "-D CMAKE_BUILD_TYPE=Release" + # ] ++ (cmakeExtraFlags.${gpu} src); - enableParallelBuilding = true; + # enableParallelBuilding = true; } diff --git a/dev/nix/shell.nix b/dev/nix/shell.nix index 01d80298b..be4b87bcb 100644 --- a/dev/nix/shell.nix +++ b/dev/nix/shell.nix @@ -1,5 +1,8 @@ { - pkgs ? import { }, + pkgs ? import { + config.allowUnfree = true; + config.cudaSupport = gpu == "CUDA"; + }, gpu ? "NONE", arch ? "NATIVE", hdf5 ? true, @@ -14,12 +17,13 @@ let kokkosPkg = ( pkgs.callPackage ./kokkos.nix { inherit pkgs; + stdenv = pkgs.stdenv; arch = archUpper; gpu = gpuUpper; } ); envVars = { - compiler = rec { + compiler = { NONE = { CXX = "g++"; CC = "gcc"; @@ -28,16 +32,7 @@ let CXX = "hipcc"; CC = "hipcc"; }; - CUDA = NONE; - }; - kokkos = { - HIP = { - Kokkos_ENABLE_HIP = "ON"; - }; - CUDA = { - Kokkos_ENABLE_CUDA = "ON"; - }; - NONE = { }; + CUDA = { }; }; }; in From b4cb794283bcf4afe308b481aa4759581cc0aa83 Mon Sep 17 00:00:00 2001 From: haykh Date: Thu, 1 May 2025 21:31:07 -0400 Subject: [PATCH 686/773] stats reduction for flds --- src/engines/engine.hpp | 1 - src/framework/domain/checkpoint.cpp | 106 ++++++- src/framework/domain/communications.cpp | 100 ++++++- src/framework/domain/grid.cpp | 8 +- src/framework/domain/metadomain.cpp | 1 - src/framework/domain/metadomain.h | 8 +- src/framework/domain/output.cpp | 128 +++++++- src/framework/domain/stats.cpp | 181 +++++++++-- src/global/enums.h | 2 + src/kernels/reduced_stats.hpp | 381 ++++++++++++++++++++++++ src/output/stats.cpp | 4 +- src/output/stats.h | 54 +++- 12 files changed, 895 insertions(+), 79 deletions(-) create mode 100644 src/kernels/reduced_stats.hpp diff --git a/src/engines/engine.hpp b/src/engines/engine.hpp index 9525874a6..5956ea5d9 100644 --- a/src/engines/engine.hpp +++ b/src/engines/engine.hpp @@ -23,7 +23,6 @@ #include "arch/traits.h" #include "utils/error.h" -#include "utils/progressbar.h" #include "utils/timer.h" #include "utils/toml.h" diff --git a/src/framework/domain/checkpoint.cpp b/src/framework/domain/checkpoint.cpp index 656ff57d0..25cdcf0f6 100644 --- a/src/framework/domain/checkpoint.cpp +++ b/src/framework/domain/checkpoint.cpp @@ -474,13 +474,103 @@ namespace ntt { HERE); } - template struct Metadomain>; - template struct Metadomain>; - template struct Metadomain>; - template struct Metadomain>; - template struct Metadomain>; - template struct Metadomain>; - template struct Metadomain>; - template struct Metadomain>; + template void Metadomain>::InitCheckpointWriter( + adios2::ADIOS*, + const SimulationParams&); + template void Metadomain>::InitCheckpointWriter( + adios2::ADIOS*, + const SimulationParams&); + template void Metadomain>::InitCheckpointWriter( + adios2::ADIOS*, + const SimulationParams&); + template void Metadomain>::InitCheckpointWriter( + adios2::ADIOS*, + const SimulationParams&); + template void Metadomain>::InitCheckpointWriter( + adios2::ADIOS*, + const SimulationParams&); + template void Metadomain>::InitCheckpointWriter( + adios2::ADIOS*, + const SimulationParams&); + template void Metadomain>::InitCheckpointWriter( + adios2::ADIOS*, + const SimulationParams&); + template void Metadomain>::InitCheckpointWriter( + adios2::ADIOS*, + const SimulationParams&); + + template auto Metadomain>::WriteCheckpoint( + const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t) -> bool; + template auto Metadomain>::WriteCheckpoint( + const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t) -> bool; + template auto Metadomain>::WriteCheckpoint( + const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t) -> bool; + template auto Metadomain>::WriteCheckpoint( + const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t) -> bool; + template auto Metadomain>::WriteCheckpoint( + const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t) -> bool; + template auto Metadomain>::WriteCheckpoint( + const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t) -> bool; + template auto Metadomain>::WriteCheckpoint( + const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t) -> bool; + template auto Metadomain>::WriteCheckpoint( + const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t) -> bool; + + template void Metadomain>::ContinueFromCheckpoint( + adios2::ADIOS*, + const SimulationParams&); + template void Metadomain>::ContinueFromCheckpoint( + adios2::ADIOS*, + const SimulationParams&); + template void Metadomain>::ContinueFromCheckpoint( + adios2::ADIOS*, + const SimulationParams&); + template void Metadomain>::ContinueFromCheckpoint( + adios2::ADIOS*, + const SimulationParams&); + template void Metadomain>::ContinueFromCheckpoint( + adios2::ADIOS*, + const SimulationParams&); + template void Metadomain>::ContinueFromCheckpoint( + adios2::ADIOS*, + const SimulationParams&); + template void Metadomain>::ContinueFromCheckpoint( + adios2::ADIOS*, + const SimulationParams&); + template void Metadomain>::ContinueFromCheckpoint( + adios2::ADIOS*, + const SimulationParams&); } // namespace ntt diff --git a/src/framework/domain/communications.cpp b/src/framework/domain/communications.cpp index 841c9a7da..23bb5b88c 100644 --- a/src/framework/domain/communications.cpp +++ b/src/framework/domain/communications.cpp @@ -641,13 +641,95 @@ namespace ntt { } } - template struct Metadomain>; - template struct Metadomain>; - template struct Metadomain>; - template struct Metadomain>; - template struct Metadomain>; - template struct Metadomain>; - template struct Metadomain>; - template struct Metadomain>; - + template void Metadomain>::CommunicateFields( + Domain>&, + CommTags); + template void Metadomain>::CommunicateFields( + Domain>&, + CommTags); + template void Metadomain>::CommunicateFields( + Domain>&, + CommTags); + template void Metadomain>::CommunicateFields( + Domain>&, + CommTags); + template void Metadomain>::CommunicateFields( + Domain>&, + CommTags); + template void Metadomain>::CommunicateFields( + Domain>&, + CommTags); + template void Metadomain>::CommunicateFields( + Domain>&, + CommTags); + template void Metadomain>::CommunicateFields( + Domain>&, + CommTags); + + template void Metadomain>::SynchronizeFields( + Domain>&, + CommTags, + const range_tuple_t&); + template void Metadomain>::SynchronizeFields( + Domain>&, + CommTags, + const range_tuple_t&); + template void Metadomain>::SynchronizeFields( + Domain>&, + CommTags, + const range_tuple_t&); + template void Metadomain>::SynchronizeFields( + Domain>&, + CommTags, + const range_tuple_t&); + template void Metadomain>::SynchronizeFields( + Domain>&, + CommTags, + const range_tuple_t&); + template void Metadomain>::SynchronizeFields( + Domain>&, + CommTags, + const range_tuple_t&); + template void Metadomain>::SynchronizeFields( + Domain>&, + CommTags, + const range_tuple_t&); + template void Metadomain>::SynchronizeFields( + Domain>&, + CommTags, + const range_tuple_t&); + + template void Metadomain>::CommunicateParticles( + Domain>&); + template void Metadomain>::CommunicateParticles( + Domain>&); + template void Metadomain>::CommunicateParticles( + Domain>&); + template void Metadomain>::CommunicateParticles( + Domain>&); + template void Metadomain>::CommunicateParticles( + Domain>&); + template void Metadomain>::CommunicateParticles( + Domain>&); + template void Metadomain>::CommunicateParticles( + Domain>&); + template void Metadomain>::CommunicateParticles( + Domain>&); + + template void Metadomain>::RemoveDeadParticles( + Domain>&); + template void Metadomain>::RemoveDeadParticles( + Domain>&); + template void Metadomain>::RemoveDeadParticles( + Domain>&); + template void Metadomain>::RemoveDeadParticles( + Domain>&); + template void Metadomain>::RemoveDeadParticles( + Domain>&); + template void Metadomain>::RemoveDeadParticles( + Domain>&); + template void Metadomain>::RemoveDeadParticles( + Domain>&); + template void Metadomain>::RemoveDeadParticles( + Domain>&); } // namespace ntt diff --git a/src/framework/domain/grid.cpp b/src/framework/domain/grid.cpp index ddbfc38f0..f087df6f5 100644 --- a/src/framework/domain/grid.cpp +++ b/src/framework/domain/grid.cpp @@ -86,8 +86,8 @@ namespace ntt { } template - auto Grid::rangeCellsOnHost(const box_region_t& region) const - -> range_h_t { + auto Grid::rangeCellsOnHost( + const box_region_t& region) const -> range_h_t { tuple_t imin, imax; for (auto i { 0u }; i < D; i++) { switch (region[i]) { @@ -163,8 +163,8 @@ namespace ntt { } template - auto Grid::rangeCells(const tuple_t, D>& ranges) const - -> range_t { + auto Grid::rangeCells( + const tuple_t, D>& ranges) const -> range_t { tuple_t imin, imax; for (auto i { 0u }; i < D; i++) { raise::ErrorIf((ranges[i][0] < -(int)N_GHOSTS) || diff --git a/src/framework/domain/metadomain.cpp b/src/framework/domain/metadomain.cpp index 4b9057e23..a0326913b 100644 --- a/src/framework/domain/metadomain.cpp +++ b/src/framework/domain/metadomain.cpp @@ -23,7 +23,6 @@ #include #include -#include #include #include diff --git a/src/framework/domain/metadomain.h b/src/framework/domain/metadomain.h index 1fb6ce007..363b164d3 100644 --- a/src/framework/domain/metadomain.h +++ b/src/framework/domain/metadomain.h @@ -19,7 +19,6 @@ #include "global.h" #include "arch/kokkos_aliases.h" -#include "utils/timer.h" #include "framework/containers/species.h" #include "framework/domain/domain.h" @@ -138,8 +137,11 @@ namespace ntt { #endif void InitStatsWriter(const SimulationParams&, bool); - auto WriteStats(const SimulationParams&, timestep_t, timestep_t, simtime_t, simtime_t) - -> bool; + auto WriteStats(const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t) -> bool; /* setters -------------------------------------------------------------- */ void setFldsBC(const bc_in&, const FldsBC&); diff --git a/src/framework/domain/output.cpp b/src/framework/domain/output.cpp index 6903c7194..99987989e 100644 --- a/src/framework/domain/output.cpp +++ b/src/framework/domain/output.cpp @@ -708,13 +708,125 @@ namespace ntt { return true; } - template struct Metadomain>; - template struct Metadomain>; - template struct Metadomain>; - template struct Metadomain>; - template struct Metadomain>; - template struct Metadomain>; - template struct Metadomain>; - template struct Metadomain>; + template void Metadomain>::InitWriter( + adios2::ADIOS*, + const SimulationParams&, + bool); + template void Metadomain>::InitWriter( + adios2::ADIOS*, + const SimulationParams&, + bool); + template void Metadomain>::InitWriter( + adios2::ADIOS*, + const SimulationParams&, + bool); + template void Metadomain>::InitWriter( + adios2::ADIOS*, + const SimulationParams&, + bool); + template void Metadomain>::InitWriter( + adios2::ADIOS*, + const SimulationParams&, + bool); + template void Metadomain>::InitWriter( + adios2::ADIOS*, + const SimulationParams&, + bool); + template void Metadomain>::InitWriter( + adios2::ADIOS*, + const SimulationParams&, + bool); + template void Metadomain>::InitWriter( + adios2::ADIOS*, + const SimulationParams&, + bool); + template auto Metadomain>::Write( + const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t, + std::function&, + std::size_t, + const Domain>&)>) + -> bool; + template auto Metadomain>::Write( + const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t, + std::function&, + std::size_t, + const Domain>&)>) + -> bool; + template auto Metadomain>::Write( + const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t, + std::function&, + std::size_t, + const Domain>&)>) + -> bool; + template auto Metadomain>::Write( + const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t, + std::function&, + std::size_t, + const Domain>&)>) + -> bool; + template auto Metadomain>::Write( + const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t, + std::function&, + std::size_t, + const Domain>&)>) + -> bool; + template auto Metadomain>::Write( + const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t, + std::function&, + std::size_t, + const Domain>&)>) + -> bool; + template auto Metadomain>::Write( + const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t, + std::function&, + std::size_t, + const Domain>&)>) + -> bool; + template auto Metadomain>::Write( + const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t, + std::function&, + std::size_t, + const Domain>&)>) + -> bool; } // namespace ntt diff --git a/src/framework/domain/stats.cpp b/src/framework/domain/stats.cpp index 60acd64a9..cf7613bdb 100644 --- a/src/framework/domain/stats.cpp +++ b/src/framework/domain/stats.cpp @@ -18,6 +18,8 @@ #include "framework/domain/metadomain.h" #include "framework/parameters.h" +#include "kernels/reduced_stats.hpp" + #include #include #include @@ -107,17 +109,63 @@ namespace ntt { } template - auto ComputeFields(Domain* domain, - const std::vector& components) -> real_t { + auto ReduceFields(Domain* domain, + const std::vector& components) -> real_t { auto buffer { ZERO }; - // Kokkos::parallel_reduce( - // "ComputeMoments", - // prtl_spec.rangeActiveParticles(), - // kernel::ReducedFields_kernel(components, - // domain->fields.em, - // domain->fields.cur, - // domain->mesh.metric), - // buffer); + if constexpr (F == StatsID::JdotE) { + if (components.size() == 0) { + Kokkos::parallel_reduce( + "ReduceFields", + domain->mesh.rangeActiveCells(), + kernel::ReducedFields_kernel(domain->fields.em, + domain->fields.cur, + domain->mesh.metric), + buffer); + } else { + raise::Error("Components not supported for JdotE", HERE); + } + } else if constexpr ( + (S == SimEngine::SRPIC) and + (F == StatsID::B2 or F == StatsID::E2 or F == StatsID::ExB)) { + raise::ErrorIf(components.size() != 1, + "Components must be of size 1 for B2, E2 or ExB stats", + HERE); + const auto comp = components[0]; + if (comp == 1) { + Kokkos::parallel_reduce( + "ReduceFields", + domain->mesh.rangeActiveCells(), + kernel::ReducedFields_kernel(domain->fields.em, + domain->fields.cur, + domain->mesh.metric), + buffer); + } else if (comp == 2) { + Kokkos::parallel_reduce( + "ReduceFields", + domain->mesh.rangeActiveCells(), + kernel::ReducedFields_kernel(domain->fields.em, + domain->fields.cur, + domain->mesh.metric), + buffer); + } else if (comp == 3) { + Kokkos::parallel_reduce( + "ReduceFields", + domain->mesh.rangeActiveCells(), + kernel::ReducedFields_kernel(domain->fields.em, + domain->fields.cur, + domain->mesh.metric), + buffer); + } else { + raise::Error( + "Invalid component for B2, E2 or ExB stats: " + std::to_string(comp), + HERE); + } + } else { + raise::Error("ReduceFields not implemented for this stats ID + SimEngine " + "combination", + HERE); + } + return buffer; } @@ -174,31 +222,108 @@ namespace ntt { comp)); } } else if (stat.id() == StatsID::JdotE) { - g_stats_writer.write(ComputeFields(local_domain, {})); - } else if (stat.id() == StatsID::E2) { - g_stats_writer.write(ComputeFields(local_domain, {})); - } else if (stat.id() == StatsID::B2) { - g_stats_writer.write(ComputeFields(local_domain, {})); - } else if (stat.id() == StatsID::ExB) { - for (const auto& comp : stat.comp) { - g_stats_writer.write( - ComputeFields(local_domain, comp)); + g_stats_writer.write(ReduceFields(local_domain, {})); + } else if (S == SimEngine::SRPIC) { + if (stat.id() == StatsID::E2) { + for (const auto& comp : stat.comp) { + g_stats_writer.write( + ReduceFields(local_domain, comp)); + } + } else if (stat.id() == StatsID::B2) { + for (const auto& comp : stat.comp) { + g_stats_writer.write( + ReduceFields(local_domain, comp)); + } + } else if (stat.id() == StatsID::ExB) { + for (const auto& comp : stat.comp) { + g_stats_writer.write( + ReduceFields(local_domain, comp)); + } + } else { + raise::Error("Unrecognized stats ID " + stat.name(), HERE); } } else { - raise::Error("Unrecognized stats ID " + stat.name(), HERE); + raise::Error("StatsID not implemented for particular SimEngine: " + + std::to_string(static_cast(S)), + HERE); } } g_stats_writer.endWriting(); return true; } - template struct Metadomain>; - template struct Metadomain>; - template struct Metadomain>; - template struct Metadomain>; - template struct Metadomain>; - template struct Metadomain>; - template struct Metadomain>; - template struct Metadomain>; + template void Metadomain>::InitStatsWriter( + const SimulationParams&, + bool); + template void Metadomain>::InitStatsWriter( + const SimulationParams&, + bool); + template void Metadomain>::InitStatsWriter( + const SimulationParams&, + bool); + template void Metadomain>::InitStatsWriter( + const SimulationParams&, + bool); + template void Metadomain>::InitStatsWriter( + const SimulationParams&, + bool); + template void Metadomain>::InitStatsWriter( + const SimulationParams&, + bool); + template void Metadomain>::InitStatsWriter( + const SimulationParams&, + bool); + template void Metadomain>::InitStatsWriter( + const SimulationParams&, + bool); + + template auto Metadomain>::WriteStats( + const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t) -> bool; + template auto Metadomain>::WriteStats( + const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t) -> bool; + template auto Metadomain>::WriteStats( + const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t) -> bool; + template auto Metadomain>::WriteStats( + const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t) -> bool; + template auto Metadomain>::WriteStats( + const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t) -> bool; + template auto Metadomain>::WriteStats( + const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t) -> bool; + template auto Metadomain>::WriteStats( + const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t) -> bool; + template auto Metadomain>::WriteStats( + const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t) -> bool; } // namespace ntt diff --git a/src/global/enums.h b/src/global/enums.h index 7e06d4a8d..8796fe310 100644 --- a/src/global/enums.h +++ b/src/global/enums.h @@ -14,6 +14,8 @@ * - enum ntt::Cooling // synchrotron, none * - enum ntt::FldsID // e, dive, d, divd, b, h, j, * a, t, rho, charge, n, nppc, v, custom + * - enum ntt::StatsID // b^2, e^2, exb, j.e, t, rho, + * charge, n, npart * @namespaces: * - ntt:: * @note Enums of the same type can be compared with each other and with strings diff --git a/src/kernels/reduced_stats.hpp b/src/kernels/reduced_stats.hpp new file mode 100644 index 000000000..373f06eb0 --- /dev/null +++ b/src/kernels/reduced_stats.hpp @@ -0,0 +1,381 @@ +/** + * @file kernels/reduced_stats.hpp + * @brief Compute reduced field/moment quantities for stats output + * @implements + * - kernel::PrtlToPhys_kernel<> + * @namespaces: + * - kernel:: + */ + +#ifndef KERNELS_REDUCED_STATS_HPP +#define KERNELS_REDUCED_STATS_HPP + +#include "enums.h" +#include "global.h" + +#include "arch/kokkos_aliases.h" +#include "utils/numeric.h" + +namespace kernel { + using namespace ntt; + + template + class ReducedFields_kernel { + static_assert(M::is_metric, "M must be a metric class"); + static_assert(I <= 3, + "I must be less than or equal to 3 for ReducedFields_kernel"); + static constexpr auto D = M::Dim; + + ndfield_t EM; + ndfield_t J; + const M metric; + + public: + ReducedFields_kernel(const ndfield_t& EM, + const ndfield_t& J, + const M& metric) + : EM { EM } + , J { J } + , metric { metric } {} + + Inline void operator()(index_t i1, real_t& buff) const { + const auto i1_ = COORD(i1); + if constexpr (F == StatsID::B2) { + if constexpr (I == 1) { + const auto b1_u = EM(i1, em::bx1); + const auto b1_d = metric.template transform<1, Idx::U, Idx::D>({ i1_ }, + b1_u); + buff += b1_u * b1_d; + } else if constexpr (I == 2) { + const auto b2_u = EM(i1, em::bx2); + const auto b2_d = metric.template transform<2, Idx::U, Idx::D>( + { i1_ + HALF }, + b2_u); + buff += b2_u * b2_d; + } else { + const auto b3_u = EM(i1, em::bx3); + const auto b3_d = metric.template transform<3, Idx::U, Idx::D>( + { i1_ + HALF }, + b3_u); + buff += b3_u * b3_d; + } + } else if constexpr (F == StatsID::E2) { + if constexpr (I == 1) { + const auto e1_u = EM(i1, em::ex1); + const auto e1_d = metric.template transform<1, Idx::U, Idx::D>( + { i1_ + HALF }, + e1_u); + buff += e1_u * e1_d; + } else if constexpr (I == 2) { + const auto e2_u = EM(i1, em::ex2); + const auto e2_d = metric.template transform<2, Idx::U, Idx::D>({ i1_ }, + e2_u); + buff += e2_u * e2_d; + } else { + const auto e3_u = EM(i1, em::ex3); + const auto e3_d = metric.template transform<3, Idx::U, Idx::D>({ i1_ }, + e3_u); + buff += e3_u * e3_d; + } + } else if constexpr (F == StatsID::ExB) { + if constexpr (I == 1) { + const auto e2_t = metric.template transform<2, Idx::U, Idx::T>( + { i1_ + HALF }, + HALF * (EM(i1, em::ex2) + EM(i1 + 1, em::ex2))); + const auto e3_t = metric.template transform<3, Idx::U, Idx::T>( + { i1_ + HALF }, + HALF * (EM(i1, em::ex3) + EM(i1 + 1, em::ex3))); + const auto b2_t = metric.template transform<2, Idx::U, Idx::T>( + { i1_ + HALF }, + EM(i1, em::bx2)); + const auto b3_t = metric.template transform<3, Idx::U, Idx::T>( + { i1_ + HALF }, + EM(i1, em::bx3)); + buff += e2_t * b3_t - e3_t * b2_t; + } else if constexpr (I == 2) { + const auto e1_t = metric.template transform<1, Idx::U, Idx::T>( + { i1_ + HALF }, + EM(i1, em::ex1)); + const auto e3_t = metric.template transform<3, Idx::U, Idx::T>( + { i1_ + HALF }, + HALF * (EM(i1, em::ex3) + EM(i1 + 1, em::ex3))); + const auto b1_t = metric.template transform<1, Idx::U, Idx::T>( + { i1_ + HALF }, + HALF * (EM(i1, em::bx1) + EM(i1 + 1, em::bx1))); + const auto b3_t = metric.template transform<3, Idx::U, Idx::T>( + { i1_ + HALF }, + EM(i1, em::bx3)); + buff += e3_t * b1_t - e1_t * b3_t; + } else { + const auto e1_t = metric.template transform<1, Idx::U, Idx::T>( + { i1_ + HALF }, + EM(i1, em::ex1)); + const auto e2_t = metric.template transform<2, Idx::U, Idx::T>( + { i1_ + HALF }, + HALF * (EM(i1, em::ex2) + EM(i1 + 1, em::ex2))); + const auto b1_t = metric.template transform<1, Idx::U, Idx::T>( + { i1_ + HALF }, + HALF * (EM(i1, em::bx1) + EM(i1 + 1, em::bx1))); + const auto b2_t = metric.template transform<2, Idx::U, Idx::T>( + { i1_ + HALF }, + EM(i1, em::bx2)); + buff += e1_t * b2_t - e2_t * b1_t; + } + } else if constexpr (F == StatsID::JdotE) { + vec_t e_t { ZERO }; + vec_t j_t { ZERO }; + metric.template transform( + { i1_ + HALF }, + { EM(i1, em::ex1), + HALF * (EM(i1, em::ex2) + EM(i1 + 1, em::ex2)), + HALF * (EM(i1, em::ex3) + EM(i1 + 1, em::ex3)) }, + e_t); + metric.template transform( + { i1_ + HALF }, + { J(i1, cur::jx1), + HALF * (J(i1, cur::jx2) + J(i1 + 1, cur::jx2)), + HALF * (J(i1, cur::jx3) + J(i1 + 1, cur::jx3)) }, + j_t); + buff += e_t[0] * j_t[0] + e_t[1] * j_t[1] + e_t[2] * j_t[2]; + } + } + + Inline void operator()(index_t i1, index_t i2, real_t& buff) const { + const auto i1_ = COORD(i1); + const auto i2_ = COORD(i2); + if constexpr (F == StatsID::B2) { + if constexpr (I == 1) { + const auto b1_u = EM(i1, i2, em::bx1); + const auto b1_d = metric.template transform<1, Idx::U, Idx::D>( + { i1_, i2_ + HALF }, + b1_u); + buff += b1_u * b1_d; + } else if constexpr (I == 2) { + const auto b2_u = EM(i1, i2, em::bx2); + const auto b2_d = metric.template transform<2, Idx::U, Idx::D>( + { i1_ + HALF, i2_ }, + b2_u); + buff += b2_u * b2_d; + } else { + const auto b3_u = EM(i1, i2, em::bx3); + const auto b3_d = metric.template transform<3, Idx::U, Idx::D>( + { i1_ + HALF, i2_ + HALF }, + b3_u); + buff += b3_u * b3_d; + } + } else if constexpr (F == StatsID::E2) { + if constexpr (I == 1) { + const auto e1_u = EM(i1, i2, em::ex1); + const auto e1_d = metric.template transform<1, Idx::U, Idx::D>( + { i1_ + HALF, i2_ }, + e1_u); + buff += e1_u * e1_d; + } else if constexpr (I == 2) { + const auto e2_u = EM(i1, i2, em::ex2); + const auto e2_d = metric.template transform<2, Idx::U, Idx::D>( + { i1_, i2_ + HALF }, + e2_u); + buff += e2_u * e2_d; + } else { + const auto e3_u = EM(i1, i2, em::ex3); + const auto e3_d = metric.template transform<3, Idx::U, Idx::D>( + { i1_, i2_ }, + e3_u); + buff += e3_u * e3_d; + } + } else if constexpr (F == StatsID::ExB) { + if constexpr (I == 1) { + const auto e2_t = metric.template transform<2, Idx::U, Idx::T>( + { i1_ + HALF, i2_ + HALF }, + HALF * (EM(i1, i2, em::ex2) + EM(i1 + 1, i2, em::ex2))); + const auto e3_t = metric.template transform<3, Idx::U, Idx::T>( + { i1_ + HALF, i2_ + HALF }, + INV_4 * (EM(i1, i2, em::ex3) + EM(i1 + 1, i2, em::ex3) + + EM(i1, i2 + 1, em::ex3) + EM(i1 + 1, i2 + 1, em::ex3))); + const auto b2_t = metric.template transform<2, Idx::U, Idx::T>( + { i1_ + HALF, i2_ + HALF }, + HALF * (EM(i1, i2, em::bx2) + EM(i1, i2 + 1, em::bx2))); + const auto b3_t = metric.template transform<3, Idx::U, Idx::T>( + { i1_ + HALF, i2_ + HALF }, + EM(i1, i2, em::bx3)); + buff += e2_t * b3_t - e3_t * b2_t; + } else if constexpr (I == 2) { + const auto e1_t = metric.template transform<1, Idx::U, Idx::T>( + { i1_ + HALF, i2_ + HALF }, + HALF * (EM(i1, i2, em::ex1) + EM(i1, i2 + 1, em::ex1))); + const auto e3_t = metric.template transform<3, Idx::U, Idx::T>( + { i1_ + HALF, i2_ + HALF }, + INV_4 * (EM(i1, i2, em::ex3) + EM(i1 + 1, i2, em::ex3) + + EM(i1, i2 + 1, em::ex3) + EM(i1 + 1, i2 + 1, em::ex3))); + const auto b1_t = metric.template transform<1, Idx::U, Idx::T>( + { i1_ + HALF, i2_ + HALF }, + HALF * (EM(i1, i2, em::bx1) + EM(i1 + 1, i2, em::bx1))); + const auto b3_t = metric.template transform<3, Idx::U, Idx::T>( + { i1_ + HALF, i2_ + HALF }, + EM(i1, i2, em::bx3)); + buff += e3_t * b1_t - e1_t * b3_t; + } else { + const auto e1_t = metric.template transform<1, Idx::U, Idx::T>( + { i1_ + HALF, i2_ + HALF }, + HALF * (EM(i1, i2, em::ex1) + EM(i1, i2 + 1, em::ex1))); + const auto e2_t = metric.template transform<2, Idx::U, Idx::T>( + { i1_ + HALF, i2_ + HALF }, + HALF * (EM(i1, i2, em::ex2) + EM(i1 + 1, i2, em::ex2))); + const auto b1_t = metric.template transform<1, Idx::U, Idx::T>( + { i1_ + HALF, i2_ + HALF }, + HALF * (EM(i1, i2, em::bx1) + EM(i1 + 1, i2, em::bx1))); + const auto b2_t = metric.template transform<2, Idx::U, Idx::T>( + { i1_ + HALF, i2_ + HALF }, + HALF * (EM(i1, i2, em::bx2) + EM(i1, i2 + 1, em::bx2))); + buff += e1_t * b2_t - e2_t * b1_t; + } + } else if constexpr (F == StatsID::JdotE) { + vec_t e_t { ZERO }; + vec_t j_t { ZERO }; + metric.template transform( + { i1_ + HALF, i2_ + HALF }, + { HALF * (EM(i1, i2, em::ex1) + EM(i1, i2 + 1, em::ex1)), + HALF * (EM(i1, i2, em::ex2) + EM(i1 + 1, i2, em::ex2)), + INV_4 * (EM(i1, i2, em::ex3) + EM(i1 + 1, i2, em::ex3) + + EM(i1, i2 + 1, em::ex3) + EM(i1 + 1, i2 + 1, em::ex3)) }, + e_t); + metric.template transform( + { i1_ + HALF, i2_ + HALF }, + { HALF * (J(i1, i2, cur::jx1) + J(i1, i2 + 1, cur::jx1)), + HALF * (J(i1, i2, cur::jx2) + J(i1 + 1, i2, cur::jx2)), + INV_4 * (J(i1, i2, cur::jx3) + J(i1 + 1, i2, cur::jx3) + + J(i1, i2 + 1, cur::jx3) + J(i1 + 1, i2 + 1, cur::jx3)) }, + j_t); + buff += e_t[0] * j_t[0] + e_t[1] * j_t[1] + e_t[2] * j_t[2]; + } + } + + Inline void operator()(index_t i1, index_t i2, index_t i3, real_t& buff) const { + const auto i1_ = COORD(i1); + const auto i2_ = COORD(i2); + const auto i3_ = COORD(i3); + if constexpr (F == StatsID::B2) { + if constexpr (I == 1) { + const auto b1_u = EM(i1, i2, i3, em::bx1); + const auto b1_d = metric.template transform<1, Idx::U, Idx::D>( + { i1_, i2_ + HALF, i3_ + HALF }, + b1_u); + buff += b1_u * b1_d; + } else if constexpr (I == 2) { + const auto b2_u = EM(i1, i2, i3, em::bx2); + const auto b2_d = metric.template transform<2, Idx::U, Idx::D>( + { i1_ + HALF, i2_, i3_ + HALF }, + b2_u); + buff += b2_u * b2_d; + } else { + const auto b3_u = EM(i1, i2, i3, em::bx3); + const auto b3_d = metric.template transform<3, Idx::U, Idx::D>( + { i1_ + HALF, i2_ + HALF, i3_ }, + b3_u); + buff += b3_u * b3_d; + } + } else if constexpr (F == StatsID::E2) { + if constexpr (I == 1) { + const auto e1_u = EM(i1, i2, i3, em::ex1); + const auto e1_d = metric.template transform<1, Idx::U, Idx::D>( + { i1_ + HALF, i2_, i3_ }, + e1_u); + buff += e1_u * e1_d; + } else if constexpr (I == 2) { + const auto e2_u = EM(i1, i2, i3, em::ex2); + const auto e2_d = metric.template transform<2, Idx::U, Idx::D>( + { i1_, i2_ + HALF, i3_ }, + e2_u); + buff += e2_u * e2_d; + } else { + const auto e3_u = EM(i1, i2, i3, em::ex3); + const auto e3_d = metric.template transform<3, Idx::U, Idx::D>( + { i1_, i2_, i3_ + HALF }, + e3_u); + buff += e3_u * e3_d; + } + } else if constexpr (F == StatsID::ExB) { + if constexpr (I == 1) { + const auto e2_t = metric.template transform<2, Idx::U, Idx::T>( + { i1_ + HALF, i2_ + HALF, i3_ + HALF }, + INV_4 * + (EM(i1, i2, i3, em::ex2) + EM(i1 + 1, i2, i3, em::ex2) + + EM(i1, i2, i3 + 1, em::ex2) + EM(i1 + 1, i2, i3 + 1, em::ex2))); + const auto e3_t = metric.template transform<3, Idx::U, Idx::T>( + { i1_ + HALF, i2_ + HALF, i3_ + HALF }, + INV_4 * + (EM(i1, i2, i3, em::ex3) + EM(i1 + 1, i2, i3, em::ex3) + + EM(i1, i2 + 1, i3, em::ex3) + EM(i1 + 1, i2 + 1, i3, em::ex3))); + const auto b2_t = metric.template transform<2, Idx::U, Idx::T>( + { i1_ + HALF, i2_ + HALF, i3_ + HALF }, + HALF * (EM(i1, i2, i3, em::bx2) + EM(i1, i2 + 1, i3, em::bx2))); + const auto b3_t = metric.template transform<3, Idx::U, Idx::T>( + { i1_ + HALF, i2_ + HALF, i3_ + HALF }, + HALF * (EM(i1, i2, i3, em::bx3) + EM(i1, i2, i3 + 1, em::bx3))); + buff += e2_t * b3_t - e3_t * b2_t; + } else if constexpr (I == 2) { + const auto e1_t = metric.template transform<1, Idx::U, Idx::T>( + { i1_ + HALF, i2_ + HALF, i3_ + HALF }, + INV_4 * + (EM(i1, i2, i3, em::ex1) + EM(i1, i2 + 1, i3, em::ex1) + + EM(i1, i2, i3 + 1, em::ex1) + EM(i1, i2 + 1, i3 + 1, em::ex1))); + const auto e3_t = metric.template transform<3, Idx::U, Idx::T>( + { i1_ + HALF, i2_ + HALF, i3_ + HALF }, + INV_4 * + (EM(i1, i2, i3, em::ex3) + EM(i1 + 1, i2, i3, em::ex3) + + EM(i1, i2 + 1, i3, em::ex3) + EM(i1 + 1, i2 + 1, i3, em::ex3))); + const auto b1_t = metric.template transform<1, Idx::U, Idx::T>( + { i1_ + HALF, i2_ + HALF, i3_ + HALF }, + HALF * (EM(i1, i2, i3, em::bx1) + EM(i1 + 1, i2, i3, em::bx1))); + const auto b3_t = metric.template transform<3, Idx::U, Idx::T>( + { i1_ + HALF, i2_ + HALF, i3_ + HALF }, + HALF * (EM(i1, i2, i3, em::bx3) + EM(i1, i2, i3 + 1, em::bx3))); + buff += e3_t * b1_t - e1_t * b3_t; + } else { + const auto e1_t = metric.template transform<1, Idx::U, Idx::T>( + { i1_ + HALF, i2_ + HALF, i3_ + HALF }, + INV_4 * + (EM(i1, i2, i3, em::ex1) + EM(i1, i2 + 1, i3, em::ex1) + + EM(i1, i2, i3 + 1, em::ex1) + EM(i1, i2 + 1, i3 + 1, em::ex1))); + const auto e2_t = metric.template transform<2, Idx::U, Idx::T>( + { i1_ + HALF, i2_ + HALF, i3_ + HALF }, + INV_4 * + (EM(i1, i2, i3, em::ex2) + EM(i1 + 1, i2, i3, em::ex2) + + EM(i1, i2, i3 + 1, em::ex2) + EM(i1 + 1, i2, i3 + 1, em::ex2))); + const auto b1_t = metric.template transform<1, Idx::U, Idx::T>( + { i1_ + HALF, i2_ + HALF, i3_ + HALF }, + HALF * (EM(i1, i2, i3, em::bx1) + EM(i1 + 1, i2, i3, em::bx1))); + const auto b2_t = metric.template transform<2, Idx::U, Idx::T>( + { i1_ + HALF, i2_ + HALF, i3_ + HALF }, + HALF * (EM(i1, i2, i3, em::bx2) + EM(i1, i2 + 1, i3, em::bx2))); + buff += e1_t * b2_t - e2_t * b1_t; + } + } else if constexpr (F == StatsID::JdotE) { + vec_t e_t { ZERO }; + vec_t j_t { ZERO }; + metric.template transform( + { i1_ + HALF, i2_ + HALF, i3_ + HALF }, + { INV_4 * (EM(i1, i2, i3, em::ex1) + EM(i1, i2 + 1, i3, em::ex1) + + EM(i1, i2, i3 + 1, em::ex1) + EM(i1, i2 + 1, i3 + 1, em::ex1)), + INV_4 * (EM(i1, i2, i3, em::ex2) + EM(i1 + 1, i2, i3, em::ex2) + + EM(i1, i2, i3 + 1, em::ex2) + EM(i1 + 1, i2, i3 + 1, em::ex2)), + INV_4 * (EM(i1, i2, i3, em::ex3) + EM(i1 + 1, i2, i3, em::ex3) + + EM(i1, i2 + 1, i3, em::ex3) + EM(i1 + 1, i2 + 1, i3, em::ex3)) }, + e_t); + metric.template transform( + { i1_ + HALF, i2_ + HALF, i3_ + HALF }, + { INV_4 * (J(i1, i2, i3, cur::jx1) + J(i1, i2 + 1, i3, cur::jx1) + + J(i1, i2, i3 + 1, cur::jx1) + J(i1, i2 + 1, i3 + 1, cur::jx1)), + INV_4 * (J(i1, i2, i3, cur::jx2) + J(i1 + 1, i2, i3, cur::jx2) + + J(i1, i2, i3 + 1, cur::jx2) + J(i1 + 1, i2, i3 + 1, cur::jx2)), + INV_4 * (J(i1, i2, i3, cur::jx3) + J(i1 + 1, i2, i3, cur::jx3) + + J(i1, i2 + 1, i3, cur::jx3) + J(i1 + 1, i2 + 1, i3, cur::jx3)) }, + j_t); + buff += e_t[0] * j_t[0] + e_t[1] * j_t[1] + e_t[2] * j_t[2]; + } + } + }; + +} // namespace kernel + +#endif diff --git a/src/output/stats.cpp b/src/output/stats.cpp index ba3e85c40..68392dc0b 100644 --- a/src/output/stats.cpp +++ b/src/output/stats.cpp @@ -38,13 +38,13 @@ namespace stats { species = {}; } if (is_vector()) { - // always write all the ExB and V components + // always write all the E^2, B^2, ExB components comp = { { 1 }, { 2 }, { 3 } }; } else if (id() == StatsID::T) { // energy-momentum tensor comp = InterpretComponents({ name.substr(1, 1), name.substr(2, 1) }); } else { - // scalar (e.g., Rho, E^2, etc.) + // scalar (e.g., Rho, Npart, etc.) comp = {}; } } diff --git a/src/output/stats.h b/src/output/stats.h index c81b9b7b3..ddea9ad4c 100644 --- a/src/output/stats.h +++ b/src/output/stats.h @@ -3,10 +3,11 @@ * @brief Class defining the metadata necessary to prepare the stats for output * @implements * - out::OutputStats + * - out::Writer * @cpp: * - stats.cpp * @namespaces: - * - out:: + * - stats:: */ #ifndef OUTPUT_STATS_H @@ -16,10 +17,16 @@ #include "global.h" #include "utils/error.h" +#include "utils/formatting.h" #include "utils/tools.h" +#if defined(MPI_ENABLED) + #include "arch/mpi_aliases.h" + + #include +#endif + #include -#include #include #include @@ -47,7 +54,7 @@ namespace stats { [[nodiscard]] auto is_vector() const -> bool { - return id() == StatsID::ExB; + return id() == StatsID::ExB || id() == StatsID::E2 || id() == StatsID::B2; } [[nodiscard]] @@ -65,7 +72,11 @@ namespace stats { if (id() == StatsID::T) { tmp += m_name.substr(1, 2); } else if (is_vector()) { - tmp += "i"; + if (id() == StatsID::E2 || id() == StatsID::B2) { + tmp = fmt::format("%ci^2", tmp[0]); + } else { + tmp += "i"; + } } if (species.size() > 0) { tmp += "_"; @@ -101,16 +112,20 @@ namespace stats { // capitalize the first letter tmp[0] = std::toupper(tmp[0]); } - for (auto& c : comp[ci]) { - tmp += std::to_string(c); - } - if (species.size() > 0) { - tmp += "_"; - for (auto& s : species) { - tmp += std::to_string(s); + if (tmp == "E^2" or tmp == "B^2") { + tmp = fmt::format("%c%d^2", tmp[0], comp[ci][0]); + } else { + for (auto& c : comp[ci]) { + tmp += std::to_string(c); + } + if (species.size() > 0) { tmp += "_"; + for (auto& s : species) { + tmp += std::to_string(s); + tmp += "_"; + } + tmp.pop_back(); } - tmp.pop_back(); } return tmp; } @@ -145,16 +160,25 @@ namespace stats { template inline void write(const T& value) const { #if defined(MPI_ENABLED) - // @TODO: reduce + T tot_value = static_cast(0); + MPI_Reduce(&value, + &tot_value, + 1, + mpi::get_type(), + MPI_SUM, + MPI_ROOT_RANK, + MPI_COMM_WORLD); +#else + tot_value = value; #endif CallOnce( - [](auto& fname, auto& value) { + [](auto&& fname, auto&& value) { std::fstream StatsOut(fname, std::fstream::out | std::fstream::app); StatsOut << value << ","; StatsOut.close(); }, m_fname, - value); + tot_value); } void endWriting(); From ea6f71ff098da761eeb72b6420cb71c17a30f1f0 Mon Sep 17 00:00:00 2001 From: haykh Date: Mon, 5 May 2025 14:02:11 -0400 Subject: [PATCH 687/773] minimial simplified --- minimal/CMakeLists.txt | 140 +++++++++++++++++++++++++++++++++++-- minimal/adios2-mpi.cmake | 17 ----- minimal/adios2-nompi.cmake | 14 ---- minimal/kokkos.cpp | 58 +++++++++++++++ minimal/mpi-simple.cmake | 31 -------- minimal/mpi.cmake | 31 -------- 6 files changed, 192 insertions(+), 99 deletions(-) delete mode 100644 minimal/adios2-mpi.cmake delete mode 100644 minimal/adios2-nompi.cmake create mode 100644 minimal/kokkos.cpp delete mode 100644 minimal/mpi-simple.cmake delete mode 100644 minimal/mpi.cmake diff --git a/minimal/CMakeLists.txt b/minimal/CMakeLists.txt index 58191d97c..b21dd0fec 100644 --- a/minimal/CMakeLists.txt +++ b/minimal/CMakeLists.txt @@ -1,5 +1,4 @@ # cmake-lint: disable=C0103,C0111,E1120,R0913,R0915 - cmake_minimum_required(VERSION 3.16) cmake_policy(SET CMP0110 NEW) @@ -30,23 +29,152 @@ set(BUILD_TESTING CACHE BOOL "Build tests") set(MODES - "ADIOS2_NOMPI;ADIOS2_MPI" + "KOKKOS;ADIOS2_NOMPI" CACHE STRING "Build modes") +function(find_kokkos) + find_package(Kokkos QUIET) + if(NOT Kokkos_FOUND) + include(FetchContent) + FetchContent_Declare( + Kokkos + GIT_REPOSITORY https://github.com/kokkos/kokkos.git + GIT_TAG 4.6.01) + FetchContent_MakeAvailable(Kokkos) + endif() + if(NOT DEFINED Kokkos_ARCH + OR Kokkos_ARCH STREQUAL "" + OR NOT DEFINED Kokkos_DEVICES + OR Kokkos_DEVICES STREQUAL "") + if(${Kokkos_FOUND}) + include(${Kokkos_DIR}/KokkosConfigCommon.cmake) + elseif(NOT ${Kokkos_BUILD_DIR} STREQUAL "") + include(${Kokkos_BUILD_DIR}/KokkosConfigCommon.cmake) + else() + message( + STATUS "${Red}Kokkos_DIR and Kokkos_BUILD_DIR not set.${ColorReset}") + endif() + endif() +endfunction() + +function(find_adios2) + find_package(adios2 QUIET) + if(NOT adios2_FOUND) + include(FetchContent) + FetchContent_Declare( + adios2 + GIT_REPOSITORY https://github.com/ornladios/ADIOS2.git + GIT_TAG 2.10.2) + FetchContent_MakeAvailable(adios2) + endif() +endfunction() + +if("KOKKOS" IN_LIST MODES) + set(libs "") + set(exec kokkos.xc) + set(src ${CMAKE_CURRENT_SOURCE_DIR}/kokkos.cpp) + + find_kokkos() + list(APPEND libs Kokkos::kokkos) + + add_executable(${exec} ${src}) + + target_link_libraries(${exec} ${libs}) +endif() + if("ADIOS2_NOMPI" IN_LIST MODES) - include(adios2-nompi.cmake) + set(libs stdc++fs) + set(exec adios2-nompi.xc) + set(src ${CMAKE_CURRENT_SOURCE_DIR}/adios2.cpp) + + find_kokkos() + find_adios2() + list(APPEND libs Kokkos::kokkos adios2::cxx11) + + add_executable(${exec} ${src}) + + target_link_libraries(${exec} ${libs}) endif() if("ADIOS2_MPI" IN_LIST MODES) - include(adios2-mpi.cmake) + set(libs stdc++fs) + set(exec adios2-mpi.xc) + set(src ${CMAKE_CURRENT_SOURCE_DIR}/adios2.cpp) + + find_package(MPI REQUIRED) + find_kokkos() + find_adios2() + list(APPEND libs MPI::MPI_CXX Kokkos::kokkos adios2::cxx11_mpi) + + add_executable(${exec} ${src}) + + target_include_directories(${exec} PUBLIC ${MPI_CXX_INCLUDE_PATH}) + target_compile_options(${exec} PUBLIC "-D MPI_ENABLED") + target_link_libraries(${exec} ${libs}) endif() if("MPI" IN_LIST MODES) - include(mpi.cmake) + set(libs "") + set(exec mpi-simple.xc) + set(src ${CMAKE_CURRENT_SOURCE_DIR}/mpi-simple.cpp) + + find_package(MPI REQUIRED) + find_kokkos() + list(APPEND libs MPI::MPI_CXX Kokkos::kokkos) + + add_executable(${exec} ${src}) + + target_include_directories(${exec} PUBLIC ${MPI_CXX_INCLUDE_PATH}) + target_link_libraries(${exec} ${libs}) + + set(GPU_AWARE_MPI + ON + CACHE BOOL "Enable GPU-aware MPI support") + + if(("${Kokkos_DEVICES}" MATCHES "CUDA") + OR ("${Kokkos_DEVICES}" MATCHES "HIP") + OR ("${Kokkos_DEVICES}" MATCHES "SYCL")) + set(DEVICE_ENABLED ON) + target_compile_options(${exec} PRIVATE -DDEVICE_ENABLED) + else() + set(DEVICE_ENABLED OFF) + endif() + + if(${GPU_AWARE_MPI}) + target_compile_options(${exec} PRIVATE -DGPU_AWARE_MPI) + endif() endif() if("MPI_SIMPLE" IN_LIST MODES) - include(mpi-simple.cmake) + set(libs "") + set(exec mpi-simple.xc) + set(src ${CMAKE_CURRENT_SOURCE_DIR}/mpi-simple.cpp) + + find_package(MPI REQUIRED) + find_kokkos() + list(APPEND libs MPI::MPI_CXX Kokkos::kokkos) + + add_executable(${exec} ${src}) + + target_include_directories(${exec} PUBLIC ${MPI_CXX_INCLUDE_PATH}) + target_link_libraries(${exec} ${libs}) + + set(GPU_AWARE_MPI + ON + CACHE BOOL "Enable GPU-aware MPI support") + + if(("${Kokkos_DEVICES}" MATCHES "CUDA") + OR ("${Kokkos_DEVICES}" MATCHES "HIP") + OR ("${Kokkos_DEVICES}" MATCHES "SYCL")) + set(DEVICE_ENABLED ON) + target_compile_options(${exec} PRIVATE -DDEVICE_ENABLED) + else() + set(DEVICE_ENABLED OFF) + endif() + + if(${GPU_AWARE_MPI}) + target_compile_options(${exec} PRIVATE -DGPU_AWARE_MPI) + endif() endif() message(STATUS "Build modes: ${MODES}") diff --git a/minimal/adios2-mpi.cmake b/minimal/adios2-mpi.cmake deleted file mode 100644 index 8e5066f68..000000000 --- a/minimal/adios2-mpi.cmake +++ /dev/null @@ -1,17 +0,0 @@ -# cmake-lint: disable=C0103 -include(${CMAKE_CURRENT_SOURCE_DIR}/../cmake/dependencies.cmake) - -set(libs stdc++fs) -set(exec adios2-mpi.xc) -set(src ${CMAKE_CURRENT_SOURCE_DIR}/adios2.cpp) - -find_or_fetch_dependency(MPI FALSE REQUIRED) -find_or_fetch_dependency(Kokkos FALSE QUIET) -find_or_fetch_dependency(adios2 FALSE QUIET) -list(APPEND libs MPI::MPI_CXX Kokkos::kokkos adios2::cxx11_mpi) - -add_executable(${exec} ${src}) - -target_include_directories(${exec} PUBLIC ${MPI_CXX_INCLUDE_PATH}) -target_compile_options(${exec} PUBLIC "-D MPI_ENABLED") -target_link_libraries(${exec} ${libs}) diff --git a/minimal/adios2-nompi.cmake b/minimal/adios2-nompi.cmake deleted file mode 100644 index c593d72e0..000000000 --- a/minimal/adios2-nompi.cmake +++ /dev/null @@ -1,14 +0,0 @@ -# cmake-lint: disable=C0103 -include(${CMAKE_CURRENT_SOURCE_DIR}/../cmake/dependencies.cmake) - -set(libs stdc++fs) -set(exec adios2-nompi.xc) -set(src ${CMAKE_CURRENT_SOURCE_DIR}/adios2.cpp) - -find_or_fetch_dependency(Kokkos FALSE QUIET) -find_or_fetch_dependency(adios2 FALSE QUIET) -list(APPEND libs Kokkos::kokkos adios2::cxx11) - -add_executable(${exec} ${src}) - -target_link_libraries(${exec} ${libs}) diff --git a/minimal/kokkos.cpp b/minimal/kokkos.cpp new file mode 100644 index 000000000..2be2996a8 --- /dev/null +++ b/minimal/kokkos.cpp @@ -0,0 +1,58 @@ +#include + +#include +#include + +auto main(int argc, char** argv) -> int { + try { + Kokkos::initialize(argc, argv); + Kokkos::DefaultExecutionSpace {}.print_configuration(std::cout); + + std::cout << "1D views" << std::endl; + for (const auto& sz : { 100u, 10000u, 1000000u }) { + Kokkos::View view { "test_view", sz }; + Kokkos::parallel_for( + "fill_1d", + Kokkos::RangePolicy<>(0, sz), + KOKKOS_LAMBDA(std::size_t i) { view(i) = static_cast(i); }); + Kokkos::fence(); + std::cout << "- allocated " << view.size() << std::endl; + } + + std::cout << "2D views" << std::endl; + for (const auto& sz : { 10u, 100u, 1000u }) { + Kokkos::View view { "test_view", sz, 2 * sz }; + Kokkos::parallel_for( + "fill_2d", + Kokkos::MDRangePolicy>({ 0, 0 }, { sz, 2 * sz }), + KOKKOS_LAMBDA(std::size_t i, std::size_t j) { + view(i, j) = static_cast(i * 2 * sz + j); + }); + Kokkos::fence(); + std::cout << "- allocated " << view.size() << std::endl; + } + + std::cout << "3D views" << std::endl; + for (const auto& sz : { 10u, 100u }) { + Kokkos::View view { "test_view", sz, 2 * sz, 3 * sz }; + Kokkos::parallel_for( + "fill_3d", + Kokkos::MDRangePolicy>({ 0, 0, 0 }, { sz, 2 * sz, 3 * sz }), + KOKKOS_LAMBDA(std::size_t i, std::size_t j, std::size_t k) { + view(i, j, k) = static_cast(i * 2 * sz * 3 * sz + j * 3 * sz + k); + }); + Kokkos::fence(); + std::cout << "- allocated " << view.size() << std::endl; + } + + } catch (const std::exception& e) { + if (Kokkos::is_initialized()) { + Kokkos::finalize(); + } + std::cerr << "Error: " << e.what() << std::endl; + return 1; + } + + Kokkos::finalize(); + return 0; +} diff --git a/minimal/mpi-simple.cmake b/minimal/mpi-simple.cmake deleted file mode 100644 index 136d009c8..000000000 --- a/minimal/mpi-simple.cmake +++ /dev/null @@ -1,31 +0,0 @@ -# cmake-lint: disable=C0103 -include(${CMAKE_CURRENT_SOURCE_DIR}/../cmake/dependencies.cmake) - -set(exec mpi-simple.xc) -set(src ${CMAKE_CURRENT_SOURCE_DIR}/mpi-simple.cpp) - -find_or_fetch_dependency(MPI FALSE REQUIRED) -find_or_fetch_dependency(Kokkos FALSE QUIET) -list(APPEND libs MPI::MPI_CXX Kokkos::kokkos) - -add_executable(${exec} ${src}) - -target_include_directories(${exec} PUBLIC ${MPI_CXX_INCLUDE_PATH}) -target_link_libraries(${exec} ${libs}) - -set(GPU_AWARE_MPI - ON - CACHE BOOL "Enable GPU-aware MPI support") - -if(("${Kokkos_DEVICES}" MATCHES "CUDA") - OR ("${Kokkos_DEVICES}" MATCHES "HIP") - OR ("${Kokkos_DEVICES}" MATCHES "SYCL")) - set(DEVICE_ENABLED ON) - target_compile_options(${exec} PRIVATE -DDEVICE_ENABLED) -else() - set(DEVICE_ENABLED OFF) -endif() - -if(${GPU_AWARE_MPI}) - target_compile_options(${exec} PRIVATE -DGPU_AWARE_MPI) -endif() diff --git a/minimal/mpi.cmake b/minimal/mpi.cmake deleted file mode 100644 index f27195c07..000000000 --- a/minimal/mpi.cmake +++ /dev/null @@ -1,31 +0,0 @@ -# cmake-lint: disable=C0103 -include(${CMAKE_CURRENT_SOURCE_DIR}/../cmake/dependencies.cmake) - -set(exec mpi.xc) -set(src ${CMAKE_CURRENT_SOURCE_DIR}/mpi.cpp) - -find_or_fetch_dependency(MPI FALSE REQUIRED) -find_or_fetch_dependency(Kokkos FALSE QUIET) -list(APPEND libs MPI::MPI_CXX Kokkos::kokkos) - -add_executable(${exec} ${src}) - -target_include_directories(${exec} PUBLIC ${MPI_CXX_INCLUDE_PATH}) -target_link_libraries(${exec} ${libs}) - -set(GPU_AWARE_MPI - ON - CACHE BOOL "Enable GPU-aware MPI support") - -if(("${Kokkos_DEVICES}" MATCHES "CUDA") - OR ("${Kokkos_DEVICES}" MATCHES "HIP") - OR ("${Kokkos_DEVICES}" MATCHES "SYCL")) - set(DEVICE_ENABLED ON) - target_compile_options(${exec} PRIVATE -DDEVICE_ENABLED) -else() - set(DEVICE_ENABLED OFF) -endif() - -if(${GPU_AWARE_MPI}) - target_compile_options(${exec} PRIVATE -DGPU_AWARE_MPI) -endif() From d3772bb524539c0c9e6394bb37244aa1b6cbd66e Mon Sep 17 00:00:00 2001 From: haykh Date: Mon, 5 May 2025 14:02:34 -0400 Subject: [PATCH 688/773] 4.5.1->4.6.1 for kokkos --- cmake/dependencies.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/dependencies.cmake b/cmake/dependencies.cmake index a21ea00e8..1780bf97e 100644 --- a/cmake/dependencies.cmake +++ b/cmake/dependencies.cmake @@ -58,7 +58,7 @@ function(find_or_fetch_dependency package_name header_only mode) FetchContent_Declare( ${package_name} GIT_REPOSITORY ${${package_name}_REPOSITORY} - GIT_TAG 4.5.01) + GIT_TAG 4.6.01) else() FetchContent_Declare(${package_name} GIT_REPOSITORY ${${package_name}_REPOSITORY}) From 5391a94f5ef7c7eba14a21045af4b2262e6ed69a Mon Sep 17 00:00:00 2001 From: haykh Date: Mon, 5 May 2025 14:04:44 -0400 Subject: [PATCH 689/773] 4.5.1->4.6.1 for kokkos --- extern/Kokkos | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extern/Kokkos b/extern/Kokkos index 175257a51..1b1383c60 160000 --- a/extern/Kokkos +++ b/extern/Kokkos @@ -1 +1 @@ -Subproject commit 175257a51ff29a0059ec48bcd233ee096b2c0438 +Subproject commit 1b1383c6001f3bfe9fe309ca923c2d786600cc79 From cc403dc58bbb9f9a75cfc516d19c866b3e4d9bc4 Mon Sep 17 00:00:00 2001 From: haykh Date: Mon, 5 May 2025 16:36:37 -0400 Subject: [PATCH 690/773] minor include rm --- src/framework/tests/comm_nompi.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/framework/tests/comm_nompi.cpp b/src/framework/tests/comm_nompi.cpp index f9581c1e1..c7646ef03 100644 --- a/src/framework/tests/comm_nompi.cpp +++ b/src/framework/tests/comm_nompi.cpp @@ -7,8 +7,6 @@ #include "arch/kokkos_aliases.h" #include "utils/numeric.h" -#include "framework/domain/comm_mpi.hpp" - #include #include From c757c3e97316583d313a85dd602da449d8393e27 Mon Sep 17 00:00:00 2001 From: haykh Date: Thu, 1 May 2025 21:31:07 -0400 Subject: [PATCH 691/773] stats reduction for flds --- src/engines/engine.hpp | 1 - src/framework/domain/checkpoint.cpp | 106 ++++++- src/framework/domain/communications.cpp | 100 ++++++- src/framework/domain/grid.cpp | 8 +- src/framework/domain/metadomain.cpp | 1 - src/framework/domain/metadomain.h | 8 +- src/framework/domain/output.cpp | 128 +++++++- src/framework/domain/stats.cpp | 181 +++++++++-- src/global/enums.h | 2 + src/kernels/reduced_stats.hpp | 381 ++++++++++++++++++++++++ src/output/stats.cpp | 4 +- src/output/stats.h | 54 +++- 12 files changed, 895 insertions(+), 79 deletions(-) create mode 100644 src/kernels/reduced_stats.hpp diff --git a/src/engines/engine.hpp b/src/engines/engine.hpp index 9525874a6..5956ea5d9 100644 --- a/src/engines/engine.hpp +++ b/src/engines/engine.hpp @@ -23,7 +23,6 @@ #include "arch/traits.h" #include "utils/error.h" -#include "utils/progressbar.h" #include "utils/timer.h" #include "utils/toml.h" diff --git a/src/framework/domain/checkpoint.cpp b/src/framework/domain/checkpoint.cpp index 656ff57d0..25cdcf0f6 100644 --- a/src/framework/domain/checkpoint.cpp +++ b/src/framework/domain/checkpoint.cpp @@ -474,13 +474,103 @@ namespace ntt { HERE); } - template struct Metadomain>; - template struct Metadomain>; - template struct Metadomain>; - template struct Metadomain>; - template struct Metadomain>; - template struct Metadomain>; - template struct Metadomain>; - template struct Metadomain>; + template void Metadomain>::InitCheckpointWriter( + adios2::ADIOS*, + const SimulationParams&); + template void Metadomain>::InitCheckpointWriter( + adios2::ADIOS*, + const SimulationParams&); + template void Metadomain>::InitCheckpointWriter( + adios2::ADIOS*, + const SimulationParams&); + template void Metadomain>::InitCheckpointWriter( + adios2::ADIOS*, + const SimulationParams&); + template void Metadomain>::InitCheckpointWriter( + adios2::ADIOS*, + const SimulationParams&); + template void Metadomain>::InitCheckpointWriter( + adios2::ADIOS*, + const SimulationParams&); + template void Metadomain>::InitCheckpointWriter( + adios2::ADIOS*, + const SimulationParams&); + template void Metadomain>::InitCheckpointWriter( + adios2::ADIOS*, + const SimulationParams&); + + template auto Metadomain>::WriteCheckpoint( + const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t) -> bool; + template auto Metadomain>::WriteCheckpoint( + const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t) -> bool; + template auto Metadomain>::WriteCheckpoint( + const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t) -> bool; + template auto Metadomain>::WriteCheckpoint( + const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t) -> bool; + template auto Metadomain>::WriteCheckpoint( + const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t) -> bool; + template auto Metadomain>::WriteCheckpoint( + const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t) -> bool; + template auto Metadomain>::WriteCheckpoint( + const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t) -> bool; + template auto Metadomain>::WriteCheckpoint( + const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t) -> bool; + + template void Metadomain>::ContinueFromCheckpoint( + adios2::ADIOS*, + const SimulationParams&); + template void Metadomain>::ContinueFromCheckpoint( + adios2::ADIOS*, + const SimulationParams&); + template void Metadomain>::ContinueFromCheckpoint( + adios2::ADIOS*, + const SimulationParams&); + template void Metadomain>::ContinueFromCheckpoint( + adios2::ADIOS*, + const SimulationParams&); + template void Metadomain>::ContinueFromCheckpoint( + adios2::ADIOS*, + const SimulationParams&); + template void Metadomain>::ContinueFromCheckpoint( + adios2::ADIOS*, + const SimulationParams&); + template void Metadomain>::ContinueFromCheckpoint( + adios2::ADIOS*, + const SimulationParams&); + template void Metadomain>::ContinueFromCheckpoint( + adios2::ADIOS*, + const SimulationParams&); } // namespace ntt diff --git a/src/framework/domain/communications.cpp b/src/framework/domain/communications.cpp index 841c9a7da..23bb5b88c 100644 --- a/src/framework/domain/communications.cpp +++ b/src/framework/domain/communications.cpp @@ -641,13 +641,95 @@ namespace ntt { } } - template struct Metadomain>; - template struct Metadomain>; - template struct Metadomain>; - template struct Metadomain>; - template struct Metadomain>; - template struct Metadomain>; - template struct Metadomain>; - template struct Metadomain>; - + template void Metadomain>::CommunicateFields( + Domain>&, + CommTags); + template void Metadomain>::CommunicateFields( + Domain>&, + CommTags); + template void Metadomain>::CommunicateFields( + Domain>&, + CommTags); + template void Metadomain>::CommunicateFields( + Domain>&, + CommTags); + template void Metadomain>::CommunicateFields( + Domain>&, + CommTags); + template void Metadomain>::CommunicateFields( + Domain>&, + CommTags); + template void Metadomain>::CommunicateFields( + Domain>&, + CommTags); + template void Metadomain>::CommunicateFields( + Domain>&, + CommTags); + + template void Metadomain>::SynchronizeFields( + Domain>&, + CommTags, + const range_tuple_t&); + template void Metadomain>::SynchronizeFields( + Domain>&, + CommTags, + const range_tuple_t&); + template void Metadomain>::SynchronizeFields( + Domain>&, + CommTags, + const range_tuple_t&); + template void Metadomain>::SynchronizeFields( + Domain>&, + CommTags, + const range_tuple_t&); + template void Metadomain>::SynchronizeFields( + Domain>&, + CommTags, + const range_tuple_t&); + template void Metadomain>::SynchronizeFields( + Domain>&, + CommTags, + const range_tuple_t&); + template void Metadomain>::SynchronizeFields( + Domain>&, + CommTags, + const range_tuple_t&); + template void Metadomain>::SynchronizeFields( + Domain>&, + CommTags, + const range_tuple_t&); + + template void Metadomain>::CommunicateParticles( + Domain>&); + template void Metadomain>::CommunicateParticles( + Domain>&); + template void Metadomain>::CommunicateParticles( + Domain>&); + template void Metadomain>::CommunicateParticles( + Domain>&); + template void Metadomain>::CommunicateParticles( + Domain>&); + template void Metadomain>::CommunicateParticles( + Domain>&); + template void Metadomain>::CommunicateParticles( + Domain>&); + template void Metadomain>::CommunicateParticles( + Domain>&); + + template void Metadomain>::RemoveDeadParticles( + Domain>&); + template void Metadomain>::RemoveDeadParticles( + Domain>&); + template void Metadomain>::RemoveDeadParticles( + Domain>&); + template void Metadomain>::RemoveDeadParticles( + Domain>&); + template void Metadomain>::RemoveDeadParticles( + Domain>&); + template void Metadomain>::RemoveDeadParticles( + Domain>&); + template void Metadomain>::RemoveDeadParticles( + Domain>&); + template void Metadomain>::RemoveDeadParticles( + Domain>&); } // namespace ntt diff --git a/src/framework/domain/grid.cpp b/src/framework/domain/grid.cpp index ddbfc38f0..f087df6f5 100644 --- a/src/framework/domain/grid.cpp +++ b/src/framework/domain/grid.cpp @@ -86,8 +86,8 @@ namespace ntt { } template - auto Grid::rangeCellsOnHost(const box_region_t& region) const - -> range_h_t { + auto Grid::rangeCellsOnHost( + const box_region_t& region) const -> range_h_t { tuple_t imin, imax; for (auto i { 0u }; i < D; i++) { switch (region[i]) { @@ -163,8 +163,8 @@ namespace ntt { } template - auto Grid::rangeCells(const tuple_t, D>& ranges) const - -> range_t { + auto Grid::rangeCells( + const tuple_t, D>& ranges) const -> range_t { tuple_t imin, imax; for (auto i { 0u }; i < D; i++) { raise::ErrorIf((ranges[i][0] < -(int)N_GHOSTS) || diff --git a/src/framework/domain/metadomain.cpp b/src/framework/domain/metadomain.cpp index 4b9057e23..a0326913b 100644 --- a/src/framework/domain/metadomain.cpp +++ b/src/framework/domain/metadomain.cpp @@ -23,7 +23,6 @@ #include #include -#include #include #include diff --git a/src/framework/domain/metadomain.h b/src/framework/domain/metadomain.h index 1fb6ce007..363b164d3 100644 --- a/src/framework/domain/metadomain.h +++ b/src/framework/domain/metadomain.h @@ -19,7 +19,6 @@ #include "global.h" #include "arch/kokkos_aliases.h" -#include "utils/timer.h" #include "framework/containers/species.h" #include "framework/domain/domain.h" @@ -138,8 +137,11 @@ namespace ntt { #endif void InitStatsWriter(const SimulationParams&, bool); - auto WriteStats(const SimulationParams&, timestep_t, timestep_t, simtime_t, simtime_t) - -> bool; + auto WriteStats(const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t) -> bool; /* setters -------------------------------------------------------------- */ void setFldsBC(const bc_in&, const FldsBC&); diff --git a/src/framework/domain/output.cpp b/src/framework/domain/output.cpp index 6903c7194..99987989e 100644 --- a/src/framework/domain/output.cpp +++ b/src/framework/domain/output.cpp @@ -708,13 +708,125 @@ namespace ntt { return true; } - template struct Metadomain>; - template struct Metadomain>; - template struct Metadomain>; - template struct Metadomain>; - template struct Metadomain>; - template struct Metadomain>; - template struct Metadomain>; - template struct Metadomain>; + template void Metadomain>::InitWriter( + adios2::ADIOS*, + const SimulationParams&, + bool); + template void Metadomain>::InitWriter( + adios2::ADIOS*, + const SimulationParams&, + bool); + template void Metadomain>::InitWriter( + adios2::ADIOS*, + const SimulationParams&, + bool); + template void Metadomain>::InitWriter( + adios2::ADIOS*, + const SimulationParams&, + bool); + template void Metadomain>::InitWriter( + adios2::ADIOS*, + const SimulationParams&, + bool); + template void Metadomain>::InitWriter( + adios2::ADIOS*, + const SimulationParams&, + bool); + template void Metadomain>::InitWriter( + adios2::ADIOS*, + const SimulationParams&, + bool); + template void Metadomain>::InitWriter( + adios2::ADIOS*, + const SimulationParams&, + bool); + template auto Metadomain>::Write( + const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t, + std::function&, + std::size_t, + const Domain>&)>) + -> bool; + template auto Metadomain>::Write( + const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t, + std::function&, + std::size_t, + const Domain>&)>) + -> bool; + template auto Metadomain>::Write( + const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t, + std::function&, + std::size_t, + const Domain>&)>) + -> bool; + template auto Metadomain>::Write( + const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t, + std::function&, + std::size_t, + const Domain>&)>) + -> bool; + template auto Metadomain>::Write( + const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t, + std::function&, + std::size_t, + const Domain>&)>) + -> bool; + template auto Metadomain>::Write( + const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t, + std::function&, + std::size_t, + const Domain>&)>) + -> bool; + template auto Metadomain>::Write( + const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t, + std::function&, + std::size_t, + const Domain>&)>) + -> bool; + template auto Metadomain>::Write( + const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t, + std::function&, + std::size_t, + const Domain>&)>) + -> bool; } // namespace ntt diff --git a/src/framework/domain/stats.cpp b/src/framework/domain/stats.cpp index 60acd64a9..cf7613bdb 100644 --- a/src/framework/domain/stats.cpp +++ b/src/framework/domain/stats.cpp @@ -18,6 +18,8 @@ #include "framework/domain/metadomain.h" #include "framework/parameters.h" +#include "kernels/reduced_stats.hpp" + #include #include #include @@ -107,17 +109,63 @@ namespace ntt { } template - auto ComputeFields(Domain* domain, - const std::vector& components) -> real_t { + auto ReduceFields(Domain* domain, + const std::vector& components) -> real_t { auto buffer { ZERO }; - // Kokkos::parallel_reduce( - // "ComputeMoments", - // prtl_spec.rangeActiveParticles(), - // kernel::ReducedFields_kernel(components, - // domain->fields.em, - // domain->fields.cur, - // domain->mesh.metric), - // buffer); + if constexpr (F == StatsID::JdotE) { + if (components.size() == 0) { + Kokkos::parallel_reduce( + "ReduceFields", + domain->mesh.rangeActiveCells(), + kernel::ReducedFields_kernel(domain->fields.em, + domain->fields.cur, + domain->mesh.metric), + buffer); + } else { + raise::Error("Components not supported for JdotE", HERE); + } + } else if constexpr ( + (S == SimEngine::SRPIC) and + (F == StatsID::B2 or F == StatsID::E2 or F == StatsID::ExB)) { + raise::ErrorIf(components.size() != 1, + "Components must be of size 1 for B2, E2 or ExB stats", + HERE); + const auto comp = components[0]; + if (comp == 1) { + Kokkos::parallel_reduce( + "ReduceFields", + domain->mesh.rangeActiveCells(), + kernel::ReducedFields_kernel(domain->fields.em, + domain->fields.cur, + domain->mesh.metric), + buffer); + } else if (comp == 2) { + Kokkos::parallel_reduce( + "ReduceFields", + domain->mesh.rangeActiveCells(), + kernel::ReducedFields_kernel(domain->fields.em, + domain->fields.cur, + domain->mesh.metric), + buffer); + } else if (comp == 3) { + Kokkos::parallel_reduce( + "ReduceFields", + domain->mesh.rangeActiveCells(), + kernel::ReducedFields_kernel(domain->fields.em, + domain->fields.cur, + domain->mesh.metric), + buffer); + } else { + raise::Error( + "Invalid component for B2, E2 or ExB stats: " + std::to_string(comp), + HERE); + } + } else { + raise::Error("ReduceFields not implemented for this stats ID + SimEngine " + "combination", + HERE); + } + return buffer; } @@ -174,31 +222,108 @@ namespace ntt { comp)); } } else if (stat.id() == StatsID::JdotE) { - g_stats_writer.write(ComputeFields(local_domain, {})); - } else if (stat.id() == StatsID::E2) { - g_stats_writer.write(ComputeFields(local_domain, {})); - } else if (stat.id() == StatsID::B2) { - g_stats_writer.write(ComputeFields(local_domain, {})); - } else if (stat.id() == StatsID::ExB) { - for (const auto& comp : stat.comp) { - g_stats_writer.write( - ComputeFields(local_domain, comp)); + g_stats_writer.write(ReduceFields(local_domain, {})); + } else if (S == SimEngine::SRPIC) { + if (stat.id() == StatsID::E2) { + for (const auto& comp : stat.comp) { + g_stats_writer.write( + ReduceFields(local_domain, comp)); + } + } else if (stat.id() == StatsID::B2) { + for (const auto& comp : stat.comp) { + g_stats_writer.write( + ReduceFields(local_domain, comp)); + } + } else if (stat.id() == StatsID::ExB) { + for (const auto& comp : stat.comp) { + g_stats_writer.write( + ReduceFields(local_domain, comp)); + } + } else { + raise::Error("Unrecognized stats ID " + stat.name(), HERE); } } else { - raise::Error("Unrecognized stats ID " + stat.name(), HERE); + raise::Error("StatsID not implemented for particular SimEngine: " + + std::to_string(static_cast(S)), + HERE); } } g_stats_writer.endWriting(); return true; } - template struct Metadomain>; - template struct Metadomain>; - template struct Metadomain>; - template struct Metadomain>; - template struct Metadomain>; - template struct Metadomain>; - template struct Metadomain>; - template struct Metadomain>; + template void Metadomain>::InitStatsWriter( + const SimulationParams&, + bool); + template void Metadomain>::InitStatsWriter( + const SimulationParams&, + bool); + template void Metadomain>::InitStatsWriter( + const SimulationParams&, + bool); + template void Metadomain>::InitStatsWriter( + const SimulationParams&, + bool); + template void Metadomain>::InitStatsWriter( + const SimulationParams&, + bool); + template void Metadomain>::InitStatsWriter( + const SimulationParams&, + bool); + template void Metadomain>::InitStatsWriter( + const SimulationParams&, + bool); + template void Metadomain>::InitStatsWriter( + const SimulationParams&, + bool); + + template auto Metadomain>::WriteStats( + const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t) -> bool; + template auto Metadomain>::WriteStats( + const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t) -> bool; + template auto Metadomain>::WriteStats( + const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t) -> bool; + template auto Metadomain>::WriteStats( + const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t) -> bool; + template auto Metadomain>::WriteStats( + const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t) -> bool; + template auto Metadomain>::WriteStats( + const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t) -> bool; + template auto Metadomain>::WriteStats( + const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t) -> bool; + template auto Metadomain>::WriteStats( + const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t) -> bool; } // namespace ntt diff --git a/src/global/enums.h b/src/global/enums.h index 7e06d4a8d..8796fe310 100644 --- a/src/global/enums.h +++ b/src/global/enums.h @@ -14,6 +14,8 @@ * - enum ntt::Cooling // synchrotron, none * - enum ntt::FldsID // e, dive, d, divd, b, h, j, * a, t, rho, charge, n, nppc, v, custom + * - enum ntt::StatsID // b^2, e^2, exb, j.e, t, rho, + * charge, n, npart * @namespaces: * - ntt:: * @note Enums of the same type can be compared with each other and with strings diff --git a/src/kernels/reduced_stats.hpp b/src/kernels/reduced_stats.hpp new file mode 100644 index 000000000..373f06eb0 --- /dev/null +++ b/src/kernels/reduced_stats.hpp @@ -0,0 +1,381 @@ +/** + * @file kernels/reduced_stats.hpp + * @brief Compute reduced field/moment quantities for stats output + * @implements + * - kernel::PrtlToPhys_kernel<> + * @namespaces: + * - kernel:: + */ + +#ifndef KERNELS_REDUCED_STATS_HPP +#define KERNELS_REDUCED_STATS_HPP + +#include "enums.h" +#include "global.h" + +#include "arch/kokkos_aliases.h" +#include "utils/numeric.h" + +namespace kernel { + using namespace ntt; + + template + class ReducedFields_kernel { + static_assert(M::is_metric, "M must be a metric class"); + static_assert(I <= 3, + "I must be less than or equal to 3 for ReducedFields_kernel"); + static constexpr auto D = M::Dim; + + ndfield_t EM; + ndfield_t J; + const M metric; + + public: + ReducedFields_kernel(const ndfield_t& EM, + const ndfield_t& J, + const M& metric) + : EM { EM } + , J { J } + , metric { metric } {} + + Inline void operator()(index_t i1, real_t& buff) const { + const auto i1_ = COORD(i1); + if constexpr (F == StatsID::B2) { + if constexpr (I == 1) { + const auto b1_u = EM(i1, em::bx1); + const auto b1_d = metric.template transform<1, Idx::U, Idx::D>({ i1_ }, + b1_u); + buff += b1_u * b1_d; + } else if constexpr (I == 2) { + const auto b2_u = EM(i1, em::bx2); + const auto b2_d = metric.template transform<2, Idx::U, Idx::D>( + { i1_ + HALF }, + b2_u); + buff += b2_u * b2_d; + } else { + const auto b3_u = EM(i1, em::bx3); + const auto b3_d = metric.template transform<3, Idx::U, Idx::D>( + { i1_ + HALF }, + b3_u); + buff += b3_u * b3_d; + } + } else if constexpr (F == StatsID::E2) { + if constexpr (I == 1) { + const auto e1_u = EM(i1, em::ex1); + const auto e1_d = metric.template transform<1, Idx::U, Idx::D>( + { i1_ + HALF }, + e1_u); + buff += e1_u * e1_d; + } else if constexpr (I == 2) { + const auto e2_u = EM(i1, em::ex2); + const auto e2_d = metric.template transform<2, Idx::U, Idx::D>({ i1_ }, + e2_u); + buff += e2_u * e2_d; + } else { + const auto e3_u = EM(i1, em::ex3); + const auto e3_d = metric.template transform<3, Idx::U, Idx::D>({ i1_ }, + e3_u); + buff += e3_u * e3_d; + } + } else if constexpr (F == StatsID::ExB) { + if constexpr (I == 1) { + const auto e2_t = metric.template transform<2, Idx::U, Idx::T>( + { i1_ + HALF }, + HALF * (EM(i1, em::ex2) + EM(i1 + 1, em::ex2))); + const auto e3_t = metric.template transform<3, Idx::U, Idx::T>( + { i1_ + HALF }, + HALF * (EM(i1, em::ex3) + EM(i1 + 1, em::ex3))); + const auto b2_t = metric.template transform<2, Idx::U, Idx::T>( + { i1_ + HALF }, + EM(i1, em::bx2)); + const auto b3_t = metric.template transform<3, Idx::U, Idx::T>( + { i1_ + HALF }, + EM(i1, em::bx3)); + buff += e2_t * b3_t - e3_t * b2_t; + } else if constexpr (I == 2) { + const auto e1_t = metric.template transform<1, Idx::U, Idx::T>( + { i1_ + HALF }, + EM(i1, em::ex1)); + const auto e3_t = metric.template transform<3, Idx::U, Idx::T>( + { i1_ + HALF }, + HALF * (EM(i1, em::ex3) + EM(i1 + 1, em::ex3))); + const auto b1_t = metric.template transform<1, Idx::U, Idx::T>( + { i1_ + HALF }, + HALF * (EM(i1, em::bx1) + EM(i1 + 1, em::bx1))); + const auto b3_t = metric.template transform<3, Idx::U, Idx::T>( + { i1_ + HALF }, + EM(i1, em::bx3)); + buff += e3_t * b1_t - e1_t * b3_t; + } else { + const auto e1_t = metric.template transform<1, Idx::U, Idx::T>( + { i1_ + HALF }, + EM(i1, em::ex1)); + const auto e2_t = metric.template transform<2, Idx::U, Idx::T>( + { i1_ + HALF }, + HALF * (EM(i1, em::ex2) + EM(i1 + 1, em::ex2))); + const auto b1_t = metric.template transform<1, Idx::U, Idx::T>( + { i1_ + HALF }, + HALF * (EM(i1, em::bx1) + EM(i1 + 1, em::bx1))); + const auto b2_t = metric.template transform<2, Idx::U, Idx::T>( + { i1_ + HALF }, + EM(i1, em::bx2)); + buff += e1_t * b2_t - e2_t * b1_t; + } + } else if constexpr (F == StatsID::JdotE) { + vec_t e_t { ZERO }; + vec_t j_t { ZERO }; + metric.template transform( + { i1_ + HALF }, + { EM(i1, em::ex1), + HALF * (EM(i1, em::ex2) + EM(i1 + 1, em::ex2)), + HALF * (EM(i1, em::ex3) + EM(i1 + 1, em::ex3)) }, + e_t); + metric.template transform( + { i1_ + HALF }, + { J(i1, cur::jx1), + HALF * (J(i1, cur::jx2) + J(i1 + 1, cur::jx2)), + HALF * (J(i1, cur::jx3) + J(i1 + 1, cur::jx3)) }, + j_t); + buff += e_t[0] * j_t[0] + e_t[1] * j_t[1] + e_t[2] * j_t[2]; + } + } + + Inline void operator()(index_t i1, index_t i2, real_t& buff) const { + const auto i1_ = COORD(i1); + const auto i2_ = COORD(i2); + if constexpr (F == StatsID::B2) { + if constexpr (I == 1) { + const auto b1_u = EM(i1, i2, em::bx1); + const auto b1_d = metric.template transform<1, Idx::U, Idx::D>( + { i1_, i2_ + HALF }, + b1_u); + buff += b1_u * b1_d; + } else if constexpr (I == 2) { + const auto b2_u = EM(i1, i2, em::bx2); + const auto b2_d = metric.template transform<2, Idx::U, Idx::D>( + { i1_ + HALF, i2_ }, + b2_u); + buff += b2_u * b2_d; + } else { + const auto b3_u = EM(i1, i2, em::bx3); + const auto b3_d = metric.template transform<3, Idx::U, Idx::D>( + { i1_ + HALF, i2_ + HALF }, + b3_u); + buff += b3_u * b3_d; + } + } else if constexpr (F == StatsID::E2) { + if constexpr (I == 1) { + const auto e1_u = EM(i1, i2, em::ex1); + const auto e1_d = metric.template transform<1, Idx::U, Idx::D>( + { i1_ + HALF, i2_ }, + e1_u); + buff += e1_u * e1_d; + } else if constexpr (I == 2) { + const auto e2_u = EM(i1, i2, em::ex2); + const auto e2_d = metric.template transform<2, Idx::U, Idx::D>( + { i1_, i2_ + HALF }, + e2_u); + buff += e2_u * e2_d; + } else { + const auto e3_u = EM(i1, i2, em::ex3); + const auto e3_d = metric.template transform<3, Idx::U, Idx::D>( + { i1_, i2_ }, + e3_u); + buff += e3_u * e3_d; + } + } else if constexpr (F == StatsID::ExB) { + if constexpr (I == 1) { + const auto e2_t = metric.template transform<2, Idx::U, Idx::T>( + { i1_ + HALF, i2_ + HALF }, + HALF * (EM(i1, i2, em::ex2) + EM(i1 + 1, i2, em::ex2))); + const auto e3_t = metric.template transform<3, Idx::U, Idx::T>( + { i1_ + HALF, i2_ + HALF }, + INV_4 * (EM(i1, i2, em::ex3) + EM(i1 + 1, i2, em::ex3) + + EM(i1, i2 + 1, em::ex3) + EM(i1 + 1, i2 + 1, em::ex3))); + const auto b2_t = metric.template transform<2, Idx::U, Idx::T>( + { i1_ + HALF, i2_ + HALF }, + HALF * (EM(i1, i2, em::bx2) + EM(i1, i2 + 1, em::bx2))); + const auto b3_t = metric.template transform<3, Idx::U, Idx::T>( + { i1_ + HALF, i2_ + HALF }, + EM(i1, i2, em::bx3)); + buff += e2_t * b3_t - e3_t * b2_t; + } else if constexpr (I == 2) { + const auto e1_t = metric.template transform<1, Idx::U, Idx::T>( + { i1_ + HALF, i2_ + HALF }, + HALF * (EM(i1, i2, em::ex1) + EM(i1, i2 + 1, em::ex1))); + const auto e3_t = metric.template transform<3, Idx::U, Idx::T>( + { i1_ + HALF, i2_ + HALF }, + INV_4 * (EM(i1, i2, em::ex3) + EM(i1 + 1, i2, em::ex3) + + EM(i1, i2 + 1, em::ex3) + EM(i1 + 1, i2 + 1, em::ex3))); + const auto b1_t = metric.template transform<1, Idx::U, Idx::T>( + { i1_ + HALF, i2_ + HALF }, + HALF * (EM(i1, i2, em::bx1) + EM(i1 + 1, i2, em::bx1))); + const auto b3_t = metric.template transform<3, Idx::U, Idx::T>( + { i1_ + HALF, i2_ + HALF }, + EM(i1, i2, em::bx3)); + buff += e3_t * b1_t - e1_t * b3_t; + } else { + const auto e1_t = metric.template transform<1, Idx::U, Idx::T>( + { i1_ + HALF, i2_ + HALF }, + HALF * (EM(i1, i2, em::ex1) + EM(i1, i2 + 1, em::ex1))); + const auto e2_t = metric.template transform<2, Idx::U, Idx::T>( + { i1_ + HALF, i2_ + HALF }, + HALF * (EM(i1, i2, em::ex2) + EM(i1 + 1, i2, em::ex2))); + const auto b1_t = metric.template transform<1, Idx::U, Idx::T>( + { i1_ + HALF, i2_ + HALF }, + HALF * (EM(i1, i2, em::bx1) + EM(i1 + 1, i2, em::bx1))); + const auto b2_t = metric.template transform<2, Idx::U, Idx::T>( + { i1_ + HALF, i2_ + HALF }, + HALF * (EM(i1, i2, em::bx2) + EM(i1, i2 + 1, em::bx2))); + buff += e1_t * b2_t - e2_t * b1_t; + } + } else if constexpr (F == StatsID::JdotE) { + vec_t e_t { ZERO }; + vec_t j_t { ZERO }; + metric.template transform( + { i1_ + HALF, i2_ + HALF }, + { HALF * (EM(i1, i2, em::ex1) + EM(i1, i2 + 1, em::ex1)), + HALF * (EM(i1, i2, em::ex2) + EM(i1 + 1, i2, em::ex2)), + INV_4 * (EM(i1, i2, em::ex3) + EM(i1 + 1, i2, em::ex3) + + EM(i1, i2 + 1, em::ex3) + EM(i1 + 1, i2 + 1, em::ex3)) }, + e_t); + metric.template transform( + { i1_ + HALF, i2_ + HALF }, + { HALF * (J(i1, i2, cur::jx1) + J(i1, i2 + 1, cur::jx1)), + HALF * (J(i1, i2, cur::jx2) + J(i1 + 1, i2, cur::jx2)), + INV_4 * (J(i1, i2, cur::jx3) + J(i1 + 1, i2, cur::jx3) + + J(i1, i2 + 1, cur::jx3) + J(i1 + 1, i2 + 1, cur::jx3)) }, + j_t); + buff += e_t[0] * j_t[0] + e_t[1] * j_t[1] + e_t[2] * j_t[2]; + } + } + + Inline void operator()(index_t i1, index_t i2, index_t i3, real_t& buff) const { + const auto i1_ = COORD(i1); + const auto i2_ = COORD(i2); + const auto i3_ = COORD(i3); + if constexpr (F == StatsID::B2) { + if constexpr (I == 1) { + const auto b1_u = EM(i1, i2, i3, em::bx1); + const auto b1_d = metric.template transform<1, Idx::U, Idx::D>( + { i1_, i2_ + HALF, i3_ + HALF }, + b1_u); + buff += b1_u * b1_d; + } else if constexpr (I == 2) { + const auto b2_u = EM(i1, i2, i3, em::bx2); + const auto b2_d = metric.template transform<2, Idx::U, Idx::D>( + { i1_ + HALF, i2_, i3_ + HALF }, + b2_u); + buff += b2_u * b2_d; + } else { + const auto b3_u = EM(i1, i2, i3, em::bx3); + const auto b3_d = metric.template transform<3, Idx::U, Idx::D>( + { i1_ + HALF, i2_ + HALF, i3_ }, + b3_u); + buff += b3_u * b3_d; + } + } else if constexpr (F == StatsID::E2) { + if constexpr (I == 1) { + const auto e1_u = EM(i1, i2, i3, em::ex1); + const auto e1_d = metric.template transform<1, Idx::U, Idx::D>( + { i1_ + HALF, i2_, i3_ }, + e1_u); + buff += e1_u * e1_d; + } else if constexpr (I == 2) { + const auto e2_u = EM(i1, i2, i3, em::ex2); + const auto e2_d = metric.template transform<2, Idx::U, Idx::D>( + { i1_, i2_ + HALF, i3_ }, + e2_u); + buff += e2_u * e2_d; + } else { + const auto e3_u = EM(i1, i2, i3, em::ex3); + const auto e3_d = metric.template transform<3, Idx::U, Idx::D>( + { i1_, i2_, i3_ + HALF }, + e3_u); + buff += e3_u * e3_d; + } + } else if constexpr (F == StatsID::ExB) { + if constexpr (I == 1) { + const auto e2_t = metric.template transform<2, Idx::U, Idx::T>( + { i1_ + HALF, i2_ + HALF, i3_ + HALF }, + INV_4 * + (EM(i1, i2, i3, em::ex2) + EM(i1 + 1, i2, i3, em::ex2) + + EM(i1, i2, i3 + 1, em::ex2) + EM(i1 + 1, i2, i3 + 1, em::ex2))); + const auto e3_t = metric.template transform<3, Idx::U, Idx::T>( + { i1_ + HALF, i2_ + HALF, i3_ + HALF }, + INV_4 * + (EM(i1, i2, i3, em::ex3) + EM(i1 + 1, i2, i3, em::ex3) + + EM(i1, i2 + 1, i3, em::ex3) + EM(i1 + 1, i2 + 1, i3, em::ex3))); + const auto b2_t = metric.template transform<2, Idx::U, Idx::T>( + { i1_ + HALF, i2_ + HALF, i3_ + HALF }, + HALF * (EM(i1, i2, i3, em::bx2) + EM(i1, i2 + 1, i3, em::bx2))); + const auto b3_t = metric.template transform<3, Idx::U, Idx::T>( + { i1_ + HALF, i2_ + HALF, i3_ + HALF }, + HALF * (EM(i1, i2, i3, em::bx3) + EM(i1, i2, i3 + 1, em::bx3))); + buff += e2_t * b3_t - e3_t * b2_t; + } else if constexpr (I == 2) { + const auto e1_t = metric.template transform<1, Idx::U, Idx::T>( + { i1_ + HALF, i2_ + HALF, i3_ + HALF }, + INV_4 * + (EM(i1, i2, i3, em::ex1) + EM(i1, i2 + 1, i3, em::ex1) + + EM(i1, i2, i3 + 1, em::ex1) + EM(i1, i2 + 1, i3 + 1, em::ex1))); + const auto e3_t = metric.template transform<3, Idx::U, Idx::T>( + { i1_ + HALF, i2_ + HALF, i3_ + HALF }, + INV_4 * + (EM(i1, i2, i3, em::ex3) + EM(i1 + 1, i2, i3, em::ex3) + + EM(i1, i2 + 1, i3, em::ex3) + EM(i1 + 1, i2 + 1, i3, em::ex3))); + const auto b1_t = metric.template transform<1, Idx::U, Idx::T>( + { i1_ + HALF, i2_ + HALF, i3_ + HALF }, + HALF * (EM(i1, i2, i3, em::bx1) + EM(i1 + 1, i2, i3, em::bx1))); + const auto b3_t = metric.template transform<3, Idx::U, Idx::T>( + { i1_ + HALF, i2_ + HALF, i3_ + HALF }, + HALF * (EM(i1, i2, i3, em::bx3) + EM(i1, i2, i3 + 1, em::bx3))); + buff += e3_t * b1_t - e1_t * b3_t; + } else { + const auto e1_t = metric.template transform<1, Idx::U, Idx::T>( + { i1_ + HALF, i2_ + HALF, i3_ + HALF }, + INV_4 * + (EM(i1, i2, i3, em::ex1) + EM(i1, i2 + 1, i3, em::ex1) + + EM(i1, i2, i3 + 1, em::ex1) + EM(i1, i2 + 1, i3 + 1, em::ex1))); + const auto e2_t = metric.template transform<2, Idx::U, Idx::T>( + { i1_ + HALF, i2_ + HALF, i3_ + HALF }, + INV_4 * + (EM(i1, i2, i3, em::ex2) + EM(i1 + 1, i2, i3, em::ex2) + + EM(i1, i2, i3 + 1, em::ex2) + EM(i1 + 1, i2, i3 + 1, em::ex2))); + const auto b1_t = metric.template transform<1, Idx::U, Idx::T>( + { i1_ + HALF, i2_ + HALF, i3_ + HALF }, + HALF * (EM(i1, i2, i3, em::bx1) + EM(i1 + 1, i2, i3, em::bx1))); + const auto b2_t = metric.template transform<2, Idx::U, Idx::T>( + { i1_ + HALF, i2_ + HALF, i3_ + HALF }, + HALF * (EM(i1, i2, i3, em::bx2) + EM(i1, i2 + 1, i3, em::bx2))); + buff += e1_t * b2_t - e2_t * b1_t; + } + } else if constexpr (F == StatsID::JdotE) { + vec_t e_t { ZERO }; + vec_t j_t { ZERO }; + metric.template transform( + { i1_ + HALF, i2_ + HALF, i3_ + HALF }, + { INV_4 * (EM(i1, i2, i3, em::ex1) + EM(i1, i2 + 1, i3, em::ex1) + + EM(i1, i2, i3 + 1, em::ex1) + EM(i1, i2 + 1, i3 + 1, em::ex1)), + INV_4 * (EM(i1, i2, i3, em::ex2) + EM(i1 + 1, i2, i3, em::ex2) + + EM(i1, i2, i3 + 1, em::ex2) + EM(i1 + 1, i2, i3 + 1, em::ex2)), + INV_4 * (EM(i1, i2, i3, em::ex3) + EM(i1 + 1, i2, i3, em::ex3) + + EM(i1, i2 + 1, i3, em::ex3) + EM(i1 + 1, i2 + 1, i3, em::ex3)) }, + e_t); + metric.template transform( + { i1_ + HALF, i2_ + HALF, i3_ + HALF }, + { INV_4 * (J(i1, i2, i3, cur::jx1) + J(i1, i2 + 1, i3, cur::jx1) + + J(i1, i2, i3 + 1, cur::jx1) + J(i1, i2 + 1, i3 + 1, cur::jx1)), + INV_4 * (J(i1, i2, i3, cur::jx2) + J(i1 + 1, i2, i3, cur::jx2) + + J(i1, i2, i3 + 1, cur::jx2) + J(i1 + 1, i2, i3 + 1, cur::jx2)), + INV_4 * (J(i1, i2, i3, cur::jx3) + J(i1 + 1, i2, i3, cur::jx3) + + J(i1, i2 + 1, i3, cur::jx3) + J(i1 + 1, i2 + 1, i3, cur::jx3)) }, + j_t); + buff += e_t[0] * j_t[0] + e_t[1] * j_t[1] + e_t[2] * j_t[2]; + } + } + }; + +} // namespace kernel + +#endif diff --git a/src/output/stats.cpp b/src/output/stats.cpp index ba3e85c40..68392dc0b 100644 --- a/src/output/stats.cpp +++ b/src/output/stats.cpp @@ -38,13 +38,13 @@ namespace stats { species = {}; } if (is_vector()) { - // always write all the ExB and V components + // always write all the E^2, B^2, ExB components comp = { { 1 }, { 2 }, { 3 } }; } else if (id() == StatsID::T) { // energy-momentum tensor comp = InterpretComponents({ name.substr(1, 1), name.substr(2, 1) }); } else { - // scalar (e.g., Rho, E^2, etc.) + // scalar (e.g., Rho, Npart, etc.) comp = {}; } } diff --git a/src/output/stats.h b/src/output/stats.h index c81b9b7b3..ddea9ad4c 100644 --- a/src/output/stats.h +++ b/src/output/stats.h @@ -3,10 +3,11 @@ * @brief Class defining the metadata necessary to prepare the stats for output * @implements * - out::OutputStats + * - out::Writer * @cpp: * - stats.cpp * @namespaces: - * - out:: + * - stats:: */ #ifndef OUTPUT_STATS_H @@ -16,10 +17,16 @@ #include "global.h" #include "utils/error.h" +#include "utils/formatting.h" #include "utils/tools.h" +#if defined(MPI_ENABLED) + #include "arch/mpi_aliases.h" + + #include +#endif + #include -#include #include #include @@ -47,7 +54,7 @@ namespace stats { [[nodiscard]] auto is_vector() const -> bool { - return id() == StatsID::ExB; + return id() == StatsID::ExB || id() == StatsID::E2 || id() == StatsID::B2; } [[nodiscard]] @@ -65,7 +72,11 @@ namespace stats { if (id() == StatsID::T) { tmp += m_name.substr(1, 2); } else if (is_vector()) { - tmp += "i"; + if (id() == StatsID::E2 || id() == StatsID::B2) { + tmp = fmt::format("%ci^2", tmp[0]); + } else { + tmp += "i"; + } } if (species.size() > 0) { tmp += "_"; @@ -101,16 +112,20 @@ namespace stats { // capitalize the first letter tmp[0] = std::toupper(tmp[0]); } - for (auto& c : comp[ci]) { - tmp += std::to_string(c); - } - if (species.size() > 0) { - tmp += "_"; - for (auto& s : species) { - tmp += std::to_string(s); + if (tmp == "E^2" or tmp == "B^2") { + tmp = fmt::format("%c%d^2", tmp[0], comp[ci][0]); + } else { + for (auto& c : comp[ci]) { + tmp += std::to_string(c); + } + if (species.size() > 0) { tmp += "_"; + for (auto& s : species) { + tmp += std::to_string(s); + tmp += "_"; + } + tmp.pop_back(); } - tmp.pop_back(); } return tmp; } @@ -145,16 +160,25 @@ namespace stats { template inline void write(const T& value) const { #if defined(MPI_ENABLED) - // @TODO: reduce + T tot_value = static_cast(0); + MPI_Reduce(&value, + &tot_value, + 1, + mpi::get_type(), + MPI_SUM, + MPI_ROOT_RANK, + MPI_COMM_WORLD); +#else + tot_value = value; #endif CallOnce( - [](auto& fname, auto& value) { + [](auto&& fname, auto&& value) { std::fstream StatsOut(fname, std::fstream::out | std::fstream::app); StatsOut << value << ","; StatsOut.close(); }, m_fname, - value); + tot_value); } void endWriting(); From 3f54fb1c003a8b7a638d7b4bdf31a9529bebcbd8 Mon Sep 17 00:00:00 2001 From: haykh Date: Tue, 6 May 2025 21:05:21 -0400 Subject: [PATCH 692/773] stats for Fields tested --- src/kernels/tests/CMakeLists.txt | 1 + src/kernels/tests/particle_moments.cpp | 9 +- src/kernels/tests/reduced_stats.cpp | 320 +++++++++++++++++++++++++ src/output/stats.h | 2 +- src/output/tests/stats.cpp | 6 +- 5 files changed, 329 insertions(+), 9 deletions(-) create mode 100644 src/kernels/tests/reduced_stats.cpp diff --git a/src/kernels/tests/CMakeLists.txt b/src/kernels/tests/CMakeLists.txt index 551f9012f..2702e0526 100644 --- a/src/kernels/tests/CMakeLists.txt +++ b/src/kernels/tests/CMakeLists.txt @@ -35,3 +35,4 @@ gen_test(prtl_bc) gen_test(flds_bc) gen_test(pusher) gen_test(ext_force) +gen_test(reduced_stats) diff --git a/src/kernels/tests/particle_moments.cpp b/src/kernels/tests/particle_moments.cpp index 25ed7d4d9..bef1592df 100644 --- a/src/kernels/tests/particle_moments.cpp +++ b/src/kernels/tests/particle_moments.cpp @@ -20,7 +20,6 @@ #include #include #include -#include #include using namespace ntt; @@ -56,7 +55,7 @@ void testParticleMoments(const std::vector& res, } else { extent = { ext[0], - {ZERO, constant::PI} + { ZERO, constant::PI } }; } @@ -106,8 +105,8 @@ void testParticleMoments(const std::vector& res, auto boundaries = boundaries_t {}; if constexpr (M::CoordType != Coord::Cart) { boundaries = { - {FldsBC::CUSTOM, FldsBC::CUSTOM}, - { FldsBC::AXIS, FldsBC::AXIS} + { FldsBC::CUSTOM, FldsBC::CUSTOM }, + { FldsBC::AXIS, FldsBC::AXIS } }; } @@ -286,4 +285,4 @@ auto main(int argc, char* argv[]) -> int { } Kokkos::finalize(); return 0; -} \ No newline at end of file +} diff --git a/src/kernels/tests/reduced_stats.cpp b/src/kernels/tests/reduced_stats.cpp new file mode 100644 index 000000000..4be11a2f7 --- /dev/null +++ b/src/kernels/tests/reduced_stats.cpp @@ -0,0 +1,320 @@ +#include "kernels/reduced_stats.hpp" + +#include "enums.h" +#include "global.h" + +#include "arch/kokkos_aliases.h" +#include "utils/comparators.h" +#include "utils/error.h" + +#include "metrics/minkowski.h" + +#include +#include +#include + +using namespace ntt; +using namespace metric; + +template +class Fill_kernel { + ndfield_t& arr; + real_t v; + unsigned short c; + +public: + Fill_kernel(ndfield_t& arr_, real_t v_, unsigned short c_) + : arr { arr_ } + , v { v_ } + , c { c_ } {} + + Inline void operator()(index_t i1) const { + arr(i1, c) = v; + } + + Inline void operator()(index_t i1, index_t i2) const { + arr(i1, i2, c) = v; + } + + Inline void operator()(index_t i1, index_t i2, index_t i3) const { + arr(i1, i2, i3, c) = v; + } +}; + +template +void put_value(ndfield_t& arr, real_t v, unsigned short c) { + range_t range; + if constexpr (D == Dim::_1D) { + range = { + { 0u, arr.extent(0) } + }; + } else if constexpr (D == Dim::_2D) { + range = { + { 0u, 0u }, + { arr.extent(0), arr.extent(1) } + }; + } else { + range = { + { 0u, 0u, 0u }, + { arr.extent(0), arr.extent(1), arr.extent(2) } + }; + } + Kokkos::parallel_for("Fill", range, Fill_kernel(arr, v, c)); +} + +inline static constexpr auto epsilon = std::numeric_limits::epsilon(); + +template +auto compute_field_stat(const M& metric, + const ndfield_t& em, + const ndfield_t& j, + const range_t& range, + ncells_t num_cells) -> real_t { + real_t buff = ZERO; + Kokkos::parallel_reduce("ReduceFields", + range, + kernel::ReducedFields_kernel(em, j, metric), + buff); + return buff / static_cast(num_cells); +} + +template +void testReducedStats(const std::vector& res, + const boundaries_t& ext, + const real_t acc = ONE) { + raise::ErrorIf(res.size() != M::Dim, "Invalid resolution size", HERE); + + M metric { res, ext, {} }; + + std::vector x_s, y_s, z_s; + + coord_t dummy { ZERO }; + std::vector values; + values.push_back(metric.template transform<1, Idx::T, Idx::U>(dummy, ONE)); + values.push_back(metric.template transform<2, Idx::T, Idx::U>(dummy, TWO)); + values.push_back(metric.template transform<3, Idx::T, Idx::U>(dummy, THREE)); + + values.push_back(metric.template transform<1, Idx::T, Idx::U>(dummy, FOUR * ONE)); + values.push_back(metric.template transform<2, Idx::T, Idx::U>(dummy, FOUR * TWO)); + values.push_back( + metric.template transform<3, Idx::T, Idx::U>(dummy, FOUR * THREE)); + + values.push_back(metric.template transform<1, Idx::T, Idx::U>(dummy, -ONE)); + values.push_back(metric.template transform<2, Idx::T, Idx::U>(dummy, -TWO)); + values.push_back(metric.template transform<3, Idx::T, Idx::U>(dummy, THREE)); + + values.push_back(metric.template transform<1, Idx::T, Idx::U>(dummy, FOUR)); + values.push_back(metric.template transform<2, Idx::T, Idx::U>(dummy, TWO)); + values.push_back(metric.template transform<3, Idx::T, Idx::U>(dummy, ONE)); + + ndfield_t EM; + ndfield_t J; + range_t cell_range; + ncells_t num_cells; + + if constexpr (M::Dim == Dim::_1D) { + EM = ndfield_t { "EM", res[0] + 2 * N_GHOSTS }; + J = ndfield_t { "J", res[0] + 2 * N_GHOSTS }; + cell_range = { N_GHOSTS, res[0] + N_GHOSTS }; + num_cells = res[0]; + + put_value(EM, values[0], em::ex1); + put_value(EM, values[1], em::ex2); + put_value(EM, values[2], em::ex3); + + put_value(EM, values[6], em::bx1); + put_value(EM, values[7], em::bx2); + put_value(EM, values[8], em::bx3); + + put_value(J, values[9], cur::jx1); + put_value(J, values[10], cur::jx2); + put_value(J, values[11], cur::jx3); + } else if constexpr (M::Dim == Dim::_2D) { + EM = ndfield_t { "EM", res[0] + 2 * N_GHOSTS, res[1] + 2 * N_GHOSTS }; + J = ndfield_t { "J", res[0] + 2 * N_GHOSTS, res[1] + 2 * N_GHOSTS }; + + cell_range = { + { N_GHOSTS, N_GHOSTS }, + { res[0] + N_GHOSTS, res[1] + N_GHOSTS } + }; + num_cells = res[0] * res[1]; + + put_value(EM, values[0], em::ex1); + put_value(EM, values[1], em::ex2); + put_value(EM, values[2], em::ex3); + + put_value(EM, values[6], em::bx1); + put_value(EM, values[7], em::bx2); + put_value(EM, values[8], em::bx3); + + put_value(J, values[9], cur::jx1); + put_value(J, values[10], cur::jx2); + put_value(J, values[11], cur::jx3); + } else { + EM = ndfield_t { "EM", + res[0] + 2 * N_GHOSTS, + res[1] + 2 * N_GHOSTS, + res[2] + 2 * N_GHOSTS }; + J = ndfield_t { "J", + res[0] + 2 * N_GHOSTS, + res[1] + 2 * N_GHOSTS, + res[2] + 2 * N_GHOSTS }; + + cell_range = { + { N_GHOSTS, N_GHOSTS, N_GHOSTS }, + { res[0] + N_GHOSTS, res[1] + N_GHOSTS, res[2] + N_GHOSTS } + }; + num_cells = res[0] * res[1] * res[2]; + + put_value(EM, values[0], em::ex1); + put_value(EM, values[1], em::ex2); + put_value(EM, values[2], em::ex3); + + put_value(EM, values[6], em::bx1); + put_value(EM, values[7], em::bx2); + put_value(EM, values[8], em::bx3); + + put_value(J, values[9], cur::jx1); + put_value(J, values[10], cur::jx2); + put_value(J, values[11], cur::jx3); + } + + { + const auto Ex_Sq = compute_field_stat(metric, + EM, + J, + cell_range, + num_cells); + printf("Ex_Sq: %.12e\n", Ex_Sq); + raise::ErrorIf(not cmp::AlmostEqual_host(Ex_Sq, (real_t)(1), acc * epsilon), + "Ex_Sq does not match expected value", + HERE); + } + + { + const auto Ey_Sq = compute_field_stat(metric, + EM, + J, + cell_range, + num_cells); + raise::ErrorIf(not cmp::AlmostEqual_host(Ey_Sq, (real_t)(4), acc * epsilon), + "Ey_Sq does not match expected value", + HERE); + } + + { + const auto Ez_Sq = compute_field_stat(metric, + EM, + J, + cell_range, + num_cells); + raise::ErrorIf(not cmp::AlmostEqual_host(Ez_Sq, (real_t)(9), acc * epsilon), + "Ez_Sq does not match expected value", + HERE); + } + + { + const auto Bx_Sq = compute_field_stat(metric, + EM, + J, + cell_range, + num_cells); + raise::ErrorIf(not cmp::AlmostEqual_host(Bx_Sq, (real_t)(1), acc * epsilon), + "Bx_Sq does not match expected value", + HERE); + } + + { + const auto By_Sq = compute_field_stat(metric, + EM, + J, + cell_range, + num_cells); + raise::ErrorIf(not cmp::AlmostEqual_host(By_Sq, (real_t)(4), acc * epsilon), + "By_Sq does not match expected value", + HERE); + } + + { + const auto Bz_Sq = compute_field_stat(metric, + EM, + J, + cell_range, + num_cells); + raise::ErrorIf(not cmp::AlmostEqual_host(Bz_Sq, (real_t)(9), acc * epsilon), + "Bz_Sq does not match expected value", + HERE); + } + + { + const auto ExB_x = compute_field_stat(metric, + EM, + J, + cell_range, + num_cells); + raise::ErrorIf(not cmp::AlmostEqual_host(ExB_x, (real_t)(12), acc * epsilon), + "ExB_x does not match expected value", + HERE); + } + + { + const auto ExB_y = compute_field_stat(metric, + EM, + J, + cell_range, + num_cells); + raise::ErrorIf(not cmp::AlmostEqual_host(ExB_y, (real_t)(-6), acc * epsilon), + "ExB_y does not match expected value", + HERE); + } + + { + const auto ExB_z = compute_field_stat(metric, + EM, + J, + cell_range, + num_cells); + raise::ErrorIf(not cmp::AlmostEqual_host(ExB_z, (real_t)(0), acc * epsilon), + "ExB_z does not match expected value", + HERE); + } + + { + const auto JdotE = compute_field_stat(metric, + EM, + J, + cell_range, + num_cells); + raise::ErrorIf(not cmp::AlmostEqual_host(JdotE, (real_t)(11), acc * epsilon), + "JdotE does not match expected value", + HERE); + } +} + +auto main(int argc, char* argv[]) -> int { + Kokkos::initialize(argc, argv); + + try { + using namespace ntt; + + const ncells_t nx = 100, ny = 123, nz = 52; + std::pair x_ext { -2.0, 2.0 }; + std::pair y_ext { 0.0, 4.92 }; + std::pair z_ext { 0.0, 2.08 }; + + testReducedStats>({ nx }, { x_ext }, 10); + testReducedStats>({ nx, ny }, + { x_ext, y_ext }, + 10); + testReducedStats>({ nx, ny, nz }, + { x_ext, y_ext, z_ext }, + 10); + + } catch (std::exception& e) { + std::cerr << e.what() << std::endl; + Kokkos::finalize(); + return 1; + } + Kokkos::finalize(); + return 0; +} diff --git a/src/output/stats.h b/src/output/stats.h index ddea9ad4c..fd4019b46 100644 --- a/src/output/stats.h +++ b/src/output/stats.h @@ -169,7 +169,7 @@ namespace stats { MPI_ROOT_RANK, MPI_COMM_WORLD); #else - tot_value = value; + T tot_value = value; #endif CallOnce( [](auto&& fname, auto&& value) { diff --git a/src/output/tests/stats.cpp b/src/output/tests/stats.cpp index db6730a89..04645cad7 100644 --- a/src/output/tests/stats.cpp +++ b/src/output/tests/stats.cpp @@ -14,12 +14,12 @@ auto main() -> int { try { { const auto e = OutputStats("E^2"); - raise::ErrorIf(e.is_vector(), "E^2 should not be a vector quantity", HERE); + raise::ErrorIf(not e.is_vector(), "E^2 should be a vector quantity", HERE); raise::ErrorIf(e.is_moment(), "E^2 should not be a moment", HERE); raise::ErrorIf(e.id() != StatsID::E2, "E^2 should have ID StatsID::E2", HERE); raise::ErrorIf(e.species.size() != 0, "E^2 should have no species", HERE); - raise::ErrorIf(e.comp.size() != 0, "E^2 should have no components", HERE); - raise::ErrorIf(e.name() != "E^2", "E^2 should have name `E^2`", HERE); + raise::ErrorIf(e.comp.size() != 3, "E^2 should have 3 components", HERE); + raise::ErrorIf(e.name() != "Ei^2", "E^2 should have name `Ei^2`", HERE); } { From fc2c046469080d7fec136c24ce3156cdf0a69783 Mon Sep 17 00:00:00 2001 From: haykh Date: Tue, 6 May 2025 21:16:41 -0400 Subject: [PATCH 693/773] disabled stats for non-Cart --- src/framework/domain/grid.h | 18 ++++++++++++++++++ src/framework/domain/stats.cpp | 8 +++++++- src/framework/parameters.cpp | 5 +++++ 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/src/framework/domain/grid.h b/src/framework/domain/grid.h index af5b6c8d5..87b21b1f5 100644 --- a/src/framework/domain/grid.h +++ b/src/framework/domain/grid.h @@ -130,6 +130,15 @@ namespace ntt { return m_resolution; } + [[nodiscard]] + auto num_active() const -> ncells_t { + ncells_t total_active = 1u; + for (const auto& res : m_resolution) { + total_active *= res; + } + return total_active; + } + [[nodiscard]] auto n_all(in i) const -> ncells_t { switch (i) { @@ -154,6 +163,15 @@ namespace ntt { return nall; } + [[nodiscard]] + auto num_all() const -> ncells_t { + ncells_t total_all = 1u; + for (const auto& res : n_all()) { + total_all *= res; + } + return total_all; + } + /* Ranges in the device execution space --------------------------------- */ /** * @brief Loop over all active cells (disregard ghost cells) diff --git a/src/framework/domain/stats.cpp b/src/framework/domain/stats.cpp index cf7613bdb..6fa41d52e 100644 --- a/src/framework/domain/stats.cpp +++ b/src/framework/domain/stats.cpp @@ -166,7 +166,8 @@ namespace ntt { HERE); } - return buffer; + // @TODO: not going to work for arbitrary metric + return buffer / static_cast(domain->mesh.num_active()); } template @@ -175,6 +176,11 @@ namespace ntt { timestep_t finished_step, simtime_t current_time, simtime_t finished_time) -> bool { + // @TODO: remove when stats are supported for all coordinate systems + raise::ErrorIf( + M::CoordType != Coord::Cart, + "Stats writing is only supported for Cartesian coordinates for now", + HERE); if (not(params.template get("output.stats.enable") and g_stats_writer.shouldWrite(finished_step, finished_time))) { return false; diff --git a/src/framework/parameters.cpp b/src/framework/parameters.cpp index 168640e1f..836d79fb5 100644 --- a/src/framework/parameters.cpp +++ b/src/framework/parameters.cpp @@ -873,6 +873,11 @@ namespace ntt { "gamma_rad", defaults::synchrotron::gamma_rad)); } + + // @TODO: disabling stats for non-Cartesian + if (coord_enum != Coord::Cart) { + set("output.stats.enable", false); + } } void SimulationParams::setSetupParams(const toml::value& toml_data) { From f50f62adbba886253a35ab3ab8fd3b02f0aa3f4e Mon Sep 17 00:00:00 2001 From: hayk Date: Tue, 13 May 2025 10:22:50 -0400 Subject: [PATCH 694/773] minor header include in tests --- src/framework/tests/comm_nompi.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/framework/tests/comm_nompi.cpp b/src/framework/tests/comm_nompi.cpp index f9581c1e1..c7646ef03 100644 --- a/src/framework/tests/comm_nompi.cpp +++ b/src/framework/tests/comm_nompi.cpp @@ -7,8 +7,6 @@ #include "arch/kokkos_aliases.h" #include "utils/numeric.h" -#include "framework/domain/comm_mpi.hpp" - #include #include From e25b9c51707abdc898239f130ba5cec10ef689e3 Mon Sep 17 00:00:00 2001 From: hayk Date: Tue, 13 May 2025 10:36:20 -0400 Subject: [PATCH 695/773] const in domain for injector --- src/archetypes/particle_injector.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/archetypes/particle_injector.h b/src/archetypes/particle_injector.h index d15036cf5..4f6a524f3 100644 --- a/src/archetypes/particle_injector.h +++ b/src/archetypes/particle_injector.h @@ -165,7 +165,7 @@ namespace arch { ~KeepConstantInjector() = default; auto ComputeAvgDensity(const SimulationParams& params, - Domain& domain) const -> real_t { + const Domain& domain) const -> real_t { const auto result = this->DeduceRegion(domain, probe_box); const auto should_probe = std::get<0>(result); if (not should_probe) { @@ -218,7 +218,7 @@ namespace arch { } auto ComputeNumInject(const SimulationParams& params, - Domain& domain, + const Domain& domain, real_t number_density, const boundaries_t& box) const -> std::tuple, array_t> override { From 435fa0f27871c4604f736b5a1a6d964035ebce8a Mon Sep 17 00:00:00 2001 From: hayk Date: Tue, 13 May 2025 12:53:29 -0400 Subject: [PATCH 696/773] setups -> pgens + external pgen support --- .vscode/.taplo.toml | 2 +- cmake/config.cmake | 38 ++- cmake/report.cmake | 2 +- {setups => pgens}/CMakeLists.txt | 13 +- .../magnetosphere/magnetosphere.py | 0 .../magnetosphere/magnetosphere.toml | 0 .../srpic => pgens}/magnetosphere/pgen.hpp | 0 {setups => pgens}/pgen.hpp | 0 {setups/srpic => pgens}/reconnection/pgen.hpp | 0 .../reconnection/reconnection.toml | 0 {setups/srpic => pgens}/shock/pgen.hpp | 0 .../legacy/shocktest => pgens/shock}/shock.py | 0 {setups/srpic => pgens}/shock/shock.toml | 0 {setups/srpic => pgens}/streaming/pgen.hpp | 0 .../srpic => pgens}/streaming/twostream.toml | 0 {setups/srpic => pgens}/streaming/weibel.toml | 0 {setups/srpic => pgens}/turbulence/pgen.hpp | 0 .../turbulence/turbulence.toml | 0 setups/grpic/pgen_grpic_example.hpp | 37 --- setups/legacy/em_vacuum/em_vacuum.py | 14 - setups/legacy/em_vacuum/em_vacuum.toml | 43 --- setups/legacy/em_vacuum/pgen.hpp | 108 ------- setups/legacy/example/pgen.hpp | 105 ------- setups/legacy/langmuir/langmuir.py | 17 -- setups/legacy/langmuir/langmuir.toml | 55 ---- setups/legacy/langmuir/pgen.hpp | 124 -------- setups/legacy/magnetar/magnetar.py | 9 - setups/legacy/magnetar/magnetar.toml | 108 ------- setups/legacy/magnetar/pgen.hpp | 281 ------------------ setups/legacy/magpump/pgen.hpp | 170 ----------- setups/legacy/rec-gravity/pgen.hpp | 174 ----------- setups/legacy/rec-gravity/rec-gravity.toml | 54 ---- setups/legacy/shocktest/pgen.hpp | 155 ---------- setups/legacy/shocktest/shock.toml | 69 ----- setups/legacy/spider/pgen.hpp | 38 --- setups/srpic/pgen_srpic_example.hpp | 39 --- setups/srpic/shock/shock.py | 75 ----- setups/tests/blob/blob.py | 62 ---- setups/tests/blob/blob.toml | 66 ---- setups/tests/blob/nparts.py | 38 --- setups/tests/blob/pgen.hpp | 103 ------- setups/tests/customout/customout.toml | 50 ---- setups/tests/customout/pgen.hpp | 86 ------ setups/tests/deposit/deposit-mink.toml | 71 ----- setups/tests/deposit/deposit-sr.toml | 71 ----- setups/tests/deposit/pgen.hpp | 113 ------- setups/tests/deposit/plot-mink.py | 62 ---- setups/tests/deposit/plot-sr.py | 29 -- setups/tests/deposit/run-mink.sh | 14 - setups/tests/injector/injector.toml | 62 ---- setups/tests/injector/pgen.hpp | 103 ------- src/CMakeLists.txt | 2 - src/archetypes/energy_dist.h | 23 +- 53 files changed, 45 insertions(+), 2640 deletions(-) rename {setups => pgens}/CMakeLists.txt (76%) rename {setups/srpic => pgens}/magnetosphere/magnetosphere.py (100%) rename {setups/srpic => pgens}/magnetosphere/magnetosphere.toml (100%) rename {setups/srpic => pgens}/magnetosphere/pgen.hpp (100%) rename {setups => pgens}/pgen.hpp (100%) rename {setups/srpic => pgens}/reconnection/pgen.hpp (100%) rename {setups/srpic => pgens}/reconnection/reconnection.toml (100%) rename {setups/srpic => pgens}/shock/pgen.hpp (100%) rename {setups/legacy/shocktest => pgens/shock}/shock.py (100%) rename {setups/srpic => pgens}/shock/shock.toml (100%) rename {setups/srpic => pgens}/streaming/pgen.hpp (100%) rename {setups/srpic => pgens}/streaming/twostream.toml (100%) rename {setups/srpic => pgens}/streaming/weibel.toml (100%) rename {setups/srpic => pgens}/turbulence/pgen.hpp (100%) rename {setups/srpic => pgens}/turbulence/turbulence.toml (100%) delete mode 100644 setups/grpic/pgen_grpic_example.hpp delete mode 100644 setups/legacy/em_vacuum/em_vacuum.py delete mode 100644 setups/legacy/em_vacuum/em_vacuum.toml delete mode 100644 setups/legacy/em_vacuum/pgen.hpp delete mode 100644 setups/legacy/example/pgen.hpp delete mode 100644 setups/legacy/langmuir/langmuir.py delete mode 100644 setups/legacy/langmuir/langmuir.toml delete mode 100644 setups/legacy/langmuir/pgen.hpp delete mode 100644 setups/legacy/magnetar/magnetar.py delete mode 100644 setups/legacy/magnetar/magnetar.toml delete mode 100644 setups/legacy/magnetar/pgen.hpp delete mode 100644 setups/legacy/magpump/pgen.hpp delete mode 100644 setups/legacy/rec-gravity/pgen.hpp delete mode 100644 setups/legacy/rec-gravity/rec-gravity.toml delete mode 100644 setups/legacy/shocktest/pgen.hpp delete mode 100644 setups/legacy/shocktest/shock.toml delete mode 100644 setups/legacy/spider/pgen.hpp delete mode 100644 setups/srpic/pgen_srpic_example.hpp delete mode 100644 setups/srpic/shock/shock.py delete mode 100644 setups/tests/blob/blob.py delete mode 100644 setups/tests/blob/blob.toml delete mode 100644 setups/tests/blob/nparts.py delete mode 100644 setups/tests/blob/pgen.hpp delete mode 100644 setups/tests/customout/customout.toml delete mode 100644 setups/tests/customout/pgen.hpp delete mode 100644 setups/tests/deposit/deposit-mink.toml delete mode 100644 setups/tests/deposit/deposit-sr.toml delete mode 100644 setups/tests/deposit/pgen.hpp delete mode 100644 setups/tests/deposit/plot-mink.py delete mode 100644 setups/tests/deposit/plot-sr.py delete mode 100755 setups/tests/deposit/run-mink.sh delete mode 100644 setups/tests/injector/injector.toml delete mode 100644 setups/tests/injector/pgen.hpp diff --git a/.vscode/.taplo.toml b/.vscode/.taplo.toml index 0bfa6bec9..c24ab0926 100644 --- a/.vscode/.taplo.toml +++ b/.vscode/.taplo.toml @@ -1,4 +1,4 @@ -include = ["input.example.toml", "setups/**/*.toml"] +include = ["input.example.toml", "pgens/**/*.toml"] exclude = [".taplo.toml"] [formatting] diff --git a/cmake/config.cmake b/cmake/config.cmake index 7214812cd..68b0db2ef 100644 --- a/cmake/config.cmake +++ b/cmake/config.cmake @@ -18,25 +18,47 @@ endfunction() # ---------------------------- Problem generator --------------------------- # function(set_problem_generator pgen_name) - file(GLOB_RECURSE PGENS "${CMAKE_CURRENT_SOURCE_DIR}/setups/**/pgen.hpp" - "${CMAKE_CURRENT_SOURCE_DIR}/setups/pgen.hpp") + if(pgen_name STREQUAL ".") + message(FATAL_ERROR "Problem generator not specified") + endif() + + file(GLOB_RECURSE PGENS "${CMAKE_CURRENT_SOURCE_DIR}/pgens/**/pgen.hpp" + "${CMAKE_CURRENT_SOURCE_DIR}/pgens/pgen.hpp") + foreach(PGEN ${PGENS}) get_filename_component(PGEN_NAME ${PGEN} DIRECTORY) - string(REPLACE "${CMAKE_CURRENT_SOURCE_DIR}/setups/" "" PGEN_NAME + string(REPLACE "${CMAKE_CURRENT_SOURCE_DIR}/pgens/" "" PGEN_NAME ${PGEN_NAME}) - string(REPLACE "${CMAKE_CURRENT_SOURCE_DIR}/setups" "" PGEN_NAME + string(REPLACE "${CMAKE_CURRENT_SOURCE_DIR}/pgens" "" PGEN_NAME ${PGEN_NAME}) list(APPEND PGEN_NAMES ${PGEN_NAME}) endforeach() + list(FIND PGEN_NAMES ${pgen_name} PGEN_FOUND) - if(NOT ${pgen_name} STREQUAL "." AND ${PGEN_FOUND} EQUAL -1) - message(FATAL_ERROR "Invalid problem generator: " - "${pgen_name}\nValid options are: ${PGEN_NAMES}") + + if(${PGEN_FOUND} EQUAL -1) + set(pgen_path ${pgen_name}) + get_filename_component(pgen_path ${pgen_path} ABSOLUTE) + string(REGEX REPLACE ".*/" "" pgen_name ${pgen_name}) + list(APPEND PGEN_NAMES ${pgen_name}) + else() + set(pgen_path ${CMAKE_CURRENT_SOURCE_DIR}/pgens/${pgen_name}) endif() + + file(GLOB_RECURSE PGEN_FILES "${pgen_path}/pgen.hpp") + if(NOT PGEN_FILES) + message(FATAL_ERROR "pgen.hpp file not found in ${pgen_path}") + endif() + + add_library(ntt_pgen INTERFACE) + target_link_libraries(ntt_pgen INTERFACE ntt_global ntt_framework + ntt_archetypes ntt_kernels) + + target_include_directories(ntt_pgen INTERFACE ${pgen_path}) + set(PGEN ${pgen_name} PARENT_SCOPE) - include_directories(${CMAKE_CURRENT_SOURCE_DIR}/setups/${pgen_name}) set(PGEN_FOUND TRUE PARENT_SCOPE) diff --git a/cmake/report.cmake b/cmake/report.cmake index b0e299d87..7bd623943 100644 --- a/cmake/report.cmake +++ b/cmake/report.cmake @@ -4,7 +4,7 @@ if(${PGEN_FOUND}) "pgen" "${problem_generators}" ${PGEN} - ${default_pgen} + "" "${Blue}" PGEN_REPORT 0) diff --git a/setups/CMakeLists.txt b/pgens/CMakeLists.txt similarity index 76% rename from setups/CMakeLists.txt rename to pgens/CMakeLists.txt index c92c1d345..e3d047a98 100644 --- a/setups/CMakeLists.txt +++ b/pgens/CMakeLists.txt @@ -3,17 +3,7 @@ # # @includes: # -# * ../ -# -# @depends: -# -# * ntt_pgen [required] -# -# @uses: -# -# * kokkos [required] -# * plog [required] -# * mpi [optional] +# * ../src/ # ------------------------------ add_library(ntt_pgen INTERFACE) @@ -22,4 +12,3 @@ target_link_libraries(ntt_pgen INTERFACE ntt_global ntt_framework target_include_directories(ntt_pgen INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/${PGEN}) - diff --git a/setups/srpic/magnetosphere/magnetosphere.py b/pgens/magnetosphere/magnetosphere.py similarity index 100% rename from setups/srpic/magnetosphere/magnetosphere.py rename to pgens/magnetosphere/magnetosphere.py diff --git a/setups/srpic/magnetosphere/magnetosphere.toml b/pgens/magnetosphere/magnetosphere.toml similarity index 100% rename from setups/srpic/magnetosphere/magnetosphere.toml rename to pgens/magnetosphere/magnetosphere.toml diff --git a/setups/srpic/magnetosphere/pgen.hpp b/pgens/magnetosphere/pgen.hpp similarity index 100% rename from setups/srpic/magnetosphere/pgen.hpp rename to pgens/magnetosphere/pgen.hpp diff --git a/setups/pgen.hpp b/pgens/pgen.hpp similarity index 100% rename from setups/pgen.hpp rename to pgens/pgen.hpp diff --git a/setups/srpic/reconnection/pgen.hpp b/pgens/reconnection/pgen.hpp similarity index 100% rename from setups/srpic/reconnection/pgen.hpp rename to pgens/reconnection/pgen.hpp diff --git a/setups/srpic/reconnection/reconnection.toml b/pgens/reconnection/reconnection.toml similarity index 100% rename from setups/srpic/reconnection/reconnection.toml rename to pgens/reconnection/reconnection.toml diff --git a/setups/srpic/shock/pgen.hpp b/pgens/shock/pgen.hpp similarity index 100% rename from setups/srpic/shock/pgen.hpp rename to pgens/shock/pgen.hpp diff --git a/setups/legacy/shocktest/shock.py b/pgens/shock/shock.py similarity index 100% rename from setups/legacy/shocktest/shock.py rename to pgens/shock/shock.py diff --git a/setups/srpic/shock/shock.toml b/pgens/shock/shock.toml similarity index 100% rename from setups/srpic/shock/shock.toml rename to pgens/shock/shock.toml diff --git a/setups/srpic/streaming/pgen.hpp b/pgens/streaming/pgen.hpp similarity index 100% rename from setups/srpic/streaming/pgen.hpp rename to pgens/streaming/pgen.hpp diff --git a/setups/srpic/streaming/twostream.toml b/pgens/streaming/twostream.toml similarity index 100% rename from setups/srpic/streaming/twostream.toml rename to pgens/streaming/twostream.toml diff --git a/setups/srpic/streaming/weibel.toml b/pgens/streaming/weibel.toml similarity index 100% rename from setups/srpic/streaming/weibel.toml rename to pgens/streaming/weibel.toml diff --git a/setups/srpic/turbulence/pgen.hpp b/pgens/turbulence/pgen.hpp similarity index 100% rename from setups/srpic/turbulence/pgen.hpp rename to pgens/turbulence/pgen.hpp diff --git a/setups/srpic/turbulence/turbulence.toml b/pgens/turbulence/turbulence.toml similarity index 100% rename from setups/srpic/turbulence/turbulence.toml rename to pgens/turbulence/turbulence.toml diff --git a/setups/grpic/pgen_grpic_example.hpp b/setups/grpic/pgen_grpic_example.hpp deleted file mode 100644 index f553ae849..000000000 --- a/setups/grpic/pgen_grpic_example.hpp +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef PROBLEM_GENERATOR_H -#define PROBLEM_GENERATOR_H - -#include "enums.h" -#include "global.h" - -#include "arch/traits.h" - -#include "archetypes/problem_generator.h" - -namespace user { - using namespace ntt; - - template - struct PGen : public ProblemGenerator { - // compatibility traits for the problem generator - static constexpr auto engines { traits::compatible_with::value }; - static constexpr auto metrics { - traits::compatible_with::value - }; - static constexpr auto dimensions { traits::compatible_with::value }; - - // for easy access to variables in the child class - using ProblemGenerator::D; - using ProblemGenerator::C; - using ProblemGenerator::params; - using ProblemGenerator::domain; - - inline PGen(SimulationParams& p, const Metadomain&) : - ProblemGenerator(p) {} - - inline PGen() {} - }; - -} // namespace user - -#endif diff --git a/setups/legacy/em_vacuum/em_vacuum.py b/setups/legacy/em_vacuum/em_vacuum.py deleted file mode 100644 index 13a62ea3b..000000000 --- a/setups/legacy/em_vacuum/em_vacuum.py +++ /dev/null @@ -1,14 +0,0 @@ -import nt2.read as nt2r -import matplotlib.pyplot as plt - -data = nt2r.Data("em_vacuum.h5") - - -def plot(ti): - fig = plt.figure(figsize=(10, 5), dpi=150) - ax = fig.add_subplot(121) - data.Bz.isel(t=ti).plot(ax=ax, cmap="BrBG") - ax = fig.add_subplot(122) - data.Ey.isel(t=ti).plot(ax=ax, cmap="RdBu_r") - for ax in fig.axes[::2]: - ax.set_aspect("equal") diff --git a/setups/legacy/em_vacuum/em_vacuum.toml b/setups/legacy/em_vacuum/em_vacuum.toml deleted file mode 100644 index 23381b1c6..000000000 --- a/setups/legacy/em_vacuum/em_vacuum.toml +++ /dev/null @@ -1,43 +0,0 @@ -[simulation] - name = "em_vacuum" - engine = "srpic" - runtime = 2.0 - -[grid] - resolution = [256, 512] - extent = [[-1.0, 1.0], [-2.0, 2.0]] - - [grid.metric] - metric = "minkowski" - - [grid.boundaries] - fields = [["PERIODIC"], ["PERIODIC"]] - particles = [["PERIODIC"], ["PERIODIC"]] - -[scales] - larmor0 = 0.1 - skindepth0 = 0.01 - -[algorithms] - - [algorithms.timestep] - CFL = 0.5 - -[particles] - ppc0 = 1.0 - -[setup] - amplitude = 1.0 - kx1 = 1 - kx2 = 1 - kx3 = 0 - -[output] - format = "hdf5" - interval_time = 0.1 - - [output.fields] - quantities = ["E", "B"] - -[diagnostics] - colored_stdout = true diff --git a/setups/legacy/em_vacuum/pgen.hpp b/setups/legacy/em_vacuum/pgen.hpp deleted file mode 100644 index 52368cbd8..000000000 --- a/setups/legacy/em_vacuum/pgen.hpp +++ /dev/null @@ -1,108 +0,0 @@ -#ifndef PROBLEM_GENERATOR_H -#define PROBLEM_GENERATOR_H - -#include "enums.h" -#include "global.h" - -#include "arch/kokkos_aliases.h" -#include "arch/traits.h" -#include "utils/comparators.h" -#include "utils/numeric.h" - -#include "archetypes/problem_generator.h" -#include "framework/domain/metadomain.h" - -namespace user { - using namespace ntt; - - template - struct InitFields { - InitFields(real_t a, real_t sx1, real_t sx2, real_t sx3, int k1, int k2, int k3) - : amplitude { a } - , kx1 { (sx1 > ZERO) ? (real_t)(constant::TWO_PI) * (real_t)k1 / sx1 : ZERO } - , kx2 { (sx2 > ZERO) ? (real_t)(constant::TWO_PI) * (real_t)k2 / sx2 : ZERO } - , kx3 { (sx3 > ZERO) ? (real_t)(constant::TWO_PI) * (real_t)k3 / sx3 : ZERO } - , kmag13 { math::sqrt(SQR(kx1) + SQR(kx3)) } - , kmag { math::sqrt(SQR(kx1) + SQR(kx2) + SQR(kx3)) } { - raise::ErrorIf(cmp::AlmostZero_host(kx1) and cmp::AlmostZero_host(kx3), - "kx1 and kx3 cannot be zero", - HERE); - } - - // B is in k x y - // E is in -k x B - - Inline auto arg(const coord_t& x_Ph) const -> real_t { - if constexpr (D == Dim::_1D) { - return kx1 * x_Ph[0]; - } else if constexpr (D == Dim::_2D) { - return kx1 * x_Ph[0] + kx2 * x_Ph[1]; - } else { - return kx1 * x_Ph[0] + kx2 * x_Ph[1] + kx3 * x_Ph[2]; - } - } - - Inline auto ex1(const coord_t& x_Ph) const -> real_t { - return -amplitude * kx1 * kx2 / (kmag13 * kmag) * math::sin(arg(x_Ph)); - } - - Inline auto ex2(const coord_t& x_Ph) const -> real_t { - return amplitude * (SQR(kx1) + SQR(kx3)) / (kmag13 * kmag) * - math::sin(arg(x_Ph)); - } - - Inline auto ex3(const coord_t& x_Ph) const -> real_t { - return -amplitude * kx3 * kx2 / (kmag13 * kmag) * math::sin(arg(x_Ph)); - } - - Inline auto bx1(const coord_t& x_Ph) const -> real_t { - return -amplitude * (kx3 / kmag13) * math::sin(arg(x_Ph)); - } - - // skipping bx2 - - Inline auto bx3(const coord_t& x_Ph) const -> real_t { - return amplitude * (kx1 / kmag13) * math::sin(arg(x_Ph)); - } - - private: - const real_t amplitude; - const real_t kx1, kx2, kx3, kmag13, kmag; - }; - - template - struct PGen : public arch::ProblemGenerator { - // compatibility traits for the problem generator - static constexpr auto engines = traits::compatible_with::value; - static constexpr auto metrics = traits::compatible_with::value; - static constexpr auto dimensions = - traits::compatible_with::value; - - // for easy access to variables in the child class - using arch::ProblemGenerator::D; - using arch::ProblemGenerator::C; - using arch::ProblemGenerator::params; - - const real_t amplitude; - const int kx1, kx2, kx3; - const real_t sx1, sx2, sx3; - InitFields init_flds; - - inline PGen(const SimulationParams& p, const Metadomain& global_domain) - : arch::ProblemGenerator { p } - , amplitude { params.template get("setup.amplitude", 1.0) } - , kx1 { params.template get("setup.kx1", 1) } - , kx2 { params.template get("setup.kx2", 0) } - , kx3 { params.template get("setup.kx3", 0) } - , sx1 { global_domain.mesh().extent(in::x1).second - - global_domain.mesh().extent(in::x1).first } - , sx2 { global_domain.mesh().extent(in::x2).second - - global_domain.mesh().extent(in::x2).first } - , sx3 { global_domain.mesh().extent(in::x3).second - - global_domain.mesh().extent(in::x3).first } - , init_flds { amplitude, sx1, sx2, sx3, kx1, kx2, kx3 } {} - }; - -} // namespace user - -#endif diff --git a/setups/legacy/example/pgen.hpp b/setups/legacy/example/pgen.hpp deleted file mode 100644 index cf6c12b7a..000000000 --- a/setups/legacy/example/pgen.hpp +++ /dev/null @@ -1,105 +0,0 @@ -#ifndef PROBLEM_GENERATOR_H -#define PROBLEM_GENERATOR_H - -#include "enums.h" -#include "global.h" - -#include "arch/kokkos_aliases.h" -#include "arch/traits.h" -#include "utils/numeric.h" - -#include "archetypes/problem_generator.h" -#include "framework/domain/metadomain.h" - -#include - -namespace user { - using namespace ntt; - - template - struct InitFields { - - InitFields(real_t a, real_t sx2, int kx2) - : amplitude { a } - , sx2 { sx2 } - , kx2 { kx2 } {} - - // only set ex2 and bx3 - - Inline auto ex2(const coord_t& x_Ph) const -> real_t { - return amplitude * math::sin(constant::TWO_PI * (x_Ph[1] / sx2) * - static_cast(kx2)); - } - - Inline auto bx3(const coord_t& x_Ph) const -> real_t { - return -amplitude * math::cos(constant::TWO_PI * (x_Ph[1] / sx2) * - static_cast(kx2)); - } - - private: - const real_t amplitude; - const real_t sx2; - const int kx2; - }; - - template - struct ExtForce { - const std::vector species { 1, 2 }; - - ExtForce() = default; - - Inline auto fx1(const spidx_t& sp, - const simtime_t& time, - const coord_t& x_Ph) const -> real_t { - (void)sp; - (void)time; - (void)x_Ph; - return ZERO; - } - - Inline auto fx2(const spidx_t& sp, - const simtime_t& time, - const coord_t& x_Ph) const -> real_t { - (void)sp; - (void)time; - (void)x_Ph; - return ZERO; - } - - Inline auto fx3(const spidx_t& sp, - const simtime_t& time, - const coord_t& x_Ph) const -> real_t { - (void)sp; - (void)time; - (void)x_Ph; - return ZERO; - } - }; - - template - struct PGen : public arch::ProblemGenerator { - // compatibility traits for the problem generator - static constexpr auto engines = traits::compatible_with::value; - static constexpr auto metrics = traits::compatible_with::value; - static constexpr auto dimensions = traits::compatible_with::value; - - // for easy access to variables in the child class - using arch::ProblemGenerator::D; - using arch::ProblemGenerator::C; - using arch::ProblemGenerator::params; - - InitFields init_flds; - ExtForce ext_force; - - inline PGen(const SimulationParams& p, const Metadomain& global_domain) - : arch::ProblemGenerator { p } - , init_flds { params.template get("setup.amplitude", 1.0), - global_domain.mesh().extent(in::x2).second - - global_domain.mesh().extent(in::x2).first, - params.template get("setup.kx2", 2) } - , ext_force {} {} - }; - -} // namespace user - -#endif diff --git a/setups/legacy/langmuir/langmuir.py b/setups/legacy/langmuir/langmuir.py deleted file mode 100644 index a880bc00b..000000000 --- a/setups/legacy/langmuir/langmuir.py +++ /dev/null @@ -1,17 +0,0 @@ -import nt2.read as nt2r -import matplotlib.pyplot as plt - -data = nt2r.Data("langmuir.h5") - - -def plot(ti, d): - # for 2D - fig = plt.figure(figsize=(10, 5), dpi=150) - ax = fig.add_subplot(211) - d.Rho.isel(t=ti).plot(ax=ax, cmap="inferno", vmin=0, vmax=4) - ax = fig.add_subplot(212) - d.Ex.isel(t=ti).plot(ax=ax, cmap="RdBu_r", vmin=-1, vmax=1) - for ax in fig.get_axes()[::2]: - ax.set_aspect("equal") - fig.get_axes()[0].set(xlabel="", xticks=[]) - fig.get_axes()[2].set(title=None) diff --git a/setups/legacy/langmuir/langmuir.toml b/setups/legacy/langmuir/langmuir.toml deleted file mode 100644 index b054a940d..000000000 --- a/setups/legacy/langmuir/langmuir.toml +++ /dev/null @@ -1,55 +0,0 @@ -[simulation] - name = "langmuir" - engine = "srpic" - runtime = 1.0 - -[grid] - resolution = [2048, 512] - extent = [[0.0, 1.0], [0.0, 0.25]] - - [grid.metric] - metric = "minkowski" - - [grid.boundaries] - fields = [["PERIODIC"], ["PERIODIC"]] - particles = [["PERIODIC"], ["PERIODIC"]] - -[scales] - larmor0 = 0.1 - skindepth0 = 0.01 - -[algorithms] - current_filters = 4 - - [algorithms.timestep] - CFL = 0.5 - -[particles] - ppc0 = 14.0 - - [[particles.species]] - label = "e-" - mass = 1.0 - charge = -1.0 - maxnpart = 1e7 - - [[particles.species]] - label = "e+" - mass = 1.0 - charge = 1.0 - maxnpart = 1e7 - -[setup] - vmax = 0.1 - nx1 = 4 - nx2 = 2 - -[output] - format = "hdf5" - interval_time = 0.0025 - - [output.fields] - quantities = ["Rho", "E"] - -[diagnostics] - colored_stdout = true diff --git a/setups/legacy/langmuir/pgen.hpp b/setups/legacy/langmuir/pgen.hpp deleted file mode 100644 index 28dbd24c5..000000000 --- a/setups/legacy/langmuir/pgen.hpp +++ /dev/null @@ -1,124 +0,0 @@ -#ifndef PROBLEM_GENERATOR_H -#define PROBLEM_GENERATOR_H - -#include "enums.h" -#include "global.h" - -#include "arch/kokkos_aliases.h" -#include "arch/traits.h" -#include "utils/numeric.h" - -#include "archetypes/energy_dist.h" -#include "archetypes/particle_injector.h" -#include "archetypes/problem_generator.h" -#include "framework/domain/domain.h" -#include "framework/domain/metadomain.h" - -namespace user { - using namespace ntt; - - template - struct SinEDist : public arch::EnergyDistribution { - SinEDist(const M& metric, - real_t v_max, - const std::vector& n, - const std::vector& s) - : arch::EnergyDistribution { metric } - , v_max { v_max } - , kx1 { s.size() > 0 ? static_cast(constant::TWO_PI) * - static_cast(n[0]) / s[0] - : ZERO } - , kx2 { s.size() > 1 ? static_cast(constant::TWO_PI) * - static_cast(n[1]) / s[1] - : ZERO } - , kx3 { s.size() > 2 ? static_cast(constant::TWO_PI) * - static_cast(n[2]) / s[2] - : ZERO } {} - - Inline void operator()(const coord_t& x_Ph, - vec_t& v, - spidx_t sp) const override { - if (sp == 1) { - const auto k = math::sqrt(SQR(kx1) + SQR(kx2) + SQR(kx3)); - if constexpr (M::Dim == Dim::_1D) { - v[0] = v_max * math::sin(kx1 * x_Ph[0]); - } else if constexpr (M::Dim == Dim::_2D) { - v[0] = v_max * kx1 / k * math::sin(kx1 * x_Ph[0] + kx2 * x_Ph[1]); - v[1] = v_max * kx2 / k * math::sin(kx1 * x_Ph[0] + kx2 * x_Ph[1]); - } else { - v[0] = v_max * kx1 / k * - math::sin(kx1 * x_Ph[0] + kx2 * x_Ph[1] + kx3 * x_Ph[2]); - v[1] = v_max * kx2 / k * - math::sin(kx1 * x_Ph[0] + kx2 * x_Ph[1] + kx3 * x_Ph[2]); - v[2] = v_max * kx3 / k * - math::sin(kx1 * x_Ph[0] + kx2 * x_Ph[1] + kx3 * x_Ph[2]); - } - } else { - v[0] = ZERO; - v[1] = ZERO; - v[2] = ZERO; - } - } - - private: - const real_t v_max, kx1, kx2, kx3; - }; - - template - struct PGen : public arch::ProblemGenerator { - - // compatibility traits for the problem generator - static constexpr auto engines = traits::compatible_with::value; - static constexpr auto metrics = traits::compatible_with::value; - static constexpr auto dimensions = - traits::compatible_with::value; - - // for easy access to variables in the child class - using arch::ProblemGenerator::D; - using arch::ProblemGenerator::C; - using arch::ProblemGenerator::params; - - const real_t sx1, sx2, sx3; - const real_t vmax; - const int nx1, nx2, nx3; - - std::vector svec; - std::vector nvec; - - inline PGen(const SimulationParams& p, const Metadomain& global_domain) - : arch::ProblemGenerator { p } - , sx1 { global_domain.mesh().extent(in::x1).second - - global_domain.mesh().extent(in::x1).first } - , sx2 { global_domain.mesh().extent(in::x2).second - - global_domain.mesh().extent(in::x2).first } - , sx3 { global_domain.mesh().extent(in::x3).second - - global_domain.mesh().extent(in::x3).first } - , vmax { p.get("setup.vmax", 0.01) } - , nx1 { p.get("setup.nx1", 10) } - , nx2 { p.get("setup.nx2", 10) } - , nx3 { p.get("setup.nx3", 10) } { - const auto sxs = std::vector { sx1, sx2, sx3 }; - const auto nxs = std::vector { nx1, nx2, nx3 }; - for (auto d = 0u; d < M::Dim; ++d) { - svec.push_back(sxs[d]); - nvec.push_back(nxs[d]); - } - } - - inline void InitPrtls(Domain& local_domain) { - const auto energy_dist = SinEDist(local_domain.mesh.metric, - vmax, - nvec, - svec); - const auto injector = arch::UniformInjector(energy_dist, - { 1, 2 }); - arch::InjectUniform>(params, - local_domain, - injector, - 1.0); - } - }; - -} // namespace user - -#endif diff --git a/setups/legacy/magnetar/magnetar.py b/setups/legacy/magnetar/magnetar.py deleted file mode 100644 index 0bbf790e5..000000000 --- a/setups/legacy/magnetar/magnetar.py +++ /dev/null @@ -1,9 +0,0 @@ -import nt2.read as nt2r -import matplotlib as mpl - -data = nt2r.Data("magnetar.h5") - -def plot (ti, data): - (data.Bph*(data.r*np.sin(data.th))).isel(t=ti).polar.pcolor( - norm=mpl.colors.Normalize(vmin=-0.075, vmax=0.075), - cmap="PuOr") \ No newline at end of file diff --git a/setups/legacy/magnetar/magnetar.toml b/setups/legacy/magnetar/magnetar.toml deleted file mode 100644 index fab2eb01c..000000000 --- a/setups/legacy/magnetar/magnetar.toml +++ /dev/null @@ -1,108 +0,0 @@ -[simulation] - name = "magnetar" - engine = "srpic" - runtime = 50.0 - -[grid] - resolution = [2048, 1024] - extent = [[1.0, 400.0]] - - [grid.metric] - metric = "qspherical" - - [grid.boundaries] - fields = [["ATMOSPHERE", "ABSORB"]] - particles = [["ATMOSPHERE", "ABSORB"]] - - [grid.boundaries.absorb] - ds = 1.0 - - [grid.boundaries.atmosphere] - temperature = 0.1 - density = 40.0 - height = 0.02 - species = [1, 2] - ds = 0.5 - -[scales] - larmor0 = 1e-5 - skindepth0 = 0.01 - -[algorithms] - current_filters = 4 - - [algorithms.timestep] - CFL = 0.5 - - [algorithms.gca] - e_ovr_b_max = 0.9 - larmor_max = 100.0 - -[particles] - ppc0 = 4.0 - use_weights = true - clear_interval = 100 - - [[particles.species]] - label = "e-" - mass = 1.0 - charge = -1.0 - maxnpart = 5e7 - pusher = "Boris,GCA" - - [[particles.species]] - label = "e+" - mass = 1.0 - charge = 1.0 - maxnpart = 5e7 - pusher = "Boris,GCA" - - [[particles.species]] - label = "e-" - mass = 1.0 - charge = -1.0 - maxnpart = 5e7 - pusher = "Boris,GCA" - - [[particles.species]] - label = "e+" - mass = 1.0 - charge = 1.0 - maxnpart = 5e7 - pusher = "Boris,GCA" - - [[particles.species]] - label = "e-" - mass = 1.0 - charge = -1.0 - maxnpart = 5e7 - pusher = "Boris,GCA" - - [[particles.species]] - label = "e+" - mass = 1.0 - charge = 1.0 - maxnpart = 5e7 - pusher = "Boris,GCA" - -[setup] - Bsurf = 1.0 - omega = 0.0125 - pp_thres = 10.0 - gamma_pairs = 1.75 - -[output] - format = "hdf5" - - [output.fields] - interval_time = 0.5 - quantities = ["N_1", "N_2", "N_3", "N_4", "N_5", "N_6", "B", "E", "J"] - - [output.particles] - enable = false - - [output.spectra] - enable = false - -[diagnostics] - interval = 1 diff --git a/setups/legacy/magnetar/pgen.hpp b/setups/legacy/magnetar/pgen.hpp deleted file mode 100644 index 10f98ea5d..000000000 --- a/setups/legacy/magnetar/pgen.hpp +++ /dev/null @@ -1,281 +0,0 @@ -#ifndef PROBLEM_GENERATOR_H -#define PROBLEM_GENERATOR_H - -#include "enums.h" -#include "global.h" - -#include "arch/kokkos_aliases.h" -#include "arch/traits.h" -#include "utils/numeric.h" - -#include "archetypes/particle_injector.h" -#include "archetypes/problem_generator.h" -#include "framework/domain/metadomain.h" - -namespace user { - using namespace ntt; - - template - struct InitFields { - InitFields(real_t bsurf, real_t rstar) : Bsurf { bsurf }, Rstar { rstar } {} - - Inline auto bx1(const coord_t& x_Ph) const -> real_t { - return Bsurf * math::cos(x_Ph[1]) / CUBE(x_Ph[0] / Rstar); - } - - Inline auto bx2(const coord_t& x_Ph) const -> real_t { - return Bsurf * HALF * math::sin(x_Ph[1]) / CUBE(x_Ph[0] / Rstar); - } - - private: - const real_t Bsurf, Rstar; - }; - - template - struct DriveFields : public InitFields { - DriveFields(real_t time, real_t bsurf, real_t rstar, real_t omega) - : InitFields { bsurf, rstar } - , time { time } - , Omega { omega } {} - - using InitFields::bx1; - using InitFields::bx2; - - Inline auto bx3(const coord_t&) const -> real_t { - return ZERO; - } - - Inline auto ex1(const coord_t& x_Ph) const -> real_t { - auto sigma = (x_Ph[1] - HALF * constant::PI) / - (static_cast(0.2) * constant::PI); - return Omega * bx2(x_Ph) * x_Ph[0] * math::sin(x_Ph[1]) * sigma * - math::exp((ONE - SQR(SQR(sigma))) * INV_4); - } - - Inline auto ex2(const coord_t& x_Ph) const -> real_t { - auto sigma = (x_Ph[1] - HALF * constant::PI) / - (static_cast(0.2) * constant::PI); - return -Omega * bx1(x_Ph) * x_Ph[0] * math::sin(x_Ph[1]) * sigma * - math::exp((ONE - SQR(SQR(sigma))) * INV_4); - } - - Inline auto ex3(const coord_t&) const -> real_t { - return ZERO; - } - - private: - const real_t time, Omega; - }; - - template - struct PGen : public arch::ProblemGenerator { - // compatibility traits for the problem generator - static constexpr auto engines { traits::compatible_with::value }; - static constexpr auto metrics { - traits::compatible_with::value - }; - static constexpr auto dimensions { traits::compatible_with::value }; - - // for easy access to variables in the child class - using arch::ProblemGenerator::D; - using arch::ProblemGenerator::C; - using arch::ProblemGenerator::params; - - const Metadomain& global_domain; - - const real_t Bsurf, Rstar, Omega, gamma_pairs, pp_thres; - InitFields init_flds; - - inline PGen(const SimulationParams& p, const Metadomain& m) - : arch::ProblemGenerator(p) - , global_domain { m } - , Bsurf { p.template get("setup.Bsurf", ONE) } - , Rstar { m.mesh().extent(in::x1).first } - , Omega { p.template get("setup.omega") } - , pp_thres { p.template get("setup.pp_thres") } - , gamma_pairs { p.template get("setup.gamma_pairs") } - , init_flds { Bsurf, Rstar } {} - - inline PGen() {} - - auto AtmFields(real_t time) const -> DriveFields { - const real_t omega_t = - Omega * - ((ONE - math::tanh((static_cast(5.0) - time) * HALF)) * - (ONE + (-ONE + math::tanh((static_cast(45.0) - time) * HALF)) * - HALF)) * - HALF; - return DriveFields { time, Bsurf, Rstar, omega_t }; - } - - auto MatchFields(real_t) const -> InitFields { - return InitFields { Bsurf, Rstar }; - } - - void CustomPostStep(std::size_t, long double, Domain& domain) { - - // Ad-hoc PP kernel - { - - auto& species2_e = domain.species[2]; - auto& species2_p = domain.species[3]; - auto& species3_e = domain.species[4]; - auto& species3_p = domain.species[5]; - auto metric = domain.mesh.metric; - auto pp_thres_ = this->pp_thres; - auto gamma_pairs_ = this->gamma_pairs; - - for (std::size_t s { 0 }; s < 6; ++s) { - if (s == 1) { - continue; - } - - array_t elec_ind("elec_ind"); - array_t pos_ind("pos_ind"); - - auto offset_e = species3_e.npart(); - auto offset_p = species3_p.npart(); - - auto ux1_e = species3_e.ux1; - auto ux2_e = species3_e.ux2; - auto ux3_e = species3_e.ux3; - auto i1_e = species3_e.i1; - auto i2_e = species3_e.i2; - auto dx1_e = species3_e.dx1; - auto dx2_e = species3_e.dx2; - auto phi_e = species3_e.phi; - auto weight_e = species3_e.weight; - auto tag_e = species3_e.tag; - - auto ux1_p = species3_p.ux1; - auto ux2_p = species3_p.ux2; - auto ux3_p = species3_p.ux3; - auto i1_p = species3_p.i1; - auto i2_p = species3_p.i2; - auto dx1_p = species3_p.dx1; - auto dx2_p = species3_p.dx2; - auto phi_p = species3_p.phi; - auto weight_p = species3_p.weight; - auto tag_p = species3_p.tag; - - if (s == 0) { - - offset_e = species2_e.npart(); - offset_p = species2_p.npart(); - - ux1_e = species2_e.ux1; - ux2_e = species2_e.ux2; - ux3_e = species2_e.ux3; - i1_e = species2_e.i1; - i2_e = species2_e.i2; - dx1_e = species2_e.dx1; - dx2_e = species2_e.dx2; - phi_e = species2_e.phi; - weight_e = species2_e.weight; - tag_e = species2_e.tag; - - ux1_p = species2_p.ux1; - ux2_p = species2_p.ux2; - ux3_p = species2_p.ux3; - i1_p = species2_p.i1; - i2_p = species2_p.i2; - dx1_p = species2_p.dx1; - dx2_p = species2_p.dx2; - phi_p = species2_p.phi; - weight_p = species2_p.weight; - tag_p = species2_p.tag; - } - - auto& species = domain.species[s]; - auto ux1 = species.ux1; - auto ux2 = species.ux2; - auto ux3 = species.ux3; - auto i1 = species.i1; - auto i2 = species.i2; - auto dx1 = species.dx1; - auto dx2 = species.dx2; - auto phi = species.phi; - auto weight = species.weight; - auto tag = species.tag; - - Kokkos::parallel_for( - "InjectPairs", - species.rangeActiveParticles(), - Lambda(index_t p) { - if (tag(p) == ParticleTag::dead) { - return; - } - - auto px = ux1(p); - auto py = ux2(p); - auto pz = ux3(p); - auto gamma = math::sqrt(ONE + SQR(px) + SQR(py) + SQR(pz)); - - const coord_t xCd { static_cast(i1(p)) + dx1(p), - static_cast(i2(p)) + dx2(p) }; - - coord_t xPh { ZERO }; - metric.template convert(xCd, xPh); - - if ((gamma > pp_thres_) && (math::sin(xPh[1]) > 0.1)) { - - auto new_gamma = gamma - 2.0 * gamma_pairs_; - auto new_fac = math::sqrt(SQR(new_gamma) - 1.0) / - math::sqrt(SQR(gamma) - 1.0); - auto pair_fac = math::sqrt(SQR(gamma_pairs_) - 1.0) / - math::sqrt(SQR(gamma) - 1.0); - - auto elec_p = Kokkos::atomic_fetch_add(&elec_ind(), 1); - auto pos_p = Kokkos::atomic_fetch_add(&pos_ind(), 1); - - i1_e(elec_p + offset_e) = i1(p); - dx1_e(elec_p + offset_e) = dx1(p); - i2_e(elec_p + offset_e) = i2(p); - dx2_e(elec_p + offset_e) = dx2(p); - phi_e(elec_p + offset_e) = phi(p); - ux1_e(elec_p + offset_e) = px * pair_fac; - ux2_e(elec_p + offset_e) = py * pair_fac; - ux3_e(elec_p + offset_e) = pz * pair_fac; - weight_e(elec_p + offset_e) = weight(p); - tag_e(elec_p + offset_e) = ParticleTag::alive; - - i1_p(pos_p + offset_p) = i1(p); - dx1_p(pos_p + offset_p) = dx1(p); - i2_p(pos_p + offset_p) = i2(p); - dx2_p(pos_p + offset_p) = dx2(p); - phi_p(pos_p + offset_p) = phi(p); - ux1_p(pos_p + offset_p) = px * pair_fac; - ux2_p(pos_p + offset_p) = py * pair_fac; - ux3_p(pos_p + offset_p) = pz * pair_fac; - weight_p(pos_p + offset_p) = weight(p); - tag_p(pos_p + offset_p) = ParticleTag::alive; - - ux1(p) *= new_fac; - ux2(p) *= new_fac; - ux3(p) *= new_fac; - } - }); - - auto elec_ind_h = Kokkos::create_mirror(elec_ind); - Kokkos::deep_copy(elec_ind_h, elec_ind); - if (s == 0) { - species2_e.set_npart(offset_e + elec_ind_h()); - } else { - species3_e.set_npart(offset_e + elec_ind_h()); - } - - auto pos_ind_h = Kokkos::create_mirror(pos_ind); - Kokkos::deep_copy(pos_ind_h, pos_ind); - if (s == 0) { - species2_p.set_npart(offset_p + pos_ind_h()); - } else { - species3_p.set_npart(offset_p + pos_ind_h()); - } - } - } // Ad-hoc PP kernel - } - }; - -} // namespace user - -#endif diff --git a/setups/legacy/magpump/pgen.hpp b/setups/legacy/magpump/pgen.hpp deleted file mode 100644 index 045552aff..000000000 --- a/setups/legacy/magpump/pgen.hpp +++ /dev/null @@ -1,170 +0,0 @@ -#ifndef PROBLEM_GENERATOR_H -#define PROBLEM_GENERATOR_H - -#include "enums.h" -#include "global.h" - -#include "arch/traits.h" - -#include "archetypes/particle_injector.h" -#include "archetypes/problem_generator.h" -#include "framework/domain/metadomain.h" - -#include - -namespace user { - using namespace ntt; - - template - struct InitFields { - InitFields(real_t bsurf, real_t rstar) : Bsurf { bsurf }, Rstar { rstar } {} - - Inline auto bx1(const coord_t& x_Ph) const -> real_t { - return Bsurf * math::cos(x_Ph[1]) / CUBE(x_Ph[0] / Rstar); - } - - Inline auto bx2(const coord_t& x_Ph) const -> real_t { - return Bsurf * HALF * math::sin(x_Ph[1]) / CUBE(x_Ph[0] / Rstar); - } - - private: - const real_t Bsurf, Rstar; - }; - - template - struct DriveFields : public InitFields { - DriveFields(real_t time, real_t bsurf, real_t rstar) - : InitFields { bsurf, rstar } - , time { time } {} - - using InitFields::bx1; - using InitFields::bx2; - - Inline auto bx3(const coord_t&) const -> real_t { - return ZERO; - } - - Inline auto ex1(const coord_t&) const -> real_t { - return ZERO; - } - - Inline auto ex2(const coord_t& x_Ph) const -> real_t { - return ZERO; - } - - Inline auto ex3(const coord_t&) const -> real_t { - return ZERO; - } - - private: - const real_t time; - }; - - template - struct Inflow : public arch::EnergyDistribution { - Inflow(const M& metric, real_t vin) - : arch::EnergyDistribution { metric } - , vin { vin } {} - - Inline void operator()(const coord_t&, - vec_t& v_Ph, - spidx_t) const override { - v_Ph[0] = -vin; - } - - private: - const real_t vin; - }; - - template - struct Sphere : public arch::SpatialDistribution { - Sphere(const M& metric, real_t r0, real_t dr) - : arch::SpatialDistribution { metric } - , r0 { r0 } - , dr { dr } {} - - Inline auto operator()(const coord_t& x_Ph) const -> real_t override { - return math::exp(-SQR((x_Ph[0] - r0) / dr)) * - (x_Ph[1] > 0.25 && x_Ph[1] < constant::PI - 0.25); - } - - private: - const real_t r0, dr; - }; - - template - struct PGen : public arch::ProblemGenerator { - static constexpr auto engines { traits::compatible_with::value }; - static constexpr auto metrics { - traits::compatible_with::value - }; - static constexpr auto dimensions { traits::compatible_with::value }; - - using arch::ProblemGenerator::D; - using arch::ProblemGenerator::C; - using arch::ProblemGenerator::params; - - const real_t Bsurf, pump_period, pump_ampl, pump_radius, Rstar; - const real_t vin, drinj; - InitFields init_flds; - - inline PGen(const SimulationParams& p, const Metadomain& m) - : arch::ProblemGenerator { p } - , Bsurf { p.template get("setup.Bsurf", ONE) } - , pump_period { p.template get("setup.pump_period") } - , pump_ampl { p.template get("setup.pump_ampl") } - , pump_radius { p.template get("setup.pump_radius") } - , Rstar { m.mesh().extent(in::x1).first } - , vin { p.template get("setup.vin") } - , drinj { p.template get("setup.drinj") } - , init_flds { Bsurf, Rstar } {} - - auto FieldDriver(real_t time) const -> DriveFields { - return DriveFields { time, Bsurf, Rstar }; - } - - void CustomPostStep(std::size_t, long double time, Domain& domain) { - const real_t radius = pump_radius + - pump_ampl * - math::sin(time * constant::TWO_PI / pump_period); - const real_t dr = 1.0; - const auto& metric = domain.mesh.metric; - auto EM = domain.fields.em; - Kokkos::parallel_for( - "outerBC", - domain.mesh.rangeActiveCells(), - Lambda(index_t i1, index_t i2) { - const auto i1_ = COORD(i1), i2_ = COORD(i2); - const auto r = metric.template convert<1, Crd::Cd, Crd::Ph>(i1_); - if (r > radius - 5 * dr) { - const auto smooth = HALF * (ONE - math::tanh((r - radius) / dr)); - EM(i1, i2, em::ex1) = smooth * EM(i1, i2, em::ex1); - EM(i1, i2, em::ex2) = smooth * EM(i1, i2, em::ex2); - EM(i1, i2, em::ex3) = smooth * EM(i1, i2, em::ex3); - EM(i1, i2, em::bx1) = smooth * EM(i1, i2, em::bx1); - EM(i1, i2, em::bx2) = smooth * EM(i1, i2, em::bx2); - EM(i1, i2, em::bx3) = smooth * EM(i1, i2, em::bx3); - } - }); - - if (time < pump_period * 0.25) { - const auto energy_dist = Inflow(domain.mesh.metric, vin); - const auto spatial_dist = Sphere(domain.mesh.metric, radius, drinj); - const auto injector = arch::NonUniformInjector( - energy_dist, - spatial_dist, - { 1, 2 }); - - arch::InjectNonUniform>( - params, - domain, - injector, - ONE, - true); - } - } - }; - -} // namespace user - -#endif diff --git a/setups/legacy/rec-gravity/pgen.hpp b/setups/legacy/rec-gravity/pgen.hpp deleted file mode 100644 index e8c461418..000000000 --- a/setups/legacy/rec-gravity/pgen.hpp +++ /dev/null @@ -1,174 +0,0 @@ -#ifndef PROBLEM_GENERATOR_H -#define PROBLEM_GENERATOR_H - -#include "enums.h" -#include "global.h" - -#include "arch/directions.h" -#include "arch/kokkos_aliases.h" -#include "arch/traits.h" -#include "utils/numeric.h" - -#include "archetypes/energy_dist.h" -#include "archetypes/particle_injector.h" -#include "archetypes/problem_generator.h" -#include "archetypes/spatial_dist.h" -#include "framework/domain/metadomain.h" - -namespace user { - using namespace ntt; - - template - struct Gravity { - const std::vector species { 1, 2 }; - - Gravity(real_t f, real_t tscale, real_t ymid) - : force { f } - , tscale { tscale } - , ymid { ymid } {} - - Inline auto fx1(const spidx_t&, const simtime_t&, const coord_t&) const - -> real_t { - return ZERO; - } - - Inline auto fx2(const spidx_t&, const simtime_t& t, const coord_t& x_Ph) const - -> real_t { - const auto sign { (x_Ph[1] < ymid) ? ONE : -ONE }; - const auto t_ { static_cast(t) }; - if (t_ > tscale) { - return sign * force; - } else { - return sign * force * (ONE - math::cos(constant::PI * t_ / tscale)) / TWO; - } - } - - Inline auto fx3(const spidx_t&, const simtime_t&, const coord_t&) const - -> real_t { - return ZERO; - } - - private: - const real_t force, tscale, ymid; - }; - - template - struct CurrentLayer : public arch::SpatialDistribution { - CurrentLayer(const M& metric, real_t width, real_t yi) - : arch::SpatialDistribution { metric } - , width { width } - , yi { yi } {} - - Inline auto operator()(const coord_t& x_Ph) const -> real_t override { - return ONE / SQR(math::cosh((x_Ph[1] - yi) / width)); - } - - private: - const real_t yi, width; - }; - - template - struct InitFields { - InitFields(real_t Bmag, real_t width, real_t y1, real_t y2) - : Bmag { Bmag } - , width { width } - , y1 { y1 } - , y2 { y2 } {} - - Inline auto bx3(const coord_t& x_Ph) const -> real_t { - return Bmag * (math::tanh((x_Ph[1] - y1) / width) - - math::tanh((x_Ph[1] - y2) / width) - 1); - } - - private: - const real_t Bmag, width, y1, y2; - }; - - template - struct PGen : public arch::ProblemGenerator { - // compatibility traits for the problem generator - static constexpr auto engines { traits::compatible_with::value }; - static constexpr auto metrics { traits::compatible_with::value }; - static constexpr auto dimensions { - traits::compatible_with::value - }; - - // for easy access to variables in the child class - using arch::ProblemGenerator::D; - using arch::ProblemGenerator::C; - using arch::ProblemGenerator::params; - - const real_t Bmag, width, overdensity, y1, y2, bg_temp; - InitFields init_flds; - - Gravity ext_force; - - inline PGen(const SimulationParams& p, const Metadomain& m) - : arch::ProblemGenerator(p) - , Bmag { p.template get("setup.Bmag", 1.0) } - , width { p.template get("setup.width") } - , overdensity { p.template get("setup.overdensity") } - , bg_temp { p.template get("setup.bg_temp") } - , y1 { m.mesh().extent(in::x2).first + - INV_4 * - (m.mesh().extent(in::x2).second - m.mesh().extent(in::x2).first) } - , y2 { m.mesh().extent(in::x2).first + - 3 * INV_4 * - (m.mesh().extent(in::x2).second - m.mesh().extent(in::x2).first) } - , init_flds { Bmag, width, y1, y2 } - , ext_force { - p.template get("setup.fmag", 0.1) * - p.template get("scales.omegaB0"), - (m.mesh().extent(in::x1).second - m.mesh().extent(in::x1).first), - INV_2 * (m.mesh().extent(in::x2).second + m.mesh().extent(in::x2).first) - } {} - - inline PGen() {} - - inline void InitPrtls(Domain& local_domain) { - // background - const auto energy_dist = arch::Maxwellian(local_domain.mesh.metric, - local_domain.random_pool, - bg_temp); - const auto injector = arch::UniformInjector( - energy_dist, - { 1, 2 }); - arch::InjectUniform(params, - local_domain, - injector, - ONE); - // current layers - const auto sigma = params.template get("scales.sigma0"); - const auto c_omp = params.template get("scales.skindepth0"); - const auto cs_drift_beta = math::sqrt(sigma) * c_omp / (width * overdensity); - const auto cs_drift_gamma = ONE / math::sqrt(ONE - SQR(cs_drift_beta)); - const auto cs_drift_u = cs_drift_beta * cs_drift_gamma; - const auto cs_temp = HALF * sigma / overdensity; - - for (auto i = 0; i < 2; ++i) { - const auto drift_vel = (i == 0) ? cs_drift_u : -cs_drift_u; - const auto y_cs = (i == 0) ? y1 : y2; - auto edist_cs = arch::Maxwellian(local_domain.mesh.metric, - local_domain.random_pool, - cs_temp, - drift_vel, - in::x1, - false); - const auto sdist_cs = CurrentLayer(local_domain.mesh.metric, - width, - y_cs); - const auto inj_cs = arch::NonUniformInjector( - edist_cs, - sdist_cs, - { 1, 2 }); - arch::InjectNonUniform(params, - local_domain, - inj_cs, - overdensity); - } - } // namespace user - }; - -} // namespace user - -#endif diff --git a/setups/legacy/rec-gravity/rec-gravity.toml b/setups/legacy/rec-gravity/rec-gravity.toml deleted file mode 100644 index f29b090e3..000000000 --- a/setups/legacy/rec-gravity/rec-gravity.toml +++ /dev/null @@ -1,54 +0,0 @@ -[simulation] - name = "rec-gravity" - engine = "srpic" - runtime = 20.0 - -[grid] - resolution = [2000, 4000] - extent = [[-0.5, 0.5], [-1.0, 1.0]] - - [grid.metric] - metric = "minkowski" - - [grid.boundaries] - fields = [["PERIODIC"], ["PERIODIC"]] - particles = [["PERIODIC"], ["PERIODIC"]] - -[scales] - larmor0 = 3.1e-4 - skindepth0 = 1e-3 - -[algorithms] - current_filters = 8 - - [algorithms.timestep] - CFL = 0.45 - -[particles] - ppc0 = 8.0 - - [[particles.species]] - label = "e-" - mass = 1.0 - charge = -1.0 - maxnpart = 1e8 - - [[particles.species]] - label = "e+" - mass = 1.0 - charge = 1.0 - maxnpart = 1e8 - -[setup] - Bmag = 1.0 - width = 0.04 - bg_temp = 1e-4 - overdensity = 3.0 - angle = 0.0 - -[output] - format = "hdf5" - interval_time = 0.36 - - [output.fields] - quantities = ["N_1", "N_2", "E", "B", "J", "T00_1", "T00_2"] diff --git a/setups/legacy/shocktest/pgen.hpp b/setups/legacy/shocktest/pgen.hpp deleted file mode 100644 index a7bcf5c3d..000000000 --- a/setups/legacy/shocktest/pgen.hpp +++ /dev/null @@ -1,155 +0,0 @@ -#ifndef PROBLEM_GENERATOR_H -#define PROBLEM_GENERATOR_H - -#include "enums.h" -#include "global.h" - -#include "arch/traits.h" -#include "utils/error.h" -#include "utils/numeric.h" - -#include "archetypes/energy_dist.h" -#include "archetypes/particle_injector.h" -#include "archetypes/problem_generator.h" -#include "framework/domain/metadomain.h" - -#include -#include - -namespace user { - using namespace ntt; - - template - struct InitFields { - /* - Sets up magnetic and electric field components for the simulation. - Must satisfy E = -v x B for Lorentz Force to be zero. - - @param bmag: magnetic field scaling - @param btheta: magnetic field polar angle - @param bphi: magnetic field azimuthal angle - @param drift_ux: drift velocity in the x direction - */ - InitFields(real_t bmag, real_t btheta, real_t bphi, real_t drift_ux) - : Bmag { bmag } - , Btheta { btheta * static_cast(convert::deg2rad) } - , Bphi { bphi * static_cast(convert::deg2rad) } - , Vx { drift_ux } {} - - // magnetic field components - Inline auto bx1(const coord_t& x_ph) const -> real_t { - return Bmag * math::cos(Btheta); - } - - Inline auto bx2(const coord_t& x_ph) const -> real_t { - return Bmag * math::sin(Btheta) * math::sin(Bphi); - } - - Inline auto bx3(const coord_t& x_ph) const -> real_t { - return Bmag * math::sin(Btheta) * math::cos(Bphi); - } - - // electric field components - Inline auto ex1(const coord_t& x_ph) const -> real_t { - return ZERO; - } - - Inline auto ex2(const coord_t& x_ph) const -> real_t { - return -Vx * Bmag * math::sin(Btheta) * math::cos(Bphi); - } - - Inline auto ex3(const coord_t& x_ph) const -> real_t { - return Vx * Bmag * math::sin(Btheta) * math::sin(Bphi); - } - - private: - const real_t Btheta, Bphi, Vx, Bmag; - }; - - template - struct PGen : public arch::ProblemGenerator { - // compatibility traits for the problem generator - static constexpr auto engines { traits::compatible_with::value }; - static constexpr auto metrics { traits::compatible_with::value }; - static constexpr auto dimensions { - traits::compatible_with::value - }; - - // for easy access to variables in the child class - using arch::ProblemGenerator::D; - using arch::ProblemGenerator::C; - using arch::ProblemGenerator::params; - - const real_t drift_ux, temperature; - - const std::vector x1arr_e, x2arr_e, ux1arr_e, ux2arr_e, ux3arr_e; - const std::vector x1arr_i, x2arr_i, ux1arr_i, ux2arr_i, ux3arr_i; - - const real_t Btheta, Bphi, Bmag; - InitFields init_flds; - const Metadomain* metadomain; - - inline PGen(const SimulationParams& p, const Metadomain& m) - : arch::ProblemGenerator { p } - , drift_ux { p.template get("setup.drift_ux") } - , temperature { p.template get("setup.temperature") } - , x1arr_e { p.template get>("setup.x_e") } - , x2arr_e { p.template get>("setup.y_e") } - , ux1arr_e { p.template get>("setup.ux_e") } - , ux2arr_e { p.template get>("setup.uy_e") } - , ux3arr_e { p.template get>("setup.uz_e") } - , x1arr_i { p.template get>("setup.x_i") } - , x2arr_i { p.template get>("setup.y_i") } - , ux1arr_i { p.template get>("setup.ux_i") } - , ux2arr_i { p.template get>("setup.uy_i") } - , ux3arr_i { p.template get>("setup.uz_i") } - , Btheta { p.template get("setup.Btheta", ZERO) } - , Bmag { p.template get("setup.Bmag", ZERO) } - , Bphi { p.template get("setup.Bphi", ZERO) } - , init_flds { Bmag, Btheta, Bphi, drift_ux } - , metadomain { &m } {} - - inline PGen() {} - - auto FixFieldsConst(const bc_in&, const em& comp) const - -> std::pair { - if (comp == em::ex2) { - return { init_flds.ex2({ ZERO }), true }; - } else if (comp == em::ex3) { - return { init_flds.ex3({ ZERO }), true }; - } else { - return { ZERO, false }; - } - } - - auto MatchFields(real_t time) const -> InitFields { - return init_flds; - } - - inline void InitPrtls(Domain& domain) { - arch::InjectGlobally(*metadomain, - domain, - 1, - { - { "x1", x1arr_e }, - { "x2", x2arr_e }, - { "ux1", ux1arr_e }, - { "ux2", ux1arr_e }, - { "ux3", ux3arr_e } - }); - arch::InjectGlobally(*metadomain, - domain, - 2, - { - { "x1", x1arr_i }, - { "x2", x2arr_i }, - { "ux1", ux1arr_i }, - { "ux2", ux1arr_i }, - { "ux3", ux3arr_i } - }); - } - }; - -} // namespace user - -#endif diff --git a/setups/legacy/shocktest/shock.toml b/setups/legacy/shocktest/shock.toml deleted file mode 100644 index 6c0c9a3a0..000000000 --- a/setups/legacy/shocktest/shock.toml +++ /dev/null @@ -1,69 +0,0 @@ -[simulation] - name = "shock" - engine = "srpic" - runtime = 50.0 - -[grid] - resolution = [2048, 128] - extent = [[0.0, 10.0], [-0.3125, 0.3125]] - - [grid.metric] - metric = "minkowski" - - [grid.boundaries] - fields = [["CONDUCTOR", "FIXED"], ["PERIODIC"]] - particles = [["REFLECT", "ABSORB"], ["PERIODIC"]] - -[scales] - larmor0 = 1e-2 - skindepth0 = 1e-2 - -[algorithms] - current_filters = 8 - fieldsolver = "false" - deposit = "false" - - [algorithms.timestep] - CFL = 0.5 - -[particles] - ppc0 = 16.0 - - [[particles.species]] - label = "e-" - mass = 1.0 - charge = -1.0 - maxnpart = 1e8 - - [[particles.species]] - label = "e+" - mass = 1.0 - charge = 1.0 - maxnpart = 1e8 - -[setup] - drift_ux = 0.1 - temperature = 1e-3 - Bmag = 1.0 - Btheta = 0.0 - Bphi = 0.0 - x_e = [0.05] - y_e = [0.0] - ux_e = [-0.01] - uy_e = [0.01] - uz_e = [0.001] - x_i = [0.05] - y_i = [0.0] - ux_i = [0.01] - uy_i = [-0.01] - uz_i = [-0.001] - -[output] - interval = 1 - format = "hdf5" - - [output.fields] - quantities = ["N_1", "N_2", "E", "B", "T0i_1", "T0i_2", "J"] - - [output.debug] - ghosts = true diff --git a/setups/legacy/spider/pgen.hpp b/setups/legacy/spider/pgen.hpp deleted file mode 100644 index 27d9504b7..000000000 --- a/setups/legacy/spider/pgen.hpp +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef PROBLEM_GENERATOR_H -#define PROBLEM_GENERATOR_H - -#include "enums.h" -#include "global.h" - -#include "arch/kokkos_aliases.h" -#include "arch/traits.h" - -#include "archetypes/problem_generator.h" -#include "framework/domain/metadomain.h" - -namespace user { - using namespace ntt; - - template - struct PGen : public arch::ProblemGenerator { - // compatibility traits for the problem generator - static constexpr auto engines { traits::compatible_with::value }; - static constexpr auto metrics { traits::compatible_with::value }; - static constexpr auto dimensions { - traits::compatible_with::value - }; - - // for easy access to variables in the child class - using arch::ProblemGenerator::D; - using arch::ProblemGenerator::C; - using arch::ProblemGenerator::params; - - inline PGen(const SimulationParams& p, const Metadomain& m) - : arch::ProblemGenerator(p) {} - - inline PGen() {} - }; - -} // namespace user - -#endif diff --git a/setups/srpic/pgen_srpic_example.hpp b/setups/srpic/pgen_srpic_example.hpp deleted file mode 100644 index de3bae408..000000000 --- a/setups/srpic/pgen_srpic_example.hpp +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef PROBLEM_GENERATOR_H -#define PROBLEM_GENERATOR_H - -#include "enums.h" -#include "global.h" - -#include "arch/traits.h" - -#include "archetypes/problem_generator.h" -#include "framework/domain/metadomain.h" - -namespace user { - using namespace ntt; - - template - struct PGen : public arch::ProblemGenerator { - // compatibility traits for the problem generator - static constexpr auto engines { traits::compatible_with::value }; - static constexpr auto metrics { - traits::compatible_with::value - }; - static constexpr auto dimensions { - traits::compatible_with::value - }; - - // for easy access to variables in the child class - using arch::ProblemGenerator::D; - using arch::ProblemGenerator::C; - using arch::ProblemGenerator::params; - - inline PGen(const SimulationParams& p, const Metadomain&) - : arch::ProblemGenerator(p) {} - - inline PGen() {} - }; - -} // namespace user - -#endif diff --git a/setups/srpic/shock/shock.py b/setups/srpic/shock/shock.py deleted file mode 100644 index dc1565572..000000000 --- a/setups/srpic/shock/shock.py +++ /dev/null @@ -1,75 +0,0 @@ -import nt2.read as nt2r -import matplotlib.pyplot as plt -import matplotlib as mpl - -data = nt2r.Data("shock.h5") - - -def frame(ti, f): - quantities = [ - { - "name": "density", - "compute": lambda f: f.N_2 + f.N_1, - "cmap": "inferno", - "norm": mpl.colors.Normalize(0, 5), - }, - { - "name": r"$E_x$", - "compute": lambda f: f.Ex, - "cmap": "RdBu_r", - "norm": mpl.colors.Normalize(-0.05, 0.05), - }, - { - "name": r"$E_y$", - "compute": lambda f: f.Ey, - "cmap": "RdBu_r", - "norm": mpl.colors.Normalize(-0.05, 0.05), - }, - { - "name": r"$E_z$", - "compute": lambda f: f.Ez, - "cmap": "RdBu_r", - "norm": mpl.colors.Normalize(-0.05, 0.05), - }, - { - "name": r"$B_x$", - "compute": lambda f: f.Bx, - "cmap": "BrBG", - "norm": mpl.colors.Normalize(-0.05, 0.05), - }, - { - "name": r"$B_y$", - "compute": lambda f: f.By, - "cmap": "BrBG", - "norm": mpl.colors.Normalize(-0.05, 0.05), - }, - { - "name": r"$B_z$", - "compute": lambda f: f.Bz, - "cmap": "BrBG", - "norm": mpl.colors.Normalize(-0.05, 0.05), - }, - ] - fig = plt.figure(figsize=(12, 5.5), dpi=300) - gs = fig.add_gridspec(len(quantities), 1, hspace=0.02) - axs = [fig.add_subplot(gs[i]) for i in range(len(quantities))] - - for ax, q in zip(axs, quantities): - q["compute"](f.isel(t=ti)).plot( - ax=ax, - cmap=q["cmap"], - norm=q["norm"], - cbar_kwargs={"label": q["name"], "shrink": 0.8, "aspect": 10, "pad": 0.005}, - ) - for i, ax in enumerate(axs): - ax.set(aspect=1) - if i != 0: - ax.set(title=None) - if i != len(axs) - 1: - ax.set( - xticks=[], - xticklabels=[], - xlabel=None, - title=ax.get_title().split(",")[0], - ) - return fig diff --git a/setups/tests/blob/blob.py b/setups/tests/blob/blob.py deleted file mode 100644 index 77337d3b2..000000000 --- a/setups/tests/blob/blob.py +++ /dev/null @@ -1,62 +0,0 @@ -import h5py -import numpy as np -import matplotlib.pyplot as plt - -f = open("report", "r") -Lines = f.readlines() -f.close() - -em_new = [] -ep_new = [] -time_new = [] -for i in range (len(Lines)): - line = Lines[i] - line = line.strip() - arr = line.split() - - if (len(arr)>0 and arr[0]=='species'): - nparts = arr[2].split("..") - if (nparts[0]=="(e-_p)"): - em_new.append(float(nparts[-1])) - if (nparts[0]=="(e+_p)"): - ep_new.append(float(nparts[-1])) - - if (len(arr)>0 and arr[0]=='Time:'): - time_new.append(float(arr[1])) - -f = h5py.File('blob.h5', 'r') - -Nsteps = len(f.keys()) -print(list(f['Step0'].keys())) - -for i in range (Nsteps): - print (i) - fig = plt.figure(dpi=300, figsize=(8,8), facecolor='white') - - densMax = max(np.max(f['Step'+str(i)]['fN_1']),np.max(f['Step'+str(i)]['fN_2'])) - print(densMax) - ax1 = fig.add_axes([0.05,0.05,0.4,0.4]) - im1=ax1.pcolormesh(f['Step'+str(i)]['X1'],f['Step'+str(i)]['X2'],f['Step'+str(i)]['fN_1'],cmap='turbo',vmin=0,vmax=1.0) - ax1.set_title(r"$N_1$") - ax1.vlines(0,-10.0,10.0,color='white') - - ax1 = fig.add_axes([0.48,0.05,0.4,0.4]) - ax1.pcolormesh(f['Step'+str(i)]['X1'],f['Step'+str(i)]['X2'],f['Step'+str(i)]['fN_2'],cmap='turbo',vmin=0,vmax=1.0) - ax1.set_yticklabels([]) - ax1.set_title(r"$N_2$") - ax1.vlines(0,-10.0,10.0,color='white') - - ax4cb = fig.add_axes([0.89, 0.05, 0.01, 0.4]) - cbar4 = fig.colorbar(im1,cax=ax4cb) - - ax1= fig.add_axes([0.05,0.5,0.83,0.4]) - ax1.plot(time_new,em_new, color='blue', label=r'$e^-$, new') - ax1.plot(time_new,ep_new, color='red', label=r'$e^+$, new') - ax1.legend() - ax1.set_ylim(0,1.8e5) - ax1.set_xlim(0,100) - ax1.vlines(i, 0,1.8e5, color='green',linewidth=0.6) - - - fig.savefig("%05d"%i+".png",dpi=300,bbox_inches='tight') - plt.close() diff --git a/setups/tests/blob/blob.toml b/setups/tests/blob/blob.toml deleted file mode 100644 index 7a047f348..000000000 --- a/setups/tests/blob/blob.toml +++ /dev/null @@ -1,66 +0,0 @@ -[simulation] - name = "blob" - engine = "srpic" - runtime = 100.0 - - [simulation.domain] - decomposition = [2, 1, 1] - -[grid] - resolution = [1024, 1024] - extent = [[-10.0, 10.0], [-10.0, 10.0]] - - [grid.metric] - metric = "minkowski" - - [grid.boundaries] - fields = [["PERIODIC"], ["PERIODIC"]] - particles = [["PERIODIC"], ["PERIODIC"]] - -[scales] - larmor0 = 1.0 - skindepth0 = 1.0 - -[algorithms] - current_filters = 4 - - [algorithms.timestep] - CFL = 0.5 - -[particles] - ppc0 = 16.0 - - [[particles.species]] - label = "e-_p" - mass = 1.0 - charge = -1.0 - maxnpart = 1e7 - - [[particles.species]] - label = "e+_p" - mass = 1.0 - charge = 1.0 - maxnpart = 1e7 - -[setup] - temp_1 = 1e-4 - x1c = -5.0 - x2c = 0.0 - v_max = 50.0 - dr = 1.0 - -[output] - format = "hdf5" - interval_time = 1.0 - - [output.fields] - quantities = ["N_1", "N_2", "B", "E"] - - [output.particles] - enable = false - - [output.spectra] - enable = false - -[diagnostics] - colored_stdout = false diff --git a/setups/tests/blob/nparts.py b/setups/tests/blob/nparts.py deleted file mode 100644 index e759422c0..000000000 --- a/setups/tests/blob/nparts.py +++ /dev/null @@ -1,38 +0,0 @@ -import h5py -import numpy as np -import matplotlib.pyplot as plt - -f = open("report", "r") -Lines = f.readlines() -f.close() - -em_new = [] -ep_new = [] -time_new = [] -for i in range (len(Lines)): - line = Lines[i] - line = line.strip() - arr = line.split() - - if (len(arr)>0 and arr[0]=='species'): - nparts = arr[2].split("..") - if (nparts[0]=="(e-_p)"): - em_new.append(float(nparts[-1])) - if (nparts[0]=="(e+_p)"): - ep_new.append(float(nparts[-1])) - - if (len(arr)>0 and arr[0]=='Time:'): - time_new.append(float(arr[1])) - - -fig = plt.figure(dpi=300, figsize=(8,8), facecolor='white') - -ax1= fig.add_axes([0.05,0.5,0.83,0.4]) -ax1.plot(time_new,em_new, color='blue', label=r'$e^-$, new') -ax1.plot(time_new,ep_new, color='red', label=r'$e^+$, new') -ax1.legend() -ax1.set_ylim(0,1.8e5) -ax1.set_xlim(0,100) - -fig.savefig("nparts.png",dpi=300,bbox_inches='tight') -plt.close() diff --git a/setups/tests/blob/pgen.hpp b/setups/tests/blob/pgen.hpp deleted file mode 100644 index 9120e244f..000000000 --- a/setups/tests/blob/pgen.hpp +++ /dev/null @@ -1,103 +0,0 @@ -#ifndef PROBLEM_GENERATOR_H -#define PROBLEM_GENERATOR_H - -#include "enums.h" -#include "global.h" - -#include "arch/kokkos_aliases.h" -#include "arch/traits.h" - -#include "archetypes/energy_dist.h" -#include "archetypes/particle_injector.h" -#include "archetypes/problem_generator.h" -#include "framework/domain/domain.h" -#include "framework/domain/metadomain.h" - -namespace user { - using namespace ntt; - - template - struct CounterstreamEnergyDist : public arch::EnergyDistribution { - CounterstreamEnergyDist(const M& metric, real_t v_max) - : arch::EnergyDistribution { metric } - , v_max { v_max } {} - - Inline void operator()(const coord_t& x_Ph, - vec_t& v, - spidx_t sp) const override { - v[0] = v_max; - } - - private: - const real_t v_max; - }; - - template - struct GaussianDist : public arch::SpatialDistribution { - GaussianDist(const M& metric, real_t x1c, real_t x2c, real_t dr) - : arch::SpatialDistribution { metric } - , x1c { x1c } - , x2c { x2c } - , dr { dr } {} - - // to properly scale the number density, the probability should be normalized to 1 - Inline auto operator()(const coord_t& x_Ph) const -> real_t override { - if (math::abs(x_Ph[0] - x1c) < dr && math::abs(x_Ph[1] - x2c) < dr) { - return 1.0; - } else { - return 0.0; - } - } - - private: - const real_t x1c, x2c, dr; - }; - - template - struct PGen : public arch::ProblemGenerator { - - // compatibility traits for the problem generator - static constexpr auto engines = traits::compatible_with::value; - static constexpr auto metrics = traits::compatible_with::value; - static constexpr auto dimensions = - traits::compatible_with::value; - - // for easy access to variables in the child class - using arch::ProblemGenerator::D; - using arch::ProblemGenerator::C; - using arch::ProblemGenerator::params; - - const real_t temp_1, x1c, x2c, dr, v_max; - - inline PGen(const SimulationParams& p, const Metadomain& global_domain) - : arch::ProblemGenerator { p } - , temp_1 { p.template get("setup.temp_1") } - , x1c { p.template get("setup.x1c") } - , x2c { p.template get("setup.x2c") } - , v_max { p.template get("setup.v_max") } - , dr { p.template get("setup.dr") } {} - - inline void InitPrtls(Domain& local_domain) { - const auto energy_dist = CounterstreamEnergyDist(local_domain.mesh.metric, - v_max); - const auto spatial_dist = GaussianDist(local_domain.mesh.metric, - x1c, - x2c, - dr); - const auto injector = - arch::NonUniformInjector( - energy_dist, - spatial_dist, - { 1, 2 }); - - arch::InjectNonUniform>( - params, - local_domain, - injector, - 1.0); - } - }; - -} // namespace user - -#endif diff --git a/setups/tests/customout/customout.toml b/setups/tests/customout/customout.toml deleted file mode 100644 index 497b96dc2..000000000 --- a/setups/tests/customout/customout.toml +++ /dev/null @@ -1,50 +0,0 @@ -[simulation] - name = "customout" - engine = "srpic" - runtime = 10.0 - -[grid] - resolution = [256, 256] - extent = [[-1.0, 1.0], [-1.0, 1.0]] - - [grid.metric] - metric = "minkowski" - - [grid.boundaries] - fields = [["PERIODIC"], ["PERIODIC"]] - particles = [["PERIODIC"], ["PERIODIC"]] - -[scales] - larmor0 = 0.01 - skindepth0 = 0.01 - -[algorithms] - current_filters = 4 - - [algorithms.timestep] - CFL = 0.5 - -[particles] - ppc0 = 20.0 - - [[particles.species]] - label = "e-" - mass = 1.0 - charge = -1.0 - maxnpart = 1e7 - pusher = "Boris" - - [[particles.species]] - label = "e+" - mass = 1.0 - charge = 1.0 - maxnpart = 1e7 - pusher = "Boris" - -[output] - format = "hdf5" - interval_time = 0.02 - - [output.fields] - quantities = ["E", "B", "J"] - custom = ["mybuff", "EdotB+1"] diff --git a/setups/tests/customout/pgen.hpp b/setups/tests/customout/pgen.hpp deleted file mode 100644 index 22c8f6564..000000000 --- a/setups/tests/customout/pgen.hpp +++ /dev/null @@ -1,86 +0,0 @@ -#ifndef PROBLEM_GENERATOR_H -#define PROBLEM_GENERATOR_H - -#include "enums.h" -#include "global.h" - -#include "arch/kokkos_aliases.h" -#include "arch/traits.h" - -#include "archetypes/problem_generator.h" -#include "framework/domain/metadomain.h" - -namespace user { - using namespace ntt; - - template - struct PGen : public arch::ProblemGenerator { - // compatibility traits for the problem generator - static constexpr auto engines { traits::compatible_with::value }; - static constexpr auto metrics { traits::compatible_with::value }; - static constexpr auto dimensions { traits::compatible_with::value }; - - // for easy access to variables in the child class - using arch::ProblemGenerator::D; - using arch::ProblemGenerator::C; - using arch::ProblemGenerator::params; - - array_t cbuff; - - inline PGen(const SimulationParams& p, const Metadomain&) - : arch::ProblemGenerator(p) {} - - inline PGen() {} - - void CustomPostStep(std::size_t step, long double, Domain& domain) { - if (step == 0) { - // allocate the array at time = 0 - cbuff = array_t("cbuff", - domain.mesh.n_all(in::x1), - domain.mesh.n_all(in::x2)); - } - // fill with zeros - Kokkos::deep_copy(cbuff, ZERO); - // populate the array atomically (here it's not strictly necessary) - auto cbuff_sc = Kokkos::Experimental::create_scatter_view(cbuff); - Kokkos::parallel_for( - "FillCbuff", - domain.mesh.rangeActiveCells(), - Lambda(index_t i1, index_t i2) { - auto cbuff_acc = cbuff_sc.access(); - cbuff_acc(i1, i2) += static_cast(i1 + i2); - }); - Kokkos::Experimental::contribute(cbuff, cbuff_sc); - } - - void CustomFieldOutput(const std::string& name, - ndfield_t buffer, - std::size_t index, - const Domain& domain) { - printf("CustomFieldOutput: %s\n", name.c_str()); - // examples for 2D - if (name == "mybuff") { - // copy the custom buffer to the buffer output - Kokkos::deep_copy(Kokkos::subview(buffer, Kokkos::ALL, Kokkos::ALL, index), - cbuff); - } else if (name == "EdotB+1") { - // calculate the custom buffer from EM fields - const auto& EM = domain.fields.em; - Kokkos::parallel_for( - "EdotB+1", - domain.mesh.rangeActiveCells(), - Lambda(index_t i1, index_t i2) { - buffer(i1, i2, index) = EM(i1, i2, em::ex1) * EM(i1, i2, em::bx1) + - EM(i1, i2, em::ex2) * EM(i1, i2, em::bx2) + - EM(i1, i2, em::ex3) * EM(i1, i2, em::bx3) + - ONE; - }); - } else { - raise::Error("Custom output not provided", HERE); - } - } - }; - -} // namespace user - -#endif diff --git a/setups/tests/deposit/deposit-mink.toml b/setups/tests/deposit/deposit-mink.toml deleted file mode 100644 index 2dc953896..000000000 --- a/setups/tests/deposit/deposit-mink.toml +++ /dev/null @@ -1,71 +0,0 @@ -[simulation] - name = "deposit-test-mink" - engine = "srpic" - runtime = 5.0 - -[grid] - resolution = [32, 32] - extent = [[0.0, 1.0], [0.0, 1.0]] - - [grid.metric] - metric = "minkowski" - - [grid.boundaries] - fields = [["PERIODIC"], ["PERIODIC"]] - particles = [["PERIODIC"], ["PERIODIC"]] - -[scales] - larmor0 = 0.1 - skindepth0 = 0.1 - -[algorithms] - current_filters = 4 - - [algorithms.timestep] - CFL = 0.5 - -[particles] - ppc0 = 10.0 - - [[particles.species]] - label = "e-" - mass = 1.0 - charge = -1.0 - maxnpart = 1e2 - - [[particles.species]] - label = "e+" - mass = 1.0 - charge = 1.0 - maxnpart = 1e2 - -[setup] - x1_e = [0.25] - x2_e = [0.85] - x3_e = [0.33] - ux1_e = [0.6] - ux2_e = [-0.3] - ux3_e = [-0.2] - - x1_i = [0.25] - x2_i = [0.85] - x3_i = [0.33] - ux1_i = [-0.6] - ux2_i = [0.3] - ux3_i = [0.2] - -[output] - format = "hdf5" - interval = 5 - - [output.fields] - quantities = ["N_1", "N_2", "E", "B", "J"] - - [output.particles] - enable = false - - [output.spectra] - enable = false - -[checkpoint] - keep = 0 diff --git a/setups/tests/deposit/deposit-sr.toml b/setups/tests/deposit/deposit-sr.toml deleted file mode 100644 index 0e1648d12..000000000 --- a/setups/tests/deposit/deposit-sr.toml +++ /dev/null @@ -1,71 +0,0 @@ -[simulation] - name = "deposit-sr" - engine = "srpic" - runtime = 10.0 - -[grid] - resolution = [64, 64] - extent = [[1.0, 5.0]] - - [grid.metric] - metric = "qspherical" - - [grid.boundaries] - fields = [["FIXED", "FIXED"]] - particles = [["REFLECT", "REFLECT"]] - -[scales] - larmor0 = 0.1 - skindepth0 = 0.1 - -[algorithms] - current_filters = 4 - - [algorithms.timestep] - CFL = 0.5 - -[particles] - ppc0 = 10.0 - - [[particles.species]] - label = "e-" - mass = 1.0 - charge = -1.0 - maxnpart = 1e2 - - [[particles.species]] - label = "e+" - mass = 1.0 - charge = 1.0 - maxnpart = 1e2 - -[setup] - x1_e = [2.25] - x2_e = [1.25] - phi_e = [0.0] - ux1_e = [0.6] - ux2_e = [-0.3] - ux3_e = [-0.2] - - x1_i = [2.25] - x2_i = [1.25] - phi_i = [0.0] - ux1_i = [-0.6] - ux2_i = [0.3] - ux3_i = [0.2] - -[output] - format = "hdf5" - interval = 5 - - [output.fields] - quantities = ["N_1", "N_2", "E", "B", "J"] - - [output.particles] - enable = false - - [output.spectra] - enable = false - -[checkpoint] - keep = 0 diff --git a/setups/tests/deposit/pgen.hpp b/setups/tests/deposit/pgen.hpp deleted file mode 100644 index 0080af8fd..000000000 --- a/setups/tests/deposit/pgen.hpp +++ /dev/null @@ -1,113 +0,0 @@ -#ifndef PROBLEM_GENERATOR_H -#define PROBLEM_GENERATOR_H - -#include "enums.h" -#include "global.h" - -#include "arch/traits.h" - -#include "archetypes/particle_injector.h" -#include "archetypes/problem_generator.h" -#include "framework/domain/domain.h" -#include "framework/domain/metadomain.h" - -#include - -namespace user { - using namespace ntt; - - template - struct PGen : public arch::ProblemGenerator { - - // compatibility traits for the problem generator - static constexpr auto engines { - traits::compatible_with::value - }; - static constexpr auto metrics { - traits::compatible_with::value - }; - static constexpr auto dimensions { - traits::compatible_with::value - }; - - // for easy access to variables in the child class - using arch::ProblemGenerator::D; - using arch::ProblemGenerator::C; - using arch::ProblemGenerator::params; - - const Metadomain& global_domain; - - inline PGen(const SimulationParams& p, const Metadomain& global_domain) - : arch::ProblemGenerator { p } - , global_domain { global_domain } {} - - inline void InitPrtls(Domain& local_domain) { - const auto empty = std::vector {}; - const auto x1_e = params.template get>("setup.x1_e", - empty); - const auto x2_e = params.template get>("setup.x2_e", - empty); - const auto x3_e = params.template get>("setup.x3_e", - empty); - const auto phi_e = params.template get>("setup.phi_e", - empty); - const auto ux1_e = params.template get>("setup.ux1_e", - empty); - const auto ux2_e = params.template get>("setup.ux2_e", - empty); - const auto ux3_e = params.template get>("setup.ux3_e", - empty); - - const auto x1_i = params.template get>("setup.x1_i", - empty); - const auto x2_i = params.template get>("setup.x2_i", - empty); - const auto x3_i = params.template get>("setup.x3_i", - empty); - const auto phi_i = params.template get>("setup.phi_i", - empty); - const auto ux1_i = params.template get>("setup.ux1_i", - empty); - const auto ux2_i = params.template get>("setup.ux2_i", - empty); - const auto ux3_i = params.template get>("setup.ux3_i", - empty); - std::map> data_e { - { "x1", x1_e }, - { "x2", x2_e }, - { "ux1", ux1_e }, - { "ux2", ux2_e }, - { "ux3", ux3_e } - }; - std::map> data_i { - { "x1", x1_i }, - { "x2", x2_i }, - { "ux1", ux1_i }, - { "ux2", ux2_i }, - { "ux3", ux3_i } - }; - if constexpr (M::CoordType == Coord::Cart or D == Dim::_3D) { - data_e["x3"] = x3_e; - data_i["x3"] = x3_i; - } else if constexpr (D == Dim::_2D) { - data_e["phi"] = phi_e; - data_i["phi"] = phi_i; - } - - arch::InjectGlobally(global_domain, local_domain, (spidx_t)1, data_e); - arch::InjectGlobally(global_domain, local_domain, (spidx_t)2, data_i); - } - - auto FixFieldsConst(const bc_in&, const em&) const -> std::pair { - return { ZERO, false }; - } - }; - -} // namespace user - -#endif diff --git a/setups/tests/deposit/plot-mink.py b/setups/tests/deposit/plot-mink.py deleted file mode 100644 index 9d6760613..000000000 --- a/setups/tests/deposit/plot-mink.py +++ /dev/null @@ -1,62 +0,0 @@ -import nt2 -import matplotlib.pyplot as plt -import matplotlib as mpl - -datas = [] -cpus = [1, 2, 3, 4, 5, 6, 8] -for i in cpus: - datas.append(nt2.Data(path=f"mink-np{i}")) - - -def plot(ti): - fig = plt.figure(figsize=(16, 7), dpi=300) - gs = mpl.gridspec.GridSpec(3, 7, figure=fig) - - for p, quant in enumerate(["Jx", "Jy", "Jz"]): - axs = [fig.add_subplot(gs[p, i]) for i in range(7)] - (datas[0].fields[quant]).isel(t=ti).plot( - ax=axs[0], - cmap="seismic", - add_colorbar=False, - norm=mpl.colors.SymLogNorm( - linthresh=1e-5, - linscale=1, - vmin=-1e-2, - vmax=1e-2, - ), - ) - for i, (d, ax) in enumerate(zip(datas[1:], axs[1:])): - (d.fields[quant] - datas[0].fields[quant]).isel(t=ti).plot( - ax=ax, - cmap="seismic", - add_colorbar=False, - norm=mpl.colors.SymLogNorm( - linthresh=1e-10, - linscale=1, - vmin=-1e-7, - vmax=1e-7, - ), - ) - - for i, ax in enumerate(axs): - ax.set_aspect(1) - if i > 0: - if p == 0: - ax.set_title(f"np{cpus[i]} - np1") - else: - ax.set_title(None) - ax.set_yticklabels([]) - ax.set_ylabel(None) - else: - if p == 0: - ax.set_title(f"np1") - else: - ax.set_title(None) - - if p != 2: - ax.set_xticklabels([]) - ax.set_xlabel(None) - - -nt2.export.makeFrames(plot, datas[0].fields.s[::4], "mink-diff", num_cpus=4) -nt2.export.makeMovie(framerate=10, input="mink-diff/", number=5, output="mink-diff.mp4") diff --git a/setups/tests/deposit/plot-sr.py b/setups/tests/deposit/plot-sr.py deleted file mode 100644 index 0ba5dff24..000000000 --- a/setups/tests/deposit/plot-sr.py +++ /dev/null @@ -1,29 +0,0 @@ -import nt2 -import matplotlib.pyplot as plt -import matplotlib as mpl - -data = nt2.Data(path=f"sr-np8") - - -def plot(ti): - fig = plt.figure(figsize=(9, 6), dpi=300) - gs = mpl.gridspec.GridSpec(1, 3, figure=fig) - axs = [fig.add_subplot(gs[0, i]) for i in range(3)] - for i, (ax, j) in enumerate(zip(axs, ["Jr", "Jth", "Jph"])): - data.fields.isel(t=ti)[j].polar.pcolor( - ax=ax, - cbar_position="top", - cbar_size="2%", - norm=mpl.colors.SymLogNorm(linthresh=1e-8, vmin=-1e-4, vmax=1e-4), - cmap="seismic", - ) - ax.set_title(None) - ax.add_artist(mpl.patches.Circle((0, 0), 1, color="k", alpha=0.2)) - ax.add_artist(mpl.patches.Circle((0, 0), 5, edgecolor="k", facecolor="none")) - if i > 0: - ax.set_yticklabels([]) - ax.set_ylabel(None) - - -nt2.export.makeFrames(plot, data.fields.s, "sr-dep", num_cpus=4) -nt2.export.makeMovie(framerate=10, input="sr-dep/", number=5, output="sr-dep.mp4") diff --git a/setups/tests/deposit/run-mink.sh b/setups/tests/deposit/run-mink.sh deleted file mode 100755 index 4b52d6642..000000000 --- a/setups/tests/deposit/run-mink.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/env bash - -for i in {1..8}; do - if [ $i -eq 7 ]; then - continue - fi - run=$(echo "np${i}") - cp deposit-mink.toml deposit-mink-${run}.toml && \ - sed -i 's/name[[:space:]]*=[[:space:]]*".*\?"/name = "mink-'${run}'"/g' deposit-mink-${run}.toml && \ - mpiexec -np ${i} ./entity.xc -input deposit-mink-${run}.toml && \ - rm deposit-mink-${run}.toml -done - -rm *.info *.err *.log *.csv diff --git a/setups/tests/injector/injector.toml b/setups/tests/injector/injector.toml deleted file mode 100644 index 10fdaa251..000000000 --- a/setups/tests/injector/injector.toml +++ /dev/null @@ -1,62 +0,0 @@ -[simulation] - name = "injector-test" - engine = "srpic" - runtime = 2.0 - -[grid] - resolution = [512, 512] - extent = [[-1.0, 1.0], [-1.0, 1.0]] - - [grid.metric] - metric = "minkowski" - - [grid.boundaries] - fields = [["ABSORB", "ABSORB"], ["ABSORB", "ABSORB"]] - particles = [["ABSORB", "ABSORB"], ["ABSORB", "ABSORB"]] - - [grid.boundaries.absorb] - ds = 0.15 - -[scales] - larmor0 = 0.1 - skindepth0 = 0.1 - -[algorithms] - current_filters = 4 - - [algorithms.timestep] - CFL = 0.5 - -[particles] - ppc0 = 1.0 - - [[particles.species]] - label = "e-" - mass = 1.0 - charge = -1.0 - maxnpart = 1e6 - - [[particles.species]] - label = "e+" - mass = 1.0 - charge = 1.0 - maxnpart = 1e6 - -[setup] - period = 0.1 - vmax = 1.0 - x1c = 0.25 - x2c = -0.32 - dr = 1e-2 - rate = 0.1 - -[output] - format = "hdf5" - interval_time = 0.01 - - [output.fields] - quantities = ["N_1", "N_2", "E"] - -[diagnostics] - interval = 10 - colored_stdout = true diff --git a/setups/tests/injector/pgen.hpp b/setups/tests/injector/pgen.hpp deleted file mode 100644 index 0b4a34a07..000000000 --- a/setups/tests/injector/pgen.hpp +++ /dev/null @@ -1,103 +0,0 @@ -#ifndef PROBLEM_GENERATOR_H -#define PROBLEM_GENERATOR_H - -#include "enums.h" -#include "global.h" - -#include "arch/kokkos_aliases.h" -#include "arch/traits.h" -#include "utils/numeric.h" - -#include "archetypes/energy_dist.h" -#include "archetypes/particle_injector.h" -#include "archetypes/problem_generator.h" -#include "archetypes/spatial_dist.h" -#include "framework/domain/domain.h" -#include "framework/domain/metadomain.h" - -namespace user { - using namespace ntt; - - template - struct Firehose : public arch::EnergyDistribution { - Firehose(const M& metric, real_t time, real_t period, real_t vmax) - : arch::EnergyDistribution { metric } - , phase { (real_t)(constant::TWO_PI)*time / period } - , vmax { vmax } {} - - Inline void operator()(const coord_t&, - vec_t& v_Ph, - spidx_t) const override { - v_Ph[0] = vmax * math::cos(phase); - v_Ph[1] = vmax * math::sin(phase); - } - - private: - const real_t phase, vmax; - }; - - template - struct PointDistribution : public arch::SpatialDistribution { - PointDistribution(const M& metric, real_t x1c, real_t x2c, real_t dr) - : arch::SpatialDistribution { metric } - , x1c { x1c } - , x2c { x2c } - , dr { dr } {} - - Inline auto operator()(const coord_t& x_Ph) const -> real_t override { - return math::exp(-(SQR(x_Ph[0] - x1c) + SQR(x_Ph[1] - x2c)) / SQR(dr)); - } - - private: - const real_t x1c, x2c, dr; - }; - - template - struct PGen : public arch::ProblemGenerator { - - // compatibility traits for the problem generator - static constexpr auto engines = traits::compatible_with::value; - static constexpr auto metrics = traits::compatible_with::value; - static constexpr auto dimensions = traits::compatible_with::value; - - // for easy access to variables in the child class - using arch::ProblemGenerator::D; - using arch::ProblemGenerator::C; - using arch::ProblemGenerator::params; - - const real_t period, vmax, x1c, x2c, dr, rate; - - inline PGen(const SimulationParams& p, const Metadomain&) - : arch::ProblemGenerator { p } - , period { params.template get("setup.period", 1.0) } - , vmax { params.template get("setup.vmax", 1.0) } - , x1c { params.template get("setup.x1c", 0.0) } - , x2c { params.template get("setup.x2c", 0.0) } - , dr { params.template get("setup.dr", 0.1) } - , rate { params.template get("setup.rate", 1.0) } {} - - void CustomPostStep(std::size_t, long double time, Domain& domain) { - const auto energy_dist = Firehose(domain.mesh.metric, - (real_t)time, - period, - vmax); - const auto spatial_dist = PointDistribution(domain.mesh.metric, - x1c, - x2c, - dr); - const auto injector = arch::NonUniformInjector( - energy_dist, - spatial_dist, - { 1, 2 }); - - arch::InjectNonUniform>( - params, - domain, - injector, - rate); - } - }; - -} // namespace user - -#endif diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 715183b64..a54a119b5 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -37,8 +37,6 @@ if(${output}) add_subdirectory(${SRC_DIR}/checkpoint ${CMAKE_CURRENT_BINARY_DIR}/checkpoint) endif() -add_subdirectory(${SRC_DIR}/../setups ${CMAKE_CURRENT_BINARY_DIR}/setups) - set(ENTITY ${PROJECT_NAME}.xc) set(SOURCES ${SRC_DIR}/entity.cpp) diff --git a/src/archetypes/energy_dist.h b/src/archetypes/energy_dist.h index 67f1bdf8a..e9ef8b0b7 100644 --- a/src/archetypes/energy_dist.h +++ b/src/archetypes/energy_dist.h @@ -184,12 +184,13 @@ namespace arch { } template - Inline void SampleFromMaxwellian(vec_t& v, - const real_t& temperature, - const real_t& boost_velocity, - const in& boost_direction, - bool flip_velocity, - const random_number_pool_t& pool) { + Inline void SampleFromMaxwellian( + vec_t& v, + const random_number_pool_t& pool, + const real_t& temperature, + const real_t& boost_velocity = static_cast(0), + const in& boost_direction = in::x1, + bool flip_velocity = false) { if (cmp::AlmostZero(temperature)) { v[0] = ZERO; v[1] = ZERO; @@ -242,7 +243,7 @@ namespace arch { "Maxwellian: Temperature must be non-negative", HERE); raise::ErrorIf( - (not cmp::AlmostZero(boost_vel, ZERO)) && (M::CoordType != Coord::Cart), + (not cmp::AlmostZero_host(boost_vel, ZERO)) && (M::CoordType != Coord::Cart), "Maxwellian: Boosting is only supported in Cartesian coordinates", HERE); } @@ -251,12 +252,12 @@ namespace arch { vec_t& v, spidx_t sp = 0) const override { SampleFromMaxwellian(v, + pool, temperature, boost_velocity, boost_direction, not zero_current and - sp % 2 == 0, - pool); + sp % 2 == 0); if constexpr (S == SimEngine::GRPIC) { // convert from the tetrad basis to covariant vec_t v_Hat; @@ -312,11 +313,11 @@ namespace arch { spidx_t sp = 0) const override { SampleFromMaxwellian( v, + pool, (sp == sp_1) ? temperature_1 : temperature_2, boost_velocity, boost_direction, - not zero_current and sp == sp_1, - pool); + not zero_current and sp == sp_1); if constexpr (S == SimEngine::GRPIC) { // convert from the tetrad basis to covariant vec_t v_Hat; From e32a902db9043eae31fe934386d2a6211ad8aa75 Mon Sep 17 00:00:00 2001 From: hayk Date: Tue, 13 May 2025 14:59:13 -0400 Subject: [PATCH 697/773] submodule for pgens --- .gitmodules | 3 +++ cmake/config.cmake | 29 +++++++++++++++++++++-------- extern/entity-pgens | 1 + 3 files changed, 25 insertions(+), 8 deletions(-) create mode 160000 extern/entity-pgens diff --git a/.gitmodules b/.gitmodules index 577d08ea6..835fbe5b8 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,3 +7,6 @@ [submodule "extern/Kokkos"] path = extern/Kokkos url = https://github.com/kokkos/kokkos.git +[submodule "extern/entity-pgens"] + path = extern/entity-pgens + url = https://github.com/entity-toolkit/entity-pgens.git diff --git a/cmake/config.cmake b/cmake/config.cmake index 68b0db2ef..97ed658e3 100644 --- a/cmake/config.cmake +++ b/cmake/config.cmake @@ -22,25 +22,38 @@ function(set_problem_generator pgen_name) message(FATAL_ERROR "Problem generator not specified") endif() - file(GLOB_RECURSE PGENS "${CMAKE_CURRENT_SOURCE_DIR}/pgens/**/pgen.hpp" - "${CMAKE_CURRENT_SOURCE_DIR}/pgens/pgen.hpp") + file(GLOB_RECURSE PGENS "${CMAKE_CURRENT_SOURCE_DIR}/pgens/**/pgen.hpp") foreach(PGEN ${PGENS}) get_filename_component(PGEN_NAME ${PGEN} DIRECTORY) string(REPLACE "${CMAKE_CURRENT_SOURCE_DIR}/pgens/" "" PGEN_NAME ${PGEN_NAME}) - string(REPLACE "${CMAKE_CURRENT_SOURCE_DIR}/pgens" "" PGEN_NAME - ${PGEN_NAME}) list(APPEND PGEN_NAMES ${PGEN_NAME}) endforeach() list(FIND PGEN_NAMES ${pgen_name} PGEN_FOUND) + file(GLOB_RECURSE EXTRA_PGENS + "${CMAKE_CURRENT_SOURCE_DIR}/extern/entity-pgens/**/pgen.hpp") + foreach(EXTRA_PGEN ${EXTRA_PGENS}) + get_filename_component(EXTRA_PGEN_NAME ${EXTRA_PGEN} DIRECTORY) + string(REPLACE "${CMAKE_CURRENT_SOURCE_DIR}/extern/entity-pgens/" "" + EXTRA_PGEN_NAME ${EXTRA_PGEN_NAME}) + list(APPEND PGEN_NAMES "pgens/${EXTRA_PGEN_NAME}") + endforeach() + if(${PGEN_FOUND} EQUAL -1) - set(pgen_path ${pgen_name}) - get_filename_component(pgen_path ${pgen_path} ABSOLUTE) - string(REGEX REPLACE ".*/" "" pgen_name ${pgen_name}) - list(APPEND PGEN_NAMES ${pgen_name}) + if(${pgen_name} MATCHES "^pgens/") + get_filename_component(pgen_name ${pgen_name} NAME) + set(pgen_path + "${CMAKE_CURRENT_SOURCE_DIR}/extern/entity-pgens/${pgen_name}") + set(pgen_name "pgens/${pgen_name}") + else() + set(pgen_path ${pgen_name}) + get_filename_component(pgen_path ${pgen_path} ABSOLUTE) + string(REGEX REPLACE ".*/" "" pgen_name ${pgen_name}) + list(APPEND PGEN_NAMES ${pgen_name}) + endif() else() set(pgen_path ${CMAKE_CURRENT_SOURCE_DIR}/pgens/${pgen_name}) endif() diff --git a/extern/entity-pgens b/extern/entity-pgens new file mode 160000 index 000000000..285aa9013 --- /dev/null +++ b/extern/entity-pgens @@ -0,0 +1 @@ +Subproject commit 285aa9013fecc32664797dab81384c3855a606dd From c1d82f1671a3816d4388fb5287722a218f73fad8 Mon Sep 17 00:00:00 2001 From: hayk Date: Wed, 14 May 2025 06:31:17 -0400 Subject: [PATCH 698/773] entity-pgens to master --- extern/entity-pgens | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extern/entity-pgens b/extern/entity-pgens index 285aa9013..386eefc80 160000 --- a/extern/entity-pgens +++ b/extern/entity-pgens @@ -1 +1 @@ -Subproject commit 285aa9013fecc32664797dab81384c3855a606dd +Subproject commit 386eefc80e2f63d0e29168869f881dd0b288952d From 1d2bb1b8902c306b81a962faf17cc87677fb40f8 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Mon, 19 May 2025 20:26:29 -0400 Subject: [PATCH 699/773] adjusted horizon BCs to work with nfilters>0; depleted aux horizon BCs --- src/kernels/fields_bcs.hpp | 66 +++++++++----------------------------- 1 file changed, 16 insertions(+), 50 deletions(-) diff --git a/src/kernels/fields_bcs.hpp b/src/kernels/fields_bcs.hpp index b3fb1761d..3f63b650a 100644 --- a/src/kernels/fields_bcs.hpp +++ b/src/kernels/fields_bcs.hpp @@ -908,70 +908,36 @@ namespace kernel::bc { } }; - template + template struct HorizonBoundaries_kernel { ndfield_t Fld; const std::size_t i1_min; const bool setE, setB; + const std::size_t nfilter; - HorizonBoundaries_kernel(ndfield_t Fld, std::size_t i1_min, BCTags tags) + HorizonBoundaries_kernel(ndfield_t Fld, std::size_t i1_min, BCTags tags, std::size_t nfilter) : Fld { Fld } , i1_min { i1_min } , setE { (tags & BC::Ex1 or tags & BC::Ex2 or tags & BC::Ex3) or (tags & BC::Dx1 or tags & BC::Dx2 or tags & BC::Dx3) } , setB { (tags & BC::Bx1 or tags & BC::Bx2 or tags & BC::Bx3) or - (tags & BC::Hx1 or tags & BC::Hx2 or tags & BC::Hx3) } {} + (tags & BC::Hx1 or tags & BC::Hx2 or tags & BC::Hx3) } + , nfilter { nfilter } {} Inline void operator()(index_t i2) const { if constexpr (M::Dim == Dim::_2D) { - if constexpr (not IsAux) { - if (setE) { - // Fld(i1_min - 1, i2, em::dx1) = Fld(i1_min, i2, em::dx1); - // Fld(i1_min, i2, em::dx2) = Fld(i1_min + 1, i2, em::dx2); - // Fld(i1_min - 1, i2, em::dx2) = Fld(i1_min, i2, em::dx2); - // Fld(i1_min, i2, em::dx3) = Fld(i1_min + 1, i2, em::dx3); - // Fld(i1_min - 1, i2, em::dx3) = Fld(i1_min, i2, em::dx3); - - Fld(i1_min , i2, em::dx1) = Fld(i1_min + 1, i2, em::dx1); - Fld(i1_min - 1, i2, em::dx1) = Fld(i1_min + 1, i2, em::dx1); - Fld(i1_min - 2, i2, em::dx1) = Fld(i1_min + 1, i2, em::dx1); - - Fld(i1_min , i2, em::dx2) = Fld(i1_min + 1, i2, em::dx2); - Fld(i1_min - 1, i2, em::dx2) = Fld(i1_min + 1, i2, em::dx2); - Fld(i1_min - 2, i2, em::dx2) = Fld(i1_min + 1, i2, em::dx2); - - Fld(i1_min , i2, em::dx3) = Fld(i1_min + 1, i2, em::dx3); - Fld(i1_min - 1, i2, em::dx3) = Fld(i1_min + 1, i2, em::dx3); - Fld(i1_min - 2, i2, em::dx3) = Fld(i1_min + 1, i2, em::dx3); - } - if (setB) { - // Fld(i1_min, i2, em::bx1) = Fld(i1_min + 1, i2, em::bx1); - // Fld(i1_min - 1, i2, em::bx1) = Fld(i1_min, i2, em::bx1); - // Fld(i1_min - 1, i2, em::bx2) = Fld(i1_min, i2, em::bx2); - // Fld(i1_min - 1, i2, em::bx3) = Fld(i1_min, i2, em::bx3); - - Fld(i1_min , i2, em::bx1) = Fld(i1_min + 1, i2, em::bx1); - Fld(i1_min - 1, i2, em::bx1) = Fld(i1_min + 1, i2, em::bx1); - Fld(i1_min - 2, i2, em::bx1) = Fld(i1_min + 1, i2, em::bx1); - - Fld(i1_min , i2, em::bx2) = Fld(i1_min + 1, i2, em::bx2); - Fld(i1_min - 1, i2, em::bx2) = Fld(i1_min + 1, i2, em::bx2); - Fld(i1_min - 2, i2, em::bx2) = Fld(i1_min + 1, i2, em::bx2); - - Fld(i1_min , i2, em::bx3) = Fld(i1_min + 1, i2, em::bx3); - Fld(i1_min - 1, i2, em::bx3) = Fld(i1_min + 1, i2, em::bx3); - Fld(i1_min - 2, i2, em::bx3) = Fld(i1_min + 1, i2, em::bx3); - } - } else { - if (setE) { - Fld(i1_min - 1, i2, em::ex1) = Fld(i1_min, i2, em::ex1); - Fld(i1_min - 1, i2, em::ex2) = Fld(i1_min, i2, em::ex2); - Fld(i1_min - 1, i2, em::ex3) = Fld(i1_min, i2, em::ex3); + if (setE) { + for (unsigned short i = 0; i <= 2 + nfilter; ++i) { + Fld(i1_min - N_GHOSTS + i, i2, em::dx1) = Fld(i1_min + 1 + nfilter, i2, em::dx1); + Fld(i1_min - N_GHOSTS + i, i2, em::dx2) = Fld(i1_min + 1 + nfilter, i2, em::dx2); + Fld(i1_min - N_GHOSTS + i, i2, em::dx3) = Fld(i1_min + 1 + nfilter, i2, em::dx3); } - if (setB) { - Fld(i1_min - 1, i2, em::hx1) = Fld(i1_min, i2, em::hx1); - Fld(i1_min - 1, i2, em::hx2) = Fld(i1_min, i2, em::hx2); - Fld(i1_min - 1, i2, em::hx3) = Fld(i1_min, i2, em::hx3); + } + if (setB) { + for (unsigned short i = 0; i <= 2 + nfilter; ++i) { + Fld(i1_min - N_GHOSTS + i, i2, em::bx1) = Fld(i1_min + 1 + nfilter, i2, em::bx1); + Fld(i1_min - N_GHOSTS + i, i2, em::bx2) = Fld(i1_min + 1 + nfilter, i2, em::bx2); + Fld(i1_min - N_GHOSTS + i, i2, em::bx3) = Fld(i1_min + 1 + nfilter, i2, em::bx3); } } } else { From 7ac1b68bb3abb7b6371db1f21a431664f631f6f7 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Mon, 19 May 2025 20:53:31 -0400 Subject: [PATCH 700/773] adjusted engine accordingly (previous below) --- src/engines/grpic.hpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index eb35be4b2..04197d12b 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -708,19 +708,23 @@ namespace ntt { const auto i1_min = domain.mesh.i_min(in::x1); auto range = CreateRangePolicy({ domain.mesh.i_min(in::x2) }, { domain.mesh.i_max(in::x2) + 1 }); + const auto nfilter = m_params.template get( + "algorithms.current_filters"); if (g == gr_bc::main) { Kokkos::parallel_for( "OpenBCFields", range, - kernel::bc::HorizonBoundaries_kernel(domain.fields.em, + kernel::bc::HorizonBoundaries_kernel(domain.fields.em, i1_min, - tags)); + tags, + nfilter)); Kokkos::parallel_for( "OpenBCFields", range, - kernel::bc::HorizonBoundaries_kernel(domain.fields.em0, + kernel::bc::HorizonBoundaries_kernel(domain.fields.em0, i1_min, - tags)); + tags, + nfilter)); } } From 612dbad5d86139061ae2ceabf4c1bcdc7eea317d Mon Sep 17 00:00:00 2001 From: gorbunove Date: Tue, 20 May 2025 14:45:42 -0500 Subject: [PATCH 701/773] turb bug fix --- pgens/turbulence/pgen.hpp | 93 ++++++++++++++++++++++++++------------- 1 file changed, 62 insertions(+), 31 deletions(-) diff --git a/pgens/turbulence/pgen.hpp b/pgens/turbulence/pgen.hpp index 4725d67db..4c4a2c78e 100644 --- a/pgens/turbulence/pgen.hpp +++ b/pgens/turbulence/pgen.hpp @@ -38,28 +38,48 @@ namespace user { Inline auto bx1(const coord_t& x_Ph) const -> real_t { auto bx1_0 = ZERO; - for (auto i = 0; i < n_modes; i++) { - auto k_dot_r = k(0, i) * x_Ph[0] + k(1, i) * x_Ph[1]; - bx1_0 -= TWO * k(1, i) * + if constexpr(D==Dim::_2D){ + for (auto i = 0; i < n_modes; i++) { + auto k_dot_r = k(0, i) * x_Ph[0] + k(1, i) * x_Ph[1]; + bx1_0 -= TWO * k(1, i) * (a_real(i) * math::sin(k_dot_r) + a_imag(i) * math::cos(k_dot_r)); - bx1_0 -= TWO * k(1, i) * + bx1_0 -= TWO * k(1, i) * (a_real_inv(i) * math::sin(k_dot_r) + a_imag_inv(i) * math::cos(k_dot_r)); + } + return bx1_0; + } + if constexpr (D==Dim::_3D){ + for (auto i = 0; i < n_modes; i++) { + auto k_dot_r = k(0, i) * x_Ph[0] + k(1, i) * x_Ph[1] + k(2, i) * x_Ph[2]; + bx1_0 -= TWO * k(1, i) * + (a_real(i) * math::sin(k_dot_r) + a_imag(i) * math::cos(k_dot_r)); + } + return bx1_0; } - return bx1_0; } Inline auto bx2(const coord_t& x_Ph) const -> real_t { auto bx2_0 = ZERO; - for (auto i = 0; i < n_modes; i++) { - auto k_dot_r = k(0, i) * x_Ph[0] + k(1, i) * x_Ph[1]; - bx2_0 += TWO * k(0, i) * - (a_real(i) * math::sin(k_dot_r) + a_imag(i) * math::cos(k_dot_r)); - bx2_0 += TWO * k(0, i) * - (a_real_inv(i) * math::sin(k_dot_r) + - a_imag_inv(i) * math::cos(k_dot_r)); + if constexpr (D==Dim::_2D){ + for (auto i = 0; i < n_modes; i++) { + auto k_dot_r = k(0, i) * x_Ph[0] + k(1, i) * x_Ph[1]; + bx2_0 += TWO * k(0, i) * + (a_real(i) * math::sin(k_dot_r) + a_imag(i) * math::cos(k_dot_r)); + bx2_0 += TWO * k(0, i) * + (a_real_inv(i) * math::sin(k_dot_r) + + a_imag_inv(i) * math::cos(k_dot_r)); + } + return bx2_0; + } + if constexpr (D==Dim::_3D){ + for (auto i = 0; i < n_modes; i++) { + auto k_dot_r = k(0, i) * x_Ph[0] + k(1, i) * x_Ph[1] + k(2, i) * x_Ph[2]; + bx2_0 += TWO * k(0, i) * + (a_real(i) * math::sin(k_dot_r) + a_imag(i) * math::cos(k_dot_r)); + } + return bx2_0; } - return bx2_0; } Inline auto bx3(const coord_t&) const -> real_t { @@ -97,10 +117,14 @@ namespace user { }; } else if constexpr (D == Dim::_3D) { return { - { 1, 0, 1 }, - { 0, 1, 1 }, - { -1, 0, 1 }, - { 0, -1, 1 } + { 1, 0, 1 }, + { 0, 1, 1 }, + { -1, 0, 1 }, + { 0, -1, 1 }, + { 1, 0,-1 }, + { 0, 1,-1 }, + { -1, 0,-1 }, + { 0, -1,-1 } }; } else { raise::Error("Invalid dimension", HERE); @@ -115,7 +139,7 @@ namespace user { real_t om0, real_t g0, std::vector>& wavenumbers, - random_number_pool_t& random_pool, + unsigned int seed, real_t Lx, real_t Ly, real_t Lz) @@ -125,6 +149,7 @@ namespace user { , Lx { Lx } , Ly { Ly } , Lz { Lz } + , seed { seed } , omega_0 { om0 } , gamma_0 { g0 } , k { "wavevector", D, n_modes } @@ -133,6 +158,8 @@ namespace user { , a_real_inv { "a_real_inv", n_modes } , a_imag_inv { "a_imag_inv", n_modes } , A0 { "A0", n_modes } { + // initializing random generator + srand(seed); // initializing wavevectors auto k_host = Kokkos::create_mirror_view(k); if constexpr (D == Dim::_2D) { @@ -159,16 +186,16 @@ namespace user { if constexpr (D == Dim::_2D) { prefac = HALF; // HALF = 1/sqrt(twice modes due to reality condition * twice the frequencies due to sign change) } else if constexpr (D == Dim::_3D) { - prefac = constant::SQRT2; // 1/sqrt(2) = 1/sqrt(twice modes due to reality condition) + prefac = ONE; } for (auto i = 0u; i < n_modes; i++) { auto k_perp = math::sqrt( k_host(0, i) * k_host(0, i) + k_host(1, i) * k_host(1, i)); - auto phase = constant::TWO_PI / 6.; + real_t phase = static_cast (rand()) / static_cast (RAND_MAX) * constant::TWO_PI; A0_host(i) = dB / math::sqrt((real_t)n_modes) / k_perp * prefac; a_real_host(i) = A0_host(i) * math::cos(phase); a_imag_host(i) = A0_host(i) * math::sin(phase); - phase = constant::TWO_PI / 3; + phase = static_cast (rand()) / static_cast (RAND_MAX) * constant::TWO_PI; a_imag_inv_host(i) = A0_host(i) * math::cos(phase); a_real_inv_host(i) = A0_host(i) * math::sin(phase); } @@ -190,8 +217,8 @@ namespace user { for (auto i = 0u; i < n_modes; i++) { auto k_dot_r = k(0, i) * x_Ph[0] + k(1, i) * x_Ph[1] + k(2, i) * x_Ph[2]; jx1_ant -= TWO * k(0, i) * k(2, i) * - (a_real_inv(i) * math::cos(k_dot_r) - - a_imag_inv(i) * math::sin(k_dot_r)); + (a_real(i) * math::cos(k_dot_r) - + a_imag(i) * math::sin(k_dot_r)); } return jx1_ant; } @@ -205,8 +232,8 @@ namespace user { for (auto i = 0u; i < n_modes; i++) { auto k_dot_r = k(0, i) * x_Ph[0] + k(1, i) * x_Ph[1] + k(2, i) * x_Ph[2]; jx2_ant -= TWO * k(1, i) * k(2, i) * - (a_real_inv(i) * math::cos(k_dot_r) - - a_imag_inv(i) * math::sin(k_dot_r)); + (a_real(i) * math::cos(k_dot_r) - + a_imag(i) * math::sin(k_dot_r)); } return jx2_ant; } @@ -232,8 +259,8 @@ namespace user { auto k_perp_sq = k(0, i) * k(0, i) + k(1, i) * k(1, i); auto k_dot_r = k(0, i) * x_Ph[0] + k(1, i) * x_Ph[1] + k(2, i) * x_Ph[2]; jx3_ant += TWO * k_perp_sq * - (a_real_inv(i) * math::cos(k_dot_r) - - a_imag_inv(i) * math::sin(k_dot_r)); + (a_real(i) * math::cos(k_dot_r) - + a_imag(i) * math::sin(k_dot_r)); } return jx3_ant; } @@ -243,6 +270,7 @@ namespace user { const std::vector> wavenumbers; const std::size_t n_modes; const real_t dB, Lx, Ly, Lz; + const int seed; public: const real_t omega_0, gamma_0; @@ -297,12 +325,12 @@ namespace user { , Lz { global_domain.mesh().extent(in::x3).second - global_domain.mesh().extent(in::x3).first } , escape_dist { p.template get("setup.escape_dist", HALF * Lx) } - , ext_current { dB, omega_0, gamma_0, wavenumbers, random_pool, Lx, Ly, Lz } + , ext_current { dB, omega_0, gamma_0, wavenumbers, init_pool(random_seed), Lx, Ly, Lz } , init_flds { ext_current.k, ext_current.a_real, ext_current.a_imag, ext_current.a_real_inv, - ext_current.a_imag_inv } {} + ext_current.a_imag_inv } {}; inline void InitPrtls(Domain& local_domain) { const auto energy_dist = arch::Maxwellian(local_domain.mesh.metric, @@ -319,6 +347,10 @@ namespace user { }; void CustomPostStep(timestep_t, simtime_t, Domain& domain) { + #if defined(MPI_ENABLED) + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + #endif // update amplitudes of antenna const auto dt = params.template get("algorithms.timestep.dt"); const auto& ext_curr = ext_current; @@ -378,7 +410,6 @@ namespace user { const auto& pld = domain.species[sp].pld; const auto& tag = domain.species[sp].tag; const auto L = escape_dist; - printf("Entering the escape loop %d, L = %f\n", sp, L); Kokkos::parallel_for( "UpdatePld", domain.species[sp].npart(), @@ -391,7 +422,7 @@ namespace user { pld(p, 0) += ux1(p) * dt / gamma; pld(p, 1) += ux2(p) * dt / gamma; - if (math::abs(pld(p, 0) > L) or (math::abs(pld(p,1)) > L)) { + if ((math::abs(pld(p, 0)) > L) or (math::abs(pld(p, 1)) > L)) { coord_t x_Ph { ZERO }; vec_t u_Mxw { ZERO }; energy_dist(x_Ph, u_Mxw); From 98e6ece593d44868efc37846bab6e84a417e047b Mon Sep 17 00:00:00 2001 From: hayk Date: Wed, 21 May 2025 14:30:45 -0400 Subject: [PATCH 702/773] rec -> periodic --- pgens/reconnection/reconnection.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pgens/reconnection/reconnection.toml b/pgens/reconnection/reconnection.toml index db3dbde72..62c1ffe80 100644 --- a/pgens/reconnection/reconnection.toml +++ b/pgens/reconnection/reconnection.toml @@ -11,8 +11,8 @@ metric = "minkowski" [grid.boundaries] - fields = [["MATCH", "MATCH"], ["MATCH", "MATCH"], ["PERIODIC"]] - particles = [["ABSORB", "ABSORB"], ["ABSORB", "ABSORB"], ["PERIODIC"]] + fields = [["PERIODIC"], ["MATCH", "MATCH"], ["PERIODIC"]] + particles = [["PERIODIC"], ["ABSORB", "ABSORB"], ["PERIODIC"]] [scales] larmor0 = 2e-4 From b5a651e43c9eda7193d106b9f676155bf4d88868 Mon Sep 17 00:00:00 2001 From: haykh Date: Thu, 1 May 2025 21:31:07 -0400 Subject: [PATCH 703/773] stats reduction for flds --- src/engines/engine.hpp | 1 - src/framework/domain/checkpoint.cpp | 106 ++++++- src/framework/domain/communications.cpp | 100 ++++++- src/framework/domain/grid.cpp | 8 +- src/framework/domain/metadomain.cpp | 1 - src/framework/domain/metadomain.h | 8 +- src/framework/domain/output.cpp | 128 +++++++- src/framework/domain/stats.cpp | 181 +++++++++-- src/global/enums.h | 2 + src/kernels/reduced_stats.hpp | 381 ++++++++++++++++++++++++ src/output/stats.cpp | 4 +- src/output/stats.h | 54 +++- 12 files changed, 895 insertions(+), 79 deletions(-) create mode 100644 src/kernels/reduced_stats.hpp diff --git a/src/engines/engine.hpp b/src/engines/engine.hpp index 9525874a6..5956ea5d9 100644 --- a/src/engines/engine.hpp +++ b/src/engines/engine.hpp @@ -23,7 +23,6 @@ #include "arch/traits.h" #include "utils/error.h" -#include "utils/progressbar.h" #include "utils/timer.h" #include "utils/toml.h" diff --git a/src/framework/domain/checkpoint.cpp b/src/framework/domain/checkpoint.cpp index 656ff57d0..25cdcf0f6 100644 --- a/src/framework/domain/checkpoint.cpp +++ b/src/framework/domain/checkpoint.cpp @@ -474,13 +474,103 @@ namespace ntt { HERE); } - template struct Metadomain>; - template struct Metadomain>; - template struct Metadomain>; - template struct Metadomain>; - template struct Metadomain>; - template struct Metadomain>; - template struct Metadomain>; - template struct Metadomain>; + template void Metadomain>::InitCheckpointWriter( + adios2::ADIOS*, + const SimulationParams&); + template void Metadomain>::InitCheckpointWriter( + adios2::ADIOS*, + const SimulationParams&); + template void Metadomain>::InitCheckpointWriter( + adios2::ADIOS*, + const SimulationParams&); + template void Metadomain>::InitCheckpointWriter( + adios2::ADIOS*, + const SimulationParams&); + template void Metadomain>::InitCheckpointWriter( + adios2::ADIOS*, + const SimulationParams&); + template void Metadomain>::InitCheckpointWriter( + adios2::ADIOS*, + const SimulationParams&); + template void Metadomain>::InitCheckpointWriter( + adios2::ADIOS*, + const SimulationParams&); + template void Metadomain>::InitCheckpointWriter( + adios2::ADIOS*, + const SimulationParams&); + + template auto Metadomain>::WriteCheckpoint( + const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t) -> bool; + template auto Metadomain>::WriteCheckpoint( + const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t) -> bool; + template auto Metadomain>::WriteCheckpoint( + const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t) -> bool; + template auto Metadomain>::WriteCheckpoint( + const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t) -> bool; + template auto Metadomain>::WriteCheckpoint( + const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t) -> bool; + template auto Metadomain>::WriteCheckpoint( + const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t) -> bool; + template auto Metadomain>::WriteCheckpoint( + const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t) -> bool; + template auto Metadomain>::WriteCheckpoint( + const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t) -> bool; + + template void Metadomain>::ContinueFromCheckpoint( + adios2::ADIOS*, + const SimulationParams&); + template void Metadomain>::ContinueFromCheckpoint( + adios2::ADIOS*, + const SimulationParams&); + template void Metadomain>::ContinueFromCheckpoint( + adios2::ADIOS*, + const SimulationParams&); + template void Metadomain>::ContinueFromCheckpoint( + adios2::ADIOS*, + const SimulationParams&); + template void Metadomain>::ContinueFromCheckpoint( + adios2::ADIOS*, + const SimulationParams&); + template void Metadomain>::ContinueFromCheckpoint( + adios2::ADIOS*, + const SimulationParams&); + template void Metadomain>::ContinueFromCheckpoint( + adios2::ADIOS*, + const SimulationParams&); + template void Metadomain>::ContinueFromCheckpoint( + adios2::ADIOS*, + const SimulationParams&); } // namespace ntt diff --git a/src/framework/domain/communications.cpp b/src/framework/domain/communications.cpp index 841c9a7da..23bb5b88c 100644 --- a/src/framework/domain/communications.cpp +++ b/src/framework/domain/communications.cpp @@ -641,13 +641,95 @@ namespace ntt { } } - template struct Metadomain>; - template struct Metadomain>; - template struct Metadomain>; - template struct Metadomain>; - template struct Metadomain>; - template struct Metadomain>; - template struct Metadomain>; - template struct Metadomain>; - + template void Metadomain>::CommunicateFields( + Domain>&, + CommTags); + template void Metadomain>::CommunicateFields( + Domain>&, + CommTags); + template void Metadomain>::CommunicateFields( + Domain>&, + CommTags); + template void Metadomain>::CommunicateFields( + Domain>&, + CommTags); + template void Metadomain>::CommunicateFields( + Domain>&, + CommTags); + template void Metadomain>::CommunicateFields( + Domain>&, + CommTags); + template void Metadomain>::CommunicateFields( + Domain>&, + CommTags); + template void Metadomain>::CommunicateFields( + Domain>&, + CommTags); + + template void Metadomain>::SynchronizeFields( + Domain>&, + CommTags, + const range_tuple_t&); + template void Metadomain>::SynchronizeFields( + Domain>&, + CommTags, + const range_tuple_t&); + template void Metadomain>::SynchronizeFields( + Domain>&, + CommTags, + const range_tuple_t&); + template void Metadomain>::SynchronizeFields( + Domain>&, + CommTags, + const range_tuple_t&); + template void Metadomain>::SynchronizeFields( + Domain>&, + CommTags, + const range_tuple_t&); + template void Metadomain>::SynchronizeFields( + Domain>&, + CommTags, + const range_tuple_t&); + template void Metadomain>::SynchronizeFields( + Domain>&, + CommTags, + const range_tuple_t&); + template void Metadomain>::SynchronizeFields( + Domain>&, + CommTags, + const range_tuple_t&); + + template void Metadomain>::CommunicateParticles( + Domain>&); + template void Metadomain>::CommunicateParticles( + Domain>&); + template void Metadomain>::CommunicateParticles( + Domain>&); + template void Metadomain>::CommunicateParticles( + Domain>&); + template void Metadomain>::CommunicateParticles( + Domain>&); + template void Metadomain>::CommunicateParticles( + Domain>&); + template void Metadomain>::CommunicateParticles( + Domain>&); + template void Metadomain>::CommunicateParticles( + Domain>&); + + template void Metadomain>::RemoveDeadParticles( + Domain>&); + template void Metadomain>::RemoveDeadParticles( + Domain>&); + template void Metadomain>::RemoveDeadParticles( + Domain>&); + template void Metadomain>::RemoveDeadParticles( + Domain>&); + template void Metadomain>::RemoveDeadParticles( + Domain>&); + template void Metadomain>::RemoveDeadParticles( + Domain>&); + template void Metadomain>::RemoveDeadParticles( + Domain>&); + template void Metadomain>::RemoveDeadParticles( + Domain>&); } // namespace ntt diff --git a/src/framework/domain/grid.cpp b/src/framework/domain/grid.cpp index ddbfc38f0..f087df6f5 100644 --- a/src/framework/domain/grid.cpp +++ b/src/framework/domain/grid.cpp @@ -86,8 +86,8 @@ namespace ntt { } template - auto Grid::rangeCellsOnHost(const box_region_t& region) const - -> range_h_t { + auto Grid::rangeCellsOnHost( + const box_region_t& region) const -> range_h_t { tuple_t imin, imax; for (auto i { 0u }; i < D; i++) { switch (region[i]) { @@ -163,8 +163,8 @@ namespace ntt { } template - auto Grid::rangeCells(const tuple_t, D>& ranges) const - -> range_t { + auto Grid::rangeCells( + const tuple_t, D>& ranges) const -> range_t { tuple_t imin, imax; for (auto i { 0u }; i < D; i++) { raise::ErrorIf((ranges[i][0] < -(int)N_GHOSTS) || diff --git a/src/framework/domain/metadomain.cpp b/src/framework/domain/metadomain.cpp index 4b9057e23..a0326913b 100644 --- a/src/framework/domain/metadomain.cpp +++ b/src/framework/domain/metadomain.cpp @@ -23,7 +23,6 @@ #include #include -#include #include #include diff --git a/src/framework/domain/metadomain.h b/src/framework/domain/metadomain.h index 1fb6ce007..363b164d3 100644 --- a/src/framework/domain/metadomain.h +++ b/src/framework/domain/metadomain.h @@ -19,7 +19,6 @@ #include "global.h" #include "arch/kokkos_aliases.h" -#include "utils/timer.h" #include "framework/containers/species.h" #include "framework/domain/domain.h" @@ -138,8 +137,11 @@ namespace ntt { #endif void InitStatsWriter(const SimulationParams&, bool); - auto WriteStats(const SimulationParams&, timestep_t, timestep_t, simtime_t, simtime_t) - -> bool; + auto WriteStats(const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t) -> bool; /* setters -------------------------------------------------------------- */ void setFldsBC(const bc_in&, const FldsBC&); diff --git a/src/framework/domain/output.cpp b/src/framework/domain/output.cpp index 6903c7194..99987989e 100644 --- a/src/framework/domain/output.cpp +++ b/src/framework/domain/output.cpp @@ -708,13 +708,125 @@ namespace ntt { return true; } - template struct Metadomain>; - template struct Metadomain>; - template struct Metadomain>; - template struct Metadomain>; - template struct Metadomain>; - template struct Metadomain>; - template struct Metadomain>; - template struct Metadomain>; + template void Metadomain>::InitWriter( + adios2::ADIOS*, + const SimulationParams&, + bool); + template void Metadomain>::InitWriter( + adios2::ADIOS*, + const SimulationParams&, + bool); + template void Metadomain>::InitWriter( + adios2::ADIOS*, + const SimulationParams&, + bool); + template void Metadomain>::InitWriter( + adios2::ADIOS*, + const SimulationParams&, + bool); + template void Metadomain>::InitWriter( + adios2::ADIOS*, + const SimulationParams&, + bool); + template void Metadomain>::InitWriter( + adios2::ADIOS*, + const SimulationParams&, + bool); + template void Metadomain>::InitWriter( + adios2::ADIOS*, + const SimulationParams&, + bool); + template void Metadomain>::InitWriter( + adios2::ADIOS*, + const SimulationParams&, + bool); + template auto Metadomain>::Write( + const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t, + std::function&, + std::size_t, + const Domain>&)>) + -> bool; + template auto Metadomain>::Write( + const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t, + std::function&, + std::size_t, + const Domain>&)>) + -> bool; + template auto Metadomain>::Write( + const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t, + std::function&, + std::size_t, + const Domain>&)>) + -> bool; + template auto Metadomain>::Write( + const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t, + std::function&, + std::size_t, + const Domain>&)>) + -> bool; + template auto Metadomain>::Write( + const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t, + std::function&, + std::size_t, + const Domain>&)>) + -> bool; + template auto Metadomain>::Write( + const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t, + std::function&, + std::size_t, + const Domain>&)>) + -> bool; + template auto Metadomain>::Write( + const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t, + std::function&, + std::size_t, + const Domain>&)>) + -> bool; + template auto Metadomain>::Write( + const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t, + std::function&, + std::size_t, + const Domain>&)>) + -> bool; } // namespace ntt diff --git a/src/framework/domain/stats.cpp b/src/framework/domain/stats.cpp index 60acd64a9..cf7613bdb 100644 --- a/src/framework/domain/stats.cpp +++ b/src/framework/domain/stats.cpp @@ -18,6 +18,8 @@ #include "framework/domain/metadomain.h" #include "framework/parameters.h" +#include "kernels/reduced_stats.hpp" + #include #include #include @@ -107,17 +109,63 @@ namespace ntt { } template - auto ComputeFields(Domain* domain, - const std::vector& components) -> real_t { + auto ReduceFields(Domain* domain, + const std::vector& components) -> real_t { auto buffer { ZERO }; - // Kokkos::parallel_reduce( - // "ComputeMoments", - // prtl_spec.rangeActiveParticles(), - // kernel::ReducedFields_kernel(components, - // domain->fields.em, - // domain->fields.cur, - // domain->mesh.metric), - // buffer); + if constexpr (F == StatsID::JdotE) { + if (components.size() == 0) { + Kokkos::parallel_reduce( + "ReduceFields", + domain->mesh.rangeActiveCells(), + kernel::ReducedFields_kernel(domain->fields.em, + domain->fields.cur, + domain->mesh.metric), + buffer); + } else { + raise::Error("Components not supported for JdotE", HERE); + } + } else if constexpr ( + (S == SimEngine::SRPIC) and + (F == StatsID::B2 or F == StatsID::E2 or F == StatsID::ExB)) { + raise::ErrorIf(components.size() != 1, + "Components must be of size 1 for B2, E2 or ExB stats", + HERE); + const auto comp = components[0]; + if (comp == 1) { + Kokkos::parallel_reduce( + "ReduceFields", + domain->mesh.rangeActiveCells(), + kernel::ReducedFields_kernel(domain->fields.em, + domain->fields.cur, + domain->mesh.metric), + buffer); + } else if (comp == 2) { + Kokkos::parallel_reduce( + "ReduceFields", + domain->mesh.rangeActiveCells(), + kernel::ReducedFields_kernel(domain->fields.em, + domain->fields.cur, + domain->mesh.metric), + buffer); + } else if (comp == 3) { + Kokkos::parallel_reduce( + "ReduceFields", + domain->mesh.rangeActiveCells(), + kernel::ReducedFields_kernel(domain->fields.em, + domain->fields.cur, + domain->mesh.metric), + buffer); + } else { + raise::Error( + "Invalid component for B2, E2 or ExB stats: " + std::to_string(comp), + HERE); + } + } else { + raise::Error("ReduceFields not implemented for this stats ID + SimEngine " + "combination", + HERE); + } + return buffer; } @@ -174,31 +222,108 @@ namespace ntt { comp)); } } else if (stat.id() == StatsID::JdotE) { - g_stats_writer.write(ComputeFields(local_domain, {})); - } else if (stat.id() == StatsID::E2) { - g_stats_writer.write(ComputeFields(local_domain, {})); - } else if (stat.id() == StatsID::B2) { - g_stats_writer.write(ComputeFields(local_domain, {})); - } else if (stat.id() == StatsID::ExB) { - for (const auto& comp : stat.comp) { - g_stats_writer.write( - ComputeFields(local_domain, comp)); + g_stats_writer.write(ReduceFields(local_domain, {})); + } else if (S == SimEngine::SRPIC) { + if (stat.id() == StatsID::E2) { + for (const auto& comp : stat.comp) { + g_stats_writer.write( + ReduceFields(local_domain, comp)); + } + } else if (stat.id() == StatsID::B2) { + for (const auto& comp : stat.comp) { + g_stats_writer.write( + ReduceFields(local_domain, comp)); + } + } else if (stat.id() == StatsID::ExB) { + for (const auto& comp : stat.comp) { + g_stats_writer.write( + ReduceFields(local_domain, comp)); + } + } else { + raise::Error("Unrecognized stats ID " + stat.name(), HERE); } } else { - raise::Error("Unrecognized stats ID " + stat.name(), HERE); + raise::Error("StatsID not implemented for particular SimEngine: " + + std::to_string(static_cast(S)), + HERE); } } g_stats_writer.endWriting(); return true; } - template struct Metadomain>; - template struct Metadomain>; - template struct Metadomain>; - template struct Metadomain>; - template struct Metadomain>; - template struct Metadomain>; - template struct Metadomain>; - template struct Metadomain>; + template void Metadomain>::InitStatsWriter( + const SimulationParams&, + bool); + template void Metadomain>::InitStatsWriter( + const SimulationParams&, + bool); + template void Metadomain>::InitStatsWriter( + const SimulationParams&, + bool); + template void Metadomain>::InitStatsWriter( + const SimulationParams&, + bool); + template void Metadomain>::InitStatsWriter( + const SimulationParams&, + bool); + template void Metadomain>::InitStatsWriter( + const SimulationParams&, + bool); + template void Metadomain>::InitStatsWriter( + const SimulationParams&, + bool); + template void Metadomain>::InitStatsWriter( + const SimulationParams&, + bool); + + template auto Metadomain>::WriteStats( + const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t) -> bool; + template auto Metadomain>::WriteStats( + const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t) -> bool; + template auto Metadomain>::WriteStats( + const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t) -> bool; + template auto Metadomain>::WriteStats( + const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t) -> bool; + template auto Metadomain>::WriteStats( + const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t) -> bool; + template auto Metadomain>::WriteStats( + const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t) -> bool; + template auto Metadomain>::WriteStats( + const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t) -> bool; + template auto Metadomain>::WriteStats( + const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t) -> bool; } // namespace ntt diff --git a/src/global/enums.h b/src/global/enums.h index 7e06d4a8d..8796fe310 100644 --- a/src/global/enums.h +++ b/src/global/enums.h @@ -14,6 +14,8 @@ * - enum ntt::Cooling // synchrotron, none * - enum ntt::FldsID // e, dive, d, divd, b, h, j, * a, t, rho, charge, n, nppc, v, custom + * - enum ntt::StatsID // b^2, e^2, exb, j.e, t, rho, + * charge, n, npart * @namespaces: * - ntt:: * @note Enums of the same type can be compared with each other and with strings diff --git a/src/kernels/reduced_stats.hpp b/src/kernels/reduced_stats.hpp new file mode 100644 index 000000000..373f06eb0 --- /dev/null +++ b/src/kernels/reduced_stats.hpp @@ -0,0 +1,381 @@ +/** + * @file kernels/reduced_stats.hpp + * @brief Compute reduced field/moment quantities for stats output + * @implements + * - kernel::PrtlToPhys_kernel<> + * @namespaces: + * - kernel:: + */ + +#ifndef KERNELS_REDUCED_STATS_HPP +#define KERNELS_REDUCED_STATS_HPP + +#include "enums.h" +#include "global.h" + +#include "arch/kokkos_aliases.h" +#include "utils/numeric.h" + +namespace kernel { + using namespace ntt; + + template + class ReducedFields_kernel { + static_assert(M::is_metric, "M must be a metric class"); + static_assert(I <= 3, + "I must be less than or equal to 3 for ReducedFields_kernel"); + static constexpr auto D = M::Dim; + + ndfield_t EM; + ndfield_t J; + const M metric; + + public: + ReducedFields_kernel(const ndfield_t& EM, + const ndfield_t& J, + const M& metric) + : EM { EM } + , J { J } + , metric { metric } {} + + Inline void operator()(index_t i1, real_t& buff) const { + const auto i1_ = COORD(i1); + if constexpr (F == StatsID::B2) { + if constexpr (I == 1) { + const auto b1_u = EM(i1, em::bx1); + const auto b1_d = metric.template transform<1, Idx::U, Idx::D>({ i1_ }, + b1_u); + buff += b1_u * b1_d; + } else if constexpr (I == 2) { + const auto b2_u = EM(i1, em::bx2); + const auto b2_d = metric.template transform<2, Idx::U, Idx::D>( + { i1_ + HALF }, + b2_u); + buff += b2_u * b2_d; + } else { + const auto b3_u = EM(i1, em::bx3); + const auto b3_d = metric.template transform<3, Idx::U, Idx::D>( + { i1_ + HALF }, + b3_u); + buff += b3_u * b3_d; + } + } else if constexpr (F == StatsID::E2) { + if constexpr (I == 1) { + const auto e1_u = EM(i1, em::ex1); + const auto e1_d = metric.template transform<1, Idx::U, Idx::D>( + { i1_ + HALF }, + e1_u); + buff += e1_u * e1_d; + } else if constexpr (I == 2) { + const auto e2_u = EM(i1, em::ex2); + const auto e2_d = metric.template transform<2, Idx::U, Idx::D>({ i1_ }, + e2_u); + buff += e2_u * e2_d; + } else { + const auto e3_u = EM(i1, em::ex3); + const auto e3_d = metric.template transform<3, Idx::U, Idx::D>({ i1_ }, + e3_u); + buff += e3_u * e3_d; + } + } else if constexpr (F == StatsID::ExB) { + if constexpr (I == 1) { + const auto e2_t = metric.template transform<2, Idx::U, Idx::T>( + { i1_ + HALF }, + HALF * (EM(i1, em::ex2) + EM(i1 + 1, em::ex2))); + const auto e3_t = metric.template transform<3, Idx::U, Idx::T>( + { i1_ + HALF }, + HALF * (EM(i1, em::ex3) + EM(i1 + 1, em::ex3))); + const auto b2_t = metric.template transform<2, Idx::U, Idx::T>( + { i1_ + HALF }, + EM(i1, em::bx2)); + const auto b3_t = metric.template transform<3, Idx::U, Idx::T>( + { i1_ + HALF }, + EM(i1, em::bx3)); + buff += e2_t * b3_t - e3_t * b2_t; + } else if constexpr (I == 2) { + const auto e1_t = metric.template transform<1, Idx::U, Idx::T>( + { i1_ + HALF }, + EM(i1, em::ex1)); + const auto e3_t = metric.template transform<3, Idx::U, Idx::T>( + { i1_ + HALF }, + HALF * (EM(i1, em::ex3) + EM(i1 + 1, em::ex3))); + const auto b1_t = metric.template transform<1, Idx::U, Idx::T>( + { i1_ + HALF }, + HALF * (EM(i1, em::bx1) + EM(i1 + 1, em::bx1))); + const auto b3_t = metric.template transform<3, Idx::U, Idx::T>( + { i1_ + HALF }, + EM(i1, em::bx3)); + buff += e3_t * b1_t - e1_t * b3_t; + } else { + const auto e1_t = metric.template transform<1, Idx::U, Idx::T>( + { i1_ + HALF }, + EM(i1, em::ex1)); + const auto e2_t = metric.template transform<2, Idx::U, Idx::T>( + { i1_ + HALF }, + HALF * (EM(i1, em::ex2) + EM(i1 + 1, em::ex2))); + const auto b1_t = metric.template transform<1, Idx::U, Idx::T>( + { i1_ + HALF }, + HALF * (EM(i1, em::bx1) + EM(i1 + 1, em::bx1))); + const auto b2_t = metric.template transform<2, Idx::U, Idx::T>( + { i1_ + HALF }, + EM(i1, em::bx2)); + buff += e1_t * b2_t - e2_t * b1_t; + } + } else if constexpr (F == StatsID::JdotE) { + vec_t e_t { ZERO }; + vec_t j_t { ZERO }; + metric.template transform( + { i1_ + HALF }, + { EM(i1, em::ex1), + HALF * (EM(i1, em::ex2) + EM(i1 + 1, em::ex2)), + HALF * (EM(i1, em::ex3) + EM(i1 + 1, em::ex3)) }, + e_t); + metric.template transform( + { i1_ + HALF }, + { J(i1, cur::jx1), + HALF * (J(i1, cur::jx2) + J(i1 + 1, cur::jx2)), + HALF * (J(i1, cur::jx3) + J(i1 + 1, cur::jx3)) }, + j_t); + buff += e_t[0] * j_t[0] + e_t[1] * j_t[1] + e_t[2] * j_t[2]; + } + } + + Inline void operator()(index_t i1, index_t i2, real_t& buff) const { + const auto i1_ = COORD(i1); + const auto i2_ = COORD(i2); + if constexpr (F == StatsID::B2) { + if constexpr (I == 1) { + const auto b1_u = EM(i1, i2, em::bx1); + const auto b1_d = metric.template transform<1, Idx::U, Idx::D>( + { i1_, i2_ + HALF }, + b1_u); + buff += b1_u * b1_d; + } else if constexpr (I == 2) { + const auto b2_u = EM(i1, i2, em::bx2); + const auto b2_d = metric.template transform<2, Idx::U, Idx::D>( + { i1_ + HALF, i2_ }, + b2_u); + buff += b2_u * b2_d; + } else { + const auto b3_u = EM(i1, i2, em::bx3); + const auto b3_d = metric.template transform<3, Idx::U, Idx::D>( + { i1_ + HALF, i2_ + HALF }, + b3_u); + buff += b3_u * b3_d; + } + } else if constexpr (F == StatsID::E2) { + if constexpr (I == 1) { + const auto e1_u = EM(i1, i2, em::ex1); + const auto e1_d = metric.template transform<1, Idx::U, Idx::D>( + { i1_ + HALF, i2_ }, + e1_u); + buff += e1_u * e1_d; + } else if constexpr (I == 2) { + const auto e2_u = EM(i1, i2, em::ex2); + const auto e2_d = metric.template transform<2, Idx::U, Idx::D>( + { i1_, i2_ + HALF }, + e2_u); + buff += e2_u * e2_d; + } else { + const auto e3_u = EM(i1, i2, em::ex3); + const auto e3_d = metric.template transform<3, Idx::U, Idx::D>( + { i1_, i2_ }, + e3_u); + buff += e3_u * e3_d; + } + } else if constexpr (F == StatsID::ExB) { + if constexpr (I == 1) { + const auto e2_t = metric.template transform<2, Idx::U, Idx::T>( + { i1_ + HALF, i2_ + HALF }, + HALF * (EM(i1, i2, em::ex2) + EM(i1 + 1, i2, em::ex2))); + const auto e3_t = metric.template transform<3, Idx::U, Idx::T>( + { i1_ + HALF, i2_ + HALF }, + INV_4 * (EM(i1, i2, em::ex3) + EM(i1 + 1, i2, em::ex3) + + EM(i1, i2 + 1, em::ex3) + EM(i1 + 1, i2 + 1, em::ex3))); + const auto b2_t = metric.template transform<2, Idx::U, Idx::T>( + { i1_ + HALF, i2_ + HALF }, + HALF * (EM(i1, i2, em::bx2) + EM(i1, i2 + 1, em::bx2))); + const auto b3_t = metric.template transform<3, Idx::U, Idx::T>( + { i1_ + HALF, i2_ + HALF }, + EM(i1, i2, em::bx3)); + buff += e2_t * b3_t - e3_t * b2_t; + } else if constexpr (I == 2) { + const auto e1_t = metric.template transform<1, Idx::U, Idx::T>( + { i1_ + HALF, i2_ + HALF }, + HALF * (EM(i1, i2, em::ex1) + EM(i1, i2 + 1, em::ex1))); + const auto e3_t = metric.template transform<3, Idx::U, Idx::T>( + { i1_ + HALF, i2_ + HALF }, + INV_4 * (EM(i1, i2, em::ex3) + EM(i1 + 1, i2, em::ex3) + + EM(i1, i2 + 1, em::ex3) + EM(i1 + 1, i2 + 1, em::ex3))); + const auto b1_t = metric.template transform<1, Idx::U, Idx::T>( + { i1_ + HALF, i2_ + HALF }, + HALF * (EM(i1, i2, em::bx1) + EM(i1 + 1, i2, em::bx1))); + const auto b3_t = metric.template transform<3, Idx::U, Idx::T>( + { i1_ + HALF, i2_ + HALF }, + EM(i1, i2, em::bx3)); + buff += e3_t * b1_t - e1_t * b3_t; + } else { + const auto e1_t = metric.template transform<1, Idx::U, Idx::T>( + { i1_ + HALF, i2_ + HALF }, + HALF * (EM(i1, i2, em::ex1) + EM(i1, i2 + 1, em::ex1))); + const auto e2_t = metric.template transform<2, Idx::U, Idx::T>( + { i1_ + HALF, i2_ + HALF }, + HALF * (EM(i1, i2, em::ex2) + EM(i1 + 1, i2, em::ex2))); + const auto b1_t = metric.template transform<1, Idx::U, Idx::T>( + { i1_ + HALF, i2_ + HALF }, + HALF * (EM(i1, i2, em::bx1) + EM(i1 + 1, i2, em::bx1))); + const auto b2_t = metric.template transform<2, Idx::U, Idx::T>( + { i1_ + HALF, i2_ + HALF }, + HALF * (EM(i1, i2, em::bx2) + EM(i1, i2 + 1, em::bx2))); + buff += e1_t * b2_t - e2_t * b1_t; + } + } else if constexpr (F == StatsID::JdotE) { + vec_t e_t { ZERO }; + vec_t j_t { ZERO }; + metric.template transform( + { i1_ + HALF, i2_ + HALF }, + { HALF * (EM(i1, i2, em::ex1) + EM(i1, i2 + 1, em::ex1)), + HALF * (EM(i1, i2, em::ex2) + EM(i1 + 1, i2, em::ex2)), + INV_4 * (EM(i1, i2, em::ex3) + EM(i1 + 1, i2, em::ex3) + + EM(i1, i2 + 1, em::ex3) + EM(i1 + 1, i2 + 1, em::ex3)) }, + e_t); + metric.template transform( + { i1_ + HALF, i2_ + HALF }, + { HALF * (J(i1, i2, cur::jx1) + J(i1, i2 + 1, cur::jx1)), + HALF * (J(i1, i2, cur::jx2) + J(i1 + 1, i2, cur::jx2)), + INV_4 * (J(i1, i2, cur::jx3) + J(i1 + 1, i2, cur::jx3) + + J(i1, i2 + 1, cur::jx3) + J(i1 + 1, i2 + 1, cur::jx3)) }, + j_t); + buff += e_t[0] * j_t[0] + e_t[1] * j_t[1] + e_t[2] * j_t[2]; + } + } + + Inline void operator()(index_t i1, index_t i2, index_t i3, real_t& buff) const { + const auto i1_ = COORD(i1); + const auto i2_ = COORD(i2); + const auto i3_ = COORD(i3); + if constexpr (F == StatsID::B2) { + if constexpr (I == 1) { + const auto b1_u = EM(i1, i2, i3, em::bx1); + const auto b1_d = metric.template transform<1, Idx::U, Idx::D>( + { i1_, i2_ + HALF, i3_ + HALF }, + b1_u); + buff += b1_u * b1_d; + } else if constexpr (I == 2) { + const auto b2_u = EM(i1, i2, i3, em::bx2); + const auto b2_d = metric.template transform<2, Idx::U, Idx::D>( + { i1_ + HALF, i2_, i3_ + HALF }, + b2_u); + buff += b2_u * b2_d; + } else { + const auto b3_u = EM(i1, i2, i3, em::bx3); + const auto b3_d = metric.template transform<3, Idx::U, Idx::D>( + { i1_ + HALF, i2_ + HALF, i3_ }, + b3_u); + buff += b3_u * b3_d; + } + } else if constexpr (F == StatsID::E2) { + if constexpr (I == 1) { + const auto e1_u = EM(i1, i2, i3, em::ex1); + const auto e1_d = metric.template transform<1, Idx::U, Idx::D>( + { i1_ + HALF, i2_, i3_ }, + e1_u); + buff += e1_u * e1_d; + } else if constexpr (I == 2) { + const auto e2_u = EM(i1, i2, i3, em::ex2); + const auto e2_d = metric.template transform<2, Idx::U, Idx::D>( + { i1_, i2_ + HALF, i3_ }, + e2_u); + buff += e2_u * e2_d; + } else { + const auto e3_u = EM(i1, i2, i3, em::ex3); + const auto e3_d = metric.template transform<3, Idx::U, Idx::D>( + { i1_, i2_, i3_ + HALF }, + e3_u); + buff += e3_u * e3_d; + } + } else if constexpr (F == StatsID::ExB) { + if constexpr (I == 1) { + const auto e2_t = metric.template transform<2, Idx::U, Idx::T>( + { i1_ + HALF, i2_ + HALF, i3_ + HALF }, + INV_4 * + (EM(i1, i2, i3, em::ex2) + EM(i1 + 1, i2, i3, em::ex2) + + EM(i1, i2, i3 + 1, em::ex2) + EM(i1 + 1, i2, i3 + 1, em::ex2))); + const auto e3_t = metric.template transform<3, Idx::U, Idx::T>( + { i1_ + HALF, i2_ + HALF, i3_ + HALF }, + INV_4 * + (EM(i1, i2, i3, em::ex3) + EM(i1 + 1, i2, i3, em::ex3) + + EM(i1, i2 + 1, i3, em::ex3) + EM(i1 + 1, i2 + 1, i3, em::ex3))); + const auto b2_t = metric.template transform<2, Idx::U, Idx::T>( + { i1_ + HALF, i2_ + HALF, i3_ + HALF }, + HALF * (EM(i1, i2, i3, em::bx2) + EM(i1, i2 + 1, i3, em::bx2))); + const auto b3_t = metric.template transform<3, Idx::U, Idx::T>( + { i1_ + HALF, i2_ + HALF, i3_ + HALF }, + HALF * (EM(i1, i2, i3, em::bx3) + EM(i1, i2, i3 + 1, em::bx3))); + buff += e2_t * b3_t - e3_t * b2_t; + } else if constexpr (I == 2) { + const auto e1_t = metric.template transform<1, Idx::U, Idx::T>( + { i1_ + HALF, i2_ + HALF, i3_ + HALF }, + INV_4 * + (EM(i1, i2, i3, em::ex1) + EM(i1, i2 + 1, i3, em::ex1) + + EM(i1, i2, i3 + 1, em::ex1) + EM(i1, i2 + 1, i3 + 1, em::ex1))); + const auto e3_t = metric.template transform<3, Idx::U, Idx::T>( + { i1_ + HALF, i2_ + HALF, i3_ + HALF }, + INV_4 * + (EM(i1, i2, i3, em::ex3) + EM(i1 + 1, i2, i3, em::ex3) + + EM(i1, i2 + 1, i3, em::ex3) + EM(i1 + 1, i2 + 1, i3, em::ex3))); + const auto b1_t = metric.template transform<1, Idx::U, Idx::T>( + { i1_ + HALF, i2_ + HALF, i3_ + HALF }, + HALF * (EM(i1, i2, i3, em::bx1) + EM(i1 + 1, i2, i3, em::bx1))); + const auto b3_t = metric.template transform<3, Idx::U, Idx::T>( + { i1_ + HALF, i2_ + HALF, i3_ + HALF }, + HALF * (EM(i1, i2, i3, em::bx3) + EM(i1, i2, i3 + 1, em::bx3))); + buff += e3_t * b1_t - e1_t * b3_t; + } else { + const auto e1_t = metric.template transform<1, Idx::U, Idx::T>( + { i1_ + HALF, i2_ + HALF, i3_ + HALF }, + INV_4 * + (EM(i1, i2, i3, em::ex1) + EM(i1, i2 + 1, i3, em::ex1) + + EM(i1, i2, i3 + 1, em::ex1) + EM(i1, i2 + 1, i3 + 1, em::ex1))); + const auto e2_t = metric.template transform<2, Idx::U, Idx::T>( + { i1_ + HALF, i2_ + HALF, i3_ + HALF }, + INV_4 * + (EM(i1, i2, i3, em::ex2) + EM(i1 + 1, i2, i3, em::ex2) + + EM(i1, i2, i3 + 1, em::ex2) + EM(i1 + 1, i2, i3 + 1, em::ex2))); + const auto b1_t = metric.template transform<1, Idx::U, Idx::T>( + { i1_ + HALF, i2_ + HALF, i3_ + HALF }, + HALF * (EM(i1, i2, i3, em::bx1) + EM(i1 + 1, i2, i3, em::bx1))); + const auto b2_t = metric.template transform<2, Idx::U, Idx::T>( + { i1_ + HALF, i2_ + HALF, i3_ + HALF }, + HALF * (EM(i1, i2, i3, em::bx2) + EM(i1, i2 + 1, i3, em::bx2))); + buff += e1_t * b2_t - e2_t * b1_t; + } + } else if constexpr (F == StatsID::JdotE) { + vec_t e_t { ZERO }; + vec_t j_t { ZERO }; + metric.template transform( + { i1_ + HALF, i2_ + HALF, i3_ + HALF }, + { INV_4 * (EM(i1, i2, i3, em::ex1) + EM(i1, i2 + 1, i3, em::ex1) + + EM(i1, i2, i3 + 1, em::ex1) + EM(i1, i2 + 1, i3 + 1, em::ex1)), + INV_4 * (EM(i1, i2, i3, em::ex2) + EM(i1 + 1, i2, i3, em::ex2) + + EM(i1, i2, i3 + 1, em::ex2) + EM(i1 + 1, i2, i3 + 1, em::ex2)), + INV_4 * (EM(i1, i2, i3, em::ex3) + EM(i1 + 1, i2, i3, em::ex3) + + EM(i1, i2 + 1, i3, em::ex3) + EM(i1 + 1, i2 + 1, i3, em::ex3)) }, + e_t); + metric.template transform( + { i1_ + HALF, i2_ + HALF, i3_ + HALF }, + { INV_4 * (J(i1, i2, i3, cur::jx1) + J(i1, i2 + 1, i3, cur::jx1) + + J(i1, i2, i3 + 1, cur::jx1) + J(i1, i2 + 1, i3 + 1, cur::jx1)), + INV_4 * (J(i1, i2, i3, cur::jx2) + J(i1 + 1, i2, i3, cur::jx2) + + J(i1, i2, i3 + 1, cur::jx2) + J(i1 + 1, i2, i3 + 1, cur::jx2)), + INV_4 * (J(i1, i2, i3, cur::jx3) + J(i1 + 1, i2, i3, cur::jx3) + + J(i1, i2 + 1, i3, cur::jx3) + J(i1 + 1, i2 + 1, i3, cur::jx3)) }, + j_t); + buff += e_t[0] * j_t[0] + e_t[1] * j_t[1] + e_t[2] * j_t[2]; + } + } + }; + +} // namespace kernel + +#endif diff --git a/src/output/stats.cpp b/src/output/stats.cpp index ba3e85c40..68392dc0b 100644 --- a/src/output/stats.cpp +++ b/src/output/stats.cpp @@ -38,13 +38,13 @@ namespace stats { species = {}; } if (is_vector()) { - // always write all the ExB and V components + // always write all the E^2, B^2, ExB components comp = { { 1 }, { 2 }, { 3 } }; } else if (id() == StatsID::T) { // energy-momentum tensor comp = InterpretComponents({ name.substr(1, 1), name.substr(2, 1) }); } else { - // scalar (e.g., Rho, E^2, etc.) + // scalar (e.g., Rho, Npart, etc.) comp = {}; } } diff --git a/src/output/stats.h b/src/output/stats.h index c81b9b7b3..ddea9ad4c 100644 --- a/src/output/stats.h +++ b/src/output/stats.h @@ -3,10 +3,11 @@ * @brief Class defining the metadata necessary to prepare the stats for output * @implements * - out::OutputStats + * - out::Writer * @cpp: * - stats.cpp * @namespaces: - * - out:: + * - stats:: */ #ifndef OUTPUT_STATS_H @@ -16,10 +17,16 @@ #include "global.h" #include "utils/error.h" +#include "utils/formatting.h" #include "utils/tools.h" +#if defined(MPI_ENABLED) + #include "arch/mpi_aliases.h" + + #include +#endif + #include -#include #include #include @@ -47,7 +54,7 @@ namespace stats { [[nodiscard]] auto is_vector() const -> bool { - return id() == StatsID::ExB; + return id() == StatsID::ExB || id() == StatsID::E2 || id() == StatsID::B2; } [[nodiscard]] @@ -65,7 +72,11 @@ namespace stats { if (id() == StatsID::T) { tmp += m_name.substr(1, 2); } else if (is_vector()) { - tmp += "i"; + if (id() == StatsID::E2 || id() == StatsID::B2) { + tmp = fmt::format("%ci^2", tmp[0]); + } else { + tmp += "i"; + } } if (species.size() > 0) { tmp += "_"; @@ -101,16 +112,20 @@ namespace stats { // capitalize the first letter tmp[0] = std::toupper(tmp[0]); } - for (auto& c : comp[ci]) { - tmp += std::to_string(c); - } - if (species.size() > 0) { - tmp += "_"; - for (auto& s : species) { - tmp += std::to_string(s); + if (tmp == "E^2" or tmp == "B^2") { + tmp = fmt::format("%c%d^2", tmp[0], comp[ci][0]); + } else { + for (auto& c : comp[ci]) { + tmp += std::to_string(c); + } + if (species.size() > 0) { tmp += "_"; + for (auto& s : species) { + tmp += std::to_string(s); + tmp += "_"; + } + tmp.pop_back(); } - tmp.pop_back(); } return tmp; } @@ -145,16 +160,25 @@ namespace stats { template inline void write(const T& value) const { #if defined(MPI_ENABLED) - // @TODO: reduce + T tot_value = static_cast(0); + MPI_Reduce(&value, + &tot_value, + 1, + mpi::get_type(), + MPI_SUM, + MPI_ROOT_RANK, + MPI_COMM_WORLD); +#else + tot_value = value; #endif CallOnce( - [](auto& fname, auto& value) { + [](auto&& fname, auto&& value) { std::fstream StatsOut(fname, std::fstream::out | std::fstream::app); StatsOut << value << ","; StatsOut.close(); }, m_fname, - value); + tot_value); } void endWriting(); From ddb91f159e9200234ab0cec225912d92de3b7d11 Mon Sep 17 00:00:00 2001 From: haykh Date: Tue, 6 May 2025 21:05:21 -0400 Subject: [PATCH 704/773] stats for Fields tested --- src/kernels/tests/CMakeLists.txt | 1 + src/kernels/tests/particle_moments.cpp | 9 +- src/kernels/tests/reduced_stats.cpp | 320 +++++++++++++++++++++++++ src/output/stats.h | 2 +- src/output/tests/stats.cpp | 6 +- 5 files changed, 329 insertions(+), 9 deletions(-) create mode 100644 src/kernels/tests/reduced_stats.cpp diff --git a/src/kernels/tests/CMakeLists.txt b/src/kernels/tests/CMakeLists.txt index 551f9012f..2702e0526 100644 --- a/src/kernels/tests/CMakeLists.txt +++ b/src/kernels/tests/CMakeLists.txt @@ -35,3 +35,4 @@ gen_test(prtl_bc) gen_test(flds_bc) gen_test(pusher) gen_test(ext_force) +gen_test(reduced_stats) diff --git a/src/kernels/tests/particle_moments.cpp b/src/kernels/tests/particle_moments.cpp index 25ed7d4d9..bef1592df 100644 --- a/src/kernels/tests/particle_moments.cpp +++ b/src/kernels/tests/particle_moments.cpp @@ -20,7 +20,6 @@ #include #include #include -#include #include using namespace ntt; @@ -56,7 +55,7 @@ void testParticleMoments(const std::vector& res, } else { extent = { ext[0], - {ZERO, constant::PI} + { ZERO, constant::PI } }; } @@ -106,8 +105,8 @@ void testParticleMoments(const std::vector& res, auto boundaries = boundaries_t {}; if constexpr (M::CoordType != Coord::Cart) { boundaries = { - {FldsBC::CUSTOM, FldsBC::CUSTOM}, - { FldsBC::AXIS, FldsBC::AXIS} + { FldsBC::CUSTOM, FldsBC::CUSTOM }, + { FldsBC::AXIS, FldsBC::AXIS } }; } @@ -286,4 +285,4 @@ auto main(int argc, char* argv[]) -> int { } Kokkos::finalize(); return 0; -} \ No newline at end of file +} diff --git a/src/kernels/tests/reduced_stats.cpp b/src/kernels/tests/reduced_stats.cpp new file mode 100644 index 000000000..4be11a2f7 --- /dev/null +++ b/src/kernels/tests/reduced_stats.cpp @@ -0,0 +1,320 @@ +#include "kernels/reduced_stats.hpp" + +#include "enums.h" +#include "global.h" + +#include "arch/kokkos_aliases.h" +#include "utils/comparators.h" +#include "utils/error.h" + +#include "metrics/minkowski.h" + +#include +#include +#include + +using namespace ntt; +using namespace metric; + +template +class Fill_kernel { + ndfield_t& arr; + real_t v; + unsigned short c; + +public: + Fill_kernel(ndfield_t& arr_, real_t v_, unsigned short c_) + : arr { arr_ } + , v { v_ } + , c { c_ } {} + + Inline void operator()(index_t i1) const { + arr(i1, c) = v; + } + + Inline void operator()(index_t i1, index_t i2) const { + arr(i1, i2, c) = v; + } + + Inline void operator()(index_t i1, index_t i2, index_t i3) const { + arr(i1, i2, i3, c) = v; + } +}; + +template +void put_value(ndfield_t& arr, real_t v, unsigned short c) { + range_t range; + if constexpr (D == Dim::_1D) { + range = { + { 0u, arr.extent(0) } + }; + } else if constexpr (D == Dim::_2D) { + range = { + { 0u, 0u }, + { arr.extent(0), arr.extent(1) } + }; + } else { + range = { + { 0u, 0u, 0u }, + { arr.extent(0), arr.extent(1), arr.extent(2) } + }; + } + Kokkos::parallel_for("Fill", range, Fill_kernel(arr, v, c)); +} + +inline static constexpr auto epsilon = std::numeric_limits::epsilon(); + +template +auto compute_field_stat(const M& metric, + const ndfield_t& em, + const ndfield_t& j, + const range_t& range, + ncells_t num_cells) -> real_t { + real_t buff = ZERO; + Kokkos::parallel_reduce("ReduceFields", + range, + kernel::ReducedFields_kernel(em, j, metric), + buff); + return buff / static_cast(num_cells); +} + +template +void testReducedStats(const std::vector& res, + const boundaries_t& ext, + const real_t acc = ONE) { + raise::ErrorIf(res.size() != M::Dim, "Invalid resolution size", HERE); + + M metric { res, ext, {} }; + + std::vector x_s, y_s, z_s; + + coord_t dummy { ZERO }; + std::vector values; + values.push_back(metric.template transform<1, Idx::T, Idx::U>(dummy, ONE)); + values.push_back(metric.template transform<2, Idx::T, Idx::U>(dummy, TWO)); + values.push_back(metric.template transform<3, Idx::T, Idx::U>(dummy, THREE)); + + values.push_back(metric.template transform<1, Idx::T, Idx::U>(dummy, FOUR * ONE)); + values.push_back(metric.template transform<2, Idx::T, Idx::U>(dummy, FOUR * TWO)); + values.push_back( + metric.template transform<3, Idx::T, Idx::U>(dummy, FOUR * THREE)); + + values.push_back(metric.template transform<1, Idx::T, Idx::U>(dummy, -ONE)); + values.push_back(metric.template transform<2, Idx::T, Idx::U>(dummy, -TWO)); + values.push_back(metric.template transform<3, Idx::T, Idx::U>(dummy, THREE)); + + values.push_back(metric.template transform<1, Idx::T, Idx::U>(dummy, FOUR)); + values.push_back(metric.template transform<2, Idx::T, Idx::U>(dummy, TWO)); + values.push_back(metric.template transform<3, Idx::T, Idx::U>(dummy, ONE)); + + ndfield_t EM; + ndfield_t J; + range_t cell_range; + ncells_t num_cells; + + if constexpr (M::Dim == Dim::_1D) { + EM = ndfield_t { "EM", res[0] + 2 * N_GHOSTS }; + J = ndfield_t { "J", res[0] + 2 * N_GHOSTS }; + cell_range = { N_GHOSTS, res[0] + N_GHOSTS }; + num_cells = res[0]; + + put_value(EM, values[0], em::ex1); + put_value(EM, values[1], em::ex2); + put_value(EM, values[2], em::ex3); + + put_value(EM, values[6], em::bx1); + put_value(EM, values[7], em::bx2); + put_value(EM, values[8], em::bx3); + + put_value(J, values[9], cur::jx1); + put_value(J, values[10], cur::jx2); + put_value(J, values[11], cur::jx3); + } else if constexpr (M::Dim == Dim::_2D) { + EM = ndfield_t { "EM", res[0] + 2 * N_GHOSTS, res[1] + 2 * N_GHOSTS }; + J = ndfield_t { "J", res[0] + 2 * N_GHOSTS, res[1] + 2 * N_GHOSTS }; + + cell_range = { + { N_GHOSTS, N_GHOSTS }, + { res[0] + N_GHOSTS, res[1] + N_GHOSTS } + }; + num_cells = res[0] * res[1]; + + put_value(EM, values[0], em::ex1); + put_value(EM, values[1], em::ex2); + put_value(EM, values[2], em::ex3); + + put_value(EM, values[6], em::bx1); + put_value(EM, values[7], em::bx2); + put_value(EM, values[8], em::bx3); + + put_value(J, values[9], cur::jx1); + put_value(J, values[10], cur::jx2); + put_value(J, values[11], cur::jx3); + } else { + EM = ndfield_t { "EM", + res[0] + 2 * N_GHOSTS, + res[1] + 2 * N_GHOSTS, + res[2] + 2 * N_GHOSTS }; + J = ndfield_t { "J", + res[0] + 2 * N_GHOSTS, + res[1] + 2 * N_GHOSTS, + res[2] + 2 * N_GHOSTS }; + + cell_range = { + { N_GHOSTS, N_GHOSTS, N_GHOSTS }, + { res[0] + N_GHOSTS, res[1] + N_GHOSTS, res[2] + N_GHOSTS } + }; + num_cells = res[0] * res[1] * res[2]; + + put_value(EM, values[0], em::ex1); + put_value(EM, values[1], em::ex2); + put_value(EM, values[2], em::ex3); + + put_value(EM, values[6], em::bx1); + put_value(EM, values[7], em::bx2); + put_value(EM, values[8], em::bx3); + + put_value(J, values[9], cur::jx1); + put_value(J, values[10], cur::jx2); + put_value(J, values[11], cur::jx3); + } + + { + const auto Ex_Sq = compute_field_stat(metric, + EM, + J, + cell_range, + num_cells); + printf("Ex_Sq: %.12e\n", Ex_Sq); + raise::ErrorIf(not cmp::AlmostEqual_host(Ex_Sq, (real_t)(1), acc * epsilon), + "Ex_Sq does not match expected value", + HERE); + } + + { + const auto Ey_Sq = compute_field_stat(metric, + EM, + J, + cell_range, + num_cells); + raise::ErrorIf(not cmp::AlmostEqual_host(Ey_Sq, (real_t)(4), acc * epsilon), + "Ey_Sq does not match expected value", + HERE); + } + + { + const auto Ez_Sq = compute_field_stat(metric, + EM, + J, + cell_range, + num_cells); + raise::ErrorIf(not cmp::AlmostEqual_host(Ez_Sq, (real_t)(9), acc * epsilon), + "Ez_Sq does not match expected value", + HERE); + } + + { + const auto Bx_Sq = compute_field_stat(metric, + EM, + J, + cell_range, + num_cells); + raise::ErrorIf(not cmp::AlmostEqual_host(Bx_Sq, (real_t)(1), acc * epsilon), + "Bx_Sq does not match expected value", + HERE); + } + + { + const auto By_Sq = compute_field_stat(metric, + EM, + J, + cell_range, + num_cells); + raise::ErrorIf(not cmp::AlmostEqual_host(By_Sq, (real_t)(4), acc * epsilon), + "By_Sq does not match expected value", + HERE); + } + + { + const auto Bz_Sq = compute_field_stat(metric, + EM, + J, + cell_range, + num_cells); + raise::ErrorIf(not cmp::AlmostEqual_host(Bz_Sq, (real_t)(9), acc * epsilon), + "Bz_Sq does not match expected value", + HERE); + } + + { + const auto ExB_x = compute_field_stat(metric, + EM, + J, + cell_range, + num_cells); + raise::ErrorIf(not cmp::AlmostEqual_host(ExB_x, (real_t)(12), acc * epsilon), + "ExB_x does not match expected value", + HERE); + } + + { + const auto ExB_y = compute_field_stat(metric, + EM, + J, + cell_range, + num_cells); + raise::ErrorIf(not cmp::AlmostEqual_host(ExB_y, (real_t)(-6), acc * epsilon), + "ExB_y does not match expected value", + HERE); + } + + { + const auto ExB_z = compute_field_stat(metric, + EM, + J, + cell_range, + num_cells); + raise::ErrorIf(not cmp::AlmostEqual_host(ExB_z, (real_t)(0), acc * epsilon), + "ExB_z does not match expected value", + HERE); + } + + { + const auto JdotE = compute_field_stat(metric, + EM, + J, + cell_range, + num_cells); + raise::ErrorIf(not cmp::AlmostEqual_host(JdotE, (real_t)(11), acc * epsilon), + "JdotE does not match expected value", + HERE); + } +} + +auto main(int argc, char* argv[]) -> int { + Kokkos::initialize(argc, argv); + + try { + using namespace ntt; + + const ncells_t nx = 100, ny = 123, nz = 52; + std::pair x_ext { -2.0, 2.0 }; + std::pair y_ext { 0.0, 4.92 }; + std::pair z_ext { 0.0, 2.08 }; + + testReducedStats>({ nx }, { x_ext }, 10); + testReducedStats>({ nx, ny }, + { x_ext, y_ext }, + 10); + testReducedStats>({ nx, ny, nz }, + { x_ext, y_ext, z_ext }, + 10); + + } catch (std::exception& e) { + std::cerr << e.what() << std::endl; + Kokkos::finalize(); + return 1; + } + Kokkos::finalize(); + return 0; +} diff --git a/src/output/stats.h b/src/output/stats.h index ddea9ad4c..fd4019b46 100644 --- a/src/output/stats.h +++ b/src/output/stats.h @@ -169,7 +169,7 @@ namespace stats { MPI_ROOT_RANK, MPI_COMM_WORLD); #else - tot_value = value; + T tot_value = value; #endif CallOnce( [](auto&& fname, auto&& value) { diff --git a/src/output/tests/stats.cpp b/src/output/tests/stats.cpp index db6730a89..04645cad7 100644 --- a/src/output/tests/stats.cpp +++ b/src/output/tests/stats.cpp @@ -14,12 +14,12 @@ auto main() -> int { try { { const auto e = OutputStats("E^2"); - raise::ErrorIf(e.is_vector(), "E^2 should not be a vector quantity", HERE); + raise::ErrorIf(not e.is_vector(), "E^2 should be a vector quantity", HERE); raise::ErrorIf(e.is_moment(), "E^2 should not be a moment", HERE); raise::ErrorIf(e.id() != StatsID::E2, "E^2 should have ID StatsID::E2", HERE); raise::ErrorIf(e.species.size() != 0, "E^2 should have no species", HERE); - raise::ErrorIf(e.comp.size() != 0, "E^2 should have no components", HERE); - raise::ErrorIf(e.name() != "E^2", "E^2 should have name `E^2`", HERE); + raise::ErrorIf(e.comp.size() != 3, "E^2 should have 3 components", HERE); + raise::ErrorIf(e.name() != "Ei^2", "E^2 should have name `Ei^2`", HERE); } { From 12cb4b246171314234dded7ebaf1f6ea5075d47c Mon Sep 17 00:00:00 2001 From: haykh Date: Tue, 6 May 2025 21:16:41 -0400 Subject: [PATCH 705/773] disabled stats for non-Cart --- src/framework/domain/grid.h | 18 ++++++++++++++++++ src/framework/domain/stats.cpp | 8 +++++++- src/framework/parameters.cpp | 5 +++++ 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/src/framework/domain/grid.h b/src/framework/domain/grid.h index af5b6c8d5..87b21b1f5 100644 --- a/src/framework/domain/grid.h +++ b/src/framework/domain/grid.h @@ -130,6 +130,15 @@ namespace ntt { return m_resolution; } + [[nodiscard]] + auto num_active() const -> ncells_t { + ncells_t total_active = 1u; + for (const auto& res : m_resolution) { + total_active *= res; + } + return total_active; + } + [[nodiscard]] auto n_all(in i) const -> ncells_t { switch (i) { @@ -154,6 +163,15 @@ namespace ntt { return nall; } + [[nodiscard]] + auto num_all() const -> ncells_t { + ncells_t total_all = 1u; + for (const auto& res : n_all()) { + total_all *= res; + } + return total_all; + } + /* Ranges in the device execution space --------------------------------- */ /** * @brief Loop over all active cells (disregard ghost cells) diff --git a/src/framework/domain/stats.cpp b/src/framework/domain/stats.cpp index cf7613bdb..6fa41d52e 100644 --- a/src/framework/domain/stats.cpp +++ b/src/framework/domain/stats.cpp @@ -166,7 +166,8 @@ namespace ntt { HERE); } - return buffer; + // @TODO: not going to work for arbitrary metric + return buffer / static_cast(domain->mesh.num_active()); } template @@ -175,6 +176,11 @@ namespace ntt { timestep_t finished_step, simtime_t current_time, simtime_t finished_time) -> bool { + // @TODO: remove when stats are supported for all coordinate systems + raise::ErrorIf( + M::CoordType != Coord::Cart, + "Stats writing is only supported for Cartesian coordinates for now", + HERE); if (not(params.template get("output.stats.enable") and g_stats_writer.shouldWrite(finished_step, finished_time))) { return false; diff --git a/src/framework/parameters.cpp b/src/framework/parameters.cpp index 168640e1f..836d79fb5 100644 --- a/src/framework/parameters.cpp +++ b/src/framework/parameters.cpp @@ -873,6 +873,11 @@ namespace ntt { "gamma_rad", defaults::synchrotron::gamma_rad)); } + + // @TODO: disabling stats for non-Cartesian + if (coord_enum != Coord::Cart) { + set("output.stats.enable", false); + } } void SimulationParams::setSetupParams(const toml::value& toml_data) { From c207b2086ae62cd56713010e25a5605731643756 Mon Sep 17 00:00:00 2001 From: haykh Date: Thu, 1 May 2025 21:31:07 -0400 Subject: [PATCH 706/773] stats reduction for flds --- src/framework/domain/stats.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/framework/domain/stats.cpp b/src/framework/domain/stats.cpp index 6fa41d52e..75a4edd1d 100644 --- a/src/framework/domain/stats.cpp +++ b/src/framework/domain/stats.cpp @@ -168,6 +168,14 @@ namespace ntt { // @TODO: not going to work for arbitrary metric return buffer / static_cast(domain->mesh.num_active()); + // Kokkos::parallel_reduce( + // "ComputeMoments", + // prtl_spec.rangeActiveParticles(), + // kernel::ReducedFields_kernel(components, + // domain->fields.em, + // domain->fields.cur, + // domain->mesh.metric), + // buffer); } template From 88168beaff3353feee5ae35267e98dd9b05b8b26 Mon Sep 17 00:00:00 2001 From: haykh Date: Thu, 1 May 2025 21:31:07 -0400 Subject: [PATCH 707/773] stats reduction for flds --- src/output/stats.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/output/stats.h b/src/output/stats.h index fd4019b46..a88437fe9 100644 --- a/src/output/stats.h +++ b/src/output/stats.h @@ -159,8 +159,8 @@ namespace stats { template inline void write(const T& value) const { -#if defined(MPI_ENABLED) T tot_value = static_cast(0); +#if defined(MPI_ENABLED) MPI_Reduce(&value, &tot_value, 1, @@ -169,7 +169,7 @@ namespace stats { MPI_ROOT_RANK, MPI_COMM_WORLD); #else - T tot_value = value; + tot_value = value; #endif CallOnce( [](auto&& fname, auto&& value) { From 9238f1da2195a3cc58ad1b4a1eead4d2dd9b6eaf Mon Sep 17 00:00:00 2001 From: haykh Date: Tue, 6 May 2025 21:05:21 -0400 Subject: [PATCH 708/773] stats for Fields tested --- src/output/stats.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/output/stats.h b/src/output/stats.h index a88437fe9..6fec08642 100644 --- a/src/output/stats.h +++ b/src/output/stats.h @@ -169,7 +169,7 @@ namespace stats { MPI_ROOT_RANK, MPI_COMM_WORLD); #else - tot_value = value; + T tot_value = value; #endif CallOnce( [](auto&& fname, auto&& value) { From 1585dcbefb92d9c3502fcc5866e2f8bc3a7de0c5 Mon Sep 17 00:00:00 2001 From: hayk Date: Sat, 24 May 2025 15:07:00 -0400 Subject: [PATCH 709/773] area-weighting in stats --- src/kernels/reduced_stats.hpp | 69 ++++++++++++++++------------- src/kernels/tests/reduced_stats.cpp | 38 ++++++++-------- src/metrics/kerr_schild.h | 9 ++++ src/metrics/kerr_schild_0.h | 14 ++++++ src/metrics/metric_base.h | 3 ++ src/metrics/minkowski.h | 33 ++++++++++---- src/metrics/qkerr_schild.h | 9 ++++ src/metrics/qspherical.h | 17 ++++++- src/metrics/spherical.h | 17 ++++++- src/output/stats.h | 4 +- 10 files changed, 153 insertions(+), 60 deletions(-) diff --git a/src/kernels/reduced_stats.hpp b/src/kernels/reduced_stats.hpp index 373f06eb0..6b6c4df2c 100644 --- a/src/kernels/reduced_stats.hpp +++ b/src/kernels/reduced_stats.hpp @@ -45,19 +45,19 @@ namespace kernel { const auto b1_u = EM(i1, em::bx1); const auto b1_d = metric.template transform<1, Idx::U, Idx::D>({ i1_ }, b1_u); - buff += b1_u * b1_d; + buff += b1_u * b1_d * metric.sqrt_det_h({ i1_ }); } else if constexpr (I == 2) { const auto b2_u = EM(i1, em::bx2); const auto b2_d = metric.template transform<2, Idx::U, Idx::D>( { i1_ + HALF }, b2_u); - buff += b2_u * b2_d; + buff += b2_u * b2_d * metric.sqrt_det_h({ i1_ + HALF }); } else { const auto b3_u = EM(i1, em::bx3); const auto b3_d = metric.template transform<3, Idx::U, Idx::D>( { i1_ + HALF }, b3_u); - buff += b3_u * b3_d; + buff += b3_u * b3_d * metric.sqrt_det_h({ i1_ + HALF }); } } else if constexpr (F == StatsID::E2) { if constexpr (I == 1) { @@ -65,17 +65,17 @@ namespace kernel { const auto e1_d = metric.template transform<1, Idx::U, Idx::D>( { i1_ + HALF }, e1_u); - buff += e1_u * e1_d; + buff += e1_u * e1_d * metric.sqrt_det_h({ i1_ + HALF }); } else if constexpr (I == 2) { const auto e2_u = EM(i1, em::ex2); const auto e2_d = metric.template transform<2, Idx::U, Idx::D>({ i1_ }, e2_u); - buff += e2_u * e2_d; + buff += e2_u * e2_d * metric.sqrt_det_h({ i1_ }); } else { const auto e3_u = EM(i1, em::ex3); const auto e3_d = metric.template transform<3, Idx::U, Idx::D>({ i1_ }, e3_u); - buff += e3_u * e3_d; + buff += e3_u * e3_d * metric.sqrt_det_h({ i1_ }); } } else if constexpr (F == StatsID::ExB) { if constexpr (I == 1) { @@ -91,7 +91,7 @@ namespace kernel { const auto b3_t = metric.template transform<3, Idx::U, Idx::T>( { i1_ + HALF }, EM(i1, em::bx3)); - buff += e2_t * b3_t - e3_t * b2_t; + buff += (e2_t * b3_t - e3_t * b2_t) * metric.sqrt_det_h({ i1_ + HALF }); } else if constexpr (I == 2) { const auto e1_t = metric.template transform<1, Idx::U, Idx::T>( { i1_ + HALF }, @@ -105,7 +105,7 @@ namespace kernel { const auto b3_t = metric.template transform<3, Idx::U, Idx::T>( { i1_ + HALF }, EM(i1, em::bx3)); - buff += e3_t * b1_t - e1_t * b3_t; + buff += (e3_t * b1_t - e1_t * b3_t) * metric.sqrt_det_h({ i1_ + HALF }); } else { const auto e1_t = metric.template transform<1, Idx::U, Idx::T>( { i1_ + HALF }, @@ -119,7 +119,7 @@ namespace kernel { const auto b2_t = metric.template transform<2, Idx::U, Idx::T>( { i1_ + HALF }, EM(i1, em::bx2)); - buff += e1_t * b2_t - e2_t * b1_t; + buff += (e1_t * b2_t - e2_t * b1_t) * metric.sqrt_det_h({ i1_ + HALF }); } } else if constexpr (F == StatsID::JdotE) { vec_t e_t { ZERO }; @@ -136,7 +136,8 @@ namespace kernel { HALF * (J(i1, cur::jx2) + J(i1 + 1, cur::jx2)), HALF * (J(i1, cur::jx3) + J(i1 + 1, cur::jx3)) }, j_t); - buff += e_t[0] * j_t[0] + e_t[1] * j_t[1] + e_t[2] * j_t[2]; + buff += (e_t[0] * j_t[0] + e_t[1] * j_t[1] + e_t[2] * j_t[2]) * + metric.sqrt_det_h({ i1_ + HALF }); } } @@ -149,19 +150,19 @@ namespace kernel { const auto b1_d = metric.template transform<1, Idx::U, Idx::D>( { i1_, i2_ + HALF }, b1_u); - buff += b1_u * b1_d; + buff += b1_u * b1_d * metric.sqrt_det_h({ i1_, i2_ + HALF }); } else if constexpr (I == 2) { const auto b2_u = EM(i1, i2, em::bx2); const auto b2_d = metric.template transform<2, Idx::U, Idx::D>( { i1_ + HALF, i2_ }, b2_u); - buff += b2_u * b2_d; + buff += b2_u * b2_d * metric.sqrt_det_h({ i1_ + HALF, i2_ }); } else { const auto b3_u = EM(i1, i2, em::bx3); const auto b3_d = metric.template transform<3, Idx::U, Idx::D>( { i1_ + HALF, i2_ + HALF }, b3_u); - buff += b3_u * b3_d; + buff += b3_u * b3_d * metric.sqrt_det_h({ i1_ + HALF, i2_ + HALF }); } } else if constexpr (F == StatsID::E2) { if constexpr (I == 1) { @@ -169,19 +170,19 @@ namespace kernel { const auto e1_d = metric.template transform<1, Idx::U, Idx::D>( { i1_ + HALF, i2_ }, e1_u); - buff += e1_u * e1_d; + buff += e1_u * e1_d * metric.sqrt_det_h({ i1_ + HALF, i2_ }); } else if constexpr (I == 2) { const auto e2_u = EM(i1, i2, em::ex2); const auto e2_d = metric.template transform<2, Idx::U, Idx::D>( { i1_, i2_ + HALF }, e2_u); - buff += e2_u * e2_d; + buff += e2_u * e2_d * metric.sqrt_det_h({ i1_, i2_ + HALF }); } else { const auto e3_u = EM(i1, i2, em::ex3); const auto e3_d = metric.template transform<3, Idx::U, Idx::D>( { i1_, i2_ }, e3_u); - buff += e3_u * e3_d; + buff += e3_u * e3_d * metric.sqrt_det_h({ i1_, i2_ }); } } else if constexpr (F == StatsID::ExB) { if constexpr (I == 1) { @@ -198,7 +199,8 @@ namespace kernel { const auto b3_t = metric.template transform<3, Idx::U, Idx::T>( { i1_ + HALF, i2_ + HALF }, EM(i1, i2, em::bx3)); - buff += e2_t * b3_t - e3_t * b2_t; + buff += (e2_t * b3_t - e3_t * b2_t) * + metric.sqrt_det_h({ i1_ + HALF, i2_ + HALF }); } else if constexpr (I == 2) { const auto e1_t = metric.template transform<1, Idx::U, Idx::T>( { i1_ + HALF, i2_ + HALF }, @@ -213,7 +215,8 @@ namespace kernel { const auto b3_t = metric.template transform<3, Idx::U, Idx::T>( { i1_ + HALF, i2_ + HALF }, EM(i1, i2, em::bx3)); - buff += e3_t * b1_t - e1_t * b3_t; + buff += (e3_t * b1_t - e1_t * b3_t) * + metric.sqrt_det_h({ i1_ + HALF, i2_ + HALF }); } else { const auto e1_t = metric.template transform<1, Idx::U, Idx::T>( { i1_ + HALF, i2_ + HALF }, @@ -227,7 +230,8 @@ namespace kernel { const auto b2_t = metric.template transform<2, Idx::U, Idx::T>( { i1_ + HALF, i2_ + HALF }, HALF * (EM(i1, i2, em::bx2) + EM(i1, i2 + 1, em::bx2))); - buff += e1_t * b2_t - e2_t * b1_t; + buff += (e1_t * b2_t - e2_t * b1_t) * + metric.sqrt_det_h({ i1_ + HALF, i2_ + HALF }); } } else if constexpr (F == StatsID::JdotE) { vec_t e_t { ZERO }; @@ -246,7 +250,8 @@ namespace kernel { INV_4 * (J(i1, i2, cur::jx3) + J(i1 + 1, i2, cur::jx3) + J(i1, i2 + 1, cur::jx3) + J(i1 + 1, i2 + 1, cur::jx3)) }, j_t); - buff += e_t[0] * j_t[0] + e_t[1] * j_t[1] + e_t[2] * j_t[2]; + buff += (e_t[0] * j_t[0] + e_t[1] * j_t[1] + e_t[2] * j_t[2]) * + metric.sqrt_det_h({ i1_ + HALF, i2_ + HALF }); } } @@ -260,19 +265,19 @@ namespace kernel { const auto b1_d = metric.template transform<1, Idx::U, Idx::D>( { i1_, i2_ + HALF, i3_ + HALF }, b1_u); - buff += b1_u * b1_d; + buff += b1_u * b1_d * metric.sqrt_det_h({ i1_, i2_ + HALF, i3_ + HALF }); } else if constexpr (I == 2) { const auto b2_u = EM(i1, i2, i3, em::bx2); const auto b2_d = metric.template transform<2, Idx::U, Idx::D>( { i1_ + HALF, i2_, i3_ + HALF }, b2_u); - buff += b2_u * b2_d; + buff += b2_u * b2_d * metric.sqrt_det_h({ i1_ + HALF, i2_, i3_ + HALF }); } else { const auto b3_u = EM(i1, i2, i3, em::bx3); const auto b3_d = metric.template transform<3, Idx::U, Idx::D>( { i1_ + HALF, i2_ + HALF, i3_ }, b3_u); - buff += b3_u * b3_d; + buff += b3_u * b3_d * metric.sqrt_det_h({ i1_ + HALF, i2_ + HALF, i3_ }); } } else if constexpr (F == StatsID::E2) { if constexpr (I == 1) { @@ -280,19 +285,19 @@ namespace kernel { const auto e1_d = metric.template transform<1, Idx::U, Idx::D>( { i1_ + HALF, i2_, i3_ }, e1_u); - buff += e1_u * e1_d; + buff += e1_u * e1_d * metric.sqrt_det_h({ i1_ + HALF, i2_, i3_ }); } else if constexpr (I == 2) { const auto e2_u = EM(i1, i2, i3, em::ex2); const auto e2_d = metric.template transform<2, Idx::U, Idx::D>( { i1_, i2_ + HALF, i3_ }, e2_u); - buff += e2_u * e2_d; + buff += e2_u * e2_d * metric.sqrt_det_h({ i1_, i2_ + HALF, i3_ }); } else { const auto e3_u = EM(i1, i2, i3, em::ex3); const auto e3_d = metric.template transform<3, Idx::U, Idx::D>( { i1_, i2_, i3_ + HALF }, e3_u); - buff += e3_u * e3_d; + buff += e3_u * e3_d * metric.sqrt_det_h({ i1_, i2_, i3_ + HALF }); } } else if constexpr (F == StatsID::ExB) { if constexpr (I == 1) { @@ -312,7 +317,8 @@ namespace kernel { const auto b3_t = metric.template transform<3, Idx::U, Idx::T>( { i1_ + HALF, i2_ + HALF, i3_ + HALF }, HALF * (EM(i1, i2, i3, em::bx3) + EM(i1, i2, i3 + 1, em::bx3))); - buff += e2_t * b3_t - e3_t * b2_t; + buff += (e2_t * b3_t - e3_t * b2_t) * + metric.sqrt_det_h({ i1_ + HALF, i2_ + HALF, i3_ + HALF }); } else if constexpr (I == 2) { const auto e1_t = metric.template transform<1, Idx::U, Idx::T>( { i1_ + HALF, i2_ + HALF, i3_ + HALF }, @@ -330,7 +336,8 @@ namespace kernel { const auto b3_t = metric.template transform<3, Idx::U, Idx::T>( { i1_ + HALF, i2_ + HALF, i3_ + HALF }, HALF * (EM(i1, i2, i3, em::bx3) + EM(i1, i2, i3 + 1, em::bx3))); - buff += e3_t * b1_t - e1_t * b3_t; + buff += (e3_t * b1_t - e1_t * b3_t) * + metric.sqrt_det_h({ i1_ + HALF, i2_ + HALF, i3_ + HALF }); } else { const auto e1_t = metric.template transform<1, Idx::U, Idx::T>( { i1_ + HALF, i2_ + HALF, i3_ + HALF }, @@ -348,7 +355,8 @@ namespace kernel { const auto b2_t = metric.template transform<2, Idx::U, Idx::T>( { i1_ + HALF, i2_ + HALF, i3_ + HALF }, HALF * (EM(i1, i2, i3, em::bx2) + EM(i1, i2 + 1, i3, em::bx2))); - buff += e1_t * b2_t - e2_t * b1_t; + buff += (e1_t * b2_t - e2_t * b1_t) * + metric.sqrt_det_h({ i1_ + HALF, i2_ + HALF, i3_ + HALF }); } } else if constexpr (F == StatsID::JdotE) { vec_t e_t { ZERO }; @@ -371,7 +379,8 @@ namespace kernel { INV_4 * (J(i1, i2, i3, cur::jx3) + J(i1 + 1, i2, i3, cur::jx3) + J(i1, i2 + 1, i3, cur::jx3) + J(i1 + 1, i2 + 1, i3, cur::jx3)) }, j_t); - buff += e_t[0] * j_t[0] + e_t[1] * j_t[1] + e_t[2] * j_t[2]; + buff += (e_t[0] * j_t[0] + e_t[1] * j_t[1] + e_t[2] * j_t[2]) * + metric.sqrt_det_h({ i1_ + HALF, i2_ + HALF, i3_ + HALF }); } } }; diff --git a/src/kernels/tests/reduced_stats.cpp b/src/kernels/tests/reduced_stats.cpp index 4be11a2f7..caae51ccd 100644 --- a/src/kernels/tests/reduced_stats.cpp +++ b/src/kernels/tests/reduced_stats.cpp @@ -62,8 +62,6 @@ void put_value(ndfield_t& arr, real_t v, unsigned short c) { Kokkos::parallel_for("Fill", range, Fill_kernel(arr, v, c)); } -inline static constexpr auto epsilon = std::numeric_limits::epsilon(); - template auto compute_field_stat(const M& metric, const ndfield_t& em, @@ -75,13 +73,18 @@ auto compute_field_stat(const M& metric, range, kernel::ReducedFields_kernel(em, j, metric), buff); - return buff / static_cast(num_cells); + return buff / metric.totVolume(); +} + +auto almost_equal(real_t a, real_t b, real_t acc) -> bool { + return (math::fabs(a - b) < acc * math::max(math::fabs(a), math::fabs(b))) + + (real_t)1e-10; } template void testReducedStats(const std::vector& res, const boundaries_t& ext, - const real_t acc = ONE) { + const real_t acc) { raise::ErrorIf(res.size() != M::Dim, "Invalid resolution size", HERE); M metric { res, ext, {} }; @@ -185,8 +188,7 @@ void testReducedStats(const std::vector& res, J, cell_range, num_cells); - printf("Ex_Sq: %.12e\n", Ex_Sq); - raise::ErrorIf(not cmp::AlmostEqual_host(Ex_Sq, (real_t)(1), acc * epsilon), + raise::ErrorIf(not almost_equal(Ex_Sq, (real_t)(1), acc), "Ex_Sq does not match expected value", HERE); } @@ -197,7 +199,7 @@ void testReducedStats(const std::vector& res, J, cell_range, num_cells); - raise::ErrorIf(not cmp::AlmostEqual_host(Ey_Sq, (real_t)(4), acc * epsilon), + raise::ErrorIf(not almost_equal(Ey_Sq, (real_t)(4), acc), "Ey_Sq does not match expected value", HERE); } @@ -208,7 +210,7 @@ void testReducedStats(const std::vector& res, J, cell_range, num_cells); - raise::ErrorIf(not cmp::AlmostEqual_host(Ez_Sq, (real_t)(9), acc * epsilon), + raise::ErrorIf(not almost_equal(Ez_Sq, (real_t)(9), acc), "Ez_Sq does not match expected value", HERE); } @@ -219,7 +221,7 @@ void testReducedStats(const std::vector& res, J, cell_range, num_cells); - raise::ErrorIf(not cmp::AlmostEqual_host(Bx_Sq, (real_t)(1), acc * epsilon), + raise::ErrorIf(not almost_equal(Bx_Sq, (real_t)(1), acc), "Bx_Sq does not match expected value", HERE); } @@ -230,7 +232,7 @@ void testReducedStats(const std::vector& res, J, cell_range, num_cells); - raise::ErrorIf(not cmp::AlmostEqual_host(By_Sq, (real_t)(4), acc * epsilon), + raise::ErrorIf(not almost_equal(By_Sq, (real_t)(4), acc), "By_Sq does not match expected value", HERE); } @@ -241,7 +243,7 @@ void testReducedStats(const std::vector& res, J, cell_range, num_cells); - raise::ErrorIf(not cmp::AlmostEqual_host(Bz_Sq, (real_t)(9), acc * epsilon), + raise::ErrorIf(not almost_equal(Bz_Sq, (real_t)(9), acc), "Bz_Sq does not match expected value", HERE); } @@ -252,7 +254,7 @@ void testReducedStats(const std::vector& res, J, cell_range, num_cells); - raise::ErrorIf(not cmp::AlmostEqual_host(ExB_x, (real_t)(12), acc * epsilon), + raise::ErrorIf(not almost_equal(ExB_x, (real_t)(12), acc), "ExB_x does not match expected value", HERE); } @@ -263,7 +265,7 @@ void testReducedStats(const std::vector& res, J, cell_range, num_cells); - raise::ErrorIf(not cmp::AlmostEqual_host(ExB_y, (real_t)(-6), acc * epsilon), + raise::ErrorIf(not almost_equal(ExB_y, (real_t)(-6), acc), "ExB_y does not match expected value", HERE); } @@ -274,7 +276,7 @@ void testReducedStats(const std::vector& res, J, cell_range, num_cells); - raise::ErrorIf(not cmp::AlmostEqual_host(ExB_z, (real_t)(0), acc * epsilon), + raise::ErrorIf(not almost_equal(ExB_z, (real_t)(0), acc), "ExB_z does not match expected value", HERE); } @@ -285,7 +287,7 @@ void testReducedStats(const std::vector& res, J, cell_range, num_cells); - raise::ErrorIf(not cmp::AlmostEqual_host(JdotE, (real_t)(11), acc * epsilon), + raise::ErrorIf(not almost_equal(JdotE, (real_t)(11), acc), "JdotE does not match expected value", HERE); } @@ -302,13 +304,13 @@ auto main(int argc, char* argv[]) -> int { std::pair y_ext { 0.0, 4.92 }; std::pair z_ext { 0.0, 2.08 }; - testReducedStats>({ nx }, { x_ext }, 10); + testReducedStats>({ nx }, { x_ext }, 1e-6); testReducedStats>({ nx, ny }, { x_ext, y_ext }, - 10); + 1e-6); testReducedStats>({ nx, ny, nz }, { x_ext, y_ext, z_ext }, - 10); + 1e-6); } catch (std::exception& e) { std::cerr << e.what() << std::endl; diff --git a/src/metrics/kerr_schild.h b/src/metrics/kerr_schild.h index 13294dd7d..5edd43f2e 100644 --- a/src/metrics/kerr_schild.h +++ b/src/metrics/kerr_schild.h @@ -127,6 +127,15 @@ namespace metric { return min_dx; } + /** + * total volume of the region described by the metric (in physical units) + */ + [[nodiscard]] + auto totVolume() const -> real_t override { + // @TODO: Ask Alisa + return ZERO; + } + /** * metric component with lower indices: h_ij * @param x coordinate array in code units diff --git a/src/metrics/kerr_schild_0.h b/src/metrics/kerr_schild_0.h index fdd2fd847..6e4f86c17 100644 --- a/src/metrics/kerr_schild_0.h +++ b/src/metrics/kerr_schild_0.h @@ -104,6 +104,20 @@ namespace metric { return min_dx; } + /** + * total volume of the region described by the metric (in physical units) + */ + [[nodiscard]] + auto totVolume() const -> real_t override { + if constexpr (D == Dim::_1D) { + raise::Error("1D spherical metric not applicable", HERE); + } else if constexpr (D == Dim::_2D) { + return (SQR(x1_max) - SQR(x1_min)) * (x2_max - x2_min); + } else { + return (SQR(x1_max) - SQR(x1_min)) * (x2_max - x2_min) * (x3_max - x3_min); + } + } + /** * metric component with lower indices: h_ij * @param x coordinate array in code units diff --git a/src/metrics/metric_base.h b/src/metrics/metric_base.h index 66cc28918..b386d46a0 100644 --- a/src/metrics/metric_base.h +++ b/src/metrics/metric_base.h @@ -77,6 +77,9 @@ namespace metric { [[nodiscard]] virtual auto find_dxMin() const -> real_t = 0; + [[nodiscard]] + virtual auto totVolume() const -> real_t = 0; + [[nodiscard]] auto dxMin() const -> real_t { return dx_min; diff --git a/src/metrics/minkowski.h b/src/metrics/minkowski.h index 244ce9f25..c1eda49dc 100644 --- a/src/metrics/minkowski.h +++ b/src/metrics/minkowski.h @@ -55,16 +55,18 @@ namespace metric { , dx_inv { ONE / dx } { set_dxMin(find_dxMin()); const auto epsilon = std::numeric_limits::epsilon() * - static_cast(100.0); + static_cast(100.0); if constexpr (D != Dim::_1D) { - raise::ErrorIf(not cmp::AlmostEqual((x2_max - x2_min) / (real_t)(nx2), dx, epsilon), - "dx2 must be equal to dx1 in 2D", - HERE); + raise::ErrorIf( + not cmp::AlmostEqual((x2_max - x2_min) / (real_t)(nx2), dx, epsilon), + "dx2 must be equal to dx1 in 2D", + HERE); } if constexpr (D == Dim::_3D) { - raise::ErrorIf(not cmp::AlmostEqual((x3_max - x3_min) / (real_t)(nx3), dx, epsilon), - "dx3 must be equal to dx1 in 3D", - HERE); + raise::ErrorIf( + not cmp::AlmostEqual((x3_max - x3_min) / (real_t)(nx3), dx, epsilon), + "dx3 must be equal to dx1 in 3D", + HERE); } } @@ -78,6 +80,20 @@ namespace metric { return dx / math::sqrt(static_cast(D)); } + /** + * total volume of the region described by the metric (in physical units) + */ + [[nodiscard]] + auto totVolume() const -> real_t override { + if constexpr (D == Dim::_1D) { + return x1_max - x1_min; + } else if constexpr (D == Dim::_2D) { + return (x1_max - x1_min) * (x2_max - x2_min); + } else { + return (x1_max - x1_min) * (x2_max - x2_min) * (x3_max - x3_min); + } + } + /** * metric component with lower indices: h_ij * @param x coordinate array in code units @@ -242,7 +258,8 @@ namespace metric { * @note tetrad/cart <-> cntrv <-> cov */ template - Inline auto transform(const coord_t& xi, const real_t& v_in) const -> real_t { + Inline auto transform(const coord_t& xi, const real_t& v_in) const + -> real_t { static_assert(i > 0 && i <= 3, "Invalid index i"); static_assert(in != out, "Invalid vector transformation"); if constexpr (i > static_cast(D)) { diff --git a/src/metrics/qkerr_schild.h b/src/metrics/qkerr_schild.h index d64fe05da..7d327b892 100644 --- a/src/metrics/qkerr_schild.h +++ b/src/metrics/qkerr_schild.h @@ -132,6 +132,15 @@ namespace metric { return min_dx; } + /** + * total volume of the region described by the metric (in physical units) + */ + [[nodiscard]] + auto totVolume() const -> real_t override { + // @TODO: Ask Alisa + return ZERO; + } + /** * metric component with lower indices: h_ij * @param x coordinate array in code units diff --git a/src/metrics/qspherical.h b/src/metrics/qspherical.h index 4df5db866..2af1f02ae 100644 --- a/src/metrics/qspherical.h +++ b/src/metrics/qspherical.h @@ -97,6 +97,20 @@ namespace metric { return min_dx; } + /** + * total volume of the region described by the metric (in physical units) + */ + [[nodiscard]] + auto totVolume() const -> real_t override { + if constexpr (D == Dim::_1D) { + raise::Error("1D spherical metric not applicable", HERE); + } else if constexpr (D == Dim::_2D) { + return (SQR(x1_max) - SQR(x1_min)) * (x2_max - x2_min); + } else { + return (SQR(x1_max) - SQR(x1_min)) * (x2_max - x2_min) * (x3_max - x3_min); + } + } + /** * metric component with lower indices: h_ij * @param x coordinate array in code units @@ -284,7 +298,8 @@ namespace metric { * @note tetrad/sph <-> cntrv <-> cov */ template - Inline auto transform(const coord_t& xi, const real_t& v_in) const -> real_t { + Inline auto transform(const coord_t& xi, const real_t& v_in) const + -> real_t { static_assert(i > 0 && i <= 3, "Invalid index i"); static_assert(in != out, "Invalid vector transformation"); if constexpr ((in == Idx::T && out == Idx::Sph) || diff --git a/src/metrics/spherical.h b/src/metrics/spherical.h index 54e12367d..bf4c34538 100644 --- a/src/metrics/spherical.h +++ b/src/metrics/spherical.h @@ -76,6 +76,20 @@ namespace metric { return ONE / math::sqrt(ONE / SQR(dx1) + ONE / SQR(dx2)); } + /** + * total volume of the region described by the metric (in physical units) + */ + [[nodiscard]] + auto totVolume() const -> real_t override { + if constexpr (D == Dim::_1D) { + raise::Error("1D spherical metric not applicable", HERE); + } else if constexpr (D == Dim::_2D) { + return (SQR(x1_max) - SQR(x1_min)) * (x2_max - x2_min); + } else { + return (SQR(x1_max) - SQR(x1_min)) * (x2_max - x2_min) * (x3_max - x3_min); + } + } + /** * metric component with lower indices: h_ij * @param x coordinate array in code units @@ -252,7 +266,8 @@ namespace metric { * @note tetrad/sph <-> cntrv <-> cov */ template - Inline auto transform(const coord_t& xi, const real_t& v_in) const -> real_t { + Inline auto transform(const coord_t& xi, const real_t& v_in) const + -> real_t { static_assert(i > 0 && i <= 3, "Invalid index i"); static_assert(in != out, "Invalid vector transformation"); if constexpr ((in == Idx::T && out == Idx::Sph) || diff --git a/src/output/stats.h b/src/output/stats.h index 6fec08642..171617215 100644 --- a/src/output/stats.h +++ b/src/output/stats.h @@ -159,7 +159,7 @@ namespace stats { template inline void write(const T& value) const { - T tot_value = static_cast(0); + auto tot_value { static_cast(0) }; #if defined(MPI_ENABLED) MPI_Reduce(&value, &tot_value, @@ -169,7 +169,7 @@ namespace stats { MPI_ROOT_RANK, MPI_COMM_WORLD); #else - T tot_value = value; + tot_value = value; #endif CallOnce( [](auto&& fname, auto&& value) { From be4b51ccab846336b582244166a48446fb98812c Mon Sep 17 00:00:00 2001 From: hayk Date: Sat, 24 May 2025 16:29:13 -0400 Subject: [PATCH 710/773] prtl mom stat --- src/framework/domain/stats.cpp | 116 ++++++++--------- src/kernels/particle_moments.hpp | 16 +-- src/kernels/reduced_stats.hpp | 161 +++++++++++++++++++++++ src/kernels/tests/particle_moments.cpp | 169 +++++++++++++++---------- 4 files changed, 324 insertions(+), 138 deletions(-) diff --git a/src/framework/domain/stats.cpp b/src/framework/domain/stats.cpp index 75a4edd1d..95be528eb 100644 --- a/src/framework/domain/stats.cpp +++ b/src/framework/domain/stats.cpp @@ -2,6 +2,7 @@ #include "global.h" #include "arch/kokkos_aliases.h" +#include "utils/comparators.h" #include "utils/error.h" #include "utils/log.h" #include "utils/numeric.h" @@ -64,12 +65,12 @@ namespace ntt { } } - template + template auto ComputeMoments(const SimulationParams& params, const Mesh& mesh, const std::vector>& prtl_species, const std::vector& species, - const std::vector& components) -> T { + const std::vector& components) -> real_t { std::vector specs = species; if (specs.size() == 0) { // if no species specified, take all massive species @@ -88,28 +89,35 @@ namespace ntt { const auto use_weights = params.template get("particles.use_weights"); const auto inv_n0 = ONE / params.template get("scales.n0"); - T buffer = static_cast(0); + real_t buffer = static_cast(0); for (const auto& sp : specs) { auto& prtl_spec = prtl_species[sp - 1]; - // Kokkos::parallel_reduce( - // "ComputeMoments", - // prtl_spec.rangeActiveParticles(), - // // clang-format off - // kernel::ReducedParticleMoments_kernel(components, - // prtl_spec.i1, prtl_spec.i2, prtl_spec.i3, - // prtl_spec.dx1, prtl_spec.dx2, prtl_spec.dx3, - // prtl_spec.ux1, prtl_spec.ux2, prtl_spec.ux3, - // prtl_spec.phi, prtl_spec.weight, prtl_spec.tag, - // prtl_spec.mass(), prtl_spec.charge(), - // use_weights, mesh.metric, mesh.flds_bc(), inv_n0), - // // clang-format on - // buffer); + if (P == StatsID::Charge and cmp::AlmostZero_host(prtl_spec.charge())) { + continue; + } + if (P == StatsID::Rho and cmp::AlmostZero_host(prtl_spec.mass())) { + continue; + } + Kokkos::parallel_reduce( + "ComputeMoments", + prtl_spec.rangeActiveParticles(), + // clang-format off + kernel::ReducedParticleMoments_kernel(components, + prtl_spec.i1, prtl_spec.i2, prtl_spec.i3, + prtl_spec.dx1, prtl_spec.dx2, prtl_spec.dx3, + prtl_spec.ux1, prtl_spec.ux2, prtl_spec.ux3, + prtl_spec.phi, prtl_spec.weight, prtl_spec.tag, + prtl_spec.mass(), prtl_spec.charge(), + use_weights, mesh.metric), + // clang-format on + buffer); } return buffer; } template auto ReduceFields(Domain* domain, + const M& global_metric, const std::vector& components) -> real_t { auto buffer { ZERO }; if constexpr (F == StatsID::JdotE) { @@ -166,16 +174,7 @@ namespace ntt { HERE); } - // @TODO: not going to work for arbitrary metric - return buffer / static_cast(domain->mesh.num_active()); - // Kokkos::parallel_reduce( - // "ComputeMoments", - // prtl_spec.rangeActiveParticles(), - // kernel::ReducedFields_kernel(components, - // domain->fields.em, - // domain->fields.cur, - // domain->mesh.metric), - // buffer); + return buffer / global_metric.totVolume(); } template @@ -184,11 +183,6 @@ namespace ntt { timestep_t finished_step, simtime_t current_time, simtime_t finished_time) -> bool { - // @TODO: remove when stats are supported for all coordinate systems - raise::ErrorIf( - M::CoordType != Coord::Cart, - "Stats writing is only supported for Cartesian coordinates for now", - HERE); if (not(params.template get("output.stats.enable") and g_stats_writer.shouldWrite(finished_step, finished_time))) { return false; @@ -199,59 +193,59 @@ namespace ntt { g_stats_writer.write(current_time); for (const auto& stat : g_stats_writer.statsWriters()) { if (stat.id() == StatsID::N) { - g_stats_writer.write( - ComputeMoments(params, - local_domain->mesh, - local_domain->species, - stat.species, - {})); + g_stats_writer.write(ComputeMoments(params, + local_domain->mesh, + local_domain->species, + stat.species, + {})); } else if (stat.id() == StatsID::Npart) { g_stats_writer.write( - ComputeMoments(params, - local_domain->mesh, - local_domain->species, - stat.species, - {})); + ComputeMoments(params, + local_domain->mesh, + local_domain->species, + stat.species, + {})); } else if (stat.id() == StatsID::Rho) { g_stats_writer.write( - ComputeMoments(params, - local_domain->mesh, - local_domain->species, - stat.species, - {})); + ComputeMoments(params, + local_domain->mesh, + local_domain->species, + stat.species, + {})); } else if (stat.id() == StatsID::Charge) { g_stats_writer.write( - ComputeMoments(params, - local_domain->mesh, - local_domain->species, - stat.species, - {})); + ComputeMoments(params, + local_domain->mesh, + local_domain->species, + stat.species, + {})); } else if (stat.id() == StatsID::T) { for (const auto& comp : stat.comp) { g_stats_writer.write( - ComputeMoments(params, - local_domain->mesh, - local_domain->species, - stat.species, - comp)); + ComputeMoments(params, + local_domain->mesh, + local_domain->species, + stat.species, + comp)); } } else if (stat.id() == StatsID::JdotE) { - g_stats_writer.write(ReduceFields(local_domain, {})); + g_stats_writer.write( + ReduceFields(local_domain, g_mesh.metric, {})); } else if (S == SimEngine::SRPIC) { if (stat.id() == StatsID::E2) { for (const auto& comp : stat.comp) { g_stats_writer.write( - ReduceFields(local_domain, comp)); + ReduceFields(local_domain, g_mesh.metric, comp)); } } else if (stat.id() == StatsID::B2) { for (const auto& comp : stat.comp) { g_stats_writer.write( - ReduceFields(local_domain, comp)); + ReduceFields(local_domain, g_mesh.metric, comp)); } } else if (stat.id() == StatsID::ExB) { for (const auto& comp : stat.comp) { g_stats_writer.write( - ReduceFields(local_domain, comp)); + ReduceFields(local_domain, g_mesh.metric, comp)); } } else { raise::Error("Unrecognized stats ID " + stat.name(), HERE); diff --git a/src/kernels/particle_moments.hpp b/src/kernels/particle_moments.hpp index 8be68f5d2..9c66aed01 100644 --- a/src/kernels/particle_moments.hpp +++ b/src/kernels/particle_moments.hpp @@ -59,7 +59,6 @@ namespace kernel { const bool use_weights; const M metric; const int ni2; - const real_t inv_n0; const unsigned short window; const real_t contrib; @@ -113,11 +112,10 @@ namespace kernel { , use_weights { use_weights } , metric { metric } , ni2 { static_cast(ni2) } - , inv_n0 { inv_n0 } , window { window } , contrib { get_contrib(mass, charge) } - , smooth { ONE / (real_t)(math::pow(TWO * (real_t)window + ONE, - static_cast(D))) } { + , smooth { inv_n0 / (real_t)(math::pow(TWO * (real_t)window + ONE, + static_cast(D))) } { raise::ErrorIf(buff_idx >= N, "Invalid buffer index", HERE); raise::ErrorIf(window > N_GHOSTS, "Window size too large", HERE); raise::ErrorIf(((F == FldsID::Rho) || (F == FldsID::Charge)) && (mass == ZERO), @@ -296,19 +294,21 @@ namespace kernel { // for nppc calculation ... // ... do not take volume, weights or smoothing into account if constexpr (D == Dim::_1D) { - coeff *= inv_n0 / + coeff *= smooth / metric.sqrt_det_h({ static_cast(i1(p)) + HALF }); } else if constexpr (D == Dim::_2D) { - coeff *= inv_n0 / + coeff *= smooth / metric.sqrt_det_h({ static_cast(i1(p)) + HALF, static_cast(i2(p)) + HALF }); } else if constexpr (D == Dim::_3D) { - coeff *= inv_n0 / + coeff *= smooth / metric.sqrt_det_h({ static_cast(i1(p)) + HALF, static_cast(i2(p)) + HALF, static_cast(i3(p)) + HALF }); } - coeff *= weight(p) * smooth; + if (use_weights) { + coeff *= weight(p); + } } auto buff_access = Buff.access(); if constexpr (D == Dim::_1D) { diff --git a/src/kernels/reduced_stats.hpp b/src/kernels/reduced_stats.hpp index 6b6c4df2c..68e6aa97b 100644 --- a/src/kernels/reduced_stats.hpp +++ b/src/kernels/reduced_stats.hpp @@ -385,6 +385,167 @@ namespace kernel { } }; + template + auto get_contrib(float mass, float charge) -> real_t { + if constexpr (P == StatsID::Rho) { + return mass; + } else if constexpr (P == StatsID::Charge) { + return charge; + } else { + return ONE; + } + } + + template + class ReducedParticleMoments_kernel { + static_assert(M::is_metric, "M must be a metric class"); + static constexpr auto D = M::Dim; + + static_assert((P == StatsID::Rho) || (P == StatsID::Charge) || + (P == StatsID::N) || (P == StatsID::Npart) || + (P == StatsID::T), + "Invalid stats ID"); + + const unsigned short c1, c2; + const array_t i1, i2, i3; + const array_t dx1, dx2, dx3; + const array_t ux1, ux2, ux3; + const array_t phi; + const array_t weight; + const array_t tag; + const float mass; + const float charge; + const bool use_weights; + const M metric; + + const real_t contrib; + + public: + ReducedParticleMoments_kernel(const std::vector& components, + const array_t& i1, + const array_t& i2, + const array_t& i3, + const array_t& dx1, + const array_t& dx2, + const array_t& dx3, + const array_t& ux1, + const array_t& ux2, + const array_t& ux3, + const array_t& phi, + const array_t& weight, + const array_t& tag, + float mass, + float charge, + bool use_weights, + const M& metric) + : c1 { (components.size() > 0) ? components[0] + : static_cast(0) } + , c2 { (components.size() == 2) ? components[1] + : static_cast(0) } + , i1 { i1 } + , i2 { i2 } + , i3 { i3 } + , dx1 { dx1 } + , dx2 { dx2 } + , dx3 { dx3 } + , ux1 { ux1 } + , ux2 { ux2 } + , ux3 { ux3 } + , phi { phi } + , weight { weight } + , tag { tag } + , mass { mass } + , charge { charge } + , use_weights { use_weights } + , metric { metric } + , contrib { get_contrib

(mass, charge) } { + raise::ErrorIf(((P == StatsID::Rho) || (P == StatsID::Charge)) && + (mass == ZERO), + "Rho & Charge for massless particles not defined", + HERE); + } + + Inline void operator()(index_t p, real_t& buff) const { + if (tag(p) == ParticleTag::dead) { + return; + } + if constexpr (P == StatsID::Npart) { + buff += ONE; + return; + } else if constexpr (P == StatsID::N or P == StatsID::Rho or + P == StatsID::Charge) { + buff += use_weights ? weight(p) : contrib; + return; + } else { + // for stress-energy tensor + real_t energy { ZERO }; + vec_t u_Phys { ZERO }; + if constexpr (S == SimEngine::SRPIC) { + // SR + // stress-energy tensor for SR is computed in the tetrad (hatted) basis + if constexpr (M::CoordType == Coord::Cart) { + u_Phys[0] = ux1(p); + u_Phys[1] = ux2(p); + u_Phys[2] = ux3(p); + } else { + static_assert(D != Dim::_1D, "non-Cartesian SRPIC 1D"); + coord_t x_Code { ZERO }; + x_Code[0] = static_cast(i1(p)) + static_cast(dx1(p)); + x_Code[1] = static_cast(i2(p)) + static_cast(dx2(p)); + if constexpr (D == Dim::_3D) { + x_Code[2] = static_cast(i3(p)) + static_cast(dx3(p)); + } else { + x_Code[2] = phi(p); + } + metric.template transform_xyz( + x_Code, + { ux1(p), ux2(p), ux3(p) }, + u_Phys); + } + if (mass == ZERO) { + energy = NORM(u_Phys[0], u_Phys[1], u_Phys[2]); + } else { + energy = mass * + math::sqrt(ONE + NORM_SQR(u_Phys[0], u_Phys[1], u_Phys[2])); + } + } else { + // GR + // stress-energy tensor for GR is computed in contravariant basis + static_assert(D != Dim::_1D, "GRPIC 1D"); + coord_t x_Code { ZERO }; + x_Code[0] = static_cast(i1(p)) + static_cast(dx1(p)); + x_Code[1] = static_cast(i2(p)) + static_cast(dx2(p)); + if constexpr (D == Dim::_3D) { + x_Code[2] = static_cast(i3(p)) + static_cast(dx3(p)); + } + vec_t u_Cntrv { ZERO }; + // compute u_i u^i for energy + metric.template transform(x_Code, + { ux1(p), ux2(p), ux3(p) }, + u_Cntrv); + energy = u_Cntrv[0] * ux1(p) + u_Cntrv[1] * ux2(p) + u_Cntrv[2] * ux3(p); + if (mass == ZERO) { + energy = math::sqrt(energy); + } else { + energy = mass * math::sqrt(ONE + energy); + } + metric.template transform(x_Code, u_Cntrv, u_Phys); + } + // compute the corresponding moment + real_t coeff = ONE; +#pragma unroll + for (const auto& c : { c1, c2 }) { + if (c == 0) { + coeff *= energy; + } else { + coeff *= u_Phys[c - 1]; + } + } + buff += coeff / energy; + } + } + }; + } // namespace kernel #endif diff --git a/src/kernels/tests/particle_moments.cpp b/src/kernels/tests/particle_moments.cpp index bef1592df..ca3c2a7a0 100644 --- a/src/kernels/tests/particle_moments.cpp +++ b/src/kernels/tests/particle_moments.cpp @@ -12,6 +12,8 @@ #include "metrics/qspherical.h" #include "metrics/spherical.h" +#include "kernels/reduced_stats.hpp" + #include #include @@ -116,84 +118,85 @@ void testParticleMoments(const std::vector& res, const unsigned short window = 1; auto scatter_buff = Kokkos::Experimental::create_scatter_view(buff); + // clang-format off Kokkos::parallel_for( - "ParticleMoments", - 10, - kernel::ParticleMoments_kernel(comp1, - scatter_buff, - 0, - i1, - i2, - i3, - dx1, - dx2, - dx3, - ux1, - ux2, - ux3, - phi, - weight, - tag, - mass, - charge, + "ParticleMoments", 10, + kernel::ParticleMoments_kernel(comp1, scatter_buff, 0, + i1, i2, i3, + dx1, dx2, dx3, + ux1, ux2, ux3, + phi, weight, tag, + mass, charge, use_weights, metric, - boundaries, - nx2, - inv_n0, - window)); + boundaries, nx2, inv_n0, window)); + Kokkos::parallel_for( - "ParticleMoments", - 10, - kernel::ParticleMoments_kernel(comp2, - scatter_buff, - 1, - i1, - i2, - i3, - dx1, - dx2, - dx3, - ux1, - ux2, - ux3, - phi, - weight, - tag, - mass, - charge, + "ParticleMoments", 10, + kernel::ParticleMoments_kernel(comp2, scatter_buff, 1, + i1, i2, i3, + dx1, dx2, dx3, + ux1, ux2, ux3, + phi, weight, tag, + mass, charge, use_weights, metric, - boundaries, - nx2, - inv_n0, - window)); + boundaries, nx2, inv_n0, window)); Kokkos::parallel_for( - "ParticleMoments", - 10, - kernel::ParticleMoments_kernel(comp3, - scatter_buff, - 2, - i1, - i2, - i3, - dx1, - dx2, - dx3, - ux1, - ux2, - ux3, - phi, - weight, - tag, - mass, - charge, + "ParticleMoments", 10, + kernel::ParticleMoments_kernel(comp3, scatter_buff, 2, + i1, i2, i3, + dx1, dx2, dx3, + ux1, ux2, ux3, + phi, weight, tag, + mass, charge, use_weights, metric, - boundaries, - nx2, - inv_n0, - window)); + boundaries, nx2, inv_n0, window)); + + real_t n = ZERO, npart = ZERO, rho = ZERO, t00 = ZERO; + Kokkos::parallel_reduce( + "ReducedParticleMoments", 10, + kernel::ReducedParticleMoments_kernel({}, + i1, i2, i3, + dx1, dx2, dx3, + ux1, ux2, ux3, + phi, weight, tag, + mass, charge, + use_weights, + metric), n); + + Kokkos::parallel_reduce( + "ReducedParticleMoments", 10, + kernel::ReducedParticleMoments_kernel({}, + i1, i2, i3, + dx1, dx2, dx3, + ux1, ux2, ux3, + phi, weight, tag, + mass, charge, + use_weights, + metric), npart); + Kokkos::parallel_reduce( + "ReducedParticleMoments", 10, + kernel::ReducedParticleMoments_kernel({}, + i1, i2, i3, + dx1, dx2, dx3, + ux1, ux2, ux3, + phi, weight, tag, + mass, charge, + use_weights, + metric), rho); + Kokkos::parallel_reduce( + "ReducedParticleMoments", 10, + kernel::ReducedParticleMoments_kernel({0u, 0u}, + i1, i2, i3, + dx1, dx2, dx3, + ux1, ux2, ux3, + phi, weight, tag, + mass, charge, + use_weights, + metric), t00); + // clang-format on Kokkos::Experimental::contribute(buff, scatter_buff); auto i1_h = Kokkos::create_mirror_view(i1); @@ -230,6 +233,9 @@ void testParticleMoments(const std::vector& res, const real_t gammaSQR_1_expect = 15.0; const real_t gammaSQR_2_expect = 15.0; + const real_t n_expect = 2.0; + const real_t t00_expect = 2.0 * math::sqrt(15.0); + errorIf(not cmp::AlmostEqual_host(gammaSQR_1, gammaSQR_1_expect, epsilon * acc), fmt::format("wrong gamma_1 %.12e %.12e for %dD %s", gammaSQR_1, @@ -242,6 +248,31 @@ void testParticleMoments(const std::vector& res, gammaSQR_2_expect, metric.Dim, metric.Label)); + + errorIf(not cmp::AlmostEqual_host(n, n_expect, epsilon * acc), + fmt::format("wrong n reduction %.12e %.12e for %dD %s", + n, + n_expect, + metric.Dim, + metric.Label)); + errorIf(not cmp::AlmostEqual_host(npart, n_expect, epsilon * acc), + fmt::format("wrong npart reduction %.12e %.12e for %dD %s", + npart, + n_expect, + metric.Dim, + metric.Label)); + errorIf(not cmp::AlmostEqual_host(rho, n_expect, epsilon * acc), + fmt::format("wrong rho reduction %.12e %.12e for %dD %s", + rho, + n_expect, + metric.Dim, + metric.Label)); + errorIf(not cmp::AlmostEqual_host(t00, t00_expect, epsilon * acc), + fmt::format("wrong t00 reduction %.12e %.12e for %dD %s", + t00, + t00_expect, + metric.Dim, + metric.Label)); } } From a7b0d7e293e0177ccf2fb6047f38c82395bf092a Mon Sep 17 00:00:00 2001 From: hayk Date: Sat, 24 May 2025 16:49:51 -0400 Subject: [PATCH 711/773] stats ready --- pgens/reconnection/reconnection.toml | 38 ++++++++++++++++++++-------- src/output/stats.cpp | 8 +++--- src/output/stats.h | 3 ++- 3 files changed, 35 insertions(+), 14 deletions(-) diff --git a/pgens/reconnection/reconnection.toml b/pgens/reconnection/reconnection.toml index 62c1ffe80..76acbf089 100644 --- a/pgens/reconnection/reconnection.toml +++ b/pgens/reconnection/reconnection.toml @@ -3,29 +3,35 @@ engine = "srpic" runtime = 10.0 + [simulation.domain] + decomposition = [-1, 2] + [grid] - resolution = [1024, 512] - extent = [[-1.0, 1.0], [-0.5, 0.5]] + resolution = [512, 512] + extent = [[-1.0, 1.0], [-1.0, 1.0]] [grid.metric] metric = "minkowski" [grid.boundaries] - fields = [["PERIODIC"], ["MATCH", "MATCH"], ["PERIODIC"]] - particles = [["PERIODIC"], ["ABSORB", "ABSORB"], ["PERIODIC"]] + fields = [["PERIODIC"], ["MATCH", "MATCH"]] + particles = [["PERIODIC"], ["ABSORB", "ABSORB"]] + + [grid.boundaries.match] + ds = [[0.04], [0.1]] [scales] larmor0 = 2e-4 skindepth0 = 2e-3 [algorithms] - current_filters = 4 + current_filters = 8 [algorithms.timestep] CFL = 0.5 [particles] - ppc0 = 2.0 + ppc0 = 8.0 [[particles.species]] label = "e-" @@ -40,10 +46,12 @@ maxnpart = 1e7 [setup] - Bmag = 1.0 - width = 0.01 - bg_temp = 1e-4 - overdensity = 3.0 + bg_B = 1.0 + bg_Bguide = 0.0 + bg_temperature = 1e-4 + inj_ypad = 0.25 + cs_width = 0.05 + cs_overdensity = 3.0 [output] format = "hdf5" @@ -51,3 +59,13 @@ [output.fields] quantities = ["N_1", "N_2", "E", "B", "J"] + + [output.particles] + enable = false + + [output.spectra] + enable = false + +[diagnostics] + colored_stdout = true + interval = 10 diff --git a/src/output/stats.cpp b/src/output/stats.cpp index 68392dc0b..407a5bd38 100644 --- a/src/output/stats.cpp +++ b/src/output/stats.cpp @@ -11,6 +11,7 @@ #include +#include #include #include @@ -71,14 +72,15 @@ namespace stats { CallOnce( [](auto& fname, auto& stat_writers) { std::fstream StatsOut(fname, std::fstream::out | std::fstream::app); - StatsOut << "step,time,"; + StatsOut << std::setw(14) << "step" << "," << std::setw(14) << "time" + << ","; for (const auto& stat : stat_writers) { if (stat.is_vector()) { for (auto i { 0u }; i < stat.comp.size(); ++i) { - StatsOut << stat.name(i) << ","; + StatsOut << std::setw(14) << stat.name(i) << ","; } } else { - StatsOut << stat.name() << ","; + StatsOut << std::setw(14) << stat.name() << ","; } } StatsOut << std::endl; diff --git a/src/output/stats.h b/src/output/stats.h index 171617215..cd48e6ca4 100644 --- a/src/output/stats.h +++ b/src/output/stats.h @@ -27,6 +27,7 @@ #endif #include +#include #include #include @@ -174,7 +175,7 @@ namespace stats { CallOnce( [](auto&& fname, auto&& value) { std::fstream StatsOut(fname, std::fstream::out | std::fstream::app); - StatsOut << value << ","; + StatsOut << std::setw(14) << value << ","; StatsOut.close(); }, m_fname, From 71a8d42b823a5ab8bc6c74354cfe1ba313dad2ad Mon Sep 17 00:00:00 2001 From: hayk Date: Sat, 24 May 2025 18:18:38 -0400 Subject: [PATCH 712/773] macro for specialized initialization --- src/framework/domain/checkpoint.cpp | 115 +++------------- src/framework/domain/communications.cpp | 128 ++++-------------- src/framework/domain/output.cpp | 170 ++++++------------------ 3 files changed, 88 insertions(+), 325 deletions(-) diff --git a/src/framework/domain/checkpoint.cpp b/src/framework/domain/checkpoint.cpp index 25cdcf0f6..a39f18e66 100644 --- a/src/framework/domain/checkpoint.cpp +++ b/src/framework/domain/checkpoint.cpp @@ -474,103 +474,26 @@ namespace ntt { HERE); } - template void Metadomain>::InitCheckpointWriter( - adios2::ADIOS*, - const SimulationParams&); - template void Metadomain>::InitCheckpointWriter( - adios2::ADIOS*, - const SimulationParams&); - template void Metadomain>::InitCheckpointWriter( - adios2::ADIOS*, - const SimulationParams&); - template void Metadomain>::InitCheckpointWriter( - adios2::ADIOS*, - const SimulationParams&); - template void Metadomain>::InitCheckpointWriter( - adios2::ADIOS*, - const SimulationParams&); - template void Metadomain>::InitCheckpointWriter( - adios2::ADIOS*, - const SimulationParams&); - template void Metadomain>::InitCheckpointWriter( - adios2::ADIOS*, - const SimulationParams&); - template void Metadomain>::InitCheckpointWriter( - adios2::ADIOS*, - const SimulationParams&); +#define METADOMAIN_CHECKPOINTS(S, M) \ + template void Metadomain::InitCheckpointWriter(adios2::ADIOS*, \ + const SimulationParams&); \ + template auto Metadomain::WriteCheckpoint(const SimulationParams&, \ + timestep_t, \ + timestep_t, \ + simtime_t, \ + simtime_t) -> bool; \ + template void Metadomain::ContinueFromCheckpoint(adios2::ADIOS*, \ + const SimulationParams&); - template auto Metadomain>::WriteCheckpoint( - const SimulationParams&, - timestep_t, - timestep_t, - simtime_t, - simtime_t) -> bool; - template auto Metadomain>::WriteCheckpoint( - const SimulationParams&, - timestep_t, - timestep_t, - simtime_t, - simtime_t) -> bool; - template auto Metadomain>::WriteCheckpoint( - const SimulationParams&, - timestep_t, - timestep_t, - simtime_t, - simtime_t) -> bool; - template auto Metadomain>::WriteCheckpoint( - const SimulationParams&, - timestep_t, - timestep_t, - simtime_t, - simtime_t) -> bool; - template auto Metadomain>::WriteCheckpoint( - const SimulationParams&, - timestep_t, - timestep_t, - simtime_t, - simtime_t) -> bool; - template auto Metadomain>::WriteCheckpoint( - const SimulationParams&, - timestep_t, - timestep_t, - simtime_t, - simtime_t) -> bool; - template auto Metadomain>::WriteCheckpoint( - const SimulationParams&, - timestep_t, - timestep_t, - simtime_t, - simtime_t) -> bool; - template auto Metadomain>::WriteCheckpoint( - const SimulationParams&, - timestep_t, - timestep_t, - simtime_t, - simtime_t) -> bool; + METADOMAIN_CHECKPOINTS(SimEngine::SRPIC, metric::Minkowski) + METADOMAIN_CHECKPOINTS(SimEngine::SRPIC, metric::Minkowski) + METADOMAIN_CHECKPOINTS(SimEngine::SRPIC, metric::Minkowski) + METADOMAIN_CHECKPOINTS(SimEngine::SRPIC, metric::Spherical) + METADOMAIN_CHECKPOINTS(SimEngine::SRPIC, metric::QSpherical) + METADOMAIN_CHECKPOINTS(SimEngine::GRPIC, metric::KerrSchild) + METADOMAIN_CHECKPOINTS(SimEngine::GRPIC, metric::QKerrSchild) + METADOMAIN_CHECKPOINTS(SimEngine::GRPIC, metric::KerrSchild0) - template void Metadomain>::ContinueFromCheckpoint( - adios2::ADIOS*, - const SimulationParams&); - template void Metadomain>::ContinueFromCheckpoint( - adios2::ADIOS*, - const SimulationParams&); - template void Metadomain>::ContinueFromCheckpoint( - adios2::ADIOS*, - const SimulationParams&); - template void Metadomain>::ContinueFromCheckpoint( - adios2::ADIOS*, - const SimulationParams&); - template void Metadomain>::ContinueFromCheckpoint( - adios2::ADIOS*, - const SimulationParams&); - template void Metadomain>::ContinueFromCheckpoint( - adios2::ADIOS*, - const SimulationParams&); - template void Metadomain>::ContinueFromCheckpoint( - adios2::ADIOS*, - const SimulationParams&); - template void Metadomain>::ContinueFromCheckpoint( - adios2::ADIOS*, - const SimulationParams&); +#undef METADOMAIN_CHECKPOINTS } // namespace ntt diff --git a/src/framework/domain/communications.cpp b/src/framework/domain/communications.cpp index 23bb5b88c..a538f8532 100644 --- a/src/framework/domain/communications.cpp +++ b/src/framework/domain/communications.cpp @@ -36,10 +36,10 @@ namespace ntt { using comm_params_t = std::pair>; template - auto GetSendRecvRanks( - Metadomain* metadomain, - Domain& domain, - dir::direction_t direction) -> std::pair { + auto GetSendRecvRanks(Metadomain* metadomain, + Domain& domain, + dir::direction_t direction) + -> std::pair { Domain* send_to_nghbr_ptr = nullptr; Domain* recv_from_nghbr_ptr = nullptr; // set pointers to the correct send/recv domains @@ -119,11 +119,11 @@ namespace ntt { } template - auto GetSendRecvParams( - Metadomain* metadomain, - Domain& domain, - dir::direction_t direction, - bool synchronize) -> std::pair { + auto GetSendRecvParams(Metadomain* metadomain, + Domain& domain, + dir::direction_t direction, + bool synchronize) + -> std::pair { const auto [send_indrank, recv_indrank] = GetSendRecvRanks(metadomain, domain, direction); const auto [send_ind, send_rank] = send_indrank; @@ -641,95 +641,23 @@ namespace ntt { } } - template void Metadomain>::CommunicateFields( - Domain>&, - CommTags); - template void Metadomain>::CommunicateFields( - Domain>&, - CommTags); - template void Metadomain>::CommunicateFields( - Domain>&, - CommTags); - template void Metadomain>::CommunicateFields( - Domain>&, - CommTags); - template void Metadomain>::CommunicateFields( - Domain>&, - CommTags); - template void Metadomain>::CommunicateFields( - Domain>&, - CommTags); - template void Metadomain>::CommunicateFields( - Domain>&, - CommTags); - template void Metadomain>::CommunicateFields( - Domain>&, - CommTags); - - template void Metadomain>::SynchronizeFields( - Domain>&, - CommTags, - const range_tuple_t&); - template void Metadomain>::SynchronizeFields( - Domain>&, - CommTags, - const range_tuple_t&); - template void Metadomain>::SynchronizeFields( - Domain>&, - CommTags, - const range_tuple_t&); - template void Metadomain>::SynchronizeFields( - Domain>&, - CommTags, - const range_tuple_t&); - template void Metadomain>::SynchronizeFields( - Domain>&, - CommTags, - const range_tuple_t&); - template void Metadomain>::SynchronizeFields( - Domain>&, - CommTags, - const range_tuple_t&); - template void Metadomain>::SynchronizeFields( - Domain>&, - CommTags, - const range_tuple_t&); - template void Metadomain>::SynchronizeFields( - Domain>&, - CommTags, - const range_tuple_t&); - - template void Metadomain>::CommunicateParticles( - Domain>&); - template void Metadomain>::CommunicateParticles( - Domain>&); - template void Metadomain>::CommunicateParticles( - Domain>&); - template void Metadomain>::CommunicateParticles( - Domain>&); - template void Metadomain>::CommunicateParticles( - Domain>&); - template void Metadomain>::CommunicateParticles( - Domain>&); - template void Metadomain>::CommunicateParticles( - Domain>&); - template void Metadomain>::CommunicateParticles( - Domain>&); - - template void Metadomain>::RemoveDeadParticles( - Domain>&); - template void Metadomain>::RemoveDeadParticles( - Domain>&); - template void Metadomain>::RemoveDeadParticles( - Domain>&); - template void Metadomain>::RemoveDeadParticles( - Domain>&); - template void Metadomain>::RemoveDeadParticles( - Domain>&); - template void Metadomain>::RemoveDeadParticles( - Domain>&); - template void Metadomain>::RemoveDeadParticles( - Domain>&); - template void Metadomain>::RemoveDeadParticles( - Domain>&); +#define METADOMAIN_COMM(S, M) \ + template void Metadomain::CommunicateFields(Domain&, CommTags); \ + template void Metadomain::SynchronizeFields(Domain&, \ + CommTags, \ + const range_tuple_t&); \ + template void Metadomain::CommunicateParticles(Domain&); \ + template void Metadomain::RemoveDeadParticles(Domain&); + + METADOMAIN_COMM(SimEngine::SRPIC, metric::Minkowski) + METADOMAIN_COMM(SimEngine::SRPIC, metric::Minkowski) + METADOMAIN_COMM(SimEngine::SRPIC, metric::Minkowski) + METADOMAIN_COMM(SimEngine::SRPIC, metric::Spherical) + METADOMAIN_COMM(SimEngine::SRPIC, metric::QSpherical) + METADOMAIN_COMM(SimEngine::GRPIC, metric::KerrSchild) + METADOMAIN_COMM(SimEngine::GRPIC, metric::QKerrSchild) + METADOMAIN_COMM(SimEngine::GRPIC, metric::KerrSchild0) + +#undef METADOMAIN_COMM + } // namespace ntt diff --git a/src/framework/domain/output.cpp b/src/framework/domain/output.cpp index 99987989e..ce5a13168 100644 --- a/src/framework/domain/output.cpp +++ b/src/framework/domain/output.cpp @@ -188,14 +188,17 @@ namespace ntt { template auto Metadomain::Write( - const SimulationParams& params, - timestep_t current_step, - timestep_t finished_step, - simtime_t current_time, - simtime_t finished_time, - std::function< - void(const std::string&, ndfield_t&, std::size_t, const Domain&)> - CustomFieldOutput) -> bool { + const SimulationParams& params, + timestep_t current_step, + timestep_t finished_step, + simtime_t current_time, + simtime_t finished_time, + std::function&, + index_t, + timestep_t, + simtime_t, + const Domain&)> CustomFieldOutput) -> bool { raise::ErrorIf( l_subdomain_indices().size() != 1, "Output for now is only supported for one subdomain per rank", @@ -382,6 +385,8 @@ namespace ntt { CustomFieldOutput(fld.name().substr(1), local_domain->fields.bckp, addresses.back(), + finished_step, + finished_time, *local_domain); } else { raise::Error("Custom output requested but no function provided", @@ -708,125 +713,32 @@ namespace ntt { return true; } - template void Metadomain>::InitWriter( - adios2::ADIOS*, - const SimulationParams&, - bool); - template void Metadomain>::InitWriter( - adios2::ADIOS*, - const SimulationParams&, - bool); - template void Metadomain>::InitWriter( - adios2::ADIOS*, - const SimulationParams&, - bool); - template void Metadomain>::InitWriter( - adios2::ADIOS*, - const SimulationParams&, - bool); - template void Metadomain>::InitWriter( - adios2::ADIOS*, - const SimulationParams&, - bool); - template void Metadomain>::InitWriter( - adios2::ADIOS*, - const SimulationParams&, - bool); - template void Metadomain>::InitWriter( - adios2::ADIOS*, - const SimulationParams&, - bool); - template void Metadomain>::InitWriter( - adios2::ADIOS*, - const SimulationParams&, - bool); - - template auto Metadomain>::Write( - const SimulationParams&, - timestep_t, - timestep_t, - simtime_t, - simtime_t, - std::function&, - std::size_t, - const Domain>&)>) - -> bool; - template auto Metadomain>::Write( - const SimulationParams&, - timestep_t, - timestep_t, - simtime_t, - simtime_t, - std::function&, - std::size_t, - const Domain>&)>) - -> bool; - template auto Metadomain>::Write( - const SimulationParams&, - timestep_t, - timestep_t, - simtime_t, - simtime_t, - std::function&, - std::size_t, - const Domain>&)>) - -> bool; - template auto Metadomain>::Write( - const SimulationParams&, - timestep_t, - timestep_t, - simtime_t, - simtime_t, - std::function&, - std::size_t, - const Domain>&)>) - -> bool; - template auto Metadomain>::Write( - const SimulationParams&, - timestep_t, - timestep_t, - simtime_t, - simtime_t, - std::function&, - std::size_t, - const Domain>&)>) - -> bool; - template auto Metadomain>::Write( - const SimulationParams&, - timestep_t, - timestep_t, - simtime_t, - simtime_t, - std::function&, - std::size_t, - const Domain>&)>) - -> bool; - template auto Metadomain>::Write( - const SimulationParams&, - timestep_t, - timestep_t, - simtime_t, - simtime_t, - std::function&, - std::size_t, - const Domain>&)>) - -> bool; - template auto Metadomain>::Write( - const SimulationParams&, - timestep_t, - timestep_t, - simtime_t, - simtime_t, - std::function&, - std::size_t, - const Domain>&)>) - -> bool; +#define METADOMAIN_OUTPUT(S, M) \ + template void Metadomain::InitWriter(adios2::ADIOS*, \ + const SimulationParams&, \ + bool); \ + template auto Metadomain::Write( \ + const SimulationParams&, \ + timestep_t, \ + timestep_t, \ + simtime_t, \ + simtime_t, \ + std::function&, \ + index_t, \ + timestep_t, \ + simtime_t, \ + const Domain&)>) -> bool; + + METADOMAIN_OUTPUT(SimEngine::SRPIC, metric::Minkowski) + METADOMAIN_OUTPUT(SimEngine::SRPIC, metric::Minkowski) + METADOMAIN_OUTPUT(SimEngine::SRPIC, metric::Minkowski) + METADOMAIN_OUTPUT(SimEngine::SRPIC, metric::Spherical) + METADOMAIN_OUTPUT(SimEngine::SRPIC, metric::QSpherical) + METADOMAIN_OUTPUT(SimEngine::GRPIC, metric::KerrSchild) + METADOMAIN_OUTPUT(SimEngine::GRPIC, metric::QKerrSchild) + METADOMAIN_OUTPUT(SimEngine::GRPIC, metric::KerrSchild0) + +#undef METADOMAIN_OUTPUT + } // namespace ntt From b25232ca01e05db2bf9fd9e067d4339031e2f77b Mon Sep 17 00:00:00 2001 From: hayk Date: Sat, 24 May 2025 18:19:08 -0400 Subject: [PATCH 713/773] custom stat --- input.example.toml | 4 + src/engines/engine_run.cpp | 45 +++++++---- src/framework/domain/metadomain.h | 19 +++-- src/framework/domain/stats.cpp | 120 ++++++++++-------------------- src/framework/parameters.cpp | 14 +++- src/global/arch/traits.h | 5 +- src/global/enums.h | 9 ++- src/global/tests/enums.cpp | 4 +- src/global/utils/error.h | 1 + src/output/stats.cpp | 16 +++- src/output/stats.h | 12 ++- 11 files changed, 132 insertions(+), 117 deletions(-) diff --git a/input.example.toml b/input.example.toml index 4a671fab6..26a5d1c96 100644 --- a/input.example.toml +++ b/input.example.toml @@ -453,6 +453,10 @@ # @default: ["B^2", "E^2", "ExB", "Rho", "T00"] # @note: Same notation as for `output.fields.quantities` quantities = "" + # Custom (user-defined) stats: + # @type: array of strings + # @default: [] + custom = "" [checkpoint] # Number of timesteps between checkpoints: diff --git a/src/engines/engine_run.cpp b/src/engines/engine_run.cpp index 472acae46..65c87e939 100644 --- a/src/engines/engine_run.cpp +++ b/src/engines/engine_run.cpp @@ -72,23 +72,41 @@ namespace ntt { auto lambda_custom_field_output = [&](const std::string& name, ndfield_t& buff, index_t idx, + timestep_t step, + simtime_t time, const Domain& dom) { - m_pgen.CustomFieldOutput(name, buff, idx, dom); + m_pgen.CustomFieldOutput(name, buff, idx, step, time, dom); }; - print_output = m_metadomain.Write(m_params, - step, - step - 1, - time, - time - dt, - lambda_custom_field_output); + print_output &= m_metadomain.Write(m_params, + step, + step - 1, + time, + time - dt, + lambda_custom_field_output); } else { - print_output = m_metadomain.Write(m_params, step, step - 1, time, time - dt); + print_output &= m_metadomain.Write(m_params, step, step - 1, time, time - dt); + } + if constexpr ( + traits::has_method::value) { + auto lambda_custom_stat = [&](const std::string& name, + timestep_t step, + simtime_t time, + const Domain& dom) -> real_t { + return m_pgen.CustomStat(name, step, time, dom); + }; + print_output &= m_metadomain.WriteStats(m_params, + step, + step - 1, + time, + time - dt, + lambda_custom_stat); + } else { + print_output &= m_metadomain.WriteStats(m_params, + step, + step - 1, + time, + time - dt); } - print_output &= m_metadomain.WriteStats(m_params, - step, - step - 1, - time, - time - dt); timers.stop("Output"); timers.start("Checkpoint"); @@ -133,4 +151,5 @@ namespace ntt { template void Engine>::run(); template void Engine>::run(); template void Engine>::run(); + } // namespace ntt diff --git a/src/framework/domain/metadomain.h b/src/framework/domain/metadomain.h index 363b164d3..0cb670965 100644 --- a/src/framework/domain/metadomain.h +++ b/src/framework/domain/metadomain.h @@ -124,8 +124,10 @@ namespace ntt { simtime_t, std::function&, - std::size_t, - const Domain&)> = {}) -> bool; + index_t, + timestep_t, + simtime_t, + const Domain&)> = nullptr) -> bool; void InitCheckpointWriter(adios2::ADIOS*, const SimulationParams&); auto WriteCheckpoint(const SimulationParams&, timestep_t, @@ -137,11 +139,14 @@ namespace ntt { #endif void InitStatsWriter(const SimulationParams&, bool); - auto WriteStats(const SimulationParams&, - timestep_t, - timestep_t, - simtime_t, - simtime_t) -> bool; + auto WriteStats( + const SimulationParams&, + timestep_t, + timestep_t, + simtime_t, + simtime_t, + std::function&)> = + nullptr) -> bool; /* setters -------------------------------------------------------------- */ void setFldsBC(const bc_in&, const FldsBC&); diff --git a/src/framework/domain/stats.cpp b/src/framework/domain/stats.cpp index 95be528eb..a252e975d 100644 --- a/src/framework/domain/stats.cpp +++ b/src/framework/domain/stats.cpp @@ -1,7 +1,6 @@ #include "enums.h" #include "global.h" -#include "arch/kokkos_aliases.h" #include "utils/comparators.h" #include "utils/error.h" #include "utils/log.h" @@ -54,11 +53,14 @@ namespace ntt { } const auto stats_to_write = params.template get>( "output.stats.quantities"); + const auto custom_stats_to_write = params.template get>( + "output.stats.custom"); g_stats_writer.init( params.template get("output.stats.interval"), params.template get("output.stats.interval_time")); g_stats_writer.defineStatsFilename(filename); - g_stats_writer.defineStatsOutputs(stats_to_write); + g_stats_writer.defineStatsOutputs(stats_to_write, false); + g_stats_writer.defineStatsOutputs(custom_stats_to_write, true); if (not std::filesystem::exists(filename)) { g_stats_writer.writeHeader(); @@ -178,11 +180,14 @@ namespace ntt { } template - auto Metadomain::WriteStats(const SimulationParams& params, - timestep_t current_step, - timestep_t finished_step, - simtime_t current_time, - simtime_t finished_time) -> bool { + auto Metadomain::WriteStats( + const SimulationParams& params, + timestep_t current_step, + timestep_t finished_step, + simtime_t current_time, + simtime_t finished_time, + std::function&)> CustomStat) + -> bool { if (not(params.template get("output.stats.enable") and g_stats_writer.shouldWrite(finished_step, finished_time))) { return false; @@ -192,7 +197,14 @@ namespace ntt { g_stats_writer.write(current_step); g_stats_writer.write(current_time); for (const auto& stat : g_stats_writer.statsWriters()) { - if (stat.id() == StatsID::N) { + if (stat.id() == StatsID::Custom) { + if (CustomStat != nullptr) { + g_stats_writer.write( + CustomStat(stat.name(), finished_step, finished_time, *local_domain)); + } else { + raise::Error("Custom output requested but no function provided", HERE); + } + } else if (stat.id() == StatsID::N) { g_stats_writer.write(ComputeMoments(params, local_domain->mesh, local_domain->species, @@ -260,78 +272,26 @@ namespace ntt { return true; } - template void Metadomain>::InitStatsWriter( - const SimulationParams&, - bool); - template void Metadomain>::InitStatsWriter( - const SimulationParams&, - bool); - template void Metadomain>::InitStatsWriter( - const SimulationParams&, - bool); - template void Metadomain>::InitStatsWriter( - const SimulationParams&, - bool); - template void Metadomain>::InitStatsWriter( - const SimulationParams&, - bool); - template void Metadomain>::InitStatsWriter( - const SimulationParams&, - bool); - template void Metadomain>::InitStatsWriter( - const SimulationParams&, - bool); - template void Metadomain>::InitStatsWriter( - const SimulationParams&, - bool); +#define METADOMAIN_STATS(S, M) \ + template void Metadomain::InitStatsWriter(const SimulationParams&, bool); \ + template auto Metadomain::WriteStats( \ + const SimulationParams&, \ + timestep_t, \ + timestep_t, \ + simtime_t, \ + simtime_t, \ + std::function&)>) \ + -> bool; + + METADOMAIN_STATS(SimEngine::SRPIC, metric::Minkowski) + METADOMAIN_STATS(SimEngine::SRPIC, metric::Minkowski) + METADOMAIN_STATS(SimEngine::SRPIC, metric::Minkowski) + METADOMAIN_STATS(SimEngine::SRPIC, metric::Spherical) + METADOMAIN_STATS(SimEngine::SRPIC, metric::QSpherical) + METADOMAIN_STATS(SimEngine::GRPIC, metric::KerrSchild) + METADOMAIN_STATS(SimEngine::GRPIC, metric::QKerrSchild) + METADOMAIN_STATS(SimEngine::GRPIC, metric::KerrSchild0) - template auto Metadomain>::WriteStats( - const SimulationParams&, - timestep_t, - timestep_t, - simtime_t, - simtime_t) -> bool; - template auto Metadomain>::WriteStats( - const SimulationParams&, - timestep_t, - timestep_t, - simtime_t, - simtime_t) -> bool; - template auto Metadomain>::WriteStats( - const SimulationParams&, - timestep_t, - timestep_t, - simtime_t, - simtime_t) -> bool; - template auto Metadomain>::WriteStats( - const SimulationParams&, - timestep_t, - timestep_t, - simtime_t, - simtime_t) -> bool; - template auto Metadomain>::WriteStats( - const SimulationParams&, - timestep_t, - timestep_t, - simtime_t, - simtime_t) -> bool; - template auto Metadomain>::WriteStats( - const SimulationParams&, - timestep_t, - timestep_t, - simtime_t, - simtime_t) -> bool; - template auto Metadomain>::WriteStats( - const SimulationParams&, - timestep_t, - timestep_t, - simtime_t, - simtime_t) -> bool; - template auto Metadomain>::WriteStats( - const SimulationParams&, - timestep_t, - timestep_t, - simtime_t, - simtime_t) -> bool; +#undef METADOMAIN_STATS } // namespace ntt diff --git a/src/framework/parameters.cpp b/src/framework/parameters.cpp index 836d79fb5..40779d731 100644 --- a/src/framework/parameters.cpp +++ b/src/framework/parameters.cpp @@ -31,10 +31,10 @@ namespace ntt { template - auto get_dx0_V0( - const std::vector& resolution, - const boundaries_t& extent, - const std::map& params) -> std::pair { + auto get_dx0_V0(const std::vector& resolution, + const boundaries_t& extent, + const std::map& params) + -> std::pair { const auto metric = M(resolution, extent, params); const auto dx0 = metric.dxMin(); coord_t x_corner { ZERO }; @@ -549,6 +549,12 @@ namespace ntt { "stats", "quantities", defaults::output::stats_quantities)); + set("output.stats.custom", + toml::find_or(toml_data, + "output", + "stats", + "custom", + std::vector {})); // intervals for (const auto& type : { "fields", "particles", "spectra", "stats" }) { diff --git a/src/global/arch/traits.h b/src/global/arch/traits.h index 6d6c51f73..d9e5e9310 100644 --- a/src/global/arch/traits.h +++ b/src/global/arch/traits.h @@ -99,7 +99,7 @@ namespace traits { using ext_force_t = decltype(&T::ext_force); template - using ext_current_t = decltype(&T::ext_current); + using ext_current_t = decltype(&T::ext_current); template using atm_fields_t = decltype(&T::AtmFields); @@ -145,6 +145,9 @@ namespace traits { template using custom_field_output_t = decltype(&T::CustomFieldOutput); + + template + using custom_stat_t = decltype(&T::CustomStat); } // namespace pgen // for pgen extforce diff --git a/src/global/enums.h b/src/global/enums.h index 8796fe310..08130a2c8 100644 --- a/src/global/enums.h +++ b/src/global/enums.h @@ -323,15 +323,16 @@ namespace ntt { Charge = 7, N = 8, Npart = 9, + Custom = 10, }; constexpr StatsID(uint8_t c) : enums_hidden::BaseEnum { c } {} static constexpr type variants[] = { B2, E2, ExB, JdotE, T, - Rho, Charge, N, Npart }; - static constexpr const char* lookup[] = { "b^2", "e^2", "exb", - "j.e", "t", "rho", - "charge", "n", "npart" }; + Rho, Charge, N, Npart, Custom }; + static constexpr const char* lookup[] = { "b^2", "e^2", "exb", "j.e", + "t", "rho", "charge", "n", + "npart", "custom" }; static constexpr std::size_t total = sizeof(variants) / sizeof(variants[0]); }; diff --git a/src/global/tests/enums.cpp b/src/global/tests/enums.cpp index 1190417ef..f653f4727 100644 --- a/src/global/tests/enums.cpp +++ b/src/global/tests/enums.cpp @@ -71,8 +71,8 @@ auto main() -> int { "h", "j", "a", "t", "rho", "charge", "n", "nppc", "v", "custom" }; - enum_str_t all_out_stats = { "b^2", "e^2", "exb", "j.e", "t", - "rho", "charge", "n", "npart" }; + enum_str_t all_out_stats = { "b^2", "e^2", "exb", "j.e", "t", + "rho", "charge", "n", "npart", "custom" }; checkEnum(all_coords); checkEnum(all_metrics); diff --git a/src/global/utils/error.h b/src/global/utils/error.h index 9d5afed29..5f378bf1b 100644 --- a/src/global/utils/error.h +++ b/src/global/utils/error.h @@ -34,6 +34,7 @@ namespace raise { using namespace files; + [[noreturn]] inline void Error(const std::string& msg, const std::string& file, const std::string& func, diff --git a/src/output/stats.cpp b/src/output/stats.cpp index 407a5bd38..6aa65067a 100644 --- a/src/output/stats.cpp +++ b/src/output/stats.cpp @@ -20,7 +20,14 @@ using namespace out; namespace stats { - OutputStats::OutputStats(const std::string& name) : m_name { name } { + OutputStats::OutputStats(const std::string& name, bool is_custom) + : m_name { name } { + if (is_custom) { + m_id = StatsID::Custom; + comp = {}; + species = {}; + return; + } // determine the stats ID const auto pos = name.find("_"); auto name_raw = (pos == std::string::npos) ? name : name.substr(0, pos); @@ -30,7 +37,7 @@ namespace stats { if (StatsID::contains(fmt::toLower(name_raw).c_str())) { m_id = StatsID::pick(fmt::toLower(name_raw).c_str()); } else { - raise::Error("Unrecognized stats ID " + fmt::toLower(name_raw), HERE); + raise::Error("Unrecognized stats name: " + name, HERE); } // determine the species and components to output if (is_moment()) { @@ -62,9 +69,10 @@ namespace stats { m_fname = filename; } - void Writer::defineStatsOutputs(const std::vector& stats_to_write) { + void Writer::defineStatsOutputs(const std::vector& stats_to_write, + bool is_custom) { for (const auto& stat : stats_to_write) { - m_stat_writers.emplace_back(stat); + m_stat_writers.emplace_back(stat, is_custom); } } diff --git a/src/output/stats.h b/src/output/stats.h index cd48e6ca4..fc5bbf3a2 100644 --- a/src/output/stats.h +++ b/src/output/stats.h @@ -43,7 +43,7 @@ namespace stats { std::vector> comp {}; std::vector species {}; - OutputStats(const std::string&); + OutputStats(const std::string&, bool); ~OutputStats() = default; @@ -58,8 +58,16 @@ namespace stats { return id() == StatsID::ExB || id() == StatsID::E2 || id() == StatsID::B2; } + [[nodiscard]] + auto is_custom() const -> bool { + return id() == StatsID::Custom; + } + [[nodiscard]] inline auto name() const -> std::string { + if (id() == StatsID::Custom) { + return m_name; + } // generate the name std::string tmp = std::string(id().to_string()); if (tmp == "exb") { @@ -151,7 +159,7 @@ namespace stats { void init(timestep_t, simtime_t); void defineStatsFilename(const std::string&); - void defineStatsOutputs(const std::vector&); + void defineStatsOutputs(const std::vector&, bool); void writeHeader(); From 49fdeed123751ca379933f54bc79e148c8da5793 Mon Sep 17 00:00:00 2001 From: hayk Date: Sat, 24 May 2025 18:24:17 -0400 Subject: [PATCH 714/773] test for custom stat --- src/output/tests/stats.cpp | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/src/output/tests/stats.cpp b/src/output/tests/stats.cpp index 04645cad7..11e9961e3 100644 --- a/src/output/tests/stats.cpp +++ b/src/output/tests/stats.cpp @@ -13,7 +13,7 @@ auto main() -> int { using namespace ntt; try { { - const auto e = OutputStats("E^2"); + const auto e = OutputStats("E^2", false); raise::ErrorIf(not e.is_vector(), "E^2 should be a vector quantity", HERE); raise::ErrorIf(e.is_moment(), "E^2 should not be a moment", HERE); raise::ErrorIf(e.id() != StatsID::E2, "E^2 should have ID StatsID::E2", HERE); @@ -23,7 +23,7 @@ auto main() -> int { } { - const auto e = OutputStats("ExB"); + const auto e = OutputStats("ExB", false); raise::ErrorIf(not e.is_vector(), "ExB should be a vector quantity", HERE); raise::ErrorIf(e.is_moment(), "ExB should not be a moment", HERE); raise::ErrorIf(e.id() != StatsID::ExB, "ExB should have ID StatsID::ExB", HERE); @@ -33,7 +33,7 @@ auto main() -> int { } { - const auto e = OutputStats("J.E"); + const auto e = OutputStats("J.E", false); raise::ErrorIf(e.is_vector(), "J.E should not be a vector quantity", HERE); raise::ErrorIf(e.is_moment(), "J.E should not be a moment", HERE); raise::ErrorIf(e.id() != StatsID::JdotE, @@ -45,7 +45,7 @@ auto main() -> int { } { - const auto rho = OutputStats("Rho_1_3"); + const auto rho = OutputStats("Rho_1_3", false); raise::ErrorIf(not rho.is_moment(), "Rho should be a moment", HERE); raise::ErrorIf(rho.id() != StatsID::Rho, "Rho should have ID StatsID::Rho", @@ -58,7 +58,7 @@ auto main() -> int { } { - const auto t = OutputStats("Tti_2_3"); + const auto t = OutputStats("Tti_2_3", false); raise::ErrorIf(not t.is_moment(), "T should be a moment", HERE); raise::ErrorIf(t.is_vector(), "T should not be a vector quantity", HERE); raise::ErrorIf(t.id() != StatsID::T, "T should have ID StatsID::T", HERE); @@ -91,9 +91,21 @@ auto main() -> int { } { - const auto t = OutputStats("Tij"); + const auto t = OutputStats("Tij", false); raise::ErrorIf(t.comp.size() != 6, "T should have 6 component", HERE); } + + { + const auto custom = OutputStats("C2x_12", true); + raise::ErrorIf(custom.name() != "C2x_12", + "Custom should have name `C2x_12`", + HERE); + raise::ErrorIf(not custom.is_custom(), + "Custom should be... well... a custom", + HERE); + raise::ErrorIf(custom.is_moment(), "Custom should not be a moment", HERE); + raise::ErrorIf(custom.is_vector(), "Custom should not be a vector", HERE); + } } catch (const std::exception& e) { std::cerr << e.what() << std::endl; return 1; From ce195d3eb79872a181a1ece0f7c135bd00263c71 Mon Sep 17 00:00:00 2001 From: hayk Date: Mon, 26 May 2025 11:11:42 -0400 Subject: [PATCH 715/773] taylor expand polar area to 4th order when small angle --- src/global/utils/numeric.h | 23 +++++++++++----------- src/metrics/qspherical.h | 40 ++++++++++++++++++++++++++++++-------- src/metrics/spherical.h | 30 +++++++++++++++++++++++++--- 3 files changed, 71 insertions(+), 22 deletions(-) diff --git a/src/global/utils/numeric.h b/src/global/utils/numeric.h index cc1191b62..afd662335 100644 --- a/src/global/utils/numeric.h +++ b/src/global/utils/numeric.h @@ -80,17 +80,18 @@ inline constexpr double INV_64 = 0.015625; #define CROSS_x3(ax1, ax2, ax3, bx1, bx2, bx3) ((ax1) * (bx2) - (ax2) * (bx1)) namespace constant { - inline constexpr std::uint64_t RandomSeed = 0x123456789abcdef0; - inline constexpr double HALF_PI = 1.57079632679489661923; - inline constexpr double PI = 3.14159265358979323846; - inline constexpr double INV_PI = 0.31830988618379067154; - inline constexpr double PI_SQR = 9.86960440108935861882; - inline constexpr double INV_PI_SQR = 0.10132118364233777144; - inline constexpr double TWO_PI = 6.28318530717958647692; - inline constexpr double E = 2.71828182845904523536; - inline constexpr double SQRT2 = 1.41421356237309504880; - inline constexpr double INV_SQRT2 = 0.70710678118654752440; - inline constexpr double SQRT3 = 1.73205080756887729352; + inline constexpr std::uint64_t RandomSeed = 0x123456789abcdef0; + inline constexpr double HALF_PI = 1.57079632679489661923; + inline constexpr double PI = 3.14159265358979323846; + inline constexpr double INV_PI = 0.31830988618379067154; + inline constexpr double PI_SQR = 9.86960440108935861882; + inline constexpr double INV_PI_SQR = 0.10132118364233777144; + inline constexpr double TWO_PI = 6.28318530717958647692; + inline constexpr double E = 2.71828182845904523536; + inline constexpr double SQRT2 = 1.41421356237309504880; + inline constexpr double INV_SQRT2 = 0.70710678118654752440; + inline constexpr double SQRT3 = 1.73205080756887729352; + inline constexpr double SMALL_ANGLE = 1e-3; } // namespace constant namespace convert { diff --git a/src/metrics/qspherical.h b/src/metrics/qspherical.h index 4df5db866..4a5a9d380 100644 --- a/src/metrics/qspherical.h +++ b/src/metrics/qspherical.h @@ -38,6 +38,7 @@ namespace metric { const real_t r0, h, chi_min, eta_min, phi_min; const real_t dchi, deta, dphi; const real_t dchi_inv, deta_inv, dphi_inv; + const bool small_angle; public: static constexpr const char* Label { "qspherical" }; @@ -69,7 +70,8 @@ namespace metric { , dphi { (x3_max - x3_min) / nx3 } , dchi_inv { ONE / dchi } , deta_inv { ONE / deta } - , dphi_inv { ONE / dphi } { + , dphi_inv { ONE / dphi } + , small_angle { eta2theta(HALF * deta) < constant::SMALL_ANGLE } { set_dxMin(find_dxMin()); } @@ -97,6 +99,20 @@ namespace metric { return min_dx; } + /** + * total volume of the region described by the metric (in physical units) + */ + [[nodiscard]] + auto totVolume() const -> real_t override { + if constexpr (D == Dim::_1D) { + raise::Error("1D spherical metric not applicable", HERE); + } else if constexpr (D == Dim::_2D) { + return (SQR(x1_max) - SQR(x1_min)) * (x2_max - x2_min); + } else { + return (SQR(x1_max) - SQR(x1_min)) * (x2_max - x2_min) * (x3_max - x3_min); + } + } + /** * metric component with lower indices: h_ij * @param x coordinate array in code units @@ -155,11 +171,11 @@ namespace metric { */ Inline auto sqrt_det_h(const coord_t& x) const -> real_t { if constexpr (D == Dim::_2D) { - real_t exp_chi { math::exp(x[0] * dchi + chi_min) }; + const real_t exp_chi { math::exp(x[0] * dchi + chi_min) }; return dchi * deta * exp_chi * dtheta_deta(x[1] * deta + eta_min) * SQR(r0 + exp_chi) * math::sin(eta2theta(x[1] * deta + eta_min)); } else if constexpr (D == Dim::_3D) { - real_t exp_chi { math::exp(x[0] * dchi + chi_min) }; + const real_t exp_chi { math::exp(x[0] * dchi + chi_min) }; return dchi * deta * dphi * exp_chi * dtheta_deta(x[1] * deta + eta_min) * SQR(r0 + exp_chi) * math::sin(eta2theta(x[1] * deta + eta_min)); } @@ -171,7 +187,7 @@ namespace metric { */ Inline auto sqrt_det_h_tilde(const coord_t& x) const -> real_t { if constexpr (D != Dim::_1D) { - real_t exp_chi { math::exp(x[0] * dchi + chi_min) }; + const real_t exp_chi { math::exp(x[0] * dchi + chi_min) }; return dchi * deta * exp_chi * dtheta_deta(x[1] * deta + eta_min) * SQR(r0 + exp_chi); } @@ -183,9 +199,16 @@ namespace metric { */ Inline auto polar_area(const real_t& x1) const -> real_t { if constexpr (D != Dim::_1D) { - real_t exp_chi { math::exp(x1 * dchi + chi_min) }; - return dchi * exp_chi * SQR(r0 + exp_chi) * - (ONE - math::cos(eta2theta(HALF * deta))); + const real_t exp_chi { math::exp(x1 * dchi + chi_min) }; + if (small_angle) { + const real_t dtheta = eta2theta(HALF * deta); + return dchi * exp_chi * SQR(r0 + exp_chi) * + (static_cast(48) - SQR(dtheta)) * SQR(dtheta) / + static_cast(384); + } else { + return dchi * exp_chi * SQR(r0 + exp_chi) * + (ONE - math::cos(eta2theta(HALF * deta))); + } } } @@ -284,7 +307,8 @@ namespace metric { * @note tetrad/sph <-> cntrv <-> cov */ template - Inline auto transform(const coord_t& xi, const real_t& v_in) const -> real_t { + Inline auto transform(const coord_t& xi, const real_t& v_in) const + -> real_t { static_assert(i > 0 && i <= 3, "Invalid index i"); static_assert(in != out, "Invalid vector transformation"); if constexpr ((in == Idx::T && out == Idx::Sph) || diff --git a/src/metrics/spherical.h b/src/metrics/spherical.h index 54e12367d..05ec6b018 100644 --- a/src/metrics/spherical.h +++ b/src/metrics/spherical.h @@ -33,6 +33,7 @@ namespace metric { const real_t dr, dtheta, dphi; const real_t dr_inv, dtheta_inv, dphi_inv; + const bool small_angle; public: static constexpr const char* Label { "spherical" }; @@ -59,7 +60,8 @@ namespace metric { , dphi((x3_max - x3_min) / nx3) , dr_inv { ONE / dr } , dtheta_inv { ONE / dtheta } - , dphi_inv { ONE / dphi } { + , dphi_inv { ONE / dphi } + , small_angle { HALF * dtheta < constant::SMALL_ANGLE } { set_dxMin(find_dxMin()); } @@ -76,6 +78,20 @@ namespace metric { return ONE / math::sqrt(ONE / SQR(dx1) + ONE / SQR(dx2)); } + /** + * total volume of the region described by the metric (in physical units) + */ + [[nodiscard]] + auto totVolume() const -> real_t override { + if constexpr (D == Dim::_1D) { + raise::Error("1D spherical metric not applicable", HERE); + } else if constexpr (D == Dim::_2D) { + return (SQR(x1_max) - SQR(x1_min)) * (x2_max - x2_min); + } else { + return (SQR(x1_max) - SQR(x1_min)) * (x2_max - x2_min) * (x3_max - x3_min); + } + } + /** * metric component with lower indices: h_ij * @param x coordinate array in code units @@ -152,9 +168,16 @@ namespace metric { /** * differential area at the pole (used in axisymmetric solvers) * @param x1 radial coordinate along the axis (code units) + * @note uses small-angle approximation when the resolution is too high */ Inline auto polar_area(const real_t& x1) const -> real_t { - return dr * SQR(x1 * dr + x1_min) * (ONE - math::cos(HALF * dtheta)); + if (small_angle) { + return dr * SQR(x1 * dr + x1_min) * + (static_cast(48) - SQR(dtheta)) * SQR(dtheta) / + static_cast(384); + } else { + return dr * SQR(x1 * dr + x1_min) * (ONE - math::cos(HALF * dtheta)); + } } /** @@ -252,7 +275,8 @@ namespace metric { * @note tetrad/sph <-> cntrv <-> cov */ template - Inline auto transform(const coord_t& xi, const real_t& v_in) const -> real_t { + Inline auto transform(const coord_t& xi, const real_t& v_in) const + -> real_t { static_assert(i > 0 && i <= 3, "Invalid index i"); static_assert(in != out, "Invalid vector transformation"); if constexpr ((in == Idx::T && out == Idx::Sph) || From a8836ac7ae3a00b3ccbef447479715b80b924435 Mon Sep 17 00:00:00 2001 From: hayk Date: Tue, 27 May 2025 15:05:27 -0400 Subject: [PATCH 716/773] walltime checkpoint added --- input.example.toml | 9 +++++++++ src/engines/engine.hpp | 5 ++++- src/engines/engine_init.cpp | 16 ++++++++++++++++ src/engines/engine_run.cpp | 10 ++++++++++ src/framework/parameters.cpp | 10 ++++++---- src/global/global.h | 12 +++++++----- 6 files changed, 52 insertions(+), 10 deletions(-) diff --git a/input.example.toml b/input.example.toml index 4a671fab6..5faacf2fc 100644 --- a/input.example.toml +++ b/input.example.toml @@ -470,6 +470,15 @@ # @note: 0 = disable checkpointing # @note: -1 = keep all checkpoints keep = "" + # Write a checkpoint once after a fixed walltime + # @type: string + # @default: "" (disabled) + # @note: The format is "HH:MM:SS" + # @note: Useful for long-running simulations to ensure that ... + # @note: ... the simulation can be resumed after allocation expires + # @note: Empty string means disables this (still writes checkpoints on interval) + # @note: This does not exit the simulation + walltime = "" # @inferred: # - is_resuming diff --git a/src/engines/engine.hpp b/src/engines/engine.hpp index 9525874a6..261b1d6ea 100644 --- a/src/engines/engine.hpp +++ b/src/engines/engine.hpp @@ -23,7 +23,6 @@ #include "arch/traits.h" #include "utils/error.h" -#include "utils/progressbar.h" #include "utils/timer.h" #include "utils/toml.h" @@ -44,6 +43,7 @@ #include #endif // MPI_ENABLED +#include #include #include @@ -61,6 +61,9 @@ namespace ntt { #else adios2::ADIOS m_adios; #endif + const timestamp_t start_walltime { std::chrono::system_clock::now() }; + timestamp_t end_walltime {}; + bool walltime_checkpoint_pending { false }; #endif SimulationParams m_params; diff --git a/src/engines/engine_init.cpp b/src/engines/engine_init.cpp index 833a7771f..0e99451e9 100644 --- a/src/engines/engine_init.cpp +++ b/src/engines/engine_init.cpp @@ -16,6 +16,8 @@ #include +#include + namespace ntt { template @@ -25,6 +27,20 @@ namespace ntt { #if defined(OUTPUT_ENABLED) m_metadomain.InitWriter(&m_adios, m_params, is_resuming); m_metadomain.InitCheckpointWriter(&m_adios, m_params); + + const auto checkpoint_walltime = m_params.template get( + "checkpoint.walltime"); + if (not checkpoint_walltime.empty()) { + walltime_checkpoint_pending = true; + raise::ErrorIf(checkpoint_walltime.size() != 8, + "invalid checkpoint walltime format, expected HH:MM:SS", + HERE); + end_walltime = + start_walltime + + std::chrono::hours(std::stoi(checkpoint_walltime.substr(0, 2))) + + std::chrono::minutes(std::stoi(checkpoint_walltime.substr(3, 2))) + + std::chrono::seconds(std::stoi(checkpoint_walltime.substr(6, 2))); + } #endif logger::Checkpoint("Initializing Engine", HERE); if (not is_resuming) { diff --git a/src/engines/engine_run.cpp b/src/engines/engine_run.cpp index 472acae46..256aac8e3 100644 --- a/src/engines/engine_run.cpp +++ b/src/engines/engine_run.cpp @@ -97,6 +97,15 @@ namespace ntt { step - 1, time, time - dt); + if ((not print_checkpoint) and (walltime_checkpoint_pending) and + (std::chrono::system_clock::now() >= end_walltime)) { + print_checkpoint = m_metadomain.WriteCheckpoint(m_params, + step, + step - 1, + time, + time - dt); + walltime_checkpoint_pending = false; + } timers.stop("Checkpoint"); #endif @@ -133,4 +142,5 @@ namespace ntt { template void Engine>::run(); template void Engine>::run(); template void Engine>::run(); + } // namespace ntt diff --git a/src/framework/parameters.cpp b/src/framework/parameters.cpp index 168640e1f..3c0b334c7 100644 --- a/src/framework/parameters.cpp +++ b/src/framework/parameters.cpp @@ -31,10 +31,10 @@ namespace ntt { template - auto get_dx0_V0( - const std::vector& resolution, - const boundaries_t& extent, - const std::map& params) -> std::pair { + auto get_dx0_V0(const std::vector& resolution, + const boundaries_t& extent, + const std::map& params) + -> std::pair { const auto metric = M(resolution, extent, params); const auto dx0 = metric.dxMin(); coord_t x_corner { ZERO }; @@ -603,6 +603,8 @@ namespace ntt { toml::find_or(toml_data, "checkpoint", "interval_time", -1.0)); set("checkpoint.keep", toml::find_or(toml_data, "checkpoint", "keep", defaults::checkpoint::keep)); + set("checkpoint.walltime", + toml::find_or(toml_data, "checkpoint", "walltime", std::string(""))); /* [diagnostics] -------------------------------------------------------- */ set("diagnostics.interval", diff --git a/src/global/global.h b/src/global/global.h index 42114a1da..1f7987929 100644 --- a/src/global/global.h +++ b/src/global/global.h @@ -342,12 +342,14 @@ template using vec_t = tuple_t; // time/duration +using duration_t = double; +using simtime_t = double; +using timestep_t = std::size_t; +using ncells_t = std::size_t; +using npart_t = unsigned long int; + +// walltime using timestamp_t = std::chrono::time_point; -using duration_t = double; -using simtime_t = double; -using timestep_t = std::size_t; -using ncells_t = std::size_t; -using npart_t = unsigned long int; // index/number using index_t = const std::size_t; From f3cb42ba308ab131defdbb1913d18dc024b923ea Mon Sep 17 00:00:00 2001 From: hayk Date: Fri, 30 May 2025 02:44:41 -0400 Subject: [PATCH 717/773] additional range checks (in compl. with gcc-15) --- src/kernels/tests/deposit.cpp | 95 +++++++++++++--------------- src/kernels/tests/digital_filter.cpp | 93 +++++++++++++-------------- src/kernels/tests/prtl_bc.cpp | 90 +++++++++++++++----------- src/metrics/kerr_schild.h | 4 +- src/metrics/kerr_schild_0.h | 4 +- src/metrics/metric_base.h | 46 +++++++++++--- src/metrics/minkowski.h | 23 ++++--- src/metrics/qkerr_schild.h | 4 +- src/metrics/qspherical.h | 7 +- src/metrics/spherical.h | 7 +- 10 files changed, 205 insertions(+), 168 deletions(-) diff --git a/src/kernels/tests/deposit.cpp b/src/kernels/tests/deposit.cpp index e6967eb14..1570937b8 100644 --- a/src/kernels/tests/deposit.cpp +++ b/src/kernels/tests/deposit.cpp @@ -55,7 +55,12 @@ void testDeposit(const std::vector& res, errorIf(res.size() != M::Dim, "res.size() != M::Dim"); using namespace ntt; - M metric { res, ext, params }; + auto extents = ext; + if constexpr (M::CoordType != Coord::Cart) { + extents.emplace_back(ZERO, (real_t)(constant::PI)); + } + + M metric { res, extents, params }; const auto nx1 = res[0]; const auto nx2 = res[1]; @@ -170,59 +175,49 @@ auto main(int argc, char* argv[]) -> int { using namespace ntt; using namespace metric; - testDeposit, SimEngine::SRPIC>( - { - 10, - 10 - }, - { { 0.0, 55.0 }, { 0.0, 55.0 } }, - {}, - 500); - - testDeposit, SimEngine::SRPIC>( - { - 10, - 10 - }, - { { 1.0, 100.0 } }, - {}, - 500); - - testDeposit, SimEngine::SRPIC>( - { - 10, - 10 + const auto res = std::vector { 10, 10 }; + const auto r_extent = boundaries_t { + { 0.0, 100.0 } + }; + const auto xy_extent = boundaries_t { + { 0.0, 55.0 }, + { 0.0, 55.0 } + }; + + testDeposit, SimEngine::SRPIC>(res, xy_extent, {}, 500); + + testDeposit, SimEngine::SRPIC>(res, r_extent, {}, 500); + + testDeposit, SimEngine::SRPIC>(res, + r_extent, + { + { "r0", 0.0 }, + { "h", 0.25 } }, - { { 1.0, 100.0 } }, - { { "r0", 0.0 }, { "h", 0.25 } }, - 500); - - testDeposit, SimEngine::GRPIC>( - { - 10, - 10 + 500); + + testDeposit, SimEngine::GRPIC>(res, + r_extent, + { + { "a", 0.9 } }, - { { 1.0, 100.0 } }, - { { "a", 0.9 } }, - 500); - - testDeposit, SimEngine::GRPIC>( - { - 10, - 10 + 500); + + testDeposit, SimEngine::GRPIC>(res, + r_extent, + { + { "r0", 0.0 }, + { "h", 0.25 }, + { "a", 0.9 } }, - { { 1.0, 100.0 } }, - { { "r0", 0.0 }, { "h", 0.25 }, { "a", 0.9 } }, - 500); - - testDeposit, SimEngine::GRPIC>( - { - 10, - 10 + 500); + + testDeposit, SimEngine::GRPIC>(res, + r_extent, + { + { "a", 0.9 } }, - { { 1.0, 100.0 } }, - { { "a", 0.9 } }, - 500); + 500); } catch (std::exception& e) { std::cerr << e.what() << std::endl; diff --git a/src/kernels/tests/digital_filter.cpp b/src/kernels/tests/digital_filter.cpp index 03a63753b..30059e471 100644 --- a/src/kernels/tests/digital_filter.cpp +++ b/src/kernels/tests/digital_filter.cpp @@ -20,7 +20,6 @@ #include #include #include -#include #include void errorIf(bool condition, const std::string& message) { @@ -34,15 +33,17 @@ void testFilter(const std::vector& res, const boundaries_t& ext, const std::map& params = {}) { static_assert(M::Dim == 2); - errorIf(res.size() != M::Dim, "res.size() != M::Dim"); + errorIf(res.size() != static_cast(M::Dim), "res.size() != M::Dim"); using namespace ntt; auto boundaries = boundaries_t {}; + auto extents = ext; if constexpr (M::CoordType != Coord::Cart) { boundaries = { { FldsBC::CUSTOM, FldsBC::CUSTOM }, { FldsBC::AXIS, FldsBC::AXIS } }; + extents.emplace_back(ZERO, (real_t)(constant::PI)); } else { boundaries = { { FldsBC::PERIODIC, FldsBC::PERIODIC }, @@ -50,7 +51,7 @@ void testFilter(const std::vector& res, }; } - M metric { res, ext, params }; + M metric { res, extents, params }; const auto nx1 = res[0]; const auto nx2 = res[1]; @@ -133,53 +134,45 @@ auto main(int argc, char* argv[]) -> int { using namespace ntt; using namespace metric; - testFilter>( - { - 10, - 10 - }, - { { 0.0, 55.0 }, { 0.0, 55.0 } }, - {}); - - testFilter>( - { - 10, - 10 - }, - { { 1.0, 100.0 } }, - {}); - - testFilter>( - { - 10, - 10 - }, - { { 1.0, 100.0 } }, - { { "r0", 0.0 }, { "h", 0.25 } }); - - testFilter>( - { - 10, - 10 - }, - { { 1.0, 100.0 } }, - { { "a", 0.9 } }); - - testFilter>( - { - 10, - 10 - }, - { { 1.0, 100.0 } }, - { { "r0", 0.0 }, { "h", 0.25 }, { "a", 0.9 } }); - - testFilter>( - { - 10, - 10 - }, - { { 1.0, 100.0 } }, - { { "a", 0.9 } }); + const auto res = std::vector { 10, 10 }; + const auto r_extent = boundaries_t { + { 0.0, 100.0 } + }; + const auto xy_extent = boundaries_t { + { 0.0, 55.0 }, + { 0.0, 55.0 } + }; + + testFilter>(res, xy_extent, {}); + + testFilter>(res, r_extent, {}); + + testFilter>(res, + r_extent, + { + { "r0", 0.0 }, + { "h", 0.25 } + }); + + testFilter>(res, + r_extent, + { + { "a", 0.9 } + }); + + testFilter>(res, + r_extent, + { + { "r0", 0.0 }, + { "h", 0.25 }, + { "a", 0.9 } + }); + + testFilter>(res, + r_extent, + { + { "a", 0.9 } + }); } catch (std::exception& e) { std::cerr << e.what() << std::endl; diff --git a/src/kernels/tests/prtl_bc.cpp b/src/kernels/tests/prtl_bc.cpp index 14c1a9f54..80e4ec7ed 100644 --- a/src/kernels/tests/prtl_bc.cpp +++ b/src/kernels/tests/prtl_bc.cpp @@ -53,35 +53,45 @@ void testPeriodicBC(const std::vector& res, const auto NoGCA = false; const auto NoExtForce = false; - boundaries_t extent; - extent = ext; - const auto sx = static_cast(extent[0].second - extent[0].first); - const auto sy = static_cast( - extent.size() > 1 ? extent[1].second - extent[1].first : 0); - const auto sz = static_cast( - extent.size() > 2 ? extent[2].second - extent[2].first : 0); + real_t sx = ZERO, sy = ZERO, sz = ZERO; + if (ext.size() > 0) { + sx = static_cast(ext.at(0).second - ext.at(0).first); + } + if (ext.size() > 1) { + sy = static_cast(ext.at(1).second - ext.at(1).first); + } + if (ext.size() > 2) { + sz = static_cast(ext.at(2).second - ext.at(2).first); + } - M metric { res, extent, params }; + M metric { res, ext, params }; - const int nx1 = res[0]; - const int nx2 = res[1]; - const int nx3 = res[2]; + int nx1 = 0, nx2 = 0, nx3 = 0; + if (res.size() > 0) { + nx1 = static_cast(res.at(0)); + } + if (res.size() > 1) { + nx2 = static_cast(res.at(1)); + } + if (res.size() > 2) { + nx3 = static_cast(res.at(2)); + } - const real_t dt = 0.1 * (extent[0].second - extent[0].first) / sx; + const real_t dt = 0.1 * (ext.at(0).second - ext.at(0).first) / sx; const real_t coeff = HALF * dt; ndfield_t emfield; if constexpr (M::Dim == Dim::_1D) { - emfield = ndfield_t { "emfield", res[0] + 2 * N_GHOSTS }; + emfield = ndfield_t { "emfield", res.at(0) + 2 * N_GHOSTS }; } else if constexpr (M::Dim == Dim::_2D) { emfield = ndfield_t { "emfield", - res[0] + 2 * N_GHOSTS, - res[1] + 2 * N_GHOSTS }; + res.at(0) + 2 * N_GHOSTS, + res.at(1) + 2 * N_GHOSTS }; } else { emfield = ndfield_t { "emfield", - res[0] + 2 * N_GHOSTS, - res[1] + 2 * N_GHOSTS, - res[2] + 2 * N_GHOSTS }; + res.at(0) + 2 * N_GHOSTS, + res.at(1) + 2 * N_GHOSTS, + res.at(2) + 2 * N_GHOSTS }; } const short sp_idx = 1; @@ -106,18 +116,26 @@ void testPeriodicBC(const std::vector& res, array_t phi; // init parameters of prtl #1 - real_t xi_1 = 0.515460 * sx + extent[0].first; - real_t yi_1 = 0.340680 * sy + extent[1].first; - real_t zi_1 = 0.940722 * sz + extent[2].first; + real_t xi_1 = ZERO, yi_1 = ZERO, zi_1 = ZERO; + real_t xi_2 = ZERO, yi_2 = ZERO, zi_2 = ZERO; + if constexpr (M::Dim == Dim::_1D or M::Dim == Dim::_2D or M::Dim == Dim::_3D) { + xi_1 = 0.515460 * sx + ext.at(0).first; + xi_2 = 0.149088 * sx + ext.at(0).first; + } + if constexpr (M::Dim == Dim::_2D or M::Dim == Dim::_3D) { + yi_1 = 0.340680 * sy + ext.at(1).first; + yi_2 = 0.997063 * sy + ext.at(1).first; + } + if constexpr (M::Dim == Dim::_3D) { + zi_1 = 0.940722 * sz + ext.at(2).first; + zi_2 = 0.607354 * sz + ext.at(2).first; + } real_t ux_1 = 0.569197; real_t uy_1 = 0.716085; real_t uz_1 = 0.760101; real_t gamma_1 = math::sqrt(1.0 + SQR(ux_1) + SQR(uy_1) + SQR(uz_1)); // init parameters of prtl #2 - real_t xi_2 = 0.149088 * sx + extent[0].first; - real_t yi_2 = 0.997063 * sy + extent[1].first; - real_t zi_2 = 0.607354 * sz + extent[2].first; real_t ux_2 = -0.872069; real_t uy_2 = 0.0484461; real_t uz_2 = -0.613575; @@ -268,16 +286,16 @@ void testPeriodicBC(const std::vector& res, if constexpr (M::Dim == Dim::_1D or M::Dim == Dim::_2D or M::Dim == Dim::_3D) { xi_1 += dt * ux_1 / gamma_1; xi_2 += dt * ux_2 / gamma_2; - if (xi_1 >= extent[0].second) { + if (xi_1 >= ext.at(0).second) { xi_1 -= sx; } - if (xi_1 < extent[0].first) { + if (xi_1 < ext.at(0).first) { xi_1 += sx; } - if (xi_2 >= extent[0].second) { + if (xi_2 >= ext.at(0).second) { xi_2 -= sx; } - if (xi_2 < extent[0].first) { + if (xi_2 < ext.at(0).first) { xi_2 += sx; } errorIf(not equal(xPh_1[0] / sx, @@ -290,16 +308,16 @@ void testPeriodicBC(const std::vector& res, if constexpr (M::Dim == Dim::_2D or M::Dim == Dim::_3D) { yi_1 += dt * uy_1 / gamma_1; yi_2 += dt * uy_2 / gamma_2; - if (yi_1 >= extent[1].second) { + if (yi_1 >= ext.at(1).second) { yi_1 -= sy; } - if (yi_1 < extent[1].first) { + if (yi_1 < ext.at(1).first) { yi_1 += sy; } - if (yi_2 >= extent[1].second) { + if (yi_2 >= ext.at(1).second) { yi_2 -= sy; } - if (yi_2 < extent[1].first) { + if (yi_2 < ext.at(1).first) { yi_2 += sy; } errorIf(not equal(xPh_1[1] / sy, @@ -312,16 +330,16 @@ void testPeriodicBC(const std::vector& res, if constexpr (M::Dim == Dim::_3D) { zi_1 += dt * uz_1 / gamma_1; zi_2 += dt * uz_2 / gamma_2; - if (zi_1 >= extent[2].second) { + if (zi_1 >= ext.at(2).second) { zi_1 -= sz; } - if (zi_1 < extent[2].first) { + if (zi_1 < ext.at(2).first) { zi_1 += sz; } - if (zi_2 >= extent[2].second) { + if (zi_2 >= ext.at(2).second) { zi_2 -= sz; } - if (zi_2 < extent[2].first) { + if (zi_2 < ext.at(2).first) { zi_2 += sz; } errorIf(not equal(xPh_1[2] / sz, diff --git a/src/metrics/kerr_schild.h b/src/metrics/kerr_schild.h index 13294dd7d..2ef702cce 100644 --- a/src/metrics/kerr_schild.h +++ b/src/metrics/kerr_schild.h @@ -72,8 +72,8 @@ namespace metric { using MetricBase::nx3; using MetricBase::set_dxMin; - KerrSchild(std::vector res, - boundaries_t ext, + KerrSchild(const std::vector& res, + const boundaries_t& ext, const std::map& params) : MetricBase { res, ext } , a { params.at("a") } diff --git a/src/metrics/kerr_schild_0.h b/src/metrics/kerr_schild_0.h index fdd2fd847..ccacbf6d9 100644 --- a/src/metrics/kerr_schild_0.h +++ b/src/metrics/kerr_schild_0.h @@ -53,8 +53,8 @@ namespace metric { using MetricBase::nx3; using MetricBase::set_dxMin; - KerrSchild0(std::vector res, - boundaries_t ext, + KerrSchild0(const std::vector& res, + const boundaries_t& ext, const std::map& = {}) : MetricBase { res, ext } , dr { (x1_max - x1_min) / nx1 } diff --git a/src/metrics/metric_base.h b/src/metrics/metric_base.h index 66cc28918..a418361a3 100644 --- a/src/metrics/metric_base.h +++ b/src/metrics/metric_base.h @@ -46,12 +46,38 @@ #include "global.h" +#include "utils/error.h" #include "utils/numeric.h" #include namespace metric { + namespace { + template + auto getNXi(const std::vector& res) -> real_t { + if constexpr (i >= static_cast(D)) { + return ONE; + } else { + raise::ErrorIf(res.size() <= i, "Invalid res size provided to metric", HERE); + return static_cast(res.at(i)); + } + }; + + template + auto getExtent(const boundaries_t& ext) -> real_t { + if constexpr (i >= static_cast(D)) { + return ZERO; + } else { + raise::ErrorIf(ext.size() <= i, "Invalid ext size provided to metric", HERE); + return min ? ext.at(i).first : ext.at(i).second; + } + }; + + constexpr bool XMin = true; + constexpr bool XMax = false; + }; // namespace + /** * Virtual parent metric class template: h_ij * Coordinates vary from `0` to `nx1` ... (code units) @@ -61,16 +87,16 @@ namespace metric { static constexpr bool is_metric { true }; static constexpr Dimension Dim { D }; - MetricBase(std::vector res, boundaries_t ext) - : nx1 { res.size() > 0 ? (real_t)(res[0]) : ONE } - , nx2 { res.size() > 1 ? (real_t)(res[1]) : ONE } - , nx3 { res.size() > 2 ? (real_t)(res[2]) : ONE } - , x1_min { res.size() > 0 ? ext[0].first : ZERO } - , x1_max { res.size() > 0 ? ext[0].second : ZERO } - , x2_min { res.size() > 1 ? ext[1].first : ZERO } - , x2_max { res.size() > 1 ? ext[1].second : ZERO } - , x3_min { res.size() > 2 ? ext[2].first : ZERO } - , x3_max { res.size() > 2 ? ext[2].second : ZERO } {} + MetricBase(const std::vector& res, const boundaries_t& ext) + : nx1 { getNXi(res) } + , nx2 { getNXi(res) } + , nx3 { getNXi(res) } + , x1_min { getExtent(ext) } + , x1_max { getExtent(ext) } + , x2_min { getExtent(ext) } + , x2_max { getExtent(ext) } + , x3_min { getExtent(ext) } + , x3_max { getExtent(ext) } {} ~MetricBase() = default; diff --git a/src/metrics/minkowski.h b/src/metrics/minkowski.h index 244ce9f25..e9ee76afa 100644 --- a/src/metrics/minkowski.h +++ b/src/metrics/minkowski.h @@ -47,24 +47,26 @@ namespace metric { using MetricBase::nx3; using MetricBase::set_dxMin; - Minkowski(std::vector res, - boundaries_t ext, + Minkowski(const std::vector& res, + const boundaries_t& ext, const std::map& = {}) : MetricBase { res, ext } , dx { (x1_max - x1_min) / nx1 } , dx_inv { ONE / dx } { set_dxMin(find_dxMin()); const auto epsilon = std::numeric_limits::epsilon() * - static_cast(100.0); + static_cast(100.0); if constexpr (D != Dim::_1D) { - raise::ErrorIf(not cmp::AlmostEqual((x2_max - x2_min) / (real_t)(nx2), dx, epsilon), - "dx2 must be equal to dx1 in 2D", - HERE); + raise::ErrorIf( + not cmp::AlmostEqual((x2_max - x2_min) / (real_t)(nx2), dx, epsilon), + "dx2 must be equal to dx1 in 2D", + HERE); } if constexpr (D == Dim::_3D) { - raise::ErrorIf(not cmp::AlmostEqual((x3_max - x3_min) / (real_t)(nx3), dx, epsilon), - "dx3 must be equal to dx1 in 3D", - HERE); + raise::ErrorIf( + not cmp::AlmostEqual((x3_max - x3_min) / (real_t)(nx3), dx, epsilon), + "dx3 must be equal to dx1 in 3D", + HERE); } } @@ -242,7 +244,8 @@ namespace metric { * @note tetrad/cart <-> cntrv <-> cov */ template - Inline auto transform(const coord_t& xi, const real_t& v_in) const -> real_t { + Inline auto transform(const coord_t& xi, const real_t& v_in) const + -> real_t { static_assert(i > 0 && i <= 3, "Invalid index i"); static_assert(in != out, "Invalid vector transformation"); if constexpr (i > static_cast(D)) { diff --git a/src/metrics/qkerr_schild.h b/src/metrics/qkerr_schild.h index d64fe05da..836646377 100644 --- a/src/metrics/qkerr_schild.h +++ b/src/metrics/qkerr_schild.h @@ -72,8 +72,8 @@ namespace metric { using MetricBase::nx3; using MetricBase::set_dxMin; - QKerrSchild(std::vector res, - boundaries_t ext, + QKerrSchild(const std::vector& res, + const boundaries_t& ext, const std::map& params) : MetricBase { res, ext } , a { params.at("a") } diff --git a/src/metrics/qspherical.h b/src/metrics/qspherical.h index 4df5db866..77c28dbff 100644 --- a/src/metrics/qspherical.h +++ b/src/metrics/qspherical.h @@ -55,8 +55,8 @@ namespace metric { using MetricBase::nx3; using MetricBase::set_dxMin; - QSpherical(std::vector res, - boundaries_t ext, + QSpherical(const std::vector& res, + const boundaries_t& ext, const std::map& params) : MetricBase { res, ext } , r0 { params.at("r0") } @@ -284,7 +284,8 @@ namespace metric { * @note tetrad/sph <-> cntrv <-> cov */ template - Inline auto transform(const coord_t& xi, const real_t& v_in) const -> real_t { + Inline auto transform(const coord_t& xi, const real_t& v_in) const + -> real_t { static_assert(i > 0 && i <= 3, "Invalid index i"); static_assert(in != out, "Invalid vector transformation"); if constexpr ((in == Idx::T && out == Idx::Sph) || diff --git a/src/metrics/spherical.h b/src/metrics/spherical.h index 54e12367d..5f510d5e1 100644 --- a/src/metrics/spherical.h +++ b/src/metrics/spherical.h @@ -50,8 +50,8 @@ namespace metric { using MetricBase::nx3; using MetricBase::set_dxMin; - Spherical(std::vector res, - boundaries_t ext, + Spherical(const std::vector& res, + const boundaries_t& ext, const std::map& = {}) : MetricBase { res, ext } , dr((x1_max - x1_min) / nx1) @@ -252,7 +252,8 @@ namespace metric { * @note tetrad/sph <-> cntrv <-> cov */ template - Inline auto transform(const coord_t& xi, const real_t& v_in) const -> real_t { + Inline auto transform(const coord_t& xi, const real_t& v_in) const + -> real_t { static_assert(i > 0 && i <= 3, "Invalid index i"); static_assert(in != out, "Invalid vector transformation"); if constexpr ((in == Idx::T && out == Idx::Sph) || From 4204cb8c7201a0471826880ba81fed9c8cedec5f Mon Sep 17 00:00:00 2001 From: Sasha Chernoglazov Date: Fri, 30 May 2025 12:59:39 -0400 Subject: [PATCH 718/773] remove override to compile the code --- src/metrics/qspherical.h | 2 +- src/metrics/spherical.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/metrics/qspherical.h b/src/metrics/qspherical.h index 4a5a9d380..3b1c8264a 100644 --- a/src/metrics/qspherical.h +++ b/src/metrics/qspherical.h @@ -103,7 +103,7 @@ namespace metric { * total volume of the region described by the metric (in physical units) */ [[nodiscard]] - auto totVolume() const -> real_t override { + auto totVolume() const -> real_t { if constexpr (D == Dim::_1D) { raise::Error("1D spherical metric not applicable", HERE); } else if constexpr (D == Dim::_2D) { diff --git a/src/metrics/spherical.h b/src/metrics/spherical.h index 05ec6b018..ee8018c52 100644 --- a/src/metrics/spherical.h +++ b/src/metrics/spherical.h @@ -82,7 +82,7 @@ namespace metric { * total volume of the region described by the metric (in physical units) */ [[nodiscard]] - auto totVolume() const -> real_t override { + auto totVolume() const -> real_t { if constexpr (D == Dim::_1D) { raise::Error("1D spherical metric not applicable", HERE); } else if constexpr (D == Dim::_2D) { From 54b9a2c71c2d789ef3e370f703b75580b3ec5412 Mon Sep 17 00:00:00 2001 From: haykh Date: Fri, 6 Jun 2025 21:03:29 -0500 Subject: [PATCH 719/773] LICENSE upd --- LICENSE | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/LICENSE b/LICENSE index 554820782..639d2b41f 100644 --- a/LICENSE +++ b/LICENSE @@ -1,19 +1,8 @@ BSD 3-Clause License -Copyright (c) 2024, Princeton University (PU), and -Princeton Plasma Physics Lab (PPPL). +Copyright (c) 2021-present, Entity development team. All rights reserved. -Core developers (alphabetical order): -* Alexander Chernoglazov -* Benjamin Crinquand -* Alisa Galishnikova -* Hayk Hakobyan -* Jens Mahlmann -* Sasha Philippov -* Arno Vanthieghem -* Muni Zhou - Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: From b42022a87f7ed828763e5f59d096f057a69dfe03 Mon Sep 17 00:00:00 2001 From: haykh Date: Fri, 6 Jun 2025 21:03:50 -0500 Subject: [PATCH 720/773] minor nix changes --- dev/nix/adios2.nix | 16 ++++++++-------- dev/nix/kokkos.nix | 14 +++++++------- dev/nix/shell.nix | 3 ++- 3 files changed, 17 insertions(+), 16 deletions(-) diff --git a/dev/nix/adios2.nix b/dev/nix/adios2.nix index 7218f894f..0418b71cd 100644 --- a/dev/nix/adios2.nix +++ b/dev/nix/adios2.nix @@ -19,10 +19,12 @@ let BUILD_TESTING = "OFF"; ADIOS2_BUILD_EXAMPLES = "OFF"; ADIOS2_USE_MPI = if mpi then "ON" else "OFF"; + ADIOS2_HAVE_HDF5_VOL = if mpi then "ON" else "OFF"; CMAKE_BUILD_TYPE = "Release"; - } // (if !mpi then { ADIOS2_HAVE_HDF5_VOL = "OFF"; } else { }); + }; + stdenv = pkgs.gcc13Stdenv; in -pkgs.stdenv.mkDerivation { +stdenv.mkDerivation { pname = "${name}${if hdf5 then "-hdf5" else ""}${if mpi then "-mpi" else ""}"; version = "${version}"; src = pkgs.fetchgit { @@ -36,12 +38,10 @@ pkgs.stdenv.mkDerivation { perl ]; - propagatedBuildInputs = - [ - pkgs.gcc13 - ] - ++ (if hdf5 then (if mpi then [ pkgs.hdf5-mpi ] else [ pkgs.hdf5 ]) else [ ]) - ++ (if mpi then [ pkgs.openmpi ] else [ ]); + propagatedBuildInputs = [ + pkgs.gcc13 + ] ++ (if hdf5 then (if mpi then [ pkgs.hdf5-mpi ] else [ pkgs.hdf5-cpp ]) else [ ]); + # ++ (if mpi then [ pkgs.openmpi ] else [ ]); configurePhase = '' cmake -B build $src ${ diff --git a/dev/nix/kokkos.nix b/dev/nix/kokkos.nix index c83a489e5..8dfe1f380 100644 --- a/dev/nix/kokkos.nix +++ b/dev/nix/kokkos.nix @@ -20,11 +20,18 @@ let "CUDA" = with pkgs.cudaPackages; [ cudatoolkit cuda_cudart + pkgs.gcc13 ]; "NONE" = [ pkgs.gcc13 ]; }; + getArch = + _: + if gpu != "NONE" && arch == "NATIVE" then + throw "Please specify an architecture when the GPU support is enabled. Available architectures: https://kokkos.org/kokkos-core-wiki/keywords.html#architectures" + else + arch; cmakeExtraFlags = { "HIP" = [ "-D Kokkos_ENABLE_HIP=ON" @@ -39,13 +46,6 @@ let ]; "NONE" = [ ]; }; - getArch = - _: - if gpu != "NONE" && arch == "NATIVE" then - throw "Please specify an architecture when the GPU support is enabled. Available architectures: https://kokkos.org/kokkos-core-wiki/keywords.html#architectures" - else - arch; - in pkgs.stdenv.mkDerivation rec { pname = "${name}"; diff --git a/dev/nix/shell.nix b/dev/nix/shell.nix index be4b87bcb..ae5451ec8 100644 --- a/dev/nix/shell.nix +++ b/dev/nix/shell.nix @@ -42,7 +42,8 @@ pkgs.mkShell { zlib cmake - clang-tools + llvmPackages_18.clang-tools + libgcc adios2Pkg kokkosPkg From 50b6a6ed68816d1d6792e93ddee5bff48f0abf70 Mon Sep 17 00:00:00 2001 From: haykh Date: Fri, 6 Jun 2025 21:06:36 -0500 Subject: [PATCH 721/773] cosmetic changes --- src/checkpoint/reader.cpp | 86 ++++++++---------------- src/checkpoint/writer.cpp | 128 +++++++++++++++++------------------- src/output/writer.cpp | 133 ++++++++++++-------------------------- 3 files changed, 128 insertions(+), 219 deletions(-) diff --git a/src/checkpoint/reader.cpp b/src/checkpoint/reader.cpp index 24aa0f079..d973b0ddd 100644 --- a/src/checkpoint/reader.cpp +++ b/src/checkpoint/reader.cpp @@ -110,7 +110,7 @@ namespace checkpoint { void ReadParticlePayloads(adios2::IO& io, adios2::Engine& reader, - spidx_t s, + spidx_t s, array_t& array, std::size_t nplds, npart_t count, @@ -130,64 +130,32 @@ namespace checkpoint { } } - template void ReadFields(adios2::IO&, - adios2::Engine&, - const std::string&, - const adios2::Box&, - ndfield_t&); - template void ReadFields(adios2::IO&, - adios2::Engine&, - const std::string&, - const adios2::Box&, - ndfield_t&); - template void ReadFields(adios2::IO&, - adios2::Engine&, - const std::string&, - const adios2::Box&, - ndfield_t&); - template void ReadFields(adios2::IO&, - adios2::Engine&, - const std::string&, - const adios2::Box&, - ndfield_t&); - template void ReadFields(adios2::IO&, - adios2::Engine&, - const std::string&, - const adios2::Box&, - ndfield_t&); - template void ReadFields(adios2::IO&, - adios2::Engine&, - const std::string&, - const adios2::Box&, - ndfield_t&); +#define CHECKPOINT_FIELDS(D, N) \ + template void ReadFields(adios2::IO&, \ + adios2::Engine&, \ + const std::string&, \ + const adios2::Box&, \ + ndfield_t&); + CHECKPOINT_FIELDS(Dim::_1D, 3) + CHECKPOINT_FIELDS(Dim::_2D, 3) + CHECKPOINT_FIELDS(Dim::_3D, 3) + CHECKPOINT_FIELDS(Dim::_1D, 6) + CHECKPOINT_FIELDS(Dim::_2D, 6) + CHECKPOINT_FIELDS(Dim::_3D, 6) +#undef CHECKPOINT_FIELDS - template void ReadParticleData(adios2::IO&, - adios2::Engine&, - const std::string&, - spidx_t, - array_t&, - npart_t, - npart_t); - template void ReadParticleData(adios2::IO&, - adios2::Engine&, - const std::string&, - spidx_t, - array_t&, - npart_t, - npart_t); - template void ReadParticleData(adios2::IO&, - adios2::Engine&, - const std::string&, - spidx_t, - array_t&, - npart_t, - npart_t); - template void ReadParticleData(adios2::IO&, - adios2::Engine&, - const std::string&, - spidx_t, - array_t&, - npart_t, - npart_t); +#define CHECKPOINT_PARTICLE_DATA(T) \ + template void ReadParticleData(adios2::IO&, \ + adios2::Engine&, \ + const std::string&, \ + spidx_t, \ + array_t&, \ + npart_t, \ + npart_t); + CHECKPOINT_PARTICLE_DATA(int) + CHECKPOINT_PARTICLE_DATA(float) + CHECKPOINT_PARTICLE_DATA(double) + CHECKPOINT_PARTICLE_DATA(short) +#undef CHECKPOINT_PARTICLE_DATA } // namespace checkpoint diff --git a/src/checkpoint/writer.cpp b/src/checkpoint/writer.cpp index b8571c246..b766ddfbd 100644 --- a/src/checkpoint/writer.cpp +++ b/src/checkpoint/writer.cpp @@ -15,21 +15,23 @@ #include #include #include -#include #include namespace checkpoint { - void Writer::init(adios2::ADIOS* ptr_adios, - timestep_t interval, - simtime_t interval_time, - int keep) { - m_keep = keep; - m_enabled = keep != 0; + void Writer::init(adios2::ADIOS* ptr_adios, + const path_t& checkpoint_root, + timestep_t interval, + simtime_t interval_time, + int keep, + const std::string& walltime) { + m_keep = keep; + m_checkpoint_root = checkpoint_root; + m_enabled = keep != 0; if (not m_enabled) { return; } - m_tracker.init("checkpoint", interval, interval_time); + m_tracker.init("checkpoint", interval, interval_time, walltime); p_adios = ptr_adios; raise::ErrorIf(p_adios == nullptr, "ADIOS pointer is null", HERE); @@ -40,12 +42,13 @@ namespace checkpoint { m_io.DefineVariable("Time"); m_io.DefineAttribute("NGhosts", ntt::N_GHOSTS); - CallOnce([]() { - const std::filesystem::path save_path { "checkpoints" }; - if (!std::filesystem::exists(save_path)) { - std::filesystem::create_directory(save_path); - } - }); + CallOnce( + [](auto&& checkpoint_root) { + if (!std::filesystem::exists(checkpoint_root)) { + std::filesystem::create_directory(checkpoint_root); + } + }, + m_checkpoint_root); } void Writer::defineFieldVariables(const ntt::SimEngine& S, @@ -147,13 +150,14 @@ namespace checkpoint { } m_writing_mode = true; try { - auto fname = fmt::format("checkpoints/step-%08lu.bp", step); - m_writer = m_io.Open(fname, adios2::Mode::Write); - auto meta_fname = fmt::format("checkpoints/meta-%08lu.toml", step); - m_written.push_back({ fname, meta_fname }); + const auto filename = m_checkpoint_root / fmt::format("step-%08lu.bp", step); + const auto metafilename = m_checkpoint_root / + fmt::format("meta-%08lu.toml", step); + m_writer = m_io.Open(filename, adios2::Mode::Write); + m_written.push_back({ filename, metafilename }); logger::Checkpoint(fmt::format("Writing checkpoint to %s and %s", - fname.c_str(), - meta_fname.c_str()), + filename.c_str(), + metafilename.c_str()), HERE); } catch (std::exception& e) { raise::Fatal(e.what(), HERE); @@ -261,54 +265,38 @@ namespace checkpoint { m_writer.Put(var, data_sub.data(), adios2::Mode::Sync); } - template void Writer::savePerDomainVariable(const std::string&, - std::size_t, - std::size_t, - int); - template void Writer::savePerDomainVariable(const std::string&, - std::size_t, - std::size_t, - float); - template void Writer::savePerDomainVariable(const std::string&, - std::size_t, - std::size_t, - double); - template void Writer::savePerDomainVariable(const std::string&, - std::size_t, - std::size_t, - npart_t); - - template void Writer::saveField(const std::string&, - const ndfield_t&); - template void Writer::saveField(const std::string&, - const ndfield_t&); - template void Writer::saveField(const std::string&, - const ndfield_t&); - template void Writer::saveField(const std::string&, - const ndfield_t&); - template void Writer::saveField(const std::string&, - const ndfield_t&); - template void Writer::saveField(const std::string&, - const ndfield_t&); - - template void Writer::saveParticleQuantity(const std::string&, - npart_t, - npart_t, - npart_t, - const array_t&); - template void Writer::saveParticleQuantity(const std::string&, - npart_t, - npart_t, - npart_t, - const array_t&); - template void Writer::saveParticleQuantity(const std::string&, - npart_t, - npart_t, - npart_t, - const array_t&); - template void Writer::saveParticleQuantity(const std::string&, - npart_t, - npart_t, - npart_t, - const array_t&); +#define CHECKPOINT_PERDOMAIN_VARIABLE(T) \ + template void Writer::savePerDomainVariable(const std::string&, \ + std::size_t, \ + std::size_t, \ + T); + CHECKPOINT_PERDOMAIN_VARIABLE(int) + CHECKPOINT_PERDOMAIN_VARIABLE(float) + CHECKPOINT_PERDOMAIN_VARIABLE(double) + CHECKPOINT_PERDOMAIN_VARIABLE(npart_t) +#undef CHECKPOINT_PERDOMAIN_VARIABLE + +#define CHECKPOINT_FIELD(D, N) \ + template void Writer::saveField(const std::string&, \ + const ndfield_t&); + CHECKPOINT_FIELD(Dim::_1D, 3) + CHECKPOINT_FIELD(Dim::_1D, 6) + CHECKPOINT_FIELD(Dim::_2D, 3) + CHECKPOINT_FIELD(Dim::_2D, 6) + CHECKPOINT_FIELD(Dim::_3D, 3) + CHECKPOINT_FIELD(Dim::_3D, 6) +#undef CHECKPOINT_FIELD + +#define CHECKPOINT_PARTICLE_QUANTITY(T) \ + template void Writer::saveParticleQuantity(const std::string&, \ + npart_t, \ + npart_t, \ + npart_t, \ + const array_t&); + CHECKPOINT_PARTICLE_QUANTITY(int) + CHECKPOINT_PARTICLE_QUANTITY(float) + CHECKPOINT_PARTICLE_QUANTITY(double) + CHECKPOINT_PARTICLE_QUANTITY(short) +#undef CHECKPOINT_PARTICLE_QUANTITY + } // namespace checkpoint diff --git a/src/output/writer.cpp b/src/output/writer.cpp index a259ba889..b073295e3 100644 --- a/src/output/writer.cpp +++ b/src/output/writer.cpp @@ -39,7 +39,7 @@ namespace out { m_io.DefineVariable("Step"); m_io.DefineVariable("Time"); - m_fname = title; + m_fname = path_t(title); } void Writer::addTracker(const std::string& type, @@ -48,8 +48,9 @@ namespace out { m_trackers.insert({ type, tools::Tracker(type, interval, interval_time) }); } - auto Writer::shouldWrite(const std::string& type, timestep_t step, simtime_t time) - -> bool { + auto Writer::shouldWrite(const std::string& type, + timestep_t step, + simtime_t time) -> bool { if (m_trackers.find(type) != m_trackers.end()) { return m_trackers.at(type).shouldWrite(step, time); } else { @@ -427,53 +428,53 @@ namespace out { if (m_active_mode != WriteMode::None) { raise::Fatal("Already writing", HERE); } - m_active_mode = write_mode; try { - std::string filename; + path_t filename; + const std::string ext = (m_engine == "hdf5") ? "h5" : "bp"; if (m_separate_files) { std::string mode_str; - if (m_active_mode == WriteMode::Fields) { + if (write_mode == WriteMode::Fields) { mode_str = "fields"; - } else if (m_active_mode == WriteMode::Particles) { + } else if (write_mode == WriteMode::Particles) { mode_str = "particles"; - } else if (m_active_mode == WriteMode::Spectra) { + } else if (write_mode == WriteMode::Spectra) { mode_str = "spectra"; } else { raise::Fatal("Unknown write mode", HERE); } CallOnce( - [](auto& main_path, auto& mode_path) { - const std::filesystem::path main { main_path }; - const std::filesystem::path mode { mode_path }; + [](auto&& main_path, auto&& mode_path) { + const path_t main { main_path }; + const path_t mode { mode_path }; if (!std::filesystem::exists(main_path)) { std::filesystem::create_directory(main_path); } - if (!std::filesystem::exists(main / mode)) { - std::filesystem::create_directory(main / mode); + if (!std::filesystem::exists(main_path / mode_path)) { + std::filesystem::create_directory(main_path / mode_path); } }, m_fname, mode_str); - filename = fmt::format("%s/%s/%s.%08lu.%s", - m_fname.c_str(), - mode_str.c_str(), - mode_str.c_str(), - tstep, - ext.c_str()); - m_mode = adios2::Mode::Write; +#if defined(MPI_ENABLED) + MPI_Barrier(MPI_COMM_WORLD); +#endif + filename = m_fname / path_t(mode_str) / + fmt::format("%s.%08lu.%s", mode_str.c_str(), tstep, ext.c_str()); + m_mode = adios2::Mode::Write; } else { filename = fmt::format("%s.%s", m_fname.c_str(), ext.c_str()); m_mode = std::filesystem::exists(filename) ? adios2::Mode::Append : adios2::Mode::Write; } m_writer = m_io.Open(filename, m_mode); + m_writer.BeginStep(); + m_writer.Put(m_io.InquireVariable("Step"), &tstep); + m_writer.Put(m_io.InquireVariable("Time"), &time); + m_active_mode = write_mode; } catch (std::exception& e) { raise::Fatal(e.what(), HERE); } - m_writer.BeginStep(); - m_writer.Put(m_io.InquireVariable("Step"), &tstep); - m_writer.Put(m_io.InquireVariable("Time"), &time); } void Writer::endWriting(WriteModeTags write_mode) { @@ -490,72 +491,24 @@ namespace out { m_writer.Close(); } - template void Writer::writeField(const std::vector&, - const ndfield_t&, - const std::vector&); - template void Writer::writeField(const std::vector&, - const ndfield_t&, - const std::vector&); - template void Writer::writeField(const std::vector&, - const ndfield_t&, - const std::vector&); - template void Writer::writeField(const std::vector&, - const ndfield_t&, - const std::vector&); - template void Writer::writeField(const std::vector&, - const ndfield_t&, - const std::vector&); - template void Writer::writeField(const std::vector&, - const ndfield_t&, - const std::vector&); - - template void WriteField(adios2::IO&, - adios2::Engine&, - const std::string&, - const ndfield_t&, - std::size_t, - std::vector, - std::vector, - bool); - template void WriteField(adios2::IO&, - adios2::Engine&, - const std::string&, - const ndfield_t&, - std::size_t, - std::vector, - std::vector, - bool); - template void WriteField(adios2::IO&, - adios2::Engine&, - const std::string&, - const ndfield_t&, - std::size_t, - std::vector, - std::vector, - bool); - template void WriteField(adios2::IO&, - adios2::Engine&, - const std::string&, - const ndfield_t&, - std::size_t, - std::vector, - std::vector, - bool); - template void WriteField(adios2::IO&, - adios2::Engine&, - const std::string&, - const ndfield_t&, - std::size_t, - std::vector, - std::vector, - bool); - template void WriteField(adios2::IO&, - adios2::Engine&, - const std::string&, - const ndfield_t&, - std::size_t, - std::vector, - std::vector, - bool); +#define WRITE_FIELD(D, N) \ + template void Writer::writeField(const std::vector&, \ + const ndfield_t&, \ + const std::vector&); \ + template void WriteField(adios2::IO&, \ + adios2::Engine&, \ + const std::string&, \ + const ndfield_t&, \ + std::size_t, \ + std::vector, \ + std::vector, \ + bool); + WRITE_FIELD(Dim::_1D, 3) + WRITE_FIELD(Dim::_1D, 6) + WRITE_FIELD(Dim::_2D, 3) + WRITE_FIELD(Dim::_2D, 6) + WRITE_FIELD(Dim::_3D, 3) + WRITE_FIELD(Dim::_3D, 6) +#undef WRITE_FIELD } // namespace out From 0599bcc71a11871e1249542bf71eee8d4e3fdd58 Mon Sep 17 00:00:00 2001 From: haykh Date: Fri, 6 Jun 2025 21:12:04 -0500 Subject: [PATCH 722/773] minor warnings + bugs --- src/archetypes/energy_dist.h | 2 +- src/checkpoint/tests/checkpoint-nompi.cpp | 35 ++++++++++++----------- src/engines/engine_printer.cpp | 10 +++---- src/framework/containers/particles.cpp | 5 ---- src/framework/simulation.h | 3 -- src/global/global.h | 4 +++ src/kernels/fields_bcs.hpp | 2 +- src/output/writer.h | 4 +-- 8 files changed, 32 insertions(+), 33 deletions(-) diff --git a/src/archetypes/energy_dist.h b/src/archetypes/energy_dist.h index e9ef8b0b7..901dbce3a 100644 --- a/src/archetypes/energy_dist.h +++ b/src/archetypes/energy_dist.h @@ -392,7 +392,7 @@ namespace arch { Inline void operator()(const coord_t& x_Code, vec_t& v, - spidx_t sp = 0) const override { + spidx_t = 0) const override { if (cmp::AlmostZero(temperature)) { v[0] = ZERO; v[1] = ZERO; diff --git a/src/checkpoint/tests/checkpoint-nompi.cpp b/src/checkpoint/tests/checkpoint-nompi.cpp index be5e97e24..85871183d 100644 --- a/src/checkpoint/tests/checkpoint-nompi.cpp +++ b/src/checkpoint/tests/checkpoint-nompi.cpp @@ -12,14 +12,13 @@ #include #include -#include using namespace ntt; using namespace checkpoint; void cleanup() { namespace fs = std::filesystem; - fs::path temp_path { "checkpoints" }; + fs::path temp_path { "chck" }; fs::remove_all(temp_path); } @@ -58,18 +57,21 @@ auto main(int argc, char* argv[]) -> int { CreateRangePolicy({ i1min, i2min, i3min }, { i1max, i2max, i3max }), Lambda(index_t i1, index_t i2, index_t i3) { - field1(i1, i2, i3, 0) = i1 + i2 + i3; - field1(i1, i2, i3, 1) = i1 * i2 / i3; - field1(i1, i2, i3, 2) = i1 / i2 * i3; - field1(i1, i2, i3, 3) = i1 + i2 - i3; - field1(i1, i2, i3, 4) = i1 * i2 + i3; - field1(i1, i2, i3, 5) = i1 / i2 - i3; - field2(i1, i2, i3, 0) = -(i1 + i2 + i3); - field2(i1, i2, i3, 1) = -(i1 * i2 / i3); - field2(i1, i2, i3, 2) = -(i1 / i2 * i3); - field2(i1, i2, i3, 3) = -(i1 + i2 - i3); - field2(i1, i2, i3, 4) = -(i1 * i2 + i3); - field2(i1, i2, i3, 5) = -(i1 / i2 - i3); + const auto i1_ = static_cast(i1); + const auto i2_ = static_cast(i2); + const auto i3_ = static_cast(i3); + field1(i1, i2, i3, 0) = i1_ + i2_ + i3; + field1(i1, i2, i3, 1) = i1_ * i2_ / i3; + field1(i1, i2, i3, 2) = i1_ / i2_ * i3; + field1(i1, i2, i3, 3) = i1_ + i2_ - i3; + field1(i1, i2, i3, 4) = i1_ * i2_ + i3; + field1(i1, i2, i3, 5) = i1_ / i2_ - i3; + field2(i1, i2, i3, 0) = -(i1_ + i2_ + i3); + field2(i1, i2, i3, 1) = -(i1_ * i2_ / i3); + field2(i1, i2, i3, 2) = -(i1_ / i2_ * i3); + field2(i1, i2, i3, 3) = -(i1_ + i2_ - i3); + field2(i1, i2, i3, 4) = -(i1_ * i2_ + i3); + field2(i1, i2, i3, 5) = -(i1_ / i2_ - i3); }); Kokkos::parallel_for( "fillPrtl1", @@ -88,10 +90,11 @@ auto main(int argc, char* argv[]) -> int { } adios2::ADIOS adios; + const path_t checkpoint_path { "chck" }; { // write checkpoint - Writer writer; + Writer writer { checkpoint_path }; writer.init(&adios, 0, 0.0, 1); writer.defineFieldVariables(SimEngine::GRPIC, @@ -127,7 +130,7 @@ auto main(int argc, char* argv[]) -> int { array_t u2_read { "u_2", npart2 }; adios2::IO io = adios.DeclareIO("checkpointRead"); - adios2::Engine reader = io.Open("checkpoints/step-00000000.bp", + adios2::Engine reader = io.Open(checkpoint_path / "step-00000000.bp", adios2::Mode::Read); reader.BeginStep(); diff --git a/src/engines/engine_printer.cpp b/src/engines/engine_printer.cpp index 9d1f74a74..20f5e81ba 100644 --- a/src/engines/engine_printer.cpp +++ b/src/engines/engine_printer.cpp @@ -106,13 +106,13 @@ namespace ntt { color::RESET); } - auto bytes_to_human_readable(std::size_t bytes) - -> std::pair { + auto bytes_to_human_readable( + std::size_t bytes) -> std::pair { const std::vector units { "B", "KB", "MB", "GB", "TB" }; idx_t unit_idx = 0; - auto size = static_cast(bytes); - while ((size >= 1024) && (unit_idx < units.size() - 1)) { - size /= 1024; + auto size = static_cast(bytes); + while ((size >= 1024.0) and (unit_idx < units.size() - 1)) { + size /= 1024.0; ++unit_idx; } return { size, units[unit_idx] }; diff --git a/src/framework/containers/particles.cpp b/src/framework/containers/particles.cpp index b69e48de4..d2db9c491 100644 --- a/src/framework/containers/particles.cpp +++ b/src/framework/containers/particles.cpp @@ -4,8 +4,6 @@ #include "global.h" #include "arch/kokkos_aliases.h" -#include "utils/numeric.h" -#include "utils/sorting.h" #include "framework/containers/species.h" @@ -13,9 +11,6 @@ #include #include -#include -#include -#include #include #include diff --git a/src/framework/simulation.h b/src/framework/simulation.h index 3cc664995..33750030f 100644 --- a/src/framework/simulation.h +++ b/src/framework/simulation.h @@ -22,9 +22,6 @@ #include "framework/parameters.h" -#include -#include - namespace ntt { class Simulation { diff --git a/src/global/global.h b/src/global/global.h index 1f7987929..04552db7f 100644 --- a/src/global/global.h +++ b/src/global/global.h @@ -93,6 +93,7 @@ #define GLOBAL_GLOBAL_H #include +#include #include #include #include @@ -357,6 +358,9 @@ using idx_t = unsigned short; using spidx_t = unsigned short; using dim_t = unsigned short; +// utility +using path_t = std::filesystem::path; + using range_tuple_t = std::pair; template diff --git a/src/kernels/fields_bcs.hpp b/src/kernels/fields_bcs.hpp index 0a5dc6168..a520616bf 100644 --- a/src/kernels/fields_bcs.hpp +++ b/src/kernels/fields_bcs.hpp @@ -491,8 +491,8 @@ namespace kernel::bc { "Invalid component index"); ndfield_t Fld; - const BCTags tags; const std::size_t i_edge; + const BCTags tags; ConductorBoundaries_kernel(ndfield_t Fld, std::size_t i_edge, BCTags tags) : Fld { Fld } diff --git a/src/output/writer.h b/src/output/writer.h index 2e8d20de5..66ee4e597 100644 --- a/src/output/writer.h +++ b/src/output/writer.h @@ -57,7 +57,7 @@ namespace out { bool m_flds_ghosts; std::string m_engine; - std::string m_fname; + path_t m_fname; std::map m_trackers; @@ -116,7 +116,7 @@ namespace out { void endWriting(WriteModeTags); /* getters -------------------------------------------------------------- */ - auto fname() const -> const std::string& { + auto fname() const -> const path_t& { return m_fname; } From ca2e1a3253124ffccb408d3ccd77aa8dcbd15264 Mon Sep 17 00:00:00 2001 From: haykh Date: Fri, 6 Jun 2025 21:12:54 -0500 Subject: [PATCH 723/773] checkpoint: read/write path + walltime --- input.example.toml | 9 +++++ src/checkpoint/writer.h | 12 ++++-- src/engines/engine.hpp | 5 --- src/engines/engine_init.cpp | 16 +------- src/engines/engine_run.cpp | 9 ----- src/framework/domain/checkpoint.cpp | 18 ++++++--- src/framework/domain/stats.cpp | 25 ++++++------- src/framework/parameters.cpp | 17 +++++++-- src/framework/parameters.h | 2 + src/framework/simulation.cpp | 28 +++++++++----- src/global/utils/tools.h | 57 ++++++++++++++++++++++------- 11 files changed, 120 insertions(+), 78 deletions(-) diff --git a/input.example.toml b/input.example.toml index bef6ab237..aa532273b 100644 --- a/input.example.toml +++ b/input.example.toml @@ -483,6 +483,15 @@ # @note: Empty string means disables this (still writes checkpoints on interval) # @note: This does not exit the simulation walltime = "" + # Parent directory to write checkpoints to + # @type: string + # @default: "checkpoints" + # @note: The directory is created if it does not exist + write_path = "" + # Parent directory to use when resuming from a checkpoint + # @type: string + # @default: inherits from `write_path` + read_path = "" # @inferred: # - is_resuming diff --git a/src/checkpoint/writer.h b/src/checkpoint/writer.h index 91c9d7a41..3aa30d04d 100644 --- a/src/checkpoint/writer.h +++ b/src/checkpoint/writer.h @@ -39,15 +39,21 @@ namespace checkpoint { std::vector> m_written; - int m_keep; - bool m_enabled; + int m_keep; + bool m_enabled; + path_t m_checkpoint_root; public: Writer() {} ~Writer() = default; - void init(adios2::ADIOS*, timestep_t, simtime_t, int); + void init(adios2::ADIOS*, + const path_t&, + timestep_t, + simtime_t, + int, + const std::string&); auto shouldSave(timestep_t, simtime_t) -> bool; diff --git a/src/engines/engine.hpp b/src/engines/engine.hpp index 261b1d6ea..17103f1de 100644 --- a/src/engines/engine.hpp +++ b/src/engines/engine.hpp @@ -43,7 +43,6 @@ #include #endif // MPI_ENABLED -#include #include #include @@ -61,9 +60,6 @@ namespace ntt { #else adios2::ADIOS m_adios; #endif - const timestamp_t start_walltime { std::chrono::system_clock::now() }; - timestamp_t end_walltime {}; - bool walltime_checkpoint_pending { false }; #endif SimulationParams m_params; @@ -114,7 +110,6 @@ namespace ntt { , time { start_time } , step { start_step } { raise::ErrorIf(not pgen_is_ok, "Problem generator is not compatible with the picked engine/metric/dimension", HERE); - print_report(); } ~Engine() = default; diff --git a/src/engines/engine_init.cpp b/src/engines/engine_init.cpp index 0e99451e9..8953b3da8 100644 --- a/src/engines/engine_init.cpp +++ b/src/engines/engine_init.cpp @@ -27,20 +27,6 @@ namespace ntt { #if defined(OUTPUT_ENABLED) m_metadomain.InitWriter(&m_adios, m_params, is_resuming); m_metadomain.InitCheckpointWriter(&m_adios, m_params); - - const auto checkpoint_walltime = m_params.template get( - "checkpoint.walltime"); - if (not checkpoint_walltime.empty()) { - walltime_checkpoint_pending = true; - raise::ErrorIf(checkpoint_walltime.size() != 8, - "invalid checkpoint walltime format, expected HH:MM:SS", - HERE); - end_walltime = - start_walltime + - std::chrono::hours(std::stoi(checkpoint_walltime.substr(0, 2))) + - std::chrono::minutes(std::stoi(checkpoint_walltime.substr(3, 2))) + - std::chrono::seconds(std::stoi(checkpoint_walltime.substr(6, 2))); - } #endif logger::Checkpoint("Initializing Engine", HERE); if (not is_resuming) { @@ -82,6 +68,7 @@ namespace ntt { #endif } } + print_report(); } template class Engine>; @@ -92,4 +79,5 @@ namespace ntt { template class Engine>; template class Engine>; template class Engine>; + } // namespace ntt diff --git a/src/engines/engine_run.cpp b/src/engines/engine_run.cpp index 80e9cb62d..65c87e939 100644 --- a/src/engines/engine_run.cpp +++ b/src/engines/engine_run.cpp @@ -115,15 +115,6 @@ namespace ntt { step - 1, time, time - dt); - if ((not print_checkpoint) and (walltime_checkpoint_pending) and - (std::chrono::system_clock::now() >= end_walltime)) { - print_checkpoint = m_metadomain.WriteCheckpoint(m_params, - step, - step - 1, - time, - time - dt); - walltime_checkpoint_pending = false; - } timers.stop("Checkpoint"); #endif diff --git a/src/framework/domain/checkpoint.cpp b/src/framework/domain/checkpoint.cpp index a39f18e66..e0e34f993 100644 --- a/src/framework/domain/checkpoint.cpp +++ b/src/framework/domain/checkpoint.cpp @@ -47,11 +47,16 @@ namespace ntt { nplds.push_back(local_domain->species[s].npld()); } + const path_t checkpoint_root = params.template get( + "checkpoint.write_path"); + g_checkpoint_writer.init( ptr_adios, + checkpoint_root, params.template get("checkpoint.interval"), params.template get("checkpoint.interval_time"), - params.template get("checkpoint.keep")); + params.template get("checkpoint.keep"), + params.template get("checkpoint.walltime")); if (g_checkpoint_writer.enabled()) { g_checkpoint_writer.defineFieldVariables(S, glob_shape_with_ghosts, @@ -261,9 +266,12 @@ namespace ntt { void Metadomain::ContinueFromCheckpoint(adios2::ADIOS* ptr_adios, const SimulationParams& params) { raise::ErrorIf(ptr_adios == nullptr, "adios == nullptr", HERE); - auto fname = fmt::format( - "checkpoints/step-%08lu.bp", - params.template get("checkpoint.start_step")); + const path_t checkpoint_root = params.template get( + "checkpoint.read_path"); + const auto fname = checkpoint_root / + fmt::format("step-%08lu.bp", + params.template get( + "checkpoint.start_step")); logger::Checkpoint(fmt::format("Reading checkpoint from %s", fname.c_str()), HERE); @@ -484,7 +492,6 @@ namespace ntt { simtime_t) -> bool; \ template void Metadomain::ContinueFromCheckpoint(adios2::ADIOS*, \ const SimulationParams&); - METADOMAIN_CHECKPOINTS(SimEngine::SRPIC, metric::Minkowski) METADOMAIN_CHECKPOINTS(SimEngine::SRPIC, metric::Minkowski) METADOMAIN_CHECKPOINTS(SimEngine::SRPIC, metric::Minkowski) @@ -493,7 +500,6 @@ namespace ntt { METADOMAIN_CHECKPOINTS(SimEngine::GRPIC, metric::KerrSchild) METADOMAIN_CHECKPOINTS(SimEngine::GRPIC, metric::QKerrSchild) METADOMAIN_CHECKPOINTS(SimEngine::GRPIC, metric::KerrSchild0) - #undef METADOMAIN_CHECKPOINTS } // namespace ntt diff --git a/src/framework/domain/stats.cpp b/src/framework/domain/stats.cpp index a252e975d..6c5bb0ffa 100644 --- a/src/framework/domain/stats.cpp +++ b/src/framework/domain/stats.cpp @@ -89,7 +89,6 @@ namespace ntt { } // some parameters const auto use_weights = params.template get("particles.use_weights"); - const auto inv_n0 = ONE / params.template get("scales.n0"); real_t buffer = static_cast(0); for (const auto& sp : specs) { @@ -186,8 +185,8 @@ namespace ntt { timestep_t finished_step, simtime_t current_time, simtime_t finished_time, - std::function&)> CustomStat) - -> bool { + std::function&)> + CustomStat) -> bool { if (not(params.template get("output.stats.enable") and g_stats_writer.shouldWrite(finished_step, finished_time))) { return false; @@ -272,16 +271,16 @@ namespace ntt { return true; } -#define METADOMAIN_STATS(S, M) \ - template void Metadomain::InitStatsWriter(const SimulationParams&, bool); \ - template auto Metadomain::WriteStats( \ - const SimulationParams&, \ - timestep_t, \ - timestep_t, \ - simtime_t, \ - simtime_t, \ - std::function&)>) \ - -> bool; +#define METADOMAIN_STATS(S, M) \ + template void Metadomain::InitStatsWriter(const SimulationParams&, bool); \ + template auto Metadomain::WriteStats( \ + const SimulationParams&, \ + timestep_t, \ + timestep_t, \ + simtime_t, \ + simtime_t, \ + std::function< \ + real_t(const std::string&, timestep_t, simtime_t, const Domain&)>) -> bool; METADOMAIN_STATS(SimEngine::SRPIC, metric::Minkowski) METADOMAIN_STATS(SimEngine::SRPIC, metric::Minkowski) diff --git a/src/framework/parameters.cpp b/src/framework/parameters.cpp index ac0a5e0dd..586a01941 100644 --- a/src/framework/parameters.cpp +++ b/src/framework/parameters.cpp @@ -31,10 +31,10 @@ namespace ntt { template - auto get_dx0_V0(const std::vector& resolution, - const boundaries_t& extent, - const std::map& params) - -> std::pair { + auto get_dx0_V0( + const std::vector& resolution, + const boundaries_t& extent, + const std::map& params) -> std::pair { const auto metric = M(resolution, extent, params); const auto dx0 = metric.dxMin(); coord_t x_corner { ZERO }; @@ -612,6 +612,15 @@ namespace ntt { set("checkpoint.walltime", toml::find_or(toml_data, "checkpoint", "walltime", std::string(""))); + const auto checkpoint_write_path = toml::find_or( + toml_data, + "checkpoint", + "write_path", + std::string("checkpoints")); + set("checkpoint.write_path", checkpoint_write_path); + set("checkpoint.read_path", + toml::find_or(toml_data, "checkpoint", "read_path", checkpoint_write_path)); + /* [diagnostics] -------------------------------------------------------- */ set("diagnostics.interval", toml::find_or(toml_data, "diagnostics", "interval", defaults::diag::interval)); diff --git a/src/framework/parameters.h b/src/framework/parameters.h index 83192f447..723e860db 100644 --- a/src/framework/parameters.h +++ b/src/framework/parameters.h @@ -26,6 +26,8 @@ namespace ntt { SimulationParams() {} + SimulationParams(const SimulationParams&) = default; + SimulationParams& operator=(const SimulationParams& other) { vars = std::move(other.vars); promises = std::move(other.promises); diff --git a/src/framework/simulation.cpp b/src/framework/simulation.cpp index 6865140c9..b130d10a7 100644 --- a/src/framework/simulation.cpp +++ b/src/framework/simulation.cpp @@ -11,8 +11,6 @@ #include "utils/plog.h" #include "utils/toml.h" -#include "framework/parameters.h" - #include #include @@ -55,13 +53,24 @@ namespace ntt { m_params.setRawData(raw_params); timestep_t checkpoint_step = 0; + if (is_resuming) { logger::Checkpoint("Reading params from a checkpoint", HERE); - if (not std::filesystem::exists("checkpoints")) { + const auto checkpoint_write_path = toml::find_or( + raw_params, + "checkpoint", + "write_path", + "checkpoints"); + const path_t checkpoint_read_path = toml::find_or( + raw_params, + "checkpoint", + "read_path", + checkpoint_write_path); + if (not std::filesystem::exists(checkpoint_read_path)) { raise::Fatal("No checkpoints found", HERE); } for (const auto& entry : - std::filesystem::directory_iterator("checkpoints")) { + std::filesystem::directory_iterator(checkpoint_read_path)) { const auto fname = entry.path().filename().string(); if (fname.find("step-") == 0) { const timestep_t step = std::stoi(fname.substr(5, fname.size() - 5 - 3)); @@ -70,17 +79,16 @@ namespace ntt { } } } - std::string checkpoint_inputfname = fmt::format( - "checkpoints/meta-%08lu.toml", - checkpoint_step); - if (not std::filesystem::exists(checkpoint_inputfname)) { + path_t checkpoint_metafname = checkpoint_read_path / + fmt::format("meta-%08lu.toml", checkpoint_step); + if (not std::filesystem::exists(checkpoint_metafname)) { raise::Fatal( fmt::format("metainformation for %lu not found", checkpoint_step), HERE); - checkpoint_inputfname = inputfname; + checkpoint_metafname = inputfname; } logger::Checkpoint(fmt::format("Using %08lu", checkpoint_step), HERE); - const auto raw_checkpoint_params = toml::parse(checkpoint_inputfname); + const auto raw_checkpoint_params = toml::parse(checkpoint_metafname); const auto start_time = toml::find(raw_checkpoint_params, "metadata", "time"); diff --git a/src/global/utils/tools.h b/src/global/utils/tools.h index 95765e2de..0f2ab0bec 100644 --- a/src/global/utils/tools.h +++ b/src/global/utils/tools.h @@ -18,11 +18,11 @@ #include "global.h" -#include "arch/kokkos_aliases.h" #include "utils/comparators.h" #include "utils/error.h" #include "utils/numeric.h" +#include #include #include #include @@ -275,6 +275,11 @@ namespace tools { } } + /** + * Class for tracking the passage of time either in steps, physical time units, or walltime + * + * @note Primarily used for writing checkpoints and all types of outputs at specified intervals + */ class Tracker { bool m_initialized { false }; @@ -283,31 +288,55 @@ namespace tools { simtime_t m_interval_time; bool m_use_time; + timestamp_t m_start_walltime; + timestamp_t m_end_walltime; + bool m_walltime_pending { false }; + simtime_t m_last_output_time { -1.0 }; public: Tracker() = default; - Tracker(const std::string& type, timestep_t interval, simtime_t interval_time) - : m_initialized { true } - , m_type { type } - , m_interval { interval } - , m_interval_time { interval_time } - , m_use_time { interval_time > 0.0 } {} + Tracker(const std::string& type, + timestep_t interval, + simtime_t interval_time, + const std::string& end_walltime = "", + const timestamp_t& start_walltime = std::chrono::system_clock::now()) { + init(type, interval, interval_time, end_walltime, start_walltime); + } ~Tracker() = default; - void init(const std::string& type, timestep_t interval, simtime_t interval_time) { - m_type = type; - m_interval = interval; - m_interval_time = interval_time; - m_use_time = interval_time > 0.0; - m_initialized = true; + void init(const std::string& type, + timestep_t interval, + simtime_t interval_time, + const std::string& end_walltime = "", + const timestamp_t& start_walltime = std::chrono::system_clock::now()) { + m_initialized = true; + m_type = type; + m_interval = interval; + m_interval_time = interval_time; + m_use_time = interval_time > 0.0; + m_start_walltime = start_walltime; + if (not end_walltime.empty()) { + m_walltime_pending = true; + raise::ErrorIf(end_walltime.size() != 8, + "invalid end walltime format, expected HH:MM:SS", + HERE); + m_end_walltime = m_start_walltime + + std::chrono::hours(std::stoi(end_walltime.substr(0, 2))) + + std::chrono::minutes(std::stoi(end_walltime.substr(3, 2))) + + std::chrono::seconds(std::stoi(end_walltime.substr(6, 2))); + } } auto shouldWrite(timestep_t step, simtime_t time) -> bool { raise::ErrorIf(!m_initialized, "Tracker not initialized", HERE); - if (m_use_time) { + if (m_walltime_pending and + (std::chrono::system_clock::now() > m_end_walltime)) { + m_walltime_pending = false; + return true; + } else if (m_use_time) { if ((m_last_output_time < 0) or (time - m_last_output_time >= m_interval_time)) { m_last_output_time = time; From b122d489fdf06e5575d11890ce6908989e48e7ae Mon Sep 17 00:00:00 2001 From: haykh Date: Fri, 6 Jun 2025 21:24:34 -0500 Subject: [PATCH 724/773] warning on failed write + fixed logging --- src/global/utils/param_container.cpp | 5 +++++ src/global/utils/plog.h | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/global/utils/param_container.cpp b/src/global/utils/param_container.cpp index e1dd57c9e..3c19b48a9 100644 --- a/src/global/utils/param_container.cpp +++ b/src/global/utils/param_container.cpp @@ -331,6 +331,11 @@ namespace prm { try { write_any(io, key, value); } catch (const std::exception& e) { + raise::Warning( + fmt::format("Failed to write parameter '%s', skipping. Error msg: %s", + key.c_str(), + e.what()), + HERE); continue; } } diff --git a/src/global/utils/plog.h b/src/global/utils/plog.h index 2422c7cf9..7713a3728 100644 --- a/src/global/utils/plog.h +++ b/src/global/utils/plog.h @@ -80,9 +80,9 @@ namespace logger { static plog::RollingFileAppender errfileAppender( errfile_name.c_str()); auto log_severity = plog::verbose; - if (fmt::toLower(log_level) == "WARNING") { + if (fmt::toLower(log_level) == "warning") { log_severity = plog::warning; - } else if (fmt::toLower(log_level) == "ERROR") { + } else if (fmt::toLower(log_level) == "error") { log_severity = plog::error; } plog::init(log_severity, &logfileAppender); From 224bdec00ef318cc994d52cb62b02da931197328 Mon Sep 17 00:00:00 2001 From: haykh Date: Fri, 6 Jun 2025 21:45:21 -0500 Subject: [PATCH 725/773] fixed meta writing after restart --- src/engines/engine_init.cpp | 2 +- src/framework/domain/metadomain.h | 2 +- src/framework/domain/output.cpp | 12 +++--------- src/output/writer.cpp | 24 ++++++++++++------------ src/output/writer.h | 6 +++--- 5 files changed, 20 insertions(+), 26 deletions(-) diff --git a/src/engines/engine_init.cpp b/src/engines/engine_init.cpp index 8953b3da8..7a963b615 100644 --- a/src/engines/engine_init.cpp +++ b/src/engines/engine_init.cpp @@ -25,7 +25,7 @@ namespace ntt { if constexpr (pgen_is_ok) { m_metadomain.InitStatsWriter(m_params, is_resuming); #if defined(OUTPUT_ENABLED) - m_metadomain.InitWriter(&m_adios, m_params, is_resuming); + m_metadomain.InitWriter(&m_adios, m_params); m_metadomain.InitCheckpointWriter(&m_adios, m_params); #endif logger::Checkpoint("Initializing Engine", HERE); diff --git a/src/framework/domain/metadomain.h b/src/framework/domain/metadomain.h index 0cb670965..efc639a86 100644 --- a/src/framework/domain/metadomain.h +++ b/src/framework/domain/metadomain.h @@ -116,7 +116,7 @@ namespace ntt { ~Metadomain() = default; #if defined(OUTPUT_ENABLED) - void InitWriter(adios2::ADIOS*, const SimulationParams&, bool); + void InitWriter(adios2::ADIOS*, const SimulationParams&); auto Write(const SimulationParams&, timestep_t, timestep_t, diff --git a/src/framework/domain/output.cpp b/src/framework/domain/output.cpp index ce5a13168..63f4b6e72 100644 --- a/src/framework/domain/output.cpp +++ b/src/framework/domain/output.cpp @@ -40,8 +40,7 @@ namespace ntt { template void Metadomain::InitWriter(adios2::ADIOS* ptr_adios, - const SimulationParams& params, - bool is_resuming) { + const SimulationParams& params) { raise::ErrorIf( l_subdomain_indices().size() != 1, "Output for now is only supported for one subdomain per rank", @@ -103,11 +102,7 @@ namespace ntt { params.template get( "output." + std::string(type) + ".interval_time")); } - if (is_resuming and std::filesystem::exists(g_writer.fname())) { - g_writer.setMode(adios2::Mode::Append); - } else { - g_writer.writeAttrs(params); - } + g_writer.writeAttrs(params); } template @@ -715,8 +710,7 @@ namespace ntt { #define METADOMAIN_OUTPUT(S, M) \ template void Metadomain::InitWriter(adios2::ADIOS*, \ - const SimulationParams&, \ - bool); \ + const SimulationParams&); \ template auto Metadomain::Write( \ const SimulationParams&, \ timestep_t, \ diff --git a/src/output/writer.cpp b/src/output/writer.cpp index b073295e3..65fa50d4c 100644 --- a/src/output/writer.cpp +++ b/src/output/writer.cpp @@ -39,7 +39,7 @@ namespace out { m_io.DefineVariable("Step"); m_io.DefineVariable("Time"); - m_fname = path_t(title); + m_root = path_t(title); } void Writer::addTracker(const std::string& type, @@ -321,7 +321,7 @@ namespace out { } auto output_field_h = Kokkos::create_mirror_view(output_field); Kokkos::deep_copy(output_field_h, output_field); - writer.Put(var, output_field_h); + writer.Put(var, output_field_h, adios2::Mode::Sync); } template @@ -356,7 +356,7 @@ namespace out { adios2::Box({ loc_offset }, { array.extent(0) })); auto array_h = Kokkos::create_mirror_view(array); Kokkos::deep_copy(array_h, array); - m_writer.Put(var, array_h); + m_writer.Put(var, array_h, adios2::Mode::Sync); } void Writer::writeSpectrum(const array_t& counts, @@ -378,12 +378,12 @@ namespace out { if (rank == MPI_ROOT_RANK) { auto var = m_io.InquireVariable(varname); var.SetSelection(adios2::Box({}, { counts.extent(0) })); - m_writer.Put(var, counts_h_all); + m_writer.Put(var, counts_h_all, adios2::Mode::Sync); } #else auto var = m_io.InquireVariable(varname); var.SetSelection(adios2::Box({}, { counts.extent(0) })); - m_writer.Put(var, counts_h); + m_writer.Put(var, counts_h, adios2::Mode::Sync); #endif } @@ -400,7 +400,7 @@ namespace out { var.SetSelection(adios2::Box({}, { e_bins.extent(0) })); auto e_bins_h = Kokkos::create_mirror_view(e_bins); Kokkos::deep_copy(e_bins_h, e_bins); - m_writer.Put(var, e_bins_h); + m_writer.Put(var, e_bins_h, adios2::Mode::Sync); } void Writer::writeMesh(unsigned short dim, @@ -413,11 +413,11 @@ namespace out { auto xe_h = Kokkos::create_mirror_view(xe); Kokkos::deep_copy(xc_h, xc); Kokkos::deep_copy(xe_h, xe); - m_writer.Put(varc, xc_h); - m_writer.Put(vare, xe_h); + m_writer.Put(varc, xc_h, adios2::Mode::Sync); + m_writer.Put(vare, xe_h, adios2::Mode::Sync); auto vard = m_io.InquireVariable( "N" + std::to_string(dim + 1) + "l"); - m_writer.Put(vard, loc_off_sz.data()); + m_writer.Put(vard, loc_off_sz.data(), adios2::Mode::Sync); } void Writer::beginWriting(WriteModeTags write_mode, @@ -454,16 +454,16 @@ namespace out { std::filesystem::create_directory(main_path / mode_path); } }, - m_fname, + m_root, mode_str); #if defined(MPI_ENABLED) MPI_Barrier(MPI_COMM_WORLD); #endif - filename = m_fname / path_t(mode_str) / + filename = m_root / path_t(mode_str) / fmt::format("%s.%08lu.%s", mode_str.c_str(), tstep, ext.c_str()); m_mode = adios2::Mode::Write; } else { - filename = fmt::format("%s.%s", m_fname.c_str(), ext.c_str()); + filename = fmt::format("%s.%s", m_root.c_str(), ext.c_str()); m_mode = std::filesystem::exists(filename) ? adios2::Mode::Append : adios2::Mode::Write; } diff --git a/src/output/writer.h b/src/output/writer.h index 66ee4e597..cc3edc733 100644 --- a/src/output/writer.h +++ b/src/output/writer.h @@ -57,7 +57,7 @@ namespace out { bool m_flds_ghosts; std::string m_engine; - path_t m_fname; + path_t m_root; std::map m_trackers; @@ -116,8 +116,8 @@ namespace out { void endWriting(WriteModeTags); /* getters -------------------------------------------------------------- */ - auto fname() const -> const path_t& { - return m_fname; + auto root() const -> const path_t& { + return m_root; } auto fieldWriters() const -> const std::vector& { From 30afad12e997ae1673678b912d9f6a72cff9a06e Mon Sep 17 00:00:00 2001 From: haykh Date: Fri, 6 Jun 2025 21:59:59 -0500 Subject: [PATCH 726/773] minor changes in tests --- src/checkpoint/tests/checkpoint-nompi.cpp | 28 ++++----- src/checkpoint/writer.h | 2 +- src/kernels/tests/prtl_bc.cpp | 74 ++++++++++++++--------- src/kernels/tests/reduced_stats.cpp | 37 ++++-------- 4 files changed, 70 insertions(+), 71 deletions(-) diff --git a/src/checkpoint/tests/checkpoint-nompi.cpp b/src/checkpoint/tests/checkpoint-nompi.cpp index 85871183d..132a3679a 100644 --- a/src/checkpoint/tests/checkpoint-nompi.cpp +++ b/src/checkpoint/tests/checkpoint-nompi.cpp @@ -60,18 +60,18 @@ auto main(int argc, char* argv[]) -> int { const auto i1_ = static_cast(i1); const auto i2_ = static_cast(i2); const auto i3_ = static_cast(i3); - field1(i1, i2, i3, 0) = i1_ + i2_ + i3; - field1(i1, i2, i3, 1) = i1_ * i2_ / i3; - field1(i1, i2, i3, 2) = i1_ / i2_ * i3; - field1(i1, i2, i3, 3) = i1_ + i2_ - i3; - field1(i1, i2, i3, 4) = i1_ * i2_ + i3; - field1(i1, i2, i3, 5) = i1_ / i2_ - i3; - field2(i1, i2, i3, 0) = -(i1_ + i2_ + i3); - field2(i1, i2, i3, 1) = -(i1_ * i2_ / i3); - field2(i1, i2, i3, 2) = -(i1_ / i2_ * i3); - field2(i1, i2, i3, 3) = -(i1_ + i2_ - i3); - field2(i1, i2, i3, 4) = -(i1_ * i2_ + i3); - field2(i1, i2, i3, 5) = -(i1_ / i2_ - i3); + field1(i1, i2, i3, 0) = i1_ + i2_ + i3_; + field1(i1, i2, i3, 1) = i1_ * i2_ / i3_; + field1(i1, i2, i3, 2) = i1_ / i2_ * i3_; + field1(i1, i2, i3, 3) = i1_ + i2_ - i3_; + field1(i1, i2, i3, 4) = i1_ * i2_ + i3_; + field1(i1, i2, i3, 5) = i1_ / i2_ - i3_; + field2(i1, i2, i3, 0) = -(i1_ + i2_ + i3_); + field2(i1, i2, i3, 1) = -(i1_ * i2_ / i3_); + field2(i1, i2, i3, 2) = -(i1_ / i2_ * i3_); + field2(i1, i2, i3, 3) = -(i1_ + i2_ - i3_); + field2(i1, i2, i3, 4) = -(i1_ * i2_ + i3_); + field2(i1, i2, i3, 5) = -(i1_ / i2_ - i3_); }); Kokkos::parallel_for( "fillPrtl1", @@ -94,8 +94,8 @@ auto main(int argc, char* argv[]) -> int { { // write checkpoint - Writer writer { checkpoint_path }; - writer.init(&adios, 0, 0.0, 1); + Writer writer {}; + writer.init(&adios, checkpoint_path, 0, 0.0, 1); writer.defineFieldVariables(SimEngine::GRPIC, { nx1_gh, nx2_gh, nx3_gh }, diff --git a/src/checkpoint/writer.h b/src/checkpoint/writer.h index 3aa30d04d..6f8bc8cb5 100644 --- a/src/checkpoint/writer.h +++ b/src/checkpoint/writer.h @@ -53,7 +53,7 @@ namespace checkpoint { timestep_t, simtime_t, int, - const std::string&); + const std::string& = ""); auto shouldSave(timestep_t, simtime_t) -> bool; diff --git a/src/kernels/tests/prtl_bc.cpp b/src/kernels/tests/prtl_bc.cpp index 80e4ec7ed..6e49f8ba5 100644 --- a/src/kernels/tests/prtl_bc.cpp +++ b/src/kernels/tests/prtl_bc.cpp @@ -160,21 +160,28 @@ void testPeriodicBC(const std::vector& res, xi[2] = zi_1; } metric.template convert_xyz(xi, xCd); - put_value(i1, static_cast(xCd[0]), prtl_idx); - put_value(i2, static_cast(xCd[1]), prtl_idx); - put_value(i3, static_cast(xCd[2]), prtl_idx); - put_value(dx1, - static_cast(xCd[0]) - - static_cast(static_cast(xCd[0])), - prtl_idx); - put_value(dx2, - static_cast(xCd[1]) - - static_cast(static_cast(xCd[1])), - prtl_idx); - put_value(dx3, - static_cast(xCd[2]) - - static_cast(static_cast(xCd[2])), - prtl_idx); + if constexpr (M::PrtlDim == Dim::_1D or M::PrtlDim == Dim::_2D or + M::PrtlDim == Dim::_3D) { + put_value(i1, static_cast(xCd[0]), prtl_idx); + put_value(dx1, + static_cast(xCd[0]) - + static_cast(static_cast(xCd[0])), + prtl_idx); + } + if constexpr (M::PrtlDim == Dim::_2D or M::PrtlDim == Dim::_3D) { + put_value(i2, static_cast(xCd[1]), prtl_idx); + put_value(dx2, + static_cast(xCd[1]) - + static_cast(static_cast(xCd[1])), + prtl_idx); + } + if constexpr (M::PrtlDim == Dim::_3D) { + put_value(i3, static_cast(xCd[2]), prtl_idx); + put_value(dx3, + static_cast(xCd[2]) - + static_cast(static_cast(xCd[2])), + prtl_idx); + } put_value(ux1, ux_1, prtl_idx); put_value(ux2, uy_1, prtl_idx); put_value(ux3, uz_1, prtl_idx); @@ -195,21 +202,28 @@ void testPeriodicBC(const std::vector& res, xi[2] = zi_2; } metric.template convert_xyz(xi, xCd); - put_value(i1, static_cast(xCd[0]), prtl_idx); - put_value(i2, static_cast(xCd[1]), prtl_idx); - put_value(i3, static_cast(xCd[2]), prtl_idx); - put_value(dx1, - static_cast(xCd[0]) - - static_cast(static_cast(xCd[0])), - prtl_idx); - put_value(dx2, - static_cast(xCd[1]) - - static_cast(static_cast(xCd[1])), - prtl_idx); - put_value(dx3, - static_cast(xCd[2]) - - static_cast(static_cast(xCd[2])), - prtl_idx); + if constexpr (M::PrtlDim == Dim::_1D or M::PrtlDim == Dim::_2D or + M::PrtlDim == Dim::_3D) { + put_value(i1, static_cast(xCd[0]), prtl_idx); + put_value(dx1, + static_cast(xCd[0]) - + static_cast(static_cast(xCd[0])), + prtl_idx); + } + if constexpr (M::PrtlDim == Dim::_2D or M::PrtlDim == Dim::_3D) { + put_value(i2, static_cast(xCd[1]), prtl_idx); + put_value(dx2, + static_cast(xCd[1]) - + static_cast(static_cast(xCd[1])), + prtl_idx); + } + if constexpr (M::PrtlDim == Dim::_3D) { + put_value(i3, static_cast(xCd[2]), prtl_idx); + put_value(dx3, + static_cast(xCd[2]) - + static_cast(static_cast(xCd[2])), + prtl_idx); + } put_value(ux1, ux_2, prtl_idx); put_value(ux2, uy_2, prtl_idx); put_value(ux3, uz_2, prtl_idx); diff --git a/src/kernels/tests/reduced_stats.cpp b/src/kernels/tests/reduced_stats.cpp index caae51ccd..499c24aa9 100644 --- a/src/kernels/tests/reduced_stats.cpp +++ b/src/kernels/tests/reduced_stats.cpp @@ -66,8 +66,7 @@ template auto compute_field_stat(const M& metric, const ndfield_t& em, const ndfield_t& j, - const range_t& range, - ncells_t num_cells) -> real_t { + const range_t& range) -> real_t { real_t buff = ZERO; Kokkos::parallel_reduce("ReduceFields", range, @@ -113,13 +112,11 @@ void testReducedStats(const std::vector& res, ndfield_t EM; ndfield_t J; range_t cell_range; - ncells_t num_cells; if constexpr (M::Dim == Dim::_1D) { EM = ndfield_t { "EM", res[0] + 2 * N_GHOSTS }; J = ndfield_t { "J", res[0] + 2 * N_GHOSTS }; cell_range = { N_GHOSTS, res[0] + N_GHOSTS }; - num_cells = res[0]; put_value(EM, values[0], em::ex1); put_value(EM, values[1], em::ex2); @@ -140,7 +137,6 @@ void testReducedStats(const std::vector& res, { N_GHOSTS, N_GHOSTS }, { res[0] + N_GHOSTS, res[1] + N_GHOSTS } }; - num_cells = res[0] * res[1]; put_value(EM, values[0], em::ex1); put_value(EM, values[1], em::ex2); @@ -167,7 +163,6 @@ void testReducedStats(const std::vector& res, { N_GHOSTS, N_GHOSTS, N_GHOSTS }, { res[0] + N_GHOSTS, res[1] + N_GHOSTS, res[2] + N_GHOSTS } }; - num_cells = res[0] * res[1] * res[2]; put_value(EM, values[0], em::ex1); put_value(EM, values[1], em::ex2); @@ -186,8 +181,7 @@ void testReducedStats(const std::vector& res, const auto Ex_Sq = compute_field_stat(metric, EM, J, - cell_range, - num_cells); + cell_range); raise::ErrorIf(not almost_equal(Ex_Sq, (real_t)(1), acc), "Ex_Sq does not match expected value", HERE); @@ -197,8 +191,7 @@ void testReducedStats(const std::vector& res, const auto Ey_Sq = compute_field_stat(metric, EM, J, - cell_range, - num_cells); + cell_range); raise::ErrorIf(not almost_equal(Ey_Sq, (real_t)(4), acc), "Ey_Sq does not match expected value", HERE); @@ -208,8 +201,7 @@ void testReducedStats(const std::vector& res, const auto Ez_Sq = compute_field_stat(metric, EM, J, - cell_range, - num_cells); + cell_range); raise::ErrorIf(not almost_equal(Ez_Sq, (real_t)(9), acc), "Ez_Sq does not match expected value", HERE); @@ -219,8 +211,7 @@ void testReducedStats(const std::vector& res, const auto Bx_Sq = compute_field_stat(metric, EM, J, - cell_range, - num_cells); + cell_range); raise::ErrorIf(not almost_equal(Bx_Sq, (real_t)(1), acc), "Bx_Sq does not match expected value", HERE); @@ -230,8 +221,7 @@ void testReducedStats(const std::vector& res, const auto By_Sq = compute_field_stat(metric, EM, J, - cell_range, - num_cells); + cell_range); raise::ErrorIf(not almost_equal(By_Sq, (real_t)(4), acc), "By_Sq does not match expected value", HERE); @@ -241,8 +231,7 @@ void testReducedStats(const std::vector& res, const auto Bz_Sq = compute_field_stat(metric, EM, J, - cell_range, - num_cells); + cell_range); raise::ErrorIf(not almost_equal(Bz_Sq, (real_t)(9), acc), "Bz_Sq does not match expected value", HERE); @@ -252,8 +241,7 @@ void testReducedStats(const std::vector& res, const auto ExB_x = compute_field_stat(metric, EM, J, - cell_range, - num_cells); + cell_range); raise::ErrorIf(not almost_equal(ExB_x, (real_t)(12), acc), "ExB_x does not match expected value", HERE); @@ -263,8 +251,7 @@ void testReducedStats(const std::vector& res, const auto ExB_y = compute_field_stat(metric, EM, J, - cell_range, - num_cells); + cell_range); raise::ErrorIf(not almost_equal(ExB_y, (real_t)(-6), acc), "ExB_y does not match expected value", HERE); @@ -274,8 +261,7 @@ void testReducedStats(const std::vector& res, const auto ExB_z = compute_field_stat(metric, EM, J, - cell_range, - num_cells); + cell_range); raise::ErrorIf(not almost_equal(ExB_z, (real_t)(0), acc), "ExB_z does not match expected value", HERE); @@ -285,8 +271,7 @@ void testReducedStats(const std::vector& res, const auto JdotE = compute_field_stat(metric, EM, J, - cell_range, - num_cells); + cell_range); raise::ErrorIf(not almost_equal(JdotE, (real_t)(11), acc), "JdotE does not match expected value", HERE); From bebf5d020bd78febe13a15db838b0a2ba6a66967 Mon Sep 17 00:00:00 2001 From: hayk Date: Sun, 8 Jun 2025 15:23:23 -0400 Subject: [PATCH 727/773] walltime defaults to 00:00:00 to prevent error in attr writing --- input.example.toml | 2 +- src/framework/parameters.cpp | 20 ++++++++++------ src/global/defaults.h | 6 +++-- src/global/utils/param_container.cpp | 33 ++++++++++++++------------- src/global/utils/tools.h | 34 +++++++++++++--------------- src/output/writer.cpp | 5 ++-- 6 files changed, 53 insertions(+), 47 deletions(-) diff --git a/input.example.toml b/input.example.toml index aa532273b..d3e8e5d81 100644 --- a/input.example.toml +++ b/input.example.toml @@ -476,7 +476,7 @@ keep = "" # Write a checkpoint once after a fixed walltime # @type: string - # @default: "" (disabled) + # @default: "00:00:00" (disabled) # @note: The format is "HH:MM:SS" # @note: Useful for long-running simulations to ensure that ... # @note: ... the simulation can be resumed after allocation expires diff --git a/src/framework/parameters.cpp b/src/framework/parameters.cpp index 586a01941..d901ce1ec 100644 --- a/src/framework/parameters.cpp +++ b/src/framework/parameters.cpp @@ -31,10 +31,10 @@ namespace ntt { template - auto get_dx0_V0( - const std::vector& resolution, - const boundaries_t& extent, - const std::map& params) -> std::pair { + auto get_dx0_V0(const std::vector& resolution, + const boundaries_t& extent, + const std::map& params) + -> std::pair { const auto metric = M(resolution, extent, params); const auto dx0 = metric.dxMin(); coord_t x_corner { ZERO }; @@ -609,14 +609,20 @@ namespace ntt { toml::find_or(toml_data, "checkpoint", "interval_time", -1.0)); set("checkpoint.keep", toml::find_or(toml_data, "checkpoint", "keep", defaults::checkpoint::keep)); - set("checkpoint.walltime", - toml::find_or(toml_data, "checkpoint", "walltime", std::string(""))); + auto walltime_str = toml::find_or(toml_data, + "checkpoint", + "walltime", + defaults::checkpoint::walltime); + if (walltime_str.empty()) { + walltime_str = defaults::checkpoint::walltime; + } + set("checkpoint.walltime", walltime_str); const auto checkpoint_write_path = toml::find_or( toml_data, "checkpoint", "write_path", - std::string("checkpoints")); + defaults::checkpoint::write_path); set("checkpoint.write_path", checkpoint_write_path); set("checkpoint.read_path", toml::find_or(toml_data, "checkpoint", "read_path", checkpoint_write_path)); diff --git a/src/global/defaults.h b/src/global/defaults.h index d673a503c..8ddbc0ce0 100644 --- a/src/global/defaults.h +++ b/src/global/defaults.h @@ -67,8 +67,10 @@ namespace ntt::defaults { } // namespace output namespace checkpoint { - const timestep_t interval = 1000; - const int keep = 2; + const timestep_t interval = 1000; + const int keep = 2; + const std::string walltime = "00:00:00"; + const std::string write_path = "checkpoints"; } // namespace checkpoint namespace diag { diff --git a/src/global/utils/param_container.cpp b/src/global/utils/param_container.cpp index 3c19b48a9..54d8591b3 100644 --- a/src/global/utils/param_container.cpp +++ b/src/global/utils/param_container.cpp @@ -13,7 +13,6 @@ #include #include #include - #include #include #include @@ -32,8 +31,8 @@ namespace prm { } template - auto write(adios2::IO& io, const std::string& name, T var) -> decltype(void(T()), - void()) { + auto write(adios2::IO& io, const std::string& name, T var) + -> decltype(void(T()), void()) { io.DefineAttribute(name, var); } @@ -48,8 +47,8 @@ namespace prm { } template - auto write_pair(adios2::IO& io, const std::string& name, std::pair var) -> - typename std::enable_if::value, void>::type { + auto write_pair(adios2::IO& io, const std::string& name, std::pair var) + -> typename std::enable_if::value, void>::type { std::vector var_str; var_str.push_back(var.first.to_string()); var_str.push_back(var.second.to_string()); @@ -57,9 +56,8 @@ namespace prm { } template - auto write_pair(adios2::IO& io, - const std::string& name, - std::pair var) -> decltype(void(T()), void()) { + auto write_pair(adios2::IO& io, const std::string& name, std::pair var) + -> decltype(void(T()), void()) { std::vector var_vec; var_vec.push_back(var.first); var_vec.push_back(var.second); @@ -77,9 +75,8 @@ namespace prm { } template - auto write_vec(adios2::IO& io, - const std::string& name, - std::vector var) -> decltype(void(T()), void()) { + auto write_vec(adios2::IO& io, const std::string& name, std::vector var) + -> decltype(void(T()), void()) { io.DefineAttribute(name, var.data(), var.size()); } @@ -99,8 +96,8 @@ namespace prm { template auto write_vec_pair(adios2::IO& io, const std::string& name, - std::vector> var) -> decltype(void(T()), - void()) { + std::vector> var) + -> decltype(void(T()), void()) { std::vector var_vec; for (const auto& v : var) { var_vec.push_back(v.first); @@ -126,8 +123,8 @@ namespace prm { template auto write_vec_vec(adios2::IO& io, const std::string& name, - std::vector> var) -> decltype(void(T()), - void()) { + std::vector> var) + -> decltype(void(T()), void()) { std::vector var_vec; for (const auto& vec : var) { for (const auto& v : vec) { @@ -328,6 +325,10 @@ namespace prm { register_write_function_for_dict(); for (auto& [key, value] : allVars()) { + // @TODO: add particles.species support in attrs + if (key == "particles.species") { + continue; + } try { write_any(io, key, value); } catch (const std::exception& e) { @@ -343,4 +344,4 @@ namespace prm { } // namespace prm -#endif +#endif // OUTPUT_ENABLED diff --git a/src/global/utils/tools.h b/src/global/utils/tools.h index 0f2ab0bec..27c7e22c8 100644 --- a/src/global/utils/tools.h +++ b/src/global/utils/tools.h @@ -60,8 +60,8 @@ namespace tools { * @return Tensor product of list */ template - inline auto TensorProduct( - const std::vector>& list) -> std::vector> { + inline auto TensorProduct(const std::vector>& list) + -> std::vector> { std::vector> result = { {} }; for (const auto& sublist : list) { std::vector> temp; @@ -81,8 +81,8 @@ namespace tools { * @param ndomains Number of domains * @param ncells Number of cells */ - inline auto decompose1D(unsigned int ndomains, - ncells_t ncells) -> std::vector { + inline auto decompose1D(unsigned int ndomains, ncells_t ncells) + -> std::vector { auto size = (ncells_t)((double)ncells / (double)ndomains); auto ncells_domain = std::vector(ndomains, size); for (auto i { 0u }; i < ncells - size * ndomains; ++i) { @@ -107,10 +107,8 @@ namespace tools { * @param s1 Proportion of the first dimension * @param s2 Proportion of the second dimension */ - inline auto divideInProportions2D( - unsigned int ntot, - unsigned int s1, - unsigned int s2) -> std::tuple { + inline auto divideInProportions2D(unsigned int ntot, unsigned int s1, unsigned int s2) + -> std::tuple { auto n1 = (unsigned int)(std::sqrt((double)ntot * (double)s1 / (double)s2)); if (n1 == 0) { return { 1, ntot }; @@ -132,11 +130,11 @@ namespace tools { * @param s2 Proportion of the second dimension * @param s3 Proportion of the third dimension */ - inline auto divideInProportions3D( - unsigned int ntot, - unsigned int s1, - unsigned int s2, - unsigned int s3) -> std::tuple { + inline auto divideInProportions3D(unsigned int ntot, + unsigned int s1, + unsigned int s2, + unsigned int s3) + -> std::tuple { auto n1 = (unsigned int)(std::cbrt( (double)ntot * (double)(SQR(s1)) / (double)(s2 * s3))); if (n1 > ntot) { @@ -165,10 +163,10 @@ namespace tools { * * @note If decomposition has -1, it will be calculated automatically */ - inline auto Decompose( - unsigned int ndomains, - const std::vector& ncells, - const std::vector& decomposition) -> std::vector> { + inline auto Decompose(unsigned int ndomains, + const std::vector& ncells, + const std::vector& decomposition) + -> std::vector> { const auto dimension = ncells.size(); raise::ErrorIf(dimension != decomposition.size(), "Decomposition error: dimension != decomposition.size", @@ -318,7 +316,7 @@ namespace tools { m_interval_time = interval_time; m_use_time = interval_time > 0.0; m_start_walltime = start_walltime; - if (not end_walltime.empty()) { + if (not(end_walltime.empty() or end_walltime == "00:00:00")) { m_walltime_pending = true; raise::ErrorIf(end_walltime.size() != 8, "invalid end walltime format, expected HH:MM:SS", diff --git a/src/output/writer.cpp b/src/output/writer.cpp index 65fa50d4c..9a96f9f56 100644 --- a/src/output/writer.cpp +++ b/src/output/writer.cpp @@ -48,9 +48,8 @@ namespace out { m_trackers.insert({ type, tools::Tracker(type, interval, interval_time) }); } - auto Writer::shouldWrite(const std::string& type, - timestep_t step, - simtime_t time) -> bool { + auto Writer::shouldWrite(const std::string& type, timestep_t step, simtime_t time) + -> bool { if (m_trackers.find(type) != m_trackers.end()) { return m_trackers.at(type).shouldWrite(step, time); } else { From ff75f581a2193a0d9b11a6db764e6249c2732fc8 Mon Sep 17 00:00:00 2001 From: hayk Date: Mon, 9 Jun 2025 13:47:24 -0400 Subject: [PATCH 728/773] default name for checkpoints -> %s.ckpt --- src/framework/parameters.cpp | 3 ++- src/framework/simulation.cpp | 2 +- src/global/defaults.h | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/framework/parameters.cpp b/src/framework/parameters.cpp index d901ce1ec..c9f612cec 100644 --- a/src/framework/parameters.cpp +++ b/src/framework/parameters.cpp @@ -622,7 +622,8 @@ namespace ntt { toml_data, "checkpoint", "write_path", - defaults::checkpoint::write_path); + fmt::format(defaults::checkpoint::write_path.c_str(), + get("simulation.name").c_str())); set("checkpoint.write_path", checkpoint_write_path); set("checkpoint.read_path", toml::find_or(toml_data, "checkpoint", "read_path", checkpoint_write_path)); diff --git a/src/framework/simulation.cpp b/src/framework/simulation.cpp index b130d10a7..6735eda79 100644 --- a/src/framework/simulation.cpp +++ b/src/framework/simulation.cpp @@ -60,7 +60,7 @@ namespace ntt { raw_params, "checkpoint", "write_path", - "checkpoints"); + fmt::format(defaults::checkpoint::write_path.c_str(), sim_name.c_str())); const path_t checkpoint_read_path = toml::find_or( raw_params, "checkpoint", diff --git a/src/global/defaults.h b/src/global/defaults.h index 8ddbc0ce0..9513493b1 100644 --- a/src/global/defaults.h +++ b/src/global/defaults.h @@ -70,7 +70,7 @@ namespace ntt::defaults { const timestep_t interval = 1000; const int keep = 2; const std::string walltime = "00:00:00"; - const std::string write_path = "checkpoints"; + const std::string write_path = "%s.ckpt"; } // namespace checkpoint namespace diag { From 79a0a6941b90693c9cc30f93013b48e2541ddb99 Mon Sep 17 00:00:00 2001 From: hayk Date: Mon, 9 Jun 2025 13:50:12 -0400 Subject: [PATCH 729/773] default checkpoint.write_path in input --- input.example.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/input.example.toml b/input.example.toml index d3e8e5d81..6bb1537a4 100644 --- a/input.example.toml +++ b/input.example.toml @@ -485,7 +485,7 @@ walltime = "" # Parent directory to write checkpoints to # @type: string - # @default: "checkpoints" + # @default: ".ckpt" # @note: The directory is created if it does not exist write_path = "" # Parent directory to use when resuming from a checkpoint From e98af4dffca65bda8f368f1f80afc9ca965a277f Mon Sep 17 00:00:00 2001 From: hayk Date: Mon, 9 Jun 2025 13:58:43 -0400 Subject: [PATCH 730/773] emojis fixed --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 915a5b358..6415a4274 100644 --- a/README.md +++ b/README.md @@ -14,10 +14,10 @@ Our [detailed documentation](https://entity-toolkit.github.io/) includes everyth * :guitar: Ludwig Böss {[@LudwigBoess](https://github.com/LudwigBoess)} * :eyes: Yangyang Cai {[@StaticObserver](https://github.com/StaticObserver)} -* :person_tipping_hand: Alexander Chernoglazov {[@SChernoglazov](https://github.com/SChernoglazov)} +* :tipping_hand_person: Alexander Chernoglazov {[@SChernoglazov](https://github.com/SChernoglazov)} * :tea: Benjamin Crinquand {[@bcrinquand](https://github.com/bcrinquand)} * :bubble_tea: Alisa Galishnikova {[@alisagk](https://github.com/alisagk)} -* :locomotive: Evgeny Gorbunov {[@Alcauchy](https://github.com/Alcauchy)} +* :steam_locomotive: Evgeny Gorbunov {[@Alcauchy](https://github.com/Alcauchy)} * :coffee: Hayk Hakobyan {[@haykh](https://github.com/haykh)} * :potato: Jens Mahlmann {[@jmahlmann](https://github.com/jmahlmann)} * :dolphin: Sasha Philippov {[@sashaph](https://github.com/sashaph)} From 81cdc01ebfef90780807a5bb41cb82474a7b91f2 Mon Sep 17 00:00:00 2001 From: haykh Date: Thu, 12 Jun 2025 17:33:08 -0700 Subject: [PATCH 731/773] merge 1.2.0rc + pgens separation --- pgens/accretion/accretion.toml | 85 ++++++++++ pgens/accretion/pgen.hpp | 281 +++++++++++++++++++++++++++++++++ pgens/wald/pgen.hpp | 278 ++++++++++++-------------------- pgens/wald/wald.toml | 54 ++----- src/engines/grpic.hpp | 18 +-- 5 files changed, 491 insertions(+), 225 deletions(-) create mode 100644 pgens/accretion/accretion.toml create mode 100644 pgens/accretion/pgen.hpp diff --git a/pgens/accretion/accretion.toml b/pgens/accretion/accretion.toml new file mode 100644 index 000000000..1ec641430 --- /dev/null +++ b/pgens/accretion/accretion.toml @@ -0,0 +1,85 @@ +[simulation] + name = "wald" + engine = "grpic" + runtime = 500.0 + +[grid] + resolution = [256, 256] + extent = [[1.0, 6.0]] + + [grid.metric] + metric = "qkerr_schild" + qsph_r0 = 0.0 + qsph_h = 0.0 + ks_a = 0.95 + + [grid.boundaries] + fields = [["MATCH"]] + particles = [["ABSORB"]] + + [grid.boundaries.absorb] + ds = 1.0 + +[scales] + larmor0 = 0.025 + skindepth0 = 0.5 + +[algorithms] + current_filters = 4 + + [algorithms.gr] + pusher_niter = 10 + pusher_eps = 1e-2 + + [algorithms.timestep] + CFL = 0.5 + correction = 1.0 + + [algorithms.toggles] + deposit = true + fieldsolver = true + +[particles] + ppc0 = 4.0 + use_weights = true + clear_interval = 100 + + [[particles.species]] + label = "e-" + mass = 1.0 + charge = -1.0 + maxnpart = 2e8 + pusher = "Boris" + + [[particles.species]] + label = "e+" + mass = 1.0 + charge = 1.0 + maxnpart = 2e8 + pusher = "Boris" + +[setup] + multiplicity = 1.0 + sigma_max = 1000.0 + temperature = 0.01 + xi_min = [1.5, 0.0] + xi_max = [4.0, 3.14159265] + m_eps = 1.0 + +[output] + format = "hdf5" + + [output.fields] + interval_time = 1.0 + quantities = ["D", "B", "N_1", "N_2", "A"] + + [output.particles] + enable = false + + [output.spectra] + enable = false + +[diagnostics] + interval = 2 + colored_stdout = true + blocking_timers = true diff --git a/pgens/accretion/pgen.hpp b/pgens/accretion/pgen.hpp new file mode 100644 index 000000000..864140dfe --- /dev/null +++ b/pgens/accretion/pgen.hpp @@ -0,0 +1,281 @@ +#ifndef PROBLEM_GENERATOR_H +#define PROBLEM_GENERATOR_H + +#include "enums.h" +#include "global.h" + +#include "arch/kokkos_aliases.h" +#include "arch/traits.h" +#include "utils/numeric.h" + +#include "archetypes/energy_dist.h" +#include "archetypes/particle_injector.h" +#include "archetypes/problem_generator.h" +#include "archetypes/spatial_dist.h" +#include "framework/domain/metadomain.h" + +#include "kernels/particle_moments.hpp" + +namespace user { + using namespace ntt; + + template + struct InitFields { + InitFields(M metric_, real_t m_eps) : metric { metric_ }, m_eps { m_eps } {} + + Inline auto A_3(const coord_t& x_Cd) const -> real_t { + return HALF * (metric.template h_<3, 3>(x_Cd) + + TWO * metric.spin() * metric.template h_<1, 3>(x_Cd) * + metric.beta1(x_Cd)); + } + + Inline auto A_1(const coord_t& x_Cd) const -> real_t { + return HALF * (metric.template h_<1, 3>(x_Cd) + + TWO * metric.spin() * metric.template h_<1, 1>(x_Cd) * + metric.beta1(x_Cd)); + } + + Inline auto A_0(const coord_t& x_Cd) const -> real_t { + real_t g_00 { -metric.alpha(x_Cd) * metric.alpha(x_Cd) + + metric.template h_<1, 1>(x_Cd) * metric.beta1(x_Cd) * + metric.beta1(x_Cd) }; + return HALF * (metric.template h_<1, 3>(x_Cd) * metric.beta1(x_Cd) + + TWO * metric.spin() * g_00); + } + + Inline auto bx1(const coord_t& x_Ph) const -> real_t { // at ( i , j + HALF ) + coord_t xi { ZERO }, x0m { ZERO }, x0p { ZERO }; + metric.template convert(x_Ph, xi); + + x0m[0] = xi[0]; + x0m[1] = xi[1] - HALF * m_eps; + x0p[0] = xi[0]; + x0p[1] = xi[1] + HALF * m_eps; + + real_t inv_sqrt_detH_ijP { ONE / metric.sqrt_det_h({ xi[0], xi[1] }) }; + + if (cmp::AlmostZero(x_Ph[1])) { + return ONE; + } else { + return (A_3(x0p) - A_3(x0m)) * inv_sqrt_detH_ijP / m_eps; + } + } + + Inline auto bx2(const coord_t& x_Ph) const -> real_t { // at ( i + HALF , j ) + coord_t xi { ZERO }, x0m { ZERO }, x0p { ZERO }; + metric.template convert(x_Ph, xi); + + x0m[0] = xi[0] - HALF * m_eps; + x0m[1] = xi[1]; + x0p[0] = xi[0] + HALF * m_eps; + x0p[1] = xi[1]; + + real_t inv_sqrt_detH_ijP { ONE / metric.sqrt_det_h({ xi[0], xi[1] }) }; + if (cmp::AlmostZero(x_Ph[1])) { + return ZERO; + } else { + return -(A_3(x0p) - A_3(x0m)) * inv_sqrt_detH_ijP / m_eps; + } + } + + Inline auto bx3(const coord_t& x_Ph) const -> real_t { + return ZERO; + } + + Inline auto dx1(const coord_t& x_Ph) const -> real_t { + return ZERO; + } + + Inline auto dx2(const coord_t& x_Ph) const -> real_t { + return ZERO; + } + + Inline auto dx3(const coord_t& x_Ph) const -> real_t { + return ZERO; + } + + private: + const M metric; + const real_t m_eps; + }; + + template + struct PointDistribution : public arch::SpatialDistribution { + PointDistribution(const std::vector& xi_min, + const std::vector& xi_max, + const real_t sigma_thr, + const real_t dens_thr, + const SimulationParams& params, + Domain* domain_ptr) + : arch::SpatialDistribution { domain_ptr->mesh.metric } + , metric { domain_ptr->mesh.metric } + , EM { domain_ptr->fields.em } + , density { domain_ptr->fields.buff } + , sigma_thr { sigma_thr } + , inv_n0 { ONE / params.template get("scales.n0") } + , dens_thr { dens_thr } { + std::copy(xi_min.begin(), xi_min.end(), x_min); + std::copy(xi_max.begin(), xi_max.end(), x_max); + + std::vector specs {}; + for (auto& sp : domain_ptr->species) { + if (sp.mass() > 0) { + specs.push_back(sp.index()); + } + } + + Kokkos::deep_copy(density, ZERO); + auto scatter_buff = Kokkos::Experimental::create_scatter_view(density); + // some parameters + auto& mesh = domain_ptr->mesh; + const auto use_weights = params.template get( + "particles.use_weights"); + const auto ni2 = mesh.n_active(in::x2); + + for (const auto& sp : specs) { + auto& prtl_spec = domain_ptr->species[sp - 1]; + // clang-format off + Kokkos::parallel_for( + "ComputeMoments", + prtl_spec.rangeActiveParticles(), + kernel::ParticleMoments_kernel({}, scatter_buff, 0u, + prtl_spec.i1, prtl_spec.i2, prtl_spec.i3, + prtl_spec.dx1, prtl_spec.dx2, prtl_spec.dx3, + prtl_spec.ux1, prtl_spec.ux2, prtl_spec.ux3, + prtl_spec.phi, prtl_spec.weight, prtl_spec.tag, + prtl_spec.mass(), prtl_spec.charge(), + use_weights, + metric, mesh.flds_bc(), + ni2, inv_n0, ZERO)); + // clang-format on + } + Kokkos::Experimental::contribute(density, scatter_buff); + } + + Inline auto sigma_crit(const coord_t& x_Ph) const -> bool { + coord_t xi { ZERO }; + if constexpr (M::Dim == Dim::_2D) { + metric.template convert(x_Ph, xi); + const auto i1 = static_cast(xi[0]) + static_cast(N_GHOSTS); + const auto i2 = static_cast(xi[1]) + static_cast(N_GHOSTS); + const vec_t B_cntrv { EM(i1, i2, em::bx1), + EM(i1, i2, em::bx2), + EM(i1, i2, em::bx3) }; + const vec_t D_cntrv { EM(i1, i2, em::dx1), + EM(i1, i2, em::dx2), + EM(i1, i2, em::dx3) }; + vec_t B_cov { ZERO }; + metric.template transform(xi, B_cntrv, B_cov); + const auto bsqr = + DOT(B_cntrv[0], B_cntrv[1], B_cntrv[2], B_cov[0], B_cov[1], B_cov[2]); + const auto dens = density(i1, i2, 0); + return (bsqr > sigma_thr * dens) || (dens < dens_thr); + } + return false; + } + + Inline auto operator()(const coord_t& x_Ph) const -> real_t override { + auto fill = true; + for (auto d = 0u; d < M::Dim; ++d) { + fill &= x_Ph[d] > x_min[d] and x_Ph[d] < x_max[d] and sigma_crit(x_Ph); + } + return fill ? ONE : ZERO; + } + + private: + tuple_t x_min; + tuple_t x_max; + const real_t sigma_thr; + const real_t dens_thr; + const real_t inv_n0; + Domain* domain_ptr; + ndfield_t density; + ndfield_t EM; + const M metric; + }; + + template + struct PGen : public arch::ProblemGenerator { + // compatibility traits for the problem generator + static constexpr auto engines { traits::compatible_with::value }; + static constexpr auto metrics { + traits::compatible_with::value + }; + static constexpr auto dimensions { traits::compatible_with::value }; + + // for easy access to variables in the child class + using arch::ProblemGenerator::D; + using arch::ProblemGenerator::C; + using arch::ProblemGenerator::params; + + const std::vector xi_min; + const std::vector xi_max; + const real_t sigma0, sigma_max, multiplicity, nGJ, temperature, m_eps; + + InitFields init_flds; + const Metadomain* metadomain; + + inline PGen(SimulationParams& p, const Metadomain& m) + : arch::ProblemGenerator(p) + , xi_min { p.template get>("setup.xi_min") } + , xi_max { p.template get>("setup.xi_max") } + , sigma_max { p.template get("setup.sigma_max") } + , sigma0 { p.template get("scales.sigma0") } + , multiplicity { p.template get("setup.multiplicity") } + , nGJ { p.template get("scales.B0") * + SQR(p.template get("scales.skindepth0")) } + , temperature { p.template get("setup.temperature") } + , m_eps { p.template get("setup.m_eps") } + , init_flds { m.mesh().metric, m_eps } + , metadomain { &m } {} + + inline void InitPrtls(Domain& local_domain) { + const auto energy_dist = arch::Maxwellian(local_domain.mesh.metric, + local_domain.random_pool, + temperature); + const auto spatial_dist = PointDistribution(xi_min, + xi_max, + sigma_max / sigma0, + multiplicity * nGJ, + params, + &local_domain); + + const auto injector = + arch::NonUniformInjector( + energy_dist, + spatial_dist, + { 1, 2 }); + arch::InjectNonUniform(params, + local_domain, + injector, + 1.0, + true); + } + + void CustomPostStep(std::size_t, long double time, Domain& local_domain) { + const auto energy_dist = arch::Maxwellian(local_domain.mesh.metric, + local_domain.random_pool, + temperature); + const auto spatial_dist = PointDistribution(xi_min, + xi_max, + sigma_max / sigma0, + multiplicity * nGJ, + params, + &local_domain); + + const auto injector = + arch::NonUniformInjector( + energy_dist, + spatial_dist, + { 1, 2 }); + arch::InjectNonUniform(params, + local_domain, + injector, + 1.0, + true); + } + }; + +} // namespace user + +#endif diff --git a/pgens/wald/pgen.hpp b/pgens/wald/pgen.hpp index 04a80de57..b2c2aeb0c 100644 --- a/pgens/wald/pgen.hpp +++ b/pgens/wald/pgen.hpp @@ -6,22 +6,25 @@ #include "arch/kokkos_aliases.h" #include "arch/traits.h" +#include "utils/comparators.h" +#include "utils/formatting.h" +#include "utils/log.h" #include "utils/numeric.h" #include "archetypes/energy_dist.h" #include "archetypes/particle_injector.h" #include "archetypes/problem_generator.h" -#include "archetypes/spatial_dist.h" +#include "framework/domain/domain.h" #include "framework/domain/metadomain.h" -#include "kernels/particle_moments.hpp" +#include namespace user { using namespace ntt; template struct InitFields { - InitFields(M metric_, real_t m_eps) : metric { metric_ }, m_eps { m_eps } {} + InitFields(M metric_) : metric { metric_ } {} Inline auto A_3(const coord_t& x_Cd) const -> real_t { return HALF * (metric.template h_<3, 3>(x_Cd) + @@ -43,157 +46,139 @@ namespace user { TWO * metric.spin() * g_00); } - Inline auto bx1(const coord_t& x_Ph) const - -> real_t { // at ( i , j + HALF ) + Inline auto bx1(const coord_t& x_Ph) const -> real_t { // at ( i , j + HALF ) coord_t xi { ZERO }, x0m { ZERO }, x0p { ZERO }; metric.template convert(x_Ph, xi); x0m[0] = xi[0]; - x0m[1] = xi[1] - HALF * m_eps; + x0m[1] = xi[1] - HALF; x0p[0] = xi[0]; - x0p[1] = xi[1] + HALF * m_eps; + x0p[1] = xi[1] + HALF; real_t inv_sqrt_detH_ijP { ONE / metric.sqrt_det_h({ xi[0], xi[1] }) }; if (cmp::AlmostZero(x_Ph[1])) { return ONE; } else { - return (A_3(x0p) - A_3(x0m)) * inv_sqrt_detH_ijP / m_eps; + return (A_3(x0p) - A_3(x0m)) * inv_sqrt_detH_ijP; } } - Inline auto bx2(const coord_t& x_Ph) const - -> real_t { // at ( i + HALF , j ) + Inline auto bx2(const coord_t& x_Ph) const -> real_t { // at ( i + HALF , j ) coord_t xi { ZERO }, x0m { ZERO }, x0p { ZERO }; metric.template convert(x_Ph, xi); - x0m[0] = xi[0] - HALF * m_eps; + x0m[0] = xi[0] - HALF; x0m[1] = xi[1]; - x0p[0] = xi[0] + HALF * m_eps; + x0p[0] = xi[0] + HALF; x0p[1] = xi[1]; real_t inv_sqrt_detH_ijP { ONE / metric.sqrt_det_h({ xi[0], xi[1] }) }; if (cmp::AlmostZero(x_Ph[1])) { return ZERO; } else { - return -(A_3(x0p) - A_3(x0m)) * inv_sqrt_detH_ijP / m_eps; + return -(A_3(x0p) - A_3(x0m)) * inv_sqrt_detH_ijP; } } - Inline auto bx3(const coord_t& x_Ph) const -> real_t { - return ZERO; - } + Inline auto bx3( + const coord_t& x_Ph) const -> real_t { // at ( i + HALF , j + HALF ) + coord_t xi { ZERO }, x0m { ZERO }, x0p { ZERO }; + metric.template convert(x_Ph, xi); - Inline auto dx1(const coord_t& x_Ph) const -> real_t { - return ZERO; - } + x0m[0] = xi[0]; + x0m[1] = xi[1] - HALF; + x0p[0] = xi[0]; + x0p[1] = xi[1] + HALF; - Inline auto dx2(const coord_t& x_Ph) const -> real_t { - return ZERO; + real_t inv_sqrt_detH_iPjP { ONE / metric.sqrt_det_h({ xi[0], xi[1] }) }; + return -(A_1(x0p) - A_1(x0m)) * inv_sqrt_detH_iPjP; } - Inline auto dx3(const coord_t& x_Ph) const -> real_t { - return ZERO; - } + Inline auto dx1(const coord_t& x_Ph) const -> real_t { // at ( i + HALF , j ) + coord_t xi { ZERO }, x0m { ZERO }, x0p { ZERO }; + metric.template convert(x_Ph, xi); - private: - const M metric; - const real_t m_eps; - }; + real_t alpha_iPj { metric.alpha({ xi[0], xi[1] }) }; + real_t inv_sqrt_detH_ij { ONE / metric.sqrt_det_h({ xi[0] - HALF, xi[1] }) }; + real_t sqrt_detH_ij { metric.sqrt_det_h({ xi[0] - HALF, xi[1] }) }; + real_t beta_ij { metric.beta1({ xi[0] - HALF, xi[1] }) }; + real_t alpha_ij { metric.alpha({ xi[0] - HALF, xi[1] }) }; - template - struct PointDistribution : public arch::SpatialDistribution { - PointDistribution(const std::vector& xi_min, - const std::vector& xi_max, - const real_t sigma_thr, - const real_t dens_thr, - const SimulationParams& params, - Domain* domain_ptr) - : arch::SpatialDistribution { domain_ptr->mesh.metric } - , metric { domain_ptr->mesh.metric } - , EM { domain_ptr->fields.em } - , density { domain_ptr->fields.buff } - , sigma_thr { sigma_thr } - , inv_n0 { ONE / params.template get("scales.n0") } - , dens_thr { dens_thr } { - std::copy(xi_min.begin(), xi_min.end(), x_min); - std::copy(xi_max.begin(), xi_max.end(), x_max); - - std::vector specs {}; - for (auto& sp : domain_ptr->species) { - if (sp.mass() > 0) { - specs.push_back(sp.index()); - } - } + // D1 at ( i + HALF , j ) + x0m[0] = xi[0] - HALF; + x0m[1] = xi[1]; + x0p[0] = xi[0] + HALF; + x0p[1] = xi[1]; + real_t E1d { (A_0(x0p) - A_0(x0m)) }; + real_t D1d { E1d / alpha_iPj }; - Kokkos::deep_copy(density, ZERO); - auto scatter_buff = Kokkos::Experimental::create_scatter_view(density); - // some parameters - auto& mesh = domain_ptr->mesh; - const auto use_weights = params.template get( - "particles.use_weights"); - const auto ni2 = mesh.n_active(in::x2); - - for (const auto& sp : specs) { - auto& prtl_spec = domain_ptr->species[sp - 1]; - // clang-format off - Kokkos::parallel_for( - "ComputeMoments", - prtl_spec.rangeActiveParticles(), - kernel::ParticleMoments_kernel({}, scatter_buff, 0u, - prtl_spec.i1, prtl_spec.i2, prtl_spec.i3, - prtl_spec.dx1, prtl_spec.dx2, prtl_spec.dx3, - prtl_spec.ux1, prtl_spec.ux2, prtl_spec.ux3, - prtl_spec.phi, prtl_spec.weight, prtl_spec.tag, - prtl_spec.mass(), prtl_spec.charge(), - use_weights, - metric, mesh.flds_bc(), - ni2, inv_n0, ZERO)); - // clang-format on - } - Kokkos::Experimental::contribute(density, scatter_buff); + // D3 at ( i , j ) + x0m[0] = xi[0] - HALF - HALF; + x0m[1] = xi[1]; + x0p[0] = xi[0] - HALF + HALF; + x0p[1] = xi[1]; + real_t D3d { (A_3(x0p) - A_3(x0m)) * beta_ij / alpha_ij }; + + real_t D1u { metric.template h<1, 1>({ xi[0], xi[1] }) * D1d + + metric.template h<1, 3>({ xi[0], xi[1] }) * D3d }; + + return D1u; } - Inline auto sigma_crit(const coord_t& x_Ph) const -> bool { - coord_t xi { ZERO }; - if constexpr (M::Dim == Dim::_2D) { - metric.template convert(x_Ph, xi); - const auto i1 = static_cast(xi[0]) + static_cast(N_GHOSTS); - const auto i2 = static_cast(xi[1]) + static_cast(N_GHOSTS); - const vec_t B_cntrv { EM(i1, i2, em::bx1), - EM(i1, i2, em::bx2), - EM(i1, i2, em::bx3) }; - const vec_t D_cntrv { EM(i1, i2, em::dx1), - EM(i1, i2, em::dx2), - EM(i1, i2, em::dx3) }; - vec_t B_cov { ZERO }; - metric.template transform(xi, B_cntrv, B_cov); - const auto bsqr = - DOT(B_cntrv[0], B_cntrv[1], B_cntrv[2], B_cov[0], B_cov[1], B_cov[2]); - const auto dens = density(i1, i2, 0); - return (bsqr > sigma_thr * dens) || (dens < dens_thr); - } - return false; + Inline auto dx2(const coord_t& x_Ph) const -> real_t { // at ( i , j + HALF ) + coord_t xi { ZERO }, x0m { ZERO }, x0p { ZERO }; + metric.template convert(x_Ph, xi); + x0m[0] = xi[0]; + x0m[1] = xi[1] - HALF; + x0p[0] = xi[0]; + x0p[1] = xi[1] + HALF; + real_t inv_sqrt_detH_ijP { ONE / metric.sqrt_det_h({ xi[0], xi[1] }) }; + real_t sqrt_detH_ijP { metric.sqrt_det_h({ xi[0], xi[1] }) }; + real_t alpha_ijP { metric.alpha({ xi[0], xi[1] }) }; + real_t beta_ijP { metric.beta1({ xi[0], xi[1] }) }; + + real_t E2d { (A_0(x0p) - A_0(x0m)) }; + real_t D2d { E2d / alpha_ijP - (A_1(x0p) - A_1(x0m)) * beta_ijP / alpha_ijP }; + real_t D2u { metric.template h<2, 2>({ xi[0], xi[1] }) * D2d }; + + return D2u; } - Inline auto operator()(const coord_t& x_Ph) const -> real_t override { - auto fill = true; - for (auto d = 0u; d < M::Dim; ++d) { - fill &= x_Ph[d] > x_min[d] and x_Ph[d] < x_max[d] and sigma_crit(x_Ph); + Inline auto dx3(const coord_t& x_Ph) const -> real_t { // at ( i , j ) + coord_t xi { ZERO }, x0m { ZERO }, x0p { ZERO }; + metric.template convert(x_Ph, xi); + real_t inv_sqrt_detH_ij { ONE / metric.sqrt_det_h({ xi[0], xi[1] }) }; + real_t sqrt_detH_ij { metric.sqrt_det_h({ xi[0], xi[1] }) }; + real_t beta_ij { metric.beta1({ xi[0], xi[1] }) }; + real_t alpha_ij { metric.alpha({ xi[0], xi[1] }) }; + real_t alpha_iPj { metric.alpha({ xi[0] + HALF, xi[1] }) }; + + // D3 at ( i , j ) + x0m[0] = xi[0] - HALF; + x0m[1] = xi[1]; + x0p[0] = xi[0] + HALF; + x0p[1] = xi[1]; + real_t D3d { (A_3(x0p) - A_3(x0m)) * beta_ij / alpha_ij }; + + // D1 at ( i + HALF , j ) + x0m[0] = xi[0] + HALF - HALF; + x0m[1] = xi[1]; + x0p[0] = xi[0] + HALF + HALF; + x0p[1] = xi[1]; + real_t E1d { (A_0(x0p) - A_0(x0m)) }; + real_t D1d { E1d / alpha_iPj }; + + if (cmp::AlmostZero(x_Ph[1])) { + return metric.template h<1, 3>({ xi[0], xi[1] }) * D1d; + } else { + return metric.template h<3, 3>({ xi[0], xi[1] }) * D3d + + metric.template h<1, 3>({ xi[0], xi[1] }) * D1d; } - return fill ? ONE : ZERO; } private: - tuple_t x_min; - tuple_t x_max; - const real_t sigma_thr; - const real_t dens_thr; - const real_t inv_n0; - Domain* domain_ptr; - ndfield_t density; - ndfield_t EM; - const M metric; + const M metric; }; template @@ -210,72 +195,13 @@ namespace user { using arch::ProblemGenerator::C; using arch::ProblemGenerator::params; - const std::vector xi_min; - const std::vector xi_max; - const real_t sigma0, sigma_max, multiplicity, nGJ, temperature, m_eps; - InitFields init_flds; - const Metadomain* metadomain; - - inline PGen(SimulationParams& p, const Metadomain& m) - : arch::ProblemGenerator(p) - , xi_min { p.template get>("setup.xi_min") } - , xi_max { p.template get>("setup.xi_max") } - , sigma_max { p.template get("setup.sigma_max") } - , sigma0 { p.template get("scales.sigma0") } - , multiplicity { p.template get("setup.multiplicity") } - , nGJ { p.template get("scales.B0") * - SQR(p.template get("scales.skindepth0")) } - , temperature { p.template get("setup.temperature") } - , m_eps { p.template get("setup.m_eps") } - , init_flds { m.mesh().metric, m_eps } - , metadomain { &m } {} - - inline void InitPrtls(Domain& local_domain) { - const auto energy_dist = arch::Maxwellian(local_domain.mesh.metric, - local_domain.random_pool, - temperature); - const auto spatial_dist = PointDistribution(xi_min, - xi_max, - sigma_max / sigma0, - multiplicity * nGJ, - params, - &local_domain); - - const auto injector = - arch::NonUniformInjector( - energy_dist, - spatial_dist, - { 1, 2 }); - arch::InjectNonUniform(params, - local_domain, - injector, - 1.0, - true); - } + const Metadomain& global_domain; - void CustomPostStep(std::size_t, long double time, Domain& local_domain) { - const auto energy_dist = arch::Maxwellian(local_domain.mesh.metric, - local_domain.random_pool, - temperature); - const auto spatial_dist = PointDistribution(xi_min, - xi_max, - sigma_max / sigma0, - multiplicity * nGJ, - params, - &local_domain); - - const auto injector = - arch::NonUniformInjector( - energy_dist, - spatial_dist, - { 1, 2 }); - arch::InjectNonUniform(params, - local_domain, - injector, - 1.0, - true); - } + inline PGen(const SimulationParams& p, const Metadomain& m) + : arch::ProblemGenerator { p } + , global_domain { m } + , init_flds { m.mesh().metric } {} }; } // namespace user diff --git a/pgens/wald/wald.toml b/pgens/wald/wald.toml index 1ec641430..1104f7a08 100644 --- a/pgens/wald/wald.toml +++ b/pgens/wald/wald.toml @@ -1,14 +1,14 @@ [simulation] - name = "wald" + name = "vacuum" engine = "grpic" - runtime = 500.0 + runtime = 100.0 [grid] - resolution = [256, 256] - extent = [[1.0, 6.0]] + resolution = [128, 128] + extent = [[1.0, 10.0]] [grid.metric] - metric = "qkerr_schild" + metric = "kerr_schild" qsph_r0 = 0.0 qsph_h = 0.0 ks_a = 0.95 @@ -21,57 +21,31 @@ ds = 1.0 [scales] - larmor0 = 0.025 - skindepth0 = 0.5 + larmor0 = 0.0025 + skindepth0 = 0.05 [algorithms] - current_filters = 4 - - [algorithms.gr] - pusher_niter = 10 - pusher_eps = 1e-2 + current_filters = 0 [algorithms.timestep] - CFL = 0.5 - correction = 1.0 + CFL = 0.5 [algorithms.toggles] - deposit = true + deposit = false fieldsolver = true [particles] - ppc0 = 4.0 - use_weights = true - clear_interval = 100 - - [[particles.species]] - label = "e-" - mass = 1.0 - charge = -1.0 - maxnpart = 2e8 - pusher = "Boris" - - [[particles.species]] - label = "e+" - mass = 1.0 - charge = 1.0 - maxnpart = 2e8 - pusher = "Boris" + ppc0 = 2.0 [setup] - multiplicity = 1.0 - sigma_max = 1000.0 - temperature = 0.01 - xi_min = [1.5, 0.0] - xi_max = [4.0, 3.14159265] - m_eps = 1.0 [output] - format = "hdf5" + format = "hdf5" + separate_files = false [output.fields] interval_time = 1.0 - quantities = ["D", "B", "N_1", "N_2", "A"] + quantities = ["D", "H", "B", "A"] [output.particles] enable = false diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index 04197d12b..6abbfd337 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -715,17 +715,17 @@ namespace ntt { "OpenBCFields", range, kernel::bc::HorizonBoundaries_kernel(domain.fields.em, - i1_min, - tags, - nfilter)); + i1_min, + tags, + nfilter)); Kokkos::parallel_for( "OpenBCFields", range, kernel::bc::HorizonBoundaries_kernel(domain.fields.em0, - i1_min, - tags, - nfilter)); - } + i1_min, + tags, + nfilter)); + } } void AxisFieldsIn(dir::direction_t direction, @@ -1099,7 +1099,7 @@ namespace ntt { "algorithms.gr.pusher_niter"); // clang-format off if (species.pusher() == PrtlPusher::PHOTON) { - auto range_policy = Kokkos::RangePolicy( + auto range_policy = Kokkos::RangePolicy( 0, species.npart()); @@ -1124,7 +1124,7 @@ namespace ntt { domain.mesh.prtl_bc() )); } else if (species.pusher() == PrtlPusher::BORIS) { - auto range_policy = Kokkos::RangePolicy( + auto range_policy = Kokkos::RangePolicy( 0, species.npart()); Kokkos::parallel_for( From f667d72ed2e5cf7ff33234f4263764fe590af073 Mon Sep 17 00:00:00 2001 From: haykh Date: Thu, 12 Jun 2025 20:38:26 -0700 Subject: [PATCH 732/773] ds param fix --- src/engines/grpic.hpp | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index 6abbfd337..6a563eb7c 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -595,13 +595,24 @@ namespace ntt { /** * match boundaries */ - const auto ds = m_params.template get("grid.boundaries.match.ds"); + // const auto ds = m_params.template get("grid.boundaries.match.ds"); + const auto ds_array = m_params.template get>( + "grid.boundaries.match.ds"); const auto dim = direction.get_dim(); real_t xg_min, xg_max, xg_edge; - xg_max = m_metadomain.mesh().extent(dim).second; - xg_min = xg_max - ds; - xg_edge = xg_max; - + auto sign = direction.get_sign(); + real_t ds; + if (sign > 0) { // + direction + ds = ds_array[(short)dim].second; + xg_max = m_metadomain.mesh().extent(dim).second; + xg_min = xg_max - ds; + xg_edge = xg_max; + } else { // - direction + ds = ds_array[(short)dim].first; + xg_min = m_metadomain.mesh().extent(dim).first; + xg_max = xg_min + ds; + xg_edge = xg_min; + } boundaries_t box; boundaries_t incl_ghosts; for (unsigned short d { 0 }; d < M::Dim; ++d) { @@ -654,9 +665,13 @@ namespace ntt { /** * match boundaries */ - const auto ds = m_params.template get("grid.boundaries.match.ds"); + // @TODO: also in MatchFieldsIn (need a better way) + const auto ds_array = m_params.template get>( + "grid.boundaries.match.ds"); const auto dim = in::x1; real_t xg_min, xg_max, xg_edge; + real_t ds; + ds = ds_array[(short)dim].second; xg_max = m_metadomain.mesh().extent(dim).second; xg_min = xg_max - ds; xg_edge = xg_max; From dcfea6206b05a4cd979900546ffbc8899762e5cc Mon Sep 17 00:00:00 2001 From: haykh Date: Sat, 14 Jun 2025 10:54:01 -0700 Subject: [PATCH 733/773] minor refactor + BCs aligned with sr --- src/engines/grpic.hpp | 241 ++++++++++++++++---------------- src/global/global.h | 4 + src/kernels/fields_bcs.hpp | 272 +++++++++++++++++++------------------ 3 files changed, 268 insertions(+), 249 deletions(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index 6a563eb7c..345c91d5d 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -16,13 +16,11 @@ #include "global.h" #include "arch/kokkos_aliases.h" -#include "arch/traits.h" #include "utils/log.h" #include "utils/numeric.h" #include "utils/timer.h" #include "utils/toml.h" -#include "archetypes/particle_injector.h" #include "framework/domain/domain.h" #include "framework/parameters.h" @@ -33,7 +31,6 @@ #include "kernels/digital_filter.hpp" #include "kernels/faraday_gr.hpp" #include "kernels/fields_bcs.hpp" -#include "kernels/particle_moments.hpp" #include "kernels/particle_pusher_gr.hpp" #include "pgen.hpp" @@ -64,7 +61,8 @@ namespace ntt { }; enum class gr_bc { main, - aux + aux, + curr }; template @@ -385,7 +383,7 @@ namespace ntt { timers.stop("Communications"); timers.start("FieldBoundaries"); - CurrentsBoundaryConditions(dom); + FieldBoundaries(dom, BC::J, gr_bc::curr); timers.stop("FieldBoundaries"); timers.start("CurrentFiltering"); @@ -563,27 +561,25 @@ namespace ntt { if (g == gr_bc::main) { for (auto& direction : dir::Directions::orth) { if (m_metadomain.mesh().flds_bc_in(direction) == FldsBC::MATCH) { - MatchFieldsIn(direction, domain, tags); - } else if (m_metadomain.mesh().flds_bc_in(direction) == FldsBC::AXIS) { - if (domain.mesh.flds_bc_in(direction) == FldsBC::AXIS) { - AxisFieldsIn(direction, domain, tags); - } + MatchFieldsIn(direction, domain, tags, g); + } else if (domain.mesh.flds_bc_in(direction) == FldsBC::AXIS) { + AxisFieldsIn(direction, domain, tags); } else if (m_metadomain.mesh().flds_bc_in(direction) == FldsBC::CUSTOM) { - if (domain.mesh.flds_bc_in(direction) == FldsBC::CUSTOM) { - CustomFieldsIn(direction, domain, tags, g); - } - } else if (m_metadomain.mesh().flds_bc_in(direction) == FldsBC::HORIZON) { - if (domain.mesh.flds_bc_in(direction) == FldsBC::HORIZON) { - HorizonFieldsIn(direction, domain, tags, g); - } + CustomFieldsIn(direction, domain, tags, g); + } else if (domain.mesh.flds_bc_in(direction) == FldsBC::HORIZON) { + HorizonFieldsIn(direction, domain, tags, g); } } // loop over directions } else if (g == gr_bc::aux) { for (auto& direction : dir::Directions::orth) { - if (m_metadomain.mesh().flds_bc_in(direction) == FldsBC::HORIZON) { - if (domain.mesh.flds_bc_in(direction) == FldsBC::HORIZON) { - HorizonFieldsIn(direction, domain, tags, g); - } + if (domain.mesh.flds_bc_in(direction) == FldsBC::HORIZON) { + HorizonFieldsIn(direction, domain, tags, g); + } + } + } else if (g == gr_bc::curr) { + for (auto& direction : dir::Directions::orth) { + if (domain.mesh.prtl_bc_in(direction) == PrtlBC::ABSORB) { + MatchFieldsIn(direction, domain, tags, g); } } } @@ -591,17 +587,22 @@ namespace ntt { void MatchFieldsIn(dir::direction_t direction, domain_t& domain, - BCTags tags) { + BCTags tags, + const gr_bc& g) { /** * match boundaries */ - // const auto ds = m_params.template get("grid.boundaries.match.ds"); const auto ds_array = m_params.template get>( "grid.boundaries.match.ds"); const auto dim = direction.get_dim(); real_t xg_min, xg_max, xg_edge; auto sign = direction.get_sign(); - real_t ds; + + raise::ErrorIf(((dim != in::x1) or (sign > 0)) and (g == gr_bc::curr), + "Absorption of currents only possible in +x1 (+r)", + HERE); + + real_t ds; if (sign > 0) { // + direction ds = ds_array[(short)dim].second; xg_max = m_metadomain.mesh().extent(dim).second; @@ -636,76 +637,88 @@ namespace ntt { range_max[d] = intersect_range[d].second; } if (dim == in::x1) { - Kokkos::parallel_for( - "MatchBoundaries", - CreateRangePolicy(range_min, range_max), - kernel::bc::MatchBoundaries_kernel( - domain.fields.em, - m_pgen.init_flds, - domain.mesh.metric, - xg_edge, - ds, - tags)); - Kokkos::parallel_for( - "MatchBoundaries", - CreateRangePolicy(range_min, range_max), - kernel::bc::MatchBoundaries_kernel( - domain.fields.em0, - m_pgen.init_flds, - domain.mesh.metric, - xg_edge, - ds, - tags)); + if (g != gr_bc::curr) { + Kokkos::parallel_for( + "MatchBoundaries", + CreateRangePolicy(range_min, range_max), + kernel::bc::MatchBoundaries_kernel( + domain.fields.em, + m_pgen.init_flds, + domain.mesh.metric, + xg_edge, + ds, + tags)); + Kokkos::parallel_for( + "MatchBoundaries", + CreateRangePolicy(range_min, range_max), + kernel::bc::MatchBoundaries_kernel( + domain.fields.em0, + m_pgen.init_flds, + domain.mesh.metric, + xg_edge, + ds, + tags)); + } else { + Kokkos::parallel_for( + "AbsorbCurrents", + CreateRangePolicy(range_min, range_max), + kernel::bc::gr::AbsorbCurrents_kernel(domain.fields.cur0, + domain.mesh.metric, + xg_edge, + ds)); + } } else { raise::Error("Invalid dimension", HERE); } } - void CurrentsBoundaryConditions(domain_t& domain) { - /** - * match boundaries - */ - // @TODO: also in MatchFieldsIn (need a better way) - const auto ds_array = m_params.template get>( - "grid.boundaries.match.ds"); - const auto dim = in::x1; - real_t xg_min, xg_max, xg_edge; - real_t ds; - ds = ds_array[(short)dim].second; - xg_max = m_metadomain.mesh().extent(dim).second; - xg_min = xg_max - ds; - xg_edge = xg_max; - - boundaries_t box; - boundaries_t incl_ghosts; - for (unsigned short d { 0 }; d < M::Dim; ++d) { - if (d == static_cast(dim)) { - box.push_back({ xg_min, xg_max }); - incl_ghosts.push_back({ false, true }); - } else { - box.push_back(Range::All); - incl_ghosts.push_back({ true, true }); - } - } - if (not domain.mesh.Intersects(box)) { - return; - } - const auto intersect_range = domain.mesh.ExtentToRange(box, incl_ghosts); - tuple_t range_min { 0 }; - tuple_t range_max { 0 }; - - for (unsigned short d { 0 }; d < M::Dim; ++d) { - range_min[d] = intersect_range[d].first; - range_max[d] = intersect_range[d].second; - } - Kokkos::parallel_for( - "AbsorbCurrentsGR", - CreateRangePolicy(range_min, range_max), - kernel::bc::AbsorbCurrentsGR_kernel(domain.fields.cur0, - domain.mesh.metric, - xg_edge, - ds)); - } + // void AbsorbCurrentsIn(dir::direction_t direction, + // domain_t& domain, + // BCTags tags) { + // /** + // * absorbing currents at the boundaries + // */ + // // @TODO: also in MatchFieldsIn (need a better way) + // const auto ds_array = m_params.template get>( + // "grid.boundaries.match.ds"); + // const auto dim = in::x1; + // real_t xg_min, xg_max, xg_edge; + // real_t ds; + // ds = ds_array[(short)dim].second; + // xg_max = m_metadomain.mesh().extent(dim).second; + // xg_min = xg_max - ds; + // xg_edge = xg_max; + // + // boundaries_t box; + // boundaries_t incl_ghosts; + // for (unsigned short d { 0 }; d < M::Dim; ++d) { + // if (d == static_cast(dim)) { + // box.push_back({ xg_min, xg_max }); + // incl_ghosts.push_back({ false, true }); + // } else { + // box.push_back(Range::All); + // incl_ghosts.push_back({ true, true }); + // } + // } + // if (not domain.mesh.Intersects(box)) { + // return; + // } + // const auto intersect_range = domain.mesh.ExtentToRange(box, incl_ghosts); + // tuple_t range_min { 0 }; + // tuple_t range_max { 0 }; + // + // for (unsigned short d { 0 }; d < M::Dim; ++d) { + // range_min[d] = intersect_range[d].first; + // range_max[d] = intersect_range[d].second; + // } + // Kokkos::parallel_for( + // "AbsorbCurrentsGR", + // CreateRangePolicy(range_min, range_max), + // kernel::bc::AbsorbCurrentsGR_kernel(domain.fields.cur0, + // domain.mesh.metric, + // xg_edge, + // ds)); + // } void HorizonFieldsIn(dir::direction_t direction, domain_t& domain, @@ -729,17 +742,17 @@ namespace ntt { Kokkos::parallel_for( "OpenBCFields", range, - kernel::bc::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::HorizonBoundaries_kernel(domain.fields.em0, - i1_min, - tags, - nfilter)); + kernel::bc::gr::HorizonBoundaries_kernel(domain.fields.em0, + i1_min, + tags, + nfilter)); } } @@ -757,34 +770,32 @@ namespace ntt { HERE); const auto i2_min = domain.mesh.i_min(in::x2); const auto i2_max = domain.mesh.i_max(in::x2); - auto range = CreateRangePolicy({ domain.mesh.i_min(in::x1) - 1 }, - { domain.mesh.i_max(in::x1) }); if (direction.get_sign() < 0) { Kokkos::parallel_for( "AxisBCFields", - range, - kernel::bc::AxisBoundariesGR_kernel(domain.fields.em, - i2_min, - tags)); + domain.mesh.n_all(in::x1), + kernel::bc::AxisBoundaries_kernel(domain.fields.em, + i2_min, + tags)); Kokkos::parallel_for( "AxisBCFields", - range, - kernel::bc::AxisBoundariesGR_kernel(domain.fields.em0, - i2_min, - tags)); + domain.mesh.n_all(in::x1), + kernel::bc::AxisBoundaries_kernel(domain.fields.em0, + i2_min, + tags)); } else { Kokkos::parallel_for( "AxisBCFields", - range, - kernel::bc::AxisBoundariesGR_kernel(domain.fields.em, - i2_max, - tags)); + domain.mesh.n_all(in::x1), + kernel::bc::AxisBoundaries_kernel(domain.fields.em, + i2_max, + tags)); Kokkos::parallel_for( "AxisBCFields", - range, - kernel::bc::AxisBoundariesGR_kernel(domain.fields.em0, - i2_max, - tags)); + domain.mesh.n_all(in::x1), + kernel::bc::AxisBoundaries_kernel(domain.fields.em0, + i2_max, + tags)); } } diff --git a/src/global/global.h b/src/global/global.h index 16cb4fc8a..adffcf6e9 100644 --- a/src/global/global.h +++ b/src/global/global.h @@ -291,10 +291,14 @@ namespace BC { Hx1 = 1 << 3, Hx2 = 1 << 4, Hx3 = 1 << 5, + Jx1 = 1 << 6, + Jx2 = 1 << 7, + Jx3 = 1 << 8, B = Bx1 | Bx2 | Bx3, E = Ex1 | Ex2 | Ex3, D = Dx1 | Dx2 | Dx3, H = Hx1 | Hx2 | Hx3, + J = Jx1 | Jx2 | Jx3, }; } // namespace BC diff --git a/src/kernels/fields_bcs.hpp b/src/kernels/fields_bcs.hpp index 3a35e4d8b..40dd3d13d 100644 --- a/src/kernels/fields_bcs.hpp +++ b/src/kernels/fields_bcs.hpp @@ -16,6 +16,7 @@ #ifndef KERNELS_FIELDS_BCS_HPP #define KERNELS_FIELDS_BCS_HPP +#include "enums.h" #include "global.h" #include "arch/kokkos_aliases.h" @@ -844,57 +845,57 @@ namespace kernel::bc { } }; - /* - * @tparam I: Field Setter class - * @tparam M: Metric - * @tparam P: Positive/Negative direction - * @tparam O: Orientation - * - * @brief Applies enforced boundary conditions (fixed value) - */ - template - struct AxisBoundariesGR_kernel { - ndfield_t Fld; - const std::size_t i_edge; - const bool setE, setB; - - AxisBoundariesGR_kernel(ndfield_t Fld, std::size_t i_edge, BCTags tags) - : Fld { Fld } // , i_edge { i_edge } - , i_edge { P ? (i_edge + 1) : i_edge } - , setE { tags & BC::Ex1 or tags & BC::Ex2 or tags & BC::Ex3 } - , setB { tags & BC::Bx1 or tags & BC::Bx2 or tags & BC::Bx3 } {} - - Inline void operator()(index_t i1) const { - if constexpr (D == Dim::_2D) { - // if (setB) { - // Fld(i1, i_edge, em::bx2) = ZERO; - // } - if constexpr (not P) { - if (setE) { - Fld(i1, i_edge - 1, em::ex2) = -Fld(i1, i_edge, em::ex2); - Fld(i1, i_edge, em::ex3) = ZERO; - } - if (setB) { - Fld(i1, i_edge - 1, em::bx1) = Fld(i1, i_edge, em::bx1); - Fld(i1, i_edge, em::bx2) = ZERO; - Fld(i1, i_edge - 1, em::bx3) = Fld(i1, i_edge, em::bx3); - } - } else { - if (setE) { - Fld(i1, i_edge + 1, em::ex2) = -Fld(i1, i_edge, em::ex2); - Fld(i1, i_edge + 1, em::ex3) = ZERO; - } - if (setB) { - Fld(i1, i_edge + 1, em::bx1) = Fld(i1, i_edge, em::bx1); - Fld(i1, i_edge + 1, em::bx2) = ZERO; - Fld(i1, i_edge + 1, em::bx3) = Fld(i1, i_edge, em::bx3); - } - } - } else { - raise::KernelError(HERE, "AxisBoundariesGR_kernel: D != 2"); - } - } - }; + // /* + // * @tparam I: Field Setter class + // * @tparam M: Metric + // * @tparam P: Positive/Negative direction + // * @tparam O: Orientation + // * + // * @brief Applies enforced boundary conditions (fixed value) + // */ + // template + // struct AxisBoundariesGR_kernel { + // ndfield_t Fld; + // const std::size_t i_edge; + // const bool setE, setB; + // + // AxisBoundariesGR_kernel(ndfield_t Fld, std::size_t i_edge, BCTags tags) + // : Fld { Fld } // , i_edge { i_edge } + // , i_edge { P ? (i_edge + 1) : i_edge } + // , setE { tags & BC::Ex1 or tags & BC::Ex2 or tags & BC::Ex3 } + // , setB { tags & BC::Bx1 or tags & BC::Bx2 or tags & BC::Bx3 } {} + // + // Inline void operator()(index_t i1) const { + // if constexpr (D == Dim::_2D) { + // // if (setB) { + // // Fld(i1, i_edge, em::bx2) = ZERO; + // // } + // if constexpr (not P) { + // if (setE) { + // Fld(i1, i_edge - 1, em::ex2) = -Fld(i1, i_edge, em::ex2); + // Fld(i1, i_edge, em::ex3) = ZERO; + // } + // if (setB) { + // Fld(i1, i_edge - 1, em::bx1) = Fld(i1, i_edge, em::bx1); + // Fld(i1, i_edge, em::bx2) = ZERO; + // Fld(i1, i_edge - 1, em::bx3) = Fld(i1, i_edge, em::bx3); + // } + // } else { + // if (setE) { + // Fld(i1, i_edge + 1, em::ex2) = -Fld(i1, i_edge, em::ex2); + // Fld(i1, i_edge + 1, em::ex3) = ZERO; + // } + // if (setB) { + // Fld(i1, i_edge + 1, em::bx1) = Fld(i1, i_edge, em::bx1); + // Fld(i1, i_edge + 1, em::bx2) = ZERO; + // Fld(i1, i_edge + 1, em::bx3) = Fld(i1, i_edge, em::bx3); + // } + // } + // } else { + // raise::KernelError(HERE, "AxisBoundariesGR_kernel: D != 2"); + // } + // } + // }; template struct EnforcedBoundaries_kernel { @@ -1215,101 +1216,104 @@ namespace kernel::bc { } }; - template - struct HorizonBoundaries_kernel { - ndfield_t Fld; - const std::size_t i1_min; - const bool setE, setB; - const std::size_t nfilter; - - HorizonBoundaries_kernel(ndfield_t Fld, - std::size_t i1_min, - BCTags tags, - std::size_t nfilter) - : Fld { Fld } - , i1_min { i1_min } - , setE { (tags & BC::Ex1 or tags & BC::Ex2 or tags & BC::Ex3) or - (tags & BC::Dx1 or tags & BC::Dx2 or tags & BC::Dx3) } - , setB { (tags & BC::Bx1 or tags & BC::Bx2 or tags & BC::Bx3) or - (tags & BC::Hx1 or tags & BC::Hx2 or tags & BC::Hx3) } - , nfilter { nfilter } {} - - Inline void operator()(index_t i2) const { - if constexpr (M::Dim == Dim::_2D) { - if (setE) { - for (unsigned short i = 0; i <= 2 + nfilter; ++i) { - Fld(i1_min - N_GHOSTS + i, i2, em::dx1) = Fld(i1_min + 1 + nfilter, - i2, - em::dx1); - Fld(i1_min - N_GHOSTS + i, i2, em::dx2) = Fld(i1_min + 1 + nfilter, - i2, - em::dx2); - Fld(i1_min - N_GHOSTS + i, i2, em::dx3) = Fld(i1_min + 1 + nfilter, - i2, - em::dx3); + namespace gr { + + template + struct HorizonBoundaries_kernel { + ndfield_t Fld; + const std::size_t i1_min; + const bool setE, setB; + const std::size_t nfilter; + + HorizonBoundaries_kernel(ndfield_t Fld, + std::size_t i1_min, + BCTags tags, + std::size_t nfilter) + : Fld { Fld } + , i1_min { i1_min } + , setE { (tags & BC::Ex1 or tags & BC::Ex2 or tags & BC::Ex3) or + (tags & BC::Dx1 or tags & BC::Dx2 or tags & BC::Dx3) } + , setB { (tags & BC::Bx1 or tags & BC::Bx2 or tags & BC::Bx3) or + (tags & BC::Hx1 or tags & BC::Hx2 or tags & BC::Hx3) } + , nfilter { nfilter } {} + + Inline void operator()(index_t i2) const { + if constexpr (M::Dim == Dim::_2D) { + if (setE) { + for (unsigned short i = 0; i <= 2 + nfilter; ++i) { + Fld(i1_min - N_GHOSTS + i, + i2, + em::dx1) = Fld(i1_min + 1 + nfilter, i2, em::dx1); + Fld(i1_min - N_GHOSTS + i, + i2, + em::dx2) = Fld(i1_min + 1 + nfilter, i2, em::dx2); + Fld(i1_min - N_GHOSTS + i, + i2, + em::dx3) = Fld(i1_min + 1 + nfilter, i2, em::dx3); + } } - } - if (setB) { - for (unsigned short i = 0; i <= 2 + nfilter; ++i) { - Fld(i1_min - N_GHOSTS + i, i2, em::bx1) = Fld(i1_min + 1 + nfilter, - i2, - em::bx1); - Fld(i1_min - N_GHOSTS + i, i2, em::bx2) = Fld(i1_min + 1 + nfilter, - i2, - em::bx2); - Fld(i1_min - N_GHOSTS + i, i2, em::bx3) = Fld(i1_min + 1 + nfilter, - i2, - em::bx3); + if (setB) { + for (unsigned short i = 0; i <= 2 + nfilter; ++i) { + Fld(i1_min - N_GHOSTS + i, + i2, + em::bx1) = Fld(i1_min + 1 + nfilter, i2, em::bx1); + Fld(i1_min - N_GHOSTS + i, + i2, + em::bx2) = Fld(i1_min + 1 + nfilter, i2, em::bx2); + Fld(i1_min - N_GHOSTS + i, + i2, + em::bx3) = Fld(i1_min + 1 + nfilter, i2, em::bx3); + } } + } else { + raise::KernelError( + HERE, + "HorizonBoundaries_kernel: 2D implementation called for D != 2"); } - } else { - raise::KernelError( - HERE, - "HorizonBoundaries_kernel: 2D implementation called for D != 2"); } - } - }; + }; - template - struct AbsorbCurrentsGR_kernel { - static_assert(M::is_metric, "M must be a metric class"); - static_assert(i <= static_cast(M::Dim), - "Invalid component index"); + template + struct AbsorbCurrents_kernel { + static_assert(M::is_metric, "M must be a metric class"); + static_assert(i <= static_cast(M::Dim), + "Invalid component index"); - ndfield_t J; - const M metric; - const real_t xg_edge; - const real_t dx_abs; + ndfield_t J; + const M metric; + const real_t xg_edge; + const real_t dx_abs; - AbsorbCurrentsGR_kernel(ndfield_t J, + AbsorbCurrents_kernel(ndfield_t J, const M& metric, real_t xg_edge, real_t dx_abs) - : J { J } - , metric { metric } - , xg_edge { xg_edge } - , dx_abs { dx_abs } {} - - Inline void operator()(index_t i1, index_t i2) const { - if constexpr (M::Dim == Dim::_2D) { - const auto i1_ = COORD(i1); - const auto i2_ = COORD(i2); - coord_t x_Cd { ZERO }; - x_Cd[0] = i1_; - x_Cd[1] = i2_; - const auto dx = math::abs( - metric.template convert(x_Cd[i - 1]) - xg_edge); - J(i1, i2, 0) *= math::tanh(dx / (INV_4 * dx_abs)); - J(i1, i2, 1) *= math::tanh(dx / (INV_4 * dx_abs)); - J(i1, i2, 2) *= math::tanh(dx / (INV_4 * dx_abs)); + : J { J } + , metric { metric } + , xg_edge { xg_edge } + , dx_abs { dx_abs } {} + + Inline void operator()(index_t i1, index_t i2) const { + if constexpr (M::Dim == Dim::_2D) { + const auto i1_ = COORD(i1); + const auto i2_ = COORD(i2); + coord_t x_Cd { ZERO }; + x_Cd[0] = i1_; + x_Cd[1] = i2_; + const auto dx = math::abs( + metric.template convert(x_Cd[i - 1]) - xg_edge); + J(i1, i2, 0) *= math::tanh(dx / (INV_4 * dx_abs)); + J(i1, i2, 1) *= math::tanh(dx / (INV_4 * dx_abs)); + J(i1, i2, 2) *= math::tanh(dx / (INV_4 * dx_abs)); - } else { - raise::KernelError( - HERE, - "AbsorbCurrentsGR_kernel: 2D implementation called for D != 2"); + } else { + raise::KernelError( + HERE, + "gr::AbsorbCurrents_kernel: 2D implementation called for D != 2"); + } } - } - }; + }; + } // namespace gr } // namespace kernel::bc From 7470a4124acf5c4ef2d57d55d89de12f0e2000f1 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Sat, 14 Jun 2025 16:07:35 -0400 Subject: [PATCH 734/773] minor bug in AbsorbCur: sign < 0 --- src/engines/grpic.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index 345c91d5d..78966a25e 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -598,7 +598,7 @@ namespace ntt { real_t xg_min, xg_max, xg_edge; auto sign = direction.get_sign(); - raise::ErrorIf(((dim != in::x1) or (sign > 0)) and (g == gr_bc::curr), + raise::ErrorIf(((dim != in::x1) or (sign < 0)) and (g == gr_bc::curr), "Absorption of currents only possible in +x1 (+r)", HERE); From ffe110cc455bc960abc97279f8d3f222c75f574e Mon Sep 17 00:00:00 2001 From: hayk Date: Sun, 15 Jun 2025 16:13:19 -0400 Subject: [PATCH 735/773] (RUNTEST) From d750384b0d1aed8b8028d7673eb528f2e253700d Mon Sep 17 00:00:00 2001 From: haykh Date: Sun, 15 Jun 2025 13:24:09 -0700 Subject: [PATCH 736/773] minor bug in test for plaw dist GR --- src/archetypes/tests/powerlaw.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/archetypes/tests/powerlaw.cpp b/src/archetypes/tests/powerlaw.cpp index 58df1f4cf..3cb76763f 100644 --- a/src/archetypes/tests/powerlaw.cpp +++ b/src/archetypes/tests/powerlaw.cpp @@ -45,10 +45,12 @@ struct Caller { raise::KernelError(HERE, "Gamma out of bounds"); } } else { - vec_t vup { ZERO }; - metric.template transform(xp, vp, vup); + vec_t vd { ZERO }; + vec_t vu { ZERO }; + metric.template transform(xp, vp, vd); + metric.template transform(xp, vp, vu); const auto gamma = math::sqrt( - ONE + vup[0] * vp[0] + vup[1] * vp[1] + vup[2] * vp[2]); + ONE + vu[0] * vd[0] + vu[1] * vd[1] + vu[2] * vd[2]); if (gamma < 10 or gamma > 1000) { raise::KernelError(HERE, "Gamma out of bounds"); } From 9a4d2b62e5b43c144b7bf697c95ac3a6da4fe7b6 Mon Sep 17 00:00:00 2001 From: haykh Date: Sun, 15 Jun 2025 17:23:07 -0400 Subject: [PATCH 737/773] minor nix-shell fix for newest HIP/ROCm --- dev/nix/kokkos.nix | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/dev/nix/kokkos.nix b/dev/nix/kokkos.nix index 8dfe1f380..e12b9d57d 100644 --- a/dev/nix/kokkos.nix +++ b/dev/nix/kokkos.nix @@ -29,13 +29,15 @@ let getArch = _: if gpu != "NONE" && arch == "NATIVE" then - throw "Please specify an architecture when the GPU support is enabled. Available architectures: https://kokkos.org/kokkos-core-wiki/keywords.html#architectures" + throw "Please specify an architecture when the GPU support is enabled. Available architectures: https://kokkos.org/kokkos-core-wiki/get-started/configuration-guide.html#gpu-architectures" else arch; cmakeExtraFlags = { "HIP" = [ "-D Kokkos_ENABLE_HIP=ON" "-D Kokkos_ARCH_${getArch { }}=ON" + # remove leading AMD_ + "-D AMDGPU_TARGETS=${builtins.replaceStrings [ "amd_" ] [ "" ] (pkgs.lib.toLower (getArch { }))}" "-D CMAKE_C_COMPILER=hipcc" "-D CMAKE_CXX_COMPILER=hipcc" ]; From 1149632ea71afb952dcd9cec32769e96525a6720 Mon Sep 17 00:00:00 2001 From: haykh Date: Sun, 15 Jun 2025 17:23:23 -0400 Subject: [PATCH 738/773] minor bugfix in test for stats --- src/kernels/tests/reduced_stats.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/kernels/tests/reduced_stats.cpp b/src/kernels/tests/reduced_stats.cpp index 499c24aa9..ee036395a 100644 --- a/src/kernels/tests/reduced_stats.cpp +++ b/src/kernels/tests/reduced_stats.cpp @@ -4,13 +4,11 @@ #include "global.h" #include "arch/kokkos_aliases.h" -#include "utils/comparators.h" #include "utils/error.h" #include "metrics/minkowski.h" #include -#include #include using namespace ntt; @@ -18,15 +16,17 @@ using namespace metric; template class Fill_kernel { - ndfield_t& arr; - real_t v; - unsigned short c; + ndfield_t arr; + real_t v; + unsigned short c; public: Fill_kernel(ndfield_t& arr_, real_t v_, unsigned short c_) : arr { arr_ } , v { v_ } - , c { c_ } {} + , c { c_ } { + raise::ErrorIf(c_ >= N, "c > N", HERE); + } Inline void operator()(index_t i1) const { arr(i1, c) = v; From b581ba340a97c8936f0221fd516424b993cfb141 Mon Sep 17 00:00:00 2001 From: haykh Date: Sun, 15 Jun 2025 17:23:44 -0400 Subject: [PATCH 739/773] (RUNTEST) From 9d3a6e7820167a0f30496dc8cd7d484e5e9ff7ca Mon Sep 17 00:00:00 2001 From: haykh Date: Sun, 15 Jun 2025 17:34:52 -0400 Subject: [PATCH 740/773] minor bug in parallel checkpoint test --- src/checkpoint/tests/checkpoint-mpi.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/checkpoint/tests/checkpoint-mpi.cpp b/src/checkpoint/tests/checkpoint-mpi.cpp index bc6d6038a..2372d81bc 100644 --- a/src/checkpoint/tests/checkpoint-mpi.cpp +++ b/src/checkpoint/tests/checkpoint-mpi.cpp @@ -20,7 +20,7 @@ using namespace checkpoint; void cleanup() { namespace fs = std::filesystem; - fs::path temp_path { "checkpoints" }; + fs::path temp_path { "chck" }; fs::remove_all(temp_path); } @@ -126,11 +126,12 @@ auto main(int argc, char* argv[]) -> int { } adios2::ADIOS adios; + const path_t checkpoint_path { "chck" }; { // write checkpoint Writer writer; - writer.init(&adios, 0, 0.0, 1); + writer.init(&adios, checkpoint_path, 0, 0.0, 1); writer.defineFieldVariables(SimEngine::GRPIC, { g_nx1_gh, g_nx2_gh }, @@ -190,7 +191,7 @@ auto main(int argc, char* argv[]) -> int { array_t plds1_read { "plds_1", npart1, 3 }; adios2::IO io = adios.DeclareIO("checkpointRead"); - adios2::Engine reader = io.Open("checkpoints/step-00000000.bp", + adios2::Engine reader = io.Open(checkpoint_path / "step-00000000.bp", adios2::Mode::Read); reader.BeginStep(); From d50161fb407963fcc421569f91bb7d81b1abf2cb Mon Sep 17 00:00:00 2001 From: haykh Date: Sun, 15 Jun 2025 17:53:49 -0400 Subject: [PATCH 741/773] fixed deposit test for dprec (RUNTEST) --- src/kernels/tests/deposit.cpp | 70 +++++++++++++---------------------- 1 file changed, 25 insertions(+), 45 deletions(-) diff --git a/src/kernels/tests/deposit.cpp b/src/kernels/tests/deposit.cpp index 1570937b8..c9acafaed 100644 --- a/src/kernels/tests/deposit.cpp +++ b/src/kernels/tests/deposit.cpp @@ -27,13 +27,16 @@ void errorIf(bool condition, const std::string& message) { } } -inline static constexpr auto epsilon = std::numeric_limits::epsilon(); +const real_t eps = std::is_same_v ? (real_t)(1e-6) + : (real_t)(1e-3); -Inline auto equal(real_t a, real_t b, const char* msg = "", real_t acc = ONE) - -> bool { - const auto eps = epsilon * acc; - if (not cmp::AlmostEqual(a, b, eps)) { +Inline auto equal(real_t a, real_t b, const char* msg, real_t eps) -> bool { + if ((a - b) >= eps * math::max(math::fabs(a), math::fabs(b))) { printf("%.12e != %.12e %s\n", a, b, msg); + printf("%.12e >= %.12e %s\n", + a - b, + eps * math::max(math::fabs(a), math::fabs(b)), + msg); return false; } return true; @@ -49,8 +52,8 @@ void put_value(array_t arr, T value, int i) { template void testDeposit(const std::vector& res, const boundaries_t& ext, - const std::map& params = {}, - const real_t acc = ONE) { + const std::map& params, + const real_t eps) { static_assert(M::Dim == 2); errorIf(res.size() != M::Dim, "res.size() != M::Dim"); using namespace ntt; @@ -158,13 +161,13 @@ void testDeposit(const std::vector& res, if (not cmp::AlmostZero(SumDivJ)) { throw std::logic_error("DepositCurrents_kernel::SumDivJ != 0"); } - errorIf(not equal(J_h(i0 + N_GHOSTS, j0 + N_GHOSTS, cur::jx1), Jx1, "", acc), + errorIf(not equal(J_h(i0 + N_GHOSTS, j0 + N_GHOSTS, cur::jx1), Jx1, "", eps), "DepositCurrents_kernel::Jx1 is incorrect"); - errorIf(not equal(J_h(i0 + N_GHOSTS, j0 + 1 + N_GHOSTS, cur::jx1), Jx2, "", acc), + errorIf(not equal(J_h(i0 + N_GHOSTS, j0 + 1 + N_GHOSTS, cur::jx1), Jx2, "", eps), "DepositCurrents_kernel::Jx2 is incorrect"); - errorIf(not equal(J_h(i0 + N_GHOSTS, j0 + N_GHOSTS, cur::jx2), Jy1, "", acc), + errorIf(not equal(J_h(i0 + N_GHOSTS, j0 + N_GHOSTS, cur::jx2), Jy1, "", eps), "DepositCurrents_kernel::Jy1 is incorrect"); - errorIf(not equal(J_h(i0 + 1 + N_GHOSTS, j0 + N_GHOSTS, cur::jx2), Jy2, "", acc), + errorIf(not equal(J_h(i0 + 1 + N_GHOSTS, j0 + N_GHOSTS, cur::jx2), Jy2, "", eps), "DepositCurrents_kernel::Jy2 is incorrect"); } @@ -183,41 +186,18 @@ auto main(int argc, char* argv[]) -> int { { 0.0, 55.0 }, { 0.0, 55.0 } }; + const std::map params { + { "r0", 0.0 }, + { "h", 0.25 }, + { "a", 0.9 } + }; - testDeposit, SimEngine::SRPIC>(res, xy_extent, {}, 500); - - testDeposit, SimEngine::SRPIC>(res, r_extent, {}, 500); - - testDeposit, SimEngine::SRPIC>(res, - r_extent, - { - { "r0", 0.0 }, - { "h", 0.25 } - }, - 500); - - testDeposit, SimEngine::GRPIC>(res, - r_extent, - { - { "a", 0.9 } - }, - 500); - - testDeposit, SimEngine::GRPIC>(res, - r_extent, - { - { "r0", 0.0 }, - { "h", 0.25 }, - { "a", 0.9 } - }, - 500); - - testDeposit, SimEngine::GRPIC>(res, - r_extent, - { - { "a", 0.9 } - }, - 500); + testDeposit, SimEngine::SRPIC>(res, xy_extent, {}, eps); + testDeposit, SimEngine::SRPIC>(res, r_extent, {}, eps); + testDeposit, SimEngine::SRPIC>(res, r_extent, params, eps); + testDeposit, SimEngine::GRPIC>(res, r_extent, params, eps); + testDeposit, SimEngine::GRPIC>(res, r_extent, params, eps); + testDeposit, SimEngine::GRPIC>(res, r_extent, params, eps); } catch (std::exception& e) { std::cerr << e.what() << std::endl; From a5b53dfaacbe73b371cc391e6f6c80f47053bf89 Mon Sep 17 00:00:00 2001 From: hayk Date: Sun, 15 Jun 2025 18:30:23 -0400 Subject: [PATCH 742/773] rm remaining overrides --- pgens/accretion/pgen.hpp | 8 +++++--- pgens/reconnection/pgen.hpp | 2 +- src/archetypes/tests/spatial_dist.cpp | 4 ++-- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/pgens/accretion/pgen.hpp b/pgens/accretion/pgen.hpp index 864140dfe..54a607352 100644 --- a/pgens/accretion/pgen.hpp +++ b/pgens/accretion/pgen.hpp @@ -43,7 +43,8 @@ namespace user { TWO * metric.spin() * g_00); } - Inline auto bx1(const coord_t& x_Ph) const -> real_t { // at ( i , j + HALF ) + Inline auto bx1(const coord_t& x_Ph) const + -> real_t { // at ( i , j + HALF ) coord_t xi { ZERO }, x0m { ZERO }, x0p { ZERO }; metric.template convert(x_Ph, xi); @@ -61,7 +62,8 @@ namespace user { } } - Inline auto bx2(const coord_t& x_Ph) const -> real_t { // at ( i + HALF , j ) + Inline auto bx2(const coord_t& x_Ph) const + -> real_t { // at ( i + HALF , j ) coord_t xi { ZERO }, x0m { ZERO }, x0p { ZERO }; metric.template convert(x_Ph, xi); @@ -174,7 +176,7 @@ namespace user { return false; } - Inline auto operator()(const coord_t& x_Ph) const -> real_t override { + Inline auto operator()(const coord_t& x_Ph) const -> real_t { auto fill = true; for (auto d = 0u; d < M::Dim; ++d) { fill &= x_Ph[d] > x_min[d] and x_Ph[d] < x_max[d] and sigma_crit(x_Ph); diff --git a/pgens/reconnection/pgen.hpp b/pgens/reconnection/pgen.hpp index e92de5847..8e8804b2d 100644 --- a/pgens/reconnection/pgen.hpp +++ b/pgens/reconnection/pgen.hpp @@ -28,7 +28,7 @@ namespace user { , center_x { center_x } , cs_y { cs_y } {} - Inline auto operator()(const coord_t& x_Ph) const -> real_t override { + Inline auto operator()(const coord_t& x_Ph) const -> real_t { return ONE / SQR(math::cosh((x_Ph[1] - cs_y) / cs_width)) * (ONE - math::exp(-SQR((x_Ph[0] - center_x) / cs_width))); } diff --git a/src/archetypes/tests/spatial_dist.cpp b/src/archetypes/tests/spatial_dist.cpp index 232ab1eb7..c27f20851 100644 --- a/src/archetypes/tests/spatial_dist.cpp +++ b/src/archetypes/tests/spatial_dist.cpp @@ -76,7 +76,7 @@ struct RadialDist : public SpatialDistribution { RadialDist(const M& metric) : SpatialDistribution { metric } {} - Inline auto operator()(const coord_t& x_Code) const -> real_t override { + auto operator()(const coord_t& x_Code) const -> real_t { coord_t x_Sph { ZERO }; metric.template convert(x_Code, x_Sph); auto r { ZERO }; @@ -123,4 +123,4 @@ auto main(int argc, char* argv[]) -> int { } Kokkos::finalize(); return 0; -} \ No newline at end of file +} From cfd3b7747a6506d43def1c87c03fd6149ddc27d0 Mon Sep 17 00:00:00 2001 From: haykh Date: Tue, 17 Jun 2025 08:46:39 -0400 Subject: [PATCH 743/773] new branch declaration From 6a36364e2837562eeae613489d65fe73d3373c93 Mon Sep 17 00:00:00 2001 From: haykh Date: Tue, 17 Jun 2025 16:11:37 -0400 Subject: [PATCH 744/773] passing flds_bc to kernel --- src/engines/grpic.hpp | 54 +++------------------------------- src/engines/srpic.hpp | 55 +++++++++++++++++------------------ src/kernels/tests/flds_bc.cpp | 13 ++++++--- 3 files changed, 39 insertions(+), 83 deletions(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index 78966a25e..168f2c730 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -647,7 +647,8 @@ namespace ntt { domain.mesh.metric, xg_edge, ds, - tags)); + tags, + domain.mesh.flds_bc())); Kokkos::parallel_for( "MatchBoundaries", CreateRangePolicy(range_min, range_max), @@ -657,7 +658,8 @@ namespace ntt { domain.mesh.metric, xg_edge, ds, - tags)); + tags, + domain.mesh.flds_bc())); } else { Kokkos::parallel_for( "AbsorbCurrents", @@ -672,54 +674,6 @@ namespace ntt { } } - // void AbsorbCurrentsIn(dir::direction_t direction, - // domain_t& domain, - // BCTags tags) { - // /** - // * absorbing currents at the boundaries - // */ - // // @TODO: also in MatchFieldsIn (need a better way) - // const auto ds_array = m_params.template get>( - // "grid.boundaries.match.ds"); - // const auto dim = in::x1; - // real_t xg_min, xg_max, xg_edge; - // real_t ds; - // ds = ds_array[(short)dim].second; - // xg_max = m_metadomain.mesh().extent(dim).second; - // xg_min = xg_max - ds; - // xg_edge = xg_max; - // - // boundaries_t box; - // boundaries_t incl_ghosts; - // for (unsigned short d { 0 }; d < M::Dim; ++d) { - // if (d == static_cast(dim)) { - // box.push_back({ xg_min, xg_max }); - // incl_ghosts.push_back({ false, true }); - // } else { - // box.push_back(Range::All); - // incl_ghosts.push_back({ true, true }); - // } - // } - // if (not domain.mesh.Intersects(box)) { - // return; - // } - // const auto intersect_range = domain.mesh.ExtentToRange(box, incl_ghosts); - // tuple_t range_min { 0 }; - // tuple_t range_max { 0 }; - // - // for (unsigned short d { 0 }; d < M::Dim; ++d) { - // range_min[d] = intersect_range[d].first; - // range_max[d] = intersect_range[d].second; - // } - // Kokkos::parallel_for( - // "AbsorbCurrentsGR", - // CreateRangePolicy(range_min, range_max), - // kernel::bc::AbsorbCurrentsGR_kernel(domain.fields.cur0, - // domain.mesh.metric, - // xg_edge, - // ds)); - // } - void HorizonFieldsIn(dir::direction_t direction, domain_t& domain, BCTags tags, diff --git a/src/engines/srpic.hpp b/src/engines/srpic.hpp index 0cdedb9b1..6b6a52039 100644 --- a/src/engines/srpic.hpp +++ b/src/engines/srpic.hpp @@ -492,31 +492,20 @@ namespace ntt { species.npart(), (double)species.charge()), HERE); + // clang-format off Kokkos::parallel_for("CurrentsDeposit", species.rangeActiveParticles(), kernel::DepositCurrents_kernel( scatter_cur, - species.i1, - species.i2, - species.i3, - species.i1_prev, - species.i2_prev, - species.i3_prev, - species.dx1, - species.dx2, - species.dx3, - species.dx1_prev, - species.dx2_prev, - species.dx3_prev, - species.ux1, - species.ux2, - species.ux3, - species.phi, - species.weight, - species.tag, + species.i1, species.i2, species.i3, + species.i1_prev, species.i2_prev, species.i3_prev, + species.dx1, species.dx2, species.dx3, + species.dx1_prev, species.dx2_prev, species.dx3_prev, + species.ux1, species.ux2, species.ux3, + species.phi, species.weight, species.tag, domain.mesh.metric, - (real_t)(species.charge()), - dt)); + (real_t)(species.charge()), dt)); + // clang-format on } Kokkos::Experimental::contribute(domain.fields.cur, scatter_cur); } @@ -685,6 +674,7 @@ namespace ntt { traits::has_member::value) { auto match_fields = m_pgen.MatchFields(time); call_match_fields(domain.fields.em, + domain.mesh.flds_bc(), match_fields, domain.mesh.metric, xg_edge, @@ -696,6 +686,7 @@ namespace ntt { traits::has_member::value) { auto match_fields = m_pgen.MatchFieldsInX1(time); call_match_fields(domain.fields.em, + domain.mesh.flds_bc(), match_fields, domain.mesh.metric, xg_edge, @@ -710,6 +701,7 @@ namespace ntt { traits::has_member::value) { auto match_fields = m_pgen.MatchFields(time); call_match_fields(domain.fields.em, + domain.mesh.flds_bc(), match_fields, domain.mesh.metric, xg_edge, @@ -721,6 +713,7 @@ namespace ntt { traits::has_member::value) { auto match_fields = m_pgen.MatchFieldsInX2(time); call_match_fields(domain.fields.em, + domain.mesh.flds_bc(), match_fields, domain.mesh.metric, xg_edge, @@ -738,6 +731,7 @@ namespace ntt { traits::has_member::value) { auto match_fields = m_pgen.MatchFields(time); call_match_fields(domain.fields.em, + domain.mesh.flds_bc(), match_fields, domain.mesh.metric, xg_edge, @@ -749,6 +743,7 @@ namespace ntt { traits::has_member::value) { auto match_fields = m_pgen.MatchFieldsInX3(time); call_match_fields(domain.fields.em, + domain.mesh.flds_bc(), match_fields, domain.mesh.metric, xg_edge, @@ -1463,14 +1458,15 @@ namespace ntt { } template - void call_match_fields(ndfield_t& fields, - const T& match_fields, - const M& metric, - real_t xg_edge, - real_t ds, - BCTags tags, - tuple_t& range_min, - tuple_t& range_max) { + void call_match_fields(ndfield_t& fields, + const boundaries_t& boundaries, + const T& match_fields, + const M& metric, + real_t xg_edge, + real_t ds, + BCTags tags, + tuple_t& range_min, + tuple_t& range_max) { Kokkos::parallel_for( "MatchFields", CreateRangePolicy(range_min, range_max), @@ -1479,7 +1475,8 @@ namespace ntt { metric, xg_edge, ds, - tags)); + tags, + boundaries)); } }; diff --git a/src/kernels/tests/flds_bc.cpp b/src/kernels/tests/flds_bc.cpp index c5675cdec..5de006d18 100644 --- a/src/kernels/tests/flds_bc.cpp +++ b/src/kernels/tests/flds_bc.cpp @@ -89,9 +89,13 @@ void testFldsBCs(const std::vector& res) { { res[0] + 2 * N_GHOSTS, res[1] + N_GHOSTS, res[2] + N_GHOSTS }); } - const auto xg_edge = (real_t)(sx[0].second); - const auto dx_abs = (real_t)(res[0] / 10.0); - + const auto xg_edge = (real_t)(sx[0].second); + const auto dx_abs = (real_t)(res[0] / 10.0); + boundaries_t flds_bc { + { FldsBC::PERIODIC, FldsBC::PERIODIC }, + { FldsBC::PERIODIC, FldsBC::PERIODIC }, + { FldsBC::PERIODIC, FldsBC::PERIODIC } + }; Kokkos::parallel_for( "MatchBoundaries_kernel", range, @@ -101,7 +105,8 @@ void testFldsBCs(const std::vector& res) { metric, xg_edge, dx_abs, - BC::E | BC::B)); + BC::E | BC::B, + flds_bc)); if constexpr (D == Dim::_1D) { Kokkos::parallel_for( From b3e72bbe41eae0a2313583a58fbd9ffac1652134 Mon Sep 17 00:00:00 2001 From: haykh Date: Tue, 17 Jun 2025 16:12:23 -0400 Subject: [PATCH 745/773] special treatment of axis --- src/kernels/fields_bcs.hpp | 60 ++++++++++++++++++++++++++------------ 1 file changed, 41 insertions(+), 19 deletions(-) diff --git a/src/kernels/fields_bcs.hpp b/src/kernels/fields_bcs.hpp index 40dd3d13d..04e630520 100644 --- a/src/kernels/fields_bcs.hpp +++ b/src/kernels/fields_bcs.hpp @@ -42,6 +42,7 @@ namespace kernel::bc { static_assert(M::is_metric, "M must be a metric class"); static_assert(static_cast(o) < static_cast(M::Dim), "Invalid component index"); + static constexpr auto D = M::Dim; static constexpr idx_t i = static_cast(o) + 1u; static constexpr bool defines_dx1 = traits::has_method::value; static constexpr bool defines_dx2 = traits::has_method::value; @@ -66,18 +67,30 @@ namespace kernel::bc { const real_t dx_abs; const BCTags tags; - MatchBoundaries_kernel(ndfield_t Fld, - const I& fset, - const M& metric, - real_t xg_edge, - real_t dx_abs, - BCTags tags) + ncells_t extent_2 { 0u }; + bool is_axis_i2min { false }, is_axis_i2max { false }; + + MatchBoundaries_kernel(ndfield_t Fld, + const I& fset, + const M& metric, + real_t xg_edge, + real_t dx_abs, + BCTags tags, + const boundaries_t& boundaries) : Fld { Fld } , fset { fset } , metric { metric } , xg_edge { xg_edge } , dx_abs { dx_abs } - , tags { tags } {} + , tags { tags } { + if constexpr ((M::CoordType != Coord::Cart) && + ((D == Dim::_2D) || (D == Dim::_3D))) { + raise::ErrorIf(boundaries.size() < 2, "boundaries defined incorrectly", HERE); + is_axis_i2min = (boundaries[1].first == FldsBC::AXIS); + is_axis_i2max = (boundaries[1].second == FldsBC::AXIS); + extent_2 = static_cast(Fld.extent(1)); + } + } Inline auto shape(const real_t& dx) const -> real_t { return math::tanh(dx * FOUR / dx_abs); @@ -281,14 +294,20 @@ namespace kernel::bc { metric.template convert({ i1_, i2_ }, x_Ph_00); if constexpr (defines_ex3 and S == SimEngine::SRPIC) { - Fld(i1, i2, em::ex3) = s * Fld(i1, i2, em::ex3) + - (ONE - s) * - metric.template transform<3, Idx::T, Idx::U>( - { i1_, i2_ }, - fset.ex3(x_Ph_00)); + Fld(i1, i2, em::ex3) = s * Fld(i1, i2, em::ex3); + if ((!is_axis_i2min or (i2 > N_GHOSTS)) and + (!is_axis_i2max or (i2 < extent_2 - N_GHOSTS))) { + Fld(i1, i2, em::ex3) += (ONE - s) * + metric.template transform<3, Idx::T, Idx::U>( + { i1_, i2_ }, + fset.ex3(x_Ph_00)); + } } else if constexpr (defines_dx3 and S == SimEngine::GRPIC) { - Fld(i1, i2, em::dx3) = s * Fld(i1, i2, em::dx3) + - (ONE - s) * fset.dx3(x_Ph_00); + Fld(i1, i2, em::dx3) = s * Fld(i1, i2, em::dx3); + if ((!is_axis_i2min or (i2 > N_GHOSTS)) and + (!is_axis_i2max or (i2 < extent_2 - N_GHOSTS))) { + Fld(i1, i2, em::dx3) += (ONE - s) * fset.dx3(x_Ph_00); + } } } } @@ -403,11 +422,14 @@ namespace kernel::bc { coord_t x_Ph_00H { ZERO }; metric.template convert({ i1_, i2_, i3_ + HALF }, x_Ph_00H); - Fld(i1, i2, i3, em::ex3) = - s * Fld(i1, i2, i3, em::ex3) + - (ONE - s) * metric.template transform<3, Idx::T, Idx::U>( - { i1_, i2_, i3_ + HALF }, - fset.ex3(x_Ph_00H)); + Fld(i1, i2, i3, em::ex3) = s * Fld(i1, i2, i3, em::ex3); + if ((!is_axis_i2min or (i2 > N_GHOSTS)) and + (!is_axis_i2max or (i2 < extent_2 - N_GHOSTS))) { + Fld(i1, i2, i3, em::ex3) += + (ONE - s) * metric.template transform<3, Idx::T, Idx::U>( + { i1_, i2_, i3_ + HALF }, + fset.ex3(x_Ph_00H)); + } } } } From b662207a3b2dd406b1ee7e627cbb35d878c025f7 Mon Sep 17 00:00:00 2001 From: hayk Date: Thu, 19 Jun 2025 20:55:35 -0400 Subject: [PATCH 746/773] assigning velocities to particle in uniforminject (bug fixed) --- src/kernels/injectors.hpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/kernels/injectors.hpp b/src/kernels/injectors.hpp index bb4235dc5..c321d18f8 100644 --- a/src/kernels/injectors.hpp +++ b/src/kernels/injectors.hpp @@ -118,9 +118,8 @@ namespace kernel { coord_t x_Ph { ZERO }; metric.template convert(x_Cd, x_Ph); if constexpr (M::CoordType == Coord::Cart) { - vec_t v_Ph { ZERO }; - energy_dist(x_Ph, v_Ph, spidx1); - energy_dist(x_Ph, v_Ph, spidx2); + energy_dist(x_Ph, v1, spidx1); + energy_dist(x_Ph, v2, spidx2); } else if constexpr (S == SimEngine::SRPIC) { coord_t x_Cd_ { ZERO }; x_Cd_[0] = x_Cd[0]; @@ -287,9 +286,8 @@ namespace kernel { coord_t x_Ph { ZERO }; metric.template convert(x_Cd, x_Ph); if constexpr (M::CoordType == Coord::Cart) { - vec_t v_Ph { ZERO }; - energy_dist_1(x_Ph, v_Ph, spidx1); - energy_dist_2(x_Ph, v_Ph, spidx2); + energy_dist_1(x_Ph, v1, spidx1); + energy_dist_2(x_Ph, v2, spidx2); } else if constexpr (S == SimEngine::SRPIC) { coord_t x_Cd_ { ZERO }; x_Cd_[0] = x_Cd[0]; From 7dafdd1a8d4f727ac288e82a2ec0255c341eceb3 Mon Sep 17 00:00:00 2001 From: LudwigBoess Date: Fri, 20 Jun 2025 11:34:56 -0500 Subject: [PATCH 747/773] added missing Kokkos::printf in tests --- src/kernels/tests/ampere_mink.cpp | 2 +- src/kernels/tests/deposit.cpp | 4 ++-- src/kernels/tests/faraday_mink.cpp | 2 +- src/kernels/tests/flds_bc.cpp | 26 +++++++++++++------------- src/kernels/tests/prtl_bc.cpp | 2 +- src/metrics/tests/coord_trans.cpp | 2 +- src/metrics/tests/ks-qks.cpp | 10 +++++----- src/metrics/tests/minkowski.cpp | 2 +- src/metrics/tests/sph-qsph.cpp | 2 +- src/metrics/tests/sr-cart-sph.cpp | 2 +- src/metrics/tests/vec_trans.cpp | 2 +- src/output/tests/writer-mpi.cpp | 2 +- src/output/tests/writer-nompi.cpp | 2 +- 13 files changed, 30 insertions(+), 30 deletions(-) diff --git a/src/kernels/tests/ampere_mink.cpp b/src/kernels/tests/ampere_mink.cpp index 80af88fa5..ab4de8134 100644 --- a/src/kernels/tests/ampere_mink.cpp +++ b/src/kernels/tests/ampere_mink.cpp @@ -25,7 +25,7 @@ void errorIf(bool condition, const std::string& message) { Inline auto equal(real_t a, real_t b, const char* msg, real_t acc) -> bool { if (not(math::abs(a - b) < acc)) { - printf("%.12e != %.12e [%.12e] %s\n", a, b, math::abs(a - b), msg); + Kokkos::printf("%.12e != %.12e [%.12e] %s\n", a, b, math::abs(a - b), msg); return false; } return true; diff --git a/src/kernels/tests/deposit.cpp b/src/kernels/tests/deposit.cpp index c9acafaed..0afb7d950 100644 --- a/src/kernels/tests/deposit.cpp +++ b/src/kernels/tests/deposit.cpp @@ -32,8 +32,8 @@ const real_t eps = std::is_same_v ? (real_t)(1e-6) Inline auto equal(real_t a, real_t b, const char* msg, real_t eps) -> bool { if ((a - b) >= eps * math::max(math::fabs(a), math::fabs(b))) { - printf("%.12e != %.12e %s\n", a, b, msg); - printf("%.12e >= %.12e %s\n", + Kokkos::printf("%.12e != %.12e %s\n", a, b, msg); + Kokkos::printf("%.12e >= %.12e %s\n", a - b, eps * math::max(math::fabs(a), math::fabs(b)), msg); diff --git a/src/kernels/tests/faraday_mink.cpp b/src/kernels/tests/faraday_mink.cpp index 74c2b9b1a..ce9f4c50c 100644 --- a/src/kernels/tests/faraday_mink.cpp +++ b/src/kernels/tests/faraday_mink.cpp @@ -25,7 +25,7 @@ void errorIf(bool condition, const std::string& message) { Inline auto equal(real_t a, real_t b, const char* msg, real_t acc) -> bool { if (not(math::abs(a - b) < acc)) { - printf("%.12e != %.12e [%.12e] %s\n", a, b, math::abs(a - b), msg); + Kokkos::printf("%.12e != %.12e [%.12e] %s\n", a, b, math::abs(a - b), msg); return false; } return true; diff --git a/src/kernels/tests/flds_bc.cpp b/src/kernels/tests/flds_bc.cpp index 5de006d18..bb27fff6e 100644 --- a/src/kernels/tests/flds_bc.cpp +++ b/src/kernels/tests/flds_bc.cpp @@ -48,7 +48,7 @@ struct DummyFieldsBCs { Inline auto equal(real_t a, real_t b, const char* msg, real_t acc) -> bool { if (not(math::abs(a - b) < acc)) { - printf("%.12e != %.12e [%.12e] %s\n", a, b, math::abs(a - b), msg); + Kokkos::printf("%.12e != %.12e [%.12e] %s\n", a, b, math::abs(a - b), msg); return false; } return true; @@ -118,19 +118,19 @@ void testFldsBCs(const std::vector& res) { FOUR * math::abs(x + HALF - xg_edge) / dx_abs); const auto factor2 = math::tanh(FOUR * math::abs(x - xg_edge) / dx_abs); if (not cmp::AlmostEqual(flds(i1, em::ex1), TWO * (ONE - factor1))) { - printf("%f != %f\n", flds(i1, em::ex1), TWO * (ONE - factor1)); + Kokkos::printf("%f != %f\n", flds(i1, em::ex1), TWO * (ONE - factor1)); raise::KernelError(HERE, "incorrect ex1"); } if (not cmp::AlmostEqual(flds(i1, em::ex2), THREE * (ONE - factor2))) { - printf("%f != %f\n", flds(i1, em::ex2), THREE * (ONE - factor2)); + Kokkos::printf("%f != %f\n", flds(i1, em::ex2), THREE * (ONE - factor2)); raise::KernelError(HERE, "incorrect ex2"); } if (not cmp::AlmostEqual(flds(i1, em::bx2), FOUR * (ONE - factor1))) { - printf("%f != %f\n", flds(i1, em::bx2), FOUR * (ONE - factor1)); + Kokkos::printf("%f != %f\n", flds(i1, em::bx2), FOUR * (ONE - factor1)); raise::KernelError(HERE, "incorrect bx2"); } if (not cmp::AlmostEqual(flds(i1, em::bx3), FIVE * (ONE - factor1))) { - printf("%f != %f\n", flds(i1, em::bx3), FIVE * (ONE - factor1)); + Kokkos::printf("%f != %f\n", flds(i1, em::bx3), FIVE * (ONE - factor1)); raise::KernelError(HERE, "incorrect bx3"); } }); @@ -145,19 +145,19 @@ void testFldsBCs(const std::vector& res) { FOUR * math::abs(x + HALF - xg_edge) / dx_abs); const auto factor2 = math::tanh(FOUR * math::abs(x - xg_edge) / dx_abs); if (not cmp::AlmostEqual(flds(i1, i2, em::ex1), TWO * (ONE - factor1))) { - printf("%f != %f\n", flds(i1, i2, em::ex1), TWO * (ONE - factor1)); + Kokkos::printf("%f != %f\n", flds(i1, i2, em::ex1), TWO * (ONE - factor1)); raise::KernelError(HERE, "incorrect ex1"); } if (not cmp::AlmostEqual(flds(i1, i2, em::ex2), THREE * (ONE - factor2))) { - printf("%f != %f\n", flds(i1, i2, em::ex2), THREE * (ONE - factor2)); + Kokkos::printf("%f != %f\n", flds(i1, i2, em::ex2), THREE * (ONE - factor2)); raise::KernelError(HERE, "incorrect ex2"); } if (not cmp::AlmostEqual(flds(i1, i2, em::bx2), FOUR * (ONE - factor1))) { - printf("%f != %f\n", flds(i1, i2, em::bx2), FOUR * (ONE - factor1)); + Kokkos::printf("%f != %f\n", flds(i1, i2, em::bx2), FOUR * (ONE - factor1)); raise::KernelError(HERE, "incorrect bx2"); } if (not cmp::AlmostEqual(flds(i1, i2, em::bx3), FIVE * (ONE - factor1))) { - printf("%f != %f\n", flds(i1, i2, em::bx3), FIVE * (ONE - factor1)); + Kokkos::printf("%f != %f\n", flds(i1, i2, em::bx3), FIVE * (ONE - factor1)); raise::KernelError(HERE, "incorrect bx3"); } }); @@ -173,22 +173,22 @@ void testFldsBCs(const std::vector& res) { FOUR * math::abs(x + HALF - xg_edge) / dx_abs); const auto factor2 = math::tanh(FOUR * math::abs(x - xg_edge) / dx_abs); if (not cmp::AlmostEqual(flds(i1, i2, i3, em::ex1), TWO * (ONE - factor1))) { - printf("%f != %f\n", flds(i1, i2, i3, em::ex1), TWO * (ONE - factor1)); + Kokkos::printf("%f != %f\n", flds(i1, i2, i3, em::ex1), TWO * (ONE - factor1)); raise::KernelError(HERE, "incorrect ex1"); } if (not cmp::AlmostEqual(flds(i1, i2, i3, em::ex2), THREE * (ONE - factor2))) { - printf("%f != %f\n", flds(i1, i2, i3, em::ex2), THREE * (ONE - factor2)); + Kokkos::printf("%f != %f\n", flds(i1, i2, i3, em::ex2), THREE * (ONE - factor2)); raise::KernelError(HERE, "incorrect ex2"); } if (not cmp::AlmostEqual(flds(i1, i2, i3, em::bx2), FOUR * (ONE - factor1))) { - printf("%f != %f\n", flds(i1, i2, i3, em::bx2), FOUR * (ONE - factor1)); + Kokkos::printf("%f != %f\n", flds(i1, i2, i3, em::bx2), FOUR * (ONE - factor1)); raise::KernelError(HERE, "incorrect bx2"); } if (not cmp::AlmostEqual(flds(i1, i2, i3, em::bx3), FIVE * (ONE - factor1))) { - printf("%f != %f\n", flds(i1, i2, i3, em::bx3), FIVE * (ONE - factor1)); + Kokkos::printf("%f != %f\n", flds(i1, i2, i3, em::bx3), FIVE * (ONE - factor1)); raise::KernelError(HERE, "incorrect bx3"); } }); diff --git a/src/kernels/tests/prtl_bc.cpp b/src/kernels/tests/prtl_bc.cpp index 6e49f8ba5..f7f8be43b 100644 --- a/src/kernels/tests/prtl_bc.cpp +++ b/src/kernels/tests/prtl_bc.cpp @@ -29,7 +29,7 @@ void errorIf(bool condition, const std::string& message = "") { Inline auto equal(real_t a, real_t b, const std::string& msg) -> bool { if (not(math::abs(a - b) < 1e-4)) { - printf("%.12e != %.12e %s\n", a, b, msg.c_str()); + Kokkos::printf("%.12e != %.12e %s\n", a, b, msg.c_str()); return false; } return true; diff --git a/src/metrics/tests/coord_trans.cpp b/src/metrics/tests/coord_trans.cpp index 67dcdda53..f2bd7e464 100644 --- a/src/metrics/tests/coord_trans.cpp +++ b/src/metrics/tests/coord_trans.cpp @@ -33,7 +33,7 @@ Inline auto equal(const coord_t& a, const auto eps = epsilon * acc; for (auto d { 0u }; d < D; ++d) { if (not cmp::AlmostEqual(a[d], b[d], eps)) { - printf("%d : %.12e != %.12e %s\n", d, a[d], b[d], msg); + Kokkos::printf("%d : %.12e != %.12e %s\n", d, a[d], b[d], msg); return false; } } diff --git a/src/metrics/tests/ks-qks.cpp b/src/metrics/tests/ks-qks.cpp index fce9004d1..98be577ec 100644 --- a/src/metrics/tests/ks-qks.cpp +++ b/src/metrics/tests/ks-qks.cpp @@ -27,7 +27,7 @@ Inline auto equal(const vec_t& a, const auto eps = epsilon * acc; for (auto d { 0u }; d < D; ++d) { if (not cmp::AlmostEqual(a[d], b[d], eps)) { - printf("%s: %.12e : %.12e\n", msg, a[d], b[d]); + Kokkos::printf("%s: %.12e : %.12e\n", msg, a[d], b[d]); return false; } } @@ -138,7 +138,7 @@ void testMetric(const std::vector& res, vec_t h_ij_expect { h_11_expect, h_22_expect, h_33_expect }; if (not equal(h_ij_predict, h_ij_expect, "h_ij", acc)) { - printf("h_ij: %.12e %.12e %.12e : %.12e %.12e %.12e\n", + Kokkos::printf("h_ij: %.12e %.12e %.12e : %.12e %.12e %.12e\n", h_ij_predict[0], h_ij_predict[1], h_ij_predict[2], @@ -148,11 +148,11 @@ void testMetric(const std::vector& res, Kokkos::abort("h_ij"); } if (not equal(h_13_predict, { h_13_expect }, "h_13", acc)) { - printf("h_13: %.12e : %.12e\n", h_13_predict[0], h_13_expect); + Kokkos::printf("h_13: %.12e : %.12e\n", h_13_predict[0], h_13_expect); Kokkos::abort("h_13"); } if (not equal(hij_predict, hij_expect, "hij", acc)) { - printf("hij: %.12e %.12e %.12e : %.12e %.12e %.12e\n", + Kokkos::printf("hij: %.12e %.12e %.12e : %.12e %.12e %.12e\n", hij_predict[0], hij_predict[1], hij_predict[2], @@ -162,7 +162,7 @@ void testMetric(const std::vector& res, Kokkos::abort("hij"); } if (not equal(h13_predict, { h13_expect }, "h13", acc)) { - printf("h13: %.12e : %.12e\n", h13_predict[0], h13_expect); + Kokkos::printf("h13: %.12e : %.12e\n", h13_predict[0], h13_expect); Kokkos::abort("h13"); } }); diff --git a/src/metrics/tests/minkowski.cpp b/src/metrics/tests/minkowski.cpp index 6073b810d..4c7d7791c 100644 --- a/src/metrics/tests/minkowski.cpp +++ b/src/metrics/tests/minkowski.cpp @@ -23,7 +23,7 @@ Inline auto equal(const coord_t& a, const coord_t& b, real_t acc = ONE) -> bool { for (auto d { 0u }; d < D; ++d) { if (not cmp::AlmostEqual(a[d], b[d], epsilon * acc)) { - printf("%d : %.12f != %.12f\n", d, a[d], b[d]); + Kokkos::printf("%d : %.12f != %.12f\n", d, a[d], b[d]); return false; } } diff --git a/src/metrics/tests/sph-qsph.cpp b/src/metrics/tests/sph-qsph.cpp index 2ad802c20..12c37bf6b 100644 --- a/src/metrics/tests/sph-qsph.cpp +++ b/src/metrics/tests/sph-qsph.cpp @@ -27,7 +27,7 @@ Inline auto equal(const vec_t& a, const auto eps = epsilon * acc; for (auto d { 0u }; d < D; ++d) { if (not cmp::AlmostEqual(a[d], b[d], eps)) { - printf("%d : %.12e != %.12e %s\n", d, a[d], b[d], msg); + Kokkos::printf("%d : %.12e != %.12e %s\n", d, a[d], b[d], msg); return false; } } diff --git a/src/metrics/tests/sr-cart-sph.cpp b/src/metrics/tests/sr-cart-sph.cpp index b3e4e163f..6ca6a52d7 100644 --- a/src/metrics/tests/sr-cart-sph.cpp +++ b/src/metrics/tests/sr-cart-sph.cpp @@ -30,7 +30,7 @@ Inline auto equal(const coord_t& a, const auto eps = epsilon * acc; for (auto d { 0u }; d < D; ++d) { if (not cmp::AlmostEqual(a[d], b[d], eps)) { - printf("%d : %.12e != %.12e %s\n", d, a[d], b[d], msg); + Kokkos::printf("%d : %.12e != %.12e %s\n", d, a[d], b[d], msg); return false; } } diff --git a/src/metrics/tests/vec_trans.cpp b/src/metrics/tests/vec_trans.cpp index af7c08813..e9a03aa50 100644 --- a/src/metrics/tests/vec_trans.cpp +++ b/src/metrics/tests/vec_trans.cpp @@ -33,7 +33,7 @@ Inline auto equal(const vec_t& a, const auto eps = epsilon * acc; for (auto d { 0u }; d < D; ++d) { if (not cmp::AlmostEqual(a[d], b[d], eps)) { - printf("%d : %.12e != %.12e %s\n", d, a[d], b[d], msg); + Kokkos::printf("%d : %.12e != %.12e %s\n", d, a[d], b[d], msg); return false; } } diff --git a/src/output/tests/writer-mpi.cpp b/src/output/tests/writer-mpi.cpp index 0770b8f80..72a8f87ec 100644 --- a/src/output/tests/writer-mpi.cpp +++ b/src/output/tests/writer-mpi.cpp @@ -158,7 +158,7 @@ auto main(int argc, char* argv[]) -> int { if (not cmp::AlmostEqual( field_read(i1), field(i1 * dwn1 + first_cell + i1min, cntr))) { - printf("\n:::::::::::::::\nfield_read(%ld) = %f != " + Kokkos::printf("\n:::::::::::::::\nfield_read(%ld) = %f != " "field(%ld, %d) = %f\n:::::::::::::::\n", i1, field_read(i1), diff --git a/src/output/tests/writer-nompi.cpp b/src/output/tests/writer-nompi.cpp index 70024d968..6e0c30859 100644 --- a/src/output/tests/writer-nompi.cpp +++ b/src/output/tests/writer-nompi.cpp @@ -179,7 +179,7 @@ auto main(int argc, char* argv[]) -> int { i2 * dwn2 + i2min, i3 * dwn3 + i3min, cntr))) { - printf("\n:::::::::::::::\nfield_read(%ld, %ld, %ld) = %f != " + Kokkos::printf("\n:::::::::::::::\nfield_read(%ld, %ld, %ld) = %f != " "field(%ld, %ld, %ld, %d) = %f\n:::::::::::::::\n", i1, i2, From 228ae2c6f04094be54e4f8d15b18c0cf950b8191 Mon Sep 17 00:00:00 2001 From: haykh Date: Sun, 22 Jun 2025 22:00:24 -0700 Subject: [PATCH 748/773] attempt to fix mpi spec --- src/framework/domain/output.cpp | 12 ++++++------ src/output/writer.cpp | 33 +++++++++++++++++++++------------ 2 files changed, 27 insertions(+), 18 deletions(-) diff --git a/src/framework/domain/output.cpp b/src/framework/domain/output.cpp index e458de0e4..ea04b10a4 100644 --- a/src/framework/domain/output.cpp +++ b/src/framework/domain/output.cpp @@ -32,7 +32,6 @@ #endif // MPI_ENABLED #include -#include #include #include @@ -200,9 +199,9 @@ namespace ntt { mesh.rangeActiveCells(), Lambda(index_t i, index_t j) { const real_t i_ { static_cast(static_cast(i) - (N_GHOSTS)) }; - const auto k_min = (i2_min - (N_GHOSTS)) + 1; - const auto k_max = (j - (N_GHOSTS)); - real_t A3 = ZERO; + const auto k_min = (i2_min - (N_GHOSTS)) + 1; + const auto k_max = (j - (N_GHOSTS)); + real_t A3 = ZERO; for (auto k { k_min }; k <= k_max; ++k) { real_t k_ = static_cast(k); real_t sqrt_detH_ij1 { mesh.metric.sqrt_det_h({ i_, k_ - HALF }) }; @@ -434,8 +433,9 @@ namespace ntt { c, local_domain->mesh); } else { - raise::Error("Vector potential can only be computed for GRPIC in 2D", - HERE); + raise::Error( + "Vector potential can only be computed for GRPIC in 2D", + HERE); } } else { raise::Error("Wrong # of components requested for " diff --git a/src/output/writer.cpp b/src/output/writer.cpp index 9a96f9f56..cc9ec0eb8 100644 --- a/src/output/writer.cpp +++ b/src/output/writer.cpp @@ -48,8 +48,9 @@ namespace out { m_trackers.insert({ type, tools::Tracker(type, interval, interval_time) }); } - auto Writer::shouldWrite(const std::string& type, timestep_t step, simtime_t time) - -> bool { + auto Writer::shouldWrite(const std::string& type, + timestep_t step, + simtime_t time) -> bool { if (m_trackers.find(type) != m_trackers.end()) { return m_trackers.at(type).shouldWrite(step, time); } else { @@ -360,6 +361,7 @@ namespace out { void Writer::writeSpectrum(const array_t& counts, const std::string& varname) { + auto var = m_io.InquireVariable(varname); auto counts_h = Kokkos::create_mirror_view(counts); Kokkos::deep_copy(counts_h, counts); #if defined(MPI_ENABLED) @@ -375,12 +377,14 @@ namespace out { MPI_ROOT_RANK, MPI_COMM_WORLD); if (rank == MPI_ROOT_RANK) { - auto var = m_io.InquireVariable(varname); - var.SetSelection(adios2::Box({}, { counts.extent(0) })); + var.SetSelection( + adios2::Box({ 0u }, { counts_h_all.extent(0) })); m_writer.Put(var, counts_h_all, adios2::Mode::Sync); + } else { + var.SetSelection(adios2::Box({ 0u }, { 0u })); + m_writer.Put(var, nullptr); } #else - auto var = m_io.InquireVariable(varname); var.SetSelection(adios2::Box({}, { counts.extent(0) })); m_writer.Put(var, counts_h, adios2::Mode::Sync); #endif @@ -388,18 +392,23 @@ namespace out { void Writer::writeSpectrumBins(const array_t& e_bins, const std::string& varname) { + auto var = m_io.InquireVariable(varname); + auto e_bins_h = Kokkos::create_mirror_view(e_bins); + Kokkos::deep_copy(e_bins_h, e_bins); #if defined(MPI_ENABLED) int rank; MPI_Comm_rank(MPI_COMM_WORLD, &rank); - if (rank != MPI_ROOT_RANK) { - return; + if (rank == MPI_ROOT_RANK) { + var.SetSelection(adios2::Box({ 0u }, { e_bins_h.extent(0) })); + m_writer.Put(var, e_bins_h.data(), adios2::Mode::Sync); + } else { + var.SetSelection(adios2::Box({ 0u }, { 0u })); + m_writer.Put(var, nullptr, adios2::Mode::Sync); } -#endif - auto var = m_io.InquireVariable(varname); - var.SetSelection(adios2::Box({}, { e_bins.extent(0) })); - auto e_bins_h = Kokkos::create_mirror_view(e_bins); - Kokkos::deep_copy(e_bins_h, e_bins); +#else + var.SetSelection(adios2::Box({}, { e_bins_h.extent(0) })); m_writer.Put(var, e_bins_h, adios2::Mode::Sync); +#endif } void Writer::writeMesh(unsigned short dim, From d19ce5b82a36c54b1e5eeb07db9f6d524c7b524b Mon Sep 17 00:00:00 2001 From: haykh Date: Fri, 27 Jun 2025 15:27:45 -0700 Subject: [PATCH 749/773] coc update --- CODE_OF_CONDUCT.md | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 CODE_OF_CONDUCT.md diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 000000000..cfd678063 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,29 @@ +This code of conduct outlines shared principles and expectations for all participants in our open-source project. It's here to keep things open, respectful, and simple for everyone. Anyone involved with using and developing the code are expected to follow these guidelines starting from the release version `1.2.0`. + +# Open-source Principles +- This project is fully open-source and does not belong to any individual or institution. +- It is developed and maintained by our team of incredibly talented people, whose goal is to make it accessible to everyone with no expectation of credits. +- Anyone is free to use, copy, modify, or distribute the code under the project's open license. +- If you contribute something to the repository, it becomes part of the project and thus will also be regarded as open-source. + +# Contributions and Credit +- The only attribution we strongly encourage is a citation of either the code repository, or the corresponding method papers (coming soon). +- All contributions are made voluntarily, and there is no expectation of recognition of isolated individuals. +- There's no built-in expectation of credit or authorship for modules or changes pushed to the repository. Anyone is free to use any part of the code with no attribution to the author of any specific module or algorithm. +- The code is there for everyone to use, and its only goal is to enable the community to produce exciting science! + +# Roles in the Project +- There are three informal roles: + - users: anyone using the code; + - contributors: users who have write access to the repository; + - maintainers: contributors who also take care of organizational, administrative, and tech-support duties. +- Role changes (user -> contributor or vice versa) are easy and open, and can be done by asking the maintainers. +- Contributors are also expected to follow any shared guidelines -- whether discussed informally or written down -- around code-development things, such as committing, merging, and creating pull requests. +- Maintainers have the most strict obligations of keeping the repository clean, managing pull-requests, issuing releases, documenting all the features and additions, writing unit tests, helping other users and contributors with any problems they encounter, etc. +- To reiterate, regardless of the extent of involvement and help, there is absolutely no expectation of recognition or attribution on maintainers' end! + +# Community and Participation +- Everyone is welcome in the community. +- Joining meetings on Zoom, using the Slack workspace, giving feedback, taking part in decision making and planning, or following development doesn't require any special status -- it's open to all. + +Finally, while we cannot enforce it, we strongly encourage any projects that build on this code to be open source too. If you build upon this project, we welcome transparency and openness in spirit. You may contribute to the code as much or as little as you like; all effort is appreciated, none is required. From 6edd462b4a9c037e384d30f8b42a1569ea6cbe42 Mon Sep 17 00:00:00 2001 From: haykh Date: Fri, 27 Jun 2025 16:14:02 -0700 Subject: [PATCH 750/773] readme upd --- README.md | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 6415a4274..fff90902b 100644 --- a/README.md +++ b/README.md @@ -2,11 +2,11 @@ tl;dr: One particle-in-cell code to rule them all. -`Entity` is an open-source coordinate-agnostic particle-in-cell (PIC) code written in C++17 specifically targeted to study plasma physics in relativistic astrophysical systems. The main algorithms of the code are written in covariant form, allowing to easily implement arbitrary grid geometries. The code is highly modular, and is written in the architecture-agnostic way using the [`Kokkos`](https://kokkos.org/kokkos-core-wiki/) performance portability library, allowing the code to efficiently use device parallelization on CPU and GPU architectures of different types. The multi-node parallelization is implemented using the `MPI` library, and the data output is done via the [`ADIOS2`](https://github.com/ornladios/ADIOS2) library which supports multiple output formats, including `HDF5` and `BP5`. +`Entity` is a community-driven open-source coordinate-agnostic general-relativistic (GR) particle-in-cell (PIC) code written in C++17 specifically targeted to study plasma physics in relativistic astrophysical systems. The main algorithms of the code are written in covariant form, allowing to easily implement arbitrary grid geometries. The code is highly modular, and is written in the architecture-agnostic way using the [`Kokkos`](https://kokkos.org/kokkos-core-wiki/) performance portability library, allowing the code to efficiently use device parallelization on CPU and GPU architectures of different types. The multi-node parallelization is implemented using the `MPI` library, and the data output is done via the [`ADIOS2`](https://github.com/ornladios/ADIOS2) library which supports multiple output formats, including `HDF5` and `BP5`. `Entity` is part of the `Entity toolkit` framework, which also includes a Python library for fast and efficient data analysis and visualization of the simulation data: [`nt2py`](https://pypi.org/project/nt2py/). -Our [detailed documentation](https://entity-toolkit.github.io/) includes everything you need to know to get started with using and/or contributing to the `Entity toolkit`. If you find bugs or issues, please feel free to add a GitHub issue or submit a pull request. Users with significant contributions to the code will be added to the list of developers, and assigned an emoji of their choice (important). +Our [detailed documentation](https://entity-toolkit.github.io/) includes everything you need to know to get started with using and/or contributing to the `Entity toolkit`. If you find bugs or issues, please feel free to add a GitHub issue or submit a pull request. Users with significant contributions to the code will be added to the list of developers, and assigned an emoji of their choice (important!). [![License](https://img.shields.io/badge/License-BSD%203--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause) @@ -27,4 +27,9 @@ Our [detailed documentation](https://entity-toolkit.github.io/) includes everyth ## Branch policy -Master branch contains the latest stable version of the code which has already been released. Development on the core is done on branches starting with `dev/`, while fixing bugs is done in branches that start with `bug/`. User-specific modifications (i.e., new problem generators plus perhaps minor corrections in the core) are done on branches starting with `pgen/`. Before merging to the master branch, all the branches must first be merged to the latest release-candidate branch, which ends with `rc`, via a pull request. After which, when all the release goals are met, the `rc` branch is merged to the master and released as a new stable version. Stale branches will be archived with a tag starting with `archive/` (can still be accessed via the "Tags" tab) and removed. +- `master` branch contains the latest stable version of the code which has already been released. +- Development on the core is done on branches starting with `dev/`. +- Bug-fixes are being pushed to branches starting with `bug/`. +- All `bug/` and `dev/` branches must have an open pull-request describing in detail its purpose. +- Before merging to the master branch, all the branches must first be merged to the latest release-candidate branch, which ends with `rc`, via a pull request. This can either be a major release: `1.X.0rc`, or a patch release `1.X.Yrc`. +- Stale branches will be archived with a tag starting with `archive/` (can still be accessed via the "Tags" tab) and removed. From 9ea6970991e65621668b072e1605f40d726f2e6c Mon Sep 17 00:00:00 2001 From: haykh Date: Fri, 27 Jun 2025 16:26:57 -0700 Subject: [PATCH 751/773] field dwn proper reading --- src/framework/parameters.cpp | 37 +++++++++++++++++++++++++++--------- 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/src/framework/parameters.cpp b/src/framework/parameters.cpp index c9f612cec..079ad615e 100644 --- a/src/framework/parameters.cpp +++ b/src/framework/parameters.cpp @@ -31,10 +31,10 @@ namespace ntt { template - auto get_dx0_V0(const std::vector& resolution, - const boundaries_t& extent, - const std::map& params) - -> std::pair { + auto get_dx0_V0( + const std::vector& resolution, + const boundaries_t& extent, + const std::map& params) -> std::pair { const auto metric = M(resolution, extent, params); const auto dx0 = metric.dxMin(); coord_t x_corner { ZERO }; @@ -491,11 +491,30 @@ namespace ntt { "fields", "mom_smooth", defaults::output::mom_smooth)); - auto field_dwn = toml::find_or(toml_data, - "output", - "fields", - "downsampling", - std::vector { 1, 1, 1 }); + std::vector field_dwn; + try { + auto field_dwn_ = toml::find>(toml_data, + "output", + "fields", + "downsampling"); + for (auto i = 0u; i < field_dwn_.size(); ++i) { + field_dwn.push_back(field_dwn_[i]); + } + } catch (...) { + try { + auto field_dwn_ = toml::find(toml_data, + "output", + "fields", + "downsampling"); + for (auto i = 0u; i < dim; ++i) { + field_dwn.push_back(field_dwn_); + } + } catch (...) { + for (auto i = 0u; i < dim; ++i) { + field_dwn.push_back(1u); + } + } + } raise::ErrorIf(field_dwn.size() > 3, "invalid `output.fields.downsampling`", HERE); if (field_dwn.size() > dim) { field_dwn.erase(field_dwn.begin() + (std::size_t)(dim), field_dwn.end()); From f2814b6cb8b66bce67b46fca55b53a86219f7928 Mon Sep 17 00:00:00 2001 From: haykh Date: Sat, 28 Jun 2025 09:53:24 -0700 Subject: [PATCH 752/773] readme upd --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index fff90902b..d1afa2487 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,14 @@ Our [detailed documentation](https://entity-toolkit.github.io/) includes everyth [![License](https://img.shields.io/badge/License-BSD%203--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause) +## Join the community + +Everyone is welcome to join our small yet steadily growing community of code users and developers; regardless of how much you are planning to contribute -- we always welcome fresh ideas and feedback. We hold weekly Zoom meetings on Mondays at 12pm NY time, and have a dedicated Slack channel where you can be easily added by [emailing](mailto:haykh.astro@gmail.com) [one of the maintainers](mailto:genegorbs@gmail.com). If you prefer to just join our Zoom meetings without the Slack involvement -- that's totally fine, just email, and we can send you the Zoom link. + +Another way of contacting us is via GitHub issues and/or pull requests. Make sure to check out our [F.A.Q.](https://entity-toolkit.github.io/wiki/content/1-getting-started/9-faq/), as it might help you answer your question. + +> Keep in mind, you are free to use the code in any capacity, and there is absolutely no requirement on our end of including any of the developers in your project/proposal (as highlighted in our Code of Conduct). When contributing, also keep in mind that the code you upload to the repository automatically becomes public and open-source, and the same standards will be applied to it as to the rest of the code. + ## Contributors (alphabetical) * :guitar: Ludwig Böss {[@LudwigBoess](https://github.com/LudwigBoess)} From 73f1f97e81e16359f1de5fea3d70f57f37f59da5 Mon Sep 17 00:00:00 2001 From: haykh Date: Thu, 3 Jul 2025 01:48:16 +0000 Subject: [PATCH 753/773] normalized input file comments --- input.example.toml | 413 +++++++++++++++++++++++---------------------- 1 file changed, 214 insertions(+), 199 deletions(-) diff --git a/input.example.toml b/input.example.toml index 6bb1537a4..6444a16f0 100644 --- a/input.example.toml +++ b/input.example.toml @@ -1,73 +1,72 @@ [simulation] - # Name of the simulation: + # Name of the simulation # @required # @type: string - # @example: "MySim" - # @note: The name is used for the output files. + # @note: The name is used for the output files name = "" # Simulation engine to use # @required # @type: string - # @valid: "SRPIC", "GRPIC" + # @enum: "SRPIC", "GRPIC" engine = "" - # Max runtime in physical (code) units: + # Max runtime in physical (code) units # @required - # @type: float: > 0 + # @type: float [> 0] # @example: 1e5 runtime = "" [simulation.domain] # Number of domains - # @type int - # @default: 1 (no MPI) - # @default: MPI_SIZE (MPI) + # @type: int + # @default: 1 [no MPI]; MPI_SIZE [MPI] number = "" - # Decomposition of the domain (e.g., for MPI) in each of the directions - # @type array of int of size 1, 2 or 3 - # @example: [2, 2, 2] (for a total of 8 domains) + # Decomposition of the domain (for MPI) in each of the directions + # @type: array [size 1 :->: 3] # @default: [-1, -1, -1] # @note: -1 means the code will determine the decomposition in the specific direction automatically - # @note: automatic detection is either done by inference from # of MPI tasks, or by balancing the grid size on each domain + # @note: Automatic detection is either done by inference from # of MPI tasks, or by balancing the grid size on each domain + # @example: [2, 2, 2] (total of 8 domains) decomposition = "" [grid] - # Spatial resolution of the grid: + # Spatial resolution of the grid # @required - # @type: array of uint of size 1, 2 or 3 - # @example: [1024, 1024, 1024] + # @type: array [size 1 :->: 3] # @note: Dimensionality is inferred from the size of this array + # @example: [1024, 1024, 1024] resolution = "" - # Physical extent of the grid: + # Physical extent of the grid # @required - # @type: 1/2/3-size array of float tuples, each of size 2 + # @type: array> [size 1 :->: 3] + # @note: For spherical geometry, only specify `[[rmin, rmax]]`, other values are set automatically + # @note: For cartesian geometry, cell aspect ratio has to be 1: `dx=dy=dz` # @example: [[0.0, 1.0], [-1.0, 1.0]] - # @note: For spherical geometry, only specify [[rmin, rmax]], other values are set automatically - # @note: For cartesian geometry, cell aspect ratio has to be 1, i.e., dx=dy=dz extent = "" # @inferred: # - dim # @brief: Dimensionality of the grid - # @type: short (1, 2, 3) + # @type: short + # @enum: 1, 2, 3 # @from: `grid.resolution` [grid.metric] # Metric on the grid # @required # @type: string - # @valid: "Minkowski", "Spherical", "QSpherical", "Kerr_Schild", "QKerr_Schild", "Kerr_Schild_0" + # @enum: "Minkowski", "Spherical", "QSpherical", "Kerr_Schild", "QKerr_Schild", "Kerr_Schild_0" metric = "" - # r0 paramter for the QSpherical metric, x1 = log(r-r0): - # @type: float: -inf < ... < rmin - # @default: 0.0 (e.g., x1 = log(r)) - # @note: negative values produce almost uniform grid in r + # `r0` paramter for the QSpherical metric `x1 = log(r-r0)` + # @type: float [-inf -> rmin] + # @default: 0.0 + # @note: Negative values produce almost uniform grid in r qsph_r0 = "" - # h paramter for the QSpherical metric, th = x2 + 2*h x2 (pi-2*x2)*(pi-x2)/pi^2: - # @type: float: -1 < ... < 1 - # @default: 0.0 (e.g., x2 = th) + # `h` paramter for the QSpherical metric `th = x2 + 2*h x2 (pi-2*x2)*(pi-x2)/pi^2` + # @type: float [-1 :->: 1] + # @default: 0.0 qsph_h = "" - # Spin parameter for the Kerr Schild metric: - # @type: float: 0 < ... < 1 + # Spin parameter for the Kerr Schild metric + # @type: float [0 :-> 1] # @default: 0.0 ks_a = "" @@ -75,7 +74,7 @@ # - coord # @brief: Coordinate system on the grid # @type: string - # @valid: "cartesian", "spherical", "qspherical" + # @enum: "cartesian", "spherical", "qspherical" # @from: `grid.metric.metric` # - ks_rh # @brief: Size of the horizon for GR Kerr Schild @@ -87,56 +86,56 @@ # @from: `grid.metric` [grid.boundaries] - # Boundary conditions for fields: + # Boundary conditions for fields # @required - # @type: 1/2/3-size array of string tuples, each of size 1 or 2 - # @valid: "PERIODIC", "MATCH", "FIXED", "ATMOSPHERE", "CUSTOM", "HORIZON", "CONDUCTOR" - # @example: [["CUSTOM", "MATCH"]] (for 2D spherical [[rmin, rmax]]) + # @type: array> [size 1 :->: 3] + # @enum: "PERIODIC", "MATCH", "FIXED", "ATMOSPHERE", "CUSTOM", "HORIZON", "CONDUCTOR" # @note: When periodic in any of the directions, you should only set one value: [..., ["PERIODIC"], ...] - # @note: In spherical, bondaries in theta/phi are set automatically (only specify bc @ [rmin, rmax]): [["ATMOSPHERE", "MATCH"]] + # @note: In spherical, bondaries in theta/phi are set automatically (only specify bc @ `[rmin, rmax]`): [["ATMOSPHERE", "MATCH"]] # @note: In GR, the horizon boundary is set automatically (only specify bc @ rmax): [["MATCH"]] + # @example: [["CUSTOM", "MATCH"]] (for 2D spherical `[[rmin, rmax]]`) fields = "" - # Boundary conditions for fields: + # Boundary conditions for fields # @required - # @type: 1/2/3-size array of string tuples, each of size 1 or 2 - # @valid: "PERIODIC", "ABSORB", "ATMOSPHERE", "CUSTOM", "REFLECT", "HORIZON" - # @example: [["PERIODIC"], ["PERIODIC"]] + # @type: array> [size 1 :->: 3] + # @enum: "PERIODIC", "ABSORB", "ATMOSPHERE", "CUSTOM", "REFLECT", "HORIZON" # @note: When periodic in any of the directions, you should only set one value [..., ["PERIODIC"], ...] - # @note: In spherical, bondaries in theta/phi are set automatically (only specify bc @ [rmin, rmax]) [["ATMOSPHERE", "ABSORB"]] - # @note: In GR, the horizon boundary is set automatically (only specify bc @ rmax): [["ABSORB"]] + # @note: In spherical, bondaries in theta/phi are set automatically (only specify bc @ `[rmin, rmax]`) [["ATMOSPHERE", "ABSORB"]] + # @note: In GR, the horizon boundary is set automatically (only specify bc @ `rmax`): [["ABSORB"]] + # @example: [["PERIODIC"], ["PERIODIC"]] particles = "" [grid.boundaries.match] - # Size of the matching layer in each direction for fields in physical (code) units: - # @type: float or array of tuples + # Size of the matching layer in each direction for fields in physical (code) units + # @type: float | array> # @default: 1% of the domain size (in shortest dimension) - # @note: In spherical, this is the size of the layer in r from the outer wall - # @example: ds = 1.5 (will set the same for all directions) - # @example: ds = [[1.5], [2.0, 1.0], [1.1]] (will duplicate 1.5 for +/- x1 and 1.1 for +/- x3) - # @example: ds = [[], [1.5], []] (will only set for x2) + # @note: In spherical, this is the size of the layer in `r` from the outer wall + # @example: `ds = 1.5` (will set the same for all directions) + # @example: `ds = [[1.5], [2.0, 1.0], [1.1]]` (will duplicate 1.5 for +/- `x1` and 1.1 for +/- `x3`) + # @example: `ds = [[], [1.5], []]` (will only set for x2) ds = "" [grid.boundaries.absorb] - # Size of the absorption layer for particles in physical (code) units: + # Size of the absorption layer for particles in physical (code) units # @type: float # @default: 1% of the domain size (in shortest dimension) - # @note: In spherical, this is the size of the layer in r from the outer wall + # @note: In spherical, this is the size of the layer in `r` from the outer wall # @note: In cartesian, this is the same for all dimensions where applicable ds = "" [grid.boundaries.atmosphere] - # @required: if ATMOSPHERE is one of the boundaries - # Temperature of the atmosphere in units of m0 c^2 + # Temperature of the atmosphere in units of `m0 c^2` # @type: float + # @note: [required] if `ATMOSPHERE` is one of the boundaries temperature = "" - # Peak number density of the atmosphere at base in units of n0 + # Peak number density of the atmosphere at base in units of `n0` # @type: float density = "" # Pressure scale-height in physical units # @type: float height = "" # Species indices of particles that populate the atmosphere - # @type: array of ints of size 2 + # @type: array [size 2] species = "" # Distance from the edge to which the gravity is imposed in physical units # @type: float @@ -145,19 +144,20 @@ ds = "" # @inferred: - # - g [= temperature / height] + # - g # @brief: Acceleration due to imposed gravity # @type: float # @from: `grid.boundaries.atmosphere.temperature`, `grid.boundaries.atmosphere.height` + # @value: `temperature / height` [scales] - # Fiducial larmor radius: + # Fiducial larmor radius # @required - # @type: float: > 0.0 + # @type: float [> 0.0] larmor0 = "" - # Fiducial plasma skin depth: + # Fiducial plasma skin depth # @required - # @type: float: > 0.0 + # @type: float [> 0.0] skindepth0 = "" # @inferred: @@ -169,238 +169,252 @@ # @brief: fiducial elementary volume # @type: float # @from: `grid` - # - n0 [= ppc0 / V0] + # - n0 # @brief: Fiducial number density # @type: float # @from: `particles.ppc0`, `grid` - # - q0 [= 1 / (n0 * skindepth0^2)] + # @value: `ppc0 / V0` + # - q0 # @brief: Fiducial elementary charge # @type: float # @from: `scales.skindepth0`, `scales.n0` - # - sigma0 [= (skindepth0 / larmor0)^2] + # @value: `1 / (n0 * skindepth0^2)` + # - sigma0 # @brief: Fiducial magnetization parameter # @type: float # @from: `scales.larmor0`, `scales.skindepth0` - # - B0 [= 1 / larmor0] + # @value: `(skindepth0 / larmor0)^2` + # - B0 # @brief: Fiducial magnetic field # @type: float # @from: `scales.larmor0` - # - omegaB0 [= 1 / larmor0] + # @value: `1 / larmor0` + # - omegaB0 # @brief: Fiducial cyclotron frequency # @type: float # @from: `scales.larmor0` + # @value: `1 / larmor0` [algorithms] - # Number of current smoothing passes: - # @type: unsigned short: >= 0 + # Number of current smoothing passes + # @type: ushort [>= 0] # @default: 0 current_filters = "" [algorithms.toggles] - # Toggle for the field solver: - # @type bool + # Toggle for the field solver + # @type: bool # @default: true fieldsolver = "" - # Toggle for the current deposition: - # @type bool + # Toggle for the current deposition + # @type: bool # @default: true deposit = "" [algorithms.timestep] - # Courant-Friedrichs-Lewy number: - # @type: float: 0.0 < ... < 1.0 + # Courant-Friedrichs-Lewy number + # @type: float [0.0 -> 1.0] # @default: 0.95 - # @note: CFL number determines the timestep duration. + # @note: CFL number determines the timestep duration CFL = "" - # Correction factor for the speed of light used in field solver: - # @type: float: ~1 + # Correction factor for the speed of light used in field solver + # @type: float # @default: 1.0 correction = "" # @inferred: - # - dt [= CFL * dx0] + # - dt # @brief: timestep duration # @type: float + # @from: `algorithms.timestep.CFL`, `scales.dx0` + # @value: `CFL * dx0` [algorithms.gr] - # Stepsize for numerical differentiation in GR pusher: - # @type: float: > 0 + # Stepsize for numerical differentiation in GR pusher + # @type: float [> 0.0] # @default: 1e-6 pusher_eps = "" - # Number of iterations for the Newton-Raphson method in GR pusher: - # @type: unsigned short: > 0 + # Number of iterations for the Newton-Raphson method in GR pusher + # @type: ushort [> 0] # @default: 10 pusher_niter = "" [algorithms.gca] - # Maximum value for E/B allowed for GCA particles: - # @type: float: 0.0 < ... < 1.0 + # Maximum value for E/B allowed for GCA particles + # @type: float [0.0 -> 1.0] # @default: 0.9 e_ovr_b_max = "" - # Maximum Larmor radius allowed for GCA particles (in physical units): + # Maximum Larmor radius allowed for GCA particles (in physical units) # @type: float # @default: 0.0 # @note: When `larmor_max` == 0, the limit is disabled larmor_max = "" [algorithms.synchrotron] - # Radiation reaction limit gamma-factor for synchrotron: - # @required [if one of the species has `cooling = "synchrotron"`] - # @type: float: > 0 + # Radiation reaction limit gamma-factor for synchrotron + # @type: float [> 0.0] + # @default: 1.0 + # @note: [required] if one of the species has `cooling = "synchrotron"` gamma_rad = "" [particles] - # Fiducial number of particles per cell: + # Fiducial number of particles per cell # @required - # @type: float: > 0 + # @type: float [> 0.0] ppc0 = "" - # Toggle for using particle weights: + # Toggle for using particle weights # @type: bool # @default: false use_weights = "" - # Timesteps between particle re-sorting (removing dead particles): - # @type: unsigned int + # Timesteps between particle re-sorting (removing dead particles) + # @type: uint # @default: 100 - # @note: set to 0 to disable re-sorting + # @note: Set to 0 to disable re-sorting clear_interval = "" # @inferred: # - nspec # @brief: Number of particle species - # @type: unsigned int - # @from: `particles.species` - # - species - # @brief: An object containing information about all the species - # @type: vector of ParticleSpecies + # @type: uint # @from: `particles.species` [[particles.species]] - # Label of the species: + # Label of the species # @type: string - # @default: "s*" (where "*" is the species index starting at 1) + # @default: "s" # @example: "e-" + # @note: `` is the index of the species in the list starting from 1 label = "" - # Mass of the species (in units of fiducial mass): + # Mass of the species (in units of fiducial mass) # @required - # @type: float + # @type: float [>= 0.0] mass = "" - # Charge of the species (in units of fiducial charge): + # Charge of the species (in units of fiducial charge) # @required # @type: float charge = "" - # Maximum number of particles per task: + # Maximum number of particles per task # @required - # @type: unsigned int: > 0 + # @type: uint [> 0] maxnpart = "" - # Pusher algorithm for the species: + # Pusher algorithm for the species # @type: string - # @default: "Boris" for massive and "Photon" for massless - # @valid: "Boris", "Vay", "Boris,GCA", "Vay,GCA", "Photon", "None" + # @default: "Boris" [massive]; "Photon" [massless] + # @enum: "Boris", "Vay", "Boris,GCA", "Vay,GCA", "Photon", "None" pusher = "" - # Number of additional (payload) variables for each particle of the given species: - # @type: unsigned short + # Number of additional (payload) variables for each particle of the given species + # @type: ushort # @default: 0 n_payloads = "" - # Radiation reaction to use for the species: + # Radiation reaction to use for the species # @type: string # @default: "None" - # @valid: "None", "Synchrotron" + # @enum: "None", "Synchrotron" cooling = "" -# Parameters for specific problem generators and setups: +# Parameters for specific problem generators and setups [setup] [output] - # Output format: + # Output format # @type: string - # @valid: "disabled", "hdf5", "BPFile" # @default: "hdf5" + # @enum: "disabled", "hdf5", "BPFile" format = "" - # Number of timesteps between all outputs (overriden by specific output interval below): - # @type: unsigned int: > 0 + # Number of timesteps between all outputs + # @type: uint [> 0] # @default: 1 + # @note: Value is overriden by output intervals for specific outputs interval = "" - # Physical (code) time interval between all outputs (overriden by specific output intervals below): + # Physical (code) time interval between all outputs # @type: float - # @default: -1.0 (disabled) + # @default: -1.0 # @note: When `interval_time` < 0, the output is controlled by `interval`, otherwise by `interval_time` + # @note: Value is overriden by output intervals for specific outputs interval_time = "" - # Whether to output each timestep into separate files: + # Whether to output each timestep into separate files # @type: bool # @default: true + # @deprecated: starting v1.3.0 separate_files = "" [output.fields] - # Toggle for the field output: + # Toggle for the field output # @type: bool # @default: true enable = "" - # Field quantities to output: - # @type: array of strings - # @valid: fields: "E", "B", "J", "divE" - # @valid: moments: "Rho", "Charge", "N", "Nppc", "T0i", "Tij", "Vi" - # @valid: for GR: "D", "H", "divD", "A" + # Field quantities to output + # @type: array # @default: [] - # @note: For T, you can use unspecified indices, e.g., Tij, T0i, or specific ones, e.g., Ttt, T00, T02, T23 - # @note: For T, in cartesian can also use "x" "y" "z" instead of "1" "2" "3" - # @note: By default, we accumulate moments from all massive species, one can specify only specific species: e.g., Ttt_1_2, Rho_1, Rho_3_4 + # @enum: "E", "B", "J", "divE", "Rho", "Charge", "N", "Nppc", "T0i", "Tij", "Vi", "D", "H", "divD", "A" + # @note: For `T`, you can use unspecified indices: `Tij`, `T0i`, or specific ones: `Ttt`, `T00`, `T02`, `T23` + # @note: For `T`, in cartesian can also use "x" "y" "z" instead of "1" "2" "3" + # @note: By default, we accumulate moments from all massive species, one can specify only specific species: `Ttt_1_2`, `Rho_1`, `Rho_3_4` quantities = "" - # Custom (user-defined) field quantities: - # @type: array of strings + # Custom (user-defined) field quantities + # @type: array # @default: [] custom = "" - # Smoothing window for the output of moments (e.g., "Rho", "Charge", "T", etc.): - # @type: unsigned short + # Smoothing window for the output of moments ("Rho", "Charge", "T", ...) + # @type: ushort # @default: 0 mom_smooth = "" - # Number of timesteps between field outputs (overrides `output.interval`): - # @type: unsigned int - # @default: 0 (use `output.interval`) + # Number of timesteps between field outputs + # @type: uint + # @default: 0 + # @note: When `!= 0`, overrides `output.interval` + # @note: When `== 0`, `output.interval` is used interval = "" - # Physical (code) time interval between field outputs (overrides `output.interval_time`): + # Physical (code) time interval between field outputs # @type: float - # @default: -1.0 (use `output.interval_time`) - # @note: When `interval_time` < 0, the output is controlled by `interval`, otherwise by `interval_time` + # @default: -1.0 + # @note: When `< 0`, the output is controlled by `interval` + # @note: When specified, overrides `output.interval_time` interval_time = "" - # Downsample factor for the output of fields: - # @type: array of unsigned int >= 1 + # Downsample factor for the output of fields + # @type: uint | array [>= 1] # @default: [1, 1, 1] # @note: The output is downsampled by the given factors in each direction + # @note: If a scalar is given, it is applied to all directions downsampling = "" [output.particles] - # Toggle for the particles output: + # Toggle for the particles output # @type: bool # @default: true enable = "" - # Particle species indices to output: - # @type: array of ints - # @default: [] = all species + # Particle species indices to output + # @type: array + # @default: [] + # @note: If empty, all species are output species = "" - # Stride for the output of particles: - # @type: unsigned int: > 1 + # Stride for the output of particles + # @type: uint [> 1] # @default: 100 stride = "" - # Number of timesteps between particle outputs (overrides `output.interval`): - # @type: unsigned int: > 0 - # @default: 0 (use `output.interval`) + # Number of timesteps between particle outputs + # @type: uint + # @default: 0 + # @note: When `!= 0`, overrides `output.interval` + # @note: When `== 0`, `output.interval` is used interval = "" - # Physical (code) time interval between field outputs (overrides `output.interval_time`): + # Physical (code) time interval between particle outputs # @type: float - # @default: -1.0 (use `output.interval_time`) - # @note: When `interval_time` < 0, the output is controlled by `interval`, otherwise by `interval_time` + # @default: -1.0 + # @note: When `< 0`, the output is controlled by `interval` + # @note: When specified, overrides `output.interval_time` interval_time = "" [output.spectra] - # Toggle for the spectra output: + # Toggle for the spectra output # @type: bool # @default: true enable = "" - # Minimum energy for the spectra output: + # Minimum energy for the spectra output # @type: float # @default: 1e-3 e_min = "" - # Maximum energy for the spectra output: + # Maximum energy for the spectra output # @type: float # @default: 1e3 e_max = "" @@ -408,67 +422,70 @@ # @type: bool # @default: true log_bins = "" - # Number of bins for the spectra output: - # @type: unsigned int: > 0 + # Number of bins for the spectra output + # @type: uint [> 0] # @default: 200 n_bins = "" - # Number of timesteps between spectra outputs (overrides `output.interval`): - # @type: unsigned int: > 0 - # @default: 0 (use `output.interval`) + # Number of timesteps between spectra outputs + # @type: uint + # @default: 0 + # @note: When `!= 0`, overrides `output.interval` + # @note: When `== 0`, `output.interval` is used interval = "" - # Physical (code) time interval between spectra outputs (overrides `output.interval_time`): + # Physical (code) time interval between spectra outputs # @type: float - # @default: -1.0 (use `output.interval_time`) - # @note: When `interval_time` < 0, the output is controlled by `interval`, otherwise by `interval_time` + # @default: -1.0 + # @note: When `< 0`, the output is controlled by `interval` + # @note: When specified, overrides `output.interval_time` interval_time = "" [output.debug] - # Output fields "as is" without conversions: + # Output fields "as is" without conversions # @type: bool # @default: false as_is = "" - # Output fields with values in ghost cells: + # Output fields with values in ghost cells # @type: bool # @default: false ghosts = "" [output.stats] - # Toggle for the stats output: + # Toggle for the stats output # @type: bool # @default: true enable = "" - # Number of timesteps between stat outputs (overriden if `output.stats.interval_time != -1`): - # @type: unsigned int: > 0 + # Number of timesteps between stat outputs + # @type: uint [> 0] # @default: 100 + # @note: Overriden if `output.stats.interval_time != -1` interval = "" - # Physical (code) time interval between stat outputs: + # Physical (code) time interval between stat outputs # @type: float - # @default: -1.0 (use `output.stats.interval_time`) - # @note: When `interval_time` < 0, the output is controlled by `interval`, otherwise by `interval_time` + # @default: -1.0 + # @note: When `< 0`, the output is controlled by `interval` interval_time = "" - # Field quantities to output: - # @type: array of strings - # @valid: fields: "B^2", "E^2", "ExB" - # @valid: moments: "N", "Charge", "Rho", "T00", "T0i", "Tij" + # Field quantities to output + # @type: array # @default: ["B^2", "E^2", "ExB", "Rho", "T00"] + # @enum: "B^2", "E^2", "ExB", "N", "Charge", "Rho", "T00", "T0i", "Tij" # @note: Same notation as for `output.fields.quantities` quantities = "" - # Custom (user-defined) stats: - # @type: array of strings + # Custom (user-defined) stats + # @type: array # @default: [] custom = "" [checkpoint] - # Number of timesteps between checkpoints: - # @type: unsigned int: > 0 + # Number of timesteps between checkpoints + # @type: uint [> 0] # @default: 1000 interval = "" - # Physical (code) time interval between checkpoints: - # @type: float: > 0 - # @default: -1.0 (disabled) - # @note: When `interval_time` < 0, the output is controlled by `interval`, otherwise by `interval_time` + # Physical (code) time interval between checkpoints + # @type: float [> 0] + # @default: -1.0 + # @note: When `< 0`, the output is controlled by `interval` interval_time = "" - # Number of checkpoints to keep: + # Number of checkpoints to keep # @type: int # @default: 2 # @note: 0 = disable checkpointing @@ -476,21 +493,19 @@ keep = "" # Write a checkpoint once after a fixed walltime # @type: string - # @default: "00:00:00" (disabled) + # @default: "00:00:00" # @note: The format is "HH:MM:SS" - # @note: Useful for long-running simulations to ensure that ... - # @note: ... the simulation can be resumed after allocation expires - # @note: Empty string means disables this (still writes checkpoints on interval) - # @note: This does not exit the simulation + # @note: Empty string or "00:00:00" disables this functionality + # @note: Writing checkpoint at walltime does not stop the simulation walltime = "" # Parent directory to write checkpoints to # @type: string - # @default: ".ckpt" + # @default: `.ckpt` # @note: The directory is created if it does not exist write_path = "" # Parent directory to use when resuming from a checkpoint # @type: string - # @default: inherits from `write_path` + # @default: inherit `write_path` read_path = "" # @inferred: @@ -500,7 +515,7 @@ # @from: command-line flag # - start_step # @brief: Timestep of the checkpoint used to resume - # @type: unsigned int + # @type: uint # @from: automatically determined during restart # - start_time # @brief: Time of the checkpoint used to resume @@ -508,11 +523,11 @@ # @from: automatically determined during restart [diagnostics] - # Number of timesteps between diagnostic logs: - # @type: int: > 0 + # Number of timesteps between diagnostic logs + # @type: int [> 0] # @default: 1 interval = "" - # Blocking timers between successive algorithms: + # Blocking timers between successive algorithms # @type: bool # @default: false blocking_timers = "" @@ -520,9 +535,9 @@ # @type: bool # @default: true colored_stdout = "" - # Specify the log level: + # Specify the log level # @type: string - # @valid: "VERBOSE", "WARNING", "ERROR" # @default: "VERBOSE" - # @note: VERBOSE prints all messages, WARNING prints only warnings and errors, ERROR prints only errors + # @enum: "VERBOSE", "WARNING", "ERROR" + # @note: "VERBOSE" prints all messages, "WARNING" prints only warnings and errors, "ERROR" prints only errors log_level = "" From f6d3098f28a91fb0e75bc3ccf1ce0f8172efb58b Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Mon, 7 Jul 2025 15:31:38 -0400 Subject: [PATCH 754/773] > SR and GR: bug in deposit: wrong jx3 in 2D > GR: bug in gr range_with_axis_BCs() > GR: symmetric BC for axes > GR: small angle check for qks metric --- src/engines/grpic.hpp | 2 +- src/kernels/currents_deposit.hpp | 2 +- src/kernels/fields_bcs.hpp | 8 ++++++-- src/metrics/qkerr_schild.h | 29 ++++++++++++++++++++++------- 4 files changed, 30 insertions(+), 11 deletions(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index 168f2c730..cd04838d7 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -840,7 +840,7 @@ namespace ntt { if constexpr (M::Dim == Dim::_2D) { if (domain.mesh.flds_bc_in({ 0, +1 }) == FldsBC::AXIS) { range = CreateRangePolicy( - { domain.mesh.i_min(in::x1) - 1, domain.mesh.i_min(in::x2) }, + { domain.mesh.i_min(in::x1), domain.mesh.i_min(in::x2) }, { domain.mesh.i_max(in::x1), domain.mesh.i_max(in::x2) + 1 }); } } else if constexpr (M::Dim == Dim::_3D) { diff --git a/src/kernels/currents_deposit.hpp b/src/kernels/currents_deposit.hpp index 98d00a9b0..e0a72e56c 100644 --- a/src/kernels/currents_deposit.hpp +++ b/src/kernels/currents_deposit.hpp @@ -232,7 +232,7 @@ namespace kernel { cur::jx3) += Fx3_1 * (ONE - Wx1_1) * (ONE - Wx2_1); J_acc(i1_prev(p) + N_GHOSTS + 1, i2_prev(p) + N_GHOSTS, - cur::jx3) += Fx3_1 * Wx1_2 * (ONE - Wx2_1); + cur::jx3) += Fx3_1 * Wx1_1 * (ONE - Wx2_1); J_acc(i1_prev(p) + N_GHOSTS, i2_prev(p) + N_GHOSTS + 1, cur::jx3) += Fx3_1 * (ONE - Wx1_1) * Wx2_1; diff --git a/src/kernels/fields_bcs.hpp b/src/kernels/fields_bcs.hpp index 04e630520..4891688a6 100644 --- a/src/kernels/fields_bcs.hpp +++ b/src/kernels/fields_bcs.hpp @@ -843,21 +843,25 @@ namespace kernel::bc { if constexpr (not P) { if (setE) { Fld(i1, i_edge - 1, em::ex2) = -Fld(i1, i_edge, em::ex2); - Fld(i1, i_edge, em::ex3) = ZERO; + Fld(i1, i_edge, em::ex3) = ZERO; + Fld(i1, i_edge - 1, em::ex3) = Fld(i1, i_edge + 1, em::ex3); } if (setB) { Fld(i1, i_edge - 1, em::bx1) = Fld(i1, i_edge, em::bx1); Fld(i1, i_edge, em::bx2) = ZERO; + Fld(i1, i_edge - 1, em::bx2) = - Fld(i1, i_edge + 1, em::bx2); Fld(i1, i_edge - 1, em::bx3) = Fld(i1, i_edge, em::bx3); } } else { if (setE) { Fld(i1, i_edge, em::ex2) = -Fld(i1, i_edge - 1, em::ex2); - Fld(i1, i_edge, em::ex3) = ZERO; + Fld(i1, i_edge, em::ex3) = ZERO; + Fld(i1, i_edge + 1, em::ex3) = Fld(i1, i_edge - 1, em::ex3); } if (setB) { Fld(i1, i_edge, em::bx1) = Fld(i1, i_edge - 1, em::bx1); Fld(i1, i_edge, em::bx2) = ZERO; + Fld(i1, i_edge + 1, em::bx2) = - Fld(i1, i_edge - 1, em::bx2); Fld(i1, i_edge, em::bx3) = Fld(i1, i_edge - 1, em::bx3); } } diff --git a/src/metrics/qkerr_schild.h b/src/metrics/qkerr_schild.h index efe44611e..6ff114b42 100644 --- a/src/metrics/qkerr_schild.h +++ b/src/metrics/qkerr_schild.h @@ -39,6 +39,7 @@ namespace metric { const real_t chi_min, eta_min, phi_min; const real_t dchi, deta, dphi; const real_t dchi_inv, deta_inv, dphi_inv; + const bool small_angle; Inline auto Delta(const real_t& r) const -> real_t { return SQR(r) - TWO * r + SQR(a); @@ -89,7 +90,8 @@ namespace metric { , dphi { (x3_max - phi_min) / nx3 } , dchi_inv { ONE / dchi } , deta_inv { ONE / deta } - , dphi_inv { ONE / dphi } { + , dphi_inv { ONE / dphi } + , small_angle { eta2theta(HALF * deta) < constant::SMALL_ANGLE } { set_dxMin(find_dxMin()); } @@ -484,12 +486,25 @@ namespace metric { * @param x1 radial coordinate along the axis (code units) */ Inline auto polar_area(const real_t& x1) const -> real_t { - return dchi * math::exp(x1 * dchi + chi_min) * - (SQR(r0 + math::exp(x1 * dchi + chi_min)) + SQR(a)) * - math::sqrt( - ONE + TWO * (r0 + math::exp(x1 * dchi + chi_min)) / - (SQR(r0 + math::exp(x1 * dchi + chi_min)) + SQR(a))) * - (ONE - math::cos(eta2theta(HALF * deta))); + if constexpr (D != Dim::_1D) { + if (small_angle) { + const real_t dtheta = eta2theta(HALF * deta); + return dchi * math::exp(x1 * dchi + chi_min) * + (SQR(r0 + math::exp(x1 * dchi + chi_min)) + SQR(a)) * + math::sqrt( + ONE + TWO * (r0 + math::exp(x1 * dchi + chi_min)) / + (SQR(r0 + math::exp(x1 * dchi + chi_min)) + SQR(a))) * + (static_cast(48) - SQR(dtheta)) * SQR(dtheta) / + static_cast(384); + } else { + return dchi * math::exp(x1 * dchi + chi_min) * + (SQR(r0 + math::exp(x1 * dchi + chi_min)) + SQR(a)) * + math::sqrt( + ONE + TWO * (r0 + math::exp(x1 * dchi + chi_min)) / + (SQR(r0 + math::exp(x1 * dchi + chi_min)) + SQR(a))) * + (ONE - math::cos(eta2theta(HALF * deta))); + } + } } /** From 6e6c67559a0aca9ff1e40c7a79b917cc1ce939f9 Mon Sep 17 00:00:00 2001 From: haykh Date: Mon, 7 Jul 2025 17:36:26 -0400 Subject: [PATCH 755/773] fast Aphi calc (WIP MPI) --- src/framework/domain/output.cpp | 81 +++++++++++++++++++++++++-------- 1 file changed, 61 insertions(+), 20 deletions(-) diff --git a/src/framework/domain/output.cpp b/src/framework/domain/output.cpp index e458de0e4..6ce0c393b 100644 --- a/src/framework/domain/output.cpp +++ b/src/framework/domain/output.cpp @@ -24,6 +24,7 @@ #include "kernels/prtls_to_phys.hpp" #include +#include #include #include @@ -32,7 +33,6 @@ #endif // MPI_ENABLED #include -#include #include #include @@ -193,26 +193,66 @@ namespace ntt { unsigned short buff_idx, const Mesh mesh) { if constexpr (M::Dim == Dim::_2D) { - const auto i2_min = mesh.i_min(in::x2); - // !TODO: this is quite slow + using TeamPolicy = Kokkos::TeamPolicy; + const auto nx1 = mesh.n_active(in::x1); + const auto nx2 = mesh.n_active(in::x2); + + TeamPolicy policy(nx1, Kokkos::AUTO); + Kokkos::parallel_for( "ComputeVectorPotential", - mesh.rangeActiveCells(), - Lambda(index_t i, index_t j) { - const real_t i_ { static_cast(static_cast(i) - (N_GHOSTS)) }; - const auto k_min = (i2_min - (N_GHOSTS)) + 1; - const auto k_max = (j - (N_GHOSTS)); - real_t A3 = ZERO; - for (auto k { k_min }; k <= k_max; ++k) { - real_t k_ = static_cast(k); - real_t sqrt_detH_ij1 { mesh.metric.sqrt_det_h({ i_, k_ - HALF }) }; - real_t sqrt_detH_ij2 { mesh.metric.sqrt_det_h({ i_, k_ + HALF }) }; - auto k1 { k + N_GHOSTS }; - A3 += HALF * (sqrt_detH_ij1 * EM(i, k1 - 1, em::bx1) + - sqrt_detH_ij2 * EM(i, k1, em::bx1)); - } - buffer(i, j, buff_idx) = A3; + policy, + Lambda(const TeamPolicy::member_type& team_member) { + index_t i1 = team_member.league_rank(); + Kokkos::parallel_scan( + Kokkos::TeamThreadRange(team_member, nx2), + [=](index_t i2, real_t& update, const bool final_pass) { + const auto i1_ { static_cast(i1) }; + const auto i2_ { static_cast(i2) }; + real_t sqrt_detH_ijM { mesh.metric.sqrt_det_h({ i1_, i2_ - HALF }) }; + real_t sqrt_detH_ijP { mesh.metric.sqrt_det_h({ i1_, i2_ + HALF }) }; + const auto input_val = + HALF * + (sqrt_detH_ijM * EM(i1 + N_GHOSTS, i2 + N_GHOSTS - 1, em::bx1) + + sqrt_detH_ijP * EM(i1 + N_GHOSTS, i2 + N_GHOSTS, em::bx1)); + if (final_pass) { + buffer(i1 + N_GHOSTS, i2 + N_GHOSTS, buff_idx) = update; + } + update += input_val; + }); }); + +#if defined(MPI_ENABLED) + array_t aphi_r { "Aphi_r", nx1 }; + Kokkos::deep_copy(aphi_r, + Kokkos::subview(buffer, + std::make_pair(N_GHOSTS, N_GHOSTS + nx1), + N_GHOSTS + nx2 - 1, + buff_idx)); +#endif + + // !TODO: this is quite slow + // Kokkos::parallel_for( + // "ComputeVectorPotential", + // mesh.rangeActiveCells(), + // Lambda(index_t i1, index_t i2) { + // const real_t i1_ { COORD(i1) }; + // // const auto k_min = (i2_min - (N_GHOSTS)) + 1; + // // const auto k_max = (j - (N_GHOSTS)); + // // real_t A3 = ZERO; + // // for (auto k { k_min }; k <= k_max; ++k) { + // // real_t k_ = static_cast(k); + // // real_t sqrt_detH_ij1 { mesh.metric.sqrt_det_h({ i_, k_ - HALF }) }; + // // real_t sqrt_detH_ij2 { mesh.metric.sqrt_det_h({ i_, k_ + HALF }) }; + // // auto k1 { k + N_GHOSTS }; + // // A3 += HALF * (sqrt_detH_ij1 * EM(i, k1 - 1, em::bx1) + + // // sqrt_detH_ij2 * EM(i, k1, em::bx1)); + // // } + // buffer(i1, i2, buff_idx) = HALF * + // (sqrt_detH_ij1 * EM(i, k1 - 1, em::bx1) + + // sqrt_detH_ij2 * EM(i, k1, em::bx1)); + // }); + // buffer(:, i2_max - 1) } else { raise::KernelError( HERE, @@ -434,8 +474,9 @@ namespace ntt { c, local_domain->mesh); } else { - raise::Error("Vector potential can only be computed for GRPIC in 2D", - HERE); + raise::Error( + "Vector potential can only be computed for GRPIC in 2D", + HERE); } } else { raise::Error("Wrong # of components requested for " From bb5b03d1f2bbc636c150fe7122a3cd66dd2a0fe3 Mon Sep 17 00:00:00 2001 From: haykh Date: Mon, 7 Jul 2025 18:35:53 -0400 Subject: [PATCH 756/773] mpicomm for vector pot --- src/framework/domain/metadomain.h | 3 + src/framework/domain/output.cpp | 162 +++++++++++++++++++----------- 2 files changed, 108 insertions(+), 57 deletions(-) diff --git a/src/framework/domain/metadomain.h b/src/framework/domain/metadomain.h index efc639a86..7ddacffb3 100644 --- a/src/framework/domain/metadomain.h +++ b/src/framework/domain/metadomain.h @@ -261,6 +261,9 @@ namespace ntt { #if defined(OUTPUT_ENABLED) out::Writer g_writer; checkpoint::Writer g_checkpoint_writer; + #if defined(MPI_ENABLED) + void CommunicateVectorPotential(unsigned short); + #endif #endif #if defined(MPI_ENABLED) diff --git a/src/framework/domain/output.cpp b/src/framework/domain/output.cpp index af97febb9..347517beb 100644 --- a/src/framework/domain/output.cpp +++ b/src/framework/domain/output.cpp @@ -192,66 +192,52 @@ namespace ntt { unsigned short buff_idx, const Mesh mesh) { if constexpr (M::Dim == Dim::_2D) { - using TeamPolicy = Kokkos::TeamPolicy; - const auto nx1 = mesh.n_active(in::x1); - const auto nx2 = mesh.n_active(in::x2); - - TeamPolicy policy(nx1, Kokkos::AUTO); - - Kokkos::parallel_for( - "ComputeVectorPotential", - policy, - Lambda(const TeamPolicy::member_type& team_member) { - index_t i1 = team_member.league_rank(); - Kokkos::parallel_scan( - Kokkos::TeamThreadRange(team_member, nx2), - [=](index_t i2, real_t& update, const bool final_pass) { - const auto i1_ { static_cast(i1) }; - const auto i2_ { static_cast(i2) }; - real_t sqrt_detH_ijM { mesh.metric.sqrt_det_h({ i1_, i2_ - HALF }) }; - real_t sqrt_detH_ijP { mesh.metric.sqrt_det_h({ i1_, i2_ + HALF }) }; - const auto input_val = - HALF * - (sqrt_detH_ijM * EM(i1 + N_GHOSTS, i2 + N_GHOSTS - 1, em::bx1) + - sqrt_detH_ijP * EM(i1 + N_GHOSTS, i2 + N_GHOSTS, em::bx1)); - if (final_pass) { - buffer(i1 + N_GHOSTS, i2 + N_GHOSTS, buff_idx) = update; - } - update += input_val; - }); - }); - -#if defined(MPI_ENABLED) - array_t aphi_r { "Aphi_r", nx1 }; - Kokkos::deep_copy(aphi_r, - Kokkos::subview(buffer, - std::make_pair(N_GHOSTS, N_GHOSTS + nx1), - N_GHOSTS + nx2 - 1, - buff_idx)); -#endif - - // !TODO: this is quite slow + // using TeamPolicy = Kokkos::TeamPolicy; + // const auto nx1 = mesh.n_active(in::x1); + // const auto nx2 = mesh.n_active(in::x2); + // + // TeamPolicy policy(nx1, Kokkos::AUTO); + // // Kokkos::parallel_for( // "ComputeVectorPotential", - // mesh.rangeActiveCells(), - // Lambda(index_t i1, index_t i2) { - // const real_t i1_ { COORD(i1) }; - // // const auto k_min = (i2_min - (N_GHOSTS)) + 1; - // // const auto k_max = (j - (N_GHOSTS)); - // // real_t A3 = ZERO; - // // for (auto k { k_min }; k <= k_max; ++k) { - // // real_t k_ = static_cast(k); - // // real_t sqrt_detH_ij1 { mesh.metric.sqrt_det_h({ i_, k_ - HALF }) }; - // // real_t sqrt_detH_ij2 { mesh.metric.sqrt_det_h({ i_, k_ + HALF }) }; - // // auto k1 { k + N_GHOSTS }; - // // A3 += HALF * (sqrt_detH_ij1 * EM(i, k1 - 1, em::bx1) + - // // sqrt_detH_ij2 * EM(i, k1, em::bx1)); - // // } - // buffer(i1, i2, buff_idx) = HALF * - // (sqrt_detH_ij1 * EM(i, k1 - 1, em::bx1) + - // sqrt_detH_ij2 * EM(i, k1, em::bx1)); + // policy, + // Lambda(const TeamPolicy::member_type& team_member) { + // index_t i1 = team_member.league_rank(); + // Kokkos::parallel_scan( + // Kokkos::TeamThreadRange(team_member, nx2), + // [=](index_t i2, real_t& update, const bool final_pass) { + // const auto i1_ { static_cast(i1) }; + // const auto i2_ { static_cast(i2) }; + // real_t sqrt_detH_ijM { mesh.metric.sqrt_det_h({ i1_, i2_ - HALF }) }; + // real_t sqrt_detH_ijP { mesh.metric.sqrt_det_h({ i1_, i2_ + HALF }) }; + // const auto input_val = + // HALF * + // (sqrt_detH_ijM * EM(i1 + N_GHOSTS, i2 + N_GHOSTS - 1, em::bx1) + + // sqrt_detH_ijP * EM(i1 + N_GHOSTS, i2 + N_GHOSTS, em::bx1)); + // if (final_pass) { + // buffer(i1 + N_GHOSTS, i2 + N_GHOSTS, buff_idx) = update; + // } + // update += input_val; + // }); // }); - // buffer(:, i2_max - 1) + Kokkos::parallel_for( + "ComputeVectorPotential", + mesh.rangeActiveCells(), + Lambda(index_t i1, index_t i2) { + const real_t i1_ { COORD(i1) }; + const ncells_t k_min = 1; + const ncells_t k_max = (i2 - (N_GHOSTS)); + real_t A3 = ZERO; + for (auto k { k_min }; k <= k_max; ++k) { + real_t k_ = static_cast(k); + real_t sqrt_detH_ij1 { mesh.metric.sqrt_det_h({ i1_, k_ - HALF }) }; + real_t sqrt_detH_ij2 { mesh.metric.sqrt_det_h({ i1_, k_ + HALF }) }; + auto k1 { k + N_GHOSTS }; + A3 += HALF * (sqrt_detH_ij1 * EM(i1, k - 1, em::bx1) + + sqrt_detH_ij2 * EM(i1, k, em::bx1)); + } + buffer(i1, i2, buff_idx) = A3; + }); } else { raise::KernelError( HERE, @@ -259,6 +245,65 @@ namespace ntt { } } +#if defined(MPI_ENABLED) && defined(OUTPUT_ENABLED) + template + void Metadomain::CommunicateVectorPotential(unsigned short buff_idx) { + if constexpr (M::Dim == Dim::_2D) { + auto local_domain = subdomain_ptr(l_subdomain_indices()[0]); + const auto nx1 = local_domain->mesh.n_active(in::x1); + const auto nx2 = local_domain->mesh.n_active(in::x2); + + auto& buffer = local_domain->fields.bckp; + + const auto nranks_x1 = ndomains_per_dim()[0]; + const auto nranks_x2 = ndomains_per_dim()[1]; + + for (auto nr2 { 1u }; nr2 < nranks_x2; ++nr2) { + const auto rank_send_pre = (nr2 - 1u) * nranks_x1; + const auto rank_recv_pre = nr2 * nranks_x1; + for (auto nr1 { 0u }; nr1 < nranks_x1; ++nr1) { + const auto rank_send = rank_send_pre + nr1; + const auto rank_recv = rank_recv_pre + nr1; + if (local_domain->mpi_rank() == rank_send) { + array_t aphi_r { "Aphi_r", nx1 }; + Kokkos::deep_copy( + aphi_r, + Kokkos::subview(buffer, + std::make_pair(N_GHOSTS, N_GHOSTS + nx1), + N_GHOSTS + nx2 - 1, + buff_idx)); + MPI_Send(aphi_r.data(), + nx1, + mpi::get_type(), + rank_recv, + 0, + MPI_COMM_WORLD); + } else if (local_domain->mpi_rank() == rank_recv) { + array_t aphi_r { "Aphi_r", nx1 }; + MPI_Recv(aphi_r.data(), + nx1, + mpi::get_type(), + rank_send, + 0, + MPI_COMM_WORLD, + MPI_STATUS_IGNORE); + Kokkos::parallel_for( + "AddVectorPotential", + local_domain->mesh.rangeActiveCells(), + Lambda(index_t i1, index_t i2) { + buffer(i1, i2, buff_idx) += aphi_r(i1 - N_GHOSTS); + }); + } + } + } + } else { + raise::Error("CommunicateVectorPotential: comm vector potential only " + "possible for 2D", + HERE); + } + } +#endif + template auto Metadomain::Write( const SimulationParams& params, @@ -472,6 +517,9 @@ namespace ntt { local_domain->fields.em, c, local_domain->mesh); +#if defined(MPI_ENABLED) + CommunicateVectorPotential(c); +#endif } else { raise::Error( "Vector potential can only be computed for GRPIC in 2D", From 5bf3be304ee7e52c66394f08ad5cbe252f166858 Mon Sep 17 00:00:00 2001 From: haykh Date: Mon, 7 Jul 2025 18:45:42 -0400 Subject: [PATCH 757/773] template spec --- src/framework/domain/output.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/framework/domain/output.cpp b/src/framework/domain/output.cpp index 347517beb..fd4787eb0 100644 --- a/src/framework/domain/output.cpp +++ b/src/framework/domain/output.cpp @@ -860,7 +860,8 @@ namespace ntt { index_t, \ timestep_t, \ simtime_t, \ - const Domain&)>) -> bool; + const Domain&)>) -> bool; \ + template void Metadomain::CommunicateVectorPotential(unsigned short); METADOMAIN_OUTPUT(SimEngine::SRPIC, metric::Minkowski) METADOMAIN_OUTPUT(SimEngine::SRPIC, metric::Minkowski) From d9a7a4bbc86bcc1f4c0613c582290d7e4539faa9 Mon Sep 17 00:00:00 2001 From: haykh Date: Mon, 7 Jul 2025 18:59:07 -0400 Subject: [PATCH 758/773] extract vector potential to outside func --- src/framework/domain/output.cpp | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/framework/domain/output.cpp b/src/framework/domain/output.cpp index fd4787eb0..b73b87caf 100644 --- a/src/framework/domain/output.cpp +++ b/src/framework/domain/output.cpp @@ -246,6 +246,19 @@ namespace ntt { } #if defined(MPI_ENABLED) && defined(OUTPUT_ENABLED) + template + void ExtractVectorPotential(ndfield_t& buffer, + array_t& aphi_r, + unsigned short buff_idx, + const Mesh mesh) { + Kokkos::parallel_for( + "AddVectorPotential", + mesh.rangeActiveCells(), + Lambda(index_t i1, index_t i2) { + buffer(i1, i2, buff_idx) += aphi_r(i1 - N_GHOSTS); + }); + } + template void Metadomain::CommunicateVectorPotential(unsigned short buff_idx) { if constexpr (M::Dim == Dim::_2D) { @@ -287,12 +300,7 @@ namespace ntt { 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE); - Kokkos::parallel_for( - "AddVectorPotential", - local_domain->mesh.rangeActiveCells(), - Lambda(index_t i1, index_t i2) { - buffer(i1, i2, buff_idx) += aphi_r(i1 - N_GHOSTS); - }); + ExtractVectorPotential(buffer, aphi_r, buff_idx, local_domain->mesh); } } } From a35451b21bde10949bf7abbd2946d6ed9fb1e55a Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Mon, 7 Jul 2025 19:37:50 -0400 Subject: [PATCH 759/773] minor adjustments of indexes --- src/framework/domain/output.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/framework/domain/output.cpp b/src/framework/domain/output.cpp index b73b87caf..7109bc078 100644 --- a/src/framework/domain/output.cpp +++ b/src/framework/domain/output.cpp @@ -220,12 +220,13 @@ namespace ntt { // update += input_val; // }); // }); + // TODO: this is slow Kokkos::parallel_for( "ComputeVectorPotential", mesh.rangeActiveCells(), Lambda(index_t i1, index_t i2) { const real_t i1_ { COORD(i1) }; - const ncells_t k_min = 1; + const ncells_t k_min = 0; const ncells_t k_max = (i2 - (N_GHOSTS)); real_t A3 = ZERO; for (auto k { k_min }; k <= k_max; ++k) { @@ -233,8 +234,8 @@ namespace ntt { real_t sqrt_detH_ij1 { mesh.metric.sqrt_det_h({ i1_, k_ - HALF }) }; real_t sqrt_detH_ij2 { mesh.metric.sqrt_det_h({ i1_, k_ + HALF }) }; auto k1 { k + N_GHOSTS }; - A3 += HALF * (sqrt_detH_ij1 * EM(i1, k - 1, em::bx1) + - sqrt_detH_ij2 * EM(i1, k, em::bx1)); + A3 += HALF * (sqrt_detH_ij1 * EM(i1, k + N_GHOSTS - 1, em::bx1) + + sqrt_detH_ij2 * EM(i1, k + N_GHOSTS, em::bx1)); } buffer(i1, i2, buff_idx) = A3; }); From 5260eca5d7ed643feba0557f590a162863c2a6bd Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Mon, 14 Jul 2025 15:05:29 -0400 Subject: [PATCH 760/773] added metric.alpha for velocity in gr deposit. important for the out-of-plane current --- src/kernels/currents_deposit.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/kernels/currents_deposit.hpp b/src/kernels/currents_deposit.hpp index e0a72e56c..00efde011 100644 --- a/src/kernels/currents_deposit.hpp +++ b/src/kernels/currents_deposit.hpp @@ -130,7 +130,7 @@ namespace kernel { metric.template transform(xp, { ux1(p), ux2(p), ux3(p) }, vp); - inv_energy = ONE / math::sqrt(ONE + ux1(p) * vp[0] + ux2(p) * vp[1] + + inv_energy = metric.alpha(xp_) / math::sqrt(ONE + ux1(p) * vp[0] + ux2(p) * vp[1] + ux3(p) * vp[2]); } if (Kokkos::isnan(vp[2]) || Kokkos::isinf(vp[2])) { From 8ed46d0cf2727952f6827ccfd018890614c4c572 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Mon, 14 Jul 2025 15:09:58 -0400 Subject: [PATCH 761/773] fixed coordinate for deposit --- src/kernels/currents_deposit.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/kernels/currents_deposit.hpp b/src/kernels/currents_deposit.hpp index 00efde011..44bc52fdb 100644 --- a/src/kernels/currents_deposit.hpp +++ b/src/kernels/currents_deposit.hpp @@ -130,7 +130,7 @@ namespace kernel { metric.template transform(xp, { ux1(p), ux2(p), ux3(p) }, vp); - inv_energy = metric.alpha(xp_) / math::sqrt(ONE + ux1(p) * vp[0] + ux2(p) * vp[1] + + inv_energy = metric.alpha(xp) / math::sqrt(ONE + ux1(p) * vp[0] + ux2(p) * vp[1] + ux3(p) * vp[2]); } if (Kokkos::isnan(vp[2]) || Kokkos::isinf(vp[2])) { From 55df3f1145ee026bc81fddf515758b0c430b02ea Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Mon, 14 Jul 2025 15:18:04 -0400 Subject: [PATCH 762/773] added check for particles close to the axis. the "closeness" is defined by a new constant --- src/global/utils/numeric.h | 25 +++++++++++++------------ src/kernels/particle_pusher_gr.hpp | 16 +++++++++++++++- 2 files changed, 28 insertions(+), 13 deletions(-) diff --git a/src/global/utils/numeric.h b/src/global/utils/numeric.h index afd662335..a3385336a 100644 --- a/src/global/utils/numeric.h +++ b/src/global/utils/numeric.h @@ -80,18 +80,19 @@ inline constexpr double INV_64 = 0.015625; #define CROSS_x3(ax1, ax2, ax3, bx1, bx2, bx3) ((ax1) * (bx2) - (ax2) * (bx1)) namespace constant { - inline constexpr std::uint64_t RandomSeed = 0x123456789abcdef0; - inline constexpr double HALF_PI = 1.57079632679489661923; - inline constexpr double PI = 3.14159265358979323846; - inline constexpr double INV_PI = 0.31830988618379067154; - inline constexpr double PI_SQR = 9.86960440108935861882; - inline constexpr double INV_PI_SQR = 0.10132118364233777144; - inline constexpr double TWO_PI = 6.28318530717958647692; - inline constexpr double E = 2.71828182845904523536; - inline constexpr double SQRT2 = 1.41421356237309504880; - inline constexpr double INV_SQRT2 = 0.70710678118654752440; - inline constexpr double SQRT3 = 1.73205080756887729352; - inline constexpr double SMALL_ANGLE = 1e-3; + inline constexpr std::uint64_t RandomSeed = 0x123456789abcdef0; + inline constexpr double HALF_PI = 1.57079632679489661923; + inline constexpr double PI = 3.14159265358979323846; + inline constexpr double INV_PI = 0.31830988618379067154; + inline constexpr double PI_SQR = 9.86960440108935861882; + inline constexpr double INV_PI_SQR = 0.10132118364233777144; + inline constexpr double TWO_PI = 6.28318530717958647692; + inline constexpr double E = 2.71828182845904523536; + inline constexpr double SQRT2 = 1.41421356237309504880; + inline constexpr double INV_SQRT2 = 0.70710678118654752440; + inline constexpr double SQRT3 = 1.73205080756887729352; + inline constexpr double SMALL_ANGLE = 1e-3; + inline constexpr double SMALL_ANGLE_GR = 1e-5; } // namespace constant namespace convert { diff --git a/src/kernels/particle_pusher_gr.hpp b/src/kernels/particle_pusher_gr.hpp index 2318d5436..15e4dd04c 100644 --- a/src/kernels/particle_pusher_gr.hpp +++ b/src/kernels/particle_pusher_gr.hpp @@ -678,6 +678,20 @@ namespace kernel::gr { xp[0] = i_di_to_Xi(i1(p), dx1(p)); xp[1] = i_di_to_Xi(i2(p), dx2(p)); + coord_t xp_ { ZERO }; + xp_[0] = xp[0]; + xp_[1] = xp[1]; + real_t theta_Cd { xp[1] }; + const real_t theta_Ph { metric.template convert<2, Crd::Cd, Crd::Ph>(theta_Cd) }; + const real_t small_angle { constant::SMALL_ANGLE_GR }; + const auto large_angle { constant::PI - small_angle }; + if (theta_Ph < small_angle) { + theta_Cd = metric.template convert<2, Crd::Ph, Crd::Cd>(small_angle); + } else if (theta_Ph >= large_angle) { + theta_Cd = metric.template convert<2, Crd::Ph, Crd::Cd>(large_angle); + } + xp_[1] = theta_Cd; + vec_t Dp_cntrv { ZERO }, Bp_cntrv { ZERO }, Dp_hat { ZERO }, Bp_hat { ZERO }; interpolateFields(p, Dp_cntrv, Bp_cntrv); @@ -694,7 +708,7 @@ namespace kernel::gr { vp[0] = vp_upd[0]; vp[1] = vp_upd[1]; vp[2] = vp_upd[2]; - GeodesicMomentumPush(Massive_t {}, xp, vp, vp_upd); + GeodesicMomentumPush(Massive_t {}, xp_, vp, vp_upd); /* u**_i(n) -> u_i(n + 1/2) */ vp[0] = vp_upd[0]; vp[1] = vp_upd[1]; From 8b692a5fbb1db566d721b616cb39628d59898aea Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Mon, 14 Jul 2025 15:29:32 -0400 Subject: [PATCH 763/773] added axis check in the GR deposit --- src/kernels/currents_deposit.hpp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/kernels/currents_deposit.hpp b/src/kernels/currents_deposit.hpp index 44bc52fdb..06eeadad8 100644 --- a/src/kernels/currents_deposit.hpp +++ b/src/kernels/currents_deposit.hpp @@ -127,10 +127,22 @@ namespace kernel { vp); inv_energy = ONE / math::sqrt(ONE + NORM_SQR(ux1(p), ux2(p), ux3(p))); } else { - metric.template transform(xp, + coord_t xp_ { ZERO }; + xp_[0] = xp[0]; + real_t theta_Cd { xp[1] }; + const real_t theta_Ph { metric.template convert<2, Crd::Cd, Crd::Ph>(theta_Cd) }; + const real_t small_angle { constant::SMALL_ANGLE_GR }; + const auto large_angle { constant::PI - small_angle }; + if (theta_Ph < small_angle) { + theta_Cd = metric.template convert<2, Crd::Ph, Crd::Cd>(small_angle); + } else if (theta_Ph >= large_angle) { + theta_Cd = metric.template convert<2, Crd::Ph, Crd::Cd>(large_angle); + } + xp_[1] = theta_Cd; + metric.template transform(xp_, { ux1(p), ux2(p), ux3(p) }, vp); - inv_energy = metric.alpha(xp) / math::sqrt(ONE + ux1(p) * vp[0] + ux2(p) * vp[1] + + inv_energy = metric.alpha(xp_) / math::sqrt(ONE + ux1(p) * vp[0] + ux2(p) * vp[1] + ux3(p) * vp[2]); } if (Kokkos::isnan(vp[2]) || Kokkos::isinf(vp[2])) { From a4965f130b3e601ffc5bf5683490821feb407740 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Mon, 14 Jul 2025 16:51:22 -0400 Subject: [PATCH 764/773] minor (deleted useless line) --- src/kernels/particle_pusher_gr.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/kernels/particle_pusher_gr.hpp b/src/kernels/particle_pusher_gr.hpp index 15e4dd04c..1eb12494e 100644 --- a/src/kernels/particle_pusher_gr.hpp +++ b/src/kernels/particle_pusher_gr.hpp @@ -680,7 +680,6 @@ namespace kernel::gr { coord_t xp_ { ZERO }; xp_[0] = xp[0]; - xp_[1] = xp[1]; real_t theta_Cd { xp[1] }; const real_t theta_Ph { metric.template convert<2, Crd::Cd, Crd::Ph>(theta_Cd) }; const real_t small_angle { constant::SMALL_ANGLE_GR }; From f5ca864c3e2419ca0a1c516f7e839e830d897e3c Mon Sep 17 00:00:00 2001 From: haykh Date: Tue, 15 Jul 2025 17:11:10 -0400 Subject: [PATCH 765/773] aphi with teampolicy --- dev/nix/kokkos.nix | 1 + src/framework/domain/output.cpp | 87 +++++++++++++++------------------ 2 files changed, 41 insertions(+), 47 deletions(-) diff --git a/dev/nix/kokkos.nix b/dev/nix/kokkos.nix index e12b9d57d..b9373015b 100644 --- a/dev/nix/kokkos.nix +++ b/dev/nix/kokkos.nix @@ -13,6 +13,7 @@ let rocm-core clr rocthrust + llvm.rocm-merged-llvm rocprim rocminfo rocm-smi diff --git a/src/framework/domain/output.cpp b/src/framework/domain/output.cpp index 7109bc078..9d59367dd 100644 --- a/src/framework/domain/output.cpp +++ b/src/framework/domain/output.cpp @@ -192,52 +192,35 @@ namespace ntt { unsigned short buff_idx, const Mesh mesh) { if constexpr (M::Dim == Dim::_2D) { - // using TeamPolicy = Kokkos::TeamPolicy; - // const auto nx1 = mesh.n_active(in::x1); - // const auto nx2 = mesh.n_active(in::x2); - // - // TeamPolicy policy(nx1, Kokkos::AUTO); - // - // Kokkos::parallel_for( - // "ComputeVectorPotential", - // policy, - // Lambda(const TeamPolicy::member_type& team_member) { - // index_t i1 = team_member.league_rank(); - // Kokkos::parallel_scan( - // Kokkos::TeamThreadRange(team_member, nx2), - // [=](index_t i2, real_t& update, const bool final_pass) { - // const auto i1_ { static_cast(i1) }; - // const auto i2_ { static_cast(i2) }; - // real_t sqrt_detH_ijM { mesh.metric.sqrt_det_h({ i1_, i2_ - HALF }) }; - // real_t sqrt_detH_ijP { mesh.metric.sqrt_det_h({ i1_, i2_ + HALF }) }; - // const auto input_val = - // HALF * - // (sqrt_detH_ijM * EM(i1 + N_GHOSTS, i2 + N_GHOSTS - 1, em::bx1) + - // sqrt_detH_ijP * EM(i1 + N_GHOSTS, i2 + N_GHOSTS, em::bx1)); - // if (final_pass) { - // buffer(i1 + N_GHOSTS, i2 + N_GHOSTS, buff_idx) = update; - // } - // update += input_val; - // }); - // }); - // TODO: this is slow + using TeamPolicy = Kokkos::TeamPolicy; + const auto nx1 = mesh.n_active(in::x1); + const auto nx2 = mesh.n_active(in::x2); + + TeamPolicy policy(nx1, Kokkos::AUTO); + + const auto metric = mesh.metric; + Kokkos::parallel_for( "ComputeVectorPotential", - mesh.rangeActiveCells(), - Lambda(index_t i1, index_t i2) { - const real_t i1_ { COORD(i1) }; - const ncells_t k_min = 0; - const ncells_t k_max = (i2 - (N_GHOSTS)); - real_t A3 = ZERO; - for (auto k { k_min }; k <= k_max; ++k) { - real_t k_ = static_cast(k); - real_t sqrt_detH_ij1 { mesh.metric.sqrt_det_h({ i1_, k_ - HALF }) }; - real_t sqrt_detH_ij2 { mesh.metric.sqrt_det_h({ i1_, k_ + HALF }) }; - auto k1 { k + N_GHOSTS }; - A3 += HALF * (sqrt_detH_ij1 * EM(i1, k + N_GHOSTS - 1, em::bx1) + - sqrt_detH_ij2 * EM(i1, k + N_GHOSTS, em::bx1)); - } - buffer(i1, i2, buff_idx) = A3; + policy, + Lambda(const TeamPolicy::member_type& team_member) { + index_t i1 = team_member.league_rank(); + Kokkos::parallel_scan( + Kokkos::TeamThreadRange(team_member, nx2), + [=](index_t i2, real_t& update, const bool final_pass) { + const auto i1_ { static_cast(i1) }; + const auto i2_ { static_cast(i2) }; + real_t sqrt_detH_ijM { metric.sqrt_det_h({ i1_, i2_ - HALF }) }; + real_t sqrt_detH_ijP { metric.sqrt_det_h({ i1_, i2_ + HALF }) }; + const auto input_val = + HALF * + (sqrt_detH_ijM * EM(i1 + N_GHOSTS, i2 + N_GHOSTS - 1, em::bx1) + + sqrt_detH_ijP * EM(i1 + N_GHOSTS, i2 + N_GHOSTS, em::bx1)); + update += input_val; + if (final_pass) { + buffer(i1 + N_GHOSTS, i2 + N_GHOSTS, buff_idx) = update; + } + }); }); } else { raise::KernelError( @@ -520,7 +503,7 @@ namespace ntt { HERE); } } else if (fld.is_vpotential()) { - if (S == SimEngine::GRPIC && M::Dim == Dim::_2D) { + if constexpr (S == SimEngine::GRPIC && M::Dim == Dim::_2D) { const auto c = static_cast(addresses.back()); ComputeVectorPotential(local_domain->fields.bckp, local_domain->fields.em, @@ -869,8 +852,7 @@ namespace ntt { index_t, \ timestep_t, \ simtime_t, \ - const Domain&)>) -> bool; \ - template void Metadomain::CommunicateVectorPotential(unsigned short); + const Domain&)>) -> bool; METADOMAIN_OUTPUT(SimEngine::SRPIC, metric::Minkowski) METADOMAIN_OUTPUT(SimEngine::SRPIC, metric::Minkowski) @@ -883,4 +865,15 @@ namespace ntt { #undef METADOMAIN_OUTPUT +#if defined(MPI_ENABLED) + #define COMMVECTORPOTENTIAL(S, M) \ + template void Metadomain::CommunicateVectorPotential(unsigned short); + + COMMVECTORPOTENTIAL(SimEngine::GRPIC, metric::KerrSchild) + COMMVECTORPOTENTIAL(SimEngine::GRPIC, metric::QKerrSchild) + COMMVECTORPOTENTIAL(SimEngine::GRPIC, metric::KerrSchild0) + + #undef COMMVECTORPOTENTIAL +#endif + } // namespace ntt From 4612481440c409c20da3b47a36ef03a27ff58ee7 Mon Sep 17 00:00:00 2001 From: haykh Date: Tue, 15 Jul 2025 21:30:00 -0400 Subject: [PATCH 766/773] wald toml fixed (slightly) --- dev/nix/kokkos.nix | 6 +++--- dev/nix/shell.nix | 3 --- pgens/wald/wald.toml | 7 +++---- 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/dev/nix/kokkos.nix b/dev/nix/kokkos.nix index b9373015b..2f6ee6b99 100644 --- a/dev/nix/kokkos.nix +++ b/dev/nix/kokkos.nix @@ -10,20 +10,22 @@ let pversion = "4.6.01"; compilerPkgs = { "HIP" = with pkgs.rocmPackages; [ + llvm.rocm-merged-llvm rocm-core clr rocthrust - llvm.rocm-merged-llvm rocprim rocminfo rocm-smi ]; "CUDA" = with pkgs.cudaPackages; [ + llvmPackages_18.clang-tools cudatoolkit cuda_cudart pkgs.gcc13 ]; "NONE" = [ + pkgs.llvmPackages_18.clang-tools pkgs.gcc13 ]; }; @@ -37,9 +39,7 @@ let "HIP" = [ "-D Kokkos_ENABLE_HIP=ON" "-D Kokkos_ARCH_${getArch { }}=ON" - # remove leading AMD_ "-D AMDGPU_TARGETS=${builtins.replaceStrings [ "amd_" ] [ "" ] (pkgs.lib.toLower (getArch { }))}" - "-D CMAKE_C_COMPILER=hipcc" "-D CMAKE_CXX_COMPILER=hipcc" ]; "CUDA" = [ diff --git a/dev/nix/shell.nix b/dev/nix/shell.nix index ae5451ec8..33ae57095 100644 --- a/dev/nix/shell.nix +++ b/dev/nix/shell.nix @@ -42,9 +42,6 @@ pkgs.mkShell { zlib cmake - llvmPackages_18.clang-tools - libgcc - adios2Pkg kokkosPkg diff --git a/pgens/wald/wald.toml b/pgens/wald/wald.toml index 1104f7a08..75a3ef2e6 100644 --- a/pgens/wald/wald.toml +++ b/pgens/wald/wald.toml @@ -4,11 +4,11 @@ runtime = 100.0 [grid] - resolution = [128, 128] + resolution = [512, 512] extent = [[1.0, 10.0]] [grid.metric] - metric = "kerr_schild" + metric = "qkerr_schild" qsph_r0 = 0.0 qsph_h = 0.0 ks_a = 0.95 @@ -40,8 +40,7 @@ [setup] [output] - format = "hdf5" - separate_files = false + format = "hdf5" [output.fields] interval_time = 1.0 From 5c481aa39c889869dc3f5b596297779b74f46344 Mon Sep 17 00:00:00 2001 From: haykh Date: Tue, 15 Jul 2025 21:50:39 -0400 Subject: [PATCH 767/773] added vertical field support in wald --- pgens/wald/pgen.hpp | 217 ++++++++++++++++++++++++++----------------- pgens/wald/wald.toml | 1 + 2 files changed, 134 insertions(+), 84 deletions(-) diff --git a/pgens/wald/pgen.hpp b/pgens/wald/pgen.hpp index b2c2aeb0c..71ee905e3 100644 --- a/pgens/wald/pgen.hpp +++ b/pgens/wald/pgen.hpp @@ -7,6 +7,7 @@ #include "arch/kokkos_aliases.h" #include "arch/traits.h" #include "utils/comparators.h" +#include "utils/error.h" #include "utils/formatting.h" #include "utils/log.h" #include "utils/numeric.h" @@ -17,14 +18,31 @@ #include "framework/domain/domain.h" #include "framework/domain/metadomain.h" +#include #include +enum InitFieldGeometry { + Wald, + Vertical, +}; + namespace user { using namespace ntt; template struct InitFields { - InitFields(M metric_) : metric { metric_ } {} + InitFields(M metric_, const std::string& init_field_geometry) + : metric { metric_ } { + if (init_field_geometry == "wald") { + field_geometry = InitFieldGeometry::Wald; + } else if (init_field_geometry == "vertical") { + field_geometry = InitFieldGeometry::Vertical; + } else { + raise::Error(fmt::format("Unrecognized field geometry: %s", + init_field_geometry.c_str()), + HERE); + } + } Inline auto A_3(const coord_t& x_Cd) const -> real_t { return HALF * (metric.template h_<3, 3>(x_Cd) + @@ -83,102 +101,132 @@ namespace user { Inline auto bx3( const coord_t& x_Ph) const -> real_t { // at ( i + HALF , j + HALF ) - coord_t xi { ZERO }, x0m { ZERO }, x0p { ZERO }; - metric.template convert(x_Ph, xi); - - x0m[0] = xi[0]; - x0m[1] = xi[1] - HALF; - x0p[0] = xi[0]; - x0p[1] = xi[1] + HALF; - - real_t inv_sqrt_detH_iPjP { ONE / metric.sqrt_det_h({ xi[0], xi[1] }) }; - return -(A_1(x0p) - A_1(x0m)) * inv_sqrt_detH_iPjP; + if (field_geometry == InitFieldGeometry::Wald) { + coord_t xi { ZERO }, x0m { ZERO }, x0p { ZERO }; + metric.template convert(x_Ph, xi); + + x0m[0] = xi[0]; + x0m[1] = xi[1] - HALF; + x0p[0] = xi[0]; + x0p[1] = xi[1] + HALF; + + real_t inv_sqrt_detH_iPjP { ONE / metric.sqrt_det_h({ xi[0], xi[1] }) }; + return -(A_1(x0p) - A_1(x0m)) * inv_sqrt_detH_iPjP; + } else if (field_geometry == InitFieldGeometry::Vertical) { + return ZERO; + } else { + raise::KernelError(HERE, "Unrecognized field geometry"); + return ZERO; + } } Inline auto dx1(const coord_t& x_Ph) const -> real_t { // at ( i + HALF , j ) - coord_t xi { ZERO }, x0m { ZERO }, x0p { ZERO }; - metric.template convert(x_Ph, xi); - - real_t alpha_iPj { metric.alpha({ xi[0], xi[1] }) }; - real_t inv_sqrt_detH_ij { ONE / metric.sqrt_det_h({ xi[0] - HALF, xi[1] }) }; - real_t sqrt_detH_ij { metric.sqrt_det_h({ xi[0] - HALF, xi[1] }) }; - real_t beta_ij { metric.beta1({ xi[0] - HALF, xi[1] }) }; - real_t alpha_ij { metric.alpha({ xi[0] - HALF, xi[1] }) }; - - // D1 at ( i + HALF , j ) - x0m[0] = xi[0] - HALF; - x0m[1] = xi[1]; - x0p[0] = xi[0] + HALF; - x0p[1] = xi[1]; - real_t E1d { (A_0(x0p) - A_0(x0m)) }; - real_t D1d { E1d / alpha_iPj }; - - // D3 at ( i , j ) - x0m[0] = xi[0] - HALF - HALF; - x0m[1] = xi[1]; - x0p[0] = xi[0] - HALF + HALF; - x0p[1] = xi[1]; - real_t D3d { (A_3(x0p) - A_3(x0m)) * beta_ij / alpha_ij }; - - real_t D1u { metric.template h<1, 1>({ xi[0], xi[1] }) * D1d + - metric.template h<1, 3>({ xi[0], xi[1] }) * D3d }; - - return D1u; + if (field_geometry == InitFieldGeometry::Wald) { + coord_t xi { ZERO }, x0m { ZERO }, x0p { ZERO }; + metric.template convert(x_Ph, xi); + + real_t alpha_iPj { metric.alpha({ xi[0], xi[1] }) }; + real_t inv_sqrt_detH_ij { ONE / metric.sqrt_det_h({ xi[0] - HALF, xi[1] }) }; + real_t sqrt_detH_ij { metric.sqrt_det_h({ xi[0] - HALF, xi[1] }) }; + real_t beta_ij { metric.beta1({ xi[0] - HALF, xi[1] }) }; + real_t alpha_ij { metric.alpha({ xi[0] - HALF, xi[1] }) }; + + // D1 at ( i + HALF , j ) + x0m[0] = xi[0] - HALF; + x0m[1] = xi[1]; + x0p[0] = xi[0] + HALF; + x0p[1] = xi[1]; + real_t E1d { (A_0(x0p) - A_0(x0m)) }; + real_t D1d { E1d / alpha_iPj }; + + // D3 at ( i , j ) + x0m[0] = xi[0] - HALF - HALF; + x0m[1] = xi[1]; + x0p[0] = xi[0] - HALF + HALF; + x0p[1] = xi[1]; + real_t D3d { (A_3(x0p) - A_3(x0m)) * beta_ij / alpha_ij }; + + real_t D1u { metric.template h<1, 1>({ xi[0], xi[1] }) * D1d + + metric.template h<1, 3>({ xi[0], xi[1] }) * D3d }; + + return D1u; + } else if (field_geometry == InitFieldGeometry::Vertical) { + return ZERO; + } else { + raise::KernelError(HERE, "Unrecognized field geometry"); + return ZERO; + } } Inline auto dx2(const coord_t& x_Ph) const -> real_t { // at ( i , j + HALF ) - coord_t xi { ZERO }, x0m { ZERO }, x0p { ZERO }; - metric.template convert(x_Ph, xi); - x0m[0] = xi[0]; - x0m[1] = xi[1] - HALF; - x0p[0] = xi[0]; - x0p[1] = xi[1] + HALF; - real_t inv_sqrt_detH_ijP { ONE / metric.sqrt_det_h({ xi[0], xi[1] }) }; - real_t sqrt_detH_ijP { metric.sqrt_det_h({ xi[0], xi[1] }) }; - real_t alpha_ijP { metric.alpha({ xi[0], xi[1] }) }; - real_t beta_ijP { metric.beta1({ xi[0], xi[1] }) }; - - real_t E2d { (A_0(x0p) - A_0(x0m)) }; - real_t D2d { E2d / alpha_ijP - (A_1(x0p) - A_1(x0m)) * beta_ijP / alpha_ijP }; - real_t D2u { metric.template h<2, 2>({ xi[0], xi[1] }) * D2d }; - - return D2u; + if (field_geometry == InitFieldGeometry::Wald) { + coord_t xi { ZERO }, x0m { ZERO }, x0p { ZERO }; + metric.template convert(x_Ph, xi); + x0m[0] = xi[0]; + x0m[1] = xi[1] - HALF; + x0p[0] = xi[0]; + x0p[1] = xi[1] + HALF; + real_t inv_sqrt_detH_ijP { ONE / metric.sqrt_det_h({ xi[0], xi[1] }) }; + real_t sqrt_detH_ijP { metric.sqrt_det_h({ xi[0], xi[1] }) }; + real_t alpha_ijP { metric.alpha({ xi[0], xi[1] }) }; + real_t beta_ijP { metric.beta1({ xi[0], xi[1] }) }; + + real_t E2d { (A_0(x0p) - A_0(x0m)) }; + real_t D2d { E2d / alpha_ijP - + (A_1(x0p) - A_1(x0m)) * beta_ijP / alpha_ijP }; + real_t D2u { metric.template h<2, 2>({ xi[0], xi[1] }) * D2d }; + + return D2u; + } else if (field_geometry == InitFieldGeometry::Vertical) { + return ZERO; + } else { + raise::KernelError(HERE, "Unrecognized field geometry"); + return ZERO; + } } Inline auto dx3(const coord_t& x_Ph) const -> real_t { // at ( i , j ) - coord_t xi { ZERO }, x0m { ZERO }, x0p { ZERO }; - metric.template convert(x_Ph, xi); - real_t inv_sqrt_detH_ij { ONE / metric.sqrt_det_h({ xi[0], xi[1] }) }; - real_t sqrt_detH_ij { metric.sqrt_det_h({ xi[0], xi[1] }) }; - real_t beta_ij { metric.beta1({ xi[0], xi[1] }) }; - real_t alpha_ij { metric.alpha({ xi[0], xi[1] }) }; - real_t alpha_iPj { metric.alpha({ xi[0] + HALF, xi[1] }) }; - - // D3 at ( i , j ) - x0m[0] = xi[0] - HALF; - x0m[1] = xi[1]; - x0p[0] = xi[0] + HALF; - x0p[1] = xi[1]; - real_t D3d { (A_3(x0p) - A_3(x0m)) * beta_ij / alpha_ij }; - - // D1 at ( i + HALF , j ) - x0m[0] = xi[0] + HALF - HALF; - x0m[1] = xi[1]; - x0p[0] = xi[0] + HALF + HALF; - x0p[1] = xi[1]; - real_t E1d { (A_0(x0p) - A_0(x0m)) }; - real_t D1d { E1d / alpha_iPj }; - - if (cmp::AlmostZero(x_Ph[1])) { - return metric.template h<1, 3>({ xi[0], xi[1] }) * D1d; + if (field_geometry == InitFieldGeometry::Wald) { + coord_t xi { ZERO }, x0m { ZERO }, x0p { ZERO }; + metric.template convert(x_Ph, xi); + real_t inv_sqrt_detH_ij { ONE / metric.sqrt_det_h({ xi[0], xi[1] }) }; + real_t sqrt_detH_ij { metric.sqrt_det_h({ xi[0], xi[1] }) }; + real_t beta_ij { metric.beta1({ xi[0], xi[1] }) }; + real_t alpha_ij { metric.alpha({ xi[0], xi[1] }) }; + real_t alpha_iPj { metric.alpha({ xi[0] + HALF, xi[1] }) }; + + // D3 at ( i , j ) + x0m[0] = xi[0] - HALF; + x0m[1] = xi[1]; + x0p[0] = xi[0] + HALF; + x0p[1] = xi[1]; + real_t D3d { (A_3(x0p) - A_3(x0m)) * beta_ij / alpha_ij }; + + // D1 at ( i + HALF , j ) + x0m[0] = xi[0] + HALF - HALF; + x0m[1] = xi[1]; + x0p[0] = xi[0] + HALF + HALF; + x0p[1] = xi[1]; + real_t E1d { (A_0(x0p) - A_0(x0m)) }; + real_t D1d { E1d / alpha_iPj }; + + if (cmp::AlmostZero(x_Ph[1])) { + return metric.template h<1, 3>({ xi[0], xi[1] }) * D1d; + } else { + return metric.template h<3, 3>({ xi[0], xi[1] }) * D3d + + metric.template h<1, 3>({ xi[0], xi[1] }) * D1d; + } + } else if (field_geometry == InitFieldGeometry::Vertical) { + return ZERO; } else { - return metric.template h<3, 3>({ xi[0], xi[1] }) * D3d + - metric.template h<1, 3>({ xi[0], xi[1] }) * D1d; + raise::KernelError(HERE, "Unrecognized field geometry"); + return ZERO; } } private: - const M metric; + const M metric; + InitFieldGeometry field_geometry; }; template @@ -201,7 +249,8 @@ namespace user { inline PGen(const SimulationParams& p, const Metadomain& m) : arch::ProblemGenerator { p } , global_domain { m } - , init_flds { m.mesh().metric } {} + , init_flds { m.mesh().metric, + p.template get("setup.init_field", "wald") } {} }; } // namespace user diff --git a/pgens/wald/wald.toml b/pgens/wald/wald.toml index 75a3ef2e6..2b05fbac9 100644 --- a/pgens/wald/wald.toml +++ b/pgens/wald/wald.toml @@ -38,6 +38,7 @@ ppc0 = 2.0 [setup] + init_field = "wald" # or "vertical" [output] format = "hdf5" From ec47ff89ec667199eeb0ee933d9351f0ccdffc8d Mon Sep 17 00:00:00 2001 From: haykh Date: Wed, 16 Jul 2025 15:01:55 -0400 Subject: [PATCH 768/773] old implementation returned --- src/framework/domain/output.cpp | 72 +++++++++++++++++++++------------ 1 file changed, 46 insertions(+), 26 deletions(-) diff --git a/src/framework/domain/output.cpp b/src/framework/domain/output.cpp index 9d59367dd..960b2c713 100644 --- a/src/framework/domain/output.cpp +++ b/src/framework/domain/output.cpp @@ -192,36 +192,56 @@ namespace ntt { unsigned short buff_idx, const Mesh mesh) { if constexpr (M::Dim == Dim::_2D) { - using TeamPolicy = Kokkos::TeamPolicy; - const auto nx1 = mesh.n_active(in::x1); - const auto nx2 = mesh.n_active(in::x2); - - TeamPolicy policy(nx1, Kokkos::AUTO); - const auto metric = mesh.metric; - Kokkos::parallel_for( "ComputeVectorPotential", - policy, - Lambda(const TeamPolicy::member_type& team_member) { - index_t i1 = team_member.league_rank(); - Kokkos::parallel_scan( - Kokkos::TeamThreadRange(team_member, nx2), - [=](index_t i2, real_t& update, const bool final_pass) { - const auto i1_ { static_cast(i1) }; - const auto i2_ { static_cast(i2) }; - real_t sqrt_detH_ijM { metric.sqrt_det_h({ i1_, i2_ - HALF }) }; - real_t sqrt_detH_ijP { metric.sqrt_det_h({ i1_, i2_ + HALF }) }; - const auto input_val = - HALF * - (sqrt_detH_ijM * EM(i1 + N_GHOSTS, i2 + N_GHOSTS - 1, em::bx1) + - sqrt_detH_ijP * EM(i1 + N_GHOSTS, i2 + N_GHOSTS, em::bx1)); - update += input_val; - if (final_pass) { - buffer(i1 + N_GHOSTS, i2 + N_GHOSTS, buff_idx) = update; - } - }); + mesh.rangeActiveCells(), + Lambda(index_t i1, index_t i2) { + const real_t i1_ { COORD(i1) }; + const ncells_t k_min = 0; + const ncells_t k_max = (i2 - (N_GHOSTS)); + real_t A3 = ZERO; + for (auto k { k_min }; k <= k_max; ++k) { + real_t k_ = static_cast(k); + real_t sqrt_detH_ij1 { metric.sqrt_det_h({ i1_, k_ - HALF }) }; + real_t sqrt_detH_ij2 { metric.sqrt_det_h({ i1_, k_ + HALF }) }; + auto k1 { k + N_GHOSTS }; + A3 += HALF * (sqrt_detH_ij1 * EM(i1, k + N_GHOSTS - 1, em::bx1) + + sqrt_detH_ij2 * EM(i1, k + N_GHOSTS, em::bx1)); + } + buffer(i1, i2, buff_idx) = A3; }); + + // @TODO: Implementation with team policies works on AMD, but not on NVIDIA GPUs + // + // using TeamPolicy = Kokkos::TeamPolicy; + // const auto nx1 = mesh.n_active(in::x1); + // const auto nx2 = mesh.n_active(in::x2); + // + // TeamPolicy policy(nx1, Kokkos::AUTO); + // + // Kokkos::parallel_for( + // "ComputeVectorPotential", + // policy, + // Lambda(const TeamPolicy::member_type& team_member) { + // index_t i1 = team_member.league_rank(); + // Kokkos::parallel_scan( + // Kokkos::TeamThreadRange(team_member, nx2), + // [=](index_t i2, real_t& update, const bool final_pass) { + // const auto i1_ { static_cast(i1) }; + // const auto i2_ { static_cast(i2) }; + // const real_t sqrt_detH_ijM { metric.sqrt_det_h({ i1_, i2_ - HALF }) }; + // const real_t sqrt_detH_ijP { metric.sqrt_det_h({ i1_, i2_ + HALF }) }; + // const auto input_val = + // HALF * + // (sqrt_detH_ijM * EM(i1 + N_GHOSTS, i2 + N_GHOSTS - 1, em::bx1) + + // sqrt_detH_ijP * EM(i1 + N_GHOSTS, i2 + N_GHOSTS, em::bx1)); + // if (final_pass) { + // buffer(i1 + N_GHOSTS, i2 + N_GHOSTS, buff_idx) = update; + // } + // update += input_val; + // }); + // }); } else { raise::KernelError( HERE, From 7911a94b56f609e7ebbbc0d442cd98d1c0d1755e Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Thu, 17 Jul 2025 16:12:51 -0400 Subject: [PATCH 769/773] removed the small angle adjustment --- src/metrics/qkerr_schild.h | 27 +++++++-------------------- 1 file changed, 7 insertions(+), 20 deletions(-) diff --git a/src/metrics/qkerr_schild.h b/src/metrics/qkerr_schild.h index 6ff114b42..c7bef6187 100644 --- a/src/metrics/qkerr_schild.h +++ b/src/metrics/qkerr_schild.h @@ -39,7 +39,6 @@ namespace metric { const real_t chi_min, eta_min, phi_min; const real_t dchi, deta, dphi; const real_t dchi_inv, deta_inv, dphi_inv; - const bool small_angle; Inline auto Delta(const real_t& r) const -> real_t { return SQR(r) - TWO * r + SQR(a); @@ -90,8 +89,7 @@ namespace metric { , dphi { (x3_max - phi_min) / nx3 } , dchi_inv { ONE / dchi } , deta_inv { ONE / deta } - , dphi_inv { ONE / dphi } - , small_angle { eta2theta(HALF * deta) < constant::SMALL_ANGLE } { + , dphi_inv { ONE / dphi } { set_dxMin(find_dxMin()); } @@ -487,23 +485,12 @@ namespace metric { */ Inline auto polar_area(const real_t& x1) const -> real_t { if constexpr (D != Dim::_1D) { - if (small_angle) { - const real_t dtheta = eta2theta(HALF * deta); - return dchi * math::exp(x1 * dchi + chi_min) * - (SQR(r0 + math::exp(x1 * dchi + chi_min)) + SQR(a)) * - math::sqrt( - ONE + TWO * (r0 + math::exp(x1 * dchi + chi_min)) / - (SQR(r0 + math::exp(x1 * dchi + chi_min)) + SQR(a))) * - (static_cast(48) - SQR(dtheta)) * SQR(dtheta) / - static_cast(384); - } else { - return dchi * math::exp(x1 * dchi + chi_min) * - (SQR(r0 + math::exp(x1 * dchi + chi_min)) + SQR(a)) * - math::sqrt( - ONE + TWO * (r0 + math::exp(x1 * dchi + chi_min)) / - (SQR(r0 + math::exp(x1 * dchi + chi_min)) + SQR(a))) * - (ONE - math::cos(eta2theta(HALF * deta))); - } + return dchi * math::exp(x1 * dchi + chi_min) * + (SQR(r0 + math::exp(x1 * dchi + chi_min)) + SQR(a)) * + math::sqrt( + ONE + TWO * (r0 + math::exp(x1 * dchi + chi_min)) / + (SQR(r0 + math::exp(x1 * dchi + chi_min)) + SQR(a))) * + (ONE - math::cos(eta2theta(HALF * deta))); } } From 7d89d5cf498d8e52ad4d5064c7285f1ca001e771 Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Thu, 17 Jul 2025 16:13:50 -0400 Subject: [PATCH 770/773] fixed ranges for aux calculation (does not matter for current BC under horizon) --- src/engines/grpic.hpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/engines/grpic.hpp b/src/engines/grpic.hpp index cd04838d7..35e544a99 100644 --- a/src/engines/grpic.hpp +++ b/src/engines/grpic.hpp @@ -840,8 +840,12 @@ namespace ntt { if constexpr (M::Dim == Dim::_2D) { if (domain.mesh.flds_bc_in({ 0, +1 }) == FldsBC::AXIS) { range = CreateRangePolicy( - { domain.mesh.i_min(in::x1), domain.mesh.i_min(in::x2) }, + { domain.mesh.i_min(in::x1) - 1, domain.mesh.i_min(in::x2) }, { domain.mesh.i_max(in::x1), domain.mesh.i_max(in::x2) + 1 }); + } else { + range = CreateRangePolicy( + { domain.mesh.i_min(in::x1) - 1, domain.mesh.i_min(in::x2) }, + { domain.mesh.i_max(in::x1), domain.mesh.i_max(in::x2) }); } } else if constexpr (M::Dim == Dim::_3D) { raise::Error("Invalid dimension", HERE); From 772333a59bff1b8d4d5e69ac3341fc5bb53def4e Mon Sep 17 00:00:00 2001 From: Alisa Galishnikova <55898700+alisagk@users.noreply.github.com> Date: Thu, 17 Jul 2025 16:41:49 -0400 Subject: [PATCH 771/773] added !TODO for axis BCs --- src/kernels/fields_bcs.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/kernels/fields_bcs.hpp b/src/kernels/fields_bcs.hpp index 4891688a6..31dded501 100644 --- a/src/kernels/fields_bcs.hpp +++ b/src/kernels/fields_bcs.hpp @@ -840,6 +840,7 @@ namespace kernel::bc { Inline void operator()(index_t i1) const { if constexpr (D == Dim::_2D) { + // ! TODO: not all components are necessary if constexpr (not P) { if (setE) { Fld(i1, i_edge - 1, em::ex2) = -Fld(i1, i_edge, em::ex2); From f50aed5014828cf82c677b2f06d9d3b962578f9a Mon Sep 17 00:00:00 2001 From: haykh Date: Thu, 17 Jul 2025 17:47:32 -0400 Subject: [PATCH 772/773] reformat + minor bug in tests --- src/archetypes/tests/spatial_dist.cpp | 2 +- src/kernels/currents_deposit.hpp | 14 +-- src/kernels/tests/deposit.cpp | 17 ++-- src/metrics/qkerr_schild.h | 138 +++++++++++++++----------- 4 files changed, 99 insertions(+), 72 deletions(-) diff --git a/src/archetypes/tests/spatial_dist.cpp b/src/archetypes/tests/spatial_dist.cpp index c27f20851..51f1703a9 100644 --- a/src/archetypes/tests/spatial_dist.cpp +++ b/src/archetypes/tests/spatial_dist.cpp @@ -76,7 +76,7 @@ struct RadialDist : public SpatialDistribution { RadialDist(const M& metric) : SpatialDistribution { metric } {} - auto operator()(const coord_t& x_Code) const -> real_t { + Inline auto operator()(const coord_t& x_Code) const -> real_t { coord_t x_Sph { ZERO }; metric.template convert(x_Code, x_Sph); auto r { ZERO }; diff --git a/src/kernels/currents_deposit.hpp b/src/kernels/currents_deposit.hpp index 06eeadad8..bd84554f8 100644 --- a/src/kernels/currents_deposit.hpp +++ b/src/kernels/currents_deposit.hpp @@ -129,10 +129,11 @@ namespace kernel { } else { coord_t xp_ { ZERO }; xp_[0] = xp[0]; - real_t theta_Cd { xp[1] }; - const real_t theta_Ph { metric.template convert<2, Crd::Cd, Crd::Ph>(theta_Cd) }; - const real_t small_angle { constant::SMALL_ANGLE_GR }; - const auto large_angle { constant::PI - small_angle }; + real_t theta_Cd { xp[1] }; + const real_t theta_Ph { metric.template convert<2, Crd::Cd, Crd::Ph>( + theta_Cd) }; + const real_t small_angle { static_cast(constant::SMALL_ANGLE_GR) }; + const auto large_angle { static_cast(constant::PI) - small_angle }; if (theta_Ph < small_angle) { theta_Cd = metric.template convert<2, Crd::Ph, Crd::Cd>(small_angle); } else if (theta_Ph >= large_angle) { @@ -142,8 +143,9 @@ namespace kernel { metric.template transform(xp_, { ux1(p), ux2(p), ux3(p) }, vp); - inv_energy = metric.alpha(xp_) / math::sqrt(ONE + ux1(p) * vp[0] + ux2(p) * vp[1] + - ux3(p) * vp[2]); + inv_energy = metric.alpha(xp_) / + math::sqrt(ONE + ux1(p) * vp[0] + ux2(p) * vp[1] + + ux3(p) * vp[2]); } if (Kokkos::isnan(vp[2]) || Kokkos::isinf(vp[2])) { vp[2] = ZERO; diff --git a/src/kernels/tests/deposit.cpp b/src/kernels/tests/deposit.cpp index 0afb7d950..3df2828b5 100644 --- a/src/kernels/tests/deposit.cpp +++ b/src/kernels/tests/deposit.cpp @@ -34,9 +34,9 @@ Inline auto equal(real_t a, real_t b, const char* msg, real_t eps) -> bool { if ((a - b) >= eps * math::max(math::fabs(a), math::fabs(b))) { Kokkos::printf("%.12e != %.12e %s\n", a, b, msg); Kokkos::printf("%.12e >= %.12e %s\n", - a - b, - eps * math::max(math::fabs(a), math::fabs(b)), - msg); + a - b, + eps * math::max(math::fabs(a), math::fabs(b)), + msg); return false; } return true; @@ -89,7 +89,7 @@ void testDeposit(const std::vector& res, array_t tag { "tag", 10 }; const real_t charge { 1.0 }, inv_dt { 1.0 }; - const int i0 = 4, j0 = 4; + const int i0 = 40, j0 = 40; const prtldx_t dxi = 0.53, dxf = 0.47; const prtldx_t dyi = 0.34, dyf = 0.52; @@ -125,13 +125,16 @@ void testDeposit(const std::vector& res, put_value(dx2, dyf, 0); put_value(dx1_prev, dxi, 0); put_value(dx2_prev, dyi, 0); + put_value(ux1, ZERO, 0); + put_value(ux2, ZERO, 0); + put_value(ux3, ZERO, 0); put_value(weight, 1.0, 0); put_value(tag, ParticleTag::alive, 0); auto J_scat = Kokkos::Experimental::create_scatter_view(J); // clang-format off - Kokkos::parallel_for("CurrentsDeposit", 10, + Kokkos::parallel_for("CurrentsDeposit", 1, kernel::DepositCurrents_kernel(J_scat, i1, i2, i3, i1_prev, i2_prev, i3_prev, @@ -178,9 +181,9 @@ auto main(int argc, char* argv[]) -> int { using namespace ntt; using namespace metric; - const auto res = std::vector { 10, 10 }; + const auto res = std::vector { 100, 100 }; const auto r_extent = boundaries_t { - { 0.0, 100.0 } + { 1.0, 100.0 } }; const auto xy_extent = boundaries_t { { 0.0, 55.0 }, diff --git a/src/metrics/qkerr_schild.h b/src/metrics/qkerr_schild.h index c7bef6187..c137b5bcf 100644 --- a/src/metrics/qkerr_schild.h +++ b/src/metrics/qkerr_schild.h @@ -250,10 +250,10 @@ namespace metric { Inline auto dr_alpha(const coord_t& x) const -> real_t { const real_t r { r0 + math::exp(x[0] * dchi + chi_min) }; const real_t theta { eta2theta(x[1] * deta + eta_min) }; - const real_t dx_r {dchi * math::exp(x[0] * dchi + chi_min)}; - const real_t dr_Sigma {TWO * r * dx_r}; - - return - (dx_r * Sigma(r, theta) - r * dr_Sigma) * CUBE(alpha(x)) / SQR(Sigma(r, theta)); + const real_t dx_r { dchi * math::exp(x[0] * dchi + chi_min) }; + const real_t dr_Sigma { TWO * r * dx_r }; + return -(dx_r * Sigma(r, theta) - r * dr_Sigma) * CUBE(alpha(x)) / + SQR(Sigma(r, theta)); } /** @@ -262,10 +262,16 @@ namespace metric { */ Inline auto dt_alpha(const coord_t& x) const -> real_t { const real_t r { r0 + math::exp(x[0] * dchi + chi_min) }; - const real_t eta {x[1] * deta + eta_min }; + const real_t eta { x[1] * deta + eta_min }; const real_t theta { eta2theta(eta) }; - const real_t dx_dt {deta * (ONE + TWO * h0 * static_cast(constant::INV_PI_SQR) * (TWO * THREE * SQR(eta) - TWO * THREE * static_cast(constant::PI) * eta + static_cast(constant::PI_SQR))) }; - const real_t dt_Sigma {- TWO * SQR(a) * math::sin(theta) * math::cos(theta) * dx_dt}; + const real_t dx_dt { + deta * (ONE + TWO * h0 * static_cast(constant::INV_PI_SQR) * + (TWO * THREE * SQR(eta) - + TWO * THREE * static_cast(constant::PI) * eta + + static_cast(constant::PI_SQR))) + }; + const real_t dt_Sigma { -TWO * SQR(a) * math::sin(theta) * + math::cos(theta) * dx_dt }; return r * dt_Sigma * CUBE(alpha(x)) / SQR(Sigma(r, theta)); } @@ -291,11 +297,13 @@ namespace metric { const real_t r { r0 + math::exp(chi) }; const real_t theta { eta2theta(x[1] * deta + eta_min) }; const real_t z_ { z(r, theta) }; - const real_t dx_r {dchi * math::exp(x[0] * dchi + chi_min)}; - const real_t dr_Sigma {TWO * r * dx_r}; + const real_t dx_r { dchi * math::exp(x[0] * dchi + chi_min) }; + const real_t dr_Sigma { TWO * r * dx_r }; - return math::exp(-chi) * dchi_inv * TWO * (dx_r * Sigma(r, theta) - r * dr_Sigma) / SQR(Sigma(r, theta) + TWO * r) - - dchi * math::exp(-chi) * dchi_inv * z_ / (ONE + z_); + return math::exp(-chi) * dchi_inv * TWO * + (dx_r * Sigma(r, theta) - r * dr_Sigma) / + SQR(Sigma(r, theta) + TWO * r) - + dchi * math::exp(-chi) * dchi_inv * z_ / (ONE + z_); } /** @@ -305,9 +313,10 @@ namespace metric { Inline auto dt_beta1(const coord_t& x) const -> real_t { const real_t chi { x[0] * dchi + chi_min }; const real_t r { r0 + math::exp(chi) }; - const real_t eta {x[1] * deta + eta_min }; + const real_t eta { x[1] * deta + eta_min }; const real_t theta { eta2theta(eta) }; - return - math::exp(-chi) * dchi_inv * TWO * r * dt_Sigma(eta) / SQR(Sigma(r, theta) * (ONE + z(r, theta))); + return -math::exp(-chi) * dchi_inv * TWO * r * dt_Sigma(eta) / + SQR(Sigma(r, theta) * (ONE + z(r, theta))); } /** @@ -318,16 +327,19 @@ namespace metric { const real_t r { r0 + math::exp(x[0] * dchi + chi_min) }; const real_t theta { eta2theta(x[1] * deta + eta_min) }; - const real_t dx_r {dchi * math::exp(x[0] * dchi + chi_min)}; - const real_t dr_Sigma {TWO * r * dx_r}; - const real_t dr_Delta {TWO * dx_r * (r - ONE)}; - const real_t dr_A {FOUR * r * dx_r * (SQR(r) + SQR(a)) - SQR(a) * SQR(math::sin(theta)) * dr_Delta}; + const real_t dx_r { dchi * math::exp(x[0] * dchi + chi_min) }; + const real_t dr_Sigma { TWO * r * dx_r }; + const real_t dr_Delta { TWO * dx_r * (r - ONE) }; + const real_t dr_A { FOUR * r * dx_r * (SQR(r) + SQR(a)) - + SQR(a) * SQR(math::sin(theta)) * dr_Delta }; - return (math::exp(-TWO * (x[0] * dchi + chi_min)) / SQR(dchi) - * (Sigma(r, theta) * (Sigma(r, theta) + TWO * r) * dr_A - - TWO * A(r, theta) * (r * dr_Sigma + Sigma(r, theta) * (dr_Sigma + dx_r))) - / (SQR(Sigma(r, theta) * (Sigma(r, theta) + TWO * r))) ) - -TWO * dchi * math::exp(-TWO * (x[0] * dchi + chi_min)) / SQR(dchi) * A(r, theta) / (Sigma(r, theta) * (Sigma(r, theta) + TWO * r)); + return (math::exp(-TWO * (x[0] * dchi + chi_min)) / SQR(dchi) * + (Sigma(r, theta) * (Sigma(r, theta) + TWO * r) * dr_A - + TWO * A(r, theta) * + (r * dr_Sigma + Sigma(r, theta) * (dr_Sigma + dx_r))) / + (SQR(Sigma(r, theta) * (Sigma(r, theta) + TWO * r)))) - + TWO * dchi * math::exp(-TWO * (x[0] * dchi + chi_min)) / SQR(dchi) * + A(r, theta) / (Sigma(r, theta) * (Sigma(r, theta) + TWO * r)); } /** @@ -337,10 +349,10 @@ namespace metric { Inline auto dr_h22(const coord_t& x) const -> real_t { const real_t r { r0 + math::exp(x[0] * dchi + chi_min) }; const real_t theta { eta2theta(x[1] * deta + eta_min) }; - const real_t dx_r {dchi * math::exp(x[0] * dchi + chi_min)}; - const real_t dr_Sigma {TWO * r * dx_r}; + const real_t dx_r { dchi * math::exp(x[0] * dchi + chi_min) }; + const real_t dr_Sigma { TWO * r * dx_r }; - return - dr_Sigma / SQR(Sigma(r, theta)) / SQR(deta); + return -dr_Sigma / SQR(Sigma(r, theta)) / SQR(deta); } /** @@ -350,10 +362,10 @@ namespace metric { Inline auto dr_h33(const coord_t& x) const -> real_t { const real_t r { r0 + math::exp(x[0] * dchi + chi_min) }; const real_t theta { eta2theta(x[1] * deta + eta_min) }; - const real_t dx_r {dchi * math::exp(x[0] * dchi + chi_min)}; - const real_t dr_Sigma {TWO * r * dx_r}; + const real_t dx_r { dchi * math::exp(x[0] * dchi + chi_min) }; + const real_t dr_Sigma { TWO * r * dx_r }; - return - dr_Sigma / SQR(Sigma(r, theta)) / SQR(math::sin(theta)); + return -dr_Sigma / SQR(Sigma(r, theta)) / SQR(math::sin(theta)); } /** @@ -363,11 +375,13 @@ namespace metric { Inline auto dr_h13(const coord_t& x) const -> real_t { const real_t r { r0 + math::exp(x[0] * dchi + chi_min) }; const real_t theta { eta2theta(x[1] * deta + eta_min) }; - const real_t dx_r {dchi * math::exp(x[0] * dchi + chi_min)}; - const real_t dr_Sigma {TWO * r * dx_r}; + const real_t dx_r { dchi * math::exp(x[0] * dchi + chi_min) }; + const real_t dr_Sigma { TWO * r * dx_r }; - return - a * dr_Sigma / SQR(Sigma(r, theta)) * (math::exp(-(x[0] * dchi + chi_min)) * dchi_inv) - - dchi * (math::exp(-(x[0] * dchi + chi_min)) * dchi_inv) * a / Sigma(r, theta); + return -a * dr_Sigma / SQR(Sigma(r, theta)) * + (math::exp(-(x[0] * dchi + chi_min)) * dchi_inv) - + dchi * (math::exp(-(x[0] * dchi + chi_min)) * dchi_inv) * a / + Sigma(r, theta); } /** @@ -376,11 +390,13 @@ namespace metric { */ Inline auto dt_Sigma(const real_t& eta) const -> real_t { const real_t theta { eta2theta(eta) }; - const real_t dt_Sigma {- TWO * SQR(a) * math::sin(theta) * math::cos(theta) * dx_dt(eta)}; - if (cmp::AlmostZero(dt_Sigma)) + const real_t dt_Sigma { -TWO * SQR(a) * math::sin(theta) * + math::cos(theta) * dx_dt(eta) }; + if (cmp::AlmostZero(dt_Sigma)) { return ZERO; - else + } else { return dt_Sigma; + } } /** @@ -389,12 +405,14 @@ namespace metric { */ Inline auto dt_A(const real_t& r, const real_t& eta) const -> real_t { const real_t theta { eta2theta(eta) }; - const real_t dt_A {- TWO * SQR(a) * math::sin(theta) * math::cos(theta) * Delta(r) * dx_dt(eta)}; - if (cmp::AlmostZero(dt_A)) + const real_t dt_A { -TWO * SQR(a) * math::sin(theta) * math::cos(theta) * + Delta(r) * dx_dt(eta) }; + if (cmp::AlmostZero(dt_A)) { return ZERO; - else + } else { return dt_A; - } + } + } /** * dtheta derivative of h^11 @@ -402,12 +420,12 @@ namespace metric { */ Inline auto dt_h11(const coord_t& x) const -> real_t { const real_t r { r0 + math::exp(x[0] * dchi + chi_min) }; - const real_t eta {x[1] * deta + eta_min }; + const real_t eta { x[1] * deta + eta_min }; const real_t theta { eta2theta(eta) }; - return math::exp(-TWO * (x[0] * dchi + chi_min)) / SQR(dchi) - * (Sigma(r, theta) * (Sigma(r, theta) + TWO * r) * dt_A(r, eta) - - TWO * A(r, theta) * dt_Sigma(eta) * (r + Sigma(r, theta))) - / (SQR(Sigma(r, theta) * (Sigma(r, theta) + TWO * r))); + return math::exp(-TWO * (x[0] * dchi + chi_min)) / SQR(dchi) * + (Sigma(r, theta) * (Sigma(r, theta) + TWO * r) * dt_A(r, eta) - + TWO * A(r, theta) * dt_Sigma(eta) * (r + Sigma(r, theta))) / + (SQR(Sigma(r, theta) * (Sigma(r, theta) + TWO * r))); } /** @@ -416,9 +434,9 @@ namespace metric { */ Inline auto dt_h22(const coord_t& x) const -> real_t { const real_t r { r0 + math::exp(x[0] * dchi + chi_min) }; - const real_t eta {x[1] * deta + eta_min }; + const real_t eta { x[1] * deta + eta_min }; const real_t theta { eta2theta(eta) }; - return - dt_Sigma(eta) / SQR(Sigma(r, theta)) / SQR(deta); + return -dt_Sigma(eta) / SQR(Sigma(r, theta)) / SQR(deta); } /** @@ -427,9 +445,11 @@ namespace metric { */ Inline auto dt_h33(const coord_t& x) const -> real_t { const real_t r { r0 + math::exp(x[0] * dchi + chi_min) }; - const real_t eta {x[1] * deta + eta_min }; + const real_t eta { x[1] * deta + eta_min }; const real_t theta { eta2theta(eta) }; - return - (dt_Sigma(eta) + TWO * math::cos(theta) / math::sin(theta) * Sigma(r, theta) * dx_dt(eta)) / SQR(Sigma(r, theta) * math::sin(theta)); + return -(dt_Sigma(eta) + TWO * math::cos(theta) / math::sin(theta) * + Sigma(r, theta) * dx_dt(eta)) / + SQR(Sigma(r, theta) * math::sin(theta)); } /** @@ -438,9 +458,10 @@ namespace metric { */ Inline auto dt_h13(const coord_t& x) const -> real_t { const real_t r { r0 + math::exp(x[0] * dchi + chi_min) }; - const real_t eta {x[1] * deta + eta_min }; + const real_t eta { x[1] * deta + eta_min }; const real_t theta { eta2theta(eta) }; - return - a * dt_Sigma(eta) / SQR(Sigma(r, theta)) * (math::exp(-(x[0] * dchi + chi_min)) * dchi_inv); + return -a * dt_Sigma(eta) / SQR(Sigma(r, theta)) * + (math::exp(-(x[0] * dchi + chi_min)) * dchi_inv); } /** @@ -486,11 +507,11 @@ namespace metric { Inline auto polar_area(const real_t& x1) const -> real_t { if constexpr (D != Dim::_1D) { return dchi * math::exp(x1 * dchi + chi_min) * - (SQR(r0 + math::exp(x1 * dchi + chi_min)) + SQR(a)) * - math::sqrt( - ONE + TWO * (r0 + math::exp(x1 * dchi + chi_min)) / - (SQR(r0 + math::exp(x1 * dchi + chi_min)) + SQR(a))) * - (ONE - math::cos(eta2theta(HALF * deta))); + (SQR(r0 + math::exp(x1 * dchi + chi_min)) + SQR(a)) * + math::sqrt( + ONE + TWO * (r0 + math::exp(x1 * dchi + chi_min)) / + (SQR(r0 + math::exp(x1 * dchi + chi_min)) + SQR(a))) * + (ONE - math::cos(eta2theta(HALF * deta))); } } @@ -662,9 +683,10 @@ namespace metric { if (cmp::AlmostZero(h0)) { return deta; } else { - return deta * (ONE - + TWO * h0 * constant::INV_PI_SQR * - (TWO * THREE * SQR(eta) - TWO * THREE * constant::PI * eta + constant::PI_SQR)); + return deta * + (ONE + TWO * h0 * constant::INV_PI_SQR * + (TWO * THREE * SQR(eta) - + TWO * THREE * constant::PI * eta + constant::PI_SQR)); } } From 60c2bcfbcc73550a131e137544b9ce0738e944ec Mon Sep 17 00:00:00 2001 From: haykh Date: Thu, 17 Jul 2025 17:50:38 -0400 Subject: [PATCH 773/773] formatting --- src/archetypes/particle_injector.h | 12 ++- src/archetypes/spatial_dist.h | 4 +- src/framework/domain/communications.cpp | 18 ++-- src/framework/domain/domain.h | 7 +- src/framework/domain/mesh.h | 5 +- src/global/arch/directions.h | 4 +- src/global/arch/kokkos_aliases.cpp | 36 +++---- src/global/arch/kokkos_aliases.h | 4 +- src/global/tests/param_container.cpp | 4 +- src/global/utils/cargs.cpp | 4 +- src/global/utils/cargs.h | 3 +- src/global/utils/colors.h | 37 ++++---- src/global/utils/comparators.h | 16 ++-- src/global/utils/diag.cpp | 5 +- src/global/utils/formatting.h | 10 +- src/global/utils/numeric.h | 26 +++--- src/global/utils/param_container.cpp | 26 +++--- src/global/utils/timer.cpp | 5 +- src/global/utils/toml.h | 12 +-- src/global/utils/tools.h | 32 ++++--- src/kernels/ampere_gr.hpp | 3 +- src/kernels/aux_fields_gr.hpp | 35 ++++--- src/kernels/comm.hpp | 72 +++++++------- src/kernels/fields_bcs.hpp | 20 ++-- src/kernels/particle_pusher_gr.hpp | 47 +++++----- src/kernels/particle_pusher_sr.hpp | 4 +- src/kernels/tests/ampere_mink.cpp | 8 +- src/kernels/tests/ext_force.cpp | 15 +-- src/kernels/tests/faraday_mink.cpp | 8 +- src/kernels/tests/fields_to_phys.cpp | 2 +- src/kernels/tests/flds_bc.cpp | 20 +++- src/metrics/kerr_schild.h | 119 +++++++++++++----------- src/metrics/kerr_schild_0.h | 18 ++-- src/metrics/minkowski.h | 3 +- src/metrics/qspherical.h | 3 +- src/metrics/spherical.h | 3 +- src/metrics/tests/ks-qks.cpp | 24 ++--- src/metrics/tests/minkowski.cpp | 3 +- src/metrics/tests/sph-qsph.cpp | 8 +- src/output/tests/writer-mpi.cpp | 12 +-- src/output/tests/writer-nompi.cpp | 26 +++--- src/output/utils/interpret_prompt.h | 4 +- 42 files changed, 378 insertions(+), 349 deletions(-) diff --git a/src/archetypes/particle_injector.h b/src/archetypes/particle_injector.h index 4f6a524f3..6313031d1 100644 --- a/src/archetypes/particle_injector.h +++ b/src/archetypes/particle_injector.h @@ -256,8 +256,10 @@ namespace arch { template class ED, - template class SD> + template + class ED, + template + class SD> struct NonUniformInjector { using energy_dist_t = ED; using spatial_dist_t = SD; @@ -507,8 +509,10 @@ namespace arch { template class ED1, - template class ED2> + template + class ED1, + template + class ED2> struct UniformInjector : BaseInjector { using energy_dist_1_t = ED1; using energy_dist_2_t = ED2; diff --git a/src/archetypes/spatial_dist.h b/src/archetypes/spatial_dist.h index eabb9ea72..55c84ddf2 100644 --- a/src/archetypes/spatial_dist.h +++ b/src/archetypes/spatial_dist.h @@ -40,7 +40,7 @@ namespace arch { struct Uniform : public SpatialDistribution { Uniform(const M& metric) : SpatialDistribution { metric } {} - Inline auto operator()(const coord_t&) const -> real_t { + Inline auto operator()(const coord_t&) const -> real_t { return ONE; } }; @@ -65,7 +65,7 @@ namespace arch { , target_density { target_density } , target_max_density { target_max_density } {} - Inline auto operator()(const coord_t& x_Ph) const -> real_t { + Inline auto operator()(const coord_t& x_Ph) const -> real_t { coord_t x_Cd { ZERO }; metric.template convert(x_Ph, x_Cd); real_t dens { ZERO }; diff --git a/src/framework/domain/communications.cpp b/src/framework/domain/communications.cpp index 507316b5c..bf6eb3dd1 100644 --- a/src/framework/domain/communications.cpp +++ b/src/framework/domain/communications.cpp @@ -36,10 +36,10 @@ namespace ntt { using comm_params_t = std::pair>; template - auto GetSendRecvRanks(Metadomain* metadomain, - Domain& domain, - dir::direction_t direction) - -> std::pair { + auto GetSendRecvRanks( + Metadomain* metadomain, + Domain& domain, + dir::direction_t direction) -> std::pair { Domain* send_to_nghbr_ptr = nullptr; Domain* recv_from_nghbr_ptr = nullptr; // set pointers to the correct send/recv domains @@ -119,11 +119,11 @@ namespace ntt { } template - auto GetSendRecvParams(Metadomain* metadomain, - Domain& domain, - dir::direction_t direction, - bool synchronize) - -> std::pair { + auto GetSendRecvParams( + Metadomain* metadomain, + Domain& domain, + dir::direction_t direction, + bool synchronize) -> std::pair { const auto [send_indrank, recv_indrank] = GetSendRecvRanks(metadomain, domain, direction); const auto [send_ind, send_rank] = send_indrank; diff --git a/src/framework/domain/domain.h b/src/framework/domain/domain.h index c26f5995f..b6cbb985a 100644 --- a/src/framework/domain/domain.h +++ b/src/framework/domain/domain.h @@ -146,8 +146,7 @@ namespace ntt { } /* setters -------------------------------------------------------------- */ - auto set_neighbor_idx(const dir::direction_t& dir, unsigned int idx) - -> void { + auto set_neighbor_idx(const dir::direction_t& dir, unsigned int idx) -> void { m_neighbor_idx[dir] = idx; } @@ -165,8 +164,8 @@ namespace ntt { }; template - inline auto operator<<(std::ostream& os, const Domain& domain) - -> std::ostream& { + inline auto operator<<(std::ostream& os, + const Domain& domain) -> std::ostream& { os << "Domain #" << domain.index(); #if defined(MPI_ENABLED) os << " [MPI rank: " << domain.mpi_rank() << "]"; diff --git a/src/framework/domain/mesh.h b/src/framework/domain/mesh.h index e4f2cba6d..afb095f44 100644 --- a/src/framework/domain/mesh.h +++ b/src/framework/domain/mesh.h @@ -131,8 +131,9 @@ namespace ntt { * @note indices are already shifted by N_GHOSTS (i.e. they start at N_GHOSTS not 0) */ [[nodiscard]] - auto ExtentToRange(boundaries_t box, boundaries_t incl_ghosts) const - -> boundaries_t { + auto ExtentToRange( + boundaries_t box, + boundaries_t incl_ghosts) const -> boundaries_t { raise::ErrorIf(box.size() != M::Dim, "Invalid box dimension", HERE); raise::ErrorIf(incl_ghosts.size() != M::Dim, "Invalid incl_ghosts dimension", diff --git a/src/global/arch/directions.h b/src/global/arch/directions.h index 5f8281ed3..850bc130d 100644 --- a/src/global/arch/directions.h +++ b/src/global/arch/directions.h @@ -132,8 +132,8 @@ namespace dir { using dirs_t = std::vector>; template - inline auto operator<<(std::ostream& os, const direction_t& dir) - -> std::ostream& { + inline auto operator<<(std::ostream& os, + const direction_t& dir) -> std::ostream& { for (auto& d : dir) { os << std::setw(2) << std::left; if (d > 0) { diff --git a/src/global/arch/kokkos_aliases.cpp b/src/global/arch/kokkos_aliases.cpp index 25397af8e..e81d41280 100644 --- a/src/global/arch/kokkos_aliases.cpp +++ b/src/global/arch/kokkos_aliases.cpp @@ -9,18 +9,18 @@ auto CreateParticleRangePolicy(npart_t p1, npart_t p2) -> range_t { } template <> -auto CreateRangePolicy(const tuple_t& i1, - const tuple_t& i2) - -> range_t { +auto CreateRangePolicy( + const tuple_t& i1, + const tuple_t& i2) -> range_t { index_t i1min = i1[0]; index_t i1max = i2[0]; return Kokkos::RangePolicy(i1min, i1max); } template <> -auto CreateRangePolicy(const tuple_t& i1, - const tuple_t& i2) - -> range_t { +auto CreateRangePolicy( + const tuple_t& i1, + const tuple_t& i2) -> range_t { index_t i1min = i1[0]; index_t i1max = i2[0]; index_t i2min = i1[1]; @@ -31,9 +31,9 @@ auto CreateRangePolicy(const tuple_t& i1, } template <> -auto CreateRangePolicy(const tuple_t& i1, - const tuple_t& i2) - -> range_t { +auto CreateRangePolicy( + const tuple_t& i1, + const tuple_t& i2) -> range_t { index_t i1min = i1[0]; index_t i1max = i2[0]; index_t i2min = i1[1]; @@ -46,18 +46,18 @@ auto CreateRangePolicy(const tuple_t& i1, } template <> -auto CreateRangePolicyOnHost(const tuple_t& i1, - const tuple_t& i2) - -> range_h_t { +auto CreateRangePolicyOnHost( + const tuple_t& i1, + const tuple_t& i2) -> range_h_t { index_t i1min = i1[0]; index_t i1max = i2[0]; return Kokkos::RangePolicy(i1min, i1max); } template <> -auto CreateRangePolicyOnHost(const tuple_t& i1, - const tuple_t& i2) - -> range_h_t { +auto CreateRangePolicyOnHost( + const tuple_t& i1, + const tuple_t& i2) -> range_h_t { index_t i1min = i1[0]; index_t i1max = i2[0]; index_t i2min = i1[1]; @@ -68,9 +68,9 @@ auto CreateRangePolicyOnHost(const tuple_t& i1, } template <> -auto CreateRangePolicyOnHost(const tuple_t& i1, - const tuple_t& i2) - -> range_h_t { +auto CreateRangePolicyOnHost( + const tuple_t& i1, + const tuple_t& i2) -> range_h_t { index_t i1min = i1[0]; index_t i1max = i2[0]; index_t i2min = i1[1]; diff --git a/src/global/arch/kokkos_aliases.h b/src/global/arch/kokkos_aliases.h index 712fc6eff..adb0b6451 100644 --- a/src/global/arch/kokkos_aliases.h +++ b/src/global/arch/kokkos_aliases.h @@ -234,8 +234,8 @@ auto CreateParticleRangePolicy(npart_t, npart_t) -> range_t; * @returns Kokkos::RangePolicy or Kokkos::MDRangePolicy in the accelerator execution space. */ template -auto CreateRangePolicy(const tuple_t&, const tuple_t&) - -> range_t; +auto CreateRangePolicy(const tuple_t&, + const tuple_t&) -> range_t; /** * @brief Function template for generating ND Kokkos range policy on the host. diff --git a/src/global/tests/param_container.cpp b/src/global/tests/param_container.cpp index 31a8ca437..60c5495c5 100644 --- a/src/global/tests/param_container.cpp +++ b/src/global/tests/param_container.cpp @@ -25,8 +25,8 @@ auto main() -> int { const auto nonexist_vec = std::vector { 1, 2, 3 }; const auto flds_bc_vec = std::vector { FldsBC::AXIS, FldsBC::PERIODIC }; const auto prtl_bc_vec = boundaries_t { - {PrtlBC::REFLECT, PrtlBC::PERIODIC}, - {PrtlBC::REFLECT, PrtlBC::REFLECT} + { PrtlBC::REFLECT, PrtlBC::PERIODIC }, + { PrtlBC::REFLECT, PrtlBC::REFLECT } }; p.set("a", 1); diff --git a/src/global/utils/cargs.cpp b/src/global/utils/cargs.cpp index 8f641214e..57b79f33b 100644 --- a/src/global/utils/cargs.cpp +++ b/src/global/utils/cargs.cpp @@ -18,8 +18,8 @@ namespace cargs { _initialized = true; } - auto CommandLineArguments::getArgument(std::string_view key, std::string_view def) - -> std::string_view { + auto CommandLineArguments::getArgument(std::string_view key, + std::string_view def) -> std::string_view { if (!_initialized) { throw std::runtime_error( "# Error: command line arguments have not been parsed."); diff --git a/src/global/utils/cargs.h b/src/global/utils/cargs.h index 7c02146b7..530969912 100644 --- a/src/global/utils/cargs.h +++ b/src/global/utils/cargs.h @@ -25,8 +25,7 @@ namespace cargs { public: void readCommandLineArguments(int argc, char* argv[]); [[nodiscard]] - auto getArgument(std::string_view key, std::string_view def) - -> std::string_view; + auto getArgument(std::string_view key, std::string_view def) -> std::string_view; [[nodiscard]] auto getArgument(std::string_view key) -> std::string_view; auto isSpecified(std::string_view key) -> bool; diff --git a/src/global/utils/colors.h b/src/global/utils/colors.h index 6f5e775cf..b997317cb 100644 --- a/src/global/utils/colors.h +++ b/src/global/utils/colors.h @@ -53,8 +53,7 @@ namespace color { return msg_nocol; } - inline auto get_color(const std::string& s, bool eight_bit = true) - -> std::string { + inline auto get_color(const std::string& s, bool eight_bit = true) -> std::string { if (not eight_bit) { return ""; } else { @@ -125,23 +124,23 @@ namespace color { c_bmagenta = c_bcyan = c_bwhite = ""; } return { - { "reset", c_reset}, - { "black", c_black}, - { "red", c_red}, - { "green", c_green}, - { "yellow", c_yellow}, - { "blue", c_blue}, - { "magenta", c_magenta}, - { "cyan", c_cyan}, - { "white", c_white}, - { "bblack", c_bblack}, - { "bred", c_bred}, - { "bgreen", c_bgreen}, - { "byellow", c_byellow}, - { "bblue", c_bblue}, - {"bmagenta", c_bmagenta}, - { "bcyan", c_bcyan}, - { "bwhite", c_bwhite} + { "reset", c_reset }, + { "black", c_black }, + { "red", c_red }, + { "green", c_green }, + { "yellow", c_yellow }, + { "blue", c_blue }, + { "magenta", c_magenta }, + { "cyan", c_cyan }, + { "white", c_white }, + { "bblack", c_bblack }, + { "bred", c_bred }, + { "bgreen", c_bgreen }, + { "byellow", c_byellow }, + { "bblue", c_bblue }, + { "bmagenta", c_bmagenta }, + { "bcyan", c_bcyan }, + { "bwhite", c_bwhite } }; } } // namespace color diff --git a/src/global/utils/comparators.h b/src/global/utils/comparators.h index d86fe868c..a12d55e73 100644 --- a/src/global/utils/comparators.h +++ b/src/global/utils/comparators.h @@ -27,31 +27,31 @@ namespace cmp { template - Inline auto AlmostEqual(T a, T b, T eps = Kokkos::Experimental::epsilon::value) - -> bool { + Inline auto AlmostEqual(T a, + T b, + T eps = Kokkos::Experimental::epsilon::value) -> bool { static_assert(std::is_floating_point_v, "T must be a floating point type"); return (a == b) || (math::abs(a - b) <= math::min(math::abs(a), math::abs(b)) * eps); } template - Inline auto AlmostZero(T a, T eps = Kokkos::Experimental::epsilon::value) - -> bool { + Inline auto AlmostZero(T a, T eps = Kokkos::Experimental::epsilon::value) -> bool { static_assert(std::is_floating_point_v, "T must be a floating point type"); return math::abs(a) <= eps; } template - inline auto AlmostEqual_host(T a, T b, T eps = std::numeric_limits::epsilon()) - -> bool { + inline auto AlmostEqual_host(T a, + T b, + T eps = std::numeric_limits::epsilon()) -> bool { static_assert(std::is_floating_point_v, "T must be a floating point type"); return (a == b) || (std::abs(a - b) <= std::min(std::abs(a), std::abs(b)) * eps); } template - inline auto AlmostZero_host(T a, T eps = std::numeric_limits::epsilon()) - -> bool { + inline auto AlmostZero_host(T a, T eps = std::numeric_limits::epsilon()) -> bool { static_assert(std::is_floating_point_v, "T must be a floating point type"); return std::abs(a) <= eps; } diff --git a/src/global/utils/diag.cpp b/src/global/utils/diag.cpp index 6764c773f..f6f615587 100644 --- a/src/global/utils/diag.cpp +++ b/src/global/utils/diag.cpp @@ -21,8 +21,9 @@ #include namespace diag { - auto npart_stats(npart_t npart, npart_t maxnpart) - -> std::vector> { + auto npart_stats( + npart_t npart, + npart_t maxnpart) -> std::vector> { auto stats = std::vector>(); #if !defined(MPI_ENABLED) stats.push_back( diff --git a/src/global/utils/formatting.h b/src/global/utils/formatting.h index c8c236cab..46c25c633 100644 --- a/src/global/utils/formatting.h +++ b/src/global/utils/formatting.h @@ -53,8 +53,10 @@ namespace fmt { * @param c Character to pad with * @param right Pad on the right */ - inline auto pad(const std::string& str, std::size_t n, char c, bool right = false) - -> std::string { + inline auto pad(const std::string& str, + std::size_t n, + char c, + bool right = false) -> std::string { if (n <= str.size()) { return str; } @@ -113,8 +115,8 @@ namespace fmt { * @param delim Delimiter * @return Vector of strings */ - inline auto splitString(const std::string& str, const std::string& delim) - -> std::vector { + inline auto splitString(const std::string& str, + const std::string& delim) -> std::vector { std::regex regexz(delim); return { std::sregex_token_iterator(str.begin(), str.end(), regexz, -1), std::sregex_token_iterator() }; diff --git a/src/global/utils/numeric.h b/src/global/utils/numeric.h index a3385336a..59cec5ba5 100644 --- a/src/global/utils/numeric.h +++ b/src/global/utils/numeric.h @@ -80,19 +80,19 @@ inline constexpr double INV_64 = 0.015625; #define CROSS_x3(ax1, ax2, ax3, bx1, bx2, bx3) ((ax1) * (bx2) - (ax2) * (bx1)) namespace constant { - inline constexpr std::uint64_t RandomSeed = 0x123456789abcdef0; - inline constexpr double HALF_PI = 1.57079632679489661923; - inline constexpr double PI = 3.14159265358979323846; - inline constexpr double INV_PI = 0.31830988618379067154; - inline constexpr double PI_SQR = 9.86960440108935861882; - inline constexpr double INV_PI_SQR = 0.10132118364233777144; - inline constexpr double TWO_PI = 6.28318530717958647692; - inline constexpr double E = 2.71828182845904523536; - inline constexpr double SQRT2 = 1.41421356237309504880; - inline constexpr double INV_SQRT2 = 0.70710678118654752440; - inline constexpr double SQRT3 = 1.73205080756887729352; - inline constexpr double SMALL_ANGLE = 1e-3; - inline constexpr double SMALL_ANGLE_GR = 1e-5; + inline constexpr std::uint64_t RandomSeed = 0x123456789abcdef0; + inline constexpr double HALF_PI = 1.57079632679489661923; + inline constexpr double PI = 3.14159265358979323846; + inline constexpr double INV_PI = 0.31830988618379067154; + inline constexpr double PI_SQR = 9.86960440108935861882; + inline constexpr double INV_PI_SQR = 0.10132118364233777144; + inline constexpr double TWO_PI = 6.28318530717958647692; + inline constexpr double E = 2.71828182845904523536; + inline constexpr double SQRT2 = 1.41421356237309504880; + inline constexpr double INV_SQRT2 = 0.70710678118654752440; + inline constexpr double SQRT3 = 1.73205080756887729352; + inline constexpr double SMALL_ANGLE = 1e-3; + inline constexpr double SMALL_ANGLE_GR = 1e-5; } // namespace constant namespace convert { diff --git a/src/global/utils/param_container.cpp b/src/global/utils/param_container.cpp index 54d8591b3..126a64e4e 100644 --- a/src/global/utils/param_container.cpp +++ b/src/global/utils/param_container.cpp @@ -31,8 +31,8 @@ namespace prm { } template - auto write(adios2::IO& io, const std::string& name, T var) - -> decltype(void(T()), void()) { + auto write(adios2::IO& io, const std::string& name, T var) -> decltype(void(T()), + void()) { io.DefineAttribute(name, var); } @@ -47,8 +47,8 @@ namespace prm { } template - auto write_pair(adios2::IO& io, const std::string& name, std::pair var) - -> typename std::enable_if::value, void>::type { + auto write_pair(adios2::IO& io, const std::string& name, std::pair var) -> + typename std::enable_if::value, void>::type { std::vector var_str; var_str.push_back(var.first.to_string()); var_str.push_back(var.second.to_string()); @@ -56,8 +56,9 @@ namespace prm { } template - auto write_pair(adios2::IO& io, const std::string& name, std::pair var) - -> decltype(void(T()), void()) { + auto write_pair(adios2::IO& io, + const std::string& name, + std::pair var) -> decltype(void(T()), void()) { std::vector var_vec; var_vec.push_back(var.first); var_vec.push_back(var.second); @@ -75,8 +76,9 @@ namespace prm { } template - auto write_vec(adios2::IO& io, const std::string& name, std::vector var) - -> decltype(void(T()), void()) { + auto write_vec(adios2::IO& io, + const std::string& name, + std::vector var) -> decltype(void(T()), void()) { io.DefineAttribute(name, var.data(), var.size()); } @@ -96,8 +98,8 @@ namespace prm { template auto write_vec_pair(adios2::IO& io, const std::string& name, - std::vector> var) - -> decltype(void(T()), void()) { + std::vector> var) -> decltype(void(T()), + void()) { std::vector var_vec; for (const auto& v : var) { var_vec.push_back(v.first); @@ -123,8 +125,8 @@ namespace prm { template auto write_vec_vec(adios2::IO& io, const std::string& name, - std::vector> var) - -> decltype(void(T()), void()) { + std::vector> var) -> decltype(void(T()), + void()) { std::vector var_vec; for (const auto& vec : var) { for (const auto& v : vec) { diff --git a/src/global/utils/timer.cpp b/src/global/utils/timer.cpp index 3cca1b365..19c7c9147 100644 --- a/src/global/utils/timer.cpp +++ b/src/global/utils/timer.cpp @@ -130,8 +130,9 @@ namespace timer { return timer_stats; } - auto Timers::printAll(TimerFlags flags, npart_t npart, ncells_t ncells) const - -> std::string { + auto Timers::printAll(TimerFlags flags, + npart_t npart, + ncells_t ncells) const -> std::string { const std::vector extras { "PrtlClear", "Output", "Checkpoint" }; const auto stats = gather(extras, npart, ncells); if (stats.empty()) { diff --git a/src/global/utils/toml.h b/src/global/utils/toml.h index 16b79f72d..5d9981e9f 100644 --- a/src/global/utils/toml.h +++ b/src/global/utils/toml.h @@ -3611,7 +3611,7 @@ namespace toml { } } // namespace ansi - } // namespace color + } // namespace color } // namespace toml #endif // TOML11_COLOR_IMPL_HPP #endif @@ -10368,7 +10368,7 @@ namespace toml { template auto last_one(Ts&&... args) -> decltype(std::get( - std::forward_as_tuple(std::forward(args)...))) { + std::forward_as_tuple(std::forward(args)...))) { return std::get( std::forward_as_tuple(std::forward(args)...)); } @@ -11787,7 +11787,7 @@ namespace toml { literal null_value(const spec&); } // namespace syntax - } // namespace detail + } // namespace detail } // namespace toml #endif // TOML11_SYNTAX_FWD_HPP @@ -12366,7 +12366,7 @@ namespace toml { } } // namespace syntax - } // namespace detail + } // namespace detail } // namespace toml #endif // TOML11_SYNTAX_IMPL_HPP #endif @@ -16465,7 +16465,7 @@ namespace toml { #endif } // namespace toml_literals - } // namespace literals + } // namespace literals } // namespace toml #endif // TOML11_LITERAL_FWD_HPP @@ -16619,7 +16619,7 @@ namespace toml { #endif } // namespace toml_literals - } // namespace literals + } // namespace literals } // namespace toml #endif // TOML11_LITERAL_IMPL_HPP #endif diff --git a/src/global/utils/tools.h b/src/global/utils/tools.h index 27c7e22c8..8a568ae20 100644 --- a/src/global/utils/tools.h +++ b/src/global/utils/tools.h @@ -60,8 +60,8 @@ namespace tools { * @return Tensor product of list */ template - inline auto TensorProduct(const std::vector>& list) - -> std::vector> { + inline auto TensorProduct( + const std::vector>& list) -> std::vector> { std::vector> result = { {} }; for (const auto& sublist : list) { std::vector> temp; @@ -81,8 +81,8 @@ namespace tools { * @param ndomains Number of domains * @param ncells Number of cells */ - inline auto decompose1D(unsigned int ndomains, ncells_t ncells) - -> std::vector { + inline auto decompose1D(unsigned int ndomains, + ncells_t ncells) -> std::vector { auto size = (ncells_t)((double)ncells / (double)ndomains); auto ncells_domain = std::vector(ndomains, size); for (auto i { 0u }; i < ncells - size * ndomains; ++i) { @@ -107,8 +107,10 @@ namespace tools { * @param s1 Proportion of the first dimension * @param s2 Proportion of the second dimension */ - inline auto divideInProportions2D(unsigned int ntot, unsigned int s1, unsigned int s2) - -> std::tuple { + inline auto divideInProportions2D( + unsigned int ntot, + unsigned int s1, + unsigned int s2) -> std::tuple { auto n1 = (unsigned int)(std::sqrt((double)ntot * (double)s1 / (double)s2)); if (n1 == 0) { return { 1, ntot }; @@ -130,11 +132,11 @@ namespace tools { * @param s2 Proportion of the second dimension * @param s3 Proportion of the third dimension */ - inline auto divideInProportions3D(unsigned int ntot, - unsigned int s1, - unsigned int s2, - unsigned int s3) - -> std::tuple { + inline auto divideInProportions3D( + unsigned int ntot, + unsigned int s1, + unsigned int s2, + unsigned int s3) -> std::tuple { auto n1 = (unsigned int)(std::cbrt( (double)ntot * (double)(SQR(s1)) / (double)(s2 * s3))); if (n1 > ntot) { @@ -163,10 +165,10 @@ namespace tools { * * @note If decomposition has -1, it will be calculated automatically */ - inline auto Decompose(unsigned int ndomains, - const std::vector& ncells, - const std::vector& decomposition) - -> std::vector> { + inline auto Decompose( + unsigned int ndomains, + const std::vector& ncells, + const std::vector& decomposition) -> std::vector> { const auto dimension = ncells.size(); raise::ErrorIf(dimension != decomposition.size(), "Decomposition error: dimension != decomposition.size", diff --git a/src/kernels/ampere_gr.hpp b/src/kernels/ampere_gr.hpp index 56f722902..327ce0cdf 100644 --- a/src/kernels/ampere_gr.hpp +++ b/src/kernels/ampere_gr.hpp @@ -74,8 +74,7 @@ namespace kernel::gr { if ((i2 == i2min) && is_axis_i2min) { // theta = 0 const real_t inv_polar_area_pH { ONE / metric.polar_area(i1_ + HALF) }; - const real_t inv_sqrt_detH_0pH { ONE / - metric.sqrt_det_h({ i1_, HALF }) }; + const real_t inv_sqrt_detH_0pH { ONE / metric.sqrt_det_h({ i1_, HALF }) }; Dout(i1, i2, em::dx1) = Din(i1, i2, em::dx1) + inv_polar_area_pH * coeff * H(i1, i2, em::hx3); Dout(i1, i2, em::dx2) = Din(i1, i2, em::dx2) + diff --git a/src/kernels/aux_fields_gr.hpp b/src/kernels/aux_fields_gr.hpp index 0983b6b7e..c2e45d6de 100644 --- a/src/kernels/aux_fields_gr.hpp +++ b/src/kernels/aux_fields_gr.hpp @@ -248,18 +248,24 @@ namespace kernel::gr { TimeAverageDB_kernel(const ndfield_t& BDf, const ndfield_t& BDf0, const M& metric) - : BDf { BDf } + : BDf { BDf } , BDf0 { BDf0 } , metric { metric } {} Inline void operator()(index_t i1, index_t i2) const { if constexpr (D == Dim::_2D) { - BDf0(i1, i2, em::bx1) = HALF * (BDf0(i1, i2, em::bx1) + BDf(i1, i2, em::bx1)); - BDf0(i1, i2, em::bx2) = HALF * (BDf0(i1, i2, em::bx2) + BDf(i1, i2, em::bx2)); - BDf0(i1, i2, em::bx3) = HALF * (BDf0(i1, i2, em::bx3) + BDf(i1, i2, em::bx3)); - BDf0(i1, i2, em::ex1) = HALF * (BDf0(i1, i2, em::ex1) + BDf(i1, i2, em::ex1)); - BDf0(i1, i2, em::ex2) = HALF * (BDf0(i1, i2, em::ex2) + BDf(i1, i2, em::ex2)); - BDf0(i1, i2, em::ex3) = HALF * (BDf0(i1, i2, em::ex3) + BDf(i1, i2, em::ex3)); + BDf0(i1, i2, em::bx1) = HALF * + (BDf0(i1, i2, em::bx1) + BDf(i1, i2, em::bx1)); + BDf0(i1, i2, em::bx2) = HALF * + (BDf0(i1, i2, em::bx2) + BDf(i1, i2, em::bx2)); + BDf0(i1, i2, em::bx3) = HALF * + (BDf0(i1, i2, em::bx3) + BDf(i1, i2, em::bx3)); + BDf0(i1, i2, em::ex1) = HALF * + (BDf0(i1, i2, em::ex1) + BDf(i1, i2, em::ex1)); + BDf0(i1, i2, em::ex2) = HALF * + (BDf0(i1, i2, em::ex2) + BDf(i1, i2, em::ex2)); + BDf0(i1, i2, em::ex3) = HALF * + (BDf0(i1, i2, em::ex3) + BDf(i1, i2, em::ex3)); } else { raise::KernelError( HERE, @@ -277,23 +283,26 @@ namespace kernel::gr { static_assert(M::is_metric, "M must be a metric class"); static constexpr auto D = M::Dim; - ndfield_t Jf; - const ndfield_t Jf0; + ndfield_t Jf; + const ndfield_t Jf0; const M metric; public: TimeAverageJ_kernel(const ndfield_t& Jf, const ndfield_t& Jf0, const M& metric) - : Jf { Jf } + : Jf { Jf } , Jf0 { Jf0 } , metric { metric } {} Inline void operator()(index_t i1, index_t i2) const { if constexpr (D == Dim::_2D) { - Jf(i1, i2, cur::jx1) = HALF * (Jf0(i1, i2, cur::jx1) + Jf(i1, i2, cur::jx1)); - Jf(i1, i2, cur::jx2) = HALF * (Jf0(i1, i2, cur::jx2) + Jf(i1, i2, cur::jx2)); - Jf(i1, i2, cur::jx3) = HALF * (Jf0(i1, i2, cur::jx3) + Jf(i1, i2, cur::jx3)); + Jf(i1, i2, cur::jx1) = HALF * + (Jf0(i1, i2, cur::jx1) + Jf(i1, i2, cur::jx1)); + Jf(i1, i2, cur::jx2) = HALF * + (Jf0(i1, i2, cur::jx2) + Jf(i1, i2, cur::jx2)); + Jf(i1, i2, cur::jx3) = HALF * + (Jf0(i1, i2, cur::jx3) + Jf(i1, i2, cur::jx3)); } else { raise::KernelError( HERE, diff --git a/src/kernels/comm.hpp b/src/kernels/comm.hpp index 6a47e56b4..60251d8c6 100644 --- a/src/kernels/comm.hpp +++ b/src/kernels/comm.hpp @@ -113,45 +113,45 @@ namespace kernel::comm { array_t send_buff_pld; const unsigned short NINTS, NREALS, NPRTLDX, NPLDS; - const npart_t idx_offset; + const npart_t idx_offset; - const array_t i1, i1_prev, i2, i2_prev, i3, i3_prev; - const array_t dx1, dx1_prev, dx2, dx2_prev, dx3, dx3_prev; - const array_t ux1, ux2, ux3, weight, phi; - const array_t pld; - array_t tag; - const array_t outgoing_indices; + const array_t i1, i1_prev, i2, i2_prev, i3, i3_prev; + const array_t dx1, dx1_prev, dx2, dx2_prev, dx3, dx3_prev; + const array_t ux1, ux2, ux3, weight, phi; + const array_t pld; + array_t tag; + const array_t outgoing_indices; public: - PopulatePrtlSendBuffer_kernel(array_t& send_buff_int, - array_t& send_buff_real, - array_t& send_buff_prtldx, - array_t& send_buff_pld, - unsigned short NINTS, - unsigned short NREALS, - unsigned short NPRTLDX, - unsigned short NPLDS, - npart_t idx_offset, - const array_t& i1, - const array_t& i1_prev, - const array_t& dx1, - const array_t& dx1_prev, - const array_t& i2, - const array_t& i2_prev, - const array_t& dx2, - const array_t& dx2_prev, - const array_t& i3, - const array_t& i3_prev, - const array_t& dx3, - const array_t& dx3_prev, - const array_t& ux1, - const array_t& ux2, - const array_t& ux3, - const array_t& weight, - const array_t& phi, - const array_t& pld, - array_t& tag, - const array_t& outgoing_indices) + PopulatePrtlSendBuffer_kernel(array_t& send_buff_int, + array_t& send_buff_real, + array_t& send_buff_prtldx, + array_t& send_buff_pld, + unsigned short NINTS, + unsigned short NREALS, + unsigned short NPRTLDX, + unsigned short NPLDS, + npart_t idx_offset, + const array_t& i1, + const array_t& i1_prev, + const array_t& dx1, + const array_t& dx1_prev, + const array_t& i2, + const array_t& i2_prev, + const array_t& dx2, + const array_t& dx2_prev, + const array_t& i3, + const array_t& i3_prev, + const array_t& dx3, + const array_t& dx3_prev, + const array_t& ux1, + const array_t& ux2, + const array_t& ux3, + const array_t& weight, + const array_t& phi, + const array_t& pld, + array_t& tag, + const array_t& outgoing_indices) : send_buff_int { send_buff_int } , send_buff_real { send_buff_real } , send_buff_prtldx { send_buff_prtldx } diff --git a/src/kernels/fields_bcs.hpp b/src/kernels/fields_bcs.hpp index 31dded501..5a1074970 100644 --- a/src/kernels/fields_bcs.hpp +++ b/src/kernels/fields_bcs.hpp @@ -840,30 +840,30 @@ namespace kernel::bc { Inline void operator()(index_t i1) const { if constexpr (D == Dim::_2D) { - // ! TODO: not all components are necessary + // ! TODO: not all components are necessary if constexpr (not P) { if (setE) { Fld(i1, i_edge - 1, em::ex2) = -Fld(i1, i_edge, em::ex2); - Fld(i1, i_edge, em::ex3) = ZERO; - Fld(i1, i_edge - 1, em::ex3) = Fld(i1, i_edge + 1, em::ex3); + Fld(i1, i_edge, em::ex3) = ZERO; + Fld(i1, i_edge - 1, em::ex3) = Fld(i1, i_edge + 1, em::ex3); } if (setB) { Fld(i1, i_edge - 1, em::bx1) = Fld(i1, i_edge, em::bx1); Fld(i1, i_edge, em::bx2) = ZERO; - Fld(i1, i_edge - 1, em::bx2) = - Fld(i1, i_edge + 1, em::bx2); + Fld(i1, i_edge - 1, em::bx2) = -Fld(i1, i_edge + 1, em::bx2); Fld(i1, i_edge - 1, em::bx3) = Fld(i1, i_edge, em::bx3); } } else { if (setE) { - Fld(i1, i_edge, em::ex2) = -Fld(i1, i_edge - 1, em::ex2); - Fld(i1, i_edge, em::ex3) = ZERO; + Fld(i1, i_edge, em::ex2) = -Fld(i1, i_edge - 1, em::ex2); + Fld(i1, i_edge, em::ex3) = ZERO; Fld(i1, i_edge + 1, em::ex3) = Fld(i1, i_edge - 1, em::ex3); } if (setB) { - Fld(i1, i_edge, em::bx1) = Fld(i1, i_edge - 1, em::bx1); - Fld(i1, i_edge, em::bx2) = ZERO; - Fld(i1, i_edge + 1, em::bx2) = - Fld(i1, i_edge - 1, em::bx2); - Fld(i1, i_edge, em::bx3) = Fld(i1, i_edge - 1, em::bx3); + Fld(i1, i_edge, em::bx1) = Fld(i1, i_edge - 1, em::bx1); + Fld(i1, i_edge, em::bx2) = ZERO; + Fld(i1, i_edge + 1, em::bx2) = -Fld(i1, i_edge - 1, em::bx2); + Fld(i1, i_edge, em::bx3) = Fld(i1, i_edge - 1, em::bx3); } } } else { diff --git a/src/kernels/particle_pusher_gr.hpp b/src/kernels/particle_pusher_gr.hpp index 1eb12494e..c1dfdf949 100644 --- a/src/kernels/particle_pusher_gr.hpp +++ b/src/kernels/particle_pusher_gr.hpp @@ -356,28 +356,22 @@ namespace kernel::gr { // DERIVATIVE_IN_TH((metric.template h<3, 3>), xp) * SQR(vp_mid[2]) + // TWO * DERIVATIVE_IN_TH((metric.template h<1, 3>), xp) * // vp_mid[0] * vp_mid[2])); - vp_upd[0] = - vp[0] + - dt * - (-metric.alpha(xp) * u0 * metric.dr_alpha(xp) + - vp_mid[0] * metric.dr_beta1(xp) - - (HALF / u0) * - (metric.dr_h11(xp) * SQR(vp_mid[0]) + - metric.dr_h22(xp) * SQR(vp_mid[1]) + - metric.dr_h33(xp) * SQR(vp_mid[2]) + - TWO * metric.dr_h13(xp) * - vp_mid[0] * vp_mid[2])); - vp_upd[1] = - vp[1] + - dt * - (-metric.alpha(xp) * u0 * metric.dt_alpha(xp) + - vp_mid[0] * metric.dt_beta1(xp) - - (HALF / u0) * - (metric.dt_h11(xp) * SQR(vp_mid[0]) + - metric.dt_h22(xp) * SQR(vp_mid[1]) + - metric.dt_h33(xp) * SQR(vp_mid[2]) + - TWO * metric.dt_h13(xp) * - vp_mid[0] * vp_mid[2])); + vp_upd[0] = vp[0] + + dt * (-metric.alpha(xp) * u0 * metric.dr_alpha(xp) + + vp_mid[0] * metric.dr_beta1(xp) - + (HALF / u0) * + (metric.dr_h11(xp) * SQR(vp_mid[0]) + + metric.dr_h22(xp) * SQR(vp_mid[1]) + + metric.dr_h33(xp) * SQR(vp_mid[2]) + + TWO * metric.dr_h13(xp) * vp_mid[0] * vp_mid[2])); + vp_upd[1] = vp[1] + + dt * (-metric.alpha(xp) * u0 * metric.dt_alpha(xp) + + vp_mid[0] * metric.dt_beta1(xp) - + (HALF / u0) * + (metric.dt_h11(xp) * SQR(vp_mid[0]) + + metric.dt_h22(xp) * SQR(vp_mid[1]) + + metric.dt_h33(xp) * SQR(vp_mid[2]) + + TWO * metric.dt_h13(xp) * vp_mid[0] * vp_mid[2])); } } else if constexpr (D == Dim::_3D) { raise::KernelNotImplementedError(HERE); @@ -680,10 +674,11 @@ namespace kernel::gr { coord_t xp_ { ZERO }; xp_[0] = xp[0]; - real_t theta_Cd { xp[1] }; - const real_t theta_Ph { metric.template convert<2, Crd::Cd, Crd::Ph>(theta_Cd) }; + real_t theta_Cd { xp[1] }; + const real_t theta_Ph { metric.template convert<2, Crd::Cd, Crd::Ph>( + theta_Cd) }; const real_t small_angle { constant::SMALL_ANGLE_GR }; - const auto large_angle { constant::PI - small_angle }; + const auto large_angle { constant::PI - small_angle }; if (theta_Ph < small_angle) { theta_Cd = metric.template convert<2, Crd::Ph, Crd::Cd>(small_angle); } else if (theta_Ph >= large_angle) { @@ -723,7 +718,7 @@ namespace kernel::gr { { (xp[0] + xp_upd[0]) * HALF, (xp[1] + xp_upd[1]) * HALF }, vp_upd, phi(p)); - + // update coordinate int i1_, i2_; prtldx_t dx1_, dx2_; diff --git a/src/kernels/particle_pusher_sr.hpp b/src/kernels/particle_pusher_sr.hpp index 6bd4e1714..91bc6a760 100644 --- a/src/kernels/particle_pusher_sr.hpp +++ b/src/kernels/particle_pusher_sr.hpp @@ -30,9 +30,7 @@ /* Local macros */ /* -------------------------------------------------------------------------- */ #define from_Xi_to_i(XI, I) \ - { \ - I = static_cast((XI + 1)) - 1; \ - } + { I = static_cast((XI + 1)) - 1; } #define from_Xi_to_i_di(XI, I, DI) \ { \ diff --git a/src/kernels/tests/ampere_mink.cpp b/src/kernels/tests/ampere_mink.cpp index ab4de8134..181946613 100644 --- a/src/kernels/tests/ampere_mink.cpp +++ b/src/kernels/tests/ampere_mink.cpp @@ -108,7 +108,7 @@ void testAmpere(const std::vector& res) { const real_t sx = constant::TWO_PI, sy = 4.0 * constant::PI; const auto metric = Minkowski { res, - {{ ZERO, sx }, { ZERO, sy }} + { { ZERO, sx }, { ZERO, sy } } }; auto emfield = ndfield_t { "emfield", res[0] + 2 * N_GHOSTS, @@ -116,7 +116,7 @@ void testAmpere(const std::vector& res) { const std::size_t i1min = N_GHOSTS, i1max = res[0] + N_GHOSTS; const std::size_t i2min = N_GHOSTS, i2max = res[1] + N_GHOSTS; const auto range = CreateRangePolicy({ i1min, i2min }, - { i1max, i2max }); + { i1max, i2max }); const auto range_ext = CreateRangePolicy( { 0, 0 }, { res[0] + 2 * N_GHOSTS, res[1] + 2 * N_GHOSTS }); @@ -213,7 +213,7 @@ void testAmpere(const std::vector& res) { sz = constant::TWO_PI; const auto metric = Minkowski { res, - {{ ZERO, sx }, { ZERO, sy }, { ZERO, sz }} + { { ZERO, sx }, { ZERO, sy }, { ZERO, sz } } }; auto emfield = ndfield_t { "emfield", res[0] + 2 * N_GHOSTS, @@ -223,7 +223,7 @@ void testAmpere(const std::vector& res) { const std::size_t i2min = N_GHOSTS, i2max = res[1] + N_GHOSTS; const std::size_t i3min = N_GHOSTS, i3max = res[2] + N_GHOSTS; const auto range = CreateRangePolicy({ i1min, i2min, i3min }, - { i1max, i2max, i3max }); + { i1max, i2max, i3max }); const auto range_ext = CreateRangePolicy( { 0, 0, 0 }, { res[0] + 2 * N_GHOSTS, res[1] + 2 * N_GHOSTS, res[2] + 2 * N_GHOSTS }); diff --git a/src/kernels/tests/ext_force.cpp b/src/kernels/tests/ext_force.cpp index 7f760e939..12e3466cf 100644 --- a/src/kernels/tests/ext_force.cpp +++ b/src/kernels/tests/ext_force.cpp @@ -53,18 +53,21 @@ struct Force { Force(real_t force) : force { force } {} - Inline auto fx1(const spidx_t&, const simtime_t&, const coord_t&) const - -> real_t { + Inline auto fx1(const spidx_t&, + const simtime_t&, + const coord_t&) const -> real_t { return force * math::sin(ONE) * math::sin(ONE); } - Inline auto fx2(const spidx_t&, const simtime_t&, const coord_t&) const - -> real_t { + Inline auto fx2(const spidx_t&, + const simtime_t&, + const coord_t&) const -> real_t { return force * math::sin(ONE) * math::cos(ONE); } - Inline auto fx3(const spidx_t&, const simtime_t&, const coord_t&) const - -> real_t { + Inline auto fx3(const spidx_t&, + const simtime_t&, + const coord_t&) const -> real_t { return force * math::cos(ONE); } diff --git a/src/kernels/tests/faraday_mink.cpp b/src/kernels/tests/faraday_mink.cpp index ce9f4c50c..db3b6d5bc 100644 --- a/src/kernels/tests/faraday_mink.cpp +++ b/src/kernels/tests/faraday_mink.cpp @@ -108,7 +108,7 @@ void testFaraday(const std::vector& res) { const real_t sx = constant::TWO_PI, sy = 4.0 * constant::PI; const auto metric = Minkowski { res, - {{ ZERO, sx }, { ZERO, sy }} + { { ZERO, sx }, { ZERO, sy } } }; auto emfield = ndfield_t { "emfield", res[0] + 2 * N_GHOSTS, @@ -116,7 +116,7 @@ void testFaraday(const std::vector& res) { const std::size_t i1min = N_GHOSTS, i1max = res[0] + N_GHOSTS; const std::size_t i2min = N_GHOSTS, i2max = res[1] + N_GHOSTS; const auto range = CreateRangePolicy({ i1min, i2min }, - { i1max, i2max }); + { i1max, i2max }); const auto range_ext = CreateRangePolicy( { 0, 0 }, { res[0] + 2 * N_GHOSTS, res[1] + 2 * N_GHOSTS }); @@ -212,7 +212,7 @@ void testFaraday(const std::vector& res) { sz = constant::TWO_PI; const auto metric = Minkowski { res, - {{ ZERO, sx }, { ZERO, sy }, { ZERO, sz }} + { { ZERO, sx }, { ZERO, sy }, { ZERO, sz } } }; auto emfield = ndfield_t { "emfield", res[0] + 2 * N_GHOSTS, @@ -222,7 +222,7 @@ void testFaraday(const std::vector& res) { const std::size_t i2min = N_GHOSTS, i2max = res[1] + N_GHOSTS; const std::size_t i3min = N_GHOSTS, i3max = res[2] + N_GHOSTS; const auto range = CreateRangePolicy({ i1min, i2min, i3min }, - { i1max, i2max, i3max }); + { i1max, i2max, i3max }); const auto range_ext = CreateRangePolicy( { 0, 0, 0 }, { res[0] + 2 * N_GHOSTS, res[1] + 2 * N_GHOSTS, res[2] + 2 * N_GHOSTS }); diff --git a/src/kernels/tests/fields_to_phys.cpp b/src/kernels/tests/fields_to_phys.cpp index 84554ed83..d05488242 100644 --- a/src/kernels/tests/fields_to_phys.cpp +++ b/src/kernels/tests/fields_to_phys.cpp @@ -45,7 +45,7 @@ void testFlds2Phys(const std::vector& res, } else { extent = { ext[0], - {ZERO, constant::PI} + { ZERO, constant::PI } }; } diff --git a/src/kernels/tests/flds_bc.cpp b/src/kernels/tests/flds_bc.cpp index bb27fff6e..4a9f50b5c 100644 --- a/src/kernels/tests/flds_bc.cpp +++ b/src/kernels/tests/flds_bc.cpp @@ -149,7 +149,9 @@ void testFldsBCs(const std::vector& res) { raise::KernelError(HERE, "incorrect ex1"); } if (not cmp::AlmostEqual(flds(i1, i2, em::ex2), THREE * (ONE - factor2))) { - Kokkos::printf("%f != %f\n", flds(i1, i2, em::ex2), THREE * (ONE - factor2)); + Kokkos::printf("%f != %f\n", + flds(i1, i2, em::ex2), + THREE * (ONE - factor2)); raise::KernelError(HERE, "incorrect ex2"); } if (not cmp::AlmostEqual(flds(i1, i2, em::bx2), FOUR * (ONE - factor1))) { @@ -173,22 +175,30 @@ void testFldsBCs(const std::vector& res) { FOUR * math::abs(x + HALF - xg_edge) / dx_abs); const auto factor2 = math::tanh(FOUR * math::abs(x - xg_edge) / dx_abs); if (not cmp::AlmostEqual(flds(i1, i2, i3, em::ex1), TWO * (ONE - factor1))) { - Kokkos::printf("%f != %f\n", flds(i1, i2, i3, em::ex1), TWO * (ONE - factor1)); + Kokkos::printf("%f != %f\n", + flds(i1, i2, i3, em::ex1), + TWO * (ONE - factor1)); raise::KernelError(HERE, "incorrect ex1"); } if (not cmp::AlmostEqual(flds(i1, i2, i3, em::ex2), THREE * (ONE - factor2))) { - Kokkos::printf("%f != %f\n", flds(i1, i2, i3, em::ex2), THREE * (ONE - factor2)); + Kokkos::printf("%f != %f\n", + flds(i1, i2, i3, em::ex2), + THREE * (ONE - factor2)); raise::KernelError(HERE, "incorrect ex2"); } if (not cmp::AlmostEqual(flds(i1, i2, i3, em::bx2), FOUR * (ONE - factor1))) { - Kokkos::printf("%f != %f\n", flds(i1, i2, i3, em::bx2), FOUR * (ONE - factor1)); + Kokkos::printf("%f != %f\n", + flds(i1, i2, i3, em::bx2), + FOUR * (ONE - factor1)); raise::KernelError(HERE, "incorrect bx2"); } if (not cmp::AlmostEqual(flds(i1, i2, i3, em::bx3), FIVE * (ONE - factor1))) { - Kokkos::printf("%f != %f\n", flds(i1, i2, i3, em::bx3), FIVE * (ONE - factor1)); + Kokkos::printf("%f != %f\n", + flds(i1, i2, i3, em::bx3), + FIVE * (ONE - factor1)); raise::KernelError(HERE, "incorrect bx3"); } }); diff --git a/src/metrics/kerr_schild.h b/src/metrics/kerr_schild.h index 186f160a1..e8626fb79 100644 --- a/src/metrics/kerr_schild.h +++ b/src/metrics/kerr_schild.h @@ -16,8 +16,8 @@ #include "global.h" #include "arch/kokkos_aliases.h" -#include "utils/numeric.h" #include "utils/comparators.h" +#include "utils/numeric.h" #include "metrics/metric_base.h" @@ -231,11 +231,12 @@ namespace metric { * @param x coordinate array in code units */ Inline auto dr_alpha(const coord_t& x) const -> real_t { - const real_t r {x[0] * dr + x1_min}; - const real_t theta {x[1] * dtheta + x2_min}; - const real_t dr_Sigma {TWO * r * dr}; + const real_t r { x[0] * dr + x1_min }; + const real_t theta { x[1] * dtheta + x2_min }; + const real_t dr_Sigma { TWO * r * dr }; - return - (dr * Sigma(r, theta) - r * dr_Sigma) * CUBE(alpha(x)) / SQR(Sigma(r, theta)); + return -(dr * Sigma(r, theta) - r * dr_Sigma) * CUBE(alpha(x)) / + SQR(Sigma(r, theta)); } /** @@ -243,8 +244,8 @@ namespace metric { * @param x coordinate array in code units */ Inline auto dt_alpha(const coord_t& x) const -> real_t { - const real_t r {x[0] * dr + x1_min}; - const real_t theta {x[1] * dtheta + x2_min}; + const real_t r { x[0] * dr + x1_min }; + const real_t theta { x[1] * dtheta + x2_min }; return CUBE(alpha(x)) * r * dt_Sigma(theta) / SQR(Sigma(r, theta)); } @@ -262,11 +263,12 @@ namespace metric { * @param x coordinate array in code units */ Inline auto dr_beta1(const coord_t& x) const -> real_t { - const real_t r {x[0] * dr + x1_min}; - const real_t theta {x[1] * dtheta + x2_min}; - const real_t dr_Sigma {TWO * r * dr}; + const real_t r { x[0] * dr + x1_min }; + const real_t theta { x[1] * dtheta + x2_min }; + const real_t dr_Sigma { TWO * r * dr }; - return dr_inv * TWO * (dr * Sigma(r, theta) - r * dr_Sigma) / SQR(Sigma(r, theta) + TWO * r); + return dr_inv * TWO * (dr * Sigma(r, theta) - r * dr_Sigma) / + SQR(Sigma(r, theta) + TWO * r); } /** @@ -274,9 +276,10 @@ namespace metric { * @param x coordinate array in code units */ Inline auto dt_beta1(const coord_t& x) const -> real_t { - const real_t r {x[0] * dr + x1_min}; - const real_t theta {x[1] * dtheta + x2_min}; - return - dr_inv * TWO * r * dt_Sigma(theta) / SQR(Sigma(r, theta) * (ONE + z(r, theta))); + const real_t r { x[0] * dr + x1_min }; + const real_t theta { x[1] * dtheta + x2_min }; + return -dr_inv * TWO * r * dt_Sigma(theta) / + SQR(Sigma(r, theta) * (ONE + z(r, theta))); } /** @@ -284,15 +287,17 @@ namespace metric { * @param x coordinate array in code units */ Inline auto dr_h11(const coord_t& x) const -> real_t { - const real_t r {x[0] * dr + x1_min}; - const real_t theta {x[1] * dtheta + x2_min}; - const real_t dr_Sigma {TWO * r * dr}; - const real_t dr_Delta {TWO * dr * (r - ONE)}; - const real_t dr_A {FOUR * r * dr * (SQR(r) + SQR(a)) - SQR(a) * SQR(math::sin(theta)) * dr_Delta}; + const real_t r { x[0] * dr + x1_min }; + const real_t theta { x[1] * dtheta + x2_min }; + const real_t dr_Sigma { TWO * r * dr }; + const real_t dr_Delta { TWO * dr * (r - ONE) }; + const real_t dr_A { FOUR * r * dr * (SQR(r) + SQR(a)) - + SQR(a) * SQR(math::sin(theta)) * dr_Delta }; - return (Sigma(r, theta) * (Sigma(r, theta) + TWO * r) * dr_A - - TWO * A(r, theta) * (r * dr_Sigma + Sigma(r, theta) * (dr_Sigma + dr))) - / (SQR(Sigma(r, theta) * (Sigma(r, theta) + TWO * r))) * SQR(dr_inv); + return (Sigma(r, theta) * (Sigma(r, theta) + TWO * r) * dr_A - + TWO * A(r, theta) * + (r * dr_Sigma + Sigma(r, theta) * (dr_Sigma + dr))) / + (SQR(Sigma(r, theta) * (Sigma(r, theta) + TWO * r))) * SQR(dr_inv); } /** @@ -300,11 +305,11 @@ namespace metric { * @param x coordinate array in code units */ Inline auto dr_h22(const coord_t& x) const -> real_t { - const real_t r {x[0] * dr + x1_min}; - const real_t theta {x[1] * dtheta + x2_min}; - const real_t dr_Sigma {TWO * r * dr}; + const real_t r { x[0] * dr + x1_min }; + const real_t theta { x[1] * dtheta + x2_min }; + const real_t dr_Sigma { TWO * r * dr }; - return - dr_Sigma / SQR(Sigma(r, theta)) * SQR(dtheta_inv); + return -dr_Sigma / SQR(Sigma(r, theta)) * SQR(dtheta_inv); } /** @@ -312,11 +317,11 @@ namespace metric { * @param x coordinate array in code units */ Inline auto dr_h33(const coord_t& x) const -> real_t { - const real_t r {x[0] * dr + x1_min}; - const real_t theta {x[1] * dtheta + x2_min}; - const real_t dr_Sigma {TWO * r * dr}; + const real_t r { x[0] * dr + x1_min }; + const real_t theta { x[1] * dtheta + x2_min }; + const real_t dr_Sigma { TWO * r * dr }; - return - dr_Sigma / SQR(Sigma(r, theta)) / SQR(math::sin(theta)); + return -dr_Sigma / SQR(Sigma(r, theta)) / SQR(math::sin(theta)); } /** @@ -324,11 +329,11 @@ namespace metric { * @param x coordinate array in code units */ Inline auto dr_h13(const coord_t& x) const -> real_t { - const real_t r {x[0] * dr + x1_min}; - const real_t theta {x[1] * dtheta + x2_min}; - const real_t dr_Sigma {TWO * r * dr}; + const real_t r { x[0] * dr + x1_min }; + const real_t theta { x[1] * dtheta + x2_min }; + const real_t dr_Sigma { TWO * r * dr }; - return - a * dr_Sigma / SQR(Sigma(r, theta)) * dr_inv; + return -a * dr_Sigma / SQR(Sigma(r, theta)) * dr_inv; } /** @@ -336,11 +341,13 @@ namespace metric { * @param x coordinate array in code units */ Inline auto dt_Sigma(const real_t& theta) const -> real_t { - const real_t dt_Sigma {- TWO * SQR(a) * math::sin(theta) * math::cos(theta) * dtheta}; - if (cmp::AlmostZero(dt_Sigma)) + const real_t dt_Sigma { -TWO * SQR(a) * math::sin(theta) * + math::cos(theta) * dtheta }; + if (cmp::AlmostZero(dt_Sigma)) { return ZERO; - else + } else { return dt_Sigma; + } } /** @@ -348,11 +355,13 @@ namespace metric { * @param x coordinate array in code units */ Inline auto dt_A(const real_t& r, const real_t& theta) const -> real_t { - const real_t dt_A {- TWO * SQR(a) * math::sin(theta) * math::cos(theta) * Delta(r) * dtheta}; - if (cmp::AlmostZero(dt_A)) + const real_t dt_A { -TWO * SQR(a) * math::sin(theta) * math::cos(theta) * + Delta(r) * dtheta }; + if (cmp::AlmostZero(dt_A)) { return ZERO; - else + } else { return dt_A; + } } /** @@ -360,11 +369,11 @@ namespace metric { * @param x coordinate array in code units */ Inline auto dt_h11(const coord_t& x) const -> real_t { - const real_t r {x[0] * dr + x1_min}; - const real_t theta {x[1] * dtheta + x2_min}; - return (Sigma(r, theta) * (Sigma(r, theta) + TWO * r) * dt_A(r, theta) - - TWO * A(r, theta) * dt_Sigma(theta) * (r + Sigma(r, theta))) - / (SQR(Sigma(r, theta) * (Sigma(r, theta) + TWO * r))) * SQR(dr_inv); + const real_t r { x[0] * dr + x1_min }; + const real_t theta { x[1] * dtheta + x2_min }; + return (Sigma(r, theta) * (Sigma(r, theta) + TWO * r) * dt_A(r, theta) - + TWO * A(r, theta) * dt_Sigma(theta) * (r + Sigma(r, theta))) / + (SQR(Sigma(r, theta) * (Sigma(r, theta) + TWO * r))) * SQR(dr_inv); } /** @@ -372,9 +381,9 @@ namespace metric { * @param x coordinate array in code units */ Inline auto dt_h22(const coord_t& x) const -> real_t { - const real_t r {x[0] * dr + x1_min}; - const real_t theta {x[1] * dtheta + x2_min}; - return - dt_Sigma(theta) / SQR(Sigma(r, theta)) * SQR(dtheta_inv); + const real_t r { x[0] * dr + x1_min }; + const real_t theta { x[1] * dtheta + x2_min }; + return -dt_Sigma(theta) / SQR(Sigma(r, theta)) * SQR(dtheta_inv); } /** @@ -382,9 +391,11 @@ namespace metric { * @param x coordinate array in code units */ Inline auto dt_h33(const coord_t& x) const -> real_t { - const real_t r {x[0] * dr + x1_min}; - const real_t theta {x[1] * dtheta + x2_min}; - return - TWO * dtheta * math::cos(theta) * (Sigma(r, theta) - SQR(a) * SQR(math::sin(theta))) / CUBE(math::sin(theta)) / SQR(Sigma(r, theta)); + const real_t r { x[0] * dr + x1_min }; + const real_t theta { x[1] * dtheta + x2_min }; + return -TWO * dtheta * math::cos(theta) * + (Sigma(r, theta) - SQR(a) * SQR(math::sin(theta))) / + CUBE(math::sin(theta)) / SQR(Sigma(r, theta)); } /** @@ -392,9 +403,9 @@ namespace metric { * @param x coordinate array in code units */ Inline auto dt_h13(const coord_t& x) const -> real_t { - const real_t r {x[0] * dr + x1_min}; - const real_t theta {x[1] * dtheta + x2_min}; - return - a * dt_Sigma(theta) / SQR(Sigma(r, theta)) * dr_inv; + const real_t r { x[0] * dr + x1_min }; + const real_t theta { x[1] * dtheta + x2_min }; + return -a * dt_Sigma(theta) / SQR(Sigma(r, theta)) * dr_inv; } /** diff --git a/src/metrics/kerr_schild_0.h b/src/metrics/kerr_schild_0.h index 3621b3e58..142e88b7a 100644 --- a/src/metrics/kerr_schild_0.h +++ b/src/metrics/kerr_schild_0.h @@ -238,9 +238,9 @@ namespace metric { * @param x coordinate array in code units */ Inline auto dr_h22(const coord_t& x) const -> real_t { - const real_t r {x[0] * dr + x1_min}; - const real_t theta {x[1] * dtheta + x2_min}; - return - TWO / CUBE(r) * SQR(dtheta_inv) * dr; + const real_t r { x[0] * dr + x1_min }; + const real_t theta { x[1] * dtheta + x2_min }; + return -TWO / CUBE(r) * SQR(dtheta_inv) * dr; } /** @@ -248,9 +248,9 @@ namespace metric { * @param x coordinate array in code units */ Inline auto dr_h33(const coord_t& x) const -> real_t { - const real_t r {x[0] * dr + x1_min}; - const real_t theta {x[1] * dtheta + x2_min}; - return - TWO / CUBE(r) / SQR(math::sin(theta)) * dr; + const real_t r { x[0] * dr + x1_min }; + const real_t theta { x[1] * dtheta + x2_min }; + return -TWO / CUBE(r) / SQR(math::sin(theta)) * dr; } /** @@ -282,9 +282,9 @@ namespace metric { * @param x coordinate array in code units */ Inline auto dt_h33(const coord_t& x) const -> real_t { - const real_t r {x[0] * dr + x1_min}; - const real_t theta {x[1] * dtheta + x2_min}; - return - TWO * math::cos(theta) / SQR(r) / CUBE(math::sin(theta)) * dtheta; + const real_t r { x[0] * dr + x1_min }; + const real_t theta { x[1] * dtheta + x2_min }; + return -TWO * math::cos(theta) / SQR(r) / CUBE(math::sin(theta)) * dtheta; } /** diff --git a/src/metrics/minkowski.h b/src/metrics/minkowski.h index 96c665a3f..cf4aad2b6 100644 --- a/src/metrics/minkowski.h +++ b/src/metrics/minkowski.h @@ -258,8 +258,7 @@ namespace metric { * @note tetrad/cart <-> cntrv <-> cov */ template - Inline auto transform(const coord_t& xi, const real_t& v_in) const - -> real_t { + Inline auto transform(const coord_t& xi, const real_t& v_in) const -> real_t { static_assert(i > 0 && i <= 3, "Invalid index i"); static_assert(in != out, "Invalid vector transformation"); if constexpr (i > static_cast(D)) { diff --git a/src/metrics/qspherical.h b/src/metrics/qspherical.h index 534b1f764..4acfda442 100644 --- a/src/metrics/qspherical.h +++ b/src/metrics/qspherical.h @@ -307,8 +307,7 @@ namespace metric { * @note tetrad/sph <-> cntrv <-> cov */ template - Inline auto transform(const coord_t& xi, const real_t& v_in) const - -> real_t { + Inline auto transform(const coord_t& xi, const real_t& v_in) const -> real_t { static_assert(i > 0 && i <= 3, "Invalid index i"); static_assert(in != out, "Invalid vector transformation"); if constexpr ((in == Idx::T && out == Idx::Sph) || diff --git a/src/metrics/spherical.h b/src/metrics/spherical.h index 5b5f87056..388d3710e 100644 --- a/src/metrics/spherical.h +++ b/src/metrics/spherical.h @@ -275,8 +275,7 @@ namespace metric { * @note tetrad/sph <-> cntrv <-> cov */ template - Inline auto transform(const coord_t& xi, const real_t& v_in) const - -> real_t { + Inline auto transform(const coord_t& xi, const real_t& v_in) const -> real_t { static_assert(i > 0 && i <= 3, "Invalid index i"); static_assert(in != out, "Invalid vector transformation"); if constexpr ((in == Idx::T && out == Idx::Sph) || diff --git a/src/metrics/tests/ks-qks.cpp b/src/metrics/tests/ks-qks.cpp index 98be577ec..ea05c0f92 100644 --- a/src/metrics/tests/ks-qks.cpp +++ b/src/metrics/tests/ks-qks.cpp @@ -139,12 +139,12 @@ void testMetric(const std::vector& res, if (not equal(h_ij_predict, h_ij_expect, "h_ij", acc)) { Kokkos::printf("h_ij: %.12e %.12e %.12e : %.12e %.12e %.12e\n", - h_ij_predict[0], - h_ij_predict[1], - h_ij_predict[2], - h_ij_expect[0], - h_ij_expect[1], - h_ij_expect[2]); + h_ij_predict[0], + h_ij_predict[1], + h_ij_predict[2], + h_ij_expect[0], + h_ij_expect[1], + h_ij_expect[2]); Kokkos::abort("h_ij"); } if (not equal(h_13_predict, { h_13_expect }, "h_13", acc)) { @@ -153,12 +153,12 @@ void testMetric(const std::vector& res, } if (not equal(hij_predict, hij_expect, "hij", acc)) { Kokkos::printf("hij: %.12e %.12e %.12e : %.12e %.12e %.12e\n", - hij_predict[0], - hij_predict[1], - hij_predict[2], - hij_expect[0], - hij_expect[1], - hij_expect[2]); + hij_predict[0], + hij_predict[1], + hij_predict[2], + hij_expect[0], + hij_expect[1], + hij_expect[2]); Kokkos::abort("hij"); } if (not equal(h13_predict, { h13_expect }, "h13", acc)) { diff --git a/src/metrics/tests/minkowski.cpp b/src/metrics/tests/minkowski.cpp index 4c7d7791c..2386d65d2 100644 --- a/src/metrics/tests/minkowski.cpp +++ b/src/metrics/tests/minkowski.cpp @@ -19,8 +19,7 @@ void errorIf(bool condition, const std::string& message) { inline static constexpr auto epsilon = std::numeric_limits::epsilon(); template -Inline auto equal(const coord_t& a, const coord_t& b, real_t acc = ONE) - -> bool { +Inline auto equal(const coord_t& a, const coord_t& b, real_t acc = ONE) -> bool { for (auto d { 0u }; d < D; ++d) { if (not cmp::AlmostEqual(a[d], b[d], epsilon * acc)) { Kokkos::printf("%d : %.12f != %.12f\n", d, a[d], b[d]); diff --git a/src/metrics/tests/sph-qsph.cpp b/src/metrics/tests/sph-qsph.cpp index 12c37bf6b..faac28562 100644 --- a/src/metrics/tests/sph-qsph.cpp +++ b/src/metrics/tests/sph-qsph.cpp @@ -115,12 +115,12 @@ auto main(int argc, char* argv[]) -> int { using namespace metric; const auto res = std::vector { 64, 32 }; const auto ext = boundaries_t { - {1.0, 10.0}, - {0.0, constant::PI} + { 1.0, 10.0 }, + { 0.0, constant::PI } }; const auto params = std::map { - {"r0", -ONE}, - { "h", (real_t)0.25} + { "r0", -ONE }, + { "h", (real_t)0.25 } }; testMetric>(res, ext, 10); diff --git a/src/output/tests/writer-mpi.cpp b/src/output/tests/writer-mpi.cpp index 72a8f87ec..bc95bbc81 100644 --- a/src/output/tests/writer-mpi.cpp +++ b/src/output/tests/writer-mpi.cpp @@ -159,12 +159,12 @@ auto main(int argc, char* argv[]) -> int { field_read(i1), field(i1 * dwn1 + first_cell + i1min, cntr))) { Kokkos::printf("\n:::::::::::::::\nfield_read(%ld) = %f != " - "field(%ld, %d) = %f\n:::::::::::::::\n", - i1, - field_read(i1), - i1 * dwn1 + first_cell + i1min, - cntr, - field(i1 * dwn1 + first_cell + i1min, cntr)); + "field(%ld, %d) = %f\n:::::::::::::::\n", + i1, + field_read(i1), + i1 * dwn1 + first_cell + i1min, + cntr, + field(i1 * dwn1 + first_cell + i1min, cntr)); raise::KernelError(HERE, "Field is not read correctly"); } }); diff --git a/src/output/tests/writer-nompi.cpp b/src/output/tests/writer-nompi.cpp index 6e0c30859..66d834f43 100644 --- a/src/output/tests/writer-nompi.cpp +++ b/src/output/tests/writer-nompi.cpp @@ -179,20 +179,18 @@ auto main(int argc, char* argv[]) -> int { i2 * dwn2 + i2min, i3 * dwn3 + i3min, cntr))) { - Kokkos::printf("\n:::::::::::::::\nfield_read(%ld, %ld, %ld) = %f != " - "field(%ld, %ld, %ld, %d) = %f\n:::::::::::::::\n", - i1, - i2, - i3, - field_read(i1, i2, i3), - i1 * dwn1 + i1min, - i2 * dwn2 + i2min, - i3 * dwn3 + i3min, - cntr, - field(i1 * dwn1 + i1min, - i2 * dwn2 + i2min, - i3 * dwn3 + i3min, - cntr)); + Kokkos::printf( + "\n:::::::::::::::\nfield_read(%ld, %ld, %ld) = %f != " + "field(%ld, %ld, %ld, %d) = %f\n:::::::::::::::\n", + i1, + i2, + i3, + field_read(i1, i2, i3), + i1 * dwn1 + i1min, + i2 * dwn2 + i2min, + i3 * dwn3 + i3min, + cntr, + field(i1 * dwn1 + i1min, i2 * dwn2 + i2min, i3 * dwn3 + i3min, cntr)); raise::KernelError(HERE, "Field is not read correctly"); } }); diff --git a/src/output/utils/interpret_prompt.h b/src/output/utils/interpret_prompt.h index 488d81101..032482cf8 100644 --- a/src/output/utils/interpret_prompt.h +++ b/src/output/utils/interpret_prompt.h @@ -26,8 +26,8 @@ namespace out { auto InterpretSpecies(const std::string&) -> std::vector; - auto InterpretComponents(const std::vector&) - -> std::vector>; + auto InterpretComponents( + const std::vector&) -> std::vector>; } // namespace out