Statistiques
| Révision :

root / ase / atom.py @ 12

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