def Pd(tmpdir): from matdb.utility import relpath, copyonce from matdb.database import Controller from os import mkdir, symlink, remove, path target = relpath("./tests/Pd/matdb.yml") dbdir = str(tmpdir.join("pd_db")) mkdir(dbdir) copyonce(target, path.join(dbdir, "matdb.yml")) target = path.join(dbdir, "matdb") #We need to copy the POSCAR over from the testing directory to the temporary #one. from shutil import copy POSCAR = relpath("./tests/Pd/POSCAR") mkdir(path.join(dbdir, "seed")) copy(POSCAR, path.join(dbdir, "seed", "Pd")) # the source file `matdb.yml` linked to might be gone, that left `matdb.yml` not an valid "file" # we need to get rid if it anyway try: remove("matdb.yml") except: pass symlink("{}.yml".format(target), "matdb.yml") result = Controller("matdb", dbdir) remove("matdb.yml") result = Controller(target, dbdir) return result
def _mimic_vasp(folder, xroot, prefix="W.1"): """Copies a `vasprun.xml` and `OUTCAR ` output files from the given folder into the execution directory to mimic what VASP would have done. Args: folder (str): path to the folder where the model files are stored. xroot (str): path to the root folder where the config steps are stored. """ from matdb.utility import chdir from glob import glob from os import path from matdb.utility import symlink files = ["vasprun.xml", "OUTCAR"] with chdir(folder): for vaspfile in files: pattern = vaspfile + "__*" for dft in glob(pattern): name, config = dft.split("__") xpath = path.join(xroot, path.join(*config.split("_")), prefix) #We want to make some testing assertions to ensure that the #stubs ran correctly. #Bypass checking the DynMatrix subfolder if "DynMatrix" in xpath: continue assert path.isfile(path.join(xpath, "CONTCAR")) assert path.isfile(path.join(xpath, ".matdb.module")) target = path.join(xpath, name) symlink(target, path.join(folder, dft))
def __init__(self, name=None, root=None, controller=None, splits=None, folder=None, pattern=None, config_type=None, energy="dft_energy", force="dft_force", virial="dft_virial", limit=None): self.name = name self.root = path.join(root, self.name) if not path.isdir(self.root): from os import mkdir mkdir(self.root) self.controller = controller self.splits = {} if splits is None else splits self.folder = folder if self.controller is None: self.ran_seed = 0 else: self.ran_seed = self.controller.ran_seed self._dbfile = path.join(self.root, "legacy-{}.h5".format(limit)) """str: path to the combined legacy database, with limits included. """ self._dbfull = path.join(self.root, "legacy.h5") """str: path to the combined legacy database, *without* limits. """ self.dbfiles = [] self.config_type = config_type from matdb.database.utility import dbconfig config = dbconfig(self._dbfull) if path.isfile(self._dbfile) and len(config) > 0: self.dbfiles = [db[0] for db in config["sources"]] self.config_type = config["config_type"] self.folder = folder else: from matdb.utility import dbcat if not path.isfile(self._dbfull): self._create_dbfull(folder, pattern, energy, force, virial, config_type) if limit is not None: msg.std("Slicing limit subset of full {} db.".format(self.name)) full = AtomsList(self._dbfull) N = np.arange(len(full)) np.random.shuffle(N) ids = N[0:limit] part = full[ids] part.write(self._dbfile) dbcat([self._dbfull], self._dbfile, docat=False, limit=limit, ids=ids) else: from matdb.utility import symlink symlink(self._dbfile, self._dbfull) #The rest of matdb expects each database to have an atoms object that is #representative. Just take the first config in the combined database. self.atoms = Atoms(self._dbfile)
def test_extract(tmpdir): """Tests the extract method and cleanup method. """ target = str(tmpdir.join("Qe")) atm = Atoms("AlPd", positions=[[0, 0, 0], [0.5, 0.5, 0.5]]) kwargs = { "potcars": { "directory": path.join(reporoot, "tests/qe"), "potentials": { "Al": "Al.pbe-n-kjpaw_psl.1.0.0.UPF", "Pd": "Pd_ONCV_PBE-1.0.upf" }, "versions": { "Al": ["2.0.1", ".5.1"], "Pd": ["2.0.1", "2.1.1"] } }, "kpoints": { "method": "kspacing", "spacing": 0.1, "offset": 1 }, "input_data": { "control": { "calculation": "relax", "prefix": "test" } } } calc = Qe(atm, target, '.', 0, **kwargs) calc.create() symlink(path.join(calc.folder, "test.xml"), relpath("tests/qe/complete.xml")) mkdir(path.join(calc.folder, "test.save")) calc.extract(target) assert hasattr(calc.atoms, "qe_force") assert hasattr(calc.atoms, "qe_stress") assert hasattr(calc.atoms, "qe_energy") assert calc.atoms.qe_energy is not None assert calc.atoms.qe_stress is not None assert calc.atoms.qe_force is not None touch(path.join(calc.folder, "test.save", "paw.txt")) calc.cleanup(target, clean_level="light") assert not path.isfile(path.join(calc.folder, "test.save", "paw.txt")) touch(path.join(calc.folder, "test.save", "charge-density.dat")) calc.cleanup(target) assert not path.isfile( path.join(calc.folder, "test.save", "charge-density.dat")) calc.cleanup(target, clean_level="aggressive") assert not path.isfile(path.join(calc.folder, "test.xml")) assert not path.isdir(path.join(calc.folder, "test.save"))
def test_can_extract(tmpdir): """Tests the can_extract method. We'll also test is_executing at the same time. """ target = str(tmpdir.join("Qe")) atm = Atoms("AlPd", positions=[[0, 0, 0], [0.5, 0.5, 0.5]]) kwargs = { "potcars": { "directory": path.join(reporoot, "tests/qe"), "potentials": { "Al": "Al.pbe-n-kjpaw_psl.1.0.0.UPF", "Pd": "Pd_ONCV_PBE-1.0.upf" }, "versions": { "Al": ["2.0.1", ".5.1"], "Pd": ["2.0.1", "2.1.1"] } }, "kpoints": { "method": "kspacing", "spacing": 0.1, "offset": 1 }, "input_data": { "control": { "calculation": "relax", "prefix": "test" } } } calc = Qe(atm, target, '.', 0, **kwargs) calc.create() assert not calc.can_extract("def") assert not calc.can_extract(target) assert not calc.is_executing(target) touch(path.join(calc.folder, "CRASH")) assert not calc.can_extract(target) remove(path.join(calc.folder, "CRASH")) symlink(path.join(calc.folder, "pwscf.xml"), relpath("tests/qe/complete.xml")) mkdir(path.join(calc.folder, "pwscf.save")) assert calc.can_extract(target) remove(path.join(calc.folder, "test.xml")) mkdir(path.join(calc.folder, "pwscf.save")) symlink(path.join(calc.folder, "pwscf.xml"), relpath("tests/qe/fail.xml")) assert not calc.can_extract(target)
def test_read(tmpdir): """Tests the read function of the QE calculator. """ target = str(tmpdir.join("Qe")) atm = Atoms("AlPd", positions=[[0, 0, 0], [0.5, 0.5, 0.5]]) kwargs = { "potcars": { "directory": path.join(reporoot, "tests/qe"), "potentials": { "Al": "Al.pbe-n-kjpaw_psl.1.0.0.UPF", "Pd": "Pd_ONCV_PBE-1.0.upf" }, "versions": { "Al": ["2.0.1", ".5.1"], "Pd": ["2.0.1", "2.1.1"] } }, "kpoints": { "method": "kspacing", "spacing": 0.1, "offset": 1 }, "input_data": { "control": { "calculation": "relax", "prefix": "test" } } } calc = Qe(atm, target, '.', 0, **kwargs) symlink(path.join(calc.folder, "test.xml"), relpath("tests/qe/complete.xml")) output = calc._read(path.join(calc.folder, "test.xml")) assert output["convergence"] == 4.068079462655824e-7 assert np.allclose(output["atoms"], [0, 0, 0]) assert np.allclose(output["cell"], [[-3.75, 0, 3.75], [0, 3.75, 3.75], [-3.75, 3.75, 0]]) assert output["etot"] == -1.975055613913407e1 assert np.allclose(output["forces"], [0, 0, 0]) assert np.allclose(output["stress"], [[ 1.578434139006113e-4, -1.219727444046192e-19, -9.486769009248164e-20 ], [ -1.490777987167569e-19, 1.578434139006113e-4, 9.486769009248164e-20 ], [-6.776263578034403e-20, 1.219727444046192e-19, 1.578434139006113e-4]]) assert calc.version == '6.2 (svn rev. 14038)'
def test_extract(tmpdir): """Tests the extract method and cleanup method. """ from matdb.utility import symlink, relpath, touch from matdb.utility import _set_config_paths _set_config_paths("AgPd_Enumerated", str(tmpdir)) target = str(tmpdir.join("Vasp")) globals_setup(target) atm = Atoms("Si", positions=[[0, 0, 0]], cell=[1, 1, 1]) kwargs = { "ibrion": 5, "nsw": 1, "kpoints": { "method": "mueller", "mindistance": 50 }, "potcars": { "directory": "./tests/vasp", "xc": "pbe", "versions": { "Si": '05Jan2001' } } } calc = Vasp(atm, target, str(tmpdir), 0, **kwargs) calc.write_input(atm, target) symlink(path.join(calc.folder, "OUTCAR"), relpath("tests/files/VASP/OUTCAR_complete")) symlink(path.join(calc.folder, "CONTCAR"), path.join(calc.folder, "POSCAR")) calc.extract(target) assert hasattr(calc.atoms, calc.force_name) assert hasattr(calc.atoms, calc.virial_name) assert hasattr(calc.atoms, calc.energy_name) assert calc.atoms.vasp_energy is not None assert calc.atoms.vasp_virial is not None assert calc.atoms.vasp_force is not None touch(path.join(calc.folder, "CHG")) calc.cleanup(target, clean_level="light") assert not path.isfile(path.join(calc.folder, "CHG")) touch(path.join(calc.folder, "CHGCAR")) calc.cleanup(target) assert not path.isfile(path.join(calc.folder, "CHGCAR")) touch(path.join(calc.folder, "vasprun.xml")) calc.cleanup(target, clean_level="aggressive") assert not path.isfile(path.join(calc.folder, "OUTCAR")) assert not path.isfile(path.join(calc.folder, "vasprun.xml")) symlink(path.join(calc.folder, "CONTCAR"), path.join(calc.folder, "POSCAR")) symlink(path.join(calc.folder, "OUTCAR"), relpath("tests/files/VASP/OUTCAR_incomplete")) assert not calc.extract(target)
def Pd_db(tmpdir): from matdb.utility import relpath, reporoot from matdb.database import Controller from os import mkdir target = relpath("./tests/Pd/matdb") dbdir = str(tmpdir.join("pd_db")) mkdir(dbdir) #We need to copy the POSCAR over from the testing directory to the temporary #one. from shutil import copy POSCAR = relpath("./tests/Pd/POSCAR") copy(POSCAR, dbdir) Pd = Controller(target, dbdir) Pd.setup() #First, we need to copy the FORCE_SETS and total_dos.dat files so that we #don't have to recompile those (they are tested elsewhere). from matdb.utility import symlink troot = path.join(reporoot, "tests", "data", "Pd", "dynmatrix") files = ["FORCE_SETS", "total_dos.dat", "mesh.yaml"] for seq in Pd.find("Pd.phonon-*.dynmatrix"): for filename in files: target = path.join(seq.root, "phonopy", filename) source = path.join(troot, "{0}__{1}".format(filename, seq.parent.name)) symlink(target, source) Pd.cleanup() Pd.setup() files = ["OUTCAR", "output.xyz"] seq = Pd["Pd.modulate.modulations"] troot = path.join(reporoot, "tests", "data", "Pd", "modulations") for i in range(1, 6): key = "M.{0:d}".format(i) for filename in files: target = path.join(seq.root, key, filename) source = path.join(troot, "{0}__{1}".format(filename, key)) symlink(target, source) return Pd
def test_symlink(tmpdir): """Tests symbolic linking of a file. """ from matdb.utility import reporoot, symlink, execute target = path.join(reporoot, "__init__.py") source = str(tmpdir.join("symlink_init")) symlink(source, target) from os import readlink result = readlink(source) assert result == target symlink(source, target) result = readlink(source) assert result == target dirsource = str(tmpdir.join("dummy-dir")) from os import mkdir mkdir(dirsource) assert symlink(dirsource, reporoot) is None
def test_extract_force_sets(tmpdir): """Tests the extract_force_sets and extract_farce_constants functions. """ from matdb.calculators.vasp import extract_force_sets, extract_force_constants from matdb.utility import relpath, symlink phonon_dir = str(tmpdir.join("phonopy")) mkdir(phonon_dir) configs = {"1": str(tmpdir)} res = extract_force_sets(configs, phonon_dir) assert compare_nested_dicts(res, {"error": ""}) symlink(path.join(str(tmpdir), "vasprun.xml"), relpath("tests/files/VASP/vasprun.xml_complete")) res = extract_force_sets(configs, phonon_dir) assert res["error"] == [] res = extract_force_constants(configs, phonon_dir) assert res["error"] == []
def test_can_extract(tmpdir): """Tests the can_extract method. We'll also test is_executing at the same time. """ from matdb.utility import symlink, relpath from matdb.utility import _set_config_paths _set_config_paths("AgPd_Enumerated", str(tmpdir)) target = str(tmpdir.join("Vasp")) globals_setup(target) atm = Atoms("Si", positions=[[0, 0, 0]]) kwargs = { "kpoints": { "method": "mueller", "mindistance": 50 }, "potcars": { "directory": "./tests/vasp", "xc": "pbe", "versions": { "Si": '05Jan2001' } } } calc = Vasp(atm, target, str(tmpdir), 0, **kwargs) assert not calc.can_extract("def") assert not calc.can_extract(target) symlink(path.join(calc.folder, "OUTCAR"), relpath("tests/files/VASP/OUTCAR_incomplete")) assert not calc.can_extract(target) assert calc.is_executing(target) symlink(path.join(calc.folder, "OUTCAR"), relpath("tests/files/VASP/OUTCAR_complete")) assert calc.can_extract(target) assert not calc.is_executing(target)
def test_recovery(Pd): """Tests the rerun on unfinshed jobs """ from os import path from matdb.utility import symlink, chdir from glob import glob Pd.setup() Pd.execute(env_vars={"SLURM_ARRAY_TASK_ID": "1"}) files = ["vasprun.xml", "OUTCAR"] folder = path.join(reporoot, "tests", "data", "Pd", "manual_recover") with chdir(folder): for vaspfile in files: pattern = vaspfile + "__*" for dft in glob(pattern): name, config = dft.split("__") xpath = path.join(Pd.root, path.join(*config.split("_")), "S1.1") target = path.join(xpath, name) symlink(target, path.join(folder, dft)) Pd.extract() Pd.recover(True) assert path.isfile( path.join(Pd.root, "Manual", "phonon.manual", "Pd", "recovery.sh")) assert path.isfile( path.join(Pd.root, "Manual", "phonon.manual", "Pd", "failures")) folder = path.join(reporoot, "tests", "data", "Pd", "manual") _mimic_vasp(folder, Pd.root, "S1.1") Pd.recover(True) assert not path.isfile( path.join(Pd.root, "Manual", "phonon.manual", "Pd", "recovery.sh")) assert not path.isfile( path.join(Pd.root, "Manual", "phonon.manual", "Pd", "failures"))
def test_to_dict(tmpdir): """Tests the calculator to_dict method. """ from matdb.utility import _set_config_paths _set_config_paths("AgPd_Enumerated", str(tmpdir)) target = str(tmpdir.join("Qe")) globals_setup(target) atm = Atoms("AlPd", positions=[[0, 0, 0], [0.5, 0.5, 0.5]]) kwargs = { "potcars": { "directory": "./tests/qe", "potentials": { "Al": "Al.pbe-n-kjpaw_psl.1.0.0.UPF", "Pd": "Pd_ONCV_PBE-1.0.upf" }, "versions": { "Al": ["2.0.1", ".5.1"], "Pd": ["2.0.1", "2.1.1"] } }, "kpoints": { "method": "kspacing", "spacing": 0.1, "offset": 1 }, "input_data": { "control": { "calculation": "relax", "prefix": "test" } } } calc = Qe(atm, '$control$/Qe', '$control$', 0, **kwargs) symlink(path.join(calc.folder, "test.xml"), relpath("tests/qe/complete.xml")) calc.extract(target) calc_dict = calc.to_dict() kwargs = { "potcars": { "directory": "156def0ed29f1a908d5a7b4eae006c672e7b0ff1", "potentials": { "Al": "Al.pbe-n-kjpaw_psl.1.0.0.UPF", "Pd": "Pd_ONCV_PBE-1.0.upf" }, "versions": { "Al": ["2.0.1", ".5.1"], "Pd": ["2.0.1", "2.1.1"] } }, "kpoints": { "method": "kspacing", "spacing": 0.1, "offset": 1 }, "input_data": { "control": { "calculation": "relax", "prefix": "test" }, 'tprnfor': True, 'tstress': True } } out = { "folder": '$control$/Qe', "ran_seed": 0, "contr_dir": '$control$', "kwargs": kwargs, "args": (), "version": "6.2 (svn rev. 14038)" } assert compare_nested_dicts(calc_dict, out)
#!/usr/bin/python """This is a stub for vasp to enable unit testing. It creates empty files that mimic the ones VASP actually creates when it executes. We don't include the OUTCAR because we want to be able to simulate VASP failing as well, if the OUTCAR is needed then we simply copy an existing OUTCAR from `tests/data`. We're copying the POSCAR to the CONTCAR so that the cleanup methods can grab the 'relaxed' atomic positions. """ from matdb.utility import touch, symlink from os import path files = ["CONTCAR", "WAVECAR", "CHGCAR"] for fname in files: touch(fname) if path.isfile("POSCAR"): symlink("CONTCAR", "POSCAR") print("vasp.4.6.35 3Apr08 complex \n")
def test_write_potcar(tmpdir): """Tests the writing of the POTCAR file. """ from matdb.utility import _set_config_paths from hashlib import sha1 _set_config_paths("AgPd_Enumerated", str(tmpdir)) target = str(tmpdir.join("Vasp")) globals_setup(target) atm = Atoms("Si", positions=[[0, 0, 0]], cell=[[1, 0, 0], [0, 1, 0], [0, 0, 1]]) kwargs = { "kpoints": { "rmin": 50 }, "potcars": { "directory": "./tests/vasp", "xc": "pbe", "versions": { "Si": '05Jan2001' } } } calc = Vasp(atm, target, str(tmpdir), 0, **kwargs) calc._write_potcar() this_potcar = str( sha1("{0}{1}".format("Si", "05Jan2001").encode()).hexdigest()) assert path.isfile(path.join(calc.contr_dir, "POTCARS", this_potcar)) assert path.isfile(path.join(calc.folder, "POTCAR")) remove(path.join(calc.contr_dir, "POTCARS", this_potcar)) kwargs = { "kpoints": { "method": "mueller", "mindistance": 50 }, "potcars": { "directory": "./tests/vasp", "xc": "pbe", "versions": { "Si": '05Jan2001' } } } calc = Vasp(atm, target, str(tmpdir), 0, **kwargs) calc._write_potcar() assert path.isfile(path.join(calc.contr_dir, "POTCARS", this_potcar)) calc._write_potcar() assert path.isfile(path.join(calc.folder, "POTCAR")) # check POTCAR reuse calc = Vasp(atm, target, str(tmpdir), 0, **kwargs) with pytest.raises(SpeciesError): kwargs = { "kpoints": { "rmin": 50 }, "potcars": { "directory": "./tests/vasp", "xc": "pbe", "versions": { "Si": '05Jan2001' } } } symlink( path.join(calc.contr_dir, "POTCARS", calc.this_potcar), path.join(reporoot, "tests", "vasp", "potpaw_PBE", "Ag", "POTCAR")) calc = Vasp(atm, '.', str(tmpdir), 0, **kwargs) with pytest.raises(VersionError): kwargs = { "kpoints": { "rmin": 50 }, "potcars": { "directory": "./tests/vasp", "xc": "pbe", "versions": { "Si": '05Jan2001' } } } symlink( path.join(calc.contr_dir, "POTCARS", calc.this_potcar), path.join(reporoot, "tests", "vasp", "potpaw_PBE", "Si_sv_GW", "POTCAR")) atm = Atoms("Si", positions=[[0, 0, 0]], cell=[[1, 0, 0], [0, 1, 0], [0, 0, 1]]) calc = Vasp(atm, '.', str(tmpdir), 0, **kwargs)
def stubs(request, tmpdir_factory): #We need to hack $PATH so that `vasp` and `module` point to the unit testing #stubs that we created. from os import path, pathsep, environ from matdb.utility import which, symlink, touch from glob import glob stubs = { "vasp": "matdb_vasp.py", "module": "matdb_module.py", "sbatch": "matdb_sbatch.py", "getKPoints": "matdb_getkpoints.py", "mlp": "matdb_mlp.py" } #Validate the existence of installed stub scripts in the python path. binpaths = {} for name, xstub in stubs.items(): binpath = which(xstub) if binpath is None: emsg = "Cannot find `{0}` stub for unit testing.".format(name) raise EnvironmentError(emsg) binpaths[name] = binpath #Create a new temporary directory as part of the unit test; create symlinks #in the directory to the stubs and hack the path to look in that directory #first. stubpath = str(tmpdir_factory.mktemp("stubs")) for name, xstub in stubs.items(): lpath = path.join(stubpath, name) symlink(lpath, binpaths[name]) environ["PATH"] = stubpath + pathsep + environ["PATH"] # from matdb.utility import execute, touch # xres = execute(["./module", "load", "mkl/*"], stubpath) # assert path.isfile(path.join(stubpath, ".matdb.module")) # xres = execute(["./sbatch", "-c", "pwd"], stubpath) # assert xres["output"] == [] # # assert xres["error"][0].strip() == "Failed to submit" # symlink(stubpath+"/sbatch.sh",stubpath+"/sbatch") # xres = execute(["./sbatch", stubpath+"/sbatch.sh"], stubpath) # temp = xres["output"][-1].strip().split()[0:3] # assert ' '.join(temp) == "Submitted batch job" # # assert xres["error"] == [] # touch(path.join(stubpath, "PRECALC")) # xres = execute(["./getKPoints"], stubpath) # assert path.isfile(path.join(stubpath, "KPOINTS")) # xres = execute(["./vasp"], stubpath) # assert path.isfile(path.join(stubpath, "CONTCAR")) # xres = execute(["./mlp", "calc-grade"], stubpath) # assert path.isfile(path.join(stubpath, "state.mvs")) # xres = execute(["./mlp", "select-add"], stubpath) # assert path.isfile(path.join(stubpath, "new_training.cfg")) # xres = execute(["./mlp", "convert-cfg"], stubpath) # assert len(glob(path.join(stubpath, "POSCAR*"))) == 10 def restore(): paths = environ["PATH"].split(pathsep) #Make sure that we actually added our temporary directory to the path. assert paths[0] == stubpath environ["PATH"] = pathsep.join(paths[1:]) request.addfinalizer(restore) return stubpath