Beispiel #1
0
    def test_port_names_overlapping_mutable_mapping_methods(self):  # pylint: disable=invalid-name
        """Check that port names take precedence over `collections.MutableMapping` methods.

        The `ProcessBuilderNamespace` is a `collections.MutableMapping` but since the port names are made accessible
        as attributes, they can overlap with some of the mappings builtin methods, e.g. `values()`, `items()` etc.
        The port names should take precendence in this case and if one wants to access the mapping methods one needs to
        cast the builder to a dictionary first."""
        builder = ExampleWorkChain.get_builder()

        # The `values` method is obscured by a port that also happens to be called `values`, so calling it should raise
        with self.assertRaises(TypeError):
            builder.values()  # pylint: disable=not-callable

        # However, we can assign a node to it
        builder.values = orm.Int(2)

        # Calling the attribute `values` will then actually try to call the node, which should raise
        with self.assertRaises(TypeError):
            builder.values()  # pylint: disable=not-callable

        # Casting the builder to a dict, *should* then make `values` callable again
        self.assertIn(orm.Int(2), dict(builder).values())

        # The mapping methods should not be auto-completed, i.e. not in the values returned by calling `dir`
        for method in [method for method in dir(MutableMapping) if method != 'values']:
            self.assertNotIn(method, dir(builder))

        # On the other hand, all the port names *should* be present
        for port_name in ExampleWorkChain.spec().inputs.keys():
            self.assertIn(port_name, dir(builder))

        # The `update` method is implemented, but prefixed with an underscore to not block the name for a port
        builder.update({'boolean': orm.Bool(False)})
        self.assertEqual(builder.boolean, orm.Bool(False))
Beispiel #2
0
    def prepare_kgrids(self):
        """Generate the complementary kpoints grids (FULL - CROP) & CROP"""
        inputs = {
            'structure': self.ctx.current_structure,
            # 'distance': self.inputs.kpoints_distance,
            'force_parity': orm.Bool(False),
            'metadata': {'call_link_label': 'create_kpoints_from_distance'}
        }
        inputs['distance'] = self.inputs.nscf_full.kpoints_distance
        k_full = create_kpoints_from_distance(**inputs)
        inputs['distance'] = self.inputs.nscf_crop.kpoints_distance
        k_crop = create_kpoints_from_distance(**inputs)

        nk_full = len(k_full.get_kpoints_mesh(print_list=True))
        nk_crop = len(k_crop.get_kpoints_mesh(print_list=True))
        self.ctx.kpoint_full = kpt_crop(k_full, self.inputs.crop_centers, self.inputs.crop_radii, orm.Bool(True))
        self.ctx.kpoint_crop = kpt_crop(k_crop, self.inputs.crop_centers, self.inputs.crop_radii, orm.Bool(False))
        self.ctx.kpoint_full_weight = self.ctx.kpoint_full
        self.ctx.kpoint_crop_weight = self.ctx.kpoint_crop
        nka_full = len(self.ctx.kpoint_full.get_kpoints())
        nka_crop = len(self.ctx.kpoint_crop.get_kpoints())
        nka_full_weight = self.ctx.kpoint_full.get_array('weights').sum()
        nka_crop_weight = self.ctx.kpoint_crop.get_array('weights').sum()
        self.report('{}/{} k-points anti-cropped from FULL grid. tot_weight={}'.format(nka_full, nk_full, nka_full_weight))
        self.report('{}/{} k-points cropped from CROP grid. tot_weight={}'.format(nka_crop, nk_crop, nka_crop_weight))

        self.out('kpoints_full', self.ctx.kpoint_full)
        self.out('kpoints_crop', self.ctx.kpoint_crop)
Beispiel #3
0
    def define(cls, spec):
        """Define the process specification."""
        # yapf: disable
        super().define(spec)
        # spec.expose_inputs(PwRelaxWorkChain, namespace='relax', exclude=('clean_workdir', 'structure'),
        #     namespace_options={'required': False, 'populate_defaults': False,
        #     'help': 'Inputs for the `PwRelaxWorkChain`, if not specified at all, the relaxation step is skipped.'})
        spec.expose_inputs(PwBaseWorkChain, namespace='scf',
            exclude=('clean_workdir', 'pw.structure'),
            namespace_options={'help': 'Inputs for the `PwBaseWorkChain` for the SCF calculation.'})
        spec.expose_inputs(PwBaseWorkChain, namespace='nscf',
            exclude=('clean_workdir', 'pw.structure'),
            namespace_options={'help': 'Inputs for the `PwBaseWorkChain` for the NSCF calculation.'})
        spec.expose_inputs(Pw2gwCalc, namespace='pw2gw',
            exclude=('parent_folder', ),
            namespace_options={'help': 'Inputs for the `DosCalculation` for the DOS calculation.'})
        spec.input('parent_folder', valid_type=orm.RemoteData, required=False)
        spec.input('structure', valid_type=orm.StructureData, help='The inputs structure.')
        # spec.input('kpoints_distance', valid_type=orm.Float, required=False,
        #     help='The minimum desired distance in 1/Å between k-points in reciprocal space. The explicit k-points will '
        #          'be generated automatically by a calculation function based on the input structure.')
        spec.input('nbands_factor', valid_type=orm.Float, default=lambda: orm.Float(1.5),
            help='The number of bands for the BANDS calculation is that used for the SCF multiplied by this factor.')
        spec.input('clean_workdir', valid_type=orm.Bool, default=lambda: orm.Bool(False),
            help='If `True`, work directories of all called calculation will be cleaned at the end of execution.')

        spec.outline(
            cls.setup,
            if_(cls.should_do_scf)(
                cls.run_scf,
                cls.inspect_scf,
                ),
            cls.run_nscf,
            cls.inspect_nscf,
            cls.run_pw2gw,
            cls.inspect_pw2gw,
            cls.results,
        )
        spec.exit_code(201, 'ERROR_INVALID_INPUT_NUMBER_OF_BANDS',
            message='Cannot specify both `nbands_factor` and `bands.pw.parameters.SYSTEM.nbnd`.')
        spec.exit_code(202, 'ERROR_INVALID_INPUT_KPOINTS',
            message='Cannot specify both `bands_kpoints` and `bands_kpoints_distance`.')
        spec.exit_code(401, 'ERROR_SUB_PROCESS_FAILED_RELAX',
            message='The PwRelaxWorkChain sub process failed')
        spec.exit_code(402, 'ERROR_SUB_PROCESS_FAILED_SCF',
            message='The scf PwBasexWorkChain sub process failed')
        spec.exit_code(403, 'ERROR_SUB_PROCESS_FAILED_NSCF',
            message='The bands PwBasexWorkChain sub process failed')
        spec.exit_code(405, 'ERROR_SUB_PROCESS_FAILED_PW2GW',
            message='The pw2gw Pw2gwCalculation sub process failed')

        spec.output('scf_remote_folder', valid_type=orm.RemoteData, required=False)
        spec.output('nscf_remote_folder', valid_type=orm.RemoteData)
        spec.output('scf_parameters', valid_type=orm.Dict, required=False,
            help='The output parameters of the SCF `PwBaseWorkChain`.')
        spec.output('nscf_parameters', valid_type=orm.Dict,
            help='The output parameters of the NSCF `PwBaseWorkChain`.')
        spec.output('pw2gw_parameters', valid_type=orm.Dict,
            help='The output parameters of the PW2GW calculation.')
        spec.output('eps', valid_type=orm.ArrayData)
 def define(cls, spec):
     super(BigDFTRelaxWorkChain, cls).define(spec)
     spec.expose_inputs(BigDFTBaseWorkChain,
                        exclude=['parameters',
                                 'extra_retrieved_files'])
     spec.input('parameters', valid_type=BigDFTParameters, required=False,
                default=lambda: orm.Dict(), help='param dictionary')
     spec.input('extra_retrieved_files', valid_type=List, required=False,
                help='', default=lambda: List())
     spec.input('relax.perform', valid_type=orm.Bool, required=False,
                default=lambda: orm.Bool(True), help='perform relaxation')
     spec.input('relax.algo', valid_type=orm.Str,
                default=lambda: orm.Str('FIRE'),
                help='algorithm to use during relaxation')
     spec.input('relax.threshold_forces', valid_type=orm.Float, required=False,
                default=lambda: orm.Float(0.0), help='energy cutoff value, in ev/Ang')
     spec.input('relax.steps', valid_type=orm.Int, required=False,
                default=lambda: orm.Int(50),
                help='number of relaxation steps to perform.')
     spec.outline(
         cls.relax,
         cls.results,
     )
     spec.expose_outputs(BigDFTBaseWorkChain)
     spec.output('relaxed_structure', valid_type=StructureData,
                 required=False)
     spec.output('forces', valid_type=ArrayData, required=False)
     spec.output('total_energy', valid_type=orm.Float, required=False)
     spec.exit_code(101, 'ERROR_FAILED_RELAX',
                    'Subprocess failed for relaxation')
