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

MechanicsDSL is a comprehensive computational framework for physics, unifying symbolic derivation and numerical simulation. It bridges the gap between algebraic formalism and high-performance computing using a LaTeX-inspired Domain-Specific Language.

Features

  • Symbolic Mechanics: Automatic derivation of equations of motion (Euler-Lagrange & Hamiltonian).
  • Computational Fluid Dynamics (CFD): Lagrangian fluid simulation using Smoothed Particle Hydrodynamics (SPH).
  • High-Performance Backends: Generates optimized C++, OpenMP, and WebAssembly (WASM) solvers.
  • Multiphysics Support: Handles rigid bodies, N-body gravity, and compressible fluids in a single framework.
  • Visualization: Built-in tools for phase space plots, energy analysis, and particle animations.

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)

Quick Start 2: Fluid Dynamics (The Dam Break)

MechanicsDSL includes a Spatial Hash SPH Solver for simulating fluids.

import matplotlib.pyplot as plt
from mechanics_dsl import PhysicsCompiler

# Define fluid regions and boundaries using the DSL
fluid_code = r"""
\system{dam_break}

% Simulation Resolution
\parameter{h}{0.04}{m}
\parameter{g}{9.81}{m/s^2}

% Fluid Column (Water)
\fluid{water}
\region{rectangle}{x=0.0 .. 0.4, y=0.0 .. 0.8}
\particle_mass{0.02}
\equation_of_state{tait}

% Container (Bucket)
\boundary{walls}
\region{line}{x=-0.05, y=0.0 .. 1.5}   % Left Wall
\region{line}{x=1.5,   y=0.0 .. 1.5}   % Right Wall
\region{line}{x=-0.05 .. 1.5, y=-0.05} % Floor
"""

compiler = PhysicsCompiler()
# 1. Generate Particles
compiler.compile_dsl(fluid_code)

# 2. Compile C++ SPH Engine
compiler.compile_to_cpp("dam_break.cpp", target="standard", compile_binary=True)

# 3. Run Simulation (Auto-executes binary)
import subprocess
subprocess.call(["./dam_break"])

# 4. Visualize
compiler.visualizer.animate_fluid_from_csv("dam_break_sph.csv")
plt.show()

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.2.1.tar.gz (72.0 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.2.1-py3-none-any.whl (56.0 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: mechanicsdsl_core-1.2.1.tar.gz
  • Upload date:
  • Size: 72.0 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.2.1.tar.gz
Algorithm Hash digest
SHA256 fb204f888fa89f40bc13c142b82f897c275a00a248696471f7835ff0c4f66d05
MD5 4237039cf204633ef5f5967cab91529d
BLAKE2b-256 b210e584fb57c559993f36ae31abc6f1b7678dee73b5f706631c7dbcfe466e7a

See more details on using hashes here.

Provenance

The following attestation bundles were made for mechanicsdsl_core-1.2.1.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.2.1-py3-none-any.whl.

File metadata

File hashes

Hashes for mechanicsdsl_core-1.2.1-py3-none-any.whl
Algorithm Hash digest
SHA256 0f46afbdc864493a106caf6b97dbbc43414beb4f5c59c072573e3756ba91e2b2
MD5 f2a034e0dd6b7e9cabffaf4003a51eb0
BLAKE2b-256 8bd919bb0d2c64873c94803644181db3a40b0c16d4a3f5f66c842ea7c33c669a

See more details on using hashes here.

Provenance

The following attestation bundles were made for mechanicsdsl_core-1.2.1-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