Ejemplo n.º 1
0
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)
Ejemplo n.º 2
0
    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
Ejemplo n.º 3
0
    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
Ejemplo n.º 4
0
    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
Ejemplo n.º 5
0
    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