def read_cml(fileobj): data = contract(json.load(fileobj)) atoms = Atoms() datoms = data['atoms'] atoms = Atoms(datoms['elements']['number']) if 'unitcell' in data: cell = data['unitcell'] a = cell['a'] b = cell['b'] c = cell['c'] alpha = cell['alpha'] beta = cell['beta'] gamma = cell['gamma'] atoms.cell = Cell.fromcellpar([a, b, c, alpha, beta, gamma]) atoms.pbc = True coords = contract(datoms['coords']) if '3d' in coords: positions = np.array(coords['3d']).reshape(len(atoms), 3) atoms.set_positions(positions) else: positions = np.array(coords['3dfractional']).reshape(len(atoms), 3) atoms.set_scaled_positions(positions) yield atoms
def get_positions(val): res = dict(lattice_vectors=[], atom_labels=[], atom_positions=[]) try: cell_par = re.search( rf'({re_f} +{re_f} +{re_f} +{re_f} +{re_f} +{re_f})', val) res['lattice_vectors'] = Cell.fromcellpar( [float(v) for v in cell_par.group(1).split()]).array * ureg.angstrom labels, positions = zip(*re.findall( rf'\d+ +([A-Z][a-z]*) +({re_f} +{re_f} +{re_f} +)\d+', val)) res['atom_labels'] = labels res['atom_positions'] = np.array( [v.split() for v in positions], dtype=np.dtype( np.float64)) * ureg.angstrom except Exception: pass return res
def read_ipi_xyz(fxyz): from ase import io from ase.cell import Cell from qharv.reel import ascii_out mm = ascii_out.read(fxyz) idxl = ascii_out.all_lines_with_tag(mm, '# ') traj = io.read(fxyz, ':', format='extxyz') nhead = len(idxl) nbody = len(traj) if nhead != nbody: msg = 'found %d headers for %d bodies' % (nhead, nbody) raise RuntimeError(msg) headers = [] for idx in idxl: mm.seek(idx) header = mm.readline().decode() headers.append(header) mm.close() for header, atoms in zip(headers, traj): tokens = header.strip('#').split() # read cell i0 = tokens.index('CELL(abcABC):') cellpart = tokens[i0+1:i0+7] cellpar = np.array(cellpart, dtype=float) cell = Cell.fromcellpar(cellpar) atoms.set_cell(cell) atoms.set_pbc(True) # read info atoms.info = {} for i, tok in enumerate(tokens): if (i >= i0) and (i < i0+7): continue if tok.endswith(':'): # key-val pair atoms.info[tok[:-1]] = tokens[i+1] if ('{' in tok) and ('}' in tok): # unit key, val = tok.split('{') atoms.info[key+'_unit'] = val[:-1] return traj
def get_tri(kcellpar): # We build the TRI lattices from cellpars of reciprocal cell icell = Cell.fromcellpar(kcellpar) cellpar = Cell(4 * icell.reciprocal()).cellpar() return TRI(*cellpar)
def _read_process_rmc6f_lines_to_pos_and_cell(lines): """ Processes the lines of rmc6f file to atom position dictionary and cell Parameters ---------- lines: list[str] List of lines from rmc6f file. Returns ------ pos : dict{int:list[str|float]} Dict for each atom id and Atoms properties based on rmc6f style. Basically, have 1) element and fractional coordinates for 'labels' or 'no_labels' style and 2) same for 'magnetic' style except adds the spin. Examples for 1) 'labels' or 'no_labels' styles or 2) 'magnetic' style: 1) pos[aid] = [element, xf, yf, zf] 2) pos[aid] = [element, xf, yf, zf, spin] cell: Cell object The ASE Cell object created from cell parameters read from the 'Cell' section of rmc6f file. """ # Inititalize output pos dictionary pos = {} # Defined the header an section lines we process header_lines = [ "Number of atoms:", "Supercell dimensions:", "Cell (Ang/deg):", "Lattice vectors (Ang):" ] sections = ["Atoms"] # Construct header and sections regex header_lines_re = _read_construct_regex(header_lines) sections_re = _read_construct_regex(sections) section = None header = True # Remove any lines that are blank lines = [line for line in lines if line != ''] # Process each line of rmc6f file pos = {} for line in lines: # check if in a section m = re.match(sections_re, line) if m is not None: section = m.group(0).strip() header = False continue # header section if header: field = None val = None # Regex that matches whitespace-separated floats float_list_re = r'\s+(\d[\d|\s\.]+[\d|\.])' m = re.search(header_lines_re + float_list_re, line) if m is not None: field = m.group(1) val = m.group(2) if field is not None and val is not None: if field == "Number of atoms:": pass """ NOTE: Can just capture via number of atoms ingested. Maybe use in future for a check. code: natoms = int(val) """ if field.startswith('Supercell'): pass """ NOTE: wrapping back down to unit cell is not necessarily needed for ASE object. code: supercell = [int(x) for x in val.split()] """ if field.startswith('Cell'): cellpar = [float(x) for x in val.split()] cell = Cell.fromcellpar(cellpar) if field.startswith('Lattice'): pass """ NOTE: Have questions about RMC fractionalization matrix for conversion in data2config vs. the ASE matrix. Currently, just support the Cell section. """ # main body section if section is not None: if section == 'Atoms': atom_id, atom_props = _read_line_of_atoms_section(line.split()) pos[atom_id] = atom_props return pos, cell
def write_rmc6f(filename, atoms, order=None, atom_type_map=None): """ Write output in rmc6f format - RMCProfile v6 fractional coordinates Parameters ---------- filename : file|str A file like object or filename. atoms: Atoms object The Atoms object to be written. order : list[str] If not None, gives a list of atom types for the order to write out each. atom_type_map: dict{str:str} Map of atom types for conversions. Mainly used if there is an atom type in the Atoms object that is a placeholder for a different atom type. This is used when the atom type is not supported by ASE but is in RMCProfile. Example to map hydrogen to deuterium: atom_type_map = { 'H': 'D' } """ # get atom types and how many of each (and set to order if passed) atom_types = set(atoms.symbols) if order is not None: if set(atom_types) != set(order): raise Exception("The order is not a set of the atom types.") atom_types = order atom_count_dict = atoms.symbols.formula.count() natom_types = [str(atom_count_dict[atom_type]) for atom_type in atom_types] # create an atom type map if one does not exist from unique atomic symbols if atom_type_map is None: symbols = set(np.array(atoms.symbols)) atom_type_map = {atype: atype for atype in symbols} # HEADER SECTION # get type and number of each atom type atom_types_list = [atom_type_map[atype] for atype in atom_types] atom_types_present = ' '.join(atom_types_list) natom_types_present = ' '.join(natom_types) header_lines = [ "(Version 6f format configuration file)", "(Generated by ASE - Atomic Simulation Environment https://wiki.fysik.dtu.dk/ase/ )", # noqa: E501 "Metadata date: " + time.strftime('%d-%m-%Y'), "Number of types of atoms: {} ".format(len(atom_types)), "Atom types present: {}".format(atom_types_present), "Number of each atom type: {}".format(natom_types_present), "Number of moves generated: 0", "Number of moves tried: 0", "Number of moves accepted: 0", "Number of prior configuration saves: 0", "Number of atoms: {}".format(len(atoms)), "Supercell dimensions: 1 1 1" ] # magnetic moments if atoms.has('magmoms'): spin_str = "Number of spins: {}" spin_line = spin_str.format(len(atoms.get_initial_magnetic_moments())) header_lines.extend([spin_line]) density_str = "Number density (Ang^-3): {}" density_line = density_str.format(len(atoms) / atoms.get_volume()) cell_angles = [str(x) for x in atoms.cell.cellpar()] cell_line = "Cell (Ang/deg): " + ' '.join(cell_angles) header_lines.extend([density_line, cell_line]) # get lattice vectors from cell lengths and angles # NOTE: RMCProfile uses a different convention for the fractionalization # matrix cell_parameters = atoms.cell.cellpar() cell = Cell.fromcellpar(cell_parameters).T x_line = ' '.join(['{:12.6f}'.format(i) for i in cell[0]]) y_line = ' '.join(['{:12.6f}'.format(i) for i in cell[1]]) z_line = ' '.join(['{:12.6f}'.format(i) for i in cell[2]]) lat_lines = ["Lattice vectors (Ang):", x_line, y_line, z_line] header_lines.extend(lat_lines) header_lines.extend(['Atoms:']) # ATOMS SECTION # create columns of data for atoms (fr_cols) fr_cols = ['id', 'symbols', 'scaled_positions', 'ref_num', 'ref_cell'] if atoms.has('magmoms'): fr_cols.extend('magmom') # Collect data to be written out natoms = len(atoms) arrays = {} arrays['id'] = np.array(range(1, natoms + 1, 1), int) arrays['symbols'] = np.array(atoms.symbols) arrays['ref_num'] = np.zeros(natoms, int) arrays['ref_cell'] = np.zeros((natoms, 3), int) arrays['scaled_positions'] = np.array(atoms.get_scaled_positions()) # get formatting for writing output based on atom arrays ncols, dtype_obj, fmt = _write_output_column_format(fr_cols, arrays) # Pack fr_cols into record array data = np.zeros(natoms, dtype_obj) for column, ncol in zip(fr_cols, ncols): value = arrays[column] if ncol == 1: data[column] = np.squeeze(value) else: for c in range(ncol): data[column + str(c)] = value[:, c] # Use map of tmp symbol to actual symbol for i in range(natoms): data[i][1] = atom_type_map[data[i][1]] # Write the output _write_output(filename, header_lines, data, fmt, order=order)