Gridded

pysammos.macroscopic_fields.gridded package

Subpackage for computing macroscopic fields on regular grids.

This subpackage contains the following modules:

Dispatcher module

Scalars module

Vectors module

Tensors module

Secondary module

Dispatcher module

pysammos.macroscopic_fields.gridded.dispatcher module

This module provides a unified interface for computing scalar, vector, and tensor quantities for both monodisperse and polydisperse systems, with or without data scaling. It also supports kinetic tensor calculations with interpolation.

The functions here act as generic wrappers that delegate to specialized implementations based on the cg_calc_mode parameter.

There are two main modes of operation:
  • Monodisperse: All particles or elements are of the same size/type.

  • Polydisperse: Particles or elements have varying sizes/types.

pysammos.macroscopic_fields.gridded.dispatcher.kinetic_tensor(weights, visibility, grid_indices, Displacement, Particle_Velocity, Particle_Mass, Velocity_Field, Velocity_Field_Gradient, phase_array, cg_calc_mode)[source]

Compute the kinetic tensor, including interpolation, for either monodisperse or polydisperse systems.

Return type:

ndarray

Inputs

weightsndarray, shape (N,).

Array of weights for each element/particle.

visibilityndarray, shape (N,).

Visibility mask array.

grid_indicesndarray, shape (N,).

Indices mapping elements to grid locations.

Displacementndarray, shape (N,3).

Displacement vectors for particles/elements.

Particle_Velocityndarray, shape (Nparticles,3).

Velocities of particles.

Particle_Massndarray, shape (Nparticles,3).

Mass of particles.

Velocity_Fieldndarray, shape (Npoints,3).

Velocity field on the grid.

Velocity_Field_Gradientndarray, shape (Npoints,3,3).

Gradient of the velocity field.

phase_arrayndarray, shape (Nparticles).

Phase values, used only in polydisperse mode.

cg_calc_mode{'Monodisperse', 'Polydisperse'}

Calculation mode.

Outputs

ndarray

Computed kinetic tensor values mapped to the grid. Options:

  • `cg_calc_mode`='Monodisperse': np.ndarray, shape(Npoints, 3, 3)

  • `cg_calc_mode`='Polydisperse': np.ndarray, shape(Npoints, Nphases+1, 3, 3)

pysammos.macroscopic_fields.gridded.dispatcher.scalar(weights, visibility, grid_indices, Data, Data_scale, Phase, cg_calc_mode)[source]

Compute a SCALAR quantity for either monodisperse or polydisperse systems.

Return type:

ndarray

Inputs

weightsndarray, shape(N,).

Array of weights for each element/particle.

visibilityndarray, shape(N,).

Visibility mask array.

grid_indicesndarray, shape(N,).

Indices mapping elements to grid locations.

Datandarray, shape(N,).

Primary scalar data values.

Data_scalendarray or None, shape(N,).

Scaling factors for the data. If None, unscaled computation is used.

Phasendarray or None, shape(N,).

Phase values, used only in polydisperse mode.

cg_calc_mode{'Monodisperse', 'Polydisperse'}

Calculation mode.

Outputs

ndarray

Computed scalar values mapped to the grid. Options:

  • `cg_calc_mode`='Monodisperse': np.ndarray, shape(Npoints,)

  • `cg_calc_mode`='Polydisperse': np.ndarray, shape(Npoints, Nphases+1)

pysammos.macroscopic_fields.gridded.dispatcher.tensor(weights, visibility, grid_indices, Data1, Data2, Data_scale, Phase, cg_calc_mode)[source]

Compute a TENSOR quantity for either monodisperse or polydisperse systems.

Return type:

ndarray

Inputs

weightsndarray, shape(N,).

Array of weights for each element/particle.

visibilityndarray, shape(N,).

Visibility mask array.

grid_indicesndarray, shape(N,).

Indices mapping elements to grid locations.

Data1ndarray, shape(N,3).

Primary scalar data values.

Data2ndarray, shape(N,3).

Primary scalar data values.

Data_scalendarray or None, shape(N,).

Scaling factors for the data. If None, unscaled computation is used.

Phasendarray or None, shape(N,).

Phase values, used only in polydisperse mode.

cg_calc_mode{'Monodisperse', 'Polydisperse'}

Calculation mode.

Outputs

ndarray

Computed tensor values mapped to the grid. Options:

  • `cg_calc_mode`='Monodisperse': np.ndarray, shape(Npoints, 3, 3)

  • `cg_calc_mode`='Polydisperse': np.ndarray, shape(Npoints, Nphases+1, 3, 3)

pysammos.macroscopic_fields.gridded.dispatcher.vector(weights, visibility, grid_indices, Data, Data_scale, Phase, cg_calc_mode)[source]

Compute a VECTOR quantity for either monodisperse or polydisperse systems.

Return type:

ndarray

Inputs

weightsndarray, shape(N,).

Array of weights for each element/particle.

visibilityndarray, shape(N,).

Visibility mask array.

grid_indicesndarray, shape(N,).

Indices mapping elements to grid locations.

Datandarray, shape(N,3).

Primary scalar data values.

Data_scalendarray or None, shape(N,).

Scaling factors for the data. If None, unscaled computation is used.

Phasendarray or None, shape(N,).

