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