def CIFopen(self, ciffile=None, cifblkname=None): from CifFile import ReadCif # part of the PycifRW module try: # the following is a trick to avoid that urllib.URLopen.open # used by ReadCif misinterprets the url when a drive:\ is # present (Win) ciffile = ciffile.replace(':', '|') cf = ReadCif(ciffile) except: logging.error('File %s could not be accessed' % ciffile) if cifblkname == None: #Try to guess blockname blocks = list(cf.keys()) if len(blocks) > 1: if len(blocks) == 2 and 'global' in blocks: cifblkname = blocks[abs(blocks.index('global') - 1)] else: logging.error('More than one possible data set:') logging.error( 'The following data block names are in the file:') for block in blocks: logging.error(block) raise Exception else: # Only one available cifblkname = blocks[0] #Extract block try: self.cifblk = cf[cifblkname] except: logging.error('Block - %s - not found in %s' % (blockname, ciffile)) raise IOError return self.cifblk
def CIFopen(self, ciffile=None, cifblkname=None): from CifFile import ReadCif # part of the PycifRW module try: # the following is a trick to avoid that urllib.URLopen.open # used by ReadCif misinterprets the url when a drive:\ is # present (Win) ciffile = ciffile.replace(':','|') cf = ReadCif(ciffile) except: logging.error('File %s could not be accessed' %ciffile) if cifblkname == None: #Try to guess blockname blocks = cf.keys() if len(blocks) > 1: if len(blocks) == 2 and 'global' in blocks: cifblkname = blocks[abs(blocks.index('global') - 1)] else: logging.error('More than one possible data set:') logging.error('The following data block names are in the file:') for block in blocks: logging.error(block) raise Exception else: # Only one available cifblkname = blocks[0] #Extract block try: self.cifblk = cf[cifblkname] except: logging.error('Block - %s - not found in %s' % (blockname, ciffile)) raise IOError return self.cifblk
def test_calculating_xrd_pattern_from_cif_file(self): fcc_cif = ReadCif(get_cif_url('fcc.cif')) cif_phase = CifPhase(fcc_cif[fcc_cif.keys()[0]]) cif_converter = CifConverter(0.31) jcpds_phase = cif_converter.convert_cif_phase_to_jcpds(cif_phase) self.assertAlmostEqual(jcpds_phase.reflections[0].intensity, 100, places=4) self.assertAlmostEqual(jcpds_phase.reflections[0].d0, 2.814, places=4) self.assertAlmostEqual(jcpds_phase.reflections[1].d0, 2.437, places=4)
def import_cif(file_path, occupancy_tolerance=100): """ Import cif with pymatgen. This is the current default. Aruments -------- occupancy_tolerance: int Occupancy tolerance for pymatgen.io.cif.CifParser. Files from the CSD can contain multiple atoms which sit on the same site when PBC are taken into account. Pymatgen correctly recognizes these as the same atom, however, it has a tolerance for the number of atoms which it will assume are the same. This is the occupancy tolerance. I don't believe this value should be limited and thus it's set at 100. """ try: pycif = CifParser(file_path, occupancy_tolerance=occupancy_tolerance) pstruct_list = pycif.get_structures(primitive=False) struct = Structure.from_pymatgen(pstruct_list[0]) except: struct = import_cif_ase(file_path) file_name = os.path.basename(file_path) struct.struct_id = file_name.replace('.cif', '') #### Read in data that may be stored as a CIF property if read_cif_data: ### Wrap in try except in case of PyCIFRW errors try: cif = ReadCif(file_path) except: print("Error in reading CIF data for {}".format(file_path)) return struct if len(cif) > 1: raise Exception("Must only have one structure per CIF file.") cif_struct = [x for x in cif.keys()] cif_data = cif[cif_struct[0]] for key, value in cif_data.items(): ## Skip over geometry information if "_atom_" == key[0:len("_atom_")]: continue elif "_cell_" == key[0:len("_cell_")]: continue elif "_symmetry_equiv" == key[0:len("_symmetry_equiv")]: continue else: pass ## Otherwise add info to structure property information struct.properties[key] = value return struct
def import_cif_file(self): file = self.ui.cif_file.text() if not os.path.isfile(file): return try: cf = ReadCif(file) search_params = { '_cell_length_a': InterplanarSpacing.PARAMETER_A, '_cell_length_b': InterplanarSpacing.PARAMETER_B, '_cell_length_c': InterplanarSpacing.PARAMETER_C, '_cell_angle_alpha': InterplanarSpacing.PARAMETER_ALPHA, '_cell_angle_beta': InterplanarSpacing.PARAMETER_BETA, '_cell_angle_gamma': InterplanarSpacing.PARAMETER_GAMMA, } ui_mapping = self.get_parameter_mapping() import re # find the lattice parameters in the cif file for key, entry in cf.items(): for search_key, search_mapping in search_params.items(): if entry.has_key(search_key): try: number = float(entry[search_key]) except: number = re.findall(r"[-+]?\d*\.\d+|\d+", entry[search_key]) if len(number) == 0: continue number = number[0] ui_mapping[search_mapping].setText(str(number)) self.system.set_parameter(self.get_lattice_parameters()) system_class = self.system.detect_system() # Now set the input text field for the crystal system crystal_family = None for key, crystal_class in self.CLASS_MAPPING.items(): if crystal_class == system_class: crystal_family = key self.set_crystal_family(crystal_family) self.update_view() except BaseException as e: print(e)
def read_reference(cif_file): """ Read a cif file and return a :mod:`~qmpy.Reference`. """ cf = ReadCif(cif_file, grammar='1.1') cif_block = cf[cf.keys()[0]] reference = rx.Reference() reference.authors = _get_authors(cif_block) reference.journal = _get_journal(cif_block) reference.volume = _get_volume(cif_block) reference.year = _get_year(cif_block) reference.first_page = _get_first_page(cif_block) reference.last_page = _get_last_page(cif_block) reference.title = _get_title(cif_block) return reference
def open_cif(param, phase): """ Open a cif file a build a structure for phase number "phase" filename: param['structure_phase_%i' %phase] returns - a structure with cif information sets - param['sgno_phase_%i' %phase] : space group number - param['sgname_phase_%i' %phase] : space group name - param['cell_choice_phase_%i' %phase] : not 100% sure - param['unit_cell_phase_%i' %phase] : unit cell parameters as [a,b,c,alpha,beta,gamma'] Adapted from polyxsim.structure Created: 12/2019, S. Merkel, Univ. Lille, France """ file = param['structure_phase_%i' % phase] cf = ReadCif( file ) # Generate an error if reading cif fails which is not always true below struct = structure.build_atomlist() struct.CIFread(ciffile=file) param['sgno_phase_%i' % phase] = sg.sg(sgname=struct.atomlist.sgname).no param['sgname_phase_%i' % phase] = struct.atomlist.sgname param['cell_choice_phase_%i' % phase] = sg.sg(sgname=struct.atomlist.sgname).cell_choice param['unit_cell_phase_%i' % phase] = struct.atomlist.cell return struct
def convert_cif_to_jcpds(self, filename): """ Reads a cif file and returns a jcpds with correct reflection and intensities :param filename: cif filename :return: converted jcpds object :rtype: jcpds """ file_url = 'file:' + pathname2url(filename) cif_file = ReadCif(file_url) cif_phase = CifPhase(cif_file[cif_file.keys()[0]]) jcpds_phase = self.convert_cif_phase_to_jcpds(cif_phase) jcpds_phase.filename = filename jcpds_phase.name = os.path.splitext(os.path.basename(filename))[0] jcpds_phase.modified = False return jcpds_phase
def convert_cif_to_jcpds(self, filename): """ Reads a cif file and returns a jcpds with correct reflection and intensities :param filename: cif filename :return: converted jcpds object :rtype: jcpds """ file_url = 'file:' + urllib.pathname2url(filename) cif_file = ReadCif(file_url) cif_phase = CifPhase(cif_file[cif_file.keys()[0]]) jcpds_phase = self.convert_cif_phase_to_jcpds(cif_phase) jcpds_phase.filename = filename jcpds_phase.name = os.path.splitext(os.path.basename(filename))[0] jcpds_phase.modified = False return jcpds_phase
def test_reading_phase(self): fcc_cif = ReadCif(get_cif_url('fcc.cif')) cif_phase = CifPhase(fcc_cif[fcc_cif.keys()[0]]) self.assertEqual(cif_phase.a, 4.874) self.assertEqual(cif_phase.b, 4.874) self.assertEqual(cif_phase.c, 4.874) self.assertEqual(cif_phase.alpha, 90) self.assertEqual(cif_phase.beta, 90) self.assertEqual(cif_phase.gamma, 90) self.assertEqual(cif_phase.volume, 115.79) self.assertEqual(cif_phase.space_group_number, 225) self.assertEqual(len(cif_phase.atoms), 8) self.assertEqual(cif_phase.comments, 'HoN, Fm-3m - NaCl structure type, ICSD 44776')
def main(name): mof = ReadCif(name) mof = mof[mof.visible_keys[0]] elements = mof["_atom_site_type_symbol"] n_atoms = len(elements) prop_dict = {} for a1, a2 in combinations_with_replacement(set(elements), 2): prop_arr = [prop[a1] * prop[a2] for prop in prop_list] prop_dict[(a1, a2)] = prop_arr if a1 != a2: prop_dict[(a2, a1)] = prop_arr la = float(mof["_cell_length_a"]) lb = float(mof["_cell_length_b"]) lc = float(mof["_cell_length_c"]) aa = np.deg2rad(float(mof["_cell_angle_alpha"])) ab = np.deg2rad(float(mof["_cell_angle_beta"])) ag = np.deg2rad(float(mof["_cell_angle_gamma"])) # If volume is missing from .cif, calculate it. try: cv = float(mof["_cell_volume"]) except KeyError: cv = la * lb * lc * math.sqrt(1 - (math.cos(aa))**2 - (math.cos(ab))**2 - (math.cos(ag))**2 + (2 * math.cos(aa) * math.cos(ab) * math.cos(ag))) frac2cart = np.zeros([3, 3], dtype=float) frac2cart[0, 0] = la frac2cart[0, 1] = lb * np.cos(ag) frac2cart[0, 2] = lc * np.cos(ab) frac2cart[1, 1] = lb * np.sin(ag) frac2cart[1, 2] = lc * (np.cos(aa) - np.cos(ab) * np.cos(ag)) / np.sin(ag) frac2cart[2, 2] = cv / (la * lb * np.sin(ag)) frac = np.array([ mof["_atom_site_fract_x"], mof["_atom_site_fract_y"], mof["_atom_site_fract_z"], ], dtype=float).T apw_rdf = np.zeros([n_props, n_bins], dtype=np.float64) for i, j in combinations(range(n_atoms), 2): cart_i = frac2cart @ frac[i] cart_j = (frac2cart @ (super_cell + frac[j]).T).T dist_ij = min(np.linalg.norm(cart_j - cart_i, axis=1)) rdf = np.exp(smooth * (bins - dist_ij)**2) rdf = rdf.repeat(n_props).reshape(n_bins, n_props) apw_rdf += (rdf * prop_dict[(elements[i], elements[j])]).T apw_rdf = np.round(apw_rdf.flatten() * factor / n_atoms, decimals=12) return ("{}," * len(apw_rdf) + "{}\n").format( name.split('/')[-1], *apw_rdf.tolist())
def read_structure(path_to_file): cwd = os.getcwd() try: os.chdir(os.path.dirname(path_to_file)) file_name = os.path.split(path_to_file)[-1] cif_data = ReadCif(file_name) os.chdir(cwd) except: os.chdir(cwd) raise ValueError("The reading or parsing of the " + file_name + " is failed!") try: name, data = list(cif_data.items())[0] structure_data = StructureData(name, data) structure = Structure().build_structure(structure_data) structure.reamove_connectivity() return structure except: print("Reading structure is failed!")
def read_structures(path_to_file): cwd = os.getcwd() try: os.chdir(os.path.dirname(path_to_file)) file_name = os.path.split(path_to_file)[-1] cif_data = ReadCif(file_name) os.chdir(cwd) except: os.chdir(cwd) raise ValueError("The reading or parsing of the " + file_name + " is failed!") for i, (name, data) in enumerate(cif_data.items()): try: structure_data = StructureData(name, data) structure = Structure().build_structure(structure_data) structure.reamove_connectivity() yield structure except: os.chdir(cwd) print("Reading " + str(i) + " structure is failed!")
def _loadFromCif(self): from CifFile import ReadCif cifFileUrl = self._getFileUrl() workspace = self.getProperty('Workspace').value # Try to parse cif file using PyCifRW parsedCifFile = ReadCif(cifFileUrl) self._setCrystalStructureFromCifFile(workspace, parsedCifFile) ubOption = self.getProperty('LoadUBMatrix').value if ubOption: self._setUBMatrixFromCifFile(workspace, parsedCifFile)
def read(cif_file, grammar=None): """ Takes a CIF format file, and returns a Structure object. Applies all symmetry operations in the CIF to the atoms supplied with the structure. If these are not correct, the structure will not be either. If the CIF contains more than one file, the return will be a list. If not, the return will be a single structure (not in a len-1 list). Examples:: >>> s = io.cif.read(INSTALL_PATH+'io/files/fe3o4.cif') """ if grammar: cf = ReadCif(cif_file, grammar=grammar) else: cf = ReadCif(cif_file) structures = [] for key in cf.keys(): structures.append(_read_cif_block(cf[key])) if len(structures) == 1: return structures[0] else: return structures
def test_sfcalc(self): ## test method names begin 'test*' # Read the cif mylist = structure.build_atomlist() mylist.CIFread('PPA.cif','oPPA') # Read the fcf fcf = ReadCif('oPPA.fcf')['oPPA'] for i in range(500):# Consider only the first 500 reflections hkl =[eval(fcf['_refln_index_h'][i]), eval(fcf['_refln_index_k'][i]), eval(fcf['_refln_index_l'][i])] (Fr, Fi) = structure.StructureFactor(hkl, mylist.atomlist.cell, mylist.atomlist.sgname, mylist.atomlist.atom, mylist.atomlist.dispersion) F2 = Fr**2 + Fi**2 reldif = F2/eval(fcf['_refln_F_squared_calc'][i])-1 print(i, reldif, F2) if F2 > 10: # Only compare those with an F^2 larger than ten # to avoid that the very weak reflections which # have a relative difference that are slightly larger self.assertAlmostEqual(reldif,0,2)
def star_reader(filename): """ star_reader: reads a star file and returns a dictionary """ key='data_' new_key='data_metadata' new_starfile='.tmp.star' # with open(filename) as f1: with open(new_starfile, 'w') as f2: lines = f1.readlines() for line in lines: if(line.startswith(key)): f2.write(new_key) else: f2.write(line) data = ReadCif(new_starfile, grammar='STAR2') os.remove(new_starfile) print('Number of particles in this star file: {}'.format(len(data['metadata'][data['metadata'].keys()[0]]))) print("The entries in the returned dictionary are:") print("data['metadata'].keys(): {}".format(data['metadata'].keys())) return data
class CIFParser(AbstractStructureParser): """ Collection of methods that parses CIF files based on cif2cell. The preferred method of using this object is as a context manager. Parameters ---------- filename : str or path-like Location of the CIF file. """ def __init__(self, filename, **kwargs): # ReadCIF would get confused between local files and URLs # Therefore, more clear to pass an open file self._handle = open(filename, mode="r") self.file = ReadCif(self._handle, **kwargs) def __exit__(self, *args, **kwargs): self._handle.close() @property def filename(self): return self._handle.name @staticmethod def sym_ops_from_equiv(equiv_site): """ Parse a symmetry operator from an equivalent-site representation Parameters ---------- equiv_site : str or iterable of strings Either comma-separated string e.g. "+y, +x, -z + 1/2" or an iterable of the comma-separated values, e.g. ["+y", "+x", "-z + 1/2"] Returns ------- sym_ops : ndarray, shape (4,4) Symmetry operator as a 4x4 affine transformation on the FRACTIONAL coordinates. """ symmetry = np.zeros((3, 3)) translation = np.zeros((3, )) if isinstance(equiv_site, str): equiv_site = equiv_site.split(",") equiv_site = tuple(map(lambda s: s.strip().lower(), equiv_site)) for j in range(3): xyz = equiv_site[j].replace("+", " +").replace("-", " -").split() for i in xyz: if i.strip("+-") == "x": symmetry[0, j] = float(i.strip("x") + "1") elif i.strip("+-") == "y": symmetry[1, j] = float(i.strip("y") + "1") elif i.strip("+-") == "z": symmetry[2, j] = float(i.strip("z") + "1") if i.strip("+-xyz") != "": translation[j] = eval(i) symmetry[:] = np.transpose(symmetry) # Combination of transform and translation into a single matrix # is done in a 4x4 affine transform symmetry_operation = affine_map(symmetry) symmetry_operation[:3, 3] = translation return symmetry_operation @property def structure_block(self): """ Retrieve which CIF block has the appropriate structural information """ blocks = (self.file[key] for key in self.file.keys()) for block in blocks: try: _, _ = get_number_with_esd(block["_cell_length_a"]) except KeyError: continue else: return block @lru_cache(maxsize=1) def hall_symbol(self): """ Returns the Hall symbol """ block = self.structure_block hall_symbol = block.get("_symmetry_space_group_name_Hall" ) or block.get("_space_group_name_Hall") # In some rare cases, the given hall symbol in the file isn't standard, # otherwise it would be a key in SymOpsHall # Then, it is preferable to infer the conventional hall symbol from other info if (hall_symbol is None) or (hall_symbol not in SymOpsHall): h_m_symbol = block.get("_symmetry_space_group_name_H-M" ) or block.get("_space_group_name_H-M_alt") if h_m_symbol is not None: h_m_symbol = re.sub(r"\s+", "", h_m_symbol) with suppress( KeyError ): # Symbol could be meaningless, e.g. h_m_symbol = '?' (True story) hall_symbol = HM2Hall[h_m_symbol] # Again, if hall_symbol is still missing OR invalid if (hall_symbol is None) or (hall_symbol not in SymOpsHall): table_number = block.get("_symmetry_Int_Tables_number" ) or block.get("_space_group_IT_number") if table_number is not None: hall_symbol = Number2Hall[int(table_number)] if hall_symbol is None: raise ParseError("Hall symbol could not be inferred") if hall_symbol[0] == "-": hall_symbol = "-" + hall_symbol[1].upper() + hall_symbol[2:].lower( ) else: hall_symbol = hall_symbol[0].upper() + hall_symbol[1:].lower() return hall_symbol @lru_cache(maxsize=1) def lattice_parameters(self): """ Returns the lattice parameters associated to a CIF structure. Returns ---------- a, b, c : float Lengths of lattice vectors [Angstroms] alpha, beta, gamma : float Angles of lattice vectors [degrees]. """ block = self.structure_block try: a_with_err = block["_cell_length_a"] except KeyError: raise ParseError( f"No lattice information is present in {self.filename}") # In case where b and c are not listed, we use the value of a a, _ = get_number_with_esd(a_with_err) b, _ = get_number_with_esd(block.get("_cell_length_b", a_with_err)) c, _ = get_number_with_esd(block.get("_cell_length_c", a_with_err)) alpha, _ = get_number_with_esd(block["_cell_angle_alpha"]) beta, _ = get_number_with_esd(block["_cell_angle_beta"]) gamma, _ = get_number_with_esd(block["_cell_angle_gamma"]) return a, b, c, alpha, beta, gamma @lru_cache(maxsize=1) def lattice_vectors(self): """ Returns the lattice vectors associated to a CIF structure. Returns ------- lv : list of ndarrays, shape (3,) """ return Lattice.from_parameters( *self.lattice_parameters()).lattice_vectors def symmetry_operators(self): """ Returns the symmetry operators that map the fractional atomic positions in a CIF file to the crystal *conventional* unit cell. Returns ------- sym_ops : iterable of ndarray, shape (4,4) Transformation matrices. Since translations and rotation are combined, the transformation matrices are 4x4. """ block = self.structure_block equivalent_sites_str = None for tag in [ "_symmetry_equiv_pos_as_xyz", "_space_group_symop_operation_xyz" ]: with suppress(KeyError): equivalent_sites_str = block.GetLoop(tag).get(tag) # P1 space group only has a single equivalent site if isinstance(equivalent_sites_str, str): equivalent_sites_str = [equivalent_sites_str] with suppress(ParseError): if not equivalent_sites_str: equivalent_sites_str = SymOpsHall[self.hall_symbol()] elif len(equivalent_sites_str) != len( SymOpsHall[self.hall_symbol()]): warnings.warn( "The number of equivalent sites is not in line with the database. The file might be incomplete" ) return list(map(self.sym_ops_from_equiv, equivalent_sites_str)) def atoms(self): """ Asymmetric unit cell. Combine with CIFParser.symmetry_operators() for a full unit cell. Returns ------- atoms : iterable of Atom instance """ block = self.structure_block try: tmpdata = block.GetLoop("_atom_site_fract_x") cartesian = False except: try: tmpdata = block.GetLoop("_atom_site_Cartn_x") cartesian = True except: raise ParseError( "Atomic positions could not be found or inferred.") t11 = block.get("_atom_sites_Cartn_tran_matrix_11") t12 = block.get("_atom_sites_Cartn_tran_matrix_12") t13 = block.get("_atom_sites_Cartn_tran_matrix_13") t21 = block.get("_atom_sites_Cartn_tran_matrix_21") t22 = block.get("_atom_sites_Cartn_tran_matrix_22") t23 = block.get("_atom_sites_Cartn_tran_matrix_23") t31 = block.get("_atom_sites_Cartn_tran_matrix_13") t32 = block.get("_atom_sites_Cartn_tran_matrix_23") t33 = block.get("_atom_sites_Cartn_tran_matrix_33") cart_trans_matrix_inv = np.array([ [float(t11), float(t12), float(t13)], [float(t21), float(t22), float(t23)], [float(t31), float(t32), float(t33)], ]) cart_trans_matrix = inv(cart_trans_matrix_inv) if not all([t11, t12, t13, t21, t22, t23, t31, t32, t33]): raise ParseError( "Cartesian coordinates in CIF but no transformation matrix given" ) if cartesian: xs = tmpdata.get("_atom_site_Cartn_x") ys = tmpdata.get("_atom_site_Cartn_y") zs = tmpdata.get("_atom_site_Cartn_z") else: xs = tmpdata.get("_atom_site_fract_x") ys = tmpdata.get("_atom_site_fract_y") zs = tmpdata.get("_atom_site_fract_z") # TODO: handle wildcards like '?', '.' in xs, ys, zs elements = tmpdata.get("_atom_site_type_symbol") if not elements: elements = tmpdata.get("_atom_site_label") if not elements: raise ParseError( "Atom symbols could not be found or inferred.") elements = map(lambda s: s.strip(punctuation + digits).title(), elements) atoms = list() for e, x, y, z in zip(elements, xs, ys, zs): coords = np.array([ get_number_with_esd(x)[0], get_number_with_esd(y)[0], get_number_with_esd(z)[0], ]) # We normalize atom position to be within the unit cell # Therefore we need the fractional coordinates if cartesian: coords = transform(cart_trans_matrix, coords) coords[:] = frac_coords(coords, self.lattice_vectors()) atoms.append(Atom(element=e, coords=np.mod(coords, 1))) return atoms
'_cell_length_c', '_cell_angle_alpha', '_cell_angle_beta', '_cell_angle_gamma', '_cell_volume', '_exptl_crystal_density_diffrn', '_symmetry_space_group_name_h-m' ] for i, row in dfMin.iterrows(): cifFolder = os.path.join(base, row.MineralName) if os.path.exists( cifFolder): #row.mineralName not in ['Angelaite','Arsenopyrite']: for cifFile in [ f for f in os.listdir(cifFolder) if f.endswith(".cif") ]: try: cf = ReadCif(os.path.join(cifFolder, cifFile)) # '_atom_site_label','_atom_site_fract_x','_atom_site_fract_y','_atom_site_fract_z','_atom_site_occupancy','_atom_site_u_iso_or_equiv']) cifDic = {key: cf['global'][key] for key in cifKeys} cifDic['Temperature'] = 'False' cifDic['Pressure'] = 'False' #remove new line from '_publ_section_title' cifDic['_publ_section_title'] = cifDic[ '_publ_section_title'].replace("\n", " ").replace('\r', " ").strip() # print(cifDic) #with multiplicity if '_atom_site_occupancy' in cf[ 'global']: #keep if it doesnt have multiple occupancies
#! ./venv/bin/python from CifFile import ReadCif import sys # I couldn't find a good way to read CIFs in ruby so we have to call this python script # pip install PyCifRW cf = ReadCif(sys.argv[1]) atoms = cf[cf.visible_keys[0]]["_atom_site_label"] j = 0 while j < len(atoms): atoms[j] = ''.join([i for i in atoms[j] if not i.isdigit()]) j = j + 1 atoms_no_dupes = [] for x in atoms: if x == "C1": y = 2 if x not in atoms_no_dupes: atoms_no_dupes.append(x) print(atoms_no_dupes)
from CifFile import ReadCif import os from shutil import copy d = '/home/kenneth/proj/proXtal/amcsd/cif/mineral/' for f in os.listdir(d): cf = ReadCif(d + f) labels = cf['global']['_atom_site_label'] subs = "Fe" if len(list(filter(lambda x: subs in x, labels))) > 0: copy(f, d + 'Fe/')
if __name__ == '__main__': parser = argparse.ArgumentParser( prog='susViewer', description= 'Convert chi-tensor to appropriate coordinate system for visualization in standard molecular viewers' ) parser.add_argument('cifname') parser.add_argument('-b', '--blockname') parser.add_argument('-s', '--scale') parser.add_argument('-r', '--repr') _cmd_line_args = parser.parse_args() _cifname = _cmd_line_args.cifname cf = ReadCif(_cifname) _blockname = _cmd_line_args.blockname _type = _cmd_line_args.repr _scale = _cmd_line_args.scale structure = cc.crystalStructure(_cifname, blockname=_blockname) if _scale is None: _scale = 1 else: _scale = float(_scale) # The following is not obsolete. It is used to find the right block, as not everything can be # done using the structure as loaded from the CIF. if _blockname is None: _blockname = structure.block if _type is None:
#------------------------------------------------------------------------------- # Name: module1 # Purpose: # # Author: Andrezio # # Created: 23/07/2017 # Copyright: (c) Andrezio 2017 # Licence: <your licence> #------------------------------------------------------------------------------- from CifFile import ReadCif <<<<<<< HEAD cf = ReadCif('UO2_STAR_246851.cif') lambida=1.54 ======= cf = ReadCif('u308.cif') >>>>>>> f26a11b75e998002824160efa1c337672e8cb21b chave = cf.keys() ##for k,v in cf[chave[0]].items(): ## print k <<<<<<< HEAD value= cf[chave[0]]['_cell_length_a'] value=value.split('(')[0] =======
def read(self): """ Read data from the CIF file """ with open(self.filename, 'r') as f: ciffile = ReadCif(f) for block in ciffile: spacegroup = Spacegroup(int(block['_space_group_IT_number'])) cellpar = np.array([ block['_cell_length_a'], block['_cell_length_b'], block['_cell_length_c'], block['_cell_angle_alpha'], block['_cell_angle_beta'], block['_cell_angle_gamma'], ], dtype=float) try: site_labels = block['_atom_site_label'] except KeyError: print('Could not get site labels from cif file') try: occupancies = np.array(block['_atom_site_occupancy'], dtype=float) except KeyError: print('Could not get occupancies from cif file') try: fract_x = np.array(block['_atom_site_fract_x'], dtype=float) fract_y = np.array(block['_atom_site_fract_y'], dtype=float) fract_z = np.array(block['_atom_site_fract_z'], dtype=float) except KeyError: warn( 'Could not get fractional coordinates from cif file, getting absolute coordinates instead.' ) try: x = np.array(block['_atom_site_cartn_x'], dtype=float) y = np.array(block['_atom_site_cartn_y'], dtype=float) z = np.array(block['_atom_site_cartn_z'], dtype=float) except KeyError: warn( 'Could not get absolute coordinates from cif file') x = [np.nan] * len(block) y = [np.nan] * len(block) z = [np.nan] * len(block) finally: fract_x = x / cellpar[0] fract_y = y / cellpar[1] fract_z = z / cellpar[2] else: x = fract_x * cellpar[0] y = fract_y * cellpar[1] z = fract_y * cellpar[2] finally: x = x.T y = y.T z = z.T fract_x = fract_x.T fract_y = fract_y.T fract_z = fract_z.T positions = np.array([x, y, z]) fractional_positions = np.array( [fract_x, fract_y, fract_z]) try: symbols = block['_atom_site_type_symbol'] except KeyError: print( 'Could not get atom site chemical symbols from cif file' ) try: dwf = block['_atom_site_B_iso_or_equiv'] except KeyError: print('Could not get Debye-Waller factors from cif file') basis_atoms = [] for label, occ, fx, fy, fz, symbol, B in zip( site_labels, occupancies, fractional_positions[0], fractional_positions[1], fractional_positions[2], symbols, dwf): atom = CIFAtom(cellpar, symbol=symbol, occupancy=occ, fractional_position=(fx, fy, fz), dwf=B, site_label=label) basis_atoms.append(atom) atoms = [] for atom in basis_atoms: equivalent_sites, kinds = spacegroup.equivalent_sites( atom.fractional_position, onduplicates='warn', occupancies=atom.occupancy) for site in equivalent_sites: position = site * cellpar[:3] equivalent_atom = CIFAtom(cellpar, fractional_position=site, site_label=atom.site_label, symbol=atom.symbol, dwf=atom.dwf, occupancy=atom.occupancy) atoms.append(equivalent_atom) self.atoms = atoms self.crystal = Crystal(atoms, cellpar)
# ASE functions from ase.io import read as read_cif elif package == 'pymatgen': # Pymatgen functions from pymatgen import Structure read_cif = Structure.from_file elif package == 'pycifrw': # PyCifRW from CifFile import ReadCif as read_cif elif package == 'pycifrw-fast': # PyCifRW from CifFile import ReadCif read_cif = lambda x: ReadCif(x, scantype="flex") elif package == 'pycodcif': # pycodcif from pycodcif import parse def get_content(file): datablocks, error_count, error_messages = parse(file) return datablocks read_cif = get_content extension = '.cif' directory = 'structures_0108' paths = glob.glob("{}/*{}".format(directory, extension))
''' Created on Mar 17, 2018 @author: Mammon ''' from CifFile import ReadCif cf = ReadCif("molecule.cif") my_data = cf.first_block() #print(my_data) print(my_data) columns = [ "_atom_site_label", "_atom_site_type_symbol", "_atom_site_fract_x", "_atom_site_fract_y", "_atom_site_fract_z" ] #store the loop inside excel from openpyxl import Workbook wb = Workbook() #get current active sheet ws = wb.active #change title of the sheet ws.title = "Sonification" #change the background color of the tab hoding this title ws.sheet_properties.tabColor = "1072BA" for i in range(1, 6): ws.cell(row=1, column=i, value=columns[i - 1])
def __init__(self, filename, **kwargs): # ReadCIF would get confused between local files and URLs # Therefore, more clear to pass an open file self._handle = open(filename, mode="r") self.file = ReadCif(self._handle, **kwargs)
def finalise_parameters(self, file_name, index, current_temp): #Finalises the CIF with important parameters such as beamline parameters cif = ReadCif(file_name) try: data_block = cif[str(index + 1)] except TypeError as error: os.remove(file_name) self.logger.info(f'Cif empty due to poor refinement - {error}') else: self.C = data_block['_diffrn_reflns_number'] self.A = data_block['_diffrn_reflns_theta_min'] self.B = data_block['_diffrn_reflns_theta_max'] beamline = self.cfg['User_Parameters_Full_Pipeline'][ 'Experiment_Configuration']['beamline'] if beamline != '': data_block['_computing_data_collection'] = self.cfg[ 'Instrument_Parameters'][beamline + '_data_collection'] data_block['_exptl_absorp_correction_type'] = self.cfg[ 'Instrument_Parameters'][beamline + '_absorp_correction'] data_block['_diffrn_radiation_wavelength'] = self.cfg[ 'User_Parameters_Full_Pipeline'][ 'Experiment_Configuration']['wavelength'] data_block['_diffrn_radiation_type'] = self.cfg[ 'Instrument_Parameters'][beamline + '_radiation_type'] data_block['_diffrn_source'] = self.cfg[ 'Instrument_Parameters'][beamline + '_radiation_type'] data_block['_diffrn_measurement_device_type'] = self.cfg[ 'Instrument_Parameters'][beamline + '_detector'] data_block['_diffrn_measurement_method'] = self.cfg[ 'Instrument_Parameters'][beamline + '_measurement_method'] data_block['_computing_cell_refinement'] = self.cfg[ 'Instrument_Parameters'][beamline + '_cell_refinement'] data_block['_computing_data_reduction'] = self.cfg[ 'Instrument_Parameters'][beamline + '_cell_refinement'] data_block['_computing_structure_solution'] = self.cfg[ 'Instrument_Parameters'][beamline + '_structure_soln'] data_block['_diffrn_radiation_monochromator'] = self.cfg[ 'Instrument_Parameters'][beamline + '_monochromator'] data_block['_diffrn_radiation_source'] = self.cfg[ 'Instrument_Parameters'][beamline + '_source'] data_block['_chemical_formula_moiety'] = self.cfg[ 'User_Parameters_Full_Pipeline']['Crystal_Descriptions'][ 'chemical_formula'] data_block['_exptl_crystal_colour'] = self.cfg[ 'User_Parameters_Full_Pipeline']['Crystal_Descriptions'][ 'crystal_colour'] data_block['_exptl_crystal_description'] = self.cfg[ 'User_Parameters_Full_Pipeline']['Crystal_Descriptions'][ 'crystal_habit'] data_block['_cell_measurement_temperature'] = current_temp data_block['_diffrn_ambient_temperature'] = current_temp data_block['_exptl_crystal_size_max'] = self.cfg[ 'User_Parameters_Full_Pipeline']['Crystal_Descriptions'][ 'max_crystal_dimension'] data_block['_exptl_crystal_size_mid'] = self.cfg[ 'User_Parameters_Full_Pipeline']['Crystal_Descriptions'][ 'middle_crystal_dimension'] data_block['_exptl_crystal_size_min'] = self.cfg[ 'User_Parameters_Full_Pipeline']['Crystal_Descriptions'][ 'min_crystal_dimension'] data_block['_cell_measurement_reflns_used'] = self.C data_block['_cell_measurement_theta_min'] = self.A data_block['_cell_measurement_theta_max'] = self.B with open('edited.cif', 'w') as updated: updated.write(cif.WriteOut()) os.rename('edited.cif', file_name)
def data_harvest(self, cif_file): #Resets the dataframes/dictionaries for item in self.search_items: self.results[item] = [] self.errors[item] = [] self.temp_df = pd.DataFrame() self.bond_df = pd.DataFrame() self.angle_df = pd.DataFrame() self.torsion_df = pd.DataFrame() #This notation is from the CifFile module and allows for easy searching of parameters cif = ReadCif(cif_file) #Identifies datablocks within the CIF file self.data_blocks = [] with open(cif_file, 'rt') as f: for line in f: if line.startswith('data_'): self.data_blocks.append(line.strip('\n').strip('data_')) number_of_structures = len(self.data_blocks) #For each search item in the config file, the cif file is searched for item in self.search_items: self.logger.info('File ' + pathlib.Path(cif_file.lower()).stem + ' opened. Searching for parameter ' + item) #This parameter is blanked every loop because each cif is searched multiple times self.cif_list = [] #Since the CifFile module works by looking at data-blocks, use the found list of data blocks to search through the CIF for experiment in self.data_blocks: try: raw = cif[experiment][item] except: self.logger.critical('Failed to find ' + item + ' in ' + pathlib.Path(cif_file.lower()).stem) exit() self.logger.info('File ' + pathlib.Path(cif_file.lower()).stem + ' - found parameter ' + item) self.cif_list.append(pathlib.Path(cif_file.lower()).stem) #Check if an error value is present and separates the value and the error, converts the error to the correct decimal point, and assigns an error of 0 if no error present if type(raw) != list: self.parameter_tidy(raw, item) else: for param in raw: self.parameter_tidy(param, item) #Creates a column in the data frame to include the file name of the CIF self.temp_df['CIF File'] = self.cif_list #Adds all of the data to one data frame bond_paras = [ '_geom_bond_atom_site_label_1', '_geom_bond_atom_site_label_2', '_geom_bond_distance' ] angle_paras = [ '_geom_angle_atom_site_label_1', '_geom_angle_atom_site_label_2', '_geom_angle_atom_site_label_3', '_geom_angle' ] torsion_paras = [ '_geom_torsion_atom_site_label_1', '_geom_torsion_atom_site_label_2', '_geom_torsion_atom_site_label_3', '_geom_torsion_atom_site_label_4', '_geom_torsion' ] for para in self.search_items: if len(self.results[para]) == len(self.cif_list): self.temp_df[para] = self.results[para] self.temp_df[para + '_error'] = self.errors[para] elif len(self.results[para]) != 0 and para in bond_paras: self.bond_df[para] = self.results[para] self.bond_df[para + '_error'] = self.errors[para] elif len(self.results[para]) != 0 and para in angle_paras: self.angle_df[para] = self.results[para] self.angle_df[para + '_error'] = self.errors[para] elif len(self.results[para]) != 0 and para in torsion_paras: self.torsion_df[para] = self.results[para] self.torsion_df[para + '_error'] = self.errors[para] try: self.bond_df['Cif File'], self.bond_df[ 'Data Block'] = self.generate_cif_list(self.bond_df) except: pass try: self.angle_df['Cif File'], self.angle_df[ 'Data Block'] = self.generate_cif_list(self.angle_df) except: pass try: self.torsion_df['Cif File'], self.torsion_df[ 'Data Block'] = self.generate_cif_list(self.torsion_df) except: pass return self.temp_df, number_of_structures, self.data_blocks, self.bond_df, self.angle_df, self.torsion_df
def run(config, input, output): dir = config['xcDir'] # Copy cif2cell related input to cif2cellInput here. Later we will be overriding some settings, # so we want to keep the original input intact. cif2cellInput = { key: input[key] for key in input if key.startswith('cif2cell.') } # Generate any data that is needed from generic input and populate cif2cellInput with # global data (needed for all feff runs.) cif2cellInput['cif2cell.cif_input'] = input['cif_input'] # Set executable directory for this exchange cif2celldir = config['cif2cell'] # Set input file - cif2cell takes input from command line, so no input file, however, maybe we can take commands from input file? #inpf = os.path.join(dir, 'cif2cell.in') # Loop over targets in output. Not sure if there will ever be more than one output target here. if set(output.keys()).issubset( set([ 'cell_vectors', 'cell_struct_xyz_red', 'cell_scaling_iso', 'cell_scaling_abc', 'number_density', 'supercell' ])): # Set output and error files with open(os.path.join(dir, 'corvus.CIF2CELL.stdout'), 'wb') as out, open( os.path.join(dir, 'corvus.CIF2CELL.stderr'), 'wb') as err: # Copy necessary files to dir cif_file = cif2cellInput['cif2cell.cif_input'][0][0] shutil.copy(cif_file, dir) # Loop over executables: This is specific to feff. Other codes # will more likely have only one executable. executables = ['cif2cell'] args = [cif_file, '-p', 'cif', '-o', 'out.cif'] iExec = 0 for executable in executables: runExecutable(cif2celldir, dir, executable, args, out, err) # For now, I am only passing the directory. print('Setting output') outCif = os.path.join(dir, 'out.cif') cifFile = ReadCif(outCif) # cifFile now contains an object that acts like a dictionary # of dictionaries, with the outer keys the data for each # structure listed in the cif, next the normal cif data, like # '_cell_angle_alpha', and '_atom_site_fract_[xyz]'. # Note that as indicated above, the cif can hold multiple # structures. For now I will assume that there is only one. cif_dict = cifFile[list(cifFile.keys())[0]] # Now lets make all of the data structures that we want out of # this. We are using the CellData structure from cif2cell's # uctools package. Right now, I have cif2cell write another # cif file first, then we read it in and analyze it. This is # because we don't want to reproduce all of the sanity check # that cif2cell already has in it. cell_data = CellData() # Fill the cell data object from the cif file. cell_data.getFromCIF(cif_dict) # Calculate cell structure for the primitive cell for now. Supercells are # represented as P1, so this will not harm that. cell_data.primitive() # The cell_data structure now has all cell data that we need # in it, or a method to get that data. if 'cell_vectors' in output: output['cell_vectors'] = cell_data.latticevectors if 'cell_struct_xyz_red' in output: xred = [] for atom in cell_data.atomdata: if atom: xred = xred + [atom[0].position] output['cell_struct_xyz_red'] = xred if 'cell_scaling_iso' in output: output['cell_scaling_iso'] = [[cell_data.lengthscale]] if 'cell_scaling_abc' in output: # For now I will output cell_data_abc as 1, since cif2cell seems to put things into lengthscale # and a,b,c are for convenience. output['cell_scaling_abc'] = [[1.0, 1.0, 1.0]] elif 'cell_structure' in output: # Return path to cif file. output['cell_structure'] = [['Working']]
def read_cif(filename: str_PathLike, pps: muti_Dict = [{}], orbitals: muti_Dict = [{}], masses: muti_Dict = [{}], magmoms: muti_Dict = [{}], move: muti_Dict = [{}], abfs: muti_Dict = [{}]) -> List[Stru]: """Read CIF(Crystallographic Information Framework) file and return `Stru` object :params filename: name of cif file """ raise UserWarning("Can only read direct positions, generating equivalent atoms based on site symmetry or Wackoff positions are not supported now") from CifFile import ReadCif strulist = [] def list_elem2split(l): def list_split(s): return s.split('(')[0] return list(map(list_split, l)) def get_elements(string): return re.search(r'([A-Z][a-z]?)', string).group(0) cf = ReadCif(filename) for index, name in enumerate(cf.keys()): data = cf[name] fract_x = list_elem2split(data["_atom_site_fract_x"]) fract_y = list_elem2split(data["_atom_site_fract_y"]) fract_z = list_elem2split(data["_atom_site_fract_z"]) if "_atom_site_type_symbol" in data.keys(): elements = list(map(get_elements, data["_atom_site_type_symbol"])) else: elements = list(map(get_elements, data["_atom_site_label"])) scaled_positions = defaultdict(list) for i, elem in enumerate(elements): scaled_positions[elem].append([np.array(fract_x[i], dtype=float), np.array( fract_y[i], dtype=float), np.array(fract_z[i], dtype=float)]) la = float(data["_cell_length_a"].split('(')[0]) lb = float(data["_cell_length_b"].split('(')[0]) lc = float(data["_cell_length_c"].split('(')[0]) alpha = float(data["_cell_angle_alpha"].split('(')[0]) beta = float(data["_cell_angle_beta"].split('(')[0]) gamma = float(data["_cell_angle_gamma"].split('(')[0]) if "_symmetry_cell_setting" in data.keys(): crystal_system = data["_symmetry_cell_setting"] elif "_symmetry_Int_Tables_number" in data.keys(): crystal_system = Spacegroup().get_crystal_system( data["_symmetry_Int_Tables_number"]) elif "_space_group_name_Hall" in data.keys(): crystal_system = Spacegroup().get_crystal_system( Hall2Number[data["_space_group_name_Hall"]]) elif "_symmetry_space_group_name_H-M" in data.keys(): crystal_system = Spacegroup().get_crystal_system( Hall2Number[HM2Hall[data["_symmetry_space_group_name_H-M "]]]) else: crystal_system = 'unknown' cell = conventional_cell( la, lb, lc, alpha, beta, gamma, crystal_system) strulist.append(Stru(lat0=1/BOHR_TO_A, cell=cell, pps=pps[index], scaled_positions=scaled_positions, orbitals=orbitals[index], masses=masses[index], magmoms=magmoms[index], move=move[index], abfs=abfs[index])) return strulist
def data_harvest(self, cif_file): #Resets the dataframes/dictionaries for item in self.search_items: self.results[item] = [] self.errors[item] = [] self.temp_df = pd.DataFrame() #This notation is from the CifFile module and allows for easy searching of parameters cif = ReadCif(cif_file) #Identifies datablocks within the CIF file data_blocks = [] with open (cif_file, 'rt') as f: for line in f: if line.startswith('data_'): data_blocks.append(line.strip('\n').strip('data_')) number_of_structures = len(data_blocks) #For each search item in the config file, the cif file is searched for item in self.search_items: self.logger.info('File ' + pathlib.Path(cif_file.lower()).stem + ' opened. Searching for parameter ' + item) #This parameter is blanked every loop because each cif is searched multiple times self.cif_list = [] #Since the CifFile module works by looking at data-blocks, use the found list of data blocks to search through the CIF for experiment in data_blocks: try: raw = cif[experiment][item] except: self.logger.critical('Failed to find ' + item + ' in ' + pathlib.Path(cif_file.lower()).stem) exit() self.logger.info('File ' + pathlib.Path(cif_file.lower()).stem + ' - found parameter ' + item) self.cif_list.append(pathlib.Path(cif_file.lower()).stem) #Check if an error value is present and separates the value and the error, converts the error to the correct decimal point, and assigns an error of 0 if no error present if '(' in raw: temp = raw.split('(') temp2 = temp[1].strip(')') self.results[item].append(float(temp[0])) if '.' in raw: temp3 = temp[0].split('.') self.errors[item].append(int(temp2)*10**-(int(len(temp3[1])))) else: self.errors[item].append(int(temp2)) else: self.results[item].append(float(raw)) self.errors[item].append(0) #Creates a column in the data frame to include the file name of the CIF self.temp_df['CIF File'] = self.cif_list #Adds all of the data to one data frame for para in self.search_items: if len(self.results[para]) != 0: self.temp_df[para] = self.results[para] self.temp_df[para + '_error'] = self.errors[para] return self.temp_df, number_of_structures, data_blocks