Skip to content

[Ramses] allow setting field values in bulk (with numba)#1676

Draft
tdavidcl wants to merge 1 commit intoShamrock-code:mainfrom
tdavidcl:patch-2026-02-23-15-53
Draft

[Ramses] allow setting field values in bulk (with numba)#1676
tdavidcl wants to merge 1 commit intoShamrock-code:mainfrom
tdavidcl:patch-2026-02-23-15-53

Conversation

@tdavidcl
Copy link
Member

To be cleaned but that's the idea

no @njit
Info: Time to compute in_values: 0.238270372 s for 262144 objects for field rho                                      [Godunov][rank=0] 
Info: Time to compute in_values: 3.8886006820000003 s for 262144 objects for field rhoetot                           [Godunov][rank=0] 
Info: Time to compute in_values: 3.4623040090000003 s for 262144 objects for field rhovel                            [Godunov][rank=0] 
with @njit
Info: Time to compute in_values: 0.591303161 s for 262144 objects for field rho                                      [Godunov][rank=0] 
Info: Time to compute in_values: 0.6172559750000001 s for 262144 objects for field rhoetot                           [Godunov][rank=0] 
Info: Time to compute in_values: 0.6365060060000001 s for 262144 objects for field rhovel                            [Godunov][rank=0] 
bulk
Info: Time to compute in_values: 0.804606302 s for 262144 objects for field rho                                      [Godunov][rank=0] 
Info: Time to compute in_values: 5.476386563 s for 262144 objects for field rhoetot                                  [Godunov][rank=0] 
Info: Time to compute in_values: 4.768827838 s for 262144 objects for field rhovel                                   [Godunov][rank=0] 
bulk @njit
Info: Time to compute in_values: 0.163942251 s for 262144 objects for field rho                                      [Godunov][rank=0] 
Info: Time to compute in_values: 0.351530924 s for 262144 objects for field rhoetot                                  [Godunov][rank=0] 
Inf

@github-actions
Copy link
Contributor

Thanks @tdavidcl for opening this PR!

You can do multiple things directly here:
1 - Comment pre-commit.ci run to run pre-commit checks.
2 - Comment pre-commit.ci autofix to apply fixes.
3 - Add label autofix.ci to fix authorship & pre-commit for every commit made.
4 - Add label light-ci to only trigger a reduced & faster version of the CI (need the full one before merge).
5 - Add label trigger-ci to create an empty commit to trigger the CI.

Once the workflow completes a message will appear displaying informations related to the run.

Also the PR gets automatically reviewed by gemini, you can:
1 - Comment /gemini review to trigger a review
2 - Comment /gemini summary for a summary
3 - Tag it using @gemini-code-assist either in the PR or in review comments on files

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @tdavidcl, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request focuses on optimizing the process of setting field values within the Ramses model by introducing a bulk assignment mechanism. This change allows Python functions, particularly those optimized with Numba, to compute and apply field values for entire blocks of cells simultaneously, rather than individually. The result is a significant reduction in computation time, enhancing the overall efficiency of the simulation setup.

Highlights

  • Bulk Field Value Setting: Introduced new C++ methods and Python bindings to allow setting field values for multiple cells in a single call, significantly improving performance for large datasets.
  • Numba Integration: Enabled the use of Numba's @njit decorator with the new bulk field setting functions, demonstrating substantial speedups as shown in the provided benchmarks.
  • API Refactoring: Refactored the set_field_value_lambda methods in the C++ Model.hpp to support bulk operations, with a new set_field_value_lambda_all taking vectors of cell coordinates.
  • Python-C++ Interoperability: Added VecToNumpy utility classes and updated pybind11 bindings to seamlessly convert between C++ std::vector and Python numpy.array for efficient data transfer during bulk operations.
  • Example Update: The run_kh.py example was updated to showcase the new bulk setting capabilities, including performance comparisons between different approaches (no Numba, with Numba, bulk, bulk with Numba).
Changelog
  • examples/ramses/run_kh.py
    • Imported njit from numba for JIT compilation.
    • Increased the plot resolution nx and ny from 512 to 1024.
    • Updated the base parameter from 32 to 64.
    • Implemented new rho_map_all, rhovel_map_all, and rhoetot_map_all functions designed for bulk processing of cell data.
    • Demonstrated the usage of the new set_field_value_lambda_f64_all and set_field_value_lambda_f64_3_all methods, both with and without Numba JIT compilation.
    • Added print statements to output performance metrics for different field setting approaches.
  • src/shammodels/ramses/include/shammodels/ramses/Model.hpp
    • Renamed the original set_field_value_lambda to set_field_value_lambda_all and modified its signature to accept std::vector<Tvec> for bulk input.
    • Updated the implementation of set_field_value_lambda_all to process all cell values in a single batch.
    • Reintroduced a new set_field_value_lambda (without _all suffix) as a convenience wrapper that adapts single-cell lambda functions to the new bulk-compatible interface.
  • src/shammodels/ramses/src/pyRamsesModel.cpp
    • Added VecToNumpy template classes to facilitate efficient conversion between C++ std::vector and Python py::array_t for scalar and 3D vector types.
    • Exposed new Python bindings set_field_value_lambda_f64_all and set_field_value_lambda_f64_3_all to allow Python functions to utilize the bulk field setting capabilities.
    • Implemented logic within the new bindings to handle the necessary data type conversions between Python numpy arrays and C++ std::vectors.
