Skip to content

Particles

Particle realizations shared by the physics packages: point masses, named forces, potentials, and thermostats.

ConstantForceInteraction(label, *, target, F=0.0, state='x', divisor='m')

Bases: RateInteraction

Constant force F on a target, the second derivative F / m of its position of order 2.

It is the rate F with the mass as divisor, and the LAMMPS backend runs it as fix addforce.

Parameters:

Name Type Description Default
label str

The label of the interaction.

required
target Annotated[str, RoleSpec()]

The path of the element or group the force acts on.

required
F Annotated[ArrayLike, ParameterSpec(vector=True)]

The force vector. A number applies to every component.

0.0
state str

The name of the vector state of order 2 that holds the position of the target.

'x'
divisor str

The name of the state or parameter that holds the mass of the target.

'm'

Examples:

>>> from skcomplex.models.physics.common.particles import ConstantForceInteraction
>>> ConstantForceInteraction('gravity', target='ball', F=[0, -9.81]).F
[0, -9.81]
Source code in src/skcomplex/models/physics/common/particles/_constant_force.py
42
43
44
45
46
47
48
49
50
51
52
def __init__(
    self,
    label: str,
    *,
    target: Annotated[str, RoleSpec()],
    F: Annotated[npt.ArrayLike, ParameterSpec(vector=True)] = 0.0,
    state: str = 'x',
    divisor: str = 'm',
) -> None:
    super().__init__(label, target=target, state=state, divisor=divisor)
    self.F = F

DampingInteraction(label, *, target, gamma=0.1, state='x', divisor='m')

Bases: RateInteraction

Linear damping, a force -gamma * v proportional and opposite to the velocity v of a target.

The velocity is the first derivative of the position, a state of order 2, whose second derivative changes by -gamma * v / m with the mass as divisor. The LAMMPS backend runs it as fix viscous.

Parameters:

Name Type Description Default
label str

The label of the interaction.

required
target Annotated[str, RoleSpec()]

The path of the element or group whose velocity is damped.

required
gamma Annotated[float, ParameterSpec(domain=closed_open(0, oo))]

The damping coefficient.

0.1
state str

The name of the state of order 2 that holds the position of the target.

'x'
divisor str

The name of the state or parameter that holds the mass of the target.

'm'

Examples:

>>> from types import SimpleNamespace
>>> from sage.all__sagemath_symbolics import var
>>> from skcomplex.models.physics.common.particles import DampingInteraction
>>> target = SimpleNamespace(x=var('x'), m=2)
>>> damping = DampingInteraction('air', target='ball', gamma=0.1).check().prepare()
>>> [law.value for law in damping.run(SimpleNamespace(target=target, gamma=var('gamma'))).laws_]
[-1/2*gamma*derivative(x, 1)]
Source code in src/skcomplex/models/physics/common/particles/_damping.py
49
50
51
52
53
54
55
56
57
58
59
def __init__(
    self,
    label: str,
    *,
    target: Annotated[str, RoleSpec()],
    gamma: Annotated[float, ParameterSpec(domain=RealSet.closed_open(0, oo))] = 0.1,
    state: str = 'x',
    divisor: str = 'm',
) -> None:
    super().__init__(label, target=target, state=state, divisor=divisor)
    self.gamma = gamma

GravityInteraction(label, *, first, second, G=1.0, states='x', divisor='m')

Bases: PotentialEnergyInteraction

Newtonian gravity between two particles.

The energy is -G * m_first * m_second / |x_first - x_second|, and its gradient moves both particles.

Parameters:

Name Type Description Default
label str

The label of the interaction.

required
first Annotated[str, RoleSpec()]

The path of the first particle.

required
second Annotated[str, RoleSpec()]

The path of the second particle.

required
G Annotated[float, ParameterSpec(domain=open(0, oo))]

The gravitational constant.

1.0
states str

The name of the vector state that holds the positions of the particles.

'x'
divisor str

The name of the state or parameter that holds the masses of the particles.

'm'

Examples:

