Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

introduce charge, mass and particle densities #921

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

rochSmets
Copy link
Contributor

@rochSmets rochSmets commented Nov 3, 2024

The charge and mass of each ion population is now treated correctly.

Summary by CodeRabbit

Release Notes

  • New Features

    • Introduced a new fluid quantity, "charge_density," enhancing diagnostic capabilities.
    • Added functions for computing hierarchical data based on charge density in 1D and 2D.
    • Enhanced plotting features for better visualization of charge density data.
  • Bug Fixes

    • Updated error handling and validation processes for charge density computations.
  • Documentation

    • Updated references and examples to reflect the shift from "density" to "charge_density" across various modules and tests.
  • Tests

    • Adjusted test cases and validation methods to ensure consistency with the new charge density terminology.

@rochSmets rochSmets added the core label Nov 3, 2024
@rochSmets rochSmets added this to the 1.0 milestone Nov 3, 2024
Copy link

coderabbitai bot commented Nov 3, 2024

📝 Walkthrough

Walkthrough

The changes in this pull request primarily introduce a new fluid quantity, "charge_density", across various modules, enhancing the capabilities of the diagnostics framework. Multiple files have been updated to reflect this new quantity, with modifications to method signatures, variable names, and logic to accommodate the shift from general density to charge density. Additionally, several tests have been adjusted to validate the new diagnostic focus, ensuring that the functionality remains intact while improving clarity and specificity in data handling.

Changes

File Path Change Summary
pyphare/pyphare/pharein/diagnostics.py Added "charge_density" to fluid_quantities in FluidDiagnostics_.
pyphare/pyphare/pharesee/hierarchy/__init__.py Updated hierarchy_from method to include an optional func parameter.
pyphare/pyphare/pharesee/hierarchy/fromfunc.py Introduced functions for 1D and 2D hierarchies and a dispatcher function.
pyphare/pyphare/pharesee/hierarchy/hierarchy.py Enhanced plotting methods in PatchHierarchy, including size and grid updates.
pyphare/pyphare/pharesee/hierarchy/hierarchy_utils.py Added "charge_density": "rho" to field_qties. Modified compatibility checks and merging logic.
pyphare/pyphare/pharesee/plotting.py Updated file path for density data from "ions_density.h5" to "ions_charge_density.h5".
pyphare/pyphare/pharesee/run/run.py Changed quantities_per_file key from "ions_density" to "ions_charge_density".
pyphare_tests/test_pharesee/test_geometry_2d.py Adjusted plotting parameters in tests.
pyphare_tests/test_pharesee/test_hierarchy.py Updated FluidDiagnostics instantiation to use "charge_density".
src/amr/level_initializer/hybrid_level_initializer.hpp Replaced density computation with charge density in initialize method.
src/amr/messengers/hybrid_hybrid_messenger_strategy.hpp Renamed density variables to charge density in methods.
src/amr/physical_models/hybrid_model.hpp Updated ion density name to charge density in fillMessengerInfo.
src/amr/tagging/default_hybrid_tagger_strategy.hpp Commented out old density retrieval.
src/core/data/electrons/electrons.hpp Replaced density references with charge density in multiple classes.
src/core/data/ions/ion_population/ion_population.hpp Introduced separate variables for particle density and charge density.
src/core/data/ions/ions.hpp Updated methods to handle charge density instead of density.
src/core/numerics/interpolator/interpolator.hpp Updated interpolation method signatures to include charge density.
src/core/numerics/ion_updater/ion_updater.hpp Changed density computation to charge density in update methods.
src/core/numerics/moments/moments.hpp Updated reset and deposit functions to manage charge densities.
src/diagnostic/detail/types/fluid.hpp Incorporated charge density in various diagnostic methods.
src/phare/phare_init.py Updated diagnostic quantity in initialization loop.
src/phare/phare_init_small.py Changed diagnostic quantity from density to charge density.
src/python3/patch_level.hpp Updated density retrieval methods to use charge density.
tests/core/data/electrons/test_electrons.cpp Renamed density-related variables for clarity.
tests/core/data/ion_population/test_ion_population_fixtures.hpp Updated rho initialization to particle density.
tests/core/data/ions/test_ions.cpp Updated tests to check charge density instead of density.
tests/core/numerics/interpolator/test_main.cpp Added new grid variable for charge density in tests.
tests/core/numerics/ion_updater/test_updater.cpp Renamed density variables and updated methods to handle charge densities.
tests/diagnostic/__init__.py Updated diagnostic loops to include charge density.
tests/diagnostic/test_diagnostics.hpp Updated validation checks to use charge density.
tests/diagnostic/test_diagnostics.ipp Updated diagnostic dictionary entry to charge density.
tests/functional/alfven_wave/alfven_wave1d.py Updated diagnostic quantity from density to charge density.
tests/functional/dispersion/dispersion.py Renamed diagnostic quantity to charge density.
tests/functional/harris/harris_2d_lb.py Updated diagnostic quantity from density to charge density.
tests/functional/shock/shock.py Changed diagnostic quantity from density to charge density.
tests/functional/td/td1d.py Updated diagnostic quantity from density to charge density.
tests/functional/tdtagged/td1dtagged.py Changed diagnostic quantity from density to charge density.
tests/functional/translation/translat1d.py Updated diagnostic quantity from density to charge density.
tests/simulator/initialize/CMakeLists.txt Added command to execute a new Python test script for density initialization.
tests/simulator/initialize/test_density_init.py Implemented testing framework for ion mass and charge densities.
tests/simulator/refinement/test_2d_10_core.py Updated diagnostic quantity and visualization parameters.
tests/simulator/refinement/test_2d_2_core.py Renamed diagnostic quantity and updated visualization parameters.
tests/simulator/test_advance.py Updated diagnostic quantities and filenames for charge density.
tests/simulator/test_initialization.py Renamed diagnostic quantity in initialization methods.
tests/simulator/test_run.py Updated diagnostic quantity in FluidDiagnostics instantiation.

Suggested reviewers

  • nicolasaunai

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • 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 generate unit testing code for this file.
    • @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 generate unit testing code.
    • @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.

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 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 for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

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: 9

🧹 Outside diff range and nitpick comments (45)
.gdbinit (1)

1-3: LGTM! Consider enhancing the debug setup further.

The added debug commands provide essential breakpoints for catching critical issues during development, which is particularly valuable when dealing with physical quantities like charge and mass calculations.

Consider adding these additional commands for an enhanced debugging experience:

break __assert_fail
break abort
catch throw
+# Print backtrace automatically when hitting breakpoints
+set pagination off
+set confirm off
+set print pretty on
+set print array on
+set print array-indexes on

These additional settings will:

  • Disable pagination for continuous output
  • Enable pretty printing of structures
  • Show array contents with indexes
  • Make debugging sessions more efficient, especially when dealing with complex physical calculations
pyphare/pyphare/pharesee/hierarchy/fromfunc.py (3)

1-4: Remove unused numpy import

The numpy import is not used in the current implementation. Consider removing it to maintain clean imports.

-import numpy as np
🧰 Tools
🪛 Ruff

3-3: numpy imported but unused

Remove unused import: numpy

(F401)

🪛 GitHub Check: CodeQL

[notice] 3-3: Unused import
Import of 'np' is not used.


6-18: Add docstring documentation

The function implementation looks good, but it would benefit from docstring documentation explaining:

  • Purpose of the function
  • Parameters and their types
  • Return value structure
  • Example usage
 def hierarchy_from_func1d(func, hier, **kwargs):
+    """
+    Compute hierarchical data from a 1D function.
+    
+    Parameters
+    ----------
+    func : callable
+        Function to apply to x coordinates
+    hier : Hierarchy
+        1D hierarchy object
+    **kwargs : dict
+        Additional arguments passed to func
+    
+    Returns
+    -------
+    dict
+        Computed hierarchical data with value and centering information
+    """
     assert hier.ndim == 1

20-33: Remove redundant import and add documentation

The implementation looks good, but there are two improvements needed:

  1. Remove the redundant import of compute_hier_from as it's already imported at the top
  2. Add docstring documentation similar to the 1D function
-    from pyphare.pharesee.hierarchy.hierarchy_utils import compute_hier_from
+    """
+    Compute hierarchical data from a 2D function.
+    
+    Parameters
+    ----------
+    func : callable
+        Function to apply to (x,y) coordinates
+    hier : Hierarchy
+        2D hierarchy object
+    **kwargs : dict
+        Additional arguments passed to func
+    
+    Returns
+    -------
+    dict
+        Computed hierarchical data with value and centering information
+    """
src/core/numerics/moments/moments.hpp (1)

51-51: Consider reducing code duplication in deposit scenarios.

The three deposit scenarios (Domain, PatchGhost, LevelGhost) follow identical patterns with different particle arrays. Consider refactoring to reduce duplication.

 template<typename Ions, typename GridLayout, typename DepositTag>
 void depositParticles(Ions& ions, GridLayout& layout,
                       Interpolator<GridLayout::dimension, GridLayout::interp_order> interpolate,
                       DepositTag)
 {
     for (auto& pop : ions)
     {
         auto& particleDensity = pop.particleDensity();
         auto& chargeDensity   = pop.chargeDensity();
         auto& flux           = pop.flux();
+        auto& partArray = [&]() -> auto& {
+            if constexpr (std::is_same_v<DepositTag, DomainDeposit>)
+                return pop.domainParticles();
+            else if constexpr (std::is_same_v<DepositTag, PatchGhostDeposit>)
+                return pop.patchGhostParticles();
+            else if constexpr (std::is_same_v<DepositTag, LevelGhostDeposit>)
+                return pop.levelGhostParticlesOld();
+        }();
+        interpolate(partArray, particleDensity, chargeDensity, flux, layout);
-        if constexpr (std::is_same_v<DepositTag, DomainDeposit>)
-        {
-            auto& partArray = pop.domainParticles();
-            interpolate(partArray, particleDensity, chargeDensity, flux, layout);
-        }
-        else if constexpr (std::is_same_v<DepositTag, PatchGhostDeposit>)
-        {
-            auto& partArray = pop.patchGhostParticles();
-            interpolate(partArray, particleDensity, chargeDensity, flux, layout);
-        }
-        else if constexpr (std::is_same_v<DepositTag, LevelGhostDeposit>)
-        {
-            auto& partArray = pop.levelGhostParticlesOld();
-            interpolate(partArray, particleDensity, chargeDensity, flux, layout);
-        }
     }
 }

Also applies to: 56-56, 61-61

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

34-35: Consider using distinct quantity types for particle and charge densities.

Both densities currently use HybridQuantity::Scalar::rho. Consider introducing a separate scalar quantity type for charge density (e.g., HybridQuantity::Scalar::charge_rho) to better distinguish between these physically different quantities.


127-128: Consider adding documentation for density fields.

While the implementation is correct, consider adding brief comments explaining the physical meaning and units of these density fields to improve maintainability.


34-35: Consider type-safe representations for physical quantities.

To prevent potential mixing of particle and charge densities in calculations, consider using strong types or a quantity library (like Boost.Units) to enforce compile-time checking of physical units and quantities.

Also applies to: 127-128

tests/simulator/refinement/test_2d_10_core.py (1)

180-182: Potential visualization conflict in error collections.

Using the same value (1) for error collections as used in line 140 might cause confusion when both collections are present. Consider using a distinct value for error visualization to improve clarity.

                 {
                     "boxes": errors,
-                    "value": 1,
+                    "value": 3,  # Use a distinct value for errors
                 }
tests/functional/translation/translat1d.py (1)

90-91: Consider expanding charge-related changes beyond diagnostics

The PR aims to ensure correct treatment of charge and mass, but the changes are limited to diagnostic quantities. Consider whether other aspects of the simulation (initialization, field calculations, etc.) should also be updated to better reflect charge-specific behaviors.

Some areas to consider:

  • Explicit charge density initialization
  • Charge-dependent field calculations
  • Validation of charge conservation

Also applies to: 185-186

tests/core/data/ions/test_ions.cpp (1)

156-158: Enhance test coverage for charge density.

While this test verifies the exception behavior, consider adding tests to verify:

  1. Correct charge density calculation for single and multiple populations
  2. Proper handling of different ion charges
  3. Conservation of charge across populations

Would you like me to help generate additional test cases?

src/amr/tagging/default_hybrid_tagger_strategy.hpp (1)

39-39: Consider renaming variable 'N' to better reflect charge density.

The variable name 'N' typically represents number density in physics notation. Since this now stores charge density, consider renaming it to rho or chargeDensity for better clarity and maintainability.

tests/functional/harris/harris_2d_lb.py (1)

141-141: LGTM! Consider updating docstrings.

The change to "charge_density" for proton diagnostics is consistent with the PR's objective to properly handle charge properties of ion populations.

Consider adding a docstring to the config() function explaining the physical quantities being diagnosed, particularly the distinction between density and charge density.

tests/simulator/test_run.py (1)

145-146: LGTM! Consider adding documentation about density types.

The change from "density" to "charge_density" in the diagnostic quantities aligns well with the PR's objective of properly handling charge properties. The coexistence of both charge density (line 145) and particle density (lines 153-155) diagnostics is correct, as they represent different physical quantities.

Consider adding a comment explaining the distinction between charge density and particle density diagnostics to help future maintainers understand the purpose of each measurement.

+    # Global charge density diagnostic
     for quantity in ["charge_density", "bulkVelocity"]:
         ph.FluidDiagnostics(quantity=quantity, write_timestamps=timestamps)

     pop = "protons"
+    # Population-specific particle density diagnostic
     ph.FluidDiagnostics(
         quantity="density", write_timestamps=timestamps, population_name=pop
     )
src/python3/patch_level.hpp (2)

40-40: Consider renaming the method to better reflect its implementation.

The method name getDensity() might be misleading since it now returns charge density instead of regular density. Consider renaming it to getChargeDensity() for better clarity and to maintain consistency with the underlying implementation.

The change to use chargeDensity() is approved as it aligns with the PR objectives of correctly handling charge properties of ion populations.


62-63: Consider renaming the method to better reflect its implementation.

Similar to the previous comment, the method name getPopDensities() might be misleading since it now returns charge densities for populations. Consider renaming it to getPopChargeDensities() for better clarity.

The change to use chargeDensity() is approved as it aligns with the PR objectives.

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

30-30: LGTM! Consider adding documentation.

The change from "ions_density" to "ions_charge_density" better reflects the physical quantity being represented. However, consider adding a docstring to explain what "Ni" represents in this context.


154-154: LGTM! Consider documenting the physical relationship.

The file path change is consistent with using charge density. Consider adding a docstring explaining how electron pressure is calculated from charge density and electron temperature (Te).


Line range hint 30-154: Consider documenting the physical model.

The transition from generic density to charge density improves physical accuracy and code clarity. Consider adding a module-level docstring explaining:

  1. The relationship between charge density and number density
  2. How these quantities are used in pressure calculations
  3. The units of measurement for each quantity
src/core/numerics/ion_updater/ion_updater.hpp (2)

161-161: Consider documenting the density types.

The change to use both particleDensity and chargeDensity is correct. However, it would be helpful to add a brief comment explaining the difference between these density types for future maintainability.

+ // particleDensity represents the number of particles per unit volume
+ // chargeDensity represents the charge per unit volume
 interpolator_(inDomain, pop.particleDensity(), pop.chargeDensity(), pop.flux(), layout);

273-274: Improve line formatting for better readability.

The change to use particleDensity and chargeDensity is correct, but the line formatting could be improved to avoid the split across lines.

