source: trunk/GSASIIspc.py @ 2406

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

change spin flip from red/black to -1/1

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