Coverage for /builds/kinetik161/ase/ase/gui/celleditor.py: 84.31%
102 statements
« prev ^ index » next coverage.py v7.2.7, created at 2023-12-10 11:04 +0000
« prev ^ index » next coverage.py v7.2.7, created at 2023-12-10 11:04 +0000
1'''celleditor.py - Window for editing the cell of an atoms object
2'''
3import numpy as np
5import ase.gui.ui as ui
6from ase.cell import Cell
7from ase.gui.i18n import _
10class CellEditor:
11 '''Window for editing the cell of an atoms object.'''
13 def __init__(self, gui):
14 self.gui = gui
15 self.gui.register_vulnerable(self)
17 # Create grid control for cells
18 # xx xy xz ||x|| pbc
19 # yx yy yz ||y|| pbc
20 # zx zy zz ||z|| pbc
21 self.cell_grid = []
22 self.pbc = []
23 self.angles = []
25 atoms = self.gui.atoms
27 cell = atoms.cell
28 mags = cell.lengths()
29 angles = cell.angles()
30 pbc = atoms.pbc
32 for i in [0, 1, 2]: # x_ y_ z_
33 row = []
34 for j in [0, 1, 2]: # _x _y _z
35 row.append(ui.SpinBox(cell[i][j], -30, 30, 0.1,
36 self.apply_vectors, rounding=7, width=9))
37 row.append(ui.SpinBox(mags[i], -30, 30, 0.1, self.apply_magnitudes,
38 rounding=7, width=9))
39 self.cell_grid.append(row)
40 self.pbc.append(ui.CheckButton('', bool(pbc[i]), self.apply_pbc))
41 self.angles.append(ui.SpinBox(angles[i], -360, 360, 15,
42 self.apply_angles,
43 rounding=7, width=9))
45 self.scale_atoms = ui.CheckButton('', False)
46 self.vacuum = ui.SpinBox(5, 0, 15, 0.1, self.apply_vacuum)
48 # TRANSLATORS: This is a title of a window.
49 win = self.win = ui.Window(_('Cell Editor'), wmtype='utility')
51 x, y, z = self.cell_grid
53 win.add([_('A:'), x[0], x[1], x[2], _('||A||:'), x[3],
54 _('periodic:'), self.pbc[0]])
55 win.add([_('B:'), y[0], y[1], y[2], _('||B||:'), y[3],
56 _('periodic:'), self.pbc[1]])
57 win.add([_('C:'), z[0], z[1], z[2], _('||C||:'), z[3],
58 _('periodic:'), self.pbc[2]])
59 win.add([_('∠BC:'), self.angles[0], _('∠AC:'), self.angles[1],
60 _('∠AB:'), self.angles[2]])
61 win.add([_('Scale atoms with cell:'), self.scale_atoms])
62 win.add([ui.Button(_('Apply Vectors'), self.apply_vectors),
63 ui.Button(_('Apply Magnitudes'), self.apply_magnitudes),
64 ui.Button(_('Apply Angles'), self.apply_angles)])
65 win.add([_('Pressing 〈Enter〉 as you enter values will '
66 'automatically apply correctly')])
67 # TRANSLATORS: verb
68 win.add([ui.Button(_('Center'), self.apply_center),
69 ui.Button(_('Wrap'), self.apply_wrap),
70 _('Vacuum:'), self.vacuum,
71 ui.Button(_('Apply Vacuum'), self.apply_vacuum)])
73 def apply_center(self, *args):
74 atoms = self.gui.atoms.copy()
75 atoms.center()
76 self.gui.new_atoms(atoms)
78 def apply_wrap(self, *args):
79 atoms = self.gui.atoms.copy()
80 atoms.wrap()
81 self.gui.new_atoms(atoms)
83 def apply_vacuum(self, *args):
84 atoms = self.gui.atoms.copy()
86 axis = []
87 for index, pbc in enumerate(atoms.pbc):
88 if not pbc:
89 axis.append(index)
91 atoms.center(vacuum=self.vacuum.value, axis=axis)
92 self.gui.new_atoms(atoms)
94 def apply_vectors(self, *args):
95 atoms = self.gui.atoms.copy()
97 atoms.set_cell(self.get_vectors(),
98 scale_atoms=self.scale_atoms.var.get())
99 self.gui.new_atoms(atoms)
101 def get_vectors(self):
102 x, y, z = self.cell_grid
103 cell = np.array(
104 [[x[0].value, x[1].value, x[2].value],
105 [y[0].value, y[1].value, y[2].value],
106 [z[0].value, z[1].value, z[2].value]]
107 )
108 return Cell(cell)
110 def get_magnitudes(self):
111 x, y, z = self.cell_grid
112 return np.array([x[3].value, y[3].value, z[3].value])
114 def apply_magnitudes(self, *args):
115 atoms = self.gui.atoms.copy()
117 old_mags = atoms.cell.lengths()
118 new_mags = self.get_magnitudes()
120 newcell = atoms.cell.copy()
121 for i in range(3):
122 newcell[i] *= new_mags[i] / old_mags[i]
124 atoms.set_cell(newcell,
125 scale_atoms=self.scale_atoms.var.get())
127 self.gui.new_atoms(atoms)
129 def apply_angles(self, *args):
130 atoms = self.gui.atoms.copy()
132 cell_data = atoms.cell.cellpar()
133 cell_data[3:7] = [self.angles[0].value, self.angles[1].value,
134 self.angles[2].value]
136 atoms.set_cell(cell_data, scale_atoms=self.scale_atoms.var.get())
138 self.gui.new_atoms(atoms)
140 def apply_pbc(self, *args):
141 atoms = self.gui.atoms.copy()
143 pbc = [pbc.var.get() for pbc in self.pbc]
144 atoms.set_pbc(pbc)
146 self.gui.new_atoms(atoms)
148 def notify_atoms_changed(self):
149 atoms = self.gui.atoms
150 self.update(atoms.cell, atoms.pbc)
152 def update(self, cell, pbc):
153 cell = Cell(cell)
154 mags = cell.lengths()
155 angles = cell.angles()
157 for i in range(3):
158 for j in range(3):
159 if np.isnan(cell[i][j]):
160 cell[i][j] = 0
161 self.cell_grid[i][j].value = cell[i][j]
163 if np.isnan(mags[i]):
164 mags[i] = 0
165 self.cell_grid[i][3].value = mags[i]
167 if np.isnan(angles[i]):
168 angles[i] = 0
169 self.angles[i].value = angles[i]
171 self.pbc[i].var.set(bool(pbc[i]))