├── .codecov.yml ├── .gitignore ├── AUTHORS ├── Cargo.toml ├── Contributing.md ├── LICENSE ├── README.md ├── benches ├── argon.rs ├── data │ ├── argon.pdb │ ├── argon.toml │ ├── nacl.pdb │ ├── nacl.toml │ ├── propane.pdb │ ├── propane.toml │ ├── water.pdb │ └── water.toml ├── nacl.rs ├── propane.rs ├── utils │ └── mod.rs └── water.rs ├── build.rs ├── doc ├── .gitignore ├── KaTeX.html ├── Makefile ├── README.md ├── index.html ├── requirements.txt ├── src │ ├── advanced │ │ ├── index.rst │ │ └── potential │ │ │ ├── external.rst │ │ │ ├── index.rst │ │ │ └── intro.rst │ ├── concepts │ │ ├── index.rst │ │ ├── simulation.rst │ │ ├── system.rst │ │ └── units.rst │ ├── conf.py │ ├── data │ │ ├── argon.toml │ │ ├── argon.xyz │ │ ├── argon.zip │ │ ├── nacl.toml │ │ ├── nacl.xyz │ │ ├── nacl.zip │ │ ├── pack.sh │ │ ├── water-fSCP.toml │ │ ├── water.toml │ │ ├── water.xyz │ │ └── water.zip │ ├── faq.rst │ ├── index.rst │ ├── input │ │ ├── index.rst │ │ ├── input.rst │ │ ├── interactions │ │ │ ├── electrostatic.rst │ │ │ ├── index.rst │ │ │ ├── non_bonded.rst │ │ │ ├── organisation.rst │ │ │ ├── potentials.rst │ │ │ └── restrictions.rst │ │ ├── log.rst │ │ ├── simulations │ │ │ ├── index.rst │ │ │ ├── mc.rst │ │ │ ├── md.rst │ │ │ ├── min.rst │ │ │ └── output.rst │ │ └── systems │ │ │ ├── configuration.rst │ │ │ └── index.rst │ ├── installation.rst │ └── tutorial │ │ ├── argon.rst │ │ ├── index.rst │ │ ├── nacl.rst │ │ └── water.rst ├── static │ └── lumol.css └── templates │ ├── layout.html │ └── sidebar-toc.html ├── examples ├── argon.rs ├── binary.rs ├── custom-potential.rs ├── data │ ├── CO2.pdb │ ├── H2O.pdb │ ├── binary.pdb │ ├── binary.toml │ ├── ethane.xyz │ ├── nacl.toml │ ├── nacl.xyz │ ├── simulation.toml │ ├── spce.xyz │ └── xenon.xyz ├── ethane.toml ├── input.rs ├── minimization.rs ├── nacl.rs └── xenon.rs ├── lumol-core ├── Cargo.toml └── src │ ├── consts.rs │ ├── energy │ ├── computations.rs │ ├── functions.rs │ ├── global │ │ ├── ewald.rs │ │ ├── mod.rs │ │ └── wolf.rs │ ├── mod.rs │ ├── pairs.rs │ └── restrictions.rs │ ├── lib.rs │ ├── math.rs │ ├── sys │ ├── cache.rs │ ├── chfl.rs │ ├── compute.rs │ ├── config │ │ ├── bonding.rs │ │ ├── cells.rs │ │ ├── composition.rs │ │ ├── configuration.rs │ │ ├── connect.rs │ │ ├── mass.rs │ │ ├── mod.rs │ │ ├── molecules.rs │ │ └── particles.rs │ ├── energy.rs │ ├── interactions.rs │ ├── mod.rs │ └── system.rs │ ├── types │ ├── arrays.rs │ ├── complex.rs │ ├── matrix.rs │ ├── mod.rs │ └── vectors.rs │ ├── units.rs │ └── utils │ ├── macros.rs │ ├── mod.rs │ ├── thread_vec.rs │ └── xyz.rs ├── lumol-input ├── Cargo.toml ├── src │ ├── alternator.rs │ ├── error.rs │ ├── extract.rs │ ├── interactions │ │ ├── angles.rs │ │ ├── coulomb.rs │ │ ├── mod.rs │ │ ├── pairs.rs │ │ └── potentials.rs │ ├── lib.rs │ └── simulations │ │ ├── logging.rs │ │ ├── mc.rs │ │ ├── md.rs │ │ ├── min.rs │ │ ├── mod.rs │ │ ├── outputs.rs │ │ ├── propagator.rs │ │ ├── simulations.rs │ │ └── system.rs └── tests │ ├── README.md │ ├── input.rs │ ├── interactions │ ├── bad │ │ ├── angles.toml │ │ ├── bonds.toml │ │ ├── born.toml │ │ ├── buckingham.toml │ │ ├── charges.toml │ │ ├── cos-harmonic.toml │ │ ├── coulomb.toml │ │ ├── dihedrals.toml │ │ ├── gaussian.toml │ │ ├── harmonic.toml │ │ ├── lj.toml │ │ ├── mie.toml │ │ ├── morse.toml │ │ ├── pairs.toml │ │ ├── torsion.toml │ │ └── version.toml │ └── good │ │ ├── angles.toml │ │ ├── bonds.toml │ │ ├── dihedrals.toml │ │ ├── ewald.toml │ │ ├── pairs.toml │ │ └── wolf.toml │ └── simulation │ ├── CO2.xyz │ ├── bad │ ├── controls.toml │ ├── integrator.toml │ ├── log.toml │ ├── mc-acceptance.toml │ ├── mc-move.toml │ ├── mc-update-frequency.toml │ ├── mc.toml │ ├── md.toml │ ├── minimization.toml │ ├── outputs.toml │ ├── simulations.toml │ ├── system.toml │ ├── thermostat.toml │ └── version.toml │ └── good │ ├── logging.toml │ ├── mc.toml │ ├── md-1.toml │ ├── md-2.toml │ ├── md-3.toml │ ├── md-4.toml │ ├── md.toml │ ├── min.toml │ ├── potentials.toml │ └── system.toml ├── lumol-sim ├── Cargo.toml ├── src │ ├── lib.rs │ ├── mc │ │ ├── mod.rs │ │ ├── monte_carlo.rs │ │ └── moves │ │ │ ├── mod.rs │ │ │ ├── resize.rs │ │ │ ├── rotate.rs │ │ │ └── translate.rs │ ├── md │ │ ├── controls.rs │ │ ├── integrators.rs │ │ ├── mod.rs │ │ ├── molecular_dynamics.rs │ │ └── thermostats.rs │ ├── min │ │ ├── minimization.rs │ │ ├── mod.rs │ │ └── steepest_descent.rs │ ├── output │ │ ├── cell.rs │ │ ├── custom.rs │ │ ├── energy.rs │ │ ├── forces.rs │ │ ├── mod.rs │ │ ├── properties.rs │ │ ├── stress.rs │ │ ├── tests.rs │ │ └── trajectory.rs │ ├── propagator.rs │ ├── simulations.rs │ └── velocities.rs └── tests │ └── thermostats.rs ├── rustfmt.toml ├── scripts ├── ci │ ├── check-whitespaces.py │ ├── generate-docs.sh │ ├── install-travis.sh │ ├── list-test-executables.py │ └── setup-travis.sh └── requirements.txt ├── src ├── input.rs ├── lib.rs ├── main.rs └── sim.rs ├── tests ├── data │ ├── mc-argon │ │ ├── argon.pdb │ │ └── npt.toml │ ├── mc-ethane │ │ ├── ethane.pdb │ │ ├── ethane.toml │ │ └── npt.toml │ ├── mc-helium │ │ ├── helium.pdb │ │ └── nvt.toml │ ├── mc-water │ │ ├── ewald.toml │ │ ├── npt-ewald.toml │ │ ├── npt-wolf.toml │ │ ├── nvt-ewald.toml │ │ ├── nvt-wolf.toml │ │ ├── water.pdb │ │ ├── water.xyz │ │ └── wolf.toml │ ├── md-butane │ │ ├── butane.toml │ │ ├── butane.xyz │ │ └── nve.toml │ ├── md-helium │ │ ├── helium-gas.pdb │ │ ├── helium.xyz │ │ ├── npt-berendsen-barostat.toml │ │ ├── nve-leap-frog.toml │ │ ├── nve-perfect-gas.toml │ │ ├── nve-shifted.toml │ │ ├── nve-table.toml │ │ ├── nve-velocity-verlet.toml │ │ └── nve-verlet.toml │ ├── md-methane │ │ ├── methane.toml │ │ ├── methane.xyz │ │ └── nve.toml │ ├── md-nacl │ │ ├── ewald-kspace.toml │ │ ├── ewald.toml │ │ ├── npt-wolf-small.toml │ │ ├── nve-ewald-kspace.toml │ │ ├── nve-ewald-small.toml │ │ ├── nve-wolf-small.toml │ │ ├── small.xyz │ │ └── wolf.toml │ ├── md-water │ │ ├── big.pdb │ │ ├── ewald.toml │ │ ├── nve-ewald.toml │ │ ├── nve-wolf.toml │ │ ├── small.pdb │ │ └── wolf.toml │ ├── nist-lj │ │ ├── lj-1.toml │ │ ├── lj-1.xyz │ │ ├── lj-2.toml │ │ ├── lj-2.xyz │ │ ├── lj-3.toml │ │ ├── lj-3.xyz │ │ ├── lj-4.toml │ │ └── lj-4.xyz │ └── nist-spce │ │ ├── forces-10-1.xyz │ │ ├── forces-10-2.xyz │ │ ├── forces-10-3.xyz │ │ ├── forces-10-4.xyz │ │ ├── forces-9-1.xyz │ │ ├── forces-9-2.xyz │ │ ├── forces-9-3.xyz │ │ ├── forces-9-4.xyz │ │ ├── spce-1.xyz │ │ ├── spce-2.xyz │ │ ├── spce-3.xyz │ │ └── spce-4.xyz ├── docs.rs ├── mc-argon.rs ├── mc-ethane.rs ├── mc-helium.rs ├── mc-water.rs ├── md-butane.rs ├── md-helium.rs ├── md-methane.rs ├── md-nacl.rs ├── md-water.rs ├── nist-lj.rs ├── nist-spce.rs └── utils │ └── mod.rs └── tutorials └── potential ├── Cargo.toml ├── data ├── argon.toml └── argon.xyz └── src ├── lib.rs └── main.rs /.codecov.yml: -------------------------------------------------------------------------------- 1 | coverage: 2 | ignore: 3 | - tests/.* 4 | status: 5 | patch: off 6 | project: 7 | default: 8 | target: 85% 9 | 10 | comment: off 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | Cargo.lock 3 | *.pyc 4 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Lumol was created and is maintained by Guillaume Fraux. 2 | Contributors to the code are listed here in alphabetic order. 3 | 4 | Antoine Wendlinger 5 | Gernot Bauer 6 | Guillaume Fraux 7 | Oscar David Arbeláez 8 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "lumol" 3 | version = "0.0.0" 4 | authors = ["Luthaf "] 5 | documentation = "https://lumol-org.github.io/lumol" 6 | repository = "https://github.com/lumol-org/lumol" 7 | readme = "README.md" 8 | license = "BSD-3-Clause" 9 | edition = "2021" 10 | 11 | [workspace] 12 | members = [ 13 | "lumol-core", 14 | "lumol-sim", 15 | "lumol-input", 16 | "tutorials/potential", 17 | ] 18 | 19 | [[bin]] 20 | name = "lumol" 21 | doc = false 22 | test = false 23 | doctest = false 24 | bench = false 25 | 26 | [lib] 27 | test = false 28 | doctest = false 29 | bench = false 30 | 31 | [dependencies] 32 | lumol-core = {path = "lumol-core"} 33 | lumol-sim = {path = "lumol-sim"} 34 | lumol-input = {path = "lumol-input"} 35 | log = "0.4" 36 | clap = "4" 37 | chrono = "0.4" 38 | backtrace = "0.3" 39 | 40 | [dev-dependencies] 41 | rand = "0.8" 42 | rand_xorshift = "0.3" 43 | env_logger = "0.11" 44 | tempfile = "3" 45 | 46 | [dev-dependencies.criterion] 47 | version = "0.5" 48 | default-features = false 49 | 50 | [[bench]] 51 | name = "water" 52 | harness = false 53 | 54 | [[bench]] 55 | name = "nacl" 56 | harness = false 57 | 58 | [[bench]] 59 | name = "argon" 60 | harness = false 61 | 62 | [[bench]] 63 | name = "propane" 64 | harness = false 65 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015-2017, Lumol's contributors 2 | All rights reserved. 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are met: 5 | 6 | 1. Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | 2. Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | 3. Neither the name of the copyright holder nor the names of its contributors 12 | may be used to endorse or promote products derived from this software 13 | without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED 16 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 17 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 18 | SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 19 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 20 | OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 22 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 23 | IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 24 | OF SUCH DAMAGE. 25 | 26 | See the AUTHORS file for a list of contributors. 27 | -------------------------------------------------------------------------------- /benches/argon.rs: -------------------------------------------------------------------------------- 1 | // Lumol, an extensible molecular simulation engine 2 | // Copyright (C) Lumol's contributors — BSD license 3 | use criterion::{Criterion, BatchSize, criterion_group, criterion_main}; 4 | 5 | use lumol::compute::{MolecularVirial, AtomicVirial, PotentialEnergy, Forces, Compute}; 6 | use lumol::EnergyCache; 7 | mod utils; 8 | 9 | fn energy_computation(c: &mut Criterion) { 10 | let system = utils::get_system("argon"); 11 | c.bench_function("argon::energy", move |b| b.iter(|| { 12 | let _ = PotentialEnergy.compute(&system); 13 | })); 14 | 15 | let system = utils::get_system("argon"); 16 | c.bench_function("argon::force", move |b| b.iter(|| { 17 | let _ = Forces.compute(&system); 18 | })); 19 | 20 | let system = utils::get_system("argon"); 21 | c.bench_function("argon::atomic_virial", move |b| b.iter(|| { 22 | let _ = AtomicVirial.compute(&system); 23 | })); 24 | 25 | let system = utils::get_system("argon"); 26 | c.bench_function("argon::molecular_virial", move |b| b.iter(|| { 27 | let _ = MolecularVirial.compute(&system); 28 | })); 29 | } 30 | 31 | fn monte_carlo_cache(c: &mut Criterion) { 32 | let system = utils::get_system("argon"); 33 | let mut cache = EnergyCache::new(); 34 | cache.init(&system); 35 | 36 | c.bench_function("argon::move_molecule_cost", move |b| b.iter_batched( 37 | || utils::move_rigid_molecule(&system), 38 | |(molid, positions)| cache.move_molecule_cost(&system, molid, &positions), 39 | BatchSize::SmallInput 40 | )); 41 | 42 | let system = utils::get_system("argon"); 43 | let mut cache = EnergyCache::new(); 44 | cache.init(&system); 45 | 46 | c.bench_function("argon::move_all_molecules_cost", move |b| b.iter_batched_ref( 47 | || utils::move_all_rigid_molecule(system.clone()), 48 | |system| cache.move_all_molecules_cost(system), 49 | BatchSize::SmallInput 50 | )); 51 | } 52 | 53 | criterion_group!(argon, energy_computation, monte_carlo_cache); 54 | criterion_main!(argon); 55 | -------------------------------------------------------------------------------- /benches/data/argon.toml: -------------------------------------------------------------------------------- 1 | [input] 2 | version = 1 3 | 4 | [global] 5 | cutoff = "10 A" 6 | tail_correction = true 7 | 8 | [pairs] 9 | Ar-Ar = {type = "lj", sigma = "3.4 A", epsilon = "1.0 kJ/mol"} 10 | -------------------------------------------------------------------------------- /benches/data/nacl.toml: -------------------------------------------------------------------------------- 1 | [input] 2 | version = 1 3 | 4 | [global] 5 | cutoff = "8 A" 6 | 7 | [pairs] 8 | Na-Na = {type = "null"} 9 | Cl-Cl = {type = "null"} 10 | Na-Cl = {type = "null"} 11 | 12 | [charges] 13 | Na = 1.0 14 | Cl = -1.0 15 | -------------------------------------------------------------------------------- /benches/data/propane.toml: -------------------------------------------------------------------------------- 1 | [input] 2 | version = 1 3 | 4 | [global] 5 | cutoff = "10 A" 6 | 7 | [pairs] 8 | C-C = {type = "lj", epsilon = "0.1078 kcal/mol", sigma = "3.8138 A"} 9 | H-C = {type = "lj", epsilon = ".04735 kcal/mol", sigma = "3.3662 A"} 10 | H-H = {type = "lj", epsilon = "0.0208 kcal/mol", sigma = "2.9186 A"} 11 | 12 | [bonds] 13 | C-C = {type = "harmonic", k = "232.52 kcal/mol", x0 = "1.538 A"} 14 | C-H = {type = "harmonic", k = "375.92 kcal/mol", x0 = "1.097 A"} 15 | 16 | [angles] 17 | C-C-C = {type = "harmonic", k = "64.888 kcal/mol", x0 = "111.510 deg"} 18 | C-C-H = {type = "harmonic", k = "46.816 kcal/mol", x0 = "109.800 deg"} 19 | H-C-H = {type = "harmonic", k = "38.960 kcal/mol", x0 = "107.580 deg"} 20 | 21 | [dihedrals] 22 | H-C-C-H = {type = "torsion", k = "0.240 kcal/mol", delta = "0.0 deg", n = 3} 23 | H-C-C-C = {type = "torsion", k = "0.080 kcal/mol", delta = "0.0 deg", n = 3} 24 | -------------------------------------------------------------------------------- /benches/data/water.toml: -------------------------------------------------------------------------------- 1 | [input] 2 | version = 1 3 | 4 | [global] 5 | cutoff = "8 A" 6 | 7 | [pairs] 8 | O-O = {type = "null"} 9 | H-H = {type = "null"} 10 | O-H = {type = "null"} 11 | 12 | [bonds] 13 | O-H = {type = "null"} 14 | 15 | [angles] 16 | H-O-H = {type = "null"} 17 | 18 | [charges] 19 | O = -0.82 20 | H = 0.41 21 | -------------------------------------------------------------------------------- /benches/propane.rs: -------------------------------------------------------------------------------- 1 | // Lumol, an extensible molecular simulation engine 2 | // Copyright (C) Lumol's contributors — BSD license 3 | use criterion::{Criterion, BatchSize, criterion_group, criterion_main}; 4 | 5 | use lumol::EnergyCache; 6 | use lumol::compute::{MolecularVirial, AtomicVirial, PotentialEnergy, Forces, Compute}; 7 | 8 | mod utils; 9 | 10 | fn energy_computation(c: &mut Criterion) { 11 | let system = utils::get_system("propane"); 12 | c.bench_function("propane::energy", move |b| b.iter(|| { 13 | let _ = PotentialEnergy.compute(&system); 14 | })); 15 | 16 | let system = utils::get_system("propane"); 17 | c.bench_function("propane::force", move |b| b.iter(|| { 18 | let _ = Forces.compute(&system); 19 | })); 20 | 21 | let system = utils::get_system("propane"); 22 | c.bench_function("propane::atomic_virial", move |b| b.iter(|| { 23 | let _ = AtomicVirial.compute(&system); 24 | })); 25 | 26 | let system = utils::get_system("propane"); 27 | c.bench_function("propane::molecular_virial", move |b| b.iter(|| { 28 | let _ = MolecularVirial.compute(&system); 29 | })); 30 | } 31 | 32 | fn monte_carlo_cache(c: &mut Criterion) { 33 | let system = utils::get_system("propane"); 34 | let mut cache = EnergyCache::new(); 35 | cache.init(&system); 36 | 37 | c.bench_function("propane::move_molecule_cost", move |b| b.iter_batched( 38 | || utils::move_rigid_molecule(&system), 39 | |(molid, positions)| cache.move_molecule_cost(&system, molid, &positions), 40 | BatchSize::SmallInput 41 | )); 42 | 43 | let system = utils::get_system("propane"); 44 | let mut cache = EnergyCache::new(); 45 | cache.init(&system); 46 | 47 | c.bench_function("propane::move_all_molecules_cost", move |b| b.iter_batched_ref( 48 | || utils::move_all_rigid_molecule(system.clone()), 49 | |system| cache.move_all_molecules_cost(system), 50 | BatchSize::SmallInput 51 | )); 52 | } 53 | 54 | criterion_group!(propane, energy_computation, monte_carlo_cache); 55 | criterion_main!(propane); 56 | -------------------------------------------------------------------------------- /benches/utils/mod.rs: -------------------------------------------------------------------------------- 1 | // Lumol, an extensible molecular simulation engine 2 | // Copyright (C) Lumol's contributors — BSD license 3 | #![allow(dead_code, clippy::needless_return)] 4 | 5 | use lumol::{System, TrajectoryBuilder, Vector3D}; 6 | use lumol::input::InteractionsInput; 7 | use std::path::Path; 8 | 9 | use rand::{SeedableRng, Rng}; 10 | use rand_xorshift::XorShiftRng; 11 | 12 | pub fn get_system(name: &str) -> System { 13 | let data = Path::new(file!()).parent().unwrap().join("..").join("data"); 14 | 15 | let system = data.join(String::from(name) + ".pdb"); 16 | let mut system = TrajectoryBuilder::new().open(system) 17 | .and_then(|mut trajectory| trajectory.read()) 18 | .unwrap(); 19 | 20 | let interactions = data.join(String::from(name) + ".toml"); 21 | InteractionsInput::new(interactions).and_then(|input| input.read(&mut system)) 22 | .unwrap(); 23 | 24 | return system; 25 | } 26 | 27 | pub fn get_rng() -> XorShiftRng { 28 | XorShiftRng::from_seed([145, 59, 58, 50, 238, 182, 97, 28, 107, 149, 227, 40, 90, 109, 196, 129]) 29 | } 30 | 31 | pub fn move_rigid_molecule(system: &System) -> (usize, Vec) { 32 | let mut rng = get_rng(); 33 | 34 | let molid = rng.gen_range(0..system.molecules().count()); 35 | let molecule = system.molecule(molid); 36 | let delta = Vector3D::new(rng.gen(), rng.gen(), rng.gen()); 37 | let mut positions = Vec::new(); 38 | for position in molecule.particles().position { 39 | positions.push(position + delta); 40 | } 41 | 42 | return (molid, positions); 43 | } 44 | 45 | pub fn move_all_rigid_molecule(mut system: System) -> System { 46 | let mut rng = get_rng(); 47 | 48 | for mut molecule in system.molecules_mut() { 49 | let delta = Vector3D::new(rng.gen(), rng.gen(), rng.gen()); 50 | for position in molecule.particles_mut().position { 51 | *position += delta; 52 | } 53 | } 54 | 55 | return system; 56 | } 57 | -------------------------------------------------------------------------------- /build.rs: -------------------------------------------------------------------------------- 1 | use std::process::Command; 2 | use std::str; 3 | 4 | fn main() { 5 | let mut version = env!("CARGO_PKG_VERSION").to_string(); 6 | if let Ok(output) = Command::new("git").args(["describe", "--always"]).output() { 7 | let git = str::from_utf8(&output.stdout).unwrap().trim(); 8 | version.push('-'); 9 | version.push_str(git); 10 | } 11 | 12 | println!("cargo:rustc-env=LUMOL_FULL_GIT_VERSION={}", version); 13 | println!("cargo:rerun-if-changed=.git/HEAD"); 14 | } 15 | -------------------------------------------------------------------------------- /doc/.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | -------------------------------------------------------------------------------- /doc/KaTeX.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | 13 | 14 | 23 | -------------------------------------------------------------------------------- /doc/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | 3 | # You can set these variables from the command line. 4 | SPHINXOPTS = 5 | SPHINXBUILD = sphinx-build 6 | SPHINXPROJ = Lumol 7 | SOURCEDIR = src 8 | BUILDDIR = build 9 | 10 | # Put it first so that "make" without argument is like "make help". 11 | help: 12 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 13 | 14 | .PHONY: help Makefile 15 | 16 | # Catch-all target: route all unknown targets to Sphinx using the new 17 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 18 | %: Makefile 19 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 20 | -------------------------------------------------------------------------------- /doc/README.md: -------------------------------------------------------------------------------- 1 | # Lumol documentation 2 | 3 | Lumol has different documentations: 4 | 5 | - The **user manual** contains information about the general concepts of systems 6 | and simulations used in Lumol. Additionally, it has tutorials on how to use 7 | and extend Lumol. Use this documentation if you want to know basic concepts 8 | and how they are used in Lumol. 9 | - The **input reference** contains information about - well, the input file 10 | system of Lumol. Use this document if you want to use Lumol as a command line 11 | tool without writing code. 12 | - To use Lumol as a library inside your own code, we have a **developer 13 | documentation**, which contains documentation for all the library public 14 | functions, and examples for most of them. 15 | 16 | Here is how you can build these documents. Both the user manual and the input 17 | reference uses [sphinx] with [reStructuredText] markup, so you will need to 18 | install some dependencies in order to build them: 19 | 20 | ``` 21 | pip install -r doc/requirements.txt 22 | ``` 23 | 24 | [sphinx]: http://www.sphinx-doc.org/en/stable/index.html 25 | [reStructuredText]: www.sphinx-doc.org/en/stable/rest.html 26 | 27 | ## User manual 28 | 29 | The user manual is located in the `book` directory. 30 | 31 | ```bash 32 | cd book 33 | make html 34 | # HTML pages are in `build/html` 35 | ``` 36 | 37 | If you prefer other formats, *sphinx* has different options. You can inspect 38 | all options by typing 39 | 40 | ```bash 41 | make help 42 | ``` 43 | 44 | The documentation is found in `build/html/` (or `build//` where `` is 45 | the specified format for `make`). 46 | 47 | ## Input reference 48 | 49 | The input reference is located in the `reference` directory. It is also built 50 | using sphinx: 51 | 52 | ```bash 53 | cd reference 54 | make html 55 | # HTML pages are in `build/html` 56 | ``` 57 | 58 | ## Programming interface documentation 59 | 60 | In addition to the user manual, Lumol provides a complete programming interface 61 | documentation, which you can build by running `cargo doc --open` in the root of 62 | the repository. 63 | 64 | This interface documentation is only useful if you want to use Lumol as a 65 | library in you own code. 66 | -------------------------------------------------------------------------------- /doc/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Lumol, extensible molecular simulation engine 6 | 35 | 36 | 37 |
38 |

Lumol

39 |

Extensible molecular simulation engine

40 | 41 | 45 | 46 |

47 |







48 | Sorry, this webpage is still in developement. 49 |

50 |
51 | 52 | 53 | -------------------------------------------------------------------------------- /doc/requirements.txt: -------------------------------------------------------------------------------- 1 | sphinx>1.8.0 2 | sphinx_bootstrap_theme 3 | pygments 4 | pygments-github-lexers 5 | toml 6 | -------------------------------------------------------------------------------- /doc/src/advanced/index.rst: -------------------------------------------------------------------------------- 1 | Modifying lumol 2 | *************** 3 | 4 | This chapter discusses ways to extend or modify Lumol. 5 | 6 | .. toctree:: 7 | :maxdepth: 2 8 | 9 | potential/index 10 | -------------------------------------------------------------------------------- /doc/src/advanced/potential/intro.rst: -------------------------------------------------------------------------------- 1 | Traits used for potentials 2 | -------------------------- 3 | 4 | As mentioned above, potential functions can be used to model all kinds of 5 | interactions between particles such as bonded and non-bonded interactions. In 6 | Lumol, ``Potential`` is a `trait `_. To further distinguish between 7 | bonded interactions (bond lengths, angles and dihedrals) and non-bonded 8 | interactions, we use another trait (often called marker traits). Your possible 9 | options to further specialise a ``Potential`` are 10 | 11 | - `PairPotential`_ for non-bonded two body interactions; 12 | - `BondPotential`_ for covalent bonds interactions; 13 | - `AnglePotential`_ for covalent angles interactions; 14 | - `DihedralPotential`_ for covalent dihedral angles interactions. 15 | 16 | .. _Potential: http://lumol.org/lumol/latest/lumol_core/energy/trait.Potential.html 17 | .. _PairPotential: http://lumol.org/lumol/latest/lumol_core/energy/trait.PairPotential.html 18 | .. _BondPotential: http://lumol.org/lumol/latest/lumol_core/energy/trait.BondPotential.html 19 | .. _AnglePotential: http://lumol.org/lumol/latest/lumol_core/energy/trait.AnglePotential.html 20 | .. _DihedralPotential: http://lumol.org/lumol/latest/lumol_core/energy/trait.DihedralPotential.html 21 | 22 | For our Mie potential implementation, we will have to implement both the 23 | ``Potential`` as well as the ``PairPotential`` traits. If we wanted to implement 24 | a function that can be used as non-bonded as well as bond-length potential, we'd 25 | have to implement ``Potential``, ``PairPotential`` as well as ``BondPotential``. 26 | "Implementing a trait" means that we will define a `struct`_ for which we will 27 | add functions to satisfy the traits' requirements. 28 | 29 | Let's start by having a look at the documentation for ``Potential``: open the 30 | `API documentation `_. As you can see from the trait, a 31 | ``Potential`` defines two functions, ``energy`` and ``force`` (we ignore the 32 | ``Sync + Send`` statement for now): 33 | 34 | .. code-block:: bash 35 | 36 | pub trait Potential: Sync + Send { 37 | fn energy(&self, x: f64) -> f64; 38 | fn force(&self, x: f64) -> f64; 39 | } 40 | 41 | ``energy`` will compute the interaction energy between atoms as a function of 42 | ``x``. The force is defined as the negative derivative of the energy function 43 | with respect to ``x``. 44 | 45 | Both functions take a single, scalar argument and return a single scalar value. 46 | In our case ``x`` stands for the distance between two interaction sites. Note 47 | that only the function definitions -- without a function body -- are specified. 48 | We will have to implement these functions for our potential. 49 | 50 | .. _struct: https://doc.rust-lang.org/book/second-edition/ch05-00-structs.html 51 | .. _trait: https://doc.rust-lang.org/book/second-edition/ch10-02-traits.html 52 | -------------------------------------------------------------------------------- /doc/src/concepts/index.rst: -------------------------------------------------------------------------------- 1 | Lumol concepts 2 | ************** 3 | 4 | In order to run a molecular simulation, you need two things: a description of 5 | the system you are simulating and a set of algorithms used to propagate the 6 | simulation. This section presents how the ``System`` and the ``Simulation`` 7 | objects work in Lumol. The ``System`` contains the full description of the 8 | system, and the ``Simulation`` contains the algorithms used to propagate the 9 | system. 10 | 11 | .. toctree:: 12 | system 13 | simulation 14 | units 15 | -------------------------------------------------------------------------------- /doc/src/concepts/simulation.rst: -------------------------------------------------------------------------------- 1 | Simulation 2 | ********** 3 | 4 | A simulation in Lumol always contains the same steps: 5 | 6 | 1. Setup the system and initialize the algorithms using system specific 7 | information; 8 | 2. Propagate the system for one step using a Propagator; 9 | 3. Compute the physical properties of the system and output them to a file; 10 | 4. Check if the simulation is finished (either the required number of steps has 11 | been done, or a convergence criterion is reached) and return the updated 12 | system. If the simulation is not finished, go back to (2) 13 | 14 | Propagators 15 | ----------- 16 | 17 | Propagators are at the heart of a Simulation. They have the responsibility to 18 | update the system at each simulation step. Currently, three propagators exists: 19 | a molecular dynamics one, a Monte Carlo one and a minimizer, for energy 20 | minimization. 21 | 22 | Output algorithms 23 | ----------------- 24 | 25 | Output algorithms have the responsibility to compute and output statistical data 26 | about the simulated system. Temperature, energy, radial distribution functions 27 | are some examples of output algorithms. 28 | -------------------------------------------------------------------------------- /doc/src/concepts/system.rst: -------------------------------------------------------------------------------- 1 | System 2 | ****** 3 | 4 | A ``System`` contains all the data about the physical system we are simulating. 5 | It contains four types of data: 6 | 7 | - A list of **Particles**, which are physical objects with a position, a 8 | velocity, a mass and a name; 9 | - A list of **Molecules** containing information about how the particles are 10 | bounded together; 11 | - An **UnitCell**, *i.e.* the bounding box of the simulation. 12 | - **Interactions**, sometimes called a force field. 13 | 14 | Particles 15 | --------- 16 | 17 | Particles are the basic building blocks of a system. They can be atoms or more 18 | complex: coarse-grained sites, dummy atoms, anisotropic particles ... 19 | 20 | They have a name, a mass, a position, a velocity, and most importantly a 21 | particle kind, defined by the name of the particle. All particles with the same 22 | name share the same kind: all ``H`` are the same, as well as all ``C``, *etc.* 23 | 24 | Molecules 25 | --------- 26 | 27 | When particles are bonded together, they form molecules. A ``Molecule`` contains 28 | the list of its bonds; molecules make for the *molecular* part in 29 | *molecular simulation*. 30 | 31 | Unit cells 32 | ---------- 33 | 34 | Lumol knows about three types of unit cells: 35 | 36 | - Infinite cells do not have any boundaries and can be used to simulate 37 | systems in vacuum; 38 | - Orthorhombic cells have up to three independent lengths whereas all angles 39 | of the cell are set to 90°; 40 | - Triclinic cells have 6 independent parameters: 3 lengths and 3 angles. 41 | 42 | Orthorhombic and Triclinic cells are used in combination with `periodic boundary 43 | conditions `_ to simulate infinite systems. 44 | 45 | .. _pbc: https://en.wikipedia.org/wiki/Periodic_boundary_conditions 46 | 47 | Interactions 48 | ------------ 49 | 50 | Interactions are potentials acting on or between particles. 51 | Lumol provides functions for various potential types: 52 | 53 | - Non-bonding pair potentials; 54 | - Bonds potentials in molecules; 55 | - Angles potentials in molecules; 56 | - Dihedral angles potentials in molecules; 57 | - Long-ranges coulombic potentials (Ewald and Wolf methods); 58 | - Arbitrary external potential applying on the whole system at once. 59 | -------------------------------------------------------------------------------- /doc/src/concepts/units.rst: -------------------------------------------------------------------------------- 1 | Units 2 | ===== 3 | 4 | The unit system used internally by Lumol is the following: 5 | 6 | - Angstrom (``A``) for distances; 7 | - Femtosecond (``fs``) for time; 8 | - Unified atomic mass unit (``u`` or ``Da``) for mass; 9 | - Kelvin (``K``) for temperature; 10 | - Number of particles for quantity of matter; 11 | - Radian (``rad``) for angles; 12 | 13 | Any other internal unit is derived from this set: 14 | 15 | - The internal unit of energy is ``u A^2 fs^-2``; 16 | - The internal unit of force is ``u A fs^-2``; 17 | - The internal unit of pressure is ``u A^-1 fs^-2``; 18 | - *etc.* 19 | 20 | For convenience Lumol provides convertion facilities for any value in these 21 | internal unit to any others units. The following table lists available units 22 | that can be converted: 23 | 24 | +------------+-----------------------------+ 25 | | Quantity | Accepted units | 26 | +============+=============================+ 27 | | Distance | A, Å, nm, pm, fm, m, bohr | 28 | +------------+-----------------------------+ 29 | | Time | fs, ps, ns | 30 | +------------+-----------------------------+ 31 | | Mass | u, Da, kDa, g, kg | 32 | +------------+-----------------------------+ 33 | | Matter | mol | 34 | +------------+-----------------------------+ 35 | | Angle | rad, deg | 36 | +------------+-----------------------------+ 37 | | Energy | J, kJ, kcal, eV, H, Ry | 38 | +------------+-----------------------------+ 39 | | Force | N | 40 | +------------+-----------------------------+ 41 | | Pressure | Pa, kPa, MPa, bar, atm | 42 | +------------+-----------------------------+ 43 | 44 | In the input files, the units are specified as strings, and must be 45 | spelled exactly as in the above table. They can be combined with other 46 | units using ``*`` for multiplication, ``/`` for division, and ``^`` for 47 | exponentiation. Parentheses can be used to group sub-units together. Some 48 | valid unit strings are ``kcal/mol``, ``(J / mol) * A^-2``, and 49 | ``m*fs^-1``. 50 | -------------------------------------------------------------------------------- /doc/src/conf.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | import toml 4 | import os 5 | import sphinx_bootstrap_theme 6 | 7 | # -- General configuration ------------------------------------------------ 8 | 9 | ROOT = os.path.join(os.path.dirname(__file__), "..") 10 | 11 | # If your documentation needs a minimal Sphinx version, state it here. 12 | needs_sphinx = '1.8' 13 | 14 | extensions = [ 15 | 'sphinx.ext.mathjax', 16 | 'sphinx.ext.ifconfig', 17 | ] 18 | 19 | templates_path = [os.path.join(ROOT, "templates")] 20 | source_suffix = '.rst' 21 | master_doc = 'index' 22 | 23 | copyright = '2019, the lumol developers' 24 | author = 'The lumol developers' 25 | project = 'Lumol' 26 | 27 | 28 | def version(): 29 | parsed = toml.loads(open(os.path.join("..", "..", "Cargo.toml")).read()) 30 | release = parsed["package"]["version"] 31 | version = ".".join(release.split(".")[:2]) 32 | return version, release 33 | 34 | 35 | version, release = version() 36 | 37 | language = None 38 | 39 | exclude_patterns = [] 40 | 41 | pygments_style = 'default' 42 | highlight_language = 'toml' 43 | 44 | 45 | def setup(app): 46 | app.add_stylesheet("lumol.css") 47 | 48 | 49 | # -- Options for HTML output ---------------------------------------------- 50 | 51 | html_theme = 'bootstrap' 52 | html_theme_path = sphinx_bootstrap_theme.get_html_theme_path() 53 | 54 | html_theme_options = { 55 | 'navbar_site_name': "Navigation", 56 | 'navbar_pagenav': False, 57 | 'source_link_position': None, 58 | 'bootswatch_theme': "sandstone", 59 | 'bootstrap_version': "3", 60 | } 61 | 62 | html_sidebars = { 63 | '**': ['sidebar-toc.html', 'searchbox.html'] 64 | } 65 | 66 | html_static_path = [os.path.join(ROOT, "static", "lumol.css")] 67 | 68 | # -- Options for LaTeX output --------------------------------------------- 69 | 70 | latex_elements = { 71 | 'papersize': 'a4paper', 72 | } 73 | 74 | latex_documents = [ 75 | (master_doc, 'Lumol.tex', 'Lumol user manual', author, 'howto'), 76 | ] 77 | -------------------------------------------------------------------------------- /doc/src/data/argon.toml: -------------------------------------------------------------------------------- 1 | [input] 2 | version = 1 3 | 4 | [[systems]] 5 | file = "argon.xyz" 6 | cell = 21.65 7 | 8 | [systems.potentials.pairs] 9 | Ar-Ar = {type = "lj", sigma = "3.4 A", epsilon = "1.0 kJ/mol", cutoff = "10 A"} 10 | 11 | [[simulations]] 12 | nsteps = 100000 13 | outputs = [ 14 | {type = "Energy", file = "energy.dat", frequency = 100}, 15 | {type = "Trajectory", file = "trajectory.xyz", frequency = 100} 16 | ] 17 | 18 | [simulations.propagator] 19 | type = "MonteCarlo" 20 | temperature = "500 K" 21 | moves = [ 22 | {type = "Translate", delta = "1 A"}, 23 | ] 24 | -------------------------------------------------------------------------------- /doc/src/data/argon.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lumol-org/lumol/2c054458f136faea1cba0c3ef61cd41946f1434f/doc/src/data/argon.zip -------------------------------------------------------------------------------- /doc/src/data/nacl.toml: -------------------------------------------------------------------------------- 1 | [input] 2 | version = 1 3 | 4 | [[systems]] 5 | file = "nacl.xyz" 6 | cell = 22.5608 7 | 8 | [systems.potentials.global] 9 | cutoff = "8 A" 10 | 11 | [systems.potentials.charges] 12 | Na = 1.0 13 | Cl = -1.0 14 | 15 | [systems.potentials.pairs] 16 | Na-Na = {type = "lj", sigma = "2.497 A", epsilon = "0.07826 kcal/mol"} 17 | Cl-Cl = {type = "lj", sigma = "4.612 A", epsilon = "0.02502 kcal/mol"} 18 | Na-Cl = {type = "lj", sigma = "3.5545 A", epsilon = "0.04425 kcal/mol"} 19 | 20 | [systems.potentials.coulomb] 21 | wolf = {cutoff = "8 A"} 22 | 23 | [[simulations]] 24 | nsteps = 5000 25 | outputs = [ 26 | {type = "Trajectory", file = "trajectory.xyz", frequency = 10} 27 | ] 28 | 29 | [simulations.propagator] 30 | type = "MolecularDynamics" 31 | timestep = "1 fs" 32 | -------------------------------------------------------------------------------- /doc/src/data/nacl.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lumol-org/lumol/2c054458f136faea1cba0c3ef61cd41946f1434f/doc/src/data/nacl.zip -------------------------------------------------------------------------------- /doc/src/data/pack.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | rm -f *.zip 4 | 5 | zip argon.zip argon.toml argon.xyz 6 | zip nacl.zip nacl.toml nacl.xyz 7 | zip water.zip water.toml water.xyz water-fSCP.toml 8 | -------------------------------------------------------------------------------- /doc/src/data/water-fSCP.toml: -------------------------------------------------------------------------------- 1 | [input] 2 | version = 1 3 | 4 | [global] 5 | cutoff = "14 A" 6 | 7 | [charges] 8 | O = -0.82 9 | H = 0.41 10 | 11 | [pairs] 12 | O-O = {type = "lj", sigma = "3.16 A", epsilon = "0.155 kcal/mol"} 13 | H-H = {type = "harmonic", k = "79.8 kcal/mol/A^2", x0 = "1.633 A", restriction = "intra-molecular"} 14 | H-O = {type = "null"} 15 | 16 | [bonds] 17 | O-H = {type = "harmonic", k = "1054.2 kcal/mol/A^2", x0 = "1.0 A"} 18 | 19 | [angles] 20 | H-O-H = {type = "harmonic", k = "75.9 kcal/mol/rad^2", x0 = "109.5 deg"} 21 | 22 | [coulomb] 23 | ewald = {cutoff = "8.5 A", kmax = 3} 24 | restriction = "inter-molecular" 25 | -------------------------------------------------------------------------------- /doc/src/data/water.toml: -------------------------------------------------------------------------------- 1 | [input] 2 | version = 1 3 | 4 | [[systems]] 5 | file = "water.xyz" 6 | guess_bonds = true 7 | cell = 28.0 8 | potentials = "water-fSCP.toml" 9 | 10 | [[simulations]] 11 | nsteps = 5000 12 | outputs = [ 13 | {type = "Trajectory", file = "trajectory.xyz", frequency = 10} 14 | ] 15 | 16 | [simulations.propagator] 17 | type = "MolecularDynamics" 18 | timestep = "1 fs" 19 | -------------------------------------------------------------------------------- /doc/src/data/water.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lumol-org/lumol/2c054458f136faea1cba0c3ef61cd41946f1434f/doc/src/data/water.zip -------------------------------------------------------------------------------- /doc/src/index.rst: -------------------------------------------------------------------------------- 1 | The Lumol user manual 2 | ===================== 3 | 4 | .. note:: 5 | 6 | Lumol is actively developed and should be considered as alpha software. 7 | 8 | As the code is likely to change so is this documentation. 9 | 10 | Welcome to the Lumol user manual. In this book we teach you how to use Lumol to 11 | set up and run classical molecular simulations. We designed Lumol to be 12 | *flexible* and *extensible*; you are able to customize your simulation to suit 13 | your needs and use it as a platform to implement your own algorithms and 14 | customized potential functions in an *easy* way. You can use Lumol as a command 15 | line tool as well as a library in your own code. 16 | 17 | .. only:: html 18 | 19 | This user manual is also available as a `PDF `_ file, if you 20 | prefer to have it available locally or printed. 21 | 22 | Excited? Then let's start with an overview of this book: 23 | 24 | .. toctree:: 25 | :maxdepth: 1 26 | 27 | installation 28 | tutorial/index 29 | concepts/index 30 | input/index 31 | advanced/index 32 | faq 33 | -------------------------------------------------------------------------------- /doc/src/input/index.rst: -------------------------------------------------------------------------------- 1 | Input file reference 2 | ==================== 3 | 4 | This section describes how to use input files to run your simulations with 5 | Lumol. An input file contains all information that you need to run a simulation 6 | and it is usually organized in four main sections: **input**, **log**, 7 | **systems** and **simulations**. 8 | 9 | - The **input** section contains metadata about the input itself (i.e. a version number). 10 | - The **log** sections explains different methods about how Lumol reports information about your simulation such as warnings and errors. 11 | - The **systems** section contains information about the initial configuration, the interactions between atoms and the simulation cell. 12 | - The **simulations** section defines how your system will propagate. You can generally choose between molecular dynamics (MD), Monte-Carlo (MC) and energy minimization. 13 | 14 | Lumol's input files use the `TOML `__ 15 | format, a simple and minimalist configuration format based on 16 | ``key = value`` pairs. You can read an introduction to the TOML format 17 | `here `__. 18 | 19 | **Example**: 20 | 21 | .. code:: 22 | 23 | # an example input file for a Monte Carlo simulation 24 | 25 | # input section 26 | [input] 27 | version = 1 28 | 29 | # log section 30 | [log] 31 | target = "lumol.log" 32 | 33 | # systems section 34 | [[systems]] 35 | file = "data/ethane.xyz" 36 | guess_bonds = true 37 | cell = 100.0 38 | 39 | [systems.potentials.global] 40 | cutoff = "14.0 A" 41 | tail_correction = true 42 | 43 | [systems.potentials.pairs.C-C] 44 | type = "lj" 45 | sigma = "3.750 A" 46 | epsilon = "0.814 kJ/mol" 47 | restriction = "InterMolecular" 48 | 49 | [systems.potentials.bonds] 50 | C-C = {type = "null"} 51 | 52 | # simulations section 53 | [[simulations]] 54 | nsteps = 1_000_000 55 | outputs = [ 56 | {type = "Energy", file = "ethane_ener.dat", frequency = 500}, 57 | {type = "Properties", file = "ethane_prp.dat", frequency = 500} 58 | ] 59 | 60 | [simulations.propagator] 61 | type = "MonteCarlo" 62 | temperature = "217.0 K" 63 | update_frequency = 500 64 | 65 | moves = [ 66 | {type = "Translate", delta = "20 A", frequency = 50, target_acceptance = 0.5}, 67 | {type = "Rotate", delta = "20 deg", frequency = 50, target_acceptance = 0.5}, 68 | {type = "Resize", pressure = "5.98 bar", delta = "5 A^3", frequency = 2, target_acceptance = 0.5}, 69 | ] 70 | 71 | 72 | .. toctree:: 73 | :hidden: 74 | 75 | input 76 | log 77 | systems/index 78 | interactions/index 79 | simulations/index 80 | -------------------------------------------------------------------------------- /doc/src/input/input.rst: -------------------------------------------------------------------------------- 1 | ``[input]`` section 2 | ******************* 3 | 4 | All input files must contain an ``[input]`` section looking like this: 5 | 6 | .. code:: 7 | 8 | [input] 9 | version = 1 10 | 11 | Introducing a ``version`` key helps us to make changes to the input file format 12 | while keeping compatibility with previous formats. Please note that Lumol is not 13 | in version 1.0 yet and we currently cannot guarantee compatibility for input 14 | files. 15 | -------------------------------------------------------------------------------- /doc/src/input/interactions/index.rst: -------------------------------------------------------------------------------- 1 | Interactions input 2 | ################## 3 | 4 | Interactions describe the energies between atoms - or more general - between 5 | interaction sites. These energies arise due to covalent bonding of atoms to form 6 | molecules, short-range van der Waals or long-range Coulombic energies. To 7 | describe interactions we use *potentials* which are functions that take a set of 8 | parameters and geometrical coordinates (for example distances or angles) as 9 | input and yield energies and forces. A set of potential functions and parameters 10 | to describe energies and forces of a molecule is also often called *force 11 | field*. We will use the terms interactions and force field interchangeably. 12 | 13 | To be more specific, we distinguish between the following contributions: 14 | 15 | - ``pairs`` are van der Waals interactions between pairs of atoms; 16 | - ``bonds`` describe the energy between bonded atoms; 17 | - ``angles`` and ``dihedrals`` describe energy contributions due to bending and 18 | twisting of bonded atoms; 19 | - ``coulomb`` and ``charges`` describe long-range contributions due to 20 | electrostatic interactions; 21 | - the ``global`` section describes additional parameter that apply to all the 22 | energy contributions. 23 | 24 | Information about interactions for ``pairs``, ``bonds``, ``angles`` and 25 | ``dihedrals`` are organized as TOML tables. The ``coulomb`` section contains 26 | information about the treatment of long-range electrostatic interactions and the 27 | ``charges`` section defines the partial charges of the atoms. 28 | 29 | .. toctree:: 30 | :maxdepth: 2 31 | 32 | organisation 33 | non_bonded 34 | electrostatic 35 | potentials 36 | restrictions 37 | -------------------------------------------------------------------------------- /doc/src/input/interactions/organisation.rst: -------------------------------------------------------------------------------- 1 | Organizing interactions 2 | ======================= 3 | 4 | You can specify interactions between atoms in two ways: either inside the main 5 | input file or in a separate file. For example take a look at the input file for 6 | the flexible SPC water model where we put all interactions directly into our 7 | main input file: 8 | 9 | .. code:: 10 | 11 | # system configuration: initial positions, topology and cell 12 | [[systems]] 13 | file = "data/water.xyz" 14 | topology = "topology.pdb" 15 | cell = 40 16 | 17 | # intermolecular potentials 18 | [systems.potentials.pairs] 19 | O-O = {type = "lj", sigma = "3.165 A", epsilon = "0.155 kcal/mol"} 20 | H-H = {type = "null"} 21 | O-H = {type = "null"} 22 | 23 | # intramolecular potentials 24 | [systems.potentials.bonds] 25 | O-H = {type = "harmonic", k = "1059.162 kcal/mol/A^2", x0 = "1.012 A"} 26 | 27 | [systems.potentials.angles] 28 | H-O-H = {type = "harmonic", k = "75.90 kcal/mol/deg^2", x0 = "113.24 deg"} 29 | 30 | # ... additional interactions omitted 31 | 32 | As you can see, there is a lot of bracket notation going on here. First, in 33 | ``[systems.potentials.xxx]``, the ``potentials`` key is actually a nested table 34 | of ``systems`` indicated by the dot notation. Accordingly, ``pairs``, ``bonds``, 35 | ``angles``, etc. are nested tables of ``potentials``. Second, ``{type = 36 | "harmonic", k = "75.90 kcal/mol/deg", x0 = "113.24 deg"}`` is the notation for 37 | an inline table. 38 | 39 | Input files can get very big and hard to read when you simulate complex systems 40 | with a large number of different atoms. In these scenarios it may be better to 41 | define a separate input file for your interactions like so: 42 | 43 | .. code:: 44 | 45 | [[systems]] 46 | file = "data/water.xyz" 47 | topology = "topology.pdb" 48 | cell = 40 49 | potentials = "water.toml" 50 | 51 | Here, the ``potentials`` key contains a string that is interpreted as the path 52 | to another input file containing only definitions of interactions. This way, you 53 | can build your own library of force field files. 54 | -------------------------------------------------------------------------------- /doc/src/input/interactions/restrictions.rst: -------------------------------------------------------------------------------- 1 | Restrictions 2 | ============ 3 | 4 | Some force fields define additional restrictions concerning which particles 5 | should interact together and which ones should not. For example, sometimes 6 | bonded particles should not interact through electrostatic potential, or some 7 | interactions should only be taken in account for particles not in the same 8 | molecule. The way to specify this is to use restrictions. Restrictions can be 9 | used in two places: in the ``[pairs]`` section, and in the ``[coulomb]`` 10 | section. In both cases, they are specified with the ``restriction`` keyword, and 11 | one of the possible values. 12 | 13 | .. code:: 14 | 15 | [pairs] 16 | O-O = {type = "lj", sigma = "3 A", epsilon = "123 kJ/mol", restriction = {scale14 = 0.5}} 17 | 18 | [coulomb] 19 | ewald = {cutoff = "8 A", kmax = 6} 20 | restriction = "intermolecular" 21 | 22 | The possible values for ``restriction`` are: 23 | 24 | * ``"intramolecular"`` or ``"intra-molecular"`` to act only on particles that 25 | are in the same molecule; 26 | * ``"intermolecular"`` or ``"inter-molecular"`` to act only on particles that 27 | are **NOT** in the same molecule; 28 | * ``"exclude12"`` to exclude particles directly bonded together; 29 | * ``"exclude13"`` to exclude particles directly bonded together or forming an 30 | angle; 31 | * ``"exclude14"`` to exclude particles directly bonded together; forming an 32 | angle or a dihedral angle; 33 | * ``{scale14 = }`` works like ``exclude13``, *i.e.* intramolecular 34 | interactions between three neighboring particles (connected by two bonds) will 35 | not be computed. Additionally, interactions between the first and the forth 36 | (hence the ``14`` in ``scale14``) particle will be computed, but using scaled 37 | energies and forces. This simply means that the energies and forces are 38 | multiplied (linear scaling) by the given scaling factor, which must be between 39 | 0 and 1. 40 | -------------------------------------------------------------------------------- /doc/src/input/simulations/index.rst: -------------------------------------------------------------------------------- 1 | ``[[simulations]]`` section 2 | *************************** 3 | 4 | The way to propagate the system is defined in the ``[[simulations]]`` section of 5 | the input file. This section always contains at least two keys: ``nsteps`` 6 | specify the number of steps in the simulation, and the 7 | ``simulations.propagator`` table specify which propagator to use. 8 | 9 | Here is an example of NPT molecular dynamics: 10 | 11 | .. code:: 12 | 13 | [[simulations]] 14 | nsteps = 1_000_000 15 | 16 | [simulations.propagator] 17 | type = "MolecularDynamics" 18 | timestep = "1 fs" 19 | integrator = {type = "BerendsenBarostat", pressure = "100 bar", timestep = 1000} 20 | thermostat = {type = "Berendsen", temperature = "400 K", timestep = 100} 21 | 22 | Three propagators are currently implemented: 23 | 24 | - A :ref:`minimization` propagator, to minimize energy of a system before 25 | running another propagator; 26 | - A :ref:`molecular-dynamics` propagator; 27 | - A :ref:`monte-carlo` propagator; 28 | 29 | 30 | .. toctree:: 31 | :maxdepth: 2 32 | 33 | output 34 | min 35 | md 36 | mc 37 | -------------------------------------------------------------------------------- /doc/src/input/simulations/min.rst: -------------------------------------------------------------------------------- 1 | .. _minimization: 2 | 3 | Minimization 4 | ============ 5 | 6 | You can run a minimization by setting the propagator ``type`` to 7 | ``Minimization``. The unique needed key is the ``minimizer`` algorithm to use 8 | for this simulation; you can also optionally set the criteria for minimization 9 | convergence. 10 | 11 | .. code:: 12 | 13 | [simulations.propagator] 14 | type = "Minimization" 15 | minimizer = {type = "SteepestDescent"} 16 | criteria = {energy = "1e-5 kJ/mol", force2 = "1e-5 kJ^2/mol^2/A^2"} 17 | 18 | The single minimization algorithm implemented is the steepest descent algorithm, 19 | that updates the coordinates of the atom following the energy gradient. 20 | 21 | The minimization stops when the energy difference between the previous and the 22 | current step is lower than the ``energy`` criterion, or when the maximal squared 23 | norm of the atomic force is lower than the ``force2`` criterion. 24 | -------------------------------------------------------------------------------- /doc/src/input/systems/index.rst: -------------------------------------------------------------------------------- 1 | ``[[systems]]`` section 2 | *********************** 3 | 4 | Let's talk about how you can set up your system. The system contains information 5 | about: 6 | 7 | - the configuration, i.e. the positions (and velocities) of your atoms; 8 | - which atoms are connected (bonded) to form molecules; 9 | - how atoms will interact with each other; 10 | - and the simulation cell (i.e. volume). 11 | 12 | All these details are listed after the ``[[systems]]`` keyword. 13 | 14 | .. toctree:: 15 | :maxdepth: 2 16 | 17 | configuration 18 | -------------------------------------------------------------------------------- /doc/src/installation.rst: -------------------------------------------------------------------------------- 1 | ************ 2 | Installation 3 | ************ 4 | 5 | Lumol is written in `rust`_ (:ref:`why? `), and you will need a 6 | Rust compiler to compile it. You can find rust installation instructions `here 7 | `_, or use your system package manager. Lumol also depends on 8 | some C++ libraries, so you will need a C++ compiler and CMake to be installed. 9 | 10 | Lumol is tested on Linux and OS X, and should build on Windows without any 11 | issue. You will need a C++11 capable compiler on Windows (MSVC > 15 or Mingw 12 | with gcc > 4.9). Be sure to pick the corresponding version of the Rust compiler. 13 | 14 | When all the dependencies are installed on you system, you can install the 15 | the latest development version with: 16 | 17 | .. code-block:: bash 18 | 19 | cargo install --git https://github.com/lumol-org/lumol lumol 20 | 21 | This command will download and install lumol in ``~/.cargo/bin/lumol``, where 22 | ``~`` is your home directory. You may want to add ``~/.cargo/bin`` to your PATH 23 | or move the ``lumol`` binary in another directory accessible in your PATH. 24 | 25 | You can check that the installation worked by running 26 | 27 | .. code-block:: bash 28 | 29 | lumol --version 30 | 31 | .. _rust: https://www.rust-lang.org/ 32 | .. _rust-install: https://www.rust-lang.org/downloads.html 33 | -------------------------------------------------------------------------------- /doc/src/tutorial/argon.rst: -------------------------------------------------------------------------------- 1 | Monte Carlo simulation of Argon 2 | =============================== 3 | 4 | So let's run out first simulation with Lumol. The easiest system to simulate is 5 | a Lennard-Jones fluid, which is a good model for noble gas fluids. Here we 6 | will simulate super-critical argon using the Metropolis Monte Carlo algorithm. 7 | 8 | For this simulation, you will need the following files: 9 | 10 | * the initial configuration ``argon.xyz`` 11 | * the input file ``argon.toml`` 12 | 13 | .. only:: html 14 | 15 | You can download both files :download:`here <../data/argon.zip>`. 16 | 17 | .. only:: latex 18 | 19 | You can download both files at the following URL: 20 | ``_. 21 | 22 | After extracting the archive, you can run the simulation with ``lumol 23 | argon.toml``. The simulation should complete in a few seconds and produce two 24 | files: ``energy.dat`` and ``trajectory.xyz``. 25 | 26 | Input file anatomy 27 | ------------------ 28 | 29 | The input file is written using the TOML syntax, you can learn more about this 30 | `syntax here `__. The file starts with a 31 | header declaring the version of the input file syntax used, here the version 1: 32 | 33 | .. literalinclude:: ../data/argon.toml 34 | :lines: 1-2 35 | 36 | Then, we declare which system that we want to simulate in the ``systems`` array. 37 | We define this system using an XYZ file for which we also have to provide the 38 | unit cell size. 39 | 40 | .. literalinclude:: ../data/argon.toml 41 | :lines: 4-6 42 | 43 | We also need to define the interaction potential between the atoms in the 44 | system, which we'll do in the ``system.potential.pairs`` section. 45 | Here, we are using a Lennard-Jones potential with a cutoff distance of 10 46 | Angstrom for all Argon (Ar) pairs. 47 | 48 | .. literalinclude:: ../data/argon.toml 49 | :lines: 8-9 50 | 51 | Next, we define how we want to simulate our system. For this brief tutorial 52 | simulating ``100000`` steps should be enough. We also specify some output: 53 | the energy is written to ``energy.dat`` every 100 steps, and the trajectory 54 | is written to ``trajectory.xyz`` also every 100 steps. 55 | 56 | .. literalinclude:: ../data/argon.toml 57 | :lines: 11-16 58 | 59 | Finally, we define how to propagate the system from one step to another. 60 | We are using a Monte Carlo simulation in this tutorial. We need to specify the 61 | temperature (set to 500 K) and the set of moves that we want to perform to 62 | change the systems. The only Monte Carlo move in this example is a translation 63 | for which we set the maximum amplitude (the furthest a particle can be 64 | translated in a single move) to 1 Angstrom. 65 | 66 | .. literalinclude:: ../data/argon.toml 67 | :lines: 18-23 68 | 69 | Wrapping all this together, here is the complete input file: 70 | 71 | .. literalinclude:: ../data/argon.toml 72 | 73 | As mentioned above, you can start the simulation using 74 | 75 | .. code-block:: bash 76 | 77 | lumol argon.toml 78 | 79 | So now we know how to run a simulation of a Lennard-Jones fluid. How about we 80 | add electrostatic interactions in the :doc:`next example `? 81 | -------------------------------------------------------------------------------- /doc/src/tutorial/index.rst: -------------------------------------------------------------------------------- 1 | ********* 2 | Tutorials 3 | ********* 4 | 5 | This section will teach you how to use Lumol to run basic simulations. You can 6 | and should re-use the input files shown in the examples to run your own 7 | simulations. 8 | 9 | .. toctree:: 10 | :maxdepth: 1 11 | 12 | argon 13 | nacl 14 | water 15 | -------------------------------------------------------------------------------- /doc/static/lumol.css: -------------------------------------------------------------------------------- 1 | html { 2 | position: relative; 3 | min-height: 100%; 4 | } 5 | 6 | body { 7 | margin-bottom: 40px; 8 | font-size: 16px; 9 | } 10 | 11 | .footer { 12 | position: absolute; 13 | bottom: 0; 14 | width: 100%; 15 | height: 40px; 16 | background-color: #f5f5f5; 17 | } 18 | 19 | .section { 20 | max-width: 700px; 21 | } 22 | 23 | .nav { 24 | font-size: 13px; 25 | } 26 | 27 | a { 28 | color: #3da48e; 29 | } 30 | 31 | pre { 32 | color: black; 33 | background-color: #e2e2e2; 34 | } 35 | 36 | code { 37 | color: black; 38 | background-color: #dadada; 39 | } 40 | 41 | /* numbers highlighting */ 42 | .highlight .mf, .highlight .mi { 43 | color: #006000; 44 | } 45 | 46 | .form-control::placeholder { 47 | color: #666666; 48 | opacity: 1; 49 | } 50 | 51 | .form-control { 52 | border-color: #adadad; 53 | } 54 | -------------------------------------------------------------------------------- /doc/templates/layout.html: -------------------------------------------------------------------------------- 1 | {% extends "!layout.html" %} 2 | 3 | {% block footer %} 4 |
5 |
6 |

7 | Back to top 8 |

9 |

10 | © Lumol contributors 11 |

12 |

13 | Available on Github 14 |

