root / ase / atom.py @ 20
Historique | Voir | Annoter | Télécharger (9,24 ko)
1 |
"""This module defines the Atom object."""
|
---|---|
2 |
|
3 |
import numpy as np |
4 |
|
5 |
from ase.data import atomic_numbers, chemical_symbols, atomic_masses |
6 |
|
7 |
|
8 |
# singular, plural, type, shape
|
9 |
data = {'symbol': ('symbols', str, () ), |
10 |
'number': ('numbers', int, () ), |
11 |
'position': ('positions', float, (3,)), |
12 |
'tag': ('tags', int, () ), |
13 |
'momentum': ('momenta', float, (3,)), |
14 |
'mass': ('masses', float, () ), |
15 |
'magmom': ('magmoms', float, () ), |
16 |
'charge': ('charges', float, () ), |
17 |
} |
18 |
|
19 |
class Atom(object): |
20 |
"""Class for representing a single atom.
|
21 |
|
22 |
Parameters:
|
23 |
|
24 |
symbol: str or int
|
25 |
Can be a chemical symbol (str) or an atomic number (int).
|
26 |
position: sequence of 3 floats
|
27 |
Atomi position.
|
28 |
tag: int
|
29 |
Special purpose tag.
|
30 |
momentum: sequence of 3 floats
|
31 |
Momentum for atom.
|
32 |
mass: float
|
33 |
Atomic mass in atomic units.
|
34 |
magmom: float
|
35 |
Magnetic moment.
|
36 |
charge: float
|
37 |
Atomic charge.
|
38 |
|
39 |
Examples:
|
40 |
|
41 |
>>> a = Atom('O', charge=-2)
|
42 |
>>> b = Atom(8, charge=-2)
|
43 |
>>> c = Atom('H', (1, 2, 3), magmom=1)
|
44 |
>>> print a.charge, a.position
|
45 |
-2 [ 0. 0. 0.]
|
46 |
>>> c.x = 0.0
|
47 |
>>> c.position
|
48 |
array([ 0., 2., 3.])
|
49 |
>>> b.symbol
|
50 |
'O'
|
51 |
>>> c.tag = 42
|
52 |
>>> c.number
|
53 |
1
|
54 |
>>> c.symbol = 'Li'
|
55 |
>>> c.number
|
56 |
3
|
57 |
|
58 |
If the atom object belongs to an Atoms object, then assigning
|
59 |
values to the atom attributes will change the corresponding
|
60 |
arrays of the atoms object:
|
61 |
|
62 |
>>> OH = Atoms('OH')
|
63 |
>>> OH[0].charge = -1
|
64 |
>>> OH.get_charges()
|
65 |
array([-1., 0.])
|
66 |
|
67 |
Another example:
|
68 |
|
69 |
>>> for atom in bulk:
|
70 |
... if atom.symbol = 'Ni':
|
71 |
... atom.magmom = 0.7
|
72 |
|
73 |
|
74 |
"""
|
75 |
|
76 |
__slots__ = ['_number', '_symbol', '_position', '_tag', '_momentum', |
77 |
'_mass', '_magmom', '_charge', 'atoms', 'index'] |
78 |
|
79 |
def __init__(self, symbol='X', position=(0, 0, 0), |
80 |
tag=None, momentum=None, mass=None, |
81 |
magmom=None, charge=None, |
82 |
atoms=None, index=None): |
83 |
if atoms is None: |
84 |
# This atom is not part of any Atoms object:
|
85 |
if isinstance(symbol, str): |
86 |
self._number = atomic_numbers[symbol]
|
87 |
self._symbol = symbol
|
88 |
else:
|
89 |
self._number = symbol
|
90 |
self._symbol = chemical_symbols[symbol]
|
91 |
self._position = np.array(position, float) |
92 |
self._tag = tag
|
93 |
if momentum is not None: |
94 |
momentum = np.array(momentum, float)
|
95 |
self._momentum = momentum
|
96 |
self._mass = mass
|
97 |
self._magmom = magmom
|
98 |
self._charge = charge
|
99 |
|
100 |
self.index = index
|
101 |
self.atoms = atoms
|
102 |
|
103 |
def __repr__(self): |
104 |
s = "Atom('%s', %s" % (self.symbol, list(self.position)) |
105 |
for attr in ['tag', 'momentum', 'mass', 'magmom', 'charge']: |
106 |
value = getattr(self, attr) |
107 |
if value is not None: |
108 |
if isinstance(value, np.ndarray): |
109 |
value = value.tolist() |
110 |
s += ', %s=%s' % (attr, value)
|
111 |
if self.atoms is None: |
112 |
s += ')'
|
113 |
else:
|
114 |
s += ', index=%d)' % self.index |
115 |
return s
|
116 |
|
117 |
def get_data(self): |
118 |
"""Helper method."""
|
119 |
return (self.position, self.number, |
120 |
self.tag, self.momentum, self.mass, |
121 |
self.magmom, self.charge) |
122 |
|
123 |
def cut_reference_to_atoms(self): |
124 |
"""Cut reference to atoms object."""
|
125 |
data = self.get_data()
|
126 |
self.index = None |
127 |
self.atoms = None |
128 |
(self._position,
|
129 |
self._number,
|
130 |
self._tag,
|
131 |
self._momentum,
|
132 |
self._mass,
|
133 |
self._magmom,
|
134 |
self._charge) = data
|
135 |
self._symbol = chemical_symbols[self._number] |
136 |
|
137 |
def _get(self, name): |
138 |
if self.atoms is None: |
139 |
return getattr(self, '_' + name) |
140 |
elif name == 'symbol': |
141 |
return chemical_symbols[self.number] |
142 |
else:
|
143 |
plural = data[name][0]
|
144 |
if plural in self.atoms.arrays: |
145 |
return self.atoms.arrays[plural][self.index] |
146 |
else:
|
147 |
return None |
148 |
|
149 |
def _get_copy(self, name, copy=False): |
150 |
if self.atoms is None: |
151 |
return getattr(self, '_' + name) |
152 |
elif name == 'symbol': |
153 |
return chemical_symbols[self.number] |
154 |
else:
|
155 |
plural = data[name][0]
|
156 |
if plural in self.atoms.arrays: |
157 |
return self.atoms.arrays[plural][self.index].copy() |
158 |
else:
|
159 |
return None |
160 |
|
161 |
def _set(self, name, value): |
162 |
if self.atoms is None: |
163 |
setattr(self, '_' + name, value) |
164 |
if name == 'symbol': |
165 |
self._number = atomic_numbers[value]
|
166 |
elif name == 'number': |
167 |
self._symbol = chemical_symbols[value]
|
168 |
elif name == 'symbol': |
169 |
self.number = atomic_numbers[value]
|
170 |
else:
|
171 |
plural, dtype, shape = data[name] |
172 |
if plural in self.atoms.arrays: |
173 |
self.atoms.arrays[plural][self.index] = value |
174 |
else:
|
175 |
array = np.zeros((len(self.atoms),) + shape, dtype) |
176 |
array[self.index] = value
|
177 |
self.atoms.new_array(plural, array)
|
178 |
|
179 |
def get_symbol(self): return self._get('symbol') |
180 |
def get_atomic_number(self): return self._get('number') |
181 |
def get_position(self): return self._get_copy('position') |
182 |
def _get_position(self): return self._get('position') |
183 |
def get_tag(self): return self._get('tag') |
184 |
def get_momentum(self): return self._get_copy('momentum') |
185 |
def _get_momentum(self): return self._get('momentum') |
186 |
def get_initial_magnetic_moment(self): return self._get('magmom') |
187 |
def get_charge(self): return self._get('charge') |
188 |
|
189 |
def set_symbol(self, symbol): self._set('symbol', symbol) |
190 |
def set_atomic_number(self, number): self._set('number', number) |
191 |
def set_position(self, position): |
192 |
self._set('position', np.array(position, float)) |
193 |
def set_tag(self, tag): self._set('tag', tag) |
194 |
def set_momentum(self, momentum): self._set('momentum', momentum) |
195 |
def set_initial_magnetic_moment(self, magmom): self._set('magmom', magmom) |
196 |
def set_charge(self, charge): self._set('charge', charge) |
197 |
|
198 |
def set_magmom(self, magmom): |
199 |
"Deprecated, use set_initial_magnetic_moment instead."
|
200 |
import warnings |
201 |
warnings.warn('set_magmom is deprecated. Please use set_initial_magnetic_moment' \
|
202 |
' instead.', DeprecationWarning, stacklevel=2) |
203 |
return self.set_initial_magnetic_moment(magmom) |
204 |
|
205 |
def get_number(self): |
206 |
"Deprecated, use get_atomic_number instead."
|
207 |
import warnings |
208 |
warnings.warn( |
209 |
'get_number is deprecated. Please use get_atomic_number instead.',
|
210 |
DeprecationWarning, stacklevel=2) |
211 |
return self.get_atomic_number() |
212 |
|
213 |
def set_number(self, number): |
214 |
"Deprecated, use set_atomic_number instead."
|
215 |
import warnings |
216 |
warnings.warn( |
217 |
'set_number is deprecated. Please use set_atomic_number instead.',
|
218 |
DeprecationWarning, stacklevel=2) |
219 |
return self.set_atomic_number(number) |
220 |
|
221 |
def get_mass(self): |
222 |
"""Get the mass of the atom.
|
223 |
|
224 |
Returns the mass of the atom, if known. If unknown, returns the
|
225 |
atomic mass corresponding to the element.
|
226 |
"""
|
227 |
m = self._get('mass') |
228 |
if m is None: |
229 |
m = atomic_masses[self.get_atomic_number()]
|
230 |
return m
|
231 |
|
232 |
def set_mass(self, mass): |
233 |
"""Sets the mass of the atom.
|
234 |
|
235 |
If the atom is part of a list of atoms, and the atoms do not yet
|
236 |
have masses, all other atoms are assigned their default masses.
|
237 |
"""
|
238 |
if self.atoms is None: |
239 |
self._mass = mass
|
240 |
else:
|
241 |
if 'masses' not in self.atoms.arrays: |
242 |
# Assign default masses to all atoms
|
243 |
self.atoms.set_masses(self.atoms.get_masses()) |
244 |
self.atoms.arrays['masses'][self.index] = mass |
245 |
|
246 |
symbol = property(get_symbol, set_symbol, doc='Chemical symbol') |
247 |
number = property(get_atomic_number, set_atomic_number, doc='Atomic number') |
248 |
position = property(_get_position, set_position, doc='XYZ-coordinates') |
249 |
tag = property(get_tag, set_tag, doc='Integer tag') |
250 |
momentum = property(_get_momentum, set_momentum, doc='XYZ-momentum') |
251 |
mass = property(get_mass, set_mass, doc='Atomic mass') |
252 |
magmom = property(get_initial_magnetic_moment, set_initial_magnetic_moment,
|
253 |
doc='Initial magnetic moment')
|
254 |
charge = property(get_charge, set_charge, doc='Atomic charge') |
255 |
|
256 |
def get_x(self): return self.position[0] |
257 |
def get_y(self): return self.position[1] |
258 |
def get_z(self): return self.position[2] |
259 |
|
260 |
def set_x(self, x): self.position[0] = x |
261 |
def set_y(self, y): self.position[1] = y |
262 |
def set_z(self, z): self.position[2] = z |
263 |
|
264 |
x = property(get_x, set_x, doc='X-coordiante') |
265 |
y = property(get_y, set_y, doc='Y-coordiante') |
266 |
z = property(get_z, set_z, doc='Z-coordiante') |
267 |
|