Skip to content

Patchghostless#1019

Merged
nicolasaunai merged 7 commits intoPHAREHUB:masterfrom
PhilipDeegan:patchghostless
Jul 26, 2025
Merged

Patchghostless#1019
nicolasaunai merged 7 commits intoPHAREHUB:masterfrom
PhilipDeegan:patchghostless

Conversation

@PhilipDeegan
Copy link
Member

@PhilipDeegan PhilipDeegan commented Jun 10, 2025

replaces #1000

@coderabbitai
Copy link

coderabbitai bot commented Jun 10, 2025

📝 Walkthrough
## Walkthrough

This update removes all handling and support for "patchGhost" particles and related diagnostics across the codebase, both in C++ and Python. It refactors particle copy, packing, and communication logic to exclude patch ghost regions, modifies field and particle fill patterns, introduces border sum refiners for field data, and updates tests, diagnostics, and utilities accordingly. Several new features and generic interfaces for field operations and boxing are introduced.

## Changes

| Files/Groups                                                                 | Change Summary |
|------------------------------------------------------------------------------|---------------|
| `src/amr/data/field/field_data.hpp`, `src/core/data/field/field_box.hpp`, `src/core/utilities/types.hpp` | Refactored field data operations to use generic, operator-based field copying and summation; added support for border summation and generic field box utilities. |
| `src/amr/data/field/field_variable_fill_pattern.hpp`                         | Simplified field fill pattern, removed conditional interior overwrite logic, and added a new ghost interpolation overlap fill pattern. |
| `src/amr/data/field/refine/field_refine_operator.hpp`                        | Removed `AFieldRefineOperator` base class; updated inheritance and constructor logic. |
| `src/amr/data/particles/particles_data.hpp`, `src/amr/data/particles/particles_variable_fill_pattern.hpp` | Reworked particle data copy/pack/unpack logic to exclude patch ghost particles; introduced new fill pattern for domain-from-ghost particle exchanges. |
| `src/amr/level_initializer/hybrid_level_initializer.hpp`                     | Refactored moment computation to separate domain and ghost region deposition, aligning with new ghost handling. |
| `src/amr/messengers/communicator.hpp`                                        | Added explicit special member functions for lifecycle management. |
| `src/amr/messengers/field_sum_transaction.hpp`                              | Added new transaction and factory classes for border sum operations on field data. |
| `src/amr/messengers/hybrid_hybrid_messenger_strategy.hpp`, `src/amr/messengers/hybrid_messenger.hpp`, `src/amr/messengers/hybrid_messenger_info.hpp`, `src/amr/messengers/hybrid_messenger_strategy.hpp`, `src/amr/messengers/mhd_hybrid_messenger_strategy.hpp` | Removed shared node and patch ghost refiners, introduced border sum refiners for flux/density, and updated messenger interfaces for border filling. |
| `src/amr/messengers/refiner.hpp`, `src/amr/messengers/refiner_pool.hpp`      | Updated refiner types and registration logic to support new border sum and ghost particle refiners; added optional fill pattern support. |
| `src/amr/physical_models/hybrid_model.hpp`                                   | Appended new ghost flux and border field names to messenger info for each ion population. |
| `src/amr/resources_manager/amr_utils.cpp`, `src/amr/resources_manager/amr_utils.hpp` | Changed AMR box utilities to return references; added ghost box construction excluding level ghost cells. |
| `src/amr/resources_manager/resources_manager.hpp`                            | Added method to retrieve lists of resource IDs for multiple keys. |
| `src/amr/solvers/solver_ppc.hpp`                                             | Introduced boxing mechanism for ion updater; removed patch ghost particle state saving/restoring; updated ion update and border fill logic. |
| `src/amr/utilities/box/amr_box.hpp`, `src/core/utilities/box/box.hpp`, `src/core/utilities/point/point.hpp` | Added utilities for unsigned box conversion, particle-in-box checks, transformation-based box shifts, and enhanced point arithmetic. |
| `src/core/data/grid/grid.hpp`, `src/core/data/grid/gridlayout.hpp`           | Added copy constructor to grid; added ghost box query methods to grid layout. |
| `src/core/data/ions/ion_population/ion_population.hpp`, `src/core/data/ions/ions.hpp` | Added bounds-checked and unchecked accessors for ion populations; added assertion for initializer info. |
| `src/core/data/particles/particle_array.hpp`, `src/core/utilities/cellmap.hpp` | Simplified erase and partition methods; removed replace_from. |
| `src/core/numerics/ion_updater/ion_updater.hpp`                              | Generalized updater methods to use boxing; removed patch ghost logic; introduced selection boxing struct. |
| `src/core/numerics/moments/moments.hpp`                                      | Removed patch ghost deposit tag and logic; added error handling for unknown deposit tags. |
| `src/diagnostic/detail/h5writer.hpp`                                         | Added timestamp accessor. |
| `src/diagnostic/diagnostic_model_view.hpp`                                   | Added support for momentum tensor refinement and border sum schedules. |
| `src/diagnostic/detail/types/fluid.hpp`, `src/diagnostic/detail/types/particle.hpp` | Removed patch ghost handling in population interpolation and particle diagnostics. |
| `src/python3/patch_level.hpp`                                                | Removed patch ghost particle data from Python patch level interface. |
| `tests/amr/data/field/refine/test_field_refine.cpp`, `tests/amr/messengers/test_messengers.cpp` | Reorganized includes; updated resource registration in tests. |
| `tests/amr/data/particles/copy/test_particledata_copyNd.cpp`, `tests/amr/data/particles/copy_overlap/test_particledata_copy_periodicNd.cpp`, `tests/amr/data/particles/stream_pack/test_main.cpp` | Updated or removed tests to reflect removal of patch ghost particles; tests now expect particles in domain containers. |
| `tests/core/numerics/ion_updater/test_updater.cpp`, `tools/bench/core/numerics/ion_updater/bench_ion_updater.cpp` | Updated tests and benchmarks to use boxing and new updater logic. |
| `tests/diagnostic/__init__.py`, `tests/diagnostic/test_diagnostics.hpp`, `tests/diagnostic/test_diagnostics.ipp`, `tests/functional/conservation/conserv.py`, `tests/simulator/test_advance.py`, `tests/simulator/test_initialization.py`, `tests/simulator/initialize/density_check.py`, `tests/simulator/initialize/test_particles_init_1d.py`, `tests/simulator/initialize/test_particles_init_2d.py`, `tests/simulator/advance/test_particles_advance_1d.py`, `tests/simulator/advance/test_particles_advance_2d.py` | Removed patch ghost diagnostics and related tests; updated expectations and test logic for new ghost handling. |
| `pyphare/pyphare/pharein/diagnostics.py`, `pyphare/pyphare/pharesee/hierarchy/fromh5.py`, `pyphare/pyphare/pharesee/hierarchy/fromsim.py`, `pyphare/pyphare/pharesee/hierarchy/hierarchy_utils.py`, `pyphare/pyphare/pharesee/run/run.py` | Removed patch ghost handling in diagnostics, file recognition, hierarchy construction, and run mass computation. |

## Sequence Diagram(s)

```mermaid
sequenceDiagram
    participant PatchA as Patch (src)
    participant PatchB as Patch (dst)
    participant BorderSumRefiner as BorderSumRefiner
    participant Messenger as Messenger

    Note over PatchA,PatchB: Field Border Summation (new flow)
    PatchA->>BorderSumRefiner: Prepare field data for border region
    BorderSumRefiner->>Messenger: Pack field border data
    Messenger->>PatchB: Send border data
    PatchB->>BorderSumRefiner: Unpack and sum into border region
sequenceDiagram
    participant PatchA as Patch (src)
    participant PatchB as Patch (dst)
    participant ParticleRefiner as ParticleDomainFromGhostRefiner
    participant Messenger as Messenger

    Note over PatchA,PatchB: Particle domain-from-ghost transfer (new logic)
    PatchA->>ParticleRefiner: Select ghost layer particles
    ParticleRefiner->>Messenger: Pack ghost particles with coordinate shift
    Messenger->>PatchB: Send ghost particles
    PatchB->>ParticleRefiner: Unpack and append to domain particles
Loading

Estimated code review effort

4 (~90 minutes)

Suggested labels

feature, refactoring

Suggested reviewers

  • nicolasaunai


</details>

<!-- walkthrough_end -->

<!-- announcements_start -->

> [!NOTE]
> <details open="true">
> <summary>⚡️ Unit Test Generation is now available in beta!</summary>
> 
> Learn more [here](https://docs.coderabbit.ai/finishing-touches/unit-test-generation), or try it out under "Finishing Touches" below.
> 
> </details>

<!-- announcements_end -->
<!-- internal state start -->


<!-- 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 -->

<!-- internal state end -->
<!-- finishing_touch_checkbox_start -->

<details>
<summary>✨ Finishing Touches</summary>

- [ ] <!-- {"checkboxId": "7962f53c-55bc-4827-bfbf-6a18da830691"} --> 📝 Generate Docstrings
<details>
<summary>🧪 Generate unit tests</summary>

- [ ] <!-- {"checkboxId": "f47ac10b-58cc-4372-a567-0e02b2c3d479", "radioGroupId": "utg-output-choice-group-unknown_comment_id"} -->   Create PR with unit tests
- [ ] <!-- {"checkboxId": "07f1e7d6-8a8e-4e23-9900-8731c2c87f58", "radioGroupId": "utg-output-choice-group-unknown_comment_id"} -->   Post copyable unit tests in a comment

</details>

</details>

<!-- finishing_touch_checkbox_end -->
<!-- tips_start -->

---

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

<details>
<summary>❤️ Share</summary>

- [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai)
- [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai)
- [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai)
- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code)

</details>

<details>
<summary>🪧 Tips</summary>

### Chat

There are 3 ways to chat with [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=PHAREHUB/PHARE&utm_content=1019):

- Review comments: Directly reply to a review comment made by CodeRabbit. Example:
  - `I pushed a fix in commit <commit_id>, please review it.`
  - `Explain this complex logic.`
  - `Open a follow-up GitHub issue for this discussion.`
- Files and specific lines of code (under the "Files changed" tab): Tag `@coderabbitai` in a new review comment at the desired location with your query. Examples:
  - `@coderabbitai explain this code block.`
  -	`@coderabbitai modularize this function.`
- PR comments: Tag `@coderabbitai` in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
  - `@coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.`
  - `@coderabbitai read src/utils.ts and explain its main purpose.`
  - `@coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.`
  - `@coderabbitai help me debug CodeRabbit configuration file.`

### Support

Need help? Create a ticket on our [support page](https://www.coderabbit.ai/contact-us/support) for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

### CodeRabbit Commands (Invoked using PR comments)

- `@coderabbitai pause` to pause the reviews on a PR.
- `@coderabbitai resume` to resume the paused reviews.
- `@coderabbitai review` to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
- `@coderabbitai full review` to do a full review from scratch and review all the files again.
- `@coderabbitai summary` to regenerate the summary of the PR.
- `@coderabbitai generate docstrings` to [generate docstrings](https://docs.coderabbit.ai/finishing-touches/docstrings) for this PR.
- `@coderabbitai generate sequence diagram` to generate a sequence diagram of the changes in this PR.
- `@coderabbitai generate unit tests` to generate unit tests for this PR.
- `@coderabbitai resolve` resolve all the CodeRabbit review comments.
- `@coderabbitai configuration` to show the current CodeRabbit configuration for the repository.
- `@coderabbitai help` to get help.

### Other keywords and placeholders

- Add `@coderabbitai ignore` anywhere in the PR description to prevent this PR from being reviewed.
- Add `@coderabbitai summary` to generate the high-level summary at a specific location in the PR description.
- Add `@coderabbitai` anywhere in the PR title to generate the title automatically.

### Documentation and Community

- Visit our [Documentation](https://docs.coderabbit.ai) for detailed information on how to use CodeRabbit.
- Join our [Discord Community](http://discord.gg/coderabbit) to get help, request features, and share feedback.
- Follow us on [X/Twitter](https://twitter.com/coderabbitai) for updates and announcements.

</details>

<!-- tips_end -->

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 11

🧹 Nitpick comments (13)
src/core/data/ions/ions.hpp (1)

256-256: Consider adding bounds checking for safety.

The indexing operator lacks bounds checking, which could lead to undefined behavior if an invalid index is passed. Consider adding a bounds check or documenting the precondition that the index must be valid.

-        auto& operator[](std::size_t const i) const { return populations_[i]; }
+        auto& operator[](std::size_t const i) const { 
+            assert(i < populations_.size());
+            return populations_[i]; 
+        }

Alternatively, consider providing a bounds-checked at() method alongside the unchecked operator.

src/core/data/ions/ion_population/ion_population.hpp (1)

46-50: Good defensive programming practice with assertion.

The runtime assertion ensures data integrity by verifying the presence of the required "density" key. This follows good defensive programming practices and will help catch configuration errors early.

Consider whether this should be a runtime exception instead of an assertion if the missing density key represents a recoverable error rather than a programming bug.

src/amr/messengers/mhd_hybrid_messenger_strategy.hpp (1)

112-121: Consider documenting the implementation strategy for border fill methods.

The new fillFluxBorders and fillDensityBorders methods are properly declared as overrides but have empty implementations with commented-out calls.

Consider adding documentation explaining:

  1. Why these methods are currently no-ops
  2. When the commented implementation might be activated
  3. The relationship to the underlying strategy object
+        // TODO: Implement flux border filling when MHD-Hybrid coupling is active
         void fillFluxBorders(IonsT& /*ions*/, SAMRAI::hier::PatchLevel& /*level*/,
                              double const /*fillTime*/) override
         {
             // strat_->fillFluxBorders(ions, level, fillTime);
         }
+        // TODO: Implement density border filling when MHD-Hybrid coupling is active
         void fillDensityBorders(IonsT& /*ions*/, SAMRAI::hier::PatchLevel& /*level*/,
                                 double const /*fillTime*/) override
         {
             // strat_->fillDensityBorders(ions, level, fillTime);
         }
src/core/utilities/types.hpp (1)

502-514: LGTM: Clean operator abstractions.

The Equals and PlusEquals template structs provide clean, reusable operator abstractions. The design using reference members and generic auto parameters is appropriate for the intended use case in field data operations.

Consider adding static_assert or concepts to constrain the template parameter D if specific requirements exist for the type.

src/core/data/grid/gridlayout.hpp (1)

1233-1255: Consider adding bounds validation in _BoxFor.

The _BoxFor helper function doesn't validate that the computed box has valid bounds (i.e., lower <= upper). Invalid bounds could lead to subtle bugs.

Add validation before returning the box:

         template<typename Field, typename Fn>
         auto _BoxFor(Field const& field, Fn startToEnd) const
         {
             std::array<std::uint32_t, dimension> lower, upper;
 
             auto const [ix0, ix1] = startToEnd(field, Direction::X);
             lower[0]              = ix0;
             upper[0]              = ix1;
             if constexpr (dimension > 1)
             {
                 auto const [iy0, iy1] = startToEnd(field, Direction::Y);
                 lower[1]              = iy0;
                 upper[1]              = iy1;
             }
             if constexpr (dimension == 3)
             {
                 auto const [iz0, iz1] = startToEnd(field, Direction::Z);
                 lower[2]              = iz0;
                 upper[2]              = iz1;
             }
+            // Validate bounds
+            for (std::size_t i = 0; i < dimension; ++i)
+            {
+                if (lower[i] > upper[i])
+                {
+                    throw std::runtime_error("Invalid box bounds: lower > upper in dimension " + std::to_string(i));
+                }
+            }
             return Box<std::uint32_t, dimension>{lower, upper};
         }
src/amr/data/particles/particles_variable_fill_pattern.hpp (1)

48-48: Consider adding virtual keyword to the destructor for consistency.

While not strictly necessary when inheriting from a virtual base, it's good practice to explicitly mark virtual destructors.

-    virtual ~ParticleDomainFromGhostFillPattern() {}
+    virtual ~ParticleDomainFromGhostFillPattern() override = default;
src/amr/messengers/field_sum_transaction.hpp (1)

161-164: Consider implementing printClassData instead of throwing.

The printClassData method throws an exception, which might cause issues if SAMRAI debugging or logging functionality expects this method to work properly.

-void FieldBorderSumTransaction<FieldData_t>::printClassData(std::ostream& stream) const
-{
-    PHARE_LOG_SCOPE(2, "FieldBorderSumTransaction::printClassData");
-    throw std::runtime_error("FieldBorderSumTransaction::printClassData!");
-}
+void FieldBorderSumTransaction<FieldData_t>::printClassData(std::ostream& stream) const
+{
+    PHARE_LOG_SCOPE(2, "FieldBorderSumTransaction::printClassData");
+    stream << "FieldBorderSumTransaction: "
+           << "dst_node=" << d_dst_node
+           << ", src_node=" << d_src_node
+           << ", item_id=" << d_item_id
+           << std::endl;
+}
src/core/data/field/field_box.hpp (1)

82-88: Consider adding automatic vector reservation in append_to.

The comment suggests the caller should reserve the vector, but it would be safer to handle this internally.

 template<typename Field_t>
 void FieldBox<Field_t>::append_to(std::vector<value_type>& vec)
 {
-    // reserve vec before use!
+    vec.reserve(vec.size() + lcl_box.size());
     auto src_it = lcl_box.begin();
     for (; src_it != lcl_box.end(); ++src_it)
         vec.push_back(field(*src_it));
 }
src/amr/solvers/solver_ppc.hpp (2)

153-168: Improve error message for debugging.

The error message "boxing map insertion failure" is not descriptive enough for debugging.

-                throw std::runtime_error("boxing map insertion failure");
+                throw std::runtime_error("Failed to insert boxing for patch " + amr::to_string(patch->getGlobalId()) + " at level " + std::to_string(lvlNbr));

434-436: Consider adding error handling for missing boxing data.

Using at() will throw if the patch ID is not found in the map. While make_boxes should ensure all patches are present, defensive programming would be beneficial.

-            ionUpdater_.updatePopulations(
-                state.ions, state.electromagAvg,
-                levelBoxing.at(amr::to_string(state.patch->getGlobalId())), dt, mode);
+            auto patch_id = amr::to_string(state.patch->getGlobalId());
+            auto it = levelBoxing.find(patch_id);
+            if (it == levelBoxing.end())
+                throw std::runtime_error("Boxing data not found for patch " + patch_id);
+            ionUpdater_.updatePopulations(
+                state.ions, state.electromagAvg, it->second, dt, mode);
src/amr/data/particles/particles_data.hpp (1)

760-772: Document the transformation asymmetry.

The unpack method doesn't apply any transformation, unlike the pack method. This appears intentional (particles are pre-transformed during packing), but should be documented for clarity.

Add a comment explaining why no transformation is needed during unpacking:

 void unpack_from_ghost(SAMRAI::tbox::MessageStream& stream,
                        ParticlesDomainOverlap const& /*pOverlap*/)
 {
     PHARE_LOG_SCOPE(3, "ParticlesData::unpack_from_ghost");
+    
+    // No transformation needed - particles were already transformed during packing
 
     std::size_t numberParticles = 0;
src/amr/messengers/hybrid_hybrid_messenger_strategy.hpp (1)

359-362: Consider using std::copy instead of memcpy for type safety

While memcpy is efficient, using std::copy would provide better type safety and work correctly with non-trivial types if the field type changes in the future.

-                        std::memcpy(sumVec[c].data(), pop.flux()[c].data(),
-                                    pop.flux()[c].size() * sizeof(value_type));
+                        std::copy(pop.flux()[c].data(), 
+                                 pop.flux()[c].data() + pop.flux()[c].size(),
+                                 sumVec[c].data());

Also applies to: 371-374

src/amr/messengers/refiner_pool.hpp (1)

211-212: Consider runtime validation instead of assertions

The size consistency checks use assert which is typically disabled in release builds. Consider either:

  • Using runtime exceptions for size mismatches
  • Using a single container of tuples/structs to ensure size consistency by design
-    assert(destinations.size() == sources.size());
-    assert(destinations.size() == keys.size());
+    if (destinations.size() != sources.size() || destinations.size() != keys.size())
+        throw std::invalid_argument("Size mismatch: destinations, sources, and keys must have the same size");
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between dfe17fa and 6f47b98.

📒 Files selected for processing (41)
  • src/amr/data/field/field_data.hpp (10 hunks)
  • src/amr/data/field/field_variable_fill_pattern.hpp (5 hunks)
  • src/amr/data/field/refine/field_refine_operator.hpp (2 hunks)
  • src/amr/data/particles/particles_data.hpp (9 hunks)
  • src/amr/data/particles/particles_variable_fill_pattern.hpp (1 hunks)
  • src/amr/level_initializer/hybrid_level_initializer.hpp (2 hunks)
  • src/amr/messengers/communicator.hpp (1 hunks)
  • src/amr/messengers/field_sum_transaction.hpp (1 hunks)
  • src/amr/messengers/hybrid_hybrid_messenger_strategy.hpp (15 hunks)
  • src/amr/messengers/hybrid_messenger.hpp (2 hunks)
  • src/amr/messengers/hybrid_messenger_info.hpp (1 hunks)
  • src/amr/messengers/hybrid_messenger_strategy.hpp (2 hunks)
  • src/amr/messengers/mhd_hybrid_messenger_strategy.hpp (4 hunks)
  • src/amr/messengers/refiner.hpp (8 hunks)
  • src/amr/messengers/refiner_pool.hpp (5 hunks)
  • src/amr/physical_models/hybrid_model.hpp (3 hunks)
  • src/amr/resources_manager/amr_utils.cpp (1 hunks)
  • src/amr/resources_manager/amr_utils.hpp (5 hunks)
  • src/amr/resources_manager/resources_manager.hpp (2 hunks)
  • src/amr/solvers/solver_ppc.hpp (8 hunks)
  • src/amr/utilities/box/amr_box.hpp (2 hunks)
  • src/core/data/field/field_box.hpp (1 hunks)
  • src/core/data/grid/grid.hpp (2 hunks)
  • src/core/data/grid/gridlayout.hpp (2 hunks)
  • src/core/data/ions/ion_population/ion_population.hpp (1 hunks)
  • src/core/data/ions/ions.hpp (2 hunks)
  • src/core/data/particles/particle_array.hpp (2 hunks)
  • src/core/numerics/ion_updater/ion_updater.hpp (7 hunks)
  • src/core/numerics/pusher/pusher.hpp (1 hunks)
  • src/core/utilities/box/box.hpp (5 hunks)
  • src/core/utilities/cellmap.hpp (2 hunks)
  • src/core/utilities/point/point.hpp (3 hunks)
  • src/core/utilities/types.hpp (2 hunks)
  • tests/amr/data/field/refine/test_field_refine.cpp (1 hunks)
  • tests/amr/messengers/test_messengers.cpp (2 hunks)
  • tests/core/numerics/ion_updater/test_updater.cpp (8 hunks)
  • tests/simulator/advance/test_particles_advance_1d.py (0 hunks)
  • tests/simulator/advance/test_particles_advance_2d.py (0 hunks)
  • tests/simulator/initialize/test_particles_init_1d.py (0 hunks)
  • tests/simulator/initialize/test_particles_init_2d.py (1 hunks)
  • tests/simulator/test_diagnostic_timestamps.py (1 hunks)
💤 Files with no reviewable changes (3)
  • tests/simulator/initialize/test_particles_init_1d.py
  • tests/simulator/advance/test_particles_advance_1d.py
  • tests/simulator/advance/test_particles_advance_2d.py
🧰 Additional context used
📓 Path-based instructions (1)
`**/*.hpp`: Review the C++ code, point out issues relative to principles of clean code, expressiveness, and performance.

**/*.hpp: Review the C++ code, point out issues relative to principles of clean code, expressiveness, and performance.

  • src/amr/messengers/communicator.hpp
  • src/amr/resources_manager/amr_utils.hpp
  • src/core/numerics/pusher/pusher.hpp
  • src/core/data/ions/ions.hpp
  • src/amr/data/field/refine/field_refine_operator.hpp
  • src/amr/resources_manager/resources_manager.hpp
  • src/core/data/ions/ion_population/ion_population.hpp
  • src/core/utilities/point/point.hpp
  • src/amr/messengers/hybrid_messenger.hpp
  • src/core/data/grid/grid.hpp
  • src/core/utilities/cellmap.hpp
  • src/amr/messengers/hybrid_messenger_info.hpp
  • src/amr/messengers/hybrid_messenger_strategy.hpp
  • src/amr/messengers/mhd_hybrid_messenger_strategy.hpp
  • src/amr/level_initializer/hybrid_level_initializer.hpp
  • src/core/utilities/types.hpp
  • src/core/data/particles/particle_array.hpp
  • src/core/data/grid/gridlayout.hpp
  • src/amr/physical_models/hybrid_model.hpp
  • src/amr/utilities/box/amr_box.hpp
  • src/amr/messengers/field_sum_transaction.hpp
  • src/amr/solvers/solver_ppc.hpp
  • src/core/utilities/box/box.hpp
  • src/core/data/field/field_box.hpp
  • src/amr/data/particles/particles_variable_fill_pattern.hpp
  • src/amr/messengers/hybrid_hybrid_messenger_strategy.hpp
  • src/core/numerics/ion_updater/ion_updater.hpp
  • src/amr/data/field/field_variable_fill_pattern.hpp
  • src/amr/messengers/refiner_pool.hpp
  • src/amr/messengers/refiner.hpp
  • src/amr/data/particles/particles_data.hpp
  • src/amr/data/field/field_data.hpp