Phase values, used only in polydisperse mode.

cg_calc_mode{'Monodisperse', 'Polydisperse'}

Calculation mode.

Outputs

ndarray

Computed vector values mapped to the grid. Options:

  • `cg_calc_mode`='Monodisperse': np.ndarray, shape(Npoints, 3)

  • `cg_calc_mode`='Polydisperse': np.ndarray, shape(Npoints, Nphases+1, 3)

Scalars module

pysammos.macroscopic_fields.gridded.scalars module

This module provides functions to compute coarse-grained scalar fields from particle data using weighted averaging over local neighborhoods.

Mathematically, the coarse-grained field \(\phi(\mathbf{x})\) at a grid point \(\mathbf{x}\) is defined as:

\[\phi(\mathbf{x}) = \sum_{i \in \mathrm{neigh}(\mathbf{x})} w_i\, d_i\]

where:

  • \(\mathbf{x}\) is a coarse-graining grid point,

  • \(\mathrm{neigh}(\mathbf{x})\) is the set of particles contributing to the grid point \(\mathbf{x}\),

  • \(w_i\) is the coarse-graining weight for particle \(i\),

  • \(d_i\) is a scalar particle property.

Functions

  • scalar_polydisperse_scaled(): Computes coarse-grained scalar fields for polydisperse particles with an additional per-particle scaling factor.

  • scalar_polydisperse(): Computes coarse-grained scalar fields for polydisperse particles without scaling.

  • scalar_monodisperse_scaled(): Computes coarse-grained scalar fields for monodisperse particles with an additional scaling factor.

  • scalar_monodisperse(): Computes coarse-grained scalar fields for monodisperse particles without scaling.

  • mean_grainsize(): Computes a weighted mean grain size metric, where \(n_\mathrm{flag}\) controls the moment order (e.g., $2$ for area, $3$ for volume).

  • scalar_x_volume(): Computes the coarse-grained average scalar field weighted by particle volume.

Overview

These functions transform particle-based quantities (e.g., mass, velocity components, diameters) into grid-based fields by applying a coarse-graining weighting scheme. The input typically consists of:

  • weights: Coarse-graining kernel weights per visible particle–grid point interaction.

  • visibility: Mapping from weight entries back to particle indices.

  • grid_indices: Index offsets marking which particles contribute to each grid point (with padding at start and end).

  • Data: Scalar quantities per particle.

  • Phase (polydisperse only): Phase identifiers for multi-phase simulations.

Monodisperse vs. Polydisperse

This module implements high-performance, parallelized functions for computing coarse-grained scalar fields from discrete particle data using Numba @njit and prange for loop-level parallelism. It supports both monodisperse and polydisperse particle systems, with optional per-particle scaling factors.

  • Monodisperse: All particles are treated identically; output is a single scalar field per grid point.

  • Polydisperse: Particles are grouped by phase; output contains both per-phase fields and a total field.

Functions with _scaled apply an additional per-particle multiplicative factor (\(\mathrm{Data\_scale}\)), useful for scaling properties before coarse-graining.

Terminology

  • \(N_\mathrm{particles}\): Number of particles in the simulation.

  • \(N_\mathrm{vis}\): Number of particle–grid point interactions (visible weights).

  • \(N_\mathrm{points}\): Number of grid points (excluding padding).

  • \(\mathrm{Phase}\): Integer labels identifying particle classes (e.g., material type).

Performance Notes

  • All functions are Numba-jitted (@njit) with explicit type signatures.

  • prange is used to parallelize over grid points.

  • Temporary arrays are allocated per grid point; results are accumulated into output arrays in a thread-safe manner.

  • Arrays must have consistent types and shapes to avoid recompilation overhead.

pysammos.macroscopic_fields.gridded.scalars.mean_grainsize(weights, visibility, grid_indices, Data, n_flag)

Compute mean grain size using a weighted average with a size exponent.

Inputs

weights(N_vis,) float64 array

Coarse-graining weights for each visible particle.

visibility(N_vis,) int32 array

Particle indices corresponding to each entry in the weights array.

grid_indices(N_points + 2,) int32 array

Start/end indices into the visibility array for each grid point.

Data(N_particles,) float32 array

Particle diameters or characteristic sizes.

n_flagint

Exponent flag:

  • 3 for volume-weighted mean size.

  • 2 for area-weighted mean size.

Outputs

CG_Field(N_points,) float64 array

Mean grain size for each grid point.

pysammos.macroscopic_fields.gridded.scalars.scalar_monodisperse(weights, visibility, grid_indices, Data)

Compute coarse-grained scalar fields for monodisperse systems.

Inputs

weights(N_vis,) float64 array

Coarse-graining weights for each visible particle.

visibility(N_vis,) int32 array

Particle indices corresponding to each entry in the weights array.

grid_indices(N_points + 2,) int32 array

Start/end indices into the visibility array for each grid point.

Data(N_particles,) float32 array

Scalar quantity per particle.

Outputs

CG_Field(N_points,) float64 array

Coarse-grained scalar field for each grid point.

pysammos.macroscopic_fields.gridded.scalars.scalar_monodisperse_scaled(weights, visibility, grid_indices, Data, Data_scale)

Compute coarse-grained scalar fields for monodisperse systems with an additional scaling factor.

