source: trunk/GSASIIspc.py @ 1699

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

rework the DData window - now shows only one histogram at a time. Eliminate the Show button, Show/Hide? menu item, etc. Show a ListBox? & SpinButton? for histogram selection
some more work on ss special positions

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