source: trunk/GSASIIspc.py @ 1561

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

avoid error on startup with no file name
fix derivative errors for lattice parameters

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Author Revision URL Id
File size: 103.7 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-11-04 16:59:58 +0000 (Tue, 04 Nov 2014) $
12# $Author: vondreele $
13# $Revision: 1561 $
14# $URL: trunk/GSASIIspc.py $
15# $Id: GSASIIspc.py 1561 2014-11-04 16:59:58Z 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: 1561 $")
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 HStrainVals(HSvals,SGData):
1327    laue = SGData['SGLaue']
1328    uniq = SGData['SGUniq']
1329    DIJ = np.zeros(6)
1330    if laue in ['m3','m3m']:
1331        DIJ[:3] = [HSvals[0],HSvals[0],HSvals[0]]
1332    elif laue in ['6/m','6/mmm','3m1','31m','3']:
1333        DIJ[:4] = [HSvals[0],HSvals[0],HSvals[1],HSvals[0]]
1334    elif laue in ['3R','3mR']:
1335        DIJ = [HSvals[0],HSvals[0],HSvals[0],HSvals[1],HSvals[1],HSvals[1]]
1336    elif laue in ['4/m','4/mmm']:
1337        DIJ[:3] = [HSvals[0],HSvals[0],HSvals[1]]
1338    elif laue in ['mmm']:
1339        DIJ[:3] = [HSvals[0],HSvals[1],HSvals[2]]
1340    elif laue in ['2/m']:
1341        DIJ[:3] = [HSvals[0],HSvals[1],HSvals[2]]
1342        if uniq == 'a':
1343            DIJ[5] = HSvals[3]
1344        elif uniq == 'b':
1345            DIJ[4] = HSvals[3]
1346        elif uniq == 'c':
1347            DIJ[3] = HSvals[3]
1348    else:
1349        DIJ = [HSvals[0],HSvals[1],HSvals[2],HSvals[3],HSvals[4],HSvals[5]]
1350    return DIJ
1351
1352def HStrainNames(SGData):
1353    'Needs a doc string'
1354    laue = SGData['SGLaue']
1355    uniq = SGData['SGUniq']
1356    if laue in ['m3','m3m']:
1357        return ['D11','eA']         #add cubic strain term
1358    elif laue in ['6/m','6/mmm','3m1','31m','3']:
1359        return ['D11','D33']
1360    elif laue in ['3R','3mR']:
1361        return ['D11','D12']
1362    elif laue in ['4/m','4/mmm']:
1363        return ['D11','D33']
1364    elif laue in ['mmm']:
1365        return ['D11','D22','D33']
1366    elif laue in ['2/m']:
1367        Dij = ['D11','D22','D33']
1368        if uniq == 'a':
1369            Dij += ['D23']
1370        elif uniq == 'b':
1371            Dij += ['D13']
1372        elif uniq == 'c':
1373            Dij += ['D12']
1374        return Dij
1375    else:
1376        Dij = ['D11','D22','D33','D12','D13','D23']
1377        return Dij
1378   
1379def MustrainCoeff(HKL,SGData):
1380    'Needs a doc string'
1381    #NB: order of terms is the same as returned by MustrainNames
1382    laue = SGData['SGLaue']
1383    uniq = SGData['SGUniq']
1384    h,k,l = HKL
1385    Strm = []
1386    if laue in ['m3','m3m']:
1387        Strm.append(h**4+k**4+l**4)
1388        Strm.append(3.0*((h*k)**2+(h*l)**2+(k*l)**2))
1389    elif laue in ['6/m','6/mmm','3m1']:
1390        Strm.append(h**4+k**4+2.0*k*h**3+2.0*h*k**3+3.0*(h*k)**2)
1391        Strm.append(l**4)
1392        Strm.append(3.0*((h*l)**2+(k*l)**2+h*k*l**2))
1393    elif laue in ['31m','3']:
1394        Strm.append(h**4+k**4+2.0*k*h**3+2.0*h*k**3+3.0*(h*k)**2)
1395        Strm.append(l**4)
1396        Strm.append(3.0*((h*l)**2+(k*l)**2+h*k*l**2))
1397        Strm.append(4.0*h*k*l*(h+k))
1398    elif laue in ['3R','3mR']:
1399        Strm.append(h**4+k**4+l**4)
1400        Strm.append(3.0*((h*k)**2+(h*l)**2+(k*l)**2))
1401        Strm.append(2.0*(h*l**3+l*k**3+k*h**3)+2.0*(l*h**3+k*l**3+l*k**3))
1402        Strm.append(4.0*(k*l*h**2+h*l*k**2+h*k*l**2))
1403    elif laue in ['4/m','4/mmm']:
1404        Strm.append(h**4+k**4)
1405        Strm.append(l**4)
1406        Strm.append(3.0*(h*k)**2)
1407        Strm.append(3.0*((h*l)**2+(k*l)**2))
1408    elif laue in ['mmm']:
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    elif laue in ['2/m']:
1416        Strm.append(h**4)
1417        Strm.append(k**4)
1418        Strm.append(l**4)
1419        Strm.append(3.0*(h*k)**2)
1420        Strm.append(3.0*(h*l)**2)
1421        Strm.append(3.0*(k*l)**2)
1422        if uniq == 'a':
1423            Strm.append(2.0*k*l**3)
1424            Strm.append(2.0*l*k**3)
1425            Strm.append(4.0*k*l*h**2)
1426        elif uniq == 'b':
1427            Strm.append(2.0*l*h**3)
1428            Strm.append(2.0*h*l**3)
1429            Strm.append(4.0*h*l*k**2)
1430        elif uniq == 'c':
1431            Strm.append(2.0*h*k**3)
1432            Strm.append(2.0*k*h**3)
1433            Strm.append(4.0*h*k*l**2)
1434    else:
1435        Strm.append(h**4)
1436        Strm.append(k**4)
1437        Strm.append(l**4)
1438        Strm.append(3.0*(h*k)**2)
1439        Strm.append(3.0*(h*l)**2)
1440        Strm.append(3.0*(k*l)**2)
1441        Strm.append(2.0*k*h**3)
1442        Strm.append(2.0*h*l**3)
1443        Strm.append(2.0*l*k**3)
1444        Strm.append(2.0*h*k**3)
1445        Strm.append(2.0*l*h**3)
1446        Strm.append(2.0*k*l**3)
1447        Strm.append(4.0*k*l*h**2)
1448        Strm.append(4.0*h*l*k**2)
1449        Strm.append(4.0*k*h*l**2)
1450    return Strm
1451   
1452def Muiso2Shkl(muiso,SGData,cell):
1453    "this is to convert isotropic mustrain to generalized Shkls"
1454    import GSASIIlattice as G2lat
1455    A = G2lat.cell2AB(cell)[0]
1456   
1457    def minMus(Shkl,muiso,H,SGData,A):
1458        U = np.inner(A.T,H)
1459        S = np.array(MustrainCoeff(U,SGData))
1460        Sum = np.sqrt(np.sum(np.multiply(S,Shkl[:,np.newaxis]),axis=0))
1461        rad = np.sqrt(np.sum((Sum[:,np.newaxis]*H)**2,axis=1))
1462        return (muiso-rad)**2
1463       
1464    laue = SGData['SGLaue']
1465    PHI = np.linspace(0.,360.,60,True)
1466    PSI = np.linspace(0.,180.,60,True)
1467    X = np.outer(npsind(PHI),npsind(PSI))
1468    Y = np.outer(npcosd(PHI),npsind(PSI))
1469    Z = np.outer(np.ones(np.size(PHI)),npcosd(PSI))
1470    HKL = np.dstack((X,Y,Z))
1471    if laue in ['m3','m3m']:
1472        S0 = [1000.,1000.]
1473    elif laue in ['6/m','6/mmm','3m1']:
1474        S0 = [1000.,1000.,1000.]
1475    elif laue in ['31m','3']:
1476        S0 = [1000.,1000.,1000.,1000.]
1477    elif laue in ['3R','3mR']:
1478        S0 = [1000.,1000.,1000.,1000.]
1479    elif laue in ['4/m','4/mmm']:
1480        S0 = [1000.,1000.,1000.,1000.]
1481    elif laue in ['mmm']:
1482        S0 = [1000.,1000.,1000.,1000.,1000.,1000.]
1483    elif laue in ['2/m']:
1484        S0 = [1000.,1000.,1000.,0.,0.,0.,0.,0.,0.]
1485    else:
1486        S0 = [1000.,1000.,1000.,1000.,1000., 1000.,1000.,1000.,1000.,1000., 
1487            1000.,1000.,0.,0.,0.]
1488    S0 = np.array(S0)
1489    HKL = np.reshape(HKL,(-1,3))
1490    result = so.leastsq(minMus,S0,(np.ones(HKL.shape[0])*muiso,HKL,SGData,A))
1491    return result[0]
1492       
1493def SytSym(XYZ,SGData):
1494    '''
1495    Generates the number of equivalent positions and a site symmetry code for a specified coordinate and space group
1496
1497    :param XYZ: an array, tuple or list containing 3 elements: x, y & z
1498    :param SGData: from SpcGroup
1499    :Returns: a two element tuple:
1500
1501     * The 1st element is a code for the site symmetry (see GetKNsym)
1502     * The 2nd element is the site multiplicity
1503
1504    '''
1505    def PackRot(SGOps):
1506        IRT = []
1507        for ops in SGOps:
1508            M = ops[0]
1509            irt = 0
1510            for j in range(2,-1,-1):
1511                for k in range(2,-1,-1):
1512                    irt *= 3
1513                    irt += M[k][j]
1514            IRT.append(int(irt))
1515        return IRT
1516       
1517    SymName = ''
1518    Mult = 1
1519    Isym = 0
1520    if SGData['SGLaue'] in ['3','3m1','31m','6/m','6/mmm']:
1521        Isym = 1073741824
1522    Jdup = 0
1523    Xeqv = GenAtom(XYZ,SGData,True)
1524    IRT = PackRot(SGData['SGOps'])
1525    L = -1
1526    for ic,cen in enumerate(SGData['SGCen']):
1527        for invers in range(int(SGData['SGInv']+1)):
1528            for io,ops in enumerate(SGData['SGOps']):
1529                irtx = (1-2*invers)*IRT[io]
1530                L += 1
1531                if not Xeqv[L][1]:
1532                    Jdup += 1
1533                    jx = GetOprPtrName(str(irtx))
1534                    if jx[2] < 39:
1535                        Isym += 2**(jx[2]-1)
1536    if Isym == 1073741824: Isym = 0
1537    Mult = len(SGData['SGOps'])*len(SGData['SGCen'])*(int(SGData['SGInv'])+1)/Jdup
1538         
1539    return GetKNsym(str(Isym)),Mult
1540   
1541def ElemPosition(SGData):
1542    ''' Under development.
1543    Object here is to return a list of symmetry element types and locations suitable
1544    for say drawing them.
1545    So far I have the element type... getting all possible locations without lookup may be impossible!
1546    '''
1547    SymElements = []
1548    Inv = SGData['SGInv']
1549    Cen = SGData['SGCen']
1550    eleSym = {-3:['','-1'],-2:['',-6],-1:['2','-4'],0:['3','-3'],1:['4','m'],2:['6',''],3:['1','']}
1551    # get operators & expand if centrosymmetric
1552    Ops = SGData['SGOps']
1553    opM = np.array([op[0].T for op in Ops])
1554    opT = np.array([op[1] for op in Ops])
1555    if Inv:
1556        opM = np.concatenate((opM,-opM))
1557        opT = np.concatenate((opT,-opT))
1558    opMT = zip(opM,opT)
1559    for M,T in opMT[1:]:        #skip I
1560        Dt = int(nl.det(M))
1561        Tr = int(np.trace(M))
1562        Dt = -(Dt-1)/2
1563        Es = eleSym[Tr][Dt]
1564        if Dt:              #rotation-inversion
1565            I = np.eye(3)
1566            if Tr == 1:     #mirrors/glides
1567                if np.any(T):       #glide
1568                    M2 = np.inner(M,M)
1569                    MT = np.inner(M,T)+T
1570                    print 'glide',Es,MT
1571                    print M2
1572                else:               #mirror
1573                    print 'mirror',Es,T
1574                    print I-M
1575                X = [-1,-1,-1]
1576            elif Tr == -3:  # pure inversion
1577                X = np.inner(nl.inv(I-M),T)
1578                print 'inversion',Es,X
1579            else:           #other rotation-inversion
1580                M2 = np.inner(M,M)
1581                MT = np.inner(M,T)+T
1582                print 'rot-inv',Es,MT
1583                print M2
1584                X = [-1,-1,-1]
1585        else:               #rotations
1586            print 'rotation',Es
1587            X = [-1,-1,-1]
1588        #SymElements.append([Es,X])
1589       
1590    return #SymElements
1591   
1592def ApplyStringOps(A,SGData,X,Uij=[]):
1593    'Needs a doc string'
1594    SGOps = SGData['SGOps']
1595    SGCen = SGData['SGCen']
1596    Ax = A.split('+')
1597    Ax[0] = int(Ax[0])
1598    iC = 0
1599    if Ax[0] < 0:
1600        iC = 1
1601    Ax[0] = abs(Ax[0])
1602    nA = Ax[0]%100-1
1603    cA = Ax[0]/100
1604    Cen = SGCen[cA]
1605    M,T = SGOps[nA]
1606    if len(Ax)>1:
1607        cellA = Ax[1].split(',')
1608        cellA = np.array([int(a) for a in cellA])
1609    else:
1610        cellA = np.zeros(3)
1611    newX = (1-2*iC)*(Cen+np.inner(M,X)+T)+cellA
1612    if len(Uij):
1613        U = Uij2U(Uij)
1614        U = np.inner(M,np.inner(U,M).T)
1615        newUij = U2Uij(U)
1616        return [newX,newUij]
1617    else:
1618        return newX
1619       
1620def StringOpsProd(A,B,SGData):
1621    """
1622    Find A*B where A & B are in strings '-' + '100*c+n' + '+ijk'
1623    where '-' indicates inversion, c(>0) is the cell centering operator,
1624    n is operator number from SgOps and ijk are unit cell translations (each may be <0).
1625    Should return resultant string - C. SGData - dictionary using entries:
1626
1627       *  'SGCen': cell centering vectors [0,0,0] at least
1628       *  'SGOps': symmetry operations as [M,T] so that M*x+T = x'
1629
1630    """
1631    SGOps = SGData['SGOps']
1632    SGCen = SGData['SGCen']
1633    #1st split out the cell translation part & work on the operator parts
1634    Ax = A.split('+'); Bx = B.split('+')
1635    Ax[0] = int(Ax[0]); Bx[0] = int(Bx[0])
1636    iC = 0
1637    if Ax[0]*Bx[0] < 0:
1638        iC = 1
1639    Ax[0] = abs(Ax[0]); Bx[0] = abs(Bx[0])
1640    nA = Ax[0]%100-1;  nB = Bx[0]%100-1
1641    cA = Ax[0]/100;  cB = Bx[0]/100
1642    Cen = (SGCen[cA]+SGCen[cB])%1.0
1643    cC = np.nonzero([np.allclose(C,Cen) for C in SGCen])[0][0]
1644    Ma,Ta = SGOps[nA]; Mb,Tb = SGOps[nB]
1645    Mc = np.inner(Ma,Mb.T)
1646#    print Ma,Mb,Mc
1647    Tc = (np.add(np.inner(Mb,Ta)+1.,Tb))%1.0
1648#    print Ta,Tb,Tc
1649#    print [np.allclose(M,Mc)&np.allclose(T,Tc) for M,T in SGOps]
1650    nC = np.nonzero([np.allclose(M,Mc)&np.allclose(T,Tc) for M,T in SGOps])[0][0]
1651    #now the cell translation part
1652    if len(Ax)>1:
1653        cellA = Ax[1].split(',')
1654        cellA = [int(a) for a in cellA]
1655    else:
1656        cellA = [0,0,0]
1657    if len(Bx)>1:
1658        cellB = Bx[1].split(',')
1659        cellB = [int(b) for b in cellB]
1660    else:
1661        cellB = [0,0,0]
1662    cellC = np.add(cellA,cellB)
1663    C = str(((nC+1)+(100*cC))*(1-2*iC))+'+'+ \
1664        str(int(cellC[0]))+','+str(int(cellC[1]))+','+str(int(cellC[2]))
1665    return C
1666           
1667def U2Uij(U):
1668    #returns the UIJ vector U11,U22,U33,U12,U13,U23 from tensor U
1669    return [U[0][0],U[1][1],U[2][2],2.*U[0][1],2.*U[0][2],2.*U[1][2]]
1670   
1671def Uij2U(Uij):
1672    #returns the thermal motion tensor U from Uij as numpy array
1673    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]]])
1674
1675def StandardizeSpcName(spcgroup):
1676    '''Accept a spacegroup name where spaces may have not been used
1677    in the names according to the GSAS convention (spaces between symmetry
1678    for each axis) and return the space group name as used in GSAS
1679    '''
1680    rspc = spcgroup.replace(' ','').upper()
1681    # deal with rhombohedral and hexagonal setting designations
1682    rhomb = ''
1683    if rspc[-1:] == 'R':
1684        rspc = rspc[:-1]
1685        rhomb = ' R'
1686    elif rspc[-1:] == 'H': # hexagonal is assumed and thus can be ignored
1687        rspc = rspc[:-1]
1688    # look for a match in the spacegroup lists
1689    for i in spglist.values():
1690        for spc in i:
1691            if rspc == spc.replace(' ','').upper():
1692                return spc + rhomb
1693    # how about the post-2002 orthorhombic names?
1694    for i,spc in sgequiv_2002_orthorhombic:
1695        if rspc == i.replace(' ','').upper():
1696            return spc
1697    # not found
1698    return ''
1699
1700   
1701spglist = {}
1702'''A dictionary of space groups as ordered and named in the pre-2002 International
1703Tables Volume A, except that spaces are used following the GSAS convention to
1704separate the different crystallographic directions.
1705Note that the symmetry codes here will recognize many non-standard space group
1706symbols with different settings. They are ordered by Laue group
1707'''
1708spglist = {
1709    'P1' : ('P 1','P -1',), # 1-2
1710    'P2/m': ('P 2','P 21','P m','P a','P c','P n',
1711        '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
1712    'C2/m':('C 2','C m','C c','C n',
1713        'C 2/m','C 2/c','C 2/n',),
1714    'Pmmm':('P 2 2 2',
1715        'P 2 2 21','P 2 21 2','P 21 2 2',
1716        'P 21 21 2','P 21 2 21','P 2 21 21',
1717        'P 21 21 21',
1718        'P m m 2','P m 2 m','P 2 m m',
1719        'P m c 21','P c m 21','P 21 m a','P 21 a m','P b 21 m','P m 21 b',
1720        'P c c 2','P 2 a a','P b 2 b',
1721        'P m a 2','P b m 2','P 2 m b','P 2 c m','P c 2 m','P m 2 a',
1722        'P c a 21','P b c 21','P 21 a b','P 21 c a','P c 21 b','P b 21 a',
1723        'P n c 2','P c n 2','P 2 n a','P 2 a n','P b 2 n','P n 2 b',
1724        'P m n 21','P n m 21','P 21 m n','P 21 n m','P n 21 m','P m 21 n',
1725        'P b a 2','P 2 c b','P c 2 a',
1726        'P n a 21','P b n 21','P 21 n b','P 21 c n','P c 21 n','P n 21 a',
1727        'P n n 2','P 2 n n','P n 2 n',
1728        'P m m m','P n n n',
1729        'P c c m','P m a a','P b m b',
1730        'P b a n','P n c b','P c n a',
1731        'P m m a','P m m b','P b m m','P c m m','P m c m','P m a m',
1732        'P n n a','P n n b','P b n n','P c n n','P n c n','P n a n',
1733        'P m n a','P n m b','P b m n','P c n m','P n c m','P m a n',
1734        'P c c a','P c c b','P b a a','P c a a','P b c b','P b a b',
1735        'P b a m','P m c b','P c m a',
1736        'P c c n','P n a a','P b n b',
1737        'P b c m','P c a m','P m c a','P m a b','P b m a','P c m b',
1738        'P n n m','P m n n','P n m n',
1739        'P m m n','P n m m','P m n m',
1740        'P b c n','P c a n','P n c a','P n a b','P b n a','P c n b',
1741        'P b c a','P c a b',
1742        'P n m a','P m n b','P b n m','P c m n','P m c n','P n a m',
1743        ),
1744    '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',
1745        'C m 2 a','C 2 m b','C 2 c m','C c 2 m','C 2 c m',
1746        'C m c a','C m m m','C c c m','C m m a','C c c a','C m c m',),
1747    'Immm':('I 2 2 2','I 21 21 21','I m m m',
1748        'I m m 2','I m 2 m','I 2 m m',
1749        'I b a 2','I 2 c b','I c 2 a',
1750        'I m a 2','I b m 2','I 2 m b','I 2 c m','I c 2 m','I m 2 a',
1751        'I b a m','I m c b','I c m a',
1752        'I b c a','I c a b',
1753        'I m m a','I m m b','I b m m ','I c m m','I m c m','I m a m',),
1754    'Fmmm':('F 2 2 2','F m m m', 'F d d d',
1755        'F m m 2','F m 2 m','F 2 m m',
1756        'F d d 2','F d 2 d','F 2 d d',),
1757    'P4/mmm':('P 4','P 41','P 42','P 43','P -4','P 4/m','P 42/m','P 4/n','P 42/n',
1758        'P 4 2 2','P 4 21 2','P 41 2 2','P 41 21 2','P 42 2 2',
1759        'P 42 21 2','P 43 2 2','P 43 21 2','P 4 m m','P 4 b m','P 42 c m',
1760        'P 42 n m','P 4 c c','P 4 n c','P 42 m c','P 42 b c','P -4 2 m',
1761        'P -4 2 c','P -4 21 m','P -4 21 c','P -4 m 2','P -4 c 2','P -4 b 2',
1762        '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',
1763        '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',
1764        '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',
1765        'P 42/n c m',),
1766    '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',
1767        'I 4 c m','I 41 m d','I 41 c d',
1768        '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',
1769        'I 41/a m d','I 41/a c d'),
1770    'R3-H':('R 3','R -3','R 3 2','R 3 m','R 3 c','R -3 m','R -3 c',),
1771    'P6/mmm': ('P 3','P 31','P 32','P -3','P 3 1 2','P 3 2 1','P 31 1 2',
1772        'P 31 2 1','P 32 1 2','P 32 2 1', 'P 3 m 1','P 3 1 m','P 3 c 1',
1773        'P 3 1 c','P -3 1 m','P -3 1 c','P -3 m 1','P -3 c 1','P 6','P 61',
1774        'P 65','P 62','P 64','P 63','P -6','P 6/m','P 63/m','P 6 2 2',
1775        'P 61 2 2','P 65 2 2','P 62 2 2','P 64 2 2','P 63 2 2','P 6 m m',
1776        'P 6 c c','P 63 c m','P 63 m c','P -6 m 2','P -6 c 2','P -6 2 m',
1777        'P -6 2 c','P 6/m m m','P 6/m c c','P 63/m c m','P 63/m m c',),
1778    'Pm3m': ('P 2 3','P 21 3','P m 3','P n 3','P a 3','P 4 3 2','P 42 3 2',
1779        'P 43 3 2','P 41 3 2','P -4 3 m','P -4 3 n','P m 3 m','P n 3 n',
1780        'P m 3 n','P n 3 m',),
1781    'Im3m':('I 2 3','I 21 3','I m -3','I a -3', 'I 4 3 2','I 41 3 2',
1782        'I -4 3 m', 'I -4 3 d','I m -3 m','I m 3 m','I a -3 d',),
1783    'Fm3m':('F 2 3','F m -3','F d -3','F 4 3 2','F 41 3 2','F -4 3 m',
1784        'F -4 3 c','F m -3 m','F m 3 m','F m -3 c','F d -3 m','F d -3 c',),
1785}
1786
1787ssdict = {}
1788'''A dictionary of superspace group symbols allowed for each entry in spglist
1789(except cubics). Monoclinics are all b-unique setting.
1790'''
1791ssdict = {
1792    'P 1':['(abg)',],'P -1':['(abg)',],
1793    #monoclinic - done
1794    'P 2':['(a0g)','(a1/2g)','(0b0)','(0b0)s','(1/2b0)','(0b1/2)','(1/2b0)s','(0b1/2)s',],
1795    'P 21':['(a0g)','(0b0)','(0b0)s','(1/2b0)','(0b1/2)','(1/2b0)s','(0b1/2)s',],
1796    'P m':['(a0g)','(a0g)s','(a1/2g)','(a1/2g)s','(0b0)','(1/2b0)','(0b1/2)',],
1797    'P a':['(a0g)','(a1/2g)','(a0g)s','(a1/2g)s','(0b0)','(0b1/2)',],
1798    'P c':['(a0g)','(a1/2g)','(a0g)s','(a1/2g)s','(0b0)','(1/2b0)',],
1799    'P n':['(a0g)','(a1/2g)','(a0g)s','(a1/2g)s','(0b0)','(1/2b1/2)',],
1800    'P 2/m':['(a0g)','(a1/2g)','(a0g)0s','(a1/2g)0s',
1801        '(0b0)','(0b0)s0','(1/2b0)','(0b1/2)','(1/2b0)s0','(0b1/2)s0',],
1802    'P 21/m':['(a0g)','(a0g)0s','(0b0)','(0b0)s0',
1803        '(1/2b0)','(0b1/2)','(1/2b0)s0','(0b1/2)s0'],
1804    'P 2/c':['(a0g)','(a1/2g)','(a0g)0s','(a1/2g)0s',
1805        '(0b0)','(0b0)s0','(1/2b0)','(1/2b0)s0',],
1806    'P 2/a':['(a0g)','(a1/2g)','(a0g)0s','(a1/2g)0s',
1807        '(0b0)','(0b0)s0','(0b1/2)','(0b1/2)s0',],
1808    'P 2/n':['(a0g)','(a1/2g)','(a0g)0s','(a1/2g)0s',
1809        '(0b0)','(0b0)s0','(1/2b1/2)','(1/2b1/2)s0',],
1810    'P 21/c':['(a0g)','(a0g)0s','(0b0)','(0b0)s0','(1/2b0)','(1/2b0)s0',],
1811    'P 21/a':['(a0g)','(a0g)0s','(0b0)','(0b0)s0','(0b1/2)','(0b1/2)s0',],
1812    'P 21/n':['(a0g)','(a0g)0s','(0b0)','(0b0)s0','(1/2b1/2)','(1/2b1/2)s0',],
1813    'C 2':['(a0g)','(0b0)','(0b0)s','(0b1/2)','(0b1/2)s',],
1814    'C m':['(a0g)','(a0g)s','(0b0)','(0b1/2)',],
1815    'C c':['(a0g)','(a0g)s','(0b0)',],
1816    'C n':['(a0g)','(a0g)s','(0b0)',],
1817    'C 2/m':['(a0g)','(a0g)0s','(0b0)','(0b0)s0','(0b1/2)','(0b1/2)s0',],
1818    'C 2/c':['(a0g)','(a0g)0s','(0b0)','(0b0)s0',],
1819    'C 2/n':['(a0g)','(a0g)0s','(0b0)','(0b0)s0',],
1820    #orthorhombic   
1821    'P 2 2 2':['(a00)','(0b0)','(00g)','(a00)s00','(0b0)0s0','(00g)00s',
1822        '(a1/20)','(a01/2)','(0b1/2)','(1/2b0)','(01/2g)','(1/20g)',
1823        '(a1/21/2)','(1/2b1/2)','(1/21/2g)',],
1824       
1825    'P 2 2 21':['(a00)','(0b0)','(00g)','(a00)s00','(0b0)0s0',
1826        '(a1/20)','(1/2b0)','(01/2g)','(1/20g)','(1/21/2g)',],
1827    'P 2 21 2':['(a00)','(0b0)','(00g)','(a00)s00','(00g)00s',
1828        '(a01/2)','(1/20g)','(0b1/2)','(1/2b0)','(1/2b1/2)',],
1829    'P 21 2 2':['(a00)','(0b0)','(00g)','(0b0)0s0','(00g)00s',
1830        '(01/2g)','(0b1/2)','(a01/2)','(a1/20)','(a1/21/2)',],
1831       
1832    'P 21 21 2':['(a00)','(0b0)','(00g)','(00g)00s','(a01/2)','(0b1/2)',],
1833    'P 21 2 21':['(a00)','(0b0)','(00g)','(0b0)0s0','(a1/20)','(01/2g)',],
1834    'P 2 21 21':['(a00)','(0b0)','(00g)','(a00)s00','(1/2b0)','(1/20g)',],
1835       
1836    'P 21 21 21':['(a00)','(0b0)','(00g)',],
1837       
1838    'P m m 2':['(a00)','(0b0)','(00g)',
1839        '(a00)s00','(0b0)0s0','(00g)s0s','(00g)ss0','(00g)0ss',
1840        '(a1/20)','(a01/2)','(0b1/2)','(1/2b0)','(01/2g)','(1/20g)',
1841        '(a1/21/2)','(1/2b1/2)','(1/21/2g)',],
1842    'P m 2 m':[],
1843    'P 2 m m':[],
1844       
1845    'P m c 21':[],
1846    'P c m 21':[],
1847    'P 21 m a':[],
1848    'P 21 a m':[],
1849    'P b 21 m':[],
1850    'P m 21 b':[],
1851       
1852    'P c c 2':[],
1853    'P 2 a a':[],
1854    'P b 2 b':[],
1855       
1856    'P m a 2':[],
1857    'P b m 2':[],
1858    'P 2 m b':[],
1859    'P 2 c m':[],
1860    'P c 2 m':[],
1861    'P m 2 a':[],
1862       
1863    'P c a 21':[],
1864    'P b c 21':[],
1865    'P 21 a b':[],
1866    'P 21 c a':[],
1867    'P c 21 b':[],
1868    'P b 21 a':[],
1869       
1870    'P n c 2':[],
1871    'P c n 2':[],
1872    'P 2 n a':[],
1873    'P 2 a n':[],
1874    'P b 2 n':[],
1875    'P n 2 b':[],
1876       
1877    'P m n 21':[],
1878    'P n m 21':[],
1879    'P 21 m n':[],
1880    'P 21 n m':[],
1881    'P n 21 m':[],
1882    'P m 21 n':[],
1883       
1884    'P b a 2':[],
1885    'P 2 c b':[],
1886    'P c 2 a':[],
1887       
1888    'P n a 21':[],
1889    'P b n 21':[],
1890    'P 21 n b':[],
1891    'P 21 c n':[],
1892    'P c 21 n':[],
1893    'P n 21 a':[],
1894       
1895    'P n n 2':[],
1896    'P 2 n n':[],
1897    'P n 2 n':[],
1898       
1899    'P m m m':[],
1900       
1901    'P n n n':[],
1902       
1903    'P c c m':[],
1904    'P m a a':[],
1905    'P b m b':[],
1906       
1907    'P b a n':[],
1908    'P n c b':[],
1909    'P c n a':[],
1910       
1911    'P m m a':[],
1912    'P m m b':[],
1913    'P b m m':[],
1914    'P c m m':[],
1915    'P m c m':[],
1916    'P m a m':[],
1917       
1918    'P n n a':[],
1919    'P n n b':[],
1920    'P b n n':[],
1921    'P c n n':[],
1922    'P n c n':[],
1923    'P n a n':[],
1924       
1925    'P m n a':[],
1926    'P n m b':[],
1927    'P b m n':[],
1928    'P c n m':[],
1929    'P n c m':[],
1930    'P m a n':[],
1931       
1932    'P c c a':[],
1933    'P c c b':[],
1934    'P b a a':[],
1935    'P c a a':[],
1936    'P b c b':[],
1937    'P b a b':[],
1938       
1939    'P b a m':[],
1940    'P m c b':[],
1941    'P c m a':[],
1942       
1943    'P c c n':['(00g)','(00g)s00','(00g)0s0','(00g)ss0','(a00)','(a00)0s0',
1944        '(a00)00s','(a00)0ss','(0b0)','(0b0)s00','(0b0)00s','(0b0)s0s'],
1945    'P n a a':['(00g)','(00g)s00','(00g)0s0','(00g)ss0','(a00)','(a00)0s0',
1946        '(a00)00s','(a00)0ss','(0b0)','(0b0)s00','(0b0)00s','(0b0)s0s'],
1947    'P b n b':['(00g)','(00g)s00','(00g)0s0','(00g)ss0','(a00)','(a00)0s0',
1948        '(a00)00s','(a00)0ss','(0b0)','(0b0)s00','(0b0)00s','(0b0)s0s'],
1949       
1950    'P b c m':[],
1951    'P c a m':[],
1952    'P m c a':[],
1953    'P m a b':[],
1954    'P b m a':[],
1955    'P c m b':[],
1956       
1957    'P n n m':['(00g)','(00g)s00','(00g)0s0','(00g)ss0','(a00)','(a00)0s0',
1958        '(a00)00s','(a00)0ss','(0b0)','(0b0)s00','(0b0)00s','(0b0)s0s'],
1959    'P m n n':['(00g)','(00g)s00','(00g)0s0','(00g)ss0','(a00)','(a00)0s0',
1960        '(a00)00s','(a00)0ss','(0b0)','(0b0)s00','(0b0)00s','(0b0)s0s'],
1961    'P n m n':['(00g)','(00g)s00','(00g)0s0','(00g)ss0','(a00)','(a00)0s0',
1962        '(a00)00s','(a00)0ss','(0b0)','(0b0)s00','(0b0)00s','(0b0)s0s'],
1963       
1964    'P m m n':[],
1965    'P n m m':[],
1966    'P m n m':[],
1967       
1968    'P b c n':['(00g)','(00g)s00','(00g)0s0','(00g)ss0','(a00)','(a00)0s0',
1969        '(a00)00s','(a00)0ss','(0b0)','(0b0)s00','(0b0)00s','(0b0)s0s'],
1970    'P c a n':['(00g)','(00g)s00','(00g)0s0','(00g)ss0','(a00)','(a00)0s0',
1971        '(a00)00s','(a00)0ss','(0b0)','(0b0)s00','(0b0)00s','(0b0)s0s'],
1972    'P n c a':['(00g)','(00g)s00','(00g)0s0','(00g)ss0','(a00)','(a00)0s0',
1973        '(a00)00s','(a00)0ss','(0b0)','(0b0)s00','(0b0)00s','(0b0)s0s'],
1974    'P n a b':['(00g)','(00g)s00','(00g)0s0','(00g)ss0','(a00)','(a00)0s0',
1975        '(a00)00s','(a00)0ss','(0b0)','(0b0)s00','(0b0)00s','(0b0)s0s'],
1976    'P b n a':['(00g)','(00g)s00','(00g)0s0','(00g)ss0','(a00)','(a00)0s0',
1977        '(a00)00s','(a00)0ss','(0b0)','(0b0)s00','(0b0)00s','(0b0)s0s'],
1978    'P c n b':['(00g)','(00g)s00','(00g)0s0','(00g)ss0','(a00)','(a00)0s0',
1979        '(a00)00s','(a00)0ss','(0b0)','(0b0)s00','(0b0)00s','(0b0)s0s'],
1980       
1981    'P b c a':[],
1982    'P c a b':[],
1983       
1984    'P n m a':['(00g)','(00g)s00','(00g)0s0','(00g)ss0','(a00)','(a00)0s0',
1985        '(a00)00s','(a00)0ss','(0b0)','(0b0)s00','(0b0)00s','(0b0)s0s'],
1986    'P m n b':['(00g)','(00g)s00','(00g)0s0','(00g)ss0','(a00)','(a00)0s0',
1987        '(a00)00s','(a00)0ss','(0b0)','(0b0)s00','(0b0)00s','(0b0)s0s'],
1988    'P b n m':['(00g)','(00g)s00','(00g)0s0','(00g)ss0','(a00)','(a00)0s0',
1989        '(a00)00s','(a00)0ss','(0b0)','(0b0)s00','(0b0)00s','(0b0)s0s'],
1990    'P c m n':['(00g)','(00g)s00','(00g)0s0','(00g)ss0','(a00)','(a00)0s0',
1991        '(a00)00s','(a00)0ss','(0b0)','(0b0)s00','(0b0)00s','(0b0)s0s'],
1992    'P m c n':['(00g)','(00g)s00','(00g)0s0','(00g)ss0','(a00)','(a00)0s0',
1993        '(a00)00s','(a00)0ss','(0b0)','(0b0)s00','(0b0)00s','(0b0)s0s'],
1994    'P n a m':['(00g)','(00g)s00','(00g)0s0','(00g)ss0','(a00)','(a00)0s0',
1995        '(a00)00s','(a00)0ss','(0b0)','(0b0)s00','(0b0)00s','(0b0)s0s'],
1996       
1997    'C 2 2 21':['(a00)','(0b0)','(00g)','(10g)','(01g)',],
1998    'C 2 2 2':[],
1999    'C m m 2':[],
2000    'C m c 21':[],
2001    'C c c 2':[],
2002       
2003    'C m 2 m':[],
2004    'C 2 m m':[],
2005       
2006    'C m 2 a':[],
2007    'C 2 m b':[],
2008       
2009    'C 2 c m':[],
2010    'C c 2 m':[],
2011    'C 2 c m':[],
2012       
2013    'C m c a':[],
2014    'C m m m':[],
2015    'C c c m':[],
2016    'C m m a':[],
2017    'C c c a':[],
2018    'C m c m':[],
2019    'I 2 2 2':[],
2020    'I 21 21 21':[],
2021    'I m m m':[],
2022       
2023    'I m m 2':[],
2024    'I m 2 m':[],
2025    'I 2 m m':[],
2026       
2027    'I b a 2':[],
2028    'I 2 c b':[],
2029    'I c 2 a':[],
2030       
2031    'I m a 2':[],
2032    'I b m 2':[],
2033    'I 2 m b':[],
2034       
2035    'I 2 c m':[],
2036    'I c 2 m':[],
2037    'I m 2 a':[],
2038       
2039    'I b a m':['(00g)','(00g)s00','(00g)0s0','(00g)ss0','(a00)','(a00)0s0',
2040        '(a00)00s','(a00)0ss','(0b0)','(0b0)s00','(0b0)00s','(0b0)s0s'],
2041    'I m c b':['(00g)','(00g)s00','(00g)0s0','(00g)ss0','(a00)','(a00)0s0',
2042        '(a00)00s','(a00)0ss','(0b0)','(0b0)s00','(0b0)00s','(0b0)s0s'],
2043    'I c m a':['(00g)','(00g)s00','(00g)0s0','(00g)ss0','(a00)','(a00)0s0',
2044        '(a00)00s','(a00)0ss','(0b0)','(0b0)s00','(0b0)00s','(0b0)s0s'],
2045       
2046    'I b c a':['(00g)','(00g)s00','(00g)0s0','(00g)ss0','(a00)','(a00)0s0',
2047        '(a00)00s','(a00)0ss','(0b0)','(0b0)s00','(0b0)00s','(0b0)s0s'],
2048    'I c a b':['(00g)','(00g)s00','(00g)0s0','(00g)ss0','(a00)','(a00)0s0',
2049        '(a00)00s','(a00)0ss','(0b0)','(0b0)s00','(0b0)00s','(0b0)s0s'],
2050       
2051    'I m m a':['(00g)','(00g)s00','(00g)0s0','(00g)ss0','(a00)','(a00)0s0',
2052        '(a00)00s','(a00)0ss','(0b0)','(0b0)s00','(0b0)00s','(0b0)s0s'],
2053    'I m m b':['(00g)','(00g)s00','(00g)0s0','(00g)ss0','(a00)','(a00)0s0',
2054        '(a00)00s','(a00)0ss','(0b0)','(0b0)s00','(0b0)00s','(0b0)s0s'],
2055    'I b m m ':['(00g)','(00g)s00','(00g)0s0','(00g)ss0','(a00)','(a00)0s0',
2056        '(a00)00s','(a00)0ss','(0b0)','(0b0)s00','(0b0)00s','(0b0)s0s'],
2057    'I c m m':['(00g)','(00g)s00','(00g)0s0','(00g)ss0','(a00)','(a00)0s0',
2058        '(a00)00s','(a00)0ss','(0b0)','(0b0)s00','(0b0)00s','(0b0)s0s'],
2059    'I m c m':['(00g)','(00g)s00','(00g)0s0','(00g)ss0','(a00)','(a00)0s0',
2060        '(a00)00s','(a00)0ss','(0b0)','(0b0)s00','(0b0)00s','(0b0)s0s'],
2061    'I m a m':['(00g)','(00g)s00','(00g)0s0','(00g)ss0','(a00)','(a00)0s0',
2062        '(a00)00s','(a00)0ss','(0b0)','(0b0)s00','(0b0)00s','(0b0)s0s'],
2063       
2064    'F 2 2 2':['(00g)','(00g)s00','(00g)0s0','(00g)ss0','(a00)','(a00)0s0',
2065        '(a00)00s','(a00)0ss','(0b0)','(0b0)s00','(0b0)00s','(0b0)s0s',
2066        '(10g)','(10g)s00','(10g)0s0','(10g)ss0','(a10)','(a10)0s0',
2067        '(a10)00s','(a10)0ss','(0b1)','(0b1)s00','(0b1)00s','(0b1)s0s',
2068        '(01g)','(01g)s00','(01g)0s0','(01g)ss0','(a01)','(a01)0s0',
2069        '(a01)00s','(a01)0ss','(1b0)','(1b0)s00','(1b0)00s','(1b0)s0s'],
2070       
2071    'F m m m':['(00g)','(00g)s00','(00g)0s0','(00g)ss0','(a00)','(a00)0s0',
2072        '(a00)00s','(a00)0ss','(0b0)','(0b0)s00','(0b0)00s','(0b0)s0s',
2073        '(10g)','(10g)s00','(10g)0s0','(10g)ss0','(a10)','(a10)0s0',
2074        '(a10)00s','(a10)0ss','(0b1)','(0b1)s00','(0b1)00s','(0b1)s0s',
2075        '(01g)','(01g)s00','(01g)0s0','(01g)ss0','(a01)','(a01)0s0',
2076        '(a01)00s','(a01)0ss','(1b0)','(1b0)s00','(1b0)00s','(1b0)s0s'],
2077       
2078    'F d d d':['(00g)','(00g)s00','(00g)0s0','(00g)ss0','(a00)','(a00)0s0',
2079        '(a00)00s','(a00)0ss','(0b0)','(0b0)s00','(0b0)00s','(0b0)s0s'],
2080       
2081    'F m m 2':['(00g)','(00g)ss0','(00g)0ss','(00g)s0s','(a00)','(a00)0s0',
2082        '(0b0)','(0b0)s00','(10g)','(10g)ss0','(10g)0ss','(10g)s0s','(a01)','(a01)0s0',
2083        '(1b0)','(1b0)s00','(01g)','(01g)ss0','(01g)0ss','(01g)s0s','(a10)','(a10)0s0',
2084        '(0b1)','(0b1)s00',],
2085       
2086    'F m 2 m':['(0b0)','(0b0)ss0','(0b0)0ss','(0b0)s0s','(a00)','(a00)00s',
2087        '(00g)','(00g)s00','(1b0)','(1b0)ss0','(1b0)0ss','(1b0)s0s','(a01)','(a01)00s',
2088        '(01g)','(01g)s00','(0b1)','(0b1)ss0','(0b1)0ss','(0b1)s0s','(a10)','(a10)00s',
2089        '(10g)','(10g)s00',],
2090       
2091    'F 2 m m':['(a00)','(a00)ss0','(a00)0ss','(a00)s0s','(0b0)','(0b0)00s',
2092        '(00g)','(00g)0s0','(a10)','(a10)ss0','(a10)0ss','(a10)s0s','(0b1)','(0b1)00s',
2093        '(10g)','(10g)0s0','(a01)','(a01)ss0','(a01)0ss','(a01)s0s','(1b0)','(1b0)00s',
2094        '(01g)','(01g)0s0',],
2095       
2096    'F d d 2':['(00g)','(00g)ss0','(00g)0ss','(00g)s0s','(a00)','(a00)0s0',
2097        '(0b0)','(0b0)s00',],
2098    'F d 2 d':['(0b0)','(0b0)ss0','(0b0)0ss','(0b0)s0s','(a00)','(a00)00s',
2099        '(00g)','(00g)s00',],
2100    'F 2 d d':['(a00)','(a00)ss0','(a00)0ss','(a00)s0s','(0b0)','(0b0)00s',
2101        '(00g)','(00g)0s0',],       
2102    #tetragonal - done
2103    'P 4':['(00g)','(00g)q','(00g)s','(1/21/2g)','(1/21/2g)q',],
2104    'P 41':['(00g)','(00g)q','(00g)s','(1/21/2g)','(1/21/2g)q',],
2105    'P 42':['(00g)','(00g)q','(00g)s','(1/21/2g)','(1/21/2g)q',],
2106    'P 43':['(00g)','(00g)q','(00g)s','(1/21/2g)','(1/21/2g)q',],
2107    'P -4':['(00g)','(1/21/2g)',],
2108    'P 4/m':['(00g)','(00g)s0','(1/21/2g)','(1/21/2g)s0',],
2109    'P 42/m':['(00g)','(00g)s0','(1/21/2g)','(1/21/2g)s0',],
2110    'P 4/n':['(00g)','(00g)s0','(1/21/2g)','(1/21/2g)q0',],
2111    'P 42/n':['(00g)','(00g)s0','(1/21/2g)','(1/21/2g)q0',],
2112    'P 4 2 2':['(00g)','(00g)q00','(00g)s00','(1/21/2g)','(1/21/2g)q00','(1/21/2g)s00',],
2113    'P 4 21 2':['(00g)','(00g)q00','(00g)s00',],
2114    'P 41 2 2':['(00g)','(00g)q00','(00g)s00','(1/21/2g)','(1/21/2g)q00','(1/21/2g)s00',],
2115    'P 41 21 2':['(00g)','(00g)q00','(00g)s00',],
2116    'P 42 2 2':['(00g)','(00g)q00','(00g)s00','(1/21/2g)','(1/21/2g)q00','(1/21/2g)s00',],
2117    'P 42 21 2':['(00g)','(00g)q00','(00g)s00',],
2118    'P 43 2 2':['(00g)','(00g)q00','(00g)s00','(1/21/2g)','(1/21/2g)q00','(1/21/2g)s00',],
2119    'P 43 21 2':['(00g)','(00g)q00','(00g)s00',],
2120    'P 4 m m':['(00g)','(00g)ss0','(00g)0ss','(00g)s0s',
2121        '(1/21/2g)','(1/21/2g)ss0','(1/21/2g)0ss','(1/21/2g)s0s',],
2122    'P 4 b m':['(00g)','(00g)ss0','(00g)0ss','(00g)s0s','(1/21/2g)','(1/21/2g)qq0','(1/21/2g)qqs',],
2123    'P 42 c m':['(00g)','(00g)ss0','(00g)0ss','(00g)s0s',
2124        '(1/21/2g)','(1/21/2g)ss0','(1/21/2g)0ss','(1/21/2g)s0s',],
2125    'P 42 n m':['(00g)','(00g)ss0','(00g)0ss','(00g)s0s','(1/21/2g)','(1/21/2g)qq0','(1/21/2g)qqs',],
2126    'P 4 c c':['(00g)','(00g)ss0','(00g)0ss','(00g)s0s',
2127        '(1/21/2g)','(1/21/2g)ss0','(1/21/2g)0ss','(1/21/2g)s0s',],
2128    'P 4 n c':['(00g)','(00g)ss0','(00g)0ss','(00g)s0s','(1/21/2g)','(1/21/2g)qq0','(1/21/2g)qqs'],
2129    'P 42 m c':['(00g)','(00g)ss0','(00g)0ss','(00g)s0s',
2130        '(1/21/2g)','(1/21/2g)ss0','(1/21/2g)0ss','(1/21/2g)s0s',],
2131    'P 42 b c':['(00g)','(00g)ss0','(00g)0ss','(00g)s0s','(1/21/2g)','(1/21/2g)qq0','(1/21/2g)qqs'],
2132    'P -4 2 m':['(00g)','(00g)00s','(1/21/2g)','(1/21/2g)00s',],
2133    'P -4 2 c':['(00g)','(00g)00s',],
2134    'P -4 21 m':['(00g)','(00g)00s',],
2135    'P -4 21 c':['(00g)','(00g)00s',],
2136    'P -4 m 2':['(00g)','(00g)0s0','(1/21/2g)','(1/21/2g)0s0',],
2137    'P -4 c 2':['(00g)','(00g)0s0','(1/21/2g)','(1/21/2g)0s0',],
2138    'P -4 b 2':['(00g)','(00g)0s0','(1/21/2g)','(1/21/2g)0q0',],
2139    'P -4 n 2':['(00g)','(00g)0s0','(1/21/2g)','(1/21/2g)0q0',],
2140    'P 4/m m m':['(00g)','(00g)s0s0','(00g)00ss','(00g)s00s',
2141        '(1/21/2g)','(1/21/2g)s0s0','(1/21/2g)00ss','(1/21/2g)s00s',],
2142    'P 4/m c c':['(00g)','(00g)s0s0','(00g)00ss','(00g)s00s',
2143        '(1/21/2g)','(1/21/2g)s0s0','(1/21/2g)00ss','(1/21/2g)s00s',],
2144    'P 4/n b m':['(00g)','(00g)s0s0','(00g)00ss','(00g)s00s',
2145        '(1/21/2g)','(1/21/2g)q0q0','(1/21/2g)q0qs',],
2146    'P 4/n n c':['(00g)','(00g)s0s0','(00g)00ss','(00g)s00s',
2147        '(1/21/2g)','(1/21/2g)q0q0','(1/21/2g)q0qs',],
2148    'P 4/m b m':['(00g)','(00g)s0s0','(00g)00ss','(00g)s00s',],
2149    'P 4/m n c':['(00g)','(00g)s0s0','(00g)00ss','(00g)s00s',],
2150    'P 4/n m m':['(00g)','(00g)s0s0','(00g)00ss','(00g)s00s',],
2151    'P 4/n c c':['(00g)','(00g)s0s0','(00g)00ss','(00g)s00s',],
2152    'P 42/m m c':['(00g)','(00g)s0s0','(00g)00ss','(00g)s00s',
2153        '(1/21/2g)','(1/21/2g)s0s0','(1/21/2g)00ss','(1/21/2g)s00s',],
2154    'P 42/m c m':['(00g)','(00g)s0s0','(00g)00ss','(00g)s00s',
2155        '(1/21/2g)','(1/21/2g)s0s0','(1/21/2g)00ss','(1/21/2g)s00s',],
2156    'P 42/n b c':['(00g)','(00g)s0s0','(00g)00ss','(00g)s00s',
2157        '(1/21/2g)','(1/21/2g)q0q0','(1/21/2g)q0qs',],
2158    'P 42/n n m':['(00g)','(00g)s0s0','(00g)00ss','(00g)s00s',
2159        '(1/21/2g)','(1/21/2g)q0q0','(1/21/2g)q0qs',],
2160    'P 42/m b c':['(00g)','(00g)s0s0','(00g)00ss','(00g)s00s',],
2161    'P 42/m n m':['(00g)','(00g)s0s0','(00g)00ss','(00g)s00s',],
2162    'P 42/n m c':['(00g)','(00g)s0s0','(00g)00ss','(00g)s00s',],
2163    'P 42/n c m':['(00g)','(00g)s0s0','(00g)00ss','(00g)s00s',],
2164    'I 4':['(00g)','(00g)q','(00g)s',],
2165    'I 41':['(00g)','(00g)q','(00g)s',],
2166    'I -4':['(00g)',],
2167    'I 4/m':['(00g)','(00g)s0',],
2168    'I 41/a':['(00g)','(00g)s0',],  #s0?
2169    'I 4 2 2':['(00g)','(00g)q00','(00g)s00',],
2170    'I 41 2 2':['(00g)','(00g)q00','(00g)s00',],
2171    'I 4 m m':['(00g)','(00g)ss0','(00g)0ss','(00g)s0s',],
2172    'I 4 c m':['(00g)','(00g)ss0','(00g)0ss','(00g)s0s',],
2173    'I 41 m d':['(00g)','(00g)ss0','(00g)0ss','(00g)s0s',],
2174    'I 41 c d':['(00g)','(00g)ss0','(00g)0ss','(00g)s0s',],
2175    'I -4 m 2':['(00g)','(00g)0s0',],
2176    'I -4 c 2':['(00g)','(00g)0s0',],
2177    'I -4 2 m':['(00g)','(00g)00s',],
2178    'I -4 2 d':['(00g)','(00g)00s',],
2179    'I 4/m m m':['(00g)','(00g)s0s0','(00g)00ss','(00g)s00s',],
2180    'I 4/m c m':['(00g)','(00g)s0s0','(00g)00ss','(00g)s00s',],
2181    'I 41/a m d':['(00g)','(00g)s0s0','(00g)00ss','(00g)s00s',],
2182    'I 41/a c d':['(00g)','(00g)s0s0','(00g)00ss','(00g)s00s',],
2183    #trigonal/rhombahedral - done & checked
2184    'R 3':['(00g)','(00g)t',],
2185    'R -3':['(00g)',],
2186    'R 3 2':['(00g)','(00g)t0',],
2187    'R 3 m':['(00g)','(00g)0s',],
2188    'R 3 c':['(00g)','(00g)0s',],   #not 0s0
2189    'R -3 m':['(00g)','(00g)0s',],
2190    'R -3 c':['(00g)','(00g)0s',],  #not 0s0
2191    'P 3':['(00g)','(00g)t','(1/31/3g)','(1/31/3g)t',],
2192    'P 31':['(00g)','(00g)t','(1/31/3g)','(1/31/3g)t',],
2193    'P 32':['(00g)','(00g)t','(1/31/3g)','(1/31/3g)t',],
2194    'P -3':['(00g)','(1/31/3g)',],
2195    'P 3 1 2':['(00g)','(00g)t00','(1/31/3g)','(1/31/3g)t00',],
2196    'P 3 2 1':['(00g)','(00g)t00',],
2197    'P 31 1 2':['(00g)','(00g)t00','(1/31/3g)','(1/31/3g)t00',],
2198    'P 31 2 1':['(00g)','(00g)t00',],
2199    'P 32 1 2':['(00g)','(00g)t00','(1/31/3g)','(1/31/3g)t00',],
2200    'P 32 2 1':['(00g)','(00g)t00',],
2201    'P 3 m 1':['(00g)','(00g)0s0',],
2202    'P 3 1 m':['(00g)','(00g)00s','(1/31/3g)','(1/31/3g)00s',],
2203    'P 3 c 1':['(00g)','(00g)0s0',],
2204    'P 3 1 c':['(00g)','(00g)00s','(1/31/3g)','(1/31/3g)00s',],
2205    'P -3 1 m':['(00g)','(00g)00s','(1/31/3g)','(1/31/3g)00s',],
2206    'P -3 1 c':['(00g)','(00g)00s','(1/31/3g)','(1/31/3g)00s',],
2207    'P -3 m 1':['(00g)','(00g)0s0',],
2208    'P -3 c 1':['(00g)','(00g)0s0',],
2209    #hexagonal - done & checked
2210    'P 6':['(00g)','(00g)h','(00g)t','(00g)s',],
2211    'P 61':['(00g)','(00g)h','(00g)t','(00g)s',],
2212    'P 65':['(00g)','(00g)h','(00g)t','(00g)s',],
2213    'P 62':['(00g)','(00g)h','(00g)t','(00g)s',],
2214    'P 64':['(00g)','(00g)h','(00g)t','(00g)s',],
2215    'P 63':['(00g)','(00g)h','(00g)t','(00g)s',],
2216    'P -6':['(00g)',],
2217    'P 6/m':['(00g)','(00g)s0',],
2218    'P 63/m':['(00g)','(00g)s0'],
2219    'P 6 2 2':['(00g)','(00g)h00','(00g)t00','(00g)s00',],
2220    'P 61 2 2':['(00g)','(00g)h00','(00g)t00','(00g)s00',],
2221    'P 65 2 2':['(00g)','(00g)h00','(00g)t00','(00g)s00',],
2222    'P 62 2 2':['(00g)','(00g)h00','(00g)t00','(00g)s00',],
2223    'P 64 2 2':['(00g)','(00g)h00','(00g)t00','(00g)s00',],
2224    'P 63 2 2':['(00g)','(00g)h00','(00g)t00','(00g)s00',],
2225    'P 6 m m':['(00g)','(00g)ss0','(00g)0ss','(00g)s0s',],
2226    'P 6 c c':['(00g)','(00g)ss0','(00g)0ss','(00g)s0s',],
2227    'P 63 c m':['(00g)','(00g)ss0','(00g)0ss','(00g)s0s',],
2228    'P 63 m c':['(00g)','(00g)ss0','(00g)0ss','(00g)s0s',],
2229    'P -6 m 2':['(00g)','(00g)0s0',],
2230    'P -6 c 2':['(00g)','(00g)0s0',],
2231    'P -6 2 m':['(00g)','(00g)00s',],
2232    'P -6 2 c':['(00g)','(00g)00s',],
2233    'P 6/m m m':['(00g)','(00g)s0s0','(00g)00ss','(00g)s00s',],
2234    'P 6/m c c':['(00g)','(00g)s0s0','(00g)00ss','(00g)s00s',],
2235    'P 63/m c m':['(00g)','(00g)s0s0','(00g)00ss','(00g)s00s',],
2236    'P 63/m m c':['(00g)','(00g)s0s0','(00g)00ss','(00g)s00s',],
2237    }
2238
2239#'A few non-standard space groups for test use'
2240nonstandard_sglist = ('P 21 1 1','P 1 21 1','P 1 1 21','R 3 r','R 3 2 h', 
2241                      'R -3 r', 'R 3 2 r','R 3 m h', 'R 3 m r',
2242                      'R 3 c r','R -3 c r','R -3 m r',),
2243
2244#A list of orthorhombic space groups that were renamed in the 2002 Volume A,
2245# along with the pre-2002 name. The e designates a double glide-plane'''
2246sgequiv_2002_orthorhombic= (('A e m 2', 'A b m 2',),
2247                            ('A e a 2', 'A b a 2',),
2248                            ('C m c e', 'C m c a',),
2249                            ('C m m e', 'C m m a',),
2250                            ('C c c e', 'C c c a'),)
2251#Use the space groups types in this order to list the symbols in the
2252#order they are listed in the International Tables, vol. A'''
2253symtypelist = ('triclinic', 'monoclinic', 'orthorhombic', 'tetragonal', 
2254               'trigonal', 'hexagonal', 'cubic')
2255
2256# self-test materials follow. Requires files in directory testinp
2257selftestlist = []
2258'''Defines a list of self-tests'''
2259selftestquiet = True
2260def _ReportTest():
2261    'Report name and doc string of current routine when ``selftestquiet`` is False'
2262    if not selftestquiet:
2263        import inspect
2264        caller = inspect.stack()[1][3]
2265        doc = eval(caller).__doc__
2266        if doc is not None:
2267            print('testing '+__file__+' with '+caller+' ('+doc+')')
2268        else:
2269            print('testing '+__file__()+" with "+caller)
2270def test0():
2271    '''self-test #0: exercise MoveToUnitCell'''
2272    _ReportTest()
2273    msg = "MoveToUnitCell failed"
2274    assert (MoveToUnitCell([1,2,3]) == [0,0,0]).all, msg
2275    assert (MoveToUnitCell([2,-1,-2]) == [0,0,0]).all, msg
2276    assert abs(MoveToUnitCell(np.array([-.1]))[0]-0.9) < 1e-6, msg
2277    assert abs(MoveToUnitCell(np.array([.1]))[0]-0.1) < 1e-6, msg
2278selftestlist.append(test0)
2279
2280def test1():
2281    '''self-test #1: SpcGroup against previous results'''
2282    #'''self-test #1: SpcGroup and SGPrint against previous results'''
2283    _ReportTest()
2284    testdir = ospath.join(ospath.split(ospath.abspath( __file__ ))[0],'testinp')
2285    if ospath.exists(testdir):
2286        if testdir not in sys.path: sys.path.insert(0,testdir)
2287    import spctestinp
2288    def CompareSpcGroup(spc, referr, refdict, reflist): 
2289        'Compare output from GSASIIspc.SpcGroup with results from a previous run'
2290        # if an error is reported, the dictionary can be ignored
2291        msg0 = "CompareSpcGroup failed on space group %s" % spc
2292        result = SpcGroup(spc)
2293        if result[0] == referr and referr > 0: return True
2294        keys = result[1].keys()
2295        #print result[1]['SpGrp']
2296        #msg = msg0 + " in list lengths"
2297        #assert len(keys) == len(refdict.keys()), msg
2298        for key in refdict.keys():
2299            if key == 'SGOps' or  key == 'SGCen':
2300                msg = msg0 + (" in key %s length" % key)
2301                assert len(refdict[key]) == len(result[1][key]), msg
2302                for i in range(len(refdict[key])):
2303                    msg = msg0 + (" in key %s level 0" % key)
2304                    assert np.allclose(result[1][key][i][0],refdict[key][i][0]), msg
2305                    msg = msg0 + (" in key %s level 1" % key)
2306                    assert np.allclose(result[1][key][i][1],refdict[key][i][1]), msg
2307            else:
2308                msg = msg0 + (" in key %s" % key)
2309                assert result[1][key] == refdict[key], msg
2310        msg = msg0 + (" in key %s reflist" % key)
2311        #for (l1,l2) in zip(reflist, SGPrint(result[1])):
2312        #    assert l2.replace('\t','').replace(' ','') == l1.replace(' ',''), 'SGPrint ' +msg
2313        # for now disable SGPrint testing, output has changed
2314        #assert reflist == SGPrint(result[1]), 'SGPrint ' +msg
2315    for spc in spctestinp.SGdat:
2316        CompareSpcGroup(spc, 0, spctestinp.SGdat[spc], spctestinp.SGlist[spc] )
2317selftestlist.append(test1)
2318
2319def test2():
2320    '''self-test #2: SpcGroup against cctbx (sgtbx) computations'''
2321    _ReportTest()
2322    testdir = ospath.join(ospath.split(ospath.abspath( __file__ ))[0],'testinp')
2323    if ospath.exists(testdir):
2324        if testdir not in sys.path: sys.path.insert(0,testdir)
2325    import sgtbxtestinp
2326    def CompareWcctbx(spcname, cctbx_in, debug=0):
2327        'Compare output from GSASIIspc.SpcGroup with results from cctbx.sgtbx'
2328        cctbx = cctbx_in[:] # make copy so we don't delete from the original
2329        spc = (SpcGroup(spcname))[1]
2330        if debug: print spc['SpGrp']
2331        if debug: print spc['SGCen']
2332        latticetype = spcname.strip().upper()[0]
2333        # lattice type of R implies Hexagonal centering", fix the rhombohedral settings
2334        if latticetype == "R" and len(spc['SGCen']) == 1: latticetype = 'P'
2335        assert latticetype == spc['SGLatt'], "Failed: %s does not match Lattice: %s" % (spcname, spc['SGLatt'])
2336        onebar = [1]
2337        if spc['SGInv']: onebar.append(-1)
2338        for (op,off) in spc['SGOps']:
2339            for inv in onebar:
2340                for cen in spc['SGCen']:
2341                    noff = off + cen
2342                    noff = MoveToUnitCell(noff)
2343                    mult = tuple((op*inv).ravel().tolist())
2344                    if debug: print "\n%s: %s + %s" % (spcname,mult,noff)
2345                    for refop in cctbx:
2346                        if debug: print refop
2347                        # check the transform
2348                        if refop[:9] != mult: continue
2349                        if debug: print "mult match"
2350                        # check the translation
2351                        reftrans = list(refop[-3:])
2352                        reftrans = MoveToUnitCell(reftrans)
2353                        if all(abs(noff - reftrans) < 1.e-5):
2354                            cctbx.remove(refop)
2355                            break
2356                    else:
2357                        assert False, "failed on %s:\n\t %s + %s" % (spcname,mult,noff)
2358    for key in sgtbxtestinp.sgtbx:
2359        CompareWcctbx(key, sgtbxtestinp.sgtbx[key])
2360selftestlist.append(test2)
2361
2362def test3(): 
2363    '''self-test #3: exercise SytSym (includes GetOprPtrName, GenAtom, GetKNsym)
2364     for selected space groups against info in IT Volume A '''
2365    _ReportTest()
2366    def ExerciseSiteSym (spc, crdlist):
2367        'compare site symmetries and multiplicities for a specified space group'
2368        msg = "failed on site sym test for %s" % spc
2369        (E,S) = SpcGroup(spc)
2370        assert not E, msg
2371        for t in crdlist:
2372            symb, m = SytSym(t[0],S)
2373            if symb.strip() != t[2].strip() or m != t[1]:
2374                print spc,t[0],m,symb,t[2]
2375            assert m == t[1]
2376            #assert symb.strip() == t[2].strip()
2377
2378    ExerciseSiteSym('p 1',[
2379            ((0.13,0.22,0.31),1,'1'),
2380            ((0,0,0),1,'1'),
2381            ])
2382    ExerciseSiteSym('p -1',[
2383            ((0.13,0.22,0.31),2,'1'),
2384            ((0,0.5,0),1,'-1'),
2385            ])
2386    ExerciseSiteSym('C 2/c',[
2387            ((0.13,0.22,0.31),8,'1'),
2388            ((0.0,.31,0.25),4,'2(y)'),
2389            ((0.25,.25,0.5),4,'-1'),
2390            ((0,0.5,0),4,'-1'),
2391            ])
2392    ExerciseSiteSym('p 2 2 2',[
2393            ((0.13,0.22,0.31),4,'1'),
2394            ((0,0.5,.31),2,'2(z)'),
2395            ((0.5,.31,0.5),2,'2(y)'),
2396            ((.11,0,0),2,'2(x)'),
2397            ((0,0.5,0),1,'222'),
2398            ])
2399    ExerciseSiteSym('p 4/n',[
2400            ((0.13,0.22,0.31),8,'1'),
2401            ((0.25,0.75,.31),4,'2(z)'),
2402            ((0.5,0.5,0.5),4,'-1'),
2403            ((0,0.5,0),4,'-1'),
2404            ((0.25,0.25,.31),2,'4(001)'),
2405            ((0.25,.75,0.5),2,'-4(001)'),
2406            ((0.25,.75,0.0),2,'-4(001)'),
2407            ])
2408    ExerciseSiteSym('p 31 2 1',[
2409            ((0.13,0.22,0.31),6,'1'),
2410            ((0.13,0.0,0.833333333),3,'2(100)'),
2411            ((0.13,0.13,0.),3,'2(110)'),
2412            ])
2413    ExerciseSiteSym('R 3 c',[
2414            ((0.13,0.22,0.31),18,'1'),
2415            ((0.0,0.0,0.31),6,'3'),
2416            ])
2417    ExerciseSiteSym('R 3 c R',[
2418            ((0.13,0.22,0.31),6,'1'),
2419            ((0.31,0.31,0.31),2,'3(111)'),
2420            ])
2421    ExerciseSiteSym('P 63 m c',[
2422            ((0.13,0.22,0.31),12,'1'),
2423            ((0.11,0.22,0.31),6,'m(100)'),
2424            ((0.333333,0.6666667,0.31),2,'3m(100)'),
2425            ((0,0,0.31),2,'3m(100)'),
2426            ])
2427    ExerciseSiteSym('I a -3',[
2428            ((0.13,0.22,0.31),48,'1'),
2429            ((0.11,0,0.25),24,'2(x)'),
2430            ((0.11,0.11,0.11),16,'3(111)'),
2431            ((0,0,0),8,'-3(111)'),
2432            ])
2433selftestlist.append(test3)
2434
2435if __name__ == '__main__':
2436    # run self-tests
2437    selftestquiet = False
2438    for test in selftestlist:
2439        test()
2440    print "OK"
Note: See TracBrowser for help on using the repository browser.