Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
a1d7e1c
[SPH] sheared wave setup
tdavidcl Jun 25, 2026
0926e28
Merge branch 'main' into sheared_wave
mergify[bot] Aug 20, 2026
ec91f59
Merge branch 'main' into sheared_wave
mergify[bot] Aug 21, 2026
10e7f6a
Merge branch 'main' into sheared_wave
mergify[bot] Aug 22, 2026
4ab461c
Merge branch 'main' into sheared_wave
mergify[bot] Aug 23, 2026
3972a7d
Merge branch 'main' into sheared_wave
mergify[bot] Aug 24, 2026
10fe744
Merge branch 'main' into sheared_wave
mergify[bot] Aug 25, 2026
a250ce5
Merge branch 'main' into sheared_wave
mergify[bot] Aug 26, 2026
f9be2cc
Merge branch 'main' into sheared_wave
mergify[bot] Aug 27, 2026
fc48ba8
Merge branch 'main' into sheared_wave
mergify[bot] Aug 28, 2026
954e502
Merge branch 'main' into sheared_wave
mergify[bot] Aug 29, 2026
c1723fa
Merge branch 'main' into sheared_wave
mergify[bot] Aug 30, 2026
637e9eb
Merge branch 'main' into sheared_wave
mergify[bot] Aug 31, 2026
7e716c0
Merge branch 'main' into sheared_wave
mergify[bot] Sep 1, 2026
49975bf
Merge branch 'main' into sheared_wave
mergify[bot] Sep 3, 2026
314ea7d
Merge branch 'main' into sheared_wave
mergify[bot] Sep 4, 2026
1f10a4c
Merge branch 'main' into sheared_wave
mergify[bot] Sep 5, 2026
101b1af
Merge branch 'main' into sheared_wave
mergify[bot] Sep 6, 2026
3750a86
Merge branch 'main' into sheared_wave
mergify[bot] Sep 7, 2026
4b0fb79
Merge branch 'main' into sheared_wave
mergify[bot] Sep 9, 2026
eeb0a2e
Merge branch 'main' into sheared_wave
mergify[bot] Sep 10, 2026
64ae50b
Merge branch 'main' into sheared_wave
mergify[bot] Sep 11, 2026
ca416c7
Merge branch 'main' into sheared_wave
mergify[bot] Sep 12, 2026
f4d7b5f
Merge branch 'main' into sheared_wave
mergify[bot] Sep 13, 2026
d696f99
Merge branch 'main' into sheared_wave
mergify[bot] Sep 14, 2026
7ade50d
Merge branch 'main' into sheared_wave
mergify[bot] Sep 15, 2026
6e123d7
Merge branch 'main' into sheared_wave
mergify[bot] Sep 16, 2026
0d8454a
Merge branch 'main' into sheared_wave
mergify[bot] Sep 17, 2026
6cfaef3
Merge branch 'main' into sheared_wave
mergify[bot] Sep 18, 2026
80d312d
Merge branch 'main' into sheared_wave
mergify[bot] Sep 19, 2026
e85982c
Merge branch 'main' into sheared_wave
mergify[bot] Sep 20, 2026
38188b1
Merge branch 'main' into sheared_wave
mergify[bot] Sep 21, 2026
a1c64ab
Merge branch 'main' into sheared_wave
mergify[bot] Sep 22, 2026
7542e32
Merge branch 'main' into sheared_wave
mergify[bot] Sep 23, 2026
de857ee
Merge branch 'main' into sheared_wave
mergify[bot] Sep 24, 2026
94af0da
Merge branch 'main' into sheared_wave
mergify[bot] Sep 25, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
266 changes: 266 additions & 0 deletions examples/sph/run_sph_sheared_wave.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,266 @@
"""
Shearing box in SPH
========================

This simple example shows how to run an unstratified shearing box simulation
"""

# sphinx_gallery_multi_image = "single"

import shamrock
from shamrock.utils.SimulationRunner import SimulationRunner, callback, simulation_setup
import numpy as np

# If we use the shamrock executable to run this script instead of the python interpreter,
# we should not initialize the system as the shamrock executable needs to handle specific MPI logic
if not shamrock.sys.is_initialized():
shamrock.change_loglevel(1)
shamrock.sys.init("0:0")

# %%
# Use shamrock documentation style for matplotlib
shamrock.matplotlib.set_shamrock_mpl_style()


# %%
# Initialize context & attach a SPH model to it
ctx = shamrock.Context()
ctx.pdata_layout_new()

model = shamrock.get_Model_SPH(context=ctx, vector_type="f64_3", sph_kernel="M4")


dump_folder = "_to_trash/sph_sheared_wave"

class Simulation(SimulationRunner):
# Use the global vars defined at the top of the file
t_end = 15.
dump_prefix = dump_folder + "/" + "dump"

# simulation parameters
gamma = 5.0 / 3.0
rho = 1
uint = 1

dr = 0.005
bmin = (-0.5, -0.5, -0.5)
bmax = (0.5, 0.5, 0.5)
pmass = -1