Beispiel #5
0
    def test_output_validation_error(self):
        """Test that a process is marked as failed if its output namespace validation fails."""

        class TestProcess1(Process):
            """Defining a new TestProcess class for testing."""

            _node_class = orm.WorkflowNode

            @classmethod
            def define(cls, spec):
                super().define(spec)
                spec.input('add_outputs', valid_type=orm.Bool, default=lambda: orm.Bool(False))
                spec.output_namespace('integer.namespace', valid_type=orm.Int, dynamic=True)
                spec.output('required_string', valid_type=orm.Str, required=True)

            def run(self):
                if self.inputs.add_outputs:
                    self.out('required_string', orm.Str('testing').store())
                    self.out('integer.namespace.two', orm.Int(2).store())

        _, node = run_get_node(TestProcess1)

        # For default inputs, no outputs will be attached, causing the validation to fail at the end so an internal
        # exit status will be set, which is a negative integer
        self.assertTrue(node.is_finished)
        self.assertFalse(node.is_finished_ok)
        self.assertEqual(node.exit_status, TestProcess1.exit_codes.ERROR_MISSING_OUTPUT.status)
        self.assertEqual(node.exit_message, TestProcess1.exit_codes.ERROR_MISSING_OUTPUT.message)

        # When settings `add_outputs` to True, the outputs should be added and validation should pass
        _, node = run_get_node(TestProcess1, add_outputs=orm.Bool(True))
        self.assertTrue(node.is_finished)
        self.assertTrue(node.is_finished_ok)
        self.assertEqual(node.exit_status, 0)
Beispiel #6
0
    def validate_kpoints(self):
        """Validate the inputs related to k-points.

        Either an explicit `KpointsData` with given mesh/path, or a desired k-points distance should be specified. In
        the case of the latter, the `KpointsData` will be constructed for the input `StructureData` using the
        `create_kpoints_from_distance` calculation function.
        """
        if all([
                key not in self.inputs
                for key in ['kpoints', 'kpoints_distance']
        ]):
            return self.exit_codes.ERROR_INVALID_INPUT_KPOINTS

        try:
            kpoints = self.inputs.kpoints
        except AttributeError:
            inputs = {
                'structure':
                self.inputs.pw.structure,
                'distance':
                self.inputs.kpoints_distance,
                'force_parity':
                self.inputs.get('kpoints_force_parity', orm.Bool(False)),
                'metadata': {
                    'call_link_label': 'create_kpoints_from_distance'
                }
            }
            kpoints = create_kpoints_from_distance(**inputs)  # pylint: disable=unexpected-keyword-arg

        self.ctx.inputs.kpoints = kpoints
