LAMMPS (Large-scale Atomic/Molecular Massively Parallel Simulator) compiled to WebAssembly for use in web browsers and Node.js environments.
npm install lammpsimport { LammpsWeb } from "lammps";
// Create a LAMMPS instance
const lammps = await LammpsWeb.create({
print: (msg) => console.log(msg),
printErr: (msg) => console.error(msg),
postStepCallback: () => {
// Called after each simulation step
// Return false to continue, true to pause
console.log("Step:", lammps.getTimesteps());
return false;
},
});
// Run LAMMPS commands
lammps.runScript(`
units lj
atom_style atomic
lattice fcc 0.8442
region box block 0 4 0 4 0 4
create_box 1 box
create_atoms 1 box
`);
// Get system information
console.log("Number of atoms:", lammps.getNumAtoms());
console.log("Timesteps:", lammps.getTimesteps());
// Control simulation
lammps.step();For running LAMMPS in a background thread without blocking the main UI, use the Web Worker wrapper with SharedArrayBuffer support.
import { LammpsWorker } from "lammps/worker";
// Create a worker instance
const lammps = await LammpsWorker.create({
workerUrl: './node_modules/lammps/dist/worker/worker-entry.js'
});
// Listen for log messages
lammps.on('log', (msg) => console.log(msg));
// Listen for step callbacks
lammps.on('step', (timestep) => {
console.log('Current timestep:', timestep);
// Update UI here - main thread is not blocked!
});
// Run commands (async)
await lammps.runScript(`
units lj
atom_style atomic
lattice fcc 0.8442
region box block 0 10 0 10 0 10
create_box 1 box
create_atoms 1 box
`);
// Zero-copy access to positions via SharedArrayBuffer
await lammps.updatePositions();
const positions = lammps.getPositions(); // Float64Array view into SAB
console.log('First atom:', positions[0], positions[1], positions[2]);- Non-blocking: Simulations run in background thread, UI stays responsive
- Zero-copy data: SharedArrayBuffer provides direct memory access to positions
- Event-based: Stream logs and receive callbacks without polling
- Full API: All LAMMPS commands available through async interface
SharedArrayBuffer requires specific HTTP headers. Use the included server:
npm run serveOr set these headers on your server:
Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp
const lammps = await LammpsWorker.create({
workerUrl?: string, // Path to worker script
initialCapacity?: number, // Initial atom capacity (default: 100000)
print?: (msg: string) => void,
printErr?: (msg: string) => void
});// Log messages from LAMMPS
lammps.on('log', (message: string) => {
console.log('LAMMPS:', message);
});
// Error messages
lammps.on('error', (message: string) => {
console.error('Error:', message);
});
// Step callbacks
lammps.on('step', (timestep: number) => {
updateProgressBar(timestep);
});All commands return Promises:
await lammps.runScript('run 1000');
await lammps.step();
await lammps.pause();
await lammps.resume();
await lammps.cancel();// Request position update
await lammps.updatePositions();
// Get direct view into SharedArrayBuffer
const positions = lammps.getPositions(); // Float64Array
// No copying! Direct access to atom positions
for (let i = 0; i < lammps.getNumAtoms(); i++) {
const x = positions[i * 3 + 0];
const y = positions[i * 3 + 1];
const z = positions[i * 3 + 2];
// Render atom at (x, y, z)
}Access atom count and timestep from SharedArrayBuffer (no async needed):
const numAtoms = lammps.getNumAtoms(); // Instant access
const timestep = lammps.getTimesteps(); // Instant accessimport { LammpsWorker } from "lammps/worker";
async function runSimulation() {
// Create worker
const lammps = await LammpsWorker.create();
// Set up event handlers
lammps.on('log', (msg) => console.log(msg));
lammps.on('step', (timestep) => {
document.getElementById('progress').textContent =
`Step ${timestep}/${totalSteps}`;
});
// Run simulation
await lammps.runScript(`
units lj
atom_style atomic
lattice fcc 0.8442
region box block 0 20 0 20 0 20
create_box 1 box
create_atoms 1 box
mass 1 1.0
velocity all create 1.0 87287
pair_style lj/cut 2.5
pair_coeff 1 1 1.0 1.0 2.5
fix 1 all nve
run 10000
`);
// Get final positions
await lammps.updatePositions();
const positions = lammps.getPositions();
console.log('Simulation complete!');
console.log('Total atoms:', lammps.getNumAtoms());
console.log('Final timestep:', lammps.getTimesteps());
// Cleanup
lammps.terminate();
}
runSimulation();The worker supports synchronous pause/resume using atomic operations:
// Start long simulation
const simulationPromise = lammps.runScript('run 100000');
// Pause after 2 seconds
setTimeout(() => lammps.pause(), 2000);
// Resume after 4 seconds
setTimeout(() => lammps.resume(), 4000);
await simulationPromise;The main class for interacting with LAMMPS.
Creates a new LAMMPS instance.
Parameters:
options.print?: (msg: string) => void- Callback for standard outputoptions.printErr?: (msg: string) => void- Callback for error outputoptions.postStepCallback?: () => boolean- Callback invoked after each simulation step. Returnfalseto continue simulation,trueto pause.
Returns: Promise<LammpsWeb>
Example:
const lammps = await LammpsWeb.create({
print: (msg) => console.log(msg),
printErr: (msg) => console.error(msg),
postStepCallback: () => {
// Called after each simulation step
// Return false to continue, true to pause
return false;
},
});runScript(script: string): void- Execute LAMMPS commands (single or multi-line)runFile(path: string): void- Execute commands from a filestart(): boolean- Start the simulationstop(): boolean- Stop the simulationstep(): void- Advance simulation by one timestepsetPaused(paused: boolean): void- Pause/unpause the simulationcancel(): void- Cancel the current simulation
getNumAtoms(): number- Get the number of atoms in the systemgetTimesteps(): number- Get the current timestepgetRunTimesteps(): number- Get timesteps in current rungetRunTotalTimesteps(): number- Get total timesteps to rungetTimestepsPerSecond(): number- Get simulation performancegetIsRunning(): boolean- Check if simulation is runninggetMemoryUsage(): number- Get memory usage in bytes
getCompute(name: string): LMPModifier- Get a compute by namegetComputeNames(): CPPArray<string>- Get all compute namesgetFix(name: string): LMPModifier- Get a fix by namegetFixNames(): CPPArray<string>- Get all fix namesgetVariable(name: string): LMPModifier- Get a variable by namegetVariableNames(): CPPArray<string>- Get all variable namessyncComputes(): void- Synchronize all computessyncFixes(): void- Synchronize all fixessyncVariables(): void- Synchronize all variables
These methods provide pointers to LAMMPS internal data structures for high-performance access:
getPositionsPointer(): number- Get pointer to atom positionsgetIdPointer(): number- Get pointer to atom IDsgetTypePointer(): number- Get pointer to atom typesgetCellMatrixPointer(): number- Get pointer to cell matrixgetOrigoPointer(): number- Get pointer to origingetBondsPosition1Pointer(): number- Get pointer to bond positions (atom 1)getBondsPosition2Pointer(): number- Get pointer to bond positions (atom 2)getBondsDistanceMapPointer(): number- Get pointer to bond distance map
computeBonds(): number- Compute bonds in the systemcomputeParticles(): number- Compute particle datasetSyncFrequency(every: number): void- Set synchronization frequencysetBuildNeighborlist(build: boolean): void- Enable/disable neighbor list buildinggetErrorMessage(): string- Get last error messagegetLastCommand(): string- Get last executed command
For advanced users who need direct access to the underlying WASM module:
import { createModule } from "lammps";
const Module = await createModule({
print: (msg) => console.log(msg),
printErr: (msg) => console.error(msg),
});
// Access the raw LAMMPS instance
const lammps = new Module.LAMMPSWeb();
// Access WASM heap
const positions = Module.HEAPF64.subarray(
lammps.getPositionsPointer() / 8,
lammps.getPositionsPointer() / 8 + lammps.getNumAtoms() * 3
);This package includes full TypeScript type definitions. All types are exported for your convenience:
import type {
LammpsWeb,
LMPModifier,
CPPArray,
Compute,
Fix,
Variable,
Data1D,
ModifierType,
} from "lammps";LAMMPS WASM includes an in-memory file system. You can write files to it before running simulations:
import { createModule, LammpsWeb } from "lammps";
const lammps = await LammpsWeb.create();
// Access the module to use the file system
const Module = await createModule({});
// Write a file to the virtual file system
Module.FS.writeFile("/input.lammps", `
units lj
atom_style atomic
lattice fcc 0.8442
region box block 0 4 0 4 0 4
create_box 1 box
create_atoms 1 box
`);
// Run the file
lammps.runFile("/input.lammps");import { LammpsWeb } from "lammps";
const lammps = await LammpsWeb.create({
print: (msg) => console.log(msg),
});
// Setup and run simulation
lammps.runScript(`
units lj
atom_style atomic
lattice fcc 0.8442
region box block 0 10 0 10 0 10
create_box 1 box
create_atoms 1 box
mass 1 1.0
pair_style lj/cut 2.5
pair_coeff 1 1 1.0 1.0 2.5
run 1000
`);
console.log(`Simulated ${lammps.getNumAtoms()} atoms`);import { LammpsWeb } from "lammps";
const lammps = await LammpsWeb.create();
// Setup system and define computes
lammps.runScript(`
compute myTemp all temp
compute myPE all pe
`);
// Sync computes
lammps.syncComputes();
// Get compute data
const temp = lammps.getCompute("myTemp");
console.log("Temperature:", temp.getScalarValue());
const pe = lammps.getCompute("myPE");
console.log("Potential Energy:", pe.getScalarValue());Monitor your simulation progress or update UI by using the postStepCallback:
import { LammpsWeb } from "lammps";
let stepCount = 0;
const lammps = await LammpsWeb.create({
postStepCallback: () => {
stepCount++;
// Update progress every 100 steps
if (stepCount % 100 === 0) {
console.log(`Completed ${stepCount} steps`);
console.log(`Current timestep: ${lammps.getTimesteps()}`);
console.log(`Atoms: ${lammps.getNumAtoms()}`);
}
// Return false to continue, true to pause
// For example, pause after 1000 steps:
if (stepCount >= 1000) {
console.log("Reached 1000 steps, pausing...");
return true;
}
return false;
},
});
// Setup and run simulation
lammps.runScript(`
units lj
atom_style atomic
lattice fcc 0.8442
region box block 0 10 0 10 0 10
create_box 1 box
create_atoms 1 box
run 2000
`);If you want to build the WASM module from source:
# Install Emscripten SDK
# Set EMSDK_PATH environment variable
# Build LAMMPS WASM
cd ../cpp
python build.py
# Build the package
cd ../package
npm install
npm run buildGPL-2.0
This package is part of the Atomify project and wraps LAMMPS compiled to WebAssembly.
LAMMPS is developed by Sandia National Laboratories.