Inputs

weights(N_vis,) float64 array

Coarse-graining weights for each visible particle.

visibility(N_vis,) int32 array

Particle indices corresponding to each entry in the weights array.

grid_indices(N_points + 2,) int32 array

Start/end indices into the visibility array for each grid point.

Data(N_particles,) float32 array

Scalar quantity per particle.

Data_scale(N_particles,) float32 array

Additional scaling factor per particle.

Outputs

CG_Field(N_points,) float64 array

Coarse-grained scalar field for each grid point.

pysammos.macroscopic_fields.gridded.scalars.scalar_polydisperse(weights, visibility, grid_indices, Data, Phase)

Compute coarse-grained scalar fields for polydisperse systems.

Inputs

weights(N_vis,) float64 array

Coarse-graining weights for each visible particle.

visibility(N_vis,) int32 array

Particle indices corresponding to each entry in the weights array.

grid_indices(N_points + 2,) int32 array

Start/end indices into the visibility array for each grid point.

Data(N_particles,) float32 array

Scalar quantity per particle (e.g., mass, velocity component).

Phase(N_particles,) int32 array

Phase index (0..P-1) for each particle.

Ouptuts

CG_Field(N_points, N_phases + 1) float64 array

Coarse-grained scalar field per phase (columns 1..P) and total (column 0).

pysammos.macroscopic_fields.gridded.scalars.scalar_polydisperse_scaled(weights, visibility, grid_indices, Data, Data_scale, Phase)

Compute coarse-grained scalar fields for polydisperse systems with an additional scaling factor.

Inputs

weights(N_vis,) float64 array

Coarse-graining weights for each visible particle.

visibility(N_vis,) int32 array

Particle indices corresponding to each entry in the weights array.

grid_indices(N_points + 2,) int32 array

Start/end indices into the visibility array for each grid point. Assumes padding: first = 0, last = len(visibility).

Data(N_particles,) float32 array

Scalar quantity per particle (e.g., mass, velocity component).

Data_scale(N_particles,) float32 array

Additional scaling factor per particle.

Phase(N_particles,) int32 array

Phase index (0..P-1) for each particle.

Outputs

CG_Field(N_points, N_phases + 1) float64 array

Coarse-grained scalar field per phase (columns 1..P) and total (column 0).

pysammos.macroscopic_fields.gridded.scalars.scalar_x_volume(weights, visibility, grid_indices, Data)

Compute the average of a scalar quantity weighted by particle volume.

Inputs

weights(N_vis,) float64 array

Coarse-graining weights (often proportional to particle volume).

visibility(N_vis,) int32 array

Particle indices corresponding to each entry in the weights array.

grid_indices(N_grid + 2,) int32 array

Start/end indices into the visibility array for each grid point.

Data(N_particles,) float32 array

Scalar quantity per particle.

Outputs

CG_Field(N_points,) float64 array

Volume-weighted scalar average per grid point.

Vectors module

pysammos.macroscopic_fields.gridded.vectors module

This module provides functions to compute coarse-grained vector fields from particle data using weighted averaging over local neighborhoods.

Mathematically, the coarse-grained field \(\mathbf{F}(\mathbf{x})\) at a grid point \(\mathbf{x}\) is defined as:

\[\mathbf{F}(\mathbf{x}) = \sum_{i \in \text{neigh}(\mathbf{x})} w_i \, \mathbf{d}_i\]

where:

  • \(\mathbf{F}(\mathbf{x})\) is the coarse-grained vector field at grid point \(\mathbf{x}\),

  • \(w_i\) is the coarse-graining weight for particle \(i\),

  • \(\mathbf{d}_i\) is a vector particle property (e.g., velocity, diameter).

Functions

  • vector_polydisperse_scaled(): Computes coarse-grained vector fields for polydisperse particles with an additional per-particle scaling factor.

  • vector_polydisperse(): Computes coarse-grained vector fields for polydisperse particles without scaling.

  • vector_monodisperse_scaled(): Computes coarse-grained vector fields for monodisperse particles with an additional scaling factor.

  • vector_monodisperse(): Computes coarse-grained vector fields for monodisperse particle mixtures without scaling.

Overview

These functions transform particle-based quantities (e.g., mass, velocity components, diameters) into grid-based fields by applying a coarse-graining weighting scheme. The input typically consists of:

  • weights: Coarse-graining kernel weights per visible particle–grid point interaction.

  • visibility: Mapping from weight entries back to particle indices.

  • grid_indices: Index offsets marking which particles contribute to each grid point (with padding at start and end).

  • Data: Scalar quantities per particle.

  • Phase (polydisperse only): Phase identifiers for multi-phase simulations.

  • Data_scale (scaled versions only): Additional per-particle scaling factors.

Monodisperse vs. Polydisperse

This module implements high-performance, parallelized functions for computing coarse-grained scalar fields from discrete particle data using Numba @njit and prange for loop-level parallelism. It supports both monodisperse and polydisperse particle systems, with optional per-particle scaling factors.

  • Monodisperse: All particles are treated identically; output is a single scalar field per grid point.

  • Polydisperse: Particles are grouped by phase; output contains both per-phase fields and a total field.

Functions with _scaled apply an additional per-particle multiplicative factor (\(\mathrm{Data\_scale}\)), useful for scaling properties before coarse-graining.

