def setUp(self): self.cscl = Structure.from_spacegroup("Pm-3m", Lattice.cubic(4.2), ["Cs", "Cl"], [[0, 0, 0], [0.5, 0.5, 0.5]]) self.Fe = Structure.from_spacegroup("Im-3m", Lattice.cubic(2.82), ["Fe"], [[0, 0, 0]]) mglatt = Lattice.from_parameters(3.2, 3.2, 5.13, 90, 90, 120) self.Mg = Structure(mglatt, ["Mg", "Mg"], [[1 / 3, 2 / 3, 1 / 4], [2 / 3, 1 / 3, 3 / 4]]) self.lifepo4 = self.get_structure("LiFePO4") self.tei = Structure.from_file(get_path("icsd_TeI.cif"), primitive=False) self.LiCoO2 = Structure.from_file(get_path("icsd_LiCoO2.cif"), primitive=False) self.p1 = Structure( Lattice.from_parameters(3, 4, 5, 31, 43, 50), ["H", "He"], [[0, 0, 0], [0.1, 0.2, 0.3]], ) self.graphite = self.get_structure("Graphite") self.trigBi = Structure( Lattice.from_parameters(3, 3, 10, 90, 90, 120), ["Bi", "Bi", "Bi", "Bi", "Bi", "Bi"], [ [0.3333, 0.6666, 0.39945113], [0.0000, 0.0000, 0.26721554], [0.0000, 0.0000, 0.73278446], [0.6666, 0.3333, 0.60054887], [0.6666, 0.3333, 0.06611779], [0.3333, 0.6666, 0.93388221], ], )
def test_distance_and_image(self): other_site = PeriodicSite("Fe", np.array([1, 1, 1]), self.lattice) (distance, image) = self.site.distance_and_image(other_site) self.assertAlmostEqual(distance, 6.22494979899, 5) self.assertTrue(([-1, -1, -1] == image).all()) (distance, image) = self.site.distance_and_image(other_site, [1, 0, 0]) self.assertAlmostEqual(distance, 19.461500456028563, 5) # Test that old and new distance algo give the same ans for # "standard lattices" lattice = Lattice(np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]])) site1 = PeriodicSite("Fe", np.array([0.01, 0.02, 0.03]), lattice) site2 = PeriodicSite("Fe", np.array([0.99, 0.98, 0.97]), lattice) self.assertAlmostEqual( get_distance_and_image_old(site1, site2)[0], site1.distance_and_image(site2)[0]) lattice = Lattice.from_parameters(1, 0.01, 1, 10, 10, 10) site1 = PeriodicSite("Fe", np.array([0.01, 0.02, 0.03]), lattice) site2 = PeriodicSite("Fe", np.array([0.99, 0.98, 0.97]), lattice) self.assertTrue( get_distance_and_image_old(site1, site2)[0] > site1.distance_and_image(site2)[0]) site2 = PeriodicSite("Fe", np.random.rand(3), lattice) (dist_old, jimage_old) = get_distance_and_image_old(site1, site2) (dist_new, jimage_new) = site1.distance_and_image(site2) self.assertTrue(dist_old - dist_new > -1e-8, "New distance algo should give smaller answers!") self.assertFalse((abs(dist_old - dist_new) < 1e-8) ^ (jimage_old == jimage_new).all(), "If old dist == new dist, images must be the same!") latt = Lattice.from_parameters(3.0, 4.0, 10.0, 3.0, 1.0, 2.0) site = PeriodicSite("Fe", [0.1, 0.1, 0.1], latt) site2 = PeriodicSite("Fe", [0.99, 0.99, 0.99], latt) (dist, img) = site.distance_and_image(site2) self.assertAlmostEqual(dist, 1.1304420998572722) self.assertEqual(list(img), [0, -1, -1])
def _identical(a, b, c, alpha, beta, gamma): mat1 = Lattice.from_parameters(a, b, c, alpha, beta, gamma, False).matrix mat2 = Lattice.from_parameters(a, b, c, alpha, beta, gamma, True).matrix # self.assertArrayAlmostEqual(mat1, mat2) return ((mat1 - mat2)**2).sum() < 1e-6
def get_lattice_quanta(self, convert_to_muC_per_cm2=True, all_in_polar=True): """ Returns the dipole / polarization quanta along a, b, and c for all structures. """ lattices = [s.lattice for s in self.structures] volumes = np.array([s.lattice.volume for s in self.structures]) L = len(self.structures) e_to_muC = -1.6021766e-13 cm2_to_A2 = 1e16 units = 1.0 / np.array(volumes) units *= e_to_muC * cm2_to_A2 # convert polarizations and lattice lengths prior to adjustment if convert_to_muC_per_cm2 and not all_in_polar: # adjust lattices for i in range(L): lattice = lattices[i] l = lattice.lengths a = lattice.angles lattices[i] = Lattice.from_parameters(*(np.array(l) * units.ravel()[i]), *a) elif convert_to_muC_per_cm2 and all_in_polar: for i in range(L): lattice = lattices[-1] l = lattice.lengths a = lattice.angles lattices[i] = Lattice.from_parameters(*(np.array(l) * units.ravel()[-1]), *a) quanta = np.array([np.array(l.lengths) for l in lattices]) return quanta
def test_distance_and_image(self): other_site = PeriodicSite("Fe", np.array([1, 1, 1]), self.lattice) (distance, image) = self.site.distance_and_image(other_site) self.assertAlmostEqual(distance, 6.22494979899, 5) self.assertTrue(([-1, -1, -1] == image).all()) (distance, image) = self.site.distance_and_image(other_site, [1, 0, 0]) self.assertAlmostEqual(distance, 19.461500456028563, 5) # Test that old and new distance algo give the same ans for # "standard lattices" lattice = Lattice(np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]])) site1 = PeriodicSite("Fe", np.array([0.01, 0.02, 0.03]), lattice) site2 = PeriodicSite("Fe", np.array([0.99, 0.98, 0.97]), lattice) self.assertAlmostEqual(get_distance_and_image_old(site1, site2)[0], site1.distance_and_image(site2)[0]) lattice = Lattice.from_parameters(1, 0.01, 1, 10, 10, 10) site1 = PeriodicSite("Fe", np.array([0.01, 0.02, 0.03]), lattice) site2 = PeriodicSite("Fe", np.array([0.99, 0.98, 0.97]), lattice) self.assertTrue(get_distance_and_image_old(site1, site2)[0] > site1.distance_and_image(site2)[0]) site2 = PeriodicSite("Fe", np.random.rand(3), lattice) (dist_old, jimage_old) = get_distance_and_image_old(site1, site2) (dist_new, jimage_new) = site1.distance_and_image(site2) self.assertTrue(dist_old - dist_new > -1e-8, "New distance algo should give smaller answers!") self.assertFalse((abs(dist_old - dist_new) < 1e-8) ^ (jimage_old == jimage_new).all(), "If old dist == new dist, images must be the same!") latt = Lattice.from_parameters(3.0, 3.1, 10.0, 2.96, 2.0, 1.0) site = PeriodicSite("Fe", [0.1, 0.1, 0.1], latt) site2 = PeriodicSite("Fe", [0.99, 0.99, 0.99], latt) (dist, img) = site.distance_and_image(site2) self.assertAlmostEqual(dist, 0.15495358379511573) self.assertEqual(list(img), [-11, 6, 0])
def test_get_niggli_reduced_lattice(self): latt = Lattice.from_parameters( 3, 5.196, 2, 103 + 55 / 60, 109 + 28 / 60, 134 + 53 / 60 ) reduced_cell = latt.get_niggli_reduced_lattice() abc = reduced_cell.lengths angles = reduced_cell.angles self.assertAlmostEqual(abc[0], 2, 3) self.assertAlmostEqual(abc[1], 3, 3) self.assertAlmostEqual(abc[2], 3, 3) self.assertAlmostEqual(angles[0], 116.382855225, 3) self.assertAlmostEqual(angles[1], 94.769790287999996, 3) self.assertAlmostEqual(angles[2], 109.466666667, 3) mat = [[5.0, 0, 0], [0, 5.0, 0], [5.0, 0, 5.0]] latt = Lattice(np.dot([[1, 1, 1], [1, 1, 0], [0, 1, 1]], mat)) reduced_cell = latt.get_niggli_reduced_lattice() abc = reduced_cell.lengths angles = reduced_cell.angles for l in abc: self.assertAlmostEqual(l, 5, 3) for a in angles: self.assertAlmostEqual(a, 90, 3) latt = Lattice( [ 1.432950, 0.827314, 4.751000, -1.432950, 0.827314, 4.751000, 0.0, -1.654628, 4.751000, ] ) # ans = [[-1.432950, -2.481942, 0.0], # [-2.8659, 0.0, 0.0], # [-1.432950, -0.827314, -4.751000]] ans = [ [-1.43295, -2.481942, 0.0], [-2.8659, 0.0, 0.0], [-1.43295, -0.827314, -4.751], ] self.assertArrayAlmostEqual(latt.get_niggli_reduced_lattice().matrix, ans) latt = Lattice.from_parameters( 7.365450, 6.199506, 5.353878, 75.542191, 81.181757, 156.396627 ) ans = [ [2.578932, 0.826965, 0.000000], [-0.831059, 2.067413, 1.547813], [-0.458407, -2.480895, 1.129126], ] self.assertArrayAlmostEqual( latt.get_niggli_reduced_lattice().matrix, np.array(ans), 5 )
def make_new_lattice(lattice, afac=0.1, alphafac=2): """make new lattice with small modification Parameters ---------- lattice: Structure.lattice lattice information afac: float a factor for lattice length modification alphafac: float a factor for lattice angle modification Returns ------- Structure.lattice new structure with small modification """ r = np.random.rand(6) a = lattice.a + r[0] * afac b = lattice.b + r[1] * afac c = lattice.c + r[2] * afac alpha = lattice.alpha + r[3] * alphafac beta = lattice.beta + r[4] * alphafac gamma = lattice.gamma + r[5] * alphafac new_lattice = Lattice.from_parameters(a, b, c, alpha, beta, gamma) return new_lattice
def compile_crystal(datarow, flavor='pmg'): """ Helper method for representing the MPDS crystal structures in two flavors: either as a Pymatgen Structure object, or as an ASE Atoms object. Attention! These two flavors are not compatible, e.g. primitive vs. crystallographic cell is defaulted, atoms wrapped or non-wrapped into the unit cell etc. Note, that the crystal structures are not retrieved by default, so one needs to specify the fields while retrieval: - cell_abc - sg_n - setting - basis_noneq - els_noneq e.g. like this: {'S':['cell_abc', 'sg_n', 'setting', 'basis_noneq', 'els_noneq']} NB. occupancies are not considered. Args: datarow: (list) Required data to construct crystal structure: [cell_abc, sg_n, setting, basis_noneq, els_noneq] flavor: (str) Either "pmg", or "ase" Returns: - if flavor is pmg, returns Pymatgen Structure object - if flavor is ase, returns ASE Atoms object """ if not datarow or not datarow[-1]: return None cell_abc, sg_n, setting, basis_noneq, els_noneq = \ datarow[-5], int(datarow[-4]), datarow[-3], datarow[-2], datarow[-1] if flavor == 'pmg': return Structure.from_spacegroup( sg_n, Lattice.from_parameters(*cell_abc), els_noneq, basis_noneq ) elif flavor == 'ase' and use_ase: atom_data = [] setting = 2 if setting == '2' else 1 for num, i in enumerate(basis_noneq): atom_data.append(Atom(els_noneq[num], tuple(i))) return crystal( atom_data, spacegroup=sg_n, cellpar=cell_abc, primitive_cell=True, setting=setting, onduplicates='replace' ) else: raise APIError("Crystal structure treatment unavailable")
def get_high_accuracy_voronoi_nodes(structure, rad_dict, probe_rad=0.1): """ Analyze the void space in the input structure using high accuracy voronoi decomposition. Calls Zeo++ for Voronoi decomposition. Args: structure: pymatgen.core.structure.Structure rad_dict (optional): Dictionary of radii of elements in structure. If not given, Zeo++ default values are used. Note: Zeo++ uses atomic radii of elements. For ionic structures, pass rad_dict with ionic radii probe_rad (optional): Sampling probe radius in Angstroms. Default is 0.1 A Returns: voronoi nodes as pymatgen.core.structure.Strucutre within the unit cell defined by the lattice of input structure voronoi face centers as pymatgen.core.structure.Strucutre within the unit cell defined by the lattice of input structure """ with ScratchDir("."): name = "temp_zeo1" zeo_inp_filename = name + ".cssr" ZeoCssr(structure).write_file(zeo_inp_filename) rad_flag = True rad_file = name + ".rad" with open(rad_file, "w+") as fp: for el in rad_dict.keys(): print(f"{el} {rad_dict[el].real}", file=fp) atmnet = AtomNetwork.read_from_CSSR(zeo_inp_filename, rad_flag=rad_flag, rad_file=rad_file) # vornet, vor_edge_centers, vor_face_centers = \ # atmnet.perform_voronoi_decomposition() red_ha_vornet = prune_voronoi_network_close_node(atmnet) # generate_simplified_highaccuracy_voronoi_network(atmnet) # get_nearest_largest_diameter_highaccuracy_vornode(atmnet) red_ha_vornet.analyze_writeto_XYZ(name, probe_rad, atmnet) voro_out_filename = name + "_voro.xyz" voro_node_mol = ZeoVoronoiXYZ.from_file(voro_out_filename).molecule species = ["X"] * len(voro_node_mol.sites) coords = [] prop = [] for site in voro_node_mol.sites: coords.append(list(site.coords)) prop.append(site.properties["voronoi_radius"]) lattice = Lattice.from_parameters(*structure.lattice.parameters) vor_node_struct = Structure( lattice, species, coords, coords_are_cartesian=True, to_unit_cell=True, site_properties={"voronoi_radius": prop}, ) return vor_node_struct
def test_pbc_shortest_vectors(self): fcoords = np.array([ [0.3, 0.3, 0.5], [0.1, 0.1, 0.3], [0.9, 0.9, 0.8], [0.1, 0.0, 0.5], [0.9, 0.7, 0.0], ]) lattice = Lattice.from_parameters(8, 8, 4, 90, 76, 58) expected = np.array([ [0.000, 3.015, 4.072, 3.519, 3.245], [3.015, 0.000, 3.207, 1.131, 4.453], [4.072, 3.207, 0.000, 2.251, 1.788], [3.519, 1.131, 2.251, 0.000, 3.852], ]) vectors = pbc_shortest_vectors(lattice, fcoords[:-1], fcoords) dists = np.sum(vectors**2, axis=-1)**0.5 self.assertArrayAlmostEqual(dists, expected, 3) # now try with small loop threshold from pymatgen.util import coord prev_threshold = coord.LOOP_THRESHOLD coord.LOOP_THRESHOLD = 0 vectors = pbc_shortest_vectors(lattice, fcoords[:-1], fcoords) dists = np.sum(vectors**2, axis=-1)**0.5 self.assertArrayAlmostEqual(dists, expected, 3) coord.LOOP_THRESHOLD = prev_threshold
def output(self,job_record): """ Collect relaxed geometry from output.""" if os.path.isfile('autogen.d12.o'): f = open('autogen.d12.o', 'r') lines = f.readlines() for li,line in enumerate(lines): if 'FINAL OPTIMIZED GEOMETRY' in line: lattice_params = [float(v) for v in lines[li+6].split()] lattice = Lattice.from_parameters( lattice_params[0], lattice_params[1], lattice_params[2], lattice_params[3], lattice_params[4], lattice_params[5]) idx = li+11 species = [] coords = [] while len(lines[idx].strip()) != 0: species.append(int(lines[idx].split()[2])-200) coords.append([float(v) for v in lines[idx].split()[4:7]]) idx += 1 coords = np.asarray(coords) job_record['dft']['relaxed_cif'] = str( CifWriter(Structure(lattice=lattice,species=species,coords=coords)) ) break job_record = AbstractRunCrystal.output(self, job_record) return job_record
def test_static_methods(self): lengths_c = [3.840198, 3.84019885, 3.8401976] angles_c = [119.99998575, 90, 60.00000728] mat_c = [ [3.840198, 0.000000, 0.0000], [1.920099, 3.325710, 0.000000], [0.000000, -2.217138, 3.135509], ] # should give the lengths and angles above newlatt = Lattice(mat_c) lengths = newlatt.lengths angles = newlatt.angles for i in range(0, 3): self.assertAlmostEqual(lengths[i], lengths_c[i], 5, "Lengths incorrect!") self.assertAlmostEqual(angles[i], angles_c[i], 5, "Angles incorrect!") latt = Lattice.from_parameters(*lengths, *angles) lengths = latt.lengths angles = latt.angles for i in range(0, 3): self.assertAlmostEqual(lengths[i], lengths_c[i], 5, "Lengths incorrect!") self.assertAlmostEqual(angles[i], angles_c[i], 5, "Angles incorrect!")
def test_find_all_mappings(self): m = np.array([[0.1, 0.2, 0.3], [-0.1, 0.2, 0.7], [0.6, 0.9, 0.2]]) latt = Lattice(m) op = SymmOp.from_origin_axis_angle([0, 0, 0], [2, -1, 3], 40) rot = op.rotation_matrix scale = np.array([[0, 2, 0], [1, 1, 0], [0, 0, 1]]) latt2 = Lattice(np.dot(rot, np.dot(scale, m).T).T) for (aligned_out, rot_out, scale_out) in latt.find_all_mappings(latt2): self.assertArrayAlmostEqual(np.inner(latt2.matrix, rot_out), aligned_out.matrix, 5) self.assertArrayAlmostEqual(np.dot(scale_out, latt.matrix), aligned_out.matrix) self.assertArrayAlmostEqual(aligned_out.parameters, latt2.parameters) self.assertFalse( np.allclose(aligned_out.parameters, latt.parameters)) latt = Lattice.orthorhombic(9, 9, 5) self.assertEqual(len(list(latt.find_all_mappings(latt))), 16) # catch the singular matrix error latt = Lattice.from_parameters(1, 1, 1, 10, 10, 10) for l, _, _ in latt.find_all_mappings(latt, ltol=0.05, atol=11): self.assertTrue(isinstance(l, Lattice))
def test_selling_dist(self): # verification process described here: https://github.com/materialsproject/pymatgen/pull/1888#issuecomment-818072164 np.testing.assert_(Lattice.selling_dist(Lattice.cubic(5), Lattice.cubic(5)) == 0) hex_lattice = Lattice.hexagonal(5, 8) triclinic_lattice = Lattice.from_parameters(4, 10, 11, 100, 110, 80) np.testing.assert_allclose(Lattice.selling_dist(hex_lattice, triclinic_lattice), 76, rtol=0.1) np.testing.assert_allclose( Lattice.selling_dist(Lattice.tetragonal(10, 12), Lattice.tetragonal(10.1, 11.9)), 3.7, rtol=0.1, ) np.testing.assert_allclose( Lattice.selling_dist(Lattice.cubic(5), Lattice.from_parameters(8, 10, 12, 80, 90, 95)), 115.6, rtol=0.1, )
def scale_slots( self, scales: Tuple[float, float, float] = (1.0, 1.0, 1.0)) -> None: """ Applies in-place a scaling along cell vectors of the slots contines in the topology. TODO: rename scales to three a, b, c parameters for clarity Parameters ---------- scales : Tuple[float, float, float], optional the cell vector lengths to apply, by default (1.0, 1.0, 1.0) """ alpha, beta, gamma = self.cell.angles a, b, c = scales scaled_cell = Lattice.from_parameters(a, b, c, alpha, beta, gamma) scaled_slots = [] for slot in self.slots: scaled_slot = copy.deepcopy(slot) fract_coords = self.cell.get_fractional_coords( slot.atoms.cart_coords) scaled_coords = scaled_cell.get_cartesian_coords(fract_coords) scaled_slot.atoms = Molecule( slot.atoms.species, scaled_coords, site_properties=slot.atoms.site_properties) scaled_slots.append(scaled_slot) self.slots = scaled_slots self.cell = scaled_cell return None
def test_get_all_distances(self): fcoords = np.array([ [0.3, 0.3, 0.5], [0.1, 0.1, 0.3], [0.9, 0.9, 0.8], [0.1, 0.0, 0.5], [0.9, 0.7, 0.0], ]) lattice = Lattice.from_parameters(8, 8, 4, 90, 76, 58) expected = np.array([ [0.000, 3.015, 4.072, 3.519, 3.245], [3.015, 0.000, 3.207, 1.131, 4.453], [4.072, 3.207, 0.000, 2.251, 1.788], [3.519, 1.131, 2.251, 0.000, 3.852], [3.245, 4.453, 1.788, 3.852, 0.000], ]) output = lattice.get_all_distances(fcoords, fcoords) self.assertArrayAlmostEqual(output, expected, 3) # test just one input point output2 = lattice.get_all_distances(fcoords[0], fcoords) self.assertArrayAlmostEqual(output2, [expected[0]], 2) # test distance when initial points are not in unit cell f1 = [0, 0, 17] f2 = [0, 0, 10] self.assertEqual(lattice.get_all_distances(f1, f2)[0, 0], 0)
def get_boxed_structure(self, a, b, c): """ Creates a Structure from a Molecule by putting the Molecule in a box. Useful for creating Structure for calculating molecules using periodic codes. Args: a: a-lattice parameter. b: b-lattice parameter. c: c-lattice parameter. Returns: Structure containing molecule in a box. """ coords = np.array(self.cart_coords) x_range = max(coords[:, 0]) - min(coords[:, 0]) y_range = max(coords[:, 1]) - min(coords[:, 1]) z_range = max(coords[:, 2]) - min(coords[:, 2]) if a <= x_range or b <= y_range or c <= z_range: raise ValueError("Box is not big enough to contain Molecule.") lattice = Lattice.from_parameters(a, b, c, 90, 90, 90) return Structure(lattice, self.species, self.cart_coords, coords_are_cartesian=True, site_properties=self.site_properties)
def make_random_lattice(self, constraints, random): """ Returns a random lattice that satisfies the constraints on maximum and minimum lengths and angles. Args: constraints: the Constraints of the search random: a copy of Python's built in PRNG """ # make three random lattice vectors that satisfy the length constraints a = constraints.min_lattice_length + random.random() * ( constraints.max_lattice_length - constraints.min_lattice_length) b = constraints.min_lattice_length + random.random() * ( constraints.max_lattice_length - constraints.min_lattice_length) c = constraints.min_lattice_length + random.random() * ( constraints.max_lattice_length - constraints.min_lattice_length) # make three random lattice angles that satisfy the angle constraints alpha = constraints.min_lattice_angle + random.random() * ( constraints.max_lattice_angle - constraints.min_lattice_angle) beta = constraints.min_lattice_angle + random.random() * ( constraints.max_lattice_angle - constraints.min_lattice_angle) gamma = constraints.min_lattice_angle + random.random() * ( constraints.max_lattice_angle - constraints.min_lattice_angle) # build the random lattice return Lattice.from_parameters(a, b, c, alpha, beta, gamma)
def from_string(string): """ Reads a string representation to a Cssr object. Args: string (str): A string representation of a CSSR. Returns: Cssr object. """ lines = string.split("\n") toks = lines[0].split() lengths = [float(i) for i in toks] toks = lines[1].split() angles = [float(i) for i in toks[0:3]] latt = Lattice.from_parameters(*lengths, *angles) sp = [] coords = [] for l in lines[4:]: m = re.match( r"\d+\s+(\w+)\s+([0-9\-\.]+)\s+([0-9\-\.]+)\s+([0-9\-\.]+)", l.strip()) if m: sp.append(m.group(1)) coords.append([float(m.group(i)) for i in range(2, 5)]) return Cssr(Structure(latt, sp, coords))
def from_string(header_str): """ Reads Header string and returns Header object if header was generated by pymatgen. Note: Checks to see if generated by pymatgen, if not it is impossible to generate structure object so it is not possible to generate header object and routine ends Args: header_str: pymatgen generated feff.inp header Returns: Structure object. """ lines = tuple(clean_lines(header_str.split("\n"), False)) comment1 = lines[0] feffpmg = comment1.find("pymatgen") if feffpmg == -1: feffpmg = False if feffpmg: comment2 = " ".join(lines[1].split()[2:]) source = " ".join(lines[2].split()[2:]) basis_vec = lines[6].split(":")[-1].split() # a, b, c a = float(basis_vec[0]) b = float(basis_vec[1]) c = float(basis_vec[2]) lengths = [a, b, c] # alpha, beta, gamma basis_ang = lines[7].split(":")[-1].split() alpha = float(basis_ang[0]) beta = float(basis_ang[1]) gamma = float(basis_ang[2]) angles = [alpha, beta, gamma] lattice = Lattice.from_parameters(*lengths, *angles) natoms = int(lines[8].split(":")[-1].split()[0]) atomic_symbols = [] for i in range(9, 9 + natoms): atomic_symbols.append(lines[i].split()[2]) # read the atomic coordinates coords = [] for i in range(natoms): toks = lines[i + 9].split() coords.append([float(s) for s in toks[3:]]) struct = Structure(lattice, atomic_symbols, coords, False, False, False) h = Header(struct, source, comment2) return h raise ValueError( "Header not generated by pymatgen, cannot return header object")
def topology_from_string(cgd: str, spacegroups: Dict[str, int]) -> Tuple[str, Structure]: lines = cgd.splitlines() lines = [l[2:].split() for l in lines if len(l) > 2] elements = [] xyz = [] is_2D = False # might benefit from new case syntax in 3.10 for l in lines: if l[0].startswith("NAME"): name = l[1].strip() elif l[0].startswith("GROUP"): groupname = l[1].strip() if groupname not in spacegroups.keys(): return groupname, None sg = spacegroups[groupname] elif l[0].startswith("CELL"): parameters = [float(p) for p in l[1:]] if len(parameters) == 3: # 2D net, only one angle and two vectors. # need to be completed up to 6 parameters parameters = parameters[0:2] + [10.0, 90.0, 90.0 ] + parameters[2:] is_2D = True lattice = Lattice.from_parameters(*parameters) elif l[0].startswith("NODE"): elements.append(get_el_sp(int(l[2]))) xyz.append(numpy.array(l[3:], dtype=float)) elif l[0].startswith("EDGE_CENTER"): # add a linear connector, represented by He elements.append(get_el_sp(int(2))) xyz.append(numpy.array(l[1:], dtype=float)) elif l[0].startswith("EDGE"): # now we append some dummies s = int((len(l) - 1) / 2) midl = int((len(l) + 1) / 2) x0 = numpy.array(l[1:midl], dtype=float).reshape(-1, 1) x1 = numpy.array(l[midl:], dtype=float).reshape(-1, 1) xx = numpy.concatenate([x0, x1], axis=1).T com = xx.mean(axis=0) xx -= com xx = xx.dot(numpy.eye(s) * 0.5) xx += com dummy_element = get_el_sp("X") xyz += [xx[0], xx[1]] elements += [dummy_element, dummy_element] # concatenate the coordinates xyz = numpy.stack(xyz, axis=0) if is_2D: # node coordinates need to be padded xyz = numpy.pad(xyz, ((0, 0), (0, 1)), 'constant', constant_values=0.0) # generate the crystal topology = Structure.from_spacegroup(sg=sg, lattice=lattice, species=elements, coords=xyz) # remove any duplicate sites topology.merge_sites(tol=1e-3, mode="delete") return name, topology
def _get_structure_from_spcgrp(self): if 'A' not in self.lattice: raise AssertionError() if 'B' not in self.lattice: logging.info('Lattice vector B not given, assume equal to A') self.lattice['B'] = self.lattice['A'] if 'C' not in self.lattice: logging.info('Lattice vector C not given, assume equal to A') self.lattice['C'] = self.lattice['C'] if 'ALPHA' not in self.lattice: logging.info('Lattice angle ALPHA not given, assume right-angle') self.lattice['ALPHA'] = 90 if 'BETA' not in self.lattice: logging.info('Lattice angle BETA not given, assume right-angle') self.lattice['BETA'] = 90 if 'GAMMA' not in self.lattice: try: spcgrp_number = int(self.lattice['SPCGRP']) except ValueError: spcgrp_number = 0 if (167 < spcgrp_number < 195): logging.info('Lattice angle GAMMA not given, ' 'hexagonal space group, assume 120') self.lattice['GAMMA'] = 120 else: logging.info('Lattice angle GAMMA not given, ' 'assume right-angle') self.lattice['GAMMA'] = 90 if self.cartesian: logging.info("Warning: Cartesian positions used without " "explicit lattice vectors") if 'UNITS' not in self.lattice or self.lattice['UNITS'] is None: if self.ignore_units: pass else: for length in ('A', 'B', 'C'): self.lattice[length] *= _bohr_to_angstrom if 'ALAT' not in self.lattice: raise AssertionError() for length in ('A', 'B', 'C'): self.lattice[length] *= self.lattice['ALAT'] lattice = Lattice.from_parameters(self.lattice['A'], self.lattice['B'], self.lattice['C'], self.lattice['ALPHA'], self.lattice['BETA'], self.lattice['GAMMA']) species, coords = self._get_species_coords() return Structure.from_spacegroup(self.lattice['SPCGRP'], lattice, species, coords, coords_are_cartesian=self.cartesian, tol=self.tol)
def test_pbc_shortest_vectors(self): fcoords = np.array( [ [0.3, 0.3, 0.5], [0.1, 0.1, 0.3], [0.9, 0.9, 0.8], [0.1, 0.0, 0.5], [0.9, 0.7, 0.0], ] ) lattice = Lattice.from_parameters(8, 8, 4, 90, 76, 58) expected = np.array( [ [0.000, 3.015, 4.072, 3.519, 3.245], [3.015, 0.000, 3.207, 1.131, 4.453], [4.072, 3.207, 0.000, 2.251, 1.788], [3.519, 1.131, 2.251, 0.000, 3.852], ] ) vectors = coord.pbc_shortest_vectors(lattice, fcoords[:-1], fcoords) dists = np.sum(vectors**2, axis=-1) ** 0.5 self.assertArrayAlmostEqual(dists, expected, 3) prev_threshold = coord.LOOP_THRESHOLD coord.LOOP_THRESHOLD = 0 vectors = coord.pbc_shortest_vectors(lattice, fcoords[:-1], fcoords) dists = np.sum(vectors**2, axis=-1) ** 0.5 self.assertArrayAlmostEqual(dists, expected, 3) coord.LOOP_THRESHOLD = prev_threshold lattice_pbc = Lattice.from_parameters(8, 8, 4, 90, 76, 58, pbc=(True, True, False)) expected_pbc = np.array( [ [0.000, 3.015, 4.072, 3.519, 4.089], [3.015, 0.000, 3.207, 1.131, 4.453], [4.072, 3.207, 0.000, 2.251, 3.578], [3.519, 1.131, 2.251, 0.000, 4.235], ] ) vectors = coord.pbc_shortest_vectors(lattice_pbc, fcoords[:-1], fcoords) dists = np.sum(vectors**2, axis=-1) ** 0.5 self.assertArrayAlmostEqual(dists, expected_pbc, 3)
def reorient_axis(self) -> None: """ Change the orientation of the lattice vector so that: a points along the x-axis, b is in the xy-plane, c is in the positive-z halve of space """ args = ( self.structure.lattice.abc + self.structure.lattice.angles ) # type: Tuple[float, float, float, float, float, float] self.structure.lattice = Lattice.from_parameters(*args, vesta=True)
def setUp(self): self.cscl = self.get_structure("CsCl") self.lifepo4 = self.get_structure("LiFePO4") self.tei = Structure.from_file(get_path("icsd_TeI.cif"), primitive=False) self.LiCoO2 = Structure.from_file(get_path("icsd_LiCoO2.cif"), primitive=False) self.p1 = Structure(Lattice.from_parameters(3, 4, 5, 31, 43, 50), ["H", "He"], [[0, 0, 0], [0.1, 0.2, 0.3]])
def test_from_structure_NPT(self): coords1 = np.array([[0.0, 0.0, 0.0], [0.5, 0.5, 0.5]]) coords2 = np.array([[0.0, 0.0, 0.0], [0.6, 0.6, 0.6]]) coords3 = np.array([[0.0, 0.0, 0.0], [0.7, 0.7, 0.7]]) lattice1 = Lattice.from_parameters(a=2.0, b=2.0, c=2.0, alpha=90, beta=90, gamma=90) lattice2 = Lattice.from_parameters(a=2.1, b=2.1, c=2.1, alpha=90, beta=90, gamma=90) lattice3 = Lattice.from_parameters(a=2.0, b=2.0, c=2.0, alpha=90, beta=90, gamma=90) s1 = Structure(coords=coords1, lattice=lattice1, species=["F", "Li"]) s2 = Structure(coords=coords2, lattice=lattice2, species=["F", "Li"]) s3 = Structure(coords=coords3, lattice=lattice3, species=["F", "Li"]) structures = [s1, s2, s3] d = DiffusionAnalyzer.from_structures( structures, specie="Li", temperature=500.0, time_step=2.0, step_skip=1, smoothed=None, ) self.assertArrayAlmostEqual( d.disp[1], np.array([[0.0, 0.0, 0.0], [0.21, 0.21, 0.21], [0.40, 0.40, 0.40]]), )
def test_process_entry_ozonide(self): el_li = Element("Li") el_o = Element("O") elts = [el_li, el_o, el_o, el_o] latt = Lattice.from_parameters(3.999911, 3.999911, 3.999911, 133.847504, 102.228244, 95.477342) coords = [[0.513004, 0.513004, 1.000000], [0.017616, 0.017616, 0.000000], [0.649993, 0.874790, 0.775203], [0.099587, 0.874790, 0.224797]] struct = Structure(latt, elts, coords) lio3_entry = ComputedStructureEntry(struct, -19.20762604) lio3_entry_corrected = self.compat.process_entry(lio3_entry) self.assertEqual(lio3_entry_corrected, None)
def setUp(self): self.cscl = Structure.from_spacegroup( "Pm-3m", Lattice.cubic(4.2), ["Cs", "Cl"], [[0, 0, 0], [0.5, 0.5, 0.5]]) self.lifepo4 = self.get_structure("LiFePO4") self.tei = Structure.from_file(get_path("icsd_TeI.cif"), primitive=False) self.LiCoO2 = Structure.from_file(get_path("icsd_LiCoO2.cif"), primitive=False) self.p1 = Structure(Lattice.from_parameters(3, 4, 5, 31, 43, 50), ["H", "He"], [[0, 0, 0], [0.1, 0.2, 0.3]]) self.graphite = self.get_structure("Graphite")
def setUp(self): self.cscl = Structure.from_spacegroup("Pm-3m", Lattice.cubic(4.2), ["Cs", "Cl"], [[0, 0, 0], [0.5, 0.5, 0.5]]) self.lifepo4 = self.get_structure("LiFePO4") self.tei = Structure.from_file(get_path("icsd_TeI.cif"), primitive=False) self.LiCoO2 = Structure.from_file(get_path("icsd_LiCoO2.cif"), primitive=False) self.p1 = Structure(Lattice.from_parameters(3, 4, 5, 31, 43, 50), ["H", "He"], [[0, 0, 0], [0.1, 0.2, 0.3]]) self.graphite = self.get_structure("Graphite")
def test_get_niggli_reduced_lattice(self): latt = Lattice.from_parameters(3, 5.196, 2, 103 + 55 / 60, 109 + 28 / 60, 134 + 53 / 60) reduced_cell = latt.get_niggli_reduced_lattice() abc, angles = reduced_cell.lengths_and_angles self.assertAlmostEqual(abc[0], 2, 3) self.assertAlmostEqual(abc[1], 3, 3) self.assertAlmostEqual(abc[2], 3, 3) self.assertAlmostEqual(angles[0], 116.382855225, 3) self.assertAlmostEqual(angles[1], 94.769790287999996, 3) self.assertAlmostEqual(angles[2], 109.466666667, 3) mat = [[5.0, 0, 0], [0, 5.0, 0], [5.0, 0, 5.0]] latt = Lattice(np.dot([[1, 1, 1], [1, 1, 0], [0, 1, 1]], mat)) reduced_cell = latt.get_niggli_reduced_lattice() abc, angles = reduced_cell.lengths_and_angles for l in abc: self.assertAlmostEqual(l, 5, 3) for a in angles: self.assertAlmostEqual(a, 90, 3) latt = Lattice([1.432950, 0.827314, 4.751000, -1.432950, 0.827314, 4.751000, 0.0, -1.654628, 4.751000]) ans = [[-1.432950, -2.481942, 0.0], [-2.8659, 0.0, 0.0], [-1.432950, -0.827314, -4.751000]] self.assertArrayAlmostEqual(latt.get_niggli_reduced_lattice().matrix, ans) latt = Lattice.from_parameters(7.365450, 6.199506, 5.353878, 75.542191, 81.181757, 156.396627) ans = [[-2.578932, -0.826965, 0.000000], [0.831059, -2.067413, -1.547813], [0.458407, 2.480895, -1.129126]] self.assertArrayAlmostEqual(latt.get_niggli_reduced_lattice().matrix, ans, 5)
def setUp(self): self.cscl = Structure.from_spacegroup( "Pm-3m", Lattice.cubic(4.2), ["Cs", "Cl"], [[0, 0, 0], [0.5, 0.5, 0.5]]) self.Fe = Structure.from_spacegroup( \ "Im-3m", Lattice.cubic(2.82), ["Fe"], [[0, 0, 0]]) self.lifepo4 = self.get_structure("LiFePO4") self.tei = Structure.from_file(get_path("icsd_TeI.cif"), primitive=False) self.LiCoO2 = Structure.from_file(get_path("icsd_LiCoO2.cif"), primitive=False) self.p1 = Structure(Lattice.from_parameters(3, 4, 5, 31, 43, 50), ["H", "He"], [[0, 0, 0], [0.1, 0.2, 0.3]]) self.graphite = self.get_structure("Graphite") self.trigBi = Structure(Lattice.from_parameters(3, 3, 10, 90, 90, 120), ["Bi", "Bi", "Bi", "Bi", "Bi", "Bi"], [[0.3333, 0.6666, 0.39945113], [0.0000, 0.0000, 0.26721554], [0.0000, 0.0000, 0.73278446], [0.6666, 0.3333, 0.60054887], [0.6666, 0.3333, 0.06611779], [0.3333, 0.6666, 0.93388221]])
def test_primitive_positions(self): coords = [[0, 0, 0], [0.3, 0.35, 0.45]] s = Structure(Lattice.from_parameters(1,2,3,50,66,88), ["Ag"] * 2, coords) a = [[-1,2,-3], [3,2,-4], [1,0,-1]] b = [[4, 0, 0], [1, 1, 0], [3, 0, 1]] c = [[2, 0, 0], [1, 3, 0], [1, 1, 1]] for sc_matrix in [c]: sc = s.copy() sc.make_supercell(sc_matrix) prim = sc.get_primitive_structure(0.01) self.assertEqual(len(prim), 2) self.assertAlmostEqual(prim.distance_matrix[0,1], 1.0203432356739286)
def test_add_sp_hydrogen(): """Add H on simplified case with one neighbor""" site_b_coord = [0, 0, 0] site_a_coord = [0.5, 0, 0] lattice = Lattice.from_parameters(1, 1, 1, 90, 90, 90) site_a = PeriodicSite(Composition("H"), site_a_coord, lattice) site_b = ConnectedSite( PeriodicSite(Composition("H"), site_b_coord, lattice)) hydrogen = add_sp_hydrogen(site_a, [site_b]) assert len(hydrogen) == 3 assert np.abs(np.linalg.norm(np.array(site_a_coord) - hydrogen) - 1) < 0.01 assert np.linalg.norm(hydrogen[1]) < 0.01 assert np.linalg.norm(hydrogen[2]) < 0.01
def test_process_entry_hydroxide(self): el_li = Element("Li") el_o = Element("O") el_h = Element("H") latt = Lattice.from_parameters(3.565276, 3.565276, 4.384277, 90.000000, 90.000000, 90.000000) elts = [el_h, el_h, el_li, el_li, el_o, el_o] coords = [[0.000000, 0.500000, 0.413969], [0.500000, 0.000000, 0.586031], [0.000000, 0.000000, 0.000000], [0.500000, 0.500000, 0.000000], [0.000000, 0.500000, 0.192672], [0.500000, 0.000000, 0.807328]] struct = Structure(latt, elts, coords) lioh_entry = ComputedStructureEntry(struct, -29.85285134) lioh_entry_corrected = self.compat.process_entry(lioh_entry) self.assertAlmostEqual(lioh_entry_corrected.energy, -28.9047, 4)
def test_consistency(self): """ when only lengths and angles are given for constructors, the internal matrix representation is ambiguous since the lattice rotation is not specified. This test makes sure that a consistent definition is specified for the lattice rotation when using different constructors from lengths angles """ l = [3.840198, 3.84019885, 3.8401976] a = [119.99998575, 90, 60.00000728] mat1 = Lattice.from_lengths_and_angles(l, a).matrix mat2 = Lattice.from_parameters(l[0], l[1], l[2], a[0], a[1], a[2]).matrix for i in range(0, 3): for j in range(0, 3): self.assertAlmostEqual(mat1[i][j], mat2[i][j], 5)
def structure(self): """ Transform from LammpsData file to a pymatgen structure object Return: A pymatgen structure object """ species_map = {} for sp in self.atomic_masses: for el in Element: if abs(el.atomic_mass - sp[1]) < 0.05: species_map[sp[0]] = el xhi, yhi, zhi = self.box_size[0][1] - self.box_size[0][0], self.box_size[1][1] - self.box_size[1][0], \ self.box_size[2][1] - self.box_size[0][0] xy, xz, yz = self.box_tilt if self.box_tilt is not None else [ 0.0, 0.0, 0.0 ] a = xhi b = np.sqrt(yhi**2 + xy**2) c = np.sqrt(zhi**2 + xz**2 + yz**2) gamma = math.degrees(math.acos(xy / b)) beta = math.degrees(math.acos(xz / c)) alpha = math.degrees(math.acos((yhi * yz + xy * xz) / b / c)) lattice = Lattice.from_parameters(a, b, c, alpha, beta, gamma) species = [] coords = [] for d in self.atoms_data: if self.atom_style == 'full': if d[3] != 0: species.append(Specie(species_map[d[2]].symbol, d[3])) else: species.append(species_map[d[1]]) coords.append(d[4:7]) elif self.atom_style == 'charge': if d[2] != 0: species.append(Specie(species_map[d[1]].symbol, d[2])) else: species.append(species_map[d[1]]) coords.append(d[3:6]) elif self.atom_style == 'atomic': species.append(species_map[d[1]]) coords.append(d[2:5]) else: raise RuntimeError('data style not implemented') return Structure(lattice, species, coords, coords_are_cartesian=True)
def _get_structure(entry, use_web_api=True): """ Extracts structure data from AFLOW CONTCAR file. If the file is unavailable, the structure can be reconstituted from different fields in the AFLOW database. Can perform web queries to retrieve those fields. Args: entry (aflow.entries.Entry): entry containing the CONTCAR data as a string in the "AEL_elastic_tensor_json" field, or containing the fields 'geometry', 'species', 'composition', and 'positions_fractional'. use_web_api (bool): True allows missing data to be retrieved from the AFLOW API. False will raise an exception if the data is missing. Default: True Returns: pymatgen.core.structure.Structure: a pymatgen structure object """ data_in = entry.raw.get('CONTCAR_relax_vasp') contcar = True if data_in is None: contcar = False if contcar: try: structure = Structure.from_str(data_in, fmt="poscar") return structure except Exception: logger.warning("Parsing structure file for {} failed.".format(entry.auid) + " Generating from material entry") if not use_web_api: if not all(kw in entry.attributes for kw in ('geometry', 'species', 'composition', 'positions_fractional')): return None from pymatgen.core.lattice import Lattice # This lazy-loads the data by making an HTTP request for each property it needs # if the fields don't exist in the entry geometry = entry.geometry lattice = Lattice.from_parameters(*geometry) elements = list(map(str.strip, entry.species)) composition = list(entry.composition) species = list(chain.from_iterable([elem] * comp for elem, comp in zip(elements, composition))) xyz = entry.positions_fractional.tolist() return Structure(lattice, species, xyz)
def test_add_sp3_hydrogens_on_cn1(): """Test on a toy example with one neighbor on the x axis""" site_b_coord = [0, 0, 0] site_a_coord = [0.5, 0, 0] lattice = Lattice.from_parameters(1, 1, 1, 90, 90, 90) site_a = PeriodicSite(Composition("H"), site_a_coord, lattice) site_b = ConnectedSite( PeriodicSite(Composition("H"), site_b_coord, lattice)) vectors = add_sp3_hydrogens_on_cn1(site_a, [site_b]) for vector in vectors: assert (np.linalg.norm(vector - np.array(site_a_coord)) - 1) < 0.01 assert vector[0] > 0.5 assert vector[1] != 0 assert vector[2] != 0
def test_primitive_positions(self): coords = [[0, 0, 0], [0.3, 0.35, 0.45]] s = Structure(Lattice.from_parameters(1, 2, 3, 50, 66, 88), ["Ag"] * 2, coords) a = [[-1, 2, -3], [3, 2, -4], [1, 0, -1]] b = [[4, 0, 0], [1, 1, 0], [3, 0, 1]] c = [[2, 0, 0], [1, 3, 0], [1, 1, 1]] for sc_matrix in [c]: sc = s.copy() sc.make_supercell(sc_matrix) prim = sc.get_primitive_structure(0.01) self.assertEqual(len(prim), 2) self.assertAlmostEqual(prim.distance_matrix[0, 1], 1.0203432356739286)
def test_process_entry_peroxide(self): latt = Lattice.from_parameters(3.159597, 3.159572, 7.685205, 89.999884, 89.999674, 60.000510) el_li = Element("Li") el_o = Element("O") elts = [el_li, el_li, el_li, el_li, el_o, el_o, el_o, el_o] coords = [[0.666656, 0.666705, 0.750001], [0.333342, 0.333378, 0.250001], [0.000001, 0.000041, 0.500001], [0.000001, 0.000021, 0.000001], [0.333347, 0.333332, 0.649191], [0.333322, 0.333353, 0.850803], [0.666666, 0.666686, 0.350813], [0.666665, 0.666684, 0.149189]] struct = Structure(latt, elts, coords) li2o2_entry = ComputedStructureEntry(struct, -38.80421304) li2o2_entry_corrected = self.compat.process_entry(li2o2_entry) self.assertAlmostEqual(li2o2_entry_corrected.energy, -37.80087, 4)
def structure(self): """ Transform from LammpsData file to a pymatgen structure object Return: A pymatgen structure object """ species_map = {} for sp in self.atomic_masses: for el in Element: if abs(el.atomic_mass - sp[1]) < 0.05: species_map[sp[0]] = el xhi, yhi, zhi = self.box_size[0][1] - self.box_size[0][0], self.box_size[1][1] - self.box_size[1][0], \ self.box_size[2][1] - self.box_size[0][0] xy, xz, yz = self.box_tilt if self.box_tilt is not None else [0.0, 0.0, 0.0] a = xhi b = np.sqrt(yhi ** 2 + xy ** 2) c = np.sqrt(zhi ** 2 + xz ** 2 + yz ** 2) gamma = math.degrees(math.acos(xy / b)) beta = math.degrees(math.acos(xz / c)) alpha = math.degrees(math.acos((yhi * yz + xy * xz) / b / c)) lattice = Lattice.from_parameters(a, b, c, alpha, beta, gamma) species = [] coords = [] for d in self.atoms_data: if self.atom_style == 'full': if d[3] != 0: species.append(Specie(species_map[d[2]].symbol, d[3])) else: species.append(species_map[d[1]]) coords.append(d[4:7]) elif self.atom_style == 'charge': if d[2] != 0: species.append(Specie(species_map[d[1]].symbol, d[2])) else: species.append(species_map[d[1]]) coords.append(d[3:6]) elif self.atom_style == 'atomic': species.append(species_map[d[1]]) coords.append(d[2:5]) else: raise RuntimeError('data style not implemented') return Structure(lattice, species, coords, coords_are_cartesian=True)
def test_distance_and_image(self): other_site = PeriodicSite("Fe", np.array([1, 1, 1]), self.lattice) (distance, image) = self.site.distance_and_image(other_site) self.assertAlmostEquals(distance, 6.22494979899, 5) self.assertTrue(([-1, -1, -1] == image).all()) (distance, image) = self.site.distance_and_image(other_site, [1, 0, 0]) self.assertAlmostEquals(distance, 19.461500456028563, 5) # Test that old and new distance algo give the same ans for "standard lattices" lattice = Lattice(np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]])) site1 = PeriodicSite("Fe", np.array([0.01, 0.02, 0.03]), lattice) site2 = PeriodicSite("Fe", np.array([0.99, 0.98, 0.97]), lattice) self.assertTrue(site1.distance_and_image_old(site2)[0] == site1.distance_and_image(site2)[0]) lattice = Lattice.from_parameters(1, 0.01, 1, 10, 10, 10) site1 = PeriodicSite("Fe", np.array([0.01, 0.02, 0.03]), lattice) site2 = PeriodicSite("Fe", np.array([0.99, 0.98, 0.97]), lattice) self.assertTrue(site1.distance_and_image_old(site2)[0] > site1.distance_and_image(site2)[0]) site2 = PeriodicSite("Fe", np.random.rand(3), lattice) (dist_old, jimage_old) = site1.distance_and_image_old(site2) (dist_new, jimage_new) = site1.distance_and_image(site2) self.assertTrue(dist_old >= dist_new, "New distance algo should always give smaller answers!") self.assertFalse((dist_old == dist_new) ^ (jimage_old == jimage_new).all(), "If old dist == new dist, the images returned must be the same!")
def get_relaxed_structure(self, gout): #Find the structure lines structure_lines = [] cell_param_lines = [] #print gout output_lines = gout.split("\n") no_lines = len(output_lines) i = 0 # Compute the input lattice parameters while i < no_lines: line = output_lines[i] if "Full cell parameters" in line: i += 2 line = output_lines[i] a = float(line.split()[8]) alpha = float(line.split()[11]) line = output_lines[i + 1] b = float(line.split()[8]) beta = float(line.split()[11]) line = output_lines[i + 2] c = float(line.split()[8]) gamma = float(line.split()[11]) i += 3 break elif "Cell parameters" in line: i += 2 line = output_lines[i] a = float(line.split()[2]) alpha = float(line.split()[5]) line = output_lines[i + 1] b = float(line.split()[2]) beta = float(line.split()[5]) line = output_lines[i + 2] c = float(line.split()[2]) gamma = float(line.split()[5]) i += 3 break else: i += 1 while i < no_lines: line = output_lines[i] if "Final fractional coordinates of atoms" in line: # read the site coordinates in the following lines i += 6 line = output_lines[i] while line[0:2] != '--': structure_lines.append(line) i += 1 line = output_lines[i] # read the cell parameters i += 9 line = output_lines[i] if "Final cell parameters" in line: i += 3 for del_i in range(6): line = output_lines[i + del_i] cell_param_lines.append(line) break else: i += 1 #Process the structure lines if structure_lines: sp = [] coords = [] for line in structure_lines: fields = line.split() if fields[2] == 'c': sp.append(fields[1]) coords.append(list(float(x) for x in fields[3:6])) else: raise IOError("No structure found") if cell_param_lines: a = float(cell_param_lines[0].split()[1]) b = float(cell_param_lines[1].split()[1]) c = float(cell_param_lines[2].split()[1]) alpha = float(cell_param_lines[3].split()[1]) beta = float(cell_param_lines[4].split()[1]) gamma = float(cell_param_lines[5].split()[1]) latt = Lattice.from_parameters(a, b, c, alpha, beta, gamma) return Structure(latt, sp, coords)
def test_oxide_type(self): el_li = Element("Li") el_o = Element("O") latt = Lattice([[3.985034, 0.0, 0.0], [0.0, 4.881506, 0.0], [0.0, 0.0, 2.959824]]) elts = [el_li, el_li, el_o, el_o, el_o, el_o] coords = list() coords.append([0.500000, 0.500000, 0.500000]) coords.append([0.0, 0.0, 0.0]) coords.append([0.632568, 0.085090, 0.500000]) coords.append([0.367432, 0.914910, 0.500000]) coords.append([0.132568, 0.414910, 0.000000]) coords.append([0.867432, 0.585090, 0.000000]) struct = Structure(latt, elts, coords) self.assertEqual(oxide_type(struct, 1.1), "superoxide") el_li = Element("Li") el_o = Element("O") elts = [el_li, el_o, el_o, el_o] latt = Lattice.from_parameters(3.999911, 3.999911, 3.999911, 133.847504, 102.228244, 95.477342) coords = [[0.513004, 0.513004, 1.000000], [0.017616, 0.017616, 0.000000], [0.649993, 0.874790, 0.775203], [0.099587, 0.874790, 0.224797]] struct = Structure(latt, elts, coords) self.assertEqual(oxide_type(struct, 1.1), "ozonide") latt = Lattice.from_parameters(3.159597, 3.159572, 7.685205, 89.999884, 89.999674, 60.000510) el_li = Element("Li") el_o = Element("O") elts = [el_li, el_li, el_li, el_li, el_o, el_o, el_o, el_o] coords = [[0.666656, 0.666705, 0.750001], [0.333342, 0.333378, 0.250001], [0.000001, 0.000041, 0.500001], [0.000001, 0.000021, 0.000001], [0.333347, 0.333332, 0.649191], [0.333322, 0.333353, 0.850803], [0.666666, 0.666686, 0.350813], [0.666665, 0.666684, 0.149189]] struct = Structure(latt, elts, coords) self.assertEqual(oxide_type(struct, 1.1), "peroxide") el_li = Element("Li") el_o = Element("O") el_h = Element("H") latt = Lattice.from_parameters(3.565276, 3.565276, 4.384277, 90.000000, 90.000000, 90.000000) elts = [el_h, el_h, el_li, el_li, el_o, el_o] coords = [[0.000000, 0.500000, 0.413969], [0.500000, 0.000000, 0.586031], [0.000000, 0.000000, 0.000000], [0.500000, 0.500000, 0.000000], [0.000000, 0.500000, 0.192672], [0.500000, 0.000000, 0.807328]] struct = Structure(latt, elts, coords) self.assertEqual(oxide_type(struct, 1.1), "hydroxide") el_li = Element("Li") el_n = Element("N") el_h = Element("H") latt = Lattice.from_parameters(3.565276, 3.565276, 4.384277, 90.000000, 90.000000, 90.000000) elts = [el_h, el_h, el_li, el_li, el_n, el_n] coords = [[0.000000, 0.500000, 0.413969], [0.500000, 0.000000, 0.586031], [0.000000, 0.000000, 0.000000], [0.500000, 0.500000, 0.000000], [0.000000, 0.500000, 0.192672], [0.500000, 0.000000, 0.807328]] struct = Structure(latt, elts, coords) self.assertEqual(oxide_type(struct, 1.1), "None")