15 |
16 |
17 | {% endblock %} 18 | -------------------------------------------------------------------------------- /doc/templates/sidebar-toc.html: -------------------------------------------------------------------------------- 1 | {{ toctree(maxdepth=3|toint, collapse=True, includehidden=theme_globaltoc_includehidden|tobool) }} 2 | -------------------------------------------------------------------------------- /examples/argon.rs: -------------------------------------------------------------------------------- 1 | // Lumol, an extensible molecular simulation engine 2 | // Copyright (C) Lumol's contributors — BSD license 3 | #![allow(clippy::cast_lossless)] 4 | 5 | //! Molecular dynamics simulation of an Argon crystal melt. 6 | //! 7 | //! In this example, we do everything by hand, from the system setup to the 8 | //! simulation run. 9 | use lumol::{Particle, Molecule, System, UnitCell, Vector3D}; 10 | use lumol::energy::{LennardJones, PairInteraction}; 11 | use lumol::units; 12 | 13 | use lumol::sim::output::{EnergyOutput, TrajectoryOutput}; 14 | use lumol::sim::{MolecularDynamics, Simulation}; 15 | use lumol::sim::{BoltzmannVelocities, InitVelocities}; 16 | 17 | fn main() -> Result<(), Box> { 18 | let mut system = System::with_cell(UnitCell::cubic(17.0)); 19 | 20 | // Create a cubic crystal of Argon by hand. 21 | for i in 0..5 { 22 | for j in 0..5 { 23 | for k in 0..5 { 24 | let position = Vector3D::new(i as f64 * 3.4, j as f64 * 3.4, k as f64 * 3.4); 25 | let particle = Particle::with_position("Ar", position); 26 | system.add_molecule(Molecule::new(particle)); 27 | } 28 | } 29 | } 30 | 31 | let lj = Box::new(LennardJones { 32 | sigma: units::from(3.4, "A")?, 33 | epsilon: units::from(1.0, "kJ/mol")?, 34 | }); 35 | system.set_pair_potential( 36 | ("Ar", "Ar"), 37 | PairInteraction::new(lj, units::from(8.5, "A")?), 38 | ); 39 | 40 | let mut velocities = BoltzmannVelocities::new(units::from(300.0, "K")?); 41 | velocities.seed(129); 42 | velocities.init(&mut system); 43 | 44 | let md = MolecularDynamics::new(units::from(1.0, "fs")?); 45 | let mut simulation = Simulation::new(Box::new(md)); 46 | 47 | let trajectory_out = Box::new(TrajectoryOutput::new("trajectory.xyz")?); 48 | // Write the trajectory to `trajectory.xyz` every 10 steps 49 | simulation.add_output_with_frequency(trajectory_out, 10); 50 | 51 | let energy_out = Box::new(EnergyOutput::new("energy.dat")?); 52 | // Write the energy to `energy.dat` every step 53 | simulation.add_output(energy_out); 54 | 55 | simulation.run(&mut system, 5000); 56 | 57 | println!("All done!"); 58 | 59 | Ok(()) 60 | } 61 | -------------------------------------------------------------------------------- /examples/binary.rs: -------------------------------------------------------------------------------- 1 | // Lumol, an extensible molecular simulation engine 2 | // Copyright (C) Lumol's contributors — BSD license 3 | 4 | //! Monte Carlo simulation of a binary mixture of H20 and CO2. 5 | use lumol::{Molecule, Particle, TrajectoryBuilder}; 6 | use lumol::read_molecule; 7 | use lumol::units; 8 | 9 | use lumol::sim::Simulation; 10 | use lumol::sim::mc::{MonteCarloBuilder, Rotate, Translate}; 11 | 12 | use lumol::input::InteractionsInput; 13 | 14 | fn main() -> Result<(), Box> { 15 | let mut system = TrajectoryBuilder::new().open("data/binary.pdb")? 16 | .read()?; 17 | let input = InteractionsInput::new("data/binary.toml")?; 18 | input.read(&mut system)?; 19 | 20 | // We can read files to get molecule hash 21 | let co2 = read_molecule("data/CO2.pdb")?.hash(); 22 | 23 | // Or define a new molecule by hand 24 | let mut molecule = Molecule::new(Particle::new("H")); 25 | molecule.add_particle_bonded_to(0, Particle::new("O")); 26 | molecule.add_particle_bonded_to(1, Particle::new("H")); 27 | let h2o = molecule.hash(); 28 | 29 | let mut builder = MonteCarloBuilder::new(units::from(500.0, "K")?); 30 | // Use the molecular types of CO2 and H2O to specify different probabilities 31 | builder.add(Box::new(Translate::new(units::from(0.5, "A")?, co2)), 1.0, None); 32 | builder.add(Box::new(Rotate::new(units::from(10.0, "deg")?, co2)), 1.0, None); 33 | 34 | builder.add(Box::new(Translate::new(units::from(10.0, "A")?, h2o)), 2.0, None); 35 | builder.add(Box::new(Rotate::new(units::from(20.0, "deg")?, h2o)), 2.0, None); 36 | 37 | let mut simulation = Simulation::new(Box::new(builder.finish())); 38 | simulation.run(&mut system, 200_000_000); 39 | 40 | Ok(()) 41 | } 42 | -------------------------------------------------------------------------------- /examples/custom-potential.rs: -------------------------------------------------------------------------------- 1 | // Lumol, an extensible molecular simulation engine 2 | // Copyright (C) Lumol's contributors — BSD license 3 | 4 | //! Using a custom potential in simulations 5 | use lumol::energy::{PairInteraction, PairPotential, Potential}; 6 | use lumol::{Particle, Molecule, System, Vector3D}; 7 | use lumol::units; 8 | 9 | use lumol::sim::{MolecularDynamics, Simulation}; 10 | 11 | /// Let's define a new version of the Lennard-Jones potential, using the 12 | /// alternative form: 13 | /// 14 | /// A B 15 | /// V = ----- - ----- 16 | /// r^12 r^6 17 | /// 18 | #[derive(Clone)] 19 | struct LJ { 20 | a: f64, 21 | b: f64, 22 | } 23 | 24 | // All we need to do is to implement the Potential trait 25 | impl Potential for LJ { 26 | // The energy function give the energy at distance `r` 27 | fn energy(&self, r: f64) -> f64 { 28 | self.a / r.powi(12) - self.b / r.powi(6) 29 | } 30 | 31 | // The force function give the norm of the force at distance `r` 32 | fn force(&self, r: f64) -> f64 { 33 | 12.0 * self.a / r.powi(13) - 6.0 * self.b / r.powi(7) 34 | } 35 | } 36 | 37 | // We want to use our LJ potential as a pair potential. 38 | impl PairPotential for LJ { 39 | // The long-range correction to the energy at the given cutoff 40 | fn tail_energy(&self, cutoff: f64) -> f64 { 41 | -(1.0 / 9.0 * self.a / cutoff.powi(9) - 1.0 / 3.0 * self.b / cutoff.powi(3)) 42 | } 43 | 44 | // The long-range correction to the virial at the given cutoff 45 | fn tail_virial(&self, cutoff: f64) -> f64 { 46 | -(12.0 / 9.0 * self.a / cutoff.powi(9) - 6.0 / 3.0 * self.b / cutoff.powi(3)) 47 | } 48 | } 49 | 50 | fn main() -> Result<(), Box> { 51 | let mut system = System::new(); 52 | system.add_molecule(Molecule::new(Particle::with_position("F", Vector3D::new(0.0, 0.0, 0.0)))); 53 | system.add_molecule(Molecule::new(Particle::with_position("F", Vector3D::new(1.5, 0.0, 0.0)))); 54 | 55 | // We can now use our new potential in the system 56 | let lj = Box::new(LJ { 57 | a: units::from(675.5, "kJ/mol/A^12")?, 58 | b: units::from(40.26, "kJ/mol/A^6")?, 59 | }); 60 | system.set_pair_potential(("F", "F"), PairInteraction::new(lj, 10.0)); 61 | 62 | let md = MolecularDynamics::new(units::from(1.0, "fs")?); 63 | let mut simulation = Simulation::new(Box::new(md)); 64 | simulation.run(&mut system, 1000); 65 | 66 | Ok(()) 67 | } 68 | -------------------------------------------------------------------------------- /examples/data/CO2.pdb: -------------------------------------------------------------------------------- 1 | HETATM 1 O XXX X 1 1.100 0.000 0.000 1.00 0.00 O 2 | HETATM 2 C XXX X 2 0.000 0.000 0.000 1.00 0.00 C 3 | HETATM 3 O XXX X 3 1.100 0.000 0.000 1.00 0.00 O 4 | CONECT 1 2 5 | CONECT 2 1 3 6 | CONECT 3 2 7 | END 8 | -------------------------------------------------------------------------------- /examples/data/H2O.pdb: -------------------------------------------------------------------------------- 1 | HETATM 1 H XXX X 1 1.100 0.000 0.000 1.00 0.00 H 2 | HETATM 2 O XXX X 2 0.000 0.000 0.000 1.00 0.00 O 3 | HETATM 3 H XXX X 3 1.100 0.000 0.000 1.00 0.00 H 4 | CONECT 1 2 5 | CONECT 2 1 3 6 | CONECT 3 2 7 | END 8 | -------------------------------------------------------------------------------- /examples/data/binary.toml: -------------------------------------------------------------------------------- 1 | [input] 2 | version = 1 3 | 4 | [global] 5 | cutoff = "3 A" 6 | 7 | [[pairs]] 8 | atoms = ["O", "O"] 9 | lj = {sigma = "3.16 A", epsilon = "0.155 kcal/mol"} 10 | restriction = "intermolecular" 11 | 12 | [[pairs]] 13 | atoms = ["C", "O"] 14 | lj = {sigma = "3.045 A", epsilon = "0.168 kcal/mol"} 15 | 16 | [[pairs]] 17 | atoms = ["C", "C"] 18 | lj = {sigma = "2.93 A", epsilon = "0.183 kcal/mol"} 19 | 20 | [[pairs]] 21 | atoms = ["H", "H"] 22 | null = {} 23 | 24 | [[pairs]] 25 | atoms = ["H", "O"] 26 | null = {} 27 | 28 | [[pairs]] 29 | atoms = ["H", "C"] 30 | null = {} 31 | 32 | [[bonds]] 33 | atoms = ["H", "O"] 34 | null = {} 35 | 36 | [[bonds]] 37 | atoms = ["C", "O"] 38 | null = {} 39 | 40 | [[angles]] 41 | atoms = ["H", "O", "H"] 42 | null = {} 43 | 44 | [[angles]] 45 | atoms = ["O", "C", "O"] 46 | null = {} 47 | -------------------------------------------------------------------------------- /examples/data/nacl.toml: -------------------------------------------------------------------------------- 1 | [input] 2 | version = 1 3 | 4 | [global] 5 | cutoff = "8 A" 6 | 7 | [[pairs]] 8 | atoms = ["Na", "Cl"] 9 | lj = {sigma = "3.5545 A", epsilon = "0.04425 kcal/mol"} 10 | 11 | [[pairs]] 12 | atoms = ["Na", "Na"] 13 | lj = {sigma = "2.497 A", epsilon = "0.07826 kcal/mol"} 14 | 15 | [[pairs]] 16 | atoms = ["Cl", "Cl"] 17 | lj = {sigma = "4.612 A", epsilon = "0.02502 kcal/mol"} 18 | 19 | [coulomb] 20 | wolf = {cutoff = "8 A"} 21 | 22 | [charges] 23 | Na = 1.0 24 | Cl = -1.0 25 | -------------------------------------------------------------------------------- /examples/data/simulation.toml: -------------------------------------------------------------------------------- 1 | [input] 2 | version = 1 3 | 4 | [[systems]] 5 | potentials = "binary.toml" 6 | file = "binary.pdb" 7 | 8 | [[simulations]] 9 | nsteps = 100000 10 | [simulations.propagator] 11 | type = "MonteCarlo" 12 | temperature = "500 K" 13 | moves = [ 14 | {type = "Rotate", delta = "10.0 deg", molecule = "CO2.pdb"}, 15 | {type = "Translate", delta = "0.5 A", molecule = "CO2.pdb"}, 16 | {type = "Rotate", delta = "20 deg", molecule = "H2O.pdb", frequency = 2}, 17 | {type = "Translate", delta = "10 A", molecule = "H2O.pdb", frequency = 2}, 18 | ] 19 | -------------------------------------------------------------------------------- /examples/ethane.toml: -------------------------------------------------------------------------------- 1 | # run via: 2 | # cargo run ethane.toml --release 3 | 4 | [input] 5 | version = 1 6 | 7 | [[systems]] 8 | file = "data/ethane.xyz" 9 | guess_bonds = true 10 | cell = 100.0 11 | 12 | [systems.potentials.global] 13 | cutoff = "14.0 A" 14 | tail_correction = true 15 | 16 | [[systems.potentials.pairs]] 17 | atoms = ["C", "C"] 18 | lj = {sigma = "3.750 A", epsilon = "0.814821 kJ/mol"} 19 | restriction = "InterMolecular" 20 | 21 | [[systems.potentials.bonds]] 22 | atoms = ["C", "C"] 23 | null = {} 24 | 25 | [[simulations]] 26 | nsteps = 1_000_000 27 | outputs = [ 28 | {type = "Energy", file = "input_ethane_ener.dat", frequency = 500}, 29 | {type = "Properties", file = "input_ethane_prp.dat", frequency = 500} 30 | ] 31 | 32 | [simulations.propagator] 33 | type = "MonteCarlo" 34 | temperature = "217.0 K" 35 | update_frequency = 500 36 | 37 | moves = [ 38 | {type = "Translate", delta = "20 A", frequency = 50, target_acceptance = 0.5}, 39 | {type = "Rotate", delta = "20 deg", frequency = 50, target_acceptance = 0.5}, 40 | {type = "Resize", pressure = "5.98 bar", delta = "5 A^3", frequency = 2, target_acceptance = 0.5}, 41 | ] 42 | -------------------------------------------------------------------------------- /examples/input.rs: -------------------------------------------------------------------------------- 1 | // Lumol, an extensible molecular simulation engine 2 | // Copyright (C) Lumol's contributors — BSD license 3 | 4 | //! Example of a run using input files for the simulation and the system 5 | //! This is the exact same simulation as the one in `binary.rs` 6 | fn main() { 7 | let input = lumol::input::Input::new("data/simulation.toml").unwrap(); 8 | match input.read() { 9 | Err(error) => println!("Error in input: {}", error), 10 | Ok(mut config) => { 11 | config.simulation.run(&mut config.system, config.nsteps); 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /examples/minimization.rs: -------------------------------------------------------------------------------- 1 | // Lumol, an extensible molecular simulation engine 2 | // Copyright (C) Lumol's contributors — BSD license 3 | 4 | //! Geometry minization of a molecule of water 5 | use lumol::energy::Harmonic; 6 | use lumol::{Particle, Molecule, System, Vector3D}; 7 | use lumol::units; 8 | 9 | use lumol::sim::{Minimization, Simulation}; 10 | use lumol::sim::min::{SteepestDescent, Tolerance}; 11 | 12 | fn main() -> Result<(), Box> { 13 | let mut system = System::new(); 14 | 15 | let alpha = units::from(50.0, "deg")?; 16 | let a_cos = 1.2 * f64::cos(alpha); 17 | let a_sin = 1.2 * f64::sin(alpha); 18 | let mut molecule = Molecule::new(Particle::with_position("O", Vector3D::new(0.0, 0.0, 0.0))); 19 | molecule.add_particle_bonded_to(0, Particle::with_position("H", Vector3D::new(a_cos, a_sin, 0.0))); 20 | molecule.add_particle_bonded_to(0, Particle::with_position("H", Vector3D::new(a_cos, -a_sin, 0.0))); 21 | system.add_molecule(molecule); 22 | 23 | system.set_bond_potential( 24 | ("O", "H"), 25 | Box::new(Harmonic { 26 | x0: units::from(1.1, "A")?, 27 | k: units::from(100.0, "kJ/mol/A^2")?, 28 | }), 29 | ); 30 | system.set_angle_potential( 31 | ("H", "O", "H"), 32 | Box::new(Harmonic { 33 | x0: units::from(109.0, "deg")?, 34 | k: units::from(30.0, "kJ/mol/deg")?, 35 | }), 36 | ); 37 | 38 | let tolerance = Tolerance { 39 | energy: units::from(1e-5, "kJ/mol")?, 40 | force2: units::from(1e-5, "(kJ/mol/A)^2")?, 41 | }; 42 | let minimization = Minimization::new(Box::new(SteepestDescent::new()), tolerance); 43 | let mut simulation = Simulation::new(Box::new(minimization)); 44 | simulation.run(&mut system, 500); 45 | 46 | Ok(()) 47 | } 48 | -------------------------------------------------------------------------------- /examples/nacl.rs: -------------------------------------------------------------------------------- 1 | // Lumol, an extensible molecular simulation engine 2 | // Copyright (C) Lumol's contributors — BSD license 3 | 4 | //! Molecular dynamics simulation of a crystal of sodium chloride, reading system and 5 | //! potentials from files. 6 | use lumol::{TrajectoryBuilder, UnitCell}; 7 | use lumol::units; 8 | 9 | use lumol::sim::Simulation; 10 | use lumol::sim::md::{MolecularDynamics, RescaleThermostat}; 11 | use lumol::sim::{BoltzmannVelocities, InitVelocities}; 12 | 13 | use lumol::input::InteractionsInput; 14 | 15 | fn main() -> Result<(), Box> { 16 | // Read the system fromt the `data/nacl.xyz` file 17 | let mut system = TrajectoryBuilder::new().open("data/nacl.xyz")? 18 | .read()?; 19 | // Set the unit cell, as there is no unit cell data in XYZ files 20 | system.cell = UnitCell::cubic(units::from(22.5608, "A")?); 21 | // Read the interactions from the `data/nacl.toml` TOML file 22 | let input = InteractionsInput::new("data/nacl.toml")?; 23 | input.read(&mut system)?; 24 | 25 | let mut velocities = BoltzmannVelocities::new(units::from(300.0, "K")?); 26 | velocities.init(&mut system); 27 | 28 | let mut md = MolecularDynamics::new(units::from(1.0, "fs")?); 29 | // Use a velocity rescaling thermostat 30 | md.set_thermostat(Box::new(RescaleThermostat::new(units::from(300.0, "K")?))); 31 | 32 | let mut simulation = Simulation::new(Box::new(md)); 33 | simulation.run(&mut system, 1000); 34 | 35 | Ok(()) 36 | } 37 | -------------------------------------------------------------------------------- /examples/xenon.rs: -------------------------------------------------------------------------------- 1 | // Lumol, an extensible molecular simulation engine 2 | // Copyright (C) Lumol's contributors — BSD license 3 | 4 | //! Monte Carlo simulation of a Xenon crystal melt. 5 | use lumol::energy::{LennardJones, PairInteraction}; 6 | use lumol::{TrajectoryBuilder, UnitCell}; 7 | use lumol::units; 8 | 9 | use lumol::sim::output::TrajectoryOutput; 10 | use lumol::sim::Simulation; 11 | use lumol::sim::mc::{MonteCarloBuilder, Translate}; 12 | 13 | fn main() -> Result<(), Box> { 14 | let mut system = TrajectoryBuilder::new().open("data/xenon.xyz")? 15 | .read()?; 16 | system.cell = UnitCell::cubic(units::from(21.65, "A")?); 17 | 18 | let lj = Box::new(LennardJones { 19 | sigma: units::from(4.57, "A")?, 20 | epsilon: units::from(1.87, "kJ/mol")?, 21 | }); 22 | system.set_pair_potential(("Xe", "Xe"), PairInteraction::new(lj, 12.0)); 23 | 24 | // Create a Monte Carlo builder 25 | let mut builder = MonteCarloBuilder::new(units::from(500.0, "K")?); 26 | // Add the `Translate` move with 0.5 A amplitude and 1.0 frequency 27 | builder.add(Box::new(Translate::new(units::from(0.5, "A")?, None)), 1.0, None); 28 | 29 | // Extract the Monte Carlo propagator 30 | let mc = builder.finish(); 31 | let mut simulation = Simulation::new(Box::new(mc)); 32 | 33 | let trajectory_out = Box::new(TrajectoryOutput::new("trajectory.xyz")?); 34 | simulation.add_output_with_frequency(trajectory_out, 50); 35 | 36 | simulation.run(&mut system, 20_000); 37 | 38 | Ok(()) 39 | } 40 | -------------------------------------------------------------------------------- /lumol-core/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "lumol-core" 3 | version = "0.0.0" 4 | authors = ["Luthaf "] 5 | documentation = "https://lumol.org/" 6 | repository = "https://github.com/lumol-org/lumol" 7 | readme = "../README.md" 8 | license = "BSD-3-Clause" 9 | edition = "2021" 10 | 11 | [lib] 12 | bench = false 13 | 14 | [dependencies] 15 | bitflags = "2" 16 | chemfiles = "0.10" 17 | lazy_static = "1" 18 | log-once = "0.4" 19 | ndarray = "0.15" 20 | num-traits = "0.2" 21 | rayon = "1" 22 | soa_derive = "0.13" 23 | special = "0.10" 24 | thread_local = "1" 25 | 26 | [dependencies.log] 27 | version = "0.4" 28 | features = ["std"] 29 | 30 | [dev-dependencies] 31 | tempfile = "3" 32 | approx = "0.5" 33 | -------------------------------------------------------------------------------- /lumol-core/src/consts.rs: -------------------------------------------------------------------------------- 1 | // Lumol, an extensible molecular simulation engine 2 | // Copyright (C) Lumol's contributors — BSD license 3 | 4 | //! Useful physical constants, expressed in the internal unit system. 5 | 6 | #![allow(clippy::unreadable_literal)] 7 | 8 | /// Boltzmann constant 9 | pub const K_BOLTZMANN: f64 = 8.31446284161522e-7; 10 | /// Bohr radius 11 | pub const BOHR_RADIUS: f64 = 0.52917720859; 12 | /// Avogadro number 13 | pub const AVOGADRO_NUMBER: f64 = 6.02214179e23; 14 | /// The constant used in Coulomb energy: 4 * π * ϵ0 15 | pub const FOUR_PI_EPSILON_0: f64 = 7.197589831304046; 16 | -------------------------------------------------------------------------------- /lumol-core/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Lumol, an extensible molecular simulation engine 2 | // Copyright (C) Lumol's contributors — BSD license 3 | 4 | //! Core types and definitions for lumol. 5 | 6 | #![warn(missing_docs, trivial_casts, unused_import_braces, variant_size_differences)] 7 | #![warn(unused_qualifications, unused_results, rust_2018_idioms)] 8 | // Clippy configuration 9 | #![warn(clippy::all, clippy::pedantic)] 10 | // Not embed software, integer and float arithmetic are allowed 11 | #![allow(clippy::float_arithmetic, clippy::indexing_slicing)] 12 | // Cast issues 13 | #![allow(clippy::cast_possible_truncation, clippy::cast_precision_loss)] 14 | #![allow(clippy::cast_sign_loss, clippy::cast_possible_wrap)] 15 | // Style issues 16 | #![allow(clippy::shadow_reuse, clippy::shadow_same, clippy::shadow_unrelated)] 17 | #![allow(clippy::use_self, clippy::redundant_field_names, clippy::or_fun_call)] 18 | #![allow(clippy::needless_return, clippy::needless_range_loop, clippy::doc_markdown)] 19 | #![allow(clippy::missing_docs_in_private_items, clippy::module_name_repetitions)] 20 | #![allow(clippy::new_without_default, clippy::range_plus_one, clippy::missing_panics_doc)] 21 | #![allow(clippy::if_not_else, clippy::redundant_closure_for_method_calls)] 22 | #![allow(clippy::must_use_candidate, clippy::return_self_not_must_use)] 23 | #![allow(clippy::type_complexity)] 24 | 25 | #![allow(clippy::missing_errors_doc)] 26 | 27 | // Tests lints 28 | #![cfg_attr(test, allow(clippy::float_cmp))] 29 | 30 | // deny(warnings) in doc tests 31 | #![doc(test(attr(deny(warnings))))] 32 | #![doc(test(attr(allow(unused_variables))))] 33 | 34 | // Helper modules 35 | #[macro_use] 36 | mod utils; 37 | mod math; 38 | 39 | // Main modules 40 | pub mod units; 41 | pub mod consts; 42 | pub mod types; 43 | pub mod energy; 44 | pub mod sys; 45 | 46 | pub use self::types::*; 47 | pub use self::energy::*; 48 | pub use self::sys::*; 49 | -------------------------------------------------------------------------------- /lumol-core/src/math.rs: -------------------------------------------------------------------------------- 1 | // Lumol, an extensible molecular simulation engine 2 | // Copyright (C) Lumol's contributors — BSD license 3 | 4 | //! Access usual math function directly, without having to use a `f64::` prefix, 5 | //! or to resort to method style call. 6 | #![allow(clippy::inline_always)] 7 | 8 | use special::Error; 9 | 10 | #[inline(always)] 11 | pub fn erf(value: f64) -> f64 { 12 | f64::error(value) 13 | } 14 | 15 | #[inline(always)] 16 | pub fn erfc(value: f64) -> f64 { 17 | f64::compl_error(value) 18 | } 19 | -------------------------------------------------------------------------------- /lumol-core/src/sys/config/mod.rs: -------------------------------------------------------------------------------- 1 | // Lumol, an extensible molecular simulation engine 2 | // Copyright (C) 2015-2016 Lumol's contributors — BSD license 3 | 4 | //! Configuration and related types 5 | 6 | mod mass; 7 | pub use self::mass::get_atomic_mass; 8 | 9 | mod particles; 10 | pub use self::particles::{Particle, ParticleKind}; 11 | pub use self::particles::{ParticleRef, ParticleRefMut}; 12 | pub use self::particles::{ParticlePtr, ParticlePtrMut}; 13 | pub use self::particles::{ParticleSlice, ParticleSliceMut, ParticleVec}; 14 | 15 | mod composition; 16 | pub use self::composition::Composition; 17 | 18 | mod cells; 19 | pub use self::cells::{CellShape, UnitCell}; 20 | 21 | mod connect; 22 | pub use self::connect::{Angle, Bond, Dihedral}; 23 | pub use self::connect::BondDistances; 24 | 25 | mod bonding; 26 | pub use self::bonding::Bonding; 27 | 28 | mod molecules; 29 | pub use self::molecules::{Molecule, MoleculeRef, MoleculeRefMut, MoleculeHash}; 30 | 31 | mod configuration; 32 | pub use self::configuration::Configuration; 33 | pub use self::configuration::Permutation; 34 | pub use self::configuration::{MoleculeIter, MoleculeIterMut}; 35 | -------------------------------------------------------------------------------- /lumol-core/src/sys/mod.rs: -------------------------------------------------------------------------------- 1 | // Lumol, an extensible molecular simulation engine 2 | // Copyright (C) Lumol's contributors — BSD license 3 | 4 | //! Representations of a simulated system 5 | 6 | mod config; 7 | pub use self::config::*; 8 | 9 | mod system; 10 | pub use self::system::System; 11 | pub use self::system::DegreesOfFreedom; 12 | 13 | mod interactions; 14 | pub use self::interactions::Interactions; 15 | 16 | mod energy; 17 | pub use self::energy::EnergyEvaluator; 18 | 19 | mod cache; 20 | pub use self::cache::EnergyCache; 21 | 22 | mod chfl; 23 | pub use chemfiles::Error as TrajectoryError; 24 | pub use self::chfl::{OpenMode, Trajectory, TrajectoryBuilder}; 25 | pub use self::chfl::read_molecule; 26 | 27 | pub mod compute; 28 | -------------------------------------------------------------------------------- /lumol-core/src/types/mod.rs: -------------------------------------------------------------------------------- 1 | // Lumol, an extensible molecular simulation engine 2 | // Copyright (C) Lumol's contributors — BSD license 3 | 4 | //! This module provides complexe numbers; 3D vectors and matrix; and 5 | //! multidimensional arrays for use in all other modules. 6 | mod vectors; 7 | pub use self::vectors::Vector3D; 8 | 9 | mod matrix; 10 | pub use self::matrix::Matrix3; 11 | 12 | mod complex; 13 | pub use self::complex::Complex; 14 | 15 | mod arrays; 16 | pub use self::arrays::{Array2, Array3}; 17 | -------------------------------------------------------------------------------- /lumol-core/src/utils/mod.rs: -------------------------------------------------------------------------------- 1 | // Lumol, an extensible molecular simulation engine 2 | // Copyright (C) Lumol's contributors — BSD license 3 | 4 | //! Various internal utilities, which do not have there own module 5 | 6 | #[macro_use] 7 | mod macros; 8 | 9 | mod thread_vec; 10 | pub use self::thread_vec::ThreadLocalVec; 11 | 12 | #[cfg(test)] 13 | mod xyz; 14 | #[cfg(test)] 15 | pub use self::xyz::system_from_xyz; 16 | -------------------------------------------------------------------------------- /lumol-core/src/utils/thread_vec.rs: -------------------------------------------------------------------------------- 1 | // Lumol, an extensible molecular simulation engine 2 | // Copyright (C) Lumol's contributors — BSD license 3 | 4 | use std::cell::{RefCell, RefMut}; 5 | use std::ops::AddAssign; 6 | 7 | use thread_local::ThreadLocal; 8 | 9 | /// A collection of vectors, one by thread using this struct. All the vectors 10 | /// are wrapped in `RefCell` to ensure mutability of the values. The thread 11 | /// creating the `ThreadLocalVec` will get faster access to the underlying data. 12 | pub struct ThreadLocalVec where T: Send { 13 | inner: ThreadLocal>>, 14 | size: usize 15 | } 16 | 17 | impl ThreadLocalVec { 18 | /// Create a new `ThreadLocalVec` with the given size, initializing the 19 | /// values with `T::default`. 20 | pub fn with_size(size: usize) -> Self { 21 | let inner = ThreadLocal::new(); 22 | // Set the current thread as owner of the data 23 | let _ = inner.get_or(|| RefCell::new(vec![T::default(); size])); 24 | ThreadLocalVec { 25 | inner: inner, 26 | size: size, 27 | } 28 | } 29 | 30 | /// Mutably borrow the thread local vector if it already exists, or create 31 | /// it and then borrow it. 32 | pub fn borrow_mut(&self) -> RefMut<'_, Vec> { 33 | self.inner 34 | .get_or(|| RefCell::new(vec![T::default(); self.size])) 35 | .borrow_mut() 36 | } 37 | } 38 | 39 | impl ThreadLocalVec { 40 | /// Get an iterator over all the vectors created by the different threads 41 | pub fn into_iter(self) -> impl Iterator> { 42 | self.inner 43 | .into_iter() 44 | .map(|cell| cell.into_inner()) 45 | } 46 | 47 | /// Sum the values from all the vectors created by the different threads in 48 | /// the `output` buffer 49 | pub fn sum_into(self, output: &mut [T]) where T: AddAssign { 50 | for local in self.into_iter() { 51 | for (a, b) in zip!(&mut *output, local) { 52 | *a += b; 53 | } 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /lumol-input/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "lumol-input" 3 | version = "0.0.0" 4 | authors = ["Luthaf "] 5 | documentation = "https://lumol.org/" 6 | repository = "https://github.com/lumol-org/lumol" 7 | readme = "../README.md" 8 | license = "BSD-3-Clause" 9 | edition = "2021" 10 | 11 | [lib] 12 | test = false 13 | bench = false 14 | 15 | [dependencies] 16 | lumol-core = {path = "../lumol-core"} 17 | lumol-sim = {path = "../lumol-sim"} 18 | toml = "0.8" 19 | log = "0.4" 20 | anyhow = "1" 21 | 22 | [dependencies.log4rs] 23 | version = "1" 24 | # log4rs has a enormous ammount of features pulling a lot of crates. 25 | # Since we don't need most of them, we selectively enable the ones we want. 26 | default-features = false 27 | features = ["console_appender", "file_appender", "threshold_filter"] 28 | 29 | [dev-dependencies] 30 | walkdir = "2" 31 | rustc-test = "0.3" 32 | env_logger = "0.11" 33 | 34 | [[test]] 35 | name = "input" 36 | harness = false 37 | -------------------------------------------------------------------------------- /lumol-input/src/alternator.rs: -------------------------------------------------------------------------------- 1 | // Lumol, an extensible molecular simulation engine 2 | // Copyright (C) Lumol's contributors — BSD license 3 | 4 | use lumol_sim::md::Control; 5 | use lumol_core::System; 6 | 7 | /// Helper struct that can wrap an algorithm to make it run only a fraction of 8 | /// the times it is called. 9 | #[derive(Debug)] 10 | pub struct Alternator { 11 | every: u64, 12 | count: u64, 13 | inner: T, 14 | } 15 | 16 | impl Alternator { 17 | /// Wrap the algorithm `base` to call it only every `every` time. 18 | pub fn new(every: u64, inner: T) -> Alternator { 19 | Alternator { 20 | every: every, 21 | inner: inner, 22 | count: 0, 23 | } 24 | } 25 | 26 | /// Check if this is the appropriate time to run the algorithm. 27 | pub fn can_run(&mut self) -> bool { 28 | self.count += 1; 29 | self.count % self.every == 0 30 | } 31 | } 32 | 33 | impl AsRef for Alternator { 34 | fn as_ref(&self) -> &T { 35 | &self.inner 36 | } 37 | } 38 | 39 | impl AsMut for Alternator { 40 | fn as_mut(&mut self) -> &mut T { 41 | &mut self.inner 42 | } 43 | } 44 | 45 | impl Control for Alternator { 46 | fn control(&mut self, system: &mut System) { 47 | if self.can_run() { 48 | self.as_mut().control(system); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /lumol-input/src/extract.rs: -------------------------------------------------------------------------------- 1 | // Lumol, an extensible molecular simulation engine 2 | // Copyright (C) Lumol's contributors — BSD license 3 | use toml::value::{Table, Value}; 4 | 5 | use crate::error::Error; 6 | 7 | /// Extract the table at the given `key`, from the `config` TOML table 8 | /// interpreted as a `context`. 9 | pub fn table<'a>(key: &str, config: &'a Table, context: &str) -> Result<&'a Table, Error> { 10 | let table = config.get(key).ok_or( 11 | Error::from(format!("missing '{key}' key in {context}")) 12 | )?; 13 | return table.as_table().ok_or( 14 | Error::from(format!("'{key}' must be a table in {context}")) 15 | ); 16 | } 17 | 18 | /// Extract the string at the given `key`, from the `config` TOML table 19 | /// interpreted as a `context` 20 | pub fn str<'a>(key: &str, config: &'a Table, context: &str) -> Result<&'a str, Error> { 21 | let string = config.get(key).ok_or( 22 | Error::from(format!("missing '{key}' key in {context}")) 23 | )?; 24 | return string.as_str().ok_or( 25 | Error::from(format!("'{key}' must be a string in {context}")) 26 | ); 27 | } 28 | 29 | /// Extract a number (integer or float) at the given `key`, from the `config` 30 | /// TOML table interpreted as a `context` 31 | pub fn number(key: &str, config: &Table, context: &str) -> Result { 32 | let number = config.get(key).ok_or( 33 | Error::from(format!("missing '{key}' key in {context}")) 34 | )?; 35 | match *number { 36 | ::toml::Value::Integer(v) => Ok(v as f64), 37 | ::toml::Value::Float(v) => Ok(v), 38 | _ => Err(Error::from(format!("'{key}' must be a number in {context}"))), 39 | } 40 | } 41 | 42 | /// Extract a unsigned integer at the given `key`, from the `config` 43 | /// TOML table interpreted as a `context` 44 | pub fn uint(key: &str, config: &Table, context: &str) -> Result { 45 | let number = config.get(key).ok_or( 46 | Error::from(format!("missing '{key}' key in {context}")) 47 | )?; 48 | match *number { 49 | ::toml::Value::Integer(v) => { 50 | if v < 0 { 51 | Err(Error::from(format!("'{key}' must be a positive integer in {context}"))) 52 | } else { 53 | Ok(v as u64) 54 | } 55 | } 56 | _ => Err(Error::from(format!("'{key}' must be a positive integer in {context}"))), 57 | } 58 | } 59 | 60 | /// Extract an array at the given `key`, from the `config` TOML table 61 | /// interpreted as a `context` 62 | pub fn slice<'a>(key: &str, config: &'a Table, context: &str) -> Result<&'a [Value], Error> { 63 | let array = config.get(key).ok_or( 64 | Error::from(format!("missing '{key}' key in {context}")) 65 | )?; 66 | let array = array.as_array().ok_or( 67 | Error::from(format!("'{key}' must be an array in {context}")) 68 | ); 69 | return array.map(|arr| arr.as_slice()); 70 | } 71 | 72 | /// Extract the string 'type' key in a TOML table 73 | pub fn typ<'a>(config: &'a Table, context: &str) -> Result<&'a str, Error> { 74 | let typ = config.get("type").ok_or( 75 | Error::from(format!("missing 'type' key in {context}")) 76 | )?; 77 | return typ.as_str().ok_or(Error::from(format!("'type' key must be a string in {context}"))); 78 | } 79 | -------------------------------------------------------------------------------- /lumol-input/src/simulations/min.rs: -------------------------------------------------------------------------------- 1 | // Lumol, an extensible molecular simulation engine 2 | // Copyright (C) Lumol's contributors — BSD license 3 | #![allow(clippy::wildcard_imports)] 4 | 5 | use toml::value::Table; 6 | 7 | use lumol_sim::min::*; 8 | use lumol_core::units; 9 | 10 | use crate::{FromToml, Error}; 11 | use crate::extract; 12 | 13 | impl FromToml for Minimization { 14 | fn from_toml(config: &Table) -> Result { 15 | let minimizer = extract::table("minimizer", config, "minimization propagator")?; 16 | 17 | let minimizer: Box = match extract::typ(minimizer, "minimizer")? { 18 | "SteepestDescent" => Box::new(SteepestDescent::from_toml(minimizer)?), 19 | other => return Err(Error::from(format!("unknown minimizer '{other}'"))), 20 | }; 21 | 22 | let tolerance = if let Some(tolerance) = config.get("tolerance") { 23 | let tolerance = tolerance.as_table().ok_or( 24 | Error::from("'tolerance' must be a table in minimization propagator") 25 | )?; 26 | Tolerance::from_toml(tolerance)? 27 | } else { 28 | Tolerance { 29 | energy: units::from(1e-5, "kJ/mol").expect("bad unit"), 30 | force2: units::from(1e-5, "kJ^2/mol^2/A^2").expect("bad unit"), 31 | } 32 | }; 33 | Ok(Minimization::new(minimizer, tolerance)) 34 | } 35 | } 36 | 37 | impl FromToml for Tolerance { 38 | fn from_toml(config: &Table) -> Result { 39 | let energy = extract::str("energy", config, "minimization tolerance")?; 40 | let force2 = extract::str("force2", config, "minimization tolerance")?; 41 | 42 | Ok(Tolerance { 43 | energy: units::from_str(energy)?, 44 | force2: units::from_str(force2)?, 45 | }) 46 | } 47 | } 48 | 49 | 50 | impl FromToml for SteepestDescent { 51 | fn from_toml(_: &Table) -> Result { 52 | Ok(SteepestDescent::new()) 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /lumol-input/src/simulations/mod.rs: -------------------------------------------------------------------------------- 1 | // Lumol, an extensible molecular simulation engine 2 | // Copyright (C) Lumol's contributors — BSD license 3 | use toml::de::from_str as parse_toml; 4 | use toml::value::Table; 5 | 6 | use std::fs::File; 7 | use std::io::prelude::*; 8 | use std::path::{Path, PathBuf}; 9 | 10 | use lumol_sim::Simulation; 11 | use lumol_core::System; 12 | 13 | use crate::Error; 14 | use crate::validate; 15 | 16 | mod logging; 17 | mod system; 18 | mod outputs; 19 | mod propagator; 20 | #[allow(clippy::module_inception)] 21 | mod simulations; 22 | mod min; 23 | mod md; 24 | mod mc; 25 | 26 | pub use self::logging::setup_default_logger; 27 | 28 | /// A configuration about how to run a single simulation. This contains the 29 | /// system to simulate, the simulation itself and the number of steps to run 30 | /// the simulation. 31 | pub struct Config { 32 | /// The simulated system 33 | pub system: System, 34 | /// The simulation object 35 | pub simulation: Simulation, 36 | /// The simulation duration 37 | pub nsteps: usize, 38 | } 39 | 40 | /// An input file for Lumol. 41 | pub struct Input { 42 | /// The input file path 43 | path: PathBuf, 44 | /// The TOML configuration 45 | config: Table, 46 | } 47 | 48 | impl Input { 49 | /// Read the file at `Path` and create a new `Input` from it. 50 | pub fn new>(path: P) -> Result { 51 | let path = path.into(); 52 | let mut file = try_io!(File::open(&path), path); 53 | let mut buffer = String::new(); 54 | let _ = try_io!(file.read_to_string(&mut buffer), path); 55 | return Input::from_str(path, &buffer); 56 | } 57 | 58 | /// Read the `Input` from a TOML formatted string. 59 | pub fn from_str(path: PathBuf, string: &str) -> Result { 60 | let config = parse_toml(string).map_err(|err| { Error::TOML(Box::new(err)) })?; 61 | validate(&config)?; 62 | Ok(Input { 63 | path: path, 64 | config: config, 65 | }) 66 | } 67 | 68 | /// Read input file and get the corresponding `Config` 69 | pub fn read(&self) -> Result { 70 | self.setup_logging()?; 71 | let system = self.read_system()?; 72 | let simulation = self.read_simulation()?; 73 | let nsteps = self.read_nsteps()?; 74 | 75 | Ok(Config { 76 | system: system, 77 | simulation: simulation, 78 | nsteps: nsteps, 79 | }) 80 | } 81 | } 82 | 83 | fn get_input_path, P2: AsRef>(root: P1, path: P2) -> PathBuf { 84 | let path = PathBuf::from(path.as_ref()); 85 | if path.is_absolute() { 86 | path 87 | } else { 88 | let parent = root.as_ref().parent().expect("Could not get parent path"); 89 | parent.join(path) 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /lumol-input/src/simulations/propagator.rs: -------------------------------------------------------------------------------- 1 | // Lumol, an extensible molecular simulation engine 2 | // Copyright (C) Lumol's contributors — BSD license 3 | use lumol_sim::{Minimization, MolecularDynamics, MonteCarlo, Propagator}; 4 | 5 | use crate::Input; 6 | use crate::{FromToml, FromTomlWithData, Error}; 7 | use crate::extract; 8 | 9 | impl Input { 10 | /// Get the the simulation propagator. 11 | pub(crate) fn read_propagator(&self) -> Result, Error> { 12 | let config = self.simulation_table()?; 13 | let propagator = extract::table("propagator", config, "simulation")?; 14 | match extract::typ(propagator, "propagator")? { 15 | "MolecularDynamics" => Ok(Box::new(MolecularDynamics::from_toml(propagator)?)), 16 | "MonteCarlo" => Ok(Box::new(MonteCarlo::from_toml(propagator, self.path.clone())?)), 17 | "Minimization" => Ok(Box::new(Minimization::from_toml(propagator)?)), 18 | other => Err(Error::from(format!("unknown propagator type '{other}'"))), 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /lumol-input/src/simulations/simulations.rs: -------------------------------------------------------------------------------- 1 | // Lumol, an extensible molecular simulation engine 2 | // Copyright (C) Lumol's contributors — BSD license 3 | use lumol_sim::Simulation; 4 | use toml::value::Table; 5 | 6 | use crate::{Input, Error}; 7 | use crate::extract; 8 | 9 | impl Input { 10 | /// Get the the simulation. 11 | pub fn read_simulation(&self) -> Result { 12 | let propagator = self.read_propagator()?; 13 | let mut simulation = Simulation::new(propagator); 14 | for (output, frequency) in self.read_outputs()? { 15 | simulation.add_output_with_frequency(output, frequency); 16 | } 17 | 18 | Ok(simulation) 19 | } 20 | 21 | /// Get the number of steps in the simulation. 22 | pub(crate) fn read_nsteps(&self) -> Result { 23 | let simulation = self.simulation_table()?; 24 | let nsteps = simulation.get("nsteps").ok_or( 25 | Error::from("missing 'nsteps' key in simulation") 26 | )?; 27 | 28 | let nsteps = nsteps.as_integer().ok_or( 29 | Error::from("'nsteps' key must be an integer") 30 | )?; 31 | 32 | Ok(nsteps as usize) 33 | } 34 | 35 | /// Get the simulation TOML table. 36 | pub(crate) fn simulation_table(&self) -> Result<&Table, Error> { 37 | let simulations = extract::slice("simulations", &self.config, "input file")?; 38 | if simulations.len() != 1 { 39 | return Err(Error::from("only one simulation is supported in the input")); 40 | } 41 | 42 | let simulation = simulations[0].as_table().ok_or( 43 | Error::from("simulations should be tables") 44 | )?; 45 | 46 | return Ok(simulation); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /lumol-input/tests/README.md: -------------------------------------------------------------------------------- 1 | # Lumol-input tests 2 | 3 | This directory contains the input tests for lumol. These tests check two things: 4 | 5 | - that correct input files are parsed without errors; 6 | - that incorrect input files generate the expeted error. 7 | 8 | The test input files are either in `simulation` for the main input or in 9 | `interactions` for the interactions inputs. In both directories, there is a 10 | `good` and a `bad` directory of sample input files. The files in `bad` are 11 | checked to check that the actual error message is the expeted one. The expected 12 | error message can occur anywhere in the file, in a single line, starting with 13 | `#^`: 14 | 15 | ```toml 16 | [input] 17 | version = 1 18 | 19 | [[angles]] 20 | atoms = ["A", "A"] 21 | #^ Wrong size for 'atoms' array in angle potential. Should be 3, is 2 22 | ``` 23 | 24 | When multiple related errors are to be tested, files can contain multiple 25 | standalone input, separated by `+++`: 26 | 27 | ```toml 28 | [input] 29 | version = 1 30 | 31 | [[angles]] 32 | atoms = ["A", "A"] 33 | #^ Wrong size for 'atoms' array in angle potential. Should be 3, is 2 34 | 35 | +++ 36 | 37 | [input] 38 | version = 1 39 | 40 | [[angles]] 41 | atoms = ["A", "B", "A", "B"] 42 | #^ Wrong size for 'atoms' array in angle potential. Should be 3, is 4 43 | ``` 44 | -------------------------------------------------------------------------------- /lumol-input/tests/interactions/bad/angles.toml: -------------------------------------------------------------------------------- 1 | [input] 2 | version = 1 3 | 4 | [angles] 5 | A = {type = "null"} 6 | #^ expected three atoms for angle potential, got 1 (["A"]) 7 | 8 | +++ 9 | 10 | [input] 11 | version = 1 12 | 13 | [angles] 14 | A-A-A-A = {type = "null"} 15 | #^ expected three atoms for angle potential, got 4 (["A", "A", "A", "A"]) 16 | 17 | +++ 18 | 19 | [input] 20 | version = 1 21 | 22 | [angles] 23 | A-A-A = {} 24 | #^ missing 'type' key in angle potential 25 | 26 | +++ 27 | 28 | [input] 29 | version = 1 30 | 31 | [angles] 32 | A-A-A = {type = false} 33 | #^ 'type' key must be a string in angle potential 34 | 35 | +++ 36 | 37 | [input] 38 | version = 1 39 | 40 | [angles] 41 | A-A-A = {type = "bad potential"} 42 | #^ unknown potential type 'bad potential' 43 | -------------------------------------------------------------------------------- /lumol-input/tests/interactions/bad/bonds.toml: -------------------------------------------------------------------------------- 1 | [input] 2 | version = 1 3 | 4 | [bonds] 5 | A = {type = "null"} 6 | #^ expected two atoms for bond potential, got 1 (["A"]) 7 | 8 | +++ 9 | 10 | [input] 11 | version = 1 12 | 13 | [bonds] 14 | A-A-A = {type = "null"} 15 | #^ expected two atoms for bond potential, got 3 (["A", "A", "A"]) 16 | 17 | +++ 18 | 19 | [input] 20 | version = 1 21 | 22 | [bonds] 23 | A-A = {} 24 | #^ missing 'type' key in bond potential 25 | 26 | +++ 27 | 28 | [input] 29 | version = 1 30 | 31 | [bonds] 32 | A-A = {type = false} 33 | #^ 'type' key must be a string in bond potential 34 | 35 | +++ 36 | 37 | [input] 38 | version = 1 39 | 40 | [bonds] 41 | A-A = {type = "bad potential"} 42 | #^ unknown potential type 'bad potential' 43 | -------------------------------------------------------------------------------- /lumol-input/tests/interactions/bad/born.toml: -------------------------------------------------------------------------------- 1 | [input] 2 | version = 1 3 | 4 | [pairs.A-A] 5 | type = "born" 6 | A = true 7 | C = "5e-6 kJ/mol/A^6" 8 | D = "7.6e-5 kJ/mol/A^8" 9 | sigma = "3.2 A" 10 | rho = "2.3 A" 11 | #^ 'A' must be a string in Born-Mayer-Huggins potential 12 | 13 | +++ 14 | 15 | [input] 16 | version = 1 17 | 18 | [pairs.A-A] 19 | type = "born" 20 | A = "4.2 kJ/mol" 21 | C = true 22 | D = "7.6e-5 kJ/mol/A^8" 23 | sigma = "3.2 A" 24 | rho = "2.3 A" 25 | #^ 'C' must be a string in Born-Mayer-Huggins potential 26 | 27 | +++ 28 | 29 | [input] 30 | version = 1 31 | 32 | [pairs.A-A] 33 | type = "born" 34 | A = "4.2 kJ/mol" 35 | C = "5e-6 kJ/mol/A^6" 36 | D = true 37 | sigma = "3.2 A" 38 | rho = "2.3 A" 39 | #^ 'D' must be a string in Born-Mayer-Huggins potential 40 | 41 | +++ 42 | 43 | [input] 44 | version = 1 45 | 46 | [pairs.A-A] 47 | type = "born" 48 | A = "4.2 kJ/mol" 49 | C = "5e-6 kJ/mol/A^6" 50 | D = "7.6e-5 kJ/mol/A^8" 51 | sigma = true 52 | rho = "2.3 A" 53 | #^ 'sigma' must be a string in Born-Mayer-Huggins potential 54 | 55 | +++ 56 | 57 | [input] 58 | version = 1 59 | 60 | [pairs.A-A] 61 | type = "born" 62 | A = "4.2 kJ/mol" 63 | C = "5e-6 kJ/mol/A^6" 64 | D = "7.6e-5 kJ/mol/A^8" 65 | sigma = "3.2 A" 66 | rho = true 67 | #^ 'rho' must be a string in Born-Mayer-Huggins potential 68 | 69 | +++ 70 | 71 | [input] 72 | version = 1 73 | 74 | [pairs.A-A] 75 | type = "born" 76 | C = "5e-6 kJ/mol/A^6" 77 | D = "7.6e-5 kJ/mol/A^8" 78 | sigma = "3.2 A" 79 | rho = "2.3 A" 80 | #^ missing 'A' key in Born-Mayer-Huggins potential 81 | 82 | +++ 83 | 84 | [input] 85 | version = 1 86 | 87 | [pairs.A-A] 88 | type = "born" 89 | A = "4.2 kJ/mol" 90 | D = "7.6e-5 kJ/mol/A^8" 91 | sigma = "3.2 A" 92 | rho = "2.3 A" 93 | #^ missing 'C' key in Born-Mayer-Huggins potential 94 | 95 | +++ 96 | 97 | [input] 98 | version = 1 99 | 100 | [pairs.A-A] 101 | type = "born" 102 | A = "4.2 kJ/mol" 103 | C = "5e-6 kJ/mol/A^6" 104 | sigma = "3.2 A" 105 | rho = "2.3 A" 106 | #^ missing 'D' key in Born-Mayer-Huggins potential 107 | 108 | +++ 109 | 110 | [input] 111 | version = 1 112 | 113 | [pairs.A-A] 114 | type = "born" 115 | A = "4.2 kJ/mol" 116 | C = "5e-6 kJ/mol/A^6" 117 | D = "7.6e-5 kJ/mol/A^8" 118 | rho = "2.3 A" 119 | #^ missing 'sigma' key in Born-Mayer-Huggins potential 120 | 121 | +++ 122 | 123 | [input] 124 | version = 1 125 | 126 | [pairs.A-A] 127 | type = "born" 128 | A = "4.2 kJ/mol" 129 | C = "5e-6 kJ/mol/A^6" 130 | D = "7.6e-5 kJ/mol/A^8" 131 | sigma = "3.2 A" 132 | #^ missing 'rho' key in Born-Mayer-Huggins potential 133 | -------------------------------------------------------------------------------- /lumol-input/tests/interactions/bad/buckingham.toml: -------------------------------------------------------------------------------- 1 | [input] 2 | version = 1 3 | 4 | [pairs] 5 | A-A = {type = "buckingham", A = 34, C = "5e-6 kJ/mol/A^6", rho = "2.3 A"} 6 | #^ 'A' must be a string in Buckingham potential 7 | 8 | +++ 9 | 10 | [input] 11 | version = 1 12 | 13 | [pairs] 14 | A-A = {type = "buckingham", A = "4.2 kJ/mol", C = 56, rho = "2.3 A"} 15 | #^ 'C' must be a string in Buckingham potential 16 | 17 | +++ 18 | 19 | [input] 20 | version = 1 21 | 22 | [pairs] 23 | A-A = {type = "buckingham", A = "4.2 kJ/mol", C = "5e-6 kJ/mol/A^6", rho = 23} 24 | #^ 'rho' must be a string in Buckingham potential 25 | 26 | +++ 27 | 28 | [input] 29 | version = 1 30 | 31 | [pairs] 32 | A-A = {type = "buckingham", C = "5e-6 kJ/mol/A^6", rho = "2.3 A"} 33 | #^ missing 'A' key in Buckingham potential 34 | 35 | +++ 36 | 37 | [input] 38 | version = 1 39 | 40 | [pairs] 41 | A-A = {type = "buckingham", A = "4.2 kJ/mol", rho = "2.3 A"} 42 | #^ missing 'C' key in Buckingham potential 43 | 44 | +++ 45 | 46 | [input] 47 | version = 1 48 | 49 | [pairs] 50 | A-A = {type = "buckingham", A = "4.2 kJ/mol", C = "5e-6 kJ/mol/A^6"} 51 | #^ missing 'rho' key in Buckingham potential 52 | -------------------------------------------------------------------------------- /lumol-input/tests/interactions/bad/charges.toml: -------------------------------------------------------------------------------- 1 | [input] 2 | version = 1 3 | 4 | [charges] 5 | Cn = "he" 6 | #^ charges must be numbers 7 | -------------------------------------------------------------------------------- /lumol-input/tests/interactions/bad/cos-harmonic.toml: -------------------------------------------------------------------------------- 1 | [input] 2 | version = 1 3 | 4 | [angles] 5 | A-A-A = {type = "cosine-harmonic", x0 = "3 A"} 6 | #^ missing 'k' key in cosine harmonic potential 7 | 8 | +++ 9 | 10 | [input] 11 | version = 1 12 | 13 | [angles] 14 | A-A-A = {type = "cosine-harmonic", k = "22 kJ/mol"} 15 | #^ missing 'x0' key in cosine harmonic potential 16 | 17 | +++ 18 | 19 | [input] 20 | version = 1 21 | 22 | [angles] 23 | A-A-A = {type = "cosine-harmonic", k = "22 kJ/mol", x0 = false} 24 | #^ 'x0' must be a string in cosine harmonic potential 25 | 26 | +++ 27 | 28 | [input] 29 | version = 1 30 | 31 | [angles] 32 | A-A-A = {type = "cosine-harmonic", k = 2.2, x0 = "7 A"} 33 | #^ 'k' must be a string in cosine harmonic potential 34 | -------------------------------------------------------------------------------- /lumol-input/tests/interactions/bad/coulomb.toml: -------------------------------------------------------------------------------- 1 | [input] 2 | version = 1 3 | 4 | [coulomb] 5 | wolf = {cutoff = "6 A"} 6 | ewald = {cutoff = "6 A", kmax = 8} 7 | #^ got more than one coulombic solver: ewald and wolf 8 | 9 | +++ 10 | 11 | [input] 12 | version = 1 13 | 14 | [coulomb] 15 | wolf = {cutoff = 6} 16 | #^ 'cutoff' must be a string in Wolf coulombic potential 17 | 18 | +++ 19 | 20 | [input] 21 | version = 1 22 | 23 | [coulomb] 24 | ewald = {cutoff = 6, kmax = 67} 25 | #^ 'cutoff' must be a string in Ewald coulombic potential 26 | 27 | +++ 28 | 29 | [input] 30 | version = 1 31 | 32 | [coulomb] 33 | ewald = {cutoff = "6 A", kmax = "67"} 34 | #^ 'kmax' must be a positive integer in Ewald coulombic potential 35 | 36 | +++ 37 | 38 | [input] 39 | version = 1 40 | 41 | [coulomb] 42 | ewald = {cutoff = "6 A", kmax = -7} 43 | #^ 'kmax' must be a positive integer in Ewald coulombic potential 44 | 45 | +++ 46 | 47 | [input] 48 | version = 1 49 | 50 | [coulomb] 51 | ewald = {cutoff = "6 A", kmax = 7, alpha = false} 52 | #^ 'alpha' must be a string in Ewald coulombic potential 53 | 54 | +++ 55 | 56 | [input] 57 | version = 1 58 | 59 | [coulomb] 60 | ewald = true 61 | #^ coulombic solver 'ewald' must be a table 62 | 63 | +++ 64 | 65 | [input] 66 | version = 1 67 | 68 | [coulomb] 69 | wolf = true 70 | #^ coulombic solver 'wolf' must be a table 71 | 72 | +++ 73 | 74 | [input] 75 | version = 1 76 | 77 | [coulomb] 78 | unknown = {} 79 | #^ unknown coulomb solver 'unknown' 80 | 81 | +++ 82 | 83 | [input] 84 | version = 1 85 | 86 | [coulomb] 87 | ewald = {cutoff = "6 A", kmax = 7, accuracy = 12} 88 | #^ can not have both accuracy and kmax/alpha in Ewald coulombic potential 89 | 90 | +++ 91 | 92 | [input] 93 | version = 1 94 | 95 | [coulomb] 96 | ewald = {cutoff = "6 A", accuracy = false} 97 | #^ 'accuracy' must be a number in Ewald coulombic potential 98 | -------------------------------------------------------------------------------- /lumol-input/tests/interactions/bad/dihedrals.toml: -------------------------------------------------------------------------------- 1 | [input] 2 | version = 1 3 | 4 | [dihedrals] 5 | A-A-A = {type = "null"} 6 | #^ expected four atoms for dihedral potential, got 3 (["A", "A", "A"]) 7 | 8 | +++ 9 | 10 | [input] 11 | version = 1 12 | 13 | [dihedrals] 14 | A-A-A-A-A = {type = "null"} 15 | #^ expected four atoms for dihedral potential, got 5 (["A", "A", "A", "A", "A"]) 16 | 17 | +++ 18 | 19 | [input] 20 | version = 1 21 | 22 | [dihedrals] 23 | A-A-A-A = {} 24 | #^ missing 'type' key in dihedral potential 25 | 26 | +++ 27 | 28 | [input] 29 | version = 1 30 | 31 | [dihedrals] 32 | A-A-A-A = {type = false} 33 | #^ 'type' key must be a string in dihedral potential 34 | 35 | +++ 36 | 37 | [input] 38 | version = 1 39 | 40 | [dihedrals] 41 | A-A-A-A = {type = "bad potential"} 42 | #^ unknown potential type 'bad potential' 43 | -------------------------------------------------------------------------------- /lumol-input/tests/interactions/bad/gaussian.toml: -------------------------------------------------------------------------------- 1 | [input] 2 | version = 1 3 | 4 | [pairs] 5 | A-A = {type = "gaussian", A = "3.0 A"} 6 | #^ missing 'B' key in Gaussian potential 7 | 8 | +++ 9 | 10 | [input] 11 | version = 1 12 | 13 | [pairs] 14 | A-A = {type = "gaussian", B = "-5.9 kJ/mol"} 15 | #^ missing 'A' key in Gaussian potential 16 | 17 | +++ 18 | 19 | [input] 20 | version = 1 21 | 22 | [pairs] 23 | A-A = {type = "gaussian", A = 3.0, B = "-5.9 kJ/mol"} 24 | #^ 'A' must be a string in Gaussian potential 25 | 26 | +++ 27 | 28 | [input] 29 | version = 1 30 | 31 | [pairs] 32 | A-A = {type = "gaussian", A = "3.0 A", B = -5.9} 33 | #^ 'B' must be a string in Gaussian potential 34 | 35 | +++ 36 | 37 | [input] 38 | version = 1 39 | 40 | [pairs] 41 | A-A = {type = "gaussian", A = "3.0 A", B = "-5.9 kJ/mol"} 42 | #^ 'B' parameter has to be positive in Gaussian potential 43 | -------------------------------------------------------------------------------- /lumol-input/tests/interactions/bad/harmonic.toml: -------------------------------------------------------------------------------- 1 | [input] 2 | version = 1 3 | 4 | [pairs] 5 | A-A = {type = "harmonic", x0 = "3 A"} 6 | #^ missing 'k' key in harmonic potential 7 | 8 | +++ 9 | 10 | [input] 11 | version = 1 12 | 13 | [pairs] 14 | A-A = {type = "harmonic", k = "22 kJ/mol"} 15 | #^ missing 'x0' key in harmonic potential 16 | 17 | +++ 18 | 19 | [input] 20 | version = 1 21 | 22 | [pairs] 23 | A-A = {type = "harmonic", k = "22 kJ/mol", x0 = false} 24 | #^ 'x0' must be a string in harmonic potential 25 | 26 | +++ 27 | 28 | [input] 29 | version = 1 30 | 31 | [pairs] 32 | A-A = {type = "harmonic", k = 2.2, x0 = "7 A"} 33 | #^ 'k' must be a string in harmonic potential 34 | -------------------------------------------------------------------------------- /lumol-input/tests/interactions/bad/lj.toml: -------------------------------------------------------------------------------- 1 | [input] 2 | version = 1 3 | 4 | [pairs] 5 | A-A = {type = "lj", sigma = "3 A"} 6 | #^ missing 'epsilon' key in Lennard-Jones potential 7 | 8 | +++ 9 | 10 | [input] 11 | version = 1 12 | 13 | [pairs] 14 | A-A = {type = "lj", epsilon = "300 kJ/mol"} 15 | #^ missing 'sigma' key in Lennard-Jones potential 16 | 17 | +++ 18 | 19 | [input] 20 | version = 1 21 | 22 | [pairs] 23 | A-A = {type = "lj", sigma = "3 A", epsilon = 1.3} 24 | #^ 'epsilon' must be a string in Lennard-Jones potential 25 | 26 | +++ 27 | 28 | [input] 29 | version = 1 30 | 31 | [pairs] 32 | A-A = {type = "lj", sigma = 3.0, epsilon = "133 K"} 33 | #^ 'sigma' must be a string in Lennard-Jones potential 34 | -------------------------------------------------------------------------------- /lumol-input/tests/interactions/bad/mie.toml: -------------------------------------------------------------------------------- 1 | [input] 2 | version = 1 3 | 4 | [pairs] 5 | A-A = {type = "mie", sigma = "3 A", epsilon = "5.9 kJ/mol", n = "12.0", m = 6.0} 6 | #^ 'n' must be a number in Mie potential 7 | 8 | +++ 9 | 10 | [input] 11 | version = 1 12 | 13 | [pairs] 14 | A-A = {type = "mie", sigma = "3 A", epsilon = "5.9 kJ/mol", n = 12.0, m = "6.0"} 15 | #^ 'm' must be a number in Mie potential 16 | 17 | +++ 18 | 19 | [input] 20 | version = 1 21 | 22 | [pairs] 23 | A-A = {type = "mie", sigma = 3, epsilon = "5.9 kJ/mol", n = 12.0, m = 6.0} 24 | #^ 'sigma' must be a string in Mie potential 25 | 26 | +++ 27 | 28 | [input] 29 | version = 1 30 | 31 | [pairs] 32 | A-A = {type = "mie", sigma = "3 A", epsilon = 5.9, n = 12.0, m = 6.0} 33 | #^ 'epsilon' must be a string in Mie potential 34 | 35 | +++ 36 | 37 | [input] 38 | version = 1 39 | 40 | [pairs] 41 | A-A = {type = "mie", epsilon = "5.9 kJ/mol", n = 12.0, m = 6.0} 42 | #^ missing 'sigma' key in Mie potential 43 | -------------------------------------------------------------------------------- /lumol-input/tests/interactions/bad/morse.toml: -------------------------------------------------------------------------------- 1 | [input] 2 | version = 1 3 | 4 | [pairs] 5 | A-A = {type = "morse", A = "5 A^-1", depth = "25 kJ/mol"} 6 | #^ missing 'x0' key in Morse potential 7 | 8 | +++ 9 | 10 | [input] 11 | version = 1 12 | 13 | [pairs] 14 | A-A = {type = "morse", A = "5 A^-1", x0 = "2.1 A"} 15 | #^ missing 'depth' key in Morse potential 16 | 17 | +++ 18 | 19 | [input] 20 | version = 1 21 | 22 | [pairs] 23 | A-A = {type = "morse", depth = "25 kJ/mol", x0 = "2.1 A"} 24 | #^ missing 'A' key in Morse potential 25 | 26 | +++ 27 | 28 | [input] 29 | version = 1 30 | 31 | [pairs] 32 | A-A = {type = "morse", A = 5, depth = "25 kJ/mol", x0 = "2.1 A"} 33 | #^ 'A' must be a string in Morse potential 34 | 35 | +++ 36 | 37 | [input] 38 | version = 1 39 | 40 | [pairs] 41 | A-A = {type = "morse", A = "5 A", depth = true, x0 = "2.1 A"} 42 | #^ 'depth' must be a string in Morse potential 43 | 44 | +++ 45 | 46 | [input] 47 | version = 1 48 | 49 | [pairs] 50 | A-A = {type = "morse", A = "5 A", depth = "25 kJ/mol", x0 = 2.1} 51 | #^ 'x0' must be a string in Morse potential 52 | -------------------------------------------------------------------------------- /lumol-input/tests/interactions/bad/pairs.toml: -------------------------------------------------------------------------------- 1 | [input] 2 | version = 1 3 | 4 | [pairs] 5 | A = {type = "null"} 6 | #^ expected two atoms for pair potential, got 1 (["A"]) 7 | 8 | +++ 9 | 10 | [input] 11 | version = 1 12 | 13 | [pairs] 14 | A-A-A = {type = "null"} 15 | #^ expected two atoms for pair potential, got 3 (["A", "A", "A"]) 16 | 17 | +++ 18 | 19 | [input] 20 | version = 1 21 | 22 | [pairs] 23 | A-A = {} 24 | #^ missing 'type' key in pair potential 25 | 26 | +++ 27 | 28 | [input] 29 | version = 1 30 | 31 | [pairs] 32 | A-A = {type = false} 33 | #^ 'type' key must be a string in pair potential 34 | 35 | +++ 36 | 37 | [input] 38 | version = 1 39 | 40 | [pairs] 41 | A-A = {type = "bad potential"} 42 | #^ unknown potential type 'bad potential' 43 | 44 | +++ 45 | 46 | [input] 47 | version = 1 48 | 49 | [pairs] 50 | A-A = {type = "lj", sigma = "3 A", epsilon = "5.9 kJ/mol"} 51 | #^ missing 'cutoff' value for pair potential 52 | 53 | +++ 54 | 55 | [input] 56 | version = 1 57 | 58 | [pairs] 59 | A-A = {type = "lj", sigma = "3 A", epsilon = "5.9 kJ/mol", cutoff = 5} 60 | #^ 'cutoff' must be a string or a table 61 | 62 | +++ 63 | 64 | [input] 65 | version = 1 66 | 67 | [global] 68 | #^ 'cutoff' must be a string or a table 69 | cutoff = 2 70 | 71 | [pairs] 72 | A-A = {type = "lj", sigma = "3 A", epsilon = "5.9 kJ/mol"} 73 | 74 | +++ 75 | 76 | [input] 77 | version = 1 78 | 79 | [global] 80 | cutoff = {foo = 6} 81 | #^ 'cutoff' table can only contain 'shifted' key 82 | 83 | [pairs] 84 | A-A = {type = "lj", sigma = "3 A", epsilon = "5.9 kJ/mol"} 85 | 86 | +++ 87 | 88 | [input] 89 | version = 1 90 | 91 | [global] 92 | cutoff = {shifted = 6} 93 | #^ 'cutoff.shifted' value must be a string 94 | 95 | [pairs] 96 | A-A = {type = "lj", sigma = "3 A", epsilon = "5.9 kJ/mol"} 97 | 98 | +++ 99 | 100 | [input] 101 | version = 1 102 | 103 | [global] 104 | tail_correction = "false" 105 | #^ the 'tail_correction' section must be a boolean value 106 | 107 | [pairs] 108 | A-A = {type = "lj", sigma = "3 A", epsilon = "5.9 kJ/mol"} 109 | 110 | +++ 111 | 112 | [input] 113 | version = 1 114 | 115 | [global] 116 | cutoff = "67 A" 117 | 118 | [pairs] 119 | A-A = {type = "lj", sigma = "3 A", epsilon = "5.9 kJ/mol", tail_correction = "true"} 120 | #^ the 'tail_correction' section must be a boolean value 121 | -------------------------------------------------------------------------------- /lumol-input/tests/interactions/bad/torsion.toml: -------------------------------------------------------------------------------- 1 | [input] 2 | version = 1 3 | 4 | [dihedrals] 5 | A-A-A-A = {type = "torsion", n = 4, k = "67 kJ/mol"} 6 | #^ missing 'delta' key in torsion potential 7 | 8 | +++ 9 | 10 | [input] 11 | version = 1 12 | 13 | [dihedrals] 14 | A-A-A-A = {type = "torsion", n = 4, delta = "80 deg"} 15 | #^ missing 'k' key in torsion potential 16 | 17 | +++ 18 | 19 | [input] 20 | version = 1 21 | 22 | [dihedrals] 23 | A-A-A-A = {type = "torsion", k = "67 kJ/mol", delta = "80 deg"} 24 | #^ missing 'n' key in torsion potential 25 | 26 | +++ 27 | 28 | [input] 29 | version = 1 30 | 31 | [dihedrals] 32 | A-A-A-A = {type = "torsion", n = 4, k = "67 kJ/mol", delta = 80.0} 33 | #^ 'delta' must be a string in torsion potential 34 | 35 | +++ 36 | 37 | [input] 38 | version = 1 39 | 40 | [dihedrals] 41 | A-A-A-A = {type = "torsion", n = '4', k = "67 kJ/mol", delta = "80 deg"} 42 | #^ 'n' must be a positive integer in torsion potential 43 | 44 | +++ 45 | 46 | [input] 47 | version = 1 48 | 49 | [dihedrals] 50 | A-A-A-A = {type = "torsion", n = 4, k = 6, delta = "80 deg"} 51 | #^ 'k' must be a string in torsion potential 52 | -------------------------------------------------------------------------------- /lumol-input/tests/interactions/bad/version.toml: -------------------------------------------------------------------------------- 1 | [input] 2 | #^ missing 'version' key in 'input' table 3 | 4 | +++ 5 | 6 | [input] 7 | version = "bla" 8 | #^ 'input.version' must be an integer 9 | 10 | +++ 11 | 12 | [input] 13 | version = 0 14 | #^ can only read version 1 of input, got version 0 15 | -------------------------------------------------------------------------------- /lumol-input/tests/interactions/good/angles.toml: -------------------------------------------------------------------------------- 1 | [input] 2 | version = 1 3 | 4 | [angles] 5 | A-A-A = {type = "null"} 6 | B-B-B = {type = "cosine-harmonic", k = "67 kJ/mol/deg^2", x0 = "120 deg"} 7 | C-C-C = {type = "morse", A = "30 deg^-1", depth = "25 kJ/mol", x0 = "109 deg"} 8 | D-D-D = {type = "harmonic", x0 = "80 deg", k = "5.9 kJ/mol/deg^2"} 9 | -------------------------------------------------------------------------------- /lumol-input/tests/interactions/good/bonds.toml: -------------------------------------------------------------------------------- 1 | [input] 2 | version = 1 3 | 4 | [bonds] 5 | A-A = {type = "null"} 6 | B-B = {type = "morse", A = "5 A^-1", depth = "25 kJ/mol", x0 = "2.1 A"} 7 | C-C = {type = "harmonic", x0 = "3 A", k = "5.9 kJ/mol/A^2"} 8 | -------------------------------------------------------------------------------- /lumol-input/tests/interactions/good/dihedrals.toml: -------------------------------------------------------------------------------- 1 | [input] 2 | version = 1 3 | 4 | [dihedrals] 5 | A-A-A-A = {type = "null"} 6 | B-B-B-B = {type = "harmonic", x0 = "3 A", k = "5.9 kJ/mol/A^2"} 7 | C-C-C-C = {type = "cosine-harmonic", k = "67 kJ/mol/deg^2", x0 = "120 deg"} 8 | D-D-D-D = {type = "torsion", n = 4, k = "67 kJ/mol", delta = "80 deg"} 9 | E-E-E-E = {type = "morse", A = "30 deg^-1", depth = "25 kJ/mol", x0 = "109 deg"} 10 | -------------------------------------------------------------------------------- /lumol-input/tests/interactions/good/ewald.toml: -------------------------------------------------------------------------------- 1 | [input] 2 | version = 1 3 | 4 | [coulomb] 5 | ewald = {cutoff = "189 A", kmax = 112} 6 | restriction = "exclude13" 7 | 8 | [charges] 9 | A = -8 10 | B = 3 11 | 12 | +++ 13 | 14 | [input] 15 | version = 1 16 | 17 | [coulomb] 18 | ewald = {cutoff = "189 A", kmax = 112, alpha = "0.28 A^-1"} 19 | 20 | [charges] 21 | A = -8 22 | B = 3 23 | 24 | +++ 25 | 26 | [input] 27 | version = 1 28 | 29 | [coulomb] 30 | ewald = {cutoff = "19 A", accuracy = 1e-6} 31 | 32 | [charges] 33 | A = -8 34 | B = 3 35 | -------------------------------------------------------------------------------- /lumol-input/tests/interactions/good/pairs.toml: -------------------------------------------------------------------------------- 1 | [input] 2 | version = 1 3 | 4 | [global] 5 | cutoff = "3 A" 6 | tail_correction = true 7 | 8 | [pairs] 9 | # a 'good' example for each potential type 10 | A-A = {type = "null"} 11 | B-B = {type = "lj", sigma = "3 A", epsilon = "5.9 kJ/mol"} 12 | C-C = {type = "harmonic", x0 = "3 A", k = "5.9 kJ/mol/A^2"} 13 | D-D = {type = "buckingham", A = "4.2 kJ/mol", C = "5e-6 kJ/mol/A^6", rho = "2.3 A"} 14 | E-E = {type = "morse", A = "5 A^-1", depth = "25 kJ/mol", x0 = "2.1 A"} 15 | F-F = {type = "gaussian", A = "8.0 kJ/mol", B = "50.0 A^-2"} 16 | G-G = {type = "mie", sigma = "3 A", epsilon = "5.9 kJ/mol", n = 12.0, m = 6} 17 | 18 | # specify other parameters 19 | AA-AA = {type = "null", computation = {table = {max = "8 A", n = 5000}}} 20 | BB-BB = {type = "null", restriction = "intermolecular"} 21 | CC-CC = {type = "null", restriction = "intramolecular"} 22 | DD-DD = {type = "null", restriction = "exclude12"} 23 | EE-EE = {type = "null", restriction = "exclude13"} 24 | FF-FF = {type = "null", restriction = "exclude14"} 25 | GG-GG = {type = "null", restriction = {scale14 = 0.8}} 26 | 27 | HH-HH = {type = "null", cutoff = "18 A"} 28 | II-II = {type = "null", cutoff = {shifted = "18 A"}} 29 | JJ-JJ = {type = "null", tail_correction = false} 30 | 31 | [pairs.Z-Z] 32 | type = "born" 33 | A = "4.2 kJ/mol" 34 | C = "5e-6 kJ/mol/A^6" 35 | D = "7.6e-5 kJ/mol/A^8" 36 | sigma = "3.2 A" 37 | rho = "2.3 A" 38 | -------------------------------------------------------------------------------- /lumol-input/tests/interactions/good/wolf.toml: -------------------------------------------------------------------------------- 1 | [input] 2 | version = 1 3 | 4 | [coulomb] 5 | wolf = {cutoff = "3 A"} 6 | 7 | [charges] 8 | A = -2 9 | B = 2 10 | -------------------------------------------------------------------------------- /lumol-input/tests/simulation/CO2.xyz: -------------------------------------------------------------------------------- 1 | 3 2 | CO2 molecule 3 | O 0 1 0 4 | C 0 0 0 5 | O 0 -1 0 6 | -------------------------------------------------------------------------------- /lumol-input/tests/simulation/bad/controls.toml: -------------------------------------------------------------------------------- 1 | [input] 2 | version = 1 3 | 4 | [[systems]] 5 | file = "../CO2.xyz" 6 | 7 | [[simulations]] 8 | nsteps = 1 9 | 10 | [simulations.propagator] 11 | type = "MolecularDynamics" 12 | timestep = "1.0 fs" 13 | controls = "yes" 14 | #^ 'controls' must be an array of tables in molecular dynamics 15 | 16 | +++ 17 | 18 | [input] 19 | version = 1 20 | 21 | [[systems]] 22 | file = "../CO2.xyz" 23 | 24 | [[simulations]] 25 | nsteps = 1 26 | 27 | [simulations.propagator] 28 | type = "MolecularDynamics" 29 | timestep = "1.0 fs" 30 | controls = [ 31 | 1, 2, 3 32 | ] 33 | #^ 'controls' must be an array of tables in molecular dynamics 34 | 35 | +++ 36 | 37 | [input] 38 | version = 1 39 | 40 | [[systems]] 41 | file = "../CO2.xyz" 42 | 43 | [[simulations]] 44 | nsteps = 1 45 | 46 | [simulations.propagator] 47 | type = "MolecularDynamics" 48 | timestep = "1.0 fs" 49 | controls = [ 50 | {bla = "bla"} 51 | #^ missing 'type' key in control 52 | ] 53 | 54 | +++ 55 | 56 | [input] 57 | version = 1 58 | 59 | [[systems]] 60 | file = "../CO2.xyz" 61 | 62 | [[simulations]] 63 | nsteps = 1 64 | 65 | [simulations.propagator] 66 | type = "MolecularDynamics" 67 | timestep = "1.0 fs" 68 | controls = [ 69 | {type = 67} 70 | #^ 'type' key must be a string in control 71 | ] 72 | 73 | +++ 74 | 75 | [input] 76 | version = 1 77 | 78 | [[systems]] 79 | file = "../CO2.xyz" 80 | 81 | [[simulations]] 82 | nsteps = 1 83 | 84 | [simulations.propagator] 85 | type = "MolecularDynamics" 86 | timestep = "1.0 fs" 87 | controls = [ 88 | {type = "null"} 89 | #^ unknown control 'null' 90 | ] 91 | 92 | +++ 93 | 94 | [input] 95 | version = 1 96 | 97 | [[systems]] 98 | file = "../CO2.xyz" 99 | 100 | [[simulations]] 101 | nsteps = 1 102 | 103 | [simulations.propagator] 104 | type = "MolecularDynamics" 105 | timestep = "1.0 fs" 106 | controls = [ 107 | {type = "RemoveRotation", every = 667.23} 108 | #^ 'every' must be a positive integer in RemoveRotation control 109 | ] 110 | 111 | +++ 112 | 113 | [input] 114 | version = 1 115 | 116 | [[systems]] 117 | file = "../CO2.xyz" 118 | 119 | [[simulations]] 120 | nsteps = 1 121 | 122 | [simulations.propagator] 123 | type = "MolecularDynamics" 124 | timestep = "1.0 fs" 125 | controls = [ 126 | {type = "RemoveTranslation", every = 667.23} 127 | #^ 'every' must be a positive integer in RemoveTranslation control 128 | ] 129 | 130 | +++ 131 | 132 | [input] 133 | version = 1 134 | 135 | [[systems]] 136 | file = "../CO2.xyz" 137 | 138 | [[simulations]] 139 | nsteps = 1 140 | 141 | [simulations.propagator] 142 | type = "MolecularDynamics" 143 | timestep = "1.0 fs" 144 | controls = [ 145 | {type = "Rewrap", every = 667.23} 146 | #^ 'every' must be a positive integer in Rewrap control 147 | ] 148 | -------------------------------------------------------------------------------- /lumol-input/tests/simulation/bad/integrator.toml: -------------------------------------------------------------------------------- 1 | [input] 2 | version = 1 3 | 4 | [[systems]] 5 | file = "../CO2.xyz" 6 | 7 | [[simulations]] 8 | nsteps = 1 9 | 10 | [simulations.propagator] 11 | type = "MolecularDynamics" 12 | timestep = "1.0 fs" 13 | integrator = {type = "BerendsenBarostat", press = "10 bar", timestep = 100} 14 | #^ missing 'pressure' key in Berendsen barostat 15 | 16 | +++ 17 | 18 | [input] 19 | version = 1 20 | 21 | [[systems]] 22 | file = "../CO2.xyz" 23 | 24 | [[simulations]] 25 | nsteps = 1 26 | 27 | [simulations.propagator] 28 | type = "MolecularDynamics" 29 | timestep = "1.0 fs" 30 | integrator = {type = "BerendsenBarostat", pressure = 100.0, timestep = 100} 31 | #^ 'pressure' must be a string in Berendsen barostat 32 | 33 | +++ 34 | 35 | [input] 36 | version = 1 37 | 38 | [[systems]] 39 | file = "../CO2.xyz" 40 | 41 | [[simulations]] 42 | nsteps = 1 43 | 44 | [simulations.propagator] 45 | type = "MolecularDynamics" 46 | timestep = "1.0 fs" 47 | integrator = {type = "BerendsenBarostat", pressure = "10 bar", tau = 100} 48 | #^ missing 'timestep' key in Berendsen barostat 49 | 50 | +++ 51 | 52 | [input] 53 | version = 1 54 | 55 | [[systems]] 56 | file = "../CO2.xyz" 57 | 58 | [[simulations]] 59 | nsteps = 1 60 | 61 | [simulations.propagator] 62 | type = "MolecularDynamics" 63 | timestep = "1.0 fs" 64 | integrator = {type = "BerendsenBarostat", pressure = "10 bar", timestep = "100"} 65 | #^ 'timestep' must be a number in Berendsen barostat 66 | 67 | +++ 68 | 69 | [input] 70 | version = 1 71 | 72 | [[systems]] 73 | file = "../CO2.xyz" 74 | 75 | [[simulations]] 76 | nsteps = 1 77 | 78 | [simulations.propagator] 79 | type = "MolecularDynamics" 80 | timestep = "1.0 fs" 81 | integrator = {type = "AnisoBerendsenBarostat", press = "10 bar", timestep = 100} 82 | #^ missing 'pressure' key in anisotropic Berendsen barostat 83 | 84 | +++ 85 | 86 | [input] 87 | version = 1 88 | 89 | [[systems]] 90 | file = "../CO2.xyz" 91 | 92 | [[simulations]] 93 | nsteps = 1 94 | 95 | [simulations.propagator] 96 | type = "MolecularDynamics" 97 | timestep = "1.0 fs" 98 | integrator = {type = "AnisoBerendsenBarostat", pressure = 42, timestep = 100} 99 | #^ 'pressure' must be a string in anisotropic Berendsen barostat 100 | 101 | +++ 102 | 103 | [input] 104 | version = 1 105 | 106 | [[systems]] 107 | file = "../CO2.xyz" 108 | 109 | [[simulations]] 110 | nsteps = 1 111 | 112 | [simulations.propagator] 113 | type = "MolecularDynamics" 114 | timestep = "1.0 fs" 115 | integrator = {type = "AnisoBerendsenBarostat", pressure = "10 bar", tau = 100} 116 | #^ missing 'timestep' key in anisotropic Berendsen barostat 117 | 118 | +++ 119 | 120 | [input] 121 | version = 1 122 | 123 | [[systems]] 124 | file = "../CO2.xyz" 125 | 126 | [[simulations]] 127 | nsteps = 1 128 | 129 | [simulations.propagator] 130 | type = "MolecularDynamics" 131 | timestep = "1.0 fs" 132 | integrator = {type = "AnisoBerendsenBarostat", pressure = "10 bar", timestep = "100"} 133 | #^ 'timestep' must be a number in anisotropic Berendsen barostat 134 | -------------------------------------------------------------------------------- /lumol-input/tests/simulation/bad/log.toml: -------------------------------------------------------------------------------- 1 | [input] 2 | version = 1 3 | 4 | [log] 5 | please_log = true 6 | #^ missing 'target' or 'targets' in log section 7 | 8 | +++ 9 | 10 | [input] 11 | version = 1 12 | 13 | [log] 14 | target = true 15 | targets = true 16 | #^ can not have both 'target' and 'targets' in the log section 17 | 18 | +++ 19 | 20 | [input] 21 | version = 1 22 | 23 | [log] 24 | target = true 25 | #^ 'target' must be a string in log target 26 | 27 | +++ 28 | 29 | [input] 30 | version = 1 31 | 32 | [log] 33 | targets = true 34 | #^ 'targets' must be an array in 'log' section 35 | 36 | +++ 37 | 38 | [input] 39 | version = 1 40 | 41 | [log] 42 | target = "" 43 | #^ 'target' can not be an empty string in log target 44 | 45 | +++ 46 | 47 | [input] 48 | version = 1 49 | 50 | [log] 51 | target = "" 52 | level = false 53 | #^ 'level' must be a string in log target 54 | 55 | +++ 56 | 57 | [input] 58 | version = 1 59 | 60 | [log] 61 | target = "" 62 | level = "false" 63 | #^ unknown logging level 'false' 64 | 65 | +++ 66 | 67 | [input] 68 | version = 1 69 | 70 | [log] 71 | target = "file.log" 72 | level = "info" 73 | append = 1 74 | #^ 'append' must be a boolean in log file target 75 | 76 | +++ 77 | 78 | [input] 79 | version = 1 80 | 81 | [log] 82 | target = "file.log" 83 | level = "info" 84 | verbose = true 85 | #^ unknown 'verbose' key in log section 86 | 87 | +++ 88 | 89 | [input] 90 | version = 1 91 | 92 | [log] 93 | targets = [ 94 | "foo", "" 95 | ] 96 | #^ 'targets' must be an array of tables in 'log' section 97 | -------------------------------------------------------------------------------- /lumol-input/tests/simulation/bad/mc-acceptance.toml: -------------------------------------------------------------------------------- 1 | [input] 2 | version = 1 3 | 4 | [[systems]] 5 | file = "../CO2.xyz" 6 | 7 | [[simulations]] 8 | nsteps = 1 9 | 10 | [simulations.propagator] 11 | type = "MonteCarlo" 12 | temperature = "300 K" 13 | moves = [ 14 | {type = "Rotate", delta = "6 A", frequency = 0.3, target_acceptance = "0.5"} 15 | #^ 'target_acceptance' must be a number in Monte Carlo move 16 | ] 17 | 18 | +++ 19 | 20 | [input] 21 | version = 1 22 | 23 | [[systems]] 24 | file = "../CO2.xyz" 25 | 26 | [[simulations]] 27 | nsteps = 1 28 | 29 | [simulations.propagator] 30 | type = "MonteCarlo" 31 | temperature = "300 K" 32 | moves = [ 33 | {type = "Rotate", delta = "6 A", frequency = 0.3, target_acceptance = 0.5} 34 | #^ No 'update_frequency' found. Please specify 'update_frequency' in combination with 'target_acceptance' 35 | ] 36 | 37 | +++ 38 | 39 | [input] 40 | version = 1 41 | 42 | [[systems]] 43 | file = "../CO2.xyz" 44 | 45 | [[simulations]] 46 | nsteps = 1 47 | 48 | [simulations.propagator] 49 | type = "MonteCarlo" 50 | temperature = "300 K" 51 | update_frequency = 100 52 | moves = [ 53 | {type = "Rotate", delta = "6 A", frequency = 0.3, target_acceptance = -0.1} 54 | #^ 'target_acceptance' has to be between 0.0 and 1.0 55 | ] 56 | 57 | +++ 58 | 59 | [input] 60 | version = 1 61 | 62 | [[systems]] 63 | file = "../CO2.xyz" 64 | 65 | [[simulations]] 66 | nsteps = 1 67 | 68 | [simulations.propagator] 69 | type = "MonteCarlo" 70 | temperature = "300 K" 71 | update_frequency = 100 72 | moves = [ 73 | {type = "Rotate", delta = "6 A", frequency = 0.3, target_acceptance = 3} 74 | #^ 'target_acceptance' has to be between 0.0 and 1.0 75 | ] 76 | -------------------------------------------------------------------------------- /lumol-input/tests/simulation/bad/mc-update-frequency.toml: -------------------------------------------------------------------------------- 1 | [input] 2 | version = 1 3 | 4 | [[systems]] 5 | file = "../CO2.xyz" 6 | 7 | [[simulations]] 8 | nsteps = 1 9 | 10 | [simulations.propagator] 11 | type = "MonteCarlo" 12 | temperature = "300 K" 13 | update_frequency = -1 14 | #^ 'update_frequency' must be a positive integer in Monte Carlo propagator 15 | moves = [ 16 | {type = "Rotate", delta = "6 A", frequency = 0.3, target_acceptance = 0.5} 17 | ] 18 | 19 | +++ 20 | 21 | [input] 22 | version = 1 23 | 24 | [[systems]] 25 | file = "../CO2.xyz" 26 | 27 | [[simulations]] 28 | nsteps = 1 29 | 30 | [simulations.propagator] 31 | type = "MonteCarlo" 32 | temperature = "300 K" 33 | update_frequency = "3" 34 | #^ 'update_frequency' must be a positive integer in Monte Carlo propagator 35 | moves = [ 36 | {type = "Rotate", delta = "6 A", frequency = 0.3, target_acceptance = 0.5} 37 | ] 38 | -------------------------------------------------------------------------------- /lumol-input/tests/simulation/bad/mc.toml: -------------------------------------------------------------------------------- 1 | [input] 2 | version = 1 3 | 4 | [[systems]] 5 | file = "../CO2.xyz" 6 | 7 | [[simulations]] 8 | nsteps = 1 9 | 10 | [simulations.propagator] 11 | type = "MonteCarlo" 12 | #^ missing 'temperature' key in Monte Carlo propagator 13 | 14 | +++ 15 | 16 | [input] 17 | version = 1 18 | 19 | [[systems]] 20 | file = "../CO2.xyz" 21 | 22 | [[simulations]] 23 | nsteps = 1 24 | 25 | [simulations.propagator] 26 | type = "MonteCarlo" 27 | temperature = true 28 | #^ 'temperature' must be a string in Monte Carlo propagator 29 | 30 | +++ 31 | 32 | [input] 33 | version = 1 34 | 35 | [[systems]] 36 | file = "../CO2.xyz" 37 | 38 | [[simulations]] 39 | nsteps = 1 40 | 41 | [simulations.propagator] 42 | type = "MonteCarlo" 43 | temperature = "300 K" 44 | mo = false 45 | #^ missing 'moves' key in Monte Carlo propagator 46 | 47 | +++ 48 | 49 | [input] 50 | version = 1 51 | 52 | [[systems]] 53 | file = "../CO2.xyz" 54 | 55 | [[simulations]] 56 | nsteps = 1 57 | 58 | [simulations.propagator] 59 | type = "MonteCarlo" 60 | temperature = "300 K" 61 | moves = false 62 | #^ 'moves' must be an array in Monte Carlo propagator 63 | -------------------------------------------------------------------------------- /lumol-input/tests/simulation/bad/md.toml: -------------------------------------------------------------------------------- 1 | [input] 2 | version = 1 3 | 4 | [[systems]] 5 | file = "../CO2.xyz" 6 | 7 | [[simulations]] 8 | nsteps = 1 9 | 10 | [simulations.propagator] 11 | type = "MolecularDynamics" 12 | step = "1 fs" 13 | #^ missing 'timestep' key in molecular dynamics propagator 14 | 15 | +++ 16 | 17 | [input] 18 | version = 1 19 | 20 | [[systems]] 21 | file = "../CO2.xyz" 22 | 23 | [[simulations]] 24 | nsteps = 1 25 | 26 | [simulations.propagator] 27 | type = "MolecularDynamics" 28 | timestep = 1.0 29 | #^ 'timestep' must be a string in molecular dynamics propagator 30 | 31 | +++ 32 | 33 | [input] 34 | version = 1 35 | 36 | [[systems]] 37 | file = "../CO2.xyz" 38 | 39 | [[simulations]] 40 | nsteps = 1 41 | 42 | [simulations.propagator] 43 | type = "MolecularDynamics" 44 | timestep = "1.0 fs" 45 | integrator = "yes" 46 | #^ 'integrator' must be a table in molecular dynamics 47 | 48 | +++ 49 | 50 | [input] 51 | version = 1 52 | 53 | [[systems]] 54 | file = "../CO2.xyz" 55 | 56 | [[simulations]] 57 | nsteps = 1 58 | 59 | [simulations.propagator] 60 | type = "MolecularDynamics" 61 | timestep = "1.0 fs" 62 | integrator = {typ = "BerendsenBarostat"} 63 | #^ missing 'type' key in integrator 64 | 65 | +++ 66 | 67 | [input] 68 | version = 1 69 | 70 | [[systems]] 71 | file = "../CO2.xyz" 72 | 73 | [[simulations]] 74 | nsteps = 1 75 | 76 | [simulations.propagator] 77 | type = "MolecularDynamics" 78 | timestep = "1.0 fs" 79 | integrator = {type = false} 80 | #^ 'type' key must be a string in integrator 81 | 82 | +++ 83 | 84 | [input] 85 | version = 1 86 | 87 | [[systems]] 88 | file = "../CO2.xyz" 89 | 90 | [[simulations]] 91 | nsteps = 1 92 | 93 | [simulations.propagator] 94 | type = "MolecularDynamics" 95 | timestep = "1.0 fs" 96 | integrator = {type = "null"} 97 | #^ unknown integrator 'null' 98 | -------------------------------------------------------------------------------- /lumol-input/tests/simulation/bad/minimization.toml: -------------------------------------------------------------------------------- 1 | [input] 2 | version = 1 3 | 4 | [[systems]] 5 | file = "../CO2.xyz" 6 | 7 | [[simulations]] 8 | nsteps = 1 9 | 10 | [simulations.propagator] 11 | type = "Minimization" 12 | algo = "1 fs" 13 | #^ missing 'minimizer' key in minimization propagator 14 | 15 | +++ 16 | 17 | [input] 18 | version = 1 19 | 20 | [[systems]] 21 | file = "../CO2.xyz" 22 | 23 | [[simulations]] 24 | nsteps = 1 25 | 26 | [simulations.propagator] 27 | type = "Minimization" 28 | minimizer = "1 fs" 29 | #^ 'minimizer' must be a table in minimization propagator 30 | 31 | +++ 32 | 33 | [input] 34 | version = 1 35 | 36 | [[systems]] 37 | file = "../CO2.xyz" 38 | 39 | [[simulations]] 40 | nsteps = 1 41 | 42 | [simulations.propagator] 43 | type = "Minimization" 44 | minimizer = {ty = "foo"} 45 | #^ missing 'type' key in minimizer 46 | 47 | +++ 48 | 49 | [input] 50 | version = 1 51 | 52 | [[systems]] 53 | file = "../CO2.xyz" 54 | 55 | [[simulations]] 56 | nsteps = 1 57 | 58 | [simulations.propagator] 59 | type = "Minimization" 60 | minimizer = {type = false} 61 | #^ 'type' key must be a string in minimizer 62 | 63 | +++ 64 | 65 | [input] 66 | version = 1 67 | 68 | [[systems]] 69 | file = "../CO2.xyz" 70 | 71 | [[simulations]] 72 | nsteps = 1 73 | 74 | [simulations.propagator] 75 | type = "Minimization" 76 | minimizer = {type = "foo"} 77 | #^ unknown minimizer 'foo' 78 | 79 | +++ 80 | 81 | [input] 82 | version = 1 83 | 84 | [[systems]] 85 | file = "../CO2.xyz" 86 | 87 | [[simulations]] 88 | nsteps = 1 89 | 90 | [simulations.propagator] 91 | type = "Minimization" 92 | minimizer = {type = "SteepestDescent"} 93 | tolerance = {ener = "1e-5 kJ/mol", force2 = "1e-5 kJ^2/mol^2/A^2"} 94 | #^ missing 'energy' key in minimization tolerance 95 | 96 | +++ 97 | 98 | [input] 99 | version = 1 100 | 101 | [[systems]] 102 | file = "../CO2.xyz" 103 | 104 | [[simulations]] 105 | nsteps = 1 106 | 107 | [simulations.propagator] 108 | type = "Minimization" 109 | minimizer = {type = "SteepestDescent"} 110 | tolerance = {energy = 1e-5, force2 = "1e-5 kJ^2/mol^2/A^2"} 111 | #^ 'energy' must be a string in minimization tolerance 112 | 113 | +++ 114 | 115 | [input] 116 | version = 1 117 | 118 | [[systems]] 119 | file = "../CO2.xyz" 120 | 121 | [[simulations]] 122 | nsteps = 1 123 | 124 | [simulations.propagator] 125 | type = "Minimization" 126 | minimizer = {type = "SteepestDescent"} 127 | tolerance = {energy = "1e-5 kJ^2/mol^2/A^2", forces = "1e-5 kJ^2/mol^2/A^2"} 128 | #^ missing 'force2' key in minimization tolerance 129 | 130 | +++ 131 | 132 | [input] 133 | version = 1 134 | 135 | [[systems]] 136 | file = "../CO2.xyz" 137 | 138 | [[simulations]] 139 | nsteps = 1 140 | 141 | [simulations.propagator] 142 | type = "Minimization" 143 | minimizer = {type = "SteepestDescent"} 144 | tolerance = {energy = "1e-5 kJ^2/mol^2/A^2", force2 = 1e-5} 145 | #^ 'force2' must be a string in minimization tolerance 146 | -------------------------------------------------------------------------------- /lumol-input/tests/simulation/bad/simulations.toml: -------------------------------------------------------------------------------- 1 | [input] 2 | version = 1 3 | 4 | [[systems]] 5 | file = "../CO2.xyz" 6 | 7 | [[simulations]] 8 | #^ missing 'nsteps' key in simulation 9 | 10 | [simulations.propagator] 11 | type = "MolecularDynamics" 12 | timestep = "1 fs" 13 | 14 | +++ 15 | 16 | [input] 17 | version = 1 18 | 19 | [[systems]] 20 | file = "../CO2.xyz" 21 | 22 | [[simulations]] 23 | nsteps = "56" 24 | #^ 'nsteps' key must be an integer 25 | 26 | [simulations.propagator] 27 | type = "MolecularDynamics" 28 | timestep = "1 fs" 29 | 30 | +++ 31 | 32 | [input] 33 | version = 1 34 | 35 | [[systems]] 36 | file = "../CO2.xyz" 37 | 38 | [[simulations]] 39 | nsteps = 1 40 | #^ missing 'propagator' key in simulation 41 | 42 | +++ 43 | 44 | [input] 45 | version = 1 46 | 47 | [[systems]] 48 | file = "../CO2.xyz" 49 | 50 | [[simulations]] 51 | nsteps = 1 52 | propagator = 3 53 | #^ 'propagator' must be a table in simulation 54 | 55 | +++ 56 | 57 | [input] 58 | version = 1 59 | 60 | [[systems]] 61 | file = "../CO2.xyz" 62 | 63 | [[simulations]] 64 | nsteps = 1 65 | 66 | [simulations.propagator] 67 | bla = 4 68 | #^ missing 'type' key in propagator 69 | 70 | +++ 71 | 72 | [input] 73 | version = 1 74 | 75 | [[systems]] 76 | file = "../CO2.xyz" 77 | 78 | [[simulations]] 79 | nsteps = 1 80 | 81 | [simulations.propagator] 82 | type = 4 83 | #^ 'type' key must be a string in propagator 84 | 85 | +++ 86 | 87 | [input] 88 | version = 1 89 | 90 | [[systems]] 91 | file = "../CO2.xyz" 92 | 93 | [[simulations]] 94 | nsteps = 1 95 | 96 | [simulations.propagator] 97 | type = "null" 98 | #^ unknown propagator type 'null' 99 | -------------------------------------------------------------------------------- /lumol-input/tests/simulation/bad/version.toml: -------------------------------------------------------------------------------- 1 | [input] 2 | #^ missing 'version' key in 'input' table 3 | bla = 4 4 | 5 | +++ 6 | 7 | [input] 8 | #^ can only read version 1 of input, got version 42 9 | version = 42 10 | -------------------------------------------------------------------------------- /lumol-input/tests/simulation/good/logging.toml: -------------------------------------------------------------------------------- 1 | [input] 2 | version = 1 3 | 4 | [log] 5 | targets = [ 6 | {target = "", level = "warning"}, 7 | {target = "file.log", level = "info"}, 8 | ] 9 | 10 | [[systems]] 11 | file = "../CO2.xyz" 12 | 13 | [[simulations]] 14 | nsteps = 1000000 15 | [simulations.propagator] 16 | type = "MolecularDynamics" 17 | timestep = "1.0 fs" 18 | -------------------------------------------------------------------------------- /lumol-input/tests/simulation/good/mc.toml: -------------------------------------------------------------------------------- 1 | [input] 2 | version = 1 3 | 4 | [log] 5 | target = "" 6 | level = "trace" 7 | 8 | [[systems]] 9 | file = "../CO2.xyz" 10 | cell = [] 11 | 12 | [[simulations]] 13 | nsteps = 1000000 14 | 15 | [simulations.propagator] 16 | type = "MonteCarlo" 17 | temperature = "500 K" 18 | update_frequency = 100 19 | moves = [ 20 | {type = "Translate", delta = "1 A", frequency = 2}, 21 | # The path for molecule is very long here, because we need to get the file 22 | # from a `cargo test` invocation 23 | {type = "Rotate", delta = "20 deg", molecule = "../CO2.xyz", target_acceptance = 0.5}, 24 | {type = "Resize", pressure = "5.00 bar", delta = "5 A^3", frequency = 1}, 25 | ] 26 | -------------------------------------------------------------------------------- /lumol-input/tests/simulation/good/md-1.toml: -------------------------------------------------------------------------------- 1 | [input] 2 | version = 1 3 | 4 | [log] 5 | target = "file.log" 6 | level = "debug" 7 | append = true 8 | 9 | [[systems]] 10 | file = "../CO2.xyz" 11 | 12 | [[simulations]] 13 | nsteps = 1000000 14 | outputs = [ 15 | {type = "Trajectory", file = "filename.xyz", frequency = 100}, 16 | {type = "Energy", file = "energy.dat", frequency = 200} 17 | ] 18 | 19 | [simulations.propagator] 20 | type = "MolecularDynamics" 21 | timestep = "1 fs" 22 | integrator = {type = "BerendsenBarostat", pressure = "100 bar", timestep = 1000} 23 | thermostat = {type = "Berendsen", temperature = "400 K", timestep = 100} 24 | controls = [ 25 | {type = "RemoveRotation", every = 10}, 26 | {type = "RemoveTranslation"}, 27 | {type = "Rewrap"}, 28 | ] 29 | -------------------------------------------------------------------------------- /lumol-input/tests/simulation/good/md-2.toml: -------------------------------------------------------------------------------- 1 | [input] 2 | version = 1 3 | 4 | [log] 5 | target = "" 6 | 7 | [[systems]] 8 | file = "../CO2.xyz" 9 | 10 | [[simulations]] 11 | nsteps = 1000000 12 | outputs = [ 13 | {type = "Cell", file = "cell.dat"}, 14 | {type = "Properties", file = "properties.dat"}, 15 | {type = "stress", file = "stress.dat"}, 16 | ] 17 | 18 | [simulations.propagator] 19 | type = "MolecularDynamics" 20 | timestep = "1 fs" 21 | integrator = {type = "LeapFrog"} 22 | thermostat = {type = "Rescale", temperature = "400 K", tolerance = "10 K"} 23 | -------------------------------------------------------------------------------- /lumol-input/tests/simulation/good/md-3.toml: -------------------------------------------------------------------------------- 1 | [input] 2 | version = 1 3 | 4 | [log] 5 | target = "" 6 | 7 | [[systems]] 8 | file = "../CO2.xyz" 9 | cell = [10.0, 10.0, 10.0, 90.0, 90.0, 110.0] 10 | 11 | [[simulations]] 12 | nsteps = 1000000 13 | 14 | [simulations.propagator] 15 | type = "MolecularDynamics" 16 | timestep = "1 fs" 17 | integrator = {type = "VelocityVerlet"} 18 | thermostat = {type = "CSVR", temperature = "333 K", timestep = 132.45} 19 | -------------------------------------------------------------------------------- /lumol-input/tests/simulation/good/md-4.toml: -------------------------------------------------------------------------------- 1 | [input] 2 | version = 1 3 | 4 | [[systems]] 5 | file = "../CO2.xyz" 6 | 7 | [[simulations]] 8 | nsteps = 1000000 9 | 10 | [simulations.propagator] 11 | type = "MolecularDynamics" 12 | timestep = "1 fs" 13 | integrator = {type = "Verlet"} 14 | -------------------------------------------------------------------------------- /lumol-input/tests/simulation/good/md.toml: -------------------------------------------------------------------------------- 1 | [input] 2 | version = 1 3 | 4 | [[systems]] 5 | file = "../CO2.xyz" 6 | 7 | [[simulations]] 8 | nsteps = 1000000 9 | outputs = [ 10 | {type = "Trajectory", file = "filename.xyz", frequency = 100}, 11 | {type = "Energy", file = "energy.dat", frequency = 200}, 12 | {type = "Forces", file = "forces.xyz", frequency = 200}, 13 | {type = "Custom", file = "custom.dat", template = "{temperature / pressure}", frequency = 200} 14 | ] 15 | 16 | [simulations.propagator] 17 | type = "MolecularDynamics" 18 | timestep = "1 fs" 19 | integrator = {type = "BerendsenBarostat", pressure = "100 bar", timestep = 1000} 20 | thermostat = {type = "Berendsen", temperature = "400 K", timestep = 100} 21 | controls = [ 22 | {type = "RemoveRotation", every = 10}, 23 | {type = "RemoveTranslation"} 24 | ] 25 | -------------------------------------------------------------------------------- /lumol-input/tests/simulation/good/min.toml: -------------------------------------------------------------------------------- 1 | [input] 2 | version = 1 3 | 4 | [[systems]] 5 | file = "../CO2.xyz" 6 | 7 | [[simulations]] 8 | nsteps = 1000000 9 | 10 | [simulations.propagator] 11 | type = "Minimization" 12 | minimizer = {type = "SteepestDescent"} 13 | tolerance = {energy = "1e-5 kJ/mol", force2 = "1e-5 kJ^2/mol^2/A^2"} 14 | -------------------------------------------------------------------------------- /lumol-input/tests/simulation/good/potentials.toml: -------------------------------------------------------------------------------- 1 | [input] 2 | version = 1 3 | 4 | [[systems]] 5 | cell = 20 6 | file = "../CO2.xyz" 7 | guess_bonds = true 8 | velocities = {init = "300 K"} 9 | 10 | # inline potentials 11 | [systems.potentials.global] 12 | cutoff = "10 A" 13 | 14 | [systems.potentials.pairs] 15 | C-O = {type = "lj", sigma = "3 A", epsilon = "5 kJ/mol"} 16 | 17 | [systems.potentials.bonds] 18 | C-O = {type = "harmonic", x0 = "3 A", k = "5 kJ/mol"} 19 | 20 | [systems.potentials.charges] 21 | C = 0.8 22 | O = -0.4 23 | 24 | [[simulations]] 25 | nsteps = 1 26 | [simulations.propagator] 27 | type = "MolecularDynamics" 28 | timestep = "1 fs" 29 | -------------------------------------------------------------------------------- /lumol-input/tests/simulation/good/system.toml: -------------------------------------------------------------------------------- 1 | [input] 2 | version = 1 3 | 4 | [[systems]] 5 | cell = 50.0 6 | file = "../CO2.xyz" 7 | guess_bonds = true 8 | velocities = {init = "300 K"} 9 | potentials = "../../interactions/good/pairs.toml" 10 | 11 | [[simulations]] 12 | nsteps = 1 13 | [simulations.propagator] 14 | type = "MolecularDynamics" 15 | timestep = "1 fs" 16 | -------------------------------------------------------------------------------- /lumol-sim/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "lumol-sim" 3 | version = "0.0.0" 4 | authors = ["Luthaf "] 5 | documentation = "https://lumol.org/" 6 | repository = "https://github.com/lumol-org/lumol" 7 | readme = "../README.md" 8 | license = "BSD-3-Clause" 9 | edition = "2018" 10 | 11 | [lib] 12 | bench = false 13 | 14 | [dependencies] 15 | lumol-core = {path = "../lumol-core"} 16 | rand = "0.8" 17 | rand_distr = "0.4" 18 | rand_xorshift = "0.3" 19 | log = "0.4" 20 | log-once = "0.4" 21 | caldyn = "0.4" 22 | soa_derive = "0.13" 23 | num-traits = "0.2" 24 | 25 | [dev-dependencies] 26 | tempfile = "3" 27 | approx = "0.5" 28 | -------------------------------------------------------------------------------- /lumol-sim/src/lib.rs: -------------------------------------------------------------------------------- 1 | // Lumol, an extensible molecular simulation engine 2 | // Copyright (C) Lumol's contributors — BSD license 3 | 4 | //! Simulation algorithms for lumol 5 | 6 | #![warn(missing_docs, trivial_casts, unused_import_braces, variant_size_differences)] 7 | #![warn(unused_qualifications, unused_results, rust_2018_idioms)] 8 | // Clippy configuration 9 | #![warn(clippy::all, clippy::pedantic)] 10 | // Not embed software, integer and float arithmetic are allowed 11 | #![allow(clippy::float_arithmetic, clippy::indexing_slicing)] 12 | // Cast issues 13 | #![allow(clippy::cast_possible_truncation, clippy::cast_precision_loss)] 14 | #![allow(clippy::cast_sign_loss, clippy::cast_possible_wrap)] 15 | // Style issues 16 | #![allow(clippy::shadow_reuse, clippy::shadow_same, clippy::shadow_unrelated)] 17 | #![allow(clippy::use_self, clippy::redundant_field_names, clippy::or_fun_call)] 18 | #![allow(clippy::needless_return, clippy::needless_range_loop, clippy::doc_markdown)] 19 | #![allow(clippy::missing_docs_in_private_items, clippy::module_name_repetitions)] 20 | #![allow(clippy::new_without_default, clippy::range_plus_one, clippy::missing_panics_doc)] 21 | #![allow(clippy::if_not_else, clippy::redundant_closure_for_method_calls)] 22 | #![allow(clippy::must_use_candidate, clippy::return_self_not_must_use, clippy::redundant_else)] 23 | 24 | #![allow(clippy::missing_errors_doc)] 25 | 26 | // Tests lints 27 | #![cfg_attr(test, allow(clippy::float_cmp))] 28 | 29 | // deny(warnings) in doc tests 30 | #![doc(test(attr(deny(warnings))))] 31 | #![doc(test(attr(allow(unused_variables))))] 32 | 33 | mod propagator; 34 | pub use self::propagator::Propagator; 35 | pub use self::propagator::TemperatureStrategy; 36 | 37 | pub mod output; 38 | pub mod md; 39 | pub mod mc; 40 | pub mod min; 41 | 42 | mod simulations; 43 | pub use self::mc::MonteCarlo; 44 | pub use self::md::MolecularDynamics; 45 | pub use self::min::Minimization; 46 | pub use self::simulations::Simulation; 47 | 48 | mod velocities; 49 | pub use self::velocities::{InitVelocities, BoltzmannVelocities, UniformVelocities}; 50 | -------------------------------------------------------------------------------- /lumol-sim/src/mc/mod.rs: -------------------------------------------------------------------------------- 1 | // Lumol, an extensible molecular simulation engine 2 | // Copyright (C) Lumol's contributors — BSD license 3 | 4 | //! Metropolis Monte Carlo related algorithms 5 | mod monte_carlo; 6 | pub use self::monte_carlo::{MonteCarlo, MonteCarloBuilder}; 7 | 8 | mod moves; 9 | pub use self::moves::{MCDegreeOfFreedom, MCMove}; 10 | pub use self::moves::{Resize, Rotate, Translate}; 11 | -------------------------------------------------------------------------------- /lumol-sim/src/md/molecular_dynamics.rs: -------------------------------------------------------------------------------- 1 | // Lumol, an extensible molecular simulation engine 2 | // Copyright (C) Lumol's contributors — BSD license 3 | 4 | use crate::propagator::{Propagator, TemperatureStrategy}; 5 | use lumol_core::{System, DegreesOfFreedom}; 6 | 7 | use super::{Control, Integrator, Thermostat}; 8 | use super::VelocityVerlet; 9 | 10 | /// Molecular Dynamics propagator for the simulation. 11 | pub struct MolecularDynamics { 12 | /// The integrator we should use to propagate the equations of motion. 13 | integrator: Box, 14 | /// Optional thermostat algorithm 15 | thermostat: Option>, 16 | /// Control algorithms in the simulation. 17 | controls: Vec>, 18 | } 19 | 20 | impl MolecularDynamics { 21 | /// Create a new `MolecularDynamics` propagator using a `VelocityVerlet` 22 | /// integrator. 23 | pub fn new(dt: f64) -> MolecularDynamics { 24 | MolecularDynamics::from_integrator(Box::new(VelocityVerlet::new(dt))) 25 | } 26 | 27 | /// Create a new `MolecularDynamics` propagator using the specified 28 | /// `integrator`. 29 | pub fn from_integrator(integrator: Box) -> MolecularDynamics { 30 | MolecularDynamics { 31 | integrator: integrator, 32 | thermostat: None, 33 | controls: Vec::new(), 34 | } 35 | } 36 | 37 | /// Add a control algorithm to the internal list of controls. 38 | pub fn add_control(&mut self, control: Box) { 39 | self.controls.push(control); 40 | } 41 | 42 | /// Set the thermostat to use with this simulation 43 | pub fn set_thermostat(&mut self, thermostat: Box) { 44 | self.thermostat = Some(thermostat); 45 | } 46 | } 47 | 48 | impl Propagator for MolecularDynamics { 49 | fn temperature_strategy(&self) -> TemperatureStrategy { 50 | TemperatureStrategy::Velocities 51 | } 52 | 53 | fn degrees_of_freedom(&self, _: &System) -> DegreesOfFreedom { 54 | // default to particles for now. change this if/when constrains are 55 | // implemented 56 | DegreesOfFreedom::Particles 57 | } 58 | 59 | fn setup(&mut self, system: &System) { 60 | self.integrator.setup(system); 61 | for control in &mut self.controls { 62 | control.setup(system); 63 | } 64 | } 65 | 66 | fn propagate(&mut self, system: &mut System) { 67 | self.integrator.integrate(system); 68 | 69 | if let Some(ref mut thermostat) = self.thermostat { 70 | thermostat.apply(system); 71 | } 72 | 73 | for control in &mut self.controls { 74 | control.control(system); 75 | } 76 | } 77 | 78 | fn finish(&mut self, system: &System) { 79 | for control in &mut self.controls { 80 | control.finish(system); 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /lumol-sim/src/min/mod.rs: -------------------------------------------------------------------------------- 1 | // Lumol, an extensible molecular simulation engine 2 | // Copyright (C) Lumol's contributors — BSD license 3 | 4 | //! Energy minimization algorithms 5 | 6 | mod minimization; 7 | pub use self::minimization::Minimization; 8 | pub use self::minimization::Minimizer; 9 | pub use self::minimization::Tolerance; 10 | 11 | mod steepest_descent; 12 | pub use self::steepest_descent::SteepestDescent; 13 | -------------------------------------------------------------------------------- /lumol-sim/src/output/cell.rs: -------------------------------------------------------------------------------- 1 | // Lumol, an extensible molecular simulation engine 2 | // Copyright (C) Lumol's contributors — BSD license 3 | 4 | use std::fs::File; 5 | use std::io::{self, BufWriter}; 6 | use std::io::prelude::*; 7 | use std::path::{Path, PathBuf}; 8 | 9 | use log::error; 10 | 11 | use super::Output; 12 | use lumol_core::System; 13 | 14 | /// The `CellOutput` writes all the components of a cell to a file . The columns 15 | /// in the file contain the following values: `step A B C α β γ`. 16 | pub struct CellOutput { 17 | file: BufWriter, 18 | path: PathBuf, 19 | } 20 | 21 | impl CellOutput { 22 | /// Create a new `CellOutput` writing to `filename`. The file is replaced if 23 | /// it already exists. 24 | pub fn new>(filename: P) -> Result { 25 | Ok(CellOutput { 26 | file: BufWriter::new(File::create(filename.as_ref())?), 27 | path: filename.as_ref().to_owned(), 28 | }) 29 | } 30 | } 31 | 32 | impl Output for CellOutput { 33 | #[allow(clippy::non_ascii_literal)] 34 | fn setup(&mut self, _: &System) { 35 | writeln_or_log!(self, "# Unit cell of the simulation"); 36 | writeln_or_log!(self, "# Step A/Å B/Å C/Å α/deg β/deg γ/deg"); 37 | } 38 | 39 | fn write(&mut self, system: &System) { 40 | writeln_or_log!(self, "{} {} {} {} {} {} {}", 41 | system.step, 42 | system.cell.a(), 43 | system.cell.b(), 44 | system.cell.c(), 45 | system.cell.alpha(), 46 | system.cell.beta(), 47 | system.cell.gamma() 48 | ); 49 | } 50 | } 51 | 52 | #[cfg(test)] 53 | #[allow(clippy::non_ascii_literal)] 54 | mod tests { 55 | use super::*; 56 | use super::super::tests::test_output; 57 | 58 | #[test] 59 | fn cell() { 60 | test_output( 61 | |path| Box::new(CellOutput::new(path).unwrap()), 62 | "# Unit cell of the simulation 63 | # Step A/Å B/Å C/Å α/deg β/deg γ/deg 64 | 42 10 10 10 90 90 90 65 | ", 66 | ); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /lumol-sim/src/output/energy.rs: -------------------------------------------------------------------------------- 1 | // Lumol, an extensible molecular simulation engine 2 | // Copyright (C) Lumol's contributors — BSD license 3 | 4 | use std::fs::File; 5 | use std::io::{self, BufWriter}; 6 | use std::io::prelude::*; 7 | use std::path::{Path, PathBuf}; 8 | 9 | use log::error; 10 | 11 | use super::Output; 12 | use lumol_core::System; 13 | use lumol_core::units; 14 | 15 | /// The `EnergyOutput` writes the energy of the system to a text file, organized 16 | /// as: `steps PotentialEnergy KineticEnergy TotalEnergy`. 17 | pub struct EnergyOutput { 18 | file: BufWriter, 19 | path: PathBuf, 20 | } 21 | 22 | impl EnergyOutput { 23 | /// Create a new `EnergyOutput` writing to `filename`. The file is replaced 24 | /// if it already exists. 25 | pub fn new>(filename: P) -> Result { 26 | Ok(EnergyOutput { 27 | file: BufWriter::new(File::create(filename.as_ref())?), 28 | path: filename.as_ref().to_owned(), 29 | }) 30 | } 31 | } 32 | 33 | impl Output for EnergyOutput { 34 | fn setup(&mut self, _: &System) { 35 | writeln_or_log!(self, "# Energy of the simulation (kJ/mol)"); 36 | writeln_or_log!(self, "# Step Potential Kinetic Total"); 37 | } 38 | 39 | fn write(&mut self, system: &System) { 40 | let potential = units::to(system.potential_energy(), "kJ/mol").expect("bad unit"); 41 | let kinetic = units::to(system.kinetic_energy(), "kJ/mol").expect("bad unit"); 42 | let total = units::to(system.total_energy(), "kJ/mol").expect("bad unit"); 43 | writeln_or_log!(self, "{} {} {} {}", system.step, potential, kinetic, total); 44 | } 45 | } 46 | 47 | #[cfg(test)] 48 | mod tests { 49 | use super::*; 50 | use super::super::tests::test_output; 51 | 52 | #[test] 53 | fn energy() { 54 | test_output( 55 | |path| Box::new(EnergyOutput::new(path).unwrap()), 56 | "# Energy of the simulation (kJ/mol) 57 | # Step Potential Kinetic Total 58 | 42 1.5000000000000027 949.9201593348566 951.4201593348566 59 | ", 60 | ); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /lumol-sim/src/output/forces.rs: -------------------------------------------------------------------------------- 1 | // Lumol, an extensible molecular simulation engine 2 | // Copyright (C) Lumol's contributors — BSD license 3 | 4 | use std::fs::File; 5 | use std::io::{self, BufWriter}; 6 | use std::io::prelude::*; 7 | use std::path::{Path, PathBuf}; 8 | 9 | use log::error; 10 | 11 | use super::Output; 12 | use lumol_core::System; 13 | use lumol_core::units; 14 | 15 | /// The `ForcesOutput` writes the forces acting on the atoms using XYZ format 16 | pub struct ForcesOutput { 17 | file: BufWriter, 18 | path: PathBuf, 19 | } 20 | 21 | impl ForcesOutput { 22 | /// Create a new `ForcesOutput` writing to `filename`. The file is replaced 23 | /// if it already exists. 24 | pub fn new>(filename: P) -> Result { 25 | Ok(ForcesOutput { 26 | file: BufWriter::new(File::create(filename.as_ref())?), 27 | path: filename.as_ref().to_owned(), 28 | }) 29 | } 30 | } 31 | 32 | impl Output for ForcesOutput { 33 | fn setup(&mut self, _: &System) {} 34 | 35 | fn write(&mut self, system: &System) { 36 | let forces = system.forces(); 37 | let names = system.particles().name; 38 | let conversion = units::to(1.0, "kJ/mol/A").expect("bad unit"); 39 | 40 | writeln_or_log!(self, "{}", forces.len()); 41 | writeln_or_log!(self, "forces in kJ/mol/A at step {}", system.step); 42 | for (i, force) in forces.iter().enumerate() { 43 | let x = conversion * force[0]; 44 | let y = conversion * force[1]; 45 | let z = conversion * force[2]; 46 | writeln_or_log!(self, "{} {} {} {}", names[i], x, y, z); 47 | } 48 | } 49 | } 50 | 51 | #[cfg(test)] 52 | mod tests { 53 | use super::*; 54 | use super::super::tests::test_output; 55 | 56 | #[test] 57 | fn energy() { 58 | test_output( 59 | |path| Box::new(ForcesOutput::new(path).unwrap()), 60 | "2 61 | forces in kJ/mol/A at step 42 62 | F 30.000000000000025 0 0 63 | F -30.000000000000025 0 0 64 | ", 65 | ); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /lumol-sim/src/output/mod.rs: -------------------------------------------------------------------------------- 1 | // Lumol, an extensible molecular simulation engine 2 | // Copyright (C) Lumol's contributors — BSD license 3 | 4 | //! Saving properties of a system during a simulation 5 | 6 | use lumol_core::System; 7 | 8 | /// The `Output` trait defines the interface for all the quantities outputted by 9 | /// the simulation during the run. An Output can be a text or a binary data 10 | /// file, an image, a text log, … 11 | pub trait Output { 12 | /// Function called once at the beginning of the simulation, which allows 13 | /// for some setup of the output if needed. 14 | fn setup(&mut self, _: &System) {} 15 | 16 | /// Write the output from the system. 17 | fn write(&mut self, system: &System); 18 | 19 | /// Function called once at the end of the simulation. 20 | fn finish(&mut self, _: &System) {} 21 | } 22 | 23 | mod tests; 24 | 25 | macro_rules! writeln_or_log { 26 | ($this: expr, $($args: expr),* $(,)*) => ( 27 | if let Err(err) = writeln!(&mut $this.file, $($args,)*) { 28 | error!("could not write to file '{}': {}", $this.path.display(), err); 29 | return; 30 | } 31 | ); 32 | } 33 | 34 | mod cell; 35 | pub use self::cell::CellOutput; 36 | 37 | mod stress; 38 | pub use self::stress::StressOutput; 39 | 40 | mod energy; 41 | pub use self::energy::EnergyOutput; 42 | 43 | mod custom; 44 | pub use self::custom::{CustomOutput, CustomOutputError}; 45 | 46 | mod forces; 47 | pub use self::forces::ForcesOutput; 48 | 49 | mod properties; 50 | pub use self::properties::PropertiesOutput; 51 | 52 | mod trajectory; 53 | pub use self::trajectory::TrajectoryOutput; 54 | -------------------------------------------------------------------------------- /lumol-sim/src/output/properties.rs: -------------------------------------------------------------------------------- 1 | // Lumol, an extensible molecular simulation engine 2 | // Copyright (C) Lumol's contributors — BSD license 3 | 4 | use std::fs::File; 5 | use std::io::{self, BufWriter}; 6 | use std::io::prelude::*; 7 | use std::path::{Path, PathBuf}; 8 | 9 | use log::error; 10 | 11 | use super::Output; 12 | 13 | use lumol_core::System; 14 | use lumol_core::units; 15 | 16 | /// The `PropertiesOutput` write various physical properties of the system to 17 | /// a file. These properties are: 18 | /// 19 | /// - volume of the unit cell; 20 | /// - instant temperature; 21 | /// - instant pressure; 22 | pub struct PropertiesOutput { 23 | file: BufWriter, 24 | path: PathBuf, 25 | } 26 | 27 | impl PropertiesOutput { 28 | /// Create a new `PropertiesOutput` writing to `filename`. The file is replaced 29 | /// if it already exists. 30 | pub fn new>(filename: P) -> Result { 31 | Ok(PropertiesOutput { 32 | file: BufWriter::new(File::create(filename.as_ref())?), 33 | path: filename.as_ref().to_owned(), 34 | }) 35 | } 36 | } 37 | 38 | impl Output for PropertiesOutput { 39 | fn setup(&mut self, _: &System) { 40 | writeln_or_log!(self, "# Physical properties of the simulation"); 41 | writeln_or_log!(self, "# Step Volume/A^3 Temperature/K Pressure/bar"); 42 | } 43 | 44 | fn write(&mut self, system: &System) { 45 | let volume = units::to(system.volume(), "A^3").expect("bad unit"); 46 | let temperature = units::to(system.temperature(), "K").expect("bad unit"); 47 | let pressure = units::to(system.pressure(), "bar").expect("bad unit"); 48 | writeln_or_log!(self, "{} {} {} {}", system.step, volume, temperature, pressure); 49 | } 50 | } 51 | 52 | #[cfg(test)] 53 | mod tests { 54 | use super::*; 55 | use super::super::tests::test_output; 56 | 57 | #[test] 58 | fn properties() { 59 | test_output( 60 | |path| Box::new(PropertiesOutput::new(path).unwrap()), 61 | "# Physical properties of the simulation 62 | # Step Volume/A^3 Temperature/K Pressure/bar 63 | 42 1000 38083.04389172312 10299.991728079816 64 | ", 65 | ); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /lumol-sim/src/output/stress.rs: -------------------------------------------------------------------------------- 1 | // Lumol, an extensible molecular simulation engine 2 | // Copyright (C) Lumol's contributors — BSD license 3 | 4 | use std::fs::File; 5 | use std::io::{self, BufWriter}; 6 | use std::io::prelude::*; 7 | use std::path::{Path, PathBuf}; 8 | 9 | use log::error; 10 | 11 | use super::Output; 12 | use lumol_core::System; 13 | use lumol_core::units; 14 | 15 | /// The `StressOutput` writes the stress of the system to a text file, organized 16 | /// as: `step stress.xx stress.yy stress.zz stress.xy stress.xz stress.yz`. 17 | pub struct StressOutput { 18 | file: BufWriter, 19 | path: PathBuf, 20 | } 21 | 22 | impl StressOutput { 23 | /// Create a new `StressOutput` writing to `filename`. The file is replaced 24 | /// if it already exists. 25 | pub fn new>(filename: P) -> Result { 26 | Ok(StressOutput { 27 | file: BufWriter::new(File::create(filename.as_ref())?), 28 | path: filename.as_ref().to_owned(), 29 | }) 30 | } 31 | } 32 | 33 | impl Output for StressOutput { 34 | fn setup(&mut self, _: &System) { 35 | if let Err(err) = writeln!(&mut self.file, "# Stress tensor of the simulation (bar)") { 36 | panic!("Could not write to file '{}': {}", self.path.display(), err); 37 | } 38 | if let Err(err) = writeln!( 39 | &mut self.file, 40 | "# step stress.xx stress.yy stress.zz stress.xy stress.xz stress.yz" 41 | ) { 42 | panic!("Could not write to file '{}': {}", self.path.display(), err); 43 | } 44 | } 45 | 46 | fn write(&mut self, system: &System) { 47 | let conversion = units::to(1.0, "bar").expect("bad unit"); 48 | let stress = system.stress(); 49 | let xx = stress[0][0] * conversion; 50 | let yy = stress[1][1] * conversion; 51 | let zz = stress[2][2] * conversion; 52 | let xy = stress[0][1] * conversion; 53 | let xz = stress[0][2] * conversion; 54 | let yz = stress[1][2] * conversion; 55 | writeln_or_log!(self, "{} {} {} {} {} {} {}", system.step, xx, yy, zz, xy, xz, yz); 56 | } 57 | } 58 | 59 | #[cfg(test)] 60 | mod tests { 61 | use super::*; 62 | use super::super::tests::test_output; 63 | 64 | #[test] 65 | fn energy() { 66 | test_output( 67 | |path| Box::new(StressOutput::new(path).unwrap()), 68 | "# Stress tensor of the simulation (bar) 69 | # step stress.xx stress.yy stress.zz stress.xy stress.xz stress.yz 70 | 42 30899.975184239443 0 0 0 0 0 71 | ", 72 | ); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /lumol-sim/src/output/tests.rs: -------------------------------------------------------------------------------- 1 | // Lumol, an extensible molecular simulation engine 2 | // Copyright (C) Lumol's contributors — BSD license 3 | 4 | //! Utilities to test the output algorithms 5 | 6 | #![cfg(test)] 7 | 8 | use tempfile::NamedTempFile; 9 | 10 | use std::fs::File; 11 | use std::io::prelude::*; 12 | use std::path::Path; 13 | 14 | use super::Output; 15 | use lumol_core::energy::{Harmonic, PairInteraction}; 16 | use lumol_core::{System, Molecule, Particle, UnitCell}; 17 | use lumol_core::units; 18 | 19 | pub fn test_output(function: F, expected: &str) 20 | where 21 | F: Fn(&Path) -> Box, 22 | { 23 | let tempfile = NamedTempFile::new().unwrap(); 24 | let system = testing_system(); 25 | { 26 | let mut output = function(tempfile.path()); 27 | output.setup(&system); 28 | output.write(&system); 29 | output.finish(&system); 30 | } 31 | 32 | let file = tempfile.reopen().unwrap(); 33 | check_file_content(file, expected); 34 | } 35 | 36 | pub fn testing_system() -> System { 37 | let mut system = System::with_cell(UnitCell::cubic(10.0)); 38 | system.add_molecule(Molecule::new(Particle::with_position("F", [0.0, 0.0, 0.0].into()))); 39 | system.add_molecule(Molecule::new(Particle::with_position("F", [1.3, 0.0, 0.0].into()))); 40 | 41 | system.particles_mut().velocity[0] = [0.1, 0.0, 0.0].into(); 42 | system.particles_mut().velocity[1] = [0.0, 0.0, 0.0].into(); 43 | 44 | let harmonic = Box::new(Harmonic { 45 | k: units::from(300.0, "kJ/mol/A^2").unwrap(), 46 | x0: units::from(1.2, "A").unwrap(), 47 | }); 48 | system.set_pair_potential(("F", "F"), PairInteraction::new(harmonic, 5.0)); 49 | system.step = 42; 50 | return system; 51 | } 52 | 53 | fn check_file_content(mut file: File, content: &str) { 54 | let mut buffer = String::new(); 55 | let _ = file.read_to_string(&mut buffer).unwrap(); 56 | 57 | for (l1, l2) in buffer.lines().zip(content.lines()) { 58 | assert_eq!(l1, l2.trim_start()); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /lumol-sim/src/output/trajectory.rs: -------------------------------------------------------------------------------- 1 | // Lumol, an extensible molecular simulation engine 2 | // Copyright (C) Lumol's contributors — BSD license 3 | 4 | use std::path::Path; 5 | 6 | use super::Output; 7 | 8 | use lumol_core::{OpenMode, Trajectory, TrajectoryBuilder, TrajectoryError}; 9 | use lumol_core::System; 10 | 11 | /// The `TrajectoryOutput` allows to write the trajectory of the system to a 12 | /// file, using any format supported by the [Chemfiles][chemfiles] library. 13 | /// 14 | /// [chemfiles]: http://chemfiles.github.io 15 | pub struct TrajectoryOutput { 16 | file: Trajectory, 17 | } 18 | 19 | impl TrajectoryOutput { 20 | /// Create a new `TrajectoryOutput` writing to `filename`. The file is 21 | /// replaced if it already exists. The file format is guessed from the 22 | /// extension. Please refer to the list of [supported formats][formats] 23 | /// for more information. 24 | /// 25 | /// [formats]: http://chemfiles.org/chemfiles/latest/formats.html 26 | pub fn new