Terminology

  • \(N_\mathrm{particles}\): Number of particles in the simulation.

  • \(N_\mathrm{vis}\): Number of particle–grid point interactions (visible weights).

  • \(N_\mathrm{points}\): Number of grid points (excluding padding).

  • \(\mathrm{Phase}\): Integer labels identifying particle classes (e.g., material type).

Performance Notes

  • All functions are Numba-jitted (@njit) with explicit type signatures.

  • prange is used to parallelize over grid points.

  • Temporary arrays are allocated per grid point; results are accumulated into output arrays in a thread-safe manner.

  • Arrays must have consistent types and shapes to avoid recompilation overhead.

pysammos.macroscopic_fields.gridded.vectors.vector_monodisperse(weights, visibility, grid_indices, Data)

Compute coarse-grained vector fields for monodisperse systems.

Parameters:
  • weights ((N_vis,) float64 array) -- Coarse-graining weights for each visible particle.

  • visibility ((N_vis,) int32 array) -- Particle indices corresponding to each entry in the weights array.

  • grid_indices ((N_points + 2,) int32 array) -- Start/end indices into the visibility array for each grid point. Assumes padding: first = 0, last = len(visibility).

  • Data ((N_particles,3) float32 array) -- Vector quantity per particle.

  • Data_scale ((N_particles,) float32 array) -- Additional scaling factor per particle.

  • Phase ((N_particles,) int32 array) -- Phase index (0..P-1) for each particle.

Returns:

CG_Field -- Coarse-grained scalar field per phase (columns 1..P) and total (column 0).

Return type:

(N_points, N_phases + 1, 3) float64 array

pysammos.macroscopic_fields.gridded.vectors.vector_monodisperse_scaled(weights, visibility, grid_indices, Data, Data_scale)

Compute coarse-grained vector fields for monodisperse systems with an additional scaling factor.

Parameters:
  • weights ((N_vis,) float64 array) -- Coarse-graining weights for each visible particle.

  • visibility ((N_vis,) int32 array) -- Particle indices corresponding to each entry in the weights array.

  • grid_indices ((N_points + 2,) int32 array) -- Start/end indices into the visibility array for each grid point. Assumes padding: first = 0, last = len(visibility).

  • Data ((N_particles,3) float32 array) -- Vector quantity per particle.

  • Data_scale ((N_particles,) float32 array) -- Additional scaling factor per particle.

Returns:

CG_Field -- Coarse-grained scalar field.

Return type:

(N_points, 3) float64 array

pysammos.macroscopic_fields.gridded.vectors.vector_polydisperse(weights, visibility, grid_indices, Data, Phase)

Compute coarse-grained vector fields for polydisperse systems.

Parameters:
  • weights ((N_vis,) float64 array) -- Coarse-graining weights for each visible particle.

  • visibility ((N_vis,) int32 array) -- Particle indices corresponding to each entry in the weights array.

  • grid_indices ((N_points + 2,) int32 array) -- Start/end indices into the visibility array for each grid point. Assumes padding: first = 0, last = len(visibility).

  • Data ((N_particles,3) float32 array) -- Vector quantity per particle.

  • Phase ((N_particles,) int32 array) -- Phase index (0..P-1) for each particle.

Returns:

CG_Field -- Coarse-grained scalar field per phase (columns 1..P) and total (column 0).

Return type:

(N_points, N_phases + 1, 3) float64 array

pysammos.macroscopic_fields.gridded.vectors.vector_polydisperse_scaled(weights, visibility, grid_indices, Data, Data_scale, Phase)

Compute coarse-grained vector fields for polydisperse systems with an additional scaling factor.

Parameters:
  • weights ((N_vis,) float64 array) -- Coarse-graining weights for each visible particle.

  • visibility ((N_vis,) int32 array) -- Particle indices corresponding to each entry in the weights array.

  • grid_indices ((N_points + 2,) int32 array) -- Start/end indices into the visibility array for each grid point. Assumes padding: first = 0, last = len(visibility).

  • Data ((N_particles,3) float32 array) -- Vector quantity per particle.

  • Data_scale ((N_particles,) float32 array) -- Additional scaling factor per particle.

  • Phase ((N_particles,) int32 array) -- Phase index (0..P-1) for each particle.

Returns:

CG_Field -- Coarse-grained scalar field per phase (columns 1..P) and total (column 0).

Return type:

(N_points, N_phases + 1, 3) float64 array

Tensors module

pysammos.macroscopic_fields.gridded.tensors module

This module provides functions to compute coarse-grained tensor fields from particle data using weighted averaging over local neighborhoods.

Mathematically, the coarse-grained field \(\mathbf{T}(\mathbf{x})\) at a grid point \(\mathbf{x}\) is defined as follows:

\[\mathbf{T}(\mathbf{x}) = \sum_{i \in \text{neigh}(\mathbf{x})} w_i \, \mathbf{d}_i \otimes \mathbf{d}_i\]

where:

  • \(\mathbf{x}\) is a coarse-graining grid point,

  • \(\text{neigh}(\mathbf{x})\) is the set of particles contributing to the grid point \(\mathbf{x}\),

  • \(w_i\) is the coarse-graining weight for particle \(i\),

  • \(\mathbf{d}_i\) is a vector particle property,

  • \(\otimes\) denotes the outer product.

