Skip to main content

A Domain-Specific Language and Transpiler for Classical Mechanics

Project description

MechanicsDSL

Python CI Python 3.8+ License: MIT DOI Documentation Status

A Domain-Specific Language for Classical Mechanics - A comprehensive framework for symbolic and numerical analysis of classical mechanical systems using LaTeX-inspired notation.

Features

  • Symbolic Computation: Automatic derivation of equations of motion from Lagrangians and Hamiltonians
  • Numerical Simulation: Advanced ODE solvers with adaptive step sizing
  • Visualization: Interactive animations and phase space plots
  • Unit System: Comprehensive dimensional analysis and unit checking
  • Constraint Handling: Support for holonomic and non-holonomic constraints
  • Performance Monitoring: Built-in profiling and optimization tools

Installation

pip install mechanicsdsl-core

Quick Start (In GitHub Codespaces)

pip install mechanicsdsl-core

# Save as a .py file (e.g., demo.py)
import numpy as np
import matplotlib
matplotlib.use('Agg') # Headless mode for Codespaces
import matplotlib.pyplot as plt
from mechanics_dsl import PhysicsCompiler

# ============================================================================
# 1. Define Figure-8 System
# ============================================================================
figure8_code = r"""
\system{figure8_orbit}
\defvar{x1}{Position}{m} \defvar{y1}{Position}{m}
\defvar{x2}{Position}{m} \defvar{y2}{Position}{m}
\defvar{x3}{Position}{m} \defvar{y3}{Position}{m}
\defvar{m}{Mass}{kg} \defvar{G}{Grav}{1}

\parameter{m}{1.0}{kg} \parameter{G}{1.0}{1}

\lagrangian{
    0.5 * m * (\dot{x1}^2 + \dot{y1}^2 + \dot{x2}^2 + \dot{y2}^2 + \dot{x3}^2 + \dot{y3}^2)
    + G*m^2/\sqrt{(x1-x2)^2 + (y1-y2)^2}
    + G*m^2/\sqrt{(x2-x3)^2 + (y2-y3)^2}
    + G*m^2/\sqrt{(x1-x3)^2 + (y1-y3)^2}
}

\initial{
    x1=0, y1=0, x1_dot=0, y1_dot=0,
    x2=0, y2=0, x2_dot=0, y2_dot=0,
    x3=0, y3=0, x3_dot=0, y3_dot=0
}
"""

print("Initializing compiler...")
compiler = PhysicsCompiler()

print("Compiling DSL...")
result = compiler.compile_dsl(figure8_code)

if not result['success']:
    print(f"Compilation failed: {result.get('error')}")
    exit(1)

# ============================================================================
# 2. Initial Conditions
# ============================================================================
print("Chenciner & Montgomery initial conditions...")
compiler.simulator.set_initial_conditions({
    'x1': 0.97000436,  'y1': -0.24308753, 'x1_dot': 0.4662036850, 'y1_dot': 0.4323657300,
    'x2': -0.97000436, 'y2': 0.24308753,  'x2_dot': 0.4662036850, 'y2_dot': 0.4323657300,
    'x3': 0.0,         'y3': 0.0,         'x3_dot': -0.93240737,  'y3_dot': -0.86473146
})

# ============================================================================
# 3. Simulate and Check Periodicity
# ============================================================================
# Exact period T for figure-8
T_period = 6.32591398
print(f"Simulating for exactly one period T={T_period:.6f}...")

# Letting the solver adapt (likely selects LSODA)
solution = compiler.simulate(t_span=(0, T_period), num_points=2000)

if not solution['success']:
    print("Simulation failed")
    exit(1)

# --- PERIODICITY CHECK ---
y = solution['y']
state_initial = y[:, 0]
state_final = y[:, -1]

# Calculate Euclidean distance between start and end state
periodicity_error = np.linalg.norm(state_final - state_initial)

