Exemplo n.º 1
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