Beispiel #7
0
 def define(cls, spec):
     """Define the process specification."""
     # yapf: disable
     super().define(spec)
     spec.expose_inputs(PwRelaxWorkChain, namespace='relax', exclude=('clean_workdir', 'structure'),
         namespace_options={'required': False, 'populate_defaults': False,
         'help': 'Inputs for the `PwRelaxWorkChain`, if not specified at all, the relaxation step is skipped.'})
     spec.expose_inputs(PwBaseWorkChain, namespace='scf',
         exclude=('clean_workdir', 'pw.structure'),
         namespace_options={'help': 'Inputs for the `PwBaseWorkChain` for the SCF calculation.'})
     spec.expose_inputs(PwBaseWorkChain, namespace='bands',
         exclude=('clean_workdir', 'pw.structure', 'pw.kpoints', 'pw.kpoints_distance'),
         namespace_options={'help': 'Inputs for the `PwBaseWorkChain` for the BANDS calculation.'})
     spec.input('structure', valid_type=orm.StructureData, help='The inputs structure.')
     spec.input('clean_workdir', valid_type=orm.Bool, default=lambda: orm.Bool(False),
         help='If `True`, work directories of all called calculation will be cleaned at the end of execution.')
     spec.input('nbands_factor', valid_type=orm.Float, required=False,
         help='The number of bands for the BANDS calculation is that used for the SCF multiplied by this factor.')
     spec.input('bands_kpoints', valid_type=orm.KpointsData, required=False,
         help='Explicit kpoints to use for the BANDS calculation. Specify either this or `bands_kpoints_distance`.')
     spec.input('bands_kpoints_distance', valid_type=orm.Float, required=False,
         help='Minimum kpoints distance for the BANDS calculation. Specify either this or `bands_kpoints`.')
     spec.inputs.validator = validate_inputs
     spec.outline(
         cls.setup,
         if_(cls.should_run_relax)(
             cls.run_relax,
             cls.inspect_relax,
         ),
         if_(cls.should_run_seekpath)(
             cls.run_seekpath,
         ),
         cls.run_scf,
         cls.inspect_scf,
         cls.run_bands,
         cls.inspect_bands,
         cls.results,
     )
     spec.exit_code(201, 'ERROR_INVALID_INPUT_NUMBER_OF_BANDS',
         message='Cannot specify both `nbands_factor` and `bands.pw.parameters.SYSTEM.nbnd`.')
     spec.exit_code(202, 'ERROR_INVALID_INPUT_KPOINTS',
         message='Cannot specify both `bands_kpoints` and `bands_kpoints_distance`.')
     spec.exit_code(401, 'ERROR_SUB_PROCESS_FAILED_RELAX',
         message='The PwRelaxWorkChain sub process failed')
     spec.exit_code(402, 'ERROR_SUB_PROCESS_FAILED_SCF',
         message='The scf PwBasexWorkChain sub process failed')
     spec.exit_code(403, 'ERROR_SUB_PROCESS_FAILED_BANDS',
         message='The bands PwBasexWorkChain sub process failed')
     spec.output('primitive_structure', valid_type=orm.StructureData,
         required=False,
         help='The normalized and primitivized structure for which the bands are computed.')
     spec.output('seekpath_parameters', valid_type=orm.Dict,
         required=False,
         help='The parameters used in the SeeKpath call to normalize the input or relaxed structure.')
     spec.output('scf_parameters', valid_type=orm.Dict,
         help='The output parameters of the SCF `PwBaseWorkChain`.')
     spec.output('band_parameters', valid_type=orm.Dict,
         help='The output parameters of the BANDS `PwBaseWorkChain`.')
     spec.output('band_structure', valid_type=orm.BandsData,
         help='The computed band structure.')
 def define(cls, spec):
     """Define the process specification."""
     # yapf: disable
     super(PwBandStructureWorkChain, cls).define(spec)
     spec.input('code', valid_type=orm.Code,
                help='The `pw.x` code to use for the `PwCalculations`.')
     spec.input('structure', valid_type=orm.StructureData,
                help='The input structure.')
     spec.input('options', valid_type=orm.Dict, required=False,
                help='Optional `options` to use for the `PwCalculations`.')
     spec.input('protocol', valid_type=orm.Dict, default=lambda: orm.Dict(dict={'name': 'theos-ht-1.0'}),
                help='The protocol to use for the workchain.', validator=validate_protocol)
     # MODIFIED
     spec.input('pseudo_family', valid_type=orm.Str, required=False,
                help='[Deprecated: use `pw.pseudos` instead] An alternative to specifying the pseudo potentials manually in'
                ' `pseudos`: one can specify the name of an existing pseudo potential family and the work chain will '
                'generate the pseudos automatically based on the input structure.')
     spec.input('set_2d_mesh', valid_type=orm.Bool, default=lambda: orm.Bool(
         False), help='Set the mesh to [x,x,1]')
     spec.expose_outputs(PwBandsWorkChain)
     spec.outline(
         cls.setup_protocol,
         cls.setup_parameters,
         cls.run_bands,
         cls.results,
     )
     spec.exit_code(201, 'ERROR_INVALID_INPUT_UNRECOGNIZED_KIND',
                    message='Input `StructureData` contains an unsupported kind.')
     spec.exit_code(401, 'ERROR_SUB_PROCESS_FAILED_BANDS',
                    message='The `PwBandsWorkChain` sub process failed.')
     spec.output('primitive_structure', valid_type=orm.StructureData)
     spec.output('seekpath_parameters', valid_type=orm.Dict)
     spec.output('scf_parameters', valid_type=orm.Dict)
     spec.output('band_parameters', valid_type=orm.Dict)
     spec.output('band_structure', valid_type=orm.BandsData)
def generate_inputs_base(protocol: Dict,
                         code: orm.Code,
                         structure: StructureData,
                         sssp_family: SsspFamily,
                         override: Dict[str, Any] = None) -> Dict[str, Any]:
    """Generate the inputs for the `PwBaseWorkChain` for a given code, structure and pseudo potential family.

    :param protocol: the dictionary with protocol inputs.
    :param code: the code to use.
    :param structure: the input structure.
    :param sssp_family: the pseudo potential family.
    :param override: a dictionary to override specific inputs.
    :return: the fully defined input dictionary.
    """
    protocol['pw'] = generate_inputs_calculation(protocol['pw'], code,
                                                 structure, sssp_family,
                                                 override.get('pw', {}))
    merged = recursive_merge(protocol, override or {})

    dictionary = {
        'pw': merged['pw'],
        'kpoints_distance': orm.Float(merged['kpoints_distance']),
        'kpoints_force_parity': orm.Bool(merged['kpoints_force_parity']),
    }

    return dictionary
Beispiel #10
0
    def parse(self, **kwargs):
        """Parse the contents of the output files stored in the `retrieved` output node."""

        try:
            with self.retrieved.open(self.node.get_option("output_filename"),
                                     "r") as handle:
                result = handle.read().strip()
        except OSError:
            return self.exit_codes.ERROR_READING_OUTPUT_FILE

        try:
            with self.retrieved.open(self.node.get_option("payload_filename"),
                                     "r") as handle:
                pass
        except OSError:
            return self.exit_codes.ERROR_READING_PAYLOAD_FILE

        self.out("result", orm.Bool(result == "success"))
        self.out(
            "out_dict",
            orm.Dict(
                dict={
                    f"output_key_{i}": f"value_{i}"
                    for i in range(self.node.get_option("output_dict_size"))
                }),
        )
        array = orm.ArrayData()
        array.set_array("example",
                        np.ones(self.node.get_option("output_array_size")))
        self.out("out_array", array)

        if not result == "success":
            return self.exit_codes.ERROR_FAILED_OUTPUT
