def write(struct, filename=None, comments=None, direct=True, distinct_by_ox=False, vasp4=False, **kwargs): """ Write a :mod:`~qmpy.Structure` to a file or string. Arguments: struct: A `~qmpy.Structure` object. Keyword Arguments: filename: If None, returns a string. direct: If True, write POSCAR in fractional coordinates. If False, returns a POSCAR in cartesian coordinates. distinct_by_ox: If True, elements with different specified oxidation states will be treated as different species. i.e. the elements line of Fe3O4 would read Fe Fe O (Fe3+, Fe4+, O2-). This can be useful for breaking symmetry, or for specifying different U-values for different oxidation state elements. vasp4: If True, omits the species line. Examples:: >>> s = io.read(INSTALL_PATH+'/io/files/POSCAR_BCC') >>> print io.poscar.write(s) Cu 1.0 3.000000 0.000000 0.000000 0.000000 3.000000 0.000000 0.000000 0.000000 3.000000 Cu 2 direct 0.0000000000 0.0000000000 0.0000000000 0.5000000000 0.5000000000 0.5000000000 >>> io.poscar.write(s, '/tmp/POSCAR') """ comp = struct.comp struct.atoms = atom_sort(struct.atoms) cdict = defaultdict(int) if not distinct_by_ox: ordered_keys = sorted(comp.keys()) for a in struct: cdict[a.element_id] += 1 counts = [int(cdict[k]) for k in ordered_keys] else: for a in struct.atoms: if int(a.oxidation_state) != a.oxidation_state: cdict['%s%+f' % (a.element_id, a.oxidation_state)] += 1 else: cdict['%s%+d' % (a.element_id, a.oxidation_state)] += 1 ordered_keys = sorted([k for k in cdict.keys()]) counts = [int(cdict[k]) for k in ordered_keys] if comments is not None: poscar = '# %s \n1.0\n' % (comments) else: poscar = ' '.join(set(a.element_id for a in struct.atoms)) + '\n1.0\n' cell = '\n'.join( [' '.join(['%16.12f' % v for v in vec]) for vec in struct.cell]) poscar += cell + '\n' names = ' '.join(a for a in ordered_keys) + '\n' ntypes = ' '.join(str(n) for n in counts) + '\n' if not vasp4: poscar += names poscar += ntypes if direct: poscar += 'Direct\n' for x, y, z in struct.coords: poscar += '%16.12f %16.12f %16.12f\n' % (x, y, z) else: poscar += 'Cartesian\n' for x, y, z in struct.cartesian_coords: poscar += ' %16.12f %16.12f %16.12f\n' % (x, y, z) if filename: open(filename, 'w').write(poscar) else: return poscar
def write(struct, filename=None, comments=None, direct=True, distinct_by_ox=False, vasp4=False, **kwargs): """ Write a :mod:`~qmpy.Structure` to a file or string. Arguments: struct: A `~qmpy.Structure` object. Keyword Arguments: filename: If None, returns a string. direct: If True, write POSCAR in fractional coordinates. If False, returns a POSCAR in cartesian coordinates. distinct_by_ox: If True, elements with different specified oxidation states will be treated as different species. i.e. the elements line of Fe3O4 would read Fe Fe O (Fe3+, Fe4+, O2-). This can be useful for breaking symmetry, or for specifying different U-values for different oxidation state elements. vasp4: If True, omits the species line. Examples:: >>> s = io.read(INSTALL_PATH+'/io/files/POSCAR_BCC') >>> print io.poscar.write(s) Cu 1.0 3.000000 0.000000 0.000000 0.000000 3.000000 0.000000 0.000000 0.000000 3.000000 Cu 2 direct 0.0000000000 0.0000000000 0.0000000000 0.5000000000 0.5000000000 0.5000000000 >>> io.poscar.write(s, '/tmp/POSCAR') """ comp = struct.comp struct.atoms = atom_sort(struct.atoms) cdict = defaultdict(int) if not distinct_by_ox: ordered_keys = sorted(comp.keys()) for a in struct: cdict[a.element_id] += 1 counts = [ int(cdict[k]) for k in ordered_keys ] else: for a in struct.atoms: if int(a.oxidation_state) != a.oxidation_state: cdict['%s%+f' % (a.element_id, a.oxidation_state)] += 1 else: cdict['%s%+d' % (a.element_id, a.oxidation_state)] += 1 ordered_keys = sorted([ k for k in cdict.keys() ]) counts = [ int(cdict[k]) for k in ordered_keys ] if comments is not None: poscar = '# %s \n 1.0\n' %(comments) else: poscar = ' '.join(set(a.element_id for a in struct.atoms)) + '\n 1.0\n' cell = '\n'.join([ ' '.join([ '%f' % v for v in vec ]) for vec in struct.cell ]) poscar += cell +'\n' names = ' '.join( a for a in ordered_keys ) + '\n' ntypes = ' '.join( str(n) for n in counts ) + '\n' if not vasp4: poscar += names poscar += ntypes if direct: poscar += 'direct\n' for x,y,z in struct.coords: poscar += ' %.10f %.10f %.10f\n' % (x,y,z) else: poscar += 'cartesian\n' for x, y, z in struct.cartesian_coords: poscar += ' %.10f %.10f %.10f\n' % (x,y,z) if filename: open(filename, 'w').write(poscar) else: return poscar