Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1"""
2This is the implementation of the exciting I/O functions
3The functions are called with read write using the format "exciting"
5"""
7import numpy as np
8import xml.etree.ElementTree as ET
9from ase.atoms import Atoms
10from ase.units import Bohr
11from ase.utils import writer
12from xml.dom import minidom
15def read_exciting(fileobj, index=-1):
16 """Reads structure from exiting xml file.
18 Parameters
19 ----------
20 fileobj: file object
21 File handle from which data should be read.
23 Other parameters
24 ----------------
25 index: integer -1
26 Not used in this implementation.
27 """
29 # Parse file into element tree
30 doc = ET.parse(fileobj)
31 root = doc.getroot()
32 speciesnodes = root.find('structure').iter('species')
33 symbols = []
34 positions = []
35 basevects = []
36 atoms = None
37 # Collect data from tree
38 for speciesnode in speciesnodes:
39 symbol = speciesnode.get('speciesfile').split('.')[0]
40 natoms = speciesnode.iter('atom')
41 for atom in natoms:
42 x, y, z = atom.get('coord').split()
43 positions.append([float(x), float(y), float(z)])
44 symbols.append(symbol)
45 # scale unit cell accorting to scaling attributes
46 if 'scale' in doc.find('structure/crystal').attrib:
47 scale = float(str(doc.find('structure/crystal').attrib['scale']))
48 else:
49 scale = 1
51 if 'stretch' in doc.find('structure/crystal').attrib:
52 a, b, c = doc.find('structure/crystal').attrib['stretch'].text.split()
53 stretch = np.array([float(a), float(b), float(c)])
54 else:
55 stretch = np.array([1.0, 1.0, 1.0])
56 basevectsn = root.findall('structure/crystal/basevect')
57 for basevect in basevectsn:
58 x, y, z = basevect.text.split()
59 basevects.append(np.array([float(x) * Bohr * stretch[0],
60 float(y) * Bohr * stretch[1],
61 float(z) * Bohr * stretch[2]
62 ]) * scale)
63 atoms = Atoms(symbols=symbols, cell=basevects)
65 atoms.set_scaled_positions(positions)
66 if 'molecule' in root.find('structure').attrib.keys():
67 if root.find('structure').attrib['molecule']:
68 atoms.set_pbc(False)
69 else:
70 atoms.set_pbc(True)
72 return atoms
75@writer
76def write_exciting(fileobj, images):
77 """writes exciting input structure in XML
79 Parameters
80 ----------
81 filename : str
82 Name of file to which data should be written.
83 images : Atom Object or List of Atoms objects
84 This function will write the first Atoms object to file.
86 Returns
87 -------
88 """
89 root = atoms2etree(images)
90 rough_string = ET.tostring(root, 'utf-8')
91 reparsed = minidom.parseString(rough_string)
92 pretty = reparsed.toprettyxml(indent="\t")
93 fileobj.write(pretty)
96def atoms2etree(images):
97 """This function creates the XML DOM corresponding
98 to the structure for use in write and calculator
100 Parameters
101 ----------
103 images : Atom Object or List of Atoms objects
105 Returns
106 -------
107 root : etree object
108 Element tree of exciting input file containing the structure
109 """
110 if not isinstance(images, (list, tuple)):
111 images = [images]
113 root = ET.Element('input')
114 root.set(
115 '{http://www.w3.org/2001/XMLSchema-instance}noNamespaceSchemaLocation',
116 'http://xml.exciting-code.org/excitinginput.xsd')
118 title = ET.SubElement(root, 'title')
119 title.text = ''
120 structure = ET.SubElement(root, 'structure')
121 crystal = ET.SubElement(structure, 'crystal')
122 atoms = images[0]
123 for vec in atoms.cell:
124 basevect = ET.SubElement(crystal, 'basevect')
125 basevect.text = '%.14f %.14f %.14f' % tuple(vec / Bohr)
127 oldsymbol = ''
128 oldrmt = -1
129 newrmt = -1
130 scaled = atoms.get_scaled_positions()
131 for aindex, symbol in enumerate(atoms.get_chemical_symbols()):
132 if 'rmt' in atoms.arrays:
133 newrmt = atoms.get_array('rmt')[aindex] / Bohr
134 if symbol != oldsymbol or newrmt != oldrmt:
135 speciesnode = ET.SubElement(structure, 'species',
136 speciesfile='%s.xml' % symbol,
137 chemicalSymbol=symbol)
138 oldsymbol = symbol
139 if 'rmt' in atoms.arrays:
140 oldrmt = atoms.get_array('rmt')[aindex] / Bohr
141 if oldrmt > 0:
142 speciesnode.attrib['rmt'] = '%.4f' % oldrmt
144 atom = ET.SubElement(speciesnode, 'atom',
145 coord='%.14f %.14f %.14f' % tuple(scaled[aindex]))
146 if 'momenta' in atoms.arrays:
147 atom.attrib['bfcmt'] = '%.14f %.14f %.14f' % tuple(
148 atoms.get_array('mommenta')[aindex])
150 return root