Functions

Overview

These functions transform particle-based quantities (e.g., mass, velocity components, diameters) into grid-based fields by applying a coarse-graining weighting scheme. The input typically consists of:

  • weights: Coarse-graining kernel weights per visible particle–grid point interaction.

  • visibility: Mapping from weight entries back to particle indices.

  • grid_indices: Index offsets marking which particles contribute to each grid point (with padding at start and end).

  • Data: Scalar quantities per particle.

  • Phase (polydisperse only): Phase identifiers for multi-phase simulations.

Monodisperse vs. Polydisperse

  • Monodisperse: All particles are treated identically; output is a single tensor field per grid point.

  • Polydisperse: Particles are grouped by phase; output contains both per-phase fields and a total field.

Functions with _scaled apply an additional per-particle multiplicative factor (Data_scale), useful for scaling properties before coarse-graining.

Terminology

  • \(N_\mathrm{particles}\): Number of particles in the simulation.

  • \(N_\mathrm{vis}\): Number of particle–grid point interactions (visible weights).

  • \(N_\mathrm{points}\): Number of grid points (excluding padding).

  • \(\mathrm{Phase}\): Integer labels identifying particle classes (e.g., material type).

Performance Notes

  • All functions are Numba-jitted (@njit) with explicit type signatures.

  • prange is used to parallelize over grid points.

  • Temporary arrays are allocated per grid point; results are accumulated into output arrays in a thread-safe manner.

  • Arrays must have consistent types and shapes to avoid recompilation overhead.

pysammos.macroscopic_fields.gridded.tensors.kinetic_tensor_interpolation_monodisperse(weights, visibility, grid_indices, displacement, Particle_Velocity, Particle_Mass, Velocity_Field, Velocity_Field_Gradient)

Compute the kinetic stress tensor for a monodisperse system by interpolating particle velocity fluctuations relative to a continuum velocity field.

Mathematical formulation:

For each grid point ( g ), the kinetic tensor is:

\[\mathbf{K}_{g} = \sum_{i \in I_g} m_i w_i (\mathbf{v}_i - \mathbf{v}_g^{\text{interp}}) \otimes (\mathbf{v}_i - \mathbf{v}_g^{\text{interp}})\]
where:
  • \(I_g\) is the set of particles contributing to grid point ( g )

  • \(m_i\) is the mass of particle ( i )

  • \(w_i\) is the kernel weight of particle ( i ) for grid point ( g )

  • \(\mathbf{v}_i\) is the velocity of particle ( i )

  • \(\mathbf{v}_g^{\text{interp}} = \mathbf{v}_g + \mathbf{G}_g \cdot \mathbf{r}_{g,i}\) is the interpolated continuum velocity at particle ( i )

  • \(\mathbf{r}_{g,i}\) is the displacement vector from grid point ( g ) to particle ( i )

Inputs

weights(N_vis,) float64 array

Coarse-graining weights for each visible particle.

visibility(N_vis,) int32 array

Particle indices corresponding to each entry in the weights array.

grid_indices(N_points + 2,) int32 array

Start/end indices into the visibility array for each grid point. Assumes padding: first = 0, last = len(visibility).

displacement(N_vis, 3) float64 array

Displacement vectors from grid points to visible particles.

Particle_Velocity(N_particles, 3) float64 array

Velocity vectors of all particles.

Particle_Mass(N_particles,) float32 array

Mass of each particle.

Velocity_Field(N_points, 3) float64 array

Velocity field values at each grid point.

Velocity_Field_Gradient(N_points, 3, 3) float64 array

Velocity gradient tensors at each grid point.

Outputs

KineticTensor(N_points, 3, 3) float64 array

Kinetic stress tensor per grid point. No interpolation is applied to the velocity fluctuations for this tensor.

FluctuationTensor(N_points, 3, 3) float64 array

Fluctuation tensor for granular temperature calculation. Interpolation is applied to the velocity fluctuations for this tensor.

pysammos.macroscopic_fields.gridded.tensors.kinetic_tensor_interpolation_polydisperse(weights, visibility, grid_indices, displacement, Particle_Velocity, Particle_Mass, Velocity_Field, Velocity_Field_Gradient, phase_array)

Compute the kinetic stress tensor for a polydisperse system by interpolating particle velocity fluctuations relative to a continuum velocity field.

The tensor is computed separately for each phase and summed to form a total tensor. For each grid point ( g ) and phase ( p ), the kinetic tensor is:

\[K_{g,p} = \sum_{i \in I_g^{(p)}} m_i w_i (v_i - v_g^{\text{interp}}) \otimes (v_i - v_g^{\text{interp}})\]

where:

  • \(I_g^{(p)}\) is the set of particles of phase p contributing to grid point g

  • \(m_i\) is the mass of particle i

  • \(w_i\) is the kernel weight of particle i for grid point g

  • \(v_i\) is the velocity of particle i

  • \(v_g^{interp} = v_g + G_g \cdot r_{g,i}\) is the interpolated continuum velocity at particle i position

  • \(r_{g,i}\) is the displacement vector from grid point g to particle i

  • \(\otimes\) denotes the outer product

Inputs

weights(N_vis,) float64 array

