root / ase / gui / calculator.py @ 4
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 |