bmin, bmax = shamrock.math.get_ideal_hcp_box(dr, bmin, bmax)
xm, ym, zm = bmin
xM, yM, zM = bmax

Omega_0 = 0
eta = 0.00
q = 3.0 / 2.0

# wave parameters
nx,ny,nz = 0, 1, 4
amplitude = 1e-6

shear_speed = -q * Omega_0 * (xM - xm)

def vel_func(self,r):
x, y, z = r

s = (x - (self.xM + self.xm) / 2) / (self.xM - self.xm)
vel = (self.shear_speed) * s

return (self.amplitude*np.sin(2.0*np.pi*(y+4*z)), vel, 0.0)
Comment on lines +64 to +70

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

The wave phase in vel_func is currently hardcoded as y + 4*z. Since the box boundaries are adjusted by get_ideal_hcp_box (which can slightly modify the box size to fit the HCP lattice), the actual box lengths in $y$ and $z$ may not be exactly $1.0$. This can lead to a wave that is not perfectly periodic, causing discontinuities at the boundaries.

To ensure perfect periodicity, scale the wave phase using the actual box dimensions and the wave parameters self.ny and self.nz.

Suggested change
def vel_func(self,r):
x, y, z = r
s = (x - (self.xM + self.xm) / 2) / (self.xM - self.xm)
vel = (self.shear_speed) * s
return (self.amplitude*np.sin(2.0*np.pi*(y+4*z)), vel, 0.0)
def vel_func(self, r):
x, y, z = r
s = (x - (self.xM + self.xm) / 2) / (self.xM - self.xm)
vel = self.shear_speed * s
phase = self.ny * (y - self.ym) / (self.yM - self.ym) + self.nz * (z - self.zm) / (self.zM - self.zm)
return (self.amplitude * np.sin(2.0 * np.pi * phase), vel, 0.0)


@callback(walltime_interval=30.0) # Checkpoint the simulation every 30 seconds
def checkpoint(self, icheckpoint):
self.do_checkpoint(icheckpoint, purge_old_dumps=True, keep_first=1, keep_last=3)

@callback(tsim_interval=0.02) # Do the analysis every 0.02 time units
def vtk_dump(self, idump):
model.do_vtk_dump(self.dump_prefix + f"dump_{idump:04}.vtk", True)

@simulation_setup
def setup(self):
cfg = model.gen_default_config()
# cfg.set_artif_viscosity_Constant(alpha_u = 1, alpha_AV = 1, beta_AV = 2)
# cfg.set_artif_viscosity_VaryingMM97(alpha_min = 0.1,alpha_max = 1,sigma_decay = 0.1, alpha_u = 1, beta_AV = 2)
cfg.set_artif_viscosity_VaryingCD10(
alpha_min=0.0, alpha_max=1, sigma_decay=0.1, alpha_u=1, beta_AV=2
)
#cfg.set_boundary_shearing_periodic((1, 0, 0), (0, 1, 0), self.shear_speed)
cfg.set_boundary_periodic()
cfg.set_eos_adiabatic(self.gamma)
#cfg.add_ext_force_shearing_box(Omega_0=self.Omega_0, eta=self.eta, q=self.q)
Comment on lines +88 to +91

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

The shearing box boundary conditions and external forces are currently commented out, and standard periodic boundaries are used instead. Since this example is intended to demonstrate a shearing box simulation (as described in the module docstring), these configurations should be enabled. If you want to run a standard periodic wave, consider creating a separate example or parameterizing this script.

cfg.set_units(shamrock.UnitSystem())
cfg.print_status()
model.set_solver_config(cfg)
model.init_scheduler(int(1e7), 1)
model.resize_simulation_box(self.bmin, self.bmax)
model.add_cube_fcc_3d(self.dr, self.bmin, self.bmax)

vol_b = (self.xM - self.xm) * (self.yM - self.ym) * (self.zM - self.zm)
totmass = self.rho * vol_b

pmass = model.total_mass_to_part_mass(totmass)

model.set_value_in_a_box("uint", "f64", 1, self.bmin, self.bmax)

model.set_field_value_lambda_f64_3("vxyz", self.vel_func)
model.set_particle_mass(pmass)

model.set_cfl_cour(0.3)
model.set_cfl_force(0.25)


sim = Simulation(model)
sim.run()

# %%
# Setup parameters



render_gif = True


import os

# Create the dump directory if it does not exist
if shamrock.sys.world_rank() == 0:
os.makedirs(dump_folder, exist_ok=True)

# %%
# Generate the config & init the scheduler
cfg = model.gen_default_config()
# cfg.set_artif_viscosity_Constant(alpha_u = 1, alpha_AV = 1, beta_AV = 2)
# cfg.set_artif_viscosity_VaryingMM97(alpha_min = 0.1,alpha_max = 1,sigma_decay = 0.1, alpha_u = 1, beta_AV = 2)
cfg.set_artif_viscosity_VaryingCD10(
alpha_min=0.0, alpha_max=1, sigma_decay=0.1, alpha_u=1, beta_AV=2
)
cfg.set_boundary_shearing_periodic((1, 0, 0), (0, 1, 0), shear_speed)
cfg.set_eos_adiabatic(gamma)
cfg.add_ext_force_shearing_box(Omega_0=Omega_0, eta=eta, q=q)
cfg.set_units(shamrock.UnitSystem())
cfg.print_status()
model.set_solver_config(cfg)

