source: trunk/GSASIIspc.py @ 1709

Last change on this file since 1709 was 1709, checked in by toby, 8 years ago

change sphinx docs links; rebuild & fixing minor formatting

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Author Revision URL Id
File size: 130.3 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-14 22:35:03 +0000 (Sat, 14 Mar 2015) $
12# $Author: toby $
13# $Revision: 1709 $
14# $URL: trunk/GSASIIspc.py $
15# $Id: GSASIIspc.py 1709 2015-03-14 22:35:03Z toby $
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: 1709 $")
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                for i in range(3):
1597                    if not XSC[i]:
1598                        CSI['Spos'][0][i] = [0,0,0]
1599                        CSI['Spos'][1][i] = [0.,0.,0.]
1600                        CSI['Spos'][0][i+3] = [0,0,0]
1601                        CSI['Spos'][1][i+3] = [0.,0.,0.]
1602            elif np.allclose(dX[0,0,:],dXT[0,1,:]*sdet):
1603                if 'xy' in siteSym or '+-0' in siteSym:
1604                    CSI['Spos'][0][3:5] = [[12,0,0],[12,0,0]]
1605                    CSI['Spos'][1][3:5] = [[1.,0,0],[-sdet,0,0]]
1606                    xsc[3:5] = 0
1607            else:
1608                for i in range(3):
1609                    if np.allclose(dX[i,i,:],dXT[i,i,:]*sdet):
1610                        xsc[i] = 1
1611                    else:
1612                        xsc[i] = 0
1613                    if np.allclose(dX[i,i+3,:],dXT[i,i+3,:]):
1614                        xsc[i+3] = 1
1615                    else:
1616                        xsc[i+3] = 0
1617            XSC &= xsc
1618           
1619        fsc = np.ones(2,dtype='i')
1620        if 'Crenel' in waveType:
1621            dFT = fracCrenel(tauT,delt2[:1],delt2[1:]).squeeze()
1622            fsc = [1,1]
1623        else:
1624            dFT = fracFourier(tauT,nH,delt2[:1],delt2[1:]).squeeze()
1625            dFT = nl.det(sop[0])*dFT
1626            dFT = dFT[:,np.argsort(tauT)]
1627            dFT[0] *= ssdet
1628            dFT[1] *= sdet
1629            dFTP.append(dFT)
1630       
1631            if np.any(dtau%.5) and ('1/2' in SSGData['modSymb'] or '1' in SSGData['modSymb']):
1632                fsc = [1,1]
1633                CSI['Sfrac'] = [[[1,0],[1,0]],[[1.,0.],[1/dT,0.]]]
1634                for i in range(2):
1635                    if not FSC[i]:
1636                        CSI['Sfrac'][0][i] = [0,0]
1637                        CSI['Sfrac'][1][i] = [0.,0.]
1638            else:
1639                for i in range(2):
1640                    if np.allclose(dF[i,:],dFT[i,:],atol=1.e-6):
1641                        fsc[i] = 1
1642                    else:
1643                        fsc[i] = 0
1644        FSC &= fsc
1645           
1646        usc = np.ones(12,dtype='i')
1647        dUT = posFourier(tauT,nH,delt12[:6],delt12[6:])                  #Uij modulations - 6x12x49 array
1648        dUijT = np.rollaxis(np.rollaxis(np.array(Uij2U(dUT)),3),3)    #convert dUT to 12x49x3x3
1649        dUijT = np.rollaxis(np.inner(np.inner(sop[0],dUijT),sop[0].T),3)
1650        dUT = np.array(U2Uij(dUijT))
1651        dUT = dUT[:,:,np.argsort(tauT)]
1652        dUTP.append(dUT)
1653        if np.any(dtau%.5) and ('1/2' in SSGData['modSymb'] or '1' in SSGData['modSymb']):
1654            CSI['Sadp'] = [[[1,0,0],[2,0,0],[3,0,0],[4,0,0],[5,0,0],[6,0,0], 
1655            [1,0,0],[2,0,0],[3,0,0],[4,0,0],[5,0,0],[6,0,0]],
1656            [[1.,0.,0.],[1.,0.,0.],[1.,0.,0.], [1.,0.,0.],[1.,0.,0.],[1.,0.,0.],
1657            [1./dT,0.,0.],[1./dT,0.,0.],[1./dT,0.,0.], [1.,0.,0.],[1.,0.,0.],[1.,0.,0.]]]
1658            if '(x)' in siteSym:
1659                CSI['Sadp'][1][9:] = [-dT,0.,0.],[-dT,0.,0.],[1./dT,0.,0.]
1660            elif '(y)' in siteSym:
1661                CSI['Sadp'][1][9:] = [-dT,0.,0.],[1./dT,0.,0.],[-dT,0.,0.]
1662            elif '(z)' in siteSym:
1663                CSI['Sadp'][1][9:] = [1./dT,0.,0.],[-dT,0.,0.],[-dT,0.,0.]
1664            for i in range(6):
1665                if not USC[i]:
1666                    CSI['Sadp'][0][i] = [0,0,0]
1667                    CSI['Sadp'][1][i] = [0.,0.,0.]
1668                    CSI['Sadp'][0][i+6] = [0,0,0]
1669                    CSI['Sadp'][1][i+6] = [0.,0.,0.]
1670        else:
1671                       
1672            for i in range(6):
1673                if np.allclose(dU[i,i,:],dUT[i,i,:]*sdet):
1674                    usc[i] = 1
1675                else:
1676                    usc[i] = 0
1677                if np.allclose(dU[i,i+6,:],dUT[i,i+6,:]):
1678                    usc[i+6] = 1
1679                else:
1680                    usc[i+6] = 0
1681            if np.any(dUT[0,1,:]):
1682                if '4/m' in siteSym:
1683                    CSI['Sadp'][0][6:8] = [[12,0,0],[12,0,0]]
1684                    if ssop[1][3]:
1685                        CSI['Sadp'][1][6:8] = [[1.,0.,0.],[-1.,0.,0.]]
1686                        usc[9] = 1
1687                    else:
1688                        CSI['Sadp'][1][6:8] = [[1.,0.,0.],[1.,0.,0.]]
1689                        usc[9] = 0
1690                elif '4' in siteSym:
1691                    CSI['Sadp'][0][6:8] = [[12,0,0],[12,0,0]]
1692                    CSI['Sadp'][0][:2] = [[11,0,0],[11,0,0]]
1693                    if ssop[1][3]:
1694                        CSI['Sadp'][1][:2] = [[1.,0.,0.],[-1.,0.,0.]]
1695                        CSI['Sadp'][1][6:8] = [[1.,0.,0.],[-1.,0.,0.]]
1696                        usc[3] = 1
1697                        usc[9] = 1
1698                    else:
1699                        CSI['Sadp'][1][:2] = [[1.,0.,0.],[1.,0.,0.]]
1700                        CSI['Sadp'][1][6:8] = [[1.,0.,0.],[1.,0.,0.]]
1701                        usc[3] = 0               
1702                        usc[9] = 0
1703                elif 'xy' in siteSym or '+-0' in siteSym:
1704                    if np.allclose(dU[0,0,:],dUT[0,1,:]*sdet):
1705                        print np.allclose(dU[0,0,:],dUT[0,1,:]*sdet),sdet
1706                        CSI['Sadp'][0][4:6] = [[12,0,0],[12,0,0]]
1707                        CSI['Sadp'][0][6:8] = [[11,0,0],[11,0,0]]
1708                        CSI['Sadp'][1][4:6] = [[1.,0.,0.],[sdet,0.,0.]]
1709                        CSI['Sadp'][1][6:8] = [[1.,0.,0.],[sdet,0.,0.]]
1710                        usc[4:6] = 0
1711                        usc[6:8] = 0
1712                   
1713            print SSMT2text(ssop).replace(' ',''),sdet,ssdet,epsinv,usc
1714        USC &= usc
1715    if not np.any(dtau%.5):
1716        n = -1
1717        for i,U in enumerate(USC):
1718            if U:
1719                n += 1
1720                CSI['Sadp'][0][i][0] = n+1
1721                CSI['Sadp'][1][i][0] = 1.0
1722        if waveType == 'Fourier':
1723            n = -1
1724            for i,X in enumerate(XSC):
1725                if X:
1726                    n += 1
1727                    CSI['Spos'][0][i][0] = n+1
1728                    CSI['Spos'][1][i][0] = 1.0
1729        n = -1
1730        for i,F in enumerate(FSC):
1731            if F:
1732                n += 1
1733                CSI['Sfrac'][0][i] = n+1
1734                CSI['Sfrac'][1][i] = 1.0
1735            else:
1736                CSI['Sfrac'][0][i] = 0
1737                CSI['Sfrac'][1][i] = 0.
1738    CSI['Spos'][0] = orderParms(CSI['Spos'][0])
1739    CSI['Sadp'][0] = orderParms(CSI['Sadp'][0])           
1740    if debug:
1741        return CSI,[tau,tauT],[dF,dFTP],[dX,dXTP],[dU,dUTP]
1742    else:
1743        return CSI
1744   
1745def MustrainNames(SGData):
1746    'Needs a doc string'
1747    laue = SGData['SGLaue']
1748    uniq = SGData['SGUniq']
1749    if laue in ['m3','m3m']:
1750        return ['S400','S220']
1751    elif laue in ['6/m','6/mmm','3m1']:
1752        return ['S400','S004','S202']
1753    elif laue in ['31m','3']:
1754        return ['S400','S004','S202','S211']
1755    elif laue in ['3R','3mR']:
1756        return ['S400','S220','S310','S211']
1757    elif laue in ['4/m','4/mmm']:
1758        return ['S400','S004','S220','S022']
1759    elif laue in ['mmm']:
1760        return ['S400','S040','S004','S220','S202','S022']
1761    elif laue in ['2/m']:
1762        SHKL = ['S400','S040','S004','S220','S202','S022']
1763        if uniq == 'a':
1764            SHKL += ['S013','S031','S211']
1765        elif uniq == 'b':
1766            SHKL += ['S301','S103','S121']
1767        elif uniq == 'c':
1768            SHKL += ['S130','S310','S112']
1769        return SHKL
1770    else:
1771        SHKL = ['S400','S040','S004','S220','S202','S022']
1772        SHKL += ['S310','S103','S031','S130','S301','S013']
1773        SHKL += ['S211','S121','S112']
1774        return SHKL
1775       
1776def HStrainVals(HSvals,SGData):
1777    laue = SGData['SGLaue']
1778    uniq = SGData['SGUniq']
1779    DIJ = np.zeros(6)
1780    if laue in ['m3','m3m']:
1781        DIJ[:3] = [HSvals[0],HSvals[0],HSvals[0]]
1782    elif laue in ['6/m','6/mmm','3m1','31m','3']:
1783        DIJ[:4] = [HSvals[0],HSvals[0],HSvals[1],HSvals[0]]
1784    elif laue in ['3R','3mR']:
1785        DIJ = [HSvals[0],HSvals[0],HSvals[0],HSvals[1],HSvals[1],HSvals[1]]
1786    elif laue in ['4/m','4/mmm']:
1787        DIJ[:3] = [HSvals[0],HSvals[0],HSvals[1]]
1788    elif laue in ['mmm']:
1789        DIJ[:3] = [HSvals[0],HSvals[1],HSvals[2]]
1790    elif laue in ['2/m']:
1791        DIJ[:3] = [HSvals[0],HSvals[1],HSvals[2]]
1792        if uniq == 'a':
1793            DIJ[5] = HSvals[3]
1794        elif uniq == 'b':
1795            DIJ[4] = HSvals[3]
1796        elif uniq == 'c':
1797            DIJ[3] = HSvals[3]
1798    else:
1799        DIJ = [HSvals[0],HSvals[1],HSvals[2],HSvals[3],HSvals[4],HSvals[5]]
1800    return DIJ
1801
1802def HStrainNames(SGData):
1803    'Needs a doc string'
1804    laue = SGData['SGLaue']
1805    uniq = SGData['SGUniq']
1806    if laue in ['m3','m3m']:
1807        return ['D11','eA']         #add cubic strain term
1808    elif laue in ['6/m','6/mmm','3m1','31m','3']:
1809        return ['D11','D33']
1810    elif laue in ['3R','3mR']:
1811        return ['D11','D12']
1812    elif laue in ['4/m','4/mmm']:
1813        return ['D11','D33']
1814    elif laue in ['mmm']:
1815        return ['D11','D22','D33']
1816    elif laue in ['2/m']:
1817        Dij = ['D11','D22','D33']
1818        if uniq == 'a':
1819            Dij += ['D23']
1820        elif uniq == 'b':
1821            Dij += ['D13']
1822        elif uniq == 'c':
1823            Dij += ['D12']
1824        return Dij
1825    else:
1826        Dij = ['D11','D22','D33','D12','D13','D23']
1827        return Dij
1828   
1829def MustrainCoeff(HKL,SGData):
1830    'Needs a doc string'
1831    #NB: order of terms is the same as returned by MustrainNames
1832    laue = SGData['SGLaue']
1833    uniq = SGData['SGUniq']
1834    h,k,l = HKL
1835    Strm = []
1836    if laue in ['m3','m3m']:
1837        Strm.append(h**4+k**4+l**4)
1838        Strm.append(3.0*((h*k)**2+(h*l)**2+(k*l)**2))
1839    elif laue in ['6/m','6/mmm','3m1']:
1840        Strm.append(h**4+k**4+2.0*k*h**3+2.0*h*k**3+3.0*(h*k)**2)
1841        Strm.append(l**4)
1842        Strm.append(3.0*((h*l)**2+(k*l)**2+h*k*l**2))
1843    elif laue in ['31m','3']:
1844        Strm.append(h**4+k**4+2.0*k*h**3+2.0*h*k**3+3.0*(h*k)**2)
1845        Strm.append(l**4)
1846        Strm.append(3.0*((h*l)**2+(k*l)**2+h*k*l**2))
1847        Strm.append(4.0*h*k*l*(h+k))
1848    elif laue in ['3R','3mR']:
1849        Strm.append(h**4+k**4+l**4)
1850        Strm.append(3.0*((h*k)**2+(h*l)**2+(k*l)**2))
1851        Strm.append(2.0*(h*l**3+l*k**3+k*h**3)+2.0*(l*h**3+k*l**3+l*k**3))
1852        Strm.append(4.0*(k*l*h**2+h*l*k**2+h*k*l**2))
1853    elif laue in ['4/m','4/mmm']:
1854        Strm.append(h**4+k**4)
1855        Strm.append(l**4)
1856        Strm.append(3.0*(h*k)**2)
1857        Strm.append(3.0*((h*l)**2+(k*l)**2))
1858    elif laue in ['mmm']:
1859        Strm.append(h**4)
1860        Strm.append(k**4)
1861        Strm.append(l**4)
1862        Strm.append(3.0*(h*k)**2)
1863        Strm.append(3.0*(h*l)**2)
1864        Strm.append(3.0*(k*l)**2)
1865    elif laue in ['2/m']:
1866        Strm.append(h**4)
1867        Strm.append(k**4)
1868        Strm.append(l**4)
1869        Strm.append(3.0*(h*k)**2)
1870        Strm.append(3.0*(h*l)**2)
1871        Strm.append(3.0*(k*l)**2)
1872        if uniq == 'a':
1873            Strm.append(2.0*k*l**3)
1874            Strm.append(2.0*l*k**3)
1875            Strm.append(4.0*k*l*h**2)
1876        elif uniq == 'b':
1877            Strm.append(2.0*l*h**3)
1878            Strm.append(2.0*h*l**3)
1879            Strm.append(4.0*h*l*k**2)
1880        elif uniq == 'c':
1881            Strm.append(2.0*h*k**3)
1882            Strm.append(2.0*k*h**3)
1883            Strm.append(4.0*h*k*l**2)
1884    else:
1885        Strm.append(h**4)
1886        Strm.append(k**4)
1887        Strm.append(l**4)
1888        Strm.append(3.0*(h*k)**2)
1889        Strm.append(3.0*(h*l)**2)
1890        Strm.append(3.0*(k*l)**2)
1891        Strm.append(2.0*k*h**3)
1892        Strm.append(2.0*h*l**3)
1893        Strm.append(2.0*l*k**3)
1894        Strm.append(2.0*h*k**3)
1895        Strm.append(2.0*l*h**3)
1896        Strm.append(2.0*k*l**3)
1897        Strm.append(4.0*k*l*h**2)
1898        Strm.append(4.0*h*l*k**2)
1899        Strm.append(4.0*k*h*l**2)
1900    return Strm
1901   
1902def Muiso2Shkl(muiso,SGData,cell):
1903    "this is to convert isotropic mustrain to generalized Shkls"
1904    import GSASIIlattice as G2lat
1905    A = G2lat.cell2AB(cell)[0]
1906   
1907    def minMus(Shkl,muiso,H,SGData,A):
1908        U = np.inner(A.T,H)
1909        S = np.array(MustrainCoeff(U,SGData))
1910        Sum = np.sqrt(np.sum(np.multiply(S,Shkl[:,np.newaxis]),axis=0))
1911        rad = np.sqrt(np.sum((Sum[:,np.newaxis]*H)**2,axis=1))
1912        return (muiso-rad)**2
1913       
1914    laue = SGData['SGLaue']
1915    PHI = np.linspace(0.,360.,60,True)
1916    PSI = np.linspace(0.,180.,60,True)
1917    X = np.outer(npsind(PHI),npsind(PSI))
1918    Y = np.outer(npcosd(PHI),npsind(PSI))
1919    Z = np.outer(np.ones(np.size(PHI)),npcosd(PSI))
1920    HKL = np.dstack((X,Y,Z))
1921    if laue in ['m3','m3m']:
1922        S0 = [1000.,1000.]
1923    elif laue in ['6/m','6/mmm','3m1']:
1924        S0 = [1000.,1000.,1000.]
1925    elif laue in ['31m','3']:
1926        S0 = [1000.,1000.,1000.,1000.]
1927    elif laue in ['3R','3mR']:
1928        S0 = [1000.,1000.,1000.,1000.]
1929    elif laue in ['4/m','4/mmm']:
1930        S0 = [1000.,1000.,1000.,1000.]
1931    elif laue in ['mmm']:
1932        S0 = [1000.,1000.,1000.,1000.,1000.,1000.]
1933    elif laue in ['2/m']:
1934        S0 = [1000.,1000.,1000.,0.,0.,0.,0.,0.,0.]
1935    else:
1936        S0 = [1000.,1000.,1000.,1000.,1000., 1000.,1000.,1000.,1000.,1000., 
1937            1000.,1000.,0.,0.,0.]
1938    S0 = np.array(S0)
1939    HKL = np.reshape(HKL,(-1,3))
1940    result = so.leastsq(minMus,S0,(np.ones(HKL.shape[0])*muiso,HKL,SGData,A))
1941    return result[0]
1942       
1943def SytSym(XYZ,SGData):
1944    '''
1945    Generates the number of equivalent positions and a site symmetry code for a specified coordinate and space group
1946
1947    :param XYZ: an array, tuple or list containing 3 elements: x, y & z
1948    :param SGData: from SpcGroup
1949    :Returns: a two element tuple:
1950
1951     * The 1st element is a code for the site symmetry (see GetKNsym)
1952     * The 2nd element is the site multiplicity
1953
1954    '''
1955    def PackRot(SGOps):
1956        IRT = []
1957        for ops in SGOps:
1958            M = ops[0]
1959            irt = 0
1960            for j in range(2,-1,-1):
1961                for k in range(2,-1,-1):
1962                    irt *= 3
1963                    irt += M[k][j]
1964            IRT.append(int(irt))
1965        return IRT
1966       
1967    SymName = ''
1968    Mult = 1
1969    Isym = 0
1970    if SGData['SGLaue'] in ['3','3m1','31m','6/m','6/mmm']:
1971        Isym = 1073741824
1972    Jdup = 0
1973    Xeqv = GenAtom(XYZ,SGData,True)
1974    IRT = PackRot(SGData['SGOps'])
1975    L = -1
1976    for ic,cen in enumerate(SGData['SGCen']):
1977        for invers in range(int(SGData['SGInv']+1)):
1978            for io,ops in enumerate(SGData['SGOps']):
1979                irtx = (1-2*invers)*IRT[io]
1980                L += 1
1981                if not Xeqv[L][1]:
1982                    Jdup += 1
1983                    jx = GetOprPtrName(str(irtx))
1984                    if jx[2] < 39:
1985                        Isym += 2**(jx[2]-1)
1986    if Isym == 1073741824: Isym = 0
1987    Mult = len(SGData['SGOps'])*len(SGData['SGCen'])*(int(SGData['SGInv'])+1)/Jdup
1988         
1989    return GetKNsym(str(Isym)),Mult
1990   
1991def ElemPosition(SGData):
1992    ''' Under development.
1993    Object here is to return a list of symmetry element types and locations suitable
1994    for say drawing them.
1995    So far I have the element type... getting all possible locations without lookup may be impossible!
1996    '''
1997    SymElements = []
1998    Inv = SGData['SGInv']
1999    Cen = SGData['SGCen']
2000    eleSym = {-3:['','-1'],-2:['',-6],-1:['2','-4'],0:['3','-3'],1:['4','m'],2:['6',''],3:['1','']}
2001    # get operators & expand if centrosymmetric
2002    Ops = SGData['SGOps']
2003    opM = np.array([op[0].T for op in Ops])
2004    opT = np.array([op[1] for op in Ops])
2005    if Inv:
2006        opM = np.concatenate((opM,-opM))
2007        opT = np.concatenate((opT,-opT))
2008    opMT = zip(opM,opT)
2009    for M,T in opMT[1:]:        #skip I
2010        Dt = int(nl.det(M))
2011        Tr = int(np.trace(M))
2012        Dt = -(Dt-1)/2
2013        Es = eleSym[Tr][Dt]
2014        if Dt:              #rotation-inversion
2015            I = np.eye(3)
2016            if Tr == 1:     #mirrors/glides
2017                if np.any(T):       #glide
2018                    M2 = np.inner(M,M)
2019                    MT = np.inner(M,T)+T
2020                    print 'glide',Es,MT
2021                    print M2
2022                else:               #mirror
2023                    print 'mirror',Es,T
2024                    print I-M
2025                X = [-1,-1,-1]
2026            elif Tr == -3:  # pure inversion
2027                X = np.inner(nl.inv(I-M),T)
2028                print 'inversion',Es,X
2029            else:           #other rotation-inversion
2030                M2 = np.inner(M,M)
2031                MT = np.inner(M,T)+T
2032                print 'rot-inv',Es,MT
2033                print M2
2034                X = [-1,-1,-1]
2035        else:               #rotations
2036            print 'rotation',Es
2037            X = [-1,-1,-1]
2038        #SymElements.append([Es,X])
2039       
2040    return #SymElements
2041   
2042def ApplyStringOps(A,SGData,X,Uij=[]):
2043    'Needs a doc string'
2044    SGOps = SGData['SGOps']
2045    SGCen = SGData['SGCen']
2046    Ax = A.split('+')
2047    Ax[0] = int(Ax[0])
2048    iC = 0
2049    if Ax[0] < 0:
2050        iC = 1
2051    Ax[0] = abs(Ax[0])
2052    nA = Ax[0]%100-1
2053    cA = Ax[0]/100
2054    Cen = SGCen[cA]
2055    M,T = SGOps[nA]
2056    if len(Ax)>1:
2057        cellA = Ax[1].split(',')
2058        cellA = np.array([int(a) for a in cellA])
2059    else:
2060        cellA = np.zeros(3)
2061    newX = (1-2*iC)*(Cen+np.inner(M,X)+T)+cellA
2062    if len(Uij):
2063        U = Uij2U(Uij)
2064        U = np.inner(M,np.inner(U,M).T)
2065        newUij = U2Uij(U)
2066        return [newX,newUij]
2067    else:
2068        return newX
2069       
2070def StringOpsProd(A,B,SGData):
2071    """
2072    Find A*B where A & B are in strings '-' + '100*c+n' + '+ijk'
2073    where '-' indicates inversion, c(>0) is the cell centering operator,
2074    n is operator number from SgOps and ijk are unit cell translations (each may be <0).
2075    Should return resultant string - C. SGData - dictionary using entries:
2076
2077       *  'SGCen': cell centering vectors [0,0,0] at least
2078       *  'SGOps': symmetry operations as [M,T] so that M*x+T = x'
2079
2080    """
2081    SGOps = SGData['SGOps']
2082    SGCen = SGData['SGCen']
2083    #1st split out the cell translation part & work on the operator parts
2084    Ax = A.split('+'); Bx = B.split('+')
2085    Ax[0] = int(Ax[0]); Bx[0] = int(Bx[0])
2086    iC = 0
2087    if Ax[0]*Bx[0] < 0:
2088        iC = 1
2089    Ax[0] = abs(Ax[0]); Bx[0] = abs(Bx[0])
2090    nA = Ax[0]%100-1;  nB = Bx[0]%100-1
2091    cA = Ax[0]/100;  cB = Bx[0]/100
2092    Cen = (SGCen[cA]+SGCen[cB])%1.0
2093    cC = np.nonzero([np.allclose(C,Cen) for C in SGCen])[0][0]
2094    Ma,Ta = SGOps[nA]; Mb,Tb = SGOps[nB]
2095    Mc = np.inner(Ma,Mb.T)
2096#    print Ma,Mb,Mc
2097    Tc = (np.add(np.inner(Mb,Ta)+1.,Tb))%1.0
2098#    print Ta,Tb,Tc
2099#    print [np.allclose(M,Mc)&np.allclose(T,Tc) for M,T in SGOps]
2100    nC = np.nonzero([np.allclose(M,Mc)&np.allclose(T,Tc) for M,T in SGOps])[0][0]
2101    #now the cell translation part
2102    if len(Ax)>1:
2103        cellA = Ax[1].split(',')
2104        cellA = [int(a) for a in cellA]
2105    else:
2106        cellA = [0,0,0]
2107    if len(Bx)>1:
2108        cellB = Bx[1].split(',')
2109        cellB = [int(b) for b in cellB]
2110    else:
2111        cellB = [0,0,0]
2112    cellC = np.add(cellA,cellB)
2113    C = str(((nC+1)+(100*cC))*(1-2*iC))+'+'+ \
2114        str(int(cellC[0]))+','+str(int(cellC[1]))+','+str(int(cellC[2]))
2115    return C
2116           
2117def U2Uij(U):
2118    #returns the UIJ vector U11,U22,U33,U12,U13,U23 from tensor U
2119    return [U[0][0],U[1][1],U[2][2],2.*U[0][1],2.*U[0][2],2.*U[1][2]]
2120   
2121def Uij2U(Uij):
2122    #returns the thermal motion tensor U from Uij as numpy array
2123    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]]])
2124
2125def StandardizeSpcName(spcgroup):
2126    '''Accept a spacegroup name where spaces may have not been used
2127    in the names according to the GSAS convention (spaces between symmetry
2128    for each axis) and return the space group name as used in GSAS
2129    '''
2130    rspc = spcgroup.replace(' ','').upper()
2131    # deal with rhombohedral and hexagonal setting designations
2132    rhomb = ''
2133    if rspc[-1:] == 'R':
2134        rspc = rspc[:-1]
2135        rhomb = ' R'
2136    elif rspc[-1:] == 'H': # hexagonal is assumed and thus can be ignored
2137        rspc = rspc[:-1]
2138    # look for a match in the spacegroup lists
2139    for i in spglist.values():
2140        for spc in i:
2141            if rspc == spc.replace(' ','').upper():
2142                return spc + rhomb
2143    # how about the post-2002 orthorhombic names?
2144    for i,spc in sgequiv_2002_orthorhombic:
2145        if rspc == i.replace(' ','').upper():
2146            return spc
2147    # not found
2148    return ''
2149
2150   
2151spglist = {}
2152'''A dictionary of space groups as ordered and named in the pre-2002 International
2153Tables Volume A, except that spaces are used following the GSAS convention to
2154separate the different crystallographic directions.
2155Note that the symmetry codes here will recognize many non-standard space group
2156symbols with different settings. They are ordered by Laue group
2157'''
2158spglist = {
2159    'P1' : ('P 1','P -1',), # 1-2
2160    'P2/m': ('P 2','P 21','P m','P a','P c','P n',
2161        '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
2162    'C2/m':('C 2','C m','C c','C n',
2163        'C 2/m','C 2/c','C 2/n',),
2164    'Pmmm':('P 2 2 2',
2165        'P 2 2 21','P 21 2 2','P 2 21 2',
2166        'P 21 21 2','P 2 21 21','P 21 2 21',
2167        'P 21 21 21',
2168        'P m m 2','P 2 m m','P m 2 m',
2169        'P m c 21','P 21 m a','P b 21 m','P m 21 b','P c m 21','P 21 a m',
2170        'P c c 2','P 2 a a','P b 2 b',
2171        'P m a 2','P 2 m b','P c 2 m','P m 2 a','P b m 2','P 2 c m',
2172        'P c a 21','P 21 a b','P c 21 b','P b 21 a','P b c 21','P 21 c a',
2173        'P n c 2','P 2 n a','P b 2 n','P n 2 b','P c n 2','P 2 a n',
2174        'P m n 21','P 21 m n','P n 21 m','P m 21 n','P n m 21','P 21 n m',
2175        'P b a 2','P 2 c b','P c 2 a',
2176        'P n a 21','P 21 n b','P c 21 n','P n 21 a','P b n 21','P 21 c n',
2177        'P n n 2','P 2 n n','P n 2 n',
2178        'P m m m','P n n n',
2179        'P c c m','P m a a','P b m b',
2180        'P b a n','P n c b','P c n a',
2181        'P m m a','P b m m','P m c m','P m a m','P m m b','P c m m',
2182        'P n n a','P b n n','P n c n','P n a n','P n n b','P c n n',
2183        'P m n a','P b m n','P n c m','P m a n','P n m b','P c n m',
2184        'P c c a','P b a a','P b c b','P b a b','P c c b','P c a a',
2185        'P b a m','P m c b','P c m a',
2186        'P c c n','P n a a','P b n b',
2187        'P b c m','P m c a','P b m a','P c m b','P c a m','P m a b',
2188        'P n n m','P m n n','P n m n',
2189        'P m m n','P n m m','P m n m',
2190        'P b c n','P n c a','P b n a','P c n b','P c a n','P n a b',
2191        'P b c a','P c a b',
2192        'P n m a','P b n m','P m c n','P n a m','P m n b','P c m n',
2193        ),
2194    'Cmmm':('C 2 2 21','C 2 2 2','C m m 2',
2195        'C m c 21','C c m 21','C c c 2','C m 2 m','C 2 m m',
2196        'C m 2 a','C 2 m b','C c 2 m','C 2 c m','C c 2 a','C 2 c b',
2197        'C m c m','C m c a','C c m b',
2198        'C m m m','C c c m','C m m a','C m m b','C c c a','C c c b',),
2199    'Immm':('I 2 2 2','I 21 21 21',
2200        'I m m 2','I m 2 m','I 2 m m',
2201        'I b a 2','I 2 c b','I c 2 a',
2202        'I m a 2','I 2 m b','I c 2 m','I m 2 a','I b m 2','I 2 c m',
2203        'I m m m','I b a m','I m c b','I c m a',
2204        'I b c a','I c a b',
2205        'I m m a','I b m m ','I m c m','I m a m','I m m b','I c m m',),
2206    'Fmmm':('F 2 2 2','F m m m', 'F d d d',
2207        'F m m 2','F m 2 m','F 2 m m',
2208        'F d d 2','F d 2 d','F 2 d d',),
2209    'P4/mmm':('P 4','P 41','P 42','P 43','P -4','P 4/m','P 42/m','P 4/n','P 42/n',
2210        'P 4 2 2','P 4 21 2','P 41 2 2','P 41 21 2','P 42 2 2',
2211        'P 42 21 2','P 43 2 2','P 43 21 2','P 4 m m','P 4 b m','P 42 c m',
2212        'P 42 n m','P 4 c c','P 4 n c','P 42 m c','P 42 b c','P -4 2 m',
2213        'P -4 2 c','P -4 21 m','P -4 21 c','P -4 m 2','P -4 c 2','P -4 b 2',
2214        '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',
2215        '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',
2216        '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',
2217        'P 42/n c m',),
2218    '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',
2219        'I 4 c m','I 41 m d','I 41 c d',
2220        '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',
2221        'I 41/a m d','I 41/a c d'),
2222    'R3-H':('R 3','R -3','R 3 2','R 3 m','R 3 c','R -3 m','R -3 c',),
2223    'P6/mmm': ('P 3','P 31','P 32','P -3','P 3 1 2','P 3 2 1','P 31 1 2',
2224        'P 31 2 1','P 32 1 2','P 32 2 1', 'P 3 m 1','P 3 1 m','P 3 c 1',
2225        'P 3 1 c','P -3 1 m','P -3 1 c','P -3 m 1','P -3 c 1','P 6','P 61',
2226        'P 65','P 62','P 64','P 63','P -6','P 6/m','P 63/m','P 6 2 2',
2227        'P 61 2 2','P 65 2 2','P 62 2 2','P 64 2 2','P 63 2 2','P 6 m m',
2228        'P 6 c c','P 63 c m','P 63 m c','P -6 m 2','P -6 c 2','P -6 2 m',
2229        'P -6 2 c','P 6/m m m','P 6/m c c','P 63/m c m','P 63/m m c',),
2230    'Pm3m': ('P 2 3','P 21 3','P m 3','P n 3','P a 3','P 4 3 2','P 42 3 2',
2231        'P 43 3 2','P 41 3 2','P -4 3 m','P -4 3 n','P m 3 m','P n 3 n',
2232        'P m 3 n','P n 3 m',),
2233    'Im3m':('I 2 3','I 21 3','I m -3','I a -3', 'I 4 3 2','I 41 3 2',
2234        'I -4 3 m', 'I -4 3 d','I m -3 m','I m 3 m','I a -3 d',),
2235    'Fm3m':('F 2 3','F m -3','F d -3','F 4 3 2','F 41 3 2','F -4 3 m',
2236        'F -4 3 c','F m -3 m','F m 3 m','F m -3 c','F d -3 m','F d -3 c',),
2237}
2238
2239ssdict = {}
2240'''A dictionary of superspace group symbols allowed for each entry in spglist
2241(except cubics). Monoclinics are all b-unique setting.
2242'''
2243ssdict = {
2244#1,2
2245    'P 1':['(abg)',],'P -1':['(abg)',],
2246#monoclinic - done
2247#3
2248    'P 2':['(a0g)','(a1/2g)','(0b0)','(0b0)s','(1/2b0)','(0b1/2)',],
2249#4       
2250    'P 21':['(a0g)','(0b0)','(1/2b0)','(0b1/2)',],
2251#5
2252    'C 2':['(a0g)','(0b0)','(0b0)s','(0b1/2)',],
2253#6
2254    'P m':['(a0g)','(a0g)s','(a1/2g)','(0b0)','(1/2b0)','(0b1/2)',],
2255#7
2256    'P a':['(a0g)','(a1/2g)','(0b0)','(0b1/2)',],
2257    'P c':['(a0g)','(a1/2g)','(0b0)','(1/2b0)',],
2258    'P n':['(a0g)','(a1/2g)','(0b0)','(1/2b1/2)',],
2259#8       
2260    'C m':['(a0g)','(a0g)s','(0b0)','(0b1/2)',],
2261#9       
2262    'C c':['(a0g)','(a0g)s','(0b0)',],
2263    'C n':['(a0g)','(a0g)s','(0b0)',],
2264#10       
2265    'P 2/m':['(a0g)','(a0g)0s','(a1/2g)','(0b0)','(0b0)s0','(1/2b0)','(0b1/2)',],
2266#11
2267    'P 21/m':['(a0g)','(a0g)0s','(0b0)','(0b0)s0','(1/2b0)','(0b1/2)',],
2268#12       
2269    'C 2/m':['(a0g)','(a0g)0s','(0b0)','(0b0)s0','(0b1/2)',],
2270#13
2271    'P 2/c':['(a0g)','(a0g)0s','(a1/2g)','(0b0)','(0b0)s0','(1/2b0)',],
2272    'P 2/a':['(a0g)','(a0g)0s','(a1/2g)','(0b0)','(0b0)s0','(0b1/2)',],
2273    'P 2/n':['(a0g)','(a0g)0s','(a1/2g)','(0b0)','(0b0)s0','(1/2b1/2)',],
2274#14
2275    'P 21/c':['(a0g)','(0b0)','(1/2b0)',],
2276    'P 21/a':['(a0g)','(0b0)','(0b1/2)',],
2277    'P 21/n':['(a0g)','(0b0)','(1/2b1/2)',],
2278#15
2279    'C 2/c':['(a0g)','(0b0)','(0b0)s0',],
2280    'C 2/n':['(a0g)','(0b0)','(0b0)s0',],
2281#orthorhombic
2282#16   
2283    'P 2 2 2':['(00g)','(00g)00s','(01/2g)','(1/20g)','(1/21/2g)',
2284        '(a00)','(a00)s00','(a01/2)','(a1/20)','(a1/21/2)',
2285        '(0b0)','(0b0)0s0','(1/2b0)','(0b1/2)','(1/2b1/2)',],
2286#17       
2287    'P 2 2 21':['(00g)','(01/2g)','(1/20g)','(1/21/2g)',
2288        '(a00)','(a00)s00','(a1/20)','(0b0)','(0b0)0s0','(1/2b0)',],
2289    'P 21 2 2':['(a00)','(a01/2)','(a1/20)','(a1/21/2)',
2290        '(0b0)','(0b0)0s0','(1/2b0)','(00g)','(00g)00s','(1/20g)',],
2291    'P 2 21 2':['(0b0)','(0b1/2)','(1/2b0)','(1/2b1/2)',
2292        '(00g)','(00g)00s','(1/20g)','(a00)','(a00)s00','(a1/20)',],
2293#18       
2294    'P 21 21 2':['(00g)','(00g)00s','(a00)','(a01/2)','(0b0)','(0b1/2)',],
2295    'P 2 21 21':['(a00)','(a00)s00','(0b0)','(0b1/2)','(00g)','(01/2g)',],
2296    'P 21 2 21':['(0b0)','(0b0)0s0','(00g)','(01/2g)','(a00)','(a01/2)',],
2297#19       
2298    'P 21 21 21':['(00g)','(a00)','(0b0)',],
2299#20       
2300    'C 2 2 21':['(00g)','(10g)','(01g)','(a00)','(a00)s00','(0b0)','(0b0)0s0',],
2301    'A 21 2 2':['(a00)','(a10)','(a01)','(0b0)','(0b0)0s0','(00g)','(00g)00s',],
2302    'B 2 21 2':['(0b0)','(1b0)','(0b1)','(00g)','(00g)00s','(a00)','(a00)s00',],
2303#21       
2304    'C 2 2 2':['(00g)','(00g)00s','(10g)','(10g)00s','(01g)','(01g)00s',
2305        '(a00)','(a00)s00','(a01/2)','(0b0)','(0b0)0s0','(0b1/2)',],
2306    'A 2 2 2':['(a00)','(a00)s00','(a10)','(a10)s00','(a01)','(a01)s00',
2307        '(0b0)','(0b0)0s0','(0b1/2)','(00g)','(00g)00s','(01/2g)',],
2308    'B 2 2 2':['(0b0)','(0b0)0s0','(1b0)','(1b0)0s0','(0b1)','(0b1)0s0',
2309        '(00g)','(00g)00s','(01/2g)','(a00)','(a00)s00','(a01/2)',],
2310#22       
2311    'F 2 2 2':['(00g)','(00g)00s','(10g)','(01g)',
2312        '(a00)','(a00)s00','(a10)','(a01)',
2313        '(0b0)','(0b0)0s0','(1b0)','(0b1)',],
2314#23       
2315    'I 2 2 2':['(00g)','(00g)00s','(a00)','(a00)s00','(0b0)','(0b0)0s0',],
2316#24       
2317    'I 21 21 21':['(00g)','(00g)00s','(a00','(a00)s00','(0b0)','(0b0)0s0',],
2318#25       
2319    'P m m 2':['(00g)','(00g)s0s','(00g)0ss','(00g)ss0',
2320        '(01/2g)','(01/2g)s0s','(1/20g)','(1/20g)0ss','(1/21/2g)',
2321        '(a00)','(a00)0s0','(a1/20)','(a01/2)','(a01/2)0s0','(a1/21/2)',
2322        '(0b0)','(0b0)s00','(0b1/2)','(0b1/2)s00','(1/2b0)','(1/2b1/2)',],       
2323    'P 2 m m':['(a00)','(a00)ss0','(a00)s0s','(a00)0ss',
2324        '(a01/2)','(a01/2)ss0','(a1/20)','(a1/20)s0s','(a1/21/2)',
2325        '(0b0)','(0b0)00s','(1/2b0)','(0b1/2)','(0b1/2)00s','(1/2b1/2)',
2326        '(00g)','(00g)0s0','(01/2g)','(01/2g)0s0','(1/20g)','(1/21/2g)',],
2327    'P m 2 m':['(0b0)','(0b0)ss0','(0b0)0ss','(0b0)s0s',
2328        '(0b1/2)','(0b1/2)ss0','(1/2b0)','(1/2b0)0ss','(1/2b1/2)',
2329        '(00g)','(00g)s00','(1/20g)','(01/2g)','(01/2g)s00','(1/21/2g)',
2330        '(a00)','(a00)0s0','(a01/2)','(a01/2)0s0','(a1/20)','(a1/21/2)',],       
2331#26       
2332    'P m c 21':['(00g)','(00g)s0s','(01/2g)','(01/2g)s0s','(1/20g)','(1/21/2g)',
2333        '(a00)','(a00)0s0','(a1/20)','(0b0)','(0b0)s00','(0b1/2)',],
2334    'P 21 m a':['(a00)','(a00)ss0','(a01/2)','(a01/2)ss0','(a1/20)','(a1/21/2)',
2335        '(0b0)','(0b0)00s','(1/2b0)','(00g)','(00g)0s0','(01/2g)',],
2336    'P b 21 m':['(0b0)','(0b0)ss0','(0b1/2)','(0b1/2)ss0','(1/2b0)','(1/2b1/2)',
2337        '(00g)','(00g)s00','(1/20g)','(a00)','(a00)0s0','(a01/2)',],
2338    'P m 21 b':['(a00)','(a00)ss0','(a01/2)','(a01/2)ss0','(a1/20)','(a1/21/2)',
2339        '(00g)','(00g)0s0','(01/2g)','(0b0)','(0b0)s00','(0b1/2)',],
2340    'P c m 21':['(00g)','(00g)0ss','(1/20g)','(1/20g)0ss','(01/2g)','(1/21/2g)',
2341        '(0b0)','(0a0)s00','(1/2b0)','(a00)','(a00)0s0','(a01/2)',],
2342    'P 21 a m':['(0b0)','(0b0)ss0','(0b1/2)','(0b1/2)ss0','(1/2b0)','(1/2b1/2)',
2343        '(a00)','(a00)00s','(a1/20)','(00g)','(00g)s00','(1/20g)',],
2344#27       
2345    'P c c 2':['(00g)','(00g)s0s','(00g)0ss','(01/2g)','(1/20g)','(1/21/2g)',
2346        '(a00)','(a00)0s0','(a1/20)','(0b0)','(0b0)s00','(1/2b0)',],
2347    'P 2 a a':['(a00)','(a00)ss0','(a00)s0s','(a01/2)','(a1/20)','(a1/21/2)',
2348        '(0b0)','(0b0)00s','(0b1/2)','(00g)','(00g)0s0','(01/2g)',],
2349    'P b 2 b':['(0b0)','(0b0)0ss','(0b0)ss0','(1/2b0)','(0b1/2)','(1/2b1/2)',
2350        '(00g)','(00g)s00','(1/20g)','(a00)','(a00)00s','(a01/2)',],
2351#28       
2352    'P m a 2':['(00g)','(00g)s0s','(00g)ss0','(00g)0ss','(01/2g)','(01/2g)s0s',
2353        '(0b1/2)','(0b1/2)s00','(a01/2)','(a00)','(0b0)','(0b0)0s0','(a1/20)','(a1/21/2)'],
2354    'P 2 m b':['(a00)','(a00)s0s','(a00)ss0','(a00)0ss','(a01/2)','(a01/2)s0s',
2355        '(1/20g)','(1/20g)s00','(1/2b0)','(0b0)','(00g)','(00g)0s0','(0b1/2)','(1/2b1/2)'],
2356    'P c 2 m':['(0b0)','(0b0)s0s','(0b0)ss0','(0b0)0ss','(1/2b0)','(1/2b0)s0s',
2357        '(a1/20)','(a1/20)s00','(01/2g)','(00g)','(a00)','(a00)0s0','(1/20g)','(1/21/2g)'],
2358    'P m 2 a':['(0b0)','(0b0)s0s','(0b0)ss0','(0b0)0ss','(0b1/2)','(0b1/2)s0s',
2359        '(01/2g)','(01/2g)s00','(a1/20)','(a00)','(00g)','(00g)0s0','(a01/2)','(a1/21/2)'],
2360    'P b m 2':['(00g)','(00g)s0s','(00g)ss0','(00g)0ss','(1/20g)','(1/20g)s0s',
2361        '(a01/2)','(a01/2)s00','(0b1/2)','(0b0)','(a00)','(a00)0s0','(1/2b0)','(1/2b1/2)'],
2362    'P 2 c m':['(a00)','(a00)s0s','(a00)ss0','(a00)0ss','(a1/20)','(a1/20)s0s',
2363        '(1/2b0)','(1/2b0)s00','(1/20g)','(00g)','(0b0)','(0b0)0s0','(01/2g)','(1/21/2g)'],
2364#29       
2365    'P c a 21':['(00g)','(00g)0ss','(01/2g)','(1/20g)',
2366        '(a00)','(a00)0s0','(a1/20)','(0b0)','(0b0)s00','(1/2b0)',],
2367    'P 21 a b':[],
2368    'P c 21 b':[],
2369    'P b 21 a':[],
2370    'P b c 21':[],
2371    'P 21 c a':[],
2372#30       
2373    'P c n 2':[],
2374    'P 2 a n':[],
2375    'P n 2 b':[],
2376    'P b 2 n':[],
2377    'P n c 2':[],
2378    'P 2 n a':[],
2379#31       
2380    'P m n 21':[],
2381    'P 21 m n':[],
2382    'P n 21 m':[],
2383    'P m 21 n':[],
2384    'P n m 21':[],
2385    'P 21 n m':[],
2386#32       
2387    'P b a 2':['(00g)','(00g)s0s','(00g)0ss','(00g)ss0','(1/21/2g)qq0',
2388        '(a00)','(a01/2)','(0b0)','(0b1/2)',],
2389    'P 2 c b':['(a00)','(a00)ss0','(a00)s0s','(a00)0ss','(a1/21/2)0qq',
2390        '(0b0)','(1/2b0)','(00g)','(1/20g)',],
2391    'P c 2 a':['(0b0)','(0b0)ss0','(0b0)0ss','(0b0)s0s','(1/2b1/2)q0q',
2392        '(00g)','01/2g)','(a00)','(a1/20)',],
2393#33       
2394    'P n a 21':[],
2395    'P 21 n b':[],
2396    'P c 21 n':[],
2397    'P n 21 a':[],
2398    'P b n 21':[],
2399    'P 21 c n':[],
2400#34       
2401    'P n n 2':['(00g)','(00g)s0s','(00g)0ss','(1/21/2g)qq0',
2402        '(a00)','(a1/21/2)0q0','(a1/21/2)00q','(0b0)','(1/2b1/2)q00','(1/2b1/2)00q',],
2403    'P 2 n n':['(a00)','(a00)ss0','(a00)s0s','(a1/21/2)0qq',
2404        '(0b0)','(1/2b1/2)q00','(1/2b1/2)00q','(00g)','(1/21/2b)0q0','(1/21/2g)q00',],
2405    'P n 2 n':['(0b0)','(0b0)ss0','(0b0)0ss','(1/2b1/2)q0q',
2406        '(00g)','(1/21/2g)0q0','(1/21/2g)q00','(a00)','(a1/21/2)00q','(b1/21/2)0q0',],
2407#35       
2408    'C m m 2':['(00g)','(00g)s0s','(00g)0ss','(00g)ss0','(10g)','(10g)s0s','(10g)0ss','(10g)ss0',
2409        '(01g)','(01g)s0s','(01g)0ss','(01g)ss0','(a00)','(a00)0s0','(a01/2)','(a01/2)0s0',
2410        '(0b0)','(0b0)s00','(0b1/2)','(0b1/2)s00',],
2411    'A 2 m m':['(a00)','(a00)s0s','(a00)0ss','(a00)ss0','(a10)','(a10)s0s','(a10)0ss','(a10)ss0',
2412        '(a01)','(a01)s0s','(a01)0ss','(a01)ss0','(0b0)','(0b0)00s','(1/2b0)','(1/2b0)00s',
2413        '(00g)','(00g)0s0','(01/2g)','(01/2g)0s0',],
2414    'B m 2 m':['(0b0)','(0b0)s0s','(0b0)0ss','(0b0)ss0','(1b0)','(1b0)s0s','(1b0)0ss','(1b0)ss0',
2415        '(0b1)','(0b1)s0s','(0b1)0ss','(0b1)ss0','(a00)','(a00)00s','(a01/2)','(a01/2)00s',
2416        '(00g)','(00g)s00','(1/20g)','(1/20g)s00',],
2417#36
2418    'C m c 21':['(00g)','(00g)s0s','(10g)','(10g)s0s','(a00)','(a00)0s0','(0b0)','(0b0)s00',],
2419    'A 21 m a':['(a00)','(a00)ss0','(a10)','(a10)ss0','(0b0)','(0b0)00s','(00g)','(00g)0s0',],
2420    'B m 21 b':['(0b0)','(0b0)ss0','(1b0)','(1b0)ss0','(a00)','(a00)00s','(00g)','(00g)s00',],
2421    'B b 21 m':['(0b0)','(0b0)0ss','(0b1)','(0b1)ss0','(a00)','(a00)00s','(00g)','(00g)s00',],
2422    'C c m 21':['(00g)','(00g)0ss','(01g)','(01g)0ss','(a00)','(a00)0s0','(0b0)','(0b0)s00',],
2423    'A 21 a m':['(a00)','(a00)s0s','(a01)','(a01)s0s','(0b0)','(0b0)00s','(00g)','(00g)0s0',],
2424#37
2425    'C c c 2':['(00g)','(00g)s0s','(00g)0ss','(10g)','(10g)s0s','(10g)0ss','(01g)','(01g)s0s','(01g)0ss',
2426        '(a00)','(a00)0s0','(0b0)','(0b0)s00',],
2427    'A 2 a a':['(a00)','(a00)ss0','(a00)s0s','(a10)','(a10)ss0','(a10)ss0','(a01)','(a01)ss0','(a01)ss0',
2428        '(0b0)','(0b0)00s','(00g)','(00g)0s0',],
2429    'B b 2 b':['(0b0)','(0b0)0ss','(0b0)ss0','(0b1)','(0b1)0ss','(0b1)ss0','(1b0)','(1b0)0ss','(1b0)ss0',
2430        '(a00)','(a00)00s','(00g)','(00g)s00',],
2431#38
2432    'A m m 2':[],
2433    'B 2 m m':[],
2434    'C m 2 m':[],
2435    'A m 2 m':[],
2436    'B m m 2':[],
2437    'C 2 m m':[],
2438#39
2439    'A b m 2':[],
2440    'B 2 c m':[],
2441    'C m 2 a':[],
2442    'A c 2 m':[],
2443    'B m a 2':[],
2444    'C 2 m b':[],
2445#40       
2446    'A m a 2':[],
2447    'B 2 m b':[],
2448    'C c 2 m':[],
2449    'A m 2 a':[],
2450    'B b m 2':[],
2451    'C 2 c m':[],
2452#41
2453    'A b a 2':[],
2454    'B 2 c b':[],
2455    'C c 2 a':[],
2456    'A c 2 a':[],
2457    'B b a 2':[],
2458    'C 2 c b':[],
2459       
2460#42       
2461    'F m m 2':['(00g)','(00g)s0s','(00g)0ss','(00g)ss0','(10g)','(10g)ss0','(10g)s0s',
2462        '(01g)','(01g)ss0','(01g)0ss','(a00)','(a00)0s0','(a01)','(a01)0s0',
2463        '(0b0)','(0b0)s00','(0b1)','(0b1)s00',],       
2464    'F 2 m m':['(a00)','(a00)ss0','(a00)s0s','(a00)0ss','(a10)','(a10)0ss','(a10)ss0',
2465        '(a01)','(a01)0ss','(a01)s0s','(0b0)','(0b0)00s','(1b0)','(1b0)00s',
2466        '(00g)','(00g)0s0','(10g)','(10g)0s0',],
2467    'F m 2 m':['(0b0)','(0b0)0ss','(0b0)ss0','(0b0)s0s','(0b1)','(0b1)s0s','(0b1)0ss',
2468        '(1b0)','(1b0)s0s','(1b0)ss0','(00g)','(00g)s00','(01g)','(01g)s00',
2469        '(a00)','(a00)00s','(a10)','(a10)00s',],       
2470#43       
2471    'F d d 2':['(00g)','(00g)0ss','(00g)s0s','(a00)','(0b0)',],
2472    'F 2 d d':['(a00)','(a00)s0s','(a00)ss0','(00g)','(0b0)',],       
2473    'F d 2 d':['(0b0)','(0b0)0ss','(0b0)ss0','(a00)','(00g)',],
2474#44
2475    'I m m 2':['(00g)','(00g)ss0','(00g)s0s','(00g)0ss','(a00)','(a00)0s0','(0b0)','(0b0)s00',],
2476    'I 2 m m':['(a00)','(00g)0ss','(00g)ss0','(00g)s0s','(0b0)','(0b0)00s','(00g)','(00g)0s0',],
2477    'I m 2 m':['(0b0)','(0b0)s0s','(0b0)0ss','(0b0)ss0','(00g)','(00g)s00','(a00)','(a00)00s',],
2478#45       
2479    'I b a 2':['(00g)','(00g)ss0','(00g)s0s','(00g)0ss','(a00)','(a00)0s0','(0b0)','(0b0)s00',],
2480    'I 2 c b':['(0b0)','(0b0)s0s','(0b0)0ss','(0b0)ss0','(00g)','(00g)s00','(a00)','(a00)00s',],
2481    'I c 2 a':['(a00)','(00g)0ss','(00g)ss0','(00g)s0s','(0b0)','(0b0)00s','(00g)','(00g)0s0',],
2482#46       
2483    'I m a 2':['(a00)','(00g)0ss','(00g)ss0','(00g)s0s','(0b0)','(0b0)00s','(00g)','(00g)0s0',],
2484    'I 2 m b':['(0b0)','(0b0)s0s','(0b0)0ss','(0b0)ss0','(00g)','(00g)s00','(a00)','(a00)00s',],       
2485    'I c 2 m':['(a00)','(00g)0ss','(00g)ss0','(00g)s0s','(0b0)','(0b0)00s','(00g)','(00g)0s0',],
2486    'I m 2 a':['(a00)','(00g)0ss','(00g)ss0','(00g)s0s','(0b0)','(0b0)00s','(00g)','(00g)0s0',],
2487    'I b m 2':['(a00)','(00g)0ss','(00g)ss0','(00g)s0s','(0b0)','(0b0)00s','(00g)','(00g)0s0',],
2488    'I 2 c m':['(0b0)','(0b0)s0s','(0b0)0ss','(0b0)ss0','(00g)','(00g)s00','(a00)','(a00)00s',],
2489#47       
2490    'P m m m':['(00g)','(00g)s00','(00g)0s0','(00g)ss0','(01/2g)','(01/2g)s00','(1/20g)','(1/20g)s00','(1/21/2g)',
2491        '(a00)','(a00)0s0','(a00)00s','(a00)0ss','(a01/2)','(a01/2)0s0','(a1/20)','(a1/20)00s','(a1/21/2)',
2492        '(0b0)','(0b0)s00','(0b0)00s','(0b0)s0s','(1/2b0)','(1/2b0)00s','(0b1/2)','(0b1/2)s00','(1/2b1/2)',],
2493#48 o@i qq0,0qq,q0q ->000
2494    'P n n n':['(00g)','(00g)s00','(00g)0s0','(1/21/2g)',
2495        '(a00)','(a00)0s0','(a00)00s','(a1/21/2)',
2496        '(0b0)','(0b0)s00','(0b0)00s','(1/2b1/2)',],
2497#49       
2498    'P c c m':['(00g)','(00g)s00','(00g)0s0','(01/2g)','(1/20g)','(1/21/2g)',
2499        '(a00)','(a00)0s0','(a00)00s','(a00)0ss','(a1/20)','(a1/20)00s',
2500        '(0b0)','(0b0)s00','(0b0)00s','(0b0)s0s','(1/2b0)','(1/2b0)00s',],       
2501    'P m a a':['(a00)','(a00)0s0','(a00)00s','(a01/2)','(a1/20)','(a1/21/2)',
2502        '(0b0)','(0b0)00s','(0b0)s00','(0b0)s0s','(0b1/2)','(0b1/2)s00',
2503        '(00g)','(00g)0s0','(00g)s00','(00g)ss0','(01/2g)','(01/2g)s00',],       
2504    'P b m b':['(0b0)','(0b0)00s','(0b0)s00','(0b1/2)','(1/2b0)','(1/2b1/2)',
2505        '(00g)','(00g)s00','(00g)0s0','(00g)ss0','(1/20g)','(1/20g)0s0',
2506        '(a00)','(a00)00s','(a00)0s0','(a00)0ss','(a01/2)','(a01/2)0s0',],
2507#50 o@i qq0,0qq,q0q ->000
2508    'P b a n':['(00g)','(00g)s00','(00g)0s0','(00g)ss0','(1/21/2g)',
2509        '(a00)','(a00)0s0','(a01/2)','(0b0)','(0b0)s00','(0b1/2)',],
2510    'P n c b':['(a00)','(a00)0s0','(a00)00s','(a00)0ss','(a1/21/2)',
2511        '(0b0)','(0b0)00s','(1/2b0)','(00g)','(00g)0s0','(1/20g)',],
2512    'P c n a':['(0b0)','(0b0)s00','(0b0)00s','(0b0)s0s','(1/2b1/2)',
2513        '(00g)','(00g)s00','(01/2a)','(a00)','(a00)00s','(a1/20)',],
2514#51       
2515    'P m m a':[],
2516    'P b m m':[],
2517    'P m c m':[],
2518    'P m a m':[],
2519    'P m m b':[],
2520    'P c m m':[],
2521#52   o@i qq0,0qq,q0q ->000     
2522    'P n n a':['(00g)','(00g)s00','(00g)0s0','(a00)','(a00)00s',
2523        '(0b0)','(0b0)00s','(a1/21/2)','(1/2b1/2)',],
2524    'P b n n':['(a00)','(a00)0s0','(a00)00s','(0b0)','(0b0)s00',
2525        '(00g)','(00g)s00','(1/2b1/2)','(1/21/2g)',],
2526    'P n c n':['(0b0)','(0b0)s00','(0b0)00s','(00g)','(00g)0s0',
2527        '(a00)','(a00)0s0','(1/21/2g)','(a1/21/2)',],
2528    'P n a n':['(0b0)','(0b0)s00','(0b0)00s','(00g)','(00g)0s0',
2529        '(a00)','(a00)0s0','(1/21/2g)','(a1/21/2)',],
2530    'P n n b':['(00g)','(00g)s00','(00g)0s0','(a00)','(a00)00s',
2531        '(0b0)','(0b0)00s','(a1/21/2)','(1/2b1/2)',],
2532    'P c n n':['(a00)','(a00)0s0','(a00)00s','(0b0)','(0b0)s00',
2533        '(00g)','(00g)s00','(1/2b1/2)','(1/21/2g)',],
2534#53       
2535    'P m n a':[],
2536    'P b m n':[],
2537    'P n c m':[],
2538    'P m a n':[],
2539    'P n m b':[],
2540    'P c n m':[],
2541#54       
2542    'P c c a':[],
2543    'P b a a':[],
2544    'P b c b':[],
2545    'P b a b':[],
2546    'P c c b':[],
2547    'P c a a':[],
2548#55       
2549    'P b a m':['(00g)','(00g)s00','(00g)0s0','(00g)ss0',
2550        '(a00)','(a00)00s','(a01/2)','(0b0)','(0b0)00s','(0b1/2)'],
2551    'P m c b':['(a00)','(a00)0s0','(a00)00s','(a00)0ss',
2552        '(0b0)','(0b0)s00','(1/2b0)','(00g)','(00g)s00','(1/20g)'],
2553    'P c m a':['(0b0)','(0b0)s00','(0b0)00s','(0b0)s0s',
2554        '(a00)','(a00)0s0','(a1/20)','(00g)','(00g)0s0','(01/2g)'],
2555#56       
2556    'P c c n':['(00g)','(00g)s00','(00g)0s0','(a00)','(a00)0s0',
2557        '(0b0)','(0b0)s00'],
2558    'P n a a':['(a00)','(a00)0s0','(a00)00s','(0b0)','(0b0)00s',
2559        '(00g)','(00g)0s0'],
2560    'P b n b':['(0b0)','(0b0)s00','(0b0)00s','(a00)','(a00)00s',
2561        '(00g)','(00g)s00'],
2562#57       
2563    'P b c m':[],
2564    'P m c a':[],
2565    'P b m a':[],
2566    'P c m b':[],
2567    'P c a m':[],
2568    'P m a b':[],
2569#58       
2570    'P n n m':['(00g)','(00g)s00','(00g)0s0','(a00)',
2571        '(a00)00s','(0b0)','(0b0)00s'],
2572    'P m n n':['(00g)','(00g)s00','(a00)','(a00)0s0',
2573        '(a00)00s','(0b0)','(0b0)s00'],
2574    'P n m n':['(00g)','(00g)0s0','(a00)','(a00)0s0',
2575        '(0b0)','(0b0)s00','(0b0)00s',],
2576#59 o@i
2577    'P m m n':['(00g)','(00g)s00','(00g)0s0','(00g)ss0','(a00)','(a00)0s0',
2578        '(a01/2)','(a01/2)0s0','(0b0)','(0b0)s00','(0b1/2)','(0b1/2)s00',],
2579    'P n m m':['(a00)','(a00)0s0','(a00)00s','(a00)0ss','(00g)','(00g)0s0',
2580        '(1/20g)','(1/20g)0s0','(0b0)','(0b0)00s','(1/2b0)','(1/2b0)00s'],
2581    'P m n m':['(0b0)','(0b0)s00','(0b0)00s','(0b0)s0s','(00g)','(00g)s00',
2582        '(01/2g)','(01/2g)s00','(a00)','(a00)00s','(a1/20)','(a1/20)00s'],
2583#60       
2584    'P b c n':['(00g)','(00g)s00','(00g)0s0','(a00)','(a00)0s0',
2585        '(a00)00s','(0b0)','(0b0)s00','(0b0)00s'],
2586    'P n c a':['(00g)','(00g)s00','(00g)0s0','(a00)','(a00)0s0',
2587        '(a00)00s','(0b0)','(0b0)s00','(0b0)00s'],
2588    'P b n a':['(00g)','(00g)s00','(00g)0s0','(a00)','(a00)0s0',
2589        '(a00)00s','(0b0)','(0b0)s00','(0b0)00s'],
2590    'P c n b':['(00g)','(00g)s00','(00g)0s0','(a00)','(a00)0s0',
2591        '(a00)00s','(0b0)','(0b0)s00','(0b0)00s'],
2592    'P c a n':['(00g)','(00g)s00','(00g)0s0','(a00)','(a00)0s0',
2593        '(a00)00s','(0b0)','(0b0)s00','(0b0)00s'],
2594    'P n a b':['(00g)','(00g)s00','(00g)0s0','(a00)','(a00)0s0',
2595        '(a00)00s','(0b0)','(0b0)s00','(0b0)00s'],
2596#61       
2597    'P b c a':['(00g)','(00g)s00','(00g)0s0','(a00)','(a00)0s0','(a00)00s',
2598        '(0b0)','(0b0)s00','(0b0)00s'],
2599    'P c a b':['(00g)','(00g)s00','(00g)0s0','(a00)','(a00)0s0','(a00)00s',
2600        '(0b0)','(0b0)s00','(0b0)00s'],
2601#62       
2602    'P n m a':['(00g)','(00g)0s0','(a00)','(a00)0s0','(0b0)','(0b0)00s'],
2603    'P b n m':['(00g)','(00g)s00','(a00)','(a00)00s','(0b0)','(0b0)00s'],
2604    'P m c n':['(00g)','(00g)s00','(a00)','(a00)0s0','(0b0)','(0b0)s00'],
2605    'P n a m':['(00g)','(00g)0s0','(a00)','(a00)00s','(0b0)','(0b0)00s'],
2606    'P m n b':['(00g)','(00g)s00','(a00)','(a00)00s','(0b0)','(0b0)s00'],
2607    'P c m n':['(00g)','(00g)0s0','(a00)','(a00)0s0','(0b0)','(0b0)s00'],
2608#63
2609    'C m c m':[],
2610    'A m m a':[],
2611    'B b m m':[],
2612    'B m m b':[],
2613    'C c m m':[],
2614    'A m a m':[],
2615#64       
2616    'C m c a':['(00g)','(00g)s00','(10g)','(10g)s00','(a00)',],
2617    'A b m a':[],
2618    'B b c m':[],
2619    'B m a b':[],
2620    'C c m b':[],
2621    'A c a m':[],
2622#65       
2623    'C m m m':[],
2624    'A m m m':[],
2625    'B m m m':[],
2626#66       
2627    'C c c m':[],
2628    'A m m a':[],
2629    'B b m b':[],
2630#67       
2631    'C m m a':[],
2632    'A b m m':[],
2633    'B m c m':[],
2634    'B m a m':[],
2635    'C m m b':[],
2636    'A c m m':[],
2637#68 o@i
2638    'C c c a':['(00g)','(00g)s00','(10g)','(01g)','(10g)s00','(01g)s00',
2639        '(a00)','(a00)s00','(a00)ss0','(a00)0s0','(0b0)','(0b0)s00','(0b0)ss0','(0b0)0s0'],
2640    'A b a a':['(a00)','(a00)s00','(a10)','(a01)','(a10)s00','(a01)s00',
2641        '(0b0)','(0b0)s00','(0b0)ss0','(0b0)0s0','(00g)','(00g)s00','(00g)ss0','(00g)0s0'],
2642    'B b c b':['(0b0)','(0b0)s00','(0b1)','(1b0)','(0b1)s00','(1b0)s00',
2643        '(00g)','(00g)s00','(00g)ss0','(0b0)0s0','(a00)','(a00)s00','(a00)ss0','(a00)0s0'],
2644    'B b a b':['(0b0)','(0b0)s00','(1b0)','(0b1)','(1b0)s00','(0b1)s00',
2645        '(a00)','(a00)s00','(a00)ss0','(a00)0s0','(00g)','(00g)s00','(00g)ss0','(00g)0s0'],
2646    'C c c b':['(00g)','(00g)ss0','(01g)','(10g)','(01g)s00','(10g)s00',
2647        '(0b0)','(0b0)s00','(0b0)ss0','(0b0)0s0','(a00)','(a00)s00','(a00)ss0','(a00)0s0'],
2648    'A c a a':['(a00)','(a00)ss0','(a01)','(a10)','(a01)s00','(a10)s00',
2649        '(00g)','(00g)s00','(00g)ss0','(00g)0s0','(0b0)','(0b0)s00','(0b0)ss0','(0b0)0s0'],
2650#69       
2651    'F m m m':['(00g)','(00g)s00','(00g)ss0','(a00)','(a00)s00',
2652        '(a00)ss0','(0b0)','(0b0)s00','(0b0)ss0',
2653        '(10g)','(10g)s00','(10g)ss0','(a10)','(a10)0s0',
2654        '(a10)00s','(a10)0ss','(0b1)','(0b1)s00','(0b1)00s','(0b1)s0s',
2655        '(01g)','(01g)s00','(01g)ss0','(a01)','(a01)0s0',
2656        '(a01)00s','(a01)0ss','(1b0)','(1b0)s00','(1b0)00s','(1b0)s0s'],
2657#70 o@i       
2658    'F d d d':['(00g)','(00g)s00','(a00)','(a00)s00','(0b0)','(0b0)s00'],       
2659#71
2660    'I m m m':['(00g)','(00g)s00','(00g)ss0','(a00)','(a00)0s0',
2661        '(a00)ss0','(0b0)','(0b0)s00','(0b0)ss0'],
2662#72       
2663    'I b a m':['(00g)','(00g)s00','(00g)0s0','(00g)ss0','(a00)','(a00)0s0',
2664        '(a00)00s','(a00)0ss','(0b0)','(0b0)s00','(0b0)00s','(0b0)s0s'],
2665    'I m c b':['(a00)','(a00)0s0','(a00)00s','(a00)0ss','(0b0)','(0b0)00s',
2666        '(0b0)s00','(0b0)s0s','(00g)','(00g)0s0','(00g)s00','(00g)ss0'],
2667    'I c m a':['(0b0)','(0b0)00s','(0b0)s00','(0b0)s0s','(00g)','(00g)s00',
2668        '(00g)0s0','(00g)ss0','(a00)','(a00)00s','(a00)0s0','(a00)0ss'],
2669#73       
2670    'I b c a':['(00g)','(00g)s00','(00g)0s0','(00g)ss0','(a00)','(a00)0s0',
2671        '(a00)00s','(a00)0ss','(0b0)','(0b0)s00','(0b0)00s','(0b0)s0s'],
2672    'I c a b':['(00g)','(00g)s00','(00g)0s0','(00g)ss0','(a00)','(a00)0s0',
2673        '(a00)00s','(a00)0ss','(0b0)','(0b0)s00','(0b0)00s','(0b0)s0s'],
2674#74       
2675    'I m m a':['(00g)','(00g)s00','(00g)0s0','(00g)ss0','(a00)','(a00)0s0',
2676        '(a00)00s','(a00)0ss','(0b0)','(0b0)s00','(0b0)00s','(0b0)s0s'],
2677    'I b m 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 m':['(00g)','(00g)s00','(00g)0s0','(00g)ss0','(a00)','(a00)0s0',
2680        '(a00)00s','(a00)0ss','(0b0)','(0b0)s00','(0b0)00s','(0b0)s0s'],
2681    'I m a m':['(00g)','(00g)s00','(00g)0s0','(00g)ss0','(a00)','(a00)0s0',
2682        '(a00)00s','(a00)0ss','(0b0)','(0b0)s00','(0b0)00s','(0b0)s0s'],
2683    'I m m b':['(00g)','(00g)s00','(00g)0s0','(00g)ss0','(a00)','(a00)0s0',
2684        '(a00)00s','(a00)0ss','(0b0)','(0b0)s00','(0b0)00s','(0b0)s0s'],
2685    'I c m m':['(00g)','(00g)s00','(00g)0s0','(00g)ss0','(a00)','(a00)0s0',
2686        '(a00)00s','(a00)0ss','(0b0)','(0b0)s00','(0b0)00s','(0b0)s0s'],
2687#tetragonal - done
2688#75
2689    'P 4':['(00g)','(00g)q','(00g)s','(1/21/2g)','(1/21/2g)q',],
2690#76
2691    'P 41':['(00g)','(1/21/2g)',],
2692#77
2693    'P 42':['(00g)','(00g)q','(1/21/2g)','(1/21/2g)q',],
2694#78
2695    'P 43':['(00g)','(1/21/2g)',],
2696#79
2697    'I 4':['(00g)','(00g)q','(00g)s',],
2698#80
2699    'I 41':['(00g)','(00g)q',],
2700#81
2701    'P -4':['(00g)','(1/21/2g)',],
2702#82
2703    'I -4':['(00g)',],
2704#83
2705    'P 4/m':['(00g)','(00g)s0','(1/21/2g)',],
2706#84
2707    'P 42/m':['(00g)','(1/21/2g)',],
2708#85 o@i q0 -> 00
2709    'P 4/n':['(00g)','(00g)s0','(1/21/2g)',], #q0?
2710#86 o@i q0 -> 00
2711    'P 42/n':['(00g)','(1/21/2g)',],      #q0?
2712#87
2713    'I 4/m':['(00g)','(00g)s0',],
2714#88
2715    'I 41/a':['(00g)',],
2716#89
2717    'P 4 2 2':['(00g)','(00g)q00','(00g)s00','(1/21/2g)','(1/21/2g)q00',],
2718#90
2719    'P 4 21 2':['(00g)','(00g)q00','(00g)s00',],
2720#91
2721    'P 41 2 2':['(00g)','(1/21/2g)',],
2722#92
2723    'P 41 21 2':['(00g)',],
2724#93
2725    'P 42 2 2':['(00g)','(00g)q00','(1/21/2g)','(1/21/2g)q00',],
2726#94
2727    'P 42 21 2':['(00g)','(00g)q00',],
2728#95
2729    'P 43 2 2':['(00g)','(1/21/2g)',],
2730#96
2731    'P 43 21 2':['(00g)',],
2732#97
2733    'I 4 2 2':['(00g)','(00g)q00','(00g)s00',],
2734#98
2735    'I 41 2 2':['(00g)','(00g)q00',],
2736#99
2737    'P 4 m m':['(00g)','(00g)ss0','(00g)0ss','(00g)s0s','(1/21/2g)','(1/21/2g)0ss'],
2738#100
2739    'P 4 b m':['(00g)','(00g)ss0','(00g)0ss','(00g)s0s','(1/21/2g)qq0','(1/21/2g)qqs',],
2740#101
2741    'P 42 c m':['(00g)','(00g)0ss','(1/21/2g)','(1/21/2g)0ss',],
2742#102
2743    'P 42 n m':['(00g)','(00g)0ss','(1/21/2g)qq0','(1/21/2g)qqs',],
2744#103
2745    'P 4 c c':['(00g)','(00g)ss0','(1/21/2g)',],
2746#104
2747    'P 4 n c':['(00g)','(00g)ss0','(1/21/2g)qq0',],
2748#105
2749    'P 42 m c':['(00g)','(00g)ss0','(1/21/2g)',],
2750#106
2751    'P 42 b c':['(00g)','(00g)ss0','(1/21/2g)qq0',],
2752#107
2753    'I 4 m m':['(00g)','(00g)ss0','(00g)0ss','(00g)s0s',],
2754#108
2755    'I 4 c m':['(00g)','(00g)ss0','(00g)0ss','(00g)s0s',],
2756#109
2757    'I 41 m d':['(00g)','(00g)ss0',],
2758#110
2759    'I 41 c d':['(00g)','(00g)ss0',],
2760#111
2761    'P -4 2 m':['(00g)','(00g)0ss','(1/21/2g)','(1/21/2g)0ss',],
2762#112
2763    'P -4 2 c':['(00g)','(1/21/2g)',],
2764#113
2765    'P -4 21 m':['(00g)','(00g)0ss',],
2766#114
2767    'P -4 21 c':['(00g)',],
2768#115    00s -> 0ss
2769    'P -4 m 2':['(00g)','(00g)0ss','(1/21/2g)',],
2770#116
2771    'P -4 c 2':['(00g)','(1/21/2g)',],
2772#117    00s -> 0ss
2773    'P -4 b 2':['(00g)','(00g)0s0','(1/21/2g)0q0',],
2774#118
2775    'P -4 n 2':['(00g)','(1/21/2g)0q0',],
2776#119
2777    'I -4 m 2':['(00g)','(00g)0s0',],
2778#120
2779    'I -4 c 2':['(00g)','(00g)0s0',],
2780#121    00s -> 0ss
2781    'I -4 2 m':['(00g)','(00g)0ss',],
2782#122
2783    'I -4 2 d':['(00g)',],
2784#123
2785    'P 4/m m m':['(00g)','(00g)s0s0','(00g)00ss','(00g)s00s',
2786        '(1/21/2g)','(1/21/2g)s0s0','(1/21/2g)00ss','(1/21/2g)s00s',],
2787#124
2788    'P 4/m c c':['(00g)','(00g)s0s0','(1/21/2g)',],
2789#125    o@i q0q0 -> 0000, q0qs -> 00ss
2790    'P 4/n b m':['(00g)','(00g)s0s0','(00g)00ss','(00g)s00s','(1/21/2g)','(1/21/2g)00ss',],
2791#126    o@i q0q0 -> 0000
2792    'P 4/n n c':['(00g)','(00g)s0s0','(1/21/2g)',],
2793#127
2794    'P 4/m b m':['(00g)','(00g)s0s0','(00g)00ss','(00g)s00s',],
2795#128
2796    'P 4/m n c':['(00g)','(00g)s0s0',],
2797#129
2798    'P 4/n m m':['(00g)','(00g)s0s0','(00g)00ss','(00g)s00s',],
2799#130
2800    'P 4/n c c':['(00g)','(00g)s0s0',],
2801#131
2802    'P 42/m m c':['(00g)','(00g)s0s0','(1/21/2g)',],
2803#132
2804    'P 42/m c m':['(00g)','(00g)00ss','(1/21/2g)','(1/21/2g)00ss',],
2805#133    o@i q0q0 -> 0000
2806    'P 42/n b c':['(00g)','(00g)s0s0','(1/21/2g)',],
2807#134    o@i q0q0 -> 0000, q0qs -> 00ss
2808    'P 42/n n m':['(00g)','(00g)00ss','(1/21/2g)','(1/21/2g)00ss',],
2809#135
2810    'P 42/m b c':['(00g)','(00g)s0s0',],
2811#136
2812    'P 42/m n m':['(00g)','(00g)00ss',],
2813#137
2814    'P 42/n m c':['(00g)','(00g)s0s0',],
2815#138
2816    'P 42/n c m':['(00g)','(00g)00ss',],
2817#139
2818    'I 4/m m m':['(00g)','(00g)s0s0','(00g)00ss','(00g)s00s',],
2819#140
2820    'I 4/m c m':['(00g)','(00g)s0s0','(00g)00ss','(00g)s00s',],
2821#141
2822    'I 41/a m d':['(00g)','(00g)s0s0',],
2823#142
2824    'I 41/a c d':['(00g)','(00g)s0s0',],
2825    #trigonal/rhombahedral - done & checked
2826#143
2827    'P 3':['(00g)','(00g)t','(1/31/3g)',],
2828#144
2829    'P 31':['(00g)','(1/31/3g)',],
2830#145
2831    'P 32':['(00g)','(1/31/3g)',],
2832#146
2833    'R 3':['(00g)','(00g)t',],
2834#147
2835    'P -3':['(00g)','(1/31/3g)',],
2836#148
2837    'R -3':['(00g)',],
2838#149
2839    'P 3 1 2':['(00g)','(00g)t00','(1/31/3g)',],
2840#150
2841    'P 3 2 1':['(00g)','(00g)t00',],
2842#151
2843    'P 31 1 2':['(00g)','(1/31/3g)',],
2844#152
2845    'P 31 2 1':['(00g)',],
2846#153
2847    'P 32 1 2':['(00g)','(1/31/3g)',],
2848#154
2849    'P 32 2 1':['(00g)',],
2850#155
2851    'R 3 2':['(00g)','(00g)t0',],
2852#156
2853    'P 3 m 1':['(00g)','(00g)0s0',],
2854#157
2855    'P 3 1 m':['(00g)','(00g)00s','(1/31/3g)','(1/31/3g)00s',],
2856#158
2857    'P 3 c 1':['(00g)',],
2858#159
2859    'P 3 1 c':['(00g)','(1/31/3g)',],
2860#160
2861    'R 3 m':['(00g)','(00g)0s',],
2862#161
2863    'R 3 c':['(00g)',],
2864#162
2865    'P -3 1 m':['(00g)','(00g)00s','(1/31/3g)','(1/31/3g)00s',],
2866#163
2867    'P -3 1 c':['(00g)','(1/31/3g)',],
2868#164
2869    'P -3 m 1':['(00g)','(00g)0s0',],
2870#165
2871    'P -3 c 1':['(00g)',],
2872#166       
2873    'R -3 m':['(00g)','(00g)0s',],
2874#167
2875    'R -3 c':['(00g)',],
2876    #hexagonal - done & checked
2877#168
2878    'P 6':['(00g)','(00g)h','(00g)t','(00g)s',],
2879#169
2880    'P 61':['(00g)',],
2881#170
2882    'P 65':['(00g)',],
2883#171
2884    'P 62':['(00g)','(00g)h',],
2885#172
2886    'P 64':['(00g)','(00g)h',],
2887#173
2888    'P 63':['(00g)','(00g)h',],
2889#174
2890    'P -6':['(00g)',],
2891#175
2892    'P 6/m':['(00g)','(00g)s0',],
2893#176
2894    'P 63/m':['(00g)',],
2895#177
2896    'P 6 2 2':['(00g)','(00g)h00','(00g)t00','(00g)s00',],
2897#178
2898    'P 61 2 2':['(00g)',],
2899#179
2900    'P 65 2 2':['(00g)',],
2901#180
2902    'P 62 2 2':['(00g)','(00g)h00',],
2903#181
2904    'P 64 2 2':['(00g)','(00g)h00',],
2905#182
2906    'P 63 2 2':['(00g)','(00g)h00',],
2907#183
2908    'P 6 m m':['(00g)','(00g)ss0','(00g)0ss','(00g)s0s',],
2909#184
2910    'P 6 c c':['(00g)','(00g)s0s',],
2911#185
2912    'P 63 c m':['(00g)','(00g)0ss',],
2913#186
2914    'P 63 m c':['(00g)','(00g)0ss',],
2915#187
2916    'P -6 m 2':['(00g)','(00g)0s0',],
2917#188
2918    'P -6 c 2':['(00g)',],
2919#189
2920    'P -6 2 m':['(00g)','(00g)00s',],
2921#190
2922    'P -6 2 c':['(00g)',],
2923#191
2924    'P 6/m m m':['(00g)','(00g)s0s0','(00g)00ss','(00g)s00s',],
2925#192
2926    'P 6/m c c':['(00g)','(00g)s00s',],
2927#193
2928    'P 63/m c m':['(00g)','(00g)00ss',],
2929#194
2930    'P 63/m m c':['(00g)','(00g)00ss'],
2931    }
2932
2933#'A few non-standard space groups for test use'
2934nonstandard_sglist = ('P 21 1 1','P 1 21 1','P 1 1 21','R 3 r','R 3 2 h', 
2935                      'R -3 r', 'R 3 2 r','R 3 m h', 'R 3 m r',
2936                      'R 3 c r','R -3 c r','R -3 m r',),
2937
2938#A list of orthorhombic space groups that were renamed in the 2002 Volume A,
2939# along with the pre-2002 name. The e designates a double glide-plane'''
2940sgequiv_2002_orthorhombic= (('A e m 2', 'A b m 2',),
2941                            ('A e a 2', 'A b a 2',),
2942                            ('C m c e', 'C m c a',),
2943                            ('C m m e', 'C m m a',),
2944                            ('C c c e', 'C c c a'),)
2945#Use the space groups types in this order to list the symbols in the
2946#order they are listed in the International Tables, vol. A'''
2947symtypelist = ('triclinic', 'monoclinic', 'orthorhombic', 'tetragonal', 
2948               'trigonal', 'hexagonal', 'cubic')
2949
2950# self-test materials follow. Requires files in directory testinp
2951selftestlist = []
2952'''Defines a list of self-tests'''
2953selftestquiet = True
2954def _ReportTest():
2955    'Report name and doc string of current routine when ``selftestquiet`` is False'
2956    if not selftestquiet:
2957        import inspect
2958        caller = inspect.stack()[1][3]
2959        doc = eval(caller).__doc__
2960        if doc is not None:
2961            print('testing '+__file__+' with '+caller+' ('+doc+')')
2962        else:
2963            print('testing '+__file__()+" with "+caller)
2964def test0():
2965    '''self-test #0: exercise MoveToUnitCell'''
2966    _ReportTest()
2967    msg = "MoveToUnitCell failed"
2968    assert (MoveToUnitCell([1,2,3]) == [0,0,0]).all, msg
2969    assert (MoveToUnitCell([2,-1,-2]) == [0,0,0]).all, msg
2970    assert abs(MoveToUnitCell(np.array([-.1]))[0]-0.9) < 1e-6, msg
2971    assert abs(MoveToUnitCell(np.array([.1]))[0]-0.1) < 1e-6, msg
2972selftestlist.append(test0)
2973
2974def test1():
2975    '''self-test #1: SpcGroup against previous results'''
2976    #'''self-test #1: SpcGroup and SGPrint against previous results'''
2977    _ReportTest()
2978    testdir = ospath.join(ospath.split(ospath.abspath( __file__ ))[0],'testinp')
2979    if ospath.exists(testdir):
2980        if testdir not in sys.path: sys.path.insert(0,testdir)
2981    import spctestinp
2982    def CompareSpcGroup(spc, referr, refdict, reflist): 
2983        'Compare output from GSASIIspc.SpcGroup with results from a previous run'
2984        # if an error is reported, the dictionary can be ignored
2985        msg0 = "CompareSpcGroup failed on space group %s" % spc
2986        result = SpcGroup(spc)
2987        if result[0] == referr and referr > 0: return True
2988        keys = result[1].keys()
2989        #print result[1]['SpGrp']
2990        #msg = msg0 + " in list lengths"
2991        #assert len(keys) == len(refdict.keys()), msg
2992        for key in refdict.keys():
2993            if key == 'SGOps' or  key == 'SGCen':
2994                msg = msg0 + (" in key %s length" % key)
2995                assert len(refdict[key]) == len(result[1][key]), msg
2996                for i in range(len(refdict[key])):
2997                    msg = msg0 + (" in key %s level 0" % key)
2998                    assert np.allclose(result[1][key][i][0],refdict[key][i][0]), msg
2999                    msg = msg0 + (" in key %s level 1" % key)
3000                    assert np.allclose(result[1][key][i][1],refdict[key][i][1]), msg
3001            else:
3002                msg = msg0 + (" in key %s" % key)
3003                assert result[1][key] == refdict[key], msg
3004        msg = msg0 + (" in key %s reflist" % key)
3005        #for (l1,l2) in zip(reflist, SGPrint(result[1])):
3006        #    assert l2.replace('\t','').replace(' ','') == l1.replace(' ',''), 'SGPrint ' +msg
3007        # for now disable SGPrint testing, output has changed
3008        #assert reflist == SGPrint(result[1]), 'SGPrint ' +msg
3009    for spc in spctestinp.SGdat:
3010        CompareSpcGroup(spc, 0, spctestinp.SGdat[spc], spctestinp.SGlist[spc] )
3011selftestlist.append(test1)
3012
3013def test2():
3014    '''self-test #2: SpcGroup against cctbx (sgtbx) computations'''
3015    _ReportTest()
3016    testdir = ospath.join(ospath.split(ospath.abspath( __file__ ))[0],'testinp')
3017    if ospath.exists(testdir):
3018        if testdir not in sys.path: sys.path.insert(0,testdir)
3019    import sgtbxtestinp
3020    def CompareWcctbx(spcname, cctbx_in, debug=0):
3021        'Compare output from GSASIIspc.SpcGroup with results from cctbx.sgtbx'
3022        cctbx = cctbx_in[:] # make copy so we don't delete from the original
3023        spc = (SpcGroup(spcname))[1]
3024        if debug: print spc['SpGrp']
3025        if debug: print spc['SGCen']
3026        latticetype = spcname.strip().upper()[0]
3027        # lattice type of R implies Hexagonal centering", fix the rhombohedral settings
3028        if latticetype == "R" and len(spc['SGCen']) == 1: latticetype = 'P'
3029        assert latticetype == spc['SGLatt'], "Failed: %s does not match Lattice: %s" % (spcname, spc['SGLatt'])
3030        onebar = [1]
3031        if spc['SGInv']: onebar.append(-1)
3032        for (op,off) in spc['SGOps']:
3033            for inv in onebar:
3034                for cen in spc['SGCen']:
3035                    noff = off + cen
3036                    noff = MoveToUnitCell(noff)
3037                    mult = tuple((op*inv).ravel().tolist())
3038                    if debug: print "\n%s: %s + %s" % (spcname,mult,noff)
3039                    for refop in cctbx:
3040                        if debug: print refop
3041                        # check the transform
3042                        if refop[:9] != mult: continue
3043                        if debug: print "mult match"
3044                        # check the translation
3045                        reftrans = list(refop[-3:])
3046                        reftrans = MoveToUnitCell(reftrans)
3047                        if all(abs(noff - reftrans) < 1.e-5):
3048                            cctbx.remove(refop)
3049                            break
3050                    else:
3051                        assert False, "failed on %s:\n\t %s + %s" % (spcname,mult,noff)
3052    for key in sgtbxtestinp.sgtbx:
3053        CompareWcctbx(key, sgtbxtestinp.sgtbx[key])
3054selftestlist.append(test2)
3055
3056def test3(): 
3057    '''self-test #3: exercise SytSym (includes GetOprPtrName, GenAtom, GetKNsym)
3058     for selected space groups against info in IT Volume A '''
3059    _ReportTest()
3060    def ExerciseSiteSym (spc, crdlist):
3061        'compare site symmetries and multiplicities for a specified space group'
3062        msg = "failed on site sym test for %s" % spc
3063        (E,S) = SpcGroup(spc)
3064        assert not E, msg
3065        for t in crdlist:
3066            symb, m = SytSym(t[0],S)
3067            if symb.strip() != t[2].strip() or m != t[1]:
3068                print spc,t[0],m,symb,t[2]
3069            assert m == t[1]
3070            #assert symb.strip() == t[2].strip()
3071
3072    ExerciseSiteSym('p 1',[
3073            ((0.13,0.22,0.31),1,'1'),
3074            ((0,0,0),1,'1'),
3075            ])
3076    ExerciseSiteSym('p -1',[
3077            ((0.13,0.22,0.31),2,'1'),
3078            ((0,0.5,0),1,'-1'),
3079            ])
3080    ExerciseSiteSym('C 2/c',[
3081            ((0.13,0.22,0.31),8,'1'),
3082            ((0.0,.31,0.25),4,'2(y)'),
3083            ((0.25,.25,0.5),4,'-1'),
3084            ((0,0.5,0),4,'-1'),
3085            ])
3086    ExerciseSiteSym('p 2 2 2',[
3087            ((0.13,0.22,0.31),4,'1'),
3088            ((0,0.5,.31),2,'2(z)'),
3089            ((0.5,.31,0.5),2,'2(y)'),
3090            ((.11,0,0),2,'2(x)'),
3091            ((0,0.5,0),1,'222'),
3092            ])
3093    ExerciseSiteSym('p 4/n',[
3094            ((0.13,0.22,0.31),8,'1'),
3095            ((0.25,0.75,.31),4,'2(z)'),
3096            ((0.5,0.5,0.5),4,'-1'),
3097            ((0,0.5,0),4,'-1'),
3098            ((0.25,0.25,.31),2,'4(001)'),
3099            ((0.25,.75,0.5),2,'-4(001)'),
3100            ((0.25,.75,0.0),2,'-4(001)'),
3101            ])
3102    ExerciseSiteSym('p 31 2 1',[
3103            ((0.13,0.22,0.31),6,'1'),
3104            ((0.13,0.0,0.833333333),3,'2(100)'),
3105            ((0.13,0.13,0.),3,'2(110)'),
3106            ])
3107    ExerciseSiteSym('R 3 c',[
3108            ((0.13,0.22,0.31),18,'1'),
3109            ((0.0,0.0,0.31),6,'3'),
3110            ])
3111    ExerciseSiteSym('R 3 c R',[
3112            ((0.13,0.22,0.31),6,'1'),
3113            ((0.31,0.31,0.31),2,'3(111)'),
3114            ])
3115    ExerciseSiteSym('P 63 m c',[
3116            ((0.13,0.22,0.31),12,'1'),
3117            ((0.11,0.22,0.31),6,'m(100)'),
3118            ((0.333333,0.6666667,0.31),2,'3m(100)'),
3119            ((0,0,0.31),2,'3m(100)'),
3120            ])
3121    ExerciseSiteSym('I a -3',[
3122            ((0.13,0.22,0.31),48,'1'),
3123            ((0.11,0,0.25),24,'2(x)'),
3124            ((0.11,0.11,0.11),16,'3(111)'),
3125            ((0,0,0),8,'-3(111)'),
3126            ])
3127selftestlist.append(test3)
3128
3129if __name__ == '__main__':
3130    # run self-tests
3131    selftestquiet = False
3132    for test in selftestlist:
3133        test()
3134    print "OK"
Note: See TracBrowser for help on using the repository browser.