root / ase / calculators / exciting.py @ 19
Historique | Voir | Annoter | Télécharger (4,49 ko)
1 | 1 | tkerber | import os |
---|---|---|---|
2 | 1 | tkerber | import numpy as np |
3 | 1 | tkerber | from ase.units import Bohr, Hartree |
4 | 1 | tkerber | |
5 | 1 | tkerber | |
6 | 1 | tkerber | class Exciting: |
7 | 1 | tkerber | """exciting calculator object."""
|
8 | 1 | tkerber | |
9 | 1 | tkerber | def __init__(self, dir='.', template=None, speciespath=None, |
10 | 1 | tkerber | bin='excitingser', kpts=(1, 1, 1), **kwargs): |
11 | 1 | tkerber | """Exciting calculator object constructor
|
12 | 1 | tkerber |
|
13 | 1 | tkerber | Parameters
|
14 | 1 | tkerber | ----------
|
15 | 1 | tkerber | dir: string
|
16 | 1 | tkerber | directory in which to excecute exciting
|
17 | 1 | tkerber | template: string
|
18 | 1 | tkerber | Path to XSLT templat if it schould be used
|
19 | 1 | tkerber | default: none
|
20 | 1 | tkerber | bin: string
|
21 | 1 | tkerber | Path or executable name of exciting
|
22 | 1 | tkerber | default: ``excitingser``
|
23 | 1 | tkerber | kpts: integer list length 3
|
24 | 1 | tkerber | Number of kpoints
|
25 | 1 | tkerber | kwargs: dictionary like
|
26 | 1 | tkerber | list of key value pairs to be converted into groundstate attributes
|
27 | 1 | tkerber |
|
28 | 1 | tkerber | """
|
29 | 1 | tkerber | self.dir = dir |
30 | 1 | tkerber | self.energy = None |
31 | 1 | tkerber | self.template = template
|
32 | 1 | tkerber | if speciespath is None: |
33 | 1 | tkerber | self.speciespath = os.environ.get('EXCITING_SPECIES_PATH', './') |
34 | 1 | tkerber | self.converged = False |
35 | 1 | tkerber | self.excitingbinary = bin |
36 | 1 | tkerber | self.groundstate_attributes = kwargs
|
37 | 1 | tkerber | if not 'ngridk' in kwargs.keys(): |
38 | 1 | tkerber | self.groundstate_attributes['ngridk'] = ' '.join(map(str, kpts)) |
39 | 1 | tkerber | |
40 | 1 | tkerber | def update(self, atoms): |
41 | 1 | tkerber | if (not self.converged or |
42 | 1 | tkerber | len(self.numbers) != len(atoms) or |
43 | 1 | tkerber | (self.numbers != atoms.get_atomic_numbers()).any()):
|
44 | 1 | tkerber | self.initialize(atoms)
|
45 | 1 | tkerber | self.calculate(atoms)
|
46 | 1 | tkerber | elif ((self.positions != atoms.get_positions()).any() or |
47 | 1 | tkerber | (self.pbc != atoms.get_pbc()).any() or |
48 | 1 | tkerber | (self.cell != atoms.get_cell()).any()):
|
49 | 1 | tkerber | self.calculate(atoms)
|
50 | 1 | tkerber | |
51 | 1 | tkerber | def initialize(self, atoms): |
52 | 1 | tkerber | self.numbers = atoms.get_atomic_numbers().copy()
|
53 | 1 | tkerber | self.write(atoms)
|
54 | 1 | tkerber | |
55 | 1 | tkerber | def get_potential_energy(self, atoms): |
56 | 1 | tkerber | self.update(atoms)
|
57 | 1 | tkerber | return self.energy |
58 | 1 | tkerber | |
59 | 1 | tkerber | def get_forces(self, atoms): |
60 | 1 | tkerber | self.update(atoms)
|
61 | 1 | tkerber | return self.forces.copy() |
62 | 1 | tkerber | |
63 | 1 | tkerber | def get_stress(self, atoms): |
64 | 1 | tkerber | self.update(atoms)
|
65 | 1 | tkerber | return self.stress.copy() |
66 | 1 | tkerber | |
67 | 1 | tkerber | def calculate(self, atoms): |
68 | 1 | tkerber | self.positions = atoms.get_positions().copy()
|
69 | 1 | tkerber | self.cell = atoms.get_cell().copy()
|
70 | 1 | tkerber | self.pbc = atoms.get_pbc().copy()
|
71 | 1 | tkerber | |
72 | 1 | tkerber | self.initialize(atoms)
|
73 | 1 | tkerber | syscall = ('cd %(dir)s; %(bin)s;' %
|
74 | 1 | tkerber | {'dir': self.dir, 'bin': self.excitingbinary}) |
75 | 1 | tkerber | print syscall
|
76 | 1 | tkerber | assert os.system(syscall ) == 0 |
77 | 1 | tkerber | self.read()
|
78 | 1 | tkerber | |
79 | 1 | tkerber | def write(self, atoms): |
80 | 1 | tkerber | from lxml import etree as ET |
81 | 1 | tkerber | from ase.io.exciting import atoms2etree |
82 | 1 | tkerber | if not os.path.isdir(self.dir): |
83 | 1 | tkerber | os.mkdir(self.dir)
|
84 | 1 | tkerber | root = atoms2etree(atoms) |
85 | 1 | tkerber | root.find('structure').attrib['speciespath'] = self.speciespath |
86 | 1 | tkerber | root.find('structure').attrib['autormt'] = 'false' |
87 | 1 | tkerber | groundstate = ET.SubElement(root, 'groundstate', tforce='true') |
88 | 1 | tkerber | for key, value in self.groundstate_attributes.items(): |
89 | 1 | tkerber | groundstate.attrib[key] = str(value)
|
90 | 1 | tkerber | if self.template: |
91 | 1 | tkerber | xslf = open(self.template, 'r') |
92 | 1 | tkerber | xslt_doc = ET.parse(xslf) |
93 | 1 | tkerber | transform = ET.XSLT(xslt_doc) |
94 | 1 | tkerber | result = transform(root) |
95 | 1 | tkerber | fd = open('%s/input.xml' % self.dir, 'w') |
96 | 1 | tkerber | fd.write(ET.tostring(result, method='xml', pretty_print=True, |
97 | 1 | tkerber | xml_declaration=True, encoding='UTF-8')) |
98 | 1 | tkerber | fd.close() |
99 | 1 | tkerber | else:
|
100 | 1 | tkerber | fd = open('%s/input.xml' % self.dir, 'w') |
101 | 1 | tkerber | fd.write(ET.tostring(root, method='xml', pretty_print=True, |
102 | 1 | tkerber | xml_declaration=True, encoding='UTF-8')) |
103 | 1 | tkerber | fd.close() |
104 | 1 | tkerber | |
105 | 1 | tkerber | def read(self): |
106 | 1 | tkerber | """ reads Total energy and forces from info.xml
|
107 | 1 | tkerber | """
|
108 | 1 | tkerber | from lxml import etree as ET |
109 | 1 | tkerber | INFO_file = '%s/info.xml' % self.dir |
110 | 1 | tkerber | |
111 | 1 | tkerber | try:
|
112 | 1 | tkerber | fd = open(INFO_file)
|
113 | 1 | tkerber | except IOError: |
114 | 1 | tkerber | print "file doesn't exist" |
115 | 1 | tkerber | info = ET.parse(fd) |
116 | 1 | tkerber | self.energy = float(info.xpath('//@totalEnergy')[-1]) * Hartree |
117 | 1 | tkerber | forces = [] |
118 | 1 | tkerber | forcesnodes = info.xpath( |
119 | 1 | tkerber | '//structure[last()]/species/atom/forces/totalforce/@*')
|
120 | 1 | tkerber | for force in forcesnodes: |
121 | 1 | tkerber | forces.append(np.array(float(force)))
|
122 | 1 | tkerber | self.forces = np.reshape(forces, (-1, 3)) |
123 | 1 | tkerber | |
124 | 1 | tkerber | if str(info.xpath('//groundstate/@status')[0]) == 'finished': |
125 | 1 | tkerber | self.converged = True |
126 | 1 | tkerber | else:
|
127 | 1 | tkerber | raise RuntimeError('calculation did not finish correctly') |
128 | 1 | tkerber | |
129 | 1 | tkerber | # Stress
|
130 | 1 | tkerber | self.stress = np.empty((3, 3)) |