source: trunk/GSASIIspc.py @ 2401

Last change on this file since 2401 was 2401, checked in by vondreele, 5 years ago

begin adding magnetism; change space group fortran code
modify tutorial menus

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