
SPEGEO: Structure-Preserving Algorithms and Geometric Numerical Integration school
Max Planck Institute for Plasma Physics, Garching, Germany
June 22-26, 2026 · Strasbourg
Part I: Theory - From Lagrangian to Eulerian coordinates via Euler-Poincaré reduction
Part II: Discretization - Particle methods for fluid Lagrangians
Part III: Software - Solving meshfree discretizations with Struphy
\[ \frac{\mathrm d}{\mathrm dt} \frac{\partial L}{\partial \dot{\mathbf x}} - \frac{\partial L}{\partial \mathbf x} = 0\quad \Leftrightarrow \quad m \ddot{\mathbf x} = -\frac{\partial V}{\partial \mathbf x} \]
\[ \mathcal A(\mathbf u, \rho, s) = \int_0^T \int \rho \left( \frac{|\mathbf u|^2}{2} - \mathcal U(\rho, s) - V/m \right) d\mathbf x\, dt\,,\qquad \delta \mathcal A = ? \]
\[ \frac{\mathrm d^2}{\mathrm dt^2} \Phi_t(\mathbf x_0) = -\frac 1m \nabla V(\Phi_t(\mathbf x_0))\,,\qquad \Phi_0(\mathbf x_0) = \mathbf x_0 \quad \Leftrightarrow \quad \left\{ \begin{aligned} &\frac{\partial}{\partial t} \rho + \nabla \cdot (\rho \mathbf u) = 0 \\ &\frac{\partial}{\partial t} \mathbf u + (\mathbf u \cdot \nabla) \mathbf u = - \frac{1}{\rho}\nabla V \end{aligned} \right. \]
\[ \mathbf u(t, \mathbf x) := \dot \Phi_t \circ \Phi_t^{-1}(\mathbf x) \]
\[ \delta \mathbf u = \dot{\boldsymbol \eta} + \mathbf u \cdot \nabla \boldsymbol \eta - \boldsymbol \eta \cdot \nabla \mathbf u \]
\[ \mathcal A_\textrm{Lagrange}(\Phi_t, \dot{\Phi}_t) \Leftrightarrow \mathcal A_{Euler}(\mathbf u, \rho, s) \]
\[ \rho:\quad \mathbf x \in \Omega \mapsto \rho(\mathbf x) \in \mathbb R,\qquad\quad \rho^\textrm{vol}:\quad \Omega \subset_\textrm{open} \mathbb R^3 \mapsto \int_\Omega \rho^{\textrm{vol}}(\mathbf x) \,\mathrm d \mathbf x \in \mathbb R \]
\[ \rho^\textrm{vol}(t, \mathbf x) \approx \rho_h^\textrm{vol}(t, \mathbf x) = \sum_{i=1}^N w_i \, \delta(\mathbf x - \mathbf x_i(t)) \quad \Rightarrow \quad \mathcal A(\mathbf u, \rho, s) \approx \mathcal A_h(\mathbf x_1, \ldots, \mathbf x_N, \dot{\mathbf x}_1, \ldots, \dot{\mathbf x}_N) \]
\[ A(\mathbf x) = \int A(\mathbf y) \delta(\mathbf x - \mathbf y) \, d\mathbf y \approx \int A(\mathbf y) W(\mathbf x - \mathbf y, h) \, d\mathbf y \approx \sum_{i=1}^N w_i A(\mathbf x_i) W(\mathbf x - \mathbf x_i, h) \]
These slides will be persistent at:

Try installing Struphy according to the instructions in the README before the hands-on session.
We seek the trajectory \(\mathbf x(t)\,\,\) of a particle moving in a potential \(V\),
\[ \mathbf x:[t_0,t_1] \to \mathbb R^3, \qquad V = V(\mathbf x)\,, \]
with initial conditions
\[ \mathbf x(0)=\mathbf x_0, \qquad \dot{\mathbf x}(0)=\mathbf v_0\,. \]
Newtonian dynamics starts from forces (\(F = -\partial V/\partial \mathbf x\quad\,\,\,\)),
\[ m\,\ddot{\mathbf x} = -\frac{\partial V}{\partial \mathbf x} \]
whereas the variational approach starts from an action \(\mathcal A[\mathbf x]\,\,\,\),
\[ \mathcal A[\mathbf x] = \int_{t_0}^{t_1} \left( \frac{m}{2}|\dot{\mathbf x}|^2 - V\right)\,\mathrm dt,\qquad \delta \mathcal A = 0, \qquad \Rightarrow \quad \frac{\mathrm d}{\mathrm dt}\frac{\partial L}{\partial \dot{\mathbf x}} - \frac{\partial L}{\partial \mathbf x} = 0 \]
\[ \mathcal A[\mathbf x] = \int_{t_0}^{t_1} L(\mathbf x,\dot{\mathbf x},t)\,\mathrm dt, \]
Consider a family of perturbed trajectories
\[ \mathbf x_\varepsilon(t) = \mathbf x(t) + \varepsilon\,\delta \mathbf x(t), \qquad \delta \mathbf x(t_0)=\delta \mathbf x(t_1)=\mathbf 0. \]

The first variation in direction \(\delta \mathbf x\) is defined by
\[ \delta \mathcal A[\mathbf x;\delta \mathbf x] := \lim_{\varepsilon\to 0}\frac{\mathcal A[\mathbf x_\varepsilon] - \mathcal A[\mathbf x]}{\varepsilon}\,, \]
The variation can be written as a directional derivative in the space of trajectories:
\[ \delta \mathcal A[\mathbf x;\delta \mathbf x] := \left.\frac{\mathrm d}{\mathrm d\varepsilon}\mathcal A[\mathbf x_\varepsilon]\right|_{\varepsilon=0}. \]
\[ \begin{aligned} \delta \mathcal A[\mathbf x;\delta \mathbf x] &= \left.\frac{\mathrm d}{\mathrm d\varepsilon}\int_{t_0}^{t_1} L \left(\mathbf x_\varepsilon,\frac{\mathrm d \mathbf x_\varepsilon}{\mathrm d t},t \right)\,\mathrm dt\right|_{\varepsilon=0} \\[1mm] &=\left.\int_{t_0}^{t_1} \left(\frac{\partial L}{\partial \mathbf x}\cdot \frac{\mathrm d}{\mathrm d\varepsilon}\mathbf x_\varepsilon + \frac{\partial L}{\partial \dot{\mathbf x}}\cdot \frac{\mathrm d}{\mathrm d\varepsilon}\frac{\mathrm d \mathbf x_\varepsilon}{\mathrm d t}\right)\,\mathrm dt\right|_{\varepsilon=0} \\[1mm] &=\int_{t_0}^{t_1} \left(\frac{\partial L}{\partial \mathbf x}\cdot \delta \mathbf{x} + \frac{\partial L}{\partial \dot{\mathbf x}}\cdot \frac{\mathrm d \delta \mathbf x}{\mathrm dt}\right)\,\mathrm dt \\[1mm] &=\int_{t_0}^{t_1} \left(\frac{\partial L}{\partial \mathbf x} - \frac{\mathrm d}{\mathrm dt}\frac{\partial L}{\partial \dot{\mathbf x}}\right) \cdot \delta \mathbf{x}\,\mathrm dt + \left.\frac{\partial L}{\partial \dot{\mathbf x}}\cdot \delta \mathbf x\right|_{t_0}^{t_1} \end{aligned} \]
Hamilton’s principle states that critical trajectories satisfy
\[ \delta \mathcal A[\mathbf x;\delta \mathbf x] = 0 \quad\text{for all admissible }\delta \mathbf x. \]
\[ \mathcal A[\mathbf x] = \int_{t_0}^{t_1} L(\mathbf x,\dot{\mathbf x},t)\,\mathrm dt \]
\[ \delta \int_{t_0}^{t_1} \big(L(\mathbf x,\dot{\mathbf x},t) + \lambda(t)\,g(\mathbf x,t)\big)\,\mathrm dt = 0 \]
\[ \textrm{symmetry of }\mathcal A\quad\Longleftrightarrow\quad\text{conserved quantity} \]
For \(L = L(t,\mathbf x,\dot{\mathbf x})\quad\,\), one obtains the identity
\[ \begin{aligned} \frac{\mathrm d}{\mathrm dt}\left(\dot{\mathbf x} \cdot \frac{\partial L}{\partial \dot{\mathbf x}} - L\right) &= \ddot{\mathbf x} \cdot \frac{\partial L}{\partial \dot{\mathbf x}} + \dot{\mathbf x} \cdot \frac{\mathrm d}{\mathrm dt} \frac{\partial L}{\partial \dot{\mathbf x}} - \dot{\mathbf x} \cdot \frac{\partial L}{\partial \mathbf x} - \ddot{\mathbf x} \cdot \frac{\partial L}{\partial \dot{\mathbf x}} - \frac{\partial L}{\partial t} \\ &= -\frac{\partial L}{\partial t} \end{aligned} \]
Therefore, if there is no explicit time dependence,
\[ \frac{\partial L}{\partial t}=0 \qquad\Longrightarrow\qquad E := \dot{\mathbf x} \cdot \frac{\partial L}{\partial \dot{\mathbf x}} - L, \quad \frac{\mathrm dE}{\mathrm dt}=0 \]
If a coordinate is cyclic, one gets momentum conservation:
\[ \frac{\partial L}{\partial \mathbf x}=0 \qquad\Longrightarrow\qquad \frac{\mathrm d}{\mathrm dt}\left(\frac{\partial L}{\partial \dot{\mathbf x}}\right)=0\,,\qquad p := \frac{\partial L}{\partial \dot{\mathbf x}}, \quad \frac{\mathrm dp}{\mathrm dt}=0 \]
Consider a particle of mass \(m\,\) in a central potential \(V(r)\,\,\) in polar coordinates \((r,\varphi)\,\,\,\).
\[ |\dot{\mathbf x}|^2 = \dot r^2 + r^2\dot\varphi^2 \qquad\Longrightarrow\qquad L(r,\varphi,\dot r,\dot\varphi) = \frac{m}{2}\!\left(\dot r^2 + r^2\dot\varphi^2\right) - V(r) \]
Energy conservation — \(L\) has no explicit time dependence (\(\partial L/\partial t = 0\quad\)):
\[ E = \dot r\,\frac{\partial L}{\partial \dot r} + \dot\varphi\,\frac{\partial L}{\partial \dot\varphi} - L = \frac{m}{2}\!\left(\dot r^2 + r^2\dot\varphi^2\right) + V(r), \qquad \frac{\mathrm dE}{\mathrm dt} = 0 \]
Angular-momentum conservation — \(\varphi\) is cyclic (\(\partial L/\partial \varphi = 0\quad\)):
\[ \frac{\partial L}{\partial \varphi} = 0 \qquad\Longrightarrow\qquad \ell = \frac{\partial L}{\partial \dot\varphi} = m r^2\dot\varphi, \qquad \frac{\mathrm d\ell}{\mathrm dt} = 0 \]
Two symmetries of \(\mathcal A\,\,\) yield two conserved quantities — without solving any equation of motion!
For a field \(u(t,\mathbf x)\,\,\,\) on spacetime \([t_0,t_1]\times\Omega\quad\), consider the action
\[ \mathcal A[u] = \int_{t_0}^{t_1}\int_\Omega \mathcal L\big(u,\partial_t u,\nabla u,t,\mathbf x\big)\,\mathrm d\mathbf x\,\mathrm dt. \]
An admissible variation is a perturbation
\[ u_\varepsilon(t,\mathbf x) = u(t,\mathbf x) + \varepsilon\,\eta(t,\mathbf x), \qquad \eta = 0 \text{ on the spacetime boundary.} \]
The first variation is defined by
\[ \delta \mathcal A[u;\eta] := \left.\frac{\mathrm d}{\mathrm d\varepsilon}\mathcal A[u_\varepsilon]\right|_{\varepsilon=0}. \]
Computing the derivative gives
\[ \delta \mathcal A[u;\eta] = \int_{t_0}^{t_1}\int_\Omega \left( \frac{\partial \mathcal L}{\partial u}\,\eta + \frac{\partial \mathcal L}{\partial (\partial_t u)}\,\partial_t \eta + \frac{\partial \mathcal L}{\partial (\nabla u)}\cdot\nabla \eta \right)\,\mathrm d\mathbf x\,\mathrm dt. \]
After integration by parts in time and space,
\[ \delta \mathcal A[u;\eta] = \int_{t_0}^{t_1}\int_\Omega \left( \frac{\partial \mathcal L}{\partial u} - \partial_t\frac{\partial \mathcal L}{\partial (\partial_t u)} - \nabla\cdot\frac{\partial \mathcal L}{\partial (\nabla u)} \right)\eta\,\mathrm d\mathbf x\,\mathrm dt. \]
Thus stationarity for all admissible \(\eta\,\) yields the field Euler-Lagrange equation
\[ \frac{\partial \mathcal L}{\partial u} - \partial_t\frac{\partial \mathcal L}{\partial (\partial_t u)} - \nabla\cdot\frac{\partial \mathcal L}{\partial (\nabla u)} = 0. \]
Let \(\phi(\mathbf x)\,\,\) be a scalar field on \(\Omega\,\) and consider
\[ \mathcal A[\phi] = \int_\Omega \left( \frac{|\nabla \phi|^2}{2} - \rho\,\phi\right)\,\mathrm d\mathbf x. \]
Take variations
\[ \phi_\varepsilon = \phi + \varepsilon\,\eta, \qquad \eta|_{\partial\Omega}=0. \]
Then
\[ \delta \mathcal A[\phi;\eta] = \left.\frac{\mathrm d}{\mathrm d\varepsilon}\mathcal A[\phi_\varepsilon]\right|_{\varepsilon=0} = \int_\Omega \left(\nabla\phi\cdot\nabla\eta - \rho\,\eta\right)\,\mathrm d\mathbf x. \]
Integrating by parts and using \(\eta|_{\partial\Omega}=0\),
\[ \int_\Omega \nabla\phi\cdot\nabla\eta\,\mathrm d\mathbf x = -\int_\Omega \Delta\phi\,\eta\,\mathrm d\mathbf x. \]
Therefore
\[ \delta \mathcal A[\phi;\eta] = \int_\Omega \left(-\,\Delta\phi - \rho\right)\eta\,\mathrm d\mathbf x. \]
Stationarity for all \(\eta\) gives
\[ -\,\Delta\phi - \rho = 0 \qquad\Longleftrightarrow\qquad -\Delta\phi = \rho. \]
Let \(\mathbf u(t,\mathbf x)\quad\) be the fluid velocity field at any given time \(t\) at position \(\mathbf x\).
Lagrangian description (particle-following):
Track each fluid parcel labeled by its initial position \(\mathbf x_0\).
\[ \begin{aligned} \frac{\mathrm d}{\mathrm dt}\Phi_t(\mathbf x_0) &= \mathbf u\big(t,\Phi_t(\mathbf x_0)\big), \qquad \Phi_0(\mathbf x_0)=\mathbf x_0. \\[1mm] \frac{\mathrm d^2}{\mathrm dt^2}\Phi_t(\mathbf x_0) &= \frac 1m \mathbf F\big(t,\Phi_t(\mathbf x_0)\big) \end{aligned} \]
\(\Phi_t(\mathbf x_0)\,\,\,\) is the position at time \(t\) of the fluid parcel that started at \(\mathbf x_0\) at time \(0\).
\(\mathbf F(t, \mathbf x)\,\,\,\) is the force acting on the fluid parcel at position \(\mathbf x\) at time \(t\).
For each \(t \in [t_0,t_1]\quad\), the mapping \(\Phi_t:\Omega \to \Omega\quad\) is a diffeomorphism. \(\Phi_t\,\) is called the flow map and encodes the full fluid motion.
Eulerian description (field-at-fixed-point):
Observe the mass density \(\rho(t,\mathbf x)\,\,\,\) at fixed spatial location \(\mathbf x\,\). For compressible flow, this yields
\[ \begin{aligned} \partial_t\rho + \nabla\cdot(\rho\mathbf u) &= 0, \\[2mm] \partial_t\mathbf u + (\mathbf u\cdot\nabla)\mathbf u &= \frac{1}{\rho} \mathbf F(t,\mathbf x). \end{aligned} \]
Bridge between both views: The Lagrangian parcel acceleration equals the Eulerian material derivative:
\[ \frac{\mathrm d}{\mathrm dt}\mathbf u\big(t,\Phi(t,\mathbf x_0)\big) = \big(\partial_t + \mathbf u\cdot\nabla\big)\mathbf u. \]

Lagrangian viewpoint
Eulerian viewpoint
Suppose we have a Lagrangian description of fluid motion in terms of the flow map \(\Phi_t(\mathbf x_0)\,\,\,\) for all \(\mathbf x_0 \in \Omega \subset \mathbb R^3:\)
\[ \begin{aligned} \frac{\mathrm d}{\mathrm dt}\Phi_t(\mathbf x_0) &= \mathbf u\big(t,\Phi_t(\mathbf x_0)\big), \qquad \Phi_0(\mathbf x_0)=\mathbf x_0. \\[1mm] \frac{\mathrm d^2}{\mathrm dt^2}\Phi_t(\mathbf x_0) &= - \frac 1m \nabla V\big(\Phi_t(\mathbf x_0)\big) \end{aligned} \]
From what we have learned so far it is easy to write down a variational principle for this Lagrangian description for a fixed initial position \(\mathbf x_0:\)
\[ \mathcal A_\textrm{Lagrange}(\Phi_t, \dot{\Phi}_t) = \int_0^T \left( m\frac{|\dot{\Phi}_t(\mathbf x_0)|^2}{2} - V\big(\Phi_t(\mathbf x_0)\big) \right) \,\mathrm dt. \]
Can we write down an equivalent variational principle for the Eulerian description?
A volume form assigns to any open subset \(\Omega \subset \mathbb R^3\quad\) a real number:
\[ \rho^\textrm{vol}:\quad \Omega \subset_\textrm{open} \mathbb R^3 \mapsto \int_\Omega \rho^\textrm{vol}(\mathbf x)\,\textrm d \mathbf x \in \mathbb R. \]
A density (transported by the flow) is a time-dependent volume form that is invariant under the flow \(\Phi_t:\)
\[ \int_{\Phi_t(\Omega_0)} \rho^\textrm{vol}(t, \mathbf x)\,\textrm d \mathbf x = \int_{\Omega_0} \rho^\textrm{vol}(0, \mathbf x_0)\,\textrm d \mathbf x_0\qquad \forall \,\Omega_0. \]

\[ \frac{\partial \rho^\textrm{vol}}{\partial t} + \nabla \cdot (\rho^\textrm{vol} \mathbf u) = 0. \]
where \(\mathbf u(t, \mathbf x):= \dot{\Phi}_t \circ \Phi_t^{-1}(\mathbf x)\qquad\,\) is the Eulerian velocity field, which follows from \(\mathbf x = \Phi_t(\mathbf x_0).\)
\[ \frac{\mathrm d}{\mathrm dt} \Big[ \rho^\textrm{vol}(\Phi_t) \,\big| \textrm{det} D\Phi_t\big| \Big] = 0. \]
\[ \delta \rho^\textrm{vol} = -\nabla \cdot (\rho^\textrm{vol} \boldsymbol\eta). \]
for arbitrary vector field \(\boldsymbol\eta(t, \mathbf x):= \delta \Phi_t \circ \Phi_t^{-1}(\mathbf x).\)
Assume an initial mass density \(\rho^\textrm{vol}(0, \mathbf x_0)\quad\) and consider the modified Lagrange action
\[ \mathcal A_\textrm{Lagrange}(\Phi_t, \dot{\Phi}_t) = \int_0^T \int_{\Omega_0} \left( \frac{|\dot{\Phi}_t(\mathbf x_0)|^2}{2} - \frac 1m V\big(\Phi_t(\mathbf x_0)\big) \right) \rho^\textrm{vol}(0, \mathbf x_0) \, \textrm d \mathbf x_0\,\mathrm dt. \]
Using the change of variables \(\mathbf x = \Phi_t(\mathbf x_0)\quad\), as well as the dynamics given by
\(\dot{\Phi}_t(\mathbf x_0) = \mathbf u(t, \Phi_t(\mathbf x_0))\qquad\,\,\,\), we get
\[ \mathcal A_\textrm{Euler}(\mathbf u, \ldots) = \int_0^T \int_{\Omega} \left( \frac{|\mathbf u(t, \mathbf x)|^2}{2} - \frac 1m V(\mathbf x) \right) \frac{\rho^\textrm{vol}(0, \Phi_t^{-1}(\mathbf x))}{ \big| \textrm{det} D\Phi_t(\Phi_t^{-1}(\mathbf x)) \big|} \, \textrm d \mathbf x\,\mathrm dt \]
We can now use 2. from the previous slide, namely
\[ \rho^\textrm{vol}(t, \Phi_t(\mathbf x_0)) = \frac{\rho^{\textrm{vol}}(0, \mathbf x_0)}{\big| \textrm{det} D\Phi_t(\mathbf x_0) \big|} \]
\[ \mathcal A_\textrm{Euler}(\mathbf u, \rho^\textrm{vol}) = \int_0^T \int_{\Omega} \left( \frac{|\mathbf u(t, \mathbf x)|^2}{2} - \frac 1m V(\mathbf x) \right) \rho^\textrm{vol}(t, \mathbf x) \, \textrm d \mathbf x\,\mathrm dt \]
The unknown flow map \(\Phi_t\,\) has thus been replaced by the two unknown fields \(\mathbf u(t, \mathbf x)\,\,\,\) and \(\rho^\textrm{vol}(t, \mathbf x)\quad\). These fields have to be determined by variation of the new action.
We already know the variations of the density \(\rho^\textrm{vol}\,\,\) from 3. in the previous slide:
\[ \delta \rho^\textrm{vol} = -\nabla \cdot (\rho^\textrm{vol} \boldsymbol\eta). \]
for arbitrary vector field \(\boldsymbol\eta(t, \mathbf x):= \delta \Phi_t \circ \Phi_t^{-1}(\mathbf x).\qquad\) We can compute the variations of the velocity field from
\[ \mathbf u(t, \mathbf x) := \dot{\Phi}_t \circ \Phi_t^{-1}(\mathbf x) \]
to obtain (after some algebra)
\[ \delta \mathbf u = \partial_t \boldsymbol\eta + \mathbf u \cdot \nabla \boldsymbol\eta - \boldsymbol\eta \cdot \nabla \mathbf u. \]
The Euler action:
\[ \mathcal A_\textrm{Euler}(\mathbf u, \rho^\textrm{vol}) = \int_0^T \int_{\Omega} \left( \frac{|\mathbf u(t, \mathbf x)|^2}{2} - \frac 1m V(\mathbf x) \right) \rho^\textrm{vol}(t, \mathbf x) \, \textrm d \mathbf x\,\mathrm dt \]
The constrained variations:
\[ \begin{aligned} \delta \mathbf u &= \partial_t \boldsymbol\eta + \mathbf u \cdot \nabla \boldsymbol\eta - \boldsymbol\eta \cdot \nabla \mathbf u, \\[2mm] \delta \rho^\textrm{vol} &= -\nabla \cdot (\rho^\textrm{vol} \boldsymbol\eta). \end{aligned} \]
The computation:
\[ \delta \mathcal A_\textrm{Euler} = \underbrace{\int_0^T \int_{\Omega} \mathbf u \cdot \delta \mathbf u \, \rho^\textrm{vol} \, \textrm d \mathbf x\,\mathrm dt}_{\text{①}} + \underbrace{\int_0^T \int_{\Omega} \left( \frac{|\mathbf u|^2}{2} - \frac 1m V \right) \delta \rho^\textrm{vol} \, \textrm d \mathbf x\,\mathrm dt}_{\text{②}} \]
First integral:
\[ \begin{aligned} \text{①} = \int_0^T \int_{\Omega} \mathbf u \cdot \delta \mathbf u \, \rho^\textrm{vol} \, \textrm d \mathbf x\,\mathrm dt &= \int_0^T \int_{\Omega} \mathbf u \cdot \left( \partial_t \boldsymbol\eta + \mathbf u \cdot \nabla \boldsymbol\eta - \boldsymbol\eta \cdot \nabla \mathbf u \right) \rho^\textrm{vol} \, \textrm d \mathbf x\,\mathrm dt \\[2mm] &= \int_0^T \int_{\Omega} \left[ - \frac{\partial}{\partial t}(\rho^\textrm{vol} \mathbf u) - \nabla \cdot (\rho^\textrm{vol} \mathbf u \mathbf u^\top) - \rho^\textrm{vol} \nabla \frac{|\mathbf u|^2}{2} \right] \cdot \boldsymbol \eta \, \textrm d \mathbf x\,\mathrm dt \end{aligned} \]
Second integral:
\[ \begin{aligned} \text{②} = \int_0^T \int_{\Omega} \left( \frac{|\mathbf u|^2}{2} - \frac 1m V \right) \delta \rho^\textrm{vol} \, \textrm d \mathbf x\,\mathrm dt &= - \int_0^T \int_{\Omega} \left( \frac{|\mathbf u|^2}{2} - \frac 1m V \right) \nabla \cdot (\rho^\textrm{vol} \boldsymbol\eta) \, \textrm d \mathbf x\,\mathrm dt \\[2mm] &= \int_0^T \int_{\Omega} \left[ \rho^\textrm{vol} \nabla \left( \frac{|\mathbf u|^2}{2} - \frac 1m V \right) \right] \cdot \boldsymbol\eta \, \textrm d \mathbf x\,\mathrm dt \end{aligned} \]
Hamilton’s principle \(\text{①} + \text{②} = 0\quad\) for arbitrary \(\boldsymbol\eta\,\) yields Euler’s equation for the fluid velocity field:
\[ \frac{\partial}{\partial t}(\rho^\textrm{vol} \mathbf u) + \nabla \cdot (\rho^\textrm{vol} \mathbf u \mathbf u^\top) = - \frac{\rho^\textrm{vol}}{m} \nabla V. \]
The mass conservation law is given by our assumption that \(\rho^\textrm{vol}\,\) is a density transported by the flow:
\[ \frac{\partial \rho^\textrm{vol}}{\partial t} + \nabla \cdot (\rho^\textrm{vol} \mathbf u) = 0. \]
A density \(\rho^\textrm{vol}\,\,\,\) satisfies
\[ \int_{\Phi_t(\Omega_0)} \rho^\textrm{vol}(t, \mathbf x)\,\textrm d \mathbf x = \int_{\Omega_0} \rho^\textrm{vol}(0, \mathbf x_0)\,\textrm d \mathbf x_0\qquad \forall \,\Omega_0. \]
Divide the initial domain \(\Omega_0\,\) into small subregions such that \(\bigcup_i \Omega_0^i = \Omega_0:\)

Define the weights \(w_i \in \mathbb R\quad\) for each subregion \(\Omega_0^i\,\) by
\[ w_i := \int_{\Omega_0^i} \rho^\textrm{vol}(0, \mathbf x_0)\,\textrm d \mathbf x_0 \]
such that
\[ \sum_i w_i = \int_{\Omega_0} \rho^\textrm{vol}(0, \mathbf x_0)\,\textrm d \mathbf x_0 \]
Now let \(\mathbf x_0^i \in \Omega_0^i\quad\), then
\[ \mathbf x^i(t) = \Phi_t(\mathbf x_0^i) \quad \in \Phi_t(\Omega_0^i) \qquad \forall t \in [0, T]. \]
Particle approximation: We can approximate the density \(\rho^\textrm{vol}(t, \mathbf x)\quad\) at time \(t\) by a sum of weighted delta distributions centered at the particle locations \(\mathbf x^i(t):\)
\[ \rho^\textrm{vol}(t, \mathbf x) \approx \rho_N(t, \mathbf x) := \sum_{i=1}^N w_i\, \delta(\mathbf x - \mathbf x^i(t)). \]
The discrete \(\rho_N\,\) is still a density (!) since
\[ \int_{\Phi_t(\Omega_0)} \rho_N(t, \mathbf x)\,\textrm d \mathbf x = \sum_{i=1}^N w_i = \int_{\Omega_0} \rho^\textrm{vol}(0, \mathbf x_0)\,\textrm d \mathbf x_0. \]
The particles are advected by the flow,
\[ \mathbf x^i(t) = \Phi_t(\mathbf x_0^i),\quad \Longleftrightarrow \quad \dot{\mathbf x}^i(t) = \mathbf u(t, \mathbf x^i(t))\quad \mathbf x^i(0) = \mathbf x_0^i. \]
The weights \(w_i\,\) are constant in time, since they are defined by the initial density \(\rho^\textrm{vol}(0, \mathbf x_0)\quad\) and the partition of the initial domain \(\Omega_0\,\) into subregions \(\Omega_0^i.\)
The equation for the acceleration of the particels can be derived from a variational principle.
Suppose we aim to compute the integral
\[ I = \int_\Omega A(\mathbf x)\,\rho^\textrm{vol}(\mathbf x)\,\textrm d \mathbf x. \]
for some function (or \(0\,\)-form) \(A(\mathbf x)\,\,\). Further, suppose \(s^\textrm{vol}\,\) denotes a probability density supported on \(\Omega\,\) such that
\[ s^\textrm{vol}(\mathbf x) > 0\quad\forall\mathbf x \in \Omega,\qquad \int_\Omega s^\textrm{vol}(\mathbf x)\,\textrm d \mathbf x = 1. \]
Then we can rewrite the integral \(I\,\) as an expectation value \(\mathbb E\,\) with respect to \(s^\textrm{vol}\,:\)
\[ I = \int_\Omega A(\mathbf x)\frac{\rho^\textrm{vol}(\mathbf x)}{s^\textrm{vol}(\mathbf x)} s^\textrm{vol}(\mathbf x)\,\textrm d \mathbf x = \mathbb E\left[ A\frac{\rho^\textrm{vol}}{s^\textrm{vol}} \right]_{s^\textrm{vol}} \]
Monte Carlo approximation. Draw \(N\,\) independent samples \(\mathbf x_i \sim s^\textrm{vol}\quad\) and approximate
\[ I \approx I_N := \frac{1}{N}\sum_{i=1}^N A(\mathbf x_i)\frac{\rho^\textrm{vol}(\mathbf x_i)}{s^\textrm{vol}(\mathbf x_i)} = \frac 1N \sum_{i=1}^N w_i A(\mathbf x_i). \]
with weights
\[ w_i = \frac{\rho^\textrm{vol}(\mathbf x_i)}{s^\textrm{vol}(\mathbf x_i)}. \]
The sample mean \(I_N\,\) can be viewed as a random variable itself, when viewing the samples \(\mathbf x_i\,\) as random variables distributed according to \(s^\textrm{vol}\,\). It is an unbiased estimator of the true mean value (which is our integral):
\[ \mathbb E[I_N] = \mathbb E\left[ \frac 1N \sum_{i=1}^N w_i A(\mathbf x_i) \right] = \frac 1N \sum_{i=1}^N \mathbb E\left[w_i A(\mathbf x_i) \right] = \frac{NI}{N} = I. \]
The variance of \(I_N\,\) is given by
\[ \mathbb V[I_N] = \mathbb E\!\left[(I_N - \mathbb E[I_N])^2\right] = \mathbb E\!\left[(I_N - I)^2\right] \]
and is a good measure for the error. Using Bienaymé’s identity for independent random variables \(X_i,\)
\[ \mathbb V\!\left[\sum_{i=1}^N X_i\right] = \sum_{i=1}^N \mathbb V[X_i], \]
We can estimate the rate of convergence of the Monte Carlo approximation:
\[ \begin{aligned} \mathbb V[I_N] &= \mathbb V\left[ \frac 1N \sum_{i=1}^N w_i A(\mathbf x_i) \right] \\[2mm] &= \frac{1}{N^2} \mathbb V\left[ \sum_{i=1}^N w_i A(\mathbf x_i) \right] \\[2mm] &= \frac{1}{N^2} \left[ \sum_{i=1}^N \mathbb V[w_i A(\mathbf x_i)] \right] = \frac{N \sigma^2}{N^2} = \frac{\sigma^2}{N}. \end{aligned} \]
where \(\sigma\,\) is the standard deviation of the random variable \(w_i A(\mathbf x_i)\quad\).
Hence the root-mean-square error decays as
\[ \boxed{\varepsilon_N := \sqrt{\mathbb E\!\left[(I_N - I)^2\right]} = \frac{\sigma}{\sqrt{N}}} \]
independent of the spatial dimension \(d\) — this is the key advantage of Monte Carlo over quadrature rules, which converge as \(N^{-k/d}\,\,\,\) for smooth \(k\,\)-th order rules.
In the Monte-Carlo approximation, the weights \(w_i\,\) are given by
\[ w_i(t) = \frac{\rho^\textrm{vol}(t, \mathbf x_i(t))}{s^\textrm{vol}(t, \mathbf x_i(t))}, \]
where \(\mathbf x_i(t) = \Phi_t(\mathbf x_0^i)\qquad\) are the particle locations at time \(t\,\). We can make the following observations:
\[ \rho^\textrm{vol}(t, \mathbf x_i(t)) = \frac{\rho^\textrm{vol}(0, \mathbf x_0^i)}{\big| \textrm{det} D\Phi_t(\mathbf x_0^i) \big|}. \]
\[s^\textrm{vol}(t, \mathbf x_i) = \frac{s^\textrm{vol}(0, \mathbf x_0^i)}{\big| \textrm{det} D\Phi_t(\mathbf x^i_0) \big|}. \]
This implies constancy of the weights:
\[ w_i(t) = \frac{\rho^\textrm{vol}(t, \mathbf x_i(t))}{s^\textrm{vol}(t, \mathbf x_i(t))} = \frac{\rho^\textrm{vol}(0, \mathbf x_0^i)}{s^\textrm{vol}(0, \mathbf x_0^i)} = w_i(0) = const. \]
Hence, in the Monte-Carlo approach, one draws the initial samples \(\mathbf x_0^i\,\) from a probability density \(s^\textrm{vol}(0, \mathbf x_0)\quad\). The information about the initial density \(\rho^\textrm{vol}(0, \mathbf x_0)\quad\) is encoded in the constant weights \(w_i\,\). The particles are then transported by the flow,
\[ \mathbf x^i(t) = \Phi_t(\mathbf x_0^i),\quad \Longleftrightarrow \quad \dot{\mathbf x}^i(t) = \mathbf u(t, \mathbf x^i(t))\quad \mathbf x^i(0) = \mathbf x_0^i, \]
and the weights remain constant.
The equation for the acceleration of the particels can be derived from a variational principle.
The particle approximation of the density \(\rho^\textrm{vol}(t, \mathbf x)\quad\) is given by
\[ \rho_N(t, \mathbf x) = \sum_{i=1}^N w_i\, \delta(\mathbf x - \mathbf x^i(t)). \]
where the markers are transported by the flow,
\[ \mathbf x^i(t) = \Phi_t(\mathbf x_0^i) \]
and the weights remain constant.
The same discrete ansatz is obtained from two different constructions of the initial markers and weights.
| Density approach | Monte-Carlo approach | |
|---|---|---|
| Drawing the markers | Partition \(\Omega_0\) into grid cells \(\Omega_0^i\) and place one marker at the cell center \(\mathbf x_0^i \in \Omega_0^i\quad\). The initial markers are therefore distributed regularly. | Draw the initial markers randomly and independently, \(\mathbf x_0^i \sim s^\textrm{vol}(0, \mathbf x_0)\quad\,\,\). The initial markers therefore follow the sampling density \(s^\textrm{vol}\). |
| Weights | \(w_i := \int_{\Omega_0^i} \rho^\textrm{vol}(0, \mathbf x_0)\,\textrm d\mathbf x_0\). | \(w_i := \dfrac 1N \dfrac{\rho^\textrm{vol}(0, \mathbf x_0^i)}{s^\textrm{vol}(0, \mathbf x_0^i)}\) |
| Comments | Needs numerical quadrature over the initial cells. | Lots of noise, but provable convergence of integrals \(\sim 1/\sqrt N\,\,\,\). |
We can now discretize the action in Eulerian coordinates,
\[ \mathcal A_\textrm{Euler}(\mathbf u, \rho^\textrm{vol}) = \int_0^T \int_{\Omega} \left( \frac{|\mathbf u(t, \mathbf x)|^2}{2} - \frac 1m V(\mathbf x) \right) \rho^\textrm{vol}(t, \mathbf x) \, \textrm d \mathbf x\,\mathrm dt \]
by substituting the particle approximation
\[ \rho^\textrm{vol}(t, \mathbf x) \approx \rho_N(t, \mathbf x) = \sum_{i=1}^N w_i\, \delta(\mathbf x - \mathbf x^i(t)) \]
to obtain …
\[ \begin{aligned} \mathcal A(\mathbf u, \mathbf x^1, \ldots, \mathbf x^N) &= \int_0^T \int_{\Omega} \left( \frac{|\mathbf u(t, \mathbf x)|^2}{2} - \frac 1m V(\mathbf x) \right) \rho_N(t, \mathbf x) \, \textrm d \mathbf x\,\mathrm dt \\[2mm] &= \sum_{i=1}^N w_i \int_0^T \left( \frac{|\mathbf u(t, \mathbf x^i(t))|^2}{2} - \frac 1m V(\mathbf x^i(t)) \right) \, \mathrm dt \\[2mm] &= \sum_{i=1}^N w_i \int_0^T \left( \frac{|\dot{\mathbf x}^i(t)|^2}{2} - \frac 1m V(\mathbf x^i(t)) \right) \, \mathrm dt \end{aligned} \]
where we used the fact that the particles are advected by the flow, i.e. \(\dot{\mathbf x}^i(t) = \mathbf u(t, \mathbf x^i(t)).\)
The action has been reduced to a sum of \(N\,\) independent single-particle actions. The dynamics of the system is thus given by \(N\,\) independent copies of the single-particle dynamics in the potential \(V(\mathbf x)\,\,\,\) i.e. \(N\,\) independent solutions of Newton’s equation
\[ \ddot{\mathbf x}^i = -\frac{1}{m}\nabla V(\mathbf x^i). \]
By contrast, an Eulerian (grid-based) discretization of the same problem would require the discretization of
\[ \begin{aligned} \frac{\partial \rho^\textrm{vol}}{\partial t} + \nabla \cdot (\rho^\textrm{vol} \mathbf u) &= 0 \\[2mm] \frac{\partial \mathbf u}{\partial t} + \mathbf u \cdot \nabla \mathbf u &= - \frac{1}{m} \nabla V \end{aligned} \]
which features nonlinear terms and requires the solution of a coupled system of equations at each time step.
At each time \(t\,\) we have
\[ \rho_N(t, \mathbf x) = \sum_{i=1}^N w_i\, \delta(\mathbf x - \mathbf x^i(t)). \]
But the true solution of the PDE is smooth.
We can obtain a smoother approximation by convolution of \(\rho_N\,\) with a smoothing kernel \(W_h\,\) (e.g. a Gaussian kernel with bandwidth \(h\,\)):
\[ \rho_{h,N}(t, \mathbf x) := (W_h * \rho_N)(t, \mathbf x) = \int_\Omega W_h(\mathbf x - \mathbf y) \rho_N(t, \mathbf y)\,\textrm d \mathbf y = \sum_{i=1}^N w_i\, W_h(\mathbf x - \mathbf x^i(t)). \]
At a chosen evaluation point \(\mathbf x^*\,\,\), the sum only includes contributions from particles within the \(h\,\)-neighborhood of \(\mathbf x^*,\)
\[ \rho_{h,N}(t, \mathbf x^*) = \sum_{i: \|\mathbf x^* - \mathbf x^i(t)\| < h} w_i\, W_h(\mathbf x^* - \mathbf x^i(t)). \]

Algorithmically, we need an efficient way to query the neighboring particles for each evaluation point \(\mathbf x^*.\)
Solution: assign particles to boxes, require box-size \(\geq h\,\,\,\), then:

The question of convergence is important:
These are non-trivial questions we will answer empirically (via simulation).
Other quantities, like the velocity, can also be evaluated in a similar way, e.g.
\[ \mathbf u_{h,N}(t, \mathbf x) = \sum_i w_i\frac{\mathbf v_i(t)}{\rho_{h,N}(\mathbf x_i(t))}\,W_h(\mathbf x - \mathbf x^i(t)), \]
with \(\mathbf v_i = \mathbf u(t, \mathbf x^i(t)) = \dot{\mathbf x}^i(t)\).
We demonstrate SPH kernel density evaluation in 1D using Struphy.
Goal: recover the density \(\rho(\eta_1) = 1.5 + \cos(2\pi\eta_1)\qquad\,\,\) on \(\eta_1 \in [0,1]\quad\) from \(N\,\) markers.
Steps:
ParticlesSPH object and draw markersThe corresponding test is test_sph_evaluation_1d in struphy/src/struphy/pic/tests/test_sph.py.

\[ \rho(\eta_1) = \underbrace{1.5}_{\text{background}} + \underbrace{\cos(2\pi\eta_1)}_{\text{perturbation}}, \qquad \eta_1 \in [0,1] \]
import numpy as np
# from the Strpuhy API
from struphy import (
BoundaryParameters, LoadingParameters, SortingParameters, domains, perturbations, equils
)
# not part of the API (loaded for this test only)
from struphy.pic.particles import ParticlesSPH
# 1D domain in logical coordinates eta1 in [0, 1]
domain = domains.Cuboid(l1=1.0, r1=2.0, l2=10.0, r2=20.0, l3=100.0, r3=200.0)
# background n=1.5 plus perturbation: rho = 1.5 + cos(2*pi*eta1)
background = equils.ConstantVelocity(n=1.5, density_profile="constant")
background.domain = domain
pert = {"n": perturbations.ModesCos(ls=(1,), amps=(1.0,))}
# tesselation: 4 markers per box placed on a regular grid
loading_params = LoadingParameters(ppb=4, seed=1607, loading="tesselation")
boundary_params = BoundaryParameters(bc_sph=("periodic", "periodic", "periodic"))
sorting_params = SortingParameters(boxes_per_dim=(24, 1, 1))particles = ParticlesSPH(
comm_world=None, # no MPI for this example
loading_params=loading_params,
boundary_params=boundary_params,
sorting_params=sorting_params,
bufsize=1.0,
domain=domain,
background=background,
perturbations=pert,
n_as_volume_form=True,
)
particles.draw_markers(sort=False) # place markers at initial positions
particles.initialize_weights() # compute w_i from background densitydraw_markers places one marker per cell center (tesselation) or draws random samplesinitialize_weights sets \(w_i = \int_{\Omega_0^i} \rho^\text{vol}(0, \mathbf x_0)\,\mathrm d\mathbf x_0\)# evaluation grid
eta1 = np.linspace(0, 1.0, 100)
ee1, ee2, ee3 = np.meshgrid(eta1, np.array([0.0]), np.array([0.0]), indexing="ij")
# bandwidth = box size h = 1/24
h1, h2, h3 = 1.0 / 24, 1.0, 1.0
rho_sph = particles.eval_density(
ee1, ee2, ee3,
h1=h1, h2=h2, h3=h3,
kernel_type="gaussian_1d",
derivative=0,
)
rho_exact = 1.5 + np.cos(2 * np.pi * eta1)
err = np.max(np.abs(np.array(rho_sph).squeeze() - rho_exact)) / np.max(np.abs(rho_exact))
print(f"Max relative error: {err:.4f}")Max relative error: 0.0008

\[ \rho_{h,N}(\eta_1) = \sum_{i=1}^N w_i\, W_h(\eta_1 - \eta_1^i) \approx 1.5 + \cos(2\pi\eta_1) \]

\[ \rho_{h,N}(\mathbf{x}) = \sum_i w_i\, W_h(\mathbf{x} - \mathbf{x}^i), \qquad W_h(\mathbf{x}) = \frac{1}{h}\,W\!\left(\frac{|\mathbf{x}|}{h}\right) \]

All three kernels recover the density well.
We extend the SPH density evaluation to 2D using Struphy.
Goal: recover \(\rho(\eta_1,\eta_2) = 1.5 + \cos(2\pi\eta_1)\cos(2\pi\eta_2)\qquad\qquad\) on \((\eta_1,\eta_2)\in[0,1]^2\quad\,\,\) from \(N\,\) markers.
Steps:
ParticlesSPH object and draw markers on a \(12\times12\quad\) gridgaussian_2dThe corresponding test is test_sph_evaluation_2d in struphy/src/struphy/pic/tests/test_sph.py.

\[ \rho(\eta_1,\eta_2) = \underbrace{1.5}_{\text{background}} + \underbrace{\cos(2\pi\eta_1)\cos(2\pi\eta_2)}_{\text{perturbation}}, \qquad (\eta_1,\eta_2)\in[0,1]^2 \]
# 2D domain; logical coordinates (eta1, eta2) in [0,1]^2
dom2d = domains.Cuboid(l1=1.0, r1=2.0, l2=0.0, r2=2.0, l3=100.0, r3=200.0)
# background n=1.5, perturbation: rho = 1.5 + cos(2pi*eta1)*cos(2pi*eta2)
bg2d = equils.ConstantVelocity(n=1.5, density_profile="constant")
bg2d.domain = dom2d
pert2d = {"n": perturbations.ModesCosCos(ls=(1,), ms=(1,), amps=(1.0,))}
# tesselation: 16 markers per box on a 12x12 grid
loading2d = LoadingParameters(ppb=16, loading="tesselation")
boundary2d = BoundaryParameters(bc_sph=("periodic", "periodic", "periodic"))
sorting2d = SortingParameters(boxes_per_dim=(12, 12, 1))# evaluation grid
eta1_2d = np.linspace(0, 1.0, 50)
eta2_2d = np.linspace(0, 1.0, 50)
ee1_2d, ee2_2d, ee3_2d = np.meshgrid(eta1_2d, eta2_2d, np.array([0.0]), indexing="ij")
h2d = 1.0 / 12 # bandwidth = box size
rho_sph_2d = particles2d.eval_density(
ee1_2d, ee2_2d, ee3_2d,
h1=h2d, h2=h2d, h3=1.0,
kernel_type="gaussian_2d",
derivative=0,
)
rho_exact_2d = 1.5 + np.cos(2 * np.pi * ee1_2d) * np.cos(2 * np.pi * ee2_2d)
err_2d = np.max(np.abs(np.array(rho_sph_2d).squeeze() - rho_exact_2d.squeeze())) / np.max(np.abs(rho_exact_2d))
print(f"Max relative error: {err_2d:.4f}")Max relative error: 0.0061

\[ \rho_{h,N}(\eta_1,\eta_2) = \sum_i w_i\, W_h(\eta_1 - \eta_1^i,\,\eta_2 - \eta_2^i) \approx 1.5 + \cos(2\pi\eta_1)\cos(2\pi\eta_2) \]

Two competing sources of error:
Optimal kernel width (red curve): trades off the two effects; as \(N\uparrow\,\) the optimal \(h\) shrinks — more markers allow a finer kernel.
Convergence: along the red curve the minimum error decreases with \(N\). Together \(h\to 0\,\,\,\), \(N\to\infty\,\,\,\,\) with \(N h^d \to\infty\) ensures \(\rho_{h,N}\to\rho\qquad\).
Lagrangian action for the viscous Euler equations:
\[ \mathcal{A}_{\mathrm{Euler}}(\mathbf{u},\rho^{\mathrm{vol}}) = \int_0^T\!\int_{\Omega} \!\left(\frac{|\mathbf{u}(t,\mathbf{x})|^2}{2} -\frac{V(\mathbf{x})}{m} -\mathcal{U}(\rho)\right) \rho^{\mathrm{vol}}(t,\mathbf{x})\,\mathrm{d}\mathbf{x}\,\mathrm{d}t \]
Substitute the particle approximation \(\rho^{\mathrm{vol}}\approx\rho_N = \sum_{i=1}^N w_i\,\delta(\mathbf{x}-\mathbf{x}^i(t))\qquad\quad\,\,\) and use \(\mathbf{u}(t,\mathbf{x}^i(t))=\dot{\mathbf{x}}^i(t)=:\mathbf{v}_i(t)\qquad\,\,\,\,\):
\[ \mathcal{A}_N = \int_0^T\sum_{i=1}^N w_i \!\left(\frac{|\mathbf{v}_i(t)|^2}{2} -\frac{V(\mathbf{x}^i(t))}{m} -\mathcal{U}\!\left(\rho\!\left(t,\mathbf{x}^i(t)\right)\right)\right)\mathrm{d}t \]
Euler–Lagrange equations of \(\mathcal{A}_N\,\,\) (with \(\rho_{h,N}\,\,\) replacing \(\rho\,\,\)) yield the SPH particle system:
\[ \begin{aligned} \dot{\mathbf{x}}^i &= \mathbf{v}_i\,, \\[3mm] \dot{\mathbf{v}}_i &= -\frac{\nabla V(\mathbf{x}^i)}{m} \;-\; \sum_{j=1}^N w_j \!\left(\frac{\partial\mathcal{U}}{\partial\rho}(\rho_i)+\frac{\partial\mathcal{U}}{\partial\rho}(\rho_j)\right) \nabla W_h(\mathbf{x}^i-\mathbf{x}^j)\,, \end{aligned} \]
where \(\rho_i := \rho_{h,N}(t,\mathbf{x}^i) = \sum_j w_j\,W_h(\mathbf{x}^i-\mathbf{x}^j)\qquad\,\,\,\).
The thermodynamic pressure is defined by
\[ p(\rho) = \rho^2\,\frac{\partial\mathcal{U}}{\partial\rho}(\rho) \]
Isothermal: \(\mathcal{U}(\rho) = \kappa\,\ln\rho\quad\,\,\), \(\;\kappa\,\,\,\) constant \(\;\Rightarrow\;p(\rho) = \kappa\rho\)
\[ \dot{\mathbf{v}}_i = -\frac{\nabla V(\mathbf{x}^i)}{m} - \kappa\sum_{j=1}^N w_j \!\left(\frac{1}{\rho_i}+\frac{1}{\rho_j}\right) \nabla W_h(\mathbf{x}^i-\mathbf{x}^j) \]
Polytropic: \(\mathcal{U}(\rho) = \dfrac{\kappa\,\rho^{\gamma-1}}{\gamma-1}\quad\,\,\,\), \(\;\kappa\,\,\,\) polytropic constant, \(\;\gamma = C_p/C_v\quad\) adiabatic index \(\;\Rightarrow\;p(\rho) = \kappa\rho^\gamma\)
\[ \dot{\mathbf{v}}_i = -\frac{\nabla V(\mathbf{x}^i)}{m} - \kappa\sum_{j=1}^N w_j \!\left(\rho_i^{\gamma-2}+\rho_j^{\gamma-2}\right) \nabla W_h(\mathbf{x}^i-\mathbf{x}^j) \]
The SPH velocity gradient at particle \(\boldsymbol\eta_i\) is obtained by differentiating the kernel interpolant:
\[ \nabla\mathbf{v}^{N,h}(\boldsymbol\eta_i) = \sum_l \frac{w_l}{\rho_{h,N}(\boldsymbol\eta_l)}\;\nabla W_h(\boldsymbol\eta_i - \boldsymbol\eta_l)\otimes\mathbf{v}_l \]
where \((\mathbf{a}\otimes\mathbf{b})_{jk}=a_j b_k\qquad\) is the outer product, so that \((\nabla\mathbf{v})_{jk}=\partial_j v_k\qquad\).
The deviatoric strain rate is the traceless symmetric part of \(\nabla\mathbf{v}^{N,h}\,\), scaled by dynamic viscosity \(\mu\):
\[ \boldsymbol\sigma(\boldsymbol\eta_i) =\mu\!\left[ \nabla\mathbf{v}^{N,h}(\boldsymbol\eta_i) +\bigl(\nabla\mathbf{v}^{N,h}(\boldsymbol\eta_i)\bigr)^{\!\top} -\tfrac{2}{3}\bigl(\nabla\cdot\mathbf{v}^{N,h}(\boldsymbol\eta_i)\bigr)\,\mathbf{I} \right] \]
The SPH density at particle \(\boldsymbol\eta_i\) is
\[ \rho^{N,h}(\boldsymbol\eta_i) = \sum_l w_l\,W_h(\boldsymbol\eta_i - \boldsymbol\eta_l)\,. \]
Using the stored stress tensors, the SPH viscous force at particle \(\boldsymbol\eta_i\) reads
\[ \bigl(-\nabla\cdot\boldsymbol\Pi_{\mathrm{vis}}\bigr)^{N,h}(\boldsymbol\eta_i) = \sum_l \frac{w_l}{\rho^{N,h}(\boldsymbol\eta_l)}\;\boldsymbol\sigma(\boldsymbol\eta_l)\,\nabla W_h(\boldsymbol\eta_i-\boldsymbol\eta_l) \]
where \(\boldsymbol\sigma(\boldsymbol\eta_l)\,\nabla W_h\quad\) is the matrix–vector product of the \(3\times3\,\,\) stress tensor at \(\boldsymbol\eta_l\) with the kernel gradient.
Available in the struphy-hub/struphy repository on GitHub (tutorials/ folder):

Meshless algorithms in Struphy - SPEGEO Strasbourg 2026