(path: P) -> Result 27 | where 28 | P: AsRef, 29 | { 30 | let builder = TrajectoryBuilder::new().mode(OpenMode::Write); 31 | Ok(TrajectoryOutput { 32 | file: builder.open(path)? 33 | }) 34 | } 35 | 36 | /// Create a new `TrajectoryOutput` writing to `filename` using the given 37 | /// `format`. The file is replaced if it already exists. 38 | /// 39 | /// Please refer to the list of [supported formats][formats] for more 40 | /// information. 41 | /// 42 | /// [formats]: http://chemfiles.org/chemfiles/latest/formats.html 43 | pub fn with_format

(path: P, format: &str) -> Result 44 | where 45 | P: AsRef, 46 | { 47 | let builder = TrajectoryBuilder::new().mode(OpenMode::Write).format(format); 48 | Ok(TrajectoryOutput { 49 | file: builder.open(path)? 50 | }) 51 | } 52 | } 53 | 54 | impl Output for TrajectoryOutput { 55 | fn write(&mut self, system: &System) { 56 | match self.file.write(system) { 57 | Ok(()) => (), 58 | Err(err) => { 59 | panic!("Error in while writing trajectory: {}", err); 60 | } 61 | } 62 | } 63 | } 64 | 65 | #[cfg(test)] 66 | mod tests { 67 | use super::*; 68 | use super::super::tests::test_output; 69 | 70 | #[test] 71 | fn cell() { 72 | test_output( 73 | |path| Box::new(TrajectoryOutput::with_format(path, "XYZ").unwrap()), 74 | "2 75 | Properties=species:S:1:pos:R:3 Lattice=\"10 0 0 0 10 0 0 0 10\" 76 | F 0 0 0 77 | F 1.3 0 0 78 | ", 79 | ); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /lumol-sim/src/propagator.rs: -------------------------------------------------------------------------------- 1 | // Lumol, an extensible molecular simulation engine 2 | // Copyright (C) Lumol's contributors — BSD license 3 | 4 | //! A propagator is responsible for updating the system during a simulation 5 | use lumol_core::{System, DegreesOfFreedom}; 6 | 7 | /// Possible temperature computation strategies. Different propagators needs 8 | /// different ways to compute the temperature: Monte Carlo temperature is a 9 | /// constant of the simulation, whereas for molecular dynamics we use the 10 | /// instantaneous velocities. 11 | #[derive(Clone, PartialEq, Debug)] 12 | pub enum TemperatureStrategy { 13 | /// No specific strategy, use whatever strategy was already in use. 14 | None, 15 | /// Use the instantaneous velocities to compute the temperature 16 | Velocities, 17 | /// Use a fixed external temperature 18 | External(f64), 19 | } 20 | 21 | /// The propagator trait is the main algorithm of a simulation, i.e. the one 22 | /// which update the system. The main function here is `propagate`, which 23 | /// should propagate the simulation for one step. 24 | pub trait Propagator { 25 | /// Get the temperature computation strategy for this propagator. 26 | /// 27 | /// This function is called once at thr beginning of the simulation 28 | fn temperature_strategy(&self) -> TemperatureStrategy; 29 | 30 | /// Get the number of degrees of freedom simulated by this propagator 31 | /// 32 | /// This function is called once at thr beginning of the simulation 33 | fn degrees_of_freedom(&self, system: &System) -> DegreesOfFreedom; 34 | 35 | /// Setup code, preparing all the meta-information needed about the 36 | /// simulation. 37 | fn setup(&mut self, _: &System) {} 38 | 39 | /// Propagate the system for one simulation step. 40 | fn propagate(&mut self, system: &mut System); 41 | 42 | /// Finish the simulation, and maybe output some information about it 43 | fn finish(&mut self, _: &System) {} 44 | } 45 | -------------------------------------------------------------------------------- /rustfmt.toml: -------------------------------------------------------------------------------- 1 | # Rustfmt configuration. All commented items are the default values, from 2 | # rustfmt --dump-default-config > rustfmt.toml 3 | 4 | # unstable_features = false 5 | # verbose = false 6 | # disable_all_formatting = false 7 | # skip_children = false 8 | # max_width = 100 9 | error_on_line_overflow = false 10 | error_on_line_overflow_comments = false 11 | # tab_spaces = 4 12 | fn_call_width = 80 13 | # struct_lit_width = 18 14 | # struct_variant_width = 35 15 | # force_explicit_abi = true 16 | # newline_style = "Unix" 17 | # fn_brace_style = "SameLineWhere" 18 | # item_brace_style = "SameLineWhere" 19 | # control_style = "Rfc" 20 | # control_brace_style = "AlwaysSameLine" 21 | # impl_empty_single_line = true 22 | # trailing_comma = "Vertical" 23 | # trailing_semicolon = true 24 | # fn_empty_single_line = true 25 | # fn_single_line = false 26 | # fn_return_indent = "WithArgs" 27 | # fn_args_paren_newline = false 28 | fn_args_density = "CompressedIfEmpty" 29 | # fn_args_indent = "Block" 30 | # array_indent = "Block" 31 | # array_width = 60 32 | # array_horizontal_layout_threshold = 0 33 | # type_punctuation_density = "Wide" 34 | # where_style = "Rfc" 35 | where_density = "Vertical" 36 | # where_single_line = false 37 | where_layout = "HorizontalVertical" 38 | # where_pred_indent = "Visual" 39 | # generics_indent = "Block" 40 | # struct_lit_indent = "Block" 41 | # struct_lit_multiline_style = "PreferSingle" 42 | # fn_call_indent = "Block" 43 | # report_todo = "Never" 44 | # report_fixme = "Never" 45 | chain_indent = "Visual" 46 | chain_width = 80 47 | # chain_split_single_child = false 48 | # imports_indent = "Visual" 49 | # imports_layout = "Mixed" 50 | # reorder_extern_crates = true 51 | # reorder_extern_crates_in_group = true 52 | reorder_imports = true 53 | reorder_imports_in_group = true 54 | # reorder_imported_names = true 55 | # single_line_if_else_max_width = 50 56 | # format_strings = false 57 | # force_format_strings = false 58 | take_source_hints = true 59 | # hard_tabs = false 60 | # wrap_comments = false 61 | # comment_width = 80 62 | # normalize_comments = false 63 | # wrap_match_arms = true 64 | # match_block_trailing_comma = false 65 | # match_arm_forces_newline = false 66 | # indent_match_arms = true 67 | # match_pattern_separator_break_point = "Back" 68 | # closure_block_indent_threshold = 7 69 | # space_before_type_annotation = false 70 | # space_after_type_annotation_colon = true 71 | # space_before_struct_lit_field_colon = false 72 | # space_after_struct_lit_field_colon = true 73 | # space_before_bound = false 74 | # space_after_bound_colon = true 75 | # spaces_around_ranges = false 76 | # spaces_within_angle_brackets = false 77 | # spaces_within_square_brackets = false 78 | # spaces_within_parens = false 79 | # use_try_shorthand = false 80 | # write_mode = "Overwrite" 81 | # condense_wildcard_suffixes = false 82 | # combine_control_expr = true 83 | # struct_field_align_threshold = 0 84 | # remove_blank_lines_at_start_or_end_of_block = true 85 | attributes_on_same_line_as_field = false 86 | attributes_on_same_line_as_variant = false 87 | multiline_closure_forces_block = true 88 | multiline_match_arm_forces_block = true 89 | # merge_derives = true 90 | # binop_separator = "Front" 91 | -------------------------------------------------------------------------------- /scripts/ci/check-whitespaces.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # coding=utf-8 3 | import os 4 | import sys 5 | 6 | ROOT = os.path.join(os.path.dirname(__file__), "..") 7 | DIRECTORIES = ["benches", "doc", "examples", "scripts", "src", "tests"] 8 | IGNORED_EXTENSIONS = [ 9 | "xyz", 10 | # website and documentation files 11 | "svg", "html", "js", 12 | # Binary files 13 | "ttf", "eot", "woff", "woff2", "png", 14 | ] 15 | 16 | ERRORS = 0 17 | 18 | 19 | def error(message): 20 | global ERRORS 21 | ERRORS += 1 22 | print(message) 23 | 24 | 25 | def check_whitespace(path): 26 | path = os.path.realpath(path) 27 | path = os.path.relpath(path, ROOT) 28 | with open(path) as fd: 29 | lines = fd.readlines() 30 | 31 | line_number = 0 32 | for line in lines: 33 | line_number += 1 34 | if line.endswith(" \n") or line.endswith("\t\n"): 35 | error( 36 | "whitespace at the end of the line at {}:{}" 37 | .format(path, line_number) 38 | ) 39 | if not lines[-1].endswith("\n"): 40 | error("missing new line at the end of the file in {}".format(path)) 41 | 42 | 43 | if __name__ == '__main__': 44 | for directory in DIRECTORIES: 45 | for (root, _, paths) in os.walk(os.path.join(ROOT, directory)): 46 | for path in paths: 47 | extension = path.split(".")[-1] 48 | if extension not in IGNORED_EXTENSIONS: 49 | check_whitespace(os.path.join(root, path)) 50 | 51 | if ERRORS != 0: 52 | print("------------------\n{} whitespace errors".format(ERRORS)) 53 | sys.exit(1) 54 | -------------------------------------------------------------------------------- /scripts/ci/generate-docs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -ex 2 | # Build the docs and the user manual 3 | 4 | if [[ "$TRAVIS_OS_NAME" != "linux" || "$TRAVIS_RUST_VERSION" != "stable" ]]; then 5 | exit 6 | fi 7 | 8 | cd $TRAVIS_BUILD_DIR 9 | pip install --user -r doc/requirements.txt 10 | 11 | # Build the doc 12 | RUSTDOCFLAGS="--html-in-header doc/KaTeX.html" cargo doc --no-deps 13 | make -C doc html latexpdf 14 | 15 | # Move it to the right place 16 | rm -rf target/gh-pages/latest 17 | mkdir -p target/gh-pages/latest 18 | cd target/gh-pages/ 19 | cp -r ../../doc/build/html latest/book 20 | cp -r ../../doc/build/latex/Lumol.pdf latest/book/ 21 | cp ../../doc/index.html latest/index.html 22 | mv ../doc/* latest/ 23 | 24 | cat < index.html 25 | 26 | EOF 27 | 28 | touch .nojekyll 29 | -------------------------------------------------------------------------------- /scripts/ci/install-travis.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -ex 2 | # Install tools for Travis CI build 3 | 4 | # Build and cache kcov 5 | if [ -f $HOME/local/bin/kcov ]; then 6 | echo "Using cached kcov from ~/local/bin/kcov" 7 | else 8 | if [[ "${TRAVIS_OS_NAME}" == "osx" ]]; then 9 | export OPENSSL_ROOT_DIR=$(brew --prefix openssl) 10 | fi 11 | 12 | mkdir -p $HOME/local 13 | cd $HOME/local 14 | wget https://github.com/SimonKagstrom/kcov/archive/master.tar.gz 15 | tar xzf master.tar.gz && mkdir kcov-master/build && cd kcov-master/build 16 | cmake -DCMAKE_INSTALL_PREFIX=$HOME/local .. 17 | make install 18 | cd $TRAVIS_BUILD_DIR 19 | fi 20 | -------------------------------------------------------------------------------- /scripts/ci/list-test-executables.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- encoding: utf8 -*- 3 | import json 4 | import subprocess 5 | 6 | 7 | def list_executables(*command): 8 | command = list(command) 9 | command.append("--no-run") 10 | command.append("--message-format=json") 11 | 12 | result = subprocess.run(command, check=True, stdout=subprocess.PIPE) 13 | # convert successive JSON documents to a list of JSON objects 14 | stdout = "[" + result.stdout.decode("utf8").replace("}\n{", "},{") + "]" 15 | 16 | executables = [] 17 | for event in json.loads(stdout): 18 | if "profile" in event and event["profile"]["test"]: 19 | for path in event["filenames"]: 20 | if path.endswith(".dSYM"): 21 | continue 22 | executables.append(path) 23 | 24 | return executables 25 | 26 | 27 | def main(): 28 | executables = [] 29 | executables.extend(list_executables("cargo", "test", "--all", "--lib")) 30 | executables.extend( 31 | list_executables("cargo", "test", "--package=lumol-input", "--tests") 32 | ) 33 | 34 | for executable in set(executables): 35 | if "lumol_tutorial" in executable: 36 | continue 37 | print(executable) 38 | 39 | 40 | if __name__ == "__main__": 41 | main() 42 | -------------------------------------------------------------------------------- /scripts/ci/setup-travis.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -ex 2 | # Setup environement variables for Travis CI build 3 | 4 | export PATH=~/.local/bin:$PATH:~/local/bin:~/.cargo/bin:~/Library/Python/2.7/bin 5 | export RUSTFLAGS="-C link-dead-code" 6 | 7 | if [[ "$TRAVIS_RUST_VERSION" == "stable" && "$TRAVIS_OS_NAME" == "linux" ]]; then 8 | export DO_COVERAGE=true 9 | else 10 | export DO_COVERAGE=false 11 | fi 12 | 13 | if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then 14 | export CC=gcc-4.9 15 | export CXX=g++-4.9 16 | fi 17 | -------------------------------------------------------------------------------- /scripts/requirements.txt: -------------------------------------------------------------------------------- 1 | click 2 | py-cpuinfo 3 | requests 4 | -------------------------------------------------------------------------------- /src/input.rs: -------------------------------------------------------------------------------- 1 | // Lumol, an extensible molecular simulation engine 2 | // Copyright (C) Lumol's contributors — BSD license 3 | 4 | #![allow(clippy::needless_doctest_main)] 5 | 6 | //! This module provide a way to build a Lumol simulation using input files. 7 | //! 8 | //! Instead of building the [`System`] and [`Simulation`] objects by hand before 9 | //! being able to use them, this module provides a way to describe the 10 | //! simulation and the system in a TOML input file, using a simpler syntax. 11 | //! 12 | //! The main entry point is the `Input` struct, which allow to read a whole 13 | //! simulation configuration. The easiest way to run a simulation using Lumol 14 | //! is then: 15 | //! 16 | //! ```no_run 17 | //! use lumol::input::Input; 18 | //! 19 | //! fn main() { 20 | //! let input = Input::new("simulation.toml").unwrap(); 21 | //! let mut config = input.read().unwrap(); 22 | //! 23 | //! config.simulation.run(&mut config.system, config.nsteps); 24 | //! } 25 | //! ``` 26 | //! 27 | //! This crate also provide an [`InteractionsInput`] for reading interactions 28 | //! from a TOML file. It can be used to set the interactions in a system: 29 | //! 30 | //! ```no_run 31 | //! use lumol::System; 32 | //! use lumol::input::InteractionsInput; 33 | //! 34 | //! fn main() { 35 | //! let mut system = System::new(); 36 | //! 37 | //! // ... Build the system by hand 38 | //! 39 | //! // Read the interactions 40 | //! let input = InteractionsInput::new("potentials.toml").unwrap(); 41 | //! input.read(&mut system).unwrap(); 42 | //! } 43 | //! ``` 44 | //! 45 | //! [`System`]: ../sys/struct.System.html 46 | //! [`Simulation`]: ../sim/struct.Simulation.html 47 | //! [`InteractionsInput`]: struct.InteractionsInput.html 48 | 49 | pub use lumol_input::*; 50 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | // Lumol, an extensible molecular simulation engine 2 | // Copyright (C) Lumol's contributors — BSD license 3 | 4 | //! Lumol is a classical molecular simulation engine that provides a solid 5 | //! base for developing new algorithms and methods. 6 | //! 7 | //! Using Lumol, you can customize the behavior of all the algorithms in a 8 | //! simulation (from force fields to barostats and Monte Carlo moves). 9 | //! 10 | //! Lumol goals are to be: 11 | //! 12 | //! - **Easy to extend**: the code is modular, object-oriented, well documented, 13 | //! well tested, open-source and readable; 14 | //! - **Easy to use**: the user interface is nice, with human-oriented input 15 | //! files; 16 | //! - **Stable**: it will never crash on a good input, and provides helpful 17 | //! error messages. 18 | 19 | /// The full version of the crate, containing git state if available 20 | pub static VERSION: &str = env!("LUMOL_FULL_GIT_VERSION"); 21 | 22 | pub mod sim; 23 | pub mod input; 24 | 25 | pub use lumol_core::*; 26 | -------------------------------------------------------------------------------- /src/sim.rs: -------------------------------------------------------------------------------- 1 | // Lumol, an extensible molecular simulation engine 2 | // Copyright (C) Lumol's contributors — BSD license 3 | 4 | //! Type and algorithms for simulations 5 | //! 6 | //! The main stuct is [`Simulation`], containing all the data to run a single 7 | //! simulation. A given `System` can be used with multiple [`Simulation`], for 8 | //! example starting with an energy minimization, and then running some 9 | //! Molecular dynamics; 10 | //! 11 | //! [`Simulation`]: struct.Simulation.html 12 | 13 | pub use lumol_sim::*; 14 | -------------------------------------------------------------------------------- /tests/data/mc-argon/npt.toml: -------------------------------------------------------------------------------- 1 | [input] 2 | version = 1 3 | 4 | [[systems]] 5 | file = "argon.pdb" 6 | 7 | [systems.potentials.pairs] 8 | Ar-Ar = {type = "lj", sigma = "3.405 A", epsilon = "1.0 kJ/mol", cutoff = "8 A", tail_correction = true} 9 | 10 | [[simulations]] 11 | nsteps = 1000 12 | 13 | [simulations.propagator] 14 | type = "MonteCarlo" 15 | temperature = "100 K" 16 | moves = [ 17 | {type = "Translate", delta = "1 A", frequency = 1}, 18 | {type = "Resize", pressure = "200 bar", delta = "1000 A^3", frequency = 50}, 19 | ] 20 | -------------------------------------------------------------------------------- /tests/data/mc-ethane/ethane.toml: -------------------------------------------------------------------------------- 1 | # TraPPE force field for ethane 2 | 3 | [input] 4 | version = 1 5 | 6 | [global] 7 | cutoff = "8 A" 8 | tail_correction = true 9 | 10 | [pairs] 11 | C-C = {type = "lj", sigma = "3.4 A", epsilon = "0.7 kcal/mol", restriction = "InterMolecular"} 12 | 13 | [bonds] 14 | C-C = {type = "null"} 15 | -------------------------------------------------------------------------------- /tests/data/mc-ethane/npt.toml: -------------------------------------------------------------------------------- 1 | [input] 2 | version = 1 3 | 4 | [[systems]] 5 | file = "ethane.pdb" 6 | potentials = "ethane.toml" 7 | 8 | [[simulations]] 9 | nsteps = 100_000 10 | 11 | [simulations.propagator] 12 | type = "MonteCarlo" 13 | temperature = "451 K" 14 | moves = [ 15 | {type = "Translate", delta = "0.5 A", frequency = 50}, 16 | {type = "Rotate", delta = "60 deg", frequency = 50}, 17 | {type = "Resize", pressure = "200 bar", delta = "200 A^3", frequency = 1}, 18 | ] 19 | -------------------------------------------------------------------------------- /tests/data/mc-helium/nvt.toml: -------------------------------------------------------------------------------- 1 | [input] 2 | version = 1 3 | 4 | [[systems]] 5 | file = "helium.pdb" 6 | 7 | [systems.potentials.pairs] 8 | He-He = {type = "lj", sigma = "2 A", epsilon = "0.2 kJ/mol", cutoff = "15 A"} 9 | 10 | [[simulations]] 11 | nsteps = 5_000 12 | 13 | [simulations.propagator] 14 | type = "MonteCarlo" 15 | temperature = "300 K" 16 | moves = [ 17 | {type = "Translate", delta = "3 A", frequency = 1}, 18 | ] 19 | -------------------------------------------------------------------------------- /tests/data/mc-water/ewald.toml: -------------------------------------------------------------------------------- 1 | [input] 2 | version = 1 3 | 4 | [global] 5 | cutoff = "6 A" 6 | tail_correction = true 7 | 8 | [pairs] 9 | O-O = {type = "lj", sigma = "3.16 A", epsilon = "0.155 kcal/mol"} 10 | H-H = {type = "null"} 11 | O-H = {type = "null"} 12 | 13 | [bonds] 14 | O-H = {type = "null"} 15 | 16 | [angles] 17 | H-O-H = {type = "null"} 18 | 19 | [coulomb] 20 | ewald = {cutoff = "6 A", accuracy = 1e-5} 21 | restriction = "inter-molecular" 22 | 23 | [charges] 24 | O = -0.82 25 | H = 0.41 26 | -------------------------------------------------------------------------------- /tests/data/mc-water/npt-ewald.toml: -------------------------------------------------------------------------------- 1 | [input] 2 | version = 1 3 | 4 | [[systems]] 5 | file = "water.pdb" 6 | potentials = "ewald.toml" 7 | 8 | [[simulations]] 9 | nsteps = 10_000 10 | 11 | [simulations.propagator] 12 | type = "MonteCarlo" 13 | temperature = "300 K" 14 | moves = [ 15 | {type = "Translate", delta = "0.3 A", frequency = 50}, 16 | {type = "Rotate", delta = "20 deg", frequency = 50}, 17 | {type = "Resize", pressure = "1000 bar", delta = "100 A^3", frequency = 1}, 18 | ] 19 | -------------------------------------------------------------------------------- /tests/data/mc-water/npt-wolf.toml: -------------------------------------------------------------------------------- 1 | [input] 2 | version = 1 3 | 4 | [[systems]] 5 | file = "water.pdb" 6 | potentials = "wolf.toml" 7 | 8 | [[simulations]] 9 | nsteps = 10_000 10 | 11 | [simulations.propagator] 12 | type = "MonteCarlo" 13 | temperature = "300 K" 14 | moves = [ 15 | {type = "Translate", delta = "0.3 A", frequency = 50}, 16 | {type = "Rotate", delta = "20 deg", frequency = 50}, 17 | {type = "Resize", pressure = "1000 bar", delta = "100 A^3", frequency = 1}, 18 | ] 19 | -------------------------------------------------------------------------------- /tests/data/mc-water/nvt-ewald.toml: -------------------------------------------------------------------------------- 1 | [input] 2 | version = 1 3 | 4 | [[systems]] 5 | file = "water.pdb" 6 | potentials = "ewald.toml" 7 | 8 | [[simulations]] 9 | nsteps = 5_000 10 | 11 | [simulations.propagator] 12 | type = "MonteCarlo" 13 | temperature = "300 K" 14 | moves = [ 15 | # WHAAAT ? The deltas are way too low ... 16 | {type = "Translate", delta = "0.1 A", frequency = 1}, 17 | {type = "Rotate", delta = "10 deg", frequency = 1}, 18 | ] 19 | -------------------------------------------------------------------------------- /tests/data/mc-water/nvt-wolf.toml: -------------------------------------------------------------------------------- 1 | [input] 2 | version = 1 3 | 4 | [[systems]] 5 | file = "water.pdb" 6 | potentials = "wolf.toml" 7 | 8 | [[simulations]] 9 | nsteps = 5_000 10 | 11 | [simulations.propagator] 12 | type = "MonteCarlo" 13 | temperature = "300 K" 14 | moves = [ 15 | {type = "Translate", delta = "1 A", frequency = 1}, 16 | {type = "Rotate", delta = "120 deg", frequency = 1}, 17 | ] 18 | -------------------------------------------------------------------------------- /tests/data/mc-water/wolf.toml: -------------------------------------------------------------------------------- 1 | [input] 2 | version = 1 3 | 4 | [global] 5 | cutoff = "6 A" 6 | tail_correction = true 7 | 8 | [pairs] 9 | O-O = {type = "lj", sigma = "3.16 A", epsilon = "0.155 kcal/mol"} 10 | H-H = {type = "null"} 11 | O-H = {type = "null"} 12 | 13 | [bonds] 14 | O-H = {type = "null"} 15 | 16 | [angles] 17 | H-O-H = {type = "null"} 18 | 19 | [coulomb] 20 | wolf = {cutoff = "6 A"} 21 | restriction = "inter-molecular" 22 | 23 | [charges] 24 | O = -0.82 25 | H = 0.41 26 | -------------------------------------------------------------------------------- /tests/data/md-butane/butane.toml: -------------------------------------------------------------------------------- 1 | [input] 2 | version = 1 3 | 4 | [global] 5 | cutoff = {shifted = "10 A"} 6 | 7 | [pairs] 8 | C-C = {type = "lj", sigma = "3.4 A", epsilon = "0.7 kcal/mol", restriction = "InterMolecular"} 9 | 10 | [bonds] 11 | C-C = {type = "harmonic", x0 = "1.53 A", k = "225 kcal/mol/A^2"} 12 | 13 | [angles] 14 | C-C-C = {type = "harmonic", x0 = "115 deg", k = "58 kcal/mol/rad^2"} 15 | 16 | [dihedrals] 17 | C-C-C-C = {type = "torsion", n = 3, delta = "180 deg", k = "1.50 kcal/mol"} 18 | -------------------------------------------------------------------------------- /tests/data/md-butane/nve.toml: -------------------------------------------------------------------------------- 1 | [input] 2 | version = 1 3 | 4 | [[systems]] 5 | file = "butane.xyz" 6 | guess_bonds = true 7 | cell = 20 8 | potentials = "butane.toml" 9 | velocities = {init = "300 K"} 10 | 11 | [[simulations]] 12 | nsteps = 1_000 13 | 14 | [simulations.propagator] 15 | type = "MolecularDynamics" 16 | timestep = "1 fs" 17 | -------------------------------------------------------------------------------- /tests/data/md-helium/npt-berendsen-barostat.toml: -------------------------------------------------------------------------------- 1 | [input] 2 | version = 1 3 | 4 | [[systems]] 5 | file = "helium.xyz" 6 | cell = 10 7 | velocities = {init = "300 K"} 8 | 9 | [systems.potentials.pairs] 10 | He-He = {type = "lj", sigma = "2 A", epsilon = "0.2 kJ/mol", cutoff = "4.5 A"} 11 | 12 | [[simulations]] 13 | nsteps = 5_000 14 | 15 | [simulations.propagator] 16 | type = "MolecularDynamics" 17 | timestep = "1 fs" 18 | integrator = {type = "BerendsenBarostat", pressure = "5000 bar", timestep = 1000} 19 | thermostat = {type = "Berendsen", temperature = "273 K", timestep = 100} 20 | -------------------------------------------------------------------------------- /tests/data/md-helium/nve-leap-frog.toml: -------------------------------------------------------------------------------- 1 | [input] 2 | version = 1 3 | 4 | [[systems]] 5 | file = "helium.xyz" 6 | cell = 10 7 | velocities = {init = "300 K"} 8 | 9 | [systems.potentials.pairs] 10 | He-He = {type = "lj", sigma = "2 A", epsilon = "0.2 kJ/mol", cutoff = "4.5 A"} 11 | 12 | [[simulations]] 13 | nsteps = 1_000 14 | 15 | [simulations.propagator] 16 | type = "MolecularDynamics" 17 | timestep = "1 fs" 18 | integrator = {type = "LeapFrog"} 19 | -------------------------------------------------------------------------------- /tests/data/md-helium/nve-perfect-gas.toml: -------------------------------------------------------------------------------- 1 | [input] 2 | version = 1 3 | 4 | [[systems]] 5 | file = "helium-gas.pdb" 6 | cell = 100 7 | velocities = {init = "300 K"} 8 | 9 | [systems.potentials.pairs] 10 | He-He = {type = "lj", sigma = "2 A", epsilon = "0.2 kJ/mol", cutoff = "4.5 A"} 11 | 12 | [[simulations]] 13 | nsteps = 1_000 14 | 15 | [simulations.propagator] 16 | type = "MolecularDynamics" 17 | timestep = "1 fs" 18 | integrator = {type = "VelocityVerlet"} 19 | -------------------------------------------------------------------------------- /tests/data/md-helium/nve-shifted.toml: -------------------------------------------------------------------------------- 1 | [input] 2 | version = 1 3 | 4 | [[systems]] 5 | file = "helium.xyz" 6 | cell = 10 7 | velocities = {init = "300 K"} 8 | 9 | [systems.potentials.pairs] 10 | He-He = {type = "lj", sigma = "2 A", epsilon = "0.2 kJ/mol", cutoff = {shifted = "4.5 A"}} 11 | 12 | [[simulations]] 13 | nsteps = 1_000 14 | 15 | [simulations.propagator] 16 | type = "MolecularDynamics" 17 | timestep = "1 fs" 18 | integrator = {type = "VelocityVerlet"} 19 | -------------------------------------------------------------------------------- /tests/data/md-helium/nve-table.toml: -------------------------------------------------------------------------------- 1 | [input] 2 | version = 1 3 | 4 | [[systems]] 5 | file = "helium.xyz" 6 | cell = 10 7 | velocities = {init = "300 K"} 8 | 9 | [systems.potentials.pairs.He-He] 10 | type = "lj" 11 | sigma = "2 A" 12 | epsilon = "0.2 kJ/mol" 13 | cutoff = "4.5 A" 14 | computation = {table = {max = "5 A", n = 1000}} 15 | 16 | [[simulations]] 17 | nsteps = 1_000 18 | 19 | [simulations.propagator] 20 | type = "MolecularDynamics" 21 | timestep = "1 fs" 22 | integrator = {type = "VelocityVerlet"} 23 | -------------------------------------------------------------------------------- /tests/data/md-helium/nve-velocity-verlet.toml: -------------------------------------------------------------------------------- 1 | [input] 2 | version = 1 3 | 4 | [[systems]] 5 | file = "helium.xyz" 6 | cell = 10 7 | velocities = {init = "300 K"} 8 | 9 | [systems.potentials.pairs] 10 | He-He = {type = "lj", sigma = "2 A", epsilon = "0.2 kJ/mol", cutoff = "4.5 A"} 11 | 12 | 13 | [[simulations]] 14 | nsteps = 1_000 15 | 16 | [simulations.propagator] 17 | type = "MolecularDynamics" 18 | timestep = "1 fs" 19 | integrator = {type = "VelocityVerlet"} 20 | -------------------------------------------------------------------------------- /tests/data/md-helium/nve-verlet.toml: -------------------------------------------------------------------------------- 1 | [input] 2 | version = 1 3 | 4 | [[systems]] 5 | file = "helium.xyz" 6 | cell = 10 7 | velocities = {init = "300 K"} 8 | 9 | [systems.potentials.pairs] 10 | He-He = {type = "lj", sigma = "2 A", epsilon = "0.2 kJ/mol", cutoff = {shifted = "4.5 A"}} 11 | 12 | [[simulations]] 13 | nsteps = 1_000 14 | 15 | [simulations.propagator] 16 | type = "MolecularDynamics" 17 | timestep = "1 fs" 18 | integrator = {type = "Verlet"} 19 | -------------------------------------------------------------------------------- /tests/data/md-methane/methane.toml: -------------------------------------------------------------------------------- 1 | [input] 2 | version = 1 3 | 4 | [global] 5 | cutoff = {shifted = "10 A"} 6 | 7 | [pairs] 8 | C-C = {type = "lj", sigma = "3.7 A", epsilon = "0.2981 kcal/mol"} 9 | C-H = {type = "null"} 10 | H-H = {type = "null"} 11 | 12 | [bonds] 13 | C-H = {type = "harmonic", x0 = "1.09 A", k = "390 kcal/mol/A^2"} 14 | 15 | [angles] 16 | H-C-H = {type = "harmonic", x0 = "109.5 deg", k = "70 kcal/mol/rad^2"} 17 | -------------------------------------------------------------------------------- /tests/data/md-methane/nve.toml: -------------------------------------------------------------------------------- 1 | [input] 2 | version = 1 3 | 4 | [[systems]] 5 | file = "methane.xyz" 6 | guess_bonds = true 7 | cell = 20 8 | potentials = "methane.toml" 9 | velocities = {init = "300 K"} 10 | 11 | [[simulations]] 12 | nsteps = 500 13 | 14 | [simulations.propagator] 15 | type = "MolecularDynamics" 16 | timestep = "1 fs" 17 | -------------------------------------------------------------------------------- /tests/data/md-nacl/ewald-kspace.toml: -------------------------------------------------------------------------------- 1 | # A modified Ewald test, with ridiculously small real space cutoff, to increase 2 | # the effect of k-space energy/forces. 3 | 4 | [input] 5 | version = 1 6 | 7 | [global] 8 | cutoff = "5.5 A" 9 | 10 | [pairs] 11 | Na-Na = {type = "lj", sigma = "2.497 A", epsilon = "0.07826 kcal/mol"} 12 | Cl-Cl = {type = "lj", sigma = "4.612 A", epsilon = "0.02502 kcal/mol"} 13 | Na-Cl = {type = "lj", sigma = "3.5545 A", epsilon = "0.04425 kcal/mol"} 14 | 15 | [coulomb] 16 | ewald = {cutoff = "1 A", kmax = 10} 17 | 18 | [charges] 19 | Na = 1.0 20 | Cl = -1.0 21 | -------------------------------------------------------------------------------- /tests/data/md-nacl/ewald.toml: -------------------------------------------------------------------------------- 1 | [input] 2 | version = 1 3 | 4 | [global] 5 | cutoff = "5.5 A" 6 | 7 | [pairs] 8 | Na-Na = {type = "lj", sigma = "2.497 A", epsilon = "0.07826 kcal/mol"} 9 | Cl-Cl = {type = "lj", sigma = "4.612 A", epsilon = "0.02502 kcal/mol"} 10 | Na-Cl = {type = "lj", sigma = "3.5545 A", epsilon = "0.04425 kcal/mol"} 11 | 12 | [coulomb] 13 | ewald = {cutoff = "5.5 A", kmax = 10} 14 | 15 | [charges] 16 | Na = 1.0 17 | Cl = -1.0 18 | -------------------------------------------------------------------------------- /tests/data/md-nacl/npt-wolf-small.toml: -------------------------------------------------------------------------------- 1 | [input] 2 | version = 1 3 | 4 | [[systems]] 5 | file = "small.xyz" 6 | cell = 11.2804 7 | potentials = "wolf.toml" 8 | velocities = {init = "300 K"} 9 | 10 | [[simulations]] 11 | nsteps = 10_000 12 | 13 | [simulations.propagator] 14 | type = "MolecularDynamics" 15 | timestep = "1 fs" 16 | integrator = {type = "AnisoBerendsenBarostat", pressure = "50000 bar", timestep = 1000} 17 | thermostat = {type = "Berendsen", temperature = "273 K", timestep = 100} 18 | -------------------------------------------------------------------------------- /tests/data/md-nacl/nve-ewald-kspace.toml: -------------------------------------------------------------------------------- 1 | [input] 2 | version = 1 3 | 4 | [[systems]] 5 | file = "small.xyz" 6 | cell = 11.2804 7 | potentials = "ewald-kspace.toml" 8 | velocities = {init = "300 K"} 9 | 10 | [[simulations]] 11 | nsteps = 100 12 | 13 | [simulations.propagator] 14 | type = "MolecularDynamics" 15 | timestep = "1 fs" 16 | -------------------------------------------------------------------------------- /tests/data/md-nacl/nve-ewald-small.toml: -------------------------------------------------------------------------------- 1 | [input] 2 | version = 1 3 | 4 | [[systems]] 5 | file = "small.xyz" 6 | cell = 11.2804 7 | potentials = "ewald.toml" 8 | velocities = {init = "300 K"} 9 | 10 | [[simulations]] 11 | nsteps = 100 12 | 13 | [simulations.propagator] 14 | type = "MolecularDynamics" 15 | timestep = "1 fs" 16 | -------------------------------------------------------------------------------- /tests/data/md-nacl/nve-wolf-small.toml: -------------------------------------------------------------------------------- 1 | [input] 2 | version = 1 3 | 4 | [[systems]] 5 | file = "small.xyz" 6 | cell = 11.2804 7 | potentials = "wolf.toml" 8 | velocities = {init = "300 K"} 9 | 10 | [[simulations]] 11 | nsteps = 1_000 12 | 13 | [simulations.propagator] 14 | type = "MolecularDynamics" 15 | timestep = "1 fs" 16 | -------------------------------------------------------------------------------- /tests/data/md-nacl/small.xyz: -------------------------------------------------------------------------------- 1 | 64 2 | Small NaCL box with a length of 11.2804 A 3 | Cl 0 0 0 4 | Na 0 0 2.8201 5 | Cl 0 0 5.6402 6 | Na 0 0 8.4603 7 | Na 0 2.8201 0 8 | Cl 0 2.8201 2.8201 9 | Na 0 2.8201 5.6402 10 | Cl 0 2.8201 8.4603 11 | Cl 0 5.6402 0 12 | Na 0 5.6402 2.8201 13 | Cl 0 5.6402 5.6402 14 | Na 0 5.6402 8.4603 15 | Na 0 8.4603 0 16 | Cl 0 8.4603 2.8201 17 | Na 0 8.4603 5.6402 18 | Cl 0 8.4603 8.4603 19 | Na 2.8201 0 0 20 | Cl 2.8201 0 2.8201 21 | Na 2.8201 0 5.6402 22 | Cl 2.8201 0 8.4603 23 | Cl 2.8201 2.8201 0 24 | Na 2.8201 2.8201 2.8201 25 | Cl 2.8201 2.8201 5.6402 26 | Na 2.8201 2.8201 8.4603 27 | Na 2.8201 5.6402 0 28 | Cl 2.8201 5.6402 2.8201 29 | Na 2.8201 5.6402 5.6402 30 | Cl 2.8201 5.6402 8.4603 31 | Cl 2.8201 8.4603 0 32 | Na 2.8201 8.4603 2.8201 33 | Cl 2.8201 8.4603 5.6402 34 | Na 2.8201 8.4603 8.4603 35 | Cl 5.6402 0 0 36 | Na 5.6402 0 2.8201 37 | Cl 5.6402 0 5.6402 38 | Na 5.6402 0 8.4603 39 | Na 5.6402 2.8201 0 40 | Cl 5.6402 2.8201 2.8201 41 | Na 5.6402 2.8201 5.6402 42 | Cl 5.6402 2.8201 8.4603 43 | Cl 5.6402 5.6402 0 44 | Na 5.6402 5.6402 2.8201 45 | Cl 5.6402 5.6402 5.6402 46 | Na 5.6402 5.6402 8.4603 47 | Na 5.6402 8.4603 0 48 | Cl 5.6402 8.4603 2.8201 49 | Na 5.6402 8.4603 5.6402 50 | Cl 5.6402 8.4603 8.4603 51 | Na 8.4603 0 0 52 | Cl 8.4603 0 2.8201 53 | Na 8.4603 0 5.6402 54 | Cl 8.4603 0 8.4603 55 | Cl 8.4603 2.8201 0 56 | Na 8.4603 2.8201 2.8201 57 | Cl 8.4603 2.8201 5.6402 58 | Na 8.4603 2.8201 8.4603 59 | Na 8.4603 5.6402 0 60 | Cl 8.4603 5.6402 2.8201 61 | Na 8.4603 5.6402 5.6402 62 | Cl 8.4603 5.6402 8.4603 63 | Cl 8.4603 8.4603 0 64 | Na 8.4603 8.4603 2.8201 65 | Cl 8.4603 8.4603 5.6402 66 | Na 8.4603 8.4603 8.4603 67 | -------------------------------------------------------------------------------- /tests/data/md-nacl/wolf.toml: -------------------------------------------------------------------------------- 1 | [input] 2 | version = 1 3 | 4 | [global] 5 | cutoff = "5.5 A" 6 | 7 | [pairs] 8 | Cl-Cl = {type = "lj", sigma = "4.612 A", epsilon = "0.02502 kcal/mol"} 9 | Na-Na = {type = "lj", sigma = "2.497 A", epsilon = "0.07826 kcal/mol"} 10 | Na-Cl = {type = "lj", sigma = "3.5545 A", epsilon = "0.04425 kcal/mol"} 11 | 12 | [coulomb] 13 | wolf = {cutoff = "5.5 A"} 14 | 15 | [charges] 16 | Na = 1.0 17 | Cl = -1.0 18 | -------------------------------------------------------------------------------- /tests/data/md-water/ewald.toml: -------------------------------------------------------------------------------- 1 | [input] 2 | version = 1 3 | 4 | [global] 5 | cutoff = "14 A" 6 | 7 | # f-SPC model of water, using ewald summation for electrostatics 8 | [pairs] 9 | O-O = {type = "lj", sigma = "3.16 A", epsilon = "0.155 kcal/mol"} 10 | H-H = {type = "harmonic", k = "79.8 kcal/mol/A^2", x0 = "1.633 A", restriction = "IntraMolecular"} 11 | H-O = {type = "null"} 12 | 13 | [bonds] 14 | O-H = {type = "harmonic", k = "1054.2 kcal/mol/A^2", x0 = "1.0 A"} 15 | 16 | [angles] 17 | H-O-H = {type = "harmonic", k = "75.9 kcal/mol/rad^2", x0 = "109.5 deg"} 18 | 19 | [coulomb] 20 | ewald = {cutoff = "8.5 A", kmax = 8} 21 | restriction = "inter-molecular" 22 | 23 | [charges] 24 | O = -0.82 25 | H = 0.41 26 | -------------------------------------------------------------------------------- /tests/data/md-water/nve-ewald.toml: -------------------------------------------------------------------------------- 1 | [input] 2 | version = 1 3 | 4 | [[systems]] 5 | file = "small.pdb" 6 | potentials = "ewald.toml" 7 | velocities = {init = "300 K"} 8 | 9 | [[simulations]] 10 | nsteps = 1_000 11 | 12 | [simulations.propagator] 13 | type = "MolecularDynamics" 14 | timestep = "1 fs" 15 | -------------------------------------------------------------------------------- /tests/data/md-water/nve-wolf.toml: -------------------------------------------------------------------------------- 1 | [input] 2 | version = 1 3 | 4 | [[systems]] 5 | file = "big.pdb" 6 | potentials = "wolf.toml" 7 | velocities = {init = "300 K"} 8 | 9 | [[simulations]] 10 | nsteps = 1_000 11 | 12 | [simulations.propagator] 13 | type = "MolecularDynamics" 14 | timestep = "1 fs" 15 | -------------------------------------------------------------------------------- /tests/data/md-water/wolf.toml: -------------------------------------------------------------------------------- 1 | [input] 2 | version = 1 3 | 4 | [global] 5 | cutoff = "14 A" 6 | 7 | # f-SPC model of water, using ewald summation for electrostatics 8 | [pairs] 9 | O-O = {type = "lj", sigma = "3.16 A", epsilon = "0.155 kcal/mol"} 10 | H-H = {type = "harmonic", k = "79.8 kcal/mol/A^2", x0 = "1.633 A", restriction = "IntraMolecular"} 11 | H-O = {type = "null"} 12 | 13 | [bonds] 14 | O-H = {type = "harmonic", k = "1054.2 kcal/mol/A^2", x0 = "1.0 A"} 15 | 16 | [angles] 17 | H-O-H = {type = "harmonic", k = "75.9 kcal/mol/rad^2", x0 = "109.5 deg"} 18 | 19 | [coulomb] 20 | wolf = {cutoff = "8.5 A"} 21 | restriction = "inter-molecular" 22 | 23 | [charges] 24 | O = -0.82 25 | H = 0.41 26 | -------------------------------------------------------------------------------- /tests/data/nist-lj/lj-1.toml: -------------------------------------------------------------------------------- 1 | [input] 2 | version = 1 3 | 4 | [[systems]] 5 | file = "lj-1.xyz" 6 | cell = 10 7 | -------------------------------------------------------------------------------- /tests/data/nist-lj/lj-2.toml: -------------------------------------------------------------------------------- 1 | [input] 2 | version = 1 3 | 4 | [[systems]] 5 | file = "lj-2.xyz" 6 | cell = 8 7 | -------------------------------------------------------------------------------- /tests/data/nist-lj/lj-3.toml: -------------------------------------------------------------------------------- 1 | [input] 2 | version = 1 3 | 4 | [[systems]] 5 | file = "lj-3.xyz" 6 | cell = 10 7 | -------------------------------------------------------------------------------- /tests/data/nist-lj/lj-4.toml: -------------------------------------------------------------------------------- 1 | [input] 2 | version = 1 3 | 4 | [[systems]] 5 | file = "lj-4.xyz" 6 | cell = 8 7 | -------------------------------------------------------------------------------- /tests/data/nist-lj/lj-4.xyz: -------------------------------------------------------------------------------- 1 | 30 2 | cell: 8.0 8.0 8.0 3 | H 1.077169909511e+00 -1.020988125886e+00 -1.348259447733e+00 4 | H 1.830884592213e-01 -1.557698231574e+00 -1.782405485883e+00 5 | H -2.060346185437e+00 3.927378276290e+00 3.889555115290e+00 6 | H 1.936298049102e+00 7.181973326223e-01 3.715169082037e+00 7 | H -7.514139041700e-01 -4.184139469527e-01 -3.250183630687e+00 8 | H 2.257391305584e+00 -1.126577405146e+00 -2.291542913197e+00 9 | H 1.208868721243e-01 -1.395611520000e+00 2.003709382777e+00 10 | H 3.327427055092e+00 -1.476502868105e+00 3.394023898450e+00 11 | H 2.130927328546e+00 -1.106827632561e+00 -1.972896367169e-01 12 | H 2.117442019559e+00 -1.844743512029e-01 9.301638993772e-01 13 | H -1.459378119580e+00 2.382882188329e+00 -3.788199401470e+00 14 | H 2.432313424884e+00 -1.118537915440e+00 -1.224088264651e+00 15 | H 2.416845366530e+00 1.845499053895e+00 2.906107003288e+00 16 | H 2.515247912050e+00 3.580976978134e-02 -2.445590080636e+00 17 | H 1.113585242376e+00 -2.478011342991e+00 -8.092189527960e-03 18 | H 1.261664073561e+00 1.075432348722e+00 -2.751715752259e+00 19 | H -5.811873476022e-01 -2.429378395199e+00 2.668996832737e+00 20 | H -1.533182296119e+00 2.319699660489e+00 1.762429379767e+00 21 | H 2.639946585704e+00 -7.847515599358e-01 2.251233247739e+00 22 | H -1.927486378623e+00 -1.432729425739e+00 -2.439226375584e+00 23 | H 9.212801355440e-01 -2.427925517025e+00 2.150024430246e+00 24 | H 2.114172305774e+00 9.586575168591e-01 -1.790678078404e+00 25 | H -7.312380271746e-01 -3.366157234697e+00 1.376597954432e-01 26 | H 1.612569300954e+00 -9.233415846164e-01 2.037484769332e+00 27 | H 3.967911812136e+00 2.002508998947e-01 2.659432175592e+00 28 | H 1.188751191387e+00 -5.955638413419e-02 -7.363070447875e-01 29 | H 3.789497702433e+00 1.570674334424e+00 7.265918374820e-01 30 | H 2.786625773109e+00 -1.524167484397e+00 8.358187540631e-01 31 | H -1.629362446504e+00 -1.139061532617e+00 -7.654084051377e-01 32 | H 2.592655226763e+00 3.786335083587e+00 -1.252452130644e+00 33 | -------------------------------------------------------------------------------- /tests/docs.rs: -------------------------------------------------------------------------------- 1 | // Lumol, an extensible molecular simulation engine 2 | // Copyright (C) Lumol's contributors — BSD license 3 | 4 | //! Checking that the documentation tutorials run 5 | use lumol::input::Input; 6 | 7 | use std::path::Path; 8 | use std::sync::Once; 9 | static START: Once = Once::new(); 10 | 11 | struct Cleaner { 12 | files: Vec<&'static str> 13 | } 14 | 15 | impl Cleaner { 16 | fn new(files: Vec<&'static str>) -> Cleaner { 17 | Cleaner { 18 | files 19 | } 20 | } 21 | } 22 | 23 | impl Drop for Cleaner { 24 | fn drop(&mut self) { 25 | for file in &self.files { 26 | let _ = std::fs::remove_file(file); 27 | } 28 | } 29 | } 30 | 31 | #[test] 32 | fn argon() { 33 | START.call_once(::env_logger::init); 34 | let path = Path::new(file!()).parent() 35 | .unwrap() 36 | .join("..") 37 | .join("doc") 38 | .join("src") 39 | .join("data") 40 | .join("argon.toml"); 41 | let mut config = Input::new(path).unwrap().read().unwrap(); 42 | 43 | let _ = Cleaner::new(vec!["energy.dat", "trajectory.xyz"]); 44 | 45 | config.simulation.run(&mut config.system, 1); 46 | } 47 | 48 | #[test] 49 | fn nacl() { 50 | START.call_once(::env_logger::init); 51 | let path = Path::new(file!()).parent() 52 | .unwrap() 53 | .join("..") 54 | .join("doc") 55 | .join("src") 56 | .join("data") 57 | .join("nacl.toml"); 58 | let mut config = Input::new(path).unwrap().read().unwrap(); 59 | 60 | let _ = Cleaner::new(vec!["trajectory.xyz"]); 61 | 62 | config.simulation.run(&mut config.system, 1); 63 | } 64 | 65 | #[test] 66 | fn water() { 67 | START.call_once(::env_logger::init); 68 | let path = Path::new(file!()).parent() 69 | .unwrap() 70 | .join("..") 71 | .join("doc") 72 | .join("src") 73 | .join("data") 74 | .join("water.toml"); 75 | let mut config = Input::new(path).unwrap().read().unwrap(); 76 | 77 | let _ = Cleaner::new(vec!["trajectory.xyz"]); 78 | 79 | config.simulation.run(&mut config.system, 1); 80 | } 81 | -------------------------------------------------------------------------------- /tests/mc-argon.rs: -------------------------------------------------------------------------------- 1 | // Lumol, an extensible molecular simulation engine 2 | // Copyright (C) Lumol's contributors — BSD license 3 | use lumol::input::Input; 4 | use lumol::units; 5 | 6 | use std::path::Path; 7 | use std::sync::Once; 8 | static START: Once = Once::new(); 9 | 10 | mod utils; 11 | 12 | #[test] 13 | fn npt() { 14 | START.call_once(::env_logger::init); 15 | let path = Path::new(file!()).parent() 16 | .unwrap() 17 | .join("data") 18 | .join("mc-argon") 19 | .join("npt.toml"); 20 | 21 | let mut config = Input::new(path).unwrap().read().unwrap(); 22 | 23 | let collector = utils::Collector::starting_at(500); 24 | let pressures = collector.pressures(); 25 | 26 | config.simulation.add_output(Box::new(collector)); 27 | config.simulation.run(&mut config.system, config.nsteps); 28 | 29 | let expected = units::from(200.0, "bar").unwrap(); 30 | let pressure = crate::utils::mean(pressures); 31 | assert!(f64::abs(pressure - expected) / expected < 1e-2); 32 | } 33 | -------------------------------------------------------------------------------- /tests/mc-ethane.rs: -------------------------------------------------------------------------------- 1 | // Lumol, an extensible molecular simulation engine 2 | // Copyright (C) Lumol's contributors — BSD license 3 | use lumol::input::Input; 4 | use lumol::units; 5 | 6 | use std::path::Path; 7 | use std::sync::Once; 8 | static START: Once = Once::new(); 9 | 10 | mod utils; 11 | 12 | #[test] 13 | fn constant_pressure() { 14 | START.call_once(::env_logger::init); 15 | let path = Path::new(file!()).parent() 16 | .unwrap() 17 | .join("data") 18 | .join("mc-ethane") 19 | .join("npt.toml"); 20 | let mut config = Input::new(path).unwrap().read().unwrap(); 21 | 22 | let collector = utils::Collector::starting_at((config.nsteps - 50_000) as u64); 23 | let pressures = collector.pressures(); 24 | 25 | config.simulation.add_output(Box::new(collector)); 26 | config.simulation.run(&mut config.system, config.nsteps); 27 | 28 | let pressure = utils::mean(pressures); 29 | let expected = units::from(200.0, "bar").unwrap(); 30 | let tolerance = units::from(200.0, "bar").unwrap(); 31 | assert!(f64::abs(pressure - expected) < tolerance); 32 | } 33 | -------------------------------------------------------------------------------- /tests/mc-helium.rs: -------------------------------------------------------------------------------- 1 | // Lumol, an extensible molecular simulation engine 2 | // Copyright (C) Lumol's contributors — BSD license 3 | 4 | //! Testing physical properties of a Lennard-Jones gaz of Helium using 5 | //! Monte Carlo simulation 6 | use lumol::consts::K_BOLTZMANN; 7 | use lumol::units; 8 | 9 | use lumol::input::Input; 10 | 11 | use std::path::Path; 12 | use std::sync::Once; 13 | static START: Once = Once::new(); 14 | 15 | 16 | #[test] 17 | fn perfect_gas() { 18 | START.call_once(::env_logger::init); 19 | let path = Path::new(file!()).parent() 20 | .unwrap() 21 | .join("data") 22 | .join("mc-helium") 23 | .join("nvt.toml"); 24 | 25 | let mut config = Input::new(path).unwrap().read().unwrap(); 26 | config.simulation.run(&mut config.system, config.nsteps); 27 | let pressure = config.system.pressure(); 28 | let volume = config.system.volume(); 29 | let temperature = units::from(300.0, "K").unwrap(); 30 | 31 | let pv = pressure * volume; 32 | let nkt = config.system.size() as f64 * K_BOLTZMANN * temperature; 33 | let msg = format!("{} {}", f64::abs(pv - nkt), f64::abs(pv - nkt) / pv); 34 | assert!(f64::abs(pv - nkt) / pv < 2e-2, "{}", msg); 35 | } 36 | -------------------------------------------------------------------------------- /tests/md-butane.rs: -------------------------------------------------------------------------------- 1 | // Lumol, an extensible molecular simulation engine 2 | // Copyright (C) Lumol's contributors — BSD license 3 | 4 | //! Testing molecular dynamics of butane 5 | use lumol::input::Input; 6 | 7 | use std::path::Path; 8 | use std::sync::Once; 9 | static START: Once = Once::new(); 10 | 11 | 12 | #[test] 13 | fn bonds_detection() { 14 | START.call_once(::env_logger::init); 15 | let path = Path::new(file!()).parent() 16 | .unwrap() 17 | .join("data") 18 | .join("md-butane") 19 | .join("nve.toml"); 20 | let system = Input::new(path).unwrap().read_system().unwrap(); 21 | assert_eq!(system.molecules().count(), 50); 22 | 23 | for molecule in system.molecules() { 24 | assert_eq!(molecule.bonds().len(), 3); 25 | assert_eq!(molecule.angles().len(), 2); 26 | assert_eq!(molecule.dihedrals().len(), 1); 27 | } 28 | } 29 | 30 | #[test] 31 | fn constant_energy() { 32 | START.call_once(::env_logger::init); 33 | let path = Path::new(file!()).parent() 34 | .unwrap() 35 | .join("data") 36 | .join("md-butane") 37 | .join("nve.toml"); 38 | let mut config = Input::new(path).unwrap().read().unwrap(); 39 | 40 | 41 | let e_initial = config.system.total_energy(); 42 | config.simulation.run(&mut config.system, config.nsteps); 43 | let e_final = config.system.total_energy(); 44 | assert!(f64::abs((e_initial - e_final) / e_final) < 1e-3); 45 | } 46 | -------------------------------------------------------------------------------- /tests/md-methane.rs: -------------------------------------------------------------------------------- 1 | // Lumol, an extensible molecular simulation engine 2 | // Copyright (C) Lumol's contributors — BSD license 3 | 4 | //! Testing molecular dynamics of methane 5 | use lumol::input::Input; 6 | 7 | use std::path::Path; 8 | use std::sync::Once; 9 | static START: Once = Once::new(); 10 | 11 | 12 | #[test] 13 | fn bonds_detection() { 14 | START.call_once(::env_logger::init); 15 | let path = Path::new(file!()).parent() 16 | .unwrap() 17 | .join("data") 18 | .join("md-methane") 19 | .join("nve.toml"); 20 | let system = Input::new(path).unwrap().read_system().unwrap(); 21 | assert_eq!(system.molecules().count(), 150); 22 | 23 | for molecule in system.molecules() { 24 | assert_eq!(molecule.bonds().len(), 4); 25 | assert_eq!(molecule.angles().len(), 6); 26 | assert_eq!(molecule.dihedrals().len(), 0); 27 | } 28 | } 29 | 30 | #[test] 31 | fn constant_energy() { 32 | START.call_once(::env_logger::init); 33 | let path = Path::new(file!()).parent() 34 | .unwrap() 35 | .join("data") 36 | .join("md-methane") 37 | .join("nve.toml"); 38 | let mut config = Input::new(path).unwrap().read().unwrap(); 39 | 40 | 41 | let e_initial = config.system.total_energy(); 42 | config.simulation.run(&mut config.system, config.nsteps); 43 | let e_final = config.system.total_energy(); 44 | assert!(f64::abs((e_initial - e_final) / e_final) < 1e-2); 45 | } 46 | -------------------------------------------------------------------------------- /tests/md-water.rs: -------------------------------------------------------------------------------- 1 | // Lumol, an extensible molecular simulation engine 2 | // Copyright (C) Lumol's contributors — BSD license 3 | 4 | //! Testing physical properties of f-SPC water 5 | use lumol::input::Input; 6 | 7 | use std::path::Path; 8 | use std::sync::Once; 9 | static START: Once = Once::new(); 10 | 11 | 12 | #[test] 13 | fn constant_energy_ewald() { 14 | START.call_once(::env_logger::init); 15 | let path = Path::new(file!()).parent() 16 | .unwrap() 17 | .join("data") 18 | .join("md-water") 19 | .join("nve-ewald.toml"); 20 | let mut config = Input::new(path).unwrap().read().unwrap(); 21 | 22 | let e_initial = config.system.total_energy(); 23 | config.simulation.run(&mut config.system, config.nsteps); 24 | let e_final = config.system.total_energy(); 25 | 26 | // FIXME? This thresold is really bad 27 | assert!(f64::abs((e_initial - e_final) / e_final) < 1e-1); 28 | } 29 | 30 | #[test] 31 | fn constant_energy_wolf() { 32 | START.call_once(::env_logger::init); 33 | let path = Path::new(file!()).parent() 34 | .unwrap() 35 | .join("data") 36 | .join("md-water") 37 | .join("nve-wolf.toml"); 38 | let mut config = Input::new(path).unwrap().read().unwrap(); 39 | 40 | let e_initial = config.system.total_energy(); 41 | config.simulation.run(&mut config.system, config.nsteps); 42 | let e_final = config.system.total_energy(); 43 | assert!(f64::abs((e_initial - e_final) / e_final) < 3e-2); 44 | } 45 | -------------------------------------------------------------------------------- /tests/utils/mod.rs: -------------------------------------------------------------------------------- 1 | // Lumol, an extensible molecular simulation engine 2 | // Copyright (C) Lumol's contributors — BSD license 3 | #![allow(dead_code)] 4 | 5 | use lumol::sim::output::Output; 6 | use lumol::System; 7 | 8 | use std::rc::Rc; 9 | use std::sync::RwLock; 10 | 11 | pub type SharedVec = Rc>>; 12 | 13 | /// Collect pressure and temperature of a simulation after a starting step 14 | pub struct Collector { 15 | start: u64, 16 | pressures: SharedVec, 17 | temperatures: SharedVec, 18 | } 19 | 20 | impl Collector { 21 | pub fn starting_at(start: u64) -> Collector { 22 | let pressures = Vec::with_capacity(10_000); 23 | let temperatures = Vec::with_capacity(10_000); 24 | Collector { 25 | start, 26 | pressures: Rc::new(RwLock::new(pressures)), 27 | temperatures: Rc::new(RwLock::new(temperatures)), 28 | } 29 | } 30 | 31 | pub fn temperatures(&self) -> SharedVec { 32 | self.temperatures.clone() 33 | } 34 | 35 | pub fn pressures(&self) -> SharedVec { 36 | self.pressures.clone() 37 | } 38 | } 39 | 40 | impl Output for Collector { 41 | fn write(&mut self, system: &System) { 42 | if system.step < self.start { 43 | return; 44 | } 45 | 46 | self.pressures.write().unwrap().push(system.pressure()); 47 | self.temperatures.write().unwrap().push(system.temperature()); 48 | } 49 | } 50 | 51 | pub fn mean(data: SharedVec) -> f64 { 52 | let data = data.read().unwrap(); 53 | data.iter().sum::() / data.len() as f64 54 | } 55 | -------------------------------------------------------------------------------- /tutorials/potential/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "lumol_tutorial_potential" 3 | version = "0.0.0" 4 | publish = false 5 | edition = "2021" 6 | 7 | [dependencies] 8 | lumol = {path = "../../"} 9 | 10 | [[bin]] 11 | name = "lumol_tutorial_potential" 12 | test = false 13 | doctest = false 14 | bench = false 15 | 16 | [lib] 17 | test = false 18 | doctest = false 19 | bench = false 20 | -------------------------------------------------------------------------------- /tutorials/potential/data/argon.toml: -------------------------------------------------------------------------------- 1 | [input] 2 | version = 1 3 | 4 | [[systems]] 5 | file = "argon.xyz" 6 | cell = 31.0 7 | 8 | [systems.potentials.global] 9 | cutoff = "14.0 A" 10 | tail_correction = true 11 | 12 | [[simulations]] 13 | nsteps = 1_00000 14 | outputs = [ 15 | {type = "Energy", file = "mie_energy.dat", frequency = 500}, 16 | {type = "Properties", file = "mie_prp.dat", frequency = 500} 17 | ] 18 | 19 | [simulations.propagator] 20 | type = "MonteCarlo" 21 | temperature = "217.0 K" 22 | update_frequency = 500 23 | 24 | moves = [ 25 | {type = "Translate", delta = "10 A", frequency = 500, target_acceptance = 0.5}, 26 | ] 27 | -------------------------------------------------------------------------------- /tutorials/potential/src/lib.rs: -------------------------------------------------------------------------------- 1 | use lumol::energy::{Potential, PairPotential}; 2 | 3 | #[derive(Clone, Copy)] 4 | pub struct Mie { 5 | /// Distance constant 6 | sigma: f64, 7 | /// Exponent of repulsive contribution 8 | n: f64, 9 | /// Exponent of attractive contribution 10 | m: f64, 11 | /// Energetic prefactor computed from the exponents and epsilon 12 | prefactor: f64, 13 | } 14 | 15 | impl Mie { 16 | pub fn new(sigma: f64, epsilon: f64, n: f64, m: f64) -> Mie { 17 | if m >= n { 18 | panic!("The repulsive exponent n has to be larger than the attractive exponent m") 19 | }; 20 | let prefactor = n / (n - m) * (n / m).powf(m / (n - m)) * epsilon; 21 | Mie { 22 | sigma, 23 | n, 24 | m, 25 | prefactor, 26 | } 27 | } 28 | } 29 | 30 | impl Potential for Mie { 31 | fn energy(&self, r: f64) -> f64 { 32 | let sigma_r = self.sigma / r; 33 | let repulsive = f64::powf(sigma_r, self.n); 34 | let attractive = f64::powf(sigma_r, self.m); 35 | 36 | self.prefactor * (repulsive - attractive) 37 | } 38 | 39 | fn force(&self, r: f64) -> f64 { 40 | let sigma_r = self.sigma / r; 41 | let repulsive = f64::powf(sigma_r, self.n); 42 | let attractive = f64::powf(sigma_r, self.m); 43 | 44 | -self.prefactor * (self.n * repulsive - self.m * attractive) / r 45 | } 46 | } 47 | 48 | impl PairPotential for Mie { 49 | fn tail_energy(&self, cutoff: f64) -> f64 { 50 | if self.m < 3.0 { 51 | return 0.0; 52 | }; 53 | let sigma_rc = self.sigma / cutoff; 54 | let n_3 = self.n - 3.0; 55 | let m_3 = self.m - 3.0; 56 | let repulsive = f64::powf(sigma_rc, n_3); 57 | let attractive = f64::powf(sigma_rc, m_3); 58 | 59 | -self.prefactor * self.sigma.powi(3) * (repulsive / n_3 - attractive / m_3) 60 | } 61 | 62 | fn tail_virial(&self, cutoff: f64) -> f64 { 63 | if self.m < 3.0 { 64 | return 0.0; 65 | }; 66 | let sigma_rc = self.sigma / cutoff; 67 | let n_3 = self.n - 3.0; 68 | let m_3 = self.m - 3.0; 69 | let repulsive = f64::powf(sigma_rc, n_3); 70 | let attractive = f64::powf(sigma_rc, m_3); 71 | 72 | -self.prefactor * self.sigma.powi(3) * (repulsive * self.n / n_3 - attractive * self.m / m_3) 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /tutorials/potential/src/main.rs: -------------------------------------------------------------------------------- 1 | use lumol_tutorial_potential::Mie; 2 | 3 | use lumol::input::Input; 4 | use lumol::energy::PairInteraction; 5 | use lumol::units; 6 | 7 | // This function runs a small Monte-Carlo simulation for Argon using a Mie potential. 8 | fn main() { 9 | // read configuration from input file located at the data/ folder 10 | let config = Input::new("data/argon.toml").unwrap().read().unwrap(); 11 | let mut system = config.system; 12 | let mut simulation = config.simulation; 13 | 14 | // build a potential 15 | let mie = Mie::new(units::from(3.405, "A").unwrap(), 16 | units::from(1.0, "kJ/mol").unwrap(), 17 | 12.0, 18 | 6.0); 19 | // use the potential with a cut off radius of 3 * sigma 20 | let mut interaction = PairInteraction::new(Box::new(mie), units::from(3.0 * 3.405, "A").unwrap()); 21 | // use tail corrections to account for our truncation 22 | interaction.enable_tail_corrections(); 23 | // finally use this interaction for Argon atoms 24 | system.set_pair_potential(("Ar", "Ar"), interaction); 25 | 26 | // report the initial system energy 27 | let initial_energy = units::to(system.total_energy(), "kJ/mol").unwrap(); 28 | println!("initial energy : {}", initial_energy); 29 | 30 | // run the simulation 31 | simulation.run(&mut system, config.nsteps); 32 | 33 | // print some final information 34 | let final_energy = units::to(system.total_energy(), "kJ/mol").unwrap(); 35 | println!("final energy : {}", final_energy); 36 | println!("It worked. Hooray!") 37 | } 38 | --------------------------------------------------------------------------------