def main(code_string, incar, kmesh, structure, potential_family, potential_mapping, options): """Main method to setup the calculation.""" # We set the workchain you would like to call workchain = WorkflowFactory('vasp.relax') # And finally, we declare the options, settings and input containers settings = AttributeDict() inputs = AttributeDict() # Organize settings settings.parser_settings = {} # Set inputs for the following WorkChain execution # Set code inputs.code = Code.get_from_string(code_string) # Set structure inputs.structure = structure # Set k-points grid density kpoints = DataFactory('array.kpoints')() kpoints.set_kpoints_mesh(kmesh) inputs.kpoints = kpoints # Set parameters inputs.parameters = DataFactory('dict')(dict=incar) # Set potentials and their mapping inputs.potential_family = DataFactory('str')(potential_family) inputs.potential_mapping = DataFactory('dict')(dict=potential_mapping) # Set options inputs.options = DataFactory('dict')(dict=options) # Set settings inputs.settings = DataFactory('dict')(dict=settings) # Set workchain related inputs, in this case, give more explicit output to report inputs.verbose = DataFactory('bool')(True) # Relaxation related parameters that is passed to the relax workchain relax = AttributeDict() # Turn on relaxation relax.perform = DataFactory('bool')(True) # Select relaxation algorithm relax.algo = DataFactory('str')('cg') # Set force cutoff limit (EDIFFG, but no sign needed) relax.force_cutoff = DataFactory('float')(0.01) # Turn on relaxation of positions (strictly not needed as the default is on) # The three next parameters correspond to the well known ISIF=3 setting relax.positions = DataFactory('bool')(True) # Turn on relaxation of the cell shape (defaults to False) relax.shape = DataFactory('bool')(True) # Turn on relaxation of the volume (defaults to False) relax.volume = DataFactory('bool')(True) # Set maximum number of ionic steps relax.steps = DataFactory('int')(100) # Set the relaxation parameters on the inputs inputs.relax = relax # Submit the requested workchain with the supplied inputs submit(workchain, **inputs)
def get_builder(self, structure: StructureData, calc_engines: Dict[str, Any], *, protocol: str = None, relax_type: RelaxType = RelaxType.ATOMS, electronic_type: ElectronicType = ElectronicType.METAL, spin_type: SpinType = SpinType.NONE, magnetization_per_site: List[float] = None, threshold_forces: float = None, threshold_stress: float = None, previous_workchain=None, **kwargs) -> engine.ProcessBuilder: """Return a process builder for the corresponding workchain class with inputs set according to the protocol. :param structure: the structure to be relaxed. :param calc_engines: a dictionary containing the computational resources for the relaxation. :param protocol: the protocol to use when determining the workchain inputs. :param relax_type: the type of relaxation to perform. :param electronic_type: the electronic character that is to be used for the structure. :param spin_type: the spin polarization type to use for the calculation. :param magnetization_per_site: a list with the initial spin polarization for each site. Float or integer in units of electrons. If not defined, the builder will automatically define the initial magnetization if and only if `spin_type != SpinType.NONE`. :param threshold_forces: target threshold for the forces in eV/Å. :param threshold_stress: target threshold for the stress in eV/Å^3. :param previous_workchain: a <Code>RelaxWorkChain node. :param kwargs: any inputs that are specific to the plugin. :return: a `aiida.engine.processes.ProcessBuilder` instance ready to be submitted. """ # pylint: disable=too-many-locals protocol = protocol or self.get_default_protocol_name() super().get_builder(structure, calc_engines, protocol=protocol, relax_type=relax_type, electronic_type=electronic_type, spin_type=spin_type, magnetization_per_site=magnetization_per_site, threshold_forces=threshold_forces, threshold_stress=threshold_stress, previous_workchain=previous_workchain, **kwargs) # Get the protocol that we want to use if protocol is None: protocol = self._default_protocol protocol = self.get_protocol(protocol) # Set the builder builder = self.process_class.get_builder() # Set code builder.code = orm.load_code(calc_engines['relax']['code']) # Set structure builder.structure = structure # Set options builder.options = plugins.DataFactory('dict')( dict=calc_engines['relax']['options']) # Set settings # Make sure we add forces and stress for the VASP parser settings = AttributeDict() settings.update( {'parser_settings': { 'add_forces': True, 'add_stress': True }}) builder.settings = plugins.DataFactory('dict')(dict=settings) # Set workchain related inputs, in this case, give more explicit output to report builder.verbose = plugins.DataFactory('bool')(True) # Set parameters builder.parameters = plugins.DataFactory('dict')( dict=protocol['parameters']) # Set potentials and their mapping builder.potential_family = plugins.DataFactory('str')( protocol['potential_family']) builder.potential_mapping = plugins.DataFactory('dict')( dict=self._potential_mapping[protocol['potential_mapping']]) # Set the kpoint grid from the density in the protocol kpoints = plugins.DataFactory('array.kpoints')() kpoints.set_kpoints_mesh([1, 1, 1]) kpoints.set_cell_from_structure(structure) rec_cell = kpoints.reciprocal_cell kpoints.set_kpoints_mesh( fetch_k_grid(rec_cell, protocol['kpoint_distance'])) builder.kpoints = kpoints # Here we set the protocols fast, moderate and precise. These currently have no formal meaning. # After a while these will be set in the VASP workchain entrypoints using the convergence workchain etc. # However, for now we rely on defaults plane wave cutoffs and a set k-point density for the chosen protocol. relax = AttributeDict() relax.perform = plugins.DataFactory('bool')(True) relax.algo = plugins.DataFactory('str')(protocol['relax']['algo']) if relax_type == RelaxType.ATOMS: relax.positions = plugins.DataFactory('bool')(True) relax.shape = plugins.DataFactory('bool')(False) relax.volume = plugins.DataFactory('bool')(False) elif relax_type == RelaxType.CELL: relax.positions = plugins.DataFactory('bool')(False) relax.shape = plugins.DataFactory('bool')(True) relax.volume = plugins.DataFactory('bool')(True) elif relax_type == RelaxType.ATOMS_CELL: relax.positions = plugins.DataFactory('bool')(True) relax.shape = plugins.DataFactory('bool')(True) relax.volume = plugins.DataFactory('bool')(True) else: raise ValueError('relaxation type `{}` is not supported'.format( relax_type.value)) if threshold_forces is not None: threshold = threshold_forces else: threshold = protocol['relax']['threshold_forces'] relax.force_cutoff = plugins.DataFactory('float')(threshold) if threshold_stress is not None: raise ValueError( 'Using a stress threshold is not directly available in VASP during relaxation.' ) builder.relax = relax return builder
def _construct_builder(self, **kwargs) -> engine.ProcessBuilder: """Construct a process builder based on the provided keyword arguments. The keyword arguments will have been validated against the input generator specification. """ # pylint: disable=too-many-branches,too-many-statements,too-many-locals structure = kwargs['structure'] engines = kwargs['engines'] protocol = kwargs['protocol'] spin_type = kwargs['spin_type'] relax_type = kwargs['relax_type'] magnetization_per_site = kwargs.get('magnetization_per_site', None) threshold_forces = kwargs.get('threshold_forces', None) threshold_stress = kwargs.get('threshold_stress', None) reference_workchain = kwargs.get('reference_workchain', None) # Get the protocol that we want to use if protocol is None: protocol = self._default_protocol protocol = self.get_protocol(protocol) # Set the builder builder = self.process_class.get_builder() # Set code builder.code = orm.load_code(engines['relax']['code']) # Set structure builder.structure = structure # Set options builder.options = plugins.DataFactory('dict')( dict=engines['relax']['options']) # Set settings # Make sure the VASP parser is configured for the problem settings = AttributeDict() settings.update({ 'parser_settings': { 'add_energies': True, 'add_forces': True, 'add_stress': True, 'add_misc': { 'type': 'dict', 'quantities': [ 'total_energies', 'maximum_stress', 'maximum_force', 'magnetization', 'notifications', 'run_status', 'run_stats', 'version' ], 'link_name': 'misc' } } }) builder.settings = plugins.DataFactory('dict')(dict=settings) # Set workchain related inputs, in this case, give more explicit output to report builder.verbose = plugins.DataFactory('bool')(True) # Fetch initial parameters from the protocol file. # Here we set the protocols fast, moderate and precise. These currently have no formal meaning. # After a while these will be set in the VASP workchain entrypoints using the convergence workchain etc. # However, for now we rely on plane wave cutoffs and a set k-point density for the chosen protocol. # Please consult the protocols.yml file for details. parameters_dict = protocol['parameters'] # Set spin related parameters if spin_type == SpinType.NONE: parameters_dict['ispin'] = 1 elif spin_type == SpinType.COLLINEAR: parameters_dict['ispin'] = 2 # Set the magnetization if magnetization_per_site is not None: parameters_dict['magmom'] = list(magnetization_per_site) # Set the parameters on the builder, put it in the code namespace to pass through # to the code inputs builder.parameters = plugins.DataFactory('dict')( dict={ 'incar': parameters_dict }) # Set potentials and their mapping builder.potential_family = plugins.DataFactory('str')( protocol['potential_family']) builder.potential_mapping = plugins.DataFactory('dict')( dict=self._potential_mapping[protocol['potential_mapping']]) # Set the kpoint grid from the density in the protocol kpoints = plugins.DataFactory('array.kpoints')() kpoints.set_cell_from_structure(structure) if reference_workchain: previous_kpoints = reference_workchain.inputs.kpoints kpoints.set_kpoints_mesh(previous_kpoints.get_attribute('mesh'), previous_kpoints.get_attribute('offset')) else: kpoints.set_kpoints_mesh_from_density(protocol['kpoint_distance']) builder.kpoints = kpoints # Set the relax parameters relax = AttributeDict() if relax_type != RelaxType.NONE: # Perform relaxation of cell or positions relax.perform = plugins.DataFactory('bool')(True) relax.algo = plugins.DataFactory('str')(protocol['relax']['algo']) relax.steps = plugins.DataFactory('int')( protocol['relax']['steps']) if relax_type == RelaxType.POSITIONS: relax.positions = plugins.DataFactory('bool')(True) relax.shape = plugins.DataFactory('bool')(False) relax.volume = plugins.DataFactory('bool')(False) elif relax_type == RelaxType.CELL: relax.positions = plugins.DataFactory('bool')(False) relax.shape = plugins.DataFactory('bool')(True) relax.volume = plugins.DataFactory('bool')(True) elif relax_type == RelaxType.VOLUME: relax.positions = plugins.DataFactory('bool')(False) relax.shape = plugins.DataFactory('bool')(False) relax.volume = plugins.DataFactory('bool')(True) elif relax_type == RelaxType.SHAPE: relax.positions = plugins.DataFactory('bool')(False) relax.shape = plugins.DataFactory('bool')(True) relax.volume = plugins.DataFactory('bool')(False) elif relax_type == RelaxType.POSITIONS_CELL: relax.positions = plugins.DataFactory('bool')(True) relax.shape = plugins.DataFactory('bool')(True) relax.volume = plugins.DataFactory('bool')(True) elif relax_type == RelaxType.POSITIONS_SHAPE: relax.positions = plugins.DataFactory('bool')(True) relax.shape = plugins.DataFactory('bool')(True) relax.volume = plugins.DataFactory('bool')(False) else: # Do not perform any relaxation relax.perform = plugins.DataFactory('bool')(False) if threshold_forces is not None: threshold = threshold_forces else: threshold = protocol['relax']['threshold_forces'] relax.force_cutoff = plugins.DataFactory('float')(threshold) if threshold_stress is not None: raise ValueError( 'Using a stress threshold is not directly available in VASP during relaxation.' ) builder.relax = relax return builder
def get_builder(self, structure, calc_engines, protocol, relaxation_type, threshold_forces=None, threshold_stress=None, previous_workchain=None, **kwargs): """Return a process builder for the corresponding workchain class with inputs set according to the protocol. :param structure: the structure to be relaxed :param calc_engines: ... :param protocol: the protocol to use when determining the workchain inputs :param relaxation_type: the type of relaxation to perform, instance of `RelaxType` :param threshold_forces: target threshold for the forces in eV/Å. :param threshold_stress: target threshold for the stress in eV/Å^3. :param kwargs: any inputs that are specific to the plugin. :return: a `aiida.engine.processes.ProcessBuilder` instance ready to be submitted. """ # pylint: disable=too-many-locals super().get_builder(structure, calc_engines, protocol, relaxation_type, threshold_forces, threshold_stress, previous_workchain, **kwargs) # Get the protocol that we want to use if protocol is None: protocol = self._default_protocol protocol = self.get_protocol(protocol) # Set the builder builder = self.process_class.get_builder() # Set code builder.code = Code.get_from_string(calc_engines['relax']['code']) # Set structure builder.structure = structure # Set options builder.options = DataFactory('dict')( dict=calc_engines['relax']['options']) # Set settings # Make sure we add forces and stress for the VASP parser settings = AttributeDict() settings.update( {'parser_settings': { 'add_forces': True, 'add_stress': True }}) builder.settings = DataFactory('dict')(dict=settings) # Set workchain related inputs, in this case, give more explicit output to report builder.verbose = DataFactory('bool')(True) # Set parameters builder.parameters = DataFactory('dict')(dict=protocol['parameters']) # Set potentials and their mapping builder.potential_family = DataFactory('str')( protocol['potential_family']) builder.potential_mapping = DataFactory('dict')( dict=self._potential_mapping[protocol['potential_mapping']]) # Set the kpoint grid from the density in the protocol kpoints = DataFactory('array.kpoints')() kpoints.set_kpoints_mesh([1, 1, 1]) kpoints.set_cell_from_structure(structure) rec_cell = kpoints.reciprocal_cell kpoints.set_kpoints_mesh( fetch_k_grid(rec_cell, protocol['kpoint_distance'])) builder.kpoints = kpoints # Here we set the protocols fast, moderate and precise. These currently have no formal meaning. # After a while these will be set in the VASP workchain entrypoints using the convergence workchain etc. # However, for now we rely on defaults plane wave cutoffs and a set k-point density for the chosen protocol. relax = AttributeDict() relax.perform = DataFactory('bool')(True) relax.algo = DataFactory('str')(protocol['relax']['algo']) if relaxation_type == RelaxType.ATOMS: relax.positions = DataFactory('bool')(True) relax.shape = DataFactory('bool')(False) relax.volume = DataFactory('bool')(False) elif relaxation_type == RelaxType.CELL: relax.positions = DataFactory('bool')(False) relax.shape = DataFactory('bool')(True) relax.volume = DataFactory('bool')(True) elif relaxation_type == RelaxType.ATOMS_CELL: relax.positions = DataFactory('bool')(True) relax.shape = DataFactory('bool')(True) relax.volume = DataFactory('bool')(True) else: raise ValueError('relaxation type `{}` is not supported'.format( relaxation_type.value)) if threshold_forces is not None: threshold = threshold_forces else: threshold = protocol['relax']['threshold_forces'] relax.force_cutoff = DataFactory('float')(threshold) if threshold_stress is not None: raise ValueError( 'Using a stress threshold is not directly available in VASP during relaxation.' ) builder.relax = relax return builder
def get_builder(self, structure: StructureData, engines: Dict[str, Any], *, protocol: str = None, relax_type: RelaxType = RelaxType.POSITIONS, electronic_type: ElectronicType = ElectronicType.METAL, spin_type: SpinType = SpinType.NONE, magnetization_per_site: List[float] = None, threshold_forces: float = None, threshold_stress: float = None, reference_workchain=None, **kwargs) -> engine.ProcessBuilder: """Return a process builder for the corresponding workchain class with inputs set according to the protocol. :param structure: the structure to be relaxed. :param engines: a dictionary containing the computational resources for the relaxation. :param protocol: the protocol to use when determining the workchain inputs. :param relax_type: the type of relaxation to perform. :param electronic_type: the electronic character that is to be used for the structure. :param spin_type: the spin polarization type to use for the calculation. :param magnetization_per_site: a list with the initial spin polarization for each site. Float or integer in units of electrons. If not defined, the builder will automatically define the initial magnetization if and only if `spin_type != SpinType.NONE`. :param threshold_forces: target threshold for the forces in eV/Å. :param threshold_stress: target threshold for the stress in eV/Å^3. :param reference_workchain: a <Code>RelaxWorkChain node. :param kwargs: any inputs that are specific to the plugin. :return: a `aiida.engine.processes.ProcessBuilder` instance ready to be submitted. """ # pylint: disable=too-many-locals, too-many-branches, too-many-statements protocol = protocol or self.get_default_protocol_name() super().get_builder(structure, engines, protocol=protocol, relax_type=relax_type, electronic_type=electronic_type, spin_type=spin_type, magnetization_per_site=magnetization_per_site, threshold_forces=threshold_forces, threshold_stress=threshold_stress, reference_workchain=reference_workchain, **kwargs) # Get the protocol that we want to use if protocol is None: protocol = self._default_protocol protocol = self.get_protocol(protocol) # Set the builder builder = self.process_class.get_builder() # Set code builder.code = orm.load_code(engines['relax']['code']) # Set structure builder.structure = structure # Set options builder.options = plugins.DataFactory('dict')( dict=engines['relax']['options']) # Set settings # Make sure the VASP parser is configured for the problem settings = AttributeDict() settings.update({ 'parser_settings': { 'add_energies': True, 'add_forces': True, 'add_stress': True, 'add_misc': { 'type': 'dict', 'quantities': [ 'total_energies', 'maximum_stress', 'maximum_force', 'magnetization', 'notifications', 'run_status', 'run_stats', 'version' ], 'link_name': 'misc' } } }) builder.settings = plugins.DataFactory('dict')(dict=settings) # Set workchain related inputs, in this case, give more explicit output to report builder.verbose = plugins.DataFactory('bool')(True) # Fetch initial parameters from the protocol file. # Here we set the protocols fast, moderate and precise. These currently have no formal meaning. # After a while these will be set in the VASP workchain entrypoints using the convergence workchain etc. # However, for now we rely on plane wave cutoffs and a set k-point density for the chosen protocol. # Please consult the protocols.yml file for details. parameters_dict = protocol['parameters'] # Set spin related parameters if spin_type == SpinType.NONE: parameters_dict['ispin'] = 1 elif spin_type == SpinType.COLLINEAR: parameters_dict['ispin'] = 2 # Set the magnetization if magnetization_per_site is not None: parameters_dict['magmom'] = list(magnetization_per_site) # Set the parameters on the builder, put it in the code namespace to pass through # to the code inputs builder.parameters = plugins.DataFactory('dict')( dict={ 'incar': parameters_dict }) # Set potentials and their mapping builder.potential_family = plugins.DataFactory('str')( protocol['potential_family']) builder.potential_mapping = plugins.DataFactory('dict')( dict=self._potential_mapping[protocol['potential_mapping']]) # Set the kpoint grid from the density in the protocol kpoints = plugins.DataFactory('array.kpoints')() kpoints.set_cell_from_structure(structure) if reference_workchain: previous_kpoints = reference_workchain.inputs.kpoints kpoints.set_kpoints_mesh(previous_kpoints.get_attribute('mesh'), previous_kpoints.get_attribute('offset')) else: kpoints.set_kpoints_mesh_from_density(protocol['kpoint_distance']) builder.kpoints = kpoints # Set the relax parameters relax = AttributeDict() if relax_type != RelaxType.NONE: # Perform relaxation of cell or positions relax.perform = plugins.DataFactory('bool')(True) relax.algo = plugins.DataFactory('str')(protocol['relax']['algo']) relax.steps = plugins.DataFactory('int')( protocol['relax']['steps']) if relax_type == RelaxType.POSITIONS: relax.positions = plugins.DataFactory('bool')(True) relax.shape = plugins.DataFactory('bool')(False) relax.volume = plugins.DataFactory('bool')(False) elif relax_type == RelaxType.CELL: relax.positions = plugins.DataFactory('bool')(False) relax.shape = plugins.DataFactory('bool')(True) relax.volume = plugins.DataFactory('bool')(True) elif relax_type == RelaxType.VOLUME: relax.positions = plugins.DataFactory('bool')(False) relax.shape = plugins.DataFactory('bool')(False) relax.volume = plugins.DataFactory('bool')(True) elif relax_type == RelaxType.SHAPE: relax.positions = plugins.DataFactory('bool')(False) relax.shape = plugins.DataFactory('bool')(True) relax.volume = plugins.DataFactory('bool')(False) elif relax_type == RelaxType.POSITIONS_CELL: relax.positions = plugins.DataFactory('bool')(True) relax.shape = plugins.DataFactory('bool')(True) relax.volume = plugins.DataFactory('bool')(True) elif relax_type == RelaxType.POSITIONS_SHAPE: relax.positions = plugins.DataFactory('bool')(True) relax.shape = plugins.DataFactory('bool')(True) relax.volume = plugins.DataFactory('bool')(False) else: # Do not perform any relaxation relax.perform = plugins.DataFactory('bool')(False) if threshold_forces is not None: threshold = threshold_forces else: threshold = protocol['relax']['threshold_forces'] relax.force_cutoff = plugins.DataFactory('float')(threshold) if threshold_stress is not None: raise ValueError( 'Using a stress threshold is not directly available in VASP during relaxation.' ) builder.relax = relax return builder