source: trunk/GSASIIspc.py @ 1565

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

super symmetry stuff - all complete except orthorhombic

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