Exemple #1
0
def test_create_builder(db_test_app, get_structure):
    """Test preparation of inputs."""
    db_test_app.get_or_create_code("crystal17.main")

    inparams = {"scf.k_points": (8, 8)}

    instruct = get_structure("MgO")
    with open_resource_text("basis_sets", "sto3g", "sto3g_Mg.basis") as handle:
        mg_basis, _ = BasisSetData.get_or_create(handle)
    with open_resource_text("basis_sets", "sto3g", "sto3g_O.basis") as handle:
        o_basis, _ = BasisSetData.get_or_create(handle)

    sym_calc = run_get_node(
        WorkflowFactory("crystal17.sym3d"),
        structure=instruct,
        settings=DataFactory("dict")(dict={
            "symprec": 0.01,
            "compute_primitive": True
        }),
    ).node
    instruct = sym_calc.get_outgoing().get_node_by_label("structure")
    symmetry = sym_calc.get_outgoing().get_node_by_label("symmetry")

    calc_cls = CalculationFactory("crystal17.main")
    builder = calc_cls.create_builder(
        inparams,
        instruct,
        {
            "O": o_basis,
            "Mg": mg_basis
        },
        symmetry=symmetry,
        unflatten=True,
    )

    assert isinstance(builder.structure, orm.StructureData)
    builder.parameters
def populate_builder(remote_data, code=None, metadata=None):
    """create ``crystal17.main`` input nodes from an existing run

    NB: none of the nodes are stored, also
    existing basis will be retrieved if availiable

    Parameters
    ----------
    folder: aiida.common.folders.Folder or str
        folder containing the input and output files
    remote_data: aiida.orm.RemoteData
        containing the input and output files required for parsing
    code: str or aiida.orm.nodes.data.code.Code or None
    metadata: dict or None
        calculation metadata

    Returns
    -------
    aiida.engine.processes.ProcessBuilder

    """
    calc_cls = CalculationFactory("crystal17.main")
    basis_cls = DataFactory("crystal17.basisset")
    struct_cls = DataFactory("structure")
    symmetry_cls = DataFactory("crystal17.symmetry")
    kind_cls = DataFactory("crystal17.kinds")

    # get files
    in_file_name = calc_cls.spec_options.get("input_file_name").default
    out_file_name = calc_cls.spec_options.get("output_main_file_name").default
    if metadata and "options" in metadata:
        in_file_name = metadata["options"].get("input_file_name", in_file_name)
        out_file_name = metadata["options"].get("output_main_file_name",
                                                out_file_name)

    remote_files = remote_data.listdir()

    if in_file_name not in remote_files:
        raise IOError(
            "The input file '{}' is not contained in the remote_data folder. "
            "If it has a different name, change "
            "metadata['options]['input_file_name']".format(in_file_name))
    if out_file_name not in remote_files:
        raise IOError(
            "The output file '{}' is not contained in the remote_data folder. "
            "If it has a different name, change "
            "metadata['options]['output_main_file_name']".format(
                out_file_name))

    with SandboxFolder() as folder:
        remote_data.getfile(in_file_name,
                            os.path.join(folder.abspath, in_file_name))

        with folder.open(in_file_name, mode="r") as handle:
            param_dict, basis_sets, atom_props = extract_data(handle.read())

        remote_data.getfile(out_file_name,
                            os.path.join(folder.abspath, out_file_name))

        with folder.open(out_file_name, mode="r") as handle:
            try:
                data = crystal_stdout.read_crystal_stdout(handle.read())
            except IOError as err:
                raise OutputParsingError(
                    "Error in CRYSTAL 17 run output: {}".format(err))

    # we retrieve the initial primitive geometry and symmetry
    atoms = _create_atoms(data, "initial_geometry")

    # convert fragment (i.e. unfixed) to fixed
    if "fragment" in atom_props:
        frag = atom_props.pop("fragment")
        atom_props["fixed"] = [
            i + 1 for i in range(atoms.get_number_of_atoms())
            if i + 1 not in frag
        ]

    atoms.set_tags(_create_tags(atom_props, atoms))

    structure = struct_cls(ase=atoms)

    if atom_props:
        kind_names = structure.get_kind_names()
        kinds_dict = {"kind_names": kind_names}
        for key, atom_indexes in atom_props.items():
            kv_map = {
                kn: i + 1 in atom_indexes
                for i, kn in enumerate(structure.get_site_kindnames())
            }
            kinds_dict[key] = [kv_map[kn] for kn in kind_names]
        kinds = kind_cls(data=kinds_dict)
    else:
        kinds = None

    symmetry = symmetry_cls(
        data={
            "operations": data["initial_geometry"]["primitive_symmops"],
            "basis": "fractional",
            "hall_number": None,
        })

    bases = {}
    for bset in basis_sets:

        bfile = tempfile.NamedTemporaryFile(delete=False)
        try:
            with open(bfile.name, "w") as f:
                f.write(bset)
            bdata, _ = basis_cls.get_or_create(bfile.name,
                                               use_first=False,
                                               store_basis=False)
            # TODO report if bases created or retrieved
        finally:
            os.remove(bfile.name)

        bases[bdata.element] = bdata

    builder = calc_cls.create_builder(
        param_dict,
        structure,
        bases,
        symmetry=symmetry,
        kinds=kinds,
        code=code,
        metadata=metadata,
    )

    return builder