source: trunk/GSASIIspc.py @ 1570

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

fix to G2strIO for space group output.
finish interpretation of super symmetry symbols

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