From c566ddafdfc9b1342a2e5ee280402eb182c73fa1 Mon Sep 17 00:00:00 2001 From: Marnik Bercx Date: Fri, 7 May 2021 02:57:38 +0200 Subject: [PATCH 1/3] Docs: Add first version of documentation --- .gitignore | 2 +- .pre-commit-config.yaml | 6 ++ aiida_pseudo/cli/root.py | 2 +- aiida_pseudo/groups/family/pseudo_dojo.py | 6 +- aiida_pseudo/groups/mixins/cutoffs.py | 5 +- docs/Makefile | 20 ++++ docs/make.bat | 35 +++++++ docs/source/_static/aiida-custom.css | 117 ++++++++++++++++++++++ docs/source/cli.rst | 8 ++ docs/source/conf.py | 68 +++++++++++++ docs/source/design.rst | 109 ++++++++++++++++++++ docs/source/howto.rst | 98 ++++++++++++++++++ docs/source/index.rst | 65 ++++++++++++ docs/source/troubleshooting.rst | 13 +++ setup.json | 6 ++ 15 files changed, 554 insertions(+), 6 deletions(-) create mode 100644 docs/Makefile create mode 100644 docs/make.bat create mode 100644 docs/source/_static/aiida-custom.css create mode 100644 docs/source/cli.rst create mode 100644 docs/source/conf.py create mode 100644 docs/source/design.rst create mode 100644 docs/source/howto.rst create mode 100644 docs/source/index.rst create mode 100644 docs/source/troubleshooting.rst diff --git a/.gitignore b/.gitignore index a4124c6..4aea4b6 100644 --- a/.gitignore +++ b/.gitignore @@ -63,7 +63,7 @@ instance/ .scrapy # Sphinx documentation -docs/_build/ +docs/build/ # PyBuilder target/ diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index c949764..e6fa4ac 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -24,15 +24,21 @@ repos: name: yapf types: [python] args: ['-i'] + exclude: &exclude_files > + (?x)^( + docs/.*| + )$ - repo: https://github.com/PyCQA/pylint rev: pylint-2.6.0 hooks: - id: pylint language: system + exclude: *exclude_files - repo: https://github.com/PyCQA/pydocstyle rev: 5.0.2 hooks: - id: pydocstyle args: ['--ignore=D104,D203,D213'] + exclude: *exclude_files diff --git a/aiida_pseudo/cli/root.py b/aiida_pseudo/cli/root.py index 68b5584..52f0ad8 100644 --- a/aiida_pseudo/cli/root.py +++ b/aiida_pseudo/cli/root.py @@ -8,4 +8,4 @@ @click.group('aiida-pseudo', context_settings={'help_option_names': ['-h', '--help']}) @options.PROFILE(type=types.ProfileParamType(load_profile=True)) def cmd_root(profile): # pylint: disable=unused-argument - """CLI for the `aiida-pseudo` plugin.""" + """CLI for the ``aiida-pseudo`` plugin.""" diff --git a/aiida_pseudo/groups/family/pseudo_dojo.py b/aiida_pseudo/groups/family/pseudo_dojo.py index 536ae54..5747049 100644 --- a/aiida_pseudo/groups/family/pseudo_dojo.py +++ b/aiida_pseudo/groups/family/pseudo_dojo.py @@ -23,10 +23,10 @@ class PseudoDojoFamily(RecommendedCutoffMixin, PseudoPotentialFamily): - """Subclass of `PseudoPotentialFfamily` designed to represent a PseudoDojo configuration. + """Subclass of ``PseudoPotentialFamily`` designed to represent a PseudoDojo configuration. - The `PseudoDojoFamily` is essentially a `PseudoPotentialFfamily` with some additional constraints. It can only be - used to contain the pseudo potentials and corresponding metadata of an official PseudoDojo configuration. + The ``PseudoDojoFamily`` is essentially a ``PseudoPotentialFamily`` with some additional constraints. It can only + be used to contain the pseudo potentials and corresponding metadata of an official PseudoDojo configuration. """ _pseudo_types = (UpfData, PsmlData, Psp8Data, JthXmlData) diff --git a/aiida_pseudo/groups/mixins/cutoffs.py b/aiida_pseudo/groups/mixins/cutoffs.py index 8227431..3d06241 100644 --- a/aiida_pseudo/groups/mixins/cutoffs.py +++ b/aiida_pseudo/groups/mixins/cutoffs.py @@ -35,6 +35,8 @@ def validate_cutoffs(elements: set, cutoffs: dict) -> None: specifies the ``cutoff_wfc`` and ``cutoff_rho`` keys, corresponding a float value with the recommended cutoff to be used for the wave functions and charge density, respectively. For example: + .. code-block:: + { "Ag": { "cutoff_wfc": 50.0, @@ -150,6 +152,8 @@ def set_cutoffs(self, cutoffs: dict, stringency: str, unit: str = None) -> None: specifies the ``cutoff_wfc`` and ``cutoff_rho`` keys, corresponding a float value with the recommended cutoff to be used for the wave functions and charge density, respectively. For example: + .. code-block:: + { "Ag": { "cutoff_wfc": 50.0, @@ -157,7 +161,6 @@ def set_cutoffs(self, cutoffs: dict, stringency: str, unit: str = None) -> None: }, ... } - :param stringency: the stringency corresponding to the provided cutoffs. :param unit: string definition of a unit of energy as recognized by the ``UnitRegistry`` of the ``pint`` lib. Defaults to electronvolt. diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 0000000..d0c3cbf --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,20 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line, and also +# from the environment for the first two. +SPHINXOPTS ?= +SPHINXBUILD ?= sphinx-build +SOURCEDIR = source +BUILDDIR = build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/make.bat b/docs/make.bat new file mode 100644 index 0000000..6247f7e --- /dev/null +++ b/docs/make.bat @@ -0,0 +1,35 @@ +@ECHO OFF + +pushd %~dp0 + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set SOURCEDIR=source +set BUILDDIR=build + +if "%1" == "" goto help + +%SPHINXBUILD% >NUL 2>NUL +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.http://sphinx-doc.org/ + exit /b 1 +) + +%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% +goto end + +:help +%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% + +:end +popd diff --git a/docs/source/_static/aiida-custom.css b/docs/source/_static/aiida-custom.css new file mode 100644 index 0000000..a3ebd1c --- /dev/null +++ b/docs/source/_static/aiida-custom.css @@ -0,0 +1,117 @@ +/* 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; +} diff --git a/docs/source/cli.rst b/docs/source/cli.rst new file mode 100644 index 0000000..6f4dba5 --- /dev/null +++ b/docs/source/cli.rst @@ -0,0 +1,8 @@ + +############# +CLI reference +############# + +.. click:: aiida_pseudo.cli.root:cmd_root + :prog: aiida-pseudo + :nested: full diff --git a/docs/source/conf.py b/docs/source/conf.py new file mode 100644 index 0000000..4b329bf --- /dev/null +++ b/docs/source/conf.py @@ -0,0 +1,68 @@ +# -*- coding: utf-8 -*- +# Configuration file for the Sphinx documentation builder. +# +# This file only contains a selection of the most common options. For a full +# list see the documentation: +# https://www.sphinx-doc.org/en/master/usage/configuration.html + +# -- Path setup -------------------------------------------------------------- + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +# +import os +import sys +sys.path.insert(0, os.path.abspath('../../')) + +import aiida_pseudo + +# -- Project information ----------------------------------------------------- + +project = 'aiida-pseudo' +copyright = '2020-2021, ECOLE POLYTECHNIQUE FEDERALE DE LAUSANNE (Theory and Simulation of Materials (THEOS) and National Centre for Computational Design and Discovery of Novel Materials (NCCR MARVEL)), Switzerland' +release = aiida_pseudo.__version__ + +# -- General configuration --------------------------------------------------- + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = ['sphinx_copybutton', 'autoapi.extension', 'sphinx_click'] + +# 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 + +# Settings for the `autoapi` extension +autoapi_dirs = ['../../aiida_pseudo'] +autoapi_ignore = ['*cli*'] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This pattern also affects html_static_path and html_extra_path. +exclude_patterns = [] + +# -- Options for HTML output ------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +# +html_theme = 'sphinx_book_theme' +html_static_path = ['_static'] +html_css_files = ['aiida-custom.css'] +html_theme_options = { + 'home_page_in_toc': True, + 'repository_url': 'https://github.com/aiidateam/aiida-pseudo', + 'repository_branch': 'master', + 'use_repository_button': True, + 'use_issues_button': True, + 'path_to_docs': 'docs', + 'use_edit_page_button': True, + 'extra_navbar': '' +} +html_domain_indices = True diff --git a/docs/source/design.rst b/docs/source/design.rst new file mode 100644 index 0000000..4ed5d5e --- /dev/null +++ b/docs/source/design.rst @@ -0,0 +1,109 @@ + +.. _design: + +###### +Design +###### + +The plugin is centered around two concepts: pseudopotentials and pseudopotential families. +The two concepts are further explained below, especially focusing on how they are implemented in ``aiida-pseudo``, what assumptions are made, and what the limitations are. + +Pseudopotentials +================ + +Pseudopotentials are implemented as `data plugins `_, and the base class is ``PseudoPotentialData``. +Pseudopotentials are assumed to be defined by a single file on disk and represent a single chemical element. +As such, each pseudopotential node, *has* to have two attributes: the md5 of the file that it represents and the symbol of chemical element that the pseudopotential describes. +The latter follows IUPAC naming conventions as used in the module ``aiida.common.constants.elements`` of ``aiida-core``. + +The ``PseudoPotentialData`` functions as a base class and does not represent an actual existing pseudopotential format. +It *is* possible to create a family of ``PseudoPotentialData`` nodes, but since the element cannot be parsed from the file content itself, it will have to be done from the *filename*, so the filename *has* to have the format ``CHEMICAL_SYMBOL.EXTENSION``, for example ``Ar.pseudo``. +Since the ``PseudoPotentialData`` class does not have any features tailored to specific formats, as do the classes which inherit from it (e.g. ``UpfData`` for UPF-formatted pseudopotentials), this class is mostly useful for development. + +The plugin comes with a variety of pseudopotential subtypes that represent various common pseudopotential formats, such as UPF, PSF, PSML and PSP8. +The corresponding data plugins implement how the element and other data are parsed from a pseudopotential file with such a format. +A new pseudopotential node can be created by instantiating the corresponding plugin class: + +.. code-block:: + + from aiida import plugins + + UpfData = plugins.DataFactory('pseudo.upf') + + with open('path/to/pseudo.upf', 'rb') as stream: + pseudo = UpfData(stream) + +Note, the pseudopotential constructor expects a stream of bytes, so be sure to open the file handle with the ``'rb'`` mode. +Alternatively, you can also use the ``get_or_create`` classmethod, which will first search the database to check if a pseudopotential of the exact same type and content already exists. +If that is the case, that node is returned, otherwise a new instance is created: + +.. code-block:: python + + from aiida import plugins + + UpfData = plugins.DataFactory('pseudo.upf') + + with open('path/to/pseudo.upf', 'rb') as stream: + pseudo = UpfData.get_or_create(stream) + +If a new node was created, it will be unstored. +Note that if more than one pseudopotential in the database is matched, a random one is selected and returned. + +Families +======== + +Having loose pseudopotentials floating around is not very practical, so groups of related pseudopotentials can be organized into "families", which are implemented as group plugins with the base class ``PseudoPotentialFamily``. +A family class can in principle support many pseudopotential formats, however, a family instance can only contain pseudopotentials of a single format. +For example, the ``PseudoPotentialFamily`` class supports all of the pseudopotential formats that are supported by this plugin. +However, any instance can only contain pseudopotentials of the same format (e.g. *all* UPF or *all* PSP8, not a mixture). +In contrast, the ``SsspFamily`` only supports the ``UpfData`` format. + +A pseudopotential family can be constructed manually, by first constructing the class instance and then adding pseudopotential data nodes to it: + +.. code-block:: python + + from aiida import plugins + + UpfData = plugins.DataFactory('pseudo.upf') + PseudoPotentialFamily = plugins.GroupFactory('pseudo') + + pseudos = [] + + for filepath in ['Ga.upf', 'As.upf']: + with open(filepath, 'rb') as stream: + pseudo = UpfData(stream) + pseudos.append(pseudo) + + family = PseudoPotentialFamily(label='pseudos/upf').store() + family.append(pseudos) + +Note that as with any ``Group``, it has to be stored before nodes can be added. +If you have a folder on disk that contains various pseudopotentials for different elements, there is an even easier way to create the family automatically: + +.. code-block:: python + + from aiida import plugins + + UpfData = plugins.DataFactory('pseudo.upf') + PseudoPotentialFamily = plugins.GroupFactory('pseudo') + + family = PseudoPotentialFamily('path/to/pseudos', 'pseudos/upf', pseudo_type=UpfData) + +The plugin is not able to reliably deduce the format of the pseudopotentials contained in the folder, so one should indicate what data type to use with the ``pseudo_type`` argument. +The exception is when the family class only supports a single pseudo type, such as for the ``SsspFamily``, in which case that type will automatically be selected. +Subclasses of supported pseudo types are also accepted. +For example, the base class ``PseudoPotentialFamily`` supports pseudopotentials of the ``PseudoPotentialData`` type. +Because all more specific pseudopotential types are subclasses of ``PseudoPotentialData``, the ``PseudoPotentialFamily`` class accepts all of them. + +Recommended cutoffs +=================== + +Certain pseudopotential family types, such as the ``SsspFamily``, provide recommended cutoff values for wave functions and charge density in plane-wave codes. +These cutoffs are always in units of electronvolt. +The recommended cutoffs for a set of elements or a ``StructureData`` can be retrieved from the family as follows: + +.. code-block:: python + + family = load_group('SSSP/1.1/PBE/efficiency') + cutoffs = family.get_recommended_cutoffs(elements=('Ga', 'As')) # From a tuple or list of element symbols + cutoffs = family.get_recommended_cutoffs(structure=load_node()) # From a `StructureData` node diff --git a/docs/source/howto.rst b/docs/source/howto.rst new file mode 100644 index 0000000..e9d53e9 --- /dev/null +++ b/docs/source/howto.rst @@ -0,0 +1,98 @@ +.. _how-to: + +############# +How-To Guides +############# + +.. _how-to:install_archive: + +Installing from archive or folder +================================= + +In case the automated install commands fail, or the pseudopotential family you want to use is not supported, you can install the pseudopotential family manually with the following command: + +.. code-block:: console + + $ aiida-pseudo install family