Skip to content

Conversation

@tdavidcl
Copy link
Member

No description provided.

@tdavidcl tdavidcl added the draft label Dec 23, 2025
@github-actions
Copy link

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

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 adds a new example script to the documentation, showcasing a complete workflow for simulating the collapse of a Bonnor-Ebert sphere using the shamrock SPH framework. It covers the analytical derivation of the density profile, the setup of a detailed SPH simulation with relevant physical models, and a robust analysis pipeline for visualizing the simulation's evolution.

Highlights

  • New Example Script: Introduced a new Python script, run_bonnor_ebert.py, which demonstrates the setup and simulation of a Bonnor-Ebert sphere collapse.
  • Bonnor-Ebert Equation Solution: The script includes the numerical solution of the Bonnor-Ebert differential equation using scipy.integrate.odeint to derive the density profile of the sphere.
  • SPH Simulation Setup: Configures a shamrock SPH model with specific physics, including a Machida06 equation of state, FMM self-gravity, CD10 varying artificial viscosity, and a kill sphere boundary condition.
  • Particle Initialization and Remapping: Particles are generated using an HCP lattice, filtered into a spherical region, and their positions are remapped to match the analytically derived Bonnor-Ebert density profile.
  • Comprehensive Analysis and Plotting: The script features an extensive analysis loop that generates various plots, including density slices, column-integrated density, sound speed, radial velocity, and phase-space plots of particle properties, saving them as PNG files.
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.

@github-actions
Copy link

Workflow report

workflow report corresponding to commit 669e0a0
Commiter email is timothee.davidcleris@proton.me

Pre-commit check report

Some failures were detected in base source checks checks.
Check the On PR / Linting / Base source checks (pull_request) job in the tests for more detailled output

❌ ruff-check

