def run_stage(self): """Check for restart, prepare input, submit and direct output to context.""" # Update structure self.ctx.base_inp['cp2k']['structure'] = self.ctx.structure # Check if it is needed to restart the calculation and provide the parent folder and new structure if self.ctx.parent_calc_folder: self.ctx.base_inp['cp2k']['parent_calc_folder'] = self.ctx.parent_calc_folder self.ctx.cp2k_param['FORCE_EVAL']['DFT']['SCF']['SCF_GUESS'] = 'RESTART' self.ctx.cp2k_param['FORCE_EVAL']['DFT']['WFN_RESTART_FILE_NAME'] = './parent_calc/aiida-RESTART.wfn' else: self.ctx.cp2k_param['FORCE_EVAL']['DFT']['SCF']['SCF_GUESS'] = 'ATOMIC' # Overwrite the generated input with the custom cp2k/parameters if 'parameters' in self.exposed_inputs(Cp2kBaseWorkChain, 'cp2k_base')['cp2k']: merge_dict( self.ctx.cp2k_param, AttributeDict(self.exposed_inputs(Cp2kBaseWorkChain, 'cp2k_base')['cp2k']['parameters'].get_dict())) self.ctx.base_inp['cp2k']['parameters'] = Dict(dict=self.ctx.cp2k_param).store() # Update labels self.ctx.base_inp['metadata'].update({ 'label': '{}_{}'.format(self.ctx.stage_tag, self.ctx.settings_tag), 'call_link_label': 'run_{}_{}'.format(self.ctx.stage_tag, self.ctx.settings_tag), }) self.ctx.base_inp['cp2k']['metadata'].update( {'label': self.ctx.base_inp['cp2k']['parameters'].get_dict()['GLOBAL']['RUN_TYPE']}) running_base = self.submit(Cp2kBaseWorkChain, **self.ctx.base_inp) self.report("submitted Cp2kBaseWorkChain for {}/{}".format(self.ctx.stage_tag, self.ctx.settings_tag)) return ToContext(stages=append_(running_base))
def inspect_and_update_stage(self): """Update geometry, parent folder and the new &MOTION settings.""" last_stage = self.ctx.stages[-1] if 'output_structure' in last_stage.outputs: self.ctx.structure = last_stage.outputs.output_structure self.report('Structure updated for next stage') else: self.report( 'New structure NOT found and NOT updated for next stage') self.ctx.parent_calc_folder = last_stage.outputs.remote_folder last_stage.outputs.output_parameters.label = '{}_{}_valid'.format( self.ctx.stage_tag, self.ctx.settings_tag) self.ctx.stage_idx += 1 next_stage_tag = 'stage_{}'.format(self.ctx.stage_idx) if next_stage_tag in self.ctx.protocol: self.ctx.stage_tag = next_stage_tag self.ctx.next_stage_exists = True merge_dict(self.ctx.cp2k_param, self.ctx.protocol[self.ctx.stage_tag]) else: self.ctx.next_stage_exists = False self.report("All stages computed, finishing...")
def setup_multistage(self): """Setup initial parameters.""" # Store the workchain inputs in context (to be modified later) self.ctx.base_inp = AttributeDict(self.exposed_inputs(Cp2kBaseWorkChain, 'cp2k_base')) # Check if an input parent_calc_folder is provided if 'parent_calc_folder' in self.inputs: self.ctx.parent_calc_folder = self.inputs.parent_calc_folder else: self.ctx.parent_calc_folder = None # Read yaml file selected as SinglefileData or chosen with the tag, and overwrite with custom modifications if 'protocol_yaml' in self.inputs: self.ctx.protocol = yaml.safe_load(self.inputs.protocol_yaml.open()) else: thisdir = os.path.dirname(os.path.abspath(__file__)) yamlfullpath = os.path.join(thisdir, 'multistage_protocols', self.inputs.protocol_tag.value + '.yaml') with open(yamlfullpath, 'r') as stream: self.ctx.protocol = yaml.safe_load(stream) merge_dict(self.ctx.protocol, self.inputs.protocol_modify.get_dict()) # Initialize self.ctx.settings_ok = False self.ctx.stage_idx = 0 self.ctx.stage_tag = 'stage_{}'.format(self.ctx.stage_idx) self.ctx.settings_idx = 0 self.ctx.settings_tag = 'settings_{}'.format(self.ctx.settings_idx) self.ctx.structure = self.inputs.structure # Resize the unit cell if min(perp_with) < inputs.min_cell_size self.ctx.resize = check_resize_unit_cell(self.ctx.structure, self.inputs.min_cell_size) # Dict if self.ctx.resize['nx'] > 1 or self.ctx.resize['ny'] > 1 or self.ctx.resize['nz'] > 1: resized_struct = resize_unit_cell(self.ctx.structure, self.ctx.resize) self.ctx.structure = resized_struct self.report("Unit cell resized by {}x{}x{} (StructureData<{}>)".format(self.ctx.resize['nx'], self.ctx.resize['ny'], self.ctx.resize['nz'], resized_struct.pk)) else: self.report("Unit cell was NOT resized") # Generate input parameters and store them self.ctx.cp2k_param = deepcopy(self.ctx.protocol['settings_0']) while self.inputs.starting_settings_idx < self.ctx.settings_idx: # overwrite untill the desired starting setting are obtained self.ctx.settings_idx += 1 self.ctx.settings_tag = 'settings_{}'.format(self.ctx.settings_idx) if self.ctx.settings_tag in self.ctx.protocol: merge_dict(self.ctx.cp2k_param, self.ctx.protocol[self.ctx.settings_tag]) else: return self.exit_codes.ERROR_MISSING_INITIAL_SETTINGS # pylint: disable=no-member kinds = get_kinds_section(self.ctx.structure, self.ctx.protocol) merge_dict(self.ctx.cp2k_param, kinds) multiplicity = get_input_multiplicity(self.ctx.structure, self.ctx.protocol) merge_dict(self.ctx.cp2k_param, multiplicity) merge_dict(self.ctx.cp2k_param, self.ctx.protocol['stage_0'])
def inspect_and_update_settings_stage0(self): # pylint: disable=inconsistent-return-statements """Inspect the stage0/settings_{idx} calculation and check if it is needed to update the settings and resubmint the calculation.""" self.ctx.settings_ok = True # Settings/structure are bad: there are problems in parsing the output file # and, most probably, the calculation didn't even start the scf cycles if 'output_parameters' in self.ctx.stages[-1].outputs: cp2k_out = self.ctx.stages[-1].outputs.output_parameters else: self.report('ERROR_PARSING_OUTPUT') return self.exit_codes.ERROR_PARSING_OUTPUT # pylint: disable=no-member # Settings are bad: the SCF did not converge in the final step if not cp2k_out["motion_step_info"]["scf_converged"][-1]: self.report("BAD SETTINGS: the SCF did not converge") self.ctx.settings_ok = False self.ctx.settings_idx += 1 else: # SCF converged, but the computed bandgap needs to be checked self.report("Bandgaps spin1/spin2: {:.3f} and {:.3f} ev".format( cp2k_out["bandgap_spin1_au"] * HARTREE2EV, cp2k_out["bandgap_spin2_au"] * HARTREE2EV)) bandgap_thr_ev = self.ctx.protocol['bandgap_thr_ev'] if ot_has_small_bandgap(self.ctx.cp2k_param, cp2k_out, bandgap_thr_ev): self.report("BAD SETTINGS: band gap is < {:.3f} eV".format( bandgap_thr_ev)) self.ctx.settings_ok = False self.ctx.settings_idx += 1 # Update the settings tag, check if it is available and overwrite if not self.ctx.settings_ok: cp2k_out.label = '{}_{}_discard'.format(self.ctx.stage_tag, self.ctx.settings_tag) next_settings_tag = 'settings_{}'.format(self.ctx.settings_idx) if next_settings_tag in self.ctx.protocol: self.ctx.settings_tag = next_settings_tag merge_dict(self.ctx.cp2k_param, self.ctx.protocol[self.ctx.settings_tag]) else: return self.exit_codes.ERROR_NO_MORE_SETTINGS # pylint: disable=no-member