From 05b8939737d19bb26741ace57b08de0aed93e4d8 Mon Sep 17 00:00:00 2001 From: mgastegger Date: Mon, 24 Oct 2022 17:29:14 +0200 Subject: [PATCH] Moved and adapted CLI docs for MD. --- docs/userguide/md.rst | 272 +++++- .../tutorial_04_molecular_dynamics.ipynb | 797 ++++++++++-------- 2 files changed, 703 insertions(+), 366 deletions(-) diff --git a/docs/userguide/md.rst b/docs/userguide/md.rst index 6c77dfbc8..1366c504e 100644 --- a/docs/userguide/md.rst +++ b/docs/userguide/md.rst @@ -1,8 +1,270 @@ -=============================== -Run MD simulations with the CLI -=============================== +=================================== +Running MD simulations with the CLI +=================================== .. _md: +Similar to the basic SchNetPack usage, it is also possible to quickly set up molecular dynamics (MD) simulations using +a combination of the `Hydra `_ command line interface (CLI) and predefined config files. The latter +can be found in ``src/schnetpack/md/md_configs``. +In the following, we will give a short introduction on how to use the CLI and/or config files for performing +MD simulations with the ``spkmd`` script. + +Basic command line input +======================== + +The inputs which need to be provided for every ``spkmd`` run are: + +* a simulation directory (``simulation_dir``) +* the initial molecular geometry in an ASE readable format (``system.molecule_file``) +* the path to a trained ML model (``calculator.model_file``) +* and the cutoff used in the neighbor list (``calculator.neighbor_list.cutoff``) + +Assuming the model and structure file are present in the local directory, the command line call would be:: + + spkmd simulation_dir=mdtut_cli system.molecule_file=md_ethanol.xyz calculator.model_file=md_ethanol.model calculator.neighbor_list.cutoff=5.0 + +This command would carry out a classical NVE simulation in the ``mdtut_cli`` directory, running on the GPU for 1000000 +steps, using a time step of 0.5 fs (the device can be switched by appending ``device=cpu``). It would further +automatically set up checkpointing and logging to HDF5 and tensorboard as described above. + +Running the command will print out the full config used for the simulation:: + + ⚙ Running with the following config: + ├── device + │ └── cuda + ├── precision + │ └── 32 + ├── seed + │ └── None + ├── simulation_dir + │ └── mdtut_cli + ├── overwrite + │ └── False + ├── restart + │ └── None + ├── calculator + │ └── neighbor_list: + │ _target_: schnetpack.md.neighborlist_md.NeighborListMD + │ cutoff: 5.0 + │ cutoff_shell: 2.0 + │ requires_triples: false + │ base_nbl: schnetpack.transform.ASENeighborList + │ collate_fn: schnetpack.data.loader._atoms_collate_fn + │ _target_: schnetpack.md.calculators.SchNetPackCalculator + │ required_properties: + │ - energy + │ - forces + │ model_file: md_ethanol.model + │ force_key: forces + │ energy_unit: kcal / mol + │ position_unit: Angstrom + │ energy_key: energy + │ stress_key: null + │ script_model: false + ├── system + │ └── initializer: + │ _target_: schnetpack.md.UniformInit + │ temperature: 300 + │ remove_center_of_mass: true + │ remove_translation: true + │ remove_rotation: true + │ wrap_positions: false + │ molecule_file: md_ethanol.xyz + │ load_system_state: null + │ n_replicas: 1 + │ position_unit_input: Angstrom + │ mass_unit_input: 1.0 + ├── dynamics + │ └── integrator: + │ _target_: schnetpack.md.integrators.VelocityVerlet + │ time_step: 0.5 + │ n_steps: 1000000 + │ thermostat: null + │ barostat: null + │ progress: true + │ simulation_hooks: [] + └── callbacks + └── checkpoint: + _target_: schnetpack.md.simulation_hooks.Checkpoint + checkpoint_file: checkpoint.chk + every_n_steps: 10 + hdf5: + _target_: schnetpack.md.simulation_hooks.FileLogger + filename: simulation.hdf5 + buffer_size: 100 + data_streams: + - _target_: schnetpack.md.simulation_hooks.MoleculeStream + store_velocities: true + - _target_: schnetpack.md.simulation_hooks.PropertyStream + target_properties: + - energy + every_n_steps: 1 + precision: 32 + tensorboard: + _target_: schnetpack.md.simulation_hooks.TensorBoardLogger + log_file: logs + properties: + - energy + - temperature + every_n_steps: 10 + +As can be seen, the config is structured into different blocks, e.g. ``calculator``, ``system``, +``dynamics`` and ``callbacks`` specifying the machine learning model, the system to be simulated, the settings for the +MD simulation and logging instructions. + +Customizing the simulation +========================== + +In the following, we will describe how to configure a simulation by overwriting existing configurations and loading +additional settings from predefined configs. As an example, we will carry out a MD run using a Langevin thermostat. + +For this, we first need to change the number of simulation steps from 1000000 to 20000. +Since the corresponding config entry is ``n_steps`` in the ``dynamics`` block, this can be done by adding +``dynamics.n_steps=20000`` to the command line. Changing other existing config entries can be done in a similar manner. + +We also need to add a thermostat to the simulation. +For convenience, several thermostats are preconfigured in ``src/schnetpack/md/md_configs/dynamics/thermostat``. +To load the Langevin thermostat (``langevin``), we add the ``+dynamics/thermostat=langevin`` option to the command line +call:: + + spkmd simulation_dir=mdtut_cli system.molecule_file=md_ethanol.xyz calculator.model_file=md_ethanol.model calculator.neighbor_list.cutoff=5.0 dynamics.n_steps=20000 +dynamics/thermostat=langevin + +The simulation config will now show a different entry for the ``thermostat`` option in the ``dynamics`` block:: + + │ thermostat: + │ _target_: schnetpack.md.simulation_hooks.LangevinThermostat + │ temperature_bath: 300.0 + │ time_constant: 100.0 + +Here, the thermostat temperature is already set to the desired 300 K. +Similar to the simulation steps, it could e.g. be changed to 500 K with the option +``dynamics.thermostat.temperature_bath=500`` + +We could also easily use another preconfigured thermostat (e.g. Nosé-Hover chains, ``+dynamic/thermostat=nhc``) +or add a barostat if we wanted to perform a constant pressure simulation (e.g. an isotropic Nosé-Hoover barostat, +``+dynamic/barostat=nhc_iso``). A similar syntax can be used to modify the neighbor list in the calculator +(e.g. to use a torch based implementation add ``calculator/neighbor_list=torch``) You might have noticed, that some +modifications use a ``+`` where others do not. A general rule is, that the ``+`` is required if the corresponding entry +did not exists before or was empty (e.g. ``thermostat: null`` in the very first config). + +Using the CLI, it is also possible to perform more extensive modifications to the simulation. +To carry out a ring polymer molecular dynamics (RPMD) simulation via the CLI for example, we have to: + +* switch the integrator from Velocity Verlet to a suitable RPMD integrator (``dynamics/integrator=rpmd``) +* set the number of beads/replicas (``system.n_replicas=4``) +* add a suitable thermostat (``+dynamics/thermostat=pile_local``) +* and change the number of steps to 50000 (``dynamics.n_steps=50000``) + +We should also change the simulation directory. +The corresponding command would be + + spkmd simulation_dir=mdtut_cli_rpmd system.molecule_file=md_ethanol.xyz calculator.model_file=md_ethanol.model calculator.neighbor_list.cutoff=5.0 dynamics/integrator=rpmd system.n_replicas=4 +dynamics/thermostat=pile_local dynamics.n_steps=50000 + +A quick look at the ``dynamics.integrator`` block confirms that it has changed and also uses reasonable defaults for the +time step and bead temperature:: + + │ └── integrator: + │ _target_: schnetpack.md.integrators.RingPolymer + │ time_step: 0.2 + │ temperature: 300.0 + +Running simulations from config files +===================================== + +In some cases, it can be useful to run simulations using config files as input. +These can for example be created using the ``spkmd`` CLI and then fine-tuned to suit one's needs. + +Full configs for the MD can either be found in the simulation directories (``mdtut_cli/.hydra/config.yaml``) or +generated with ``spkmd`` by adding the ``--cfg job`` option and redirecting the output to a ``yaml`` file. This can then +be saved, modified and used to run simulations. + +The config file for the MD with the Langevin thermostat would look something like this:: + + calculator: + neighbor_list: + _target_: schnetpack.md.neighborlist_md.NeighborListMD + cutoff: 5.0 + cutoff_shell: 2.0 + requires_triples: false + base_nbl: schnetpack.transform.ASENeighborList + collate_fn: schnetpack.data.loader._atoms_collate_fn + _target_: schnetpack.md.calculators.SchNetPackCalculator + required_properties: + - energy + - forces + model_file: md_ethanol.model + force_key: forces + energy_unit: kcal / mol + position_unit: Angstrom + energy_key: energy + stress_key: null + script_model: false + system: + initializer: + _target_: schnetpack.md.UniformInit + temperature: 300 + remove_center_of_mass: true + remove_translation: true + remove_rotation: true + wrap_positions: false + molecule_file: md_ethanol.xyz + load_system_state: null + n_replicas: 1 + position_unit_input: Angstrom + mass_unit_input: 1.0 + dynamics: + integrator: + _target_: schnetpack.md.integrators.VelocityVerlet + time_step: 0.5 + n_steps: 20000 + thermostat: + _target_: schnetpack.md.simulation_hooks.LangevinThermostat + temperature_bath: 300.0 + time_constant: 100.0 + barostat: null + progress: true + simulation_hooks: [] + callbacks: + checkpoint: + _target_: schnetpack.md.simulation_hooks.Checkpoint + checkpoint_file: checkpoint.chk + every_n_steps: 10 + hdf5: + _target_: schnetpack.md.simulation_hooks.FileLogger + filename: simulation.hdf5 + buffer_size: 100 + data_streams: + - _target_: schnetpack.md.simulation_hooks.MoleculeStream + store_velocities: true + - _target_: schnetpack.md.simulation_hooks.PropertyStream + target_properties: + - energy + every_n_steps: 1 + precision: ${precision} + tensorboard: + _target_: schnetpack.md.simulation_hooks.TensorBoardLogger + log_file: logs + properties: + - energy + - temperature + every_n_steps: 10 + device: cuda + precision: 32 + seed: null + simulation_dir: mdtut_cli + overwrite: false + restart: null + +Settings can then be changed by modifying the corresponding entries. +E.g. to increase the simulation temperature to 500 K, the ``temperature_bath`` entry in the ``thermostat`` block can be +changed to 500. + +Assuming the config file is e.g. stored in ``md_input_langevin.yaml``, it can be used to run the MD with the command:: + + spkmd simulation_dir=md_from_config load_config=md_input_langevin.yaml + +The ``simulation_dir`` option is still required, due to how hydra resolves configs. +Any ``simulation_dir`` entries in the provided config file will be ignored. + +Since the ``hydra`` parser operates on classes from python modules, they can also be easily adapted to integrate external modules, e.g. custom calculators for simulations. -TODO -==== \ No newline at end of file diff --git a/examples/tutorials/tutorial_04_molecular_dynamics.ipynb b/examples/tutorials/tutorial_04_molecular_dynamics.ipynb index a2742abca..678dc6b2f 100644 --- a/examples/tutorials/tutorial_04_molecular_dynamics.ipynb +++ b/examples/tutorials/tutorial_04_molecular_dynamics.ipynb @@ -2,7 +2,11 @@ "cells": [ { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, "source": [ "# Molecular dynamics in SchNetPack\n", "\n", @@ -23,7 +27,11 @@ }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, "source": [ "## Getting started\n", "\n", @@ -34,7 +42,11 @@ { "cell_type": "code", "execution_count": 1, - "metadata": {}, + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, "outputs": [], "source": [ "import os\n", @@ -48,7 +60,11 @@ }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, "source": [ "Since we want to run MD simulations, we need a SchNetPack model trained on forces and a molecular structure as a starting point.\n", "In principle, we could use the ethanol model and structure generated in the previous tutorial.\n", @@ -61,8 +77,21 @@ { "cell_type": "code", "execution_count": 2, - "metadata": {}, - "outputs": [], + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/home/mitx/anaconda3/envs/spkdev/lib/python3.8/site-packages/torchvision/io/image.py:13: UserWarning: Failed to load image Python extension: /home/mitx/anaconda3/envs/spkdev/lib/python3.8/site-packages/torchvision/image.so: undefined symbol: _ZN3c106detail19maybe_wrap_dim_slowEllb\n", + " warn(f\"Failed to load image Python extension: {e}\")\n" + ] + } + ], "source": [ "import schnetpack as spk\n", "\n", @@ -79,7 +108,11 @@ }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, "source": [ "## MD in SchNetPack\n", "\n", @@ -102,7 +135,11 @@ }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, "source": [ "### System\n", "\n", @@ -162,7 +199,11 @@ }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, "source": [ "Right now, all system momenta are set to zero.\n", "For practical purposes, one usually wants to draw the momenta from a distribution corresponding to a certain temperature.\n", @@ -174,7 +215,11 @@ { "cell_type": "code", "execution_count": 4, - "metadata": {}, + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, "outputs": [], "source": [ "from schnetpack.md import UniformInit\n", @@ -195,14 +240,22 @@ }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, "source": [ "The `Initializer` can also be used to center the moleculer structure on the center of mass and remove all translational and rotational components of the momenta, as was done in the code snippet above." ] }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, "source": [ "### Integrator\n", "\n", @@ -220,7 +273,11 @@ { "cell_type": "code", "execution_count": 5, - "metadata": {}, + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, "outputs": [], "source": [ "from schnetpack.md.integrators import VelocityVerlet\n", @@ -233,14 +290,22 @@ }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, "source": [ "### Calculator" ] }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, "source": [ "The only ingredient missing for simulating our system is a `Calculator` to compute molecular forces and other properties.\n", "A `Calculator` can be thought of as an interface between a computation method (e.g. a machine learning model) and the MD code in SchNetPack.\n", @@ -283,7 +348,11 @@ }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, "source": [ "In a second step, the `Calculator` needs to be set up.\n", "Similar as for the ASE interface in the [last tutorial](tutorial_03_force_models.ipynb), we have to tell the calculator the path to a stored model and how the forces are named in the output.\n", @@ -302,6 +371,9 @@ "cell_type": "code", "execution_count": 7, "metadata": { + "pycharm": { + "name": "#%%\n" + }, "scrolled": true }, "outputs": [ @@ -333,7 +405,11 @@ }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, "source": [ "### Simulator (bringing it all together)\n", "\n", @@ -345,7 +421,11 @@ { "cell_type": "code", "execution_count": 8, - "metadata": {}, + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, "outputs": [], "source": [ "from schnetpack.md import Simulator\n", @@ -359,7 +439,11 @@ }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, "source": [ "Before starting the actual simulation, it is also recommended to set the desired floating point precision and computational device:" ] @@ -393,7 +477,11 @@ }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, "source": [ "To finally carry out the simulation, one needs to call the `simulate` function with an integer argument specifying the number of simulation steps.\n", "\n", @@ -404,6 +492,9 @@ "cell_type": "code", "execution_count": 10, "metadata": { + "pycharm": { + "name": "#%%\n" + }, "scrolled": true }, "outputs": [ @@ -411,7 +502,7 @@ "name": "stderr", "output_type": "stream", "text": [ - "100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 100/100 [00:01<00:00, 97.72it/s]\n" + "100%|█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 100/100 [00:00<00:00, 122.97it/s]\n" ] } ], @@ -423,7 +514,11 @@ }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, "source": [ "Since the `Simulator` keeps track of the state of the dynamics and the system, we can call it repeatetly to get longer trajectories." ] @@ -431,13 +526,17 @@ { "cell_type": "code", "execution_count": 11, - "metadata": {}, + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 100/100 [00:01<00:00, 83.36it/s]\n" + "100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 100/100 [00:01<00:00, 83.10it/s]\n" ] } ], @@ -447,7 +546,11 @@ }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, "source": [ "The actual number of steps is stored in the `step` variable of the `Simulator` class." ] @@ -455,7 +558,11 @@ { "cell_type": "code", "execution_count": 12, - "metadata": {}, + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, "outputs": [ { "name": "stdout", @@ -471,7 +578,11 @@ }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, "source": [ "Although we are now able to run a full-fledged MD simulation, there is one major problem with the current setup:\n", "we do not collect any information during the simulation, such as nuclear positions.\n", @@ -483,7 +594,11 @@ }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, "source": [ "\n", "\n", @@ -512,7 +627,11 @@ }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, "source": [ "### Adding a Thermostat\n", "\n", @@ -526,7 +645,11 @@ { "cell_type": "code", "execution_count": 13, - "metadata": {}, + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, "outputs": [], "source": [ "from schnetpack.md.simulation_hooks import LangevinThermostat\n", @@ -541,7 +664,11 @@ }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, "source": [ "In case of the Langevin thermostat, a bath temperature (in Kelvin) and a time constant (in fs) have to be provided.\n", "The first regulates the temperature the system is kept at, the second how fast the thermostat adjusts the temperature. \n", @@ -553,7 +680,11 @@ { "cell_type": "code", "execution_count": 14, - "metadata": {}, + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, "outputs": [], "source": [ "simulation_hooks = [\n", @@ -563,7 +694,11 @@ }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, "source": [ "### Collecting Data\n", "\n", @@ -583,7 +718,11 @@ { "cell_type": "code", "execution_count": 15, - "metadata": {}, + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, "outputs": [], "source": [ "from schnetpack.md.simulation_hooks import callback_hooks\n", @@ -615,7 +754,11 @@ }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, "source": [ "### Storing checkpoints\n", "\n", @@ -630,7 +773,11 @@ { "cell_type": "code", "execution_count": 16, - "metadata": {}, + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, "outputs": [], "source": [ "#Set the path to the checkpoint file\n", @@ -645,7 +792,11 @@ }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, "source": [ "### Monitoring the simulation with TensorBoard\n", "\n", @@ -685,7 +836,11 @@ }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, "source": [ "The simulation progress of the different properties can then be viewed in TensorBoard via\n", "\n", @@ -694,7 +849,11 @@ }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, "source": [ "### Adding hooks and running the simulation\n", "\n", @@ -705,7 +864,11 @@ { "cell_type": "code", "execution_count": 18, - "metadata": {}, + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, "outputs": [], "source": [ "md_simulator = Simulator(md_system, md_integrator, md_calculator, simulator_hooks=simulation_hooks)\n", @@ -716,7 +879,11 @@ }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, "source": [ "We can now use the simulator to run a MD trajectory of our ethanol. Here, we run for 20000 steps, which are 10 ps.\n", "This should take approximately 5 minutes on a notebook GPU." @@ -726,6 +893,9 @@ "cell_type": "code", "execution_count": 19, "metadata": { + "pycharm": { + "name": "#%%\n" + }, "scrolled": false }, "outputs": [ @@ -733,7 +903,7 @@ "name": "stderr", "output_type": "stream", "text": [ - "100%|█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 20000/20000 [03:04<00:00, 108.59it/s]\n" + "100%|█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 20000/20000 [03:15<00:00, 102.34it/s]\n" ] } ], @@ -745,7 +915,11 @@ }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, "source": [ "After the simulation, the tutorial directory should contain the following entries:\n", "- `simulation.hdf5` holding the collected data\n", @@ -755,7 +929,11 @@ }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, "source": [ "## Reading HDF5 outputs\n", "\n", @@ -766,7 +944,11 @@ { "cell_type": "code", "execution_count": 20, - "metadata": {}, + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, "outputs": [ { "name": "stderr", @@ -784,7 +966,11 @@ }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, "source": [ "Extracted data is stored in the `properties` dictionary of the `HDF5Loader` and can be accessed with the `get_property` function.\n", "Right now, we can access the following entries, most of which should be self explaining and correspond to the standard SchNetPack `properties` keys:" @@ -793,7 +979,11 @@ { "cell_type": "code", "execution_count": 21, - "metadata": {}, + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, "outputs": [ { "name": "stdout", @@ -816,14 +1006,22 @@ }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, "source": [ "`masses` are the atomic masses in Dalton. The two energies `energy` and `energy_system` are present, since we a) requested the energy from the `Calculator` to be stored as the potential energy of `System` with the `energy_key` keyword and b) we requested the `energy` property to be logged in the `PropertyStream` of the `FileLogger`. The difference between both quantities is that the former uses SchNetPack internal units (kJ/mol) while the latter uses the `Calculator`'s units (kcal/mol). While logging both is not necessary for practical purposes, it serves as an example for the different ways to log quantities during simulations." ] }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, "source": [ "### Extracting basic properties\n", "\n", @@ -842,7 +1040,11 @@ { "cell_type": "code", "execution_count": 22, - "metadata": {}, + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, "outputs": [ { "name": "stdout", @@ -1819,7 +2021,7 @@ { "data": { "text/html": [ - "" + "" ], "text/plain": [ "" @@ -1864,14 +2066,22 @@ }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, "source": [ "As would be expected, once the energy stored in the `System` class has been converted from MD internal units to kcal/mol with the `convert_units` function, both curves are identical." ] }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, "source": [ "The functions provided by the `HDF5Loader` also offer access to a number of derived properties, such as the kinetic energy (`get_kinetic_energy`), the temperature (`get_temperature`) or the pressure (`get_pressure`).\n", "\n", @@ -1881,7 +2091,11 @@ { "cell_type": "code", "execution_count": 23, - "metadata": {}, + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, "outputs": [ { "data": { @@ -2851,7 +3065,7 @@ { "data": { "text/html": [ - "" + "" ], "text/plain": [ "" @@ -2889,7 +3103,11 @@ }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, "source": [ "As can be seen, the system requires an initial period for equilibration.\n", "This is relevant for simulations, as ensemble properties are typically only computed for fully equilibrated systems.\n", @@ -2905,7 +3123,11 @@ { "cell_type": "code", "execution_count": 24, - "metadata": {}, + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, "outputs": [ { "name": "stderr", @@ -2921,7 +3143,11 @@ }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, "source": [ "We can easily see, that only the later part of the simulation is now considered by plotting the data once again:" ] @@ -2929,7 +3155,11 @@ { "cell_type": "code", "execution_count": 25, - "metadata": {}, + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, "outputs": [ { "data": { @@ -3899,7 +4129,7 @@ { "data": { "text/html": [ - "" + "" ], "text/plain": [ "" @@ -3915,7 +4145,11 @@ }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, "source": [ "As stated before, the HDF5 datafile uses a special convention for units.\n", "For internal quantities (e.g. positions, velocities and kinetic energy), internal MD units are used (based on kJ/mol, nm and Dalton).\n", @@ -3926,7 +4160,11 @@ }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, "source": [ "### Extracting structures\n", "\n", @@ -3949,7 +4187,7 @@ "output_type": "stream", "text": [ "INFO:schnetpack.md.data.hdf5_data:Extracting structures...\n", - "100%|████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 20000/20000 [00:02<00:00, 8022.83it/s]\n" + "100%|████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 20000/20000 [00:02<00:00, 8499.63it/s]\n" ] } ], @@ -3969,7 +4207,11 @@ }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, "source": [ "### Vibrational spectra\n", "\n", @@ -3985,7 +4227,11 @@ { "cell_type": "code", "execution_count": 27, - "metadata": {}, + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, "outputs": [ { "name": "stderr", @@ -4008,7 +4254,11 @@ }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, "source": [ "The `resolution` keyword specifies, how finely the peaks in the spectrum are resolved.\n", "`PowerSpectrum` also computes the effective resolution in inverse centimeters, as well as the spectral range.\n", @@ -4018,7 +4268,11 @@ { "cell_type": "code", "execution_count": 28, - "metadata": {}, + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, "outputs": [ { "data": { @@ -4988,7 +5242,7 @@ { "data": { "text/html": [ - "" + "" ], "text/plain": [ "" @@ -5014,7 +5268,11 @@ }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, "source": [ "The spectrum shows several typical vibrational bands for ethanol (which can be checked with [experimental tables available online](https://chem.libretexts.org/Ancillary_Materials/Reference/Reference_Tables/Spectroscopic_Parameters/Infrared_Spectroscopy_Absorption_Table)).\n", "For example, the peak close to 3700 cm-1 stems from the bond vibrations of the OH-group.\n", @@ -5032,7 +5290,11 @@ }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, "source": [ "## Restarting simulations\n", "\n", @@ -5044,7 +5306,11 @@ { "cell_type": "code", "execution_count": 29, - "metadata": {}, + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, "outputs": [], "source": [ "checkpoint = torch.load(chk_file)\n", @@ -5053,7 +5319,11 @@ }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, "source": [ "This restores the full state, including the system state, simulation steps and states of the thermostats.\n", "\n", @@ -5064,7 +5334,11 @@ { "cell_type": "code", "execution_count": 30, - "metadata": {}, + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, "outputs": [], "source": [ "md_simulator.system.load_system_state(checkpoint)" @@ -5072,7 +5346,11 @@ }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, "source": [ "## Ring polymer molecular dynamics with SchNetPack\n", "\n", @@ -5101,7 +5379,11 @@ { "cell_type": "code", "execution_count": 31, - "metadata": {}, + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, "outputs": [], "source": [ "# Number of beads in RPMD simulation\n", @@ -5121,7 +5403,11 @@ }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, "source": [ "Next, we need to change the integrator to the `RingPolymer` integrator.\n", "For RPMD, we need to use a smaller time step, in order to keep the integration numerically stable.\n", @@ -5155,7 +5441,11 @@ }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, "source": [ "Next, we have to change our thermostat to one suitable for RPMD simulations.\n", "We will use the local PILE thermostat, which can be thought of as a RPMD equivalent of the classical Langevin thermostat used above.\n", @@ -5166,7 +5456,11 @@ { "cell_type": "code", "execution_count": 33, - "metadata": {}, + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, "outputs": [], "source": [ "from schnetpack.md.simulation_hooks import PILELocalThermostat\n", @@ -5177,7 +5471,11 @@ }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, "source": [ "The hooks are generated in exactly the same way as before." ] @@ -5185,7 +5483,11 @@ { "cell_type": "code", "execution_count": 34, - "metadata": {}, + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, "outputs": [], "source": [ "# Logging\n", @@ -5223,7 +5525,11 @@ }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, "source": [ "And so is the simulator:" ] @@ -5231,7 +5537,11 @@ { "cell_type": "code", "execution_count": 35, - "metadata": {}, + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, "outputs": [], "source": [ "# Assemble the simulator\n", @@ -5243,7 +5553,11 @@ }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, "source": [ "Now we can carry out the simulations.\n", "Since our time step is shorter, we will run for longer in order to cover the same time scale as the classical simulation (runs approximately 13 minutes on a notebook GPU):" @@ -5252,13 +5566,17 @@ { "cell_type": "code", "execution_count": 36, - "metadata": {}, + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 50000/50000 [13:42<00:00, 60.79it/s]\n" + "100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 50000/50000 [16:02<00:00, 51.96it/s]\n" ] } ], @@ -5270,7 +5588,11 @@ }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, "source": [ "Loading of the data with the `HDF5Loader` works exactly the same as before.\n", "When loading properties for RPMD datafiles, the `HDF5Loader` default of using centroid properties (meaning an average over all beads) becomes active.\n", @@ -5282,7 +5604,11 @@ { "cell_type": "code", "execution_count": 37, - "metadata": {}, + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, "outputs": [ { "name": "stderr", @@ -6259,7 +6585,7 @@ { "data": { "text/html": [ - "" + "" ], "text/plain": [ "" @@ -6276,7 +6602,11 @@ }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, "source": [ "Finally, we can compute the power spectrum and compare it to its classical counterpart:" ] @@ -7266,7 +7596,7 @@ { "data": { "text/html": [ - "" + "" ], "text/plain": [ "" @@ -7301,7 +7631,11 @@ }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, "source": [ "One problem of purely classical simulations can be observed in the high frequency regions of the MD spectrum.\n", "Peaks are shifted towards higher wave numbers compared to the expected [experimental values](https://chem.libretexts.org/Ancillary_Materials/Reference/Reference_Tables/Spectroscopic_Parameters/Infrared_Spectroscopy_Absorption_Table),\n", @@ -7311,283 +7645,24 @@ }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, "source": [ "## Using the command line interface and config files\n", "\n", - "While setting up simulations in the way described above can be useful for testing and developing new approaches, it can grow tedious for routine simulations.\n", - "Because of this, SchNetPack provides the script `spkmd` to quickly set up MD simulations using a combination of the `hydra` command line interface (CLI) and predefined config files.\n", - "The latter can be found in `src/schnetpack/md/md_configs`.\n", - "\n", - "In the following, we will give a short introduction on how to use the CLI and/or config files for performing simulations with `spkmd`." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Basic command line input\n", - "\n", - "The inputs which need to be provided for every `spkmd` run are:\n", - "\n", - "- a simulation directory (`simulation_dir`)\n", - "- the initial molecular geometry in an ASE readable format (`system.molecule_file`)\n", - "- the path to a trained ML model (`calculator.model_file`)\n", - "- and the cutoff used in the neighbor list (`calculator.neighbor_list.cutoff`)\n", - "\n", - "Assuming the model and structure file used above are present in the local directory, the command line call would be:\n", - "\n", - " spkmd simulation_dir=mdtut_cli system.molecule_file=md_ethanol.xyz calculator.model_file=md_ethanol.model calculator.neighbor_list.cutoff=5.0\n", - "\n", - "This command would carry out a classical NVE simulation in the `mdtut_cli` directory, running on the GPU for 1 000 000 steps, using a time step of 0.5 fs (the device can be switched by appending `device=cpu`).\n", - "It would further automatically set up checkpointing and logging to HDF5 and tensorboard as described above.\n", - "\n", - "Running the command will print out the full config used for the simulation:\n", - "```\n", - "⚙ Running with the following config:\n", - "├── device\n", - "│ └── cuda\n", - "├── precision\n", - "│ └── 32\n", - "├── seed\n", - "│ └── None\n", - "├── simulation_dir\n", - "│ └── mdtut_cli\n", - "├── overwrite\n", - "│ └── False\n", - "├── restart\n", - "│ └── None\n", - "├── calculator\n", - "│ └── neighbor_list:\n", - "│ _target_: schnetpack.md.neighborlist_md.NeighborListMD\n", - "│ cutoff: 5.0\n", - "│ cutoff_shell: 2.0\n", - "│ requires_triples: false\n", - "│ base_nbl: schnetpack.transform.ASENeighborList\n", - "│ collate_fn: schnetpack.data.loader._atoms_collate_fn\n", - "│ _target_: schnetpack.md.calculators.SchNetPackCalculator\n", - "│ required_properties:\n", - "│ - energy\n", - "│ - forces\n", - "│ model_file: md_ethanol.model\n", - "│ force_key: forces\n", - "│ energy_unit: kcal / mol\n", - "│ position_unit: Angstrom\n", - "│ energy_key: energy\n", - "│ stress_key: null\n", - "│ script_model: false\n", - "├── system\n", - "│ └── initializer:\n", - "│ _target_: schnetpack.md.UniformInit\n", - "│ temperature: 300\n", - "│ remove_center_of_mass: true\n", - "│ remove_translation: true\n", - "│ remove_rotation: true\n", - "│ wrap_positions: false\n", - "│ molecule_file: md_ethanol.xyz\n", - "│ load_system_state: null\n", - "│ n_replicas: 1\n", - "│ position_unit_input: Angstrom\n", - "│ mass_unit_input: 1.0\n", - "├── dynamics\n", - "│ └── integrator:\n", - "│ _target_: schnetpack.md.integrators.VelocityVerlet\n", - "│ time_step: 0.5\n", - "│ n_steps: 1000000\n", - "│ thermostat: null\n", - "│ barostat: null\n", - "│ progress: true\n", - "│ simulation_hooks: []\n", - "└── callbacks\n", - " └── checkpoint:\n", - " _target_: schnetpack.md.simulation_hooks.Checkpoint\n", - " checkpoint_file: checkpoint.chk\n", - " every_n_steps: 10\n", - " hdf5:\n", - " _target_: schnetpack.md.simulation_hooks.FileLogger\n", - " filename: simulation.hdf5\n", - " buffer_size: 100\n", - " data_streams:\n", - " - _target_: schnetpack.md.simulation_hooks.MoleculeStream\n", - " store_velocities: true\n", - " - _target_: schnetpack.md.simulation_hooks.PropertyStream\n", - " target_properties:\n", - " - energy\n", - " every_n_steps: 1\n", - " precision: 32\n", - " tensorboard:\n", - " _target_: schnetpack.md.simulation_hooks.TensorBoardLogger\n", - " log_file: logs\n", - " properties:\n", - " - energy\n", - " - temperature\n", - " every_n_steps: 10\n", - "```\n", - "\n", - "As can be seen, the config is structured into different blocks, which correspond to the `calculator`, `system`, `dynamics` and `callbacks` structure introduced above." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Customizing the simulation\n", - "\n", - "In the following, we will describe how to configure a simulation by overwriting existing configurations and loading additional settings from predefined configs.\n", - "As an example, we will reproduce the MD run using the Langevin thermostat from above.\n", - "\n", - "For this, we first need to change the number of simulation steps from 1 000&\\thinsp;000 to 20 000.\n", - "Since the corresponding config entry is `n_steps` in the `dynamics` block, this can be done by adding `dynamics.n_steps=20000` to the command line.\n", - "Changing other existing config entries can be done in a similar manner.\n", - "\n", - "We also need to add a thermostat to the simulation.\n", - "For convenience, several thermostats are preconfigured in `src/schnetpack/md/md_configs/dynamics/thermostat`.\n", - "To load the Langevin thermostat (`langevin`), we add the `+dynamics/thermostat=langevin` option to the command line call:\n", - "\n", - " spkmd simulation_dir=mdtut_cli system.molecule_file=md_ethanol.xyz calculator.model_file=md_ethanol.model calculator.neighbor_list.cutoff=5.0 dynamics.n_steps=20000 +dynamics/thermostat=langevin\n", - "\n", - "The simulation config will now show a different entry for the `thermostat` option in the `dynamics` block:\n", - "```\n", - "│ thermostat:\n", - "│ _target_: schnetpack.md.simulation_hooks.LangevinThermostat\n", - "│ temperature_bath: 300.0\n", - "│ time_constant: 100.0\n", - "```\n", - "Here, the thermostat temperature is already set to the desired 300 K.\n", - "Similar to the simulation steps, it could e.g. be changed to 500 K with the option `dynamics.thermostat.temperature_bath=500`\n", - "\n", - "We could also easily use another preconfigured thermostat (e.g. Nosé--Hover chains, `+dynamic/thermostat=nhc`) or add a barostat if we wanted to perform a constant pressure simulation (e.g. an isotropic Nosé--Hoover barostat, `+dynamic/barostat=nhc_iso`).\n", - "A similar syntax can further be used to modify the neighbor list in the calculator (e.g. to use a torch based implementation add `calculator/neighbor_list=torch`)\n", - "You might have noticed, that some modifications use a `+` where others do not.\n", - "A general rule is, that the `+` is required if the corresponding entry did not exists before or was empty (e.g. `thermostat: null` in the very first config).\n", - "\n", - "Let us have a look at the RPMD simulation above.\n", - "To reproduce it via the CLI, we have to:\n", - "\n", - "- switch the integrator from Velocity Verlet to a suitable RPMD integrator (`dynamics/integrator=rpmd`)\n", - "- set the number of beads/replicas (`system.n_replicas=4`)\n", - "- add a suitable thermostat (`+dynamics/thermostat=pile_local`)\n", - "- and change the number of steps to 50000 (`dynamics.n_steps=50000`)\n", - "\n", - "We should also change the simulation directory.\n", - "The corresponding command would be\n", - "\n", - " spkmd simulation_dir=mdtut_cli_rpmd system.molecule_file=md_ethanol.xyz calculator.model_file=md_ethanol.model calculator.neighbor_list.cutoff=5.0 dynamics/integrator=rpmd system.n_replicas=4 +dynamics/thermostat=pile_local dynamics.n_steps=50000\n", - "\n", - "A quick look at the `dynamics.integrator` block confirms that it has changed and also uses reasonable defaults for the time step and bead temperature:\n", - "```\n", - "│ └── integrator:\n", - "│ _target_: schnetpack.md.integrators.RingPolymer\n", - "│ time_step: 0.2\n", - "│ temperature: 300.0\n", - "```" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Running simulations from config files\n", - "\n", - "In some cases, it can be useful to run simulations using config files as input.\n", - "These can for example be created using the `spkmd` CLI and then fine-tuned to suit one's needs.\n", - "\n", - "Full configs for the MD can either be found in the simulation directories (`mdtut_cli/.hydra/config.yaml`) or generated with `spkmd` by adding the `--cfg job` option and redirecting the output to a `yaml` file. This can then be saved, modified and used to run simulations.\n", - "\n", - "The config file for the MD with the Langevin thermostat would look something like this:\n", - "```yaml\n", - "calculator:\n", - " neighbor_list:\n", - " _target_: schnetpack.md.neighborlist_md.NeighborListMD\n", - " cutoff: 5.0\n", - " cutoff_shell: 2.0\n", - " requires_triples: false\n", - " base_nbl: schnetpack.transform.ASENeighborList\n", - " collate_fn: schnetpack.data.loader._atoms_collate_fn\n", - " _target_: schnetpack.md.calculators.SchNetPackCalculator\n", - " required_properties:\n", - " - energy\n", - " - forces\n", - " model_file: md_ethanol.model\n", - " force_key: forces\n", - " energy_unit: kcal / mol\n", - " position_unit: Angstrom\n", - " energy_key: energy\n", - " stress_key: null\n", - " script_model: false\n", - "system:\n", - " initializer:\n", - " _target_: schnetpack.md.UniformInit\n", - " temperature: 300\n", - " remove_center_of_mass: true\n", - " remove_translation: true\n", - " remove_rotation: true\n", - " wrap_positions: false\n", - " molecule_file: md_ethanol.xyz\n", - " load_system_state: null\n", - " n_replicas: 1\n", - " position_unit_input: Angstrom\n", - " mass_unit_input: 1.0\n", - "dynamics:\n", - " integrator:\n", - " _target_: schnetpack.md.integrators.VelocityVerlet\n", - " time_step: 0.5\n", - " n_steps: 20000\n", - " thermostat:\n", - " _target_: schnetpack.md.simulation_hooks.LangevinThermostat\n", - " temperature_bath: 300.0\n", - " time_constant: 100.0\n", - " barostat: null\n", - " progress: true\n", - " simulation_hooks: []\n", - "callbacks:\n", - " checkpoint:\n", - " _target_: schnetpack.md.simulation_hooks.Checkpoint\n", - " checkpoint_file: checkpoint.chk\n", - " every_n_steps: 10\n", - " hdf5:\n", - " _target_: schnetpack.md.simulation_hooks.FileLogger\n", - " filename: simulation.hdf5\n", - " buffer_size: 100\n", - " data_streams:\n", - " - _target_: schnetpack.md.simulation_hooks.MoleculeStream\n", - " store_velocities: true\n", - " - _target_: schnetpack.md.simulation_hooks.PropertyStream\n", - " target_properties:\n", - " - energy\n", - " every_n_steps: 1\n", - " precision: ${precision}\n", - " tensorboard:\n", - " _target_: schnetpack.md.simulation_hooks.TensorBoardLogger\n", - " log_file: logs\n", - " properties:\n", - " - energy\n", - " - temperature\n", - " every_n_steps: 10\n", - "device: cuda\n", - "precision: 32\n", - "seed: null\n", - "simulation_dir: mdtut_cli\n", - "overwrite: false\n", - "restart: null\n", - "```\n", - "\n", - "Settings can then be changed by modifying the corresponding entries.\n", - "E.g. to increase the simulation temperature to 500 K, the `temperature_bath` entry in the `thermostat` block can be changed to 500.\n", - "\n", - "Assuming the config file is e.g. stored in `md_input_langevin.yaml`, it can be used to run the MD with the command:\n", - "\n", - " spkmd simulation_dir=md_from_config load_config=md_input_langevin.yaml\n", - "\n", - "The `simulation_dir` option is still required, due to how hydra resolves configs.\n", - "Any `simulation_dir` entries in the provided config file will be ignored.\n", - "\n", - "Since the `hydra` parser operates on classes from python modules, they can also be easily adapted to integrate external modules, e.g. custom calculators for simulations." + "While setting up simulations in the way described above can be useful for testing and developing new approaches, it can grow tedious for routine simulations. Because of this, SchNetPack provides the script `spkmd` to quickly set up MD simulations using a combination of the `hydra` command line interface (CLI) and predefined config files. This functionality is covered in detail in the [Run MD simulations with the CLI](https://schnetpack.readthedocs.io/en/latest/userguide/md.html) section of the general SchNetPack user guide." ] }, { "cell_type": "markdown", - "metadata": {}, + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, "source": [ "## Summary\n", "\n",