From b0f43a5ea6796c8bc2229a28344206c627619f1c Mon Sep 17 00:00:00 2001 From: janssenhenning Date: Fri, 21 Jan 2022 18:22:21 +0100 Subject: [PATCH 01/29] Initial commit for Hubbard1 workflow --- aiida_fleur/workflows/hubbard1.py | 258 ++++++++++++++++++++++++++++++ 1 file changed, 258 insertions(+) create mode 100644 aiida_fleur/workflows/hubbard1.py diff --git a/aiida_fleur/workflows/hubbard1.py b/aiida_fleur/workflows/hubbard1.py new file mode 100644 index 000000000..fd2f4adc3 --- /dev/null +++ b/aiida_fleur/workflows/hubbard1.py @@ -0,0 +1,258 @@ +# -*- coding: utf-8 -*- +""" +This module contains the FleurHubbard1WorkChain, which is used to perform +a complete hubbard 1 calculation including calculating model parameters beforehand +""" +from collections import defaultdict + +from aiida.common import AttributeDict +from aiida.engine import WorkChain, ToContext, if_ +from aiida import orm + +from aiida_fleur.workflows.scf import FleurScfWorkChain +from .cfcoeff import FleurCFCoeffWorkChain + + +class FleurHubbard1WorkChain(WorkChain): + """ + WorkChain for performing Hubbard-1 calculations + """ + + _workflow_version = '0.0.1' + + _default_wf_para = { + 'ldahia_dict': None, + 'soc': 'auto', + 'exchange_constants': None, + 'cf_coefficients': None, + 'occupation_converged': 0.01, + 'matrix_elements_converged': 0.001, + 'itmax_hubbard1': 5, + 'energy_contours': { + 'shape': 'semircircle', + 'eb': -1.0, + 'n': 128 + }, + 'energy_grid': { + 'ellow': -1.0, + 'elup': 1.0, + 'n': 5400 + }, + 'inpxml_changes': [], + } + + @classmethod + def define(cls, spec): + super().define(spec) + spec.expose_inputs(FleurCFCoeffWorkChain, + namespace='cfcoeff', + namespace_options={ + 'required': False, + 'populate_defaults': False + }) + spec.expose_inputs(FleurScfWorkChain, namespace='hubbard1_scf', namespace_options={ + 'required': True, + }) + spec.input('wf_parameters', valid_type=orm.Dict, required=False) + + spec.outline( + cls.start, cls.validate_inputs, + if_(cls.preliminary_calcs_needed)(cls.run_preliminary_calculations, cls.inspect_preliminary_calculations), + cls.run_hubbard1_calculation, cls.inspect_hubbard1_calculation, cls.return_results) + + spec.output('output_hubbard1_wc_para', valid_type=orm.Dict) + spec.expose_outputs(FleurScfWorkChain, namespace='scf') + + spec.exit_code(230, 'ERROR_INVALID_INPUT_PARAM', message='Invalid workchain parameters.') + spec.exit_code(231, 'ERROR_INVALID_INPUT_CONFIG', message='Invalid input configuration.') + spec.exit_code(377, 'ERROR_CFCOEFF_CALCULATION_FAILED', message='Crystal field coefficient calculation failed') + spec.exit_code(378, 'ERROR_HUBBARD1_CALCULATION_FAILED', message='Hubbard 1 calculation failed') + + def start(self): + """ + init context and some parameters + """ + self.report(f'INFO: started hubbard1 workflow version {self._workflowversion}') + + self.ctx.run_preliminary = False + self.ctx.fleurinp_hubbard1 = None + + wf_default = self._default_wf_para + if 'wf_parameters' in self.inputs: + wf_dict = self.inputs.wf_parameters.get_dict() + else: + wf_dict = wf_default + + for key, val in wf_default.items(): + wf_dict[key] = wf_dict.get(key, val) + self.ctx.wf_dict = wf_dict + + def validate_inputs(self): + """ + Validate the input configuration + """ + + extra_keys = {key for key in self.ctx.wf_dict if key not in self._default_wf_para} + if extra_keys: + error = f'ERROR: input wf_parameters for Orbcontrol contains extra keys: {extra_keys}' + self.report(error) + return self.exit_codes.ERROR_INVALID_INPUT_PARAM + + inputs = self.inputs + if 'cfcoeff' in inputs: + self.ctx.run_preliminary = True + if self.ctx.wf_dict['cf_coefficients'] is not None: + error = 'ERROR: you gave cfcoeff input + explicit cf_coefficients in wf_parameters' + self.control_end_wc(error) + return self.exit_codes.ERROR_INVALID_INPUT_CONFIG + + def preliminary_calcs_needed(self): + """ + Return whether calculations need to be run before the hubbard 1 calculation + """ + return self.ctx.run_prelimiary + + def run_preliminary_calculations(self): + """ + Run calculations needed before hubbard 1 + """ + + self.report('INFO: Starting Preliminary calculations') + + calcs = {} + if 'cfcoeff' in self.inputs: + self.report('INFO: Starting Crystal field calculation') + + inputs = AttributeDict(self.exposed_inputs(FleurCFCoeffWorkChain, namespace='cfcoeff')) + calcs['cfcoeff'] = self.submit(FleurCFCoeffWorkChain, **inputs) + + return ToContext(**calcs) + + def inspect_preliminary_calculations(self): + """ + Check that the preliminary calculations finished sucessfully + """ + if not self.ctx.cfcoeff.is_finished_ok: + error = ('ERROR: CFCoeff workflow was not successful') + self.report(error) + return self.exit_codes.ERROR_CFCOEFF_CALCULATION_FAILED + + try: + self.ctx.cfcoeff.outputs.output_cfcoeff_wc_para + except KeyError: + message = ('ERROR: CFCoeff workflow failed, no output node') + self.ctx.errors.append(message) + return self.exit_codes.ERROR_CFCOEFF_CALCULATION_FAILED + + def create_hubbard1_input(self): + """ + Create the inpxml_changes input to create the hubbard 1 input + """ + inputs_hubbard1 = AttributeDict(self.exposed_inputs(FleurScfWorkChain, namespace='scf')) + + if 'wf_parameters' in inputs_hubbard1: + scf_wf_para = inputs_hubbard1.wf_parameters.get_dict() + else: + scf_wf_para = {} + + fchanges = self.ctx.wf_dict.get('inpxml_changes', []) + scf_wf_para.setdefault('inpxml_changes', []).extend(fchanges) + + scf_wf_para['inpxml_changes'].append(('set_inpchanges', { + 'change_dict': { + 'minoccdistance': self.ctx.wf_dict['occupation_converged'], + 'minmatdistance': self.ctx.wf_dict['matrix_elements_converged'], + 'itmaxhubbard1': self.ctx.wf_dict['itmax_hubbard1'] + } + })) + + scf_wf_para['inpxml_changes'].append(('set_simple_tag', { + 'tag_name': 'realAxis', + 'changes': self.ctx.wf_dict['energy_grid'], + 'create_parents': True + })) + + complex_contours = self.ctx.wf_dict['energy_contours'] + if not isinstance(complex_contours, list): + complex_contours = [complex_contours] + + #Build the list of changes (we need to provide them in one go to not override each other) + contour_tags = defaultdict(list) + for contour in complex_contours: + shape = contour.pop('shape') + + if shape.lower() == 'semircircle': + contour_tags['contourSemicircle'].append(contour) + elif shape.lower() == 'dos': + contour_tags['contourDOS'].append(contour) + elif shape.lower() == 'rectangle': + contour_tags['contourRectangle'].append(contour) + + scf_wf_para['inpxml_changes'].append(('set_complex_tag', { + 'tag_name': 'greensFunction', + 'changes': dict(contour_tags) + })) + + if 'cfcoeff' in self.ctx: + #Take the output crystal field cofficients from the CFCoeffWorkchain + #TODO: Select spin channel + cf_coefficients = self.ctx.cfcoeff.outputs.output_cfcoeff_wc_para.dict.cf_coefficients_up + #Drop coefficients with negative m + cf_coefficients = {key: coeff for key, coeff in cf_coefficients.items() if '-' in key} + else: + cf_coefficients = self.ctx.wf_dict.get('cf_coefficients', {}) + + coefficient_tags = [] + for key, coeff in cf_coefficients.items(): + l, m = key.split('/') + coefficient_tags.append({'l': l, 'm': m, 'value': coeff}) + + exc_constant_tags = [] + exc_constant = self.ctx.wf_dict.get('exchange_constant', {}) + for l, exc_dict in exc_constant.items(): + exc_constant_tags.append({'l': l, **exc_dict}) + + for species_name, ldahia_dict in self.ctx.wf_dict['ldahia_dict'].items(): + if coefficient_tags: + ldahia_dict = {**ldahia_dict, 'cfCoeff': coefficient_tags} + + if exc_constant_tags: + ldahia_dict = {**ldahia_dict, 'exc': exc_constant_tags} + + if self.ctx.wf_dict['soc'] != 'auto': + ldahia_dict = {**ldahia_dict, 'addarg': {'key': 'xiSOC', 'value': self.ctx.wf_dict['soc']}} + + scf_wf_para['inpxml_changes'].append(('set_species', {'species_name': species_name, 'ldahia': ldahia_dict})) + + inputs_hubbard1.wf_parameters = orm.Dict(dict=scf_wf_para) + + return inputs_hubbard1 + + def run_hubbard1_calculation(self): + """ + Start the Hubbard1 calculation by submitting the SCF workchain with the correct inputs + """ + self.report('INFO: Starting Hubbard 1 calculation') + + inputs = self.create_hubbard1_input() + result = self.submit(FleurScfWorkChain, **inputs) + return ToContext(hubbard1=result) + + def inspect_hubbard1_calculation(self): + """ + Inspect the finished Hubbard 1 calculation + """ + if not self.ctx.hubbard1.is_finished_ok: + error = ('ERROR: Hubbard1 SCF workflow was not successful') + self.report(error) + return self.exit_codes.ERROR_HUBBARD1_CALCULATION_FAILED + + try: + self.ctx.hubbard1.outputs.output_scf_wc_para + except KeyError: + message = ('ERROR: Hubbard1 SCF workflow failed, no output node') + self.ctx.errors.append(message) + return self.exit_codes.ERROR_HUBBARD1_CALCULATION_FAILED + + def return_results(self): + pass From 11fa918864bbda2af63136228577c68d7796e76b Mon Sep 17 00:00:00 2001 From: janssenhenning Date: Fri, 21 Jan 2022 18:44:10 +0100 Subject: [PATCH 02/29] Add return_results --- aiida_fleur/workflows/hubbard1.py | 89 ++++++++++++++++++++++++++++--- 1 file changed, 81 insertions(+), 8 deletions(-) diff --git a/aiida_fleur/workflows/hubbard1.py b/aiida_fleur/workflows/hubbard1.py index fd2f4adc3..3c3517672 100644 --- a/aiida_fleur/workflows/hubbard1.py +++ b/aiida_fleur/workflows/hubbard1.py @@ -6,7 +6,8 @@ from collections import defaultdict from aiida.common import AttributeDict -from aiida.engine import WorkChain, ToContext, if_ +from aiida.common.exceptions import NotExistent +from aiida.engine import WorkChain, ToContext, if_, calcfunction from aiida import orm from aiida_fleur.workflows.scf import FleurScfWorkChain @@ -55,13 +56,14 @@ def define(cls, spec): }) spec.input('wf_parameters', valid_type=orm.Dict, required=False) + #TODO: hubbard1 calculation in loop until converged? spec.outline( cls.start, cls.validate_inputs, if_(cls.preliminary_calcs_needed)(cls.run_preliminary_calculations, cls.inspect_preliminary_calculations), cls.run_hubbard1_calculation, cls.inspect_hubbard1_calculation, cls.return_results) spec.output('output_hubbard1_wc_para', valid_type=orm.Dict) - spec.expose_outputs(FleurScfWorkChain, namespace='scf') + spec.expose_outputs(FleurScfWorkChain) spec.exit_code(230, 'ERROR_INVALID_INPUT_PARAM', message='Invalid workchain parameters.') spec.exit_code(231, 'ERROR_INVALID_INPUT_CONFIG', message='Invalid input configuration.') @@ -76,6 +78,10 @@ def start(self): self.ctx.run_preliminary = False self.ctx.fleurinp_hubbard1 = None + self.ctx.successful = True + self.ctx.info = [] + self.ctx.errors = [] + self.ctx.warnings = [] wf_default = self._default_wf_para if 'wf_parameters' in self.inputs: @@ -244,15 +250,82 @@ def inspect_hubbard1_calculation(self): """ if not self.ctx.hubbard1.is_finished_ok: error = ('ERROR: Hubbard1 SCF workflow was not successful') - self.report(error) - return self.exit_codes.ERROR_HUBBARD1_CALCULATION_FAILED + self.ctx.successful = False + self.control_end_wc(error) try: self.ctx.hubbard1.outputs.output_scf_wc_para except KeyError: - message = ('ERROR: Hubbard1 SCF workflow failed, no output node') - self.ctx.errors.append(message) - return self.exit_codes.ERROR_HUBBARD1_CALCULATION_FAILED + error = ('ERROR: Hubbard1 SCF workflow failed, no output node') + self.ctx.successful = False + self.control_end_wc(error) def return_results(self): - pass + """ + Return results of the hubbard1 workchain + """ + + try: # if something failed, we still might be able to retrieve something + last_calc_out = self.ctx.hubbard1.outputs.last_calc.output_parameters + retrieved = self.ctx.hubbard1.outputs.last_calc.retrieved + except (NotExistent, AttributeError): + last_calc_out = None + retrieved = None + + outputnode_dict = {} + + outputnode_dict['workflow_name'] = self.__class__.__name__ + outputnode_dict['warnings'] = self.ctx.warnings + outputnode_dict['info'] = self.ctx.info + outputnode_dict['errors'] = self.ctx.errors + outputnode_dict['successful'] = self.ctx.successful + #TODO: What should be in here + # - magnetic moments + # - orbital moments + # What else + + outputnode = orm.Dict(dict=outputnode_dict) + + outdict = create_hubbard1_result_node(outpara=outputnode, + last_calc_out=last_calc_out, + last_calc_retrieved=retrieved) + + if self.ctx.hubbard1: + self.out_many(self.exposed_outputs(self.ctx.hubbard1, FleurScfWorkChain)) + + for link_name, node in outdict.items(): + self.out(link_name, node) + + if not self.ctx.successful: + return self.exit_codes.ERROR_HUBBARD1_CALCULATION_FAILED + + def control_end_wc(self, errormsg): + """ + Controlled way to shutdown the workchain. will initialize the output nodes + The shutdown of the workchain will has to be done afterwards + """ + self.ctx.successful = False + self.ctx.abort = True + self.report(errormsg) # because return_results still fails somewhen + self.ctx.errors.append(errormsg) + self.return_results() + + +@calcfunction +def create_hubbard1_result_node(**kwargs): + """ + This is a pseudo wf, to create the right graph structure of AiiDA. + This wokfunction will create the output node in the database. + It also connects the output_node to all nodes the information commes from. + So far it is just also parsed in as argument, because so far we are to lazy + to put most of the code overworked from return_results in here. + """ + outpara = kwargs['outpara'] #Should always be there + outdict = {} + outputnode = outpara.clone() + outputnode.label = 'output_hubbard1_wc_para' + outputnode.description = ( + 'Contains self-consistency/magnetic information results and information of an FleurHubbard1WorkChain run.') + + outdict['output_hubbard1_wc_para'] = outputnode + return outdict From c6aa4ed8657c8f5a80f9deb416c5e7f9ceebb5f0 Mon Sep 17 00:00:00 2001 From: janssenhenning Date: Fri, 21 Jan 2022 18:55:35 +0100 Subject: [PATCH 03/29] Add entry point --- setup.json | 1 + tests/test_entrypoints.py | 7 +++++++ tests/test_workflows_builder_init.py | 8 ++++++++ 3 files changed, 16 insertions(+) diff --git a/setup.json b/setup.json index 6eb09da3b..5af9802a1 100644 --- a/setup.json +++ b/setup.json @@ -85,6 +85,7 @@ "fleur.strain = aiida_fleur.workflows.strain:FleurStrainWorkChain", "fleur.eos = aiida_fleur.workflows.eos:FleurEosWorkChain", "fleur.cfcoeff = aiida_fleur.workflows.cfcoeff:FleurCFCoeffWorkChain", + "fleur.hubbard1 = aiida_fleur.workflows.hubbard1:FleurHubbard1WorkChain", "fleur.init_cls = aiida_fleur.workflows.initial_cls:FleurInitialCLSWorkChain", "fleur.corehole = aiida_fleur.workflows.corehole:FleurCoreholeWorkChain", "fleur.mae = aiida_fleur.workflows.mae:FleurMaeWorkChain", diff --git a/tests/test_entrypoints.py b/tests/test_entrypoints.py index 637077e22..47d0c52c2 100644 --- a/tests/test_entrypoints.py +++ b/tests/test_entrypoints.py @@ -178,3 +178,10 @@ def test_fleur_cfcoeff_wc_entry_point(self): workflow = WorkflowFactory('fleur.cfcoeff') assert workflow == FleurCFCoeffWorkChain + + def test_fleur_hubbard1_wc_entry_point(self): + from aiida.plugins import WorkflowFactory + from aiida_fleur.workflows.hubbard1 import FleurHubbard1WorkChain + + workflow = WorkflowFactory('fleur.hubbard1') + assert workflow == FleurHubbard1WorkChain diff --git a/tests/test_workflows_builder_init.py b/tests/test_workflows_builder_init.py index 270e7c402..fcdc2626a 100644 --- a/tests/test_workflows_builder_init.py +++ b/tests/test_workflows_builder_init.py @@ -164,3 +164,11 @@ def test_fleur_cfcoeff_wc_init(self): from aiida_fleur.workflows.cfcoeff import FleurCFCoeffWorkChain builder = FleurCFCoeffWorkChain.get_builder() + + def test_fleur_hubbard1_wc_init(self): + """ + Test the interface of the cfcoeff workchain + """ + from aiida_fleur.workflows.hubbard1 import FleurHubbard1WorkChain + + builder = FleurHubbard1WorkChain.get_builder() From 043be80558383fbb89ff17088c72325ec3a3109e Mon Sep 17 00:00:00 2001 From: janssenhenning Date: Fri, 21 Jan 2022 19:05:39 +0100 Subject: [PATCH 04/29] Correct exception to catch missing output nodes --- aiida_fleur/workflows/hubbard1.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aiida_fleur/workflows/hubbard1.py b/aiida_fleur/workflows/hubbard1.py index 3c3517672..764d187f2 100644 --- a/aiida_fleur/workflows/hubbard1.py +++ b/aiida_fleur/workflows/hubbard1.py @@ -145,7 +145,7 @@ def inspect_preliminary_calculations(self): try: self.ctx.cfcoeff.outputs.output_cfcoeff_wc_para - except KeyError: + except NotExistent: message = ('ERROR: CFCoeff workflow failed, no output node') self.ctx.errors.append(message) return self.exit_codes.ERROR_CFCOEFF_CALCULATION_FAILED @@ -255,7 +255,7 @@ def inspect_hubbard1_calculation(self): try: self.ctx.hubbard1.outputs.output_scf_wc_para - except KeyError: + except NotExistent: error = ('ERROR: Hubbard1 SCF workflow failed, no output node') self.ctx.successful = False self.control_end_wc(error) From 531758b7534bd8d4e978eeb23bf24d774e010e00 Mon Sep 17 00:00:00 2001 From: janssenhenning Date: Fri, 21 Jan 2022 19:19:13 +0100 Subject: [PATCH 05/29] Correct workflowversion attribute name --- aiida_fleur/workflows/hubbard1.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/aiida_fleur/workflows/hubbard1.py b/aiida_fleur/workflows/hubbard1.py index 764d187f2..2be120654 100644 --- a/aiida_fleur/workflows/hubbard1.py +++ b/aiida_fleur/workflows/hubbard1.py @@ -19,7 +19,7 @@ class FleurHubbard1WorkChain(WorkChain): WorkChain for performing Hubbard-1 calculations """ - _workflow_version = '0.0.1' + _workflowversion = '0.0.1' _default_wf_para = { 'ldahia_dict': None, @@ -275,6 +275,7 @@ def return_results(self): outputnode_dict = {} outputnode_dict['workflow_name'] = self.__class__.__name__ + outputnode_dict['workflow_version'] = self._workflowversion outputnode_dict['warnings'] = self.ctx.warnings outputnode_dict['info'] = self.ctx.info outputnode_dict['errors'] = self.ctx.errors From a6826f4de467aeb5acd913c771dde71f18b28892 Mon Sep 17 00:00:00 2001 From: janssenhenning Date: Fri, 21 Jan 2022 19:22:09 +0100 Subject: [PATCH 06/29] fix typo --- aiida_fleur/workflows/hubbard1.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aiida_fleur/workflows/hubbard1.py b/aiida_fleur/workflows/hubbard1.py index 2be120654..4cd4b3efe 100644 --- a/aiida_fleur/workflows/hubbard1.py +++ b/aiida_fleur/workflows/hubbard1.py @@ -116,7 +116,7 @@ def preliminary_calcs_needed(self): """ Return whether calculations need to be run before the hubbard 1 calculation """ - return self.ctx.run_prelimiary + return self.ctx.run_preliminary def run_preliminary_calculations(self): """ From 1d0cf0102e6c913c5e2e999e8469915fe47542c9 Mon Sep 17 00:00:00 2001 From: janssenhenning Date: Fri, 21 Jan 2022 19:26:23 +0100 Subject: [PATCH 07/29] fix format --- tests/test_entrypoints.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_entrypoints.py b/tests/test_entrypoints.py index 47d0c52c2..2a51a5abb 100644 --- a/tests/test_entrypoints.py +++ b/tests/test_entrypoints.py @@ -178,7 +178,7 @@ def test_fleur_cfcoeff_wc_entry_point(self): workflow = WorkflowFactory('fleur.cfcoeff') assert workflow == FleurCFCoeffWorkChain - + def test_fleur_hubbard1_wc_entry_point(self): from aiida.plugins import WorkflowFactory from aiida_fleur.workflows.hubbard1 import FleurHubbard1WorkChain From fd5ab945a95e353cfe9967b69a7a89c3f2e902df Mon Sep 17 00:00:00 2001 From: janssenhenning Date: Sat, 22 Jan 2022 11:22:05 +0100 Subject: [PATCH 08/29] Correct name of namespace for hubbard 1 --- aiida_fleur/workflows/hubbard1.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aiida_fleur/workflows/hubbard1.py b/aiida_fleur/workflows/hubbard1.py index 4cd4b3efe..4fe0fc676 100644 --- a/aiida_fleur/workflows/hubbard1.py +++ b/aiida_fleur/workflows/hubbard1.py @@ -154,7 +154,7 @@ def create_hubbard1_input(self): """ Create the inpxml_changes input to create the hubbard 1 input """ - inputs_hubbard1 = AttributeDict(self.exposed_inputs(FleurScfWorkChain, namespace='scf')) + inputs_hubbard1 = AttributeDict(self.exposed_inputs(FleurScfWorkChain, namespace='hubbard1_scf')) if 'wf_parameters' in inputs_hubbard1: scf_wf_para = inputs_hubbard1.wf_parameters.get_dict() From 27f1ffd8dbc1505eb8a031b13317d2bb39ff3102 Mon Sep 17 00:00:00 2001 From: janssenhenning Date: Sun, 23 Jan 2022 14:46:41 +0100 Subject: [PATCH 09/29] Correct set_species change in hubbard1 wc --- aiida_fleur/workflows/hubbard1.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/aiida_fleur/workflows/hubbard1.py b/aiida_fleur/workflows/hubbard1.py index 4fe0fc676..8452b958d 100644 --- a/aiida_fleur/workflows/hubbard1.py +++ b/aiida_fleur/workflows/hubbard1.py @@ -228,7 +228,12 @@ def create_hubbard1_input(self): if self.ctx.wf_dict['soc'] != 'auto': ldahia_dict = {**ldahia_dict, 'addarg': {'key': 'xiSOC', 'value': self.ctx.wf_dict['soc']}} - scf_wf_para['inpxml_changes'].append(('set_species', {'species_name': species_name, 'ldahia': ldahia_dict})) + scf_wf_para['inpxml_changes'].append(('set_species', { + 'species_name': species_name, + 'attributedict': { + 'ldahia': ldahia_dict + } + })) inputs_hubbard1.wf_parameters = orm.Dict(dict=scf_wf_para) From fadd52849e7faccc7be9c54f2e4970f5da67d022 Mon Sep 17 00:00:00 2001 From: janssenhenning Date: Sun, 23 Jan 2022 15:05:32 +0100 Subject: [PATCH 10/29] Fix name of number of energy points --- aiida_fleur/workflows/hubbard1.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aiida_fleur/workflows/hubbard1.py b/aiida_fleur/workflows/hubbard1.py index 8452b958d..61297449b 100644 --- a/aiida_fleur/workflows/hubbard1.py +++ b/aiida_fleur/workflows/hubbard1.py @@ -37,7 +37,7 @@ class FleurHubbard1WorkChain(WorkChain): 'energy_grid': { 'ellow': -1.0, 'elup': 1.0, - 'n': 5400 + 'ne': 5400 }, 'inpxml_changes': [], } From 36de5028ae3a24d30fc5fd403281f958168fbba9 Mon Sep 17 00:00:00 2001 From: janssenhenning Date: Mon, 24 Jan 2022 09:34:29 +0100 Subject: [PATCH 11/29] Make sure that the defaults are not mutated --- aiida_fleur/workflows/hubbard1.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/aiida_fleur/workflows/hubbard1.py b/aiida_fleur/workflows/hubbard1.py index 61297449b..ba848d199 100644 --- a/aiida_fleur/workflows/hubbard1.py +++ b/aiida_fleur/workflows/hubbard1.py @@ -4,6 +4,7 @@ a complete hubbard 1 calculation including calculating model parameters beforehand """ from collections import defaultdict +import copy from aiida.common import AttributeDict from aiida.common.exceptions import NotExistent @@ -83,7 +84,7 @@ def start(self): self.ctx.errors = [] self.ctx.warnings = [] - wf_default = self._default_wf_para + wf_default = copy.deepcopy(self._default_wf_para) if 'wf_parameters' in self.inputs: wf_dict = self.inputs.wf_parameters.get_dict() else: From 701fa352eeb586b05236bbe86026008f8383c829 Mon Sep 17 00:00:00 2001 From: janssenhenning Date: Tue, 25 Jan 2022 12:07:40 +0100 Subject: [PATCH 12/29] Correct name of cf_coefficients output name --- aiida_fleur/workflows/hubbard1.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aiida_fleur/workflows/hubbard1.py b/aiida_fleur/workflows/hubbard1.py index ba848d199..16d791ef2 100644 --- a/aiida_fleur/workflows/hubbard1.py +++ b/aiida_fleur/workflows/hubbard1.py @@ -203,7 +203,7 @@ def create_hubbard1_input(self): if 'cfcoeff' in self.ctx: #Take the output crystal field cofficients from the CFCoeffWorkchain #TODO: Select spin channel - cf_coefficients = self.ctx.cfcoeff.outputs.output_cfcoeff_wc_para.dict.cf_coefficients_up + cf_coefficients = self.ctx.cfcoeff.outputs.output_cfcoeff_wc_para.dict.cf_coefficients_spin_up #Drop coefficients with negative m cf_coefficients = {key: coeff for key, coeff in cf_coefficients.items() if '-' in key} else: From 0183c782cafc6ac399ccbd8466e08a90d49e943d Mon Sep 17 00:00:00 2001 From: janssenhenning Date: Tue, 25 Jan 2022 12:54:46 +0100 Subject: [PATCH 13/29] Also retrieve n_mmp_mat file for hubbard1 calculations --- aiida_fleur/calculation/fleur.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aiida_fleur/calculation/fleur.py b/aiida_fleur/calculation/fleur.py index f4cc50041..080662711 100644 --- a/aiida_fleur/calculation/fleur.py +++ b/aiida_fleur/calculation/fleur.py @@ -388,7 +388,7 @@ def prepare_for_submission(self, folder): if modes['relax']: # if l_f="T" retrieve relax.xml mode_retrieved_filelist.append(self._RELAX_FILE_NAME) - if modes['ldau']: + if modes['ldau'] or modes['ldahia']: if with_hdf5: mode_retrieved_filelist.append(self._NMMPMAT_HDF5_FILE_NAME) else: From ec956ed16024392a1c3025709c788e44249fa7b2 Mon Sep 17 00:00:00 2001 From: janssenhenning Date: Tue, 25 Jan 2022 13:57:38 +0100 Subject: [PATCH 14/29] Condition for excluding coefficients with negative m was the wrong way around --- aiida_fleur/workflows/hubbard1.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aiida_fleur/workflows/hubbard1.py b/aiida_fleur/workflows/hubbard1.py index 16d791ef2..b79571207 100644 --- a/aiida_fleur/workflows/hubbard1.py +++ b/aiida_fleur/workflows/hubbard1.py @@ -205,7 +205,7 @@ def create_hubbard1_input(self): #TODO: Select spin channel cf_coefficients = self.ctx.cfcoeff.outputs.output_cfcoeff_wc_para.dict.cf_coefficients_spin_up #Drop coefficients with negative m - cf_coefficients = {key: coeff for key, coeff in cf_coefficients.items() if '-' in key} + cf_coefficients = {key: coeff for key, coeff in cf_coefficients.items() if '-' not in key} else: cf_coefficients = self.ctx.wf_dict.get('cf_coefficients', {}) From a9466ac0d54a7d2e544e52adaac4126d7af01933 Mon Sep 17 00:00:00 2001 From: janssenhenning Date: Tue, 25 Jan 2022 14:05:45 +0100 Subject: [PATCH 15/29] fix typo --- aiida_fleur/workflows/hubbard1.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aiida_fleur/workflows/hubbard1.py b/aiida_fleur/workflows/hubbard1.py index b79571207..ec683ab6f 100644 --- a/aiida_fleur/workflows/hubbard1.py +++ b/aiida_fleur/workflows/hubbard1.py @@ -215,7 +215,7 @@ def create_hubbard1_input(self): coefficient_tags.append({'l': l, 'm': m, 'value': coeff}) exc_constant_tags = [] - exc_constant = self.ctx.wf_dict.get('exchange_constant', {}) + exc_constant = self.ctx.wf_dict.get('exchange_constants', {}) for l, exc_dict in exc_constant.items(): exc_constant_tags.append({'l': l, **exc_dict}) From 5a00cb20d0ead728247bd74d27b7e6b539c1e81b Mon Sep 17 00:00:00 2001 From: janssenhenning Date: Thu, 27 Jan 2022 14:48:01 +0100 Subject: [PATCH 16/29] FIx wrong convention used from the crystal field coefficients --- aiida_fleur/workflows/hubbard1.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/aiida_fleur/workflows/hubbard1.py b/aiida_fleur/workflows/hubbard1.py index ec683ab6f..6b8ad339b 100644 --- a/aiida_fleur/workflows/hubbard1.py +++ b/aiida_fleur/workflows/hubbard1.py @@ -107,10 +107,15 @@ def validate_inputs(self): inputs = self.inputs if 'cfcoeff' in inputs: + if 'wf_parameters' in inputs: + if inputs.wf_parameters.get_dict().get('convert_to_stevens') is True: + error = 'ERROR: you gave cfcoeff input with explcitly setting convert_to_setvens to True. This needs to be False' + self.report(error) + return self.exit_codes.ERROR_INVALID_INPUT_PARAM self.ctx.run_preliminary = True if self.ctx.wf_dict['cf_coefficients'] is not None: error = 'ERROR: you gave cfcoeff input + explicit cf_coefficients in wf_parameters' - self.control_end_wc(error) + self.report(error) return self.exit_codes.ERROR_INVALID_INPUT_CONFIG def preliminary_calcs_needed(self): @@ -131,6 +136,15 @@ def run_preliminary_calculations(self): self.report('INFO: Starting Crystal field calculation') inputs = AttributeDict(self.exposed_inputs(FleurCFCoeffWorkChain, namespace='cfcoeff')) + + if 'wf_parameters' in inputs: + if 'convert_to_stevens' not in inputs: + inputs.wf_parameters = orm.Dict(dict={ + **inputs.wf_parameters.get_dict(), 'convert_to_stevens': False + }) + else: + inputs.wf_parameters = orm.Dict(dict={'convert_to_stevens': False}) + calcs['cfcoeff'] = self.submit(FleurCFCoeffWorkChain, **inputs) return ToContext(**calcs) From e16fe622d5721ad0a5f9c301c14b6bda49186228 Mon Sep 17 00:00:00 2001 From: janssenhenning Date: Mon, 31 Jan 2022 09:29:48 +0100 Subject: [PATCH 17/29] Experimental: Also retrieve Hubbard1 subfolder For now all files are retrieved. It might be better to limit the data --- aiida_fleur/calculation/fleur.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/aiida_fleur/calculation/fleur.py b/aiida_fleur/calculation/fleur.py index 080662711..e27a265d4 100644 --- a/aiida_fleur/calculation/fleur.py +++ b/aiida_fleur/calculation/fleur.py @@ -104,6 +104,9 @@ class FleurCalculation(CalcJob): #files for greensfunctions _GREENSF_HDF5_FILE_NAME = 'greensf.hdf' + #Name of the folder containing the hubbard1 results + _HUBBARD1_FOLDER_NAME = 'Hubbard1' + # files for hybrid functionals _COULOMB1_FILE_NAME = 'coulomb1' _MIXBAS_FILE_NAME = 'mixbas' @@ -393,6 +396,8 @@ def prepare_for_submission(self, folder): mode_retrieved_filelist.append(self._NMMPMAT_HDF5_FILE_NAME) else: mode_retrieved_filelist.append(self._NMMPMAT_FILE_NAME) + if modes['ldahia']: + mode_retrieved_filelist.append(self._HUBBARD1_FOLDER_NAME) if with_hdf5 and modes['greensf']: mode_retrieved_filelist.append(self._GREENSF_HDF5_FILE_NAME) if modes['cf_coeff']: From acc51d4fe07843e3e37a91727b651582c2537a3f Mon Sep 17 00:00:00 2001 From: janssenhenning Date: Tue, 1 Feb 2022 11:58:07 +0100 Subject: [PATCH 18/29] Add detection of a non-converged hubbard1 calculation. This only works with the upcoming release --- aiida_fleur/workflows/scf.py | 48 +++++++++++++++++++++++++++++++++--- 1 file changed, 44 insertions(+), 4 deletions(-) diff --git a/aiida_fleur/workflows/scf.py b/aiida_fleur/workflows/scf.py index c2ba8ba3b..28a581044 100644 --- a/aiida_fleur/workflows/scf.py +++ b/aiida_fleur/workflows/scf.py @@ -71,6 +71,8 @@ class FleurScfWorkChain(WorkChain): 'kpoints_force_even': False, 'kpoints_force_gamma': False, 'nmmp_converged': 0.002, + 'hubbard1_occ_converged': 0.01, + 'hubbard1_elem_converged': 0.001, 'mode': 'density', # 'density', 'energy', 'force' or 'gw' 'add_comp_para': { 'only_even_MPI': False, @@ -216,10 +218,14 @@ def start(self): self.ctx.all_forces = [] self.ctx.total_energy = [] self.ctx.nmmp_distance = [] + self.ctx.hubbard1_occ_distance = [] + self.ctx.hubbard1_elem_distance = [] self.ctx.energydiff = 10000 self.ctx.forcediff = 10000 self.ctx.last_charge_density = 10000 self.ctx.last_nmmp_distance = -10000 + self.ctx.last_hubbard1_occ_distance = -10000 + self.ctx.last_hubbard1_elem_distance = -10000 self.ctx.warnings = [] # "debug": {}, self.ctx.errors = [] @@ -668,6 +674,15 @@ def get_res(self): if nmmp_distances is not None: self.ctx.nmmp_distance.extend(nmmp_distances) + + if 'ldahia_info' in output_dict: + occ_distances = output_dict['ldahia_info'].get('occupation_distance', []) + elem_distances = output_dict['ldahia_info'].get('element_distance', []) + + if occ_distances: + #Assume both worked + self.ctx.hubbard1_occ_distance.extend(occ_distances) + self.ctx.hubbard1_elem_distance.extend(elem_distances) if mode == 'force': forces = output_dict.get('force_atoms', []) @@ -709,6 +724,7 @@ def condition(self): self.report('INFO: checking condition FLEUR') mode = self.ctx.wf_dict['mode'] ldau_notconverged = False + ldahia_notconverged = False energy = self.ctx.total_energy if len(energy) >= 2: @@ -725,14 +741,22 @@ def condition(self): if self.ctx.last_nmmp_distance > 0.0 and \ self.ctx.last_nmmp_distance >= self.ctx.wf_dict['nmmp_converged']: ldau_notconverged = True + + if self.ctx.last_hubbard1_occ_distance > 0.0 and \ + self.ctx.last_hubbard1_occ_distance >= self.ctx.wf_dict['hubbard1_occ_converged']: + ldahia_notconverged = True + + if self.ctx.last_hubbard1_elem_distance > 0.0 and \ + self.ctx.last_hubbard1_elem_distance >= self.ctx.wf_dict['hubbard1_elem_converged']: + ldahia_notconverged = True if mode == 'density': if self.ctx.wf_dict['density_converged'] >= self.ctx.last_charge_density: - if not ldau_notconverged: + if not ldau_notconverged or not ldahia_notconverged: return False elif mode in ('energy', 'spex'): if self.ctx.wf_dict['energy_converged'] >= self.ctx.energydiff: - if not ldau_notconverged: + if not ldau_notconverged or not ldahia_notconverged: return False elif mode == 'force': if self.ctx.last_charge_density is None: @@ -741,7 +765,7 @@ def condition(self): except NotExistent: pass else: - if not ldau_notconverged: + if not ldau_notconverged or not ldahia_notconverged: return False elif self.ctx.wf_dict['density_converged'] >= self.ctx.last_charge_density: @@ -750,7 +774,7 @@ def condition(self): except NotExistent: pass else: - if not ldau_notconverged: + if not ldau_notconverged or not ldahia_notconverged: return False if self.ctx.loop_count >= self.ctx.max_number_runs: @@ -785,6 +809,14 @@ def return_results(self): last_nmmp_distance = None if self.ctx.last_nmmp_distance > 0.0: last_nmmp_distance = self.ctx.last_nmmp_distance + + last_hubbard1_occ_distance = None + if self.ctx.last_hubbard1_occ_distance > 0.0: + last_hubbard1_occ_distance = self.ctx.last_hubbard1_occ_distance + + last_hubbard1_elem_distance = None + if self.ctx.last_hubbard1_elem_distance > 0.0: + last_hubbard1_elem_distance = self.ctx.last_hubbard1_elem_distance outputnode_dict = {} outputnode_dict['workflow_name'] = self.__class__.__name__ @@ -803,6 +835,10 @@ def return_results(self): outputnode_dict['total_energy_units'] = 'Htr' outputnode_dict['nmmp_distance'] = last_nmmp_distance outputnode_dict['nmmp_distance_all'] = self.ctx.nmmp_distance + outputnode_dict['hubbard1_occ_distance'] = last_hubbard1_occ_distance + outputnode_dict['hubbard1_occ_distance_all'] = self.ctx.hubbard1_occ_distance + outputnode_dict['hubbard1_elem_distance'] = last_hubbard1_elem_distance + outputnode_dict['hubbard1_elem_distance_all'] = self.ctx.hubbard1_elem_distance outputnode_dict['last_calc_uuid'] = last_calc_uuid outputnode_dict['total_wall_time'] = self.ctx.total_wall_time outputnode_dict['total_wall_time_units'] = 's' @@ -856,6 +892,10 @@ def return_results(self): if self.ctx.last_nmmp_distance > 0.0: self.report(f'INFO: The LDA+U density matrix is converged to {self.ctx.last_nmmp_distance} change ' 'of all matrix elements') + + if self.ctx.last_hubbard1_occ_distance > 0.0: + self.report(f'INFO: The LDA+Hubbard 1 density matrix is converged to {self.ctx.last_hubbard1_occ_distance} change ' + f'of occupation and {self.ctx.last_hubbard1_elem_distance} change of all matrix elements') outputnode_t = Dict(dict=outputnode_dict) # this is unsafe so far, because last_calc_out could not exist... From d1d7c12dd41d04eeadf5b8c7e9f53de19692e98c Mon Sep 17 00:00:00 2001 From: janssenhenning Date: Tue, 1 Feb 2022 12:05:40 +0100 Subject: [PATCH 19/29] formatting fixes --- aiida_fleur/workflows/scf.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/aiida_fleur/workflows/scf.py b/aiida_fleur/workflows/scf.py index 28a581044..3e565007f 100644 --- a/aiida_fleur/workflows/scf.py +++ b/aiida_fleur/workflows/scf.py @@ -674,7 +674,7 @@ def get_res(self): if nmmp_distances is not None: self.ctx.nmmp_distance.extend(nmmp_distances) - + if 'ldahia_info' in output_dict: occ_distances = output_dict['ldahia_info'].get('occupation_distance', []) elem_distances = output_dict['ldahia_info'].get('element_distance', []) @@ -741,11 +741,11 @@ def condition(self): if self.ctx.last_nmmp_distance > 0.0 and \ self.ctx.last_nmmp_distance >= self.ctx.wf_dict['nmmp_converged']: ldau_notconverged = True - + if self.ctx.last_hubbard1_occ_distance > 0.0 and \ self.ctx.last_hubbard1_occ_distance >= self.ctx.wf_dict['hubbard1_occ_converged']: ldahia_notconverged = True - + if self.ctx.last_hubbard1_elem_distance > 0.0 and \ self.ctx.last_hubbard1_elem_distance >= self.ctx.wf_dict['hubbard1_elem_converged']: ldahia_notconverged = True @@ -809,11 +809,11 @@ def return_results(self): last_nmmp_distance = None if self.ctx.last_nmmp_distance > 0.0: last_nmmp_distance = self.ctx.last_nmmp_distance - + last_hubbard1_occ_distance = None if self.ctx.last_hubbard1_occ_distance > 0.0: last_hubbard1_occ_distance = self.ctx.last_hubbard1_occ_distance - + last_hubbard1_elem_distance = None if self.ctx.last_hubbard1_elem_distance > 0.0: last_hubbard1_elem_distance = self.ctx.last_hubbard1_elem_distance @@ -892,10 +892,11 @@ def return_results(self): if self.ctx.last_nmmp_distance > 0.0: self.report(f'INFO: The LDA+U density matrix is converged to {self.ctx.last_nmmp_distance} change ' 'of all matrix elements') - + if self.ctx.last_hubbard1_occ_distance > 0.0: - self.report(f'INFO: The LDA+Hubbard 1 density matrix is converged to {self.ctx.last_hubbard1_occ_distance} change ' - f'of occupation and {self.ctx.last_hubbard1_elem_distance} change of all matrix elements') + self.report( + f'INFO: The LDA+Hubbard 1 density matrix is converged to {self.ctx.last_hubbard1_occ_distance} change ' + f'of occupation and {self.ctx.last_hubbard1_elem_distance} change of all matrix elements') outputnode_t = Dict(dict=outputnode_dict) # this is unsafe so far, because last_calc_out could not exist... From dd1fa3730fbef9c7a007a9b87bae837c135fc1b0 Mon Sep 17 00:00:00 2001 From: janssenhenning Date: Wed, 2 Feb 2022 10:35:27 +0100 Subject: [PATCH 20/29] Add rudimentary support for multiple atomtypes coming from the crystal field coefficient workchain --- aiida_fleur/workflows/hubbard1.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/aiida_fleur/workflows/hubbard1.py b/aiida_fleur/workflows/hubbard1.py index 6b8ad339b..fae8eacfe 100644 --- a/aiida_fleur/workflows/hubbard1.py +++ b/aiida_fleur/workflows/hubbard1.py @@ -218,6 +218,10 @@ def create_hubbard1_input(self): #Take the output crystal field cofficients from the CFCoeffWorkchain #TODO: Select spin channel cf_coefficients = self.ctx.cfcoeff.outputs.output_cfcoeff_wc_para.dict.cf_coefficients_spin_up + if all(isinstance(key, int) for key in cf_coefficients): + self.report('WARNING: Crystal field coefficients from multiple atomtypes not supported fully') + _, cf_coefficients = cf_coefficients.popitem() #Just take one (To support multiple we need to split up species) + #Drop coefficients with negative m cf_coefficients = {key: coeff for key, coeff in cf_coefficients.items() if '-' not in key} else: From 86bd336f3af170602492e8ea31267c55ef0ef75d Mon Sep 17 00:00:00 2001 From: janssenhenning Date: Wed, 2 Feb 2022 12:57:58 +0100 Subject: [PATCH 21/29] Correct condition --- aiida_fleur/workflows/hubbard1.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aiida_fleur/workflows/hubbard1.py b/aiida_fleur/workflows/hubbard1.py index fae8eacfe..b7e29f4a2 100644 --- a/aiida_fleur/workflows/hubbard1.py +++ b/aiida_fleur/workflows/hubbard1.py @@ -218,7 +218,7 @@ def create_hubbard1_input(self): #Take the output crystal field cofficients from the CFCoeffWorkchain #TODO: Select spin channel cf_coefficients = self.ctx.cfcoeff.outputs.output_cfcoeff_wc_para.dict.cf_coefficients_spin_up - if all(isinstance(key, int) for key in cf_coefficients): + if all('/' not in key for key in cf_coefficients): self.report('WARNING: Crystal field coefficients from multiple atomtypes not supported fully') _, cf_coefficients = cf_coefficients.popitem() #Just take one (To support multiple we need to split up species) From 18ba797cd258420a147c65157802194570286be7 Mon Sep 17 00:00:00 2001 From: janssenhenning Date: Mon, 14 Feb 2022 10:23:57 +0100 Subject: [PATCH 22/29] Fix for not specifying cfcoefficients in hubbard1 input --- aiida_fleur/workflows/hubbard1.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/aiida_fleur/workflows/hubbard1.py b/aiida_fleur/workflows/hubbard1.py index b7e29f4a2..db789a587 100644 --- a/aiida_fleur/workflows/hubbard1.py +++ b/aiida_fleur/workflows/hubbard1.py @@ -228,12 +228,14 @@ def create_hubbard1_input(self): cf_coefficients = self.ctx.wf_dict.get('cf_coefficients', {}) coefficient_tags = [] + cf_coefficients = cf_coefficients or {} for key, coeff in cf_coefficients.items(): l, m = key.split('/') coefficient_tags.append({'l': l, 'm': m, 'value': coeff}) exc_constant_tags = [] exc_constant = self.ctx.wf_dict.get('exchange_constants', {}) + exc_constant = exc_constant or {} for l, exc_dict in exc_constant.items(): exc_constant_tags.append({'l': l, **exc_dict}) From 03980915cfbab27ca0638c07ee0bb6268681063c Mon Sep 17 00:00:00 2001 From: janssenhenning Date: Mon, 28 Feb 2022 16:11:56 +0100 Subject: [PATCH 23/29] Allow setting the exchange field explicitely --- aiida_fleur/workflows/hubbard1.py | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/aiida_fleur/workflows/hubbard1.py b/aiida_fleur/workflows/hubbard1.py index db789a587..5e311dcb7 100644 --- a/aiida_fleur/workflows/hubbard1.py +++ b/aiida_fleur/workflows/hubbard1.py @@ -26,6 +26,7 @@ class FleurHubbard1WorkChain(WorkChain): 'ldahia_dict': None, 'soc': 'auto', 'exchange_constants': None, + 'exchange_field': None, 'cf_coefficients': None, 'occupation_converged': 0.01, 'matrix_elements_converged': 0.001, @@ -118,6 +119,12 @@ def validate_inputs(self): self.report(error) return self.exit_codes.ERROR_INVALID_INPUT_CONFIG + if self.ctx.wf_dict['exchange_constants'] is not None and \ + self.ctx.wf_dict['exchange_field'] is not None: + error = 'ERROR: you gave exchange_constants input + exchange_field in wf_parameters' + self.report(error) + return self.exit_codes.ERROR_INVALID_INPUT_CONFIG + def preliminary_calcs_needed(self): """ Return whether calculations need to be run before the hubbard 1 calculation @@ -220,7 +227,8 @@ def create_hubbard1_input(self): cf_coefficients = self.ctx.cfcoeff.outputs.output_cfcoeff_wc_para.dict.cf_coefficients_spin_up if all('/' not in key for key in cf_coefficients): self.report('WARNING: Crystal field coefficients from multiple atomtypes not supported fully') - _, cf_coefficients = cf_coefficients.popitem() #Just take one (To support multiple we need to split up species) + _, cf_coefficients = cf_coefficients.popitem( + ) #Just take one (To support multiple we need to split up species) #Drop coefficients with negative m cf_coefficients = {key: coeff for key, coeff in cf_coefficients.items() if '-' not in key} @@ -239,6 +247,13 @@ def create_hubbard1_input(self): for l, exc_dict in exc_constant.items(): exc_constant_tags.append({'l': l, **exc_dict}) + addarg_tags = [] + if self.ctx.wf_dict['soc'] != 'auto': + addarg_tags.append({'key': 'xiSOC', 'value': self.ctx.wf_dict['soc']}) + + if self.ctx.wf_dict['exchange_field'] is not None: + addarg_tags.append({'key': 'Exc', 'value': self.ctx.wf_dict['exchange_field']}) + for species_name, ldahia_dict in self.ctx.wf_dict['ldahia_dict'].items(): if coefficient_tags: ldahia_dict = {**ldahia_dict, 'cfCoeff': coefficient_tags} @@ -246,8 +261,8 @@ def create_hubbard1_input(self): if exc_constant_tags: ldahia_dict = {**ldahia_dict, 'exc': exc_constant_tags} - if self.ctx.wf_dict['soc'] != 'auto': - ldahia_dict = {**ldahia_dict, 'addarg': {'key': 'xiSOC', 'value': self.ctx.wf_dict['soc']}} + if addarg_tags: + ldahia_dict.setdefault('addarg', []).extend(addarg_tags) scf_wf_para['inpxml_changes'].append(('set_species', { 'species_name': species_name, From 8ed5e55d2d67342c935320a96c372f0717b51438 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 30 Mar 2022 14:19:19 +0000 Subject: [PATCH 24/29] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- aiida_fleur/workflows/hubbard1.py | 1 - 1 file changed, 1 deletion(-) diff --git a/aiida_fleur/workflows/hubbard1.py b/aiida_fleur/workflows/hubbard1.py index 5e311dcb7..75b95e9c3 100644 --- a/aiida_fleur/workflows/hubbard1.py +++ b/aiida_fleur/workflows/hubbard1.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- """ This module contains the FleurHubbard1WorkChain, which is used to perform a complete hubbard 1 calculation including calculating model parameters beforehand From 4f11f0236755568a6eb9e644d3a0c6e0498ac0c4 Mon Sep 17 00:00:00 2001 From: janssenhenning Date: Thu, 31 Mar 2022 12:23:07 +0200 Subject: [PATCH 25/29] Fix detection of non-converged LDA+U/LDA+HIA the previous condition would abort always if the criteria were reached --- aiida_fleur/workflows/scf.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/aiida_fleur/workflows/scf.py b/aiida_fleur/workflows/scf.py index 3e565007f..c7fc341cc 100644 --- a/aiida_fleur/workflows/scf.py +++ b/aiida_fleur/workflows/scf.py @@ -750,13 +750,14 @@ def condition(self): self.ctx.last_hubbard1_elem_distance >= self.ctx.wf_dict['hubbard1_elem_converged']: ldahia_notconverged = True + ignore_convergence_criteria = ldau_notconverged or ldahia_notconverged if mode == 'density': if self.ctx.wf_dict['density_converged'] >= self.ctx.last_charge_density: - if not ldau_notconverged or not ldahia_notconverged: + if not ignore_convergence_criteria: return False elif mode in ('energy', 'spex'): if self.ctx.wf_dict['energy_converged'] >= self.ctx.energydiff: - if not ldau_notconverged or not ldahia_notconverged: + if not ignore_convergence_criteria: return False elif mode == 'force': if self.ctx.last_charge_density is None: @@ -765,7 +766,7 @@ def condition(self): except NotExistent: pass else: - if not ldau_notconverged or not ldahia_notconverged: + if not ignore_convergence_criteria: return False elif self.ctx.wf_dict['density_converged'] >= self.ctx.last_charge_density: @@ -774,7 +775,7 @@ def condition(self): except NotExistent: pass else: - if not ldau_notconverged or not ldahia_notconverged: + if not ignore_convergence_criteria: return False if self.ctx.loop_count >= self.ctx.max_number_runs: From 4b8b1dd5e69b67080e908ba87b0998c8058bfae1 Mon Sep 17 00:00:00 2001 From: janssenhenning Date: Tue, 24 May 2022 09:49:15 +0200 Subject: [PATCH 26/29] Move inpxml_changes in hubbard1 wc to the end --- aiida_fleur/workflows/hubbard1.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/aiida_fleur/workflows/hubbard1.py b/aiida_fleur/workflows/hubbard1.py index 75b95e9c3..61aa00e5a 100644 --- a/aiida_fleur/workflows/hubbard1.py +++ b/aiida_fleur/workflows/hubbard1.py @@ -182,10 +182,7 @@ def create_hubbard1_input(self): else: scf_wf_para = {} - fchanges = self.ctx.wf_dict.get('inpxml_changes', []) - scf_wf_para.setdefault('inpxml_changes', []).extend(fchanges) - - scf_wf_para['inpxml_changes'].append(('set_inpchanges', { + scf_wf_para.setdefault('inpxml_changes', []).append(('set_inpchanges', { 'change_dict': { 'minoccdistance': self.ctx.wf_dict['occupation_converged'], 'minmatdistance': self.ctx.wf_dict['matrix_elements_converged'], @@ -269,6 +266,7 @@ def create_hubbard1_input(self): 'ldahia': ldahia_dict } })) + scf_wf_para.extend(self.ctx.wf_dict.get('inpxml_changes', [])) inputs_hubbard1.wf_parameters = orm.Dict(dict=scf_wf_para) From e860fb7e51b9abf79a79e3f841cedd0d95edc92e Mon Sep 17 00:00:00 2001 From: janssenhenning Date: Tue, 24 May 2022 10:01:50 +0200 Subject: [PATCH 27/29] fix last commit --- aiida_fleur/workflows/hubbard1.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aiida_fleur/workflows/hubbard1.py b/aiida_fleur/workflows/hubbard1.py index 61aa00e5a..b1912461d 100644 --- a/aiida_fleur/workflows/hubbard1.py +++ b/aiida_fleur/workflows/hubbard1.py @@ -266,7 +266,7 @@ def create_hubbard1_input(self): 'ldahia': ldahia_dict } })) - scf_wf_para.extend(self.ctx.wf_dict.get('inpxml_changes', [])) + scf_wf_para['inpxml_changes'].extend(self.ctx.wf_dict.get('inpxml_changes', [])) inputs_hubbard1.wf_parameters = orm.Dict(dict=scf_wf_para) From 81749e04176c41b97fcf2f4e4e0d63e17f1af298 Mon Sep 17 00:00:00 2001 From: janssenhenning Date: Mon, 30 May 2022 17:08:58 +0200 Subject: [PATCH 28/29] Add missing return of exit code Otherwise return_results is executed twice --- aiida_fleur/workflows/hubbard1.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/aiida_fleur/workflows/hubbard1.py b/aiida_fleur/workflows/hubbard1.py index b1912461d..d6542e61e 100644 --- a/aiida_fleur/workflows/hubbard1.py +++ b/aiida_fleur/workflows/hubbard1.py @@ -290,6 +290,7 @@ def inspect_hubbard1_calculation(self): error = ('ERROR: Hubbard1 SCF workflow was not successful') self.ctx.successful = False self.control_end_wc(error) + return self.exit_codes.ERROR_HUBBARD1_CALCULATION_FAILED try: self.ctx.hubbard1.outputs.output_scf_wc_para @@ -297,6 +298,7 @@ def inspect_hubbard1_calculation(self): error = ('ERROR: Hubbard1 SCF workflow failed, no output node') self.ctx.successful = False self.control_end_wc(error) + return self.exit_codes.ERROR_HUBBARD1_CALCULATION_FAILED def return_results(self): """ From 9426197884847434638842f23d525b4a81f6d07f Mon Sep 17 00:00:00 2001 From: janssenhenning Date: Tue, 5 Jul 2022 00:01:36 +0200 Subject: [PATCH 29/29] Fix rebase --- aiida_fleur/workflows/scf.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/aiida_fleur/workflows/scf.py b/aiida_fleur/workflows/scf.py index c7fc341cc..9b3d2d081 100644 --- a/aiida_fleur/workflows/scf.py +++ b/aiida_fleur/workflows/scf.py @@ -717,6 +717,10 @@ def get_res(self): 'Assuming that the calculatin should be continued') self.ctx.last_nmmp_distance = self.ctx.wf_dict['nmmp_converged'] + 1 + if self.ctx.hubbard1_occ_distance: + self.ctx.last_hubbard1_occ_distance = self.ctx.hubbard1_occ_distance[-1] + self.ctx.last_hubbard1_elem_distance = self.ctx.hubbard1_elem_distance[-1] + def condition(self): """ check convergence condition