Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move calcfunctions to aiida_quantumespresso.calculations.functions #520

Merged
merged 1 commit into from
May 7, 2020
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
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# -*- coding: utf-8 -*-
"""Calculation function to compute a k-point mesh for a structure with a guaranteed minimum k-point distance."""
from aiida.engine import calcfunction


@calcfunction
def create_kpoints_from_distance(structure, distance, force_parity):
"""Generate a uniformly spaced kpoint mesh for a given structure.

The spacing between kpoints in reciprocal space is guaranteed to be at least the defined distance.

:param structure: the StructureData to which the mesh should apply
:param distance: a Float with the desired distance between kpoints in reciprocal space
:param force_parity: a Bool to specify whether the generated mesh should maintain parity
:returns: a KpointsData with the generated mesh
"""
from numpy import linalg
from aiida.orm import KpointsData

epsilon = 1E-5

kpoints = KpointsData()
kpoints.set_cell_from_structure(structure)
kpoints.set_kpoints_mesh_from_density(distance.value, force_parity=force_parity.value)

lengths_vector = [linalg.norm(vector) for vector in structure.cell]
lengths_kpoint = kpoints.get_kpoints_mesh()[0]

is_symmetric_cell = all(abs(length - lengths_vector[0]) < epsilon for length in lengths_vector)
is_symmetric_mesh = all(length == lengths_kpoint[0] for length in lengths_kpoint)

# If the vectors of the cell all have the same length, the kpoint mesh should be isotropic as well
if is_symmetric_cell and not is_symmetric_mesh:
nkpoints = max(lengths_kpoint)
kpoints.set_kpoints_mesh([nkpoints, nkpoints, nkpoints])

return kpoints
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# -*- coding: utf-8 -*-
"""Calcfunction to primitivize a structure and return high symmetry k-point path through its Brillouin zone."""
from aiida.engine import calcfunction
from aiida.orm import Data


@calcfunction
def seekpath_structure_analysis(structure, **kwargs):
"""Primitivize the structure with SeeKpath and generate the high symmetry k-point path through its Brillouin zone.

This calcfunction will take a structure and pass it through SeeKpath to get the normalized primitive cell and the
path of high symmetry k-points through its Brillouin zone. Note that the returned primitive cell may differ from the
original structure in which case the k-points are only congruent with the primitive cell.

The keyword arguments can be used to specify various Seekpath parameters, such as:

with_time_reversal: True
reference_distance: 0.025
recipe: 'hpkot'
threshold: 1e-07
symprec: 1e-05
angle_tolerance: -1.0

Note that exact parameters that are available and their defaults will depend on your Seekpath version.
"""
from aiida.tools import get_explicit_kpoints_path

# All keyword arugments should be `Data` node instances of base type and so should have the `.value` attribute
unwrapped_kwargs = {key: node.value for key, node in kwargs.items() if isinstance(node, Data)}

return get_explicit_kpoints_path(structure, **unwrapped_kwargs)
Original file line number Diff line number Diff line change
@@ -1,37 +1,12 @@
# -*- coding: utf-8 -*-
"""Calculation function to compute a k-point mesh for a structure with a guaranteed minimum k-point distance."""
from aiida.engine import calcfunction


@calcfunction
def create_kpoints_from_distance(structure, distance, force_parity):
"""Generate a uniformly spaced kpoint mesh for a given structure.

The spacing between kpoints in reciprocal space is guaranteed to be at least the defined distance.

:param structure: the StructureData to which the mesh should apply
:param distance: a Float with the desired distance between kpoints in reciprocal space
:param force_parity: a Bool to specify whether the generated mesh should maintain parity
:returns: a KpointsData with the generated mesh
"""
from numpy import linalg
from aiida.orm import KpointsData

epsilon = 1E-5

kpoints = KpointsData()
kpoints.set_cell_from_structure(structure)
kpoints.set_kpoints_mesh_from_density(distance.value, force_parity=force_parity.value)

lengths_vector = [linalg.norm(vector) for vector in structure.cell]
lengths_kpoint = kpoints.get_kpoints_mesh()[0]

is_symmetric_cell = all(abs(length - lengths_vector[0]) < epsilon for length in lengths_vector)
is_symmetric_mesh = all(length == lengths_kpoint[0] for length in lengths_kpoint)

