Skip to content

Commit

Permalink
Add a test for a full silicon SCF workchain
Browse files Browse the repository at this point in the history
  • Loading branch information
Technici4n committed Nov 6, 2024
1 parent 53ef8e5 commit 94f10a8
Show file tree
Hide file tree
Showing 6 changed files with 4,813 additions and 203 deletions.
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ dependencies = [
'importlib_resources',
'jsonschema',
'numpy',
'packaging'
'packaging',
'pymatgen',
]

Expand Down
229 changes: 27 additions & 202 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -1,132 +1,26 @@
# -*- coding: utf-8 -*-
# pylint: disable=redefined-outer-name,too-many-statements
"""Initialise a text database and profile for pytest."""
import os

import pytest

pytest_plugins = ['aiida.manage.tests.pytest_fixtures'] # pylint: disable=invalid-name


@pytest.fixture(scope='session')
def filepath_tests():
"""Return the absolute filepath of the `tests` folder.
.. warning:: if this file moves with respect to the `tests` folder, the implementation should change.
:return: absolute filepath of `tests` folder which is the basepath for all test resources.
"""
return os.path.dirname(os.path.abspath(__file__))


@pytest.fixture
def filepath_fixtures(filepath_tests):
"""Return the absolute filepath to the directory containing the file `fixtures`."""
return os.path.join(filepath_tests, 'fixtures')


@pytest.fixture(scope='function')
def fixture_sandbox():
"""Return a `SandboxFolder`."""
from aiida.common.folders import SandboxFolder
with SandboxFolder() as folder:
yield folder


@pytest.fixture
def fixture_localhost(aiida_localhost):
"""Return a localhost `Computer`."""
localhost = aiida_localhost
localhost.set_default_mpiprocs_per_machine(1)
return localhost


@pytest.fixture
def fixture_code(fixture_localhost):
"""Return a ``Code`` instance configured to run calculations of given entry point on localhost ``Computer``."""

def _fixture_code(entry_point_name):
from aiida.common import exceptions
from aiida.orm import Code

label = f'test.{entry_point_name}'

try:
return Code.objects.get(label=label) # pylint: disable=no-member
except exceptions.NotExistent:
return Code(
label=label,
input_plugin_name=entry_point_name,
remote_computer_exec=[fixture_localhost, '/bin/true'],
)

return _fixture_code


@pytest.fixture
def serialize_builder():
"""Serialize the given process builder into a dictionary with nodes turned into their value representation.
:param builder: the process builder to serialize
:return: dictionary
"""

def serialize_data(data):
# pylint: disable=too-many-return-statements
from aiida.orm import BaseType, Code, Dict
from aiida.plugins import DataFactory

StructureData = DataFactory('core.structure')
UpfData = DataFactory('pseudo.upf')

if isinstance(data, dict):
return {key: serialize_data(value) for key, value in data.items()}

if isinstance(data, BaseType):
return data.value

if isinstance(data, Code):
return data.full_label

if isinstance(data, Dict):
return data.get_dict()

if isinstance(data, StructureData):
return data.get_formula()

if isinstance(data, UpfData):
return f'{data.element}<md5={data.md5}>'

return data

def _serialize_builder(builder):
return serialize_data(builder._inputs(prune=True)) # pylint: disable=protected-access

return _serialize_builder

pytest_plugins = 'aiida.manage.tests.pytest_fixtures'

@pytest.fixture
def generate_calc_job():
"""Fixture to construct a new `CalcJob` instance and call `prepare_for_submission` for testing `CalcJob` classes.
The fixture will return the `CalcInfo` returned by `prepare_for_submission` and the temporary folder that was passed
to it, into which the raw input files will have been written.
"""

def _generate_calc_job(folder, entry_point_name, inputs=None):
"""Fixture to generate a mock `CalcInfo` for testing calculation jobs."""
from aiida.engine.utils import instantiate_process
from aiida.manage.manager import get_manager
from aiida.plugins import CalculationFactory

manager = get_manager()
runner = manager.get_runner()
def get_dftk_code(aiida_local_code_factory):
"""Return an ``InstalledCode`` instance configured to run DFTK calculations on localhost."""

process_class = CalculationFactory(entry_point_name)
process = instantiate_process(runner, process_class, **inputs)
def _get_code():
import os

