def calculate_trim_wf(self): """Launch a pw_bands calculation on the TRIM points for the structure.""" self.report( 'Using parities at TRIM points to calculatte Z2 invariant.') kpoints = generate_trim(self.ctx.current_structure, self.inputs.dimensionality) inputs = AttributeDict( self.exposed_inputs(PwBaseWorkChain, namespace='band')) inputs.clean_workdir = self.inputs.clean_workdir inputs.pw.code = self.inputs.pw_code inputs.pw.structure = self.ctx.current_structure inputs.pw.parameters = inputs.pw.parameters.get_dict() inputs.pw.parameters.setdefault('CONTROL', {}) inputs.pw.parameters['CONTROL']['calculation'] = 'bands' inputs.pw.parent_folder = self.ctx.scf_folder inputs.kpoints = kpoints inputs = prepare_process_inputs(PwBaseWorkChain, inputs) running = self.submit(PwBaseWorkChain, **inputs) self.report('launching PwBaseWorkChain<{}> in {} mode'.format( running.pk, 'bands')) return ToContext(workchain_trim=running)
def run_nscf_crop(self): """Run the PwBaseWorkChain in nscf mode along the path of high-symmetry determined by seekpath.""" inputs = AttributeDict(self.exposed_inputs(PwBaseWorkChain, namespace='nscf_crop')) inputs.metadata.call_link_label = 'nscf_crop' # inputs.pw.metadata.options.max_wallclock_seconds *= 4 # inputs.kpoints_distance = self.inputs.kpoints_distance inputs.pw.structure = self.ctx.current_structure inputs.pw.parent_folder = self.ctx.current_folder inputs.pw.parameters = inputs.pw.parameters.get_dict() inputs.pw.parameters.setdefault('CONTROL', {}) inputs.pw.parameters.setdefault('SYSTEM', {}) inputs.pw.parameters.setdefault('ELECTRONS', {}) # The following flags always have to be set in the parameters, regardless of what caller specified in the inputs inputs.pw.parameters['CONTROL']['calculation'] = 'nscf' inputs.pop('kpoints_distance', None) inputs.kpoints = self.ctx.kpoint_crop # Only set the following parameters if not directly explicitly defined in the inputs # inputs.pw.parameters['ELECTRONS'].setdefault('diagonalization', 'cg') # inputs.pw.parameters['ELECTRONS'].setdefault('diago_full_acc', True) # If `nbands_factor` is defined in the inputs we set the `nbnd` parameter if 'nbands_factor_crop' in self.inputs: factor = self.inputs.nbands_factor_crop.value parameters = self.ctx.workchain_scf.outputs.output_parameters.get_dict() if int(parameters['number_of_spin_components']) > 1: nspin_factor = 2 else: nspin_factor = 1 nbands = int(parameters['number_of_bands']) nelectron = int(parameters['number_of_electrons']) nbnd = max( int(0.5 * nelectron * nspin_factor * factor), int(0.5 * nelectron * nspin_factor) + 4 * nspin_factor, nbands) inputs.pw.parameters['SYSTEM']['nbnd'] = nbnd # Otherwise set the current number of bands, unless explicitly set in the inputs else: inputs.pw.parameters['SYSTEM'].setdefault('nbnd', self.ctx.current_number_of_bands) inputs = prepare_process_inputs(PwBaseWorkChain, inputs) running = self.submit(PwBaseWorkChain, **inputs) self.report('launching PwBaseWorkChain<{}> in {} mode for CROP grid'.format(running.pk, 'nscf')) return ToContext(workchain_nscf_crop=running)
def first_bands_step(self): """Do a bandcalculation using the kpoints provided in `starting_kpoints`.""" self.ctx.iteration += 1 inputs = AttributeDict(deep_copy(self.ctx.inputs)) inputs.kpoints = self.inputs.starting_kpoints try: kpt = inputs.kpoints.get_kpoints() except: kpt = inputs.kpoints.get_kpoints_mesh(print_list=True) nkpt = len(kpt) if 'settings' in inputs.pw: settings = inputs.pw.settings.get_dict() if 'cmdline' in settings: ptr = settings['cmdline'] npools = None if '-npools' in ptr: i = ptr.index('-npools') npools = int(ptr[i + 1]) elif '-nk' in ptr: i = ptr.index('-nk') npools = int(ptr[i + 1]) if not npools is None and npools > nkpt: self.report('WARNING: npools={} > nkpt={}'.format( npools, nkpt)) for n in range(nkpt, 0, -1): if npools % n == 0: ptr[i + 1] = str(n) self.report('... reducing npools to {}.'.format(n)) break inputs.pw.settings = settings inputs = prepare_process_inputs(PwBaseWorkChain, inputs) running = self.submit(PwBaseWorkChain, **inputs) self.report( 'launching PwBaseWorkChain<{}> in {} mode, iteration {}'.format( running.pk, 'bands', self.ctx.iteration)) return ToContext(workchain_bands=append_(running))
def run_nscf(self): """Run the PwBaseWorkChain in bands mode along the path of high-symmetry determined by seekpath.""" inputs = AttributeDict(self.exposed_inputs(PwBaseWorkChain, namespace='nscf')) inputs.metadata.call_link_label = 'nscf' inputs.kpoints = self.ctx.bands_kpoints inputs.pw.structure = self.ctx.current_structure inputs.pw.parent_folder = self.ctx.current_folder inputs.pw.parameters = inputs.pw.parameters.get_dict() inputs.pw.parameters.setdefault('CONTROL', {}) inputs.pw.parameters.setdefault('SYSTEM', {}) inputs.pw.parameters.setdefault('ELECTRONS', {}) # The following flags always have to be set in the parameters, regardless of what caller specified in the inputs inputs.pw.parameters['CONTROL']['calculation'] = 'nscf' # Only set the following parameters if not directly explicitly defined in the inputs inputs.pw.parameters['ELECTRONS'].setdefault('diagonalization', 'cg') inputs.pw.parameters['ELECTRONS'].setdefault('diago_full_acc', True) # If `nbands_factor` is defined in the inputs we set the `nbnd` parameter factor = 1.2 parameters = self.ctx.workchain_scf.outputs.output_parameters.get_dict() if int(parameters['number_of_spin_components']) > 1: nspin_factor = 2 else: nspin_factor = 1 nbands = int(parameters['number_of_bands']) nelectron = int(parameters['number_of_electrons']) nbnd = max( int(0.5 * nelectron * nspin_factor * factor), int(0.5 * nelectron * nspin_factor) + 4 * nspin_factor, nbands ) inputs.pw.parameters['SYSTEM']['nbnd'] = nbnd inputs.pw.parameters['SYSTEM']['nosym'] = True inputs = prepare_process_inputs(PwBaseWorkChain, inputs) running = self.submit(PwBaseWorkChain, **inputs) self.report(f'launching PwBaseWorkChain<{running.pk}> in nscf mode') return ToContext(workchain_nscf=running)
def setup_bands(self): """Set the inputs for the `bands` calculation.""" inputs = AttributeDict( self.exposed_inputs(PwBaseWorkChain, namespace='bands')) inputs.pw.code = self.inputs.code inputs.kpoints = self.ctx.kpt_data inputs.pw.pseudos = self.inputs.pseudos inputs.pw.structure = self.inputs.structure inputs.pw.parent_folder = self.ctx.remote inputs.clean_workdir = self.inputs.clean_workdir inputs.pw.parameters = inputs.pw.parameters.get_dict() inputs.pw.parameters.setdefault('CONTROL', {}) inputs.pw.parameters['CONTROL']['calculation'] = 'bands' inputs.pw.parameters['SYSTEM']['nosym'] = True inputs = prepare_process_inputs(PwBaseWorkChain, inputs) self.ctx.inputs = inputs
def run_bands(self): """Run the PwBaseWorkChain in bands mode along the path of high-symmetry determined by seekpath.""" # Get info from SCF on number of electrons and number of spin components scf_out_dict = self.ctx.workchain_scf.outputs.output_parameters.get_dict() nelectron = int(scf_out_dict['number_of_electrons']) nspin = int(scf_out_dict['number_of_spin_components']) nbands = max( int(0.5 * nelectron * nspin * self.inputs.nbands_factor.value), int(0.5 * nelectron * nspin) + 4 * nspin) inputs = AttributeDict(self.exposed_inputs(PwBaseWorkChain, namespace='bands')) inputs.pw.parameters = inputs.pw.parameters.get_dict() inputs.pw.parameters.setdefault('CONTROL', {}) inputs.pw.parameters.setdefault('SYSTEM', {}) inputs.pw.parameters.setdefault('ELECTRONS', {}) inputs.pw.parameters['CONTROL']['restart_mode'] = 'restart' inputs.pw.parameters['CONTROL']['calculation'] = 'bands' inputs.pw.parameters['ELECTRONS']['diagonalization'] = 'cg' inputs.pw.parameters['ELECTRONS']['diago_full_acc'] = True inputs.pw.parameters['SYSTEM']['nbnd'] = nbands if 'kpoints' not in self.inputs.bands: inputs.kpoints = self.ctx.kpoints_path inputs.pw.structure = self.ctx.current_structure inputs.pw.parent_folder = self.ctx.current_folder inputs = prepare_process_inputs(PwBaseWorkChain, inputs) running = self.submit(PwBaseWorkChain, **inputs) self.report('launching PwBaseWorkChain<{}> in {} mode'.format(running.pk, 'bands')) return ToContext(workchain_bands=running)
def run_wannier90_pp(self): """The input of wannier90 calculation is build here. :return: [description] :rtype: [type] """ inputs = AttributeDict( self.exposed_inputs(Wannier90Calculation, namespace='wannier90')) inputs.structure = self.ctx.current_structure parameters = inputs.parameters.get_dict() # get nscf kmesh inputs.kpoints = self.ctx.workchain_nscf.inputs.kpoints # the input kpoints of nscf is an explicitly generated list of kpoints, # we mush retrieve the original kmesh, and explicitly set w90 mp_grid keyword parameters['mp_grid'] = self.ctx.nscf_kmesh.get_kpoints_mesh()[0] # check num_bands, exclude_bands, nscf nbnd nbnd = self.ctx.workchain_nscf.outputs.output_parameters.get_dict( )['number_of_bands'] num_ex_bands = len(get_exclude_bands(inputs.parameters.get_dict())) parameters['num_bands'] = nbnd - num_ex_bands # set num_wann for auto_projections if self.ctx.auto_projections: if self.inputs.only_valence: parameters['num_wann'] = parameters['num_bands'] inputs.parameters = orm.Dict(dict=parameters) else: inputs.parameters = orm.Dict(dict=parameters) inputs.parameters = update_w90_params_numwann( inputs.parameters, self.ctx.calc_projwfc.outputs.projections) self.report( 'number of Wannier functions extracted from projections: ' + str(inputs.parameters['num_wann'])) # get scf Fermi energy try: energies_relative_to_fermi = self.inputs.get( 'wannier_energies_relative_to_fermi') inputs.parameters = update_w90_params_fermi( inputs.parameters, self.ctx.workchain_scf.outputs.output_parameters, energies_relative_to_fermi) except TypeError: self.report("Error in retriving the SCF Fermi energy " "from pk: {}".format(self.ctx.workchain_scf)) return self.exit_codes.ERROR_SUB_PROCESS_FAILED_WANNIER90PP #Check if settings is given in input try: settings = inputs['settings'].get_dict() except KeyError: settings = {} settings['postproc_setup'] = True inputs['settings'] = settings inputs = prepare_process_inputs(Wannier90Calculation, inputs) running = self.submit(Wannier90Calculation, **inputs) self.report( 'wannier90 postproc step - launching Wannier90Calculation<{}> in postproc mode' .format(running.pk)) return ToContext(calc_wannier90_pp=running)
def run_nscf(self): """ Run the PwBaseWorkChain in nscf mode """ inputs = AttributeDict( self.exposed_inputs(PwBaseWorkChain, namespace='nscf')) inputs.pw.structure = self.ctx.current_structure inputs.pw.parent_folder = self.ctx.current_folder inputs.pw.parameters = inputs.pw.parameters.get_dict() inputs.pw.parameters.setdefault('CONTROL', {}) inputs.pw.parameters.setdefault('SYSTEM', {}) inputs.pw.parameters.setdefault('ELECTRONS', {}) inputs.pw.parameters['CONTROL']['restart_mode'] = 'from_scratch' inputs.pw.parameters['CONTROL']['calculation'] = 'nscf' inputs.pw.parameters['SYSTEM']['nosym'] = True inputs.pw.parameters['SYSTEM']['noinv'] = True inputs.pw.parameters['ELECTRONS']['diagonalization'] = 'cg' inputs.pw.parameters['ELECTRONS']['diago_full_acc'] = True if self.inputs.only_valence: inputs.pw.parameters['SYSTEM']['occupations'] = 'fixed' inputs.pw.parameters['SYSTEM'].pop( 'smearing', None) # pop None to avoid KeyError inputs.pw.parameters['SYSTEM'].pop( 'degauss', None) # pop None to avoid KeyError # inputs.pw.pseudos is an AttributeDict, but calcfunction only accepts # orm.Data, so we unpack it to pass in orm.UpfData inputs.pw.parameters = update_nscf_num_bands( orm.Dict(dict=inputs.pw.parameters), self.ctx.workchain_scf.outputs.output_parameters, self.ctx.current_structure, self.inputs.only_valence, **inputs.pw.pseudos) self.report('nscf number of bands set as ' + str(inputs.pw.parameters['SYSTEM']['nbnd'])) # check kmesh try: inputs.kpoints except AttributeError: # then kpoints_distance must exists, since this is ensured by inputs check of this workchain from aiida_quantumespresso.workflows.functions.create_kpoints_from_distance import create_kpoints_from_distance force_parity = inputs.get('kpoints_force_parity', orm.Bool(False)) kmesh = create_kpoints_from_distance(self.ctx.current_structure, inputs.kpoints_distance, force_parity) #kpoints_data = orm.KpointsData() # kpoints_data.set_cell_from_structure(self.ctx.current_structure) # kmesh = kpoints_data.set_kpoints_mesh_from_density(inputs.kpoints_distance.value) else: try: inputs.kpoints.get_kpoints_mesh() except AttributeError: self.report("nscf only support `mesh' type KpointsData") return self.exit_codes.ERROR_SUB_PROCESS_FAILED_NSCF else: kmesh = inputs.kpoints # convert kmesh to explicit list, since auto generated kpoints # maybe different between QE & Wannier90. Here we explicitly # generate a list of kpoint to avoid discrepencies between # QE's & Wannier90's automatically generated kpoints. self.ctx.nscf_kmesh = kmesh # store it since it will be used by w90 inputs.kpoints = convert_kpoints_mesh_to_list(kmesh) inputs = prepare_process_inputs(PwBaseWorkChain, inputs) running = self.submit(PwBaseWorkChain, **inputs) self.report( 'nscf step - launching PwBaseWorkChain<{}> in {} mode'.format( running.pk, 'nscf')) return ToContext(workchain_nscf=running)