# If the vectors of the cell all have the same length, the kpoint mesh should be isotropic as well
if is_symmetric_cell and not is_symmetric_mesh:
nkpoints = max(lengths_kpoint)
kpoints.set_kpoints_mesh([nkpoints, nkpoints, nkpoints])

return kpoints
# pylint: disable=unused-import
import warnings
from aiida_quantumespresso.calculations.functions.create_kpoints_from_distance import create_kpoints_from_distance

warnings.warn(
'This module is deprecated and will be removed soon.\nPlease use instead the new module:\n'
'from aiida_quantumespresso.calculations.functions.create_kpoints_from_distance import create_kpoints_from_distance'
"\nOr use the entry point with the factory: CalculationFactory('quantumespresso.create_kpoints_from_distance')",
FutureWarning
)
Original file line number Diff line number Diff line change
@@ -1,31 +1,12 @@
# -*- coding: utf-8 -*-
"""Calcfunction to primitivize a structure and return high symmetry k-point path through its Brillouin zone."""
from aiida.engine import calcfunction
from aiida.orm import Data


@calcfunction
def seekpath_structure_analysis(structure, **kwargs):
"""Primitivize the structure with SeeKpath and generate the high symmetry k-point path through its Brillouin zone.

This calcfunction will take a structure and pass it through SeeKpath to get the normalized primitive cell and the
path of high symmetry k-points through its Brillouin zone. Note that the returned primitive cell may differ from the
original structure in which case the k-points are only congruent with the primitive cell.

The keyword arguments can be used to specify various Seekpath parameters, such as:

with_time_reversal: True
reference_distance: 0.025
recipe: 'hpkot'
threshold: 1e-07
symprec: 1e-05
angle_tolerance: -1.0

Note that exact parameters that are available and their defaults will depend on your Seekpath version.
"""
from aiida.tools import get_explicit_kpoints_path

# All keyword arugments should be `Data` node instances of base type and so should have the `.value` attribute
unwrapped_kwargs = {key: node.value for key, node in kwargs.items() if isinstance(node, Data)}

return get_explicit_kpoints_path(structure, **unwrapped_kwargs)
# pylint: disable=unused-import
import warnings
from aiida_quantumespresso.calculations.functions.seekpath_structure_analysis import seekpath_structure_analysis

warnings.warn(
'This module is deprecated and will be removed soon.\nPlease use instead the new module:\n'
'from aiida_quantumespresso.calculations.functions.seekpath_structure_analysis import seekpath_structure_analysis'
"\nOr use the entry point with the factory: CalculationFactory('quantumespresso.seekpath_structure_analysis')",
FutureWarning
)
2 changes: 1 addition & 1 deletion aiida_quantumespresso/workflows/pw/bands.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
from aiida.plugins import WorkflowFactory
from aiida.engine import WorkChain, ToContext, if_

from aiida_quantumespresso.calculations.functions.seekpath_structure_analysis import seekpath_structure_analysis
from aiida_quantumespresso.utils.mapping import prepare_process_inputs
from aiida_quantumespresso.workflows.functions.seekpath_structure_analysis import seekpath_structure_analysis

PwBaseWorkChain = WorkflowFactory('quantumespresso.pw.base')
PwRelaxWorkChain = WorkflowFactory('quantumespresso.pw.relax')
Expand Down
2 changes: 1 addition & 1 deletion aiida_quantumespresso/workflows/pw/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@
from aiida.engine import ToContext, if_, while_
from aiida.plugins import CalculationFactory

from aiida_quantumespresso.calculations.functions.create_kpoints_from_distance import create_kpoints_from_distance
from aiida_quantumespresso.common.workchain.utils import register_error_handler, ErrorHandlerReport
from aiida_quantumespresso.common.workchain.base.restart import BaseRestartWorkChain
from aiida_quantumespresso.utils.defaults.calculation import pw as qe_defaults
from aiida_quantumespresso.utils.mapping import update_mapping, prepare_process_inputs
from aiida_quantumespresso.utils.pseudopotential import validate_and_prepare_pseudos_inputs
from aiida_quantumespresso.utils.resources import get_default_options, get_pw_parallelization_parameters
from aiida_quantumespresso.utils.resources import cmdline_remove_npools, create_scheduler_resources
from aiida_quantumespresso.workflows.functions.create_kpoints_from_distance import create_kpoints_from_distance

