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

Postprocessing plugin #17

Merged
merged 3 commits into from
Dec 20, 2023
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
53 changes: 53 additions & 0 deletions aiida_flexpart/calculations/flexpart_post.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# -*- coding: utf-8 -*-
"""
Calculations provided by aiida_flexpart.
Register calculations via the "aiida.calculations" entry point in setup.json.
"""
from aiida import orm, common, engine


class PostProcessingCalculation(engine.CalcJob):
"""AiiDA calculation plugin for post processing."""
@classmethod
def define(cls, spec):
"""Define inputs and outputs of the calculation."""
# yapf: disable
super().define(spec)

# set default values for AiiDA options
spec.inputs['metadata']['options']['resources'].default = {
'num_machines': 1,
'num_mpiprocs_per_machine': 1,
}

#INPUTS
spec.input('metadata.options.parser_name', valid_type=str, default='flexpart.post')
spec.input('input_dir', valid_type = orm.RemoteData, required=True,
help = 'main FLEXPART output dir')
spec.input('input_offline_dir', valid_type = orm.RemoteData, required=False,
help = 'offline-nested FLEXPART output dir')
spec.input('metadata.options.output_filename', valid_type=str, default='aiida.out', required=True)
#exit codes
spec.outputs.dynamic = True
spec.exit_code(300, 'ERROR_MISSING_OUTPUT_FILES', message='Calculation did not produce all expected output files.')

def prepare_for_submission(self, folder):

params = ['-m',self.inputs.input_dir.get_remote_path(),
'-r','./'
]
if 'input_offline_dir' in self.inputs:
params += ['-n',self.inputs.input_offline_dir.get_remote_path()]

codeinfo = common.CodeInfo()
codeinfo.cmdline_params = params
codeinfo.code_uuid = self.inputs.code.uuid
codeinfo.stdout_name = self.metadata.options.output_filename
codeinfo.withmpi = self.inputs.metadata.options.withmpi

# Prepare a `CalcInfo` to be returned to the engine
calcinfo = common.CalcInfo()
calcinfo.codes_info = [codeinfo]
calcinfo.retrieve_list = ['grid_time_*.nc', 'boundary_sensitivity_*.nc', 'aiida.out']

return calcinfo
53 changes: 53 additions & 0 deletions aiida_flexpart/parsers/flexpart_post.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# -*- coding: utf-8 -*-
"""
Parsers provided by aiida_flexpart.

Register parsers via the "aiida.parsers" entry point in setup.json.
"""
from aiida import engine, parsers, plugins, common, orm

FlexpartCalculation = plugins.CalculationFactory('flexpart.post')


class FlexpartPostParser(parsers.Parser):
"""
Parser class for parsing output of calculation.
"""
def __init__(self, node):
"""
Initialize Parser instance

Checks that the ProcessNode being passed was produced by a FlexpartCalculation.

:param node: ProcessNode of calculation
:param type node: :class:`aiida.orm.ProcessNode`
"""
super().__init__(node)
if not issubclass(node.process_class, FlexpartCalculation):
raise common.ParsingError('Can only parse FlexpartCalculation')

def parse(self, **kwargs):
"""
Parse outputs, store results in database.

:returns: an exit code, if parsing fails (or nothing if parsing succeeds)
"""
output_filename = self.node.get_option('output_filename')

# Check that folder content is as expected
files_retrieved = self.retrieved.list_object_names()
files_expected = [output_filename]
# Note: set(A) <= set(B) checks whether A is a subset of B
if not set(files_expected) <= set(files_retrieved):
self.logger.error(
f"Found files '{files_retrieved}', expected to find '{files_expected}'"
)
return self.exit_codes.ERROR_MISSING_OUTPUT_FILES

# add output file
self.logger.info(f"Parsing '{output_filename}'")
with self.retrieved.open(output_filename, 'rb') as handle:
output_node = orm.SinglefileData(file=handle)
self.out('output_file', output_node)

return engine.ExitCode(0)
Loading