Coarse-graining weights for each visible particle.

visibility(N_vis,) int32 array

Particle indices corresponding to each entry in the weights array.

grid_indices(N_points + 2,) int32 array

Start/end indices into the visibility array for each grid point. Assumes padding: first = 0, last = len(visibility).

displacement(N_vis, 3) float64 array

Displacement vectors from grid points to visible particles.

Particle_Velocity(N_particles, 3) float64 array

Velocity vectors of all particles.

Particle_Mass(N_particles,) float64 array

Mass of each particle.

Velocity_Field(N_points, 3) float64 array

Velocity field values at each grid point.

Velocity_Field_Gradient(N_points, 3, 3) float32 array

Velocity gradient tensors at each grid point.

phase_array(N_particles,) int32 array

Phase index (0..P-1) for each particle.

Outputs

KineticTensor(N_points, N_phases + 1, 3, 3) float64 array

Kinetic stress tensor per grid point and phase. Index 0 is total over phases. No interpolation is applied to the velocity fluctuations for this tensor.

FluctuationTensor(N_points, N_phases + 1, 3, 3) float64 array

Fluctuation tensor for granular temperature calculation. Interpolation is applied to the velocity fluctuations for this tensor.

pysammos.macroscopic_fields.gridded.tensors.tensor_monodisperse(weights, visibility, grid_indices, Data1, Data2)

Compute coarse-grained tensor fields for monodisperse systems.

Inputs

weights(N_vis,) float64 array

Coarse-graining weights for each visible particle.

visibility(N_vis,) int32 array

Particle indices corresponding to each entry in the weights array.

grid_indices(N_points + 2,) int32 array

Start/end indices into the visibility array for each grid point. Assumes padding: first = 0, last = len(visibility).

Data1(N_particles,3) float32 array

Vector quantity per particle.

Data2(N_particles,3) float32 array

Vector quantity per particle.

Data_scale(N_particles,) float32 array

Additional scaling factor per particle.

Phase(N_particles,) int32 array

Phase index (0..P-1) for each particle.

Outputs

CG_Field(N_points, N_phases + 1, 3, 3) float64 array

Coarse-grained scalar field per phase (columns 1..P) and total (column 0).

pysammos.macroscopic_fields.gridded.tensors.tensor_monodisperse_scaled(weights, visibility, grid_indices, Data1, Data2, Data_scale)

Compute coarse-grained tensor fields for monodisperse systems with an additional scaling factor.

Inputs

weights(N_vis,) float64 array

Coarse-graining weights for each visible particle.

visibility(N_vis,) int32 array

Particle indices corresponding to each entry in the weights array.

grid_indices(N_points + 2,) int32 array

Start/end indices into the visibility array for each grid point. Assumes padding: first = 0, last = len(visibility).

Data1(N_particles,3) float32 array

Vector quantity per particle.

Data2(N_particles,3) float32 array

Vector quantity per particle.

Data_scale(N_particles,) float32 array

Additional scaling factor per particle.

Outputs

CG_Field(N_points, 3, 3) float64 array

Coarse-grained scalar field.

pysammos.macroscopic_fields.gridded.tensors.tensor_polydisperse(weights, visibility, grid_indices, Data1, Data2, Phase)

Compute coarse-grained tensor fields for polydisperse systems.

Inputs

weights(N_vis,) float64 array

Coarse-graining weights for each visible particle.

visibility(N_vis,) int32 array

Particle indices corresponding to each entry in the weights array.

grid_indices(N_points + 2,) int32 array

Start/end indices into the visibility array for each grid point. Assumes padding: first = 0, last = len(visibility).

Data1(N_particles,3) float32 array

Vector quantity per particle.

Data2(N_particles,3) float32 array

Vector quantity per particle.

Phase(N_particles,) int32 array

Phase index (0..P-1) for each particle.

Outputs

CG_Field(N_points, N_phases + 1, 3, 3) float64 array

Coarse-grained scalar field per phase (columns 1..P) and total (column 0).

pysammos.macroscopic_fields.gridded.tensors.tensor_polydisperse_scaled(weights, visibility, grid_indices, Data1, Data2, Data_scale, Phase)

Compute coarse-grained tensor fields for polydisperse systems with an additional scaling factor.

Inputs

weights(N_vis,) float64 array

Coarse-graining weights for each visible particle.

visibility(N_vis,) int32 array

Particle indices corresponding to each entry in the weights array.

grid_indices(N_points + 2,) int32 array

Start/end indices into the visibility array for each grid point. Assumes padding: first = 0, last = len(visibility).

Data1(N_particles,3) float32 array

Vector quantity per particle.

Data2(N_particles,3) float32 array

Vector quantity per particle.

Data_scale(N_particles,) float32 array

Additional scaling factor per particle.

Phase(N_particles,) int32 array

Phase index (0..P-1) for each particle.

returns:

CG_Field -- Coarse-grained scalar field per phase (columns 1..P) and total (column 0).

rtype:

(N_points, N_phases + 1, 3, 3) float64 array

Secondary module

pysammos.macroscopic_fields.gridded.secondary module

This module provides functions to compute velocity gradients, shear rate tensors, deviatoric tensors, tensor invariants, pressure, inertial numbers, granular temperature, and bulk fabric tensors for both monodisperse and polydisperse particulate systems.

