source: trunk/GSASIIspc.py @ 1569

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

Make 222, mm2, m2m & 2mm SS work. Fill some SS choices

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