Beispiel #11
0
def test_sequential_not_conv(aiida_profile, generate_workchain_seq_converger,
                             generate_wc_job_node, fixture_localhost):
    """
    We test here the SiestaSequentialConverger, in the case a Converger fails
    to converge.
    """

    from aiida.common.extendeddicts import AttributeDict

    process = generate_workchain_seq_converger()
    process.initialize()

    assert process.ctx.iteration_keys == ('iterate_over', )

    inputs = {"iterate_over": orm.Dict(dict={"s": [2, 2]})}
    convergerwc = generate_wc_job_node("siesta.converger", fixture_localhost,
                                       inputs)
    convergerwc.set_process_state(ProcessState.FINISHED)
    convergerwc.set_exit_status(ExitCode(0).status)
    out_conv = orm.Bool(False)
    out_conv.store()
    out_conv.add_incoming(convergerwc,
                          link_type=LinkType.RETURN,
                          link_label='converged')

    process.ctx.last_inputs = AttributeDict({"parameters": {"yo": "yo"}})

    process._analyze_process(convergerwc)

    assert process.ctx.already_converged == {}
    assert "parameters" in process.ctx.last_inputs
Beispiel #12
0
    def test_valid_cache_hook(self):
        """
        Test that the is_valid_cache behavior can be specified from
        the method in the Process sub-class.
        """
        # Sanity check that caching works when the hook returns True.
        with enable_caching():
            _, node1 = run_get_node(test_processes.IsValidCacheHook)
            _, node2 = run_get_node(test_processes.IsValidCacheHook)
            self.assertEqual(node1.get_extra('_aiida_hash'), node2.get_extra('_aiida_hash'))
            self.assertIn('_aiida_cached_from', node2.extras)

        with enable_caching():
            _, node3 = run_get_node(test_processes.IsValidCacheHook, not_valid_cache=orm.Bool(True))
            _, node4 = run_get_node(test_processes.IsValidCacheHook, not_valid_cache=orm.Bool(True))
            self.assertEqual(node3.get_extra('_aiida_hash'), node4.get_extra('_aiida_hash'))
            self.assertNotIn('_aiida_cached_from', node4.extras)
Beispiel #13
0
 def define(cls, spec):
     """Define the process specification."""
     # yapf: disable
     super().define(spec)
     spec.expose_inputs(PwBaseWorkChain, namespace='base',
         exclude=('clean_workdir', 'pw.structure', 'pw.parent_folder'),
         namespace_options={'help': 'Inputs for the `PwBaseWorkChain` for the main relax loop.'})
     spec.expose_inputs(PwBaseWorkChain, namespace='base_final_scf',
         exclude=('clean_workdir', 'pw.structure', 'pw.parent_folder'),
         namespace_options={'required': False, 'populate_defaults': False,
             'help': 'Inputs for the `PwBaseWorkChain` for the final scf.'})
     spec.input('structure', valid_type=orm.StructureData, help='The inputs structure.')
     spec.input('final_scf', valid_type=orm.Bool, default=lambda: orm.Bool(False), validator=validate_final_scf,
         help='If `True`, a final SCF calculation will be performed on the successfully relaxed structure.')
     spec.input('relaxation_scheme', valid_type=orm.Str, required=False, validator=validate_relaxation_scheme,
         help='The relaxation scheme to use: choose either `relax` or `vc-relax` for variable cell relax.')
     spec.input('relax_type', valid_type=orm.Str, default=lambda: orm.Str(RelaxType.ATOMS_CELL.value),
         validator=validate_relax_type,
         help='The relax type to use: should be a value of the enum ``common.types.RelaxType``.')
     spec.input('meta_convergence', valid_type=orm.Bool, default=lambda: orm.Bool(True),
         help='If `True` the workchain will perform a meta-convergence on the cell volume.')
     spec.input('max_meta_convergence_iterations', valid_type=orm.Int, default=lambda: orm.Int(5),
         help='The maximum number of variable cell relax iterations in the meta convergence cycle.')
     spec.input('volume_convergence', valid_type=orm.Float, default=lambda: orm.Float(0.01),
         help='The volume difference threshold between two consecutive meta convergence iterations.')
     spec.input('clean_workdir', valid_type=orm.Bool, default=lambda: orm.Bool(False),
         help='If `True`, work directories of all called calculation will be cleaned at the end of execution.')
     spec.outline(
         cls.setup,
         while_(cls.should_run_relax)(
             cls.run_relax,
             cls.inspect_relax,
         ),
         if_(cls.should_run_final_scf)(
             cls.run_final_scf,
             cls.inspect_final_scf,
         ),
         cls.results,
     )
     spec.exit_code(401, 'ERROR_SUB_PROCESS_FAILED_RELAX',
         message='the relax PwBaseWorkChain sub process failed')
     spec.exit_code(402, 'ERROR_SUB_PROCESS_FAILED_FINAL_SCF',
         message='the final scf PwBaseWorkChain sub process failed')
     spec.expose_outputs(PwBaseWorkChain, exclude=('output_structure',))
     spec.output('output_structure', valid_type=orm.StructureData, required=False,
         help='The successfully relaxed structure, unless `relax_type is RelaxType.NONE`.')
def submit_workchain(xsf_file, protocol, only_valence, do_disentanglement,
                     do_mlwf, retrieve_hamiltonian, group_name):
    codes = check_codes()

    group_name = update_group_name(group_name, only_valence,
                                   do_disentanglement, do_mlwf)

    if isinstance(xsf_file, orm.StructureData):
        structure = xsf_file
    else:
        structure = read_structure(xsf_file)

    controls = {
        'retrieve_hamiltonian': orm.Bool(retrieve_hamiltonian),
        'only_valence': orm.Bool(only_valence),
        'do_disentanglement': orm.Bool(do_disentanglement),
        'do_mlwf': orm.Bool(do_mlwf)
    }

    if only_valence:
        print("Running only_valence/insulating for {}".format(
            structure.get_formula()))
    else:
        print("Running with conduction bands for {}".format(
            structure.get_formula()))

    wannier90_workchain_parameters = {
        "code": {
            'pw': codes['pw_code'],
            'pw2wannier90': codes['pw2wannier90_code'],
            'projwfc': codes['projwfc_code'],
            'wannier90': codes['wannier90_code']
        },
        "protocol": orm.Dict(dict={'name': protocol}),
        "structure": structure,
        "controls": controls
    }

    workchain = submit(Wannier90BandsWorkChain,
                       **wannier90_workchain_parameters)

    add_to_group(workchain, group_name)
    print_help(workchain, structure)
    return workchain.pk
