| name | computational-physics |
| description | Numerical methods for physics including finite difference, Monte Carlo, molecular dynamics, finite element analysis, and chaos theory for simulation applications. |
| category | physics |
| tags | ["physics","computational-physics","numerical-methods","monte-carlo","molecular-dynamics","finite-element","simulation","chaos"] |
| difficulty | advanced |
| author | neuralblitz |
Computational Physics
What I do
I provide comprehensive expertise in computational physics, applying numerical methods and algorithms to solve physics problems. I enable you to implement finite difference methods, Monte Carlo simulations, molecular dynamics, finite element analysis, and study chaotic systems. My knowledge spans from foundational numerical analysis to advanced simulation techniques essential for modern physics research, engineering analysis, and scientific computing.
When to use me
Use computational physics when you need to: simulate particle dynamics and many-body systems, solve partial differential equations numerically, model random processes and statistical mechanics, perform finite element structural/thermal analysis, analyze chaotic and nonlinear systems, implement grid-based and particle-based simulations, optimize numerical parameters, or visualize physical phenomena.
Core Concepts
- Finite Difference Methods: Discretizing derivatives on grids for solving ODEs and PDEs.
- Monte Carlo Methods: Random sampling for integration, optimization, and statistical simulation.
- Molecular Dynamics: Simulating atomic trajectories using Newton's laws with interatomic potentials.
- Finite Element Analysis: Dividing domains into elements for solving boundary value problems.
- Chaos and Sensitivity: Deterministic unpredictability with sensitive dependence on initial conditions.
- Numerical Stability: Ensuring algorithms produce bounded results without amplification of errors.
- Convergence Analysis: Verifying numerical solutions approach exact solutions as discretization refines.
- Boundary Conditions: Enforcing constraints at domain boundaries (Dirichlet, Neumann, periodic).
- Symplectic Integrators: Preserving phase space volume in Hamiltonian dynamics.
- Parallel Computing: Distributing computations across processors for scaling performance.
Code Examples
Finite Difference Methods
import numpy as np
def central_difference(f, x, h=1e-5):
"""Central difference for first derivative."""
return (f(x + h) - f(x - h)) / (2 * h)
def second_derivative(f, x, h=1e-5):
"""Central difference for second derivative."""
return (f(x + h) - 2*f(x) + f(x - h)) / h**2
def laplacian_2d(f, x, y, h):
"""5-point stencil for 2D Laplacian."""
return (f(x+h, y) + f(x-h, y) + f(x, y+h) + f(x, y-h) - 4*f(x,y)) / h**2
def solve_poisson_2d(f, nx, ny, Lx, Ly, tol=1e-6):
"""Solve Poisson equation ∇²φ = f using SOR."""
hx, hy = Lx/nx, Ly/ny
phi = np.zeros((nx+1, ny+1))
omega = 1.5
max_iter = 10000
for iteration in range(max_iter):
phi_old = phi.copy()
for i in range(1, nx):
for j in range(1, ny):
phi[i,j] = (1-omega)*phi[i,j] + omega/4 * (
phi[i+,j] + phi[i-,j] + phi[i,j+] + phi[i,j-] - hx** * f(i*hx, j*hy)
)
np.(np.(phi - phi_old)) < tol:
phi
():
phi = np.zeros((n, n))
phi[:, -] =
omega = / ( + np.sin(np.pi/n))
iteration ():
phi_old = phi.copy()
i (, n-):
j (, n-):
phi[i,j] = (-omega)*phi[i,j] + omega/ * (
phi[i+,j] + phi[i-,j] + phi[i,j+] + phi[i,j-]
)
np.(np.(phi - phi_old)) < tol:
()
phi
phi = laplace_sor()
()
()
Molecular Dynamics
import numpy as np
class MolecularDynamics:
def __init__(self, n_atoms, box_size, mass=1.0, dt=0.001):
self.n = n_atoms
self.L = box_size
self.m = mass
self.dt = dt
n_per_side = int(np.ceil(n_atoms**(1/3)))
self.r = np.zeros((n_atoms, 3))
idx = 0
for i in range(n_per_side):
for j in range(n_per_side):
for k in range(n_per_side):
if idx < n_atoms:
self.r[idx] = [i/n_per_side, j/n_per_side, k/n_per_side] * box_size
idx += 1
T = 1.0
self.v = np.random.normal(0, np.sqrt(T/mass), (n_atoms, 3))
def lennard_jones(self, r):
"""LJ potential: V = 4ε[(σ/r)^12 - (σ/r)^6]"""
sigma, epsilon = 1.0, 1.0
r6 = (sigma/r)**6
* epsilon * (r6** - r6)
():
sigma, epsilon = ,
r = np.linalg.norm(r_vec)
r2 = r*r
r6 = (sigma**/r2)**
r12 = r6**
force_mag = * epsilon * (*(sigma**)/r12 - (sigma**)/r6) / r2
force_mag * r_vec
():
f = np.zeros((.n, ))
rc =
i (.n):
j (i+, .n):
r_vec = .r[i] - .r[j]
r_vec = r_vec - .L * np.(r_vec / .L)
r = np.linalg.norm(r_vec)
r < rc r > :
f_ij = .lj_force(r_vec)
f[i] += f_ij
f[j] -= f_ij
f
():
f = .compute_forces()
energies = []
step (n_steps):
.r += .v * .dt + * f / .m * .dt**
.r = .r % .L
f_new = .compute_forces()
.v += * (f + f_new) / .m * .dt
f = f_new
thermostat:
thermostat.apply(.v)
KE = * .m * np.(.v**)
PE = .compute_potential()
energies.append((KE, PE))
energies
():
PE =
i (.n):
j (i+, .n):
r_vec = .r[i] - .r[j]
r_vec = r_vec - .L * np.(r_vec / .L)
r = np.linalg.norm(r_vec)
< r < :
PE += .lennard_jones(r)
PE
md = MolecularDynamics(, )
energies = md.integrate()
()
()
()
Monte Carlo Methods
import numpy as np
from scipy import integrate
def metropolis_hastings(log_prob, proposal_std, n_samples, x0):
"""Metropolis-Hastings algorithm for sampling."""
samples = [x0]
x = x0
accept_count = 0
for _ in range(n_samples):
x_proposed = x + np.random.normal(0, proposal_std)
log_alpha = log_prob(x_proposed) - log_prob(x)
if np.log(np.random.random()) < log_alpha:
x = x_proposed
accept_count += 1
samples.append(x)
return np.array(samples), accept_count / n_samples
def log_prob_gaussian_mixture(x):
"""Log probability of mixture of two Gaussians."""
mu1, sigma1 = -2, 1
mu2, sigma2 = 2, 0.5
w1, w2 = 0.4, 0.6
p1 = w1 * np.exp(-0.5 * ((x - mu1)/sigma1)**2) / (sigma1 * np.sqrt(2*np.pi))
p2 = w2 * np.exp(-0.5 * ((x - mu2)/sigma2)**2) / (sigma2 * np.sqrt(2*np.pi))
return np.log(p1 + p2)
samples, accept_rate = metropolis_hastings(log_prob_gaussian_mixture, 0.5, 10000, 0.0)
print(f"Metropolis-Hastings sampling:")
print(f" Acceptance rate: %")
()
()
():
np.random.seed()
x = np.random.uniform(-, , n_samples)
y = np.random.uniform(-, , n_samples)
inside = np.(x** + y** <= )
* inside / n_samples
n [, , , ]:
pi_est = estimate_pi_mc(n)
error = (pi_est - np.pi)
()
():
np.random.seed()
x = proposal_dist.rvs(n_samples)
weights = target_dist.pdf(x) / proposal_dist.pdf(x)
np.mean(weights * f(x)), np.std(weights * f(x)) / np.sqrt(n_samples)
scipy.stats norm, expon
result, error = importance_sampling_integral(
x: x**,
norm(, ),
expon(scale=),
)
()
Chaos and Nonlinear Dynamics
import numpy as np
from scipy.integrate import solve_ivp
def lorenz_attractor(t, state, sigma=10, rho=28, beta=8/3):
"""Lorenz system: dx/dt = σ(y-x), dy/dt = x(ρ-z)-y, dz/dt = xy-βz"""
x, y, z = state
dxdt = sigma * (y - x)
dydt = x * (rho - z) - y
dzdt = x * y - beta * z
return [dxdt, dydt, dzdt]
def rossler_system(t, state, a=0.2, b=0.2, c=5.7):
"""Rössler system."""
x, y, z = state
dxdt = -y - z
dydt = x + a * y
dzdt = b + z * (x - c)
return [dxdt, dydt, dzdt]
def lyapunov_exponent(system, state0, t_span, n_perturbations=4):
"""Estimate Lyapunov exponents using Bennetin's algorithm."""
t_eval = np.linspace(t_span[0], t_span[1], 100)
perturbed = [state0 + epsilon * np.random.randn(len(state0))
for epsilon in [1e-8]*n_perturbations]
for eps_state in perturbed:
sol = solve_ivp(system, t_span, eps_state, t_eval=t_eval)
return np.random.randn(n_perturbations)
state0 = [1.0, 1.0, 1.0]
t_span = (0, )
sol = solve_ivp(lorenz_attractor, t_span, state0, t_eval=np.linspace(, , ))
()
()
()
()
state1 = [, , ]
state2 = [, , ]
sol1 = solve_ivp(lorenz_attractor, (, ), state1, t_eval=np.linspace(, , ))
sol2 = solve_ivp(lorenz_attractor, (, ), state2, t_eval=np.linspace(, , ))
divergence = np.linalg.norm(sol1.y - sol2.y, axis=)
()
()
()
():
r * x * ( - x)
()
r [, , , , ]:
x =
transient = []
orbit = []
_ ():
x = logistic_map(r, x)
transient.append(x)
_ ():
x = logistic_map(r, x)
orbit.append(x)
n_unique = (((x, ) x orbit))
behavior = n_unique == + (n_unique) n_unique <
()
Finite Element Analysis
import numpy as np
class FiniteElement1D:
def __init__(self, n_elements, length, degree=1):
self.n = n_elements
self.L = length
self.h = length / n_elements
self.nodes = np.linspace(0, length, n_elements + 1)
self.elements = [(i, i+1) for i in range(n_elements)]
def shape_functions(self, xi):
"""Linear shape functions on reference element [-1, 1]."""
N1 = (1 - xi) / 2
N2 = (1 + xi) / 2
return np.array([N1, N2])
def shape_derivatives(self, xi):
"""Derivatives of shape functions."""
return np.array([-1/2, 1/2])
def assemble_stiffness(self):
"""Assemble stiffness matrix for -u'' = f."""
K = np.zeros((self.n + 1, self.n + 1))
for (i, j) .elements:
ke = np.array([[/.h, -/.h],
[-/.h, /.h]])
K[i:i+, i:i+] += ke
K
():
F = np.zeros(.n + )
f_eval = f(.nodes)
(i, j) .elements:
fe = .h / * np.array([f_eval[i], f_eval[j]])
F[i:i+] += fe
F
():
K = .assemble_stiffness()
F = .assemble_load(f)
bc_type == :
K[, :] =
K[, ] =
F[] = bc_values[]
K[-, :] =
K[-, -] =
F[-] = bc_values[]
np.linalg.solve(K, F)
():
np.ones_like(x)
fem = FiniteElement1D(, )
u = fem.solve(f_constant)
()
()
()
():
errors = []
ns = [, , , , ]
n ns:
fem = FiniteElement1D(n, )
u_fem = fem.solve(f_constant)
u_analytical = * fem.nodes - * fem.nodes**
error = np.(np.(u_fem - u_analytical))
errors.append(error)
()
(errors) > :
rate = np.log(errors[-]/errors[-]) / np.log()
()
convergence_test()
Best Practices
- Verify numerical solutions against known analytical solutions when available to check implementation.
- Use adaptive step sizes in ODE/PDE solvers to balance accuracy and computational cost.
- For molecular dynamics, ensure adequate equilibration before collecting statistics.
- Check energy conservation in symplectic integrators as a validation test.
- For chaotic systems, use many trajectories and ensemble averages for statistical reliability.
- Consider numerical dispersion and dissipation when choosing numerical schemes for wave equations.
- Use appropriate boundary conditions (absorbing, periodic, reflective) for your physical problem.
- Profile and parallelize computationally intensive sections for performance optimization.
- Validate convergence by refining grids/step sizes until results change within tolerance.
- Use dimensional analysis and physical intuition to check if numerical results are reasonable.