Python · import caps
Python API
The same core as the command line and the Studio, through its C library: open and build structures, assign force fields, relax, run, crosslink, analyse, export, and write pipeline steps the Studio runs. Every entry below is the docstring of the installed package (ABI 67).
Setup
The package is plain Python 3 (standard library only; NumPy for pipeline steps) and ships with the program. Put its folder on PYTHONPATH; it finds the CAPS library beside it.
| System | PYTHONPATH |
|---|---|
| macOS | /Applications/CAPS Studio.app/Contents/Resources/data/python |
| Windows | <install folder>\data\python |
| Linux (.deb) | /opt/caps/data/python |
| Linux (tarball) | <unpacked folder>/data/python |
export PYTHONPATH="/Applications/CAPS Studio.app/Contents/Resources/data/python"
python3 -c "import caps; print(caps.abi_version())"CAPS_LIB overrides the library's path (a development build, for instance).
A first script
Grow a natural-rubber cell, type it with OPLS-AA, cure it with a peroxide template, and write LAMMPS and GROMACS inputs. Every call is a method of a Document (one structure with its frames, force field and provenance).
import caps
d = caps.polymer("*CC(C)=CC*", dp=10, chains=6, density=0.6, seed=1) # cis-1,4-polyisoprene
d.relax(max_iterations=300)
d.field.assign("opls2005") # types and charges from the library
print(d.react("peroxide_allylic", cycles=5, per_cycle=4, target=0.3, seed=1))
d.save("nr_xl.data")
d.export_engines("engines", stem="nr", run="npt", temperature=300, steps=5000)The crosslinking tutorial goes through each step, and the LAMMPS fix bond/react export.
Pipeline steps in Python
The Studio's analysis pipeline (and caps pipeline) runs Python steps in a separate process. A step is one function decorated with @step; it reads the frame's particles and writes attributes, tables or new per-particle properties.
import numpy as np
from caps.pipeline import step
@step(name="Backbone height")
def modify(frame, data):
pos = data.particles.positions_unwrapped
data.attributes["MeanZ"] = float(np.mean(pos[:, 2]))The reference below is generated from the installed package's docstrings.
Functions
function
functioncaps.protocol_text(name: 'str', temperature: 'float' = 300.0, t_max: 'float' = 600.0, pressure: 'float' = 1.0, p_max: 'float' = 49346.2, time_scale: 'float' = 1.0, cycles: 'int' = 3, t_low: 'float' = 300.0, t_high: 'float' = 600.0, ramp_ps: 'float' = 50.0, hold_ps: 'float' = 50.0) -> 'str'
functioncaps.water_models() -> 'list'
functioncaps.open(path: 'str', topology: 'Optional[str]' = None, first: 'int' = 0, last: 'Optional[int]' = None, stride: 'int' = 1) -> 'Document'
functioncaps.pack(molecules=None, box=30.0, tolerance: 'float' = 2.0, seed: 'int' = 1, density: 'Optional[float]' = None, inp: 'Optional[str]' = None, forcefield: 'Optional[str]' = None, relax: 'bool' = False, base_dir: 'Optional[str]' = None) -> 'Document'
functioncaps.potentials() -> 'list'
functioncaps.current() -> 'Document'
functioncaps.hand_back(doc: "'Document'") -> 'str'
functioncaps.import_file(path: 'str', bonds: 'str' = 'perceive', tolerance: 'float' = 0.45, bond_orders: 'bool' = True, split: 'bool' = True, unwrap: 'bool' = True, use_cell: 'bool' = True, topology: 'Optional[str]' = None) -> 'Document'
functioncaps.import_preview(path: 'str', **options) -> 'dict'
functioncaps.run(recipe, out_dir: 'str' = '.', seed: 'Optional[int]' = None, threads: 'int' = 0, progress=None, base_dir: 'Optional[str]' = None) -> 'Document'
functioncaps.polymer(smiles, dp: 'int' = 20, chains: 'int' = 1, tacticity: 'str' = 'atactic', seed: 'int' = 1, density: 'Optional[float]' = None, forcefield: 'Optional[str]' = None, relax: 'bool' = False, sequence: 'str' = 'homopolymer', trials: 'int' = 120, blocks: 'Optional[list]' = None, weights: 'Optional[list]' = None, pattern: 'str' = '', r1: 'Optional[float]' = None, r2: 'Optional[float]' = None, pm: 'Optional[float]' = None, p_mr: 'Optional[float]' = None, p_rm: 'Optional[float]' = None, lengths: 'Optional[dict]' = None, chain_dp: 'Optional[list]' = None, architecture: 'str' = 'linear', arms: 'Optional[int]' = None, arm_dp: 'Optional[int]' = None, spacing: 'Optional[int]' = None, branch_probability: 'Optional[float]' = None, generations: 'Optional[int]' = None, region: 'Optional[dict]' = None, method: 'str' = 'trials', method_temperature: 'float' = 450.0, orientation: 'Optional[dict]' = None, lookahead: 'int' = 1, head_cap: 'str' = '', tail_cap: 'str' = '') -> 'Document'
functioncaps.table(cells, properties) -> 'Table'
functioncaps.library() -> 'C.CDLL'
functioncaps.abi_version() -> 'int'
functioncaps.space_groups() -> 'list'
functioncaps.provenance_file(path: 'str') -> 'dict'
functioncaps.compare_provenance(a: 'dict', b: 'dict') -> 'dict'
functioncaps.bibtex(manifest: 'dict') -> 'str'
functioncaps.methods(manifest: 'dict', replicas: 'Optional[list]' = None) -> 'dict'
functioncaps.chain_lengths(distribution: 'str' = 'schulz-zimm', nn: 'float' = 40, pdi: 'float' = 1.1, count: 'int' = 20, seed: 'int' = 2026, m0: 'float' = 104.15, best_of: 'int' = 1) -> 'dict'
functioncaps.bead_templates(forcefield: 'str') -> 'dict'
functioncaps.copolymer_model(r1: 'float', r2: 'float', f1: 'float', dp: 'int' = 80, seed: 'int' = 1) -> 'dict'
functioncaps.stereo(pm: 'float' = 0.5, p_mr: 'Optional[float]' = None, p_rm: 'Optional[float]' = None, dyads: 'str' = '', measured: 'Optional[list]' = None) -> 'dict'
functioncaps.blend_phase(na: 'float', nb: 'float', a: 'float', b: 'float', t: 'float' = 300.0) -> 'dict'
functioncaps.solvent_chi(delta_polymer: 'float', solvents: 'list', t: 'float' = 298.15) -> 'list'
functioncaps.ewald_params(cutoff: 'float' = 12.0, tolerance: 'float' = 1e-05, spacing: 'float' = 1.2, order: 'int' = 4, edges: 'Optional[list]' = None, doc: "Optional['Document']" = None) -> 'dict'
functioncaps.chi_by_md(polymer, solvent: 'Optional[str]' = None, polymer_b=None, dp: 'int' = 10, chains: 'int' = 6, temperature: 'float' = 300.0, eq_ps: 'float' = 200.0, prod_ps: 'float' = 300.0, seed: 'int' = 1) -> 'dict'
functioncaps.chi_by_contacts(a: 'str', b: 'str', forcefield: 'Optional[str]' = 'gaff2', samples: 'int' = 1000000, pack_trials: 'int' = 5000, temperatures=(250, 275, 300, 325, 350, 375, 400), t: 'float' = 298.15, seed: 'int' = 1) -> 'dict'
functioncaps.reaction_templates() -> 'list'
functioncaps.reaction_template(name: 'str') -> 'str'
functioncaps.bond_react_template(pre: 'str', post: 'str', map: 'str', masses_from: 'str' = '', name: 'str' = '', capture: 'float' = 0.0) -> 'dict'
functioncaps.reaction_library(path: 'str' = '') -> 'list'
caps.Document
A structure or trajectory: frames, a current frame, and everything CAPS does to it.
methodDocument.add_hydrogens(self) -> 'int'
methodDocument.adsorption(self, adsorbates, cycles: 'int' = 3, steps: 'int' = 20000, t_high: 'float' = 10000.0, t_low: 'float' = 100.0, region: 'str' = 'cell', cutoff: 'float' = 12.0, coulomb: 'bool' = True, keep: 'int' = 10, seed: 'int' = 1) -> 'dict'
methodDocument.analyze(self, properties='density', first: 'int' = 0, last: 'int' = -1, stride: 'int' = 1, blocks: 'int' = 5, threads: 'int' = 0, **options) -> 'list'
methodDocument.animate_mode(self, mode: 'int', amplitude: 'float' = 0.3, frames: 'int' = 20, selection: 'bool' = False) -> 'dict'
methodDocument.atom(self, i: 'int') -> 'dict'
methodDocument.atom_labels(self, kind: 'str' = 'element') -> 'list'
methodDocument.atom_states(self) -> 'list'
propertyDocument.atoms
methodDocument.backmap_kg(self, unit: 'str', name: 'str' = 'unit', relax: 'bool' = True, seed: 'int' = 1) -> "'Document'"
methodDocument.bond_labels(self, kind: 'str' = 'length') -> 'list'
methodDocument.bond_react(self, templates, directory: 'str', **options) -> 'dict'
methodDocument.bond_rules(self, rules: 'list', apply: 'bool' = False) -> 'dict'
methodDocument.cg_map(self, scheme: 'str' = 'unit', per_bead: 'int' = 3, temperature: 'float' = 300.0, ibi: 'Optional[dict]' = None, rules=None) -> "'Document'"
methodDocument.checks(self) -> 'list'
methodDocument.close(self) -> 'None'
methodDocument.conformers(self, trials: 'int' = 50, method: 'str' = 'torsions', selection: 'bool' = False, window: 'float' = 10.0, rmsd: 'float' = 0.5, temperature: 'float' = 298.15, seed: 'int' = 1) -> 'dict'
methodDocument.convert(self, to: 'str' = 'united-atom', per_bead: 'int' = 5) -> "'Document'"
methodDocument.edit(self, **op) -> 'dict'
methodDocument.energy(self) -> 'dict'
methodDocument.equilibrate(self, protocol: 'str' = 'larsen21', temperature: 'float' = 300.0, t_max: 'float' = 600.0, pressure: 'float' = 1.0, p_max: 'float' = 49346.2, time_scale: 'float' = 1.0, cycles: 'int' = 3, t_low: 'float' = 300.0, t_high: 'float' = 600.0, ramp_ps: 'float' = 50.0, hold_ps: 'float' = 50.0, dt: 'float' = 1.0, thermostat: 'str' = 'bussi', barostat: 'str' = 'crescale', tau_t: 'float' = 100.0, tau_p: 'float' = 1000.0, seed: 'int' = 1, cutoff: 'float' = 10.0, coulomb: 'bool' = True, frame_ps: 'float' = 10.0, thermo_ps: 'float' = 0.5, until_converged: 'bool' = False, block_ps: 'float' = 20.0, max_blocks: 'int' = 20, constraints: 'str' = 'none', constraint_solver: 'str' = 'shake', tail: 'bool' = True) -> 'bool'
methodDocument.export_engines(self, folder: 'str', stem: 'str' = 'system', lammps: 'bool' = True, gromacs: 'bool' = True, run: 'str' = 'check', **opts) -> 'dict'
methodDocument.export_scene(self, path: 'str', format: 'str' = '', width: 'int' = 1280, height: 'int' = 800, background: 'str' = 'white', style: 'str' = 'ball_and_stick', colour: 'str' = 'molecule', yaw: 'float' = 0.55, pitch: 'float' = 0.4, zoom: 'float' = 1.0) -> 'dict'
methodDocument.fragment_smiles(self, atoms=None) -> 'str'
propertyDocument.frames
methodDocument.ghost(self, atoms=None) -> 'int'
methodDocument.hide(self, atoms=None) -> 'int'
methodDocument.hold(self, molecule: 'int' = 0, atoms: 'Optional[list]' = None) -> 'None'
methodDocument.hydrogen_plan(self) -> 'dict'
methodDocument.insert(self, smiles: 'str', count: 'int', tolerance: 'float' = 2.0, seed: 'int' = 1) -> 'str'
methodDocument.interactions(self, **options) -> 'dict'
methodDocument.layers(self) -> 'dict'
methodDocument.lock(self, atoms=None, locked: 'bool' = True) -> 'int'
methodDocument.md(self, steps: 'int' = 10000, dt: 'float' = 1.0, temperature: 'float' = 300.0, thermostat: 'str' = 'bussi', barostat: 'str' = 'none', pressure: 'float' = 1.0, seed: 'int' = 1, frame_every: 'int' = 1000, thermo_every: 'int' = 100, cutoff: 'float' = 10.0, respa: 'int' = 1, constraints: 'str' = 'none', constraint_solver: 'str' = 'shake', couple_axes: 'str' = '', efield: 'tuple' = (0.0, 0.0, 0.0), full_shape: 'bool' = False) -> 'str'
methodDocument.normal_modes(self, temperature: 'float' = 298.15) -> 'dict'
methodDocument.pair_histograms(self, lo: 'float' = 0.8, hi: 'float' = 3.2, bin: 'float' = 0.04) -> 'list'
methodDocument.positions(self) -> 'list'
methodDocument.probe(self, kind: 'str', atoms) -> 'dict'
methodDocument.probe_series(self, a: 'tuple', b: 'Optional[tuple]' = None, measure: 'str' = 'distance') -> 'list'
propertyDocument.provenance
methodDocument.query(self, query: 'str', op: 'str' = 'replace') -> 'int'
methodDocument.react(self, templates, cycles: 'int' = 50, per_cycle: 'int' = 5, target: 'float' = 1.0, capture: 'float' = 0.0, relax: 'bool' = True, relax_iterations: 'int' = 500, md_ps: 'float' = 0.0, temperature: 'float' = 500.0, cutoff: 'float' = 10.0, seed: 'int' = 1, during_md: 'bool' = False, between_chains: 'bool' = False, keep_byproducts: 'bool' = False, weights=None, auto_capture: 'bool' = False, capture_max: 'float' = 0.0, capture_step: 'float' = 0.0, crosslinks=None, default_field: 'bool' = False, sites_per_chain: 'int' = 0) -> 'str'
methodDocument.react_sites(self, templates) -> 'dict'
methodDocument.react_summary(self) -> 'dict'
methodDocument.relax(self, ftol: 'float' = 0.5, method: 'str' = 'lbfgs', max_iterations: 'int' = 5000, density: 'float' = 0.0, pushoff: 'bool' = True, box: 'bool' = False, pressure: 'float' = 1.0, cutoff: 'float' = 10.0, coulomb: 'bool' = True, threads: 'int' = 0, restraints: 'Optional[list]' = None, box_axes: 'str' = '', pushoff_md_ps: 'float' = 0.0, pushoff_cap: 'float' = 0.0, pushoff_temperature: 'float' = 0.0, etol: 'float' = 0.0, pressure_tol: 'float' = 0.0) -> 'int'
methodDocument.render(self, path: 'str', width: 'int' = 1280, height: 'int' = 800, background: 'str' = 'white', style: 'str' = 'ball_and_stick', colour: 'str' = 'molecule', yaw: 'float' = 0.55, pitch: 'float' = 0.4, zoom: 'float' = 1.0, engine: 'str' = 'raster', bits: 'int' = 8, samples: 'int' = 64, shadows: 'bool' = True, occlusion: 'bool' = True, depth_of_field: 'float' = 0.0, outlines: 'bool' = False, dpi: 'float' = 0) -> 'None'
methodDocument.resolution(self, per_bead: 'int' = 5) -> 'dict'
methodDocument.rigid(self, molecules: 'str' = '') -> 'int'
methodDocument.save(self, path: 'str') -> 'None'
methodDocument.save_gromacs(self, stem: 'str') -> 'str'
methodDocument.save_trajectory(self, path: 'str') -> 'None'
methodDocument.scene(self, hydrogens: 'bool' = True, max_atoms: 'int' = 60000) -> 'dict'
methodDocument.select(self, mode: 'str', pattern: 'str' = '', op: 'str' = 'replace', **kw) -> 'int'
methodDocument.selection(self) -> 'list'
methodDocument.series(self, molecule: 'int' = 0, dt_fs: 'float' = 1.0, log: 'str' = '') -> 'dict'
methodDocument.set_frame(self, k: 'int') -> 'None'
methodDocument.show(self, atoms=None) -> 'int'
methodDocument.sorption(self, sorbate: 'str' = 'O=C=O', pressures_kpa=(), temperature: 'float' = 300.0, insertions: 'int' = 100000, steps: 'int' = 200000, mixture=None, map_grid: 'int' = 0, cutoff: 'float' = 12.0, coulomb: 'bool' = True, seed: 'int' = 1) -> 'dict'
methodDocument.summary(self) -> 'dict'
methodDocument.tacticity(self) -> 'dict'
methodDocument.tag(self, name: 'str', atoms=None, colour: 'str' = '', op: 'str' = 'set') -> 'int'
propertyDocument.tags
methodDocument.torsion_scan(self, atoms, step: 'float' = 15, relax: 'bool' = False, forcefield: 'str' = 'auto') -> 'dict'
methodDocument.undo(self, redo: 'bool' = False) -> 'None'
methodDocument.view(self, style: 'str' = 'ball-and-stick', width: 'int' = 640, height: 'int' = 400, hydrogens: 'bool' = True, max_atoms: 'int' = 60000, cell: 'Optional[bool]' = None)
caps.build
The builders: each returns a new Document.