🧬 Code Graph Analysis (7)
src/amr/messengers/hybrid_messenger.hpp (2)
src/amr/messengers/hybrid_hybrid_messenger_strategy.hpp (16)
  • ions (330-343)
  • ions (330-331)
  • ions (347-376)
  • ions (347-348)
  • ions (378-403)
  • ions (378-379)
  • ions (415-451)
  • ions (415-416)
  • ions (459-465)
  • ions (459-460)
  • level (477-502)
  • level (477-480)
  • level (607-619)
  • level (607-607)
  • level (754-769)
  • level (754-754)
src/amr/messengers/hybrid_messenger_strategy.hpp (6)
  • ions (78-79)
  • ions (83-84)
  • ions (88-89)
  • ions (122-123)
  • ions (125-126)
  • level (116-116)
src/amr/messengers/hybrid_messenger_strategy.hpp (2)
src/amr/messengers/hybrid_hybrid_messenger_strategy.hpp (16)
  • ions (330-343)
  • ions (330-331)
  • ions (347-376)
  • ions (347-348)
  • ions (378-403)
  • ions (378-379)
  • ions (415-451)
  • ions (415-416)
  • ions (459-465)
  • ions (459-460)
  • level (477-502)
  • level (477-480)
  • level (607-619)
  • level (607-607)
  • level (754-769)
  • level (754-754)
src/amr/messengers/hybrid_messenger.hpp (7)
  • ions (299-303)
  • ions (299-300)
  • ions (314-318)
  • ions (314-315)
  • ions (321-325)
  • ions (321-322)
  • level (188-188)
src/amr/messengers/mhd_hybrid_messenger_strategy.hpp (1)
src/amr/messengers/mhd_messenger.hpp (1)
  • stratName (121-121)
src/amr/physical_models/hybrid_model.hpp (3)
src/amr/messengers/hybrid_hybrid_messenger_strategy.hpp (12)
  • level (477-502)
  • level (477-480)
  • level (607-619)
  • level (607-607)
  • level (754-769)
  • level (754-754)
  • info (659-685)
  • info (659-659)
  • info (690-732)
  • info (690-690)
  • info (736-749)
  • info (736-736)
src/amr/solvers/solver_ppc.hpp (10)
  • level (106-109)
  • level (106-106)
  • level (116-117)
  • level (120-121)
  • level (124-125)
  • level (128-129)
  • level (132-133)
  • level (136-136)
  • level (137-137)
  • info (83-83)
src/amr/solvers/solver.hpp (1)
  • info (81-81)
src/amr/utilities/box/amr_box.hpp (4)
src/core/data/particles/particle_array.hpp (15)
  • dim (21-65)
  • dim (251-288)
  • box (232-232)
  • box (232-232)
  • bool (78-81)
  • bool (215-225)
  • bool (322-325)
  • i (75-75)
  • i (75-75)
  • i (76-76)
  • i (76-76)
  • i (305-305)
  • i (305-305)
  • i (306-306)
  • i (306-306)
src/core/utilities/box/box.hpp (11)
  • dim (99-115)
  • dim (117-132)
  • box (50-50)
  • bool (50-53)
  • bool (73-73)
  • bool (243-257)
  • lower (93-93)
  • lower (98-98)
  • upper (88-88)
  • shift (282-288)
  • shift (282-282)
src/core/utilities/point/point.hpp (6)
  • bool (73-84)
  • bool (86-86)
  • i (68-68)
  • i (68-68)
  • i (69-69)
  • i (69-69)
src/core/utilities/types.hpp (4)
  • for_N (428-459)
  • for_N (428-428)
  • for_N (462-465)
  • for_N (462-462)
src/amr/messengers/field_sum_transaction.hpp (2)
src/amr/data/particles/particles_data.hpp (15)
  • overlap (274-293)
  • overlap (274-274)
  • overlap (618-646)
  • overlap (618-618)
  • overlap (650-688)
  • overlap (650-652)
  • stream (318-338)
  • stream (318-319)
  • stream (340-354)
  • stream (340-341)
  • stream (371-372)
  • stream (374-426)
  • stream (374-375)
  • stream (428-442)
  • stream (428-429)
src/amr/data/field/field_data.hpp (11)
  • overlap (208-211)
  • overlap (208-208)
  • overlap (417-434)
  • overlap (417-417)
  • stream (219-250)
  • stream (219-220)
  • stream (257-261)
  • stream (257-258)
  • stream (324-325)
  • unpackStream (264-292)
  • unpackStream (264-265)
src/amr/data/field/field_variable_fill_pattern.hpp (4)
src/amr/data/particles/particles_variable_fill_pattern.hpp (4)
  • dst_geometry (50-78)
  • dst_geometry (51-55)
  • fill_boxes (100-109)
  • fill_boxes (101-104)
src/amr/utilities/box/amr_box.hpp (6)
  • phare_box_from (25-31)
  • phare_box_from (25-25)
  • shift (153-157)
  • shift (153-154)
  • samrai_box_from (16-22)
  • samrai_box_from (16-16)
src/core/utilities/box/box.hpp (5)
  • box (50-50)
  • grow (274-279)
  • grow (274-274)
  • shift (282-288)
  • shift (282-282)
src/amr/data/field/field_geometry.hpp (4)
  • box (155-258)
  • box (155-156)
  • box (267-276)
  • box (267-267)
⏰ Context from checks skipped due to timeout of 90000ms (7)
  • GitHub Check: build (ubuntu-latest, clang)
  • GitHub Check: build (ubuntu-latest, gcc)
  • GitHub Check: Analyze (python)
  • GitHub Check: build (macos-latest)
  • GitHub Check: Analyze (cpp)
  • GitHub Check: build (macos-14)
  • GitHub Check: build (macos-13)
🔇 Additional comments (74)
src/core/numerics/pusher/pusher.hpp (1)

23-24: LGTM! Good API improvement.

Making ParticleSelector public appropriately exposes this type alias for external use, which aligns with the broader particle data handling refactoring mentioned in the PR objectives.

tests/simulator/test_diagnostic_timestamps.py (1)

120-120: LGTM! Appropriate fix for MPI testing issues.

Changing from h5_flush_never to a fixed flush interval of 10000 is a reasonable solution to address the MPI parallelism issues observed at t=46.42300. This ensures data consistency during testing without significantly impacting performance.

tests/amr/messengers/test_messengers.cpp (2)

263-264: LGTM! Good refactoring of resource registration.

Simplifying the resource registration by registering the entire state objects instead of individual sub-components (electromag, ions, B, V) makes the code cleaner and more maintainable. This aligns well with the broader messenger refactoring.


307-307: LGTM! Proper solver resource registration.

Adding the call to registerResources on the hybrid solver ensures complete test setup and is consistent with the resource management patterns being established.

tests/amr/data/field/refine/test_field_refine.cpp (1)

4-5: LGTM! Better include organization.

The reorganization logically groups related includes together - core grid layout headers first, then AMR-specific includes, followed by external library headers. The addition of gridlayoutimplyee.hpp suggests preparation for testing updated grid layout functionality.

Also applies to: 13-17

src/amr/messengers/hybrid_messenger_info.hpp (1)

69-71: LGTM! Well-structured additions for enhanced field management.

The new member variables ghostFlux and sumBorderFields follow the established naming conventions and appropriately extend the class to support ghost flux field tracking and border field summation functionality.

src/amr/resources_manager/amr_utils.cpp (1)

34-40: LGTM! Improved interface with fluent design pattern.

The change from void return to SAMRAI::hier::Box& enables method chaining and follows the fluent interface pattern. This maintains existing functionality while providing additional flexibility for callers.

src/amr/messengers/communicator.hpp (1)

55-59: LGTM! Excellent application of the Rule of Five.

The explicit special member functions provide clear object lifecycle semantics:

  • Virtual destructor ensures proper cleanup in inheritance hierarchies
  • Deleted copy constructor prevents accidental copying of resource-managing objects
  • Defaulted move constructor allows efficient resource transfer

This is best practice for template classes managing SAMRAI resources.

src/core/utilities/cellmap.hpp (2)

173-173: Simplified parameter passing - acceptable trade-off.

The change from Range&& to Range removes perfect forwarding in favor of pass-by-value. This simplifies the interface and is acceptable since Range is likely a lightweight object containing iterators.


451-451:

Details

✅ Verification successful

Verify the partition return value calculation.

The change from range.ibegin() + pivot to just pivot in the makeRange call alters the end iterator calculation. Ensure that pivot is the correct absolute iterator position rather than an offset.


🏁 Script executed:

#!/bin/bash
# Description: Verify makeRange function signature and usage to confirm correct arguments
# Expected: makeRange should accept (array, begin_iter, end_iter) where end_iter is absolute position

# Search for makeRange function definition
ast-grep --pattern 'makeRange($_, $_, $_) { $$$ }'

# Search for other makeRange usage patterns
rg -A 2 -B 2 "makeRange"

Length of output: 7607


🏁 Script executed:

#!/bin/bash
# Locate and display the context where `pivot` is computed and used
rg -n "pivot" src/core/utilities/cellmap.hpp
pivot_line=$(rg -n "pivot" src/core/utilities/cellmap.hpp | head -n1 | cut -d: -f1)
start=$((pivot_line - 10)); [ $start -lt 1 ] && start=1
end=$((pivot_line + 10))
sed -n "${start},${end}p" src/core/utilities/cellmap.hpp

Length of output: 1552


🏁 Script executed:

#!/bin/bash
# Extract the full partition implementation to verify pivot calculation
start_line=$(rg -n "template<typename Range, typename Predicate" -n src/core/utilities/cellmap.hpp | head -n1 | cut -d: -f1)
end_line=$((start_line + 200))
sed -n "${start_line},${end_line}p" src/core/utilities/cellmap.hpp

Length of output: 5883


🏁 Script executed:

#!/bin/bash
# Locate the definition of CellMap::partition
rg -n "CellMap<.*>::partition" -n src/core/utilities/cellmap.hpp | head -n5

# If found, print the surrounding implementation
def_line=$(rg -n "CellMap<.*>::partition" -n src/core/utilities/cellmap.hpp | head -n1 | cut -d: -f1)
start=$((def_line - 10)); [ $start -lt 1 ] && start=1
end=$((def_line + 200))
sed -n "${start},${end}p" src/core/utilities/cellmap.hpp

Length of output: 3460


No change needed: Pivot is already an absolute end index
The overload makeRange(Array&, std::size_t, std::size_t) expects absolute begin/end indices, and here pivot is initialized to range.iend() (an absolute index) and decremented in absolute terms. Returning

makeRange(range.array(), range.ibegin(), pivot);

correctly yields the subrange [ibegin, pivot).

src/amr/resources_manager/resources_manager.hpp (1)

452-452: Minor formatting improvement noted.

The formatting adjustment aligns the parameter list properly, improving code readability.

tests/simulator/initialize/test_particles_init_2d.py (1)

26-26: Correct class name fix.

The class name change from Initialization1DTest to Initialization2DTest properly reflects that this file contains 2D tests (as evidenced by ndim = 2 on line 16). This fixes a naming inconsistency.

src/core/data/grid/grid.hpp (2)

64-72: Excellent refactoring for centralized initialization.

The addition of the copy constructor and removal of field_ initialization from constructors is a well-designed improvement:

  1. RAII compliance: Field initialization is now centralized at the member declaration, ensuring consistent initialization regardless of constructor used.
  2. DRY principle: Eliminates code duplication across multiple constructors.
  3. Copy semantics: The explicit copy constructor properly handles copying the grid data and metadata.

This change aligns with modern C++ best practices for member initialization.


93-93: Centralized member initialization follows best practices.

Moving the field_ initialization to the member declaration ensures consistent initialization and eliminates potential issues with constructor ordering.

src/amr/messengers/mhd_hybrid_messenger_strategy.hpp (3)

22-22: Consistent const placement style.

The change from static const std::string to static std::string const follows the consistent const placement style where const appears after the type it modifies.


69-69: Parameter const qualification improvement.

Adding const qualification to the parameter enhances const-correctness and clearly indicates the parameter won't be modified.


162-163: Static member definition consistency maintained.

The static member definition correctly matches the updated declaration, maintaining consistency across the codebase.

src/amr/data/field/refine/field_refine_operator.hpp (3)

9-14: Clean include removal improves compilation efficiency.

Removing unused includes reduces compilation dependencies and improves build times. The remaining includes appear sufficient for the class functionality.


27-27: Class hierarchy simplification reduces complexity.

Removing the inheritance from AFieldRefineOperator simplifies the class hierarchy and eliminates an unnecessary abstraction layer. Direct inheritance from SAMRAI::hier::RefineOperator is more straightforward and maintainable.


36-37: Constructor simplification follows hierarchy changes.

The simplified constructor initialization list correctly reflects the removal of the intermediate base class, maintaining proper initialization while reducing complexity.

src/amr/messengers/hybrid_messenger_strategy.hpp (2)

57-57: LGTM: Minor formatting improvement.

Removing trailing whitespace improves code cleanliness.


122-127: LGTM: Well-designed interface extension.

The new pure virtual methods fillFluxBorders and fillDensityBorders follow the established pattern of existing fill methods and maintain consistent parameter naming and types. The interface expansion is coherent with the existing design.

src/core/utilities/types.hpp (1)

229-229: LGTM: Proper const qualification.

Adding const to the char* return from std::getenv follows best practices for immutable data.

src/amr/level_initializer/hybrid_level_initializer.hpp (2)

82-97: LGTM: Improved data exchange sequence.

The refactored initialization sequence properly separates domain particle deposits from level ghost operations, allowing for explicit border filling between phases. This design enhances the control over data exchange patterns and aligns with the new border filling capabilities.

The comment at line 82 accurately describes the algorithmic change.


99-113: LGTM: Consistent level ghost handling.

The second loop correctly handles level ghost deposits and moment computations after border filling is complete. The conditional level ghost deposit based on !isRootLevel(levelNumber) maintains the existing logic correctly.

src/amr/resources_manager/amr_utils.hpp (5)

7-20: LGTM: Improved header organization.

Moving SAMRAI headers into a grouped block after project-specific includes improves code organization and readability.


47-48: LGTM: Consistent return type.

Changing AMRToLocal to return a reference to the modified box is consistent with the typical pattern of in-place modification functions and provides better usability.


139-139: LGTM: Improved type deduction.

Using auto constexpr instead of int constexpr for dimension allows better type deduction while maintaining compile-time evaluation.


213-218: LGTM: Generalized utility function.

Converting the to_string function to a generic template with auto parameter improves reusability while maintaining the same functionality for the original use case.


192-211:

Details

❓ Verification inconclusive

Verify the complex box computation logic.

The makeNonLevelGhostBoxFor function implements sophisticated logic to compute patch ghost boxes excluding level ghost cells. The algorithm merges overlapping neighbor boxes to determine the final ghost region.


🏁 Script executed:

#!/bin/bash
# Verify the usage and integration of makeNonLevelGhostBoxFor
ast-grep --pattern 'makeNonLevelGhostBoxFor($$$)'

Length of output: 51


Verify makeNonLevelGhostBoxFor Logic and Usage

Please manually confirm the following for the makeNonLevelGhostBoxFor function in
src/amr/resources_manager/amr_utils.hpp (lines 192–211):

  • The merging of neighbor boxes correctly excludes level-ghost cells in all dimensions, including edge and corner cases at domain boundaries.
  • There are no missing neighbor contributions or unintended overlaps when calling
    hier_nbrs.getSameLevelNeighbors(…).
  • Template instantiations (GridLayoutT) with different dimension and nbrParticleGhosts() values behave as expected.
  • Adequate test coverage exists (or should be added) to validate the computed ghost box for representative grid layouts.
  • Ensure this utility is actually invoked where intended; if it’s not used yet, either integrate it or remove dead code.
src/core/data/particles/particle_array.hpp (2)

99-99: LGTM: Simplified method signature.

Consolidating the two erase overloads into a single method taking IndexRange_ by value eliminates unnecessary forwarding complexity while maintaining the same functionality.


200-206: LGTM: Well-designed delegation with safety check.

The templated partition method properly delegates to cellMap_ and includes a defensive assertion to ensure the returned range size doesn't exceed the input range size. The template design allows for flexible range types while maintaining type safety.

src/amr/physical_models/hybrid_model.hpp (3)

46-46: Good placement of static member declaration.

Moving the static member declaration closer to its usage improves code readability.


53-53: Correct removal of redundant virtual keyword.

The override specifier already implies virtual, so removing the explicit virtual keyword follows C++ best practices and reduces redundancy.

Also applies to: 73-73


178-182: Correctly implements population of new messenger info fields.

The loop properly adds flux and density fields for each ion population to support the new border summation features.

src/amr/messengers/hybrid_messenger.hpp (2)

334-342: Well-implemented delegation methods for border filling.

The new fillFluxBorders and fillDensityBorders methods properly follow the established delegation pattern to the strategy object.


354-354: Good use of const correctness for the strategy pointer.

Making the unique_ptr itself const prevents accidental reassignment of the strategy after construction while still allowing modification of the strategy object itself.

src/core/utilities/point/point.hpp (2)

133-146: Well-implemented operator+= overloads.

Both scalar and array-like overloads are correctly implemented with appropriate use of template template parameters for generic array support.


206-215: ⚠️ Potential issue

Add handling for non-4-byte types in as_unsigned().

The method only handles 4-byte types and lacks an else clause, which could lead to undefined behavior for other type sizes.

Add proper handling for all type sizes:

        auto as_unsigned() const
        {
            PHARE_DEBUG_DO({
                for (auto iDim = 0u; iDim < dim; ++iDim)
                    assert(r[iDim] >= 0);
            })
            if constexpr (sizeof(Type) == 4)
                return Point<std::uint32_t, dim>{this->template toArray<std::uint32_t>()};
-            // else no return cause not yet handled
+            else if constexpr (sizeof(Type) == 8)
+                return Point<std::uint64_t, dim>{this->template toArray<std::uint64_t>()};
+            else
+                static_assert(sizeof(Type) == 4 || sizeof(Type) == 8, 
+                            "as_unsigned() only supports 4-byte and 8-byte types");
        }
⛔ Skipped due to learnings
Learnt from: PhilipDeegan
PR: PHAREHUB/PHARE#998
File: src/core/utilities/point/point.hpp:195-210
Timestamp: 2025-04-17T14:41:53.643Z
Learning: In `src/core/utilities/point/point.hpp`, the `as_signed()` and `as_unsigned()` methods are intentionally designed to cause compilation errors for unsupported types (only 4-byte types are supported). This forces developers to implement proper conversions themselves when extending the functionality to new types. The comment "else no return cause not yet handled" indicates this is a deliberate design choice.
tests/core/numerics/ion_updater/test_updater.cpp (2)

358-367: Correct introduction of boxing abstraction.

The Boxing_t type alias and boxing member properly encapsulate the particle selection logic, with the AMR box correctly grown by the number of particle ghosts.


493-495: Test updates correctly reflect the new particle management approach.

The tests have been properly updated to:

  1. Use the boxing abstraction in all updatePopulations calls
  2. Expect zero patch ghost particles, reflecting the new particle management strategy
  3. Maintain appropriate test coverage for the refactored functionality

Also applies to: 733-733, 779-779, 804-804, 824-824, 842-842

src/amr/utilities/box/amr_box.hpp (3)

33-39: LGTM!

The function correctly converts SAMRAI boxes to PHARE boxes with unsigned coordinates, properly reusing existing functionality.


137-149: LGTM!

The as_point overloads correctly convert SAMRAI types to PHARE points using appropriate compile-time utilities.


152-157: LGTM!

The function correctly shifts boxes using the transformation offset, properly delegating to the core shift function.

src/amr/data/particles/particles_variable_fill_pattern.hpp (2)

19-35: LGTM!

The ParticlesDomainOverlap class correctly serves as a marker type for particle domain overlaps.


51-78: LGTM!

The calculateOverlap method correctly computes overlap regions by growing destination boxes and intersecting with the patch box.

src/amr/messengers/field_sum_transaction.hpp (2)

186-222: LGTM!

The factory class correctly implements the transaction factory interface with appropriate allocate method and intentional no-op preprocessing.


146-156:

Details

✅ Verification successful

Verify that unpackStreamAndSum method exists in FieldData_t.

