source: trunk/GSASIIstrMath.py @ 5525

Last change on this file since 5525 was 5522, checked in by vondreele, 2 years ago

more fixes to sp. harm. derivatives
change list of atoms in RB to be multi lines
patch plot for spin RBs

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Author Revision URL Id
File size: 252.2 KB
Line 
1# -*- coding: utf-8 -*-
2'''
3*GSASIIstrMath - structure math routines*
4-----------------------------------------
5'''
6########### SVN repository information ###################
7# $Date: 2023-03-24 17:34:43 +0000 (Fri, 24 Mar 2023) $
8# $Author: toby $
9# $Revision: 5522 $
10# $URL: trunk/GSASIIstrMath.py $
11# $Id: GSASIIstrMath.py 5522 2023-03-24 17:34:43Z 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 scipy.special as sp
21import multiprocessing as mp
22import pickle
23import GSASIIpath
24GSASIIpath.SetVersionNumber("$Revision: 5522 $")
25import GSASIIElem as G2el
26import GSASIIlattice as G2lat
27import GSASIIspc as G2spc
28import GSASIIpwd as G2pwd
29import GSASIImapvars as G2mv
30import GSASIImath as G2mth
31import GSASIIobj as G2obj
32import GSASIImpsubs as G2mp
33#G2mp.InitMP(False)  # This disables multiprocessing
34
35sind = lambda x: np.sin(x*np.pi/180.)
36cosd = lambda x: np.cos(x*np.pi/180.)
37tand = lambda x: np.tan(x*np.pi/180.)
38asind = lambda x: 180.*np.arcsin(x)/np.pi
39acosd = lambda x: 180.*np.arccos(x)/np.pi
40atan2d = lambda y,x: 180.*np.arctan2(y,x)/np.pi
41   
42try:  # fails on doc build
43    ateln2 = 8.0*np.log(2.0)
44    twopi = 2.0*np.pi
45    twopisq = 2.0*np.pi**2
46except TypeError:
47    pass
48nxs = np.newaxis
49
50################################################################################
51##### Rigid Body Models
52################################################################################
53       
54def ApplyRBModels(parmDict,Phases,rigidbodyDict,Update=False):
55    ''' Takes RB info from RBModels in Phase and RB data in rigidbodyDict along with
56    current RB values in parmDict & modifies atom contents (fxyz & Uij) of parmDict
57    '''
58    atxIds = ['Ax:','Ay:','Az:']
59    atuIds = ['AU11:','AU22:','AU33:','AU12:','AU13:','AU23:']
60    RBIds = rigidbodyDict.get('RBIds',{'Vector':[],'Residue':[],'Spin':[]})  #these are lists of rbIds
61    RBIds['Spin'] = RBIds.get('Spin',[])        #patch
62    if not RBIds['Vector'] and not RBIds['Residue'] and not RBIds['Spin']:
63        return
64    VRBIds = RBIds['Vector']
65    RRBIds = RBIds['Residue']
66    SRBIds = RBIds['Spin']
67    if Update:
68        RBData = rigidbodyDict
69    else:
70        RBData = copy.deepcopy(rigidbodyDict)     # don't mess with original!
71    if RBIds['Vector']:                       # first update the vector magnitudes
72        VRBData = RBData['Vector']
73        for i,rbId in enumerate(VRBIds):
74            if VRBData[rbId]['useCount']:
75                for j in range(len(VRBData[rbId]['VectMag'])):
76                    name = '::RBV;'+str(j)+':'+str(i)
77                    VRBData[rbId]['VectMag'][j] = parmDict[name]
78       
79    for phase in Phases:
80        Phase = Phases[phase]
81        General = Phase['General']
82        cx,ct,cs,cia = General['AtomPtrs']
83        cell = General['Cell'][1:7]
84        Amat,Bmat = G2lat.cell2AB(cell)
85        AtLookup = G2mth.FillAtomLookUp(Phase['Atoms'],cia+8)
86        pfx = str(Phase['pId'])+'::'
87        if Update:
88            RBModels = Phase['RBModels']
89        else:
90            RBModels =  copy.deepcopy(Phase['RBModels']) # again don't mess with original!
91        for irb,RBObj in enumerate(RBModels.get('Vector',[])):
92            jrb = VRBIds.index(RBObj['RBId'])
93            rbsx = str(irb)+':'+str(jrb)
94            for i,px in enumerate(['RBVPx:','RBVPy:','RBVPz:']):
95                RBObj['Orig'][0][i] = parmDict[pfx+px+rbsx]
96            for i,po in enumerate(['RBVOa:','RBVOi:','RBVOj:','RBVOk:']):
97                RBObj['Orient'][0][i] = parmDict[pfx+po+rbsx]
98            RBObj['Orient'][0] = G2mth.normQ(RBObj['Orient'][0])
99            RBObj['AtomFrac'][0] = parmDict[pfx+'RBVf:'+rbsx]
100            TLS = RBObj['ThermalMotion']
101            if 'T' in TLS[0]:
102                for i,pt in enumerate(['RBVT11:','RBVT22:','RBVT33:','RBVT12:','RBVT13:','RBVT23:']):
103                    TLS[1][i] = parmDict[pfx+pt+rbsx]
104            if 'L' in TLS[0]:
105                for i,pt in enumerate(['RBVL11:','RBVL22:','RBVL33:','RBVL12:','RBVL13:','RBVL23:']):
106                    TLS[1][i+6] = parmDict[pfx+pt+rbsx]
107            if 'S' in TLS[0]:
108                for i,pt in enumerate(['RBVS12:','RBVS13:','RBVS21:','RBVS23:','RBVS31:','RBVS32:','RBVSAA:','RBVSBB:']):
109                    TLS[1][i+12] = parmDict[pfx+pt+rbsx]
110            if 'U' in TLS[0]:
111                TLS[1][0] = parmDict[pfx+'RBVU:'+rbsx]
112            XYZ,Cart = G2mth.UpdateRBXYZ(Bmat,RBObj,RBData,'Vector')
113            UIJ = G2mth.UpdateRBUIJ(Bmat,Cart,RBObj)
114            for i,x in enumerate(XYZ):
115                atId = RBObj['Ids'][i]
116                if parmDict[pfx+'Afrac:'+str(AtLookup[atId])]:
117                    parmDict[pfx+'Afrac:'+str(AtLookup[atId])] = RBObj['AtomFrac'][0]
118                for j in [0,1,2]:
119                    parmDict[pfx+atxIds[j]+str(AtLookup[atId])] = x[j]
120                if UIJ[i][0] == 'A':
121                    for j in range(6):
122                        parmDict[pfx+atuIds[j]+str(AtLookup[atId])] = UIJ[i][j+2]
123                elif UIJ[i][0] == 'I':
124                    parmDict[pfx+'AUiso:'+str(AtLookup[atId])] = UIJ[i][1]
125           
126        for irb,RBObj in enumerate(RBModels.get('Residue',[])):
127            jrb = RRBIds.index(RBObj['RBId'])
128            rbsx = str(irb)+':'+str(jrb)
129            for i,px in enumerate(['RBRPx:','RBRPy:','RBRPz:']):
130                RBObj['Orig'][0][i] = parmDict[pfx+px+rbsx]
131            for i,po in enumerate(['RBROa:','RBROi:','RBROj:','RBROk:']):
132                RBObj['Orient'][0][i] = parmDict[pfx+po+rbsx]               
133            RBObj['Orient'][0] = G2mth.normQ(RBObj['Orient'][0])
134            RBObj['AtomFrac'][0] = parmDict[pfx+'RBRf:'+rbsx]
135            TLS = RBObj['ThermalMotion']
136            if 'T' in TLS[0]:
137                for i,pt in enumerate(['RBRT11:','RBRT22:','RBRT33:','RBRT12:','RBRT13:','RBRT23:']):
138                    RBObj['ThermalMotion'][1][i] = parmDict[pfx+pt+rbsx]
139            if 'L' in TLS[0]:
140                for i,pt in enumerate(['RBRL11:','RBRL22:','RBRL33:','RBRL12:','RBRL13:','RBRL23:']):
141                    RBObj['ThermalMotion'][1][i+6] = parmDict[pfx+pt+rbsx]
142            if 'S' in TLS[0]:
143                for i,pt in enumerate(['RBRS12:','RBRS13:','RBRS21:','RBRS23:','RBRS31:','RBRS32:','RBRSAA:','RBRSBB:']):
144                    RBObj['ThermalMotion'][1][i+12] = parmDict[pfx+pt+rbsx]
145            if 'U' in TLS[0]:
146                RBObj['ThermalMotion'][1][0] = parmDict[pfx+'RBRU:'+rbsx]
147            for itors,tors in enumerate(RBObj['Torsions']):
148                tors[0] = parmDict[pfx+'RBRTr;'+str(itors)+':'+rbsx]
149            XYZ,Cart = G2mth.UpdateRBXYZ(Bmat,RBObj,RBData,'Residue')
150            UIJ = G2mth.UpdateRBUIJ(Bmat,Cart,RBObj)
151            for i,x in enumerate(XYZ):
152                atId = RBObj['Ids'][i]
153                if parmDict[pfx+'Afrac:'+str(AtLookup[atId])]:
154                    parmDict[pfx+'Afrac:'+str(AtLookup[atId])] = RBObj['AtomFrac'][0]
155                for j in [0,1,2]:
156                    parmDict[pfx+atxIds[j]+str(AtLookup[atId])] = x[j]
157                if UIJ[i][0] == 'A':
158                    for j in range(6):
159                        parmDict[pfx+atuIds[j]+str(AtLookup[atId])] = UIJ[i][j+2]
160                elif UIJ[i][0] == 'I':
161                    parmDict[pfx+'AUiso:'+str(AtLookup[atId])] = UIJ[i][1]
162                   
163        for irb,RBObj in enumerate(RBModels.get('Spin',[])):
164            iAt = AtLookup[RBObj['Ids'][0]]
165            jrb = SRBIds.index(RBObj['RBId'][0])
166            name = pfx+'RBSOa:%d:%d'%(iAt,jrb)
167            for i,po in enumerate(['RBSOa:','RBSOi:','RBSOj:','RBSOk:']):
168                name = pfx+'%s%d:%d'%(po,iAt,jrb)
169                RBObj['Orient'][0][i] = parmDict[name]               
170            for ish in range(len(RBObj['RBId'])):
171                jrb = SRBIds.index(RBObj['RBId'][ish])
172                for item in RBObj['SHC'][ish]:
173                    name = pfx+'RBSSh;%d;%s:%d:%d'%(ish,item,iAt,jrb)
174                    RBObj['SHC'][ish][item][0] = parmDict[name]
175                   
176def ApplyRBModelDervs(dFdvDict,parmDict,rigidbodyDict,Phase):
177    'Computes rigid body derivatives'
178    atxIds = ['dAx:','dAy:','dAz:']
179    atuIds = ['AU11:','AU22:','AU33:','AU12:','AU13:','AU23:']
180    OIds = ['Oa:','Oi:','Oj:','Ok:']
181    RBIds = rigidbodyDict.get('RBIds',{'Vector':[],'Residue':[],'spin':[]})  #these are lists of rbIds
182    if not RBIds['Vector'] and not RBIds['Residue'] and not RBIds['Spin']:
183        return
184    VRBIds = RBIds['Vector']
185    RRBIds = RBIds['Residue']
186    RBData = rigidbodyDict
187    for item in parmDict:
188        if 'RBV' in item or 'RBR' in item:
189            dFdvDict[item] = 0.        #NB: this is a vector which is no. refl. long & must be filled!
190    General = Phase['General']
191    cx,ct,cs,cia = General['AtomPtrs']
192    cell = General['Cell'][1:7]
193    Amat,Bmat = G2lat.cell2AB(cell)
194    rpd = np.pi/180.
195    rpd2 = rpd**2
196    g = nl.inv(np.inner(Bmat,Bmat))
197    gvec = np.sqrt(np.array([g[0][0]**2,g[1][1]**2,g[2][2]**2,
198        g[0][0]*g[1][1],g[0][0]*g[2][2],g[1][1]*g[2][2]]))
199    AtLookup = G2mth.FillAtomLookUp(Phase['Atoms'],cia+8)
200    pfx = str(Phase['pId'])+'::'
201    RBModels =  Phase['RBModels']
202   
203    # for irb,RBObj in enumerate(RBModels.get('Spin',[])):
204    #     name = '::RBS;0:%d'%irb
205    #     if name in dFdvDict:
206    #         dFdvDict[name] += dFdvDict[pfx+'RBS;0:%d'%irb]
207    #     else:           
208    #         dFdvDict[name] = dFdvDict[pfx+'RBS;0:%d'%irb]
209                   
210    for irb,RBObj in enumerate(RBModels.get('Vector',[])):
211        symAxis = RBObj.get('symAxis')
212        VModel = RBData['Vector'][RBObj['RBId']]
213        Q = RBObj['Orient'][0]
214        jrb = VRBIds.index(RBObj['RBId'])
215        rbsx = str(irb)+':'+str(jrb)
216        dXdv = []
217        for iv in range(len(VModel['VectMag'])):
218            dCdv = []
219            for vec in VModel['rbVect'][iv]:
220                dCdv.append(G2mth.prodQVQ(Q,vec))
221            dXdv.append(np.inner(Bmat,np.array(dCdv)).T)
222        XYZ,Cart = G2mth.UpdateRBXYZ(Bmat,RBObj,RBData,'Vector')
223        for ia,atId in enumerate(RBObj['Ids']):
224            atNum = AtLookup[atId]
225            if parmDict[pfx+'Afrac:'+str(AtLookup[atId])]:
226                dFdvDict[pfx+'RBVf:'+rbsx] += dFdvDict[pfx+'Afrac:'+str(atNum)]
227            dx = 0.00001
228            for iv in range(len(VModel['VectMag'])):
229                for ix in [0,1,2]:
230                    dFdvDict['::RBV;'+str(iv)+':'+str(jrb)] += dXdv[iv][ia][ix]*dFdvDict[pfx+atxIds[ix]+str(atNum)]
231            for i,name in enumerate(['RBVPx:','RBVPy:','RBVPz:']):
232                dFdvDict[pfx+name+rbsx] += dFdvDict[pfx+atxIds[i]+str(atNum)]
233            for iv in range(4):
234                Q[iv] -= dx
235                XYZ1 = G2mth.RotateRBXYZ(Bmat,Cart,G2mth.normQ(Q),symAxis)
236                Q[iv] += 2.*dx
237                XYZ2 = G2mth.RotateRBXYZ(Bmat,Cart,G2mth.normQ(Q),symAxis)
238                Q[iv] -= dx
239                dXdO = (XYZ2[ia]-XYZ1[ia])/(2.*dx)
240                for ix in [0,1,2]:
241                    dFdvDict[pfx+'RBV'+OIds[iv]+rbsx] += dXdO[ix]*dFdvDict[pfx+atxIds[ix]+str(atNum)]
242            X = G2mth.prodQVQ(Q,Cart[ia])
243            dFdu = np.array([dFdvDict[pfx+Uid+str(AtLookup[atId])] for Uid in atuIds]).T/gvec
244            dFdu = G2lat.U6toUij(dFdu.T)
245            dFdu = np.tensordot(Amat,np.tensordot(Amat,dFdu,([1,0])),([0,1]))           
246            dFdu = G2lat.UijtoU6(dFdu)
247            atNum = AtLookup[atId]
248            if 'T' in RBObj['ThermalMotion'][0]:
249                for i,name in enumerate(['RBVT11:','RBVT22:','RBVT33:','RBVT12:','RBVT13:','RBVT23:']):
250                    dFdvDict[pfx+name+rbsx] += dFdu[i]
251            if 'L' in RBObj['ThermalMotion'][0]:
252                dFdvDict[pfx+'RBVL11:'+rbsx] += rpd2*(dFdu[1]*X[2]**2+dFdu[2]*X[1]**2-dFdu[5]*X[1]*X[2])
253                dFdvDict[pfx+'RBVL22:'+rbsx] += rpd2*(dFdu[0]*X[2]**2+dFdu[2]*X[0]**2-dFdu[4]*X[0]*X[2])
254                dFdvDict[pfx+'RBVL33:'+rbsx] += rpd2*(dFdu[0]*X[1]**2+dFdu[1]*X[0]**2-dFdu[3]*X[0]*X[1])
255                dFdvDict[pfx+'RBVL12:'+rbsx] += rpd2*(-dFdu[3]*X[2]**2-2.*dFdu[2]*X[0]*X[1]+
256                    dFdu[4]*X[1]*X[2]+dFdu[5]*X[0]*X[2])
257                dFdvDict[pfx+'RBVL13:'+rbsx] += rpd2*(-dFdu[4]*X[1]**2-2.*dFdu[1]*X[0]*X[2]+
258                    dFdu[3]*X[1]*X[2]+dFdu[5]*X[0]*X[1])
259                dFdvDict[pfx+'RBVL23:'+rbsx] += rpd2*(-dFdu[5]*X[0]**2-2.*dFdu[0]*X[1]*X[2]+
260                    dFdu[3]*X[0]*X[2]+dFdu[4]*X[0]*X[1])
261            if 'S' in RBObj['ThermalMotion'][0]:
262                dFdvDict[pfx+'RBVS12:'+rbsx] += rpd*(dFdu[5]*X[1]-2.*dFdu[1]*X[2])
263                dFdvDict[pfx+'RBVS13:'+rbsx] += rpd*(-dFdu[5]*X[2]+2.*dFdu[2]*X[1])
264                dFdvDict[pfx+'RBVS21:'+rbsx] += rpd*(-dFdu[4]*X[0]+2.*dFdu[0]*X[2])
265                dFdvDict[pfx+'RBVS23:'+rbsx] += rpd*(dFdu[4]*X[2]-2.*dFdu[2]*X[0])
266                dFdvDict[pfx+'RBVS31:'+rbsx] += rpd*(dFdu[3]*X[0]-2.*dFdu[0]*X[1])
267                dFdvDict[pfx+'RBVS32:'+rbsx] += rpd*(-dFdu[3]*X[1]+2.*dFdu[1]*X[0])
268                dFdvDict[pfx+'RBVSAA:'+rbsx] += rpd*(dFdu[4]*X[1]-dFdu[3]*X[2])
269                dFdvDict[pfx+'RBVSBB:'+rbsx] += rpd*(dFdu[5]*X[0]-dFdu[3]*X[2])
270            if 'U' in RBObj['ThermalMotion'][0]:
271                dFdvDict[pfx+'RBVU:'+rbsx] += dFdvDict[pfx+'AUiso:'+str(AtLookup[atId])]
272
273    for irb,RBObj in enumerate(RBModels.get('Residue',[])):
274        symAxis = RBObj.get('symAxis')
275        Q = RBObj['Orient'][0]
276        jrb = RRBIds.index(RBObj['RBId'])
277        torData = RBData['Residue'][RBObj['RBId']]['rbSeq']
278        rbsx = str(irb)+':'+str(jrb)
279        XYZ,Cart = G2mth.UpdateRBXYZ(Bmat,RBObj,RBData,'Residue')
280        for itors,tors in enumerate(RBObj['Torsions']):     #derivative error?
281            tname = pfx+'RBRTr;'+str(itors)+':'+rbsx           
282            orId,pvId = torData[itors][:2]
283            pivotVec = Cart[orId]-Cart[pvId]
284            QA = G2mth.AVdeg2Q(-0.001,pivotVec)
285            QB = G2mth.AVdeg2Q(0.001,pivotVec)
286            for ir in torData[itors][3]:
287                atNum = AtLookup[RBObj['Ids'][ir]]
288                rVec = Cart[ir]-Cart[pvId]
289                dR = G2mth.prodQVQ(QB,rVec)-G2mth.prodQVQ(QA,rVec)
290                dRdT = np.inner(Bmat,G2mth.prodQVQ(Q,dR))/.002
291                for ix in [0,1,2]:
292                    dFdvDict[tname] += dRdT[ix]*dFdvDict[pfx+atxIds[ix]+str(atNum)]
293        for ia,atId in enumerate(RBObj['Ids']):
294            atNum = AtLookup[atId]
295            if parmDict[pfx+'Afrac:'+str(AtLookup[atId])]:
296                dFdvDict[pfx+'RBRf:'+rbsx] += dFdvDict[pfx+'Afrac:'+str(atNum)]
297            dx = 0.00001
298            for i,name in enumerate(['RBRPx:','RBRPy:','RBRPz:']):
299                dFdvDict[pfx+name+rbsx] += dFdvDict[pfx+atxIds[i]+str(atNum)]
300            for iv in range(4):
301                Q[iv] -= dx
302                XYZ1 = G2mth.RotateRBXYZ(Bmat,Cart,G2mth.normQ(Q),symAxis)
303                Q[iv] += 2.*dx
304                XYZ2 = G2mth.RotateRBXYZ(Bmat,Cart,G2mth.normQ(Q),symAxis)
305                Q[iv] -= dx
306                dXdO = (XYZ2[ia]-XYZ1[ia])/(2.*dx)
307                for ix in [0,1,2]:
308                    dFdvDict[pfx+'RBR'+OIds[iv]+rbsx] += dXdO[ix]*dFdvDict[pfx+atxIds[ix]+str(atNum)]
309            X = G2mth.prodQVQ(Q,Cart[ia])
310            dFdu = np.array([dFdvDict[pfx+Uid+str(AtLookup[atId])] for Uid in atuIds]).T/gvec
311            dFdu = G2lat.U6toUij(dFdu.T)
312            dFdu = np.tensordot(Amat.T,np.tensordot(Amat,dFdu,([1,0])),([0,1]))
313            dFdu = G2lat.UijtoU6(dFdu)
314            atNum = AtLookup[atId]
315            if 'T' in RBObj['ThermalMotion'][0]:
316                for i,name in enumerate(['RBRT11:','RBRT22:','RBRT33:','RBRT12:','RBRT13:','RBRT23:']):
317                    dFdvDict[pfx+name+rbsx] += dFdu[i]
318            if 'L' in RBObj['ThermalMotion'][0]:
319                dFdvDict[pfx+'RBRL11:'+rbsx] += rpd2*(dFdu[1]*X[2]**2+dFdu[2]*X[1]**2-dFdu[5]*X[1]*X[2])
320                dFdvDict[pfx+'RBRL22:'+rbsx] += rpd2*(dFdu[0]*X[2]**2+dFdu[2]*X[0]**2-dFdu[4]*X[0]*X[2])
321                dFdvDict[pfx+'RBRL33:'+rbsx] += rpd2*(dFdu[0]*X[1]**2+dFdu[1]*X[0]**2-dFdu[3]*X[0]*X[1])
322                dFdvDict[pfx+'RBRL12:'+rbsx] += rpd2*(-dFdu[3]*X[2]**2-2.*dFdu[2]*X[0]*X[1]+
323                    dFdu[4]*X[1]*X[2]+dFdu[5]*X[0]*X[2])
324                dFdvDict[pfx+'RBRL13:'+rbsx] += rpd2*(dFdu[4]*X[1]**2-2.*dFdu[1]*X[0]*X[2]+
325                    dFdu[3]*X[1]*X[2]+dFdu[5]*X[0]*X[1])
326                dFdvDict[pfx+'RBRL23:'+rbsx] += rpd2*(dFdu[5]*X[0]**2-2.*dFdu[0]*X[1]*X[2]+
327                    dFdu[3]*X[0]*X[2]+dFdu[4]*X[0]*X[1])
328            if 'S' in RBObj['ThermalMotion'][0]:
329                dFdvDict[pfx+'RBRS12:'+rbsx] += rpd*(dFdu[5]*X[1]-2.*dFdu[1]*X[2])
330                dFdvDict[pfx+'RBRS13:'+rbsx] += rpd*(-dFdu[5]*X[2]+2.*dFdu[2]*X[1])
331                dFdvDict[pfx+'RBRS21:'+rbsx] += rpd*(-dFdu[4]*X[0]+2.*dFdu[0]*X[2])
332                dFdvDict[pfx+'RBRS23:'+rbsx] += rpd*(dFdu[4]*X[2]-2.*dFdu[2]*X[0])
333                dFdvDict[pfx+'RBRS31:'+rbsx] += rpd*(dFdu[3]*X[0]-2.*dFdu[0]*X[1])
334                dFdvDict[pfx+'RBRS32:'+rbsx] += rpd*(-dFdu[3]*X[1]+2.*dFdu[1]*X[0])
335                dFdvDict[pfx+'RBRSAA:'+rbsx] += rpd*(dFdu[4]*X[1]-dFdu[3]*X[2])
336                dFdvDict[pfx+'RBRSBB:'+rbsx] += rpd*(dFdu[5]*X[0]-dFdu[3]*X[2])
337            if 'U' in RBObj['ThermalMotion'][0]:
338                dFdvDict[pfx+'RBRU:'+rbsx] += dFdvDict[pfx+'AUiso:'+str(AtLookup[atId])]
339               
340def MakeSpHarmFF(HKL,Bmat,SHCdict,Tdata,hType,FFtables,BLtables,FF,SQ,ifDeriv=False):
341    ''' Computes hkl dependent form factors & derivatives from spinning rigid bodies
342    :param array HKL: reflection hkl set to be considered
343    :param array Bmat: inv crystal to Cartesian transfomation matrix
344    :param dict SHCdict: spin RB data
345    :param array Tdata: atom type info
346    :param str hType: histogram type
347    :param dict FFtables: x-ray form factor tables
348    :param dict BLtables: neutron scattering lenghts
349    :param array FF: form factors - will be modified by adding the spin RB spherical harmonics terms
350    :param array SQ: 1/4d^2 for the HKL set
351    :param bool ifDeriv: True if dFF/dR, dFF/dA, & dFF/dShC to be returned
352   
353    :returns: dict dFFdS of derivatives if ifDeriv = True
354    '''
355   
356    def MakePolar(Orient,QB):
357        QA = G2mth.invQ(Orient)       #rotates about chosen axis
358        Q = G2mth.prodQQ(QA,QB)     #might be switched? QB,QA is order for plotting
359        return G2lat.H2ThPh(np.reshape(HKL,(-1,3)),Bmat,Q)
360       
361    dFFdS = {}
362    atFlg = []
363    for iAt,Atype in enumerate(Tdata):
364        if 'Q' in Atype:
365            atFlg.append(1.0)
366            SHdat = SHCdict[iAt]
367            symAxis = np.array(SHdat['symAxis'])
368            QB = G2mth.make2Quat(np.array([0,0,1.]),symAxis)[0]     #position obj polar axis
369            Th,Ph = MakePolar([SHdat['Oa'],SHdat['Oi'],SHdat['Oj'],SHdat['Ok']],QB)
370            ThP,PhP = MakePolar([SHdat['Oa']+.0001,SHdat['Oi'],SHdat['Oj'],SHdat['Ok']],QB)
371            dp = 0.00001
372            ThPi,PhPi = MakePolar([SHdat['Oa'],SHdat['Oi']+dp,SHdat['Oj'],SHdat['Ok']],QB)
373            ThPj,PhPj = MakePolar([SHdat['Oa'],SHdat['Oi'],SHdat['Oj']+dp,SHdat['Ok']],QB)
374            ThPk,PhPk = MakePolar([SHdat['Oa'],SHdat['Oi'],SHdat['Oj'],SHdat['Ok']+dp],QB)
375            ThM,PhM = MakePolar([SHdat['Oa']-.0001,SHdat['Oi'],SHdat['Oj'],SHdat['Ok']],QB)
376            ThMi,PhMi = MakePolar([SHdat['Oa'],SHdat['Oi']-dp,SHdat['Oj'],SHdat['Ok']],QB)
377            ThMj,PhMj = MakePolar([SHdat['Oa'],SHdat['Oi'],SHdat['Oj']-dp,SHdat['Ok']],QB)
378            ThMk,PhMk = MakePolar([SHdat['Oa'],SHdat['Oi'],SHdat['Oj'],SHdat['Ok']-dp],QB)
379            QR = np.repeat(twopi*np.sqrt(4.*SQ),HKL.shape[1])     #refl Q for Bessel fxn
380            SQR = np.repeat(SQ,HKL.shape[1])
381            FF[:,iAt] = 0.
382            ishl = 0
383#            dBSdR = np.zeros(HKL.shape[0]*HKL.shape[1])
384            dSHdO = np.zeros(HKL.shape[0]*HKL.shape[1])
385            dSHdOi = np.zeros(HKL.shape[0]*HKL.shape[1])
386            dSHdOj = np.zeros(HKL.shape[0]*HKL.shape[1])
387            dSHdOk = np.zeros(HKL.shape[0]*HKL.shape[1])
388            if '0' not in SHdat:    #no spin RB for atom Q??
389                break
390            Shell = SHdat['0']
391            Irb = Shell['ShR']
392            Oname = 'Oa:%d:%s'%(iAt,Irb)
393            Oiname = 'Oi:%d:%s'%(iAt,Irb)
394            Ojname = 'Oj:%d:%s'%(iAt,Irb)
395            Okname = 'Ok:%d:%s'%(iAt,Irb)
396            while True:
397                shl = '%d'%ishl
398                if shl not in SHdat:
399                    break
400                Shell = SHdat[shl]
401                R = Shell['Radius']
402                Atm = Shell['AtType']
403                Nat = Shell['Natoms']
404                Irb = Shell['ShR']
405                if 'X' in hType:
406                    SFF = G2el.ScatFac(FFtables[Atm],SQR)
407                    dat = G2el.getBLvalues(BLtables)
408                elif 'N' in hType:
409                    dat = G2el.getBLvalues(BLtables)
410                    SFF = dat[Atm]
411                Rname = 'Sh;%s;Radius:%d:%s'%(shl,iAt,Irb)
412                R0 = sp.spherical_jn(0,QR*R)/(4.*np.pi)
413                R0P = sp.spherical_jn(0,QR*(R+0.01))/(4.*np.pi)
414                R0M = sp.spherical_jn(0,QR*(R-0.01))/(4.*np.pi)
415                dBSdR = Nat*SFF*(R0P-R0M)/0.02
416                FF[:,iAt] += Nat*SFF*R0    #Bessel function; L=0 term
417                for item in Shell:
418                    if 'C(' in item:
419                        l,m = eval(item.strip('C').strip('c'))
420                        SH = G2lat.KslCalc(item,Th,Ph)
421                        SHP = G2lat.KslCalc(item,ThP,PhP)
422                        SHPi = G2lat.KslCalc(item,ThPi,PhPi)
423                        SHPj = G2lat.KslCalc(item,ThPj,PhPj)
424                        SHPk = G2lat.KslCalc(item,ThPk,PhPk)
425                        SHM = G2lat.KslCalc(item,ThM,PhM)
426                        SHMi = G2lat.KslCalc(item,ThMi,PhMi)
427                        SHMj = G2lat.KslCalc(item,ThMj,PhMj)
428                        SHMk = G2lat.KslCalc(item,ThMk,PhMk)
429                        BS = 1.0
430                        if R > 0.:
431                            BS = sp.spherical_jn(l,QR*R)    #Bessel function
432                            BSP = sp.spherical_jn(l,QR*(R+0.01))
433                            BSM = sp.spherical_jn(l,QR*(R-0.01))
434                            dBSdR += Nat*SFF*SH*Shell[item]*(BSP-BSM)/0.02
435                        dSHdO += Nat*SFF*BS*Shell[item]*(SHP-SHM)/0.0002
436                        dSHdOi += Nat*SFF*BS*Shell[item]*(SHPi-SHMi)/(2.*dp)
437                        dSHdOj += Nat*SFF*BS*Shell[item]*(SHPj-SHMj)/(2.*dp)
438                        dSHdOk += Nat*SFF*BS*Shell[item]*(SHPk-SHMk)/(2.*dp)
439                        FF[:,iAt] += Nat*SFF*BS*SH*Shell[item]
440                        name = 'Sh;%s;%s:%d:%s'%(shl,item,iAt,Irb)
441                        dFFdS[name] = Nat*SFF*BS*SH
442                dFFdS[Rname] = dBSdR
443                ishl += 1
444            dFFdS[Oname] = dSHdO
445            dFFdS[Oiname] = dSHdOi
446            dFFdS[Ojname] = dSHdOj
447            dFFdS[Okname] = dSHdOk
448        else:
449            atFlg.append(0.)
450    if ifDeriv:
451        return dFFdS,atFlg   
452           
453def GetSHC(pfx,parmDict):
454    SHCdict = {}
455    for parm in parmDict:
456        if pfx+'RBS' in parm and 'RBS;' not in parm:    #skips radii parms
457            items = parm.split(':')
458            atid = int(items[-2])
459            name = items[2][3:]    #strip 'RBS'
460            if atid not in SHCdict:
461                SHCdict[atid] = {}
462            if ';' not in name:     # will get Oa, Oi ,Oj, Ok
463                if name not in ['AtNo','Px','Py','Pz','SytSym']:
464                    SHCdict[atid][name] = parmDict[parm]
465                continue
466            bits = name.split(';')
467            shno = bits[1]
468            if shno not in SHCdict[atid]:
469                SHCdict[atid][shno] = {}
470            if 'AtType' in bits[0] or 'Natoms' in bits[0] or 'ShR' in bits[0]:
471                SHCdict[atid][shno][bits[0]] = parmDict[parm]
472            elif 'Sh' in name:
473                cof = bits[2]
474                SHCdict[atid][shno][cof] = parmDict[parm]
475    return SHCdict
476   
477################################################################################
478##### Penalty & restraint functions
479################################################################################
480
481def penaltyFxn(HistoPhases,calcControls,parmDict,varyList):
482    'Compute user-supplied and built-in restraint functions'
483    Histograms,Phases,restraintDict,rigidbodyDict = HistoPhases
484    pNames = []
485    pVals = []
486    pWt = []
487    negWt = {}
488    pWsum = {}
489    pWnum = {}
490    for phase in Phases:
491        pId = Phases[phase]['pId']
492        negWt[pId] = Phases[phase]['General']['Pawley neg wt']
493        General = Phases[phase]['General']
494        cx,ct,cs,cia = General['AtomPtrs']
495        textureData = General['SH Texture']
496        SGData = General['SGData']
497        Atoms = Phases[phase]['Atoms']
498        AtLookup = G2mth.FillAtomLookUp(Phases[phase]['Atoms'],cia+8)
499        cell = General['Cell'][1:7]
500        Amat,Bmat = G2lat.cell2AB(cell)
501        if phase not in restraintDict:
502            continue
503        phaseRest = restraintDict[phase]
504        names = [['Bond','Bonds'],['Angle','Angles'],['Plane','Planes'],
505            ['Chiral','Volumes'],['Torsion','Torsions'],['Rama','Ramas'],
506            ['ChemComp','Sites'],['Texture','HKLs'],['General','General'],]
507        for name,rest in names:
508            pWsum[name] = 0.
509            pWnum[name] = 0
510            if name not in phaseRest:
511                continue
512            itemRest = phaseRest[name]
513            if itemRest[rest] and itemRest['Use']:
514                wt = itemRest.get('wtFactor',1.)
515                if name in ['Bond','Angle','Plane','Chiral']:
516                    for i,[indx,ops,obs,esd] in enumerate(itemRest[rest]):
517                        pNames.append(str(pId)+':'+name+':'+str(i))
518                        XYZ = np.array(G2mth.GetAtomCoordsByID(pId,parmDict,AtLookup,indx))
519                        XYZ = G2mth.getSyXYZ(XYZ,ops,SGData)
520                        if name == 'Bond':
521                            calc = G2mth.getRestDist(XYZ,Amat)
522                        elif name == 'Angle':
523                            calc = G2mth.getRestAngle(XYZ,Amat)
524                        elif name == 'Plane':
525                            calc = G2mth.getRestPlane(XYZ,Amat)
526                        elif name == 'Chiral':
527                            calc = G2mth.getRestChiral(XYZ,Amat)
528                        pVals.append(obs-calc)
529                        pWt.append(wt/esd**2)
530                        pWsum[name] += wt*((obs-calc)/esd)**2
531                        pWnum[name] += 1
532                elif name in ['Torsion','Rama']:
533                    coeffDict = itemRest['Coeff']
534                    for i,[indx,ops,cofName,esd] in enumerate(itemRest[rest]):
535                        pNames.append(str(pId)+':'+name+':'+str(i))
536                        XYZ = np.array(G2mth.GetAtomCoordsByID(pId,parmDict,AtLookup,indx))
537                        XYZ = G2mth.getSyXYZ(XYZ,ops,SGData)
538                        if name == 'Torsion':
539                            tor = G2mth.getRestTorsion(XYZ,Amat)
540                            restr,calc = G2mth.calcTorsionEnergy(tor,coeffDict[cofName])
541                        else:
542                            phi,psi = G2mth.getRestRama(XYZ,Amat)
543                            restr,calc = G2mth.calcRamaEnergy(phi,psi,coeffDict[cofName])                               
544                        pVals.append(restr)
545                        pWt.append(wt/esd**2)
546                        pWsum[name] += wt*(restr/esd)**2
547                        pWnum[name] += 1
548                elif name == 'ChemComp':
549                    for i,[indx,factors,obs,esd] in enumerate(itemRest[rest]):
550                        pNames.append(str(pId)+':'+name+':'+str(i))
551                        mul = np.array(G2mth.GetAtomItemsById(Atoms,AtLookup,indx,cs+1))
552                        frac = np.array(G2mth.GetAtomFracByID(pId,parmDict,AtLookup,indx))
553                        calc = np.sum(mul*frac*factors)
554                        pVals.append(obs-calc)
555                        pWt.append(wt/esd**2)                   
556                        pWsum[name] += wt*((obs-calc)/esd)**2
557                        pWnum[name] += 1
558                elif name == 'Texture':
559                    SHkeys = list(textureData['SH Coeff'][1].keys())
560                    SHCoef = G2mth.GetSHCoeff(pId,parmDict,SHkeys)
561                    shModels = ['cylindrical','none','shear - 2/m','rolling - mmm']
562                    SamSym = dict(zip(shModels,['0','-1','2/m','mmm']))
563                    for i,[hkl,grid,esd1,ifesd2,esd2] in enumerate(itemRest[rest]):
564                        PH = np.array(hkl)
565                        phi,beta = G2lat.CrsAng(np.array(hkl),cell,SGData)
566                        ODFln = G2lat.Flnh(SHCoef,phi,beta,SGData)
567                        R,P,Z = G2mth.getRestPolefig(ODFln,SamSym[textureData['Model']],grid)
568                        Z1 = ma.masked_greater(Z,0.0)           #is this + or -?
569                        IndZ1 = np.array(ma.nonzero(Z1))
570                        for ind in IndZ1.T:
571                            pNames.append('%d:%s:%d:%.2f:%.2f'%(pId,name,i,R[ind[0],ind[1]],P[ind[0],ind[1]]))
572                            pVals.append(Z1[ind[0]][ind[1]])
573                            pWt.append(wt/esd1**2)
574                            pWsum[name] += wt*(-Z1[ind[0]][ind[1]]/esd1)**2
575                            pWnum[name] += 1
576                        if ifesd2:
577                            Z2 = 1.-Z
578                            for ind in np.ndindex(grid,grid):
579                                pNames.append('%d:%s:%d:%.2f:%.2f'%(pId,name+'-unit',i,R[ind[0],ind[1]],P[ind[0],ind[1]]))
580                                pVals.append(Z2[ind[0]][ind[1]])
581                                pWt.append(wt/esd2**2)
582                                pWsum[name] += wt*(Z2/esd2)**2
583                                pWnum[name] += 1
584                elif name == 'General':
585                    for i,(eq,obs,esd) in enumerate(itemRest[rest]):
586                        calcobj = G2obj.ExpressionCalcObj(eq)
587                        calcobj.SetupCalc(parmDict)
588                        calc = calcobj.EvalExpression()
589                        try:
590                            pVals.append(obs-calc)
591                            pWt.append(wt/esd**2)                   
592                            pWsum[name] += wt*((obs-calc)/esd)**2
593                            pWnum[name] += 1
594                            pNames.append(str(pId)+':'+name+':'+str(i))
595                        except:
596                            print('Error computing General restraint #{}'.format(i+1))
597    for phase in Phases:
598        name = 'SH-Pref.Ori.'
599        pId = Phases[phase]['pId']
600        General = Phases[phase]['General']
601        SGData = General['SGData']
602        cell = General['Cell'][1:7]
603        pWsum[name] = 0.0
604        pWnum[name] = 0
605        for hist in Phases[phase]['Histograms']:
606            if not Phases[phase]['Histograms'][hist]['Use']:
607                continue
608            if hist in Histograms and 'PWDR' in hist:
609                hId = Histograms[hist]['hId']
610                phfx = '%d:%d:'%(pId,hId)
611                if calcControls.get(phfx+'poType','') == 'SH':
612                    toler = calcControls[phfx+'SHtoler']
613                    wt = 1./toler**2
614                    HKLs = np.array(calcControls[phfx+'SHhkl'])
615                    SHnames = calcControls[phfx+'SHnames']
616                    SHcof = dict(zip(SHnames,[parmDict[phfx+cof] for cof in SHnames]))
617                    for i,PH in enumerate(HKLs):
618                        phi,beta = G2lat.CrsAng(PH,cell,SGData)
619                        SH3Coef = {}
620                        for item in SHcof:
621                            L,N = eval(item.strip('C'))
622                            SH3Coef['C%d,0,%d'%(L,N)] = SHcof[item]                       
623                        ODFln = G2lat.Flnh(SH3Coef,phi,beta,SGData)
624                        X = np.linspace(0,90.0,26)
625                        Y = ma.masked_greater(G2lat.polfcal(ODFln,'0',X,0.0),0.0)       #+ or -?
626                        IndY = ma.nonzero(Y)
627                        for ind in IndY[0]:
628                            pNames.append('%d:%d:%s:%d:%.2f'%(pId,hId,name,i,X[ind]))
629                            pVals.append(Y[ind])
630                            pWt.append(wt)
631                            pWsum[name] += wt*(Y[ind])**2
632                            pWnum[name] += 1
633    pWsum['PWLref'] = 0.
634    pWnum['PWLref'] = 0
635    for item in varyList:
636        if 'PWLref' in item and parmDict[item] < 0.:
637            pId = int(item.split(':')[0])
638            if negWt[pId]:
639                pNames.append(item)
640                pVals.append(parmDict[item])
641                pWt.append(negWt[pId])
642                pWsum['PWLref'] += negWt[pId]*(parmDict[item])**2
643                pWnum['PWLref'] += 1
644    pVals = np.array(pVals)
645    pWt = np.array(pWt)         #should this be np.sqrt?
646    return pNames,pVals,pWt,pWsum,pWnum
647   
648def penaltyDeriv(pNames,pVal,HistoPhases,calcControls,parmDict,varyList):
649    '''Compute derivatives on user-supplied and built-in restraint
650    (penalty) functions
651
652    where pNames is list of restraint labels
653
654    :returns: array pDerv: partial derivatives by variable# in varList and
655       restraint# in pNames (pDerv[variable#][restraint#])
656    '''
657    Histograms,Phases,restraintDict,rigidbodyDict = HistoPhases
658    pDerv = np.zeros((len(varyList),len(pVal)))
659    for pName in pNames: # loop over restraints
660        if 'General' == pName.split(':')[1]:
661            # initialize for General restraint(s) here
662            parmDict0 = parmDict.copy()
663            # setup steps for each parameter
664            stepDict = {}
665            for parm in varyList:
666                stepDict[parm] = G2obj.getVarStep(parm,parmDict)
667            break
668    for phase in Phases:
669#        if phase not in restraintDict:
670#            continue
671        pId = Phases[phase]['pId']
672        General = Phases[phase]['General']
673        cx,ct,cs,cia = General['AtomPtrs']
674        SGData = General['SGData']
675        Atoms = Phases[phase]['Atoms']
676        AtLookup = G2mth.FillAtomLookUp(Phases[phase]['Atoms'],cia+8)
677        cell = General['Cell'][1:7]
678        Amat,Bmat = G2lat.cell2AB(cell)
679        textureData = General['SH Texture']
680
681        SHkeys = list(textureData['SH Coeff'][1].keys())
682        SHCoef = G2mth.GetSHCoeff(pId,parmDict,SHkeys)
683        shModels = ['cylindrical','none','shear - 2/m','rolling - mmm']
684        SamSym = dict(zip(shModels,['0','-1','2/m','mmm']))
685        sam = SamSym[textureData['Model']]
686        phaseRest = restraintDict.get(phase,{})
687        names = {'Bond':'Bonds','Angle':'Angles','Plane':'Planes',
688            'Chiral':'Volumes','Torsion':'Torsions','Rama':'Ramas',
689            'ChemComp':'Sites','Texture':'HKLs'}
690        lasthkl = np.array([0,0,0])
691        for ip,pName in enumerate(pNames): # loop over restraints
692            pnames = pName.split(':')
693            if pId == int(pnames[0]):
694                name = pnames[1]
695                if 'PWL' in pName:
696                    pDerv[varyList.index(pName)][ip] += 1.
697                    continue
698                elif 'SH-' in pName:
699                    continue
700                Id = int(pnames[2]) 
701                itemRest = phaseRest[name]
702                if name in ['Bond','Angle','Plane','Chiral']:
703                    indx,ops,obs,esd = itemRest[names[name]][Id]
704                    dNames = []
705                    for ind in indx:
706                        dNames += [str(pId)+'::dA'+Xname+':'+str(AtLookup[ind]) for Xname in ['x','y','z']]
707                    XYZ = np.array(G2mth.GetAtomCoordsByID(pId,parmDict,AtLookup,indx))
708                    if name == 'Bond':
709                        deriv = G2mth.getRestDeriv(G2mth.getRestDist,XYZ,Amat,ops,SGData)
710                    elif name == 'Angle':
711                        deriv = G2mth.getRestDeriv(G2mth.getRestAngle,XYZ,Amat,ops,SGData)
712                    elif name == 'Plane':
713                        deriv = G2mth.getRestDeriv(G2mth.getRestPlane,XYZ,Amat,ops,SGData)
714                    elif name == 'Chiral':
715                        deriv = G2mth.getRestDeriv(G2mth.getRestChiral,XYZ,Amat,ops,SGData)
716                elif name in ['Torsion','Rama']:
717                    coffDict = itemRest['Coeff']
718                    indx,ops,cofName,esd = itemRest[names[name]][Id]
719                    dNames = []
720                    for ind in indx:
721                        dNames += [str(pId)+'::dA'+Xname+':'+str(AtLookup[ind]) for Xname in ['x','y','z']]
722                    XYZ = np.array(G2mth.GetAtomCoordsByID(pId,parmDict,AtLookup,indx))
723                    if name == 'Torsion':
724                        deriv = G2mth.getTorsionDeriv(XYZ,Amat,coffDict[cofName])
725                    else:
726                        deriv = G2mth.getRamaDeriv(XYZ,Amat,coffDict[cofName])
727                elif name == 'ChemComp':
728                    indx,factors,obs,esd = itemRest[names[name]][Id]
729                    dNames = []
730                    for ind in indx:
731                        dNames += [str(pId)+'::Afrac:'+str(AtLookup[ind])]
732                        mul = np.array(G2mth.GetAtomItemsById(Atoms,AtLookup,indx,cs+1))
733                        deriv = mul*factors
734                elif 'Texture' in name:
735                    deriv = []
736                    dNames = []
737                    hkl,grid,esd1,ifesd2,esd2 = itemRest[names[name]][Id]
738                    hkl = np.array(hkl)
739                    if np.any(lasthkl-hkl):
740                        phi,beta = G2lat.CrsAng(np.array(hkl),cell,SGData)
741                        ODFln = G2lat.Flnh(SHCoef,phi,beta,SGData)
742                        lasthkl = copy.copy(hkl)                       
743                    if 'unit' in name:
744                        pass
745                    else:
746                        gam = float(pnames[3])
747                        psi = float(pnames[4])
748                        for SHname in ODFln:
749                            l,m,n = eval(SHname[1:])
750                            Ksl = G2lat.GetKsl(l,m,sam,psi,gam)[0]
751                            dNames += [str(pId)+'::'+SHname]
752                            deriv.append(-ODFln[SHname][0]*Ksl/SHCoef[SHname])
753                elif name == 'General':
754                    deriv = []
755                    dNames = []
756                    eq,obs,esd = itemRest[name][Id]
757                    calcobj = G2obj.ExpressionCalcObj(eq)
758                    parmlist = list(eq.assgnVars.values()) # parameters used in this expression
759                    for parm in parmlist: # expand list if any parms are determined by constraints
760                        if parm in G2mv.GetDependentVars():
761                            parmlist += G2mv.GetIndependentVars()
762                            break
763                    for ind,var in enumerate(varyList):
764                        drv = 0
765                        if var in parmlist:
766                            step = stepDict.get(var,1e-5)
767                            calc = []
768                            # apply step to parameter
769                            oneparm = True
770                            for s in -step,2*step:
771                                parmDict[var] += s
772                                # extend shift if needed to other parameters
773                                if var in G2mv.independentVars:
774                                    G2mv.Dict2Map(parmDict)
775                                    oneparm = False
776                                elif var in G2mv.dependentVars:
777                                    G2mv.Map2Dict(parmDict,[])
778                                    oneparm = False
779                                if 'RB' in var:
780                                    ApplyRBModels(parmDict,Phases,rigidbodyDict)
781# test
782                                    oneparm = False
783                                calcobj.SetupCalc(parmDict)
784                                calc.append(calcobj.EvalExpression())
785                            drv = (calc[1]-calc[0])*.5/step
786                            # restore the dict
787                            if oneparm:
788                                parmDict[var] = parmDict0[var]
789                            else:
790                                parmDict = parmDict0.copy()
791                        else:
792                            drv = 0
793                        pDerv[ind][ip] = drv
794                # Add derivatives into matrix, if needed
795                for dName,drv in zip(dNames,deriv):
796                    try:
797                        ind = varyList.index(dName)
798                        pDerv[ind][ip] += drv
799                    except ValueError:
800                        pass
801       
802        lasthkl = np.array([0,0,0])
803        for ip,pName in enumerate(pNames):
804            deriv = []
805            dNames = []
806            pnames = pName.split(':')
807            if 'SH-' in pName and pId == int(pnames[0]):
808                hId = int(pnames[1])
809                phfx = '%d:%d:'%(pId,hId)
810                psi = float(pnames[4])
811                HKLs = calcControls[phfx+'SHhkl']
812                SHnames = calcControls[phfx+'SHnames']
813                SHcof = dict(zip(SHnames,[parmDict[phfx+cof] for cof in SHnames]))
814                hkl = np.array(HKLs[int(pnames[3])])     
815                if np.any(lasthkl-hkl):
816                    phi,beta = G2lat.CrsAng(np.array(hkl),cell,SGData)
817                    SH3Coef = {}
818                    for item in SHcof:
819                        L,N = eval(item.strip('C'))
820                        SH3Coef['C%d,0,%d'%(L,N)] = SHcof[item]                       
821                    ODFln = G2lat.Flnh(SH3Coef,phi,beta,SGData)
822                    lasthkl = copy.copy(hkl)                       
823                for SHname in SHnames:
824                    l,n = eval(SHname[1:])
825                    SH3name = 'C%d,0,%d'%(l,n)
826                    Ksl = G2lat.GetKsl(l,0,'0',psi,0.0)[0]
827                    dNames += [phfx+SHname]
828                    deriv.append(ODFln[SH3name][0]*Ksl/SHcof[SHname])
829            for dName,drv in zip(dNames,deriv):
830                try:
831                    ind = varyList.index(dName)
832                    pDerv[ind][ip] += drv
833                except ValueError:
834                    pass
835    return pDerv
836
837################################################################################
838##### Function & derivative calculations
839################################################################################       
840                   
841def GetAtomFXU(pfx,calcControls,parmDict):
842    'Needs a doc string'
843    Natoms = calcControls['Natoms'][pfx]
844    Tdata = Natoms*[' ',]
845    Mdata = np.zeros(Natoms)
846    IAdata = Natoms*[' ',]
847    Fdata = np.zeros(Natoms)
848    Xdata = np.zeros((3,Natoms))
849    dXdata = np.zeros((3,Natoms))
850    Uisodata = np.zeros(Natoms)
851    Uijdata = np.zeros((6,Natoms))
852    Gdata = np.zeros((3,Natoms))
853    keys = {'Atype:':Tdata,'Amul:':Mdata,'Afrac:':Fdata,'AI/A:':IAdata,
854        'dAx:':dXdata[0],'dAy:':dXdata[1],'dAz:':dXdata[2],
855        'Ax:':Xdata[0],'Ay:':Xdata[1],'Az:':Xdata[2],'AUiso:':Uisodata,
856        'AU11:':Uijdata[0],'AU22:':Uijdata[1],'AU33:':Uijdata[2],
857        'AU12:':Uijdata[3],'AU13:':Uijdata[4],'AU23:':Uijdata[5],
858        'AMx:':Gdata[0],'AMy:':Gdata[1],'AMz:':Gdata[2],}
859    for iatm in range(Natoms):
860        for key in keys:
861            parm = pfx+key+str(iatm)
862            if parm in parmDict:
863                keys[key][iatm] = parmDict[parm]
864    Fdata = np.where(Fdata,Fdata,1.e-8)         #avoid divide by zero in derivative calc.
865    Gdata = np.where(Gdata,Gdata,1.e-8)         #avoid divide by zero in derivative calc.
866   
867    return Tdata,Mdata,Fdata,Xdata,dXdata,IAdata,Uisodata,Uijdata,Gdata
868   
869def GetAtomSSFXU(pfx,calcControls,parmDict):
870    'Needs a doc string'
871    Natoms = calcControls['Natoms'][pfx]
872    maxSSwave = calcControls['maxSSwave'][pfx]
873    Nwave = {'F':maxSSwave['Sfrac'],'X':maxSSwave['Spos'],'Y':maxSSwave['Spos'],'Z':maxSSwave['Spos'],
874        'U':maxSSwave['Sadp'],'M':maxSSwave['Smag'],'T':maxSSwave['Spos']}
875    XSSdata = np.zeros((6,maxSSwave['Spos'],Natoms))
876    FSSdata = np.zeros((2,maxSSwave['Sfrac'],Natoms))
877    USSdata = np.zeros((12,maxSSwave['Sadp'],Natoms))
878    MSSdata = np.zeros((6,maxSSwave['Smag'],Natoms))
879    waveTypes = []
880    keys = {'Fsin:':FSSdata[0],'Fcos:':FSSdata[1],'Fzero:':FSSdata[0],'Fwid:':FSSdata[1],
881        'Tmin:':XSSdata[0],'Tmax:':XSSdata[1],'Xmax:':XSSdata[2],'Ymax:':XSSdata[3],'Zmax:':XSSdata[4],
882        'Xsin:':XSSdata[0],'Ysin:':XSSdata[1],'Zsin:':XSSdata[2],'Xcos:':XSSdata[3],'Ycos:':XSSdata[4],'Zcos:':XSSdata[5],
883        'U11sin:':USSdata[0],'U22sin:':USSdata[1],'U33sin:':USSdata[2],'U12sin:':USSdata[3],'U13sin:':USSdata[4],'U23sin:':USSdata[5],
884        'U11cos:':USSdata[6],'U22cos:':USSdata[7],'U33cos:':USSdata[8],'U12cos:':USSdata[9],'U13cos:':USSdata[10],'U23cos:':USSdata[11],
885        'MXsin:':MSSdata[0],'MYsin:':MSSdata[1],'MZsin:':MSSdata[2],'MXcos:':MSSdata[3],'MYcos:':MSSdata[4],'MZcos:':MSSdata[5]}
886    for iatm in range(Natoms):
887        wavetype = [parmDict.get(pfx+kind+'waveType:'+str(iatm),'') for kind in ['F','P','A','M']]
888        waveTypes.append(wavetype)
889        for key in keys:
890            for m in range(Nwave[key[0]]):
891                parm = pfx+key+str(iatm)+':%d'%(m)
892                if parm in parmDict:
893                    keys[key][m][iatm] = parmDict[parm]
894    return waveTypes,FSSdata,XSSdata,USSdata,MSSdata
895   
896def StructureFactor2(refDict,G,hfx,pfx,SGData,calcControls,parmDict):
897    ''' Compute structure factors for all h,k,l for phase
898    puts the result, F^2, in each ref[8] in refList
899    operates on blocks of 100 reflections for speed
900    input:
901   
902    :param dict refDict: where
903        'RefList' list where each ref = h,k,l,it,d,...
904        'FF' dict of form factors - filed in below
905    :param np.array G:      reciprocal metric tensor
906    :param str pfx:    phase id string
907    :param dict SGData: space group info. dictionary output from SpcGroup
908    :param dict calcControls:
909    :param dict ParmDict:
910
911    '''       
912    phfx = pfx.split(':')[0]+hfx
913    ast = np.sqrt(np.diag(G))
914    Mast = twopisq*np.multiply.outer(ast,ast)
915    SGMT = np.array([ops[0].T for ops in SGData['SGOps']])      # must be ops[0].T
916    SGT = np.array([ops[1] for ops in SGData['SGOps']])
917    FFtables = calcControls['FFtables']
918    EFtables = calcControls['EFtables']
919    BLtables = calcControls['BLtables']
920    Amat,Bmat = G2lat.Gmat2AB(G)
921    Flack = 1.0
922    if not SGData['SGInv'] and 'S' in calcControls[hfx+'histType'] and phfx+'Flack' in parmDict:
923        Flack = 1.-2.*parmDict[phfx+'Flack']
924    TwinLaw = np.array([[[1,0,0],[0,1,0],[0,0,1]],])
925    TwDict = refDict.get('TwDict',{})
926    hType = calcControls[hfx+'histType'] 
927    if 'S' in hType:
928        NTL = calcControls[phfx+'NTL']
929        NM = calcControls[phfx+'TwinNMN']+1
930        TwinLaw = calcControls[phfx+'TwinLaw']
931        TwinFr = np.array([parmDict[phfx+'TwinFr:'+str(i)] for i in range(len(TwinLaw))])
932        TwinInv = list(np.where(calcControls[phfx+'TwinInv'],-1,1))
933    Tdata,Mdata,Fdata,Xdata,dXdata,IAdata,Uisodata,Uijdata,Gdata = \
934        GetAtomFXU(pfx,calcControls,parmDict)
935    if not Xdata.size:          #no atoms in phase!
936        return
937    if 'NC' in hType or 'NB' in calcControls[hfx+'histType']:
938        FP,FPP = G2el.BlenResCW(Tdata,BLtables,parmDict[hfx+'Lam'])
939    elif 'X' in hType:
940        FP = np.array([FFtables[El][hfx+'FP'] for El in Tdata])
941        FPP = np.array([FFtables[El][hfx+'FPP'] for El in Tdata])
942    elif 'SEC' in hType:
943        FP = np.zeros(len(Tdata))
944        FPP = np.zeros(len(Tdata))
945    Uij = np.array(G2lat.U6toUij(Uijdata))
946    bij = Mast*Uij.T
947    blkSize = 100       #no. of reflections in a block - size seems optimal
948    nRef = refDict['RefList'].shape[0]
949    SQ = 1./(2.*refDict['RefList'].T[4])**2
950    if 'N' in hType:
951        dat = G2el.getBLvalues(BLtables)
952        refDict['FF']['El'] = list(dat.keys())
953        refDict['FF']['FF'] = np.ones((nRef,len(dat)))*list(dat.values())
954    elif 'SEC' in hType:
955        dat = G2el.getFFvalues(EFtables,0.)
956        refDict['FF']['El'] = list(dat.keys())
957        refDict['FF']['FF'] = np.zeros((nRef,len(dat)))
958        for iel,El in enumerate(refDict['FF']['El']):
959            refDict['FF']['FF'].T[iel] = G2el.ScatFac(EFtables[El],SQ)       
960    else:       #'X'
961        dat = G2el.getFFvalues(FFtables,0.)
962        refDict['FF']['El'] = list(dat.keys())
963        refDict['FF']['FF'] = np.zeros((nRef,len(dat)))
964        for iel,El in enumerate(refDict['FF']['El']):
965            refDict['FF']['FF'].T[iel] = G2el.ScatFac(FFtables[El],SQ)
966    SHCdict = GetSHC(pfx,parmDict)
967#reflection processing begins here - big arrays!
968    iBeg = 0
969    while iBeg < nRef:
970        iFin = min(iBeg+blkSize,nRef)
971        refl = refDict['RefList'][iBeg:iFin]    #array(blkSize,nItems)
972        H = refl.T[:3]                          #array(blkSize,3)
973        H = np.squeeze(np.inner(H.T,TwinLaw))   #maybe array(blkSize,nTwins,3) or (blkSize,3)
974        TwMask = np.any(H,axis=-1)
975        if TwinLaw.shape[0] > 1 and TwDict: #need np.inner(TwinLaw[?],TwDict[iref][i])*TwinInv[i]
976            for ir in range(blkSize):
977                iref = ir+iBeg
978                if iref in TwDict:
979                    for i in TwDict[iref]:
980                        for n in range(NTL):
981                            H[ir][i+n*NM] = np.inner(TwinLaw[n*NM],np.array(TwDict[iref][i])*TwinInv[i+n*NM])
982            TwMask = np.any(H,axis=-1)
983        SQ = 1./(2.*refl.T[4])**2               #array(blkSize)
984        SQfactor = 4.0*SQ*twopisq               #ditto prev.
985        if 'T' in hType:
986            if 'P' in calcControls[hfx+'histType']:
987                FP,FPP = G2el.BlenResTOF(Tdata,BLtables,refl.T[14])
988            else:
989                FP,FPP = G2el.BlenResTOF(Tdata,BLtables,refl.T[12])
990            FP = np.repeat(FP.T,len(SGT)*len(TwinLaw),axis=0)
991            FPP = np.repeat(FPP.T,len(SGT)*len(TwinLaw),axis=0)
992        Uniq = np.inner(H,SGMT)
993        Phi = np.inner(H,SGT)
994        phase = twopi*(np.inner(Uniq,(dXdata+Xdata).T).T+Phi.T).T
995        sinp = np.sin(phase)
996        cosp = np.cos(phase)
997        biso = -SQfactor*Uisodata[:,nxs]
998        Tiso = np.repeat(np.where(biso<1.,np.exp(biso),1.0),len(SGT)*len(TwinLaw),axis=1).T
999        HbH = -np.sum(Uniq.T*np.swapaxes(np.inner(bij,Uniq),2,-1),axis=1)
1000#        HbH = -np.sum(np.inner(Uniq,bij)*Uniq[:,:,nxs,:],axis=-1).T    #doesn't work, but should!
1001        Tuij = np.where(HbH<1.,np.exp(HbH),1.0).T
1002        Tcorr = np.reshape(Tiso,Tuij.shape)*Tuij*Mdata*Fdata/len(SGMT)
1003        Tindx = np.array([refDict['FF']['El'].index(El) for El in Tdata])
1004        FF = np.repeat(refDict['FF']['FF'][iBeg:iFin].T[Tindx].T,len(SGT)*len(TwinLaw),axis=0)
1005        #FF has to have the Bessel*Sph.Har.*atm form factor for each refletion in Uniq for Q atoms; otherwise just normal FF
1006        #this must be done here. NB: same place for non-spherical atoms; same math except no Bessel part.
1007        if len(SHCdict):
1008            MakeSpHarmFF(Uniq,Bmat,SHCdict,Tdata,hType,FFtables,BLtables,FF,SQ)
1009        Bab = np.repeat(parmDict[phfx+'BabA']*np.exp(-parmDict[phfx+'BabU']*SQfactor),len(SGT)*len(TwinLaw))
1010        if 'T' in calcControls[hfx+'histType']: #fa,fb are 2 X blkSize X nTwin X nOps x nAtoms
1011            fa = np.array([np.reshape(((FF+FP).T-Bab).T,cosp.shape)*cosp*Tcorr,-np.reshape(Flack*FPP,sinp.shape)*sinp*Tcorr])
1012            fb = np.array([np.reshape(((FF+FP).T-Bab).T,sinp.shape)*sinp*Tcorr,np.reshape(Flack*FPP,cosp.shape)*cosp*Tcorr])
1013        else:
1014            fa = np.array([np.reshape(((FF+FP).T-Bab).T,cosp.shape)*cosp*Tcorr,-Flack*FPP*sinp*Tcorr])
1015            fb = np.array([np.reshape(((FF+FP).T-Bab).T,sinp.shape)*sinp*Tcorr,Flack*FPP*cosp*Tcorr])
1016        fas = np.sum(np.sum(fa,axis=-1),axis=-1)  #real 2 x blkSize x nTwin; sum over atoms & uniq hkl
1017        fbs = np.sum(np.sum(fb,axis=-1),axis=-1)  #imag
1018        if SGData['SGInv']: #centrosymmetric; B=0
1019            fbs[0] *= 0.
1020            fas[1] *= 0.
1021        if 'P' in hType:     #PXC, PNC & PNT: F^2 = A[0]^2 + A[1]^2 + B[0]^2 + B[1]^2
1022            refl.T[9] = np.sum(fas**2,axis=0)+np.sum(fbs**2,axis=0)   
1023            refl.T[10] = atan2d(fbs[0],fas[0])  #ignore f' & f"
1024        else:                                       #HKLF: F^2 = (A[0]+A[1])^2 + (B[0]+B[1])^2
1025            if len(TwinLaw) > 1:
1026                refl.T[9] = np.sum(fas[:,:,0],axis=0)**2+np.sum(fbs[:,:,0],axis=0)**2   #FcT from primary twin element
1027                refl.T[7] = np.sum(TwinFr*TwMask*np.sum(fas,axis=0)**2,axis=-1)+   \
1028                    np.sum(TwinFr*TwMask*np.sum(fbs,axis=0)**2,axis=-1)                        #Fc sum over twins
1029                refl.T[10] = atan2d(fbs[0].T[0],fas[0].T[0])  #ignore f' & f" & use primary twin
1030            else:   # checked correct!!
1031                refl.T[9] = np.sum(fas,axis=0)**2+np.sum(fbs,axis=0)**2
1032                refl.T[7] = np.copy(refl.T[9])               
1033                refl.T[10] = atan2d(fbs[0],fas[0])  #ignore f' & f"
1034#                refl.T[10] = atan2d(np.sum(fbs,axis=0),np.sum(fas,axis=0)) #include f' & f"
1035        iBeg += blkSize
1036#    print 'sf time %.4f, nref %d, blkSize %d'%(time.time()-time0,nRef,blkSize)
1037   
1038def StructureFactorDerv2(refDict,G,hfx,pfx,SGData,calcControls,parmDict):
1039    '''Compute structure factor derivatives on blocks of reflections - for powders/nontwins only
1040    faster than StructureFactorDerv - correct for powders/nontwins!!
1041    input:
1042   
1043    :param dict refDict: where
1044        'RefList' list where each ref = h,k,l,it,d,...
1045        'FF' dict of form factors - filled in below
1046    :param np.array G:      reciprocal metric tensor
1047    :param str hfx:    histogram id string
1048    :param str pfx:    phase id string
1049    :param dict SGData: space group info. dictionary output from SpcGroup
1050    :param dict calcControls:
1051    :param dict parmDict:
1052   
1053    :returns: dict dFdvDict: dictionary of derivatives
1054    '''
1055    phfx = pfx.split(':')[0]+hfx
1056    ast = np.sqrt(np.diag(G))
1057    Mast = twopisq*np.multiply.outer(ast,ast)
1058    SGMT = np.array([ops[0].T for ops in SGData['SGOps']])    # must be ops[0].T
1059    SGT = np.array([ops[1] for ops in SGData['SGOps']])
1060    FFtables = calcControls['FFtables']
1061    BLtables = calcControls['BLtables']
1062    hType = calcControls[hfx+'histType'] 
1063    Amat,Bmat = G2lat.Gmat2AB(G)
1064    nRef = len(refDict['RefList'])
1065    Tdata,Mdata,Fdata,Xdata,dXdata,IAdata,Uisodata,Uijdata,Gdata = \
1066        GetAtomFXU(pfx,calcControls,parmDict)
1067    atFlg = np.zeros(len(Tdata)) #non zero for Q type atoms - see below
1068    if not Xdata.size:          #no atoms in phase!
1069        return {}
1070    mSize = len(Mdata)
1071    nOps = len(SGMT)
1072    FF = np.zeros(len(Tdata))
1073    if 'NC' in calcControls[hfx+'histType'] or 'NB' in calcControls[hfx+'histType']:
1074        FP,FPP = G2el.BlenResCW(Tdata,BLtables,parmDict[hfx+'Lam'])
1075    elif 'X' in calcControls[hfx+'histType']:
1076        FP = np.array([FFtables[El][hfx+'FP'] for El in Tdata])
1077        FPP = np.array([FFtables[El][hfx+'FPP'] for El in Tdata])
1078    elif 'SEC' in calcControls[hfx+'histType']:
1079        FP = np.zeros(len(Tdata))
1080        FPP = np.zeros(len(Tdata))
1081    Uij = np.array(G2lat.U6toUij(Uijdata))
1082    bij = Mast*Uij.T
1083    dFdvDict = {}
1084    dFdfr = np.zeros((nRef,mSize))
1085    dFdff = np.zeros((nRef,nOps,mSize))
1086    dFdx = np.zeros((nRef,mSize,3))
1087    dFdui = np.zeros((nRef,mSize))
1088    dFdua = np.zeros((nRef,mSize,6))
1089    dFdbab = np.zeros((nRef,2))
1090    dFdfl = np.zeros((nRef))
1091    Flack = 1.0
1092    if not SGData['SGInv'] and 'S' in calcControls[hfx+'histType'] and phfx+'Flack' in parmDict:
1093        Flack = 1.-2.*parmDict[phfx+'Flack']
1094    SHCdict = GetSHC(pfx,parmDict)
1095    dffdSH = {}
1096#reflection processing begins here - big arrays!
1097    iBeg = 0
1098    blkSize = 32       #no. of reflections in a block - optimized for speed
1099    while iBeg < nRef:
1100        iFin = min(iBeg+blkSize,nRef)
1101        refl = refDict['RefList'][iBeg:iFin]    #array(blkSize,nItems)
1102        H = refl.T[:3].T
1103        SQ = 1./(2.*refl.T[4])**2             # or (sin(theta)/lambda)**2
1104        SQfactor = 8.0*SQ*np.pi**2
1105        if 'T' in calcControls[hfx+'histType']:
1106            if 'P' in calcControls[hfx+'histType']:
1107                FP,FPP = G2el.BlenResTOF(Tdata,BLtables,refl.T[14])
1108            else:
1109                FP,FPP = G2el.BlenResTOF(Tdata,BLtables,refl.T[12])
1110            FP = np.repeat(FP.T,len(SGT),axis=0)
1111            FPP = np.repeat(FPP.T,len(SGT),axis=0)
1112        dBabdA = np.exp(-parmDict[phfx+'BabU']*SQfactor)
1113        Bab = np.repeat(parmDict[phfx+'BabA']*np.exp(-parmDict[phfx+'BabU']*SQfactor),len(SGT))
1114        Tindx = np.array([refDict['FF']['El'].index(El) for El in Tdata])
1115        FF = np.repeat(refDict['FF']['FF'][iBeg:iFin].T[Tindx].T,len(SGT),axis=0)
1116        Uniq = np.inner(H,SGMT)             # array(nSGOp,3)
1117        Phi = np.inner(H,SGT)
1118        phase = twopi*(np.inner(Uniq,(dXdata+Xdata).T).T+Phi.T).T
1119        sinp = np.sin(phase)        #refBlk x nOps x nAtoms
1120        cosp = np.cos(phase)
1121        occ = Mdata*Fdata/len(SGT)
1122        biso = -SQfactor*Uisodata[:,nxs]
1123        Tiso = np.repeat(np.where(biso<1.,np.exp(biso),1.0),len(SGT),axis=1).T
1124        HbH = -np.sum(Uniq.T*np.swapaxes(np.inner(bij,Uniq),2,-1),axis=1)       #Natm,Nops,Nref
1125        Tuij = np.where(HbH<1.,np.exp(HbH),1.0).T       #Nref,Nops,Natm
1126        Tcorr = np.reshape(Tiso,Tuij.shape)*Tuij*Mdata*Fdata/len(SGMT)
1127        Hij = np.array([Mast*np.multiply.outer(U,U) for U in np.reshape(Uniq,(-1,3))])      #Nref*Nops,3,3
1128        Hij = np.reshape(np.array([G2lat.UijtoU6(uij) for uij in Hij]),(-1,len(SGT),6))     #Nref,Nops,6
1129        if len(SHCdict):
1130            dffdsh,atFlg = MakeSpHarmFF(Uniq,Bmat,SHCdict,Tdata,hType,FFtables,BLtables,FF,SQ,True)
1131            if len(dffdSH):
1132                for item in dffdSH:
1133                    dffdSH[item] = np.concatenate((dffdSH[item],dffdsh[item]))
1134            else:
1135                dffdSH.update(dffdsh)
1136        fot = np.reshape(((FF+FP).T-Bab).T,cosp.shape)*Tcorr
1137        if len(FPP.shape) > 1:
1138            fotp = np.reshape(FPP,cosp.shape)*Tcorr
1139        else:
1140            fotp = FPP*Tcorr     
1141        if 'T' in calcControls[hfx+'histType']:
1142            fa = np.array([fot*cosp,-np.reshape(Flack*FPP,sinp.shape)*sinp*Tcorr])
1143            fb = np.array([fot*sinp,np.reshape(Flack*FPP,cosp.shape)*cosp*Tcorr])
1144        else:
1145            fa = np.array([fot*cosp,-Flack*FPP*sinp*Tcorr])
1146            fb = np.array([fot*sinp,Flack*FPP*cosp*Tcorr])
1147        fas = np.sum(np.sum(fa,axis=-1),axis=-1)      #real sum over atoms & unique hkl array(2,refBlk,nTwins)
1148        fbs = np.sum(np.sum(fb,axis=-1),axis=-1)      #imag sum over atoms & uniq hkl
1149        fax = np.array([-fot*sinp,-fotp*cosp])   #positions array(2,refBlk,nEqv,nAtoms)
1150        fbx = np.array([fot*cosp,-fotp*sinp])
1151        #sum below is over Uniq
1152        dfadfr = np.sum(fa/occ,axis=-2)        #array(2,refBlk,nAtom) Fdata != 0 avoids /0. problem
1153#        dfadff = np.sum(fa[0]*Tcorr*atFlg/fot,axis=-2)           #ignores resonant scattering? #TODO needs only for Q atoms!
1154        dfadff = fa[0]*Tcorr*atFlg/fot           #ignores resonant scattering? no sum on Uniq
1155        dfadba = np.sum(-cosp*Tcorr,axis=-2)  #array(refBlk,nAtom)
1156        dfadx = np.sum(twopi*Uniq[nxs,:,nxs,:,:]*np.swapaxes(fax,-2,-1)[:,:,:,:,nxs],axis=-2)
1157        dfadui = np.sum(-SQfactor[nxs,:,nxs,nxs]*fa,axis=-2) #array(Ops,refBlk,nAtoms)
1158        dfadua = np.sum(-Hij[nxs,:,nxs,:,:]*np.swapaxes(fa,-2,-1)[:,:,:,:,nxs],axis=-2)
1159        # array(2,refBlk,nAtom,3) & array(2,refBlk,nAtom,6)
1160        if not SGData['SGInv']:
1161            dfbdfr = np.sum(fb/occ,axis=-2)        #Fdata != 0 avoids /0. problem
1162#            dfbdff = np.sum(fb[0]*Tcorr*atFlg/fot,axis=-2)           #ignores resonant scattering?
1163            dfbdff = fb[0]*Tcorr*atFlg/fot           #ignores resonant scattering? no sum on Uniq
1164            dfbdba = np.sum(-sinp*Tcorr,axis=-2)
1165            dfadfl = np.sum(np.sum(-fotp*sinp,axis=-1),axis=-1)
1166            dfbdfl = np.sum(np.sum(fotp*cosp,axis=-1),axis=-1)
1167            dfbdx = np.sum(twopi*Uniq[nxs,:,nxs,:,:]*np.swapaxes(fbx,-2,-1)[:,:,:,:,nxs],axis=-2)           
1168            dfbdui = np.sum(-SQfactor[nxs,:,nxs,nxs]*fb,axis=-2)
1169            dfbdua = np.sum(-Hij[nxs,:,nxs,:,:]*np.swapaxes(fb,-2,-1)[:,:,:,:,nxs],axis=-2)
1170        else:
1171            dfbdfr = np.zeros_like(dfadfr)
1172            dfbdff = np.zeros_like(dfadff)
1173            dfbdx = np.zeros_like(dfadx)
1174            dfbdui = np.zeros_like(dfadui)
1175            dfbdua = np.zeros_like(dfadua)
1176            dfbdba = np.zeros_like(dfadba)
1177            dfadfl = 0.0
1178            dfbdfl = 0.0
1179        #NB: the above have been checked against PA(1:10,1:2) in strfctr.for for Al2O3!   
1180        SA = fas[0]+fas[1]
1181        SB = fbs[0]+fbs[1]
1182        if 'P' in calcControls[hfx+'histType']: #checked perfect for centro & noncentro
1183            dFdfr[iBeg:iFin] = 2.*np.sum(fas[:,:,nxs]*dfadfr+fbs[:,:,nxs]*dfbdfr,axis=0)*Mdata/len(SGMT)
1184#            dFdff[iBeg:iFin] = 2.*np.sum(fas[:,:,nxs]*dfadff+fbs[:,:,nxs]*dfbdff,axis=0)/len(SGMT)
1185            dFdff[iBeg:iFin] = 2.*np.sum(fas[:,:,nxs,nxs]*dfadff[nxs,:,:,:]+fbs[:,:,nxs,nxs]*dfbdff[nxs,:,:,:],axis=0) #not summed on Uniq yet
1186            dFdx[iBeg:iFin] = 2.*np.sum(fas[:,:,nxs,nxs]*dfadx+fbs[:,:,nxs,nxs]*dfbdx,axis=0)
1187            dFdui[iBeg:iFin] = 2.*np.sum(fas[:,:,nxs]*dfadui+fbs[:,:,nxs]*dfbdui,axis=0)
1188            dFdua[iBeg:iFin] = 2.*np.sum(fas[:,:,nxs,nxs]*dfadua+fbs[:,:,nxs,nxs]*dfbdua,axis=0)
1189        else:
1190            dFdfr[iBeg:iFin] = (2.*SA[:,nxs]*(dfadfr[0]+dfadfr[1])+2.*SB[:,nxs]*(dfbdfr[0]+dfbdfr[1]))*Mdata/len(SGMT)
1191#            dFdff[iBeg:iFin] = (2.*SA[:,nxs]*dfadff+2.*SB[:,nxs]*dfbdff)/len(SGMT)
1192            dFdff[iBeg:iFin] = (2.*SA[:,nxs,nxs]*dfadff+2.*SB[:,nxs,nxs]*dfbdff)      #not summed on Uniq yet
1193            dFdx[iBeg:iFin] = 2.*SA[:,nxs,nxs]*(dfadx[0]+dfadx[1])+2.*SB[:,nxs,nxs]*(dfbdx[0]+dfbdx[1])
1194            dFdui[iBeg:iFin] = 2.*SA[:,nxs]*(dfadui[0]+dfadui[1])+2.*SB[:,nxs]*(dfbdui[0]+dfbdui[1])
1195            dFdua[iBeg:iFin] = 2.*SA[:,nxs,nxs]*(dfadua[0]+dfadua[1])+2.*SB[:,nxs,nxs]*(dfbdua[0]+dfbdua[1])
1196            dFdfl[iBeg:iFin] = -SA*dfadfl-SB*dfbdfl  #array(nRef,)
1197        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)])+ \
1198                            fbs[0,nxs]*np.array([np.sum(dfbdba.T*dBabdA,axis=0),np.sum(-dfbdba.T*parmDict[phfx+'BabA']*SQfactor*dBabdA,axis=0)])).T
1199        iBeg += blkSize
1200#    print 'derv time %.4f, nref %d, blkSize %d'%(time.time()-time0,nRef,blkSize)
1201        #loop over atoms - each dict entry is list of derivatives for all the reflections
1202    for i in range(len(Mdata)):
1203        dFdvDict[pfx+'Afrac:'+str(i)] = dFdfr.T[i]
1204        dFdvDict[pfx+'dAx:'+str(i)] = dFdx.T[0][i]
1205        dFdvDict[pfx+'dAy:'+str(i)] = dFdx.T[1][i]
1206        dFdvDict[pfx+'dAz:'+str(i)] = dFdx.T[2][i]
1207        dFdvDict[pfx+'AUiso:'+str(i)] = dFdui.T[i]
1208        dFdvDict[pfx+'AU11:'+str(i)] = dFdua.T[0][i]
1209        dFdvDict[pfx+'AU22:'+str(i)] = dFdua.T[1][i]
1210        dFdvDict[pfx+'AU33:'+str(i)] = dFdua.T[2][i]
1211        dFdvDict[pfx+'AU12:'+str(i)] = dFdua.T[3][i]
1212        dFdvDict[pfx+'AU13:'+str(i)] = dFdua.T[4][i]
1213        dFdvDict[pfx+'AU23:'+str(i)] = dFdua.T[5][i]
1214        for item in dffdSH:
1215            i = int(item.split(':')[1])
1216            dFdvDict[pfx+'RBS'+item] = np.sum(dFdff[:,:,i]*np.reshape(dffdSH[item],(nRef,-1)),axis=-1)
1217    dFdvDict[phfx+'Flack'] = 4.*dFdfl.T
1218    dFdvDict[phfx+'BabA'] = dFdbab.T[0]
1219    dFdvDict[phfx+'BabU'] = dFdbab.T[1]
1220    return dFdvDict
1221   
1222def MagStructureFactor2(refDict,G,hfx,pfx,SGData,calcControls,parmDict):
1223    ''' Compute neutron magnetic structure factors for all h,k,l for phase
1224    puts the result, F^2, in each ref[8] in refList
1225    operates on blocks of 100 reflections for speed
1226    input:
1227   
1228    :param dict refDict: where
1229        'RefList' list where each ref = h,k,l,it,d,...
1230        'FF' dict of form factors - filed in below
1231    :param np.array G:      reciprocal metric tensor
1232    :param str pfx:    phase id string
1233    :param dict SGData: space group info. dictionary output from SpcGroup
1234    :param dict calcControls:
1235    :param dict ParmDict:
1236       
1237    :returns: copy of new refList - used in calculating numerical derivatives
1238
1239    '''       
1240    g = nl.inv(G)
1241    ast = np.sqrt(np.diag(G))
1242    ainv = np.sqrt(np.diag(g))
1243    GS = G/np.outer(ast,ast)
1244    Ginv = g/np.outer(ainv,ainv)
1245    uAmat = G2lat.Gmat2AB(GS)[0]
1246    Bmat = G2lat.Gmat2AB(G)[1]
1247    Mast = twopisq*np.multiply.outer(ast,ast)
1248    SGMT = np.array([ops[0].T for ops in SGData['SGOps']])
1249    SGT = np.array([ops[1] for ops in SGData['SGOps']])
1250    Ncen = len(SGData['SGCen'])
1251    Nops = len(SGMT)*Ncen
1252    if not SGData['SGFixed']:
1253        Nops *= (1+SGData['SGInv'])
1254    MFtables = calcControls['MFtables']
1255    TwinLaw = np.ones(1)
1256#    TwinLaw = np.array([[[1,0,0],[0,1,0],[0,0,1]],])
1257#    TwDict = refDict.get('TwDict',{})           
1258#    if 'S' in calcControls[hfx+'histType']:
1259#        NTL = calcControls[phfx+'NTL']
1260#        NM = calcControls[phfx+'TwinNMN']+1
1261#        TwinLaw = calcControls[phfx+'TwinLaw']
1262#        TwinFr = np.array([parmDict[phfx+'TwinFr:'+str(i)] for i in range(len(TwinLaw))])
1263#        TwinInv = list(np.where(calcControls[phfx+'TwinInv'],-1,1))
1264    Tdata,Mdata,Fdata,Xdata,dXdata,IAdata,Uisodata,Uijdata,Gdata = \
1265        GetAtomFXU(pfx,calcControls,parmDict)
1266    if not Xdata.size:          #no atoms in phase!
1267        return
1268    Mag = np.array([np.sqrt(np.inner(mag,np.inner(mag,Ginv))) for mag in Gdata.T])
1269    Gdata = np.inner(Gdata.T,np.swapaxes(SGMT,1,2)).T            #apply sym. ops.
1270    if SGData['SGInv'] and not SGData['SGFixed']:
1271        Gdata = np.hstack((Gdata,-Gdata))       #inversion if any
1272    Gdata = np.hstack([Gdata for icen in range(Ncen)])        #dup over cell centering--> [Mxyz,nops,natms]
1273    Gdata = SGData['MagMom'][nxs,:,nxs]*Gdata   #flip vectors according to spin flip * det(opM)
1274    Mag = np.tile(Mag[:,nxs],Nops).#make Mag same length as Gdata
1275    Kdata = np.inner(Gdata.T,uAmat).T
1276    Kmean = np.mean(np.sqrt(np.sum(Kdata**2,axis=0)),axis=0)
1277    Kdata /= Kmean     #Cartesian unit vectors
1278    Uij = np.array(G2lat.U6toUij(Uijdata))
1279    bij = Mast*Uij.T
1280    blkSize = 100       #no. of reflections in a block - size seems optimal
1281    nRef = refDict['RefList'].shape[0]
1282    SQ = 1./(2.*refDict['RefList'].T[4])**2
1283    refDict['FF']['El'] = list(MFtables.keys())
1284    refDict['FF']['MF'] = np.zeros((nRef,len(MFtables)))
1285    for iel,El in enumerate(refDict['FF']['El']):
1286        refDict['FF']['MF'].T[iel] = G2el.MagScatFac(MFtables[El],SQ)
1287#reflection processing begins here - big arrays!
1288    iBeg = 0
1289    while iBeg < nRef:
1290        iFin = min(iBeg+blkSize,nRef)
1291        refl = refDict['RefList'][iBeg:iFin]    #array(blkSize,nItems)
1292        H = refl.T[:3].T                          #array(blkSize,3)
1293#        H = np.squeeze(np.inner(H.T,TwinLaw))   #maybe array(blkSize,nTwins,3) or (blkSize,3)
1294#        TwMask = np.any(H,axis=-1)
1295#        if TwinLaw.shape[0] > 1 and TwDict: #need np.inner(TwinLaw[?],TwDict[iref][i])*TwinInv[i]
1296#            for ir in range(blkSize):
1297#                iref = ir+iBeg
1298#                if iref in TwDict:
1299#                    for i in TwDict[iref]:
1300#                        for n in range(NTL):
1301#                            H[ir][i+n*NM] = np.inner(TwinLaw[n*NM],np.array(TwDict[iref][i])*TwinInv[i+n*NM])
1302#            TwMask = np.any(H,axis=-1)
1303        SQ = 1./(2.*refl.T[4])**2               #array(blkSize)
1304        SQfactor = 4.0*SQ*twopisq               #ditto prev.
1305        Uniq = np.inner(H,SGMT)
1306        Phi = np.inner(H,SGT)
1307        phase = twopi*(np.inner(Uniq,(dXdata+Xdata).T).T+Phi.T).T
1308        biso = -SQfactor*Uisodata[:,nxs]
1309        Tiso = np.repeat(np.where(biso<1.,np.exp(biso),1.0),len(SGT)*len(TwinLaw),axis=1).T
1310        HbH = -np.sum(Uniq.T*np.swapaxes(np.inner(bij,Uniq),2,-1),axis=1)
1311        Tuij = np.where(HbH<1.,np.exp(HbH),1.0).T
1312        Tindx = np.array([refDict['FF']['El'].index(El) for El in Tdata])
1313        MF = refDict['FF']['MF'][iBeg:iFin].T[Tindx].T   #Nref,Natm
1314        TMcorr = 0.539*(np.reshape(Tiso,Tuij.shape)*Tuij)[:,0,:]*Fdata*Mdata*MF/(2*Nops)     #Nref,Natm
1315        if SGData['SGInv']:
1316            if not SGData['SGFixed']:
1317                mphase = np.hstack((phase,-phase))  #OK
1318            else:
1319                mphase = phase
1320        else:
1321            mphase = phase                    #
1322        mphase = np.array([mphase+twopi*np.inner(cen,H)[:,nxs,nxs] for cen in SGData['SGCen']])
1323        mphase = np.concatenate(mphase,axis=1)              #Nref,full Nop,Natm
1324        sinm = np.sin(mphase)                               #ditto - match magstrfc.for
1325        cosm = np.cos(mphase)                               #ditto
1326        HM = np.inner(Bmat,H)                             #put into cartesian space
1327        HM = HM/np.sqrt(np.sum(HM**2,axis=0))               #Kdata = MAGS & HM = UVEC in magstrfc.for both OK
1328        eDotK = np.sum(HM[:,:,nxs,nxs]*Kdata[:,nxs,:,:],axis=0)
1329        Q = HM[:,:,nxs,nxs]*eDotK[nxs,:,:,:]-Kdata[:,nxs,:,:] #xyz,Nref,Nop,Natm = BPM in magstrfc.for OK
1330        fam = Q*TMcorr[nxs,:,nxs,:]*cosm[nxs,:,:,:]*Mag[nxs,nxs,:,:]    #ditto
1331        fbm = Q*TMcorr[nxs,:,nxs,:]*sinm[nxs,:,:,:]*Mag[nxs,nxs,:,:]    #ditto
1332        fams = np.sum(np.sum(fam,axis=-1),axis=-1)     #Mxyz,Nref  Sum(sum(fam,atoms),ops)
1333        fbms = np.sum(np.sum(fbm,axis=-1),axis=-1)     #ditto
1334        refl.T[9] = np.sum(fams**2,axis=0)+np.sum(fbms**2,axis=0)   #Sum(fams**2,Mxyz) Re + Im
1335        refl.T[7] = np.copy(refl.T[9])               
1336        refl.T[10] = atan2d(fbms[0],fams[0]) #- what is phase for mag refl?
1337#        if 'P' in calcControls[hfx+'histType']:     #PXC, PNC & PNT: F^2 = A[0]^2 + A[1]^2 + B[0]^2 + B[1]^2
1338#            refl.T[9] = np.sum(fas**2,axis=0)+np.sum(fbs**2,axis=0) #add fam**2 & fbm**2 here   
1339#            refl.T[10] = atan2d(fbs[0],fas[0])  #ignore f' & f"
1340#        else:                                       #HKLF: F^2 = (A[0]+A[1])^2 + (B[0]+B[1])^2
1341#            if len(TwinLaw) > 1:
1342#                refl.T[9] = np.sum(fas[:,:,0],axis=0)**2+np.sum(fbs[:,:,0],axis=0)**2   #FcT from primary twin element
1343#                refl.T[7] = np.sum(TwinFr*TwMask*np.sum(fas,axis=0)**2,axis=-1)+   \
1344#                    np.sum(TwinFr*TwMask*np.sum(fbs,axis=0)**2,axis=-1)                        #Fc sum over twins
1345#                refl.T[10] = atan2d(fbs[0].T[0],fas[0].T[0])  #ignore f' & f" & use primary twin
1346#            else:   # checked correct!!
1347#                refl.T[9] = np.sum(fas,axis=0)**2+np.sum(fbs,axis=0)**2
1348#                refl.T[7] = np.copy(refl.T[9])               
1349#                refl.T[10] = atan2d(fbs[0],fas[0])  #ignore f' & f"
1350##                refl.T[10] = atan2d(np.sum(fbs,axis=0),np.sum(fas,axis=0)) #include f' & f"
1351        iBeg += blkSize
1352#    print 'sf time %.4f, nref %d, blkSize %d'%(time.time()-time0,nRef,blkSize)
1353    return copy.deepcopy(refDict['RefList'])
1354
1355def MagStructureFactorDerv2(refDict,G,hfx,pfx,SGData,calcControls,parmDict):
1356    '''Compute magnetic structure factor derivatives numerically - for powders/nontwins only
1357    input:
1358   
1359    :param dict refDict: where
1360        'RefList' list where each ref = h,k,l,it,d,...
1361        'FF' dict of form factors - filled in below
1362    :param np.array G:      reciprocal metric tensor
1363    :param str hfx:    histogram id string
1364    :param str pfx:    phase id string
1365    :param dict SGData: space group info. dictionary output from SpcGroup
1366    :param dict calcControls:
1367    :param dict parmDict:
1368   
1369    :returns: dict dFdvDict: dictionary of magnetic derivatives
1370    '''
1371   
1372    trefDict = copy.deepcopy(refDict)
1373    dM = 1.e-6
1374    dFdvDict = {}
1375    for parm in parmDict:
1376        if 'AM' in parm:
1377            parmDict[parm] += dM
1378            prefList = MagStructureFactor2(trefDict,G,hfx,pfx,SGData,calcControls,parmDict)
1379            parmDict[parm] -= 2*dM
1380            mrefList = MagStructureFactor2(trefDict,G,hfx,pfx,SGData,calcControls,parmDict)
1381            parmDict[parm] += dM
1382            dFdvDict[parm] = (prefList[:,9]-mrefList[:,9])/(2.*dM)
1383    return dFdvDict
1384           
1385def MagStructureFactorDerv(refDict,G,hfx,pfx,SGData,calcControls,parmDict):
1386    '''Compute nonmagnetic structure factor derivatives on blocks of reflections in magnetic structures - for powders/nontwins only
1387    input:
1388   
1389    :param dict refDict: where
1390        'RefList' list where each ref = h,k,l,it,d,...
1391        'FF' dict of form factors - filled in below
1392    :param np.array G:      reciprocal metric tensor
1393    :param str hfx:    histogram id string
1394    :param str pfx:    phase id string
1395    :param dict SGData: space group info. dictionary output from SpcGroup
1396    :param dict calcControls:
1397    :param dict parmDict:
1398   
1399    :returns: dict dFdvDict: dictionary of derivatives
1400    '''
1401   
1402    g = nl.inv(G)
1403    ast = np.sqrt(np.diag(G))
1404    ainv = np.sqrt(np.diag(g))
1405    GS = G/np.outer(ast,ast)
1406    Ginv = g/np.outer(ainv,ainv)
1407    uAmat = G2lat.Gmat2AB(GS)[0]
1408    Mast = twopisq*np.multiply.outer(ast,ast)
1409    SGMT = np.array([ops[0].T for ops in SGData['SGOps']])
1410    SGT = np.array([ops[1] for ops in SGData['SGOps']])
1411    Ncen = len(SGData['SGCen'])
1412    Nops = len(SGMT)*Ncen
1413    if not SGData['SGFixed']:
1414        Nops *= (1+SGData['SGInv'])
1415    Bmat = G2lat.Gmat2AB(G)[1]
1416    nRef = len(refDict['RefList'])
1417    Tdata,Mdata,Fdata,Xdata,dXdata,IAdata,Uisodata,Uijdata,Gdata = \
1418        GetAtomFXU(pfx,calcControls,parmDict)
1419    if not Xdata.size:          #no atoms in phase!
1420        return {}
1421    mSize = len(Mdata)
1422    Mag = np.array([np.sqrt(np.inner(mag,np.inner(mag,Ginv))) for mag in Gdata.T])
1423    Gones = np.ones_like(Gdata)
1424    Gdata = np.inner(Gdata.T,np.swapaxes(SGMT,1,2)).T            #apply sym. ops.
1425    Gones = np.inner(Gones.T,SGMT).T
1426    if SGData['SGInv'] and not SGData['SGFixed']:
1427        Gdata = np.hstack((Gdata,-Gdata))       #inversion if any
1428        Gones = np.hstack((Gones,-Gones))       #inversion if any
1429    Gdata = np.hstack([Gdata for icen in range(Ncen)])        #dup over cell centering
1430    Gones = np.hstack([Gones for icen in range(Ncen)])        #dup over cell centering
1431    Gdata = SGData['MagMom'][nxs,:,nxs]*Gdata   #flip vectors according to spin flip
1432    Gones = SGData['MagMom'][nxs,:,nxs]*Gones   #flip vectors according to spin flip
1433    Mag = np.tile(Mag[:,nxs],Nops).#make Mag same length as Gdata
1434    Kdata = np.inner(Gdata.T,uAmat).T     #Cartesian unit vectors
1435    Kmean = np.mean(np.sqrt(np.sum(Kdata**2,axis=0)),axis=0)
1436    Kdata /= Kmean
1437    Uij = np.array(G2lat.U6toUij(Uijdata))
1438    bij = Mast*Uij.T
1439    dFdvDict = {}
1440    dFdfr = np.zeros((nRef,mSize))
1441    dFdx = np.zeros((nRef,mSize,3))
1442    dFdui = np.zeros((nRef,mSize))
1443    dFdua = np.zeros((nRef,mSize,6))
1444    time0 = time.time()
1445#reflection processing begins here - big arrays!
1446    iBeg = 0
1447    blkSize = 5       #no. of reflections in a block - optimized for speed
1448    while iBeg < nRef:
1449        iFin = min(iBeg+blkSize,nRef)
1450        refl = refDict['RefList'][iBeg:iFin]    #array(blkSize,nItems)
1451        H = refl.T[:3].T
1452        SQ = 1./(2.*refl.T[4])**2             # or (sin(theta)/lambda)**2
1453        SQfactor = 8.0*SQ*np.pi**2
1454        Uniq = np.inner(H,SGMT)             # array(nSGOp,3)
1455        Phi = np.inner(H,SGT)
1456        phase = twopi*(np.inner(Uniq,(dXdata+Xdata).T).T+Phi.T).T
1457        occ = Mdata*Fdata/Nops
1458        biso = -SQfactor*Uisodata[:,nxs]
1459        Tiso = np.repeat(np.where(biso<1.,np.exp(biso),1.0),len(SGT),axis=1).T
1460        HbH = -np.sum(Uniq.T*np.swapaxes(np.inner(bij,Uniq),2,-1),axis=1)
1461        Tuij = np.where(HbH<1.,np.exp(HbH),1.0).T
1462        Hij = np.array([Mast*np.multiply.outer(U,U) for U in np.reshape(Uniq,(-1,3))])
1463        Hij = np.reshape(np.array([G2lat.UijtoU6(uij) for uij in Hij]),(-1,len(SGT),6))
1464        Tindx = np.array([refDict['FF']['El'].index(El) for El in Tdata])
1465        MF = refDict['FF']['MF'][iBeg:iFin].T[Tindx].T   #Nref,Natm
1466        TMcorr = 0.539*(np.reshape(Tiso,Tuij.shape)*Tuij)[:,0,:]*Fdata*Mdata*MF/(2*Nops)     #Nref,Natm
1467        if SGData['SGInv']:
1468            if not SGData['SGFixed']:
1469                mphase = np.hstack((phase,-phase))  #OK
1470                Uniq = np.hstack((Uniq,-Uniq))      #Nref,Nops,hkl
1471                Hij = np.hstack((Hij,Hij))
1472            else:
1473                mphase = phase
1474        else:
1475            mphase = phase                    #
1476        Hij = np.concatenate(np.array([Hij for cen in SGData['SGCen']]),axis=1)
1477        Uniq = np.hstack([Uniq for cen in SGData['SGCen']])
1478        mphase = np.array([mphase+twopi*np.inner(cen,H)[:,nxs,nxs] for cen in SGData['SGCen']])
1479        mphase = np.concatenate(mphase,axis=1)              #Nref,Nop,Natm
1480        sinm = np.sin(mphase)                               #ditto - match magstrfc.for
1481        cosm = np.cos(mphase)                               #ditto
1482        HM = np.inner(Bmat.T,H)                             #put into cartesian space
1483        HM = HM/np.sqrt(np.sum(HM**2,axis=0))               #unit cartesian vector for H
1484        eDotK = np.sum(HM[:,:,nxs,nxs]*Kdata[:,nxs,:,:],axis=0)
1485        Q = HM[:,:,nxs,nxs]*eDotK[nxs,:,:,:]-Kdata[:,nxs,:,:] #Mxyz,Nref,Nop,Natm = BPM in magstrfc.for OK
1486       
1487        fam = Q*TMcorr[nxs,:,nxs,:]*cosm[nxs,:,:,:]*Mag[nxs,nxs,:,:]    #Mxyz,Nref,Nop,Natm
1488        fbm = Q*TMcorr[nxs,:,nxs,:]*sinm[nxs,:,:,:]*Mag[nxs,nxs,:,:]
1489        fams = np.sum(np.sum(fam,axis=-1),axis=-1)                      #Mxyz,Nref
1490        fbms = np.sum(np.sum(fbm,axis=-1),axis=-1)
1491        famx = -Q*TMcorr[nxs,:,nxs,:]*Mag[nxs,nxs,:,:]*sinm[nxs,:,:,:]   #Mxyz,Nref,Nops,Natom
1492        fbmx = Q*TMcorr[nxs,:,nxs,:]*Mag[nxs,nxs,:,:]*cosm[nxs,:,:,:]
1493        #sums below are over Nops - real part
1494        dfadfr = np.sum(fam/occ,axis=2)        #array(Mxyz,refBlk,nAtom) Fdata != 0 avoids /0. problem deriv OK
1495        dfadx = np.sum(twopi*Uniq[nxs,:,:,nxs,:]*famx[:,:,:,:,nxs],axis=2)          #deriv OK
1496        dfadui = np.sum(-SQfactor[:,nxs,nxs]*fam,axis=2) #array(Ops,refBlk,nAtoms)  deriv OK
1497        dfadua = np.sum(-Hij[nxs,:,:,nxs,:]*fam[:,:,:,:,nxs],axis=2)            #deriv OK
1498        # imaginary part; array(3,refBlk,nAtom,3) & array(3,refBlk,nAtom,6)
1499        dfbdfr = np.sum(fbm/occ,axis=2)        #array(mxyz,refBlk,nAtom) Fdata != 0 avoids /0. problem
1500        dfbdx = np.sum(twopi*Uniq[nxs,:,:,nxs,:]*fbmx[:,:,:,:,nxs],axis=2)
1501        dfbdui = np.sum(-SQfactor[:,nxs,nxs]*fbm,axis=2) #array(Ops,refBlk,nAtoms)
1502        dfbdua = np.sum(-Hij[nxs,:,:,nxs,:]*fbm[:,:,:,:,nxs],axis=2)
1503        #accumulate derivatives   
1504        dFdfr[iBeg:iFin] = 2.*np.sum((fams[:,:,nxs]*dfadfr+fbms[:,:,nxs]*dfbdfr)*Mdata/Nops,axis=0) #ok
1505        dFdx[iBeg:iFin] = 2.*np.sum(fams[:,:,nxs,nxs]*dfadx+fbms[:,:,nxs,nxs]*dfbdx,axis=0)         #ok
1506        dFdui[iBeg:iFin] = 2.*np.sum(fams[:,:,nxs]*dfadui+fbms[:,:,nxs]*dfbdui,axis=0)              #ok
1507        dFdua[iBeg:iFin] = 2.*np.sum(fams[:,:,nxs,nxs]*dfadua+fbms[:,:,nxs,nxs]*dfbdua,axis=0)      #ok
1508        iBeg += blkSize
1509    print (' %d derivative time %.4f\r'%(nRef,time.time()-time0))
1510        #loop over atoms - each dict entry is list of derivatives for all the reflections
1511    for i in range(len(Mdata)):
1512        dFdvDict[pfx+'Afrac:'+str(i)] = dFdfr.T[i]
1513        dFdvDict[pfx+'dAx:'+str(i)] = dFdx.T[0][i]
1514        dFdvDict[pfx+'dAy:'+str(i)] = dFdx.T[1][i]
1515        dFdvDict[pfx+'dAz:'+str(i)] = dFdx.T[2][i]
1516        dFdvDict[pfx+'AUiso:'+str(i)] = dFdui.T[i]
1517        dFdvDict[pfx+'AU11:'+str(i)] = dFdua.T[0][i]
1518        dFdvDict[pfx+'AU22:'+str(i)] = dFdua.T[1][i]
1519        dFdvDict[pfx+'AU33:'+str(i)] = dFdua.T[2][i]
1520        dFdvDict[pfx+'AU12:'+str(i)] = dFdua.T[3][i]
1521        dFdvDict[pfx+'AU13:'+str(i)] = dFdua.T[4][i]
1522        dFdvDict[pfx+'AU23:'+str(i)] = dFdua.T[5][i]
1523    return dFdvDict
1524       
1525def StructureFactorDervTw2(refDict,G,hfx,pfx,SGData,calcControls,parmDict):
1526    '''Compute structure factor derivatives on blocks of reflections - for twins only
1527    faster than StructureFactorDervTw
1528    input:
1529   
1530    :param dict refDict: where
1531        'RefList' list where each ref = h,k,l,it,d,...
1532        'FF' dict of form factors - filled in below
1533    :param np.array G:      reciprocal metric tensor
1534    :param str hfx:    histogram id string
1535    :param str pfx:    phase id string
1536    :param dict SGData: space group info. dictionary output from SpcGroup
1537    :param dict calcControls:
1538    :param dict parmDict:
1539   
1540    :returns: dict dFdvDict: dictionary of derivatives
1541    '''
1542    phfx = pfx.split(':')[0]+hfx
1543    ast = np.sqrt(np.diag(G))
1544    Mast = twopisq*np.multiply.outer(ast,ast)
1545    SGMT = np.array([ops[0].T for ops in SGData['SGOps']])
1546    SGT = np.array([ops[1] for ops in SGData['SGOps']])
1547    FFtables = calcControls['FFtables']
1548    BLtables = calcControls['BLtables']
1549    TwDict = refDict.get('TwDict',{})           
1550    NTL = calcControls[phfx+'NTL']
1551    NM = calcControls[phfx+'TwinNMN']+1
1552    TwinLaw = calcControls[phfx+'TwinLaw']
1553    TwinFr = np.array([parmDict[phfx+'TwinFr:'+str(i)] for i in range(len(TwinLaw))])
1554    TwinInv = list(np.where(calcControls[phfx+'TwinInv'],-1,1))
1555    nTwin = len(TwinLaw)       
1556    nRef = len(refDict['RefList'])
1557    Tdata,Mdata,Fdata,Xdata,dXdata,IAdata,Uisodata,Uijdata,Gdata = \
1558        GetAtomFXU(pfx,calcControls,parmDict)
1559    if not Xdata.size:          #no atoms in phase!
1560        return {}
1561    mSize = len(Mdata)
1562    FF = np.zeros(len(Tdata))
1563    if 'NC' in calcControls[hfx+'histType'] or 'NB' in calcControls[hfx+'histType']:
1564        FP,FPP = G2el.BlenResCW(Tdata,BLtables,parmDict[hfx+'Lam'])
1565    elif 'X' in calcControls[hfx+'histType']:
1566        FP = np.array([FFtables[El][hfx+'FP'] for El in Tdata])
1567        FPP = np.array([FFtables[El][hfx+'FPP'] for El in Tdata])
1568    elif 'SEC' in calcControls[hfx+'histType']:
1569        FP = np.zeros(len(Tdata))
1570        FPP = np.zeros(len(Tdata))
1571       
1572    Uij = np.array(G2lat.U6toUij(Uijdata))
1573    bij = Mast*Uij.T
1574    dFdvDict = {}
1575    dFdfr = np.zeros((nRef,nTwin,mSize))
1576    dFdx = np.zeros((nRef,nTwin,mSize,3))
1577    dFdui = np.zeros((nRef,nTwin,mSize))
1578    dFdua = np.zeros((nRef,nTwin,mSize,6))
1579    dFdbab = np.zeros((nRef,nTwin,2))
1580    dFdtw = np.zeros((nRef,nTwin))
1581    time0 = time.time()
1582#reflection processing begins here - big arrays!
1583    iBeg = 0
1584    blkSize = 16       #no. of reflections in a block - optimized for speed
1585    while iBeg < nRef:
1586        iFin = min(iBeg+blkSize,nRef)
1587        refl = refDict['RefList'][iBeg:iFin]    #array(blkSize,nItems)
1588        H = refl.T[:3]
1589        H = np.inner(H.T,TwinLaw)   #array(3,nTwins)
1590        TwMask = np.any(H,axis=-1)
1591        for ir in range(blkSize):
1592            iref = ir+iBeg
1593            if iref in TwDict:
1594                for i in TwDict[iref]:
1595                    for n in range(NTL):
1596                        H[ir][i+n*NM] = np.inner(TwinLaw[n*NM],np.array(TwDict[iref][i])*TwinInv[i+n*NM])
1597        TwMask = np.any(H,axis=-1)
1598        SQ = 1./(2.*refl.T[4])**2             # or (sin(theta)/lambda)**2
1599        SQfactor = 8.0*SQ*np.pi**2
1600        if 'T' in calcControls[hfx+'histType']:
1601            if 'P' in calcControls[hfx+'histType']:
1602                FP,FPP = G2el.BlenResTOF(Tdata,BLtables,refl.T[14])
1603            else:
1604                FP,FPP = G2el.BlenResTOF(Tdata,BLtables,refl.T[12])
1605            FP = np.repeat(FP.T,len(SGT)*len(TwinLaw),axis=0)
1606            FPP = np.repeat(FPP.T,len(SGT)*len(TwinLaw),axis=0)
1607        dBabdA = np.exp(-parmDict[phfx+'BabU']*SQfactor)
1608        Bab = np.repeat(parmDict[phfx+'BabA']*dBabdA,len(SGT)*nTwin)
1609        Tindx = np.array([refDict['FF']['El'].index(El) for El in Tdata])
1610        FF = np.repeat(refDict['FF']['FF'][iBeg:iFin].T[Tindx].T,len(SGT)*len(TwinLaw),axis=0)
1611        Uniq = np.inner(H,SGMT)             # (nTwin,nSGOp,3)
1612        Phi = np.inner(H,SGT)
1613        phase = twopi*(np.inner(Uniq,(dXdata+Xdata).T).T+Phi.T).T
1614        sinp = np.sin(phase)
1615        cosp = np.cos(phase)
1616        occ = Mdata*Fdata/len(SGT)
1617        biso = -SQfactor*Uisodata[:,nxs]
1618        Tiso = np.repeat(np.where(biso<1.,np.exp(biso),1.0),len(SGT)*nTwin,axis=1)
1619        HbH = -np.sum(Uniq.T*np.swapaxes(np.inner(bij,Uniq),2,-1),axis=1)
1620        Hij = np.array([Mast*np.multiply.outer(U,U) for U in np.reshape(Uniq,(-1,3))])
1621        Hij = np.reshape(np.array([G2lat.UijtoU6(uij) for uij in Hij]),(-1,nTwin,len(SGT),6))
1622        Tuij = np.where(HbH<1.,np.exp(HbH),1.0)
1623        Tcorr = (np.reshape(Tiso,Tuij.shape)*Tuij).T*Mdata*Fdata/len(SGMT)
1624        fot = np.reshape(((FF+FP).T-Bab).T,cosp.shape)*Tcorr
1625        fotp = FPP*Tcorr       
1626        if 'T' in calcControls[hfx+'histType']: #fa,fb are 2 X blkSize X nTwin X nOps x nAtoms
1627            fa = np.array([np.reshape(((FF+FP).T-Bab).T,cosp.shape)*cosp*Tcorr,-np.reshape(FPP,sinp.shape)*sinp*Tcorr])
1628            fb = np.array([np.reshape(((FF+FP).T-Bab).T,sinp.shape)*sinp*Tcorr,np.reshape(FPP,cosp.shape)*cosp*Tcorr])
1629        else:
1630            fa = np.array([np.reshape(((FF+FP).T-Bab).T,cosp.shape)*cosp*Tcorr,-FPP*sinp*Tcorr])
1631            fb = np.array([np.reshape(((FF+FP).T-Bab).T,sinp.shape)*sinp*Tcorr,FPP*cosp*Tcorr])
1632        fas = np.sum(np.sum(fa,axis=-1),axis=-1)      #real sum over atoms & unique hkl array(2,nTwins)
1633        fbs = np.sum(np.sum(fb,axis=-1),axis=-1)      #imag sum over atoms & uniq hkl
1634        if SGData['SGInv']: #centrosymmetric; B=0
1635            fbs[0] *= 0.
1636            fas[1] *= 0.
1637        fax = np.array([-fot*sinp,-fotp*cosp])   #positions array(2,nRef,ntwi,nEqv,nAtoms)
1638        fbx = np.array([fot*cosp,-fotp*sinp])
1639        #sum below is over Uniq
1640        dfadfr = np.sum(np.sum(fa/occ,axis=-2),axis=0)        #array(2,nRef,ntwin,nAtom) Fdata != 0 avoids /0. problem
1641        dfadba = np.sum(-cosp*Tcorr[:,nxs],axis=1)
1642        dfadui = np.sum(np.sum(-SQfactor[nxs,:,nxs,nxs,nxs]*fa,axis=-2),axis=0)           
1643        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'
1644        dfadua = np.sum(np.sum(-Hij[nxs,:,:,:,nxs,:]*fa[:,:,:,:,:,nxs],axis=-3),axis=0) 
1645        if not SGData['SGInv']:
1646            dfbdfr = np.sum(np.sum(fb/occ,axis=-2),axis=0)        #Fdata != 0 avoids /0. problem
1647            dfadba /= 2.
1648#            dfbdba = np.sum(-sinp*Tcorr[:,nxs],axis=1)/2.
1649            dfbdui = np.sum(np.sum(-SQfactor[nxs,:,nxs,nxs,nxs]*fb,axis=-2),axis=0)
1650            dfbdx = np.sum(np.sum(twopi*Uniq[nxs,:,:,:,nxs,:]*fbx[:,:,:,:,:,nxs],axis=-3),axis=0)
1651            dfbdua = np.sum(np.sum(-Hij[nxs,:,:,:,nxs,:]*fb[:,:,:,:,:,nxs],axis=-3),axis=0)
1652        else:
1653            dfbdfr = np.zeros_like(dfadfr)
1654            dfbdx = np.zeros_like(dfadx)
1655            dfbdui = np.zeros_like(dfadui)
1656            dfbdua = np.zeros_like(dfadua)
1657#            dfbdba = np.zeros_like(dfadba)
1658        SA = fas[0]+fas[1]
1659        SB = fbs[0]+fbs[1]
1660        dFdfr[iBeg:iFin] = ((2.*TwMask*SA)[:,:,nxs]*dfadfr+(2.*TwMask*SB)[:,:,nxs]*dfbdfr)*Mdata[nxs,nxs,:]/len(SGMT)
1661        dFdx[iBeg:iFin] = (2.*TwMask*SA)[:,:,nxs,nxs]*dfadx+(2.*TwMask*SB)[:,:,nxs,nxs]*dfbdx
1662        dFdui[iBeg:iFin] = (2.*TwMask*SA)[:,:,nxs]*dfadui+(2.*TwMask*SB)[:,:,nxs]*dfbdui
1663        dFdua[iBeg:iFin] = (2.*TwMask*SA)[:,:,nxs,nxs]*dfadua+(2.*TwMask*SB)[:,:,nxs,nxs]*dfbdua
1664        if SGData['SGInv']: #centrosymmetric; B=0
1665            dFdtw[iBeg:iFin] = np.sum(TwMask[nxs,:]*fas,axis=0)**2
1666        else:               
1667            dFdtw[iBeg:iFin] = np.sum(TwMask[nxs,:]*fas,axis=0)**2+np.sum(TwMask[nxs,:]*fbs,axis=0)**2
1668#        dFdbab[iBeg:iFin] = fas[0,:,nxs]*np.array([np.sum(dfadba*dBabdA),np.sum(-dfadba*parmDict[phfx+'BabA']*SQfactor*dBabdA)]).T+ \
1669#            fbs[0,:,nxs]*np.array([np.sum(dfbdba*dBabdA),np.sum(-dfbdba*parmDict[phfx+'BabA']*SQfactor*dBabdA)]).T
1670        iBeg += blkSize
1671    print (' %d derivative time %.4f\r'%(len(refDict['RefList']),time.time()-time0))
1672    #loop over atoms - each dict entry is list of derivatives for all the reflections
1673    for i in range(len(Mdata)):     #these all OK
1674        dFdvDict[pfx+'Afrac:'+str(i)] = np.sum(dFdfr.T[i]*TwinFr[:,nxs],axis=0)
1675        dFdvDict[pfx+'dAx:'+str(i)] = np.sum(dFdx.T[0][i]*TwinFr[:,nxs],axis=0)
1676        dFdvDict[pfx+'dAy:'+str(i)] = np.sum(dFdx.T[1][i]*TwinFr[:,nxs],axis=0)
1677        dFdvDict[pfx+'dAz:'+str(i)] = np.sum(dFdx.T[2][i]*TwinFr[:,nxs],axis=0)
1678        dFdvDict[pfx+'AUiso:'+str(i)] = np.sum(dFdui.T[i]*TwinFr[:,nxs],axis=0)
1679        dFdvDict[pfx+'AU11:'+str(i)] = np.sum(dFdua.T[0][i]*TwinFr[:,nxs],axis=0)
1680        dFdvDict[pfx+'AU22:'+str(i)] = np.sum(dFdua.T[1][i]*TwinFr[:,nxs],axis=0)
1681        dFdvDict[pfx+'AU33:'+str(i)] = np.sum(dFdua.T[2][i]*TwinFr[:,nxs],axis=0)
1682        dFdvDict[pfx+'AU12:'+str(i)] = np.sum(dFdua.T[3][i]*TwinFr[:,nxs],axis=0)
1683        dFdvDict[pfx+'AU13:'+str(i)] = np.sum(dFdua.T[4][i]*TwinFr[:,nxs],axis=0)
1684        dFdvDict[pfx+'AU23:'+str(i)] = np.sum(dFdua.T[5][i]*TwinFr[:,nxs],axis=0)
1685    dFdvDict[phfx+'BabA'] = dFdbab.T[0]
1686    dFdvDict[phfx+'BabU'] = dFdbab.T[1]
1687    for i in range(nTwin):
1688        dFdvDict[phfx+'TwinFr:'+str(i)] = dFdtw.T[i]
1689    return dFdvDict
1690   
1691def SStructureFactor(refDict,G,hfx,pfx,SGData,SSGData,calcControls,parmDict):
1692    '''
1693    Compute super structure factors for all h,k,l,m for phase - no twins
1694    puts the result, F^2, in each ref[9] in refList
1695    works on blocks of 32 reflections for speed
1696    input:
1697   
1698    :param dict refDict: where
1699        'RefList' list where each ref = h,k,l,m,it,d,...
1700        'FF' dict of form factors - filed in below
1701    :param np.array G:      reciprocal metric tensor
1702    :param str pfx:    phase id string
1703    :param dict SGData: space group info. dictionary output from SpcGroup
1704    :param dict calcControls:
1705    :param dict ParmDict:
1706
1707    '''
1708    phfx = pfx.split(':')[0]+hfx
1709    ast = np.sqrt(np.diag(G))
1710    GS = G/np.outer(ast,ast)
1711    uAmat,uBmat = G2lat.Gmat2AB(GS)
1712    Amat,Bmat = G2lat.Gmat2AB(G)
1713    Mast = twopisq*np.multiply.outer(ast,ast)   
1714    SGInv = SGData['SGInv']
1715    SGMT = np.array([ops[0].T for ops in SGData['SGOps']])
1716    Nops = len(SGMT)*(1+SGData['SGInv'])
1717    if SGData['SGGray']:
1718        Nops *= 2
1719    SSGMT = np.array([ops[0].T for ops in SSGData['SSGOps']])
1720    GamI = np.array([ops[0][3,3] for ops in SSGData['SSGOps']])
1721    if SGData['SGInv']:
1722        GamI = np.hstack((GamI,-GamI))
1723    GamI = np.hstack([GamI for cen in SGData['SGCen']])
1724    if SGData['SGGray']:
1725        GamI = np.hstack((GamI,GamI))
1726    SSGT = np.array([ops[1] for ops in SSGData['SSGOps']])
1727    SSCen = SSGData['SSGCen']
1728    FFtables = calcControls['FFtables']
1729    EFtables = calcControls['EFtables']
1730    BLtables = calcControls['BLtables']
1731    MFtables = calcControls['MFtables']
1732    Flack = 1.0
1733    if not SGData['SGInv'] and 'S' in calcControls[hfx+'histType'] and phfx+'Flack' in parmDict:
1734        Flack = 1.-2.*parmDict[phfx+'Flack']
1735    Tdata,Mdata,Fdata,Xdata,dXdata,IAdata,Uisodata,Uijdata,Gdata = \
1736        GetAtomFXU(pfx,calcControls,parmDict)
1737    if not Xdata.size:          #no atoms in phase!
1738        return
1739    waveTypes,FSSdata,XSSdata,USSdata,MSSdata = GetAtomSSFXU(pfx,calcControls,parmDict)
1740    ngl,nWaves,Fmod,Xmod,Umod,Mmod,glTau,glWt = G2mth.makeWaves(waveTypes,FSSdata,XSSdata,USSdata,MSSdata,Mast)      #NB: Mmod is ReIm,Mxyz,Ntau,Natm
1741    modQ = np.array([parmDict[pfx+'mV0'],parmDict[pfx+'mV1'],parmDict[pfx+'mV2']])
1742
1743    if parmDict[pfx+'isMag']:       #This part correct for making modulated mag moments on equiv atoms - Mmod matched drawing & Bilbao drawings
1744   
1745        # 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
1746        # if SGData['SGGray']:
1747        #     mXYZ = np.hstack((mXYZ,mXYZ))
1748
1749#        MmodAR,MmodBR,MmodAI,MmodBI = G2mth.MagMod(glTau,mXYZ,modQ,MSSdata,SGData,SSGData)  #Ntau,Nops,Natm,Mxyz cos,sin parts sum matches drawing
1750        mXYZ,MmodAR,MmodBR,MmodAI,MmodBI = G2mth.MagMod2(glTau,Xdata+dXdata,modQ,MSSdata,SGData,SSGData)  #Ntau,Nops,Natm,Mxyz cos,sin parts sum matches drawing
1751        #expand Mmod over mag symm ops. --> GSSdata
1752        if not SGData['SGGray']:    #for fixed Mx,My,Mz
1753            GSdata = np.inner(Gdata.T,np.swapaxes(SGMT,1,2))  #apply sym. ops.--> Natm,Nops,Nxyz
1754            if SGData['SGInv'] and not SGData['SGFixed']:   #inversion if any
1755                GSdata = np.hstack((GSdata,-GSdata))     
1756            GSdata = np.hstack([GSdata for cen in SSCen])        #dup over cell centering - Natm,Nops,Mxyz
1757            GSdata = SGData['MagMom'][nxs,:,nxs]*GSdata   #flip vectors according to spin flip * det(opM)
1758            GSdata = np.swapaxes(GSdata,0,1)    #Nop,Natm,Mxyz
1759       
1760    FF = np.zeros(len(Tdata))
1761    if 'NC' in calcControls[hfx+'histType'] or 'NB' in calcControls[hfx+'histType']:
1762        FP,FPP = G2el.BlenResCW(Tdata,BLtables,parmDict[hfx+'Lam'])
1763    elif 'X' in calcControls[hfx+'histType']:
1764        FP = np.array([FFtables[El][hfx+'FP'] for El in Tdata])
1765        FPP = np.array([FFtables[El][hfx+'FPP'] for El in Tdata])
1766    elif 'SEC' in calcControls[hfx+'histType']:
1767        FP = np.zeros(len(Tdata))
1768        FPP = np.zeros(len(Tdata))
1769    Uij = np.array(G2lat.U6toUij(Uijdata)).T
1770    bij = Mast*Uij
1771    blkSize = 48       #no. of reflections in a block
1772    nRef = refDict['RefList'].shape[0]
1773    SQ = 1./(2.*refDict['RefList'].T[5])**2
1774    if 'N' in calcControls[hfx+'histType']:
1775        dat = G2el.getBLvalues(BLtables)
1776        refDict['FF']['El'] = list(dat.keys())
1777        refDict['FF']['FF'] = np.ones((nRef,len(dat)))*list(dat.values())
1778        refDict['FF']['MF'] = np.zeros((nRef,len(dat)))
1779        for iel,El in enumerate(refDict['FF']['El']):
1780            if El in MFtables:
1781                refDict['FF']['MF'].T[iel] = G2el.MagScatFac(MFtables[El],SQ)
1782    elif 'SEC' in calcControls[hfx+'histType']:
1783        dat = G2el.getFFvalues(EFtables,0.)
1784        refDict['FF']['El'] = list(dat.keys())
1785        refDict['FF']['FF'] = np.zeros((nRef,len(dat)))
1786        for iel,El in enumerate(refDict['FF']['El']):
1787            refDict['FF']['FF'].T[iel] = G2el.ScatFac(EFtables[El],SQ)       
1788    else:
1789        dat = G2el.getFFvalues(FFtables,0.)
1790        refDict['FF']['El'] = list(dat.keys())
1791        refDict['FF']['FF'] = np.zeros((nRef,len(dat)))
1792        for iel,El in enumerate(refDict['FF']['El']):
1793            refDict['FF']['FF'].T[iel] = G2el.ScatFac(FFtables[El],SQ)
1794#reflection processing begins here - big arrays!
1795    iBeg = 0
1796    while iBeg < nRef:
1797        iFin = min(iBeg+blkSize,nRef)
1798        mRef= iFin-iBeg
1799        refl = refDict['RefList'][iBeg:iFin]    #array(blkSize,nItems)
1800        H = refl.T[:4]                          #array(blkSize,4)
1801        HP = H[:3]+modQ[:,nxs]*H[3:]            #projected hklm to hkl
1802        SQ = 1./(2.*refl.T[5])**2               #array(blkSize)
1803        SQfactor = 4.0*SQ*twopisq               #ditto prev.
1804        Uniq = np.inner(H.T,SSGMT)
1805        UniqP = np.inner(HP.T,SGMT)
1806        Phi = np.inner(H.T,SSGT)
1807        if SGInv and not SGData['SGFixed']:   #if centro - expand HKL sets
1808            Uniq = np.hstack((Uniq,-Uniq))
1809            Phi = np.hstack((Phi,-Phi))
1810            UniqP = np.hstack((UniqP,-UniqP))
1811        if 'T' in calcControls[hfx+'histType']:
1812            if 'P' in calcControls[hfx+'histType']:
1813                FP,FPP = G2el.BlenResTOF(Tdata,BLtables,refl.T[14])
1814            else:
1815                FP,FPP = G2el.BlenResTOF(Tdata,BLtables,refl.T[12])
1816            FP = np.repeat(FP.T,Uniq.shape[1],axis=0)
1817            FPP = np.repeat(FPP.T,Uniq.shape[1],axis=0)
1818        Bab = 0.
1819        if phfx+'BabA' in parmDict:
1820            Bab = np.repeat(parmDict[phfx+'BabA']*np.exp(-parmDict[phfx+'BabU']*SQfactor),Uniq.shape[1])
1821        Tindx = np.array([refDict['FF']['El'].index(El) for El in Tdata])
1822        FF = np.repeat(refDict['FF']['FF'][iBeg:iFin].T[Tindx].T,Uniq.shape[1],axis=0)
1823        phase = twopi*(np.inner(Uniq[:,:,:3],(dXdata.T+Xdata.T))-Phi[:,:,nxs])
1824        sinp = np.sin(phase)
1825        cosp = np.cos(phase)
1826        biso = -SQfactor*Uisodata[:,nxs]
1827        Tiso = np.repeat(np.where(biso<1.,np.exp(biso),1.0),Uniq.shape[1],axis=1).T
1828        HbH = -np.sum(UniqP[:,:,nxs,:]*np.inner(UniqP[:,:,:],bij),axis=-1)  #use hklt proj to hkl
1829        Tuij = np.where(HbH<1.,np.exp(HbH),1.0)
1830        Tcorr = np.reshape(Tiso,Tuij.shape)*Tuij*Mdata*Fdata/Uniq.shape[1]  #refBlk x ops x atoms
1831
1832        if 'N' in calcControls[hfx+'histType'] and parmDict[pfx+'isMag']:           
1833           
1834            phasem = twopi*np.inner(mXYZ,HP.T).T    #2pi(Q.r)
1835            cosm = np.cos(phasem)                   #Nref,nops,natm
1836            sinm = np.sin(phasem)
1837            MF = refDict['FF']['MF'][iBeg:iFin].T[Tindx].T   #Nref,Natm
1838            TMcorr = 0.539*(np.reshape(Tiso,Tuij.shape)*Tuij)[:,0,:]*Mdata*Fdata*MF/(2*Nops)     #Nref,Natm
1839            HM = np.inner(Bmat,HP.T)                #put into cartesian space X||H,Z||H*L; Bmat.T correct Cart coordinates
1840            eM = (HM*refl.T[5]).T                   # normalize HP by d*    Nref,hkl=Unit vectors || Q
1841
1842            if not SGData['SGGray']:     #correct -fixed Mx,My,Mz contribution             
1843                fam0 = TMcorr[:,nxs,:,nxs]*GSdata[nxs,:,:,:]*cosm[:,:,:,nxs]    #Nref,Nops,Natm,Mxyz
1844                fbm0 = TMcorr[:,nxs,:,nxs]*GSdata[nxs,:,:,:]*sinm[:,:,:,nxs]
1845#  calc mag. structure factors; Nref,Ntau,Nops,Natm,Mxyz                           
1846            fams = TMcorr[:,nxs,nxs,:,nxs]*SGData['MagMom'][nxs,nxs,:,nxs,nxs]*np.array([np.where(H[3,i]!=0,(
1847                (-MmodAR+H[3,i]*MmodBR)*cosm[i,nxs,:,:,nxs]+   
1848                GamI[nxs,:,nxs,nxs]*(MmodAI-H[3,i]*MmodBI)*sinm[i,nxs,:,:,nxs]),
1849                0.) for i in range(mRef)])/2.          #Nref,Ntau,Nops,Natm,Mxyz
1850                       
1851            fbms = TMcorr[:,nxs,nxs,:,nxs]*SGData['MagMom'][nxs,nxs,:,nxs,nxs]*np.array([np.where(H[3,i]!=0,(
1852                (MmodAR-H[3,i]*MmodBR)*sinm[i,nxs,:,:,nxs]+   
1853                GamI[nxs,:,nxs,nxs]*(-MmodAI+H[3,i]*MmodBI)*cosm[i,nxs,:,:,nxs]),
1854                0.) for i in range(mRef)])/2.          #Nref,Ntau,Nops,Natm,Mxyz
1855           
1856            if not SGData['SGGray']:
1857                fams += fam0[:,nxs,:,:,:]
1858                fbms += fbm0[:,nxs,:,:,:]
1859                               
1860#sum ops & atms                               
1861            fasm = np.sum(np.sum(fams,axis=-2),axis=-2)    #Nref,Ntau,Mxyz; sum ops & atoms
1862            fbsm = np.sum(np.sum(fbms,axis=-2),axis=-2)
1863# #put into cartesian space
1864            facm = np.inner(fasm,uBmat)       #uBmat best fit for DyMnGe; +,- & -,+ fams, fbms; Nref, Ntau, Mxyz
1865            fbcm = np.inner(fbsm,uBmat)         #Nref,Ntau,Mxyz
1866#form e.F dot product
1867            eDotFa = np.sum(eM[:,nxs,:]*facm,axis=-1)    #Nref,Ntau       
1868            eDotFb = np.sum(eM[:,nxs,:]*fbcm,axis=-1)
1869#intensity Halpern & Johnson
1870            fass = np.sum((facm-eM[:,nxs,:]*eDotFa[:,:,nxs])**2,axis=-1)    #Nref,Ntau
1871            fbss = np.sum((fbcm-eM[:,nxs,:]*eDotFb[:,:,nxs])**2,axis=-1)
1872# gray *2
1873            if SGData['SGGray']:
1874                fass *= 2.
1875                fbss *= 2.
1876## #do integration           
1877            fas = np.sum(fass*glWt[nxs,:],axis=1)
1878            fbs = np.sum(fbss*glWt[nxs,:],axis=1)
1879           
1880            refl.T[10] = fas+fbs   #Sum(fams**2,Mxyz) Re + Im
1881            refl.T[11] = atan2d(fbs,fas)
1882
1883        else:
1884            GfpuA = G2mth.Modulation(Uniq,UniqP,nWaves,Fmod,Xmod,Umod,glTau,glWt) #2 x refBlk x sym X atoms
1885            if 'T' in calcControls[hfx+'histType']:
1886                fa = np.array([np.reshape(((FF+FP).T-Bab).T,cosp.shape)*cosp*Tcorr,-np.reshape(Flack*FPP,sinp.shape)*sinp*Tcorr])
1887                fb = np.array([np.reshape(Flack*FPP,cosp.shape)*cosp*Tcorr,np.reshape(((FF+FP).T-Bab).T,sinp.shape)*sinp*Tcorr])
1888            else:
1889                fa = np.array([np.reshape(((FF+FP).T-Bab).T,cosp.shape)*cosp*Tcorr,-Flack*FPP*sinp*Tcorr])
1890                fb = np.array([Flack*FPP*cosp*Tcorr,np.reshape(((FF+FP).T-Bab).T,sinp.shape)*sinp*Tcorr])
1891            fag = fa*GfpuA[0]-fb*GfpuA[1]   #real; 2 x refBlk x sym x atoms
1892            fbg = fb*GfpuA[0]+fa*GfpuA[1]
1893            fas = np.sum(np.sum(fag,axis=-1),axis=-1)   #2 x refBlk; sum sym & atoms
1894            fbs = np.sum(np.sum(fbg,axis=-1),axis=-1)
1895           
1896            refl.T[10] = np.sum(fas,axis=0)**2+np.sum(fbs,axis=0)**2    #square of sums
1897            refl.T[11] = atan2d(fbs[0],fas[0])  #use only tau=0; ignore f' & f"
1898        if 'P' not in calcControls[hfx+'histType']:
1899            refl.T[8] = np.copy(refl.T[10])               
1900        iBeg += blkSize
1901    return copy.deepcopy(refDict['RefList'])
1902
1903def SStructureFactorTw(refDict,G,hfx,pfx,SGData,SSGData,calcControls,parmDict):
1904    '''
1905    Compute super structure factors for all h,k,l,m for phase - twins only
1906    puts the result, F^2, in each ref[8+im] in refList
1907    works on blocks of 32 reflections for speed
1908    input:
1909   
1910    :param dict refDict: where
1911        'RefList' list where each ref = h,k,l,m,it,d,...
1912        'FF' dict of form factors - filed in below
1913    :param np.array G:      reciprocal metric tensor
1914    :param str pfx:    phase id string
1915    :param dict SGData: space group info. dictionary output from SpcGroup
1916    :param dict calcControls:
1917    :param dict ParmDict:
1918
1919    '''
1920    phfx = pfx.split(':')[0]+hfx
1921    ast = np.sqrt(np.diag(G))
1922    Mast = twopisq*np.multiply.outer(ast,ast)   
1923    SGInv = SGData['SGInv']
1924    SGMT = np.array([ops[0].T for ops in SGData['SGOps']])
1925    SSGMT = np.array([ops[0].T for ops in SSGData['SSGOps']])
1926    SSGT = np.array([ops[1] for ops in SSGData['SSGOps']])
1927    FFtables = calcControls['FFtables']
1928    EFtables = calcControls['EFtables']
1929    BLtables = calcControls['BLtables']
1930    MFtables = calcControls['MFtables']
1931    Flack = 1.0
1932    if not SGData['SGInv'] and 'S' in calcControls[hfx+'histType'] and phfx+'Flack' in parmDict:
1933        Flack = 1.-2.*parmDict[phfx+'Flack']
1934    TwinLaw = np.array([[[1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1]],])    #4D?
1935    TwDict = refDict.get('TwDict',{})           
1936    if 'S' in calcControls[hfx+'histType']:
1937        NTL = calcControls[phfx+'NTL']
1938        NM = calcControls[phfx+'TwinNMN']+1
1939        TwinLaw = calcControls[phfx+'TwinLaw']  #this'll have to be 4D also...
1940        TwinFr = np.array([parmDict[phfx+'TwinFr:'+str(i)] for i in range(len(TwinLaw))])
1941        TwinInv = list(np.where(calcControls[phfx+'TwinInv'],-1,1))
1942    Tdata,Mdata,Fdata,Xdata,dXdata,IAdata,Uisodata,Uijdata,Gdata = \
1943        GetAtomFXU(pfx,calcControls,parmDict)
1944    if not Xdata.size:          #no atoms in phase!
1945        return
1946    waveTypes,FSSdata,XSSdata,USSdata,MSSdata = GetAtomSSFXU(pfx,calcControls,parmDict)
1947    ngl,nWaves,Fmod,Xmod,Umod,Mmod,glTau,glWt = G2mth.makeWaves(waveTypes,FSSdata,XSSdata,USSdata,Mast)
1948    modQ = np.array([parmDict[pfx+'mV0'],parmDict[pfx+'mV1'],parmDict[pfx+'mV2']])
1949    FF = np.zeros(len(Tdata))
1950    if 'NC' in calcControls[hfx+'histType'] or 'NB' in calcControls[hfx+'histType']:
1951        FP,FPP = G2el.BlenResCW(Tdata,BLtables,parmDict[hfx+'Lam'])
1952    elif 'X' in calcControls[hfx+'histType']:
1953        FP = np.array([FFtables[El][hfx+'FP'] for El in Tdata])
1954        FPP = np.array([FFtables[El][hfx+'FPP'] for El in Tdata])
1955    elif 'SEC' in calcControls[hfx+'histType']:
1956        FP = np.zeros(len(Tdata))
1957        FPP = np.zeros(len(Tdata))
1958    Uij = np.array(G2lat.U6toUij(Uijdata)).T
1959    bij = Mast*Uij
1960    blkSize = 32       #no. of reflections in a block
1961    nRef = refDict['RefList'].shape[0]
1962    if not len(refDict['FF']):                #no form factors - 1st time thru StructureFactor
1963        SQ = 1./(2.*refDict['RefList'].T[5])**2
1964        if 'N' in calcControls[hfx+'histType']:
1965            dat = G2el.getBLvalues(BLtables)
1966            refDict['FF']['El'] = list(dat.keys())
1967            refDict['FF']['FF'] = np.ones((nRef,len(dat)))*list(dat.values())
1968            refDict['FF']['MF'] = np.zeros((nRef,len(dat)))
1969            for iel,El in enumerate(refDict['FF']['El']):
1970                if El in MFtables:
1971                    refDict['FF']['MF'].T[iel] = G2el.MagScatFac(MFtables[El],SQ)
1972        elif 'SEC' in calcControls[hfx+'histType']:
1973            dat = G2el.getFFvalues(EFtables,0.)
1974            refDict['FF']['El'] = list(dat.keys())
1975            refDict['FF']['FF'] = np.zeros((nRef,len(dat)))
1976            for iel,El in enumerate(refDict['FF']['El']):
1977                refDict['FF']['FF'].T[iel] = G2el.ScatFac(EFtables[El],SQ)       
1978        else:
1979            dat = G2el.getFFvalues(FFtables,0.)
1980            refDict['FF']['El'] = list(dat.keys())
1981            refDict['FF']['FF'] = np.zeros((nRef,len(dat)))
1982            for iel,El in enumerate(refDict['FF']['El']):
1983                refDict['FF']['FF'].T[iel] = G2el.ScatFac(FFtables[El],SQ)
1984#    time0 = time.time()
1985#reflection processing begins here - big arrays!
1986    iBeg = 0
1987    while iBeg < nRef:
1988        iFin = min(iBeg+blkSize,nRef)
1989        refl = refDict['RefList'][iBeg:iFin]    #array(blkSize,nItems)
1990        H = refl[:,:4]                          #array(blkSize,4)
1991        H3 = refl[:,:3]
1992        HP = H[:,:3]+modQ[nxs,:]*H[:,3:]        #projected hklm to hkl
1993        HP = np.inner(HP,TwinLaw)             #array(blkSize,nTwins,4)
1994        H3 = np.inner(H3,TwinLaw)       
1995        TwMask = np.any(HP,axis=-1)
1996        if TwinLaw.shape[0] > 1 and TwDict: #need np.inner(TwinLaw[?],TwDict[iref][i])*TwinInv[i]
1997            for ir in range(blkSize):
1998                iref = ir+iBeg
1999                if iref in TwDict:
2000                    for i in TwDict[iref]:
2001                        for n in range(NTL):
2002                            HP[ir][i+n*NM] = np.inner(TwinLaw[n*NM],np.array(TwDict[iref][i])*TwinInv[i+n*NM])
2003                            H3[ir][i+n*NM] = np.inner(TwinLaw[n*NM],np.array(TwDict[iref][i])*TwinInv[i+n*NM])
2004            TwMask = np.any(HP,axis=-1)
2005        SQ = 1./(2.*refl.T[5])**2               #array(blkSize)
2006        SQfactor = 4.0*SQ*twopisq               #ditto prev.
2007        Uniq = np.inner(H,SSGMT)
2008        Uniq3 = np.inner(H3,SGMT)
2009        UniqP = np.inner(HP,SGMT)
2010        Phi = np.inner(H,SSGT)
2011        if SGInv:   #if centro - expand HKL sets
2012            Uniq = np.hstack((Uniq,-Uniq))
2013            Uniq3 = np.hstack((Uniq3,-Uniq3))
2014            Phi = np.hstack((Phi,-Phi))
2015            UniqP = np.hstack((UniqP,-UniqP))
2016        if 'T' in calcControls[hfx+'histType']:
2017            if 'P' in calcControls[hfx+'histType']:
2018                FP,FPP = G2el.BlenResTOF(Tdata,BLtables,refl.T[14])
2019            else:
2020                FP,FPP = G2el.BlenResTOF(Tdata,BLtables,refl.T[12])
2021            FP = np.repeat(FP.T,Uniq.shape[1]*len(TwinLaw),axis=0)
2022            FPP = np.repeat(FPP.T,Uniq.shape[1]*len(TwinLaw),axis=0)
2023        Bab = np.repeat(parmDict[phfx+'BabA']*np.exp(-parmDict[phfx+'BabU']*SQfactor),Uniq.shape[1]*len(TwinLaw))
2024        Tindx = np.array([refDict['FF']['El'].index(El) for El in Tdata])
2025        FF = np.repeat(refDict['FF']['FF'][iBeg:iFin].T[Tindx].T,Uniq.shape[1]*len(TwinLaw),axis=0)
2026        phase = twopi*(np.inner(Uniq3,(dXdata.T+Xdata.T))-Phi[:,nxs,:,nxs])
2027        sinp = np.sin(phase)
2028        cosp = np.cos(phase)
2029        biso = -SQfactor*Uisodata[:,nxs]
2030        Tiso = np.repeat(np.where(biso<1.,np.exp(biso),1.0),Uniq.shape[1]*len(TwinLaw),axis=1).T
2031        HbH = -np.sum(UniqP[:,:,:,nxs]*np.inner(UniqP[:,:,:],bij),axis=-1)  #use hklt proj to hkl
2032        Tuij = np.where(HbH<1.,np.exp(HbH),1.0)
2033        Tcorr = np.reshape(Tiso,Tuij.shape)*Tuij*Mdata*Fdata/Uniq.shape[1]  #refBlk x ops x atoms
2034        if 'T' in calcControls[hfx+'histType']:
2035            fa = np.array([np.reshape(((FF+FP).T-Bab).T,cosp.shape)*cosp*Tcorr,-np.reshape(Flack*FPP,sinp.shape)*sinp*Tcorr])
2036            fb = np.array([np.reshape(Flack*FPP,cosp.shape)*cosp*Tcorr,np.reshape(((FF+FP).T-Bab).T,sinp.shape)*sinp*Tcorr])
2037        else:
2038            fa = np.array([np.reshape(((FF+FP).T-Bab).T,cosp.shape)*cosp*Tcorr,-Flack*FPP*sinp*Tcorr])
2039            fb = np.array([Flack*FPP*cosp*Tcorr,np.reshape(((FF+FP).T-Bab).T,sinp.shape)*sinp*Tcorr])
2040        GfpuA = G2mth.ModulationTw(Uniq,UniqP,nWaves,Fmod,Xmod,Umod,glTau,glWt) #2 x refBlk x sym X atoms
2041        fag = fa*GfpuA[0]-fb*GfpuA[1]   #real; 2 x refBlk x sym x atoms
2042        fbg = fb*GfpuA[0]+fa*GfpuA[1]
2043        fas = np.sum(np.sum(fag,axis=-1),axis=-1)   #2 x refBlk; sum sym & atoms
2044        fbs = np.sum(np.sum(fbg,axis=-1),axis=-1)
2045        refl.T[10] = np.sum(fas[:,:,0],axis=0)**2+np.sum(fbs[:,:,0],axis=0)**2                  #FcT from primary twin element
2046        refl.T[8] = np.sum(TwinFr*np.sum(TwMask[nxs,:,:]*fas,axis=0)**2,axis=-1)+   \
2047            np.sum(TwinFr*np.sum(TwMask[nxs,:,:]*fbs,axis=0)**2,axis=-1)                 #Fc sum over twins
2048        refl.T[11] = atan2d(fbs[0].T[0],fas[0].T[0])  #ignore f' & f"
2049        iBeg += blkSize
2050#    print ('nRef %d time %.4f\r'%(nRef,time.time()-time0))
2051
2052def SStructureFactorDerv(refDict,im,G,hfx,pfx,SGData,SSGData,calcControls,parmDict):
2053    '''
2054    Compute super structure factor derivatives for all h,k,l,m for phase - no twins
2055    Only Fourier component are done analytically here
2056    input:
2057   
2058    :param dict refDict: where
2059        'RefList' list where each ref = h,k,l,m,it,d,...
2060        'FF' dict of form factors - filled in below
2061    :param int im: = 1 (could be eliminated)
2062    :param np.array G:      reciprocal metric tensor
2063    :param str hfx:    histogram id string
2064    :param str pfx:    phase id string
2065    :param dict SGData: space group info. dictionary output from SpcGroup
2066    :param dict SSGData: super space group info.
2067    :param dict calcControls:
2068    :param dict ParmDict:
2069   
2070    :returns: dict dFdvDict: dictionary of derivatives
2071    '''
2072    phfx = pfx.split(':')[0]+hfx
2073    ast = np.sqrt(np.diag(G))
2074    Mast = twopisq*np.multiply.outer(ast,ast)
2075    SGInv = SGData['SGInv']
2076    SGMT = np.array([ops[0].T for ops in SGData['SGOps']])
2077    SSGMT = np.array([ops[0].T for ops in SSGData['SSGOps']])
2078    SSGT = np.array([ops[1] for ops in SSGData['SSGOps']])
2079    FFtables = calcControls['FFtables']
2080    EFtables = calcControls['EFtables']
2081    BLtables = calcControls['BLtables']
2082    nRef = len(refDict['RefList'])
2083    Tdata,Mdata,Fdata,Xdata,dXdata,IAdata,Uisodata,Uijdata,Gdata = \
2084        GetAtomFXU(pfx,calcControls,parmDict)
2085    if not Xdata.size:          #no atoms in phase!
2086        return {}
2087    mSize = len(Mdata)  #no. atoms
2088    waveTypes,FSSdata,XSSdata,USSdata,MSSdata = GetAtomSSFXU(pfx,calcControls,parmDict)
2089    ngl,nWaves,Fmod,Xmod,Umod,Mmod,glTau,glWt = G2mth.makeWaves(waveTypes,FSSdata,XSSdata,USSdata,MSSdata,Mast)
2090    waveShapes,SCtauF,SCtauX,SCtauU,UmodAB = G2mth.makeWavesDerv(ngl,waveTypes,FSSdata,XSSdata,USSdata,Mast)
2091    modQ = np.array([parmDict[pfx+'mV0'],parmDict[pfx+'mV1'],parmDict[pfx+'mV2']])
2092    FF = np.zeros(len(Tdata))
2093    if 'NC' in calcControls[hfx+'histType'] or 'NB' in calcControls[hfx+'histType']:
2094        FP,FPP = G2el.BlenResCW(Tdata,BLtables,parmDict[hfx+'Lam'])
2095    elif 'X' in calcControls[hfx+'histType']:
2096        FP = np.array([FFtables[El][hfx+'FP'] for El in Tdata])
2097        FPP = np.array([FFtables[El][hfx+'FPP'] for El in Tdata])
2098    elif 'SEC' in calcControls[hfx+'histType']:
2099        FP = np.zeros(len(Tdata))
2100        FPP = np.zeros(len(Tdata))
2101    Uij = np.array(G2lat.U6toUij(Uijdata)).T
2102    bij = Mast*Uij
2103    if not len(refDict['FF']):
2104        if 'N' in calcControls[hfx+'histType']:
2105            dat = G2el.getBLvalues(BLtables)        #will need wave here for anom. neutron b's
2106        elif 'SEC' in calcControls[hfx+'histType']:
2107            dat = G2el.getFFvalues(EFtables,0.)
2108        else:
2109            dat = G2el.getFFvalues(FFtables,0.)       
2110        refDict['FF']['El'] = list(dat.keys())
2111        refDict['FF']['FF'] = np.zeros((len(refDict['RefList']),len(dat)))
2112    dFdvDict = {}
2113    dFdfr = np.zeros((nRef,mSize))
2114    dFdx = np.zeros((nRef,mSize,3))
2115    dFdui = np.zeros((nRef,mSize))
2116    dFdua = np.zeros((nRef,mSize,6))
2117    dFdbab = np.zeros((nRef,2))
2118    dFdfl = np.zeros((nRef))
2119    dFdGf = np.zeros((nRef,mSize,FSSdata.shape[1],2))
2120    dFdGx = np.zeros((nRef,mSize,XSSdata.shape[1],6))
2121    dFdGu = np.zeros((nRef,mSize,USSdata.shape[1],12))
2122    Flack = 1.0
2123    if not SGData['SGInv'] and 'S' in calcControls[hfx+'histType'] and phfx+'Flack' in parmDict:
2124        Flack = 1.-2.*parmDict[phfx+'Flack']
2125    time0 = time.time()
2126    nRef = len(refDict['RefList'])/100
2127    for iref,refl in enumerate(refDict['RefList']):
2128        if 'T' in calcControls[hfx+'histType']:
2129            FP,FPP = G2el.BlenResCW(Tdata,BLtables,refl.T[12+im])
2130        H = np.array(refl[:4])
2131        HP = H[:3]+modQ*H[3:]            #projected hklm to hkl
2132        SQ = 1./(2.*refl[4+im])**2             # or (sin(theta)/lambda)**2
2133        SQfactor = 8.0*SQ*np.pi**2
2134        Bab = 0.0
2135        if phfx+'BabA' in parmDict:
2136            dBabdA = np.exp(-parmDict[phfx+'BabU']*SQfactor)
2137            Bab = parmDict[phfx+'BabA']*dBabdA
2138        Tindx = np.array([refDict['FF']['El'].index(El) for El in Tdata])
2139        FF = refDict['FF']['FF'][iref].T[Tindx]
2140        Uniq = np.inner(H,SSGMT)
2141        Phi = np.inner(H,SSGT)
2142        UniqP = np.inner(HP,SGMT)
2143        if SGInv:   #if centro - expand HKL sets
2144            Uniq = np.vstack((Uniq,-Uniq))
2145            Phi = np.hstack((Phi,-Phi))
2146            UniqP = np.vstack((UniqP,-UniqP))
2147        phase = twopi*(np.inner(Uniq[:,:3],(dXdata+Xdata).T)+Phi[:,nxs])
2148        sinp = np.sin(phase)
2149        cosp = np.cos(phase)
2150        occ = Mdata*Fdata/Uniq.shape[0]
2151        biso = -SQfactor*Uisodata[:,nxs]
2152        Tiso = np.repeat(np.where(biso<1.,np.exp(biso),1.0),Uniq.shape[0],axis=1).T    #ops x atoms
2153        HbH = -np.sum(UniqP[:,nxs,:3]*np.inner(UniqP[:,:3],bij),axis=-1)  #ops x atoms
2154        Hij = np.array([Mast*np.multiply.outer(U[:3],U[:3]) for U in UniqP]) #atoms x 3x3
2155        Hij = np.array([G2lat.UijtoU6(uij) for uij in Hij])                     #atoms x 6
2156        Tuij = np.where(HbH<1.,np.exp(HbH),1.0)     #ops x atoms
2157        Tcorr = np.reshape(Tiso,Tuij.shape)*Tuij*Mdata*Fdata/Uniq.shape[0]  #ops x atoms
2158        fot = (FF+FP-Bab)*Tcorr     #ops x atoms
2159        fotp = FPP*Tcorr            #ops x atoms
2160        GfpuA = G2mth.Modulation(Uniq,UniqP,nWaves,Fmod,Xmod,Umod,glTau,glWt) #2 x sym X atoms
2161        dGdf,dGdx,dGdu = G2mth.ModulationDerv(Uniq,UniqP,Hij,nWaves,waveShapes,Fmod,Xmod,UmodAB,SCtauF,SCtauX,SCtauU,glTau,glWt)
2162        # GfpuA is 2 x ops x atoms
2163        # derivs are: ops x atoms x waves x 2,6,12, or 5 parms as [real,imag] parts
2164        fa = np.array([((FF+FP).T-Bab).T*cosp*Tcorr,-Flack*FPP*sinp*Tcorr]) # array(2,nEqv,nAtoms)
2165        fb = np.array([((FF+FP).T-Bab).T*sinp*Tcorr,Flack*FPP*cosp*Tcorr])  #or array(2,nEqv,nAtoms)
2166        fag = fa*GfpuA[0]-fb*GfpuA[1]
2167        fbg = fb*GfpuA[0]+fa*GfpuA[1]
2168       
2169        fas = np.sum(np.sum(fag,axis=1),axis=1)     # 2 x twin
2170        fbs = np.sum(np.sum(fbg,axis=1),axis=1)
2171        fax = np.array([-fot*sinp,-fotp*cosp])   #positions; 2 x ops x atoms
2172        fbx = np.array([fot*cosp,-fotp*sinp])
2173        fax = fax*GfpuA[0]-fbx*GfpuA[1]
2174        fbx = fbx*GfpuA[0]+fax*GfpuA[1]
2175        #sum below is over Uniq
2176        dfadfr = np.sum(fag/occ,axis=1)        #Fdata != 0 ever avoids /0. problem
2177        dfbdfr = np.sum(fbg/occ,axis=1)        #Fdata != 0 avoids /0. problem
2178        dfadba = np.sum(-cosp*Tcorr[:,nxs],axis=1)
2179        dfbdba = np.sum(-sinp*Tcorr[:,nxs],axis=1)
2180        dfadui = np.sum(-SQfactor*fag,axis=1)
2181        dfbdui = np.sum(-SQfactor*fbg,axis=1)
2182        dfadx = np.sum(twopi*Uniq[:,:3]*np.swapaxes(fax,-2,-1)[:,:,:,nxs],axis=-2)  #2 x nAtom x 3xyz; sum nOps
2183        dfbdx = np.sum(twopi*Uniq[:,:3]*np.swapaxes(fbx,-2,-1)[:,:,:,nxs],axis=-2)           
2184        dfadua = np.sum(-Hij*np.swapaxes(fag,-2,-1)[:,:,:,nxs],axis=-2)             #2 x nAtom x 6Uij; sum nOps
2185        dfbdua = np.sum(-Hij*np.swapaxes(fbg,-2,-1)[:,:,:,nxs],axis=-2)         #these are correct also for twins above
2186        # array(2,nAtom,nWave,2) & array(2,nAtom,nWave,6) & array(2,nAtom,nWave,12); sum on nOps
2187        dfadGf = np.sum(fa[:,:,:,nxs,nxs]*dGdf[0][nxs,:,:,:,:]-fb[:,:,:,nxs,nxs]*dGdf[1][nxs,:,:,:,:],axis=1)
2188        dfbdGf = np.sum(fb[:,:,:,nxs,nxs]*dGdf[0][nxs,:,:,:,:]+fa[:,:,:,nxs,nxs]*dGdf[1][nxs,:,:,:,:],axis=1)
2189        dfadGx = np.sum(fa[:,:,:,nxs,nxs]*dGdx[0][nxs,:,:,:,:]-fb[:,:,:,nxs,nxs]*dGdx[1][nxs,:,:,:,:],axis=1)
2190        dfbdGx = np.sum(fb[:,:,:,nxs,nxs]*dGdx[0][nxs,:,:,:,:]+fa[:,:,:,nxs,nxs]*dGdx[1][nxs,:,:,:,:],axis=1)
2191        dfadGu = np.sum(fa[:,:,:,nxs,nxs]*dGdu[0][nxs,:,:,:,:]-fb[:,:,:,nxs,nxs]*dGdu[1][nxs,:,:,:,:],axis=1)
2192        dfbdGu = np.sum(fb[:,:,:,nxs,nxs]*dGdu[0][nxs,:,:,:,:]+fa[:,:,:,nxs,nxs]*dGdu[1][nxs,:,:,:,:],axis=1)   
2193        if not SGData['SGInv']:   #Flack derivative
2194            dfadfl = np.sum(-FPP*Tcorr*sinp)
2195            dfbdfl = np.sum(FPP*Tcorr*cosp)
2196        else:
2197            dfadfl = 1.0
2198            dfbdfl = 1.0
2199        SA = fas[0]+fas[1]      #float = A+A'
2200        SB = fbs[0]+fbs[1]      #float = B+B'
2201        if 'P' in calcControls[hfx+'histType']: #checked perfect for centro & noncentro?
2202            dFdfl[iref] = -SA*dfadfl-SB*dfbdfl                  #array(nRef,)
2203            dFdfr[iref] = 2.*(fas[0]*dfadfr[0]+fas[1]*dfadfr[1])*Mdata/len(Uniq)+   \
2204                2.*(fbs[0]*dfbdfr[0]-fbs[1]*dfbdfr[1])*Mdata/len(Uniq)
2205            dFdx[iref] = 2.*(fas[0]*dfadx[0]+fas[1]*dfadx[1])+  \
2206                2.*(fbs[0]*dfbdx[0]+fbs[1]*dfbdx[1])
2207            dFdui[iref] = 2.*(fas[0]*dfadui[0]+fas[1]*dfadui[1])+   \
2208                2.*(fbs[0]*dfbdui[0]-fbs[1]*dfbdui[1])
2209            dFdua[iref] = 2.*(fas[0]*dfadua[0]+fas[1]*dfadua[1])+   \
2210                2.*(fbs[0]*dfbdua[0]+fbs[1]*dfbdua[1])
2211            dFdGf[iref] = 2.*(fas[0]*dfadGf[0]+fas[1]*dfadGf[1])+  \
2212                2.*(fbs[0]*dfbdGf[0]+fbs[1]*dfbdGf[1])
2213            dFdGx[iref] = 2.*(fas[0]*dfadGx[0]+fas[1]*dfadGx[1])+  \
2214                2.*(fbs[0]*dfbdGx[0]-fbs[1]*dfbdGx[1])
2215            dFdGu[iref] = 2.*(fas[0]*dfadGu[0]+fas[1]*dfadGu[1])+  \
2216                2.*(fbs[0]*dfbdGu[0]+fbs[1]*dfbdGu[1])
2217        else:                       #OK, I think
2218            dFdfr[iref] = 2.*(SA*dfadfr[0]+SA*dfadfr[1]+SB*dfbdfr[0]+SB*dfbdfr[1])*Mdata/len(Uniq) #array(nRef,nAtom)
2219            dFdx[iref] = 2.*(SA*dfadx[0]+SA*dfadx[1]+SB*dfbdx[0]+SB*dfbdx[1])    #array(nRef,nAtom,3)
2220            dFdui[iref] = 2.*(SA*dfadui[0]+SA*dfadui[1]+SB*dfbdui[0]+SB*dfbdui[1])   #array(nRef,nAtom)
2221            dFdua[iref] = 2.*(SA*dfadua[0]+SA*dfadua[1]+SB*dfbdua[0]+SB*dfbdua[1])    #array(nRef,nAtom,6)
2222            dFdfl[iref] = -SA*dfadfl-SB*dfbdfl                  #array(nRef,)
2223                           
2224            dFdGf[iref] = 2.*(SA*dfadGf[0]+SB*dfbdGf[1])      #array(nRef,natom,nwave,2)
2225            dFdGx[iref] = 2.*(SA*dfadGx[0]+SB*dfbdGx[1])      #array(nRef,natom,nwave,6)
2226            dFdGu[iref] = 2.*(SA*dfadGu[0]+SB*dfbdGu[1])      #array(nRef,natom,nwave,12)
2227        if phfx+'BabA' in parmDict:
2228            dFdbab[iref] = 2.*fas[0]*np.array([np.sum(dfadba*dBabdA),np.sum(-dfadba*parmDict[phfx+'BabA']*SQfactor*dBabdA)]).T+ \
2229                2.*fbs[0]*np.array([np.sum(dfbdba*dBabdA),np.sum(-dfbdba*parmDict[phfx+'BabA']*SQfactor*dBabdA)]).T
2230        #loop over atoms - each dict entry is list of derivatives for all the reflections
2231        if not iref%100 :
2232            print (' %d derivative time %.4f\r'%(iref,time.time()-time0),end='')
2233    for i in range(len(Mdata)):     #loop over atoms
2234        dFdvDict[pfx+'Afrac:'+str(i)] = dFdfr.T[i]
2235        dFdvDict[pfx+'dAx:'+str(i)] = dFdx.T[0][i]
2236        dFdvDict[pfx+'dAy:'+str(i)] = dFdx.T[1][i]
2237        dFdvDict[pfx+'dAz:'+str(i)] = dFdx.T[2][i]
2238        dFdvDict[pfx+'AUiso:'+str(i)] = dFdui.T[i]
2239        dFdvDict[pfx+'AU11:'+str(i)] = dFdua.T[0][i]
2240        dFdvDict[pfx+'AU22:'+str(i)] = dFdua.T[1][i]
2241        dFdvDict[pfx+'AU33:'+str(i)] = dFdua.T[2][i]
2242        dFdvDict[pfx+'AU12:'+str(i)] = dFdua.T[3][i]
2243        dFdvDict[pfx+'AU13:'+str(i)] = dFdua.T[4][i]
2244        dFdvDict[pfx+'AU23:'+str(i)] = dFdua.T[5][i]
2245        for j in range(FSSdata.shape[1]):        #loop over waves Fzero & Fwid?
2246            dFdvDict[pfx+'Fsin:'+str(i)+':'+str(j)] = dFdGf.T[0][j][i]
2247            dFdvDict[pfx+'Fcos:'+str(i)+':'+str(j)] = dFdGf.T[1][j][i]
2248        nx = 0
2249        if waveTypes[i] in ['Block','ZigZag']:
2250            nx = 1 
2251        for j in range(XSSdata.shape[1]-nx):       #loop over waves
2252            dFdvDict[pfx+'Xsin:'+str(i)+':'+str(j+nx)] = dFdGx.T[0][j][i]
2253            dFdvDict[pfx+'Ysin:'+str(i)+':'+str(j+nx)] = dFdGx.T[1][j][i]
2254            dFdvDict[pfx+'Zsin:'+str(i)+':'+str(j+nx)] = dFdGx.T[2][j][i]
2255            dFdvDict[pfx+'Xcos:'+str(i)+':'+str(j+nx)] = dFdGx.T[3][j][i]
2256            dFdvDict[pfx+'Ycos:'+str(i)+':'+str(j+nx)] = dFdGx.T[4][j][i]
2257            dFdvDict[pfx+'Zcos:'+str(i)+':'+str(j+nx)] = dFdGx.T[5][j][i]
2258        for j in range(USSdata.shape[1]):       #loop over waves
2259            dFdvDict[pfx+'U11sin:'+str(i)+':'+str(j)] = dFdGu.T[0][j][i]
2260            dFdvDict[pfx+'U22sin:'+str(i)+':'+str(j)] = dFdGu.T[1][j][i]
2261            dFdvDict[pfx+'U33sin:'+str(i)+':'+str(j)] = dFdGu.T[2][j][i]
2262            dFdvDict[pfx+'U12sin:'+str(i)+':'+str(j)] = dFdGu.T[3][j][i]
2263            dFdvDict[pfx+'U13sin:'+str(i)+':'+str(j)] = dFdGu.T[4][j][i]
2264            dFdvDict[pfx+'U23sin:'+str(i)+':'+str(j)] = dFdGu.T[5][j][i]
2265            dFdvDict[pfx+'U11cos:'+str(i)+':'+str(j)] = dFdGu.T[6][j][i]
2266            dFdvDict[pfx+'U22cos:'+str(i)+':'+str(j)] = dFdGu.T[7][j][i]
2267            dFdvDict[pfx+'U33cos:'+str(i)+':'+str(j)] = dFdGu.T[8][j][i]
2268            dFdvDict[pfx+'U12cos:'+str(i)+':'+str(j)] = dFdGu.T[9][j][i]
2269            dFdvDict[pfx+'U13cos:'+str(i)+':'+str(j)] = dFdGu.T[10][j][i]
2270            dFdvDict[pfx+'U23cos:'+str(i)+':'+str(j)] = dFdGu.T[11][j][i]
2271           
2272    dFdvDict[phfx+'Flack'] = 4.*dFdfl.T
2273    dFdvDict[phfx+'BabA'] = dFdbab.T[0]
2274    dFdvDict[phfx+'BabU'] = dFdbab.T[1]
2275    return dFdvDict
2276
2277def SStructureFactorDerv2(refDict,im,G,hfx,pfx,SGData,SSGData,calcControls,parmDict):
2278    '''
2279    Compute super structure factor derivatives for all h,k,l,m for phase - no twins
2280    input:
2281   
2282    :param dict refDict: where
2283        'RefList' list where each ref = h,k,l,m,it,d,...
2284        'FF' dict of form factors - filled in below
2285    :param int im: = 1 (could be eliminated)
2286    :param np.array G:      reciprocal metric tensor
2287    :param str hfx:    histogram id string
2288    :param str pfx:    phase id string
2289    :param dict SGData: space group info. dictionary output from SpcGroup
2290    :param dict SSGData: super space group info.
2291    :param dict calcControls:
2292    :param dict ParmDict:
2293   
2294    :returns: dict dFdvDict: dictionary of derivatives
2295    '''
2296
2297    trefDict = copy.deepcopy(refDict)
2298    dM = 1.e-4
2299    dFdvDict = {}
2300    for parm in parmDict:
2301        if ':' not in parm:
2302            continue
2303        if parm.split(':')[2] in ['Tmin','Tmax','Xmax','Ymax','Zmax','Fzero','Fwid',
2304            'MXsin','MXcos','MYsin','MYcos','MZsin','MZcos','AMx','AMy','AMz',]:
2305            parmDict[parm] += dM
2306            prefList = SStructureFactor(trefDict,G,hfx,pfx,SGData,SSGData,calcControls,parmDict)
2307            parmDict[parm] -= 2*dM
2308            mrefList = SStructureFactor(trefDict,G,hfx,pfx,SGData,SSGData,calcControls,parmDict)
2309            parmDict[parm] += dM
2310            dFdvDict[parm] = (prefList[:,9+im]-mrefList[:,9+im])/(2.*dM)
2311    return dFdvDict
2312   
2313def SStructureFactorDervTw(refDict,im,G,hfx,pfx,SGData,SSGData,calcControls,parmDict):
2314    'Needs a doc string'
2315    phfx = pfx.split(':')[0]+hfx
2316    ast = np.sqrt(np.diag(G))
2317    Mast = twopisq*np.multiply.outer(ast,ast)
2318    SGInv = SGData['SGInv']
2319    SGMT = np.array([ops[0].T for ops in SGData['SGOps']])
2320    SSGMT = np.array([ops[0].T for ops in SSGData['SSGOps']])
2321    SSGT = np.array([ops[1] for ops in SSGData['SSGOps']])
2322    FFtables = calcControls['FFtables']
2323    EFtables = calcControls['EFtables']
2324    BLtables = calcControls['BLtables']
2325    TwinLaw = np.array([[[1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1]],])
2326    TwDict = refDict.get('TwDict',{})           
2327    if 'S' in calcControls[hfx+'histType']:
2328        NTL = calcControls[phfx+'NTL']
2329        NM = calcControls[phfx+'TwinNMN']+1
2330        TwinLaw = calcControls[phfx+'TwinLaw']
2331        TwinInv = list(np.where(calcControls[phfx+'TwinInv'],-1,1))
2332    nTwin = len(TwinLaw)       
2333    nRef = len(refDict['RefList'])
2334    Tdata,Mdata,Fdata,Xdata,dXdata,IAdata,Uisodata,Uijdata,Gdata = \
2335        GetAtomFXU(pfx,calcControls,parmDict)
2336    if not Xdata.size:          #no atoms in phase!
2337        return {}
2338    mSize = len(Mdata)  #no. atoms
2339    waveTypes,FSSdata,XSSdata,USSdata,MSSdata = GetAtomSSFXU(pfx,calcControls,parmDict)
2340    ngl,nWaves,Fmod,Xmod,Umod,Mmod,glTau,glWt = G2mth.makeWaves(waveTypes,FSSdata,XSSdata,USSdata,MSSdata,Mast)     #NB: Mmod is ReIm,Mxyz,Ntau,Natm
2341    waveShapes,SCtauF,SCtauX,SCtauU,UmodAB = G2mth.makeWavesDerv(ngl,waveTypes,FSSdata,XSSdata,USSdata,Mast)
2342    modQ = np.array([parmDict[pfx+'mV0'],parmDict[pfx+'mV1'],parmDict[pfx+'mV2']])
2343    FF = np.zeros(len(Tdata))
2344    if 'NC' in calcControls[hfx+'histType'] or 'NB' in calcControls[hfx+'histType']:
2345        FP,FPP = G2el.BlenResCW(Tdata,BLtables,parmDict[hfx+'Lam'])
2346    elif 'X' in calcControls[hfx+'histType']:
2347        FP = np.array([FFtables[El][hfx+'FP'] for El in Tdata])
2348        FPP = np.array([FFtables[El][hfx+'FPP'] for El in Tdata])
2349    elif 'SEC' in calcControls[hfx+'histType']:
2350        FP = np.zeros(len(Tdata))
2351        FPP = np.zeros(len(Tdata))
2352    Uij = np.array(G2lat.U6toUij(Uijdata)).T
2353    bij = Mast*Uij
2354    if not len(refDict['FF']):
2355        if 'N' in calcControls[hfx+'histType']:
2356            dat = G2el.getBLvalues(BLtables)        #will need wave here for anom. neutron b's
2357        elif 'SEC' in calcControls[hfx+'histType']:
2358            dat = G2el.getFFvalues(EFtables,0.)       
2359        else:
2360            dat = G2el.getFFvalues(FFtables,0.)       
2361        refDict['FF']['El'] = list(dat.keys())
2362        refDict['FF']['FF'] = np.zeros((len(refDict['RefList']),len(dat)))
2363    dFdvDict = {}
2364    dFdfr = np.zeros((nRef,nTwin,mSize))
2365    dFdx = np.zeros((nRef,nTwin,mSize,3))
2366    dFdui = np.zeros((nRef,nTwin,mSize))
2367    dFdua = np.zeros((nRef,nTwin,mSize,6))
2368    dFdbab = np.zeros((nRef,nTwin,2))
2369    dFdtw = np.zeros((nRef,nTwin))
2370    dFdGf = np.zeros((nRef,nTwin,mSize,FSSdata.shape[1]))
2371    dFdGx = np.zeros((nRef,nTwin,mSize,XSSdata.shape[1],3))
2372    dFdGz = np.zeros((nRef,nTwin,mSize,5))
2373    dFdGu = np.zeros((nRef,nTwin,mSize,USSdata.shape[1],6))
2374    Flack = 1.0
2375    if not SGData['SGInv'] and 'S' in calcControls[hfx+'histType'] and phfx+'Flack' in parmDict:
2376        Flack = 1.-2.*parmDict[phfx+'Flack']
2377    time0 = time.time()
2378    nRef = len(refDict['RefList'])/100
2379    for iref,refl in enumerate(refDict['RefList']):
2380        if 'T' in calcControls[hfx+'histType']:
2381            FP,FPP = G2el.BlenResCW(Tdata,BLtables,refl.T[12+im])
2382        H = np.array(refl[:4])
2383        HP = H[:3]+modQ*H[3:]            #projected hklm to hkl
2384        H = np.inner(H.T,TwinLaw)   #maybe array(4,nTwins) or (4)
2385        TwMask = np.any(H,axis=-1)
2386        if TwinLaw.shape[0] > 1 and TwDict:
2387            if iref in TwDict:
2388                for i in TwDict[iref]:
2389                    for n in range(NTL):
2390                        H[i+n*NM] = np.inner(TwinLaw[n*NM],np.array(TwDict[iref][i])*TwinInv[i+n*NM])
2391            TwMask = np.any(H,axis=-1)
2392        SQ = 1./(2.*refl[4+im])**2             # or (sin(theta)/lambda)**2
2393        SQfactor = 8.0*SQ*np.pi**2
2394        dBabdA = np.exp(-parmDict[phfx+'BabU']*SQfactor)
2395        Bab = parmDict[phfx+'BabA']*dBabdA
2396        Tindx = np.array([refDict['FF']['El'].index(El) for El in Tdata])
2397        FF = refDict['FF']['FF'][iref].T[Tindx]
2398        Uniq = np.inner(H,SSGMT)
2399        Phi = np.inner(H,SSGT)
2400        UniqP = np.inner(HP,SGMT)
2401        if SGInv:   #if centro - expand HKL sets
2402            Uniq = np.vstack((Uniq,-Uniq))
2403            Phi = np.hstack((Phi,-Phi))
2404            UniqP = np.vstack((UniqP,-UniqP))
2405        phase = twopi*(np.inner(Uniq[:,:3],(dXdata+Xdata).T)+Phi[:,nxs])
2406        sinp = np.sin(phase)
2407        cosp = np.cos(phase)
2408        occ = Mdata*Fdata/Uniq.shape[0]
2409        biso = -SQfactor*Uisodata[:,nxs]
2410        Tiso = np.repeat(np.where(biso<1.,np.exp(biso),1.0),Uniq.shape[0]*len(TwinLaw),axis=1).T    #ops x atoms
2411        HbH = -np.sum(UniqP[:,nxs,:3]*np.inner(UniqP[:,:3],bij),axis=-1)  #ops x atoms
2412        Hij = np.array([Mast*np.multiply.outer(U[:3],U[:3]) for U in UniqP]) #atoms x 3x3
2413        Hij = np.squeeze(np.reshape(np.array([G2lat.UijtoU6(uij) for uij in Hij]),(nTwin,-1,6)))
2414        Tuij = np.where(HbH<1.,np.exp(HbH),1.0)     #ops x atoms
2415        Tcorr = np.reshape(Tiso,Tuij.shape)*Tuij*Mdata*Fdata/Uniq.shape[0]  #ops x atoms
2416        fot = (FF+FP-Bab)*Tcorr     #ops x atoms
2417        fotp = FPP*Tcorr            #ops x atoms
2418        GfpuA = G2mth.Modulation(Uniq,UniqP,nWaves,Fmod,Xmod,Umod,glTau,glWt) #2 x sym X atoms
2419        dGdf,dGdx,dGdu,dGdz = G2mth.ModulationDerv(Uniq,UniqP,Hij,nWaves,waveShapes,Fmod,Xmod,UmodAB,SCtauF,SCtauX,SCtauU,glTau,glWt)
2420        # GfpuA is 2 x ops x atoms
2421        # derivs are: ops x atoms x waves x 2,6,12, or 5 parms as [real,imag] parts
2422        fa = np.array([((FF+FP).T-Bab).T*cosp*Tcorr,-Flack*FPP*sinp*Tcorr]) # array(2,nTwin,nEqv,nAtoms)
2423        fb = np.array([((FF+FP).T-Bab).T*sinp*Tcorr,Flack*FPP*cosp*Tcorr])  #or array(2,nEqv,nAtoms)
2424        fag = fa*GfpuA[0]-fb*GfpuA[1]
2425        fbg = fb*GfpuA[0]+fa*GfpuA[1]
2426       
2427        fas = np.sum(np.sum(fag,axis=1),axis=1)     # 2 x twin
2428        fbs = np.sum(np.sum(fbg,axis=1),axis=1)
2429        fax = np.array([-fot*sinp,-fotp*cosp])   #positions; 2 x twin x ops x atoms
2430        fbx = np.array([fot*cosp,-fotp*sinp])
2431        fax = fax*GfpuA[0]-fbx*GfpuA[1]
2432        fbx = fbx*GfpuA[0]+fax*GfpuA[1]
2433        #sum below is over Uniq
2434        dfadfr = np.sum(fag/occ,axis=1)        #Fdata != 0 ever avoids /0. problem
2435        dfbdfr = np.sum(fbg/occ,axis=1)        #Fdata != 0 avoids /0. problem
2436        dfadba = np.sum(-cosp*Tcorr[:,nxs],axis=1)
2437        dfbdba = np.sum(-sinp*Tcorr[:,nxs],axis=1)
2438        dfadui = np.sum(-SQfactor*fag,axis=1)
2439        dfbdui = np.sum(-SQfactor*fbg,axis=1)
2440        dfadx = np.array([np.sum(twopi*Uniq[it,:,:3]*np.swapaxes(fax,-2,-1)[:,it,:,:,nxs],axis=-2) for it in range(nTwin)])
2441        dfbdx = np.array([np.sum(twopi*Uniq[it,:,:3]*np.swapaxes(fbx,-2,-1)[:,it,:,:,nxs],axis=-2) for it in range(nTwin)])           
2442        dfadua = np.array([np.sum(-Hij[it]*np.swapaxes(fag,-2,-1)[:,it,:,:,nxs],axis=-2) for it in range(nTwin)])
2443        dfbdua = np.array([np.sum(-Hij[it]*np.swapaxes(fbg,-2,-1)[:,it,:,:,nxs],axis=-2) for it in range(nTwin)])
2444        # array(2,nTwin,nAtom,3) & array(2,nTwin,nAtom,6) & array(2,nTwin,nAtom,12)
2445        dfadGf = np.sum(fa[:,it,:,:,nxs,nxs]*dGdf[0][nxs,nxs,:,:,:,:]-fb[:,it,:,:,nxs,nxs]*dGdf[1][nxs,nxs,:,:,:,:],axis=1)
2446        dfbdGf = np.sum(fb[:,it,:,:,nxs,nxs]*dGdf[0][nxs,nxs,:,:,:,:]+fa[:,it,:,:,nxs,nxs]*dGdf[1][nxs,nxs,:,:,:,:],axis=1)
2447        dfadGx = np.sum(fa[:,it,:,:,nxs,nxs]*dGdx[0][nxs,nxs,:,:,:,:]-fb[:,it,:,:,nxs,nxs]*dGdx[1][nxs,nxs,:,:,:,:],axis=1)
2448        dfbdGx = np.sum(fb[:,it,:,:,nxs,nxs]*dGdx[0][nxs,nxs,:,:,:,:]+fa[:,it,:,:,nxs,nxs]*dGdx[1][nxs,nxs,:,:,:,:],axis=1)
2449        dfadGz = np.sum(fa[:,it,:,0,nxs,nxs]*dGdz[0][nxs,nxs,:,:,:]-fb[:,it,:,0,nxs,nxs]*dGdz[1][nxs,nxs,:,:,:],axis=1)
2450        dfbdGz = np.sum(fb[:,it,:,0,nxs,nxs]*dGdz[0][nxs,nxs,:,:,:]+fa[:,it,:,0,nxs,nxs]*dGdz[1][nxs,nxs,:,:,:],axis=1)
2451        dfadGu = np.sum(fa[:,it,:,:,nxs,nxs]*dGdu[0][nxs,nxs,:,:,:,:]-fb[:,it,:,:,nxs,nxs]*dGdu[1][nxs,nxs,:,:,:,:],axis=1)
2452        dfbdGu = np.sum(fb[:,it,:,:,nxs,nxs]*dGdu[0][nxs,nxs,:,:,:,:]+fa[:,it,:,:,nxs,nxs]*dGdu[1][nxs,nxs,:,:,:,:],axis=1)
2453#        GSASIIpath.IPyBreak()
2454        #NB: the above have been checked against PA(1:10,1:2) in strfctr.for for Al2O3!   
2455        SA = fas[0]+fas[1]      #float = A+A' (might be array[nTwin])
2456        SB = fbs[0]+fbs[1]      #float = B+B' (might be array[nTwin])
2457        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)]
2458        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)]
2459        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)]
2460        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)]
2461        dFdtw[iref] = np.sum(TwMask*fas,axis=0)**2+np.sum(TwMask*fbs,axis=0)**2
2462
2463        dFdGf[iref] = [2.*TwMask[it]*(SA[it]*dfadGf[1]+SB[it]*dfbdGf[1]) for it in range(nTwin)]
2464        dFdGx[iref] = [2.*TwMask[it]*(SA[it]*dfadGx[1]+SB[it]*dfbdGx[1]) for it in range(nTwin)]
2465        dFdGz[iref] = [2.*TwMask[it]*(SA[it]*dfadGz[1]+SB[it]*dfbdGz[1]) for it in range(nTwin)]
2466        dFdGu[iref] = [2.*TwMask[it]*(SA[it]*dfadGu[1]+SB[it]*dfbdGu[1]) for it in range(nTwin)]               
2467#            GSASIIpath.IPyBreak()
2468        dFdbab[iref] = 2.*fas[0]*np.array([np.sum(dfadba*dBabdA),np.sum(-dfadba*parmDict[phfx+'BabA']*SQfactor*dBabdA)]).T+ \
2469            2.*fbs[0]*np.array([np.sum(dfbdba*dBabdA),np.sum(-dfbdba*parmDict[phfx+'BabA']*SQfactor*dBabdA)]).T
2470        #loop over atoms - each dict entry is list of derivatives for all the reflections
2471        if not iref%100 :
2472            print (' %d derivative time %.4f\r'%(iref,time.time()-time0),end='')
2473    for i in range(len(Mdata)):     #loop over atoms
2474        dFdvDict[pfx+'Afrac:'+str(i)] = dFdfr.T[i]
2475        dFdvDict[pfx+'dAx:'+str(i)] = dFdx.T[0][i]
2476        dFdvDict[pfx+'dAy:'+str(i)] = dFdx.T[1][i]
2477        dFdvDict[pfx+'dAz:'+str(i)] = dFdx.T[2][i]
2478        dFdvDict[pfx+'AUiso:'+str(i)] = dFdui.T[i]
2479        dFdvDict[pfx+'AU11:'+str(i)] = dFdua.T[0][i]
2480        dFdvDict[pfx+'AU22:'+str(i)] = dFdua.T[1][i]
2481        dFdvDict[pfx+'AU33:'+str(i)] = dFdua.T[2][i]
2482        dFdvDict[pfx+'AU12:'+str(i)] = dFdua.T[3][i]
2483        dFdvDict[pfx+'AU13:'+str(i)] = dFdua.T[4][i]
2484        dFdvDict[pfx+'AU23:'+str(i)] = dFdua.T[5][i]
2485        for j in range(FSSdata.shape[1]):        #loop over waves Fzero & Fwid?
2486            dFdvDict[pfx+'Fsin:'+str(i)+':'+str(j)] = dFdGf.T[0][j][i]
2487            dFdvDict[pfx+'Fcos:'+str(i)+':'+str(j)] = dFdGf.T[1][j][i]
2488        nx = 0
2489        if waveTypes[i] in ['Block','ZigZag']:
2490            nx = 1 
2491            dFdvDict[pfx+'Tmin:'+str(i)+':0'] = dFdGz.T[0][i]   #ZigZag/Block waves (if any)
2492            dFdvDict[pfx+'Tmax:'+str(i)+':0'] = dFdGz.T[1][i]
2493            dFdvDict[pfx+'Xmax:'+str(i)+':0'] = dFdGz.T[2][i]
2494            dFdvDict[pfx+'Ymax:'+str(i)+':0'] = dFdGz.T[3][i]
2495            dFdvDict[pfx+'Zmax:'+str(i)+':0'] = dFdGz.T[4][i]
2496        for j in range(XSSdata.shape[1]-nx):       #loop over waves
2497            dFdvDict[pfx+'Xsin:'+str(i)+':'+str(j+nx)] = dFdGx.T[0][j][i]
2498            dFdvDict[pfx+'Ysin:'+str(i)+':'+str(j+nx)] = dFdGx.T[1][j][i]
2499            dFdvDict[pfx+'Zsin:'+str(i)+':'+str(j+nx)] = dFdGx.T[2][j][i]
2500            dFdvDict[pfx+'Xcos:'+str(i)+':'+str(j+nx)] = dFdGx.T[3][j][i]
2501            dFdvDict[pfx+'Ycos:'+str(i)+':'+str(j+nx)] = dFdGx.T[4][j][i]
2502            dFdvDict[pfx+'Zcos:'+str(i)+':'+str(j+nx)] = dFdGx.T[5][j][i]
2503        for j in range(USSdata.shape[1]):       #loop over waves
2504            dFdvDict[pfx+'U11sin:'+str(i)+':'+str(j)] = dFdGu.T[0][j][i]
2505            dFdvDict[pfx+'U22sin:'+str(i)+':'+str(j)] = dFdGu.T[1][j][i]
2506            dFdvDict[pfx+'U33sin:'+str(i)+':'+str(j)] = dFdGu.T[2][j][i]
2507            dFdvDict[pfx+'U12sin:'+str(i)+':'+str(j)] = dFdGu.T[3][j][i]
2508            dFdvDict[pfx+'U13sin:'+str(i)+':'+str(j)] = dFdGu.T[4][j][i]
2509            dFdvDict[pfx+'U23sin:'+str(i)+':'+str(j)] = dFdGu.T[5][j][i]
2510            dFdvDict[pfx+'U11cos:'+str(i)+':'+str(j)] = dFdGu.T[6][j][i]
2511            dFdvDict[pfx+'U22cos:'+str(i)+':'+str(j)] = dFdGu.T[7][j][i]
2512            dFdvDict[pfx+'U33cos:'+str(i)+':'+str(j)] = dFdGu.T[8][j][i]
2513            dFdvDict[pfx+'U12cos:'+str(i)+':'+str(j)] = dFdGu.T[9][j][i]
2514            dFdvDict[pfx+'U13cos:'+str(i)+':'+str(j)] = dFdGu.T[10][j][i]
2515            dFdvDict[pfx+'U23cos:'+str(i)+':'+str(j)] = dFdGu.T[11][j][i]
2516           
2517#        GSASIIpath.IPyBreak()
2518    dFdvDict[phfx+'BabA'] = dFdbab.T[0]
2519    dFdvDict[phfx+'BabU'] = dFdbab.T[1]
2520    return dFdvDict
2521   
2522def SCExtinction(ref,im,phfx,hfx,pfx,calcControls,parmDict,varyList):
2523    ''' Single crystal extinction function; returns extinction & derivative
2524    '''
2525    extCor = 1.0
2526    dervDict = {}
2527    dervCor = 1.0
2528    if calcControls[phfx+'EType'] != 'None':
2529        SQ = 1/(4.*ref[4+im]**2)
2530        if 'C' in parmDict[hfx+'Type']:           
2531            cos2T = 1.0-2.*SQ*parmDict[hfx+'Lam']**2           #cos(2theta)
2532        else:   #'T'
2533            cos2T = 1.0-2.*SQ*ref[12+im]**2                       #cos(2theta)           
2534        if 'SXC' in parmDict[hfx+'Type'] or 'SEC' in parmDict[hfx+'Type']:
2535            AV = 7.9406e5/parmDict[pfx+'Vol']**2    #is 7.9406e5 constant right for electroms?
2536            PL = np.sqrt(1.0-cos2T**2)/parmDict[hfx+'Lam']
2537            P12 = (calcControls[phfx+'Cos2TM']+cos2T**4)/(calcControls[phfx+'Cos2TM']+cos2T**2)
2538            PLZ = AV*P12*ref[9+im]*parmDict[hfx+'Lam']**2
2539        elif 'SNT' in parmDict[hfx+'Type']:
2540            AV = 1.e7/parmDict[pfx+'Vol']**2
2541            PL = SQ
2542            PLZ = AV*ref[9+im]*ref[12+im]**2
2543        elif 'SNC' in parmDict[hfx+'Type']:
2544            AV = 1.e7/parmDict[pfx+'Vol']**2
2545            PL = np.sqrt(1.0-cos2T**2)/parmDict[hfx+'Lam']
2546            PLZ = AV*ref[9+im]*parmDict[hfx+'Lam']**2
2547           
2548        if 'Primary' in calcControls[phfx+'EType']:
2549            PLZ *= 1.5
2550        else:
2551            if 'C' in parmDict[hfx+'Type']:
2552                PLZ *= calcControls[phfx+'Tbar']
2553            else: #'T'
2554                PLZ *= ref[13+im]      #t-bar
2555        if 'Primary' in calcControls[phfx+'EType']:
2556            PLZ *= 1.5
2557            PSIG = parmDict[phfx+'Ep']
2558        elif 'I & II' in calcControls[phfx+'EType']:
2559            PSIG = parmDict[phfx+'Eg']/np.sqrt(1.+(parmDict[phfx+'Es']*PL/parmDict[phfx+'Eg'])**2)
2560        elif 'Type II' in calcControls[phfx+'EType']:
2561            PSIG = parmDict[phfx+'Es']
2562        else:       # 'Secondary Type I'
2563            PSIG = parmDict[phfx+'Eg']/PL
2564           
2565        AG = 0.58+0.48*cos2T+0.24*cos2T**2
2566        AL = 0.025+0.285*cos2T
2567        BG = 0.02-0.025*cos2T
2568        BL = 0.15-0.2*(0.75-cos2T)**2
2569        if cos2T < 0.:
2570            BL = -0.45*cos2T
2571        CG = 2.
2572        CL = 2.
2573        PF = PLZ*PSIG
2574       
2575        if 'Gaussian' in calcControls[phfx+'EApprox']:
2576            PF4 = 1.+CG*PF+AG*PF**2/(1.+BG*PF)
2577            extCor = np.sqrt(PF4)
2578            PF3 = 0.5*(CG+2.*AG*PF/(1.+BG*PF)-AG*PF**2*BG/(1.+BG*PF)**2)/(PF4*extCor)
2579        else:
2580            PF4 = 1.+CL*PF+AL*PF**2/(1.+BL*PF)
2581            extCor = np.sqrt(PF4)
2582            PF3 = 0.5*(CL+2.*AL*PF/(1.+BL*PF)-AL*PF**2*BL/(1.+BL*PF)**2)/(PF4*extCor)
2583
2584        dervCor = (1.+PF)*PF3   #extinction corr for other derivatives
2585        if 'Primary' in calcControls[phfx+'EType'] and phfx+'Ep' in varyList:
2586            dervDict[phfx+'Ep'] = -ref[7+im]*PLZ*PF3
2587        if 'II' in calcControls[phfx+'EType'] and phfx+'Es' in varyList:
2588            dervDict[phfx+'Es'] = -ref[7+im]*PLZ*PF3*(PSIG/parmDict[phfx+'Es'])**3
2589        if 'I' in calcControls[phfx+'EType'] and phfx+'Eg' in varyList:
2590            dervDict[phfx+'Eg'] = -ref[7+im]*PLZ*PF3*(PSIG/parmDict[phfx+'Eg'])**3*PL**2
2591               
2592    return 1./extCor,dervDict,dervCor
2593   
2594def Dict2Values(parmdict, varylist):
2595    '''Use before call to leastsq to setup list of values for the parameters
2596    in parmdict, as selected by key in varylist'''
2597    return [parmdict[key] for key in varylist] 
2598   
2599def Values2Dict(parmdict, varylist, values):
2600    ''' Use after call to leastsq to update the parameter dictionary with
2601    values corresponding to keys in varylist'''
2602    parmdict.update(zip(varylist,values))
2603   
2604def GetNewCellParms(parmDict,varyList):
2605    '''Compute unit cell tensor terms from varied Aij and Dij values.
2606    Terms are included in the dict only if Aij or Dij is varied.
2607    '''
2608    newCellDict = {}
2609    Anames = ['A'+str(i) for i in range(6)]
2610    Ddict = dict(zip(['D11','D22','D33','D12','D13','D23'],Anames))
2611    for item in varyList:
2612        keys = item.split(':')
2613        if keys[2] in Ddict:
2614            key = keys[0]+'::'+Ddict[keys[2]]       #key is e.g. '0::A0'
2615            parm = keys[0]+'::'+keys[2]             #parm is e.g. '0::D11'
2616            newCellDict[parm] = [key,parmDict[key]+parmDict[item]]
2617    return newCellDict          # is e.g. {'0::D11':A0-D11}
2618   
2619def ApplyXYZshifts(parmDict,varyList):
2620    '''
2621    takes atom x,y,z shift and applies it to corresponding atom x,y,z value
2622   
2623    :param dict parmDict: parameter dictionary
2624    :param list varyList: list of variables (not used!)
2625    :returns: newAtomDict - dictionary of new atomic coordinate names & values; key is parameter shift name
2626
2627    '''
2628    newAtomDict = {}
2629    for item in parmDict:
2630        if 'dA' in item:
2631            parm = ''.join(item.split('d'))
2632            parmDict[parm] += parmDict[item]
2633            newAtomDict[item] = [parm,parmDict[parm]]
2634    return newAtomDict
2635   
2636def SHTXcal(refl,im,g,pfx,hfx,SGData,calcControls,parmDict):
2637    'Spherical harmonics texture'
2638    IFCoup = 'Bragg' in calcControls[hfx+'instType']
2639    if 'T' in calcControls[hfx+'histType']:
2640        tth = parmDict[hfx+'2-theta']
2641    else:
2642        tth = refl[5+im]
2643    odfCor = 1.0
2644    H = refl[:3]
2645    cell = G2lat.Gmat2cell(g)
2646    Sangls = [parmDict[pfx+'SH omega'],parmDict[pfx+'SH chi'],parmDict[pfx+'SH phi']]
2647    Gangls = [parmDict[hfx+'Phi'],parmDict[hfx+'Chi'],parmDict[hfx+'Omega'],parmDict[hfx+'Azimuth']]
2648    phi,beta = G2lat.CrsAng(H,cell,SGData)
2649    psi,gam,x,x = G2lat.SamAng(tth/2.,Gangls,Sangls,IFCoup) #ignore 2 sets of angle derivs.
2650    SHnames = G2lat.GenSHCoeff(SGData['SGLaue'],parmDict[pfx+'SHmodel'],parmDict[pfx+'SHorder'])
2651    for item in SHnames:
2652        L,M,N = eval(item.strip('C'))
2653        Kcl = G2lat.GetKcl(L,N,SGData['SGLaue'],phi,beta)
2654        Ksl,x,x = G2lat.GetKsl(L,M,parmDict[pfx+'SHmodel'],psi,gam)
2655        Lnorm = G2lat.Lnorm(L)
2656        odfCor += parmDict[pfx+item]*Lnorm*Kcl*Ksl
2657    return odfCor
2658   
2659def SHTXcalDerv(refl,im,g,pfx,hfx,SGData,calcControls,parmDict):
2660    'Spherical harmonics texture derivatives'
2661    if 'T' in calcControls[hfx+'histType']:
2662        tth = parmDict[hfx+'2-theta']
2663    else:
2664        tth = refl[5+im]
2665    IFCoup = 'Bragg' in calcControls[hfx+'instType']
2666    odfCor = 1.0
2667    dFdODF = {}
2668    dFdSA = [0,0,0]
2669    H = refl[:3]
2670    cell = G2lat.Gmat2cell(g)
2671    Sangls = [parmDict[pfx+'SH omega'],parmDict[pfx+'SH chi'],parmDict[pfx+'SH phi']]
2672    Gangls = [parmDict[hfx+'Phi'],parmDict[hfx+'Chi'],parmDict[hfx+'Omega'],parmDict[hfx+'Azimuth']]
2673    phi,beta = G2lat.CrsAng(H,cell,SGData)
2674    psi,gam,dPSdA,dGMdA = G2lat.SamAng(tth/2.,Gangls,Sangls,IFCoup)
2675    SHnames = G2lat.GenSHCoeff(SGData['SGLaue'],parmDict[pfx+'SHmodel'],parmDict[pfx+'SHorder'])
2676    for item in SHnames:
2677        L,M,N = eval(item.strip('C'))
2678        Kcl = G2lat.GetKcl(L,N,SGData['SGLaue'],phi,beta)
2679        Ksl,dKsdp,dKsdg = G2lat.GetKsl(L,M,parmDict[pfx+'SHmodel'],psi,gam)
2680        Lnorm = G2lat.Lnorm(L)
2681        odfCor += parmDict[pfx+item]*Lnorm*Kcl*Ksl
2682        dFdODF[pfx+item] = Lnorm*Kcl*Ksl
2683        for i in range(3):
2684            dFdSA[i] += parmDict[pfx+item]*Lnorm*Kcl*(dKsdp*dPSdA[i]+dKsdg*dGMdA[i])
2685    return odfCor,dFdODF,dFdSA
2686   
2687def SHPOcal(refl,im,g,phfx,hfx,SGData,calcControls,parmDict):
2688    'spherical harmonics preferred orientation (cylindrical symmetry only)'
2689    if 'T' in calcControls[hfx+'histType']:
2690        tth = parmDict[hfx+'2-theta']
2691    else:
2692        tth = refl[5+im]
2693    odfCor = 1.0
2694    H = refl[:3]
2695    cell = G2lat.Gmat2cell(g)
2696    Sangls = [0.,0.,0.]
2697    if 'Bragg' in calcControls[hfx+'instType']:
2698        Gangls = [0.,90.,0.,parmDict[hfx+'Azimuth']]
2699        IFCoup = True
2700    else:
2701        Gangls = [parmDict[hfx+'Phi'],parmDict[hfx+'Chi'],parmDict[hfx+'Omega'],parmDict[hfx+'Azimuth']]
2702        IFCoup = False
2703    phi,beta = G2lat.CrsAng(H,cell,SGData)
2704    psi,gam,x,x = G2lat.SamAng(tth/2.,Gangls,Sangls,IFCoup) #ignore 2 sets of angle derivs.
2705    SHnames = calcControls[phfx+'SHnames']
2706    for item in SHnames:
2707        L,N = eval(item.strip('C'))
2708        Kcl = G2lat.GetKcl(L,N,SGData['SGLaue'],phi,beta)
2709        Ksl,x,x = G2lat.GetKsl(L,0,'0',psi,gam)
2710        Lnorm = G2lat.Lnorm(L)
2711        odfCor += parmDict[phfx+item]*Lnorm*Kcl*Ksl
2712    return np.squeeze(odfCor)
2713   
2714def SHPOcalDerv(refl,im,g,phfx,hfx,SGData,calcControls,parmDict):
2715    'spherical harmonics preferred orientation derivatives (cylindrical symmetry only)'
2716    if 'T' in calcControls[hfx+'histType']:
2717        tth = parmDict[hfx+'2-theta']
2718    else:
2719        tth = refl[5+im]
2720    odfCor = 1.0
2721    dFdODF = {}
2722    H = refl[:3]
2723    cell = G2lat.Gmat2cell(g)
2724    Sangls = [0.,0.,0.]
2725    if 'Bragg' in calcControls[hfx+'instType']:
2726        Gangls = [0.,90.,0.,parmDict[hfx+'Azimuth']]
2727        IFCoup = True
2728    else:
2729        Gangls = [parmDict[hfx+'Phi'],parmDict[hfx+'Chi'],parmDict[hfx+'Omega'],parmDict[hfx+'Azimuth']]
2730        IFCoup = False
2731    phi,beta = G2lat.CrsAng(H,cell,SGData)
2732    psi,gam,x,x = G2lat.SamAng(tth/2.,Gangls,Sangls,IFCoup) #ignore 2 sets of angle derivs.
2733    SHnames = calcControls[phfx+'SHnames']
2734    for item in SHnames:
2735        L,N = eval(item.strip('C'))
2736        Kcl = G2lat.GetKcl(L,N,SGData['SGLaue'],phi,beta)
2737        Ksl,x,x = G2lat.GetKsl(L,0,'0',psi,gam)
2738        Lnorm = G2lat.Lnorm(L)
2739        odfCor += parmDict[phfx+item]*Lnorm*Kcl*Ksl
2740        dFdODF[phfx+item] = Kcl*Ksl*Lnorm
2741    return odfCor,dFdODF
2742   
2743def GetPrefOri(uniq,G,g,phfx,hfx,SGData,calcControls,parmDict):
2744    'March-Dollase preferred orientation correction'
2745    POcorr = 1.0
2746    MD = parmDict[phfx+'MD']
2747    if MD != 1.0:
2748        MDAxis = calcControls[phfx+'MDAxis']
2749        sumMD = 0
2750        for H in uniq:           
2751            cosP,sinP = G2lat.CosSinAngle(H,MDAxis,G)
2752            A = 1.0/np.sqrt((MD*cosP)**2+sinP**2/MD)
2753            sumMD += A**3
2754        POcorr = sumMD/len(uniq)
2755    return POcorr
2756   
2757def GetPrefOriDerv(refl,im,uniq,G,g,phfx,hfx,SGData,calcControls,parmDict):
2758    'Needs a doc string'
2759    POcorr = 1.0
2760    POderv = {}
2761    if calcControls[phfx+'poType'] == 'MD':
2762        MD = parmDict[phfx+'MD']
2763        MDAxis = calcControls[phfx+'MDAxis']
2764        sumMD = 0
2765        sumdMD = 0
2766        for H in uniq:           
2767            cosP,sinP = G2lat.CosSinAngle(H,MDAxis,G)
2768            A = 1.0/np.sqrt((MD*cosP)**2+sinP**2/MD)
2769            sumMD += A**3
2770            sumdMD -= (1.5*A**5)*(2.0*MD*cosP**2-(sinP/MD)**2)
2771        POcorr = sumMD/len(uniq)
2772        POderv[phfx+'MD'] = sumdMD/len(uniq)
2773    else:   #spherical harmonics
2774        if calcControls[phfx+'SHord']:
2775            POcorr,POderv = SHPOcalDerv(refl,im,g,phfx,hfx,SGData,calcControls,parmDict)
2776    return POcorr,POderv
2777   
2778def GetAbsorb(refl,im,hfx,calcControls,parmDict):
2779    'Needs a doc string'
2780    if 'Debye' in calcControls[hfx+'instType']:
2781        if 'T' in calcControls[hfx+'histType']:
2782            return G2pwd.Absorb('Cylinder',parmDict[hfx+'Absorption']*refl[14+im],abs(parmDict[hfx+'2-theta']),0,0)
2783        else:
2784            return G2pwd.Absorb('Cylinder',parmDict[hfx+'Absorption'],refl[5+im],0,0)
2785    else:
2786        return G2pwd.SurfaceRough(parmDict[hfx+'SurfRoughA'],parmDict[hfx+'SurfRoughB'],refl[5+im])
2787   
2788def GetAbsorbDerv(refl,im,hfx,calcControls,parmDict):
2789    'Needs a doc string'
2790    if 'Debye' in calcControls[hfx+'instType']:
2791        if 'T' in calcControls[hfx+'histType']:
2792            return G2pwd.AbsorbDerv('Cylinder',parmDict[hfx+'Absorption']*refl[14+im],abs(parmDict[hfx+'2-theta']),0,0)
2793        else:
2794            return G2pwd.AbsorbDerv('Cylinder',parmDict[hfx+'Absorption'],refl[5+im],0,0)
2795    else:
2796        return np.array(G2pwd.SurfaceRoughDerv(parmDict[hfx+'SurfRoughA'],parmDict[hfx+'SurfRoughB'],refl[5+im]))
2797       
2798def GetPwdrExt(refl,im,pfx,phfx,hfx,calcControls,parmDict):
2799    'Needs a doc string'
2800    coef = np.array([-0.5,0.25,-0.10416667,0.036458333,-0.0109375,2.8497409E-3])
2801    pi2 = np.sqrt(2./np.pi)
2802    if 'T' in calcControls[hfx+'histType']:
2803        sth2 = sind(abs(parmDict[hfx+'2-theta'])/2.)**2
2804        wave = refl[14+im]
2805    else:   #'C'W
2806        sth2 = sind(refl[5+im]/2.)**2
2807        wave = parmDict.get(hfx+'Lam',parmDict.get(hfx+'Lam1',1.0))
2808    c2th = 1.-2.0*sth2
2809    flv2 = refl[9+im]*(wave/parmDict[pfx+'Vol'])**2
2810    if 'X' in calcControls[hfx+'histType']:
2811        flv2 *= 0.079411*(1.0+c2th**2)/2.0
2812    xfac = flv2*parmDict[phfx+'Extinction']
2813    exb = 1.0
2814    if xfac > -1.:
2815        exb = 1./np.sqrt(1.+xfac)
2816    exl = 1.0
2817    if 0 < xfac <= 1.:
2818        xn = np.array([xfac**(i+1) for i in range(6)])
2819        exl += np.sum(xn*coef)
2820    elif xfac > 1.:
2821        xfac2 = 1./np.sqrt(xfac)
2822        exl = pi2*(1.-0.125/xfac)*xfac2
2823    return exb*sth2+exl*(1.-sth2)
2824   
2825def GetPwdrExtDerv(refl,im,pfx,phfx,hfx,calcControls,parmDict):
2826    'Needs a doc string'
2827    coef = np.array([-0.5,0.25,-0.10416667,0.036458333,-0.0109375,2.8497409E-3])
2828    pi2 = np.sqrt(2./np.pi)
2829    if 'T' in calcControls[hfx+'histType']:
2830        sth2 = sind(abs(parmDict[hfx+'2-theta'])/2.)**2
2831        wave = refl[14+im]
2832    else:   #'C'W
2833        sth2 = sind(refl[5+im]/2.)**2
2834        wave = parmDict.get(hfx+'Lam',parmDict.get(hfx+'Lam1',1.0))
2835    c2th = 1.-2.0*sth2
2836    flv2 = refl[9+im]*(wave/parmDict[pfx+'Vol'])**2
2837    if 'X' in calcControls[hfx+'histType']:
2838        flv2 *= 0.079411*(1.0+c2th**2)/2.0
2839    xfac = flv2*parmDict[phfx+'Extinction']
2840    dbde = -500.*flv2
2841    if xfac > -1.:
2842        dbde = -0.5*flv2/np.sqrt(1.+xfac)**3
2843    dlde = 0.
2844    if 0 < xfac <= 1.:
2845        xn = np.array([i*flv2*xfac**i for i in [1,2,3,4,5,6]])
2846        dlde = np.sum(xn*coef)/xfac
2847    elif xfac > 1.:
2848        xfac2 = 1./np.sqrt(xfac)
2849        dlde = 0.5*flv2*pi2*xfac2*(-1./xfac+0.375/xfac**2)
2850       
2851    return dbde*sth2+dlde*(1.-sth2)
2852   
2853def GetIntensityCorr(refl,im,uniq,G,g,pfx,phfx,hfx,SGData,calcControls,parmDict):
2854    'Needs a doc string'    #need powder extinction!
2855    parmDict[phfx+'Scale'] = max(1.e-12,parmDict[phfx+'Scale'])                      #put floor on phase fraction scale
2856    parmDict[hfx+'Scale'] = max(1.e-12,parmDict[hfx+'Scale'])                        #put floor on histogram scale
2857    Icorr = parmDict[phfx+'Scale']*parmDict[hfx+'Scale']*refl[3+im]               #scale*multiplicity
2858    if 'XC' in parmDict[hfx+'Type']:
2859        Icorr *= G2pwd.Polarization(parmDict[hfx+'Polariz.'],refl[5+im],parmDict[hfx+'Azimuth'])[0]
2860    POcorr = 1.0
2861    if pfx+'SHorder' in parmDict:                 #generalized spherical harmonics texture - takes precidence
2862        POcorr = SHTXcal(refl,im,g,pfx,hfx,SGData,calcControls,parmDict)
2863    elif calcControls[phfx+'poType'] == 'MD':         #March-Dollase
2864        POcorr = GetPrefOri(uniq,G,g,phfx,hfx,SGData,calcControls,parmDict)
2865    elif calcControls[phfx+'SHord']:                #cylindrical spherical harmonics
2866        POcorr = SHPOcal(refl,im,g,phfx,hfx,SGData,calcControls,parmDict)
2867    Icorr *= POcorr
2868    AbsCorr = 1.0
2869    AbsCorr = GetAbsorb(refl,im,hfx,calcControls,parmDict)
2870    Icorr *= AbsCorr
2871    ExtCorr = GetPwdrExt(refl,im,pfx,phfx,hfx,calcControls,parmDict)
2872    Icorr *= ExtCorr
2873    return Icorr,POcorr,AbsCorr,ExtCorr
2874   
2875def GetIntensityDerv(refl,im,wave,uniq,G,g,pfx,phfx,hfx,SGData,calcControls,parmDict):
2876    'Needs a doc string'    #need powder extinction derivs!
2877    dIdsh = 1./parmDict[hfx+'Scale']
2878    dIdsp = 1./parmDict[phfx+'Scale']
2879    if 'XC' in parmDict[hfx+'Type']:
2880        pola,dIdPola = G2pwd.Polarization(parmDict[hfx+'Polariz.'],refl[5+im],parmDict[hfx+'Azimuth'])
2881        dIdPola /= pola
2882    else:       #'N'
2883        dIdPola = 0.0
2884    dFdODF = {}
2885    dFdSA = [0,0,0]
2886    dIdPO = {}
2887    if pfx+'SHorder' in parmDict:
2888        odfCor,dFdODF,dFdSA = SHTXcalDerv(refl,im,g,pfx,hfx,SGData,calcControls,parmDict)
2889        for iSH in dFdODF:
2890            dFdODF[iSH] /= odfCor
2891        for i in range(3):
2892            dFdSA[i] /= odfCor
2893    elif calcControls[phfx+'poType'] == 'MD' or calcControls[phfx+'SHord']:
2894        POcorr,dIdPO = GetPrefOriDerv(refl,im,uniq,G,g,phfx,hfx,SGData,calcControls,parmDict)       
2895        for iPO in dIdPO:
2896            dIdPO[iPO] /= POcorr
2897    if 'T' in parmDict[hfx+'Type']:
2898        dFdAb = GetAbsorbDerv(refl,im,hfx,calcControls,parmDict)*wave/refl[16+im] #wave/abs corr
2899        dFdEx = GetPwdrExtDerv(refl,im,pfx,phfx,hfx,calcControls,parmDict)/refl[17+im]    #/ext corr
2900    else:
2901        dFdAb = GetAbsorbDerv(refl,im,hfx,calcControls,parmDict)*wave/refl[13+im] #wave/abs corr
2902        dFdEx = GetPwdrExtDerv(refl,im,pfx,phfx,hfx,calcControls,parmDict)/refl[14+im]    #/ext corr       
2903    return dIdsh,dIdsp,dIdPola,dIdPO,dFdODF,dFdSA,dFdAb,dFdEx
2904       
2905def GetSampleSigGam(refl,im,wave,G,GB,SGData,hfx,phfx,calcControls,parmDict):
2906    'Needs a doc string'
2907    if 'C' in calcControls[hfx+'histType'] or 'B' in calcControls[hfx+'histType']:     #All checked & OK
2908        costh = cosd(refl[5+im]/2.)
2909        #crystallite size
2910        if calcControls[phfx+'SizeType'] == 'isotropic':
2911            Sgam = 1.8*wave/(np.pi*parmDict[phfx+'Size;i']*costh)
2912        elif calcControls[phfx+'SizeType'] == 'uniaxial':
2913            H = np.array(refl[:3])
2914            P = np.array(calcControls[phfx+'SizeAxis'])
2915            cosP,sinP = G2lat.CosSinAngle(H,P,G)
2916            Sgam = (1.8*wave/np.pi)/(parmDict[phfx+'Size;i']*parmDict[phfx+'Size;a']*costh)
2917            Sgam *= np.sqrt((sinP*parmDict[phfx+'Size;a'])**2+(cosP*parmDict[phfx+'Size;i'])**2)
2918        else:           #ellipsoidal crystallites
2919            Sij =[parmDict[phfx+'Size;%d'%(i)] for i in range(6)]
2920            H = np.array(refl[:3])
2921            lenR = G2pwd.ellipseSize(H,Sij,GB)
2922            Sgam = 1.8*wave/(np.pi*costh*lenR)
2923        #microstrain               
2924        if calcControls[phfx+'MustrainType'] == 'isotropic':
2925            Mgam = 0.018*parmDict[phfx+'Mustrain;i']*tand(refl[5+im]/2.)/np.pi
2926        elif calcControls[phfx+'MustrainType'] == 'uniaxial':
2927            H = np.array(refl[:3])
2928            P = np.array(calcControls[phfx+'MustrainAxis'])
2929            cosP,sinP = G2lat.CosSinAngle(H,P,G)
2930            Si = parmDict[phfx+'Mustrain;i']
2931            Sa = parmDict[phfx+'Mustrain;a']
2932            Mgam = 0.018*Si*Sa*tand(refl[5+im]/2.)/(np.pi*np.sqrt((Si*cosP)**2+(Sa*sinP)**2))
2933        else:       #generalized - P.W. Stephens model
2934            Strms = G2spc.MustrainCoeff(refl[:3],SGData)
2935            Sum = 0
2936            for i,strm in enumerate(Strms):
2937                Sum += parmDict[phfx+'Mustrain;'+str(i)]*strm
2938            Mgam = 0.018*refl[4+im]**2*tand(refl[5+im]/2.)*np.sqrt(Sum)/np.pi
2939    elif 'E' in calcControls[hfx+'histType']:
2940        return 0.,0.        #wrong - fix later if wanted
2941    elif 'T' in calcControls[hfx+'histType']:       #All checked & OK
2942        #crystallite size
2943        if calcControls[phfx+'SizeType'] == 'isotropic':    #OK
2944            Sgam = 1.e-4*parmDict[hfx+'difC']*refl[4+im]**2/parmDict[phfx+'Size;i']
2945        elif calcControls[phfx+'SizeType'] == 'uniaxial':   #OK
2946            H = np.array(refl[:3])
2947            P = np.array(calcControls[phfx+'SizeAxis'])
2948            cosP,sinP = G2lat.CosSinAngle(H,P,G)
2949            Sgam = 1.e-4*parmDict[hfx+'difC']*refl[4+im]**2/(parmDict[phfx+'Size;i']*parmDict[phfx+'Size;a'])
2950            Sgam *= np.sqrt((sinP*parmDict[phfx+'Size;a'])**2+(cosP*parmDict[phfx+'Size;i'])**2)
2951        else:           #ellipsoidal crystallites   #OK
2952            Sij =[parmDict[phfx+'Size;%d'%(i)] for i in range(6)]
2953            H = np.array(refl[:3])
2954            lenR = G2pwd.ellipseSize(H,Sij,GB)
2955            Sgam = 1.e-4*parmDict[hfx+'difC']*refl[4+im]**2/lenR
2956        #microstrain               
2957        if calcControls[phfx+'MustrainType'] == 'isotropic':    #OK
2958            Mgam = 1.e-6*parmDict[hfx+'difC']*refl[4+im]*parmDict[phfx+'Mustrain;i']
2959        elif calcControls[phfx+'MustrainType'] == 'uniaxial':   #OK
2960            H = np.array(refl[:3])
2961            P = np.array(calcControls[phfx+'MustrainAxis'])
2962            cosP,sinP = G2lat.CosSinAngle(H,P,G)
2963            Si = parmDict[phfx+'Mustrain;i']
2964            Sa = parmDict[phfx+'Mustrain;a']
2965            Mgam = 1.e-6*parmDict[hfx+'difC']*refl[4+im]*Si*Sa/np.sqrt((Si*cosP)**2+(Sa*sinP)**2)
2966        else:       #generalized - P.W. Stephens model  OK
2967            Strms = G2spc.MustrainCoeff(refl[:3],SGData)
2968            Sum = 0
2969            for i,strm in enumerate(Strms):
2970                Sum += parmDict[phfx+'Mustrain;'+str(i)]*strm
2971            Mgam = 1.e-6*parmDict[hfx+'difC']*np.sqrt(Sum)*refl[4+im]**3
2972           
2973    gam = Sgam*parmDict[phfx+'Size;mx']+Mgam*parmDict[phfx+'Mustrain;mx']
2974    sig = (Sgam*(1.-parmDict[phfx+'Size;mx']))**2+(Mgam*(1.-parmDict[phfx+'Mustrain;mx']))**2
2975    sig /= ateln2
2976    return sig,gam
2977       
2978def GetSampleSigGamDerv(refl,im,wave,G,GB,SGData,hfx,phfx,calcControls,parmDict):
2979    'Needs a doc string'
2980    gamDict = {}
2981    sigDict = {}
2982    if 'C' in calcControls[hfx+'histType'] or 'B' in calcControls[hfx+'histType']:         #All checked & OK
2983        costh = cosd(refl[5+im]/2.)
2984        tanth = tand(refl[5+im]/2.)
2985        #crystallite size derivatives
2986        if calcControls[phfx+'SizeType'] == 'isotropic':
2987            Sgam = 1.8*wave/(np.pi*costh*parmDict[phfx+'Size;i'])
2988            gamDict[phfx+'Size;i'] = -1.8*wave*parmDict[phfx+'Size;mx']/(np.pi*costh*parmDict[phfx+'Size;i']**2)
2989            sigDict[phfx+'Size;i'] = -3.6*Sgam*wave*(1.-parmDict[phfx+'Size;mx'])**2/(np.pi*costh*ateln2)
2990        elif calcControls[phfx+'SizeType'] == 'uniaxial':
2991            H = np.array(refl[:3])
2992            P = np.array(calcControls[phfx+'SizeAxis'])
2993            cosP,sinP = G2lat.CosSinAngle(H,P,G)
2994            Si = parmDict[phfx+'Size;i']
2995            Sa = parmDict[phfx+'Size;a']
2996            gami = 1.8*wave/(costh*np.pi*Si*Sa)
2997            sqtrm = np.sqrt((sinP*Sa)**2+(cosP*Si)**2)
2998            Sgam = gami*sqtrm
2999            dsi = gami*Si*cosP**2/sqtrm-Sgam/Si
3000            dsa = gami*Sa*sinP**2/sqtrm-Sgam/Sa
3001            gamDict[phfx+'Size;i'] = dsi*parmDict[phfx+'Size;mx']
3002            gamDict[phfx+'Size;a'] = dsa*parmDict[phfx+'Size;mx']
3003            sigDict[phfx+'Size;i'] = 2.*dsi*Sgam*(1.-parmDict[phfx+'Size;mx'])**2/ateln2
3004            sigDict[phfx+'Size;a'] = 2.*dsa*Sgam*(1.-parmDict[phfx+'Size;mx'])**2/ateln2
3005        else:           #ellipsoidal crystallites
3006            const = 1.8*wave/(np.pi*costh)
3007            Sij =[parmDict[phfx+'Size;%d'%(i)] for i in range(6)]
3008            H = np.array(refl[:3])
3009            lenR,dRdS = G2pwd.ellipseSizeDerv(H,Sij,GB)
3010            Sgam = const/lenR
3011            for i,item in enumerate([phfx+'Size;%d'%(j) for j in range(6)]):
3012                gamDict[item] = -(const/lenR**2)*dRdS[i]*parmDict[phfx+'Size;mx']
3013                sigDict[item] = -2.*Sgam*(const/lenR**2)*dRdS[i]*(1.-parmDict[phfx+'Size;mx'])**2/ateln2
3014        gamDict[phfx+'Size;mx'] = Sgam
3015        sigDict[phfx+'Size;mx'] = -2.*Sgam**2*(1.-parmDict[phfx+'Size;mx'])/ateln2
3016               
3017        #microstrain derivatives               
3018        if calcControls[phfx+'MustrainType'] == 'isotropic':
3019            Mgam = 0.018*parmDict[phfx+'Mustrain;i']*tand(refl[5+im]/2.)/np.pi
3020            gamDict[phfx+'Mustrain;i'] =  0.018*tanth*parmDict[phfx+'Mustrain;mx']/np.pi
3021            sigDict[phfx+'Mustrain;i'] =  0.036*Mgam*tanth*(1.-parmDict[phfx+'Mustrain;mx'])**2/(np.pi*ateln2)       
3022        elif calcControls[phfx+'MustrainType'] == 'uniaxial':
3023            H = np.array(refl[:3])
3024            P = np.array(calcControls[phfx+'MustrainAxis'])
3025            cosP,sinP = G2lat.CosSinAngle(H,P,G)
3026            Si = parmDict[phfx+'Mustrain;i']
3027            Sa = parmDict[phfx+'Mustrain;a']
3028            gami = 0.018*Si*Sa*tanth/np.pi
3029            sqtrm = np.sqrt((Si*cosP)**2+(Sa*sinP)**2)
3030            Mgam = gami/sqtrm
3031            dsi = -gami*Si*cosP**2/sqtrm**3
3032            dsa = -gami*Sa*sinP**2/sqtrm**3
3033            gamDict[phfx+'Mustrain;i'] = (Mgam/Si+dsi)*parmDict[phfx+'Mustrain;mx']
3034            gamDict[phfx+'Mustrain;a'] = (Mgam/Sa+dsa)*parmDict[phfx+'Mustrain;mx']
3035            sigDict[phfx+'Mustrain;i'] = 2*(Mgam/Si+dsi)*Mgam*(1.-parmDict[phfx+'Mustrain;mx'])**2/ateln2
3036            sigDict[phfx+'Mustrain;a'] = 2*(Mgam/Sa+dsa)*Mgam*(1.-parmDict[phfx+'Mustrain;mx'])**2/ateln2       
3037        else:       #generalized - P.W. Stephens model
3038            const = 0.018*refl[4+im]**2*tanth/np.pi
3039            Strms = G2spc.MustrainCoeff(refl[:3],SGData)
3040            Sum = 0
3041            for i,strm in enumerate(Strms):
3042                Sum += parmDict[phfx+'Mustrain;'+str(i)]*strm
3043                gamDict[phfx+'Mustrain;'+str(i)] = strm*parmDict[phfx+'Mustrain;mx']/2.
3044                sigDict[phfx+'Mustrain;'+str(i)] = strm*(1.-parmDict[phfx+'Mustrain;mx'])**2
3045            Mgam = const*np.sqrt(Sum)
3046            for i in range(len(Strms)):
3047                gamDict[phfx+'Mustrain;'+str(i)] *= Mgam/Sum
3048                sigDict[phfx+'Mustrain;'+str(i)] *= const**2/ateln2
3049        gamDict[phfx+'Mustrain;mx'] = Mgam
3050        sigDict[phfx+'Mustrain;mx'] = -2.*Mgam**2*(1.-parmDict[phfx+'Mustrain;mx'])/ateln2
3051    elif 'E' in calcControls[hfx+'histType']:
3052        return {},{}            #wrong - fix later if wanted
3053    else:   #'T'OF - All checked & OK
3054        if calcControls[phfx+'SizeType'] == 'isotropic':    #OK
3055            Sgam = 1.e-4*parmDict[hfx+'difC']*refl[4+im]**2/parmDict[phfx+'Size;i']
3056            gamDict[phfx+'Size;i'] = -Sgam*parmDict[phfx+'Size;mx']/parmDict[phfx+'Size;i']
3057            sigDict[phfx+'Size;i'] = -2.*Sgam**2*(1.-parmDict[phfx+'Size;mx'])**2/(ateln2*parmDict[phfx+'Size;i'])
3058        elif calcControls[phfx+'SizeType'] == 'uniaxial':   #OK
3059            const = 1.e-4*parmDict[hfx+'difC']*refl[4+im]**2
3060            H = np.array(refl[:3])
3061            P = np.array(calcControls[phfx+'SizeAxis'])
3062            cosP,sinP = G2lat.CosSinAngle(H,P,G)
3063            Si = parmDict[phfx+'Size;i']
3064            Sa = parmDict[phfx+'Size;a']
3065            gami = const/(Si*Sa)
3066            sqtrm = np.sqrt((sinP*Sa)**2+(cosP*Si)**2)
3067            Sgam = gami*sqtrm
3068            dsi = gami*Si*cosP**2/sqtrm-Sgam/Si
3069            dsa = gami*Sa*sinP**2/sqtrm-Sgam/Sa
3070            gamDict[phfx+'Size;i'] = dsi*parmDict[phfx+'Size;mx']
3071            gamDict[phfx+'Size;a'] = dsa*parmDict[phfx+'Size;mx']
3072            sigDict[phfx+'Size;i'] = 2.*dsi*Sgam*(1.-parmDict[phfx+'Size;mx'])**2/ateln2
3073            sigDict[phfx+'Size;a'] = 2.*dsa*Sgam*(1.-parmDict[phfx+'Size;mx'])**2/ateln2
3074        else:           #OK  ellipsoidal crystallites
3075            const = 1.e-4*parmDict[hfx+'difC']*refl[4+im]**2
3076            Sij =[parmDict[phfx+'Size;%d'%(i)] for i in range(6)]
3077            H = np.array(refl[:3])
3078            lenR,dRdS = G2pwd.ellipseSizeDerv(H,Sij,GB)
3079            Sgam = const/lenR
3080            for i,item in enumerate([phfx+'Size;%d'%(j) for j in range(6)]):
3081                gamDict[item] = -(const/lenR**2)*dRdS[i]*parmDict[phfx+'Size;mx']
3082                sigDict[item] = -2.*Sgam*(const/lenR**2)*dRdS[i]*(1.-parmDict[phfx+'Size;mx'])**2/ateln2
3083        gamDict[phfx+'Size;mx'] = Sgam  #OK
3084        sigDict[phfx+'Size;mx'] = -2.*Sgam**2*(1.-parmDict[phfx+'Size;mx'])/ateln2  #OK
3085               
3086        #microstrain derivatives               
3087        if calcControls[phfx+'MustrainType'] == 'isotropic':
3088            Mgam = 1.e-6*parmDict[hfx+'difC']*refl[4+im]*parmDict[phfx+'Mustrain;i']
3089            gamDict[phfx+'Mustrain;i'] =  1.e-6*refl[4+im]*parmDict[hfx+'difC']*parmDict[phfx+'Mustrain;mx']   #OK
3090            sigDict[phfx+'Mustrain;i'] =  2.*Mgam**2*(1.-parmDict[phfx+'Mustrain;mx'])**2/(ateln2*parmDict[phfx+'Mustrain;i'])       
3091        elif calcControls[phfx+'MustrainType'] == 'uniaxial':
3092            H = np.array(refl[:3])
3093            P = np.array(calcControls[phfx+'MustrainAxis'])
3094            cosP,sinP = G2lat.CosSinAngle(H,P,G)
3095            Si = parmDict[phfx+'Mustrain;i']
3096            Sa = parmDict[phfx+'Mustrain;a']
3097            gami = 1.e-6*parmDict[hfx+'difC']*refl[4+im]*Si*Sa
3098            sqtrm = np.sqrt((Si*cosP)**2+(Sa*sinP)**2)
3099            Mgam = gami/sqtrm
3100            dsi = -gami*Si*cosP**2/sqtrm**3
3101            dsa = -gami*Sa*sinP**2/sqtrm**3
3102            gamDict[phfx+'Mustrain;i'] = (Mgam/Si+dsi)*parmDict[phfx+'Mustrain;mx']
3103            gamDict[phfx+'Mustrain;a'] = (Mgam/Sa+dsa)*parmDict[phfx+'Mustrain;mx']
3104            sigDict[phfx+'Mustrain;i'] = 2*(Mgam/Si+dsi)*Mgam*(1.-parmDict[phfx+'Mustrain;mx'])**2/ateln2
3105            sigDict[phfx+'Mustrain;a'] = 2*(Mgam/Sa+dsa)*Mgam*(1.-parmDict[phfx+'Mustrain;mx'])**2/ateln2       
3106        else:       #generalized - P.W. Stephens model OK
3107            Strms = G2spc.MustrainCoeff(refl[:3],SGData)
3108            const = 1.e-6*parmDict[hfx+'difC']*refl[4+im]**3
3109            Sum = 0
3110            for i,strm in enumerate(Strms):
3111                Sum += parmDict[phfx+'Mustrain;'+str(i)]*strm
3112                gamDict[phfx+'Mustrain;'+str(i)] = strm*parmDict[phfx+'Mustrain;mx']/2.
3113                sigDict[phfx+'Mustrain;'+str(i)] = strm*(1.-parmDict[phfx+'Mustrain;mx'])**2
3114            Mgam = const*np.sqrt(Sum)
3115            for i in range(len(Strms)):
3116                gamDict[phfx+'Mustrain;'+str(i)] *= Mgam/Sum
3117                sigDict[phfx+'Mustrain;'+str(i)] *= const**2/ateln2       
3118        gamDict[phfx+'Mustrain;mx'] = Mgam
3119        sigDict[phfx+'Mustrain;mx'] = -2.*Mgam**2*(1.-parmDict[phfx+'Mustrain;mx'])/ateln2
3120       
3121    return sigDict,gamDict
3122       
3123def GetReflPos(refl,im,wave,A,pfx,hfx,phfx,calcControls,parmDict):
3124    'Needs a doc string'
3125    if im:
3126        h,k,l,m = refl[:4]
3127        vec = np.array([parmDict[pfx+'mV0'],parmDict[pfx+'mV1'],parmDict[pfx+'mV2']])
3128        d = 1./np.sqrt(G2lat.calc_rDsqSS(np.array([h,k,l,m]),A,vec))
3129    else:
3130        h,k,l = refl[:3]
3131        d = 1./np.sqrt(G2lat.calc_rDsq(np.array([h,k,l]),A))
3132    refl[4+im] = d
3133    if 'C' in calcControls[hfx+'histType'] or 'B' in calcControls[hfx+'histType']:
3134        pos = 2.0*asind(wave/(2.0*d))+parmDict[hfx+'Zero']
3135        const = 9.e-2/(np.pi*parmDict[hfx+'Gonio. radius'])                  #shifts in microns
3136        if 'Bragg' in calcControls[hfx+'instType']:
3137            pos -= const*(4.*parmDict[hfx+'Shift']*cosd(pos/2.0)+ \
3138                parmDict[hfx+'Transparency']*sind(pos)*100.0)            #trans(=1/mueff) in cm
3139        else:               #Debye-Scherrer - simple but maybe not right
3140            pos -= const*(parmDict[hfx+'DisplaceX']*cosd(pos)+(parmDict[hfx+'DisplaceY']+parmDict[phfx+'LayerDisp'])*sind(pos))
3141    elif 'E' in calcControls[hfx+'histType']:
3142        pos = 12.397639/(2.0*d*sind(parmDict[hfx+'2-theta']/2.0))+parmDict[hfx+'ZE']+parmDict[hfx+'YE']*d+parmDict[hfx+'XE']*d**2
3143    elif 'T' in calcControls[hfx+'histType']:
3144        pos = parmDict[hfx+'difC']*d+parmDict[hfx+'difA']*d**2+parmDict[hfx+'difB']/d+parmDict[hfx+'Zero']
3145        #do I need sample position effects - maybe?
3146    return pos
3147
3148def GetReflPosDerv(refl,im,wave,A,pfx,hfx,phfx,calcControls,parmDict):
3149    'Needs a doc string'
3150    dpr = 180./np.pi
3151    if im:
3152        h,k,l,m = refl[:4]
3153        vec = np.array([parmDict[pfx+'mV0'],parmDict[pfx+'mV1'],parmDict[pfx+'mV2']])
3154        dstsq = G2lat.calc_rDsqSS(np.array([h,k,l,m]),A,vec)
3155        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
3156    else:
3157        m = 0
3158        h,k,l = refl[:3]       
3159        dstsq = G2lat.calc_rDsq(np.array([h,k,l]),A)
3160    dst = np.sqrt(dstsq)
3161    dsp = 1./dst
3162    if 'C' in calcControls[hfx+'histType'] or 'B' in calcControls[hfx+'histType']:
3163        pos = refl[5+im]-parmDict[hfx+'Zero']
3164        const = dpr/np.sqrt(1.0-wave**2*dstsq/4.0)
3165        dpdw = const*dst
3166        dpdA = np.array([h**2,k**2,l**2,h*k,h*l,k*l])*const*wave/(2.0*dst)
3167        dpdZ = 1.0
3168        dpdV = np.array([2.*h*A[0]+k*A[3]+l*A[4],2*k*A[1]+h*A[3]+l*A[5],
3169            2*l*A[2]+h*A[4]+k*A[5]])*m*const*wave/(2.0*dst)
3170        shft = 9.e-2/(np.pi*parmDict[hfx+'Gonio. radius'])                  #shifts in microns
3171        if 'Bragg' in calcControls[hfx+'instType']:
3172            dpdSh = -4.*shft*cosd(pos/2.0)
3173            dpdTr = -shft*sind(pos)*100.0
3174            return dpdA,dpdw,dpdZ,dpdSh,dpdTr,0.,0.,dpdV
3175        else:               #Debye-Scherrer - simple but maybe not right
3176            dpdXd = -shft*cosd(pos)
3177            dpdYd = -shft*sind(pos)
3178            return dpdA,dpdw,dpdZ,0.,0.,dpdXd,dpdYd,dpdV
3179    elif 'E' in calcControls[hfx+'histType']:
3180        tth = parmDict[hfx+'2-theta']/2.0
3181        dpdZE = 1.0
3182        dpdYE = dsp
3183        dpdXE = dsp**2
3184        dpdA = np.array([h**2,k**2,l**2,h*k,h*l,k*l])*refl[5+im]*dsp**2/2.
3185        dpdTTh = -12.397639*cosd(tth)/(dsp*sind(tth)**2)
3186        return dpdA,dpdTTh,dpdXE,dpdYE,dpdZE
3187    elif 'T' in calcControls[hfx+'histType']:
3188        dpdA = -np.array([h**2,k**2,l**2,h*k,h*l,k*l])*parmDict[hfx+'difC']*dsp**3/2.
3189        dpdZ = 1.0
3190        dpdDC = dsp
3191        dpdDA = dsp**2
3192        dpdDB = 1./dsp
3193        dpdV = np.array([2.*h*A[0]+k*A[3]+l*A[4],2*k*A[1]+h*A[3]+l*A[5],
3194            2*l*A[2]+h*A[4]+k*A[5]])*m*parmDict[hfx+'difC']*dsp**3/2.
3195        return dpdA,dpdZ,dpdDC,dpdDA,dpdDB,dpdV
3196           
3197def GetHStrainShift(refl,im,SGData,phfx,hfx,calcControls,parmDict):
3198    '''Computes the shifts in peak position due to the Hydrostatic strain
3199    (HStrain, Dij terms).
3200    This routine is not used anywhere
3201    '''
3202    laue = SGData['SGLaue']
3203    uniq = SGData['SGUniq']
3204    h,k,l = refl[:3]
3205    if laue in ['m3','m3m']:
3206        hkl1 = (h**2+k**2+l**2)
3207        hkl2 = ((h*k)**2+(h*l)**2+(k*l)**2)/hkl1**2
3208        Dij = parmDict[phfx+'D11']*hkl1+parmDict[phfx+'eA']*hkl2
3209    elif laue in ['6/m','6/mmm','3m1','31m','3']:
3210        Dij = parmDict[phfx+'D11']*(h**2+k**2+h*k)+parmDict[phfx+'D33']*l**2
3211    elif laue in ['3R','3mR']:
3212        Dij = parmDict[phfx+'D11']*(h**2+k**2+l**2)+parmDict[phfx+'D12']*(h*k+h*l+k*l)
3213    elif laue in ['4/m','4/mmm']:
3214        Dij = parmDict[phfx+'D11']*(h**2+k**2)+parmDict[phfx+'D33']*l**2
3215    elif laue in ['mmm']:
3216        Dij = parmDict[phfx+'D11']*h**2+parmDict[phfx+'D22']*k**2+parmDict[phfx+'D33']*l**2
3217    elif laue in ['2/m']:
3218        Dij = parmDict[phfx+'D11']*h**2+parmDict[phfx+'D22']*k**2+parmDict[phfx+'D33']*l**2
3219        if uniq == 'a':
3220            Dij += parmDict[phfx+'D23']*k*l
3221        elif uniq == 'b':
3222            Dij += parmDict[phfx+'D13']*h*l
3223        elif uniq == 'c':
3224            Dij += parmDict[phfx+'D12']*h*k
3225    else:
3226        Dij = parmDict[phfx+'D11']*h**2+parmDict[phfx+'D22']*k**2+parmDict[phfx+'D33']*l**2+ \
3227            parmDict[phfx+'D12']*h*k+parmDict[phfx+'D13']*h*l+parmDict[phfx+'D23']*k*l
3228    if 'C' in calcControls[hfx+'histType'] or 'B' in calcControls[hfx+'histType']:
3229        return -180.*Dij*refl[4+im]**2*tand(refl[5+im]/2.0)/np.pi
3230    elif 'E' in calcControls[hfx+'histType']:
3231        return Dij*refl[5+im]/refl[4+im]**2
3232    else:
3233        return -Dij*parmDict[hfx+'difC']*0.5*refl[4+im]**2
3234           
3235def GetHStrainShiftDerv(refl,im,SGData,phfx,hfx,calcControls,parmDict):
3236    '''Computes the derivatives due to the shifts in peak position from Hydrostatic strain
3237    (HStrain, Dij terms).
3238    '''
3239    laue = SGData['SGLaue']
3240    uniq = SGData['SGUniq']
3241    h,k,l = refl[:3]
3242    if laue in ['m3','m3m']:
3243        dDijDict = {phfx+'D11':h**2+k**2+l**2,
3244            phfx+'eA':((h*k)**2+(h*l)**2+(k*l)**2)/(h**2+k**2+l**2)**2}
3245    elif laue in ['6/m','6/mmm','3m1','31m','3']:
3246        dDijDict = {phfx+'D11':h**2+k**2+h*k,phfx+'D33':l**2}
3247    elif laue in ['3R','3mR']:
3248        dDijDict = {phfx+'D11':h**2+k**2+l**2,phfx+'D12':h*k+h*l+k*l}
3249    elif laue in ['4/m','4/mmm']:
3250        dDijDict = {phfx+'D11':h**2+k**2,phfx+'D33':l**2}
3251    elif laue in ['mmm']:
3252        dDijDict = {phfx+'D11':h**2,phfx+'D22':k**2,phfx+'D33':l**2}
3253    elif laue in ['2/m']:
3254        dDijDict = {phfx+'D11':h**2,phfx+'D22':k**2,phfx+'D33':l**2}
3255        if uniq == 'a':
3256            dDijDict[phfx+'D23'] = k*l
3257        elif uniq == 'b':
3258            dDijDict[phfx+'D13'] = h*l
3259        elif uniq == 'c':
3260            dDijDict[phfx+'D12'] = h*k
3261    else:
3262        dDijDict = {phfx+'D11':h**2,phfx+'D22':k**2,phfx+'D33':l**2,
3263            phfx+'D12':h*k,phfx+'D13':h*l,phfx+'D23':k*l}
3264    if 'C' in calcControls[hfx+'histType'] or 'B' in calcControls[hfx+'histType']:
3265        for item in dDijDict:
3266            dDijDict[item] *= 180.0*refl[4+im]**2*tand(refl[5+im]/2.0)/np.pi
3267    elif 'E' in calcControls[hfx+'histType']:
3268        for item in dDijDict:
3269            dDijDict[item] *= refl[5+im]/refl[4+im]**2
3270    else:
3271        for item in dDijDict:
3272            dDijDict[item] *= -parmDict[hfx+'difC']*refl[4+im]**3/2.
3273    return dDijDict
3274   
3275def GetDij(phfx,SGData,parmDict):
3276    HSvals = [parmDict[phfx+name] for name in G2spc.HStrainNames(SGData)]
3277    return G2spc.HStrainVals(HSvals,SGData)
3278               
3279def GetFobsSq(Histograms,Phases,parmDict,calcControls):
3280    '''Compute the observed structure factors for Powder histograms and store in reflection array
3281    Multiprocessing support added
3282    '''
3283    if GSASIIpath.GetConfigValue('Show_timing',False):
3284        starttime = time.time() #; print 'start GetFobsSq'
3285    histoList = list(Histograms.keys())
3286    histoList.sort()
3287    Ka2 = shl = lamRatio = kRatio = None
3288    for histogram in histoList:
3289        if 'PWDR' in histogram[:4]:
3290            Histogram = Histograms[histogram]
3291            hId = Histogram['hId']
3292            hfx = ':%d:'%(hId)
3293            Limits = calcControls[hfx+'Limits']
3294            if 'C' in calcControls[hfx+'histType']:
3295                shl = max(parmDict[hfx+'SH/L'],0.0005)
3296                Ka2 = False
3297                kRatio = 0.0
3298                if hfx+'Lam1' in list(parmDict.keys()):
3299                    Ka2 = True
3300                    lamRatio = 360*(parmDict[hfx+'Lam2']-parmDict[hfx+'Lam1'])/(np.pi*parmDict[hfx+'Lam1'])
3301                    kRatio = parmDict[hfx+'I(L2)/I(L1)']
3302            x,y,w,yc,yb,yd = Histogram['Data']
3303            xMask = ma.getmaskarray(x)
3304            xB = np.searchsorted(x,Limits[0])
3305            xF = np.searchsorted(x,Limits[1])
3306            ymb = np.array(y-yb)
3307            ymb = np.where(ymb,ymb,1.0)
3308            ycmb = np.array(yc-yb)
3309            ratio = 1./np.where(ycmb,ycmb/ymb,1.e10)         
3310            refLists = Histogram['Reflection Lists']
3311            for phase in refLists:
3312                if phase not in Phases:     #skips deleted or renamed phases silently!
3313                    continue
3314                Phase = Phases[phase]
3315                if histogram not in Phase['Histograms']:
3316                    continue
3317                im = 0
3318                if Phase['General'].get('Modulated',False):
3319                    im = 1
3320                pId = Phase['pId']
3321                phfx = '%d:%d:'%(pId,hId)
3322                refDict = refLists[phase]
3323                sumFo = 0.0
3324                sumdF = 0.0
3325                sumFosq = 0.0
3326                sumdFsq = 0.0
3327                sumInt = 0.0
3328                nExcl = 0
3329                # test to see if we are using multiprocessing below
3330                useMP,ncores = G2mp.InitMP()
3331                if len(refDict['RefList']) < 100: useMP = False       
3332                if useMP: # multiprocessing: create a set of initialized Python processes
3333                    MPpool = mp.Pool(G2mp.ncores,G2mp.InitFobsSqGlobals,
3334                                    [x,ratio,shl,xB,xF,im,lamRatio,kRatio,xMask,Ka2])
3335                    profArgs = [[] for i in range(G2mp.ncores)]
3336                else:
3337                    G2mp.InitFobsSqGlobals(x,ratio,shl,xB,xF,im,lamRatio,kRatio,xMask,Ka2)
3338                if 'C' in calcControls[hfx+'histType']:
3339                    # are we multiprocessing?
3340                    for iref,refl in enumerate(refDict['RefList']):
3341                        if useMP: 
3342                            profArgs[iref%G2mp.ncores].append((refl,iref))
3343                        else:
3344                            icod = G2mp.ComputeFobsSqCW(refl,iref)
3345                            if type(icod) is tuple:
3346                                refl[8+im] = icod[0]
3347                                sumInt += icod[1]
3348                                if parmDict.get(phfx+'LeBail'): 
3349                                    refl[9+im] = refl[8+im]
3350                            elif icod == -1:
3351                                refl[3+im] *= -1
3352                                nExcl += 1
3353                            elif icod == -2:
3354                                break
3355                    if useMP:
3356                        for sInt,resList in MPpool.imap_unordered(G2mp.ComputeFobsSqCWbatch,profArgs):
3357                            sumInt += sInt
3358                            for refl8im,irefl in resList:
3359                                if refl8im is None:
3360                                    refDict['RefList'][irefl][3+im] *= -1
3361                                    nExcl += 1
3362                                else:
3363                                    refDict['RefList'][irefl][8+im] = refl8im
3364                                    if parmDict.get(phfx+'LeBail'):
3365                                        refDict['RefList'][irefl][9+im] = refDict['RefList'][irefl][8+im]
3366                elif 'T' in calcControls[hfx+'histType']:
3367                    for iref,refl in enumerate(refDict['RefList']):
3368                        if useMP: 
3369                            profArgs[iref%G2mp.ncores].append((refl,iref))
3370                        else:
3371                            icod = G2mp.ComputeFobsSqTOF(refl,iref)
3372                            if type(icod) is tuple:
3373                                refl[8+im] = icod[0]
3374                                sumInt += icod[1]
3375                                if parmDict.get(phfx+'LeBail'): 
3376                                    refl[9+im] = refl[8+im]
3377                            elif icod == -1:
3378                                refl[3+im] *= -1
3379                                nExcl += 1
3380                            elif icod == -2:
3381                                break
3382                    if useMP:
3383                        for sInt,resList in MPpool.imap_unordered(G2mp.ComputeFobsSqTOFbatch,profArgs):
3384                            sumInt += sInt
3385                            for refl8im,irefl in resList:
3386                                if refl8im is None:
3387                                    refDict['RefList'][irefl][3+im] *= -1
3388                                    nExcl += 1
3389                                else:
3390                                    refDict['RefList'][irefl][8+im] = refl8im
3391                                    if parmDict.get(phfx+'LeBail'):
3392                                        refDict['RefList'][irefl][9+im] = refDict['RefList'][irefl][8+im]
3393                elif 'E' in calcControls[hfx+'histType']:
3394                    for iref,refl in enumerate(refDict['RefList']):
3395                        if useMP: 
3396                            profArgs[iref%G2mp.ncores].append((refl,iref))
3397                        else:
3398                            icod = G2mp.ComputeFobsSqED(refl,iref)
3399                            if type(icod) is tuple:
3400                                refl[8+im] = icod[0]
3401                                sumInt += icod[1]
3402                                if parmDict.get(phfx+'LeBail'): 
3403                                    refl[9+im] = refl[8+im]
3404                            elif icod == -1:
3405                                refl[3+im] *= -1
3406                                nExcl += 1
3407                            elif icod == -2:
3408                                break
3409                    if useMP:
3410                        for sInt,resList in MPpool.imap_unordered(G2mp.ComputeFobsSqEDbatch,profArgs):
3411                            sumInt += sInt
3412                            for refl8im,irefl in resList:
3413                                if refl8im is None:
3414                                    refDict['RefList'][irefl][3+im] *= -1
3415                                    nExcl += 1
3416                                else:
3417                                    refDict['RefList'][irefl][8+im] = refl8im
3418                                    if parmDict.get(phfx+'LeBail'):
3419                                        refDict['RefList'][irefl][9+im] = refDict['RefList'][irefl][8+im]
3420                elif 'B' in calcControls[hfx+'histType']:
3421                    for iref,refl in enumerate(refDict['RefList']):
3422                        if useMP: 
3423                            profArgs[iref%G2mp.ncores].append((refl,iref))
3424                        else:
3425                            icod = G2mp.ComputeFobsSqPink(refl,iref)
3426                            if type(icod) is tuple:
3427                                refl[8+im] = icod[0]
3428                                sumInt += icod[1]
3429                                if parmDict.get(phfx+'LeBail'): 
3430                                    refl[9+im] = refl[8+im]
3431                            elif icod == -1:
3432                                refl[3+im] *= -1
3433                                nExcl += 1
3434                            elif icod == -2:
3435                                break
3436                    if useMP:
3437                        for sInt,resList in MPpool.imap_unordered(G2mp.ComputeFobsSqPinkbatch,profArgs):
3438                            sumInt += sInt
3439                            for refl8im,irefl in resList:
3440                                if refl8im is None:
3441                                    refDict['RefList'][irefl][3+im] *= -1
3442                                    nExcl += 1
3443                                else:
3444                                    refDict['RefList'][irefl][8+im] = refl8im
3445                                    if parmDict.get(phfx+'LeBail'):
3446                                        refDict['RefList'][irefl][9+im] = refDict['RefList'][irefl][8+im]
3447                if useMP: MPpool.terminate()
3448                sumFo = 0.0
3449                sumdF = 0.0
3450                sumFosq = 0.0
3451                sumdFsq = 0.0
3452                for iref,refl in enumerate(refDict['RefList']):
3453                    Fo = np.sqrt(np.abs(refl[8+im]))
3454                    Fc = np.sqrt(np.abs(refl[9+im]))
3455                    sumFo += Fo
3456                    sumFosq += refl[8+im]**2
3457                    sumdF += np.abs(Fo-Fc)
3458                    sumdFsq += (refl[8+im]-refl[9+im])**2
3459                if sumFo:
3460                    Histogram['Residuals'][phfx+'Rf'] = min(100.,(sumdF/sumFo)*100.)
3461                    Histogram['Residuals'][phfx+'Rf^2'] = min(100.,np.sqrt(sumdFsq/sumFosq)*100.)
3462                else:
3463                    Histogram['Residuals'][phfx+'Rf'] = 100.
3464                    Histogram['Residuals'][phfx+'Rf^2'] = 100.
3465                Histogram['Residuals'][phfx+'sumInt'] = sumInt
3466                Histogram['Residuals'][phfx+'Nref'] = len(refDict['RefList'])-nExcl
3467                Histogram['Residuals']['hId'] = hId
3468        elif 'HKLF' in histogram[:4]:
3469            Histogram = Histograms[histogram]
3470            Histogram['Residuals']['hId'] = Histograms[histogram]['hId']
3471    if GSASIIpath.GetConfigValue('Show_timing',False):
3472        print ('GetFobsSq t=',time.time()-starttime)
3473               
3474def getPowderProfile(parmDict,x,varylist,Histogram,Phases,calcControls,pawleyLookup,histogram=None):
3475    'Computes the powder pattern for a histogram based on contributions from all used phases'
3476    if GSASIIpath.GetConfigValue('Show_timing',False): starttime = time.time()
3477   
3478    def GetReflSigGamCW(refl,im,wave,G,GB,phfx,calcControls,parmDict):
3479        U = parmDict[hfx+'U']
3480        V = parmDict[hfx+'V']
3481        W = parmDict[hfx+'W']
3482        X = parmDict[hfx+'X']
3483        Y = parmDict[hfx+'Y']
3484        Z = parmDict[hfx+'Z']
3485        tanPos = tand(refl[5+im]/2.0)
3486        Ssig,Sgam = GetSampleSigGam(refl,im,wave,G,GB,SGData,hfx,phfx,calcControls,parmDict)
3487        sig = U*tanPos**2+V*tanPos+W+Ssig     #save peak sigma
3488        sig = max(0.001,sig)
3489        gam = X/cosd(refl[5+im]/2.0)+Y*tanPos+Sgam+Z     #save peak gamma
3490        gam = max(0.001,gam)
3491        return sig,gam
3492               
3493    def GetReflSigGamTOF(refl,im,G,GB,phfx,calcControls,parmDict):
3494        sig = parmDict[hfx+'sig-0']+parmDict[hfx+'sig-1']*refl[4+im]**2+   \
3495            parmDict[hfx+'sig-2']*refl[4+im]**4+parmDict[hfx+'sig-q']*refl[4+im]
3496        gam = parmDict[hfx+'X']*refl[4+im]+parmDict[hfx+'Y']*refl[4+im]**2+parmDict[hfx+'Z']
3497        Ssig,Sgam = GetSampleSigGam(refl,im,0.0,G,GB,SGData,hfx,phfx,calcControls,parmDict)
3498        sig += Ssig
3499        gam += Sgam
3500        return sig,gam
3501   
3502    def GetReflSigGamED(refl,im,G,GB,phfx,calcControls,parmDict):
3503        sig = parmDict[hfx+'A']*refl[5+im]**2+parmDict[hfx+'B']*refl[5+im]+parmDict[hfx+'C']
3504        gam = 0.001
3505        # Ssig,Sgam = GetSampleSigGam(refl,im,0.0,G,GB,SGData,hfx,phfx,calcControls,parmDict)
3506        # sig += Ssig
3507        # gam += Sgam
3508        return sig,gam
3509       
3510    def GetReflAlpBet(refl,im,hfx,parmDict):
3511        alp = parmDict[hfx+'alpha']/refl[4+im]
3512        bet = parmDict[hfx+'beta-0']+parmDict[hfx+'beta-1']/refl[4+im]**4+parmDict[hfx+'beta-q']/refl[4+im]**2
3513        return alp,bet
3514       
3515    def GetPinkReflAlpBet(refl,im,hfx,parmDict):
3516        tanPos = tand(refl[5+im]/2.0)
3517        alp = max(0.1,parmDict[hfx+'alpha-0']+parmDict[hfx+'alpha-1']*tanPos)
3518        bet = max(0.001,parmDict[hfx+'beta-0']+parmDict[hfx+'beta-1']*tanPos)
3519        return alp,bet
3520
3521    def SavePartial(phase,y):
3522        phPartialFP = open(phasePartials,'ab')  # append to file
3523        pickle.dump(phase,phPartialFP)
3524        pickle.dump(y,phPartialFP)
3525        phPartialFP.close()
3526           
3527    hId = Histogram['hId']
3528    hfx = ':%d:'%(hId)
3529    bakType = calcControls[hfx+'bakType']
3530    fixback = Histogram['Background'][1].get('fixback',None)
3531    yb,Histogram['sumBk'] = G2pwd.getBackground(hfx,parmDict,bakType,calcControls[hfx+'histType'],x,fixback)
3532    yc = np.zeros_like(yb)
3533    cw = np.diff(ma.getdata(x))
3534    cw = np.append(cw,cw[-1])
3535    # set up for save of phase partials if triggered in GSASIIdataGUI.OnRefinePartials
3536    phasePartials = calcControls.get('PhasePartials',None)
3537    Nphase = len(Histogram['Reflection Lists'])     #partials made ony if Nphase > 1
3538    if phasePartials:
3539       
3540        phPartialFP = open(phasePartials,'ab')  # create histogram header
3541        pickle.dump(None,phPartialFP)
3542        pickle.dump(hId,phPartialFP)
3543        if Nphase > 1:
3544            pickle.dump(x,phPartialFP)
3545            pickle.dump(yb,phPartialFP)
3546        else:
3547            pickle.dump(None,phPartialFP)
3548            pickle.dump(None,phPartialFP)
3549        phPartialFP.close()
3550       
3551    if 'C' in calcControls[hfx+'histType']:   
3552        shl = max(parmDict[hfx+'SH/L'],0.002)
3553        Ka2 = False
3554        if hfx+'Lam1' in (parmDict.keys()):
3555            wave = parmDict[hfx+'Lam1']
3556            Ka2 = True
3557            lamRatio = 360*(parmDict[hfx+'Lam2']-parmDict[hfx+'Lam1'])/(np.pi*parmDict[hfx+'Lam1'])
3558            kRatio = parmDict[hfx+'I(L2)/I(L1)']
3559        else:
3560            wave = parmDict[hfx+'Lam']
3561    elif 'B' in calcControls[hfx+'histType']:
3562            wave = parmDict[hfx+'Lam']
3563    else:
3564        shl = 0.
3565    for phase in Histogram['Reflection Lists']:
3566        refDict = Histogram['Reflection Lists'][phase]
3567        if phase not in Phases:     #skips deleted or renamed phases silently!
3568            continue
3569        Phase = Phases[phase]
3570        if histogram and not histogram in Phase['Histograms']:
3571            continue
3572        pId = Phase['pId']
3573        pfx = '%d::'%(pId)
3574        phfx = '%d:%d:'%(pId,hId)
3575        hfx = ':%d:'%(hId)
3576        SGData = Phase['General']['SGData']
3577        SGMT = np.array([ops[0].T for ops in SGData['SGOps']])
3578        im = 0
3579        if Phase['General'].get('Modulated',False):
3580            SSGData = Phase['General']['SSGData']
3581            im = 1  #offset in SS reflection list
3582        Dij = GetDij(phfx,SGData,parmDict)
3583        A = [parmDict[pfx+'A%d'%(i)]+Dij[i] for i in range(6)]  #TODO: need to do something if Dij << 0.
3584        G,g = G2lat.A2Gmat(A)       #recip & real metric tensors
3585        if np.any(np.diag(G)<0.):
3586            msg = 'Invalid metric tensor for phase #{}\n   ({})'.format(
3587                pId,Phase['General']['Name'])
3588        elif np.any(np.isnan(A)):
3589            msg = 'Infinite metric tensor for phase #{}\n   ({})'.format(
3590                pId,Phase['General']['Name'])
3591        else:
3592            msg = None
3593        if msg:
3594            print('\nInvalid cell metric tensor for phase #{} ({})\n'.format(
3595                pId,Phase['General']['Name']),'values (A): {:.3f} {:.3f} {:.3f} {:.3f} {:.3f} {:.3f}\n'.format(*A))
3596            raise G2obj.G2Exception('Error: '+msg+' See console.\nCheck for refinement of conflicting variables')
3597        GA,GB = G2lat.Gmat2AB(G)    #Orthogonalization matrices
3598        Vst = np.sqrt(nl.det(G))    #V*
3599        if not Phase['General'].get('doPawley') and not parmDict.get(phfx+'LeBail'):
3600            if 'E' in calcControls[hfx+'histType']:
3601                print('\n\n**** Error: EDX data not suitable for Rietveld refinement ****\n\n')
3602            else:
3603                if im:
3604                    SStructureFactor(refDict,G,hfx,pfx,SGData,SSGData,calcControls,parmDict)
3605                elif parmDict[pfx+'isMag'] and 'N' in calcControls[hfx+'histType']:
3606                    MagStructureFactor2(refDict,G,hfx,pfx,SGData,calcControls,parmDict)
3607                else:
3608                    StructureFactor2(refDict,G,hfx,pfx,SGData,calcControls,parmDict)
3609        badPeak = False
3610        # test to see if we are using multiprocessing here
3611        useMP,ncores = G2mp.InitMP()
3612        if len(refDict['RefList']) < 100: useMP = False       
3613        if phasePartials:
3614            useMP = False
3615            ypartial = np.zeros_like(yb)
3616        if useMP: # multiprocessing: create a set of initialized Python processes
3617            MPpool = mp.Pool(ncores,G2mp.InitPwdrProfGlobals,[im,shl,x])
3618            profArgs = [[] for i in range(ncores)]
3619        if 'C' in calcControls[hfx+'histType']:
3620            for iref,refl in enumerate(refDict['RefList']):
3621                if im:
3622                    h,k,l,m = refl[:4]
3623                else:
3624                    h,k,l = refl[:3]
3625                Uniq = np.inner(refl[:3],SGMT)
3626                refl[5+im] = GetReflPos(refl,im,wave,A,pfx,hfx,phfx,calcControls,parmDict)         #corrected reflection position
3627#                refl[5+im] += GetHStrainShift(refl,im,SGData,phfx,hfx,calcControls,parmDict)               #apply hydrostatic strain shift
3628                Lorenz = 1./(2.*sind(refl[5+im]/2.)**2*cosd(refl[5+im]/2.))           #Lorentz correction
3629                refl[6+im:8+im] = GetReflSigGamCW(refl,im,wave,G,GB,phfx,calcControls,parmDict)    #peak sig & gam
3630                refl[11+im:15+im] = GetIntensityCorr(refl,im,Uniq,G,g,pfx,phfx,hfx,SGData,calcControls,parmDict)
3631                refl[11+im] *= Vst*Lorenz
3632                 
3633                if Phase['General'].get('doPawley'):
3634                    try:
3635                        if im:
3636                            pInd = pfx+'PWLref:%d'%(pawleyLookup[pfx+'%d,%d,%d,%d'%(h,k,l,m)])
3637                        else:
3638                            pInd = pfx+'PWLref:%d'%(pawleyLookup[pfx+'%d,%d,%d'%(h,k,l)])
3639                        refl[9+im] = parmDict[pInd]
3640                    except KeyError:
3641#                        print ' ***Error %d,%d,%d missing from Pawley reflection list ***'%(h,k,l)
3642                        continue
3643                Wd,fmin,fmax = G2pwd.getWidthsCW(refl[5+im],refl[6+im],refl[7+im],shl)
3644                iBeg = np.searchsorted(x,refl[5+im]-fmin)
3645                iFin = np.searchsorted(x,refl[5+im]+fmax)
3646                if not iBeg+iFin:       #peak below low limit - skip peak
3647                    continue
3648                elif not iBeg-iFin:     #peak above high limit - done
3649                    break
3650                elif iBeg > iFin:   #bad peak coeff - skip
3651                    badPeak = True
3652                    continue
3653                if useMP:
3654                    profArgs[iref%ncores].append((refl[5+im],refl,iBeg,iFin,1.))
3655                else:
3656                    fp = G2pwd.getFCJVoigt3(refl[5+im],refl[6+im],refl[7+im],shl,ma.getdata(x[iBeg:iFin]))[0]
3657                    yc[iBeg:iFin] += refl[11+im]*refl[9+im]*fp   #>90% of time spent here
3658                    if phasePartials: ypartial[iBeg:iFin] += refl[11+im]*refl[9+im]*fp
3659                if Ka2:
3660                    pos2 = refl[5+im]+lamRatio*tand(refl[5+im]/2.0)       # + 360/pi * Dlam/lam * tan(th)
3661                    Wd,fmin,fmax = G2pwd.getWidthsCW(pos2,refl[6+im],refl[7+im],shl)
3662                    iBeg = np.searchsorted(x,pos2-fmin)
3663                    iFin = np.searchsorted(x,pos2+fmax)
3664                    if not iBeg+iFin:       #peak below low limit - skip peak
3665                        continue
3666                    elif not iBeg-iFin:     #peak above high limit - done
3667                        return yc,yb
3668                    elif iBeg > iFin:   #bad peak coeff - skip
3669                        continue
3670                    if useMP:
3671                        profArgs[iref%ncores].append((pos2,refl,iBeg,iFin,kRatio))
3672                    else:
3673                        fp2 = G2pwd.getFCJVoigt3(pos2,refl[6+im],refl[7+im],shl,ma.getdata(x[iBeg:iFin]))[0]
3674                        yc[iBeg:iFin] += refl[11+im]*refl[9+im]*kRatio*fp2       #and here
3675                        if phasePartials: ypartial[iBeg:iFin] += refl[11+im]*refl[9+im]*kRatio*fp2
3676        elif 'E' in calcControls[hfx+'histType']:
3677           
3678            for iref,refl in enumerate(refDict['RefList']):
3679                if im:
3680                    h,k,l,m = refl[:4]
3681                else:
3682                    h,k,l = refl[:3]
3683                Uniq = np.inner(refl[:3],SGMT)
3684                refl[5+im] = GetReflPos(refl,im,0.0,A,pfx,hfx,phfx,calcControls,parmDict)         #corrected reflection position
3685#                refl[5+im] += GetHStrainShift(refl,im,SGData,phfx,hfx,calcControls,parmDict)               #apply hydrostatic strain shift
3686                refl[6+im:8+im] = GetReflSigGamED(refl,im,G,GB,phfx,calcControls,parmDict)    #peak sig & gam
3687                refl[11+im] = 1.0       #no intensity corrections; default = 1.0
3688                 
3689                if Phase['General'].get('doPawley'):
3690                    try:
3691                        if im:
3692                            pInd = pfx+'PWLref:%d'%(pawleyLookup[pfx+'%d,%d,%d,%d'%(h,k,l,m)])
3693                        else:
3694                            pInd = pfx+'PWLref:%d'%(pawleyLookup[pfx+'%d,%d,%d'%(h,k,l)])
3695                        refl[9+im] = parmDict[pInd]
3696                    except KeyError:
3697                        continue
3698                Wd,fmin,fmax = G2pwd.getWidthsED(refl[5+im],refl[6+im])
3699                iBeg = np.searchsorted(x,refl[5+im]-fmin)
3700                iFin = np.searchsorted(x,refl[5+im]+fmax)
3701                if not iBeg+iFin:       #peak below low limit - skip peak
3702                    continue
3703                elif not iBeg-iFin:     #peak above high limit - done
3704                    break
3705                elif iBeg > iFin:   #bad peak coeff - skip
3706                    badPeak = True
3707                    continue
3708                if useMP:
3709                    profArgs[iref%ncores].append((refl[5+im],refl,iBeg,iFin,1.))
3710                else:
3711                    fp = G2pwd.getPsVoigt(refl[5+im],refl[6+im]*1.e4,.001,ma.getdata(x[iBeg:iFin]))[0]
3712                    yc[iBeg:iFin] += refl[9+im]*fp
3713                    if phasePartials: ypartial[iBeg:iFin] += refl[11+im]*refl[9+im]*fp
3714           
3715        elif 'B' in calcControls[hfx+'histType']:
3716            for iref,refl in enumerate(refDict['RefList']):
3717                if im:
3718                    h,k,l,m = refl[:4]
3719                else:
3720                    h,k,l = refl[:3]
3721                Uniq = np.inner(refl[:3],SGMT)
3722                refl[5+im] = GetReflPos(refl,im,wave,A,pfx,hfx,phfx,calcControls,parmDict)         #corrected reflection position
3723#                refl[5+im] += GetHStrainShift(refl,im,SGData,phfx,hfx,calcControls,parmDict)               #apply hydrostatic strain shift
3724                Lorenz = 1./(2.*sind(refl[5+im]/2.)**2*cosd(refl[5+im]/2.))           #Lorentz correction
3725                refl[6+im:8+im] = GetReflSigGamCW(refl,im,wave,G,GB,phfx,calcControls,parmDict)    #peak sig & gam
3726                refl[12+im:14+im] = GetPinkReflAlpBet(refl,im,hfx,parmDict)
3727                refl[11+im],refl[14+im],refl[15+im],refl[16+im] = GetIntensityCorr(refl,im,Uniq,G,g,pfx,phfx,hfx,SGData,calcControls,parmDict)
3728                refl[11+im] *= Vst*Lorenz
3729                 
3730                if Phase['General'].get('doPawley'):
3731                    try:
3732                        if im:
3733                            pInd = pfx+'PWLref:%d'%(pawleyLookup[pfx+'%d,%d,%d,%d'%(h,k,l,m)])
3734                        else:
3735                            pInd = pfx+'PWLref:%d'%(pawleyLookup[pfx+'%d,%d,%d'%(h,k,l)])
3736                        refl[9+im] = parmDict[pInd]
3737                    except KeyError:
3738                        continue
3739                Wd,fmin,fmax = G2pwd.getWidthsTOF(refl[5+im],refl[12+im],refl[13+im],refl[6+im]/1.e4,refl[7+im]/100.)
3740                iBeg = np.searchsorted(x,refl[5+im]-fmin)
3741                iFin = np.searchsorted(x,refl[5+im]+fmax)
3742                if not iBeg+iFin:       #peak below low limit - skip peak
3743                    continue
3744                elif not iBeg-iFin:     #peak above high limit - done
3745                    break
3746                elif iBeg > iFin:   #bad peak coeff - skip
3747                    badPeak = True
3748                    continue
3749                if useMP:
3750                    profArgs[iref%ncores].append((refl[5+im],refl,iBeg,iFin,1.))
3751                else:
3752                    fp = G2pwd.getEpsVoigt(refl[5+im],refl[12+im],refl[13+im],refl[6+im]/1.e4,refl[7+im]/100.,ma.getdata(x[iBeg:iFin]))[0]
3753                    # if 'NB' in calcControls[hfx+'histType']:
3754                    #     yc[iBeg:iFin] += refl[11+im]*refl[9+im]*fp*.001/cw[iBeg:iFin]
3755                    # else:
3756                    #     yc[iBeg:iFin] += refl[11+im]*refl[9+im]*fp
3757                    yc[iBeg:iFin] += refl[11+im]*refl[9+im]*fp
3758                    if phasePartials: ypartial[iBeg:iFin] += refl[11+im]*refl[9+im]*fp
3759           
3760        elif 'T' in calcControls[hfx+'histType']:
3761            for iref,refl in enumerate(refDict['RefList']):
3762                if im:
3763                    h,k,l,m = refl[:4]
3764                else:
3765                    h,k,l = refl[:3]
3766                Uniq = np.inner(refl[:3],SGMT)
3767                refl[5+im] = GetReflPos(refl,im,0.0,A,pfx,hfx,phfx,calcControls,parmDict)         #corrected reflection position - #TODO - what about tabluated offset?
3768                Lorenz = sind(abs(parmDict[hfx+'2-theta'])/2)*refl[4+im]**4                                                #TOF Lorentz correction
3769#                refl[5+im] += GetHStrainShift(refl,im,SGData,phfx,hfx,calcControls,parmDict)               #apply hydrostatic strain shift
3770                refl[6+im:8+im] = GetReflSigGamTOF(refl,im,G,GB,phfx,calcControls,parmDict)    #peak sig & gam
3771                refl[12+im:14+im] = GetReflAlpBet(refl,im,hfx,parmDict)             #TODO - skip if alp, bet tabulated?
3772                refl[11+im],refl[15+im],refl[16+im],refl[17+im] = GetIntensityCorr(refl,im,Uniq,G,g,pfx,phfx,hfx,SGData,calcControls,parmDict)
3773                refl[11+im] *= Vst*Lorenz
3774                if Phase['General'].get('doPawley'):
3775                    try:
3776                        if im:
3777                            pInd =pfx+'PWLref:%d'%(pawleyLookup[pfx+'%d,%d,%d,%d'%(h,k,l,m)])
3778                        else:
3779                            pInd =pfx+'PWLref:%d'%(pawleyLookup[pfx+'%d,%d,%d'%(h,k,l)])
3780                        refl[9+im] = parmDict[pInd]
3781                    except KeyError:
3782                        continue
3783                Wd,fmin,fmax = G2pwd.getWidthsTOF(refl[5+im],refl[12+im],refl[13+im],refl[6+im],refl[7+im])
3784                iBeg = np.searchsorted(x,refl[5+im]-fmin)
3785                iFin = np.searchsorted(x,refl[5+im]+fmax)
3786                if not iBeg+iFin:       #peak below low limit - skip peak
3787                    continue
3788                elif not iBeg-iFin:     #peak above high limit - done
3789                    break
3790                elif iBeg > iFin:   #bad peak coeff - skip
3791                    badPeak = True
3792                    continue
3793                if useMP:
3794                    profArgs[iref%ncores].append((refl[5+im],refl,iBeg,iFin))
3795                else:
3796                    fp = G2pwd.getEpsVoigt(refl[5+im],refl[12+im],refl[13+im],refl[6+im],refl[7+im],ma.getdata(x[iBeg:iFin]))[0]
3797                    yc[iBeg:iFin] += refl[11+im]*refl[9+im]*fp
3798                    if phasePartials: ypartial[iBeg:iFin] += refl[11+im]*refl[9+im]*fp
3799                   
3800        if phasePartials:   #for all flavors of PWDR
3801            if Nphase > 1:
3802                SavePartial(phase,ypartial)
3803            else:
3804                SavePartial(phase,[])
3805               
3806#        print 'profile calc time: %.3fs'%(time.time()-time0)
3807        if useMP and 'C' in calcControls[hfx+'histType']:
3808            for y in MPpool.imap_unordered(G2mp.ComputePwdrProfCW,profArgs):
3809                yc += y
3810            MPpool.terminate()
3811        elif useMP and 'T' in calcControls[hfx+'histType']:
3812            for y in MPpool.imap_unordered(G2mp.ComputePwdrProfTOF,profArgs):
3813                yc += y
3814            MPpool.terminate()
3815        elif useMP and 'B' in calcControls[hfx+'histType']:
3816            for y in MPpool.imap_unordered(G2mp.ComputePwdrProfPink,profArgs):
3817                yc += y
3818            MPpool.terminate()
3819        elif useMP and 'E' in calcControls[hfx+'histType']:
3820            for y in MPpool.imap_unordered(G2mp.ComputePwdrProfED,profArgs):
3821                yc += y
3822            MPpool.terminate()
3823    if badPeak:
3824        print ('ouch #7 bad profile coefficients yield negative peak width; some reflections skipped')
3825    if GSASIIpath.GetConfigValue('Show_timing',False):
3826        print ('getPowderProfile t=%.3f'%(time.time()-starttime))
3827    return yc,yb
3828   
3829def getPowderProfileDerv(args):
3830    '''Computes the derivatives of the computed powder pattern with respect to all
3831    refined parameters.
3832    Used for single processor & Multiprocessor versions
3833    '''
3834    import pytexture as ptx
3835    ptx.pyqlmninit()            #initialize fortran arrays for spherical harmonics for each processor
3836    parmDict,x,varylist,Histogram,Phases,rigidbodyDict,calcControls,pawleyLookup,dependentVars = args[:9]
3837    prc,tprc,histogram = 0,1,None
3838    if len(args) >= 10: prc=args[9]
3839    if len(args) >= 11: tprc=args[10]
3840    if len(args) >= 12: histogram=args[11]
3841   
3842    def cellVaryDerv(pfx,SGData,dpdA): 
3843        if SGData['SGLaue'] in ['-1',]:
3844            return [[pfx+'A0',dpdA[0]],[pfx+'A1',dpdA[1]],[pfx+'A2',dpdA[2]],
3845                [pfx+'A3',dpdA[3]],[pfx+'A4',dpdA[4]],[pfx+'A5',dpdA[5]]]
3846        elif SGData['SGLaue'] in ['2/m',]:
3847            if SGData['SGUniq'] == 'a':
3848                return [[pfx+'A0',dpdA[0]],[pfx+'A1',dpdA[1]],[pfx+'A2',dpdA[2]],[pfx+'A5',dpdA[5]]]
3849            elif SGData['SGUniq'] == 'b':
3850                return [[pfx+'A0',dpdA[0]],[pfx+'A1',dpdA[1]],[pfx+'A2',dpdA[2]],[pfx+'A4',dpdA[4]]]
3851            else:
3852                return [[pfx+'A0',dpdA[0]],[pfx+'A1',dpdA[1]],[pfx+'A2',dpdA[2]],[pfx+'A3',dpdA[3]]]
3853        elif SGData['SGLaue'] in ['mmm',]:
3854            return [[pfx+'A0',dpdA[0]],[pfx+'A1',dpdA[1]],[pfx+'A2',dpdA[2]]]
3855        elif SGData['SGLaue'] in ['4/m','4/mmm']:
3856            return [[pfx+'A0',dpdA[0]],[pfx+'A2',dpdA[2]]]
3857        elif SGData['SGLaue'] in ['6/m','6/mmm','3m1', '31m', '3']:
3858            return [[pfx+'A0',dpdA[0]],[pfx+'A2',dpdA[2]]]
3859        elif SGData['SGLaue'] in ['3R', '3mR']:
3860            return [[pfx+'A0',dpdA[0]+dpdA[1]+dpdA[2]],[pfx+'A3',dpdA[3]+dpdA[4]+dpdA[5]]]                       
3861        elif SGData['SGLaue'] in ['m3m','m3']:
3862            return [[pfx+'A0',dpdA[0]]]
3863           
3864    # create a list of dependent variables and set up a dictionary to hold their derivatives
3865#    dependentVars = G2mv.GetDependentVars()
3866    depDerivDict = {}
3867    for j in dependentVars:
3868        depDerivDict[j] = np.zeros(shape=(len(x)))
3869#    print ('dependent vars',dependentVars)
3870    hId = Histogram['hId']
3871    hfx = ':%d:'%(hId)
3872    bakType = calcControls[hfx+'bakType']
3873    dMdv = np.zeros(shape=(len(varylist),len(x)))
3874    fixback = Histogram['Background'][1].get('fixback',None)
3875    dMdb,dMddb,dMdpk,dMdfb = G2pwd.getBackgroundDerv(hfx,parmDict,bakType,calcControls[hfx+'histType'],x,fixback)
3876    if prc == 0 and hfx+'Back;0' in varylist: # for now assume that Back;x vars do not appear in constraints
3877        bBpos = varylist.index(hfx+'Back;0')
3878        dMdv[bBpos:bBpos+len(dMdb)] += dMdb     #TODO crash if bck parms tossed
3879    names = [hfx+'DebyeA',hfx+'DebyeR',hfx+'DebyeU']
3880    for name in varylist:
3881        if prc == 0 and 'Debye' in name:
3882            Id = int(name.split(';')[-1])
3883            parm = name[:int(name.rindex(';'))]
3884            if parm in names:       #skips if bkg fxn not in current histogram
3885                ip = names.index(parm)
3886                dMdv[varylist.index(name)] += dMddb[3*Id+ip]
3887    names = [hfx+'BkPkpos',hfx+'BkPkint',hfx+'BkPksig',hfx+'BkPkgam']
3888    for name in varylist:
3889        if prc == 0 and 'BkPk' in name:
3890            parm,Id = name.split(';')
3891            Id = int(Id)
3892            if parm in names:       #skips if bkg fxn not in current histogram
3893                ip = names.index(parm)
3894                dMdv[varylist.index(name)] += dMdpk[4*Id+ip]
3895    if hfx+'BF mult' in varylist:
3896        dMdv[varylist.index(hfx+'BF mult')] += dMdfb
3897    cw = np.diff(ma.getdata(x))
3898    cw = np.append(cw,cw[-1])
3899    Ka2 = False #also for TOF!
3900    if 'C' in calcControls[hfx+'histType']:   
3901        shl = max(parmDict[hfx+'SH/L'],0.002)
3902        if hfx+'Lam1' in (parmDict.keys()):
3903            wave = parmDict[hfx+'Lam1']
3904            Ka2 = True
3905            lamRatio = 360*(parmDict[hfx+'Lam2']-parmDict[hfx+'Lam1'])/(np.pi*parmDict[hfx+'Lam1'])
3906            kRatio = parmDict[hfx+'I(L2)/I(L1)']
3907        else:
3908            wave = parmDict[hfx+'Lam']
3909    elif 'B' in calcControls[hfx+'histType']:
3910        wave = parmDict[hfx+'Lam']
3911    for phase in Histogram['Reflection Lists']:
3912        refDict = Histogram['Reflection Lists'][phase]
3913        if phase not in Phases:     #skips deleted or renamed phases silently!
3914            continue
3915        Phase = Phases[phase]
3916        if histogram and histogram not in Phase['Histograms']:
3917            continue
3918        SGData = Phase['General']['SGData']
3919        SGMT = np.array([ops[0].T for ops in SGData['SGOps']])
3920        im = 0
3921        if Phase['General'].get('Modulated',False):
3922            SSGData = Phase['General']['SSGData']
3923            im = 1  #offset in SS reflection list
3924            #??
3925        pId = Phase['pId']
3926        pfx = '%d::'%(pId)
3927        phfx = '%d:%d:'%(pId,hId)
3928        Dij = GetDij(phfx,SGData,parmDict)
3929        A = [parmDict[pfx+'A%d'%(i)]+Dij[i] for i in range(6)]
3930        G,g = G2lat.A2Gmat(A)       #recip & real metric tensors
3931        GA,GB = G2lat.Gmat2AB(G)    #Orthogonalization matricies
3932        if not Phase['General'].get('doPawley') and not parmDict.get(phfx+'LeBail') and 'E' not in calcControls[hfx+'histType']:
3933            if im:
3934                dFdvDict = SStructureFactorDerv(refDict,im,G,hfx,pfx,SGData,SSGData,calcControls,parmDict)
3935                dFdvDict.update(SStructureFactorDerv2(refDict,im,G,hfx,pfx,SGData,SSGData,calcControls,parmDict))
3936            else:
3937                if Phase['General']['Type'] == 'magnetic': 
3938                    dFdvDict = MagStructureFactorDerv(refDict,G,hfx,pfx,SGData,calcControls,parmDict)
3939                    dFdvDict.update(MagStructureFactorDerv2(refDict,G,hfx,pfx,SGData,calcControls,parmDict))
3940                else:
3941                    dFdvDict = StructureFactorDerv2(refDict,G,hfx,pfx,SGData,calcControls,parmDict)
3942            ApplyRBModelDervs(dFdvDict,parmDict,rigidbodyDict,Phase)
3943        # determine the parameters that will have derivatives computed only at end
3944        nonatomvarylist = []
3945        for name in varylist:
3946            if '::RBV;' not in name and '::RBS;' not in name:
3947                try:
3948                    aname = name.split(pfx)[1][:2]
3949                    if aname not in ['Af','dA','AU','RB','AM','Xs','Xc','Ys','Yc','Zs','Zc',    \
3950                        'Tm','Xm','Ym','Zm','U1','U2','U3','MX','MY','MZ']: continue # skip anything not an atom or rigid body param
3951                except IndexError:
3952                    continue
3953            nonatomvarylist.append(name)
3954        nonatomdependentVars = []
3955        for name in dependentVars:
3956            if '::RBV;' not in name and '::RBS;' not in name:
3957                try:
3958                    aname = name.split(pfx)[1][:2]
3959                    if aname not in ['Af','dA','AU','RB','AM','Xs','Xc','Ys','Yc','Zs','Zc',    \
3960                        'Tm','Xm','Ym','Zm','U1','U2','U3','MX','MY','MZ']: continue # skip anything not an atom or rigid body param
3961                except IndexError:
3962                    continue
3963            nonatomdependentVars.append(name)
3964        #==========================================================================================
3965        #==========================================================================================
3966        for iref in range(prc,len(refDict['RefList']),tprc):
3967            refl = refDict['RefList'][iref]
3968            if im:
3969                h,k,l,m = refl[:4]
3970            else:
3971                h,k,l = refl[:3]
3972            Uniq = np.inner(refl[:3],SGMT)
3973            if 'T' in calcControls[hfx+'histType']:
3974                wave = refl[14+im]
3975            if 'E' in calcControls[hfx+'histType']:
3976                dIdsh,dIdsp,dIdpola,dIdPO,dFdODF,dFdSA,dFdAb,dFdEx = [[],[],[],[],[],[],[],[]]
3977            else:
3978                dIdsh,dIdsp,dIdpola,dIdPO,dFdODF,dFdSA,dFdAb,dFdEx = GetIntensityDerv(refl,im,wave,Uniq,G,g,pfx,phfx,hfx,SGData,calcControls,parmDict)
3979            if 'C' in calcControls[hfx+'histType']:        #CW powder
3980                Wd,fmin,fmax = G2pwd.getWidthsCW(refl[5+im],refl[6+im],refl[7+im],shl)
3981            elif 'T' in calcControls[hfx+'histType']:
3982                Wd,fmin,fmax = G2pwd.getWidthsTOF(refl[5+im],refl[12+im],refl[13+im],refl[6+im],refl[7+im])
3983            elif 'B' in calcControls[hfx+'histType']:
3984                Wd,fmin,fmax = G2pwd.getWidthsTOF(refl[5+im],refl[12+im],refl[13+im],refl[6+im]/1.e4,refl[7+im]/100.)
3985            elif 'E' in calcControls[hfx+'histType']:
3986                Wd,fmin,fmax = G2pwd.getWidthsED(refl[5+im],refl[6+im])
3987            iBeg = np.searchsorted(x,refl[5+im]-fmin)
3988            iFin = np.searchsorted(x,refl[5+im]+fmax)
3989            if not iBeg+iFin:       #peak below low limit - skip peak
3990                continue
3991            elif not iBeg-iFin:     #peak above high limit - done
3992                break
3993            pos = refl[5+im]
3994            if 'C' in calcControls[hfx+'histType']:
3995                tanth = tand(pos/2.0)
3996                costh = cosd(pos/2.0)
3997                lenBF = iFin-iBeg
3998                dMdpk = np.zeros(shape=(6,lenBF))
3999                dMdipk = G2pwd.getdFCJVoigt3(refl[5+im],refl[6+im],refl[7+im],shl,ma.getdata(x[iBeg:iFin]))
4000                for i in range(5):
4001                    dMdpk[i] += refl[11+im]*refl[9+im]*dMdipk[i]
4002                dervDict = {'int':dMdpk[0],'pos':dMdpk[1],'sig':dMdpk[2],'gam':dMdpk[3],'shl':dMdpk[4],'L1/L2':np.zeros_like(dMdpk[0])}
4003                if Ka2:
4004                    pos2 = refl[5+im]+lamRatio*tanth       # + 360/pi * Dlam/lam * tan(th)
4005                    iBeg2 = np.searchsorted(x,pos2-fmin)
4006                    iFin2 = np.searchsorted(x,pos2+fmax)
4007                    if iBeg2-iFin2:
4008                        lenBF2 = iFin2-iBeg2
4009                        dMdpk2 = np.zeros(shape=(6,lenBF2))
4010                        dMdipk2 = G2pwd.getdFCJVoigt3(pos2,refl[6+im],refl[7+im],shl,ma.getdata(x[iBeg2:iFin2]))
4011                        for i in range(5):
4012                            dMdpk2[i] = refl[11+im]*refl[9+im]*kRatio*dMdipk2[i]
4013                        dMdpk2[5] = refl[11+im]*dMdipk2[0]
4014                        dervDict2 = {'int':dMdpk2[0],'pos':dMdpk2[1],'sig':dMdpk2[2],'gam':dMdpk2[3],'shl':dMdpk2[4],'L1/L2':dMdpk2[5]*refl[9]}
4015            elif 'T' in calcControls[hfx+'histType']:
4016                lenBF = iFin-iBeg
4017                if lenBF < 0:   #bad peak coeff
4018                    break
4019                dMdpk = np.zeros(shape=(6,lenBF))
4020                dMdipk = G2pwd.getdEpsVoigt(refl[5+im],refl[12+im],refl[13+im],refl[6+im],refl[7+im],ma.getdata(x[iBeg:iFin]))
4021                for i in range(6):
4022                    dMdpk[i] += refl[11+im]*refl[9+im]*dMdipk[i]
4023                dervDict = {'int':dMdpk[0],'pos':dMdpk[1],'alp':dMdpk[2],'bet':dMdpk[3],'sig':dMdpk[4],'gam':dMdpk[5]}           
4024            elif 'B' in calcControls[hfx+'histType']:
4025                tanth = tand(pos/2.0)
4026                costh = cosd(pos/2.0)
4027                lenBF = iFin-iBeg
4028                if lenBF < 0:   #bad peak coeff
4029                    break
4030                dMdpk = np.zeros(shape=(6,lenBF))
4031                dMdipk = G2pwd.getdEpsVoigt(refl[5+im],refl[12+im],refl[13+im],refl[6+im]/1.e4,refl[7+im]/100.,ma.getdata(x[iBeg:iFin]))
4032                for i in range(6):
4033                    dMdpk[i] = refl[11+im]*refl[9+im]*dMdipk[i]
4034                dervDict = {'int':dMdpk[0],'pos':dMdpk[1],'alp':dMdpk[2],'bet':dMdpk[3],'sig':dMdpk[4]/1.e4,'gam':dMdpk[5]/100.}   
4035            elif 'E' in calcControls[hfx+'histType']:
4036                lenBF = iFin-iBeg
4037                if lenBF < 0:   #bad peak coeff
4038                    break
4039                dMdpk = np.zeros(shape=(4,lenBF))
4040                dMdipk = G2pwd.getdPsVoigt(refl[5+im],refl[6+im]*10**4,0.001,ma.getdata(x[iBeg:iFin]))
4041                for i in range(4):
4042                    dMdpk[i] = refl[9+im]*dMdipk[i]
4043                dervDict = {'int':dMdpk[0],'pos':-dMdpk[1],'sig':dMdpk[2]*1.e4}   
4044            if Phase['General'].get('doPawley'):
4045                dMdpw = np.zeros(len(x))
4046                try:
4047                    if im:
4048                        pIdx = pfx+'PWLref:'+str(pawleyLookup[pfx+'%d,%d,%d,%d'%(h,k,l,m)])
4049                    else:
4050                        pIdx = pfx+'PWLref:'+str(pawleyLookup[pfx+'%d,%d,%d'%(h,k,l)])
4051                    idx = varylist.index(pIdx)
4052                    dMdpw[iBeg:iFin] = dervDict['int']/refl[9+im]
4053                    if Ka2: #not for TOF either
4054                        dMdpw[iBeg2:iFin2] += dervDict2['int']/refl[9+im]
4055                    dMdv[idx] = dMdpw
4056                except: # ValueError:
4057                    pass
4058            if 'C' in calcControls[hfx+'histType']:
4059                dpdA,dpdw,dpdZ,dpdSh,dpdTr,dpdX,dpdY,dpdV = GetReflPosDerv(refl,im,wave,A,pfx,hfx,phfx,calcControls,parmDict)
4060                names = {hfx+'Scale':[dIdsh,'int'],hfx+'Polariz.':[dIdpola,'int'],phfx+'Scale':[dIdsp,'int'],
4061                    hfx+'U':[tanth**2,'sig'],hfx+'V':[tanth,'sig'],hfx+'W':[1.0,'sig'],
4062                    hfx+'X':[1.0/costh,'gam'],hfx+'Y':[tanth,'gam'],hfx+'Z':[1.0,'gam'],hfx+'SH/L':[1.0,'shl'],
4063                    hfx+'I(L2)/I(L1)':[1.0,'L1/L2'],hfx+'Zero':[dpdZ,'pos'],hfx+'Lam':[dpdw,'pos'],
4064                    hfx+'Shift':[dpdSh,'pos'],hfx+'Transparency':[dpdTr,'pos'],hfx+'DisplaceX':[dpdX,'pos'],
4065                    hfx+'DisplaceY':[dpdY,'pos'],phfx+'Extinction':[dFdEx,'int'],phfx+'LayerDisp':[dpdY,'pos']}
4066                if 'Bragg' in calcControls[hfx+'instType']:
4067                    names.update({hfx+'SurfRoughA':[dFdAb[0],'int'],
4068                        hfx+'SurfRoughB':[dFdAb[1],'int'],})
4069                else:
4070                    names.update({hfx+'Absorption':[dFdAb,'int'],})
4071            elif 'T' in calcControls[hfx+'histType']:   #'T'OF
4072                dpdA,dpdZ,dpdDC,dpdDA,dpdDB,dpdV = GetReflPosDerv(refl,im,0.0,A,pfx,hfx,phfx,calcControls,parmDict)
4073                names = {hfx+'Scale':[dIdsh,'int'],phfx+'Scale':[dIdsp,'int'],
4074                    hfx+'difC':[dpdDC,'pos'],hfx+'difA':[dpdDA,'pos'],hfx+'difB':[dpdDB,'pos'],
4075                    hfx+'Zero':[dpdZ,'pos'],hfx+'X':[refl[4+im],'gam'],hfx+'Y':[refl[4+im]**2,'gam'],hfx+'Z':[1.0,'gam'],
4076                    hfx+'alpha':[1./refl[4+im],'alp'],hfx+'beta-0':[1.0,'bet'],hfx+'beta-1':[1./refl[4+im]**4,'bet'],
4077                    hfx+'beta-q':[1./refl[4+im]**2,'bet'],hfx+'sig-0':[1.0,'sig'],hfx+'sig-1':[refl[4+im]**2,'sig'],
4078                    hfx+'sig-2':[refl[4+im]**4,'sig'],hfx+'sig-q':[refl[4+im],'sig'],
4079                    hfx+'Absorption':[dFdAb,'int'],phfx+'Extinction':[dFdEx,'int'],}
4080            elif 'B' in calcControls[hfx+'histType']:
4081                dpdA,dpdw,dpdZ,dpdSh,dpdTr,dpdX,dpdY,dpdV = GetReflPosDerv(refl,im,wave,A,pfx,hfx,phfx,calcControls,parmDict)
4082                names = {hfx+'Scale':[dIdsh,'int'],phfx+'Scale':[dIdsp,'int'],hfx+'Lam':[dpdw,'pos'],
4083                    hfx+'Zero':[dpdZ,'pos'],hfx+'X':[1.0/costh,'gam'],hfx+'Y':[tanth,'gam'],hfx+'Z':[1.0,'gam'],
4084                    hfx+'U':[tanth**2,'sig'],hfx+'V':[tanth,'sig'],hfx+'W':[1.0,'sig'],hfx+'Polariz.':[dIdpola,'int'],
4085                    hfx+'alpha-0':[1.0,'alp'],hfx+'alpha-1':[tanth,'alp'],hfx+'beta-0':[1.0,'bet'],hfx+'beta-1':[tanth,'bet'],
4086                    hfx+'Absorption':[dFdAb,'int'],phfx+'Extinction':[dFdEx,'int'],hfx+'DisplaceX':[dpdX,'pos'],hfx+'DisplaceY':[dpdY,'pos']}
4087            elif 'E' in calcControls[hfx+'histType']:
4088                dpdA,dpdTTh,dpdXE,dpdYE,dpdZE = GetReflPosDerv(refl,im,0.0,A,pfx,hfx,phfx,calcControls,parmDict)
4089                names = {hfx+'Scale':[dIdsh,'int'],hfx+'2-theta':[dpdTTh,'pos'],
4090                    hfx+'A':[refl[5+im]**2,'sig'],hfx+'B':[refl[5+im],'sig'],hfx+'C':[1.0,'sig'],
4091                    hfx+'XE':[dpdXE,'pos'],hfx+'YE':[dpdYE,'pos'],hfx+'ZE':[dpdZE,'pos']   }
4092            for name in names:
4093                item = names[name]
4094                if name in varylist:
4095                    dMdv[varylist.index(name)][iBeg:iFin] += item[0]*dervDict[item[1]]
4096                    if Ka2 and iFin2-iBeg2:
4097                        dMdv[varylist.index(name)][iBeg2:iFin2] += item[0]*dervDict2[item[1]]
4098                elif name in dependentVars:
4099                    depDerivDict[name][iBeg:iFin] += item[0]*dervDict[item[1]]
4100                    if Ka2 and iFin2-iBeg2:
4101                        depDerivDict[name][iBeg2:iFin2] += item[0]*dervDict2[item[1]]
4102            for iPO in dIdPO:
4103                if iPO in varylist:
4104                    dMdv[varylist.index(iPO)][iBeg:iFin] += dIdPO[iPO]*dervDict['int']
4105                    if Ka2 and iFin2-iBeg2:
4106                        dMdv[varylist.index(iPO)][iBeg2:iFin2] += dIdPO[iPO]*dervDict2['int']
4107                elif iPO in dependentVars:
4108                    depDerivDict[iPO][iBeg:iFin] += dIdPO[iPO]*dervDict['int']
4109                    if Ka2 and iFin2-iBeg2:
4110                        depDerivDict[iPO][iBeg2:iFin2] += dIdPO[iPO]*dervDict2['int']
4111            for i,name in enumerate(['omega','chi','phi']):
4112                aname = pfx+'SH '+name
4113                if aname in varylist:
4114                    dMdv[varylist.index(aname)][iBeg:iFin] += dFdSA[i]*dervDict['int']
4115                    if Ka2 and iFin2-iBeg2:
4116                        dMdv[varylist.index(aname)][iBeg2:iFin2] += dFdSA[i]*dervDict2['int']
4117                elif aname in dependentVars:
4118                    depDerivDict[aname][iBeg:iFin] += dFdSA[i]*dervDict['int']
4119                    if Ka2 and iFin2-iBeg2:
4120                        depDerivDict[aname][iBeg2:iFin2] += dFdSA[i]*dervDict2['int']
4121            for iSH in dFdODF:
4122                if iSH in varylist:
4123                    dMdv[varylist.index(iSH)][iBeg:iFin] += dFdODF[iSH]*dervDict['int']
4124                    if Ka2 and iFin2-iBeg2:
4125                        dMdv[varylist.index(iSH)][iBeg2:iFin2] += dFdODF[iSH]*dervDict2['int']
4126                elif iSH in dependentVars:
4127                    depDerivDict[iSH][iBeg:iFin] += dFdODF[iSH]*dervDict['int']
4128                    if Ka2 and iFin2-iBeg2:
4129                        depDerivDict[iSH][iBeg2:iFin2] += dFdODF[iSH]*dervDict2['int']
4130            cellDervNames = cellVaryDerv(pfx,SGData,dpdA)
4131            for name,dpdA in cellDervNames:
4132                if name in varylist:
4133                    dMdv[varylist.index(name)][iBeg:iFin] += dpdA*dervDict['pos']
4134                    if Ka2 and iFin2-iBeg2:
4135                        dMdv[varylist.index(name)][iBeg2:iFin2] += dpdA*dervDict2['pos']
4136                elif name in dependentVars: #need to scale for mixed phase constraints?
4137                    depDerivDict[name][iBeg:iFin] += dpdA*dervDict['pos']
4138                    if Ka2 and iFin2-iBeg2:
4139                        depDerivDict[name][iBeg2:iFin2] += dpdA*dervDict2['pos']
4140            dDijDict = GetHStrainShiftDerv(refl,im,SGData,phfx,hfx,calcControls,parmDict)
4141            for name in dDijDict:
4142                if name in varylist:
4143                    dMdv[varylist.index(name)][iBeg:iFin] += dDijDict[name]*dervDict['pos']
4144                    if Ka2 and iFin2-iBeg2:
4145                        dMdv[varylist.index(name)][iBeg2:iFin2] += dDijDict[name]*dervDict2['pos']
4146                elif name in dependentVars:
4147                    depDerivDict[name][iBeg:iFin] += dDijDict[name]*dervDict['pos']
4148                    if Ka2 and iFin2-iBeg2:
4149                        depDerivDict[name][iBeg2:iFin2] += dDijDict[name]*dervDict2['pos']
4150#TODO: need Layer Disp deriv here
4151            for i,name in enumerate([pfx+'mV0',pfx+'mV1',pfx+'mV2']):
4152                if name in varylist:
4153                    dMdv[varylist.index(name)][iBeg:iFin] += dpdV[i]*dervDict['pos']
4154                    if Ka2 and iFin2-iBeg2:
4155                        dMdv[varylist.index(name)][iBeg2:iFin2] += dpdV[i]*dervDict2['pos']
4156                elif name in dependentVars:
4157                    depDerivDict[name][iBeg:iFin] += dpdV[i]*dervDict['pos']
4158                    if Ka2 and iFin2-iBeg2:
4159                        depDerivDict[name][iBeg2:iFin2] += dpdV[i]*dervDict2['pos']
4160            if 'C' in calcControls[hfx+'histType'] or 'B' in calcControls[hfx+'histType']:
4161                sigDict,gamDict = GetSampleSigGamDerv(refl,im,wave,G,GB,SGData,hfx,phfx,calcControls,parmDict)
4162            elif 'T' in calcControls[hfx+'histType']:   #'T'OF
4163                sigDict,gamDict = GetSampleSigGamDerv(refl,im,0.0,G,GB,SGData,hfx,phfx,calcControls,parmDict)
4164            else: #'E'
4165                sigDict = {}
4166                gamDict = {}
4167            for name in gamDict:
4168                if name in varylist:
4169                    dMdv[varylist.index(name)][iBeg:iFin] += gamDict[name]*dervDict['gam']
4170                    if Ka2 and iFin2-iBeg2:
4171                        dMdv[varylist.index(name)][iBeg2:iFin2] += gamDict[name]*dervDict2['gam']
4172                elif name in dependentVars:
4173                    depDerivDict[name][iBeg:iFin] += gamDict[name]*dervDict['gam']
4174                    if Ka2 and iFin2-iBeg2:
4175                        depDerivDict[name][iBeg2:iFin2] += gamDict[name]*dervDict2['gam']
4176            for name in sigDict:
4177                if name in varylist:
4178                    dMdv[varylist.index(name)][iBeg:iFin] += sigDict[name]*dervDict['sig']
4179                    if Ka2 and iFin2-iBeg2:
4180                        dMdv[varylist.index(name)][iBeg2:iFin2] += sigDict[name]*dervDict2['sig']
4181                elif name in dependentVars:
4182                    depDerivDict[name][iBeg:iFin] += sigDict[name]*dervDict['sig']
4183                    if Ka2 and iFin2-iBeg2:
4184                        depDerivDict[name][iBeg2:iFin2] += sigDict[name]*dervDict2['sig']
4185            for name in ['BabA','BabU']:
4186                if refl[9+im]:
4187                    if phfx+name in varylist:
4188                        dMdv[varylist.index(phfx+name)][iBeg:iFin] += parmDict[phfx+'Scale']*dFdvDict[phfx+name][iref]*dervDict['int']/refl[9+im]
4189                        if Ka2 and iFin2-iBeg2:
4190                            dMdv[varylist.index(phfx+name)][iBeg2:iFin2] += parmDict[phfx+'Scale']*dFdvDict[phfx+name][iref]*dervDict2['int']/refl[9+im]
4191                    elif phfx+name in dependentVars:                   
4192                        depDerivDict[phfx+name][iBeg:iFin] += parmDict[phfx+'Scale']*dFdvDict[phfx+name][iref]*dervDict['int']/refl[9+im]
4193                        if Ka2 and iFin2-iBeg2:
4194                            depDerivDict[phfx+name][iBeg2:iFin2] += parmDict[phfx+'Scale']*dFdvDict[phfx+name][iref]*dervDict2['int']/refl[9+im]                 
4195            if not Phase['General'].get('doPawley') and not parmDict.get(phfx+'LeBail') and 'E' not in calcControls[hfx+'histType']:
4196                #do atom derivatives -  for RB,F,X & U so far - how do I scale mixed phase constraints?
4197                corr = 0.
4198                corr2 = 0.
4199                if refl[9+im]:             
4200                    corr = dervDict['int']/refl[9+im]
4201                    if Ka2 and iFin2-iBeg2:
4202                        corr2 = dervDict2['int']/refl[9+im]
4203                for name in nonatomvarylist:
4204                    dMdv[varylist.index(name)][iBeg:iFin] += dFdvDict[name][iref]*corr
4205                    if Ka2 and iFin2-iBeg2:
4206                       dMdv[varylist.index(name)][iBeg2:iFin2] += dFdvDict[name][iref]*corr2
4207                for name in nonatomdependentVars:
4208                   depDerivDict[name][iBeg:iFin] += dFdvDict[name][iref]*corr
4209                   if Ka2 and iFin2-iBeg2:
4210                       depDerivDict[name][iBeg2:iFin2] += dFdvDict[name][iref]*corr2
4211    # now process derivatives in constraints
4212    dMdv[:,ma.getmaskarray(x)] = 0.  # instead of masking, zero out masked values
4213    #G2mv.Dict2Deriv(varylist,depDerivDict,dMdv)
4214    return dMdv,depDerivDict
4215   
4216def UserRejectHKL(ref,im,userReject):
4217    if ref[5+im]/ref[6+im] < userReject['minF/sig']:
4218        return False
4219    elif userReject['MaxD'] < ref[4+im] > userReject['MinD']:
4220        return False
4221    elif ref[11+im] < userReject['MinExt']:
4222        return False
4223    elif abs(ref[5+im]-ref[7+im])/ref[6+im] > userReject['MaxDF/F']:
4224        return False
4225    return True
4226   
4227def dervHKLF(Histogram,Phase,calcControls,varylist,parmDict,rigidbodyDict):
4228    '''Loop over reflections in a HKLF histogram and compute derivatives of the fitting
4229    model (M) with respect to all parameters.  Independent and dependant dM/dp arrays
4230    are returned to either dervRefine or HessRefine.
4231
4232    :returns:
4233    '''
4234    hId = Histogram['hId']
4235    hfx = ':%d:'%(hId)
4236    pfx = '%d::'%(Phase['pId'])
4237    phfx = '%d:%d:'%(Phase['pId'],hId)
4238    SGData = Phase['General']['SGData']
4239    im = 0
4240    if Phase['General'].get('Modulated',False):
4241        SSGData = Phase['General']['SSGData']
4242        im = 1  #offset in SS reflection list
4243    A = [parmDict[pfx+'A%d'%(i)] for i in range(6)]
4244    G,g = G2lat.A2Gmat(A)       #recip & real metric tensors
4245    TwinLaw = calcControls[phfx+'TwinLaw']
4246    refDict = Histogram['Data']
4247    if parmDict[phfx+'Scale'] < 0.:
4248        parmDict[phfx+'Scale'] = .001
4249    if im: # split to nontwin/twin versions
4250        if len(TwinLaw) > 1:
4251            dFdvDict = SStructureFactorDervTw(refDict,im,G,hfx,pfx,SGData,SSGData,calcControls,parmDict)    #not ok
4252        else:
4253            dFdvDict = SStructureFactorDerv(refDict,im,G,hfx,pfx,SGData,SSGData,calcControls,parmDict)  #OK
4254            dFdvDict.update(SStructureFactorDerv2(refDict,im,G,hfx,pfx,SGData,SSGData,calcControls,parmDict))
4255    else:
4256        if len(TwinLaw) > 1:
4257            dFdvDict = StructureFactorDervTw2(refDict,G,hfx,pfx,SGData,calcControls,parmDict)
4258        else:   #correct!!
4259            if Phase['General']['Type'] == 'magnetic': 
4260                dFdvDict = MagStructureFactorDerv(refDict,G,hfx,pfx,SGData,calcControls,parmDict)
4261                dFdvDict.update(MagStructureFactorDerv2(refDict,G,hfx,pfx,SGData,calcControls,parmDict))
4262            else:
4263                dFdvDict = StructureFactorDerv2(refDict,G,hfx,pfx,SGData,calcControls,parmDict)
4264    ApplyRBModelDervs(dFdvDict,parmDict,rigidbodyDict,Phase)
4265    dMdvh = np.zeros((len(varylist),len(refDict['RefList'])))
4266    dependentVars = G2mv.GetDependentVars()
4267    depDerivDict = {}
4268    for j in dependentVars:
4269        depDerivDict[j] = np.zeros(shape=(len(refDict['RefList'])))
4270    wdf = np.zeros(len(refDict['RefList']))
4271    if calcControls['F**2']:
4272        for iref,ref in enumerate(refDict['RefList']):
4273            if ref[6+im] > 0:
4274                dervDict,dervCor = SCExtinction(ref,im,phfx,hfx,pfx,calcControls,parmDict,varylist+dependentVars)[1:]
4275                w = 1.0/ref[6+im]
4276                if ref[3+im] > 0:
4277                    wdf[iref] = w*(ref[5+im]-ref[7+im])
4278                    for j,var in enumerate(varylist):
4279                        if var in dFdvDict:
4280                            dMdvh[j][iref] = w*dFdvDict[var][iref]*parmDict[phfx+'Scale']*ref[11+im]
4281                    for var in dependentVars:
4282                        if var in dFdvDict:
4283                            depDerivDict[var][iref] = w*dFdvDict[var][iref]*parmDict[phfx+'Scale']*ref[11+im]
4284                    if phfx+'Scale' in varylist:
4285                        dMdvh[varylist.index(phfx+'Scale')][iref] = w*ref[7+im]*ref[11+im]/parmDict[phfx+'Scale']  #OK
4286                    elif phfx+'Scale' in dependentVars:
4287                        depDerivDict[phfx+'Scale'][iref] = w*ref[7+im]*ref[11+im]/parmDict[phfx+'Scale']   #OK
4288                    for item in ['Ep','Es','Eg']:
4289                        if phfx+item in varylist and phfx+item in dervDict:
4290                            dMdvh[varylist.index(phfx+item)][iref] = w*dervDict[phfx+item]/ref[11+im]  #OK
4291                        elif phfx+item in dependentVars and phfx+item in dervDict:
4292                            depDerivDict[phfx+item][iref] = w*dervDict[phfx+item]/ref[11+im]  #OK
4293                    for item in ['BabA','BabU']:
4294                        if phfx+item in varylist:
4295                            dMdvh[varylist.index(phfx+item)][iref] = w*dFdvDict[phfx+item][iref]*parmDict[phfx+'Scale']*ref[11+im]
4296                        elif phfx+item in dependentVars:
4297                            depDerivDict[phfx+item][iref] = w*dFdvDict[phfx+item][iref]*parmDict[phfx+'Scale']*ref[11+im]
4298    else:   #F refinement
4299        for iref,ref in enumerate(refDict['RefList']):
4300            if ref[5+im] > 0.:
4301                dervDict,dervCor = SCExtinction(ref,im,phfx,hfx,pfx,calcControls,parmDict,varylist+dependentVars)[1:]
4302                Fo = np.sqrt(ref[5+im])
4303                Fc = np.sqrt(ref[7+im])
4304                w = 1.0/ref[6+im]
4305                if ref[3+im] > 0:
4306                    wdf[iref] = 2.0*Fc*w*(Fo-Fc)
4307                    for j,var in enumerate(varylist):
4308                        if var in dFdvDict:
4309                            dMdvh[j][iref] = w*dFdvDict[var][iref]*parmDict[phfx+'Scale']*ref[11+im]
4310                    for var in dependentVars:
4311                        if var in dFdvDict:
4312                            depDerivDict[var][iref] = w*dFdvDict[var][iref]*parmDict[phfx+'Scale']*ref[11+im]
4313                    if phfx+'Scale' in varylist:
4314                        dMdvh[varylist.index(phfx+'Scale')][iref] = w*ref[7+im]*ref[11+im]/parmDict[phfx+'Scale']  #OK
4315                    elif phfx+'Scale' in dependentVars:
4316                        depDerivDict[phfx+'Scale'][iref] = w*ref[7+im]*ref[11+im]/parmDict[phfx+'Scale']   #OK                   
4317                    for item in ['Ep','Es','Eg']:   #OK!
4318                        if phfx+item in varylist and phfx+item in dervDict:
4319                            dMdvh[varylist.index(phfx+item)][iref] = w*dervDict[phfx+item]/ref[11+im] 
4320                        elif phfx+item in dependentVars and phfx+item in dervDict:
4321                            depDerivDict[phfx+item][iref] = w*dervDict[phfx+item]/ref[11+im]
4322                    for item in ['BabA','BabU']:
4323                        if phfx+item in varylist:
4324                            dMdvh[varylist.index(phfx+item)][iref] = w*dFdvDict[phfx+item][iref]*parmDict[phfx+'Scale']*ref[11+im]
4325                        elif phfx+item in dependentVars:
4326                            depDerivDict[phfx+item][iref] = w*dFdvDict[phfx+item][iref]*parmDict[phfx+'Scale']*ref[11+im]
4327    return dMdvh,depDerivDict,wdf
4328   
4329
4330def dervRefine(values,HistoPhases,parmDict,varylist,calcControls,pawleyLookup,dlg):
4331    '''Loop over histograms and compute derivatives of the fitting
4332    model (M) with respect to all parameters.  Results are returned in
4333    a Jacobian matrix (aka design matrix) of dimensions (n by m) where
4334    n is the number of parameters and m is the number of data
4335    points. This can exceed memory when m gets large. This routine is
4336    used when refinement derivatives are selected as "analtytic
4337    Jacobian" in Controls.
4338
4339    :returns: Jacobian numpy.array dMdv for all histograms concatinated
4340    '''
4341    parmDict.update(zip(varylist,values))
4342    G2mv.Dict2Map(parmDict)
4343    Histograms,Phases,restraintDict,rigidbodyDict = HistoPhases
4344    dependentVars = G2mv.GetDependentVars()
4345    histoList = list(Histograms.keys())
4346    histoList.sort()
4347    First = True
4348    for histogram in histoList:
4349        if 'PWDR' in histogram[:4]:
4350            Histogram = Histograms[histogram]
4351            hId = Histogram['hId']
4352            hfx = ':%d:'%(hId)
4353            wtFactor = calcControls[hfx+'wtFactor']
4354            Limits = calcControls[hfx+'Limits']
4355            x,y,w,yc,yb,yd = Histogram['Data']
4356            xB = np.searchsorted(x,Limits[0])
4357            xF = np.searchsorted(x,Limits[1])+1
4358            dMdv,depDerivDict = getPowderProfileDerv([parmDict,x[xB:xF],
4359                varylist,Histogram,Phases,rigidbodyDict,calcControls,pawleyLookup,dependentVars])
4360            G2mv.Dict2Deriv(varylist,depDerivDict,dMdv)
4361            dMdvh = np.sqrt(w[xB:xF])*dMdv
4362        elif 'HKLF' in histogram[:4]:
4363            Histogram = Histograms[histogram]
4364            phase = Histogram['Reflection Lists']
4365            Phase = Phases[phase]
4366            dMdvh,depDerivDict,wdf = dervHKLF(Histogram,Phase,calcControls,varylist,parmDict,rigidbodyDict)
4367            hfx = ':%d:'%(Histogram['hId'])
4368            wtFactor = calcControls[hfx+'wtFactor']
4369            # now process derivatives in constraints
4370            G2mv.Dict2Deriv(varylist,depDerivDict,dMdvh)
4371        else:
4372            continue        #skip non-histogram entries
4373        if First:
4374            dMdV = np.sqrt(wtFactor)*dMdvh
4375            First = False
4376        else:
4377            dMdV = np.concatenate((dMdV.T,np.sqrt(wtFactor)*dMdvh.T)).T
4378
4379    GetFobsSq(Histograms,Phases,parmDict,calcControls)
4380    pNames,pVals,pWt,pWsum,pWnum = penaltyFxn(HistoPhases,calcControls,parmDict,varylist)
4381    if np.any(pVals):
4382        dpdv = penaltyDeriv(pNames,pVals,HistoPhases,calcControls,parmDict,varylist)
4383        dMdV = np.concatenate((dMdV.T,(np.sqrt(pWt)*dpdv).T)).T
4384       
4385    return dMdV
4386
4387def HessRefine(values,HistoPhases,parmDict,varylist,calcControls,pawleyLookup,dlg):
4388    '''Loop over histograms and compute derivatives of the fitting
4389    model (M) with respect to all parameters.  For each histogram, the
4390    Jacobian matrix, dMdv, with dimensions (n by m) where n is the
4391    number of parameters and m is the number of data points *in the
4392    histogram*. The (n by n) Hessian is computed from each Jacobian
4393    and it is returned.  This routine is used when refinement
4394    derivatives are selected as "analtytic Hessian" in Controls.
4395
4396    :returns: Vec,Hess where Vec is the least-squares vector and Hess is the Hessian
4397    '''
4398    parmDict.update(zip(varylist,values))
4399    G2mv.Dict2Map(parmDict)
4400    Histograms,Phases,restraintDict,rigidbodyDict = HistoPhases
4401    dependentVars = G2mv.GetDependentVars()
4402    #fixup H atom positions here?
4403    ApplyRBModels(parmDict,Phases,rigidbodyDict)        #,Update=True??
4404    Hess = np.empty(0)
4405    Vec = np.empty(0)
4406    histoList = list(Histograms.keys())
4407    histoList.sort()
4408    for histogram in histoList:
4409        if 'PWDR' in histogram[:4]:
4410            if hasattr(dlg,'SetHistogram'): dlg.SetHistogram(None,'Computing derivatives for '+histogram)
4411            Histogram = Histograms[histogram]
4412            hId = Histogram['hId']
4413            hfx = ':%d:'%(hId)
4414            wtFactor = calcControls[hfx+'wtFactor']
4415            Limits = calcControls[hfx+'Limits']
4416            x,y,w,yc,yb,yd = Histogram['Data']
4417            W = wtFactor*w
4418            dy = y-yc
4419            xB = np.searchsorted(x,Limits[0])
4420            xF = np.searchsorted(x,Limits[1])+1
4421            useMP,ncores = G2mp.InitMP()
4422            if GSASIIpath.GetConfigValue('Show_timing',False): starttime = time.time()
4423            if useMP:
4424                MPpool = mp.Pool(ncores)
4425                dMdvh = None
4426                depDerivDict = None
4427                # old approach, create all args prior to use
4428#                profArgs = [
4429#                    (parmDict,x[xB:xF],varylist,Histogram,Phases,rigidbodyDict,calcControls,pawleyLookup,dependentVars,
4430#                     i,ncores,histogram) for i in range(ncores)]
4431#                for dmdv,depDerivs in MPpool.imap_unordered(getPowderProfileDerv,profArgs):
4432                # better, use a generator so arg is created as used
4433                profGenArgs = (
4434                    (parmDict,x[xB:xF],varylist,Histogram,Phases,rigidbodyDict,calcControls,pawleyLookup,dependentVars,
4435                     i,ncores,histogram) for i in range(ncores))
4436                for dmdv,depDerivs in MPpool.imap_unordered(getPowderProfileDerv,profGenArgs):
4437                    if dMdvh is None:
4438                       dMdvh = dmdv
4439                       depDerivDict = depDerivs
4440                    else: 
4441                       dMdvh += dmdv
4442                       for key in depDerivs.keys(): depDerivDict[key] += depDerivs[key]                       
4443                MPpool.terminate()
4444            else:
4445                dMdvh,depDerivDict = getPowderProfileDerv([parmDict,x[xB:xF],
4446                    varylist,Histogram,Phases,rigidbodyDict,calcControls,pawleyLookup,dependentVars,0,1,histogram])
4447                #dMdvh = getPowderProfileDerv(parmDict,x[xB:xF],
4448                #    varylist,Histogram,Phases,rigidbodyDict,calcControls,pawleyLookup,dependentVars)
4449            G2mv.Dict2Deriv(varylist,depDerivDict,dMdvh)
4450            if GSASIIpath.GetConfigValue('Show_timing',False): print ('getPowderProfileDerv t=%.3f'%(time.time()-starttime))
4451            Wt = ma.sqrt(W[xB:xF])[nxs,:]
4452            Dy = dy[xB:xF][nxs,:]
4453            dMdvh *= Wt
4454            if dlg:
4455                GoOn = dlg.Update(Histogram['Residuals']['wR'],newmsg='Hessian for histogram %d\nAll data Rw=%8.3f%s'%(hId,Histogram['Residuals']['wR'],'%'))
4456                if type(GoOn) is tuple:
4457                    if not GoOn[0]:
4458                        raise G2obj.G2RefineCancel('Cancel pressed')
4459                elif not GoOn:
4460                    raise G2obj.G2RefineCancel('Cancel pressed')
4461                #dlg.Raise()
4462            if len(Hess):
4463                Hess += np.inner(dMdvh,dMdvh)
4464                dMdvh *= Wt*Dy
4465                Vec += np.sum(dMdvh,axis=1)
4466            else:
4467                Hess = np.inner(dMdvh,dMdvh)
4468                dMdvh *= Wt*Dy
4469                Vec = np.sum(dMdvh,axis=1)
4470        elif 'HKLF' in histogram[:4]:
4471            if hasattr(dlg,'SetHistogram'): dlg.SetHistogram(None,'Computing derivatives for '+histogram)
4472            Histogram = Histograms[histogram]
4473            phase = Histogram['Reflection Lists']
4474            Phase = Phases[phase]
4475            dMdvh,depDerivDict,wdf = dervHKLF(Histogram,Phase,calcControls,varylist,parmDict,rigidbodyDict)
4476            hId = Histogram['hId']
4477            hfx = ':%d:'%(Histogram['hId'])
4478            wtFactor = calcControls[hfx+'wtFactor']
4479            # now process derivatives in constraints
4480            G2mv.Dict2Deriv(varylist,depDerivDict,dMdvh)
4481#            print 'matrix build time: %.3f'%(time.time()-time0)
4482
4483            if dlg:
4484                GoOn = dlg.Update(Histogram['Residuals']['wR'],newmsg='Hessian for histogram %d Rw=%8.3f%s'%(hId,Histogram['Residuals']['wR'],'%'))
4485                if type(GoOn) is tuple:
4486                    if not GoOn[0]:
4487                        raise G2obj.G2RefineCancel('Cancel pressed')
4488                elif not GoOn:
4489                    raise G2obj.G2RefineCancel('Cancel pressed')
4490                #dlg.Raise()
4491            if len(Hess):
4492                Vec += wtFactor*np.sum(dMdvh*wdf,axis=1)
4493                Hess += wtFactor*np.inner(dMdvh,dMdvh)
4494            else:
4495                Vec = wtFactor*np.sum(dMdvh*wdf,axis=1)
4496                Hess = wtFactor*np.inner(dMdvh,dMdvh)
4497        else:
4498            continue        #skip non-histogram entries
4499    GetFobsSq(Histograms,Phases,parmDict,calcControls)
4500    pNames,pVals,pWt,pWsum,pWnum = penaltyFxn(HistoPhases,calcControls,parmDict,varylist)
4501    if np.any(pVals):
4502        dpdv = penaltyDeriv(pNames,pVals,HistoPhases,calcControls,parmDict,varylist)
4503        Vec -= np.sum(dpdv*pWt*pVals,axis=1)
4504        Hess += np.inner(dpdv*pWt,dpdv)
4505    return Vec,Hess
4506
4507def errRefine(values,HistoPhases,parmDict,varylist,calcControls,pawleyLookup,dlg=None):       
4508    '''Computes the point-by-point discrepancies between every data point in every histogram
4509    and the observed value. Used in the Jacobian, Hessian & numeric least-squares to compute function
4510   
4511    :returns: an np array of differences between observed and computed diffraction values.
4512    '''
4513    Values2Dict(parmDict, varylist, values)
4514    if len(varylist):   #skip if no variables; e.g. in a zero cycle LeBail refinement
4515        G2mv.Dict2Map(parmDict)
4516    Histograms,Phases,restraintDict,rigidbodyDict = HistoPhases
4517    M = np.empty(0)
4518    SumwYo = 0
4519    Nobs = 0
4520    Nrej = 0
4521    Next = 0
4522    ApplyRBModels(parmDict,Phases,rigidbodyDict)
4523    #fixup Hatom positions here....
4524    histoList = list(Histograms.keys())
4525    histoList.sort()
4526    phasePartials = calcControls.get('PhasePartials',None)
4527    if phasePartials:
4528        print('Storing intensity by phase in',phasePartials)
4529        phPartialFP = open(phasePartials,'wb')  # create/clear partials file
4530        phPartialFP.close()
4531    for histogram in histoList:
4532        if 'PWDR' in histogram[:4]:
4533            Histogram = Histograms[histogram]
4534            hId = Histogram['hId']
4535            if hasattr(dlg,'SetHistogram'): dlg.SetHistogram(hId,histogram)
4536            hfx = ':%d:'%(hId)
4537            wtFactor = calcControls[hfx+'wtFactor']
4538            Limits = calcControls[hfx+'Limits']
4539            x,y,w,yc,yb,yd = Histogram['Data']
4540            yc *= 0.0                           #zero full calcd profiles
4541            yb *= 0.0
4542            yd *= 0.0
4543            xB = np.searchsorted(x,Limits[0])
4544            xF = np.searchsorted(x,Limits[1])+1
4545            yc[xB:xF],yb[xB:xF] = getPowderProfile(parmDict,x[xB:xF],
4546                varylist,Histogram,Phases,calcControls,pawleyLookup,histogram)
4547            yc[xB:xF] += yb[xB:xF]
4548            if not np.any(y):                   #fill dummy data
4549                try:
4550                    rv = st.poisson(yc[xB:xF])
4551                    y[xB:xF] = rv.rvs()
4552                except ValueError:
4553                    y[xB:xF] = yc[xB:xF]
4554                Z = np.ones_like(yc[xB:xF])
4555                Z[1::2] *= -1
4556                y[xB:xF] = yc[xB:xF]+np.abs(y[xB:xF]-yc[xB:xF])*Z
4557                w[xB:xF] = np.where(y[xB:xF]>0.,1./y[xB:xF],1.0)
4558            yd[xB:xF] = y[xB:xF]-yc[xB:xF]
4559            W = wtFactor*w
4560            wdy = -ma.sqrt(w[xB:xF])*(yd[xB:xF])
4561            Histogram['Residuals']['Durbin-Watson'] = ma.sum(ma.diff(wdy)**2)/ma.sum(wdy**2)
4562            wdy *= np.sqrt(wtFactor)
4563            Histogram['Residuals']['Nobs'] = ma.count(x[xB:xF])
4564            Nobs += Histogram['Residuals']['Nobs']
4565            Histogram['Residuals']['sumwYo'] = ma.sum(W[xB:xF]*y[xB:xF]**2)
4566            SumwYo += Histogram['Residuals']['sumwYo']
4567            Histogram['Residuals']['R'] = min(100.,ma.sum(ma.abs(yd[xB:xF]))/ma.sum(y[xB:xF])*100.)
4568            Histogram['Residuals']['wR'] = min(100.,ma.sqrt(ma.sum(wdy**2)/Histogram['Residuals']['sumwYo'])*100.)
4569            sumYmB = ma.sum(ma.where(yc[xB:xF]!=yb[xB:xF],ma.abs(y[xB:xF]-yb[xB:xF]),0.))
4570            sumwYmB2 = ma.sum(ma.where(yc[xB:xF]!=yb[xB:xF],W[xB:xF]*(y[xB:xF]-yb[xB:xF])**2,0.))
4571            sumYB = ma.sum(ma.where(yc[xB:xF]!=yb[xB:xF],ma.abs(y[xB:xF]-yc[xB:xF])*ma.abs(y[xB:xF]-yb[xB:xF])/y[xB:xF],0.))
4572            sumwYB2 = ma.sum(ma.where(yc[xB:xF]!=yb[xB:xF],W[xB:xF]*(ma.abs(y[xB:xF]-yc[xB:xF])*ma.abs(y[xB:xF]-yb[xB:xF])/y[xB:xF])**2,0.))
4573            Histogram['Residuals']['Rb'] = min(100.,100.*sumYB/sumYmB)
4574            Histogram['Residuals']['wRb'] = min(100.,100.*ma.sqrt(sumwYB2/sumwYmB2))
4575            Histogram['Residuals']['wRmin'] = min(100.,100.*ma.sqrt(Histogram['Residuals']['Nobs']/Histogram['Residuals']['sumwYo']))
4576            if dlg:
4577                GoOn = dlg.Update(Histogram['Residuals']['wR'],newmsg='For histogram %d Rw=%8.3f%s'%(hId,Histogram['Residuals']['wR'],'%'))
4578                if type(GoOn) is tuple:
4579                    if not GoOn[0]:
4580                        raise G2obj.G2RefineCancel('Cancel pressed')
4581                elif not GoOn:
4582                    raise G2obj.G2RefineCancel('Cancel pressed')
4583                #dlg.Raise()
4584            M = np.concatenate((M,wdy))
4585#end of PWDR processing
4586        elif 'HKLF' in histogram[:4]:
4587            Histogram = Histograms[histogram]
4588            hId = Histogram['hId']
4589            if hasattr(dlg,'SetHistogram'): dlg.SetHistogram(hId,histogram)
4590            Histogram['Residuals'] = {}
4591            phase = Histogram['Reflection Lists']
4592            Phase = Phases[phase]
4593            hfx = ':%d:'%(hId)
4594            wtFactor = calcControls[hfx+'wtFactor']
4595            pfx = '%d::'%(Phase['pId'])
4596            phfx = '%d:%d:'%(Phase['pId'],hId)
4597            SGData = Phase['General']['SGData']
4598            TwinLaw = calcControls[phfx+'TwinLaw']
4599            im = 0
4600            if parmDict[phfx+'Scale'] < 0.:
4601                parmDict[phfx+'Scale'] = .001               
4602            if Phase['General'].get('Modulated',False):
4603                SSGData = Phase['General']['SSGData']
4604                im = 1  #offset in SS reflection list
4605            A = [parmDict[pfx+'A%d'%(i)] for i in range(6)]
4606            G,g = G2lat.A2Gmat(A)       #recip & real metric tensors
4607            refDict = Histogram['Data']
4608            if im:
4609                if len(TwinLaw) > 1:
4610                    SStructureFactorTw(refDict,G,hfx,pfx,SGData,SSGData,calcControls,parmDict)
4611                else:
4612                    SStructureFactor(refDict,G,hfx,pfx,SGData,SSGData,calcControls,parmDict)
4613            else:
4614                StructureFactor2(refDict,G,hfx,pfx,SGData,calcControls,parmDict)
4615#            print 'sf-calc time: %.3f'%(time.time()-time0)
4616            df = np.zeros(len(refDict['RefList']))
4617            sumwYo = 0
4618            sumFo = 0
4619            sumFo2 = 0
4620            sumFc2 = 0
4621            sumdF = 0
4622            sumdF2 = 0
4623            if im:
4624                sumSSFo = np.zeros(10)
4625                sumSSFo2 = np.zeros(10)
4626                sumSSdF = np.zeros(10)
4627                sumSSdF2 = np.zeros(10)
4628                sumSSwYo = np.zeros(10)
4629                sumSSwdf2 = np.zeros(10)
4630                SSnobs = np.zeros(10)
4631            nobs = 0
4632            nrej = 0
4633            next = 0
4634            maxH = 0
4635            if calcControls['F**2']:
4636                for i,ref in enumerate(refDict['RefList']):
4637                    if ref[6+im] > 0:
4638                        ref[11+im] = SCExtinction(ref,im,phfx,hfx,pfx,calcControls,parmDict,varylist)[0]
4639                        w = 1.0/ref[6+im]   # 1/sig(F^2)
4640                        ref[7+im] *= parmDict[phfx+'Scale']*ref[11+im]  #correct Fc^2 for extinction
4641                        ref[8+im] = ref[5+im]/(parmDict[phfx+'Scale']*ref[11+im])
4642                        if UserRejectHKL(ref,im,calcControls['UsrReject']) and ref[3+im]:    #skip sp.gp. absences (mul=0)
4643                            ref[3+im] = abs(ref[3+im])      #mark as allowed
4644                            Fo = np.sqrt(ref[5+im])
4645                            sumFo += Fo
4646                            sumFo2 += ref[5+im]
4647                            sumFc2 += ref[7+im]
4648                            sumdF += abs(Fo-np.sqrt(ref[7+im]))
4649                            sumdF2 += abs(ref[5+im]-ref[7+im])
4650                            nobs += 1
4651                            df[i] = -w*(ref[5+im]-ref[7+im])
4652                            sumwYo += (w*ref[5+im])**2      #w*Fo^2
4653                            if im:  #accumulate super lattice sums
4654                                ind = int(abs(ref[3]))
4655                                sumSSFo[ind] += Fo
4656                                sumSSFo2[ind] += ref[5+im]
4657                                sumSSdF[ind] += abs(Fo-np.sqrt(ref[7+im]))
4658                                sumSSdF2[ind] += abs(ref[5+im]-ref[7+im])
4659                                sumSSwYo[ind] += (w*ref[5+im])**2      #w*Fo^2
4660                                sumSSwdf2[ind] +=  df[i]**2
4661                                SSnobs[ind] += 1
4662                                maxH = max(maxH,ind)                           
4663                        else:
4664                            if ref[3+im]:
4665                                ref[3+im] = -abs(ref[3+im])      #mark as rejected
4666                                nrej += 1
4667                            else:   #sp.gp.extinct
4668                                next += 1
4669            else:
4670                for i,ref in enumerate(refDict['RefList']):
4671                    if ref[5+im] > 0.:
4672                        ref[11+im] = SCExtinction(ref,im,phfx,hfx,pfx,calcControls,parmDict,varylist)[0]
4673                        ref[7+im] *= parmDict[phfx+'Scale']*ref[11+im]    #correct Fc^2 for extinction
4674                        ref[8+im] = ref[5+im]/(parmDict[phfx+'Scale']*ref[11+im])
4675                        Fo = np.sqrt(ref[5+im])
4676                        Fc = np.sqrt(ref[7+im])
4677                        w = 2.0*Fo/ref[6+im]    # 1/sig(F)?
4678                        if UserRejectHKL(ref,im,calcControls['UsrReject']) and ref[3+im]:    #skip sp.gp. absences (mul=0)
4679                            ref[3+im] = abs(ref[3+im])      #mark as allowed
4680                            sumFo += Fo
4681                            sumFo2 += ref[5+im]
4682                            sumFc2 += ref[7+im]
4683                            sumdF += abs(Fo-Fc)
4684                            sumdF2 += abs(ref[5+im]-ref[7+im])
4685                            nobs += 1
4686                            df[i] = -w*(Fo-Fc)
4687                            sumwYo += (w*Fo)**2
4688                            if im:
4689                                ind = int(abs(ref[3]))
4690                                sumSSFo[ind] += Fo
4691                                sumSSFo2[ind] += ref[5+im]
4692                                sumSSdF[ind] += abs(Fo-Fc)
4693                                sumSSdF2[ind] += abs(ref[5+im]-ref[7+im])
4694                                sumSSwYo[ind] += (w*Fo)**2                                                           
4695                                sumSSwdf2[ind] +=  df[i]**2
4696                                SSnobs[ind] += 1                           
4697                                maxH = max(maxH,ind)                           
4698                        else:
4699                            if ref[3+im]:
4700                                ref[3+im] = -abs(ref[3+im])      #mark as rejected
4701                                nrej += 1
4702                            else:   #sp.gp.extinct
4703                                next += 1
4704            Scale = sumFo2/sumFc2
4705            if (Scale < 0.8 or Scale > 1.2) and phfx+'Scale' in varylist:
4706                print ('New scale: %.4f'%(Scale*parmDict[phfx+'Scale']))
4707                indx = varylist.index(phfx+'Scale')
4708                values[indx] = Scale*parmDict[phfx+'Scale']             
4709            Histogram['Residuals']['Nobs'] = nobs
4710            Histogram['Residuals']['sumwYo'] = sumwYo
4711            SumwYo += sumwYo
4712            Histogram['Residuals']['wR'] = min(100.,np.sqrt(np.sum(df**2)/sumwYo)*100.)
4713            Histogram['Residuals'][phfx+'Rf'] = 100.*sumdF/sumFo
4714            Histogram['Residuals'][phfx+'Rf^2'] = 100.*sumdF2/sumFo2
4715            Histogram['Residuals'][phfx+'Nref'] = nobs
4716            Histogram['Residuals'][phfx+'Nrej'] = nrej
4717            Histogram['Residuals'][phfx+'Next'] = next
4718            if im:
4719                Histogram['Residuals'][phfx+'SSRf'] = 100.*sumSSdF[:maxH+1]/sumSSFo[:maxH+1]
4720                Histogram['Residuals'][phfx+'SSRf^2'] = 100.*sumSSdF2[:maxH+1]/sumSSFo2[:maxH+1]
4721                Histogram['Residuals'][phfx+'SSNref'] = SSnobs[:maxH+1]
4722                Histogram['Residuals']['SSwR'] = np.sqrt(sumSSwdf2[:maxH+1]/sumSSwYo[:maxH+1])*100.               
4723            Nobs += nobs
4724            Nrej += nrej
4725            Next += next
4726            if dlg:
4727                GoOn = dlg.Update(Histogram['Residuals']['wR'],newmsg='For histogram %d Rw=%8.3f%s'%(hId,Histogram['Residuals']['wR'],'%'))
4728                if type(GoOn) is tuple:
4729                    if not GoOn[0]:
4730                        raise G2obj.G2RefineCancel('Cancel pressed')
4731                elif not GoOn:
4732                    raise G2obj.G2RefineCancel('Cancel pressed')
4733                #dlg.Raise()
4734            M = np.concatenate((M,wtFactor*df))
4735# end of HKLF processing
4736#    GetFobsSq(Histograms,Phases,parmDict,calcControls)
4737    Histograms['sumwYo'] = SumwYo
4738    Histograms['Nobs'] = Nobs
4739    Histograms['Nrej'] = Nrej
4740    Histograms['Next'] = Next
4741    Rw = min(100.,np.sqrt(np.sum(M**2)/SumwYo)*100.)
4742    if dlg:
4743        if hasattr(dlg,'SetHistogram'): dlg.SetHistogram(-1,'overall')
4744        GoOn = dlg.Update(Rw,newmsg='%s%8.3f%s'%('All data Rw =',Rw,'%'))
4745        if type(GoOn) is tuple:
4746            if not GoOn[0]:
4747                parmDict['saved values'] = values
4748                raise G2obj.G2RefineCancel('Cancel pressed')
4749        elif not GoOn:
4750            parmDict['saved values'] = values
4751            raise G2obj.G2RefineCancel('Cancel pressed')
4752        #dlg.Raise()
4753    pDict,pVals,pWt,pWsum,pWnum = penaltyFxn(HistoPhases,calcControls,parmDict,varylist)
4754    if len(pVals):
4755        pSum = np.sum(pWt*pVals**2)
4756        for name in pWsum:
4757            if pWsum[name]:
4758                print ('  Penalty function for %5d %8ss = %12.5g'%(pWnum[name],name,pWsum[name]))
4759        print ('Total penalty function: %12.5g on %d terms'%(pSum,len(pVals)))
4760        if hasattr(dlg,'SetHistogram'): dlg.SetHistogram(-2,'Restraints')
4761        Nobs += len(pVals)
4762        M = np.concatenate((M,np.sqrt(pWt)*pVals))
4763        GoOn = dlg.Update(100*pSum/np.sum(M**2),newmsg='Restraints')
4764    return M
4765
4766def calcMassFracs(varyList,covMatrix,Phases,hist,hId):
4767    '''Compute mass fractions and their uncertainties for all
4768    phases in a histogram. Computed using the covariance matrix,
4769    along with the derivatives for the mass fraction equations.
4770
4771    :param list varyList: list of varied parameters
4772    :param np.array covMatrix: covariance matrix, order of rows and columns
4773       must match varyList
4774    :param dict Phases: data structure (from tree or .gpx) with all
4775       phase information
4776    :param str hist: name of selected histogram
4777    :param int hId: number of current histogram
4778    :returns: valDict,sigDict which contain the mass fraction values and
4779        sigmas, keyed by "ph:h:WgtFrac"
4780    '''
4781    # Compute mass normalizer & assemble list of refined PF terms
4782    wtSum = 0.0
4783    mass = {}
4784    phFr = {}
4785    used = {}
4786    for phase in Phases:
4787        if Phases[phase]['General']['Type'] == 'magnetic': continue
4788        if Phases[phase]['General']['doPawley']: continue
4789        if hist not in Phases[phase]['Histograms']: continue
4790        if not Phases[phase]['Histograms'][hist]['Use']: continue
4791        pId = Phases[phase]['pId']
4792        mass[pId] = Phases[phase]['General']['Mass']
4793        phFr[pId] = Phases[phase]['Histograms'][hist]['Scale'][0]
4794        wtSum += mass[pId]*phFr[pId]
4795        # Is this PF refined?
4796        var = "{}:{}:Scale".format(pId,hId)
4797        if var in varyList: # yes, save it
4798            used[varyList.index(var)] = pId
4799        elif var in G2mv.GetDependentVars():
4800            for v,m in zip(*G2mv.getInvConstraintEq(var,varyList)):
4801                if v not in varyList: continue
4802                i = varyList.index(v)
4803                if i not in used: used[i] = {}
4804                used[i][pId] = m
4805    valDict = {}
4806    sigDict = {}
4807    for phasej in Phases:
4808        if Phases[phasej]['General']['Type'] == 'magnetic': continue
4809        if Phases[phase]['General']['doPawley']: continue
4810        if hist not in Phases[phasej]['Histograms']: continue
4811        if not Phases[phasej]['Histograms'][hist]['Use']: continue
4812        if wtSum < 1.0: continue  #no atoms; probable LeBail
4813        pId_j = Phases[phasej]['pId']
4814        var = "{}:{}:WgtFrac".format(pId_j,hId)
4815        valDict[var] = mass[pId_j] * phFr[pId_j] / wtSum
4816        Avec = np.zeros(len(varyList))
4817        for i in used:
4818            if type(used[i]) is dict:
4819                for pId_i in used[i]:
4820                    if pId_i ==  pId_j:
4821                        deriv = (mass[pId_j]/wtSum) - (mass[pId_j]**2 * phFr[pId_j]/wtSum**2)
4822                    else:
4823                        deriv = -mass[pId_j]* mass[pId_i] * phFr[pId_j]/wtSum**2
4824                    Avec[i] +=  used[i][pId_i] * deriv # dot product
4825            else:
4826                pId_i = used[i]
4827                if pId_i ==  pId_j:
4828                    Avec[i] = (mass[pId_j]/wtSum) - (mass[pId_j]**2 * phFr[pId_j]/wtSum**2)
4829                else:
4830                    Avec[i] = -mass[pId_j]* mass[pId_i] * phFr[pId_j]/wtSum**2
4831        sigDict[var] = np.sqrt(np.inner(Avec.T,np.inner(covMatrix,Avec)))
4832    if len(valDict) == 1: return {},{}  # don't add where only a single phase is present
4833    return valDict,sigDict
Note: See TracBrowser for help on using the repository browser.