def submit_workchain(structure,
                     daemon,
                     protocol,
                     parameters,
                     pseudo_family,
                     num_machines,
                     num_mpiprocs_per_machine=4,
                     set_2d_mesh=False):
    print("running dft band structure calculation for {}".format(
        structure.get_formula()))

    # Set custom pseudo
    modifiers = {'parameters': parameters}
    """ if pseudo_family is not None:
        from aiida_quantumespresso.utils.protocols.pw import _load_pseudo_metadata
        pseudo_data = _load_pseudo_metadata(pseudo_family)
        modifiers.update({'pseudo': 'custom', 'pseudo_data': pseudo_data}) """
    # if pseudo_family is not None:
    #     from aiida_quantumespresso.utils.pseudopotential import get_pseudos_from_structure
    #     pseudo_data = get_pseudos_from_structure(structure, pseudo_family)
    #     modifiers.update({'pseudo': 'custom', 'pseudo_data': pseudo_data})

    # Submit the DFT bands workchain
    pwbands_workchain_parameters = {
        'code':
        code,
        'structure':
        structure,
        'protocol':
        orm.Dict(dict={
            'name': protocol,
            'modifiers': modifiers
        }),
        'options':
        orm.Dict(
            dict={
                'resources': {
                    'num_machines': num_machines,
                    'num_mpiprocs_per_machine': num_mpiprocs_per_machine
                },
                'max_wallclock_seconds': 3600 * 5,
                'withmpi': True,
            }),
        'set_2d_mesh':
        orm.Bool(set_2d_mesh)
    }
    if pseudo_family is not None:
        pwbands_workchain_parameters['pseudo_family'] = orm.Str(pseudo_family)
    if daemon:
        dft_workchain = submit(PwBandStructureWorkChain,
                               **pwbands_workchain_parameters)
    else:
        from aiida.engine import run_get_pk
        dft_workchain = run_get_pk(PwBandStructureWorkChain,
                                   **pwbands_workchain_parameters)
    return dft_workchain
Beispiel #16
0
    def get_builder_from_protocol(cls,
                                  code,
                                  structure,
                                  protocol=None,
                                  overrides=None,
                                  **kwargs):
        """Return a builder prepopulated with inputs selected according to the chosen protocol.

        :param code: the ``Code`` instance configured for the ``quantumespresso.pw`` plugin.
        :param structure: the ``StructureData`` instance to use.
        :param protocol: protocol to use, if not specified, the default will be used.
        :param overrides: optional dictionary of inputs to override the defaults of the protocol.
        :param kwargs: additional keyword arguments that will be passed to the ``get_builder_from_protocol`` of all the
            sub processes that are called by this workchain.
        :return: a process builder instance with all inputs defined ready for launch.
        """
        args = (code, structure, protocol)
        inputs = cls.get_protocol_inputs(protocol, overrides)
        builder = cls.get_builder()

        base = PwBaseWorkChain.get_builder_from_protocol(*args,
                                                         overrides=inputs.get(
                                                             'base', None),
                                                         **kwargs)
        base_final_scf = PwBaseWorkChain.get_builder_from_protocol(
            *args, overrides=inputs.get('base_final_scf', None), **kwargs)

        base['pw'].pop('structure', None)
        base.pop('clean_workdir', None)
        base_final_scf['pw'].pop('structure', None)
        base_final_scf.pop('clean_workdir', None)

        builder.base = base
        builder.base_final_scf = base_final_scf
        builder.structure = structure
        builder.clean_workdir = orm.Bool(inputs['clean_workdir'])
        builder.max_meta_convergence_iterations = orm.Int(
            inputs['max_meta_convergence_iterations'])
        builder.meta_convergence = orm.Bool(inputs['meta_convergence'])
        builder.relax_type = orm.Str(inputs['relax_type'])
        builder.volume_convergence = orm.Float(inputs['volume_convergence'])

        return builder
    def get_inputs_and_processclass_from_extras(self,
                                                extras_values: ty.Tuple[str]):
        """Construct the inputs and get the process class from the values of the uniquely identifying extras."""
        structure = self._get_structure_from_extras(extras_values)
        pseudos = self._pseudo_family.get_pseudos(structure=structure)
        ecutwfc, ecutrho = self._pseudo_family.get_recommended_cutoffs(
            structure=structure)
        metadata = {
            'options': {
                'resources': {
                    'num_machines': 1,
                    'num_mpiprocs_per_machine': 1
                },
                'max_wallclock_seconds': 2 * 60,
                'withmpi': True
            }
        }

        inputs = {
            'clean_workdir': orm.Bool(True),
            'kpoints_distance': orm.Float(0.25),
            'pw': {
                'structure':
                structure,
                'metadata':
                metadata,
                'code':
                self._code,
                'pseudos':
                pseudos,
                'parameters':
                orm.Dict(
                    dict={
                        'CONTROL': {
                            'calculation': 'scf',
                            'verbosity': 'low'
                        },
                        'SYSTEM': {
                            'ecutwfc': ecutwfc,
                            'ecutrho': ecutrho,
                            'nosym': False,
                            'occupations': 'smearing',
                            'smearing': 'gaussian',
                            'degauss': 0.5 / CONSTANTS.ry_to_ev
                        },
                        'ELECTRONS': {
                            'conv_thr': 1e-8,
                            'mixing_beta': 4e-1,
                            'electron_maxstep': 80,
                        }
                    })
            }
        }

        return inputs, self._process_class
Beispiel #18
0
 def define(cls, spec):
     super().define(spec)
     spec.input('add_outputs',
                valid_type=orm.Bool,
                default=lambda: orm.Bool(False))
     spec.output_namespace('integer.namespace',
                           valid_type=orm.Int,
                           dynamic=True)
     spec.output('required_string',
                 valid_type=orm.Str,
                 required=True)
