API Reference#
Complete API documentation for soliton_solver. This section documents the public interfaces for creating and running simulations.
Quick start#
Loading a theory and running a simulation#
from soliton_solver.theories import load_theory
from soliton_solver.core.simulation import Simulation
# Load a theory
theory = load_theory("Chiral magnet")
# Create parameters
params = theory.params.default_params(
xlen=256, ylen=256, xsize=10.0, ysize=10.0
)
# Create simulation
sim = Simulation(params, theory)
sim.initialize({"mode": "ground"})
# Run minimization step
energy, err = sim.step(prev_energy=0.0)
print(f"Energy: {energy}, Gradient norm: {err}")
Listing available theories#
from soliton_solver import theories
# List all theories
theories.print_table()
# Get canonical names
available = theories.list()
print(available)
# Get theory description
theories.print_description("Baby Skyrme")
soliton_solver.theories#
Theory registry and loading interface.
Functions#
load_theory(name: str) → module
Load a theory by name.
theory = load_theory("Ginzburg-Landau superconductor")
Parameters:
name(str) — Canonical theory name or alias
Returns: Theory module with submodules:
params,kernels,initial_config,observables,io,render_glRaises: KeyError if theory name not registered
list_theories() → tuple[str, ...]
Return canonical names of all registered theories.
for theory_name in theories.list():
print(theory_name)
list() → tuple[str, ...]
Convenience alias for list_theories().
print_table() → None
Print a formatted table of registered theories with descriptions.
print_description(name: str) → None
Print detailed description of a theory.
theories.print_description("Chiral magnet")
get_theory_spec(name: str) → TheorySpec
Get metadata for a theory.
spec = theories.registry.get_theory_spec("Baby Skyrme")
print(spec.name, spec.version, spec.description)
Classes#
TheorySpec(name, import_path, description, version, aliases, required_submodules)
Immutable metadata for a theory.
Attributes:
name(str) — Canonical theory nameimport_path(str) — Python import pathdescription(str) — Short descriptionversion(str) — Version identifieraliases(tuple[str]) — Alternative namesrequired_submodules(tuple[str]) — Required submodules
soliton_solver.core.simulation#
Main simulation interface.
Simulation class#
Simulation(params, theory)
High-level simulation wrapper binding a theory to the CUDA solver.
sim = Simulation(params, theory)
Parameters:
params(Params) — Parameter settheory(module) — Loaded theory module
Methods#
initialize(init_config: dict | None = None) → None
Set up the grid and apply initial field configuration.
sim.initialize({"mode": "ground"}) # Ground state
sim.initialize({"mode": "vortex"}) # Vortex configuration
Parameters:
init_config(dict, optional) — Initialization options (theory-specific)
step(prev_energy: float) → tuple[float, float]
Advance simulation by one arrested Newton flow step.
energy, err = sim.step(prev_energy=energy)
Parameters:
prev_energy(float) — Energy from previous step (used for arrest logic)
Returns: Tuple (new_energy, gradient_norm_max)
observables() → dict
Compute theory-specific observables.
obs = sim.observables()
energy = obs["energy"]
topological_charge = obs.get("topological_charge")
Returns: Dictionary of observable values
save_output(output_dir: str | None = None, precision: int = 32) → None
Write simulation results to disk.
sim.save_output(output_dir="results", precision=32)
Parameters:
output_dir(str, optional) — Output directory (defaults to theory results dir)precision(int) — Number of significant figures for formatting
Attributes#
Field(CUDA device array) — Current field configurationVelocity(CUDA device array) — Current velocity fieldgrid(CUDA device array) — Physical coordinate gridp_i_h,p_f_h(numpy arrays) — Integer and float parameters (host)p_i_d,p_f_d(CUDA device arrays) — Integer and float parameters (device)theory(module) — Theory modulerp(ResolvedParams) — Resolved parameters
soliton_solver.core.params#
Parameter management.
Classes#
Params(xlen, ylen, halo, xsize, ysize, lsx, lsy, courant, time_step, killkinen, newtonflow, unit_magnetization)
User-facing parameter set.
params = Params(
xlen=256, ylen=256,
xsize=80.0, ysize=80.0,
time_step=0.01
)
Attributes:
xlen(int) — Grid points along x (default: 256)ylen(int) — Grid points along y (default: 256)halo(int) — Halo width for stencils (default: 2)xsize(float) — Physical domain size x (default: 80.0)ysize(float) — Physical domain size y (default: 80.0)lsx,lsy(float | None) — Lattice spacings (computed if None)courant(float) — Courant number for adaptive time step (default: 0.5)time_step(float | None) — Explicit time step (if None, computed from Courant)killkinen(bool) — Reset velocity on energy increase (default: True)newtonflow(bool) — Enable Newton flow vs. gradient descent (default: True)unit_magnetization(bool) — Enforce unit magnetization constraint (default: False)
Params.with_(**kwargs) → Params
Create a modified copy.
params2 = params.with_(xlen=512, ylen=512)
Params.resolved() → ResolvedParams
Derive solver-ready parameters.
rp = params.resolved()
print(rp.lsx, rp.lsy, rp.time_step)
ResolvedParams
Computed parameters ready for the solver.
Attributes:
dim_grid(int) — Total grid pointsdim_fields(int) — Total field valueslsx,lsy(float) — Lattice spacingsgrid_volume(float) — Cell areatime_step(float) — Actual time stepkillkinen,newtonflow,unit_magnetization(int) — Integer flags
soliton_solver.core.integrator#
Time integration and minimization algorithms.
Functions#
make_do_gradient_step_kernel(do_gradient_step_point) → cuda.jit
Factory for creating a gradient computation kernel.
def my_gradient_point(Velocity, Field, EnergyGradient, d1fd1x, d2fd2x, x, y, p_i, p_f):
# Compute gradient at (x, y)
...
gradient_kernel = make_do_gradient_step_kernel(my_gradient_point)
Parameters:
do_gradient_step_point(function) — Per-thread gradient computation
Returns: CUDA kernel for computing gradients
make_do_rk4_kernel(compute_norm, project_orthogonal) → cuda.jit
Factory for creating an RK4 finalization kernel with constraint projection.
Parameters:
compute_norm(function) — Field normalization (e.g., for magnetization)project_orthogonal(function) — Constraint projection (e.g., unit norm)
Returns: CUDA kernel for RK4 updates with constraints
do_arrested_newton_flow(...) → tuple[float, float]
Perform one arrested Newton flow step.
Returns: (new_energy, convergence_error)
soliton_solver.core.derivatives#
Finite-difference operators.
Functions#
compute_derivative_first(d1fd1x, Field, a, x, y, p_i, p_f) → None
Compute fourth-order first spatial derivatives at (x, y).
Device function (for use inside CUDA kernels):
@cuda.jit
def my_kernel(d1fd1x, Field, p_i, p_f):
x, y = cuda.grid(2)
if in_bounds(x, y, p_i):
compute_derivative_first(d1fd1x, Field, 0, x, y, p_i, p_f)
compute_derivative_second(d2fd2x, Field, a, x, y, p_i, p_f) → None
Compute fourth-order second spatial derivatives (Laplacian + mixed) at (x, y).
soliton_solver.core.utils#
GPU utilities and helpers.
Functions#
idx_field(a, i, j, p_i) → int
Map field component and lattice site to flattened index.
Device function:
idx = idx_field(0, x, y, p_i)
value = Field[idx]
idx_d1(coord, field, i, j, p_i) → int
Map coordinate, field component, and lattice site to first derivative index.
idx_d2(coord1, coord2, field, i, j, p_i) → int
Map two coordinates, field component, and lattice site to second derivative index.
launch_2d(p_i_h, threads=(8, 8)) → tuple
Construct a 2D CUDA launch configuration.
grid2d, block2d = launch_2d(p_i_h, threads=(8, 8))
my_kernel[grid2d, block2d](...)
Returns: Tuple (grid, block) for CUDA kernel launch
in_bounds(x, y, p_i) → bool
Device function to check if (x, y) is within the interior domain (beyond halo).
@cuda.jit
def my_kernel(Field, p_i):
x, y = cuda.grid(2)
if in_bounds(x, y, p_i):
# Compute on interior points only
...
compute_sum(Field, gridsum_partial, dim_grid) → float
Reduce a field to a scalar sum.
compute_max(Field, max_partial, dim_grid) → float
Reduce a field to the maximum absolute value.
compute_min(Field, min_partial, dim_grid) → float
Reduce a field to the minimum value.
soliton_solver.core.colormaps#
Color mapping for visualization.
Functions#
render_jet_density_to_rgba(pbo_rgba, density, min_val, max_val, p_i) → None
Map a density field to jet colormap and write to RGBA buffer.
CUDA kernel:
render_jet_density_to_rgba[grid2d, block2d](
pbo_rgba, density, 0.0, 1.0, p_i_d
)
render_gray_density_to_rgba(pbo_rgba, density, min_val, max_val, p_i) → None
Map a density field to grayscale.
render_magnetization_to_rgba(pbo_rgba, magnetization, p_i) → None
Map a magnetization vector field (3-component) to HSV colormap.
soliton_solver.visualization.gl_backend#
OpenGL and CUDA-OpenGL interoperability.
GLBackend class#
GLBackend(width, height, title="CUDA-OpenGL")
GLFW window and OpenGL-CUDA rendering backend.
backend = GLBackend(512, 512, title="My Simulation")
Methods#
map_pbo() → cuda_array
Map the pixel buffer object for CUDA access.
pbo_rgba = backend.map_pbo()
my_render_kernel[grid2d, block2d](pbo_rgba, ...)
cuda.synchronize()
Returns: CUDA array view of the PBO (uint8, shape (height, width, 4))
unmap_pbo() → None
Release the PBO back to OpenGL.
upload_and_draw() → None
Copy PBO to texture and display.
should_close() → bool
Check if the user requested window close.
set_title(text: str) → None
Update the window title.
Theory interface#
Each theory module must provide:
Required submodules#
params
Paramsclass (extends coreParams)default_params(**kwargs)functionpack_device_params(params)function returning (p_i_h, p_f_h) tuples
kernels
do_gradient_step_kernel— CUDA kernel for gradient computationdo_rk4_kernel(optional) — CUDA kernel for RK4 with constraints
initial_config
initialize(Velocity, Field, ..., config)— Set up initial fields
observables
compute_energy(Field, d1fd1x, ...)— Compute total energyTheory-specific observable functions
io
save_output(output_dir, h_Field, ...)— Write results to disk
render_gl
run_viewer(sim, params, **kwargs)— Launch interactive viewer
Optional submodules#
instructions.py
print_instructions()— Print keyboard controls
results/plotting.py
Post-processing and analysis scripts
Common patterns#
Running a minimization loop#
from soliton_solver.theories import load_theory
from soliton_solver.core.simulation import Simulation
theory = load_theory("Chiral magnet")
params = theory.params.default_params(xlen=256, ylen=256, xsize=10.0, ysize=10.0)
sim = Simulation(params, theory)
sim.initialize({"mode": "ground"})
# Initial energy
energy = sim.observables_mod.compute_energy(
sim.Field, sim.d1fd1x, sim.en, sim.entmp,
sim.gridsum_partial, sim.p_i_d, sim.p_f_d,
sim.p_i_h, sim.p_f_h
)
# Minimize
for step in range(10000):
new_energy, err = sim.step(prev_energy=energy)
energy = new_energy
if step % 100 == 0:
print(f"Step {step:5d}: E={energy:.6e}, ||∇E||={err:.6e}")
if err < 1e-4:
print(f"Converged in {step} steps")
break
sim.save_output()
Computing custom observables#
from numba import cuda
@cuda.jit
def my_observable_kernel(observable, Field, p_i, p_f):
x, y = cuda.grid(2)
if in_bounds(x, y, p_i):
# Theory-specific computation
observable[idx_field(0, x, y, p_i)] = ...
# Compute
grid2d, block2d = launch_2d(sim.p_i_h, threads=(8, 8))
my_observable_kernel[grid2d, block2d](observable_buffer, sim.Field, sim.p_i_d, sim.p_f_d)
cuda.synchronize()
# Copy to host
h_observable = observable_buffer.copy_to_host()
result = np.sum(h_observable) # Aggregate
Interactive visualization with custom controls#
from soliton_solver.visualization.gl_backend import GLBackend
backend = GLBackend(512, 512, title="Custom Viewer")
while not backend.should_close():
# Map PBO for rendering
pbo_rgba = backend.map_pbo()
# Render field density
render_density_kernel[grid2d, block2d](pbo_rgba, sim.Field, ...)
cuda.synchronize()
# Unmap and display
backend.unmap_pbo()
backend.upload_and_draw()
# Advance solver
energy, err = sim.step(energy)
# Update title with status
backend.set_title(f"E={energy:.4e} ||∇E||={err:.4e}")
backend.terminate()
Extending the solver#
To add a new theory, see Extending the Solver.