Statistiques
| Révision :

root / ase / lattice / spacegroup / crystal.py @ 1

Historique | Voir | Annoter | Télécharger (4,93 ko)

1
# Copyright (C) 2010, Jesper Friis
2
# (see accompanying license files for details).
3

    
4
"""
5
A module for ASE for simple creation of crystalline structures from
6
knowledge of the space group.
7

8
"""
9

    
10
import numpy as np
11

    
12
import ase
13
from ase.atoms import string2symbols
14
from spacegroup import Spacegroup
15
from cell import cellpar_to_cell
16

    
17
__all__ = ['crystal']
18

    
19

    
20

    
21
def crystal(symbols=None, basis=None, spacegroup=1, setting=1, 
22
            cell=None, cellpar=None, 
23
            ab_normal=(0,0,1), a_direction=None, size=(1,1,1),
24
            ondublicates='warn', symprec=0.001, 
25
            pbc=True, **kwargs):
26
    """Create an Atoms instance for a conventional unit cell of a
27
    space group.
28

29
    Parameters:
30

31
    symbols : string | sequence of strings
32
        Either a string formula or a sequence of element
33
        symbols. E.g. ('Na', 'Cl') and 'NaCl' are equivalent.
34
    basis : list of scaled coordinates | atoms instance
35
        Positions of the non-equivalent sites given either as
36
        scaled positions or through an atoms instance.
37
    spacegroup : int | string | Spacegroup instance
38
        Space group given either as its number in International Tables
39
        or as its Hermann-Mauguin symbol.
40
    setting : 1 | 2
41
        Space group setting.
42
    cell : 3x3 matrix
43
        Unit cell vectors.
44
    cellpar : [a, b, c, alpha, beta, gamma]
45
        Cell parameters with angles in degree. Is not used when `cell`
46
        is given. 
47
    ab_normal : vector
48
        Is used to define the orientation of the unit cell relative
49
        to the Cartesian system when `cell` is not given. It is the
50
        normal vector of the plane spanned by a and b.
51
    a_direction : vector
52
        Defines the orientation of the unit cell a vector. a will be 
53
        parallel to the projection of `a_direction` onto the a-b plane.
54
    size : 3 positive integers
55
        How many times the conventional unit cell should be repeated
56
        in each direction.
57
    ondublicates : 'keep' | 'replace' | 'warn' | 'error'
58
        Action if `basis` contain symmetry-equivalent positions:
59
            'keep'    - ignore additional symmetry-equivalent positions
60
            'replace' - reolace
61
            'warn'    - like 'keep', but issue an UserWarning
62
            'error'   - raises a SpacegroupValueError
63
    symprec : float
64
        Minimum "distance" betweed two sites in scaled coordinates
65
        before they are counted as the same site.
66
    pbc : one or three bools
67
        Periodic boundary conditions flags.  Examples: True,
68
        False, 0, 1, (1, 1, 0), (True, False, False).  Default
69
        is True.
70

71
    Keyword arguments:
72

73
    All additional keyword arguments are passed on to the Atoms constructor. 
74
    Currently, probably the most useful additional keyword arguments are
75
    `constraint` and `calculator`.
76

77
    Examples:
78

79
    Two diamond unit cells (space group number 227)
80

81
    >>> diamond = crystal('C', [(0,0,0)], spacegroup=227, 
82
    ...     cellpar=[3.57, 3.57, 3.57, 90, 90, 90], size=(2,1,1))
83
    >>> ase.view(diamond)  # doctest: +SKIP
84

85
    A CoSb3 skutterudite unit cell containing 32 atoms
86

87
    >>> skutterudite = crystal(('Co', 'Sb'), 
88
    ...     basis=[(0.25,0.25,0.25), (0.0, 0.335, 0.158)], 
89
    ...     spacegroup=204, cellpar=[9.04, 9.04, 9.04, 90, 90, 90])
90
    >>> len(skutterudite)
91
    32
92
    """
93
    sg = Spacegroup(spacegroup, setting)
94
    if isinstance(symbols, ase.Atoms):
95
        basis = symbols
96
        symbols = basis.get_chemical_symbols()
97
    if isinstance(basis, ase.Atoms):
98
        basis_coords = basis.get_scaled_positions()
99
        if cell is None and cellpar is None:
100
            cell = basis.cell
101
        if symbols is None:
102
            symbols = basis.get_chemical_symbols()
103
    else:
104
        basis_coords = np.array(basis, dtype=float, copy=False, ndmin=2)
105
    sites, kinds = sg.equivalent_sites(basis_coords, 
106
                                       ondublicates=ondublicates, 
107
                                       symprec=symprec)
108
    symbols = parse_symbols(symbols)
109
    symbols = [symbols[i] for i in kinds]
110
    if cell is None:
111
        cell = cellpar_to_cell(cellpar, ab_normal, a_direction)
112

    
113
    atoms = ase.Atoms(symbols, 
114
                      scaled_positions=sites, 
115
                      cell=cell,
116
                      pbc=pbc,
117
                      **kwargs)
118

    
119
    if isinstance(basis, ase.Atoms):
120
        for name in basis.arrays:
121
            if not atoms.has(name):
122
                array = basis.get_array(name)
123
                atoms.new_array(name, [array[i] for i in kinds], 
124
                                dtype=array.dtype, shape=array.shape[1:])
125

    
126
    if size != (1, 1, 1):
127
        atoms = atoms.repeat(size)
128
    return atoms
129

    
130
def parse_symbols(symbols):
131
    """Return `sumbols` as a sequence of element symbols."""
132
    if isinstance(symbols, basestring):
133
        symbols = string2symbols(symbols)
134
    return symbols
135

    
136

    
137

    
138

    
139

    
140

    
141
#-----------------------------------------------------------------
142
# Self test
143
if __name__ == '__main__':
144
    import doctest
145
    print 'doctest: ', doctest.testmod()
146