source: trunk/GSASIIspc.py @ 2544

Last change on this file since 2544 was 2544, checked in by vondreele, 7 years ago

major cleanup of unused variables, etc.

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