It supports 1D, 2D, and 3D grids and uses NumPy for array operations and Numba for accelerated numerical loops.

The main functions include:

Notes

  • All array shapes are explicitly described in the function docstrings.

  • The functions handle both monodisperse and polydisperse cases: the number of phases is denoted by P.

  • Functions decorated with @njit are JIT-compiled with Numba for performance.

pysammos.macroscopic_fields.gridded.secondary.bulk_fabric_tensor_Sun2015(normalised_center_to_center_vectors)

Compute the bulk fabric tensor following Sun et al. (2015).

\[\mathbf{A} = \frac{1}{N_c} \sum_{i=1}^{N_c} \left( \mathbf{l}_i \otimes \mathbf{l}_i - \frac{1}{3} \mathbf{I} \right)\]

where \(N_c\) is the number of contacts, \(\mathbf{l}_i\) is the normalised contact vector between particle centers, and \(\mathbf{I}\) is the identity matrix.

Inputs

normalised_center_to_center_vectors(Nc, 3) ndarray

Normalised contact vectors between particle centers.

Outputs

A(3, 3) ndarray

Bulk fabric tensor.

rtype:

ndarray

pysammos.macroscopic_fields.gridded.secondary.compute_deviatoric_tensor(Tensor)

Compute the deviatoric tensor by removing the mean normal stress, given by:

\[\mathbf{T}_{dev} = \mathbf{T} - \frac{1}{D} \text{tr}(\mathbf{T}) \mathbf{I}\]

where \(D\) is the spatial dimension (2 or 3), \(\text{tr}(\mathbf{T})\) is the trace of the tensor, and \(\mathbf{I}\) is the identity matrix.

Inputs

Tensor(N, 3, 3) or (N, P, 3, 3) ndarray

Stress tensor(s). P is number of phases.

Outputs

DeviatoricTensorndarray, shape (N, 3, 3) or (N, P, 3, 3)

Tensor(s) with isotropic part removed. Shape matches input.

rtype:

ndarray

pysammos.macroscopic_fields.gridded.secondary.compute_granular_temperature(DensityMixture, KineticTensor)

Compute granular temperature following Weinhart (2016).

\[T_g = \frac{1}{D} \frac{\text{tr}(\mathbf{\sigma}^k)}{\rho_p}\]

where \(D\) is the spatial dimension (2 or 3), \(\text{tr}(\mathbf{\sigma}^k)\) is the trace of the kinetic energy tensor, and \(\rho_p\) is the particle density.

Inputs

DensityMixture(N,) or (N, P) ndarray

Bulk or phase-wise particle density.

KineticTensor(N, 3, 3), (N, P, 3, 3), (N,), or (N, P) ndarray

Full kinetic energy tensor or scalar kinetic energy component.

Outputs

GranularTemperature(N,) or (N, P) ndarray

Granular temperature(s).

rtype:

ndarray

pysammos.macroscopic_fields.gridded.secondary.compute_inertial_number(shear_rate_tens_dev_mag, pressure, particle_density_mix, particle_diameter_mix, density_phases, diameter_phases)

Compute the inertial number for monodisperse or polydisperse systems, given by:

\[I = \frac{\dot{\gamma} d \sqrt{\rho}}{\sqrt{|p|}}\]

where \(\dot{\gamma}\) is the magnitude of the deviatoric shear rate tensor, \(d\) is the particle diameter, \(\rho\) is the particle density, and \(p\) is the pressure.

Inputs

shear_rate_tens_dev_mag(N,) ndarray

Magnitude of the deviatoric shear rate tensor.

pressure(N,) or (N, P) ndarray

Pressure values.

particle_density_mix(N,) or (N, P) ndarray

Bulk particle density.

particle_diameter_mix(N,) ndarray

Bulk particle diameter.

density_phases(P-1,) ndarray

Densities for individual phases (polydisperse case).

diameter_phases(P-1,) ndarray

Diameters for individual phases (polydisperse case).

Outputs

Inertial_Number(N,) or (N, P) ndarray

Dimensionless inertial number(s).

rtype:

ndarray

pysammos.macroscopic_fields.gridded.secondary.compute_pressure(StressTensor)

Compute pressure from the stress tensor.

Return type:

ndarray

Inputs

StressTensor(N, 3, 3) or (N, P, 3, 3) ndarray

Stress tensor(s), where P is the number of phases.

Outputs

Pressure(N,) or (N, P) ndarray

Computed pressure(s).

pysammos.macroscopic_fields.gridded.secondary.compute_second_invariant(Tensor, factor=0.5)

Compute the second invariant of a deviatoric stress tensor, defined as:

\[\begin{split}J_2(\mathbf{r}, t) := \alpha\, \mathrm{tr}\left( \mathbf{\Pi}^2(\mathbf{r}, t) \right), \quad \text{where} \quad \alpha = \begin{cases} \frac{1}{2}, & \text{if } \mathbf{\Pi} \neq \boldsymbol{\Gamma} \\[2mm] 2, & \text{if } \mathbf{\Pi} = \boldsymbol{\Gamma} \end{cases}\end{split}\]

