source: trunk/GSASIIspc.py @ 1571

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

fix typos in small angle tutorials
add menu with copy & reset to instrument parameters for SASD data
copy masks now copies the lower threshold
work on indexing incommensurate powder patterns, plots

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