source: trunk/GSASIIspc.py @ 1948

Last change on this file since 1948 was 1948, checked in by vondreele, 7 years ago

modify SS special position code

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