source: trunk/GSASIIspc.py @ 1747

Last change on this file since 1747 was 1747, checked in by vondreele, 9 years ago

a few more SS site symmetries

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