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

Implement CommonBandsWorkChain for FLEUR #259

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
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
7 changes: 7 additions & 0 deletions aiida_common_workflows/workflows/bands/fleur/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# -*- coding: utf-8 -*-
# pylint: disable=undefined-variable
"""Module with the implementations of the common bands workchain for Siesta."""
from .generator import *
from .workchain import *

__all__ = (generator.__all__ + workchain.__all__)
63 changes: 63 additions & 0 deletions aiida_common_workflows/workflows/bands/fleur/generator.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
# -*- coding: utf-8 -*-
"""Implementation of `aiida_common_workflows.common.bands.generator.CommonBandsInputGenerator` for Fleur."""

from aiida import engine, orm

from aiida_common_workflows.generators import CodeType

from ..generator import CommonBandsInputGenerator

__all__ = ('FleurCommonBandsInputGenerator',)


class FleurCommonBandsInputGenerator(CommonBandsInputGenerator):
"""Generator of inputs for the FleurCommonBandsWorkChain"""

@classmethod
def define(cls, spec):
"""Define the specification of the input generator.

The ports defined on the specification are the inputs that will be accepted by the ``get_builder`` method.
"""
super().define(spec)
spec.inputs['engines']['bands']['code'].valid_type = CodeType('fleur.fleur')

def _construct_builder(self, **kwargs) -> engine.ProcessBuilder:
"""Construct a process builder based on the provided keyword arguments.

The keyword arguments will have been validated against the input generator specification.
"""
# pylint: disable=too-many-branches,too-many-statements,too-many-locals
engines = kwargs.get('engines', None)
parent_folder = kwargs['parent_folder']
bands_kpoints = kwargs['bands_kpoints']

# From the parent folder, we retrieve the calculation that created it.
parent_calc = parent_folder.creator
if parent_calc.process_type != 'aiida.calculations:fleur.fleur':
raise ValueError('The `parent_folder` has not been created by a FleurCalculation')
builder_parent = parent_folder.creator.get_builder_restart()

#Transfer inputs from the parent calculation
builder = self.process_class.get_builder()
builder.options = orm.Dict(dict=builder_parent.metadata.options)
builder.fleur = builder_parent.code
Comment on lines +43 to +44
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not really a point for this PR, but I don't think it is advisable to have the Code and options inputs a separate ports. And especially exposing the options as a Dict node instead of a normal dict in the metadata of the calculation job is subideal. Is there a reason why you do this and you don't let the caller specify this information in the exposed inputs of the FleurScfWorkChain?

Taking a closer look, it seems that this is just a continuation problem of the fact that FleurScfWorkChain doesn't expose the inputs of FleurBaseWorkChain but manually creates input ports. If possible, I would recommend to properly use expose_inputs when wrapping subworkflows.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes you are right we have definitely underused exposing the inputs/outputs in the aiida-fleur plugin. I've been trying to expand the usage of this, where it leads to no breaking changes in the last months. One slight problem is that on the level of the FleurSCFWorkChain we have two different codes that can potentially be used. The fleur code and the inpgen code, which is used when we start a calculation from a structure input.

We can probably move to exposing the inputs by exposing both the FleurBaseWorkChain and the FleurinputgenCalculation, with one or both being in a namespace. But since the scf workchain is the main workchain that is then used throughout almost all higher level workchains this is quite a large breaking change, so we need to be careful with it.


wf_parameters = {'kpath': 'skip'}

builder.wf_parameters = orm.Dict(dict=wf_parameters)
builder.kpoints = bands_kpoints
builder.remote = parent_folder

#Add inputs from engines if given
if engines:
try:
band_engines = engines['bands']
except KeyError:
raise ValueError('The `engines` dictionary must contain `bands` as a top-level key')
if 'code' in band_engines:
builder.fleur = band_engines['code']
if 'options' in band_engines:
builder.options = orm.Dict(dict=band_engines['options'])

return builder
28 changes: 28 additions & 0 deletions aiida_common_workflows/workflows/bands/fleur/workchain.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# -*- coding: utf-8 -*-
"""Implementation of `aiida_common_workflows.common.relax.workchain.CommonRelaxWorkChain` for Fleur."""
from aiida.orm import Float
from aiida.plugins import WorkflowFactory

from ..workchain import CommonBandsWorkChain
from .generator import FleurCommonBandsInputGenerator

__all__ = ('FleurCommonBandsWorkChain',)


class FleurCommonBandsWorkChain(CommonBandsWorkChain):
"""Implementation of `aiida_common_workflows.common.bands.workchain.CommonBandsWorkChain` for Fleur."""

_process_class = WorkflowFactory('fleur.banddos')
_generator_class = FleurCommonBandsInputGenerator

def convert_outputs(self):
"""Convert the outputs of the sub workchain to the common output specification."""
self.report('Bands calculation concluded sucessfully, converting outputs')
if 'output_banddos_wc_bands' not in self.ctx.workchain.outputs:
self.report('FleurBandDOSWorkChain concluded without returning bands!')
return self.exit_codes.ERROR_SUB_PROCESS_FAILED

#The bands output of fleur is shifted to have the fermi energy at zero
self.out('fermi_energy', Float(0.0))

self.out('bands', self.ctx.workchain.outputs['output_banddos_wc_bands'])
1 change: 1 addition & 0 deletions setup.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@
"common_workflows.relax.quantum_espresso = aiida_common_workflows.workflows.relax.quantum_espresso.workchain:QuantumEspressoCommonRelaxWorkChain",
"common_workflows.relax.siesta = aiida_common_workflows.workflows.relax.siesta.workchain:SiestaCommonRelaxWorkChain",
"common_workflows.relax.vasp = aiida_common_workflows.workflows.relax.vasp.workchain:VaspCommonRelaxWorkChain",
"common_workflows.bands.fleur = aiida_common_workflows.workflows.bands.fleur.workchain:FleurCommonBandsWorkChain",
"common_workflows.bands.siesta = aiida_common_workflows.workflows.bands.siesta.workchain:SiestaCommonBandsWorkChain"
]
},
Expand Down