-
Notifications
You must be signed in to change notification settings - Fork 80
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'main' into fix/cli-workflows-pw-base
- Loading branch information
Showing
15 changed files
with
369 additions
and
25 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
# -*- coding: utf-8 -*- | ||
"""`CalcJob` implementation for the bands.x code of Quantum ESPRESSO.""" | ||
|
||
from aiida import orm | ||
|
||
from aiida_quantumespresso.calculations.namelists import NamelistsCalculation | ||
|
||
|
||
class BandsCalculation(NamelistsCalculation): | ||
"""`CalcJob` implementation for the bands.x code of Quantum ESPRESSO. | ||
bands.x code of the Quantum ESPRESSO distribution, re-orders bands, and computes band-related properties. | ||
It computes for instance the expectation value of the momentum operator: | ||
<Psi(n,k) | i * m * [H, x] | Psi(m,k)>. For more information, refer to http://www.quantum-espresso.org/ | ||
""" | ||
|
||
_MOMENTUM_OPERATOR_NAME = 'momentum_operator.dat' | ||
_BANDS_NAME = 'bands.dat' | ||
|
||
_default_namelists = ['BANDS'] | ||
_blocked_keywords = [ | ||
('BANDS', 'outdir', NamelistsCalculation._OUTPUT_SUBFOLDER), # pylint: disable=protected-access | ||
('BANDS', 'prefix', NamelistsCalculation._PREFIX), # pylint: disable=protected-access | ||
('BANDS', 'filband', _BANDS_NAME), | ||
('BANDS', 'filp', _MOMENTUM_OPERATOR_NAME), # Momentum operator | ||
] | ||
|
||
_internal_retrieve_list = [] | ||
_default_parser = 'quantumespresso.bands' | ||
|
||
@classmethod | ||
def define(cls, spec): | ||
"""Define the process specification.""" | ||
# yapf: disable | ||
super().define(spec) | ||
spec.input('parent_folder', valid_type=(orm.RemoteData, orm.FolderData), required=True) | ||
spec.output('output_parameters', valid_type=orm.Dict) | ||
# yapf: enable |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
# -*- coding: utf-8 -*- | ||
from aiida.orm import Dict | ||
|
||
from aiida_quantumespresso.utils.mapping import get_logging_container | ||
|
||
from .base import BaseParser | ||
|
||
|
||
class BandsParser(BaseParser): | ||
"""``Parser`` implementation for the ``BandsCalculation`` calculation job class.""" | ||
|
||
def parse(self, **kwargs): | ||
"""Parse the retrieved files of a ``BandsCalculation`` into output nodes.""" | ||
logs = get_logging_container() | ||
|
||
_, parsed_data, logs = self.parse_stdout_from_retrieved(logs) | ||
|
||
base_exit_code = self.check_base_errors(logs) | ||
if base_exit_code: | ||
return self.exit(base_exit_code, logs) | ||
|
||
self.out('output_parameters', Dict(parsed_data)) | ||
|
||
if 'ERROR_OUTPUT_STDOUT_INCOMPLETE'in logs.error: | ||
return self.exit(self.exit_codes.ERROR_OUTPUT_STDOUT_INCOMPLETE, logs) | ||
|
||
return self.exit(logs=logs) |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
# -*- coding: utf-8 -*- | ||
"""Workchain to run a Quantum ESPRESSO bands.x calculation with automated error handling and restarts.""" | ||
from aiida.common import AttributeDict | ||
from aiida.engine import BaseRestartWorkChain, ProcessHandlerReport, process_handler, while_ | ||
from aiida.plugins import CalculationFactory | ||
|
||
BandsCalculation = CalculationFactory('quantumespresso.bands') | ||
|
||
|
||
class BandsBaseWorkChain(BaseRestartWorkChain): | ||
"""Workchain to run a Quantum ESPRESSO bands.x calculation with automated error handling and restarts.""" | ||
|
||
_process_class = BandsCalculation | ||
|
||
@classmethod | ||
def define(cls, spec): | ||
"""Define the process specification.""" | ||
# yapf: disable | ||
super().define(spec) | ||
spec.expose_inputs(BandsCalculation, namespace='bands') | ||
spec.expose_outputs(BandsCalculation) | ||
spec.outline( | ||
cls.setup, | ||
while_(cls.should_run_process)( | ||
cls.run_process, | ||
cls.inspect_process, | ||
), | ||
cls.results, | ||
) | ||
spec.exit_code(300, 'ERROR_UNRECOVERABLE_FAILURE', | ||
message='The calculation failed with an unrecoverable error.') | ||
# yapf: enable | ||
|
||
def setup(self): | ||
"""Call the `setup` of the `BaseRestartWorkChain` and then create the inputs dictionary in `self.ctx.inputs`. | ||
This `self.ctx.inputs` dictionary will be used by the `BaseRestartWorkChain` to submit the calculations in the | ||
internal loop. | ||
""" | ||
super().setup() | ||
self.ctx.restart_calc = None | ||
self.ctx.inputs = AttributeDict(self.exposed_inputs(BandsCalculation, 'bands')) | ||
|
||
def report_error_handled(self, calculation, action): | ||
"""Report an action taken for a calculation that has failed. | ||
This should be called in a registered error handler if its condition is met and an action was taken. | ||
:param calculation: the failed calculation node | ||
:param action: a string message with the action taken | ||
""" | ||
arguments = [calculation.process_label, calculation.pk, calculation.exit_status, calculation.exit_message] | ||
self.report('{}<{}> failed with exit status {}: {}'.format(*arguments)) | ||
self.report(f'Action taken: {action}') | ||
|
||
@process_handler(priority=600) | ||
def handle_unrecoverable_failure(self, node): | ||
"""Handle calculations with an exit status below 400 which are unrecoverable, so abort the work chain.""" | ||
if node.is_failed and node.exit_status < 400: | ||
self.report_error_handled(node, 'unrecoverable error, aborting...') | ||
return ProcessHandlerReport(True, self.exit_codes.ERROR_UNRECOVERABLE_FAILURE) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
# -*- coding: utf-8 -*- | ||
"""Tests for the `BandsCalculation` class.""" | ||
# pylint: disable=protected-access | ||
from aiida.common import datastructures | ||
|
||
from aiida_quantumespresso.calculations.bands import BandsCalculation | ||
|
||
|
||
def test_bands_default(fixture_sandbox, generate_calc_job, generate_inputs_bands, file_regression): | ||
"""Test a default `BandsCalculation`.""" | ||
entry_point_name = 'quantumespresso.bands' | ||
|
||
inputs = generate_inputs_bands() | ||
calc_info = generate_calc_job(fixture_sandbox, entry_point_name, inputs) | ||
|
||
retrieve_list = [BandsCalculation._DEFAULT_OUTPUT_FILE] + BandsCalculation._internal_retrieve_list | ||
|
||
# Check the attributes of the returned `CalcInfo` | ||
assert isinstance(calc_info, datastructures.CalcInfo) | ||
assert sorted(calc_info.retrieve_list) == sorted(retrieve_list) | ||
|
||
with fixture_sandbox.open('aiida.in') as handle: | ||
input_written = handle.read() | ||
|
||
# Checks on the files written to the sandbox folder as raw input | ||
assert sorted(fixture_sandbox.get_content_list()) == sorted(['aiida.in']) | ||
file_regression.check(input_written, encoding='utf-8', extension='.in') |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
&BANDS | ||
filband = 'bands.dat' | ||
filp = 'momentum_operator.dat' | ||
outdir = './out/' | ||
prefix = 'aiida' | ||
/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.