From 31c6c9015aacb42a13b0dd0f2b7e7de48b432cdf Mon Sep 17 00:00:00 2001 From: Minotakm Date: Tue, 19 Nov 2024 09:40:33 +0100 Subject: [PATCH] Tried to sum up everything said on the Issue #961, extrapolated the number of maximum steps and use them to increase the number of maximum electron steps if can be convergede. --- .../workflows/pw/base.py | 101 ++++++++++++++++-- 1 file changed, 93 insertions(+), 8 deletions(-) diff --git a/src/aiida_quantumespresso/workflows/pw/base.py b/src/aiida_quantumespresso/workflows/pw/base.py index 8e53dfa6e..463df44ad 100644 --- a/src/aiida_quantumespresso/workflows/pw/base.py +++ b/src/aiida_quantumespresso/workflows/pw/base.py @@ -29,10 +29,15 @@ class PwBaseWorkChain(ProtocolMixin, BaseRestartWorkChain): 'qe': qe_defaults, 'delta_threshold_degauss': 30, 'delta_factor_degauss': 0.1, - 'delta_factor_mixing_beta': 0.8, + 'delta_factor_mixing_beta': 0.5, + 'delta_addition_mixing_ndim': 4, 'delta_factor_max_seconds': 0.95, 'delta_factor_nbnd': 0.05, 'delta_minimum_nbnd': 4, + 'conv_slope_threshold': -0.1, + 'max_electronic_steps': 300, + 'conv_slope_range': 30, + 'low_symmetry_threshold': 6 }) @classmethod @@ -564,15 +569,95 @@ def handle_electronic_convergence_not_reached(self, calculation): Decrease the mixing beta and fully restart from the previous calculation. """ - factor = self.defaults.delta_factor_mixing_beta - mixing_beta = self.ctx.inputs.parameters.get('ELECTRONS', {}).get('mixing_beta', self.defaults.qe.mixing_beta) - mixing_beta_new = mixing_beta * factor + import numpy + from numpy.polynomial import Polynomial + + scf_accuracy = calculation.tools.get_scf_accuracy(-1)[-self.defaults.conv_slope_range:] + scf_accuracy_slope, scf_accuracy_intercept = Polynomial.fit(numpy.arange(0, len(scf_accuracy)), numpy.log(scf_accuracy), 1).convert().coef + + mixing_beta = self.ctx.inputs.parameters['ELECTRONS'].get('mixing_beta', self.defaults.qe.mixing_beta) + mixing_ndim = self.ctx.inputs.parameters['ELECTRONS'].get('mixing_ndim', self.defaults.qe.mixing_ndim) + mixing_mode = self.ctx.inputs.parameters['ELECTRONS'].get('mixing_mode', self.defaults.qe.mixing_mode) + low_symmetry_structure = ( + len(calculation.outputs.output_parameters.get_dict()['symmetries']) < self.defaults. + ) + low_dim_structure = calculation.inputs.structure.pbc != (True, True, True) + nbnd_cur = calculation.outputs.output_parameters.get_dict()['number_of_bands'] + diagonalization = self.ctx.inputs.parameters['ELECTRONS'].get('diagonalization', 'david') + + self.report(f'number of bands: {nbnd_cur}') + self.report(f'scf accuracy slope: {scf_accuracy_slope:.2f}') + self.report(f'mixing beta: {mixing_beta:.2f}') + self.report(f'mixing ndim: {mixing_ndim}') + self.report(f'mixing mode: {mixing_mode}') + self.report(f"structure symmetries: {len(calculation.outputs.output_parameters.get_dict()['symmetries'])}") + self.report(f'low symmetry structure: {low_symmetry_structure}') + self.report(f'low dimension structure: {low_dim_structure}') + + if self.ctx.inputs.parameters['ELECTRONS']['electron_maxstep'] < self.defaults.max_electronic_steps: + electron_steps_new = min(self.defaults.max_electronic_steps,[ numpy.log(scf_accuracy) - scf_accuracy_intercept] / scf_accuracy_slope) + self.ctx.inputs.parameters['ELECTRONS']['electron_maxstep'] = electron_steps_new + self.report( + f'Changed the number of electron maxsteps: increasing number of electron maxsteps {electron_steps_new}' + ) - self.ctx.inputs.parameters['ELECTRONS']['mixing_beta'] = mixing_beta_new - action = f'reduced beta mixing from {mixing_beta} to {mixing_beta_new} and restarting from the last calculation' + if 'scf_failed_once' not in self.ctx: + nbnd_new = nbnd_cur + max(int(nbnd_cur * self.defaults.delta_factor_nbnd), self.defaults.delta_minimum_nbnd) + self.ctx.inputs.parameters['SYSTEM']['nbnd'] = nbnd_new + self.report( + f'First SCF failure encountered: increasing number of bands to {nbnd_new}' + ) + self.ctx.scf_failed_once = True + + if scf_accuracy_slope < self.defaults.conv_slope_threshold: + action = ( + f'electronic convergence not reached but the scf accuracy slope ({scf_accuracy_slope:.2f}) is smaller ' + f'than the threshold ({self.defaults.conv_slope_threshold:.2f}): restart from the last calculation.' + ) + self.set_restart_type(RestartType.FROM_SCRATCH) + self.report_error_handled(calculation, action) + return ProcessHandlerReport(True) + + if mixing_mode == 'plain' and low_dim_structure: + + self.ctx.inputs.parameters['ELECTRONS'].setdefault('mixing_mode', 'local-TF') + action = ( + 'electronic convergence not reached and structure is low dimensional: switch to local-TF mixing and ' + 'restart from the last calculation.' + ) + self.set_restart_type(RestartType.FROM_SCRATCH) + self.report_error_handled(calculation, action) + return ProcessHandlerReport(True) + + if 'diagonalizations' not in self.ctx: + # Initialize a list to track diagonalisations that haven't been tried in reverse order or preference + self.ctx.diagonalizations = [value for value in ['cg', 'paro', 'ppcg', 'rmm-paro', 'david'] if value != diagonalization.lower()] + + try: + new = self.ctx.diagonalizations.pop() + self.ctx.inputs.parameters['ELECTRONS']['diagonalization'] = new + action = f'electronic convergence not reached: switching to `{new}` diagonalization.' + self.set_restart_type(RestartType.FROM_SCRATCH) + self.report_error_handled(calculation, action) + return ProcessHandlerReport(True) + except IndexError: + pass + + if mixing_beta > 0.1: + + mixing_beta_new = mixing_beta * self.defaults.delta_factor_mixing_beta + mixing_ndim_new = mixing_ndim + self.defaults.delta_addition_mixing_ndim + + self.ctx.inputs.parameters['ELECTRONS']['mixing_beta'] = mixing_beta_new + self.ctx.inputs.parameters['ELECTRONS']['mixing_ndim'] = mixing_ndim_new + action = ( + f'reduced beta mixing from {mixing_beta} to {mixing_beta_new}, increased `mixing_ndim` from ' + f'{mixing_ndim} to {mixing_ndim_new} and restarting from the last calculation.' + ) + self.set_restart_type(RestartType.FROM_SCRATCH) + self.report_error_handled(calculation, action) + return ProcessHandlerReport(True) - self.set_restart_type(RestartType.FULL, calculation.outputs.remote_folder) - self.report_error_handled(calculation, action) return ProcessHandlerReport(True) @process_handler(priority=420, exit_codes=[