Activity
  • The pull request description indicates that the current state is a working concept ('To be cleaned but that's the idea').
  • Performance benchmarks are included in the description, showcasing the speed improvements achieved with Numba and bulk operations for various fields.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request includes changes to the run_kh.py example, such as importing numba, increasing the grid resolution, and modifying physical parameters. It also introduces the use of @njit decorator to accelerate the computation of rho_map, rhovel_map, and rhoetot_map functions. Additionally, the code defines new functions rho_map_all, rhovel_map_all, and rhoetot_map_all to compute the density, velocity, and total energy density, respectively, using all cells. The C++ code in Model.hpp was modified to include a new function set_field_value_lambda_all that takes a lambda function to set field values for all cells. The pyRamsesModel.cpp file was updated to include a utility class VecToNumpy for converting vectors to NumPy arrays, and to expose the set_field_value_lambda_all function to Python. The reviewer noted a critical bug in rhoetot_map_all where the return statement is inside the for loop, causing premature exit and incorrect results, and suggested using NumPy vectorization for performance and bug resolution. The reviewer also suggested replacing the for loop in rho_map_all with np.where for efficiency and readability, and to avoid redundant calculations of rho by calculating it once and passing it as an argument to rhovel_map_all and rhoetot_map_all.

Comment on lines +276 to +294
ncells = in_min_cell.shape[0]
rhoekin = np.zeros(ncells)

for i in range(ncells):
x, y, z = in_min_cell[i]

rhovel2 = (
rhovel[i][0] * rhovel[i][0]
+ rhovel[i][1] * rhovel[i][1]
+ rhovel[i][2] * rhovel[i][2]
)
rhoekin[i] = 0.5 * rhovel2 / rho[i]

if y > y_interface:
P = P_2
else:
P = P_1

return rhoekin + P / (gamma - 1)
Copy link
Contributor

Choose a reason for hiding this comment

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

critical

This function contains a critical bug: the return statement is inside the for loop, which will cause it to exit after the first iteration with partially computed data. This leads to incorrect results.

Additionally, the function can be fully vectorized using NumPy to improve performance and readability, which also resolves the bug. The current implementation also performs redundant calculations by calling rho_map_all and rhovel_map_all.

        y = in_min_cell[:, 1]
        rhovel2 = np.sum(rhovel**2, axis=1)
        rhoekin = 0.5 * rhovel2 / rho

        P = np.where(y > y_interface, P_2, P_1)

        return rhoekin + P / (gamma - 1)

Comment on lines +231 to +237
rho = np.zeros(ncells)
for i in range(ncells):
x, y, z = in_min_cell[i]
if y > y_interface:
rho[i] = rho_2
else:
rho[i] = rho_1
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

The for loop used to populate the rho array can be replaced by a more idiomatic and efficient vectorized NumPy operation. Using np.where will improve both performance and code readability.

        y = in_min_cell[:, 1]
        rho = np.where(y > y_interface, rho_2, rho_1)

return rho

def rhovel_map_all(in_min_cell: np.ndarray, in_max_cell: np.ndarray) -> np.array:
rho = rho_map_all(in_min_cell, in_max_cell)
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

This function recalculates rho by calling rho_map_all, which is inefficient, especially since rhoetot_map_all will also call this function, leading to redundant computations. Consider calculating rho once and passing it as an argument if these functions are to be used together.

Additionally, the loop over ncells can be vectorized using NumPy for significant performance improvements, which aligns with the goal of using numba.

@github-actions
Copy link
Contributor

Workflow report

workflow report corresponding to commit 230b202
Commiter email is timothee.davidcleris@proton.me

Light CI is enabled. This will only run the basic tests and not the full tests.
Merging a PR require the job "on PR / all" to pass which is disabled in this case.

Pre-commit check report

Pre-commit check: ✅

trim trailing whitespace.................................................Passed
fix end of files.........................................................Passed
check for merge conflicts................................................Passed
check that executables have shebangs.....................................Passed
check that scripts with shebangs are executable..........................Passed
check for added large files..............................................Passed
check for case conflicts.................................................Passed
check for broken symlinks................................................Passed
check yaml...............................................................Passed
detect private key.......................................................Passed
No-tabs checker..........................................................Passed
Tabs remover.............................................................Passed
Validate GitHub Workflows................................................Passed
clang-format.............................................................Passed
ruff check...............................................................Passed
ruff format..............................................................Passed
Check doxygen headers....................................................Passed
Check license headers....................................................Passed
Check #pragma once.......................................................Passed
Check SYCL #include......................................................Passed
No ssh in git submodules remote..........................................Passed
No UTF-8 in files (except for authors)...................................Passed

Test pipeline can run.

Doxygen diff with main

Removed warnings : 10
New warnings : 15
Warnings count : 8183 → 8188 (0.1%)

Detailed changes :
- src/shammodels/ramses/include/shammodels/ramses/Model.hpp:107: warning: Member evolve_once_time_expl(f64 t_curr, f64 dt_input) (function) of class shammodels::basegodunov::Model is not documented.
- src/shammodels/ramses/include/shammodels/ramses/Model.hpp:111: warning: Member timestep() (function) of class shammodels::basegodunov::Model is not documented.
- src/shammodels/ramses/include/shammodels/ramses/Model.hpp:113: warning: Member evolve_once() (function) of class shammodels::basegodunov::Model is not documented.
- src/shammodels/ramses/include/shammodels/ramses/Model.hpp:118: warning: Member evolve_until(Tscal target_time, i32 niter_max) (function) of class shammodels::basegodunov::Model is not documented.
- src/shammodels/ramses/include/shammodels/ramses/Model.hpp:126: warning: Member dump(std::string fname) (function) of class shammodels::basegodunov::Model is not documented.
+ src/shammodels/ramses/include/shammodels/ramses/Model.hpp:127: warning: Member set_field_value_lambda(std::string field_name, const std::function< T(Tvec, Tvec)> pos_to_val, const i32 offset) (function) of class shammodels::basegodunov::Model is not documented.
+ src/shammodels/ramses/include/shammodels/ramses/Model.hpp:146: warning: Member get_cell_coords(std::pair< TgridVec, TgridVec > block_coords, u32 lid) (function) of class shammodels::basegodunov::Model is not documented.
+ src/shammodels/ramses/include/shammodels/ramses/Model.hpp:155: warning: Member evolve_once_time_expl(f64 t_curr, f64 dt_input) (function) of class shammodels::basegodunov::Model is not documented.
+ src/shammodels/ramses/include/shammodels/ramses/Model.hpp:159: warning: Member timestep() (function) of class shammodels::basegodunov::Model is not documented.
+ src/shammodels/ramses/include/shammodels/ramses/Model.hpp:161: warning: Member evolve_once() (function) of class shammodels::basegodunov::Model is not documented.
+ src/shammodels/ramses/include/shammodels/ramses/Model.hpp:166: warning: Member evolve_until(Tscal target_time, i32 niter_max) (function) of class shammodels::basegodunov::Model is not documented.
+ src/shammodels/ramses/include/shammodels/ramses/Model.hpp:174: warning: Member dump(std::string fname) (function) of class shammodels::basegodunov::Model is not documented.
- src/shammodels/ramses/include/shammodels/ramses/Model.hpp:56: warning: Member set_field_value_lambda(std::string field_name, const std::function< T(Tvec, Tvec)> pos_to_val, const i32 offset) (function) of class shammodels::basegodunov::Model is not documented.
+ src/shammodels/ramses/include/shammodels/ramses/Model.hpp:56: warning: Member set_field_value_lambda_all(std::string field_name, const std::function< std::vector< T >(const std::vector< Tvec > &, const std::vector< Tvec > &)> pos_to_val, const i32 offset) (function) of class shammodels::basegodunov::Model is not documented.
- src/shammodels/ramses/include/shammodels/ramses/Model.hpp:98: warning: Member get_cell_coords(std::pair< TgridVec, TgridVec > block_coords, u32 lid) (function) of class shammodels::basegodunov::Model is not documented.
- src/shammodels/ramses/src/pyRamsesModel.cpp:339: warning: Member Register_pymod(pybasegodunovmodel) (function) of file pyRamsesModel.cpp is not documented.
+ src/shammodels/ramses/src/pyRamsesModel.cpp:33: warning: Compound VecToNumpy is not documented.
- src/shammodels/ramses/src/pyRamsesModel.cpp:33: warning: Member add_instance(py::module &m, std::string name_config, std::string name_model) (function) of namespace shammodels::basegodunov is not documented.
- src/shammodels/ramses/src/pyRamsesModel.cpp:33: warning: Member add_instance(py::module &m, std::string name_config, std::string name_model) (function) of namespace shammodels::basegodunov is not documented.
+ src/shammodels/ramses/src/pyRamsesModel.cpp:35: warning: Member convert(const std::vector< T > &vec) (function) of class VecToNumpy is not documented.
+ src/shammodels/ramses/src/pyRamsesModel.cpp:438: warning: Member Register_pymod(pybasegodunovmodel) (function) of file pyRamsesModel.cpp is not documented.
+ src/shammodels/ramses/src/pyRamsesModel.cpp:51: warning: Compound VecToNumpy< sycl::vec< T, 3 > > is not documented.
+ src/shammodels/ramses/src/pyRamsesModel.cpp:53: warning: Member convert(const std::vector< sycl::vec< T, 3 > > &vec) (function) of class VecToNumpy< sycl::vec< T, 3 > > is not documented.
+ src/shammodels/ramses/src/pyRamsesModel.cpp:71: warning: Member add_instance(py::module &m, std::string name_config, std::string name_model) (function) of namespace shammodels::basegodunov is not documented.
+ src/shammodels/ramses/src/pyRamsesModel.cpp:71: warning: Member add_instance(py::module &m, std::string name_config, std::string name_model) (function) of namespace shammodels::basegodunov is not documented.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant