mcpy is a Python package designed to run atomistic Monte Carlo simulations. It provides tools for performing Grand Canonical Monte Carlo (GCMC) simulations using the Atomic Simulation Environment (ASE) and other dependencies.
- Basin Hopping, Canonical & Grand Canonical Monte Carlo simulations
- Molecular adsorbates: whole-molecule insertion/deletion and rigid
translate+rotate displacement moves (O2, H2O, CO, NH3, any ASE-buildable
template), with per-atom
molecule_idbookkeeping that survives rollback, trajectories, and restarts — cross-validated against LAMMPSfix gcmc(seebenchmark/README.md) - Atomic and molecular species can coexist in one simulation (e.g. dissociative O at mu_O = mu_O2/2 alongside molecular O2)
- Integration with ASE for atomic simulations
- Support for MACE calculator potential and other calculators
- Optional NVIDIA Alchemi backend (
nvalchemi-toolkit) for GPU-native MACE evaluation and FIRE relaxation — 3x speedup - Configurable simulation parameters and logging
To install the mcpy package, ensure you have Python 3.11 or higher and run the following commands:
pip install .Alternatively, you can install the package in editable mode:
pip install -e .To use the MACE calculators (and run the bundled examples), add the mace extra:
pip install -e .[mace]For GPU-native MACE evaluation on systems with ≥500 atoms, install the optional
alchemi extra:
pip install -e .[alchemi]This pulls in nvalchemi-toolkit[mace]. Requires a CUDA-enabled PyTorch build.
See NVALCHEMI_NOTES.md for tuning details (keep the defaults
compile_model=True and dt=1.0; compile costs a one-time warmup and then
speeds up GCMC even though the atom count varies).
GCMC insertions/deletions change the atom count every accepted move, so each relaxation allocates differently sized tensors. PyTorch's CUDA caching allocator reserves a fresh block-set per size and pools it, so reserved GPU memory drifts far above the live footprint over a long run (live stays ~model-sized; reserved can climb to the card limit and cause spurious OOM).
Launch long runs with expandable segments, which grows one segment in place instead of a pool per size:
PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True python your_run.pyThis keeps reserved memory near the true per-step peak; live usage is only ever a small model-sized footprint.
mpi4py is not pulled in automatically — install it with conda:
conda install mpi4pyCore:
ase>=3.23.0
Optional:
mace-torch>=0.3.9— MACE calculators (install via.[mace])nvalchemi-toolkit[mace]>=0.1.0— GPU-native MACE (install via.[alchemi])mpi4py>=4.0.3— replica exchange (install via conda)
Here is an example of how to use the mcpy package to run a GCMC simulation:
from ase.cluster import Octahedron
from mace.calculators import mace_mp
from mcpy.moves import DeletionMove
from mcpy.moves import InsertionMove
from mcpy.moves.move_selector import MoveSelector
from mcpy.ensembles.grand_canonical_ensemble import GrandCanonicalEnsemble
from mcpy.calculators import MACE_F_Calculator
# For large systems on GPU, use AlchemiFCalculator instead:
# from mcpy.calculators import AlchemiFCalculator
from mcpy.cell import SphericalCell
atoms = Octahedron('Ag', 6, 1)
scell = SphericalCell(atoms, vacuum=3, species_radii={'Ag': 2.947, 'O' : 0},
mc_sample_points=100_000)
calculator = mace_mp(device='cuda')
species = ['O']
move_list = [[1, 1],
[DeletionMove(scell,
species=['O'],
seed=43215423143),
InsertionMove(scell,
species=['O'],
min_insert=0.5,
seed=3675437856)]]
move_selector = MoveSelector(*move_list)
mus = {'Ag': -2.99, 'O': -4.91}
delta_mu_O = -0.5
mus['O'] += delta_mu_O
T = 500
gcmc = GrandCanonicalEnsemble(
atoms=atoms,
cells=[scell],
calculator=calculator,
mu=mus,
units_type='metal',
species=species,
temperature=T,
move_selector=move_selector)
gcmc.run(1000000)Whole molecules are exchanged with the reservoir by passing an ASE template:
the chemical potential is the full molecular chemical potential
(mu = E(molecule) + delta_mu; orientations are sampled uniformly, so the
rotational partition function is absorbed into mu — see
docs/gcmc_acceptance_convention.rst).
from ase.build import molecule
from mcpy.moves import (MoleculeInsertionMove, MoleculeDeletionMove,
MoleculeDisplacementMove)
co = molecule('CO')
e_co = calculator.get_potential_energy(molecule('CO', cell=[20.0] * 3))
moves = MoveSelector(
[2, 2, 1],
[MoleculeInsertionMove(scell, co, 'CO', seed=1, min_insert=1.3),
MoleculeDeletionMove(scell, co, 'CO', seed=2),
MoleculeDisplacementMove(scell, co, 'CO', seed=3,
max_displacement=0.6, max_angle=0.6)],
)
gcmc = GrandCanonicalEnsemble(
atoms=atoms, cells=[scell], calculator=calculator,
mu={'CO': e_co - 0.65},
molecules={'CO': co}, # registers the molecular species
units_type='metal', species=[], temperature=400.0,
move_selector=moves)Runnable examples: examples/gcmc_molecule_mace.py (O2 on Ag(111); any g2 molecule via --molecule) and
examples/re_gcmc_co_cupd_batched.py (CO on a CuPd nanoparticle with batched
replica exchange and a phase diagram). The notebooks in notebooks/ walk
through the machinery step by step.
Contributions are welcome! See CONTRIBUTING.md for development setup, how to run the tests, and how to submit changes. Bug reports and feature requests go to the issue tracker.
Run the tests with:
pip install -e ".[test]"
pytest tests/This project is licensed under the MIT License. See the LICENSE file for details.