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

feat: Add a multi-region constant B-field provider #3927

Merged
merged 2 commits into from
Dec 5, 2024

Conversation

stephenswat
Copy link
Member

@stephenswat stephenswat commented Dec 2, 2024

In order to facilitate the ALICE3 use-case (as described to me by @Cas1997) we need to support magnetic fields that are constant in multiple regions, but which may have different field values in each of these regions. I implemented a new magnetic field provider based on a mapping of 3D ranges to field vectors which should support this use case.

The core idea is that the user provides a list of regions and the provider will check (with some simple caching) which region matches. The mechanism implemented is that -- in case of overlap -- the region later in the list takes precedence.

Also implements C++ and Python tests for this new field provider.

Summary by CodeRabbit

Release Notes

  • New Features

    • Introduced the MultiRangeBField class for modeling magnetic fields with multiple overlapping regions.
    • Added the RangeXDDim3 class for handling three-dimensional ranges in the geometry module.
  • Tests

    • Implemented comprehensive tests for the MultiRangeBField class, covering various scenarios to validate its behavior.
    • Added a new test function for the acts.MultiRangeBField class in Python.
  • Documentation

    • Updated documentation to include details about the Acts::MultiRangeBField class and its functionality, including caching mechanisms.
  • Chores

    • Expanded the unit test suite to include tests for the MultiRangeBField class.
    • Added a new source file for the MultiRangeBField class to the project.

Copy link

coderabbitai bot commented Dec 2, 2024

Walkthrough

A new class MultiRangeBField, introduced it is. Extending the MagneticFieldProvider interface, this class models a magnetic field with multiple overlapping regions. Added, too, is a class RangeXDDim3 for handling three-dimensional ranges. Tests for these classes, both unit and integration, implemented have been. Enhance the magnetic field handling and testing capabilities within the project, these changes do.

Changes

File Path Change Summary
Core/include/Acts/MagneticField/MultiRangeBField.hpp Added class MultiRangeBField with constructors and methods for managing multi-range magnetic fields.
Core/src/MagneticField/MultiRangeBField.cpp Implemented MultiRangeBField class, including caching and field retrieval methods.
Examples/Python/src/Geometry.cpp Added class RangeXDDim3 for handling three-dimensional ranges with a constructor.
Examples/Python/src/MagneticField.cpp Added class Acts::MultiRangeBField with Python bindings for multi-range magnetic field representation.
Examples/Python/tests/test_magnetic_field.py Introduced test_multiregion_bfield to test acts.MultiRangeBField behavior and field retrieval.
Tests/UnitTests/Core/MagneticField/CMakeLists.txt Added unit test entry for MultiRangeBField.
Tests/UnitTests/Core/MagneticField/MultiRangeBFieldTests.cpp Created new test file for MultiRangeBField, implementing various test cases for getField.
docs/core/magnetic_field.md Expanded documentation to include Acts::MultiRangeBField class details.

Poem

In the realm of fields, where ranges collide,
MultiRangeBField, a new guide.
With dimensions three, RangeXDDim3,
Expanding horizons, as wide as can be!
Tests now abound, ensuring all's right,
In the dance of the fields, we take flight! 🌌✨


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.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

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.

@stephenswat stephenswat changed the title feat: Add a multi-region constant BField provider feat: Add a multi-region constant B-field provider Dec 2, 2024
@github-actions github-actions bot added this to the next milestone Dec 2, 2024
@github-actions github-actions bot added Component - Core Affects the Core module Component - Examples Affects the Examples module labels Dec 2, 2024
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Outside diff range and nitpick comments (3)
Core/include/Acts/MagneticField/MultiRangeBField.hpp (2)

52-52: Unnecessary semicolon after function definition, there is. Remove it, you should.

The semicolon after the function closing brace is redundant.

Apply this diff to improve code clarity:

-  };
+  }

104-104: Unnecessary semicolon after function definition, there is. Remove it, you should.

The semicolon after the function closing brace is redundant.

Apply this diff to improve code clarity:

-  };
+  }
Examples/Python/src/Geometry.cpp (1)

495-509: Approve the changes, I do. A small suggestion, I have.

Clean and well-structured, this implementation is. Follows the established patterns for RangeXDDim1 and RangeXDDim2, it does. Proper initialization of ranges using the shrink method, I observe.

For consistency with other dimensional implementations and improved readability, consider adding a descriptive comment, you should.