>>> from skcomplex.models.physics.common.particles import GravityInteraction
>>> GravityInteraction('gravity', first='sun', second='earth', G=1.0).G
1.0
Source code in src/skcomplex/models/physics/common/particles/_gravity.py
46
47
48
49
50
51
52
53
54
55
56
57
58
59
def __init__(
    self,
    label: str,
    *,
    first: Annotated[str, RoleSpec()],
    second: Annotated[str, RoleSpec()],
    G: Annotated[float, ParameterSpec(domain=RealSet.open(0, oo))] = 1.0,
    states: str = 'x',
    divisor: str = 'm',
) -> None:
    super().__init__(label, target=first, states=states, divisor=divisor)
    self.first = first
    self.second = second
    self.G = G

HarmonicPotentialInteraction(label, *, target, k=1.0, center=0.0, states='x', divisor='m')

Bases: PotentialEnergyInteraction

Harmonic potential that pulls a particle towards a center.

The energy is k * |x - center|**2 / 2.

Parameters:

Name Type Description Default
label str

The label of the interaction.

required
target Annotated[str, RoleSpec()]

The path of the particle.

required
k Annotated[float, ParameterSpec(domain=open(0, oo))]

The stiffness.

1.0
center Annotated[ArrayLike, ParameterSpec(vector=True)]

The center. A number applies to every component.

0.0
states str

The name of the vector state that holds the position of the particle.

'x'
divisor str

The name of the state or parameter that holds the mass of the particle.

'm'

Examples:

>>> from skcomplex.models.physics.common.particles import HarmonicPotentialInteraction
>>> HarmonicPotentialInteraction('trap', target='ball', k=2.0).k
2.0
Source code in src/skcomplex/models/physics/common/particles/_harmonic_potential.py
47
48
49
50
51
52
53
54
55
56
57
58
59
def __init__(
    self,
    label: str,
    *,
    target: Annotated[str, RoleSpec()],
    k: Annotated[float, ParameterSpec(domain=RealSet.open(0, oo))] = 1.0,
    center: Annotated[npt.ArrayLike, ParameterSpec(vector=True)] = 0.0,
    states: str = 'x',
    divisor: str = 'm',
) -> None:
    super().__init__(label, target=target, states=states, divisor=divisor)
    self.k = k
    self.center = center

LangevinThermostatInteraction(label, *, target, temperature=1.0, gamma=1.0, state='x', divisor='m')

Bases: RelaxationInteraction

Langevin thermostat, which adds a drag -gamma * v and a random force that hold particles at a temperature.

Every velocity component follows dv = -gamma * v / m * dt + sqrt(2 * gamma * temperature) / m * dW, with the temperature in energy units, a relaxation of the velocity towards rest over the time m / gamma with additive noise. The velocity is the first derivative of the position, a state of order 2, and the mass is the divisor. A system with a thermostat is stochastic, and its velocities relax to the Maxwell-Boltzmann distribution at that temperature.

Parameters:

Name Type Description Default
label str

The label of the interaction.

required
target Annotated[str, RoleSpec()]

The path of the particle or particle group.

required
temperature Annotated[float, ParameterSpec(domain=closed_open(0, oo))]

The temperature in energy units.

1.0
gamma Annotated[float, ParameterSpec(domain=open(0, oo))]

The friction coefficient.

1.0
state str

The name of the vector state of order 2 that holds the positions of the particles.

'x'
divisor str

The name of the state or parameter that holds the masses of the particles.

'm'

Examples:

>>> from skcomplex.models.physics.common.particles import LangevinThermostatInteraction
>>> LangevinThermostatInteraction('bath', target='gas', temperature=2.0).temperature
2.0
Source code in src/skcomplex/models/physics/common/particles/_langevin_thermostat.py
51
52
53
54
55
56
57
58
59
60
61
62
63
64
def __init__(
    self,
    label: str,
    *,
    target: Annotated[str, RoleSpec()],
    temperature: Annotated[float, ParameterSpec(domain=RealSet.closed_open(0, oo))] = 1.0,
    gamma: Annotated[float, ParameterSpec(domain=RealSet.open(0, oo))] = 1.0,
    state: str = 'x',
    divisor: str = 'm',
) -> None:
    super().__init__(label, target=target, state=state)
    self.temperature = temperature
    self.gamma = gamma
    self.divisor = divisor

LennardJonesInteraction(label, first, second, cutoff=1.0, position='x', *, write='x', divisor=None, period=None, epsilon=1.0, sigma=1.0)

Bases: PairCouplingInteraction

