source: trunk/GSASIIspc.py @ 3136

Last change on this file since 3136 was 3136, checked in by vondreele, 6 years ago

make GSAS-II python 3.6 compliant & preserve python 2.7 use;changes:
do from future import division, print_function for all GSAS-II py sources
all menu items revised to be py 2.7/3.6 compliant
all wx.OPEN --> wx.FD_OPEN in file dialogs
all integer divides (typically for image pixel math) made explicit with ; ambiguous ones made floats as appropriate
all print "stuff" --> print (stuff)
all print >> pFile,'stuff' --> pFile.writeCIFtemplate('stuff')
all read file opens made explicit 'r' or 'rb'
all cPickle imports made for py2.7 or 3.6 as cPickle or _pickle; test for '2' platform.version_tuple[0] for py 2.7
define cPickleload to select load(fp) or load(fp,encoding='latin-1') for loading gpx files; provides cross compatibility between py 2.7/3.6 gpx files
make dict.keys() as explicit list(dict.keys()) as needed (NB: possible source of remaining py3.6 bugs)
make zip(a,b) as explicit list(zip(a,b)) as needed (NB: possible source of remaining py3.6 bugs)
select unichr/chr according test for '2' platform.version_tuple[0] for py 2.7 (G2pwdGUI * G2plot) for special characters
select wg.EVT_GRID_CELL_CHANGE (classic) or wg.EVT_GRID_CELL_CHANGED (phoenix) in grid Bind
maxint --> maxsize; used in random number stuff
raise Exception,"stuff" --> raise Exception("stuff")
wx 'classic' sizer.DeleteWindows?() or 'phoenix' sizer.Clear(True)
wx 'classic' SetToolTipString?(text) or 'phoenix' SetToolTip?(wx.ToolTip?(text)); define SetToolTipString?(self,text) to handle the choice in plots
status.SetFields? --> status.SetStatusText?
'classic' AddSimpleTool? or 'phoenix' self.AddTool? for plot toolbar; Bind different as well
define GetItemPydata? as it doesn't exist in wx 'phoenix'
allow python versions 2.7 & 3.6 to run GSAS-II
Bind override commented out - no logging capability (NB: remove all logging code?)
all import ContentsValidator? open filename & test if valid then close; filepointer removed from Reader
binary importers (mostly images) test for 'byte' type & convert as needed to satisfy py 3.6 str/byte rules

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