source: trunk/GSASIIspc.py @ 1567

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

fixups of some tetragonals & hexagonals - now confirmed by B. Campbell's FINDSSG code

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