source: trunk/GSASIIspc.py @ 2075

Last change on this file since 2075 was 2075, checked in by vondreele, 6 years ago

explicit plot destroy when GSAS2 closes
work on scrolling on phase data tabs - scroll back to place last used
fix(?) Block/ZigZag? derivatives
eliminate Refine & max index buttons for mod vector for single crystal data

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