physicskit.classical#
physicskit.classical: classical_mechanics_kit.
Visual and computational demonstrations of classical mechanics – from Newtonian vector dynamics to Lagrangian variational principles, Hamiltonian phase spaces, coupled lattice chains, and rigid body rotations – built on Numba-accelerated symplectic integrators.
- class physicskit.classical.BeadOnRotatingHoop(theta0, thetadot0, R=1.0, omega=2.0, g=9.81)[source]#
Bases:
LagrangianSystemA bead sliding without friction on a hoop of radius R rotating at fixed angular speed Omega about the vertical diameter.
Generalized coordinate: q = (theta,), the bead’s polar angle on the hoop. In the rotating frame the effective Lagrangian is autonomous (no explicit time dependence), so the system is a genuine 1-DOF conservative Hamiltonian; above the critical speed
Omega_c = sqrt(g / R)the theta=0 equilibrium becomes unstable and two symmetric stable equilibria appear (a pitchfork bifurcation).- Parameters:
- class physicskit.classical.CoupledOscillators(q0, qdot0, n=3, m=1.0, k=1.0)[source]#
Bases:
LagrangianSystemA chain of N masses connected by linear springs, both ends fixed to immovable walls – the small-N, harmonic prototype of the larger lattice chains in
physicskit.classical.systems.chains.Generalized coordinates: q_i = displacement of mass i from equilibrium, i = 1..N.
- Parameters:
- class physicskit.classical.DoublePendulum(theta0, thetadot0, m1=1.0, m2=1.0, l1=1.0, l2=1.0, g=9.81)[source]#
Bases:
LagrangianSystemPlanar double pendulum: two point masses on massless rods.
Generalized coordinates: q = (theta1, theta2), angles from the downward vertical. A classic showcase of deterministic chaos and of the non-separable-Hamiltonian case for symplectic integration (the mass matrix depends on
theta2 - theta1).- Parameters:
- class physicskit.classical.DynamicalSystem(state0)[source]#
Bases:
ABCCommon base for any system with a state vector evolving in time.
- class physicskit.classical.EulerTop(omega0, I1=1.0, I2=2.0, I3=3.0, quat0=None)[source]#
Bases:
ODESystemTorque-free rigid body: Euler’s equations for omega = (w1, w2, w3) in the body frame, coupled to the orientation quaternion (qw, qx, qy, qz).
State:
[w1, w2, w3, qw, qx, qy, qz]. The default integrator,implicit_midpoint, exactly conserves both the rotational kinetic energy and the (squared) angular momentum magnitude and quaternion norm – all quadratic invariants of this quadratic ODE (a classical result: the implicit midpoint / average-vector-field map preserves every quadratic invariant of any ODE, not only linear ones).Excite a spin dominantly about the intermediate-inertia axis (e.g.
omega0 = [0.01, 1.0, 0.01]withI1 < I2 < I3) to see the periodic tumbling of the Intermediate Axis Theorem.- Parameters:
omega0 (array-like, shape (3,)) – Initial body-frame angular velocity.
I1 (float) – Principal moments of inertia.
I2 (float) – Principal moments of inertia.
I3 (float) – Principal moments of inertia.
quat0 (array-like, shape (4,), optional) – Initial orientation quaternion
(w, x, y, z); defaults to the identity orientation. Normalized automatically.
- class physicskit.classical.FPUTChain(n=32, m=1.0, k=1.0, beta=0.0, mode=1, amplitude=1.0)[source]#
Bases:
_ChainBaseFermi-Pasta-Ulam-Tsingou beta-lattice: N masses (default 32) with the quartic non-linear coupling potential V(r) = (k/2) r^2 + (beta/4) r^4, r = q_{i+1} - q_i.
Famous for its “paradox”: exciting a single low-order normal mode does not thermalize energy across all modes as naive ergodic reasoning predicts; instead the energy in
modal_energies()returns almost exactly to the initially excited mode after a characteristic recurrence time (the FPUT recurrence).- Parameters:
- class physicskit.classical.HamiltonianSystem(q0, p0)[source]#
Bases:
DynamicalSystemBase class for canonical Hamiltonian systems H(q, p, t).
Subclasses set
ndof,separable, andmass_inv, and buildself._force_njit(q, t) -> array(required whenseparableis True, giving -dV/dq for H = T(p) + V(q)) and/orself._deriv_njit(t, y) -> dyfor the full stacked state (required for non-separable systems, and optional otherwise – if omitted it is built automatically from_force_njit).- Parameters:
Notes
stateis stored flattened as[q_1..q_n, p_1..p_n].- force(q, t=0.0)[source]#
Return -dV/dq (only defined for separable systems).
- Parameters:
- Return type:
- Returns:
ndarray
- Raises:
NotImplementedError – If the system is non-separable (no
_force_njitset).
- integrate(t_span, dt, method='yoshida4')[source]#
Integrate the system forward in time.
- Parameters:
- Return type:
- Returns:
SimulationResult – The full
(q, p)trajectory and energy diagnostics.
- class physicskit.classical.HarmonicChain(q0, p0, m=1.0, k=1.0)[source]#
Bases:
_ChainBaseLinear chain of N masses coupled by identical springs k, both ends fixed to walls – the exactly-solvable reference lattice whose normal modes are the sine waves used to analyze the non-linear
FPUTChainbelow.- Parameters:
- class physicskit.classical.HeavySymmetricTop(angles0, angledots0, I1=1.0, I3=0.5, M=1.0, l=1.0, g=9.81)[source]#
Bases:
LagrangianSystemSymmetric top with one point fixed, spinning under gravity.
Generalized coordinates q = (phi, theta, psi) – the standard z-x-z Euler angles (precession, nutation, spin). Lagrangian:
- L = (I1/2)(thetadot^2 + phidot^2 sin^2(theta))
(I3/2)(psidot + phidot cos(theta))^2 - M*g*l*cos(theta)
where I1 is the transverse moment of inertia about the fixed point, I3 the axial moment, M the mass, and l the distance from the pivot to the center of mass. Because M(q) depends on theta, this is a genuinely non-separable Hamiltonian system – exactly the case
physicskit.classical.utils.symbolic.LagrangianEngineandimplicit_midpointwere built to handle.- Parameters:
angles0 (array-like, shape (3,)) – Initial
(phi, theta, psi)and their time derivatives.angledots0 (array-like, shape (3,)) – Initial
(phi, theta, psi)and their time derivatives.I1 (float) – Transverse moment of inertia about the fixed point.
I3 (float) – Axial moment of inertia.
M (float) – Mass.
l (float) – Distance from the pivot to the center of mass.
g (float) – Gravitational acceleration.
- class physicskit.classical.HenonHeilesSystem(q0, p0)[source]#
Bases:
HamiltonianSystemH = (px^2 + py^2)/2 + (x^2 + y^2)/2 + x^2*y - y^3/3.
A non-integrable 2-DOF oscillator (originally a model of stellar orbits in an axisymmetric galactic potential). Below E ~ 1/6 the Poincare section (x, px) at y=0 is dominated by smooth KAM tori; as E approaches and exceeds 1/6 the tori progressively break up into chaotic seas.
- Parameters:
q0 (array-like, shape (2,)) – Initial position
(x, y)and momentum(px, py).p0 (array-like, shape (2,)) – Initial position
(x, y)and momentum(px, py).
- class physicskit.classical.KeplerSystem(q0, p0, k=1.0, mu=1.0, eps=0.0, c_eps=0.0, c_pn=0.0, softening=0.0)[source]#
Bases:
HamiltonianSystemPlanar 2-body Kepler problem with optional non-Newtonian perturbations.
- Parameters:
q0 (array-like, shape (2,)) – Initial position and (reduced-mass) momentum.
p0 (array-like, shape (2,)) – Initial position and (reduced-mass) momentum.
k (float) – Gravitational coupling
G * M * mu(standard Kepler strength).mu (float) – Reduced mass (sets kinetic energy
T = |p|^2 / (2 mu)).eps (float) – Exponent and coefficient of an additional
c_eps / r**(1+eps)perturbing potential (eps=0 reduces to an extra inverse-square term).c_eps (float) – Exponent and coefficient of an additional
c_eps / r**(1+eps)perturbing potential (eps=0 reduces to an extra inverse-square term).c_pn (float) – Coefficient of the effective post-Newtonian
c_pn / r**3correction driving perihelion precession.softening (float) – Small Plummer-style softening length to avoid a singular force at r=0 (0 for the exact point-mass limit).
- classmethod from_orbital_elements(a, e, k=1.0, mu=1.0, **kwargs)[source]#
Construct a system starting at perihelion (pure two-body reference orbit).
- lrl_vector(q=None, p=None)[source]#
Laplace-Runge-Lenz vector
A = p x L - mu*k*r_hat(planar form).Exactly conserved (a fixed vector pointing at perihelion) for the unperturbed 1/r potential; its slow rotation once
c_epsorc_pnis nonzero is the precession signature (e.g. Mercury’s perihelion advance).
- class physicskit.classical.LagrangianSystem(q0, qdot0)[source]#
Bases:
DynamicalSystemBase class for systems defined via a Lagrangian L(q, qdot, t).
Subclasses typically obtain their equations of motion from
physicskit.classical.utils.symbolic.LagrangianEngine, which derives both a direct acceleration function (for reporting/plotting in (q, qdot) coordinates, viaself._accel_njit) and a canonical Hamiltonian form (self._canonical_deriv_njit, used for symplectic integration viaimplicit_midpoint– valid even when the mass matrix M(q) is configuration-dependent and the system is therefore non-separable, e.g. the double pendulum).- Parameters:
Notes
stateis stored flattened as[q_1..q_n, qdot_1..qdot_n].- integrate(t_span, dt, method='implicit_midpoint')[source]#
Integrate the system forward in time.
- Parameters:
- Return type:
- Returns:
SimulationResult – The full
(q, qdot)trajectory and energy diagnostics (withresult.pholding qdot, not a canonical momentum).
- class physicskit.classical.ODESystem(state0)[source]#
Bases:
DynamicalSystemA general (possibly non-conservative) first-order ODE system.
Concrete subclasses must set
self._deriv_njit(an@njitdispatcher with signature(t, state) -> dstate) in__init__. Suitable for systems that are not naturally Hamiltonian/symplectic, e.g. central-force problems with drag, or rigid-body Euler equations (whose implicit-midpoint flow exactly conserves the quadratic energy and angular-momentum-squared invariants).
- class physicskit.classical.PendulumSwarm(q0, p0, g_over_l=1.0)[source]#
Bases:
HamiltonianSystemAn ensemble of N independent, identical simple pendulums, H_i = p_i^2 / 2 - (g/l) cos(q_i) for each i = 1..N.
The pendulums are mutually decoupled (each is its own 1-DOF Hamiltonian system) but are integrated together as one N-DOF separable Hamiltonian so a whole ensemble can be evolved with a single Yoshida4/Verlet call. Seeding N points inside a small (dq, dp) box and watching the occupied phase-space patch shear over time – its area invariant even as its shape stretches into a filament – is the standard visual proof of Liouville’s theorem.
- Parameters:
- classmethod from_box(q_center, p_center, dq, dp, n=1000, g_over_l=1.0, seed=0)[source]#
Seed N phase points uniformly inside a (dq x dp) box centered at (q_center, p_center).
- Parameters:
- Returns:
PendulumSwarm
- per_particle_energy(q=None, p=None)[source]#
Energy of each individual pendulum, used to color/track the swarm.
Conserved per-particle since the ensemble is decoupled.
- phase_space_area(q=None, p=None)[source]#
Convex-hull area of the current swarm’s (q, p) point cloud.
A practical proxy for the occupied phase-space volume.
- class physicskit.classical.ProjectileMotion(q0, p0, m=1.0, g=9.81, drag_coeff=0.0)[source]#
Bases:
HamiltonianSystemFree fall under constant gravity with an oblique initial velocity – the “cannonball” problem – with optional quadratic air drag.
Without drag this is the separable Hamiltonian
H(q, p) = |p|^2/(2m) + m*g*y, q = (x, y), whose exact solution is Galileo’s parabolic trajectory (seeanalytic_trajectory()); because the force is constant, the symplectic Verlet/Yoshida4 backends reproduce it to machine precision at any step size.With
drag_coeff > 0a quadratic air-resistance forceF = -drag_coeff * |v| * vis added. This makes the system genuinely dissipative (energy decreases monotonically, there is no closed-form trajectory), so it is only available through therk4/implicit_midpointmethods –verlet/yoshida4would silently ignore it (their force callback only sees the conservative gravity term) and are therefore refused outright.- Parameters:
q0 (array-like, shape (2,)) – Initial position and momentum, q = (x, y), p = (px, py).
p0 (array-like, shape (2,)) – Initial position and momentum, q = (x, y), p = (px, py).
m (
float) – Projectile mass and gravitational acceleration.g (
float) – Projectile mass and gravitational acceleration.drag_coeff (
float) – Quadratic air-drag coefficient (0 for the vacuum/exact case).
- static analytic_trajectory(speed, angle_deg, g, t, height=0.0)[source]#
Exact vacuum trajectory x(t), y(t) – Galileo’s parabola.
Used to validate the numerical integration (
drag_coeff=0only).- Parameters:
- Returns:
x, y (ndarray)
- classmethod from_launch(speed, angle_deg, m=1.0, g=9.81, drag_coeff=0.0, height=0.0)[source]#
Construct a system launched from
(0, height)– the natural “aim the cannon” entry point.- Parameters:
speed (
float) – Launch speed.angle_deg (
float) – Launch angle above the horizontal, in degrees.m (
float) – Projectile mass and gravitational acceleration.g (
float) – Projectile mass and gravitational acceleration.drag_coeff (
float) – Quadratic air-drag coefficient (0 for the vacuum/exact case).height (
float) – Initial height.
- Returns:
ProjectileMotion
- class physicskit.classical.SimulationResult(t, y, q=None, p=None, energy=None, method='', extra=<factory>)[source]#
Bases:
objectContainer for the output of a system’s
integratecall.- Parameters:
- energy: ndarray | None = None#
Total mechanical energy H(t) (or T+V) at each sample.
- Type:
ndarray, shape (n_steps + 1,), optional
- p: ndarray | None = None#
Canonical momenta for Hamiltonian systems, or qdot for Lagrangian systems.
- Type:
ndarray, shape (n_steps + 1, ndof), optional
- class physicskit.classical.SineGordonChain(n=200, m=1.0, k=1.0, q0=None, p0=None)[source]#
Bases:
_ChainBaseDiscretized pendulum chain (Frenkel-Kontorova model): N coupled pendulums, V = sum_i [k/2 (q_{i+1}-q_i)^2 + (1 - cos q_i)], with free (Neumann-like) boundary conditions so a topological kink can propagate off either end without an artificial restoring wall.
Continuum-limit kink initial data from
kink()(q_i = 4*atan(exp((i - i0)/width)), width=1 for the default m=1, k=1) launches a soliton that propagates and scatters off other kinks/antikinks – the discrete analogue of the exact sine-Gordon soliton solutions.- Parameters:
n (int) – Number of pendulums.
m (float) – Mass and coupling constant.
k (float) – Mass and coupling constant.
q0 (array-like, shape (n,), optional) – Initial displacements and momenta; defaults to all zeros. Use
kink()to build soliton initial data instead.p0 (array-like, shape (n,), optional) – Initial displacements and momenta; defaults to all zeros. Use
kink()to build soliton initial data instead.
- static kink(n, center, width=1.0, velocity=0.0, polarity=1)[source]#
Continuum-limit single-kink (or antikink, polarity=-1) initial condition, optionally boosted to move at
velocity(sites per unit time; to the right for positivevelocity, assuming the defaultm=1, k=1– i.e. a natural wave/”light” speedc = sqrt(k/m) = 1, the sine-Gordon equation’s exact Lorentz-invariance scale, so|velocity| < 1is required).widthis not a free shape knob: q_xx = sin(q) (the continuum equation this chain approximates, with the default m=1, k=1) is solved by q=4*atan(exp(x)) only for exactly unit width. Passing a differentwidthhere without also scalingkto match (the static kink ofm q_tt = k q_xx - sin(q)haswidth = sqrt(k);monly sets the wave speedc = sqrt(k/m)) gives a profile that visibly relaxes/radiates under the true dynamics instead of propagating as a clean, stable soliton.The exact traveling-wave solution of the continuum sine-Gordon equation is the Lorentz-contracted profile
q(x, t) = polarity * 4*atan(exp(gamma * (x - center - v*t) / width)),gamma = 1 / sqrt(1 - v**2)– both the spatial profile at t=0 and its time derivative must be boosted together (not just the momentum on top of the unboosted static profile, which is only a small-v approximation and becomes badly wrong as|v|approaches 1).- Parameters:
- Return type:
- Returns:
q0, p0 (ndarray, shape (n,)) – Initial displacements and momenta.
p0isdq/dtat t=0, i.e. the momentum for the defaultm=1; multiply bymfor another mass.- Raises:
ValueError – If
abs(velocity) >= 1.
- physicskit.classical.effective_potential_symmetric_top(theta, p_phi, p_psi, I1, I3, Mgl)[source]#
V_eff(theta) for the heavy symmetric top, given the two conserved (cyclic-coordinate) momenta p_phi and p_psi:
- V_eff(theta) = (p_phi - p_psi cos(theta))^2 / (2 I1 sin^2(theta))
p_psi^2 / (2 I3) + Mgl * cos(theta)
Motion in theta is confined to where the total energy E >= V_eff(theta); the turning points bound the nutation range.
- Parameters:
theta (array-like) – Angle(s) to evaluate at.
p_phi (
float) – Conserved (cyclic-coordinate) momenta.p_psi (
float) – Conserved (cyclic-coordinate) momenta.I1 (
float) – Transverse and axial moments of inertia.I3 (
float) – Transverse and axial moments of inertia.Mgl (
float) –M * g * l(mass times gravity times pivot-to-CM distance).
- Returns:
ndarray
- physicskit.classical.find_theta_equilibrium(p_phi, p_psi, I1, I3, Mgl, bracket=(0.001, 3.1405926535897932))[source]#
The nutation angle theta_eq at which V_eff(theta) is minimized.
The angle steady (non-nutating) precession would hold at, and the center about which a real top’s nutation oscillates.
- Parameters:
p_phi (
float) – Conserved (cyclic-coordinate) momenta.p_psi (
float) – Conserved (cyclic-coordinate) momenta.I1 (
float) – Transverse and axial moments of inertia.I3 (
float) – Transverse and axial moments of inertia.Mgl (
float) –M * g * l.bracket (tuple of float) – Search interval for the minimization.
- Return type:
- Returns:
float
- physicskit.classical.nutation_frequency(p_phi, p_psi, I1, I3, Mgl, theta_eq=None, dtheta=1e-05)[source]#
Small-oscillation nutation frequency about
theta_eq.Treating theta as a 1-DOF particle of “mass” I1 moving in the effective potential V_eff (see
effective_potential_symmetric_top()), the harmonic-approximation frequency about its minimum issqrt(V_eff''(theta_eq) / I1), found here by a central finite difference. Iftheta_eqis not supplied it is located withfind_theta_equilibrium().- Parameters:
p_phi (
float) – Conserved (cyclic-coordinate) momenta.p_psi (
float) – Conserved (cyclic-coordinate) momenta.I1 (
float) – Transverse and axial moments of inertia.I3 (
float) – Transverse and axial moments of inertia.Mgl (
float) –M * g * l.theta_eq (
float) – Equilibrium angle; computed viafind_theta_equilibrium()if omitted.dtheta (
float) – Finite-difference step.
- Return type:
- Returns:
float
- physicskit.classical.pendulum_action_angle(E, g_over_l=1.0)[source]#
Action J(E) and period T(E) for a simple pendulum H = p^2/2 - (g/l)cos(q).
For librating orbits (-g/l < E < g/l), uses the standard elliptic-integral closed form: with k^2 = (E + g/l) / (2 g/l),
J(E) = (8/pi) * sqrt(g/l) * [E_ellip(k) - (1 - k^2) * K_ellip(k)] T(E) = 4 * K_ellip(k) / sqrt(g/l)
where K, E are the complete elliptic integrals of the first/second kind (SciPy’s
special.ellipk/ellipetake the parameter m = k^2, not the modulus k).- Parameters:
- Returns:
J (float) – Action.
T (float) – Orbital period.
- Raises:
ValueError – If
Eis outside the librating range.
- physicskit.classical.precession_frequency(p_phi, p_psi, I1, theta_eq)[source]#
Mean precession rate phidot at nutation angle
theta_eq:(p_phi - p_psi*cos(theta_eq)) / (I1*sin(theta_eq)**2)– the standard steady-precession-rate approximation, exact when the top is not nutating at all (theta held fixed at theta_eq).