Beispiel #19
0
def crop_kpoints(structure, kpt_data, centers, radius):
    """Crop a given set of k-points `kpt_data` that are within a spherical radius `r` from a set of centers `centers`.

    :param structure: aiida.orm.StructureData used to get the cell of the material.
    :param kpt_data: aiida.orm.KpointsData to crop.
    :param centers: aiida.orm.ArrayData containing an array named `centers`.
                    Each element of `centers` is used as the center of a spherical cropping.
    :param radius: radius of the sphere cropping.

    :return: aiida.orm.KpointsData node containing the cropped kpoints
    """
    if not isinstance(structure, orm.StructureData):
        raise InputValidationError(
            'Invalide type {} for parameter `structure`'.format(
                type(structure)))
    if not isinstance(kpt_data, orm.KpointsData):
        raise InputValidationError(
            'Invalide type {} for parameter `kpt_data`'.format(type(kpt_data)))
    if not isinstance(centers, orm.ArrayData):
        raise InputValidationError(
            'Invalide type {} for parameter `centers`'.format(type(centers)))
    if not isinstance(radius, orm.Float):
        raise InputValidationError(
            'Invalide type {} for parameter `radius`'.format(type(radius)))
    centers = centers.get_array('centers')
    if len(centers.shape) != 2 or centers.shape[1] != 3:
        raise InputValidationError(
            'Invalide shape {} for array `centers`. Expected (*,3)'.format(
                centers.shape))

    r = radius.value
    cell = np.array(structure.cell)
    recipr = recipr_base(cell)

    try:
        kpt_cryst = np.array(kpt_data.get_kpoints_mesh(print_list=True))
    except MemoryError:
        return orm.Bool(False)
    kpt_cart = np.dot(kpt_cryst, recipr)

    c_cryst = centers
    c_cart = np.dot(c_cryst, recipr)

    kpt_cart = KDTree(kpt_cart)
    centers = KDTree(c_cart)

    query = kpt_cart.query_ball_tree(centers, r=r)

    where = [n for n, l in enumerate(query) if len(l)]

    new = orm.KpointsData()
    new.set_kpoints(kpt_cryst[where])

    return new
Beispiel #20
0
 def define(cls, spec):
     # yapf: disable
     super().define(spec)
     spec.input('max_iterations', valid_type=orm.Int, default=lambda: orm.Int(3),
                help='Maximum number of iterations the work chain will restart the calculation to finish successfully.')
     spec.input('clean_workdir', valid_type=orm.Bool, default=lambda: orm.Bool(False),
                help='If `True`, work directories of all called calculation will be cleaned at the end of execution.')
     spec.exit_code(101, 'ERROR_MAXIMUM_ITERATIONS_EXCEEDED',
                    message='The maximum number of iterations was exceeded.')
     spec.exit_code(102, 'ERROR_SECOND_CONSECUTIVE_UNHANDLED_FAILURE',
                    message='The calculation failed for an unknown reason, twice in a row.')
Beispiel #21
0
    def run_bands(self):
        """Run the `PwBandsWorkChain` to compute the band structure."""

        def get_common_inputs():
            """Return the dictionary of inputs to be used as the basis for each `PwBaseWorkChain`."""
            protocol, protocol_modifiers = self._get_protocol()
            checked_pseudos = protocol.check_pseudos(
                modifier_name=protocol_modifiers.get('pseudo', None),
                pseudo_data=protocol_modifiers.get('pseudo_data', None)
            )
            known_pseudos = checked_pseudos['found']

            inputs = AttributeDict({
                'pw': {
                    'code': self.inputs.code,
                    'pseudos': get_pseudos_from_dict(self.inputs.structure, known_pseudos),
                    'parameters': self.ctx.parameters,
                    'metadata': {},
                }
            })

            if 'options' in self.inputs:
                inputs.pw.metadata.options = self.inputs.options.get_dict()
            else:
                inputs.pw.metadata.options = get_default_options(with_mpi=True)

            return inputs

        inputs = AttributeDict({
            'structure': self.inputs.structure,
            'relax': {
                'base': get_common_inputs(),
                'relaxation_scheme': orm.Str('vc-relax'),
                'meta_convergence': orm.Bool(self.ctx.protocol['meta_convergence']),
                'volume_convergence': orm.Float(self.ctx.protocol['volume_convergence']),
            },
            'scf': get_common_inputs(),
            'bands': get_common_inputs(),
        })

        inputs.relax.base.kpoints_distance = orm.Float(self.ctx.protocol['kpoints_mesh_density'])
        inputs.scf.kpoints_distance = orm.Float(self.ctx.protocol['kpoints_mesh_density'])
        inputs.bands.kpoints_distance = orm.Float(self.ctx.protocol['kpoints_distance_for_bands'])

        num_bands_factor = self.ctx.protocol.get('num_bands_factor', None)
        if num_bands_factor is not None:
            inputs.nbands_factor = orm.Float(num_bands_factor)

        running = self.submit(PwBandsWorkChain, **inputs)

        self.report(f'launching PwBandsWorkChain<{running.pk}>')

        return ToContext(workchain_bands=running)
