source: trunk/GSASIIstrMath.py @ 4662

Last change on this file since 4662 was 4662, checked in by toby, 12 months ago

improve error message

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Author Revision URL Id
File size: 225.0 KB
Line 
1# -*- coding: utf-8 -*-
2'''
3*GSASIIstrMath - structure math routines*
4-----------------------------------------
5'''
6########### SVN repository information ###################
7# $Date: 2020-11-28 17:33:01 +0000 (Sat, 28 Nov 2020) $
8# $Author: toby $
9# $Revision: 4662 $
10# $URL: trunk/GSASIIstrMath.py $
11# $Id: GSASIIstrMath.py 4662 2020-11-28 17:33:01Z toby $
12########### SVN repository information ###################
13from __future__ import division, print_function
14import time
15import copy
16import numpy as np
17import numpy.ma as ma
18import numpy.linalg as nl
19import scipy.stats as st
20import multiprocessing as mp
21import GSASIIpath
22GSASIIpath.SetVersionNumber("$Revision: 4662 $")
23import GSASIIElem as G2el
24import GSASIIlattice as G2lat
25import GSASIIspc as G2spc
26import GSASIIpwd as G2pwd
27import GSASIImapvars as G2mv
28import GSASIImath as G2mth
29import GSASIIobj as G2obj
30import GSASIImpsubs as G2mp
31#G2mp.InitMP(False)  # This disables multiprocessing
32
33sind = lambda x: np.sin(x*np.pi/180.)
34cosd = lambda x: np.cos(x*np.pi/180.)
35tand = lambda x: np.tan(x*np.pi/180.)
36asind = lambda x: 180.*np.arcsin(x)/np.pi
37acosd = lambda x: 180.*np.arccos(x)/np.pi
38atan2d = lambda y,x: 180.*np.arctan2(y,x)/np.pi
39   
40try:  # fails on doc build
41    ateln2 = 8.0*np.log(2.0)
42    twopi = 2.0*np.pi
43    twopisq = 2.0*np.pi**2
44except TypeError:
45    pass
46nxs = np.newaxis
47
48################################################################################
49##### Rigid Body Models
50################################################################################
51       
52def ApplyRBModels(parmDict,Phases,rigidbodyDict,Update=False):
53    ''' Takes RB info from RBModels in Phase and RB data in rigidbodyDict along with
54    current RB values in parmDict & modifies atom contents (xyz & Uij) of parmDict
55    '''
56    atxIds = ['Ax:','Ay:','Az:']
57    atuIds = ['AU11:','AU22:','AU33:','AU12:','AU13:','AU23:']
58    RBIds = rigidbodyDict.get('RBIds',{'Vector':[],'Residue':[]})  #these are lists of rbIds
59    if not RBIds['Vector'] and not RBIds['Residue']:
60        return
61    VRBIds = RBIds['Vector']
62    RRBIds = RBIds['Residue']
63    if Update:
64        RBData = rigidbodyDict
65    else:
66        RBData = copy.deepcopy(rigidbodyDict)     # don't mess with original!
67    if RBIds['Vector']:                       # first update the vector magnitudes
68        VRBData = RBData['Vector']
69        for i,rbId in enumerate(VRBIds):
70            if VRBData[rbId]['useCount']:
71                for j in range(len(VRBData[rbId]['VectMag'])):
72                    name = '::RBV;'+str(j)+':'+str(i)
73                    VRBData[rbId]['VectMag'][j] = parmDict[name]
74    for phase in Phases:
75        Phase = Phases[phase]
76        General = Phase['General']
77        cx,ct,cs,cia = General['AtomPtrs']
78        cell = General['Cell'][1:7]
79        Amat,Bmat = G2lat.cell2AB(cell)
80        AtLookup = G2mth.FillAtomLookUp(Phase['Atoms'],cia+8)
81        pfx = str(Phase['pId'])+'::'
82        if Update:
83            RBModels = Phase['RBModels']
84        else:
85            RBModels =  copy.deepcopy(Phase['RBModels']) # again don't mess with original!
86        for irb,RBObj in enumerate(RBModels.get('Vector',[])):
87            jrb = VRBIds.index(RBObj['RBId'])
88            rbsx = str(irb)+':'+str(jrb)
89            for i,px in enumerate(['RBVPx:','RBVPy:','RBVPz:']):
90                RBObj['Orig'][0][i] = parmDict[pfx+px+rbsx]
91            for i,po in enumerate(['RBVOa:','RBVOi:','RBVOj:','RBVOk:']):
92                RBObj['Orient'][0][i] = parmDict[pfx+po+rbsx]
93            RBObj['Orient'][0] = G2mth.normQ(RBObj['Orient'][0])
94            TLS = RBObj['ThermalMotion']
95            if 'T' in TLS[0]:
96                for i,pt in enumerate(['RBVT11:','RBVT22:','RBVT33:','RBVT12:','RBVT13:','RBVT23:']):
97                    TLS[1][i] = parmDict[pfx+pt+rbsx]
98            if 'L' in TLS[0]:
99                for i,pt in enumerate(['RBVL11:','RBVL22:','RBVL33:','RBVL12:','RBVL13:','RBVL23:']):
100                    TLS[1][i+6] = parmDict[pfx+pt+rbsx]
101            if 'S' in TLS[0]:
102                for i,pt in enumerate(['RBVS12:','RBVS13:','RBVS21:','RBVS23:','RBVS31:','RBVS32:','RBVSAA:','RBVSBB:']):
103                    TLS[1][i+12] = parmDict[pfx+pt+rbsx]
104            if 'U' in TLS[0]:
105                TLS[1][0] = parmDict[pfx+'RBVU:'+rbsx]
106            XYZ,Cart = G2mth.UpdateRBXYZ(Bmat,RBObj,RBData,'Vector')
107            UIJ = G2mth.UpdateRBUIJ(Bmat,Cart,RBObj)
108            for i,x in enumerate(XYZ):
109                atId = RBObj['Ids'][i]
110                for j in [0,1,2]:
111                    parmDict[pfx+atxIds[j]+str(AtLookup[atId])] = x[j]
112                if UIJ[i][0] == 'A':
113                    for j in range(6):
114                        parmDict[pfx+atuIds[j]+str(AtLookup[atId])] = UIJ[i][j+2]
115                elif UIJ[i][0] == 'I':
116                    parmDict[pfx+'AUiso:'+str(AtLookup[atId])] = UIJ[i][1]
117           
118        for irb,RBObj in enumerate(RBModels.get('Residue',[])):
119            jrb = RRBIds.index(RBObj['RBId'])
120            rbsx = str(irb)+':'+str(jrb)
121            for i,px in enumerate(['RBRPx:','RBRPy:','RBRPz:']):
122                RBObj['Orig'][0][i] = parmDict[pfx+px+rbsx]
123            for i,po in enumerate(['RBROa:','RBROi:','RBROj:','RBROk:']):
124                RBObj['Orient'][0][i] = parmDict[pfx+po+rbsx]               
125            RBObj['Orient'][0] = G2mth.normQ(RBObj['Orient'][0])
126            TLS = RBObj['ThermalMotion']
127            if 'T' in TLS[0]:
128                for i,pt in enumerate(['RBRT11:','RBRT22:','RBRT33:','RBRT12:','RBRT13:','RBRT23:']):
129                    RBObj['ThermalMotion'][1][i] = parmDict[pfx+pt+rbsx]
130            if 'L' in TLS[0]:
131                for i,pt in enumerate(['RBRL11:','RBRL22:','RBRL33:','RBRL12:','RBRL13:','RBRL23:']):
132                    RBObj['ThermalMotion'][1][i+6] = parmDict[pfx+pt+rbsx]
133            if 'S' in TLS[0]:
134                for i,pt in enumerate(['RBRS12:','RBRS13:','RBRS21:','RBRS23:','RBRS31:','RBRS32:','RBRSAA:','RBRSBB:']):
135                    RBObj['ThermalMotion'][1][i+12] = parmDict[pfx+pt+rbsx]
136            if 'U' in TLS[0]:
137                RBObj['ThermalMotion'][1][0] = parmDict[pfx+'RBRU:'+rbsx]
138            for itors,tors in enumerate(RBObj['Torsions']):
139                tors[0] = parmDict[pfx+'RBRTr;'+str(itors)+':'+rbsx]
140            XYZ,Cart = G2mth.UpdateRBXYZ(Bmat,RBObj,RBData,'Residue')
141            UIJ = G2mth.UpdateRBUIJ(Bmat,Cart,RBObj)
142            for i,x in enumerate(XYZ):
143                atId = RBObj['Ids'][i]
144                for j in [0,1,2]:
145                    parmDict[pfx+atxIds[j]+str(AtLookup[atId])] = x[j]
146                if UIJ[i][0] == 'A':
147                    for j in range(6):
148                        parmDict[pfx+atuIds[j]+str(AtLookup[atId])] = UIJ[i][j+2]
149                elif UIJ[i][0] == 'I':
150                    parmDict[pfx+'AUiso:'+str(AtLookup[atId])] = UIJ[i][1]
151                   
152def ApplyRBModelDervs(dFdvDict,parmDict,rigidbodyDict,Phase):
153    'Computes rigid body derivatives'
154    atxIds = ['dAx:','dAy:','dAz:']
155    atuIds = ['AU11:','AU22:','AU33:','AU12:','AU13:','AU23:']
156    OIds = ['Oa:','Oi:','Oj:','Ok:']
157    RBIds = rigidbodyDict.get('RBIds',{'Vector':[],'Residue':[]})  #these are lists of rbIds
158    if not RBIds['Vector'] and not RBIds['Residue']:
159        return
160    VRBIds = RBIds['Vector']
161    RRBIds = RBIds['Residue']
162    RBData = rigidbodyDict
163    for item in parmDict:
164        if 'RB' in item:
165            dFdvDict[item] = 0.        #NB: this is a vector which is no. refl. long & must be filled!
166    General = Phase['General']
167    cx,ct,cs,cia = General['AtomPtrs']
168    cell = General['Cell'][1:7]
169    Amat,Bmat = G2lat.cell2AB(cell)
170    rpd = np.pi/180.
171    rpd2 = rpd**2
172    g = nl.inv(np.inner(Bmat,Bmat))
173    gvec = np.sqrt(np.array([g[0][0]**2,g[1][1]**2,g[2][2]**2,
174        g[0][0]*g[1][1],g[0][0]*g[2][2],g[1][1]*g[2][2]]))
175    AtLookup = G2mth.FillAtomLookUp(Phase['Atoms'],cia+8)
176    pfx = str(Phase['pId'])+'::'
177    RBModels =  Phase['RBModels']
178    for irb,RBObj in enumerate(RBModels.get('Vector',[])):
179        symAxis = RBObj.get('symAxis')
180        VModel = RBData['Vector'][RBObj['RBId']]
181        Q = RBObj['Orient'][0]
182        jrb = VRBIds.index(RBObj['RBId'])
183        rbsx = str(irb)+':'+str(jrb)
184        dXdv = []
185        for iv in range(len(VModel['VectMag'])):
186            dCdv = []
187            for vec in VModel['rbVect'][iv]:
188                dCdv.append(G2mth.prodQVQ(Q,vec))
189            dXdv.append(np.inner(Bmat,np.array(dCdv)).T)
190        XYZ,Cart = G2mth.UpdateRBXYZ(Bmat,RBObj,RBData,'Vector')
191        for ia,atId in enumerate(RBObj['Ids']):
192            atNum = AtLookup[atId]
193            dx = 0.00001
194            for iv in range(len(VModel['VectMag'])):
195                for ix in [0,1,2]:
196                    dFdvDict['::RBV;'+str(iv)+':'+str(jrb)] += dXdv[iv][ia][ix]*dFdvDict[pfx+atxIds[ix]+str(atNum)]
197            for i,name in enumerate(['RBVPx:','RBVPy:','RBVPz:']):
198                dFdvDict[pfx+name+rbsx] += dFdvDict[pfx+atxIds[i]+str(atNum)]
199            for iv in range(4):
200                Q[iv] -= dx
201                XYZ1 = G2mth.RotateRBXYZ(Bmat,Cart,G2mth.normQ(Q),symAxis)
202                Q[iv] += 2.*dx
203                XYZ2 = G2mth.RotateRBXYZ(Bmat,Cart,G2mth.normQ(Q),symAxis)
204                Q[iv] -= dx
205                dXdO = (XYZ2[ia]-XYZ1[ia])/(2.*dx)
206                for ix in [0,1,2]:
207                    dFdvDict[pfx+'RBV'+OIds[iv]+rbsx] += dXdO[ix]*dFdvDict[pfx+atxIds[ix]+str(atNum)]
208            X = G2mth.prodQVQ(Q,Cart[ia])
209            dFdu = np.array([dFdvDict[pfx+Uid+str(AtLookup[atId])] for Uid in atuIds]).T/gvec
210            dFdu = G2lat.U6toUij(dFdu.T)
211            dFdu = np.tensordot(Amat,np.tensordot(Amat,dFdu,([1,0])),([0,1]))           
212            dFdu = G2lat.UijtoU6(dFdu)
213            atNum = AtLookup[atId]
214            if 'T' in RBObj['ThermalMotion'][0]:
215                for i,name in enumerate(['RBVT11:','RBVT22:','RBVT33:','RBVT12:','RBVT13:','RBVT23:']):
216                    dFdvDict[pfx+name+rbsx] += dFdu[i]
217            if 'L' in RBObj['ThermalMotion'][0]:
218                dFdvDict[pfx+'RBVL11:'+rbsx] += rpd2*(dFdu[1]*X[2]**2+dFdu[2]*X[1]**2-dFdu[5]*X[1]*X[2])
219                dFdvDict[pfx+'RBVL22:'+rbsx] += rpd2*(dFdu[0]*X[2]**2+dFdu[2]*X[0]**2-dFdu[4]*X[0]*X[2])
220                dFdvDict[pfx+'RBVL33:'+rbsx] += rpd2*(dFdu[0]*X[1]**2+dFdu[1]*X[0]**2-dFdu[3]*X[0]*X[1])
221                dFdvDict[pfx+'RBVL12:'+rbsx] += rpd2*(-dFdu[3]*X[2]**2-2.*dFdu[2]*X[0]*X[1]+
222                    dFdu[4]*X[1]*X[2]+dFdu[5]*X[0]*X[2])
223                dFdvDict[pfx+'RBVL13:'+rbsx] += rpd2*(-dFdu[4]*X[1]**2-2.*dFdu[1]*X[0]*X[2]+
224                    dFdu[3]*X[1]*X[2]+dFdu[5]*X[0]*X[1])
225                dFdvDict[pfx+'RBVL23:'+rbsx] += rpd2*(-dFdu[5]*X[0]**2-2.*dFdu[0]*X[1]*X[2]+
226                    dFdu[3]*X[0]*X[2]+dFdu[4]*X[0]*X[1])
227            if 'S' in RBObj['ThermalMotion'][0]:
228                dFdvDict[pfx+'RBVS12:'+rbsx] += rpd*(dFdu[5]*X[1]-2.*dFdu[1]*X[2])
229                dFdvDict[pfx+'RBVS13:'+rbsx] += rpd*(-dFdu[5]*X[2]+2.*dFdu[2]*X[1])
230                dFdvDict[pfx+'RBVS21:'+rbsx] += rpd*(-dFdu[4]*X[0]+2.*dFdu[0]*X[2])
231                dFdvDict[pfx+'RBVS23:'+rbsx] += rpd*(dFdu[4]*X[2]-2.*dFdu[2]*X[0])
232                dFdvDict[pfx+'RBVS31:'+rbsx] += rpd*(dFdu[3]*X[0]-2.*dFdu[0]*X[1])
233                dFdvDict[pfx+'RBVS32:'+rbsx] += rpd*(-dFdu[3]*X[1]+2.*dFdu[1]*X[0])
234                dFdvDict[pfx+'RBVSAA:'+rbsx] += rpd*(dFdu[4]*X[1]-dFdu[3]*X[2])
235                dFdvDict[pfx+'RBVSBB:'+rbsx] += rpd*(dFdu[5]*X[0]-dFdu[3]*X[2])
236            if 'U' in RBObj['ThermalMotion'][0]:
237                dFdvDict[pfx+'RBVU:'+rbsx] += dFdvDict[pfx+'AUiso:'+str(AtLookup[atId])]
238
239
240    for irb,RBObj in enumerate(RBModels.get('Residue',[])):
241        symAxis = RBObj.get('symAxis')
242        Q = RBObj['Orient'][0]
243        jrb = RRBIds.index(RBObj['RBId'])
244        torData = RBData['Residue'][RBObj['RBId']]['rbSeq']
245        rbsx = str(irb)+':'+str(jrb)
246        XYZ,Cart = G2mth.UpdateRBXYZ(Bmat,RBObj,RBData,'Residue')
247        for itors,tors in enumerate(RBObj['Torsions']):     #derivative error?
248            tname = pfx+'RBRTr;'+str(itors)+':'+rbsx           
249            orId,pvId = torData[itors][:2]
250            pivotVec = Cart[orId]-Cart[pvId]
251            QA = G2mth.AVdeg2Q(-0.001,pivotVec)
252            QB = G2mth.AVdeg2Q(0.001,pivotVec)
253            for ir in torData[itors][3]:
254                atNum = AtLookup[RBObj['Ids'][ir]]
255                rVec = Cart[ir]-Cart[pvId]
256                dR = G2mth.prodQVQ(QB,rVec)-G2mth.prodQVQ(QA,rVec)
257                dRdT = np.inner(Bmat,G2mth.prodQVQ(Q,dR))/.002
258                for ix in [0,1,2]:
259                    dFdvDict[tname] += dRdT[ix]*dFdvDict[pfx+atxIds[ix]+str(atNum)]
260        for ia,atId in enumerate(RBObj['Ids']):
261            atNum = AtLookup[atId]
262            dx = 0.00001
263            for i,name in enumerate(['RBRPx:','RBRPy:','RBRPz:']):
264                dFdvDict[pfx+name+rbsx] += dFdvDict[pfx+atxIds[i]+str(atNum)]
265            for iv in range(4):
266                Q[iv] -= dx
267                XYZ1 = G2mth.RotateRBXYZ(Bmat,Cart,G2mth.normQ(Q),symAxis)
268                Q[iv] += 2.*dx
269                XYZ2 = G2mth.RotateRBXYZ(Bmat,Cart,G2mth.normQ(Q),symAxis)
270                Q[iv] -= dx
271                dXdO = (XYZ2[ia]-XYZ1[ia])/(2.*dx)
272                for ix in [0,1,2]:
273                    dFdvDict[pfx+'RBR'+OIds[iv]+rbsx] += dXdO[ix]*dFdvDict[pfx+atxIds[ix]+str(atNum)]
274            X = G2mth.prodQVQ(Q,Cart[ia])
275            dFdu = np.array([dFdvDict[pfx+Uid+str(AtLookup[atId])] for Uid in atuIds]).T/gvec
276            dFdu = G2lat.U6toUij(dFdu.T)
277            dFdu = np.tensordot(Amat.T,np.tensordot(Amat,dFdu,([1,0])),([0,1]))
278            dFdu = G2lat.UijtoU6(dFdu)
279            atNum = AtLookup[atId]
280            if 'T' in RBObj['ThermalMotion'][0]:
281                for i,name in enumerate(['RBRT11:','RBRT22:','RBRT33:','RBRT12:','RBRT13:','RBRT23:']):
282                    dFdvDict[pfx+name+rbsx] += dFdu[i]
283            if 'L' in RBObj['ThermalMotion'][0]:
284                dFdvDict[pfx+'RBRL11:'+rbsx] += rpd2*(dFdu[1]*X[2]**2+dFdu[2]*X[1]**2-dFdu[5]*X[1]*X[2])
285                dFdvDict[pfx+'RBRL22:'+rbsx] += rpd2*(dFdu[0]*X[2]**2+dFdu[2]*X[0]**2-dFdu[4]*X[0]*X[2])
286                dFdvDict[pfx+'RBRL33:'+rbsx] += rpd2*(dFdu[0]*X[1]**2+dFdu[1]*X[0]**2-dFdu[3]*X[0]*X[1])
287                dFdvDict[pfx+'RBRL12:'+rbsx] += rpd2*(-dFdu[3]*X[2]**2-2.*dFdu[2]*X[0]*X[1]+
288                    dFdu[4]*X[1]*X[2]+dFdu[5]*X[0]*X[2])
289                dFdvDict[pfx+'RBRL13:'+rbsx] += rpd2*(dFdu[4]*X[1]**2-2.*dFdu[1]*X[0]*X[2]+
290                    dFdu[3]*X[1]*X[2]+dFdu[5]*X[0]*X[1])
291                dFdvDict[pfx+'RBRL23:'+rbsx] += rpd2*(dFdu[5]*X[0]**2-2.*dFdu[0]*X[1]*X[2]+
292                    dFdu[3]*X[0]*X[2]+dFdu[4]*X[0]*X[1])
293            if 'S' in RBObj['ThermalMotion'][0]:
294                dFdvDict[pfx+'RBRS12:'+rbsx] += rpd*(dFdu[5]*X[1]-2.*dFdu[1]*X[2])
295                dFdvDict[pfx+'RBRS13:'+rbsx] += rpd*(-dFdu[5]*X[2]+2.*dFdu[2]*X[1])
296                dFdvDict[pfx+'RBRS21:'+rbsx] += rpd*(-dFdu[4]*X[0]+2.*dFdu[0]*X[2])
297                dFdvDict[pfx+'RBRS23:'+rbsx] += rpd*(dFdu[4]*X[2]-2.*dFdu[2]*X[0])
298                dFdvDict[pfx+'RBRS31:'+rbsx] += rpd*(dFdu[3]*X[0]-2.*dFdu[0]*X[1])
299                dFdvDict[pfx+'RBRS32:'+rbsx] += rpd*(-dFdu[3]*X[1]+2.*dFdu[1]*X[0])
300                dFdvDict[pfx+'RBRSAA:'+rbsx] += rpd*(dFdu[4]*X[1]-dFdu[3]*X[2])
301                dFdvDict[pfx+'RBRSBB:'+rbsx] += rpd*(dFdu[5]*X[0]-dFdu[3]*X[2])
302            if 'U' in RBObj['ThermalMotion'][0]:
303                dFdvDict[pfx+'RBRU:'+rbsx] += dFdvDict[pfx+'AUiso:'+str(AtLookup[atId])]
304   
305################################################################################
306##### Penalty & restraint functions
307################################################################################
308
309def penaltyFxn(HistoPhases,calcControls,parmDict,varyList):
310    'Compute user-supplied and built-in restraint functions'
311    Histograms,Phases,restraintDict,rigidbodyDict = HistoPhases
312    pNames = []
313    pVals = []
314    pWt = []
315    negWt = {}
316    pWsum = {}
317    pWnum = {}
318    for phase in Phases:
319        pId = Phases[phase]['pId']
320        negWt[pId] = Phases[phase]['General']['Pawley neg wt']
321        General = Phases[phase]['General']
322        cx,ct,cs,cia = General['AtomPtrs']
323        textureData = General['SH Texture']
324        SGData = General['SGData']
325        Atoms = Phases[phase]['Atoms']
326        AtLookup = G2mth.FillAtomLookUp(Phases[phase]['Atoms'],cia+8)
327        cell = General['Cell'][1:7]
328        Amat,Bmat = G2lat.cell2AB(cell)
329        if phase not in restraintDict:
330            continue
331        phaseRest = restraintDict[phase]
332        names = [['Bond','Bonds'],['Angle','Angles'],['Plane','Planes'],
333            ['Chiral','Volumes'],['Torsion','Torsions'],['Rama','Ramas'],
334            ['ChemComp','Sites'],['Texture','HKLs'],['General','General'],]
335        for name,rest in names:
336            pWsum[name] = 0.
337            pWnum[name] = 0
338            if name not in phaseRest:
339                continue
340            itemRest = phaseRest[name]
341            if itemRest[rest] and itemRest['Use']:
342                wt = itemRest.get('wtFactor',1.)
343                if name in ['Bond','Angle','Plane','Chiral']:
344                    for i,[indx,ops,obs,esd] in enumerate(itemRest[rest]):
345                        pNames.append(str(pId)+':'+name+':'+str(i))
346                        XYZ = np.array(G2mth.GetAtomCoordsByID(pId,parmDict,AtLookup,indx))
347                        XYZ = G2mth.getSyXYZ(XYZ,ops,SGData)
348                        if name == 'Bond':
349                            calc = G2mth.getRestDist(XYZ,Amat)
350                        elif name == 'Angle':
351                            calc = G2mth.getRestAngle(XYZ,Amat)
352                        elif name == 'Plane':
353                            calc = G2mth.getRestPlane(XYZ,Amat)
354                        elif name == 'Chiral':
355                            calc = G2mth.getRestChiral(XYZ,Amat)
356                        pVals.append(obs-calc)
357                        pWt.append(wt/esd**2)
358                        pWsum[name] += wt*((obs-calc)/esd)**2
359                        pWnum[name] += 1
360                elif name in ['Torsion','Rama']:
361                    coeffDict = itemRest['Coeff']
362                    for i,[indx,ops,cofName,esd] in enumerate(itemRest[rest]):
363                        pNames.append(str(pId)+':'+name+':'+str(i))
364                        XYZ = np.array(G2mth.GetAtomCoordsByID(pId,parmDict,AtLookup,indx))
365                        XYZ = G2mth.getSyXYZ(XYZ,ops,SGData)
366                        if name == 'Torsion':
367                            tor = G2mth.getRestTorsion(XYZ,Amat)
368                            restr,calc = G2mth.calcTorsionEnergy(tor,coeffDict[cofName])
369                        else:
370                            phi,psi = G2mth.getRestRama(XYZ,Amat)
371                            restr,calc = G2mth.calcRamaEnergy(phi,psi,coeffDict[cofName])                               
372                        pVals.append(restr)
373                        pWt.append(wt/esd**2)
374                        pWsum[name] += wt*(restr/esd)**2
375                        pWnum[name] += 1
376                elif name == 'ChemComp':
377                    for i,[indx,factors,obs,esd] in enumerate(itemRest[rest]):
378                        pNames.append(str(pId)+':'+name+':'+str(i))
379                        mul = np.array(G2mth.GetAtomItemsById(Atoms,AtLookup,indx,cs+1))
380                        frac = np.array(G2mth.GetAtomFracByID(pId,parmDict,AtLookup,indx))
381                        calc = np.sum(mul*frac*factors)
382                        pVals.append(obs-calc)
383                        pWt.append(wt/esd**2)                   
384                        pWsum[name] += wt*((obs-calc)/esd)**2
385                        pWnum[name] += 1
386                elif name == 'Texture':
387                    SHkeys = list(textureData['SH Coeff'][1].keys())
388                    SHCoef = G2mth.GetSHCoeff(pId,parmDict,SHkeys)
389                    shModels = ['cylindrical','none','shear - 2/m','rolling - mmm']
390                    SamSym = dict(zip(shModels,['0','-1','2/m','mmm']))
391                    for i,[hkl,grid,esd1,ifesd2,esd2] in enumerate(itemRest[rest]):
392                        PH = np.array(hkl)
393                        phi,beta = G2lat.CrsAng(np.array(hkl),cell,SGData)
394                        ODFln = G2lat.Flnh(False,SHCoef,phi,beta,SGData)
395                        R,P,Z = G2mth.getRestPolefig(ODFln,SamSym[textureData['Model']],grid)
396                        Z1 = ma.masked_greater(Z,0.0)           #is this + or -?
397                        IndZ1 = np.array(ma.nonzero(Z1))
398                        for ind in IndZ1.T:
399                            pNames.append('%d:%s:%d:%.2f:%.2f'%(pId,name,i,R[ind[0],ind[1]],P[ind[0],ind[1]]))
400                            pVals.append(Z1[ind[0]][ind[1]])
401                            pWt.append(wt/esd1**2)
402                            pWsum[name] += wt*(-Z1[ind[0]][ind[1]]/esd1)**2
403                            pWnum[name] += 1
404                        if ifesd2:
405                            Z2 = 1.-Z
406                            for ind in np.ndindex(grid,grid):
407                                pNames.append('%d:%s:%d:%.2f:%.2f'%(pId,name+'-unit',i,R[ind[0],ind[1]],P[ind[0],ind[1]]))
408                                pVals.append(Z2[ind[0]][ind[1]])
409                                pWt.append(wt/esd2**2)
410                                pWsum[name] += wt*(Z2/esd2)**2
411                                pWnum[name] += 1
412                elif name == 'General':
413                    for i,(eq,obs,esd) in enumerate(itemRest[rest]):
414                        pNames.append(str(pId)+':'+name+':'+str(i))
415                        calcobj = G2obj.ExpressionCalcObj(eq)
416                        calcobj.SetupCalc(parmDict)
417                        calc = calcobj.EvalExpression()
418                        pVals.append(obs-calc)
419                        pWt.append(wt/esd**2)                   
420                        pWsum[name] += wt*((obs-calc)/esd)**2
421                        pWnum[name] += 1
422       
423    for phase in Phases:
424        name = 'SH-Pref.Ori.'
425        pId = Phases[phase]['pId']
426        General = Phases[phase]['General']
427        SGData = General['SGData']
428        cell = General['Cell'][1:7]
429        pWsum[name] = 0.0
430        pWnum[name] = 0
431        for hist in Phases[phase]['Histograms']:
432            if not Phases[phase]['Histograms'][hist]['Use']:
433                continue
434            if hist in Histograms and 'PWDR' in hist:
435                hId = Histograms[hist]['hId']
436                phfx = '%d:%d:'%(pId,hId)
437                if calcControls[phfx+'poType'] == 'SH':
438                    toler = calcControls[phfx+'SHtoler']
439                    wt = 1./toler**2
440                    HKLs = np.array(calcControls[phfx+'SHhkl'])
441                    SHnames = calcControls[phfx+'SHnames']
442                    SHcof = dict(zip(SHnames,[parmDict[phfx+cof] for cof in SHnames]))
443                    for i,PH in enumerate(HKLs):
444                        phi,beta = G2lat.CrsAng(PH,cell,SGData)
445                        SH3Coef = {}
446                        for item in SHcof:
447                            L,N = eval(item.strip('C'))
448                            SH3Coef['C%d,0,%d'%(L,N)] = SHcof[item]                       
449                        ODFln = G2lat.Flnh(False,SH3Coef,phi,beta,SGData)
450                        X = np.linspace(0,90.0,26)
451                        Y = ma.masked_greater(G2lat.polfcal(ODFln,'0',X,0.0),0.0)       #+ or -?
452                        IndY = ma.nonzero(Y)
453                        for ind in IndY[0]:
454                            pNames.append('%d:%d:%s:%d:%.2f'%(pId,hId,name,i,X[ind]))
455                            pVals.append(Y[ind])
456                            pWt.append(wt)
457                            pWsum[name] += wt*(Y[ind])**2
458                            pWnum[name] += 1
459    pWsum['PWLref'] = 0.
460    pWnum['PWLref'] = 0
461    for item in varyList:
462        if 'PWLref' in item and parmDict[item] < 0.:
463            pId = int(item.split(':')[0])
464            if negWt[pId]:
465                pNames.append(item)
466                pVals.append(parmDict[item])
467                pWt.append(negWt[pId])
468                pWsum['PWLref'] += negWt[pId]*(parmDict[item])**2
469                pWnum['PWLref'] += 1
470    pVals = np.array(pVals)
471    pWt = np.array(pWt)         #should this be np.sqrt?
472    return pNames,pVals,pWt,pWsum,pWnum
473   
474def penaltyDeriv(pNames,pVal,HistoPhases,calcControls,parmDict,varyList):
475    '''Compute derivatives on user-supplied and built-in restraint
476    (penalty) functions
477
478    where pNames is list of restraint labels
479
480    returns pDerv with partial derivatives by variable# in varList and
481       restraint# in pNames (pDerv[variable#][restraint#])
482    '''
483    Histograms,Phases,restraintDict,rigidbodyDict = HistoPhases
484    pDerv = np.zeros((len(varyList),len(pVal)))
485    for pName in pNames: # loop over restraints
486        if 'General' == pName.split(':')[1]:
487            # initialize for General restraint(s) here
488            GeneralInit = True
489            parmDict0 = parmDict.copy()
490            # setup steps for each parameter
491            stepDict = {}
492            for parm in varyList:
493                stepDict[parm] = G2obj.getVarStep(parm,parmDict)
494            break
495    for phase in Phases:
496#        if phase not in restraintDict:
497#            continue
498        pId = Phases[phase]['pId']
499        General = Phases[phase]['General']
500        cx,ct,cs,cia = General['AtomPtrs']
501        SGData = General['SGData']
502        Atoms = Phases[phase]['Atoms']
503        AtLookup = G2mth.FillAtomLookUp(Phases[phase]['Atoms'],cia+8)
504        cell = General['Cell'][1:7]
505        Amat,Bmat = G2lat.cell2AB(cell)
506        textureData = General['SH Texture']
507
508        SHkeys = list(textureData['SH Coeff'][1].keys())
509        SHCoef = G2mth.GetSHCoeff(pId,parmDict,SHkeys)
510        shModels = ['cylindrical','none','shear - 2/m','rolling - mmm']
511        SamSym = dict(zip(shModels,['0','-1','2/m','mmm']))
512        sam = SamSym[textureData['Model']]
513        phaseRest = restraintDict.get(phase,{})
514        names = {'Bond':'Bonds','Angle':'Angles','Plane':'Planes',
515            'Chiral':'Volumes','Torsion':'Torsions','Rama':'Ramas',
516            'ChemComp':'Sites','Texture':'HKLs'}
517        lasthkl = np.array([0,0,0])
518        for ip,pName in enumerate(pNames): # loop over restraints
519            pnames = pName.split(':')
520            if pId == int(pnames[0]):
521                name = pnames[1]
522                if 'PWL' in pName:
523                    pDerv[varyList.index(pName)][ip] += 1.
524                    continue
525                elif 'SH-' in pName:
526                    continue
527                Id = int(pnames[2]) 
528                itemRest = phaseRest[name]
529                if name in ['Bond','Angle','Plane','Chiral']:
530                    indx,ops,obs,esd = itemRest[names[name]][Id]
531                    dNames = []
532                    for ind in indx:
533                        dNames += [str(pId)+'::dA'+Xname+':'+str(AtLookup[ind]) for Xname in ['x','y','z']]
534                    XYZ = np.array(G2mth.GetAtomCoordsByID(pId,parmDict,AtLookup,indx))
535                    if name == 'Bond':
536                        deriv = G2mth.getRestDeriv(G2mth.getRestDist,XYZ,Amat,ops,SGData)
537                    elif name == 'Angle':
538                        deriv = G2mth.getRestDeriv(G2mth.getRestAngle,XYZ,Amat,ops,SGData)
539                    elif name == 'Plane':
540                        deriv = G2mth.getRestDeriv(G2mth.getRestPlane,XYZ,Amat,ops,SGData)
541                    elif name == 'Chiral':
542                        deriv = G2mth.getRestDeriv(G2mth.getRestChiral,XYZ,Amat,ops,SGData)
543                elif name in ['Torsion','Rama']:
544                    coffDict = itemRest['Coeff']
545                    indx,ops,cofName,esd = itemRest[names[name]][Id]
546                    dNames = []
547                    for ind in indx:
548                        dNames += [str(pId)+'::dA'+Xname+':'+str(AtLookup[ind]) for Xname in ['x','y','z']]
549                    XYZ = np.array(G2mth.GetAtomCoordsByID(pId,parmDict,AtLookup,indx))
550                    if name == 'Torsion':
551                        deriv = G2mth.getTorsionDeriv(XYZ,Amat,coffDict[cofName])
552                    else:
553                        deriv = G2mth.getRamaDeriv(XYZ,Amat,coffDict[cofName])
554                elif name == 'ChemComp':
555                    indx,factors,obs,esd = itemRest[names[name]][Id]
556                    dNames = []
557                    for ind in indx:
558                        dNames += [str(pId)+'::Afrac:'+str(AtLookup[ind])]
559                        mul = np.array(G2mth.GetAtomItemsById(Atoms,AtLookup,indx,cs+1))
560                        deriv = mul*factors
561                elif 'Texture' in name:
562                    deriv = []
563                    dNames = []
564                    hkl,grid,esd1,ifesd2,esd2 = itemRest[names[name]][Id]
565                    hkl = np.array(hkl)
566                    if np.any(lasthkl-hkl):
567                        phi,beta = G2lat.CrsAng(np.array(hkl),cell,SGData)
568                        ODFln = G2lat.Flnh(False,SHCoef,phi,beta,SGData)
569                        lasthkl = copy.copy(hkl)                       
570                    if 'unit' in name:
571                        pass
572                    else:
573                        gam = float(pnames[3])
574                        psi = float(pnames[4])
575                        for SHname in ODFln:
576                            l,m,n = eval(SHname[1:])
577                            Ksl = G2lat.GetKsl(l,m,sam,psi,gam)[0]
578                            dNames += [str(pId)+'::'+SHname]
579                            deriv.append(-ODFln[SHname][0]*Ksl/SHCoef[SHname])
580                elif name == 'General':
581                    deriv = []
582                    dNames = []
583                    eq,obs,esd = itemRest[name][Id]
584                    calcobj = G2obj.ExpressionCalcObj(eq)
585                    parmlist = list(eq.assgnVars.values()) # parameters used in this expression
586                    for parm in parmlist: # expand list if any parms are determined by constraints
587                        if parm in G2mv.dependentVars:
588                            parmlist += G2mv.independentVars
589                            break
590                    for ind,var in enumerate(varyList):
591                        drv = 0
592                        if var in parmlist:
593                            step = stepDict.get(var,1e-5)
594                            calc = []
595                            # apply step to parameter
596                            oneparm = True
597                            for s in -step,2*step:
598                                parmDict[var] += s
599                                # extend shift if needed to other parameters
600                                if var in G2mv.independentVars:
601                                    G2mv.Dict2Map(parmDict,[])
602                                    oneparm = False
603                                elif var in G2mv.dependentVars:
604                                    G2mv.Map2Dict(parmDict,[])
605                                    oneparm = False
606                                if 'RB' in var:
607                                    ApplyRBModels(parmDict,Phases,rigidbodyDict)
608# test
609                                    oneparm = False
610                                calcobj.SetupCalc(parmDict)
611                                calc.append(calcobj.EvalExpression())
612                            drv = (calc[1]-calc[0])*.5/step
613                            # restore the dict
614                            if oneparm:
615                                parmDict[var] = parmDict0[var]
616                            else:
617                                parmDict = parmDict0.copy()
618                        else:
619                            drv = 0
620                        pDerv[ind][ip] = drv
621                # Add derivatives into matrix, if needed
622                for dName,drv in zip(dNames,deriv):
623                    try:
624                        ind = varyList.index(dName)
625                        pDerv[ind][ip] += drv
626                    except ValueError:
627                        pass
628       
629        lasthkl = np.array([0,0,0])
630        for ip,pName in enumerate(pNames):
631            deriv = []
632            dNames = []
633            pnames = pName.split(':')
634            if 'SH-' in pName and pId == int(pnames[0]):
635                hId = int(pnames[1])
636                phfx = '%d:%d:'%(pId,hId)
637                psi = float(pnames[4])
638                HKLs = calcControls[phfx+'SHhkl']
639                SHnames = calcControls[phfx+'SHnames']
640                SHcof = dict(zip(SHnames,[parmDict[phfx+cof] for cof in SHnames]))
641                hkl = np.array(HKLs[int(pnames[3])])     
642                if np.any(lasthkl-hkl):
643                    phi,beta = G2lat.CrsAng(np.array(hkl),cell,SGData)
644                    SH3Coef = {}
645                    for item in SHcof:
646                        L,N = eval(item.strip('C'))
647                        SH3Coef['C%d,0,%d'%(L,N)] = SHcof[item]                       
648                    ODFln = G2lat.Flnh(False,SH3Coef,phi,beta,SGData)
649                    lasthkl = copy.copy(hkl)                       
650                for SHname in SHnames:
651                    l,n = eval(SHname[1:])
652                    SH3name = 'C%d,0,%d'%(l,n)
653                    Ksl = G2lat.GetKsl(l,0,'0',psi,0.0)[0]
654                    dNames += [phfx+SHname]
655                    deriv.append(ODFln[SH3name][0]*Ksl/SHcof[SHname])
656            for dName,drv in zip(dNames,deriv):
657                try:
658                    ind = varyList.index(dName)
659                    pDerv[ind][ip] += drv
660                except ValueError:
661                    pass
662    return pDerv
663
664################################################################################
665##### Function & derivative calculations
666################################################################################       
667                   
668def GetAtomFXU(pfx,calcControls,parmDict):
669    'Needs a doc string'
670    Natoms = calcControls['Natoms'][pfx]
671    Tdata = Natoms*[' ',]
672    Mdata = np.zeros(Natoms)
673    IAdata = Natoms*[' ',]
674    Fdata = np.zeros(Natoms)
675    Xdata = np.zeros((3,Natoms))
676    dXdata = np.zeros((3,Natoms))
677    Uisodata = np.zeros(Natoms)
678    Uijdata = np.zeros((6,Natoms))
679    Gdata = np.zeros((3,Natoms))
680    keys = {'Atype:':Tdata,'Amul:':Mdata,'Afrac:':Fdata,'AI/A:':IAdata,
681        'dAx:':dXdata[0],'dAy:':dXdata[1],'dAz:':dXdata[2],
682        'Ax:':Xdata[0],'Ay:':Xdata[1],'Az:':Xdata[2],'AUiso:':Uisodata,
683        'AU11:':Uijdata[0],'AU22:':Uijdata[1],'AU33:':Uijdata[2],
684        'AU12:':Uijdata[3],'AU13:':Uijdata[4],'AU23:':Uijdata[5],
685        'AMx:':Gdata[0],'AMy:':Gdata[1],'AMz:':Gdata[2],}
686    for iatm in range(Natoms):
687        for key in keys:
688            parm = pfx+key+str(iatm)
689            if parm in parmDict:
690                keys[key][iatm] = parmDict[parm]
691    Fdata = np.where(Fdata,Fdata,1.e-8)         #avoid divide by zero in derivative calc.
692    Gdata = np.where(Gdata,Gdata,1.e-8)         #avoid divide by zero in derivative calc.
693   
694    return Tdata,Mdata,Fdata,Xdata,dXdata,IAdata,Uisodata,Uijdata,Gdata
695   
696def GetAtomSSFXU(pfx,calcControls,parmDict):
697    'Needs a doc string'
698    Natoms = calcControls['Natoms'][pfx]
699    maxSSwave = calcControls['maxSSwave'][pfx]
700    Nwave = {'F':maxSSwave['Sfrac'],'X':maxSSwave['Spos'],'Y':maxSSwave['Spos'],'Z':maxSSwave['Spos'],
701        'U':maxSSwave['Sadp'],'M':maxSSwave['Smag'],'T':maxSSwave['Spos']}
702    XSSdata = np.zeros((6,maxSSwave['Spos'],Natoms))
703    FSSdata = np.zeros((2,maxSSwave['Sfrac'],Natoms))
704    USSdata = np.zeros((12,maxSSwave['Sadp'],Natoms))
705    MSSdata = np.zeros((6,maxSSwave['Smag'],Natoms))
706    waveTypes = []
707    keys = {'Fsin:':FSSdata[0],'Fcos:':FSSdata[1],'Fzero:':FSSdata[0],'Fwid:':FSSdata[1],
708        'Tmin:':XSSdata[0],'Tmax:':XSSdata[1],'Xmax:':XSSdata[2],'Ymax:':XSSdata[3],'Zmax:':XSSdata[4],
709        'Xsin:':XSSdata[0],'Ysin:':XSSdata[1],'Zsin:':XSSdata[2],'Xcos:':XSSdata[3],'Ycos:':XSSdata[4],'Zcos:':XSSdata[5],
710        'U11sin:':USSdata[0],'U22sin:':USSdata[1],'U33sin:':USSdata[2],'U12sin:':USSdata[3],'U13sin:':USSdata[4],'U23sin:':USSdata[5],
711        'U11cos:':USSdata[6],'U22cos:':USSdata[7],'U33cos:':USSdata[8],'U12cos:':USSdata[9],'U13cos:':USSdata[10],'U23cos:':USSdata[11],
712        'MXsin:':MSSdata[0],'MYsin:':MSSdata[1],'MZsin:':MSSdata[2],'MXcos:':MSSdata[3],'MYcos:':MSSdata[4],'MZcos:':MSSdata[5]}
713    for iatm in range(Natoms):
714        wavetype = [parmDict.get(pfx+kind+'waveType:'+str(iatm),'') for kind in ['F','P','A','M']]
715        waveTypes.append(wavetype)
716        for key in keys:
717            for m in range(Nwave[key[0]]):
718                parm = pfx+key+str(iatm)+':%d'%(m)
719                if parm in parmDict:
720                    keys[key][m][iatm] = parmDict[parm]
721    return waveTypes,FSSdata,XSSdata,USSdata,MSSdata
722   
723def StructureFactor2(refDict,G,hfx,pfx,SGData,calcControls,parmDict):
724    ''' Compute structure factors for all h,k,l for phase
725    puts the result, F^2, in each ref[8] in refList
726    operates on blocks of 100 reflections for speed
727    input:
728   
729    :param dict refDict: where
730        'RefList' list where each ref = h,k,l,it,d,...
731        'FF' dict of form factors - filed in below
732    :param np.array G:      reciprocal metric tensor
733    :param str pfx:    phase id string
734    :param dict SGData: space group info. dictionary output from SpcGroup
735    :param dict calcControls:
736    :param dict ParmDict:
737
738    '''       
739    phfx = pfx.split(':')[0]+hfx
740    ast = np.sqrt(np.diag(G))
741    Mast = twopisq*np.multiply.outer(ast,ast)
742    SGMT = np.array([ops[0].T for ops in SGData['SGOps']])
743    SGT = np.array([ops[1] for ops in SGData['SGOps']])
744    FFtables = calcControls['FFtables']
745    BLtables = calcControls['BLtables']
746    Amat,Bmat = G2lat.Gmat2AB(G)
747    Flack = 1.0
748    if not SGData['SGInv'] and 'S' in calcControls[hfx+'histType'] and phfx+'Flack' in parmDict:
749        Flack = 1.-2.*parmDict[phfx+'Flack']
750    TwinLaw = np.array([[[1,0,0],[0,1,0],[0,0,1]],])
751    TwDict = refDict.get('TwDict',{})           
752    if 'S' in calcControls[hfx+'histType']:
753        NTL = calcControls[phfx+'NTL']
754        NM = calcControls[phfx+'TwinNMN']+1
755        TwinLaw = calcControls[phfx+'TwinLaw']
756        TwinFr = np.array([parmDict[phfx+'TwinFr:'+str(i)] for i in range(len(TwinLaw))])
757        TwinInv = list(np.where(calcControls[phfx+'TwinInv'],-1,1))
758    Tdata,Mdata,Fdata,Xdata,dXdata,IAdata,Uisodata,Uijdata,Gdata = \
759        GetAtomFXU(pfx,calcControls,parmDict)
760    if not Xdata.size:          #no atoms in phase!
761        return
762    if 'NC' in calcControls[hfx+'histType'] or 'NB' in calcControls[hfx+'histType']:
763        FP,FPP = G2el.BlenResCW(Tdata,BLtables,parmDict[hfx+'Lam'])
764    elif 'X' in calcControls[hfx+'histType']:
765        FP = np.array([FFtables[El][hfx+'FP'] for El in Tdata])
766        FPP = np.array([FFtables[El][hfx+'FPP'] for El in Tdata])
767    Uij = np.array(G2lat.U6toUij(Uijdata))
768    bij = Mast*Uij.T
769    blkSize = 100       #no. of reflections in a block - size seems optimal
770    nRef = refDict['RefList'].shape[0]
771    SQ = 1./(2.*refDict['RefList'].T[4])**2
772    if 'N' in calcControls[hfx+'histType']:
773        dat = G2el.getBLvalues(BLtables)
774        refDict['FF']['El'] = list(dat.keys())
775        refDict['FF']['FF'] = np.ones((nRef,len(dat)))*list(dat.values())
776    else:       #'X'
777        dat = G2el.getFFvalues(FFtables,0.)
778        refDict['FF']['El'] = list(dat.keys())
779        refDict['FF']['FF'] = np.zeros((nRef,len(dat)))
780        for iel,El in enumerate(refDict['FF']['El']):
781            refDict['FF']['FF'].T[iel] = G2el.ScatFac(FFtables[El],SQ)
782#reflection processing begins here - big arrays!
783    iBeg = 0
784    while iBeg < nRef:
785        iFin = min(iBeg+blkSize,nRef)
786        refl = refDict['RefList'][iBeg:iFin]    #array(blkSize,nItems)
787        H = refl.T[:3]                          #array(blkSize,3)
788        H = np.squeeze(np.inner(H.T,TwinLaw))   #maybe array(blkSize,nTwins,3) or (blkSize,3)
789        TwMask = np.any(H,axis=-1)
790        if TwinLaw.shape[0] > 1 and TwDict: #need np.inner(TwinLaw[?],TwDict[iref][i])*TwinInv[i]
791            for ir in range(blkSize):
792                iref = ir+iBeg
793                if iref in TwDict:
794                    for i in TwDict[iref]:
795                        for n in range(NTL):
796                            H[ir][i+n*NM] = np.inner(TwinLaw[n*NM],np.array(TwDict[iref][i])*TwinInv[i+n*NM])
797            TwMask = np.any(H,axis=-1)
798        SQ = 1./(2.*refl.T[4])**2               #array(blkSize)
799        SQfactor = 4.0*SQ*twopisq               #ditto prev.
800        if 'T' in calcControls[hfx+'histType']:
801            if 'P' in calcControls[hfx+'histType']:
802                FP,FPP = G2el.BlenResTOF(Tdata,BLtables,refl.T[14])
803            else:
804                FP,FPP = G2el.BlenResTOF(Tdata,BLtables,refl.T[12])
805            FP = np.repeat(FP.T,len(SGT)*len(TwinLaw),axis=0)
806            FPP = np.repeat(FPP.T,len(SGT)*len(TwinLaw),axis=0)
807        Uniq = np.inner(H,SGMT)
808        Phi = np.inner(H,SGT)
809        phase = twopi*(np.inner(Uniq,(dXdata+Xdata).T).T+Phi.T).T
810        sinp = np.sin(phase)
811        cosp = np.cos(phase)
812        biso = -SQfactor*Uisodata[:,nxs]
813        Tiso = np.repeat(np.where(biso<1.,np.exp(biso),1.0),len(SGT)*len(TwinLaw),axis=1).T
814        HbH = -np.sum(Uniq.T*np.swapaxes(np.inner(bij,Uniq),2,-1),axis=1)
815        Tuij = np.where(HbH<1.,np.exp(HbH),1.0).T
816        Tcorr = np.reshape(Tiso,Tuij.shape)*Tuij*Mdata*Fdata/len(SGMT)
817        Tindx = np.array([refDict['FF']['El'].index(El) for El in Tdata])
818        FF = np.repeat(refDict['FF']['FF'][iBeg:iFin].T[Tindx].T,len(SGT)*len(TwinLaw),axis=0)
819        Bab = np.repeat(parmDict[phfx+'BabA']*np.exp(-parmDict[phfx+'BabU']*SQfactor),len(SGT)*len(TwinLaw))
820        if 'T' in calcControls[hfx+'histType']: #fa,fb are 2 X blkSize X nTwin X nOps x nAtoms
821            fa = np.array([np.reshape(((FF+FP).T-Bab).T,cosp.shape)*cosp*Tcorr,-np.reshape(Flack*FPP,sinp.shape)*sinp*Tcorr])
822            fb = np.array([np.reshape(((FF+FP).T-Bab).T,sinp.shape)*sinp*Tcorr,np.reshape(Flack*FPP,cosp.shape)*cosp*Tcorr])
823        else:
824            fa = np.array([np.reshape(((FF+FP).T-Bab).T,cosp.shape)*cosp*Tcorr,-Flack*FPP*sinp*Tcorr])
825            fb = np.array([np.reshape(((FF+FP).T-Bab).T,sinp.shape)*sinp*Tcorr,Flack*FPP*cosp*Tcorr])
826        fas = np.sum(np.sum(fa,axis=-1),axis=-1)  #real 2 x blkSize x nTwin; sum over atoms & uniq hkl
827        fbs = np.sum(np.sum(fb,axis=-1),axis=-1)  #imag
828        if SGData['SGInv']: #centrosymmetric; B=0
829            fbs[0] *= 0.
830            fas[1] *= 0.
831        if 'P' in calcControls[hfx+'histType']:     #PXC, PNC & PNT: F^2 = A[0]^2 + A[1]^2 + B[0]^2 + B[1]^2
832            refl.T[9] = np.sum(fas**2,axis=0)+np.sum(fbs**2,axis=0) #add fam**2 & fbm**2 here   
833            refl.T[10] = atan2d(fbs[0],fas[0])  #ignore f' & f"
834        else:                                       #HKLF: F^2 = (A[0]+A[1])^2 + (B[0]+B[1])^2
835            if len(TwinLaw) > 1:
836                refl.T[9] = np.sum(fas[:,:,0],axis=0)**2+np.sum(fbs[:,:,0],axis=0)**2   #FcT from primary twin element
837                refl.T[7] = np.sum(TwinFr*TwMask*np.sum(fas,axis=0)**2,axis=-1)+   \
838                    np.sum(TwinFr*TwMask*np.sum(fbs,axis=0)**2,axis=-1)                        #Fc sum over twins
839                refl.T[10] = atan2d(fbs[0].T[0],fas[0].T[0])  #ignore f' & f" & use primary twin
840            else:   # checked correct!!
841                refl.T[9] = np.sum(fas,axis=0)**2+np.sum(fbs,axis=0)**2
842                refl.T[7] = np.copy(refl.T[9])               
843                refl.T[10] = atan2d(fbs[0],fas[0])  #ignore f' & f"
844#                refl.T[10] = atan2d(np.sum(fbs,axis=0),np.sum(fas,axis=0)) #include f' & f"
845        iBeg += blkSize
846#    print 'sf time %.4f, nref %d, blkSize %d'%(time.time()-time0,nRef,blkSize)
847   
848def StructureFactorDerv2(refDict,G,hfx,pfx,SGData,calcControls,parmDict):
849    '''Compute structure factor derivatives on blocks of reflections - for powders/nontwins only
850    faster than StructureFactorDerv - correct for powders/nontwins!!
851    input:
852   
853    :param dict refDict: where
854        'RefList' list where each ref = h,k,l,it,d,...
855        'FF' dict of form factors - filled in below
856    :param np.array G:      reciprocal metric tensor
857    :param str hfx:    histogram id string
858    :param str pfx:    phase id string
859    :param dict SGData: space group info. dictionary output from SpcGroup
860    :param dict calcControls:
861    :param dict parmDict:
862   
863    :returns: dict dFdvDict: dictionary of derivatives
864    '''
865    phfx = pfx.split(':')[0]+hfx
866    ast = np.sqrt(np.diag(G))
867    Mast = twopisq*np.multiply.outer(ast,ast)
868    SGMT = np.array([ops[0].T for ops in SGData['SGOps']])
869    SGT = np.array([ops[1] for ops in SGData['SGOps']])
870    FFtables = calcControls['FFtables']
871    BLtables = calcControls['BLtables']
872    Amat,Bmat = G2lat.Gmat2AB(G)
873    nRef = len(refDict['RefList'])
874    Tdata,Mdata,Fdata,Xdata,dXdata,IAdata,Uisodata,Uijdata,Gdata = \
875        GetAtomFXU(pfx,calcControls,parmDict)
876    if not Xdata.size:          #no atoms in phase!
877        return {}
878    mSize = len(Mdata)
879    FF = np.zeros(len(Tdata))
880    if 'NC' in calcControls[hfx+'histType'] or 'NB' in calcControls[hfx+'histType']:
881        FP,FPP = G2el.BlenResCW(Tdata,BLtables,parmDict[hfx+'Lam'])
882    elif 'X' in calcControls[hfx+'histType']:
883        FP = np.array([FFtables[El][hfx+'FP'] for El in Tdata])
884        FPP = np.array([FFtables[El][hfx+'FPP'] for El in Tdata])
885    Uij = np.array(G2lat.U6toUij(Uijdata))
886    bij = Mast*Uij.T
887    dFdvDict = {}
888    dFdfr = np.zeros((nRef,mSize))
889    dFdx = np.zeros((nRef,mSize,3))
890    dFdui = np.zeros((nRef,mSize))
891    dFdua = np.zeros((nRef,mSize,6))
892    dFdbab = np.zeros((nRef,2))
893    dFdfl = np.zeros((nRef))
894    Flack = 1.0
895    if not SGData['SGInv'] and 'S' in calcControls[hfx+'histType'] and phfx+'Flack' in parmDict:
896        Flack = 1.-2.*parmDict[phfx+'Flack']
897#    time0 = time.time()
898#reflection processing begins here - big arrays!
899    iBeg = 0
900    blkSize = 32       #no. of reflections in a block - optimized for speed
901    while iBeg < nRef:
902        iFin = min(iBeg+blkSize,nRef)
903        refl = refDict['RefList'][iBeg:iFin]    #array(blkSize,nItems)
904        H = refl.T[:3].T
905        SQ = 1./(2.*refl.T[4])**2             # or (sin(theta)/lambda)**2
906        SQfactor = 8.0*SQ*np.pi**2
907        if 'T' in calcControls[hfx+'histType']:
908            if 'P' in calcControls[hfx+'histType']:
909                FP,FPP = G2el.BlenResTOF(Tdata,BLtables,refl.T[14])
910            else:
911                FP,FPP = G2el.BlenResTOF(Tdata,BLtables,refl.T[12])
912            FP = np.repeat(FP.T,len(SGT),axis=0)
913            FPP = np.repeat(FPP.T,len(SGT),axis=0)
914        dBabdA = np.exp(-parmDict[phfx+'BabU']*SQfactor)
915        Bab = np.repeat(parmDict[phfx+'BabA']*np.exp(-parmDict[phfx+'BabU']*SQfactor),len(SGT))
916        Tindx = np.array([refDict['FF']['El'].index(El) for El in Tdata])
917        FF = np.repeat(refDict['FF']['FF'][iBeg:iFin].T[Tindx].T,len(SGT),axis=0)
918        Uniq = np.inner(H,SGMT)             # array(nSGOp,3)
919        Phi = np.inner(H,SGT)
920        phase = twopi*(np.inner(Uniq,(dXdata+Xdata).T).T+Phi.T).T
921        sinp = np.sin(phase)        #refBlk x nOps x nAtoms
922        cosp = np.cos(phase)
923        occ = Mdata*Fdata/len(SGT)
924        biso = -SQfactor*Uisodata[:,nxs]
925        Tiso = np.repeat(np.where(biso<1.,np.exp(biso),1.0),len(SGT),axis=1).T
926        HbH = -np.sum(Uniq.T*np.swapaxes(np.inner(bij,Uniq),2,-1),axis=1)
927        Tuij = np.where(HbH<1.,np.exp(HbH),1.0).T
928        Tcorr = np.reshape(Tiso,Tuij.shape)*Tuij*Mdata*Fdata/len(SGMT)
929        Hij = np.array([Mast*np.multiply.outer(U,U) for U in np.reshape(Uniq,(-1,3))])      #Nref*Nops,3,3
930        Hij = np.reshape(np.array([G2lat.UijtoU6(uij) for uij in Hij]),(-1,len(SGT),6))     #Nref,Nops,6
931        fot = np.reshape(((FF+FP).T-Bab).T,cosp.shape)*Tcorr
932        if len(FPP.shape) > 1:
933            fotp = np.reshape(FPP,cosp.shape)*Tcorr
934        else:
935            fotp = FPP*Tcorr     
936        if 'T' in calcControls[hfx+'histType']:
937            fa = np.array([fot*cosp,-np.reshape(Flack*FPP,sinp.shape)*sinp*Tcorr])
938            fb = np.array([fot*sinp,np.reshape(Flack*FPP,cosp.shape)*cosp*Tcorr])
939        else:
940            fa = np.array([fot*cosp,-Flack*FPP*sinp*Tcorr])
941            fb = np.array([fot*sinp,Flack*FPP*cosp*Tcorr])
942        fas = np.sum(np.sum(fa,axis=-1),axis=-1)      #real sum over atoms & unique hkl array(2,refBlk,nTwins)
943        fbs = np.sum(np.sum(fb,axis=-1),axis=-1)      #imag sum over atoms & uniq hkl
944        fax = np.array([-fot*sinp,-fotp*cosp])   #positions array(2,refBlk,nEqv,nAtoms)
945        fbx = np.array([fot*cosp,-fotp*sinp])
946        #sum below is over Uniq
947        dfadfr = np.sum(fa/occ,axis=-2)        #array(2,refBlk,nAtom) Fdata != 0 avoids /0. problem
948        dfadba = np.sum(-cosp*Tcorr,axis=-2)  #array(refBlk,nAtom)
949        dfadx = np.sum(twopi*Uniq[nxs,:,nxs,:,:]*np.swapaxes(fax,-2,-1)[:,:,:,:,nxs],axis=-2)
950        dfadui = np.sum(-SQfactor[nxs,:,nxs,nxs]*fa,axis=-2) #array(Ops,refBlk,nAtoms)
951        dfadua = np.sum(-Hij[nxs,:,nxs,:,:]*np.swapaxes(fa,-2,-1)[:,:,:,:,nxs],axis=-2)
952        # array(2,refBlk,nAtom,3) & array(2,refBlk,nAtom,6)
953        if not SGData['SGInv']:
954            dfbdfr = np.sum(fb/occ,axis=-2)        #Fdata != 0 avoids /0. problem
955            dfbdba = np.sum(-sinp*Tcorr,axis=-2)
956            dfadfl = np.sum(np.sum(-fotp*sinp,axis=-1),axis=-1)
957            dfbdfl = np.sum(np.sum(fotp*cosp,axis=-1),axis=-1)
958            dfbdx = np.sum(twopi*Uniq[nxs,:,nxs,:,:]*np.swapaxes(fbx,-2,-1)[:,:,:,:,nxs],axis=-2)           
959            dfbdui = np.sum(-SQfactor[nxs,:,nxs,nxs]*fb,axis=-2)
960            dfbdua = np.sum(-Hij[nxs,:,nxs,:,:]*np.swapaxes(fb,-2,-1)[:,:,:,:,nxs],axis=-2)
961        else:
962            dfbdfr = np.zeros_like(dfadfr)
963            dfbdx = np.zeros_like(dfadx)
964            dfbdui = np.zeros_like(dfadui)
965            dfbdua = np.zeros_like(dfadua)
966            dfbdba = np.zeros_like(dfadba)
967            dfadfl = 0.0
968            dfbdfl = 0.0
969        #NB: the above have been checked against PA(1:10,1:2) in strfctr.for for Al2O3!   
970        SA = fas[0]+fas[1]
971        SB = fbs[0]+fbs[1]
972        if 'P' in calcControls[hfx+'histType']: #checked perfect for centro & noncentro
973            dFdfr[iBeg:iFin] = 2.*np.sum(fas[:,:,nxs]*dfadfr+fbs[:,:,nxs]*dfbdfr,axis=0)*Mdata/len(SGMT)
974            dFdx[iBeg:iFin] = 2.*np.sum(fas[:,:,nxs,nxs]*dfadx+fbs[:,:,nxs,nxs]*dfbdx,axis=0)
975            dFdui[iBeg:iFin] = 2.*np.sum(fas[:,:,nxs]*dfadui+fbs[:,:,nxs]*dfbdui,axis=0)
976            dFdua[iBeg:iFin] = 2.*np.sum(fas[:,:,nxs,nxs]*dfadua+fbs[:,:,nxs,nxs]*dfbdua,axis=0)
977        else:
978            dFdfr[iBeg:iFin] = (2.*SA[:,nxs]*(dfadfr[0]+dfadfr[1])+2.*SB[:,nxs]*(dfbdfr[0]+dfbdfr[1]))*Mdata/len(SGMT)
979            dFdx[iBeg:iFin] = 2.*SA[:,nxs,nxs]*(dfadx[0]+dfadx[1])+2.*SB[:,nxs,nxs]*(dfbdx[0]+dfbdx[1])
980            dFdui[iBeg:iFin] = 2.*SA[:,nxs]*(dfadui[0]+dfadui[1])+2.*SB[:,nxs]*(dfbdui[0]+dfbdui[1])
981            dFdua[iBeg:iFin] = 2.*SA[:,nxs,nxs]*(dfadua[0]+dfadua[1])+2.*SB[:,nxs,nxs]*(dfbdua[0]+dfbdua[1])
982            dFdfl[iBeg:iFin] = -SA*dfadfl-SB*dfbdfl  #array(nRef,)
983        dFdbab[iBeg:iFin] = 2.*(fas[0,nxs]*np.array([np.sum(dfadba.T*dBabdA,axis=0),np.sum(-dfadba.T*parmDict[phfx+'BabA']*SQfactor*dBabdA,axis=0)])+ \
984                            fbs[0,nxs]*np.array([np.sum(dfbdba.T*dBabdA,axis=0),np.sum(-dfbdba.T*parmDict[phfx+'BabA']*SQfactor*dBabdA,axis=0)])).T
985        iBeg += blkSize
986#    print 'derv time %.4f, nref %d, blkSize %d'%(time.time()-time0,nRef,blkSize)
987        #loop over atoms - each dict entry is list of derivatives for all the reflections
988    for i in range(len(Mdata)):
989        dFdvDict[pfx+'Afrac:'+str(i)] = dFdfr.T[i]
990        dFdvDict[pfx+'dAx:'+str(i)] = dFdx.T[0][i]
991        dFdvDict[pfx+'dAy:'+str(i)] = dFdx.T[1][i]
992        dFdvDict[pfx+'dAz:'+str(i)] = dFdx.T[2][i]
993        dFdvDict[pfx+'AUiso:'+str(i)] = dFdui.T[i]
994        dFdvDict[pfx+'AU11:'+str(i)] = dFdua.T[0][i]
995        dFdvDict[pfx+'AU22:'+str(i)] = dFdua.T[1][i]
996        dFdvDict[pfx+'AU33:'+str(i)] = dFdua.T[2][i]
997        dFdvDict[pfx+'AU12:'+str(i)] = 2.*dFdua.T[3][i]
998        dFdvDict[pfx+'AU13:'+str(i)] = 2.*dFdua.T[4][i]
999        dFdvDict[pfx+'AU23:'+str(i)] = 2.*dFdua.T[5][i]
1000    dFdvDict[phfx+'Flack'] = 4.*dFdfl.T
1001    dFdvDict[phfx+'BabA'] = dFdbab.T[0]
1002    dFdvDict[phfx+'BabU'] = dFdbab.T[1]
1003    return dFdvDict
1004   
1005def MagStructureFactor2(refDict,G,hfx,pfx,SGData,calcControls,parmDict):
1006    ''' Compute neutron magnetic structure factors for all h,k,l for phase
1007    puts the result, F^2, in each ref[8] in refList
1008    operates on blocks of 100 reflections for speed
1009    input:
1010   
1011    :param dict refDict: where
1012        'RefList' list where each ref = h,k,l,it,d,...
1013        'FF' dict of form factors - filed in below
1014    :param np.array G:      reciprocal metric tensor
1015    :param str pfx:    phase id string
1016    :param dict SGData: space group info. dictionary output from SpcGroup
1017    :param dict calcControls:
1018    :param dict ParmDict:
1019       
1020    :returns: copy of new refList - used in calculating numerical derivatives
1021
1022    '''       
1023    g = nl.inv(G)
1024    ast = np.sqrt(np.diag(G))
1025    ainv = np.sqrt(np.diag(g))
1026    GS = G/np.outer(ast,ast)
1027    Ginv = g/np.outer(ainv,ainv)
1028    uAmat = G2lat.Gmat2AB(GS)[0]
1029    Mast = twopisq*np.multiply.outer(ast,ast)
1030    SGMT = np.array([ops[0].T for ops in SGData['SGOps']])
1031    SGT = np.array([ops[1] for ops in SGData['SGOps']])
1032    Ncen = len(SGData['SGCen'])
1033    Nops = len(SGMT)*Ncen
1034    if not SGData['SGFixed']:
1035        Nops *= (1+SGData['SGInv'])
1036    MFtables = calcControls['MFtables']
1037    Bmat = G2lat.Gmat2AB(G)[1]
1038    TwinLaw = np.ones(1)
1039#    TwinLaw = np.array([[[1,0,0],[0,1,0],[0,0,1]],])
1040#    TwDict = refDict.get('TwDict',{})           
1041#    if 'S' in calcControls[hfx+'histType']:
1042#        NTL = calcControls[phfx+'NTL']
1043#        NM = calcControls[phfx+'TwinNMN']+1
1044#        TwinLaw = calcControls[phfx+'TwinLaw']
1045#        TwinFr = np.array([parmDict[phfx+'TwinFr:'+str(i)] for i in range(len(TwinLaw))])
1046#        TwinInv = list(np.where(calcControls[phfx+'TwinInv'],-1,1))
1047    Tdata,Mdata,Fdata,Xdata,dXdata,IAdata,Uisodata,Uijdata,Gdata = \
1048        GetAtomFXU(pfx,calcControls,parmDict)
1049    if not Xdata.size:          #no atoms in phase!
1050        return
1051    Mag = np.array([np.sqrt(np.inner(mag,np.inner(mag,Ginv))) for mag in Gdata.T])
1052    Gdata = np.inner(Gdata.T,np.swapaxes(SGMT,1,2)).T            #apply sym. ops.
1053    if SGData['SGInv'] and not SGData['SGFixed']:
1054        Gdata = np.hstack((Gdata,-Gdata))       #inversion if any
1055    Gdata = np.hstack([Gdata for icen in range(Ncen)])        #dup over cell centering--> [Mxyz,nops,natms]
1056    Gdata = SGData['MagMom'][nxs,:,nxs]*Gdata   #flip vectors according to spin flip * det(opM)
1057    Mag = np.tile(Mag[:,nxs],Nops).#make Mag same length as Gdata
1058    Kdata = np.inner(Gdata.T,uAmat).T
1059    Kmean = np.mean(np.sqrt(np.sum(Kdata**2,axis=0)),axis=0)
1060    Kdata /= Kmean     #Cartesian unit vectors
1061    Uij = np.array(G2lat.U6toUij(Uijdata))
1062    bij = Mast*Uij.T
1063    blkSize = 100       #no. of reflections in a block - size seems optimal
1064    nRef = refDict['RefList'].shape[0]
1065    SQ = 1./(2.*refDict['RefList'].T[4])**2
1066    refDict['FF']['El'] = list(MFtables.keys())
1067    refDict['FF']['MF'] = np.zeros((nRef,len(MFtables)))
1068    for iel,El in enumerate(refDict['FF']['El']):
1069        refDict['FF']['MF'].T[iel] = G2el.MagScatFac(MFtables[El],SQ)
1070#reflection processing begins here - big arrays!
1071    iBeg = 0
1072    while iBeg < nRef:
1073        iFin = min(iBeg+blkSize,nRef)
1074        refl = refDict['RefList'][iBeg:iFin]    #array(blkSize,nItems)
1075        H = refl.T[:3].T                          #array(blkSize,3)
1076#        H = np.squeeze(np.inner(H.T,TwinLaw))   #maybe array(blkSize,nTwins,3) or (blkSize,3)
1077#        TwMask = np.any(H,axis=-1)
1078#        if TwinLaw.shape[0] > 1 and TwDict: #need np.inner(TwinLaw[?],TwDict[iref][i])*TwinInv[i]
1079#            for ir in range(blkSize):
1080#                iref = ir+iBeg
1081#                if iref in TwDict:
1082#                    for i in TwDict[iref]:
1083#                        for n in range(NTL):
1084#                            H[ir][i+n*NM] = np.inner(TwinLaw[n*NM],np.array(TwDict[iref][i])*TwinInv[i+n*NM])
1085#            TwMask = np.any(H,axis=-1)
1086        SQ = 1./(2.*refl.T[4])**2               #array(blkSize)
1087        SQfactor = 4.0*SQ*twopisq               #ditto prev.
1088        Uniq = np.inner(H,SGMT)
1089        Phi = np.inner(H,SGT)
1090        phase = twopi*(np.inner(Uniq,(dXdata+Xdata).T).T+Phi.T).T
1091        biso = -SQfactor*Uisodata[:,nxs]
1092        Tiso = np.repeat(np.where(biso<1.,np.exp(biso),1.0),len(SGT)*len(TwinLaw),axis=1).T
1093        HbH = -np.sum(Uniq.T*np.swapaxes(np.inner(bij,Uniq),2,-1),axis=1)
1094        Tuij = np.where(HbH<1.,np.exp(HbH),1.0).T
1095        Tindx = np.array([refDict['FF']['El'].index(El) for El in Tdata])
1096        MF = refDict['FF']['MF'][iBeg:iFin].T[Tindx].T   #Nref,Natm
1097        TMcorr = 0.539*(np.reshape(Tiso,Tuij.shape)*Tuij)[:,0,:]*Fdata*Mdata*MF/(2*Nops)     #Nref,Natm
1098        if SGData['SGInv']:
1099            if not SGData['SGFixed']:
1100                mphase = np.hstack((phase,-phase))  #OK
1101            else:
1102                mphase = phase
1103        else:
1104            mphase = phase                    #
1105        mphase = np.array([mphase+twopi*np.inner(cen,H)[:,nxs,nxs] for cen in SGData['SGCen']])
1106        mphase = np.concatenate(mphase,axis=1)              #Nref,full Nop,Natm
1107        sinm = np.sin(mphase)                               #ditto - match magstrfc.for
1108        cosm = np.cos(mphase)                               #ditto
1109        HM = np.inner(Bmat,H)                             #put into cartesian space
1110        HM = HM/np.sqrt(np.sum(HM**2,axis=0))               #Kdata = MAGS & HM = UVEC in magstrfc.for both OK
1111        eDotK = np.sum(HM[:,:,nxs,nxs]*Kdata[:,nxs,:,:],axis=0)
1112        Q = HM[:,:,nxs,nxs]*eDotK[nxs,:,:,:]-Kdata[:,nxs,:,:] #xyz,Nref,Nop,Natm = BPM in magstrfc.for OK
1113        fam = Q*TMcorr[nxs,:,nxs,:]*cosm[nxs,:,:,:]*Mag[nxs,nxs,:,:]    #ditto
1114        fbm = Q*TMcorr[nxs,:,nxs,:]*sinm[nxs,:,:,:]*Mag[nxs,nxs,:,:]    #ditto
1115        fams = np.sum(np.sum(fam,axis=-1),axis=-1)     #Mxyz,Nref  Sum(sum(fam,atoms),ops)
1116        fbms = np.sum(np.sum(fbm,axis=-1),axis=-1)     #ditto
1117        refl.T[9] = np.sum(fams**2,axis=0)+np.sum(fbms**2,axis=0)   #Sum(fams**2,Mxyz) Re + Im
1118        refl.T[7] = np.copy(refl.T[9])               
1119        refl.T[10] = atan2d(fbms[0],fams[0]) #- what is phase for mag refl?
1120#        if 'P' in calcControls[hfx+'histType']:     #PXC, PNC & PNT: F^2 = A[0]^2 + A[1]^2 + B[0]^2 + B[1]^2
1121#            refl.T[9] = np.sum(fas**2,axis=0)+np.sum(fbs**2,axis=0) #add fam**2 & fbm**2 here   
1122#            refl.T[10] = atan2d(fbs[0],fas[0])  #ignore f' & f"
1123#        else:                                       #HKLF: F^2 = (A[0]+A[1])^2 + (B[0]+B[1])^2
1124#            if len(TwinLaw) > 1:
1125#                refl.T[9] = np.sum(fas[:,:,0],axis=0)**2+np.sum(fbs[:,:,0],axis=0)**2   #FcT from primary twin element
1126#                refl.T[7] = np.sum(TwinFr*TwMask*np.sum(fas,axis=0)**2,axis=-1)+   \
1127#                    np.sum(TwinFr*TwMask*np.sum(fbs,axis=0)**2,axis=-1)                        #Fc sum over twins
1128#                refl.T[10] = atan2d(fbs[0].T[0],fas[0].T[0])  #ignore f' & f" & use primary twin
1129#            else:   # checked correct!!
1130#                refl.T[9] = np.sum(fas,axis=0)**2+np.sum(fbs,axis=0)**2
1131#                refl.T[7] = np.copy(refl.T[9])               
1132#                refl.T[10] = atan2d(fbs[0],fas[0])  #ignore f' & f"
1133##                refl.T[10] = atan2d(np.sum(fbs,axis=0),np.sum(fas,axis=0)) #include f' & f"
1134        iBeg += blkSize
1135#    print 'sf time %.4f, nref %d, blkSize %d'%(time.time()-time0,nRef,blkSize)
1136    return copy.deepcopy(refDict['RefList'])
1137
1138def MagStructureFactorDerv2(refDict,G,hfx,pfx,SGData,calcControls,parmDict):
1139    '''Compute magnetic structure factor derivatives numerically - for powders/nontwins only
1140    input:
1141   
1142    :param dict refDict: where
1143        'RefList' list where each ref = h,k,l,it,d,...
1144        'FF' dict of form factors - filled in below
1145    :param np.array G:      reciprocal metric tensor
1146    :param str hfx:    histogram id string
1147    :param str pfx:    phase id string
1148    :param dict SGData: space group info. dictionary output from SpcGroup
1149    :param dict calcControls:
1150    :param dict parmDict:
1151   
1152    :returns: dict dFdvDict: dictionary of magnetic derivatives
1153    '''
1154   
1155    trefDict = copy.deepcopy(refDict)
1156    dM = 1.e-6
1157    dFdvDict = {}
1158    for parm in parmDict:
1159        if 'AM' in parm:
1160            parmDict[parm] += dM
1161            prefList = MagStructureFactor2(trefDict,G,hfx,pfx,SGData,calcControls,parmDict)
1162            parmDict[parm] -= 2*dM
1163            mrefList = MagStructureFactor2(trefDict,G,hfx,pfx,SGData,calcControls,parmDict)
1164            parmDict[parm] += dM
1165            dFdvDict[parm] = (prefList[:,9]-mrefList[:,9])/(2.*dM)
1166    return dFdvDict
1167           
1168def MagStructureFactorDerv(refDict,G,hfx,pfx,SGData,calcControls,parmDict):
1169    '''Compute nonmagnetic structure factor derivatives on blocks of reflections in magnetic structures - for powders/nontwins only
1170    input:
1171   
1172    :param dict refDict: where
1173        'RefList' list where each ref = h,k,l,it,d,...
1174        'FF' dict of form factors - filled in below
1175    :param np.array G:      reciprocal metric tensor
1176    :param str hfx:    histogram id string
1177    :param str pfx:    phase id string
1178    :param dict SGData: space group info. dictionary output from SpcGroup
1179    :param dict calcControls:
1180    :param dict parmDict:
1181   
1182    :returns: dict dFdvDict: dictionary of derivatives
1183    '''
1184   
1185    g = nl.inv(G)
1186    ast = np.sqrt(np.diag(G))
1187    ainv = np.sqrt(np.diag(g))
1188    GS = G/np.outer(ast,ast)
1189    Ginv = g/np.outer(ainv,ainv)
1190    uAmat = G2lat.Gmat2AB(GS)[0]
1191    Mast = twopisq*np.multiply.outer(ast,ast)
1192    SGMT = np.array([ops[0].T for ops in SGData['SGOps']])
1193    SGT = np.array([ops[1] for ops in SGData['SGOps']])
1194    Ncen = len(SGData['SGCen'])
1195    Nops = len(SGMT)*Ncen
1196    if not SGData['SGFixed']:
1197        Nops *= (1+SGData['SGInv'])
1198    Bmat = G2lat.Gmat2AB(G)[1]
1199    nRef = len(refDict['RefList'])
1200    Tdata,Mdata,Fdata,Xdata,dXdata,IAdata,Uisodata,Uijdata,Gdata = \
1201        GetAtomFXU(pfx,calcControls,parmDict)
1202    if not Xdata.size:          #no atoms in phase!
1203        return {}
1204    mSize = len(Mdata)
1205    Mag = np.array([np.sqrt(np.inner(mag,np.inner(mag,Ginv))) for mag in Gdata.T])
1206    Gones = np.ones_like(Gdata)
1207    Gdata = np.inner(Gdata.T,np.swapaxes(SGMT,1,2)).T            #apply sym. ops.
1208    Gones = np.inner(Gones.T,SGMT).T
1209    if SGData['SGInv'] and not SGData['SGFixed']:
1210        Gdata = np.hstack((Gdata,-Gdata))       #inversion if any
1211        Gones = np.hstack((Gones,-Gones))       #inversion if any
1212    Gdata = np.hstack([Gdata for icen in range(Ncen)])        #dup over cell centering
1213    Gones = np.hstack([Gones for icen in range(Ncen)])        #dup over cell centering
1214    Gdata = SGData['MagMom'][nxs,:,nxs]*Gdata   #flip vectors according to spin flip
1215    Gones = SGData['MagMom'][nxs,:,nxs]*Gones   #flip vectors according to spin flip
1216    Mag = np.tile(Mag[:,nxs],Nops).#make Mag same length as Gdata
1217    Kdata = np.inner(Gdata.T,uAmat).T     #Cartesian unit vectors
1218    Kmean = np.mean(np.sqrt(np.sum(Kdata**2,axis=0)),axis=0)
1219    Kdata /= Kmean
1220    Uij = np.array(G2lat.U6toUij(Uijdata))
1221    bij = Mast*Uij.T
1222    dFdvDict = {}
1223    dFdfr = np.zeros((nRef,mSize))
1224    dFdx = np.zeros((nRef,mSize,3))
1225    dFdui = np.zeros((nRef,mSize))
1226    dFdua = np.zeros((nRef,mSize,6))
1227    time0 = time.time()
1228#reflection processing begins here - big arrays!
1229    iBeg = 0
1230    blkSize = 5       #no. of reflections in a block - optimized for speed
1231    while iBeg < nRef:
1232        iFin = min(iBeg+blkSize,nRef)
1233        refl = refDict['RefList'][iBeg:iFin]    #array(blkSize,nItems)
1234        H = refl.T[:3].T
1235        SQ = 1./(2.*refl.T[4])**2             # or (sin(theta)/lambda)**2
1236        SQfactor = 8.0*SQ*np.pi**2
1237        Uniq = np.inner(H,SGMT)             # array(nSGOp,3)
1238        Phi = np.inner(H,SGT)
1239        phase = twopi*(np.inner(Uniq,(dXdata+Xdata).T).T+Phi.T).T
1240        occ = Mdata*Fdata/Nops
1241        biso = -SQfactor*Uisodata[:,nxs]
1242        Tiso = np.repeat(np.where(biso<1.,np.exp(biso),1.0),len(SGT),axis=1).T
1243        HbH = -np.sum(Uniq.T*np.swapaxes(np.inner(bij,Uniq),2,-1),axis=1)
1244        Tuij = np.where(HbH<1.,np.exp(HbH),1.0).T
1245        Hij = np.array([Mast*np.multiply.outer(U,U) for U in np.reshape(Uniq,(-1,3))])
1246        Hij = np.reshape(np.array([G2lat.UijtoU6(uij) for uij in Hij]),(-1,len(SGT),6))
1247        Tindx = np.array([refDict['FF']['El'].index(El) for El in Tdata])
1248        MF = refDict['FF']['MF'][iBeg:iFin].T[Tindx].T   #Nref,Natm
1249        TMcorr = 0.539*(np.reshape(Tiso,Tuij.shape)*Tuij)[:,0,:]*Fdata*Mdata*MF/(2*Nops)     #Nref,Natm
1250        if SGData['SGInv']:
1251            if not SGData['SGFixed']:
1252                mphase = np.hstack((phase,-phase))  #OK
1253                Uniq = np.hstack((Uniq,-Uniq))      #Nref,Nops,hkl
1254                Hij = np.hstack((Hij,Hij))
1255            else:
1256                mphase = phase
1257        else:
1258            mphase = phase                    #
1259        Hij = np.concatenate(np.array([Hij for cen in SGData['SGCen']]),axis=1)
1260        Uniq = np.hstack([Uniq for cen in SGData['SGCen']])
1261        mphase = np.array([mphase+twopi*np.inner(cen,H)[:,nxs,nxs] for cen in SGData['SGCen']])
1262        mphase = np.concatenate(mphase,axis=1)              #Nref,Nop,Natm
1263        sinm = np.sin(mphase)                               #ditto - match magstrfc.for
1264        cosm = np.cos(mphase)                               #ditto
1265        HM = np.inner(Bmat.T,H)                             #put into cartesian space
1266        HM = HM/np.sqrt(np.sum(HM**2,axis=0))               #unit cartesian vector for H
1267        eDotK = np.sum(HM[:,:,nxs,nxs]*Kdata[:,nxs,:,:],axis=0)
1268        Q = HM[:,:,nxs,nxs]*eDotK[nxs,:,:,:]-Kdata[:,nxs,:,:] #Mxyz,Nref,Nop,Natm = BPM in magstrfc.for OK
1269       
1270        fam = Q*TMcorr[nxs,:,nxs,:]*cosm[nxs,:,:,:]*Mag[nxs,nxs,:,:]    #Mxyz,Nref,Nop,Natm
1271        fbm = Q*TMcorr[nxs,:,nxs,:]*sinm[nxs,:,:,:]*Mag[nxs,nxs,:,:]
1272        fams = np.sum(np.sum(fam,axis=-1),axis=-1)                      #Mxyz,Nref
1273        fbms = np.sum(np.sum(fbm,axis=-1),axis=-1)
1274        famx = -Q*TMcorr[nxs,:,nxs,:]*Mag[nxs,nxs,:,:]*sinm[nxs,:,:,:]   #Mxyz,Nref,Nops,Natom
1275        fbmx = Q*TMcorr[nxs,:,nxs,:]*Mag[nxs,nxs,:,:]*cosm[nxs,:,:,:]
1276        #sums below are over Nops - real part
1277        dfadfr = np.sum(fam/occ,axis=2)        #array(Mxyz,refBlk,nAtom) Fdata != 0 avoids /0. problem deriv OK
1278        dfadx = np.sum(twopi*Uniq[nxs,:,:,nxs,:]*famx[:,:,:,:,nxs],axis=2)          #deriv OK
1279        dfadui = np.sum(-SQfactor[:,nxs,nxs]*fam,axis=2) #array(Ops,refBlk,nAtoms)  deriv OK
1280        dfadua = np.sum(-Hij[nxs,:,:,nxs,:]*fam[:,:,:,:,nxs],axis=2)            #deriv OK
1281        # imaginary part; array(3,refBlk,nAtom,3) & array(3,refBlk,nAtom,6)
1282        dfbdfr = np.sum(fbm/occ,axis=2)        #array(mxyz,refBlk,nAtom) Fdata != 0 avoids /0. problem
1283        dfbdx = np.sum(twopi*Uniq[nxs,:,:,nxs,:]*fbmx[:,:,:,:,nxs],axis=2)
1284        dfbdui = np.sum(-SQfactor[:,nxs,nxs]*fbm,axis=2) #array(Ops,refBlk,nAtoms)
1285        dfbdua = np.sum(-Hij[nxs,:,:,nxs,:]*fbm[:,:,:,:,nxs],axis=2)
1286        #accumulate derivatives   
1287        dFdfr[iBeg:iFin] = 2.*np.sum((fams[:,:,nxs]*dfadfr+fbms[:,:,nxs]*dfbdfr)*Mdata/Nops,axis=0) #ok
1288        dFdx[iBeg:iFin] = 2.*np.sum(fams[:,:,nxs,nxs]*dfadx+fbms[:,:,nxs,nxs]*dfbdx,axis=0)         #ok
1289        dFdui[iBeg:iFin] = 2.*np.sum(fams[:,:,nxs]*dfadui+fbms[:,:,nxs]*dfbdui,axis=0)              #ok
1290        dFdua[iBeg:iFin] = 2.*np.sum(fams[:,:,nxs,nxs]*dfadua+fbms[:,:,nxs,nxs]*dfbdua,axis=0)      #ok
1291        iBeg += blkSize
1292    print (' %d derivative time %.4f\r'%(nRef,time.time()-time0))
1293        #loop over atoms - each dict entry is list of derivatives for all the reflections
1294    for i in range(len(Mdata)):
1295        dFdvDict[pfx+'Afrac:'+str(i)] = dFdfr.T[i]
1296        dFdvDict[pfx+'dAx:'+str(i)] = dFdx.T[0][i]
1297        dFdvDict[pfx+'dAy:'+str(i)] = dFdx.T[1][i]
1298        dFdvDict[pfx+'dAz:'+str(i)] = dFdx.T[2][i]
1299        dFdvDict[pfx+'AUiso:'+str(i)] = dFdui.T[i]
1300        dFdvDict[pfx+'AU11:'+str(i)] = dFdua.T[0][i]
1301        dFdvDict[pfx+'AU22:'+str(i)] = dFdua.T[1][i]
1302        dFdvDict[pfx+'AU33:'+str(i)] = dFdua.T[2][i]
1303        dFdvDict[pfx+'AU12:'+str(i)] = 2.*dFdua.T[3][i]
1304        dFdvDict[pfx+'AU13:'+str(i)] = 2.*dFdua.T[4][i]
1305        dFdvDict[pfx+'AU23:'+str(i)] = 2.*dFdua.T[5][i]
1306    return dFdvDict
1307       
1308def StructureFactorDervTw2(refDict,G,hfx,pfx,SGData,calcControls,parmDict):
1309    '''Compute structure factor derivatives on blocks of reflections - for twins only
1310    faster than StructureFactorDervTw
1311    input:
1312   
1313    :param dict refDict: where
1314        'RefList' list where each ref = h,k,l,it,d,...
1315        'FF' dict of form factors - filled in below
1316    :param np.array G:      reciprocal metric tensor
1317    :param str hfx:    histogram id string
1318    :param str pfx:    phase id string
1319    :param dict SGData: space group info. dictionary output from SpcGroup
1320    :param dict calcControls:
1321    :param dict parmDict:
1322   
1323    :returns: dict dFdvDict: dictionary of derivatives
1324    '''
1325    phfx = pfx.split(':')[0]+hfx
1326    ast = np.sqrt(np.diag(G))
1327    Mast = twopisq*np.multiply.outer(ast,ast)
1328    SGMT = np.array([ops[0].T for ops in SGData['SGOps']])
1329    SGT = np.array([ops[1] for ops in SGData['SGOps']])
1330    FFtables = calcControls['FFtables']
1331    BLtables = calcControls['BLtables']
1332    TwDict = refDict.get('TwDict',{})           
1333    NTL = calcControls[phfx+'NTL']
1334    NM = calcControls[phfx+'TwinNMN']+1
1335    TwinLaw = calcControls[phfx+'TwinLaw']
1336    TwinFr = np.array([parmDict[phfx+'TwinFr:'+str(i)] for i in range(len(TwinLaw))])
1337    TwinInv = list(np.where(calcControls[phfx+'TwinInv'],-1,1))
1338    nTwin = len(TwinLaw)       
1339    nRef = len(refDict['RefList'])
1340    Tdata,Mdata,Fdata,Xdata,dXdata,IAdata,Uisodata,Uijdata,Gdata = \
1341        GetAtomFXU(pfx,calcControls,parmDict)
1342    if not Xdata.size:          #no atoms in phase!
1343        return {}
1344    mSize = len(Mdata)
1345    FF = np.zeros(len(Tdata))
1346    if 'NC' in calcControls[hfx+'histType'] or 'NB' in calcControls[hfx+'histType']:
1347        FP,FPP = G2el.BlenResCW(Tdata,BLtables,parmDict[hfx+'Lam'])
1348    elif 'X' in calcControls[hfx+'histType']:
1349        FP = np.array([FFtables[El][hfx+'FP'] for El in Tdata])
1350        FPP = np.array([FFtables[El][hfx+'FPP'] for El in Tdata])
1351    Uij = np.array(G2lat.U6toUij(Uijdata))
1352    bij = Mast*Uij.T
1353    dFdvDict = {}
1354    dFdfr = np.zeros((nRef,nTwin,mSize))
1355    dFdx = np.zeros((nRef,nTwin,mSize,3))
1356    dFdui = np.zeros((nRef,nTwin,mSize))
1357    dFdua = np.zeros((nRef,nTwin,mSize,6))
1358    dFdbab = np.zeros((nRef,nTwin,2))
1359    dFdtw = np.zeros((nRef,nTwin))
1360    time0 = time.time()
1361#reflection processing begins here - big arrays!
1362    iBeg = 0
1363    blkSize = 16       #no. of reflections in a block - optimized for speed
1364    while iBeg < nRef:
1365        iFin = min(iBeg+blkSize,nRef)
1366        refl = refDict['RefList'][iBeg:iFin]    #array(blkSize,nItems)
1367        H = refl.T[:3]
1368        H = np.inner(H.T,TwinLaw)   #array(3,nTwins)
1369        TwMask = np.any(H,axis=-1)
1370        for ir in range(blkSize):
1371            iref = ir+iBeg
1372            if iref in TwDict:
1373                for i in TwDict[iref]:
1374                    for n in range(NTL):
1375                        H[ir][i+n*NM] = np.inner(TwinLaw[n*NM],np.array(TwDict[iref][i])*TwinInv[i+n*NM])
1376        TwMask = np.any(H,axis=-1)
1377        SQ = 1./(2.*refl.T[4])**2             # or (sin(theta)/lambda)**2
1378        SQfactor = 8.0*SQ*np.pi**2
1379        if 'T' in calcControls[hfx+'histType']:
1380            if 'P' in calcControls[hfx+'histType']:
1381                FP,FPP = G2el.BlenResTOF(Tdata,BLtables,refl.T[14])
1382            else:
1383                FP,FPP = G2el.BlenResTOF(Tdata,BLtables,refl.T[12])
1384            FP = np.repeat(FP.T,len(SGT)*len(TwinLaw),axis=0)
1385            FPP = np.repeat(FPP.T,len(SGT)*len(TwinLaw),axis=0)
1386        dBabdA = np.exp(-parmDict[phfx+'BabU']*SQfactor)
1387        Bab = np.repeat(parmDict[phfx+'BabA']*dBabdA,len(SGT)*nTwin)
1388        Tindx = np.array([refDict['FF']['El'].index(El) for El in Tdata])
1389        FF = np.repeat(refDict['FF']['FF'][iBeg:iFin].T[Tindx].T,len(SGT)*len(TwinLaw),axis=0)
1390        Uniq = np.inner(H,SGMT)             # (nTwin,nSGOp,3)
1391        Phi = np.inner(H,SGT)
1392        phase = twopi*(np.inner(Uniq,(dXdata+Xdata).T).T+Phi.T).T
1393        sinp = np.sin(phase)
1394        cosp = np.cos(phase)
1395        occ = Mdata*Fdata/len(SGT)
1396        biso = -SQfactor*Uisodata[:,nxs]
1397        Tiso = np.repeat(np.where(biso<1.,np.exp(biso),1.0),len(SGT)*nTwin,axis=1)
1398        HbH = -np.sum(Uniq.T*np.swapaxes(np.inner(bij,Uniq),2,-1),axis=1)
1399        Hij = np.array([Mast*np.multiply.outer(U,U) for U in np.reshape(Uniq,(-1,3))])
1400        Hij = np.reshape(np.array([G2lat.UijtoU6(uij) for uij in Hij]),(-1,nTwin,len(SGT),6))
1401        Tuij = np.where(HbH<1.,np.exp(HbH),1.0)
1402        Tcorr = (np.reshape(Tiso,Tuij.shape)*Tuij).T*Mdata*Fdata/len(SGMT)
1403        fot = np.reshape(((FF+FP).T-Bab).T,cosp.shape)*Tcorr
1404        fotp = FPP*Tcorr       
1405        if 'T' in calcControls[hfx+'histType']: #fa,fb are 2 X blkSize X nTwin X nOps x nAtoms
1406            fa = np.array([np.reshape(((FF+FP).T-Bab).T,cosp.shape)*cosp*Tcorr,-np.reshape(FPP,sinp.shape)*sinp*Tcorr])
1407            fb = np.array([np.reshape(((FF+FP).T-Bab).T,sinp.shape)*sinp*Tcorr,np.reshape(FPP,cosp.shape)*cosp*Tcorr])
1408        else:
1409            fa = np.array([np.reshape(((FF+FP).T-Bab).T,cosp.shape)*cosp*Tcorr,-FPP*sinp*Tcorr])
1410            fb = np.array([np.reshape(((FF+FP).T-Bab).T,sinp.shape)*sinp*Tcorr,FPP*cosp*Tcorr])
1411        fas = np.sum(np.sum(fa,axis=-1),axis=-1)      #real sum over atoms & unique hkl array(2,nTwins)
1412        fbs = np.sum(np.sum(fb,axis=-1),axis=-1)      #imag sum over atoms & uniq hkl
1413        if SGData['SGInv']: #centrosymmetric; B=0
1414            fbs[0] *= 0.
1415            fas[1] *= 0.
1416        fax = np.array([-fot*sinp,-fotp*cosp])   #positions array(2,nRef,ntwi,nEqv,nAtoms)
1417        fbx = np.array([fot*cosp,-fotp*sinp])
1418        #sum below is over Uniq
1419        dfadfr = np.sum(np.sum(fa/occ,axis=-2),axis=0)        #array(2,nRef,ntwin,nAtom) Fdata != 0 avoids /0. problem
1420        dfadba = np.sum(-cosp*Tcorr[:,nxs],axis=1)
1421        dfadui = np.sum(np.sum(-SQfactor[nxs,:,nxs,nxs,nxs]*fa,axis=-2),axis=0)           
1422        dfadx = np.sum(np.sum(twopi*Uniq[nxs,:,:,:,nxs,:]*fax[:,:,:,:,:,nxs],axis=-3),axis=0) # nRef x nTwin x nAtoms x xyz; sum on ops & A,A'
1423        dfadua = np.sum(np.sum(-Hij[nxs,:,:,:,nxs,:]*fa[:,:,:,:,:,nxs],axis=-3),axis=0) 
1424        if not SGData['SGInv']:
1425            dfbdfr = np.sum(np.sum(fb/occ,axis=-2),axis=0)        #Fdata != 0 avoids /0. problem
1426            dfadba /= 2.
1427#            dfbdba = np.sum(-sinp*Tcorr[:,nxs],axis=1)/2.
1428            dfbdui = np.sum(np.sum(-SQfactor[nxs,:,nxs,nxs,nxs]*fb,axis=-2),axis=0)
1429            dfbdx = np.sum(np.sum(twopi*Uniq[nxs,:,:,:,nxs,:]*fbx[:,:,:,:,:,nxs],axis=-3),axis=0)
1430            dfbdua = np.sum(np.sum(-Hij[nxs,:,:,:,nxs,:]*fb[:,:,:,:,:,nxs],axis=-3),axis=0)
1431        else:
1432            dfbdfr = np.zeros_like(dfadfr)
1433            dfbdx = np.zeros_like(dfadx)
1434            dfbdui = np.zeros_like(dfadui)
1435            dfbdua = np.zeros_like(dfadua)
1436#            dfbdba = np.zeros_like(dfadba)
1437        SA = fas[0]+fas[1]
1438        SB = fbs[0]+fbs[1]
1439        dFdfr[iBeg:iFin] = ((2.*TwMask*SA)[:,:,nxs]*dfadfr+(2.*TwMask*SB)[:,:,nxs]*dfbdfr)*Mdata[nxs,nxs,:]/len(SGMT)
1440        dFdx[iBeg:iFin] = (2.*TwMask*SA)[:,:,nxs,nxs]*dfadx+(2.*TwMask*SB)[:,:,nxs,nxs]*dfbdx
1441        dFdui[iBeg:iFin] = (2.*TwMask*SA)[:,:,nxs]*dfadui+(2.*TwMask*SB)[:,:,nxs]*dfbdui
1442        dFdua[iBeg:iFin] = (2.*TwMask*SA)[:,:,nxs,nxs]*dfadua+(2.*TwMask*SB)[:,:,nxs,nxs]*dfbdua
1443        if SGData['SGInv']: #centrosymmetric; B=0
1444            dFdtw[iBeg:iFin] = np.sum(TwMask[nxs,:]*fas,axis=0)**2
1445        else:               
1446            dFdtw[iBeg:iFin] = np.sum(TwMask[nxs,:]*fas,axis=0)**2+np.sum(TwMask[nxs,:]*fbs,axis=0)**2
1447#        dFdbab[iBeg:iFin] = fas[0,:,nxs]*np.array([np.sum(dfadba*dBabdA),np.sum(-dfadba*parmDict[phfx+'BabA']*SQfactor*dBabdA)]).T+ \
1448#            fbs[0,:,nxs]*np.array([np.sum(dfbdba*dBabdA),np.sum(-dfbdba*parmDict[phfx+'BabA']*SQfactor*dBabdA)]).T
1449        iBeg += blkSize
1450    print (' %d derivative time %.4f\r'%(len(refDict['RefList']),time.time()-time0))
1451    #loop over atoms - each dict entry is list of derivatives for all the reflections
1452    for i in range(len(Mdata)):     #these all OK
1453        dFdvDict[pfx+'Afrac:'+str(i)] = np.sum(dFdfr.T[i]*TwinFr[:,nxs],axis=0)
1454        dFdvDict[pfx+'dAx:'+str(i)] = np.sum(dFdx.T[0][i]*TwinFr[:,nxs],axis=0)
1455        dFdvDict[pfx+'dAy:'+str(i)] = np.sum(dFdx.T[1][i]*TwinFr[:,nxs],axis=0)
1456        dFdvDict[pfx+'dAz:'+str(i)] = np.sum(dFdx.T[2][i]*TwinFr[:,nxs],axis=0)
1457        dFdvDict[pfx+'AUiso:'+str(i)] = np.sum(dFdui.T[i]*TwinFr[:,nxs],axis=0)
1458        dFdvDict[pfx+'AU11:'+str(i)] = np.sum(dFdua.T[0][i]*TwinFr[:,nxs],axis=0)
1459        dFdvDict[pfx+'AU22:'+str(i)] = np.sum(dFdua.T[1][i]*TwinFr[:,nxs],axis=0)
1460        dFdvDict[pfx+'AU33:'+str(i)] = np.sum(dFdua.T[2][i]*TwinFr[:,nxs],axis=0)
1461        dFdvDict[pfx+'AU12:'+str(i)] = 2.*np.sum(dFdua.T[3][i]*TwinFr[:,nxs],axis=0)
1462        dFdvDict[pfx+'AU13:'+str(i)] = 2.*np.sum(dFdua.T[4][i]*TwinFr[:,nxs],axis=0)
1463        dFdvDict[pfx+'AU23:'+str(i)] = 2.*np.sum(dFdua.T[5][i]*TwinFr[:,nxs],axis=0)
1464    dFdvDict[phfx+'BabA'] = dFdbab.T[0]
1465    dFdvDict[phfx+'BabU'] = dFdbab.T[1]
1466    for i in range(nTwin):
1467        dFdvDict[phfx+'TwinFr:'+str(i)] = dFdtw.T[i]
1468    return dFdvDict
1469   
1470def SStructureFactor(refDict,G,hfx,pfx,SGData,SSGData,calcControls,parmDict):
1471    '''
1472    Compute super structure factors for all h,k,l,m for phase - no twins
1473    puts the result, F^2, in each ref[9] in refList
1474    works on blocks of 32 reflections for speed
1475    input:
1476   
1477    :param dict refDict: where
1478        'RefList' list where each ref = h,k,l,m,it,d,...
1479        'FF' dict of form factors - filed in below
1480    :param np.array G:      reciprocal metric tensor
1481    :param str pfx:    phase id string
1482    :param dict SGData: space group info. dictionary output from SpcGroup
1483    :param dict calcControls:
1484    :param dict ParmDict:
1485
1486    '''
1487    phfx = pfx.split(':')[0]+hfx
1488    ast = np.sqrt(np.diag(G))
1489    GS = G/np.outer(ast,ast)
1490    uAmat,uBmat = G2lat.Gmat2AB(GS)
1491    Mast = twopisq*np.multiply.outer(ast,ast)   
1492    SGInv = SGData['SGInv']
1493    SGMT = np.array([ops[0].T for ops in SGData['SGOps']])
1494    Nops = len(SGMT)*(1+SGData['SGInv'])
1495    if SGData['SGGray']:
1496        Nops *= 2
1497    SSGMT = np.array([ops[0].T for ops in SSGData['SSGOps']])
1498    SSGT = np.array([ops[1] for ops in SSGData['SSGOps']])
1499    SSCen = SSGData['SSGCen']
1500    FFtables = calcControls['FFtables']
1501    BLtables = calcControls['BLtables']
1502    MFtables = calcControls['MFtables']
1503    Amat,Bmat = G2lat.Gmat2AB(G)
1504    Flack = 1.0
1505    if not SGData['SGInv'] and 'S' in calcControls[hfx+'histType'] and phfx+'Flack' in parmDict:
1506        Flack = 1.-2.*parmDict[phfx+'Flack']
1507    Tdata,Mdata,Fdata,Xdata,dXdata,IAdata,Uisodata,Uijdata,Gdata = \
1508        GetAtomFXU(pfx,calcControls,parmDict)
1509    if not Xdata.size:          #no atoms in phase!
1510        return
1511    waveTypes,FSSdata,XSSdata,USSdata,MSSdata = GetAtomSSFXU(pfx,calcControls,parmDict)
1512    ngl,nWaves,Fmod,Xmod,Umod,Mmod,glTau,glWt = G2mth.makeWaves(waveTypes,FSSdata,XSSdata,USSdata,MSSdata,Mast)      #NB: Mmod is ReIm,Mxyz,Ntau,Natm
1513    modQ = np.array([parmDict[pfx+'mV0'],parmDict[pfx+'mV1'],parmDict[pfx+'mV2']])
1514
1515    if parmDict[pfx+'isMag']:       #This part correct for making modulated mag moments on equiv atoms - Mmod matched drawing & Bilbao drawings
1516   
1517        mXYZ = np.array([[XYZ[0] for XYZ in list(G2spc.GenAtom(xyz,SGData,All=True,Move=True))] for xyz in (Xdata+dXdata).T]) #Natn,Nop,xyz
1518        if SGData['SGGray']:
1519            mXYZ = np.hstack((mXYZ,mXYZ))
1520
1521        MmodA,MmodB = G2mth.MagMod(glTau,mXYZ,modQ,MSSdata,SGData,SSGData)  #Ntau,Nops,Natm,Mxyz cos,sim parts sum matches drawing
1522       
1523        if not SGData['SGGray']:    #for fixed Mx,My,Mz
1524            GSdata = np.inner(Gdata.T,np.swapaxes(SGMT,1,2))  #apply sym. ops.--> Natm,Nops,Nxyz
1525            if SGData['SGInv'] and not SGData['SGFixed']:   #inversion if any
1526                GSdata = np.hstack((GSdata,-GSdata))     
1527            GSdata = np.hstack([GSdata for cen in SSCen])        #dup over cell centering - Natm,Nops,Mxyz
1528            GSdata = SGData['MagMom'][nxs,:,nxs]*GSdata   #flip vectors according to spin flip * det(opM)
1529            GSdata = np.swapaxes(GSdata,0,1)    #Nop,Natm,Mxyz
1530       
1531    FF = np.zeros(len(Tdata))
1532    if 'NC' in calcControls[hfx+'histType'] or 'NB' in calcControls[hfx+'histType']:
1533        FP,FPP = G2el.BlenResCW(Tdata,BLtables,parmDict[hfx+'Lam'])
1534    elif 'X' in calcControls[hfx+'histType']:
1535        FP = np.array([FFtables[El][hfx+'FP'] for El in Tdata])
1536        FPP = np.array([FFtables[El][hfx+'FPP'] for El in Tdata])
1537    Uij = np.array(G2lat.U6toUij(Uijdata)).T
1538    bij = Mast*Uij
1539    blkSize = 48       #no. of reflections in a block
1540    nRef = refDict['RefList'].shape[0]
1541    SQ = 1./(2.*refDict['RefList'].T[5])**2
1542    if 'N' in calcControls[hfx+'histType']:
1543        dat = G2el.getBLvalues(BLtables)
1544        refDict['FF']['El'] = list(dat.keys())
1545        refDict['FF']['FF'] = np.ones((nRef,len(dat)))*list(dat.values())
1546        refDict['FF']['MF'] = np.zeros((nRef,len(dat)))
1547        for iel,El in enumerate(refDict['FF']['El']):
1548            if El in MFtables:
1549                refDict['FF']['MF'].T[iel] = G2el.MagScatFac(MFtables[El],SQ)
1550    else:
1551        dat = G2el.getFFvalues(FFtables,0.)
1552        refDict['FF']['El'] = list(dat.keys())
1553        refDict['FF']['FF'] = np.zeros((nRef,len(dat)))
1554        for iel,El in enumerate(refDict['FF']['El']):
1555            refDict['FF']['FF'].T[iel] = G2el.ScatFac(FFtables[El],SQ)
1556#reflection processing begins here - big arrays!
1557    iBeg = 0
1558    while iBeg < nRef:
1559        iFin = min(iBeg+blkSize,nRef)
1560        mRef= iFin-iBeg
1561        refl = refDict['RefList'][iBeg:iFin]    #array(blkSize,nItems)
1562        H = refl.T[:4]                          #array(blkSize,4)
1563        HP = H[:3]+modQ[:,nxs]*H[3:]            #projected hklm to hkl
1564        SQ = 1./(2.*refl.T[5])**2               #array(blkSize)
1565        SQfactor = 4.0*SQ*twopisq               #ditto prev.
1566        Uniq = np.inner(H.T,SSGMT)
1567        UniqP = np.inner(HP.T,SGMT)
1568        Phi = np.inner(H.T,SSGT)
1569        if SGInv and not SGData['SGFixed']:   #if centro - expand HKL sets
1570            Uniq = np.hstack((Uniq,-Uniq))
1571            Phi = np.hstack((Phi,-Phi))
1572            UniqP = np.hstack((UniqP,-UniqP))
1573        if 'T' in calcControls[hfx+'histType']:
1574            if 'P' in calcControls[hfx+'histType']:
1575                FP,FPP = G2el.BlenResTOF(Tdata,BLtables,refl.T[14])
1576            else:
1577                FP,FPP = G2el.BlenResTOF(Tdata,BLtables,refl.T[12])
1578            FP = np.repeat(FP.T,Uniq.shape[1],axis=0)
1579            FPP = np.repeat(FPP.T,Uniq.shape[1],axis=0)
1580        Bab = 0.
1581        if phfx+'BabA' in parmDict:
1582            Bab = np.repeat(parmDict[phfx+'BabA']*np.exp(-parmDict[phfx+'BabU']*SQfactor),Uniq.shape[1])
1583        Tindx = np.array([refDict['FF']['El'].index(El) for El in Tdata])
1584        FF = np.repeat(refDict['FF']['FF'][iBeg:iFin].T[Tindx].T,Uniq.shape[1],axis=0)
1585        phase = twopi*(np.inner(Uniq[:,:,:3],(dXdata.T+Xdata.T))-Phi[:,:,nxs])
1586        phase = np.hstack([phase for cen in SSCen])
1587        sinp = np.sin(phase)
1588        cosp = np.cos(phase)
1589        biso = -SQfactor*Uisodata[:,nxs]
1590        Tiso = np.repeat(np.where(biso<1.,np.exp(biso),1.0),Uniq.shape[1],axis=1).T
1591        HbH = -np.sum(UniqP[:,:,nxs,:]*np.inner(UniqP[:,:,:],bij),axis=-1)  #use hklt proj to hkl
1592        Tuij = np.where(HbH<1.,np.exp(HbH),1.0)
1593        Tcorr = np.reshape(Tiso,Tuij.shape)*Tuij*Mdata*Fdata/Uniq.shape[1]  #refBlk x ops x atoms
1594
1595        if 'N' in calcControls[hfx+'histType'] and parmDict[pfx+'isMag']:           
1596           
1597            phasem = twopi*np.inner(mXYZ,HP.T).T    #2pi(Q.r)
1598            cosm = np.cos(phasem)                   #Nref,nops,natm
1599            sinm = np.sin(phasem)
1600            MF = refDict['FF']['MF'][iBeg:iFin].T[Tindx].T   #Nref,Natm
1601            TMcorr = 0.539*(np.reshape(Tiso,Tuij.shape)*Tuij)[:,0,:]*Mdata*Fdata*MF/(2*Nops)     #Nref,Natm
1602            HM = np.inner(uAmat,HP.T)                    #put into cartesian space X||H,Z||H*L; uAmat better than uBmat
1603            eM = (HM/np.sqrt(np.sum(HM**2,axis=0))).T    # normalize  HP  Nref,hkl=Unit vectors || Q
1604
1605            if not SGData['SGGray']:     #correct -fixed Mx,My,Mz contribution             
1606                fam0 = TMcorr[:,nxs,:,nxs]*GSdata[nxs,:,:,:]*cosm[:,:,:,nxs]    #Nref,Nops,Natm,Mxyz
1607                fbm0 = TMcorr[:,nxs,:,nxs]*GSdata[nxs,:,:,:]*sinm[:,:,:,nxs]
1608#  calc mag. structure factors; Nref,Ntau,Nops,Natm,Mxyz                           
1609            fams = TMcorr[:,nxs,nxs,:,nxs]*np.array([np.where(H[3,i]!=0,(MmodA*cosm[i,nxs,:,:,nxs]+   
1610                H[3,i]*MmodB*sinm[i,nxs,:,:,nxs]),0.) for i in range(mRef)])          #Nref,Ntau,Nops,Natm,Mxyz
1611                       
1612            fbms = TMcorr[:,nxs,nxs,:,nxs]*np.array([np.where(H[3,i]!=0,(MmodA*sinm[i,nxs,:,:,nxs]+   
1613                H[3,i]*MmodB*cosm[i,nxs,:,:,nxs]),0.) for i in range(mRef)])          #Nref,Ntau,Nops,Natm,Mxyz
1614
1615            if not SGData['SGGray']:           
1616                fams += fam0[:,nxs,:,:,:]
1617                fbms += fbm0[:,nxs,:,:,:]
1618                               
1619#sum ops & atms                               
1620            fasm = np.sum(np.sum(fams,axis=-2),axis=-2)    #Nref,Mxyz; sum ops & atoms
1621            fbsm = np.sum(np.sum(fbms,axis=-2),axis=-2)
1622#put into cartesian space
1623            facm = np.inner(fasm,uBmat.T)
1624            fbcm = np.inner(fbsm,uBmat.T)
1625#form e.F dot product
1626            eDotFa = np.sum(eM[:,nxs,:]*facm,axis=-1)    #Nref,Ntau       
1627            eDotFb = np.sum(eM[:,nxs,:]*fbcm,axis=-1)
1628#intensity Halpern & Johnson
1629            fass = np.sum((facm-eM[:,nxs,:]*eDotFa[:,:,nxs])**2,axis=-1)
1630            fbss = np.sum((fbcm-eM[:,nxs,:]*eDotFb[:,:,nxs])**2,axis=-1)
1631## #do integration           
1632            fas = np.sum(fass*glWt[nxs,:],axis=1)
1633            fbs = np.sum(fbss*glWt[nxs,:],axis=1)
1634           
1635            refl.T[10] = fas+fbs   #Sum(fams**2,Mxyz) Re + Im
1636            refl.T[11] = atan2d(fbs,fas)
1637
1638        else:
1639            GfpuA = G2mth.Modulation(Uniq,UniqP,nWaves,Fmod,Xmod,Umod,glTau,glWt) #2 x refBlk x sym X atoms
1640            if 'T' in calcControls[hfx+'histType']:
1641                fa = np.array([np.reshape(((FF+FP).T-Bab).T,cosp.shape)*cosp*Tcorr,-np.reshape(Flack*FPP,sinp.shape)*sinp*Tcorr])
1642                fb = np.array([np.reshape(Flack*FPP,cosp.shape)*cosp*Tcorr,np.reshape(((FF+FP).T-Bab).T,sinp.shape)*sinp*Tcorr])
1643            else:
1644                fa = np.array([np.reshape(((FF+FP).T-Bab).T,cosp.shape)*cosp*Tcorr,-Flack*FPP*sinp*Tcorr])
1645                fb = np.array([Flack*FPP*cosp*Tcorr,np.reshape(((FF+FP).T-Bab).T,sinp.shape)*sinp*Tcorr])
1646            fag = fa*GfpuA[0]-fb*GfpuA[1]   #real; 2 x refBlk x sym x atoms
1647            fbg = fb*GfpuA[0]+fa*GfpuA[1]
1648            fas = np.sum(np.sum(fag,axis=-1),axis=-1)   #2 x refBlk; sum sym & atoms
1649            fbs = np.sum(np.sum(fbg,axis=-1),axis=-1)
1650           
1651            refl.T[10] = np.sum(fas,axis=0)**2+np.sum(fbs,axis=0)**2    #square of sums
1652            refl.T[11] = atan2d(fbs[0],fas[0])  #use only tau=0; ignore f' & f"
1653        if 'P' not in calcControls[hfx+'histType']:
1654            refl.T[8] = np.copy(refl.T[10])               
1655        iBeg += blkSize
1656    return copy.deepcopy(refDict['RefList'])
1657
1658def SStructureFactorTw(refDict,G,hfx,pfx,SGData,SSGData,calcControls,parmDict):
1659    '''
1660    Compute super structure factors for all h,k,l,m for phase - twins only
1661    puts the result, F^2, in each ref[8+im] in refList
1662    works on blocks of 32 reflections for speed
1663    input:
1664   
1665    :param dict refDict: where
1666        'RefList' list where each ref = h,k,l,m,it,d,...
1667        'FF' dict of form factors - filed in below
1668    :param np.array G:      reciprocal metric tensor
1669    :param str pfx:    phase id string
1670    :param dict SGData: space group info. dictionary output from SpcGroup
1671    :param dict calcControls:
1672    :param dict ParmDict:
1673
1674    '''
1675    phfx = pfx.split(':')[0]+hfx
1676    ast = np.sqrt(np.diag(G))
1677    Mast = twopisq*np.multiply.outer(ast,ast)   
1678    SGInv = SGData['SGInv']
1679    SGMT = np.array([ops[0].T for ops in SGData['SGOps']])
1680    SSGMT = np.array([ops[0].T for ops in SSGData['SSGOps']])
1681    SSGT = np.array([ops[1] for ops in SSGData['SSGOps']])
1682    FFtables = calcControls['FFtables']
1683    BLtables = calcControls['BLtables']
1684    MFtables = calcControls['MFtables']
1685    Flack = 1.0
1686    if not SGData['SGInv'] and 'S' in calcControls[hfx+'histType'] and phfx+'Flack' in parmDict:
1687        Flack = 1.-2.*parmDict[phfx+'Flack']
1688    TwinLaw = np.array([[[1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1]],])    #4D?
1689    TwDict = refDict.get('TwDict',{})           
1690    if 'S' in calcControls[hfx+'histType']:
1691        NTL = calcControls[phfx+'NTL']
1692        NM = calcControls[phfx+'TwinNMN']+1
1693        TwinLaw = calcControls[phfx+'TwinLaw']  #this'll have to be 4D also...
1694        TwinFr = np.array([parmDict[phfx+'TwinFr:'+str(i)] for i in range(len(TwinLaw))])
1695        TwinInv = list(np.where(calcControls[phfx+'TwinInv'],-1,1))
1696    Tdata,Mdata,Fdata,Xdata,dXdata,IAdata,Uisodata,Uijdata,Gdata = \
1697        GetAtomFXU(pfx,calcControls,parmDict)
1698    if not Xdata.size:          #no atoms in phase!
1699        return
1700    waveTypes,FSSdata,XSSdata,USSdata,MSSdata = GetAtomSSFXU(pfx,calcControls,parmDict)
1701    ngl,nWaves,Fmod,Xmod,Umod,Mmod,glTau,glWt = G2mth.makeWaves(waveTypes,FSSdata,XSSdata,USSdata,Mast)
1702    modQ = np.array([parmDict[pfx+'mV0'],parmDict[pfx+'mV1'],parmDict[pfx+'mV2']])
1703    FF = np.zeros(len(Tdata))
1704    if 'NC' in calcControls[hfx+'histType'] or 'NB' in calcControls[hfx+'histType']:
1705        FP,FPP = G2el.BlenResCW(Tdata,BLtables,parmDict[hfx+'Lam'])
1706    elif 'X' in calcControls[hfx+'histType']:
1707        FP = np.array([FFtables[El][hfx+'FP'] for El in Tdata])
1708        FPP = np.array([FFtables[El][hfx+'FPP'] for El in Tdata])
1709    Uij = np.array(G2lat.U6toUij(Uijdata)).T
1710    bij = Mast*Uij
1711    blkSize = 32       #no. of reflections in a block
1712    nRef = refDict['RefList'].shape[0]
1713    if not len(refDict['FF']):                #no form factors - 1st time thru StructureFactor
1714        SQ = 1./(2.*refDict['RefList'].T[5])**2
1715        if 'N' in calcControls[hfx+'histType']:
1716            dat = G2el.getBLvalues(BLtables)
1717            refDict['FF']['El'] = list(dat.keys())
1718            refDict['FF']['FF'] = np.ones((nRef,len(dat)))*list(dat.values())
1719            refDict['FF']['MF'] = np.zeros((nRef,len(dat)))
1720            for iel,El in enumerate(refDict['FF']['El']):
1721                if El in MFtables:
1722                    refDict['FF']['MF'].T[iel] = G2el.MagScatFac(MFtables[El],SQ)
1723        else:
1724            dat = G2el.getFFvalues(FFtables,0.)
1725            refDict['FF']['El'] = list(dat.keys())
1726            refDict['FF']['FF'] = np.zeros((nRef,len(dat)))
1727            for iel,El in enumerate(refDict['FF']['El']):
1728                refDict['FF']['FF'].T[iel] = G2el.ScatFac(FFtables[El],SQ)
1729#    time0 = time.time()
1730#reflection processing begins here - big arrays!
1731    iBeg = 0
1732    while iBeg < nRef:
1733        iFin = min(iBeg+blkSize,nRef)
1734        refl = refDict['RefList'][iBeg:iFin]    #array(blkSize,nItems)
1735        H = refl[:,:4]                          #array(blkSize,4)
1736        H3 = refl[:,:3]
1737        HP = H[:,:3]+modQ[nxs,:]*H[:,3:]        #projected hklm to hkl
1738        HP = np.inner(HP,TwinLaw)             #array(blkSize,nTwins,4)
1739        H3 = np.inner(H3,TwinLaw)       
1740        TwMask = np.any(HP,axis=-1)
1741        if TwinLaw.shape[0] > 1 and TwDict: #need np.inner(TwinLaw[?],TwDict[iref][i])*TwinInv[i]
1742            for ir in range(blkSize):
1743                iref = ir+iBeg
1744                if iref in TwDict:
1745                    for i in TwDict[iref]:
1746                        for n in range(NTL):
1747                            HP[ir][i+n*NM] = np.inner(TwinLaw[n*NM],np.array(TwDict[iref][i])*TwinInv[i+n*NM])
1748                            H3[ir][i+n*NM] = np.inner(TwinLaw[n*NM],np.array(TwDict[iref][i])*TwinInv[i+n*NM])
1749            TwMask = np.any(HP,axis=-1)
1750        SQ = 1./(2.*refl.T[5])**2               #array(blkSize)
1751        SQfactor = 4.0*SQ*twopisq               #ditto prev.
1752        Uniq = np.inner(H,SSGMT)
1753        Uniq3 = np.inner(H3,SGMT)
1754        UniqP = np.inner(HP,SGMT)
1755        Phi = np.inner(H,SSGT)
1756        if SGInv:   #if centro - expand HKL sets
1757            Uniq = np.hstack((Uniq,-Uniq))
1758            Uniq3 = np.hstack((Uniq3,-Uniq3))
1759            Phi = np.hstack((Phi,-Phi))
1760            UniqP = np.hstack((UniqP,-UniqP))
1761        if 'T' in calcControls[hfx+'histType']:
1762            if 'P' in calcControls[hfx+'histType']:
1763                FP,FPP = G2el.BlenResTOF(Tdata,BLtables,refl.T[14])
1764            else:
1765                FP,FPP = G2el.BlenResTOF(Tdata,BLtables,refl.T[12])
1766            FP = np.repeat(FP.T,Uniq.shape[1]*len(TwinLaw),axis=0)
1767            FPP = np.repeat(FPP.T,Uniq.shape[1]*len(TwinLaw),axis=0)
1768        Bab = np.repeat(parmDict[phfx+'BabA']*np.exp(-parmDict[phfx+'BabU']*SQfactor),Uniq.shape[1]*len(TwinLaw))
1769        Tindx = np.array([refDict['FF']['El'].index(El) for El in Tdata])
1770        FF = np.repeat(refDict['FF']['FF'][iBeg:iFin].T[Tindx].T,Uniq.shape[1]*len(TwinLaw),axis=0)
1771        phase = twopi*(np.inner(Uniq3,(dXdata.T+Xdata.T))-Phi[:,nxs,:,nxs])
1772        sinp = np.sin(phase)
1773        cosp = np.cos(phase)
1774        biso = -SQfactor*Uisodata[:,nxs]
1775        Tiso = np.repeat(np.where(biso<1.,np.exp(biso),1.0),Uniq.shape[1]*len(TwinLaw),axis=1).T
1776        HbH = -np.sum(UniqP[:,:,:,nxs]*np.inner(UniqP[:,:,:],bij),axis=-1)  #use hklt proj to hkl
1777        Tuij = np.where(HbH<1.,np.exp(HbH),1.0)
1778        Tcorr = np.reshape(Tiso,Tuij.shape)*Tuij*Mdata*Fdata/Uniq.shape[1]  #refBlk x ops x atoms
1779        if 'T' in calcControls[hfx+'histType']:
1780            fa = np.array([np.reshape(((FF+FP).T-Bab).T,cosp.shape)*cosp*Tcorr,-np.reshape(Flack*FPP,sinp.shape)*sinp*Tcorr])
1781            fb = np.array([np.reshape(Flack*FPP,cosp.shape)*cosp*Tcorr,np.reshape(((FF+FP).T-Bab).T,sinp.shape)*sinp*Tcorr])
1782        else:
1783            fa = np.array([np.reshape(((FF+FP).T-Bab).T,cosp.shape)*cosp*Tcorr,-Flack*FPP*sinp*Tcorr])
1784            fb = np.array([Flack*FPP*cosp*Tcorr,np.reshape(((FF+FP).T-Bab).T,sinp.shape)*sinp*Tcorr])
1785        GfpuA = G2mth.ModulationTw(Uniq,UniqP,nWaves,Fmod,Xmod,Umod,glTau,glWt) #2 x refBlk x sym X atoms
1786        fag = fa*GfpuA[0]-fb*GfpuA[1]   #real; 2 x refBlk x sym x atoms
1787        fbg = fb*GfpuA[0]+fa*GfpuA[1]
1788        fas = np.sum(np.sum(fag,axis=-1),axis=-1)   #2 x refBlk; sum sym & atoms
1789        fbs = np.sum(np.sum(fbg,axis=-1),axis=-1)
1790        refl.T[10] = np.sum(fas[:,:,0],axis=0)**2+np.sum(fbs[:,:,0],axis=0)**2                  #FcT from primary twin element
1791        refl.T[8] = np.sum(TwinFr*np.sum(TwMask[nxs,:,:]*fas,axis=0)**2,axis=-1)+   \
1792            np.sum(TwinFr*np.sum(TwMask[nxs,:,:]*fbs,axis=0)**2,axis=-1)                 #Fc sum over twins
1793        refl.T[11] = atan2d(fbs[0].T[0],fas[0].T[0])  #ignore f' & f"
1794        iBeg += blkSize
1795#    print ('nRef %d time %.4f\r'%(nRef,time.time()-time0))
1796
1797def SStructureFactorDerv(refDict,im,G,hfx,pfx,SGData,SSGData,calcControls,parmDict):
1798    '''
1799    Compute super structure factor derivatives for all h,k,l,m for phase - no twins
1800    Only Fourier component are done analytically here
1801    input:
1802   
1803    :param dict refDict: where
1804        'RefList' list where each ref = h,k,l,m,it,d,...
1805        'FF' dict of form factors - filled in below
1806    :param int im: = 1 (could be eliminated)
1807    :param np.array G:      reciprocal metric tensor
1808    :param str hfx:    histogram id string
1809    :param str pfx:    phase id string
1810    :param dict SGData: space group info. dictionary output from SpcGroup
1811    :param dict SSGData: super space group info.
1812    :param dict calcControls:
1813    :param dict ParmDict:
1814   
1815    :returns: dict dFdvDict: dictionary of derivatives
1816    '''
1817    phfx = pfx.split(':')[0]+hfx
1818    ast = np.sqrt(np.diag(G))
1819    Mast = twopisq*np.multiply.outer(ast,ast)
1820    SGInv = SGData['SGInv']
1821    SGMT = np.array([ops[0].T for ops in SGData['SGOps']])
1822    SSGMT = np.array([ops[0].T for ops in SSGData['SSGOps']])
1823    SSGT = np.array([ops[1] for ops in SSGData['SSGOps']])
1824    FFtables = calcControls['FFtables']
1825    BLtables = calcControls['BLtables']
1826    nRef = len(refDict['RefList'])
1827    Tdata,Mdata,Fdata,Xdata,dXdata,IAdata,Uisodata,Uijdata,Gdata = \
1828        GetAtomFXU(pfx,calcControls,parmDict)
1829    if not Xdata.size:          #no atoms in phase!
1830        return {}
1831    mSize = len(Mdata)  #no. atoms
1832    waveTypes,FSSdata,XSSdata,USSdata,MSSdata = GetAtomSSFXU(pfx,calcControls,parmDict)
1833    ngl,nWaves,Fmod,Xmod,Umod,Mmod,glTau,glWt = G2mth.makeWaves(waveTypes,FSSdata,XSSdata,USSdata,MSSdata,Mast)
1834    waveShapes,SCtauF,SCtauX,SCtauU,UmodAB = G2mth.makeWavesDerv(ngl,waveTypes,FSSdata,XSSdata,USSdata,Mast)
1835    modQ = np.array([parmDict[pfx+'mV0'],parmDict[pfx+'mV1'],parmDict[pfx+'mV2']])
1836    FF = np.zeros(len(Tdata))
1837    if 'NC' in calcControls[hfx+'histType'] or 'NB' in calcControls[hfx+'histType']:
1838        FP,FPP = G2el.BlenResCW(Tdata,BLtables,parmDict[hfx+'Lam'])
1839    elif 'X' in calcControls[hfx+'histType']:
1840        FP = np.array([FFtables[El][hfx+'FP'] for El in Tdata])
1841        FPP = np.array([FFtables[El][hfx+'FPP'] for El in Tdata])
1842    Uij = np.array(G2lat.U6toUij(Uijdata)).T
1843    bij = Mast*Uij
1844    if not len(refDict['FF']):
1845        if 'N' in calcControls[hfx+'histType']:
1846            dat = G2el.getBLvalues(BLtables)        #will need wave here for anom. neutron b's
1847        else:
1848            dat = G2el.getFFvalues(FFtables,0.)       
1849        refDict['FF']['El'] = list(dat.keys())
1850        refDict['FF']['FF'] = np.zeros((len(refDict['RefList']),len(dat)))
1851    dFdvDict = {}
1852    dFdfr = np.zeros((nRef,mSize))
1853    dFdx = np.zeros((nRef,mSize,3))
1854    dFdui = np.zeros((nRef,mSize))
1855    dFdua = np.zeros((nRef,mSize,6))
1856    dFdbab = np.zeros((nRef,2))
1857    dFdfl = np.zeros((nRef))
1858    dFdGf = np.zeros((nRef,mSize,FSSdata.shape[1],2))
1859    dFdGx = np.zeros((nRef,mSize,XSSdata.shape[1],6))
1860    dFdGu = np.zeros((nRef,mSize,USSdata.shape[1],12))
1861    Flack = 1.0
1862    if not SGData['SGInv'] and 'S' in calcControls[hfx+'histType'] and phfx+'Flack' in parmDict:
1863        Flack = 1.-2.*parmDict[phfx+'Flack']
1864    time0 = time.time()
1865    nRef = len(refDict['RefList'])/100
1866    for iref,refl in enumerate(refDict['RefList']):
1867        if 'T' in calcControls[hfx+'histType']:
1868            FP,FPP = G2el.BlenResCW(Tdata,BLtables,refl.T[12+im])
1869        H = np.array(refl[:4])
1870        HP = H[:3]+modQ*H[3:]            #projected hklm to hkl
1871        SQ = 1./(2.*refl[4+im])**2             # or (sin(theta)/lambda)**2
1872        SQfactor = 8.0*SQ*np.pi**2
1873        Bab = 0.0
1874        if phfx+'BabA' in parmDict:
1875            dBabdA = np.exp(-parmDict[phfx+'BabU']*SQfactor)
1876            Bab = parmDict[phfx+'BabA']*dBabdA
1877        Tindx = np.array([refDict['FF']['El'].index(El) for El in Tdata])
1878        FF = refDict['FF']['FF'][iref].T[Tindx]
1879        Uniq = np.inner(H,SSGMT)
1880        Phi = np.inner(H,SSGT)
1881        UniqP = np.inner(HP,SGMT)
1882        if SGInv:   #if centro - expand HKL sets
1883            Uniq = np.vstack((Uniq,-Uniq))
1884            Phi = np.hstack((Phi,-Phi))
1885            UniqP = np.vstack((UniqP,-UniqP))
1886        phase = twopi*(np.inner(Uniq[:,:3],(dXdata+Xdata).T)+Phi[:,nxs])
1887        sinp = np.sin(phase)
1888        cosp = np.cos(phase)
1889        occ = Mdata*Fdata/Uniq.shape[0]
1890        biso = -SQfactor*Uisodata[:,nxs]
1891        Tiso = np.repeat(np.where(biso<1.,np.exp(biso),1.0),Uniq.shape[0],axis=1).T    #ops x atoms
1892        HbH = -np.sum(UniqP[:,nxs,:3]*np.inner(UniqP[:,:3],bij),axis=-1)  #ops x atoms
1893        Hij = np.array([Mast*np.multiply.outer(U[:3],U[:3]) for U in UniqP]) #atoms x 3x3
1894        Hij = np.array([G2lat.UijtoU6(uij) for uij in Hij])                     #atoms x 6
1895        Tuij = np.where(HbH<1.,np.exp(HbH),1.0)     #ops x atoms
1896        Tcorr = np.reshape(Tiso,Tuij.shape)*Tuij*Mdata*Fdata/Uniq.shape[0]  #ops x atoms
1897        fot = (FF+FP-Bab)*Tcorr     #ops x atoms
1898        fotp = FPP*Tcorr            #ops x atoms
1899        GfpuA = G2mth.Modulation(Uniq,UniqP,nWaves,Fmod,Xmod,Umod,glTau,glWt) #2 x sym X atoms
1900        dGdf,dGdx,dGdu = G2mth.ModulationDerv(Uniq,UniqP,Hij,nWaves,waveShapes,Fmod,Xmod,UmodAB,SCtauF,SCtauX,SCtauU,glTau,glWt)
1901        # GfpuA is 2 x ops x atoms
1902        # derivs are: ops x atoms x waves x 2,6,12, or 5 parms as [real,imag] parts
1903        fa = np.array([((FF+FP).T-Bab).T*cosp*Tcorr,-Flack*FPP*sinp*Tcorr]) # array(2,nEqv,nAtoms)
1904        fb = np.array([((FF+FP).T-Bab).T*sinp*Tcorr,Flack*FPP*cosp*Tcorr])  #or array(2,nEqv,nAtoms)
1905        fag = fa*GfpuA[0]-fb*GfpuA[1]
1906        fbg = fb*GfpuA[0]+fa*GfpuA[1]
1907       
1908        fas = np.sum(np.sum(fag,axis=1),axis=1)     # 2 x twin
1909        fbs = np.sum(np.sum(fbg,axis=1),axis=1)
1910        fax = np.array([-fot*sinp,-fotp*cosp])   #positions; 2 x ops x atoms
1911        fbx = np.array([fot*cosp,-fotp*sinp])
1912        fax = fax*GfpuA[0]-fbx*GfpuA[1]
1913        fbx = fbx*GfpuA[0]+fax*GfpuA[1]
1914        #sum below is over Uniq
1915        dfadfr = np.sum(fag/occ,axis=1)        #Fdata != 0 ever avoids /0. problem
1916        dfbdfr = np.sum(fbg/occ,axis=1)        #Fdata != 0 avoids /0. problem
1917        dfadba = np.sum(-cosp*Tcorr[:,nxs],axis=1)
1918        dfbdba = np.sum(-sinp*Tcorr[:,nxs],axis=1)
1919        dfadui = np.sum(-SQfactor*fag,axis=1)
1920        dfbdui = np.sum(-SQfactor*fbg,axis=1)
1921        dfadx = np.sum(twopi*Uniq[:,:3]*np.swapaxes(fax,-2,-1)[:,:,:,nxs],axis=-2)  #2 x nAtom x 3xyz; sum nOps
1922        dfbdx = np.sum(twopi*Uniq[:,:3]*np.swapaxes(fbx,-2,-1)[:,:,:,nxs],axis=-2)           
1923        dfadua = np.sum(-Hij*np.swapaxes(fag,-2,-1)[:,:,:,nxs],axis=-2)             #2 x nAtom x 6Uij; sum nOps
1924        dfbdua = np.sum(-Hij*np.swapaxes(fbg,-2,-1)[:,:,:,nxs],axis=-2)         #these are correct also for twins above
1925        # array(2,nAtom,nWave,2) & array(2,nAtom,nWave,6) & array(2,nAtom,nWave,12); sum on nOps
1926        dfadGf = np.sum(fa[:,:,:,nxs,nxs]*dGdf[0][nxs,:,:,:,:]-fb[:,:,:,nxs,nxs]*dGdf[1][nxs,:,:,:,:],axis=1)
1927        dfbdGf = np.sum(fb[:,:,:,nxs,nxs]*dGdf[0][nxs,:,:,:,:]+fa[:,:,:,nxs,nxs]*dGdf[1][nxs,:,:,:,:],axis=1)
1928        dfadGx = np.sum(fa[:,:,:,nxs,nxs]*dGdx[0][nxs,:,:,:,:]-fb[:,:,:,nxs,nxs]*dGdx[1][nxs,:,:,:,:],axis=1)
1929        dfbdGx = np.sum(fb[:,:,:,nxs,nxs]*dGdx[0][nxs,:,:,:,:]+fa[:,:,:,nxs,nxs]*dGdx[1][nxs,:,:,:,:],axis=1)
1930        dfadGu = np.sum(fa[:,:,:,nxs,nxs]*dGdu[0][nxs,:,:,:,:]-fb[:,:,:,nxs,nxs]*dGdu[1][nxs,:,:,:,:],axis=1)
1931        dfbdGu = np.sum(fb[:,:,:,nxs,nxs]*dGdu[0][nxs,:,:,:,:]+fa[:,:,:,nxs,nxs]*dGdu[1][nxs,:,:,:,:],axis=1)   
1932        if not SGData['SGInv']:   #Flack derivative
1933            dfadfl = np.sum(-FPP*Tcorr*sinp)
1934            dfbdfl = np.sum(FPP*Tcorr*cosp)
1935        else:
1936            dfadfl = 1.0
1937            dfbdfl = 1.0
1938        SA = fas[0]+fas[1]      #float = A+A'
1939        SB = fbs[0]+fbs[1]      #float = B+B'
1940        if 'P' in calcControls[hfx+'histType']: #checked perfect for centro & noncentro?
1941            dFdfl[iref] = -SA*dfadfl-SB*dfbdfl                  #array(nRef,)
1942            dFdfr[iref] = 2.*(fas[0]*dfadfr[0]+fas[1]*dfadfr[1])*Mdata/len(Uniq)+   \
1943                2.*(fbs[0]*dfbdfr[0]-fbs[1]*dfbdfr[1])*Mdata/len(Uniq)
1944            dFdx[iref] = 2.*(fas[0]*dfadx[0]+fas[1]*dfadx[1])+  \
1945                2.*(fbs[0]*dfbdx[0]+fbs[1]*dfbdx[1])
1946            dFdui[iref] = 2.*(fas[0]*dfadui[0]+fas[1]*dfadui[1])+   \
1947                2.*(fbs[0]*dfbdui[0]-fbs[1]*dfbdui[1])
1948            dFdua[iref] = 2.*(fas[0]*dfadua[0]+fas[1]*dfadua[1])+   \
1949                2.*(fbs[0]*dfbdua[0]+fbs[1]*dfbdua[1])
1950            dFdGf[iref] = 2.*(fas[0]*dfadGf[0]+fas[1]*dfadGf[1])+  \
1951                2.*(fbs[0]*dfbdGf[0]+fbs[1]*dfbdGf[1])
1952            dFdGx[iref] = 2.*(fas[0]*dfadGx[0]+fas[1]*dfadGx[1])+  \
1953                2.*(fbs[0]*dfbdGx[0]-fbs[1]*dfbdGx[1])
1954            dFdGu[iref] = 2.*(fas[0]*dfadGu[0]+fas[1]*dfadGu[1])+  \
1955                2.*(fbs[0]*dfbdGu[0]+fbs[1]*dfbdGu[1])
1956        else:                       #OK, I think
1957            dFdfr[iref] = 2.*(SA*dfadfr[0]+SA*dfadfr[1]+SB*dfbdfr[0]+SB*dfbdfr[1])*Mdata/len(Uniq) #array(nRef,nAtom)
1958            dFdx[iref] = 2.*(SA*dfadx[0]+SA*dfadx[1]+SB*dfbdx[0]+SB*dfbdx[1])    #array(nRef,nAtom,3)
1959            dFdui[iref] = 2.*(SA*dfadui[0]+SA*dfadui[1]+SB*dfbdui[0]+SB*dfbdui[1])   #array(nRef,nAtom)
1960            dFdua[iref] = 2.*(SA*dfadua[0]+SA*dfadua[1]+SB*dfbdua[0]+SB*dfbdua[1])    #array(nRef,nAtom,6)
1961            dFdfl[iref] = -SA*dfadfl-SB*dfbdfl                  #array(nRef,)
1962                           
1963            dFdGf[iref] = 2.*(SA*dfadGf[0]+SB*dfbdGf[1])      #array(nRef,natom,nwave,2)
1964            dFdGx[iref] = 2.*(SA*dfadGx[0]+SB*dfbdGx[1])      #array(nRef,natom,nwave,6)
1965            dFdGu[iref] = 2.*(SA*dfadGu[0]+SB*dfbdGu[1])      #array(nRef,natom,nwave,12)
1966        if phfx+'BabA' in parmDict:
1967            dFdbab[iref] = 2.*fas[0]*np.array([np.sum(dfadba*dBabdA),np.sum(-dfadba*parmDict[phfx+'BabA']*SQfactor*dBabdA)]).T+ \
1968                2.*fbs[0]*np.array([np.sum(dfbdba*dBabdA),np.sum(-dfbdba*parmDict[phfx+'BabA']*SQfactor*dBabdA)]).T
1969        #loop over atoms - each dict entry is list of derivatives for all the reflections
1970        if not iref%100 :
1971            print (' %d derivative time %.4f\r'%(iref,time.time()-time0),end='')
1972    for i in range(len(Mdata)):     #loop over atoms
1973        dFdvDict[pfx+'Afrac:'+str(i)] = dFdfr.T[i]
1974        dFdvDict[pfx+'dAx:'+str(i)] = dFdx.T[0][i]
1975        dFdvDict[pfx+'dAy:'+str(i)] = dFdx.T[1][i]
1976        dFdvDict[pfx+'dAz:'+str(i)] = dFdx.T[2][i]
1977        dFdvDict[pfx+'AUiso:'+str(i)] = dFdui.T[i]
1978        dFdvDict[pfx+'AU11:'+str(i)] = dFdua.T[0][i]
1979        dFdvDict[pfx+'AU22:'+str(i)] = dFdua.T[1][i]
1980        dFdvDict[pfx+'AU33:'+str(i)] = dFdua.T[2][i]
1981        dFdvDict[pfx+'AU12:'+str(i)] = 2.*dFdua.T[3][i]
1982        dFdvDict[pfx+'AU13:'+str(i)] = 2.*dFdua.T[4][i]
1983        dFdvDict[pfx+'AU23:'+str(i)] = 2.*dFdua.T[5][i]
1984        for j in range(FSSdata.shape[1]):        #loop over waves Fzero & Fwid?
1985            dFdvDict[pfx+'Fsin:'+str(i)+':'+str(j)] = dFdGf.T[0][j][i]
1986            dFdvDict[pfx+'Fcos:'+str(i)+':'+str(j)] = dFdGf.T[1][j][i]
1987        nx = 0
1988        if waveTypes[i] in ['Block','ZigZag']:
1989            nx = 1 
1990        for j in range(XSSdata.shape[1]-nx):       #loop over waves
1991            dFdvDict[pfx+'Xsin:'+str(i)+':'+str(j+nx)] = dFdGx.T[0][j][i]
1992            dFdvDict[pfx+'Ysin:'+str(i)+':'+str(j+nx)] = dFdGx.T[1][j][i]
1993            dFdvDict[pfx+'Zsin:'+str(i)+':'+str(j+nx)] = dFdGx.T[2][j][i]
1994            dFdvDict[pfx+'Xcos:'+str(i)+':'+str(j+nx)] = dFdGx.T[3][j][i]
1995            dFdvDict[pfx+'Ycos:'+str(i)+':'+str(j+nx)] = dFdGx.T[4][j][i]
1996            dFdvDict[pfx+'Zcos:'+str(i)+':'+str(j+nx)] = dFdGx.T[5][j][i]
1997        for j in range(USSdata.shape[1]):       #loop over waves
1998            dFdvDict[pfx+'U11sin:'+str(i)+':'+str(j)] = dFdGu.T[0][j][i]
1999            dFdvDict[pfx+'U22sin:'+str(i)+':'+str(j)] = dFdGu.T[1][j][i]
2000            dFdvDict[pfx+'U33sin:'+str(i)+':'+str(j)] = dFdGu.T[2][j][i]
2001            dFdvDict[pfx+'U12sin:'+str(i)+':'+str(j)] = 2.*dFdGu.T[3][j][i]
2002            dFdvDict[pfx+'U13sin:'+str(i)+':'+str(j)] = 2.*dFdGu.T[4][j][i]
2003            dFdvDict[pfx+'U23sin:'+str(i)+':'+str(j)] = 2.*dFdGu.T[5][j][i]
2004            dFdvDict[pfx+'U11cos:'+str(i)+':'+str(j)] = dFdGu.T[6][j][i]
2005            dFdvDict[pfx+'U22cos:'+str(i)+':'+str(j)] = dFdGu.T[7][j][i]
2006            dFdvDict[pfx+'U33cos:'+str(i)+':'+str(j)] = dFdGu.T[8][j][i]
2007            dFdvDict[pfx+'U12cos:'+str(i)+':'+str(j)] = 2.*dFdGu.T[9][j][i]
2008            dFdvDict[pfx+'U13cos:'+str(i)+':'+str(j)] = 2.*dFdGu.T[10][j][i]
2009            dFdvDict[pfx+'U23cos:'+str(i)+':'+str(j)] = 2.*dFdGu.T[11][j][i]
2010           
2011    dFdvDict[phfx+'Flack'] = 4.*dFdfl.T
2012    dFdvDict[phfx+'BabA'] = dFdbab.T[0]
2013    dFdvDict[phfx+'BabU'] = dFdbab.T[1]
2014    return dFdvDict
2015
2016def SStructureFactorDerv2(refDict,im,G,hfx,pfx,SGData,SSGData,calcControls,parmDict):
2017    '''
2018    Compute super structure factor derivatives for all h,k,l,m for phase - no twins
2019    input:
2020   
2021    :param dict refDict: where
2022        'RefList' list where each ref = h,k,l,m,it,d,...
2023        'FF' dict of form factors - filled in below
2024    :param int im: = 1 (could be eliminated)
2025    :param np.array G:      reciprocal metric tensor
2026    :param str hfx:    histogram id string
2027    :param str pfx:    phase id string
2028    :param dict SGData: space group info. dictionary output from SpcGroup
2029    :param dict SSGData: super space group info.
2030    :param dict calcControls:
2031    :param dict ParmDict:
2032   
2033    :returns: dict dFdvDict: dictionary of derivatives
2034    '''
2035
2036    trefDict = copy.deepcopy(refDict)
2037    dM = 1.e-4
2038    dFdvDict = {}
2039    for parm in parmDict:
2040        if ':' not in parm:
2041            continue
2042        if parm.split(':')[2] in ['Tmin','Tmax','Xmax','Ymax','Zmax','Fzero','Fwid',
2043            'MXsin','MXcos','MYsin','MYcos','MZsin','MZcos','AMx','AMy','AMz',]:
2044            parmDict[parm] += dM
2045            prefList = SStructureFactor(trefDict,G,hfx,pfx,SGData,SSGData,calcControls,parmDict)
2046            parmDict[parm] -= 2*dM
2047            mrefList = SStructureFactor(trefDict,G,hfx,pfx,SGData,SSGData,calcControls,parmDict)
2048            parmDict[parm] += dM
2049            dFdvDict[parm] = (prefList[:,9+im]-mrefList[:,9+im])/(2.*dM)
2050    return dFdvDict
2051   
2052def SStructureFactorDervTw(refDict,im,G,hfx,pfx,SGData,SSGData,calcControls,parmDict):
2053    'Needs a doc string'
2054    phfx = pfx.split(':')[0]+hfx
2055    ast = np.sqrt(np.diag(G))
2056    Mast = twopisq*np.multiply.outer(ast,ast)
2057    SGInv = SGData['SGInv']
2058    SGMT = np.array([ops[0].T for ops in SGData['SGOps']])
2059    SSGMT = np.array([ops[0].T for ops in SSGData['SSGOps']])
2060    SSGT = np.array([ops[1] for ops in SSGData['SSGOps']])
2061    FFtables = calcControls['FFtables']
2062    BLtables = calcControls['BLtables']
2063    TwinLaw = np.array([[[1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1]],])
2064    TwDict = refDict.get('TwDict',{})           
2065    if 'S' in calcControls[hfx+'histType']:
2066        NTL = calcControls[phfx+'NTL']
2067        NM = calcControls[phfx+'TwinNMN']+1
2068        TwinLaw = calcControls[phfx+'TwinLaw']
2069        TwinInv = list(np.where(calcControls[phfx+'TwinInv'],-1,1))
2070    nTwin = len(TwinLaw)       
2071    nRef = len(refDict['RefList'])
2072    Tdata,Mdata,Fdata,Xdata,dXdata,IAdata,Uisodata,Uijdata,Gdata = \
2073        GetAtomFXU(pfx,calcControls,parmDict)
2074    if not Xdata.size:          #no atoms in phase!
2075        return {}
2076    mSize = len(Mdata)  #no. atoms
2077    waveTypes,FSSdata,XSSdata,USSdata,MSSdata = GetAtomSSFXU(pfx,calcControls,parmDict)
2078    ngl,nWaves,Fmod,Xmod,Umod,Mmod,glTau,glWt = G2mth.makeWaves(waveTypes,FSSdata,XSSdata,USSdata,MSSdata,Mast)     #NB: Mmod is ReIm,Mxyz,Ntau,Natm
2079    waveShapes,SCtauF,SCtauX,SCtauU,UmodAB = G2mth.makeWavesDerv(ngl,waveTypes,FSSdata,XSSdata,USSdata,Mast)
2080    modQ = np.array([parmDict[pfx+'mV0'],parmDict[pfx+'mV1'],parmDict[pfx+'mV2']])
2081    FF = np.zeros(len(Tdata))
2082    if 'NC' in calcControls[hfx+'histType'] or 'NB' in calcControls[hfx+'histType']:
2083        FP,FPP = G2el.BlenResCW(Tdata,BLtables,parmDict[hfx+'Lam'])
2084    elif 'X' in calcControls[hfx+'histType']:
2085        FP = np.array([FFtables[El][hfx+'FP'] for El in Tdata])
2086        FPP = np.array([FFtables[El][hfx+'FPP'] for El in Tdata])
2087    Uij = np.array(G2lat.U6toUij(Uijdata)).T
2088    bij = Mast*Uij
2089    if not len(refDict['FF']):
2090        if 'N' in calcControls[hfx+'histType']:
2091            dat = G2el.getBLvalues(BLtables)        #will need wave here for anom. neutron b's
2092        else:
2093            dat = G2el.getFFvalues(FFtables,0.)       
2094        refDict['FF']['El'] = list(dat.keys())
2095        refDict['FF']['FF'] = np.zeros((len(refDict['RefList']),len(dat)))
2096    dFdvDict = {}
2097    dFdfr = np.zeros((nRef,nTwin,mSize))
2098    dFdx = np.zeros((nRef,nTwin,mSize,3))
2099    dFdui = np.zeros((nRef,nTwin,mSize))
2100    dFdua = np.zeros((nRef,nTwin,mSize,6))
2101    dFdbab = np.zeros((nRef,nTwin,2))
2102    dFdtw = np.zeros((nRef,nTwin))
2103    dFdGf = np.zeros((nRef,nTwin,mSize,FSSdata.shape[1]))
2104    dFdGx = np.zeros((nRef,nTwin,mSize,XSSdata.shape[1],3))
2105    dFdGz = np.zeros((nRef,nTwin,mSize,5))
2106    dFdGu = np.zeros((nRef,nTwin,mSize,USSdata.shape[1],6))
2107    Flack = 1.0
2108    if not SGData['SGInv'] and 'S' in calcControls[hfx+'histType'] and phfx+'Flack' in parmDict:
2109        Flack = 1.-2.*parmDict[phfx+'Flack']
2110    time0 = time.time()
2111    nRef = len(refDict['RefList'])/100
2112    for iref,refl in enumerate(refDict['RefList']):
2113        if 'T' in calcControls[hfx+'histType']:
2114            FP,FPP = G2el.BlenResCW(Tdata,BLtables,refl.T[12+im])
2115        H = np.array(refl[:4])
2116        HP = H[:3]+modQ*H[3:]            #projected hklm to hkl
2117        H = np.inner(H.T,TwinLaw)   #maybe array(4,nTwins) or (4)
2118        TwMask = np.any(H,axis=-1)
2119        if TwinLaw.shape[0] > 1 and TwDict:
2120            if iref in TwDict:
2121                for i in TwDict[iref]:
2122                    for n in range(NTL):
2123                        H[i+n*NM] = np.inner(TwinLaw[n*NM],np.array(TwDict[iref][i])*TwinInv[i+n*NM])
2124            TwMask = np.any(H,axis=-1)
2125        SQ = 1./(2.*refl[4+im])**2             # or (sin(theta)/lambda)**2
2126        SQfactor = 8.0*SQ*np.pi**2
2127        dBabdA = np.exp(-parmDict[phfx+'BabU']*SQfactor)
2128        Bab = parmDict[phfx+'BabA']*dBabdA
2129        Tindx = np.array([refDict['FF']['El'].index(El) for El in Tdata])
2130        FF = refDict['FF']['FF'][iref].T[Tindx]
2131        Uniq = np.inner(H,SSGMT)
2132        Phi = np.inner(H,SSGT)
2133        UniqP = np.inner(HP,SGMT)
2134        if SGInv:   #if centro - expand HKL sets
2135            Uniq = np.vstack((Uniq,-Uniq))
2136            Phi = np.hstack((Phi,-Phi))
2137            UniqP = np.vstack((UniqP,-UniqP))
2138        phase = twopi*(np.inner(Uniq[:,:3],(dXdata+Xdata).T)+Phi[:,nxs])
2139        sinp = np.sin(phase)
2140        cosp = np.cos(phase)
2141        occ = Mdata*Fdata/Uniq.shape[0]
2142        biso = -SQfactor*Uisodata[:,nxs]
2143        Tiso = np.repeat(np.where(biso<1.,np.exp(biso),1.0),Uniq.shape[0]*len(TwinLaw),axis=1).T    #ops x atoms
2144        HbH = -np.sum(UniqP[:,nxs,:3]*np.inner(UniqP[:,:3],bij),axis=-1)  #ops x atoms
2145        Hij = np.array([Mast*np.multiply.outer(U[:3],U[:3]) for U in UniqP]) #atoms x 3x3
2146        Hij = np.squeeze(np.reshape(np.array([G2lat.UijtoU6(uij) for uij in Hij]),(nTwin,-1,6)))
2147        Tuij = np.where(HbH<1.,np.exp(HbH),1.0)     #ops x atoms
2148        Tcorr = np.reshape(Tiso,Tuij.shape)*Tuij*Mdata*Fdata/Uniq.shape[0]  #ops x atoms
2149        fot = (FF+FP-Bab)*Tcorr     #ops x atoms
2150        fotp = FPP*Tcorr            #ops x atoms
2151        GfpuA = G2mth.Modulation(Uniq,UniqP,nWaves,Fmod,Xmod,Umod,glTau,glWt) #2 x sym X atoms
2152        dGdf,dGdx,dGdu,dGdz = G2mth.ModulationDerv(Uniq,UniqP,Hij,nWaves,waveShapes,Fmod,Xmod,UmodAB,SCtauF,SCtauX,SCtauU,glTau,glWt)
2153        # GfpuA is 2 x ops x atoms
2154        # derivs are: ops x atoms x waves x 2,6,12, or 5 parms as [real,imag] parts
2155        fa = np.array([((FF+FP).T-Bab).T*cosp*Tcorr,-Flack*FPP*sinp*Tcorr]) # array(2,nTwin,nEqv,nAtoms)
2156        fb = np.array([((FF+FP).T-Bab).T*sinp*Tcorr,Flack*FPP*cosp*Tcorr])  #or array(2,nEqv,nAtoms)
2157        fag = fa*GfpuA[0]-fb*GfpuA[1]
2158        fbg = fb*GfpuA[0]+fa*GfpuA[1]
2159       
2160        fas = np.sum(np.sum(fag,axis=1),axis=1)     # 2 x twin
2161        fbs = np.sum(np.sum(fbg,axis=1),axis=1)
2162        fax = np.array([-fot*sinp,-fotp*cosp])   #positions; 2 x twin x ops x atoms
2163        fbx = np.array([fot*cosp,-fotp*sinp])
2164        fax = fax*GfpuA[0]-fbx*GfpuA[1]
2165        fbx = fbx*GfpuA[0]+fax*GfpuA[1]
2166        #sum below is over Uniq
2167        dfadfr = np.sum(fag/occ,axis=1)        #Fdata != 0 ever avoids /0. problem
2168        dfbdfr = np.sum(fbg/occ,axis=1)        #Fdata != 0 avoids /0. problem
2169        dfadba = np.sum(-cosp*Tcorr[:,nxs],axis=1)
2170        dfbdba = np.sum(-sinp*Tcorr[:,nxs],axis=1)
2171        dfadui = np.sum(-SQfactor*fag,axis=1)
2172        dfbdui = np.sum(-SQfactor*fbg,axis=1)
2173        dfadx = np.array([np.sum(twopi*Uniq[it,:,:3]*np.swapaxes(fax,-2,-1)[:,it,:,:,nxs],axis=-2) for it in range(nTwin)])
2174        dfbdx = np.array([np.sum(twopi*Uniq[it,:,:3]*np.swapaxes(fbx,-2,-1)[:,it,:,:,nxs],axis=-2) for it in range(nTwin)])           
2175        dfadua = np.array([np.sum(-Hij[it]*np.swapaxes(fag,-2,-1)[:,it,:,:,nxs],axis=-2) for it in range(nTwin)])
2176        dfbdua = np.array([np.sum(-Hij[it]*np.swapaxes(fbg,-2,-1)[:,it,:,:,nxs],axis=-2) for it in range(nTwin)])
2177        # array(2,nTwin,nAtom,3) & array(2,nTwin,nAtom,6) & array(2,nTwin,nAtom,12)
2178        dfadGf = np.sum(fa[:,it,:,:,nxs,nxs]*dGdf[0][nxs,nxs,:,:,:,:]-fb[:,it,:,:,nxs,nxs]*dGdf[1][nxs,nxs,:,:,:,:],axis=1)
2179        dfbdGf = np.sum(fb[:,it,:,:,nxs,nxs]*dGdf[0][nxs,nxs,:,:,:,:]+fa[:,it,:,:,nxs,nxs]*dGdf[1][nxs,nxs,:,:,:,:],axis=1)
2180        dfadGx = np.sum(fa[:,it,:,:,nxs,nxs]*dGdx[0][nxs,nxs,:,:,:,:]-fb[:,it,:,:,nxs,nxs]*dGdx[1][nxs,nxs,:,:,:,:],axis=1)
2181        dfbdGx = np.sum(fb[:,it,:,:,nxs,nxs]*dGdx[0][nxs,nxs,:,:,:,:]+fa[:,it,:,:,nxs,nxs]*dGdx[1][nxs,nxs,:,:,:,:],axis=1)
2182        dfadGz = np.sum(fa[:,it,:,0,nxs,nxs]*dGdz[0][nxs,nxs,:,:,:]-fb[:,it,:,0,nxs,nxs]*dGdz[1][nxs,nxs,:,:,:],axis=1)
2183        dfbdGz = np.sum(fb[:,it,:,0,nxs,nxs]*dGdz[0][nxs,nxs,:,:,:]+fa[:,it,:,0,nxs,nxs]*dGdz[1][nxs,nxs,:,:,:],axis=1)
2184        dfadGu = np.sum(fa[:,it,:,:,nxs,nxs]*dGdu[0][nxs,nxs,:,:,:,:]-fb[:,it,:,:,nxs,nxs]*dGdu[1][nxs,nxs,:,:,:,:],axis=1)
2185        dfbdGu = np.sum(fb[:,it,:,:,nxs,nxs]*dGdu[0][nxs,nxs,:,:,:,:]+fa[:,it,:,:,nxs,nxs]*dGdu[1][nxs,nxs,:,:,:,:],axis=1)
2186#        GSASIIpath.IPyBreak()
2187        #NB: the above have been checked against PA(1:10,1:2) in strfctr.for for Al2O3!   
2188        SA = fas[0]+fas[1]      #float = A+A' (might be array[nTwin])
2189        SB = fbs[0]+fbs[1]      #float = B+B' (might be array[nTwin])
2190        dFdfr[iref] = [2.*TwMask[it]*(SA[it]*dfadfr[0][it]+SA[it]*dfadfr[1][it]+SB[it]*dfbdfr[0][it]+SB[it]*dfbdfr[1][it])*Mdata/len(Uniq[it]) for it in range(nTwin)]
2191        dFdx[iref] = [2.*TwMask[it]*(SA[it]*dfadx[it][0]+SA[it]*dfadx[it][1]+SB[it]*dfbdx[it][0]+SB[it]*dfbdx[it][1]) for it in range(nTwin)]
2192        dFdui[iref] = [2.*TwMask[it]*(SA[it]*dfadui[it][0]+SA[it]*dfadui[it][1]+SB[it]*dfbdui[it][0]+SB[it]*dfbdui[it][1]) for it in range(nTwin)]
2193        dFdua[iref] = [2.*TwMask[it]*(SA[it]*dfadua[it][0]+SA[it]*dfadua[it][1]+SB[it]*dfbdua[it][0]+SB[it]*dfbdua[it][1]) for it in range(nTwin)]
2194        dFdtw[iref] = np.sum(TwMask*fas,axis=0)**2+np.sum(TwMask*fbs,axis=0)**2
2195
2196        dFdGf[iref] = [2.*TwMask[it]*(SA[it]*dfadGf[1]+SB[it]*dfbdGf[1]) for it in range(nTwin)]
2197        dFdGx[iref] = [2.*TwMask[it]*(SA[it]*dfadGx[1]+SB[it]*dfbdGx[1]) for it in range(nTwin)]
2198        dFdGz[iref] = [2.*TwMask[it]*(SA[it]*dfadGz[1]+SB[it]*dfbdGz[1]) for it in range(nTwin)]
2199        dFdGu[iref] = [2.*TwMask[it]*(SA[it]*dfadGu[1]+SB[it]*dfbdGu[1]) for it in range(nTwin)]               
2200#            GSASIIpath.IPyBreak()
2201        dFdbab[iref] = 2.*fas[0]*np.array([np.sum(dfadba*dBabdA),np.sum(-dfadba*parmDict[phfx+'BabA']*SQfactor*dBabdA)]).T+ \
2202            2.*fbs[0]*np.array([np.sum(dfbdba*dBabdA),np.sum(-dfbdba*parmDict[phfx+'BabA']*SQfactor*dBabdA)]).T
2203        #loop over atoms - each dict entry is list of derivatives for all the reflections
2204        if not iref%100 :
2205            print (' %d derivative time %.4f\r'%(iref,time.time()-time0),end='')
2206    for i in range(len(Mdata)):     #loop over atoms
2207        dFdvDict[pfx+'Afrac:'+str(i)] = dFdfr.T[i]
2208        dFdvDict[pfx+'dAx:'+str(i)] = dFdx.T[0][i]
2209        dFdvDict[pfx+'dAy:'+str(i)] = dFdx.T[1][i]
2210        dFdvDict[pfx+'dAz:'+str(i)] = dFdx.T[2][i]
2211        dFdvDict[pfx+'AUiso:'+str(i)] = dFdui.T[i]
2212        dFdvDict[pfx+'AU11:'+str(i)] = dFdua.T[0][i]
2213        dFdvDict[pfx+'AU22:'+str(i)] = dFdua.T[1][i]
2214        dFdvDict[pfx+'AU33:'+str(i)] = dFdua.T[2][i]
2215        dFdvDict[pfx+'AU12:'+str(i)] = 2.*dFdua.T[3][i]
2216        dFdvDict[pfx+'AU13:'+str(i)] = 2.*dFdua.T[4][i]
2217        dFdvDict[pfx+'AU23:'+str(i)] = 2.*dFdua.T[5][i]
2218        for j in range(FSSdata.shape[1]):        #loop over waves Fzero & Fwid?
2219            dFdvDict[pfx+'Fsin:'+str(i)+':'+str(j)] = dFdGf.T[0][j][i]
2220            dFdvDict[pfx+'Fcos:'+str(i)+':'+str(j)] = dFdGf.T[1][j][i]
2221        nx = 0
2222        if waveTypes[i] in ['Block','ZigZag']:
2223            nx = 1 
2224            dFdvDict[pfx+'Tmin:'+str(i)+':0'] = dFdGz.T[0][i]   #ZigZag/Block waves (if any)
2225            dFdvDict[pfx+'Tmax:'+str(i)+':0'] = dFdGz.T[1][i]
2226            dFdvDict[pfx+'Xmax:'+str(i)+':0'] = dFdGz.T[2][i]
2227            dFdvDict[pfx+'Ymax:'+str(i)+':0'] = dFdGz.T[3][i]
2228            dFdvDict[pfx+'Zmax:'+str(i)+':0'] = dFdGz.T[4][i]
2229        for j in range(XSSdata.shape[1]-nx):       #loop over waves
2230            dFdvDict[pfx+'Xsin:'+str(i)+':'+str(j+nx)] = dFdGx.T[0][j][i]
2231            dFdvDict[pfx+'Ysin:'+str(i)+':'+str(j+nx)] = dFdGx.T[1][j][i]
2232            dFdvDict[pfx+'Zsin:'+str(i)+':'+str(j+nx)] = dFdGx.T[2][j][i]
2233            dFdvDict[pfx+'Xcos:'+str(i)+':'+str(j+nx)] = dFdGx.T[3][j][i]
2234            dFdvDict[pfx+'Ycos:'+str(i)+':'+str(j+nx)] = dFdGx.T[4][j][i]
2235            dFdvDict[pfx+'Zcos:'+str(i)+':'+str(j+nx)] = dFdGx.T[5][j][i]
2236        for j in range(USSdata.shape[1]):       #loop over waves
2237            dFdvDict[pfx+'U11sin:'+str(i)+':'+str(j)] = dFdGu.T[0][j][i]
2238            dFdvDict[pfx+'U22sin:'+str(i)+':'+str(j)] = dFdGu.T[1][j][i]
2239            dFdvDict[pfx+'U33sin:'+str(i)+':'+str(j)] = dFdGu.T[2][j][i]
2240            dFdvDict[pfx+'U12sin:'+str(i)+':'+str(j)] = 2.*dFdGu.T[3][j][i]
2241            dFdvDict[pfx+'U13sin:'+str(i)+':'+str(j)] = 2.*dFdGu.T[4][j][i]
2242            dFdvDict[pfx+'U23sin:'+str(i)+':'+str(j)] = 2.*dFdGu.T[5][j][i]
2243            dFdvDict[pfx+'U11cos:'+str(i)+':'+str(j)] = dFdGu.T[6][j][i]
2244            dFdvDict[pfx+'U22cos:'+str(i)+':'+str(j)] = dFdGu.T[7][j][i]
2245            dFdvDict[pfx+'U33cos:'+str(i)+':'+str(j)] = dFdGu.T[8][j][i]
2246            dFdvDict[pfx+'U12cos:'+str(i)+':'+str(j)] = 2.*dFdGu.T[9][j][i]
2247            dFdvDict[pfx+'U13cos:'+str(i)+':'+str(j)] = 2.*dFdGu.T[10][j][i]
2248            dFdvDict[pfx+'U23cos:'+str(i)+':'+str(j)] = 2.*dFdGu.T[11][j][i]
2249           
2250#        GSASIIpath.IPyBreak()
2251    dFdvDict[phfx+'BabA'] = dFdbab.T[0]
2252    dFdvDict[phfx+'BabU'] = dFdbab.T[1]
2253    return dFdvDict
2254   
2255def SCExtinction(ref,im,phfx,hfx,pfx,calcControls,parmDict,varyList):
2256    ''' Single crystal extinction function; returns extinction & derivative
2257    '''
2258    extCor = 1.0
2259    dervDict = {}
2260    dervCor = 1.0
2261    if calcControls[phfx+'EType'] != 'None':
2262        SQ = 1/(4.*ref[4+im]**2)
2263        if 'C' in parmDict[hfx+'Type']:           
2264            cos2T = 1.0-2.*SQ*parmDict[hfx+'Lam']**2           #cos(2theta)
2265        else:   #'T'
2266            cos2T = 1.0-2.*SQ*ref[12+im]**2                       #cos(2theta)           
2267        if 'SXC' in parmDict[hfx+'Type']:
2268            AV = 7.9406e5/parmDict[pfx+'Vol']**2
2269            PL = np.sqrt(1.0-cos2T**2)/parmDict[hfx+'Lam']
2270            P12 = (calcControls[phfx+'Cos2TM']+cos2T**4)/(calcControls[phfx+'Cos2TM']+cos2T**2)
2271            PLZ = AV*P12*ref[9+im]*parmDict[hfx+'Lam']**2
2272        elif 'SNT' in parmDict[hfx+'Type']:
2273            AV = 1.e7/parmDict[pfx+'Vol']**2
2274            PL = SQ
2275            PLZ = AV*ref[9+im]*ref[12+im]**2
2276        elif 'SNC' in parmDict[hfx+'Type']:
2277            AV = 1.e7/parmDict[pfx+'Vol']**2
2278            PL = np.sqrt(1.0-cos2T**2)/parmDict[hfx+'Lam']
2279            PLZ = AV*ref[9+im]*parmDict[hfx+'Lam']**2
2280           
2281        if 'Primary' in calcControls[phfx+'EType']:
2282            PLZ *= 1.5
2283        else:
2284            if 'C' in parmDict[hfx+'Type']:
2285                PLZ *= calcControls[phfx+'Tbar']
2286            else: #'T'
2287                PLZ *= ref[13+im]      #t-bar
2288        if 'Primary' in calcControls[phfx+'EType']:
2289            PLZ *= 1.5
2290            PSIG = parmDict[phfx+'Ep']
2291        elif 'I & II' in calcControls[phfx+'EType']:
2292            PSIG = parmDict[phfx+'Eg']/np.sqrt(1.+(parmDict[phfx+'Es']*PL/parmDict[phfx+'Eg'])**2)
2293        elif 'Type II' in calcControls[phfx+'EType']:
2294            PSIG = parmDict[phfx+'Es']
2295        else:       # 'Secondary Type I'
2296            PSIG = parmDict[phfx+'Eg']/PL
2297           
2298        AG = 0.58+0.48*cos2T+0.24*cos2T**2
2299        AL = 0.025+0.285*cos2T
2300        BG = 0.02-0.025*cos2T
2301        BL = 0.15-0.2*(0.75-cos2T)**2
2302        if cos2T < 0.:
2303            BL = -0.45*cos2T
2304        CG = 2.
2305        CL = 2.
2306        PF = PLZ*PSIG
2307       
2308        if 'Gaussian' in calcControls[phfx+'EApprox']:
2309            PF4 = 1.+CG*PF+AG*PF**2/(1.+BG*PF)
2310            extCor = np.sqrt(PF4)
2311            PF3 = 0.5*(CG+2.*AG*PF/(1.+BG*PF)-AG*PF**2*BG/(1.+BG*PF)**2)/(PF4*extCor)
2312        else:
2313            PF4 = 1.+CL*PF+AL*PF**2/(1.+BL*PF)
2314            extCor = np.sqrt(PF4)
2315            PF3 = 0.5*(CL+2.*AL*PF/(1.+BL*PF)-AL*PF**2*BL/(1.+BL*PF)**2)/(PF4*extCor)
2316
2317        dervCor = (1.+PF)*PF3   #extinction corr for other derivatives
2318        if 'Primary' in calcControls[phfx+'EType'] and phfx+'Ep' in varyList:
2319            dervDict[phfx+'Ep'] = -ref[7+im]*PLZ*PF3
2320        if 'II' in calcControls[phfx+'EType'] and phfx+'Es' in varyList:
2321            dervDict[phfx+'Es'] = -ref[7+im]*PLZ*PF3*(PSIG/parmDict[phfx+'Es'])**3
2322        if 'I' in calcControls[phfx+'EType'] and phfx+'Eg' in varyList:
2323            dervDict[phfx+'Eg'] = -ref[7+im]*PLZ*PF3*(PSIG/parmDict[phfx+'Eg'])**3*PL**2
2324               
2325    return 1./extCor,dervDict,dervCor
2326   
2327def Dict2Values(parmdict, varylist):
2328    '''Use before call to leastsq to setup list of values for the parameters
2329    in parmdict, as selected by key in varylist'''
2330    return [parmdict[key] for key in varylist] 
2331   
2332def Values2Dict(parmdict, varylist, values):
2333    ''' Use after call to leastsq to update the parameter dictionary with
2334    values corresponding to keys in varylist'''
2335    parmdict.update(zip(varylist,values))
2336   
2337def GetNewCellParms(parmDict,varyList):
2338    '''Compute unit cell tensor terms from varied Aij and Dij values.
2339    Terms are included in the dict only if Aij or Dij is varied.
2340    '''
2341    newCellDict = {}
2342    Anames = ['A'+str(i) for i in range(6)]
2343    Ddict = dict(zip(['D11','D22','D33','D12','D13','D23'],Anames))
2344    for item in varyList:
2345        keys = item.split(':')
2346        if keys[2] in Ddict:
2347            key = keys[0]+'::'+Ddict[keys[2]]       #key is e.g. '0::A0'
2348            parm = keys[0]+'::'+keys[2]             #parm is e.g. '0::D11'
2349            newCellDict[parm] = [key,parmDict[key]+parmDict[item]]
2350    return newCellDict          # is e.g. {'0::D11':A0-D11}
2351   
2352def ApplyXYZshifts(parmDict,varyList):
2353    '''
2354    takes atom x,y,z shift and applies it to corresponding atom x,y,z value
2355   
2356    :param dict parmDict: parameter dictionary
2357    :param list varyList: list of variables (not used!)
2358    :returns: newAtomDict - dictionary of new atomic coordinate names & values; key is parameter shift name
2359
2360    '''
2361    newAtomDict = {}
2362    for item in parmDict:
2363        if 'dA' in item:
2364            parm = ''.join(item.split('d'))
2365            parmDict[parm] += parmDict[item]
2366            newAtomDict[item] = [parm,parmDict[parm]]
2367    return newAtomDict
2368   
2369def SHTXcal(refl,im,g,pfx,hfx,SGData,calcControls,parmDict):
2370    'Spherical harmonics texture'
2371    IFCoup = 'Bragg' in calcControls[hfx+'instType']
2372    if 'T' in calcControls[hfx+'histType']:
2373        tth = parmDict[hfx+'2-theta']
2374    else:
2375        tth = refl[5+im]
2376    odfCor = 1.0
2377    H = refl[:3]
2378    cell = G2lat.Gmat2cell(g)
2379    Sangls = [parmDict[pfx+'SH omega'],parmDict[pfx+'SH chi'],parmDict[pfx+'SH phi']]
2380    Gangls = [parmDict[hfx+'Phi'],parmDict[hfx+'Chi'],parmDict[hfx+'Omega'],parmDict[hfx+'Azimuth']]
2381    phi,beta = G2lat.CrsAng(H,cell,SGData)
2382    psi,gam,x,x = G2lat.SamAng(tth/2.,Gangls,Sangls,IFCoup) #ignore 2 sets of angle derivs.
2383    SHnames = G2lat.GenSHCoeff(SGData['SGLaue'],parmDict[pfx+'SHmodel'],parmDict[pfx+'SHorder'])
2384    for item in SHnames:
2385        L,M,N = eval(item.strip('C'))
2386        Kcl = G2lat.GetKcl(L,N,SGData['SGLaue'],phi,beta)
2387        Ksl,x,x = G2lat.GetKsl(L,M,parmDict[pfx+'SHmodel'],psi,gam)
2388        Lnorm = G2lat.Lnorm(L)
2389        odfCor += parmDict[pfx+item]*Lnorm*Kcl*Ksl
2390    return odfCor
2391   
2392def SHTXcalDerv(refl,im,g,pfx,hfx,SGData,calcControls,parmDict):
2393    'Spherical harmonics texture derivatives'
2394    if 'T' in calcControls[hfx+'histType']:
2395        tth = parmDict[hfx+'2-theta']
2396    else:
2397        tth = refl[5+im]
2398    IFCoup = 'Bragg' in calcControls[hfx+'instType']
2399    odfCor = 1.0
2400    dFdODF = {}
2401    dFdSA = [0,0,0]
2402    H = refl[:3]
2403    cell = G2lat.Gmat2cell(g)
2404    Sangls = [parmDict[pfx+'SH omega'],parmDict[pfx+'SH chi'],parmDict[pfx+'SH phi']]
2405    Gangls = [parmDict[hfx+'Phi'],parmDict[hfx+'Chi'],parmDict[hfx+'Omega'],parmDict[hfx+'Azimuth']]
2406    phi,beta = G2lat.CrsAng(H,cell,SGData)
2407    psi,gam,dPSdA,dGMdA = G2lat.SamAng(tth/2.,Gangls,Sangls,IFCoup)
2408    SHnames = G2lat.GenSHCoeff(SGData['SGLaue'],parmDict[pfx+'SHmodel'],parmDict[pfx+'SHorder'])
2409    for item in SHnames:
2410        L,M,N = eval(item.strip('C'))
2411        Kcl = G2lat.GetKcl(L,N,SGData['SGLaue'],phi,beta)
2412        Ksl,dKsdp,dKsdg = G2lat.GetKsl(L,M,parmDict[pfx+'SHmodel'],psi,gam)
2413        Lnorm = G2lat.Lnorm(L)
2414        odfCor += parmDict[pfx+item]*Lnorm*Kcl*Ksl
2415        dFdODF[pfx+item] = Lnorm*Kcl*Ksl
2416        for i in range(3):
2417            dFdSA[i] += parmDict[pfx+item]*Lnorm*Kcl*(dKsdp*dPSdA[i]+dKsdg*dGMdA[i])
2418    return odfCor,dFdODF,dFdSA
2419   
2420def SHPOcal(refl,im,g,phfx,hfx,SGData,calcControls,parmDict):
2421    'spherical harmonics preferred orientation (cylindrical symmetry only)'
2422    if 'T' in calcControls[hfx+'histType']:
2423        tth = parmDict[hfx+'2-theta']
2424    else:
2425        tth = refl[5+im]
2426    odfCor = 1.0
2427    H = refl[:3]
2428    cell = G2lat.Gmat2cell(g)
2429    Sangls = [0.,0.,0.]
2430    if 'Bragg' in calcControls[hfx+'instType']:
2431        Gangls = [0.,90.,0.,parmDict[hfx+'Azimuth']]
2432        IFCoup = True
2433    else:
2434        Gangls = [parmDict[hfx+'Phi'],parmDict[hfx+'Chi'],parmDict[hfx+'Omega'],parmDict[hfx+'Azimuth']]
2435        IFCoup = False
2436    phi,beta = G2lat.CrsAng(H,cell,SGData)
2437    psi,gam,x,x = G2lat.SamAng(tth/2.,Gangls,Sangls,IFCoup) #ignore 2 sets of angle derivs.
2438    SHnames = calcControls[phfx+'SHnames']
2439    for item in SHnames:
2440        L,N = eval(item.strip('C'))
2441        Kcl = G2lat.GetKcl(L,N,SGData['SGLaue'],phi,beta)
2442        Ksl,x,x = G2lat.GetKsl(L,0,'0',psi,gam)
2443        Lnorm = G2lat.Lnorm(L)
2444        odfCor += parmDict[phfx+item]*Lnorm*Kcl*Ksl
2445    return np.squeeze(odfCor)
2446   
2447def SHPOcalDerv(refl,im,g,phfx,hfx,SGData,calcControls,parmDict):
2448    'spherical harmonics preferred orientation derivatives (cylindrical symmetry only)'
2449    if 'T' in calcControls[hfx+'histType']:
2450        tth = parmDict[hfx+'2-theta']
2451    else:
2452        tth = refl[5+im]
2453    odfCor = 1.0
2454    dFdODF = {}
2455    H = refl[:3]
2456    cell = G2lat.Gmat2cell(g)
2457    Sangls = [0.,0.,0.]
2458    if 'Bragg' in calcControls[hfx+'instType']:
2459        Gangls = [0.,90.,0.,parmDict[hfx+'Azimuth']]
2460        IFCoup = True
2461    else:
2462        Gangls = [parmDict[hfx+'Phi'],parmDict[hfx+'Chi'],parmDict[hfx+'Omega'],parmDict[hfx+'Azimuth']]
2463        IFCoup = False
2464    phi,beta = G2lat.CrsAng(H,cell,SGData)
2465    psi,gam,x,x = G2lat.SamAng(tth/2.,Gangls,Sangls,IFCoup) #ignore 2 sets of angle derivs.
2466    SHnames = calcControls[phfx+'SHnames']
2467    for item in SHnames:
2468        L,N = eval(item.strip('C'))
2469        Kcl = G2lat.GetKcl(L,N,SGData['SGLaue'],phi,beta)
2470        Ksl,x,x = G2lat.GetKsl(L,0,'0',psi,gam)
2471        Lnorm = G2lat.Lnorm(L)
2472        odfCor += parmDict[phfx+item]*Lnorm*Kcl*Ksl
2473        dFdODF[phfx+item] = Kcl*Ksl*Lnorm
2474    return odfCor,dFdODF
2475   
2476def GetPrefOri(uniq,G,g,phfx,hfx,SGData,calcControls,parmDict):
2477    'March-Dollase preferred orientation correction'
2478    POcorr = 1.0
2479    MD = parmDict[phfx+'MD']
2480    if MD != 1.0:
2481        MDAxis = calcControls[phfx+'MDAxis']
2482        sumMD = 0
2483        for H in uniq:           
2484            cosP,sinP = G2lat.CosSinAngle(H,MDAxis,G)
2485            A = 1.0/np.sqrt((MD*cosP)**2+sinP**2/MD)
2486            sumMD += A**3
2487        POcorr = sumMD/len(uniq)
2488    return POcorr
2489   
2490def GetPrefOriDerv(refl,im,uniq,G,g,phfx,hfx,SGData,calcControls,parmDict):
2491    'Needs a doc string'
2492    POcorr = 1.0
2493    POderv = {}
2494    if calcControls[phfx+'poType'] == 'MD':
2495        MD = parmDict[phfx+'MD']
2496        MDAxis = calcControls[phfx+'MDAxis']
2497        sumMD = 0
2498        sumdMD = 0
2499        for H in uniq:           
2500            cosP,sinP = G2lat.CosSinAngle(H,MDAxis,G)
2501            A = 1.0/np.sqrt((MD*cosP)**2+sinP**2/MD)
2502            sumMD += A**3
2503            sumdMD -= (1.5*A**5)*(2.0*MD*cosP**2-(sinP/MD)**2)
2504        POcorr = sumMD/len(uniq)
2505        POderv[phfx+'MD'] = sumdMD/len(uniq)
2506    else:   #spherical harmonics
2507        if calcControls[phfx+'SHord']:
2508            POcorr,POderv = SHPOcalDerv(refl,im,g,phfx,hfx,SGData,calcControls,parmDict)
2509    return POcorr,POderv
2510   
2511def GetAbsorb(refl,im,hfx,calcControls,parmDict):
2512    'Needs a doc string'
2513    if 'Debye' in calcControls[hfx+'instType']:
2514        if 'T' in calcControls[hfx+'histType']:
2515            return G2pwd.Absorb('Cylinder',parmDict[hfx+'Absorption']*refl[14+im],abs(parmDict[hfx+'2-theta']),0,0)
2516        else:
2517            return G2pwd.Absorb('Cylinder',parmDict[hfx+'Absorption'],refl[5+im],0,0)
2518    else:
2519        return G2pwd.SurfaceRough(parmDict[hfx+'SurfRoughA'],parmDict[hfx+'SurfRoughB'],refl[5+im])
2520   
2521def GetAbsorbDerv(refl,im,hfx,calcControls,parmDict):
2522    'Needs a doc string'
2523    if 'Debye' in calcControls[hfx+'instType']:
2524        if 'T' in calcControls[hfx+'histType']:
2525            return G2pwd.AbsorbDerv('Cylinder',parmDict[hfx+'Absorption']*refl[14+im],abs(parmDict[hfx+'2-theta']),0,0)
2526        else:
2527            return G2pwd.AbsorbDerv('Cylinder',parmDict[hfx+'Absorption'],refl[5+im],0,0)
2528    else:
2529        return np.array(G2pwd.SurfaceRoughDerv(parmDict[hfx+'SurfRoughA'],parmDict[hfx+'SurfRoughB'],refl[5+im]))
2530       
2531def GetPwdrExt(refl,im,pfx,phfx,hfx,calcControls,parmDict):
2532    'Needs a doc string'
2533    coef = np.array([-0.5,0.25,-0.10416667,0.036458333,-0.0109375,2.8497409E-3])
2534    pi2 = np.sqrt(2./np.pi)
2535    if 'T' in calcControls[hfx+'histType']:
2536        sth2 = sind(abs(parmDict[hfx+'2-theta'])/2.)**2
2537        wave = refl[14+im]
2538    else:   #'C'W
2539        sth2 = sind(refl[5+im]/2.)**2
2540        wave = parmDict.get(hfx+'Lam',parmDict.get(hfx+'Lam1',1.0))
2541    c2th = 1.-2.0*sth2
2542    flv2 = refl[9+im]*(wave/parmDict[pfx+'Vol'])**2
2543    if 'X' in calcControls[hfx+'histType']:
2544        flv2 *= 0.079411*(1.0+c2th**2)/2.0
2545    xfac = flv2*parmDict[phfx+'Extinction']
2546    exb = 1.0
2547    if xfac > -1.:
2548        exb = 1./np.sqrt(1.+xfac)
2549    exl = 1.0
2550    if 0 < xfac <= 1.:
2551        xn = np.array([xfac**(i+1) for i in range(6)])
2552        exl += np.sum(xn*coef)
2553    elif xfac > 1.:
2554        xfac2 = 1./np.sqrt(xfac)
2555        exl = pi2*(1.-0.125/xfac)*xfac2
2556    return exb*sth2+exl*(1.-sth2)
2557   
2558def GetPwdrExtDerv(refl,im,pfx,phfx,hfx,calcControls,parmDict):
2559    'Needs a doc string'
2560    coef = np.array([-0.5,0.25,-0.10416667,0.036458333,-0.0109375,2.8497409E-3])
2561    pi2 = np.sqrt(2./np.pi)
2562    if 'T' in calcControls[hfx+'histType']:
2563        sth2 = sind(abs(parmDict[hfx+'2-theta'])/2.)**2
2564        wave = refl[14+im]
2565    else:   #'C'W
2566        sth2 = sind(refl[5+im]/2.)**2
2567        wave = parmDict.get(hfx+'Lam',parmDict.get(hfx+'Lam1',1.0))
2568    c2th = 1.-2.0*sth2
2569    flv2 = refl[9+im]*(wave/parmDict[pfx+'Vol'])**2
2570    if 'X' in calcControls[hfx+'histType']:
2571        flv2 *= 0.079411*(1.0+c2th**2)/2.0
2572    xfac = flv2*parmDict[phfx+'Extinction']
2573    dbde = -500.*flv2
2574    if xfac > -1.:
2575        dbde = -0.5*flv2/np.sqrt(1.+xfac)**3
2576    dlde = 0.
2577    if 0 < xfac <= 1.:
2578        xn = np.array([i*flv2*xfac**i for i in [1,2,3,4,5,6]])
2579        dlde = np.sum(xn*coef)/xfac
2580    elif xfac > 1.:
2581        xfac2 = 1./np.sqrt(xfac)
2582        dlde = 0.5*flv2*pi2*xfac2*(-1./xfac+0.375/xfac**2)
2583       
2584    return dbde*sth2+dlde*(1.-sth2)
2585   
2586def GetIntensityCorr(refl,im,uniq,G,g,pfx,phfx,hfx,SGData,calcControls,parmDict):
2587    'Needs a doc string'    #need powder extinction!
2588    Icorr = parmDict[phfx+'Scale']*parmDict[hfx+'Scale']*refl[3+im]               #scale*multiplicity
2589    if 'X' in parmDict[hfx+'Type']:
2590        Icorr *= G2pwd.Polarization(parmDict[hfx+'Polariz.'],refl[5+im],parmDict[hfx+'Azimuth'])[0]
2591    POcorr = 1.0
2592    if pfx+'SHorder' in parmDict:                 #generalized spherical harmonics texture - takes precidence
2593        POcorr = SHTXcal(refl,im,g,pfx,hfx,SGData,calcControls,parmDict)
2594    elif calcControls[phfx+'poType'] == 'MD':         #March-Dollase
2595        POcorr = GetPrefOri(uniq,G,g,phfx,hfx,SGData,calcControls,parmDict)
2596    elif calcControls[phfx+'SHord']:                #cylindrical spherical harmonics
2597        POcorr = SHPOcal(refl,im,g,phfx,hfx,SGData,calcControls,parmDict)
2598    Icorr *= POcorr
2599    AbsCorr = 1.0
2600    AbsCorr = GetAbsorb(refl,im,hfx,calcControls,parmDict)
2601    Icorr *= AbsCorr
2602    ExtCorr = GetPwdrExt(refl,im,pfx,phfx,hfx,calcControls,parmDict)
2603    Icorr *= ExtCorr
2604    return Icorr,POcorr,AbsCorr,ExtCorr
2605   
2606def GetIntensityDerv(refl,im,wave,uniq,G,g,pfx,phfx,hfx,SGData,calcControls,parmDict):
2607    'Needs a doc string'    #need powder extinction derivs!
2608    dIdsh = 1./parmDict[hfx+'Scale']
2609    dIdsp = 1./parmDict[phfx+'Scale']
2610    if 'X' in parmDict[hfx+'Type']:
2611        pola,dIdPola = G2pwd.Polarization(parmDict[hfx+'Polariz.'],refl[5+im],parmDict[hfx+'Azimuth'])
2612        dIdPola /= pola
2613    else:       #'N'
2614        dIdPola = 0.0
2615    dFdODF = {}
2616    dFdSA = [0,0,0]
2617    dIdPO = {}
2618    if pfx+'SHorder' in parmDict:
2619        odfCor,dFdODF,dFdSA = SHTXcalDerv(refl,im,g,pfx,hfx,SGData,calcControls,parmDict)
2620        for iSH in dFdODF:
2621            dFdODF[iSH] /= odfCor
2622        for i in range(3):
2623            dFdSA[i] /= odfCor
2624    elif calcControls[phfx+'poType'] == 'MD' or calcControls[phfx+'SHord']:
2625        POcorr,dIdPO = GetPrefOriDerv(refl,im,uniq,G,g,phfx,hfx,SGData,calcControls,parmDict)       
2626        for iPO in dIdPO:
2627            dIdPO[iPO] /= POcorr
2628    if 'T' in parmDict[hfx+'Type']:
2629        dFdAb = GetAbsorbDerv(refl,im,hfx,calcControls,parmDict)*wave/refl[16+im] #wave/abs corr
2630        dFdEx = GetPwdrExtDerv(refl,im,pfx,phfx,hfx,calcControls,parmDict)/refl[17+im]    #/ext corr
2631    else:
2632        dFdAb = GetAbsorbDerv(refl,im,hfx,calcControls,parmDict)*wave/refl[13+im] #wave/abs corr
2633        dFdEx = GetPwdrExtDerv(refl,im,pfx,phfx,hfx,calcControls,parmDict)/refl[14+im]    #/ext corr       
2634    return dIdsh,dIdsp,dIdPola,dIdPO,dFdODF,dFdSA,dFdAb,dFdEx
2635       
2636def GetSampleSigGam(refl,im,wave,G,GB,SGData,hfx,phfx,calcControls,parmDict):
2637    'Needs a doc string'
2638    if 'C' in calcControls[hfx+'histType'] or 'B' in calcControls[hfx+'histType']:     #All checked & OK
2639        costh = cosd(refl[5+im]/2.)
2640        #crystallite size
2641        if calcControls[phfx+'SizeType'] == 'isotropic':
2642            Sgam = 1.8*wave/(np.pi*parmDict[phfx+'Size;i']*costh)
2643        elif calcControls[phfx+'SizeType'] == 'uniaxial':
2644            H = np.array(refl[:3])
2645            P = np.array(calcControls[phfx+'SizeAxis'])
2646            cosP,sinP = G2lat.CosSinAngle(H,P,G)
2647            Sgam = (1.8*wave/np.pi)/(parmDict[phfx+'Size;i']*parmDict[phfx+'Size;a']*costh)
2648            Sgam *= np.sqrt((sinP*parmDict[phfx+'Size;a'])**2+(cosP*parmDict[phfx+'Size;i'])**2)
2649        else:           #ellipsoidal crystallites
2650            Sij =[parmDict[phfx+'Size;%d'%(i)] for i in range(6)]
2651            H = np.array(refl[:3])
2652            lenR = G2pwd.ellipseSize(H,Sij,GB)
2653            Sgam = 1.8*wave/(np.pi*costh*lenR)
2654        #microstrain               
2655        if calcControls[phfx+'MustrainType'] == 'isotropic':
2656            Mgam = 0.018*parmDict[phfx+'Mustrain;i']*tand(refl[5+im]/2.)/np.pi
2657        elif calcControls[phfx+'MustrainType'] == 'uniaxial':
2658            H = np.array(refl[:3])
2659            P = np.array(calcControls[phfx+'MustrainAxis'])
2660            cosP,sinP = G2lat.CosSinAngle(H,P,G)
2661            Si = parmDict[phfx+'Mustrain;i']
2662            Sa = parmDict[phfx+'Mustrain;a']
2663            Mgam = 0.018*Si*Sa*tand(refl[5+im]/2.)/(np.pi*np.sqrt((Si*cosP)**2+(Sa*sinP)**2))
2664        else:       #generalized - P.W. Stephens model
2665            Strms = G2spc.MustrainCoeff(refl[:3],SGData)
2666            Sum = 0
2667            for i,strm in enumerate(Strms):
2668                Sum += parmDict[phfx+'Mustrain;'+str(i)]*strm
2669            Mgam = 0.018*refl[4+im]**2*tand(refl[5+im]/2.)*np.sqrt(Sum)/np.pi
2670    elif 'T' in calcControls[hfx+'histType']:       #All checked & OK
2671        #crystallite size
2672        if calcControls[phfx+'SizeType'] == 'isotropic':    #OK
2673            Sgam = 1.e-4*parmDict[hfx+'difC']*refl[4+im]**2/parmDict[phfx+'Size;i']
2674        elif calcControls[phfx+'SizeType'] == 'uniaxial':   #OK
2675            H = np.array(refl[:3])
2676            P = np.array(calcControls[phfx+'SizeAxis'])
2677            cosP,sinP = G2lat.CosSinAngle(H,P,G)
2678            Sgam = 1.e-4*parmDict[hfx+'difC']*refl[4+im]**2/(parmDict[phfx+'Size;i']*parmDict[phfx+'Size;a'])
2679            Sgam *= np.sqrt((sinP*parmDict[phfx+'Size;a'])**2+(cosP*parmDict[phfx+'Size;i'])**2)
2680        else:           #ellipsoidal crystallites   #OK
2681            Sij =[parmDict[phfx+'Size;%d'%(i)] for i in range(6)]
2682            H = np.array(refl[:3])
2683            lenR = G2pwd.ellipseSize(H,Sij,GB)
2684            Sgam = 1.e-4*parmDict[hfx+'difC']*refl[4+im]**2/lenR
2685        #microstrain               
2686        if calcControls[phfx+'MustrainType'] == 'isotropic':    #OK
2687            Mgam = 1.e-6*parmDict[hfx+'difC']*refl[4+im]*parmDict[phfx+'Mustrain;i']
2688        elif calcControls[phfx+'MustrainType'] == 'uniaxial':   #OK
2689            H = np.array(refl[:3])
2690            P = np.array(calcControls[phfx+'MustrainAxis'])
2691            cosP,sinP = G2lat.CosSinAngle(H,P,G)
2692            Si = parmDict[phfx+'Mustrain;i']
2693            Sa = parmDict[phfx+'Mustrain;a']
2694            Mgam = 1.e-6*parmDict[hfx+'difC']*refl[4+im]*Si*Sa/np.sqrt((Si*cosP)**2+(Sa*sinP)**2)
2695        else:       #generalized - P.W. Stephens model  OK
2696            Strms = G2spc.MustrainCoeff(refl[:3],SGData)
2697            Sum = 0
2698            for i,strm in enumerate(Strms):
2699                Sum += parmDict[phfx+'Mustrain;'+str(i)]*strm
2700            Mgam = 1.e-6*parmDict[hfx+'difC']*np.sqrt(Sum)*refl[4+im]**3
2701           
2702    gam = Sgam*parmDict[phfx+'Size;mx']+Mgam*parmDict[phfx+'Mustrain;mx']
2703    sig = (Sgam*(1.-parmDict[phfx+'Size;mx']))**2+(Mgam*(1.-parmDict[phfx+'Mustrain;mx']))**2
2704    sig /= ateln2
2705    return sig,gam
2706       
2707def GetSampleSigGamDerv(refl,im,wave,G,GB,SGData,hfx,phfx,calcControls,parmDict):
2708    'Needs a doc string'
2709    gamDict = {}
2710    sigDict = {}
2711    if 'C' in calcControls[hfx+'histType'] or 'B' in calcControls[hfx+'histType']:         #All checked & OK
2712        costh = cosd(refl[5+im]/2.)
2713        tanth = tand(refl[5+im]/2.)
2714        #crystallite size derivatives
2715        if calcControls[phfx+'SizeType'] == 'isotropic':
2716            Sgam = 1.8*wave/(np.pi*costh*parmDict[phfx+'Size;i'])
2717            gamDict[phfx+'Size;i'] = -1.8*wave*parmDict[phfx+'Size;mx']/(np.pi*costh*parmDict[phfx+'Size;i']**2)
2718            sigDict[phfx+'Size;i'] = -3.6*Sgam*wave*(1.-parmDict[phfx+'Size;mx'])**2/(np.pi*costh*ateln2)
2719        elif calcControls[phfx+'SizeType'] == 'uniaxial':
2720            H = np.array(refl[:3])
2721            P = np.array(calcControls[phfx+'SizeAxis'])
2722            cosP,sinP = G2lat.CosSinAngle(H,P,G)
2723            Si = parmDict[phfx+'Size;i']
2724            Sa = parmDict[phfx+'Size;a']
2725            gami = 1.8*wave/(costh*np.pi*Si*Sa)
2726            sqtrm = np.sqrt((sinP*Sa)**2+(cosP*Si)**2)
2727            Sgam = gami*sqtrm
2728            dsi = gami*Si*cosP**2/sqtrm-Sgam/Si
2729            dsa = gami*Sa*sinP**2/sqtrm-Sgam/Sa
2730            gamDict[phfx+'Size;i'] = dsi*parmDict[phfx+'Size;mx']
2731            gamDict[phfx+'Size;a'] = dsa*parmDict[phfx+'Size;mx']
2732            sigDict[phfx+'Size;i'] = 2.*dsi*Sgam*(1.-parmDict[phfx+'Size;mx'])**2/ateln2
2733            sigDict[phfx+'Size;a'] = 2.*dsa*Sgam*(1.-parmDict[phfx+'Size;mx'])**2/ateln2
2734        else:           #ellipsoidal crystallites
2735            const = 1.8*wave/(np.pi*costh)
2736            Sij =[parmDict[phfx+'Size;%d'%(i)] for i in range(6)]
2737            H = np.array(refl[:3])
2738            lenR,dRdS = G2pwd.ellipseSizeDerv(H,Sij,GB)
2739            Sgam = const/lenR
2740            for i,item in enumerate([phfx+'Size;%d'%(j) for j in range(6)]):
2741                gamDict[item] = -(const/lenR**2)*dRdS[i]*parmDict[phfx+'Size;mx']
2742                sigDict[item] = -2.*Sgam*(const/lenR**2)*dRdS[i]*(1.-parmDict[phfx+'Size;mx'])**2/ateln2
2743        gamDict[phfx+'Size;mx'] = Sgam
2744        sigDict[phfx+'Size;mx'] = -2.*Sgam**2*(1.-parmDict[phfx+'Size;mx'])/ateln2
2745               
2746        #microstrain derivatives               
2747        if calcControls[phfx+'MustrainType'] == 'isotropic':
2748            Mgam = 0.018*parmDict[phfx+'Mustrain;i']*tand(refl[5+im]/2.)/np.pi
2749            gamDict[phfx+'Mustrain;i'] =  0.018*tanth*parmDict[phfx+'Mustrain;mx']/np.pi
2750            sigDict[phfx+'Mustrain;i'] =  0.036*Mgam*tanth*(1.-parmDict[phfx+'Mustrain;mx'])**2/(np.pi*ateln2)       
2751        elif calcControls[phfx+'MustrainType'] == 'uniaxial':
2752            H = np.array(refl[:3])
2753            P = np.array(calcControls[phfx+'MustrainAxis'])
2754            cosP,sinP = G2lat.CosSinAngle(H,P,G)
2755            Si = parmDict[phfx+'Mustrain;i']
2756            Sa = parmDict[phfx+'Mustrain;a']
2757            gami = 0.018*Si*Sa*tanth/np.pi
2758            sqtrm = np.sqrt((Si*cosP)**2+(Sa*sinP)**2)
2759            Mgam = gami/sqtrm
2760            dsi = -gami*Si*cosP**2/sqtrm**3
2761            dsa = -gami*Sa*sinP**2/sqtrm**3
2762            gamDict[phfx+'Mustrain;i'] = (Mgam/Si+dsi)*parmDict[phfx+'Mustrain;mx']
2763            gamDict[phfx+'Mustrain;a'] = (Mgam/Sa+dsa)*parmDict[phfx+'Mustrain;mx']
2764            sigDict[phfx+'Mustrain;i'] = 2*(Mgam/Si+dsi)*Mgam*(1.-parmDict[phfx+'Mustrain;mx'])**2/ateln2
2765            sigDict[phfx+'Mustrain;a'] = 2*(Mgam/Sa+dsa)*Mgam*(1.-parmDict[phfx+'Mustrain;mx'])**2/ateln2       
2766        else:       #generalized - P.W. Stephens model
2767            const = 0.018*refl[4+im]**2*tanth/np.pi
2768            Strms = G2spc.MustrainCoeff(refl[:3],SGData)
2769            Sum = 0
2770            for i,strm in enumerate(Strms):
2771                Sum += parmDict[phfx+'Mustrain;'+str(i)]*strm
2772                gamDict[phfx+'Mustrain;'+str(i)] = strm*parmDict[phfx+'Mustrain;mx']/2.
2773                sigDict[phfx+'Mustrain;'+str(i)] = strm*(1.-parmDict[phfx+'Mustrain;mx'])**2
2774            Mgam = const*np.sqrt(Sum)
2775            for i in range(len(Strms)):
2776                gamDict[phfx+'Mustrain;'+str(i)] *= Mgam/Sum
2777                sigDict[phfx+'Mustrain;'+str(i)] *= const**2/ateln2
2778        gamDict[phfx+'Mustrain;mx'] = Mgam
2779        sigDict[phfx+'Mustrain;mx'] = -2.*Mgam**2*(1.-parmDict[phfx+'Mustrain;mx'])/ateln2
2780    else:   #'T'OF - All checked & OK
2781        if calcControls[phfx+'SizeType'] == 'isotropic':    #OK
2782            Sgam = 1.e-4*parmDict[hfx+'difC']*refl[4+im]**2/parmDict[phfx+'Size;i']
2783            gamDict[phfx+'Size;i'] = -Sgam*parmDict[phfx+'Size;mx']/parmDict[phfx+'Size;i']
2784            sigDict[phfx+'Size;i'] = -2.*Sgam**2*(1.-parmDict[phfx+'Size;mx'])**2/(ateln2*parmDict[phfx+'Size;i'])
2785        elif calcControls[phfx+'SizeType'] == 'uniaxial':   #OK
2786            const = 1.e-4*parmDict[hfx+'difC']*refl[4+im]**2
2787            H = np.array(refl[:3])
2788            P = np.array(calcControls[phfx+'SizeAxis'])
2789            cosP,sinP = G2lat.CosSinAngle(H,P,G)
2790            Si = parmDict[phfx+'Size;i']
2791            Sa = parmDict[phfx+'Size;a']
2792            gami = const/(Si*Sa)
2793            sqtrm = np.sqrt((sinP*Sa)**2+(cosP*Si)**2)
2794            Sgam = gami*sqtrm
2795            dsi = gami*Si*cosP**2/sqtrm-Sgam/Si
2796            dsa = gami*Sa*sinP**2/sqtrm-Sgam/Sa
2797            gamDict[phfx+'Size;i'] = dsi*parmDict[phfx+'Size;mx']
2798            gamDict[phfx+'Size;a'] = dsa*parmDict[phfx+'Size;mx']
2799            sigDict[phfx+'Size;i'] = 2.*dsi*Sgam*(1.-parmDict[phfx+'Size;mx'])**2/ateln2
2800            sigDict[phfx+'Size;a'] = 2.*dsa*Sgam*(1.-parmDict[phfx+'Size;mx'])**2/ateln2
2801        else:           #OK  ellipsoidal crystallites
2802            const = 1.e-4*parmDict[hfx+'difC']*refl[4+im]**2
2803            Sij =[parmDict[phfx+'Size;%d'%(i)] for i in range(6)]
2804            H = np.array(refl[:3])
2805            lenR,dRdS = G2pwd.ellipseSizeDerv(H,Sij,GB)
2806            Sgam = const/lenR
2807            for i,item in enumerate([phfx+'Size;%d'%(j) for j in range(6)]):
2808                gamDict[item] = -(const/lenR**2)*dRdS[i]*parmDict[phfx+'Size;mx']
2809                sigDict[item] = -2.*Sgam*(const/lenR**2)*dRdS[i]*(1.-parmDict[phfx+'Size;mx'])**2/ateln2
2810        gamDict[phfx+'Size;mx'] = Sgam  #OK
2811        sigDict[phfx+'Size;mx'] = -2.*Sgam**2*(1.-parmDict[phfx+'Size;mx'])/ateln2  #OK
2812               
2813        #microstrain derivatives               
2814        if calcControls[phfx+'MustrainType'] == 'isotropic':
2815            Mgam = 1.e-6*parmDict[hfx+'difC']*refl[4+im]*parmDict[phfx+'Mustrain;i']
2816            gamDict[phfx+'Mustrain;i'] =  1.e-6*refl[4+im]*parmDict[hfx+'difC']*parmDict[phfx+'Mustrain;mx']   #OK
2817            sigDict[phfx+'Mustrain;i'] =  2.*Mgam**2*(1.-parmDict[phfx+'Mustrain;mx'])**2/(ateln2*parmDict[phfx+'Mustrain;i'])       
2818        elif calcControls[phfx+'MustrainType'] == 'uniaxial':
2819            H = np.array(refl[:3])
2820            P = np.array(calcControls[phfx+'MustrainAxis'])
2821            cosP,sinP = G2lat.CosSinAngle(H,P,G)
2822            Si = parmDict[phfx+'Mustrain;i']
2823            Sa = parmDict[phfx+'Mustrain;a']
2824            gami = 1.e-6*parmDict[hfx+'difC']*refl[4+im]*Si*Sa
2825            sqtrm = np.sqrt((Si*cosP)**2+(Sa*sinP)**2)
2826            Mgam = gami/sqtrm
2827            dsi = -gami*Si*cosP**2/sqtrm**3
2828            dsa = -gami*Sa*sinP**2/sqtrm**3
2829            gamDict[phfx+'Mustrain;i'] = (Mgam/Si+dsi)*parmDict[phfx+'Mustrain;mx']
2830            gamDict[phfx+'Mustrain;a'] = (Mgam/Sa+dsa)*parmDict[phfx+'Mustrain;mx']
2831            sigDict[phfx+'Mustrain;i'] = 2*(Mgam/Si+dsi)*Mgam*(1.-parmDict[phfx+'Mustrain;mx'])**2/ateln2
2832            sigDict[phfx+'Mustrain;a'] = 2*(Mgam/Sa+dsa)*Mgam*(1.-parmDict[phfx+'Mustrain;mx'])**2/ateln2       
2833        else:       #generalized - P.W. Stephens model OK
2834            Strms = G2spc.MustrainCoeff(refl[:3],SGData)
2835            const = 1.e-6*parmDict[hfx+'difC']*refl[4+im]**3
2836            Sum = 0
2837            for i,strm in enumerate(Strms):
2838                Sum += parmDict[phfx+'Mustrain;'+str(i)]*strm
2839                gamDict[phfx+'Mustrain;'+str(i)] = strm*parmDict[phfx+'Mustrain;mx']/2.
2840                sigDict[phfx+'Mustrain;'+str(i)] = strm*(1.-parmDict[phfx+'Mustrain;mx'])**2
2841            Mgam = const*np.sqrt(Sum)
2842            for i in range(len(Strms)):
2843                gamDict[phfx+'Mustrain;'+str(i)] *= Mgam/Sum
2844                sigDict[phfx+'Mustrain;'+str(i)] *= const**2/ateln2       
2845        gamDict[phfx+'Mustrain;mx'] = Mgam
2846        sigDict[phfx+'Mustrain;mx'] = -2.*Mgam**2*(1.-parmDict[phfx+'Mustrain;mx'])/ateln2
2847       
2848    return sigDict,gamDict
2849       
2850def GetReflPos(refl,im,wave,A,pfx,hfx,phfx,calcControls,parmDict):
2851    'Needs a doc string'
2852    if im:
2853        h,k,l,m = refl[:4]
2854        vec = np.array([parmDict[pfx+'mV0'],parmDict[pfx+'mV1'],parmDict[pfx+'mV2']])
2855        d = 1./np.sqrt(G2lat.calc_rDsqSS(np.array([h,k,l,m]),A,vec))
2856    else:
2857        h,k,l = refl[:3]
2858        d = 1./np.sqrt(G2lat.calc_rDsq(np.array([h,k,l]),A))
2859    refl[4+im] = d
2860    if 'C' in calcControls[hfx+'histType'] or 'B' in calcControls[hfx+'histType']:
2861        pos = 2.0*asind(wave/(2.0*d))+parmDict[hfx+'Zero']
2862        const = 9.e-2/(np.pi*parmDict[hfx+'Gonio. radius'])                  #shifts in microns
2863        if 'Bragg' in calcControls[hfx+'instType']:
2864            pos -= const*(4.*parmDict[hfx+'Shift']*cosd(pos/2.0)+ \
2865                parmDict[hfx+'Transparency']*sind(pos)*100.0)            #trans(=1/mueff) in cm
2866        else:               #Debye-Scherrer - simple but maybe not right
2867            pos -= const*(parmDict[hfx+'DisplaceX']*cosd(pos)+(parmDict[hfx+'DisplaceY']+parmDict[phfx+'LayerDisp'])*sind(pos))
2868    elif 'T' in calcControls[hfx+'histType']:
2869        pos = parmDict[hfx+'difC']*d+parmDict[hfx+'difA']*d**2+parmDict[hfx+'difB']/d+parmDict[hfx+'Zero']
2870        #do I need sample position effects - maybe?
2871    return pos
2872
2873def GetReflPosDerv(refl,im,wave,A,pfx,hfx,phfx,calcControls,parmDict):
2874    'Needs a doc string'
2875    dpr = 180./np.pi
2876    if im:
2877        h,k,l,m = refl[:4]
2878        vec = np.array([parmDict[pfx+'mV0'],parmDict[pfx+'mV1'],parmDict[pfx+'mV2']])
2879        dstsq = G2lat.calc_rDsqSS(np.array([h,k,l,m]),A,vec)
2880        h,k,l = [h+m*vec[0],k+m*vec[1],l+m*vec[2]]          #do proj of hklm to hkl so dPdA & dPdV come out right
2881    else:
2882        m = 0
2883        h,k,l = refl[:3]       
2884        dstsq = G2lat.calc_rDsq(np.array([h,k,l]),A)
2885    dst = np.sqrt(dstsq)
2886    dsp = 1./dst
2887    if 'C' in calcControls[hfx+'histType'] or 'B' in calcControls[hfx+'histType']:
2888        pos = refl[5+im]-parmDict[hfx+'Zero']
2889        const = dpr/np.sqrt(1.0-wave**2*dstsq/4.0)
2890        dpdw = const*dst
2891        dpdA = np.array([h**2,k**2,l**2,h*k,h*l,k*l])*const*wave/(2.0*dst)
2892        dpdZ = 1.0
2893        dpdV = np.array([2.*h*A[0]+k*A[3]+l*A[4],2*k*A[1]+h*A[3]+l*A[5],
2894            2*l*A[2]+h*A[4]+k*A[5]])*m*const*wave/(2.0*dst)
2895        shft = 9.e-2/(np.pi*parmDict[hfx+'Gonio. radius'])                  #shifts in microns
2896        if 'Bragg' in calcControls[hfx+'instType']:
2897            dpdSh = -4.*shft*cosd(pos/2.0)
2898            dpdTr = -shft*sind(pos)*100.0
2899            return dpdA,dpdw,dpdZ,dpdSh,dpdTr,0.,0.,dpdV
2900        else:               #Debye-Scherrer - simple but maybe not right
2901            dpdXd = -shft*cosd(pos)
2902            dpdYd = -shft*sind(pos)
2903            return dpdA,dpdw,dpdZ,0.,0.,dpdXd,dpdYd,dpdV
2904    elif 'T' in calcControls[hfx+'histType']:
2905        dpdA = -np.array([h**2,k**2,l**2,h*k,h*l,k*l])*parmDict[hfx+'difC']*dsp**3/2.
2906        dpdZ = 1.0
2907        dpdDC = dsp
2908        dpdDA = dsp**2
2909        dpdDB = 1./dsp
2910        dpdV = np.array([2.*h*A[0]+k*A[3]+l*A[4],2*k*A[1]+h*A[3]+l*A[5],
2911            2*l*A[2]+h*A[4]+k*A[5]])*m*parmDict[hfx+'difC']*dsp**3/2.
2912        return dpdA,dpdZ,dpdDC,dpdDA,dpdDB,dpdV
2913           
2914def GetHStrainShift(refl,im,SGData,phfx,hfx,calcControls,parmDict):
2915    'Needs a doc string'
2916    laue = SGData['SGLaue']
2917    uniq = SGData['SGUniq']
2918    h,k,l = refl[:3]
2919    if laue in ['m3','m3m']:
2920        Dij = parmDict[phfx+'D11']*(h**2+k**2+l**2)+ \
2921            refl[4+im]**2*parmDict[phfx+'eA']*((h*k)**2+(h*l)**2+(k*l)**2)/(h**2+k**2+l**2)**2
2922    elif laue in ['6/m','6/mmm','3m1','31m','3']:
2923        Dij = parmDict[phfx+'D11']*(h**2+k**2+h*k)+parmDict[phfx+'D33']*l**2
2924    elif laue in ['3R','3mR']:
2925        Dij = parmDict[phfx+'D11']*(h**2+k**2+l**2)+parmDict[phfx+'D12']*(h*k+h*l+k*l)
2926    elif laue in ['4/m','4/mmm']:
2927        Dij = parmDict[phfx+'D11']*(h**2+k**2)+parmDict[phfx+'D33']*l**2
2928    elif laue in ['mmm']:
2929        Dij = parmDict[phfx+'D11']*h**2+parmDict[phfx+'D22']*k**2+parmDict[phfx+'D33']*l**2
2930    elif laue in ['2/m']:
2931        Dij = parmDict[phfx+'D11']*h**2+parmDict[phfx+'D22']*k**2+parmDict[phfx+'D33']*l**2
2932        if uniq == 'a':
2933            Dij += parmDict[phfx+'D23']*k*l
2934        elif uniq == 'b':
2935            Dij += parmDict[phfx+'D13']*h*l
2936        elif uniq == 'c':
2937            Dij += parmDict[phfx+'D12']*h*k
2938    else:
2939        Dij = parmDict[phfx+'D11']*h**2+parmDict[phfx+'D22']*k**2+parmDict[phfx+'D33']*l**2+ \
2940            parmDict[phfx+'D12']*h*k+parmDict[phfx+'D13']*h*l+parmDict[phfx+'D23']*k*l
2941    if 'C' in calcControls[hfx+'histType'] or 'B' in calcControls[hfx+'histType']:
2942        return -180.*Dij*refl[4+im]**2*tand(refl[5+im]/2.0)/np.pi
2943    else:
2944        return -Dij*parmDict[hfx+'difC']*refl[4+im]**2/2.
2945           
2946def GetHStrainShiftDerv(refl,im,SGData,phfx,hfx,calcControls,parmDict):
2947    'Needs a doc string'
2948    laue = SGData['SGLaue']
2949    uniq = SGData['SGUniq']
2950    h,k,l = refl[:3]
2951    if laue in ['m3','m3m']:
2952        dDijDict = {phfx+'D11':h**2+k**2+l**2,
2953            phfx+'eA':refl[4+im]**2*((h*k)**2+(h*l)**2+(k*l)**2)/(h**2+k**2+l**2)**2}
2954    elif laue in ['6/m','6/mmm','3m1','31m','3']:
2955        dDijDict = {phfx+'D11':h**2+k**2+h*k,phfx+'D33':l**2}
2956    elif laue in ['3R','3mR']:
2957        dDijDict = {phfx+'D11':h**2+k**2+l**2,phfx+'D12':h*k+h*l+k*l}
2958    elif laue in ['4/m','4/mmm']:
2959        dDijDict = {phfx+'D11':h**2+k**2,phfx+'D33':l**2}
2960    elif laue in ['mmm']:
2961        dDijDict = {phfx+'D11':h**2,phfx+'D22':k**2,phfx+'D33':l**2}
2962    elif laue in ['2/m']:
2963        dDijDict = {phfx+'D11':h**2,phfx+'D22':k**2,phfx+'D33':l**2}
2964        if uniq == 'a':
2965            dDijDict[phfx+'D23'] = k*l
2966        elif uniq == 'b':
2967            dDijDict[phfx+'D13'] = h*l
2968        elif uniq == 'c':
2969            dDijDict[phfx+'D12'] = h*k
2970    else:
2971        dDijDict = {phfx+'D11':h**2,phfx+'D22':k**2,phfx+'D33':l**2,
2972            phfx+'D12':h*k,phfx+'D13':h*l,phfx+'D23':k*l}
2973    if 'C' in calcControls[hfx+'histType'] or 'B' in calcControls[hfx+'histType']:
2974        for item in dDijDict:
2975            dDijDict[item] *= 180.0*refl[4+im]**2*tand(refl[5+im]/2.0)/np.pi
2976    else:
2977        for item in dDijDict:
2978            dDijDict[item] *= -parmDict[hfx+'difC']*refl[4+im]**3/2.
2979    return dDijDict
2980   
2981def GetDij(phfx,SGData,parmDict):
2982    HSvals = [parmDict[phfx+name] for name in G2spc.HStrainNames(SGData)]
2983    return G2spc.HStrainVals(HSvals,SGData)
2984               
2985def GetFobsSq(Histograms,Phases,parmDict,calcControls):
2986    '''Compute the observed structure factors for Powder histograms and store in reflection array
2987    Multiprocessing support added
2988    '''
2989    if GSASIIpath.GetConfigValue('Show_timing',False):
2990        starttime = time.time() #; print 'start GetFobsSq'
2991    histoList = list(Histograms.keys())
2992    histoList.sort()
2993    Ka2 = shl = lamRatio = kRatio = None
2994    for histogram in histoList:
2995        if 'PWDR' in histogram[:4]:
2996            Histogram = Histograms[histogram]
2997            hId = Histogram['hId']
2998            hfx = ':%d:'%(hId)
2999            Limits = calcControls[hfx+'Limits']
3000            if 'C' in calcControls[hfx+'histType']:
3001                shl = max(parmDict[hfx+'SH/L'],0.0005)
3002                Ka2 = False
3003                kRatio = 0.0
3004                if hfx+'Lam1' in list(parmDict.keys()):
3005                    Ka2 = True
3006                    lamRatio = 360*(parmDict[hfx+'Lam2']-parmDict[hfx+'Lam1'])/(np.pi*parmDict[hfx+'Lam1'])
3007                    kRatio = parmDict[hfx+'I(L2)/I(L1)']
3008            x,y,w,yc,yb,yd = Histogram['Data']
3009            xMask = ma.getmaskarray(x)
3010            xB = np.searchsorted(x,Limits[0])
3011            xF = np.searchsorted(x,Limits[1])
3012            ymb = np.array(y-yb)
3013            ymb = np.where(ymb,ymb,1.0)
3014            ycmb = np.array(yc-yb)
3015            ratio = 1./np.where(ycmb,ycmb/ymb,1.e10)         
3016            refLists = Histogram['Reflection Lists']
3017            for phase in refLists:
3018                if phase not in Phases:     #skips deleted or renamed phases silently!
3019                    continue
3020                Phase = Phases[phase]
3021                if histogram not in Phase['Histograms']:
3022                    continue
3023                im = 0
3024                if Phase['General'].get('Modulated',False):
3025                    im = 1
3026                pId = Phase['pId']
3027                phfx = '%d:%d:'%(pId,hId)
3028                refDict = refLists[phase]
3029                sumFo = 0.0
3030                sumdF = 0.0
3031                sumFosq = 0.0
3032                sumdFsq = 0.0
3033                sumInt = 0.0
3034                nExcl = 0
3035                # test to see if we are using multiprocessing below
3036                useMP,ncores = G2mp.InitMP()
3037                if len(refDict['RefList']) < 100: useMP = False       
3038                if useMP: # multiprocessing: create a set of initialized Python processes
3039                    MPpool = mp.Pool(G2mp.ncores,G2mp.InitFobsSqGlobals,
3040                                    [x,ratio,shl,xB,xF,im,lamRatio,kRatio,xMask,Ka2])
3041                    profArgs = [[] for i in range(G2mp.ncores)]
3042                else:
3043                    G2mp.InitFobsSqGlobals(x,ratio,shl,xB,xF,im,lamRatio,kRatio,xMask,Ka2)
3044                if 'C' in calcControls[hfx+'histType']:
3045                    # are we multiprocessing?
3046                    for iref,refl in enumerate(refDict['RefList']):
3047                        if useMP: 
3048                            profArgs[iref%G2mp.ncores].append((refl,iref))
3049                        else:
3050                            icod= G2mp.ComputeFobsSqCW(refl,iref)
3051                            if type(icod) is tuple:
3052                                refl[8+im] = icod[0]
3053                                sumInt += icod[1]
3054                                if parmDict[phfx+'LeBail']: refl[9+im] = refl[8+im]
3055                            elif icod == -1:
3056                                refl[3+im] *= -1
3057                                nExcl += 1
3058                            elif icod == -2:
3059                                break
3060                    if useMP:
3061                        for sInt,resList in MPpool.imap_unordered(G2mp.ComputeFobsSqCWbatch,profArgs):
3062                            sumInt += sInt
3063                            for refl8im,irefl in resList:
3064                                if refl8im is None:
3065                                    refDict['RefList'][irefl][3+im] *= -1
3066                                    nExcl += 1
3067                                else:
3068                                    refDict['RefList'][irefl][8+im] = refl8im
3069                                    if parmDict[phfx+'LeBail']:
3070                                        refDict['RefList'][irefl][9+im] = refDict['RefList'][irefl][8+im]
3071                elif 'T' in calcControls[hfx+'histType']:
3072                    for iref,refl in enumerate(refDict['RefList']):
3073                        if useMP: 
3074                            profArgs[iref%G2mp.ncores].append((refl,iref))
3075                        else:
3076                            icod= G2mp.ComputeFobsSqTOF(refl,iref)
3077                            if type(icod) is tuple:
3078                                refl[8+im] = icod[0]
3079                                sumInt += icod[1]
3080                                if parmDict[phfx+'LeBail']: refl[9+im] = refl[8+im]
3081                            elif icod == -1:
3082                                refl[3+im] *= -1
3083                                nExcl += 1
3084                            elif icod == -2:
3085                                break
3086                    if useMP:
3087                        for sInt,resList in MPpool.imap_unordered(G2mp.ComputeFobsSqTOFbatch,profArgs):
3088                            sumInt += sInt
3089                            for refl8im,irefl in resList:
3090                                if refl8im is None:
3091                                    refDict['RefList'][irefl][3+im] *= -1
3092                                    nExcl += 1
3093                                else:
3094                                    refDict['RefList'][irefl][8+im] = refl8im
3095                                    if parmDict[phfx+'LeBail']:
3096                                        refDict['RefList'][irefl][9+im] = refDict['RefList'][irefl][8+im]
3097                elif 'B' in calcControls[hfx+'histType']:
3098                    for iref,refl in enumerate(refDict['RefList']):
3099                        if useMP: 
3100                            profArgs[iref%G2mp.ncores].append((refl,iref))
3101                        else:
3102                            icod= G2mp.ComputeFobsSqPink(refl,iref)
3103                            if type(icod) is tuple:
3104                                refl[8+im] = icod[0]
3105                                sumInt += icod[1]
3106                                if parmDict[phfx+'LeBail']: refl[9+im] = refl[8+im]
3107                            elif icod == -1:
3108                                refl[3+im] *= -1
3109                                nExcl += 1
3110                            elif icod == -2:
3111                                break
3112                    if useMP:
3113                        for sInt,resList in MPpool.imap_unordered(G2mp.ComputeFobsSqPinkbatch,profArgs):
3114                            sumInt += sInt
3115                            for refl8im,irefl in resList:
3116                                if refl8im is None:
3117                                    refDict['RefList'][irefl][3+im] *= -1
3118                                    nExcl += 1
3119                                else:
3120                                    refDict['RefList'][irefl][8+im] = refl8im
3121                                    if parmDict[phfx+'LeBail']:
3122                                        refDict['RefList'][irefl][9+im] = refDict['RefList'][irefl][8+im]
3123                if useMP: MPpool.terminate()
3124                sumFo = 0.0
3125                sumdF = 0.0
3126                sumFosq = 0.0
3127                sumdFsq = 0.0
3128                for iref,refl in enumerate(refDict['RefList']):
3129                    Fo = np.sqrt(np.abs(refl[8+im]))
3130                    Fc = np.sqrt(np.abs(refl[9]+im))
3131                    sumFo += Fo
3132                    sumFosq += refl[8+im]**2
3133                    sumdF += np.abs(Fo-Fc)
3134                    sumdFsq += (refl[8+im]-refl[9+im])**2
3135                if sumFo:
3136                    Histogram['Residuals'][phfx+'Rf'] = min(100.,(sumdF/sumFo)*100.)
3137                    Histogram['Residuals'][phfx+'Rf^2'] = min(100.,np.sqrt(sumdFsq/sumFosq)*100.)
3138                else:
3139                    Histogram['Residuals'][phfx+'Rf'] = 100.
3140                    Histogram['Residuals'][phfx+'Rf^2'] = 100.
3141                Histogram['Residuals'][phfx+'sumInt'] = sumInt
3142                Histogram['Residuals'][phfx+'Nref'] = len(refDict['RefList'])-nExcl
3143                Histogram['Residuals']['hId'] = hId
3144        elif 'HKLF' in histogram[:4]:
3145            Histogram = Histograms[histogram]
3146            Histogram['Residuals']['hId'] = Histograms[histogram]['hId']
3147    if GSASIIpath.GetConfigValue('Show_timing',False):
3148        print ('GetFobsSq t=',time.time()-starttime)
3149               
3150def getPowderProfile(parmDict,x,varylist,Histogram,Phases,calcControls,pawleyLookup,histogram=None):
3151    'Computes the powder pattern for a histogram based on contributions from all used phases'
3152    if GSASIIpath.GetConfigValue('Show_timing',False): starttime = time.time()
3153   
3154    def GetReflSigGamCW(refl,im,wave,G,GB,phfx,calcControls,parmDict):
3155        U = parmDict[hfx+'U']
3156        V = parmDict[hfx+'V']
3157        W = parmDict[hfx+'W']
3158        X = parmDict[hfx+'X']
3159        Y = parmDict[hfx+'Y']
3160        Z = parmDict[hfx+'Z']
3161        tanPos = tand(refl[5+im]/2.0)
3162        Ssig,Sgam = GetSampleSigGam(refl,im,wave,G,GB,SGData,hfx,phfx,calcControls,parmDict)
3163        sig = U*tanPos**2+V*tanPos+W+Ssig     #save peak sigma
3164        sig = max(0.001,sig)
3165        gam = X/cosd(refl[5+im]/2.0)+Y*tanPos+Sgam+Z     #save peak gamma
3166        gam = max(0.001,gam)
3167        return sig,gam
3168               
3169    def GetReflSigGamTOF(refl,im,G,GB,phfx,calcControls,parmDict):
3170        sig = parmDict[hfx+'sig-0']+parmDict[hfx+'sig-1']*refl[4+im]**2+   \
3171            parmDict[hfx+'sig-2']*refl[4+im]**4+parmDict[hfx+'sig-q']*refl[4+im]
3172        gam = parmDict[hfx+'X']*refl[4+im]+parmDict[hfx+'Y']*refl[4+im]**2+parmDict[hfx+'Z']
3173        Ssig,Sgam = GetSampleSigGam(refl,im,0.0,G,GB,SGData,hfx,phfx,calcControls,parmDict)
3174        sig += Ssig
3175        gam += Sgam
3176        return sig,gam
3177       
3178    def GetReflAlpBet(refl,im,hfx,parmDict):
3179        alp = parmDict[hfx+'alpha']/refl[4+im]
3180        bet = parmDict[hfx+'beta-0']+parmDict[hfx+'beta-1']/refl[4+im]**4+parmDict[hfx+'beta-q']/refl[4+im]**2
3181        return alp,bet
3182       
3183    def GetPinkReflAlpBet(refl,im,hfx,parmDict):
3184        tanPos = tand(refl[5+im]/2.0)
3185        alp = parmDict[hfx+'alpha-0']+parmDict[hfx+'alpha-0']*tanPos
3186        bet = parmDict[hfx+'beta-0']+parmDict[hfx+'beta-1']*tanPos
3187        return alp,bet
3188
3189    hId = Histogram['hId']
3190    hfx = ':%d:'%(hId)
3191    bakType = calcControls[hfx+'bakType']
3192    fixedBkg = {i:Histogram['Background'][1][i] for i in Histogram['Background'][1] if i.startswith("_")} 
3193    yb,Histogram['sumBk'] = G2pwd.getBackground(hfx,parmDict,bakType,calcControls[hfx+'histType'],x,fixedBkg)
3194    yc = np.zeros_like(yb)
3195    cw = np.diff(ma.getdata(x))
3196    cw = np.append(cw,cw[-1])
3197       
3198    if 'C' in calcControls[hfx+'histType']:   
3199        shl = max(parmDict[hfx+'SH/L'],0.002)
3200        Ka2 = False
3201        if hfx+'Lam1' in (parmDict.keys()):
3202            wave = parmDict[hfx+'Lam1']
3203            Ka2 = True
3204            lamRatio = 360*(parmDict[hfx+'Lam2']-parmDict[hfx+'Lam1'])/(np.pi*parmDict[hfx+'Lam1'])
3205            kRatio = parmDict[hfx+'I(L2)/I(L1)']
3206        else:
3207            wave = parmDict[hfx+'Lam']
3208    elif 'B' in calcControls[hfx+'histType']:
3209            wave = parmDict[hfx+'Lam']
3210    else:
3211        shl = 0.
3212    for phase in Histogram['Reflection Lists']:
3213        refDict = Histogram['Reflection Lists'][phase]
3214        if phase not in Phases:     #skips deleted or renamed phases silently!
3215            continue
3216        Phase = Phases[phase]
3217        if histogram and not histogram in Phase['Histograms']:
3218            continue
3219        pId = Phase['pId']
3220        pfx = '%d::'%(pId)
3221        phfx = '%d:%d:'%(pId,hId)
3222        hfx = ':%d:'%(hId)
3223        SGData = Phase['General']['SGData']
3224        SGMT = np.array([ops[0].T for ops in SGData['SGOps']])
3225        im = 0
3226        if Phase['General'].get('Modulated',False):
3227            SSGData = Phase['General']['SSGData']
3228            im = 1  #offset in SS reflection list
3229            #??
3230        Dij = GetDij(phfx,SGData,parmDict)
3231        A = [parmDict[pfx+'A%d'%(i)]+Dij[i] for i in range(6)]  #TODO: need to do someting if Dij << 0.
3232        G,g = G2lat.A2Gmat(A)       #recip & real metric tensors
3233        if np.any(np.diag(G)<0.) or np.any(np.isnan(A)):
3234            G2obj.HowDidIgetHere()
3235            raise G2obj.G2Exception('Error in metric tensor refinement\nCheck for refinement of conflicting variables')
3236        GA,GB = G2lat.Gmat2AB(G)    #Orthogonalization matricies
3237        Vst = np.sqrt(nl.det(G))    #V*
3238        if not Phase['General'].get('doPawley') and not parmDict[phfx+'LeBail']:
3239            if im:
3240                SStructureFactor(refDict,G,hfx,pfx,SGData,SSGData,calcControls,parmDict)
3241            elif parmDict[pfx+'isMag'] and 'N' in calcControls[hfx+'histType']:
3242                MagStructureFactor2(refDict,G,hfx,pfx,SGData,calcControls,parmDict)
3243            else:
3244                StructureFactor2(refDict,G,hfx,pfx,SGData,calcControls,parmDict)
3245        badPeak = False
3246        # test to see if we are using multiprocessing here
3247        useMP,ncores = G2mp.InitMP()
3248        if len(refDict['RefList']) < 100: useMP = False       
3249        if useMP: # multiprocessing: create a set of initialized Python processes
3250            MPpool = mp.Pool(ncores,G2mp.InitPwdrProfGlobals,[im,shl,x])
3251            profArgs = [[] for i in range(ncores)]
3252        if 'C' in calcControls[hfx+'histType']:
3253            for iref,refl in enumerate(refDict['RefList']):
3254                if im:
3255                    h,k,l,m = refl[:4]
3256                else:
3257                    h,k,l = refl[:3]
3258                Uniq = np.inner(refl[:3],SGMT)
3259                refl[5+im] = GetReflPos(refl,im,wave,A,pfx,hfx,phfx,calcControls,parmDict)         #corrected reflection position
3260                Lorenz = 1./(2.*sind(refl[5+im]/2.)**2*cosd(refl[5+im]/2.))           #Lorentz correction
3261                refl[6+im:8+im] = GetReflSigGamCW(refl,im,wave,G,GB,phfx,calcControls,parmDict)    #peak sig & gam
3262                refl[11+im:15+im] = GetIntensityCorr(refl,im,Uniq,G,g,pfx,phfx,hfx,SGData,calcControls,parmDict)
3263                refl[11+im] *= Vst*Lorenz
3264                 
3265                if Phase['General'].get('doPawley'):
3266                    try:
3267                        if im:
3268                            pInd = pfx+'PWLref:%d'%(pawleyLookup[pfx+'%d,%d,%d,%d'%(h,k,l,m)])
3269                        else:
3270                            pInd = pfx+'PWLref:%d'%(pawleyLookup[pfx+'%d,%d,%d'%(h,k,l)])
3271                        refl[9+im] = parmDict[pInd]
3272                    except KeyError:
3273#                        print ' ***Error %d,%d,%d missing from Pawley reflection list ***'%(h,k,l)
3274                        continue
3275                Wd,fmin,fmax = G2pwd.getWidthsCW(refl[5+im],refl[6+im],refl[7+im],shl)
3276                iBeg = np.searchsorted(x,refl[5+im]-fmin)
3277                iFin = np.searchsorted(x,refl[5+im]+fmax)
3278                if not iBeg+iFin:       #peak below low limit - skip peak
3279                    continue
3280                elif not iBeg-iFin:     #peak above high limit - done
3281                    break
3282                elif iBeg > iFin:   #bad peak coeff - skip
3283                    badPeak = True
3284                    continue
3285                if useMP:
3286                    profArgs[iref%ncores].append((refl[5+im],refl,iBeg,iFin,1.))
3287                else:
3288                    yc[iBeg:iFin] += refl[11+im]*refl[9+im]*G2pwd.getFCJVoigt3(refl[5+im],refl[6+im],refl[7+im],shl,ma.getdata(x[iBeg:iFin]))    #>90% of time spent here
3289                if Ka2:
3290                    pos2 = refl[5+im]+lamRatio*tand(refl[5+im]/2.0)       # + 360/pi * Dlam/lam * tan(th)
3291                    Wd,fmin,fmax = G2pwd.getWidthsCW(pos2,refl[6+im],refl[7+im],shl)
3292                    iBeg = np.searchsorted(x,pos2-fmin)
3293                    iFin = np.searchsorted(x,pos2+fmax)
3294                    if not iBeg+iFin:       #peak below low limit - skip peak
3295                        continue
3296                    elif not iBeg-iFin:     #peak above high limit - done
3297                        return yc,yb
3298                    elif iBeg > iFin:   #bad peak coeff - skip
3299                        continue
3300                    if useMP:
3301                        profArgs[iref%ncores].append((pos2,refl,iBeg,iFin,kRatio))
3302                    else:
3303                        yc[iBeg:iFin] += refl[11+im]*refl[9+im]*kRatio*G2pwd.getFCJVoigt3(pos2,refl[6+im],refl[7+im],shl,ma.getdata(x[iBeg:iFin]))        #and here
3304        elif 'B' in calcControls[hfx+'histType']:
3305            for iref,refl in enumerate(refDict['RefList']):
3306                if im:
3307                    h,k,l,m = refl[:4]
3308                else:
3309                    h,k,l = refl[:3]
3310                Uniq = np.inner(refl[:3],SGMT)
3311                refl[5+im] = GetReflPos(refl,im,wave,A,pfx,hfx,phfx,calcControls,parmDict)         #corrected reflection position
3312                Lorenz = 1./(2.*sind(refl[5+im]/2.)**2*cosd(refl[5+im]/2.))           #Lorentz correction
3313                refl[6+im:8+im] = GetReflSigGamCW(refl,im,wave,G,GB,phfx,calcControls,parmDict)    #peak sig & gam
3314                refl[12+im:14+im] = GetPinkReflAlpBet(refl,im,hfx,parmDict)             #TODO - skip if alp, bet tabulated?
3315                refl[11+im],refl[14+im],refl[15+im],refl[16+im] = GetIntensityCorr(refl,im,Uniq,G,g,pfx,phfx,hfx,SGData,calcControls,parmDict)
3316                refl[11+im] *= Vst*Lorenz
3317                 
3318                if Phase['General'].get('doPawley'):
3319                    try:
3320                        if im:
3321                            pInd = pfx+'PWLref:%d'%(pawleyLookup[pfx+'%d,%d,%d,%d'%(h,k,l,m)])
3322                        else:
3323                            pInd = pfx+'PWLref:%d'%(pawleyLookup[pfx+'%d,%d,%d'%(h,k,l)])
3324                        refl[9+im] = parmDict[pInd]
3325                    except KeyError:
3326#                        print ' ***Error %d,%d,%d missing from Pawley reflection list ***'%(h,k,l)
3327                        continue
3328                Wd,fmin,fmax = G2pwd.getWidthsTOF(refl[5+im],refl[12+im],refl[13+im],refl[6+im]/1.e4,refl[7+im]/100.)
3329                iBeg