source: trunk/GSASIIspc.py @ 1873

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

add remaining ortho super space group symbols & check all - all done!

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Author Revision URL Id
File size: 141.4 KB
Line 
1# -*- coding: utf-8 -*-
2"""
3*GSASIIspc: Space group module*
4-------------------------------
5
6Space group interpretation routines. Note that space group information is
7stored in a :ref:`Space Group (SGData)<SGData_table>` object.
8
9"""
10########### SVN repository information ###################
11# $Date: 2015-05-29 20:57:45 +0000 (Fri, 29 May 2015) $
12# $Author: vondreele $
13# $Revision: 1873 $
14# $URL: trunk/GSASIIspc.py $
15# $Id: GSASIIspc.py 1873 2015-05-29 20:57:45Z 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 copy
24import os.path as ospath
25
26import GSASIIpath
27GSASIIpath.SetVersionNumber("$Revision: 1873 $")
28import pyspg
29
30npsind = lambda x: np.sin(x*np.pi/180.)
31npcosd = lambda x: np.cos(x*np.pi/180.)
32DEBUG = False
33   
34################################################################################
35#### Space group codes
36################################################################################
37
38def SpcGroup(SGSymbol):
39    """
40    Determines cell and symmetry information from a short H-M space group name
41
42    :param SGSymbol: space group symbol (string) with spaces between axial fields
43    :returns: (SGError,SGData)
44   
45       * SGError = 0 for no errors; >0 for errors (see SGErrors below for details)
46       * SGData - is a dict (see :ref:`Space Group object<SGData_table>`) with entries:
47       
48             * 'SpGrp': space group symbol, slightly cleaned up
49             * 'SGLaue':  one of '-1', '2/m', 'mmm', '4/m', '4/mmm', '3R',
50               '3mR', '3', '3m1', '31m', '6/m', '6/mmm', 'm3', 'm3m'
51             * 'SGInv': boolean; True if centrosymmetric, False if not
52             * 'SGLatt': one of 'P', 'A', 'B', 'C', 'I', 'F', 'R'
53             * 'SGUniq': one of 'a', 'b', 'c' if monoclinic, '' otherwise
54             * 'SGCen': cell centering vectors [0,0,0] at least
55             * 'SGOps': symmetry operations as [M,T] so that M*x+T = x'
56             * 'SGSys': one of 'triclinic', 'monoclinic', 'orthorhombic',
57               'tetragonal', 'rhombohedral', 'trigonal', 'hexagonal', 'cubic'
58             * 'SGPolax': one of ' ', 'x', 'y', 'x y', 'z', 'x z', 'y z',
59               'xyz', '111' for arbitrary axes
60             * 'SGPtGrp': one of 32 point group symbols (with some permutations), which
61                is filled by SGPtGroup, is external (KE) part of supersymmetry point group
62             * 'SSGKl': default internal (Kl) part of supersymmetry point group; modified
63                in supersymmetry stuff depending on chosen modulation vector for Mono & Ortho
64
65    """
66    LaueSym = ('-1','2/m','mmm','4/m','4/mmm','3R','3mR','3','3m1','31m','6/m','6/mmm','m3','m3m')
67    LattSym = ('P','A','B','C','I','F','R')
68    UniqSym = ('','','a','b','c','',)
69    SysSym = ('triclinic','monoclinic','orthorhombic','tetragonal','rhombohedral','trigonal','hexagonal','cubic')
70    SGData = {}
71    SGInfo = pyspg.sgforpy(SGSymbol)
72    SGData['SpGrp'] = SGSymbol.strip().lower().capitalize()
73    SGData['SGLaue'] = LaueSym[SGInfo[0]-1]
74    SGData['SGInv'] = bool(SGInfo[1])
75    SGData['SGLatt'] = LattSym[SGInfo[2]-1]
76    SGData['SGUniq'] = UniqSym[SGInfo[3]+1]
77    if SGData['SGLatt'] == 'P':
78        SGData['SGCen'] = np.array(([0,0,0],))
79    elif SGData['SGLatt'] == 'A':
80        SGData['SGCen'] = np.array(([0,0,0],[0,.5,.5]))
81    elif SGData['SGLatt'] == 'B':
82        SGData['SGCen'] = np.array(([0,0,0],[.5,0,.5]))
83    elif SGData['SGLatt'] == 'C':
84        SGData['SGCen'] = np.array(([0,0,0],[.5,.5,0,]))
85    elif SGData['SGLatt'] == 'I':
86        SGData['SGCen'] = np.array(([0,0,0],[.5,.5,.5]))
87    elif SGData['SGLatt'] == 'F':
88        SGData['SGCen'] = np.array(([0,0,0],[0,.5,.5],[.5,0,.5],[.5,.5,0,]))
89    elif SGData['SGLatt'] == 'R':
90        SGData['SGCen'] = np.array(([0,0,0],[1./3.,2./3.,2./3.],[2./3.,1./3.,1./3.]))
91    SGData['SGOps'] = []
92    for i in range(SGInfo[5]):
93        Mat = np.array(SGInfo[6][i])
94        Trns = np.array(SGInfo[7][i])
95        SGData['SGOps'].append([Mat,Trns])
96    if SGData['SGLaue'] in '-1':
97        SGData['SGSys'] = SysSym[0]
98    elif SGData['SGLaue'] in '2/m':
99        SGData['SGSys'] = SysSym[1]
100    elif SGData['SGLaue'] in 'mmm':
101        SGData['SGSys'] = SysSym[2]
102    elif SGData['SGLaue'] in ['4/m','4/mmm']:
103        SGData['SGSys'] = SysSym[3]
104    elif SGData['SGLaue'] in ['3R','3mR']:
105        SGData['SGSys'] = SysSym[4]
106    elif SGData['SGLaue'] in ['3','3m1','31m']:
107        SGData['SGSys'] = SysSym[5]
108    elif SGData['SGLaue'] in ['6/m','6/mmm']:
109        SGData['SGSys'] = SysSym[6]
110    elif SGData['SGLaue'] in ['m3','m3m']:
111        SGData['SGSys'] = SysSym[7]
112    SGData['SGPolax'] = SGpolar(SGData)
113    SGData['SGPtGrp'],SGData['SSGKl'] = SGPtGroup(SGData)
114    return SGInfo[8],SGData
115
116def SGErrors(IErr):
117    '''
118    Interprets the error message code from SpcGroup. Used in SpaceGroup.
119   
120    :param IErr: see SGError in :func:`SpcGroup`
121    :returns:
122        ErrString - a string with the error message or "Unknown error"
123    '''
124
125    ErrString = [' ',
126        'Less than 2 operator fields were found',
127        'Illegal Lattice type, not P, A, B, C, I, F or R',
128        'Rhombohedral lattice requires a 3-axis',
129        'Minus sign does not preceed 1, 2, 3, 4 or 6',
130        'Either a 5-axis anywhere or a 3-axis in field not allowed',
131        ' ',
132        'I for COMPUTED GO TO out of range.',
133        'An a-glide mirror normal to A not allowed',
134        'A b-glide mirror normal to B not allowed',
135        'A c-glide mirror normal to C not allowed',
136        'D-glide in a primitive lattice not allowed',
137        'A 4-axis not allowed in the 2nd operator field',
138        'A 6-axis not allowed in the 2nd operator field',
139        'More than 24 matrices needed to define group',
140        ' ',
141        'Improper construction of a rotation operator',
142        'Mirror following a / not allowed',
143        'A translation conflict between operators',
144        'The 2bar operator is not allowed',
145        '3 fields are legal only in R & m3 cubic groups',
146        'Syntax error. Expected I -4 3 d at this point',
147        ' ',
148        'A or B centered tetragonal not allowed',
149        ' ','unknown error in sgroup',' ',' ',' ',
150        'Illegal character in the space group symbol',
151        ]
152    try:
153        return ErrString[IErr]
154    except:
155        return "Unknown error"
156
157def SGpolar(SGData):
158    '''
159    Determine identity of polar axes if any
160    '''
161    POL = ('','x','y','x y','z','x z','y z','xyz','111')
162    NP = [1,2,4]
163    NPZ = [0,1]
164    for M,T in SGData['SGOps']:
165        for i in range(3):
166            if M[i][i] <= 0.: NP[i] = 0
167        if M[0][2] > 0: NPZ[0] = 8
168        if M[1][2] > 0: NPZ[1] = 0
169    NPol = (NP[0]+NP[1]+NP[2]+NPZ[0]*NPZ[1])*(1-int(SGData['SGInv']))
170    return POL[NPol]
171   
172def SGPtGroup(SGData):
173    '''
174    Determine point group of the space group - done after space group symbol has
175    been evaluated by SpcGroup. Only short symbols are allowed
176   
177    :param SGData: from :func SpcGroup
178    :returns: SSGPtGrp & SSGKl (only defaults for Mono & Ortho)
179    '''
180    Flds = SGData['SpGrp'].split()
181    if len(Flds) < 2:
182        return '',[]
183    if SGData['SGLaue'] == '-1':    #triclinic
184        if '-' in Flds[1]:
185            return '-1',[-1,]
186        else:
187            return '1',[1,]
188    elif SGData['SGLaue'] == '2/m': #monoclinic - default for 2D modulation vector
189        if '/' in SGData['SpGrp']:
190            return '2/m',[-1,1]
191        elif '2' in SGData['SpGrp']:
192            return '2',[-1,]
193        else:
194            return 'm',[1,]
195    elif SGData['SGLaue'] == 'mmm': #orthorhombic
196        if SGData['SpGrp'].count('2') == 3:
197            return '222',[-1,-1,-1]
198        elif SGData['SpGrp'].count('2') == 1:
199            if SGData['SGPolax'] == 'x':
200                return '2mm',[-1,1,1]
201            elif SGData['SGPolax'] == 'y':
202                return 'm2m',[1,-1,1]
203            elif SGData['SGPolax'] == 'z':
204                return 'mm2',[1,1,-1]
205        else:
206            return 'mmm',[1,1,1]
207    elif SGData['SGLaue'] == '4/m': #tetragonal
208        if '/' in SGData['SpGrp']:
209            return '4/m',[1,-1]
210        elif '-' in Flds[1]:
211            return '-4',[-1,]
212        else:
213            return '4',[1,]
214    elif SGData['SGLaue'] == '4/mmm':
215        if '/' in SGData['SpGrp']:
216            return '4/mmm',[1,-1,1,1]
217        elif '-' in Flds[1]:
218            if '2' in Flds[2]:
219                return '-42m',[-1,-1,1]
220            else:
221                return '-4m2',[-1,1,-1]             
222        elif '2' in Flds[2:]:
223            return '422',[1,-1,-1]
224        else:
225            return '4mm',[1,1,1]
226    elif SGData['SGLaue'] in ['3','3R']:  #trigonal/rhombohedral
227        if '-' in Flds[1]:
228            return '-3',[-1,]
229        else:
230            return '3',[1,]
231    elif SGData['SGLaue'] == '3mR' or 'R' in Flds[0]:
232        if '2' in Flds[2]:
233            return '32',[1,-1]
234        elif '-' in Flds[1]:
235            return '-3m',[-1,1]
236        else:
237            return '3m',[1,1]
238    elif SGData['SGLaue'] == '3m1':
239        if '2' in Flds[2]:
240            return '321',[1,-1,1]
241        elif '-' in Flds[1]:
242            return '-3m1',[-1,1,1]
243        else:
244            return '3m1',[1,1,1]
245    elif SGData['SGLaue'] == '31m':
246        if '2' in Flds[3]:
247            return '312',[1,1,-1]
248        elif '-' in Flds[1]:
249            return '-31m',[-1,1,1]
250        else:
251            return '31m',[1,1,1]
252    elif SGData['SGLaue'] == '6/m': #hexagonal
253        if '/' in SGData['SpGrp']:
254            return '6/m',[1,-1]
255        elif '-' in SGData['SpGrp']:
256            return '-6',[-1,]
257        else:
258            return '6',[1,]
259    elif SGData['SGLaue'] == '6/mmm':
260        if '/' in SGData['SpGrp']:
261            return '6/mmm',[1,-1,1,1]
262        elif '-' in Flds[1]:
263            if '2' in Flds[2]:
264                return '-62m',[-1,-1,1]
265            else:
266                return '-6m2',[-1,1,-1]                 
267        elif '2' in Flds[2:]:
268            return '622',[1,-1,-1]
269        else:
270            return '6mm',[1,1,1]   
271    elif SGData['SGLaue'] == 'm3':      #cubic - no (3+1) supersymmetry
272        if '2' in Flds[1]:
273            return '23',[]
274        else: 
275            return 'm3',[]
276    elif SGData['SGLaue'] == 'm3m':
277        if '4' in Flds[1]:
278            if '-' in Flds[1]:
279                return '-43m',[]
280            else:
281                return '432',[]
282        else:
283            return 'm-3m',[]
284   
285def SGPrint(SGData):
286    '''
287    Print the output of SpcGroup in a nicely formatted way. Used in SpaceGroup
288
289    :param SGData: from :func:`SpcGroup`
290    :returns:
291        SGText - list of strings with the space group details
292        SGTable - list of strings for each of the operations
293    '''
294    Mult = len(SGData['SGCen'])*len(SGData['SGOps'])*(int(SGData['SGInv'])+1)
295    SGText = []
296    SGText.append(' Space Group: '+SGData['SpGrp'])
297    CentStr = 'centrosymmetric'
298    if not SGData['SGInv']:
299        CentStr = 'non'+CentStr
300    if SGData['SGLatt'] in 'ABCIFR':
301        SGText.append(' The lattice is '+CentStr+' '+SGData['SGLatt']+'-centered '+SGData['SGSys'].lower())
302    else:
303        SGText.append(' The lattice is '+CentStr+' '+'primitive '+SGData['SGSys'].lower()) 
304    SGText.append(' The Laue symmetry is '+SGData['SGLaue'])
305    if 'SGPtGrp' in SGData:         #patch
306        SGText.append(' The lattice point group is '+SGData['SGPtGrp'])
307    SGText.append(' Multiplicity of a general site is '+str(Mult))
308    if SGData['SGUniq'] in ['a','b','c']:
309        SGText.append(' The unique monoclinic axis is '+SGData['SGUniq'])
310    if SGData['SGInv']:
311        SGText.append(' The inversion center is located at 0,0,0')
312    if SGData['SGPolax']:
313        SGText.append(' The location of the origin is arbitrary in '+SGData['SGPolax'])
314    SGText.append(' ')
315    if SGData['SGLatt'] == 'P':
316        SGText.append(' The equivalent positions are:\n')
317    else:   
318        SGText.append(' The equivalent positions are:')
319        SGText.append(' ('+Latt2text(SGData['SGLatt'])+')+\n')
320    SGTable = []
321    for i,Opr in enumerate(SGData['SGOps']):
322        SGTable.append('(%2d) %s'%(i+1,MT2text(Opr)))
323    return SGText,SGTable
324
325def AllOps(SGData):
326    '''
327    Returns a list of all operators for a space group, including those for
328    centering and a center of symmetry
329   
330    :param SGData: from :func:`SpcGroup`
331    :returns: (SGTextList,offsetList,symOpList,G2oprList) where
332
333      * SGTextList: a list of strings with formatted and normalized
334        symmetry operators.
335      * offsetList: a tuple of (dx,dy,dz) offsets that relate the GSAS-II
336        symmetry operation to the operator in SGTextList and symOpList.
337        these dx (etc.) values are added to the GSAS-II generated
338        positions to provide the positions that are generated
339        by the normalized symmetry operators.       
340      * symOpList: a list of tuples with the normalized symmetry
341        operations as (M,T) values
342        (see ``SGOps`` in the :ref:`Space Group object<SGData_table>`)
343      * G2oprList: The GSAS-II operations for each symmetry operation as
344        a tuple with (center,mult,opnum), where center is (0,0,0), (0.5,0,0),
345        (0.5,0.5,0.5),...; where mult is 1 or -1 for the center of symmetry
346        and opnum is the number for the symmetry operation, in ``SGOps``
347        (starting with 0).
348    '''
349    SGTextList = []
350    offsetList = []
351    symOpList = []
352    G2oprList = []
353    onebar = (1,)
354    if SGData['SGInv']:
355        onebar += (-1,)
356    for cen in SGData['SGCen']:
357        for mult in onebar:
358            for j,(M,T) in enumerate(SGData['SGOps']):
359                offset = [0,0,0]
360                Tprime = (mult*T)+cen
361                for i in range(3):
362                    while Tprime[i] < 0:
363                        Tprime[i] += 1
364                        offset[i] += 1
365                    while Tprime[i] >= 1:
366                        Tprime[i] += -1
367                        offset[i] += -1
368                Opr = [mult*M,Tprime]
369                OPtxt = MT2text(Opr)
370                SGTextList.append(OPtxt.replace(' ',''))
371                offsetList.append(tuple(offset))
372                symOpList.append((mult*M,Tprime))
373                G2oprList.append((cen,mult,j))
374    return SGTextList,offsetList,symOpList,G2oprList
375   
376def MT2text(Opr):
377    "From space group matrix/translation operator returns text version"
378    XYZ = ('-Z','-Y','-X','X-Y','ERR','Y-X','X','Y','Z')
379    TRA = ('   ','ERR','1/6','1/4','1/3','ERR','1/2','ERR','2/3','3/4','5/6','ERR')
380    Fld = ''
381    M,T = Opr
382    for j in range(3):
383        IJ = int(round(2*M[j][0]+3*M[j][1]+4*M[j][2]+4))%12
384        IK = int(round(T[j]*12))%12
385        if IK:
386            if IJ < 3:
387                Fld += (TRA[IK]+XYZ[IJ]).rjust(5)
388            else:
389                Fld += (TRA[IK]+'+'+XYZ[IJ]).rjust(5)
390        else:
391            Fld += XYZ[IJ].rjust(5)
392        if j != 2: Fld += ', '
393    return Fld
394   
395def Latt2text(Latt):
396    "From lattice type ('P',A', etc.) returns ';' delimited cell centering vectors"
397    lattTxt = {'A':'0,0,0; 0,1/2,1/2','B':'0,0,0; 1/2,0,1/2',
398        'C':'0,0,0; 1/2,1/2,0','I':'0,0,0; 1/2,1/2,1/2',
399        'F':'0,0,0; 0,1/2,1/2; 1/2,0,1/2; 1/2,1/2,0',
400        'R':'0,0,0; 1/3,2/3,2/3; 2/3,1/3,1/3','P':'0,0,0'}
401    return lattTxt[Latt]   
402       
403def SpaceGroup(SGSymbol):
404    '''
405    Print the output of SpcGroup in a nicely formatted way.
406
407    :param SGSymbol: space group symbol (string) with spaces between axial fields
408    :returns: nothing
409    '''
410    E,A = SpcGroup(SGSymbol)
411    if E > 0:
412        print SGErrors(E)
413        return
414    for l in SGPrint(A):
415        print l
416       
417################################################################################
418#### Superspace group codes
419################################################################################
420       
421def SSpcGroup(SGData,SSymbol):
422    """
423    Determines supersymmetry information from superspace group name; currently only for (3+1) superlattices
424
425    :param SGData: space group data structure as defined in SpcGroup above (see :ref:`SGData<SGData_table>`).
426    :param SSymbol: superspace group symbol extension (string) defining modulation direction & generator info.
427    :returns: (SSGError,SSGData)
428   
429       * SGError = 0 for no errors; >0 for errors (see SGErrors below for details)
430       * SSGData - is a dict (see :ref:`Superspace Group object<SSGData_table>`) with entries:
431       
432             * 'SSpGrp': superspace group symbol extension to space group symbol, accidental spaces removed
433             * 'SSGCen': 4D cell centering vectors [0,0,0,0] at least
434             * 'SSGOps': 4D symmetry operations as [M,T] so that M*x+T = x'
435
436    """
437   
438    def checkModSym():
439        '''
440        Checks to see if proposed modulation form is allowed for Laue group
441        '''
442        if LaueId in [0,] and LaueModId in [0,]:
443            return True
444        elif LaueId in [1,]:
445            try:
446                if modsym.index('1/2') != ['A','B','C'].index(SGData['SGLatt']):
447                    return False
448                if 'I'.index(SGData['SGLatt']) and modsym.count('1/2') not in [0,2]:
449                    return False
450            except ValueError:
451                pass
452            if SGData['SGUniq'] == 'a' and LaueModId in [5,6,7,8,9,10,]:
453                return True
454            elif SGData['SGUniq'] == 'b' and LaueModId in [3,4,13,14,15,16,]:
455                return True
456            elif SGData['SGUniq'] == 'c' and LaueModId in [1,2,19,20,21,22,]:
457                return True
458        elif LaueId in [2,] and LaueModId in [i+7 for i in range(18)]:
459            try:
460                if modsym.index('1/2') != ['A','B','C'].index(SGData['SGLatt']):
461                    return False
462                if SGData['SGLatt'] in ['I','F',] and modsym.index('1/2'):
463                    return False
464            except ValueError:
465                pass
466            return True
467        elif LaueId in [3,4,] and LaueModId in [19,22,]:
468            try:
469                if SGData['SGLatt'] == 'I' and modsym.count('1/2'):
470                    return False
471            except ValueError:
472                pass
473            return True
474        elif LaueId in [7,8,9,] and LaueModId in [19,25,]:
475            if (SGData['SGLatt'] == 'R' or SGData['SGPtGrp'] in ['3m1','-3m1']) and modsym.count('1/3'):
476                return False
477            return True
478        elif LaueId in [10,11,] and LaueModId in [19,]:
479            return True
480        return False
481       
482    def fixMonoOrtho():
483        mod = ''.join(modsym).replace('1/2','0').replace('1','0')
484        if SGData['SGPtGrp'] in ['2','m']:  #OK
485            if mod in ['a00','0b0','00g']:
486                result = [i*-1 for i in SGData['SSGKl']]
487            else:
488                result = SGData['SSGKl'][:]
489            if '/' in mod:
490                return [i*-1 for i in result]
491            else:
492                return result
493        elif SGData['SGPtGrp'] == '2/m':    #OK
494            if mod in ['a00','0b0','00g']:
495                result =  SGData['SSGKl'][:]
496            else:
497                result = [i*-1 for i in SGData['SSGKl']]
498            if '/' in mod:
499                return [i*-1 for i in result]
500            else:
501                return result
502        else:   #orthorhombic
503            return [-SSGKl[i] if mod[i] in ['a','b','g'] else SSGKl[i] for i in range(3)]
504               
505    def extendSSGOps(SSGOps):
506        nOps = len(SSGOps)
507        for OpA in SSGOps:
508            OpAtxt = SSMT2text(OpA)
509            if 't' not in OpAtxt:
510                continue
511            for OpB in SSGOps:
512                OpBtxt = SSMT2text(OpB)
513                if 't' not in OpBtxt:
514                    continue
515                OpC = list(SGProd(OpB,OpA))
516                OpC[1] %= 1.
517                OpCtxt = SSMT2text(OpC)
518#                print OpAtxt.replace(' ','')+' * '+OpBtxt.replace(' ','')+' = '+OpCtxt.replace(' ','')
519                for k,OpD in enumerate(SSGOps):
520                    OpDtxt = SSMT2text(OpD)
521                    if 't' in OpDtxt:
522                        continue
523#                    print '    ('+OpCtxt.replace(' ','')+' = ? '+OpDtxt.replace(' ','')+')'
524                    if OpCtxt == OpDtxt:
525                        continue
526                    elif OpCtxt.split(',')[:3] == OpDtxt.split(',')[:3]:
527                        if 't' not in OpDtxt:
528                            SSGOps[k] = OpC
529#                            print k,'   new:',OpCtxt.replace(' ','')
530                            break
531                        else:
532                            OpCtxt = OpCtxt.replace(' ','')
533                            OpDtxt = OpDtxt.replace(' ','')
534                            Txt = OpCtxt+' conflict with '+OpDtxt
535                            print Txt
536                            return False,Txt
537        return True,SSGOps
538       
539    def findMod(modSym):
540        for a in ['a','b','g']:
541            if a in modSym:
542                return a
543               
544    def genSSGOps():
545        SSGOps = SSGData['SSGOps'][:]
546        iFrac = {}
547        for i,frac in enumerate(SSGData['modSymb']):
548            if frac in ['1/2','1/3','1/4','1/6','1']:
549                iFrac[i] = frac+'.'
550#        print SGData['SpGrp']+SSymbol
551#        print 'SSGKl',SSGKl,'genQ',genQ,'iFrac',iFrac,'modSymb',SSGData['modSymb']
552# set identity & 1,-1; triclinic
553        SSGOps[0][0][3,3] = 1.
554## expand if centrosymmetric
555#        if SGData['SGInv']:
556#            SSGOps += [[-1*M,V] for M,V in SSGOps[:]]
557# monoclinic - all done & all checked
558        if SGData['SGPtGrp'] in ['2','m']:  #OK
559            SSGOps[1][0][3,3] = SSGKl[0]
560            SSGOps[1][1][3] = genQ[0]
561            for i in iFrac:
562                SSGOps[1][0][3,i] = -SSGKl[0]
563        elif SGData['SGPtGrp'] == '2/m':    #OK
564            SSGOps[1][0][3,3] = SSGKl[1]
565            if gensym:
566                SSGOps[1][1][3] = 0.5
567            for i in iFrac:
568                SSGOps[1][0][3,i] = SSGKl[0]
569           
570# orthorhombic - all OK not fully checked
571        elif SGData['SGPtGrp'] in ['222','mm2','m2m','2mm']:    #OK
572            if SGData['SGPtGrp'] == '222':
573                OrOps = {'g':{0:[1,3],1:[2,3]},'a':{1:[1,2],2:[1,3]},'b':{2:[3,2],0:[1,2]}} #OK
574            elif SGData['SGPtGrp'] == 'mm2':
575                OrOps = {'g':{0:[1,3],1:[2,3]},'a':{1:[2,1],2:[3,1]},'b':{0:[1,2],2:[3,2]}} #OK
576            elif SGData['SGPtGrp'] == 'm2m':
577                OrOps = {'b':{0:[1,2],2:[3,2]},'g':{0:[1,3],1:[2,3]},'a':{1:[2,1],2:[3,1]}} #OK
578            elif SGData['SGPtGrp'] == '2mm':
579                OrOps = {'a':{1:[2,1],2:[3,1]},'b':{0:[1,2],2:[3,2]},'g':{0:[1,3],1:[2,3]}} #OK
580            a = findMod(SSGData['modSymb'])
581            OrFrac = OrOps[a]
582            for j in iFrac:
583                for i in OrFrac[j]:
584                    SSGOps[i][0][3,j] = -2.*eval(iFrac[j])*SSGKl[i-1]
585            for i in [0,1,2]:
586                SSGOps[i+1][0][3,3] = SSGKl[i]
587                SSGOps[i+1][1][3] = genQ[i]
588                E,SSGOps = extendSSGOps(SSGOps)
589                if not E:
590                    return E,SSGOps
591        elif SGData['SGPtGrp'] == 'mmm':    #OK
592            OrOps = {'g':{0:[1,3],1:[2,3]},'a':{1:[2,1],2:[3,1]},'b':{0:[1,2],2:[3,2]}} 
593            a = findMod(SSGData['modSymb'])
594            if a == 'g':
595                SSkl = [1,1,1]
596            elif a == 'a':
597                SSkl = [-1,1,-1]
598            else:
599                SSkl = [1,-1,-1]
600            OrFrac = OrOps[a]
601            for j in iFrac:
602                for i in OrFrac[j]:
603                    SSGOps[i][0][3,j] = -2.*eval(iFrac[j])*SSkl[i-1]
604            for i in [0,1,2]:
605                SSGOps[i+1][0][3,3] = SSkl[i]
606                SSGOps[i+1][1][3] = genQ[i]
607                E,SSGOps = extendSSGOps(SSGOps)
608                if not E:
609                    return E,SSGOps               
610# tetragonal - all done & checked
611        elif SGData['SGPtGrp'] == '4':  #OK
612            SSGOps[1][0][3,3] = SSGKl[0]
613            SSGOps[1][1][3] = genQ[0]
614            if '1/2' in SSGData['modSymb']:
615                SSGOps[1][0][3,1] = -1
616        elif SGData['SGPtGrp'] == '-4': #OK
617            SSGOps[1][0][3,3] = SSGKl[0]
618            if '1/2' in SSGData['modSymb']:
619                SSGOps[1][0][3,1] = 1
620        elif SGData['SGPtGrp'] in ['4/m',]: #OK
621            if '1/2' in SSGData['modSymb']:
622                SSGOps[1][0][3,1] = -SSGKl[0]
623            for i,j in enumerate([1,3]):
624                SSGOps[j][0][3,3] = 1
625                if genQ[i]:
626                    SSGOps[j][1][3] = genQ[i]
627                E,SSGOps = extendSSGOps(SSGOps)
628                if not E:
629                    return E,SSGOps
630        elif SGData['SGPtGrp'] in ['422','4mm','-42m','-4m2',]: #OK
631            iGens = [1,4,5]
632            if SGData['SGPtGrp'] in ['4mm','-4m2',]:
633                iGens = [1,6,7]
634            for i,j in enumerate(iGens):
635                if '1/2' in SSGData['modSymb'] and i < 2:
636                    SSGOps[j][0][3,1] = SSGKl[i]
637                SSGOps[j][0][3,3] = SSGKl[i]
638                if genQ[i]:
639                    if 's' in gensym and j == 6:
640                        SSGOps[j][1][3] = -genQ[i]
641                    else:
642                        SSGOps[j][1][3] = genQ[i]
643                E,SSGOps = extendSSGOps(SSGOps)
644                if not E:
645                    return E,SSGOps
646        elif SGData['SGPtGrp'] in ['4/mmm',]:#OK
647            if '1/2' in SSGData['modSymb']:
648                SSGOps[1][0][3,1] = -SSGKl[0]
649                SSGOps[6][0][3,1] = SSGKl[1]
650                if modsym:
651                   SSGOps[1][1][3]  = -genQ[3]
652            for i,j in enumerate([1,2,6,7]):
653                SSGOps[j][0][3,3] = 1
654                SSGOps[j][1][3] = genQ[i]
655                E,Result = extendSSGOps(SSGOps)
656                if not E:
657                    return E,Result
658                else:
659                    SSGOps = Result
660               
661# trigonal - all done & checked
662        elif SGData['SGPtGrp'] == '3':  #OK
663            SSGOps[1][0][3,3] = SSGKl[0]
664            if '1/3' in SSGData['modSymb']:
665                SSGOps[1][0][3,1] = -1
666            SSGOps[1][1][3] = genQ[0]
667        elif SGData['SGPtGrp'] == '-3': #OK
668            SSGOps[1][0][3,3] = -SSGKl[0]
669            if '1/3' in SSGData['modSymb']:
670                SSGOps[1][0][3,1] = -1
671            SSGOps[1][1][3] = genQ[0]
672        elif SGData['SGPtGrp'] in ['312','3m','-3m','-3m1','3m1']:   #OK
673            if '1/3' in SSGData['modSymb']:
674                SSGOps[1][0][3,1] = -1
675            for i,j in enumerate([1,5]):
676                if SGData['SGPtGrp'] in ['3m','-3m']:
677                    SSGOps[j][0][3,3] = 1
678                else:                   
679                    SSGOps[j][0][3,3] = SSGKl[i+1]
680                if genQ[i]:
681                    SSGOps[j][1][3] = genQ[i]
682        elif SGData['SGPtGrp'] in ['321','32']:   #OK
683            for i,j in enumerate([1,4]):
684                SSGOps[j][0][3,3] = SSGKl[i]
685                if genQ[i]:
686                    SSGOps[j][1][3] = genQ[i]
687        elif SGData['SGPtGrp'] in ['31m','-31m']:   #OK
688            ids = [1,3]
689            if SGData['SGPtGrp'] == '-31m':
690                ids = [1,3]
691            if '1/3' in SSGData['modSymb']:
692                SSGOps[ids[0]][0][3,1] = -SSGKl[0]
693            for i,j in enumerate(ids):
694                SSGOps[j][0][3,3] = 1
695                if genQ[i+1]:
696                    SSGOps[j][1][3] = genQ[i+1]
697                     
698# hexagonal all done & checked
699        elif SGData['SGPtGrp'] == '6':  #OK
700            SSGOps[1][0][3,3] = SSGKl[0]
701            SSGOps[1][1][3] = genQ[0]
702        elif SGData['SGPtGrp'] == '-6': #OK
703            SSGOps[1][0][3,3] = SSGKl[0]
704        elif SGData['SGPtGrp'] in ['6/m',]: #OK
705            SSGOps[1][0][3,3] = -SSGKl[1]
706            SSGOps[1][1][3] = genQ[0]
707            SSGOps[2][1][3] = genQ[1]
708        elif SGData['SGPtGrp'] in ['622',]: #OK
709            for i,j in enumerate([1,8,9]):
710                SSGOps[j][0][3,3] = SSGKl[i]
711                if genQ[i]:
712                    SSGOps[j][1][3] = genQ[i]
713                E,SSGOps = extendSSGOps(SSGOps)
714           
715        elif SGData['SGPtGrp'] in ['6mm','-62m','-6m2',]: #OK
716            for i,j in enumerate([1,6,7]):
717                SSGOps[j][0][3,3] = SSGKl[i]
718                if genQ[i]:
719                    SSGOps[j][1][3] = genQ[i]
720                E,SSGOps = extendSSGOps(SSGOps)
721        elif SGData['SGPtGrp'] in ['6/mmm',]: # OK
722            for i,j in enumerate([1,2,10,11]):
723                SSGOps[j][0][3,3] = 1
724                if genQ[i]:
725                    SSGOps[j][1][3] = genQ[i]
726                E,SSGOps = extendSSGOps(SSGOps)
727        elif SGData['SGPtGrp'] in ['1','-1']: #triclinic - done
728            return True,SSGOps
729        E,SSGOps = extendSSGOps(SSGOps)
730        return E,SSGOps
731       
732    def specialGen(gensym,modsym):
733        sym = ''.join(gensym)
734        if SGData['SGPtGrp'] in ['2/m',] and 'n' in SGData['SpGrp']:
735            if 's' in sym:
736                gensym = 'ss'
737        if SGData['SGPtGrp'] in ['-62m',] and sym == '00s':
738            gensym = '0ss'
739        elif SGData['SGPtGrp'] in ['222',]:
740            if sym == '00s':
741                gensym = '0ss'
742            elif sym == '0s0':
743                gensym = 'ss0'
744            elif sym == 's00':
745                gensym = 's0s'
746        elif SGData['SGPtGrp'] in ['mmm',]:
747            if 'g' in modsym:
748                if sym == 's00':
749                    gensym = 's0s'
750                elif sym == '0s0':
751                    gensym = '0ss'
752            elif 'a' in modsym:
753                if sym == '0s0':
754                    gensym = 'ss0'
755                elif sym == '00s':
756                    gensym = 's0s'
757            elif 'b' in modsym:
758                if sym == '00s':
759                    gensym = '0ss'
760                elif sym == 's00':
761                    gensym = 'ss0'
762        return gensym
763                   
764    def checkGen(gensym):
765        '''
766    GenSymList = ['','s','0s','s0', '00s','0s0','s00','s0s','ss0','0ss','q00','0q0','00q','qq0','q0q', '0qq',
767        'q','qqs','s0s0','00ss','s00s','t','t00','t0','h','h00','000s']
768        '''
769        sym = ''.join(gensym)
770# monoclinic - all done
771        if str(SSGKl) == '[-1]' and sym == 's':
772            return False
773        elif SGData['SGPtGrp'] in ['2/m',]:
774            if str(SSGKl) == '[-1, 1]' and sym == '0s':
775                return False
776            elif str(SSGKl) == '[1, -1]' and sym == 's0':
777                return False
778#orthorhombic - all
779        elif SGData['SGPtGrp'] in ['222',] and sym not in ['','s00','0s0','00s']:
780            return False 
781        elif SGData['SGPtGrp'] in ['2mm','m2m','mm2','mmm'] and sym not in ['',]+GenSymList[4:16]:
782            return False 
783#tetragonal - all done
784        elif SGData['SGPtGrp'] in ['4',] and sym not in ['','s','q']:
785            return False 
786        elif SGData['SGPtGrp'] in ['-4',] and sym not in ['',]:
787            return False             
788        elif SGData['SGPtGrp'] in ['4/m',] and sym not in ['','s0','q0']:
789            return False
790        elif SGData['SGPtGrp'] in ['422',] and sym not in ['','q00','s00']:
791            return False         
792        elif SGData['SGPtGrp'] in ['4mm',] and sym not in ['','ss0','s0s','0ss','00s','qq0','qqs']:
793            return False
794        elif SGData['SGPtGrp'] in ['-4m2',] and sym not in ['','0s0','0q0']:
795            return False
796        elif SGData['SGPtGrp'] in ['-42m',] and sym not in ['','0ss','00q',]:
797            return False
798        elif SGData['SGPtGrp'] in ['4/mmm',] and sym not in ['','s00s','s0s0','00ss','000s',]:
799            return False
800#trigonal/rhombohedral - all done
801        elif SGData['SGPtGrp'] in ['3',] and sym not in ['','t']:
802            return False 
803        elif SGData['SGPtGrp'] in ['-3',] and sym not in ['',]:
804            return False 
805        elif SGData['SGPtGrp'] in ['32',] and sym not in ['','t0']:
806            return False 
807        elif SGData['SGPtGrp'] in ['321','312'] and sym not in ['','t00']:
808            return False 
809        elif SGData['SGPtGrp'] in ['3m','-3m'] and sym not in ['','0s']:
810            return False 
811        elif SGData['SGPtGrp'] in ['3m1','-3m1'] and sym not in ['','0s0']:
812            return False 
813        elif SGData['SGPtGrp'] in ['31m','-31m'] and sym not in ['','00s']:
814            return False 
815#hexagonal - all done
816        elif SGData['SGPtGrp'] in ['6',] and sym not in ['','s','h','t']:
817            return False 
818        elif SGData['SGPtGrp'] in ['-6',] and sym not in ['',]:
819            return False
820        elif SGData['SGPtGrp'] in ['6/m',] and sym not in ['','s0']:
821            return False
822        elif SGData['SGPtGrp'] in ['622',] and sym not in ['','h00','t00','s00']:
823            return False         
824        elif SGData['SGPtGrp'] in ['6mm',] and sym not in ['','ss0','s0s','0ss']:
825            return False
826        elif SGData['SGPtGrp'] in ['-6m2',] and sym not in ['','0s0']:
827            return False
828        elif SGData['SGPtGrp'] in ['-62m',] and sym not in ['','00s']:
829            return False
830        elif SGData['SGPtGrp'] in ['6/mmm',] and sym not in ['','s00s','s0s0','00ss']:
831            return False
832        return True
833       
834    LaueModList = [
835        'abg','ab0','ab1/2','a0g','a1/2g',  '0bg','1/2bg','a00','a01/2','a1/20',
836        'a1/21/2','a01','a10','0b0','0b1/2', '1/2b0','1/2b1/2','0b1','1b0','00g',
837        '01/2g','1/20g','1/21/2g','01g','10g', '1/31/3g']
838    LaueList = ['-1','2/m','mmm','4/m','4/mmm','3R','3mR','3','3m1','31m','6/m','6/mmm','m3','m3m']
839    GenSymList = ['','s','0s','s0', '00s','0s0','s00','s0s','ss0','0ss','q00','0q0','00q','qq0','q0q', '0qq',
840        'q','qqs','s0s0','00ss','s00s','t','t00','t0','h','h00','000s']
841    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.}
842    LaueId = LaueList.index(SGData['SGLaue'])
843    if SGData['SGLaue'] in ['m3','m3m']:
844        return '(3+1) superlattices not defined for cubic space groups',None
845    elif SGData['SGLaue'] in ['3R','3mR']:
846        return '(3+1) superlattices not defined for rhombohedral settings - use hexagonal setting',None
847    try:
848        modsym,gensym = splitSSsym(SSymbol)
849    except ValueError:
850        return 'Error in superspace symbol '+SSymbol,None
851    if ''.join(gensym) not in GenSymList:
852        return 'unknown generator symbol '+''.join(gensym),None
853    try:
854        LaueModId = LaueModList.index(''.join(modsym))
855    except ValueError:
856        return 'Unknown modulation symbol '+''.join(modsym),None
857    if not checkModSym():
858        return 'Modulation '+''.join(modsym)+' not consistent with space group '+SGData['SpGrp'],None
859    modQ = [Fracs[mod] for mod in modsym]
860    SSGKl = SGData['SSGKl'][:]
861    if SGData['SGLaue'] in ['2/m','mmm']:
862        SSGKl = fixMonoOrtho()
863    if len(gensym) and len(gensym) != len(SSGKl):
864        return 'Wrong number of items in generator symbol '+''.join(gensym),None
865    if not checkGen(gensym):
866        return 'Generator '+''.join(gensym)+' not consistent with space group '+SGData['SpGrp'],None
867    gensym = specialGen(gensym,modsym)
868    genQ = [Fracs[mod] for mod in gensym]
869    if not genQ:
870        genQ = [0,0,0,0]
871    SSGData = {'SSpGrp':SGData['SpGrp']+SSymbol,'modQ':modQ,'modSymb':modsym,'SSGKl':SSGKl}
872    SSCen = np.zeros((len(SGData['SGCen']),4))
873    for icen,cen in enumerate(SGData['SGCen']):
874        SSCen[icen,0:3] = cen
875    SSCen[0] = np.zeros(4)
876    SSGData['SSGCen'] = SSCen
877    SSGData['SSGOps'] = []
878    for iop,op in enumerate(SGData['SGOps']):
879        T = np.zeros(4)
880        ssop = np.zeros((4,4))
881        ssop[:3,:3] = op[0]
882        T[:3] = op[1]
883        SSGData['SSGOps'].append([ssop,T])
884    E,Result = genSSGOps()
885    if E:
886        SSGData['SSGOps'] = Result
887        if DEBUG:
888            print 'Super spacegroup operators for '+SSGData['SSpGrp']
889            for Op in Result:
890                print SSMT2text(Op).replace(' ','')
891            if SGData['SGInv']:                                 
892                for Op in Result:
893                    Op = [-Op[0],-Op[1]%1.]
894                    print SSMT2text(Op).replace(' ','')                                 
895        return None,SSGData
896    else:
897        return Result+'\nOperator conflict - incorrect superspace symbol',None
898
899def splitSSsym(SSymbol):
900    '''
901    Splits supersymmetry symbol into two lists of strings
902    '''
903    modsym,gensym = SSymbol.replace(' ','').split(')')
904    nfrac = modsym.count('/')
905    modsym = modsym.lstrip('(')
906    if nfrac == 0:
907        modsym = list(modsym)
908    elif nfrac == 1:
909        pos = modsym.find('/')
910        if pos == 1:
911            modsym = [modsym[:3],modsym[3],modsym[4]]
912        elif pos == 2:
913            modsym = [modsym[0],modsym[1:4],modsym[4]]
914        else:
915            modsym = [modsym[0],modsym[1],modsym[2:]]
916    else:
917        lpos = modsym.find('/')
918        rpos = modsym.rfind('/')
919        if lpos == 1 and rpos == 4:
920            modsym = [modsym[:3],modsym[3:6],modsym[6]]
921        elif lpos == 1 and rpos == 5:
922            modsym = [modsym[:3],modsym[3],modsym[4:]]
923        else:
924            modsym = [modsym[0],modsym[1:4],modsym[4:]]
925    gensym = list(gensym)
926    return modsym,gensym
927       
928def SSGPrint(SGData,SSGData):
929    '''
930    Print the output of SSpcGroup in a nicely formatted way. Used in SSpaceGroup
931
932    :param SGData: space group data structure as defined in SpcGroup above.
933    :param SSGData: from :func:`SSpcGroup`
934    :returns:
935        SSGText - list of strings with the superspace group details
936        SGTable - list of strings for each of the operations
937    '''
938    Mult = len(SSGData['SSGCen'])*len(SSGData['SSGOps'])*(int(SGData['SGInv'])+1)
939    SSGText = []
940    SSGText.append(' Superspace Group: '+SSGData['SSpGrp'])
941    CentStr = 'centrosymmetric'
942    if not SGData['SGInv']:
943        CentStr = 'non'+CentStr
944    if SGData['SGLatt'] in 'ABCIFR':
945        SSGText.append(' The lattice is '+CentStr+' '+SGData['SGLatt']+'-centered '+SGData['SGSys'].lower())
946    else:
947        SSGText.append(' The superlattice is '+CentStr+' '+'primitive '+SGData['SGSys'].lower())       
948    SSGText.append(' The Laue symmetry is '+SGData['SGLaue'])
949    SSGText.append(' The superlattice point group is '+SGData['SGPtGrp']+', '+''.join([str(i) for i in SSGData['SSGKl']]))
950    SSGText.append(' The number of superspace group generators is '+str(len(SGData['SSGKl'])))
951    SSGText.append(' Multiplicity of a general site is '+str(Mult))
952    if SGData['SGUniq'] in ['a','b','c']:
953        SSGText.append(' The unique monoclinic axis is '+SGData['SGUniq'])
954    if SGData['SGInv']:
955        SSGText.append(' The inversion center is located at 0,0,0')
956    if SGData['SGPolax']:
957        SSGText.append(' The location of the origin is arbitrary in '+SGData['SGPolax'])
958    SSGText.append(' ')
959    if len(SSGData['SSGCen']) > 1:
960        SSGText.append(' The equivalent positions are:')
961        SSGText.append(' ('+SSLatt2text(SSGData['SSGCen'])+')+\n')
962    else:
963        SSGText.append(' The equivalent positions are:\n')
964    SSGTable = []
965    for i,Opr in enumerate(SSGData['SSGOps']):
966        SSGTable.append('(%2d) %s'%(i+1,SSMT2text(Opr)))
967    return SSGText,SSGTable
968   
969def SSGModCheck(Vec,modSymb):
970    ''' Checks modulation vector compatibility with supersymmetry space group symbol.
971    Superspace group symbol takes precidence & the vector will be modified accordingly
972    '''
973    Fracs = {'1/2':0.5,'1/3':1./3,'1':1.0,'0':0.,'a':0.,'b':0.,'g':0.}
974    modQ = [Fracs[mod] for mod in modSymb]
975    Vec = [0.1 if (vec == 0.0 and mod in ['a','b','g']) else vec for [vec,mod] in zip(Vec,modSymb)]
976    return [Q if mod not in ['a','b','g'] and vec != Q else vec for [vec,mod,Q] in zip(Vec,modSymb,modQ)],  \
977        [True if mod in ['a','b','g'] else False for mod in modSymb]
978
979def SSMT2text(Opr):
980    "From superspace group matrix/translation operator returns text version"
981    XYZS = ('x','y','z','t')    #Stokes, Campbell & van Smaalen notation
982    TRA = ('   ','ERR','1/6','1/4','1/3','ERR','1/2','ERR','2/3','3/4','5/6','ERR')
983    Fld = ''
984    M,T = Opr
985    for j in range(4):
986        IJ = ''
987        for k in range(4):
988            txt = str(int(round(M[j][k])))
989            txt = txt.replace('1',XYZS[k]).replace('0','')
990            if '2' in txt:
991                txt += XYZS[k]
992            if IJ and M[j][k] > 0:
993                IJ += '+'+txt
994            else:
995                IJ += txt
996        IK = int(round(T[j]*12))%12
997        if IK:
998            if not IJ:
999                break
1000            if IJ[0] == '-':
1001                Fld += (TRA[IK]+IJ).rjust(8)
1002            else:
1003                Fld += (TRA[IK]+'+'+IJ).rjust(8)
1004        else:
1005            Fld += IJ.rjust(8)
1006        if j != 3: Fld += ', '
1007    return Fld
1008   
1009def SSLatt2text(SSGCen):
1010    "Lattice centering vectors to text"
1011    lattTxt = ''
1012    for vec in SSGCen:
1013        lattTxt += ' '
1014        for item in vec:
1015            if int(item*12.):
1016                lattTxt += '1/%d,'%(12/int(item*12))
1017            else:
1018                lattTxt += '0,'
1019        lattTxt = lattTxt.rstrip(',')
1020        lattTxt += ';'
1021    lattTxt = lattTxt.rstrip(';').lstrip(' ')
1022    return lattTxt
1023       
1024def SSpaceGroup(SGSymbol,SSymbol):
1025    '''
1026    Print the output of SSpcGroup in a nicely formatted way.
1027
1028    :param SGSymbol: space group symbol with spaces between axial fields.
1029    :param SSymbol: superspace group symbol extension (string).
1030    :returns: nothing
1031    '''
1032
1033    E,A = SpcGroup(SGSymbol)
1034    if E > 0:
1035        print SGErrors(E)
1036        return
1037    E,B = SSpcGroup(A,SSymbol)   
1038    if E > 0:
1039        print E
1040        return
1041    for l in SSGPrint(B):
1042        print l
1043       
1044def SGProd(OpA,OpB):
1045    '''
1046    Form space group operator product. OpA & OpB are [M,V] pairs;
1047        both must be of same dimension (3 or 4). Returns [M,V] pair
1048    '''
1049    A,U = OpA
1050    B,V = OpB
1051    M = np.inner(B,A.T)
1052    W = np.inner(B,U)+V
1053    return M,W
1054       
1055def MoveToUnitCell(xyz):
1056    '''
1057    Translates a set of coordinates so that all values are >=0 and < 1
1058
1059    :param xyz: a list or numpy array of fractional coordinates
1060    :returns: XYZ - numpy array of new coordinates now 0 or greater and less than 1
1061    '''
1062    XYZ = np.zeros(3)
1063    for i,x in enumerate(xyz):
1064        XYZ[i] = (x-int(x))%1.0
1065    return XYZ
1066       
1067def Opposite(XYZ,toler=0.0002):
1068    '''
1069    Gives opposite corner, edge or face of unit cell for position within tolerance.
1070        Result may be just outside the cell within tolerance
1071
1072    :param XYZ: 0 >= np.array[x,y,z] > 1 as by MoveToUnitCell
1073    :param toler: unit cell fraction tolerance making opposite
1074    :returns:
1075        XYZ: array of opposite positions; always contains XYZ
1076    '''
1077    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]]
1078    TB = np.where(abs(XYZ-1)<toler,-1,0)+np.where(abs(XYZ)<toler,1,0)
1079    perm = TB*perm3
1080    cperm = ['%d%d%d'%(i,j,k) for i,j,k in perm]
1081    D = dict(zip(cperm,perm))
1082    new = []
1083    for key in D:
1084        new.append(np.array(D[key])+np.array(XYZ))
1085    return new
1086       
1087def GenAtom(XYZ,SGData,All=False,Uij=[],Move=True):
1088    '''
1089    Generates the equivalent positions for a specified coordinate and space group
1090
1091    :param XYZ: an array, tuple or list containing 3 elements: x, y & z
1092    :param SGData: from :func:`SpcGroup`
1093    :param All: True return all equivalent positions including duplicates;
1094      False return only unique positions
1095    :param Uij: [U11,U22,U33,U12,U13,U23] or [] if no Uij
1096    :param Move: True move generated atom positions to be inside cell
1097      False do not move atoms       
1098    :return: [[XYZEquiv],Idup,[UijEquiv]]
1099
1100      *  [XYZEquiv] is list of equivalent positions (XYZ is first entry)
1101      *  Idup = [-][C]SS where SS is the symmetry operator number (1-24), C (if not 0,0,0)
1102      * is centering operator number (1-4) and - is for inversion
1103        Cell = unit cell translations needed to put new positions inside cell
1104        [UijEquiv] - equivalent Uij; absent if no Uij given
1105       
1106    '''
1107    XYZEquiv = []
1108    UijEquiv = []
1109    Idup = []
1110    Cell = []
1111    X = np.array(XYZ)
1112    if Move:
1113        X = MoveToUnitCell(X)
1114    for ic,cen in enumerate(SGData['SGCen']):
1115        C = np.array(cen)
1116        for invers in range(int(SGData['SGInv']+1)):
1117            for io,[M,T] in enumerate(SGData['SGOps']):
1118                idup = ((io+1)+100*ic)*(1-2*invers)
1119                XT = np.inner(M,X)+T
1120                if len(Uij):
1121                    U = Uij2U(Uij)
1122                    U = np.inner(M,np.inner(U,M).T)
1123                    newUij = U2Uij(U)
1124                if invers:
1125                    XT = -XT
1126                XT += C
1127                if Move:
1128                    newX = MoveToUnitCell(XT)
1129                else:
1130                    newX = XT
1131                cell = np.asarray(np.rint(newX-XT),dtype=np.int32)
1132                if All:
1133                    if np.allclose(newX,X,atol=0.0002):
1134                        idup = False
1135                else:
1136                    if True in [np.allclose(newX,oldX,atol=0.0002) for oldX in XYZEquiv]:
1137                        idup = False
1138                if All or idup:
1139                    XYZEquiv.append(newX)
1140                    Idup.append(idup)
1141                    Cell.append(cell)
1142                    if len(Uij):
1143                        UijEquiv.append(newUij)                   
1144    if len(Uij):
1145        return zip(XYZEquiv,UijEquiv,Idup,Cell)
1146    else:
1147        return zip(XYZEquiv,Idup,Cell)
1148
1149def GenHKLf(HKL,SGData):
1150    '''
1151    Uses old GSAS Fortran routine genhkl.for
1152
1153    :param HKL:  [h,k,l] must be integral values for genhkl.for to work
1154    :param SGData: space group data obtained from SpcGroup
1155    :returns: iabsnt,mulp,Uniq,phi
1156
1157     *   iabsnt = True if reflection is forbidden by symmetry
1158     *   mulp = reflection multiplicity including Friedel pairs
1159     *   Uniq = numpy array of equivalent hkl in descending order of h,k,l
1160     *   phi = phase offset for each equivalent h,k,l
1161
1162    '''
1163    hklf = list(HKL)+[0,]       #could be numpy array!
1164    Ops = SGData['SGOps']
1165    OpM = np.array([op[0] for op in Ops])
1166    OpT = np.array([op[1] for op in Ops])
1167    Inv = SGData['SGInv']
1168    Cen = np.array([cen for cen in SGData['SGCen']])
1169   
1170    Nuniq,Uniq,iabsnt,mulp = pyspg.genhklpy(hklf,len(Ops),OpM,OpT,SGData['SGInv'],len(Cen),Cen)
1171    h,k,l,f = Uniq
1172    Uniq=np.array(zip(h[:Nuniq],k[:Nuniq],l[:Nuniq]))
1173    phi = f[:Nuniq]
1174   
1175    return iabsnt,mulp,Uniq,phi
1176   
1177def checkSSLaue(HKL,SGData,SSGData):
1178    #Laue check here - Toss HKL if outside unique Laue part
1179    h,k,l,m = HKL
1180    if SGData['SGLaue'] == '2/m':
1181        if SGData['SGUniq'] == 'a':
1182            if 'a' in SSGData['modSymb'] and h == 0 and m < 0:
1183                return False
1184            elif 'b' in SSGData['modSymb'] and k == 0 and l ==0 and m < 0:
1185                return False
1186            else:
1187                return True
1188        elif SGData['SGUniq'] == 'b':
1189            if 'b' in SSGData['modSymb'] and k == 0 and m < 0:
1190                return False
1191            elif 'a' in SSGData['modSymb'] and h == 0 and l ==0 and m < 0:
1192                return False
1193            else:
1194                return True
1195        elif SGData['SGUniq'] == 'c':
1196            if 'g' in SSGData['modSymb'] and l == 0 and m < 0:
1197                return False
1198            elif 'a' in SSGData['modSymb'] and h == 0 and k ==0 and m < 0:
1199                return False
1200            else:
1201                return True
1202    elif SGData['SGLaue'] == 'mmm':
1203        if 'a' in SSGData['modSymb']:
1204            if h == 0 and m < 0:
1205                return False
1206            else:
1207                return True
1208        elif 'b' in SSGData['modSymb']:
1209            if k == 0 and m < 0:
1210                return False
1211            else:
1212                return True
1213        elif 'g' in SSGData['modSymb']:
1214            if l == 0 and m < 0:
1215                return False
1216            else:
1217                return True
1218    else:   #tetragonal, trigonal, hexagonal (& triclinic?)
1219        if l == 0 and m < 0:
1220            return False
1221        else:
1222            return True
1223       
1224   
1225def checkSSextc(HKL,SSGData):
1226    Ops = SSGData['SSGOps']
1227    OpM = np.array([op[0] for op in Ops])
1228    OpT = np.array([op[1] for op in Ops])
1229    HKLS = np.array([HKL,-HKL])     #Freidel's Law
1230    DHKL = np.reshape(np.inner(HKLS,OpM)-HKL,(-1,4))
1231    PHKL = np.reshape(np.inner(HKLS,OpT),(-1,))
1232    for dhkl,phkl in zip(DHKL,PHKL)[1:]:    #skip identity
1233        if dhkl.any():
1234            continue
1235        else:
1236            if phkl%1.:
1237                return False
1238    return True
1239                                 
1240def GetOprPtrName(key):
1241    'Needs a doc string'
1242    OprPtrName = {
1243        '-6643':[   2,' 1bar ', 1],'6479' :[  10,'  2z  ', 2],'-6479':[   9,'  mz  ', 3],
1244        '6481' :[   7,'  my  ', 4],'-6481':[   6,'  2y  ', 5],'6641' :[   4,'  mx  ', 6],
1245        '-6641':[   3,'  2x  ', 7],'6591' :[  28,' m+-0 ', 8],'-6591':[  27,' 2+-0 ', 9],
1246        '6531' :[  25,' m110 ',10],'-6531':[  24,' 2110 ',11],'6537' :[  61,'  4z  ',12],
1247        '-6537':[  62,' -4z  ',13],'975'  :[  68,' 3+++1',14],'6456' :[ 114,'  3z1 ',15],
1248        '-489' :[  73,' 3+-- ',16],'483'  :[  78,' 3-+- ',17],'-969' :[  83,' 3--+ ',18],
1249        '819'  :[  22,' m+0- ',19],'-819' :[  21,' 2+0- ',20],'2431' :[  16,' m0+- ',21],
1250        '-2431':[  15,' 20+- ',22],'-657' :[  19,' m101 ',23],'657'  :[  18,' 2101 ',24],
1251        '1943' :[  48,' -4x  ',25],'-1943':[  47,'  4x  ',26],'-2429':[  13,' m011 ',27],
1252        '2429' :[  12,' 2011 ',28],'639'  :[  55,' -4y  ',29],'-639' :[  54,'  4y  ',30],
1253        '-6484':[ 146,' 2010 ', 4],'6484' :[ 139,' m010 ', 5],'-6668':[ 145,' 2100 ', 6],
1254        '6668' :[ 138,' m100 ', 7],'-6454':[ 148,' 2120 ',18],'6454' :[ 141,' m120 ',19],
1255        '-6638':[ 149,' 2210 ',20],'6638' :[ 142,' m210 ',21],              #search ends here
1256        '2223' :[  68,' 3+++2',39],
1257        '6538' :[ 106,'  6z1 ',40],'-2169':[  83,' 3--+2',41],'2151' :[  73,' 3+--2',42],
1258        '2205' :[  79,'-3-+-2',43],'-2205':[  78,' 3-+-2',44],'489'  :[  74,'-3+--1',45],
1259        '801'  :[  53,'  4y1 ',46],'1945' :[  47,'  4x3 ',47],'-6585':[  62,' -4z3 ',48],
1260        '6585' :[  61,'  4z3 ',49],'6584' :[ 114,'  3z2 ',50],'6666' :[ 106,'  6z5 ',51],
1261        '6643' :[   1,' Iden ',52],'-801' :[  55,' -4y1 ',53],'-1945':[  48,' -4x3 ',54],
1262        '-6666':[ 105,' -6z5 ',55],'-6538':[ 105,' -6z1 ',56],'-2223':[  69,'-3+++2',57],
1263        '-975' :[  69,'-3+++1',58],'-6456':[ 113,' -3z1 ',59],'-483' :[  79,'-3-+-1',60],
1264        '969'  :[  84,'-3--+1',61],'-6584':[ 113,' -3z2 ',62],'2169' :[  84,'-3--+2',63],
1265        '-2151':[  74,'-3+--2',64],'0':[0,' ????',0]
1266        }
1267    return OprPtrName[key]
1268
1269def GetKNsym(key):
1270    'Needs a doc string'
1271    KNsym = {
1272        '0'         :'    1   ','1'         :'   -1   ','64'        :'    2(x)','32'        :'    m(x)',
1273        '97'        :'  2/m(x)','16'        :'    2(y)','8'         :'    m(y)','25'        :'  2/m(y)',
1274        '2'         :'    2(z)','4'         :'    m(z)','7'         :'  2/m(z)','134217728' :'   2(yz)',
1275        '67108864'  :'   m(yz)','201326593' :' 2/m(yz)','2097152'   :'  2(0+-)','1048576'   :'  m(0+-)',
1276        '3145729'   :'2/m(0+-)','8388608'   :'   2(xz)','4194304'   :'   m(xz)','12582913'  :' 2/m(xz)',
1277        '524288'    :'  2(+0-)','262144'    :'  m(+0-)','796433'    :'2/m(+0-)','1024'      :'   2(xy)',
1278        '512'       :'   m(xy)','1537'      :' 2/m(xy)','256'       :'  2(+-0)','128'       :'  m(+-0)',
1279        '385'       :'2/m(+-0)','76'        :'  mm2(x)','52'        :'  mm2(y)','42'        :'  mm2(z)',
1280        '135266336' :' mm2(yz)','69206048'  :'mm2(0+-)','8650760'   :' mm2(xz)','4718600'   :'mm2(+0-)',
1281        '1156'      :' mm2(xy)','772'       :'mm2(+-0)','82'        :'  222   ','136314944' :'  222(x)',
1282        '8912912'   :'  222(y)','1282'      :'  222(z)','127'       :'  mmm   ','204472417' :'  mmm(x)',
1283        '13369369'  :'  mmm(y)','1927'      :'  mmm(z)','33554496'  :'  4(100)','16777280'  :' -4(100)',
1284        '50331745'  :'4/m(100)','169869394' :'422(100)','84934738'  :'-42m 100','101711948' :'4mm(100)',
1285        '254804095' :'4/mmm100','536870928 ':'  4(010)','268435472' :' -4(010)','805306393' :'4/m (10)',
1286        '545783890' :'422(010)','272891986' :'-42m 010','541327412' :'4mm(010)','818675839' :'4/mmm010',
1287        '2050'      :'  4(001)','4098'      :' -4(001)','6151'      :'4/m(001)','3410'      :'422(001)',
1288        '4818'      :'-42m 001','2730'      :'4mm(001)','8191'      :'4/mmm001','8192'      :'  3(111)',
1289        '8193'      :' -3(111)','2629888'   :' 32(111)','1319040'   :' 3m(111)','3940737'   :'-3m(111)',
1290        '32768'     :'  3(+--)','32769'     :' -3(+--)','10519552'  :' 32(+--)','5276160'   :' 3m(+--)',
1291        '15762945'  :'-3m(+--)','65536'     :'  3(-+-)','65537'     :' -3(-+-)','134808576' :' 32(-+-)',
1292        '67437056'  :' 3m(-+-)','202180097' :'-3m(-+-)','131072'    :'  3(--+)','131073'    :' -3(--+)',
1293        '142737664' :' 32(--+)','71434368'  :' 3m(--+)','214040961' :'-3m(--+)','237650'    :'   23   ',
1294        '237695'    :'   m3   ','715894098' :'   432  ','358068946' :'  -43m  ','1073725439':'   m3m  ',
1295        '68157504'  :' mm2d100','4456464'   :' mm2d010','642'       :' mm2d001','153092172' :'-4m2 100',
1296        '277348404' :'-4m2 010','5418'      :'-4m2 001','1075726335':'  6/mmm ','1074414420':'-6m2 100',
1297        '1075070124':'-6m2 120','1075069650':'   6mm  ','1074414890':'   622  ','1073758215':'   6/m  ',
1298        '1073758212':'   -6   ','1073758210':'    6   ','1073759865':'-3m(100)','1075724673':'-3m(120)',
1299        '1073758800':' 3m(100)','1075069056':' 3m(120)','1073759272':' 32(100)','1074413824':' 32(120)',
1300        '1073758209':'   -3   ','1073758208':'    3   ','1074135143':'mmm(100)','1075314719':'mmm(010)',
1301        '1073743751':'mmm(110)','1074004034':' mm2z100','1074790418':' mm2z010','1073742466':' mm2z110',
1302        '1074004004':'mm2(100)','1074790412':'mm2(010)','1073742980':'mm2(110)','1073872964':'mm2(120)',
1303        '1074266132':'mm2(210)','1073742596':'mm2(+-0)','1073872930':'222(100)','1074266122':'222(010)',
1304        '1073743106':'222(110)','1073741831':'2/m(001)','1073741921':'2/m(100)','1073741849':'2/m(010)',
1305        '1073743361':'2/m(110)','1074135041':'2/m(120)','1075314689':'2/m(210)','1073742209':'2/m(+-0)',
1306        '1073741828':' m(001) ','1073741888':' m(100) ','1073741840':' m(010) ','1073742336':' m(110) ',
1307        '1074003968':' m(120) ','1074790400':' m(210) ','1073741952':' m(+-0) ','1073741826':' 2(001) ',
1308        '1073741856':' 2(100) ','1073741832':' 2(010) ','1073742848':' 2(110) ','1073872896':' 2(120) ',
1309        '1074266112':' 2(210) ','1073742080':' 2(+-0) ','1073741825':'   -1   '
1310        }
1311    return KNsym[key]       
1312
1313def GetNXUPQsym(siteSym):
1314    '''       
1315    The codes XUPQ are for lookup of symmetry constraints for position(X), thermal parm(U) & magnetic moments
1316    (P&Q-not used in GSAS-II)
1317    '''
1318    NXUPQsym = {
1319        '    1   ':(28,29,28,28),'   -1   ':( 1,29,28, 0),'    2(x)':(12,18,12,25),'    m(x)':(25,18,12,25),
1320        '  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),
1321        '    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),
1322        '   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),
1323        '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),
1324        '  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),
1325        '   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),
1326        '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),
1327        ' mm2(yz)':(10,13, 0,-1),'mm2(0+-)':(11,13, 0,-1),' mm2(xz)':( 8,12, 0,-1),'mm2(+0-)':( 9,12, 0,-1),
1328        ' mm2(xy)':( 6,11, 0,-1),'mm2(+-0)':( 7,11, 0,-1),'  222   ':( 1,10, 0,-1),'  222(x)':( 1,13, 0,-1),
1329        '  222(y)':( 1,12, 0,-1),'  222(z)':( 1,11, 0,-1),'  mmm   ':( 1,10, 0,-1),'  mmm(x)':( 1,13, 0,-1),
1330        '  mmm(y)':( 1,12, 0,-1),'  mmm(z)':( 1,11, 0,-1),'  4(100)':(12, 4,12, 0),' -4(100)':( 1, 4,12, 0),
1331        '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),
1332        '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),
1333        '422(010)':( 1, 3, 0,-1),'-42m 010':( 1, 3, 0,-1),'4mm(010)':(13, 3, 0,-1),'4/mmm010':(1, 3, 0,-1,),
1334        '  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),
1335        '-42m 001':( 1, 2, 0,-1),'4mm(001)':(14, 2, 0,-1),'4/mmm001':( 1, 2, 0,-1),'  3(111)':( 2, 5, 2, 0),
1336        ' -3(111)':( 1, 5, 2, 0),' 32(111)':( 1, 5, 0, 2),' 3m(111)':( 2, 5, 0, 2),'-3m(111)':( 1, 5, 0,-1),
1337        '  3(+--)':( 5, 8, 5, 0),' -3(+--)':( 1, 8, 5, 0),' 32(+--)':( 1, 8, 0, 5),' 3m(+--)':( 5, 8, 0, 5),
1338        '-3m(+--)':( 1, 8, 0,-1),'  3(-+-)':( 4, 7, 4, 0),' -3(-+-)':( 1, 7, 4, 0),' 32(-+-)':( 1, 7, 0, 4),
1339        ' 3m(-+-)':( 4, 7, 0, 4),'-3m(-+-)':( 1, 7, 0,-1),'  3(--+)':( 3, 6, 3, 0),' -3(--+)':( 1, 6, 3, 0),
1340        ' 32(--+)':( 1, 6, 0, 3),' 3m(--+)':( 3, 6, 0, 3),'-3m(--+)':( 1, 6, 0,-1),'   23   ':( 1, 1, 0, 0),
1341        '   m3   ':( 1, 1, 0, 0),'   432  ':( 1, 1, 0, 0),'  -43m  ':( 1, 1, 0, 0),'   m3m  ':( 1, 1, 0, 0),
1342        ' mm2d100':(12,13, 0,-1),' mm2d010':(13,12, 0,-1),' mm2d001':(14,11, 0,-1),'-4m2 100':( 1, 4, 0,-1),
1343        '-4m2 010':( 1, 3, 0,-1),'-4m2 001':( 1, 2, 0,-1),'  6/mmm ':( 1, 9, 0,-1),'-6m2 100':( 1, 9, 0,-1),
1344        '-6m2 120':( 1, 9, 0,-1),'   6mm  ':(14, 9, 0,-1),'   622  ':( 1, 9, 0,-1),'   6/m  ':( 1, 9,14,-1),
1345        '   -6   ':( 1, 9,14, 0),'    6   ':(14, 9,14, 0),'-3m(100)':( 1, 9, 0,-1),'-3m(120)':( 1, 9, 0,-1),
1346        ' 3m(100)':(14, 9, 0,14),' 3m(120)':(14, 9, 0,14),' 32(100)':( 1, 9, 0,14),' 32(120)':( 1, 9, 0,14),
1347        '   -3   ':( 1, 9,14, 0),'    3   ':(14, 9,14, 0),'mmm(100)':( 1,14, 0,-1),'mmm(010)':( 1,15, 0,-1),
1348        'mmm(110)':( 1,11, 0,-1),' mm2z100':(14,14, 0,-1),' mm2z010':(14,15, 0,-1),' mm2z110':(14,11, 0,-1),
1349        'mm2(100)':(12,14, 0,-1),'mm2(010)':(13,15, 0,-1),'mm2(110)':( 6,11, 0,-1),'mm2(120)':(15,14, 0,-1),
1350        'mm2(210)':(16,15, 0,-1),'mm2(+-0)':( 7,11, 0,-1),'222(100)':( 1,14, 0,-1),'222(010)':( 1,15, 0,-1),
1351        '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),
1352        '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),
1353        ' m(001) ':(23,16,14,23),' m(100) ':(26,25,12,26),' m(010) ':(27,28,13,27),' m(110) ':(18,19, 6,18),
1354        ' m(120) ':(24,27,15,24),' m(210) ':(25,26,16,25),' m(+-0) ':(17,20, 7,17),' 2(001) ':(14,16,14,23),
1355        ' 2(100) ':(12,25,12,26),' 2(010) ':(13,28,13,27),' 2(110) ':( 6,19, 6,18),' 2(120) ':(15,27,15,24),
1356        ' 2(210) ':(16,26,16,25),' 2(+-0) ':( 7,20, 7,17),'   -1   ':( 1,29,28, 0)
1357        }
1358    return NXUPQsym[siteSym]
1359
1360def GetCSxinel(siteSym): 
1361    'Needs a doc string'
1362    CSxinel = [[],                         # 0th empty - indices are Fortran style
1363        [[0,0,0],[ 0.0, 0.0, 0.0]],      #1  0  0  0
1364        [[1,1,1],[ 1.0, 1.0, 1.0]],      #2  X  X  X
1365        [[1,1,1],[ 1.0, 1.0,-1.0]],      #3  X  X -X
1366        [[1,1,1],[ 1.0,-1.0, 1.0]],      #4  X -X  X
1367        [[1,1,1],[ 1.0,-1.0,-1.0]],      #5 -X  X  X
1368        [[1,1,0],[ 1.0, 1.0, 0.0]],      #6  X  X  0
1369        [[1,1,0],[ 1.0,-1.0, 0.0]],      #7  X -X  0
1370        [[1,0,1],[ 1.0, 0.0, 1.0]],      #8  X  0  X
1371        [[1,0,1],[ 1.0, 0.0,-1.0]],      #9  X  0 -X
1372        [[0,1,1],[ 0.0, 1.0, 1.0]],      #10  0  Y  Y
1373        [[0,1,1],[ 0.0, 1.0,-1.0]],      #11 0  Y -Y
1374        [[1,0,0],[ 1.0, 0.0, 0.0]],      #12  X  0  0
1375        [[0,1,0],[ 0.0, 1.0, 0.0]],      #13  0  Y  0
1376        [[0,0,1],[ 0.0, 0.0, 1.0]],      #14  0  0  Z
1377        [[1,1,0],[ 1.0, 2.0, 0.0]],      #15  X 2X  0
1378        [[1,1,0],[ 2.0, 1.0, 0.0]],      #16 2X  X  0
1379        [[1,1,2],[ 1.0, 1.0, 1.0]],      #17  X  X  Z
1380        [[1,1,2],[ 1.0,-1.0, 1.0]],      #18  X -X  Z
1381        [[1,2,1],[ 1.0, 1.0, 1.0]],      #19  X  Y  X
1382        [[1,2,1],[ 1.0, 1.0,-1.0]],      #20  X  Y -X
1383        [[1,2,2],[ 1.0, 1.0, 1.0]],      #21  X  Y  Y
1384        [[1,2,2],[ 1.0, 1.0,-1.0]],      #22  X  Y -Y
1385        [[1,2,0],[ 1.0, 1.0, 0.0]],      #23  X  Y  0
1386        [[1,0,2],[ 1.0, 0.0, 1.0]],      #24  X  0  Z
1387        [[0,1,2],[ 0.0, 1.0, 1.0]],      #25  0  Y  Z
1388        [[1,1,2],[ 1.0, 2.0, 1.0]],      #26  X 2X  Z
1389        [[1,1,2],[ 2.0, 1.0, 1.0]],      #27 2X  X  Z
1390        [[1,2,3],[ 1.0, 1.0, 1.0]],      #28  X  Y  Z
1391        ]
1392    indx = GetNXUPQsym(siteSym)
1393    return CSxinel[indx[0]]
1394   
1395def GetCSuinel(siteSym):
1396    "returns Uij terms, multipliers, GUI flags & Uiso2Uij multipliers"
1397    CSuinel = [[],                                             # 0th empty - indices are Fortran style
1398        [[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
1399        [[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
1400        [[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
1401        [[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
1402        [[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
1403        [[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
1404        [[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
1405        [[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
1406        [[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
1407        [[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
1408        [[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
1409        [[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
1410        [[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
1411        [[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
1412        [[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
1413        [[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
1414        [[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
1415        [[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
1416        [[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
1417        [[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
1418        [[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
1419        [[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
1420        [[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
1421        [[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
1422        [[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
1423        [[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
1424        [[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
1425        [[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
1426        [[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
1427        ]
1428    indx = GetNXUPQsym(siteSym)
1429    return CSuinel[indx[1]]
1430   
1431def GetSSfxuinel(waveType,nH,XYZ,SGData,SSGData,debug=False):
1432   
1433    def orderParms(CSI):
1434        parms = [0,]
1435        for csi in CSI:
1436            for i in [0,1,2]:
1437                if csi[i] not in parms:
1438                    parms.append(csi[i])
1439        for csi in CSI:
1440            for i in [0,1,2]:
1441                csi[i] = parms.index(csi[i])
1442        return CSI
1443   
1444    def fracCrenel(tau,Toff,Twid):
1445        Tau = (tau-Toff)%1.
1446        A = np.where(Tau<Twid,1.,0.)
1447        return A
1448       
1449    def fracFourier(tau,nH,fsin,fcos):
1450        SA = np.sin(2.*nH*np.pi*tau)
1451        CB = np.cos(2.*nH*np.pi*tau)
1452        A = SA[np.newaxis,np.newaxis,:]*fsin[:,:,np.newaxis]
1453        B = CB[np.newaxis,np.newaxis,:]*fcos[:,:,np.newaxis]
1454        return A+B
1455       
1456    def posFourier(tau,nH,psin,pcos):
1457        SA = np.sin(2*nH*np.pi*tau)
1458        CB = np.cos(2*nH*np.pi*tau)
1459        A = SA[np.newaxis,np.newaxis,:]*psin[:,:,np.newaxis]
1460        B = CB[np.newaxis,np.newaxis,:]*pcos[:,:,np.newaxis]
1461        return A+B   
1462
1463    def posSawtooth(tau,Toff,slopes):
1464        Tau = (tau-Toff[:,np.newaxis])%1.
1465        A = slopes[:,:,np.newaxis]*Tau
1466        return A
1467   
1468    def posZigZag(tau,Toff,slopes):
1469        Tau = (tau-Toff[:,np.newaxis])%1.
1470        A = np.where(Tau <= 0.5,slopes[:,:,np.newaxis]*Tau,slopes[:,:,np.newaxis]*(1.-Tau))
1471        return A
1472       
1473    print 'super space group: ',SSGData['SSpGrp']
1474    CSI = {'Sfrac':[[[1,0],[2,0]],[[1.,0.],[1.,0.]]],
1475        'Spos':[[[1,0,0],[2,0,0],[3,0,0], [4,0,0],[5,0,0],[6,0,0]],
1476            [[1.,0.,0.],[1.,0.,0.],[1.,0.,0.], [1.,0.,0.],[1.,0.,0.],[1.,0.,0.]]],    #sin & cos
1477        'Sadp':[[[1,0,0],[2,0,0],[3,0,0],[4,0,0],[5,0,0],[6,0,0], 
1478            [7,0,0],[8,0,0],[9,0,0],[10,0,0],[11,0,0],[12,0,0]],
1479            [[1.,0.,0.],[1.,0.,0.],[1.,0.,0.], [1.,0.,0.],[1.,0.,0.],[1.,0.,0.],
1480            [1.,0.,0.],[1.,0.,0.],[1.,0.,0.], [1.,0.,0.],[1.,0.,0.],[1.,0.,0.]]],
1481        'Smag':[[[1,0,0],[2,0,0],[3,0,0], [4,0,0],[5,0,0],[6,0,0]],
1482            [[1.,0.,0.],[1.,0.,0.],[1.,0.,0.], [1.,0.,0.],[1.,0.,0.],[1.,0.,0.]]],}
1483    xyz = np.array(XYZ)%1.
1484    xyzt = np.array(XYZ+[0,])%1.
1485    SGOps = copy.deepcopy(SGData['SGOps'])
1486    siteSym = SytSym(XYZ,SGData)[0].strip()
1487    print 'siteSym: ',siteSym
1488    if siteSym == '1':   #"1" site symmetry
1489        if debug:
1490            return CSI,None,None,None,None
1491        else:
1492            return CSI
1493    elif siteSym == '-1':   #"-1" site symmetry
1494        CSI['Sfrac'][0] = [[1,0],[0,0]]
1495        CSI['Spos'][0] = [[1,0,0],[2,0,0],[3,0,0], [0,0,0],[0,0,0],[0,0,0]]
1496        CSI['Sadp'][0] = [[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0], 
1497        [1,0,0],[2,0,0],[3,0,0],[4,0,0],[5,0,0],[6,0,0]]
1498        if debug:
1499            return CSI,None,None,None,None
1500        else:
1501            return CSI
1502    SSGOps = copy.deepcopy(SSGData['SSGOps'])
1503    #expand ops to include inversions if any
1504    if SGData['SGInv']:
1505        for op,sop in zip(SGData['SGOps'],SSGData['SSGOps']):
1506            SGOps.append([-op[0],-op[1]%1.])
1507            SSGOps.append([-sop[0],-sop[1]%1.])
1508    #build set of sym ops around special poasition       
1509    SSop = []
1510    Sop = []
1511    Sdtau = []
1512    for iop,Op in enumerate(SGOps):         
1513        nxyz = (np.inner(Op[0],xyz)+Op[1])%1.
1514        if np.allclose(xyz,nxyz,1.e-4) and iop and MT2text(Op).replace(' ','') != '-X,-Y,-Z':
1515            SSop.append(SSGOps[iop])
1516            Sop.append(SGOps[iop])
1517            ssopinv = nl.inv(SSGOps[iop][0])
1518            mst = ssopinv[3][:3]
1519            epsinv = ssopinv[3][3]
1520            Sdtau.append(np.sum(mst*(XYZ-SGOps[iop][1])-epsinv*SSGOps[iop][1][3]))
1521    SdIndx = np.argsort(np.array(Sdtau))     # just to do in sensible order
1522    OpText =  [MT2text(s).replace(' ','') for s in Sop]         #debug?
1523    SSOpText = [SSMT2text(ss).replace(' ','') for ss in SSop]   #debug?
1524    print 'special pos super operators: ',SSOpText
1525    #setup displacement arrays
1526    tau = np.linspace(0,1,49,True)
1527    delt2 = np.eye(2)*0.001
1528    delt4 = np.eye(4)*0.001
1529    delt6 = np.eye(6)*0.001
1530    delt12 = np.eye(12)*0.0001
1531    #make modulation arrays - one parameter at a time
1532    #site fractions
1533    CSI['Sfrac'] = [np.zeros((2),dtype='i'),np.ones(2)]
1534    if 'Crenel' in waveType:
1535        dF = fracCrenel(tau,delt2[:1],delt2[1:]).squeeze()
1536    else:
1537        dF = fracFourier(tau,nH,delt2[:1],delt2[1:]).squeeze()
1538    dFT = np.zeros_like(dF)
1539    #positions       
1540    if 'Fourier' in waveType:
1541        dX = posFourier(tau,nH,delt6[:3],delt6[3:]) #+np.array(XYZ)[:,np.newaxis,np.newaxis]
1542          #3x6x12 modulated position array (X,Spos,tau)& force positive
1543        CSI['Spos'] = [np.zeros((6,3),dtype='i'),np.zeros((6,3))]
1544    elif waveType == 'Sawtooth':
1545        CSI['Spos'] = [np.array([[1,],[2,],[3,],[4,]]),np.array([[1.0,],[1.0,],[1.0,],[1.0,]])]
1546    elif waveType == 'ZigZag':
1547        CSI['Spos'] = [np.array([[1,],[2,],[3,],[4,]]),np.array([[1.0,],[1.0,],[1.0,],[1.0,]])]
1548    #anisotropic thermal motion
1549    dU = posFourier(tau,nH,delt12[:6],delt12[6:])                  #Uij modulations - 6x12x12 array
1550    CSI['Sadp'] = [np.zeros((12,3),dtype='i'),np.zeros((12,3))]
1551       
1552    FSC = np.ones(2,dtype='i')
1553    VFSC = np.ones(2)
1554    XSC = np.ones(6,dtype='i')
1555    USC = np.ones(12,dtype='i')
1556    dFTP = []
1557    dXTP = []
1558    dUTP = []
1559    for i in SdIndx:
1560        sop = Sop[i]
1561        ssop = SSop[i]
1562        fsc = np.ones(2,dtype='i')
1563        xsc = np.ones(6,dtype='i')
1564        ssopinv = nl.inv(ssop[0])
1565        mst = ssopinv[3][:3]
1566        epsinv = ssopinv[3][3]
1567        sdet = nl.det(sop[0])
1568        ssdet = nl.det(ssop[0])
1569        dtau = mst*(XYZ-sop[1])-epsinv*ssop[1][3]
1570        dT = 1.0
1571        if np.any(dtau%.5):
1572            dT = np.tan(np.pi*np.sum(dtau%.5))
1573        tauT = np.inner(mst,XYZ-sop[1])+epsinv*(tau-ssop[1][3])
1574        if waveType == 'Fourier':
1575            dXT = posFourier(np.sort(tauT),nH,delt6[:3],delt6[3:])   #+np.array(XYZ)[:,np.newaxis,np.newaxis]
1576        elif waveType == 'Sawtooth':
1577            dXT = posSawtooth(tauT,delt4[0],delt4[1:])+np.array(XYZ)[:,np.newaxis,np.newaxis]
1578        elif waveType == 'ZigZag':
1579            dXT = posZigZag(tauT,delt4[0],delt4[1:])+np.array(XYZ)[:,np.newaxis,np.newaxis]           
1580        dXT = np.inner(sop[0],dXT.T)
1581        dXT = np.swapaxes(dXT,1,2)
1582        dXT[:,:3,:] *= ssdet
1583        dXTP.append(dXT)
1584        if waveType == 'Fourier':
1585            if np.any(dtau%.5) and ('1/2' in SSGData['modSymb'] or '1' in SSGData['modSymb']):
1586                CSI['Spos'] = [[[1,0,0],[2,0,0],[3,0,0], [1,0,0],[2,0,0],[3,0,0]],
1587                    [[1.,0.,0.],[1.,0.,0.],[1.,0.,0.], [1.,0.,0.],[1.,0.,0.],[1.,0.,0.]]]                   
1588                if '(x)' in siteSym:
1589                    CSI['Spos'][1][3:] = [1./dT,0.,0.],[-dT,0.,0.],[-dT,0.,0.]
1590                    if 'm' in siteSym and len(SdIndx) == 1:
1591                        CSI['Spos'][1][3:] = [-dT,0.,0.],[1./dT,0.,0.],[1./dT,0.,0.]
1592                elif '(y)' in siteSym:
1593                    CSI['Spos'][1][3:] = [-dT,0.,0.],[1./dT,0.,0.],[-dT,0.,0.]
1594                    if 'm' in siteSym and len(SdIndx) == 1:
1595                        CSI['Spos'][1][3:] = [1./dT,0.,0.],[-dT,0.,0.],[1./dT,0.,0.]
1596                elif '(z)' in siteSym:
1597                    CSI['Spos'][1][3:] = [-dT,0.,0.],[-dT,0.,0.],[1./dT,0.,0.]
1598                    if 'm' in siteSym and len(SdIndx) == 1:
1599                        CSI['Spos'][1][3:] = [1./dT,0.,0.],[1./dT,0.,0.],[-dT,0.,0.]
1600                elif '(xy)' in siteSym:
1601                    CSI['Spos'][0] = [[1,0,0],[1,0,0],[2,0,0], [1,0,0],[1,0,0],[2,0,0]]
1602                    CSI['Spos'][1][3:] = [[1./dT,0.,0.],[1./dT,0.,0.],[-dT,0.,0.]]
1603                for i in range(3):
1604                    if not XSC[i]:
1605                        CSI['Spos'][0][i] = [0,0,0]
1606                        CSI['Spos'][1][i] = [0.,0.,0.]
1607                        CSI['Spos'][0][i+3] = [0,0,0]
1608                        CSI['Spos'][1][i+3] = [0.,0.,0.]
1609            elif np.allclose(dX[0,0,:],dXT[0,1,:]*sdet):
1610                if 'xy' in siteSym or '+-0' in siteSym:
1611                    CSI['Spos'][0][3:5] = [[12,0,0],[12,0,0]]
1612                    CSI['Spos'][1][3:5] = [[1.,0,0],[-sdet,0,0]]
1613                    xsc[3:5] = 0
1614            else:
1615                for i in range(3):
1616                    if np.allclose(dX[i,i,:],dXT[i,i,:]*sdet):
1617                        xsc[i] = 1
1618                    else:
1619                        xsc[i] = 0
1620                    if np.allclose(dX[i,i+3,:],dXT[i,i+3,:]):
1621                        xsc[i+3] = 1
1622                    else:
1623                        xsc[i+3] = 0
1624            XSC &= xsc
1625           
1626        fsc = np.ones(2,dtype='i')
1627        if 'Crenel' in waveType:
1628            dFT = fracCrenel(tauT,delt2[:1],delt2[1:]).squeeze()
1629            fsc = [1,1]
1630        else:
1631            dFT = fracFourier(tauT,nH,delt2[:1],delt2[1:]).squeeze()
1632            dFT = nl.det(sop[0])*dFT
1633            dFT = dFT[:,np.argsort(tauT)]
1634            dFT[0] *= ssdet
1635            dFT[1] *= sdet
1636            dFTP.append(dFT)
1637       
1638            if np.any(dtau%.5) and ('1/2' in SSGData['modSymb'] or '1' in SSGData['modSymb']):
1639                fsc = [1,1]
1640                CSI['Sfrac'] = [[[1,0],[1,0]],[[1.,0.],[1/dT,0.]]]
1641                for i in range(2):
1642                    if not FSC[i]:
1643                        CSI['Sfrac'][0][i] = [0,0]
1644                        CSI['Sfrac'][1][i] = [0.,0.]
1645            else:
1646                for i in range(2):
1647                    if np.allclose(dF[i,:],dFT[i,:],atol=1.e-6):
1648                        fsc[i] = 1
1649                    else:
1650                        fsc[i] = 0
1651        FSC &= fsc
1652           
1653        usc = np.ones(12,dtype='i')
1654        dUT = posFourier(tauT,nH,delt12[:6],delt12[6:])                  #Uij modulations - 6x12x49 array
1655        dUijT = np.rollaxis(np.rollaxis(np.array(Uij2U(dUT)),3),3)    #convert dUT to 12x49x3x3
1656        dUijT = np.rollaxis(np.inner(np.inner(sop[0],dUijT),sop[0].T),3)
1657        dUT = np.array(U2Uij(dUijT))
1658        dUT = dUT[:,:,np.argsort(tauT)]
1659        dUTP.append(dUT)
1660        if np.any(dtau%.5) and ('1/2' in SSGData['modSymb'] or '1' in SSGData['modSymb']):
1661            CSI['Sadp'] = [[[1,0,0],[2,0,0],[3,0,0],[4,0,0],[5,0,0],[6,0,0], 
1662            [1,0,0],[2,0,0],[3,0,0],[4,0,0],[5,0,0],[6,0,0]],
1663            [[1.,0.,0.],[1.,0.,0.],[1.,0.,0.], [1.,0.,0.],[1.,0.,0.],[1.,0.,0.],
1664            [1./dT,0.,0.],[1./dT,0.,0.],[1./dT,0.,0.], [1.,0.,0.],[1.,0.,0.],[1.,0.,0.]]]
1665            if 'mm2(x)' in siteSym:
1666                CSI['Sadp'][1][9:] = [0.,0.,0.],[-dT,0.,0.],[0.,0.,0.]
1667                USC = [1,1,1,0,1,0,1,1,1,0,1,0]
1668            elif '(xy)' in siteSym:
1669                CSI['Sadp'][0] = [[1,0,0],[1,0,0],[2,0,0],[3,0,0],[4,0,0],[4,0,0],
1670                    [1,0,0],[1,0,0],[2,0,0],[3,0,0],[4,0,0],[4,0,0]]
1671                CSI['Sadp'][1][9:] = [[1./dT,0.,0.],[-dT,0.,0.],[-dT,0.,0.]]
1672                USC = [1,1,1,1,1,1,1,1,1,1,1,1]                             
1673            elif '(x)' in siteSym:
1674                CSI['Sadp'][1][9:] = [-dT,0.,0.],[-dT,0.,0.],[1./dT,0.,0.]
1675            elif '(y)' in siteSym:
1676                CSI['Sadp'][1][9:] = [-dT,0.,0.],[1./dT,0.,0.],[-dT,0.,0.]
1677            elif '(z)' in siteSym:
1678                CSI['Sadp'][1][9:] = [1./dT,0.,0.],[-dT,0.,0.],[-dT,0.,0.]
1679            for i in range(6):
1680                if not USC[i]:
1681                    CSI['Sadp'][0][i] = [0,0,0]
1682                    CSI['Sadp'][1][i] = [0.,0.,0.]
1683                    CSI['Sadp'][0][i+6] = [0,0,0]
1684                    CSI['Sadp'][1][i+6] = [0.,0.,0.]
1685        else:                       
1686            for i in range(6):
1687                if np.allclose(dU[i,i,:],-dUT[i,i,:]):
1688                    usc[i] = 1
1689                else:
1690                    usc[i] = 0
1691                if np.allclose(dU[i,i+6,:],dUT[i,i+6,:]):
1692                    usc[i+6] = 1
1693                else:
1694                    usc[i+6] = 0
1695            if np.any(dUT[0,1,:]):
1696                if '4/m' in siteSym:
1697                    CSI['Sadp'][0][6:8] = [[12,0,0],[12,0,0]]
1698                    if ssop[1][3]:
1699                        CSI['Sadp'][1][6:8] = [[1.,0.,0.],[-1.,0.,0.]]
1700                        usc[9] = 1
1701                    else:
1702                        CSI['Sadp'][1][6:8] = [[1.,0.,0.],[1.,0.,0.]]
1703                        usc[9] = 0
1704                elif '4' in siteSym:
1705                    CSI['Sadp'][0][6:8] = [[12,0,0],[12,0,0]]
1706                    CSI['Sadp'][0][:2] = [[11,0,0],[11,0,0]]
1707                    if ssop[1][3]:
1708                        CSI['Sadp'][1][:2] = [[1.,0.,0.],[-1.,0.,0.]]
1709                        CSI['Sadp'][1][6:8] = [[1.,0.,0.],[-1.,0.,0.]]
1710                        usc[2] = 0
1711                        usc[8] = 0
1712                        usc[3] = 1
1713                        usc[9] = 1
1714                    else:
1715                        CSI['Sadp'][1][:2] = [[1.,0.,0.],[1.,0.,0.]]
1716                        CSI['Sadp'][1][6:8] = [[1.,0.,0.],[1.,0.,0.]]
1717                        usc[2] = 1
1718                        usc[8] = 1
1719                        usc[3] = 0               
1720                        usc[9] = 0
1721                elif 'xy' in siteSym or '+-0' in siteSym:
1722                    if np.allclose(dU[0,0,:],dUT[0,1,:]*sdet):
1723                        print np.allclose(dU[0,0,:],dUT[0,1,:]*sdet),sdet
1724                        CSI['Sadp'][0][4:6] = [[12,0,0],[12,0,0]]
1725                        CSI['Sadp'][0][6:8] = [[11,0,0],[11,0,0]]
1726                        CSI['Sadp'][1][4:6] = [[1.,0.,0.],[sdet,0.,0.]]
1727                        CSI['Sadp'][1][6:8] = [[1.,0.,0.],[sdet,0.,0.]]
1728                        usc[4:6] = 0
1729                        usc[6:8] = 0
1730                   
1731            print SSMT2text(ssop).replace(' ',''),sdet,ssdet,epsinv,usc
1732        USC &= usc
1733    if not np.any(dtau%.5):
1734        n = -1
1735        for i,U in enumerate(USC):
1736            if U:
1737                n += 1
1738                CSI['Sadp'][0][i][0] = n+1
1739                CSI['Sadp'][1][i][0] = 1.0
1740        if waveType == 'Fourier':
1741            n = -1
1742            for i,X in enumerate(XSC):
1743                if X:
1744                    n += 1
1745                    CSI['Spos'][0][i][0] = n+1
1746                    CSI['Spos'][1][i][0] = 1.0
1747        n = -1
1748        for i,F in enumerate(FSC):
1749            if F:
1750                n += 1
1751                CSI['Sfrac'][0][i] = n+1
1752                CSI['Sfrac'][1][i] = 1.0
1753            else:
1754                CSI['Sfrac'][0][i] = 0
1755                CSI['Sfrac'][1][i] = 0.
1756    CSI['Spos'][0] = orderParms(CSI['Spos'][0])
1757    CSI['Sadp'][0] = orderParms(CSI['Sadp'][0])           
1758    if debug:
1759        return CSI,[tau,tauT],[dF,dFTP],[dX,dXTP],[dU,dUTP]
1760    else:
1761        return CSI
1762   
1763def MustrainNames(SGData):
1764    'Needs a doc string'
1765    laue = SGData['SGLaue']
1766    uniq = SGData['SGUniq']
1767    if laue in ['m3','m3m']:
1768        return ['S400','S220']
1769    elif laue in ['6/m','6/mmm','3m1']:
1770        return ['S400','S004','S202']
1771    elif laue in ['31m','3']:
1772        return ['S400','S004','S202','S211']
1773    elif laue in ['3R','3mR']:
1774        return ['S400','S220','S310','S211']
1775    elif laue in ['4/m','4/mmm']:
1776        return ['S400','S004','S220','S022']
1777    elif laue in ['mmm']:
1778        return ['S400','S040','S004','S220','S202','S022']
1779    elif laue in ['2/m']:
1780        SHKL = ['S400','S040','S004','S220','S202','S022']
1781        if uniq == 'a':
1782            SHKL += ['S013','S031','S211']
1783        elif uniq == 'b':
1784            SHKL += ['S301','S103','S121']
1785        elif uniq == 'c':
1786            SHKL += ['S130','S310','S112']
1787        return SHKL
1788    else:
1789        SHKL = ['S400','S040','S004','S220','S202','S022']
1790        SHKL += ['S310','S103','S031','S130','S301','S013']
1791        SHKL += ['S211','S121','S112']
1792        return SHKL
1793       
1794def HStrainVals(HSvals,SGData):
1795    laue = SGData['SGLaue']
1796    uniq = SGData['SGUniq']
1797    DIJ = np.zeros(6)
1798    if laue in ['m3','m3m']:
1799        DIJ[:3] = [HSvals[0],HSvals[0],HSvals[0]]
1800    elif laue in ['6/m','6/mmm','3m1','31m','3']:
1801        DIJ[:4] = [HSvals[0],HSvals[0],HSvals[1],HSvals[0]]
1802    elif laue in ['3R','3mR']:
1803        DIJ = [HSvals[0],HSvals[0],HSvals[0],HSvals[1],HSvals[1],HSvals[1]]
1804    elif laue in ['4/m','4/mmm']:
1805        DIJ[:3] = [HSvals[0],HSvals[0],HSvals[1]]
1806    elif laue in ['mmm']:
1807        DIJ[:3] = [HSvals[0],HSvals[1],HSvals[2]]
1808    elif laue in ['2/m']:
1809        DIJ[:3] = [HSvals[0],HSvals[1],HSvals[2]]
1810        if uniq == 'a':
1811            DIJ[5] = HSvals[3]
1812        elif uniq == 'b':
1813            DIJ[4] = HSvals[3]
1814        elif uniq == 'c':
1815            DIJ[3] = HSvals[3]
1816    else:
1817        DIJ = [HSvals[0],HSvals[1],HSvals[2],HSvals[3],HSvals[4],HSvals[5]]
1818    return DIJ
1819
1820def HStrainNames(SGData):
1821    'Needs a doc string'
1822    laue = SGData['SGLaue']
1823    uniq = SGData['SGUniq']
1824    if laue in ['m3','m3m']:
1825        return ['D11','eA']         #add cubic strain term
1826    elif laue in ['6/m','6/mmm','3m1','31m','3']:
1827        return ['D11','D33']
1828    elif laue in ['3R','3mR']:
1829        return ['D11','D12']
1830    elif laue in ['4/m','4/mmm']:
1831        return ['D11','D33']
1832    elif laue in ['mmm']:
1833        return ['D11','D22','D33']
1834    elif laue in ['2/m']:
1835        Dij = ['D11','D22','D33']
1836        if uniq == 'a':
1837            Dij += ['D23']
1838        elif uniq == 'b':
1839            Dij += ['D13']
1840        elif uniq == 'c':
1841            Dij += ['D12']
1842        return Dij
1843    else:
1844        Dij = ['D11','D22','D33','D12','D13','D23']
1845        return Dij
1846   
1847def MustrainCoeff(HKL,SGData):
1848    'Needs a doc string'
1849    #NB: order of terms is the same as returned by MustrainNames
1850    laue = SGData['SGLaue']
1851    uniq = SGData['SGUniq']
1852    h,k,l = HKL
1853    Strm = []
1854    if laue in ['m3','m3m']:
1855        Strm.append(h**4+k**4+l**4)
1856        Strm.append(3.0*((h*k)**2+(h*l)**2+(k*l)**2))
1857    elif laue in ['6/m','6/mmm','3m1']:
1858        Strm.append(h**4+k**4+2.0*k*h**3+2.0*h*k**3+3.0*(h*k)**2)
1859        Strm.append(l**4)
1860        Strm.append(3.0*((h*l)**2+(k*l)**2+h*k*l**2))
1861    elif laue in ['31m','3']:
1862        Strm.append(h**4+k**4+2.0*k*h**3+2.0*h*k**3+3.0*(h*k)**2)
1863        Strm.append(l**4)
1864        Strm.append(3.0*((h*l)**2+(k*l)**2+h*k*l**2))
1865        Strm.append(4.0*h*k*l*(h+k))
1866    elif laue in ['3R','3mR']:
1867        Strm.append(h**4+k**4+l**4)
1868        Strm.append(3.0*((h*k)**2+(h*l)**2+(k*l)**2))
1869        Strm.append(2.0*(h*l**3+l*k**3+k*h**3)+2.0*(l*h**3+k*l**3+l*k**3))
1870        Strm.append(4.0*(k*l*h**2+h*l*k**2+h*k*l**2))
1871    elif laue in ['4/m','4/mmm']:
1872        Strm.append(h**4+k**4)
1873        Strm.append(l**4)
1874        Strm.append(3.0*(h*k)**2)
1875        Strm.append(3.0*((h*l)**2+(k*l)**2))
1876    elif laue in ['mmm']:
1877        Strm.append(h**4)
1878        Strm.append(k**4)
1879        Strm.append(l**4)
1880        Strm.append(3.0*(h*k)**2)
1881        Strm.append(3.0*(h*l)**2)
1882        Strm.append(3.0*(k*l)**2)
1883    elif laue in ['2/m']:
1884        Strm.append(h**4)
1885        Strm.append(k**4)
1886        Strm.append(l**4)
1887        Strm.append(3.0*(h*k)**2)
1888        Strm.append(3.0*(h*l)**2)
1889        Strm.append(3.0*(k*l)**2)
1890        if uniq == 'a':
1891            Strm.append(2.0*k*l**3)
1892            Strm.append(2.0*l*k**3)
1893            Strm.append(4.0*k*l*h**2)
1894        elif uniq == 'b':
1895            Strm.append(2.0*l*h**3)
1896            Strm.append(2.0*h*l**3)
1897            Strm.append(4.0*h*l*k**2)
1898        elif uniq == 'c':
1899            Strm.append(2.0*h*k**3)
1900            Strm.append(2.0*k*h**3)
1901            Strm.append(4.0*h*k*l**2)
1902    else:
1903        Strm.append(h**4)
1904        Strm.append(k**4)
1905        Strm.append(l**4)
1906        Strm.append(3.0*(h*k)**2)
1907        Strm.append(3.0*(h*l)**2)
1908        Strm.append(3.0*(k*l)**2)
1909        Strm.append(2.0*k*h**3)
1910        Strm.append(2.0*h*l**3)
1911        Strm.append(2.0*l*k**3)
1912        Strm.append(2.0*h*k**3)
1913        Strm.append(2.0*l*h**3)
1914        Strm.append(2.0*k*l**3)
1915        Strm.append(4.0*k*l*h**2)
1916        Strm.append(4.0*h*l*k**2)
1917        Strm.append(4.0*k*h*l**2)
1918    return Strm
1919   
1920def Muiso2Shkl(muiso,SGData,cell):
1921    "this is to convert isotropic mustrain to generalized Shkls"
1922    import GSASIIlattice as G2lat
1923    A = G2lat.cell2AB(cell)[0]
1924   
1925    def minMus(Shkl,muiso,H,SGData,A):
1926        U = np.inner(A.T,H)
1927        S = np.array(MustrainCoeff(U,SGData))
1928        Sum = np.sqrt(np.sum(np.multiply(S,Shkl[:,np.newaxis]),axis=0))
1929        rad = np.sqrt(np.sum((Sum[:,np.newaxis]*H)**2,axis=1))
1930        return (muiso-rad)**2
1931       
1932    laue = SGData['SGLaue']
1933    PHI = np.linspace(0.,360.,60,True)
1934    PSI = np.linspace(0.,180.,60,True)
1935    X = np.outer(npsind(PHI),npsind(PSI))
1936    Y = np.outer(npcosd(PHI),npsind(PSI))
1937    Z = np.outer(np.ones(np.size(PHI)),npcosd(PSI))
1938    HKL = np.dstack((X,Y,Z))
1939    if laue in ['m3','m3m']:
1940        S0 = [1000.,1000.]
1941    elif laue in ['6/m','6/mmm','3m1']:
1942        S0 = [1000.,1000.,1000.]
1943    elif laue in ['31m','3']:
1944        S0 = [1000.,1000.,1000.,1000.]
1945    elif laue in ['3R','3mR']:
1946        S0 = [1000.,1000.,1000.,1000.]
1947    elif laue in ['4/m','4/mmm']:
1948        S0 = [1000.,1000.,1000.,1000.]
1949    elif laue in ['mmm']:
1950        S0 = [1000.,1000.,1000.,1000.,1000.,1000.]
1951    elif laue in ['2/m']:
1952        S0 = [1000.,1000.,1000.,0.,0.,0.,0.,0.,0.]
1953    else:
1954        S0 = [1000.,1000.,1000.,1000.,1000., 1000.,1000.,1000.,1000.,1000., 
1955            1000.,1000.,0.,0.,0.]
1956    S0 = np.array(S0)
1957    HKL = np.reshape(HKL,(-1,3))
1958    result = so.leastsq(minMus,S0,(np.ones(HKL.shape[0])*muiso,HKL,SGData,A))
1959    return result[0]
1960       
1961def SytSym(XYZ,SGData):
1962    '''
1963    Generates the number of equivalent positions and a site symmetry code for a specified coordinate and space group
1964
1965    :param XYZ: an array, tuple or list containing 3 elements: x, y & z
1966    :param SGData: from SpcGroup
1967    :Returns: a two element tuple:
1968
1969     * The 1st element is a code for the site symmetry (see GetKNsym)
1970     * The 2nd element is the site multiplicity
1971
1972    '''
1973    def PackRot(SGOps):
1974        IRT = []
1975        for ops in SGOps:
1976            M = ops[0]
1977            irt = 0
1978            for j in range(2,-1,-1):
1979                for k in range(2,-1,-1):
1980                    irt *= 3
1981                    irt += M[k][j]
1982            IRT.append(int(irt))
1983        return IRT
1984       
1985    SymName = ''
1986    Mult = 1
1987    Isym = 0
1988    if SGData['SGLaue'] in ['3','3m1','31m','6/m','6/mmm']:
1989        Isym = 1073741824
1990    Jdup = 0
1991    Xeqv = GenAtom(XYZ,SGData,True)
1992    IRT = PackRot(SGData['SGOps'])
1993    L = -1
1994    for ic,cen in enumerate(SGData['SGCen']):
1995        for invers in range(int(SGData['SGInv']+1)):
1996            for io,ops in enumerate(SGData['SGOps']):
1997                irtx = (1-2*invers)*IRT[io]
1998                L += 1
1999                if not Xeqv[L][1]:
2000                    Jdup += 1
2001                    jx = GetOprPtrName(str(irtx))
2002                    if jx[2] < 39:
2003                        Isym += 2**(jx[2]-1)
2004    if Isym == 1073741824: Isym = 0
2005    Mult = len(SGData['SGOps'])*len(SGData['SGCen'])*(int(SGData['SGInv'])+1)/Jdup
2006         
2007    return GetKNsym(str(Isym)),Mult
2008   
2009def ElemPosition(SGData):
2010    ''' Under development.
2011    Object here is to return a list of symmetry element types and locations suitable
2012    for say drawing them.
2013    So far I have the element type... getting all possible locations without lookup may be impossible!
2014    '''
2015    SymElements = []
2016    Inv = SGData['SGInv']
2017    Cen = SGData['SGCen']
2018    eleSym = {-3:['','-1'],-2:['',-6],-1:['2','-4'],0:['3','-3'],1:['4','m'],2:['6',''],3:['1','']}
2019    # get operators & expand if centrosymmetric
2020    Ops = SGData['SGOps']
2021    opM = np.array([op[0].T for op in Ops])
2022    opT = np.array([op[1] for op in Ops])
2023    if Inv:
2024        opM = np.concatenate((opM,-opM))
2025        opT = np.concatenate((opT,-opT))
2026    opMT = zip(opM,opT)
2027    for M,T in opMT[1:]:        #skip I
2028        Dt = int(nl.det(M))
2029        Tr = int(np.trace(M))
2030        Dt = -(Dt-1)/2
2031        Es = eleSym[Tr][Dt]
2032        if Dt:              #rotation-inversion
2033            I = np.eye(3)
2034            if Tr == 1:     #mirrors/glides
2035                if np.any(T):       #glide
2036                    M2 = np.inner(M,M)
2037                    MT = np.inner(M,T)+T
2038                    print 'glide',Es,MT
2039                    print M2
2040                else:               #mirror
2041                    print 'mirror',Es,T
2042                    print I-M
2043                X = [-1,-1,-1]
2044            elif Tr == -3:  # pure inversion
2045                X = np.inner(nl.inv(I-M),T)
2046                print 'inversion',Es,X
2047            else:           #other rotation-inversion
2048                M2 = np.inner(M,M)
2049                MT = np.inner(M,T)+T
2050                print 'rot-inv',Es,MT
2051                print M2
2052                X = [-1,-1,-1]
2053        else:               #rotations
2054            print 'rotation',Es
2055            X = [-1,-1,-1]
2056        #SymElements.append([Es,X])
2057       
2058    return #SymElements
2059   
2060def ApplyStringOps(A,SGData,X,Uij=[]):
2061    'Needs a doc string'
2062    SGOps = SGData['SGOps']
2063    SGCen = SGData['SGCen']
2064    Ax = A.split('+')
2065    Ax[0] = int(Ax[0])
2066    iC = 0
2067    if Ax[0] < 0:
2068        iC = 1
2069    Ax[0] = abs(Ax[0])
2070    nA = Ax[0]%100-1
2071    cA = Ax[0]/100
2072    Cen = SGCen[cA]
2073    M,T = SGOps[nA]
2074    if len(Ax)>1:
2075        cellA = Ax[1].split(',')
2076        cellA = np.array([int(a) for a in cellA])
2077    else:
2078        cellA = np.zeros(3)
2079    newX = (1-2*iC)*(Cen+np.inner(M,X)+T)+cellA
2080    if len(Uij):
2081        U = Uij2U(Uij)
2082        U = np.inner(M,np.inner(U,M).T)
2083        newUij = U2Uij(U)
2084        return [newX,newUij]
2085    else:
2086        return newX
2087       
2088def StringOpsProd(A,B,SGData):
2089    """
2090    Find A*B where A & B are in strings '-' + '100*c+n' + '+ijk'
2091    where '-' indicates inversion, c(>0) is the cell centering operator,
2092    n is operator number from SgOps and ijk are unit cell translations (each may be <0).
2093    Should return resultant string - C. SGData - dictionary using entries:
2094
2095       *  'SGCen': cell centering vectors [0,0,0] at least
2096       *  'SGOps': symmetry operations as [M,T] so that M*x+T = x'
2097
2098    """
2099    SGOps = SGData['SGOps']
2100    SGCen = SGData['SGCen']
2101    #1st split out the cell translation part & work on the operator parts
2102    Ax = A.split('+'); Bx = B.split('+')
2103    Ax[0] = int(Ax[0]); Bx[0] = int(Bx[0])
2104    iC = 0
2105    if Ax[0]*Bx[0] < 0:
2106        iC = 1
2107    Ax[0] = abs(Ax[0]); Bx[0] = abs(Bx[0])
2108    nA = Ax[0]%100-1;  nB = Bx[0]%100-1
2109    cA = Ax[0]/100;  cB = Bx[0]/100
2110    Cen = (SGCen[cA]+SGCen[cB])%1.0
2111    cC = np.nonzero([np.allclose(C,Cen) for C in SGCen])[0][0]
2112    Ma,Ta = SGOps[nA]; Mb,Tb = SGOps[nB]
2113    Mc = np.inner(Ma,Mb.T)
2114#    print Ma,Mb,Mc
2115    Tc = (np.add(np.inner(Mb,Ta)+1.,Tb))%1.0
2116#    print Ta,Tb,Tc
2117#    print [np.allclose(M,Mc)&np.allclose(T,Tc) for M,T in SGOps]
2118    nC = np.nonzero([np.allclose(M,Mc)&np.allclose(T,Tc) for M,T in SGOps])[0][0]
2119    #now the cell translation part
2120    if len(Ax)>1:
2121        cellA = Ax[1].split(',')
2122        cellA = [int(a) for a in cellA]
2123    else:
2124        cellA = [0,0,0]
2125    if len(Bx)>1:
2126        cellB = Bx[1].split(',')
2127        cellB = [int(b) for b in cellB]
2128    else:
2129        cellB = [0,0,0]
2130    cellC = np.add(cellA,cellB)
2131    C = str(((nC+1)+(100*cC))*(1-2*iC))+'+'+ \
2132        str(int(cellC[0]))+','+str(int(cellC[1]))+','+str(int(cellC[2]))
2133    return C
2134           
2135def U2Uij(U):
2136    #returns the UIJ vector U11,U22,U33,U12,U13,U23 from tensor U
2137    return [U[0][0],U[1][1],U[2][2],2.*U[0][1],2.*U[0][2],2.*U[1][2]]
2138   
2139def Uij2U(Uij):
2140    #returns the thermal motion tensor U from Uij as numpy array
2141    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]]])
2142
2143def StandardizeSpcName(spcgroup):
2144    '''Accept a spacegroup name where spaces may have not been used
2145    in the names according to the GSAS convention (spaces between symmetry
2146    for each axis) and return the space group name as used in GSAS
2147    '''
2148    rspc = spcgroup.replace(' ','').upper()
2149    # deal with rhombohedral and hexagonal setting designations
2150    rhomb = ''
2151    if rspc[-1:] == 'R':
2152        rspc = rspc[:-1]
2153        rhomb = ' R'
2154    elif rspc[-1:] == 'H': # hexagonal is assumed and thus can be ignored
2155        rspc = rspc[:-1]
2156    # look for a match in the spacegroup lists
2157    for i in spglist.values():
2158        for spc in i:
2159            if rspc == spc.replace(' ','').upper():
2160                return spc + rhomb
2161    # how about the post-2002 orthorhombic names?
2162    for i,spc in sgequiv_2002_orthorhombic:
2163        if rspc == i.replace(' ','').upper():
2164            return spc
2165    # not found
2166    return ''
2167
2168   
2169spglist = {}
2170'''A dictionary of space groups as ordered and named in the pre-2002 International
2171Tables Volume A, except that spaces are used following the GSAS convention to
2172separate the different crystallographic directions.
2173Note that the symmetry codes here will recognize many non-standard space group
2174symbols with different settings. They are ordered by Laue group
2175'''
2176spglist = {
2177    'P1' : ('P 1','P -1',), # 1-2
2178    'P2/m': ('P 2','P 21','P m','P a','P c','P n',
2179        '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
2180    'C2/m':('C 2','C m','C c','C n',
2181        'C 2/m','C 2/c','C 2/n',),
2182    'Pmmm':('P 2 2 2',
2183        'P 2 2 21','P 21 2 2','P 2 21 2',
2184        'P 21 21 2','P 2 21 21','P 21 2 21',
2185        'P 21 21 21',
2186        'P m m 2','P 2 m m','P m 2 m',
2187        'P m c 21','P 21 m a','P b 21 m','P m 21 b','P c m 21','P 21 a m',
2188        'P c c 2','P 2 a a','P b 2 b',
2189        'P m a 2','P 2 m b','P c 2 m','P m 2 a','P b m 2','P 2 c m',
2190        'P c a 21','P 21 a b','P c 21 b','P b 21 a','P b c 21','P 21 c a',
2191        'P n c 2','P 2 n a','P b 2 n','P n 2 b','P c n 2','P 2 a n',
2192        'P m n 21','P 21 m n','P n 21 m','P m 21 n','P n m 21','P 21 n m',
2193        'P b a 2','P 2 c b','P c 2 a',
2194        'P n a 21','P 21 n b','P c 21 n','P n 21 a','P b n 21','P 21 c n',
2195        'P n n 2','P 2 n n','P n 2 n',
2196        'P m m m','P n n n',
2197        'P c c m','P m a a','P b m b',
2198        'P b a n','P n c b','P c n a',
2199        'P m m a','P b m m','P m c m','P m a m','P m m b','P c m m',
2200        'P n n a','P b n n','P n c n','P n a n','P n n b','P c n n',
2201        'P m n a','P b m n','P n c m','P m a n','P n m b','P c n m',
2202        'P c c a','P b a a','P b c b','P b a b','P c c b','P c a a',
2203        'P b a m','P m c b','P c m a',
2204        'P c c n','P n a a','P b n b',
2205        'P b c m','P m c a','P b m a','P c m b','P c a m','P m a b',
2206        'P n n m','P m n n','P n m n',
2207        'P m m n','P n m m','P m n m',
2208        'P b c n','P n c a','P b n a','P c n b','P c a n','P n a b',
2209        'P b c a','P c a b',
2210        'P n m a','P b n m','P m c n','P n a m','P m n b','P c m n',
2211        ),
2212    'Cmmm':('C 2 2 21','C 2 2 2','C m m 2',
2213        'C m c 21','C c m 21','C c c 2','C m 2 m','C 2 m m',
2214        'C m 2 a','C 2 m b','C c 2 m','C 2 c m','C c 2 a','C 2 c b',
2215        'C m c m','C m c a','C c m b',
2216        'C m m m','C c c m','C m m a','C m m b','C c c a','C c c b',),
2217    'Immm':('I 2 2 2','I 21 21 21',
2218        'I m m 2','I m 2 m','I 2 m m',
2219        'I b a 2','I 2 c b','I c 2 a',
2220        'I m a 2','I 2 m b','I c 2 m','I m 2 a','I b m 2','I 2 c m',
2221        'I m m m','I b a m','I m c b','I c m a',
2222        'I b c a','I c a b',
2223        'I m m a','I b m m ','I m c m','I m a m','I m m b','I c m m',),
2224    'Fmmm':('F 2 2 2','F m m m', 'F d d d',
2225        'F m m 2','F m 2 m','F 2 m m',
2226        'F d d 2','F d 2 d','F 2 d d',),
2227    'P4/mmm':('P 4','P 41','P 42','P 43','P -4','P 4/m','P 42/m','P 4/n','P 42/n',
2228        'P 4 2 2','P 4 21 2','P 41 2 2','P 41 21 2','P 42 2 2',
2229        'P 42 21 2','P 43 2 2','P 43 21 2','P 4 m m','P 4 b m','P 42 c m',
2230        'P 42 n m','P 4 c c','P 4 n c','P 42 m c','P 42 b c','P -4 2 m',
2231        'P -4 2 c','P -4 21 m','P -4 21 c','P -4 m 2','P -4 c 2','P -4 b 2',
2232        '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',
2233        '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',
2234        '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',
2235        'P 42/n c m',),
2236    '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',
2237        'I 4 c m','I 41 m d','I 41 c d',
2238        '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',
2239        'I 41/a m d','I 41/a c d'),
2240    'R3-H':('R 3','R -3','R 3 2','R 3 m','R 3 c','R -3 m','R -3 c',),
2241    'P6/mmm': ('P 3','P 31','P 32','P -3','P 3 1 2','P 3 2 1','P 31 1 2',
2242        'P 31 2 1','P 32 1 2','P 32 2 1', 'P 3 m 1','P 3 1 m','P 3 c 1',
2243        'P 3 1 c','P -3 1 m','P -3 1 c','P -3 m 1','P -3 c 1','P 6','P 61',
2244        'P 65','P 62','P 64','P 63','P -6','P 6/m','P 63/m','P 6 2 2',
2245        'P 61 2 2','P 65 2 2','P 62 2 2','P 64 2 2','P 63 2 2','P 6 m m',
2246        'P 6 c c','P 63 c m','P 63 m c','P -6 m 2','P -6 c 2','P -6 2 m',
2247        'P -6 2 c','P 6/m m m','P 6/m c c','P 63/m c m','P 63/m m c',),
2248    'Pm3m': ('P 2 3','P 21 3','P m 3','P n 3','P a 3','P 4 3 2','P 42 3 2',
2249        'P 43 3 2','P 41 3 2','P -4 3 m','P -4 3 n','P m 3 m','P n 3 n',
2250        'P m 3 n','P n 3 m',),
2251    'Im3m':('I 2 3','I 21 3','I m -3','I a -3', 'I 4 3 2','I 41 3 2',
2252        'I -4 3 m', 'I -4 3 d','I m -3 m','I m 3 m','I a -3 d',),
2253    'Fm3m':('F 2 3','F m -3','F d -3','F 4 3 2','F 41 3 2','F -4 3 m',
2254        'F -4 3 c','F m -3 m','F m 3 m','F m -3 c','F d -3 m','F d -3 c',),
2255}
2256
2257ssdict = {}
2258'''A dictionary of superspace group symbols allowed for each entry in spglist
2259(except cubics). Monoclinics are all b-unique setting.
2260'''
2261ssdict = {
2262#1,2
2263    'P 1':['(abg)',],'P -1':['(abg)',],
2264#monoclinic - done
2265#3
2266    'P 2':['(a0g)','(a1/2g)','(0b0)','(0b0)s','(1/2b0)','(0b1/2)',],
2267#4       
2268    'P 21':['(a0g)','(0b0)','(1/2b0)','(0b1/2)',],
2269#5
2270    'C 2':['(a0g)','(0b0)','(0b0)s','(0b1/2)',],
2271#6
2272    'P m':['(a0g)','(a0g)s','(a1/2g)','(0b0)','(1/2b0)','(0b1/2)',],
2273#7
2274    'P a':['(a0g)','(a1/2g)','(0b0)','(0b1/2)',],
2275    'P c':['(a0g)','(a1/2g)','(0b0)','(1/2b0)',],
2276    'P n':['(a0g)','(a1/2g)','(0b0)','(1/2b1/2)',],
2277#8       
2278    'C m':['(a0g)','(a0g)s','(0b0)','(0b1/2)',],
2279#9       
2280    'C c':['(a0g)','(a0g)s','(0b0)',],
2281    'C n':['(a0g)','(a0g)s','(0b0)',],
2282#10       
2283    'P 2/m':['(a0g)','(a0g)0s','(a1/2g)','(0b0)','(0b0)s0','(1/2b0)','(0b1/2)',],
2284#11
2285    'P 21/m':['(a0g)','(a0g)0s','(0b0)','(0b0)s0','(1/2b0)','(0b1/2)',],
2286#12       
2287    'C 2/m':['(a0g)','(a0g)0s','(0b0)','(0b0)s0','(0b1/2)',],
2288#13
2289    'P 2/c':['(a0g)','(a0g)0s','(a1/2g)','(0b0)','(0b0)s0','(1/2b0)',],
2290    'P 2/a':['(a0g)','(a0g)0s','(a1/2g)','(0b0)','(0b0)s0','(0b1/2)',],
2291    'P 2/n':['(a0g)','(a0g)0s','(a1/2g)','(0b0)','(0b0)s0','(1/2b1/2)',],
2292#14
2293    'P 21/c':['(a0g)','(0b0)','(1/2b0)',],
2294    'P 21/a':['(a0g)','(0b0)','(0b1/2)',],
2295    'P 21/n':['(a0g)','(0b0)','(1/2b1/2)',],
2296#15
2297    'C 2/c':['(a0g)','(0b0)','(0b0)s0',],
2298    'C 2/n':['(a0g)','(0b0)','(0b0)s0',],
2299#orthorhombic
2300#16   
2301    'P 2 2 2':['(00g)','(00g)00s','(01/2g)','(1/20g)','(1/21/2g)',
2302        '(a00)','(a00)s00','(a01/2)','(a1/20)','(a1/21/2)',
2303        '(0b0)','(0b0)0s0','(1/2b0)','(0b1/2)','(1/2b1/2)',],
2304#17       
2305    'P 2 2 21':['(00g)','(01/2g)','(1/20g)','(1/21/2g)',
2306        '(a00)','(a00)s00','(a1/20)','(0b0)','(0b0)0s0','(1/2b0)',],
2307    'P 21 2 2':['(a00)','(a01/2)','(a1/20)','(a1/21/2)',
2308        '(0b0)','(0b0)0s0','(1/2b0)','(00g)','(00g)00s','(1/20g)',],
2309    'P 2 21 2':['(0b0)','(0b1/2)','(1/2b0)','(1/2b1/2)',
2310        '(00g)','(00g)00s','(1/20g)','(a00)','(a00)s00','(a1/20)',],
2311#18       
2312    'P 21 21 2':['(00g)','(00g)00s','(a00)','(a01/2)','(0b0)','(0b1/2)',],
2313    'P 2 21 21':['(a00)','(a00)s00','(0b0)','(0b1/2)','(00g)','(01/2g)',],
2314    'P 21 2 21':['(0b0)','(0b0)0s0','(00g)','(01/2g)','(a00)','(a01/2)',],
2315#19       
2316    'P 21 21 21':['(00g)','(a00)','(0b0)',],
2317#20       
2318    'C 2 2 21':['(00g)','(10g)','(01g)','(a00)','(a00)s00','(0b0)','(0b0)0s0',],
2319    'A 21 2 2':['(a00)','(a10)','(a01)','(0b0)','(0b0)0s0','(00g)','(00g)00s',],
2320    'B 2 21 2':['(0b0)','(1b0)','(0b1)','(00g)','(00g)00s','(a00)','(a00)s00',],
2321#21       
2322    'C 2 2 2':['(00g)','(00g)00s','(10g)','(10g)00s','(01g)','(01g)00s',
2323        '(a00)','(a00)s00','(a01/2)','(0b0)','(0b0)0s0','(0b1/2)',],
2324    'A 2 2 2':['(a00)','(a00)s00','(a10)','(a10)s00','(a01)','(a01)s00',
2325        '(0b0)','(0b0)0s0','(1/2b0)','(00g)','(00g)00s','(1/20g)',],
2326    'B 2 2 2':['(0b0)','(0b0)0s0','(1b0)','(1b0)0s0','(0b1)','(0b1)0s0',
2327        '(00g)','(00g)00s','(01/2g)','(a00)','(a00)s00','(a1/20)',],
2328#22       
2329    'F 2 2 2':['(00g)','(00g)00s','(10g)','(01g)',
2330        '(a00)','(a00)s00','(a10)','(a01)',
2331        '(0b0)','(0b0)0s0','(1b0)','(0b1)',],
2332#23       
2333    'I 2 2 2':['(00g)','(00g)00s','(a00)','(a00)s00','(0b0)','(0b0)0s0',],
2334#24       
2335    'I 21 21 21':['(00g)','(00g)00s','(a00)','(a00)s00','(0b0)','(0b0)0s0',],
2336#25       
2337    'P m m 2':['(00g)','(00g)s0s','(00g)0ss','(00g)ss0',
2338        '(01/2g)','(01/2g)s0s','(1/20g)','(1/20g)0ss','(1/21/2g)',
2339        '(a00)','(a00)0s0','(a1/20)','(a01/2)','(a01/2)0s0','(a1/21/2)',
2340        '(0b0)','(0b0)s00','(0b1/2)','(0b1/2)s00','(1/2b0)','(1/2b1/2)',],       
2341    'P 2 m m':['(a00)','(a00)ss0','(a00)s0s','(a00)0ss',
2342        '(a01/2)','(a01/2)ss0','(a1/20)','(a1/20)s0s','(a1/21/2)',
2343        '(0b0)','(0b0)00s','(1/2b0)','(0b1/2)','(0b1/2)00s','(1/2b1/2)',
2344        '(00g)','(00g)0s0','(01/2g)','(01/2g)0s0','(1/20g)','(1/21/2g)',],
2345    'P m 2 m':['(0b0)','(0b0)ss0','(0b0)0ss','(0b0)s0s',
2346        '(0b1/2)','(0b1/2)ss0','(1/2b0)','(1/2b0)0ss','(1/2b1/2)',
2347        '(00g)','(00g)s00','(1/20g)','(01/2g)','(01/2g)s00','(1/21/2g)',
2348        '(a00)','(a00)0s0','(a01/2)','(a01/2)0s0','(a1/20)','(a1/21/2)',],       
2349#26       
2350    'P m c 21':['(00g)','(00g)s0s','(01/2g)','(01/2g)s0s','(1/20g)','(1/21/2g)',
2351        '(a00)','(a00)0s0','(a1/20)','(0b0)','(0b0)s00','(0b1/2)',],
2352    'P 21 m a':['(a00)','(a00)ss0','(a01/2)','(a01/2)ss0','(a1/20)','(a1/21/2)',
2353        '(0b0)','(0b0)00s','(1/2b0)','(00g)','(00g)0s0','(01/2g)',],
2354    'P b 21 m':['(0b0)','(0b0)ss0','(0b1/2)','(0b1/2)ss0','(1/2b0)','(1/2b1/2)',
2355        '(00g)','(00g)s00','(1/20g)','(a00)','(a00)0s0','(a01/2)',],
2356    'P m 21 b':['(a00)','(a00)ss0','(a01/2)','(a01/2)ss0','(a1/20)','(a1/21/2)',
2357        '(00g)','(00g)0s0','(01/2g)','(0b0)','(0b0)s00','(0b1/2)',],
2358    'P c m 21':['(00g)','(00g)0ss','(1/20g)','(1/20g)0ss','(01/2g)','(1/21/2g)',
2359        '(0b0)','(0b0)s00','(1/2b0)','(a00)','(a00)0s0','(a01/2)',],
2360    'P 21 a m':['(0b0)','(0b0)ss0','(0b1/2)','(0b1/2)ss0','(1/2b0)','(1/2b1/2)',
2361        '(a00)','(a00)00s','(a1/20)','(00g)','(00g)s00','(1/20g)',],
2362#27       
2363    'P c c 2':['(00g)','(00g)s0s','(00g)0ss','(01/2g)','(1/20g)','(1/21/2g)',
2364        '(a00)','(a00)0s0','(a1/20)','(0b0)','(0b0)s00','(1/2b0)',],
2365    'P 2 a a':['(a00)','(a00)ss0','(a00)s0s','(a01/2)','(a1/20)','(a1/21/2)',
2366        '(0b0)','(0b0)00s','(0b1/2)','(00g)','(00g)0s0','(01/2g)',],
2367    'P b 2 b':['(0b0)','(0b0)0ss','(0b0)ss0','(1/2b0)','(0b1/2)','(1/2b1/2)',
2368        '(00g)','(00g)s00','(1/20g)','(a00)','(a00)00s','(a01/2)',],
2369#28       
2370    'P m a 2':['(00g)','(00g)s0s','(00g)ss0','(00g)0ss','(01/2g)','(01/2g)s0s',
2371        '(0b1/2)','(0b1/2)s00','(a01/2)','(a00)','(0b0)','(0b0)0s0','(a1/20)','(a1/21/2)'],
2372    'P 2 m b':['(a00)','(a00)s0s','(a00)ss0','(a00)0ss','(a01/2)','(a01/2)s0s',
2373        '(1/20g)','(1/20g)s00','(1/2b0)','(0b0)','(00g)','(00g)0s0','(0b1/2)','(1/2b1/2)'],
2374    'P c 2 m':['(0b0)','(0b0)s0s','(0b0)ss0','(0b0)0ss','(1/2b0)','(1/2b0)s0s',
2375        '(a1/20)','(a1/20)s00','(01/2g)','(00g)','(a00)','(a00)0s0','(1/20g)','(1/21/2g)'],
2376    'P m 2 a':['(0b0)','(0b0)s0s','(0b0)ss0','(0b0)0ss','(0b1/2)','(0b1/2)s0s',
2377        '(01/2g)','(01/2g)s00','(a1/20)','(a00)','(00g)','(00g)0s0','(a01/2)','(a1/21/2)'],
2378    'P b m 2':['(00g)','(00g)s0s','(00g)ss0','(00g)0ss','(1/20g)','(1/20g)s0s',
2379        '(a01/2)','(a01/2)s00','(0b1/2)','(0b0)','(a00)','(a00)0s0','(1/2b0)','(1/2b1/2)'],
2380    'P 2 c m':['(a00)','(a00)s0s','(a00)ss0','(a00)0ss','(a1/20)','(a1/20)s0s',
2381        '(1/2b0)','(1/2b0)s00','(1/20g)','(00g)','(0b0)','(0b0)0s0','(01/2g)','(1/21/2g)'],
2382#29       
2383    'P c a 21':['(00g)','(00g)0ss','(01/2g)','(1/20g)',
2384        '(a00)','(a00)0s0','(a1/20)','(0b0)','(0b0)s00','(1/2b0)',],
2385    'P 21 a b':['(a00)','(a00)s0s','(a01/2)','(a1/20)',
2386        '(0b0)','(0b0)00s','(0b1/2)','(00g)','(00g)0s0','(01/2g)',],
2387    'P c 21 b':['(0b0)','(0b0)ss0','(1/2b0)','(0b1/2)',
2388        '(00g)','(00g)s00','(1/20g)','(a00)','(a00)00s','(a01/2)',],
2389    'P b 21 a':['(0b0)','(0b0)0ss','(0b1/2)','(1/2b0)',
2390        '(a00)','(a00)00s','(a1/20)','(00g)','(00g)s00','(1/20g)',],
2391    'P b c 21':['(00g)','(00g)s0s','(1/20g)','(01/2g)',
2392        '(0b0)','(0b0)s00','(0b1/2)','(a00)','(a00)0s0','(a1/20)',],
2393    'P 21 c a':['(a00)','(a00)ss0','(a1/20)','(a01/2)',
2394        '(00g)','(00g)0s0','(1/20g)','(0b0)','(0b0)00s','(0b1/2)',],
2395#30       
2396    'P c n 2':['(00g)','(00g)s0s','(01/2g)','(a00)','(0b0)','(0b0)s00',
2397        '(a1/20)','(1/2b1/2)q00',],
2398    'P 2 a n':['(a00)','(a00)ss0','(a01/2)','(0b0)','(00g)','(00g)0s0',
2399        '(0b1/2)','(1/21/2g)0q0',],
2400    'P n 2 b':['(0b0)','(0b0)0ss','(1/2b0)','(00g)','(a00)','(a00)00s',
2401        '(1/20g)','(a1/21/2)00q',],
2402    'P b 2 n':['(0b0)','(0b0)ss0','(0b1/2)','(a00)','(00g)','(00g)s00',
2403        '(a01/2)','(1/21/2g)0ss',],
2404    'P n c 2':['(00g)','(00g)0ss','(1/20g)','(0b0)','(a00)','(a00)0s0',
2405        '(1/2b0)','(a1/21/2)s0s',],
2406    'P 2 n a':['(a00)','(a00)s0s','(a1/20)','(00g)','(0b0)','(0b0)00s',
2407        '(01/2g)','(1/2b1/2)ss0',],
2408#31       
2409    'P m n 21':['(00g)','(00g)s0s','(01/2g)','(01/2g)s0s','(a00)','(0b0)',
2410        '(0b0)s00','(a1/20)',],
2411    'P 21 m n':['(a00)','(a00)ss0','(a01/2)','(a01/2)ss0','(0b0)','(00g)',
2412        '(00g)0s0','(0b1/2)',],
2413    'P n 21 m':['(0b0)','(0b0)0ss','(1/2b0)','(1/2b0)0ss','(00g)','(a00)',
2414        '(a00)00s','(1/20g)',],
2415    'P m 21 n':['(0b0)','(0b0)ss0','(0b1/2)','(0b1/2)ss0','(a00)','(00g)',
2416        '(00g)s00','(a01/2)',],
2417    'P n m 21':['(00g)','(00g)0ss','(1/20g)','(1/20g)0ss','(0b0)','(a00)',
2418        '(a00)0s0','(1/2b0)',],
2419    'P 21 n m':['(a00)','(a00)s0s','(a1/20)','(a1/20)s0s','(00g)','(0b0)',
2420        '(0b0)00s','(01/2g)',],
2421#32       
2422    'P b a 2':['(00g)','(00g)s0s','(00g)0ss','(00g)ss0','(1/21/2g)qq0',
2423        '(a00)','(a01/2)','(0b0)','(0b1/2)',],
2424    'P 2 c b':['(a00)','(a00)ss0','(a00)s0s','(a00)0ss','(a1/21/2)0qq',
2425        '(0b0)','(1/2b0)','(00g)','(1/20g)',],
2426    'P c 2 a':['(0b0)','(0b0)ss0','(0b0)0ss','(0b0)s0s','(1/2b1/2)q0q',
2427        '(00g)','01/2g)','(a00)','(a1/20)',],
2428#33       
2429    'P b n 21':['(00g)','(00g)s0s','(1/21/2g)qq0','(a00)','(0b0)',],
2430    'P 21 c n':['(a00)','(a00)ss0','(a1/21/2)0qq','(0b0)','(00g)',],
2431    'P n 21 a':['(0b0)','(0b0)0ss','(1/2b1/2)q0q','(00g)','(a00)',],
2432    'P c 21 n':['(0b0)','(0b0)ss0','(1/2b1/2)q0q','(a00)','(00g)',],
2433    'P n a 21':['(00g)','(00g)0ss','(1/21/2g)qq0','(0b0)','(a00)',],
2434    'P 21 n b':['(a00)','(a00)s0s','(a1/21/2)0qq','(00g)','(0b0)',],
2435#34       
2436    'P n n 2':['(00g)','(00g)s0s','(00g)0ss','(1/21/2g)qq0',
2437        '(a00)','(a1/21/2)0q0','(a1/21/2)00q','(0b0)','(1/2b1/2)q00','(1/2b1/2)00q',],
2438    'P 2 n n':['(a00)','(a00)ss0','(a00)s0s','(a1/21/2)0qq',
2439        '(0b0)','(1/2b1/2)q00','(1/2b1/2)00q','(00g)','(1/21/2g)0q0','(1/21/2g)q00',],
2440    'P n 2 n':['(0b0)','(0b0)ss0','(0b0)0ss','(1/2b1/2)q0q',
2441        '(00g)','(1/21/2g)0q0','(1/21/2g)q00','(a00)','(a1/21/2)00q','(a1/21/2)0q0',],
2442#35       
2443    'C m m 2':['(00g)','(00g)s0s','(00g)ss0','(10g)','(10g)s0s','(10g)ss0',
2444        '(0b0)','(0b0)s00','(0b1/2)','(0b1/2)s00',],
2445    'A 2 m m':['(a00)','(a00)ss0','(a00)0ss','(a10)','(a10)ss0','(a10)0ss',
2446        '(00g)','(00g)0s0','(1/20g)','(1/20g)0s0',],
2447    'B m 2 m':['(0b0)','(0b0)0ss','(0b0)s0s','(0b1)','(0b1)0ss','(0b1)s0s',
2448        '(a00)','(a00)00s','(a1/20)','(a1/20)00s',],
2449#36
2450    'C m c 21':['(00g)','(00g)s0s','(10g)','(10g)s0s','(a00)','(a00)0s0','(0b0)','(0b0)s00',],
2451    'A 21 m a':['(a00)','(a00)ss0','(a10)','(a10)ss0','(0b0)','(0b0)00s','(00g)','(00g)0s0',],
2452    'B m 21 b':['(0b0)','(0b0)ss0','(1b0)','(1b0)ss0','(a00)','(a00)00s','(00g)','(00g)s00',],
2453    'B b 21 m':['(0b0)','(0b0)0ss','(0b1)','(0b1)ss0','(a00)','(a00)00s','(00g)','(00g)s00',],
2454    'C c m 21':['(00g)','(00g)0ss','(01g)','(01g)0ss','(a00)','(a00)0s0','(0b0)','(0b0)s00',],
2455    'A 21 a m':['(a00)','(a00)s0s','(a01)','(a01)s0s','(0b0)','(0b0)00s','(00g)','(00g)0s0',],
2456#37
2457    'C c c 2':['(00g)','(00g)s0s','(00g)0ss','(10g)','(10g)s0s','(10g)0ss','(01g)','(01g)s0s','(01g)0ss',
2458        '(a00)','(a00)0s0','(0b0)','(0b0)s00',],
2459    'A 2 a a':['(a00)','(a00)ss0','(a00)s0s','(a10)','(a10)ss0','(a10)ss0','(a01)','(a01)ss0','(a01)ss0',
2460        '(0b0)','(0b0)00s','(00g)','(00g)0s0',],
2461    'B b 2 b':['(0b0)','(0b0)0ss','(0b0)ss0','(0b1)','(0b1)0ss','(0b1)ss0','(1b0)','(1b0)0ss','(1b0)ss0',
2462        '(a00)','(a00)00s','(00g)','(00g)s00',],
2463#38
2464    'A m m 2':['(a00)','(a00)0s0','(a10)','(a10)0s0','(00g)','(00g)0s0',
2465        '(00g)ss0','(00g)0ss','(1/20g)','(1/20g)0ss','(0b0)','(0b0)s00','(1/2b0)',],
2466    'B 2 m m':['(0b0)','(0b0)00s','(0b1)','(0b1)00s','(a00)','(a00)00s',
2467        '(a00)0ss','(a00)s0s','(a1/20)','(a1/20)s0s','(00g)','(00g)0s0','(01/2g)',],
2468    'C m 2 m':['(00g)','(00g)s00','(10g)','(10g)s00','(0b0)','(0b0)s00',
2469        '(0b0)s0s','(0b0)ss0','(0b1/2)','(0b1/2)ss0','(a00)','(a00)00s','(a01/2)',],
2470    'A m 2 m':['(a00)','(a00)00s','(a01)','(a01)00s','(0b0)','(0b0)00s',
2471        '(0b0)s0s','(0b0)0ss','(1/2b0)','(1/2b0)0ss','(00g)','(00g)s00','(1/20g)',],
2472    'B m m 2':['(0b0)','(0b0)s00','(0b1)','(0b1)s00','(a00)','(a00)0s0',
2473        '(a00)0ss','(a00)ss0','(01/2g)','(01/2g)s0s','(a00)','(a00)0s0','(a1/20)',],
2474    'C 2 m m':['(00g)','(00g)0s0','(10g)','(10g)0s0','(00g)','(00g)s00',
2475        '(0b0)s0s','(0b0)0ss','(a01/2)','(a01/2)ss0','(0b0)','(0b0)00s','(0b1/2)',],
2476#39
2477    'A b m 2':['(a00)','(a00)0s0','(a01)','(a01)0s0','(00g)','(00g)s0s',
2478        '(00g)ss0','(00g)0ss','(1/20g)','(1/20g)0ss','(0b0)','(0b0)s00','(1/2b0)',],
2479    'B 2 c m':['(0b0)','(0b0)00s','(1b0)','(1b0)00s','(a00)','(a00)ss0',
2480        '(a00)0ss','(a00)s0s','(a1/20)','(a1/20)s0s','(00g)','(00g)0s0','(01/2g)',],
2481    'C m 2 a':['(00g)','(00g)s00','(01g)','(01g)s00','(0b0)','(0b0)0ss',
2482        '(0b0)s0s','(0b0)ss0','(0b1/2)','(0b1/2)ss0','(a00)','(a00)00s','(a01/2)',],
2483    'A c 2 m':['(a00)','(a00)00s','(a10)','(a10)00s','(0b0)','(0b0)ss0',
2484        '(0b0)s0s','(0b0)0ss','(1/2b0)','(1/2b0)0ss','(00g)','(00g)s00','(1/20g)',],
2485    'B m a 2':['(0b0)','(0b0)s00','(0b1)','(0b1)s00','(00g)','(00g)s0s',
2486        '(00g)0ss','(00g)ss0','(01/2g)','(01/2g)ss0','(a00)','(a00)00s','(a1/20)',],
2487    'C 2 m b':['(00g)','(00g)0s0','(10g)','(10g)0s0','(a00)','(a00)0ss',
2488        '(a00)ss0','(a00)s0s','(a01/2)','(a01/2)s0s','(0b0)','(0b0)0s0','(0b1/2)',],
2489#40       
2490    'A m a 2':['(a00)','(a01)','(00g)','(00g)s0s','(00g)ss0','(00g)0ss','(0b0)','(0b0)s00',],
2491    'B 2 m b':['(0b0)','(1b0)','(a00)','(a00)ss0','(a00)0ss','(a00)s0s','(00g)','(00g)0s0',],
2492    'C c 2 m':['(00g)','(01g)','(0b0)','(0b0)0ss','(0b0)s0s','(0b0)ss0','(a00)','(a00)00s',],
2493    'A m 2 a':['(a00)','(a10)','(0b0)','(0b0)ss0','(0b0)s0s','(0b0)0ss','(00g)','(00g)s00',],
2494    'B b m 2':['(0b0)','(0b1)','(00g)','(00g)0ss','(00g)ss0','(00g)s0s','(a00)','(a00)0s0',],
2495    'C 2 c m':['(00g)','(10g)','(a00)','(a00)s0s','(a00)0ss','(a00)ss0','(0b0)','(0b0)00s',],
2496#41
2497    'A b a 2':['(a00)','(a01)','(00g)','(00g)s0s','(00g)ss0','(00g)0ss','(0b0)','(0b0)s00',],
2498    'B 2 c b':['(0b0)','(1b0)','(a00)','(a00)ss0','(a00)0ss','(a00)s0s','(00g)','(00g)0s0',],
2499    'C c 2 a':['(00g)','(01g)','(0b0)','(0b0)0ss','(0b0)s0s','(0b0)ss0','(a00)','(a00)00s',],
2500    'A c 2 a':['(a00)','(a10)','(0b0)','(0b0)ss0','(0b0)s0s','(0b0)0ss','(00g)','(00g)s00',],
2501    'B b a 2':['(0b0)','(0b1)','(00g)','(00g)0ss','(00g)ss0','(00g)s0s','(a00)','(a00)0s0',],
2502    'C 2 c b':['(00g)','(10g)','(a00)','(a00)s0s','(a00)0ss','(a00)ss0','(0b0)','(0b0)00s',],
2503       
2504#42       
2505    'F m m 2':['(00g)','(00g)s0s','(00g)0ss','(00g)ss0','(10g)','(10g)ss0','(10g)s0s',
2506        '(01g)','(01g)ss0','(01g)0ss','(a00)','(a00)0s0','(a01)','(a01)0s0',
2507        '(0b0)','(0b0)s00','(0b1)','(0b1)s00',],       
2508    'F 2 m m':['(a00)','(a00)ss0','(a00)s0s','(a00)0ss','(a10)','(a10)0ss','(a10)ss0',
2509        '(a01)','(a01)0ss','(a01)s0s','(0b0)','(0b0)00s','(1b0)','(1b0)00s',
2510        '(00g)','(00g)0s0','(10g)','(10g)0s0',],
2511    'F m 2 m':['(0b0)','(0b0)0ss','(0b0)ss0','(0b0)s0s','(0b1)','(0b1)s0s','(0b1)0ss',
2512        '(1b0)','(1b0)s0s','(1b0)ss0','(00g)','(00g)s00','(01g)','(01g)s00',
2513        '(a00)','(a00)00s','(a10)','(a10)00s',],       
2514#43       
2515    'F d d 2':['(00g)','(00g)0ss','(00g)s0s','(a00)','(0b0)',],
2516    'F 2 d d':['(a00)','(a00)s0s','(a00)ss0','(00g)','(0b0)',],       
2517    'F d 2 d':['(0b0)','(0b0)0ss','(0b0)ss0','(a00)','(00g)',],
2518#44
2519    'I m m 2':['(00g)','(00g)ss0','(00g)s0s','(00g)0ss','(a00)','(a00)0s0','(0b0)','(0b0)s00',],
2520    'I 2 m m':['(a00)','(00g)0ss','(00g)ss0','(00g)s0s','(0b0)','(0b0)00s','(00g)','(00g)0s0',],
2521    'I m 2 m':['(0b0)','(0b0)s0s','(0b0)0ss','(0b0)ss0','(00g)','(00g)s00','(a00)','(a00)00s',],
2522#45       
2523    'I b a 2':['(00g)','(00g)ss0','(00g)s0s','(00g)0ss','(a00)','(a00)0s0','(0b0)','(0b0)s00',],
2524    'I 2 c b':['(0b0)','(0b0)s0s','(0b0)0ss','(0b0)ss0','(00g)','(00g)s00','(a00)','(a00)00s',],
2525    'I c 2 a':['(a00)','(00g)0ss','(00g)ss0','(00g)s0s','(0b0)','(0b0)00s','(00g)','(00g)0s0',],
2526#46       
2527    'I m a 2':['(a00)','(00g)0ss','(00g)ss0','(00g)s0s','(0b0)','(0b0)00s','(00g)','(00g)0s0',],
2528    'I 2 m b':['(0b0)','(0b0)s0s','(0b0)0ss','(0b0)ss0','(00g)','(00g)s00','(a00)','(a00)00s',],       
2529    'I c 2 m':['(a00)','(00g)0ss','(00g)ss0','(00g)s0s','(0b0)','(0b0)00s','(00g)','(00g)0s0',],
2530    'I m 2 a':['(a00)','(00g)0ss','(00g)ss0','(00g)s0s','(0b0)','(0b0)00s','(00g)','(00g)0s0',],
2531    'I b m 2':['(a00)','(00g)0ss','(00g)ss0','(00g)s0s','(0b0)','(0b0)00s','(00g)','(00g)0s0',],
2532    'I 2 c m':['(0b0)','(0b0)s0s','(0b0)0ss','(0b0)ss0','(00g)','(00g)s00','(a00)','(a00)00s',],
2533#47       
2534    'P m m m':['(00g)','(00g)s00','(00g)0s0','(00g)ss0','(01/2g)','(01/2g)s00','(1/20g)','(1/20g)s00','(1/21/2g)',
2535        '(a00)','(a00)0s0','(a00)00s','(a00)0ss','(a01/2)','(a01/2)0s0','(a1/20)','(a1/20)00s','(a1/21/2)',
2536        '(0b0)','(0b0)s00','(0b0)00s','(0b0)s0s','(1/2b0)','(1/2b0)00s','(0b1/2)','(0b1/2)s00','(1/2b1/2)',],
2537#48 o@i qq0,0qq,q0q ->000
2538    'P n n n':['(00g)','(00g)s00','(00g)0s0','(1/21/2g)',
2539        '(a00)','(a00)0s0','(a00)00s','(a1/21/2)',
2540        '(0b0)','(0b0)s00','(0b0)00s','(1/2b1/2)',],
2541#49       
2542    'P c c m':['(00g)','(00g)s00','(00g)0s0','(01/2g)','(1/20g)','(1/21/2g)',
2543        '(a00)','(a00)0s0','(a00)00s','(a00)0ss','(a1/20)','(a1/20)00s',
2544        '(0b0)','(0b0)s00','(0b0)00s','(0b0)s0s','(1/2b0)','(1/2b0)00s',],       
2545    'P m a a':['(a00)','(a00)0s0','(a00)00s','(a01/2)','(a1/20)','(a1/21/2)',
2546        '(0b0)','(0b0)00s','(0b0)s00','(0b0)s0s','(0b1/2)','(0b1/2)s00',
2547        '(00g)','(00g)0s0','(00g)s00','(00g)ss0','(01/2g)','(01/2g)s00',],       
2548    'P b m b':['(0b0)','(0b0)00s','(0b0)s00','(0b1/2)','(1/2b0)','(1/2b1/2)',
2549        '(00g)','(00g)s00','(00g)0s0','(00g)ss0','(1/20g)','(1/20g)0s0',
2550        '(a00)','(a00)00s','(a00)0s0','(a00)0ss','(a01/2)','(a01/2)0s0',],
2551#50 o@i qq0,0qq,q0q ->000
2552    'P b a n':['(00g)','(00g)s00','(00g)0s0','(00g)ss0','(1/21/2g)',
2553        '(a00)','(a00)0s0','(a01/2)','(0b0)','(0b0)s00','(0b1/2)',],
2554    'P n c b':['(a00)','(a00)0s0','(a00)00s','(a00)0ss','(a1/21/2)',
2555        '(0b0)','(0b0)00s','(1/2b0)','(00g)','(00g)0s0','(1/20g)',],
2556    'P c n a':['(0b0)','(0b0)s00','(0b0)00s','(0b0)s0s','(1/2b1/2)',
2557        '(00g)','(00g)s00','(01/2g)','(a00)','(a00)00s','(a1/20)',],
2558#51       
2559    'P m m a':['(00g)','(00g)s00','(00g)ss0','(00g)0s0','(0b0)','(0b0)s00',
2560        '(0b0)s0s','(0b0)00s','(a00)','(a00)0s0','(01/2g)','(01/2g)s00',
2561        '(0b1/2)','(0b1/2)s00','(a01/2)','(a01/2)0s0','(1/2b0)','(1/2b1/2)',],
2562    'P b m m':['(a00)','(a00)0s0','(a00)0ss','(a00)00s','(00g)','(00g)0s0',
2563        '(00g)ss0','(00g)s00','(0b0)','(0b0)00s','(a01/2)','(a01/2)0s0',
2564        '(1/20g)','(1/20g)0s0','(1/2b0)','(1/2b0)00s','(01/2g)','(1/21/2g)',],
2565    'P m c m':['(0b0)','(0b0)00s','(0b0)s0s','(0b0)s00','(a00)','(a00)00s',
2566        '(a00)0ss','(a00)0s0','(00g)','(00g)s00','(1/2b0)','(1/2b0)00s',
2567        '(a1/20)','(a1/20)00s','(01/2g)','(01/2g)s00','(a01/2)','(a1/21/2)',],
2568    'P m a m':['(0b0)','(0b0)s00','(0b0)s0s','(0b0)00s','(00g)','(00g)s00',
2569        '(00g)ss0','(00g)0s0','(a00)','(a00)00s','(0b1/2)','(0b1/2)s00',
2570        '(01/2g)','(01/2g)s00','(a1/20)','(a1/20)00s','(1/20g)','(1/21/2g)',],
2571    'P m m b':['(00g)','(00g)0s0','(00g)ss0','(00g)s00','(a00)','(a00)0s0',
2572        '(a00)0ss','(a00)00s','(0b0)','(0b0)s00','(a00)','(a00)0s0',
2573        '(a01/2)','(a01/2)0s0','(0b1/2)','(0b1/2)s00','(a1/20)','(a1/21/2)',],
2574    'P c m m':['(a00)','(a00)00s','(a00)0ss','(a00)0s0','(0b0)','(0b0)00s',
2575        '(0b0)s0s','(0b0)s00','(00g)','(00g)0s0','(0b0)','(0b0)00s',
2576        '(1/2b0)','(1/2b0)00s','(1/20g)','(1/20g)0s0','(0b1/2)','(1/2b1/2)',],
2577#52   o@i qq0,0qq,q0q ->000     
2578    'P n n a':['(00g)','(00g)s00','(00g)0s0','(a00)','(a00)00s',
2579        '(0b0)','(0b0)00s','(a1/21/2)','(1/2b1/2)',],
2580    'P b n n':['(a00)','(a00)0s0','(a00)00s','(0b0)','(0b0)s00',
2581        '(00g)','(00g)s00','(1/2b1/2)','(1/21/2g)',],
2582    'P n c n':['(0b0)','(0b0)s00','(0b0)00s','(00g)','(00g)0s0',
2583        '(a00)','(a00)0s0','(1/21/2g)','(a1/21/2)',],
2584    'P n a n':['(0b0)','(0b0)s00','(0b0)00s','(00g)','(00g)0s0',
2585        '(a00)','(a00)0s0','(1/21/2g)','(a1/21/2)',],
2586    'P n n b':['(00g)','(00g)s00','(00g)0s0','(a00)','(a00)00s',
2587        '(0b0)','(0b0)00s','(a1/21/2)','(1/2b1/2)',],
2588    'P c n n':['(a00)','(a00)0s0','(a00)00s','(0b0)','(0b0)s00',
2589        '(00g)','(00g)s00','(1/2b1/2)','(1/21/2g)',],
2590#53       
2591    'P m n a':['(00g)','(00g)s00','(a00)','(a00)00s','(0b0)','(0b0)00s',
2592        '(0b0)s0s','(0b0)s00','(01/2g)','(01/2g)s00','(a1/20)',],
2593    'P b m n':['(a00)','(a00)0s0','(0b0)','(0b0)s00','(00g)','(00g)s00',
2594        '(00g)ss0','(00g)0s0','(a01/2)','(a01/2)0s0','(0b1/2)',],
2595    'P n c m':['(0b0)','(0b0)00s','(00g)','(00g)0s0','(a00)','(a00)0s0',
2596        '(a00)0ss','(a00)00s','(1/2b0)','(1/2b0)00s','(1/20g)',],
2597    'P m a n':['(0b0)','(0b0)s00','(a00)','(a00)0s0','(00g)','(00g)0s0',
2598        '(00g)ss0','(00g)s00','(0b1/2)','(0b1/2)s00','(a01/2)',],
2599    'P n m b':['(00g)','(00g)0s0','(0b0)','(0b0)00s','(a00)','(a00)00s',
2600        '(a00)0ss','(a00)0s0','(1/20g)','(1/20g)0s0','(1/2b0)',],
2601    'P c n m':['(a00)','(a00)00s','(00g)','(00g)s00','(0b0)','(0b0)s00',
2602        '(0b0)s0s','(0b0)00s','(a1/20)','(a1/20)00s','(01/2g)',],
2603#54       
2604    'P c c a':['(00g)','(00g)s00','(0b0)','(0b0)s00','(a00)','(a00)0s0',
2605        '(a00)0ss','(a00)00s','(01/2g)','(1/2b0)',],
2606    'P b a a':['(a00)','(a00)0s0','(00g)','(00g)0s0','(0b0)','(0b0)00s',
2607        '(0b0)s0s','(0b0)s00','(a01/2)','(01/2g)',],
2608    'P b c b':['(0b0)','(0b0)00s','(a00)','(a00)00s','(00g)','(00g)s00',
2609        '(00g)ss0','(00g)0s0','(1/2b0)','(a01/2)',],
2610    'P b a b':['(0b0)','(0b0)s00','(00g)','(00g)s00','(a00)','(a00)00s',
2611        '(a00)0ss','(a00)0s0','(0b1/2)','(1/20g)',],
2612    'P c c b':['(00g)','(00g)0s0','(a00)','(a00)0s0','(0b0)','(0b0)s00',
2613        '(0b0)s0s','(0b0)00s','(1/20g)','(a1/20)',],
2614    'P c a a':['(a00)','(a00)00s','(0b0)','(0b0)00s','(00g)','(00g)0s0',
2615        '(00g)ss0','(00g)s00','(a1/20)','(0b1/2)',],
2616#55       
2617    'P b a m':['(00g)','(00g)s00','(00g)0s0','(00g)ss0',
2618        '(a00)','(a00)00s','(a01/2)','(0b0)','(0b0)00s','(0b1/2)'],
2619    'P m c b':['(a00)','(a00)0s0','(a00)00s','(a00)0ss',
2620        '(0b0)','(0b0)s00','(1/2b0)','(00g)','(00g)s00','(1/20g)'],
2621    'P c m a':['(0b0)','(0b0)s00','(0b0)00s','(0b0)s0s',
2622        '(a00)','(a00)0s0','(a1/20)','(00g)','(00g)0s0','(01/2g)'],
2623#56       
2624    'P c c n':['(00g)','(00g)s00','(00g)0s0','(a00)','(a00)0s0',
2625        '(0b0)','(0b0)s00'],
2626    'P n a a':['(a00)','(a00)0s0','(a00)00s','(0b0)','(0b0)00s',
2627        '(00g)','(00g)0s0'],
2628    'P b n b':['(0b0)','(0b0)s00','(0b0)00s','(a00)','(a00)00s',
2629        '(00g)','(00g)s00'],
2630#57       
2631    'P c a m':['(00g)','(00g)0s0','(a00)','(a00)00s','(0b0)','(0b0)s00',
2632        '(0b0)ss0','(0b0)00s','(01/2g)','(a1/20)','(a1/20)00s',],
2633    'P m a b':['(a00)','(a00)00s','(0b0)','(0b0)s00','(00g)','(00g)0s0',
2634        '(00g)s0s','(00g)s00','(a01/2)','(0b1/2)','(0b1/2)s00',],
2635    'P c m b':['(0b0)','(0b0)s00','(00g)','(00g)0s0','(a00)','(a00)00s',
2636        '(a00)0ss','(a00)0s0','(1/2b0)','(1/20g)','(1/20g)0s0',],
2637    'P b m a':['(0b0)','(0b0)00s','(a00)','(a00)0s0','(00g)','(00g)s00',
2638        '(00g)ss0','(00g)0s0','(0b1/2)','(a01/2)','(a01/2)0s0',],
2639    'P m c a':['(a00)','(a00)0s0','(00g)','(00g)s00','(0b0)','(0b0)00s',
2640        '(0b0)s0s','(0b0)s00','(a1/20)','(01/2g)','(01/2g)s00'],
2641    'P b c m':['(00g)','(00g)s00','(0b0)','(0b0)00s','(a00)','(a00)0s0',
2642        '(a00)0ss','(a00)00s','(1/20g)','(1/2b0)','(1/2b0)00s',],
2643#58       
2644    'P n n m':['(00g)','(00g)s00','(00g)0s0','(a00)',
2645        '(a00)00s','(0b0)','(0b0)00s'],
2646    'P m n n':['(00g)','(00g)s00','(a00)','(a00)0s0',
2647        '(a00)00s','(0b0)','(0b0)s00'],
2648    'P n m n':['(00g)','(00g)0s0','(a00)','(a00)0s0',
2649        '(0b0)','(0b0)s00','(0b0)00s',],
2650#59 o@i
2651    'P m m n':['(00g)','(00g)s00','(00g)0s0','(00g)ss0','(a00)','(a00)0s0',
2652        '(a01/2)','(a01/2)0s0','(0b0)','(0b0)s00','(0b1/2)','(0b1/2)s00',],
2653    'P n m m':['(a00)','(a00)0s0','(a00)00s','(a00)0ss','(00g)','(00g)0s0',
2654        '(1/20g)','(1/20g)0s0','(0b0)','(0b0)00s','(1/2b0)','(1/2b0)00s'],
2655    'P m n m':['(0b0)','(0b0)s00','(0b0)00s','(0b0)s0s','(00g)','(00g)s00',
2656        '(01/2g)','(01/2g)s00','(a00)','(a00)00s','(a1/20)','(a1/20)00s'],
2657#60       
2658    'P b c n':['(00g)','(00g)s00','(00g)0s0','(a00)','(a00)0s0',
2659        '(a00)00s','(0b0)','(0b0)s00','(0b0)00s'],
2660    'P n c a':['(00g)','(00g)s00','(00g)0s0','(a00)','(a00)0s0',
2661        '(a00)00s','(0b0)','(0b0)s00','(0b0)00s'],
2662    'P b n a':['(00g)','(00g)s00','(00g)0s0','(a00)','(a00)0s0',
2663        '(a00)00s','(0b0)','(0b0)s00','(0b0)00s'],
2664    'P c n b':['(00g)','(00g)s00','(00g)0s0','(a00)','(a00)0s0',
2665        '(a00)00s','(0b0)','(0b0)s00','(0b0)00s'],
2666    'P c a n':['(00g)','(00g)s00','(00g)0s0','(a00)','(a00)0s0',
2667        '(a00)00s','(0b0)','(0b0)s00','(0b0)00s'],
2668    'P n a b':['(00g)','(00g)s00','(00g)0s0','(a00)','(a00)0s0',
2669        '(a00)00s','(0b0)','(0b0)s00','(0b0)00s'],
2670#61       
2671    'P b c a':['(00g)','(00g)s00','(00g)0s0','(a00)','(a00)0s0','(a00)00s',
2672        '(0b0)','(0b0)s00','(0b0)00s'],
2673    'P c a b':['(00g)','(00g)s00','(00g)0s0','(a00)','(a00)0s0','(a00)00s',
2674        '(0b0)','(0b0)s00','(0b0)00s'],
2675#62       
2676    'P n m a':['(00g)','(00g)0s0','(a00)','(a00)0s0','(0b0)','(0b0)00s'],
2677    'P b n m':['(00g)','(00g)s00','(a00)','(a00)00s','(0b0)','(0b0)00s'],
2678    'P m c n':['(00g)','(00g)s00','(a00)','(a00)0s0','(0b0)','(0b0)s00'],
2679    'P n a m':['(00g)','(00g)0s0','(a00)','(a00)00s','(0b0)','(0b0)00s'],
2680    'P m n b':['(00g)','(00g)s00','(a00)','(a00)00s','(0b0)','(0b0)s00'],
2681    'P c m n':['(00g)','(00g)0s0','(a00)','(a00)0s0','(0b0)','(0b0)s00'],
2682#63
2683    'C m c m':['(00g)','(00g)s00','(10g)','(10g)s00','(a00)','(a00)00s','(a00)0ss','(a00)0s0','(0b0)','(0b0)00s','(0b0)s0s','(0b0)s00',],
2684    'A m m a':['(a00)','(a00)0s0','(a10)','(a10)0s0','(0b0)','(0b0)s00','(0b0)s0s','(00g)00s','(00g)','(00g)s00','(00g)ss0','(00g)0s0',],
2685    'B b m m':['(0b0)','(0b0)00s','(0b1)','(0b1)00s','(00g)','(00g)0s0','(00g)ss0','(00g)s00','(a00)','(a00)0s0','(a00)0ss','(a00)00s',],
2686    'B m m b':['(0b0)','(0b0)s00','(1b0)','(1b0)s00','(a00)','(a00)0s0','(a00)0ss','(a00)00s','(00g)','(00g)0s0','(00g)ss0','(00g)s00',],
2687    'C c m m':['(00g)','(00g)0s0','(01g)','(01g)0s0','(0b0)','(0b0)00s','(0b0)s0s','(0b0)s00','(a00)','(a00)00s','(a00)0ss','(a00)0s0',],
2688    'A m a m':['(a00)','(a00)00s','(a01)','(a01)00s','(00g)','(00g)s00','(00g)ss0','(00g)0s0','(0b0)','(0b0)s00','(0b0)s0s','(0b0)00s',],
2689#64       
2690    'C m c a':['(00g)','(00g)s00','(10g)','(10g)s00','(0b0)','(0b0)00s','(0b0)s0s','(0b0)s00','(a00)','(a00)00s','(a00)0ss','(a00)0s0',],
2691    'A b m a':['(a00)','(a00)0s0','(a10)','(a10)0s0','(00g)','(00g)s00','(00g)ss0','(00g)0s0','(0b0)','(0b0)s00','(0b0)s0s','(0b0)00s',],
2692    'B b c m':['(0b0)','(0b0)00s','(0b1)','(0b1)00s','(a00)','(a00)0s0','(a00)0ss','(a00)00s','(00g)','(00g)0s0','(00g)ss0','(00g)s00',],
2693    'B m a b':['(0b0)','(0b0)s00','(1b0)','(1b0)s00','(00g)','(00g)0s0','(00g)ss0','(00g)s00','(a00)','(a00)0s0','(a00)0ss','(a00)00s',],
2694    'C c m b':['(00g)','(00g)0s0','(01g)','(01g)0s0','(a00)','(a00)00s','(a00)0ss','(a00)0s0','(0b0)','(0b0)00s','(0b0)s0s','(0b0)s00',],
2695    'A c a m':['(a00)','(a00)00s','(a01)','(a01)00s','(0b0)','(0b0)s00','(0b0)s0s','(0b0)00s','(00g)','(00g)s00','(00g)ss0','(00g)0s0',],
2696#65       
2697    'C m m m':['(00g)','(00g)s00','(00g)ss0','(10g)','(10g)s00','(10g)ss0','(0b0)','(0b0)00s','(0b0)s0s','(0b0)s00','(0b1/2)','(0b1/2)s00',],
2698    'A m m m':['(a00)','(a00)0s0','(a00)0ss','(a10)','(a10)0s0','(a10)0ss','(00g)','(00g)s00','(00g)ss0','(00g)0s0','(1/20g)','(1/20g)0s0',],
2699    'B m m m':['(0b0)','(0b0)00s','(0b0)s0s','(0b1)','(0b1)00s','(0b1)s0s','(a00)','(a00)0s0','(a00)0ss','(a00)00s','(a1/20)','(a1/20)00s',],
2700#66       
2701    'C c c m':['(00g)','(00g)s00','(10g)','(10g)s00','(0b0)','(0b0)00s','(0b0)s0s','(0b0)s00',],
2702    'A m m a':['(a00)','(a00)0s0','(a10)','(a10)0s0','(00g)','(00g)s00','(00g)ss0','(00g)0s0',],
2703    'B b m b':['(0b0)','(0b0)00s','(0b1)','(0b1)00s','(a00)','(a00)0s0','(a00)0ss','(a00)00s',],
2704#67       
2705    'C m m a':['(00g)','(00g)s00','(00g)ss0','(10g)','(10g)s00','(10g)ss0','(a00)','(a00)00s','(a00)0ss','(a00)0s0','(a01/2)','(a01/2)0s0',],
2706    'A b m m':['(a00)','(a00)0s0','(a00)0ss','(a10)','(a10)0s0','(a10)0ss','(0b0)','(0b0)s00','(0b0)s0s','(0b0)00s','(1/2b0)','(1/2b0)00s',],
2707    'B m c m':['(0b0)','(0b0)00s','(0b0)s0s','(0b1)','(0b1)00s','(0b1)s0s','(00g)','(00g)0s0','(00g)ss0','(00g)s00','(01/2g)','(01/2g)s00',],
2708    'B m a m':['(0b0)','(0b0)s00','(0b0)s0s','(1b0)','(1b0)s00','(1b0)s0s','(a00)','(a00)0s0','(a00)0ss','(a00)00s','(a1/20)','(a1/20)00s',],
2709    'C m m b':['(00g)','(00g)0s0','(00g)ss0','(01g)','(01g)0s0','(01g)ss0','(0b0)','(0b0)00s','(0b0)s0s','(0b0)s00','(0b1/2)','(0b1/2)s00',],
2710    'A c m m':['(a00)','(a00)00s','(a00)0ss','(a01)','(a01)00s','(a01)0ss','(00g)','(00g)s00','(00g)ss0','(00g)0s0','(1/20g)','(1/20g)0s0',],
2711#68 o@i
2712    'C c c a':['(00g)','(00g)s00','(10g)','(01g)','(10g)s00','(01g)s00',
2713        '(a00)','(a00)s00','(a00)ss0','(a00)0s0','(0b0)','(0b0)s00','(0b0)ss0','(0b0)0s0'],
2714    'A b a a':['(a00)','(a00)s00','(a10)','(a01)','(a10)s00','(a01)s00',
2715        '(0b0)','(0b0)s00','(0b0)ss0','(0b0)0s0','(00g)','(00g)s00','(00g)ss0','(00g)0s0'],
2716    'B b c b':['(0b0)','(0b0)s00','(0b1)','(1b0)','(0b1)s00','(1b0)s00',
2717        '(00g)','(00g)s00','(00g)ss0','(0b0)0s0','(a00)','(a00)s00','(a00)ss0','(a00)0s0'],
2718    'B b a b':['(0b0)','(0b0)s00','(1b0)','(0b1)','(1b0)s00','(0b1)s00',
2719        '(a00)','(a00)s00','(a00)ss0','(a00)0s0','(00g)','(00g)s00','(00g)ss0','(00g)0s0'],
2720    'C c c b':['(00g)','(00g)ss0','(01g)','(10g)','(01g)s00','(10g)s00',
2721        '(0b0)','(0b0)s00','(0b0)ss0','(0b0)0s0','(a00)','(a00)s00','(a00)ss0','(a00)0s0'],
2722    'A c a a':['(a00)','(a00)ss0','(a01)','(a10)','(a01)s00','(a10)s00',
2723        '(00g)','(00g)s00','(00g)ss0','(00g)0s0','(0b0)','(0b0)s00','(0b0)ss0','(0b0)0s0'],
2724#69       
2725    'F m m m':['(00g)','(00g)s00','(00g)ss0','(a00)','(a00)s00',
2726        '(a00)ss0','(0b0)','(0b0)s00','(0b0)ss0',
2727        '(10g)','(10g)s00','(10g)ss0','(a10)','(a10)0s0',
2728        '(a10)00s','(a10)0ss','(0b1)','(0b1)s00','(0b1)00s','(0b1)s0s',
2729        '(01g)','(01g)s00','(01g)ss0','(a01)','(a01)0s0',
2730        '(a01)00s','(a01)0ss','(1b0)','(1b0)s00','(1b0)00s','(1b0)s0s'],
2731#70 o@i       
2732    'F d d d':['(00g)','(00g)s00','(a00)','(a00)s00','(0b0)','(0b0)s00'],       
2733#71
2734    'I m m m':['(00g)','(00g)s00','(00g)ss0','(a00)','(a00)0s0',
2735        '(a00)ss0','(0b0)','(0b0)s00','(0b0)ss0'],
2736#72       
2737    'I b a m':['(00g)','(00g)s00','(00g)0s0','(00g)ss0','(a00)','(a00)0s0',
2738        '(a00)00s','(a00)0ss','(0b0)','(0b0)s00','(0b0)00s','(0b0)s0s'],
2739    'I m c b':['(a00)','(a00)0s0','(a00)00s','(a00)0ss','(0b0)','(0b0)00s',
2740        '(0b0)s00','(0b0)s0s','(00g)','(00g)0s0','(00g)s00','(00g)ss0'],
2741    'I c m a':['(0b0)','(0b0)00s','(0b0)s00','(0b0)s0s','(00g)','(00g)s00',
2742        '(00g)0s0','(00g)ss0','(a00)','(a00)00s','(a00)0s0','(a00)0ss'],
2743#73       
2744    'I b c a':['(00g)','(00g)s00','(00g)0s0','(00g)ss0','(a00)','(a00)0s0',
2745        '(a00)00s','(a00)0ss','(0b0)','(0b0)s00','(0b0)00s','(0b0)s0s'],
2746    'I c a b':['(00g)','(00g)s00','(00g)0s0','(00g)ss0','(a00)','(a00)0s0',
2747        '(a00)00s','(a00)0ss','(0b0)','(0b0)s00','(0b0)00s','(0b0)s0s'],
2748#74       
2749    'I m m a':['(00g)','(00g)s00','(00g)0s0','(00g)ss0','(a00)','(a00)0s0',
2750        '(a00)00s','(a00)0ss','(0b0)','(0b0)s00','(0b0)00s','(0b0)s0s'],
2751    'I b m m':['(00g)','(00g)s00','(00g)0s0','(00g)ss0','(a00)','(a00)0s0',
2752        '(a00)00s','(a00)0ss','(0b0)','(0b0)s00','(0b0)00s','(0b0)s0s'],
2753    'I m c m':['(00g)','(00g)s00','(00g)0s0','(00g)ss0','(a00)','(a00)0s0',
2754        '(a00)00s','(a00)0ss','(0b0)','(0b0)s00','(0b0)00s','(0b0)s0s'],
2755    'I m a m':['(00g)','(00g)s00','(00g)0s0','(00g)ss0','(a00)','(a00)0s0',
2756        '(a00)00s','(a00)0ss','(0b0)','(0b0)s00','(0b0)00s','(0b0)s0s'],
2757    'I m m b':['(00g)','(00g)s00','(00g)0s0','(00g)ss0','(a00)','(a00)0s0',
2758        '(a00)00s','(a00)0ss','(0b0)','(0b0)s00','(0b0)00s','(0b0)s0s'],
2759    'I c m m':['(00g)','(00g)s00','(00g)0s0','(00g)ss0','(a00)','(a00)0s0',
2760        '(a00)00s','(a00)0ss','(0b0)','(0b0)s00','(0b0)00s','(0b0)s0s'],
2761#tetragonal - done & checked
2762#75
2763    'P 4':['(00g)','(00g)q','(00g)s','(1/21/2g)','(1/21/2g)q',],
2764#76
2765    'P 41':['(00g)','(1/21/2g)',],
2766#77
2767    'P 42':['(00g)','(00g)q','(1/21/2g)','(1/21/2g)q',],
2768#78
2769    'P 43':['(00g)','(1/21/2g)',],
2770#79
2771    'I 4':['(00g)','(00g)q','(00g)s',],
2772#80
2773    'I 41':['(00g)','(00g)q',],
2774#81
2775    'P -4':['(00g)','(1/21/2g)',],
2776#82
2777    'I -4':['(00g)',],
2778#83
2779    'P 4/m':['(00g)','(00g)s0','(1/21/2g)',],
2780#84
2781    'P 42/m':['(00g)','(1/21/2g)',],
2782#85 o@i q0 -> 00
2783    'P 4/n':['(00g)','(00g)s0','(1/21/2g)',], #q0?
2784#86 o@i q0 -> 00
2785    'P 42/n':['(00g)','(1/21/2g)',],      #q0?
2786#87
2787    'I 4/m':['(00g)','(00g)s0',],
2788#88
2789    'I 41/a':['(00g)',],
2790#89
2791    'P 4 2 2':['(00g)','(00g)q00','(00g)s00','(1/21/2g)','(1/21/2g)q00',],
2792#90
2793    'P 4 21 2':['(00g)','(00g)q00','(00g)s00',],
2794#91
2795    'P 41 2 2':['(00g)','(1/21/2g)',],
2796#92
2797    'P 41 21 2':['(00g)',],
2798#93
2799    'P 42 2 2':['(00g)','(00g)q00','(1/21/2g)','(1/21/2g)q00',],
2800#94
2801    'P 42 21 2':['(00g)','(00g)q00',],
2802#95
2803    'P 43 2 2':['(00g)','(1/21/2g)',],
2804#96
2805    'P 43 21 2':['(00g)',],
2806#97
2807    'I 4 2 2':['(00g)','(00g)q00','(00g)s00',],
2808#98
2809    'I 41 2 2':['(00g)','(00g)q00',],
2810#99
2811    'P 4 m m':['(00g)','(00g)ss0','(00g)0ss','(00g)s0s','(1/21/2g)','(1/21/2g)0ss'],
2812#100
2813    'P 4 b m':['(00g)','(00g)ss0','(00g)0ss','(00g)s0s','(1/21/2g)qq0','(1/21/2g)qqs',],
2814#101
2815    'P 42 c m':['(00g)','(00g)0ss','(1/21/2g)','(1/21/2g)0ss',],
2816#102
2817    'P 42 n m':['(00g)','(00g)0ss','(1/21/2g)qq0','(1/21/2g)qqs',],
2818#103
2819    'P 4 c c':['(00g)','(00g)ss0','(1/21/2g)',],
2820#104
2821    'P 4 n c':['(00g)','(00g)ss0','(1/21/2g)qq0',],
2822#105
2823    'P 42 m c':['(00g)','(00g)ss0','(1/21/2g)',],
2824#106
2825    'P 42 b c':['(00g)','(00g)ss0','(1/21/2g)qq0',],
2826#107
2827    'I 4 m m':['(00g)','(00g)ss0','(00g)0ss','(00g)s0s',],
2828#108
2829    'I 4 c m':['(00g)','(00g)ss0','(00g)0ss','(00g)s0s',],
2830#109
2831    'I 41 m d':['(00g)','(00g)ss0',],
2832#110
2833    'I 41 c d':['(00g)','(00g)ss0',],
2834#111
2835    'P -4 2 m':['(00g)','(00g)0ss','(1/21/2g)','(1/21/2g)0ss',],
2836#112
2837    'P -4 2 c':['(00g)','(1/21/2g)',],
2838#113
2839    'P -4 21 m':['(00g)','(00g)0ss',],
2840#114
2841    'P -4 21 c':['(00g)',],
2842#115    00s -> 0ss
2843    'P -4 m 2':['(00g)','(00g)0s0','(1/21/2g)',],
2844#116
2845    'P -4 c 2':['(00g)','(1/21/2g)',],
2846#117    00s -> 0ss
2847    'P -4 b 2':['(00g)','(00g)0s0','(1/21/2g)0q0',],
2848#118
2849    'P -4 n 2':['(00g)','(1/21/2g)0q0',],
2850#119
2851    'I -4 m 2':['(00g)','(00g)0s0',],
2852#120
2853    'I -4 c 2':['(00g)','(00g)0s0',],
2854#121    00s -> 0ss
2855    'I -4 2 m':['(00g)','(00g)0ss',],
2856#122
2857    'I -4 2 d':['(00g)',],
2858#123
2859    'P 4/m m m':['(00g)','(00g)s0s0','(00g)00ss','(00g)s00s',
2860        '(1/21/2g)','(1/21/2g)s0s0','(1/21/2g)00ss','(1/21/2g)s00s',],
2861#124
2862    'P 4/m c c':['(00g)','(00g)s0s0','(1/21/2g)',],
2863#125    o@i q0q0 -> 0000, q0qs -> 00ss
2864    'P 4/n b m':['(00g)','(00g)s0s0','(00g)00ss','(00g)s00s','(1/21/2g)','(1/21/2g)00ss',],
2865#126    o@i q0q0 -> 0000
2866    'P 4/n n c':['(00g)','(00g)s0s0','(1/21/2g)',],
2867#127
2868    'P 4/m b m':['(00g)','(00g)s0s0','(00g)00ss','(00g)s00s',],
2869#128
2870    'P 4/m n c':['(00g)','(00g)s0s0',],
2871#129
2872    'P 4/n m m':['(00g)','(00g)s0s0','(00g)00ss','(00g)s00s',],
2873#130
2874    'P 4/n c c':['(00g)','(00g)s0s0',],
2875#131
2876    'P 42/m m c':['(00g)','(00g)s0s0','(1/21/2g)',],
2877#132
2878    'P 42/m c m':['(00g)','(00g)00ss','(1/21/2g)','(1/21/2g)00ss',],
2879#133    o@i q0q0 -> 0000
2880    'P 42/n b c':['(00g)','(00g)s0s0','(1/21/2g)',],
2881#134    o@i q0q0 -> 0000, q0qs -> 00ss
2882    'P 42/n n m':['(00g)','(00g)00ss','(1/21/2g)','(1/21/2g)00ss',],
2883#135
2884    'P 42/m b c':['(00g)','(00g)s0s0',],
2885#136
2886    'P 42/m n m':['(00g)','(00g)00ss',],
2887#137
2888    'P 42/n m c':['(00g)','(00g)s0s0',],
2889#138
2890    'P 42/n c m':['(00g)','(00g)00ss',],
2891#139
2892    'I 4/m m m':['(00g)','(00g)s0s0','(00g)00ss','(00g)s00s',],
2893#140
2894    'I 4/m c m':['(00g)','(00g)s0s0','(00g)00ss','(00g)s00s',],
2895#141
2896    'I 41/a m d':['(00g)','(00g)s0s0',],
2897#142
2898    'I 41/a c d':['(00g)','(00g)s0s0',],
2899    #trigonal/rhombahedral - done & checked
2900#143
2901    'P 3':['(00g)','(00g)t','(1/31/3g)',],
2902#144
2903    'P 31':['(00g)','(1/31/3g)',],
2904#145
2905    'P 32':['(00g)','(1/31/3g)',],
2906#146
2907    'R 3':['(00g)','(00g)t',],
2908#147
2909    'P -3':['(00g)','(1/31/3g)',],
2910#148
2911    'R -3':['(00g)',],
2912#149
2913    'P 3 1 2':['(00g)','(00g)t00','(1/31/3g)',],
2914#150
2915    'P 3 2 1':['(00g)','(00g)t00',],
2916#151
2917    'P 31 1 2':['(00g)','(1/31/3g)',],
2918#152
2919    'P 31 2 1':['(00g)',],
2920#153
2921    'P 32 1 2':['(00g)','(1/31/3g)',],
2922#154
2923    'P 32 2 1':['(00g)',],
2924#155
2925    'R 3 2':['(00g)','(00g)t0',],
2926#156
2927    'P 3 m 1':['(00g)','(00g)0s0',],
2928#157
2929    'P 3 1 m':['(00g)','(00g)00s','(1/31/3g)','(1/31/3g)00s',],
2930#158
2931    'P 3 c 1':['(00g)',],
2932#159
2933    'P 3 1 c':['(00g)','(1/31/3g)',],
2934#160
2935    'R 3 m':['(00g)','(00g)0s',],
2936#161
2937    'R 3 c':['(00g)',],
2938#162
2939    'P -3 1 m':['(00g)','(00g)00s','(1/31/3g)','(1/31/3g)00s',],
2940#163
2941    'P -3 1 c':['(00g)','(1/31/3g)',],
2942#164
2943    'P -3 m 1':['(00g)','(00g)0s0',],
2944#165
2945    'P -3 c 1':['(00g)',],
2946#166       
2947    'R -3 m':['(00g)','(00g)0s',],
2948#167
2949    'R -3 c':['(00g)',],
2950    #hexagonal - done & checked
2951#168
2952    'P 6':['(00g)','(00g)h','(00g)t','(00g)s',],
2953#169
2954    'P 61':['(00g)',],
2955#170
2956    'P 65':['(00g)',],
2957#171
2958    'P 62':['(00g)','(00g)h',],
2959#172
2960    'P 64':['(00g)','(00g)h',],
2961#173
2962    'P 63':['(00g)','(00g)h',],
2963#174
2964    'P -6':['(00g)',],
2965#175
2966    'P 6/m':['(00g)','(00g)s0',],
2967#176
2968    'P 63/m':['(00g)',],
2969#177
2970    'P 6 2 2':['(00g)','(00g)h00','(00g)t00','(00g)s00',],
2971#178
2972    'P 61 2 2':['(00g)',],
2973#179
2974    'P 65 2 2':['(00g)',],
2975#180
2976    'P 62 2 2':['(00g)','(00g)h00',],
2977#181
2978    'P 64 2 2':['(00g)','(00g)h00',],
2979#182
2980    'P 63 2 2':['(00g)','(00g)h00',],
2981#183
2982    'P 6 m m':['(00g)','(00g)ss0','(00g)0ss','(00g)s0s',],
2983#184
2984    'P 6 c c':['(00g)','(00g)s0s',],
2985#185
2986    'P 63 c m':['(00g)','(00g)0ss',],
2987#186
2988    'P 63 m c':['(00g)','(00g)0ss',],
2989#187
2990    'P -6 m 2':['(00g)','(00g)0s0',],
2991#188
2992    'P -6 c 2':['(00g)',],
2993#189
2994    'P -6 2 m':['(00g)','(00g)00s',],
2995#190
2996    'P -6 2 c':['(00g)',],
2997#191
2998    'P 6/m m m':['(00g)','(00g)s0s0','(00g)00ss','(00g)s00s',],
2999#192
3000    'P 6/m c c':['(00g)','(00g)s00s',],
3001#193
3002    'P 63/m c m':['(00g)','(00g)00ss',],
3003#194
3004    'P 63/m m c':['(00g)','(00g)00ss'],
3005    }
3006
3007#'A few non-standard space groups for test use'
3008nonstandard_sglist = ('P 21 1 1','P 1 21 1','P 1 1 21','R 3 r','R 3 2 h', 
3009                      'R -3 r', 'R 3 2 r','R 3 m h', 'R 3 m r',
3010                      'R 3 c r','R -3 c r','R -3 m r',),
3011
3012#A list of orthorhombic space groups that were renamed in the 2002 Volume A,
3013# along with the pre-2002 name. The e designates a double glide-plane'''
3014sgequiv_2002_orthorhombic= (('A e m 2', 'A b m 2',),
3015                            ('A e a 2', 'A b a 2',),
3016                            ('C m c e', 'C m c a',),
3017                            ('C m m e', 'C m m a',),
3018                            ('C c c e', 'C c c a'),)
3019#Use the space groups types in this order to list the symbols in the
3020#order they are listed in the International Tables, vol. A'''
3021symtypelist = ('triclinic', 'monoclinic', 'orthorhombic', 'tetragonal', 
3022               'trigonal', 'hexagonal', 'cubic')
3023
3024# self-test materials follow. Requires files in directory testinp
3025selftestlist = []
3026'''Defines a list of self-tests'''
3027selftestquiet = True
3028def _ReportTest():
3029    'Report name and doc string of current routine when ``selftestquiet`` is False'
3030    if not selftestquiet:
3031        import inspect
3032        caller = inspect.stack()[1][3]
3033        doc = eval(caller).__doc__
3034        if doc is not None:
3035            print('testing '+__file__+' with '+caller+' ('+doc+')')
3036        else:
3037            print('testing '+__file__()+" with "+caller)
3038def test0():
3039    '''self-test #0: exercise MoveToUnitCell'''
3040    _ReportTest()
3041    msg = "MoveToUnitCell failed"
3042    assert (MoveToUnitCell([1,2,3]) == [0,0,0]).all, msg
3043    assert (MoveToUnitCell([2,-1,-2]) == [0,0,0]).all, msg
3044    assert abs(MoveToUnitCell(np.array([-.1]))[0]-0.9) < 1e-6, msg
3045    assert abs(MoveToUnitCell(np.array([.1]))[0]-0.1) < 1e-6, msg
3046selftestlist.append(test0)
3047
3048def test1():
3049    '''self-test #1: SpcGroup against previous results'''
3050    #'''self-test #1: SpcGroup and SGPrint against previous results'''
3051    _ReportTest()
3052    testdir = ospath.join(ospath.split(ospath.abspath( __file__ ))[0],'testinp')
3053    if ospath.exists(testdir):
3054        if testdir not in sys.path: sys.path.insert(0,testdir)
3055    import spctestinp
3056    def CompareSpcGroup(spc, referr, refdict, reflist): 
3057        'Compare output from GSASIIspc.SpcGroup with results from a previous run'
3058        # if an error is reported, the dictionary can be ignored
3059        msg0 = "CompareSpcGroup failed on space group %s" % spc
3060        result = SpcGroup(spc)
3061        if result[0] == referr and referr > 0: return True
3062        keys = result[1].keys()
3063        #print result[1]['SpGrp']
3064        #msg = msg0 + " in list lengths"
3065        #assert len(keys) == len(refdict.keys()), msg
3066        for key in refdict.keys():
3067            if key == 'SGOps' or  key == 'SGCen':
3068                msg = msg0 + (" in key %s length" % key)
3069                assert len(refdict[key]) == len(result[1][key]), msg
3070                for i in range(len(refdict[key])):
3071                    msg = msg0 + (" in key %s level 0" % key)
3072                    assert np.allclose(result[1][key][i][0],refdict[key][i][0]), msg
3073                    msg = msg0 + (" in key %s level 1" % key)
3074                    assert np.allclose(result[1][key][i][1],refdict[key][i][1]), msg
3075            else:
3076                msg = msg0 + (" in key %s" % key)
3077                assert result[1][key] == refdict[key], msg
3078        msg = msg0 + (" in key %s reflist" % key)
3079        #for (l1,l2) in zip(reflist, SGPrint(result[1])):
3080        #    assert l2.replace('\t','').replace(' ','') == l1.replace(' ',''), 'SGPrint ' +msg
3081        # for now disable SGPrint testing, output has changed
3082        #assert reflist == SGPrint(result[1]), 'SGPrint ' +msg
3083    for spc in spctestinp.SGdat:
3084        CompareSpcGroup(spc, 0, spctestinp.SGdat[spc], spctestinp.SGlist[spc] )
3085selftestlist.append(test1)
3086
3087def test2():
3088    '''self-test #2: SpcGroup against cctbx (sgtbx) computations'''
3089    _ReportTest()
3090    testdir = ospath.join(ospath.split(ospath.abspath( __file__ ))[0],'testinp')
3091    if ospath.exists(testdir):
3092        if testdir not in sys.path: sys.path.insert(0,testdir)
3093    import sgtbxtestinp
3094    def CompareWcctbx(spcname, cctbx_in, debug=0):
3095        'Compare output from GSASIIspc.SpcGroup with results from cctbx.sgtbx'
3096        cctbx = cctbx_in[:] # make copy so we don't delete from the original
3097        spc = (SpcGroup(spcname))[1]
3098        if debug: print spc['SpGrp']
3099        if debug: print spc['SGCen']
3100        latticetype = spcname.strip().upper()[0]
3101        # lattice type of R implies Hexagonal centering", fix the rhombohedral settings
3102        if latticetype == "R" and len(spc['SGCen']) == 1: latticetype = 'P'
3103        assert latticetype == spc['SGLatt'], "Failed: %s does not match Lattice: %s" % (spcname, spc['SGLatt'])
3104        onebar = [1]
3105        if spc['SGInv']: onebar.append(-1)
3106        for (op,off) in spc['SGOps']:
3107            for inv in onebar:
3108                for cen in spc['SGCen']:
3109                    noff = off + cen
3110                    noff = MoveToUnitCell(noff)
3111                    mult = tuple((op*inv).ravel().tolist())
3112                    if debug: print "\n%s: %s + %s" % (spcname,mult,noff)
3113                    for refop in cctbx:
3114                        if debug: print refop
3115                        # check the transform
3116                        if refop[:9] != mult: continue
3117                        if debug: print "mult match"
3118                        # check the translation
3119                        reftrans = list(refop[-3:])
3120                        reftrans = MoveToUnitCell(reftrans)
3121                        if all(abs(noff - reftrans) < 1.e-5):
3122                            cctbx.remove(refop)
3123                            break
3124                    else:
3125                        assert False, "failed on %s:\n\t %s + %s" % (spcname,mult,noff)
3126    for key in sgtbxtestinp.sgtbx:
3127        CompareWcctbx(key, sgtbxtestinp.sgtbx[key])
3128selftestlist.append(test2)
3129
3130def test3(): 
3131    '''self-test #3: exercise SytSym (includes GetOprPtrName, GenAtom, GetKNsym)
3132     for selected space groups against info in IT Volume A '''
3133    _ReportTest()
3134    def ExerciseSiteSym (spc, crdlist):
3135        'compare site symmetries and multiplicities for a specified space group'
3136        msg = "failed on site sym test for %s" % spc
3137        (E,S) = SpcGroup(spc)
3138        assert not E, msg
3139        for t in crdlist:
3140            symb, m = SytSym(t[0],S)
3141            if symb.strip() != t[2].strip() or m != t[1]:
3142                print spc,t[0],m,symb,t[2]
3143            assert m == t[1]
3144            #assert symb.strip() == t[2].strip()
3145
3146    ExerciseSiteSym('p 1',[
3147            ((0.13,0.22,0.31),1,'1'),
3148            ((0,0,0),1,'1'),
3149            ])
3150    ExerciseSiteSym('p -1',[
3151            ((0.13,0.22,0.31),2,'1'),
3152            ((0,0.5,0),1,'-1'),
3153            ])
3154    ExerciseSiteSym('C 2/c',[
3155            ((0.13,0.22,0.31),8,'1'),
3156            ((0.0,.31,0.25),4,'2(y)'),
3157            ((0.25,.25,0.5),4,'-1'),
3158            ((0,0.5,0),4,'-1'),
3159            ])
3160    ExerciseSiteSym('p 2 2 2',[
3161            ((0.13,0.22,0.31),4,'1'),
3162            ((0,0.5,.31),2,'2(z)'),
3163            ((0.5,.31,0.5),2,'2(y)'),
3164            ((.11,0,0),2,'2(x)'),
3165            ((0,0.5,0),1,'222'),
3166            ])
3167    ExerciseSiteSym('p 4/n',[
3168            ((0.13,0.22,0.31),8,'1'),
3169            ((0.25,0.75,.31),4,'2(z)'),
3170            ((0.5,0.5,0.5),4,'-1'),
3171            ((0,0.5,0),4,'-1'),
3172            ((0.25,0.25,.31),2,'4(001)'),
3173            ((0.25,.75,0.5),2,'-4(001)'),
3174            ((0.25,.75,0.0),2,'-4(001)'),
3175            ])
3176    ExerciseSiteSym('p 31 2 1',[
3177            ((0.13,0.22,0.31),6,'1'),
3178            ((0.13,0.0,0.833333333),3,'2(100)'),
3179            ((0.13,0.13,0.),3,'2(110)'),
3180            ])
3181    ExerciseSiteSym('R 3 c',[
3182            ((0.13,0.22,0.31),18,'1'),
3183            ((0.0,0.0,0.31),6,'3'),
3184            ])
3185    ExerciseSiteSym('R 3 c R',[
3186            ((0.13,0.22,0.31),6,'1'),
3187            ((0.31,0.31,0.31),2,'3(111)'),
3188            ])
3189    ExerciseSiteSym('P 63 m c',[
3190            ((0.13,0.22,0.31),12,'1'),
3191            ((0.11,0.22,0.31),6,'m(100)'),
3192            ((0.333333,0.6666667,0.31),2,'3m(100)'),
3193            ((0,0,0.31),2,'3m(100)'),
3194            ])
3195    ExerciseSiteSym('I a -3',[
3196            ((0.13,0.22,0.31),48,'1'),
3197            ((0.11,0,0.25),24,'2(x)'),
3198            ((0.11,0.11,0.11),16,'3(111)'),
3199            ((0,0,0),8,'-3(111)'),
3200            ])
3201selftestlist.append(test3)
3202
3203if __name__ == '__main__':
3204    # run self-tests
3205    selftestquiet = False
3206    for test in selftestlist:
3207        test()
3208    print "OK"
Note: See TracBrowser for help on using the repository browser.