source: trunk/GSASIIspc.py @ 2470

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

magnetic structure editing/drawing work - includes site symm restrictions

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