The code calls unpackStreamAndSum on the field data object. Ensure this method is properly implemented in all FieldData types that will be used with this transaction.


🏁 Script executed:

#!/bin/bash
# Description: Verify that unpackStreamAndSum method exists in FieldData classes

# Search for unpackStreamAndSum method definition
ast-grep --pattern 'unpackStreamAndSum($_) { $$$ }'

# Also search with rg for any declarations or definitions
rg -A 5 "unpackStreamAndSum"

Length of output: 1417


Confirmed unpackStreamAndSum Exists in FieldData

  • The method is declared and defined in src/amr/data/field/field_data.hpp:
    • Declaration:
      void unpackStreamAndSum(SAMRAI::tbox::MessageStream& stream,
                              SAMRAI::hier::BoxOverlap const& overlap);
    • Definition:
      template<typename GridLayoutT, typename Grid_t, typename PhysicalQuantity>
      void FieldData<GridLayoutT, Grid_t, PhysicalQuantity>::unpackStreamAndSum(
          SAMRAI::tbox::MessageStream& stream,
          SAMRAI::hier::BoxOverlap const& overlap)
      {
          using PlusEqualOp = core::PlusEquals<value_type>;
          unpackStream<PlusEqualOp>(stream, overlap, field);
      }
  • The call in src/amr/messengers/field_sum_transaction.hpp (line 155) is therefore valid.

No further action required.

src/core/utilities/box/box.hpp (4)

28-28: LGTM!

Adding the static dimension member is a good practice for template metaprogramming consistency.


242-257: LGTM!

The improved parameter names and template signature enhance code readability.


259-264: LGTM!

The particle overload with SFINAE trailing return type is well-designed for type safety.


310-320: LGTM!

The merge method correctly computes the minimal bounding box containing both boxes.

src/amr/data/field/field_variable_fill_pattern.hpp (4)

32-37: LGTM! Constructor simplification is appropriate.

The defaulted parameter makes this the default constructor while maintaining backward compatibility.


61-67: Good use of static member for pattern name.

Using a static member for the pattern name is cleaner and more efficient than returning a temporary string.


142-146: Clarify the purpose of adding 1 to the ghost box upper bound.

The lambda _primal_ghost_box adds 1 to the upper bound after growing by ghost width. This seems arbitrary and could lead to off-by-one errors.

Please document why this +1 is necessary or remove it if not needed. Is this related to primal/dual grid indexing?


54-58:

Details

❓ Verification inconclusive

Verify the assertion logic for overwrite_interior.

The assertion expects fn_overwrite_interior == true, but the class comment (lines 19-21) states that overwrite_interior defaults to "false" to avoid overwriting shared border nodes. This appears contradictory.

Please verify whether this assertion is correct or if it should be removed/inverted. Run the following script to check how this method is called:


🏁 Script executed:

#!/bin/bash
# Search for calls to calculateOverlap to understand the expected fn_overwrite_interior values
ast-grep --pattern 'calculateOverlap($$$)'
rg -A 5 "calculateOverlap.*fn_overwrite_interior" 

Length of output: 96


🏁 Script executed:

#!/bin/bash
# Inspect the class comment and default for overwrite_interior_
sed -n '1,60p' src/amr/data/field/field_variable_fill_pattern.hpp

# Show the constructor(s) to see how overwrite_interior_ is initialized
rg -n "FieldVariableFillPattern\s*::\s*FieldVariableFillPattern" -C 2 src/amr/data/field/field_variable_fill_pattern.hpp

# Search for any definitions or overloads of calculateOverlap in the repo
rg -n "calculateOverlap" -A 2

Length of output: 11343


Verify assertion logic for fn_overwrite_interior

The class comment (lines 19–21) states that overwrite_interior_ defaults to false so shared border nodes aren’t overwritten, yet the override asserts that the SAMRAI-provided fn_overwrite_interior must always be true. These behaviors seem at odds—please confirm:

  • Does SAMRAI always call this method with fn_overwrite_interior == true?
  • If not, should the assert(fn_overwrite_interior == true) be removed or inverted?

Location:

  • src/amr/data/field/field_variable_fill_pattern.hpp:54–58
src/amr/solvers/solver_ppc.hpp (2)

99-103: LGTM! Proper cleanup in onRegrid.

Clearing the boxing map and resetting the ion updater ensures clean state after regridding.


442-443: Good placement of border filling calls.

The flux and density border filling is correctly placed after ion population updates and before ghost particle filling.

src/core/numerics/ion_updater/ion_updater.hpp (3)

119-158: Well-designed boxing abstraction.

The UpdaterSelectionBoxing struct nicely encapsulates particle selection logic with clear predicates for different particle regions. The lambda captures are properly done to detach from class references.


176-183: Clean refactoring of domain particle update.

Good use of local copy to avoid aliasing issues. The boxing selectors make the particle filtering logic much clearer.


244-252: Efficient patch ghost particle extraction.

Good approach to extract patch ghosts from particles leaving the domain. The reserve() call helps avoid reallocations.

src/amr/data/particles/particles_data.hpp (2)

231-258: Well-structured overlap type dispatch.

The dynamic dispatch based on overlap type is cleanly implemented with appropriate use of dynamic_cast and early returns.


708-719: Correct transformation handling in ghost copy.

The use of negative offset to transform from destination to source space is correct. The offseter lambda properly shifts particle coordinates.

src/amr/data/field/field_data.hpp (2)

340-357: Excellent refactoring with operator templates.

The use of FieldBox abstraction and operator templates greatly improves code reusability. The same logic can now handle both assignment and accumulation operations.


449-471: Clean implementation of sum operations.

The sum and unpackStreamAndSum methods elegantly reuse the existing copy logic with the PlusEquals operator.

src/amr/messengers/hybrid_hybrid_messenger_strategy.hpp (3)

651-657: Good refactoring with the makeKeys helper

The makeKeys lambda effectively reduces code duplication and improves readability when extracting vector field names.


718-732: Border sum refiner registration looks correct

The implementation properly creates separate refiners for each population's flux and density fields using the new FieldGhostInterpOverlapFillPattern. The use of emplace_back is efficient.


335-343:

Details

❌ Incorrect review comment

Verify the architectural change from patch to domain ghost particles

The method now uses domainGhostPartRefiners_ and clears patchGhostParticles(). This represents a significant architectural change in ghost particle handling.


🏁 Script executed:

#!/bin/bash
# Description: Verify that patchGhostParticles are no longer used elsewhere after being cleared

# Search for any remaining uses of patchGhostParticles
rg -A 3 "patchGhostParticles\(\)" --type cpp

# Check if there are any tests that might be affected by this change
fd -e cpp -e py test | xargs rg "patchGhost|patch.*ghost" -l

Length of output: 8333


Incorrect review concern: patchGhostParticles remains in active use
A global search shows patchGhostParticles() is still referenced throughout core code paths and tests (e.g. in ion_updater.hpp, moments.hpp, solver PPC, diagnostics, and numerous unit tests). The local .clear() in the hybrid messenger strategy is simply housekeeping before using the new domainGhostPartRefiners_, not a wholesale removal of patch‐level ghost handling. You can disregard the original suggestion to verify a global architectural shift away from patch ghosts.

Likely an incorrect or invalid review comment.

src/amr/messengers/refiner.hpp (4)

16-24: RefinerType enum changes are properly handled

The removal of InteriorGhostParticles and SharedBorder and addition of PatchFieldBorderSum and ExteriorGhostParticles are correctly handled in the registerLevel method's switch statement.


274-310: Excellent refactoring with helper methods

The new helper methods (register_resource, register_time_interpolated_resource, register_vector_field, register_time_interpolated_vector_field) effectively modularize the registration logic and improve code maintainability. The use of structured bindings with getIDsList is clean and modern.


199-200: Good API design with optional fill pattern parameters

The addition of optional variableFillPattern parameters with nullptr defaults maintains backward compatibility while enabling new functionality. This is a clean way to extend the API.

Also applies to: 217-217, 244-244, 254-254


75-83:

Details

❓ Verification inconclusive

Verify the hardcoded overlap width parameter

The createSchedule call uses 0 as the second parameter (overlap width). Please verify this is intentional for border sum operations.


🏁 Script executed:

#!/bin/bash
# Description: Check other uses of createSchedule to understand the overlap parameter

# Search for other createSchedule calls with explicit overlap values
ast-grep --pattern 'createSchedule($_, $NUM, $_)'

# Check FieldBorderSumTransactionFactory usage patterns
rg -A 5 "FieldBorderSumTransactionFactory"

Length of output: 2071


Verify overlap width for PatchFieldBorderSum schedule

The new createSchedule(level, 0, …) invocation hard-codes the overlap width to 0. In other refinement schedules we typically pass the ghost-cell width or rely on the default overload. Please double-check that a zero overlap is intentional for the border-sum transaction (and, if so, consider documenting it or using a named constant for clarity).

• File: src/amr/messengers/refiner.hpp
Lines 75–83: algo->createSchedule(level, 0, …)

src/amr/messengers/refiner_pool.hpp (2)

31-39: Good practice with explicit special member functions

Explicitly defining the constructor, virtual destructor, deleted copy constructor, and defaulted move constructor follows the Rule of Five and prevents unintended object slicing or copying.


186-191: Excellent error handling for duplicate keys

The addition of runtime exceptions for duplicate key registration prevents silent failures and provides clear error messages. This is good defensive programming.

Also applies to: 239-241, 265-268

@PHAREHUB PHAREHUB deleted a comment from coderabbitai bot Jun 10, 2025
@PHAREHUB PHAREHUB deleted a comment from coderabbitai bot Jun 10, 2025
@PHAREHUB PHAREHUB deleted a comment from coderabbitai bot Jun 10, 2025
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (5)
src/core/data/field/field_box.hpp (1)

61-68: ⚠️ Potential issue

Add size compatibility check in operate_on_fields.

The function assumes dst and src boxes have the same size but doesn't verify this, which could lead to undefined behavior if they differ.

 template<typename Operator>
 void operate_on_fields(auto& dst, auto const& src)
 {
+    assert(dst.lcl_box.size() == src.lcl_box.size());
     auto src_it = src.lcl_box.begin();
     auto dst_it = dst.lcl_box.begin();
     for (; dst_it != dst.lcl_box.end(); ++src_it, ++dst_it)
         Operator{dst.field(*dst_it)}(src.field(*src_it));
 }
src/amr/resources_manager/resources_manager.hpp (1)

323-331: Consider improving error handling and method naming.

The new getIDsList method has several areas for improvement:

  1. Generic error message: The throw std::runtime_error("bad key") provides minimal debugging information. Consider including the problematic key in the error message.

  2. Method naming: getIDsList is redundant since it returns an array, not a list. Consider renaming to getIDs for consistency with the existing API.

  3. Exception performance: Throwing exceptions in a tight loop could impact performance if multiple keys are invalid.

-        auto getIDsList(auto&&... keys) const
+        template<typename... Keys>
+        auto getIDs(Keys&&... keys) const
         {
             auto const Fn = [&](auto& key) {
                 if (auto const id = getID(key))
                     return *id;
-                throw std::runtime_error("bad key");
+                throw std::runtime_error("Invalid resource key: " + std::string(key));
             };
             return std::array{Fn(keys)...};
         }
src/amr/data/field/field_variable_fill_pattern.hpp (1)

115-124: Add validation for the primal field assumption.

The comment states "ASSUMED ALL PRIMAL!" but there's no enforcement of this assumption. Consider adding validation.