�[1m�[91mNPY002 �[0m�[1mReplace legacy `np.random.seed` call with `np.random.Generator`�[0m
   �[1m�[94m-->�[0m doc/sphinx/examples/math/run_bonnor_ebert.py:168:1
    �[1m�[94m|�[0m
�[1m�[94m167 |�[0m # random set of points between 0 and 1
�[1m�[94m168 |�[0m np.random.seed(111)
    �[1m�[94m|�[0m �[1m�[91m^^^^^^^^^^^^^^�[0m
�[1m�[94m169 |�[0m points = np.random.rand(100000)[:]
    �[1m�[94m|�[0m

�[1m�[91mNPY002 �[0m�[1mReplace legacy `np.random.rand` call with `np.random.Generator`�[0m
   �[1m�[94m-->�[0m doc/sphinx/examples/math/run_bonnor_ebert.py:169:10
    �[1m�[94m|�[0m
�[1m�[94m167 |�[0m # random set of points between 0 and 1
�[1m�[94m168 |�[0m np.random.seed(111)
�[1m�[94m169 |�[0m points = np.random.rand(100000)[:]
    �[1m�[94m|�[0m          �[1m�[91m^^^^^^^^^^^^^^�[0m
�[1m�[94m170 |�[0m
�[1m�[94m171 |�[0m range_end = (0, r_[-1])
    �[1m�[94m|�[0m

Found 2 errors.

Suggested changes

Detailed changes :

Copy link

@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 introduces an example script for simulating a Bonnor-Ebert sphere collapse. The script is a valuable addition to the documentation. My review provides feedback to enhance the script's performance, readability, and maintainability. Key suggestions include vectorizing loops using NumPy/SciPy for better performance, refactoring duplicated code into helper functions, improving the structure of the main simulation loop for clarity, and addressing potential issues that could block non-interactive execution.


plt.grid()

plt.show()

Choose a reason for hiding this comment

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

high

The plt.show() call will block script execution until the plot window is manually closed. For a documentation example script that might be run non-interactively, this will cause it to hang. Consider saving the figure to a file instead, or removing this call if the plot is not essential for the script's logic that follows. The later part of the script saves figures, which is a better practice for non-interactive runs.

Suggested change
plt.show()
# plt.show()

plt.title("t = {:0.3f} [year]".format(model.get_time()))

plt.colorbar()
plt.show()

Choose a reason for hiding this comment

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

high

The plt.show() call will block script execution until the plot window is manually closed. For a documentation example script that might be run non-interactively, this will cause it to hang. Consider saving the figure to a file instead, or removing this call if the plot is not essential for the script's logic that follows.

Suggested change
plt.show()
# plt.show()

Comment on lines +44 to +55
rho_c_rho_0 = []
dimless_arr = []
for i in range(len(t)):

dimless_mass = xidudxi[i] * (4 * np.pi * dens[i] ** -1) ** (-1 / 2)
# print("rho_c/rho_0",dens[i]**-1)
# print("xidudxi[-1]",xidudxi[i])
# print("(4*np.pi*dens[-1]**-1)**(1/2)",(4*np.pi*dens[i]**-1)**(-1/2))
# print(xidudxi[i]*(4*np.pi*dens[i]**-1)**(-1/2))

rho_c_rho_0.append(dens[i] ** -1)
dimless_arr.append(dimless_mass)

Choose a reason for hiding this comment

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

medium

This loop can be vectorized using NumPy for improved performance and readability. This avoids manual iteration and is more idiomatic for NumPy arrays.

Suggested change
rho_c_rho_0 = []
dimless_arr = []
for i in range(len(t)):
dimless_mass = xidudxi[i] * (4 * np.pi * dens[i] ** -1) ** (-1 / 2)
# print("rho_c/rho_0",dens[i]**-1)
# print("xidudxi[-1]",xidudxi[i])
# print("(4*np.pi*dens[-1]**-1)**(1/2)",(4*np.pi*dens[i]**-1)**(-1/2))
# print(xidudxi[i]*(4*np.pi*dens[i]**-1)**(-1/2))
rho_c_rho_0.append(dens[i] ** -1)
dimless_arr.append(dimless_mass)
rho_c_rho_0 = dens**-1
dimless_arr = xidudxi * (4 * np.pi * dens**-1) ** (-1 / 2)

Comment on lines +115 to +116
r_ = r_
rho_ = rho_

Choose a reason for hiding this comment

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

medium

These assignments are redundant as they assign variables to themselves. They can be removed to improve code clarity.

Comment on lines +128 to +138
primitive = []
accum = 0
dx = np.diff(r_)
dx = np.concatenate([[dx[0]], dx])
for r_val, rho_val, dx_val in zip(r_, rho_, dx):
r_val = r_val
primitive.append(accum)
# print(r_val, rho_val, accum, dx_val)
accum += rho_val * dx_val

primitive = np.array(primitive)

Choose a reason for hiding this comment

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

medium

The manual calculation of the primitive (cumulative integral) is verbose and can be simplified. Using scipy.integrate.cumulative_trapezoid is more efficient, readable, and less error-prone. The line r_val = r_val is also a no-op and should be removed.

Suggested change
primitive = []
accum = 0
dx = np.diff(r_)
dx = np.concatenate([[dx[0]], dx])
for r_val, rho_val, dx_val in zip(r_, rho_, dx):
r_val = r_val
primitive.append(accum)
# print(r_val, rho_val, accum, dx_val)
accum += rho_val * dx_val
primitive = np.array(primitive)
primitive = scipy.integrate.cumulative_trapezoid(rho_, r_, initial=0)

m_s_codeu = codeu.get("m") * codeu.get("s", power=-1)
kg_m3_codeu = codeu.get("kg") * codeu.get("m", power=-3)

print(f"m_s_codeu: {kg_m3_codeu}")

Choose a reason for hiding this comment

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

medium

There appears to be a copy-paste error in this print statement. The f-string variable name is m_s_codeu, but the value being printed is kg_m3_codeu.

Suggested change
print(f"m_s_codeu: {kg_m3_codeu}")
print(f"m_s_codeu: {m_s_codeu}")

# lattice volume
part_vol_lattice = 0.74 * part_vol

dr = (part_vol_lattice / ((4.0 / 3.0) * 3.1416)) ** (1.0 / 3.0)

Choose a reason for hiding this comment

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

medium

Avoid using magic numbers like 3.1416 for pi. Use np.pi for better precision and code readability.

Suggested change
dr = (part_vol_lattice / ((4.0 / 3.0) * 3.1416)) ** (1.0 / 3.0)
dr = (part_vol_lattice / ((4.0 / 3.0) * np.pi)) ** (1.0 / 3.0)


dpi = 200
plt.figure(num=1, clear=True, dpi=dpi)
import copy

Choose a reason for hiding this comment

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

medium

import copy should be at the top of the file. This import is also repeated multiple times inside the analysis function (e.g., lines 460, 484, 509, 534). Imports should be at the top of the file for clarity and to avoid performance issues from re-importing within a loop. Please move this and other import copy statements to the top of the script.

plt.show()


def analysis(i):

Choose a reason for hiding this comment

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

medium

The analysis function contains a lot of duplicated code for plotting. The blocks for generating plots for arr_rho, arr_rho2, arr_cs, and arr_vxyz are nearly identical. This can be refactored into a helper function to reduce code duplication and improve maintainability. Also, the my_cmap colormap is created from scratch multiple times within the function; it could be created once and reused.

Example refactoring for plotting:

def plot_slice(data, cmap, title, filename, extent, dpi=200):
    plt.figure(num=1, clear=True, dpi=dpi)
    res = plt.imshow(
        data,
        cmap=cmap,
        origin="lower",
        extent=extent,
    )
    plt.xlabel("x")
    plt.ylabel("y")
    plt.title(title)
    plt.colorbar()
    plt.savefig(filename)
    plt.close()

# In analysis function:
# ...
# my_cmap = ... (created once)
# title = f"t = {model.get_time():0.3f} [year]"
# plot_slice(arr_rho, my_cmap, title, f"collapse/rho_slice_{i:04}.png", [-ext, ext, -ext, ext])
# ...

Comment on lines +646 to +661
i = 0
t = 0

steps = 10
while True:
rho_max = analysis(i)

for j in range(steps):
model.timestep()

i += 1
t += 2.0e-3

if i > 1:
analysis(i)
break

Choose a reason for hiding this comment

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

medium

The main simulation loop is confusing and contains an unused variable.

  • The while True loop with an if i > 1: break condition is hard to follow. A for loop would be more explicit about the number of iterations.
  • The variable t is initialized and incremented in the loop but never used. It should be removed.

Consider refactoring the loop for clarity.

Suggested change
i = 0
t = 0
steps = 10
while True:
rho_max = analysis(i)
for j in range(steps):
model.timestep()
i += 1
t += 2.0e-3
if i > 1:
analysis(i)
break
steps = 10
num_analysis_steps = 3
for i in range(num_analysis_steps):
rho_max = analysis(i)
if i < num_analysis_steps - 1:
for _ in range(steps):
model.timestep()

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