Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions docs/source/installation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,34 @@ flight: a task whose worker disappears may be retried on the next one, in the sa
directory as the interrupted run. ``koopmans backend uninstall`` removes the whole
setup, database included.

*******************
Pseudopotentials
*******************

You do not have to install pseudopotentials up front. The ``pseudo_library`` keyword of
your input file names a family, and ``koopmans`` downloads that family the first time it
is needed. It can fetch `PseudoDojo <http://www.pseudo-dojo.org/>`_, `SSSP
<https://www.materialscloud.org/discover/sssp/table/efficiency>`_ and `SG15
<http://www.quantum-simulation.org/potentials/sg15_oncv/>`_ families, named like

- ``PseudoDojo/0.4/LDA/SR/standard/upf``
- ``SSSP/1.3/PBEsol/efficiency``
- ``SG15/1.2/PBE/SR``

A family that you install yourself works just as well, under whatever label you give it:
``koopmans`` downloads a family only when no installed one carries the label you asked
for. This is the route for pseudopotentials it cannot fetch — the full-relativistic LDA
sets that spin-orbit calculations need, for instance. Point ``aiida-pseudo`` at a
directory holding one file per element:

.. code-block:: console

$ aiida-pseudo install family <directory> my-lda-fr

Then set ``pseudo_library`` to ``my-lda-fr``. A family installed this way publishes no
recommended cutoffs, so state ``calculator_parameters.ecutwfc`` in your input file;
``ecutrho`` follows at four times it, the ratio norm-conserving pseudopotentials use.

****************************
Installing for development
****************************
Expand Down
28 changes: 19 additions & 9 deletions src/koopmans/aiida/setup/pseudos.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,16 @@
def ensure_pseudo_family_installed(pseudo_family: str) -> None:
"""Ensure a pseudopotential family is installed, installing it if necessary.

Supports PseudoDojo families with labels like:
Any already-installed family is used as it stands, whatever its label. A
label that names no installed family is downloaded, which koopmans can do
for three families:
'PseudoDojo/0.4/LDA/SR/standard/upf'

SSSP families with labels like:
'SSSP/1.3/PBEsol/efficiency'

And SG15 ONCV families with labels like:
'SG15/1.2/PBE/SR'

Raises:
ValueError: If the family format is not recognized or installation fails.
ValueError: If no family carries the label and koopmans cannot
download it, or if the download fails.
"""
from aiida.common.exceptions import NotExistent
from aiida_pseudo.groups.family import PseudoPotentialFamily
Expand Down Expand Up @@ -58,7 +57,10 @@ def pseudo_family_has_cutoffs(pseudo_family: str) -> bool:


def install_pseudo_family(pseudo_family: str) -> None:
"""Install a pseudopotential family. Parse the label and dispatch."""
"""Download and install a pseudopotential family. Parse the label and dispatch.

No family may already carry the label.
"""
parts = pseudo_family.split("/")