-        interpolator_(makeIndexRange(domainParticles), pop.particleDensity(), pop.chargeDensity(),
-                      pop.flux(), layout);
+        interpolator_(
+            makeIndexRange(domainParticles),
+            pop.particleDensity(),
+            pop.chargeDensity(),
+            pop.flux(),
+            layout);
src/core/data/electrons/electrons.hpp (3)

68-68: Consider renaming the density() method to chargeDensity().

While the implementation correctly returns charge density now, the method name density() could be misleading as it doesn't clearly indicate what type of density it returns. Consider renaming it to chargeDensity() for better clarity and consistency with the underlying implementation.

-    NO_DISCARD Field const& density() const
+    NO_DISCARD Field const& chargeDensity() const
     {
         if (isUsable())
         {
             return ions_.chargeDensity();
         }
         // ...
     }

-    NO_DISCARD Field& density()
+    NO_DISCARD Field& chargeDensity()
     {
         if (isUsable())
         {
             return ions_.chargeDensity();
         }
         // ...
     }

Also applies to: 81-81


115-115: Update comment and consider variable naming.

  1. The comment "from Ni because all components defined on primal" might need updating since we're now using charge density.
  2. While Ne is a common notation for electron density in physics, consider adding a type suffix to clarify it's charge density, e.g., Ne_charge.
-        auto const& Ne  = ions_.chargeDensity();
+        auto const& Ne_charge = ions_.chargeDensity();

