Continuous Systems & Field Mechanics

The continuum module provides tools for analyzing continuous mechanical systems like vibrating strings, membranes, and elastic bodies.

Overview

For continuous systems, the Lagrangian becomes a Lagrangian density integrated over space. The module implements:

  • Lagrangian Density: For strings, membranes, and general fields

  • Field Euler-Lagrange Equations: Derive wave equations and field equations

  • Vibrating String: Normal modes, Fourier decomposition

  • Vibrating Membrane: 2D mode shapes and frequencies

  • Stress-Energy Tensor: Energy density and momentum flux

Theory

Lagrangian Density

For a field \(\phi(x, t)\), the Lagrangian density is:

\[\mathcal{L} = \mathcal{L}\left(\phi, \frac{\partial\phi}{\partial t}, \frac{\partial\phi}{\partial x}\right)\]

The action is:

\[S = \int \int \mathcal{L} \, dx \, dt\]

Field Euler-Lagrange Equation

The variational principle \(\delta S = 0\) gives:

\[\frac{\partial\mathcal{L}}{\partial\phi} - \frac{\partial}{\partial t}\frac{\partial\mathcal{L}}{\partial\phi_t} - \frac{\partial}{\partial x}\frac{\partial\mathcal{L}}{\partial\phi_x} = 0\]

Wave Equation

For a string with tension \(T\) and linear density \(\mu\):

\[\mathcal{L} = \frac{1}{2}\mu\left(\frac{\partial u}{\partial t}\right)^2 - \frac{1}{2}T\left(\frac{\partial u}{\partial x}\right)^2\]

This gives the wave equation:

\[\frac{\partial^2 u}{\partial t^2} = c^2 \frac{\partial^2 u}{\partial x^2}, \quad c = \sqrt{T/\mu}\]

Usage Examples

Vibrating String Setup

from mechanics_dsl.domains.classical import VibratingString
import numpy as np

# Create string: 1 meter long, wave speed 100 m/s
string = VibratingString(length=1.0, wave_speed=100.0)

# Fundamental frequency
f1 = string.fundamental_frequency()
print(f"Fundamental: f₁ = {f1} Hz")  # f = c/(2L) = 50 Hz

# Harmonic series
for n in range(1, 6):
    f_n = string.mode_frequency(n)
    print(f"Mode {n}: f = {f_n} Hz")

Mode Shapes

from mechanics_dsl.domains.classical import VibratingString
import numpy as np
import matplotlib.pyplot as plt

string = VibratingString(length=1.0, wave_speed=100.0)

x = np.linspace(0, 1, 100)

plt.figure(figsize=(10, 6))
for n in range(1, 5):
    shape = string.mode_shape(n, x)
    plt.plot(x, shape, label=f'Mode {n}')

plt.xlabel('Position (m)')
plt.ylabel('Amplitude')
plt.legend()
plt.title('String Normal Mode Shapes')

Fourier Decomposition

from mechanics_dsl.domains.classical import VibratingString
import numpy as np

string = VibratingString(length=1.0, wave_speed=100.0)

# Initial plucked shape: triangle at center
x = np.linspace(0, 1, 100)
initial_shape = np.where(x <= 0.5, 2*x, 2*(1-x))

# Compute Fourier coefficients
coeffs = string.fourier_coefficients(initial_shape, x, n_modes=10)

print("Fourier coefficients:")
for n, c in enumerate(coeffs, 1):
    print(f"  A_{n} = {c:.4f}")

Time Evolution of String

from mechanics_dsl.domains.classical import VibratingString
import numpy as np
import matplotlib.pyplot as plt

string = VibratingString(length=1.0, wave_speed=100.0)

x = np.linspace(0, 1, 100)
t = np.linspace(0, 0.05, 50)

# Initial displacement
initial = np.sin(np.pi * x)  # First mode only
coeffs = string.fourier_coefficients(initial, x, n_modes=5)

# Compute solution u(x, t)
u = string.solution(x, t, coeffs)

# Plot at different times
for i, t_val in enumerate([0, 10, 25, 40]):
    plt.plot(x, u[:, i], label=f't = {t[t_val]*1000:.1f} ms')
plt.legend()

Vibrating Membrane

from mechanics_dsl.domains.classical import VibratingMembrane
import numpy as np

# Rectangular membrane
membrane = VibratingMembrane(length_x=1.0, length_y=1.5, wave_speed=100.0)

# Mode frequencies
f_11 = membrane.mode_frequency(1, 1)
f_21 = membrane.mode_frequency(2, 1)
f_12 = membrane.mode_frequency(1, 2)