if parts[0] == "PseudoDojo" and len(parts) == 6:
Expand All @@ -69,8 +71,16 @@ def install_pseudo_family(pseudo_family: str) -> None:
_install_sg15_family(pseudo_family, parts)
else:
raise ValueError(
f"Unrecognized pseudo family format: '{pseudo_family}'. "
"Expected 'PseudoDojo/version/functional/relativistic/protocol/format', "
f"No installed pseudopotential family has the label '{pseudo_family}', and "
"koopmans cannot download one under that label.\n"
"Install the pseudopotentials yourself, from a directory holding one file "
"per element:\n"
f" aiida-pseudo install family <directory> {pseudo_family}\n"
"A family installed this way publishes no recommended cutoffs, so set "
"`calculator_parameters.ecutwfc` in your input file; `ecutrho` follows at "
"four times it.\n"
"Alternatively, name a family koopmans can download for you, as "
"'PseudoDojo/version/functional/relativistic/protocol/format', "
"'SSSP/version/functional/protocol', "
"or 'SG15/version/functional/relativistic'."
)
Expand Down
2 changes: 1 addition & 1 deletion src/koopmans/input_file/workflow.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ class WorkflowConfig(BaseModel):
default=True, description="whether or not to calculate the screening parameters ab-initio"
)
pseudo_library: str = Field(
description="the pseudopotential library to use (for valid options, run `koopmans pseudos list`)"
description="the label of the pseudopotential family to use. Any family you have installed yourself is used as it stands, whatever its label; a label naming no installed family is downloaded, which koopmans can do for 'PseudoDojo/version/functional/relativistic/protocol/format', 'SSSP/version/functional/protocol' and 'SG15/version/functional/relativistic'. A family that publishes no recommended cutoffs takes them from `calculator_parameters.ecutwfc` instead"
)
screening_method: CalculateScreeningMethod = Field(
default=CalculateScreeningMethod.DSCF,
Expand Down
19 changes: 10 additions & 9 deletions tests/fixtures.py
Original file line number Diff line number Diff line change
Expand Up @@ -521,11 +521,11 @@ def _install_fake_family(
The streams are enough for ``UpfData`` validation, not physically
meaningful pseudos. ``cutoffs=True`` builds a
``CutoffsPseudoPotentialFamily`` with recommended cutoffs — needed by
builders that call ``get_builder_from_protocol`` eagerly at build time
(the aiida-qe protocol machinery only accepts SSSP, PseudoDojo, or a
cutoffs family); plain families cover ``ensure_pseudo_family_installed``.
``recommended_cutoffs=False`` leaves that cutoffs family with no stringency
defined, the shape ``_install_sg15_family`` produces.
a build that states none of its own; ``cutoffs=False`` builds a plain
``PseudoPotentialFamily``, the shape both ``aiida-pseudo install family``
and ``_install_sg15_family`` produce.
``recommended_cutoffs=False`` leaves the cutoffs family with no stringency
defined, the shape ``-F pseudo.family.cutoffs`` produces on its own.
``has_so=True`` marks every pseudo fully relativistic.
"""
from aiida.common.exceptions import NotExistent
Expand Down Expand Up @@ -575,11 +575,12 @@ def fake_sg15_cutoffs_family(aiida_profile: Any) -> Any:

@pytest.fixture
def fake_sg15_family_without_cutoffs(aiida_profile: Any) -> Any:
"""Install ``SG15/1.2/PBE/FR`` in the shape ``_install_sg15_family`` produces.
"""Install ``SG15/1.2/PBE/FR`` as a cutoffs family with no stringency defined.

A ``CutoffsPseudoPotentialFamily`` with no stringency defined, so it can
recommend no cutoffs. A label of its own so it coexists with the other
SG15 fixtures in one session profile.
The half-configured shape a user reaches by passing
``-F pseudo.family.cutoffs`` and never running ``aiida-pseudo family
cutoffs set``: it can recommend no cutoffs. A label of its own so it
coexists with the other SG15 fixtures in one session profile.
"""
return _install_fake_family(
"SG15/1.2/PBE/FR", {"Si": 4.0}, cutoffs=True, recommended_cutoffs=False
Expand Down
55 changes: 55 additions & 0 deletions tests/test_pseudos.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
"""Tests for resolving the ``pseudo_library`` label to a pseudopotential family."""

from __future__ import annotations

from typing import Any

import pytest


class TestEnsurePseudoFamilyInstalled:
"""``ensure_pseudo_family_installed`` downloads only what is missing."""

def test_installed_family_under_arbitrary_label_is_used_as_is(
self, fake_user_built_family: Any, monkeypatch: pytest.MonkeyPatch
) -> None:
"""A label matching no download format resolves to the installed family."""
from koopmans.aiida.setup import pseudos

def _fail(label: str) -> None:
raise AssertionError(f"attempted to download '{label}'")

monkeypatch.setattr(pseudos, "install_pseudo_family", _fail)

pseudos.ensure_pseudo_family_installed(fake_user_built_family.label)

def test_uninstallable_label_reports_both_routes(self, aiida_profile_clean: Any) -> None:
"""An unknown label names the install command and the download formats."""
from koopmans.aiida.setup import pseudos

with pytest.raises(ValueError) as excinfo:
pseudos.ensure_pseudo_family_installed("my-gaas-fr")

message = str(excinfo.value)
assert "No installed pseudopotential family has the label 'my-gaas-fr'" in message
assert "aiida-pseudo install family <directory> my-gaas-fr\n" in message
assert "calculator_parameters.ecutwfc" in message
assert "PseudoDojo/version/functional/relativistic/protocol/format" in message

def test_the_install_command_asks_for_no_cutoffs_family(self, aiida_profile_clean: Any) -> None:
"""The command offered is the plain-family one, with no cutoffs to set.

A family built with ``-F pseudo.family.cutoffs`` and no
``aiida-pseudo family cutoffs set`` can recommend no cutoffs, which is
the half-configured shape the message must not send anyone to; the
cutoffs come from the input file instead.
"""
from koopmans.aiida.setup import pseudos

with pytest.raises(ValueError) as excinfo:
pseudos.ensure_pseudo_family_installed("my-gaas-fr")

message = str(excinfo.value)
assert "-F" not in message
assert "pseudo.family.cutoffs" not in message
assert "cutoffs set" not in message