source: trunk/GSASIIspc.py @ 1568

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

revise super space group to reflect latest table of unique SS groups from Stokes, Campbell & van Smaalen (2010). Shortened some lists. Mono, Tetr, Trig/rhom & hex all checked out OK. More work on ortho.

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