diff --git a/CMakeLists.txt b/CMakeLists.txt index b9633bb88..ce0ddf748 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -35,7 +35,7 @@ include("${PHARE_PROJECT_DIR}/res/cmake/coverage.cmake") include("${PHARE_PROJECT_DIR}/res/cmake/dep.cmake") include("${PHARE_PROJECT_DIR}/res/cmake/cppcheck.cmake") -set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) #### post deps config diff --git a/res/cmake/def.cmake b/res/cmake/def.cmake index 2d68b4c96..db31c4ba9 100644 --- a/res/cmake/def.cmake +++ b/res/cmake/def.cmake @@ -5,7 +5,9 @@ set (PHARE_FLAGS ${PHARE_FLAGS} ) if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") set (PHARE_FLAGS ${PHARE_FLAGS} ) else() # !Clang - set (PHARE_FLAGS ${PHARE_FLAGS} --param=min-pagesize=0 ) + # --param=min-pagesize=0 https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105523 + # --param=evrp-mode=legacy https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105329 + set (PHARE_FLAGS ${PHARE_FLAGS} --param=min-pagesize=0 --param=evrp-mode=legacy ) endif() # clang set (PHARE_LINK_FLAGS ) diff --git a/src/amr/data/particles/particles_data.hpp b/src/amr/data/particles/particles_data.hpp index f9a3cd785..060e0017a 100644 --- a/src/amr/data/particles/particles_data.hpp +++ b/src/amr/data/particles/particles_data.hpp @@ -178,7 +178,7 @@ namespace amr using Packer = core::ParticlePacker; auto getParticles = [&](std::string const name, auto& particles) { - auto const keys_exist = core::generate( + std::array keys_exist = core::generate( [&](auto const& key) { return restart_db->keyExists(name + "_" + key); }, Packer::keys()); diff --git a/src/core/data/grid/gridlayout.hpp b/src/core/data/grid/gridlayout.hpp index d737adab3..b70d5c31d 100644 --- a/src/core/data/grid/gridlayout.hpp +++ b/src/core/data/grid/gridlayout.hpp @@ -559,7 +559,7 @@ namespace core /** * @brief the number of ghost nodes on each side of the mesh for a given centering */ - NO_DISCARD auto static constexpr nbrGhosts( + NO_DISCARD std::uint32_t static constexpr nbrGhosts( QtyCentering /*centering*/ = QtyCentering::primal) { // Both dual and primal ghosts are the same! static_assert(nbrDualGhosts_() == nbrPrimalGhosts_()); @@ -569,7 +569,7 @@ namespace core template - NO_DISCARD auto static constexpr nbrGhosts() + NO_DISCARD std::uint32_t static constexpr nbrGhosts() { if constexpr (centering == QtyCentering::dual) return nbrDualGhosts_(); diff --git a/src/core/data/particles/particle_packer.hpp b/src/core/data/particles/particle_packer.hpp index ed544102e..ab00f843a 100644 --- a/src/core/data/particles/particle_packer.hpp +++ b/src/core/data/particles/particle_packer.hpp @@ -15,6 +15,8 @@ template class ParticlePacker { public: + static constexpr std::size_t n_keys = 5; + ParticlePacker(ParticleArray const& particles) : particles_{particles} { @@ -63,7 +65,8 @@ class ParticlePacker private: ParticleArray const& particles_; std::size_t it_ = 0; - static inline std::array keys_{"weight", "charge", "iCell", "delta", "v"}; + static inline const std::array keys_{"weight", "charge", "iCell", "delta", + "v"}; }; diff --git a/src/core/utilities/box/box.hpp b/src/core/utilities/box/box.hpp index fd3e1fe09..41a3697a2 100644 --- a/src/core/utilities/box/box.hpp +++ b/src/core/utilities/box/box.hpp @@ -33,20 +33,21 @@ struct Box Box() = default; - constexpr Box(std::array _lower, std::array _upper) + constexpr Box(std::array const& _lower, std::array const& _upper) : lower{_lower} , upper{_upper} { } template - Box(Point _lower, Point _upper) + Box(Point const& _lower, Point const& _upper) : lower{_lower} , upper{_upper} { } - NO_DISCARD bool operator==(Box const& box) const + template + NO_DISCARD bool operator==(Box const& box) const { return box.lower == lower && box.upper == upper; } diff --git a/src/core/utilities/point/point.hpp b/src/core/utilities/point/point.hpp index 754b0a12e..95c1e6c1e 100644 --- a/src/core/utilities/point/point.hpp +++ b/src/core/utilities/point/point.hpp @@ -49,8 +49,8 @@ namespace core } - constexpr Point(std::array coords) - : r{std::move(coords)} + constexpr Point(std::array const& coords) + : r{coords} { } @@ -69,7 +69,8 @@ namespace core NO_DISCARD auto const& operator[](std::size_t i) const { return r[i]; } - NO_DISCARD bool operator==(Point const& p) const + template + NO_DISCARD bool operator==(Point const& p) const { bool areEqual = true; for (std::size_t i = 0; i < dim; ++i) @@ -77,7 +78,7 @@ namespace core static_assert(std::is_integral_v, "this function is only valid for integral type of Point"); - areEqual &= ((*this)[i] == p[i]); + areEqual &= int_equals((*this)[i], p[i]); // handles signed differences } return areEqual; } diff --git a/src/core/utilities/types.hpp b/src/core/utilities/types.hpp index 485ad3e87..b3022b433 100644 --- a/src/core/utilities/types.hpp +++ b/src/core/utilities/types.hpp @@ -281,7 +281,7 @@ NO_DISCARD auto generate(F&& f, std::size_t count) template -NO_DISCARD auto generate(F&& f, Container& container) +NO_DISCARD auto generate(F&& f, Container const& container) { using T = typename Container::value_type; using value_type = std::decay_t>; @@ -300,13 +300,13 @@ NO_DISCARD auto generate(F&& f, std::vector&& v) } template -NO_DISCARD auto constexpr generate_array__(F& f, std::array& arr) +NO_DISCARD auto constexpr generate_array__(F& f, std::array const& arr) { return f(arr[Idx]); } template -NO_DISCARD auto constexpr generate_array_(F& f, std::array& arr, +NO_DISCARD auto constexpr generate_array_(F& f, std::array const& arr, std::integer_sequence) { return std::array{generate_array__(f, arr)...}; @@ -336,13 +336,41 @@ NO_DISCARD auto any(Container const& container, Fn fn = to_bool) return std::any_of(container.begin(), container.end(), fn); } - template NO_DISCARD auto none(Container const& container, Fn fn = to_bool) { return std::none_of(container.begin(), container.end(), fn); } + +template +bool diff_sign_int_equals(SignedInt const& i0, UnsignedInt const& i1) +{ + static_assert(std::is_unsigned_v); + static_assert(std::is_signed_v); + static_assert(sizeof(UnsignedInt) >= sizeof(SignedInt), "Bad int comparison!"); + if (i0 < 0) + return false; + return static_cast(i0) == i1; +} + + +template +bool int_equals(Int0 const& i0, Int1 const& i1) +{ + if constexpr (std::is_same_v) + return i0 == i1; + else + { + if constexpr (std::is_unsigned_v and std::is_signed_v) + return diff_sign_int_equals(i1, i0); + if constexpr (std::is_unsigned_v and std::is_signed_v) + return diff_sign_int_equals(i0, i1); + } + // reaching here == compiler error +} + + auto inline float_equals(float const& a, float const& b, float diff = 1e-6) { return std::abs(a - b) < diff; diff --git a/src/simulator/simulator.hpp b/src/simulator/simulator.hpp index 5475925fa..539f6a3b0 100644 --- a/src/simulator/simulator.hpp +++ b/src/simulator/simulator.hpp @@ -38,6 +38,8 @@ class ISimulator virtual std::string to_str() = 0; virtual ~ISimulator() {} + + virtual bool dump(double timestamp, double timestep) { return false; } // overriding optional }; @@ -106,6 +108,9 @@ class Simulator : public ISimulator using Integrator = PHARE::amr::Integrator; +protected: + // provided to force flush for diags + void reset_dman() { this->dMan.reset(); } private: auto find_model(std::string name); diff --git a/tests/core/data/gridlayout/gridlayout_amr.cpp b/tests/core/data/gridlayout/gridlayout_amr.cpp index d1c319254..d18bf223d 100644 --- a/tests/core/data/gridlayout/gridlayout_amr.cpp +++ b/tests/core/data/gridlayout/gridlayout_amr.cpp @@ -80,11 +80,13 @@ TEST(GridLayout, canTransformAnAMRIndexIntoALocalIndex) TEST(GridLayout, canTransformAnAMRBoxIntoALocalBox) { - GridLayout> layout{{0.1}, {50u}, {{0.}}, Box{Point{50}, Point{99}}}; + std::size_t constexpr static dim = 1; + GridLayout> layout{{0.1}, {50u}, {{0.}}, Box{Point{50}, Point{99}}}; - int nGhosts = layout.nbrGhosts(QtyCentering::dual); - auto AMRBox = Box{Point{55}, Point{65}}; - auto expectedLocalBox = Box{Point{nGhosts + 5}, Point{nGhosts + 15}}; + std::uint32_t nGhosts = layout.nbrGhosts(QtyCentering::dual); + auto AMRBox = Box{Point{55}, Point{65}}; + auto expectedLocalBox = Box{Point{nGhosts + 5}, + Point{nGhosts + 15}}; EXPECT_EQ(expectedLocalBox, layout.AMRToLocal(AMRBox)); } diff --git a/tests/core/utilities/box/test_box.cpp b/tests/core/utilities/box/test_box.cpp index e6e429702..1e2fac759 100644 --- a/tests/core/utilities/box/test_box.cpp +++ b/tests/core/utilities/box/test_box.cpp @@ -197,54 +197,63 @@ TEST(BoxIterator, iterates) Box b2{{1, 4}, {10, 12}}; Box b3{{1, 4, 9}, {10, 12, 24}}; - auto expected = Point{2}; - auto actual = std::begin(b1); - EXPECT_EQ(expected, *(++actual)); - - auto const cexpected = Point{2}; - auto cactual = std::begin(cb1); - EXPECT_EQ(cexpected, *(++cactual)); - - auto expected2 = Point{1, 5}; - auto actual2 = std::begin(b2); - EXPECT_EQ(expected2, *(++actual2)); - - auto expected3 = Point{1, 4, 10}; - auto actual3 = std::begin(b3); - EXPECT_EQ(expected3, *(++actual3)); - - Box small{{2, 1}, {3, 2}}; - auto it = std::begin(small); - ++it; - expected = Point{2, 2}; - EXPECT_EQ(expected, *it); - ++it; - expected = Point{3, 1}; - EXPECT_EQ(expected, *it); - - auto dummy1 = Point{}; - for (auto const& point : b1) { - dummy1 = point; + auto expected = Point{2}; + auto actual = std::begin(b1); + EXPECT_EQ(expected, *(++actual)); } - auto expected1 = Point{10}; - EXPECT_EQ(expected1, dummy1); - - auto dummy = Point{}; - for (auto const& point : b2) { - dummy = point; + auto const cexpected = Point{2}; + auto cactual = std::begin(cb1); + EXPECT_EQ(cexpected, *(++cactual)); + } + { + auto expected2 = Point{1, 5}; + auto actual2 = std::begin(b2); + EXPECT_EQ(expected2, *(++actual2)); + } + { + auto expected3 = Point{1, 4, 10}; + auto actual3 = std::begin(b3); + EXPECT_EQ(expected3, *(++actual3)); + } + { + Box small{{2, 1}, {3, 2}}; + auto it = std::begin(small); + ++it; + auto expected = Point{2, 2}; + EXPECT_EQ(expected, *it); + ++it; + expected = Point{3, 1}; + EXPECT_EQ(expected, *it); + } + { + auto dummy1 = Point{}; + for (auto const& point : b1) + { + dummy1 = point; + } + auto expected1 = Point{10}; + EXPECT_EQ(expected1, dummy1); + } + { + auto dummy = Point{}; + for (auto const& point : b2) + { + dummy = point; + } + auto expected = Point{10, 12}; + EXPECT_EQ(expected, dummy); } - expected = Point{10, 12}; - EXPECT_EQ(expected, dummy); - - auto dummy3 = Point{}; - for (auto const& point : b3) { - dummy3 = point; + auto dummy3 = Point{}; + for (auto const& point : b3) + { + dummy3 = point; + } + auto expected = Point{10, 12, 24}; + EXPECT_EQ(expected, dummy3); } - expected = Point{10, 12, 24}; - EXPECT_EQ(expected, dummy3); } diff --git a/tests/diagnostic/test_diagnostics.hpp b/tests/diagnostic/test_diagnostics.hpp index a560db732..04575ba86 100644 --- a/tests/diagnostic/test_diagnostics.hpp +++ b/tests/diagnostic/test_diagnostics.hpp @@ -85,6 +85,11 @@ struct Hi5Diagnostic return Writer_t::getFullPatchPath(timestamp, level, patch); } + void dump(double current_timestamp = 0, double current_timestep = 1) + { + dMan.dump(current_timestamp, current_timestep); + } + Hierarchy& hierarchy_; HybridModel& model_; std::string out_; diff --git a/tests/diagnostic/test_diagnostics.ipp b/tests/diagnostic/test_diagnostics.ipp index 1c15f150a..b6813b165 100644 --- a/tests/diagnostic/test_diagnostics.ipp +++ b/tests/diagnostic/test_diagnostics.ipp @@ -23,7 +23,7 @@ void fluid_test(Simulator&& sim, std::string out_dir) .addDiagDict(hi5.fluid("/ions/pop/protons/density")) .addDiagDict(hi5.fluid("/ions/pop/protons/flux")) .addDiagDict(hi5.fluid("/ions/pop/protons/momentum_tensor")); - sim.dump(hi5.dMan); + hi5.dump(); } Hi5Diagnostic hi5{hierarchy, hybridModel, out_dir, @@ -42,7 +42,7 @@ void electromag_test(Simulator&& sim, std::string out_dir) { // scoped to destruct after dump Hi5Diagnostic hi5{hierarchy, hybridModel, out_dir, NEW_HI5_FILE}; hi5.dMan.addDiagDict(hi5.electromag("/EM_B")).addDiagDict(hi5.electromag("/EM_E")); - sim.dump(hi5.dMan); + hi5.dump(); } Hi5Diagnostic hi5{hierarchy, hybridModel, out_dir, @@ -68,7 +68,7 @@ void particles_test(Simulator&& sim, std::string out_dir) .addDiagDict(hi5.particles("/ions/pop/protons/domain")) .addDiagDict(hi5.particles("/ions/pop/protons/levelGhost")) .addDiagDict(hi5.particles("/ions/pop/protons/patchGhost")); - sim.dump(hi5.dMan); + hi5.dump(); } Hi5Diagnostic hi5{hierarchy, hybridModel, out_dir, @@ -83,11 +83,11 @@ void allFromPython_test(Simulator&& sim, std::string out_dir) using HybridModel = typename Simulator::HybridModel; using Hierarchy = typename Simulator::Hierarchy; - sim.dump(*sim.dMan); + sim.dump(/*timestamp= */ 0, /*timestep= */ 1); // flush h5files, killing the DiagnosticsManager killes the H5TypeWriter shared_ptrs internally, // and forces closed any open h5files, flushing any remaining contents, which we use below in // this test - sim.dMan.reset(); + sim.reset_dman(); auto& hybridModel = *sim.getHybridModel(); auto& hierarchy = *sim.hierarchy; diff --git a/tests/functional/harris/harris_2d_2.py b/tests/functional/harris/harris_2d_2.py new file mode 100644 index 000000000..9c7808449 --- /dev/null +++ b/tests/functional/harris/harris_2d_2.py @@ -0,0 +1,104 @@ +#!/usr/bin/env python3 + +import pyphare.pharein as ph +from pyphare.simulator.simulator import Simulator, startMPI + +import numpy as np +import matplotlib as mpl + +mpl.use("Agg") + + +def config(): + L = 0.5 + sim = ph.Simulation( + time_step=0.005, + time_step_nbr=5, + cells=(800, 400), + dl=(0.40, 0.40), + refinement="tagging", + max_nbr_levels=1, + nesting_buffer=1, + clustering="tile", + tag_buffer="10", + hyper_resistivity=0.002, + resistivity=0.001, + strict=True, + ) + + def density(x, y): + Ly = sim.simulation_domain()[1] + return ( + 0.4 + + 1.0 / np.cosh((y - Ly * 0.3) / L) ** 2 + + 1.0 / np.cosh((y - Ly * 0.7) / L) ** 2 + ) + + def S(y, y0, l): + return 0.5 * (1.0 + np.tanh((y - y0) / l)) + + def by(x, y): + Lx, Ly = sim.simulation_domain() + sigma = 1.0 + dB = 0.1 + x0 = x - 0.5 * Lx + y1 = y - 0.3 * Ly + y2 = y - 0.7 * Ly + dBy1 = 2 * dB * x0 * np.exp(-(x0**2 + y1**2) / (sigma) ** 2) + dBy2 = -2 * dB * x0 * np.exp(-(x0**2 + y2**2) / (sigma) ** 2) + return dBy1 + dBy2 + + def bx(x, y): + Lx, Ly = sim.simulation_domain() + sigma = 1.0 + dB = 0.1 + x0 = x - 0.5 * Lx + y1 = y - 0.3 * Ly + y2 = y - 0.7 * Ly + dBx1 = -2 * dB * y1 * np.exp(-(x0**2 + y1**2) / (sigma) ** 2) + dBx2 = 2 * dB * y2 * np.exp(-(x0**2 + y2**2) / (sigma) ** 2) + v1 = -1 + v2 = 1.0 + return v1 + (v2 - v1) * (S(y, Ly * 0.3, L) - S(y, Ly * 0.7, L)) + dBx1 + dBx2 + + def bz(x, y): + return 0.0 + + def b2(x, y): + return bx(x, y) ** 2 + by(x, y) ** 2 + bz(x, y) ** 2 + + def T(x, y): + K = 0.7 + temp = 1.0 / density(x, y) * (K - b2(x, y) * 0.5) + assert np.all(temp > 0) + return temp + + def vxyz(x, y): + return 0.0 + + def vthxyz(x, y): + return np.sqrt(T(x, y)) + + ph.MaxwellianFluidModel( + bx=bx, + by=by, + bz=bz, + protons={ + "charge": 1, + "density": density, + "vbulkx": vxyz, + "vbulky": vxyz, + "vbulkz": vxyz, + "vthx": vthxyz, + "vthy": vthxyz, + "vthz": vthxyz, + "nbr_part_per_cell": 100, + "init": {"seed": 1333337}, + }, + ) + ph.ElectronModel(closure="isothermal", Te=0.0) + return sim + + +if __name__ == "__main__": + Simulator(config()).run() diff --git a/tests/simulator/per_test.hpp b/tests/simulator/per_test.hpp index 91d428d09..d4a8be4e0 100644 --- a/tests/simulator/per_test.hpp +++ b/tests/simulator/per_test.hpp @@ -49,8 +49,6 @@ struct SimulatorTestParam : private HierarchyMaker<_dim>, using MHDModel = typename PHARETypes::MHDModel_t; using HierarchyMaker::hierarchy; - std::unique_ptr dMan; - auto& dict(std::string job_py) { auto& input = StaticIntepreter::INSTANCE().input; @@ -68,21 +66,9 @@ struct SimulatorTestParam : private HierarchyMaker<_dim>, , Simulator{dict(job_py), this->hierarchy} { Simulator::initialize(); - - if (dict(job_py)["simulation"].contains("diagnostics")) - { - dMan = PHARE::diagnostic::DiagnosticsManagerResolver::make_unique( - *this->hierarchy, *this->getHybridModel(), - dict(job_py)["simulation"]["diagnostics"]); - } } - - template - void dump(DMan& dman, double current_timestamp = 0, double current_timestep = 1) - { - dman.dump(current_timestamp, current_timestep); - } + void reset_dman() { Simulator::reset_dman(); } }; template