calc_info = process.prepare_for_submission(folder)
project_path = os.path.join(__file__, "..", "julia_environment")

return calc_info

return _generate_calc_job
return aiida_local_code_factory(
'dftk',
'julia',
label='dftk',
prepend_text=f"""\
export JULIA_PROJECT="{project_path}"
""",
)

return _get_code

@pytest.fixture
def generate_structure():
Expand Down Expand Up @@ -177,90 +71,21 @@ def _generate_kpoints_mesh(npoints):

return _generate_kpoints_mesh


@pytest.fixture(scope='session')
def generate_parser():
"""Fixture to load a parser class for testing parsers."""

def _generate_parser(entry_point_name):
"""Fixture to load a parser class for testing parsers.
:param entry_point_name: entry point name of the parser class
:return: the `Parser` sub class
"""
from aiida.plugins import ParserFactory
return ParserFactory(entry_point_name)

return _generate_parser


# TODO: It would be nicer to automatically download the psp through aiida-pseudo
@pytest.fixture
def generate_remote_data():
"""Return a `RemoteData` node."""

def _generate_remote_data(computer, remote_path, entry_point_name=None):
"""Return a `KpointsData` with a mesh of npoints in each direction."""
from aiida.common.links import LinkType
from aiida.orm import CalcJobNode, RemoteData
from aiida.plugins.entry_point import format_entry_point_string

entry_point = format_entry_point_string('aiida.calculations', entry_point_name)

remote = RemoteData(remote_path=remote_path)
remote.computer = computer
def load_psp():
"""Return the pd_nc_sr_pbe_standard_0.4.1_upf pseudopotential for an element"""

if entry_point_name is not None:
creator = CalcJobNode(computer=computer, process_type=entry_point)
creator.set_option('resources', {'num_machines': 1, 'num_mpiprocs_per_machine': 1})
remote.base.links.add_incoming(creator, link_type=LinkType.CREATE, link_label='remote_folder')
creator.store()
def _load_psp(element: str):
from aiida import plugins
from pathlib import Path

return remote

return _generate_remote_data


@pytest.fixture
def generate_bands_data():
"""Return a `BandsData` node."""

def _generate_bands_data():
"""Return a `BandsData` instance with some basic `kpoints` and `bands` arrays."""
from aiida.plugins import DataFactory
import numpy
BandsData = DataFactory('core.array.bands') #pylint: disable=invalid-name
bands_data = BandsData()

bands_data.set_kpoints(numpy.array([[0., 0., 0.], [0.625, 0.25, 0.625]]))

bands_data.set_bands(
numpy.array([[-5.64024889, 6.66929678, 6.66929678, 6.66929678, 8.91047649],
[-1.71354964, -0.74425095, 1.82242466, 3.98697455, 7.37979746]]),
units='eV'
)

return bands_data

return _generate_bands_data


@pytest.fixture
def generate_workchain():
"""Generate an instance of a `WorkChain`."""

def _generate_workchain(entry_point, inputs):
"""Generate an instance of a `WorkChain` with the given entry point and inputs.
:param entry_point: entry point name of the work chain subclass.
:param inputs: inputs to be passed to process construction.
:return: a `WorkChain` instance.
"""
from aiida.engine.utils import instantiate_process
from aiida.manage.manager import get_manager
from aiida.plugins import WorkflowFactory
if element != "Si":
raise ValueError("Only the Si psp is available for the moment.")

process_class = WorkflowFactory(entry_point)
runner = get_manager().get_runner()
process = instantiate_process(runner, process_class, **inputs)
UpfData = plugins.DataFactory('pseudo.upf')
with open((Path(__file__) / ".." / "pseudos" / (element + ".upf")).resolve(), "rb") as stream:
return UpfData(stream)

return process
return _load_psp

return _generate_workchain
2 changes: 2 additions & 0 deletions tests/julia_environment/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
LocalPreferences.toml
Manifest.toml
5 changes: 5 additions & 0 deletions tests/julia_environment/Project.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[deps]
AiidaDFTK = "26386dbc-b74b-4d9a-b75a-41d28ada84fc"

[compat]
AiidaDFTK = "0.1"
Loading

0 comments on commit 94f10a8

Please sign in to comment.