where \(\mathbf{\Pi}\) is any tensor, and \(\boldsymbol{\Gamma}\) is the shear rate tensor, which is related to the effective shear rate \(\dot \gamma_{\text{eff}} = \sqrt{2J_2}\), hence \(\alpha=2\) when \(\mathbf{\Pi}=\boldsymbol{\Gamma}\).

Inputs

Tensor(N, 3, 3), (N, 2, 2), (N, P, 3, 3), or (N, P, 2, 2) ndarray

Deviatoric stress tensor(s).

factorfloat, optional

Multiplicative factor in the invariant calculation (default is 0.5).

returns:

second_invariant -- Second invariant magnitude for each tensor.

rtype:

ndarray

pysammos.macroscopic_fields.gridded.secondary.compute_shear_rate_tensor(VelocityGrad)

Compute the symmetric shear rate tensor from a velocity gradient tensor, given by:

\[\boldsymbol{\Gamma}(\mathbf{r}, t) := \frac{1}{2} \left( \nabla \mathbf{V}(\mathbf{r}, t) + \left[\nabla \mathbf{V}(\mathbf{r}, t)\right]^T \right)\]

where \(\nabla \mathbf{V}\) is the velocity gradient tensor.

Inputs

VelocityGrad(N, 3, 3) ndarray

Velocity gradient tensor for N points.

Outputs

ShearRateTensor(N, 3, 3) ndarray

Symmetric part of the velocity gradient tensor.

rtype:

ndarray

pysammos.macroscopic_fields.gridded.secondary.compute_vector_bulk_gradient(Velocity_bulk_CG, nodes, spacing)[source]

Compute the gradient tensor of a bulk velocity field on a regular grid. The gradient tensor is defined as:

\[\begin{split}\nabla \mathbf{V}(\mathbf{r}, t) = \begin{bmatrix} \frac{\partial u}{\partial x} & \frac{\partial u}{\partial y} & \frac{\partial u}{\partial z} \\ \frac{\partial v}{\partial x} & \frac{\partial v}{\partial y} & \frac{\partial v}{\partial z} \\ \frac{\partial w}{\partial x} & \frac{\partial w}{\partial y} & \frac{\partial w}{\partial z} \end{bmatrix}\end{split}\]

where \(\mathbf{V} = (u, v, w)\) is the velocity vector, and the partial derivatives are taken with respect to spatial coordinates.

Inputs

Velocity_bulk_CG(N, 3) ndarray

Flattened velocity field with 3 components per grid point.

nodestuple of int

Shape of the grid. Can be (nx,), (nx, ny), or (nx, ny, nz).

spacingtuple of float

Grid spacings along each dimension (dx,), (dx, dy), or (dx, dy, dz).

Outputs

GradTen(N, 3, ndim) ndarray

Velocity gradient tensor at each grid point, where ndim is the number of spatial dimensions (1, 2, or 3).

raises ValueError:

If the dimensionality is not 1, 2, or 3.

Notes

  • The function handles 1D, 2D, and 3D grids automatically.

  • Output is flattened back to match the input node order.

rtype:

ndarray

pysammos.macroscopic_fields.gridded.secondary.compute_velgrad_leastsquares(weights, visibility, grid_indices, displacement, Particle_Velocity, Particle_Mass, Velocity_Field)

Compute the velocity gradient tensor at grid points using a least-squares approach based on particle contributions.

Assuming that the velocity field can be locally approximated as a linear function of position around each grid point, the method minimizes the error in the velocity approximation for particles contributing to that grid point. The velocity field at a particle position is approximated as:

\(\mathbf{V}(\mathbf{r}_i(t), t) := \mathbf{V}(\mathbf{r}, t) - \nabla \mathbf{V}(\mathbf{r}, t)\cdot(\mathbf{r}-\mathbf{r}_i)\)

The velocity gradient tensor is then obtained by minimizing the error function:

\[\varepsilon(\mathbf{G}(\mathbf{r})) := \sum_i \Psi m_i \left| \mathbf{v}_i - \mathbf{V}(\mathbf{r}, t) + \mathbf{G}(\mathbf{r}) \cdot (\mathbf{r} - \mathbf{r}_i) \right|^2\]

For which the optimal gradient tensor is given by:

\[\mathbf{G}(\mathbf{r}) = \left( \sum_i \Psi m_i (\mathbf{r} - \mathbf{r}_i) \otimes (\mathbf{r} - \mathbf{r}_i) \right)^{-1} \left( \sum_i \Psi m_i (\mathbf{v}_i - \mathbf{V}(\mathbf{r}, t)) \times (\mathbf{r} - \mathbf{r}_i) \right)\]

Inputs

weights(N,) ndarray

Coarse-graining weights for each particle contribution.

visibility(N,) ndarray

Indices of particles contributing to each grid point, flattened.

grid_indices(G+1,) ndarray

Start and end indices in visibility for each grid point, where G is the number of grid points.

displacement(N, 3) ndarray

Displacement vectors from grid points to particles for each contribution.

Particle_Velocity(N, 3) ndarray

Velocities of particles for each contribution.

Particle_Mass(N,) ndarray

Masses of particles for each contribution.

Velocity_Field(G, 3) ndarray

Velocity field at grid points, used to compute relative velocities.

Outputs

GradV(G, 3, 3) ndarray

Velocity gradient tensor at each grid point.