source: trunk/GSASIIspc.py @ 2360

Last change on this file since 2360 was 2289, checked in by vondreele, 9 years ago

fixed interpretation of space group symbols with :1/2 at end indicating setting (in some cif files)
change naming of image integration PWDR names to have zero filled frame numbers (default= '000')
fix handling of constrained Uisos in Shelx ins/res files

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