Beispiel #22
0
    def define(cls, spec):
        """Define the process specification."""
        # yapf: disable
        super().define(spec)
        spec.expose_inputs(PwBaseWorkChain, namespace='scf',
            exclude=('clean_workdir', 'pw.structure'),
            namespace_options={'help': 'Inputs for the `PwBaseWorkChain` for the SCF calculation.'})
        spec.expose_inputs(PwBaseWorkChain, namespace='nscf',
            exclude=('clean_workdir', 'pw.structure'),
            namespace_options={'help': 'Inputs for the `PwBaseWorkChain` for the NSCF calculation.'})
        spec.expose_inputs(PpCalculation, namespace='pp',
            exclude=('parent_folder', ),
            namespace_options={'help': 'Inputs for the `PpCalculation` for the PP calculation.'})
        spec.input('structure', valid_type=orm.StructureData, help='The inputs structure.')
        spec.input('kpoints', valid_type=orm.KpointsData,
            help='Explicit kpoints to use for the NSCF calculation.')
        spec.input('wavefunction_min', valid_type=orm.Int, required=False,
            help='Smallest index of wavefunctions to compute.')
        spec.input('wavefunction_max', valid_type=orm.Int, required=False,
            help='Largest index of wavefunctions to compute.')
        spec.input('wavefunction_ef_min', valid_type=orm.Int, required=False,
            help='Smallest index, with respoect to the fermi level, of wavefunctions to compute.')
        spec.input('wavefunction_ef_max', valid_type=orm.Int, required=False,
            help='Largest index, with respoect to the fermi level, of wavefunctions to compute.')
        spec.input('clean_workdir', valid_type=orm.Bool, default=lambda: orm.Bool(False),
            help='If `True`, work directories of all called calculation will be cleaned at the end of execution.')
        # spec.inputs.validator = validate_inputs
        spec.outline(
            cls.setup,
            cls.run_scf,
            cls.inspect_scf,
            cls.run_nscf,
            cls.inspect_nscf,
            cls.run_pp,
            cls.inspect_pp,
            cls.results,
        )

        spec.exit_code(402, 'ERROR_SUB_PROCESS_FAILED_SCF',
            message='The scf PwBasexWorkChain sub process failed')
        spec.exit_code(403, 'ERROR_SUB_PROCESS_FAILED_NSCF',
            message='The nscf PwBasexWorkChain sub process failed')
        spec.exit_code(404, 'ERROR_SUB_PROCESS_FAILED_PP',
            message='The PpCalculation sub process failed')

        spec.output('scf_parameters', valid_type=orm.Dict,
            help='The output parameters of the SCF `PwBaseWorkChain`.')
        spec.output('nscf_parameters', valid_type=orm.Dict,
            help='The output parameters of the NSCF `PwBaseWorkChain`.')
        spec.output('pp_parameters', valid_type=orm.Dict,
            help='The output parameters of the `PpCalculation`.')
        spec.output_namespace('wfc_data', valid_type=orm.ArrayData, dynamic=True)
Beispiel #23
0
    def __init__(self,
                 base,
                 base_final_scf,
                 structure,
                 relaxation_scheme,
                 relax_type,
                 meta_convergence=True,
                 max_meta_convergence_iterations=5,
                 volume_convergence=0.01,
                 clean_workdir=True):

        self.base = base
        self.base_final_scf = base_final_scf
        self.structure = structure
        # self.final_scf = orm.Bool(final_scf)
        self.relaxation_scheme = orm.Str(relaxation_scheme)
        self.relax_type = orm.Str(relax_type)
        self.meta_convergence = orm.Bool(meta_convergence)
        self.max_meta_convergence_iterations = orm.Int(
            max_meta_convergence_iterations)
        self.volume_convergence = orm.Float(volume_convergence)
        self.clean_workdir = orm.Bool(clean_workdir)
Beispiel #24
0
    def get_builder_from_protocol(cls,
                                  code,
                                  structure,
                                  protocol=None,
                                  overrides=None,
                                  **kwargs):
        """Return a builder prepopulated with inputs selected according to the chosen protocol.

        :param code: the ``Code`` instance configured for the ``quantumespresso.pw`` plugin.
        :param structure: the ``StructureData`` instance to use.
        :param protocol: protocol to use, if not specified, the default will be used.
        :param overrides: optional dictionary of inputs to override the defaults of the protocol.
        :param kwargs: additional keyword arguments that will be passed to the ``get_builder_from_protocol`` of all the
            sub processes that are called by this workchain.
        :return: a process builder instance with all inputs defined ready for launch.
        """
        args = (code, structure, protocol)
        inputs = cls.get_protocol_inputs(protocol, overrides)
        builder = cls.get_builder()

        relax = PwRelaxWorkChain.get_builder_from_protocol(
            *args, overrides=inputs.get('relax', None), **kwargs)
        scf = PwBaseWorkChain.get_builder_from_protocol(*args,
                                                        overrides=inputs.get(
                                                            'scf', None),
                                                        **kwargs)
        bands = PwBaseWorkChain.get_builder_from_protocol(*args,
                                                          overrides=inputs.get(
                                                              'bands', None),
                                                          **kwargs)

        relax.pop('structure', None)
        relax.pop('clean_workdir', None)
        relax.pop('base_final_scf', None)
        scf['pw'].pop('structure', None)
        scf.pop('clean_workdir', None)
        bands['pw'].pop('structure', None)
        bands.pop('clean_workdir', None)
        bands.pop('kpoints_distance', None)
        bands.pop('kpoints_force_parity', None)

        builder.structure = structure
        builder.relax = relax
        builder.scf = scf
        builder.bands = bands
        builder.clean_workdir = orm.Bool(inputs['clean_workdir'])
        builder.nbands_factor = orm.Float(inputs['nbands_factor'])
        builder.bands_kpoints_distance = orm.Float(
            inputs['bands_kpoints_distance'])

        return builder
Beispiel #25
0
 def define(cls, spec):
     """Define the process specification"""
     # yapf: disable
     super(DpEvaluateBaseWorkChain, cls).define(spec)
     spec.input('code', valid_type=orm.Code,
         help='The `pw.x` code to use for the `PwCalculations`.')
     spec.input('structure', valid_type=orm.StructureData,
         help='The input structure.')
     spec.input('options', valid_type=orm.Dict, required=False,
         help='Optional `options` to use for the `PwCalculations`.')
     spec.input('protocol', valid_type=orm.Dict,
         default=orm.Dict(dict={'name': 'theos-ht-1.0', 'modifiers': {'parameters': 'default', 'pseudo': 'SSSP-efficiency-1.1'}}),
         help='The protocol to use for the workchain.', validator=validate_protocol)
     spec.input('do_relax', valid_type=orm.Bool, default=orm.Bool(True),
         help='If `True`, running the relax and then scf')
     spec.input('clean_workdir', valid_type=orm.Bool, default=orm.Bool(True),
         help='If `True`, work directories of all called calculation will be cleaned at the end of execution.')
     spec.outline(
         cls.setup_protocol,
         cls.setup_parameters,
         if_(cls.should_do_relax)(
             cls.run_relax,
             cls.inspect_relax,
         ),
         cls.run_scf,
         cls.inspect_scf,
         cls.results,
     )
     spec.exit_code(201, 'ERROR_INVALID_INPUT_UNRECOGNIZED_KIND',
         message='Input `StructureData` contains an unsupported kind.')
     spec.exit_code(401, 'ERROR_SUB_PROCESS_FAILED_RELAX',
         message='the PwRelaxWorkChain sub process failed')
     spec.exit_code(402, 'ERROR_SUB_PROCESS_FAILED_SCF',
         message='the scf PwBasexWorkChain sub process failed')
     spec.output('primitive_structure', valid_type=orm.StructureData,
         help='The normalized and primitivized structure for which the scf step are computed.')
     spec.output('scf_parameters', valid_type=orm.Dict,
         help='The output parameters of the SCF `PwBaseWorkChain`.')
