rmc
Reverse Monte Carlo structural refinement: move atoms at random, and keep a move
when it brings the structure's computed G(r), S(Q) or bond-angle distribution
closer to experiment. The engine is C++; rmc drives it from Python, with
coordinates as NumPy arrays and the refinement running with the GIL released.
pip install reverse-monte-carlo
The distribution is reverse-monte-carlo and the import is rmc. Wheels are for
Linux x86-64 (manylinux_2_28, CPython 3.11–3.14) and need an AVX2 CPU; Boost is
linked in statically and oneTBB rides inside the wheel. Elsewhere — Windows
included — build from source (below); Windows is supported and tested, it simply
has no published wheel.
Refine from a configuration
RMCConfig holds the same knobs as the RMC_run command line, validated;
refine builds the engine, runs it and writes the result:
import rmc
config = rmc.RMCConfig(
pdb_path="input.pdb", # or lammps_path / vasp_path
pdf_path="experimental_gr.dat", # and/or sq_path, adf_path
rho0=0.033,
box_override=(20.0, 20.0, 20.0), # or "inf"
steps=100_000,
out_path="refined.vasp", # the extension picks the format
)
engine = rmc.refine(config, chi2_csv="chi2.csv")
print(engine.stats, engine.constraints.error_breakdown())
refine also takes a sampler, a selector and a step_callback.
rmc.refine_ensemble(config, 4) runs four replicas in parallel and keeps the best.
Drive the engine
start = rmc.make_random_amorphous(["Cu", "Zr"], [32, 32], seed=7)
engine = rmc.Engine(start.structure, start.periodic_bc())
engine.build_atomic_groups(0.0, 0.2) # one translation group per atom
pdf = rmc.PairDistributionConstraint()
pdf.set_experimental_data(rmc.read_xy_data("experimental_gr.dat"))
pdf.set_number_density(0.06)
pdf.set_elements(engine.structure) # bind to engine.structure
engine.add_constraint(pdf)
engine.set_sampler(rmc.MetropolisSampler(0.01))
engine.set_track_best()
engine.run(50_000) # releases the GIL
best = engine.best_structure # a copy
curve = engine.constraints[0].concrete().computed
engine.structure.coordinates is an (N, 3) float64 view into the engine,
not a copy; writing into it moves atoms.
| Structures and files | AtomicStructure, read_pdb/write_pdb, read_vasp/write_vasp, read_lammps_data/write_lammps_data, read_structure_by_ext, read_xy_data, save_checkpoint/load_checkpoint |
| Boundary conditions | PeriodicBC(box), InfiniteBC(volume) |
| Constraints | PairDistributionConstraint, PairCorrelationConstraint, StructureFactorConstraint, ReducedStructureFactorConstraint, AngularDistributionConstraint, InterMolecularDistanceConstraint, IntraMolecularDistanceConstraint, CoordinationConstraint, BondConstraint, AngleConstraint, DihedralAngleConstraint, ImproperAngleConstraint, ClusterCorrelationConstraint |
| Moves | TranslationGenerator, RotationGenerator and their axis variants, OrientationGenerator, agitations, swaps, paths, MoveGeneratorCollector, SpeciesSwapGenerator, RemoveGenerator, Langevin and leapfrog (gradient) moves, grouped with Group |
| Acceptance | GreedySampler (default), MetropolisSampler, AnnealingSampler |
| Group selection | RandomSelector (default), WeightedRandomSelector, OrderedSelector, SmartRandomSelector, DirectionalOrderSelector, RecursiveGroupSelector |
| Progress | set_step_callback(fn), Chi2CollectorCallback, PDBSnapshotCallback, HistogramCallback |
Every class and function has a docstring, and the package ships type stubs.
Constraints and moves written in Python
Any object with compute_error(coords, moved) -> float is a constraint, and any
object with generate(coords, indices) is a move:
import numpy as np
class StayNearOrigin:
cost = 0.5 # optional: cheapest run first
def compute_error(self, coords: np.ndarray, moved: np.ndarray) -> float:
return float(np.sum(coords[:, :2] ** 2))
engine.add_constraint(rmc.Constraint(StayNearOrigin()))
rmc.ConstraintProtocol and rmc.MoveGeneratorProtocol list the optional
hooks (rigid, name, modifies_species, rejection_override, ...). Each call
takes the GIL, so a Python constraint costs about a microsecond more per step
than a C++ one.
Ensembles
def make(i: int) -> rmc.Engine:
engine = rmc.Engine(start.structure, start.periodic_bc())
engine.build_atomic_groups(0.0, 0.2, seed=100 + i)
... # constraints
return engine
best = rmc.run_ensemble(make, 4, 20_000) # replicas on threads, best one back
run_ensemble_cooperative shares the best structure between replicas every
sync_every steps.
Analysis
g = rmc.compute_gr(start.structure, start.periodic_bc(), params=rmc.GrParams(r_max=8.0))
adf = rmc.compute_adf(start.structure, start.periodic_bc())
columns = g.as_dict() # {"r", "total", "Cu-Cu", ...}: pandas.DataFrame(columns)
Special quasirandom structures
import numpy as np
from rmc import mcsqs
sqs = mcsqs.enumerate(mcsqs.parse_lattice("rndstr.in"), np.diag([2, 2, 2]), {2: 3.0})
engine = mcsqs.sqs_engine(sqs, sampler=rmc.AnnealingSampler(), seed=7)
engine.run(100_000)
rmc.write_pdb(engine.best_structure, "bestsqs.pdb")
Keeping borrowed data valid
- The engine copies the structure it is given. Bind constraints to
engine.structure, not to the structure you passed in. - Constraints borrow a structure's per-atom arrays. A structure keeps its
atom count once built; setters that would change it raise
ValueError. - Gradient moves point into
engine.constraints. Build them after every constraint is added:engine.build_langevin_groups(...), orrun_ensemble(..., prepare=...).
Every library failure raises a subclass of rmc.RmcError (IoError,
AnalysisError, ConfigError, RandomStructureError, McsqsError).
Building from source
GCC 15 (or MSVC 19.43+) and CMake 3.28+. Boost, oneTBB, Catch2 and spdlog are all fetched when they are not installed:
git clone https://github.com/reach2sayan/ReverseMonteCarlo && cd ReverseMonteCarlo
CXX=g++-15 pip install .
On Windows, from an x64 Native Tools prompt:
set CMAKE_GENERATOR=Ninja
pip install .
For development, the python CMake preset builds the extension in place and runs
the tests; see the repository README.
Metadata
Release files for reverse-monte-carlo 1.0.3
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| reverse_monte_carlo-1.0.3.tar.gz | 326.9 kB | Details |
Built distributions (wheels)
| File | Reset | |||
|---|---|---|---|---|
| reverse_monte_carlo-1.0.3-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl | CPython 3.14 | CPython 3.14 | Linux glibc 2.27+ x86-64, Linux glibc 2.28+ x86-64 | Details |
| reverse_monte_carlo-1.0.3-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl | CPython 3.13 | CPython 3.13 | Linux glibc 2.27+ x86-64, Linux glibc 2.28+ x86-64 | Details |
| reverse_monte_carlo-1.0.3-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl | CPython 3.12 | CPython 3.12 | Linux glibc 2.28+ x86-64, Linux glibc 2.27+ x86-64 | Details |
| reverse_monte_carlo-1.0.3-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl | CPython 3.11 | CPython 3.11 | Linux glibc 2.28+ x86-64, Linux glibc 2.27+ x86-64 | Details |
Total release size: 10.8 MB
Release files / reverse_monte_carlo-1.0.3.tar.gz
| Download URL | reverse_monte_carlo-1.0.3.tar.gz |
|---|---|
| Size | 326.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
8445beda33032212b3b7591598c6ff5d6692f9e6aa335af211dfb1b8c5f99077
|
|
BLAKE2b-256 checksum How to use checksums |
a41b8983616cfe66d8db23b37574a442c741e8b8e54f1850836782ad82aeee32
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 14, 2026.
Transparency logRelease files / reverse_monte_carlo-1.0.3-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
| Download URL | reverse_monte_carlo-1.0.3-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl |
|---|---|
| Size | 2.6 MB |
| Tags | CPython 3.14 Linux glibc 2.27+ x86-64 Linux glibc 2.28+ x86-64 |
|
SHA-256 checksum How to use checksums |
9655b91d79b2f9c631aacbe9c39950bb4fd5a71cf75e427cc70f537d490abac6
|
|
BLAKE2b-256 checksum How to use checksums |
3463419357b34a02647d1c9ea2db68e9e9eb95b7ae797e5fef06dc2fa7678a56
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 14, 2026.
Transparency logRelease files / reverse_monte_carlo-1.0.3-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
| Download URL | reverse_monte_carlo-1.0.3-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl |
|---|---|
| Size | 2.6 MB |
| Tags | CPython 3.13 Linux glibc 2.27+ x86-64 Linux glibc 2.28+ x86-64 |
|
SHA-256 checksum How to use checksums |
137e89b3d0d8fac49fcd554c8dfe50a063ab02eb14ff7672cf628a4bb2ca77f7
|
|
BLAKE2b-256 checksum How to use checksums |
f61aa679cc56403048ee4c4576400fabd88b2d77c74e75220f1a6f5b937a7555
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 14, 2026.
Transparency logRelease files / reverse_monte_carlo-1.0.3-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
| Download URL | reverse_monte_carlo-1.0.3-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl |
|---|---|
| Size | 2.6 MB |
| Tags | CPython 3.12 Linux glibc 2.27+ x86-64 Linux glibc 2.28+ x86-64 |
|
SHA-256 checksum How to use checksums |
57a1f0eb19550bfb600d90a981f009dbad99daf29d7c2f2debd1178eb7f717f7
|
|
BLAKE2b-256 checksum How to use checksums |
98547ba0085f2c494d1b4c79bf065d9e1f74b59fef123a7cbd9bd9575721d95a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 14, 2026.
Transparency logRelease files / reverse_monte_carlo-1.0.3-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
| Download URL | reverse_monte_carlo-1.0.3-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl |
|---|---|
| Size | 2.6 MB |
| Tags | CPython 3.11 Linux glibc 2.27+ x86-64 Linux glibc 2.28+ x86-64 |
|
SHA-256 checksum How to use checksums |
13d1946959052eb0a4090cf45bcca074f850592ab99c3222eb788da19db9d4d9
|
|
BLAKE2b-256 checksum How to use checksums |
cccf66f74ceebb4abe031100ffd34a4889f2b357e2733b3dd909de36686abb97
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 14, 2026.
Transparency log