diff --git a/CHANGELOG.md b/CHANGELOG.md index 450347f6826f2..4782501a84df6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ ## Current develop ### Added (new features/APIs/variables/...) +- [[PR 1391]](https://github.com/parthenon-hpc-lab/parthenon/pull/1391) Towards Curvilinear Swarms - [[PR 1408]](https://github.com/parthenon-hpc-lab/parthenon/pull/1408) Add GetAsUnresolvedString() method to ParameterInput - [[PR 1050]](https://github.com/parthenon-hpc-lab/parthenon/pull/1050) Add support for OpenPMD/ADIOS2 output (incl slices and coarsened dumps) - [[PR 1271]](https://github.com/parthenon-hpc-lab/parthenon/pull/1271) Add option to set a minimum number of teams for boundary communication kernels @@ -51,6 +52,7 @@ ### Incompatibilities (i.e. breaking changes) +- [[PR 1391]](https://github.com/parthenon-hpc-lab/parthenon/pull/1391) Towards Curvilinear Swarms - [[PR 1385]](https://github.com/parthenon-hpc-lab/parthenon/pull/1385) ParameterInput internal storage refactor removes direct access to linked list (`pfirst_block`). Use `GetBlocksWithPrefix()` or `GetBlockNames()` instead. - [[PR 1351]](https://github.com/parthenon-hpc-lab/parthenon/pull/1351) Bump Kokkos 5 & C++20 - [[PR 1377]](https://github.com/parthenon-hpc-lab/parthenon/pull/1377) Extend Initialization Hierarchy diff --git a/doc/sphinx/src/particles.rst b/doc/sphinx/src/particles.rst index 4578763a31e79..30534c1d1d8c8 100644 --- a/doc/sphinx/src/particles.rst +++ b/doc/sphinx/src/particles.rst @@ -1,3 +1,5 @@ +.. This file was made in part with generative AI. + Particles ========= @@ -11,8 +13,8 @@ Swarms A ``Swarm`` contains all the particle data for all particles of a given species. It owns a set of ``ParticleVariable``\ s, one for each value of -each particle. For example, the spatial positions ``x``, ``y``, and -``z`` of the particles in a swarm are three separate +each particle. For example, the spatial positions ``x1``, ``x2``, and +``x3`` of the particles in a swarm are three separate ``ParticleVariable``\ s. ``ParticleVariable``\ s can be either ``Real``-, ``uint64_t``-, or ``int``-valued, which is specified by the metadata values ``Metadata::Real``, ``MetaData::UInt64``, and ``Metadata::Integer``. ``ParticleVariable``\ s @@ -21,7 +23,7 @@ should also contain the ``Metadata::Particle`` flag. By default, to 2D data per particle is currently supported, by passing ``std::vector{N1, N2}`` as the second argument to the ``ParticleVariable`` ``Metadata``. All ``Swarm``\ s by default contain -positional ``x``, ``y``, and ``z`` ``ParticleVariable``\ s and a ``uint64`` particle +positional ``x1``, ``x2``, and ``x3`` ``ParticleVariable``\ s and a ``uint64`` particle ``id`` that is persistent and unique for a given simulation. The latter field can be disabled (e.g., because it is not required for a method that constant creates and destroys anonymous particles) by providing the @@ -47,6 +49,13 @@ permit ``Swarm``s to be retrieved from ``"base"`` ``MeshBlockData`` and ``MeshDa particles that the reservation holds for a given swarm by calling ``metadata.SetInitialSwarmPoolReservation(nparticles);``. +.. note:: + + Particle infrastructure now operates in the native ``x1``, ``x2``, and ``x3`` + coordinate directions rather than assuming Cartesian ``x``, ``y``, and ``z``. + That said, particles and swarms in curvilinear coordinate systems remain mostly + untested. + The ``Swarm`` is a host-side object, but some of its data members are required for device- side compution. To access this data, a ``SwarmDeviceContext`` object is created via @@ -92,11 +101,11 @@ computations on currently active particles: .. code:: cpp - auto &x = swarm.Get("x").Get(); + auto &x1 = swarm.Get(swarm_position::x1::name()).Get(); swarm.pmy_block->par_for("Simple loop", 0, swarm.GetMaxActiveIndex(), KOKKOS_LAMBDA(const int n) { if (swarm_d.IsActive(n)) { - x(n) += 1.0; + x1(n) += 1.0; } }); @@ -177,14 +186,14 @@ Similar to grid variables, swarms can be packed over ``MeshBlock``\ s via ``Swar a ``SwarmPack`` via a ``std::vector`` or the type-based variable prescription previously used by ``SparsePack``\ s (see :ref:`sparse_packs`). -For packing via string (wherein below, ``swarm_position::x::name()`` returns a string), +For packing via string (wherein below, ``swarm_position::x1::name()`` returns a string), one must specify the data type by template argument: .. code:: cpp - std::vector vars{swarm_position::x::name(), - swarm_position::y::name(), - swarm_position::z::name()}; + std::vector vars{swarm_position::x1::name(), + swarm_position::x2::name(), + swarm_position::x3::name()}; static auto desc = MakeSwarmPackDescriptor(swarm_name, vars); auto pack = desc.GetPack(md); @@ -194,9 +203,9 @@ example), the type can be inferred automatically: .. code:: cpp - static auto desc = MakeSwarmPackDescriptor(swarm_name); + static auto desc = MakeSwarmPackDescriptor(swarm_name); auto pack = desc.GetPack(md); diff --git a/example/particle_leapfrog/particle_leapfrog.cpp b/example/particle_leapfrog/particle_leapfrog.cpp index 33ea36b1ee27a..12cbd1017bad1 100644 --- a/example/particle_leapfrog/particle_leapfrog.cpp +++ b/example/particle_leapfrog/particle_leapfrog.cpp @@ -183,9 +183,9 @@ void PostInitialization(MeshBlock *pmb, ParameterInput *pin) { auto new_particles_context = swarm->AddEmptyParticles(num_particles_this_block); auto &id = swarm->Get(swarm_position::id::name()).Get(); - auto &x = swarm->Get(swarm_position::x::name()).Get(); - auto &y = swarm->Get(swarm_position::y::name()).Get(); - auto &z = swarm->Get(swarm_position::z::name()).Get(); + auto &x = swarm->Get(swarm_position::x1::name()).Get(); + auto &y = swarm->Get(swarm_position::x2::name()).Get(); + auto &z = swarm->Get(swarm_position::x3::name()).Get(); auto &v = swarm->Get("v").Get(); auto &vv = swarm->Get("vv").Get(); @@ -225,7 +225,7 @@ TaskStatus TransportParticles(MeshData *md, const StagedIntegrator *integr // NOTE(@pdmullen): the data type for Positions (Real) are automatically deduced from // the variable typing static auto desc_pos = - MakeSwarmPackDescriptor( + MakeSwarmPackDescriptor( swarm_name); auto pack_pos = desc_pos.GetPack(md); @@ -250,9 +250,9 @@ TaskStatus TransportParticles(MeshData *md, const StagedIntegrator *integr const auto swarm_d = pack_pos.GetContext(b); if (swarm_d.IsActive(n)) { // drift - pack_pos(b, swarm_position::x(), n) += pack_v(b, iv + 0, n) * 0.5 * dt; - pack_pos(b, swarm_position::y(), n) += pack_v(b, iv + 1, n) * 0.5 * dt; - pack_pos(b, swarm_position::z(), n) += pack_v(b, iv + 2, n) * 0.5 * dt; + pack_pos(b, swarm_position::x1(), n) += pack_v(b, iv + 0, n) * 0.5 * dt; + pack_pos(b, swarm_position::x2(), n) += pack_v(b, iv + 1, n) * 0.5 * dt; + pack_pos(b, swarm_position::x3(), n) += pack_v(b, iv + 2, n) * 0.5 * dt; // kick pack_v(b, iv + 0, n) += ax * dt; @@ -260,9 +260,9 @@ TaskStatus TransportParticles(MeshData *md, const StagedIntegrator *integr pack_v(b, iv + 2, n) += az * dt; // drift - pack_pos(b, swarm_position::x(), n) += pack_v(b, iv + 0, n) * 0.5 * dt; - pack_pos(b, swarm_position::y(), n) += pack_v(b, iv + 1, n) * 0.5 * dt; - pack_pos(b, swarm_position::z(), n) += pack_v(b, iv + 2, n) * 0.5 * dt; + pack_pos(b, swarm_position::x1(), n) += pack_v(b, iv + 0, n) * 0.5 * dt; + pack_pos(b, swarm_position::x2(), n) += pack_v(b, iv + 1, n) * 0.5 * dt; + pack_pos(b, swarm_position::x3(), n) += pack_v(b, iv + 2, n) * 0.5 * dt; // id PARTHENON_REQUIRE(pack_id(b, swarm_position::id(), n) >= 0, diff --git a/example/particle_tracers/particle_tracers.cpp b/example/particle_tracers/particle_tracers.cpp index 5cabad548d148..022699edde27d 100644 --- a/example/particle_tracers/particle_tracers.cpp +++ b/example/particle_tracers/particle_tracers.cpp @@ -284,7 +284,7 @@ void SourceTracers(MeshBlock *pmb, ParameterInput *pin) { // Create pack static auto desc = - MakeSwarmPackDescriptor( + MakeSwarmPackDescriptor( swarm_name); auto pack = desc.GetPack(mbd.get()); @@ -296,9 +296,9 @@ void SourceTracers(MeshBlock *pmb, ParameterInput *pin) { auto rng_gen = rng_pool.get_state(); // Extract particle position - Real &xx = pack(0, swarm_position::x(), n); - Real &yy = pack(0, swarm_position::y(), n); - Real &zz = pack(0, swarm_position::z(), n); + Real &xx = pack(0, swarm_position::x1(), n); + Real &yy = pack(0, swarm_position::x2(), n); + Real &zz = pack(0, swarm_position::x3(), n); // Rejection sample the x position Real val; @@ -334,7 +334,7 @@ TaskStatus AdvectTracers(MeshData *md, const Real dt) { // Create pack static auto desc = - MakeSwarmPackDescriptor( + MakeSwarmPackDescriptor( swarm_name); auto pack = desc.GetPack(md); @@ -345,9 +345,9 @@ TaskStatus AdvectTracers(MeshData *md, const Real dt) { auto [b, n] = pack.GetBlockParticleIndices(idx); const auto &swarm_d = pack.GetContext(b); if (swarm_d.IsActive(n)) { - pack(b, swarm_position::x(), n) += vx * dt; - pack(b, swarm_position::y(), n) += vy * dt; - pack(b, swarm_position::z(), n) += vz * dt; + pack(b, swarm_position::x1(), n) += vx * dt; + pack(b, swarm_position::x2(), n) += vy * dt; + pack(b, swarm_position::x3(), n) += vz * dt; } }); @@ -366,7 +366,7 @@ TaskStatus DepositTracers(MeshData *md) { // Create packs static auto desc = MakePackDescriptor(resolved_pkgs.get()); static auto pdesc = - MakeSwarmPackDescriptor( + MakeSwarmPackDescriptor( swarm_name); auto vmesh = desc.GetPack(md); auto vpart = pdesc.GetPack(md); @@ -387,9 +387,9 @@ TaskStatus DepositTracers(MeshData *md) { const auto &swarm_d = vpart.GetContext(b); if (swarm_d.IsActive(n)) { int ip, jp, kp; - const Real &xx = vpart(b, swarm_position::x(), n); - const Real &yy = vpart(b, swarm_position::y(), n); - const Real &zz = vpart(b, swarm_position::z(), n); + const Real &xx = vpart(b, swarm_position::x1(), n); + const Real &yy = vpart(b, swarm_position::x2(), n); + const Real &zz = vpart(b, swarm_position::x3(), n); swarm_d.Xtoijk(xx, yy, zz, ip, jp, kp); // For testing in this example we make sure the indices are correct; these diff --git a/example/particles/particles.cpp b/example/particles/particles.cpp index 0f250e9ab02f1..1683e6d9b093c 100644 --- a/example/particles/particles.cpp +++ b/example/particles/particles.cpp @@ -1,5 +1,5 @@ //======================================================================================== -// (C) (or copyright) 2020-2024. Triad National Security, LLC. All rights reserved. +// (C) (or copyright) 2020-2026. Triad National Security, LLC. All rights reserved. // // This program was produced under U.S. Government contract 89233218CNA000001 for Los // Alamos National Laboratory (LANL), which is operated by Triad National Security, LLC @@ -11,6 +11,8 @@ // the public, perform publicly and display publicly, and to permit others to do so. //======================================================================================== +// This file was made in part with generative AI. + #include #include #include @@ -183,9 +185,9 @@ TaskStatus DepositParticles(MeshBlock *pmb) { const Real &minx_j = pmb->coords.Xf<2>(jb.s); const Real &minx_k = pmb->coords.Xf<3>(kb.s); - const auto &x = swarm->Get(swarm_position::x::name()).Get(); - const auto &y = swarm->Get(swarm_position::y::name()).Get(); - const auto &z = swarm->Get(swarm_position::z::name()).Get(); + const auto &x = swarm->Get(swarm_position::x1::name()).Get(); + const auto &y = swarm->Get(swarm_position::x2::name()).Get(); + const auto &z = swarm->Get(swarm_position::x3::name()).Get(); const auto &weight = swarm->Get("weight").Get(); auto swarm_d = swarm->GetDeviceContext(); @@ -262,9 +264,9 @@ TaskStatus CreateSomeParticles(MeshBlock *pmb, const double t0) { const Real &minx_k = pmb->coords.Xf<3>(kb.s); auto &t = swarm->Get("t").Get(); - auto &x = swarm->Get(swarm_position::x::name()).Get(); - auto &y = swarm->Get(swarm_position::y::name()).Get(); - auto &z = swarm->Get(swarm_position::z::name()).Get(); + auto &x = swarm->Get(swarm_position::x1::name()).Get(); + auto &y = swarm->Get(swarm_position::x2::name()).Get(); + auto &z = swarm->Get(swarm_position::x3::name()).Get(); auto &v = swarm->Get("v").Get(); auto &weight = swarm->Get("weight").Get(); @@ -373,9 +375,9 @@ TaskStatus TransportParticles(MeshBlock *pmb, const double t0, const double dt) int max_active_index = swarm->GetMaxActiveIndex(); auto &t = swarm->Get("t").Get(); - auto &x = swarm->Get(swarm_position::x::name()).Get(); - auto &y = swarm->Get(swarm_position::y::name()).Get(); - auto &z = swarm->Get(swarm_position::z::name()).Get(); + auto &x = swarm->Get(swarm_position::x1::name()).Get(); + auto &y = swarm->Get(swarm_position::x2::name()).Get(); + auto &z = swarm->Get(swarm_position::x3::name()).Get(); auto &v = swarm->Get("v").Get(); const Real &dx_i = pmb->coords.Dxf<1>(pmb->cellbounds.is(IndexDomain::interior)); diff --git a/scripts/python/packages/parthenon_tools/parthenon_tools/movie2d.py b/scripts/python/packages/parthenon_tools/parthenon_tools/movie2d.py index d35179328cc5b..1e5c79591caeb 100755 --- a/scripts/python/packages/parthenon_tools/parthenon_tools/movie2d.py +++ b/scripts/python/packages/parthenon_tools/parthenon_tools/movie2d.py @@ -4,7 +4,7 @@ # Copyright(C) 2020-2025 The Parthenon collaboration # Licensed under the 3-clause BSD License, see LICENSE file for details # ========================================================================================= -# (C) (or copyright) 2020-2025. Triad National Security, LLC. All rights reserved. +# (C) (or copyright) 2020-2026. Triad National Security, LLC. All rights reserved. # # This program was produced under U.S. Government contract 89233218CNA000001 for Los # Alamos National Laboratory (LANL), which is operated by Triad National Security, LLC @@ -16,6 +16,8 @@ # the public, perform publicly and display publicly, and to permit others to do so. # ========================================================================================= +# This file was made in part with generative AI. + from __future__ import print_function import re @@ -450,8 +452,8 @@ def main(): ERROR_FLAG = True break swarm = data.GetSwarm(args.swarm) - swarmx = subsample(swarm.x, args.maxparticles) - swarmy = subsample(swarm.y, args.maxparticles) + swarmx = subsample(swarm.x1, args.maxparticles) + swarmy = subsample(swarm.x2, args.maxparticles) if args.swarmcolor is not None: if not is_color_like(args.swarmcolor): if args.swarmcolor not in swarm.variables: diff --git a/scripts/python/packages/parthenon_tools/parthenon_tools/phdf.py b/scripts/python/packages/parthenon_tools/parthenon_tools/phdf.py index 58dae44f2ba7b..ecab791b091c3 100644 --- a/scripts/python/packages/parthenon_tools/parthenon_tools/phdf.py +++ b/scripts/python/packages/parthenon_tools/parthenon_tools/phdf.py @@ -3,7 +3,7 @@ # Copyright(C) 2020-2024 The Parthenon collaboration # Licensed under the 3-clause BSD License, see LICENSE file for details # ========================================================================================= -# (C) (or copyright) 2020-2024. Triad National Security, LLC. All rights reserved. +# (C) (or copyright) 2020-2026. Triad National Security, LLC. All rights reserved. # # This program was produced under U.S. Government contract 89233218CNA000001 for Los # Alamos National Laboratory (LANL), which is operated by Triad National Security, LLC @@ -15,6 +15,8 @@ # the public, perform publicly and display publicly, and to permit others to do so. # ========================================================================================= +# This file was made in part with generative AI. + from __future__ import print_function import h5py as h import os, sys, errno @@ -27,7 +29,8 @@ class Swarm: name: The name of the swarm variables: The variables in available in the swarm. varData: The swarm variables. Greedily accessed. - x, y, z: The x, y, and z positions of the swarm + x, y, z: Legacy position accessors + x1, x2, x3: Position accessors in native mesh coordinates """ def __init__(self, fid, swarmname): @@ -43,6 +46,20 @@ def Block(self, b): """Returns a Python slice for the particles only on block b""" return slice(self.offsets[b], self.offsets[b] + self.counts[b] + 1) + def _get_exact(self, variable): + if variable not in self.varData: + self.varData[variable] = self.gid[variable][:] + return self.varData[variable] + + def _get_compat(self, variables): + for variable in variables: + try: + return self._get_exact(variable) + except KeyError: + pass + print(f"ERROR: none of {variables} found in {self.name}") + return None + def Get(self, variable): """Reads data for the named swarm var from file and caches it in the dictionary. Returns None if variable is not found in the file @@ -50,9 +67,7 @@ def Get(self, variable): [tensor indices, particle index] """ try: - if self.varData.get(variable) is None: - self.varData[variable] = self.gid[variable][:] - return self.varData[variable] + return self._get_exact(variable) except KeyError: print(f"ERROR: {variable} not found in {self.name}") return None @@ -63,15 +78,27 @@ def id(self): @property def x(self): - return self.Get("swarm.x") + return self._get_compat(("swarm.x", "swarm.x1")) @property def y(self): - return self.Get("swarm.y") + return self._get_compat(("swarm.y", "swarm.x2")) @property def z(self): - return self.Get("swarm.z") + return self._get_compat(("swarm.z", "swarm.x3")) + + @property + def x1(self): + return self._get_compat(("swarm.x1", "swarm.x")) + + @property + def x2(self): + return self._get_compat(("swarm.x2", "swarm.y")) + + @property + def x3(self): + return self._get_compat(("swarm.x3", "swarm.z")) def __getitem__(self, key): return self.Get(key) diff --git a/src/bvals/boundary_conditions_generic.hpp b/src/bvals/boundary_conditions_generic.hpp index 12e9cb1043be5..c4b430c1f72bd 100644 --- a/src/bvals/boundary_conditions_generic.hpp +++ b/src/bvals/boundary_conditions_generic.hpp @@ -1,5 +1,5 @@ //======================================================================================== -// (C) (or copyright) 2020-2024. Triad National Security, LLC. All rights reserved. +// (C) (or copyright) 2020-2026. Triad National Security, LLC. All rights reserved. // // This program was produced under U.S. Government contract 89233218CNA000001 for Los // Alamos National Laboratory (LANL), which is operated by Triad National Security, LLC @@ -14,6 +14,8 @@ #ifndef BVALS_BOUNDARY_CONDITIONS_GENERIC_HPP_ #define BVALS_BOUNDARY_CONDITIONS_GENERIC_HPP_ +// This file was made in part with generative AI. + #include #include #include @@ -49,9 +51,9 @@ void GenericSwarmBC(std::shared_ptr &swarm) { auto pmb = swarm->GetBlockPointer(); - auto &x_ = swarm->Get(swarm_position::x::name()).Get(); - auto &y_ = swarm->Get(swarm_position::y::name()).Get(); - auto &z_ = swarm->Get(swarm_position::z::name()).Get(); + auto &x1_ = swarm->Get(swarm_position::x1::name()).Get(); + auto &x2_ = swarm->Get(swarm_position::x2::name()).Get(); + auto &x3_ = swarm->Get(swarm_position::x3::name()).Get(); pmb->par_for( PARTHENON_AUTO_LABEL, 0, max_active_index, KOKKOS_LAMBDA(const int n) { @@ -60,30 +62,30 @@ void GenericSwarmBC(std::shared_ptr &swarm) { [[maybe_unused]] constexpr bool X2 = (DIR == X2DIR); [[maybe_unused]] constexpr bool X3 = (DIR == X3DIR); // Cannot capture variables inside constexpr if context - [[maybe_unused]] const auto &x = x_; - [[maybe_unused]] const auto &y = y_; - [[maybe_unused]] const auto &z = z_; + [[maybe_unused]] const auto &x1 = x1_; + [[maybe_unused]] const auto &x2 = x2_; + [[maybe_unused]] const auto &x3 = x3_; const auto &swarm_d = swarm_d_; constexpr bool INNER = (SIDE == BCSide::Inner); if (swarm_d.IsActive(n)) { if constexpr (X1) { if constexpr (INNER) { if constexpr (TYPE == BCType::Periodic) { - if (x(n) > swarm_d.x_max_global_) { - x(n) = swarm_d.x_min_global_ + (x(n) - swarm_d.x_max_global_); + if (x1(n) > swarm_d.x1_max_global_) { + x1(n) = swarm_d.x1_min_global_ + (x1(n) - swarm_d.x1_max_global_); } } else if constexpr (TYPE == BCType::Outflow) { - if (x(n) < swarm_d.x_min_global_) { + if (x1(n) < swarm_d.x1_min_global_) { swarm_d.MarkParticleForRemoval(n); } } } else { if constexpr (TYPE == BCType::Periodic) { - if (x(n) < swarm_d.x_min_global_) { - x(n) = swarm_d.x_max_global_ - (swarm_d.x_min_global_ - x(n)); + if (x1(n) < swarm_d.x1_min_global_) { + x1(n) = swarm_d.x1_max_global_ - (swarm_d.x1_min_global_ - x1(n)); } } else if constexpr (TYPE == BCType::Outflow) { - if (x(n) > swarm_d.x_max_global_) { + if (x1(n) > swarm_d.x1_max_global_) { swarm_d.MarkParticleForRemoval(n); } } @@ -91,21 +93,21 @@ void GenericSwarmBC(std::shared_ptr &swarm) { } else if constexpr (X2) { if constexpr (INNER) { if constexpr (TYPE == BCType::Periodic) { - if (y(n) > swarm_d.y_max_global_) { - y(n) = swarm_d.y_min_global_ + (y(n) - swarm_d.y_max_global_); + if (x2(n) > swarm_d.x2_max_global_) { + x2(n) = swarm_d.x2_min_global_ + (x2(n) - swarm_d.x2_max_global_); } } else if constexpr (TYPE == BCType::Outflow) { - if (y(n) < swarm_d.y_min_global_) { + if (x2(n) < swarm_d.x2_min_global_) { swarm_d.MarkParticleForRemoval(n); } } } else { if constexpr (TYPE == BCType::Periodic) { - if (y(n) < swarm_d.y_min_global_) { - y(n) = swarm_d.y_max_global_ - (swarm_d.y_min_global_ - y(n)); + if (x2(n) < swarm_d.x2_min_global_) { + x2(n) = swarm_d.x2_max_global_ - (swarm_d.x2_min_global_ - x2(n)); } } else if constexpr (TYPE == BCType::Outflow) { - if (y(n) > swarm_d.y_max_global_) { + if (x2(n) > swarm_d.x2_max_global_) { swarm_d.MarkParticleForRemoval(n); } } @@ -113,21 +115,21 @@ void GenericSwarmBC(std::shared_ptr &swarm) { } else if constexpr (X3) { if constexpr (INNER) { if constexpr (TYPE == BCType::Periodic) { - if (z(n) > swarm_d.z_max_global_) { - z(n) = swarm_d.z_min_global_ + (z(n) - swarm_d.z_max_global_); + if (x3(n) > swarm_d.x3_max_global_) { + x3(n) = swarm_d.x3_min_global_ + (x3(n) - swarm_d.x3_max_global_); } } else if constexpr (TYPE == BCType::Outflow) { - if (z(n) < swarm_d.z_min_global_) { + if (x3(n) < swarm_d.x3_min_global_) { swarm_d.MarkParticleForRemoval(n); } } } else { if constexpr (TYPE == BCType::Periodic) { - if (z(n) < swarm_d.z_min_global_) { - z(n) = swarm_d.z_max_global_ - (swarm_d.z_min_global_ - z(n)); + if (x3(n) < swarm_d.x3_min_global_) { + x3(n) = swarm_d.x3_max_global_ - (swarm_d.x3_min_global_ - x3(n)); } } else if constexpr (TYPE == BCType::Outflow) { - if (z(n) > swarm_d.z_max_global_) { + if (x3(n) > swarm_d.x3_max_global_) { swarm_d.MarkParticleForRemoval(n); } } diff --git a/src/interface/swarm.cpp b/src/interface/swarm.cpp index 3bbd13e98b964..09f715d7bdff8 100644 --- a/src/interface/swarm.cpp +++ b/src/interface/swarm.cpp @@ -3,7 +3,7 @@ // Copyright(C) 2020-2026 The Parthenon collaboration // Licensed under the 3-clause BSD License, see LICENSE file for details //======================================================================================== -// (C) (or copyright) 2020-2024. Triad National Security, LLC. All rights reserved. +// (C) (or copyright) 2020-2026. Triad National Security, LLC. All rights reserved. // // This program was produced under U.S. Government contract 89233218CNA000001 for Los // Alamos National Laboratory (LANL), which is operated by Triad National Security, LLC @@ -14,6 +14,9 @@ // license in this material to reproduce, prepare derivative works, distribute copies to // the public, perform publicly and display publicly, and to permit others to do so. //======================================================================================== + +// This file was made in part with generative AI. + #include #include #include @@ -53,18 +56,18 @@ SwarmDeviceContext Swarm::GetDeviceContext() const { context.ib_s_ = ib.s; context.jb_s_ = jb.s; context.kb_s_ = kb.s; - context.x_min_ = pmb->coords.Xf<1>(ib.s); - context.y_min_ = pmb->coords.Xf<2>(jb.s); - context.z_min_ = pmb->coords.Xf<3>(kb.s); - context.x_max_ = pmb->coords.Xf<1>(ib.e + 1); - context.y_max_ = pmb->coords.Xf<2>(jb.e + 1); - context.z_max_ = pmb->coords.Xf<3>(kb.e + 1); - context.x_min_global_ = mesh_size.xmin(X1DIR); - context.x_max_global_ = mesh_size.xmax(X1DIR); - context.y_min_global_ = mesh_size.xmin(X2DIR); - context.y_max_global_ = mesh_size.xmax(X2DIR); - context.z_min_global_ = mesh_size.xmin(X3DIR); - context.z_max_global_ = mesh_size.xmax(X3DIR); + context.x1_min_ = pmb->coords.Xf<1>(ib.s); + context.x2_min_ = pmb->coords.Xf<2>(jb.s); + context.x3_min_ = pmb->coords.Xf<3>(kb.s); + context.x1_max_ = pmb->coords.Xf<1>(ib.e + 1); + context.x2_max_ = pmb->coords.Xf<2>(jb.e + 1); + context.x3_max_ = pmb->coords.Xf<3>(kb.e + 1); + context.x1_min_global_ = mesh_size.xmin(X1DIR); + context.x1_max_global_ = mesh_size.xmax(X1DIR); + context.x2_min_global_ = mesh_size.xmin(X2DIR); + context.x2_max_global_ = mesh_size.xmax(X2DIR); + context.x3_min_global_ = mesh_size.xmin(X3DIR); + context.x3_max_global_ = mesh_size.xmax(X3DIR); context.ndim_ = pmb->pmy_mesh->ndim; context.my_rank_ = Globals::my_rank; context.coords_ = pmb->coords; @@ -85,18 +88,15 @@ Swarm::Swarm(const std::string &label, const Metadata &metadata, neighbor_received_particles_("neighbor_received_particles_", NMAX_NEIGHBORS), cell_sorted_("cell_sorted_", nmax_pool_), buffer_sorted_("buffer_sorted_", nmax_pool_), mpiStatus(true) { - PARTHENON_REQUIRE_THROWS(typeid(Coordinates_t) == typeid(UniformCartesian), - "SwarmDeviceContext only supports a uniform Cartesian mesh!"); - uid_ = get_uid_(label_); // Add default swarm fields if (!metadata.IsSet(Metadata::NoPersistentParticleIds)) { Add(swarm_position::id::name(), Metadata({Metadata::UInt64})); } - Add(swarm_position::x::name(), Metadata({Metadata::Real})); - Add(swarm_position::y::name(), Metadata({Metadata::Real})); - Add(swarm_position::z::name(), Metadata({Metadata::Real})); + Add(swarm_position::x1::name(), Metadata({Metadata::Real})); + Add(swarm_position::x2::name(), Metadata({Metadata::Real})); + Add(swarm_position::x3::name(), Metadata({Metadata::Real})); // Initialize index metadata num_active_ = 0; @@ -488,9 +488,9 @@ void Swarm::Defrag() { void Swarm::SortParticlesByCell() { auto pmb = GetBlockPointer(); - auto &x = Get(swarm_position::x::name()).Get(); - auto &y = Get(swarm_position::y::name()).Get(); - auto &z = Get(swarm_position::z::name()).Get(); + auto &x1 = Get(swarm_position::x1::name()).Get(); + auto &x2 = Get(swarm_position::x2::name()).Get(); + auto &x3 = Get(swarm_position::x3::name()).Get(); const int nx1 = pmb->cellbounds.ncellsi(IndexDomain::entire); const int nx2 = pmb->cellbounds.ncellsj(IndexDomain::entire); @@ -516,7 +516,7 @@ void Swarm::SortParticlesByCell() { pmb->par_for( PARTHENON_AUTO_LABEL, 0, max_active_index_, KOKKOS_LAMBDA(const int n) { int i, j, k; - swarm_d.Xtoijk(x(n), y(n), z(n), i, j, k); + swarm_d.Xtoijk(x1(n), x2(n), x3(n), i, j, k); const int64_t cell_idx_1d = i + nx1 * (j + nx2 * k); cell_sorted(n) = SwarmKey(static_cast(cell_idx_1d), n); }); diff --git a/src/interface/swarm_comms.cpp b/src/interface/swarm_comms.cpp index 592420b1b8567..41a4cc310d16c 100644 --- a/src/interface/swarm_comms.cpp +++ b/src/interface/swarm_comms.cpp @@ -1,5 +1,5 @@ //======================================================================================== -// (C) (or copyright) 2020-2024. Triad National Security, LLC. All rights reserved. +// (C) (or copyright) 2020-2026. Triad National Security, LLC. All rights reserved. // // This program was produced under U.S. Government contract 89233218CNA000001 for Los // Alamos National Laboratory (LANL), which is operated by Triad National Security, LLC @@ -10,6 +10,9 @@ // license in this material to reproduce, prepare derivative works, distribute copies to // the public, perform publicly and display publicly, and to permit others to do so. //======================================================================================== + +// This file was made in part with generative AI. + #include #include #include @@ -181,9 +184,9 @@ void Swarm::LoadBuffers_() { const int intPackDim = vint.GetDim(2); const int uint64PackDim = vuint64.GetDim(2); - auto &x = Get(swarm_position::x::name()).Get(); - auto &y = Get(swarm_position::y::name()).Get(); - auto &z = Get(swarm_position::z::name()).Get(); + auto &x1 = Get(swarm_position::x1::name()).Get(); + auto &x2 = Get(swarm_position::x2::name()).Get(); + auto &x3 = Get(swarm_position::x3::name()).Get(); if (max_active_index_ >= 0) { auto &buffer_sorted = buffer_sorted_; @@ -193,8 +196,8 @@ void Swarm::LoadBuffers_() { PARTHENON_AUTO_LABEL, 0, max_active_index_, KOKKOS_LAMBDA(const int n) { if (swarm_d.IsActive(n)) { bool on_current_mesh_block = true; - const int m = - swarm_d.GetNeighborBlockIndex(n, x(n), y(n), z(n), on_current_mesh_block); + const int m = swarm_d.GetNeighborBlockIndex(n, x1(n), x2(n), x3(n), + on_current_mesh_block); buffer_sorted(n) = SwarmKey(m, n); } else { buffer_sorted(n) = SwarmKey(this_block_, n); diff --git a/src/interface/swarm_device_context.hpp b/src/interface/swarm_device_context.hpp index e438dcf53d022..59ea9f31839be 100644 --- a/src/interface/swarm_device_context.hpp +++ b/src/interface/swarm_device_context.hpp @@ -1,5 +1,5 @@ //======================================================================================== -// (C) (or copyright) 2021-2024. Triad National Security, LLC. All rights reserved. +// (C) (or copyright) 2021-2026. Triad National Security, LLC. All rights reserved. // // This program was produced under U.S. Government contract 89233218CNA000001 for Los // Alamos National Laboratory (LANL), which is operated by Triad National Security, LLC @@ -13,6 +13,8 @@ #ifndef INTERFACE_SWARM_DEVICE_CONTEXT_HPP_ #define INTERFACE_SWARM_DEVICE_CONTEXT_HPP_ +// This file was made in part with generative AI. + #include #include "coordinates/coordinates.hpp" @@ -56,19 +58,19 @@ class SwarmDeviceContext { // TODO(BRR) This logic will change for non-uniform cartesian meshes KOKKOS_INLINE_FUNCTION - int GetNeighborBlockIndex(const int &n, const double &x, const double &y, - const double &z, bool &is_on_current_mesh_block) const { - int i = static_cast(std::floor((x - x_min_) / ((x_max_ - x_min_) / 2.))) + 1; - int j = static_cast(std::floor((y - y_min_) / ((y_max_ - y_min_) / 2.))) + 1; - int k = static_cast(std::floor((z - z_min_) / ((z_max_ - z_min_) / 2.))) + 1; + int GetNeighborBlockIndex(const int &n, const double &x1, const double &x2, + const double &x3, bool &is_on_current_mesh_block) const { + int i = static_cast(std::floor((x1 - x1_min_) / ((x1_max_ - x1_min_) / 2.))) + 1; + int j = static_cast(std::floor((x2 - x2_min_) / ((x2_max_ - x2_min_) / 2.))) + 1; + int k = static_cast(std::floor((x3 - x3_min_) / ((x3_max_ - x3_min_) / 2.))) + 1; // Particle is on neither this block nor a neighboring block if (i < 0 || i > 3 || ((j < 0 || j > 3) && ndim_ > 1) || ((k < 0 || k > 3) && ndim_ > 2)) { printf("[%i] k = %i j = %i i = %i\n", n, k, j, i); - printf("x = %e [%e %e]\n", x, x_min_, x_max_); - printf("y = %e [%e %e]\n", y, y_min_, y_max_); - printf("z = %e [%e %e]\n", z, z_min_, z_max_); + printf("x1 = %e [%e %e]\n", x1, x1_min_, x1_max_); + printf("x2 = %e [%e %e]\n", x2, x2_min_, x2_max_); + printf("x3 = %e [%e %e]\n", x3, x3_min_, x3_max_); PARTHENON_FAIL("Particle neighbor indices out of bounds; particle has somehow " "moved beyond the halo of adjacent blocks which is not permitted."); } @@ -92,16 +94,17 @@ class SwarmDeviceContext { // TODO(BRR) This logic will change for non-uniform cartesian meshes KOKKOS_INLINE_FUNCTION - void Xtoijk(const Real &x, const Real &y, const Real &z, int &i, int &j, int &k) const { + void Xtoijk(const Real &x1, const Real &x2, const Real &x3, int &i, int &j, + int &k) const { i = static_cast( - std::floor((x - x_min_) / coords_.Dx())) + + std::floor((x1 - x1_min_) / coords_.Dx())) + ib_s_; j = (ndim_ > 1) ? static_cast(std::floor( - (y - y_min_) / coords_.Dx())) + + (x2 - x2_min_) / coords_.Dx())) + jb_s_ : jb_s_; k = (ndim_ > 2) ? static_cast(std::floor( - (z - z_min_) / coords_.Dx())) + + (x3 - x3_min_) / coords_.Dx())) + kb_s_ : kb_s_; } @@ -122,18 +125,18 @@ class SwarmDeviceContext { int ib_s_; int jb_s_; int kb_s_; - Real x_min_; - Real x_max_; - Real y_min_; - Real y_max_; - Real z_min_; - Real z_max_; - Real x_min_global_; - Real x_max_global_; - Real y_min_global_; - Real y_max_global_; - Real z_min_global_; - Real z_max_global_; + Real x1_min_; + Real x1_max_; + Real x2_min_; + Real x2_max_; + Real x3_min_; + Real x3_max_; + Real x1_min_global_; + Real x1_max_global_; + Real x2_min_global_; + Real x2_max_global_; + Real x3_min_global_; + Real x3_max_global_; ParArray1D mask_; ParArray1D marked_for_removal_; ParArrayND block_index_; diff --git a/src/mesh/mesh.cpp b/src/mesh/mesh.cpp index 83f0e5a2dd4bd..910cbbc6acc89 100644 --- a/src/mesh/mesh.cpp +++ b/src/mesh/mesh.cpp @@ -204,6 +204,14 @@ Mesh::Mesh(ParameterInput *pin, ApplicationInput *app_in, Packages_t &packages, SetupMPIComms(); + if constexpr (!std::is_same_v) { + if (!resolved_packages->AllSwarms().empty()) { + PARTHENON_WARN("Parthenon swarm infrastructure assumes a uniform mesh in native " + "x1/x2/x3 coordinates. Curvilinear swarm support remains mostly " + "untested."); + } + } + PARTHENON_REQUIRE(minimum_number_of_teams_for_boundary_kernel > 0, "parthenon/mesh/minimum_number_of_teams_for_boundary_kernel " "must be positive."); diff --git a/src/mesh/swarm_amr_remesh.cpp b/src/mesh/swarm_amr_remesh.cpp index b21c68ba157c6..378b061b4e59f 100644 --- a/src/mesh/swarm_amr_remesh.cpp +++ b/src/mesh/swarm_amr_remesh.cpp @@ -142,10 +142,13 @@ BuildBlockSendPlan(const std::shared_ptr &swarm, const Mesh *pmesh, // Refinement is the only case where particles from one old block fan out to several // new leaf blocks. Compute that daughter ownership on device and only copy back the // compact destination-gid result, rather than mirroring full coordinate arrays. - const auto block = pmesh->GetBlockSize(old_loc); - const Real x_mid = 0.5 * (block.xmin(X1DIR) + block.xmax(X1DIR)); - const Real y_mid = 0.5 * (block.xmin(X2DIR) + block.xmax(X2DIR)); - const Real z_mid = 0.5 * (block.xmin(X3DIR) + block.xmax(X3DIR)); + const Real x1_split = pmesh->GetBlockSize(old_loc.GetDaughter(1, 0, 0)).xmin(X1DIR); + const Real x2_split = + pmesh->ndim > 1 ? pmesh->GetBlockSize(old_loc.GetDaughter(0, 1, 0)).xmin(X2DIR) + : 0.0; + const Real x3_split = + pmesh->ndim > 2 ? pmesh->GetBlockSize(old_loc.GetDaughter(0, 0, 1)).xmin(X3DIR) + : 0.0; auto child_gids_h = GetRefinedDestinationGids(pmesh, old_loc, new_gid_by_loc); ParArray1D child_gids("swarm_amr_remesh_child_gids", child_gids_h.size()); @@ -157,20 +160,21 @@ BuildBlockSendPlan(const std::shared_ptr &swarm, const Mesh *pmesh, ParArray1D refined_dest_gids("swarm_amr_remesh_refined_dest_gids", swarm->GetMaxActiveIndex() + 1); auto mask = swarm->GetMask(); - auto x = swarm->Get(swarm_position::x::name()).Get(); - auto y = swarm->Get(swarm_position::y::name()).Get(); - auto z = swarm->Get(swarm_position::z::name()).Get(); + auto x1 = swarm->Get(swarm_position::x1::name()).Get(); + auto x2 = swarm->Get(swarm_position::x2::name()).Get(); + auto x3 = swarm->Get(swarm_position::x3::name()).Get(); const int ndim = pmesh->ndim; parthenon::par_for( DEFAULT_LOOP_PATTERN, PARTHENON_AUTO_LABEL, DevExecSpace(), 0, swarm->GetMaxActiveIndex(), KOKKOS_LAMBDA(const int n) { if (!mask(n)) return; - const int ox1 = x(n) > x_mid; + const int ox1 = x1(n) > x1_split; + // Particle positions are stored in x1/x2/x3 coordinates. Compare those + // directly against the actual daughter interfaces in the same coordinates. // Inactive mesh directions do not participate in refinement, so they always - // contribute daughter bit 0 even if particles carry nontrivial coordinates in - // those directions. - const int ox2 = ndim > 1 ? y(n) > y_mid : 0; - const int ox3 = ndim > 2 ? z(n) > z_mid : 0; + // contribute daughter bit 0. + const int ox2 = ndim > 1 ? x2(n) > x2_split : 0; + const int ox3 = ndim > 2 ? x3(n) > x3_split : 0; refined_dest_gids(n) = child_gids(ox1 + 2 * ox2 + 4 * ox3); }); diff --git a/src/outputs/outputs.cpp b/src/outputs/outputs.cpp index 1d35462dab64a..bb6994ae4df9a 100644 --- a/src/outputs/outputs.cpp +++ b/src/outputs/outputs.cpp @@ -7,7 +7,7 @@ // Copyright(C) 2014 James M. Stone and other code contributors // Licensed under the 3-clause BSD License, see LICENSE file for details //======================================================================================== -// (C) (or copyright) 2020-2025. Triad National Security, LLC. All rights reserved. +// (C) (or copyright) 2020-2026. Triad National Security, LLC. All rights reserved. // // This program was produced under U.S. Government contract 89233218CNA000001 for Los // Alamos National Laboratory (LANL), which is operated by Triad National Security, LLC @@ -18,6 +18,9 @@ // license in this material to reproduce, prepare derivative works, distribute copies to // the public, perform publicly and display publicly, and to permit others to do so. //======================================================================================== + +// This file was made in part with generative AI. + //! \file outputs.cpp // \brief implements functions for Parthenon outputs // @@ -342,12 +345,13 @@ Outputs::Outputs(Mesh *pm, ParameterInput *pin, SimTime *tm) { "swarm variables to output for a specific swarm"); op.swarms[swname].insert(varnames.begin(), varnames.end()); } - // Always output id, x, y, and z for swarms so that they work with vis tools. + // Always output id, x1, x2, and x3 for swarms so that they work with vis + // tools. // Note, it's fine to add the id by default (even though it might not actually // exist) because only variables that do exists are actually being written. std::vector coords = { - swarm_position::id::name(), swarm_position::x::name(), - swarm_position::y::name(), swarm_position::z::name()}; + swarm_position::id::name(), swarm_position::x1::name(), + swarm_position::x2::name(), swarm_position::x3::name()}; op.swarms[swname].insert(coords.begin(), coords.end()); } } diff --git a/src/outputs/parthenon_hdf5.cpp b/src/outputs/parthenon_hdf5.cpp index c553e6e2288dd..cd44ec5c522ce 100644 --- a/src/outputs/parthenon_hdf5.cpp +++ b/src/outputs/parthenon_hdf5.cpp @@ -1,9 +1,9 @@ //======================================================================================== // Parthenon performance portable AMR framework -// Copyright(C) 2020-2025 The Parthenon collaboration +// Copyright(C) 2020-2026 The Parthenon collaboration // Licensed under the 3-clause BSD License, see LICENSE file for details //======================================================================================== -// (C) (or copyright) 2020-2025. Triad National Security, LLC. All rights reserved. +// (C) (or copyright) 2020-2026. Triad National Security, LLC. All rights reserved. // // This program was produced under U.S. Government contract 89233218CNA000001 for Los // Alamos National Laboratory (LANL), which is operated by Triad National Security, LLC @@ -15,6 +15,8 @@ // the public, perform publicly and display publicly, and to permit others to do so. //======================================================================================== +// This file was made in part with generative AI. + // options for building #include "config.hpp" #include "globals.hpp" @@ -554,8 +556,8 @@ void PHDF5Output::WriteOutputFileImpl(Mesh *pm, ParameterInput *pin, SimTime *tm HDF5WriteND(g_var, vname, host_data.data(), vinfo.tensor_rank + 1, local_offset, local_count, global_count, pl_xfer, H5P_DEFAULT); if (output_params.write_swarm_xdmf && - (vname == swarm_position::x::name() || vname == swarm_position::y::name() || - vname == swarm_position::z::name())) { + (vname == swarm_position::x1::name() || vname == swarm_position::x2::name() || + vname == swarm_position::x3::name())) { pos_tmp.insert(pos_tmp.end(), host_data.begin(), host_data.end()); } } diff --git a/src/outputs/parthenon_opmd.cpp b/src/outputs/parthenon_opmd.cpp index 85f0e10255a1f..a1b773d9630cc 100644 --- a/src/outputs/parthenon_opmd.cpp +++ b/src/outputs/parthenon_opmd.cpp @@ -3,7 +3,7 @@ // Copyright(C) 2024-2026 The Parthenon collaboration // Licensed under the 3-clause BSD License, see LICENSE file for details //======================================================================================== -// (C) (or copyright) 2024. Triad National Security, LLC. All rights reserved. +// (C) (or copyright) 2026. Triad National Security, LLC. All rights reserved. // // This program was produced under U.S. Government contract 89233218CNA000001 for Los // Alamos National Laboratory (LANL), which is operated by Triad National Security, LLC @@ -18,6 +18,8 @@ // \brief Output for OpenPMD https://www.openpmd.org/ (supporting various backends) // This file was made in part with generative AI. +// This file was made in part with generative AI. + #include #include #include @@ -206,19 +208,29 @@ GetParticleRecordAndComponentNames(const std::string &vname, const int rank, std::string particle_record; std::string particle_record_component; - // special sauce to align "positions" with standard - if (vname == swarm_position::x::name()) { + // Map swarm positions to OpenPMD standard "position" record with x1/x2/x3 components + if (vname == swarm_position::x1::name()) { particle_record = "position"; - particle_record_component = "x"; - } else if (vname == swarm_position::y::name()) { + particle_record_component = "x1"; + } else if (vname == swarm_position::x2::name()) { particle_record = "position"; - particle_record_component = "y"; - } else if (vname == swarm_position::z::name()) { + particle_record_component = "x2"; + } else if (vname == swarm_position::x3::name()) { particle_record = "position"; - particle_record_component = "z"; + particle_record_component = "x3"; } else if (vname == swarm_position::id::name()) { particle_record = "id"; particle_record_component = openPMD::MeshRecordComponent::SCALAR; + // Backwards compatibility: support old position names (swarm.x/y/z -> position/x,y,z) + } else if (vname == "swarm.x") { + particle_record = "position"; + particle_record_component = "x"; + } else if (vname == "swarm.y") { + particle_record = "position"; + particle_record_component = "y"; + } else if (vname == "swarm.z") { + particle_record = "position"; + particle_record_component = "z"; } else { particle_record = vname; particle_record_component = diff --git a/src/outputs/parthenon_xdmf.cpp b/src/outputs/parthenon_xdmf.cpp index 5605b0fcbcc8f..a5570fde6c2bb 100644 --- a/src/outputs/parthenon_xdmf.cpp +++ b/src/outputs/parthenon_xdmf.cpp @@ -3,7 +3,7 @@ // Copyright(C) 2023-2024 The Parthenon collaboration // Licensed under the 3-clause BSD License, see LICENSE file for details //======================================================================================== -// (C) (or copyright) 2020-2024. Triad National Security, LLC. All rights reserved. +// (C) (or copyright) 2020-2026. Triad National Security, LLC. All rights reserved. // // This program was produced under U.S. Government contract 89233218CNA000001 for Los // Alamos National Laboratory (LANL), which is operated by Triad National Security, LLC @@ -15,6 +15,8 @@ // the public, perform publicly and display publicly, and to permit others to do so. //======================================================================================== +// This file was made in part with generative AI. + // options for building #include "config.hpp" #include "globals.hpp" @@ -241,9 +243,9 @@ void genXDMF(std::string hdfFile, Mesh *pm, SimTime *tm, IndexDomain domain, int "Float", "", swminfo.global_count); pxdmf << " " << std::endl; for (const auto &[varname, varinfo] : swminfo.var_info) { - if ((varname == swarm_position::x::name()) || - (varname == swarm_position::y::name()) || - (varname == swarm_position::z::name())) { + if ((varname == swarm_position::x1::name()) || + (varname == swarm_position::x2::name()) || + (varname == swarm_position::x3::name())) { continue; // We already did this one! } ParticleVariableRef(pxdmf, varname, varinfo, swmname, hdfFile, diff --git a/src/outputs/restart.hpp b/src/outputs/restart.hpp index e61cfe2dd6d44..b64c4342d8731 100644 --- a/src/outputs/restart.hpp +++ b/src/outputs/restart.hpp @@ -3,7 +3,7 @@ // Copyright(C) 2020-2024 The Parthenon collaboration // Licensed under the 3-clause BSD License, see LICENSE file for details //======================================================================================== -// (C) (or copyright) 2020-2021. Triad National Security, LLC. All rights reserved. +// (C) (or copyright) 2020-2026. Triad National Security, LLC. All rights reserved. // // This program was produced under U.S. Government contract 89233218CNA000001 for Los // Alamos National Laboratory (LANL), which is operated by Triad National Security, LLC @@ -14,12 +14,16 @@ // license in this material to reproduce, prepare derivative works, distribute copies to // the public, perform publicly and display publicly, and to permit others to do so. //======================================================================================== + +// This file was made in part with generative AI. + #ifndef OUTPUTS_RESTART_HPP_ #define OUTPUTS_RESTART_HPP_ //! \file io_wrapper.hpp // \brief defines a set of small wrapper functions for MPI versus Serial Output. #include +#include #include #include #include @@ -146,7 +150,113 @@ class RestartReader { void Close(); [[nodiscard]] virtual int HasGhost() const = 0; + + // Backwards compatibility: map new swarm position names to old names + static std::string GetBackwardsCompatibleSwarmVarName(const std::string &varname) { + if (varname == "swarm.x1") { + return "swarm.x"; + } else if (varname == "swarm.x2") { + return "swarm.y"; + } else if (varname == "swarm.x3") { + return "swarm.z"; + } + return varname; + } + + // High-level template function to read all swarm variables of a given type from restart + // file and distribute them to blocks + template + void ReadSwarmVars(const std::shared_ptr &pswarm, + const std::vector> &block_list, + const std::size_t count_on_rank, const std::size_t offset); }; +// Include full definitions needed for template implementation +#include "interface/swarm.hpp" +#include "mesh/meshblock.hpp" +#include "utils/string_utils.hpp" + +// Template implementation for ReadSwarmVars +// This needs to be in the header since it's a template function +template +void RestartReader::ReadSwarmVars( + const std::shared_ptr &pswarm, + const std::vector> &block_list, + const std::size_t count_on_rank, const std::size_t offset) { + const std::string &swarmname = pswarm->label(); + std::vector dataVec; + for (const auto &var : pswarm->GetVariableVector()) { + const std::string &varname = var->label(); + const auto &m = var->metadata(); + auto arrdims = m.GetArrayDims(pswarm->GetBlockPointer(), false); + + auto var_missing_on_disk = !VariableExists(swarmname, DataType::SwarmVar, varname); + + // Backwards compatibility: try old position names if new ones missing + std::string varname_to_read = varname; + if (var_missing_on_disk) { + varname_to_read = GetBackwardsCompatibleSwarmVarName(varname); + // Check if the old name exists + if (varname_to_read != varname) { + var_missing_on_disk = + !VariableExists(swarmname, DataType::SwarmVar, varname_to_read); + if (!var_missing_on_disk && Globals::my_rank == 0) { + std::cout << "SwarmVar: " << varname + << " using backwards-compatible name: " << varname_to_read << "\n"; + } + } + } + + if (Globals::my_rank == 0 && var_missing_on_disk) { + std::cout << "SwarmVar: " << varname << " missing on disk\n"; + } else if (Globals::my_rank == 0 && varname_to_read == varname) { + std::cout << "SwarmVar: " << varname << "\n"; + } + + if (var_missing_on_disk) { + // TODO(JMM/PG) Add failed load list of "fail/needs fix" list + continue; + } + + try { + ReadSwarmVar(swarmname, varname_to_read, count_on_rank, offset, m, dataVec); + } catch (std::exception &ex) { + // Variable does exist but could not be read. So we definitely want to fail here. + PARTHENON_THROW(StringPrintf("[%d] WARNING: Failed to read Swarm %s Variable %s " + "from restart file:\n%s", + Globals::my_rank, swarmname.c_str(), varname.c_str(), + ex.what())); + } + + // Only safe because swarm starts completely defragged. + // Note ordering here: block is second-inner-most loop. + // If output format changes, this needs to change too. + std::size_t ivec = 0; + for (int n6 = 0; n6 < arrdims[5]; ++n6) { + for (int n5 = 0; n5 < arrdims[4]; ++n5) { + for (int n4 = 0; n4 < arrdims[3]; ++n4) { + for (int n3 = 0; n3 < arrdims[2]; ++n3) { + for (int n2 = 0; n2 < arrdims[1]; ++n2) { + for (auto &pmb : block_list) { + // 1 deep copy per tensor component per swarmvar per + // block, unfortunately. But only at initialization. + auto swarm_container = pmb->meshblock_data.Get()->GetSwarmData(); + auto pswarm_blk = swarm_container->Get(swarmname); + auto v = Kokkos::subview(pswarm_blk->Get(varname).data, n6, n5, n4, n3, + n2, Kokkos::ALL()); + auto v_h = Kokkos::create_mirror_view(v); + for (int n1 = 0; n1 < pswarm_blk->GetNumActive(); ++n1) { + v_h(n1) = dataVec[ivec++]; + } + Kokkos::deep_copy(v, v_h); + } + } + } + } + } + } + } +} + } // namespace parthenon #endif // OUTPUTS_RESTART_HPP_ diff --git a/src/outputs/restart_hdf5.hpp b/src/outputs/restart_hdf5.hpp index fe14cacb152f5..6b56271145cc2 100644 --- a/src/outputs/restart_hdf5.hpp +++ b/src/outputs/restart_hdf5.hpp @@ -3,7 +3,7 @@ // Copyright(C) 2020-2022 The Parthenon collaboration // Licensed under the 3-clause BSD License, see LICENSE file for details //======================================================================================== -// (C) (or copyright) 2020-2021. Triad National Security, LLC. All rights reserved. +// (C) (or copyright) 2020-2026. Triad National Security, LLC. All rights reserved. // // This program was produced under U.S. Government contract 89233218CNA000001 for Los // Alamos National Laboratory (LANL), which is operated by Triad National Security, LLC @@ -14,11 +14,16 @@ // license in this material to reproduce, prepare derivative works, distribute copies to // the public, perform publicly and display publicly, and to permit others to do so. //======================================================================================== + +// This file was made in part with generative AI. + #ifndef OUTPUTS_RESTART_HDF5_HPP_ #define OUTPUTS_RESTART_HDF5_HPP_ //! \file io_wrapper.hpp // \brief defines a set of small wrapper functions for MPI versus Serial Output. +#include +#include #include #include @@ -41,6 +46,8 @@ namespace parthenon { class Mesh; class Param; +class Swarm; +class MeshBlock; class RestartReaderHDF5 : public RestartReader { public: @@ -262,7 +269,6 @@ class RestartReaderHDF5 : public RestartReader { // perhaps belongs in a destructor? void Close(); - private: const std::string filename_; // Does file have ghost cells? diff --git a/src/outputs/restart_opmd.hpp b/src/outputs/restart_opmd.hpp index 953c440e9d70f..d48058a848599 100644 --- a/src/outputs/restart_opmd.hpp +++ b/src/outputs/restart_opmd.hpp @@ -3,6 +3,20 @@ // Copyright(C) 2024-2026 The Parthenon collaboration // Licensed under the 3-clause BSD License, see LICENSE file for details //======================================================================================== +// (C) (or copyright) 2026. Triad National Security, LLC. All rights reserved. +// +// This program was produced under U.S. Government contract 89233218CNA000001 for Los +// Alamos National Laboratory (LANL), which is operated by Triad National Security, LLC +// for the U.S. Department of Energy/National Nuclear Security Administration. All rights +// in the program are reserved by Triad National Security, LLC, and the U.S. Department +// of Energy/National Nuclear Security Administration. The Government is granted for +// itself and others acting on its behalf a nonexclusive, paid-up, irrevocable worldwide +// license in this material to reproduce, prepare derivative works, distribute copies to +// the public, perform publicly and display publicly, and to permit others to do so. +//======================================================================================== + +// This file was made in part with generative AI. + #ifndef OUTPUTS_RESTART_OPMD_HPP_ #define OUTPUTS_RESTART_OPMD_HPP_ //! \file restart_opmd.hpp @@ -81,9 +95,20 @@ class RestartReaderOPMD : public RestartReader { data_vec.resize(total_count); } + // Backwards compatibility: Old files have position/x,y,z while new files have + // position/x1,x2,x3 Check if the new component names exist, if not try the old ones + std::string varname_to_read = varname; + auto [particle_record_test, particle_record_component_test] = + OpenPMDUtils::GetParticleRecordAndComponentNames(varname, rank, 0); + if (!swm.contains(particle_record_test) || + !swm[particle_record_test].contains(particle_record_component_test)) { + // Try backwards compatible name (swarm.x1 -> swarm.x, etc.) + varname_to_read = GetBackwardsCompatibleSwarmVarName(varname); + } + for (auto n = 0; n < ncomp; n++) { auto [particle_record, particle_record_component] = - OpenPMDUtils::GetParticleRecordAndComponentNames(varname, rank, n); + OpenPMDUtils::GetParticleRecordAndComponentNames(varname_to_read, rank, n); openPMD::RecordComponent rc = swm[particle_record][particle_record_component]; rc.loadChunkRaw(&data_vec[n * count], {offset}, {count}); } diff --git a/src/pack/default_names.hpp b/src/pack/default_names.hpp index 57ba4b98b847b..6bc17c08919d3 100644 --- a/src/pack/default_names.hpp +++ b/src/pack/default_names.hpp @@ -1,5 +1,5 @@ //======================================================================================== -// (C) (or copyright) 2020-2024. Triad National Security, LLC. All rights reserved. +// (C) (or copyright) 2020-2026. Triad National Security, LLC. All rights reserved. // // This program was produced under U.S. Government contract 89233218CNA000001 for Los // Alamos National Laboratory (LANL), which is operated by Triad National Security, LLC @@ -13,6 +13,8 @@ #ifndef PACK_DEFAULT_NAMES_HPP_ #define PACK_DEFAULT_NAMES_HPP_ +// This file was made in part with generative AI. + #include #include #include @@ -38,9 +40,9 @@ namespace swarm_position { PAR_SWARMVAR(std::uint64_t, swarm, id); -PAR_SWARMVAR(parthenon::Real, swarm, x); -PAR_SWARMVAR(parthenon::Real, swarm, y); -PAR_SWARMVAR(parthenon::Real, swarm, z); +PAR_SWARMVAR(parthenon::Real, swarm, x1); +PAR_SWARMVAR(parthenon::Real, swarm, x2); +PAR_SWARMVAR(parthenon::Real, swarm, x3); } // namespace swarm_position #endif // PACK_DEFAULT_NAMES_HPP_ diff --git a/src/parthenon_manager.cpp b/src/parthenon_manager.cpp index 1df620c177856..d7860f15e4088 100644 --- a/src/parthenon_manager.cpp +++ b/src/parthenon_manager.cpp @@ -439,9 +439,9 @@ void ParthenonManager::RestartPackages(Mesh &rm, RestartReader &resfile) { pswarm_blk->AddEmptyParticles(counts[block_index]); block_index++; } - ReadSwarmVars_(swarm, rm.block_list, count_on_rank, offsets[0]); - ReadSwarmVars_(swarm, rm.block_list, count_on_rank, offsets[0]); - ReadSwarmVars_(swarm, rm.block_list, count_on_rank, offsets[0]); + resfile.ReadSwarmVars(swarm, rm.block_list, count_on_rank, offsets[0]); + resfile.ReadSwarmVars(swarm, rm.block_list, count_on_rank, offsets[0]); + resfile.ReadSwarmVars(swarm, rm.block_list, count_on_rank, offsets[0]); } // Params diff --git a/src/parthenon_manager.hpp b/src/parthenon_manager.hpp index 34fe5458e710f..7d6a5791e0520 100644 --- a/src/parthenon_manager.hpp +++ b/src/parthenon_manager.hpp @@ -1,5 +1,5 @@ //======================================================================================== -// (C) (or copyright) 2020-2024. Triad National Security, LLC. All rights reserved. +// (C) (or copyright) 2020-2026. Triad National Security, LLC. All rights reserved. // // This program was produced under U.S. Government contract 89233218CNA000001 for Los // Alamos National Laboratory (LANL), which is operated by Triad National Security, LLC @@ -11,6 +11,8 @@ // the public, perform publicly and display publicly, and to permit others to do so. //======================================================================================== +// This file was made in part with generative AI. + #ifndef PARTHENON_MANAGER_HPP_ #define PARTHENON_MANAGER_HPP_ @@ -29,6 +31,7 @@ #include "mesh/forest/forest_topology.hpp" #include "mesh/mesh.hpp" #include "outputs/restart.hpp" +#include "outputs/restart_hdf5.hpp" #include "parameter_input.hpp" #include "utils/error_checking.hpp" #include "utils/utils.hpp" @@ -61,68 +64,6 @@ class ParthenonManager { ArgParse arg; bool called_init_env_ = false; bool called_init_packages_and_mesh_ = false; - - template - void ReadSwarmVars_(const SP_Swarm &pswarm, const BlockList_t &block_list, - const std::size_t count_on_rank, const std::size_t offset) { - const std::string &swarmname = pswarm->label(); - std::vector dataVec; - for (const auto &var : pswarm->GetVariableVector()) { - const std::string &varname = var->label(); - const auto &m = var->metadata(); - auto arrdims = m.GetArrayDims(pswarm->GetBlockPointer(), false); - - auto var_missing_on_disk = !restartReader->VariableExists( - swarmname, RestartReader::DataType::SwarmVar, varname); - if (Globals::my_rank == 0) { - std::cout << "SwarmVar: " << varname - << (var_missing_on_disk ? " missing on disk\n" : "\n"); - } - if (var_missing_on_disk) { - // TODO(JMM/PG) Add failed load list of "fail/needs fix" list - continue; - } - - try { - restartReader->ReadSwarmVar(swarmname, varname, count_on_rank, offset, m, - dataVec); - } catch (std::exception &ex) { - // Variable does exist but could not be read. So we definitely want to fail here. - PARTHENON_THROW(StringPrintf("[%d] WARNING: Failed to read Swarm %s Variable %s " - "from restart file:\n%s", - Globals::my_rank, swarmname.c_str(), varname.c_str(), - ex.what())); - } - - // Only safe because swarm starts completely defragged. - // Note ordering here: block is second-inner-most loop. - // If hdf5 output format changes, this needs to change too. - std::size_t ivec = 0; - for (int n6 = 0; n6 < arrdims[5]; ++n6) { - for (int n5 = 0; n5 < arrdims[4]; ++n5) { - for (int n4 = 0; n4 < arrdims[3]; ++n4) { - for (int n3 = 0; n3 < arrdims[2]; ++n3) { - for (int n2 = 0; n2 < arrdims[1]; ++n2) { - for (auto &pmb : block_list) { - // 1 deep copy per tensor component per swarmvar per - // block, unfortunately. But only at initialization. - auto swarm_container = pmb->meshblock_data.Get()->GetSwarmData(); - auto pswarm_blk = swarm_container->Get(swarmname); - auto v = Kokkos::subview(pswarm_blk->Get(varname).data, n6, n5, n4, - n3, n2, Kokkos::ALL()); - auto v_h = Kokkos::create_mirror_view(v); - for (int n1 = 0; n1 < pswarm_blk->GetNumActive(); ++n1) { - v_h(n1) = dataVec[ivec++]; - } - Kokkos::deep_copy(v, v_h); - } - } - } - } - } - } - } - } }; } // namespace parthenon diff --git a/tst/regression/test_suites/particle_leapfrog/particle_leapfrog.py b/tst/regression/test_suites/particle_leapfrog/particle_leapfrog.py index f90137e274eee..62871680ea731 100644 --- a/tst/regression/test_suites/particle_leapfrog/particle_leapfrog.py +++ b/tst/regression/test_suites/particle_leapfrog/particle_leapfrog.py @@ -3,7 +3,7 @@ # Copyright(C) 2021 The Parthenon collaboration # Licensed under the 3-clause BSD License, see LICENSE file for details # ======================================================================================== -# (C) (or copyright) 2021. Triad National Security, LLC. All rights reserved. +# (C) (or copyright) 2021-2026. Triad National Security, LLC. All rights reserved. # # This program was produced under U.S. Government contract 89233218CNA000001 for Los # Alamos National Laboratory (LANL), which is operated by Triad National Security, LLC @@ -15,6 +15,8 @@ # the public, perform publicly and display publicly, and to permit others to do so. # ======================================================================================== +# This file was made in part with generative AI. + # Modules import math import numpy as np @@ -60,7 +62,7 @@ def Analyse(self, parameters): data = phdf("particles.out0.final.phdf") swarm = data.GetSwarm("my_particles") inds = np.argsort(swarm.id) - final_data = np.vstack((swarm.x, swarm.y, swarm.z, swarm["v"])) + final_data = np.vstack((swarm.x1, swarm.x2, swarm.x3, swarm["v"])) final_data = final_data.transpose()[inds] final_data[np.abs(final_data) < 1e-12] = 0 print(final_data) diff --git a/tst/regression/test_suites/particle_leapfrog_outflow/particle_leapfrog_outflow.py b/tst/regression/test_suites/particle_leapfrog_outflow/particle_leapfrog_outflow.py index 8a490a4b1cc5c..87277425082d9 100644 --- a/tst/regression/test_suites/particle_leapfrog_outflow/particle_leapfrog_outflow.py +++ b/tst/regression/test_suites/particle_leapfrog_outflow/particle_leapfrog_outflow.py @@ -3,7 +3,7 @@ # Copyright(C) 2021 The Parthenon collaboration # Licensed under the 3-clause BSD License, see LICENSE file for details # ======================================================================================== -# (C) (or copyright) 2021. Triad National Security, LLC. All rights reserved. +# (C) (or copyright) 2021-2026. Triad National Security, LLC. All rights reserved. # # This program was produced under U.S. Government contract 89233218CNA000001 for Los # Alamos National Laboratory (LANL), which is operated by Triad National Security, LLC @@ -15,6 +15,8 @@ # the public, perform publicly and display publicly, and to permit others to do so. # ======================================================================================== +# This file was made in part with generative AI. + # Modules import numpy as np from numpy.lib.recfunctions import structured_to_unstructured @@ -42,7 +44,7 @@ def Analyse(self, parameters): data = phdf("particles.out0.final.phdf") swarm = data.GetSwarm("my_particles") inds = np.argsort(swarm.id) - final_data = np.vstack((swarm.x, swarm.y, swarm.z, swarm["v"])) + final_data = np.vstack((swarm.x1, swarm.x2, swarm.x3, swarm["v"])) final_data = final_data.transpose()[inds] # see examples/particle_leapfrog/particle_leapfrog.cpp for reference data diff --git a/tst/regression/test_suites/particle_tracers/particle_tracers.py b/tst/regression/test_suites/particle_tracers/particle_tracers.py index 127fbc97a7766..e5939abbb70c2 100644 --- a/tst/regression/test_suites/particle_tracers/particle_tracers.py +++ b/tst/regression/test_suites/particle_tracers/particle_tracers.py @@ -3,7 +3,7 @@ # Copyright(C) 2021 The Parthenon collaboration # Licensed under the 3-clause BSD License, see LICENSE file for details # ======================================================================================== -# (C) (or copyright) 2024. Triad National Security, LLC. All rights reserved. +# (C) (or copyright) 2024-2026. Triad National Security, LLC. All rights reserved. # # This program was produced under U.S. Government contract 89233218CNA000001 for Los # Alamos National Laboratory (LANL), which is operated by Triad National Security, LLC @@ -15,6 +15,8 @@ # the public, perform publicly and display publicly, and to permit others to do so. # ======================================================================================== +# This file was made in part with generative AI. + # Modules import math import numpy as np @@ -46,7 +48,7 @@ def Analyse(self, parameters): data = phdf("particle_tracers.out0.final.phdf") swarm = data.GetSwarm("tracers") inds = np.argsort(swarm.Get("id")) - final_data = np.vstack((swarm.x, swarm.y, swarm.z)) + final_data = np.vstack((swarm.x1, swarm.x2, swarm.x3)) final_data = final_data.transpose()[inds] final_data[np.abs(final_data) < 1e-12] = 0 print(final_data) diff --git a/tst/regression/test_suites/particle_tracers_amr/particle_tracers_amr.py b/tst/regression/test_suites/particle_tracers_amr/particle_tracers_amr.py index 0ccbe693d526b..1aea318b58faf 100644 --- a/tst/regression/test_suites/particle_tracers_amr/particle_tracers_amr.py +++ b/tst/regression/test_suites/particle_tracers_amr/particle_tracers_amr.py @@ -58,9 +58,9 @@ def Analyse(self, parameters): initial_swarm = initial.GetSwarm("tracers") initial_pos = np.vstack( - (initial_swarm.x, initial_swarm.y, initial_swarm.z) + (initial_swarm.x1, initial_swarm.x2, initial_swarm.x3) ).transpose() - amr_pos = np.vstack((amr_swarm.x, amr_swarm.y, amr_swarm.z)).transpose() + amr_pos = np.vstack((amr_swarm.x1, amr_swarm.x2, amr_swarm.x3)).transpose() initial_pos[:, 0] = ((initial_pos[:, 0] + 0.5 + 0.35) % 1.0) - 0.5 initial_pos = sorted_positions(initial_pos) diff --git a/tst/unit/test_swarm.cpp b/tst/unit/test_swarm.cpp index 4d6effc610e94..020258b622016 100644 --- a/tst/unit/test_swarm.cpp +++ b/tst/unit/test_swarm.cpp @@ -3,7 +3,7 @@ // Copyright(C) 2020-2024 The Parthenon collaboration // Licensed under the 3-clause BSD License, see LICENSE file for details //======================================================================================== -// (C) (or copyright) 2020-2025. Triad National Security, LLC. All rights reserved. +// (C) (or copyright) 2020-2026. Triad National Security, LLC. All rights reserved. // // This program was produced under U.S. Government contract 89233218CNA000001 // for Los Alamos National Laboratory (LANL), which is operated by Triad @@ -17,6 +17,8 @@ // so. //======================================================================================== +// This file was made in part with generative AI. + #include #include #include @@ -131,22 +133,22 @@ TEST_CASE("Swarm memory management", "[Swarm][MPI]") { swarm->AddEmptyParticles(1); swarm_d = swarm->GetDeviceContext(); - auto x_d = swarm->Get(swarm_position::x::name()).Get(); - auto x_h = x_d.GetHostMirrorAndCopy(); + auto x1_d = swarm->Get(swarm_position::x1::name()).Get(); + auto x1_h = x1_d.GetHostMirrorAndCopy(); auto i_d = swarm->Get("i").Get(); auto i_h = i_d.GetHostMirrorAndCopy(); - x_h(0) = 0.5; + x1_h(0) = 0.5; i_h(1) = 2; - x_d.DeepCopy(x_h); + x1_d.DeepCopy(x1_h); i_d.DeepCopy(i_h); swarm->AddEmptyParticles(11); swarm_d = swarm->GetDeviceContext(); - x_d = swarm->Get(swarm_position::x::name()).Get(); + x1_d = swarm->Get(swarm_position::x1::name()).Get(); i_d = swarm->Get("i").Get(); - x_h = x_d.GetHostMirrorAndCopy(); + x1_h = x1_d.GetHostMirrorAndCopy(); i_h = i_d.GetHostMirrorAndCopy(); meshblock->par_for( "Check mask", 0, 2 * NUMINIT - 1, KOKKOS_LAMBDA(const int n) { @@ -163,8 +165,8 @@ TEST_CASE("Swarm memory management", "[Swarm][MPI]") { failures_h = failures_d.GetHostMirrorAndCopy(); REQUIRE(failures_h(0) == 0); // Check that existing data was successfully copied during pool resize - x_h = swarm->Get(swarm_position::x::name()).Get().GetHostMirrorAndCopy(); - REQUIRE(x_h(0) == 0.5); + x1_h = swarm->Get(swarm_position::x1::name()).Get().GetHostMirrorAndCopy(); + REQUIRE(x1_h(0) == 0.5); // Remove particles 3 and 5 meshblock->par_for( @@ -191,10 +193,10 @@ TEST_CASE("Swarm memory management", "[Swarm][MPI]") { REQUIRE(failures_h(0) == 0); // Enter some data to be moved during defragment - x_h = swarm->Get(swarm_position::x::name()).Get().GetHostMirrorAndCopy(); - x_h(10) = 1.1; - x_h(11) = 1.2; - x_d.DeepCopy(x_h); + x1_h = swarm->Get(swarm_position::x1::name()).Get().GetHostMirrorAndCopy(); + x1_h(10) = 1.1; + x1_h(11) = 1.2; + x1_d.DeepCopy(x1_h); // Defragment the list swarm->Defrag(); @@ -218,9 +220,9 @@ TEST_CASE("Swarm memory management", "[Swarm][MPI]") { swarm->Validate(); // Check that data was moved during defrag - x_h = swarm->Get(swarm_position::x::name()).Get().GetHostMirrorAndCopy(); - REQUIRE(x_h(2) == 1.1); - REQUIRE(x_h(4) == 1.2); + x1_h = swarm->Get(swarm_position::x1::name()).Get().GetHostMirrorAndCopy(); + REQUIRE(x1_h(2) == 1.1); + REQUIRE(x1_h(4) == 1.2); i_h = swarm->Get("i").Get().GetHostMirrorAndCopy(); REQUIRE(i_h(1) == 2); @@ -228,7 +230,7 @@ TEST_CASE("Swarm memory management", "[Swarm][MPI]") { ParArray1D bc_indices("Boundary indices", 1); meshblock->par_for( "Transport", 0, 0, KOKKOS_LAMBDA(const int n) { - x_d(0) = -0.6; + x1_d(0) = -0.6; bc_indices(0) = 0; }); diff --git a/tst/unit/test_swarm_amr_remesh.cpp b/tst/unit/test_swarm_amr_remesh.cpp index 0dec49386a5af..71ecd30d2f78d 100644 --- a/tst/unit/test_swarm_amr_remesh.cpp +++ b/tst/unit/test_swarm_amr_remesh.cpp @@ -123,20 +123,20 @@ void AddParticles(const SP_Swarm &swarm, const std::vector> &positions) { REQUIRE(swarm->GetNumActive() == 0); swarm->AddEmptyParticles(positions.size()); - auto x = swarm->Get(swarm_position::x::name()).Get(); - auto y = swarm->Get(swarm_position::y::name()).Get(); - auto z = swarm->Get(swarm_position::z::name()).Get(); - auto x_h = x.GetHostMirrorAndCopy(); - auto y_h = y.GetHostMirrorAndCopy(); - auto z_h = z.GetHostMirrorAndCopy(); + auto x1 = swarm->Get(swarm_position::x1::name()).Get(); + auto x2 = swarm->Get(swarm_position::x2::name()).Get(); + auto x3 = swarm->Get(swarm_position::x3::name()).Get(); + auto x1_h = x1.GetHostMirrorAndCopy(); + auto x2_h = x2.GetHostMirrorAndCopy(); + auto x3_h = x3.GetHostMirrorAndCopy(); for (int n = 0; n < positions.size(); ++n) { - x_h(n) = positions[n][0]; - y_h(n) = positions[n][1]; - z_h(n) = 0.0; + x1_h(n) = positions[n][0]; + x2_h(n) = positions[n][1]; + x3_h(n) = 0.0; } - x.DeepCopy(x_h); - y.DeepCopy(y_h); - z.DeepCopy(z_h); + x1.DeepCopy(x1_h); + x2.DeepCopy(x2_h); + x3.DeepCopy(x3_h); } //---------------------------------------------------------------------------------------- @@ -144,11 +144,11 @@ void AddParticles(const SP_Swarm &swarm, // against a deterministic reference ordering. std::vector> GetParticles(const SP_Swarm &swarm) { auto mask_h = swarm->GetMask().GetHostMirrorAndCopy(); - auto x_h = swarm->Get(swarm_position::x::name()).Get().GetHostMirrorAndCopy(); - auto y_h = swarm->Get(swarm_position::y::name()).Get().GetHostMirrorAndCopy(); + auto x1_h = swarm->Get(swarm_position::x1::name()).Get().GetHostMirrorAndCopy(); + auto x2_h = swarm->Get(swarm_position::x2::name()).Get().GetHostMirrorAndCopy(); std::vector> particles; for (int n = 0; n <= swarm->GetMaxActiveIndex(); ++n) { - if (mask_h(n)) particles.push_back({x_h(n), y_h(n)}); + if (mask_h(n)) particles.push_back({x1_h(n), x2_h(n)}); } std::sort(particles.begin(), particles.end()); return particles;