source: trunk/GSASIIspc.py @ 1559

Last change on this file since 1559 was 1559, checked in by vondreele, 8 years ago

use deepcopy for various copy operations in G2ddataGUI
use complementary colors to background for cell edges
trap superlattice in cubics
more fixes to cell indexing routines from possible use of superlattice
add HStrainVals to G2spc
use it (maybe) in G2strIO, Math
make arguments for GetReflPos? & GetReflPosDeriv? the same (use A not G)
add GetDij? to G2strMath
topas xye file comments start with "'" sometimes

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Author Revision URL Id
File size: 103.7 KB
Line 
1# -*- coding: utf-8 -*-
2"""
3*GSASIIspc: Space group module*
4-------------------------------
5
6Space group interpretation routines. Note that space group information is
7stored in a :ref:`Space Group (SGData)<SGData_table>` object.
8
9"""
10########### SVN repository information ###################
11# $Date: 2014-11-03 20:48:51 +0000 (Mon, 03 Nov 2014) $
12# $Author: vondreele $
13# $Revision: 1559 $
14# $URL: trunk/GSASIIspc.py $
15# $Id: GSASIIspc.py 1559 2014-11-03 20:48:51Z vondreele $
16########### SVN repository information ###################
17import numpy as np
18import numpy.ma as ma
19import numpy.linalg as nl
20import scipy.optimize as so
21import math
22import sys
23import os.path as ospath
24
25import GSASIIpath
26GSASIIpath.SetVersionNumber("$Revision: 1559 $")
27import pyspg
28
29npsind = lambda x: np.sin(x*np.pi/180.)
30npcosd = lambda x: np.cos(x*np.pi/180.)
31   
32################################################################################
33#### Space group codes
34################################################################################
35
36def SpcGroup(SGSymbol):
37    """
38    Determines cell and symmetry information from a short H-M space group name
39
40    :param SGSymbol: space group symbol (string) with spaces between axial fields
41    :returns: (SGError,SGData)
42       * SGError = 0 for no errors; >0 for errors (see SGErrors below for details)
43       * SGData - is a dict (see :ref:`Space Group object<SGData_table>`) with entries:
44       
45             * 'SpGrp': space group symbol, slightly cleaned up
46             * 'SGLaue':  one of '-1', '2/m', 'mmm', '4/m', '4/mmm', '3R',
47               '3mR', '3', '3m1', '31m', '6/m', '6/mmm', 'm3', 'm3m'
48             * 'SGInv': boolean; True if centrosymmetric, False if not
49             * 'SGLatt': one of 'P', 'A', 'B', 'C', 'I', 'F', 'R'
50             * 'SGUniq': one of 'a', 'b', 'c' if monoclinic, '' otherwise
51             * 'SGCen': cell centering vectors [0,0,0] at least
52             * 'SGOps': symmetry operations as [M,T] so that M*x+T = x'
53             * 'SGSys': one of 'triclinic', 'monoclinic', 'orthorhombic',
54               'tetragonal', 'rhombohedral', 'trigonal', 'hexagonal', 'cubic'
55             * 'SGPolax': one of '', 'x', 'y', 'x y', 'z', 'x z', 'y z',
56               'xyz', '111' for arbitrary axes
57             * 'SGPtGrp': one of 32 point group symbols (with some permutations)
58                - filled by SGPtGroup - is external (KE) part of supersymmetry point group
59             * 'SSGKl': default internal (Kl) part of supersymmetry point group; modified
60             in supersymmetry stuff depending on chosen modulation vector for Mono & Ortho
61
62    """
63    LaueSym = ('-1','2/m','mmm','4/m','4/mmm','3R','3mR','3','3m1','31m','6/m','6/mmm','m3','m3m')
64    LattSym = ('P','A','B','C','I','F','R')
65    UniqSym = ('','','a','b','c','',)
66    SysSym = ('triclinic','monoclinic','orthorhombic','tetragonal','rhombohedral','trigonal','hexagonal','cubic')
67    SGData = {}
68    SGInfo = pyspg.sgforpy(SGSymbol)
69    SGData['SpGrp'] = SGSymbol.strip().lower().capitalize()
70    SGData['SGLaue'] = LaueSym[SGInfo[0]-1]
71    SGData['SGInv'] = bool(SGInfo[1])
72    SGData['SGLatt'] = LattSym[SGInfo[2]-1]
73    SGData['SGUniq'] = UniqSym[SGInfo[3]+1]
74    if SGData['SGLatt'] == 'P':
75        SGData['SGCen'] = np.array(([0,0,0],))
76    elif SGData['SGLatt'] == 'A':
77        SGData['SGCen'] = np.array(([0,0,0],[0,.5,.5]))
78    elif SGData['SGLatt'] == 'B':
79        SGData['SGCen'] = np.array(([0,0,0],[.5,0,.5]))
80    elif SGData['SGLatt'] == 'C':
81        SGData['SGCen'] = np.array(([0,0,0],[.5,.5,0,]))
82    elif SGData['SGLatt'] == 'I':
83        SGData['SGCen'] = np.array(([0,0,0],[.5,.5,.5]))
84    elif SGData['SGLatt'] == 'F':
85        SGData['SGCen'] = np.array(([0,0,0],[0,.5,.5],[.5,0,.5],[.5,.5,0,]))
86    elif SGData['SGLatt'] == 'R':
87        SGData['SGCen'] = np.array(([0,0,0],[1./3.,2./3.,2./3.],[2./3.,1./3.,1./3.]))
88    SGData['SGOps'] = []
89    for i in range(SGInfo[5]):
90        Mat = np.array(SGInfo[6][i])
91        Trns = np.array(SGInfo[7][i])
92        SGData['SGOps'].append([Mat,Trns])
93    if SGData['SGLaue'] in '-1':
94        SGData['SGSys'] = SysSym[0]
95    elif SGData['SGLaue'] in '2/m':
96        SGData['SGSys'] = SysSym[1]
97    elif SGData['SGLaue'] in 'mmm':
98        SGData['SGSys'] = SysSym[2]
99    elif SGData['SGLaue'] in ['4/m','4/mmm']:
100        SGData['SGSys'] = SysSym[3]
101    elif SGData['SGLaue'] in ['3R','3mR']:
102        SGData['SGSys'] = SysSym[4]
103    elif SGData['SGLaue'] in ['3','3m1','31m']:
104        SGData['SGSys'] = SysSym[5]
105    elif SGData['SGLaue'] in ['6/m','6/mmm']:
106        SGData['SGSys'] = SysSym[6]
107    elif SGData['SGLaue'] in ['m3','m3m']:
108        SGData['SGSys'] = SysSym[7]
109    SGData['SGPolax'] = SGpolar(SGData)
110    SGData['SGPtGrp'],SGData['SSGKl'] = SGPtGroup(SGData)
111    return SGInfo[8],SGData
112
113def SGErrors(IErr):
114    '''
115    Interprets the error message code from SpcGroup. Used in SpaceGroup.
116   
117    :param IErr: see SGError in :func:`SpcGroup`
118    :returns:
119        ErrString - a string with the error message or "Unknown error"
120    '''
121
122    ErrString = [' ',
123        'Less than 2 operator fields were found',
124        'Illegal Lattice type, not P, A, B, C, I, F or R',
125        'Rhombohedral lattice requires a 3-axis',
126        'Minus sign does not preceed 1, 2, 3, 4 or 6',
127        'Either a 5-axis anywhere or a 3-axis in field not allowed',
128        ' ',
129        'I for COMPUTED GO TO out of range.',
130        'An a-glide mirror normal to A not allowed',
131        'A b-glide mirror normal to B not allowed',
132        'A c-glide mirror normal to C not allowed',
133        'D-glide in a primitive lattice not allowed',
134        'A 4-axis not allowed in the 2nd operator field',
135        'A 6-axis not allowed in the 2nd operator field',
136        'More than 24 matrices needed to define group',
137        ' ',
138        'Improper construction of a rotation operator',
139        'Mirror following a / not allowed',
140        'A translation conflict between operators',
141        'The 2bar operator is not allowed',
142        '3 fields are legal only in R & m3 cubic groups',
143        'Syntax error. Expected I -4 3 d at this point',
144        ' ',
145        'A or B centered tetragonal not allowed',
146        ' ','unknown error in sgroup',' ',' ',' ',
147        'Illegal character in the space group symbol',
148        ]
149    try:
150        return ErrString[IErr]
151    except:
152        return "Unknown error"
153
154def SGpolar(SGData):
155    '''
156    Determine identity of polar axes if any
157    '''
158    POL = ('','x','y','x y','z','x z','y z','xyz','111')
159    NP = [1,2,4]
160    NPZ = [0,1]
161    for M,T in SGData['SGOps']:
162        for i in range(3):
163            if M[i][i] <= 0.: NP[i] = 0
164        if M[0][2] > 0: NPZ[0] = 8
165        if M[1][2] > 0: NPZ[1] = 0
166    NPol = (NP[0]+NP[1]+NP[2]+NPZ[0]*NPZ[1])*(1-int(SGData['SGInv']))
167    return POL[NPol]
168   
169def SGPtGroup(SGData):
170    '''
171    Determine point group of the space group - done after space group symbol has
172    been evaluated by SpcGroup. Only short symbols are allowed
173   
174    :param SGData: from :func SpcGroup
175    returns SSGPtGrp & SSGKl (only defaults for Mono & Ortho)
176    '''
177    Flds = SGData['SpGrp'].split()
178    if len(Flds) < 2:
179        return '',[]
180    if SGData['SGLaue'] == '-1':    #triclinic
181        if '-' in Flds[1]:
182            return '-1',[-1,]
183        else:
184            return '1',[1,]
185    elif SGData['SGLaue'] == '2/m': #monoclinic - default for 2D modulation vector
186        if '/' in SGData['SpGrp']:
187            return '2/m',[-1,1]
188        elif '2' in SGData['SpGrp']:
189            return '2',[-1,]
190        else:
191            return 'm',[1,]
192    elif SGData['SGLaue'] == 'mmm': #orthorhombic
193        if SGData['SpGrp'].count('2') == 3:
194            return '222',[1,1,1]
195        elif SGData['SpGrp'].count('2') == 1:
196            if SGData['SGPolax'] == 'x':
197                return '2mm',[1,1,1]
198            elif SGData['SGPolax'] == 'y':
199                return 'm2m',[1,1,1]
200            elif SGData['SGPolax'] == 'z':
201                return 'mm2',[1,1,1]
202        else:
203            return 'mmm',[1,1,-1]
204    elif SGData['SGLaue'] == '4/m': #tetragonal
205        if '/' in SGData['SpGrp']:
206            return '4/m',[1,-1]
207        elif '-' in Flds[1]:
208            return '-4',[-1,]
209        else:
210            return '4',[1,]
211    elif SGData['SGLaue'] == '4/mmm':
212        if '/' in SGData['SpGrp']:
213            return '4/mmm',[1,-1,1,1]
214        elif '-' in Flds[1]:
215            if '2' in Flds[2]:
216                return '-42m',[-1,-1,1]
217            else:
218                return '-4m2',[-1,1,-1]             
219        elif '2' in Flds[2:]:
220            return '422',[1,-1,-1]
221        else:
222            return '4mm',[1,1,1]
223    elif SGData['SGLaue'] in ['3','3R']:  #trigonal/rhombohedral
224        if '-' in Flds[1]:
225            return '-3',[-1,]
226        else:
227            return '3',[1,]
228    elif SGData['SGLaue'] == '3mR' or 'R' in Flds[0]:
229        if '2' in Flds[2]:
230            return '32',[1,-1]
231        elif '-' in Flds[1]:
232            return '-3m',[-1,1]
233        else:
234            return '3m',[1,1]
235    elif SGData['SGLaue'] == '3m1':
236        if '2' in Flds[2]:
237            return '321',[1,-1,1]
238        elif '-' in Flds[1]:
239            return '-3m1',[-1,1,1]
240        else:
241            return '3m1',[1,1,1]
242    elif SGData['SGLaue'] == '31m':
243        if '2' in Flds[3]:
244            return '312',[1,1,-1]
245        elif '-' in Flds[1]:
246            return '-31m',[-1,1,1]
247        else:
248            return '31m',[1,1,1]
249    elif SGData['SGLaue'] == '6/m': #hexagonal
250        if '/' in SGData['SpGrp']:
251            return '6/m',[1,-1]
252        elif '-' in SGData['SpGrp']:
253            return '-6',[-1,]
254        else:
255            return '6',[1,]
256    elif SGData['SGLaue'] == '6/mmm':
257        if '/' in SGData['SpGrp']:
258            return '6/mmm',[1,-1,1,1]
259        elif '-' in Flds[1]:
260            if '2' in Flds[2]:
261                return '-62m',[-1,-1,1]
262            else:
263                return '-6m2',[-1,1,-1]                 
264        elif '2' in Flds[2:]:
265            return '622',[1,-1,-1]
266        else:
267            return '6mm',[1,1,1]   
268    elif SGData['SGLaue'] == 'm3':      #cubic - no (3+1) supersymmetry
269        if '2' in Flds[1]:
270            return '23',[]
271        else: 
272            return 'm3',[]
273    elif SGData['SGLaue'] == 'm3m':
274        if '4' in Flds[1]:
275            if '-' in Flds[1]:
276                return '-43m',[]
277            else:
278                return '432',[]
279        else:
280            return 'm-3m',[]
281   
282def SGPrint(SGData):
283    '''
284    Print the output of SpcGroup in a nicely formatted way. Used in SpaceGroup
285
286    :param SGData: from :func:`SpcGroup`
287    :returns:
288        SGText - list of strings with the space group details
289        SGTable - list of strings for each of the operations
290    '''
291    Mult = len(SGData['SGCen'])*len(SGData['SGOps'])*(int(SGData['SGInv'])+1)
292    SGText = []
293    SGText.append(' Space Group: '+SGData['SpGrp'])
294    CentStr = 'centrosymmetric'
295    if not SGData['SGInv']:
296        CentStr = 'non'+CentStr
297    if SGData['SGLatt'] in 'ABCIFR':
298        SGText.append(' The lattice is '+CentStr+' '+SGData['SGLatt']+'-centered '+SGData['SGSys'].lower())
299    else:
300        SGText.append(' The lattice is '+CentStr+' '+'primitive '+SGData['SGSys'].lower()) 
301    SGText.append(' The Laue symmetry is '+SGData['SGLaue'])
302    if 'SGPtGrp' in SGData:         #patch
303        SGText.append(' The lattice point group is '+SGData['SGPtGrp'])
304    SGText.append(' Multiplicity of a general site is '+str(Mult))
305    if SGData['SGUniq'] in ['a','b','c']:
306        SGText.append(' The unique monoclinic axis is '+SGData['SGUniq'])
307    if SGData['SGInv']:
308        SGText.append(' The inversion center is located at 0,0,0')
309    if SGData['SGPolax']:
310        SGText.append(' The location of the origin is arbitrary in '+SGData['SGPolax'])
311    SGText.append(' ')
312    if SGData['SGLatt'] == 'P':
313        SGText.append(' The equivalent positions are:\n')
314    else:   
315        SGText.append(' The equivalent positions are:')
316        SGText.append(' ('+Latt2text(SGData['SGLatt'])+')+\n')
317    SGTable = []
318    for i,Opr in enumerate(SGData['SGOps']):
319        SGTable.append('(%2d) %s'%(i+1,MT2text(Opr)))
320    return SGText,SGTable
321
322def AllOps(SGData):
323    '''
324    Returns a list of all operators for a space group, including those for
325    centering and a center of symmetry
326   
327    :param SGData: from :func:`SpcGroup`
328    :returns: (SGTextList,offsetList,symOpList,G2oprList) where
329
330      * SGTextList: a list of strings with formatted and normalized
331        symmetry operators.
332      * offsetList: a tuple of (dx,dy,dz) offsets that relate the GSAS-II
333        symmetry operation to the operator in SGTextList and symOpList.
334        these dx (etc.) values are added to the GSAS-II generated
335        positions to provide the positions that are generated
336        by the normalized symmetry operators.       
337      * symOpList: a list of tuples with the normalized symmetry
338        operations as (M,T) values
339        (see ``SGOps`` in the :ref:`Space Group object<SGData_table>`)
340      * G2oprList: The GSAS-II operations for each symmetry operation as
341        a tuple with (center,mult,opnum), where center is (0,0,0), (0.5,0,0),
342        (0.5,0.5,0.5),...; where mult is 1 or -1 for the center of symmetry
343        and opnum is the number for the symmetry operation, in ``SGOps``
344        (starting with 0).
345    '''
346    SGTextList = []
347    offsetList = []
348    symOpList = []
349    G2oprList = []
350    onebar = (1,)
351    if SGData['SGInv']:
352        onebar += (-1,)
353    for cen in SGData['SGCen']:
354        for mult in onebar:
355            for j,(M,T) in enumerate(SGData['SGOps']):
356                offset = [0,0,0]
357                Tprime = (mult*T)+cen
358                for i in range(3):
359                    while Tprime[i] < 0:
360                        Tprime[i] += 1
361                        offset[i] += 1
362                    while Tprime[i] >= 1:
363                        Tprime[i] += -1
364                        offset[i] += -1
365                Opr = [mult*M,Tprime]
366                OPtxt = MT2text(Opr)
367                SGTextList.append(OPtxt.replace(' ',''))
368                offsetList.append(tuple(offset))
369                symOpList.append((mult*M,Tprime))
370                G2oprList.append((cen,mult,j))
371    return SGTextList,offsetList,symOpList,G2oprList
372   
373def MT2text(Opr):
374    "From space group matrix/translation operator returns text version"
375    XYZ = ('-Z','-Y','-X','X-Y','ERR','Y-X','X','Y','Z')
376    TRA = ('   ','ERR','1/6','1/4','1/3','ERR','1/2','ERR','2/3','3/4','5/6','ERR')
377    Fld = ''
378    M,T = Opr
379    for j in range(3):
380        IJ = int(round(2*M[j][0]+3*M[j][1]+4*M[j][2]+4))%12
381        IK = int(round(T[j]*12))%12
382        if IK:
383            if IJ < 3:
384                Fld += (TRA[IK]+XYZ[IJ]).rjust(5)
385            else:
386                Fld += (TRA[IK]+'+'+XYZ[IJ]).rjust(5)
387        else:
388            Fld += XYZ[IJ].rjust(5)
389        if j != 2: Fld += ', '
390    return Fld
391   
392def Latt2text(Latt):
393    "From lattice type ('P',A', etc.) returns ';' delimited cell centering vectors"
394    lattTxt = {'A':'0,0,0; 0,1/2,1/2','B':'0,0,0; 1/2,0,1/2',
395        'C':'0,0,0; 1/2,1/2,0','I':'0,0,0; 1/2,1/2,1/2',
396        'F':'0,0,0; 0,1/2,1/2; 1/2,0,1/2; 1/2,1/2,0',
397        'R':'0,0,0; 1/3,2/3,2/3; 2/3,1/3,1/3','P':'0,0,0'}
398    return lattTxt[Latt]   
399       
400def SpaceGroup(SGSymbol):
401    '''
402    Print the output of SpcGroup in a nicely formatted way.
403
404    :param SGSymbol: space group symbol (string) with spaces between axial fields
405    :returns: nothing
406    '''
407    E,A = SpcGroup(SGSymbol)
408    if E > 0:
409        print SGErrors(E)
410        return
411    for l in SGPrint(A):
412        print l
413       
414################################################################################
415#### Superspace group codes
416################################################################################
417       
418def SSpcGroup(SGData,SSymbol):
419    """
420    Determines supersymmetry information from superspace group name; currently only for (3+1) superlattices
421
422    :param SGData: space group data structure as defined in SpcGroup above.
423    :param SSymbol: superspace group symbol extension (string) defining modulation direction & generator info.
424    :returns: (SSGError,SSGData)
425       * SGError = 0 for no errors; >0 for errors (see SGErrors below for details)
426       * SSGData - is a dict (see :ref:`Superspace Group object<SSGData_table>`) with entries:
427       
428             * 'SSpGrp': superspace group symbol extension to space group symbol, accidental spaces removed
429             * 'SSGCen': 4D cell centering vectors [0,0,0,0] at least
430             * 'SSGOps': 4D symmetry operations as [M,T] so that M*x+T = x'
431
432    """
433   
434    def checkModSym():
435        '''
436        Checks to see if proposed modulation form is allowed for Laue group
437        '''
438        if LaueId in [0,] and LaueModId in [0,]:
439            return True
440        elif LaueId in [1,]:
441            try:
442                if modsym.index('1/2') != ['A','B','C'].index(SGData['SGLatt']):
443                    return False
444                if 'I'.index(SGData['SGLatt']) and modsym.count('1/2') not in [0,2]:
445                    return False
446            except ValueError:
447                pass
448            if SGData['SGUniq'] == 'a' and LaueModId in [5,6,7,8,9,]:
449                return True
450            elif SGData['SGUniq'] == 'b' and LaueModId in [3,4,13,14,15,]:
451                return True
452            elif SGData['SGUniq'] == 'c' and LaueModId in [1,2,19,20,21,]:
453                return True
454        elif LaueId in [2,] and LaueModId in [i+7 for i in range(18)]:
455            try:
456                if modsym.index('1/2') != ['A','B','C'].index(SGData['SGLatt']):
457                    return False
458                if SGData['SGLatt'] in ['I','F',] and modsym.index('1/2'):
459                    return False
460            except ValueError:
461                pass
462            return True
463        elif LaueId in [3,4,] and LaueModId in [19,22,]:
464            try:
465                if SGData['SGLatt'] == 'I' and modsym.count('1/2'):
466                    return False
467            except ValueError:
468                pass
469            return True
470        elif LaueId in [7,8,9,] and LaueModId in [19,25,]:
471            if (SGData['SGLatt'] == 'R' or SGData['SGPtGrp'] in ['3m1','-3m1']) and modsym.count('1/3'):
472                return False
473            return True
474        elif LaueId in [10,11,] and LaueModId in [19,]:
475            return True
476        return False
477       
478    def fixMonoOrtho():
479        mod = ''.join(modsym).replace('1/2','0').replace('1','0')
480        if SGData['SGPtGrp'] in ['2','m']:  #OK
481            if mod in ['a00','0b0','00g']:
482                result = [i*-1 for i in SGData['SSGKl']]
483            else:
484                result = SGData['SSGKl'][:]
485            if '/' in mod:
486                return [i*-1 for i in result]
487            else:
488                return result
489        elif SGData['SGPtGrp'] == '2/m':    #OK
490            if mod in ['a00','0b0','00g']:
491                result =  SGData['SSGKl'][:]
492            else:
493                result = [i*-1 for i in SGData['SSGKl']]
494            if '/' in mod:
495                return [i*-1 for i in result]
496            else:
497                return result
498        else:   #orthorhombic
499            if SGData['SGPtGrp'] == '222':
500                return [1 if i in ['a','b','g'] else -1 for i in mod]
501            elif SGData['SGPtGrp'] == 'mm2':
502                if 'g' in mod:
503                    return [1,1,1]
504                elif 'b' in mod:
505                    return [1,-1,-1]
506                else:
507                    return [-1,1,-1]
508            elif SGData['SGPtGrp'] == 'm2m':
509                if 'b' in mod:
510                    return [1,1,1]
511                elif 'g' in mod:
512                    return [1,-1,-1]
513                else:
514                    return [-1,-1,1]               
515            elif SGData['SGPtGrp'] == '2mm':
516                if 'a' in mod:
517                    return [1,1,1]
518                elif 'b' in mod:
519                    return [-1,-1,1]
520                else:
521                    return [-1,1,-1]
522            else:
523                return [-1 if i in ['a','b','g'] else 1 for i in mod]
524               
525    def extendSSGOps(SSGOps):
526        nOps = len(SSGOps)
527        for i in range(nOps):
528            if np.allclose(SSGOps[i][0][3],np.zeros(4)):
529                continue
530            for j in range(nOps):
531                if np.allclose(SSGOps[j][0][3],np.zeros(4)):
532                    continue
533                OpC = list(SGProd(SSGOps[j],SSGOps[i]))
534                OpC[1] %= 1.
535                for k in range(nOps):
536                    OpD = SSGOps[k]
537                    if SSMT2text(OpC) == SSMT2text(OpD):
538                        continue
539                    elif np.allclose(OpC[0][:3,:3],OpD[0][:3,:3]):
540                        if np.allclose(OpD[0][3],np.zeros(4)):
541                            SSGOps[k] = OpC
542                        elif np.any([np.allclose(OpC[0][3][:3],cen) for cen in SGData['SGCen']]):   #?
543                            continue
544                        else:
545                            OpCtxt = SSMT2text(OpC).replace(' ','')
546                            OpDtxt = SSMT2text(OpD).replace(' ','')
547                            print 'OpC',OpCtxt,'OpD',OpDtxt
548                            return False,OpCtxt+' conflict with '+OpDtxt
549        return True,SSGOps
550               
551    def genSSGOps():
552        SSGOps = SSGData['SSGOps'][:]
553        iFrac = {}
554        for i,frac in enumerate(SSGData['modSymb']):
555            if frac in ['1/2','1/3','1/4','1/6','1']:
556                iFrac[i] = frac
557        print SGData['SpGrp']+SSymbol
558        print 'SSGKl',SSGKl,'genQ',genQ,'iFrac',iFrac
559# set identity & 1,-1; triclinic
560        SSGOps[0][0][3,3] = 1.
561# expand if centrosymmetric
562        if SGData['SGInv']:
563            SSGOps += [[-1*M,V] for M,V in SSGOps[:]]
564# monoclinic - all done & all checked
565        if SGData['SGPtGrp'] in ['2','m']:  #OK
566            SSGOps[1][0][3,3] = SSGKl[0]
567            SSGOps[1][1][3] = genQ[0]
568            for i in iFrac:
569                SSGOps[1][0][3,i] = -SSGKl[0]
570        elif SGData['SGPtGrp'] == '2/m':    #OK
571            for i,j in enumerate([1,3]):
572                SSGOps[j][0][3,3] = -SSGKl[i]
573                if genQ[i]:
574                    SSGOps[j][1][3] = genQ[i]
575                for k in iFrac:
576                    SSGOps[j][0][3,k] = SSGKl[i]
577           
578# orthorhombic
579        elif SGData['SGPtGrp'] in ['222','mm2','m2m','2mm','mmm']:
580            for i in [0,1,2]:
581                SSGOps[i+1][0][3,3] = SSGKl[i]
582                SSGOps[i+1][1][3] = genQ[i]
583            for i in iFrac:
584                SSGOps[1][0][3,i] = -1
585            print SSMT2text(SSGOps[1]).replace(' ',''),SSMT2text(SSGOps[2]).replace(' ',''), \
586                SSMT2text(SSGOps[3]).replace(' ','')
587               
588# tetragonal
589        elif SGData['SGPtGrp'] == '4':  #OK
590            SSGOps[1][0][3,3] = SSGKl[0]
591            SSGOps[1][1][3] = genQ[0]
592            if '1/2' in SSGData['modSymb']:
593                SSGOps[1][0][3,1] = -1
594        elif SGData['SGPtGrp'] == '-4': #OK
595            SSGOps[1][0][3,3] = SSGKl[0]
596            if '1/2' in SSGData['modSymb']:
597                SSGOps[1][0][3,1] = 1
598        elif SGData['SGPtGrp'] in ['4/m',]:
599            if '1/2' in SSGData['modSymb']:
600                SSGOps[1][0][3,1] = SSGKl[0]
601            for i,j in enumerate([1,6]):
602                SSGOps[j][0][3,3] = SSGKl[i]
603                if genQ[i]:
604                    SSGOps[j][1][3] = genQ[i]
605                E,SSGOps = extendSSGOps(SSGOps)
606        elif SGData['SGPtGrp'] in ['422','4mm','-42m','-4m2',]:
607            if '1/2' in SSGData['modSymb']:
608                SSGOps[1][0][3,1] = SSGKl[0]
609            for i,j in enumerate([1,4,5]):
610                SSGOps[j][0][3,3] = SSGKl[i]
611                if genQ[i]:
612                    SSGOps[j][1][3] = genQ[i]
613                E,SSGOps = extendSSGOps(SSGOps)
614        elif SGData['SGPtGrp'] in ['4/mmm',]:
615            if '1/2' in SSGData['modSymb']:
616                SSGOps[1][0][3,1] = -1
617            for i,j in enumerate([1,10,6,7]):
618                SSGOps[j][0][3,3] = SSGKl[i]
619                if genQ[i]:
620                    SSGOps[j][1][3] = genQ[i]
621#                for k in iFrac:
622#                    SSGOps[j][0][3,k] = SSGKl[i]
623                E,SSGOps = extendSSGOps(SSGOps)
624               
625# trigonal - all done
626        elif SGData['SGPtGrp'] == '3':  #OK
627            SSGOps[1][0][3,3] = SSGKl[0]
628            if '1/3' in SSGData['modSymb']:
629                SSGOps[1][0][3,1] = -1
630            SSGOps[1][1][3] = genQ[0]
631        elif SGData['SGPtGrp'] == '-3': #OK
632            SSGOps[1][0][3,3] = -SSGKl[0]
633            if '1/3' in SSGData['modSymb']:
634                SSGOps[1][0][3,1] = -1
635            SSGOps[1][1][3] = genQ[0]
636        elif SGData['SGPtGrp'] in ['312','3m','-3m','-3m1','3m1']:   #OK
637            if '1/3' in SSGData['modSymb']:
638                SSGOps[1][0][3,1] = -1
639            for i,j in enumerate([1,5]):
640                if SGData['SGPtGrp'] in ['3m','-3m']:
641                    SSGOps[j][0][3,3] = SSGKl[i]
642                else:                   
643                    SSGOps[j][0][3,3] = SSGKl[i+1]
644                if genQ[i]:
645                    SSGOps[j][1][3] = genQ[i]
646        elif SGData['SGPtGrp'] in ['321','32']:   #OK
647            for i,j in enumerate([1,4]):
648                SSGOps[j][0][3,3] = SSGKl[i]
649                if genQ[i]:
650                    SSGOps[j][1][3] = genQ[i]
651        elif SGData['SGPtGrp'] in ['31m','-31m']:   #OK
652            ids = [1,3]
653            if SGData['SGPtGrp'] == '-31m':
654                ids = [7,3]
655            if '1/3' in SSGData['modSymb']:
656                SSGOps[ids[0]][0][3,1] = -1
657            for i,j in enumerate(ids):
658                SSGOps[j][0][3,3] = SSGKl[i]
659                if genQ[i+1]:
660                    SSGOps[j][1][3] = genQ[i+1]
661                     
662# hexagonal - all done
663        elif SGData['SGPtGrp'] == '6':  #OK
664            SSGOps[1][0][3,3] = SSGKl[0]
665            SSGOps[1][1][3] = genQ[0]
666        elif SGData['SGPtGrp'] == '-6': #OK
667            SSGOps[1][0][3,3] = SSGKl[0]
668        elif SGData['SGPtGrp'] in ['6/m',]: #OK
669            SSGOps[1][0][3,3] = -SSGKl[1]
670            SSGOps[1][1][3] = genQ[0]
671            SSGOps[2][1][3] = genQ[1]
672        elif SGData['SGPtGrp'] in ['622','6mm','-62m','-6m2',]: #OK
673            for i,j in enumerate([1,10,11]):
674                SSGOps[j][0][3,3] = SSGKl[i]
675                if genQ[i]:
676                    SSGOps[j][1][3] = genQ[i]
677                E,SSGOps = extendSSGOps(SSGOps)
678        elif SGData['SGPtGrp'] in ['6/mmm',]: #OK
679            for i,j in enumerate([1,15,10,11]):
680                SSGOps[j][0][3,3] = SSGKl[i]
681                if genQ[i]:
682                    SSGOps[j][1][3] = genQ[i]
683                E,SSGOps = extendSSGOps(SSGOps)
684        elif SGData['SGPtGrp'] in ['1','-1']: #triclinic - done
685            return True,SSGOps
686        E,SSGOps = extendSSGOps(SSGOps)
687        return E,SSGOps
688       
689    def specialGen(gensym):
690        sym = ''.join(gensym)
691        if SGData['SGPtGrp'] in ['2/m',] and 'n' in SGData['SpGrp']:
692            if 's' in sym:
693                gensym = 'ss'
694        if SGData['SGPtGrp'] in ['-62m',] and sym == '00s':
695            gensym = '0ss'
696        elif SGData['SGPtGrp'] in ['222',]:
697            if sym == '00s':
698                gensym = '0ss'
699            elif sym == '0s0':
700                gensym = 'ss0'
701            elif sym == 's00':
702                gensym = 's0s'
703        return gensym
704                   
705    def checkGen(gensym):
706        sym = ''.join(gensym)
707        print str(SSGKl),sym
708# monoclinic - all done
709        if str(SSGKl) == '[-1]' and sym == 's':
710            return False
711        elif SGData['SGPtGrp'] in ['2/m',]:
712            if str(SSGKl) == '[-1, 1]' and sym == '0s':
713                return False
714            elif str(SSGKl) == '[1, -1]' and sym == 's0':
715                return False
716#orthorhombic - all
717        elif SGData['SGPtGrp'] in ['222',] and sym not in ['','s00','0s0','00s']:
718            return False 
719        elif SGData['SGPtGrp'] in ['2mm','m2m','mm2','mmm'] and sym not in GenSymList[4:15]:
720            return False 
721#tetragonal - all done
722        elif SGData['SGPtGrp'] in ['4',] and sym not in ['','s','q']:
723            return False 
724        elif SGData['SGPtGrp'] in ['-4',] and sym not in ['',]:
725            return False             
726        elif SGData['SGPtGrp'] in ['4/m',] and sym not in ['','s0','q0']:
727            return False
728        elif SGData['SGPtGrp'] in ['422',] and sym not in ['','q00','s00']:
729            return False         
730        elif SGData['SGPtGrp'] in ['4mm',] and sym not in ['','ss0','s0s','0ss','qq0','qqs']:
731            return False
732        elif SGData['SGPtGrp'] in ['-4m2',] and sym not in ['','00s','00q']:
733            return False
734        elif SGData['SGPtGrp'] in ['-42m',] and sym not in ['','0s0','0q0']:
735            return False
736        elif SGData['SGPtGrp'] in ['4/mmm',] and sym not in ['','s00s','s0s0','00ss','q0q0','q0qs']:
737            return False
738#trigonal/rhombohedral - all done
739        elif SGData['SGPtGrp'] in ['3',] and sym not in ['','t']:
740            return False 
741        elif SGData['SGPtGrp'] in ['-3',] and sym not in ['',]:
742            return False 
743        elif SGData['SGPtGrp'] in ['32',] and sym not in ['','t0']:
744            return False 
745        elif SGData['SGPtGrp'] in ['321','312'] and sym not in ['','t00']:
746            return False 
747        elif SGData['SGPtGrp'] in ['3m','-3m'] and sym not in ['','0s']:
748            return False 
749        elif SGData['SGPtGrp'] in ['3m1','-3m1'] and sym not in ['','0s0']:
750            return False 
751        elif SGData['SGPtGrp'] in ['31m','-31m'] and sym not in ['','00s']:
752            return False 
753#hexagonal - all done
754        elif SGData['SGPtGrp'] in ['6',] and sym not in ['','s','h','t']:
755            return False 
756        elif SGData['SGPtGrp'] in ['-6',] and sym not in ['',]:
757            return False
758        elif SGData['SGPtGrp'] in ['6/m',] and sym not in ['','s0']:
759            return False
760        elif SGData['SGPtGrp'] in ['622',] and sym not in ['','h00','t00','s00']:
761            return False         
762        elif SGData['SGPtGrp'] in ['6mm',] and sym not in ['','ss0','s0s','0ss']:
763            return False
764        elif SGData['SGPtGrp'] in ['-6m2',] and sym not in ['','0s0']:
765            return False
766        elif SGData['SGPtGrp'] in ['-62m',] and sym not in ['','0ss']:
767            return False
768        elif SGData['SGPtGrp'] in ['6/mmm',] and sym not in ['','s00s','s0s0','00ss']:
769            return False
770        return True
771       
772    LaueModList = ['abg', 'ab0', 'ab1/2', 'a0g', 'a1/2g','0bg', '1/2bg',
773               'a00', 'a01/2', 'a1/20', 'a1/21/2', 'a01', 'a10', 
774               '0b0', '0b1/2', '1/2b0', '1/2b1/2', '0b1', '1b0',
775               '00g', '01/2g', '1/20g', '1/21/2g', '01g', '10g','1/31/3g']
776    LaueList = ['-1','2/m','mmm','4/m','4/mmm','3R','3mR','3','3m1','31m','6/m','6/mmm','m3','m3m']
777    GenSymList = ['','s','0s','s0','00s','0s0','s00','s0s','ss0','0ss','q00','0q0','00q','qq0','q0q','0qq',
778        'q','q0','0q','qqs','s0s0','00ss','s00s','q0q0','q0qs','t','t00','t0','h','h00']
779    Fracs = {'1/2':0.5,'1/3':1./3,'1':1.0,'0':0.,'s':.5,'t':1./3,'q':.25,'h':1./6,'a':0.,'b':0.,'g':0.}
780    LaueId = LaueList.index(SGData['SGLaue'])
781    if SGData['SGLaue'] in ['m3','m3m']:
782        return '(3+1) superlattices not defined for cubic space groups',None
783    elif SGData['SGLaue'] in ['3R','3mR']:
784        return '(3+1) superlattices not defined for rhombohedral settings - use hexagonal setting',None
785    try:
786        modsym,gensym = splitSSsym(SSymbol)
787    except ValueError:
788        return 'Error in superspace symbol '+SSymbol,None
789    if ''.join(gensym) not in GenSymList:
790        return 'unknown generator symbol '+''.join(gensym),None
791    try:
792        print modsym,''.join(modsym)
793        LaueModId = LaueModList.index(''.join(modsym))
794    except ValueError:
795        return 'Unknown modulation symbol '+''.join(modsym),None
796    if not checkModSym():
797        return 'Modulation '+''.join(modsym)+' not consistent with space group '+SGData['SpGrp'],None
798    modQ = [Fracs[mod] for mod in modsym]
799    SSGKl = SGData['SSGKl'][:]
800    if SGData['SGLaue'] in ['2/m','mmm']:
801        SSGKl = fixMonoOrtho()
802    if len(gensym) and len(gensym) != len(SSGKl):
803        return 'Wrong number of items in generator symbol '+''.join(gensym),None
804    if not checkGen(gensym):
805        return 'Generator '+''.join(gensym)+' not consistent with space group '+SGData['SpGrp'],None
806    gensym = specialGen(gensym)
807    genQ = [Fracs[mod] for mod in gensym]
808    if not genQ:
809        genQ = [0,0,0,0]
810    SSGData = {'SSpGrp':SGData['SpGrp']+SSymbol,'modQ':modQ,'modSymb':modsym}
811    SSCen = np.zeros((len(SGData['SGCen']),4))
812    for icen,cen in enumerate(SGData['SGCen']):
813        SSCen[icen,0:3] = cen
814    SSCen[0] = np.zeros(4)
815    SSGData['SSGCen'] = SSCen
816    SSGData['SSGOps'] = []
817    for iop,op in enumerate(SGData['SGOps']):
818        T = np.zeros(4)
819        ssop = np.zeros((4,4))
820        ssop[:3,:3] = op[0]
821        T[:3] = op[1]
822        SSGData['SSGOps'].append([ssop,T])
823    E,Result = genSSGOps()
824    if E:
825        SSGData['SSGOps'] = Result                     
826        return None,SSGData
827    else:
828        return Result+'\nOperator conflict - incorrect superspace symbol',None
829
830def splitSSsym(SSymbol):
831    '''
832    Splits supersymmetry symbol into two lists of strings
833    '''
834    modsym,gensym = SSymbol.replace(' ','').split(')')
835    nfrac = modsym.count('/')
836    modsym = modsym.lstrip('(')
837    if nfrac == 0:
838        modsym = list(modsym)
839    elif nfrac == 1:
840        pos = modsym.find('/')
841        if pos == 1:
842            modsym = [modsym[:3],modsym[3],modsym[4]]
843        elif pos == 2:
844            modsym = [modsym[0],modsym[1:4],modsym[4]]
845        else:
846            modsym = [modsym[0],modsym[1],modsym[2:]]
847    else:
848        lpos = modsym.find('/')
849        rpos = modsym.rfind('/')
850        if lpos == 1 and rpos == 4:
851            modsym = [modsym[:3],modsym[3:6],modsym[6]]
852        elif lpos == 1 and rpos == 5:
853            modsym = [modsym[:3],modsym[3],modsym[4:]]
854        else:
855            modsym = [modsym[0],modsym[1:4],modsym[4:]]
856    gensym = list(gensym)
857    return modsym,gensym
858       
859def SSGPrint(SGData,SSGData):
860    '''
861    Print the output of SSpcGroup in a nicely formatted way. Used in SSpaceGroup
862
863    :param SGData: space group data structure as defined in SpcGroup above.
864    :param SSGData: from :func:`SSpcGroup`
865    :returns:
866        SSGText - list of strings with the superspace group details
867        SGTable - list of strings for each of the operations
868    '''
869    Mult = len(SSGData['SSGCen'])*len(SSGData['SSGOps'])
870    SSGText = []
871    SSGText.append(' Superspace Group: '+SSGData['SSpGrp'])
872    CentStr = 'centrosymmetric'
873    if not SGData['SGInv']:
874        CentStr = 'non'+CentStr
875    if SGData['SGLatt'] in 'ABCIFR':
876        SSGText.append(' The lattice is '+CentStr+' '+SGData['SGLatt']+'-centered '+SGData['SGSys'].lower())
877    else:
878        SSGText.append(' The superlattice is '+CentStr+' '+'primitive '+SGData['SGSys'].lower())       
879    SSGText.append(' The Laue symmetry is '+SGData['SGLaue'])
880    SSGText.append(' The superlattice point group is '+SGData['SGPtGrp']+','+''.join([str(i) for i in SGData['SSGKl']]))
881    SSGText.append(' The number of superspace group generators is '+str(len(SGData['SSGKl'])))
882    SSGText.append(' Multiplicity of a general site is '+str(Mult))
883    if SGData['SGUniq'] in ['a','b','c']:
884        SSGText.append(' The unique monoclinic axis is '+SGData['SGUniq'])
885    if SGData['SGInv']:
886        SSGText.append(' The inversion center is located at 0,0,0')
887    if SGData['SGPolax']:
888        SSGText.append(' The location of the origin is arbitrary in '+SGData['SGPolax'])
889    SSGText.append(' ')
890    if len(SSGData['SSGCen']) > 1:
891        SSGText.append(' The equivalent positions are:')
892        SSGText.append(' ('+SSLatt2text(SSGData['SSGCen'])+')+\n')
893    else:
894        SSGText.append(' The equivalent positions are:\n')
895    SSGTable = []
896    for i,Opr in enumerate(SSGData['SSGOps']):
897        SSGTable.append('(%2d) %s'%(i+1,SSMT2text(Opr)))
898    return SSGText,SSGTable
899   
900def SSGModCheck(Vec,modSymb):
901    ''' Checks modulation vector compatibility with supersymmetry space group symbol.
902    Superspace group symbol takes precidence & the vector will be modified accordingly
903    '''
904    Fracs = {'1/2':0.5,'1/3':1./3,'1':1.0,'0':0.,'a':0.,'b':0.,'g':0.}
905    modQ = [Fracs[mod] for mod in modSymb]
906    Vec = [0.1 if (vec == 0.0 and mod in ['a','b','g']) else vec for [vec,mod] in zip(Vec,modSymb)]
907    return [Q if mod not in ['a','b','g'] and vec != Q else vec for [vec,mod,Q] in zip(Vec,modSymb,modQ)],  \
908        [True if mod in ['a','b','g'] else False for mod in modSymb]
909
910def SSMT2text(Opr):
911    "From superspace group matrix/translation operator returns text version"
912    XYZS = ('x','y','z','t')    #Stokes, Campbell & van Smaalen notation
913    TRA = ('   ','ERR','1/6','1/4','1/3','ERR','1/2','ERR','2/3','3/4','5/6','ERR')
914    Fld = ''
915    M,T = Opr
916    for j in range(4):
917        IJ = ''
918        for k in range(4):
919            txt = str(int(round(M[j][k])))
920            txt = txt.replace('1',XYZS[k]).replace('0','')
921            if '2' in txt:
922                txt += XYZS[k]
923            if IJ and M[j][k] > 0:
924                IJ += '+'+txt
925            else:
926                IJ += txt
927        IK = int(round(T[j]*12))%12
928        if IK:
929            if not IJ:
930                break
931            if IJ[0] == '-':
932                Fld += (TRA[IK]+IJ).rjust(8)
933            else:
934                Fld += (TRA[IK]+'+'+IJ).rjust(8)
935        else:
936            Fld += IJ.rjust(8)
937        if j != 3: Fld += ', '
938    return Fld
939   
940def SSLatt2text(SSGCen):
941    "Lattice centering vectors to text"
942    lattTxt = ''
943    for vec in SSGCen:
944        lattTxt += ' '
945        for item in vec:
946            if int(item*12.):
947                lattTxt += '1/%d,'%(12/int(item*12))
948            else:
949                lattTxt += '0,'
950        lattTxt = lattTxt.rstrip(',')
951        lattTxt += ';'
952    lattTxt = lattTxt.rstrip(';').lstrip(' ')
953    return lattTxt
954       
955def SSpaceGroup(SGSymbol,SSymbol):
956    '''
957    Print the output of SSpcGroup in a nicely formatted way.
958
959    :param SGSymbol: space group symbol with spaces between axial fields.
960    :param SSymbol: superspace group symbol extension (string).
961    :returns: nothing
962    '''
963
964    E,A = SpcGroup(SGSymbol)
965    if E > 0:
966        print SGErrors(E)
967        return
968    E,B = SSpcGroup(A,SSymbol)   
969    if E > 0:
970        print E
971        return
972    for l in SSGPrint(B):
973        print l
974       
975def SGProd(OpA,OpB):
976    '''
977    Form space group operator product. OpA & OpB are [M,V] pairs;
978        both must be of same dimension (3 or 4). Returns [M,V] pair
979    '''
980    A,U = OpA
981    B,V = OpB
982    M = np.inner(B.T,A)
983    W = np.inner(B,U)+V
984    return M.T,W
985       
986def MoveToUnitCell(xyz):
987    '''
988    Translates a set of coordinates so that all values are >=0 and < 1
989
990    :param xyz: a list or numpy array of fractional coordinates
991    :returns: XYZ - numpy array of new coordinates now 0 or greater and less than 1
992    '''
993    XYZ = np.zeros(3)
994    for i,x in enumerate(xyz):
995        XYZ[i] = (x-int(x))%1.0
996    return XYZ
997       
998def Opposite(XYZ,toler=0.0002):
999    '''
1000    Gives opposite corner, edge or face of unit cell for position within tolerance.
1001        Result may be just outside the cell within tolerance
1002
1003    :param XYZ: 0 >= np.array[x,y,z] > 1 as by MoveToUnitCell
1004    :param toler: unit cell fraction tolerance making opposite
1005    :returns:
1006        XYZ: array of opposite positions; always contains XYZ
1007    '''
1008    perm3 = [[1,1,1],[0,1,1],[1,0,1],[1,1,0],[1,0,0],[0,1,0],[0,0,1],[0,0,0]]
1009    TB = np.where(abs(XYZ-1)<toler,-1,0)+np.where(abs(XYZ)<toler,1,0)
1010    perm = TB*perm3
1011    cperm = ['%d%d%d'%(i,j,k) for i,j,k in perm]
1012    D = dict(zip(cperm,perm))
1013    new = []
1014    for key in D:
1015        new.append(np.array(D[key])+np.array(XYZ))
1016    return new
1017       
1018def GenAtom(XYZ,SGData,All=False,Uij=[],Move=True):
1019    '''
1020    Generates the equivalent positions for a specified coordinate and space group
1021
1022    :param XYZ: an array, tuple or list containing 3 elements: x, y & z
1023    :param SGData: from :func:`SpcGroup`
1024    :param All: True return all equivalent positions including duplicates;
1025      False return only unique positions
1026    :param Uij: [U11,U22,U33,U12,U13,U23] or [] if no Uij
1027    :param Move: True move generated atom positions to be inside cell
1028      False do not move atoms       
1029    :return: [[XYZEquiv],Idup,[UijEquiv]]
1030
1031      *  [XYZEquiv] is list of equivalent positions (XYZ is first entry)
1032      *  Idup = [-][C]SS where SS is the symmetry operator number (1-24), C (if not 0,0,0)
1033      * is centering operator number (1-4) and - is for inversion
1034        Cell = unit cell translations needed to put new positions inside cell
1035        [UijEquiv] - equivalent Uij; absent if no Uij given
1036       
1037    '''
1038    XYZEquiv = []
1039    UijEquiv = []
1040    Idup = []
1041    Cell = []
1042    X = np.array(XYZ)
1043    if Move:
1044        X = MoveToUnitCell(X)
1045    for ic,cen in enumerate(SGData['SGCen']):
1046        C = np.array(cen)
1047        for invers in range(int(SGData['SGInv']+1)):
1048            for io,[M,T] in enumerate(SGData['SGOps']):
1049                idup = ((io+1)+100*ic)*(1-2*invers)
1050                XT = np.inner(M,X)+T
1051                if len(Uij):
1052                    U = Uij2U(Uij)
1053                    U = np.inner(M,np.inner(U,M).T)
1054                    newUij = U2Uij(U)
1055                if invers:
1056                    XT = -XT
1057                XT += C
1058                if Move:
1059                    newX = MoveToUnitCell(XT)
1060                else:
1061                    newX = XT
1062                cell = np.asarray(np.rint(newX-XT),dtype=np.int32)
1063                if All:
1064                    if np.allclose(newX,X,atol=0.0002):
1065                        idup = False
1066                else:
1067                    if True in [np.allclose(newX,oldX,atol=0.0002) for oldX in XYZEquiv]:
1068                        idup = False
1069                if All or idup:
1070                    XYZEquiv.append(newX)
1071                    Idup.append(idup)
1072                    Cell.append(cell)
1073                    if len(Uij):
1074                        UijEquiv.append(newUij)                   
1075    if len(Uij):
1076        return zip(XYZEquiv,UijEquiv,Idup,Cell)
1077    else:
1078        return zip(XYZEquiv,Idup,Cell)
1079
1080def GenHKLf(HKL,SGData):
1081    '''
1082    Uses old GSAS Fortran routine genhkl.for
1083
1084    :param HKL:  [h,k,l]
1085    :param SGData: space group data obtained from SpcGroup
1086    :returns: iabsnt,mulp,Uniq,phi
1087
1088     *   iabsnt = True if reflection is forbidden by symmetry
1089     *   mulp = reflection multiplicity including Friedel pairs
1090     *   Uniq = numpy array of equivalent hkl in descending order of h,k,l
1091
1092    '''
1093    hklf = HKL+[0,]
1094    Ops = SGData['SGOps']
1095    OpM = np.array([op[0] for op in Ops])
1096    OpT = np.array([op[1] for op in Ops])
1097    Inv = SGData['SGInv']
1098    Cen = np.array([cen for cen in SGData['SGCen']])
1099   
1100    Nuniq,Uniq,iabsnt,mulp = pyspg.genhklpy(hklf,len(Ops),OpM,OpT,SGData['SGInv'],len(Cen),Cen)
1101    h,k,l,f = Uniq
1102    Uniq=np.array(zip(h[:Nuniq],k[:Nuniq],l[:Nuniq]))
1103    phi = f[:Nuniq]
1104   
1105    return iabsnt,mulp,Uniq,phi
1106                                 
1107def GetOprPtrName(key):
1108    'Needs a doc string'
1109    OprPtrName = {
1110        '-6643':[   2,' 1bar ', 1],'6479' :[  10,'  2z  ', 2],'-6479':[   9,'  mz  ', 3],
1111        '6481' :[   7,'  my  ', 4],'-6481':[   6,'  2y  ', 5],'6641' :[   4,'  mx  ', 6],
1112        '-6641':[   3,'  2x  ', 7],'6591' :[  28,' m+-0 ', 8],'-6591':[  27,' 2+-0 ', 9],
1113        '6531' :[  25,' m110 ',10],'-6531':[  24,' 2110 ',11],'6537' :[  61,'  4z  ',12],
1114        '-6537':[  62,' -4z  ',13],'975'  :[  68,' 3+++1',14],'6456' :[ 114,'  3z1 ',15],
1115        '-489' :[  73,' 3+-- ',16],'483'  :[  78,' 3-+- ',17],'-969' :[  83,' 3--+ ',18],
1116        '819'  :[  22,' m+0- ',19],'-819' :[  21,' 2+0- ',20],'2431' :[  16,' m0+- ',21],
1117        '-2431':[  15,' 20+- ',22],'-657' :[  19,' m101 ',23],'657'  :[  18,' 2101 ',24],
1118        '1943' :[  48,' -4x  ',25],'-1943':[  47,'  4x  ',26],'-2429':[  13,' m011 ',27],
1119        '2429' :[  12,' 2011 ',28],'639'  :[  55,' -4y  ',29],'-639' :[  54,'  4y  ',30],
1120        '-6484':[ 146,' 2010 ', 4],'6484' :[ 139,' m010 ', 5],'-6668':[ 145,' 2100 ', 6],
1121        '6668' :[ 138,' m100 ', 7],'-6454':[ 148,' 2120 ',18],'6454' :[ 141,' m120 ',19],
1122        '-6638':[ 149,' 2210 ',20],'6638' :[ 142,' m210 ',21],              #search ends here
1123        '2223' :[  68,' 3+++2',39],
1124        '6538' :[ 106,'  6z1 ',40],'-2169':[  83,' 3--+2',41],'2151' :[  73,' 3+--2',42],
1125        '2205' :[  79,'-3-+-2',43],'-2205':[  78,' 3-+-2',44],'489'  :[  74,'-3+--1',45],
1126        '801'  :[  53,'  4y1 ',46],'1945' :[  47,'  4x3 ',47],'-6585':[  62,' -4z3 ',48],
1127        '6585' :[  61,'  4z3 ',49],'6584' :[ 114,'  3z2 ',50],'6666' :[ 106,'  6z5 ',51],
1128        '6643' :[   1,' Iden ',52],'-801' :[  55,' -4y1 ',53],'-1945':[  48,' -4x3 ',54],
1129        '-6666':[ 105,' -6z5 ',55],'-6538':[ 105,' -6z1 ',56],'-2223':[  69,'-3+++2',57],
1130        '-975' :[  69,'-3+++1',58],'-6456':[ 113,' -3z1 ',59],'-483' :[  79,'-3-+-1',60],
1131        '969'  :[  84,'-3--+1',61],'-6584':[ 113,' -3z2 ',62],'2169' :[  84,'-3--+2',63],
1132        '-2151':[  74,'-3+--2',64],'0':[0,' ????',0]
1133        }
1134    return OprPtrName[key]
1135
1136def GetKNsym(key):
1137    'Needs a doc string'
1138    KNsym = {
1139        '0'         :'    1   ','1'         :'   -1   ','64'        :'    2(x)','32'        :'    m(x)',
1140        '97'        :'  2/m(x)','16'        :'    2(y)','8'         :'    m(y)','25'        :'  2/m(y)',
1141        '2'         :'    2(z)','4'         :'    m(z)','7'         :'  2/m(z)','134217728' :'   2(yz)',
1142        '67108864'  :'   m(yz)','201326593' :' 2/m(yz)','2097152'   :'  2(0+-)','1048576'   :'  m(0+-)',
1143        '3145729'   :'2/m(0+-)','8388608'   :'   2(xz)','4194304'   :'   m(xz)','12582913'  :' 2/m(xz)',
1144        '524288'    :'  2(+0-)','262144'    :'  m(+0-)','796433'    :'2/m(+0-)','1024'      :'   2(xy)',
1145        '512'       :'   m(xy)','1537'      :' 2/m(xy)','256'       :'  2(+-0)','128'       :'  m(+-0)',
1146        '385'       :'2/m(+-0)','76'        :'  mm2(x)','52'        :'  mm2(y)','42'        :'  mm2(z)',
1147        '135266336' :' mm2(yz)','69206048'  :'mm2(0+-)','8650760'   :' mm2(xz)','4718600'   :'mm2(+0-)',
1148        '1156'      :' mm2(xy)','772'       :'mm2(+-0)','82'        :'  222   ','136314944' :'  222(x)',
1149        '8912912'   :'  222(y)','1282'      :'  222(z)','127'       :'  mmm   ','204472417' :'  mmm(x)',
1150        '13369369'  :'  mmm(y)','1927'      :'  mmm(z)','33554496'  :'  4(100)','16777280'  :' -4(100)',
1151        '50331745'  :'4/m(100)','169869394' :'422(100)','84934738'  :'-42m 100','101711948' :'4mm(100)',
1152        '254804095' :'4/mmm100','536870928 ':'  4(010)','268435472' :' -4(010)','805306393' :'4/m (10)',
1153        '545783890' :'422(010)','272891986' :'-42m 010','541327412' :'4mm(010)','818675839' :'4/mmm010',
1154        '2050'      :'  4(001)','4098'      :' -4(001)','6151'      :'4/m(001)','3410'      :'422(001)',
1155        '4818'      :'-42m 001','2730'      :'4mm(001)','8191'      :'4/mmm001','8192'      :'  3(111)',
1156        '8193'      :' -3(111)','2629888'   :' 32(111)','1319040'   :' 3m(111)','3940737'   :'-3m(111)',
1157        '32768'     :'  3(+--)','32769'     :' -3(+--)','10519552'  :' 32(+--)','5276160'   :' 3m(+--)',
1158        '15762945'  :'-3m(+--)','65536'     :'  3(-+-)','65537'     :' -3(-+-)','134808576' :' 32(-+-)',
1159        '67437056'  :' 3m(-+-)','202180097' :'-3m(-+-)','131072'    :'  3(--+)','131073'    :' -3(--+)',
1160        '142737664' :' 32(--+)','71434368'  :' 3m(--+)','214040961' :'-3m(--+)','237650'    :'   23   ',
1161        '237695'    :'   m3   ','715894098' :'   432  ','358068946' :'  -43m  ','1073725439':'   m3m  ',
1162        '68157504'  :' mm2d100','4456464'   :' mm2d010','642'       :' mm2d001','153092172' :'-4m2 100',
1163        '277348404' :'-4m2 010','5418'      :'-4m2 001','1075726335':'  6/mmm ','1074414420':'-6m2 100',
1164        '1075070124':'-6m2 120','1075069650':'   6mm  ','1074414890':'   622  ','1073758215':'   6/m  ',
1165        '1073758212':'   -6   ','1073758210':'    6   ','1073759865':'-3m(100)','1075724673':'-3m(120)',
1166        '1073758800':' 3m(100)','1075069056':' 3m(120)','1073759272':' 32(100)','1074413824':' 32(120)',
1167        '1073758209':'   -3   ','1073758208':'    3   ','1074135143':'mmm(100)','1075314719':'mmm(010)',
1168        '1073743751':'mmm(110)','1074004034':' mm2z100','1074790418':' mm2z010','1073742466':' mm2z110',
1169        '1074004004':'mm2(100)','1074790412':'mm2(010)','1073742980':'mm2(110)','1073872964':'mm2(120)',
1170        '1074266132':'mm2(210)','1073742596':'mm2(+-0)','1073872930':'222(100)','1074266122':'222(010)',
1171        '1073743106':'222(110)','1073741831':'2/m(001)','1073741921':'2/m(100)','1073741849':'2/m(010)',
1172        '1073743361':'2/m(110)','1074135041':'2/m(120)','1075314689':'2/m(210)','1073742209':'2/m(+-0)',
1173        '1073741828':' m(001) ','1073741888':' m(100) ','1073741840':' m(010) ','1073742336':' m(110) ',
1174        '1074003968':' m(120) ','1074790400':' m(210) ','1073741952':' m(+-0) ','1073741826':' 2(001) ',
1175        '1073741856':' 2(100) ','1073741832':' 2(010) ','1073742848':' 2(110) ','1073872896':' 2(120) ',
1176        '1074266112':' 2(210) ','1073742080':' 2(+-0) ','1073741825':'   -1   '
1177        }
1178    return KNsym[key]       
1179
1180def GetNXUPQsym(siteSym):       
1181    'Needs a doc string'
1182    NXUPQsym = {
1183        '    1   ':(28,29,28,28),'   -1   ':( 1,29,28, 0),'    2(x)':(12,18,12,25),'    m(x)':(25,18,12,25),
1184        '  2/m(x)':( 1,18, 0,-1),'    2(y)':(13,17,13,24),'    m(y)':(24,17,13,24),'  2/m(y)':( 1,17, 0,-1),
1185        '    2(z)':(14,16,14,23),'    m(z)':(23,16,14,23),'  2/m(z)':( 1,16, 0,-1),'   2(yz)':(10,23,10,22),
1186        '   m(yz)':(22,23,10,22),' 2/m(yz)':( 1,23, 0,-1),'  2(0+-)':(11,24,11,21),'  m(0+-)':(21,24,11,21),
1187        '2/m(0+-)':( 1,24, 0,-1),'   2(xz)':( 8,21, 8,20),'   m(xz)':(20,21, 8,20),' 2/m(xz)':( 1,21, 0,-1),
1188        '  2(+0-)':( 9,22, 9,19),'  m(+0-)':(19,22, 9,19),'2/m(+0-)':( 1,22, 0,-1),'   2(xy)':( 6,19, 6,18),
1189        '   m(xy)':(18,19, 6,18),' 2/m(xy)':( 1,19, 0,-1),'  2(+-0)':( 7,20, 7,17),'  m(+-0)':(17,20, 7,17),
1190        '2/m(+-0)':( 1,20, 0,-1),'  mm2(x)':(12,10, 0,-1),'  mm2(y)':(13,10, 0,-1),'  mm2(z)':(14,10, 0,-1),
1191        ' mm2(yz)':(10,13, 0,-1),'mm2(0+-)':(11,13, 0,-1),' mm2(xz)':( 8,12, 0,-1),'mm2(+0-)':( 9,12, 0,-1),
1192        ' mm2(xy)':( 6,11, 0,-1),'mm2(+-0)':( 7,11, 0,-1),'  222   ':( 1,10, 0,-1),'  222(x)':( 1,13, 0,-1),
1193        '  222(y)':( 1,12, 0,-1),'  222(z)':( 1,11, 0,-1),'  mmm   ':( 1,10, 0,-1),'  mmm(x)':( 1,13, 0,-1),
1194        '  mmm(y)':( 1,12, 0,-1),'  mmm(z)':( 1,11, 0,-1),'  4(100)':(12, 4,12, 0),' -4(100)':( 1, 4,12, 0),
1195        '4/m(100)':( 1, 4,12,-1),'422(100)':( 1, 4, 0,-1),'-42m 100':( 1, 4, 0,-1),'4mm(100)':(12, 4, 0,-1),
1196        '4/mmm100':( 1, 4, 0,-1),'  4(010)':(13, 3,13, 0),' -4(010)':( 1, 3,13, 0),'4/m (10)':( 1, 3,13,-1),
1197        '422(010)':( 1, 3, 0,-1),'-42m 010':( 1, 3, 0,-1),'4mm(010)':(13, 3, 0,-1),'4/mmm010':(1, 3, 0,-1,),
1198        '  4(001)':(14, 2,14, 0),' -4(001)':( 1, 2,14, 0),'4/m(001)':( 1, 2,14,-1),'422(001)':( 1, 2, 0,-1),
1199        '-42m 001':( 1, 2, 0,-1),'4mm(001)':(14, 2, 0,-1),'4/mmm001':( 1, 2, 0,-1),'  3(111)':( 2, 5, 2, 0),
1200        ' -3(111)':( 1, 5, 2, 0),' 32(111)':( 1, 5, 0, 2),' 3m(111)':( 2, 5, 0, 2),'-3m(111)':( 1, 5, 0,-1),
1201        '  3(+--)':( 5, 8, 5, 0),' -3(+--)':( 1, 8, 5, 0),' 32(+--)':( 1, 8, 0, 5),' 3m(+--)':( 5, 8, 0, 5),
1202        '-3m(+--)':( 1, 8, 0,-1),'  3(-+-)':( 4, 7, 4, 0),' -3(-+-)':( 1, 7, 4, 0),' 32(-+-)':( 1, 7, 0, 4),
1203        ' 3m(-+-)':( 4, 7, 0, 4),'-3m(-+-)':( 1, 7, 0,-1),'  3(--+)':( 3, 6, 3, 0),' -3(--+)':( 1, 6, 3, 0),
1204        ' 32(--+)':( 1, 6, 0, 3),' 3m(--+)':( 3, 6, 0, 3),'-3m(--+)':( 1, 6, 0,-1),'   23   ':( 1, 1, 0, 0),
1205        '   m3   ':( 1, 1, 0, 0),'   432  ':( 1, 1, 0, 0),'  -43m  ':( 1, 1, 0, 0),'   m3m  ':( 1, 1, 0, 0),
1206        ' mm2d100':(12,13, 0,-1),' mm2d010':(13,12, 0,-1),' mm2d001':(14,11, 0,-1),'-4m2 100':( 1, 4, 0,-1),
1207        '-4m2 010':( 1, 3, 0,-1),'-4m2 001':( 1, 2, 0,-1),'  6/mmm ':( 1, 9, 0,-1),'-6m2 100':( 1, 9, 0,-1),
1208        '-6m2 120':( 1, 9, 0,-1),'   6mm  ':(14, 9, 0,-1),'   622  ':( 1, 9, 0,-1),'   6/m  ':( 1, 9,14,-1),
1209        '   -6   ':( 1, 9,14, 0),'    6   ':(14, 9,14, 0),'-3m(100)':( 1, 9, 0,-1),'-3m(120)':( 1, 9, 0,-1),
1210        ' 3m(100)':(14, 9, 0,14),' 3m(120)':(14, 9, 0,14),' 32(100)':( 1, 9, 0,14),' 32(120)':( 1, 9, 0,14),
1211        '   -3   ':( 1, 9,14, 0),'    3   ':(14, 9,14, 0),'mmm(100)':( 1,14, 0,-1),'mmm(010)':( 1,15, 0,-1),
1212        'mmm(110)':( 1,11, 0,-1),' mm2z100':(14,14, 0,-1),' mm2z010':(14,15, 0,-1),' mm2z110':(14,11, 0,-1),
1213        'mm2(100)':(12,14, 0,-1),'mm2(010)':(13,15, 0,-1),'mm2(110)':( 6,11, 0,-1),'mm2(120)':(15,14, 0,-1),
1214        'mm2(210)':(16,15, 0,-1),'mm2(+-0)':( 7,11, 0,-1),'222(100)':( 1,14, 0,-1),'222(010)':( 1,15, 0,-1),
1215        '222(110)':( 1,11, 0,-1),'2/m(001)':( 1,16,14,-1),'2/m(100)':( 1,25,12,-1),'2/m(010)':( 1,28,13,-1),
1216        '2/m(110)':( 1,19, 6,-1),'2/m(120)':( 1,27,15,-1),'2/m(210)':( 1,26,16,-1),'2/m(+-0)':( 1,20,17,-1),
1217        ' m(001) ':(23,16,14,23),' m(100) ':(26,25,12,26),' m(010) ':(27,28,13,27),' m(110) ':(18,19, 6,18),
1218        ' m(120) ':(24,27,15,24),' m(210) ':(25,26,16,25),' m(+-0) ':(17,20, 7,17),' 2(001) ':(14,16,14,23),
1219        ' 2(100) ':(12,25,12,26),' 2(010) ':(13,28,13,27),' 2(110) ':( 6,19, 6,18),' 2(120) ':(15,27,15,24),
1220        ' 2(210) ':(16,26,16,25),' 2(+-0) ':( 7,20, 7,17),'   -1   ':( 1,29,28, 0)
1221        }
1222    return NXUPQsym[siteSym]
1223
1224def GetCSxinel(siteSym): 
1225    'Needs a doc string'
1226    CSxinel = [[],                         # 0th empty - indices are Fortran style
1227        [[0,0,0],[ 0.0, 0.0, 0.0]],      #1  0  0  0
1228        [[1,1,1],[ 1.0, 1.0, 1.0]],      #2  X  X  X
1229        [[1,1,1],[ 1.0, 1.0,-1.0]],      #3  X  X -X
1230        [[1,1,1],[ 1.0,-1.0, 1.0]],      #4  X -X  X
1231        [[1,1,1],[ 1.0,-1.0,-1.0]],      #5 -X  X  X
1232        [[1,1,0],[ 1.0, 1.0, 0.0]],      #6  X  X  0
1233        [[1,1,0],[ 1.0,-1.0, 0.0]],      #7  X -X  0
1234        [[1,0,1],[ 1.0, 0.0, 1.0]],      #8  X  0  X
1235        [[1,0,1],[ 1.0, 0.0,-1.0]],      #9  X  0 -X
1236        [[0,1,1],[ 0.0, 1.0, 1.0]],      #10  0  Y  Y
1237        [[0,1,1],[ 0.0, 1.0,-1.0]],      #11 0  Y -Y
1238        [[1,0,0],[ 1.0, 0.0, 0.0]],      #12  X  0  0
1239        [[0,1,0],[ 0.0, 1.0, 0.0]],      #13  0  Y  0
1240        [[0,0,1],[ 0.0, 0.0, 1.0]],      #14  0  0  Z
1241        [[1,1,0],[ 1.0, 2.0, 0.0]],      #15  X 2X  0
1242        [[1,1,0],[ 2.0, 1.0, 0.0]],      #16 2X  X  0
1243        [[1,1,2],[ 1.0, 1.0, 1.0]],      #17  X  X  Z
1244        [[1,1,2],[ 1.0,-1.0, 1.0]],      #18  X -X  Z
1245        [[1,2,1],[ 1.0, 1.0, 1.0]],      #19  X  Y  X
1246        [[1,2,1],[ 1.0, 1.0,-1.0]],      #20  X  Y -X
1247        [[1,2,2],[ 1.0, 1.0, 1.0]],      #21  X  Y  Y
1248        [[1,2,2],[ 1.0, 1.0,-1.0]],      #22  X  Y -Y
1249        [[1,2,0],[ 1.0, 1.0, 0.0]],      #23  X  Y  0
1250        [[1,0,2],[ 1.0, 0.0, 1.0]],      #24  X  0  Z
1251        [[0,1,2],[ 0.0, 1.0, 1.0]],      #25  0  Y  Z
1252        [[1,1,2],[ 1.0, 2.0, 1.0]],      #26  X 2X  Z
1253        [[1,1,2],[ 2.0, 1.0, 1.0]],      #27 2X  X  Z
1254        [[1,2,3],[ 1.0, 1.0, 1.0]],      #28  X  Y  Z
1255        ]
1256    indx = GetNXUPQsym(siteSym)
1257    return CSxinel[indx[0]]
1258   
1259def GetCSuinel(siteSym):
1260    "returns Uij terms, multipliers, GUI flags & Uiso2Uij multipliers"
1261    CSuinel = [[],                                             # 0th empty - indices are Fortran style
1262        [[1,1,1,0,0,0],[ 1.0, 1.0, 1.0, 0.0, 0.0, 0.0],[1,0,0,0,0,0],[1.0,1.0,1.0,0.0,0.0,0.0]],    #1  A  A  A  0  0  0
1263        [[1,1,2,0,0,0],[ 1.0, 1.0, 1.0, 0.0, 0.0, 0.0],[1,0,1,0,0,0],[1.0,1.0,1.0,0.0,0.0,0.0]],    #2  A  A  C  0  0  0
1264        [[1,2,1,0,0,0],[ 1.0, 1.0, 1.0, 0.0, 0.0, 0.0],[1,1,0,0,0,0],[1.0,1.0,1.0,0.0,0.0,0.0]],    #3  A  B  A  0  0  0
1265        [[1,2,2,0,0,0],[ 1.0, 1.0, 1.0, 0.0, 0.0, 0.0],[1,1,0,0,0,0],[1.0,1.0,1.0,0.0,0.0,0.0]],    #4  A  B  B  0  0  0
1266        [[1,1,1,2,2,2],[ 1.0, 1.0, 1.0, 1.0, 1.0, 1.0],[1,0,0,1,0,0],[1.0,1.0,1.0,0.0,0.0,0.0]],    #5  A  A  A  D  D  D
1267        [[1,1,1,2,2,2],[ 1.0, 1.0, 1.0, 1.0,-1.0,-1.0],[1,0,0,1,0,0],[1.0,1.0,1.0,0.0,0.0,0.0]],    #6  A  A  A  D -D -D
1268        [[1,1,1,2,2,2],[ 1.0, 1.0, 1.0, 1.0,-1.0, 1.0],[1,0,0,1,0,0],[1.0,1.0,1.0,0.0,0.0,0.0]],    #7  A  A  A  D -D  D
1269        [[1,1,1,2,2,2],[ 1.0, 1.0, 1.0, 1.0, 1.0,-1.0],[1,0,0,1,0,0],[1.0,1.0,1.0,0.0,0.0,0.0]],    #8  A  A  A  D  D -D
1270        [[1,1,2,1,0,0],[ 1.0, 1.0, 1.0, 0.5, 0.0, 0.0],[1,0,1,0,0,0],[1.0,1.0,1.0,0.5,0.0,0.0]],    #9  A  A  C A/2 0  0
1271        [[1,2,3,0,0,0],[ 1.0, 1.0, 1.0, 0.0, 0.0, 0.0],[1,1,1,0,0,0],[1.0,1.0,1.0,0.0,0.0,0.0]],    #10  A  B  C  0  0  0
1272        [[1,1,2,3,0,0],[ 1.0, 1.0, 1.0, 1.0, 0.0, 0.0],[1,0,1,1,0,0],[1.0,1.0,1.0,0.0,0.0,0.0]],    #11  A  A  C  D  0  0
1273        [[1,2,1,0,3,0],[ 1.0, 1.0, 1.0, 0.0, 1.0, 0.0],[1,1,0,0,1,0],[1.0,1.0,1.0,0.0,0.0,0.0]],    #12  A  B  A  0  E  0
1274        [[1,2,2,0,0,3],[ 1.0, 1.0, 1.0, 0.0, 0.0, 1.0],[1,1,0,0,0,1],[1.0,1.0,1.0,0.0,0.0,0.0]],    #13  A  B  B  0  0  F
1275        [[1,2,3,2,0,0],[ 1.0, 1.0, 1.0, 0.5, 0.0, 0.0],[1,1,1,0,0,0],[1.0,1.0,1.0,0.0,0.5,0.0]],    #14  A  B  C B/2 0  0
1276        [[1,2,3,1,0,0],[ 1.0, 1.0, 1.0, 0.5, 0.0, 0.0],[1,1,1,0,0,0],[1.0,1.0,1.0,0.0,0.5,0.0]],    #15  A  B  C A/2 0  0
1277        [[1,2,3,4,0,0],[ 1.0, 1.0, 1.0, 1.0, 0.0, 0.0],[1,1,1,1,0,0],[1.0,1.0,1.0,0.0,0.0,0.0]],    #16  A  B  C  D  0  0
1278        [[1,2,3,0,4,0],[ 1.0, 1.0, 1.0, 0.0, 1.0, 0.0],[1,1,1,0,1,0],[1.0,1.0,1.0,0.0,0.0,0.0]],    #17  A  B  C  0  E  0
1279        [[1,2,3,0,0,4],[ 1.0, 1.0, 1.0, 0.0, 0.0, 1.0],[1,1,1,0,0,1],[1.0,1.0,1.0,0.0,0.0,0.0]],    #18  A  B  C  0  0  F
1280        [[1,1,2,3,4,4],[ 1.0, 1.0, 1.0, 1.0, 1.0,-1.0],[1,0,1,1,1,0],[1.0,1.0,1.0,0.0,0.0,0.0]],    #19  A  A  C  D  E -E
1281        [[1,1,2,3,4,4],[ 1.0, 1.0, 1.0, 1.0, 1.0, 1.0],[1,0,1,1,1,0],[1.0,1.0,1.0,0.0,0.0,0.0]],    #20  A  A  C  D  E  E
1282        [[1,2,1,3,4,3],[ 1.0, 1.0, 1.0, 1.0, 1.0,-1.0],[1,1,0,1,1,0],[1.0,1.0,1.0,0.0,0.0,0.0]],    #21  A  B  A  D  E -D
1283        [[1,2,1,3,4,3],[ 1.0, 1.0, 1.0, 1.0, 1.0, 1.0],[1,1,0,1,1,0],[1.0,1.0,1.0,0.0,0.0,0.0]],    #22  A  B  A  D  E  D
1284        [[1,2,2,3,3,4],[ 1.0, 1.0, 1.0, 1.0,-1.0, 1.0],[1,1,0,1,0,1],[1.0,1.0,1.0,0.0,0.0,0.0]],    #23  A  B  B  D -D  F
1285        [[1,2,2,3,3,4],[ 1.0, 1.0, 1.0, 1.0, 1.0, 1.0],[1,1,0,1,0,1],[1.0,1.0,1.0,0.0,0.0,0.0]],    #24  A  B  B  D  D  F
1286        [[1,2,3,2,4,4],[ 1.0, 1.0, 1.0, 0.5, 0.5, 1.0],[1,1,1,0,0,1],[1.0,1.0,1.0,0.5,0.0,0.0]],    #25  A  B  C B/2 F/2 F
1287        [[1,2,3,1,0,4],[ 1.0, 1.0, 1.0, 0.5, 0.0, 1.0],[1,1,1,0,0,1],[1.0,1.0,1.0,0.5,0.0,0.0]],    #26  A  B  C A/2  0  F
1288        [[1,2,3,2,4,0],[ 1.0, 1.0, 1.0, 0.5, 1.0, 0.0],[1,1,1,0,1,0],[1.0,1.0,1.0,0.5,0.0,0.0]],    #27  A  B  C B/2  E  0
1289        [[1,2,3,1,4,4],[ 1.0, 1.0, 1.0, 0.5, 1.0, 0.5],[1,1,1,0,1,0],[1.0,1.0,1.0,0.5,0.0,0.0]],    #28  A  B  C A/2  E E/2
1290        [[1,2,3,4,5,6],[ 1.0, 1.0, 1.0, 1.0, 1.0, 1.0],[1,1,1,1,1,1],[1.0,1.0,1.0,0.0,0.0,0.0]],    #29  A  B  C  D  E   F
1291        ]
1292    indx = GetNXUPQsym(siteSym)
1293    return CSuinel[indx[1]]
1294   
1295def MustrainNames(SGData):
1296    'Needs a doc string'
1297    laue = SGData['SGLaue']
1298    uniq = SGData['SGUniq']
1299    if laue in ['m3','m3m']:
1300        return ['S400','S220']
1301    elif laue in ['6/m','6/mmm','3m1']:
1302        return ['S400','S004','S202']
1303    elif laue in ['31m','3']:
1304        return ['S400','S004','S202','S211']
1305    elif laue in ['3R','3mR']:
1306        return ['S400','S220','S310','S211']
1307    elif laue in ['4/m','4/mmm']:
1308        return ['S400','S004','S220','S022']
1309    elif laue in ['mmm']:
1310        return ['S400','S040','S004','S220','S202','S022']
1311    elif laue in ['2/m']:
1312        SHKL = ['S400','S040','S004','S220','S202','S022']
1313        if uniq == 'a':
1314            SHKL += ['S013','S031','S211']
1315        elif uniq == 'b':
1316            SHKL += ['S301','S103','S121']
1317        elif uniq == 'c':
1318            SHKL += ['S130','S310','S112']
1319        return SHKL
1320    else:
1321        SHKL = ['S400','S040','S004','S220','S202','S022']
1322        SHKL += ['S310','S103','S031','S130','S301','S013']
1323        SHKL += ['S211','S121','S112']
1324        return SHKL
1325       
1326def HStrainVals(HSvals,SGData):
1327    laue = SGData['SGLaue']
1328    uniq = SGData['SGUniq']
1329    DIJ = np.zeros(6)
1330    if laue in ['m3','m3m']:
1331        DIJ[:3] = [HSvals[0],HSvals[0],HSvals[0]]
1332    elif laue in ['6/m','6/mmm','3m1','31m','3']:
1333        DIJ[:4] = [HSvals[0],HSvals[0],HSvals[1],HSvals[0]]
1334    elif laue in ['3R','3mR']:
1335        DIJ = [HSvals[0],HSvals[0],HSvals[0],HSvals[1],HSvals[1],HSvals[1]]
1336    elif laue in ['4/m','4/mmm']:
1337        DIJ[:3] = [HSvals[0],HSvals[0],HSvals[1]]
1338    elif laue in ['mmm']:
1339        DIJ[:3] = [HSvals[0],HSvals[1],HSvals[2]]
1340    elif laue in ['2/m']:
1341        DIJ[:3] = [HSvals[0],HSvals[1],HSvals[2]]
1342        if uniq == 'a':
1343            DIJ[5] = HSvals[3]
1344        elif uniq == 'b':
1345            DIJ[4] = HSvals[3]
1346        elif uniq == 'c':
1347            DIJ[3] = HSvals[3]
1348        return Dij
1349    else:
1350        DIJ = [HSvals[0],HSvals[1],HSvals[2],HSvals[3],HSvals[4],HSvals[5]]
1351    return DIJ
1352
1353def HStrainNames(SGData):
1354    'Needs a doc string'
1355    laue = SGData['SGLaue']
1356    uniq = SGData['SGUniq']
1357    if laue in ['m3','m3m']:
1358        return ['D11','eA']         #add cubic strain term
1359    elif laue in ['6/m','6/mmm','3m1','31m','3']:
1360        return ['D11','D33']
1361    elif laue in ['3R','3mR']:
1362        return ['D11','D12']
1363    elif laue in ['4/m','4/mmm']:
1364        return ['D11','D33']
1365    elif laue in ['mmm']:
1366        return ['D11','D22','D33']
1367    elif laue in ['2/m']:
1368        Dij = ['D11','D22','D33']
1369        if uniq == 'a':
1370            Dij += ['D23']
1371        elif uniq == 'b':
1372            Dij += ['D13']
1373        elif uniq == 'c':
1374            Dij += ['D12']
1375        return Dij
1376    else:
1377        Dij = ['D11','D22','D33','D12','D13','D23']
1378        return Dij
1379   
1380def MustrainCoeff(HKL,SGData):
1381    'Needs a doc string'
1382    #NB: order of terms is the same as returned by MustrainNames
1383    laue = SGData['SGLaue']
1384    uniq = SGData['SGUniq']
1385    h,k,l = HKL
1386    Strm = []
1387    if laue in ['m3','m3m']:
1388        Strm.append(h**4+k**4+l**4)
1389        Strm.append(3.0*((h*k)**2+(h*l)**2+(k*l)**2))
1390    elif laue in ['6/m','6/mmm','3m1']:
1391        Strm.append(h**4+k**4+2.0*k*h**3+2.0*h*k**3+3.0*(h*k)**2)
1392        Strm.append(l**4)
1393        Strm.append(3.0*((h*l)**2+(k*l)**2+h*k*l**2))
1394    elif laue in ['31m','3']:
1395        Strm.append(h**4+k**4+2.0*k*h**3+2.0*h*k**3+3.0*(h*k)**2)
1396        Strm.append(l**4)
1397        Strm.append(3.0*((h*l)**2+(k*l)**2+h*k*l**2))
1398        Strm.append(4.0*h*k*l*(h+k))
1399    elif laue in ['3R','3mR']:
1400        Strm.append(h**4+k**4+l**4)
1401        Strm.append(3.0*((h*k)**2+(h*l)**2+(k*l)**2))
1402        Strm.append(2.0*(h*l**3+l*k**3+k*h**3)+2.0*(l*h**3+k*l**3+l*k**3))
1403        Strm.append(4.0*(k*l*h**2+h*l*k**2+h*k*l**2))
1404    elif laue in ['4/m','4/mmm']:
1405        Strm.append(h**4+k**4)
1406        Strm.append(l**4)
1407        Strm.append(3.0*(h*k)**2)
1408        Strm.append(3.0*((h*l)**2+(k*l)**2))
1409    elif laue in ['mmm']:
1410        Strm.append(h**4)
1411        Strm.append(k**4)
1412        Strm.append(l**4)
1413        Strm.append(3.0*(h*k)**2)
1414        Strm.append(3.0*(h*l)**2)
1415        Strm.append(3.0*(k*l)**2)
1416    elif laue in ['2/m']:
1417        Strm.append(h**4)
1418        Strm.append(k**4)
1419        Strm.append(l**4)
1420        Strm.append(3.0*(h*k)**2)
1421        Strm.append(3.0*(h*l)**2)
1422        Strm.append(3.0*(k*l)**2)
1423        if uniq == 'a':
1424            Strm.append(2.0*k*l**3)
1425            Strm.append(2.0*l*k**3)
1426            Strm.append(4.0*k*l*h**2)
1427        elif uniq == 'b':
1428            Strm.append(2.0*l*h**3)
1429            Strm.append(2.0*h*l**3)
1430            Strm.append(4.0*h*l*k**2)
1431        elif uniq == 'c':
1432            Strm.append(2.0*h*k**3)
1433            Strm.append(2.0*k*h**3)
1434            Strm.append(4.0*h*k*l**2)
1435    else:
1436        Strm.append(h**4)
1437        Strm.append(k**4)
1438        Strm.append(l**4)
1439        Strm.append(3.0*(h*k)**2)
1440        Strm.append(3.0*(h*l)**2)
1441        Strm.append(3.0*(k*l)**2)
1442        Strm.append(2.0*k*h**3)
1443        Strm.append(2.0*h*l**3)
1444        Strm.append(2.0*l*k**3)
1445        Strm.append(2.0*h*k**3)
1446        Strm.append(2.0*l*h**3)
1447        Strm.append(2.0*k*l**3)
1448        Strm.append(4.0*k*l*h**2)
1449        Strm.append(4.0*h*l*k**2)
1450        Strm.append(4.0*k*h*l**2)
1451    return Strm
1452   
1453def Muiso2Shkl(muiso,SGData,cell):
1454    "this is to convert isotropic mustrain to generalized Shkls"
1455    import GSASIIlattice as G2lat
1456    A = G2lat.cell2AB(cell)[0]
1457   
1458    def minMus(Shkl,muiso,H,SGData,A):
1459        U = np.inner(A.T,H)
1460        S = np.array(MustrainCoeff(U,SGData))
1461        Sum = np.sqrt(np.sum(np.multiply(S,Shkl[:,np.newaxis]),axis=0))
1462        rad = np.sqrt(np.sum((Sum[:,np.newaxis]*H)**2,axis=1))
1463        return (muiso-rad)**2
1464       
1465    laue = SGData['SGLaue']
1466    PHI = np.linspace(0.,360.,60,True)
1467    PSI = np.linspace(0.,180.,60,True)
1468    X = np.outer(npsind(PHI),npsind(PSI))
1469    Y = np.outer(npcosd(PHI),npsind(PSI))
1470    Z = np.outer(np.ones(np.size(PHI)),npcosd(PSI))
1471    HKL = np.dstack((X,Y,Z))
1472    if laue in ['m3','m3m']:
1473        S0 = [1000.,1000.]
1474    elif laue in ['6/m','6/mmm','3m1']:
1475        S0 = [1000.,1000.,1000.]
1476    elif laue in ['31m','3']:
1477        S0 = [1000.,1000.,1000.,1000.]
1478    elif laue in ['3R','3mR']:
1479        S0 = [1000.,1000.,1000.,1000.]
1480    elif laue in ['4/m','4/mmm']:
1481        S0 = [1000.,1000.,1000.,1000.]
1482    elif laue in ['mmm']:
1483        S0 = [1000.,1000.,1000.,1000.,1000.,1000.]
1484    elif laue in ['2/m']:
1485        S0 = [1000.,1000.,1000.,0.,0.,0.,0.,0.,0.]
1486    else:
1487        S0 = [1000.,1000.,1000.,1000.,1000., 1000.,1000.,1000.,1000.,1000., 
1488            1000.,1000.,0.,0.,0.]
1489    S0 = np.array(S0)
1490    HKL = np.reshape(HKL,(-1,3))
1491    result = so.leastsq(minMus,S0,(np.ones(HKL.shape[0])*muiso,HKL,SGData,A))
1492    return result[0]
1493       
1494def SytSym(XYZ,SGData):
1495    '''
1496    Generates the number of equivalent positions and a site symmetry code for a specified coordinate and space group
1497
1498    :param XYZ: an array, tuple or list containing 3 elements: x, y & z
1499    :param SGData: from SpcGroup
1500    :Returns: a two element tuple:
1501
1502     * The 1st element is a code for the site symmetry (see GetKNsym)
1503     * The 2nd element is the site multiplicity
1504
1505    '''
1506    def PackRot(SGOps):
1507        IRT = []
1508        for ops in SGOps:
1509            M = ops[0]
1510            irt = 0
1511            for j in range(2,-1,-1):
1512                for k in range(2,-1,-1):
1513                    irt *= 3
1514                    irt += M[k][j]
1515            IRT.append(int(irt))
1516        return IRT
1517       
1518    SymName = ''
1519    Mult = 1
1520    Isym = 0
1521    if SGData['SGLaue'] in ['3','3m1','31m','6/m','6/mmm']:
1522        Isym = 1073741824
1523    Jdup = 0
1524    Xeqv = GenAtom(XYZ,SGData,True)
1525    IRT = PackRot(SGData['SGOps'])
1526    L = -1
1527    for ic,cen in enumerate(SGData['SGCen']):
1528        for invers in range(int(SGData['SGInv']+1)):
1529            for io,ops in enumerate(SGData['SGOps']):
1530                irtx = (1-2*invers)*IRT[io]
1531                L += 1
1532                if not Xeqv[L][1]:
1533                    Jdup += 1
1534                    jx = GetOprPtrName(str(irtx))
1535                    if jx[2] < 39:
1536                        Isym += 2**(jx[2]-1)
1537    if Isym == 1073741824: Isym = 0
1538    Mult = len(SGData['SGOps'])*len(SGData['SGCen'])*(int(SGData['SGInv'])+1)/Jdup
1539         
1540    return GetKNsym(str(Isym)),Mult
1541   
1542def ElemPosition(SGData):
1543    ''' Under development.
1544    Object here is to return a list of symmetry element types and locations suitable
1545    for say drawing them.
1546    So far I have the element type... getting all possible locations without lookup may be impossible!
1547    '''
1548    SymElements = []
1549    Inv = SGData['SGInv']
1550    Cen = SGData['SGCen']
1551    eleSym = {-3:['','-1'],-2:['',-6],-1:['2','-4'],0:['3','-3'],1:['4','m'],2:['6',''],3:['1','']}
1552    # get operators & expand if centrosymmetric
1553    Ops = SGData['SGOps']
1554    opM = np.array([op[0].T for op in Ops])
1555    opT = np.array([op[1] for op in Ops])
1556    if Inv:
1557        opM = np.concatenate((opM,-opM))
1558        opT = np.concatenate((opT,-opT))
1559    opMT = zip(opM,opT)
1560    for M,T in opMT[1:]:        #skip I
1561        Dt = int(nl.det(M))
1562        Tr = int(np.trace(M))
1563        Dt = -(Dt-1)/2
1564        Es = eleSym[Tr][Dt]
1565        if Dt:              #rotation-inversion
1566            I = np.eye(3)
1567            if Tr == 1:     #mirrors/glides
1568                if np.any(T):       #glide
1569                    M2 = np.inner(M,M)
1570                    MT = np.inner(M,T)+T
1571                    print 'glide',Es,MT
1572                    print M2
1573                else:               #mirror
1574                    print 'mirror',Es,T
1575                    print I-M
1576                X = [-1,-1,-1]
1577            elif Tr == -3:  # pure inversion
1578                X = np.inner(nl.inv(I-M),T)
1579                print 'inversion',Es,X
1580            else:           #other rotation-inversion
1581                M2 = np.inner(M,M)
1582                MT = np.inner(M,T)+T
1583                print 'rot-inv',Es,MT
1584                print M2
1585                X = [-1,-1,-1]
1586        else:               #rotations
1587            print 'rotation',Es
1588            X = [-1,-1,-1]
1589        #SymElements.append([Es,X])
1590       
1591    return #SymElements
1592   
1593def ApplyStringOps(A,SGData,X,Uij=[]):
1594    'Needs a doc string'
1595    SGOps = SGData['SGOps']
1596    SGCen = SGData['SGCen']
1597    Ax = A.split('+')
1598    Ax[0] = int(Ax[0])
1599    iC = 0
1600    if Ax[0] < 0:
1601        iC = 1
1602    Ax[0] = abs(Ax[0])
1603    nA = Ax[0]%100-1
1604    cA = Ax[0]/100
1605    Cen = SGCen[cA]
1606    M,T = SGOps[nA]
1607    if len(Ax)>1:
1608        cellA = Ax[1].split(',')
1609        cellA = np.array([int(a) for a in cellA])
1610    else:
1611        cellA = np.zeros(3)
1612    newX = (1-2*iC)*(Cen+np.inner(M,X)+T)+cellA
1613    if len(Uij):
1614        U = Uij2U(Uij)
1615        U = np.inner(M,np.inner(U,M).T)
1616        newUij = U2Uij(U)
1617        return [newX,newUij]
1618    else:
1619        return newX
1620       
1621def StringOpsProd(A,B,SGData):
1622    """
1623    Find A*B where A & B are in strings '-' + '100*c+n' + '+ijk'
1624    where '-' indicates inversion, c(>0) is the cell centering operator,
1625    n is operator number from SgOps and ijk are unit cell translations (each may be <0).
1626    Should return resultant string - C. SGData - dictionary using entries:
1627
1628       *  'SGCen': cell centering vectors [0,0,0] at least
1629       *  'SGOps': symmetry operations as [M,T] so that M*x+T = x'
1630
1631    """
1632    SGOps = SGData['SGOps']
1633    SGCen = SGData['SGCen']
1634    #1st split out the cell translation part & work on the operator parts
1635    Ax = A.split('+'); Bx = B.split('+')
1636    Ax[0] = int(Ax[0]); Bx[0] = int(Bx[0])
1637    iC = 0
1638    if Ax[0]*Bx[0] < 0:
1639        iC = 1
1640    Ax[0] = abs(Ax[0]); Bx[0] = abs(Bx[0])
1641    nA = Ax[0]%100-1;  nB = Bx[0]%100-1
1642    cA = Ax[0]/100;  cB = Bx[0]/100
1643    Cen = (SGCen[cA]+SGCen[cB])%1.0
1644    cC = np.nonzero([np.allclose(C,Cen) for C in SGCen])[0][0]
1645    Ma,Ta = SGOps[nA]; Mb,Tb = SGOps[nB]
1646    Mc = np.inner(Ma,Mb.T)
1647#    print Ma,Mb,Mc
1648    Tc = (np.add(np.inner(Mb,Ta)+1.,Tb))%1.0
1649#    print Ta,Tb,Tc
1650#    print [np.allclose(M,Mc)&np.allclose(T,Tc) for M,T in SGOps]
1651    nC = np.nonzero([np.allclose(M,Mc)&np.allclose(T,Tc) for M,T in SGOps])[0][0]
1652    #now the cell translation part
1653    if len(Ax)>1:
1654        cellA = Ax[1].split(',')
1655        cellA = [int(a) for a in cellA]
1656    else:
1657        cellA = [0,0,0]
1658    if len(Bx)>1:
1659        cellB = Bx[1].split(',')
1660        cellB = [int(b) for b in cellB]
1661    else:
1662        cellB = [0,0,0]
1663    cellC = np.add(cellA,cellB)
1664    C = str(((nC+1)+(100*cC))*(1-2*iC))+'+'+ \
1665        str(int(cellC[0]))+','+str(int(cellC[1]))+','+str(int(cellC[2]))
1666    return C
1667           
1668def U2Uij(U):
1669    #returns the UIJ vector U11,U22,U33,U12,U13,U23 from tensor U
1670    return [U[0][0],U[1][1],U[2][2],2.*U[0][1],2.*U[0][2],2.*U[1][2]]
1671   
1672def Uij2U(Uij):
1673    #returns the thermal motion tensor U from Uij as numpy array
1674    return np.array([[Uij[0],Uij[3]/2.,Uij[4]/2.],[Uij[3]/2.,Uij[1],Uij[5]/2.],[Uij[4]/2.,Uij[5]/2.,Uij[2]]])
1675
1676def StandardizeSpcName(spcgroup):
1677    '''Accept a spacegroup name where spaces may have not been used
1678    in the names according to the GSAS convention (spaces between symmetry
1679    for each axis) and return the space group name as used in GSAS
1680    '''
1681    rspc = spcgroup.replace(' ','').upper()
1682    # deal with rhombohedral and hexagonal setting designations
1683    rhomb = ''
1684    if rspc[-1:] == 'R':
1685        rspc = rspc[:-1]
1686        rhomb = ' R'
1687    elif rspc[-1:] == 'H': # hexagonal is assumed and thus can be ignored
1688        rspc = rspc[:-1]
1689    # look for a match in the spacegroup lists
1690    for i in spglist.values():
1691        for spc in i:
1692            if rspc == spc.replace(' ','').upper():
1693                return spc + rhomb
1694    # how about the post-2002 orthorhombic names?
1695    for i,spc in sgequiv_2002_orthorhombic:
1696        if rspc == i.replace(' ','').upper():
1697            return spc
1698    # not found
1699    return ''
1700
1701   
1702spglist = {}
1703'''A dictionary of space groups as ordered and named in the pre-2002 International
1704Tables Volume A, except that spaces are used following the GSAS convention to
1705separate the different crystallographic directions.
1706Note that the symmetry codes here will recognize many non-standard space group
1707symbols with different settings. They are ordered by Laue group
1708'''
1709spglist = {
1710    'P1' : ('P 1','P -1',), # 1-2
1711    'P2/m': ('P 2','P 21','P m','P a','P c','P n',
1712        'P 2/m','P 21/m','P 2/c','P 2/a','P 2/n','P 21/c','P 21/a','P 21/n',), #3-15
1713    'C2/m':('C 2','C m','C c','C n',
1714        'C 2/m','C 2/c','C 2/n',),
1715    'Pmmm':('P 2 2 2',
1716        'P 2 2 21','P 2 21 2','P 21 2 2',
1717        'P 21 21 2','P 21 2 21','P 2 21 21',
1718        'P 21 21 21',
1719        'P m m 2','P m 2 m','P 2 m m',
1720        'P m c 21','P c m 21','P 21 m a','P 21 a m','P b 21 m','P m 21 b',
1721        'P c c 2','P 2 a a','P b 2 b',
1722        'P m a 2','P b m 2','P 2 m b','P 2 c m','P c 2 m','P m 2 a',
1723        'P c a 21','P b c 21','P 21 a b','P 21 c a','P c 21 b','P b 21 a',
1724        'P n c 2','P c n 2','P 2 n a','P 2 a n','P b 2 n','P n 2 b',
1725        'P m n 21','P n m 21','P 21 m n','P 21 n m','P n 21 m','P m 21 n',
1726        'P b a 2','P 2 c b','P c 2 a',
1727        'P n a 21','P b n 21','P 21 n b','P 21 c n','P c 21 n','P n 21 a',
1728        'P n n 2','P 2 n n','P n 2 n',
1729        'P m m m','P n n n',
1730        'P c c m','P m a a','P b m b',
1731        'P b a n','P n c b','P c n a',
1732        'P m m a','P m m b','P b m m','P c m m','P m c m','P m a m',
1733        'P n n a','P n n b','P b n n','P c n n','P n c n','P n a n',
1734        'P m n a','P n m b','P b m n','P c n m','P n c m','P m a n',
1735        'P c c a','P c c b','P b a a','P c a a','P b c b','P b a b',
1736        'P b a m','P m c b','P c m a',
1737        'P c c n','P n a a','P b n b',
1738        'P b c m','P c a m','P m c a','P m a b','P b m a','P c m b',
1739        'P n n m','P m n n','P n m n',
1740        'P m m n','P n m m','P m n m',
1741        'P b c n','P c a n','P n c a','P n a b','P b n a','P c n b',
1742        'P b c a','P c a b',
1743        'P n m a','P m n b','P b n m','P c m n','P m c n','P n a m',
1744        ),
1745    'Cmmm':('C 2 2 21','C 2 2 2','C m m 2','C m c 21','C c c 2','C m 2 m','C 2 m m',
1746        'C m 2 a','C 2 m b','C 2 c m','C c 2 m','C 2 c m',
1747        'C m c a','C m m m','C c c m','C m m a','C c c a','C m c m',),
1748    'Immm':('I 2 2 2','I 21 21 21','I m m m',
1749        'I m m 2','I m 2 m','I 2 m m',
1750        'I b a 2','I 2 c b','I c 2 a',
1751        'I m a 2','I b m 2','I 2 m b','I 2 c m','I c 2 m','I m 2 a',
1752        'I b a m','I m c b','I c m a',
1753        'I b c a','I c a b',
1754        'I m m a','I m m b','I b m m ','I c m m','I m c m','I m a m',),
1755    'Fmmm':('F 2 2 2','F m m m', 'F d d d',
1756        'F m m 2','F m 2 m','F 2 m m',
1757        'F d d 2','F d 2 d','F 2 d d',),
1758    'P4/mmm':('P 4','P 41','P 42','P 43','P -4','P 4/m','P 42/m','P 4/n','P 42/n',
1759        'P 4 2 2','P 4 21 2','P 41 2 2','P 41 21 2','P 42 2 2',
1760        'P 42 21 2','P 43 2 2','P 43 21 2','P 4 m m','P 4 b m','P 42 c m',
1761        'P 42 n m','P 4 c c','P 4 n c','P 42 m c','P 42 b c','P -4 2 m',
1762        'P -4 2 c','P -4 21 m','P -4 21 c','P -4 m 2','P -4 c 2','P -4 b 2',
1763        'P -4 n 2','P 4/m m m','P 4/m c c','P 4/n b m','P 4/n n c','P 4/m b m',
1764        'P 4/m n c','P 4/n m m','P 4/n c c','P 42/m m c','P 42/m c m',
1765        'P 42/n b c','P 42/n n m','P 42/m b c','P 42/m n m','P 42/n m c',
1766        'P 42/n c m',),
1767    'I4/mmm':('I 4','I 41','I -4','I 4/m','I 41/a','I 4 2 2','I 41 2 2','I 4 m m',
1768        'I 4 c m','I 41 m d','I 41 c d',
1769        'I -4 m 2','I -4 c 2','I -4 2 m','I -4 2 d','I 4/m m m','I 4/m c m',
1770        'I 41/a m d','I 41/a c d'),
1771    'R3-H':('R 3','R -3','R 3 2','R 3 m','R 3 c','R -3 m','R -3 c',),
1772    'P6/mmm': ('P 3','P 31','P 32','P -3','P 3 1 2','P 3 2 1','P 31 1 2',
1773        'P 31 2 1','P 32 1 2','P 32 2 1', 'P 3 m 1','P 3 1 m','P 3 c 1',
1774        'P 3 1 c','P -3 1 m','P -3 1 c','P -3 m 1','P -3 c 1','P 6','P 61',
1775        'P 65','P 62','P 64','P 63','P -6','P 6/m','P 63/m','P 6 2 2',
1776        'P 61 2 2','P 65 2 2','P 62 2 2','P 64 2 2','P 63 2 2','P 6 m m',
1777        'P 6 c c','P 63 c m','P 63 m c','P -6 m 2','P -6 c 2','P -6 2 m',
1778        'P -6 2 c','P 6/m m m','P 6/m c c','P 63/m c m','P 63/m m c',),
1779    'Pm3m': ('P 2 3','P 21 3','P m 3','P n 3','P a 3','P 4 3 2','P 42 3 2',
1780        'P 43 3 2','P 41 3 2','P -4 3 m','P -4 3 n','P m 3 m','P n 3 n',
1781        'P m 3 n','P n 3 m',),
1782    'Im3m':('I 2 3','I 21 3','I m -3','I a -3', 'I 4 3 2','I 41 3 2',
1783        'I -4 3 m', 'I -4 3 d','I m -3 m','I m 3 m','I a -3 d',),
1784    'Fm3m':('F 2 3','F m -3','F d -3','F 4 3 2','F 41 3 2','F -4 3 m',
1785        'F -4 3 c','F m -3 m','F m 3 m','F m -3 c','F d -3 m','F d -3 c',),
1786}
1787
1788ssdict = {}
1789'''A dictionary of superspace group symbols allowed for each entry in spglist
1790(except cubics). Monoclinics are all b-unique setting.
1791'''
1792ssdict = {
1793    'P 1':['(abg)',],'P -1':['(abg)',],
1794    #monoclinic - done
1795    'P 2':['(a0g)','(a1/2g)','(0b0)','(0b0)s','(1/2b0)','(0b1/2)','(1/2b0)s','(0b1/2)s',],
1796    'P 21':['(a0g)','(0b0)','(0b0)s','(1/2b0)','(0b1/2)','(1/2b0)s','(0b1/2)s',],
1797    'P m':['(a0g)','(a0g)s','(a1/2g)','(a1/2g)s','(0b0)','(1/2b0)','(0b1/2)',],
1798    'P a':['(a0g)','(a1/2g)','(a0g)s','(a1/2g)s','(0b0)','(0b1/2)',],
1799    'P c':['(a0g)','(a1/2g)','(a0g)s','(a1/2g)s','(0b0)','(1/2b0)',],
1800    'P n':['(a0g)','(a1/2g)','(a0g)s','(a1/2g)s','(0b0)','(1/2b1/2)',],
1801    'P 2/m':['(a0g)','(a1/2g)','(a0g)0s','(a1/2g)0s',
1802        '(0b0)','(0b0)s0','(1/2b0)','(0b1/2)','(1/2b0)s0','(0b1/2)s0',],
1803    'P 21/m':['(a0g)','(a0g)0s','(0b0)','(0b0)s0',
1804        '(1/2b0)','(0b1/2)','(1/2b0)s0','(0b1/2)s0'],
1805    'P 2/c':['(a0g)','(a1/2g)','(a0g)0s','(a1/2g)0s',
1806        '(0b0)','(0b0)s0','(1/2b0)','(1/2b0)s0',],
1807    'P 2/a':['(a0g)','(a1/2g)','(a0g)0s','(a1/2g)0s',
1808        '(0b0)','(0b0)s0','(0b1/2)','(0b1/2)s0',],
1809    'P 2/n':['(a0g)','(a1/2g)','(a0g)0s','(a1/2g)0s',
1810        '(0b0)','(0b0)s0','(1/2b1/2)','(1/2b1/2)s0',],
1811    'P 21/c':['(a0g)','(a0g)0s','(0b0)','(0b0)s0','(1/2b0)','(1/2b0)s0',],
1812    'P 21/a':['(a0g)','(a0g)0s','(0b0)','(0b0)s0','(0b1/2)','(0b1/2)s0',],
1813    'P 21/n':['(a0g)','(a0g)0s','(0b0)','(0b0)s0','(1/2b1/2)','(1/2b1/2)s0',],
1814    'C 2':['(a0g)','(0b0)','(0b0)s','(0b1/2)','(0b1/2)s',],
1815    'C m':['(a0g)','(a0g)s','(0b0)','(0b1/2)',],
1816    'C c':['(a0g)','(a0g)s','(0b0)',],
1817    'C n':['(a0g)','(a0g)s','(0b0)',],
1818    'C 2/m':['(a0g)','(a0g)0s','(0b0)','(0b0)s0','(0b1/2)','(0b1/2)s0',],
1819    'C 2/c':['(a0g)','(a0g)0s','(0b0)','(0b0)s0',],
1820    'C 2/n':['(a0g)','(a0g)0s','(0b0)','(0b0)s0',],
1821    #orthorhombic   
1822    'P 2 2 2':['(a00)','(0b0)','(00g)','(a00)s00','(0b0)0s0','(00g)00s',
1823        '(a1/20)','(a01/2)','(0b1/2)','(1/2b0)','(01/2g)','(1/20g)',
1824        '(a1/21/2)','(1/2b1/2)','(1/21/2g)',],
1825       
1826    'P 2 2 21':['(a00)','(0b0)','(00g)','(a00)s00','(0b0)0s0',
1827        '(a1/20)','(1/2b0)','(01/2g)','(1/20g)','(1/21/2g)',],
1828    'P 2 21 2':['(a00)','(0b0)','(00g)','(a00)s00','(00g)00s',
1829        '(a01/2)','(1/20g)','(0b1/2)','(1/2b0)','(1/2b1/2)',],
1830    'P 21 2 2':['(a00)','(0b0)','(00g)','(0b0)0s0','(00g)00s',
1831        '(01/2g)','(0b1/2)','(a01/2)','(a1/20)','(a1/21/2)',],
1832       
1833    'P 21 21 2':['(a00)','(0b0)','(00g)','(00g)00s','(a01/2)','(0b1/2)',],
1834    'P 21 2 21':['(a00)','(0b0)','(00g)','(0b0)0s0','(a1/20)','(01/2g)',],
1835    'P 2 21 21':['(a00)','(0b0)','(00g)','(a00)s00','(1/2b0)','(1/20g)',],
1836       
1837    'P 21 21 21':['(a00)','(0b0)','(00g)',],
1838       
1839    'P m m 2':['(a00)','(0b0)','(00g)',
1840        '(a00)s00','(0b0)0s0','(00g)s0s','(00g)ss0','(00g)0ss',
1841        '(a1/20)','(a01/2)','(0b1/2)','(1/2b0)','(01/2g)','(1/20g)',
1842        '(a1/21/2)','(1/2b1/2)','(1/21/2g)',],
1843    'P m 2 m':[],
1844    'P 2 m m':[],
1845       
1846    'P m c 21':[],
1847    'P c m 21':[],
1848    'P 21 m a':[],
1849    'P 21 a m':[],
1850    'P b 21 m':[],
1851    'P m 21 b':[],
1852       
1853    'P c c 2':[],
1854    'P 2 a a':[],
1855    'P b 2 b':[],
1856       
1857    'P m a 2':[],
1858    'P b m 2':[],
1859    'P 2 m b':[],
1860    'P 2 c m':[],
1861    'P c 2 m':[],
1862    'P m 2 a':[],
1863       
1864    'P c a 21':[],
1865    'P b c 21':[],
1866    'P 21 a b':[],
1867    'P 21 c a':[],
1868    'P c 21 b':[],
1869    'P b 21 a':[],
1870       
1871    'P n c 2':[],
1872    'P c n 2':[],
1873    'P 2 n a':[],
1874    'P 2 a n':[],
1875    'P b 2 n':[],
1876    'P n 2 b':[],
1877       
1878    'P m n 21':[],
1879    'P n m 21':[],
1880    'P 21 m n':[],
1881    'P 21 n m':[],
1882    'P n 21 m':[],
1883    'P m 21 n':[],
1884       
1885    'P b a 2':[],
1886    'P 2 c b':[],
1887    'P c 2 a':[],
1888       
1889    'P n a 21':[],
1890    'P b n 21':[],
1891    'P 21 n b':[],
1892    'P 21 c n':[],
1893    'P c 21 n':[],
1894    'P n 21 a':[],
1895       
1896    'P n n 2':[],
1897    'P 2 n n':[],
1898    'P n 2 n':[],
1899       
1900    'P m m m':[],
1901       
1902    'P n n n':[],
1903       
1904    'P c c m':[],
1905    'P m a a':[],
1906    'P b m b':[],
1907       
1908    'P b a n':[],
1909    'P n c b':[],
1910    'P c n a':[],
1911       
1912    'P m m a':[],
1913    'P m m b':[],
1914    'P b m m':[],
1915    'P c m m':[],
1916    'P m c m':[],
1917    'P m a m':[],
1918       
1919    'P n n a':[],
1920    'P n n b':[],
1921    'P b n n':[],
1922    'P c n n':[],
1923    'P n c n':[],
1924    'P n a n':[],
1925       
1926    'P m n a':[],
1927    'P n m b':[],
1928    'P b m n':[],
1929    'P c n m':[],
1930    'P n c m':[],
1931    'P m a n':[],
1932       
1933    'P c c a':[],
1934    'P c c b':[],
1935    'P b a a':[],
1936    'P c a a':[],
1937    'P b c b':[],
1938    'P b a b':[],
1939       
1940    'P b a m':[],
1941    'P m c b':[],
1942    'P c m a':[],
1943       
1944    'P c c n':['(00g)','(00g)s00','(00g)0s0','(00g)ss0','(a00)','(a00)0s0',
1945        '(a00)00s','(a00)0ss','(0b0)','(0b0)s00','(0b0)00s','(0b0)s0s'],
1946    'P n a a':['(00g)','(00g)s00','(00g)0s0','(00g)ss0','(a00)','(a00)0s0',
1947        '(a00)00s','(a00)0ss','(0b0)','(0b0)s00','(0b0)00s','(0b0)s0s'],
1948    'P b n b':['(00g)','(00g)s00','(00g)0s0','(00g)ss0','(a00)','(a00)0s0',
1949        '(a00)00s','(a00)0ss','(0b0)','(0b0)s00','(0b0)00s','(0b0)s0s'],
1950       
1951    'P b c m':[],
1952    'P c a m':[],
1953    'P m c a':[],
1954    'P m a b':[],
1955    'P b m a':[],
1956    'P c m b':[],
1957       
1958    'P n n m':['(00g)','(00g)s00','(00g)0s0','(00g)ss0','(a00)','(a00)0s0',
1959        '(a00)00s','(a00)0ss','(0b0)','(0b0)s00','(0b0)00s','(0b0)s0s'],
1960    'P m n n':['(00g)','(00g)s00','(00g)0s0','(00g)ss0','(a00)','(a00)0s0',
1961        '(a00)00s','(a00)0ss','(0b0)','(0b0)s00','(0b0)00s','(0b0)s0s'],
1962    'P n m n':['(00g)','(00g)s00','(00g)0s0','(00g)ss0','(a00)','(a00)0s0',
1963        '(a00)00s','(a00)0ss','(0b0)','(0b0)s00','(0b0)00s','(0b0)s0s'],
1964       
1965    'P m m n':[],
1966    'P n m m':[],
1967    'P m n m':[],
1968       
1969    'P b c n':['(00g)','(00g)s00','(00g)0s0','(00g)ss0','(a00)','(a00)0s0',
1970        '(a00)00s','(a00)0ss','(0b0)','(0b0)s00','(0b0)00s','(0b0)s0s'],
1971    'P c a n':['(00g)','(00g)s00','(00g)0s0','(00g)ss0','(a00)','(a00)0s0',
1972        '(a00)00s','(a00)0ss','(0b0)','(0b0)s00','(0b0)00s','(0b0)s0s'],
1973    'P n c a':['(00g)','(00g)s00','(00g)0s0','(00g)ss0','(a00)','(a00)0s0',
1974        '(a00)00s','(a00)0ss','(0b0)','(0b0)s00','(0b0)00s','(0b0)s0s'],
1975    'P n a b':['(00g)','(00g)s00','(00g)0s0','(00g)ss0','(a00)','(a00)0s0',
1976        '(a00)00s','(a00)0ss','(0b0)','(0b0)s00','(0b0)00s','(0b0)s0s'],
1977    'P b n a':['(00g)','(00g)s00','(00g)0s0','(00g)ss0','(a00)','(a00)0s0',
1978        '(a00)00s','(a00)0ss','(0b0)','(0b0)s00','(0b0)00s','(0b0)s0s'],
1979    'P c n b':['(00g)','(00g)s00','(00g)0s0','(00g)ss0','(a00)','(a00)0s0',
1980        '(a00)00s','(a00)0ss','(0b0)','(0b0)s00','(0b0)00s','(0b0)s0s'],
1981       
1982    'P b c a':[],
1983    'P c a b':[],
1984       
1985    'P n m a':['(00g)','(00g)s00','(00g)0s0','(00g)ss0','(a00)','(a00)0s0',
1986        '(a00)00s','(a00)0ss','(0b0)','(0b0)s00','(0b0)00s','(0b0)s0s'],
1987    'P m n b':['(00g)','(00g)s00','(00g)0s0','(00g)ss0','(a00)','(a00)0s0',
1988        '(a00)00s','(a00)0ss','(0b0)','(0b0)s00','(0b0)00s','(0b0)s0s'],
1989    'P b n m':['(00g)','(00g)s00','(00g)0s0','(00g)ss0','(a00)','(a00)0s0',
1990        '(a00)00s','(a00)0ss','(0b0)','(0b0)s00','(0b0)00s','(0b0)s0s'],
1991    'P c m n':['(00g)','(00g)s00','(00g)0s0','(00g)ss0','(a00)','(a00)0s0',
1992        '(a00)00s','(a00)0ss','(0b0)','(0b0)s00','(0b0)00s','(0b0)s0s'],
1993    'P m c n':['(00g)','(00g)s00','(00g)0s0','(00g)ss0','(a00)','(a00)0s0',
1994        '(a00)00s','(a00)0ss','(0b0)','(0b0)s00','(0b0)00s','(0b0)s0s'],
1995    'P n a m':['(00g)','(00g)s00','(00g)0s0','(00g)ss0','(a00)','(a00)0s0',
1996        '(a00)00s','(a00)0ss','(0b0)','(0b0)s00','(0b0)00s','(0b0)s0s'],
1997       
1998    'C 2 2 21':['(a00)','(0b0)','(00g)','(10g)','(01g)',],
1999    'C 2 2 2':[],
2000    'C m m 2':[],
2001    'C m c 21':[],
2002    'C c c 2':[],
2003       
2004    'C m 2 m':[],
2005    'C 2 m m':[],
2006       
2007    'C m 2 a':[],
2008    'C 2 m b':[],
2009       
2010    'C 2 c m':[],
2011    'C c 2 m':[],
2012    'C 2 c m':[],
2013       
2014    'C m c a':[],
2015    'C m m m':[],
2016    'C c c m':[],
2017    'C m m a':[],
2018    'C c c a':[],
2019    'C m c m':[],
2020    'I 2 2 2':[],
2021    'I 21 21 21':[],
2022    'I m m m':[],
2023       
2024    'I m m 2':[],
2025    'I m 2 m':[],
2026    'I 2 m m':[],
2027       
2028    'I b a 2':[],
2029    'I 2 c b':[],
2030    'I c 2 a':[],
2031       
2032    'I m a 2':[],
2033    'I b m 2':[],
2034    'I 2 m b':[],
2035       
2036    'I 2 c m':[],
2037    'I c 2 m':[],
2038    'I m 2 a':[],
2039       
2040    'I b a m':['(00g)','(00g)s00','(00g)0s0','(00g)ss0','(a00)','(a00)0s0',
2041        '(a00)00s','(a00)0ss','(0b0)','(0b0)s00','(0b0)00s','(0b0)s0s'],
2042    'I m c b':['(00g)','(00g)s00','(00g)0s0','(00g)ss0','(a00)','(a00)0s0',
2043        '(a00)00s','(a00)0ss','(0b0)','(0b0)s00','(0b0)00s','(0b0)s0s'],
2044    'I c m a':['(00g)','(00g)s00','(00g)0s0','(00g)ss0','(a00)','(a00)0s0',
2045        '(a00)00s','(a00)0ss','(0b0)','(0b0)s00','(0b0)00s','(0b0)s0s'],
2046       
2047    'I b c a':['(00g)','(00g)s00','(00g)0s0','(00g)ss0','(a00)','(a00)0s0',
2048        '(a00)00s','(a00)0ss','(0b0)','(0b0)s00','(0b0)00s','(0b0)s0s'],
2049    'I c a b':['(00g)','(00g)s00','(00g)0s0','(00g)ss0','(a00)','(a00)0s0',
2050        '(a00)00s','(a00)0ss','(0b0)','(0b0)s00','(0b0)00s','(0b0)s0s'],
2051       
2052    'I m m a':['(00g)','(00g)s00','(00g)0s0','(00g)ss0','(a00)','(a00)0s0',
2053        '(a00)00s','(a00)0ss','(0b0)','(0b0)s00','(0b0)00s','(0b0)s0s'],
2054    'I m m b':['(00g)','(00g)s00','(00g)0s0','(00g)ss0','(a00)','(a00)0s0',
2055        '(a00)00s','(a00)0ss','(0b0)','(0b0)s00','(0b0)00s','(0b0)s0s'],
2056    'I b m m ':['(00g)','(00g)s00','(00g)0s0','(00g)ss0','(a00)','(a00)0s0',
2057        '(a00)00s','(a00)0ss','(0b0)','(0b0)s00','(0b0)00s','(0b0)s0s'],
2058    'I c m m':['(00g)','(00g)s00','(00g)0s0','(00g)ss0','(a00)','(a00)0s0',
2059        '(a00)00s','(a00)0ss','(0b0)','(0b0)s00','(0b0)00s','(0b0)s0s'],
2060    'I m c m':['(00g)','(00g)s00','(00g)0s0','(00g)ss0','(a00)','(a00)0s0',
2061        '(a00)00s','(a00)0ss','(0b0)','(0b0)s00','(0b0)00s','(0b0)s0s'],
2062    'I m a m':['(00g)','(00g)s00','(00g)0s0','(00g)ss0','(a00)','(a00)0s0',
2063        '(a00)00s','(a00)0ss','(0b0)','(0b0)s00','(0b0)00s','(0b0)s0s'],
2064       
2065    'F 2 2 2':['(00g)','(00g)s00','(00g)0s0','(00g)ss0','(a00)','(a00)0s0',
2066        '(a00)00s','(a00)0ss','(0b0)','(0b0)s00','(0b0)00s','(0b0)s0s',
2067        '(10g)','(10g)s00','(10g)0s0','(10g)ss0','(a10)','(a10)0s0',
2068        '(a10)00s','(a10)0ss','(0b1)','(0b1)s00','(0b1)00s','(0b1)s0s',
2069        '(01g)','(01g)s00','(01g)0s0','(01g)ss0','(a01)','(a01)0s0',
2070        '(a01)00s','(a01)0ss','(1b0)','(1b0)s00','(1b0)00s','(1b0)s0s'],
2071       
2072    'F m m m':['(00g)','(00g)s00','(00g)0s0','(00g)ss0','(a00)','(a00)0s0',
2073        '(a00)00s','(a00)0ss','(0b0)','(0b0)s00','(0b0)00s','(0b0)s0s',
2074        '(10g)','(10g)s00','(10g)0s0','(10g)ss0','(a10)','(a10)0s0',
2075        '(a10)00s','(a10)0ss','(0b1)','(0b1)s00','(0b1)00s','(0b1)s0s',
2076        '(01g)','(01g)s00','(01g)0s0','(01g)ss0','(a01)','(a01)0s0',
2077        '(a01)00s','(a01)0ss','(1b0)','(1b0)s00','(1b0)00s','(1b0)s0s'],
2078       
2079    'F d d d':['(00g)','(00g)s00','(00g)0s0','(00g)ss0','(a00)','(a00)0s0',
2080        '(a00)00s','(a00)0ss','(0b0)','(0b0)s00','(0b0)00s','(0b0)s0s'],
2081       
2082    'F m m 2':['(00g)','(00g)ss0','(00g)0ss','(00g)s0s','(a00)','(a00)0s0',
2083        '(0b0)','(0b0)s00','(10g)','(10g)ss0','(10g)0ss','(10g)s0s','(a01)','(a01)0s0',
2084        '(1b0)','(1b0)s00','(01g)','(01g)ss0','(01g)0ss','(01g)s0s','(a10)','(a10)0s0',
2085        '(0b1)','(0b1)s00',],
2086       
2087    'F m 2 m':['(0b0)','(0b0)ss0','(0b0)0ss','(0b0)s0s','(a00)','(a00)00s',
2088        '(00g)','(00g)s00','(1b0)','(1b0)ss0','(1b0)0ss','(1b0)s0s','(a01)','(a01)00s',
2089        '(01g)','(01g)s00','(0b1)','(0b1)ss0','(0b1)0ss','(0b1)s0s','(a10)','(a10)00s',
2090        '(10g)','(10g)s00',],
2091       
2092    'F 2 m m':['(a00)','(a00)ss0','(a00)0ss','(a00)s0s','(0b0)','(0b0)00s',
2093        '(00g)','(00g)0s0','(a10)','(a10)ss0','(a10)0ss','(a10)s0s','(0b1)','(0b1)00s',
2094        '(10g)','(10g)0s0','(a01)','(a01)ss0','(a01)0ss','(a01)s0s','(1b0)','(1b0)00s',
2095        '(01g)','(01g)0s0',],
2096       
2097    'F d d 2':['(00g)','(00g)ss0','(00g)0ss','(00g)s0s','(a00)','(a00)0s0',
2098        '(0b0)','(0b0)s00',],
2099    'F d 2 d':['(0b0)','(0b0)ss0','(0b0)0ss','(0b0)s0s','(a00)','(a00)00s',
2100        '(00g)','(00g)s00',],
2101    'F 2 d d':['(a00)','(a00)ss0','(a00)0ss','(a00)s0s','(0b0)','(0b0)00s',
2102        '(00g)','(00g)0s0',],       
2103    #tetragonal - done
2104    'P 4':['(00g)','(00g)q','(00g)s','(1/21/2g)','(1/21/2g)q',],
2105    'P 41':['(00g)','(00g)q','(00g)s','(1/21/2g)','(1/21/2g)q',],
2106    'P 42':['(00g)','(00g)q','(00g)s','(1/21/2g)','(1/21/2g)q',],
2107    'P 43':['(00g)','(00g)q','(00g)s','(1/21/2g)','(1/21/2g)q',],
2108    'P -4':['(00g)','(1/21/2g)',],
2109    'P 4/m':['(00g)','(00g)s0','(1/21/2g)','(1/21/2g)s0',],
2110    'P 42/m':['(00g)','(00g)s0','(1/21/2g)','(1/21/2g)s0',],
2111    'P 4/n':['(00g)','(00g)s0','(1/21/2g)','(1/21/2g)q0',],
2112    'P 42/n':['(00g)','(00g)s0','(1/21/2g)','(1/21/2g)q0',],
2113    'P 4 2 2':['(00g)','(00g)q00','(00g)s00','(1/21/2g)','(1/21/2g)q00','(1/21/2g)s00',],
2114    'P 4 21 2':['(00g)','(00g)q00','(00g)s00',],
2115    'P 41 2 2':['(00g)','(00g)q00','(00g)s00','(1/21/2g)','(1/21/2g)q00','(1/21/2g)s00',],
2116    'P 41 21 2':['(00g)','(00g)q00','(00g)s00',],
2117    'P 42 2 2':['(00g)','(00g)q00','(00g)s00','(1/21/2g)','(1/21/2g)q00','(1/21/2g)s00',],
2118    'P 42 21 2':['(00g)','(00g)q00','(00g)s00',],
2119    'P 43 2 2':['(00g)','(00g)q00','(00g)s00','(1/21/2g)','(1/21/2g)q00','(1/21/2g)s00',],
2120    'P 43 21 2':['(00g)','(00g)q00','(00g)s00',],
2121    'P 4 m m':['(00g)','(00g)ss0','(00g)0ss','(00g)s0s',
2122        '(1/21/2g)','(1/21/2g)ss0','(1/21/2g)0ss','(1/21/2g)s0s',],
2123    'P 4 b m':['(00g)','(00g)ss0','(00g)0ss','(00g)s0s','(1/21/2g)','(1/21/2g)qq0','(1/21/2g)qqs',],
2124    'P 42 c m':['(00g)','(00g)ss0','(00g)0ss','(00g)s0s',
2125        '(1/21/2g)','(1/21/2g)ss0','(1/21/2g)0ss','(1/21/2g)s0s',],
2126    'P 42 n m':['(00g)','(00g)ss0','(00g)0ss','(00g)s0s','(1/21/2g)','(1/21/2g)qq0','(1/21/2g)qqs',],
2127    'P 4 c c':['(00g)','(00g)ss0','(00g)0ss','(00g)s0s',
2128        '(1/21/2g)','(1/21/2g)ss0','(1/21/2g)0ss','(1/21/2g)s0s',],
2129    'P 4 n c':['(00g)','(00g)ss0','(00g)0ss','(00g)s0s','(1/21/2g)','(1/21/2g)qq0','(1/21/2g)qqs'],
2130    'P 42 m c':['(00g)','(00g)ss0','(00g)0ss','(00g)s0s',
2131        '(1/21/2g)','(1/21/2g)ss0','(1/21/2g)0ss','(1/21/2g)s0s',],
2132    'P 42 b c':['(00g)','(00g)ss0','(00g)0ss','(00g)s0s','(1/21/2g)','(1/21/2g)qq0','(1/21/2g)qqs'],
2133    'P -4 2 m':['(00g)','(00g)00s','(1/21/2g)','(1/21/2g)00s',],
2134    'P -4 2 c':['(00g)','(00g)00s',],
2135    'P -4 21 m':['(00g)','(00g)00s',],
2136    'P -4 21 c':['(00g)','(00g)00s',],
2137    'P -4 m 2':['(00g)','(00g)0s0','(1/21/2g)','(1/21/2g)0s0',],
2138    'P -4 c 2':['(00g)','(00g)0s0','(1/21/2g)','(1/21/2g)0s0',],
2139    'P -4 b 2':['(00g)','(00g)0s0','(1/21/2g)','(1/21/2g)0q0',],
2140    'P -4 n 2':['(00g)','(00g)0s0','(1/21/2g)','(1/21/2g)0q0',],
2141    'P 4/m m m':['(00g)','(00g)s0s0','(00g)00ss','(00g)s00s',
2142        '(1/21/2g)','(1/21/2g)s0s0','(1/21/2g)00ss','(1/21/2g)s00s',],
2143    'P 4/m c c':['(00g)','(00g)s0s0','(00g)00ss','(00g)s00s',
2144        '(1/21/2g)','(1/21/2g)s0s0','(1/21/2g)00ss','(1/21/2g)s00s',],
2145    'P 4/n b m':['(00g)','(00g)s0s0','(00g)00ss','(00g)s00s',
2146        '(1/21/2g)','(1/21/2g)q0q0','(1/21/2g)q0qs',],
2147    'P 4/n n c':['(00g)','(00g)s0s0','(00g)00ss','(00g)s00s',
2148        '(1/21/2g)','(1/21/2g)q0q0','(1/21/2g)q0qs',],
2149    'P 4/m b m':['(00g)','(00g)s0s0','(00g)00ss','(00g)s00s',],
2150    'P 4/m n c':['(00g)','(00g)s0s0','(00g)00ss','(00g)s00s',],
2151    'P 4/n m m':['(00g)','(00g)s0s0','(00g)00ss','(00g)s00s',],
2152    'P 4/n c c':['(00g)','(00g)s0s0','(00g)00ss','(00g)s00s',],
2153    'P 42/m m c':['(00g)','(00g)s0s0','(00g)00ss','(00g)s00s',
2154        '(1/21/2g)','(1/21/2g)s0s0','(1/21/2g)00ss','(1/21/2g)s00s',],
2155    'P 42/m c m':['(00g)','(00g)s0s0','(00g)00ss','(00g)s00s',
2156        '(1/21/2g)','(1/21/2g)s0s0','(1/21/2g)00ss','(1/21/2g)s00s',],
2157    'P 42/n b c':['(00g)','(00g)s0s0','(00g)00ss','(00g)s00s',
2158        '(1/21/2g)','(1/21/2g)q0q0','(1/21/2g)q0qs',],
2159    'P 42/n n m':['(00g)','(00g)s0s0','(00g)00ss','(00g)s00s',
2160        '(1/21/2g)','(1/21/2g)q0q0','(1/21/2g)q0qs',],
2161    'P 42/m b c':['(00g)','(00g)s0s0','(00g)00ss','(00g)s00s',],
2162    'P 42/m n m':['(00g)','(00g)s0s0','(00g)00ss','(00g)s00s',],
2163    'P 42/n m c':['(00g)','(00g)s0s0','(00g)00ss','(00g)s00s',],
2164    'P 42/n c m':['(00g)','(00g)s0s0','(00g)00ss','(00g)s00s',],
2165    'I 4':['(00g)','(00g)q','(00g)s',],
2166    'I 41':['(00g)','(00g)q','(00g)s',],
2167    'I -4':['(00g)',],
2168    'I 4/m':['(00g)','(00g)s0',],
2169    'I 41/a':['(00g)','(00g)s0',],  #s0?
2170    'I 4 2 2':['(00g)','(00g)q00','(00g)s00',],
2171    'I 41 2 2':['(00g)','(00g)q00','(00g)s00',],
2172    'I 4 m m':['(00g)','(00g)ss0','(00g)0ss','(00g)s0s',],
2173    'I 4 c m':['(00g)','(00g)ss0','(00g)0ss','(00g)s0s',],
2174    'I 41 m d':['(00g)','(00g)ss0','(00g)0ss','(00g)s0s',],
2175    'I 41 c d':['(00g)','(00g)ss0','(00g)0ss','(00g)s0s',],
2176    'I -4 m 2':['(00g)','(00g)0s0',],
2177    'I -4 c 2':['(00g)','(00g)0s0',],
2178    'I -4 2 m':['(00g)','(00g)00s',],
2179    'I -4 2 d':['(00g)','(00g)00s',],
2180    'I 4/m m m':['(00g)','(00g)s0s0','(00g)00ss','(00g)s00s',],
2181    'I 4/m c m':['(00g)','(00g)s0s0','(00g)00ss','(00g)s00s',],
2182    'I 41/a m d':['(00g)','(00g)s0s0','(00g)00ss','(00g)s00s',],
2183    'I 41/a c d':['(00g)','(00g)s0s0','(00g)00ss','(00g)s00s',],
2184    #trigonal/rhombahedral - done & checked
2185    'R 3':['(00g)','(00g)t',],
2186    'R -3':['(00g)',],
2187    'R 3 2':['(00g)','(00g)t0',],
2188    'R 3 m':['(00g)','(00g)0s',],
2189    'R 3 c':['(00g)','(00g)0s',],   #not 0s0
2190    'R -3 m':['(00g)','(00g)0s',],
2191    'R -3 c':['(00g)','(00g)0s',],  #not 0s0
2192    'P 3':['(00g)','(00g)t','(1/31/3g)','(1/31/3g)t',],
2193    'P 31':['(00g)','(00g)t','(1/31/3g)','(1/31/3g)t',],
2194    'P 32':['(00g)','(00g)t','(1/31/3g)','(1/31/3g)t',],
2195    'P -3':['(00g)','(1/31/3g)',],
2196    'P 3 1 2':['(00g)','(00g)t00','(1/31/3g)','(1/31/3g)t00',],
2197    'P 3 2 1':['(00g)','(00g)t00',],
2198    'P 31 1 2':['(00g)','(00g)t00','(1/31/3g)','(1/31/3g)t00',],
2199    'P 31 2 1':['(00g)','(00g)t00',],
2200    'P 32 1 2':['(00g)','(00g)t00','(1/31/3g)','(1/31/3g)t00',],
2201    'P 32 2 1':['(00g)','(00g)t00',],
2202    'P 3 m 1':['(00g)','(00g)0s0',],
2203    'P 3 1 m':['(00g)','(00g)00s','(1/31/3g)','(1/31/3g)00s',],
2204    'P 3 c 1':['(00g)','(00g)0s0',],
2205    'P 3 1 c':['(00g)','(00g)00s','(1/31/3g)','(1/31/3g)00s',],
2206    'P -3 1 m':['(00g)','(00g)00s','(1/31/3g)','(1/31/3g)00s',],
2207    'P -3 1 c':['(00g)','(00g)00s','(1/31/3g)','(1/31/3g)00s',],
2208    'P -3 m 1':['(00g)','(00g)0s0',],
2209    'P -3 c 1':['(00g)','(00g)0s0',],
2210    #hexagonal - done & checked
2211    'P 6':['(00g)','(00g)h','(00g)t','(00g)s',],
2212    'P 61':['(00g)','(00g)h','(00g)t','(00g)s',],
2213    'P 65':['(00g)','(00g)h','(00g)t','(00g)s',],
2214    'P 62':['(00g)','(00g)h','(00g)t','(00g)s',],
2215    'P 64':['(00g)','(00g)h','(00g)t','(00g)s',],
2216    'P 63':['(00g)','(00g)h','(00g)t','(00g)s',],
2217    'P -6':['(00g)',],
2218    'P 6/m':['(00g)','(00g)s0',],
2219    'P 63/m':['(00g)','(00g)s0'],
2220    'P 6 2 2':['(00g)','(00g)h00','(00g)t00','(00g)s00',],
2221    'P 61 2 2':['(00g)','(00g)h00','(00g)t00','(00g)s00',],
2222    'P 65 2 2':['(00g)','(00g)h00','(00g)t00','(00g)s00',],
2223    'P 62 2 2':['(00g)','(00g)h00','(00g)t00','(00g)s00',],
2224    'P 64 2 2':['(00g)','(00g)h00','(00g)t00','(00g)s00',],
2225    'P 63 2 2':['(00g)','(00g)h00','(00g)t00','(00g)s00',],
2226    'P 6 m m':['(00g)','(00g)ss0','(00g)0ss','(00g)s0s',],
2227    'P 6 c c':['(00g)','(00g)ss0','(00g)0ss','(00g)s0s',],
2228    'P 63 c m':['(00g)','(00g)ss0','(00g)0ss','(00g)s0s',],
2229    'P 63 m c':['(00g)','(00g)ss0','(00g)0ss','(00g)s0s',],
2230    'P -6 m 2':['(00g)','(00g)0s0',],
2231    'P -6 c 2':['(00g)','(00g)0s0',],
2232    'P -6 2 m':['(00g)','(00g)00s',],
2233    'P -6 2 c':['(00g)','(00g)00s',],
2234    'P 6/m m m':['(00g)','(00g)s0s0','(00g)00ss','(00g)s00s',],
2235    'P 6/m c c':['(00g)','(00g)s0s0','(00g)00ss','(00g)s00s',],
2236    'P 63/m c m':['(00g)','(00g)s0s0','(00g)00ss','(00g)s00s',],
2237    'P 63/m m c':['(00g)','(00g)s0s0','(00g)00ss','(00g)s00s',],
2238    }
2239
2240#'A few non-standard space groups for test use'
2241nonstandard_sglist = ('P 21 1 1','P 1 21 1','P 1 1 21','R 3 r','R 3 2 h', 
2242                      'R -3 r', 'R 3 2 r','R 3 m h', 'R 3 m r',
2243                      'R 3 c r','R -3 c r','R -3 m r',),
2244
2245#A list of orthorhombic space groups that were renamed in the 2002 Volume A,
2246# along with the pre-2002 name. The e designates a double glide-plane'''
2247sgequiv_2002_orthorhombic= (('A e m 2', 'A b m 2',),
2248                            ('A e a 2', 'A b a 2',),
2249                            ('C m c e', 'C m c a',),
2250                            ('C m m e', 'C m m a',),
2251                            ('C c c e', 'C c c a'),)
2252#Use the space groups types in this order to list the symbols in the
2253#order they are listed in the International Tables, vol. A'''
2254symtypelist = ('triclinic', 'monoclinic', 'orthorhombic', 'tetragonal', 
2255               'trigonal', 'hexagonal', 'cubic')
2256
2257# self-test materials follow. Requires files in directory testinp
2258selftestlist = []
2259'''Defines a list of self-tests'''
2260selftestquiet = True
2261def _ReportTest():
2262    'Report name and doc string of current routine when ``selftestquiet`` is False'
2263    if not selftestquiet:
2264        import inspect
2265        caller = inspect.stack()[1][3]
2266        doc = eval(caller).__doc__
2267        if doc is not None:
2268            print('testing '+__file__+' with '+caller+' ('+doc+')')
2269        else:
2270            print('testing '+__file__()+" with "+caller)
2271def test0():
2272    '''self-test #0: exercise MoveToUnitCell'''
2273    _ReportTest()
2274    msg = "MoveToUnitCell failed"
2275    assert (MoveToUnitCell([1,2,3]) == [0,0,0]).all, msg
2276    assert (MoveToUnitCell([2,-1,-2]) == [0,0,0]).all, msg
2277    assert abs(MoveToUnitCell(np.array([-.1]))[0]-0.9) < 1e-6, msg
2278    assert abs(MoveToUnitCell(np.array([.1]))[0]-0.1) < 1e-6, msg
2279selftestlist.append(test0)
2280
2281def test1():
2282    '''self-test #1: SpcGroup against previous results'''
2283    #'''self-test #1: SpcGroup and SGPrint against previous results'''
2284    _ReportTest()
2285    testdir = ospath.join(ospath.split(ospath.abspath( __file__ ))[0],'testinp')
2286    if ospath.exists(testdir):
2287        if testdir not in sys.path: sys.path.insert(0,testdir)
2288    import spctestinp
2289    def CompareSpcGroup(spc, referr, refdict, reflist): 
2290        'Compare output from GSASIIspc.SpcGroup with results from a previous run'
2291        # if an error is reported, the dictionary can be ignored
2292        msg0 = "CompareSpcGroup failed on space group %s" % spc
2293        result = SpcGroup(spc)
2294        if result[0] == referr and referr > 0: return True
2295        keys = result[1].keys()
2296        #print result[1]['SpGrp']
2297        #msg = msg0 + " in list lengths"
2298        #assert len(keys) == len(refdict.keys()), msg
2299        for key in refdict.keys():
2300            if key == 'SGOps' or  key == 'SGCen':
2301                msg = msg0 + (" in key %s length" % key)
2302                assert len(refdict[key]) == len(result[1][key]), msg
2303                for i in range(len(refdict[key])):
2304                    msg = msg0 + (" in key %s level 0" % key)
2305                    assert np.allclose(result[1][key][i][0],refdict[key][i][0]), msg
2306                    msg = msg0 + (" in key %s level 1" % key)
2307                    assert np.allclose(result[1][key][i][1],refdict[key][i][1]), msg
2308            else:
2309                msg = msg0 + (" in key %s" % key)
2310                assert result[1][key] == refdict[key], msg
2311        msg = msg0 + (" in key %s reflist" % key)
2312        #for (l1,l2) in zip(reflist, SGPrint(result[1])):
2313        #    assert l2.replace('\t','').replace(' ','') == l1.replace(' ',''), 'SGPrint ' +msg
2314        # for now disable SGPrint testing, output has changed
2315        #assert reflist == SGPrint(result[1]), 'SGPrint ' +msg
2316    for spc in spctestinp.SGdat:
2317        CompareSpcGroup(spc, 0, spctestinp.SGdat[spc], spctestinp.SGlist[spc] )
2318selftestlist.append(test1)
2319
2320def test2():
2321    '''self-test #2: SpcGroup against cctbx (sgtbx) computations'''
2322    _ReportTest()
2323    testdir = ospath.join(ospath.split(ospath.abspath( __file__ ))[0],'testinp')
2324    if ospath.exists(testdir):
2325        if testdir not in sys.path: sys.path.insert(0,testdir)
2326    import sgtbxtestinp
2327    def CompareWcctbx(spcname, cctbx_in, debug=0):
2328        'Compare output from GSASIIspc.SpcGroup with results from cctbx.sgtbx'
2329        cctbx = cctbx_in[:] # make copy so we don't delete from the original
2330        spc = (SpcGroup(spcname))[1]
2331        if debug: print spc['SpGrp']
2332        if debug: print spc['SGCen']
2333        latticetype = spcname.strip().upper()[0]
2334        # lattice type of R implies Hexagonal centering", fix the rhombohedral settings
2335        if latticetype == "R" and len(spc['SGCen']) == 1: latticetype = 'P'
2336        assert latticetype == spc['SGLatt'], "Failed: %s does not match Lattice: %s" % (spcname, spc['SGLatt'])
2337        onebar = [1]
2338        if spc['SGInv']: onebar.append(-1)
2339        for (op,off) in spc['SGOps']:
2340            for inv in onebar:
2341                for cen in spc['SGCen']:
2342                    noff = off + cen
2343                    noff = MoveToUnitCell(noff)
2344                    mult = tuple((op*inv).ravel().tolist())
2345                    if debug: print "\n%s: %s + %s" % (spcname,mult,noff)
2346                    for refop in cctbx:
2347                        if debug: print refop
2348                        # check the transform
2349                        if refop[:9] != mult: continue
2350                        if debug: print "mult match"
2351                        # check the translation
2352                        reftrans = list(refop[-3:])
2353                        reftrans = MoveToUnitCell(reftrans)
2354                        if all(abs(noff - reftrans) < 1.e-5):
2355                            cctbx.remove(refop)
2356                            break
2357                    else:
2358                        assert False, "failed on %s:\n\t %s + %s" % (spcname,mult,noff)
2359    for key in sgtbxtestinp.sgtbx:
2360        CompareWcctbx(key, sgtbxtestinp.sgtbx[key])
2361selftestlist.append(test2)
2362
2363def test3(): 
2364    '''self-test #3: exercise SytSym (includes GetOprPtrName, GenAtom, GetKNsym)
2365     for selected space groups against info in IT Volume A '''
2366    _ReportTest()
2367    def ExerciseSiteSym (spc, crdlist):
2368        'compare site symmetries and multiplicities for a specified space group'
2369        msg = "failed on site sym test for %s" % spc
2370        (E,S) = SpcGroup(spc)
2371        assert not E, msg
2372        for t in crdlist:
2373            symb, m = SytSym(t[0],S)
2374            if symb.strip() != t[2].strip() or m != t[1]:
2375                print spc,t[0],m,symb,t[2]
2376            assert m == t[1]
2377            #assert symb.strip() == t[2].strip()
2378
2379    ExerciseSiteSym('p 1',[
2380            ((0.13,0.22,0.31),1,'1'),
2381            ((0,0,0),1,'1'),
2382            ])
2383    ExerciseSiteSym('p -1',[
2384            ((0.13,0.22,0.31),2,'1'),
2385            ((0,0.5,0),1,'-1'),
2386            ])
2387    ExerciseSiteSym('C 2/c',[
2388            ((0.13,0.22,0.31),8,'1'),
2389            ((0.0,.31,0.25),4,'2(y)'),
2390            ((0.25,.25,0.5),4,'-1'),
2391            ((0,0.5,0),4,'-1'),
2392            ])
2393    ExerciseSiteSym('p 2 2 2',[
2394            ((0.13,0.22,0.31),4,'1'),
2395            ((0,0.5,.31),2,'2(z)'),
2396            ((0.5,.31,0.5),2,'2(y)'),
2397            ((.11,0,0),2,'2(x)'),
2398            ((0,0.5,0),1,'222'),
2399            ])
2400    ExerciseSiteSym('p 4/n',[
2401            ((0.13,0.22,0.31),8,'1'),
2402            ((0.25,0.75,.31),4,'2(z)'),
2403            ((0.5,0.5,0.5),4,'-1'),
2404            ((0,0.5,0),4,'-1'),
2405            ((0.25,0.25,.31),2,'4(001)'),
2406            ((0.25,.75,0.5),2,'-4(001)'),
2407            ((0.25,.75,0.0),2,'-4(001)'),
2408            ])
2409    ExerciseSiteSym('p 31 2 1',[
2410            ((0.13,0.22,0.31),6,'1'),
2411            ((0.13,0.0,0.833333333),3,'2(100)'),
2412            ((0.13,0.13,0.),3,'2(110)'),
2413            ])
2414    ExerciseSiteSym('R 3 c',[
2415            ((0.13,0.22,0.31),18,'1'),
2416            ((0.0,0.0,0.31),6,'3'),
2417            ])
2418    ExerciseSiteSym('R 3 c R',[
2419            ((0.13,0.22,0.31),6,'1'),
2420            ((0.31,0.31,0.31),2,'3(111)'),
2421            ])
2422    ExerciseSiteSym('P 63 m c',[
2423            ((0.13,0.22,0.31),12,'1'),
2424            ((0.11,0.22,0.31),6,'m(100)'),
2425            ((0.333333,0.6666667,0.31),2,'3m(100)'),
2426            ((0,0,0.31),2,'3m(100)'),
2427            ])
2428    ExerciseSiteSym('I a -3',[
2429            ((0.13,0.22,0.31),48,'1'),
2430            ((0.11,0,0.25),24,'2(x)'),
2431            ((0.11,0.11,0.11),16,'3(111)'),
2432            ((0,0,0),8,'-3(111)'),
2433            ])
2434selftestlist.append(test3)
2435
2436if __name__ == '__main__':
2437    # run self-tests
2438    selftestquiet = False
2439    for test in selftestlist:
2440        test()
2441    print "OK"
Note: See TracBrowser for help on using the repository browser.