def test_cart2frac(self): lattice_cart = [[2, 0, 0], [0, 2, 0], [0, 0, 2]] positions_abs = [1, 1, 1] self.assertEqual(cart2frac(lattice_cart, positions_abs), [0.5, 0.5, 0.5]) lattice_cart = [[2, 0, 0], [0, 2, 0], [0, 0, 2]] positions_abs = [[1, 1, 1]] self.assertEqual(cart2frac(lattice_cart, positions_abs), [[0.5, 0.5, 0.5]]) lattice_cart = [[2, 0, 0], [0, 2, 0], [0, 0, 2]] positions_abs = [[2, 2, 2], [1, 1, 1]] self.assertEqual(cart2frac(lattice_cart, positions_abs), [[1, 1, 1], [0.5, 0.5, 0.5]])
def positions_frac(self): """ Return list of fractional positions. """ from matador.utils.cell_utils import cart2frac if 'positions_frac' not in self._data: self._data['positions_frac'] = cart2frac(self.cell.lattice_cart, self.positions_abs) return self._data['positions_frac']
def optimade_to_basic_cif(structure): """ A simple CIF creator that is enough to trick ChemDoodle. """ cif_string = "" lattice_abc = cart2abc(structure.attributes.lattice_vectors) positions_frac = cart2frac( structure.attributes.lattice_vectors, structure.attributes.cartesian_site_positions, ) cif_string += f"_cell_length_a {lattice_abc[0][0]}\n" cif_string += f"_cell_length_b {lattice_abc[0][1]}\n" cif_string += f"_cell_length_c {lattice_abc[0][2]}\n" cif_string += f"_cell_angle_alpha {lattice_abc[1][0]}\n" cif_string += f"_cell_angle_beta {lattice_abc[1][1]}\n" cif_string += f"_cell_angle_gamma {lattice_abc[1][2]}\n" cif_string += "loop_\n" cif_string += "_atom_site_label\n" cif_string += "_atom_site_symbol\n" cif_string += "_atom_site_fract_x\n" cif_string += "_atom_site_fract_y\n" cif_string += "_atom_site_fract_z\n" for atom, pos in zip(structure.attributes.species_at_sites, positions_frac): cif_string += f"{atom} {atom} {pos[0]} {pos[1]} {pos[2]}\n" return cif_string
def test_conversion_transitivity(self): """ Test that cart2frac(frac2cart(A)) == A. """ castep_fname = REAL_PATH + "data/Na3Zn4-swap-ReOs-OQMD_759599.castep" test_doc, s = castep2dict(castep_fname, db=True, verbosity=VERBOSITY) lattice_cart = test_doc["lattice_cart"] positions_frac = test_doc["positions_frac"] np.testing.assert_almost_equal( cart2frac(lattice_cart, frac2cart(lattice_cart, positions_frac)), positions_frac, decimal=10, )
def test_cart2abc(self): castep_fname = REAL_PATH + "data/Na3Zn4-swap-ReOs-OQMD_759599.castep" self.assertTrue(os.path.isfile(castep_fname)) test_doc, s = castep2dict(castep_fname, db=True, verbosity=VERBOSITY) try: self.assertTrue( np.allclose(test_doc["lattice_abc"], cart2abc(test_doc["lattice_cart"])), msg="Conversion cart2abc failed.", ) self.assertTrue( np.allclose( cart2abc(test_doc["lattice_cart"]), cart2abc(abc2cart(test_doc["lattice_abc"])), ), msg="Conversion abc2cart failed.", ) self.assertAlmostEqual( test_doc["cell_volume"], cart2volume(test_doc["lattice_cart"]), msg="Failed to calculate volume from lattice vectors.", places=5, ) self.assertIsInstance(test_doc["lattice_abc"], list, msg="Failed abc numpy cast to list") self.assertIsInstance( test_doc["lattice_cart"], list, msg="Failed cartesian numpy cast to list", ) cart_pos = frac2cart(test_doc["lattice_cart"], test_doc["positions_frac"]) back2frac = cart2frac(test_doc["lattice_cart"], cart_pos) np.testing.assert_array_almost_equal(back2frac, test_doc["positions_frac"]) except AssertionError: print("cart:", test_doc["lattice_cart"], abc2cart(test_doc["lattice_abc"])) print("abc:", test_doc["lattice_abc"], cart2abc(test_doc["lattice_cart"])) print( "volume:", test_doc["cell_volume"], cart2volume(test_doc["lattice_cart"]), ) raise AssertionError
def set_position(self, position, units): if len(position) != 3 or not all( isinstance(p, (float, int)) for p in position): raise RuntimeError( 'CrystalSite position has wrong shape: {}'.format(position)) if not hasattr(self, '_coords'): self._coords = dict() if units == 'fractional': self._coords['fractional'] = wrap_frac_coords( [float(pos) for pos in position], remove=False) elif units == 'cartesian': self._coords['fractional'] = wrap_frac_coords(cart2frac( self.lattice, self.coords), remove=False) else: raise RuntimeError( 'Unit system {} not understood, expecting `fractional`/`cartesian`' .format(units))
def relax(self): from ase.optimize import LBFGS cached = sys.__stdout__ try: optimizer = LBFGS(self.ucf) optimizer.logfile = None optimised = optimizer.run(fmax=0.05, steps=100) except Exception: optimised = False self.doc["optimised"] = bool(optimised) self.doc["positions_abs"] = self.atoms.get_positions().tolist() self.doc["lattice_cart"] = self.atoms.get_cell().tolist() self.doc["lattice_abc"] = cart2abc(self.doc["lattice_cart"]) self.doc["positions_frac"] = cart2frac(self.doc["lattice_cart"], self.doc["positions_abs"]) self.doc["enthalpy_per_atom"] = float(self.calc.results["energy"] / len(self.doc["atom_types"])) self.doc["enthalpy"] = float(self.calc.results["energy"]) self.queue.put(self.doc) sys.stdout = cached
def magres2dict(fname, **kwargs): """ Extract available information from .magres file. Assumes units of Angstrom and ppm for relevant quantities. """ magres = defaultdict(list) flines, fname = get_flines_extension_agnostic(fname, "magres") magres['source'] = [fname] # grab file owner username try: from pwd import getpwuid magres['user'] = getpwuid(stat(fname).st_uid).pw_name except Exception: magres['user'] = '******' magres['magres_units'] = dict() for line_no, line in enumerate(flines): line = line.lower().strip() if line in ['<atoms>', '[atoms]']: i = 1 while flines[line_no + i].strip().lower() not in ['</atoms>', '[/atoms]']: split_line = flines[line_no + i].split() if not split_line: i += 1 continue if i > len(flines): raise RuntimeError("Something went wrong in reader loop") if split_line[0] == 'units': magres['magres_units'][split_line[1]] = split_line[2] elif 'lattice' in split_line: lattice = split_line[1:] for j in range(3): magres['lattice_cart'].append([ float(elem) for elem in lattice[j * 3:(j + 1) * 3] ]) magres['lattice_abc'] = cart2abc(magres['lattice_cart']) elif 'atom' in split_line: atom = split_line magres['atom_types'].append(atom[1]) magres['positions_abs'].append( [float(elem) for elem in atom[-3:]]) i += 1 break if "atom_types" in magres: magres['num_atoms'] = len(magres['atom_types']) magres['positions_frac'] = cart2frac(magres['lattice_cart'], magres['positions_abs']) magres['stoichiometry'] = get_stoich(magres['atom_types']) for line_no, line in enumerate(flines): line = line.lower().strip() if line in ['<magres>', '[magres]']: i = 1 while flines[line_no + i].strip().lower() not in ['</magres>', '[/magres]']: split_line = flines[line_no + i].split() if not split_line: i += 1 continue if i > len(flines): raise RuntimeError("Something went wrong in reader loop") if split_line[0] == 'units': magres['magres_units'][split_line[1]] = split_line[2] elif 'sus' in split_line: magres["susceptibility_tensor"] = np.array( [float(val) for val in split_line[1:]]).reshape(3, 3) elif 'ms' in split_line: ms = np.array([float(val) for val in split_line[3:]]).reshape(3, 3) s_iso = np.trace(ms) / 3 # find eigenvalues of symmetric part of shielding and order them to calc anisotropy eta symmetric_shielding = _symmetrise_tensor(ms) s_yy, s_xx, s_zz = _get_haeberlen_eigs(symmetric_shielding) s_aniso = s_zz - (s_xx + s_yy) / 2.0 asymm = (s_yy - s_xx) / (s_zz - s_iso) # convert from reduced anistropy to CSA magres["magnetic_shielding_tensors"].append(ms) magres["chemical_shielding_isos"].append(s_iso) magres["chemical_shift_anisos"].append(s_aniso) magres["chemical_shift_asymmetries"].append(asymm) elif "efg" in split_line: efg = np.array([float(val) for val in split_line[3:]]).reshape(3, 3) species = split_line[1] eigs = _get_haeberlen_eigs(efg) v_zz, eta = eigs[2], (eigs[0] - eigs[1]) / eigs[2] # calculate C_Q in MHz quadrupole_moment = ELECTRIC_QUADRUPOLE_MOMENTS.get( species, 1.0) C_Q = ((ELECTRON_CHARGE * v_zz * quadrupole_moment * EFG_AU_TO_SI * BARN_TO_M2) / (PLANCK_CONSTANT * 1e6)) magres["electric_field_gradient"].append(efg) magres["quadrupolar_couplings"].append(C_Q) magres["quadrupolar_asymmetries"].append(eta) i += 1 for line_no, line in enumerate(flines): line = line.lower().strip() if line in ['<calculation>', '[calculation]']: i = 1 while flines[line_no + i].strip().lower() not in [ '</calculation>', '[/calculation]' ]: if i > len(flines): raise RuntimeError("Something went wrong in reader loop") # space important as it excludes other calc_code_x variables if 'calc_code ' in flines[line_no + i]: magres['calculator'] = flines[line_no + i].split()[1] if 'calc_code_version' in flines[line_no + i]: magres['calculator_version'] = flines[line_no + i].split()[1] i += 1 return dict(magres), True
def magres2dict(fname, **kwargs): """ Extract available information from .magres file. Assumes units of Angstrom and ppm for relevant quantities. """ magres = defaultdict(list) flines, fname = get_flines_extension_agnostic(fname, "magres") magres['source'] = [fname] # grab file owner username try: magres['user'] = getpwuid(stat(fname).st_uid).pw_name except Exception: magres['user'] = '******' magres['magres_units'] = dict() for line_no, line in enumerate(flines): line = line.lower().strip() if line in ['<atoms>', '[atoms]']: i = 1 while flines[line_no + i].strip().lower() not in ['</atoms>', '[/atoms]']: split_line = flines[line_no + i].split() if not split_line: i += 1 continue if i > len(flines): raise RuntimeError("Something went wrong in reader loop") if split_line[0] == 'units': magres['magres_units'][split_line[1]] = split_line[2] elif 'lattice' in flines[line_no + i]: lattice = flines[line_no + i].split()[1:] for j in range(3): magres['lattice_cart'].append([ float(elem) for elem in lattice[j * 3:(j + 1) * 3] ]) magres['lattice_abc'] = cart2abc(magres['lattice_cart']) elif 'atom' in flines[line_no + i]: atom = flines[line_no + i].split() magres['atom_types'].append(atom[1]) magres['positions_abs'].append( [float(elem) for elem in atom[-3:]]) i += 1 break magres['num_atoms'] = len(magres['atom_types']) magres['positions_frac'] = cart2frac(magres['lattice_cart'], magres['positions_abs']) magres['stoichiometry'] = get_stoich(magres['atom_types']) for line_no, line in enumerate(flines): line = line.lower().strip() if line in ['<magres>', '[magres]']: i = 1 while flines[line_no + i].strip().lower() not in ['</magres>', '[/magres]']: split_line = flines[line_no + i].split() if not split_line: i += 1 continue if i > len(flines): raise RuntimeError("Something went wrong in reader loop") if split_line[0] == 'units': magres['magres_units'][split_line[1]] = split_line[2] elif 'sus' in flines[line_no + i]: sus = flines[line_no + i].split()[1:] for j in range(3): magres['susceptibility_tensor'].append( [float(val) for val in sus[3 * j:3 * (j + 1)]]) elif 'ms' in flines[line_no + i]: ms = flines[line_no + i].split()[3:] magres['magnetic_shielding_tensors'].append([]) for j in range(3): magres['magnetic_shielding_tensors'][-1].append( [float(val) for val in ms[3 * j:3 * (j + 1)]]) magres['chemical_shielding_isos'].append(0) magres['chemical_shift_anisos'].append(0) magres['chemical_shift_asymmetries'].append(0) for j in range(3): magres['chemical_shielding_isos'][-1] += magres[ 'magnetic_shielding_tensors'][-1][j][j] / 3 # find eigenvalues of symmetric part of shielding and order them to calc anisotropy eta symmetric_shielding = ( 0.5 * (magres['magnetic_shielding_tensors'][-1] + np.asarray( magres['magnetic_shielding_tensors'][-1]).T)) eig_vals, eig_vecs = np.linalg.eig(symmetric_shielding) eig_vals, eig_vecs = zip( *sorted(zip(eig_vals, eig_vecs), key=lambda eig: abs(eig[0] - magres[ 'chemical_shielding_isos'][-1]))) # Haeberlen convention: |s_zz - s_iso| >= |s_xx - s_iso| >= |s_yy - s_iso| s_yy, s_xx, s_zz = eig_vals s_iso = magres['chemical_shielding_isos'][-1] # convert from reduced anistropy to CSA magres['chemical_shift_anisos'][-1] = s_zz - (s_xx + s_yy) / 2.0 magres['chemical_shift_asymmetries'][-1] = ( s_yy - s_xx) / (s_zz - s_iso) i += 1 for line_no, line in enumerate(flines): line = line.lower().strip() if line in ['<calculation>', '[calculation]']: i = 1 while flines[line_no + i].strip().lower() not in [ '</calculation>', '[/calculation]' ]: if i > len(flines): raise RuntimeError("Something went wrong in reader loop") # space important as it excludes other calc_code_x variables if 'calc_code ' in flines[line_no + i]: magres['calculator'] = flines[line_no + i].split()[1] if 'calc_code_version' in flines[line_no + i]: magres['calculator_version'] = flines[line_no + i].split()[1] i += 1 return magres, True