Apply this change, you may:

  {
+   // Python bindings for 3D range implementation used in magnetic field calculations
    using RangeXDDim3 = Acts::RangeXD<3u, double>;

    py::class_<RangeXDDim3>(m, "RangeXDDim3")
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 8895da1 and 44edbb8.

📒 Files selected for processing (6)
  • Core/include/Acts/MagneticField/MultiRangeBField.hpp (1 hunks)
  • Examples/Python/src/Geometry.cpp (1 hunks)
  • Examples/Python/src/MagneticField.cpp (2 hunks)
  • Examples/Python/tests/test_magnetic_field.py (1 hunks)
  • Tests/UnitTests/Core/MagneticField/CMakeLists.txt (1 hunks)
  • Tests/UnitTests/Core/MagneticField/MultiRangeBFieldTests.cpp (1 hunks)
🧰 Additional context used
🪛 cppcheck (2.10-2)
Tests/UnitTests/Core/MagneticField/MultiRangeBFieldTests.cpp

[error] 20-20: syntax error

(syntaxError)

🔇 Additional comments (4)
Tests/UnitTests/Core/MagneticField/CMakeLists.txt (1)

4-4: LGTM, it does.

The addition of the unit test for MultiRangeBField appropriate is. Correct the test configuration is.

Tests/UnitTests/Core/MagneticField/MultiRangeBFieldTests.cpp (1)

20-20: ⚠️ Potential issue

Syntax error detected by static analysis tools, there is. Verify and fix, you must.

Static analysis reports a syntax error on line 20. Ensure that macros and syntax correct are.

Run the following script to identify syntax errors:

🧰 Tools
🪛 cppcheck (2.10-2)

[error] 20-20: syntax error

(syntaxError)

Examples/Python/tests/test_magnetic_field.py (1)

77-112: Good addition of test cases for MultiRangeBField, it is.

Comprehensive the test coverage is, and functionality it validates correctly.

Examples/Python/src/MagneticField.cpp (1)

90-93: Bindings for MultiRangeBField correctly added, they are.

The Python bindings for MultiRangeBField properly defined are, matching the constructor signature.

Core/include/Acts/MagneticField/MultiRangeBField.hpp Outdated Show resolved Hide resolved
Core/include/Acts/MagneticField/MultiRangeBField.hpp Outdated Show resolved Hide resolved
Copy link

github-actions bot commented Dec 2, 2024

📊: Physics performance monitoring for 1d84bb1

Full contents

physmon summary

@beomki-yeo
Copy link
Contributor

It would be nice to support this in covfie field as well or does it already?

@stephenswat
Copy link
Member Author

It would be nice to support this in covfie field as well or does it already?

Of course, that's a good idea. 👍

@stephenswat stephenswat force-pushed the feat/multi_range_bfield branch from 44edbb8 to 93624ea Compare December 2, 2024 11:56
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Outside diff range and nitpick comments (1)
Examples/Python/tests/test_magnetic_field.py (1)

77-112: Enhance the test coverage with random points, we should.

Good tests you have written, but stronger they could become. Like the null_bfield test function above, random point testing add you should.

Apply this enhancement, you could:

def test_multiregion_bfield():
    with pytest.raises(TypeError):
        acts.MultiRangeBField()

    rs = [
        (acts.RangeXDDim3((0, 3), (0, 3), (0, 3)), acts.Vector3(0.0, 0.0, 2.0)),
        (acts.RangeXDDim3((1, 2), (1, 2), (1, 10)), acts.Vector3(2.0, 0.0, 0.0)),
    ]
    f = acts.MultiRangeBField(rs)
    assert f

    ctx = acts.MagneticFieldContext()
    assert ctx

    fc = f.makeCache(ctx)
    assert fc

+   # Random point testing for comprehensive coverage
+   for _ in range(100):
+       x = random.uniform(-1.0, 4.0)
+       y = random.uniform(-1.0, 4.0)
+       z = random.uniform(-1.0, 11.0)
+       rv = f.getField(acts.Vector3(x, y, z), fc)
+       # Assert field values based on point location
+       # Add appropriate assertions here

    # Existing specific test cases below...
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 44edbb8 and 93624ea.

📒 Files selected for processing (6)
  • Core/include/Acts/MagneticField/MultiRangeBField.hpp (1 hunks)
  • Examples/Python/src/Geometry.cpp (1 hunks)
  • Examples/Python/src/MagneticField.cpp (2 hunks)
  • Examples/Python/tests/test_magnetic_field.py (1 hunks)
  • Tests/UnitTests/Core/MagneticField/CMakeLists.txt (1 hunks)
  • Tests/UnitTests/Core/MagneticField/MultiRangeBFieldTests.cpp (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • Tests/UnitTests/Core/MagneticField/CMakeLists.txt
  • Examples/Python/src/MagneticField.cpp
  • Core/include/Acts/MagneticField/MultiRangeBField.hpp
🧰 Additional context used
🪛 cppcheck (2.10-2)
Tests/UnitTests/Core/MagneticField/MultiRangeBFieldTests.cpp

[error] 20-20: syntax error

(syntaxError)

🔇 Additional comments (2)
Tests/UnitTests/Core/MagneticField/MultiRangeBFieldTests.cpp (1)

20-73: Well structured and comprehensive, these tests are!

Cover all essential scenarios, your test cases do:

  • Inside first volume, testing is
  • Second volume verification, included it is
  • Overlap regions, handled they are
  • Outside volumes, tested it is also

Pleased with this implementation, I am.

🧰 Tools
🪛 cppcheck (2.10-2)

[error] 20-20: syntax error

(syntaxError)

Examples/Python/src/Geometry.cpp (1)

495-508: Consistent with the Force, this implementation is!

Follow the established patterns of RangeXDDim1 and RangeXDDim2, it does. Clean and well-structured, the code is.

Copy link
Member

@paulgessinger paulgessinger left a comment

Choose a reason for hiding this comment

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

We could even consider making the regular ConstantBField use this behind the scenes, since it's essentially a special case.

@stephenswat stephenswat force-pushed the feat/multi_range_bfield branch from 93624ea to b55fbc1 Compare December 2, 2024 12:58
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Outside diff range and nitpick comments (4)
Examples/Python/src/Geometry.cpp (1)

495-509: Approve this implementation, I do.

Proper and consistent with its siblings RangeXDDim1 and RangeXDDim2, this implementation is. Well-structured binding for three-dimensional ranges, you have created. Follows the established patterns of pybind11, it does.

A suggestion for documentation, I have:

    {
+     // Binding for three-dimensional range support
      using RangeXDDim3 = Acts::RangeXD<3u, double>;

      py::class_<RangeXDDim3>(m, "RangeXDDim3")
Tests/UnitTests/Core/MagneticField/MultiRangeBFieldTests.cpp (2)

20-39: Define tolerance as named constant, hmm yes.

Magic number 0.05 for comparison tolerance, I see. Better readability and maintainability, a named constant would provide.

+ constexpr double kFieldTolerance = 0.05;
  BOOST_AUTO_TEST_CASE(TestMultiRangeBField) {
    // ... existing code ...
-   BOOST_CHECK_CLOSE((*r)[0], 0., 0.05);
-   BOOST_CHECK_CLOSE((*r)[1], 0., 0.05);
-   BOOST_CHECK_CLOSE((*r)[2], 2., 0.05);
+   BOOST_CHECK_CLOSE((*r)[0], 0., kFieldTolerance);
+   BOOST_CHECK_CLOSE((*r)[1], 0., kFieldTolerance);
+   BOOST_CHECK_CLOSE((*r)[2], 2., kFieldTolerance);
🧰 Tools
🪛 cppcheck (2.10-2)

[error] 20-20: syntax error

(syntaxError)


1-74: Additional test cases, we need.

Well-structured the tests are, but edge cases we must also verify. Test points exactly on region boundaries and corners, we should.

Add these test cases:

// Test point exactly on boundary
{
  Result<Vector3> r = bfield.getField({3.0, 3.0, 3.0}, bcache);
  BOOST_CHECK(r.ok());
  BOOST_CHECK_CLOSE((*r)[0], 0., kFieldTolerance);
  BOOST_CHECK_CLOSE((*r)[1], 0., kFieldTolerance);
  BOOST_CHECK_CLOSE((*r)[2], 2., kFieldTolerance);
}

// Test point on corner where regions meet
{
  Result<Vector3> r = bfield.getField({1.0, 1.0, 1.0}, bcache);
  BOOST_CHECK(r.ok());
  BOOST_CHECK_CLOSE((*r)[0], 2., kFieldTolerance);
  BOOST_CHECK_CLOSE((*r)[1], 0., kFieldTolerance);
  BOOST_CHECK_CLOSE((*r)[2], 0., kFieldTolerance);
}
🧰 Tools
🪛 cppcheck (2.10-2)

[error] 20-20: syntax error

(syntaxError)

docs/core/magnetic_field.md (1)

240-250: Grammar and formatting improvements, need we do.

Consistent with style guide, these changes must be:

-The multi-range constant field allows to model cases where a magnetic field can
+The multi-range constant field allows modeling cases where a magnetic field can
 be described as multiple (potentially overlapping) regions, each of which has
 its own constant magnetic field.

 Magnetic field lookup then proceeds by finding the _last_ region in the
-user-provided list which contains the requested coordinate and returning the
+user-provided list that contains the requested coordinate and returning the
 corresponding field vector.
🧰 Tools
🪛 LanguageTool

[grammar] ~240-~240: Did you mean “modeling”, “modelling”? Or maybe you should add a pronoun? In active voice, ‘allow’ + ‘to’ takes an object, usually a pronoun.
Context: ... The multi-range constant field allows to model cases where a magnetic field can be des...

(ALLOW_TO)

🪛 Markdownlint (0.35.0)

248-248: Expected: asterisk; Actual: underscore
Emphasis style

(MD049, emphasis-style)


248-248: Expected: asterisk; Actual: underscore
Emphasis style

(MD049, emphasis-style)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 93624ea and b55fbc1.

📒 Files selected for processing (7)
  • Core/include/Acts/MagneticField/MultiRangeBField.hpp (1 hunks)
  • Examples/Python/src/Geometry.cpp (1 hunks)
  • Examples/Python/src/MagneticField.cpp (2 hunks)
  • Examples/Python/tests/test_magnetic_field.py (1 hunks)
  • Tests/UnitTests/Core/MagneticField/CMakeLists.txt (1 hunks)
  • Tests/UnitTests/Core/MagneticField/MultiRangeBFieldTests.cpp (1 hunks)
  • docs/core/magnetic_field.md (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • Tests/UnitTests/Core/MagneticField/CMakeLists.txt
  • Examples/Python/tests/test_magnetic_field.py
  • Examples/Python/src/MagneticField.cpp
  • Core/include/Acts/MagneticField/MultiRangeBField.hpp
🧰 Additional context used
🪛 LanguageTool
docs/core/magnetic_field.md

[grammar] ~240-~240: Did you mean “modeling”, “modelling”? Or maybe you should add a pronoun? In active voice, ‘allow’ + ‘to’ takes an object, usually a pronoun.
Context: ... The multi-range constant field allows to model cases where a magnetic field can be des...

(ALLOW_TO)

🪛 Markdownlint (0.35.0)
docs/core/magnetic_field.md

248-248: Expected: asterisk; Actual: underscore
Emphasis style

(MD049, emphasis-style)


248-248: Expected: asterisk; Actual: underscore
Emphasis style

(MD049, emphasis-style)

🪛 cppcheck (2.10-2)
Tests/UnitTests/Core/MagneticField/MultiRangeBFieldTests.cpp

[error] 20-20: syntax error

(syntaxError)

docs/core/magnetic_field.md Outdated Show resolved Hide resolved
@github-actions github-actions bot added the Component - Documentation Affects the documentation label Dec 2, 2024
@stephenswat stephenswat force-pushed the feat/multi_range_bfield branch from b55fbc1 to c6e2dee Compare December 2, 2024 13:49
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Outside diff range and nitpick comments (1)
docs/core/magnetic_field.md (1)

248-248: Emphasis style, inconsistent it is.

Underscores for emphasis used, asterisks preferred they are. Consistency maintain, you should.

Apply this diff to correct the emphasis:

-    Magnetic field lookup then proceeds by finding the _last_ region in the
+    Magnetic field lookup then proceeds by finding the *last* region in the
🧰 Tools
🪛 Markdownlint (0.35.0)

248-248: Expected: asterisk; Actual: underscore
Emphasis style

(MD049, emphasis-style)


248-248: Expected: asterisk; Actual: underscore
Emphasis style

(MD049, emphasis-style)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between b55fbc1 and c6e2dee.

📒 Files selected for processing (9)
  • Core/include/Acts/MagneticField/MultiRangeBField.hpp (1 hunks)
  • Core/src/MagneticField/CMakeLists.txt (1 hunks)
  • Core/src/MagneticField/MultiRangeBField.cpp (1 hunks)
  • Examples/Python/src/Geometry.cpp (1 hunks)
  • Examples/Python/src/MagneticField.cpp (2 hunks)
  • Examples/Python/tests/test_magnetic_field.py (1 hunks)
  • Tests/UnitTests/Core/MagneticField/CMakeLists.txt (1 hunks)
  • Tests/UnitTests/Core/MagneticField/MultiRangeBFieldTests.cpp (1 hunks)
  • docs/core/magnetic_field.md (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • Tests/UnitTests/Core/MagneticField/CMakeLists.txt
  • Examples/Python/tests/test_magnetic_field.py
  • Examples/Python/src/MagneticField.cpp
  • Core/include/Acts/MagneticField/MultiRangeBField.hpp
🧰 Additional context used
🪛 Markdownlint (0.35.0)
docs/core/magnetic_field.md

248-248: Expected: asterisk; Actual: underscore
Emphasis style

(MD049, emphasis-style)


248-248: Expected: asterisk; Actual: underscore
Emphasis style

(MD049, emphasis-style)

🪛 cppcheck (2.10-2)
Tests/UnitTests/Core/MagneticField/MultiRangeBFieldTests.cpp

[error] 20-20: syntax error

(syntaxError)

🔇 Additional comments (5)
Core/src/MagneticField/MultiRangeBField.cpp (2)

15-21: Constructors well-defined, they are.

Initialization with both lvalue and rvalue references handled efficiently.


27-71: Efficient caching mechanism, implemented you have.

Caching of the last matched range optimizes field retrieval performance.

Core/src/MagneticField/CMakeLists.txt (1)

7-7: New source file added correctly, it is.

MultiRangeBField.cpp included in target sources as required.

docs/core/magnetic_field.md (1)

238-256: Additional documentation, beneficial it would be.

Details on performance characteristics, cache implementation benefits, and thread safety guarantees, provide you should.

Consider adding these sections to enrich the documentation:

+### Performance and Implementation Details
+
+The implementation uses a simple caching mechanism to store the last matched
+region, providing improved performance for consecutive lookups within the same
+region. Compared to `ConstantBField`, this implementation has minimal overhead
+when using a single region, and scales linearly with the number of regions.
+
+### Thread Safety
+
+The `MultiRangeBField` is thread-safe when each thread uses its own cache
+instance obtained through `makeCache()`. The field configuration itself is
+immutable after construction.
🧰 Tools
🪛 Markdownlint (0.35.0)

248-248: Expected: asterisk; Actual: underscore
Emphasis style

(MD049, emphasis-style)


248-248: Expected: asterisk; Actual: underscore
Emphasis style

(MD049, emphasis-style)

Examples/Python/src/Geometry.cpp (1)

495-508: Exposing 3D range to Python, good this is.

The RangeXDDim3 class added, allowing three-dimensional range handling in Python bindings.

@stephenswat stephenswat force-pushed the feat/multi_range_bfield branch from c6e2dee to b4c1434 Compare December 3, 2024 13:10
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Outside diff range and nitpick comments (4)
Tests/UnitTests/Core/MagneticField/MultiRangeBFieldTests.cpp (2)

21-31: More descriptive names for test data, suggest I do.

Clearer intent, better variable names would show. Consider these changes:

-  std::vector<std::pair<RangeXD<3, double>, Vector3>> inputs;
+  std::vector<std::pair<RangeXD<3, double>, Vector3>> fieldRegions;

-  inputs.emplace_back(
+  fieldRegions.emplace_back(

32-72: Additional test scenarios, consider we should.

Well-structured your tests are, but stronger they could become. Additional scenarios to consider:

  • Test with empty region list
  • Test with single region
  • Test region priority with complete overlap

Help with implementing these test cases, would you like?

Examples/Python/tests/test_magnetic_field.py (1)

77-112: Use pytest fixtures for test data, recommend I do.

Good your tests are, but better organization achieve we can. Create a fixture for field regions and context:

@pytest.fixture
def field_regions():
    return [
        (acts.RangeXDDim3((0, 3), (0, 3), (0, 3)), acts.Vector3(0.0, 0.0, 2.0)),
        (acts.RangeXDDim3((1, 2), (1, 2), (1, 10)), acts.Vector3(2.0, 0.0, 0.0)),
    ]

@pytest.fixture
def field_context():
    return acts.MagneticFieldContext()

Cleaner and more reusable, your tests will become.

Examples/Python/src/Geometry.cpp (1)

495-508: Approve the implementation, I do. A suggestion for consistency, I have.

Clean and well-structured, the implementation is. Follows the established patterns for RangeXDDim1 and RangeXDDim2, it does. Yet, for better consistency with sibling implementations, a surfaces method could be beneficial.

Consider adding this implementation, you should:

 py::class_<RangeXDDim3>(m, "RangeXDDim3")
     .def(py::init([](const std::array<double, 2u>& range0,
                      const std::array<double, 2u>& range1,
                      const std::array<double, 2u>& range2) {
       RangeXDDim3 range;
       range[0].shrink(range0[0], range0[1]);
       range[1].shrink(range1[0], range1[1]);
       range[2].shrink(range2[0], range2[1]);
       return range;
     }));
+    .def("surfaces", py::overload_cast<const RangeXDDim3&>(
+        &RangeXDDim3::surfaces, py::const_));
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between c6e2dee and b4c1434.

📒 Files selected for processing (9)
  • Core/include/Acts/MagneticField/MultiRangeBField.hpp (1 hunks)
  • Core/src/MagneticField/CMakeLists.txt (1 hunks)
  • Core/src/MagneticField/MultiRangeBField.cpp (1 hunks)
  • Examples/Python/src/Geometry.cpp (1 hunks)
  • Examples/Python/src/MagneticField.cpp (2 hunks)
  • Examples/Python/tests/test_magnetic_field.py (1 hunks)
  • Tests/UnitTests/Core/MagneticField/CMakeLists.txt (1 hunks)
  • Tests/UnitTests/Core/MagneticField/MultiRangeBFieldTests.cpp (1 hunks)
  • docs/core/magnetic_field.md (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (5)
  • Core/src/MagneticField/MultiRangeBField.cpp
  • Core/include/Acts/MagneticField/MultiRangeBField.hpp
  • Core/src/MagneticField/CMakeLists.txt
  • Tests/UnitTests/Core/MagneticField/CMakeLists.txt
  • Examples/Python/src/MagneticField.cpp
🧰 Additional context used
🪛 Markdownlint (0.35.0)
docs/core/magnetic_field.md

248-248: Expected: asterisk; Actual: underscore
Emphasis style

(MD049, emphasis-style)


248-248: Expected: asterisk; Actual: underscore
Emphasis style

(MD049, emphasis-style)

🪛 cppcheck (2.10-2)
Tests/UnitTests/Core/MagneticField/MultiRangeBFieldTests.cpp

[error] 20-20: syntax error

(syntaxError)

🔇 Additional comments (2)
Tests/UnitTests/Core/MagneticField/MultiRangeBFieldTests.cpp (1)

20-20: Fix the syntax error in test case declaration, you must.

A syntax error in the test case declaration, I sense. Follow the BOOST test macro style guidelines, we should.

Apply this diff to correct the syntax:

-BOOST_AUTO_TEST_CASE(TestMultiRangeBField) {
+BOOST_AUTO_TEST_CASE(TestMultiRangeBField)
+{
🧰 Tools
🪛 cppcheck (2.10-2)

[error] 20-20: syntax error

(syntaxError)

docs/core/magnetic_field.md (1)

238-259: More documentation details, require we do.

Clear the basic functionality is, but missing important details I sense:

  • Performance characteristics compared to other implementations
  • Cache implementation and its benefits
  • Thread safety guarantees

Add these sections to documentation, you should:

 corresponding field vector.

+### Performance and Implementation Details
+
+The implementation uses a simple caching mechanism to store the last matched
+region, providing improved performance for consecutive lookups within the same
+region. Compared to `ConstantBField`, this implementation has minimal overhead
+when using a single region, and scales linearly with the number of regions.
+
+### Thread Safety
+
+The `MultiRangeBField` is thread-safe when each thread uses its own cache
+instance obtained through `makeCache()`. The field configuration itself is
+immutable after construction.
🧰 Tools
🪛 Markdownlint (0.35.0)

248-248: Expected: asterisk; Actual: underscore
Emphasis style

(MD049, emphasis-style)


248-248: Expected: asterisk; Actual: underscore
Emphasis style

(MD049, emphasis-style)

Copy link
Member

@paulgessinger paulgessinger left a comment

Choose a reason for hiding this comment

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

I have one more nitpick.

Core/src/MagneticField/MultiRangeBField.cpp Outdated Show resolved Hide resolved
@stephenswat stephenswat force-pushed the feat/multi_range_bfield branch from b4c1434 to 954072f Compare December 3, 2024 14:37
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Outside diff range and nitpick comments (4)
Tests/UnitTests/Core/MagneticField/MultiRangeBFieldTests.cpp (1)

32-39: Well structured test cases, these are. Approve them, I do.

Comprehensive coverage of test scenarios, you have achieved:

  • Testing points inside first volume
  • Testing points inside second volume
  • Testing points in overlap region
  • Testing points outside all volumes

Good use of BOOST_CHECK and BOOST_CHECK_CLOSE for assertions, I observe.

Consider adding more descriptive comments for each test block to explain the expected behavior in detail, you should.

Also applies to: 41-48, 50-57, 59-66, 68-72

Examples/Python/tests/test_magnetic_field.py (1)

77-112: Strong with the Force, these Python tests are.

Well-structured test cases that mirror the C++ tests, you have created. Good practices observed:

  • Testing error cases with pytest.raises
  • Comprehensive field value verification
  • Clear test structure

Add docstring to explain test purpose and scenarios, you should. Example:

def test_multiregion_bfield():
    """Test MultiRangeBField behavior with overlapping regions.
    
    Test cases:
    - Invalid instantiation
    - Field values in first region
    - Field values in second region
    - Field values in overlap region
    """
docs/core/magnetic_field.md (2)

238-244: Add context about ALICE3 use case, we must.

Clear the basic functionality is, but strengthen the documentation with real-world example, we should. Add a note about ALICE3 use case, I suggest:

 has its own constant magnetic field. This provides more flexibility than the
 {class}`Acts::ConstantBField` while providing higher performance than
-{class}`Acts::InterpolatedBFieldMap`.
+{class}`Acts::InterpolatedBFieldMap`.
+
+This implementation was primarily motivated by the ALICE3 experiment, where
+different detector regions require distinct constant magnetic field values.

248-248: Consistent emphasis style, maintain we must.

Replace underscore with asterisk for emphasis, according to project style:

-Magnetic field lookup then proceeds by finding the _last_ region in the
+Magnetic field lookup then proceeds by finding the *last* region in the
🧰 Tools
🪛 Markdownlint (0.35.0)

248-248: Expected: asterisk; Actual: underscore
Emphasis style

(MD049, emphasis-style)


248-248: Expected: asterisk; Actual: underscore
Emphasis style

(MD049, emphasis-style)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between b4c1434 and 954072f.

📒 Files selected for processing (9)
  • Core/include/Acts/MagneticField/MultiRangeBField.hpp (1 hunks)
  • Core/src/MagneticField/CMakeLists.txt (1 hunks)
  • Core/src/MagneticField/MultiRangeBField.cpp (1 hunks)
  • Examples/Python/src/Geometry.cpp (1 hunks)
  • Examples/Python/src/MagneticField.cpp (2 hunks)
  • Examples/Python/tests/test_magnetic_field.py (1 hunks)
  • Tests/UnitTests/Core/MagneticField/CMakeLists.txt (1 hunks)
  • Tests/UnitTests/Core/MagneticField/MultiRangeBFieldTests.cpp (1 hunks)
  • docs/core/magnetic_field.md (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (5)
  • Tests/UnitTests/Core/MagneticField/CMakeLists.txt
  • Core/src/MagneticField/CMakeLists.txt
  • Examples/Python/src/MagneticField.cpp
  • Core/src/MagneticField/MultiRangeBField.cpp
  • Core/include/Acts/MagneticField/MultiRangeBField.hpp
🧰 Additional context used
🪛 Markdownlint (0.35.0)
docs/core/magnetic_field.md

248-248: Expected: asterisk; Actual: underscore
Emphasis style

(MD049, emphasis-style)


248-248: Expected: asterisk; Actual: underscore
Emphasis style

(MD049, emphasis-style)

🪛 cppcheck (2.10-2)
Tests/UnitTests/Core/MagneticField/MultiRangeBFieldTests.cpp

[error] 20-20: syntax error

(syntaxError)

🔇 Additional comments (4)
Tests/UnitTests/Core/MagneticField/MultiRangeBFieldTests.cpp (1)

20-20: Fix the syntax error in test case declaration, you must.

A syntax error in the test case declaration, there is. Match the existing review comment, this does.

🧰 Tools
🪛 cppcheck (2.10-2)

[error] 20-20: syntax error

(syntaxError)

Examples/Python/src/Geometry.cpp (1)

495-508: Clean and consistent implementation, this is.

Follow the established pattern of RangeXDDim1 and RangeXDDim2, it does. Good practices observed:

  • Proper use of pybind11 for Python bindings
  • Consistent implementation pattern
  • Clear parameter handling

Verify consistency with other dimensional implementations, we must:

✅ Verification successful

Verified, the consistency is. Approved, this implementation shall be.

Through the Force, seen the implementations I have. Perfect alignment exists:

  • Each dimension (1,2,3) follows same pattern of initialization
  • Consistent use of shrink() method for range boundaries
  • Proper parameter handling with std::array<double, 2u>

Most importantly, follows the established pattern perfectly, RangeXDDim3 does. A natural progression from RangeXDDim1 and RangeXDDim2, it represents.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check consistency across RangeXD implementations
rg -A 10 "RangeXDDim[123]" Examples/Python/src/Geometry.cpp

Length of output: 3191

docs/core/magnetic_field.md (2)

252-256: Well documented, the implementation details are.

Clear explanation of caching mechanism and thread safety guarantees, you provide. Addressed previous review concerns about documentation completeness, this has.


257-259: Properly integrated, the class reference is.

Follows the established documentation pattern, this does. Consistent with other class references in the document, it is.

@stephenswat stephenswat force-pushed the feat/multi_range_bfield branch from 954072f to 45d2a4c Compare December 3, 2024 14:51
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Outside diff range and nitpick comments (7)
Tests/UnitTests/Core/MagneticField/MultiRangeBFieldTests.cpp (3)

23-26: More descriptive comments for test regions, need we do.

Clearer understanding of test regions, help others it would. Add comments explaining the physical meaning and purpose of each region's coordinates and field values.

 inputs.emplace_back(RangeXD<3, double>{{0., 0., 0.}, {3., 3., 3.}},
                     Vector3{0., 0., 2.});
+// First region: Cubic volume from origin to (3,3,3) with 2T field in z-direction
 inputs.emplace_back(RangeXD<3, double>{{1., 1., 1.}, {2., 2., 10.}},
                     Vector3{2., 0., 0.});
+// Second region: Elongated volume with 2T field in x-direction, overlapping first region

34-38: A helper function for field verification, create we should.

Repeated verification pattern, I see. A helper function, reduce duplication it would.

+namespace {
+void checkField(const Result<Vector3>& r, double x, double y, double z) {
+  BOOST_CHECK(r.ok());
+  BOOST_CHECK_CLOSE((*r)[0], x, 0.05);
+  BOOST_CHECK_CLOSE((*r)[1], y, 0.05);
+  BOOST_CHECK_CLOSE((*r)[2], z, 0.05);
+}
+}  // namespace
+
 Result<Vector3> r = bfield.getField({0.5, 0.5, 0.5}, bcache);
-BOOST_CHECK(r.ok());
-BOOST_CHECK_CLOSE((*r)[0], 0., 0.05);
-BOOST_CHECK_CLOSE((*r)[1], 0., 0.05);
-BOOST_CHECK_CLOSE((*r)[2], 2., 0.05);
+checkField(r, 0., 0., 2.);

60-66: Document overlapping region behavior, we must.

Clear the behavior is, but explicit documentation missing it is. Add comment explaining precedence rules.

-  // Test a point inside the second volume in the overlap region.
+  // Test a point inside the overlap region between volumes.
+  // Expect field from second volume (2T in x-direction) as it appears later in the list,
+  // demonstrating the last-match-wins behavior for overlapping regions.
   {
     Result<Vector3> r = bfield.getField({1.5, 1.5, 1.5}, bcache);
Examples/Python/tests/test_magnetic_field.py (2)

78-79: More Pythonic assertions, use we should.

The force of Python's context manager, strong it is. Better error message, provide we must.

-    with pytest.raises(TypeError):
-        acts.MultiRangeBField()
+    with pytest.raises(TypeError, match=".*at least 1 argument.*"):
+        acts.MultiRangeBField()

94-112: A helper function for field assertions, create we must.

Repeated assertions, I see. DRY principles, follow we should.

+def assert_field_vector(rv, x, y, z):
+    """Assert that field vector components match expected values."""
+    assert rv[0] == pytest.approx(x)
+    assert rv[1] == pytest.approx(y)
+    assert rv[2] == pytest.approx(z)
+
 rv = f.getField(acts.Vector3(0.5, 0.5, 0.5), fc)
-assert rv[0] == pytest.approx(0.0)
-assert rv[1] == pytest.approx(0.0)
-assert rv[2] == pytest.approx(2.0)
+assert_field_vector(rv, 0.0, 0.0, 2.0)
docs/core/magnetic_field.md (1)

238-259: Enhanced documentation with examples and performance details, add we must.

Clear the documentation is, but stronger with examples and performance characteristics it would be.

Add these sections to documentation:

 field configuration itself is immutable after construction.
+
+#### Example Configuration
+
+```cpp
+std::vector<std::pair<Acts::RangeXD<3, double>, Acts::Vector3>> regions;
+// Define a 2T field in z-direction for a cubic volume
+regions.emplace_back(
+    Acts::RangeXD<3, double>{{0., 0., 0.}, {3., 3., 3.}},
+    Acts::Vector3{0., 0., 2.});
+// Define a 2T field in x-direction for an overlapping volume
+regions.emplace_back(
+    Acts::RangeXD<3, double>{{1., 1., 1.}, {2., 2., 10.}},
+    Acts::Vector3{2., 0., 0.});
+Acts::MultiRangeBField bfield(std::move(regions));
+```
+
+#### Performance Characteristics
+
+The implementation has O(n) complexity for field lookup, where n is the number
+of regions. However, the caching mechanism provides O(1) lookup for consecutive
+queries within the same region, making it efficient for typical use cases where
+field queries follow continuous trajectories.
🧰 Tools
🪛 Markdownlint (0.35.0)

248-248: Expected: asterisk; Actual: underscore
Emphasis style

(MD049, emphasis-style)


248-248: Expected: asterisk; Actual: underscore
Emphasis style

(MD049, emphasis-style)

Examples/Python/src/Geometry.cpp (1)

495-508: Approve the changes, I do. Hmmmm.

Well-implemented, the Python bindings for RangeXDDim3 are. Follows the established patterns of dimension 1 and 2, it does. Consistent with the Force, your code is.

A small suggestion, I have. For consistency with RangeXDDim1 and RangeXDDim2, consider adding the surfaces method binding, you should:

    py::class_<RangeXDDim3>(m, "RangeXDDim3")
        .def(py::init([](const std::array<double, 2u>& range0,
                         const std::array<double, 2u>& range1,
                         const std::array<double, 2u>& range2) {
          RangeXDDim3 range;
          range[0].shrink(range0[0], range0[1]);
          range[1].shrink(range1[0], range1[1]);
          range[2].shrink(range2[0], range2[1]);
          return range;
        }));
+       .def("surfaces", py::overload_cast<const RangeXDDim3&>(
+            &KdtSurfacesDim3Bin100::surfaces, py::const_));
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 954072f and 45d2a4c.

📒 Files selected for processing (9)
  • Core/include/Acts/MagneticField/MultiRangeBField.hpp (1 hunks)
  • Core/src/MagneticField/CMakeLists.txt (1 hunks)
  • Core/src/MagneticField/MultiRangeBField.cpp (1 hunks)
  • Examples/Python/src/Geometry.cpp (1 hunks)
  • Examples/Python/src/MagneticField.cpp (2 hunks)
  • Examples/Python/tests/test_magnetic_field.py (1 hunks)
  • Tests/UnitTests/Core/MagneticField/CMakeLists.txt (1 hunks)
  • Tests/UnitTests/Core/MagneticField/MultiRangeBFieldTests.cpp (1 hunks)
  • docs/core/magnetic_field.md (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (5)
  • Core/src/MagneticField/CMakeLists.txt
  • Tests/UnitTests/Core/MagneticField/CMakeLists.txt
  • Examples/Python/src/MagneticField.cpp
  • Core/src/MagneticField/MultiRangeBField.cpp
  • Core/include/Acts/MagneticField/MultiRangeBField.hpp
🧰 Additional context used
🪛 Markdownlint (0.35.0)
docs/core/magnetic_field.md

248-248: Expected: asterisk; Actual: underscore
Emphasis style

(MD049, emphasis-style)


248-248: Expected: asterisk; Actual: underscore
Emphasis style

(MD049, emphasis-style)

🪛 cppcheck (2.10-2)
Tests/UnitTests/Core/MagneticField/MultiRangeBFieldTests.cpp

[error] 20-20: syntax error

(syntaxError)

@stephenswat stephenswat force-pushed the feat/multi_range_bfield branch from 45d2a4c to 46f5666 Compare December 4, 2024 21:29
In order to facilitate the ALICE3 use-case (as described to me by
@Cas1997) we need to support magnetic fields that are constant in
multiple regions, but which may have different field values in each of
these regions. I implemented a new magnetic field provider based on a
mapping of 3D ranges to field vectors which should support this use
case.

The core idea is that the user provides a list of regions and the
provider will check (with some simple caching) which region matches. The
mechanism implemented is that -- in case of overlap -- the region later
in the list takes precedence.

Also implements C++ and Python tests for this new field provider.
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Outside diff range and nitpick comments (2)
Examples/Python/tests/test_magnetic_field.py (1)

77-112: Add test case for point outside all regions, you should.

Currently, no test for points outside defined volumes, there is. Ensure correct behavior when position is outside all ranges, you must.

Consider adding this test:

rv = f.getField(acts.Vector3(-1.0, -1.0, -1.0), fc)
assert rv is None or rv == pytest.approx(acts.Vector3(0.0, 0.0, 0.0))
docs/core/magnetic_field.md (1)

248-248: Use asterisks for emphasis, you should.

Markdownlint advises replacing underscores with asterisks for emphasis style consistency.

Apply this diff to fix the emphasis style:

-Magnetic field lookup then proceeds by finding the _last_ region in the
+Magnetic field lookup then proceeds by finding the *last* region in the
🧰 Tools
🪛 Markdownlint (0.35.0)

248-248: Expected: asterisk; Actual: underscore
Emphasis style

(MD049, emphasis-style)


248-248: Expected: asterisk; Actual: underscore
Emphasis style

(MD049, emphasis-style)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 45d2a4c and 46f5666.

📒 Files selected for processing (9)
  • Core/include/Acts/MagneticField/MultiRangeBField.hpp (1 hunks)
  • Core/src/MagneticField/CMakeLists.txt (1 hunks)
  • Core/src/MagneticField/MultiRangeBField.cpp (1 hunks)
  • Examples/Python/src/Geometry.cpp (1 hunks)
  • Examples/Python/src/MagneticField.cpp (2 hunks)
  • Examples/Python/tests/test_magnetic_field.py (1 hunks)
  • Tests/UnitTests/Core/MagneticField/CMakeLists.txt (1 hunks)
  • Tests/UnitTests/Core/MagneticField/MultiRangeBFieldTests.cpp (1 hunks)
  • docs/core/magnetic_field.md (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • Tests/UnitTests/Core/MagneticField/CMakeLists.txt
  • Core/src/MagneticField/CMakeLists.txt
  • Examples/Python/src/MagneticField.cpp
  • Core/include/Acts/MagneticField/MultiRangeBField.hpp
🧰 Additional context used
🪛 Markdownlint (0.35.0)
docs/core/magnetic_field.md

248-248: Expected: asterisk; Actual: underscore
Emphasis style

(MD049, emphasis-style)


248-248: Expected: asterisk; Actual: underscore
Emphasis style

(MD049, emphasis-style)

🪛 cppcheck (2.10-2)
Tests/UnitTests/Core/MagneticField/MultiRangeBFieldTests.cpp

[error] 20-20: syntax error

(syntaxError)

🔇 Additional comments (3)
Tests/UnitTests/Core/MagneticField/MultiRangeBFieldTests.cpp (2)

36-38: Review the tolerance value in BOOST_CHECK_CLOSE, you should.

The tolerance is set to 0.05, representing 0.05%. Perhaps 5.0% tolerance intended, you did. Adjust accordingly, if necessary.

Also applies to: 45-47, 54-56, 63-65


20-20: ⚠️ Potential issue

Syntax error at line 20, there is.

Static analysis reports a syntax error in the test case declaration. Verify the BOOST test macro and ensure proper syntax, you must.

Apply this diff to correct the syntax:

-BOOST_AUTO_TEST_CASE(TestMultiRangeBField) {
+BOOST_AUTO_TEST_CASE(TestMultiRangeBField)
+{
🧰 Tools
🪛 cppcheck (2.10-2)

[error] 20-20: syntax error

(syntaxError)

Examples/Python/src/Geometry.cpp (1)

495-508: Successfully exposed RangeXDDim3 to Python, you have.

Enhances functionality by allowing 3D ranges in Python bindings, it does.

Core/src/MagneticField/MultiRangeBField.cpp Show resolved Hide resolved
@andiwand
Copy link
Contributor

andiwand commented Dec 5, 2024

resolved the AI conversations to make this pass

@kodiakhq kodiakhq bot merged commit b3933b0 into acts-project:main Dec 5, 2024
48 checks passed
@github-actions github-actions bot removed the automerge label Dec 5, 2024
@acts-project-service
Copy link
Collaborator

🔴 Athena integration test results [b3933b0]

Build job with this PR failed!

Please investigate the build job for the pipeline!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Breaks Athena build This PR breaks the Athena build Component - Core Affects the Core module Component - Documentation Affects the documentation Component - Examples Affects the Examples module
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants