source: trunk/GSASIIspc.py @ 1715

Last change on this file since 1715 was 1715, checked in by vondreele, 8 years ago

make plot styles global instead of individual; now qplot, dplot work for multiplots

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