PwCalculation = CalculationFactory('quantumespresso.pw')

Expand Down
8 changes: 5 additions & 3 deletions setup.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,21 @@
"entry_points": {
"aiida.calculations": [
"quantumespresso.cp = aiida_quantumespresso.calculations.cp:CpCalculation",
"quantumespresso.create_kpoints_from_distance = aiida_quantumespresso.calculations.functions.create_kpoints_from_distance:create_kpoints_from_distance",
"quantumespresso.dos = aiida_quantumespresso.calculations.dos:DosCalculation",
"quantumespresso.epw = aiida_quantumespresso.calculations.epw:EpwCalculation",
"quantumespresso.matdyn = aiida_quantumespresso.calculations.matdyn:MatdynCalculation",
"quantumespresso.namelists = aiida_quantumespresso.calculations.namelists:NamelistsCalculation",
"quantumespresso.neb = aiida_quantumespresso.calculations.neb:NebCalculation",
"quantumespresso.ph = aiida_quantumespresso.calculations.ph:PhCalculation",
"quantumespresso.pp = aiida_quantumespresso.calculations.pp:PpCalculation",
"quantumespresso.projwfc = aiida_quantumespresso.calculations.projwfc:ProjwfcCalculation",
"quantumespresso.pw = aiida_quantumespresso.calculations.pw:PwCalculation",
"quantumespresso.epw = aiida_quantumespresso.calculations.epw:EpwCalculation",
"quantumespresso.pw2gw = aiida_quantumespresso.calculations.pw2gw:Pw2gwCalculation",
"quantumespresso.projwfc = aiida_quantumespresso.calculations.projwfc:ProjwfcCalculation",
"quantumespresso.pw2wannier90 = aiida_quantumespresso.calculations.pw2wannier90:Pw2wannier90Calculation",
"quantumespresso.pwimmigrant = aiida_quantumespresso.calculations.pwimmigrant:PwimmigrantCalculation",
"quantumespresso.q2r = aiida_quantumespresso.calculations.q2r:Q2rCalculation",
"quantumespresso.pwimmigrant = aiida_quantumespresso.calculations.pwimmigrant:PwimmigrantCalculation"
"quantumespresso.seekpath_structure_analysis = aiida_quantumespresso.calculations.functions.seekpath_structure_analysis:seekpath_structure_analysis"
],
"aiida.data": [
"quantumespresso.force_constants = aiida_quantumespresso.data.force_constants:ForceConstantsData"
Expand Down
17 changes: 9 additions & 8 deletions tests/calculations/test_autoinvalidate_cache.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,12 @@
# -*- coding: utf-8 -*-
"""Test the automatic 'invalidates_cache' attribute for exit codes."""
from distutils.version import StrictVersion # pylint: disable=import-error,no-name-in-module

import inspect
import pytest

import aiida
from aiida.engine import CalcJob
from aiida.plugins import CalculationFactory
from aiida.plugins.entry_point import get_entry_point_names

if StrictVersion(aiida.__version__) < StrictVersion('1.1.0'):
pytest.skip("The 'invalidates_cache' feature is only available on AiiDA 1.1+", allow_module_level=True)

QE_CALC_ENTRY_POINT_NAMES = [
ep_name for ep_name in get_entry_point_names(group='aiida.calculations') if ep_name.startswith('quantumespresso')
]
Expand All @@ -28,9 +24,14 @@ def test_exit_code_invalidates_cache(entry_point_name):
Test that the 'invalidates_cache' attribute of exit codes is automatically
set according to the status integer.
"""
calc_class = CalculationFactory(entry_point_name)
entry_point = CalculationFactory(entry_point_name)

if not inspect.isclass(entry_point) or not issubclass(entry_point, CalcJob):
return

overrides = EXPLICIT_OVERRIDES.get(entry_point_name, [])
for exit_code in calc_class.exit_codes.values():

for exit_code in entry_point.exit_codes.values():
if exit_code.status not in overrides:
if exit_code.status < 400:
assert exit_code.invalidates_cache
Expand Down