source: trunk/GSASIIspc.py @ 2062

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

exclude non variable SS parms from constraint lists
define ZigZag? & Block position modulations; eliminate Sawtooth (it's a variant of ZigZag?)
fix SS names in constraint lists
implement ZigZag? & Block position wave plots
implement ZigZag? & Block atom motion in structure plots
add movie making option (hidden - no file output for it yet)
fix LS I/O for ZigZag? & Block waves

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