print(f"f(1,1) = {f_11/(2*np.pi):.2f} Hz")
print(f"f(2,1) = {f_21/(2*np.pi):.2f} Hz")
print(f"f(1,2) = {f_12/(2*np.pi):.2f} Hz")

# Get sorted modes
modes = membrane.compute_modes(max_m=3, max_n=3)
print("\nModes sorted by frequency:")
for m, n, freq in modes[:5]:
    print(f"  ({m},{n}): ω = {freq:.2f}")

Membrane Mode Shapes

from mechanics_dsl.domains.classical import VibratingMembrane
import numpy as np
import matplotlib.pyplot as plt

membrane = VibratingMembrane(length_x=1.0, length_y=1.0, wave_speed=100.0)

x = np.linspace(0, 1, 50)
y = np.linspace(0, 1, 50)

fig, axes = plt.subplots(2, 2, figsize=(10, 10))

modes = [(1,1), (2,1), (1,2), (2,2)]
for ax, (m, n) in zip(axes.flat, modes):
    shape = membrane.mode_shape(m, n, x, y)
    ax.contourf(x, y, shape.T, levels=20, cmap='RdBu')
    ax.set_title(f'Mode ({m},{n})')
    ax.set_aspect('equal')

Lagrangian Density

from mechanics_dsl.domains.classical import LagrangianDensity
import sympy as sp

density = LagrangianDensity()

# String Lagrangian density
L_string = density.string_lagrangian()
print(f"String: L = {L_string}")
# L = (1/2)*μ*u_t² - (1/2)*T*u_x²

# Membrane Lagrangian density
L_membrane = density.membrane_lagrangian()
print(f"Membrane: L = {L_membrane}")

# Klein-Gordon (relativistic scalar field)
L_kg = density.klein_gordon_lagrangian()
print(f"Klein-Gordon: L = {L_kg}")

Field Euler-Lagrange

from mechanics_dsl.domains.classical import FieldEulerLagrange
import sympy as sp

field_el = FieldEulerLagrange()

# Derive wave equation from string Lagrangian
wave_eq = field_el.wave_equation_1d()
print(f"Wave equation: {wave_eq}")
# u_tt = c²·u_xx

Convenience Functions

from mechanics_dsl.domains.classical import string_mode_frequencies, wave_speed

# Compute wave speed from tension and density
T = 100.0   # N (tension)
mu = 0.01   # kg/m (linear density)

c = wave_speed(tension=T, density=mu)
print(f"Wave speed: c = {c:.1f} m/s")  # 100 m/s

# Get first 5 mode frequencies
L = 1.0  # m
freqs = string_mode_frequencies(length=L, tension=T, density=mu, n_modes=5)
print("Mode frequencies:", [f"{f:.1f}" for f in freqs])

API Reference

Classes

class VibratingString(length, wave_speed)

Solver for vibrating string.

fundamental_frequency()

Get first harmonic frequency \(f_1 = c/(2L)\).

mode_frequency(n)

Get frequency of mode n: \(f_n = nc/(2L)\).

mode_shape(n, x)

Get mode shape \(\sin(n\pi x/L)\).

compute_modes(n_modes)

Compute list of WaveMode objects.

fourier_coefficients(initial_shape, x_points, n_modes)

Compute Fourier coefficients for initial displacement.

solution(x, t, coefficients)

Compute \(u(x,t)\) via modal superposition.

class VibratingMembrane(length_x, length_y, wave_speed)

Solver for rectangular vibrating membrane.

mode_frequency(m, n)

Get frequency \(\omega_{mn} = \pi c\sqrt{(m/a)^2 + (n/b)^2}\).

mode_shape(m, n, x, y)

Get 2D mode shape.

compute_modes(max_m, max_n)

Get sorted list of (m, n, frequency) tuples.

class LagrangianDensity

Construct Lagrangian densities.

string_lagrangian()

String: \(\mathcal{L} = \frac{1}{2}\mu u_t^2 - \frac{1}{2}T u_x^2\).

membrane_lagrangian()

Membrane Lagrangian density.

klein_gordon_lagrangian()

Relativistic scalar field.

class FieldEulerLagrange

Derive field equations.

derive_field_equation(lagrangian, field, coordinates)

Apply field Euler-Lagrange equation.

wave_equation_1d()

Derive 1D wave equation.

class WaveMode

Normal mode representation.

mode_number

Mode index

frequency

Angular frequency ω

wavenumber

Wave number k

Functions

string_mode_frequencies(length, tension, density, n_modes)

Compute mode frequencies for a string.

wave_speed(tension, density)

Compute \(c = \sqrt{T/\mu}\).

See Also