print("\n" + "="*50)
print("ANALYSIS RESULTS")
print("="*50)
print(f"Solver Used:       {solution.get('method_used', 'Adaptive')}")
print(f"Periodicity Error: {periodicity_error:.6e}")
print(f"Status:            {'CLOSED ORBIT' if periodicity_error < 1e-2 else 'DRIFT DETECTED'}")
print("="*50 + "\n")

# ============================================================================
# 4. Visualization
# ============================================================================
print("Plotting trajectories...")
coords = solution['coordinates']

def get_traj(name):
    idx = coords.index(name)
    return y[2*idx]

x1, y1 = get_traj('x1'), get_traj('y1')
x2, y2 = get_traj('x2'), get_traj('y2')
x3, y3 = get_traj('x3'), get_traj('y3')

plt.figure(figsize=(10, 6))
plt.plot(x1, y1, label='Body 1', color='#E63946', linewidth=2)
plt.plot(x2, y2, label='Body 2', color='#457B9D', linewidth=2, linestyle='--')
plt.plot(x3, y3, label='Body 3', color='#1D3557', linewidth=2, linestyle=':')

# Annotate the error on the plot
plt.title(f'Three-Body Figure-8 Orbit (Error: {periodicity_error:.2e})')
plt.xlabel('x (m)')
plt.ylabel('y (m)')
plt.axis('equal')
plt.grid(True, alpha=0.3)
plt.legend(loc='upper right')

plt.savefig('figure8_periodicity.png', dpi=150)
print("Saved plot to 'figure8_periodicity.png'")

# Then run python name_of_file.py (e.g., python demo.py)

Validation Gallery

MechanicsDSL has been rigorously tested against analytical solutions, chaotic systems, and conservation laws.

Coupled Modes 3D Dynamics Complex Motion
Wilberforce
Wilberforce Pendulum Beats
Gyroscope
Gyroscope Precession
Elastic
Elastic Pendulum Trajectory
Strange Attractors Phase Space Conservation
Duffing
Duffing Chaotic Attractor
Phase
Harmonic Portraits
Energy
Monotonic Energy Dissipation

Documentation

Full documentation is available at https://mechanicsdsl.readthedocs.io/en/latest/index.html

License

MIT License - see LICENSE file for details.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

mechanicsdsl_core-1.1.0.tar.gz (67.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

mechanicsdsl_core-1.1.0-py3-none-any.whl (52.0 kB view details)

Uploaded Python 3

File details

Details for the file mechanicsdsl_core-1.1.0.tar.gz.

File metadata

  • Download URL: mechanicsdsl_core-1.1.0.tar.gz
  • Upload date:
  • Size: 67.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for mechanicsdsl_core-1.1.0.tar.gz
Algorithm Hash digest
SHA256 205d0fb53dbe9cc8faa4aa1291704e3a08c8c6ff779dc5cf9cb9d438fc7f3fa6
MD5 6b3b99c93737970111fbaf82ca0cb414
BLAKE2b-256 5239b33fffd4434b5040a7efead3842a1ca7b90080b5bb37263a1c3e14d19a1e

See more details on using hashes here.

Provenance

The following attestation bundles were made for mechanicsdsl_core-1.1.0.tar.gz:

Publisher: publish.yml on MechanicsDSL/mechanicsdsl

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file mechanicsdsl_core-1.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for mechanicsdsl_core-1.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 73130ca50be081a2e3d08ce4dff60f0eebc8cc0a446ce53710f70f9ed13db9cf
MD5 08a70a831e5e599a32cdc7093b47c0e1
BLAKE2b-256 e5c352abb69248a4e74fe150c9b5b7c364222e0a165d9652c4ce645b05509280

See more details on using hashes here.

Provenance

The following attestation bundles were made for mechanicsdsl_core-1.1.0-py3-none-any.whl:

Publisher: publish.yml on MechanicsDSL/mechanicsdsl

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page