source: trunk/GSASIIspc.py @ 2402

Last change on this file since 2402 was 2402, checked in by vondreele, 5 years ago

a patch for use of old fortran binaries

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