diff --git a/src/aiida_quantumespresso/workflows/ph/base.py b/src/aiida_quantumespresso/workflows/ph/base.py index 81f80b79f..ab3001aab 100644 --- a/src/aiida_quantumespresso/workflows/ph/base.py +++ b/src/aiida_quantumespresso/workflows/ph/base.py @@ -23,8 +23,9 @@ class PhBaseWorkChain(ProtocolMixin, BaseRestartWorkChain): defaults = AttributeDict({ 'delta_factor_max_seconds': 0.95, - 'delta_factor_alpha_mix': 0.90, - 'alpha_mix': 0.70, + 'delta_factor_alpha_mix': 0.5, + 'nmix_ph': 4, + 'alpha_mix': 0.7, }) @classmethod @@ -276,13 +277,33 @@ def handle_out_of_walltime(self, node): @process_handler(priority=410, exit_codes=PhCalculation.exit_codes.ERROR_CONVERGENCE_NOT_REACHED) def handle_convergence_not_reached(self, node): """Handle `ERROR_CONVERGENCE_NOT_REACHED` exit code: decrease the mixing beta and restart.""" + self.ctx.restart_calc = node factor = self.defaults.delta_factor_alpha_mix + + nmix_ph = self.ctx.inputs.parameters.get('INPUTPH', {}).get('nmix_ph', self.defaults.nmix_ph) + + if nmix_ph < 8: # 8~20 is the recommended range on the Quantum ESPRESSO documentation + self.ctx.inputs.parameters.setdefault('INPUTPH', {})['nmix_ph'] = 8 + action = f'increased number of mixing iteration from {nmix_ph} to 8 and restarting' + self.report_error_handled(node, action) + + return ProcessHandlerReport(True) + + # now try playing with the mixing parameters alpha_mix = self.ctx.inputs.parameters.get('INPUTPH', {}).get('alpha_mix(1)', self.defaults.alpha_mix) alpha_mix_new = alpha_mix * factor - self.ctx.restart_calc = node - self.ctx.inputs.parameters.setdefault('INPUTPH', {})['alpha_mix(1)'] = alpha_mix_new + if self.ctx.inputs.parameters.get('INPUTPH', {}).get('alpha_mix(20)', -1) != -1: + action = 'no more efficient strategies for convergence.' + self.report_error_handled(node, action) + return ProcessHandlerReport(False) + + if alpha_mix_new >= 0.1: + self.ctx.inputs.parameters.setdefault('INPUTPH', {})['alpha_mix(1)'] = alpha_mix_new + action = f'reduced alpha_mix from {alpha_mix} to {alpha_mix_new} and restarting' + else: + self.ctx.inputs.parameters.setdefault('INPUTPH', {})['alpha_mix(20)'] = 0.4 + action = f'introduing alpha_mix(20)={alpha_mix_new} and restarting' - action = f'reduced alpha_mix from {alpha_mix} to {alpha_mix_new} and restarting' self.report_error_handled(node, action) return ProcessHandlerReport(True) diff --git a/src/aiida_quantumespresso/workflows/protocols/ph/base.yaml b/src/aiida_quantumespresso/workflows/protocols/ph/base.yaml index 126c6b836..b281d8a90 100644 --- a/src/aiida_quantumespresso/workflows/protocols/ph/base.yaml +++ b/src/aiida_quantumespresso/workflows/protocols/ph/base.yaml @@ -10,6 +10,8 @@ default_inputs: withmpi: True parameters: INPUTPH: + alpha_mix: 0.4 + nmix_ph: 8 tr2_ph: 1.0e-18 qpoints: - 3 diff --git a/tests/workflows/ph/test_base.py b/tests/workflows/ph/test_base.py index aaa6b5467..edef058a1 100644 --- a/tests/workflows/ph/test_base.py +++ b/tests/workflows/ph/test_base.py @@ -99,15 +99,28 @@ def test_handle_convergence_not_reached(generate_workchain_ph): process.setup() process.validate_parameters() + result = process.handle_convergence_not_reached(process.ctx.children[-1]) + assert isinstance(result, ProcessHandlerReport) + assert result.do_break + assert process.ctx.inputs.parameters['INPUTPH']['nmix_ph'] == 8 + alpha_new = PhBaseWorkChain.defaults.alpha_mix * PhBaseWorkChain.defaults.delta_factor_alpha_mix + for _ in range(2): # this is dependent on PhBaseWorkChain.defaults.delta_factor_alpha_mix + result = process.handle_convergence_not_reached(process.ctx.children[-1]) + assert isinstance(result, ProcessHandlerReport) + assert result.do_break + assert process.ctx.inputs.parameters['INPUTPH']['alpha_mix(1)'] == alpha_new + alpha_new = alpha_new * PhBaseWorkChain.defaults.delta_factor_alpha_mix + result = process.handle_convergence_not_reached(process.ctx.children[-1]) assert isinstance(result, ProcessHandlerReport) assert result.do_break - assert process.ctx.inputs.parameters['INPUTPH']['alpha_mix(1)'] == alpha_new + assert process.ctx.inputs.parameters['INPUTPH']['alpha_mix(20)'] == 0.4 - result = process.inspect_process() - assert result.status == 0 + result = process.handle_convergence_not_reached(process.ctx.children[-1]) + assert isinstance(result, ProcessHandlerReport) + assert not result.do_break def test_handle_diagonalization_errors(generate_workchain_ph): diff --git a/tests/workflows/protocols/ph/test_base/test_default.yml b/tests/workflows/protocols/ph/test_base/test_default.yml index 845fe3211..530f5282f 100644 --- a/tests/workflows/protocols/ph/test_base/test_default.yml +++ b/tests/workflows/protocols/ph/test_base/test_default.yml @@ -10,6 +10,8 @@ ph: withmpi: true parameters: INPUTPH: + alpha_mix: 0.4 + nmix_ph: 8 tr2_ph: 1.0e-18 qpoints: - - 3