Add a static assertion or runtime check to ensure the grid layout is indeed all primal:

 template<typename Gridlayout_t> // ASSUMED ALL PRIMAL!
 class FieldGhostInterpOverlapFillPattern : public SAMRAI::xfer::VariableFillPattern
 {
     std::size_t constexpr static dim = Gridlayout_t::dimension;
     using FieldGeometry_t            = FieldGeometryBase<dim>;
+    
+    // Validate the primal assumption
+    static_assert(/* Add appropriate check for primal layout */);
 
 public:
src/amr/data/field/field_data.hpp (2)

227-228: Improve rotation error handling.

Instead of silently returning when rotation is detected, the code should throw an exception for consistency with other error cases.

-            if (transformation.getRotation() != NO_ROTATE)
-                return; // throw, we don't do rotations in phare....
+            if (transformation.getRotation() != NO_ROTATE)
+                throw std::runtime_error("Rotations are not supported in PHARE");

271-272: Fix inconsistent rotation handling.

This rotation check also silently returns instead of throwing.

-            if (fieldOverlap.getTransformation().getRotation() != NO_ROTATE)
-                return;
+            if (fieldOverlap.getTransformation().getRotation() != NO_ROTATE)
+                throw std::runtime_error("Rotations are not supported in PHARE");
🧹 Nitpick comments (1)
src/amr/messengers/refiner.hpp (1)

274-311: Consider improving template parameter clarity for better maintainability.

While the helper functions correctly implement the registration logic and support method chaining, the extensive use of auto parameters may impact code readability and debugging experience.

Consider making template parameters more explicit for better error messages and code clarity:

-    auto& register_resource(auto& rm, auto& dst, auto& src, auto& scratch, auto&&... args)
+    template<typename ResourceManager, typename DstType, typename SrcType, typename ScratchType, typename... Args>
+    auto& register_resource(ResourceManager& rm, DstType& dst, SrcType& src, ScratchType& scratch, Args&&... args)

This would improve:

  • Compiler error message clarity
  • IDE code completion and navigation
  • Code documentation and understanding

However, the current implementation is functionally correct and the auto usage follows modern C++ patterns for generic programming.

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6f47b98 and e08d0bc.

📒 Files selected for processing (43)
  • src/amr/data/field/field_data.hpp (10 hunks)
  • src/amr/data/field/field_variable_fill_pattern.hpp (5 hunks)
  • src/amr/data/field/refine/field_refine_operator.hpp (2 hunks)
  • src/amr/data/particles/particles_data.hpp (9 hunks)
  • src/amr/data/particles/particles_variable_fill_pattern.hpp (1 hunks)
  • src/amr/level_initializer/hybrid_level_initializer.hpp (2 hunks)
  • src/amr/messengers/communicator.hpp (1 hunks)
  • src/amr/messengers/field_sum_transaction.hpp (1 hunks)
  • src/amr/messengers/hybrid_hybrid_messenger_strategy.hpp (15 hunks)
  • src/amr/messengers/hybrid_messenger.hpp (2 hunks)
  • src/amr/messengers/hybrid_messenger_info.hpp (1 hunks)
  • src/amr/messengers/hybrid_messenger_strategy.hpp (2 hunks)
  • src/amr/messengers/mhd_hybrid_messenger_strategy.hpp (4 hunks)
  • src/amr/messengers/refiner.hpp (8 hunks)
  • src/amr/messengers/refiner_pool.hpp (5 hunks)
  • src/amr/physical_models/hybrid_model.hpp (3 hunks)
  • src/amr/resources_manager/amr_utils.cpp (1 hunks)
  • src/amr/resources_manager/amr_utils.hpp (5 hunks)
  • src/amr/resources_manager/resources_guards.hpp (2 hunks)
  • src/amr/resources_manager/resources_manager.hpp (5 hunks)
  • src/amr/resources_manager/resources_manager_utilities.hpp (0 hunks)
  • src/amr/solvers/solver_ppc.hpp (8 hunks)
  • src/amr/utilities/box/amr_box.hpp (2 hunks)
  • src/core/data/field/field_box.hpp (1 hunks)
  • src/core/data/grid/grid.hpp (2 hunks)
  • src/core/data/grid/gridlayout.hpp (2 hunks)
  • src/core/data/ions/ion_population/ion_population.hpp (1 hunks)
  • src/core/data/ions/ions.hpp (2 hunks)
  • src/core/data/particles/particle_array.hpp (2 hunks)
  • src/core/numerics/ion_updater/ion_updater.hpp (7 hunks)
  • src/core/numerics/pusher/pusher.hpp (1 hunks)
  • src/core/utilities/box/box.hpp (5 hunks)
  • src/core/utilities/cellmap.hpp (2 hunks)
  • src/core/utilities/point/point.hpp (3 hunks)
  • src/core/utilities/types.hpp (2 hunks)
  • tests/amr/data/field/refine/test_field_refine.cpp (1 hunks)
  • tests/amr/messengers/test_messengers.cpp (2 hunks)
  • tests/amr/resources_manager/test_resources_manager.cpp (2 hunks)
  • tests/core/numerics/ion_updater/test_updater.cpp (8 hunks)
  • tests/simulator/advance/test_particles_advance_1d.py (0 hunks)
  • tests/simulator/advance/test_particles_advance_2d.py (0 hunks)
  • tests/simulator/initialize/test_particles_init_1d.py (0 hunks)
  • tests/simulator/initialize/test_particles_init_2d.py (1 hunks)
💤 Files with no reviewable changes (4)
  • src/amr/resources_manager/resources_manager_utilities.hpp
  • tests/simulator/initialize/test_particles_init_1d.py
  • tests/simulator/advance/test_particles_advance_2d.py
  • tests/simulator/advance/test_particles_advance_1d.py
🚧 Files skipped from review as they are similar to previous changes (28)
  • src/core/data/ions/ions.hpp
  • src/core/data/ions/ion_population/ion_population.hpp
  • tests/amr/messengers/test_messengers.cpp
  • src/core/numerics/pusher/pusher.hpp
  • src/amr/messengers/communicator.hpp
  • tests/simulator/initialize/test_particles_init_2d.py
  • src/amr/resources_manager/amr_utils.cpp
  • tests/amr/data/field/refine/test_field_refine.cpp
  • src/core/utilities/cellmap.hpp
  • src/amr/data/field/refine/field_refine_operator.hpp
  • src/amr/messengers/hybrid_messenger_info.hpp
  • src/amr/messengers/mhd_hybrid_messenger_strategy.hpp
  • src/amr/level_initializer/hybrid_level_initializer.hpp
  • src/core/data/grid/grid.hpp
  • src/core/utilities/types.hpp
  • src/core/data/particles/particle_array.hpp
  • src/amr/resources_manager/amr_utils.hpp
  • src/amr/messengers/hybrid_messenger_strategy.hpp
  • src/amr/physical_models/hybrid_model.hpp
  • src/amr/messengers/hybrid_messenger.hpp
  • src/amr/data/particles/particles_variable_fill_pattern.hpp
  • src/core/data/grid/gridlayout.hpp
  • src/core/utilities/point/point.hpp
  • src/amr/utilities/box/amr_box.hpp
  • src/amr/messengers/field_sum_transaction.hpp
  • src/core/utilities/box/box.hpp
  • src/amr/messengers/hybrid_hybrid_messenger_strategy.hpp
  • src/amr/messengers/refiner_pool.hpp
🧰 Additional context used
📓 Path-based instructions (1)
`**/*.hpp`: Review the C++ code, point out issues relative to principles of clean code, expressiveness, and performance.

**/*.hpp: Review the C++ code, point out issues relative to principles of clean code, expressiveness, and performance.

  • src/amr/resources_manager/resources_guards.hpp
  • src/amr/resources_manager/resources_manager.hpp
  • src/core/data/field/field_box.hpp
  • src/amr/data/particles/particles_data.hpp
  • src/amr/data/field/field_variable_fill_pattern.hpp
  • src/amr/solvers/solver_ppc.hpp
  • src/core/numerics/ion_updater/ion_updater.hpp
  • src/amr/messengers/refiner.hpp
  • src/amr/data/field/field_data.hpp
🧬 Code Graph Analysis (2)
src/amr/solvers/solver_ppc.hpp (5)
src/amr/messengers/hybrid_messenger_strategy.hpp (4)
  • hierarchy (52-53)
  • hierarchy (56-59)
  • level (116-116)
  • patch (33-33)
src/amr/messengers/hybrid_messenger.hpp (8)
  • hierarchy (109-113)
  • hierarchy (109-110)
  • hierarchy (120-126)
  • hierarchy (120-123)
  • level (188-188)
  • level (188-188)
  • patch (81-84)
  • patch (81-81)
src/amr/messengers/hybrid_hybrid_messenger_strategy.hpp (14)
  • hierarchy (151-188)
  • hierarchy (151-152)
  • hierarchy (196-249)
  • hierarchy (196-199)
  • hierarchy (810-993)
  • hierarchy (810-811)
  • level (470-495)
  • level (470-473)
  • level (600-612)
  • level (600-600)
  • level (747-762)
  • level (747-747)
  • patch (115-122)
  • patch (115-115)
src/amr/multiphysics_integrator.hpp (6)
  • hierarchy (301-376)
  • hierarchy (301-306)
  • hierarchy (380-409)
  • hierarchy (381-382)
  • level (500-551)
  • level (500-503)
src/amr/resources_manager/amr_utils.hpp (6)
  • to_string (213-218)
  • to_string (213-213)
  • layoutFromPatch (137-189)
  • layoutFromPatch (137-137)
  • makeNonLevelGhostBoxFor (194-211)
  • makeNonLevelGhostBoxFor (194-195)
src/amr/data/field/field_data.hpp (4)
src/amr/data/field/field_geometry.hpp (3)
  • box (155-258)
  • box (155-156)
  • box (267-276)
src/amr/messengers/field_sum_transaction.hpp (5)
  • stream (60-60)
  • stream (62-62)
  • stream (66-66)
  • unpackStream (146-156)
  • unpackStream (146-146)
src/amr/resources_manager/amr_utils.hpp (5)
  • AMRToLocal (47-48)
  • AMRToLocal (55-56)
  • AMRToLocal (64-64)
  • AMRToLocal (79-92)
  • AMRToLocal (79-80)
src/core/data/field/field_box.hpp (2)
  • operate_on_fields (62-68)
  • operate_on_fields (62-62)
⏰ Context from checks skipped due to timeout of 90000ms (7)
  • GitHub Check: Analyze (python)
  • GitHub Check: Analyze (cpp)
  • GitHub Check: build (ubuntu-latest, gcc)
  • GitHub Check: build (ubuntu-latest, clang)
  • GitHub Check: build (macos-14)
  • GitHub Check: build (macos-13)
  • GitHub Check: build (macos-latest)
🔇 Additional comments (37)
src/amr/resources_manager/resources_guards.hpp (2)

45-48: LGTM! Clean simplification using fold expressions.

The constructor now uses a concise fold expression to set resources directly, eliminating the need for tag structs and improving readability.


56-58: LGTM! Simplified destructor implementation.

The destructor correctly calls unsetResources_ on each user using a fold expression, which is cleaner than the previous tag-based approach.

tests/amr/resources_manager/test_resources_manager.cpp (2)

213-235: LGTM! Well-structured test for enumerate functionality.

The test properly validates the new enumerate method by checking resource user states during and after enumeration. The lambda-based approach maintains consistency with existing test patterns.


270-271: LGTM! Proper test registration.

The new test is correctly registered in the typed test suite alongside the existing test.

tests/core/numerics/ion_updater/test_updater.cpp (4)

358-367: LGTM! Clean boxing abstraction integration.

The addition of Boxing_t type alias and the boxing member properly encapsulates the particle selection logic, making the test more aligned with the new architecture.


493-498: LGTM! Updated assertions reflect new particle handling.

The assertions correctly reflect the new approach where patch ghost particles are not manually created (size 0), while domain and level ghost particles are properly present.


733-734: LGTM! Consistent boxing usage in test calls.

All ionUpdater.updatePopulations calls have been correctly updated to use the boxing parameter instead of the direct layout, maintaining consistency with the new API.

Also applies to: 779-780, 804-805, 824-825, 842-843


663-663: LGTM! Updated expectation for patch ghost particles.

The expectation correctly reflects that patch ghost particles are no longer manually created in the test fixture.

src/core/data/field/field_box.hpp (2)

16-58: LGTM! Well-designed field abstraction.

The FieldBox template class provides a clean, dimension-agnostic interface for field operations. The multiple constructor overloads handle different box types appropriately, and the template parameter design is flexible.


72-88: LGTM! Well-implemented template methods.

The set_from and append_to methods provide clean interfaces for data transfer operations. The use of iterators and the template operator pattern is appropriate.

src/core/numerics/ion_updater/ion_updater.hpp (5)

59-61: LGTM! Clean abstraction with boxing template parameter.

The refactoring to template key methods on Boxing_t provides better separation of concerns and makes the updater more flexible while maintaining type safety.

Also applies to: 75-76, 78-79, 90-93


119-158: LGTM! Well-designed particle selection abstraction.

The UpdaterSelectionBoxing struct effectively encapsulates particle selection logic with appropriate lambda captures and clear predicates. The design separates particle partitioning concerns from the updater logic.


176-185: LGTM! Simplified domain particle handling.

The updated logic uses local copies and the boxing selectors effectively. The approach of pushing particles and accumulating those in the non-level ghost box is clean and efficient.


241-252: LGTM! Improved particle array management.

The logic correctly handles domain particle pushing, identifies particles that become ghosts, copies non-level ghosts to patch ghost arrays, and properly erases ghost particles from the domain array.


254-271: LGTM! Clean level ghost particle handling.

The level ghost particle processing correctly handles pushing, exports particles entering the domain, and interpolates both domain and patch ghost particles appropriately.

src/amr/resources_manager/resources_manager.hpp (3)

336-387: Well-designed RAII iterator pattern for patch-level resource management.

The enumerate method and LevelLooper struct implement a clean iterator pattern with automatic resource management. The design ensures resources are properly set when accessing patches and unset when the iterator is destroyed, preventing resource leaks.


465-478: Clean refactoring of sub-resource handling logic.

The handle_sub_resources static method effectively consolidates the duplicate logic for handling both runtime and compile-time sub-resource lists, improving code maintainability.


482-509: Effective use of the helper function to reduce code duplication.

The refactored setResources_ and unsetResources_ methods now cleanly delegate sub-resource handling to the handle_sub_resources helper, improving code clarity and maintainability.

src/amr/data/field/field_variable_fill_pattern.hpp (1)

33-68: Good improvements to the FieldFillPattern class.

The changes improve the class by:

  • Making the constructor more flexible with a defaulted parameter
  • Adding an assertion to validate expected behavior
  • Using a static string for the pattern name, which is more efficient
src/amr/data/particles/particles_data.hpp (5)

244-260: Dynamic dispatch pattern properly handles multiple overlap types.

The copy method correctly implements dynamic dispatch based on overlap type, handling both ParticlesDomainOverlap and CellOverlap cases with appropriate error handling for unknown types.


276-295: Correct stream size calculation for new overlap type.

The method properly calculates the data stream size for ParticlesDomainOverlap by counting patch ghost particles in the transformed overlap boxes.


342-356: Consistent implementation of dynamic dispatch in packStream.

The method follows the same clean dispatch pattern as the copy method, maintaining consistency across the codebase.


700-721: Well-implemented particle transfer with coordinate transformation.

The copy_from_ghost method correctly exports particles from patch ghost to domain particles, applying the necessary coordinate transformations through the offseter function.


760-773: Simple and correct unpacking implementation.

The unpack_from_ghost method correctly unpacks particles directly into the domain array, as the particles are already in the destination coordinate space.

src/amr/solvers/solver_ppc.hpp (4)

99-104: Proper cleanup of cached data on regrid.

The onRegrid method correctly clears the boxing cache and resets the ion updater when the grid structure changes, ensuring stale data is not used.


153-168: Well-implemented boxing initialization with proper error handling.

The make_boxes method correctly initializes boxing data for all patches in a level, with proper error handling for map insertion failures. The structured binding properly uses the iterator variable, addressing the previous unused variable issue.


170-176: Clean helper method for level setup.

The setup_level method provides a clean interface for ensuring boxing data is initialized before use, following good defensive programming practices.


429-443: Proper integration of boxing mechanism and border filling.

The modified moveIons_ method correctly:

  1. Uses the cached boxing data for ion updates
  2. Adds necessary border filling operations for flux and density after ion movement

This aligns well with the new ghost particle handling approach.

src/amr/data/field/field_data.hpp (2)

230-250: Excellent refactoring to generic operator-based field operations.

The refactoring to use FieldBox with generic operators is a significant improvement:

  • Eliminates dimension-specific code duplication
  • Enables easy extension with new operators (e.g., SetEqualOp, PlusEqualOp)
  • Improves code clarity and maintainability

This is a well-designed abstraction that follows modern C++ best practices.

Also applies to: 340-357


323-325: Clean implementation of summation operations.

The new sum and unpackStreamAndSum methods elegantly reuse the existing generic infrastructure by simply changing the operator to PlusEqualOp. This demonstrates the flexibility and power of the operator-based design.

Also applies to: 449-472

src/amr/messengers/refiner.hpp (7)

7-11: LGTM: Appropriate includes added for new functionality.

The new includes support the enhanced functionality: field_sum_transaction.hpp for border sum operations, and standard library headers for tuple destructuring and exception handling.


22-24: LGTM: Enum values updated to reflect new refiner types.

The addition of PatchFieldBorderSum and ExteriorGhostParticles aligns with the refactoring objectives and new transaction mechanisms.


75-83: LGTM: Consistent implementation pattern for new refiner type.

The PatchFieldBorderSum conditional block follows the established pattern and correctly uses the FieldBorderSumTransactionFactory with the appropriate template parameter.


128-132: LGTM: Simple and consistent implementation for exterior ghost particles.

The implementation follows the same pattern as PatchGhostField and is appropriate for the ExteriorGhostParticles refiner type.


199-200: LGTM: Optional fill pattern support added consistently.

The addition of the optional VariableFillPattern parameter with nullptr default maintains backward compatibility while enabling new functionality.

Also applies to: 216-218


204-206: LGTM: Constructor refactored to use helper functions.

The replacement of inline logic with dedicated helper functions improves code maintainability and reduces duplication.

Also applies to: 221-223


241-258: LGTM: Consistent parameter naming and implementation.

The constructor updates maintain consistency with other overloads and correctly handle the optional fill pattern parameter.

@PHAREHUB PHAREHUB deleted a comment from coderabbitai bot Jun 10, 2025
@PHAREHUB PHAREHUB deleted a comment from coderabbitai bot Jun 10, 2025
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

♻️ Duplicate comments (2)
src/amr/data/field/field_data.hpp (2)

227-228: Good improvement in error handling.

The rotation check now properly throws an exception instead of silently returning, addressing the previous review feedback.


271-272: Consistent error handling for rotations.

This rotation check also properly throws an exception, maintaining consistency with the fix in the packStream method.

🧹 Nitpick comments (4)
src/core/numerics/ion_updater/ion_updater.hpp (4)

27-27: Remove unused type alias.

The This type alias is defined but never used in the class.

-    using This = IonUpdater<Ions, Electromag, GridLayout>;

188-199: Consider extracting lambda into a named function.

The pushAndAccumulateGhosts lambda is complex and could benefit from being extracted into a separate method for better readability and testability.

+    template<typename Boxing_t>
+    void pushAndAccumulateGhosts_(auto const& inputArray, auto& pop, 
+                                  Electromag const& em, Boxing_t const& boxing) {
+        tmp_particles_ = inputArray; // work on local copy
+        auto outRange = makeIndexRange(tmp_particles_);
+        auto enteredInDomain = pusher_->move(outRange, outRange, em, pop.mass(), interpolator_,
+                                             boxing.layout, boxing.inGhostBox, boxing.inDomainBox);
+        interpolator_(enteredInDomain, pop.density(), pop.flux(), boxing.layout);
+    }

-        auto pushAndAccumulateGhosts = [&](auto const& inputArray) {
-            tmp_particles_ = inputArray; // work on local copy
-            auto outRange = makeIndexRange(tmp_particles_);
-            auto enteredInDomain = pusher_->move(outRange, outRange, em, pop.mass(), interpolator_,
-                                                 layout, boxing.inGhostBox, boxing.inDomainBox);
-            interpolator_(enteredInDomain, pop.density(), pop.flux(), layout);
-        };

         if (pop.levelGhostParticles().size())
-            pushAndAccumulateGhosts(pop.levelGhostParticles());
+            pushAndAccumulateGhosts_(pop.levelGhostParticles(), pop, em, boxing);

201-210: Address the TODO comment.

The TODO comment indicates uncertainty about the implementation logic. This should be resolved before merging to ensure correctness.

The comment suggests there might be issues with how particle contributions are handled for different ghost layer types. Would you like me to help clarify the logic or create a tracking issue for this?


243-250: Potential performance issue with vector operations.

The code performs multiple vector operations (partition, reserve, copy, erase) that could be optimized. Consider if these operations can be combined or if a more efficient data structure could be used.

Consider using a single pass algorithm or custom container operations to reduce the number of vector manipulations.

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e08d0bc and 4af6155.

📒 Files selected for processing (8)
  • src/amr/data/field/field_data.hpp (10 hunks)
  • src/amr/messengers/mhd_hybrid_messenger_strategy.hpp (4 hunks)
  • src/amr/utilities/box/amr_box.hpp (2 hunks)
  • src/core/data/field/field_box.hpp (1 hunks)
  • src/core/data/grid/gridlayout.hpp (2 hunks)
  • src/core/numerics/ion_updater/ion_updater.hpp (7 hunks)
  • src/core/utilities/box/box.hpp (5 hunks)
  • src/core/utilities/point/point.hpp (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (6)
  • src/amr/messengers/mhd_hybrid_messenger_strategy.hpp
  • src/amr/utilities/box/amr_box.hpp
  • src/core/data/grid/gridlayout.hpp
  • src/core/utilities/point/point.hpp
  • src/core/data/field/field_box.hpp
  • src/core/utilities/box/box.hpp
🧰 Additional context used
📓 Path-based instructions (1)
`**/*.hpp`: Review the C++ code, point out issues relative to principles of clean code, expressiveness, and performance.

**/*.hpp: Review the C++ code, point out issues relative to principles of clean code, expressiveness, and performance.

  • src/core/numerics/ion_updater/ion_updater.hpp
  • src/amr/data/field/field_data.hpp
⏰ Context from checks skipped due to timeout of 90000ms (7)
  • GitHub Check: build (macos-14)
  • GitHub Check: build (macos-latest)
  • GitHub Check: build (macos-13)
  • GitHub Check: build (ubuntu-latest, clang)
  • GitHub Check: build (ubuntu-latest, gcc)
  • GitHub Check: Analyze (cpp)
  • GitHub Check: Analyze (python)
🔇 Additional comments (4)
src/core/numerics/ion_updater/ion_updater.hpp (2)

119-157: Well-designed particle selection abstraction.

The UpdaterSelectionBoxing struct effectively encapsulates particle selection logic and provides clear, reusable selectors. The use of lambda copy captures ensures proper detachment from class references during copy construction.


175-183:

Details

❓ Verification inconclusive

Verify particle copy semantics and performance.

The domain particles are copied locally (tmp_particles_ = pop.domainParticles()), which could be expensive for large particle arrays. Consider if this copy is necessary or if working with references/views would be more efficient.


🏁 Script executed:

#!/bin/bash
# Description: Check if there are alternative approaches to particle copying in the codebase
# Expected: Find patterns of particle array manipulation that might avoid copying

rg -A 5 -B 5 "domainParticles\(\)" --type cpp

Length of output: 21496


Evaluate necessity of deep-copying domain particles for each update

The call

auto& domain = (tmp_particles_ = pop.domainParticles());

per population causes a full copy of the ParticleArray on every invocation of the updater. This may be expensive for large domains.

• Confirm whether pusher_->move(...) actually mutates its input container. If it does not, you can avoid the copy by working directly on pop.domainParticles() via a non-owning view (e.g. std::span or your index‐range type).
• If mutation is required, consider reusing a pre-allocated tmp_particles_ buffer (reserve once outside the loop) to eliminate repeated allocations and copies.

Location:

  • src/core/numerics/ion_updater/ion_updater.hpp around line 175
src/amr/data/field/field_data.hpp (2)

263-292: Well-designed generic unpackStream method.

The templated approach with operator support provides excellent flexibility for different operation types (assignment vs. summation). The design is clean and follows the single responsibility principle.


340-357: Excellent use of FieldBox abstraction.

The refactored copy method using core::FieldBox provides a much cleaner interface and better encapsulates the field operations. The generic operator support enhances reusability.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
pyphare/pyphare/pharesee/hierarchy/fromsim.py (2)

87-92: Update outdated comments referencing patchGhost.

The comments still reference patchGhost processing logic, but the code below (line 93) no longer processes patchGhost particles. Consider updating these comments to reflect the current implementation.

-            # ok now let's add the patchGhost if present
-            # note that patchGhost patches may not be the same list as the
-            # domain patches... since not all patches may not have patchGhost while they do have
-            # domain... while looping on the patchGhost items, we need to search in
-            # the already created patches which one to which add the patchGhost particles
+            # ok now let's add the levelGhost if present
+            # note that levelGhost patches may not be the same list as the
+            # domain patches... since not all patches may not have levelGhost while they do have
+            # domain... while looping on the levelGhost items, we need to search in
+            # the already created patches which one to which add the levelGhost particles

100-115: Update variable names for clarity.

The variable patchGhost_part (line 100) and related comments still reference patchGhost terminology, but this code now only processes levelGhost particles.

-                        patchGhost_part = Particles(
+                        levelGhost_part = Particles(
                             icells=np.asarray(dwpatch.data.iCell),
                             deltas=np.asarray(dwpatch.data.delta),
                             v=v,
                             weights=np.asarray(dwpatch.data.weight),
                             charges=np.asarray(dwpatch.data.charge),
                         )

                         box = Box(dwpatch.lower, dwpatch.upper)

-                        # now search which of the already created patches has the same box
-                        # once found we add the new particles to the ones already present
+                        # search for the patch with matching box and add levelGhost particles
                         
                         patch = [p for p in patches[ilvl] if p.box == box][0]
                         patch.patch_datas[pop + "_particles"].dataset.add(
-                            patchGhost_part
+                            levelGhost_part
                         )
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4af6155 and d7ccbef.

📒 Files selected for processing (16)
  • pyphare/pyphare/pharein/diagnostics.py (1 hunks)
  • pyphare/pyphare/pharesee/hierarchy/fromh5.py (1 hunks)
  • pyphare/pyphare/pharesee/hierarchy/fromsim.py (1 hunks)
  • pyphare/pyphare/pharesee/hierarchy/hierarchy_utils.py (0 hunks)
  • pyphare/pyphare/pharesee/run/run.py (1 hunks)
  • src/diagnostic/detail/types/fluid.hpp (2 hunks)
  • src/diagnostic/detail/types/particle.hpp (1 hunks)
  • src/python3/patch_level.hpp (0 hunks)
  • tests/diagnostic/__init__.py (1 hunks)
  • tests/diagnostic/test_diagnostics.hpp (1 hunks)
  • tests/diagnostic/test_diagnostics.ipp (1 hunks)
  • tests/functional/conservation/conserv.py (1 hunks)
  • tests/simulator/initialize/test_particles_init_1d.py (0 hunks)
  • tests/simulator/initialize/test_particles_init_2d.py (1 hunks)
  • tests/simulator/test_advance.py (1 hunks)
  • tests/simulator/test_initialization.py (1 hunks)
💤 Files with no reviewable changes (3)
  • src/python3/patch_level.hpp
  • tests/simulator/initialize/test_particles_init_1d.py
  • pyphare/pyphare/pharesee/hierarchy/hierarchy_utils.py
✅ Files skipped from review due to trivial changes (3)
  • tests/diagnostic/init.py
  • pyphare/pyphare/pharesee/hierarchy/fromh5.py
  • src/diagnostic/detail/types/particle.hpp
🧰 Additional context used
📓 Path-based instructions (1)
`**/*.hpp`: Review the C++ code, point out issues relative to principles of clean code, expressiveness, and performance.

**/*.hpp: Review the C++ code, point out issues relative to principles of clean code, expressiveness, and performance.

  • tests/diagnostic/test_diagnostics.hpp
  • src/diagnostic/detail/types/fluid.hpp
🧬 Code Graph Analysis (1)
tests/simulator/initialize/test_particles_init_2d.py (2)
tests/simulator/initialize/test_fields_init_2d.py (1)
  • Initialization2DTest (22-43)
tests/simulator/test_initialization.py (1)
  • InitializationTest (28-722)
⏰ Context from checks skipped due to timeout of 90000ms (7)
  • GitHub Check: build (macos-13)
  • GitHub Check: build (macos-14)
  • GitHub Check: build (macos-latest)
  • GitHub Check: build (ubuntu-latest, clang)
  • GitHub Check: build (ubuntu-latest, gcc)
  • GitHub Check: Analyze (python)
  • GitHub Check: Analyze (cpp)
🔇 Additional comments (12)
tests/functional/conservation/conserv.py (1)

87-87: LGTM: Consistent with patchGhost removal.

The removal of "patchGhost" from particle diagnostics aligns with the broader codebase refactoring to eliminate patch ghost particle handling.

tests/diagnostic/test_diagnostics.ipp (1)

68-68: LGTM: Clean removal of patchGhost diagnostics.

The removal of patchGhost diagnostic dictionary additions is consistent with the broader refactoring. The code maintains clean structure and proper syntax.

pyphare/pyphare/pharesee/hierarchy/fromsim.py (1)

93-93: LGTM: Correct implementation of levelGhost-only processing.

The change to only iterate over "levelGhost" is consistent with the broader patchGhost removal refactoring.

pyphare/pyphare/pharein/diagnostics.py (1)

306-306: LGTM: Correct removal of patchGhost from valid quantities.

Removing "patchGhost" from the particle_quantities list ensures validation consistency with the broader patchGhost removal refactoring.

tests/diagnostic/test_diagnostics.hpp (2)

229-229: LGTM: Correct adjustment of expected file count.

Reducing expectedPopAttrFiles from 5 to 4 correctly reflects the removal of patchGhost files from the population attribute files, maintaining test accuracy.


246-250:

Details

✅ Verification successful

Verify the math: expectedPopAttrFiles calculation.

With patchGhost removed, each population now contributes 4 files: domain, levelGhost, density, and flux. For 2 populations, this gives 2 × 4 = 8 files. However, the expectation check at line 287 uses expectedPopNbr * expectedPopAttrFiles which would be 2 × 4 = 8. Please verify this matches the actual number of population-specific files being created.


🏁 Script executed:

#!/bin/bash
# Description: Verify the number of h5FileTypes entries that contain "/ions/pop/" 
# Expected: Should match expectedPopNbr * expectedPopAttrFiles = 2 * 4 = 8

echo "Searching for population-specific h5FileTypes in the test code..."
rg -A 10 -B 5 "h5FileTypes.*emplace_back.*ions/pop" tests/diagnostic/test_diagnostics.hpp

Length of output: 232


🏁 Script executed:

#!/bin/bash
# List all h5FileTypes.emplace_back calls with their line numbers
echo "=== All emplace_back calls in test_diagnostics.hpp ==="
rg -n "h5FileTypes.emplace_back" tests/diagnostic/test_diagnostics.hpp

# Count total emplace_back occurrences in this file
echo
echo "=== Total emplace_back count ==="
rg -c "h5FileTypes.emplace_back" tests/diagnostic/test_diagnostics.hpp

# Show context around ionsPopPath to isolate population loop
echo
echo "=== Context around ionsPopPath ==="
rg -n -A 5 -B 2 "ionsPopPath" tests/diagnostic/test_diagnostics.hpp

Length of output: 2042


No action required: population-specific file count is correct

The constant expectedPopAttrFiles is set to 4 (lines 229–231), matching the four h5FileTypes.emplace_back calls (domain, levelGhost, density, flux) per population (lines 246–249). At runtime this loop runs expectedPopNbr times, so
expectedPopNbr × expectedPopAttrFiles = 2 × 4 = 8
correctly reflects the total population-specific files created.

– No changes needed.

tests/simulator/test_advance.py (1)

170-173: LGTM: Consistent removal of patchGhost particle diagnostics.

The removal of "patchGhost" from the particle diagnostics quantities is consistent with the broader refactor to eliminate patchGhost particle support throughout the codebase.

pyphare/pyphare/pharesee/run/run.py (1)

205-205: LGTM: Consistent removal of patchGhost from mass attribute lookup.

The removal of "patchGhost" from the list of quantities in the GetMass method aligns with the systematic elimination of patchGhost particle support. The method will no longer attempt to read mass attributes from patchGhost particle files.

tests/simulator/test_initialization.py (1)

187-192: LGTM: Consistent removal of patchGhost particle diagnostics.

The removal of "patchGhost" from the particle diagnostics quantities list is consistent with the codebase-wide refactor to eliminate patchGhost particle support.

src/diagnostic/detail/types/fluid.hpp (2)

99-104: LGTM: Removal of patchGhost particles from momentum tensor computation.

The removal of patchGhostParts index range from the momentum tensor interpolation is consistent with the broader elimination of patchGhost particle support. The computation now only uses domain and level ghost particles, which should provide sufficient coverage.


124-129: LGTM: Consistent removal in population-specific momentum tensor computation.

The removal of patchGhostParts index range in the population-specific momentum tensor computation path maintains consistency with the changes in the total momentum tensor computation above.

tests/simulator/initialize/test_particles_init_2d.py (1)

26-26: LGTM: Bug fix - correcting class name to match test dimension.

The class name change from Initialization1DTest to Initialization2DTest correctly reflects that this file tests 2D particle initialization (ndim = 2, uses Box2D). This fixes the naming inconsistency.

std::shared_ptr<SAMRAI::hier::RefineOperator> const& refineOp, Key const& key,
std::shared_ptr<SAMRAI::xfer::VariableFillPattern> fillPattern)
{
auto const [it, success]

Check notice

Code scanning / CodeQL

Unused local variable

Variable it is not used.
std::shared_ptr<SAMRAI::hier::TimeInterpolateOperator> const& timeOp, std::string const& key,
std::shared_ptr<SAMRAI::xfer::VariableFillPattern> fillPattern)
{
auto const [it, success] = refiners_.insert(

Check notice

Code scanning / CodeQL

Unused local variable

Variable it is not used.
auto& levelBoxing = boxing[lvlNbr]; // creates if missing

for (auto const& patch : level)
if (auto [it, suc] = levelBoxing.try_emplace(

Check notice

Code scanning / CodeQL

Unused local variable

Variable it is not used.
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (2)
src/amr/data/particles/particles_data.hpp (1)

250-260: Consider refactoring dynamic dispatch pattern for consistency.

The dynamic dispatch logic works correctly but could benefit from a more systematic approach. As noted in previous comments, consider refactoring this pattern similar to the pack method for better maintainability and consistency across the codebase.

 void copy(SAMRAI::hier::PatchData const& source,
           SAMRAI::hier::BoxOverlap const& overlap) override
 {
     auto& pSource = dynamic_cast<ParticlesData const&>(source);
-    
-    if (auto particleOverlap = dynamic_cast<ParticlesDomainOverlap const*>(&overlap))
-        copy_from_ghost(pSource, *particleOverlap);
-    
-    else if (auto pOverlap = dynamic_cast<SAMRAI::pdat::CellOverlap const*>(&overlap))
-        copy_from_cell_overlap(pSource, *pOverlap);
-    
-    else
-        throw std::runtime_error("Unknown overlap type");
+    
+    std::visit([&](auto&& overlap_impl) {
+        using T = std::decay_t<decltype(overlap_impl)>;
+        if constexpr (std::is_same_v<T, ParticlesDomainOverlap>)
+            copy_from_ghost(pSource, overlap_impl);
+        else if constexpr (std::is_same_v<T, SAMRAI::pdat::CellOverlap>)
+            copy_from_cell_overlap(pSource, overlap_impl);
+        else
+            static_assert(false, "Unknown overlap type");
+    }, overlap);
 }
src/amr/solvers/solver_ppc.hpp (1)

153-168: Fix unused variable warning from static analysis.

The static analysis correctly identifies that the iterator it from try_emplace is unused. Either use the iterator for additional operations or simplify the insertion check.

-        for (auto const& patch : level)
-            if (auto [it, suc] = levelBoxing.try_emplace(
-                    amr::to_string(patch->getGlobalId()),
-                    Boxing_t{amr::layoutFromPatch<GridLayout>(*patch),
-                             amr::makeNonLevelGhostBoxFor<GridLayout>(*patch, hierarchy)});
-                !suc)
-                throw std::runtime_error("boxing map insertion failure");
+        for (auto const& patch : level)
+        {
+            auto [_, success] = levelBoxing.try_emplace(
+                amr::to_string(patch->getGlobalId()),
+                Boxing_t{amr::layoutFromPatch<GridLayout>(*patch),
+                         amr::makeNonLevelGhostBoxFor<GridLayout>(*patch, hierarchy)});
+            if (!success)
+                throw std::runtime_error("boxing map insertion failure");
+        }
🧹 Nitpick comments (2)
src/core/numerics/moments/moments.hpp (1)

54-55: Good addition of explicit error handling.

The std::runtime_error provides clear feedback for unsupported deposit tags, which is better than undefined behavior. Consider using static_assert if the deposit tag types can be validated at compile time for better performance.

 else
-    throw std::runtime_error("unknown deposit tag");
+    static_assert(std::is_same_v<DepositTag, DomainDeposit> || 
+                  std::is_same_v<DepositTag, LevelGhostDeposit>, 
+                  "unknown deposit tag");
src/amr/solvers/solver_ppc.hpp (1)

179-180: Consider using numeric patch IDs for better performance.

The nested unordered_map structure is well-designed for organizing boxing data by level and patch. However, using string patch IDs (amr::to_string(patch->getGlobalId())) as map keys might have performance implications. Consider using numeric patch IDs directly if this structure is accessed frequently during simulation loops.

-std::unordered_map<int /*level*/, std::unordered_map<std::string /*patchid*/, Boxing_t>> boxing;
+std::unordered_map<int /*level*/, std::unordered_map<SAMRAI::tbox::GlobalId /*patchid*/, Boxing_t>> boxing;
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d7ccbef and 95f5a2d.

📒 Files selected for processing (8)
  • src/amr/data/particles/particles_data.hpp (14 hunks)
  • src/amr/data/particles/refine/particles_data_split.hpp (1 hunks)
  • src/amr/solvers/solver_ppc.hpp (9 hunks)
  • src/core/numerics/moments/moments.hpp (2 hunks)
  • tests/amr/data/particles/copy/test_particledata_copyNd.cpp (4 hunks)
  • tests/amr/data/particles/copy_overlap/test_particledata_copy_periodicNd.cpp (2 hunks)
  • tests/amr/data/particles/stream_pack/test_main.cpp (4 hunks)
  • tests/core/numerics/ion_updater/test_updater.cpp (8 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
`**/*.hpp`: Review the C++ code, point out issues relative to principles of clean code, expressiveness, and performance.

**/*.hpp: Review the C++ code, point out issues relative to principles of clean code, expressiveness, and performance.

  • src/core/numerics/moments/moments.hpp
  • src/amr/data/particles/refine/particles_data_split.hpp
  • src/amr/data/particles/particles_data.hpp
  • src/amr/solvers/solver_ppc.hpp
🧬 Code Graph Analysis (1)
tests/amr/data/particles/copy/test_particledata_copyNd.cpp (1)
src/core/utilities/types.hpp (2)
  • ConstArray (162-168)
  • ConstArray (162-162)
⏰ Context from checks skipped due to timeout of 90000ms (7)
  • GitHub Check: Analyze (python)
  • GitHub Check: Analyze (cpp)
  • GitHub Check: build (macos-latest)
  • GitHub Check: build (macos-14)
  • GitHub Check: build (macos-13)
  • GitHub Check: build (ubuntu-latest, clang)
  • GitHub Check: build (ubuntu-latest, gcc)
🔇 Additional comments (17)
tests/amr/data/particles/copy_overlap/test_particledata_copy_periodicNd.cpp (1)

114-142: LGTM: Consistent update to test expectations.

The test assertions have been systematically updated to verify particles in domainParticles instead of patchGhostParticles, which aligns with the broader refactoring to remove patch ghost particle handling. The test logic remains sound and all particle attribute checks are preserved.

tests/amr/data/particles/stream_pack/test_main.cpp (1)

122-267: LGTM: Systematic test update maintains integrity.

All test assertions have been consistently updated to verify domainParticles instead of patchGhostParticles. The particle streaming and packing test logic remains intact, and all particle attribute validations (velocity, cell index, delta, weight, charge) are preserved across all test functions.

src/core/numerics/moments/moments.hpp (1)

5-5: LGTM: Proper header inclusion for error handling.

Adding <stdexcept> header is correct for the std::runtime_error usage introduced in the function.

src/amr/data/particles/refine/particles_data_split.hpp (1)

175-241: LGTM: Simplified and cleaner particle refinement logic.

The removal of srcGhostParticles iteration simplifies the refinement process while preserving all the essential logic for particle splitting, position conversion to fine grid, and conditional copying based on splitType. The code is now more focused and easier to understand.

tests/core/numerics/ion_updater/test_updater.cpp (5)

358-358: Good use of type alias for readability.

The Boxing_t type alias improves code readability and makes the template instantiation more manageable.


367-367: Appropriate boxing initialization.

The boxing object is correctly initialized with the layout and a grown AMR box using the particle ghost count, which aligns with the new boxing-based particle selection approach.


493-498: Consistent test assertions with refactoring goals.

The assertions now correctly expect domain and level ghost particles to be present while expecting patch ghost particles to be absent (size 0), which aligns with the systematic removal of patch ghost particle handling.


731-731: Correct parameter change to boxing approach.

The function call correctly uses this->boxing instead of this->layout, which is consistent with the new boxing-based particle selection mechanism.


661-661: Updated test expectation reflects refactoring.

The expectation that patchGhostParticles() size equals 0 is correct given the systematic removal of patch ghost particle creation and management.

tests/amr/data/particles/copy/test_particledata_copyNd.cpp (3)

128-135: Good test isolation practice.

The explicit clearing of particle containers and verification of clean state between test runs is excellent practice. This ensures test independence and prevents state leakage between test cases.


206-207: Correctly updated expectations for architectural change.

The test expectations have been properly updated to reflect that particles copied during overlap operations now reside in domainParticles rather than patchGhostParticles. This aligns with the architectural shift described in the PR.


269-271: Consistent expectation updates across test cases.

These assertion updates are consistent with the broader architectural change and correctly verify the new behavior where transformed particles are stored in domainParticles.

src/amr/data/particles/particles_data.hpp (3)

695-770: Well-structured template implementations.

The template method implementations demonstrate good C++ practices:

  • Proper separation from class definition
  • Modern C++ features (structured bindings, auto)
  • Consistent error handling and logging
  • Clear variable naming and const correctness

707-715: Correct coordinate transformation implementation.

The coordinate offset handling is implemented correctly with proper forward and inverse transformations. The offseter lambda provides a clean encapsulation of the transformation logic that's reused consistently across different operations.


131-134:

Details

❓ Verification inconclusive

Verify that excluding patchGhostParticles from restart doesn't break functionality.

The patchGhostParticles are no longer being serialized during restart. Ensure this is intentional and that these particles can be properly reconstructed from neighbor patches upon restart without losing critical simulation state.


🏁 Script executed:

#!/bin/bash
# Check if patchGhostParticles are being reconstructed elsewhere after restart
rg -A 5 -B 5 "patchGhostParticles.*push_back\|patchGhostParticles.*insert\|patchGhostParticles.*export_particles"

Length of output: 115


🏁 Script executed:

#!/bin/bash
# Identify the particles_data.hpp file
file=$(fd particles_data.hpp -t f)
echo "Using file: $file"

# Display the serialization (putToRestart) and deserialization (getFromRestart) functions
echo "----- putToRestart -----"
sed -n '/putToRestart/,/}/p' "$file"

echo "----- getFromRestart -----"
sed -n '/getFromRestart/,/}/p' "$file"

# Search for any references to patchGhostParticles throughout the repo
echo "----- References to patchGhostParticles -----"
rg -n "patchGhostParticles" -C3

Length of output: 26634


🏁 Script executed:

#!/bin/bash
file=src/amr/data/particles/particles_data.hpp

echo "putParticles calls in putToRestart():"
grep -n "putParticles" "$file" | sed -n '131,140p'

echo
echo "getParticles calls in getFromRestart():"
grep -n "getParticles" "$file" | sed -n '140,200p'

Length of output: 396


Confirm transient nature of patchGhostParticles on restart

  • The calls to putParticles/getParticles now cover only domainParticles, levelGhostParticlesNew/Old, and omit patchGhostParticles.
  • Ensure that patchGhostParticles are meant to be ephemeral and that the ghost‐exchange or fill‐pattern machinery will reliably repopulate them immediately after a restart, before any code uses them.
  • If persistent state for patchGhostParticles is required across restarts, either reintroduce their serialization in putToRestart/getFromRestart or document and provide a reconstruction step in the restart workflow.
src/amr/solvers/solver_ppc.hpp (2)

435-436: Well-positioned border filling functionality.

The new fillFluxBorders and fillDensityBorders calls are properly positioned before particle and moment ghost filling. This ordering ensures that border data is updated before dependent operations, which should improve boundary condition accuracy.


99-103: Essential cleanup for AMR regridding.

The onRegrid() method properly cleans up state that becomes invalid when the grid structure changes. Clearing the boxing data and resetting the ion updater ensures that cached grid-dependent information is rebuilt correctly after regridding operations.

Comment on lines +65 to +67
// TYPED_TEST(AParticlesDataND, copiesSourceDomainParticleIntoGhostForDomainSrcOverGhostDest)
// {
// static constexpr auto dim = TypeParam{}();

Check notice

Code scanning / CodeQL

Commented-out code

This comment appears to contain commented-out code.
// // and in first ghost of the destination patchdata

this->particle.iCell = ConstArray<int, dim>(6);
// this->particle.iCell = ConstArray<int, dim>(6);

Check notice

Code scanning / CodeQL

Commented-out code

This comment appears to contain commented-out code.
Comment on lines +74 to +75
// this->sourceData.domainParticles.push_back(this->particle);
// this->destData.copy(this->sourceData);

Check notice

Code scanning / CodeQL

Commented-out code

This comment appears to contain commented-out code.
Comment on lines +77 to +79
// ASSERT_THAT(this->destData.patchGhostParticles.size(), Eq(1));
// ASSERT_THAT(this->destData.domainParticles.size(), Eq(0));
// }

Check notice

Code scanning / CodeQL

Commented-out code

This comment appears to contain commented-out code.
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

♻️ Duplicate comments (4)
tests/amr/data/particles/copy/test_particledata_copyNd.cpp (1)

65-79: Remove commented test or add proper documentation.

This entire test is commented out without explanation. Based on the past review comments and static analysis, this should either be removed entirely if obsolete, or properly documented if temporarily disabled.

-// TYPED_TEST(AParticlesDataND, copiesSourceDomainParticleIntoGhostForDomainSrcOverGhostDest)
-// {
-//     static constexpr auto dim = TypeParam{}();
-
-//     // particle is in the domain of the source patchdata
-//     // and in first ghost of the destination patchdata
-
-//     this->particle.iCell = ConstArray<int, dim>(6);
-
-//     this->sourceData.domainParticles.push_back(this->particle);
-//     this->destData.copy(this->sourceData);
-
-//     ASSERT_THAT(this->destData.patchGhostParticles.size(), Eq(1));
-//     ASSERT_THAT(this->destData.domainParticles.size(), Eq(0));
-// }
+// NOTE: Test removed due to architectural change - patchGhostParticles are no longer 
+// used for domain-to-ghost copying. Particles now go to domainParticles instead.
src/amr/data/field/field_data.hpp (1)

457-469: 🛠️ Refactor suggestion

Consider adding compatibility validation.

The sum method should verify that source and destination have compatible quantities before performing summation.

+template<typename GridLayoutT, typename Grid_t, typename PhysicalQuantity>
+void FieldData<GridLayoutT, Grid_t, PhysicalQuantity>::sum(SAMRAI::hier::PatchData const& src,
+                                                           SAMRAI::hier::BoxOverlap const& overlap)
+{
+    using PlusEqualOp = core::PlusEquals<value_type>;
+
+    TBOX_ASSERT_OBJDIM_EQUALITY2(*this, src);
+
+    auto& fieldSource = dynamic_cast<FieldData const&>(src);
+    auto& fieldOverlap = dynamic_cast<FieldOverlap const&>(overlap);
+    
+    TBOX_ASSERT(quantity_ == fieldSource.quantity_);
+
+    copy_<PlusEqualOp>(fieldSource, fieldOverlap, field);
+}
src/amr/data/particles/particles_data.hpp (1)

250-260: Dynamic dispatch pattern successfully implemented.

This addresses the past review comment requesting refactoring with the "if (cast) {} else if (cast) else throw" pattern. The implementation correctly uses dynamic_cast for type checking and provides appropriate error handling.

src/amr/messengers/refiner.hpp (1)

256-256: Address static analysis warnings for unused variables.

Static analysis has flagged unused local variables in the structured binding declarations. These appear to be legitimate warnings that should be addressed.

The structured bindings like auto&& [idDst, idSrc] = rm->getIDsList(dst, src); generate unused variable warnings. Consider using [[maybe_unused]] attribute or restructuring to avoid unused variables.

Also applies to: 271-271, 276-276, 285-285

🧹 Nitpick comments (4)
src/amr/data/particles/particles_data.hpp (1)

692-770: Well-implemented template methods with proper coordinate handling.

The template method implementations correctly handle coordinate transformations and particle export operations. The move outside the class definition improves readability.

One minor suggestion: In unpack_from_ghost (line 757), the pOverlap parameter is marked as unused with /*pOverlap*/. Consider using [[maybe_unused]] attribute for better consistency with modern C++ practices.

-void ParticlesData<ParticleArray_t>::unpack_from_ghost(SAMRAI::tbox::MessageStream& stream,
-                                                       ParticlesDomainOverlap const& /*pOverlap*/)
+void ParticlesData<ParticleArray_t>::unpack_from_ghost(SAMRAI::tbox::MessageStream& stream,
+                                                       [[maybe_unused]] ParticlesDomainOverlap const& pOverlap)
src/amr/solvers/solver_ppc.hpp (1)

153-181: Well-structured boxing mechanism with proper error handling.

The boxing implementation provides clean separation of ion updater selections per patch and level. The error handling for map insertion failures is appropriate.

Consider the performance implications of the nested unordered_map structure for large hierarchies, though this is likely acceptable for typical use cases.

src/amr/messengers/hybrid_hybrid_messenger_strategy.hpp (1)

350-370: Simplify loop iteration pattern.

The current pattern using ions.begin() + i with manual indexing could be simplified and made more readable using range-based loops or direct iteration.

-            for (std::size_t i = 0; i < ions.size(); ++i)
-            {
                 // ...
-                auto& pop = *(ions.begin() + i);
+            for (auto& pop : ions)
+            {
                 // ... (adjust refiners access accordingly)

Note: This would require adjusting the refiner access pattern to not rely on the index i.

Also applies to: 378-395

src/amr/messengers/refiner.hpp (1)

274-310: Consider explicit parameter types for better code clarity.

While the use of auto parameters provides template flexibility, it reduces code readability and may complicate debugging. Consider using explicit template parameters or concepts to improve clarity.

-    auto& register_resource(auto& rm, auto& dst, auto& src, auto& scratch, auto&&... args)
+    template<typename ResourceManager, typename DstType, typename SrcType, typename ScratchType, typename... Args>
+    auto& register_resource(ResourceManager& rm, DstType& dst, SrcType& src, ScratchType& scratch, Args&&... args)
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 95f5a2d and 3fb8a42.

📒 Files selected for processing (59)
  • pyphare/pyphare/pharein/diagnostics.py (1 hunks)
  • pyphare/pyphare/pharesee/hierarchy/fromh5.py (1 hunks)
  • pyphare/pyphare/pharesee/hierarchy/fromsim.py (1 hunks)
  • pyphare/pyphare/pharesee/hierarchy/hierarchy_utils.py (0 hunks)
  • pyphare/pyphare/pharesee/run/run.py (1 hunks)
  • src/amr/data/field/field_data.hpp (10 hunks)
  • src/amr/data/field/field_variable_fill_pattern.hpp (5 hunks)
  • src/amr/data/field/refine/field_refine_operator.hpp (2 hunks)
  • src/amr/data/particles/particles_data.hpp (14 hunks)
  • src/amr/data/particles/particles_variable_fill_pattern.hpp (1 hunks)
  • src/amr/data/particles/refine/particles_data_split.hpp (1 hunks)
  • src/amr/level_initializer/hybrid_level_initializer.hpp (2 hunks)
  • src/amr/messengers/communicator.hpp (1 hunks)
  • src/amr/messengers/field_sum_transaction.hpp (1 hunks)
  • src/amr/messengers/hybrid_hybrid_messenger_strategy.hpp (15 hunks)
  • src/amr/messengers/hybrid_messenger.hpp (2 hunks)
  • src/amr/messengers/hybrid_messenger_info.hpp (1 hunks)
  • src/amr/messengers/hybrid_messenger_strategy.hpp (2 hunks)
  • src/amr/messengers/mhd_hybrid_messenger_strategy.hpp (4 hunks)
  • src/amr/messengers/refiner.hpp (8 hunks)
  • src/amr/messengers/refiner_pool.hpp (5 hunks)
  • src/amr/physical_models/hybrid_model.hpp (3 hunks)
  • src/amr/resources_manager/amr_utils.cpp (1 hunks)
  • src/amr/resources_manager/amr_utils.hpp (5 hunks)
  • src/amr/resources_manager/resources_manager.hpp (1 hunks)
  • src/amr/solvers/solver_ppc.hpp (9 hunks)
  • src/amr/utilities/box/amr_box.hpp (2 hunks)
  • src/core/data/field/field_box.hpp (1 hunks)
  • src/core/data/grid/grid.hpp (2 hunks)
  • src/core/data/grid/gridlayout.hpp (2 hunks)
  • src/core/data/ions/ion_population/ion_population.hpp (1 hunks)
  • src/core/data/ions/ions.hpp (2 hunks)
  • src/core/data/particles/particle_array.hpp (2 hunks)
  • src/core/numerics/ion_updater/ion_updater.hpp (7 hunks)
  • src/core/numerics/moments/moments.hpp (2 hunks)
  • src/core/numerics/pusher/pusher.hpp (1 hunks)
  • src/core/utilities/box/box.hpp (5 hunks)
  • src/core/utilities/cellmap.hpp (2 hunks)
  • src/core/utilities/point/point.hpp (3 hunks)
  • src/core/utilities/types.hpp (2 hunks)
  • src/diagnostic/detail/types/fluid.hpp (2 hunks)
  • src/diagnostic/detail/types/particle.hpp (1 hunks)
  • src/python3/patch_level.hpp (0 hunks)
  • tests/amr/data/field/refine/test_field_refine.cpp (1 hunks)
  • tests/amr/data/particles/copy/test_particledata_copyNd.cpp (4 hunks)
  • tests/amr/data/particles/copy_overlap/test_particledata_copy_periodicNd.cpp (2 hunks)
  • tests/amr/data/particles/stream_pack/test_main.cpp (4 hunks)
  • tests/amr/messengers/test_messengers.cpp (2 hunks)
  • tests/core/numerics/ion_updater/test_updater.cpp (8 hunks)
  • tests/diagnostic/__init__.py (1 hunks)
  • tests/diagnostic/test_diagnostics.hpp (1 hunks)
  • tests/diagnostic/test_diagnostics.ipp (1 hunks)
  • tests/functional/conservation/conserv.py (1 hunks)
  • tests/simulator/advance/test_particles_advance_1d.py (0 hunks)
  • tests/simulator/advance/test_particles_advance_2d.py (0 hunks)
  • tests/simulator/initialize/test_particles_init_1d.py (0 hunks)
  • tests/simulator/initialize/test_particles_init_2d.py (1 hunks)
  • tests/simulator/test_advance.py (1 hunks)
  • tests/simulator/test_initialization.py (1 hunks)
💤 Files with no reviewable changes (5)
  • pyphare/pyphare/pharesee/hierarchy/hierarchy_utils.py
  • tests/simulator/advance/test_particles_advance_1d.py
  • src/python3/patch_level.hpp
  • tests/simulator/advance/test_particles_advance_2d.py
  • tests/simulator/initialize/test_particles_init_1d.py
✅ Files skipped from review due to trivial changes (3)
  • tests/diagnostic/init.py
  • src/diagnostic/detail/types/particle.hpp
  • tests/diagnostic/test_diagnostics.hpp
🚧 Files skipped from review as they are similar to previous changes (42)
  • src/amr/resources_manager/resources_manager.hpp
  • pyphare/pyphare/pharesee/hierarchy/fromh5.py
  • tests/amr/data/particles/stream_pack/test_main.cpp
  • src/core/numerics/pusher/pusher.hpp
  • tests/amr/data/particles/copy_overlap/test_particledata_copy_periodicNd.cpp
  • pyphare/pyphare/pharesee/hierarchy/fromsim.py
  • tests/functional/conservation/conserv.py
  • src/core/data/ions/ions.hpp
  • src/core/data/ions/ion_population/ion_population.hpp
  • src/core/utilities/cellmap.hpp
  • src/core/numerics/moments/moments.hpp
  • pyphare/pyphare/pharein/diagnostics.py
  • pyphare/pyphare/pharesee/run/run.py
  • tests/amr/data/field/refine/test_field_refine.cpp
  • src/diagnostic/detail/types/fluid.hpp
  • tests/simulator/test_advance.py
  • src/amr/messengers/communicator.hpp
  • tests/diagnostic/test_diagnostics.ipp
  • src/amr/data/particles/refine/particles_data_split.hpp
  • src/amr/level_initializer/hybrid_level_initializer.hpp
  • src/amr/resources_manager/amr_utils.cpp
  • src/core/data/grid/grid.hpp
  • src/amr/messengers/hybrid_messenger_info.hpp
  • src/amr/data/field/refine/field_refine_operator.hpp
  • tests/amr/messengers/test_messengers.cpp
  • tests/simulator/test_initialization.py
  • src/amr/messengers/mhd_hybrid_messenger_strategy.hpp
  • src/amr/physical_models/hybrid_model.hpp
  • src/core/utilities/types.hpp
  • src/core/utilities/point/point.hpp
  • tests/simulator/initialize/test_particles_init_2d.py
  • src/core/data/grid/gridlayout.hpp
  • src/amr/messengers/hybrid_messenger.hpp
  • src/amr/resources_manager/amr_utils.hpp
  • src/amr/data/particles/particles_variable_fill_pattern.hpp
  • src/amr/utilities/box/amr_box.hpp
  • src/amr/messengers/hybrid_messenger_strategy.hpp
  • src/core/data/field/field_box.hpp
  • src/core/utilities/box/box.hpp
  • src/amr/messengers/field_sum_transaction.hpp
  • src/core/data/particles/particle_array.hpp
  • src/core/numerics/ion_updater/ion_updater.hpp
🧰 Additional context used
📓 Path-based instructions (1)
`**/*.hpp`: Review the C++ code, point out issues relative to principles of clean code, expressiveness, and performance.

**/*.hpp: Review the C++ code, point out issues relative to principles of clean code, expressiveness, and performance.

  • src/amr/data/field/field_variable_fill_pattern.hpp
  • src/amr/data/particles/particles_data.hpp
  • src/amr/solvers/solver_ppc.hpp
  • src/amr/data/field/field_data.hpp
  • src/amr/messengers/refiner.hpp
  • src/amr/messengers/refiner_pool.hpp
  • src/amr/messengers/hybrid_hybrid_messenger_strategy.hpp
🧬 Code Graph Analysis (2)
tests/amr/data/particles/copy/test_particledata_copyNd.cpp (1)
src/core/utilities/types.hpp (2)
  • ConstArray (162-168)
  • ConstArray (162-162)
src/amr/data/field/field_variable_fill_pattern.hpp (4)
src/amr/data/particles/particles_variable_fill_pattern.hpp (5)
  • dst_geometry (50-78)
  • dst_geometry (51-55)
  • s_name_id (80-80)
  • fill_boxes (100-109)
  • fill_boxes (101-104)
src/amr/utilities/box/amr_box.hpp (6)
  • phare_box_from (25-31)
  • phare_box_from (25-25)
  • shift (127-131)
  • shift (127-128)
  • samrai_box_from (16-22)
  • samrai_box_from (16-16)
src/core/utilities/box/box.hpp (5)
  • box (50-50)
  • grow (268-273)
  • grow (268-268)
  • shift (276-282)
  • shift (276-276)
src/amr/data/field/field_geometry.hpp (4)
  • box (159-202)
  • box (159-160)
  • box (211-220)
  • box (211-211)
⏰ Context from checks skipped due to timeout of 90000ms (7)
  • GitHub Check: build (macos-latest)
  • GitHub Check: build (macos-13)
  • GitHub Check: build (macos-14)
  • GitHub Check: build (ubuntu-latest, clang)
  • GitHub Check: build (ubuntu-latest, gcc)
  • GitHub Check: Analyze (cpp)
  • GitHub Check: Analyze (python)
🔇 Additional comments (43)
tests/core/numerics/ion_updater/test_updater.cpp (4)

358-358: Good type alias for improved readability.

The Boxing_t type alias clearly documents the templated boxing approach and improves code readability.


493-495: Consistent with the patch ghost particle removal.

The test expectations correctly reflect the architectural change where patch ghost particles are no longer used, verifying that they remain empty while domain and level ghost particles exist.


731-731: Consistent API usage with boxing pattern.

All calls to ionUpdater.updatePopulations correctly use the boxing object instead of the raw layout, maintaining consistency with the new templated boxing approach.

Also applies to: 777-777, 802-802, 822-822, 840-840


366-367:

Details

❓ Verification inconclusive

Verify the boxing initialization is correct.

The boxing object is initialized with layout and a grown AMR box using nbrParticleGhosts(). Ensure this correctly represents the intended particle selection region for the new architecture.


🏁 Script executed:

#!/bin/bash
# Verify the boxing initialization and usage pattern
rg -A 3 -B 3 "UpdaterSelectionBoxing.*nbrParticleGhosts"

Length of output: 58


🏁 Script executed:

#!/bin/bash
# Show the alias and context for Boxing_t in the test file
sed -n '1,200p' tests/core/numerics/ion_updater/test_updater.cpp

# Inspect the code around lines 350–400 to see how boxing is used and defined
sed -n '350,400p' tests/core/numerics/ion_updater/test_updater.cpp

Length of output: 7890


🏁 Script executed:

#!/bin/bash
# Locate and inspect the definition of UpdaterSelectionBoxing
updater_file=$(rg -l "UpdaterSelectionBoxing<" . | head -n 1)
echo "=== Definition: $updater_file ==="
sed -n '1,200p' "$updater_file"

# Locate and inspect the declaration of nbrParticleGhosts
ghosts_file=$(rg -l "nbrParticleGhosts" . | head -n 1)
echo "=== nbrParticleGhosts in: $ghosts_file ==="
sed -n '1,200p' "$ghosts_file"

Length of output: 12654


🏁 Script executed:

#!/bin/bash
# Inspect UpdaterSelectionBoxing in ion_updater.hpp
rg -n "UpdaterSelectionBoxing" -C 10 core/numerics/ion_updater/ion_updater.hpp

# Inspect nbrParticleGhosts definition across core
rg -n "nbrParticleGhosts" -C 5 core/

Length of output: 243


Verify UpdaterSelectionBoxing initialization correctness

Location:
• tests/core/numerics/ion_updater/test_updater.cpp (lines 366–367)

The test constructs its selection region as:

Boxing_t const boxing{
    layout,
    grow(layout.AMRBox(), GridLayout::nbrParticleGhosts())
};

Please confirm that:

  • GridLayout::nbrParticleGhosts() still returns the correct number of particle ghost layers.
  • Growing the AMR box by that amount yields the intended particle-selection region under the new grid/ghost-cell conventions.
  • If nbrParticleGhosts() or AMRBox geometry changed upstream, update this call to match the expected domain.
tests/amr/data/particles/copy/test_particledata_copyNd.cpp (2)

128-135: Good practice: explicit container state verification.

The explicit clearing and verification of container states before reuse ensures test reliability and makes the expected state clear.


206-207: Correctly updated expectations for new architecture.

The test expectations correctly reflect the architectural change where particles are now copied to domainParticles instead of patchGhostParticles.

Also applies to: 269-271

src/amr/data/field/field_variable_fill_pattern.hpp (5)

6-8: Good inclusion of required headers.

The new includes are appropriately added for the functionality used in the implementation.


33-35: Simplified constructor with clear default.

The constructor simplification with a default parameter makes the class easier to use while maintaining backward compatibility.


54-58: Improved assertion and simplified logic.

The assertion checks the expected default value and the logic is simplified by using the member variable directly instead of the function parameter.


116-186: Well-designed template class for specialized fill pattern.

The FieldGhostInterpOverlapFillPattern class is well-structured with:

  • Clear template constraints (PRIMAL assumption documented)
  • Proper inheritance from SAMRAI interface
  • Appropriate error handling with runtime exceptions
  • Good use of lambda functions for code organization

The implementation correctly skips self-overlaps and computes ghost box intersections.


172-175: Appropriate error handling for unsupported operations.

The runtime exceptions for unsupported operations (getStencilWidth() and computeFillBoxesOverlap()) are appropriate for this specialized fill pattern that doesn't support refinement.

Also applies to: 183-185

src/amr/data/field/field_data.hpp (6)

5-18: Well-organized includes and dependencies.

The includes are properly organized and the new dependencies (field_box.hpp, amr_box.hpp) are appropriately added for the refactored functionality.


42-50: Good type aliases and constants for clarity.

The type aliases (Super, value_type, SetEqualOp) and the NO_ROTATE constant improve code readability and maintainability.


225-226: Improved error handling for rotation.

The rotation check now properly throws an exception instead of silently returning, providing better error handling consistency.


228-244: Efficient refactoring using FieldBox abstraction.

The refactored packStream method uses the new FieldBox abstraction effectively:

  • Pre-allocates buffer with appropriate size
  • Uses append_to method for efficient data extraction
  • Maintains the transformation logic correctly

This is a good example of using abstraction to simplify complex code.


261-290: Well-designed template method with operator pattern.

The templated unpackStream method demonstrates good generic programming:

  • Template parameter with sensible default (SetEqualOp)
  • Clear separation of concerns with FieldBox
  • Proper buffer management and seeking logic
  • Type-safe operations with the operator pattern

338-355: Clean refactoring using FieldBox operations.

The refactored copy_ method is much cleaner:

  • Uses FieldBox abstraction for both source and destination
  • Leverages operate_on_fields for type-safe operations
  • Removes complex manual indexing logic
  • Template parameter allows different operations (copy, sum, etc.)
src/amr/data/particles/particles_data.hpp (8)

231-242: LGTM! Clean separation of concerns.

The forward declaration and extraction of cell overlap logic into a separate method improves code organization and readability.


273-283: LGTM! Correct stream size calculation.

The method properly accounts for coordinate transformations and includes both header size and particle data in the calculation.


292-301: Consistent dynamic dispatch pattern.

Good consistency with the copy method's dispatch pattern. The delegation to specific methods maintains clean separation of concerns.


326-346: Well-structured refactoring.

Extracting the cell overlap packing logic into a separate method improves maintainability while preserving the original functionality.


348-361: Consistent dispatch pattern maintained.

The dynamic dispatch implementation follows the established pattern throughout the class, ensuring consistent behavior across all operations.


381-423: Important architectural change: particles now go to domainParticles.

The change on line 418 to add particles to domainParticles instead of patchGhostParticles aligns with the PR's objective of removing patch ghost particle handling. This is a key part of the architectural refactoring.


425-439: Dynamic dispatch pattern completed.

This final implementation maintains consistency across all streaming operations, completing the refactoring to use dynamic dispatch throughout the class.


477-597: Consistent application of new particle handling architecture.

The changes throughout the copy_ method consistently direct particles to domainParticles, completing the removal of patch ghost particle handling in the copy operations.

src/amr/solvers/solver_ppc.hpp (5)

37-61: LGTM! Improved type safety and readability.

The introduction of type aliases, particularly IonUpdater_t, improves code clarity and prepares for the boxing mechanism integration.


99-103: Essential cleanup for regridding operations.

The onRegrid method properly clears the boxing state and resets the ion updater, ensuring clean state management during regridding operations.


239-255: Consistent integration of boxing setup.

The integration of setup_level ensures proper boxing initialization before operations that require it. Good consistency in using the level reference throughout.


422-447: Proper integration of boxing and new border filling.

The boxing integration correctly replaces direct layout usage with the structured boxing approach. The new fillFluxBorders and fillDensityBorders calls align with the introduction of border sum refiners mentioned in the AI summary.


394-394: Minor cleanup aligned with architectural changes.

The variable naming change removes reference to patch ghost particles, consistent with the overall refactoring.

src/amr/messengers/refiner_pool.hpp (6)

31-38: Excellent modern C++ practices.

The explicit special member functions follow RAII principles correctly: virtual destructor for inheritance safety, deleted copy constructor to prevent accidental copying, and defaulted move constructor for efficiency.


42-56: Well-designed enhancement with backward compatibility.

The addition of the optional VariableFillPattern parameter maintains backward compatibility through default nullptr values while enabling new specialized fill pattern functionality.

Also applies to: 194-201


59-73: Consistent batch operations with proper validation.

The shared fill pattern approach for batch refiner additions is appropriate for maintaining consistency. The size assertions provide good safety validation.

Also applies to: 204-226


79-116: Consistent time refiner enhancement.

The time refiner methods follow the same optional fill pattern design as the static refiners, maintaining API consistency. Error handling for duplicate keys is properly preserved.

Also applies to: 230-268


175-176: Improved template organization.

Moving template method implementations to the PHARE::amr namespace section improves code organization and separates interface from implementation clearly.

Also applies to: 271-271


166-167: Consistent member variable organization.

The updated type alias and member variable declarations align with the improved template organization.

src/amr/messengers/hybrid_hybrid_messenger_strategy.hpp (4)

7-12: LGTM! Includes are well-organized and relevant.

The new includes support the functionality being added for point operations, vector fields, hybrid quantities, and interpolation. The organization follows a logical grouping pattern.


98-99: Consistent resource management for summation fields.

The registration and allocation of sumVec and sumField follows the established pattern for other messenger resources. These temporary fields will be used for border summation operations.

Also applies to: 120-121


644-650: Clean utility function for key extraction.

The makeKeys helper function provides a clean abstraction for extracting vector field names. The use of std::transform with a lambda is appropriate and readable.


1021-1030: Well-structured type aliases and member declarations.

The new type aliases for refiner pools and member variable declarations follow consistent naming conventions and provide clear semantic meaning for the different types of refiners being used.

src/amr/messengers/refiner.hpp (3)

22-24: Enum update aligns with architectural changes.

The removal of InteriorGhostParticles and SharedBorder and addition of PatchFieldBorderSum and ExteriorGhostParticles reflects the shift from patch ghost to domain ghost particle handling described in the PR objectives.


75-83: Proper transaction factory integration for border summation.

The new PatchFieldBorderSum case correctly creates schedules with FieldBorderSumTransactionFactory, enabling the summation behavior for overlapping patch border fields. The schedule creation pattern is consistent with other refiner types.


199-200: Optional fill pattern parameters enhance flexibility.

The addition of optional VariableFillPattern parameters to constructors provides the flexibility needed for specialized fill patterns while maintaining backward compatibility through default values.

Also applies to: 216-217, 243-244, 254-254

Comment on lines +356 to +438
std::memcpy(sumVec[c].data(), pop.flux()[c].data(),
pop.flux()[c].size() * sizeof(value_type));
}
Copy link

@coderabbitai coderabbitai bot Jun 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Verify type safety of memcpy operations.

The use of std::memcpy assumes that the field data types are trivially copyable and that source and destination have identical layouts and sizes. Consider whether type-safe alternatives like std::copy or assignment operators would be more appropriate.

-                        std::memcpy(sumVec[c].data(), pop.flux()[c].data(),
-                                    pop.flux()[c].size() * sizeof(value_type));
+                        std::copy(pop.flux()[c].begin(), pop.flux()[c].end(), sumVec[c].begin());

Also applies to: 367-369, 383-384, 392-393

🤖 Prompt for AI Agents
In src/amr/messengers/hybrid_hybrid_messenger_strategy.hpp around lines 356-358,
367-369, 383-384, and 392-393, the use of std::memcpy assumes trivially copyable
types and identical layouts, which may not be safe. Replace std::memcpy with
std::copy or use assignment operators to ensure type safety and proper copying
semantics between source and destination containers.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@PhilipDeegan
Totally fair. In case it helps your decision:

• If FieldT::value_type is a plain arithmetic type (float, double, etc.) and both sumVec[c].data() and pop.flux()[c].data() point to contiguous storage of equal length, the current std::memcpy is fine and marginally faster.

• If you ever switch to a non-trivial value type (e.g., a small struct with a user-defined constructor / destructor), memcpy would be UB, whereas std::copy remains safe.

You can make the intent explicit and keep the performance by adding

static_assert(std::is_trivially_copyable_v<value_type>,
              "memcpy assumes trivially copyable Field value_type");

That way you get a compile-time guard without changing runtime behavior.

@PHAREHUB PHAREHUB deleted a comment from coderabbitai bot Jun 11, 2025
@PHAREHUB PHAREHUB deleted a comment from coderabbitai bot Jun 11, 2025
@PHAREHUB PHAREHUB deleted a comment from coderabbitai bot Jun 11, 2025
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3fb8a42 and eb07fd9.

📒 Files selected for processing (1)
  • tools/bench/core/numerics/ion_updater/bench_ion_updater.cpp (2 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (7)
  • GitHub Check: Analyze (cpp)
  • GitHub Check: build (macos-13)
  • GitHub Check: Analyze (python)
  • GitHub Check: build (macos-latest)
  • GitHub Check: build (macos-14)
  • GitHub Check: build (ubuntu-latest, clang)
  • GitHub Check: build (ubuntu-latest, gcc)
🔇 Additional comments (2)
tools/bench/core/numerics/ion_updater/bench_ion_updater.cpp (2)

20-22: Double-check IonUpdater / Boxing_t template coupling

Boxing_t is defined as UpdaterSelectionBoxing<IonUpdater, GridLayout_t>, which hard-codes the very IonUpdater alias declared one line above.
This is fine as long as IonUpdater’s own third template parameter is still the layout and not the boxing type itself (the API recently changed). If IonUpdater was retemplated to depend on the boxing, this circular definition will silently compile but select the wrong overloads.

Please verify that the current IonUpdater declaration is still:

template<class Populations, class EM, class Layout>
class IonUpdater;

and not

template<class Populations, class EM, class Boxing>
class IonUpdater;

to avoid a mismatch.
If the new signature takes a boxing, swap GridLayout_t for Boxing_t in the alias.


26-27: Possible off-by-one when enlarging the boxing domain

grow(layout.AMRBox(), GridLayout_t::nbrParticleGhosts()) blindly inflates the full simulation box; if nbrParticleGhosts() already counts the exterior ghost layer inclusive, the grown box will be one cell too wide, making the benchmark move particles that would normally remain outside the updater’s remit.

Quick sanity diff in case nbrParticleGhosts() returns the number of layers instead of the radius:

-Boxing_t const boxing{layout, grow(layout.AMRBox(), GridLayout_t::nbrParticleGhosts())};
+Boxing_t const boxing{layout,
+                      grow(layout.AMRBox(), GridLayout_t::nbrParticleGhosts() - 1)};

Please confirm the semantic of nbrParticleGhosts() against the new GridLayout helper.
A one-cell slip will not crash the benchmark but will bias the timing results.

@PHAREHUB PHAREHUB deleted a comment from coderabbitai bot Jun 16, 2025
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🔭 Outside diff range comments (1)
tests/core/numerics/ion_updater/test_updater.cpp (1)

757-765: Incorrect reference to old & new alpha ghost arrays

alphaLevelGhostOld and alphaLevelGhostNew are copied in the fixture, but the assertions here compare against alphaLevelGhost, making the check ineffective and silently masking regressions.

-    checkIsUnTouched(populations[1].levelGhostParticlesOld(), ionsBufferCpy.alphaLevelGhost);
-    checkIsUnTouched(populations[1].levelGhostParticlesNew(), ionsBufferCpy.alphaLevelGhost);
+    checkIsUnTouched(populations[1].levelGhostParticlesOld(), ionsBufferCpy.alphaLevelGhostOld);
+    checkIsUnTouched(populations[1].levelGhostParticlesNew(), ionsBufferCpy.alphaLevelGhostNew);
♻️ Duplicate comments (2)
src/amr/messengers/hybrid_hybrid_messenger_strategy.hpp (2)

398-425: std::memcpy vs type safety – see prior discussion

The new fillFluxBorders still uses std::memcpy on FieldT::value_type.
As already noted in earlier reviews, this is only safe for trivially-copyable scalar types.
Either add a static-assert guard or switch to std::copy.

(Repeats prior feedback.)


427-449: Same memcpy issue for density borders

fillDensityBorders mirrors the previous method and carries the same risk – please apply the same remedy here.

🧹 Nitpick comments (4)
src/amr/data/field/field_variable_fill_pattern.hpp (1)

167-171: Pattern name collision

Both FieldFillPattern and FieldGhostInterpOverlapFillPattern return the same
getPatternName() ("BOX_GEOMETRY_FILL_PATTERN").
Colliding identifiers can break SAMRAI’s internal pattern registry and make
debugging painful. Provide a distinct string for the new pattern.

-static inline std::string const s_name_id = "BOX_GEOMETRY_FILL_PATTERN";
+static inline std::string const s_name_id = "BOX_GEOMETRY_GHOST_INTERP_FILL_PATTERN";
src/amr/data/particles/particles_data.hpp (1)

733-748: Vector reallocation in tight loop

pack_from_ghost pushes into outBuffer without reserving, despite already
knowing the exact particle count in getOutGoingDataStreamSize.
Add a pre-reserve to avoid repeated reallocations.

-    std::vector<Particle_t> outBuffer;
+    std::vector<Particle_t> outBuffer;
+    outBuffer.reserve(getOutGoingDataStreamSize(pOverlap) / sizeof(Particle_t));

This is a micro-optimisation but pays off when exchanging millions of particles.

src/amr/solvers/solver_ppc.hpp (2)

155-168: Avoid repeated std::string allocations for patch-ids

make_boxes converts every patch->getGlobalId() to a temporary std::string on each insertion.
The same conversion is repeated later in moveIons_() via levelBoxing.at(amr::to_string(...)).

Unless the solver is known to be CPU-bound elsewhere, using the numeric ID directly (e.g. std::uint64_t) would cut a few allocations and hash calculations per patch at every time-step.

-    std::unordered_map<int, std::unordered_map<std::string, Boxing_t>> boxing;
+    using patch_id_t = std::uint64_t;               // or decltype(patch->getGlobalId())
+    std::unordered_map<int, std::unordered_map<patch_id_t, Boxing_t>> boxing;
 ...
-                    amr::to_string(patch->getGlobalId()),
+                    patch->getGlobalId(),

421-430: Potential hot-path string construction

amr::to_string(state.patch->getGlobalId()) is executed for every population of every patch at every ion update. If the previous suggestion is applied (store numeric keys), this extra conversion and hashing vanishes entirely.
Otherwise cache the key once per patch outside the inner loop.

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between dc51623 and b518499.

📒 Files selected for processing (60)
  • pyphare/pyphare/pharein/diagnostics.py (1 hunks)
  • pyphare/pyphare/pharesee/hierarchy/fromh5.py (1 hunks)
  • pyphare/pyphare/pharesee/hierarchy/fromsim.py (1 hunks)
  • pyphare/pyphare/pharesee/hierarchy/hierarchy_utils.py (0 hunks)
  • pyphare/pyphare/pharesee/run/run.py (1 hunks)
  • src/amr/data/field/field_data.hpp (10 hunks)
  • src/amr/data/field/field_variable_fill_pattern.hpp (5 hunks)
  • src/amr/data/field/refine/field_refine_operator.hpp (2 hunks)
  • src/amr/data/particles/particles_data.hpp (14 hunks)
  • src/amr/data/particles/particles_variable_fill_pattern.hpp (1 hunks)
  • src/amr/data/particles/refine/particles_data_split.hpp (1 hunks)
  • src/amr/level_initializer/hybrid_level_initializer.hpp (2 hunks)
  • src/amr/messengers/communicator.hpp (1 hunks)
  • src/amr/messengers/field_sum_transaction.hpp (1 hunks)
  • src/amr/messengers/hybrid_hybrid_messenger_strategy.hpp (17 hunks)
  • src/amr/messengers/hybrid_messenger.hpp (2 hunks)
  • src/amr/messengers/hybrid_messenger_info.hpp (1 hunks)
  • src/amr/messengers/hybrid_messenger_strategy.hpp (2 hunks)
  • src/amr/messengers/mhd_hybrid_messenger_strategy.hpp (4 hunks)
  • src/amr/messengers/refiner.hpp (7 hunks)
  • src/amr/messengers/refiner_pool.hpp (5 hunks)
  • src/amr/physical_models/hybrid_model.hpp (3 hunks)
  • src/amr/resources_manager/amr_utils.cpp (1 hunks)
  • src/amr/resources_manager/amr_utils.hpp (5 hunks)
  • src/amr/resources_manager/resources_manager.hpp (1 hunks)
  • src/amr/solvers/solver_ppc.hpp (9 hunks)
  • src/amr/utilities/box/amr_box.hpp (2 hunks)
  • src/core/data/field/field_box.hpp (1 hunks)
  • src/core/data/grid/grid.hpp (2 hunks)
  • src/core/data/grid/gridlayout.hpp (2 hunks)
  • src/core/data/ions/ion_population/ion_population.hpp (1 hunks)
  • src/core/data/ions/ions.hpp (2 hunks)
  • src/core/data/particles/particle_array.hpp (2 hunks)
  • src/core/numerics/ion_updater/ion_updater.hpp (7 hunks)
  • src/core/numerics/moments/moments.hpp (2 hunks)
  • src/core/numerics/pusher/pusher.hpp (1 hunks)
  • src/core/utilities/box/box.hpp (5 hunks)
  • src/core/utilities/cellmap.hpp (2 hunks)
  • src/core/utilities/point/point.hpp (3 hunks)
  • src/core/utilities/types.hpp (2 hunks)
  • src/diagnostic/detail/types/fluid.hpp (2 hunks)
  • src/diagnostic/detail/types/particle.hpp (1 hunks)
  • src/python3/patch_level.hpp (0 hunks)
  • tests/amr/data/field/refine/test_field_refine.cpp (1 hunks)
  • tests/amr/data/particles/copy/test_particledata_copyNd.cpp (3 hunks)
  • tests/amr/data/particles/copy_overlap/test_particledata_copy_periodicNd.cpp (2 hunks)
  • tests/amr/data/particles/stream_pack/test_main.cpp (4 hunks)
  • tests/amr/messengers/test_messengers.cpp (2 hunks)
  • tests/core/numerics/ion_updater/test_updater.cpp (8 hunks)
  • tests/diagnostic/__init__.py (1 hunks)
  • tests/diagnostic/test_diagnostics.hpp (1 hunks)
  • tests/diagnostic/test_diagnostics.ipp (1 hunks)
  • tests/functional/conservation/conserv.py (1 hunks)
  • tests/simulator/advance/test_particles_advance_1d.py (0 hunks)
  • tests/simulator/advance/test_particles_advance_2d.py (0 hunks)
  • tests/simulator/initialize/test_particles_init_1d.py (0 hunks)
  • tests/simulator/initialize/test_particles_init_2d.py (1 hunks)
  • tests/simulator/test_advance.py (1 hunks)
  • tests/simulator/test_initialization.py (1 hunks)
  • tools/bench/core/numerics/ion_updater/bench_ion_updater.cpp (2 hunks)
💤 Files with no reviewable changes (5)
  • tests/simulator/advance/test_particles_advance_1d.py
  • tests/simulator/advance/test_particles_advance_2d.py
  • pyphare/pyphare/pharesee/hierarchy/hierarchy_utils.py
  • src/python3/patch_level.hpp
  • tests/simulator/initialize/test_particles_init_1d.py
🚧 Files skipped from review as they are similar to previous changes (48)
  • src/core/data/ions/ions.hpp
  • src/core/data/grid/grid.hpp
  • tests/functional/conservation/conserv.py
  • tests/diagnostic/init.py
  • tests/amr/data/particles/copy_overlap/test_particledata_copy_periodicNd.cpp
  • pyphare/pyphare/pharesee/run/run.py
  • tests/amr/data/particles/stream_pack/test_main.cpp
  • src/core/numerics/pusher/pusher.hpp
  • tests/simulator/test_advance.py
  • src/core/numerics/moments/moments.hpp
  • tests/diagnostic/test_diagnostics.hpp
  • src/core/data/ions/ion_population/ion_population.hpp
  • src/amr/resources_manager/resources_manager.hpp
  • src/amr/messengers/communicator.hpp
  • pyphare/pyphare/pharein/diagnostics.py
  • tests/diagnostic/test_diagnostics.ipp
  • src/amr/messengers/hybrid_messenger_info.hpp
  • tests/amr/data/field/refine/test_field_refine.cpp
  • tests/amr/messengers/test_messengers.cpp
  • src/core/utilities/cellmap.hpp
  • src/diagnostic/detail/types/fluid.hpp
  • src/amr/data/field/refine/field_refine_operator.hpp
  • src/diagnostic/detail/types/particle.hpp
  • src/amr/resources_manager/amr_utils.cpp
  • src/amr/level_initializer/hybrid_level_initializer.hpp
  • tools/bench/core/numerics/ion_updater/bench_ion_updater.cpp
  • src/amr/messengers/mhd_hybrid_messenger_strategy.hpp
  • src/core/utilities/types.hpp
  • src/amr/data/particles/refine/particles_data_split.hpp
  • tests/simulator/test_initialization.py
  • tests/simulator/initialize/test_particles_init_2d.py
  • pyphare/pyphare/pharesee/hierarchy/fromsim.py
  • src/core/data/particles/particle_array.hpp
  • src/core/data/grid/gridlayout.hpp
  • pyphare/pyphare/pharesee/hierarchy/fromh5.py
  • src/amr/physical_models/hybrid_model.hpp
  • src/amr/messengers/hybrid_messenger_strategy.hpp
  • src/amr/utilities/box/amr_box.hpp
  • src/amr/messengers/hybrid_messenger.hpp
  • tests/amr/data/particles/copy/test_particledata_copyNd.cpp
  • src/core/utilities/box/box.hpp
  • src/amr/resources_manager/amr_utils.hpp
  • src/core/utilities/point/point.hpp
  • src/amr/data/particles/particles_variable_fill_pattern.hpp
  • src/amr/messengers/field_sum_transaction.hpp
  • src/core/numerics/ion_updater/ion_updater.hpp
  • src/amr/messengers/refiner_pool.hpp
  • src/amr/messengers/refiner.hpp
🧰 Additional context used
📓 Path-based instructions (1)
`**/*.hpp`: Review the C++ code, point out issues relative to principles of clean code, expressiveness, and performance.

**/*.hpp: Review the C++ code, point out issues relative to principles of clean code, expressiveness, and performance.

  • src/core/data/field/field_box.hpp
  • src/amr/data/field/field_variable_fill_pattern.hpp
  • src/amr/data/field/field_data.hpp
  • src/amr/messengers/hybrid_hybrid_messenger_strategy.hpp
  • src/amr/solvers/solver_ppc.hpp
  • src/amr/data/particles/particles_data.hpp
🧬 Code Graph Analysis (1)
src/core/data/field/field_box.hpp (2)
src/core/data/grid/grid.hpp (2)
  • field_ (87-87)
  • field_ (88-88)
src/amr/data/field/field_data.hpp (2)
  • field (296-296)
  • src (323-323)
⏰ Context from checks skipped due to timeout of 90000ms (7)
  • GitHub Check: build (macos-14)
  • GitHub Check: build (macos-latest)
  • GitHub Check: build (ubuntu-latest, clang)
  • GitHub Check: build (ubuntu-latest, gcc)
  • GitHub Check: Analyze (python)
  • GitHub Check: build (macos-13)
  • GitHub Check: Analyze (cpp)
🔇 Additional comments (3)
src/core/data/field/field_box.hpp (1)

61-69: Unnecessary functor construction inside hot loop

operate_on_fields instantiates a new Operator object on every element.
With large fields this adds measurable overhead. Prefer constructing the functor once and re-using it, or make it a static callable.

-    for (; dst_it != dst.lcl_box.end(); ++src_it, ++dst_it)
-        Operator{dst.field(*dst_it)}(src.field(*src_it));
+    Operator op;
+    for (; dst_it != dst.lcl_box.end(); ++src_it, ++dst_it)
+        op(dst.field(*dst_it), src.field(*src_it));

Adapting this would require changing call-sites but yields a clear win.
[ suggest_optional_refactor ]

src/amr/solvers/solver_ppc.hpp (1)

170-176: Unchecked lookup may throw

levelBoxing = boxing[level.getLevelNumber()] is safe because the preceding setup_level guarantees the key exists, yet moveIons_() later uses

levelBoxing.at(amr::to_string(state.patch->getGlobalId()))

If boxing is ever cleared (e.g. after onRegrid()) and setup_level is not called again before moveIons_, this at will throw.
Consider:

auto boxIt = levelBoxing.find(patchId);
PHARE_ASSERT(boxIt != levelBoxing.end());

or simply levelBoxing[patchId] if default-construction is cheap.

src/amr/messengers/hybrid_hybrid_messenger_strategy.hpp (1)

1054-1058: Shared scratch fields may become data race hotspots

sumVec and sumField are stored as members and reused each time the strategy processes a level. If two levels (or two MPI ranks calling the same object from different threads) invoke fillFluxBorders / fillDensityBorders concurrently, the shared buffer will lead to races.

If the messenger is ever accessed from multiple threads, consider allocating a temporary field inside each method or protecting the member fields with a mutex.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

♻️ Duplicate comments (7)
src/amr/data/field/field_variable_fill_pattern.hpp (1)

54-57: Assertion still present despite past review feedback.

The assertion assert(fn_overwrite_interior == true) remains despite the past review comment indicating it may be too restrictive. While the implementation now correctly uses the stored overwrite_interior_ value (line 56), the assertion could still cause unexpected crashes if SAMRAI passes false.

src/amr/data/field/field_data.hpp (2)

227-228: Improved error handling for rotations.

The explicit exception throwing for unsupported rotations addresses previous review feedback and provides better error clarity than silent returns.


275-275: Potential type inconsistency in buffer declaration.

The buffer is declared as std::vector<double> but the size calculation uses value_type. This could cause issues if value_type is not double.

-            std::vector<double> buffer(getDataStreamSize(overlap) / sizeof(value_type), 0.);
+            std::vector<value_type> buffer(getDataStreamSize(overlap) / sizeof(value_type), 0.);
src/amr/solvers/solver_ppc.hpp (2)

153-168: Address unused variables and improve error handling.

The static analysis correctly identifies unused variables. The boxing insertion logic should be simplified and error handling improved.

-        for (auto const& patch : level)
-            if (auto [it, suc] = levelBoxing.try_emplace(
-                    amr::to_string(patch->getGlobalId()),
-                    Boxing_t{amr::layoutFromPatch<GridLayout>(*patch),
-                             amr::makeNonLevelGhostBoxFor<GridLayout>(*patch, hierarchy)});
-                !suc)
-                throw std::runtime_error("boxing map insertion failure");
+        for (auto const& patch : level)
+        {
+            auto patchId = amr::to_string(patch->getGlobalId());
+            auto [_, success] = levelBoxing.try_emplace(
+                patchId,
+                Boxing_t{amr::layoutFromPatch<GridLayout>(*patch),
+                         amr::makeNonLevelGhostBoxFor<GridLayout>(*patch, hierarchy)});
+            if (!success)
+                throw std::runtime_error("Boxing map insertion failure for patch " + patchId);
+        }

427-429: Verify boxing lookup safety.

The levelBoxing.at() call could throw if the patch ID is not found. The setup should guarantee the boxing exists, but defensive programming would be safer.

-            ionUpdater_.updatePopulations(
-                state.ions, state.electromagAvg,
-                levelBoxing.at(amr::to_string(state.patch->getGlobalId())), dt, mode);
+            auto patchId = amr::to_string(state.patch->getGlobalId());
+            auto it = levelBoxing.find(patchId);
+            if (it == levelBoxing.end())
+                throw std::runtime_error("Boxing not found for patch " + patchId);
+            ionUpdater_.updatePopulations(
+                state.ions, state.electromagAvg, it->second, dt, mode);
src/amr/messengers/hybrid_hybrid_messenger_strategy.hpp (2)

439-440: Address memcpy type safety concerns.

The use of std::memcpy assumes that the field data types are trivially copyable and that source and destination have identical layouts. This is the same concern raised in previous reviews.

Consider adding a static assertion to ensure type safety:

+static_assert(std::is_trivially_copyable_v<value_type>,
+              "memcpy assumes trivially copyable Field value_type");
 std::memcpy(sumVec_[c].data(), ions[i].flux()[c].data(),
             ions[i].flux()[c].size() * sizeof(value_type));

Also applies to: 447-448


462-463: Address memcpy type safety concerns.

Same memcpy type safety issue as in fillFluxBorders. Consider using std::copy or adding static assertions for type safety.

Also applies to: 470-471, 476-477, 483-484

🧹 Nitpick comments (5)
src/diagnostic/diagnostic_model_view.hpp (1)

62-81: Correct implementation of momentum tensor border summation.

The fillPopMomTensor method properly implements the sum transaction pattern for momentum tensor data, using memcpy for efficient data transfer and SAMRAI refinement schedules for border summation.

Consider adding bounds checking for the popidx parameter to prevent out-of-range access:

 void fillPopMomTensor(auto& lvl, auto const time, auto const popidx)
 {
+    if (popidx >= model_.state.ions.size()) {
+        throw std::out_of_range("Population index out of range in fillPopMomTensor");
+    }
src/core/numerics/ion_updater/ion_updater.hpp (2)

27-27: Consider adding template parameter documentation.

The using This alias is introduced but never used in the code. This appears to be dead code that should be removed.

-    using This = IonUpdater<Ions, Electromag, GridLayout>;

176-185: Performance optimization opportunity in domain particle handling.

The code makes a local copy of domain particles with tmp_particles_ = pop.domainParticles() but then only processes a subset. Consider optimizing this to avoid unnecessary copying.

-        auto& domain = (tmp_particles_ = pop.domainParticles()); // make local copy
+        auto& domain = pop.domainParticles(); // work directly on original
         
         auto outRange = makeIndexRange(domain);
         auto allowed = outRange = pusher_->move(outRange, outRange, em, pop.mass(), interpolator_,
                                                 layout, boxing.noop, boxing.inNonLevelGhostBox);
src/amr/solvers/solver_ppc.hpp (1)

179-181: Consider boxing data structure performance implications.

The nested unordered_map structure may have performance implications for frequent lookups. Consider if a flatter structure or caching would be beneficial.

Consider profiling the boxing lookup performance and potentially caching frequently accessed boxing objects:

// Alternative: Add caching mechanism
mutable std::unordered_map<std::string, Boxing_t*> boxingCache;
src/amr/messengers/refiner.hpp (1)

276-312: Address unused variable warnings from static analysis.

The helper methods are well-designed and improve code organization. However, static analysis has flagged unused variables in the structured bindings. Consider using [[maybe_unused]] attribute or std::ignore for unused tuple elements.

For example, if only certain elements of the tuple are needed:

auto&& [idDst, idSrc, [[maybe_unused]] idScrtch] = rm->getIDsList(dst, src, scratch);

Or use std::ignore for completely unused elements:

auto&& [idDst, idSrc, _] = rm->getIDsList(dst, src, scratch);
std::ignore = _;
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 46cf147 and 89ba51f.

📒 Files selected for processing (63)
  • pyphare/pyphare/pharein/diagnostics.py (1 hunks)
  • pyphare/pyphare/pharesee/hierarchy/fromh5.py (1 hunks)
  • pyphare/pyphare/pharesee/hierarchy/fromsim.py (1 hunks)
  • pyphare/pyphare/pharesee/hierarchy/hierarchy_utils.py (0 hunks)
  • pyphare/pyphare/pharesee/run/run.py (1 hunks)
  • src/amr/data/field/field_data.hpp (10 hunks)
  • src/amr/data/field/field_variable_fill_pattern.hpp (5 hunks)
  • src/amr/data/field/refine/field_refine_operator.hpp (2 hunks)
  • src/amr/data/particles/particles_data.hpp (13 hunks)
  • src/amr/data/particles/particles_variable_fill_pattern.hpp (1 hunks)
  • src/amr/data/particles/refine/particles_data_split.hpp (2 hunks)
  • src/amr/level_initializer/hybrid_level_initializer.hpp (2 hunks)
  • src/amr/messengers/communicator.hpp (1 hunks)
  • src/amr/messengers/field_sum_transaction.hpp (1 hunks)
  • src/amr/messengers/hybrid_hybrid_messenger_strategy.hpp (19 hunks)
  • src/amr/messengers/hybrid_messenger.hpp (2 hunks)
  • src/amr/messengers/hybrid_messenger_info.hpp (1 hunks)
  • src/amr/messengers/hybrid_messenger_strategy.hpp (2 hunks)
  • src/amr/messengers/mhd_hybrid_messenger_strategy.hpp (4 hunks)
  • src/amr/messengers/refiner.hpp (7 hunks)
  • src/amr/messengers/refiner_pool.hpp (5 hunks)
  • src/amr/physical_models/hybrid_model.hpp (3 hunks)
  • src/amr/resources_manager/amr_utils.cpp (1 hunks)
  • src/amr/resources_manager/amr_utils.hpp (5 hunks)
  • src/amr/resources_manager/resources_manager.hpp (1 hunks)
  • src/amr/solvers/solver_ppc.hpp (9 hunks)
  • src/amr/utilities/box/amr_box.hpp (2 hunks)
  • src/core/data/field/field_box.hpp (1 hunks)
  • src/core/data/grid/grid.hpp (2 hunks)
  • src/core/data/grid/gridlayout.hpp (2 hunks)
  • src/core/data/ions/ion_population/ion_population.hpp (1 hunks)
  • src/core/data/ions/ions.hpp (2 hunks)
  • src/core/data/particles/particle_array.hpp (2 hunks)
  • src/core/numerics/ion_updater/ion_updater.hpp (7 hunks)
  • src/core/numerics/moments/moments.hpp (2 hunks)
  • src/core/numerics/pusher/pusher.hpp (1 hunks)
  • src/core/utilities/box/box.hpp (4 hunks)
  • src/core/utilities/cellmap.hpp (2 hunks)
  • src/core/utilities/point/point.hpp (3 hunks)
  • src/core/utilities/types.hpp (1 hunks)
  • src/diagnostic/detail/h5writer.hpp (1 hunks)
  • src/diagnostic/detail/types/fluid.hpp (1 hunks)
  • src/diagnostic/detail/types/particle.hpp (1 hunks)
  • src/diagnostic/diagnostic_model_view.hpp (4 hunks)
  • src/python3/patch_level.hpp (0 hunks)
  • tests/amr/data/field/refine/test_field_refine.cpp (1 hunks)
  • tests/amr/data/particles/copy/test_particledata_copyNd.cpp (3 hunks)
  • tests/amr/data/particles/copy_overlap/test_particledata_copy_periodicNd.cpp (2 hunks)
  • tests/amr/data/particles/stream_pack/test_main.cpp (4 hunks)
  • tests/amr/messengers/test_messengers.cpp (2 hunks)
  • tests/core/numerics/ion_updater/test_updater.cpp (8 hunks)
  • tests/diagnostic/__init__.py (1 hunks)
  • tests/diagnostic/test_diagnostics.hpp (1 hunks)
  • tests/diagnostic/test_diagnostics.ipp (1 hunks)
  • tests/functional/conservation/conserv.py (1 hunks)
  • tests/simulator/advance/test_particles_advance_1d.py (0 hunks)
  • tests/simulator/advance/test_particles_advance_2d.py (0 hunks)
  • tests/simulator/initialize/density_check.py (7 hunks)
  • tests/simulator/initialize/test_particles_init_1d.py (0 hunks)
  • tests/simulator/initialize/test_particles_init_2d.py (1 hunks)
  • tests/simulator/test_advance.py (1 hunks)
  • tests/simulator/test_initialization.py (1 hunks)
  • tools/bench/core/numerics/ion_updater/bench_ion_updater.cpp (2 hunks)
💤 Files with no reviewable changes (5)
  • tests/simulator/initialize/test_particles_init_1d.py
  • tests/simulator/advance/test_particles_advance_1d.py
  • src/python3/patch_level.hpp
  • tests/simulator/advance/test_particles_advance_2d.py
  • pyphare/pyphare/pharesee/hierarchy/hierarchy_utils.py
✅ Files skipped from review due to trivial changes (1)
  • pyphare/pyphare/pharein/diagnostics.py
🚧 Files skipped from review as they are similar to previous changes (47)
  • src/core/numerics/pusher/pusher.hpp
  • src/diagnostic/detail/h5writer.hpp
  • tests/diagnostic/test_diagnostics.ipp
  • pyphare/pyphare/pharesee/hierarchy/fromsim.py
  • tests/amr/data/particles/copy_overlap/test_particledata_copy_periodicNd.cpp
  • src/core/numerics/moments/moments.hpp
  • tests/amr/messengers/test_messengers.cpp
  • src/amr/resources_manager/resources_manager.hpp
  • pyphare/pyphare/pharesee/hierarchy/fromh5.py
  • tests/functional/conservation/conserv.py
  • tests/diagnostic/test_diagnostics.hpp
  • tests/amr/data/particles/stream_pack/test_main.cpp
  • src/core/utilities/cellmap.hpp
  • tests/diagnostic/init.py
  • src/amr/resources_manager/amr_utils.cpp
  • src/core/utilities/types.hpp
  • src/core/data/ions/ion_population/ion_population.hpp
  • src/amr/level_initializer/hybrid_level_initializer.hpp
  • tests/simulator/test_advance.py
  • pyphare/pyphare/pharesee/run/run.py
  • src/core/data/grid/grid.hpp
  • src/diagnostic/detail/types/particle.hpp
  • src/amr/data/field/refine/field_refine_operator.hpp
  • src/amr/messengers/communicator.hpp
  • src/core/data/ions/ions.hpp
  • tests/amr/data/field/refine/test_field_refine.cpp
  • src/amr/messengers/hybrid_messenger_strategy.hpp
  • src/amr/physical_models/hybrid_model.hpp
  • tests/simulator/test_initialization.py
  • src/core/data/particles/particle_array.hpp
  • src/amr/messengers/mhd_hybrid_messenger_strategy.hpp
  • tools/bench/core/numerics/ion_updater/bench_ion_updater.cpp
  • src/diagnostic/detail/types/fluid.hpp
  • src/core/data/grid/gridlayout.hpp
  • tests/simulator/initialize/density_check.py
  • src/amr/data/particles/particles_variable_fill_pattern.hpp
  • src/amr/messengers/hybrid_messenger_info.hpp
  • src/amr/utilities/box/amr_box.hpp
  • tests/simulator/initialize/test_particles_init_2d.py
  • src/core/utilities/box/box.hpp
  • src/amr/resources_manager/amr_utils.hpp
  • src/amr/data/particles/particles_data.hpp
  • src/amr/data/particles/refine/particles_data_split.hpp
  • src/core/utilities/point/point.hpp
  • src/amr/messengers/hybrid_messenger.hpp
  • src/amr/messengers/refiner_pool.hpp
  • src/amr/messengers/field_sum_transaction.hpp
🧰 Additional context used
📓 Path-based instructions (1)
**/*.hpp

⚙️ CodeRabbit Configuration File

Review the C++ code, point out issues relative to principles of clean code, expressiveness, and performance.

Files:

  • src/core/data/field/field_box.hpp
  • src/core/numerics/ion_updater/ion_updater.hpp
  • src/amr/solvers/solver_ppc.hpp
  • src/diagnostic/diagnostic_model_view.hpp
  • src/amr/data/field/field_variable_fill_pattern.hpp
  • src/amr/data/field/field_data.hpp
  • src/amr/messengers/refiner.hpp
  • src/amr/messengers/hybrid_hybrid_messenger_strategy.hpp
🧬 Code Graph Analysis (3)
src/core/data/field/field_box.hpp (1)
src/core/data/grid/grid.hpp (2)
  • field_ (86-86)
  • field_ (87-87)
tests/amr/data/particles/copy/test_particledata_copyNd.cpp (1)
src/core/utilities/types.hpp (2)
  • ConstArray (159-165)
  • ConstArray (159-159)
src/diagnostic/diagnostic_model_view.hpp (6)
src/core/data/ions/ions.hpp (9)
  • vector (220-223)
  • i (170-175)
  • i (170-170)
  • i (177-182)
  • i (177-177)
  • i (250-250)
  • i (250-250)
  • i (251-251)
  • i (251-251)
src/core/hybrid/hybrid_quantities.hpp (2)
  • auto (45-45)
  • auto (46-46)
src/amr/messengers/refiner.hpp (8)
  • rm (276-281)
  • rm (276-276)
  • rm (284-290)
  • rm (284-285)
  • rm (293-299)
  • rm (293-293)
  • rm (302-312)
  • rm (302-303)
src/amr/messengers/hybrid_hybrid_messenger_strategy.hpp (12)
  • ions (410-420)
  • ions (410-411)
  • ions (424-450)
  • ions (424-425)
  • ions (452-486)
  • ions (452-453)
  • ions (498-537)
  • ions (498-499)
  • ions (545-551)
  • ions (545-546)
  • patch (137-145)
  • patch (137-137)
src/amr/data/field/field_data.hpp (4)
  • patch (299-308)
  • patch (299-299)
  • patch (311-320)
  • patch (311-311)
src/amr/physical_models/hybrid_model.hpp (4)
  • patch (59-62)
  • patch (59-59)
  • patch (75-78)
  • patch (75-75)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
  • GitHub Check: build (macos-latest)
  • GitHub Check: build (macos-14)
  • GitHub Check: build (macos-13)
  • GitHub Check: Analyze (cpp)
  • GitHub Check: build (ubuntu-latest, gcc)
  • GitHub Check: build (ubuntu-latest, clang)
🔇 Additional comments (46)
tests/amr/data/particles/copy/test_particledata_copyNd.cpp (3)

112-138: Enhanced test verification aligns with architectural changes.

The explicit clearing and verification of particle containers (lines 112-119) improves test reliability by ensuring clean state between test phases. The introduction of newCell variable (line 120) enhances readability. The updated assertions (lines 129-137) correctly reflect the architectural shift where particles now go to domainParticles instead of patchGhostParticles, consistent with the removal of patch ghost particle handling mentioned in the AI summary.


190-191: Correct expectation update for new particle classification.

The swapped assertions properly reflect the architectural change where particles are now classified as domain particles instead of patch ghost particles during overlap operations.


253-255: Consistent particle classification update with transformation handling.

The updated assertions correctly expect particles in domainParticles rather than patchGhostParticles, and the transformation verification (line 255) properly validates the transformed cell index.

tests/core/numerics/ion_updater/test_updater.cpp (3)

507-509: Updated particle container expectations align with architectural changes.

The assertions correctly reflect the new particle classification where patch ghost particles are no longer used (size 0), while domain and level ghost particles remain populated.


746-746: Consistent interface update to use boxing abstraction.

All calls to ionUpdater.updatePopulations have been correctly updated to use the new boxing parameter instead of the direct layout, reflecting the improved modular design for particle selection logic.

Also applies to: 817-817, 837-837, 855-855


372-381: Assumption about level ghost cells holds

I’ve confirmed that the boxing region is only grown by GridLayout::nbrParticleGhosts() (i.e. the patch‐ghost layer) and does not include any level‐ghost cells. All level‐ghost particles in the test are explicitly added afterward, so the comment “assumes no level ghost cells” is accurate across all scenarios. No further changes required.

src/core/data/field/field_box.hpp (5)

16-26: Clean template design with appropriate type deduction.

The FieldBox template provides a good abstraction for field operations within spatial regions. The use of std::decay_t for value_type extraction is appropriate, and the static dimension constant provides compile-time access to dimensionality.


28-51: Well-designed constructors provide flexible initialization options.

The three constructors accommodate different use cases effectively:

  1. Default initialization using layout ghost boxes
  2. Explicit local coordinate selection
  3. AMR coordinate selection with automatic conversion

This design provides good flexibility for different spatial region specifications.


61-69: Generic field operation function with good safety checks.

The operate_on_fields function provides a clean generic interface for element-wise operations between field boxes. The size compatibility assertion (line 64) prevents undefined behavior, and the simultaneous iteration pattern is implemented correctly.


73-80: Correct implementation of vector-to-field operation.

The set_from method correctly implements the pattern for applying operators from vector data to field elements within the local box, with proper handling of the seek offset for vector positioning.


82-89: Simple and correct field-to-vector extraction.

The append_to method correctly extracts field values to a vector. The comment about reserving the vector (line 85) is helpful for performance optimization.

src/diagnostic/diagnostic_model_view.hpp (4)

8-39: Appropriate includes and type aliases for new functionality.

The new includes support the momentum tensor diagnostic capabilities, and the type aliases improve code clarity and maintainability. The static dimension constant provides useful compile-time access to dimensionality.


52-53: Proper initialization and tensor buffer for momentum diagnostics.

The constructor call to declareMomentumTensorAlgos() ensures proper initialization, and the sumTensor_ member provides the necessary buffer for momentum tensor sum operations.

Also applies to: 190-190


148-169: Proper setup of momentum tensor refinement algorithms.

The declareMomentumTensorAlgos method correctly initializes the refinement algorithms for momentum tensor operations, using the new FieldGhostInterpOverlapFillPattern and properly registering refinement operations for each tensor component.


171-189: Well-designed nested struct for refinement algorithm management.

The MTAlgo struct provides clean encapsulation of refinement algorithms and schedules. The lazy creation pattern in getOrCreateSchedule is efficient, and the use of FieldBorderSumTransactionFactory aligns with the new sum transaction infrastructure.

src/amr/data/field/field_variable_fill_pattern.hpp (3)

115-148: Excellent documentation explaining the fill pattern purpose.

The comprehensive documentation clearly explains why this specialized fill pattern is needed for incomplete ghost domain moment nodes, with helpful diagrams and detailed explanations of interpolation order effects. This greatly aids code understanding and maintenance.


159-198: Correct implementation of specialized ghost overlap calculation.

The calculateOverlap method properly handles the specialized case of ghost interpolation overlaps. The self-overlap skip condition (line 169-170) is appropriate, and the primal ghost box calculation with upper bound adjustment (line 177) correctly handles primal grid geometry.


205-218: Appropriate disabling of unsupported interface methods.

The runtime errors for getStencilWidth and computeFillBoxesOverlap correctly indicate that these interface methods are not applicable for this specialized fill pattern, providing clear feedback if they are inadvertently called.

src/core/numerics/ion_updater/ion_updater.hpp (4)

118-158: Excellent encapsulation of particle selection logic.

The UpdaterSelectionBoxing struct provides a clean abstraction that decouples particle selection from the updater implementation. The lambda-based selectors with appropriate capture semantics ensure proper behavior even with object copying.


211-213: Good architectural decision for level ghost particle handling.

The conditional processing of level ghost particles only when non-empty is a good optimization that avoids unnecessary work.


246-250: Patch ghost particle handling is intentional and should remain

  • Ripgrep shows patchGhostParticles is still widely used across the codebase (unit tests in test_particles_fixtures.hpp, test_updater.cpp, AMR copy tests, hybrid messenger, ParticlesData, ParticlePack, etc.).
  • The IonUpdater code relies on appending non-level ghosts into pop.patchGhostParticles() before running the interpolator on patch ghosts.
  • Existing tests in test_updater.cpp expect patchGhostParticles() to stay empty when there are no patch-ghost particles, and to be populated correctly otherwise.
  • Removing this copy would break both the interpolation logic and the tests that verify patch-ghost support.

No change needed here.


135-138: Lambda capture semantics are already consistent
Verified that all selectors in ion_updater.hpp use initializer captures ([domainBox = domainBox], [ghostBox = ghostBox], [nonLevelGhostBox = nonLevelGhostBox], and [ghostBox = ghostBox, domainBox = domainBox]) and that the noop selector rightly omits captures. No changes required.

src/amr/data/field/field_data.hpp (6)

42-44: Clean template alias definitions.

The type aliases Super, value_type, and SetEqualOp improve code readability and maintainability.


230-246: Efficient generic packing implementation.

The refactored packStream method using FieldBox and append_to provides a clean, generic approach that eliminates dimension-specific code duplication.


286-292: Excellent generic unpacking implementation.

The use of FieldBox with templated operators provides a flexible and clean implementation that supports both copy and sum operations.


323-325: New summation methods enhance AMR messaging capabilities.

The addition of sum and unpackStreamAndSum methods supports the new border sum transaction infrastructure, which is a key architectural improvement.


340-357: Generic operator-based copying is well-designed.

The templated copy_ method with operator parameter allows for both assignment and summation operations using the same code path, reducing duplication and improving maintainability.


449-455: Clean implementation of summation methods.

The unpackStreamAndSum and sum methods properly use the PlusEquals operator to implement summation behavior, integrating well with the generic template design.

src/amr/solvers/solver_ppc.hpp (3)

99-103: Good resource cleanup in onRegrid.

The onRegrid() method properly clears the boxing data structure and resets the ion updater, ensuring clean state after grid changes.


170-176: Well-designed level setup with boxing management.

The setup_level() method provides a clean interface that handles boxing lifecycle management transparently.


435-437: New border filling methods enhance AMR capabilities.

The addition of fillFluxBorders and fillDensityBorders methods integrates with the new border sum transaction infrastructure, providing essential functionality for the updated AMR messaging system.

src/amr/messengers/hybrid_hybrid_messenger_strategy.hpp (11)

8-46: LGTM - Include organization and type definitions are well-structured.

The new includes support the enhanced functionality (field operations, interpolation, SAMRAI integration), and the type alias definitions improve code readability and maintainability.


119-121: LGTM - New temporary sum fields properly registered.

The addition of sumVec_, sumField_, and sumTensor_ resources supports the new border sum functionality described in the PR objectives.


142-144: LGTM - Allocation calls match resource registration.

The allocation of sum fields is consistent with their registration in the constructor.


235-241: LGTM - New refiner registration follows established patterns.

The registration of domain ghost particle refiners and border sum refiners for flux and density follows the established pattern and correctly handles multiple refiners with loops.


494-534: LGTM - Simplified moment ghost filling aligns with architecture changes.

The removal of patch ghost particle deposition and focus on level ghost particles with time interpolation is consistent with the "patchghostless" objectives.


747-762: LGTM - Improved code organization with helper function and consistent fill patterns.

The use of makeKeys() helper and defaultFieldFillPattern improves consistency and readability compared to the previous node-only refiner approach.


788-806: LGTM - Well-structured registration of new refiners with appropriate fill patterns.

The registration of domain ghost particle refiners and border sum refiners uses appropriate specialized fill patterns and follows established coding patterns for multiple refiner registration.


737-743: LGTM - Clean utility function improves code reuse.

The makeKeys helper function provides a clean, functional approach to extracting vector names and reduces code duplication.


1058-1091: LGTM - Well-organized member variables with clear documentation.

The new sum fields and border sum refiner pools are properly typed, documented, and follow established naming conventions.


1148-1149: LGTM - Appropriate use of shared_ptr for fill pattern.

The shared_ptr usage for the stateless fill pattern is consistent with SAMRAI patterns and provides appropriate lifecycle management.


415-420: We need to gather the relevant code context around domainGhostPartRefiners_ in src/amr/messengers/hybrid_hybrid_messenger_strategy.hpp (declarations and how it’s used elsewhere) to understand what fill() does and whether clearing patchGhostParticles() afterward is still necessary. Please run:

#!/bin/bash
# Show class member declarations and related methods
grep -R "domainGhostPartRefiners_" -n src/amr/messengers/hybrid_hybrid_messenger_strategy.hpp

# Show the typedef or class of domainGhostPartRefiners_
grep -R "class .*Refiner" -n src/amr/messengers

# Print surrounding code for fillIonGhostParticles
sed -n '380,450p' src/amr/messengers/hybrid_hybrid_messenger_strategy.hpp

These snippets will clarify the type and behavior of domainGhostPartRefiners_ and whether it populates or depends on patchGhostParticles.

src/amr/messengers/refiner.hpp (4)

7-24: LGTM - Enum updates align with architecture changes.

The addition of PatchFieldBorderSum and ExteriorGhostParticles to the RefinerType enum and the new includes support the shift away from patch ghost handling described in the PR objectives.


77-84: LGTM - Proper implementation of border sum schedule creation.

The PatchFieldBorderSum case correctly uses FieldBorderSumTransactionFactory to handle the specialized summation requirements for border field data.


130-133: LGTM - Simple schedule creation for exterior ghost particles.

The ExteriorGhostParticles case appropriately uses the basic schedule creation for particle communication within the same level.


201-207: LGTM - Constructor refactoring improves maintainability.

The delegation to helper methods like register_time_interpolated_vector_field reduces code duplication and improves maintainability. The optional VariableFillPattern parameter provides needed flexibility.

Comment on lines +263 to +266
template<typename Operator = SetEqualOp>
void unpackStream(SAMRAI::tbox::MessageStream& stream,
const SAMRAI::hier::BoxOverlap& overlap, Grid_t& dst_grid)
{
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Verify template parameter consistency.

The templated unpackStream method should use consistent types throughout. The Operator template parameter defaults to SetEqualOp which is appropriate.

Check if the buffer type consistency issue mentioned in past reviews has been addressed:


🏁 Script executed:

#!/bin/bash
# Check for buffer type declarations in unpackStream methods
ast-grep --pattern $'std::vector<$_> buffer'

Length of output: 45


🏁 Script executed:

#!/bin/bash
# Display the unpackStream method with context
rg -C5 "template<typename Operator = SetEqualOp>.*unpackStream" src/amr/data/field/field_data.hpp -n

# Search for any use of 'buffer' in this file to verify type consistency
rg "buffer" src/amr/data/field/field_data.hpp -n

Length of output: 815


Unify buffer element types in unpackStream

The unpackStream implementation in src/amr/data/field/field_data.hpp currently declares two different buffer types—std::vector<value_type> for the pack phase and std::vector<double> for the unpack phase—which will break when value_type != double. Please choose a single element type (either double if the stream always serializes as double, or value_type if you want a pure binary copy) and adjust both buffers plus their size calculations to match.

• Lines 230–231: change

std::vector<value_type> buffer;
buffer.reserve(getDataStreamSize_(overlap) / sizeof(double));

to use the chosen type and sizeof(...) accordingly.
• Lines 275–276: change

std::vector<double> buffer(getDataStreamSize(overlap) / sizeof(value_type), 0.);

to the same element type and division by its sizeof.

Example diff if you decide to standardize on double:

--- a/src/amr/data/field/field_data.hpp
+++ b/src/amr/data/field/field_data.hpp
@@ -230,7 +230,7 @@
-            std::vector<value_type> buffer;
-            buffer.reserve(getDataStreamSize_(overlap) / sizeof(double));
+            std::vector<double> buffer;
+            buffer.reserve(getDataStreamSize_(overlap) / sizeof(double));
@@ -275,7 +275,7 @@
-            std::vector<double> buffer(getDataStreamSize(overlap) / sizeof(value_type), 0.);
+            std::vector<double> buffer(getDataStreamSize(overlap) / sizeof(double), 0.);
🤖 Prompt for AI Agents
In src/amr/data/field/field_data.hpp around lines 230-231 and 275-276, the
unpackStream function uses inconsistent buffer element types:
std::vector<value_type> in the pack phase and std::vector<double> in the unpack
phase, causing issues when value_type is not double. To fix this, choose a
single element type (either double or value_type) and update both buffer
declarations and their size calculations to use that type consistently,
adjusting the sizeof operator accordingly to ensure compatibility.

Comment on lines +58 to 60
template<typename Boxing_t>
void updatePopulations(Ions& ions, Electromag const& em, Boxing_t const& boxing, double dt,
UpdaterMode = UpdaterMode::all);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Improve template parameter constraints.

The templated updatePopulations method accepts a generic Boxing_t parameter but lacks constraints to ensure the boxing type has the required interface (layout, selector functions, etc.).

Consider adding a concept or static assertions to document and enforce the Boxing_t requirements:

+    template<typename Boxing_t>
+    concept BoxingType = requires(Boxing_t const& boxing) {
+        boxing.layout;
+        boxing.noop;
+        boxing.inDomainBox;
+        boxing.inGhostBox;
+        boxing.inNonLevelGhostBox;
+        boxing.inGhostLayer;
+    };
+
-    template<typename Boxing_t>
+    template<BoxingType Boxing_t>
     void updatePopulations(Ions& ions, Electromag const& em, Boxing_t const& boxing, double dt,
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
template<typename Boxing_t>
void updatePopulations(Ions& ions, Electromag const& em, Boxing_t const& boxing, double dt,
UpdaterMode = UpdaterMode::all);
// Add a concept to document and enforce the required Boxing_t interface
template<typename Boxing_t>
concept BoxingType = requires(Boxing_t const& boxing) {
boxing.layout;
boxing.noop;
boxing.inDomainBox;
boxing.inGhostBox;
boxing.inNonLevelGhostBox;
boxing.inGhostLayer;
};
// Constrain updatePopulations to only accept types satisfying BoxingType
template<BoxingType Boxing_t>
void updatePopulations(Ions& ions, Electromag const& em, Boxing_t const& boxing, double dt,
UpdaterMode = UpdaterMode::all);
🤖 Prompt for AI Agents
In src/core/numerics/ion_updater/ion_updater.hpp around lines 58 to 60, the
template parameter Boxing_t for the updatePopulations method lacks constraints
to ensure it meets the required interface. Add a concept or static_assert
statements to enforce that Boxing_t provides the necessary functions and types
such as layout and selector functions. This will document the requirements
clearly and cause compilation errors if Boxing_t does not conform, improving
code safety and clarity.

@nicolasaunai nicolasaunai merged commit 66f1230 into PHAREHUB:master Jul 26, 2025
13 checks passed
@PhilipDeegan PhilipDeegan deleted the patchghostless branch July 27, 2025 14:31
UCaromel pushed a commit to UCaromel/PHARE that referenced this pull request Aug 1, 2025
* PatchGhostLess

* comments

* Update particles_variable_fill_pattern.hpp

* slightly raise empirical threshold for PGL

* blackened \m/

* torm

* point conventions

---------

Co-authored-by: Nicolas Aunai <nicolas.aunai@lpp.polytechnique.fr>
PhilipDeegan added a commit to PhilipDeegan/PHARE that referenced this pull request Aug 7, 2025
* PatchGhostLess

* comments

* Update particles_variable_fill_pattern.hpp

* slightly raise empirical threshold for PGL

* blackened \m/

* torm

* point conventions

---------

Co-authored-by: Nicolas Aunai <nicolas.aunai@lpp.polytechnique.fr>
This was referenced Sep 17, 2025
@coderabbitai coderabbitai bot mentioned this pull request Oct 7, 2025
PhilipDeegan added a commit to PhilipDeegan/PHARE that referenced this pull request Oct 8, 2025
* PatchGhostLess

* comments

* Update particles_variable_fill_pattern.hpp

* slightly raise empirical threshold for PGL

* blackened \m/

* torm

* point conventions

---------

Co-authored-by: Nicolas Aunai <nicolas.aunai@lpp.polytechnique.fr>
UCaromel pushed a commit to UCaromel/PHARE that referenced this pull request Oct 14, 2025
* PatchGhostLess

* comments

* Update particles_variable_fill_pattern.hpp

* slightly raise empirical threshold for PGL

* blackened \m/

* torm

* point conventions

---------

Co-authored-by: Nicolas Aunai <nicolas.aunai@lpp.polytechnique.fr>
This was referenced Nov 5, 2025
This was referenced Jan 27, 2026
UCaromel pushed a commit to UCaromel/PHARE that referenced this pull request Feb 6, 2026
* PatchGhostLess

* comments

* Update particles_variable_fill_pattern.hpp

* slightly raise empirical threshold for PGL

* blackened \m/

* torm

* point conventions

---------

Co-authored-by: Nicolas Aunai <nicolas.aunai@lpp.polytechnique.fr>
This was referenced Feb 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants