def test___eq__(self): atom1 = Atom("N", [0.0, 0.0, 0.0]) atom2 = Atom("N", [0.0, 0.0, 1.1]) pos1 = Posinp([atom1, atom2], "angstroem", "free") pos2 = Posinp([atom2, atom1], "angstroem", "free") assert pos1 == pos2 # The order of the atoms in the list do not count assert pos1 != 1 # No error if other object is not a posinp
def test_to_barycenter(self): atoms = [Atom("N", [0, 0, 0]), Atom("N", [0, 0, 1.1])] pos = Posinp(atoms, units="angstroem", boundary_conditions="free") expected_atoms = [Atom("N", [0, 0, -0.55]), Atom("N", [0, 0, 0.55])] expected_pos = Posinp( expected_atoms, units="angstroem", boundary_conditions="free" ) assert pos.to_barycenter() == expected_pos
def test_positions(self): expected = [7.327412521, 0.0, 3.461304757] pos1 = Posinp( [Atom("C", expected)], units="angstroem", boundary_conditions="free" ) pos2 = pos1.translate_atom(0, [-7.327412521, 0.0, -3.461304757]) assert np.allclose(pos1.positions, expected) assert np.allclose(pos2.positions, [0, 0, 0])
def test_convert(self): pos_angstrom = Posinp.from_file( os.path.join(pos_folder, "H2O_unrelaxed.xyz")) pos_atomic = Posinp.from_file( os.path.join(pos_folder, "H2O_atomic.xyz")) job1 = Job(posinp=pos_angstrom, calculator=self.calc3) job2 = Job(posinp=pos_atomic, calculator=self.calc3) job1.run("energy") job2.run("energy") assert job1.results["energy"] == job2.results["energy"]
def test_with_surface_boundary_conditions(self): # Two Posinp instances with surface BC are the same even if they # have a different cell size along y-axis pos_with_inf = Posinp( [ Atom( "N", [2.97630782434901e-23, 6.87220595204354e-23, 0.0107161998748779], ), Atom( "N", [-1.10434491945017e-23, -4.87342174483075e-23, 1.10427379608154], ), ], "angstroem", "surface", cell=[40, ".inf", 40], ) with pytest.raises(ValueError): pos_wo_inf = Posinp( [ Atom( "N", [2.97630782434901e-23, 6.87220595204354e-23, 0.0107161998748779], ), Atom( "N", [-1.10434491945017e-23, -4.87342174483075e-23, 1.10427379608154], ), ], "angstroem", "surface", cell=[40, 40, 40], ) # They are obviously different if the cell size along the other # directions are not the same pos2_with_inf = Posinp( [ Atom( "N", [2.97630782434901e-23, 6.87220595204354e-23, 0.0107161998748779], ), Atom( "N", [-1.10434491945017e-23, -4.87342174483075e-23, 1.10427379608154], ), ], "angstroem", "surface", cell=[20, "inf", 40], ) assert pos_with_inf != pos2_with_inf # They still have the same BC assert pos2_with_inf.boundary_conditions == pos_with_inf.boundary_conditions
class TestEnsemble: pos1 = Posinp.from_file(os.path.join(pos_folder, "H2O_unrelaxed.xyz")) model1 = os.path.join(model_folder, "H2O_forces_model") model2 = os.path.join(model_folder, "H2O_model") def test_both_models(self): ens = EnsembleCalculator(modelpaths=[self.model1, self.model2]) job1 = Job(posinp=self.pos1, calculator=ens) job1.run("energy") assert job1.results["energy"] == np.array(-1277.0513) assert job1.results["energy_std"] == np.array(799.70636) ref_forces = np.array( [ [0, 0.7647542, -7.8656354], [0, -2.2895808, 3.8240397], [0, 1.5248268, 4.0415955], ], dtype=np.float32, ) ref_std = np.array( [ [0, 0.03656149, 1.2570109], [0, 0.8168775, 0.4650414], [0, 0.8534391, 0.7919693], ], dtype=np.float32, ) job2 = Job(posinp=self.pos1, calculator=ens) job2.run("forces") assert np.isclose(job2.results["forces"], ref_forces, atol=1e-04).all() assert np.isclose(job2.results["forces_std"], ref_std, atol=1e-04).all()
def main(args): function = get_function(args.function) distances = np.linspace(args.range[0], args.range[1], args.ndata) with connect(args.dbname) as db: for d in distances: pos_dict = { "units": "angstroem", "boundary_conditions": "free", "positions": [ { args.element: [0, 0, 0] }, { args.element: [d, 0, 0] }, ], } posinp = Posinp.from_dict(pos_dict) atoms = posinp_to_ase_atoms(posinp) energy = function.value(d) forces = np.array([ [-1.0 * function.first_derivative(-d), 0, 0], [-1.0 * function.first_derivative(d), 0, 0], ]) db.write(atoms, data={"energy": energy, "forces": forces})
def test_convert(self): pos1 = self.periodic_pos.positions assert self.periodic_pos.units == "angstroem" self.periodic_pos.convert_units("atomic") assert np.isclose( self.periodic_pos.positions, np.array( [ [0.15747717, 0.94486299, 0.4724315], [0.78738583, 0.94486299, 0.4724315], [1.10234016, 0.94486299, 1.41729449], [1.73224882, 0.94486299, 1.41729449], ] ), ).all() assert self.periodic_pos.units == "atomic" self.periodic_pos.convert_units("angstroem") assert np.isclose(self.periodic_pos.positions, pos1).all() assert self.periodic_pos.units == "angstroem" self.periodic_pos.convert_units("angstroem") assert np.isclose(self.periodic_pos.positions, pos1).all() red = Posinp.from_file(tests_fol + "reduced.xyz") red.convert_units("angstroem") print(red.positions) assert np.isclose( red.positions, np.array( [ [0.4233418, 1.32294312, 0.95251905], [3.81007619, 0.26458862, 0.47625952], ] ), ).all()
def test_repr(self): atoms = [Atom("C", [0, 0, 0]), Atom("N", [0, 0, 1])] new_pos = Posinp(atoms, units="angstroem", boundary_conditions="free") msg = ( "Posinp([Atom('C', [0.0, 0.0, 0.0]), Atom('N', [0.0, 0.0, " "1.0])], 'angstroem', 'free', cell=Cell([0.0, 0.0, 0.0]), angles=[90. 90. 90.])" ) assert repr(new_pos) == msg
class TestSchnetPack: pos1 = Posinp.from_file(os.path.join(pos_folder, "N2.xyz")) model1 = os.path.join(model_folder, "ani1_N2_model") model2 = os.path.join(model_folder, "wacsf_model") model3 = os.path.join(model_folder, "H2O_model") calc1 = SchnetPackCalculator(model_dir=model1) calc2 = SchnetPackCalculator(model_dir=model2) calc3 = SchnetPackCalculator(model_dir=model3) job = Job(posinp=pos1, calculator=calc1) jobwacsf = Job(posinp=pos1, calculator=calc2) def test_only_energy(self): self.job.run("energy") assert np.array(-2979.6067) == self.job.results["energy"][0] new_job = deepcopy(self.job) new_job.calculator.units = {"energy": "hartree", "positions": "atomic"} new_job.run("energy") assert new_job.results["energy"][0] == np.array(-81079.228) self.job.results["energy"] = None def test_forces_from_deriv(self): assert self.job.calculator.available_properties == ["energy"] self.job.run("forces") ref_forces = np.array([[-0.0, -0.0, -0.31532133], [-0.0, -0.0, 0.31532133]]) assert np.isclose(self.job.results["forces"][0], ref_forces).all() new_job = deepcopy(self.job) new_job.calculator.units = {"energy": "hartree", "positions": "atomic"} new_job.run("forces") assert np.isclose(ref_forces * 51.42206334724, new_job.results["forces"][0]).all() def test_forces_from_finite_difference(self): assert self.job.calculator.available_properties == ["energy"] self.job.run("forces", finite_difference=True) ref_forces = np.array([[-0.0, -0.0, -0.32416448], [-0.0, -0.0, 0.32416448]]) assert np.isclose(self.job.results["forces"][0], ref_forces).all() def test_wacsf(self): self.jobwacsf.run("energy") assert self.jobwacsf.results["energy"] is not None def test_bad_property(self): with pytest.raises(ValueError): self.job.run("dipole") def test_convert(self): pos_angstrom = Posinp.from_file( os.path.join(pos_folder, "H2O_unrelaxed.xyz")) pos_atomic = Posinp.from_file( os.path.join(pos_folder, "H2O_atomic.xyz")) job1 = Job(posinp=pos_angstrom, calculator=self.calc3) job2 = Job(posinp=pos_atomic, calculator=self.calc3) job1.run("energy") job2.run("energy") assert job1.results["energy"] == job2.results["energy"]
class TestGeopt: posN2 = Posinp.from_file(os.path.join(pos_folder, "N2_unrelaxed.xyz")) posH2O = Posinp.from_file(os.path.join(pos_folder, "H2O_unrelaxed.xyz")) calcN2 = SchnetPackCalculator(os.path.join(model_folder, "ani1_N2_model")) calcH2O = SchnetPackCalculator(os.path.join(model_folder, "H2O_model")) def test_N2(self, capsys): init = Job(posinp=self.posN2, calculator=self.calcN2) init.run("energy") assert init.results["energy"][0] == -2978.2354 geo = Geopt(posinp=self.posN2, calculator=self.calcN2) geo.run(recenter=True, verbose=2) output = capsys.readouterr() assert 1.101 < geo.final_posinp.distance(0, 1) < 1.103 assert np.isclose( geo.final_posinp.positions[0, 2], -geo.final_posinp.positions[1, 2], atol=1e-6, ) assert output.out is not None final = Job(posinp=geo.final_posinp, calculator=self.calcN2) final.run("energy") assert final.results["energy"][0] == -2979.6070 def test_H2O(self): init = Job(posinp=self.posH2O, calculator=self.calcH2O) init.run("energy") assert np.isclose(init.results["energy"][0], -2076.7576, atol=1e-4) geo = Geopt(posinp=self.posH2O, calculator=self.calcH2O) geo.run() assert 0.964 < geo.final_posinp.distance(0, 1) < 0.965 assert (geo.final_posinp.distance(0, 1) - geo.final_posinp.distance(0, 2)) < 0.0001 # TODO Check the angle final = Job(posinp=geo.final_posinp, calculator=self.calcH2O) final.run("energy") assert np.isclose(final.results["energy"][0], -2078.6301, atol=1e-4) def test_errors(self): with pytest.raises(ValueError): geo = Geopt(posinp=None, calculator=self.calcN2) with pytest.raises(TypeError): geo = Geopt(posinp=self.posN2, calculator=1)
class TestJob: file1, file2, file3 = ( os.path.join(pos_folder, "free.xyz"), os.path.join(pos_folder, "surface.xyz"), os.path.join(pos_folder, "N2.xyz"), ) pos1, pos2, pos3 = ( Posinp.from_file(file1), Posinp.from_file(file2), Posinp.from_file(file3), ) dummy = Calculator(available_properties="", units={ "positions": "atomic", "energy": "eV" }) badCalc = dict() job = Job(name="test", posinp=[pos1, pos2, pos3], calculator=dummy) def test_raises_no_positions(self): with pytest.raises(ValueError): j = Job(calculator=self.dummy) def test_raises_posinp_types(self): with pytest.raises(TypeError): j = Job(posinp=[self.pos1, 1], calculator=self.dummy) def test_raises_bad_calc(self): with pytest.raises(TypeError): j = Job(posinp=[self.pos1], calculator=self.badCalc) def test_posinp_types(self): job1 = Job(posinp=self.pos1, calculator=self.dummy) job2 = Job(posinp=[self.pos1], calculator=self.dummy) assert job1.posinp == job2.posinp @pytest.mark.parametrize( "value, expected", [(job.name, "test"), (job.num_struct, 3), (job.posinp[1], pos2)], ) def test_values(self, value, expected): assert value == expected
class TestGrapheneAngles: graphene2_name = os.path.join(pos_folder, "gra2.xyz") pos_2at = Posinp.from_file(graphene2_name) graphene4_name = os.path.join(pos_folder, "gra4_red.xyz") pos_4at_red = Posinp.from_file(graphene4_name) calc = SchnetPackCalculator(os.path.join(model_folder, "H2O_model")) def test_same_result(self): j1 = Job(posinp=self.pos_2at, calculator=self.calc) j1.run("energy") e1 = j1.results["energy"] j2 = Job(posinp=self.pos_4at_red, calculator=self.calc) j2.run("energy") e2 = j2.results["energy"] pos_4at = deepcopy(self.pos_4at_red) pos_4at.convert_units("angstroem") j3 = Job(posinp=pos_4at, calculator=self.calc) j3.run("energy") e3 = j3.results["energy"] assert e2 == e3 assert np.isclose(e2, 2 * e1, atol=0.0002) def test_cell_with_angles(self): assert np.isclose( self.pos_2at.cell.array, np.array([[2.46, 0.0, 0.0], [0.0, 0.0, 0.0], [1.23, 0.0, 2.13042249]]), ).all() def test_verify_values(self): assert np.isclose(self.pos_2at.angles, np.array([90.0, 60.0, 90.0])).all() assert self.pos_4at_red.orthorhombic assert not self.pos_2at.orthorhombic assert np.isclose(self.pos_2at.cell.lengths(), np.array([2.46, 0.0, 2.46])).all()
def main(args): eval_name = args.modelpath.split("/")[-1] eval_file = "evaluation_" + eval_name + ".txt" if os.path.exists(eval_file): if args.overwrite: os.remove(eval_file) else: raise Exception( "The evaluation file already exists. Delete it or add the overwrite flag." ) device = "cuda" if args.cuda else "cpu" calculator = mlcalcdriver.calculators.SchnetPackCalculator(args.modelpath, device=device) with connect(args.dbpath) as db: answers, results = ( [[] for _ in range(len(args.properties))], [[] for _ in range(len(args.properties))], ) posinp = [] for row in db.select(): for i, prop in enumerate(args.properties): answers[i].append(row.data[prop]) posinp.append(Posinp.from_ase(row.toatoms())) if len(posinp) == args.batch_size: job = Job(posinp=posinp, calculator=calculator) for i, prop in enumerate(args.properties): job.run(prop, batch_size=args.batch_size) results[i].append(job.results[prop].tolist()) posinp = [] if len(posinp) > 0: job = Job(posinp=posinp, calculator=calculator) for i, prop in enumerate(args.properties): job.run(prop, batch_size=args.batch_size) results[i].append(job.results[prop]) posinp = [] header, error = [], [] for prop in args.properties: header += ["MAE_" + prop, "%Error_" + prop, "RMSE_" + prop] for l1, l2 in zip(answers, results): an, re = np.array(l1).flatten(), np.concatenate(l2).flatten() error.append(np.abs(an - re).mean()) error.append(np.abs((an - re) / an).mean() * 100) error.append(np.sqrt(np.mean((an - re)**2))) with open(eval_file, "w") as file: wr = csv.writer(file) wr.writerow(header) wr.writerow(error)
def get_dos( model, posinp, device="cpu", supercell=(6, 6, 6), qpoints=[30, 30, 30], npts=1000, width=0.004, ): if isinstance(posinp, str): atoms = posinp_to_ase_atoms(Posinp.from_file(posinp)) elif isinstance(posinp, Posinp): atoms = posinp_to_ase_atoms(posinp) else: raise ValueError("The posinp variable is not recognized.") if isinstance(model, str): model = load_model(model, map_location=device) elif isinstance(model, torch.nn.Module): pass else: raise ValueError("The model variable is not recognized.") # Bugfix to make older models work with PyTorch 1.6 # Hopefully temporary for mod in model.modules(): if not hasattr(mod, "_non_persistent_buffers_set"): mod._non_persistent_buffers_set = set() assert len(supercell) == 3, "Supercell should be a length 3 object." assert len(qpoints) == 3, "Qpoints should be a length 3 object." supercell = tuple(supercell) cutoff = float(model.state_dict() ["representation.interactions.0.cutoff_network.cutoff"]) calculator = SpkCalculator( model, device=device, energy="energy", forces="forces", environment_provider=AseEnvironmentProvider(cutoff), ) ph = Phonons(atoms, calculator, supercell=supercell, delta=0.02) ph.run() ph.read(acoustic=True) dos = ph.get_dos(kpts=qpoints).sample_grid(npts=npts, width=width) ph.clean() return Dos(dos.energy * 8065.6, dos.weights[0])
def generate_graphene_cell(xsize, zsize): base_cell = np.array([2.4674318, 0, 4.2737150]) positions = [] reduced_pos = np.array([[0, 0, 0], [0, 0, 1.0 / 3], [0.5, 0, 0.5], [0.5, 0, 5.0 / 6]]) for i in range(xsize): for j in range(zsize): p = (np.array([i, 0, j]) + reduced_pos) * base_cell for pi in p: positions.append({"C": pi}) pos_dict = { "units": "angstroem", "cell": base_cell * np.array([xsize, 0, zsize]), "positions": positions, } pos = Posinp.from_dict(pos_dict) return pos
class TestPhononAutoGrad: posH2O = Posinp.from_file(os.path.join(pos_folder, "H2Orelaxed.xyz")) calc_ener = SchnetPackCalculator(os.path.join(model_folder, "H2O_model")) calc_for = SchnetPackCalculator( os.path.join(model_folder, "H2O_forces_model")) def test_ph_h2o_autograd_2nd_derivative(self): ph1 = Phonon(posinp=self.posH2O, calculator=self.calc_ener) ph1.run() ph1.energies.sort() assert np.allclose(ph1.energies[6:9], [1726, 3856, 3942], atol=1) def test_ph_h2o_autograd_1st_derivative(self): ph1 = Phonon(posinp=self.posH2O, calculator=self.calc_for) ph1.run() ph1.energies.sort() assert np.allclose(ph1.energies[6:9], [1589, 3703, 3812], atol=1)
def get_orthonormal_basis(modes=None, model=None, posinp=None, write=False): if modes: with h5py.File(modes, "r") as f: normal_modes = f["modes"][:] orthonormal_basis = gramschmidt(normal_modes) else: calculator = SchnetPackCalculator(model) posinp = Posinp.from_file(posinp) ph = Phonon(posinp=posinp, calculator=calculator) ph.run() normal_modes = ph.normal_modes.copy() orthonormal_basis = gramschmidt(normal_modes) if write: fx = h5py.File("orthonormal_basis.h5", "w") fx.create_dataset("basis", data=orthonormal_basis) fx.close() return orthonormal_basis
class TestPhononFinite: posN2 = Posinp.from_file(os.path.join(pos_folder, "N2_unrelaxed.xyz")) calcN2 = SchnetPackCalculator(os.path.join(model_folder, "myN2_model")) def test_ph_N2(self): ph1 = Phonon(posinp=self.posN2, calculator=self.calcN2, finite_difference=True) ph1.run(batch_size=1) assert np.isclose(ph1.energies.max(), 2339.53, atol=0.01) assert all( np.abs(np.delete(ph1.energies, np.argmax(ph1.energies))) < 30) ph2 = Phonon( posinp=ph1._ground_state, calculator=ph1.calculator, relax=False, finite_difference=True, translation_amplitudes=0.03, ) ph2.run() assert np.allclose(ph1.energies, ph2.energies) ph3 = Phonon( posinp=self.posN2, calculator=self.calcN2, finite_difference=True, relax=False, ) ph3.run() assert not np.allclose(ph3.energies, ph1.energies, atol=100) def test_phonon_posinp_error(self): with pytest.raises(TypeError): ph = Phonon(posinp=None, calculator=self.calcN2) def test_phonon_calc_error(self): with pytest.raises(TypeError): ph = Phonon(posinp=self.posN2, calculator=None)
def get_normal_modes(posinp, model, device="cpu", rotate=False): calculator = SchnetPackCalculator(model, device=device) posinp = Posinp.from_file(posinp) ph = Phonon(posinp=posinp, calculator=calculator) ph.run() if rotate: ndim = 3 * len(posinp) final_modes = np.zeros((ndim, ndim)) idx = np.arange(ndim) for i in range(ndim): init = ph.normal_modes[:, i] final = np.empty_like(init) final[np.where(idx % 3 == 0)[0]] = init[np.where(idx % 3 == 0)[0]] final[np.where(idx % 3 == 1)[0]] = init[np.where(idx % 3 == 2)[0]] final[np.where(idx % 3 == 2)[0]] = -1.0 * init[np.where(idx % 3 == 1)[0]] final_modes[:, i] = final return ph.energies, final_modes else: return ph.energies, ph.normal_modes
def main(args): with connect(args.dbname) as db: db.metadata = DEFAULT_METADATA if args.run_mode == "bigdft": files = [f for f in os.listdir() if f.endswith(".xyz")] for f in files: atoms = posinp_to_ase_atoms(Posinp.from_file(f)) with open(f, "r") as posinp_file: energy = float( posinp_file.readline().split()[2]) * 27.21138602 forces = None for line in posinp_file: if "forces" not in line: continue else: forces = [] for _ in range(len(atoms)): forces.append([ float(force) for force in posinp_file.readline().split()[-3:] ]) forces = np.array( forces) * 27.21138602 / 0.529177249 break db.write(atoms, data={"energy": energy, "forces": forces}) elif args.run_mode == "abinit": files = [f for f in os.listdir() if f.endswith(".out")] for f in files: atoms = read(f, format="abinit-out") about = AbinitOutputFile(f) energy = float(about.final_vars_global["etotal"]) * 27.21138602 forces = (np.array([ float(g) for g in about.final_vars_global["fcart"].split() ]).reshape(-1, 3) * 27.21138602 / 0.529177249) db.write(atoms, data={"energy": energy, "forces": forces})
def test_surface(self): pos1 = Posinp.from_file(os.path.join(pos_folder, "surface2.xyz")) atoms = posinp_to_ase_atoms(pos1) pos2 = Posinp.from_ase(atoms) assert pos1 == pos2
class TestPosinp: # Posinp with surface boundary conditions surface_filename = os.path.join(tests_fol, "surface.xyz") pos = Posinp.from_file(surface_filename) # Posinp with free boundary conditions free_filename = os.path.join(tests_fol, "free.xyz") free_pos = Posinp.from_file(free_filename) periodic_filename = os.path.join(tests_fol, "periodic.xyz") periodic_pos = Posinp.from_file(periodic_filename) # Posinp read from a string string = """\ 4 atomic free C 0.6661284109 0.000000000 1.153768252 C 3.330642055 0.000000000 1.153768252 C 4.662898877 1.000000000 3.461304757 C 7.327412521 0.000000000 3.461304757""" str_pos = Posinp.from_string(string) value = [len(pos), pos.units, pos.boundary_conditions, pos.cell, pos[0], pos.angles] expected = [ 4, "reduced", "surface", Cell.new(np.array([8.07007483423, 0.0, 4.65925987792])), Atom("C", [0.08333333333, 0.5, 0.25]), np.array([90.0, 90.0, 90.0]), ] def test_from_file(self): for v, e in zip(self.value, self.expected): if isinstance(v, np.ndarray) or isinstance(v, Cell): assert np.allclose(v, e) else: assert v == e def test_from_string(self): assert self.str_pos == self.free_pos def test_repr(self): atoms = [Atom("C", [0, 0, 0]), Atom("N", [0, 0, 1])] new_pos = Posinp(atoms, units="angstroem", boundary_conditions="free") msg = ( "Posinp([Atom('C', [0.0, 0.0, 0.0]), Atom('N', [0.0, 0.0, " "1.0])], 'angstroem', 'free', cell=Cell([0.0, 0.0, 0.0]), angles=[90. 90. 90.])" ) assert repr(new_pos) == msg def test_write(self): fname = os.path.join(tests_fol, "test.xyz") self.pos.write(fname) assert self.pos == Posinp.from_file(fname) os.remove(fname) def test_free_boundary_conditions_has_no_cell(self): assert (self.free_pos.cell == Cell.new()).all() def test_translate_atom(self): new_pos = self.pos.translate_atom(0, [0.5, 0, 0]) assert new_pos != self.pos assert new_pos[0] == Atom("C", [0.58333333333, 0.5, 0.25]) @pytest.mark.parametrize( "fname", ["free_reduced.xyz", "missing_atom.xyz", "additional_atom.xyz"] ) def test_init_raises_ValueError(self, fname): with pytest.raises(ValueError): Posinp.from_file(os.path.join(tests_fol, fname)) @pytest.mark.parametrize( "to_evaluate", [ "Posinp([Atom('C', [0, 0, 0])], 'bohr', 'periodic')", "Posinp([Atom('C', [0, 0, 0])], 'bohr', 'periodic', cell=[1, 1])", "Posinp([Atom('C', [0, 0, 0])], 'bohr', 'periodic', cell=[1,'inf',1])", ], ) def test_init_raises_ValueError2(self, to_evaluate): with pytest.raises(ValueError): eval(to_evaluate) def test_positions(self): expected = [7.327412521, 0.0, 3.461304757] pos1 = Posinp( [Atom("C", expected)], units="angstroem", boundary_conditions="free" ) pos2 = pos1.translate_atom(0, [-7.327412521, 0.0, -3.461304757]) assert np.allclose(pos1.positions, expected) assert np.allclose(pos2.positions, [0, 0, 0]) def test___eq__(self): atom1 = Atom("N", [0.0, 0.0, 0.0]) atom2 = Atom("N", [0.0, 0.0, 1.1]) pos1 = Posinp([atom1, atom2], "angstroem", "free") pos2 = Posinp([atom2, atom1], "angstroem", "free") assert pos1 == pos2 # The order of the atoms in the list do not count assert pos1 != 1 # No error if other object is not a posinp def test_with_surface_boundary_conditions(self): # Two Posinp instances with surface BC are the same even if they # have a different cell size along y-axis pos_with_inf = Posinp( [ Atom( "N", [2.97630782434901e-23, 6.87220595204354e-23, 0.0107161998748779], ), Atom( "N", [-1.10434491945017e-23, -4.87342174483075e-23, 1.10427379608154], ), ], "angstroem", "surface", cell=[40, ".inf", 40], ) with pytest.raises(ValueError): pos_wo_inf = Posinp( [ Atom( "N", [2.97630782434901e-23, 6.87220595204354e-23, 0.0107161998748779], ), Atom( "N", [-1.10434491945017e-23, -4.87342174483075e-23, 1.10427379608154], ), ], "angstroem", "surface", cell=[40, 40, 40], ) # They are obviously different if the cell size along the other # directions are not the same pos2_with_inf = Posinp( [ Atom( "N", [2.97630782434901e-23, 6.87220595204354e-23, 0.0107161998748779], ), Atom( "N", [-1.10434491945017e-23, -4.87342174483075e-23, 1.10427379608154], ), ], "angstroem", "surface", cell=[20, "inf", 40], ) assert pos_with_inf != pos2_with_inf # They still have the same BC assert pos2_with_inf.boundary_conditions == pos_with_inf.boundary_conditions def test_to_centroid(self): atoms = [Atom("N", [0, 0, 0]), Atom("N", [0, 0, 1.1])] pos = Posinp(atoms, units="angstroem", boundary_conditions="free") expected_atoms = [Atom("N", [0, 0, -0.55]), Atom("N", [0, 0, 0.55])] expected_pos = Posinp( expected_atoms, units="angstroem", boundary_conditions="free" ) assert pos.to_centroid() == expected_pos def test_to_barycenter(self): atoms = [Atom("N", [0, 0, 0]), Atom("N", [0, 0, 1.1])] pos = Posinp(atoms, units="angstroem", boundary_conditions="free") expected_atoms = [Atom("N", [0, 0, -0.55]), Atom("N", [0, 0, 0.55])] expected_pos = Posinp( expected_atoms, units="angstroem", boundary_conditions="free" ) assert pos.to_barycenter() == expected_pos def test_distance(self): assert np.isclose(self.free_pos.distance(0, 2), 4.722170992308181) def test_convert(self): pos1 = self.periodic_pos.positions assert self.periodic_pos.units == "angstroem" self.periodic_pos.convert_units("atomic") assert np.isclose( self.periodic_pos.positions, np.array( [ [0.15747717, 0.94486299, 0.4724315], [0.78738583, 0.94486299, 0.4724315], [1.10234016, 0.94486299, 1.41729449], [1.73224882, 0.94486299, 1.41729449], ] ), ).all() assert self.periodic_pos.units == "atomic" self.periodic_pos.convert_units("angstroem") assert np.isclose(self.periodic_pos.positions, pos1).all() assert self.periodic_pos.units == "angstroem" self.periodic_pos.convert_units("angstroem") assert np.isclose(self.periodic_pos.positions, pos1).all() red = Posinp.from_file(tests_fol + "reduced.xyz") red.convert_units("angstroem") print(red.positions) assert np.isclose( red.positions, np.array( [ [0.4233418, 1.32294312, 0.95251905], [3.81007619, 0.26458862, 0.47625952], ] ), ).all() def test_angles(self): h2o = Posinp.from_file(tests_fol + "H2Orelaxed.xyz") a = h2o.angle(1, 0, 2) * 180 / np.pi assert np.isclose(a, 104.1219, atol=10 ** -4) a1, a2 = h2o.angle(0, 1, 2), h2o.angle(2, 1, 0) assert a1 == a2
def test_periodic(self): pos1 = Posinp.from_file(os.path.join(pos_folder, "periodic.xyz")) atoms = posinp_to_ase_atoms(pos1) pos2 = Posinp.from_ase(atoms) assert pos1 == pos2
def get_normal_modes(posinp, model, device="cpu"): calculator = SchnetPackCalculator(model, device=device) posinp = Posinp.from_file(posinp) ph = Phonon(posinp=posinp, calculator=calculator) ph.run() return ph.energies, ph.normal_modes
import numpy as np from mlcalcdriver import Posinp import matplotlib.pyplot as plt pos = Posinp.from_file("data/posinp.xyz") translations = ( np.array( [ [0, 0, 0], [1, 0, 0], [-1, 0, 0], [0, 0, 1], [0, 0, -1], [1, 0, 1], [1, 0, -1], [-1, 0, 1], [-1, 0, -1], ] ) * pos.cell ) results = [] n = 50000 n_at = len(pos) for _ in range(n): i,j = np.random.choice(n_at, 2, replace=False) atom1, atom2 = pos[i], pos[j]
def test_init_raises_ValueError(self, fname): with pytest.raises(ValueError): Posinp.from_file(os.path.join(tests_fol, fname))
def test_write(self): fname = os.path.join(tests_fol, "test.xyz") self.pos.write(fname) assert self.pos == Posinp.from_file(fname) os.remove(fname)
def test_angles(self): h2o = Posinp.from_file(tests_fol + "H2Orelaxed.xyz") a = h2o.angle(1, 0, 2) * 180 / np.pi assert np.isclose(a, 104.1219, atol=10 ** -4) a1, a2 = h2o.angle(0, 1, 2), h2o.angle(2, 1, 0) assert a1 == a2
from mlcalcdriver import Posinp import numpy as np import os from copy import copy import matplotlib.pyplot as plt pos_folder = "positions/" positions = [ Posinp.from_file(pos_folder + file) for file in os.listdir(pos_folder) if file.endswith(".xyz") ] distances, angles = [], [] for pos in positions: az_idx = [i for i, at in enumerate(pos) if at.type == "N"] if len(az_idx) == 2: distances.append(pos.distance(az_idx[0], az_idx[1])) angles.append(np.pi) elif len(az_idx) == 3: mid = np.array(pos.cell) / 2 d = np.array( [np.linalg.norm(pos[idx].position - mid) for idx in az_idx]) mid_idx = az_idx[np.argmin(d)] other_idx = copy(az_idx) del other_idx[np.argmin(d)] distances.append(pos.distance(mid_idx, other_idx[0])) distances.append(pos.distance(mid_idx, other_idx[1])) angles.append(pos.angle(other_idx[0], mid_idx, other_idx[1])) else: