source: trunk/GSASIIspc.py @ 1955

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

Add error message for TOF calibration if peak positions weren't fitted
fix a bug in SS structure factor calc.
put debug prints back in GetSSfxuinel; now only if debug=True

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