Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1"Module for displaying information about the system."
4import numpy as np
5from ase.gui.i18n import _
6import warnings
9ucellformat = """\
10 {:8.3f} {:8.3f} {:8.3f}
11 {:8.3f} {:8.3f} {:8.3f}
12 {:8.3f} {:8.3f} {:8.3f}
13"""
16def info(gui):
17 images = gui.images
18 nimg = len(images)
19 atoms = gui.atoms
21 tokens = []
23 def add(token=''):
24 tokens.append(token)
26 if len(atoms) < 1:
27 add(_('This frame has no atoms.'))
28 else:
29 img = gui.frame
31 if nimg == 1:
32 add(_('Single image loaded.'))
33 else:
34 add(_('Image {} loaded (0–{}).').format(img, nimg - 1))
35 add()
36 add(_('Number of atoms: {}').format(len(atoms)))
38 # We need to write ų further down, so we have no choice but to
39 # use proper subscripts in the chemical formula:
40 formula = atoms.get_chemical_formula()
41 subscripts = dict(zip('0123456789', '₀₁₂₃₄₅₆₇₈₉'))
42 pretty_formula = ''.join(subscripts.get(c, c) for c in formula)
43 add(pretty_formula)
45 add()
46 add(_('Unit cell [Å]:'))
47 add(ucellformat.format(*atoms.cell.ravel()))
48 periodic = [[_('no'), _('yes')][int(periodic)]
49 for periodic in atoms.pbc]
50 # TRANSLATORS: This has the form Periodic: no, no, yes
51 add(_('Periodic: {}, {}, {}').format(*periodic))
52 add()
54 cellpar = atoms.cell.cellpar()
55 add()
56 add(_('Lengths [Å]: {:.3f}, {:.3f}, {:.3f}').format(*cellpar[:3]))
57 add(_('Angles: {:.1f}°, {:.1f}°, {:.1f}°').format(*cellpar[3:]))
59 if atoms.cell.rank == 3:
60 add(_('Volume: {:.3f} ų').format(atoms.cell.volume))
62 add()
64 if nimg > 1:
65 if all((atoms.cell == img.cell).all() for img in images):
66 add(_('Unit cell is fixed.'))
67 else:
68 add(_('Unit cell varies.'))
70 if atoms.pbc[:2].all() and atoms.cell.rank >= 1:
71 try:
72 lat = atoms.cell.get_bravais_lattice()
73 except RuntimeError:
74 add(_('Could not recognize the lattice type'))
75 except Exception:
76 add(_('Unexpected error determining lattice type'))
77 else:
78 add(_('Reduced Bravais lattice:\n{}').format(lat))
80 # Print electronic structure information if we have a calculator
81 if atoms.calc:
82 calc = atoms.calc
84 def getresult(name, get_quantity):
85 # ase/io/trajectory.py line 170 does this by using
86 # the get_property(prop, atoms, allow_calculation=False)
87 # so that is an alternative option.
88 try:
89 if calc.calculation_required(atoms, [name]):
90 quantity = None
91 else:
92 quantity = get_quantity()
93 except Exception as err:
94 quantity = None
95 errmsg = ('An error occurred while retrieving {} '
96 'from the calculator: {}'.format(name, err))
97 warnings.warn(errmsg)
98 return quantity
100 # SinglePointCalculators are named after the code which
101 # produced the result, so this will typically list the
102 # name of a code even if they are just cached results.
103 add()
104 from ase.calculators.singlepoint import SinglePointCalculator
105 if isinstance(calc, SinglePointCalculator):
106 add(_('Calculator: {} (cached)').format(calc.name))
107 else:
108 add(_('Calculator: {} (attached)').format(calc.name))
110 energy = getresult('energy', atoms.get_potential_energy)
111 forces = getresult('forces', atoms.get_forces)
112 magmom = getresult('magmom', atoms.get_magnetic_moment)
114 if energy is not None:
115 energy_str = _('Energy: {:.3f} eV').format(energy)
116 add(energy_str)
118 if forces is not None:
119 maxf = np.linalg.norm(forces, axis=1).max()
120 forces_str = _('Max force: {:.3f} eV/Å').format(maxf)
121 add(forces_str)
123 if magmom is not None:
124 mag_str = _('Magmom: {:.3f} µ').format(magmom)
125 add(mag_str)
127 return '\n'.join(tokens)