diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml index ae7755b0..d2a48571 100644 --- a/.github/workflows/cd.yml +++ b/.github/workflows/cd.yml @@ -16,7 +16,7 @@ jobs: with: python-version: "3.8" - name: Make sure virtualevn>20 is installed, which will yield newer pip and possibility to pin pip version. - run: pip install virtualenv>20 + run: pip install "virtualenv>20" - name: Install Tox run: pip install tox - name: Run pre-commit in Tox @@ -77,7 +77,7 @@ jobs: run: conda install -y lammps==${{ matrix.lammps-version }} - name: Make sure virtualevn>20 is installed, which will yield newer pip and possibility to pin pip version. - run: pip install virtualenv>20 + run: pip install "virtualenv>20" - name: Install Tox run: pip install tox diff --git a/.gitignore b/.gitignore index 99c98074..3e725ab0 100644 --- a/.gitignore +++ b/.gitignore @@ -44,4 +44,4 @@ pip-wheel-metadata # Docs docs/_build/ docs/build -docs/source/reference/apidoc +docs/source/reference/api diff --git a/README.md b/README.md index 7f0b39d2..a3f36b12 100644 --- a/README.md +++ b/README.md @@ -2,15 +2,22 @@ [![Coverage Status](https://codecov.io/gh/aiidaplugins/aiida-lammps/branch/master/graph/badge.svg)](https://codecov.io/gh/aiidaplugins/aiida-lammps) [![PyPI](https://img.shields.io/pypi/v/aiida-lammps.svg)](https://pypi.python.org/pypi/aiida-lammps/) [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/ambv/black) +[![Docs status](https://readthedocs.org/projects/aiida-lammps/badge)](http://aiida-lammps.readthedocs.io/) # AiiDA LAMMPS plugin -A LAMMPS plugin for the [AiiDA](http://aiida-core.readthedocs.io/) framework. -This plugin contains 4 code types: +An [AiiDA](http://aiida-core.readthedocs.io/) plugin for the classical molecular dynamics code [LAMMPS](https://www.lammps.org). -- `lammps.forces`: Atomic single-point forces calculation -- `lammps.optimize`: Crystal structure optimization -- `lammps.md`: Molecular dynamics calculation +This plugin contains 2 types of calculations: + +- `lammps.base`: Calculation making use of parameter based input generation for single stage LAMMPS calculations. +- `lammps.raw`: Calculation making use of a pre-made LAMMPS input file. + +The `lammps.base` is also used to handle three workflows: + +- `lammps.base`: A workflow that can be used to submit any single stage LAMMPS calculation. +- `lammps.relax`: A workflow to submit a structural relaxation using LAMMPS. +- `lammps.md`: A workflow to submit a molecular dynamics calculation using LAMMPS. - [AiiDA LAMMPS plugin](#aiida-lammps-plugin) - [Installation](#installation) @@ -28,449 +35,96 @@ This plugin contains 4 code types: ## Installation -To install from pypi: +To install a stable version from pypi: ```shell pip install aiida-lammps ``` -## Built-in Potential Support - -- EAM -- Lennad Jones -- Tersoff -- ReaxFF - -## Examples - -More example calculations are found in the folder **/examples**, -and there are many test examples in **/aiida_lammps/tests/test_calculations**. - -### Code Setup - -```python -from tests.utils import ( - get_or_create_local_computer, get_or_create_code) -from tests.utils import lammps_version - -computer_local = get_or_create_local_computer('work_directory', 'localhost') -code_lammps_force = get_or_create_code('lammps.force', computer_local, 'lammps') -code_lammps_opt = get_or_create_code('lammps.optimize', computer_local, 'lammps') -code_lammps_md = get_or_create_code('lammps.md', computer_local, 'lammps') - -meta_options = { - "resources": { - "num_machines": 1, - "num_mpiprocs_per_machine": 1} -} -``` - -### Structure Setup - -```python -from aiida.plugins import DataFactory -import numpy as np - -cell = [[3.1900000572, 0, 0], - [-1.5950000286, 2.762621076, 0], - [0.0, 0, 5.1890001297]] - -positions = [(0.6666669, 0.3333334, 0.0000000), - (0.3333331, 0.6666663, 0.5000000), - (0.6666669, 0.3333334, 0.3750000), - (0.3333331, 0.6666663, 0.8750000)] - -symbols = names = ['Ga', 'Ga', 'N', 'N'] - -structure = DataFactory('structure')(cell=cell) -for position, symbol, name in zip(positions, symbols, names): - position = np.dot(position, cell).tolist() - structure.append_atom( - position=position, symbols=symbol, name=name) - -structure -``` +To install from source: -```console - -``` - -### Potential Setup - -```python -pair_style = 'tersoff' -potential_dict = { - 'Ga Ga Ga': '1.0 0.007874 1.846 1.918000 0.75000 -0.301300 1.0 1.0 1.44970 410.132 2.87 0.15 1.60916 535.199', - 'N N N': '1.0 0.766120 0.000 0.178493 0.20172 -0.045238 1.0 1.0 2.38426 423.769 2.20 0.20 3.55779 1044.77', - 'Ga Ga N': '1.0 0.001632 0.000 65.20700 2.82100 -0.518000 1.0 0.0 0.00000 0.00000 2.90 0.20 0.00000 0.00000', - 'Ga N N': '1.0 0.001632 0.000 65.20700 2.82100 -0.518000 1.0 1.0 2.63906 3864.27 2.90 0.20 2.93516 6136.44', - 'N Ga Ga': '1.0 0.001632 0.000 65.20700 2.82100 -0.518000 1.0 1.0 2.63906 3864.27 2.90 0.20 2.93516 6136.44', - 'N Ga N ': '1.0 0.766120 0.000 0.178493 0.20172 -0.045238 1.0 0.0 0.00000 0.00000 2.20 0.20 0.00000 0.00000', - 'N N Ga': '1.0 0.001632 0.000 65.20700 2.82100 -0.518000 1.0 0.0 0.00000 0.00000 2.90 0.20 0.00000 0.00000', - 'Ga N Ga': '1.0 0.007874 1.846 1.918000 0.75000 -0.301300 1.0 0.0 0.00000 0.00000 2.87 0.15 0.00000 0.00000'} -potential = DataFactory("lammps.potential")( - type=pair_style, data=potential_dict -) -potential.attributes -``` - -```python -{'kind_elements': ['Ga', 'N'], - 'potential_type': 'tersoff', - 'atom_style': 'atomic', - 'default_units': 'metal', - 'potential_md5': 'b3b7d45ae7b92eba05ed99ffe69810d0', - 'input_lines_md5': '3145644a408a6d464e80866b833115a2'} -``` - -### Force Calculation - -```python -from aiida.engine import run_get_node -parameters = DataFactory('dict')(dict={ - 'lammps_version': lammps_version(), - 'output_variables': ["temp", "etotal", "pe", "ke"], - 'thermo_keywords': [] -}) -builder = code_lammps_force.get_builder() -builder.metadata.options = meta_options -builder.structure = structure -builder.potential = potential -builder.parameters = parameters -result, calc_node = run_get_node(builder) -``` - -```console -$ verdi process list -D desc -a -l 1 - PK Created Process label Process State Process status ----- --------- ---------------- --------------- ---------------- -2480 32s ago LammpsForceCalculation Finished [0] - -Total results: 1 - -Info: last time an entry changed state: 28s ago (at 02:02:36 on 2019-06-21) - -$ verdi process show 2480 -Property Value -------------- ------------------------------------ -type CalcJobNode -pk 2480 -uuid c754f044-b190-4505-b121-776b79d2d1c8 -label -description -ctime 2019-06-21 02:02:32.894858+00:00 -mtime 2019-06-21 02:02:33.297377+00:00 -process state Finished -exit status 0 -computer [2] localhost - -Inputs PK Type ----------- ---- ------------------ -code 1351 Code -parameters 2479 Dict -potential 2478 LammpsEmpiricalPotential -structure 2477 StructureData - -Outputs PK Type -------------- ---- ---------- -arrays 2483 ArrayData -remote_folder 2481 RemoteData -results 2484 Dict -retrieved 2482 FolderData -``` - -```python -calc_node.outputs.results.attributes -``` - -```python -{'parser_version': '0.4.0b3', - 'parser_class': 'LammpsForceParser', - 'errors': [], - 'warnings': '', - 'distance_units': 'Angstroms', - 'force_units': 'eV/Angstrom', - 'energy_units': 'eV', - 'energy': -18.1098859130104, - 'final_variables': {'ke': 0.0, - 'pe': -18.1098859130104, - 'etotal': -18.1098859130104, - 'temp': 0.0}, - 'units_style': 'metal'} -``` - -```python -calc_node.outputs.arrays.attributes -``` - -```python -{'array|forces': [1, 4, 3]} +```shell +git clone https://github.com/aiidaplugins/aiida-lammps.git +pip install -e aiida-lammps ``` -### Optimisation Calculation - -```python -from aiida.engine import run_get_node -parameters = DataFactory('dict')(dict={ - 'lammps_version': lammps_version(), - 'output_variables': ["temp", "etotal", "pe", "ke"], - 'thermo_keywords': [], - 'units': 'metal', - 'relax': { - 'type': 'iso', - 'pressure': 0.0, - 'vmax': 0.001, - }, - "minimize": { - 'style': 'cg', - 'energy_tolerance': 1.0e-25, - 'force_tolerance': 1.0e-25, - 'max_evaluations': 100000, - 'max_iterations': 50000} -}) -builder = code_lammps_opt.get_builder() -builder.metadata.options = meta_options -builder.structure = structure -builder.potential = potential -builder.parameters = parameters -result, calc_node = run_get_node(builder) -``` +## Built-in Potential Support -```console -$ verdi process list -D desc -a -l 1 - PK Created Process label Process State Process status ----- --------- ------------------- --------------- ---------------- -2486 1m ago OptimizeCalculation ⏹ Finished [0] - -Total results: 1 - -Info: last time an entry changed state: 1m ago (at 02:09:54 on 2019-06-21) - -$ verdi process show 2486 -Property Value -------------- ------------------------------------ -type CalcJobNode -pk 2486 -uuid 5c64433d-6337-4352-a0a8-0acb4083a0c3 -label -description -ctime 2019-06-21 02:09:50.872336+00:00 -mtime 2019-06-21 02:09:51.128639+00:00 -process state Finished -exit status 0 -computer [2] localhost - -Inputs PK Type ----------- ---- ------------------ -code 1344 Code -parameters 2485 Dict -potential 2478 LammpsEmpiricalPotential -structure 2477 StructureData - -Outputs PK Type -------------- ---- ------------- -arrays 2490 ArrayData -remote_folder 2487 RemoteData -results 2491 Dict -retrieved 2488 FolderData -structure 2489 StructureData -``` +The `lammps.base` calculation and associated workflows make use of the ``LammpsPotentialData`` data structure which is created by passing a potential file, plus some labelling parameters to it. -```python -calc_node.outputs.results.attributes -``` +This data structure can be used to handle the following potential types: -```python -{'parser_version': '0.4.0b3', - 'parser_class': 'LammpsOptimizeParser', - 'errors': [], - 'warnings': '', - 'stress_units': 'bars', - 'distance_units': 'Angstroms', - 'force_units': 'eV/Angstrom', - 'energy_units': 'eV', - 'energy': -18.1108516231423, - 'final_variables': {'ke': 0.0, - 'pe': -18.1108516231423, - 'etotal': -18.1108516231423, - 'temp': 0.0}, - 'units_style': 'metal'} -``` +- Single file potentials: Any potential that can be stored in a single file, e.g. [EAM](https://docs.lammps.org/pair_eam.html), [MEAM](https://docs.lammps.org/pair_meam.html), [Tersoff](https://docs.lammps.org/pair_tersoff.html) and [ReaxFF](https://docs.lammps.org/pair_reaxff.html). +- Directly parametrized potentials: Potentials whose parameters are directly given via ``pair_coeff`` in the input file, e.g [Born](https://docs.lammps.org/pair_born_gauss.html), [Lennard-Jones](https://docs.lammps.org/pair_line_lj.html) and [Yukawa](https://docs.lammps.org/pair_yukawa.html). These parameters should be written into a file that is then stored into a ``LammpsPotentialData`` node. -```python -calc_node.outputs.arrays.attributes -``` -```python -{'array|positions': [56, 4, 3], - 'array|stress': [3, 3], - 'array|forces': [56, 4, 3]} -``` -### MD Calculation - -```python -from aiida.engine import submit -parameters = DataFactory('dict')(dict={ - 'lammps_version': lammps_version(), - 'output_variables': ["temp", "etotal", "pe", "ke"], - 'thermo_keywords': [], - 'units': 'metal', - 'timestep': 0.001, - 'integration': { - 'style': 'nvt', - 'constraints': { - 'temp': [300, 300, 0.5] - } - }, - "neighbor": [0.3, "bin"], - "neigh_modify": {"every": 1, "delay": 0, "check": False}, - 'equilibrium_steps': 100, - 'total_steps': 1000, - 'dump_rate': 10, - 'restart': 100 -}) -builder = code_lammps_md.get_builder() -builder.metadata.options = meta_options -builder.structure = structure -builder.potential = potential -builder.parameters = parameters -result, calc_node = run_get_node(builder) -``` +## Examples -```console -$ verdi process list -D desc -a -l 1 - PK Created Process label Process State Process status ----- --------- --------------- --------------- ---------------- -2493 12s ago LammpsMdCalculation ⏹ Finished [0] - -Total results: 1 - -Info: last time an entry changed state: 4s ago (at 02:15:02 on 2019-06-21) - -$ verdi process show 2493 -Property Value -------------- ------------------------------------ -type CalcJobNode -pk 2493 -uuid 351b4721-10ff-406c-8f1c-951317091524 -label -description -ctime 2019-06-21 02:14:54.986384+00:00 -mtime 2019-06-21 02:14:55.282272+00:00 -process state Finished -exit status 0 -computer [2] localhost - -Inputs PK Type ----------- ---- ------------------ -code 1540 Code -parameters 2492 Dict -potential 2478 LammpsEmpiricalPotential -structure 2477 StructureData - -Outputs PK Type ---------------- ---- -------------- -remote_folder 2494 RemoteData -results 2496 Dict -retrieved 2495 FolderData -system_data 2498 ArrayData -trajectory_data 2497 TrajectoryData -``` +More example calculations are found in the folder **/examples** as well as in the documentation. The examples touch some common cases for the usage of LAMMPS for a single stage calculation. -```python -calc_node.outputs.results.attributes -``` +## Development -```python -{'parser_version': '0.4.0b3', - 'parser_class': 'LammpsMdParser', - 'errors': [], - 'warnings': '', - 'time_units': 'picoseconds', - 'distance_units': 'Angstroms', - 'energy': -17.8464193488116, - 'units_style': 'metal'} -``` +### Running tests -```python -calc_node.outputs.system_data.attributes -``` +The test suite can be run in an isolated, virtual environment using `tox` (see `tox.ini` in the repo): -```python -{'units_style': 'metal', - 'array|step': [100], - 'array|ke': [100], - 'array|pe': [100], - 'array|etotal': [100], - 'array|temp': [100]} +```shell +pip install tox +tox -e 3.9-aiida_lammps -- tests/ ``` -```python -calc_node.outputs.trajectory_data.attributes -``` +or directly: -```python -{'array|times': [101], - 'array|cells': [101, 3, 3], - 'array|steps': [101], - 'array|positions': [101, 4, 3], - 'symbols': ['Ga', 'Ga', 'N', 'N']} +```shell +pip install .[testing] +pytest -v ``` -## Development - -### Coding Style Requirements - -The code is formatted and linted using [pre-commit](https://pre-commit.com/), which runs in an isolated, virtual environment: +The tests require that both PostgreSQL and RabbitMQ are running. +If you wish to run an isolated RabbitMQ instance, see the `docker-compose.yml` file in the repo. -```shell ->> pip install pre-commit ->> pre-commit run --all -``` +Some tests require that a `lammps` executable be present. -or to automate runs, triggered before each commit: +The easiest way to achieve this is to use Conda: ```shell ->> pre-commit install +conda install lammps==2019.06.05 +# this will install lmp_serial and lmp_mpi ``` -### Testing - -the test suite can be run in an isolated, virtual environment using `tox` (see `tox.ini` in the repo): +You can specify a different executable name for LAMMPS with: ```shell ->> pip install tox ->> tox -e py37 +tox -e 3.9-aiida_lammps -- --lammps-exec lmp_exec ``` -or directly: +To output the results of calcjob executions to a specific directory: ```shell ->> pip install .[testing] ->> pytest -v +pytest --lammps-workdir "test_workdir" ``` -The tests require that both PostgreSQL and RabbitMQ are running. -If you wish to run an isolated RabbitMQ instance, see the `docker-compose.yml` file in the repo. - -Some tests require that a `lammps` executable be present. +### Pre-commit -The easiest way to achieve this is to use Conda: +The code is formatted and linted using [pre-commit](https://pre-commit.com/), so that the code conform to the standard. One must simply install the repository with the `pre-commit` extra dependencies: ```shell ->> conda install lammps==2019.06.05 -# this will install lmp_serial and lmp_mpi +cd aiida-lammps +pip install -e .[pre-commit] +pre-commit run --all ``` - -You can specify a different executable name for LAMMPS with: +or to automate runs, triggered before each commit: ```shell ->> tox -e py37 -- --lammps-exec lmp_exec +pre-commit install ``` -To output the results of calcjob executions to a specific directory: +The pre-commit can also be run in an isolated environment via `tox` with: ```shell ->> pytest --lammps-workdir "test_workdir" +tox -e pre-commit ``` + +## License +The `aiida-lammps` plugin package is released under the MIT license. See the `LICENSE.txt` file for more details. diff --git a/aiida_lammps/data/potential.py b/aiida_lammps/data/potential.py index 7fa09c14..40b4beec 100644 --- a/aiida_lammps/data/potential.py +++ b/aiida_lammps/data/potential.py @@ -2,7 +2,7 @@ Base class for the LAMMPS potentials. This class allows the storage/recovering of LAMMPS potentials, it allows -one to store any LAMMPS potential as a ``SinglefileData`` object, which can +one to store any LAMMPS potential as a :py:class:`~aiida.orm.nodes.data.singlefile.SinglefileData` object, which can then be either written to the LAMMPS input script and/or to a file, where it can be easily read by LAMMPS. This distinction depends on the assigned ``pair_style`` which require different ``pair_coeff`` entries in the input @@ -140,7 +140,7 @@ class LammpsPotentialData(orm.SinglefileData): Base class for the LAMMPS potentials. This class allows the storage/recovering of LAMMPS potentials, it allows - one to store any LAMMPS potential as a ``SinglefileData`` object, which can + one to store any LAMMPS potential as a :py:class:`~aiida.orm.nodes.data.singlefile.SinglefileData` object, which can then be either written to the LAMMPS input script and/or to a file, where it can be easily read by LAMMPS. This distinction depends on the assigned ``pair_style`` which require different ``pair_coeff`` entries in the input diff --git a/aiida_lammps/parsers/inputfile.py b/aiida_lammps/parsers/inputfile.py index 338f197a..78d09279 100644 --- a/aiida_lammps/parsers/inputfile.py +++ b/aiida_lammps/parsers/inputfile.py @@ -27,7 +27,7 @@ def generate_input_file( parameters: dict, potential: LammpsPotentialData, structure: orm.StructureData, - trajectory_filename: str = "aiida_lampps.trajectory.dump", + trajectory_filename: str = "aiida_lammps.trajectory.dump", restart_filename: str = "lammps.restart", potential_filename: str = "potential.dat", structure_filename: str = "structure.dat", @@ -45,14 +45,14 @@ def generate_input_file( command is used to overwrite the structure and set the velocity and other parameters from a previous calculation. - :param parameters: calculation paramters used to control the LAMMPS calculation + :param parameters: calculation parameters used to control the LAMMPS calculation :type parameters: dict :param potential: potential used during the LAMMPS calculation :type potential: LammpsPotentialData :param structure: structure used during the LAMMPS calculation :type structure: orm.StructureData :param trajectory_filename: filename used to write the trajectory information, - defaults to 'aiida_lampps.trajectory.dump' + defaults to 'aiida_lammps.trajectory.dump' :type trajectory_filename: str, optional :param restart_filename: filename used to write the restart information, defaults to 'restart.aiida' @@ -973,7 +973,7 @@ def generate_id_tag(name: str = None, group: str = None) -> str: """Generate an id tag for fixes and/or computes. To standardize the naming of computes and/or fixes and to ensure that one - can programatically recreate them their name will consist of the name of the fix/compute + can programmatically recreate them their name will consist of the name of the fix/compute with the group at which is applied appended plus the aiida keyword. Of this way one can always regenerate these tags by knowing which fix/computes were asked of the calculation. diff --git a/aiida_lammps/workflows/relax.py b/aiida_lammps/workflows/relax.py index 8f71cca0..3336f958 100644 --- a/aiida_lammps/workflows/relax.py +++ b/aiida_lammps/workflows/relax.py @@ -1,4 +1,4 @@ -"""Workflow for the relaxation of a structure using the minimization proceedure in LAMMPS.""" +"""Workflow for the relaxation of a structure using the minimization procedure in LAMMPS.""" from itertools import groupby import os from typing import Union @@ -36,7 +36,7 @@ def define(cls, spec): default=lambda: orm.Str("cg"), validator=cls._validate_relaxation_algorithms, help=""" - The algorithm to be used suring relaxation. + The algorithm to be used during relaxation. """, ) spec.input( diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 00000000..365008f5 --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,43 @@ +# Makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +PAPER = +BUILDDIR = build + +# User-friendly check for sphinx-build +ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) +$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) +endif + +# Internal variables. +PAPEROPT_a4 = -D latex_paper_size=a4 +PAPEROPT_letter = -D latex_paper_size=letter +ALLSPHINXOPTS = -n -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source +# the i18n builder cannot share the environment and doctrees with the others +I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source + +.PHONY: all help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest coverage gettext default + +default: + $(SPHINXBUILD) -b html -nW $(ALLSPHINXOPTS) $(BUILDDIR)/html + +# Same as 'default' but does not exit at the first warning +debug: + $(SPHINXBUILD) -b html -nW --keep-going $(ALLSPHINXOPTS) $(BUILDDIR)/html + +all: clean html view + +clean: + rm -rf $(BUILDDIR) + rm -rf $(shell find . -type d -wholename "*/reference/api/auto") + +html: + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." + +view: + open $(BUILDDIR)/html/index.html diff --git a/docs/source/_static/aiida-custom.css b/docs/source/_static/aiida-custom.css new file mode 100644 index 00000000..42d2fa2d --- /dev/null +++ b/docs/source/_static/aiida-custom.css @@ -0,0 +1,130 @@ +/* Fix CSS of top bar link icons */ +a.nav-link.nav-external i { + padding-left: 0.3em !important; + font-size: inherit !important; + vertical-align: inherit !important; +} +/* Current fix for https://github.com/pandas-dev/pydata-sphinx-theme/issues/193 */ +dl.field-list { + display: grid; + grid-template-columns: fit-content(30%) minmax(0, 1fr); +} +/* For icon unicodes see https://fontawesome.com/v4.7.0/icons/ */ +.title-icon-rocket .admonition-title:before { + margin-right:.5rem; + content: "\f135" +} +.title-icon-info-circle .admonition-title:before { + margin-right:.5rem; + content: "\f05a" +} +.title-icon-question-circle .admonition-title:before { + margin-right:.5rem; + content: "\f059" +} +.title-icon-download .admonition-title:before { + margin-right:.5rem; + content: "\f019" +} +.title-icon-external-link .admonition-title:before { + margin-right:.5rem; + content: "\f08e" +} +.title-icon-lightbulb .admonition-title:before { + margin-right:.5rem; + content: "\f0eb" +} +.title-icon-wrench .admonition-title:before { + margin-right:.5rem; + content: "\f0ad" +} +.title-icon-cog .admonition-title:before { + margin-right:.5rem; + content: "\f013" +} +.title-icon-cogs .admonition-title:before { + margin-right:.5rem; + content: "\f085" +} +.title-icon-code-fork .admonition-title:before { + margin-right:.5rem; + content: "\f126" +} +/* Semantic icon names */ +.title-icon-launch-software .admonition-title:before { + margin-right:.5rem; + content: "\f135" /* rocket */ +} +.title-icon-install-software .admonition-title:before { + margin-right:.5rem; + content: "\f019" /* download */ +} +.title-icon-information .admonition-title:before { + margin-right:.5rem; + content: "\f05a" /* info-circle */ +} +.title-icon-tip .admonition-title:before { + margin-right:.5rem; + content: "\f0eb" /* lightbulb */ +} +.title-icon-important .admonition-title:before { + margin-right:.5rem; + content: "\f06a" /* exclamation-circle */ +} +.title-icon-warning .admonition-title:before { + margin-right:.5rem; + content: "\f071" /* exclamation-triangle */ +} +.title-icon-troubleshoot .admonition-title:before { + margin-right:.5rem; + content: "\f0ad" /* wrench */ +} +.title-icon-read-more .admonition-title:before { + margin-right:.5rem; + content: "\f518" /* external-link */ +} + +.dropdown-group .dropdown .summary-title { + border-bottom: 0 !important; + font-weight:700 !important; +} +.dropdown-group .dropdown:not(:last-child) { + margin-bottom: 0 !important; + border-radius: 0 !important; +} +.dropdown-group .dropdown:first-child, +.dropdown-group .dropdown:first-child .summary-title { + border-radius: 1rem 1rem 0rem 0rem !important; +} +.dropdown-group .dropdown:last-child, +.dropdown-group .dropdown:last-child .summary-title { + border-radius: 0rem 0rem 1rem 1rem !important; +} + +.dropdown-group .dropdown:last-child { + margin-bottom: 24px !important; +} + +div.admonition :last-child { + margin-bottom: 0 +} + +div.highlight-bash div.highlight { + background-color: aliceblue; +} + +div.highlight-console div.highlight { + background-color: aliceblue; +} + +.aiida-green { + color: #32B805; +} + +.aiida-blue { + color: #0496DE; +} + +.aiida-orange { + color: #FF7D16; +} diff --git a/docs/source/_static/aiida-lammps-custom.css b/docs/source/_static/aiida-lammps-custom.css new file mode 100644 index 00000000..8ebb4c26 --- /dev/null +++ b/docs/source/_static/aiida-lammps-custom.css @@ -0,0 +1,58 @@ +.logo-table td { + padding: 20px 10px; +} + +.center { + text-align: center; + max-width: 90%; +} + +.bigfont { + font-size: 140%; +} + +.navbar-brand { + padding: 0; + padding-top: 0.5rem; +} + +img.logo__image { + max-height: 180px; + padding-left: 1.5rem; + padding-bottom: 1rem; +} + +.navbar-icon-links i.fa-brands { + font-size: 40px!important; +} + +img.aiida-sidebar-logo { + height: 40px!important; +} + +img.aiida-logo { + width: 20px; + padding-bottom: 3px; +} + +.fa { + color: var(--pst-color-primary); +} + +.bd-search { + padding: 0 1rem; +} + +.tutor-footer { + padding-top: 0rem; + border-top: none!important; +} + +.footer-table { + margin-bottom: 0rem; + border-color: transparent; +} + +.footer-table td:last-child { + text-align: right; +} diff --git a/docs/source/static/logo.png b/docs/source/_static/logo.png similarity index 100% rename from docs/source/static/logo.png rename to docs/source/_static/logo.png diff --git a/docs/source/_static/logo_aiida.svg b/docs/source/_static/logo_aiida.svg new file mode 100644 index 00000000..f28d9625 --- /dev/null +++ b/docs/source/_static/logo_aiida.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/docs/source/_templates/icon-links.html b/docs/source/_templates/icon-links.html new file mode 100644 index 00000000..356c4f73 --- /dev/null +++ b/docs/source/_templates/icon-links.html @@ -0,0 +1,40 @@ +{%- macro icon_link_nav_item(url, icon, name, type, attributes='') -%} + {%- if url | length > 2 %} + + {%- endif -%} +{%- endmacro -%} +{%- if theme_icon_links -%} + +{%- endif -%} diff --git a/docs/source/_templates/sbt-sidebar-nav.html b/docs/source/_templates/sbt-sidebar-nav.html new file mode 100644 index 00000000..e9bbe7b6 --- /dev/null +++ b/docs/source/_templates/sbt-sidebar-nav.html @@ -0,0 +1,24 @@ + diff --git a/docs/source/conf.py b/docs/source/conf.py index 9093276d..7e9c5a15 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -4,9 +4,8 @@ `tox -e docs-clean` and `tox -e docs-update`, or directly: `sphinx-build -n -W --keep-going docs/source docs/_build` """ -import os -import subprocess -import sys +import pathlib +import time from aiida.manage.configuration import load_documentation_profile @@ -19,98 +18,108 @@ # default profile of the AiiDA installation does not use a Django backend. load_documentation_profile() -PROJECT = "AiiDA LAMMPS" -COPYRIGHT = "2021, AiiDA Team" +project = "AiiDA LAMMPS" +copyright = f"2021-{time.localtime().tm_year}, AiiDA Team. All rights reserved" AUTHOR = "AiiDA Team" VERSION = __version__ extensions = [ - # read Markdown files - "myst_parser", - # specify sitemap in single file (not toctrees) - "sphinx_external_toc", + "sphinx.ext.mathjax", "sphinx.ext.intersphinx", - "sphinx.ext.autodoc", "sphinx.ext.viewcode", "sphinx_copybutton", + "sphinx_click.ext", + "sphinx_design", + "myst_parser", + "aiida.sphinxext", + "autoapi.extension", ] intersphinx_mapping = { - "python": ("https://docs.python.org/3", None), + "python": ("https://docs.python.org/3.9", None), "aiida": ("https://aiida-core.readthedocs.io/en/latest", None), "click": ("https://click.palletsprojects.com/", None), - "flask": ("http://flask.pocoo.org/docs/latest/", None), - "flask_restful": ("https://flask-restful.readthedocs.io/en/latest/", None), - "kiwipy": ("https://kiwipy.readthedocs.io/en/latest/", None), - "pandas": ("https://pandas.pydata.org/docs/", None), - "plumpy": ("https://plumpy.readthedocs.io/en/latest/", None), "pymatgen": ("https://pymatgen.org/", None), } -suppress_warnings = ["etoc.toctree"] -html_theme = "furo" # pylint: disable=invalid-name +# Settings for the `autoapi.extenstion` automatically generating API docs +filepath_docs = pathlib.Path(__file__).parent.parent +filepath_src = filepath_docs.parent / "aiida_lammps" +autoapi_type = "python" +autoapi_dirs = [filepath_src] +autoapi_ignore = [filepath_src / "*cli*"] +autoapi_root = str(filepath_docs / "source" / "reference" / "api" / "auto") +autoapi_keep_files = True +autoapi_add_toctree_entry = False + +# Settings for the `sphinx_copybutton` extension +copybutton_selector = "div:not(.no-copy)>div.highlight pre" +copybutton_prompt_text = ( + r">>> |\.\.\. |(?:\(.*\) )?\$ |In \[\d*\]: | {2,5}\.\.\.: | {5,8}: " +) +copybutton_prompt_is_regexp = True + +# Add any paths that contain templates here, relative to this directory. +templates_path = ["_templates"] + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = "en" + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = ["**.ipynb_checkpoints", "reference/api/auto/aiida_lammps/index.rst"] + +# -- MyST options + +myst_enable_extensions = [ + "deflist", + "colon_fence", + "substitution", + "attrs_inline", + "substitution", +] +myst_substitutions = { + "aiida_logo": '', +} + +html_theme = "sphinx_book_theme" # pylint: disable=invalid-name html_title = f"v{__version__}" # pylint: disable=invalid-name -html_logo = "static/logo.png" # pylint: disable=invalid-name html_theme_options = { "announcement": "This documentation is in development!", + "repository_url": "https://github.com/aiidaplugins/aiida-lammps", + "github_url": "https://github.com/aiidaplugins/aiida-lammps", + "use_edit_page_button": True, + "navigation_with_keys": False, + "logo": { + "text": "AiiDA LAMMPS", + "image_light": "_static/logo.png", + "image_dark": "_static/logo.png", + }, +} +html_static_path = ["_static"] +html_context = { + "github_user": "aiidaplugins", + "github_repo": "aiida-lammps", + "github_version": "main", + "doc_path": "docs/source", + "default_mode": "dark", } - -def run_apidoc(_): - """Runs sphinx-apidoc when building the documentation. - - Needs to be done in conf.py in order to include the APIdoc in the - build on readthedocs. - - See also https://github.com/rtfd/readthedocs.org/issues/1139 - """ - source_dir = os.path.abspath(os.path.dirname(__file__)) - apidoc_dir = os.path.join(source_dir, "reference", "apidoc") - package_dir = os.path.join(source_dir, os.pardir, os.pardir, "aiida_lammps") - - # In #1139, they suggest the route below, but this ended up - # calling sphinx-build, not sphinx-apidoc - # from sphinx.apidoc import main - # main([None, '-e', '-o', apidoc_dir, package_dir, '--force']) - - cmd_path = "sphinx-apidoc" - if hasattr(sys, "real_prefix"): # Check to see if we are in a virtualenv - # If we are, assemble the path manually - cmd_path = os.path.abspath( - os.path.join( - sys.prefix, - "bin", - "sphinx-apidoc", - ) - ) - - options = [ - "-o", - apidoc_dir, - package_dir, - "--private", - "--force", - "--no-headings", - "--module-first", - "--no-toc", - "--maxdepth", - "4", +html_sidebars = { + "**": [ + "navbar-logo.html", + "navbar-icon-links.html", + "sbt-sidebar-nav.html", + "search-field.html", ] +} - # See https://stackoverflow.com/a/30144019 - env = os.environ.copy() - env[ - "SPHINX_APIDOC_OPTIONS" - ] = "members,special-members,private-members,undoc-members,show-inheritance" - subprocess.check_call([cmd_path] + options, env=env) - - -def setup(app): - """Run the apidoc.""" - if os.environ.get("RUN_APIDOC", None) != "False": - app.connect("builder-inited", run_apidoc) - +html_css_files = ["aiida-custom.css", "aiida-lammps-custom.css"] autodoc_mock_imports = ["pytest"] # We should ignore any python built-in exception, for instance diff --git a/docs/source/developers/intro.md b/docs/source/developers/index.md similarity index 56% rename from docs/source/developers/intro.md rename to docs/source/developers/index.md index 88b35822..cf625086 100644 --- a/docs/source/developers/intro.md +++ b/docs/source/developers/index.md @@ -6,31 +6,40 @@ This is a guide for internal development of `aiida-lammps` The code is formatted and linted using [pre-commit](https://pre-commit.com/), which runs in an isolated, virtual environment: -```shell -$ pip install pre-commit -$ pre-commit run --all +```console +pip install pre-commit +pre-commit run --all ``` or to automate runs, triggered before each commit: -```shell -$ pre-commit install +```console +pre-commit install ``` +To avoid problems arising from different configurations in virtual environments, one can also use [tox](https://tox.wiki/en/latest/index.html) to run the pre-commit command inside a clean virtual environment. This can be done in the following manner + +```console +pip install tox +pip install -e .[pre-commit] +tox -e pre-commit +``` + + ## Testing -The test suite can be run in an isolated, virtual environment using `tox` (see `tox.ini` in the repo): +The test suite can be run in an isolated, virtual environment using `tox` (see `[tool.tox]` in `pyproject.toml`): -```shell -$ pip install tox -$ tox -e py37 +```console +pip install tox +tox -e 3.8-aiida_lammps ``` or directly: -```shell -$ pip install .[testing] -$ pytest -v +```console +pip install .[tests] +pytest -v ``` The tests require that both PostgreSQL and RabbitMQ are running. @@ -40,33 +49,33 @@ Some tests require that a `lammps` executable be present. The easiest way to achieve this is to use Conda: -```shell -$ conda install lammps==2019.06.05 +```console +conda install lammps==2019.06.05 # this will install lmp_serial and lmp_mpi ``` You can specify a different executable name for LAMMPS with: -```shell -$ tox -e py37 -- --lammps-exec lmp_exec +```console +tox -e 3.8-aiida_lammps -- --lammps-exec lmp_exec ``` To output the results of calcjob executions to a specific directory: -```shell -$ pytest --lammps-workdir "test_workdir" +```console +pytest --lammps-workdir "test_workdir" ``` ## Documentation To run a full docs build: -```shell -$ tox -e docs-clean +```console +tox -e docs-clean ``` or to re-build from the current documentation: -```shell +```console $ tox -e docs-update ``` diff --git a/docs/source/getting_started/index.md b/docs/source/getting_started/index.md new file mode 100644 index 00000000..7157ac6b --- /dev/null +++ b/docs/source/getting_started/index.md @@ -0,0 +1,163 @@ +--- +myst: + substitutions: + pip: '[`pip`](https://pip.pypa.io/en/stable/index.html)' + PyPI: '[PyPI](https://pypi.org/)' +--- + +# Get started + +(getting_started-requirements)= + +## Requirements + +To use `aiida-lammps` one should have already: + +- installed [aiida-core](https://github.com/aiidateam/aiida-core) +- configured an AiiDA profile. + +Information about how to perform these steps can be found in the `aiida-core` [documentation](https://aiida.readthedocs.io/projects/aiida-core/en/latest/intro/get_started.html) + +(getting_started-installation)= + +## Installation + +The package can be installed either from the Python Package Index {{ PyPI }} or from the source. + +::::{tab-set} + +:::{tab-item} PyPI +Installing via {{ PyPI }} can be done making use of the Python package manager {{ pip }}: + +```console +pip install aiida-lammps +``` + +This will install the latest release version available in {{ PyPI }}. Other releases can be installed vy explicitly passing the release version number in the installation command. +::: + +:::{tab-item} Source +To install from source one needs to clone the repository and then install the package making use of {{ pip }}: + +```console +git clone https://github.com/aiidaplugins/aiida-lammps.git +pip install -e aiida-lammps +``` + +Notice that the flag ``-e`` means that the package is installed in editable mode, meaning that any changes to the source code will be automatically picked up. +::: + +:::: + +:::{note} +Installing from source in the editable mode is recommended when developing as one would not need to re-install the package every time that a change has been made. +::: + + +(getting_started-setup)= + +## Setup + +Setting up `aiida-lammps` to run a [LAMMPS](https://www.lammps.org/#gsc.tab=0) job is done in a similar way as any other [AiiDA plugin](https://aiida.readthedocs.io/projects/aiida-core/en/latest/topics/plugins.html). That is a [Computer](https://aiida.readthedocs.io/projects/aiida-core/en/latest/howto/run_codes.html#how-to-set-up-a-computer) and a [Code](https://aiida.readthedocs.io/projects/aiida-core/en/latest/howto/run_codes.html#how-to-create-a-code) need to be setup for the current profile. + +(getting_started-setup-computer)= + +### Computer + +A [Computer](https://aiida.readthedocs.io/projects/aiida-core/en/latest/reference/apidoc/aiida.orm.html#aiida.orm.computers.Computer) is an aiida data type that contains the information about a compute resource, this could be a local machine, a remote personal computer, an HPC center, etc. Basically it is the machine where [LAMMPS](https://www.lammps.org/#gsc.tab=0) is installed and it will be run. + +For the following it will be considered that [LAMMPS](https://www.lammps.org/#gsc.tab=0) is installed in the same machine where the [AiiDA](https://aiida.net/) instance is running, i.e. `localhost`. + +The computer setup can be done either via the [AiiDA](https://aiida.net/) command line interface (CLI), [verdi](https://aiida.readthedocs.io/projects/aiida-core/en/latest/reference/command_line.html), or the Python application programming interface (API). + +::::{tab-set} + +:::{tab-item} bash +To define the computer via the CLI one needs to run the following command: + +```console +verdi computer setup -n --label localhost --hostname localhost --transport core.local --scheduler core.direct --work-dir /home/my_username/aiida_workspace +``` + +This command will create a [Computer](https://aiida.readthedocs.io/projects/aiida-core/en/latest/reference/apidoc/aiida.orm.html#aiida.orm.computers.Computer) named `localhost`, with the `localhost` hostname, no scheduler is considered and no special transport plugin is needed. All the calculations performed using this computer will be stored in the directory `/home/my_username/aiida_workspace`. + +After this its is still necessary to configure the `core.local` transport: + +```console +verdi computer configure core.local localhost -n --safe-interval 0 --user my_email@provider.com +``` +This configures that the computer will wait 0 seconds between connections attempts (one can increase this to avoid putting pressure in a network) for the user with email `my_email@provider.com` +::: + +:::{tab-item} API + +Using the Python API one can create a [Computer](https://aiida.readthedocs.io/projects/aiida-core/en/latest/reference/apidoc/aiida.orm.html#aiida.orm.computers.Computer) by running the following code either in the `verdi shell` or using `verdi run` in a script that contains the code + +```python +from aiida.orm import Computer +from pathlib import Path + +# Create the node with the computer +computer = Computer( + label='localhost', + hostname='localhost', + transport_type='core.local', + scheduler_type='core.direct', + workdir=Path('/home/my_username/aiida_workspace').resolve() +) +# Store the node in the database +computer.store() +# Configure the core.local transport +computer.configure() +``` +::: +:::: + +For more detailed information, please refer to the documentation [on setting up compute resources](https://aiida.readthedocs.io/projects/aiida-core/en/latest/howto/run_codes.html#how-to-set-up-a-computer). + +(getting_started-setup-code)= + +### Code + +Since LAMMPS is a piece of software that is installed in a machine we have to create a [InstalledCode](https://aiida.readthedocs.io/projects/aiida-core/en/latest/reference/apidoc/aiida.orm.nodes.data.code.html#aiida.orm.nodes.data.code.installed.InstalledCode) node in the database which contains the information about this program. As with the [Computer](https://aiida.readthedocs.io/projects/aiida-core/en/latest/reference/apidoc/aiida.orm.html#aiida.orm.computers.Computer) it is possible to define this both via the [AiiDA](https://aiida.net/) command line interface (CLI), [verdi](https://aiida.readthedocs.io/projects/aiida-core/en/latest/reference/command_line.html), or the Python application programming interface (API). + +In the following it will be assumed that [LAMMPS](https://www.lammps.org/#gsc.tab=0) is installed in the same machine that is running [AiiDA](https://aiida.net/), `localhost`, that the executable is called `lmp` and that there is already a [Computer](https://aiida.readthedocs.io/projects/aiida-core/en/latest/reference/apidoc/aiida.orm.html#aiida.orm.computers.Computer) named `localhost` setup in the database. + +::::{tab-set} + +:::{tab-item} CLI + +To define the [InstalledCode](https://aiida.readthedocs.io/projects/aiida-core/en/latest/reference/apidoc/aiida.orm.nodes.data.code.html#aiida.orm.nodes.data.code.installed.InstalledCode) which refers to the [LAMMPS](https://www.lammps.org/#gsc.tab=0) installation via the CLI one runs the command: + +```console +verdi code create core.code.installed --label lammps --computer localhost --default-calc-job-plugin lammps.base --filepath-executable /path/to/lammps/lmp +``` + +This will create an [InstalledCode](https://aiida.readthedocs.io/projects/aiida-core/en/latest/reference/apidoc/aiida.orm.nodes.data.code.html#aiida.orm.nodes.data.code.installed.InstalledCode) with the name `lammps` associated to the [Computer](https://aiida.readthedocs.io/projects/aiida-core/en/latest/reference/apidoc/aiida.orm.html#aiida.orm.computers.Computer) named `localhost` whose executable absolute path is `/path/to/lammps/lmp` +::: + +:::{tab-item} API +To define the [InstalledCode](https://aiida.readthedocs.io/projects/aiida-core/en/latest/reference/apidoc/aiida.orm.nodes.data.code.html#aiida.orm.nodes.data.code.installed.InstalledCode) which refers to the [LAMMPS](https://www.lammps.org/#gsc.tab=0) installation via the Python API one can use the following code in either the `verdi shell` or by running a script which contains it via `verdi run`: + +```python +from aiida.orm import InstalledCode + +# Load the computer resource where LAMMPS is installed +computer = load_computer('localhost') + +# Define the code node +code = InstalledCode( + label='lammps', + computer=computer, + filepath_executable='/path/to/lammps/lmp', + default_calc_job_plugin='lammps.base' +) + +# Store the code node in the database +code.store() +``` +::: + +:::: + +For more detailed information, please refer to the documentation [on setting up codes](https://aiida.readthedocs.io/projects/aiida-core/en/latest/howto/run_codes.html#how-to-setup-a-code). diff --git a/docs/source/index.md b/docs/source/index.md index 39c68fb2..e4285bd4 100644 --- a/docs/source/index.md +++ b/docs/source/index.md @@ -1,37 +1,113 @@ -# AiiDA LAMMPS Plugin +--- +myst: + substitutions: + aiida_lammps: '`aiida-lammps`' + LAMMPS: '[LAMMPS](https://lammps.org)' + AiiDA: '[AiiDA](https://www.aiida.net/)' +--- -``aiida-lammps`` is a Python package that allows the workflow management and data provenance tracking framework [AiiDA](http://aiida-core.readthedocs.io/) run [LAMMPS](https://www.lammps.org/) calculations. -``LAMMPS`` is a classical molecular dynamics (MD) code with a focus on materials modeling, it is used broadly inside the MD community due to its flexibility, and in-built capability to generate complex workflows in its input script. +```{toctree} +:hidden: true -## Installation +getting_started/index +tutorials/index +``` -One can install ``aiida-lammps`` in a Python environment using ``pip``: +```{toctree} +:hidden: true +:caption: Topic guides +topics/data/index +topics/calculations/index +topics/workflows/index +``` -```{code-block} console -pip install aiida-lammps +```{toctree} +:hidden: true +:caption: Development information +developers/index ``` -``aiida-lammps`` will install ``aiida-core`` if it is not already installed in your system, as it is a pre-requisite of the package. Information on the requirements of ``aiida-core``, and steps needed to configure it to be able to perform calculations can be found in the [AiiDA documentation](http://aiida-core.readthedocs.io/). +```{toctree} +:hidden: true +:caption: Reference +reference/api/index +``` -## Compatibility -``aiida-lammps`` has been developed to work with [aiida-core v2.x](https://www.aiida.net/news/posts/2022-04-27-aiida-2-release.html) and tested with the ``LAMMPS`` releases [19Jul2019](https://github.com/lammps/lammps/releases/tag/patch_19Jul2019) and [29Oct2020](https://github.com/lammps/lammps/releases/tag/stable_29Oct2020). It is important to notice that older versions of ``LAMMPS`` can have different formats which means that the plugin is not guaranteed to be able to properly produce input files and/or parse the output generated by the program. If there are any compatibility problems with the plugin, please open an [issue](https://github.com/aiidaplugins/aiida-lammps/issues) so that it can be addressed. -```{warning} -In this version a major refactoring of the entrie plugin has been done so that render it backwards incompatible with older versions. +# AiiDA LAMMPS Plugin + +{{ aiida_lammps }} is a Python package that allows the workflow management and data provenance tracking framework {{ AiiDA }} to run {{ LAMMPS }} calculations. + +{{ LAMMPS }} is a classical molecular dynamics (MD) code with a focus on materials modeling, it is used broadly inside the MD community due to its flexibility, and in-built capability to generate complex workflows in its input script. + +[![PyPI version](https://badge.fury.io/py/aiida-lammps.svg)](https://badge.fury.io/py/aiida-lammps) +[![PyPI pyversions](https://img.shields.io/pypi/pyversions/aiida-lammps.svg)](https://pypi.python.org/pypi/aiida-lammps) +[![Build Status](https://github.com/aiidaplugins/aiida-lammps/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/aiidateam/aiida-lammps/actions) +[![Docs status](https://readthedocs.org/projects/aiida-lammps/badge)](http://aiida-lammps.readthedocs.io/) + +______________________________________________________________________ + + +::::{grid} 1 2 2 2 +:gutter: 3 + +:::{grid-item-card} {fa}`rocket;mr-1` Get started +:text-align: center +:shadow: md + +Instructions to install, configure and setup the plugin package. -New potential datastructures and calculations have been introduced with the aim of improving the flexibility of the plugin. ++++ -The same basic types of calculations than were previously supported (optimization and molecular dynamics) are still possible with examples for [optimization](users/example_minimize.md) and [molecular dynamics](users/example_md.md) being given in the documentation. +```{button-ref} getting_started/index +:ref-type: doc +:click-parent: +:expand: +:color: primary +:outline: + +To the installation guides +``` +::: + +:::{grid-item-card} {fa}`info-circle;mr-1` Tutorials +:text-align: center +:shadow: md + +Easy examples to take the first steps with the plugin package. + ++++ + +```{button-ref} tutorials/index +:ref-type: doc +:click-parent: +:expand: +:color: primary +:outline: + +To the tutorials ``` -## Getting Started +::: +:::: + + +## Compatibility + +{{ aiida_lammps }} has been developed to work with [aiida-core v2.x](https://www.aiida.net/news/posts/2022-04-27-aiida-2-release.html) and tested with the {{ LAMMPS }} releases [19Jul2019](https://github.com/lammps/lammps/releases/tag/patch_19Jul2019) and [29Oct2020](https://github.com/lammps/lammps/releases/tag/stable_29Oct2020). It is important to notice that older versions of {{ LAMMPS }} can have different formats which means that the plugin is not guaranteed to be able to properly produce input files and/or parse the output generated by the program. If there are any compatibility problems with the plugin, please open an [issue](https://github.com/aiidaplugins/aiida-lammps/issues) so that it can be addressed. + +:::{warning} +In this version a major refactoring of the entire plugin has been done so that render it backwards incompatible with older versions. + +New potential data structures and calculations have been introduced with the aim of improving the flexibility of the plugin. -The ``aiida-lammps`` package includes a series of examples in the ``examples/`` folder, with those a user can learn how to perform simple ``LAMMPS`` calculations using ``aiida-lammps``. +The same basic types of calculations than were previously supported (optimization and molecular dynamics) are still possible with examples for [optimization](tutorials/first_relaxation.md) and [molecular dynamics](tutorials/first_md.md) being given in the documentation. +::: ## Capabilities -``aiida-lammps`` has been designed in such a way that the base ``Calculation`` method can run a single-phase ``LAMMPS`` calculation with as much flexibility as possible, with multi-stage runs being handled by specially designed ``WorkChains`` instead. +{{ aiida_lammps }} has been designed in such a way that the base ``Calculation`` method can run a single-phase LAMMPS calculation with as much flexibility as possible, with multi-stage runs being handled by specially designed ``WorkChains`` instead. -### What does this implies? +### What does this imply? -Instead of relying on the internal ``LAMMPS`` scripting language to treat loops, multiple phases, definition of custom variables, etc., those tasks are off loaded to the AiiDA worchains, allowing one to make use of the provenance tracking, automated data storage and caching capabilities of AiiDA. +Instead of relying on the internal {{ LAMMPS }} scripting language to treat loops, multiple phases, definition of custom variables, etc., those tasks are off loaded to the AiiDA workchains, allowing one to make use of the provenance tracking, automated data storage and caching capabilities of AiiDA. diff --git a/docs/source/reference/api/index.md b/docs/source/reference/api/index.md new file mode 100644 index 00000000..5d76d3ea --- /dev/null +++ b/docs/source/reference/api/index.md @@ -0,0 +1,11 @@ +# Python API + +```{toctree} +:maxdepth: 3 +auto/aiida_lammps/utils/index +auto/aiida_lammps/calculations/index +auto/aiida_lammps/data/index +auto/aiida_lammps/parsers/index +auto/aiida_lammps/validation/index +auto/aiida_lammps/workflows/index +``` diff --git a/docs/source/static/logo.pptx b/docs/source/static/logo.pptx deleted file mode 100644 index f029058f..00000000 Binary files a/docs/source/static/logo.pptx and /dev/null differ diff --git a/docs/source/topics/calculations/base.md b/docs/source/topics/calculations/base.md new file mode 100644 index 00000000..eb11e138 --- /dev/null +++ b/docs/source/topics/calculations/base.md @@ -0,0 +1,37 @@ +# ``LammpsBaseCalculation`` + +The {class}`~aiida_lammps.calculations.base.LammpsBaseCalculation` performs a single stage LAMMPS calculation, the input is generated by a set of parameters passed as a dictionary. The inputs accepted are the following: + +## Inputs: + +- **structure**, ({class}`~aiida.orm.nodes.data.structure.StructureData`) - Structure used in the ``LAMMPS`` calculation. +- **potential**, ({class}`~aiida_lammps.data.potential.LammpsPotentialData`) - Potential used in the ``LAMMPS`` calculation. See [](#topics-data-potential). +- **parameters**, ({class}`~aiida.orm.nodes.data.dict.Dict`) - Parameters that control the input script generated for the ``LAMMPS`` calculation. See [](#topics-data-parameters). +- **settings**, ({class}`~aiida.orm.nodes.data.dict.Dict`), *optional* - Additional settings that control the ``LAMMPS`` calculation. +- **input_restartfile** ({class}`~aiida.orm.nodes.data.singlefile.SinglefileData`), *optional* - Input restart file to continue from a previous ``LAMMPS`` calculation. +- **parent_folder**, ({class}`~aiida.orm.nodes.data.remote.base.RemoteData`), *optional* - An optional working directory of a previously completed calculation to restart from. +- **metadata.options.input_filename**, (`str`), *optional* - Name of the input file for the calculation. Defaults to `input.in`. +- **metadata.options.structure_filename**, (`str`), *optional* - Name of the file where the structure is stored. Defaults to `structure.dat` +- **metadata.options.output_filename**, (`str`). *optional* - Name of the main output file for LAMMPS. Defaults to `lammps.out`. +- **metadata.options.variables_filename**, (`str`), *optional* - Name of the file where the final values of the thermodynamic variables are stored. Defaults to `aiida_lammps.yaml`. +- **metadata.options.trajectory_filename**, (`str`), *optional* - Name of the file where the trajectories are stored. Defaults to `aiida_lammps.trajectory.dump`. +- **metadata.options.restart_filename**, (`str`), *optional* - Name of the restart file to be written. Defaults to `lammps.restart`. +- **metadata.options.parser_name**, (`str`), *optional* - Name of the parser to be used for this calculation. Defaults to `lammps.base`. + +:::{note} +LAMMPS can produce binary restart files which contain all the atomic positions, forces and other computed variables until when the are asked to be printed. One can control this by passing a dictionary called `restart` to the `settings` input. The available options for the `restart` are: +- `print_final`, (`bool`) - whether to print a restart file at the end of the calculation. Defaults to `False`. See [`write_restart`](https://docs.lammps.org/write_restart.html). +- `print intermediate`, (`bool`) - whether to print restart files periodically throughout the calculation. Defaults to `False`. See [`restart`](https://docs.lammps.org/restart.html). +- `num_steps`, (`int`) - how often is the intermediate restart file printed. Defaults to 10% of the total number of steps. +::: + +## Outputs: + +- **results**, ({class}`~aiida.orm.nodes.data.dict.Dict`) - The parsed data extracted from the lammps output file. +- **trajectories** ({class}`~aiida_lammps.data.trajectory.LammpsTrajectory`) - The data extracted from the lammps trajectory file, includes the atomic trajectories and the site and time dependent calculation parameters. +- **time_dependent_computes**, ({class}`~aiida.orm.nodes.data.array.array.ArrayData`) - The data with the time dependent computes parsed from the lammps.out. +- **restartfile**, ({class}`~aiida.orm.nodes.data.singlefile.SinglefileData`), *optional* - The restart file of a ``LAMMPS`` calculation. +- **structure**, ({class}`~aiida.orm.nodes.data.structure.StructureData`), *optional* - The output structure of the calculation. +- **remote_folder**, ({class}`~aiida.orm.nodes.data.remote.base.RemoteData`) - Folder in the remote machine where the calculation was performed. +- **remote_stash**, ({class}`~aiida.orm.nodes.data.remote.stash.base.RemoteStashData`), *optional* – Contents of the stash.source_list option are stored in this remote folder after job completion. +- **retrieved**, ({class}`~aiida.orm.nodes.data.folder.FolderData`) - Files that are retrieved by the daemon will be stored in this node. By default the stdout and stderr of the scheduler will be added, but one can add more by specifying them in `CalcInfo.retrieve_list`. diff --git a/docs/source/topics/calculations/index.md b/docs/source/topics/calculations/index.md new file mode 100644 index 00000000..176372cd --- /dev/null +++ b/docs/source/topics/calculations/index.md @@ -0,0 +1,24 @@ +--- +myst: + substitutions: + aiida_lammps: '`aiida-lammps`' + LAMMPS: '[LAMMPS](https://lammps.org)' + AiiDA: '[AiiDA](https://www.aiida.net/)' + LammpsBaseCalculation: '{class}`~aiida_lammps.calculations.base.LammpsBaseCalculation`' + LammpsRawCalculation: '{class}`~aiida_lammps.calculations.raw.LammpsRawCalculation`' +--- + + +(topics-calculations)= + +# Calculations + +```{toctree} +:maxdepth: 1 + +base +raw + +``` + +{{ aiida_lammps }} has two different types of calculations {{ LammpsBaseCalculation }} and {{ LammpsRawCalculation }}. The {{ LammpsBaseCalculation }} generates a {{ LAMMPS }} input script for a single stage calculation from a set of parameters passed as as dictionary to the calculation. However, to give more flexibility for cases not being tractable with a single stage calculation, or that require options not covered by the {{ LammpsBaseCalculation }} the {{ LammpsRawCalculation }} is designed to be able to accept any {{ LAMMPS }} script as an input. diff --git a/docs/source/topics/calculations/raw.md b/docs/source/topics/calculations/raw.md new file mode 100644 index 00000000..dc93c096 --- /dev/null +++ b/docs/source/topics/calculations/raw.md @@ -0,0 +1,19 @@ +# ``LammpsRawCalculation`` + +The {class}`~aiida_lammps.calculations.raw.LammpsRawCalculation` performs a LAMMPS calculation from a given LAMMPS input script and a set of files. + +## Inputs: + +- **script**, ({class}`~aiida.orm.nodes.data.singlefile.SinglefileData`) - Complete input script to use. If specified, `structure`, `potential` and `parameters` are ignored. +- **files**, (Namespace of {class}`~aiida.orm.nodes.data.singlefile.SinglefileData`), *optional* - Optional files that should be written to the working directory. This is an +- **filenames**, ({class}`~aiida.orm.nodes.data.dict.Dict`), *optional* - Optional namespace to specify with which filenames the files of ``files`` input should be written. +- **metadata.options.input_filename**, (`str`), *optional* - Name of the input file for the calculation. Defaults to `input.in`. +- **metadata.options.output_filename**, (`str`). *optional* - Name of the main output file for LAMMPS. Defaults to `lammps.out`. +- **metadata.options.parser_name**, (`str`), *optional* - Name of the parser to be used for this calculation. Defaults to `lammps.raw`. + +## Outputs: + +- **results**, ({class}`~aiida.orm.nodes.data.dict.Dict`) - The parsed data extracted from the lammps output file. +- **remote_folder**, ({class}`~aiida.orm.nodes.data.remote.base.RemoteData`) - Folder in the remote machine where the calculation was performed. +- **remote_stash**, ({class}`~aiida.orm.nodes.data.remote.stash.base.RemoteStashData`), *optional* – Contents of the stash.source_list option are stored in this remote folder after job completion. +- **retrieved**, ({class}`~aiida.orm.nodes.data.folder.FolderData`) - Files that are retrieved by the daemon will be stored in this node. By default the stdout and stderr of the scheduler will be added, but one can add more by specifying them in `CalcInfo.retrieve_list`. diff --git a/docs/source/topics/data/index.md b/docs/source/topics/data/index.md new file mode 100644 index 00000000..3c53d303 --- /dev/null +++ b/docs/source/topics/data/index.md @@ -0,0 +1,14 @@ +# Data + +```{toctree} +:maxdepth: 1 + +parameters +potential +trajectory + +``` + +`aiida-lammps` has two specific data types, the [`LammpsPotentialData`](potential.md) handling the different types of interatomic potentials and the [`LammpsTrajectory`](trajectory.md) dealing with the atomic positions and the time dependent site dependent calculated properties of the system. + +Another data set of interest, is the [parameters](parameters.md), this is a dictionary that contains the instructions on how to generate the LAMMPS input file. It abstracts, as much as possible, the generation of a single stage LAMMPS calculation input file into a python dictionary. diff --git a/docs/source/topics/data/parameters.md b/docs/source/topics/data/parameters.md new file mode 100644 index 00000000..8b538a86 --- /dev/null +++ b/docs/source/topics/data/parameters.md @@ -0,0 +1,98 @@ +--- +myst: + substitutions: + aiida_lammps: '`aiida-lammps`' + LAMMPS: '[LAMMPS](https://lammps.org)' + AiiDA: '[AiiDA](https://www.aiida.net/)' + pair_style: '[pair-style](https://docs.lammps.org/pair_style.html)' +--- + + +(topics-data-parameters)= + +# Parameters + +The behavior of the {{ aiida_lammps }} calculation can be controlled by collecting {{ LAMMPS }} simulation parameters in a dictionary + +```python +parameters = { + 'md': { + 'velocity': [{'group': 'all', 'create': {'temp': 300}}], + 'integration': { + 'style': 'npt', + 'constraints': {'iso': [0.0, 0.0, 1000.0], 'temp': [300, 300, 100]} + }, + 'max_number_steps': 5000 + }, + 'dump': {'dump_rate': 1000}, + 'thermo': { + 'printing_rate': 100, + 'thermo_printing': { + 'ke': True, + 'pe': True, + 'pxx': True, + 'pyy': True, + 'pzz': True, + 'step': True, + 'press': True + } + }, + 'compute': { + 'ke/atom': [{'type': [{'value': ' ', 'keyword': ' '}], 'group': 'all'}], + 'pe/atom': [{'type': [{'value': ' ', 'keyword': ' '}], 'group': 'all'}], + 'pressure': [{'type': ['thermo_temp'], 'group': 'all'}], + 'stress/atom': [{'type': ['NULL'], 'group': 'all'}] + }, + 'control': {'units': 'metal', 'timestep': 1e-05}, + 'structure': {'atom_style': 'atomic'} +} +``` + +The dictionary is separated into several nested dictionaries that control different behaviors of the {{ LAMMPS }} simulation: +- ``control``: takes keywords specifying global simulation parameters: + * ``units``: {{ LAMMPS }} [units](https://docs.lammps.org/units.html) used in the calculation (default: ``si``). + * ``timestep``: [time step](https://docs.lammps.org/timestep.html) used in the simulation, it depends on the units used (default: {{ LAMMPS }} default dependent on units parameter). + * ``newton``: it controls whether the Newton's third law is [turned on or off](https://docs.lammps.org/newton.html) for the calculation (default: ``on``). + * ``processors``: specifies how [processors](https://docs.lammps.org/processors.html) are mapped to the simulation box (default: ignore the command). +- ``structure``: variables controlling structure options: + * ``box_tilt``: determines how [skewed the cell](https://docs.lammps.org/box.html) is, of great importance for triclinic systems (default: ``small``). + * ``groups``: list with the names of the groups to be added. The names of the possible groups are generated by the list of possible kind names generated by the structure (default: skip parameter). + * ``atom_style``: how the [atoms](https://docs.lammps.org/atom_style.html) are treated by the ``LAMMPS`` simulation. +- ``potential``: parameters related to the potential describing the system: + * ``potential_style_options``: extra parameters related to each of the possible pair styles (default: skip parameter). + * ``neighbor``: sets the parameters affecting the construction of the [neighbor list](https://docs.lammps.org/neighbor.html) (default: skip parameter). + * ``neighbor_modify``: set of options that [modify](https://docs.lammps.org/neigh_modify.html) the pairwise neighbor list generation (default: skip parameter). +- ``dump``: controls parameters regarding the printing of the site dependent quantities: + * ``dump_rate``: how often are the site dependent quantities printed to file (default: 10). +- ``compute``: set of lists containing information about which {{ LAMMPS }} [computes](https://docs.lammps.org/compute.html) should be calculated. For each {{ LAMMPS }} command one passes a list of dictionaries, each dictionary has a ``type`` key containing the options of the compute and ``group`` a key specifying over which group the compute is acting on. +- ``fix``: set of list containing information about which {{ LAMMPS }} [fixes](https://docs.lammps.org/fix.html) should be calculated. For each {{ LAMMPS }} command one passes a list of dictionaries, each dictionary has a ``type`` key containing the options of the fixes and ``group`` a key specifying over which group the fix is acting on. +- ``thermo``: set of variables indicating which global parameters (printed in the ``lammps.out``) should be printed: + * ``printing_rate``: how often should the parameters be written to the ``lammps.out`` (default: 1000) + * ``thermo_printing``: dictionary containing which {{ LAMMPS }} internal [variables](https://docs.lammps.org/thermo_style.html) are printed to the ``lammps.out``. The keys are the names of {{ LAMMPS }} parameters and the value is a boolean on whether to print it or not. +- ``md``: set of variables controlling a molecular dynamics simulation (exclusionary with ``minimize`` key word): + * ``max_number_steps``: maximum number of steps for the molecular dynamics simulation (default: 100) + * ``run_style``: type of molecular dynamics algorithm (default: ``verlet``). + * ``velocity``: set of variables needed to define the [velocity](https://docs.lammps.org/velocity.html) of the system. + * ``integration``: parameters relating to the integrators of the molecular dynamics simulation: + - ``style``: Type of [integrator](https://docs.lammps.org/fixes.html) used for the molecular dynamics simulation. + - ``constraints``: set of options for each integrator, the values depend on the type of integrator. +- ``minimize``: set of variables controlling a minimization simulation (exclusionary with ``md`` key word): + * ``style``: [type of minimization](https://docs.lammps.org/min_style.html) algorithm (default: ``cg``). + * ``energy_tolerance``: tolerance for the energy minimization (default: 1e-4). + * ``force_tolerance``: tolerance for the force minimization (default: 1e-4). + * ``max_iterations``: maximum number of iterations (default: 1000). + * ``max_evaluations``: maximum number of evaluations (default: 1000). +- ``restart``: set of variables controlling the printing of the binary file to [restart](https://docs.lammps.org/Howto_restart.html) a {{ LAMMPS }} calculation. + * ``print_final``: whether or not to print a restart file at the end of the calculation, equivalent to setting [write_restart](https://docs.lammps.org/write_restart.html) at the end of the calculation (default: ``False``). + * ``print_intermediate``: whether or not to print restart files throughout the run at regular intervals, equivalent to the [restart](https://docs.lammps.org/restart.html) {{ LAMMPS }} command (default: ``False``). + * ``num_steps``: however often the restart file is written if ``print_intermediate`` is used (default: ``max_number_steps*0.1``). + +:::{note} +As the restart files can be very large, they are by default not printed, nor stored in the database. Even when one prints them with the ``print_final`` and/or ``print_intermediate`` they are not retrieved and are only kept in the remote folder. The storage of the restart file can be controlled via the ``store_restart=True``(``store_restart=False``) to store(not-store) option in the ``settings`` dictionary. +::: + +## Compute parameters +When asking {{ aiida_lammps }} to calculate a certain ``compute`` its {{ LAMMPS }} name will be automatically generated following the pattern ``compute_name_group_name_aiida`` where ``compute_name`` is the ``LAMMPS`` name of the compute, e.g. ``pe/atom`` with the difference than the ``/`` character is replaced by ``_`` and ``group_name`` is the name of the group to which the compute is applied. All global computes are printed to the ``lammps.out`` and all site dependent quantities are printed to the trajectory file. These computes can then be accessed as outputs of the simulation. + +## Input validation +{{ LAMMPS }} has a quite large amount of possible parameters which can be passed into it to control its behavior. Many of these options are incompatible which can cause the {{ LAMMPS }} simulation to fail. To try to catch as many as possible of these possible conflicts the {{ aiida_lammps }} input is validated against a [JSON schema](https://json-schema.org/understanding-json-schema/index.html), that checks that the provided input parameters fulfill this schema as much as possible, e.g. it checks that only {{ LAMMPS }} computes can be passed to the ``compute`` block, etc. Due to the large amount and variety of options for each compute/fixes these options are not thoroughly checked, only the name of the compute itself is checked. diff --git a/docs/source/topics/data/potential.md b/docs/source/topics/data/potential.md new file mode 100644 index 00000000..5e426bf0 --- /dev/null +++ b/docs/source/topics/data/potential.md @@ -0,0 +1,88 @@ +--- +myst: + substitutions: + aiida_lammps: '`aiida-lammps`' + LAMMPS: '[LAMMPS](https://lammps.org)' + AiiDA: '[AiiDA](https://www.aiida.net/)' + pair_style: '[pair-style](https://docs.lammps.org/pair_style.html)' +--- + +(topics-data-potential)= + +# ``LammpsPotentialData`` + +The potential is one of the most important pieces of data in a MD simulation, since it controls how the atoms interact with each other. +In {{ aiida_lammps }} the potential file is stored in the {class}`~aiida_lammps.data.potential.LammpsPotentialData` data type, which will store the entire potential file in the database, and add certain attributes so that the data node is easily queryable for later usage. These attributes have been chosen so that they resemble the [OpenKIM](https://openkim.org/doc/schema/kimspec/) standard as much as possible. + +To demonstrate how this works one can [download](https://openkim.org/id/EAM_Dynamo_Mendelev_2003_Fe__MO_546673549085_000) a potential from the OpenKIM database, after the file has been downloaded one can generate a dictionary with the metadata of the potential to tag it in the {{ AiiDA }} database. + +```python +potential_parameters = { + 'species': ['Fe'], # Which species can be treated by this potential (required) + 'atom_style': 'atomic', # Which kind of atomic style is associated with this potential (required) + 'pair_style': 'eam/fs', # LAMMPS pair style (required) + 'units': 'metal', # Default units of this potential (required) + 'extra_tags': { + 'content_origin': 'NIST IPRP: https: // www.ctcms.nist.gov/potentials/Fe.html', # Where the file was original found + 'content_other_locations': None, # If the file can be found somewhere else + 'data_method': 'unknown', # How was the data generated + 'description': """ + This Fe EAM potential parameter file is from the NIST repository, \"Fe_2.eam.fs\" as of the March 9, 2009 update. + It is similar to \"Fe_mm.eam.fs\" in the LAMMPS distribution dated 2007-06-11, + but gives different results for very small interatomic distances + (The LAMMPS potential is in fact the deprecated potential referred to in the March 9, 2009 update on the NIST repository). + The file header includes a note from the NIST contributor: + \"The potential was taken from v9_4_bcc (in C:\\SIMULATION.MD\\Fe\\Results\\ab_initio+Interstitials)\" + """, # Short description of the potential + 'developer': ['Ronald E. Miller'], # Name of the developer that uploaded it to OpenKIM + 'disclaimer': """ + According to the developer Giovanni Bonny (as reported by the NIST IPRP), + this potential was not stiffened and cannot be used in its present form for collision cascades. + """, # Any known issues with the potential + 'properties': None, # If any specific properties are associated to the potential + 'publication_year': 2018, # Year of publication to OpenKIM + 'source_citations': [{ + 'abstract': None, + 'author': + 'Mendelev, MI and Han, S and Srolovitz, DJ and Ackland, GJ and Sun, DY and Asta, M', + 'doi': '10.1080/14786430310001613264', + 'journal': '{Phil. Mag.}', + 'number': '{35}', + 'pages': '{3977-3994}', + 'recordkey': 'MO_546673549085_000a', + 'recordprimary': 'recordprimary', + 'recordtype': 'article', + 'title': + '{Development of new interatomic potentials appropriate for crystalline and liquid iron}', + 'volume': '{83}', + 'year': '{2003}' + }], + 'title': 'EAM potential (LAMMPS cubic hermite tabulation) for Fe developed by Mendelev et al. (2003) v000' # Title of the potential + } +} +``` +Certain tags are required, and must be provided to be able to upload the potential to the database. This is because they identify which {{ pair_style }} is associated with the potential, which atomic species can be treated with it, etc. The rest of the tags, in this example are filled so that they follow the [OpenKIM](https://openkim.org/doc/schema/kimspec/) standard as that is the place where the potential was obtained. If another database is used or if it is a homemade potential, these tags can be used to facilitate the querying of the potential. + +Then the potential can be uploaded to the database +```python +from aiida_lamps.data.potential import LammpsPotentialData + +potential = LammpsPotentialData.get_or_create( + source='Fe_2.eam.fs', # Relative path to the potential file + **potential_parameters, # Parameters to tag the potential +) + +``` + +The {meth}`~aiida_lammps.data.potential.LammpsPotentialData.get_or_create` method is based on the one by [aiida-pseudo](https://github.com/aiidateam/aiida-pseudo/blob/master/aiida_pseudo/data/pseudo/pseudo.py), which will calculate the md5 sum of the file and check the database for another file with the same [md5 hash](https://en.wikipedia.org/wiki/MD5), if such entry is found, that potential is used instead. This avoids the unnecessary replication of potential data nodes whenever one tries to upload a previously uploaded potential. + +:::{note} +When calculating the md5 hash the program will look at the contents of the file, so that even if a minor change is done (that should not affect the result of a calculation), the checksum will be different and hence a new potential node will be created. +::: + +## Potentials without files +In {{ LAMMPS }} certain {{ pair_style }} such as the Lenard-Johns potential do not read their parameters from an auxiliary file, if not they are directly written to the main input file. In {{ aiida_lammps }} to standardize the potential storage in the database these kinds of potentials are expected to be also be stored as a file. The format expected for these kinds of potentials is simply the coefficients that one would normally write the in the {{ LAMMPS }} input file. The input file generator will then generate the necessary lines for the input file depending on the potential {{ pair_style }}. + + +## Potentials with multiple files +In {{ LAMMPS }} it is in principle possible to give several potential files to treat different atoms. Currently this is **not** supported in the plugin. As only one potential file can be give as to treat the entire system. This is a situation that is aimed to be solved in future releases. diff --git a/docs/source/topics/data/trajectory.md b/docs/source/topics/data/trajectory.md new file mode 100644 index 00000000..a3a012fc --- /dev/null +++ b/docs/source/topics/data/trajectory.md @@ -0,0 +1,16 @@ +--- +myst: + substitutions: + aiida_lammps: '`aiida-lammps`' + LAMMPS: '[LAMMPS](https://lammps.org)' + AiiDA: '[AiiDA](https://www.aiida.net/)' +--- + +# ``LammpsTrajectory`` + +During the course of a {{ LAMMPS }} simulation large trajectory files are generated. However, these are text files that can be compressed greatly reducing the used space. Hence, storing them directly in the {{ AiiDA }} repository is not efficient. The {class}`~aiida_lammps.data.trajectory.LammpsTrajectory` data class takes care of this by storing each trajectory step is as a separate file, within a compressed zip folder. Thus reducing storage space, and allowing for fast access to each step. + +It is possible to access the data for each step using several methods: +- {meth}`~aiida_lammps.data.trajectory.LammpsTrajectory.get_step_string`: which returns the raw step string from the {{ LAMMPS }} output for a given step. +- {meth}`~aiida_lammps.data.trajectory.LammpsTrajectory.get_step_data`: which returns the parsed data for a given step. +- {meth}`~aiida_lammps.data.trajectory.LammpsTrajectory.get_step_structure`: which returns a {class}`~aiida.orm.nodes.data.structure.StructureData` instance for the crystal structure for a given step. diff --git a/docs/source/topics/workflows/base.md b/docs/source/topics/workflows/base.md new file mode 100644 index 00000000..5c231f29 --- /dev/null +++ b/docs/source/topics/workflows/base.md @@ -0,0 +1,36 @@ +# ``LammpsBaseWorkChain`` + +The {class}`~aiida_lammps.workflows.base.LammpsBaseWorkChain` is a `WorkChain` wrapper for the {class}`~aiida_lammps.calculations.base.LammpsBaseCalculation` that includes the capabilities of the AiiDA [`BaseRestartWorkchain`](https://aiida.readthedocs.io/projects/aiida-core/en/latest/reference/apidoc/aiida.engine.processes.workchains.html#aiida.engine.processes.workchains.restart.BaseRestartWorkChain). That is it allows for automatic error handling and restarting of calculations if certain conditions are met. + +Right now the restart capabilities are limited to: +- Restarting an structural optimization from the last parsed structure if the minimization threshold was not reached. +- Restarting a calculation that ran out of walltime by attempting to start from the last stored structure, if no structure is found restart from scratch but with 50% more walltime. + +The inputs for the {class}`~aiida_lammps.workflows.base.LammpsBaseWorkChain` are quite similar to those from the {class}`~aiida_lammps.calculations.base.LammpsBaseCalculation`, with the only difference being, that for the Workchain the are encapsulated inside the `lammps` namespace. + +## Inputs: +- **lammps.structure**, ({class}`~aiida.orm.nodes.data.structure.StructureData`) - Structure used in the ``LAMMPS`` calculation. +- **lammps.potential**, ({class}`~aiida_lammps.data.potential.LammpsPotentialData`) - Potential used in the ``LAMMPS`` calculation. See [](#topics-data-potential). +- **lammps.parameters**, ({class}`~aiida.orm.nodes.data.dict.Dict`) - Parameters that control the input script generated for the ``LAMMPS`` calculation. See [](#topics-data-parameters). +- **lammps.settings**, ({class}`~aiida.orm.nodes.data.dict.Dict`), *optional* - Additional settings that control the ``LAMMPS`` calculation. +- **lammps.input_restartfile** ({class}`~aiida.orm.nodes.data.singlefile.SinglefileData`), *optional* - Input restart file to continue from a previous ``LAMMPS`` calculation. +- **lammps.parent_folder**, ({class}`~aiida.orm.nodes.data.remote.base.RemoteData`), *optional* - An optional working directory of a previously completed calculation to restart from. +- **store_restart**, ({class}`~aiida.orm.nodes.data.bool.Bool`), *optional* - Whether to store the restart file in the repository. Defaults to `False`. + +:::{note} +LAMMPS can produce binary restart files which contain all the atomic positions, forces and other computed variables until when the are asked to be printed. One can control this by passing a dictionary called `restart` to the `settings` input. The available options for the `restart` are: +- `print_final`, (`bool`) - whether to print a restart file at the end of the calculation. Defaults to `False`. See [`write_restart`](https://docs.lammps.org/write_restart.html). +- `print intermediate`, (`bool`) - whether to print restart files periodically throughout the calculation. Defaults to `False`. See [`restart`](https://docs.lammps.org/restart.html). +- `num_steps`, (`int`) - how often is the intermediate restart file printed. Defaults to 10% of the total number of steps. +::: + +## Outputs: + +- **results**, ({class}`~aiida.orm.nodes.data.dict.Dict`) - The parsed data extracted from the lammps output file. +- **trajectories** ({class}`~aiida_lammps.data.trajectory.LammpsTrajectory`) - The data extracted from the lammps trajectory file, includes the atomic trajectories and the site and time dependent calculation parameters. +- **time_dependent_computes**, ({class}`~aiida.orm.nodes.data.array.array.ArrayData`) - The data with the time dependent computes parsed from the lammps.out. +- **restartfile**, ({class}`~aiida.orm.nodes.data.singlefile.SinglefileData`), *optional* - The restart file of a ``LAMMPS`` calculation. +- **structure**, ({class}`~aiida.orm.nodes.data.structure.StructureData`), *optional* - The output structure of the calculation. +- **remote_folder**, ({class}`~aiida.orm.nodes.data.remote.base.RemoteData`) - Folder in the remote machine where the calculation was performed. +- **remote_stash**, ({class}`~aiida.orm.nodes.data.remote.stash.base.RemoteStashData`), *optional* – Contents of the stash.source_list option are stored in this remote folder after job completion. +- **retrieved**, ({class}`~aiida.orm.nodes.data.folder.FolderData`) - Files that are retrieved by the daemon will be stored in this node. By default the stdout and stderr of the scheduler will be added, but one can add more by specifying them in `CalcInfo.retrieve_list`. diff --git a/docs/source/topics/workflows/index.md b/docs/source/topics/workflows/index.md new file mode 100644 index 00000000..68fdb9da --- /dev/null +++ b/docs/source/topics/workflows/index.md @@ -0,0 +1,21 @@ +--- +myst: + substitutions: + aiida_lammps: '`aiida-lammps`' + LAMMPS: '[LAMMPS](https://lammps.org)' + AiiDA: '[AiiDA](https://www.aiida.net/)' +--- + +(topics-workflows)= + +# Workflows + +```{toctree} +:maxdepth: 1 + +base +relax +md +``` + +The workflows act as abstractions of the {class}`~aiida_lammps.calculations.base.LammpsBaseCalculation` focusing on being able to perform error correction as well as specific tasks. The idea is that these are used as building blocks for more complex calculations, offloading what is normally done inside by scripting in the {{ LAMMPS }} input to {{ AiiDA }}. The advantage of this is that each step of the complex workflow will be stored in the {{ AiiDA }} provenance graph, and will be able to be used for other calculations, data analysis or just as a way to effectively monitor what happens at each stage. The drawback with this approach is that each stage is a {{ LAMMPS }} calculation, which implies some overhead, as well as effort into rewriting the {{ LAMMPS }} script into an {{ AiiDA }} compliant workflow. diff --git a/docs/source/topics/workflows/md.md b/docs/source/topics/workflows/md.md new file mode 100644 index 00000000..568c7eaa --- /dev/null +++ b/docs/source/topics/workflows/md.md @@ -0,0 +1,52 @@ +--- +myst: + substitutions: + aiida_lammps: '`aiida-lammps`' + LAMMPS: '[LAMMPS](https://lammps.org)' + AiiDA: '[AiiDA](https://www.aiida.net/)' + LammpsBaseCalculation: '{class}`~aiida_lammps.calculations.base.LammpsBaseCalculation`' + LammpsRawCalculation: '{class}`~aiida_lammps.calculations.raw.LammpsRawCalculation`' + Int: '{class}`~aiida.orm.nodes.data.int.Int`' + Str: '{class}`~aiida.orm.nodes.data.str.Str`' + Dict: '{class}`~aiida.orm.nodes.data.dict.Dict`' + List: '{class}`~aiida.orm.nodes.data.list.List`' +--- + +# ``LammpsMDWorkChain`` + +This is a subclass of the {class}`~aiida_lammps.workflows.base.LammpsBaseWorkChain` which focuses on MD simulations specifically. It overrides any set of parameters given in the md block (see [](#topics-data-parameters)) and instead directly exposes them to the user in the `md` input namespace. + + +## Inputs: + +- **lammps.structure**, ({class}`~aiida.orm.nodes.data.structure.StructureData`) - Structure used in the ``LAMMPS`` calculation. +- **lammps.potential**, ({class}`~aiida_lammps.data.potential.LammpsPotentialData`) - Potential used in the ``LAMMPS`` calculation. See [](#topics-data-potential). +- **lammps.parameters**, ({class}`~aiida.orm.nodes.data.dict.Dict`) - Parameters that control the input script generated for the ``LAMMPS`` calculation. See [](#topics-data-parameters). +- **lammps.settings**, ({class}`~aiida.orm.nodes.data.dict.Dict`), *optional* - Additional settings that control the ``LAMMPS`` calculation. +- **lammps.input_restartfile** ({class}`~aiida.orm.nodes.data.singlefile.SinglefileData`), *optional* - Input restart file to continue from a previous ``LAMMPS`` calculation. +- **lammps.parent_folder**, ({class}`~aiida.orm.nodes.data.remote.base.RemoteData`), *optional* - An optional working directory of a previously completed calculation to restart from. +- **store_restart**, ({class}`~aiida.orm.nodes.data.bool.Bool`), *optional* - Whether to store the restart file in the repository. Defaults to `False`. +- **md.steps**, ({{ Int }}), *optional* - Number of steps in the MD simulation. Defaults to `1000`. +- **md.algo**, {{ Str }}, *optional* - Type of time integrator used for MD simulations in LAMMPS ([run_style](https://docs.lammps.org/run_style.html)). Defaults to verlet. +- **md.integrator**, ({{ Str }}), *optional* - Type of thermostat used for the MD simulation in LAMMPS, e.g. ``fix npt``. Defaults to `npt`. +- **md.integrator_constraints**, ({{ Dict }}), *optional* - Set of constraints that are applied to the thermostat. Defaults to `{"temp":[300,300,100], "iso":[0.0, 0.0, 1000]}`. +- **md.velocity**, ({{ List }}), *optional* - List with the information describing how to generate the velocities for the initialization of the MD run. +- **md.respa_options**, ({{ List }}), *optional* - List with the information needed to setup the respa options. + +:::{note} +LAMMPS can produce binary restart files which contain all the atomic positions, forces and other computed variables until when the are asked to be printed. One can control this by passing a dictionary called `restart` to the `settings` input. The available options for the `restart` are: +- `print_final`, (`bool`) - whether to print a restart file at the end of the calculation. Defaults to `False`. See [`write_restart`](https://docs.lammps.org/write_restart.html). +- `print intermediate`, (`bool`) - whether to print restart files periodically throughout the calculation. Defaults to `False`. See [`restart`](https://docs.lammps.org/restart.html). +- `num_steps`, (`int`) - how often is the intermediate restart file printed. Defaults to 10% of the total number of steps. +::: + +## Outputs: + +- **results**, ({class}`~aiida.orm.nodes.data.dict.Dict`) - The parsed data extracted from the lammps output file. +- **trajectories** ({class}`~aiida_lammps.data.trajectory.LammpsTrajectory`) - The data extracted from the lammps trajectory file, includes the atomic trajectories and the site and time dependent calculation parameters. +- **time_dependent_computes**, ({class}`~aiida.orm.nodes.data.array.array.ArrayData`) - The data with the time dependent computes parsed from the lammps.out. +- **restartfile**, ({class}`~aiida.orm.nodes.data.singlefile.SinglefileData`), *optional* - The restart file of a ``LAMMPS`` calculation. +- **structure**, ({class}`~aiida.orm.nodes.data.structure.StructureData`), *optional* - The output structure of the calculation. +- **remote_folder**, ({class}`~aiida.orm.nodes.data.remote.base.RemoteData`) - Folder in the remote machine where the calculation was performed. +- **remote_stash**, ({class}`~aiida.orm.nodes.data.remote.stash.base.RemoteStashData`), *optional* – Contents of the stash.source_list option are stored in this remote folder after job completion. +- **retrieved**, ({class}`~aiida.orm.nodes.data.folder.FolderData`) - Files that are retrieved by the daemon will be stored in this node. By default the stdout and stderr of the scheduler will be added, but one can add more by specifying them in `CalcInfo.retrieve_list`. diff --git a/docs/source/topics/workflows/relax.md b/docs/source/topics/workflows/relax.md new file mode 100644 index 00000000..3bae3cd5 --- /dev/null +++ b/docs/source/topics/workflows/relax.md @@ -0,0 +1,61 @@ +--- +myst: + substitutions: + aiida_lammps: '`aiida-lammps`' + LAMMPS: '[LAMMPS](https://lammps.org)' + AiiDA: '[AiiDA](https://www.aiida.net/)' + LammpsBaseCalculation: '{class}`~aiida_lammps.calculations.base.LammpsBaseCalculation`' + LammpsRawCalculation: '{class}`~aiida_lammps.calculations.raw.LammpsRawCalculation`' + Int: '{class}`~aiida.orm.nodes.data.int.Int`' + Float: '{class}`~aiida.orm.nodes.data.float.Float`' + Str: '{class}`~aiida.orm.nodes.data.str.Str`' + Dict: '{class}`~aiida.orm.nodes.data.dict.Dict`' + List: '{class}`~aiida.orm.nodes.data.list.List`' + Bool: '{class}`~aiida.orm.nodes.data.bool.Bool`' +--- + +# ``LammpsRelaxWorkChain`` + +This is a subclass of the {class}`~aiida_lammps.workflows.base.LammpsBaseWorkChain` which focuses on minimization simulations specifically. It overrides any set of parameters given in the minimize block (see [](#topics-data-parameters)) and instead directly exposes them to the user in the `relax` input namespace. + +## Inputs: + +- **lammps.structure**, ({class}`~aiida.orm.nodes.data.structure.StructureData`) - Structure used in the ``LAMMPS`` calculation. +- **lammps.potential**, ({class}`~aiida_lammps.data.potential.LammpsPotentialData`) - Potential used in the ``LAMMPS`` calculation. See [](#topics-data-potential). +- **lammps.parameters**, ({class}`~aiida.orm.nodes.data.dict.Dict`) - Parameters that control the input script generated for the ``LAMMPS`` calculation. See [](#topics-data-parameters). +- **lammps.settings**, ({class}`~aiida.orm.nodes.data.dict.Dict`), *optional* - Additional settings that control the ``LAMMPS`` calculation. +- **lammps.input_restartfile** ({class}`~aiida.orm.nodes.data.singlefile.SinglefileData`), *optional* - Input restart file to continue from a previous ``LAMMPS`` calculation. +- **lammps.parent_folder**, ({class}`~aiida.orm.nodes.data.remote.base.RemoteData`), *optional* - An optional working directory of a previously completed calculation to restart from. +- **store_restart**, ({{ Bool }}), *optional* - Whether to store the restart file in the repository. Defaults to `False`. +- **relax.algo**, ({{ Str }}), *optional* - The algorithm to be used during relaxation. Defaults to cg. +- **relax.volume**, ({{ Bool }}), *optional* - Whether or not relaxation of the volume will be performed by using the [box/relax](https://docs.lammps.org/fix_box_relax.html) fix from LAMMPS. Defaults to `False`. +- **relax.shape**, ({{ Bool }}), *optional* - Whether or not the shape of the cell will be relaxed by using the [box/relax](https://docs.lammps.org/fix_box_relax.html) fix from LAMMPS. Defaults to `False` +- **relax.positions**, ({{ Bool }}), *optional* - Whether or not to allow the relaxation of the atomic positions. Defaults to `True`. +- **relax.steps**, ({{ Int }}), *optional* - Maximum number of steps during the relaxation. Defaults to `1000`. +- **relax.evaluations**, ({{ Int }}), *optional* - Maximum number of force/energy evaluations during the relaxation. Defaults to `10000`. +- **relax.energy_tolerance**, ({{ Float }}), *optional* - The tolerance that determined whether the relaxation procedure is stopped. In this case it stops when the relative change between outer iterations of the relaxation run is less than the given value. Defaults to 1e-4. +- **relax.force_tolerance**, ({{ Float }}), *optional* - The tolerance that determines whether the relaxation procedure is stopped. In this case it stops when the 2-norm of the global force vector is less than the given value. Defaults to `1e-4`. +- **relax.target_pressure**, ({{ Dict }}), *optional* - Dictionary containing the values for the target pressure tensor. See the [box/relax](https://docs.lammps.org/fix_box_relax.html) for more information. +- **relax.max_volume_change**, ({{ Float }}), *optional* - Maximum allowed change in one iteration (``vmax``). +- **relax.nreset**, ({{ Int }}), *optional* - Reset the reference cell every this many minimizer iterations. +- **relax.meta_convergence**, ({{ Bool }}), *optional* - If `True` the workchain will perform a meta-convergence on the cell volume. Defaults to `True`. +- **relax.max_meta_convergence_iterations**, ({{ Int}}), *optional* - The maximum number of variable cell relax iterations in the meta convergence cycle. Defaults to `5`. +- **relax.volume_convergence**, ({{ Float }}), *optional* - The volume difference threshold between two consecutive meta convergence iterations. Defaults to `0.1`. + +:::{note} +LAMMPS can produce binary restart files which contain all the atomic positions, forces and other computed variables until when the are asked to be printed. One can control this by passing a dictionary called `restart` to the `settings` input. The available options for the `restart` are: +- `print_final`, (`bool`) - whether to print a restart file at the end of the calculation. Defaults to `False`. See [`write_restart`](https://docs.lammps.org/write_restart.html). +- `print intermediate`, (`bool`) - whether to print restart files periodically throughout the calculation. Defaults to `False`. See [`restart`](https://docs.lammps.org/restart.html). +- `num_steps`, (`int`) - how often is the intermediate restart file printed. Defaults to 10% of the total number of steps. +::: + +## Outputs: + +- **results**, ({class}`~aiida.orm.nodes.data.dict.Dict`) - The parsed data extracted from the lammps output file. +- **trajectories** ({class}`~aiida_lammps.data.trajectory.LammpsTrajectory`) - The data extracted from the lammps trajectory file, includes the atomic trajectories and the site and time dependent calculation parameters. +- **time_dependent_computes**, ({class}`~aiida.orm.nodes.data.array.array.ArrayData`) - The data with the time dependent computes parsed from the lammps.out. +- **restartfile**, ({class}`~aiida.orm.nodes.data.singlefile.SinglefileData`), *optional* - The restart file of a ``LAMMPS`` calculation. +- **structure**, ({class}`~aiida.orm.nodes.data.structure.StructureData`), *optional* - The output structure of the calculation. +- **remote_folder**, ({class}`~aiida.orm.nodes.data.remote.base.RemoteData`) - Folder in the remote machine where the calculation was performed. +- **remote_stash**, ({class}`~aiida.orm.nodes.data.remote.stash.base.RemoteStashData`), *optional* – Contents of the stash.source_list option are stored in this remote folder after job completion. +- **retrieved**, ({class}`~aiida.orm.nodes.data.folder.FolderData`) - Files that are retrieved by the daemon will be stored in this node. By default the stdout and stderr of the scheduler will be added, but one can add more by specifying them in `CalcInfo.retrieve_list`. diff --git a/docs/source/tutorials/first_md.md b/docs/source/tutorials/first_md.md new file mode 100644 index 00000000..d633c5c2 --- /dev/null +++ b/docs/source/tutorials/first_md.md @@ -0,0 +1,217 @@ +--- +myst: + substitutions: + aiida_lammps: '`aiida-lammps`' + LAMMPS: '[LAMMPS](https://lammps.org)' + OpenKIM: '[OpenKIM](https://openkim.org/)' +--- + +(tutorials-md)= + +# Molecular dynamics in LAMMPS + +The following example will show how one performs a [LAMMPS molecular dynamics](https://docs.lammps.org/run.html) calculation through AiiDA's Python API. +For the purpose of this demonstration, the dynamics of the atoms of bcc iron at room temperature will be calculated. + +:::{tip} +The code shown in the snippets below can be {download}`downloaded as a script `, +The script can be made executable and then run to execute the example calculation. +::: + +First import the required classes and functions: + +```python +from aiida.engine import run +from aiida.orm import Dict, StructureData, load_code +from aiida_lammps.data.potential import LammpsPotentialData +``` + +Then, load the code that was setup in AiiDA for `lmp` and get an instance of the [process builder](https://aiida.readthedocs.io/projects/aiida-core/en/latest/topics/processes/usage.html#process-builder): + +```python +# Load the code configured for ``lmp``. Make sure to replace +# this string with the label used in the code setup. +code = load_code('lammps@localhost') +builder = code.get_builder() +``` + +The process builder can be used to assign and automatically validate the inputs that will be used for the calculation. +One can start by defining and assigning the structure to the builder: + +```python +from ase.build import bulk +structure = StructureData(ase=bulk('Fe', 'bcc', 2.87, cubic=True)) +builder.structure = structure +``` + +The crystal structure is generated by making use of the `bulk` method of the [ASE library](https://wiki.fysik.dtu.dk/ase/ase/build/build.html#ase.build.bulk). +The ase structure is then passed to the {class}`~aiida.orm.nodes.data.structure.StructureData`, which generates a node that is stored in AiiDA's provenance graph, and then passed to the builder. + +:::{note} +The structure is constructed in such as way as to have a cubic cell with orthogonal axis as {{ LAMMPS }} prefers this kind of setup. +::: + +The next step is to define the interatomic potential that will be used for this system. +The interatomic potentials can be found in many repositories such as the ones from [NIST](https://www.ctcms.nist.gov/potentials/) and OpenKIM. +In the following a potential from the OpenKIM repository will be used. + +```python +import requests +import io + +# Download the potential from the repository and store it as a BytesIO object +_stream = io.BytesIO(requests.get('https://openkim.org/files/MO_546673549085_000/Fe_2.eam.fs', timeout=20).text.encode('utf-8')) + +# Set the metadata for the potential +potential_parameters = { + 'species': ['Fe'], + 'atom_style': 'atomic', + 'pair_style': 'eam/fs', + 'units': 'metal', + 'extra_tags': { + 'title': 'EAM potential (LAMMPS cubic hermite tabulation) for Fe developed by Mendelev et al. (2003) v000', + 'content_origin': 'NIST IPRP: https: // www.ctcms.nist.gov/potentials/Fe.html', + 'developer': ['Ronald E. Miller'], + 'publication_year': 2018, + } +} + +# Store the potential in an AiiDA node +potential = LammpsPotentialData.get_or_create(source=_stream,**potential_parameters) + +builder.potential = potential +``` + +The potential is downloaded from the OpenKIM repository making use of the [requests library](https://docs.python-requests.org/en/latest/index.html) and then transformed into a bytes stream via the `BytesIO` class from the [core io library](https://docs.python.org/3/library/io.html). +After that one needs to define the metadata for the potential, this is necessary to be able to make sure that the potential is used only on appropriate systems and that it can be easily tracked. + +:::{note} +All the parameters in the `extra_tags` are not necessary to define a potential node, but they will improve the querying and tracking of the potential. For a more detailed explanation see the topic section [](#topics-data-potential). +::: + +With the potential data and the metadata dictionary one can then generate a {class}`~aiida_lammps.data.potential.LammpsPotentialData` node which can be assigned to the builder. + +Then one needs to define the parameters which control how the input file for the {{ LAMMPS }} calculation is generated. +For a structural minimization the minimal set of parameters is the following: + +```python + +# Parameters to control the input file generation +parameters = Dict({ + "control": { + "units": "metal", + "timestep": 1e-5 + }, + "compute":{ + "pe/atom": [{"type": [{"keyword": " ", "value": " "}], "group": "all"}], + "ke/atom": [{"type": [{"keyword": " ", "value": " "}], "group": "all"}], + "stress/atom": [{"type": ["NULL"], "group": "all"}], + "pressure": [{"type": ["thermo_temp"], "group": "all"}], + }, + + "structure":{"atom_style": "atomic"}, + "thermo":{ + "printing_rate": 100, + "thermo_printing": { + "step": True, + "pe": True, + "ke": True, + "press": True, + "pxx": True, + "pyy": True, + "pzz": True, + } + }, + "md":{ + "integration": { + "style": "npt", + "constraints": { + "temp": [300, 300, 100], + "iso": [0.0, 0.0, 1000.0], + }, + }, + "max_number_steps": 5000, + "velocity": [{"create": {"temp": 300}, "group": "all"}], + }, +}) +builder.parameters = parameters +``` +The parameters have several sections which control different behavior of the calculation: + +- `control` section handles global parameters for the simulation, such as the units and time step. +- `compute` section specifies which parameters will be calculated and printed to file during the LAMMPS simulation ([see compute command](https://docs.lammps.org/compute.html)). +- `structure`: controls aspects related to the structure handling in {{ LAMMPS }}. +- `thermo`: controls which global thermodynamic information will be calculated and written to file ([see thermo command](https://docs.lammps.org/thermo.html)). +- `md`: controls how the molecular dynamics calculations are performed. Controlling which type of ensemble will be used, eg. [npt](https://docs.lammps.org/fix_nh.html#fix-npt-command), [nvt](https://docs.lammps.org/fix_nh.html#fix-nvt-command), [nve](https://docs.lammps.org/fix_nve.html) as well as initial thermalization parameters such as the [velocities](https://docs.lammps.org/velocity.html) of the particles. + +:::{note} +For a detailed explanation of the possible options in the parameters see the [](#topics-data-parameters) topic section. + +::: + +Lastly one needs to define the computational resources needed to perform the calculation +```python +# Run the calculation on 1 CPU and kill it if it runs longer than 1800 seconds. +# Set ``withmpi`` to ``False`` if ``pw.x`` was compiled without MPI support. +builder.metadata.options = { + 'resources': { + 'num_machines': 1, + }, + 'max_wallclock_seconds': 1800, + 'withmpi': False, +} +``` + +Now as all the needed parameters have been defined the calculation can bse launched using the process builder: + +```python +outputs, node = run.get_node(builder) +``` + +Once the calculation is finished `run.get_node` will return the outputs produced and the calculation node, `outputs` and `node` respectively. + +The `node` is the entry that contains the information pertaining the calculation. +It is possible to check if the calculation finished successfully (processes that return `0` are considered to be successful) by looking at its exit status: + +```python +node.exit_status +``` + +If the result is different from zero it means that a problem was encountered in the calculation. This might indicate that some output is not present, that the calculation failed due to a transitory issue, an input problem, etc. + +The `outputs` is a dictionary containing the output nodes produced by the calculation: + +```python +print(outputs) +{ + 'remote_folder': , + 'retrieved': , + 'results': , + 'time_dependent_computes': , + 'trajectories': , + 'structure': , +} +``` + +The `results` node is a dictionary that will contain the final result of the calculated thermodynamic variables as well as general information about the calculation status + +```python +print(outputs['results'].get_dict()) +{ + 'final_ke': 0.024456795122703, + 'final_pe': -8.2274854545799, + 'final_pxx': -26539.404872624, + 'final_pyy': -25646.583264533, + 'final_pzz': -25646.563988137, + 'final_step': 5000, + ... +} +``` + +The `time_dependent_computes` contains a series of numpy arrays each one representing the values the global variables as a function of time. One can get the names of the arrays by making use of the `.get_arraynames()` method and an individual array can be accesses by making use of `.get_array('array_name')` where `'array_name'` is one of the strings found with the previous command. + +The complete output that was written by {{ LAMMPS }} to stdout, can be retrieved as follows: + +```python +results['retrieved'].base.repository.get_object_content('aiida_lammps.out') +``` diff --git a/docs/source/tutorials/first_raw.md b/docs/source/tutorials/first_raw.md new file mode 100644 index 00000000..82dd4764 --- /dev/null +++ b/docs/source/tutorials/first_raw.md @@ -0,0 +1,171 @@ +--- +myst: + substitutions: + aiida_lammps: '`aiida-lammps`' + LAMMPS: '[LAMMPS](https://lammps.org)' + OpenKIM: '[OpenKIM](https://openkim.org/)' +--- + +(tutorials-raw)= + +# Raw LAMMPS calculation + +Sometimes transforming a {{ LAMMPS }} script into a set of parameters that can be passed as a dictionary to {{ aiida_lammps }} can be very complicated or impossible. That is why the {class}`~aiida_lammps.calculations.raw.LammpsRawCalculation` is included, as it gives a way to pass a functioning {{ LAMMPS }} script to {{ aiida_lammps }} and run it via AiiDA. This will store the calculation in the AiiDA provenance graph and perform some basic parsing functions. However, as a great deal of the information needed to be able to parse the data is not present (due to the lack of parameters passed to the calculation engine) many of the automatic parsing done in the {class}`~aiida_lammps.calculations.base.LammpsBaseCalculation` is not performed in this case. + +:::{note} +The usage of the {class}`~aiida_lammps.calculations.raw.LammpsRawCalculation` also introduces difficulties with regards to the querying of results. With the {class}`~aiida_lammps.calculations.base.LammpsBaseCalculation` one passes several nodes, parameters, structure and potential which can be used in the AiiDA query engine to get specific calculations. As these do not exist for the {class}`~aiida_lammps.calculations.raw.LammpsRawCalculation` the querying can be severely limited. +::: + +:::{tip} +The code shown in the snippets below can be {download}`downloaded as a script `, +The script can be made executable and then run to execute the example calculation. +::: + + + +First import the required classes and functions: + +```python +from aiida.plugins import CalculationFactory +from aiida import engine +from aiida.orm import SinglefileData, load_code +``` + +Then, load the code that was setup in AiiDA for `lmp` and get an instance of the [process builder](https://aiida.readthedocs.io/projects/aiida-core/en/latest/topics/processes/usage.html#process-builder): + +```python +# Load the code configured for ``lmp``. Make sure to replace +# this string with the label used in the code setup. +code = load_code('lammps@localhost') +builder = CalculationFactory("lammps.raw").get_builder() +builder.code = code +``` + +The process builder can be used to assign and automatically validate the inputs that will be used for the calculation. + +For the raw calculation the most important piece is to pass the LAMMPS script that will be run. To be able to pass it to AiiDA one needs to store it as a {class}`~aiida.orm.nodes.data.singlefile.SinglefileData` node, which basically stores a file in the AiiDA provenance graph. When a {class}`~aiida_lammps.calculations.raw.LammpsRawCalculation` is submitted this file will be copied **exactly** in the machine performing the calculation. +```python +import io +import textwrap + +script = SinglefileData( + io.StringIO( + textwrap.dedent( + """ + # Rhodopsin model + + units real + neigh_modify delay 5 every 1 + + atom_style full + bond_style harmonic + angle_style charmm + dihedral_style charmm + improper_style harmonic + pair_style lj/charmm/coul/long 8.0 10.0 + pair_modify mix arithmetic + kspace_style pppm 1e-4 + + read_data data.rhodo + + fix 1 all shake 0.0001 5 0 m 1.0 a 232 + fix 2 all npt temp 300.0 300.0 100.0 & + z 0.0 0.0 1000.0 mtk no pchain 0 tchain 1 + + special_bonds charmm + + thermo 50 + thermo_style multi + timestep 2.0 + + run 100 + """ + ) + ) +) +builder.script = script +``` + +As one can notice the script wants to read a file named `data.rhodo` via the [`read_data`](https://docs.lammps.org/read_data.html) command. One can pass any set of files that the script might need, in this case a file stored in the lammps repository that is downloaded using the [requests library](https://docs.python-requests.org/en/latest/index.html), by first storing them as {class}`~aiida.orm.nodes.data.singlefile.SinglefileData` nodes and the passing them to the builder as follows: + +```python +import requests +request = requests.get("https://raw.githubusercontent.com/lammps/lammps/develop/bench/data.rhodo") +data = SinglefileData(io.StringIO(request.text)) +builder.files = {"data": data} +builder.filenames = {"data": "data.rhodo"} +``` + +:::{important} +Notice that one first passes the files in a dictionary with a key called `data`, the filename dictionary specifies the name that will be given to the file stored under the key `data` in the machine performing the calculation. One needs to ensure that this name, `data.rhodo` in this case, matches the expected name by the script. +::: + +Lastly one needs to define the computational resources needed to perform the calculation +```python +# Run the calculation on 1 CPU and kill it if it runs longer than 1800 seconds. +# Set ``withmpi`` to ``False`` if ``pw.x`` was compiled without MPI support. +builder.metadata.options = { + 'resources': { + 'num_machines': 1, + }, + 'max_wallclock_seconds': 1800, + 'withmpi': False, +} +``` + +Now as all the needed parameters have been defined the calculation can bse launched using the process builder: + +```python +outputs, node = engine.get_node(builder) +``` + +Once the calculation is finished `run.get_node` will return the outputs produced and the calculation node, `outputs` and `node` respectively. + +The `node` is the entry that contains the information pertaining the calculation. +It is possible to check if the calculation finished successfully (processes that return `0` are considered to be successful) by looking at its exit status: + +```python +node.exit_status +``` + +If the result is different from zero it means that a problem was encountered in the calculation. This might indicate that some output is not present, that the calculation failed due to a transitory issue, an input problem, etc. + +The `outputs` is a dictionary containing the output nodes produced by the calculation: + +```python +print(outputs) +{ + 'remote_folder': , + 'retrieved': , + 'results': +} +``` + +The `results` node is a dictionary that will contain some basic parsed information from the data written to the stdout + + +```python +print(outputs['results'].get_dict()) +{ + 'compute_variables': { + 'bin': 'standard', + 'bins': [10, 13, 13], + 'errors': [], + 'binsize': 6, + 'warnings': [], + 'units_style': 'real', + 'total_wall_time': '0:00:20', + 'steps_per_second': 5.046, + 'ghost_atom_cutoff': 12, + 'max_neighbors_atom': 2000, + 'total_wall_time_seconds': 20, + 'master_list_distance_cutoff': 12 + } +} +``` + +The complete output that was written by {{ LAMMPS }} to stdout, can be retrieved as follows: + +```python +results['retrieved'].base.repository.get_object_content('lammps.out') +``` diff --git a/docs/source/tutorials/first_relaxation.md b/docs/source/tutorials/first_relaxation.md new file mode 100644 index 00000000..daf777c1 --- /dev/null +++ b/docs/source/tutorials/first_relaxation.md @@ -0,0 +1,213 @@ +--- +myst: + substitutions: + aiida_lammps: '`aiida-lammps`' + LAMMPS: '[LAMMPS](https://lammps.org)' + OpenKIM: '[OpenKIM](https://openkim.org/)' +--- + +(tutorials-minimization)= + +# Minimization in LAMMPS + +The following example will show how one performs a [LAMMPS minimization](https://docs.lammps.org/minimize.html) calculation through AiiDA's Python API. +For the purpose of this demonstration, the optimal structure for bcc iron will is computed. + +:::{tip} +The code shown in the snippets below can be {download}`downloaded as a script `, +The script can be made executable and then run to execute the example calculation. +::: + +First import the required classes and functions: + +```python +from aiida.engine import run +from aiida.orm import Dict, StructureData, load_code +from aiida_lammps.data.potential import LammpsPotentialData +``` + +Then, load the code that was setup in AiiDA for `lmp` and get an instance of the [process builder](https://aiida.readthedocs.io/projects/aiida-core/en/latest/topics/processes/usage.html#process-builder): + +```python +# Load the code configured for ``lmp``. Make sure to replace +# this string with the label used in the code setup. +code = load_code('lammps@localhost') +builder = code.get_builder() +``` + +The process builder can be used to assign and automatically validate the inputs that will be used for the calculation. +One can start by defining and assigning the structure to the builder: + +```python +from ase.build import bulk +structure = StructureData(ase=bulk('Fe', 'bcc', 2.87, cubic=True)) +builder.structure = structure +``` + +The crystal structure is generated by making use of the `bulk` method of the [ASE library](https://wiki.fysik.dtu.dk/ase/ase/build/build.html#ase.build.bulk). +The ase structure is then passed to the {class}`~aiida.orm.nodes.data.structure.StructureData`, which generates a node that is stored in AiiDA's provenance graph, and then passed to the builder. + +:::{note} +The structure is constructed in such as way as to have a cubic cell with orthogonal axis as {{ LAMMPS }} prefers this kind of setup. +::: + +The next step is to define the interatomic potential that will be used for this system. +The interatomic potentials can be found in many repositories such as the ones from [NIST](https://www.ctcms.nist.gov/potentials/) and OpenKIM. +In the following a potential from the OpenKIM repository will be used. + +```python +import requests +import io + +# Download the potential from the repository and store it as a BytesIO object +_stream = io.BytesIO(requests.get('https://openkim.org/files/MO_546673549085_000/Fe_2.eam.fs').text.encode('ascii')) + +# Set the metadata for the potential +potential_parameters = { + 'species': ['Fe'], + 'atom_style': 'atomic', + 'pair_style': 'eam/fs', + 'units': 'metal', + 'extra_tags': { + 'title': 'EAM potential (LAMMPS cubic hermite tabulation) for Fe developed by Mendelev et al. (2003) v000', + 'content_origin': 'NIST IPRP: https: // www.ctcms.nist.gov/potentials/Fe.html', + 'developer': ['Ronald E. Miller'], + 'publication_year': 2018, + } +} + +# Store the potential in an AiiDA node +potential = LammpsPotentialData.get_or_create(source=_stream,**potential_parameters) + +builder.potential = potential +``` + +The potential is downloaded from the OpenKIM repository making use of the [requests library](https://docs.python-requests.org/en/latest/index.html) and then transformed into a bytes stream via the `BytesIO` class from the [core io library](https://docs.python.org/3/library/io.html). +After that one needs to define the metadata for the potential, this is necessary to be able to make sure that the potential is used only on appropriate systems and that it can be easily tracked. + +:::{note} +All the parameters in the `extra_tags` are not necessary to define a potential node, but they will improve the querying and tracking of the potential. For a more detailed explanation see the topic section [](#topics-data-potential). +::: + +With the potential data and the metadata dictionary one can then generate a {class}`~aiida_lammps.data.potential.LammpsPotentialData` node which can be assigned to the builder. + +Then one needs to define the parameters which control how the input file for the {{ LAMMPS }} calculation is generated. +For a structural minimization the minimal set of parameters is the following: + +```python + +# Parameters to control the input file generation +parameters = Dict({ + "control": { + "units": "metal", + "timestep": 1e-5 + }, + "compute":{ + "pe/atom": [{"type": [{"keyword": " ", "value": " "}], "group": "all"}], + "ke/atom": [{"type": [{"keyword": " ", "value": " "}], "group": "all"}], + "stress/atom": [{"type": ["NULL"], "group": "all"}], + "pressure": [{"type": ["thermo_temp"], "group": "all"}], + }, + + "structure":{"atom_style": "atomic"}, + "thermo":{ + "printing_rate": 100, + "thermo_printing": { + "step": True, + "pe": True, + "ke": True, + "press": True, + "pxx": True, + "pyy": True, + "pzz": True, + } + }, + "minimize":{ + "style": "cg", + "energy_tolerance": 1e-4, + "force_tolerance": 1e-4, + "max_iterations": 1000, + "max_evaluations": 1000, + }, +}) +builder.parameters = parameters +``` +The parameters have several sections which control different behavior of the calculation: + +- `control` section handles global parameters for the simulation, such as the units and time step. +- `compute` section specifies which parameters will be calculated and printed to file during the LAMMPS simulation ([see compute command](https://docs.lammps.org/compute.html)). +- `structure`: controls aspects related to the structure handling in {{ LAMMPS }}. +- `thermo`: controls which global thermodynamic information will be calculated and written to file ([see thermo command](https://docs.lammps.org/thermo.html)). +- `minimize`: controls the structural minimization algorithm used ([see minimize command](https://docs.lammps.org/minimize.html)). + + +:::{note} +For a detailed explanation of the possible options in the parameters see the [](#topics-data-parameters) topic section. + +::: + +Lastly one needs to define the computational resources needed to perform the calculation +```python +# Run the calculation on 1 CPU and kill it if it runs longer than 1800 seconds. +# Set ``withmpi`` to ``False`` if ``pw.x`` was compiled without MPI support. +builder.metadata.options = { + 'resources': { + 'num_machines': 1, + }, + 'max_wallclock_seconds': 1800, + 'withmpi': False, +} +``` + +Now as all the needed parameters have been defined the calculation can bse launched using the process builder: + +```python +outputs, node = run.get_node(builder) +``` + +Once the calculation is finished `run.get_node` will return the outputs produced and the calculation node, `outputs` and `node` respectively. + +The `node` is the entry that contains the information pertaining the calculation. +It is possible to check if the calculation finished successfully (processes that return `0` are considered to be successful) by looking at its exit status: + +```python +node.exit_status +``` + +If the result is different from zero it means that a problem was encountered in the calculation. This might indicate that some output is not present, that the calculation failed due to a transitory issue, an input problem, etc. + +The `outputs` is a dictionary containing the output nodes produced by the calculation: + +```python +print(outputs) +{ + 'results': , + 'time_dependent_computes': , + 'trajectories': , + 'structure': , + 'remote_folder': , + 'retrieved': +} +``` + +The `results` node is a dictionary that will contain the final result of the calculated thermodynamic variables as well as general information about the calculation status + +```python +print(outputs['results'].get_dict()) +{ + 'final_ke': 0, + 'final_pe': -8.2418066986197, + 'final_pxx': -27037.610112703, + 'final_pyy': -27037.610112703, + 'final_pzz': -27037.610112703, + ... +} +``` + +The `time_dependent_computes` contains a series of numpy arrays each one representing the values the global variables as a function of time. One can get the names of the arrays by making use of the `.get_arraynames()` method and an individual array can be accesses by making use of `.get_array('array_name')` where `'array_name'` is one of the strings found with the previous command. + +The complete output that was written by {{ LAMMPS }} to stdout, can be retrieved as follows: + +```python +results['retrieved'].base.repository.get_object_content('aiida_lammps.out') +``` diff --git a/docs/source/tutorials/include/scripts/run_md_basic.py b/docs/source/tutorials/include/scripts/run_md_basic.py new file mode 100755 index 00000000..34f01794 --- /dev/null +++ b/docs/source/tutorials/include/scripts/run_md_basic.py @@ -0,0 +1,96 @@ +#!/usr/bin/env runaiida +import io + +from aiida.engine import run +from aiida.orm import Dict, StructureData, load_code +from ase.build import bulk +import requests + +from aiida_lammps.data.potential import LammpsPotentialData + +# Load the code configured for ``lmp``. Make sure to replace +# this string with the label used in the code setup. +code = load_code("lammps@localhost") +builder = code.get_builder() + +structure = StructureData(ase=bulk("Fe", "bcc", 2.87, cubic=True)) +builder.structure = structure + +# Download the potential from the repository and store it as a BytesIO object +_stream = io.BytesIO( + requests.get( + "https://openkim.org/files/MO_546673549085_000/Fe_2.eam.fs", timeout=20 + ).text.encode("ascii") +) + +# Set the metadata for the potential +potential_parameters = { + "species": ["Fe"], + "atom_style": "atomic", + "pair_style": "eam/fs", + "units": "metal", + "extra_tags": { + "title": "EAM potential (LAMMPS cubic hermite tabulation) for Fe developed by Mendelev et al. (2003) v000", + "content_origin": "NIST IPRP: https: // www.ctcms.nist.gov/potentials/Fe.html", + "developer": ["Ronald E. Miller"], + "publication_year": 2018, + }, +} + +# Store the potential in an AiiDA node +potential = LammpsPotentialData.get_or_create(source=_stream, **potential_parameters) + +builder.potential = potential + +parameters = Dict( + { + "control": {"units": "metal", "timestep": 1e-5}, + "compute": { + "pe/atom": [{"type": [{"keyword": " ", "value": " "}], "group": "all"}], + "ke/atom": [{"type": [{"keyword": " ", "value": " "}], "group": "all"}], + "stress/atom": [{"type": ["NULL"], "group": "all"}], + "pressure": [{"type": ["thermo_temp"], "group": "all"}], + }, + "structure": {"atom_style": "atomic"}, + "thermo": { + "printing_rate": 100, + "thermo_printing": { + "step": True, + "pe": True, + "ke": True, + "press": True, + "pxx": True, + "pyy": True, + "pzz": True, + }, + }, + "md": { + "integration": { + "style": "npt", + "constraints": { + "temp": [300, 300, 100], + "iso": [0.0, 0.0, 1000.0], + }, + }, + "max_number_steps": 5000, + "velocity": [{"create": {"temp": 300}, "group": "all"}], + }, + } +) +builder.parameters = parameters + +builder.metadata.options = { + "resources": { + "num_machines": 1, + }, + "max_wallclock_seconds": 1800, + "withmpi": False, +} + +results, node = run.get_node(builder) + +print( + f"Calculation: {node.process_class}<{node.pk}> {node.process_state.value} [{node.exit_status}]" +) +print(f"Results: {results}") +assert node.is_finished_ok, f"{node} failed: [{node.exit_status}] {node.exit_message}" diff --git a/docs/source/tutorials/include/scripts/run_minimization_basic.py b/docs/source/tutorials/include/scripts/run_minimization_basic.py new file mode 100755 index 00000000..79a3b0ae --- /dev/null +++ b/docs/source/tutorials/include/scripts/run_minimization_basic.py @@ -0,0 +1,92 @@ +#!/usr/bin/env runaiida +import io + +from aiida.engine import run +from aiida.orm import Dict, StructureData, load_code +from ase.build import bulk +import requests + +from aiida_lammps.data.potential import LammpsPotentialData + +# Load the code configured for ``lmp``. Make sure to replace +# this string with the label used in the code setup. +code = load_code("lammps@localhost") +builder = code.get_builder() + +structure = StructureData(ase=bulk("Fe", "bcc", 2.87, cubic=True)) +builder.structure = structure + +# Download the potential from the repository and store it as a BytesIO object +_stream = io.BytesIO( + requests.get( + "https://openkim.org/files/MO_546673549085_000/Fe_2.eam.fs", timeout=20 + ).text.encode("ascii") +) + +# Set the metadata for the potential +potential_parameters = { + "species": ["Fe"], + "atom_style": "atomic", + "pair_style": "eam/fs", + "units": "metal", + "extra_tags": { + "title": "EAM potential (LAMMPS cubic hermite tabulation) for Fe developed by Mendelev et al. (2003) v000", + "content_origin": "NIST IPRP: https: // www.ctcms.nist.gov/potentials/Fe.html", + "developer": ["Ronald E. Miller"], + "publication_year": 2018, + }, +} + +# Store the potential in an AiiDA node +potential = LammpsPotentialData.get_or_create(source=_stream, **potential_parameters) + +builder.potential = potential + +parameters = Dict( + { + "control": {"units": "metal", "timestep": 1e-5}, + "compute": { + "pe/atom": [{"type": [{"keyword": " ", "value": " "}], "group": "all"}], + "ke/atom": [{"type": [{"keyword": " ", "value": " "}], "group": "all"}], + "stress/atom": [{"type": ["NULL"], "group": "all"}], + "pressure": [{"type": ["thermo_temp"], "group": "all"}], + }, + "structure": {"atom_style": "atomic"}, + "thermo": { + "printing_rate": 100, + "thermo_printing": { + "step": True, + "pe": True, + "ke": True, + "press": True, + "pxx": True, + "pyy": True, + "pzz": True, + }, + }, + "minimize": { + "style": "cg", + "energy_tolerance": 1e-4, + "force_tolerance": 1e-4, + "max_iterations": 1000, + "max_evaluations": 1000, + }, + } +) +builder.parameters = parameters + +builder.metadata.options = { + "resources": { + "num_machines": 1, + }, + "max_wallclock_seconds": 1800, + "withmpi": False, +} + +results, node = run.get_node(builder) + +print( + f"Calculation: {node.process_class}<{node.pk}> {node.process_state.value} [{node.exit_status}]" +) +print(f"Results: {results}") +assert node.is_finished_ok, f"{node} failed: [{node.exit_status}] {node.exit_message}" diff --git a/docs/source/tutorials/include/scripts/run_raw_basic.py b/docs/source/tutorials/include/scripts/run_raw_basic.py new file mode 100755 index 00000000..a0b39c78 --- /dev/null +++ b/docs/source/tutorials/include/scripts/run_raw_basic.py @@ -0,0 +1,69 @@ +#!/usr/bin/env runaiida +"""Run a LAMMPS calculation with additional input files + +The example input script is taken from https://www.lammps.org/inputs/in.rhodo.txt and is an example benchmark script for +the official benchmarks of LAMMPS. It is a simple MD simulation of a protein. It requires an additional input file in +the working directory ``data.rhodo``. This example shows how to add such additional input files. +""" +import io +import textwrap + +from aiida import engine +from aiida.orm import SinglefileData, load_code +from aiida.plugins import CalculationFactory +import requests + +script = SinglefileData( + io.StringIO( + textwrap.dedent( + """ + # Rhodopsin model + + units real + neigh_modify delay 5 every 1 + + atom_style full + bond_style harmonic + angle_style charmm + dihedral_style charmm + improper_style harmonic + pair_style lj/charmm/coul/long 8.0 10.0 + pair_modify mix arithmetic + kspace_style pppm 1e-4 + + read_data data.rhodo + + fix 1 all shake 0.0001 5 0 m 1.0 a 232 + fix 2 all npt temp 300.0 300.0 100.0 & + z 0.0 0.0 1000.0 mtk no pchain 0 tchain 1 + + special_bonds charmm + + thermo 50 + thermo_style multi + timestep 2.0 + + run 100 + """ + ) + ) +) +request = requests.get( + "https://raw.githubusercontent.com/lammps/lammps/develop/bench/data.rhodo", + timeout=20, +) +data = SinglefileData(io.StringIO(request.text)) + +builder = CalculationFactory("lammps.raw").get_builder() +builder.code = load_code("lammps@localhost") +builder.script = script +builder.files = {"data": data} +builder.filenames = {"data": "data.rhodo"} +builder.metadata.options = {"resources": {"num_machines": 1}} +results, node = engine.run_get_node(builder) + +print( + f"Calculation: {node.process_class}<{node.pk}> {node.process_state.value} [{node.exit_status}]" +) +print(f"Results: {results}") +assert node.is_finished_ok, f"{node} failed: [{node.exit_status}] {node.exit_message}" diff --git a/docs/source/tutorials/index.md b/docs/source/tutorials/index.md new file mode 100644 index 00000000..d384982d --- /dev/null +++ b/docs/source/tutorials/index.md @@ -0,0 +1,76 @@ +(tutorials)= +# Tutorials + +:::{important} +Before working with the tutorial, the following steps need to have been performed: + +- installation of the `aiida-lammps` plugin ([see the instructions](#getting_started-installation)) +- configure the `LAMMPS` code ([see the instructions](#getting_started-setup-code)) +::: +```{toctree} +:hidden: true +:maxdepth: 1 + +first_relaxation +first_md +first_raw +``` + +:::{card} +:class-header: panel-header-text +:class-footer: tutor-footer +:link: tutorials-minimization +:link-type: ref +:margin: 4 + +{fa}`fa-regular fa-rocket` Running your first minimization calculation. +^^^ +Learn how to run a LAMMPS minimization with AiiDA, using the Python API. ++++ +::::{list-table} +:class: footer-table +:widths: 50 50 +* - {fa}`fa-sharp fa-regular fa-clock` 30 min + - {{ aiida_logo }} [Beginner]{.aiida-green} +:::: +::: + + +:::{card} +:class-header: panel-header-text +:class-footer: tutor-footer +:link: tutorials-md +:link-type: ref +:margin: 4 + +{fa}`fa-solid fa-atom` Molecular dynamics +^^^ +Learn how to run a LAMMPS molecular dynamics calculation. ++++ +::::{list-table} +:class: footer-table +:widths: 50 50 +* - {fa}`fa-sharp fa-regular fa-clock` 20 min + - {{ aiida_logo }} [Beginner]{.aiida-green} +:::: +::: + + +:::{card} +:class-header: panel-header-text +:class-footer: tutor-footer +:link: tutorials-raw +:link-type: ref +:margin: 4 + +{fa}`fa-solid fa-file-lines` Raw calculation +^^^ +Learn how to run a raw LAMMPS calculation based on an input file. ++++ +::::{list-table} +:class: footer-table +:widths: 50 50 +* - {fa}`fa-sharp fa-regular fa-clock` 20 min + - {{ aiida_logo }} [Beginner]{.aiida-green} +:::: +::: diff --git a/docs/source/users/example_md.md b/docs/source/users/example_md.md deleted file mode 100644 index 4bca9feb..00000000 --- a/docs/source/users/example_md.md +++ /dev/null @@ -1,188 +0,0 @@ -# Molecular dynamics simulations - -``LAMMPS`` is widely used to perform molecular dynamics simulations, these can be codified in an ``aiida-lammps`` process by submitting a ``Calculation`` with the correct ``parameters``. - -## Parameters setup -To run a MD simulation, one needs to define a dictionary named ``md`` inside the parameters dictionary (which controls the ``LAMMPS`` simulation). The ``md`` dictionary defines the options that control how the molecular dynamics simulations are performed, several entries are needed to fully control its behavior: -* ``max_number_steps``: maximum number of steps for the molecular dynamics simulation (default: 100) -* ``run_style``: type of molecular dynamics algorithm (default: ``verlet``). -* ``velocity``: set of variables needed to define the [velocity](https://docs.lammps.org/velocity.html) of the system. -* ``integration``: parameters relating to the integrators of the molecular dynamics simulation: - - ``style``: Type of [integrator](https://docs.lammps.org/fixes.html) used for the molecular dynamics simulation. In this example the chosen integrator is [npt](https://docs.lammps.org/fix_nh.html#fix-npt-command), which requires that one at leasts sets the temperature of the simulation box, one can also setup the pressure which acts over the simulation box. These parameters called ``constraints`` are set in another entry of the ``integration`` dictionary. - - ``constraints``: set of options for each integrator, the values depend on the type of integrator. This dictionary takes as keys the options available for the ``npt`` integrator, in this case the values ``temp`` for the temperature and ``iso`` for the barostat. The values for each key in the dictionary are lists which contain each one of the values that one would normally add besides these commands in the ``LAMMPS`` input. - -```{code-block} python -from aiida import orm -from aiida.common.extendeddicts import AttributeDict - -parameters = AttributeDict() -parameters.control = AttributeDict() -parameters.control.units = 'metal' -parameters.control.timestep = 1e-5 -parameters.compute = { - 'pe/atom': [{ - 'type': [{ - 'keyword': ' ', - 'value': ' ' - }], - 'group': 'all' - }], - 'ke/atom': [{ - 'type': [{ - 'keyword': ' ', - 'value': ' ' - }], - 'group': 'all' - }], - 'stress/atom': [{ - 'type': ['NULL'], - 'group': 'all' - }], - 'pressure': [{ - 'type': ['thermo_temp'], - 'group': 'all' - }], -} -parameters.md = { - 'integration': { - 'style': 'npt', - 'constraints': { - 'temp': [300, 300, 100], - 'iso': [0.0, 0.0, 1000.0], - } - }, - 'max_number_steps': 5000, - 'velocity': [{ - 'create': { - 'temp': 300 - }, - 'group': 'all' - }] -} -parameters.structure = {'atom_style': 'atomic'} -parameters.thermo = { - 'printing_rate': 100, - 'thermo_printing': { - 'step': True, - 'pe': True, - 'ke': True, - 'press': True, - 'pxx': True, - 'pyy': True, - 'pzz': True, - } -} -parameters.dump = {'dump_rate': 1000} - -PARAMETERS = orm.Dict(dict=parameters) -``` - -## Structure setup -In this case the structure to be used is bcc Fe, with a basis of two atoms, one can use the ``kind_name`` property for each site in the ``orm.StructureData`` to differentiate the two Fe atoms, that will allow ``aiida-lammps`` to define two possible ``groups`` so that computes, fixes, etc. can be applied individually to each of the atoms. - -```{code-block} python -import numpy as np -from aiida import orm - -def generate_structure() -> orm.StructureData: - """ - Generates the structure for the calculation. - - It will create a bcc structure in a square lattice. - - :return: structure to be used in the calculation - :rtype: orm.StructureData - """ - - cell = [ - [2.848116, 0.000000, 0.000000], - [0.000000, 2.848116, 0.000000], - [0.000000, 0.000000, 2.848116], - ] - - positions = [ - (0.0000000, 0.0000000, 0.0000000), - (0.5000000, 0.5000000, 0.5000000), - ] - fractional = True - - symbols = ['Fe', 'Fe'] - names = ['Fe1', 'Fe2'] - - structure = orm.StructureData(cell=cell) - for position, symbol, name in zip(positions, symbols, names): - if fractional: - position = np.dot(position, cell).tolist() - structure.append_atom(position=position, symbols=symbol, name=name) - - return structure -``` - - -## Potential setup -When dealing with a new potential that one wishes to use for a simulation one can upload a potential by using the ``get_or_create`` method in the ``LammpsPotentialData``, this method will calculate the ``md5`` checksum of the file and check if exists in the database, if it does that database entry is used, otherwise the file it is uploaded into the database and the used in the simulation. To make the potential easy to find and reuse one can pass a series of optional tags based of the [OpenKIM schema](https://openkim.org/doc/schema/kimspec/), which will provide a systematic way of tagging and finding potentials. - -```{code-block} python -from aiida_lammps.data.potential import LammpsPotentialData - -def generate_potential() -> LammpsPotentialData: - """ - Generate the potential to be used in the calculation. - - Takes a potential form OpenKIM and stores it as a LammpsPotentialData object. - - :return: potential to do the calculation - :rtype: LammpsPotentialData - """ - - potential_parameters = { - 'species': ['Fe'], - 'atom_style': 'atomic', - 'pair_style': 'eam/fs', - 'units': 'metal', - 'extra_tags': { - 'content_origin': - 'NIST IPRP: https: // www.ctcms.nist.gov/potentials/Fe.html', - 'content_other_locations': - None, - 'data_method': - 'unknown', - 'description': """ - This Fe EAM potential parameter file is from the NIST repository, \"Fe_2.eam.fs\" as of the March 9, 2009 update. It is similar to \"Fe_mm.eam.fs\" in the LAMMPS distribution dated 2007-06-11, but gives different results for very small interatomic distances (The LAMMPS potential is in fact the deprecated potential referred to in the March 9, 2009 update on the NIST repository). The file header includes a note from the NIST contributor: \"The potential was taken from v9_4_bcc (in C:\\SIMULATION.MD\\Fe\\Results\\ab_initio+Interstitials)\" - """, - 'developer': ['Ronald E. Miller'], - 'disclaimer':""" - According to the developer Giovanni Bonny (as reported by the NIST IPRP), this potential was not stiffened and cannot be used in its present form for collision cascades. - """, - 'properties': - None, - 'publication_year': - 2018, - 'source_citations': [{ - 'abstract': None, - 'author': - 'Mendelev, MI and Han, S and Srolovitz, DJ and Ackland, GJ and Sun, DY and Asta, M', - 'doi': '10.1080/14786430310001613264', - 'journal': '{Phil. Mag.}', - 'number': '{35}', - 'pages': '{3977-3994}', - 'recordkey': 'MO_546673549085_000a', - 'recordprimary': 'recordprimary', - 'recordtype': 'article', - 'title': - '{Development of new interatomic potentials appropriate for crystalline and liquid iron}', - 'volume': '{83}', - 'year': '{2003}' - }], - 'title': - 'EAM potential (LAMMPS cubic hermite tabulation) for Fe developed by Mendelev et al. (2003) v000' - } - } - - potential = LammpsPotentialData.get_or_create( - source='Fe_2.eam.fs', - **potential_parameters, - ) - - return potential -``` diff --git a/docs/source/users/example_minimize.md b/docs/source/users/example_minimize.md deleted file mode 100644 index 2a8d76b9..00000000 --- a/docs/source/users/example_minimize.md +++ /dev/null @@ -1,178 +0,0 @@ -# Minimization simulations - -``LAMMPS`` is widely used to perform minimization simulations, these can be codified in an ``aiida-lammps`` process by submitting a ``Calculation`` with the correct ``parameters``. - -## Parameters setup -To run a minimization simulation, one needs to define a dictionary named ``minimization`` inside the parameters dictionary (which controls the ``LAMMPS`` simulation). The ``minimize`` dictionary defines the options that control how the minimization simulations are performed, several entries are needed to fully control its behavior: -* ``style``: [Algorithm](https://docs.lammps.org/min_style.html) used for the minimization (default: ``cg``). -* ``energy_tolerance``: energy tolerance used to determine if the minimization is successful. -* ``force_tolerance``: force tolerance used to determine if the minimization is successful. -* ``max_iterations``: maximum number of iterations of the minimizer. -* ``max_evaluations``: maximum number of evaluations of the force/energy. - -```{code-block} python -from aiida import orm -from aiida.common.extendeddicts import AttributeDict - -parameters = AttributeDict() -parameters.control = AttributeDict() -parameters.control.units = 'metal' -parameters.control.timestep = 1e-5 -parameters.compute = { - 'pe/atom': [{ - 'type': [{ - 'keyword': ' ', - 'value': ' ' - }], - 'group': 'all' - }], - 'ke/atom': [{ - 'type': [{ - 'keyword': ' ', - 'value': ' ' - }], - 'group': 'all' - }], - 'stress/atom': [{ - 'type': ['NULL'], - 'group': 'all' - }], - 'pressure': [{ - 'type': ['thermo_temp'], - 'group': 'all' - }], -} -parameters.minimize = { - 'style': 'cg', - 'energy_tolerance': 1e-4, - 'force_tolerance': 1e-4, - 'max_iterations': 1000, - 'max_evaluations': 1000, -} -parameters.structure = {'atom_style': 'atomic'} -parameters.thermo = { - 'printing_rate': 100, - 'thermo_printing': { - 'step': True, - 'pe': True, - 'ke': True, - 'press': True, - 'pxx': True, - 'pyy': True, - 'pzz': True, - } -} -parameters.dump = {'dump_rate': 1000} - -PARAMETERS = orm.Dict(dict=parameters) -``` - -## Structure setup -In this case the structure to be used is bcc Fe, with a basis of two atoms, one can use the ``kind_name`` property for each site in the ``orm.StructureData`` to differentiate the two Fe atoms, that will allow ``aiida-lammps`` to define two possible ``groups`` so that computes, fixes, etc. can be applied individually to each of the atoms. - -```{code-block} python -import numpy as np -from aiida import orm - -def generate_structure() -> orm.StructureData: - """ - Generates the structure for the calculation. - - It will create a bcc structure in a square lattice. - - :return: structure to be used in the calculation - :rtype: orm.StructureData - """ - - cell = [ - [2.848116, 0.000000, 0.000000], - [0.000000, 2.848116, 0.000000], - [0.000000, 0.000000, 2.848116], - ] - - positions = [ - (0.0000000, 0.0000000, 0.0000000), - (0.5000000, 0.5000000, 0.5000000), - ] - fractional = True - - symbols = ['Fe', 'Fe'] - names = ['Fe1', 'Fe2'] - - structure = orm.StructureData(cell=cell) - for position, symbol, name in zip(positions, symbols, names): - if fractional: - position = np.dot(position, cell).tolist() - structure.append_atom(position=position, symbols=symbol, name=name) - - return structure -``` - - -## Potential setup -When dealing with a new potential that one wishes to use for a simulation one can upload a potential by using the ``get_or_create`` method in the ``LammpsPotentialData``, this method will calculate the ``md5`` checksum of the file and check if exists in the database, if it does that database entry is used, otherwise the file it is uploaded into the database and the used in the simulation. To make the potential easy to find and reuse one can pass a series of optional tags based of the [OpenKIM schema](https://openkim.org/doc/schema/kimspec/), which will provide a systematic way of tagging and finding potentials. - -```{code-block} python -from aiida_lammps.data.potential import LammpsPotentialData - -def generate_potential() -> LammpsPotentialData: - """ - Generate the potential to be used in the calculation. - - Takes a potential form OpenKIM and stores it as a LammpsPotentialData object. - - :return: potential to do the calculation - :rtype: LammpsPotentialData - """ - - potential_parameters = { - 'species': ['Fe'], - 'atom_style': 'atomic', - 'pair_style': 'eam/fs', - 'units': 'metal', - 'extra_tags': { - 'content_origin': - 'NIST IPRP: https: // www.ctcms.nist.gov/potentials/Fe.html', - 'content_other_locations': - None, - 'data_method': - 'unknown', - 'description': """ - This Fe EAM potential parameter file is from the NIST repository, \"Fe_2.eam.fs\" as of the March 9, 2009 update. It is similar to \"Fe_mm.eam.fs\" in the LAMMPS distribution dated 2007-06-11, but gives different results for very small interatomic distances (The LAMMPS potential is in fact the deprecated potential referred to in the March 9, 2009 update on the NIST repository). The file header includes a note from the NIST contributor: \"The potential was taken from v9_4_bcc (in C:\\SIMULATION.MD\\Fe\\Results\\ab_initio+Interstitials)\" - """, - 'developer': ['Ronald E. Miller'], - 'disclaimer':""" - According to the developer Giovanni Bonny (as reported by the NIST IPRP), this potential was not stiffened and cannot be used in its present form for collision cascades. - """, - 'properties': - None, - 'publication_year': - 2018, - 'source_citations': [{ - 'abstract': None, - 'author': - 'Mendelev, MI and Han, S and Srolovitz, DJ and Ackland, GJ and Sun, DY and Asta, M', - 'doi': '10.1080/14786430310001613264', - 'journal': '{Phil. Mag.}', - 'number': '{35}', - 'pages': '{3977-3994}', - 'recordkey': 'MO_546673549085_000a', - 'recordprimary': 'recordprimary', - 'recordtype': 'article', - 'title': - '{Development of new interatomic potentials appropriate for crystalline and liquid iron}', - 'volume': '{83}', - 'year': '{2003}' - }], - 'title': - 'EAM potential (LAMMPS cubic hermite tabulation) for Fe developed by Mendelev et al. (2003) v000' - } - } - - potential = LammpsPotentialData.get_or_create( - source='Fe_2.eam.fs', - **potential_parameters, - ) - - return potential -``` diff --git a/docs/source/users/get_started.md b/docs/source/users/get_started.md deleted file mode 100644 index b08de3a7..00000000 --- a/docs/source/users/get_started.md +++ /dev/null @@ -1,180 +0,0 @@ -# Getting started - -In a traditional ``LAMMPS`` calculation a user has an input file which is sequentially read by the executable, each line has a command specifying what actions will be taken, usually the potential is kept as a separate file which is then referred to in the input file. - -``aiida-lammps`` generates the necessary inputs by taking three principal data types, namely the ``structure``, the ``potential`` and the ``parameters``, which decribe the simulation box, the interaction parameters between the atoms and the parameters needed to construct the input file (which kind of simulation, which computes/fixes, etc.) respectively. - -## Structure - -The structure is the simulation box that will be used for the simulation. The data structure must be of an `~:code:aiida.orm.StructureData` type. - -```{note} -``LAMMPS`` can in principle generate the structure internally, but this is not supported by the input generator that is shipped with the plugin. One can instead if necessary run the entire calculation only giving a ``LAMMPS`` input file. -``` - -```{note} - LAMMPS requires the simulation cell to be in the format of a lower triangular matrix (right-handed basis). Therefore the cell and positions may require [rotation and inversion](https://lammps.sandia.gov/doc/Howto_triclinic.html). This is **automatically** done to **every structure** at the calculation level, so it might be that the cell that is provided is modified so that it follows this convention. However, this is just a different representation of the cell, its symmetry group, should remain unchanged in this process. -``` - -## Potential - -The potential is one of the most important pieces of data in a MD simulation, since it controls how the atoms interact with each other. -In ``aiida-lammps`` the potential file is stored in the `LammpsPotentialData` data type, which will store the entire potential file in the database, and add certain attributes so that the data node is easily queryable for later usage. These attributes have been chosen so that they resemble the [OpenKIM](https://openkim.org/doc/schema/kimspec/) standard as much as possible. - -To demonstrate how this works one can [download](https://openkim.org/id/EAM_Dynamo_Mendelev_2003_Fe__MO_546673549085_000) a potential from the OpenKIM database, after the file has been downloaded one can generate a dictionary with the metadata of the potential to tag it in the ``AiiDA`` database. - -```{code-block} python -potential_parameters = { - 'species': ['Fe'], # Which species can be treated by this potential (required) - 'atom_style': 'atomic', # Which kind of atomic style is associated with this potential (required) - 'pair_style': 'eam/fs', # LAMMPS pair style (required) - 'units': 'metal', # Default units of this potential (required) - 'extra_tags': { - 'content_origin': 'NIST IPRP: https: // www.ctcms.nist.gov/potentials/Fe.html', # Where the file was original found - 'content_other_locations': None, # If the file can be found somewhere else - 'data_method': 'unknown', # How was the data generated - 'description': """ - This Fe EAM potential parameter file is from the NIST repository, \"Fe_2.eam.fs\" as of the March 9, 2009 update. - It is similar to \"Fe_mm.eam.fs\" in the LAMMPS distribution dated 2007-06-11, - but gives different results for very small interatomic distances - (The LAMMPS potential is in fact the deprecated potential referred to in the March 9, 2009 update on the NIST repository). - The file header includes a note from the NIST contributor: - \"The potential was taken from v9_4_bcc (in C:\\SIMULATION.MD\\Fe\\Results\\ab_initio+Interstitials)\" - """, # Short description of the potential - 'developer': ['Ronald E. Miller'], # Name of the developer that uploaded it to OpenKIM - 'disclaimer': """ - According to the developer Giovanni Bonny (as reported by the NIST IPRP), - this potential was not stiffened and cannot be used in its present form for collision cascades. - """, # Any known issues with the potential - 'properties': None, # If any specific properties are associated to the potential - 'publication_year': 2018, # Year of publication to OpenKIM - 'source_citations': [{ - 'abstract': None, - 'author': - 'Mendelev, MI and Han, S and Srolovitz, DJ and Ackland, GJ and Sun, DY and Asta, M', - 'doi': '10.1080/14786430310001613264', - 'journal': '{Phil. Mag.}', - 'number': '{35}', - 'pages': '{3977-3994}', - 'recordkey': 'MO_546673549085_000a', - 'recordprimary': 'recordprimary', - 'recordtype': 'article', - 'title': - '{Development of new interatomic potentials appropriate for crystalline and liquid iron}', - 'volume': '{83}', - 'year': '{2003}' - }], - 'title': 'EAM potential (LAMMPS cubic hermite tabulation) for Fe developed by Mendelev et al. (2003) v000' # Title of the potential - } -} -``` -Certain tags are required, and must be provided to be able to upload the potential to the database. This is because they identify which ``pair_style`` is associated with the potential, which atomic species can be treated with it, etc. The rest of the tags, in this example are filled so that they follow the [OpenKIM](https://openkim.org/doc/schema/kimspec/) standard as that is the place where the potential was obtained. If another database is used or if it is a homemade potential, these tags can be used to facilitate the querying of the potential. - -Then the potential can be uploaded to the database -```{code-block} python -from aiida_lamps.data.potential import LammpsPotentialData - -potential = LammpsPotentialData.get_or_create( - source='Fe_2.eam.fs', # Relative path to the potential file - **potential_parameters, # Parameters to tag the potential -) - -``` - -The ``get_or_create`` method is based on the one by [aiida-pseudo](https://github.com/aiidateam/aiida-pseudo/blob/master/aiida_pseudo/data/pseudo/pseudo.py), which will calculate the md5 sum of the file and check the database for another file with the same [md5 hash](https://en.wikipedia.org/wiki/MD5), if such entry is found, that potential is used instead. This avoids the unnecessary replication of potential data nodes whenever one tries to upload a previously uploaded potential. - -```{note} -When calculating the md5 hash the program will look at the contents of the file, so that even if a minor change is done (that should not affect the result of a calculation), the checksum will be different and hence a new potential node will be created. -``` - -### Potentials without files -In ``LAMMPS`` certain [pair_style](https://docs.lammps.org/pair_style.html) such as the Lenard-Johns potential do not read their parameters from an auxiliary file, if not they are directly written to the main input file. In ``aiida-lammps`` to standardize the potential storage in the database these kinds of potentials are expected to be also be stored as a file. The format expected for these kinds of potentials is simply the coefficients that one would normally write the in the ``LAMMPS`` input file. The input file generator will then generate the necessary lines for the input file depending on the potential ``pair_style``. - - -### Potentials with multiple files -In ``LAMMPS`` it is in principle possible to give several potential files to treat different atoms. Currently this is **not** supported in the plugin. As only one potential file can be give as to treat the entire system. This is a situation that is aimed to be solved in future releases. - -## Parameters -The behavior of the ``aiida-lammps`` calculation can be controlled by collecting ``LAMMPS`` simulation parameters in a dictionary - -```{code-block} python -parameters = { - 'md': { - 'velocity': [{'group': 'all', 'create': {'temp': 300}}], - 'integration': { - 'style': 'npt', - 'constraints': {'iso': [0.0, 0.0, 1000.0], 'temp': [300, 300, 100]} - }, - 'max_number_steps': 5000 - }, - 'dump': {'dump_rate': 1000}, - 'thermo': { - 'printing_rate': 100, - 'thermo_printing': { - 'ke': True, - 'pe': True, - 'pxx': True, - 'pyy': True, - 'pzz': True, - 'step': True, - 'press': True - } - }, - 'compute': { - 'ke/atom': [{'type': [{'value': ' ', 'keyword': ' '}], 'group': 'all'}], - 'pe/atom': [{'type': [{'value': ' ', 'keyword': ' '}], 'group': 'all'}], - 'pressure': [{'type': ['thermo_temp'], 'group': 'all'}], - 'stress/atom': [{'type': ['NULL'], 'group': 'all'}] - }, - 'control': {'units': 'metal', 'timestep': 1e-05}, - 'structure': {'atom_style': 'atomic'} -} -``` - -The dictionary is separated into several nested dictionaries that control different behaviors of the ``LAMMPS`` simulation: -- ``control``: takes keywords specifying global simulation parameters: - * ``units``: ``LAMMPS`` [units](https://docs.lammps.org/units.html) used in the calculation (default: ``si``). - * ``timestep``: [time step](https://docs.lammps.org/timestep.html) used in the simulation, it depends on the units used (default: ``LAMMPS`` default dependent on units parameter). - * ``newton``: it controls whether the Newton's third law is [turned on or off](https://docs.lammps.org/newton.html) for the calculation (default: ``on``). - * ``processors``: specifies how [processors](https://docs.lammps.org/processors.html) are mapped to the simulation box (default: ignore the command). -- ``structure``: variables controlling structure options: - * ``box_tilt``: determines how [skewed the cell](https://docs.lammps.org/box.html) is, of great importance for triclinic systems (default: ``small``). - * ``groups``: list with the names of the groups to be added. The names of the possible groups are generated by the list of possible kind names generated by the structure (default: skip parameter). - * ``atom_style``: how the [atoms](https://docs.lammps.org/atom_style.html) are treated by the ``LAMMPS`` simulation. -- ``potential``: parameters related to the potential describing the system: - * ``potential_style_options``: extra parameters related to each of the possible pair styles (default: skip parameter). - * ``neighbor``: sets the parameters affecting the construction of the [neighbor list](https://docs.lammps.org/neighbor.html) (default: skip parameter). - * ``neighbor_modify``: set of options that [modify](https://docs.lammps.org/neigh_modify.html) the pairwise neighbor list generation (default: skip parameter). -- ``dump``: controls parameters regarding the printing of the site dependent quantities: - * ``dump_rate``: how often are the site dependent quantities printed to file (default: 10). -- ``compute``: set of lists containing information about which ``LAMMPS`` [computes](https://docs.lammps.org/compute.html) should be calculated. For each ``LAMMPS`` command one passes a list of dictionaries, each dictionary has a ``type`` key containing the options of the compute and ``group`` a key specifying over which group the compute is acting on. -- ``fix``: set of list containing information about which ``LAMMPS`` [fixes](https://docs.lammps.org/fix.html) should be calculated. For each ``LAMMPS`` command one passes a list of dictionaries, each dictionary has a ``type`` key containing the options of the fixes and ``group`` a key specifying over which group the fix is acting on. -- ``thermo``: set of variables indicating which global parameters (printed in the ``lammps.out``) should be printed: - * ``printing_rate``: how often should the parameters be written to the ``lammps.out`` (default: 1000) - * ``thermo_printing``: dictionary containing which ``LAMMPS`` internal [variables](https://docs.lammps.org/thermo_style.html) are printed to the ``lammps.out``. The keys are the names of ``LAMMPS`` parameters and the value is a boolean on whether to print it or not. -- ``md``: set of variables controlling a molecular dynamics simulation (exclusionary with ``minimize`` key word): - * ``max_number_steps``: maximum number of steps for the molecular dynamics simulation (default: 100) - * ``run_style``: type of molecular dynamics algorithm (default: ``verlet``). - * ``velocity``: set of variables needed to define the [velocity](https://docs.lammps.org/velocity.html) of the system. - * ``integration``: parameters relating to the integrators of the molecular dynamics simulation: - - ``style``: Type of [integrator](https://docs.lammps.org/fixes.html) used for the molecular dynamics simulation. - - ``constraints``: set of options for each integrator, the values depend on the type of integrator. -- ``minimize``: set of variables controlling a minimization simulation (exclusionary with ``md`` key word): - * ``style``: [type of minimization](https://docs.lammps.org/min_style.html) algorithm (default: ``cg``). - * ``energy_tolerance``: tolerance for the energy minimization (default: 1e-4). - * ``force_tolerance``: tolerance for the force minimization (default: 1e-4). - * ``max_iterations``: maximum number of iterations (default: 1000). - * ``max_evaluations``: maximum number of evaluations (default: 1000). -- ``restart``: set of variables controlling the printing of the binary file to [restart](https://docs.lammps.org/Howto_restart.html) a ``LAMMPS`` calculation. - * ``print_final``: whether or not to print a restart file at the end of the calculation, equivalent to setting [write_restart](https://docs.lammps.org/write_restart.html) at the end of the calculation (default: ``False``). - * ``print_intermediate``: whether or not to print restart files throughout the run at regular intervals, equivalent to the [restart](https://docs.lammps.org/restart.html) ``LAMMPS`` command (default: ``False``). - * ``num_steps``: however often the restart file is written if ``print_intermediate`` is used (default: ``max_number_steps*0.1``). - -```{note} -As the restart files can be very large, they are by default not printed, nor stored in the database. Even when one prints them with the ``print_final`` and/or ``print_intermediate`` they are not retrieved and are only kept in the remote folder. The storage of the restart file can be controlled via the ``store_restart=True``(``store_restart=False``) to store(not-store) option in the ``settings`` dictionary. -``` -### Compute parameters -When asking ``aiida-lammps`` to calculate a certain ``compute`` its ``LAMMPS`` name will be automatically generated following the pattern ``compute_name_group_name_aiida`` where ``compute_name`` is the ``LAMMPS`` name of the compute, e.g. ``pe/atom`` with the difference than the ``/`` character is replaced by ``_`` and ``group_name`` is the name of the group to which the compute is applied. All global computes are printed to the ``lammps.out`` and all site dependent quantities are printed to the trajectory file. These computes can then be accessed as outputs of the simulation. - -### Input validation -``LAMMPS`` has a quite large amount of possible parameters which can be passed into it to control its behavior. Many of these options are incompatible which can cause the ``LAMMPS`` simulation to fail. To try to catch as many as possible of these possible conflicts the ``aiida-lammps`` input is validated against a [JSON schema](https://json-schema.org/understanding-json-schema/index.html), that checks that the provided input parameters fulfill this schema as much as possible, e.g. it checks that only ``LAMMPS`` computes can be passed to the ``compute`` block, etc. Due to the large amount and variety of options for each compute/fixes these options are not thoroughly checked, only the name of the compute itself is checked. diff --git a/examples/launch_lammps_base_md.py b/examples/calculations/launch_lammps_md.py similarity index 100% rename from examples/launch_lammps_base_md.py rename to examples/calculations/launch_lammps_md.py diff --git a/examples/launch_lammps_base_minimize.py b/examples/calculations/launch_lammps_minimize.py similarity index 100% rename from examples/launch_lammps_base_minimize.py rename to examples/calculations/launch_lammps_minimize.py diff --git a/examples/launch_lammps_raw_script.py b/examples/launch_lammps_raw_script.py index d87021b8..4dfb3355 100644 --- a/examples/launch_lammps_raw_script.py +++ b/examples/launch_lammps_raw_script.py @@ -8,6 +8,7 @@ import textwrap from aiida import engine, orm, plugins +import requests script = orm.SinglefileData( io.StringIO( @@ -44,22 +45,11 @@ ) ) ) -data = orm.SinglefileData( - io.StringIO( - textwrap.dedent( - """ - LAMMPS data file from restart file: timestep = 5000, procs = 1 - - 32000 atoms - 27723 bonds - 40467 angles - 56829 dihedrals - 1034 impropers - ... - """ - ) - ) +request = requests.get( + "https://raw.githubusercontent.com/lammps/lammps/develop/bench/data.rhodo", + timeout=20, ) +data = SinglefileData(io.StringIO(request.text)) builder = plugins.CalculationFactory("lammps.raw").get_builder() builder.code = orm.load_code("lammps-23.06.2022@localhost") @@ -69,4 +59,4 @@ builder.metadata.options = {"resources": {"num_machines": 1}} _, node = engine.run_get_node(builder) -print(f"Calculation node: {submission_node}") +print(f"Calculation node: {node}") diff --git a/pyproject.toml b/pyproject.toml index 4186731e..0a7c3353 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -36,10 +36,10 @@ Documentation = "https://aiida-lammps.readthedocs.io" Source = "https://github.com/aiidaplugins/aiida-lammps" [project.optional-dependencies] -testing = [ - "attrs>=17.4.0", - "pgtest", - "pytest", +tests = [ + 'pgtest~=1.3', + 'pytest~=6.0', + 'pytest-regressions~=2.3', "pytest-cov", "coverage", "pytest-timeout", @@ -47,15 +47,21 @@ testing = [ ] pre-commit = [ - "aiida-core[pre-commit]~=2.2", - "tox>=3.23.0", - "virtualenv>20" + 'pre-commit~=2.17', + 'pylint~=2.17.2', + 'pylint-aiida~=0.1.1', + 'toml', ] docs = [ - "myst-parser~=0.15.0", - "sphinx-external-toc", - "sphinx-copybutton", + 'sphinx~=6.2.1', + 'sphinx-copybutton~=0.5.2', + 'sphinx-book-theme~=1.0.1', + 'sphinx-click~=4.4.0', + 'sphinx-design~=0.4.1', + 'sphinxcontrib-details-directive~=0.1.0', + 'sphinx-autoapi~=3.0', + 'myst_parser~=1.0.0', "furo" ] @@ -119,7 +125,7 @@ commands = mkdir -p {toxworkdir}/.aiida pytest --lammps-exec lmp_serial {posargs} rm -r {toxworkdir}/.aiida -extras = testing +extras = tests [testenv:pre-commit] allowlist_externals = bash @@ -130,14 +136,20 @@ extras = [testenv:docs-{clean,update}] extras = docs +description = + clean: Build the documentation (remove any existing build) + update: Build the documentation (modify any existing build) +passenv = RUN_APIDOC +setenv = + update: RUN_APIDOC = False +changedir = docs allowlist_externals = + make rm echo commands = - clean: rm -rf docs/_build - clean: rm -rf docs/source/reference/apidoc - sphinx-build -n -W --keep-going -c docs/source docs/source docs/_build -commands_post = echo "open docs/_build/index.html" + clean: make clean + make debug [pytest] addopts = --ignore=setup.py diff --git a/tests/calculations/test_raw.py b/tests/calculations/test_raw.py index 6d4a81fb..2458c64a 100644 --- a/tests/calculations/test_raw.py +++ b/tests/calculations/test_raw.py @@ -1,3 +1,4 @@ +"""Test the `LammpsRawCalculation`""" import io import textwrap @@ -26,12 +27,12 @@ def test_script(generate_calc_job, aiida_local_code_factory): "script": orm.SinglefileData(io.StringIO(content)), } - tmp_path, calc_info = generate_calc_job("lammps.raw", inputs) + tmp_path, _ = generate_calc_job("lammps.raw", inputs) assert (tmp_path / LammpsRawCalculation.FILENAME_INPUT).read_text() == content def test_files_invalid(generate_calc_job, aiida_local_code_factory): - """Test the ``files`` input valdiation. + """Test the ``files`` input validation. The list of filenames that will be used to write to the working directory needs to be unique. """ @@ -81,7 +82,7 @@ def test_files(generate_calc_job, aiida_local_code_factory): def test_filenames_invalid(generate_calc_job, aiida_local_code_factory): - """Test the ``filenames`` input valdiation. + """Test the ``filenames`` input validation. The list of filenames that will be used to write to the working directory needs to be unique. """