source: trunk/GSASIIspc.py @ 1572

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

complete SS indexing, apply hklm extinction rules
cleanup indexing, cell refine, load cell, make new phase, calibration, etc.

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