Lennard-Jones pair potential, 4 * epsilon * ((sigma / r) ** 12 - (sigma / r) ** 6), without a shift.

Parameters:

Name Type Description Default
label str

The label of the interaction.

required
first str

The path of the group or particle of the first members.

required
second str

The path of the group or particle of the second members.

required
cutoff float

The distance beyond which pairs do not interact.

1.0
position str

The name of the vector state that holds the positions of the members.

'x'
write str

The name of the state whose rate the force changes, the position of order 2 by default.

'x'
divisor str | None

The name of the parameter that holds the masses of the members, or None for unit masses.

None
period float | None

The side of a periodic box, for minimum image distances, or None for the period of the space.

None
epsilon Annotated[float, ParameterSpec(domain=open(0, oo))]

The depth of the potential well.

1.0
sigma Annotated[float, ParameterSpec(domain=open(0, oo))]

The distance at which the potential is zero.

1.0

Examples:

>>> from skcomplex.models.physics.common.particles import LennardJonesInteraction
>>> LennardJonesInteraction('lj', first='gas', second='gas', cutoff=2.5).sigma
1.0
Source code in src/skcomplex/models/physics/common/particles/_lennard_jones.py
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
def __init__(
    self,
    label: str,
    first: str,
    second: str,
    cutoff: float = 1.0,
    position: str = 'x',
    *,
    write: str = 'x',
    divisor: str | None = None,
    period: float | None = None,
    epsilon: Annotated[float, ParameterSpec(domain=RealSet.open(0, oo))] = 1.0,
    sigma: Annotated[float, ParameterSpec(domain=RealSet.open(0, oo))] = 1.0,
) -> None:
    super().__init__(
        label,
        first,
        second,
        cutoff=cutoff,
        position=position,
        write=write,
        potential=self._get_lennard_jones_energy,
        divisor=divisor,
        period=period,
    )
    self.epsilon = epsilon
    self.sigma = sigma

MassPointElement(label, x=0.0, x_d1=0.0, visual=None, *, m=1.0)

Bases: PointElement

Point mass, a point whose position x has order 2, with its velocity x_d1 and a mass m.

The forces on the point divide by the mass through their divisor 'm'.

Parameters:

Name Type Description Default
label str

The label of the point.

required
x ArrayLike

The initial position. A number applies to every component.

0.0
x_d1 ArrayLike

The initial velocity. A number applies to every component.

0.0
visual VisualSpec | None

How the point is drawn, or None for default_visual_.

None
m Annotated[float, ParameterSpec(domain=open(0, oo))]

The mass.

1.0

Attributes:

Name Type Description
default_visual_

Points at the positions.

Examples:

>>> from skcomplex.models.physics.common.particles import MassPointElement
>>> MassPointElement('ball', x=[0.0, 1.0], m=2.0).m
2.0
Source code in src/skcomplex/models/physics/common/particles/_mass_point.py
47
48
49
50
51
52
53
54
55
56
57
def __init__(
    self,
    label: str,
    x: npt.ArrayLike = 0.0,
    x_d1: npt.ArrayLike = 0.0,
    visual: VisualSpec | None = None,
    *,
    m: Annotated[float, ParameterSpec(domain=RealSet.open(0, oo))] = 1.0,
) -> None:
    super().__init__(label, x=x, x_d1=x_d1, visual=visual)
    self.m = m

PotentialEnergyInteraction(label, *, target, potential=None, states='x', divisor='m')

Bases: GradientInteraction

Potential energy of the positions of particles, whose force on every particle changes its velocity.

It is the gradient of the energy with the mass as divisor: the force -dU/dx on every particle gives the second derivative of its position of order 2, the force divided by its mass. A subclass binds one role per particle and returns the energy from _get_potential, or a user passes the energy as potential.

Parameters:

Name Type Description Default
label str

The label of the interaction.

required
target Annotated[str, RoleSpec()]

The path of the particle or particle group.

required
potential Callable[[SimpleNamespace], object] | None

A function of the namespace that returns the energy, or None for a subclass that returns it.

None
states str | Sequence[str]

The name of the vector state that holds the position of every particle.

'x'
divisor str

The name of the state or parameter that holds the mass of every particle.

'm'

Examples:

