source: trunk/GSASIIspc.py @ 1548

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

more super structure stuff - now some in unit cell indexing
now using pulldown ComboBoxes? for supersymmetry choices
continue building tables of supersymmetry codes
use deepcopy for peaks in various places; copy wasn't enough
get seq. peak fit to stop when a refinement goes bad; then allow display of results

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