model.init_scheduler(int(1e7), 1)

model.resize_simulation_box(bmin, bmax)


# %%
# Add the particles & set fields values
# Note that every field that are not mentioned are set to zero
model.add_cube_fcc_3d(dr, bmin, bmax)

vol_b = (xM - xm) * (yM - ym) * (zM - zm)

totmass = rho * vol_b
# print("Total mass :", totmass)

pmass = model.total_mass_to_part_mass(totmass)

model.set_value_in_a_box("uint", "f64", 1, bmin, bmax)
# model.set_value_in_a_box("vxyz","f64_3", (-10,0,0) , bmin,bmax)

pen_sz = 0.1

mm = 1
MM = 0


def vel_func(r):
global mm, MM
x, y, z = r

s = (x - (xM + xm) / 2) / (xM - xm)
vel = (shear_speed) * s

mm = min(mm, vel)
MM = max(MM, vel)

return (0, vel, 0.0)
# return (1,0,0)


model.set_field_value_lambda_f64_3("vxyz", vel_func)
# print("Current part mass :", pmass)
model.set_particle_mass(pmass)


tot_u = pmass * model.get_sum("uint", "f64")
# print("total u :",tot_u)

print(f"v_shear = {shear_speed} | dv = {MM - mm}")


model.set_cfl_cour(0.3)
model.set_cfl_force(0.25)

# %%
# Perform the plot

from math import exp

import matplotlib.pyplot as plt
import numpy as np


def plot(iplot):
dic = ctx.collect_data()
fig, axs = plt.subplots(2, 1, figsize=(5, 8), sharex=True)
fig.suptitle("t = {:.2f}".format(model.get_time()))
axs[0].scatter(dic["xyz"][:, 0], dic["xyz"][:, 1], s=1)
axs[1].scatter(dic["xyz"][:, 0], dic["vxyz"][:, 1], s=1)

axs[0].set_ylabel("y")
axs[1].set_ylabel("vy")
axs[1].set_xlabel("x")

axs[0].set_xlim(xm - 0.1, xM + 0.1)
axs[0].set_ylim(ym - 0.1, yM + 0.1)

axs[1].set_xlim(xm - 0.1, xM + 0.1)
axs[1].set_ylim(shear_speed * 0.7, -shear_speed * 0.7)

plt.tight_layout()
plt.savefig(os.path.join(dump_folder, f"{sim_name}_{iplot:04}.png"))
plt.close(fig)


# %%
# Performing the timestep loop
model.timestep()

dt_stop = 0.02
for i in range(20):
t_target = i * dt_stop
# skip if the model is already past the target
if model.get_time() > t_target:
continue

model.evolve_until(i * dt_stop)

# Dump name is "dump_xxxx.sham" where xxxx is the timestep
model.do_vtk_dump(os.path.join(dump_folder, f"{sim_name}_{i:04}.vtk"), True)
plot(i)

####################################################
# Convert PNG sequence to Image sequence in mpl
####################################################

import matplotlib.animation as animation
from shamrock.utils.plot import show_image_sequence

# If the animation is not returned only a static image will be shown in the doc
glob_str = os.path.join(dump_folder, f"{sim_name}_*.png")
ani = show_image_sequence(glob_str, render_gif=render_gif)

if render_gif and shamrock.sys.world_rank() == 0:
# To save the animation using Pillow as a gif
# writer = animation.PillowWriter(fps=15,
# metadata=dict(artist='Me'),
# bitrate=1800)
# ani.save('scatter.gif', writer=writer)

# Show the animation
plt.show()
Comment on lines +116 to +266

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

high

This entire block of procedural code at the bottom of the file appears to be a redundant/leftover version of the simulation setup. It is completely broken and will raise multiple NameErrors if executed because:

  1. Variables like shear_speed, gamma, Omega_0, eta, q, bmin, bmax, dr, rho, xm, xM, ym, yM, zm, zM are defined as class attributes of Simulation and are not available in the global scope.
  2. sim_name is used but never defined anywhere in the script.

Since the simulation is already successfully configured and run using the Simulation class on lines 35-114, this entire section (lines 116-266) should be removed. If you want to keep the plotting or animation functionality, it should be refactored as a callback method inside the Simulation class.

Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ namespace shammodels::sph {
p.set_shearing_periodic(
j.at("shear_base").get<i32_3>(),
j.at("shear_dir").get<i32_3>(),
j.at("speed").get<Tscal>());
j.at("shear_speed").get<Tscal>());
} else {
shambase::throw_unimplemented("wtf !");
}
Expand Down
Loading