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