Skip to content

microsolvator.workflow

solvate_trajectory — one-call interface

from microsolvator.workflow import solvate_trajectory
solvate_trajectory(
    reaction_images: list[Atoms],
    solvent: Atoms,
    *,
    calc,                            # calculator instance or factory
    nsolv: int = 5,
    solvent_density: float = 1.0,
    ts_index: int | None = None,
    config: SolvationWorkflowConfig | None = None,
    **kwargs,
) -> SolvatedTrajectoryResult
Parameter Description
reaction_images NEB / string-method images
solvent One solvent molecule
calc Calculator instance (deep-copied) or zero-arg factory callable
nsolv Number of microsolvation-shell molecules (ignored when config is given)
solvent_density Target bulk density in g/cm³ (ignored when config is given)
ts_index TS image index; Nonelen(images) // 2
config Full SolvationWorkflowConfig for fine-grained control
**kwargs Forwarded to SolvatedTrajectoryBuilder.build (e.g. log_callback)
# Minimal usage
result = solvate_trajectory(images, water, calc=lambda: XTB(method="GFN-FF"))

# With custom config
result = solvate_trajectory(images, water, calc=lambda: XTB(method="GFN-FF"), config=my_config)

SolvatedTrajectoryBuilder

from microsolvator.workflow import SolvatedTrajectoryBuilder

build — full pipeline

SolvatedTrajectoryBuilder.build(
    *,
    reaction_images: list[Atoms],
    solvent: Atoms,
    config: SolvationWorkflowConfig,
    calc,                            # calculator instance or factory
    log_callback: Callable[[str, Any], None] | None = None,
) -> SolvatedTrajectoryResult
Parameter Description
reaction_images NEB / string-method images
solvent One solvent molecule
config SolvationWorkflowConfig
calc Calculator instance (deep-copied per step) or zero-arg factory callable
log_callback Called at each step: callback(step_name, info)

Backwards compatibility

calculator= is still accepted as an alias for calc=.

Individual steps

# Step 1
SolvatedTrajectoryBuilder.microsolvate_ts(ts_image, solvent, config, **kwargs)
    -> MicrosolvationResult

# Step 2
SolvatedTrajectoryBuilder.pack_solvent_box(cluster, solvent, config, workdir=None)
    -> tuple[Atoms, int]  # (boxed_system, n_bulk_solvent)

# Step 3
SolvatedTrajectoryBuilder.equilibrate(system, n_fixed, calc, config,
                                       traj_path=None, log_callback=None)
    -> Atoms

# Step 4
SolvatedTrajectoryBuilder.swap_and_relax(template, reaction_images, n_solute,
                                          ts_index, calc, config)
    -> list[Atoms]

Steps 3 and 4 also accept calculator= as a backwards-compatible alias for calc=.


Calculator types

The calc parameter accepts two types:

Type Example Behavior
Instance calc=EMT() copy.deepcopy(calc) for each step
Factory calc=lambda: XTB(method="GFN-FF") calc() called for each step

Use a factory for stateful calculators (GPAW, VASP, CP2K, …) that may not survive deep-copy.


SolvationWorkflowConfig

from microsolvator.workflow import SolvationWorkflowConfig
Field Type Default Description
microsolv MicrosolvatorConfig (required) CREST QCG config for Step 1
packmol PackmolConfig PackmolConfig() Packmol config for Step 2
equilibration EquilibrationConfig EquilibrationConfig() MD config for Step 3
relaxation RelaxationConfig RelaxationConfig() Relax config for Step 4
ts_index int \| None None TS image index; Nonelen(images) // 2
working_directory Path \| None None Intermediate files directory
keep_temps bool False Keep auto-generated temp dir

PackmolConfig

from microsolvator.workflow import PackmolConfig
Field Type Default Description
box_margin float 10.0 Å from cluster to box wall
solvent_density float \| None None g/cm³ — auto-compute molecule count
n_bulk_solvent int \| None None Explicit molecule count
min_distance float 2.0 Packmol tolerance (Å)
packmol_executable str \| None None Packmol binary path; None → PATH
retry_margin_increment float 2.0 Å added on each retry
max_retries int 3 Max retries before raising

Provide exactly one of solvent_density or n_bulk_solvent.


EquilibrationConfig

from microsolvator.workflow import EquilibrationConfig
Field Type Default Description
temperature float 300.0 K — NVT/NPT target temperature
nvt_steps int 5000 NVT production steps (Langevin)
npt_steps int 0 NPT steps; 0 skips NPT phase
npt_pfactor float \| None None NPT barostat coupling (eV·fs²/ų); None → 2.2 GPa estimate
timestep float 1.0 fs
friction float 0.01 Langevin friction (1/fs)
heating_schedule list[tuple[float, int]] \| None None [(T_K, steps), …]

MD phases: NVT heating → NPT (optional) → NVT production.


RelaxationConfig

from microsolvator.workflow import RelaxationConfig
Field Type Default Description
method str "optimize" "optimize" (LBFGS), "fire", or "md" (Langevin)
fmax float 0.05 eV/Å convergence threshold
max_steps int 500 Max optimizer steps
md_steps int 200 Steps for method="md"
md_temperature float 300.0 K for method="md"
md_timestep float 0.5 fs for method="md"
md_friction float 0.01 1/fs for method="md"

SolvatedTrajectoryResult

from microsolvator.workflow import SolvatedTrajectoryResult
Attribute Type Description
solvated_images list[Atoms] Final solvated trajectory
microsolvated_ts Atoms CREST cluster (Step 1)
boxed_system Atoms Packmol output with cell (Step 2)
equilibrated_system Atoms MD-equilibrated template (Step 3)
n_solute_atoms int Atoms in one NEB image
n_cluster_atoms int Solute + microsolvation shell atoms
n_total_atoms int Total atoms in solvated box
ts_index int Resolved TS index
config SolvationWorkflowConfig Config used
working_directory Path Where intermediate files were written

Atom ordering in all images: [solute | microsolv_shell | bulk_solvent].


Low-level utilities

from microsolvator.workflow.swap import kabsch_align, swap_solute, relax_interface
from microsolvator.workflow.packmol import PackmolSolvator
from microsolvator.workflow.equilibration import equilibrate
from microsolvator.workflow.utils import (
    estimate_box_size,
    count_solvent_molecules,
    validate_packmol_output,
)
from microsolvator.workflow.builder import _make_calculator