>>> from types import SimpleNamespace
>>> from sage.all__sagemath_symbolics import var, vector
>>> from skcomplex.models.physics.common.particles import PotentialEnergyInteraction
>>> ball = SimpleNamespace(x=vector([var('x')]), m=2)
>>> trap = PotentialEnergyInteraction('trap', target='ball', potential=lambda s: s.target.x[0] ** 2)
>>> [law.value for law in trap.check().prepare().run(SimpleNamespace(target=ball)).laws_]
[(-x)]
Source code in src/skcomplex/models/physics/common/particles/_potential_energy.py
47
48
49
50
51
52
53
54
55
56
def __init__(
    self,
    label: str,
    *,
    target: Annotated[str, RoleSpec()],
    potential: Callable[[SimpleNamespace], object] | None = None,
    states: str | Sequence[str] = 'x',
    divisor: str = 'm',
) -> None:
    super().__init__(label, target=target, states=states, potential=potential, divisor=divisor)

SoftSphereInteraction(label, first, second, cutoff=1.0, position='x', *, write='x', divisor=None, period=None, k=100.0)

Bases: PairCouplingInteraction

Soft repulsion between overlapping spheres, k * (cutoff - r) ** 2 / 2 closer than the cutoff.

Parameters:

Name Type Description Default
label str

The label of the interaction.

required
first str

The path of the group or particle of the first members.

required
second str

The path of the group or particle of the second members.

required
cutoff float

The contact distance, the sum of the two radii.

1.0
position str

The name of the vector state that holds the positions of the members.

'x'
write str

The name of the state whose rate the force changes, the position of order 2 by default.

'x'
divisor str | None

The name of the parameter that holds the masses of the members, or None for unit masses.

None
period float | None

The side of a periodic box, for minimum image distances, or None for the period of the space.

None
k Annotated[float, ParameterSpec(domain=open(0, oo))]

The stiffness.

100.0

Examples:

>>> from skcomplex.models.physics.common.particles import SoftSphereInteraction
>>> SoftSphereInteraction('contact', first='gas', second='gas', cutoff=0.1, k=50.0).k
50.0
Source code in src/skcomplex/models/physics/common/particles/_soft_sphere.py
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
def __init__(
    self,
    label: str,
    first: str,
    second: str,
    cutoff: float = 1.0,
    position: str = 'x',
    *,
    write: str = 'x',
    divisor: str | None = None,
    period: float | None = None,
    k: Annotated[float, ParameterSpec(domain=RealSet.open(0, oo))] = 100.0,
) -> None:
    super().__init__(
        label,
        first,
        second,
        cutoff=cutoff,
        position=position,
        write=write,
        potential=self._get_soft_sphere_energy,
        divisor=divisor,
        period=period,
    )
    self.k = k

SpringInteraction(label, *, first, second, k=1.0, length=0.0, states='x', divisor='m')

Bases: PotentialEnergyInteraction

Spring between two particles.

The energy is k * (|x_first - x_second| - length)**2 / 2, and its gradient moves both particles.

Parameters:

Name Type Description Default
label str

The label of the interaction.

required
first Annotated[str, RoleSpec()]

The path of the first particle.

required
second Annotated[str, RoleSpec()]

The path of the second particle.

required
k Annotated[float, ParameterSpec(domain=open(0, oo))]

The stiffness.

1.0
length Annotated[float, ParameterSpec(domain=closed_open(0, oo))]

The rest length.

0.0
states str

The name of the vector state that holds the positions of the particles.

'x'
divisor str

The name of the state or parameter that holds the masses of the particles.

'm'

Examples:

>>> from skcomplex.models.physics.common.particles import SpringInteraction
>>> SpringInteraction('spring', first='a', second='b', k=3.0, length=1.0).length
1.0
Source code in src/skcomplex/models/physics/common/particles/_spring.py
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
def __init__(
    self,
    label: str,
    *,
    first: Annotated[str, RoleSpec()],
    second: Annotated[str, RoleSpec()],
    k: Annotated[float, ParameterSpec(domain=RealSet.open(0, oo))] = 1.0,
    length: Annotated[float, ParameterSpec(domain=RealSet.closed_open(0, oo))] = 0.0,
    states: str = 'x',
    divisor: str = 'm',
) -> None:
    super().__init__(label, target=first, states=states, divisor=divisor)
    self.first = first
    self.second = second
    self.k = k
    self.length = length