-        // from Ni because all components defined on primal
-        layout.evalOnBox(Ne, [&](auto const&... args) {
+        // evaluate on primal grid points
+        layout.evalOnBox(Ne_charge, [&](auto const&... args) {
             auto arr = std::array{args...};

             auto const JxOnVx = GridLayout::project(Jx, arr, GridLayout::JxToMoments());
             auto const JyOnVy = GridLayout::project(Jy, arr, GridLayout::JyToMoments());
             auto const JzOnVz = GridLayout::project(Jz, arr, GridLayout::JzToMoments());

-            Vex(arr) = Vix(arr) - JxOnVx / Ne(arr);
-            Vey(arr) = Viy(arr) - JyOnVy / Ne(arr);
-            Vez(arr) = Viz(arr) - JzOnVz / Ne(arr);
+            Vex(arr) = Vix(arr) - JxOnVx / Ne_charge(arr);
+            Vey(arr) = Viy(arr) - JyOnVy / Ne_charge(arr);
+            Vez(arr) = Viz(arr) - JzOnVz / Ne_charge(arr);

Also applies to: 122-122, 129-131


214-214: Maintain consistent variable naming style.

The variable Ne_ uses an underscore suffix while other similar variables in the codebase don't. Consider removing the underscore to maintain consistency with the codebase style.

-        auto const& Ne_ = ions_.chargeDensity();
-        std::transform(std::begin(Ne_), std::end(Ne_), std::begin(Pe_),
+        auto const& Ne = ions_.chargeDensity();
+        std::transform(std::begin(Ne), std::end(Ne), std::begin(Pe_),
                        [this](auto n) { return n * Te_; });
pyphare/pyphare/pharesee/plotting.py (1)

Line range hint 277-281: Improve documentation and naming for clarity.

The variable name rho traditionally represents mass density in physics, but here it's being used for charge density. Consider:

  1. Updating the function's docstring to clarify that rho represents charge density
  2. Consider renaming the rho parameter to charge_density for clarity
  3. Update the error message at the end of the function to reflect this distinction
src/diagnostic/detail/types/fluid.hpp (1)

202-204: Consider documenting density types

The distinction between particleDensity() and chargeDensity() is important for users. Consider adding a brief comment explaining their differences and use cases.

Also applies to: 212-213

pyphare/pyphare_tests/test_pharesee/test_geometry_2d.py (1)

180-184: Document the meaning of collection values.

The numeric values (1 for overlap boxes, 2 for patch boxes) could benefit from a comment explaining their significance in the visualization context.

 collections=[
     {
         "boxes": overlap_boxes,
-        "value": 1,
+        "value": 1,  # Value 1 represents overlap boxes
     },
     {
         "boxes": [p.box for p in hierarchy.level(ilvl).patches],
-        "value": 2,
+        "value": 2,  # Value 2 represents patch boxes
     },
 ],
tests/core/data/electrons/test_electrons.cpp (1)

166-184: Consider adding documentation for the _ions helper function.

While the function implementation is correct, adding documentation would help explain:

  1. The purpose of this helper function
  2. The meaning of each parameter in the tuple
  3. The relationship between the parameters and the ions object being created
+    /**
+     * Helper function to create and initialize an IonsT object with the given resources.
+     * @param ionFlux - Flux field for ions
+     * @param ionChargeDensity - Charge density field for all ions
+     * @param ionMassDensity - Mass density field for all ions
+     * @param protonParticleDensity - Particle density field for protons
+     * @param protonChargeDensity - Charge density field for protons
+     * @param Vi - Ion velocity field
+     * @param ionTensor - Momentum tensor for all ions
+     * @param protonTensor - Momentum tensor for protons
+     * @param pack - Particle pack for initialization
+     * @return Initialized IonsT object
+     */
     template<typename... Args>
     auto static _ions(Args&... args)
src/core/numerics/interpolator/interpolator.hpp (1)

491-495: Consider optimizing repeated particleToMesh_ calls.

While the implementation is correct, the repeated calls to particleToMesh_ with similar parameters could be optimized. Consider creating a helper method that takes a tuple of fields and corresponding value extractors to reduce code duplication and potentially improve performance.

Example approach:

template<typename... Fields, typename... Extractors>
void interpolateFields(
    const std::tuple<Fields&...>& fields,
    const std::tuple<Extractors...>& extractors,
    const auto& particle,
    const auto& startIndex,
    const auto& weights,
    double coef)
{
    std::apply([&](auto&... args) {
        (particleToMesh_(args, particle, extractors, startIndex, weights, coef), ...);
    }, fields);
}
pyphare/pyphare/pharesee/hierarchy/hierarchy_utils.py (1)

39-39: Consider improving field quantity mapping clarity.

While the addition of "charge_density" aligns with the PR objectives, having multiple density types ("density", "mass_density", "charge_density") all mapped to "rho" could lead to confusion. Consider either:

  1. Adding documentation to clarify the distinction between these density types
  2. Using distinct field names to avoid potential confusion
+    # Field quantities mapping:
+    # - density: number density (particles per unit volume)
+    # - mass_density: mass per unit volume
+    # - charge_density: charge per unit volume
     "density": "rho",
     "mass_density": "rho",
     "charge_density": "rho",
tests/simulator/test_initialization.py (1)

475-475: Consider removing the commented debug print statement.

While not harmful, it's generally good practice to clean up commented debug statements before merging.

-                # print(patch.patch_datas.items())
tests/simulator/test_advance.py (1)

296-313: LGTM: Enhanced error reporting, but fix f-string.

The added error reporting with visualization is a valuable improvement for debugging. However, there's a minor issue:

-        fig.savefig(f"pd1.png")
+        fig.savefig("pd1.png")
🧰 Tools
🪛 Ruff

312-312: f-string without any placeholders

Remove extraneous f prefix

(F541)

src/core/data/ions/ions.hpp (3)

102-102: Consider Consistency in Mass Density Calculation

In computeMassDensity(), you're using pop.particleDensity() multiplied by pop.mass(). Ensure this aligns with how pop.chargeDensity() is calculated to maintain consistency between mass and charge density computations.

If pop.chargeDensity() already includes ion charge, consider creating a similar approach for mass density where pop.massDensity() could be used. This would enhance code clarity and symmetry.


175-176: Simplify Logical Expression in isUsable()

The logical expression in isUsable() can be simplified for better readability by initializing usable to true and using a range-based std::all_of algorithm.

Consider refactoring as follows:

-bool usable = chargeDensity_.isUsable() and bulkVelocity_.isUsable()
-              and momentumTensor_.isUsable() and massDensity_.isUsable();

-for (auto const& pop : populations_)
-{
-    usable = usable and pop.isUsable();
-}
-return usable;
+bool usable = chargeDensity_.isUsable() && bulkVelocity_.isUsable() &&
+              momentumTensor_.isUsable() && massDensity_.isUsable() &&
+              std::all_of(populations_.begin(), populations_.end(),
+                          [](auto const& pop) { return pop.isUsable(); });
+return usable;

This enhances readability and leverages the standard library for cleaner code.


189-190: Simplify Logical Expression in isSettable()

Similar to isUsable(), the isSettable() method's logic can be streamlined using std::all_of.

Refactor as follows:

-bool settable = massDensity_.isSettable() and chargeDensity_.isSettable()
-                and bulkVelocity_.isSettable() and momentumTensor_.isSettable();

-for (auto const& pop : populations_)
-{
-    settable = settable and pop.isSettable();
-}
-return settable;
+bool settable = massDensity_.isSettable() && chargeDensity_.isSettable() &&
+                bulkVelocity_.isSettable() && momentumTensor_.isSettable() &&
+                std::all_of(populations_.begin(), populations_.end(),
+                            [](auto const& pop) { return pop.isSettable(); });
+return settable;

This improves code clarity and consistency with modern C++ practices.

pyphare/pyphare/pharesee/hierarchy/hierarchy.py (3)

373-373: Consider renaming the subplot keyword argument for clarity

Using subplot as a keyword argument may be confusing since it is also a function in Matplotlib. Consider renaming it to fig_ax or axes to improve readability and avoid potential confusion.


387-390: Add validation for coordinate indices in coords

When assigning values using collection["coords"], consider adding checks to ensure that the indices are within the bounds of the ij array to prevent potential IndexError exceptions.


448-449: Remove commented-out code to improve code cleanliness

The commented-out line and remark can be removed to clean up the code and eliminate unnecessary comments.

Apply this diff to remove the unused code:

-    # nbrGhosts = layout.nbrGhostFor(qty) # bad !!!
tests/core/numerics/ion_updater/test_updater.cpp (2)

279-290: Simplify copy constructor using constructor delegation

To reduce code duplication and improve maintainability, consider delegating the copy constructor to the existing constructor by calling IonsBuffers(layout) and then copying the data. This approach is already used in ElectromagBuffers.

Apply this diff to modify the copy constructor:

 IonsBuffers(IonsBuffers const& source, GridLayout const& layout)
-    : ionChargeDensity{"chargeDensity", HybridQuantity::Scalar::rho,
-                       layout.allocSize(HybridQuantity::Scalar::rho)}
-    , ionMassDensity{"massDensity", HybridQuantity::Scalar::rho,
-                     layout.allocSize(HybridQuantity::Scalar::rho)}
-    , protonParticleDensity{"protons_particleDensity", HybridQuantity::Scalar::rho,
-                            layout.allocSize(HybridQuantity::Scalar::rho)}
-    , protonChargeDensity{"protons_chargeDensity", HybridQuantity::Scalar::rho,
-                          layout.allocSize(HybridQuantity::Scalar::rho)}
-    , alphaParticleDensity{"alpha_particleDensity", HybridQuantity::Scalar::rho,
-                           layout.allocSize(HybridQuantity::Scalar::rho)}
-    , alphaChargeDensity{"alpha_chargeDensity", HybridQuantity::Scalar::rho,
-                         layout.allocSize(HybridQuantity::Scalar::rho)}
-    // ... initialize other members
+    : IonsBuffers{layout}
 {
     // Copy data
     ionChargeDensity.copyData(source.ionChargeDensity);
     ionMassDensity.copyData(source.ionMassDensity);
     protonParticleDensity.copyData(source.protonParticleDensity);
     protonChargeDensity.copyData(source.protonChargeDensity);
     alphaParticleDensity.copyData(source.alphaParticleDensity);
     alphaChargeDensity.copyData(source.alphaChargeDensity);
     // ... copy other data
 }

668-673: Verify chargeDensity in addition to particleDensity

In checkDensityIsAsPrescribed, you are verifying particleDensity against the prescribed density function. To ensure consistency and correctness of chargeDensity, consider adding similar checks for chargeDensity.

Apply this diff to include chargeDensity in the verification:

 auto& populations           = this->ions.getRunTimeResourcesViewList();
 auto& protonParticleDensity = populations[0].particleDensity();
 auto& alphaParticleDensity  = populations[1].particleDensity();
+auto& protonChargeDensity   = populations[0].chargeDensity();
+auto& alphaChargeDensity    = populations[1].chargeDensity();

 check(protonParticleDensity, density);
 check(alphaParticleDensity, density);
+check(protonChargeDensity, density);
+check(alphaChargeDensity, density);
tests/simulator/initialize/test_density_init.py (5)

24-35: Refactor common code in ions_mass_density_func1d and ions_charge_density_func1d

The functions ions_mass_density_func1d and ions_charge_density_func1d share similar logic. Consider refactoring them into a single generic function to reduce code duplication and improve maintainability.

For example, you could create a generic function that accepts a factor (mass or charge) and computes the density:

def ions_density_func1d(x, factors, densities):
    assert len(factors) == len(densities)
    funcs = np.zeros((x.size, len(factors)))
    for i, (factor, density) in enumerate(zip(factors, densities)):
        funcs[:, i] = factor * density(x)
    return funcs.sum(axis=1)

Then use this function for mass and charge densities:

def ions_mass_density_func1d(x, masses, densities):
    return ions_density_func1d(x, masses, densities)

def ions_charge_density_func1d(x, charges, densities):
    return ions_density_func1d(x, charges, densities)

52-65: Refactor common code in ions_mass_density_func2d and ions_charge_density_func2d

Similar to the 1D case, the 2D functions share code. Refactoring them into a generic function will enhance code reuse and readability.

Example refactoring:

def ions_density_func2d(x, y, factors, densities):
    assert len(factors) == len(densities)
    yv, xv = np.meshgrid(y, x)
    funcs = np.zeros((x.size, y.size, len(factors)))
    for i, (factor, density) in enumerate(zip(factors, densities)):
        funcs[:, :, i] = factor * density(xv, yv)
    return funcs.sum(axis=2)

def ions_mass_density_func2d(x, y, masses, densities):
    return ions_density_func2d(x, y, masses, densities)

def ions_charge_density_func2d(x, y, charges, densities):
    return ions_density_func2d(x, y, charges, densities)

130-137: Refactor common population parameters into a helper function

The v_pop dictionaries in config_1d() and config_2d() are identical. Define v_pop once and reuse it to avoid code duplication.

For example, move v_pop to a shared scope:

v_pop = {
    "vbulkx": v0_func,
    "vbulky": v0_func,
    "vbulkz": v0_func,
    "vthx": vth_func,
    "vthy": vth_func,
    "vthz": vth_func,
}

Then adjust config_1d() and config_2d() accordingly, defining v0_func and vth_func based on dimensionality.

Also applies to: 212-219


258-274: Pass time as a parameter to assert_close_enough function

To improve code clarity and avoid relying on variables from the outer scope, pass time as an argument to assert_close_enough().

Apply this diff:

-def assert_close_enough(h, H):
+def assert_close_enough(h, H, time):
     for lvl_h, lvl_H in zip(h.levels(time).values(), H.levels(time).values()):
         # ... rest of the code ...

# Update function calls
-assert_close_enough(h1, H1)
+assert_close_enough(h1, H1, time)

-assert_close_enough(h2, H2)
+assert_close_enough(h2, H2, time)

327-328: Use a more descriptive filename for the output plot

The plot is saved as "nCheck.pdf", which may not clearly indicate its purpose. Consider renaming the file to better reflect its content.

For example:

-plt.savefig("nCheck.pdf", dpi=300)
+plt.savefig("density_validation.pdf", dpi=300)
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between e61b34c and fa838a0.

📒 Files selected for processing (46)
  • .gdbinit (1 hunks)
  • pyphare/pyphare/pharein/diagnostics.py (1 hunks)
  • pyphare/pyphare/pharesee/hierarchy/__init__.py (2 hunks)
  • pyphare/pyphare/pharesee/hierarchy/fromfunc.py (1 hunks)
  • pyphare/pyphare/pharesee/hierarchy/hierarchy.py (4 hunks)
  • pyphare/pyphare/pharesee/hierarchy/hierarchy_utils.py (1 hunks)
  • pyphare/pyphare/pharesee/plotting.py (1 hunks)
  • pyphare/pyphare/pharesee/run/run.py (3 hunks)
  • pyphare/pyphare_tests/test_pharesee/test_geometry_2d.py (3 hunks)
  • pyphare/pyphare_tests/test_pharesee/test_hierarchy.py (1 hunks)
  • src/amr/level_initializer/hybrid_level_initializer.hpp (1 hunks)
  • src/amr/messengers/hybrid_hybrid_messenger_strategy.hpp (2 hunks)
  • src/amr/physical_models/hybrid_model.hpp (1 hunks)
  • src/amr/tagging/default_hybrid_tagger_strategy.hpp (1 hunks)
  • src/core/data/electrons/electrons.hpp (4 hunks)
  • src/core/data/ions/ion_population/ion_population.hpp (5 hunks)
  • src/core/data/ions/ions.hpp (9 hunks)
  • src/core/numerics/interpolator/interpolator.hpp (3 hunks)
  • src/core/numerics/ion_updater/ion_updater.hpp (4 hunks)
  • src/core/numerics/moments/moments.hpp (2 hunks)
  • src/diagnostic/detail/types/fluid.hpp (5 hunks)
  • src/phare/phare_init.py (1 hunks)
  • src/phare/phare_init_small.py (1 hunks)
  • src/python3/patch_level.hpp (2 hunks)
  • tests/core/data/electrons/test_electrons.cpp (8 hunks)
  • tests/core/data/ion_population/test_ion_population_fixtures.hpp (1 hunks)
  • tests/core/data/ions/test_ions.cpp (1 hunks)
  • tests/core/numerics/interpolator/test_main.cpp (5 hunks)
  • tests/core/numerics/ion_updater/test_updater.cpp (12 hunks)
  • tests/diagnostic/__init__.py (1 hunks)
  • tests/diagnostic/test_diagnostics.hpp (4 hunks)
  • tests/diagnostic/test_diagnostics.ipp (1 hunks)
  • tests/functional/alfven_wave/alfven_wave1d.py (1 hunks)
  • tests/functional/dispersion/dispersion.py (1 hunks)
  • tests/functional/harris/harris_2d_lb.py (1 hunks)
  • tests/functional/shock/shock.py (1 hunks)
  • tests/functional/td/td1d.py (1 hunks)
  • tests/functional/tdtagged/td1dtagged.py (1 hunks)
  • tests/functional/translation/translat1d.py (2 hunks)
  • tests/simulator/initialize/CMakeLists.txt (1 hunks)
  • tests/simulator/initialize/test_density_init.py (1 hunks)
  • tests/simulator/refinement/test_2d_10_core.py (3 hunks)
  • tests/simulator/refinement/test_2d_2_core.py (3 hunks)
  • tests/simulator/test_advance.py (4 hunks)
  • tests/simulator/test_initialization.py (3 hunks)
  • tests/simulator/test_run.py (1 hunks)
🧰 Additional context used
📓 Path-based instructions (14)
src/amr/level_initializer/hybrid_level_initializer.hpp (1)

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

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

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

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

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

src/amr/tagging/default_hybrid_tagger_strategy.hpp (1)

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

src/core/data/electrons/electrons.hpp (1)

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

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

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

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

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

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

Pattern **/*.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 (1)

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

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

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

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

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

src/python3/patch_level.hpp (1)

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

tests/core/data/ion_population/test_ion_population_fixtures.hpp (1)

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

tests/diagnostic/test_diagnostics.hpp (1)

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

🪛 Ruff
pyphare/pyphare/pharesee/hierarchy/fromfunc.py

3-3: numpy imported but unused

Remove unused import: numpy

(F401)

tests/simulator/test_advance.py

312-312: f-string without any placeholders

Remove extraneous f prefix

(F541)

🪛 GitHub Check: CodeQL
pyphare/pyphare/pharesee/hierarchy/fromfunc.py

[notice] 3-3: Unused import
Import of 'np' is not used.


[notice] 35-35: Explicit returns mixed with implicit (fall through) returns
Mixing implicit and explicit returns may indicate an error as implicit returns always return None.

🔇 Additional comments (80)
tests/simulator/initialize/CMakeLists.txt (1)

23-24: LGTM! Verify test script existence.

The new test command follows the established pattern and is correctly placed within the HighFive conditional block.

Let's verify the test script exists:

✅ Verification successful

Test script exists and follows the expected path convention

The test_density_init.py script is present at the expected location tests/simulator/initialize/test_density_init.py, confirming that the CMake test command is properly configured and will not cause build failures.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify test_density_init.py exists in the correct location
# Expected: Script should be present in the tests/simulator/initialize directory

fd --type f "test_density_init.py$" --exec echo "Test script found: {}"

Length of output: 142

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

14-14: LGTM: Function signature extension maintains backward compatibility.

The addition of the optional func parameter at the end of the signature is well-designed, preserving compatibility with existing callers.

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

18-19: LGTM! Good separation of particle and charge density concerns.

The split between particleDensity and chargeDensity aligns well with the PR objectives and provides better clarity in handling different physical quantities.


44-46: Verify the updated interpolator interface across the codebase.

The interpolate function signature has been modified to handle both particle and charge density. Let's verify this change is consistent across the codebase.

Also applies to: 51-51, 56-56, 61-61

✅ Verification successful

The interpolator interface changes are consistent across the codebase

The review comment's concern about the interpolator interface changes has been verified. The code shows that:

  • The interpolate function in moments.hpp correctly uses the updated interface with particleDensity, chargeDensity, and flux parameters
  • The implementation in interpolator.hpp shows this is the correct interface, with the operator() method of the Interpolator class handling these parameters consistently
  • All calls to interpolate in the codebase (both in tests and source) follow this pattern
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check if the interpolator interface has been updated consistently
# Expected: All interpolate calls should include both particleDensity and chargeDensity

# Search for interpolate function declarations
ast-grep --pattern 'interpolate($$$particleDensity$$$, $$$chargeDensity$$$, $$$)'

# Search for any old-style interpolate calls that might have been missed
rg 'interpolate.*density.*flux' --type cpp

Length of output: 128


Script:

#!/bin/bash
# Let's try a broader search for interpolate function definitions and calls

# Search for interpolate function declarations/definitions
ast-grep --pattern 'interpolate($$$) {
  $$$
}'

# Search for interpolate function calls
ast-grep --pattern 'interpolate($$$)'

# Backup search using ripgrep for any interpolate mentions
rg 'interpolate\(' -A 2 -B 2 --type cpp

Length of output: 4507


Script:

#!/bin/bash
# Let's search for the interpolate function definition to verify its interface

# Search for interpolate function definition with more context
ast-grep --pattern 'template$$$
$$$interpolate($$$) {
  $$$
}'

# Also search for any header files that might contain the interpolate declaration
fd interpolator -e hpp -e h --exec cat {}

Length of output: 22398

tests/diagnostic/__init__.py (2)

31-36: LGTM! The diagnostic quantities align with PR objectives.

The change from "density" to specific "charge_density" and "mass_density" quantities improves clarity in physical property tracking.


44-44: Verify the consistency of density-related diagnostics.

There seems to be an inconsistency in how density quantities are handled:

  • The main loop uses "charge_density" and "mass_density" (removing "density")
  • The population loop keeps both "density" and "charge_density"
  • The population loop is missing "mass_density"

Consider either:

  1. Keeping only specific densities (charge, mass) for consistency with the main loop
  2. Adding "mass_density" to match the main loop's quantities
✅ Verification successful

Let me gather more information about the density-related quantities in the codebase.


Density-related diagnostics are correctly implemented

After analyzing the codebase, the current implementation is consistent:

  1. The main loop in tests/diagnostic/__init__.py correctly uses both charge_density and mass_density for total quantities.
  2. The population loop includes density and charge_density for per-population diagnostics, which is the correct approach since:
    • density represents the particle number density for each population
    • charge_density represents the charge contribution of each population
    • mass_density is only meaningful as a total quantity (main loop) and not per population

The current implementation follows a logical pattern where population-specific and total quantities are handled appropriately.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for consistency in density-related diagnostics across the codebase

# Search for density-related diagnostic configurations
echo "Searching for density diagnostic patterns..."
rg -A 5 "density.*write_timestamps" 

# Search for FluidDiagnostics usage with density quantities
echo "Searching for FluidDiagnostics with density quantities..."
ast-grep --pattern 'FluidDiagnostics(
  quantity=$_,
  $$$
)'

Length of output: 3835


Script:

#!/bin/bash
# Search for all density-related quantities in the test files
echo "Searching for density-related quantities in tests..."
rg -B2 -A2 '"(density|charge_density|mass_density)"' tests/

# Search for the main loop implementation
echo "Searching for main loop implementation..."
ast-grep --pattern 'for $_ in ["$$$"]:'

Length of output: 30516

src/phare/phare_init.py (1)

104-105: LGTM! Verify diagnostic data consumers.

The change from "density" to "charge_density" aligns well with the PR's objective of properly handling charge properties. This provides more precise terminology for the physical quantity being measured.

Let's verify if there are any diagnostic data consumers that need to be updated:

✅ Verification successful

Change from "density" to "charge_density" is safe to proceed

From the verification results, we found:

  • The change aligns with the supported diagnostic quantities in pyphare/pyphare/pharein/diagnostics.py
  • No test files or examples were found using the old "density" diagnostic name
  • The visualization module (pharesee/plotting.py) already expects "charge_density" in HDF5 files
  • No other direct consumers of the diagnostic data were found that depend on the old name
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Search for code that might be affected by the change from "density" to "charge_density"
# Look for potential consumers of diagnostic data that might expect the old name

# Search for files containing "density" in diagnostic-related paths
rg -g "**/{diagnostic,diag,plot,visual,post}*" "density"

# Search for HDF5 file operations involving density
rg "\.h5.*density"

Length of output: 713


Script:

#!/bin/bash
# Let's check for any test files or examples that might be using the old "density" diagnostic name
rg -g "**/{test,tests,example}*" "density.*diagnostic"

# Also search for Python files importing or using FluidDiagnostics
ast-grep --pattern 'from phare.phare_init import FluidDiagnostics'

# Check for direct usage of FluidDiagnostics in Python files
ast-grep --pattern 'FluidDiagnostics\(.*quantity.*=.*density'

Length of output: 189

src/phare/phare_init_small.py (1)

107-108: LGTM: Change from density to charge_density is correct.

The switch to charge_density in diagnostics aligns with the PR objectives to properly handle charge properties. This is consistent with the physical model since:

  1. The proton charge is set to 1 in the MaxwellianFluidModel
  2. The original density function is still correctly used for initialization

Let's verify the relationship between density and charge_density in the codebase:

✅ Verification successful

Change from density to charge_density is correctly implemented

The verification confirms that the change is consistent with the codebase implementation:

  • The chargeDensity field is properly integrated in the ion population model (ion_population.hpp)
  • The fluid diagnostics (fluid.hpp) correctly handles both individual population and total ion charge density outputs
  • The moments calculation (moments.hpp) shows proper deposit of charge density from particles
  • The electron model (electrons.hpp) uses ion charge density as expected in a hybrid model

The switch from "density" to "charge_density" in diagnostics maintains physical consistency since:

  1. The charge density is computed directly from particle deposits
  2. The electron model correctly uses ion charge density for quasi-neutrality
  3. Both individual population and total ion charge densities are properly tracked
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the relationship between density and charge_density
# Expected: Find implementations showing charge_density = charge * density

# Search for charge density calculations in source files
rg -g '!*.py' -l 'chargeDensity|charge_density' src/

# Search for related test cases
rg -g '*.cpp' -A 5 'TEST.*charge.*density' tests/

Length of output: 571


Script:

#!/bin/bash
# Let's examine the implementation details in key files

# Check ion population implementation for charge density calculation
rg -A 10 'chargeDensity|charge_density' src/core/data/ions/ion_population/ion_population.hpp

# Check fluid diagnostics implementation
rg -A 10 'chargeDensity|charge_density' src/diagnostic/detail/types/fluid.hpp

# Look for density to charge density relationship in moments
rg -A 10 'chargeDensity|charge_density' src/core/numerics/moments/moments.hpp

# Check electron implementation for charge density
rg -A 10 'chargeDensity|charge_density' src/core/data/electrons/electrons.hpp

Length of output: 8912

tests/functional/td/td1d.py (2)

Line range hint 103-107: LGTM! Change aligns with charge density focus.

The update from "density" to "charge_density" in the diagnostics configuration properly reflects the PR's objective of ensuring correct treatment of charge properties.


Line range hint 103-107: Verify diagnostic quantity name.

Let's verify that "charge_density" is a valid diagnostic quantity name across the codebase.

✅ Verification successful

"charge_density" is a valid diagnostic quantity name

The verification shows that "charge_density" is consistently used across the codebase:

  • It's a valid diagnostic quantity defined in pyphare/pyphare/pharein/diagnostics.py
  • Used in multiple test files and functional tests with FluidDiagnostics
  • Properly handled in the diagnostic implementation (src/diagnostic/detail/types/fluid.hpp)
  • Commonly paired with "bulkVelocity" in diagnostic configurations
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the usage of "charge_density" as a diagnostic quantity
# Expected: Find consistent usage of "charge_density" in diagnostic configurations

# Search for FluidDiagnostics configurations
rg -A 3 'FluidDiagnostics\(' 

# Search for any references to charge_density
rg 'charge_density'

Length of output: 14501

tests/diagnostic/test_diagnostics.ipp (1)

Line range hint 17-25: LGTM! The diagnostic path update aligns with the charge density transition.

The change from "density" to "charge_density" correctly reflects the PR's objective of properly handling charge properties for ion populations.

Let's verify that related test validation functions have been updated accordingly:

✅ Verification successful

The change from "density" to "charge_density" is correctly implemented and validated

The validation function validateFluidDump in tests/diagnostic/test_diagnostics.hpp already handles the transition correctly:

  • It validates the population-specific charge density: checkF(layout, path, "/ions/pop/" + pop.name(), "/density"s, pop.chargeDensity())
  • It validates the total ions charge density: checkF(layout, path, "/ions"s, "/charge_density"s, ions.chargeDensity())

Additionally, the diagnostic writer in src/diagnostic/detail/types/fluid.hpp shows consistent handling:

  • For populations: writes both density (particle density) and charge_density
  • For ions: writes both charge_density and mass_density
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for validateFluidDump usage and implementation to ensure consistency
rg -A 5 "validateFluidDump" --type cpp --type hpp

# Look for other potential density-related test validations that might need updates
ast-grep --pattern 'density()'

Length of output: 110


Script:

#!/bin/bash
# Search for validateFluidDump with correct file extensions
rg -A 5 "validateFluidDump" --type cpp --type-add 'hpp:*.{hpp,ipp}'

# Search for density-related test validations using ripgrep
rg -A 5 "density.*\(" --type cpp --type-add 'hpp:*.{hpp,ipp}'

# Look for fluid validation functions
rg -A 5 "validate.*Fluid" --type cpp --type-add 'hpp:*.{hpp,ipp}'

Length of output: 25890

tests/functional/dispersion/dispersion.py (1)

174-177: LGTM! The diagnostic changes align with the PR objectives.

The addition of "charge_density" diagnostic aligns with the PR's goal of correctly handling charge properties of ion populations.

Let's verify the impact of flush_every=0:

✅ Verification successful

flush_every=0 is consistent with other diagnostic configurations in the codebase

The codebase shows that:

  • flush_every=0 is equivalent to h5_flush_never used in other test files
  • This parameter is consistently used across electromagnetic and fluid diagnostics in the dispersion test
  • Other test files either omit this parameter (using default) or explicitly set it to never flush

The parameter choice is appropriate for this test scenario and aligns with similar diagnostic configurations in the codebase.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check if flush_every=0 is consistently used across similar test files
# and verify its implications in the codebase

# Search for other test files using FluidDiagnostics
rg -A 2 "FluidDiagnostics\(" "tests/"

# Look for any documentation or comments about flush_every
rg "flush_every" -g "*.rst" -g "*.md"

Length of output: 5176


Script:

#!/bin/bash
# Let's search for the definition of FluidDiagnostics to understand the flush_every parameter
ast-grep --pattern 'class FluidDiagnostics'

# Also search for any comments or documentation about flush_every in Python files
rg -B 2 -A 2 "flush_every" "**/*.py"

Length of output: 130


Script:

#!/bin/bash
# Search for flush_every in Python files (corrected path)
rg -B 2 -A 2 "flush_every" tests/

# Look for FluidDiagnostics class definition
rg -B 5 -A 5 "class FluidDiagnostics"

Length of output: 4889

tests/simulator/refinement/test_2d_2_core.py (3)

173-173: LGTM! Parameter change maintains consistency.

The change from "facecolor" to "value" maintains consistency with the earlier visualization parameter changes.


116-124: Verify visualization system compatibility with parameter change.

The change from "facecolor" to "value" in the patch visualization parameters needs verification to ensure it doesn't break existing visualization functionality.

#!/bin/bash
# Description: Check for consistent usage of visualization parameters
# Expect: All similar visualization code should use the same parameter name

echo "Checking for other visualization parameter usage patterns..."
rg -g '*.py' 'plot_2d_patches.*facecolor|plot_2d_patches.*value' tests/

104-105: LGTM! Verify consistent terminology across test suite.

The change from "density" to "charge_density" aligns with the PR's objective to properly handle charge properties.

✅ Verification successful

This script will help us:

  1. Find all usages of FluidDiagnostics to understand the diagnostic patterns
  2. Specifically look for any density-related diagnostic quantities to verify consistency

This script will help us examine the actual quantity values used in all files that contain FluidDiagnostics, giving us the context needed to verify the terminology consistency.


Terminology change is consistent across the test suite

The search results confirm that all FluidDiagnostics instances using density-related quantities consistently use "charge_density" instead of "density", specifically in:

  • tests/simulator/test_run.py
  • tests/functional/tdtagged/td1dtagged.py
  • tests/functional/harris/harris_2d_lb.py

The only remaining "density" usage appears in tests/simulator/test_run.py but it's used with a different diagnostic type, not with FluidDiagnostics.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify consistent use of "charge_density" across test files
# Expect: All diagnostic quantity specifications use "charge_density" instead of "density"

echo "Checking for any remaining 'density' diagnostic quantities in test files..."
rg -g 'test_*.py' 'FluidDiagnostics.*density' tests/

Length of output: 298


Script:

#!/bin/bash
# Let's try a more comprehensive search for diagnostic quantities
echo "Searching for FluidDiagnostics usage patterns..."
rg -g '*.py' 'FluidDiagnostics\(' tests/

echo -e "\nSearching specifically for density-related diagnostics..."
rg -g '*.py' 'quantity\s*=\s*["\'](?:charge_)?density' tests/

Length of output: 2466


Script:

#!/bin/bash
# Let's search for the actual quantity values in these files
echo "Searching for diagnostic quantity specifications..."
for file in $(rg -l 'FluidDiagnostics' tests/); do
    echo "=== $file ==="
    rg -A 1 'quantity\s*=' "$file"
done

Length of output: 7300

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

50-50: LGTM! Clean implementation of resource validation.

The implementation correctly validates both density fields and follows a consistent parameter ordering that matches the member declarations.

Also applies to: 55-55


79-83: LGTM! Well-designed accessor methods.

The implementation follows C++ best practices:

  • Proper const-correctness
  • NO_DISCARD prevents accidental value dropping
  • Clean, inline implementations

102-103: LGTM! Efficient resource view implementation.

The implementation correctly includes both density fields and uses std::forward_as_tuple for optimal performance.

tests/functional/shock/shock.py (2)

110-111: LGTM! The diagnostic quantity change aligns with PR objectives.

The change from "density" to "charge_density" properly reflects the physical quantity being measured, which is consistent with the PR's goal of ensuring correct charge handling for ion populations.


110-111: Verify visualization code compatibility with charge_density.

While the diagnostic quantity has been updated, the visualization code in the main() function only plots magnetic field components. Consider adding visualization for charge density to validate the new diagnostic output.

Would you like me to provide an example implementation for visualizing the charge density alongside the magnetic field components?

tests/simulator/refinement/test_2d_10_core.py (2)

140-140: Clarify the visualization value mapping.

The change from descriptive colors ("grey", "yellow") to numeric values (1, 2) might affect visualization clarity. Please clarify:

  1. How do these numeric values map to colors?
  2. Is there a color scheme defined elsewhere in the codebase?

Also applies to: 148-148


104-105: Verify test expectations with new charge_density diagnostic.

The change from "density" to "charge_density" aligns with the PR objectives. However, please ensure that:

  1. The test expectations have been updated to account for this change
  2. The combination of "charge_density" and "bulkVelocity" diagnostics is sufficient for the test's purpose
✅ Verification successful

The diagnostic changes are safe to proceed

The change from "density" to "charge_density" is verified to be safe because:

  1. The test file uses these diagnostics only for data collection, not in any assertions
  2. Both "charge_density" and "bulkVelocity" diagnostics are used together with electromagnetic diagnostics ("E", "B") for a complete simulation state capture
  3. The actual field comparisons are handled by generic test utilities that compare hierarchical data structures, not specific diagnostic names
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check if test expectations or assertions depend on the old "density" diagnostic
rg -A 5 "density.*assert" tests/

Length of output: 673


Script:

#!/bin/bash
# Let's search for any test assertions or verifications related to diagnostics
rg -B 2 -A 5 "assert.*(?i)diagnos" tests/simulator/refinement/test_2d_10_core.py

# Also check for any test verification patterns in the specific test file
rg -B 2 -A 5 "assert|verify|check|compare" tests/simulator/refinement/test_2d_10_core.py

# Look for any diagnostic configuration or setup in the test
ast-grep --pattern 'FluidDiagnostics($$$)'

Length of output: 3571


Script:

#!/bin/bash
# Let's check how the test file uses these diagnostics
rg -B 5 -A 10 "charge_density|bulkVelocity" tests/simulator/refinement/test_2d_10_core.py

# Also check for any test validation or comparison logic
ast-grep --pattern 'test.base_test_$_($$$)'

Length of output: 606

tests/functional/translation/translat1d.py (2)

185-186: Review temperature calculation with respect to charge density

The temperature calculation (T(x)) uses the plain density function. Consider whether this should be adjusted to account for charge effects, especially since we're now tracking charge density in diagnostics.


90-91: Verify physical consistency between initialization and diagnostics

While the diagnostic now correctly uses "charge_density", the initialization in MaxwellianFluidModel still uses a plain density function. Please verify that the relationship between the initialization density and the diagnosed charge density is physically correct.

✅ Verification successful

Let me gather more information about the initialization to understand the relationship between density and charge density.


No inconsistency between initialization and diagnostics

The change from "density" to "charge_density" in diagnostics is correct and consistent with the initialization. Here's why:

  • The MaxwellianFluidModel initialization takes "density" and "charge" as separate parameters for each species
  • The charge density diagnostic is automatically computed as the product of density and charge for each species
  • This is evidenced by the test implementations in test_density_init.py where ions_charge_density_func explicitly combines charges and densities
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for other test files to see if they maintain consistency between initialization and diagnostics
rg -l "MaxwellianFluidModel" | xargs rg "charge_density"

Length of output: 3014


Script:

#!/bin/bash
# Search for MaxwellianFluidModel initialization and density handling
ast-grep --pattern 'MaxwellianFluidModel($$$)'

# Also check for density-related functions and their implementations
rg -A 5 "def.*density" tests/simulator/initialize/test_density_init.py

Length of output: 4442

tests/functional/alfven_wave/alfven_wave1d.py (1)

99-100: LGTM! The diagnostic quantity change aligns with PR objectives.

The change from "density" to "charge_density" in FluidDiagnostics is appropriate for plasma simulations and consistent with the PR's focus on proper charge handling.

Let's verify the consistency of this change across other test files:

✅ Verification successful

Change to charge_density is consistent across the codebase

The search results confirm that all test files using FluidDiagnostics consistently use "charge_density" instead of plain "density" for diagnostics. This change aligns with the PR's focus on proper charge handling and is consistently implemented across the test suite.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify consistent usage of charge_density in other test files
# Expect: All test files should use charge_density instead of density in FluidDiagnostics

# Search for any remaining usage of plain density in FluidDiagnostics
rg -l 'FluidDiagnostics.*density[^_]' tests/

Length of output: 46


Script:

#!/bin/bash
# Let's try a broader search to find all FluidDiagnostics quantity parameters
rg -A 1 'FluidDiagnostics\(.*quantity' tests/

# Also search for all density-related diagnostics to ensure completeness
rg 'density' tests/ --type py

Length of output: 19453

tests/core/data/ions/test_ions.cpp (1)

157-157: LGTM! Change aligns with PR objectives.

The update from density() to chargeDensity() correctly reflects the focus on proper charge handling in ion populations.

tests/core/data/ion_population/test_ion_population_fixtures.hpp (1)

53-53: Verify consistent usage of particle density terminology

Let's ensure this semantic change is consistently applied across the codebase.

✅ Verification successful

Based on the shell script results, I can now generate the final response:

Naming convention for particle density is consistent across the codebase

The verification shows that:

  • The naming pattern {population}_particleDensity is consistently used across the codebase
  • HybridQuantity::Scalar::rho is correctly used as the underlying quantity type
  • All test files and implementations follow this convention
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for potential inconsistencies in density-related naming

echo "Checking for rho vs particle density naming inconsistencies..."
rg -l "rho|density" --type cpp

echo "\nChecking for HybridQuantity::Scalar::rho usage..."
ast-grep --pattern 'HybridQuantity::Scalar::rho'

echo "\nChecking for related test assertions..."
rg -A 2 "TEST|EXPECT" --type cpp | grep -i "density"

Length of output: 12862

tests/functional/harris/harris_2d_lb.py (1)

137-137: Verify plot compatibility with the new diagnostic quantity name.

The change from "density" to "charge_density" correctly reflects the physical quantity being measured. However, ensure that the plotting functions in the plot() method (which uses GetN()) are compatible with this change.

✅ Verification successful

The change from "density" to "charge_density" is safe and compatible with plotting functions

The code inspection shows that:

  • The plotting code in harris_2d_lb.py uses GetN() which is independent of the diagnostic quantity name
  • The diagnostics system (FluidDiagnostics_) supports both "density" and "charge_density" as valid fluid quantities
  • The change correctly reflects the physical quantity being measured while maintaining compatibility with visualization code
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for any plotting functions that might still reference the old "density" name
rg -l 'GetN|density' --type py

Length of output: 1626


Script:

#!/bin/bash
# Let's check the actual usage of density/charge_density in plotting related code
rg -A 5 -B 5 'GetN|density' pyphare/pyphare/pharesee/plotting.py

# Also check the diagnostic configuration to see if it handles both names
rg -A 5 -B 5 'density|charge_density' pyphare/pyphare/pharein/diagnostics.py

# Check the specific test file for any plotting code
rg -A 5 -B 5 'plot|GetN|density' tests/functional/harris/harris_2d_lb.py

Length of output: 5705

tests/functional/tdtagged/td1dtagged.py (1)

123-123: LGTM: Change aligns with physics requirements.

The switch from "density" to "charge_density" in FluidDiagnostics correctly reflects the PR's focus on proper charge handling for ion populations.

Let's verify consistency across other test files:

✅ Verification successful

Change from "density" to "charge_density" is consistent across the codebase

The search results confirm that the change from "density" to "charge_density" in FluidDiagnostics is consistently implemented across the test files. All functional tests and simulator tests now use "charge_density" instead of "density" when configuring general fluid diagnostics. The only remaining uses of "density" are specifically for population-specific diagnostics where both "density" and "charge_density" are valid and serve different purposes.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check if all test files have been updated to use charge_density
# consistently in their FluidDiagnostics configurations

# Search for any remaining uses of "density" in FluidDiagnostics
rg -A 2 -B 2 'FluidDiagnostics.*density' 'tests/'

# Search for new uses of "charge_density"
rg -A 2 -B 2 'FluidDiagnostics.*charge_density' 'tests/'

Length of output: 106


Script:

#!/bin/bash
# Let's try a different approach to find diagnostic configurations in test files

# Search for any test files that contain "FluidDiagnostics"
fd . tests/ -e py -x rg -l "FluidDiagnostics" {}

# Then let's look at the content around "quantity" or "quantities" in these files
# to see the diagnostic configurations
rg -B 3 -A 3 'quantity.*=|quantities.*=' tests/

Length of output: 29236

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

157-157: LGTM! Improved physics representation.

The change from densityName() to chargeDensityName() better reflects the physical quantity being used and aligns with the PR's objective of ensuring correct treatment of charge properties.


157-157: Verify consistent usage of charge density across the codebase.

Let's ensure this naming change is consistently applied in related components.

✅ Verification successful

Let me try a different search strategy to specifically look for charge density related functions and their usage.


Let me check the specific implementation and usage of charge density in the core files.


No inconsistencies found in charge density usage across the codebase

Based on the code analysis, the charge density implementation is consistent throughout the codebase:

  • In ions.hpp, the charge density is properly defined with a consistent name through chargeDensityName() static method
  • The Electrons class correctly uses the ions' charge density through the StandardHybridElectronFluxComputer
  • The charge density is consistently used for computing electron properties and maintaining charge conservation
  • Test files show proper initialization and usage of the charge density field
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for any remaining usage of the old density name and verify consistent usage of charge density

# Search for old density name usage in hpp/cpp files
echo "Checking for old density name usage..."
rg -t cpp -t hpp "densityName\(\)" -A 5

# Search for new charge density name usage to verify consistency
echo "Checking charge density name usage..."
rg -t cpp -t hpp "chargeDensityName\(\)" -A 5

# Search for related density terminology in diagnostic configurations
echo "Checking diagnostic configurations..."
rg -t py "density.*=|charge_density.*=" -A 5

Length of output: 13731


Script:

#!/bin/bash
# Search for charge density related functions and their usage
ast-grep --pattern 'chargeDensityName()' 

# Search for any density related functions in hpp files
fd -e hpp -x rg -l "density" {} \;

# Search for any charge density related functions in cpp files
fd -e cpp -x rg -l "chargeDensity|charge_density" {} \;

Length of output: 1275


Script:

#!/bin/bash
# Check the implementation in ions.hpp
echo "Content of ions.hpp:"
cat src/core/data/ions/ions.hpp

# Check tests for charge density usage
echo "Content of test_ions.cpp:"
cat tests/core/data/ions/test_ions.cpp

# Check electron implementation for charge density usage
echo "Content of electrons.hpp:"
cat src/core/data/electrons/electrons.hpp

Length of output: 25382

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

101-102: Verify the computation sequence.

The order of operations is crucial for physics accuracy:

  1. Charge density computation
  2. Bulk velocity computation

Please verify that this sequence aligns with the physical model requirements and doesn't introduce any temporal dependencies.

Let's check the implementation of these computations:

✅ Verification successful

Computation sequence is correctly ordered

The implementation shows that computeBulkVelocity() depends on charge density data:

  • computeChargeDensity() zeroes and computes the charge density first
  • computeBulkVelocity() internally calls computeMassDensity() and uses the previously computed charge density data

This sequence is found consistently across the codebase in:

  • src/core/numerics/ion_updater/ion_updater.hpp
  • src/amr/level_initializer/hybrid_level_initializer.hpp
  • tests/core/numerics/ion_updater/test_updater.cpp

The current order maintains proper temporal dependencies and aligns with physical model requirements.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Examine the implementation of charge density and bulk velocity computations

# Look for the implementation of computeChargeDensity
echo "Examining charge density computation implementation:"
ast-grep --pattern 'computeChargeDensity() {
  $$$
}'

# Look for the implementation of computeBulkVelocity
echo "Examining bulk velocity computation implementation:"
ast-grep --pattern 'computeBulkVelocity() {
  $$$
}'

Length of output: 433


Script:

#!/bin/bash
# Let's try a different approach to find these methods
# Search for files containing these method names first
echo "Files containing computeChargeDensity:"
rg -l "computeChargeDensity"

echo -e "\nFiles containing computeBulkVelocity:"
rg -l "computeBulkVelocity"

# Then examine the implementation with context
echo -e "\nImplementation of computeChargeDensity:"
rg "computeChargeDensity" -A 10

echo -e "\nImplementation of computeBulkVelocity:"
rg "computeBulkVelocity" -A 10

Length of output: 10565


101-101: LGTM: Change aligns with PR objectives.

The switch from computeDensity() to computeChargeDensity() correctly implements the PR's goal of properly handling ion charge properties. The change is made in the appropriate context, after particle deposition and before bulk velocity computation.

Let's verify that all related ion density computations have been updated consistently:

✅ Verification successful

Based on the extensive search results, I can now verify the review comment. The codebase shows that:

  1. The change from computeDensity() to computeChargeDensity() is consistent with the overall architecture where:

    • Each ion population has both particleDensity and chargeDensity fields
    • The computeChargeDensity() method is used consistently across the codebase
    • The method is called after particle deposition and before bulk velocity computation
  2. The change is part of a well-structured system where:

    • Ion populations track both particle and charge densities separately
    • The charge density is used by the electron model and other components
    • The computation sequence is consistent with the physics requirements

Change is correct and properly integrated

The switch to computeChargeDensity() is verified to be the correct approach, as it's used consistently throughout the codebase for handling ion charge properties and is called at the appropriate point in the initialization sequence.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for any remaining references to the old density computation
# and verify the new charge density computation is used consistently

# Search for any remaining calls to computeDensity
echo "Checking for remaining computeDensity() calls:"
rg "computeDensity\(\)" -A 3

# Search for new computeChargeDensity calls to verify consistent usage
echo "Verifying computeChargeDensity() usage pattern:"
rg "computeChargeDensity\(\)" -A 3

Length of output: 433


Script:

#!/bin/bash
# Let's try a more comprehensive search for both old and new methods
echo "Searching for density computation methods:"
rg -i "density|charge" --type cpp -A 3

# Also search for the specific class implementation
echo "Searching for IonPopulation class implementation:"
fd -e hpp -e cpp -e h | xargs rg "class.*IonPopulation" -A 10

# Look for test files related to density computation
echo "Searching for related test files:"
fd -e cpp test | xargs rg -i "density|charge" -A 3

Length of output: 149168

pyphare/pyphare_tests/test_pharesee/test_hierarchy.py (2)

148-149: Verify GetNi() method compatibility with charge density changes.

The test cases use GetNi() to retrieve ion-related data. Since we've switched from "density" to "charge_density" in diagnostics, we should verify that this method still returns the expected data.

Let's check the implementation:

Also applies to: 169-172, 241-244

✅ Verification successful

The git log output shows that GetNi() has indeed been updated to use ions_charge_density.h5 instead of ions_density.h5. Let me verify if this change is consistent across the codebase.


GetNi() method has been properly updated for charge density compatibility

The verification shows that:

  • The GetNi() method has been updated to use ions_charge_density.h5 instead of ions_density.h5
  • All references to ions_density.h5 have been removed from the codebase
  • All relevant files consistently use ions_charge_density.h5

The changes are consistent across the codebase, and the method will return the expected charge density data.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify GetNi implementation and its relation to charge density
# Expected: Find the implementation and any related changes

# Search for GetNi implementation
ast-grep --pattern 'def GetNi' 

# Search for recent changes to GetNi
git log -p --since="1 month ago" | rg -A 10 'GetNi'

Length of output: 5966


Script:

#!/bin/bash
# Search for any remaining references to ions_density.h5
rg "ions_density\.h5"

# Search for references to ions_charge_density.h5
rg "ions_charge_density\.h5"

# Look for any test assertions or verifications related to GetNi
rg -A 5 "assert.*GetNi"

Length of output: 758


148-149: LGTM! The diagnostic quantity change aligns with the PR objectives.

The change from "density" to "charge_density" in FluidDiagnostics configuration correctly reflects the shift to proper charge density handling for ion populations.

Let's verify the test coverage for the new charge density diagnostic:

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

117-117: Verify simulation output files and consider method documentation.

The file path change is consistent with the new charge density nomenclature. However:

  1. Ensure all simulation output files have been updated to use the new "ions_charge_density.h5" naming.
  2. Consider adding method documentation to clarify that this returns charge density, not just number density.
✅ Verification successful

Let me gather more information about the method and its usage to better understand the context.


File path change is consistent with the codebase

The change from "ions_density.h5" to "ions_charge_density.h5" is correct and consistent with the codebase for the following reasons:

  1. The GetNi method is specifically returning charge density as evidenced by the implementation and usage throughout the codebase.
  2. The new filename "ions_charge_density.h5" is used consistently in tests and diagnostics (e.g., in tests/simulator/test_advance.py, tests/diagnostic/test_diagnostics.hpp).
  3. The method name "GetNi" aligns with the internal variable naming convention where "Ni" represents ion charge density (as seen in src/core/data/electrons/electrons.hpp).
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for any remaining references to old filename
# and verify existence of new filename in test data

# Search for old filename references
echo "Checking for old filename references:"
rg "ions_density\.h5"

# Search for test data files
echo "Checking test data files:"
fd "ions_charge_density.h5"

Length of output: 197


Script:

#!/bin/bash
# Search for GetNi method definition and its usages
echo "Searching for GetNi method definition:"
ast-grep --pattern 'def GetNi'

echo -e "\nSearching for GetNi method calls:"
rg "GetNi\(" -A 2

echo -e "\nSearching for related test files:"
fd "test.*\.py$" --exec rg -l "GetNi"

echo -e "\nChecking for any documentation or comments about ions density:"
rg -i "ions.*density" -A 2

Length of output: 24155

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

110-110: LGTM: Charge density computation aligns with PR objectives.

The change from computeDensity() to computeChargeDensity() correctly implements the PR's goal of properly handling ion population charge properties.

src/core/data/electrons/electrons.hpp (1)

68-68: Verify charge density usage across the codebase.

The changes consistently replace density() with chargeDensity(). Let's verify that all callers are updated to handle charge density correctly.

Also applies to: 81-81, 115-115, 214-214

✅ Verification successful

The previous search revealed several density() calls that need to be cross-referenced with chargeDensity() usage to ensure consistency in the changes. Let's gather more context about the charge density usage to make a proper assessment.


No issues found with charge density usage

The codebase shows consistent and correct usage of chargeDensity() and density() methods:

  • chargeDensity() is used in ion-related code to represent the ionic charge density
  • density() in the electrons code correctly returns ions_.chargeDensity(), maintaining charge neutrality
  • All callers are properly using these methods according to their context
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for any remaining direct calls to density() that might need updating
rg -g '*.{hpp,cpp}' --no-heading -A 2 -B 2 '\bdensity\(\)'

# Search for comments or documentation mentioning density to ensure they're updated
rg -g '*.{hpp,cpp}' --no-heading -A 2 -B 2 'density' '(?i)//.*density|/\*.*density'

Length of output: 4098


Script:

#!/bin/bash
# Search for chargeDensity() usage to verify the transition
rg -g '*.{hpp,cpp}' --no-heading -A 2 -B 2 'chargeDensity\(\)'

# Search for any density-related method calls in the electrons class
ast-grep --pattern 'electrons.$_density()'

Length of output: 13109

pyphare/pyphare/pharesee/plotting.py (2)

277-277: LGTM! File path updated to reflect charge density.

The change from "ions_density.h5" to "ions_charge_density.h5" aligns with the PR's objective of properly handling charge-related quantities.


Line range hint 277-281: Verify the impact of file name change.

The change from "ions_density.h5" to "ions_charge_density.h5" could affect dependent code. Also, the use of GetNi() method (suggesting number density) for charge density data seems inconsistent.

Let's verify the usage and dependencies:

✅ Verification successful

Let me gather more context about the charge density and number density relationship in the codebase.


No issues with the file name change and GetNi usage

The codebase consistently uses "ions_charge_density.h5" for charge density data, and the GetNi method is correctly implemented to read this file. The method name "GetNi" appears to be a historical artifact but is consistently used throughout the codebase to handle charge density data, as evidenced by its implementation in run.py:

def GetNi(self, time, merged=False, interp="nearest", **kwargs):
    hier = self._get_hierarchy(time, "ions_charge_density.h5", **kwargs)
    return ScalarField(self._get(hier, time, merged, interp))
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for any remaining references to the old file name and verify GetNi usage

# Check for any remaining references to the old file name
echo "Checking for old file name references..."
rg "ions_density\.h5"

# Check for GetNi method usage contexts
echo "Checking GetNi method usage..."
rg "GetNi\(" -A 3

Length of output: 4870


Script:

#!/bin/bash
# Check for any references to charge density and number density in the codebase
echo "Checking for charge density references..."
rg -i "charge.?density"

echo "Checking for number density references..."
rg -i "number.?density"

# Check the implementation of GetNi
echo "Checking GetNi implementation and related code..."
ast-grep --pattern 'def GetNi($$$)'

Length of output: 16435

tests/diagnostic/test_diagnostics.hpp (2)

125-128: LGTM: Proper validation of charge density diagnostics

The changes correctly validate both the individual population charge densities and the total ions charge density, aligning with the PR's objective to properly handle charge-related quantities.


Line range hint 229-251: Verify the relationship between mass and charge density attributes

While the changes correctly add validation for charge density attributes, please verify:

  1. Is the /ions/mass_density attribute still needed?
  2. If yes, should we add explicit tests for mass density similar to charge density?
  3. Should we document the relationship between mass and charge density for future maintainers?
✅ Verification successful

Mass density attribute is required and properly tested

The codebase analysis shows that both mass density and charge density serve distinct purposes:

  • Mass density is used across multiple components (core, diagnostics, tests) and is a fundamental quantity
  • Both quantities are consistently tested:
    • Global ions mass and charge density in /ions/ path
    • Per-population density attributes including both mass and charge density
  • The relationship is already well-structured in the diagnostic tests:
    1. Global level: /ions/mass_density and /ions/charge_density
    2. Population level: density and charge_density under each population path

The current implementation maintains proper separation and testing of both quantities, requiring no additional changes.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for mass density usage across the codebase

# Search for mass density references
echo "Searching for mass density usage..."
rg -l "mass_density|massDensity" --type cpp --type python

# Search for related test cases
echo "Searching for related test cases..."
rg -l "mass.*density.*test|test.*mass.*density" --type cpp --type python

Length of output: 358


Script:

#!/bin/bash
# Search for mass density references with correct file type flags
echo "Searching for mass density usage..."
rg -l "mass_density|massDensity"

# Search for mass density in diagnostic code
echo "Searching for mass density in diagnostics..."
rg "mass_density" -C 3 tests/diagnostic/

# Search for charge density references for comparison
echo "Searching for charge density usage..."
rg "charge_density" -C 3 tests/diagnostic/

Length of output: 5049

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

225-227: 🛠️ Refactor suggestion

Consider documenting and validating density relationships

The introduction of "charge_density" and "mass_density" alongside "density" raises some important considerations:

  1. The relationship between these quantities should be documented:

    • density: number of particles per volume
    • charge_density: charge per volume (density * charge_per_particle)
    • mass_density: mass per volume (density * mass_per_particle)
  2. Consider adding runtime validation to ensure these relationships hold:

    def validate_densities(number_density, charge_density, mass_density, charge_per_particle, mass_per_particle):
        assert np.allclose(charge_density, number_density * charge_per_particle)
        assert np.allclose(mass_density, number_density * mass_per_particle)
  3. Consider deprecating or clarifying the generic "density" term to avoid confusion with the more specific density quantities.

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

149-150: LGTM: Charge density diagnostic properly integrated

The addition of charge density diagnostics at both population and ion-wide levels is well-structured and consistent with the existing diagnostic framework.

Also applies to: 154-155


274-275: LGTM: Dataset initialization properly handles charge density

The initialization of charge density datasets is consistent with the existing pattern and properly handles both population-specific and ion-wide cases.

Also applies to: 283-284


355-355: LGTM: Attribute writing properly extended

The addition of charge density to attribute writing completes the diagnostic chain consistently.


315-317: Verify data writing consistency

The implementation looks correct, but let's verify that all density types are consistently written.

Also applies to: 325-326

✅ Verification successful

Density types are consistently written across the codebase

The verification shows that:

  • particleDensity() and chargeDensity() are consistently used together in ion populations
  • The writing pattern in fluid.hpp correctly matches the usage pattern found in the rest of the codebase
  • Both population-specific and ion-wide densities are handled consistently in diagnostics and computations
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check for consistent handling of density types across the codebase
echo "Checking density type consistency..."
rg -A 2 "density\(\)" --type cpp
rg -A 2 "particleDensity\(\)" --type cpp
rg -A 2 "chargeDensity\(\)" --type cpp

Length of output: 16749

pyphare/pyphare_tests/test_pharesee/test_geometry_2d.py (2)

393-397: LGTM! Consistent with previous usage.

The values follow the same pattern as in test_large_patchoverlaps, maintaining consistency across test visualizations.


505-505: Verify the value usage for periodic patches.

While other test methods use values 1 and 2 to differentiate between different types of boxes, this method only uses value 2. Consider whether periodic patches should have a distinct value for clearer visualization.

tests/core/data/electrons/test_electrons.cpp (4)

Line range hint 129-153: LGTM! Clear and descriptive member variable names.

The renaming of member variables improves code clarity by explicitly distinguishing between different types of densities (charge, mass, particle) and tensors. This aligns well with the PR's objective of correctly handling charge and mass properties.


196-208: LGTM! Constructor initialization maintains consistency with renamed fields.

The constructor initialization list correctly initializes all renamed fields with appropriate HybridQuantity types and descriptive names.


Line range hint 247-324: LGTM! Consistent initialization of charge density across dimensions.

The initialization of ionChargeDensity is implemented consistently across all dimensions (1D, 2D, and 3D) using appropriate hyperbolic functions.


373-373: LGTM! Updated test to use chargeDensity() instead of density().

The test correctly uses the new chargeDensity() method instead of density(), aligning with the PR's focus on proper charge handling.

src/core/numerics/interpolator/interpolator.hpp (2)

472-474: LGTM! Well-structured parameter list.

The signature change appropriately separates particle density from charge density while maintaining good parameter grouping and efficient parameter passing.


509-512: LGTM! Proper parameter forwarding implementation.

The overload correctly handles rvalue references and forwards all parameters to the main implementation.

tests/core/numerics/interpolator/test_main.cpp (4)

519-519: LGTM: Grid variable for charge density added.

The addition of rho_c with the same type and initialization parameters as rho maintains consistency with the existing grid structure.

Also applies to: 530-530


637-637: Verify test coverage for charge density interpolation.

The interpolator call has been updated to include rho_c, but there are no explicit test assertions for the charge density values.

Consider adding test assertions similar to the existing ones for rho:

 TYPED_TEST_P(ACollectionOfParticles_1d, DepositCorrectlyTheirWeight_1d)
 {
     constexpr auto interp = TypeParam::interp_order;
     auto idx = 20 + this->layout.nbrGhosts(QtyCentering::dual);
     auto const& [vx, vy, vz] = this->v();
     EXPECT_DOUBLE_EQ(this->rho(idx), 1.0);
+    EXPECT_DOUBLE_EQ(this->rho_c(idx), 1.0);  // Verify charge density
     EXPECT_DOUBLE_EQ(vx(idx), 2.0);
     EXPECT_DOUBLE_EQ(vy(idx), -1.0);
     EXPECT_DOUBLE_EQ(vz(idx), 1.0);
 }

683-683: LGTM: Consistent implementation in 2D test fixture.

The rho_c grid variable is correctly added to the 2D test fixture with the same initialization parameters as rho.

Also applies to: 690-690


704-704: Verify test coverage for 2D charge density interpolation.

Similar to the 1D case, the 2D test should include assertions for charge density values.

Consider adding test assertions:

 TYPED_TEST_P(ACollectionOfParticles_2d, DepositCorrectlyTheirWeight_2d)
 {
     constexpr auto interp = TypeParam::interp_order;
     auto idx = 2 + this->layout.nbrGhosts(QtyCentering::dual);
     auto const& [vx, vy, vz] = this->v();
     EXPECT_DOUBLE_EQ(this->rho(idx, idx), 1.0);
+    EXPECT_DOUBLE_EQ(this->rho_c(idx, idx), 1.0);  // Verify charge density
     EXPECT_DOUBLE_EQ(vx(idx, idx), 2.0);
     EXPECT_DOUBLE_EQ(vy(idx, idx), -1.0);
     EXPECT_DOUBLE_EQ(vz(idx, idx), 1.0);
 }
tests/simulator/test_initialization.py (2)

173-176: LGTM! Diagnostic quantity update aligns with PR objectives.

The change from "density" to "charge_density" in FluidDiagnostics initialization correctly reflects the new focus on charge properties of ion populations.


Line range hint 235-243: LGTM! Consistent update to diagnostic file paths.

The hierarchy retrieval paths have been updated to match the new charge_density diagnostic quantity, maintaining consistency across the codebase.

tests/simulator/test_advance.py (3)

155-157: LGTM: Diagnostic quantity update aligns with PR objectives.

The change from "density" to "charge_density" correctly implements the PR's goal of properly handling charge properties of ion populations.


225-225: LGTM: File paths consistently updated.

The h5 file paths have been consistently updated to reflect the change from "density" to "charge_density".

Also applies to: 234-234


292-292: Verify the increased tolerance threshold.

The tolerance has been increased significantly from 5.5e-15 to 2.5e-14. While this fixes the test, it might indicate underlying numerical stability issues that should be investigated.

✅ Verification successful

Let me gather more context about the specific test case where the tolerance was increased.


Tolerance increase is justified by empirical evidence

The increased tolerance (2.5e-14) is well-documented and justified in the code comments:

  • Previous empirical maximum was 5.2e-15 (observed in CI build #78544)
  • The higher tolerance accounts for accumulated rounding errors from ghost cell calculations involving linear/spatial interpolations
  • The increase provides a reasonable safety margin above the observed maximum while still maintaining strict precision requirements

The change appears to be a data-driven adjustment rather than masking numerical stability issues.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for other similar tolerance values in test files
rg -A 2 "atol=.*e-1[45]" tests/

Length of output: 1774


Script:

#!/bin/bash
# Get more context around the increased tolerance in test_advance.py
rg -B 10 -A 5 "atol=2.5e-14" tests/simulator/test_advance.py

Length of output: 1287

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

388-389: Improved variable naming for better physics representation.

The distinction between particleDensity and chargeDensity better reflects the physical quantities being handled, which aligns with the PR objective of correctly handling charge properties.


392-392: LGTM: Interpolation updated to handle both density types.

The interpolation call has been correctly updated to handle both particleDensity and chargeDensity.


399-402: LGTM: Level ghost particle interpolation properly updated.

The interpolation calls for level ghost particles (both old and new) have been correctly updated to handle both density types while maintaining the existing time interpolation logic.


542-542: Verify the state preparation with new charge density.

The change from density to chargeDensity is consistent with the new naming scheme. However, let's verify that all related state preparation code has been updated.

✅ Verification successful

The change from density to chargeDensity is correctly implemented.

The codebase search confirms that:

  • No references to the old density method remain in the ion state
  • The chargeDensity naming is consistently used across the codebase
  • The change aligns with the existing API in ions.hpp where chargeDensityName() is the standard method name
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for any remaining references to old density naming in state preparation
rg -A 5 'state\.ions\.density\(' 

Length of output: 34


Script:

#!/bin/bash
# Search for any remaining references to density in ion state with broader patterns
rg -A 5 'ions.*density' 

# Also search for chargeDensity to verify the new naming pattern
rg -A 5 'chargeDensity'

# Use ast-grep to find any state.ions member access
ast-grep --pattern 'state.ions.$_'

Length of output: 53460

src/core/data/ions/ions.hpp (4)

44-45: Ensure Initialization Order Matches Declaration Order

The member variables massDensity_ and chargeDensity_ are initialized in the constructor's initializer list. To prevent potential bugs, ensure that the initialization order matches the order of their declaration in the class.

According to the C++ standard, member variables are initialized in the order they are declared, not the order listed in the initializer list. Verify that massDensity_ is declared before chargeDensity_ to match the initialization order.


214-215: Ensure Safe Return of Member References

In getCompileTimeResourcesViewList(), you're returning references to member variables. Verify that exposing these references is intended and doesn't violate encapsulation or introduce potential risks.

Consider whether these members should be modified externally. If not, returning const references or encapsulating them might be safer.


239-239: Align Member Declaration Order with Initialization

The class member chargeDensity_ is declared after massDensity_, matching their initialization order in the constructor. This is good practice as it avoids potential warnings or bugs related to member initialization order.


75-91: Verify Correctness of computeChargeDensity() Implementation

In computeChargeDensity(), you're summing pop.chargeDensity() into chargeDensity_. Confirm that pop.chargeDensity() accurately represents the charge density for each population and accounts for the ion charge.

To ensure correctness, check if pop.chargeDensity() internally multiplies particle density by the ion charge. If it doesn't, you may need to adjust the calculation by incorporating pop.charge().

You can run the following script to inspect the implementation of pop.chargeDensity():

✅ Verification successful

Based on the code analysis, I can now provide a definitive response about the charge density calculation.

computeChargeDensity() Implementation is Correct

The charge density is correctly calculated in the codebase through the following mechanism:

  1. Each particle has a charge property that is initialized from the configuration (as seen in particle initializer code).
  2. The interpolator uses this charge when computing the charge density for each population through the interpolate function, which is called in multiple places including the moments calculation.
  3. The computeChargeDensity() method in ions.hpp correctly sums up the charge densities from all populations, which have already been weighted by their respective charges during the interpolation step.

The charge density for each population is properly computed during particle interpolation, and the total charge density summation in computeChargeDensity() is the correct approach.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify how `pop.chargeDensity()` is calculated.

# Test: Search for the `chargeDensity` method in `IonPopulation`.
# Expect: The method should account for the ion charge.

ast-grep --pattern $'class IonPopulation {
  $$$
  field_type& chargeDensity() {
    $$$
  }
  $$$
}'

Length of output: 102


Script:

#!/bin/bash
# Let's try a broader search to find the IonPopulation class and its methods
rg -l "class.*IonPopulation" --type cpp

# Then search for chargeDensity method implementation
rg "chargeDensity\(\)" --type cpp -A 5

# Also search for any charge-related calculations
rg "charge.*density" --type cpp -A 5

Length of output: 22811


Script:

#!/bin/bash
# Let's search for how the charge density is initialized or calculated in IonPopulation
rg "chargeDensity_" --type cpp -A 5

# Also search for particle density and charge relationship
rg "particleDensity.*charge" --type cpp -A 5

Length of output: 13926


Script:

#!/bin/bash
# Let's search for the interpolator implementation to see how charge density is calculated
rg "interpolate.*particleDensity.*chargeDensity" --type cpp -A 10

# Also search for any charge-related initialization in IonPopulation constructor
rg "IonPopulation.*charge" --type cpp -A 10

Length of output: 3974


Script:

#!/bin/bash
# Let's search for the interpolator class implementation
rg "class.*Interpolator" --type cpp -A 20

# Also search for particle charge initialization
rg "charge.*=.*" --type cpp -A 5

Length of output: 30729

pyphare/pyphare/pharesee/hierarchy/hierarchy.py (6)

361-361: Necessary import of Rectangle added

The Rectangle class from matplotlib.patches is now imported, which is required for patch plotting functionality introduced later in the code.


375-379: Initialization of plotting grid indices is correct

The calculation of indices and grid setup for plotting is properly implemented, ensuring accurate representation of the domain.


382-386: Correctly populating the grid with collection values

The code accurately assigns the specified value to the ij grid for each box in collections, which is essential for visualizing the data correctly.


391-394: Proper use of ax.pcolormesh for grid visualization

The implementation of ax.pcolormesh with the transposed ij grid effectively visualizes the data, and setting the tick marks enhances the plot's readability.


410-413: Allow users to set axis limits for enhanced flexibility

Including xlim and ylim in the plotting function allows users to specify axis limits, improving the flexibility and usability of the plotting method.


560-563: Conditional addition of color bar enhances plotting options

The change allows users to control the display of the color bar via the cbar keyword argument, increasing the flexibility of the plot2d method.

tests/simulator/initialize/test_density_init.py (2)

252-256: Ensure proper cleanup of simulation objects

Setting ph.global_vars.sim = None after the first simulation helps prevent conflicts. Ensure this practice is consistently applied when running multiple simulations sequentially.


333-334: LGTM: Entry point defined correctly

The script's entry point is properly defined with if __name__ == "__main__":, allowing it to be run as a standalone module.

pyphare/pyphare/pharesee/hierarchy/fromfunc.py Outdated Show resolved Hide resolved
pyphare/pyphare/pharesee/hierarchy/__init__.py Outdated Show resolved Hide resolved
Comment on lines 156 to 158
{
EXPECT_ANY_THROW(auto& n = ions.density()(0));
EXPECT_ANY_THROW(auto& n = ions.chargeDensity()(0));
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Consider improving error handling in release builds.

The comment "no throw in release mode! JUST SEGFAULTS! :D" indicates a serious issue where invalid access leads to undefined behavior in release builds instead of proper error handling.

Consider implementing runtime checks that are active in both debug and release builds to prevent segmentation faults.

@@ -50,7 +50,7 @@ class UsableIonsPopulation : public _defaults::IonPopulation_t
public:
UsableIonsPopulation(initializer::PHAREDict const& dict, GridLayout_t const& layout)
: Super{dict}
, rho{this->name() + "_rho", layout, HybridQuantity::Scalar::rho}
, rho{this->name() + "_particleDensity", layout, HybridQuantity::Scalar::rho}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Consider renaming the member variable to match its semantic meaning

While the initialization string has been updated to "_particleDensity", the member variable is still named rho, which could be misleading as rho typically represents charge density in physics. Consider the following improvements:

  1. Rename the member variable to match its semantic meaning:
- typename _defaults::Grid_t rho;
+ typename _defaults::Grid_t particleDensity;
  1. Update the constructor initialization accordingly:
- , rho{this->name() + "_particleDensity", layout, HybridQuantity::Scalar::rho}
+ , particleDensity{this->name() + "_particleDensity", layout, HybridQuantity::Scalar::particleDensity}

This would improve code clarity and maintain consistency with physics terminology.

Committable suggestion skipped: line range outside the PR's diff.

src/amr/tagging/default_hybrid_tagger_strategy.hpp Outdated Show resolved Hide resolved
Comment on lines +138 to +142
std::transform(std::begin(vx), std::end(vx), std::begin(massDensity_), std::begin(vx),
std::divides<Float>{});
std::transform(std::begin(vy), std::end(vy), std::begin(density), std::begin(vy),
std::transform(std::begin(vy), std::end(vy), std::begin(massDensity_), std::begin(vy),
std::divides<Float>{});
std::transform(std::begin(vz), std::end(vz), std::begin(density), std::begin(vz),
std::transform(std::begin(vz), std::end(vz), std::begin(massDensity_), std::begin(vz),
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Handle Potential Division by Zero in Bulk Velocity Calculation

When computing the bulk velocity, dividing by massDensity_ without checking for zero values can lead to division by zero errors. Implement a safeguard to handle cases where massDensity_ might be zero.

Apply this diff to add a lambda function that checks for zero mass density:

 std::transform(std::begin(vx), std::end(vx), std::begin(massDensity_), std::begin(vx),
-               std::divides<Float>{});
+               [](Float v, Float m) { return m != 0 ? v / m : 0; });

 std::transform(std::begin(vy), std::end(vy), std::begin(massDensity_), std::begin(vy),
-               std::divides<Float>{});
+               [](Float v, Float m) { return m != 0 ? v / m : 0; });

 std::transform(std::begin(vz), std::end(vz), std::begin(massDensity_), std::begin(vz),
-               std::divides<Float>{});
+               [](Float v, Float m) { return m != 0 ? v / m : 0; });

This ensures that when massDensity_ is zero, the velocity component is set to zero instead of causing an error.

📝 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
std::transform(std::begin(vx), std::end(vx), std::begin(massDensity_), std::begin(vx),
std::divides<Float>{});
std::transform(std::begin(vy), std::end(vy), std::begin(density), std::begin(vy),
std::transform(std::begin(vy), std::end(vy), std::begin(massDensity_), std::begin(vy),
std::divides<Float>{});
std::transform(std::begin(vz), std::end(vz), std::begin(density), std::begin(vz),
std::transform(std::begin(vz), std::end(vz), std::begin(massDensity_), std::begin(vz),
std::transform(std::begin(vx), std::end(vx), std::begin(massDensity_), std::begin(vx),
[](Float v, Float m) { return m != 0 ? v / m : 0; });
std::transform(std::begin(vy), std::end(vy), std::begin(massDensity_), std::begin(vy),
[](Float v, Float m) { return m != 0 ? v / m : 0; });
std::transform(std::begin(vz), std::end(vz), std::begin(massDensity_), std::begin(vz),
[](Float v, Float m) { return m != 0 ? v / m : 0; });

Comment on lines +395 to +402
for patch in self.level(ilvl).patches:
box = patch.box
r = Rectangle(box.lower - 0.5, *(box.upper + 0.5))

r.set_edgecolor("r")
r.set_facecolor("none")
r.set_linewidth(2)
ax.add_patch(r)
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Correct the Rectangle dimensions in patch plotting

The parameters for Rectangle are incorrect. The width and height should be calculated as the difference between the upper and lower coordinates. Apply this fix:

-    r = Rectangle(box.lower - 0.5, *(box.upper + 0.5))
+    r = Rectangle(box.lower - 0.5, *(box.upper - box.lower + 1.0))

This ensures that the rectangle accurately represents the dimensions of the patch.

📝 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
for patch in self.level(ilvl).patches:
box = patch.box
r = Rectangle(box.lower - 0.5, *(box.upper + 0.5))
r.set_edgecolor("r")
r.set_facecolor("none")
r.set_linewidth(2)
ax.add_patch(r)
for patch in self.level(ilvl).patches:
box = patch.box
r = Rectangle(box.lower - 0.5, *(box.upper - box.lower + 1.0))
r.set_edgecolor("r")
r.set_facecolor("none")
r.set_linewidth(2)
ax.add_patch(r)

tests/core/numerics/ion_updater/test_updater.cpp Outdated Show resolved Hide resolved
tests/simulator/initialize/test_density_init.py Outdated Show resolved Hide resolved
@@ -164,22 +163,25 @@
template<typename... Args>
auto static _ions(Args&... args)
{
auto const& [Fi, Nibuffer, NiProtons, Vi, M, protons_M, pack]
auto const& [ionFlux, ionChargeDensity, ionMassDensity, protonParticleDensity,

Check notice

Code scanning / CodeQL

Unused local variable Note test

Variable (unnamed local variable) is not used.
= std::forward_as_tuple(args...);
IonsT ions{createDict<dim>()["ions"]};
{
auto const& [V, m, d, md] = ions.getCompileTimeResourcesViewList();
d.setBuffer(&Nibuffer);
auto const& [V, m, d_c, d_m] = ions.getCompileTimeResourcesViewList();

Check notice

Code scanning / CodeQL

Unused local variable Note test

Variable (unnamed local variable) is not used.
@@ -313,25 +325,27 @@
void setBuffers(Ions& ions)
{
{
auto const& [V, m, d, md] = ions.getCompileTimeResourcesViewList();
auto const& [V, m, cd, md] = ions.getCompileTimeResourcesViewList();

Check notice

Code scanning / CodeQL

Unused local variable Note test

Variable (unnamed local variable) is not used.
md.setBuffer(&ionMassDensity);
}

auto& pops = ions.getRunTimeResourcesViewList();
{
auto const& [F, M, d, particles] = pops[0].getCompileTimeResourcesViewList();
d.setBuffer(&protonDensity);
auto const& [F, M, d, c, particles] = pops[0].getCompileTimeResourcesViewList();

Check notice

Code scanning / CodeQL

Unused local variable Note test

Variable (unnamed local variable) is not used.
protons_M.set_on(M);
protonF.set_on(F);
particles.setBuffer(&protonPack);
}

{
auto const& [F, M, d, particles] = pops[1].getCompileTimeResourcesViewList();
d.setBuffer(&alphaDensity);
auto const& [F, M, d, c, particles] = pops[1].getCompileTimeResourcesViewList();

Check notice

Code scanning / CodeQL

Unused local variable Note test

Variable (unnamed local variable) is not used.
@nicolasaunai
Copy link
Member

On build fails.
I think what should be done is not testing function VS data on a point-wise basis for such noisy quantities but rather computing the standard deviation between function and data over the whole dataset and put a (empirical) threshold on that. This is what we do for density initialization tests and it's quite less sensitive to noise.

Copy link
Member

@nicolasaunai nicolasaunai left a comment

Choose a reason for hiding this comment

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

.gdbinit Outdated Show resolved Hide resolved
tests/simulator/initialize/test_density_init.py Outdated Show resolved Hide resolved
tests/simulator/initialize/test_density_init.py Outdated Show resolved Hide resolved
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: 3

🧹 Outside diff range and nitpick comments (19)
pyphare/pyphare/pharesee/hierarchy/__init__.py (1)

14-14: Update docstring to document the new func parameter

The function signature has been updated with the new func parameter, but the docstring doesn't describe its purpose or usage.

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

18-19: LGTM with potential optimization opportunity

The separation of particle and charge density is well-implemented. Consider adding a comment explaining the relationship between these quantities for future maintainability.

If particleDensity and chargeDensity share the same memory layout, consider implementing a single zero operation that spans both containers for better cache utilization.


44-46: Add documentation for density relationships

Consider adding documentation explaining:

  1. The relationship between particle density and charge density
  2. The units of each quantity
  3. Any invariants that should be maintained between these quantities

Line range hint 1-70: Consider adding compile-time assertions and documentation

To improve robustness and maintainability:

  1. Add static_assert statements to validate template parameters (e.g., checking if Ions type meets required concept)
  2. Document the physical meaning and units of moments in the class/file header
  3. Consider adding invariant checks in debug builds to validate the relationship between particle and charge density
pyphare/pyphare/pharesee/hierarchy/fromfunc.py (2)

4-15: Add type hints and improve validation

Consider enhancing the function with type hints and replacing the assertion with a more informative validation.

-def hierarchy_from_func1d(func, hier, **kwargs):
-    assert hier.ndim == 1
+from typing import Callable, Dict, Any
+
+def hierarchy_from_func1d(func: Callable, hier: 'Hierarchy', **kwargs: Any) -> Dict:
+    if hier.ndim != 1:
+        raise ValueError(f"Expected 1D hierarchy, got {hier.ndim}D")

58-63: Simplify control flow

The else clause is redundant since the code will only reach that point if neither condition is true.

     if hier.ndim == 1:
         return hierarchy_from_func1d(func, hier, **kwargs)
     if hier.ndim == 2:
         return hierarchy_from_func2d(func, hier, **kwargs)
-    else:
-        raise ValueError(f"Unsupported hierarchy dimension: {hier.ndim}")
+    raise ValueError(f"Unsupported hierarchy dimension: {hier.ndim}")
src/core/data/ions/ions.hpp (2)

85-88: Add debug assertions for array bounds

While the std::transform usage is efficient, consider adding debug assertions to verify that popDensity and chargeDensity_ have matching sizes.

+    assert(std::size(chargeDensity_) == std::size(popDensity) && "Density arrays must have matching sizes");
     std::transform(std::begin(chargeDensity_), std::end(chargeDensity_),
                   std::begin(popDensity), std::begin(chargeDensity_),
                   std::plus<Float>{});

175-176: Consider using standard C++ operators

Replace the alternative operator 'and' with the more conventional '&&' for better readability and consistency with common C++ practices.

-    bool usable = chargeDensity_.isUsable() and bulkVelocity_.isUsable()
-                  and momentumTensor_.isUsable() and massDensity_.isUsable();
+    bool usable = chargeDensity_.isUsable() && bulkVelocity_.isUsable()
+                  && momentumTensor_.isUsable() && massDensity_.isUsable();

-    bool settable = massDensity_.isSettable() and chargeDensity_.isSettable()
-                    and bulkVelocity_.isSettable() and momentumTensor_.isSettable();
+    bool settable = massDensity_.isSettable() && chargeDensity_.isSettable()
+                    && bulkVelocity_.isSettable() && momentumTensor_.isSettable();

Also applies to: 189-190

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

491-495: Consider extracting lambda functions for better readability.

While the implementation is correct, we could improve readability by extracting the lambda functions into named constants. This would make the code more self-documenting and easier to maintain.

Here's a suggested improvement:

+    static constexpr auto getParticleDensity = [](auto const& part) { return 1.; };
+    static constexpr auto getChargeDensity = [](auto const& part) { return part.charge; };
+
     particleToMesh_(
-        particleDensity, *currPart, [](auto const& part) { return 1.; }, startIndex_,
+        particleDensity, *currPart, getParticleDensity, startIndex_,
         weights_, coef);
     particleToMesh_(
-        chargeDensity, *currPart, [](auto const& part) { return part.charge; }, startIndex_,
+        chargeDensity, *currPart, getChargeDensity, startIndex_,
         weights_, coef);
pyphare/pyphare/pharesee/hierarchy/hierarchy.py (2)

373-373: Consider making the figure size configurable.

The hardcoded figure size of (16, 16) might be too large for some displays. Consider making it configurable through kwargs with a reasonable default size.

-        fig, ax = kwargs.get("subplot", plt.subplots(figsize=(16, 16)))
+        default_figsize = (10, 10)
+        fig, ax = kwargs.get("subplot", plt.subplots(figsize=kwargs.get("figsize", default_figsize)))

560-563: Consider making colorbar parameters configurable.

While the colorbar implementation is good, consider making its size and padding configurable through kwargs for better flexibility.

         if kwargs.get("cbar", True):
             divider = make_axes_locatable(ax)
-            cax = divider.append_axes("right", size="5%", pad=0.08)
+            cbar_size = kwargs.get("cbar_size", "5%")
+            cbar_pad = kwargs.get("cbar_pad", 0.08)
+            cax = divider.append_axes("right", size=cbar_size, pad=cbar_pad)
             fig.colorbar(im, ax=ax, cax=cax)
tests/simulator/test_advance.py (1)

312-312: Remove unnecessary f-string prefix.

The string "pd1.png" doesn't contain any placeholders, so the f prefix can be removed.

-        fig.savefig(f"pd1.png")
+        fig.savefig("pd1.png")
🧰 Tools
🪛 Ruff

312-312: f-string without any placeholders

Remove extraneous f prefix

(F541)

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

556-567: Consider adding error handling for interpolation failures

The interpolation calls should include error handling to catch and report any potential failures during ghost particle interpolation.

- interpolate(makeIndexRange(pop.patchGhostParticles()), pop.particleDensity(),
-            pop.chargeDensity(), pop.flux(), layout);
+ try {
+     interpolate(makeIndexRange(pop.patchGhostParticles()), pop.particleDensity(),
+                pop.chargeDensity(), pop.flux(), layout);
+ } catch (const std::exception& e) {
+     FAIL() << "Interpolation failed for patch ghost particles: " << e.what();
+ }

668-673: Consider adding relative error tolerance

The density check against prescribed values uses a fixed tolerance of 0.07. Consider making this tolerance relative to the magnitude of the expected values.

- EXPECT_GE(0.07, diff);
+ const double relativeTolerance = 0.07;
+ EXPECT_GE(relativeTolerance * std::abs(functionX[i]), diff);
tests/simulator/initialize/test_density_init.py (5)

174-175: Replace assert statements with explicit exception handling

Using assert statements for input validation is not recommended because they can be disabled with Python optimizations (-O flag). Replace the assert statements with explicit exception handling to ensure these checks are always performed.

Apply this diff to replace the assert statements with ValueError exceptions:

 def densityMain_2d(x, y):
-    assert len(x) == len(y)
+    if len(x) != len(y):
+        raise ValueError("Length of x and y must be equal")
     return 1.0*np.ones_like(x)

 def densityBeam_2d(x, y):
-    assert len(x) == len(y)
+    if len(x) != len(y):
+        raise ValueError("Length of x and y must be equal")
     u = x/L-0.5
     v = y/L-0.5
     return np.exp(-u**2-v**2)

Also applies to: 178-179


117-170: Refactor duplicated code in config_1d() and config_2d()

The config_1d() and config_2d() functions share significant portions of code. Consider refactoring common code into shared functions or utilities to improve maintainability and reduce duplication.

For example, you can create a function to generate the simulation configuration:

def create_simulation_config(dimensions, diag_dir):
    sim = ph.Simulation(
        smallest_patch_size=20,
        largest_patch_size=60,
        time_step=ts,
        time_step_nbr=1,
        boundary_types="periodic" if dimensions == 1 else ("periodic", "periodic"),
        cells=(ncell,) * dimensions,
        dl=(dl,) * dimensions,
        diag_options={
            "format": "phareh5",
            "options": {"dir": diag_dir, "mode": "overwrite"},
        },
    )
    return sim

Then, use this function in both config_1d() and config_2d():

def config_1d():
    sim = create_simulation_config(1, "test_densities_1d")
    # ... rest of the code ...

def config_2d():
    sim = create_simulation_config(2, "test_densities_2d")
    # ... rest of the code ...

Also applies to: 199-252


94-115: Consolidate similar functions to enhance reusability

The functions densityMain_1d, densityBeam_1d, v0_1d, vth_1d and their 2D counterparts have similar implementations. Consider creating dimension-agnostic versions of these functions to reduce code duplication and improve reusability.

For example:

def density_main(*args):
    return np.ones_like(args[0])

def density_beam(*args):
    u = args[0]/L - 0.5
    if len(args) == 1:
        return np.exp(-u**2)
    else:
        v = args[1]/L - 0.5
        return np.exp(-u**2 - v**2)

def v0(*args):
    return 0.0

def vth(*args):
    return np.sqrt(1.0)

Then, use these functions in your configurations:

def config_1d():
    # ...
    v_pop = {
        "vbulkx": v0,
        "vthx": vth,
        # ...
    }
    # use density_main and density_beam
    # ...

def config_2d():
    # ...
    v_pop = {
        "vbulkx": v0,
        "vbulky": v0,
        "vthx": vth,
        "vthy": vth,
        # ...
    }
    # use density_main and density_beam
    # ...

Also applies to: 173-197


261-275: Pass time as a parameter to the noise_level function

The noise_level function relies on the time variable from the enclosing scope. To enhance clarity and make the function self-contained, pass time as an explicit parameter.

Apply this diff:

 def noise_level(h, H):
-    for lvl_h, lvl_H in zip(h.levels(time).values(), H.levels(time).values()):
+    for lvl_h, lvl_H in zip(h.levels(t).values(), H.levels(t).values()):
         # ...
+def main():
+    # ...
+    def noise_level(h, H, t):
+        # function body remains the same
+    # ...
     assert np.mean(noise_level(h1, H1, time)) < 0.18
     assert np.mean(noise_level(h2, H2, time)) < 0.12

90-91: Use explicit data structures for ion properties

Associating ion properties with populations using indices from masses and charges tuples can lead to errors if the order changes. Consider using dictionaries or data classes to explicitly associate each population with its properties.

For example:

ion_populations = {
    "main": {"mass": 2, "charge": 1, "density": densityMain_1d},
    "beam": {"mass": 3, "charge": 2, "density": densityBeam_1d},
}

# Then, in your configuration:
ph.MaxwellianFluidModel(
    bx=bx_1d,
    by=by_1d,
    bz=bz_1d,
    main={**ion_populations["main"], "nbr_part_per_cell": 100, **v_pop},
    beam={**ion_populations["beam"], "nbr_part_per_cell": 100, **v_pop},
)

Also applies to: 146-147, 228-229

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between fa838a0 and 8473002.

📒 Files selected for processing (45)
  • pyphare/pyphare/pharein/diagnostics.py (1 hunks)
  • pyphare/pyphare/pharesee/hierarchy/__init__.py (2 hunks)
  • pyphare/pyphare/pharesee/hierarchy/fromfunc.py (1 hunks)
  • pyphare/pyphare/pharesee/hierarchy/hierarchy.py (4 hunks)
  • pyphare/pyphare/pharesee/hierarchy/hierarchy_utils.py (1 hunks)
  • pyphare/pyphare/pharesee/plotting.py (1 hunks)
  • pyphare/pyphare/pharesee/run/run.py (3 hunks)
  • pyphare/pyphare_tests/test_pharesee/test_geometry_2d.py (3 hunks)
  • pyphare/pyphare_tests/test_pharesee/test_hierarchy.py (1 hunks)
  • src/amr/level_initializer/hybrid_level_initializer.hpp (1 hunks)
  • src/amr/messengers/hybrid_hybrid_messenger_strategy.hpp (2 hunks)
  • src/amr/physical_models/hybrid_model.hpp (1 hunks)
  • src/amr/tagging/default_hybrid_tagger_strategy.hpp (1 hunks)
  • src/core/data/electrons/electrons.hpp (4 hunks)
  • src/core/data/ions/ion_population/ion_population.hpp (5 hunks)
  • src/core/data/ions/ions.hpp (9 hunks)
  • src/core/numerics/interpolator/interpolator.hpp (3 hunks)
  • src/core/numerics/ion_updater/ion_updater.hpp (4 hunks)
  • src/core/numerics/moments/moments.hpp (2 hunks)
  • src/diagnostic/detail/types/fluid.hpp (5 hunks)
  • src/phare/phare_init.py (1 hunks)
  • src/phare/phare_init_small.py (1 hunks)
  • src/python3/patch_level.hpp (2 hunks)
  • tests/core/data/electrons/test_electrons.cpp (8 hunks)
  • tests/core/data/ion_population/test_ion_population_fixtures.hpp (1 hunks)
  • tests/core/data/ions/test_ions.cpp (1 hunks)
  • tests/core/numerics/interpolator/test_main.cpp (5 hunks)
  • tests/core/numerics/ion_updater/test_updater.cpp (12 hunks)
  • tests/diagnostic/__init__.py (1 hunks)
  • tests/diagnostic/test_diagnostics.hpp (4 hunks)
  • tests/diagnostic/test_diagnostics.ipp (1 hunks)
  • tests/functional/alfven_wave/alfven_wave1d.py (1 hunks)
  • tests/functional/dispersion/dispersion.py (1 hunks)
  • tests/functional/harris/harris_2d_lb.py (1 hunks)
  • tests/functional/shock/shock.py (1 hunks)
  • tests/functional/td/td1d.py (1 hunks)
  • tests/functional/tdtagged/td1dtagged.py (1 hunks)
  • tests/functional/translation/translat1d.py (2 hunks)
  • tests/simulator/initialize/CMakeLists.txt (1 hunks)
  • tests/simulator/initialize/test_density_init.py (1 hunks)
  • tests/simulator/refinement/test_2d_10_core.py (3 hunks)
  • tests/simulator/refinement/test_2d_2_core.py (3 hunks)
  • tests/simulator/test_advance.py (4 hunks)
  • tests/simulator/test_initialization.py (3 hunks)
  • tests/simulator/test_run.py (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (34)
  • pyphare/pyphare/pharein/diagnostics.py
  • pyphare/pyphare/pharesee/hierarchy/hierarchy_utils.py
  • pyphare/pyphare/pharesee/plotting.py
  • pyphare/pyphare/pharesee/run/run.py
  • pyphare/pyphare_tests/test_pharesee/test_geometry_2d.py
  • pyphare/pyphare_tests/test_pharesee/test_hierarchy.py
  • src/amr/level_initializer/hybrid_level_initializer.hpp
  • src/amr/messengers/hybrid_hybrid_messenger_strategy.hpp
  • src/amr/physical_models/hybrid_model.hpp
  • src/amr/tagging/default_hybrid_tagger_strategy.hpp
  • src/core/data/electrons/electrons.hpp
  • src/core/data/ions/ion_population/ion_population.hpp
  • src/core/numerics/ion_updater/ion_updater.hpp
  • src/phare/phare_init.py
  • src/phare/phare_init_small.py
  • src/python3/patch_level.hpp
  • tests/core/data/electrons/test_electrons.cpp
  • tests/core/data/ion_population/test_ion_population_fixtures.hpp
  • tests/core/data/ions/test_ions.cpp
  • tests/diagnostic/init.py
  • tests/diagnostic/test_diagnostics.hpp
  • tests/diagnostic/test_diagnostics.ipp
  • tests/functional/alfven_wave/alfven_wave1d.py
  • tests/functional/dispersion/dispersion.py
  • tests/functional/harris/harris_2d_lb.py
  • tests/functional/shock/shock.py
  • tests/functional/td/td1d.py
  • tests/functional/tdtagged/td1dtagged.py
  • tests/functional/translation/translat1d.py
  • tests/simulator/initialize/CMakeLists.txt
  • tests/simulator/refinement/test_2d_10_core.py
  • tests/simulator/refinement/test_2d_2_core.py
  • tests/simulator/test_initialization.py
  • tests/simulator/test_run.py
🧰 Additional context used
📓 Path-based instructions (4)
src/core/data/ions/ions.hpp (1)

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

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

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

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

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

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

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

🪛 Ruff
tests/simulator/test_advance.py

312-312: f-string without any placeholders

Remove extraneous f prefix

(F541)

🔇 Additional comments (29)
pyphare/pyphare/pharesee/hierarchy/__init__.py (2)

18-18: LGTM!

The import is correctly placed and properly grouped with related hierarchy imports.


43-47: LGTM! Well-implemented function handling

The implementation includes proper validation and error handling:

  • Checks for both required parameters (func and hier)
  • Validates that func is callable
  • Delegates to the appropriate handler function
src/core/numerics/moments/moments.hpp (1)

51-51: Verify interpolation behavior with new parameters

The interpolate function now handles both particle and charge density. Please ensure:

  1. The interpolation weights are correctly applied for both quantities
  2. The order of parameters matches the interpolator's expectations
  3. The changes are consistent with the physical model requirements

Also applies to: 56-56, 61-61

src/core/data/ions/ions.hpp (4)

44-45: LGTM: Proper initialization of density fields

The initialization order matches the declaration order and uses appropriate quantity types.


60-64: LGTM: Well-designed accessor methods

The accessors properly implement const-correctness and follow consistent naming patterns.


138-142: Previous division by zero warning still applies


239-239: LGTM: Proper member declaration

The chargeDensity_ field is properly declared and ordered consistently with the initialization list.

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

149-150: LGTM: Consistent addition of charge_density diagnostic

The addition of "charge_density" to both population-specific and global ion diagnostics is implemented correctly and maintains consistency with the existing pattern.

Also applies to: 154-155


202-204: LGTM: Improved clarity with particleDensity and consistent charge_density implementation

The renaming from density to particleDensity improves code clarity by being more specific about the quantity being measured. The addition of charge_density checks and info collection is implemented consistently for both individual populations and global ions.

Also applies to: 212-213


274-275: LGTM: Consistent dataset initialization for charge_density

The initialization of charge_density datasets is implemented correctly for both population-specific and global ion diagnostics, following the established pattern.

Also applies to: 283-284


315-317: LGTM: Consistent implementation of charge_density writing

The writing of charge_density data is implemented correctly, maintaining consistency with the changes in getDataSetInfo method. The use of particleDensity maintains naming consistency throughout the class.

Also applies to: 325-326


355-355: LGTM: Complete attribute handling for charge_density

The addition of charge_density to the attribute writing completes the implementation consistently.


Line range hint 149-355: Well-structured implementation of charge density diagnostics

The implementation of charge density diagnostics is thorough and well-structured, maintaining consistency across all relevant methods while following established patterns. The separation between population-specific and global ion diagnostics is clear and maintainable.

Regarding the build failures mentioned in the PR comments, consider implementing the suggested standard deviation comparison approach for noisy quantities. This could be added as a utility method in this class or in a separate helper class.

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

472-474: LGTM! Method signatures updated to handle charge density.

The parameter names are now more descriptive, and the addition of the charge density parameter aligns well with the PR objectives.

Also applies to: 509-512

tests/core/numerics/interpolator/test_main.cpp (4)

519-519: LGTM: Grid variable initialization for charge density.

The new grid variable rho_c is properly initialized with the same parameters as rho, maintaining consistency in the test setup.

Also applies to: 530-530


637-637: Verify test coverage for charge density interpolation.

While the interpolator call has been updated to include rho_c, there are no explicit test assertions verifying the charge density values after interpolation.

Consider adding test assertions for rho_c similar to the existing ones for rho to ensure proper charge density interpolation.


683-683: LGTM: 2D Grid variable initialization for charge density.

The new grid variable rho_c is properly initialized in the 2D test case, maintaining consistency with the 1D implementation.

Also applies to: 690-690


704-704: Add test assertions for 2D charge density interpolation.

Similar to the 1D case, the 2D test should include explicit assertions for rho_c values to verify correct charge density interpolation behavior.

Consider adding test assertions in the DepositCorrectlyTheirWeight_2d test case.

pyphare/pyphare/pharesee/hierarchy/hierarchy.py (2)

375-379: LGTM: Grid initialization is well implemented.

The grid initialization using numpy arrays with NaN values is a good practice for visualization, as it clearly distinguishes between plotted and non-plotted regions.


448-449: LGTM: Improved ghost number retrieval.

The change simplifies the code by directly accessing ghosts_nbr instead of using the layout method, making the code more straightforward and maintainable.

tests/simulator/test_advance.py (4)

155-155: LGTM: Diagnostic quantity updated to reflect charge density.

The change from "density" to "charge_density" aligns with the PR's objective of correctly handling charge density for ion populations.


225-225: LGTM: File references updated consistently.

The h5 file references have been updated to reflect the change from density to charge density, maintaining consistency across the codebase.

Also applies to: 234-234


292-292: Verify the increased tolerance threshold.

The absolute tolerance has been increased from 5.5e-15 to 2.5e-14. While this may be necessary for numerical stability, please ensure this relaxation doesn't mask potential issues in the charge density calculations.

Also applies to: 296-297


296-313: LGTM: Enhanced error reporting with visualization.

Excellent addition of detailed error reporting that includes:

  • Error location visualization
  • Patch box information
  • Coordinate information
    This will significantly improve debugging capabilities for charge density mismatches.
🧰 Tools
🪛 Ruff

312-312: f-string without any placeholders

Remove extraneous f prefix

(F541)

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

214-219: LGTM: Clear separation of particle and charge density fields

The addition of separate fields for particle and charge density improves clarity and accurately represents the physical quantities being simulated.


242-253: Consider adding validation for density field initialization

While the field initialization looks correct, consider adding assertions to verify that the allocated sizes and quantities are properly initialized in both constructors.

Also applies to: 279-290


328-339: LGTM: Proper buffer assignment for both particle and charge densities

The buffer assignments correctly handle both particle and charge densities for each population.

Also applies to: 346-348


577-587: LGTM: Comprehensive moment evolution checks

The test properly verifies the evolution of both particle and charge density moments for all populations.

Also applies to: 616-623


927-936: LGTM: Comprehensive NaN checks for all density types

The test properly verifies that both particle and charge densities are free from NaN values.



def hierarchy_from_func2d(func, hier, **kwargs):
from pyphare.pharesee.hierarchy.hierarchy_utils import compute_hier_from
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Remove duplicate import

The compute_hier_from function is already imported at the module level (line 1). This duplicate import is unnecessary.

-    from pyphare.pharesee.hierarchy.hierarchy_utils import compute_hier_from
📝 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
from pyphare.pharesee.hierarchy.hierarchy_utils import compute_hier_from

Comment on lines +18 to +30
def hierarchy_from_func2d(func, hier, **kwargs):
from pyphare.pharesee.hierarchy.hierarchy_utils import compute_hier_from

def compute_(patch_datas, **kwargs):
ref_name = next(iter(patch_datas.keys()))
x_ = patch_datas[ref_name].x
y_ = patch_datas[ref_name].y

return (
{"name": "value", "data": func(x_, y_, **kwargs), "centering": patch_datas[ref_name].centerings},
)

return compute_hier_from(compute_, hier, **kwargs)
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Add dimension validation for consistency

The 2D function should validate dimensions similarly to the 1D version for consistency.

 def hierarchy_from_func2d(func, hier, **kwargs):
-    from pyphare.pharesee.hierarchy.hierarchy_utils import compute_hier_from
+    if hier.ndim != 2:
+        raise ValueError(f"Expected 2D hierarchy, got {hier.ndim}D")

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +382 to +390
value = collection.get("value", np.nan)
for box in collection["boxes"]:
i0, j0 = box.lower
i1, j1 = box.upper
ij[i0 : i1 + 1, j0 : j1 + 1] = value
if "coords" in collection:
for coords in collection["coords"]:
ij[coords] = collection["value"]

Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add error handling for invalid collection values.

The code should validate collection values before plotting to prevent potential runtime errors.

+            if not isinstance(value, (int, float, np.number)) and not np.isnan(value):
+                raise ValueError(f"Invalid value type in collection: {type(value)}")
             for box in collection["boxes"]:
📝 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
value = collection.get("value", np.nan)
for box in collection["boxes"]:
i0, j0 = box.lower
i1, j1 = box.upper
ij[i0 : i1 + 1, j0 : j1 + 1] = value
if "coords" in collection:
for coords in collection["coords"]:
ij[coords] = collection["value"]
value = collection.get("value", np.nan)
if not isinstance(value, (int, float, np.number)) and not np.isnan(value):
raise ValueError(f"Invalid value type in collection: {type(value)}")
for box in collection["boxes"]:
i0, j0 = box.lower
i1, j1 = box.upper
ij[i0 : i1 + 1, j0 : j1 + 1] = value
if "coords" in collection:
for coords in collection["coords"]:
ij[coords] = collection["value"]

@@ -36,7 +36,7 @@
auto& By = model.state.electromag.B.getComponent(PHARE::core::Component::Y);
auto& Bz = model.state.electromag.B.getComponent(PHARE::core::Component::Z);

auto& N = model.state.ions.density();
// auto& N = model.state.ions.chargeDensity();

Check notice

Code scanning / CodeQL

Commented-out code Note

This comment appears to contain commented-out code.
"facecolor": "yellow",
"value": 1,
Copy link
Member

Choose a reason for hiding this comment

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

is there some reason for this I don't see?

@@ -632,7 +634,7 @@ class ACollectionOfParticles_1d : public ::testing::Test
part.v[2] = +1.;
particles.push_back(part);
}
interpolator(makeIndexRange(particles), rho, v, layout);
interpolator(makeIndexRange(particles), rho, rho_c, v, layout);
Copy link
Member

Choose a reason for hiding this comment

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

is there some check that could be added to the tests DepositCorrectlyTheirWeight_*d

eg

Comment on lines +331 to +332
if __name__ == "__main__":
main()
Copy link
Member

Choose a reason for hiding this comment

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

This test will leave behind diagnostic files which we generally try to avoid across tests

I would suggest you replace the last two lines with something like

from tests.simulator import SimulatorTest

class DensityInitTest(SimulatorTest):
    def __init__(self, *args, **kwargs):
        super(DensityInitTest, self).__init__(*args, **kwargs)
        self.simulator = None

    def tearDown(self):
        super(DensityInitTest, self).tearDown()
        if self.simulator is not None:
            self.simulator.reset()
        self.simulator = None
        ph.global_vars.sim = None

    def test_run(self):
        self.register_diag_dir_for_cleanup("test_densities_1d")
        self.register_diag_dir_for_cleanup("test_densities_2d")
        main()
        return self


if __name__ == "__main__":
    DensityInitTest().test_run().tearDown()

leaving your main() function as is

@@ -472,6 +472,7 @@ def _test_density_is_as_provided_by_user(self, dim, interp_order):
print("patch {}".format(ip))

ion_density = patch.patch_datas["rho"].dataset[:]
# print(patch.patch_datas.items())
Copy link
Member

Choose a reason for hiding this comment

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

✂️

@@ -431,7 +445,8 @@ def plot1d(self, **kwargs):
qty = pdata_names[0]

layout = patch.patch_datas[qty].layout
nbrGhosts = layout.nbrGhostFor(qty)
# nbrGhosts = layout.nbrGhostFor(qty) # bad !!!
Copy link
Member

Choose a reason for hiding this comment

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

bad as there's some inconsistency or some other reason?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants