root / ase / gui / calculator.py @ 3
Historique | Voir | Annoter | Télécharger (67,5 ko)
1 |
# encoding: utf-8
|
---|---|
2 |
"calculator.py - module for choosing a calculator."
|
3 |
|
4 |
import gtk |
5 |
import os |
6 |
import numpy as np |
7 |
from copy import copy |
8 |
from ase.gui.setupwindow import SetupWindow |
9 |
from ase.gui.progress import DefaultProgressIndicator, GpawProgressIndicator |
10 |
from ase.gui.widgets import pack, oops, cancel_apply_ok |
11 |
from ase import Atoms |
12 |
from ase.data import chemical_symbols |
13 |
import ase |
14 |
|
15 |
# Asap and GPAW may be imported if selected.
|
16 |
|
17 |
introtext = """\
|
18 |
To make most calculations on the atoms, a Calculator object must first
|
19 |
be associated with it. ASE supports a number of calculators, supporting
|
20 |
different elements, and implementing different physical models for the
|
21 |
interatomic interactions.\
|
22 |
"""
|
23 |
|
24 |
# Informational text about the calculators
|
25 |
lj_info_txt = """\
|
26 |
The Lennard-Jones pair potential is one of the simplest
|
27 |
possible models for interatomic interactions, mostly
|
28 |
suitable for noble gasses and model systems.
|
29 |
|
30 |
Interactions are described by an interaction length and an
|
31 |
interaction strength.\
|
32 |
"""
|
33 |
|
34 |
emt_info_txt = """\
|
35 |
The EMT potential is a many-body potential, giving a
|
36 |
good description of the late transition metals crystalling
|
37 |
in the FCC crystal structure. The elements described by the
|
38 |
main set of EMT parameters are Al, Ni, Cu, Pd, Ag, Pt, and
|
39 |
Au, the Al potential is however not suitable for materials
|
40 |
science application, as the stacking fault energy is wrong.
|
41 |
|
42 |
A number of parameter sets are provided.
|
43 |
|
44 |
<b>Default parameters:</b>
|
45 |
|
46 |
The default EMT parameters, as published in K. W. Jacobsen,
|
47 |
P. Stoltze and J. K. Nørskov, <i>Surf. Sci.</i> <b>366</b>, 394 (1996).
|
48 |
|
49 |
<b>Alternative Cu, Ag and Au:</b>
|
50 |
|
51 |
An alternative set of parameters for Cu, Ag and Au,
|
52 |
reoptimized to experimental data including the stacking
|
53 |
fault energies by Torben Rasmussen (partly unpublished).
|
54 |
|
55 |
<b>Ruthenium:</b>
|
56 |
|
57 |
Parameters for Ruthenium, as published in J. Gavnholt and
|
58 |
J. Schiøtz, <i>Phys. Rev. B</i> <b>77</b>, 035404 (2008).
|
59 |
|
60 |
<b>Metallic glasses:</b>
|
61 |
|
62 |
Parameters for MgCu and CuZr metallic glasses. MgCu
|
63 |
parameters are in N. P. Bailey, J. Schiøtz and
|
64 |
K. W. Jacobsen, <i>Phys. Rev. B</i> <b>69</b>, 144205 (2004).
|
65 |
CuZr in A. Paduraru, A. Kenoufi, N. P. Bailey and
|
66 |
J. Schiøtz, <i>Adv. Eng. Mater.</i> <b>9</b>, 505 (2007).
|
67 |
"""
|
68 |
|
69 |
aseemt_info_txt = """\
|
70 |
The EMT potential is a many-body potential, giving a
|
71 |
good description of the late transition metals crystalling
|
72 |
in the FCC crystal structure. The elements described by the
|
73 |
main set of EMT parameters are Al, Ni, Cu, Pd, Ag, Pt, and
|
74 |
Au. In addition, this implementation allows for the use of
|
75 |
H, N, O and C adatoms, although the description of these is
|
76 |
most likely not very good.
|
77 |
|
78 |
<b>This is the ASE implementation of EMT.</b> For large
|
79 |
simulations the ASAP implementation is more suitable; this
|
80 |
implementation is mainly to make EMT available when ASAP is
|
81 |
not installed.
|
82 |
"""
|
83 |
|
84 |
brenner_info_txt = """\
|
85 |
The Brenner potential is a reactive bond-order potential for
|
86 |
carbon and hydrocarbons. As a bond-order potential, it takes
|
87 |
into account that carbon orbitals can hybridize in different
|
88 |
ways, and that carbon can form single, double and triple
|
89 |
bonds. That the potential is reactive means that it can
|
90 |
handle gradual changes in the bond order as chemical bonds
|
91 |
are formed or broken.
|
92 |
|
93 |
The Brenner potential is implemented in Asap, based on a
|
94 |
C implentation published at http://www.rahul.net/pcm/brenner/ .
|
95 |
|
96 |
The potential is documented here:
|
97 |
Donald W Brenner, Olga A Shenderova, Judith A Harrison,
|
98 |
Steven J Stuart, Boris Ni and Susan B Sinnott:
|
99 |
"A second-generation reactive empirical bond order (REBO)
|
100 |
potential energy expression for hydrocarbons",
|
101 |
J. Phys.: Condens. Matter 14 (2002) 783-802.
|
102 |
doi: 10.1088/0953-8984/14/4/312
|
103 |
"""
|
104 |
|
105 |
|
106 |
gpaw_info_txt = """\
|
107 |
GPAW implements Density Functional Theory using a
|
108 |
<b>G</b>rid-based real-space representation of the wave
|
109 |
functions, and the <b>P</b>rojector <b>A</b>ugmented <b>W</b>ave
|
110 |
method for handling the core regions.
|
111 |
"""
|
112 |
|
113 |
aims_info_txt = """\
|
114 |
FHI-aims is an external package implementing density
|
115 |
functional theory and quantum chemical methods using
|
116 |
all-electron methods and a numeric local orbital basis set.
|
117 |
For full details, see http://www.fhi-berlin.mpg.de/aims/
|
118 |
or Comp. Phys. Comm. v180 2175 (2009). The ASE
|
119 |
documentation contains information on the keywords and
|
120 |
functionalities available within this interface.
|
121 |
"""
|
122 |
|
123 |
aims_pbc_warning_text = """\
|
124 |
WARNING:
|
125 |
Your system seems to have more than zero but less than
|
126 |
three periodic dimensions. Please check that this is
|
127 |
really what you want to compute. Assuming full
|
128 |
3D periodicity for this calculator."""
|
129 |
|
130 |
vasp_info_txt = """\
|
131 |
VASP is an external package implementing density
|
132 |
functional functional theory using pseudopotentials
|
133 |
or the projector-augmented wave method together
|
134 |
with a plane wave basis set. For full details, see
|
135 |
http://cms.mpi.univie.ac.at/vasp/vasp/
|
136 |
"""
|
137 |
|
138 |
emt_parameters = ( |
139 |
("Default (Al, Ni, Cu, Pd, Ag, Pt, Au)", None), |
140 |
("Alternative Cu, Ag and Au", "EMTRasmussenParameters"), |
141 |
("Ruthenium", "EMThcpParameters"), |
142 |
("CuMg and CuZr metallic glass", "EMTMetalGlassParameters") |
143 |
) |
144 |
|
145 |
class SetCalculator(SetupWindow): |
146 |
"Window for selecting a calculator."
|
147 |
|
148 |
# List the names of the radio button attributes
|
149 |
radios = ("none", "lj", "emt", "aseemt", "brenner", "gpaw", "aims", "vasp") |
150 |
# List the names of the parameter dictionaries
|
151 |
paramdicts = ("lj_parameters",)
|
152 |
# The name used to store parameters on the gui object
|
153 |
classname = "SetCalculator"
|
154 |
|
155 |
def __init__(self, gui): |
156 |
SetupWindow.__init__(self)
|
157 |
self.set_title("Select calculator") |
158 |
vbox = gtk.VBox() |
159 |
|
160 |
# Intoductory text
|
161 |
self.packtext(vbox, introtext)
|
162 |
|
163 |
pack(vbox, [gtk.Label("Calculator:")])
|
164 |
|
165 |
# No calculator (the default)
|
166 |
self.none_radio = gtk.RadioButton(None, "None") |
167 |
pack(vbox, [self.none_radio])
|
168 |
|
169 |
# Lennard-Jones
|
170 |
self.lj_radio = gtk.RadioButton(self.none_radio, "Lennard-Jones (ASAP)") |
171 |
self.lj_setup = gtk.Button("Setup") |
172 |
self.lj_info = InfoButton(lj_info_txt)
|
173 |
self.lj_setup.connect("clicked", self.lj_setup_window) |
174 |
self.pack_line(vbox, self.lj_radio, self.lj_setup, self.lj_info) |
175 |
|
176 |
# EMT
|
177 |
self.emt_radio = gtk.RadioButton(
|
178 |
self.none_radio, "EMT - Effective Medium Theory (ASAP)") |
179 |
self.emt_setup = gtk.combo_box_new_text()
|
180 |
self.emt_param_info = {}
|
181 |
for p in emt_parameters: |
182 |
self.emt_setup.append_text(p[0]) |
183 |
self.emt_param_info[p[0]] = p[1] |
184 |
self.emt_setup.set_active(0) |
185 |
self.emt_info = InfoButton(emt_info_txt)
|
186 |
self.pack_line(vbox, self.emt_radio, self.emt_setup, self.emt_info) |
187 |
|
188 |
# EMT (ASE implementation)
|
189 |
self.aseemt_radio = gtk.RadioButton(
|
190 |
self.none_radio, "EMT - Effective Medium Theory (ASE)") |
191 |
self.aseemt_info = InfoButton(aseemt_info_txt)
|
192 |
self.pack_line(vbox, self.aseemt_radio, None, self.aseemt_info) |
193 |
|
194 |
# Brenner potential
|
195 |
self.brenner_radio = gtk.RadioButton(
|
196 |
self.none_radio, "Brenner Potential (ASAP)") |
197 |
self.brenner_info = InfoButton(brenner_info_txt)
|
198 |
self.pack_line(vbox, self.brenner_radio, None, self.brenner_info) |
199 |
|
200 |
# GPAW
|
201 |
self.gpaw_radio = gtk.RadioButton(self.none_radio, |
202 |
"Density Functional Theory (GPAW)")
|
203 |
self.gpaw_setup = gtk.Button("Setup") |
204 |
self.gpaw_info = InfoButton(gpaw_info_txt)
|
205 |
self.gpaw_setup.connect("clicked", self.gpaw_setup_window) |
206 |
self.pack_line(vbox, self.gpaw_radio, self.gpaw_setup, self.gpaw_info) |
207 |
|
208 |
# FHI-aims
|
209 |
self.aims_radio = gtk.RadioButton(self.none_radio, |
210 |
"Density Functional Theory (FHI-aims)")
|
211 |
self.aims_setup = gtk.Button("Setup") |
212 |
self.aims_info = InfoButton(aims_info_txt)
|
213 |
self.aims_setup.connect("clicked", self.aims_setup_window) |
214 |
self.pack_line(vbox, self.aims_radio, self.aims_setup, self.aims_info) |
215 |
|
216 |
# VASP
|
217 |
self.vasp_radio = gtk.RadioButton(self.none_radio, |
218 |
"Density Functional Theory (VASP)")
|
219 |
self.vasp_setup = gtk.Button("Setup") |
220 |
self.vasp_info = InfoButton(vasp_info_txt)
|
221 |
self.vasp_setup.connect("clicked", self.vasp_setup_window) |
222 |
self.pack_line(vbox, self.vasp_radio, self.vasp_setup, self.vasp_info) |
223 |
|
224 |
# Buttons etc.
|
225 |
pack(vbox, gtk.Label(""))
|
226 |
buts = cancel_apply_ok(cancel=lambda widget: self.destroy(), |
227 |
apply=self.apply,
|
228 |
ok=self.ok)
|
229 |
pack(vbox, [buts], end=True, bottom=True) |
230 |
self.check = gtk.CheckButton("Check that the calculator is reasonable.") |
231 |
self.check.set_active(True) |
232 |
fr = gtk.Frame() |
233 |
fr.add(self.check)
|
234 |
fr.show_all() |
235 |
pack(vbox, [fr], end=True, bottom=True) |
236 |
|
237 |
# Finalize setup
|
238 |
self.add(vbox)
|
239 |
vbox.show() |
240 |
self.show()
|
241 |
self.gui = gui
|
242 |
self.load_state()
|
243 |
|
244 |
def pack_line(self, box, radio, setup, info): |
245 |
hbox = gtk.HBox() |
246 |
hbox.pack_start(radio, 0, 0) |
247 |
hbox.pack_start(gtk.Label(" "), 0, 0) |
248 |
hbox.pack_end(info, 0, 0) |
249 |
if setup is not None: |
250 |
radio.connect("toggled", self.radio_toggled, setup) |
251 |
setup.set_sensitive(False)
|
252 |
hbox.pack_end(setup, 0, 0) |
253 |
hbox.show_all() |
254 |
box.pack_start(hbox, 0, 0) |
255 |
|
256 |
def radio_toggled(self, radio, button): |
257 |
button.set_sensitive(radio.get_active()) |
258 |
|
259 |
def lj_setup_window(self, widget): |
260 |
if not self.get_atoms(): |
261 |
return
|
262 |
lj_param = getattr(self, "lj_parameters", None) |
263 |
LJ_Window(self, lj_param, "lj_parameters") |
264 |
# When control is retuned, self.lj_parameters has been set.
|
265 |
|
266 |
def gpaw_setup_window(self, widget): |
267 |
if not self.get_atoms(): |
268 |
return
|
269 |
gpaw_param = getattr(self, "gpaw_parameters", None) |
270 |
GPAW_Window(self, gpaw_param, "gpaw_parameters") |
271 |
# When control is retuned, self.gpaw_parameters has been set.
|
272 |
|
273 |
def aims_setup_window(self, widget): |
274 |
if not self.get_atoms(): |
275 |
return
|
276 |
aims_param = getattr(self, "aims_parameters", None) |
277 |
AIMS_Window(self, aims_param, "aims_parameters") |
278 |
# When control is retuned, self.aims_parameters has been set.
|
279 |
|
280 |
def vasp_setup_window(self, widget): |
281 |
if not self.get_atoms(): |
282 |
return
|
283 |
vasp_param = getattr(self, "vasp_parameters", None) |
284 |
VASP_Window(self, vasp_param, "vasp_parameters") |
285 |
# When control is retuned, self.vasp_parameters has been set.
|
286 |
|
287 |
def get_atoms(self): |
288 |
"Make an atoms object from the active image"
|
289 |
images = self.gui.images
|
290 |
if images.natoms < 1: |
291 |
oops("No atoms present")
|
292 |
return False |
293 |
self.atoms = Atoms(positions=images.P[0], symbols=images.Z, |
294 |
cell=images.A[0], pbc=images.pbc)
|
295 |
if not images.dynamic.all(): |
296 |
from ase.constraints import FixAtoms |
297 |
self.atoms.set_constraint(FixAtoms(mask=1-images.dynamic)) |
298 |
return True |
299 |
|
300 |
def apply(self, *widget): |
301 |
if self.do_apply(): |
302 |
self.save_state()
|
303 |
return True |
304 |
else:
|
305 |
return False |
306 |
|
307 |
def do_apply(self): |
308 |
nochk = not self.check.get_active() |
309 |
self.gui.simulation["progress"] = DefaultProgressIndicator() |
310 |
if self.none_radio.get_active(): |
311 |
self.gui.simulation['calc'] = None |
312 |
return True |
313 |
elif self.lj_radio.get_active(): |
314 |
if nochk or self.lj_check(): |
315 |
self.choose_lj()
|
316 |
return True |
317 |
elif self.emt_radio.get_active(): |
318 |
if nochk or self.emt_check(): |
319 |
self.choose_emt()
|
320 |
return True |
321 |
elif self.aseemt_radio.get_active(): |
322 |
if nochk or self.aseemt_check(): |
323 |
self.choose_aseemt()
|
324 |
return True |
325 |
elif self.brenner_radio.get_active(): |
326 |
if nochk or self.brenner_check(): |
327 |
self.choose_brenner()
|
328 |
return True |
329 |
elif self.gpaw_radio.get_active(): |
330 |
if nochk or self.gpaw_check(): |
331 |
self.choose_gpaw()
|
332 |
return True |
333 |
elif self.aims_radio.get_active(): |
334 |
if nochk or self.aims_check(): |
335 |
self.choose_aims()
|
336 |
return True |
337 |
elif self.vasp_radio.get_active(): |
338 |
if nochk or self.vasp_check(): |
339 |
self.choose_vasp()
|
340 |
return True |
341 |
return False |
342 |
|
343 |
def ok(self, *widget): |
344 |
if self.apply(): |
345 |
self.destroy()
|
346 |
|
347 |
def save_state(self): |
348 |
state = {} |
349 |
for r in self.radios: |
350 |
radiobutton = getattr(self, r+"_radio") |
351 |
if radiobutton.get_active():
|
352 |
state["radio"] = r
|
353 |
state["emtsetup"] = self.emt_setup.get_active() |
354 |
state["check"] = self.check.get_active() |
355 |
for p in self.paramdicts: |
356 |
if hasattr(self, p): |
357 |
state[p] = getattr(self, p) |
358 |
self.gui.module_state[self.classname] = state |
359 |
|
360 |
def load_state(self): |
361 |
try:
|
362 |
state = self.gui.module_state[self.classname] |
363 |
except KeyError: |
364 |
return
|
365 |
r = state["radio"]
|
366 |
radiobutton = getattr(self, r+"_radio") |
367 |
radiobutton.set_active(True)
|
368 |
self.emt_setup.set_active(state["emtsetup"]) |
369 |
self.check.set_active(state["check"]) |
370 |
for p in self.paramdicts: |
371 |
if state.has_key(p):
|
372 |
setattr(self, p, state[p]) |
373 |
|
374 |
def lj_check(self): |
375 |
try:
|
376 |
import asap3 |
377 |
except ImportError: |
378 |
oops("ASAP is not installed. (Failed to import asap3)")
|
379 |
return False |
380 |
if not hasattr(self, "lj_parameters"): |
381 |
oops("You must set up the Lennard-Jones parameters")
|
382 |
return False |
383 |
try:
|
384 |
self.atoms.set_calculator(asap3.LennardJones(**self.lj_parameters)) |
385 |
except (asap3.AsapError, TypeError, ValueError), e: |
386 |
oops("Could not create useful Lennard-Jones calculator.",
|
387 |
str(e))
|
388 |
return False |
389 |
return True |
390 |
|
391 |
def choose_lj(self): |
392 |
# Define a function on the fly!
|
393 |
import asap3 |
394 |
def lj_factory(p=self.lj_parameters, lj=asap3.LennardJones): |
395 |
return lj(**p)
|
396 |
self.gui.simulation["calc"] = lj_factory |
397 |
|
398 |
def emt_get(self): |
399 |
import asap3 |
400 |
provider_name = self.emt_setup.get_active_text()
|
401 |
provider = self.emt_param_info[provider_name]
|
402 |
if provider is not None: |
403 |
provider = getattr(asap3, provider)
|
404 |
return (asap3.EMT, provider, asap3)
|
405 |
|
406 |
def emt_check(self): |
407 |
if not self.get_atoms(): |
408 |
return False |
409 |
try:
|
410 |
emt, provider, asap3 = self.emt_get()
|
411 |
except ImportError: |
412 |
oops("ASAP is not installed. (Failed to import asap3)")
|
413 |
return False |
414 |
try:
|
415 |
if provider is not None: |
416 |
self.atoms.set_calculator(emt(provider()))
|
417 |
else:
|
418 |
self.atoms.set_calculator(emt())
|
419 |
except (asap3.AsapError, TypeError, ValueError), e: |
420 |
oops("Could not attach EMT calculator to the atoms.",
|
421 |
str(e))
|
422 |
return False |
423 |
return True |
424 |
|
425 |
def choose_emt(self): |
426 |
emt, provider, asap3 = self.emt_get()
|
427 |
if provider is None: |
428 |
emt_factory = emt |
429 |
else:
|
430 |
def emt_factory(emt=emt, prov=provider): |
431 |
return emt(prov())
|
432 |
self.gui.simulation["calc"] = emt_factory |
433 |
|
434 |
def aseemt_check(self): |
435 |
return self.element_check("ASE EMT", ['H', 'Al', 'Cu', 'Ag', 'Au', |
436 |
'Ni', 'Pd', 'Pt', 'C', 'N', 'O']) |
437 |
|
438 |
def choose_aseemt(self): |
439 |
self.gui.simulation["calc"] = ase.EMT |
440 |
ase.EMT.disabled = False # In case Asap has been imported. |
441 |
|
442 |
def brenner_check(self): |
443 |
try:
|
444 |
import asap3 |
445 |
except ImportError: |
446 |
oops("ASAP is not installed. (Failed to import asap3)")
|
447 |
return False |
448 |
return self.element_check("Brenner potential", ['H', 'C', 'Si']) |
449 |
|
450 |
def choose_brenner(self): |
451 |
import asap3 |
452 |
self.gui.simulation["calc"] = asap3.BrennerPotential |
453 |
|
454 |
def choose_aseemt(self): |
455 |
self.gui.simulation["calc"] = ase.EMT |
456 |
ase.EMT.disabled = False # In case Asap has been imported. |
457 |
|
458 |
def gpaw_check(self): |
459 |
try:
|
460 |
import gpaw |
461 |
except ImportError: |
462 |
oops("GPAW is not installed. (Failed to import gpaw)")
|
463 |
return False |
464 |
if not hasattr(self, "gpaw_parameters"): |
465 |
oops("You must set up the GPAW parameters")
|
466 |
return False |
467 |
return True |
468 |
|
469 |
def choose_gpaw(self): |
470 |
# This reuses the same GPAW object.
|
471 |
try:
|
472 |
import gpaw |
473 |
except ImportError: |
474 |
oops("GPAW is not installed. (Failed to import gpaw)")
|
475 |
return False |
476 |
p = self.gpaw_parameters
|
477 |
use = ["xc", "kpts", "mode"] |
478 |
if p["use_h"]: |
479 |
use.append("h")
|
480 |
else:
|
481 |
use.append("gpts")
|
482 |
if p["mode"] == "lcao": |
483 |
use.append("basis")
|
484 |
gpaw_param = {} |
485 |
for s in use: |
486 |
gpaw_param[s] = p[s] |
487 |
if p["use mixer"]: |
488 |
mx = getattr(gpaw, p["mixer"]) |
489 |
mx_args = {} |
490 |
mx_arg_n = ["beta", "nmaxold", "weight"] |
491 |
if p["mixer"] == "MixerDiff": |
492 |
mx_arg_n.extend(["beta_m", "nmaxold_m", "weight_m"]) |
493 |
for s in mx_arg_n: |
494 |
mx_args[s] = p[s] |
495 |
gpaw_param["mixer"] = mx(**mx_args)
|
496 |
progress = GpawProgressIndicator() |
497 |
self.gui.simulation["progress"] = progress |
498 |
gpaw_param["txt"] = progress.get_gpaw_stream()
|
499 |
gpaw_calc = gpaw.GPAW(**gpaw_param) |
500 |
def gpaw_factory(calc = gpaw_calc): |
501 |
return calc
|
502 |
self.gui.simulation["calc"] = gpaw_factory |
503 |
|
504 |
def aims_check(self): |
505 |
if not hasattr(self, "aims_parameters"): |
506 |
oops("You must set up the FHI-aims parameters")
|
507 |
return False |
508 |
return True |
509 |
|
510 |
def choose_aims(self): |
511 |
param = self.aims_parameters
|
512 |
from ase.calculators.aims import Aims |
513 |
calc_aims = Aims(**param) |
514 |
def aims_factory(calc = calc_aims): |
515 |
return calc
|
516 |
self.gui.simulation["calc"] = aims_factory |
517 |
|
518 |
def vasp_check(self): |
519 |
if not hasattr(self, "vasp_parameters"): |
520 |
oops("You must set up the VASP parameters")
|
521 |
return False |
522 |
return True |
523 |
|
524 |
def choose_vasp(self): |
525 |
param = self.vasp_parameters
|
526 |
from ase.calculators.vasp import Vasp |
527 |
calc_vasp = Vasp(**param) |
528 |
def vasp_factory(calc = calc_vasp): |
529 |
return calc
|
530 |
self.gui.simulation["calc"] = vasp_factory |
531 |
|
532 |
def element_check(self, name, elements): |
533 |
"Check that all atoms are allowed"
|
534 |
elements = [ase.data.atomic_numbers[s] for s in elements] |
535 |
elements_dict = {} |
536 |
for e in elements: |
537 |
elements_dict[e] = True
|
538 |
if not self.get_atoms(): |
539 |
return False |
540 |
try:
|
541 |
for e in self.atoms.get_atomic_numbers(): |
542 |
elements_dict[e] |
543 |
except KeyError: |
544 |
oops("Element %s is not allowed by the '%s' calculator"
|
545 |
% (ase.data.chemical_symbols[e], name)) |
546 |
return False |
547 |
return True |
548 |
|
549 |
class InfoButton(gtk.Button): |
550 |
def __init__(self, txt): |
551 |
gtk.Button.__init__(self, "Info") |
552 |
self.txt = txt
|
553 |
self.connect('clicked', self.run) |
554 |
|
555 |
def run(self, widget): |
556 |
dialog = gtk.MessageDialog(flags=gtk.DIALOG_MODAL, |
557 |
type=gtk.MESSAGE_INFO, |
558 |
buttons=gtk.BUTTONS_CLOSE) |
559 |
dialog.set_markup(self.txt)
|
560 |
dialog.connect('response', lambda x, y: dialog.destroy()) |
561 |
dialog.show() |
562 |
|
563 |
|
564 |
class LJ_Window(gtk.Window): |
565 |
def __init__(self, owner, param, attrname): |
566 |
gtk.Window.__init__(self)
|
567 |
self.set_title("Lennard-Jones parameters") |
568 |
self.owner = owner
|
569 |
self.attrname = attrname
|
570 |
atoms = owner.atoms |
571 |
atnos = atoms.get_atomic_numbers() |
572 |
found = {} |
573 |
for z in atnos: |
574 |
found[z] = True
|
575 |
self.present = found.keys()
|
576 |
self.present.sort() # Sorted list of atomic numbers |
577 |
nelem = len(self.present) |
578 |
vbox = gtk.VBox() |
579 |
label = gtk.Label("Specify the Lennard-Jones parameters here")
|
580 |
pack(vbox, [label]) |
581 |
pack(vbox, gtk.Label(""))
|
582 |
pack(vbox, [gtk.Label("Epsilon (eV):")])
|
583 |
tbl, self.epsilon_adj = self.makematrix(self.present) |
584 |
pack(vbox, [tbl]) |
585 |
pack(vbox, gtk.Label(""))
|
586 |
pack(vbox, [gtk.Label("Sigma (Å):")])
|
587 |
tbl, self.sigma_adj = self.makematrix(self.present) |
588 |
pack(vbox, [tbl]) |
589 |
self.modif = gtk.CheckButton("Shift to make smooth at cutoff") |
590 |
self.modif.set_active(True) |
591 |
pack(vbox, gtk.Label(""))
|
592 |
pack(vbox, self.modif)
|
593 |
pack(vbox, gtk.Label(""))
|
594 |
butbox = gtk.HButtonBox() |
595 |
cancel_but = gtk.Button(stock=gtk.STOCK_CANCEL) |
596 |
cancel_but.connect('clicked', lambda widget: self.destroy()) |
597 |
ok_but = gtk.Button(stock=gtk.STOCK_OK) |
598 |
ok_but.connect('clicked', self.ok) |
599 |
butbox.pack_start(cancel_but, 0, 0) |
600 |
butbox.pack_start(ok_but, 0, 0) |
601 |
butbox.show_all() |
602 |
pack(vbox, [butbox], end=True, bottom=True) |
603 |
vbox.show() |
604 |
self.add(vbox)
|
605 |
|
606 |
# Now, set the parameters
|
607 |
if param and param['elements'] == self.present: |
608 |
self.set_param(self.epsilon_adj, param["epsilon"], nelem) |
609 |
self.set_param(self.sigma_adj, param["sigma"], nelem) |
610 |
self.modif.set_active(param["modified"]) |
611 |
|
612 |
self.show()
|
613 |
self.grab_add() # Lock all other windows |
614 |
|
615 |
def makematrix(self, present): |
616 |
nelem = len(present)
|
617 |
adjdict = {} |
618 |
tbl = gtk.Table(2+nelem, 2+nelem) |
619 |
for i in range(nelem): |
620 |
s = chemical_symbols[present[i]] |
621 |
tbl.attach(gtk.Label(" " + str(present[i])), 0, 1, i, i+1) |
622 |
tbl.attach(gtk.Label(" "+s+" "), 1, 2, i, i+1) |
623 |
tbl.attach(gtk.Label(str(present[i])), i+2, i+3, 1+nelem, 2+nelem) |
624 |
tbl.attach(gtk.Label(s), i+2, i+3, nelem, 1+nelem) |
625 |
for j in range(i+1): |
626 |
adj = gtk.Adjustment(1.0, 0.0, 100.0, 0.1) |
627 |
spin = gtk.SpinButton(adj, 0.1, 3) |
628 |
tbl.attach(spin, 2+j, 3+j, i, i+1) |
629 |
adjdict[(i,j)] = adj |
630 |
tbl.show_all() |
631 |
return tbl, adjdict
|
632 |
|
633 |
def set_param(self, adj, params, n): |
634 |
for i in range(n): |
635 |
for j in range(n): |
636 |
if j <= i:
|
637 |
adj[(i,j)].value = params[i,j] |
638 |
|
639 |
def get_param(self, adj, params, n): |
640 |
for i in range(n): |
641 |
for j in range(n): |
642 |
if j <= i:
|
643 |
params[i,j] = params[j,i] = adj[(i,j)].value |
644 |
|
645 |
|
646 |
def destroy(self): |
647 |
self.grab_remove()
|
648 |
gtk.Window.destroy(self)
|
649 |
|
650 |
def ok(self, *args): |
651 |
params = {} |
652 |
params["elements"] = copy(self.present) |
653 |
n = len(self.present) |
654 |
eps = np.zeros((n,n)) |
655 |
self.get_param(self.epsilon_adj, eps, n) |
656 |
sigma = np.zeros((n,n)) |
657 |
self.get_param(self.sigma_adj, sigma, n) |
658 |
params["epsilon"] = eps
|
659 |
params["sigma"] = sigma
|
660 |
params["modified"] = self.modif.get_active() |
661 |
setattr(self.owner, self.attrname, params) |
662 |
self.destroy()
|
663 |
|
664 |
|
665 |
class GPAW_Window(gtk.Window): |
666 |
gpaw_xc_list = ['LDA', 'PBE', 'RPBE', 'revPBE'] |
667 |
gpaw_xc_default = 'PBE'
|
668 |
def __init__(self, owner, param, attrname): |
669 |
gtk.Window.__init__(self)
|
670 |
self.set_title("GPAW parameters") |
671 |
self.owner = owner
|
672 |
self.attrname = attrname
|
673 |
atoms = owner.atoms |
674 |
self.ucell = atoms.get_cell()
|
675 |
self.size = tuple([self.ucell[i,i] for i in range(3)]) |
676 |
self.pbc = atoms.get_pbc()
|
677 |
self.orthogonal = self.isorthogonal(self.ucell) |
678 |
self.natoms = len(atoms) |
679 |
|
680 |
vbox = gtk.VBox() |
681 |
#label = gtk.Label("Specify the GPAW parameters here")
|
682 |
#pack(vbox, [label])
|
683 |
|
684 |
# Print some info
|
685 |
txt = "%i atoms.\n" % (self.natoms,) |
686 |
if self.orthogonal: |
687 |
txt += "Orthogonal unit cell: %.2f x %.2f x %.2f Å." % self.size |
688 |
else:
|
689 |
txt += "Non-orthogonal unit cell:\n"
|
690 |
txt += str(self.ucell) |
691 |
pack(vbox, [gtk.Label(txt)]) |
692 |
|
693 |
# XC potential
|
694 |
self.xc = gtk.combo_box_new_text()
|
695 |
for i, x in enumerate(self.gpaw_xc_list): |
696 |
self.xc.append_text(x)
|
697 |
if x == self.gpaw_xc_default: |
698 |
self.xc.set_active(i)
|
699 |
pack(vbox, [gtk.Label("Exchange-correlation functional: "),
|
700 |
self.xc])
|
701 |
|
702 |
# Grid spacing
|
703 |
self.radio_h = gtk.RadioButton(None, "Grid spacing") |
704 |
self.h = gtk.Adjustment(0.18, 0.0, 1.0, 0.01) |
705 |
self.h_spin = gtk.SpinButton(self.h, 0, 2) |
706 |
pack(vbox, [self.radio_h, gtk.Label(" h = "), self.h_spin, |
707 |
gtk.Label("Å")])
|
708 |
self.radio_gpts = gtk.RadioButton(self.radio_h, "Grid points") |
709 |
self.gpts = []
|
710 |
self.gpts_spin = []
|
711 |
for i in range(3): |
712 |
g = gtk.Adjustment(4, 4, 1000, 4) |
713 |
s = gtk.SpinButton(g, 0, 0) |
714 |
self.gpts.append(g)
|
715 |
self.gpts_spin.append(s)
|
716 |
self.gpts_hlabel = gtk.Label("") |
717 |
self.gpts_hlabel_format = "h<sub>eff</sub> = (%.3f, %.3f, %.3f) Å" |
718 |
pack(vbox, [self.radio_gpts, gtk.Label(" gpts = ("), self.gpts_spin[0], |
719 |
gtk.Label(", "), self.gpts_spin[1], gtk.Label(", "), |
720 |
self.gpts_spin[2], gtk.Label(") "), self.gpts_hlabel]) |
721 |
self.radio_h.connect("toggled", self.radio_grid_toggled) |
722 |
self.radio_gpts.connect("toggled", self.radio_grid_toggled) |
723 |
self.radio_grid_toggled(None) |
724 |
for g in self.gpts: |
725 |
g.connect("value-changed", self.gpts_changed) |
726 |
self.h.connect("value-changed", self.h_changed) |
727 |
|
728 |
# K-points
|
729 |
self.kpts = []
|
730 |
self.kpts_spin = []
|
731 |
for i in range(3): |
732 |
if self.pbc[i] and self.orthogonal: |
733 |
default = np.ceil(20.0 / self.size[i]) |
734 |
else:
|
735 |
default = 1
|
736 |
g = gtk.Adjustment(default, 1, 100, 1) |
737 |
s = gtk.SpinButton(g, 0, 0) |
738 |
self.kpts.append(g)
|
739 |
self.kpts_spin.append(s)
|
740 |
if not self.pbc[i]: |
741 |
s.set_sensitive(False)
|
742 |
g.connect("value-changed", self.k_changed) |
743 |
pack(vbox, [gtk.Label("k-points k = ("), self.kpts_spin[0], |
744 |
gtk.Label(", "), self.kpts_spin[1], gtk.Label(", "), |
745 |
self.kpts_spin[2], gtk.Label(")")]) |
746 |
self.kpts_label = gtk.Label("") |
747 |
self.kpts_label_format = "k-points x size: (%.1f, %.1f, %.1f) Å" |
748 |
pack(vbox, [self.kpts_label])
|
749 |
self.k_changed()
|
750 |
|
751 |
# Spin polarized
|
752 |
self.spinpol = gtk.CheckButton("Spin polarized") |
753 |
pack(vbox, [self.spinpol])
|
754 |
pack(vbox, gtk.Label(""))
|
755 |
|
756 |
# Mode and basis functions
|
757 |
self.mode = gtk.combo_box_new_text()
|
758 |
self.mode.append_text("FD - Finite Difference (grid) mode") |
759 |
self.mode.append_text("LCAO - Linear Combination of Atomic Orbitals") |
760 |
self.mode.set_active(0) |
761 |
pack(vbox, [gtk.Label("Mode: "), self.mode]) |
762 |
self.basis = gtk.combo_box_new_text()
|
763 |
self.basis.append_text("sz - Single Zeta") |
764 |
self.basis.append_text("szp - Single Zeta polarized") |
765 |
self.basis.append_text("dzp - Double Zeta polarized") |
766 |
self.basis.set_active(2) # dzp |
767 |
pack(vbox, [gtk.Label("Basis functions: "), self.basis]) |
768 |
pack(vbox, gtk.Label(""))
|
769 |
self.mode.connect("changed", self.mode_changed) |
770 |
self.mode_changed()
|
771 |
|
772 |
# Mixer
|
773 |
self.use_mixer = gtk.CheckButton("Non-standard mixer parameters") |
774 |
pack(vbox, [self.use_mixer])
|
775 |
self.radio_mixer = gtk.RadioButton(None, "Mixer ") |
776 |
self.radio_mixersum = gtk.RadioButton(self.radio_mixer, "MixerSum ") |
777 |
self.radio_mixerdiff = gtk.RadioButton(self.radio_mixer, "MixerDiff") |
778 |
pack(vbox, [self.radio_mixer, self.radio_mixersum, |
779 |
self.radio_mixerdiff])
|
780 |
self.beta_adj = gtk.Adjustment(0.25, 0.0, 1.0, 0.05) |
781 |
self.beta_spin = gtk.SpinButton(self.beta_adj, 0, 2) |
782 |
self.nmaxold_adj = gtk.Adjustment(3, 1, 10, 1) |
783 |
self.nmaxold_spin = gtk.SpinButton(self.nmaxold_adj, 0, 0) |
784 |
self.weight_adj = gtk.Adjustment(50, 1, 500, 1) |
785 |
self.weight_spin = gtk.SpinButton(self.weight_adj, 0, 0) |
786 |
pack(vbox, [gtk.Label("beta = "), self.beta_spin, |
787 |
gtk.Label(" nmaxold = "), self.nmaxold_spin, |
788 |
gtk.Label(" weight = "), self.weight_spin]) |
789 |
self.beta_m_adj = gtk.Adjustment(0.70, 0.0, 1.0, 0.05) |
790 |
self.beta_m_spin = gtk.SpinButton(self.beta_m_adj, 0, 2) |
791 |
self.nmaxold_m_adj = gtk.Adjustment(2, 1, 10, 1) |
792 |
self.nmaxold_m_spin = gtk.SpinButton(self.nmaxold_m_adj, 0, 0) |
793 |
self.weight_m_adj = gtk.Adjustment(10, 1, 500, 1) |
794 |
self.weight_m_spin = gtk.SpinButton(self.weight_m_adj, 0, 0) |
795 |
pack(vbox, [gtk.Label("beta_m = "), self.beta_m_spin, |
796 |
gtk.Label(" nmaxold_m = "), self.nmaxold_m_spin, |
797 |
gtk.Label(" weight_m = "), self.weight_m_spin]) |
798 |
for but in (self.spinpol, self.use_mixer, self.radio_mixer, |
799 |
self.radio_mixersum, self.radio_mixerdiff): |
800 |
but.connect("clicked", self.mixer_changed) |
801 |
self.mixer_changed()
|
802 |
|
803 |
# Eigensolver
|
804 |
# Poisson-solver
|
805 |
|
806 |
vbox.show() |
807 |
self.add(vbox)
|
808 |
|
809 |
# Buttons at the bottom
|
810 |
pack(vbox, gtk.Label(""))
|
811 |
butbox = gtk.HButtonBox() |
812 |
cancel_but = gtk.Button(stock=gtk.STOCK_CANCEL) |
813 |
cancel_but.connect('clicked', lambda widget: self.destroy()) |
814 |
ok_but = gtk.Button(stock=gtk.STOCK_OK) |
815 |
ok_but.connect('clicked', self.ok) |
816 |
butbox.pack_start(cancel_but, 0, 0) |
817 |
butbox.pack_start(ok_but, 0, 0) |
818 |
butbox.show_all() |
819 |
pack(vbox, [butbox], end=True, bottom=True) |
820 |
|
821 |
# Set stored parameters
|
822 |
if param:
|
823 |
self.xc.set_active(param["xc#"]) |
824 |
if param["use_h"]: |
825 |
self.radio_h.set_active(True) |
826 |
else:
|
827 |
self.radio_gpts.set_active(True) |
828 |
for i in range(3): |
829 |
self.gpts[i].value = param["gpts"][i] |
830 |
self.kpts[i].value = param["kpts"][i] |
831 |
self.spinpol.set_active(param["spinpol"]) |
832 |
self.mode.set_active(param["mode#"]) |
833 |
self.basis.set_active(param["basis#"]) |
834 |
self.use_mixer.set_active(param["use mixer"]) |
835 |
getattr(self, "radio_"+param["mixer"].lower()).set_active(True) |
836 |
for t in ("beta", "nmaxold", "weight", "beta_m", "nmaxold_m", |
837 |
"weight_m"):
|
838 |
getattr(self, t+"_adj").value = param[t] |
839 |
|
840 |
self.show()
|
841 |
self.grab_add() # Lock all other windows |
842 |
|
843 |
def radio_grid_toggled(self, widget): |
844 |
hmode = self.radio_h.get_active()
|
845 |
self.h_spin.set_sensitive(hmode)
|
846 |
for s in self.gpts_spin: |
847 |
s.set_sensitive(not hmode)
|
848 |
self.gpts_changed()
|
849 |
|
850 |
def gpts_changed(self, *args): |
851 |
if self.radio_gpts.get_active(): |
852 |
g = np.array([int(g.value) for g in self.gpts]) |
853 |
size = np.array([self.ucell[i,i] for i in range(3)]) |
854 |
txt = self.gpts_hlabel_format % tuple(size / g) |
855 |
self.gpts_hlabel.set_markup(txt)
|
856 |
else:
|
857 |
self.gpts_hlabel.set_markup("") |
858 |
|
859 |
def h_changed(self, *args): |
860 |
h = self.h.value
|
861 |
for i in range(3): |
862 |
g = 4 * round(self.ucell[i,i] / (4*h)) |
863 |
self.gpts[i].value = g
|
864 |
|
865 |
def k_changed(self, *args): |
866 |
if self.orthogonal: |
867 |
size = [self.kpts[i].value * self.size[i] for i in range(3)] |
868 |
self.kpts_label.set_text(self.kpts_label_format % tuple(size)) |
869 |
|
870 |
def mode_changed(self, *args): |
871 |
self.basis.set_sensitive(self.mode.get_active() == 1) |
872 |
|
873 |
def mixer_changed(self, *args): |
874 |
radios = (self.radio_mixer, self.radio_mixersum, self.radio_mixerdiff) |
875 |
spin1 = (self.beta_spin, self.nmaxold_spin, self.weight_spin) |
876 |
spin2 = (self.beta_m_spin, self.nmaxold_m_spin, self.weight_m_spin) |
877 |
if self.use_mixer.get_active(): |
878 |
# Mixer parameters can be specified.
|
879 |
if self.spinpol.get_active(): |
880 |
self.radio_mixer.set_sensitive(False) |
881 |
self.radio_mixersum.set_sensitive(True) |
882 |
self.radio_mixerdiff.set_sensitive(True) |
883 |
if self.radio_mixer.get_active(): |
884 |
self.radio_mixersum.set_active(True) |
885 |
else:
|
886 |
self.radio_mixer.set_sensitive(True) |
887 |
self.radio_mixersum.set_sensitive(False) |
888 |
self.radio_mixerdiff.set_sensitive(False) |
889 |
self.radio_mixer.set_active(True) |
890 |
if self.radio_mixerdiff.get_active(): |
891 |
active = spin1 + spin2 |
892 |
passive = () |
893 |
else:
|
894 |
active = spin1 |
895 |
passive = spin2 |
896 |
for widget in active: |
897 |
widget.set_sensitive(True)
|
898 |
for widget in passive: |
899 |
widget.set_sensitive(False)
|
900 |
else:
|
901 |
# No mixer parameters
|
902 |
for widget in radios + spin1 + spin2: |
903 |
widget.set_sensitive(False)
|
904 |
|
905 |
def isorthogonal(self, matrix): |
906 |
ortho = True
|
907 |
for i in range(3): |
908 |
for j in range(3): |
909 |
if i != j and matrix[i][j] != 0.0: |
910 |
ortho = False
|
911 |
return ortho
|
912 |
|
913 |
def ok(self, *args): |
914 |
param = {} |
915 |
param["xc"] = self.xc.get_active_text() |
916 |
param["xc#"] = self.xc.get_active() |
917 |
param["use_h"] = self.radio_h.get_active() |
918 |
param["h"] = self.h.value |
919 |
param["gpts"] = [int(g.value) for g in self.gpts] |
920 |
param["kpts"] = [int(k.value) for k in self.kpts] |
921 |
param["spinpol"] = self.spinpol.get_active() |
922 |
param["mode"] = self.mode.get_active_text().split()[0].lower() |
923 |
param["mode#"] = self.mode.get_active() |
924 |
param["basis"] = self.basis.get_active_text().split()[0].lower() |
925 |
param["basis#"] = self.basis.get_active() |
926 |
param["use mixer"] = self.use_mixer.get_active() |
927 |
if self.radio_mixer.get_active(): |
928 |
m = "Mixer"
|
929 |
elif self.radio_mixersum.get_active(): |
930 |
m = "MixerSum"
|
931 |
else:
|
932 |
assert self.radio_mixerdiff.get_active() |
933 |
m = "MixerDiff"
|
934 |
param["mixer"] = m
|
935 |
for t in ("beta", "nmaxold", "weight", "beta_m", "nmaxold_m", |
936 |
"weight_m"):
|
937 |
param[t] = getattr(self, t+"_adj").value |
938 |
setattr(self.owner, self.attrname, param) |
939 |
self.destroy()
|
940 |
|
941 |
class AIMS_Window(gtk.Window): |
942 |
aims_xc_cluster = ['pw-lda','pz-lda','pbe','pbesol','rpbe','revpbe', |
943 |
'blyp','am05','b3lyp','hse03','hse06','pbe0','pbesol0', |
944 |
'hf','mp2'] |
945 |
aims_xc_periodic = ['pw-lda','pz-lda','pbe','pbesol','rpbe','revpbe', |
946 |
'blyp','am05'] |
947 |
aims_xc_default = 'pbe'
|
948 |
aims_relativity_list = ['none','atomic_zora','zora'] |
949 |
aims_keyword_gui_list = ['xc','vdw_correction_hirshfeld','k_grid','spin','charge','relativistic', |
950 |
'sc_accuracy_etot','sc_accuracy_eev','sc_accuracy_rho','sc_accuracy_forces', |
951 |
'compute_forces','run_command','species_dir'] |
952 |
def __init__(self, owner, param, attrname): |
953 |
self.owner = owner
|
954 |
self.attrname = attrname
|
955 |
atoms = owner.atoms |
956 |
self.periodic = atoms.get_pbc().all()
|
957 |
if not self.periodic and atoms.get_pbc().any(): |
958 |
aims_periodic_warning = True
|
959 |
self.periodic = True |
960 |
else:
|
961 |
aims_periodic_warning = False
|
962 |
from ase.calculators.aims import float_keys,exp_keys,string_keys,int_keys,bool_keys,list_keys,input_keys |
963 |
self.aims_keyword_list =float_keys+exp_keys+string_keys+int_keys+bool_keys+list_keys+input_keys
|
964 |
self.expert_keywords = []
|
965 |
|
966 |
natoms = len(atoms)
|
967 |
gtk.Window.__init__(self)
|
968 |
self.set_title("FHI-aims parameters") |
969 |
vbox = gtk.VBox() |
970 |
# Print some info
|
971 |
txt = "%i atoms.\n" % (natoms)
|
972 |
if self.periodic: |
973 |
self.ucell = atoms.get_cell()
|
974 |
txt += "Periodic geometry, unit cell is: \n"
|
975 |
for i in range(3): |
976 |
txt += "(%8.3f %8.3f %8.3f)\n" % (self.ucell[i][0], self.ucell[i][1], self.ucell[i][2]) |
977 |
self.xc_list = self.aims_xc_periodic |
978 |
else:
|
979 |
txt += "Non-periodic geometry. \n"
|
980 |
self.xc_list = self.aims_xc_cluster |
981 |
pack(vbox, [gtk.Label(txt)]) |
982 |
|
983 |
# XC functional & dispersion correction
|
984 |
self.xc = gtk.combo_box_new_text()
|
985 |
self.xc_setup = False |
986 |
self.TS = gtk.CheckButton("Hirshfeld-based dispersion correction") |
987 |
pack(vbox, [gtk.Label("Exchange-correlation functional: "),self.xc]) |
988 |
pack(vbox, [self.TS])
|
989 |
pack(vbox, [gtk.Label("")])
|
990 |
|
991 |
# k-grid?
|
992 |
if self.periodic: |
993 |
self.kpts = []
|
994 |
self.kpts_spin = []
|
995 |
for i in range(3): |
996 |
default = np.ceil(20.0 / np.sqrt(np.vdot(self.ucell[i],self.ucell[i]))) |
997 |
g = gtk.Adjustment(default, 1, 100, 1) |
998 |
s = gtk.SpinButton(g, 0, 0) |
999 |
self.kpts.append(g)
|
1000 |
self.kpts_spin.append(s)
|
1001 |
g.connect("value-changed", self.k_changed) |
1002 |
pack(vbox, [gtk.Label("k-points k = ("), self.kpts_spin[0], |
1003 |
gtk.Label(", "), self.kpts_spin[1], gtk.Label(", "), |
1004 |
self.kpts_spin[2], gtk.Label(")")]) |
1005 |
self.kpts_label = gtk.Label("") |
1006 |
self.kpts_label_format = "k-points x size: (%.1f, %.1f, %.1f) Å" |
1007 |
pack(vbox, [self.kpts_label])
|
1008 |
self.k_changed()
|
1009 |
pack(vbox, gtk.Label(""))
|
1010 |
|
1011 |
# Spin polarized, charge, relativity
|
1012 |
self.spinpol = gtk.CheckButton("Spin polarized") |
1013 |
self.charge = gtk.Adjustment(0,-100,100,0.1) |
1014 |
self.charge_spin = gtk.SpinButton(self.charge, 0, 0) |
1015 |
self.charge_spin.set_digits(2) |
1016 |
self.relativity_type = gtk.combo_box_new_text()
|
1017 |
for i, x in enumerate(self.aims_relativity_list): |
1018 |
self.relativity_type.append_text(x)
|
1019 |
self.relativity_type.connect('changed',self.relativity_changed) |
1020 |
self.relativity_threshold = gtk.Entry(max=8) |
1021 |
self.relativity_threshold.set_text('1.00e-12') |
1022 |
self.relativity_threshold.set_sensitive(False) |
1023 |
pack(vbox, [self.spinpol,
|
1024 |
gtk.Label(" Charge"),
|
1025 |
self.charge_spin,
|
1026 |
gtk.Label(" Relativity"),
|
1027 |
self.relativity_type,
|
1028 |
gtk.Label(" Threshold"),
|
1029 |
self.relativity_threshold])
|
1030 |
pack(vbox, gtk.Label(""))
|
1031 |
|
1032 |
# self-consistency criteria
|
1033 |
pack(vbox,[gtk.Label("Self-consistency convergence:")])
|
1034 |
self.sc_tot_energy = gtk.Adjustment(1e-6, 1e-6, 1e0, 1e-6) |
1035 |
self.sc_tot_energy_spin = gtk.SpinButton(self.sc_tot_energy, 0, 0) |
1036 |
self.sc_tot_energy_spin.set_digits(6) |
1037 |
self.sc_tot_energy_spin.set_numeric(True) |
1038 |
self.sc_sum_eigenvalue = gtk.Adjustment(1e-3, 1e-6, 1e0, 1e-6) |
1039 |
self.sc_sum_eigenvalue_spin = gtk.SpinButton(self.sc_sum_eigenvalue, 0, 0) |
1040 |
self.sc_sum_eigenvalue_spin.set_digits(6) |
1041 |
self.sc_sum_eigenvalue_spin.set_numeric(True) |
1042 |
self.sc_density = gtk.Adjustment(1e-4, 1e-6, 1e0, 1e-6) |
1043 |
self.sc_density_spin = gtk.SpinButton(self.sc_density, 0, 0) |
1044 |
self.sc_density_spin.set_digits(6) |
1045 |
self.sc_density_spin.set_numeric(True) |
1046 |
self.compute_forces = gtk.CheckButton("Compute forces") |
1047 |
self.compute_forces.set_active(True) |
1048 |
self.compute_forces.connect("toggled", self.compute_forces_toggled,"") |
1049 |
self.sc_forces = gtk.Adjustment(1e-4, 1e-6, 1e0, 1e-6) |
1050 |
self.sc_forces_spin = gtk.SpinButton(self.sc_forces, 0, 0) |
1051 |
self.sc_forces_spin.set_numeric(True) |
1052 |
self.sc_forces_spin.set_digits(6) |
1053 |
pack(vbox, [gtk.Label("Energy: "),
|
1054 |
self.sc_tot_energy_spin,
|
1055 |
gtk.Label(" eV Sum of eigenvalues: "),
|
1056 |
self.sc_sum_eigenvalue_spin,
|
1057 |
gtk.Label(" eV")])
|
1058 |
pack(vbox, [gtk.Label("Electron density: "),
|
1059 |
self.sc_density_spin,
|
1060 |
gtk.Label(" Force convergence: "),
|
1061 |
self.sc_forces_spin,
|
1062 |
gtk.Label(" eV/Ang ")])
|
1063 |
|
1064 |
pack(vbox, [self.compute_forces])
|
1065 |
pack(vbox, gtk.Label(""))
|
1066 |
|
1067 |
self.expert_keyword_set = gtk.Entry(max = 55) |
1068 |
self.expert_keyword_add = gtk.Button(stock = gtk.STOCK_ADD)
|
1069 |
self.expert_keyword_add.connect("clicked", self.expert_keyword_import) |
1070 |
self.expert_keyword_set.connect("activate", self.expert_keyword_import) |
1071 |
pack(vbox,[gtk.Label("Additional keywords: "),
|
1072 |
self.expert_keyword_set,
|
1073 |
self.expert_keyword_add])
|
1074 |
self.expert_vbox = gtk.VBox()
|
1075 |
pack(vbox, self.expert_vbox)
|
1076 |
pack(vbox, gtk.Label(""))
|
1077 |
|
1078 |
# run command and species defaults:
|
1079 |
pack(vbox, gtk.Label('FHI-aims execution command: '))
|
1080 |
self.run_command = pack(vbox, gtk.Entry(max=0)) |
1081 |
pack(vbox, gtk.Label('Directory for species defaults: '))
|
1082 |
self.species_defaults = pack(vbox, gtk.Entry(max=0)) |
1083 |
|
1084 |
# set defaults from previous instance of the calculator, if applicable:
|
1085 |
if param is not None: |
1086 |
self.set_param(param)
|
1087 |
else:
|
1088 |
self.set_defaults()
|
1089 |
|
1090 |
# Buttons at the bottom
|
1091 |
pack(vbox, gtk.Label(""))
|
1092 |
butbox = gtk.HButtonBox() |
1093 |
default_but = gtk.Button("Set Defaults")
|
1094 |
default_but.connect("clicked",self.set_defaults) |
1095 |
import_control_but = gtk.Button("Import control.in")
|
1096 |
import_control_but.connect("clicked",self.import_control) |
1097 |
export_control_but = gtk.Button("Export control.in")
|
1098 |
export_control_but.connect("clicked", self.export_control) |
1099 |
cancel_but = gtk.Button(stock=gtk.STOCK_CANCEL) |
1100 |
cancel_but.connect('clicked', lambda widget: self.destroy()) |
1101 |
ok_but = gtk.Button(stock=gtk.STOCK_OK) |
1102 |
ok_but.connect('clicked', self.ok) |
1103 |
butbox.pack_start(default_but, 0, 0) |
1104 |
butbox.pack_start(import_control_but, 0, 0) |
1105 |
butbox.pack_start(export_control_but, 0, 0) |
1106 |
butbox.pack_start(cancel_but, 0, 0) |
1107 |
butbox.pack_start(ok_but, 0, 0) |
1108 |
butbox.show_all() |
1109 |
pack(vbox, [butbox], end=True, bottom=True) |
1110 |
self.expert_vbox.show()
|
1111 |
vbox.show() |
1112 |
self.add(vbox)
|
1113 |
self.show()
|
1114 |
self.grab_add()
|
1115 |
if aims_periodic_warning:
|
1116 |
oops(aims_pbc_warning_text) |
1117 |
|
1118 |
def set_defaults(self, *args): |
1119 |
atoms = self.owner.atoms.copy()
|
1120 |
if not self.xc_setup: |
1121 |
self.xc_setup = True |
1122 |
for i, x in enumerate(self.xc_list): |
1123 |
self.xc.append_text(x)
|
1124 |
for i, x in enumerate(self.xc_list): |
1125 |
if x == self.aims_xc_default: |
1126 |
self.xc.set_active(i)
|
1127 |
self.TS.set_active(False) |
1128 |
if self.periodic: |
1129 |
self.ucell = atoms.get_cell()
|
1130 |
for i in range(3): |
1131 |
default = np.ceil(20.0 / np.sqrt(np.vdot(self.ucell[i],self.ucell[i]))) |
1132 |
self.kpts_spin[i].set_value(default)
|
1133 |
self.spinpol.set_active(False) |
1134 |
self.charge.set_value(0) |
1135 |
aims_relativity_default = 'none'
|
1136 |
for a in atoms: |
1137 |
if a.get_atomic_number() > 20: |
1138 |
aims_relativity_default = 'atomic_zora'
|
1139 |
for i, x in enumerate(self.aims_relativity_list): |
1140 |
if x == aims_relativity_default:
|
1141 |
self.relativity_type.set_active(i)
|
1142 |
self.sc_tot_energy.set_value(1e-6) |
1143 |
self.sc_sum_eigenvalue.set_value(1e-3) |
1144 |
self.sc_density.set_value(1e-4) |
1145 |
self.sc_forces.set_value(1e-4) |
1146 |
for key in self.expert_keywords: |
1147 |
key[0].destroy()
|
1148 |
key[1].destroy()
|
1149 |
key[2].destroy()
|
1150 |
key[3] = False |
1151 |
if os.environ.has_key('AIMS_COMMAND'): |
1152 |
text = os.environ['AIMS_COMMAND']
|
1153 |
else:
|
1154 |
text = ""
|
1155 |
self.run_command.set_text(text)
|
1156 |
if os.environ.has_key('AIMS_SPECIES_DIR'): |
1157 |
text = os.environ['AIMS_SPECIES_DIR']
|
1158 |
else:
|
1159 |
text = ""
|
1160 |
self.species_defaults.set_text(text)
|
1161 |
|
1162 |
def set_attributes(self, *args): |
1163 |
param = {} |
1164 |
param["xc"] = self.xc.get_active_text() |
1165 |
if self.periodic: |
1166 |
param["k_grid"] = (int(self.kpts[0].value), |
1167 |
int(self.kpts[1].value), |
1168 |
int(self.kpts[2].value)) |
1169 |
if self.spinpol.get_active(): |
1170 |
param["spin"] = "collinear" |
1171 |
else:
|
1172 |
param["spin"] = "none" |
1173 |
param["vdw_correction_hirshfeld"] = self.TS.get_active() |
1174 |
param["charge"] = self.charge.value |
1175 |
param["relativistic"] = self.relativity_type.get_active_text() |
1176 |
if param["relativistic"] == 'atomic_zora': |
1177 |
param["relativistic"] += " scalar " |
1178 |
if param["relativistic"] == 'zora': |
1179 |
param["relativistic"] += " scalar "+self.relativity_threshold.get_text() |
1180 |
param["sc_accuracy_etot"] = self.sc_tot_energy.value |
1181 |
param["sc_accuracy_eev"] = self.sc_sum_eigenvalue.value |
1182 |
param["sc_accuracy_rho"] = self.sc_density.value |
1183 |
param["compute_forces"] = self.compute_forces.get_active() |
1184 |
param["sc_accuracy_forces"] = self.sc_forces.value |
1185 |
param["run_command"] = self.run_command.get_text() |
1186 |
param["species_dir"] = self.species_defaults.get_text() |
1187 |
from ase.calculators.aims import float_keys,exp_keys,string_keys,int_keys,bool_keys,list_keys,input_keys |
1188 |
for option in self.expert_keywords: |
1189 |
if option[3]: # set type of parameter accoding to which list it is in |
1190 |
key = option[0].get_text().strip()
|
1191 |
val = option[1].get_text().strip()
|
1192 |
if key == 'output': |
1193 |
if param.has_key('output'): |
1194 |
param[key] += [val] |
1195 |
else:
|
1196 |
param[key] = [val] |
1197 |
elif key in float_keys or key in exp_keys: |
1198 |
param[key] = float(val)
|
1199 |
elif key in list_keys or key in string_keys or key in input_keys: |
1200 |
param[key] = val |
1201 |
elif key in int_keys: |
1202 |
param[key] = int(val)
|
1203 |
elif key in bool_keys: |
1204 |
param[key] = bool(val)
|
1205 |
setattr(self.owner, self.attrname, param) |
1206 |
|
1207 |
def set_param(self, param): |
1208 |
if param["xc"] is not None: |
1209 |
for i, x in enumerate(self.xc_list): |
1210 |
if x == param["xc"]: |
1211 |
self.xc.set_active(i)
|
1212 |
if isinstance(param["vdw_correction_hirshfeld"],bool): |
1213 |
self.TS.set_active(param["vdw_correction_hirshfeld"]) |
1214 |
if self.periodic and param["k_grid"] is not None: |
1215 |
self.kpts[0].value = int(param["k_grid"][0]) |
1216 |
self.kpts[1].value = int(param["k_grid"][1]) |
1217 |
self.kpts[2].value = int(param["k_grid"][2]) |
1218 |
if param["spin"] is not None: |
1219 |
self.spinpol.set_active(param["spin"] == "collinear") |
1220 |
if param["charge"] is not None: |
1221 |
self.charge.value = param["charge"] |
1222 |
if param["relativistic"] is not None: |
1223 |
if isinstance(param["relativistic"],(tuple,list)): |
1224 |
rel = param["relativistic"]
|
1225 |
else:
|
1226 |
rel = param["relativistic"].split()
|
1227 |
for i, x in enumerate(self.aims_relativity_list): |
1228 |
if x == rel[0]: |
1229 |
self.relativity_type.set_active(i)
|
1230 |
if x == 'zora': |
1231 |
self.relativity_threshold.set_text(rel[2]) |
1232 |
self.relativity_threshold.set_sensitive(True) |
1233 |
if param["sc_accuracy_etot"] is not None: |
1234 |
self.sc_tot_energy.value = param["sc_accuracy_etot"] |
1235 |
if param["sc_accuracy_eev"] is not None: |
1236 |
self.sc_sum_eigenvalue.value = param["sc_accuracy_eev"] |
1237 |
if param["sc_accuracy_rho"] is not None: |
1238 |
self.sc_density.value = param["sc_accuracy_rho"] |
1239 |
if param["compute_forces"] is not None: |
1240 |
if param["compute_forces"]: |
1241 |
if param["sc_accuracy_forces"] is not None: |
1242 |
self.sc_forces.value = param["sc_accuracy_forces"] |
1243 |
self.compute_forces.set_active(param["compute_forces"]) |
1244 |
else:
|
1245 |
self.compute_forces.set_active(False) |
1246 |
if param["run_command"] is not None: |
1247 |
self.run_command.set_text(param["run_command"]) |
1248 |
if param["species_dir"] is not None: |
1249 |
self.species_defaults.set_text(param["species_dir"]) |
1250 |
for (key,val) in param.items(): |
1251 |
if key in self.aims_keyword_list and key not in self.aims_keyword_gui_list: |
1252 |
if val is not None: # = existing "expert keyword" |
1253 |
if key == 'output': # 'output' can be used more than once |
1254 |
options = val |
1255 |
if isinstance(options,str): options = [options] |
1256 |
for arg in options: |
1257 |
self.expert_keyword_create([key]+[arg])
|
1258 |
else:
|
1259 |
if isinstance(val,str): |
1260 |
arg = [key]+val.split() |
1261 |
elif isinstance(val,(tuple,list)): |
1262 |
arg = [key]+[str(a) for a in val] |
1263 |
else:
|
1264 |
arg = [key]+[str(val)]
|
1265 |
self.expert_keyword_create(arg)
|
1266 |
|
1267 |
def ok(self, *args): |
1268 |
self.set_attributes(*args)
|
1269 |
self.destroy()
|
1270 |
|
1271 |
def export_control(self, *args): |
1272 |
filename = "control.in"
|
1273 |
chooser = gtk.FileChooserDialog( |
1274 |
'Export parameters ... ', None, gtk.FILE_CHOOSER_ACTION_SAVE, |
1275 |
(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, |
1276 |
gtk.STOCK_SAVE, gtk.RESPONSE_OK)) |
1277 |
chooser.set_filename(filename) |
1278 |
save = chooser.run() |
1279 |
if save == gtk.RESPONSE_OK or save == gtk.RESPONSE_SAVE: |
1280 |
filename = chooser.get_filename() |
1281 |
self.set_attributes(*args)
|
1282 |
param = getattr(self.owner, "aims_parameters") |
1283 |
from ase.calculators.aims import Aims |
1284 |
calc_temp = Aims(**param) |
1285 |
atoms_temp = self.owner.atoms.copy()
|
1286 |
atoms_temp.set_calculator(calc_temp) |
1287 |
atoms_temp.calc.write_control(file = filename) |
1288 |
atoms_temp.calc.write_species(file = filename) |
1289 |
chooser.destroy() |
1290 |
|
1291 |
def import_control(self, *args): |
1292 |
filename = "control.in"
|
1293 |
chooser = gtk.FileChooserDialog( |
1294 |
'Import control.in file ... ', None, gtk.FILE_CHOOSER_ACTION_SAVE, |
1295 |
(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, |
1296 |
gtk.STOCK_SAVE, gtk.RESPONSE_OK)) |
1297 |
chooser.set_filename(filename) |
1298 |
save = chooser.run() |
1299 |
if save == gtk.RESPONSE_OK:
|
1300 |
self.set_defaults()
|
1301 |
filename = chooser.get_filename() |
1302 |
control = open(filename,'r') |
1303 |
while True: |
1304 |
line = control.readline() |
1305 |
if not line: |
1306 |
break
|
1307 |
if "List of parameters used to initialize the calculator:" in line: |
1308 |
control.readline() |
1309 |
from ase.io.aims import read_aims_calculator |
1310 |
calc = read_aims_calculator(control) |
1311 |
found_aims_calculator = True
|
1312 |
control.close() |
1313 |
if found_aims_calculator:
|
1314 |
param = calc.float_params |
1315 |
for key in calc.exp_params: |
1316 |
param[key] = calc.exp_params[key] |
1317 |
for key in calc.string_params: |
1318 |
param[key] = calc.string_params[key] |
1319 |
for key in calc.int_params: |
1320 |
param[key] = calc.int_params[key] |
1321 |
for key in calc.bool_params: |
1322 |
param[key] = calc.bool_params[key] |
1323 |
for key in calc.list_params: |
1324 |
param[key] = calc.list_params[key] |
1325 |
for key in calc.input_parameters: |
1326 |
param[key] = calc.input_parameters[key] |
1327 |
self.set_defaults()
|
1328 |
self.set_param(param)
|
1329 |
chooser.destroy() |
1330 |
|
1331 |
def k_changed(self, *args): |
1332 |
size = [self.kpts[i].value * np.sqrt(np.vdot(self.ucell[i],self.ucell[i])) for i in range(3)] |
1333 |
self.kpts_label.set_text(self.kpts_label_format % tuple(size)) |
1334 |
|
1335 |
def compute_forces_toggled(self, *args): |
1336 |
self.sc_forces_spin.set_sensitive(self.compute_forces.get_active()) |
1337 |
|
1338 |
def relativity_changed(self, *args): |
1339 |
self.relativity_threshold.set_sensitive(self.relativity_type.get_active() == 2) |
1340 |
|
1341 |
def expert_keyword_import(self, *args): |
1342 |
command = self.expert_keyword_set.get_text().split()
|
1343 |
if len(command) > 0 and command[0] in self.aims_keyword_list and not command[0] in self.aims_keyword_gui_list: |
1344 |
self.expert_keyword_create(command)
|
1345 |
elif command[0] in self.aims_keyword_gui_list: |
1346 |
oops("Please use the facilities provided in this window to manipulate "+
|
1347 |
"the keyword:" + command[0] + "!") |
1348 |
else:
|
1349 |
oops("Don't know this keyword:" + command[0] |
1350 |
+ "\nPlease check!\n\n"
|
1351 |
+ "If you really think it should be available, "
|
1352 |
+ "please add it to the top of ase/calculators/aims.py.")
|
1353 |
self.expert_keyword_set.set_text("") |
1354 |
|
1355 |
def expert_keyword_create(self, command): |
1356 |
key = command[0]
|
1357 |
argument = command[1]
|
1358 |
if len(command) > 2: |
1359 |
for a in command[2:]: |
1360 |
argument += ' '+a
|
1361 |
index = len(self.expert_keywords) |
1362 |
self.expert_keywords += [[gtk.Label(" " +key+" "), |
1363 |
gtk.Entry(max=45),
|
1364 |
ExpertDeleteButton(index), |
1365 |
True]]
|
1366 |
self.expert_keywords[index][1].set_text(argument) |
1367 |
self.expert_keywords[index][2].connect('clicked',self.expert_keyword_delete) |
1368 |
pack(self.expert_vbox, [self.expert_keywords[index][0], |
1369 |
self.expert_keywords[index][1], |
1370 |
self.expert_keywords[index][2]]) |
1371 |
|
1372 |
def expert_keyword_delete(self, button, *args): |
1373 |
index = button.index # which one to kill
|
1374 |
for i in [0,1,2]: |
1375 |
self.expert_keywords[index][i].destroy()
|
1376 |
self.expert_keywords[index][3] = False |
1377 |
|
1378 |
|
1379 |
class ExpertDeleteButton(gtk.Button): |
1380 |
def __init__(self, index): |
1381 |
gtk.Button.__init__(self, stock=gtk.STOCK_DELETE)
|
1382 |
alignment = self.get_children()[0] |
1383 |
hbox = alignment.get_children()[0]
|
1384 |
image, label = hbox.get_children() |
1385 |
if image is not None: |
1386 |
label.set_text('')
|
1387 |
self.index = index
|
1388 |
|
1389 |
|
1390 |
class VASP_Window(gtk.Window): |
1391 |
vasp_xc_list = ['PW91', 'PBE', 'LDA'] |
1392 |
vasp_xc_default = 'PBE'
|
1393 |
vasp_prec_default = 'Normal'
|
1394 |
def __init__(self, owner, param, attrname): |
1395 |
self.owner = owner
|
1396 |
self.attrname = attrname
|
1397 |
atoms = owner.atoms |
1398 |
self.periodic = atoms.get_pbc().all()
|
1399 |
self.vasp_keyword_gui_list = ['ediff','encut', 'ismear', 'ispin', 'prec', 'sigma'] |
1400 |
from ase.calculators.vasp import float_keys,exp_keys,string_keys,int_keys,bool_keys,list_keys,special_keys |
1401 |
self.vasp_keyword_list = float_keys+exp_keys+string_keys+int_keys+bool_keys+list_keys+special_keys
|
1402 |
self.expert_keywords = []
|
1403 |
natoms = len(atoms)
|
1404 |
gtk.Window.__init__(self)
|
1405 |
self.set_title("VASP parameters") |
1406 |
vbox = gtk.VBox() |
1407 |
# Print some info
|
1408 |
txt = "%i atoms.\n" % (natoms)
|
1409 |
self.ucell = atoms.get_cell()
|
1410 |
txt += "Periodic geometry, unit cell is: \n"
|
1411 |
for i in range(3): |
1412 |
txt += "(%8.3f %8.3f %8.3f)\n" % (self.ucell[i][0], self.ucell[i][1], self.ucell[i][2]) |
1413 |
pack(vbox, [gtk.Label(txt)]) |
1414 |
|
1415 |
# XC functional ()
|
1416 |
self.xc = gtk.combo_box_new_text()
|
1417 |
for i, x in enumerate(self.vasp_xc_list): |
1418 |
self.xc.append_text(x)
|
1419 |
if x == self.vasp_xc_default: |
1420 |
self.xc.set_active(i)
|
1421 |
|
1422 |
# Spin polarized
|
1423 |
self.spinpol = gtk.CheckButton("Spin polarized") |
1424 |
|
1425 |
pack(vbox, [gtk.Label("Exchange-correlation functional: "),
|
1426 |
self.xc,
|
1427 |
gtk.Label(" "),
|
1428 |
self.spinpol])
|
1429 |
pack(vbox, gtk.Label(""))
|
1430 |
|
1431 |
# k-grid
|
1432 |
self.kpts = []
|
1433 |
self.kpts_spin = []
|
1434 |
for i in range(3): |
1435 |
default = np.ceil(20.0 / np.sqrt(np.vdot(self.ucell[i],self.ucell[i]))) |
1436 |
g = gtk.Adjustment(default, 1, 100, 1) |
1437 |
s = gtk.SpinButton(g, 0, 0) |
1438 |
self.kpts.append(g)
|
1439 |
self.kpts_spin.append(s)
|
1440 |
g.connect("value-changed", self.k_changed) |
1441 |
|
1442 |
# Precision of calculation
|
1443 |
self.prec = gtk.combo_box_new_text()
|
1444 |
for i, x in enumerate(['Low', 'Normal', 'Accurate']): |
1445 |
self.prec.append_text(x)
|
1446 |
if x == self.vasp_prec_default: |
1447 |
self.prec.set_active(i)
|
1448 |
|
1449 |
# cutoff energy
|
1450 |
if os.environ.has_key('VASP_PP_PATH'): |
1451 |
self.encut_min_default, self.encut_max_default = self.get_min_max_cutoff() |
1452 |
else:
|
1453 |
self.encut_max_default = 400.0 |
1454 |
self.encut_min_default = 100.0 |
1455 |
self.encut = gtk.Adjustment(self.encut_max_default, 0, 9999, 10) |
1456 |
self.encut_spin = gtk.SpinButton(self.encut, 0, 0) |
1457 |
self.encut_spin.set_digits(2) |
1458 |
self.encut_spin.connect("value-changed",self.check_encut_warning) |
1459 |
self.encut_warning = gtk.Label("") |
1460 |
|
1461 |
pack(vbox, [gtk.Label("k-points k = ("), self.kpts_spin[0], |
1462 |
gtk.Label(", "), self.kpts_spin[1], gtk.Label(", "), |
1463 |
self.kpts_spin[2], |
1464 |
gtk.Label(") Cutoff: "),self.encut_spin, |
1465 |
gtk.Label(" Precision: "),self.prec]) |
1466 |
self.kpts_label = gtk.Label("") |
1467 |
self.kpts_label_format = "k-points x size: (%.1f, %.1f, %.1f) Å " |
1468 |
pack(vbox, [self.kpts_label, self.encut_warning]) |
1469 |
self.k_changed()
|
1470 |
pack(vbox, gtk.Label(""))
|
1471 |
|
1472 |
self.ismear = gtk.combo_box_new_text()
|
1473 |
for x in ['Fermi', 'Gauss', 'Methfessel-Paxton']: |
1474 |
self.ismear.append_text(x)
|
1475 |
self.ismear.set_active(2) |
1476 |
self.smearing_order = gtk.Adjustment(2,0,9,1) |
1477 |
self.smearing_order_spin = gtk.SpinButton(self.smearing_order,0,0) |
1478 |
self.smearing_order_spin.set_digits(0) |
1479 |
self.ismear.connect("changed", self.check_ismear_changed) |
1480 |
self.sigma = gtk.Adjustment(0.1, 0.001, 9.0, 0.1) |
1481 |
self.sigma_spin = gtk.SpinButton(self.sigma,0,0) |
1482 |
self.sigma_spin.set_digits(3) |
1483 |
pack(vbox, [gtk.Label("Smearing: "),
|
1484 |
self.ismear,
|
1485 |
gtk.Label(" order: "),
|
1486 |
self.smearing_order_spin,
|
1487 |
gtk.Label(" width: "),
|
1488 |
self.sigma_spin])
|
1489 |
pack(vbox, gtk.Label(""))
|
1490 |
|
1491 |
self.ediff = gtk.Adjustment(1e-4, 1e-6, 1e0, 1e-4) |
1492 |
self.ediff_spin = gtk.SpinButton(self.ediff, 0, 0) |
1493 |
self.ediff_spin.set_digits(6) |
1494 |
pack(vbox,[gtk.Label("Self-consistency convergence: "),
|
1495 |
self.ediff_spin,
|
1496 |
gtk.Label(" eV")])
|
1497 |
pack(vbox,gtk.Label(""))
|
1498 |
|
1499 |
self.expert_keyword_set = gtk.Entry(max = 55) |
1500 |
self.expert_keyword_add = gtk.Button(stock = gtk.STOCK_ADD)
|
1501 |
self.expert_keyword_add.connect("clicked", self.expert_keyword_import) |
1502 |
self.expert_keyword_set.connect("activate", self.expert_keyword_import) |
1503 |
pack(vbox,[gtk.Label("Additional keywords: "),
|
1504 |
self.expert_keyword_set,
|
1505 |
self.expert_keyword_add])
|
1506 |
self.expert_vbox = gtk.VBox()
|
1507 |
pack(vbox, self.expert_vbox)
|
1508 |
pack(vbox, gtk.Label(""))
|
1509 |
|
1510 |
# run command and location of POTCAR files:
|
1511 |
pack(vbox, gtk.Label('VASP execution command: '))
|
1512 |
self.run_command = pack(vbox, gtk.Entry(max=0)) |
1513 |
if os.environ.has_key('VASP_COMMAND'): |
1514 |
self.run_command.set_text(os.environ['VASP_COMMAND']) |
1515 |
pack(vbox, gtk.Label('Directory for species defaults: '))
|
1516 |
self.pp_path = pack(vbox, gtk.Entry(max=0)) |
1517 |
if os.environ.has_key('VASP_PP_PATH'): |
1518 |
self.pp_path.set_text(os.environ['VASP_PP_PATH']) |
1519 |
|
1520 |
# Buttons at the bottom
|
1521 |
pack(vbox, gtk.Label(""))
|
1522 |
butbox = gtk.HButtonBox() |
1523 |
export_vasp_but = gtk.Button("Export VASP files")
|
1524 |
export_vasp_but.connect("clicked", self.export_vasp_files) |
1525 |
cancel_but = gtk.Button(stock=gtk.STOCK_CANCEL) |
1526 |
cancel_but.connect('clicked', lambda widget: self.destroy()) |
1527 |
ok_but = gtk.Button(stock=gtk.STOCK_OK) |
1528 |
ok_but.connect('clicked', self.ok) |
1529 |
butbox.pack_start(export_vasp_but, 0, 0) |
1530 |
butbox.pack_start(cancel_but, 0, 0) |
1531 |
butbox.pack_start(ok_but, 0, 0) |
1532 |
butbox.show_all() |
1533 |
pack(vbox, [butbox], end=True, bottom=True) |
1534 |
vbox.show() |
1535 |
self.add(vbox)
|
1536 |
self.show()
|
1537 |
self.grab_add() # Lock all other windows |
1538 |
|
1539 |
def set_attributes(self, *args): |
1540 |
self.param = {}
|
1541 |
self.param["xc"] = self.xc.get_active_text() |
1542 |
self.param["prec"] = self.prec.get_active_text() |
1543 |
self.param["kpts"] = (int(self.kpts[0].value), |
1544 |
int(self.kpts[1].value), |
1545 |
int(self.kpts[2].value)) |
1546 |
self.param["encut"] = self.encut.value |
1547 |
self.param["ediff"] = self.ediff.value |
1548 |
self.param["ismear"] = self.get_ismear() |
1549 |
self.param["sigma"] = self.sigma.value |
1550 |
if self.spinpol.get_active(): |
1551 |
self.param["ispin"] = 2 |
1552 |
else:
|
1553 |
self.param["ispin"] = 1 |
1554 |
from ase.calculators.vasp import float_keys,exp_keys,string_keys,int_keys,bool_keys,list_keys,special_keys |
1555 |
for option in self.expert_keywords: |
1556 |
if option[3]: # set type of parameter accoding to which list it is in |
1557 |
key = option[0].get_text().strip()
|
1558 |
val = option[1].get_text().strip()
|
1559 |
if key in float_keys or key in exp_keys: |
1560 |
self.param[key] = float(val) |
1561 |
elif key in list_keys or key in string_keys: |
1562 |
self.param[key] = val
|
1563 |
elif key in int_keys: |
1564 |
self.param[key] = int(val) |
1565 |
elif key in bool_keys: |
1566 |
self.param[key] = bool(val) |
1567 |
setattr(self.owner, self.attrname, self.param) |
1568 |
os.environ['VASP_COMMAND'] = self.run_command.get_text() |
1569 |
os.environ['VASP_PP_PATH'] = self.pp_path.get_text() |
1570 |
|
1571 |
def ok(self, *args): |
1572 |
self.set_attributes(*args)
|
1573 |
self.destroy()
|
1574 |
|
1575 |
def get_min_max_cutoff(self, *args): |
1576 |
# determine the recommended energy cutoff limits
|
1577 |
from ase.calculators.vasp import Vasp |
1578 |
calc_temp = Vasp() |
1579 |
atoms_temp = self.owner.atoms.copy()
|
1580 |
calc_temp.initialize(atoms_temp) |
1581 |
calc_temp.write_potcar(suffix = '.check_energy_cutoff')
|
1582 |
enmin = -1e6
|
1583 |
enmax = -1e6
|
1584 |
for line in open("POTCAR.check_energy_cutoff",'r').readlines(): |
1585 |
if "ENMIN" in line: |
1586 |
enmax = max(enmax,float(line.split()[2].split(';')[0])) |
1587 |
enmin = max(enmin,float(line.split()[5])) |
1588 |
from os import system |
1589 |
system("rm POTCAR.check_energy_cutoff")
|
1590 |
return enmin, enmax
|
1591 |
|
1592 |
def k_changed(self, *args): |
1593 |
size = [self.kpts[i].value * np.sqrt(np.vdot(self.ucell[i],self.ucell[i])) for i in range(3)] |
1594 |
self.kpts_label.set_text(self.kpts_label_format % tuple(size)) |
1595 |
|
1596 |
def check_encut_warning(self,*args): |
1597 |
if self.encut.value < self.encut_min_default: |
1598 |
self.encut_warning.set_markup("<b>WARNING:</b> cutoff energy is lower than recommended minimum!") |
1599 |
else:
|
1600 |
self.encut_warning.set_markup("") |
1601 |
|
1602 |
def check_ismear_changed(self,*args): |
1603 |
if self.ismear.get_active_text() == 'Methfessel-Paxton': |
1604 |
self.smearing_order_spin.set_sensitive(True) |
1605 |
else:
|
1606 |
self.smearing_order_spin.set_sensitive(False) |
1607 |
|
1608 |
def get_ismear(self,*args): |
1609 |
type = self.ismear.get_active_text()
|
1610 |
if type == 'Methfessel-Paxton': |
1611 |
ismear_value = self.smearing_order.value
|
1612 |
elif type == 'Fermi': |
1613 |
ismear_value = -1
|
1614 |
else:
|
1615 |
ismear_value = 0
|
1616 |
return ismear_value
|
1617 |
|
1618 |
def destroy(self): |
1619 |
self.grab_remove()
|
1620 |
gtk.Window.destroy(self)
|
1621 |
|
1622 |
def export_vasp_files(self, *args): |
1623 |
filename = ""
|
1624 |
chooser = gtk.FileChooserDialog( |
1625 |
'Export VASP input files: choose directory ... ',
|
1626 |
None, gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER,
|
1627 |
(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, |
1628 |
gtk.STOCK_SAVE, gtk.RESPONSE_OK)) |
1629 |
chooser.set_filename(filename) |
1630 |
save = chooser.run() |
1631 |
if save == gtk.RESPONSE_OK or save == gtk.RESPONSE_SAVE: |
1632 |
filename = chooser.get_filename() |
1633 |
from os import chdir |
1634 |
chdir(filename) |
1635 |
self.set_attributes(*args)
|
1636 |
param = getattr(self.owner, "vasp_parameters") |
1637 |
from ase.calculators.vasp import Vasp |
1638 |
calc_temp = Vasp(**param) |
1639 |
atoms_temp = self.owner.atoms.copy()
|
1640 |
atoms_temp.set_calculator(calc_temp) |
1641 |
calc_temp.initialize(atoms_temp) |
1642 |
calc_temp.write_incar(atoms_temp) |
1643 |
calc_temp.write_potcar() |
1644 |
calc_temp.write_kpoints() |
1645 |
calc_temp.write_sort_file() |
1646 |
from ase.io.vasp import write_vasp |
1647 |
write_vasp('POSCAR', calc_temp.atoms_sorted, symbol_count = calc_temp.symbol_count)
|
1648 |
chooser.destroy() |
1649 |
|
1650 |
def expert_keyword_import(self, *args): |
1651 |
command = self.expert_keyword_set.get_text().split()
|
1652 |
if len(command) > 0 and command[0] in self.vasp_keyword_list and not command[0] in self.vasp_keyword_gui_list: |
1653 |
self.expert_keyword_create(command)
|
1654 |
elif command[0] in self.vasp_keyword_gui_list: |
1655 |
oops("Please use the facilities provided in this window to manipulate "+
|
1656 |
"the keyword: " + command[0] + "!") |
1657 |
else:
|
1658 |
oops("Don't know this keyword: " + command[0] |
1659 |
+ "\nPlease check!\n\n"
|
1660 |
+ "If you really think it should be available, "
|
1661 |
+ "please add it to the top of ase/calculators/vasp.py.")
|
1662 |
self.expert_keyword_set.set_text("") |
1663 |
|
1664 |
def expert_keyword_create(self, command): |
1665 |
key = command[0]
|
1666 |
if command[1] == "=": |
1667 |
command.remove("=")
|
1668 |
argument = command[1]
|
1669 |
if len(command) > 2: |
1670 |
for a in command[2:]: |
1671 |
argument += ' '+a
|
1672 |
index = len(self.expert_keywords) |
1673 |
self.expert_keywords += [[gtk.Label(" " +key+" = "), |
1674 |
gtk.Entry(max=45),
|
1675 |
ExpertDeleteButton(index), |
1676 |
True]]
|
1677 |
self.expert_keywords[index][1].set_text(argument) |
1678 |
self.expert_keywords[index][2].connect('clicked',self.expert_keyword_delete) |
1679 |
pack(self.expert_vbox, [self.expert_keywords[index][0], |
1680 |
self.expert_keywords[index][1], |
1681 |
self.expert_keywords[index][2]]) |
1682 |
|
1683 |
def expert_keyword_delete(self, button, *args): |
1684 |
index = button.index # which one to kill
|
1685 |
for i in [0,1,2]: |
1686 |
self.expert_keywords[index][i].destroy()
|
1687 |
self.expert_keywords[index][3] = False |