def generate_inputs_relax(protocol: Dict,
                          code: orm.Code,
                          structure: StructureData,
                          sssp_family: SsspFamily,
                          override: Dict[str, Any] = None) -> Dict[str, Any]:
    """Generate the inputs for the `PwRelaxWorkChain` for a given code, structure and pseudo potential family.

    :param protocol: the dictionary with protocol inputs.
    :param code: the code to use.
    :param structure: the input structure.
    :param sssp_family: the pseudo potential family.
    :param override: a dictionary to override specific inputs.
    :return: the fully defined input dictionary.
    """
    protocol['base'] = generate_inputs_base(protocol['base'], code, structure,
                                            sssp_family,
                                            override.get('base', {}))
    merged = recursive_merge(protocol, override)

    # Remove inputs that should not be passed top-level
    merged['base']['pw'].pop('structure', None)

    dictionary = {
        'base':
        merged['base'],
        'structure':
        structure,
        'final_scf':
        orm.Bool(merged['final_scf']),
        'max_meta_convergence_iterations':
        orm.Int(merged['max_meta_convergence_iterations']),
        'meta_convergence':
        orm.Bool(merged['meta_convergence']),
        'volume_convergence':
        orm.Float(merged['volume_convergence']),
    }

    return dictionary
Beispiel #27
0
    def test_exit_codes_invalidate_cache(self):
        """
        Test that returning an exit code with 'invalidates_cache' set to ``True``
        indeed means that the ProcessNode will not be cached from.
        """
        # Sanity check that caching works when the exit code is not returned.
        with enable_caching():
            _, node1 = run_get_node(test_processes.InvalidateCaching,
                                    return_exit_code=orm.Bool(False))
            _, node2 = run_get_node(test_processes.InvalidateCaching,
                                    return_exit_code=orm.Bool(False))
            self.assertEqual(node1.get_extra('_aiida_hash'),
                             node2.get_extra('_aiida_hash'))
            self.assertIn('_aiida_cached_from', node2.extras)

        with enable_caching():
            _, node3 = run_get_node(test_processes.InvalidateCaching,
                                    return_exit_code=orm.Bool(True))
            _, node4 = run_get_node(test_processes.InvalidateCaching,
                                    return_exit_code=orm.Bool(True))
            self.assertEqual(node3.get_extra('_aiida_hash'),
                             node4.get_extra('_aiida_hash'))
            self.assertNotIn('_aiida_cached_from', node4.extras)
 def define(cls, spec):
     """Define the process specification."""
     # yapf: disable
     super().define(spec)
     spec.input('max_iterations', valid_type=orm.Int, default=lambda: orm.Int(5),
         help='Maximum number of iterations the work chain will restart the calculation to finish successfully.')
     spec.input('clean_workdir', valid_type=orm.Bool, default=lambda: orm.Bool(False),
         help='If `True`, work directories of all called calculation will be cleaned at the end of execution.')
     spec.input_namespace('fixers', valid_type=tuple, required=False,
         help="Fixers you want to apply to the outputs of every calculation.", dynamic=True)
     spec.exit_code(101, 'ERROR_MAXIMUM_ITERATIONS_EXCEEDED',
         message='The maximum number of iterations was exceeded.')
     spec.exit_code(102, 'ERROR_SECOND_CONSECUTIVE_UNHANDLED_FAILURE',
         message='The calculation failed for an unknown reason, twice in a row.')
Beispiel #29
0
    def run_relax(self):
        """Run the PwRelaxWorkChain to run a relax PwCalculation."""
        inputs = AttributeDict({
            'structure': self.inputs.structure,
            'base': self._get_common_inputs(),
            'relaxation_scheme': orm.Str('vc-relax'),
            'meta_convergence': orm.Bool(self.ctx.protocol['meta_convergence']),
            'volume_convergence': orm.Float(self.ctx.protocol['volume_convergence']),
        })
        inputs.base.kpoints_distance = orm.Float(self.ctx.protocol['kpoints_mesh_density'])

        running = self.submit(PwRelaxWorkChain, **inputs)

        self.report('launching PwRelaxWorkChain<{}>'.format(running.pk))

        return ToContext(workchain_relax=running)
Beispiel #30
0
def test_sequential(aiida_profile, generate_workchain_seq_converger,
                    generate_wc_job_node, fixture_localhost):
    """
    We test here the SiestaSequentialConverger, just the main two methods
    that distinguish it from the BaseIterator, meaning the `initialize` and the 
    `_analyze_process`
    """

    from aiida.common.extendeddicts import AttributeDict

    process = generate_workchain_seq_converger()
    process.initialize()

    assert process.ctx.iteration_keys == ('iterate_over', )

    convergerwc = generate_wc_job_node("siesta.converger", fixture_localhost)
    convergerwc.set_process_state(ProcessState.FINISHED)
    convergerwc.set_exit_status(ExitCode(0).status)
    out_par = orm.Dict(dict={"test_par_1": 1111, "test_par_2": "eV"})
    out_par.store()
    out_conv = orm.Bool(True)
    out_conv.store()
    val_conv = orm.Float(1)
    val_conv.store()
    out_par.add_incoming(convergerwc,
                         link_type=LinkType.RETURN,
                         link_label='converged_parameters')
    out_conv.add_incoming(convergerwc,
                          link_type=LinkType.RETURN,
                          link_label='converged')
    val_conv.add_incoming(convergerwc,
                          link_type=LinkType.RETURN,
                          link_label='converged_target_value')

    process.ctx.last_inputs = AttributeDict({})

    process._analyze_process(convergerwc)

    assert process.ctx.already_converged == {
        "test_par_1": 1111,
        "test_par_2": "eV"
    }
    assert process.ctx.last_target_value == val_conv
    assert "parameters" in process.ctx.last_inputs
    assert "test_par_1" in process.ctx.last_inputs.parameters.attributes
    assert process.ctx.last_inputs.parameters.attributes["test_par_2"] == "eV"