From c5c1cb7e3586e81e43f9f48d75bc2e68059b2cbf Mon Sep 17 00:00:00 2001 From: Jonathan Chico Date: Mon, 20 Nov 2023 13:55:51 +0100 Subject: [PATCH] (WIP) Fixing an issue with the building of the documentation via tox. Adding a tutorial for the md and an example. Moving information to the topics related to the data. --- .github/workflows/cd.yml | 4 +- docs/Makefile | 8 +- docs/source/developers/{intro.md => index.md} | 0 docs/source/index.md | 8 +- docs/source/reference/api/index.md | 11 + docs/source/topics/data/index.md | 1 + .../data/parameters.md} | 101 +-------- docs/source/topics/data/potential.md | 76 +++++++ docs/source/tutorials/first_md.md | 208 ++++++++++++++++++ .../tutorials/include/scripts/run_md_basic.py | 96 ++++++++ docs/source/users/example_md.md | 188 ---------------- docs/source/users/example_minimize.md | 178 --------------- pyproject.toml | 16 +- 13 files changed, 421 insertions(+), 474 deletions(-) rename docs/source/developers/{intro.md => index.md} (100%) create mode 100644 docs/source/reference/api/index.md rename docs/source/{users/get_started.md => topics/data/parameters.md} (51%) create mode 100755 docs/source/tutorials/include/scripts/run_md_basic.py delete mode 100644 docs/source/users/example_md.md delete mode 100644 docs/source/users/example_minimize.md 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/docs/Makefile b/docs/Makefile index 6b0e93df..365008f5 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -19,9 +19,13 @@ ALLSPHINXOPTS = -n -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) # 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 customdefault +.PHONY: all help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest coverage gettext default -customdefault: +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 diff --git a/docs/source/developers/intro.md b/docs/source/developers/index.md similarity index 100% rename from docs/source/developers/intro.md rename to docs/source/developers/index.md diff --git a/docs/source/index.md b/docs/source/index.md index 2953c6e2..6d1988f4 100644 --- a/docs/source/index.md +++ b/docs/source/index.md @@ -22,6 +22,12 @@ topics/calculations/index topics/workflows/index ``` +```{toctree} +:hidden: true +:caption: Development information +developers/index +``` + ```{toctree} :hidden: true :caption: Reference @@ -96,7 +102,7 @@ In this version a major refactoring of the entire plugin has been done so that r New potential data structures 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. +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 diff --git a/docs/source/reference/api/index.md b/docs/source/reference/api/index.md new file mode 100644 index 00000000..9d0e2520 --- /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 +``` \ No newline at end of file diff --git a/docs/source/topics/data/index.md b/docs/source/topics/data/index.md index 69acd8df..d9caebdf 100644 --- a/docs/source/topics/data/index.md +++ b/docs/source/topics/data/index.md @@ -3,6 +3,7 @@ ```{toctree} :maxdepth: 1 +parameters potential trajectory diff --git a/docs/source/users/get_started.md b/docs/source/topics/data/parameters.md similarity index 51% rename from docs/source/users/get_started.md rename to docs/source/topics/data/parameters.md index b08de3a7..e3e4f4a4 100644 --- a/docs/source/users/get_started.md +++ b/docs/source/topics/data/parameters.md @@ -1,100 +1,5 @@ -# Getting started +# Parameters -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 @@ -173,8 +78,8 @@ The dictionary is separated into several nested dictionaries that control differ ```{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 +## 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 +## 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 index 482a45f9..762f1ad0 100644 --- a/docs/source/topics/data/potential.md +++ b/docs/source/topics/data/potential.md @@ -1 +1,77 @@ # `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 `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. diff --git a/docs/source/tutorials/first_md.md b/docs/source/tutorials/first_md.md index de9def23..a2ea791c 100644 --- a/docs/source/tutorials/first_md.md +++ b/docs/source/tutorials/first_md.md @@ -1,3 +1,211 @@ +--- +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 `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. +::: + +With the potential data and the metadata dictionary one can then generate a `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. + +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(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..f788867c --- /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/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/pyproject.toml b/pyproject.toml index 0741ef7d..e0ce28dc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -136,14 +136,20 @@ extras = [testenv:docs-{clean,update}] extras = docs -allowlist_externals = +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