1 | # -*- coding: utf-8 -*- |
---|
2 | #GSASIImath - major mathematics routines |
---|
3 | ########### SVN repository information ################### |
---|
4 | # $Date: 2019-04-12 20:35:08 +0000 (Fri, 12 Apr 2019) $ |
---|
5 | # $Author: vondreele $ |
---|
6 | # $Revision: 3893 $ |
---|
7 | # $URL: trunk/GSASIImath.py $ |
---|
8 | # $Id: GSASIImath.py 3893 2019-04-12 20:35:08Z vondreele $ |
---|
9 | ########### SVN repository information ################### |
---|
10 | ''' |
---|
11 | *GSASIImath: computation module* |
---|
12 | ================================ |
---|
13 | |
---|
14 | Routines for least-squares minimization and other stuff |
---|
15 | |
---|
16 | ''' |
---|
17 | from __future__ import division, print_function |
---|
18 | import random as rn |
---|
19 | import numpy as np |
---|
20 | import numpy.linalg as nl |
---|
21 | import numpy.ma as ma |
---|
22 | import time |
---|
23 | import math |
---|
24 | import copy |
---|
25 | import GSASIIpath |
---|
26 | GSASIIpath.SetVersionNumber("$Revision: 3893 $") |
---|
27 | import GSASIIElem as G2el |
---|
28 | import GSASIIlattice as G2lat |
---|
29 | import GSASIIspc as G2spc |
---|
30 | import GSASIIpwd as G2pwd |
---|
31 | import numpy.fft as fft |
---|
32 | import scipy.optimize as so |
---|
33 | try: |
---|
34 |   import pypowder as pwd |
---|
35 | except ImportError: |
---|
36 |   print ('pypowder is not available - profile calcs. not allowed') |
---|
37 | |
---|
38 | sind = lambda x: np.sin(x*np.pi/180.) |
---|
39 | cosd = lambda x: np.cos(x*np.pi/180.) |
---|
40 | tand = lambda x: np.tan(x*np.pi/180.) |
---|
41 | asind = lambda x: 180.*np.arcsin(x)/np.pi |
---|
42 | acosd = lambda x: 180.*np.arccos(x)/np.pi |
---|
43 | atand = lambda x: 180.*np.arctan(x)/np.pi |
---|
44 | atan2d = lambda y,x: 180.*np.arctan2(y,x)/np.pi |
---|
45 | twopi =Â 2.0*np.pi |
---|
46 | twopisq =Â 2.0*np.pi**2 |
---|
47 | nxs =Â np.newaxis |
---|
48 | Â Â |
---|
49 | ################################################################################ |
---|
50 | ##### Hessian least-squares Levenberg-Marquardt routine |
---|
51 | ################################################################################ |
---|
52 | |
---|
53 | def pinv(a, rcond=1e-15 ): |
---|
54 | Â Â """ |
---|
55 | Â Â Compute the (Moore-Penrose) pseudo-inverse of a matrix. |
---|
56 | Â Â Modified from numpy.linalg.pinv; assumes a is Hessian & returns no. zeros found |
---|
57 | Â Â Calculate the generalized inverse of a matrix using its |
---|
58 | Â Â singular-value decomposition (SVD) and including all |
---|
59 | Â Â *large* singular values. |
---|
60 | |
---|
61 | Â Â :param array a: (M, M) array_like - here assumed to be LS Hessian |
---|
62 | Â Â Â Matrix to be pseudo-inverted. |
---|
63 | Â Â :param float rcond: Cutoff for small singular values. |
---|
64 | Â Â Â Singular values smaller (in modulus) than |
---|
65 | Â Â Â `rcond` * largest_singular_value (again, in modulus) |
---|
66 | Â Â Â are set to zero. |
---|
67 | |
---|
68 | Â Â :returns: B : (M, M) ndarray |
---|
69 | Â Â Â The pseudo-inverse of `a` |
---|
70 | |
---|
71 | Â Â Raises: LinAlgError |
---|
72 | Â Â Â If the SVD computation does not converge. |
---|
73 | |
---|
74 | Â Â Notes: |
---|
75 | Â Â Â The pseudo-inverse of a matrix A, denoted :math:`A^+`, is |
---|
76 | Â Â Â defined as: "the matrix that 'solves' [the least-squares problem] |
---|
77 | Â Â Â :math:`Ax = b`," i.e., if :math:`\\bar{x}` is said solution, then |
---|
78 | Â Â Â :math:`A^+` is that matrix such that :math:`\\bar{x} = A^+b`. |
---|
79 | |
---|
80 | Â Â It can be shown that if :math:`Q_1 \\Sigma Q_2^T = A` is the singular |
---|
81 | Â Â value decomposition of A, then |
---|
82 | Â Â :math:`A^+ = Q_2 \\Sigma^+ Q_1^T`, where :math:`Q_{1,2}` are |
---|
83 | Â Â orthogonal matrices, :math:`\\Sigma` is a diagonal matrix consisting |
---|
84 | Â Â of A's so-called singular values, (followed, typically, by |
---|
85 | Â Â zeros), and then :math:`\\Sigma^+` is simply the diagonal matrix |
---|
86 | Â Â consisting of the reciprocals of A's singular values |
---|
87 | Â Â (again, followed by zeros). [1] |
---|
88 | |
---|
89 | Â Â References: |
---|
90 | Â Â .. [1] G. Strang, *Linear Algebra and Its Applications*, 2nd Ed., Orlando, FL, Academic Press, Inc., 1980, pp. 139-142. |
---|
91 | |
---|
92 | Â Â """ |
---|
93 |   u, s, vt = nl.svd(a) |
---|
94 | Â Â cutoff =Â rcond*np.maximum.reduce(s) |
---|
95 | Â Â s =Â np.where(s>cutoff,1./s,0.) |
---|
96 | Â Â nzero =Â s.shape[0]-np.count_nonzero(s) |
---|
97 | #Â Â res = np.dot(np.transpose(vt), np.multiply(s[:, np.newaxis], np.transpose(u))) |
---|
98 | Â Â res =Â np.dot(vt.T,s[:,nxs]*u.T) |
---|
99 |   return res,nzero |
---|
100 | |
---|
101 | def HessianLSQ(func,x0,Hess,args=(),ftol=1.49012e-8,xtol=1.e-6, maxcyc=0,lamda=-3,Print=False): |
---|
102 | Â Â |
---|
103 | Â Â """ |
---|
104 | Â Â Minimize the sum of squares of a function (:math:`f`) evaluated on a series of |
---|
105 | Â Â values (y): :math:`\sum_{y=0}^{N_{obs}} f(y,{args})`Â Â |
---|
106 | Â Â where :math:`x = arg min(\sum_{y=0}^{N_{obs}} (func(y)^2,axis=0))` |
---|
107 | |
---|
108 | Â Â :param function func: callable method or function |
---|
109 | Â Â Â Â should take at least one (possibly length N vector) argument and |
---|
110 | Â Â Â Â returns M floating point numbers. |
---|
111 | Â Â :param np.ndarray x0: The starting estimate for the minimization of length N |
---|
112 | Â Â :param function Hess: callable method or function |
---|
113 | Â Â Â Â A required function or method to compute the weighted vector and Hessian for func. |
---|
114 | Â Â Â Â It must be a symmetric NxN array |
---|
115 | Â Â :param tuple args: Any extra arguments to func are placed in this tuple. |
---|
116 | Â Â :param float ftol: Relative error desired in the sum of squares. |
---|
117 | Â Â :param float xtol: Relative tolerance of zeros in the SVD solution in nl.pinv. |
---|
118 | Â Â :param int maxcyc: The maximum number of cycles of refinement to execute, if -1 refine |
---|
119 | Â Â Â Â until other limits are met (ftol, xtol) |
---|
120 | Â Â :param int lamda: initial Marquardt lambda=10**lamda |
---|
121 | Â Â :param bool Print: True for printing results (residuals & times) by cycle |
---|
122 | |
---|
123 | Â Â :returns: (x,cov_x,infodict) where |
---|
124 | |
---|
125 | Â Â Â * x : ndarray |
---|
126 | Â Â Â Â The solution (or the result of the last iteration for an unsuccessful |
---|
127 | Â Â Â Â call). |
---|
128 | Â Â Â * cov_x : ndarray |
---|
129 | Â Â Â Â Uses the fjac and ipvt optional outputs to construct an |
---|
130 |     estimate of the jacobian around the solution. ``None`` if a |
---|
131 | Â Â Â Â singular matrix encountered (indicates very flat curvature in |
---|
132 |     some direction). This matrix must be multiplied by the |
---|
133 | Â Â Â Â residual standard deviation to get the covariance of the |
---|
134 | Â Â Â Â parameter estimates -- see curve_fit. |
---|
135 | Â Â Â * infodict : dict |
---|
136 | Â Â Â Â a dictionary of optional outputs with the keys: |
---|
137 | |
---|
138 | Â Â Â Â Â * 'fvec' : the function evaluated at the output |
---|
139 | Â Â Â Â Â * 'num cyc': |
---|
140 | Â Â Â Â Â * 'nfev': |
---|
141 | Â Â Â Â Â * 'lamMax': |
---|
142 | Â Â Â Â Â * 'psing': |
---|
143 | Â Â Â Â Â * 'SVD0': |
---|
144 | Â Â Â Â Â Â |
---|
145 | Â Â """ |
---|
146 | Â Â Â Â Â Â Â Â |
---|
147 | Â Â ifConverged =Â False |
---|
148 | Â Â deltaChi2 =Â -10. |
---|
149 |   x0 = np.array(x0, ndmin=1)   #might be redundant? |
---|
150 | Â Â n =Â len(x0) |
---|
151 |   if type(args) != type(()): |
---|
152 | Â Â Â Â args =Â (args,) |
---|
153 | Â Â Â Â |
---|
154 | Â Â icycle =Â 0 |
---|
155 | Â Â One =Â np.ones((n,n)) |
---|
156 | Â Â lam =Â 10.**lamda |
---|
157 | Â Â lamMax =Â lam |
---|
158 | Â Â nfev =Â 0 |
---|
159 |   if Print: |
---|
160 |     print (' Hessian Levenberg-Marquardt SVD refinement on %d variables:'%(n)) |
---|
161 | Â Â Lam =Â np.zeros((n,n)) |
---|
162 |   while icycle < maxcyc: |
---|
163 | Â Â Â Â time0 =Â time.time() |
---|
164 | Â Â Â Â M =Â func(x0,*args) |
---|
165 | Â Â Â Â Nobs =Â len(M) |
---|
166 | Â Â Â Â nfev +=Â 1 |
---|
167 | Â Â Â Â chisq0 =Â np.sum(M**2) |
---|
168 | Â Â Â Â Yvec,Amat =Â Hess(x0,*args) |
---|
169 | Â Â Â Â Adiag =Â np.sqrt(np.diag(Amat)) |
---|
170 | Â Â Â Â psing =Â np.where(np.abs(Adiag)Â <Â 1.e-14,True,False) |
---|
171 |     if np.any(psing):        #hard singularity in matrix |
---|
172 |       return [x0,None,{'num cyc':icycle,'fvec':M,'nfev':nfev,'lamMax':lamMax,'psing':psing,'SVD0':-1}] |
---|
173 | Â Â Â Â Anorm =Â np.outer(Adiag,Adiag) |
---|
174 | Â Â Â Â Yvec /=Â Adiag |
---|
175 | Â Â Â Â Amat /=Â Anorm |
---|
176 |     if Print: |
---|
177 |       print ('initial chi^2 %.5g on %d obs.'%(chisq0,Nobs)) |
---|
178 | Â Â Â Â chitol =Â ftol |
---|
179 |     while True: |
---|
180 | Â Â Â Â Â Â Lam =Â np.eye(Amat.shape[0])*lam |
---|
181 | Â Â Â Â Â Â Amatlam =Â Amat*(One+Lam) |
---|
182 | Â Â Â Â Â Â try: |
---|
183 | Â Â Â Â Â Â Â Â Ainv,Nzeros =Â pinv(Amatlam,xtol)Â Â #do Moore-Penrose inversion (via SVD) |
---|
184 |       except nl.LinAlgError: |
---|
185 | Â Â Â Â Â Â Â Â psing =Â list(np.where(np.diag(nl.qr(Amatlam)[1])Â <Â 1.e-14)[0]) |
---|
186 |         print ('ouch #1 bad SVD inversion; change parameterization for ',psing) |
---|
187 |         return [x0,None,{'num cyc':icycle,'fvec':M,'nfev':nfev,'lamMax':lamMax,'psing':psing,'SVD0':-1}] |
---|
188 | Â Â Â Â Â Â Xvec =Â np.inner(Ainv,Yvec)Â Â Â #solve |
---|
189 | Â Â Â Â Â Â Xvec /=Â Adiag |
---|
190 | Â Â Â Â Â Â M2 =Â func(x0+Xvec,*args) |
---|
191 | Â Â Â Â Â Â nfev +=Â 1 |
---|
192 | Â Â Â Â Â Â chisq1 =Â np.sum(M2**2) |
---|
193 |       if chisq1 > chisq0*(1.+chitol):   #TODO put Alan Coehlo's criteria for lambda here? |
---|
194 | Â Â Â Â Â Â Â Â lam *=Â 10. |
---|
195 |         if Print: |
---|
196 |           print ('new chi^2 %.5g on %d obs., %d SVD zeros ; matrix modification needed; lambda now %.1e' \ |
---|
197 | Â Â Â Â Â Â Â Â Â Â Â Â Â Â %(chisq1,Nobs,Nzeros,lam)) |
---|
198 | Â Â Â Â Â Â else: |
---|
199 | Â Â Â Â Â Â Â Â x0 +=Â Xvec |
---|
200 | Â Â Â Â Â Â Â Â lam /=Â 10. |
---|
201 | Â Â Â Â Â Â Â Â break |
---|
202 |       if lam > 10.: |
---|
203 |         print ('ouch #3 chisq1 %g.4 stuck > chisq0 %g.4'%(chisq1,chisq0)) |
---|
204 | Â Â Â Â Â Â Â Â break |
---|
205 | Â Â Â Â Â Â chitol *=Â 2 |
---|
206 | Â Â Â Â lamMax =Â max(lamMax,lam) |
---|
207 | Â Â Â Â deltaChi2 =Â (chisq0-chisq1)/chisq0 |
---|
208 |     if Print: |
---|
209 |       print (' Cycle: %d, Time: %.2fs, Chi**2: %.5g for %d obs., Lambda: %.3g, Delta: %.3g'%( |
---|
210 | Â Â Â Â Â Â Â Â icycle,time.time()-time0,chisq1,Nobs,lamMax,deltaChi2)) |
---|
211 |     if deltaChi2 < ftol: |
---|
212 | Â Â Â Â Â Â ifConverged =Â True |
---|
213 |       if Print: print ("converged") |
---|
214 | Â Â Â Â Â Â break |
---|
215 | Â Â Â Â icycle +=Â 1 |
---|
216 | Â Â M =Â func(x0,*args) |
---|
217 | Â Â nfev +=Â 1 |
---|
218 | Â Â Yvec,Amat =Â Hess(x0,*args) |
---|
219 | Â Â Adiag =Â np.sqrt(np.diag(Amat)) |
---|
220 | Â Â Anorm =Â np.outer(Adiag,Adiag) |
---|
221 | Â Â Lam =Â np.eye(Amat.shape[0])*lam |
---|
222 |   Amatlam = Amat/Anorm    |
---|
223 | Â Â try: |
---|
224 | Â Â Â Â Bmat,Nzero =Â pinv(Amatlam,xtol)Â Â #Moore-Penrose inversion (via SVD) & count of zeros |
---|
225 |     if Print: print ('Found %d SVD zeros'%(Nzero)) |
---|
226 | Â Â Â Â Bmat =Â Bmat/Anorm |
---|
227 |     return [x0,Bmat,{'num cyc':icycle,'fvec':M,'nfev':nfev,'lamMax':lamMax,'psing':[],'SVD0':Nzero,'Converged': ifConverged, 'DelChi2':deltaChi2}] |
---|
228 |   except nl.LinAlgError: |
---|
229 |     print ('ouch #2 linear algebra error in making v-cov matrix') |
---|
230 | Â Â Â Â psing =Â [] |
---|
231 |     if maxcyc: |
---|
232 | Â Â Â Â Â Â psing =Â list(np.where(np.diag(nl.qr(Amat)[1])Â <Â 1.e-14)[0]) |
---|
233 |     return [x0,None,{'num cyc':icycle,'fvec':M,'nfev':nfev,'lamMax':lamMax,'psing':psing,'SVD0':-1}]     |
---|
234 | Â Â Â Â Â Â |
---|
235 | def HessianSVD(func,x0,Hess,args=(),ftol=1.49012e-8,xtol=1.e-6, maxcyc=0,lamda=-3,Print=False): |
---|
236 | Â Â |
---|
237 | Â Â """ |
---|
238 | Â Â Minimize the sum of squares of a function (:math:`f`) evaluated on a series of |
---|
239 | Â Â values (y): :math:`\sum_{y=0}^{N_{obs}} f(y,{args})`Â Â |
---|
240 | Â Â where :math:`x = arg min(\sum_{y=0}^{N_{obs}} (func(y)^2,axis=0))` |
---|
241 | |
---|
242 | Â Â :param function func: callable method or function |
---|
243 | Â Â Â Â should take at least one (possibly length N vector) argument and |
---|
244 | Â Â Â Â returns M floating point numbers. |
---|
245 | Â Â :param np.ndarray x0: The starting estimate for the minimization of length N |
---|
246 | Â Â :param function Hess: callable method or function |
---|
247 | Â Â Â Â A required function or method to compute the weighted vector and Hessian for func. |
---|
248 | Â Â Â Â It must be a symmetric NxN array |
---|
249 | Â Â :param tuple args: Any extra arguments to func are placed in this tuple. |
---|
250 | Â Â :param float ftol: Relative error desired in the sum of squares. |
---|
251 | Â Â :param float xtol: Relative tolerance of zeros in the SVD solution in nl.pinv. |
---|
252 | Â Â :param int maxcyc: The maximum number of cycles of refinement to execute, if -1 refine |
---|
253 | Â Â Â Â until other limits are met (ftol, xtol) |
---|
254 | Â Â :param bool Print: True for printing results (residuals & times) by cycle |
---|
255 | |
---|
256 | Â Â :returns: (x,cov_x,infodict) where |
---|
257 | |
---|
258 | Â Â Â * x : ndarray |
---|
259 | Â Â Â Â The solution (or the result of the last iteration for an unsuccessful |
---|
260 | Â Â Â Â call). |
---|
261 | Â Â Â * cov_x : ndarray |
---|
262 | Â Â Â Â Uses the fjac and ipvt optional outputs to construct an |
---|
263 |     estimate of the jacobian around the solution. ``None`` if a |
---|
264 | Â Â Â Â singular matrix encountered (indicates very flat curvature in |
---|
265 |     some direction). This matrix must be multiplied by the |
---|
266 | Â Â Â Â residual standard deviation to get the covariance of the |
---|
267 | Â Â Â Â parameter estimates -- see curve_fit. |
---|
268 | Â Â Â * infodict : dict |
---|
269 | Â Â Â Â a dictionary of optional outputs with the keys: |
---|
270 | |
---|
271 | Â Â Â Â Â * 'fvec' : the function evaluated at the output |
---|
272 | Â Â Â Â Â * 'num cyc': |
---|
273 | Â Â Â Â Â * 'nfev': |
---|
274 | Â Â Â Â Â * 'lamMax':0. |
---|
275 | Â Â Â Â Â * 'psing': |
---|
276 | Â Â Â Â Â * 'SVD0': |
---|
277 | Â Â Â Â Â Â |
---|
278 | Â Â """ |
---|
279 | Â Â Â Â Â Â Â Â |
---|
280 | Â Â ifConverged =Â False |
---|
281 | Â Â deltaChi2 =Â -10. |
---|
282 |   x0 = np.array(x0, ndmin=1)   #might be redundant? |
---|
283 | Â Â n =Â len(x0) |
---|
284 |   if type(args) != type(()): |
---|
285 | Â Â Â Â args =Â (args,) |
---|
286 | Â Â Â Â |
---|
287 | Â Â icycle =Â 0 |
---|
288 | Â Â nfev =Â 0 |
---|
289 |   if Print: |
---|
290 |     print (' Hessian SVD refinement on %d variables:'%(n)) |
---|
291 |   while icycle < maxcyc: |
---|
292 | Â Â Â Â time0 =Â time.time() |
---|
293 | Â Â Â Â M =Â func(x0,*args) |
---|
294 | Â Â Â Â nfev +=Â 1 |
---|
295 | Â Â Â Â chisq0 =Â np.sum(M**2) |
---|
296 | Â Â Â Â Yvec,Amat =Â Hess(x0,*args) |
---|
297 | Â Â Â Â Adiag =Â np.sqrt(np.diag(Amat)) |
---|
298 | Â Â Â Â psing =Â np.where(np.abs(Adiag)Â <Â 1.e-14,True,False) |
---|
299 |     if np.any(psing):        #hard singularity in matrix |
---|
300 |       return [x0,None,{'num cyc':icycle,'fvec':M,'nfev':nfev,'lamMax':0.,'psing':psing,'SVD0':-1}] |
---|
301 | Â Â Â Â Anorm =Â np.outer(Adiag,Adiag) |
---|
302 | Â Â Â Â Yvec /=Â Adiag |
---|
303 | Â Â Â Â Amat /=Â Anorm |
---|
304 |     if Print: |
---|
305 |       print ('initial chi^2 %.5g'%(chisq0)) |
---|
306 | Â Â Â Â try: |
---|
307 | Â Â Â Â Â Â Ainv,Nzeros =Â pinv(Amat,xtol)Â Â #do Moore-Penrose inversion (via SVD) |
---|
308 |     except nl.LinAlgError: |
---|
309 |       print ('ouch #1 bad SVD inversion; change parameterization') |
---|
310 | Â Â Â Â Â Â psing =Â list(np.where(np.diag(nl.qr(Amat)[1])Â <Â 1.e-14)[0]) |
---|
311 |       return [x0,None,{'num cyc':icycle,'fvec':M,'nfev':nfev,'lamMax':0.,'psing':psing,'SVD0':-1}] |
---|
312 | Â Â Â Â Xvec =Â np.inner(Ainv,Yvec)Â Â Â #solve |
---|
313 | Â Â Â Â Xvec /=Â Adiag |
---|
314 | Â Â Â Â M2 =Â func(x0+Xvec,*args) |
---|
315 | Â Â Â Â nfev +=Â 1 |
---|
316 | Â Â Â Â chisq1 =Â np.sum(M2**2) |
---|
317 | Â Â Â Â deltaChi2 =Â (chisq0-chisq1)/chisq0 |
---|
318 |     if Print: |
---|
319 |       print (' Cycle: %d, Time: %.2fs, Chi**2: %.5g, Delta: %.3g'%( |
---|
320 | Â Â Â Â Â Â Â Â icycle,time.time()-time0,chisq1,deltaChi2)) |
---|
321 |     if deltaChi2 < ftol: |
---|
322 | Â Â Â Â Â Â ifConverged =Â True |
---|
323 |       if Print: print ("converged") |
---|
324 | Â Â Â Â Â Â break |
---|
325 | Â Â Â Â icycle +=Â 1 |
---|
326 | Â Â M =Â func(x0,*args) |
---|
327 | Â Â nfev +=Â 1 |
---|
328 | Â Â Yvec,Amat =Â Hess(x0,*args) |
---|
329 | Â Â Adiag =Â np.sqrt(np.diag(Amat)) |
---|
330 | Â Â Anorm =Â np.outer(Adiag,Adiag) |
---|
331 |   Amat = Amat/Anorm    |
---|
332 | Â Â try: |
---|
333 | Â Â Â Â Bmat,Nzero =Â pinv(Amat,xtol)Â Â #Moore-Penrose inversion (via SVD) & count of zeros |
---|
334 |     print ('Found %d SVD zeros'%(Nzero)) |
---|
335 | #Â Â Â Â Bmat = nl.inv(Amatlam); Nzeros = 0 |
---|
336 | Â Â Â Â Bmat =Â Bmat/Anorm |
---|
337 |     return [x0,Bmat,{'num cyc':icycle,'fvec':M,'nfev':nfev,'lamMax':0.,'psing':[], |
---|
338 |       'SVD0':Nzero,'Converged': ifConverged, 'DelChi2':deltaChi2}] |
---|
339 |   except nl.LinAlgError: |
---|
340 |     print ('ouch #2 linear algebra error in making v-cov matrix') |
---|
341 | Â Â Â Â psing =Â [] |
---|
342 |     if maxcyc: |
---|
343 | Â Â Â Â Â Â psing =Â list(np.where(np.diag(nl.qr(Amat)[1])Â <Â 1.e-14)[0]) |
---|
344 |     return [x0,None,{'num cyc':icycle,'fvec':M,'nfev':nfev,'lamMax':0.,'psing':psing,'SVD0':-1}]     |
---|
345 | Â Â Â Â Â Â |
---|
346 | def getVCov(varyNames,varyList,covMatrix): |
---|
347 | Â Â '''obtain variance-covariance terms for a set of variables. NB: the varyList |
---|
348 | Â Â and covMatrix were saved by the last least squares refinement so they must match. |
---|
349 | Â Â |
---|
350 | Â Â :param list varyNames: variable names to find v-cov matric for |
---|
351 | Â Â :param list varyList: full list of all variables in v-cov matrix |
---|
352 | Â Â :param nparray covMatrix: full variance-covariance matrix from the last |
---|
353 | Â Â Â least squares refinement |
---|
354 | Â Â |
---|
355 | Â Â :returns: nparray vcov: variance-covariance matrix for the variables given |
---|
356 | Â Â Â in varyNames |
---|
357 | Â Â |
---|
358 | Â Â ''' |
---|
359 | Â Â vcov =Â np.zeros((len(varyNames),len(varyNames))) |
---|
360 |   for i1,name1 in enumerate(varyNames): |
---|
361 |     for i2,name2 in enumerate(varyNames): |
---|
362 | Â Â Â Â Â Â try: |
---|
363 | Â Â Â Â Â Â Â Â vcov[i1][i2]Â =Â covMatrix[varyList.index(name1)][varyList.index(name2)] |
---|
364 |       except ValueError: |
---|
365 | Â Â Â Â Â Â Â Â vcov[i1][i2]Â =Â 0.0 |
---|
366 | #Â Â Â Â Â Â Â Â if i1 == i2: |
---|
367 | #Â Â Â Â Â Â Â Â Â Â vcov[i1][i2] = 1e-20 |
---|
368 | #Â Â Â Â Â Â Â Â else: |
---|
369 | #Â Â Â Â Â Â Â Â Â Â vcov[i1][i2] = 0.0 |
---|
370 |   return vcov |
---|
371 | Â Â |
---|
372 | ################################################################################ |
---|
373 | ##### Atom manipulations |
---|
374 | ################################################################################ |
---|
375 | |
---|
376 | def FindMolecule(ind,generalData,atomData):          #uses numpy & masks - very fast even for proteins! |
---|
377 | |
---|
378 |   def getNeighbors(atom,radius): |
---|
379 | Â Â Â Â Dx =Â UAtoms-np.array(atom[cx:cx+3]) |
---|
380 | Â Â Â Â dist =Â ma.masked_less(np.sqrt(np.sum(np.inner(Amat,Dx)**2,axis=0)),0.5)Â #gets rid of disorder "bonds" < 0.5A |
---|
381 | Â Â Â Â sumR =Â Radii+radius |
---|
382 |     return set(ma.nonzero(ma.masked_greater(dist-factor*sumR,0.))[0])        #get indices of bonded atoms |
---|
383 | |
---|
384 |   import numpy.ma as ma |
---|
385 | Â Â indices =Â (-1,0,1) |
---|
386 |   Units = np.array([[h,k,l] for h in indices for k in indices for l in indices],dtype='f') |
---|
387 | Â Â cx,ct,cs,ci =Â generalData['AtomPtrs'] |
---|
388 | Â Â DisAglCtls =Â generalData['DisAglCtls'] |
---|
389 | Â Â SGData =Â generalData['SGData'] |
---|
390 | Â Â Amat,Bmat =Â G2lat.cell2AB(generalData['Cell'][1:7]) |
---|
391 | Â Â radii =Â DisAglCtls['BondRadii'] |
---|
392 | Â Â atomTypes =Â DisAglCtls['AtomTypes'] |
---|
393 | Â Â factor =Â DisAglCtls['Factors'][0] |
---|
394 | Â Â unit =Â np.zeros(3) |
---|
395 | Â Â try: |
---|
396 | Â Â Â Â indH =Â atomTypes.index('H') |
---|
397 | Â Â Â Â radii[indH]Â =Â 0.5 |
---|
398 | Â Â except: |
---|
399 |     pass      |
---|
400 | Â Â nAtom =Â len(atomData) |
---|
401 | Â Â Indx =Â range(nAtom) |
---|
402 | Â Â UAtoms =Â [] |
---|
403 | Â Â Radii =Â [] |
---|
404 |   for atom in atomData: |
---|
405 | Â Â Â Â UAtoms.append(np.array(atom[cx:cx+3])) |
---|
406 | Â Â Â Â Radii.append(radii[atomTypes.index(atom[ct])]) |
---|
407 | Â Â UAtoms =Â np.array(UAtoms) |
---|
408 | Â Â Radii =Â np.array(Radii) |
---|
409 |   for nOp,Op in enumerate(SGData['SGOps'][1:]): |
---|
410 | Â Â Â Â UAtoms =Â np.concatenate((UAtoms,(np.inner(Op[0],UAtoms[:nAtom]).T+Op[1]))) |
---|
411 | Â Â Â Â Radii =Â np.concatenate((Radii,Radii[:nAtom])) |
---|
412 | Â Â Â Â Indx +=Â Indx[:nAtom] |
---|
413 |   for icen,cen in enumerate(SGData['SGCen'][1:]): |
---|
414 | Â Â Â Â UAtoms =Â np.concatenate((UAtoms,(UAtoms+cen))) |
---|
415 | Â Â Â Â Radii =Â np.concatenate((Radii,Radii)) |
---|
416 | Â Â Â Â Indx +=Â Indx[:nAtom] |
---|
417 |   if SGData['SGInv']: |
---|
418 | Â Â Â Â UAtoms =Â np.concatenate((UAtoms,-UAtoms)) |
---|
419 | Â Â Â Â Radii =Â np.concatenate((Radii,Radii)) |
---|
420 | Â Â Â Â Indx +=Â Indx |
---|
421 | Â Â UAtoms %=Â 1. |
---|
422 | Â Â mAtoms =Â len(UAtoms) |
---|
423 |   for unit in Units: |
---|
424 |     if np.any(unit):  #skip origin cell |
---|
425 | Â Â Â Â Â Â UAtoms =Â np.concatenate((UAtoms,UAtoms[:mAtoms]+unit)) |
---|
426 | Â Â Â Â Â Â Radii =Â np.concatenate((Radii,Radii[:mAtoms])) |
---|
427 | Â Â Â Â Â Â Indx +=Â Indx[:mAtoms] |
---|
428 | Â Â UAtoms =Â np.array(UAtoms) |
---|
429 | Â Â Radii =Â np.array(Radii) |
---|
430 | Â Â newAtoms =Â [atomData[ind],] |
---|
431 | Â Â atomData[ind]Â =Â None |
---|
432 | Â Â radius =Â Radii[ind] |
---|
433 | Â Â IndB =Â getNeighbors(newAtoms[-1],radius) |
---|
434 |   while True: |
---|
435 |     if not len(IndB): |
---|
436 | Â Â Â Â Â Â break |
---|
437 | Â Â Â Â indb =Â IndB.pop() |
---|
438 |     if atomData[Indx[indb]] == None: |
---|
439 | Â Â Â Â Â Â continue |
---|
440 |     while True: |
---|
441 | Â Â Â Â Â Â try: |
---|
442 | Â Â Â Â Â Â Â Â jndb =Â IndB.index(indb) |
---|
443 | Â Â Â Â Â Â Â Â IndB.remove(jndb) |
---|
444 | Â Â Â Â Â Â except: |
---|
445 | Â Â Â Â Â Â Â Â break |
---|
446 | Â Â Â Â newAtom =Â copy.copy(atomData[Indx[indb]]) |
---|
447 | Â Â Â Â newAtom[cx:cx+3]Â =Â UAtoms[indb]Â Â Â #NB: thermal Uij, etc. not transformed! |
---|
448 | Â Â Â Â newAtoms.append(newAtom) |
---|
449 | Â Â Â Â atomData[Indx[indb]]Â =Â None |
---|
450 | Â Â Â Â IndB =Â set(list(IndB)+list(getNeighbors(newAtoms[-1],radius))) |
---|
451 |     if len(IndB) > nAtom: |
---|
452 |       return 'Assemble molecule cannot be used on extended structures' |
---|
453 |   for atom in atomData: |
---|
454 |     if atom != None: |
---|
455 | Â Â Â Â Â Â newAtoms.append(atom) |
---|
456 |   return newAtoms |
---|
457 | Â Â Â Â |
---|
458 | def FindAtomIndexByIDs(atomData,loc,IDs,Draw=True): |
---|
459 | Â Â '''finds the set of atom array indices for a list of atom IDs. Will search |
---|
460 | Â Â either the Atom table or the drawAtom table. |
---|
461 | Â Â |
---|
462 | Â Â :param list atomData: Atom or drawAtom table containting coordinates, etc. |
---|
463 | Â Â :param int loc: location of atom id in atomData record |
---|
464 | Â Â :param list IDs: atom IDs to be found |
---|
465 | Â Â :param bool Draw: True if drawAtom table to be searched; False if Atom table |
---|
466 | Â Â Â is searched |
---|
467 | Â Â |
---|
468 | Â Â :returns: list indx: atom (or drawAtom) indices |
---|
469 | Â Â |
---|
470 | Â Â ''' |
---|
471 | Â Â indx =Â [] |
---|
472 |   for i,atom in enumerate(atomData): |
---|
473 |     if Draw and atom[loc] in IDs: |
---|
474 | Â Â Â Â Â Â indx.append(i) |
---|
475 |     elif atom[loc] in IDs: |
---|
476 | Â Â Â Â Â Â indx.append(i) |
---|
477 |   return indx |
---|
478 | |
---|
479 | def FillAtomLookUp(atomData,indx): |
---|
480 | Â Â '''create a dictionary of atom indexes with atom IDs as keys |
---|
481 | Â Â |
---|
482 | Â Â :param list atomData: Atom table to be used |
---|
483 | Â Â |
---|
484 | Â Â :returns: dict atomLookUp: dictionary of atom indexes with atom IDs as keys |
---|
485 | Â Â |
---|
486 | Â Â ''' |
---|
487 | Â Â atomLookUp =Â {} |
---|
488 |   for iatm,atom in enumerate(atomData): |
---|
489 | Â Â Â Â atomLookUp[atom[indx]]Â =Â iatm |
---|
490 |   return atomLookUp |
---|
491 | |
---|
492 | def GetAtomsById(atomData,atomLookUp,IdList): |
---|
493 | Â Â '''gets a list of atoms from Atom table that match a set of atom IDs |
---|
494 | Â Â |
---|
495 | Â Â :param list atomData: Atom table to be used |
---|
496 | Â Â :param dict atomLookUp: dictionary of atom indexes with atom IDs as keys |
---|
497 | Â Â :param list IdList: atom IDs to be found |
---|
498 | Â Â |
---|
499 | Â Â :returns: list atoms: list of atoms found |
---|
500 | Â Â |
---|
501 | Â Â ''' |
---|
502 | Â Â atoms =Â [] |
---|
503 |   for Id in IdList: |
---|
504 | Â Â Â Â atoms.append(atomData[atomLookUp[Id]]) |
---|
505 |   return atoms |
---|
506 | Â Â |
---|
507 | def GetAtomItemsById(atomData,atomLookUp,IdList,itemLoc,numItems=1): |
---|
508 | Â Â '''gets atom parameters for atoms using atom IDs |
---|
509 | Â Â |
---|
510 | Â Â :param list atomData: Atom table to be used |
---|
511 | Â Â :param dict atomLookUp: dictionary of atom indexes with atom IDs as keys |
---|
512 | Â Â :param list IdList: atom IDs to be found |
---|
513 | Â Â :param int itemLoc: pointer to desired 1st item in an atom table entry |
---|
514 | Â Â :param int numItems: number of items to be retrieved |
---|
515 | Â Â |
---|
516 | Â Â :returns: type name: description |
---|
517 | Â Â |
---|
518 | Â Â ''' |
---|
519 | Â Â Items =Â [] |
---|
520 |   if not isinstance(IdList,list): |
---|
521 | Â Â Â Â IdList =Â [IdList,] |
---|
522 |   for Id in IdList: |
---|
523 |     if numItems == 1: |
---|
524 | Â Â Â Â Â Â Items.append(atomData[atomLookUp[Id]][itemLoc]) |
---|
525 | Â Â Â Â else: |
---|
526 | Â Â Â Â Â Â Items.append(atomData[atomLookUp[Id]][itemLoc:itemLoc+numItems]) |
---|
527 |   return Items |
---|
528 | Â Â |
---|
529 | def GetAtomCoordsByID(pId,parmDict,AtLookup,indx): |
---|
530 | Â Â '''default doc string |
---|
531 | Â Â |
---|
532 | Â Â :param type name: description |
---|
533 | Â Â |
---|
534 | Â Â :returns: type name: description |
---|
535 | Â Â |
---|
536 | Â Â ''' |
---|
537 |   pfx = [str(pId)+'::A'+i+':' for i in ['x','y','z']] |
---|
538 |   dpfx = [str(pId)+'::dA'+i+':' for i in ['x','y','z']] |
---|
539 | Â Â XYZ =Â [] |
---|
540 |   for ind in indx: |
---|
541 |     names = [pfx[i]+str(AtLookup[ind]) for i in range(3)] |
---|
542 |     dnames = [dpfx[i]+str(AtLookup[ind]) for i in range(3)] |
---|
543 |     XYZ.append([parmDict[name]+parmDict[dname] for name,dname in zip(names,dnames)]) |
---|
544 |   return XYZ |
---|
545 | Â Â |
---|
546 | def GetAtomFracByID(pId,parmDict,AtLookup,indx): |
---|
547 | Â Â '''default doc string |
---|
548 | Â Â |
---|
549 | Â Â :param type name: description |
---|
550 | Â Â |
---|
551 | Â Â :returns: type name: description |
---|
552 | Â Â |
---|
553 | Â Â ''' |
---|
554 | Â Â pfx =Â str(pId)+'::Afrac:' |
---|
555 | Â Â Frac =Â [] |
---|
556 |   for ind in indx: |
---|
557 | Â Â Â Â name =Â pfx+str(AtLookup[ind]) |
---|
558 | Â Â Â Â Frac.append(parmDict[name]) |
---|
559 |   return Frac |
---|
560 | Â Â |
---|
561 | #Â Â for Atom in Atoms: |
---|
562 | #Â Â Â Â XYZ = Atom[cx:cx+3] |
---|
563 | #Â Â Â Â if 'A' in Atom[cia]: |
---|
564 | #Â Â Â Â Â Â U6 = Atom[cia+2:cia+8] |
---|
565 | Â Â |
---|
566 | |
---|
567 | def ApplySeqData(data,seqData): |
---|
568 | Â Â '''Applies result from seq. refinement to drawing atom positions & Uijs |
---|
569 | Â Â ''' |
---|
570 | Â Â generalData =Â data['General'] |
---|
571 | Â Â SGData =Â generalData['SGData'] |
---|
572 | Â Â cx,ct,cs,cia =Â generalData['AtomPtrs'] |
---|
573 | Â Â drawingData =Â data['Drawing'] |
---|
574 | Â Â dcx,dct,dcs,dci =Â drawingData['atomPtrs'] |
---|
575 | Â Â atoms =Â data['Atoms'] |
---|
576 | Â Â drawAtoms =Â drawingData['Atoms'] |
---|
577 | Â Â pId =Â data['pId'] |
---|
578 | Â Â pfx =Â '%d::'%(pId) |
---|
579 | Â Â parmDict =Â seqData['parmDict'] |
---|
580 |   for ia,atom in enumerate(atoms): |
---|
581 | Â Â Â Â dxyz =Â np.array([parmDict[pfx+'dAx:'+str(ia)],parmDict[pfx+'dAy:'+str(ia)],parmDict[pfx+'dAz:'+str(ia)]]) |
---|
582 |     if atom[cia] == 'A': |
---|
583 | Â Â Â Â Â Â atuij =Â np.array([parmDict[pfx+'AU11:'+str(ia)],parmDict[pfx+'AU22:'+str(ia)],parmDict[pfx+'AU33:'+str(ia)], |
---|
584 | Â Â Â Â Â Â Â Â parmDict[pfx+'AU12:'+str(ia)],parmDict[pfx+'AU13:'+str(ia)],parmDict[pfx+'AU23:'+str(ia)]]) |
---|
585 | Â Â Â Â else: |
---|
586 | Â Â Â Â Â Â atuiso =Â parmDict[pfx+'AUiso:'+str(ia)] |
---|
587 | Â Â Â Â atxyz =Â G2spc.MoveToUnitCell(np.array(atom[cx:cx+3])+dxyz)[0] |
---|
588 | Â Â Â Â indx =Â FindAtomIndexByIDs(drawAtoms,dci,[atom[cia+8],],True) |
---|
589 |     for ind in indx: |
---|
590 | Â Â Â Â Â Â drawatom =Â drawAtoms[ind] |
---|
591 | Â Â Â Â Â Â opr =Â drawatom[dcs-1] |
---|
592 | Â Â Â Â Â Â #how do I handle Sfrac? - fade the atoms? |
---|
593 |       if atom[cia] == 'A':          |
---|
594 | Â Â Â Â Â Â Â Â X,U =Â G2spc.ApplyStringOps(opr,SGData,atxyz,atuij) |
---|
595 | Â Â Â Â Â Â Â Â drawatom[dcx:dcx+3]Â =Â X |
---|
596 | Â Â Â Â Â Â Â Â drawatom[dci-6:dci]Â =Â U |
---|
597 | Â Â Â Â Â Â else: |
---|
598 | Â Â Â Â Â Â Â Â X =Â G2spc.ApplyStringOps(opr,SGData,atxyz) |
---|
599 | Â Â Â Â Â Â Â Â drawatom[dcx:dcx+3]Â =Â X |
---|
600 | Â Â Â Â Â Â Â Â drawatom[dci-7]Â =Â atuiso |
---|
601 |   return drawAtoms |
---|
602 | Â Â |
---|
603 | def FindNeighbors(phase,FrstName,AtNames,notName=''): |
---|
604 | Â Â General =Â phase['General'] |
---|
605 | Â Â cx,ct,cs,cia =Â General['AtomPtrs'] |
---|
606 | Â Â Atoms =Â phase['Atoms'] |
---|
607 |   atNames = [atom[ct-1] for atom in Atoms] |
---|
608 | Â Â Cell =Â General['Cell'][1:7] |
---|
609 | Â Â Amat,Bmat =Â G2lat.cell2AB(Cell) |
---|
610 | Â Â atTypes =Â General['AtomTypes'] |
---|
611 | Â Â Radii =Â np.array(General['BondRadii']) |
---|
612 | Â Â DisAglCtls =Â General['DisAglCtls']Â Â |
---|
613 | Â Â radiusFactor =Â DisAglCtls['Factors'][0] |
---|
614 | Â Â AtInfo =Â dict(zip(atTypes,Radii))Â #or General['BondRadii'] |
---|
615 | Â Â Orig =Â atNames.index(FrstName) |
---|
616 | Â Â OId =Â Atoms[Orig][cia+8] |
---|
617 | Â Â OType =Â Atoms[Orig][ct] |
---|
618 | Â Â XYZ =Â getAtomXYZ(Atoms,cx)Â Â Â Â |
---|
619 | Â Â Neigh =Â [] |
---|
620 | Â Â Ids =Â [] |
---|
621 | Â Â Dx =Â np.inner(Amat,XYZ-XYZ[Orig]).T |
---|
622 | Â Â dist =Â np.sqrt(np.sum(Dx**2,axis=1)) |
---|
623 |   sumR = np.array([AtInfo[OType]+AtInfo[atom[ct]] for atom in Atoms]) |
---|
624 | Â Â IndB =Â ma.nonzero(ma.masked_greater(dist-radiusFactor*sumR,0.)) |
---|
625 |   for j in IndB[0]: |
---|
626 |     if j != Orig: |
---|
627 |       if AtNames[j] != notName: |
---|
628 | Â Â Â Â Â Â Â Â Neigh.append([AtNames[j],dist[j],True]) |
---|
629 | Â Â Â Â Â Â Â Â Ids.append(Atoms[j][cia+8]) |
---|
630 |   return Neigh,[OId,Ids] |
---|
631 | Â Â |
---|
632 | def FindAllNeighbors(phase,FrstName,AtNames,notName=''): |
---|
633 | Â Â General =Â phase['General'] |
---|
634 | Â Â cx,ct,cs,cia =Â General['AtomPtrs'] |
---|
635 | Â Â Atoms =Â phase['Atoms'] |
---|
636 |   atNames = [atom[ct-1] for atom in Atoms] |
---|
637 | Â Â Cell =Â General['Cell'][1:7] |
---|
638 | Â Â Amat,Bmat =Â G2lat.cell2AB(Cell) |
---|
639 | Â Â SGData =Â General['SGData'] |
---|
640 | Â Â indices =Â (-1,0,1) |
---|
641 |   Units = np.array([[h,k,l] for h in indices for k in indices for l in indices]) |
---|
642 | Â Â atTypes =Â General['AtomTypes'] |
---|
643 | Â Â Radii =Â np.array(General['BondRadii']) |
---|
644 | Â Â DisAglCtls =Â General['DisAglCtls']Â Â |
---|
645 | Â Â radiusFactor =Â DisAglCtls['Factors'][0] |
---|
646 | Â Â AtInfo =Â dict(zip(atTypes,Radii))Â #or General['BondRadii'] |
---|
647 | Â Â Orig =Â atNames.index(FrstName) |
---|
648 | Â Â OId =Â Atoms[Orig][cia+8] |
---|
649 | Â Â OType =Â Atoms[Orig][ct] |
---|
650 | Â Â XYZ =Â getAtomXYZ(Atoms,cx)Â Â Â Â |
---|
651 | Â Â Oxyz =Â XYZ[Orig] |
---|
652 | Â Â Neigh =Â [] |
---|
653 | Â Â Ids =Â [] |
---|
654 |   sumR = np.array([AtInfo[OType]+AtInfo[atom[ct]] for atom in Atoms]) |
---|
655 | Â Â sumR =Â np.reshape(np.tile(sumR,27),(27,-1)) |
---|
656 | Â Â results =Â [] |
---|
657 |   for xyz in XYZ: |
---|
658 | Â Â Â Â results.append(G2spc.GenAtom(xyz,SGData,False,Move=False)) |
---|
659 |   for iA,result in enumerate(results): |
---|
660 |     if iA != Orig:        |
---|
661 |       for [Txyz,Top,Tunit,Spn] in result: |
---|
662 |         Dx = np.array([Txyz-Oxyz+unit for unit in Units]) |
---|
663 | Â Â Â Â Â Â Â Â dx =Â np.inner(Dx,Amat) |
---|
664 | Â Â Â Â Â Â Â Â dist =Â np.sqrt(np.sum(dx**2,axis=1)) |
---|
665 | Â Â Â Â Â Â Â Â IndB =Â ma.nonzero(ma.masked_greater(dist-radiusFactor*sumR[:,iA],0.)) |
---|
666 | Â Â Â Â #Â Â Â Â GSASIIpath.IPyBreak() |
---|
667 |         for iU in IndB[0]: |
---|
668 |           if AtNames[iA] != notName: |
---|
669 | Â Â Â Â Â Â Â Â Â Â Â Â unit =Â Units[iU] |
---|
670 |             if np.any(unit): |
---|
671 | Â Â Â Â Â Â Â Â Â Â Â Â Â Â Topstr =Â ' +(%4d)[%2d,%2d,%2d]'%(Top,unit[0],unit[1],unit[2]) |
---|
672 | Â Â Â Â Â Â Â Â Â Â Â Â else: |
---|
673 | Â Â Â Â Â Â Â Â Â Â Â Â Â Â Topstr =Â ' +(%4d)'%(Top) |
---|
674 | Â Â Â Â Â Â Â Â Â Â Â Â Neigh.append([AtNames[iA]+Topstr,dist[iU]]) |
---|
675 | Â Â Â Â Â Â Â Â Â Â Â Â Ids.append(Atoms[iA][cia+8]) |
---|
676 |   return Neigh,[OId,Ids] |
---|
677 | Â Â |
---|
678 | def calcBond(A,Ax,Bx,MTCU): |
---|
679 | Â Â cell =Â G2lat.A2cell(A) |
---|
680 | Â Â Amat,Bmat =Â G2lat.cell2AB(cell) |
---|
681 | Â Â M,T,C,U =Â MTCU |
---|
682 | Â Â Btx =Â np.inner(M,Bx)+T+C+U |
---|
683 | Â Â Dx =Â Btx-Ax |
---|
684 | Â Â dist =Â np.sqrt(np.inner(Amat,Dx)) |
---|
685 |   return dist |
---|
686 | Â Â |
---|
687 | def AddHydrogens(AtLookUp,General,Atoms,AddHydId): |
---|
688 | Â Â |
---|
689 |   def getTransMat(RXYZ,OXYZ,TXYZ,Amat): |
---|
690 | Â Â Â Â Vec =Â np.inner(Amat,np.array([OXYZ-TXYZ[0],RXYZ-TXYZ[0]])).TÂ Â Â Â Â Â |
---|
691 | Â Â Â Â Vec /=Â np.sqrt(np.sum(Vec**2,axis=1))[:,nxs] |
---|
692 | Â Â Â Â Mat2 =Â np.cross(Vec[0],Vec[1])Â Â Â #UxV |
---|
693 | Â Â Â Â Mat2 /=Â np.sqrt(np.sum(Mat2**2)) |
---|
694 | Â Â Â Â Mat3 =Â np.cross(Mat2,Vec[0])Â Â Â Â #(UxV)xU |
---|
695 |     return nl.inv(np.array([Vec[0],Mat2,Mat3]))    |
---|
696 | Â Â |
---|
697 | Â Â cx,ct,cs,cia =Â General['AtomPtrs'] |
---|
698 | Â Â Cell =Â General['Cell'][1:7] |
---|
699 | Â Â Amat,Bmat =Â G2lat.cell2AB(Cell) |
---|
700 | Â Â nBonds =Â AddHydId[-1]+len(AddHydId[1]) |
---|
701 | Â Â Oatom =Â GetAtomsById(Atoms,AtLookUp,[AddHydId[0],])[0] |
---|
702 | Â Â OXYZ =Â np.array(Oatom[cx:cx+3]) |
---|
703 |   if 'I' in Oatom[cia]: |
---|
704 | Â Â Â Â Uiso =Â Oatom[cia+1] |
---|
705 | Â Â else: |
---|
706 | Â Â Â Â Uiso =Â (Oatom[cia+2]+Oatom[cia+3]+Oatom[cia+4])/3.0Â Â Â Â #simple average |
---|
707 | Â Â Uiso =Â max(Uiso,0.005)Â Â Â Â Â Â Â Â Â Â Â #set floor! |
---|
708 | Â Â Tatoms =Â GetAtomsById(Atoms,AtLookUp,AddHydId[1]) |
---|
709 |   TXYZ = np.array([tatom[cx:cx+3] for tatom in Tatoms]) #3 x xyz |
---|
710 |   if nBonds == 4: |
---|
711 |     if AddHydId[-1] == 1: |
---|
712 | Â Â Â Â Â Â Vec =Â TXYZ-OXYZ |
---|
713 | Â Â Â Â Â Â Len =Â np.sqrt(np.sum(np.inner(Amat,Vec).T**2,axis=0)) |
---|
714 | Â Â Â Â Â Â Vec =Â np.sum(Vec/Len,axis=0) |
---|
715 | Â Â Â Â Â Â Len =Â np.sqrt(np.sum(Vec**2)) |
---|
716 | Â Â Â Â Â Â Hpos =Â OXYZ-0.98*np.inner(Bmat,Vec).T/Len |
---|
717 | Â Â Â Â Â Â HU =Â 1.1*Uiso |
---|
718 |       return [Hpos,],[HU,] |
---|
719 |     elif AddHydId[-1] == 2: |
---|
720 | Â Â Â Â Â Â Vec =Â np.inner(Amat,TXYZ-OXYZ).T |
---|
721 | Â Â Â Â Â Â Vec[0]Â +=Â Vec[1]Â Â Â Â Â Â #U - along bisector |
---|
722 | Â Â Â Â Â Â Vec /=Â np.sqrt(np.sum(Vec**2,axis=1))[:,nxs] |
---|
723 | Â Â Â Â Â Â Mat2 =Â np.cross(Vec[0],Vec[1])Â Â Â #UxV |
---|
724 | Â Â Â Â Â Â Mat2 /=Â np.sqrt(np.sum(Mat2**2)) |
---|
725 | Â Â Â Â Â Â Mat3 =Â np.cross(Mat2,Vec[0])Â Â Â Â #(UxV)xU |
---|
726 | Â Â Â Â Â Â iMat =Â nl.inv(np.array([Vec[0],Mat2,Mat3])) |
---|
727 | Â Â Â Â Â Â Hpos =Â np.array([[-0.97*cosd(54.75),0.97*sind(54.75),0.], |
---|
728 | Â Â Â Â Â Â Â Â [-0.97*cosd(54.75),-0.97*sind(54.75),0.]]) |
---|
729 | Â Â Â Â Â Â HU =Â 1.2*Uiso*np.ones(2) |
---|
730 | Â Â Â Â Â Â Hpos =Â np.inner(Bmat,np.inner(iMat,Hpos).T).T+OXYZ |
---|
731 |       return Hpos,HU |
---|
732 | Â Â Â Â else: |
---|
733 | Â Â Â Â Â Â Ratom =Â GetAtomsById(Atoms,AtLookUp,[AddHydId[2],])[0] |
---|
734 | Â Â Â Â Â Â RXYZ =Â np.array(Ratom[cx:cx+3]) |
---|
735 | Â Â Â Â Â Â iMat =Â getTransMat(RXYZ,OXYZ,TXYZ,Amat) |
---|
736 | Â Â Â Â Â Â a =Â 0.96*cosd(70.5) |
---|
737 | Â Â Â Â Â Â b =Â 0.96*sind(70.5) |
---|
738 | Â Â Â Â Â Â Hpos =Â np.array([[a,0.,-b],[a,-b*cosd(30.),0.5*b],[a,b*cosd(30.),0.5*b]]) |
---|
739 | Â Â Â Â Â Â Hpos =Â np.inner(Bmat,np.inner(iMat,Hpos).T).T+OXYZ |
---|
740 | Â Â Â Â Â Â HU =Â 1.5*Uiso*np.ones(3) |
---|
741 |       return Hpos,HU     |
---|
742 |   elif nBonds == 3: |
---|
743 |     if AddHydId[-1] == 1: |
---|
744 | Â Â Â Â Â Â Vec =Â np.sum(TXYZ-OXYZ,axis=0)Â Â Â Â Â Â Â Â |
---|
745 | Â Â Â Â Â Â Len =Â np.sqrt(np.sum(np.inner(Amat,Vec).T**2)) |
---|
746 | Â Â Â Â Â Â Vec =Â -0.93*Vec/Len |
---|
747 | Â Â Â Â Â Â Hpos =Â OXYZ+Vec |
---|
748 | Â Â Â Â Â Â HU =Â 1.1*Uiso |
---|
749 |       return [Hpos,],[HU,] |
---|
750 |     elif AddHydId[-1] == 2: |
---|
751 | Â Â Â Â Â Â Ratom =Â GetAtomsById(Atoms,AtLookUp,[AddHydId[2],])[0] |
---|
752 | Â Â Â Â Â Â RXYZ =Â np.array(Ratom[cx:cx+3]) |
---|
753 | Â Â Â Â Â Â iMat =Â getTransMat(RXYZ,OXYZ,TXYZ,Amat) |
---|
754 | Â Â Â Â Â Â a =Â 0.93*cosd(60.) |
---|
755 | Â Â Â Â Â Â b =Â 0.93*sind(60.) |
---|
756 | Â Â Â Â Â Â Hpos =Â [[a,b,0],[a,-b,0]] |
---|
757 | Â Â Â Â Â Â Hpos =Â np.inner(Bmat,np.inner(iMat,Hpos).T).T+OXYZ |
---|
758 | Â Â Â Â Â Â HU =Â 1.2*Uiso*np.ones(2) |
---|
759 |       return Hpos,HU |
---|
760 | Â Â else:Â Â #2 bonds |
---|
761 |     if 'C' in Oatom[ct]: |
---|
762 | Â Â Â Â Â Â Vec =Â TXYZ[0]-OXYZ |
---|
763 | Â Â Â Â Â Â Len =Â np.sqrt(np.sum(np.inner(Amat,Vec).T**2)) |
---|
764 | Â Â Â Â Â Â Vec =Â -0.93*Vec/Len |
---|
765 | Â Â Â Â Â Â Hpos =Â OXYZ+Vec |
---|
766 | Â Â Â Â Â Â HU =Â 1.1*Uiso |
---|
767 |       return [Hpos,],[HU,] |
---|
768 |     elif 'O' in Oatom[ct]: |
---|
769 | Â Â Â Â Â Â mapData =Â General['Map'] |
---|
770 | Â Â Â Â Â Â Ratom =Â GetAtomsById(Atoms,AtLookUp,[AddHydId[2],])[0] |
---|
771 | Â Â Â Â Â Â RXYZ =Â np.array(Ratom[cx:cx+3]) |
---|
772 | Â Â Â Â Â Â iMat =Â getTransMat(RXYZ,OXYZ,TXYZ,Amat) |
---|
773 | Â Â Â Â Â Â a =Â 0.82*cosd(70.5) |
---|
774 | Â Â Â Â Â Â b =Â 0.82*sind(70.5) |
---|
775 | Â Â Â Â Â Â azm =Â np.arange(0.,360.,5.) |
---|
776 |       Hpos = np.array([[a,b*cosd(x),b*sind(x)] for x in azm]) |
---|
777 | Â Â Â Â Â Â Hpos =Â np.inner(Bmat,np.inner(iMat,Hpos).T).T+OXYZ |
---|
778 |       Rhos = np.array([getRho(pos,mapData) for pos in Hpos]) |
---|
779 | Â Â Â Â Â Â imax =Â np.argmax(Rhos) |
---|
780 | Â Â Â Â Â Â HU =Â 1.5*Uiso |
---|
781 |       return [Hpos[imax],],[HU,] |
---|
782 |   return [],[] |
---|
783 | Â Â Â Â |
---|
784 | #def AtomUij2TLS(atomData,atPtrs,Amat,Bmat,rbObj):Â Â #unfinished & not used |
---|
785 | #Â Â '''default doc string |
---|
786 | #Â Â |
---|
787 | #Â Â :param type name: description |
---|
788 | #Â Â |
---|
789 | #Â Â :returns: type name: description |
---|
790 | #Â Â |
---|
791 | #Â Â ''' |
---|
792 | #Â Â for atom in atomData: |
---|
793 | #Â Â Â Â XYZ = np.inner(Amat,atom[cx:cx+3]) |
---|
794 | #Â Â Â Â if atom[cia] == 'A': |
---|
795 | #Â Â Â Â Â Â UIJ = atom[cia+2:cia+8] |
---|
796 | Â Â Â Â Â Â Â Â |
---|
797 | def TLS2Uij(xyz,g,Amat,rbObj):  #not used anywhere, but could be? |
---|
798 | Â Â '''default doc string |
---|
799 | Â Â |
---|
800 | Â Â :param type name: description |
---|
801 | Â Â |
---|
802 | Â Â :returns: type name: description |
---|
803 | Â Â |
---|
804 | Â Â ''' |
---|
805 | Â Â TLStype,TLS =Â rbObj['ThermalMotion'][:2] |
---|
806 | Â Â Tmat =Â np.zeros((3,3)) |
---|
807 | Â Â Lmat =Â np.zeros((3,3)) |
---|
808 | Â Â Smat =Â np.zeros((3,3)) |
---|
809 | Â Â gvec =Â np.sqrt(np.array([g[0][0]**2,g[1][1]**2,g[2][2]**2, |
---|
810 | Â Â Â Â g[0][0]*g[1][1],g[0][0]*g[2][2],g[1][1]*g[2][2]])) |
---|
811 |   if 'T' in TLStype: |
---|
812 | Â Â Â Â Tmat =Â G2lat.U6toUij(TLS[:6]) |
---|
813 |   if 'L' in TLStype: |
---|
814 | Â Â Â Â Lmat =Â G2lat.U6toUij(TLS[6:12]) |
---|
815 |   if 'S' in TLStype: |
---|
816 | Â Â Â Â Smat =Â np.array([[TLS[18],TLS[12],TLS[13]],[TLS[14],TLS[19],TLS[15]],[TLS[16],TLS[17],0]Â ]) |
---|
817 | Â Â XYZ =Â np.inner(Amat,xyz) |
---|
818 |   Axyz = np.array([[ 0,XYZ[2],-XYZ[1]], [-XYZ[2],0,XYZ[0]], [XYZ[1],-XYZ[0],0]] ) |
---|
819 | Â Â Umat =Â Tmat+np.inner(Axyz,Smat)+np.inner(Smat.T,Axyz.T)+np.inner(np.inner(Axyz,Lmat),Axyz.T) |
---|
820 | Â Â beta =Â np.inner(np.inner(g,Umat),g) |
---|
821 |   return G2lat.UijtoU6(beta)*gvec  |
---|
822 | Â Â Â Â |
---|
823 | def AtomTLS2UIJ(atomData,atPtrs,Amat,rbObj):  #not used anywhere, but could be? |
---|
824 | Â Â '''default doc string |
---|
825 | Â Â |
---|
826 | Â Â :param type name: description |
---|
827 | Â Â |
---|
828 | Â Â :returns: type name: description |
---|
829 | Â Â |
---|
830 | Â Â ''' |
---|
831 | Â Â cx,ct,cs,cia =Â atPtrs |
---|
832 | Â Â TLStype,TLS =Â rbObj['ThermalMotion'][:2] |
---|
833 | Â Â Tmat =Â np.zeros((3,3)) |
---|
834 | Â Â Lmat =Â np.zeros((3,3)) |
---|
835 | Â Â Smat =Â np.zeros((3,3)) |
---|
836 | Â Â G,g =Â G2lat.A2Gmat(Amat) |
---|
837 | Â Â gvec =Â 1./np.sqrt(np.array([g[0][0],g[1][1],g[2][2],g[0][1],g[0][2],g[1][2]])) |
---|
838 |   if 'T' in TLStype: |
---|
839 | Â Â Â Â Tmat =Â G2lat.U6toUij(TLS[:6]) |
---|
840 |   if 'L' in TLStype: |
---|
841 | Â Â Â Â Lmat =Â G2lat.U6toUij(TLS[6:12]) |
---|
842 |   if 'S' in TLStype: |
---|
843 |     Smat = np.array([ [TLS[18],TLS[12],TLS[13]], [TLS[14],TLS[19],TLS[15]], [TLS[16],TLS[17],0] ]) |
---|
844 |   for atom in atomData: |
---|
845 | Â Â Â Â XYZ =Â np.inner(Amat,atom[cx:cx+3]) |
---|
846 |     Axyz = np.array([ 0,XYZ[2],-XYZ[1], -XYZ[2],0,XYZ[0], XYZ[1],-XYZ[0],0],ndmin=2 ) |
---|
847 |     if 'U' in TLStype: |
---|
848 | Â Â Â Â Â Â atom[cia+1]Â =Â TLS[0] |
---|
849 | Â Â Â Â Â Â atom[cia]Â =Â 'I' |
---|
850 | Â Â Â Â else: |
---|
851 | Â Â Â Â Â Â atom[cia]Â =Â 'A' |
---|
852 | Â Â Â Â Â Â Umat =Â Tmat+np.inner(Axyz,Smat)+np.inner(Smat.T,Axyz.T)+np.inner(np.inner(Axyz,Lmat),Axyz.T) |
---|
853 | Â Â Â Â Â Â beta =Â np.inner(np.inner(g,Umat),g) |
---|
854 | Â Â Â Â Â Â atom[cia+2:cia+8]Â =Â G2spc.U2Uij(beta/gvec) |
---|
855 | |
---|
856 | def GetXYZDist(xyz,XYZ,Amat): |
---|
857 | Â Â '''gets distance from position xyz to all XYZ, xyz & XYZ are np.array |
---|
858 | Â Â Â Â and are in crystal coordinates; Amat is crystal to Cart matrix |
---|
859 | Â Â |
---|
860 | Â Â :param type name: description |
---|
861 | Â Â |
---|
862 | Â Â :returns: type name: description |
---|
863 | Â Â |
---|
864 | Â Â ''' |
---|
865 |   return np.sqrt(np.sum(np.inner(Amat,XYZ-xyz)**2,axis=0)) |
---|
866 | |
---|
867 | def getAtomXYZ(atoms,cx): |
---|
868 | Â Â '''default doc string |
---|
869 | Â Â |
---|
870 | Â Â :param type name: description |
---|
871 | Â Â |
---|
872 | Â Â :returns: type name: description |
---|
873 | Â Â |
---|
874 | Â Â ''' |
---|
875 | Â Â XYZ =Â [] |
---|
876 |   for atom in atoms: |
---|
877 | Â Â Â Â XYZ.append(atom[cx:cx+3]) |
---|
878 |   return np.array(XYZ) |
---|
879 | |
---|
880 | def getRBTransMat(X,Y): |
---|
881 | Â Â '''Get transformation for Cartesian axes given 2 vectors |
---|
882 |   X will be parallel to new X-axis; X cross Y will be new Z-axis & |
---|
883 | Â Â (X cross Y) cross Y will be new Y-axis |
---|
884 | Â Â Useful for rigid body axes definintion |
---|
885 | Â Â |
---|
886 | Â Â :param array X: normalized vector |
---|
887 | Â Â :param array Y: normalized vector |
---|
888 | Â Â |
---|
889 | Â Â :returns: array M: transformation matrix |
---|
890 | Â Â |
---|
891 | Â Â use as XYZ' = np.inner(M,XYZ) where XYZ are Cartesian |
---|
892 | Â Â |
---|
893 | Â Â ''' |
---|
894 | Â Â Mat2 =Â np.cross(X,Y)Â Â Â #UxV-->Z |
---|
895 | Â Â Mat2 /=Â np.sqrt(np.sum(Mat2**2)) |
---|
896 | Â Â Mat3 =Â np.cross(Mat2,X)Â Â Â Â #(UxV)xU-->Y |
---|
897 | Â Â Mat3 /=Â np.sqrt(np.sum(Mat3**2)) |
---|
898 |   return np.array([X,Mat3,Mat2])    |
---|
899 | Â Â Â Â Â Â Â Â |
---|
900 | def RotateRBXYZ(Bmat,Cart,oriQ): |
---|
901 | Â Â '''rotate & transform cartesian coordinates to crystallographic ones |
---|
902 | Â Â no translation applied. To be used for numerical derivatives |
---|
903 | Â Â |
---|
904 | Â Â :param type name: description |
---|
905 | Â Â |
---|
906 | Â Â :returns: type name: description |
---|
907 | Â Â |
---|
908 | Â Â ''' |
---|
909 | Â Â ''' returns crystal coordinates for atoms described by RBObj |
---|
910 | Â Â ''' |
---|
911 | Â Â XYZ =Â np.zeros_like(Cart) |
---|
912 |   for i,xyz in enumerate(Cart): |
---|
913 | Â Â Â Â XYZ[i]Â =Â np.inner(Bmat,prodQVQ(oriQ,xyz)) |
---|
914 |   return XYZ |
---|
915 | |
---|
916 | def UpdateRBXYZ(Bmat,RBObj,RBData,RBType): |
---|
917 | Â Â '''default doc string |
---|
918 | Â Â |
---|
919 | Â Â :param type name: description |
---|
920 | Â Â |
---|
921 | Â Â :returns: type name: description |
---|
922 | Â Â |
---|
923 | Â Â ''' |
---|
924 | Â Â ''' returns crystal coordinates for atoms described by RBObj |
---|
925 | Â Â ''' |
---|
926 | Â Â RBRes =Â RBData[RBType][RBObj['RBId']] |
---|
927 |   if RBType == 'Vector': |
---|
928 | Â Â Â Â vecs =Â RBRes['rbVect'] |
---|
929 | Â Â Â Â mags =Â RBRes['VectMag'] |
---|
930 | Â Â Â Â Cart =Â np.zeros_like(vecs[0]) |
---|
931 |     for vec,mag in zip(vecs,mags): |
---|
932 | Â Â Â Â Â Â Cart +=Â vec*mag |
---|
933 |   elif RBType == 'Residue': |
---|
934 | Â Â Â Â Cart =Â np.array(RBRes['rbXYZ']) |
---|
935 |     for tor,seq in zip(RBObj['Torsions'],RBRes['rbSeq']): |
---|
936 | Â Â Â Â Â Â QuatA =Â AVdeg2Q(tor[0],Cart[seq[0]]-Cart[seq[1]]) |
---|
937 | Â Â Â Â Â Â Cart[seq[3]]Â =Â prodQVQ(QuatA,(Cart[seq[3]]-Cart[seq[1]]))+Cart[seq[1]] |
---|
938 | Â Â XYZ =Â np.zeros_like(Cart) |
---|
939 |   for i,xyz in enumerate(Cart): |
---|
940 | Â Â Â Â XYZ[i]Â =Â np.inner(Bmat,prodQVQ(RBObj['Orient'][0],xyz))+RBObj['Orig'][0] |
---|
941 |   return XYZ,Cart |
---|
942 | |
---|
943 | def UpdateMCSAxyz(Bmat,MCSA): |
---|
944 | Â Â '''default doc string |
---|
945 | Â Â |
---|
946 | Â Â :param type name: description |
---|
947 | Â Â |
---|
948 | Â Â :returns: type name: description |
---|
949 | Â Â |
---|
950 | Â Â ''' |
---|
951 | Â Â xyz =Â [] |
---|
952 | Â Â atTypes =Â [] |
---|
953 | Â Â iatm =Â 0 |
---|
954 |   for model in MCSA['Models'][1:]:    #skip the MD model |
---|
955 |     if model['Type'] == 'Atom': |
---|
956 | Â Â Â Â Â Â xyz.append(model['Pos'][0]) |
---|
957 | Â Â Â Â Â Â atTypes.append(model['atType']) |
---|
958 | Â Â Â Â Â Â iatm +=Â 1 |
---|
959 | Â Â Â Â else: |
---|
960 | Â Â Â Â Â Â RBRes =Â MCSA['rbData'][model['Type']][model['RBId']] |
---|
961 | Â Â Â Â Â Â Pos =Â np.array(model['Pos'][0]) |
---|
962 | Â Â Â Â Â Â Ori =Â np.array(model['Ori'][0]) |
---|
963 | Â Â Â Â Â Â Qori =Â AVdeg2Q(Ori[0],Ori[1:]) |
---|
964 |       if model['Type'] == 'Vector': |
---|
965 | Â Â Â Â Â Â Â Â vecs =Â RBRes['rbVect'] |
---|
966 | Â Â Â Â Â Â Â Â mags =Â RBRes['VectMag'] |
---|
967 | Â Â Â Â Â Â Â Â Cart =Â np.zeros_like(vecs[0]) |
---|
968 |         for vec,mag in zip(vecs,mags): |
---|
969 | Â Â Â Â Â Â Â Â Â Â Cart +=Â vec*mag |
---|
970 |       elif model['Type'] == 'Residue': |
---|
971 | Â Â Â Â Â Â Â Â Cart =Â np.array(RBRes['rbXYZ']) |
---|
972 |         for itor,seq in enumerate(RBRes['rbSeq']): |
---|
973 | Â Â Â Â Â Â Â Â Â Â QuatA =Â AVdeg2Q(model['Tor'][0][itor],Cart[seq[0]]-Cart[seq[1]]) |
---|
974 | Â Â Â Â Â Â Â Â Â Â Cart[seq[3]]Â =Â prodQVQ(QuatA,(Cart[seq[3]]-Cart[seq[1]]))+Cart[seq[1]] |
---|
975 |       if model['MolCent'][1]: |
---|
976 | Â Â Â Â Â Â Â Â Cart -=Â model['MolCent'][0] |
---|
977 |       for i,x in enumerate(Cart): |
---|
978 | Â Â Â Â Â Â Â Â xyz.append(np.inner(Bmat,prodQVQ(Qori,x))+Pos) |
---|
979 | Â Â Â Â Â Â Â Â atType =Â RBRes['rbTypes'][i] |
---|
980 | Â Â Â Â Â Â Â Â atTypes.append(atType) |
---|
981 | Â Â Â Â Â Â Â Â iatm +=Â 1 |
---|
982 |   return np.array(xyz),atTypes |
---|
983 | Â Â |
---|
984 | def SetMolCent(model,RBData): |
---|
985 | Â Â '''default doc string |
---|
986 | Â Â |
---|
987 | Â Â :param type name: description |
---|
988 | Â Â |
---|
989 | Â Â :returns: type name: description |
---|
990 | Â Â |
---|
991 | Â Â ''' |
---|
992 | Â Â rideList =Â [] |
---|
993 | Â Â RBRes =Â RBData[model['Type']][model['RBId']] |
---|
994 |   if model['Type'] == 'Vector': |
---|
995 | Â Â Â Â vecs =Â RBRes['rbVect'] |
---|
996 | Â Â Â Â mags =Â RBRes['VectMag'] |
---|
997 | Â Â Â Â Cart =Â np.zeros_like(vecs[0]) |
---|
998 |     for vec,mag in zip(vecs,mags): |
---|
999 | Â Â Â Â Â Â Cart +=Â vec*mag |
---|
1000 |   elif model['Type'] == 'Residue': |
---|
1001 | Â Â Â Â Cart =Â np.array(RBRes['rbXYZ']) |
---|
1002 |     for seq in RBRes['rbSeq']: |
---|
1003 | Â Â Â Â Â Â rideList +=Â seq[3] |
---|
1004 | Â Â centList =Â set(range(len(Cart)))-set(rideList) |
---|
1005 | Â Â cent =Â np.zeros(3) |
---|
1006 |   for i in centList: |
---|
1007 | Â Â Â Â cent +=Â Cart[i] |
---|
1008 | Â Â model['MolCent'][0]Â =Â cent/len(centList)Â Â |
---|
1009 | Â Â |
---|
1010 | def UpdateRBUIJ(Bmat,Cart,RBObj): |
---|
1011 | Â Â '''default doc string |
---|
1012 | Â Â |
---|
1013 | Â Â :param type name: description |
---|
1014 | Â Â |
---|
1015 | Â Â :returns: type name: description |
---|
1016 | Â Â |
---|
1017 | Â Â ''' |
---|
1018 | Â Â ''' returns atom I/A, Uiso or UIJ for atoms at XYZ as described by RBObj |
---|
1019 | Â Â ''' |
---|
1020 | Â Â TLStype,TLS =Â RBObj['ThermalMotion'][:2] |
---|
1021 | Â Â T =Â np.zeros(6) |
---|
1022 | Â Â L =Â np.zeros(6) |
---|
1023 | Â Â S =Â np.zeros(8) |
---|
1024 |   if 'T' in TLStype: |
---|
1025 | Â Â Â Â T =Â TLS[:6] |
---|
1026 |   if 'L' in TLStype: |
---|
1027 | Â Â Â Â L =Â np.array(TLS[6:12])*(np.pi/180.)**2 |
---|
1028 |   if 'S' in TLStype: |
---|
1029 | Â Â Â Â S =Â np.array(TLS[12:])*(np.pi/180.) |
---|
1030 | Â Â g =Â nl.inv(np.inner(Bmat,Bmat)) |
---|
1031 | Â Â gvec =Â np.sqrt(np.array([g[0][0]**2,g[1][1]**2,g[2][2]**2, |
---|
1032 | Â Â Â Â g[0][0]*g[1][1],g[0][0]*g[2][2],g[1][1]*g[2][2]])) |
---|
1033 | Â Â Uout =Â [] |
---|
1034 | Â Â Q =Â RBObj['Orient'][0] |
---|
1035 |   for X in Cart: |
---|
1036 | Â Â Â Â X =Â prodQVQ(Q,X) |
---|
1037 |     if 'U' in TLStype: |
---|
1038 | Â Â Â Â Â Â Uout.append(['I',TLS[0],0,0,0,0,0,0]) |
---|
1039 |     elif not 'N' in TLStype: |
---|
1040 | Â Â Â Â Â Â U =Â [0,0,0,0,0,0] |
---|
1041 | Â Â Â Â Â Â U[0]Â =Â T[0]+L[1]*X[2]**2+L[2]*X[1]**2-2.0*L[5]*X[1]*X[2]+2.0*(S[2]*X[2]-S[4]*X[1]) |
---|
1042 | Â Â Â Â Â Â U[1]Â =Â T[1]+L[0]*X[2]**2+L[2]*X[0]**2-2.0*L[4]*X[0]*X[2]+2.0*(S[5]*X[0]-S[0]*X[2]) |
---|
1043 | Â Â Â Â Â Â U[2]Â =Â T[2]+L[1]*X[0]**2+L[0]*X[1]**2-2.0*L[3]*X[1]*X[0]+2.0*(S[1]*X[1]-S[3]*X[0]) |
---|
1044 | Â Â Â Â Â Â U[3]Â =Â T[3]+L[4]*X[1]*X[2]+L[5]*X[0]*X[2]-L[3]*X[2]**2-L[2]*X[0]*X[1]+Â \ |
---|
1045 | Â Â Â Â Â Â Â Â S[4]*X[0]-S[5]*X[1]-(S[6]+S[7])*X[2] |
---|
1046 | Â Â Â Â Â Â U[4]Â =Â T[4]+L[3]*X[1]*X[2]+L[5]*X[0]*X[1]-L[4]*X[1]**2-L[1]*X[0]*X[2]+Â \ |
---|
1047 | Â Â Â Â Â Â Â Â S[3]*X[2]-S[2]*X[0]+S[6]*X[1] |
---|
1048 | Â Â Â Â Â Â U[5]Â =Â T[5]+L[3]*X[0]*X[2]+L[4]*X[0]*X[1]-L[5]*X[0]**2-L[0]*X[2]*X[1]+Â \ |
---|
1049 | Â Â Â Â Â Â Â Â S[0]*X[1]-S[1]*X[2]+S[7]*X[0] |
---|
1050 | Â Â Â Â Â Â Umat =Â G2lat.U6toUij(U) |
---|
1051 | Â Â Â Â Â Â beta =Â np.inner(np.inner(Bmat.T,Umat),Bmat) |
---|
1052 | Â Â Â Â Â Â Uout.append(['A',0.0,]+list(G2lat.UijtoU6(beta)*gvec)) |
---|
1053 | Â Â Â Â else: |
---|
1054 | Â Â Â Â Â Â Uout.append(['N',]) |
---|
1055 |   return Uout |
---|
1056 | Â Â |
---|
1057 | def GetSHCoeff(pId,parmDict,SHkeys): |
---|
1058 | Â Â '''default doc string |
---|
1059 | Â Â |
---|
1060 | Â Â :param type name: description |
---|
1061 | Â Â |
---|
1062 | Â Â :returns: type name: description |
---|
1063 | Â Â |
---|
1064 | Â Â ''' |
---|
1065 | Â Â SHCoeff =Â {} |
---|
1066 |   for shkey in SHkeys: |
---|
1067 | Â Â Â Â shname =Â str(pId)+'::'+shkey |
---|
1068 | Â Â Â Â SHCoeff[shkey]Â =Â parmDict[shname] |
---|
1069 |   return SHCoeff |
---|
1070 | Â Â Â Â |
---|
1071 | def getMass(generalData): |
---|
1072 | Â Â '''Computes mass of unit cell contents |
---|
1073 | Â Â |
---|
1074 | Â Â :param dict generalData: The General dictionary in Phase |
---|
1075 | Â Â |
---|
1076 | Â Â :returns: float mass: Crystal unit cell mass in AMU. |
---|
1077 | Â Â |
---|
1078 | Â Â ''' |
---|
1079 | Â Â mass =Â 0. |
---|
1080 |   for i,elem in enumerate(generalData['AtomTypes']): |
---|
1081 | Â Â Â Â mass +=Â generalData['NoAtoms'][elem]*generalData['AtomMass'][i] |
---|
1082 |   return max(mass,1.0)  |
---|
1083 | |
---|
1084 | def getDensity(generalData): |
---|
1085 | Â Â '''calculate crystal structure density |
---|
1086 | Â Â |
---|
1087 | Â Â :param dict generalData: The General dictionary in Phase |
---|
1088 | Â Â |
---|
1089 | Â Â :returns: float density: crystal density in gm/cm^3 |
---|
1090 | Â Â |
---|
1091 | Â Â ''' |
---|
1092 | Â Â mass =Â getMass(generalData) |
---|
1093 | Â Â Volume =Â generalData['Cell'][7] |
---|
1094 | Â Â density =Â mass/(0.6022137*Volume) |
---|
1095 |   return density,Volume/mass |
---|
1096 | Â Â |
---|
1097 | def getWave(Parms): |
---|
1098 | Â Â '''returns wavelength from Instrument parameters dictionary |
---|
1099 | Â Â |
---|
1100 | Â Â :param dict Parms: Instrument parameters; |
---|
1101 | Â Â Â Â must contain: |
---|
1102 | Â Â Â Â Lam: single wavelength |
---|
1103 | Â Â Â Â or |
---|
1104 | Â Â Â Â Lam1: Ka1 radiation wavelength |
---|
1105 | Â Â |
---|
1106 | Â Â :returns: float wave: wavelength |
---|
1107 | Â Â |
---|
1108 | Â Â ''' |
---|
1109 | Â Â try: |
---|
1110 |     return Parms['Lam'][1] |
---|
1111 |   except KeyError: |
---|
1112 |     return Parms['Lam1'][1] |
---|
1113 | Â Â Â Â |
---|
1114 | def getMeanWave(Parms): |
---|
1115 | Â Â '''returns mean wavelength from Instrument parameters dictionary |
---|
1116 | Â Â |
---|
1117 | Â Â :param dict Parms: Instrument parameters; |
---|
1118 | Â Â Â Â must contain: |
---|
1119 | Â Â Â Â Lam: single wavelength |
---|
1120 | Â Â Â Â or |
---|
1121 | Â Â Â Â Lam1,Lam2: Ka1,Ka2 radiation wavelength |
---|
1122 | Â Â Â Â I(L2)/I(L1): Ka2/Ka1 ratio |
---|
1123 | Â Â |
---|
1124 | Â Â :returns: float wave: mean wavelength |
---|
1125 | Â Â |
---|
1126 | Â Â ''' |
---|
1127 | Â Â try: |
---|
1128 |     return Parms['Lam'][1] |
---|
1129 |   except KeyError: |
---|
1130 | Â Â Â Â meanLam =Â (Parms['Lam1'][1]+Parms['I(L2)/I(L1)'][1]*Parms['Lam2'][1])/Â Â \ |
---|
1131 | Â Â Â Â Â Â (1.+Parms['I(L2)/I(L1)'][1]) |
---|
1132 |     return meanLam |
---|
1133 | Â Â |
---|
1134 | Â Â Â Â |
---|
1135 | def El2Mass(Elements): |
---|
1136 | Â Â '''compute molecular weight from Elements |
---|
1137 | Â Â |
---|
1138 | Â Â :param dict Elements: elements in molecular formula; |
---|
1139 | Â Â Â Â each must contain |
---|
1140 | Â Â Â Â Num: number of atoms in formula |
---|
1141 | Â Â Â Â Mass: at. wt. |
---|
1142 | Â Â |
---|
1143 | Â Â :returns: float mass: molecular weight. |
---|
1144 | Â Â |
---|
1145 | Â Â ''' |
---|
1146 | Â Â mass =Â 0 |
---|
1147 |   for El in Elements: |
---|
1148 | Â Â Â Â mass +=Â Elements[El]['Num']*Elements[El]['Mass'] |
---|
1149 |   return mass |
---|
1150 | Â Â Â Â |
---|
1151 | def Den2Vol(Elements,density): |
---|
1152 | Â Â '''converts density to molecular volume |
---|
1153 | Â Â |
---|
1154 | Â Â :param dict Elements: elements in molecular formula; |
---|
1155 | Â Â Â Â each must contain |
---|
1156 | Â Â Â Â Num: number of atoms in formula |
---|
1157 | Â Â Â Â Mass: at. wt. |
---|
1158 | Â Â :param float density: material density in gm/cm^3 |
---|
1159 | Â Â |
---|
1160 | Â Â :returns: float volume: molecular volume in A^3 |
---|
1161 | Â Â |
---|
1162 | Â Â ''' |
---|
1163 |   return El2Mass(Elements)/(density*0.6022137) |
---|
1164 | Â Â |
---|
1165 | def Vol2Den(Elements,volume): |
---|
1166 | Â Â '''converts volume to density |
---|
1167 | Â Â |
---|
1168 | Â Â :param dict Elements: elements in molecular formula; |
---|
1169 | Â Â Â Â each must contain |
---|
1170 | Â Â Â Â Num: number of atoms in formula |
---|
1171 | Â Â Â Â Mass: at. wt. |
---|
1172 | Â Â :param float volume: molecular volume in A^3 |
---|
1173 | Â Â |
---|
1174 | Â Â :returns: float density: material density in gm/cm^3 |
---|
1175 | Â Â |
---|
1176 | Â Â ''' |
---|
1177 |   return El2Mass(Elements)/(volume*0.6022137) |
---|
1178 | Â Â |
---|
1179 | def El2EstVol(Elements): |
---|
1180 | Â Â '''Estimate volume from molecular formula; assumes atom volume = 10A^3 |
---|
1181 | Â Â |
---|
1182 | Â Â :param dict Elements: elements in molecular formula; |
---|
1183 | Â Â Â Â each must contain |
---|
1184 | Â Â Â Â Num: number of atoms in formula |
---|
1185 | Â Â |
---|
1186 | Â Â :returns: float volume: estimate of molecular volume in A^3 |
---|
1187 | Â Â |
---|
1188 | Â Â ''' |
---|
1189 | Â Â vol =Â 0 |
---|
1190 |   for El in Elements: |
---|
1191 | Â Â Â Â vol +=Â 10.*Elements[El]['Num'] |
---|
1192 |   return vol |
---|
1193 | Â Â |
---|
1194 | def XScattDen(Elements,vol,wave=0.): |
---|
1195 | Â Â '''Estimate X-ray scattering density from molecular formula & volume; |
---|
1196 | Â Â ignores valence, but includes anomalous effects |
---|
1197 | Â Â |
---|
1198 | Â Â :param dict Elements: elements in molecular formula; |
---|
1199 | Â Â Â Â each element must contain |
---|
1200 | Â Â Â Â Num: number of atoms in formula |
---|
1201 | Â Â Â Â Z: atomic number |
---|
1202 | Â Â :param float vol: molecular volume in A^3 |
---|
1203 | Â Â :param float wave: optional wavelength in A |
---|
1204 | Â Â |
---|
1205 | Â Â :returns: float rho: scattering density in 10^10cm^-2; |
---|
1206 | Â Â Â Â if wave > 0 the includes f' contribution |
---|
1207 | Â Â :returns: float mu: if wave>0 absorption coeff in cm^-1 ; otherwise 0 |
---|
1208 | Â Â :returns: float fpp: if wave>0 f" in 10^10cm^-2; otherwise 0 |
---|
1209 | Â Â |
---|
1210 | Â Â ''' |
---|
1211 | Â Â rho =Â 0 |
---|
1212 | Â Â mu =Â 0 |
---|
1213 | Â Â fpp =Â 0 |
---|
1214 |   if wave: |
---|
1215 | Â Â Â Â Xanom =Â XAnomAbs(Elements,wave) |
---|
1216 |   for El in Elements: |
---|
1217 | Â Â Â Â f0 =Â Elements[El]['Z'] |
---|
1218 |     if wave: |
---|
1219 | Â Â Â Â Â Â f0 +=Â Xanom[El][0] |
---|
1220 | Â Â Â Â Â Â fpp +=Â Xanom[El][1]*Elements[El]['Num'] |
---|
1221 | Â Â Â Â Â Â mu +=Â Xanom[El][2]*Elements[El]['Num'] |
---|
1222 | Â Â Â Â rho +=Â Elements[El]['Num']*f0 |
---|
1223 |   return 28.179*rho/vol,0.1*mu/vol,28.179*fpp/vol |
---|
1224 | Â Â |
---|
1225 | def NCScattDen(Elements,vol,wave=0.): |
---|
1226 | Â Â '''Estimate neutron scattering density from molecular formula & volume; |
---|
1227 | Â Â ignores valence, but includes anomalous effects |
---|
1228 | Â Â |
---|
1229 | Â Â :param dict Elements: elements in molecular formula; |
---|
1230 | Â Â Â Â each element must contain |
---|
1231 | Â Â Â Â Num: number of atoms in formula |
---|
1232 | Â Â Â Â Z: atomic number |
---|
1233 | Â Â :param float vol: molecular volume in A^3 |
---|
1234 | Â Â :param float wave: optional wavelength in A |
---|
1235 | Â Â |
---|
1236 | Â Â :returns: float rho: scattering density in 10^10cm^-2; |
---|
1237 | Â Â Â Â if wave > 0 the includes f' contribution |
---|
1238 | Â Â :returns: float mu: if wave>0 absorption coeff in cm^-1 ; otherwise 0 |
---|
1239 | Â Â :returns: float fpp: if wave>0 f" in 10^10cm^-2; otherwise 0 |
---|
1240 | Â Â |
---|
1241 | Â Â ''' |
---|
1242 | Â Â rho =Â 0 |
---|
1243 | Â Â mu =Â 0 |
---|
1244 | Â Â bpp =Â 0 |
---|
1245 |   for El in Elements: |
---|
1246 | Â Â Â Â isotope =Â Elements[El]['Isotope'] |
---|
1247 | Â Â Â Â b0 =Â Elements[El]['Isotopes'][isotope]['SL'][0] |
---|
1248 | Â Â Â Â mu +=Â Elements[El]['Isotopes'][isotope].get('SA',0.)*Elements[El]['Num'] |
---|
1249 |     if wave and 'BW-LS' in Elements[El]['Isotopes'][isotope]: |
---|
1250 | Â Â Â Â Â Â Re,Im,E0,gam,A,E1,B,E2 =Â Elements[El]['Isotopes'][isotope]['BW-LS'][1:] |
---|
1251 | Â Â Â Â Â Â Emev =Â 81.80703/wave**2 |
---|
1252 | Â Â Â Â Â Â T0 =Â Emev-E0 |
---|
1253 | Â Â Â Â Â Â T1 =Â Emev-E1 |
---|
1254 | Â Â Â Â Â Â T2 =Â Emev-E2 |
---|
1255 | Â Â Â Â Â Â D0 =Â T0**2+gam**2 |
---|
1256 | Â Â Â Â Â Â D1 =Â T1**2+gam**2 |
---|
1257 | Â Â Â Â Â Â D2 =Â T2**2+gam**2 |
---|
1258 | Â Â Â Â Â Â b0 +=Â Re*(T0/D0+A*T1/D1+B*T2/D2) |
---|
1259 | Â Â Â Â Â Â bpp +=Â Im*(1/D0+A/D1+B/D2) |
---|
1260 | Â Â Â Â else: |
---|
1261 | Â Â Â Â Â Â bpp +=Â Elements[El]['Isotopes'][isotope]['SL'][1] |
---|
1262 | Â Â Â Â rho +=Â Elements[El]['Num']*b0 |
---|
1263 |   if wave: mu *= wave |
---|
1264 |   return 100.*rho/vol,mu/vol,100.*bpp/vol |
---|
1265 | Â Â |
---|
1266 | def wavekE(wavekE): |
---|
1267 | Â Â '''Convert wavelength to energy & vise versa |
---|
1268 | Â Â |
---|
1269 | Â Â :param float waveKe:wavelength in A or energy in kE |
---|
1270 | Â Â |
---|
1271 | Â Â :returns float waveKe:the other one |
---|
1272 | Â Â |
---|
1273 | Â Â ''' |
---|
1274 |   return 12.397639/wavekE |
---|
1275 | Â Â Â Â |
---|
1276 | def XAnomAbs(Elements,wave): |
---|
1277 | Â Â kE =Â wavekE(wave) |
---|
1278 | Â Â Xanom =Â {} |
---|
1279 |   for El in Elements: |
---|
1280 | Â Â Â Â Orbs =Â G2el.GetXsectionCoeff(El) |
---|
1281 |     Xanom[El] = G2el.FPcalc(Orbs, kE) |
---|
1282 |   return Xanom    #f',f", mu |
---|
1283 | Â Â |
---|
1284 | ################################################################################ |
---|
1285 | #### Modulation math |
---|
1286 | ################################################################################ |
---|
1287 | |
---|
1288 | def makeWaves(waveTypes,FSSdata,XSSdata,USSdata,MSSdata,Mast): |
---|
1289 | Â Â ''' |
---|
1290 | Â Â waveTypes: array nAtoms: 'Fourier','ZigZag' or 'Block' |
---|
1291 |   FSSdata: array 2 x atoms x waves  (sin,cos terms) |
---|
1292 | Â Â XSSdata: array 2x3 x atoms X waves (sin,cos terms) |
---|
1293 | Â Â USSdata: array 2x6 x atoms X waves (sin,cos terms) |
---|
1294 | Â Â MSSdata: array 2x3 x atoms X waves (sin,cos terms) |
---|
1295 | Â Â |
---|
1296 | Â Â Mast: array orthogonalization matrix for Uij |
---|
1297 | Â Â ''' |
---|
1298 | Â Â ngl =Â 36Â Â Â Â Â Â Â Â Â Â #selected for integer steps for 1/6,1/4,1/3... |
---|
1299 | Â Â glTau,glWt =Â pwd.pygauleg(0.,1.,ngl)Â Â Â Â Â #get Gauss-Legendre intervals & weights |
---|
1300 | Â Â mglTau =Â np.arange(0.,1.,1./ngl) |
---|
1301 | Â Â Ax =Â np.array(XSSdata[:3]).TÂ Â #atoms x waves x sin pos mods |
---|
1302 | Â Â Bx =Â np.array(XSSdata[3:]).TÂ Â #...cos pos mods |
---|
1303 | Â Â Af =Â np.array(FSSdata[0]).TÂ Â #sin frac mods x waves x atoms |
---|
1304 | Â Â Bf =Â np.array(FSSdata[1]).TÂ Â #cos frac mods... |
---|
1305 | Â Â Au =Â Mast*np.array(G2lat.U6toUij(USSdata[:6])).TÂ Â #atoms x waves x sin Uij mods as betaij |
---|
1306 | Â Â Bu =Â Mast*np.array(G2lat.U6toUij(USSdata[6:])).TÂ Â #...cos Uij mods as betaij |
---|
1307 | Â Â Am =Â np.array(MSSdata[:3]).TÂ Â #atoms x waves x sin pos mods |
---|
1308 | Â Â Bm =Â np.array(MSSdata[3:]).TÂ Â #...cos pos mods |
---|
1309 | Â Â nWaves =Â [Af.shape[1],Ax.shape[1],Au.shape[1],Am.shape[1]]Â |
---|
1310 |   if nWaves[0]: |
---|
1311 |     tauF = np.arange(1.,nWaves[0]+1)[:,nxs]*glTau #Fwaves x ngl |
---|
1312 | Â Â Â Â FmodA =Â Af[:,:,nxs]*np.sin(twopi*tauF[nxs,:,:])Â Â #atoms X Fwaves X ngl |
---|
1313 | Â Â Â Â FmodB =Â Bf[:,:,nxs]*np.cos(twopi*tauF[nxs,:,:]) |
---|
1314 | Â Â Â Â Fmod =Â np.sum(1.0+FmodA+FmodB,axis=1)Â Â Â Â Â Â Â #atoms X ngl; sum waves |
---|
1315 | Â Â else: |
---|
1316 | Â Â Â Â Fmod =Â 1.0Â Â Â Â Â Â |
---|
1317 | Â Â XmodZ =Â np.zeros((Ax.shape[0],Ax.shape[1],3,ngl)) |
---|
1318 | Â Â XmodA =Â np.zeros((Ax.shape[0],Ax.shape[1],3,ngl)) |
---|
1319 | Â Â XmodB =Â np.zeros((Ax.shape[0],Ax.shape[1],3,ngl)) |
---|
1320 |   for iatm in range(Ax.shape[0]): |
---|
1321 | Â Â Â Â nx =Â 0 |
---|
1322 |     if 'ZigZag' in waveTypes[iatm]: |
---|
1323 | Â Â Â Â Â Â nx =Â 1 |
---|
1324 | Â Â Â Â Â Â Tmm =Â Ax[iatm][0][:2]Â Â Â Â Â Â Â Â Â Â Â Â |
---|
1325 | Â Â Â Â Â Â XYZmax =Â np.array([Ax[iatm][0][2],Bx[iatm][0][0],Bx[iatm][0][1]]) |
---|
1326 | Â Â Â Â Â Â XmodZ[iatm][0]Â +=Â posZigZag(glTau,Tmm,XYZmax).T |
---|
1327 |     elif 'Block' in waveTypes[iatm]: |
---|
1328 | Â Â Â Â Â Â nx =Â 1 |
---|
1329 | Â Â Â Â Â Â Tmm =Â Ax[iatm][0][:2]Â Â Â Â Â Â Â Â Â Â Â Â |
---|
1330 | Â Â Â Â Â Â XYZmax =Â np.array([Ax[iatm][0][2],Bx[iatm][0][0],Bx[iatm][0][1]]) |
---|
1331 | Â Â Â Â Â Â XmodZ[iatm][0]Â +=Â posBlock(glTau,Tmm,XYZmax).T |
---|
1332 |     tauX = np.arange(1.,nWaves[1]+1-nx)[:,nxs]*glTau #Xwaves x ngl |
---|
1333 |     if nx:  |
---|
1334 | Â Â Â Â Â Â XmodA[iatm][:-nx]Â =Â Ax[iatm,nx:,:,nxs]*np.sin(twopi*tauX[nxs,:,nxs,:])Â #atoms X waves X 3 X ngl |
---|
1335 | Â Â Â Â Â Â XmodB[iatm][:-nx]Â =Â Bx[iatm,nx:,:,nxs]*np.cos(twopi*tauX[nxs,:,nxs,:])Â #ditto |
---|
1336 | Â Â Â Â else: |
---|
1337 | Â Â Â Â Â Â XmodA[iatm]Â =Â Ax[iatm,:,:,nxs]*np.sin(twopi*tauX[nxs,:,nxs,:])Â #atoms X waves X 3 X ngl |
---|
1338 | Â Â Â Â Â Â XmodB[iatm]Â =Â Bx[iatm,:,:,nxs]*np.cos(twopi*tauX[nxs,:,nxs,:])Â #ditto |
---|
1339 | Â Â Xmod =Â np.sum(XmodA+XmodB+XmodZ,axis=1)Â Â Â Â Â Â Â Â #atoms X 3 X ngl; sum waves |
---|
1340 | Â Â Xmod =Â np.swapaxes(Xmod,1,2) |
---|
1341 |   if nWaves[2]: |
---|
1342 |     tauU = np.arange(1.,nWaves[2]+1)[:,nxs]*glTau   #Uwaves x ngl |
---|
1343 | Â Â Â Â UmodA =Â Au[:,:,:,:,nxs]*np.sin(twopi*tauU[nxs,:,nxs,nxs,:])Â #atoms x waves x 3x3 x ngl |
---|
1344 | Â Â Â Â UmodB =Â Bu[:,:,:,:,nxs]*np.cos(twopi*tauU[nxs,:,nxs,nxs,:])Â #ditto |
---|
1345 | Â Â Â Â Umod =Â np.swapaxes(np.sum(UmodA+UmodB,axis=1),1,3)Â Â Â #atoms x 3x3 x ngl; sum waves |
---|
1346 | Â Â else: |
---|
1347 | Â Â Â Â Umod =Â 1.0 |
---|
1348 |   if nWaves[3]: |
---|
1349 |     tauM = np.arange(1.,nWaves[3]+1-nx)[:,nxs]*mglTau #Mwaves x ngl |
---|
1350 | Â Â Â Â MmodA =Â Am[:,:,:,nxs]*np.sin(twopi*tauM[nxs,:,nxs,:])Â #atoms X waves X 3 X ngl |
---|
1351 | Â Â Â Â MmodB =Â Bm[:,:,:,nxs]*np.cos(twopi*tauM[nxs,:,nxs,:])Â #ditto |
---|
1352 | Â Â Â Â Mmod =Â np.sum(MmodA+MmodB,axis=1) |
---|
1353 | Â Â Â Â Mmod =Â np.swapaxes(Mmod,1,2)Â Â #Mxyz,Ntau,Natm |
---|
1354 | Â Â else: |
---|
1355 | Â Â Â Â Mmod =Â 1.0 |
---|
1356 |   return ngl,nWaves,Fmod,Xmod,Umod,Mmod,glTau,glWt |
---|
1357 | |
---|
1358 | def MagMod(ngl,XYZ,modQ,MSSdata,SGData,SSGData): |
---|
1359 | Â Â ''' |
---|
1360 | Â Â this needs to make magnetic moment modulations & magnitudes as |
---|
1361 | Â Â fxn of ngl tau points |
---|
1362 | Â Â ''' |
---|
1363 | Â Â Bm =Â np.array(MSSdata[:3]).TÂ Â #atoms x waves x sin pos mods |
---|
1364 | Â Â Am =Â np.array(MSSdata[3:]).TÂ #...cos pos mods |
---|
1365 | Â Â nWaves =Â Am.shape[1] |
---|
1366 | Â Â tau =Â np.arange(ngl)/ngl |
---|
1367 |   if not nWaves: |
---|
1368 |     return 0.0,0.0 |
---|
1369 |   SGMT = np.array([ops[0] for ops in SGData['SGOps']])    #not .T!! |
---|
1370 |   Sinv = np.array([nl.inv(ops[0]) for ops in SSGData['SSGOps']]) |
---|
1371 |   SGT = np.array([ops[1] for ops in SSGData['SSGOps']]) |
---|
1372 |   if SGData['SGInv']: |
---|
1373 | Â Â Â Â SGMT =Â np.vstack((SGMT,-SGMT)) |
---|
1374 | Â Â Â Â Sinv =np.vstack((Sinv,-Sinv)) |
---|
1375 | Â Â Â Â SGT =Â np.vstack((SGT,-SGT)) |
---|
1376 |   SGMT = np.vstack([SGMT for cen in SGData['SGCen']]) |
---|
1377 |   Sinv = np.vstack([Sinv for cen in SGData['SGCen']]) |
---|
1378 |   SGT = np.vstack([SGT+cen for cen in SSGData['SSGCen']])%1. |
---|
1379 | Â Â detSM =Â nl.det(SGMT) |
---|
1380 | Â Â mst =Â Sinv[:,3,:3] |
---|
1381 | Â Â epsinv =Â Sinv[:,3,3] |
---|
1382 | Â Â phi =Â np.inner(XYZ,modQ).T |
---|
1383 | Â Â TA =Â np.sum(mst[nxs,:,:]*(XYZ-SGT[:,:3][nxs,:,:]),axis=-1).T |
---|
1384 | Â Â tauT =Â TA[nxs,:,:]Â +Â epsinv[nxs,:,nxs]*(tau[:,nxs,nxs]-SGT[:,3][nxs,:,nxs]+phi[nxs,:,:]) |
---|
1385 | Â Â modind =Â np.arange(nWaves)+1. |
---|
1386 | Â Â phase =Â (modind[:,nxs,nxs]*tauT)Â Â Â #Nops,Natm,Nwave |
---|
1387 | Â Â psin =Â np.sin(twopi*phase) |
---|
1388 | Â Â pcos =Â np.cos(twopi*phase) |
---|
1389 | Â Â MmodA =Â np.sum(Am[nxs,nxs,:,:,:]*pcos[:,:,:,nxs,nxs],axis=3) |
---|
1390 | Â Â MmodB =Â np.sum(Bm[nxs,nxs,:,:,:]*psin[:,:,:,nxs,nxs],axis=3) |
---|
1391 |   if SGData['SGGray']: |
---|
1392 | Â Â Â Â MmodA =Â -np.sum(SGMT[nxs,:,nxs,:,:]*MmodA[:,:,:,nxs,:],axis=-1)*detSM[nxs,:,nxs,nxs] |
---|
1393 | Â Â Â Â MmodB =Â -np.sum(SGMT[nxs,:,nxs,:,:]*MmodB[:,:,:,nxs,:],axis=-1)*detSM[nxs,:,nxs,nxs] |
---|
1394 | Â Â else: |
---|
1395 | Â Â Â Â MmodA =Â np.sum(SGMT[nxs,:,nxs,:,:]*MmodA[:,:,:,nxs,:],axis=-1)*SGData['MagMom'][nxs,:,nxs,nxs] |
---|
1396 | Â Â Â Â MmodB =Â np.sum(SGMT[nxs,:,nxs,:,:]*MmodB[:,:,:,nxs,:],axis=-1)*SGData['MagMom'][nxs,:,nxs,nxs] |
---|
1397 | Â Â Mmod =Â MmodA+MmodB |
---|
1398 |   return Mmod,MmodA,MmodB  #Ntau,Nops,Natm,,Mxyz; sum,Re & Im parts |
---|
1399 | Â Â Â Â |
---|
1400 | def Modulation(H,HP,nWaves,Fmod,Xmod,Umod,glTau,glWt): |
---|
1401 | Â Â ''' |
---|
1402 | Â Â H: array nRefBlk x ops X hklt |
---|
1403 | Â Â HP: array nRefBlk x ops X hklt proj to hkl |
---|
1404 | Â Â nWaves: list number of waves for frac, pos, uij & mag |
---|
1405 |   Fmod: array 2 x atoms x waves  (sin,cos terms) |
---|
1406 | Â Â Xmod: array atoms X 3 X ngl |
---|
1407 | Â Â Umod: array atoms x 3x3 x ngl |
---|
1408 | Â Â glTau,glWt: arrays Gauss-Lorentzian pos & wts |
---|
1409 | Â Â ''' |
---|
1410 | Â Â |
---|
1411 |   if nWaves[2]:    #uij (adp) waves |
---|
1412 |     if len(HP.shape) > 2: |
---|
1413 | Â Â Â Â Â Â HbH =Â np.exp(-np.sum(HP[:,:,nxs,nxs,:]*np.inner(HP,Umod),axis=-1))Â # refBlk x ops x atoms x ngl add Overhauser corr.? |
---|
1414 | Â Â Â Â else: |
---|
1415 | Â Â Â Â Â Â HbH =Â np.exp(-np.sum(HP[:,nxs,nxs,:]*np.inner(HP,Umod),axis=-1))Â # refBlk x ops x atoms x ngl add Overhauser corr.? |
---|
1416 | Â Â else: |
---|
1417 | Â Â Â Â HbH =Â 1.0 |
---|
1418 | Â Â HdotX =Â np.inner(HP,Xmod)Â Â Â Â Â Â Â Â Â Â #refBlk x ops x atoms X ngl |
---|
1419 |   if len(H.shape) > 2: |
---|
1420 | Â Â Â Â D =Â H[:,:,3:]*glTau[nxs,nxs,:]Â Â Â Â Â Â Â #m*e*tau; refBlk x ops X ngl |
---|
1421 | Â Â Â Â HdotXD =Â twopi*(HdotX+D[:,:,nxs,:]) |
---|
1422 | Â Â else: |
---|
1423 | Â Â Â Â D =Â H[:,3:]*glTau[nxs,:]Â Â Â Â Â Â Â #m*e*tau; refBlk x ops X ngl |
---|
1424 | Â Â Â Â HdotXD =Â twopi*(HdotX+D[:,nxs,:]) |
---|
1425 | Â Â cosHA =Â np.sum(Fmod*HbH*np.cos(HdotXD)*glWt,axis=-1)Â Â Â Â #real part; refBlk X ops x atoms; sum for G-L integration |
---|
1426 | Â Â sinHA =Â np.sum(Fmod*HbH*np.sin(HdotXD)*glWt,axis=-1)Â Â Â Â #imag part; ditto |
---|
1427 |   return np.array([cosHA,sinHA])       # 2 x refBlk x SGops x atoms |
---|
1428 | Â Â |
---|
1429 | def MagModulation(H,HP,nWaves,Fmod,Xmod,Umod,Mmod,glTau,glWt): |
---|
1430 | Â Â ''' |
---|
1431 | Â Â H: array nRefBlk x ops X hklt |
---|
1432 | Â Â HP: array nRefBlk x ops X hklt proj to hkl |
---|
1433 | Â Â nWaves: list number of waves for frac, pos, uij & mag |
---|
1434 |   Fmod: array 2 x atoms x waves  (sin,cos terms) |
---|
1435 | Â Â Xmod: array atoms X 3 X ngl |
---|
1436 | Â Â Umod: array atoms x 3x3 x ngl |
---|
1437 | Â Â glTau,glWt: arrays Gauss-Lorentzian pos & wts |
---|
1438 | Â Â ''' |
---|
1439 | Â Â |
---|
1440 |   if nWaves[2]:    #uij (adp) waves |
---|
1441 |     if len(HP.shape) > 2: |
---|
1442 | Â Â Â Â Â Â HbH =Â np.exp(-np.sum(HP[:,:,nxs,nxs,:]*np.inner(HP,Umod),axis=-1))Â # refBlk x ops x atoms x ngl add Overhauser corr.? |
---|
1443 | Â Â Â Â else: |
---|
1444 | Â Â Â Â Â Â HbH =Â np.exp(-np.sum(HP[:,nxs,nxs,:]*np.inner(HP,Umod),axis=-1))Â # refBlk x ops x atoms x ngl add Overhauser corr.? |
---|
1445 | Â Â else: |
---|
1446 | Â Â Â Â HbH =Â 1.0 |
---|
1447 | Â Â HdotX =Â np.inner(HP,Xmod)Â Â Â Â Â Â Â Â Â Â #refBlk x ops x atoms X ngl |
---|
1448 |   if len(H.shape) > 2: |
---|
1449 | Â Â Â Â D =Â H[:,:,3:]*glTau[nxs,nxs,:]Â Â Â Â Â Â Â #m*e*tau; refBlk x ops X ngl |
---|
1450 | Â Â Â Â HdotXD =Â twopi*(HdotX+D[:,:,nxs,:]) |
---|
1451 | Â Â else: |
---|
1452 | Â Â Â Â D =Â H[:,3:]*glTau[nxs,:]Â Â Â Â Â Â Â #m*e*tau; refBlk x ops X ngl |
---|
1453 | Â Â Â Â HdotXD =Â twopi*(HdotX+D[:,nxs,:]) |
---|
1454 | Â Â M =Â np.swapaxes(Mmod,1,2) |
---|
1455 | Â Â cosHA =Â np.sum(M[nxs,nxs,:,:,:]*(Fmod*HbH*np.cos(HdotXD)[:,:,:,nxs,:]*glWt),axis=-1)Â Â Â Â #real part; refBlk X ops x atoms; sum for G-L integration |
---|
1456 | Â Â sinHA =Â np.sum(M[nxs,nxs,:,:,:]*(Fmod*HbH*np.sin(HdotXD)[:,:,:,nxs,:]*glWt),axis=-1)Â Â Â Â #imag part; ditto |
---|
1457 |   return np.array([cosHA,sinHA])       # 2 x refBlk x SGops x atoms |
---|
1458 | |
---|
1459 | def ModulationTw(H,HP,nWaves,Fmod,Xmod,Umod,glTau,glWt): |
---|
1460 | Â Â ''' |
---|
1461 | Â Â H: array nRefBlk x tw x ops X hklt |
---|
1462 | Â Â HP: array nRefBlk x tw x ops X hklt proj to hkl |
---|
1463 |   Fmod: array 2 x atoms x waves  (sin,cos terms) |
---|
1464 | Â Â Xmod: array atoms X ngl X 3 |
---|
1465 | Â Â Umod: array atoms x ngl x 3x3 |
---|
1466 | Â Â glTau,glWt: arrays Gauss-Lorentzian pos & wts |
---|
1467 | Â Â ''' |
---|
1468 | Â Â |
---|
1469 |   if nWaves[2]: |
---|
1470 |     if len(HP.shape) > 3:  #Blocks of reflections |
---|
1471 | Â Â Â Â Â Â HbH =Â np.exp(-np.sum(HP[:,:,nxs,nxs,:]*np.inner(HP,Umod),axis=-1))Â # refBlk x ops x atoms x ngl add Overhauser corr.? |
---|
1472 | Â Â Â Â else:Â Â #single reflections |
---|
1473 | Â Â Â Â Â Â HbH =Â np.exp(-np.sum(HP[:,nxs,nxs,:]*np.inner(HP,Umod),axis=-1))Â # refBlk x ops x atoms x ngl add Overhauser corr.? |
---|
1474 | Â Â else: |
---|
1475 | Â Â Â Â HbH =Â 1.0 |
---|
1476 | Â Â HdotX =Â np.inner(HP,Xmod)Â Â Â Â Â Â Â Â Â Â #refBlk x tw x ops x atoms X ngl |
---|
1477 |   if len(H.shape) > 3: |
---|
1478 | Â Â Â Â D =Â glTau*H[:,:,:,3:,nxs]Â Â Â Â Â Â Â #m*e*tau; refBlk x tw x ops X ngl |
---|
1479 | Â Â Â Â HdotXD =Â twopi*(HdotX+D[:,:,:,nxs,:]) |
---|
1480 | Â Â else: |
---|
1481 | Â Â Â Â D =Â H*glTau[nxs,:]Â Â Â Â Â Â Â #m*e*tau; refBlk x ops X ngl |
---|
1482 | Â Â Â Â HdotXD =Â twopi*(HdotX+D[:,nxs,:]) |
---|
1483 | Â Â cosHA =Â np.sum(Fmod*HbH*np.cos(HdotXD)*glWt,axis=-1)Â Â Â Â #real part; refBlk X ops x atoms; sum for G-L integration |
---|
1484 | Â Â sinHA =Â np.sum(Fmod*HbH*np.sin(HdotXD)*glWt,axis=-1)Â Â Â Â #imag part; ditto |
---|
1485 |   return np.array([cosHA,sinHA])       # 2 x refBlk x SGops x atoms |
---|
1486 | Â Â |
---|
1487 | def makeWavesDerv(ngl,waveTypes,FSSdata,XSSdata,USSdata,Mast): |
---|
1488 | Â Â ''' |
---|
1489 | Â Â Only for Fourier waves for fraction, position & adp (probably not used for magnetism) |
---|
1490 |   FSSdata: array 2 x atoms x waves  (sin,cos terms) |
---|
1491 | Â Â XSSdata: array 2x3 x atoms X waves (sin,cos terms) |
---|
1492 | Â Â USSdata: array 2x6 x atoms X waves (sin,cos terms) |
---|
1493 | Â Â Mast: array orthogonalization matrix for Uij |
---|
1494 | Â Â ''' |
---|
1495 | Â Â glTau,glWt =Â pwd.pygauleg(0.,1.,ngl)Â Â Â Â Â #get Gauss-Legendre intervals & weights |
---|
1496 | Â Â waveShapes =Â [FSSdata.T.shape,XSSdata.T.shape,USSdata.T.shape] |
---|
1497 | Â Â Af =Â np.array(FSSdata[0]).TÂ Â #sin frac mods x waves x atoms |
---|
1498 | Â Â Bf =Â np.array(FSSdata[1]).TÂ Â #cos frac mods... |
---|
1499 | Â Â Ax =Â np.array(XSSdata[:3]).TÂ Â #...cos pos mods x waves x atoms |
---|
1500 | Â Â Bx =Â np.array(XSSdata[3:]).TÂ Â #...cos pos mods |
---|
1501 | Â Â Au =Â Mast*np.array(G2lat.U6toUij(USSdata[:6])).TÂ Â #atoms x waves x sin Uij mods |
---|
1502 | Â Â Bu =Â Mast*np.array(G2lat.U6toUij(USSdata[6:])).TÂ Â #...cos Uij mods |
---|
1503 | Â Â nWaves =Â [Af.shape[1],Ax.shape[1],Au.shape[1]]Â |
---|
1504 | Â Â StauX =Â np.zeros((Ax.shape[0],Ax.shape[1],3,ngl))Â Â #atoms x waves x 3 x ngl |
---|
1505 | Â Â CtauX =Â np.zeros((Ax.shape[0],Ax.shape[1],3,ngl)) |
---|
1506 | Â Â ZtauXt =Â np.zeros((Ax.shape[0],2,3,ngl))Â Â Â Â Â Â Â Â #atoms x Tminmax x 3 x ngl |
---|
1507 | Â Â ZtauXx =Â np.zeros((Ax.shape[0],3,ngl))Â Â Â Â Â Â Â Â #atoms x XYZmax x ngl |
---|
1508 |   for iatm in range(Ax.shape[0]): |
---|
1509 | Â Â Â Â nx =Â 0 |
---|
1510 |     if 'ZigZag' in waveTypes[iatm]: |
---|
1511 | Â Â Â Â Â Â nx =Â 1 |
---|
1512 |     elif 'Block' in waveTypes[iatm]: |
---|
1513 | Â Â Â Â Â Â nx =Â 1 |
---|
1514 |     tauX = np.arange(1.,nWaves[1]+1-nx)[:,nxs]*glTau #Xwaves x ngl |
---|
1515 |     if nx:  |
---|
1516 | Â Â Â Â Â Â StauX[iatm][nx:]Â =Â np.ones_like(Ax)[iatm,nx:,:,nxs]*np.sin(twopi*tauX)[nxs,:,nxs,:]Â Â #atoms X waves X 3(xyz) X ngl |
---|
1517 | Â Â Â Â Â Â CtauX[iatm][nx:]Â =Â np.ones_like(Bx)[iatm,nx:,:,nxs]*np.cos(twopi*tauX)[nxs,:,nxs,:]Â Â #ditto |
---|
1518 | Â Â Â Â else: |
---|
1519 | Â Â Â Â Â Â StauX[iatm]Â =Â np.ones_like(Ax)[iatm,:,:,nxs]*np.sin(twopi*tauX)[nxs,:,nxs,:]Â Â #atoms X waves X 3(xyz) X ngl |
---|
1520 | Â Â Â Â Â Â CtauX[iatm]Â =Â np.ones_like(Bx)[iatm,:,:,nxs]*np.cos(twopi*tauX)[nxs,:,nxs,:]Â Â #ditto |
---|
1521 |   if nWaves[0]: |
---|
1522 |     tauF = np.arange(1.,nWaves[0]+1)[:,nxs]*glTau #Fwaves x ngl |
---|
1523 | Â Â Â Â StauF =Â np.ones_like(Af)[:,:,nxs]*np.sin(twopi*tauF)[nxs,:,:]Â #also dFmod/dAf |
---|
1524 | Â Â Â Â CtauF =Â np.ones_like(Bf)[:,:,nxs]*np.cos(twopi*tauF)[nxs,:,:]Â #also dFmod/dBf |
---|
1525 | Â Â else: |
---|
1526 | Â Â Â Â StauF =Â 1.0 |
---|
1527 | Â Â Â Â CtauF =Â 1.0 |
---|
1528 |   if nWaves[2]: |
---|
1529 |     tauU = np.arange(1.,nWaves[2]+1)[:,nxs]*glTau   #Uwaves x ngl |
---|
1530 | Â Â Â Â StauU =Â np.ones_like(Au)[:,:,:,:,nxs]*np.sin(twopi*tauU)[nxs,:,nxs,nxs,:]Â Â #also dUmodA/dAu |
---|
1531 | Â Â Â Â CtauU =Â np.ones_like(Bu)[:,:,:,:,nxs]*np.cos(twopi*tauU)[nxs,:,nxs,nxs,:]Â Â #also dUmodB/dBu |
---|
1532 | Â Â Â Â UmodA =Â Au[:,:,:,:,nxs]*StauU #atoms x waves x 3x3 x ngl |
---|
1533 | Â Â Â Â UmodB =Â Bu[:,:,:,:,nxs]*CtauU #ditto |
---|
1534 | #derivs need to be ops x atoms x waves x 6uij; ops x atoms x waves x ngl x 6uij before sum |
---|
1535 | Â Â Â Â StauU =Â np.rollaxis(np.rollaxis(np.swapaxes(StauU,2,4),-1),-1) |
---|
1536 | Â Â Â Â CtauU =Â np.rollaxis(np.rollaxis(np.swapaxes(CtauU,2,4),-1),-1) |
---|
1537 | Â Â else: |
---|
1538 | Â Â Â Â StauU =Â 1.0 |
---|
1539 | Â Â Â Â CtauU =Â 1.0 |
---|
1540 | Â Â Â Â UmodA =Â 0. |
---|
1541 | Â Â Â Â UmodB =Â 0. |
---|
1542 |   return waveShapes,[StauF,CtauF],[StauX,CtauX,ZtauXt,ZtauXx],[StauU,CtauU],UmodA+UmodB |
---|
1543 | Â Â |
---|
1544 | def ModulationDerv(H,HP,Hij,nWaves,waveShapes,Fmod,Xmod,UmodAB,SCtauF,SCtauX,SCtauU,glTau,glWt): |
---|
1545 | Â Â ''' |
---|
1546 | Â Â Compute Fourier modulation derivatives |
---|
1547 | Â Â H: array ops X hklt proj to hkl |
---|
1548 | Â Â HP: array ops X hklt proj to hkl |
---|
1549 | Â Â Hij: array 2pi^2[a*^2h^2 b*^2k^2 c*^2l^2 a*b*hk a*c*hl b*c*kl] of projected hklm to hkl space |
---|
1550 | Â Â ''' |
---|
1551 | Â Â |
---|
1552 | Â Â Mf =Â [H.shape[0],]+list(waveShapes[0])Â Â #=[ops,atoms,waves,2] (sin+cos frac mods) |
---|
1553 | Â Â dGdMfC =Â np.zeros(Mf) |
---|
1554 | Â Â dGdMfS =Â np.zeros(Mf) |
---|
1555 | Â Â Mx =Â [H.shape[0],]+list(waveShapes[1])Â Â #=[ops,atoms,waves,6] (sin+cos pos mods) |
---|
1556 | Â Â dGdMxC =Â np.zeros(Mx) |
---|
1557 | Â Â dGdMxS =Â np.zeros(Mx) |
---|
1558 | Â Â Mu =Â [H.shape[0],]+list(waveShapes[2])Â Â #=[ops,atoms,waves,12] (sin+cos Uij mods) |
---|
1559 | Â Â dGdMuC =Â np.zeros(Mu) |
---|
1560 | Â Â dGdMuS =Â np.zeros(Mu) |
---|
1561 | Â Â |
---|
1562 | Â Â D =Â twopi*H[:,3][:,nxs]*glTau[nxs,:]Â Â Â Â Â Â Â #m*e*tau; ops X ngl |
---|
1563 | Â Â HdotX =Â twopi*np.inner(HP,Xmod)Â Â Â Â #ops x atoms X ngl |
---|
1564 | Â Â HdotXD =Â HdotX+D[:,nxs,:] |
---|
1565 |   if nWaves[2]: |
---|
1566 | Â Â Â Â Umod =Â np.swapaxes((UmodAB),2,4)Â Â Â #atoms x waves x ngl x 3x3 (symmetric so I can do this!) |
---|
1567 | Â Â Â Â HuH =Â np.sum(HP[:,nxs,nxs,nxs]*np.inner(HP,Umod),axis=-1)Â Â #ops x atoms x waves x ngl |
---|
1568 | Â Â Â Â HuH =Â np.sum(HP[:,nxs,nxs,nxs]*np.inner(HP,Umod),axis=-1)Â Â #ops x atoms x waves x ngl |
---|
1569 | Â Â Â Â HbH =Â np.exp(-np.sum(HuH,axis=-2))Â # ops x atoms x ngl; sum waves - OK vs Modulation version |
---|
1570 | #Â Â Â Â part1 = -np.exp(-HuH)*Fmod[nxs,:,nxs,:]Â Â #ops x atoms x waves x ngl |
---|
1571 |     part1 = -np.exp(-HuH)*Fmod  #ops x atoms x waves x ngl |
---|
1572 | Â Â Â Â dUdAu =Â Hij[:,nxs,nxs,nxs,:]*np.rollaxis(G2lat.UijtoU6(SCtauU[0]),0,4)[nxs,:,:,:,:]Â Â #ops x atoms x waves x ngl x 6sinUij |
---|
1573 | Â Â Â Â dUdBu =Â Hij[:,nxs,nxs,nxs,:]*np.rollaxis(G2lat.UijtoU6(SCtauU[1]),0,4)[nxs,:,:,:,:]Â Â #ops x atoms x waves x ngl x 6cosUij |
---|
1574 | Â Â Â Â dGdMuCa =Â np.sum(part1[:,:,:,:,nxs]*dUdAu*np.cos(HdotXD)[:,:,nxs,:,nxs]*glWt[nxs,nxs,nxs,:,nxs],axis=-2)Â Â #ops x atoms x waves x 6uij; G-L sum |
---|
1575 | Â Â Â Â dGdMuCb =Â np.sum(part1[:,:,:,:,nxs]*dUdBu*np.cos(HdotXD)[:,:,nxs,:,nxs]*glWt[nxs,nxs,nxs,:,nxs],axis=-2) |
---|
1576 | Â Â Â Â dGdMuC =Â np.concatenate((dGdMuCa,dGdMuCb),axis=-1)Â Â #ops x atoms x waves x 12uij |
---|
1577 | Â Â Â Â dGdMuSa =Â np.sum(part1[:,:,:,:,nxs]*dUdAu*np.sin(HdotXD)[:,:,nxs,:,nxs]*glWt[nxs,nxs,nxs,:,nxs],axis=-2)Â Â #ops x atoms x waves x 6uij; G-L sum |
---|
1578 | Â Â Â Â dGdMuSb =Â np.sum(part1[:,:,:,:,nxs]*dUdBu*np.sin(HdotXD)[:,:,nxs,:,nxs]*glWt[nxs,nxs,nxs,:,nxs],axis=-2) |
---|
1579 | Â Â Â Â dGdMuS =Â np.concatenate((dGdMuSa,dGdMuSb),axis=-1)Â Â #ops x atoms x waves x 12uij |
---|
1580 | Â Â else: |
---|
1581 | Â Â Â Â HbH =Â np.ones_like(HdotX) |
---|
1582 | Â Â dHdXA =Â twopi*HP[:,nxs,nxs,nxs,:]*np.swapaxes(SCtauX[0],-1,-2)[nxs,:,:,:,:]Â Â #ops x atoms x sine waves x ngl x xyz |
---|
1583 | Â Â dHdXB =Â twopi*HP[:,nxs,nxs,nxs,:]*np.swapaxes(SCtauX[1],-1,-2)[nxs,:,:,:,:]Â Â #ditto - cos waves |
---|
1584 | # ops x atoms x waves x 2xyz - real part - good |
---|
1585 | #Â Â dGdMxCa = -np.sum((Fmod[nxs,:,:]*HbH)[:,:,nxs,:,nxs]*(dHdXA*np.sin(HdotXD)[:,:,nxs,:,nxs])*glWt[nxs,nxs,nxs,:,nxs],axis=-2) |
---|
1586 | #Â Â dGdMxCb = -np.sum((Fmod[nxs,:,:]*HbH)[:,:,nxs,:,nxs]*(dHdXB*np.sin(HdotXD)[:,:,nxs,:,nxs])*glWt[nxs,nxs,nxs,:,nxs],axis=-2) |
---|
1587 | Â Â dGdMxCa =Â -np.sum((Fmod*HbH)[:,:,nxs,:,nxs]*(dHdXA*np.sin(HdotXD)[:,:,nxs,:,nxs])*glWt[nxs,nxs,nxs,:,nxs],axis=-2) |
---|
1588 | Â Â dGdMxCb =Â -np.sum((Fmod*HbH)[:,:,nxs,:,nxs]*(dHdXB*np.sin(HdotXD)[:,:,nxs,:,nxs])*glWt[nxs,nxs,nxs,:,nxs],axis=-2) |
---|
1589 | Â Â dGdMxC =Â np.concatenate((dGdMxCa,dGdMxCb),axis=-1) |
---|
1590 | # ops x atoms x waves x 2xyz - imag part - good |
---|
1591 | #Â Â dGdMxSa = np.sum((Fmod[nxs,:,:]*HbH)[:,:,nxs,:,nxs]*(dHdXA*np.cos(HdotXD)[:,:,nxs,:,nxs])*glWt[nxs,nxs,nxs,:,nxs],axis=-2)Â Â |
---|
1592 | #Â Â dGdMxSb = np.sum((Fmod[nxs,:,:]*HbH)[:,:,nxs,:,nxs]*(dHdXB*np.cos(HdotXD)[:,:,nxs,:,nxs])*glWt[nxs,nxs,nxs,:,nxs],axis=-2)Â Â |
---|
1593 | Â Â dGdMxSa =Â np.sum((Fmod*HbH)[:,:,nxs,:,nxs]*(dHdXA*np.cos(HdotXD)[:,:,nxs,:,nxs])*glWt[nxs,nxs,nxs,:,nxs],axis=-2)Â Â |
---|
1594 | Â Â dGdMxSb =Â np.sum((Fmod*HbH)[:,:,nxs,:,nxs]*(dHdXB*np.cos(HdotXD)[:,:,nxs,:,nxs])*glWt[nxs,nxs,nxs,:,nxs],axis=-2)Â Â |
---|
1595 | Â Â dGdMxS =Â np.concatenate((dGdMxSa,dGdMxSb),axis=-1) |
---|
1596 |   return [dGdMfC,dGdMfS],[dGdMxC,dGdMxS],[dGdMuC,dGdMuS] |
---|
1597 | Â Â Â Â |
---|
1598 | def posFourier(tau,psin,pcos): |
---|
1599 |   A = np.array([ps[:,nxs]*np.sin(2*np.pi*(i+1)*tau) for i,ps in enumerate(psin)]) |
---|
1600 |   B = np.array([pc[:,nxs]*np.cos(2*np.pi*(i+1)*tau) for i,pc in enumerate(pcos)]) |
---|
1601 |   return np.sum(A,axis=0)+np.sum(B,axis=0) |
---|
1602 | Â Â |
---|
1603 | def posZigZag(T,Tmm,Xmax): |
---|
1604 | Â Â DT =Â Tmm[1]-Tmm[0] |
---|
1605 | Â Â Su =Â 2.*Xmax/DT |
---|
1606 | Â Â Sd =Â 2.*Xmax/(1.-DT) |
---|
1607 |   A = np.array([np.where( 0.< (t-Tmm[0])%1. <= DT, -Xmax+Su*((t-Tmm[0])%1.), Xmax-Sd*((t-Tmm[1])%1.)) for t in T]) |
---|
1608 |   return A |
---|
1609 | Â Â |
---|
1610 | #def posZigZagDerv(T,Tmm,Xmax): |
---|
1611 | #Â Â DT = Tmm[1]-Tmm[0] |
---|
1612 | #Â Â Su = 2.*Xmax/DT |
---|
1613 | #Â Â Sd = 2.*Xmax/(1.-DT) |
---|
1614 | #Â Â dAdT = np.zeros((2,3,len(T))) |
---|
1615 | #Â Â dAdT[0] = np.array([np.where(Tmm[0] < t <= Tmm[1],Su*(t-Tmm[0]-1)/DT,-Sd*(t-Tmm[1])/(1.-DT)) for t in T]).T |
---|
1616 | #Â Â dAdT[1] = np.array([np.where(Tmm[0] < t <= Tmm[1],-Su*(t-Tmm[0])/DT,Sd*(t-Tmm[1])/(1.-DT)) for t in T]).T |
---|
1617 | #Â Â dAdX = np.ones(3)[:,nxs]*np.array([np.where(Tmm[0] < t%1. <= Tmm[1],-1.+2.*(t-Tmm[0])/DT,1.-2.*(t-Tmm[1])%1./DT) for t in T]) |
---|
1618 | #Â Â return dAdT,dAdX |
---|
1619 | |
---|
1620 | def posBlock(T,Tmm,Xmax): |
---|
1621 |   A = np.array([np.where(Tmm[0] < t%1. <= Tmm[1],-Xmax,Xmax) for t in T]) |
---|
1622 |   return A |
---|
1623 | Â Â |
---|
1624 | #def posBlockDerv(T,Tmm,Xmax): |
---|
1625 | #Â Â dAdT = np.zeros((2,3,len(T))) |
---|
1626 | #Â Â ind = np.searchsorted(T,Tmm) |
---|
1627 | #Â Â dAdT[0,:,ind[0]] = -Xmax/len(T) |
---|
1628 | #Â Â dAdT[1,:,ind[1]] = Xmax/len(T) |
---|
1629 | #Â Â dAdX = np.ones(3)[:,nxs]*np.array([np.where(Tmm[0] < t <= Tmm[1],-1.,1.) for t in T])Â #OK |
---|
1630 | #Â Â return dAdT,dAdX |
---|
1631 | Â Â |
---|
1632 | def fracCrenel(tau,Toff,Twid): |
---|
1633 | Â Â Tau =Â (tau-Toff)%1. |
---|
1634 | Â Â A =Â np.where(Tau<Twid,1.,0.) |
---|
1635 |   return A |
---|
1636 | Â Â |
---|
1637 | def fracFourier(tau,fsin,fcos): |
---|
1638 |   if len(fsin) == 1: |
---|
1639 | Â Â Â Â A =Â np.array([fsin[0]*np.sin(2.*np.pi*tau)]) |
---|
1640 | Â Â Â Â B =Â np.array([fcos[0]*np.cos(2.*np.pi*tau)]) |
---|
1641 | Â Â else: |
---|
1642 |     A = np.array([fs[:,nxs]*np.sin(2.*np.pi*(i+1)*tau) for i,fs in enumerate(fsin)]) |
---|
1643 |     B = np.array([fc[:,nxs]*np.cos(2.*np.pi*(i+1)*tau) for i,fc in enumerate(fcos)]) |
---|
1644 |   return np.sum(A,axis=0)+np.sum(B,axis=0) |
---|
1645 | |
---|
1646 | def ApplyModulation(data,tau): |
---|
1647 | Â Â '''Applies modulation to drawing atom positions & Uijs for given tau |
---|
1648 | Â Â ''' |
---|
1649 | Â Â generalData =Â data['General'] |
---|
1650 | Â Â cell =Â generalData['Cell'][1:7] |
---|
1651 | Â Â G,g =Â G2lat.cell2Gmat(cell) |
---|
1652 | Â Â SGData =Â generalData['SGData'] |
---|
1653 | Â Â SSGData =Â generalData['SSGData'] |
---|
1654 | Â Â cx,ct,cs,cia =Â generalData['AtomPtrs'] |
---|
1655 | Â Â drawingData =Â data['Drawing'] |
---|
1656 | Â Â modul =Â generalData['SuperVec'][0] |
---|
1657 | Â Â dcx,dct,dcs,dci =Â drawingData['atomPtrs'] |
---|
1658 | Â Â atoms =Â data['Atoms'] |
---|
1659 | Â Â drawAtoms =Â drawingData['Atoms'] |
---|
1660 | Â Â Fade =Â np.ones(len(drawAtoms)) |
---|
1661 |   for atom in atoms: |
---|
1662 | Â Â Â Â atxyz =Â np.array(atom[cx:cx+3]) |
---|
1663 | Â Â Â Â atuij =Â np.array(atom[cia+2:cia+8]) |
---|
1664 | Â Â Â Â Sfrac =Â atom[-1]['SS1']['Sfrac'] |
---|
1665 | Â Â Â Â Spos =Â atom[-1]['SS1']['Spos'] |
---|
1666 | Â Â Â Â Sadp =Â atom[-1]['SS1']['Sadp'] |
---|
1667 |     if generalData['Type'] == 'magnetic': |
---|
1668 | Â Â Â Â Â Â Smag =Â atom[-1]['SS1']['Smag'] |
---|
1669 | Â Â Â Â Â Â atmom =Â np.array(atom[cx+4:cx+7]) |
---|
1670 | Â Â Â Â indx =Â FindAtomIndexByIDs(drawAtoms,dci,[atom[cia+8],],True) |
---|
1671 |     for ind in indx: |
---|
1672 | Â Â Â Â Â Â drawatom =Â drawAtoms[ind] |
---|
1673 | Â Â Â Â Â Â opr =Â drawatom[dcs-1] |
---|
1674 | Â Â Â Â Â Â sop,ssop,icent,cent,unit =Â G2spc.OpsfromStringOps(opr,SGData,SSGData) |
---|
1675 | Â Â Â Â Â Â drxyz =Â (np.inner(sop[0],atxyz)+sop[1]+cent)*icent+np.array(unit) |
---|
1676 | Â Â Â Â Â Â tauT =Â G2spc.getTauT(tau,sop,ssop,drxyz,modul)[-1] |
---|
1677 |       tauT *= icent    #invert wave on -1 |
---|
1678 | #Â Â Â Â Â Â print(tau,tauT,opr,G2spc.MT2text(sop).replace(' ',''),G2spc.SSMT2text(ssop).replace(' ','')) |
---|
1679 | Â Â Â Â Â Â wave =Â np.zeros(3) |
---|
1680 | Â Â Â Â Â Â uwave =Â np.zeros(6) |
---|
1681 | Â Â Â Â Â Â mom =Â np.zeros(3) |
---|
1682 |       if len(Sfrac): |
---|
1683 | Â Â Â Â Â Â Â Â scof =Â [] |
---|
1684 | Â Â Â Â Â Â Â Â ccof =Â [] |
---|
1685 | Â Â Â Â Â Â Â Â waveType =Â Sfrac[0] |
---|
1686 |         for i,sfrac in enumerate(Sfrac[1:]): |
---|
1687 |           if not i and 'Crenel' in waveType: |
---|
1688 | Â Â Â Â Â Â Â Â Â Â Â Â Fade[ind]Â +=Â fracCrenel(tauT,sfrac[0][0],sfrac[0][1]) |
---|
1689 | Â Â Â Â Â Â Â Â Â Â else: |
---|
1690 | Â Â Â Â Â Â Â Â Â Â Â Â scof.append(sfrac[0][0]) |
---|
1691 | Â Â Â Â Â Â Â Â Â Â Â Â ccof.append(sfrac[0][1]) |
---|
1692 |           if len(scof): |
---|
1693 | Â Â Â Â Â Â Â Â Â Â Â Â Fade[ind]Â +=Â np.sum(fracFourier(tauT,scof,ccof))Â Â Â Â Â Â Â Â Â Â Â Â Â Â |
---|
1694 |       if len(Spos): |
---|
1695 | Â Â Â Â Â Â Â Â scof =Â [] |
---|
1696 | Â Â Â Â Â Â Â Â ccof =Â [] |
---|
1697 | Â Â Â Â Â Â Â Â waveType =Â Spos[0] |
---|
1698 |         for i,spos in enumerate(Spos[1:]): |
---|
1699 |           if waveType in ['ZigZag','Block'] and not i: |
---|
1700 | Â Â Â Â Â Â Â Â Â Â Â Â Tminmax =Â spos[0][:2] |
---|
1701 | Â Â Â Â Â Â Â Â Â Â Â Â XYZmax =Â np.array(spos[0][2:5]) |
---|
1702 |             if waveType == 'Block': |
---|
1703 | Â Â Â Â Â Â Â Â Â Â Â Â Â Â wave =Â np.array(posBlock([tauT,],Tminmax,XYZmax))[0] |
---|
1704 |             elif waveType == 'ZigZag': |
---|
1705 | Â Â Â Â Â Â Â Â Â Â Â Â Â Â wave =Â np.array(posZigZag([tauT,],Tminmax,XYZmax))[0] |
---|
1706 | Â Â Â Â Â Â Â Â Â Â else: |
---|
1707 | Â Â Â Â Â Â Â Â Â Â Â Â scof.append(spos[0][:3]) |
---|
1708 | Â Â Â Â Â Â Â Â Â Â Â Â ccof.append(spos[0][3:]) |
---|
1709 |         if len(scof): |
---|
1710 | Â Â Â Â Â Â Â Â Â Â wave +=Â np.sum(posFourier(tauT,np.array(scof),np.array(ccof)),axis=1) |
---|
1711 |       if generalData['Type'] == 'magnetic' and len(Smag): |
---|
1712 | Â Â Â Â Â Â Â Â scof =Â [] |
---|
1713 | Â Â Â Â Â Â Â Â ccof =Â [] |
---|
1714 | Â Â Â Â Â Â Â Â waveType =Â Smag[0] |
---|
1715 |         for i,spos in enumerate(Smag[1:]): |
---|
1716 | Â Â Â Â Â Â Â Â Â Â scof.append(spos[0][:3]) |
---|
1717 | Â Â Â Â Â Â Â Â Â Â ccof.append(spos[0][3:]) |
---|
1718 |         if len(scof): |
---|
1719 | Â Â Â Â Â Â Â Â Â Â mom +=Â np.sum(posFourier(tauT,np.array(scof),np.array(ccof)),axis=1) |
---|
1720 |       if len(Sadp): |
---|
1721 | Â Â Â Â Â Â Â Â scof =Â [] |
---|
1722 | Â Â Â Â Â Â Â Â ccof =Â [] |
---|
1723 | Â Â Â Â Â Â Â Â waveType =Â Sadp[0] |
---|
1724 |         for i,sadp in enumerate(Sadp[1:]): |
---|
1725 | Â Â Â Â Â Â Â Â Â Â scof.append(sadp[0][:6]) |
---|
1726 | Â Â Â Â Â Â Â Â Â Â ccof.append(sadp[0][6:]) |
---|
1727 | Â Â Â Â Â Â Â Â ures =Â posFourier(tauT,np.array(scof),np.array(ccof)) |
---|
1728 |         if np.any(ures): |
---|
1729 | Â Â Â Â Â Â Â Â Â Â uwave +=Â np.sum(ures,axis=1) |
---|
1730 |       if atom[cia] == 'A':          |
---|
1731 | Â Â Â Â Â Â Â Â X,U =Â G2spc.ApplyStringOps(opr,SGData,atxyz+wave,atuij+uwave) |
---|
1732 | Â Â Â Â Â Â Â Â drawatom[dcx:dcx+3]Â =Â X |
---|
1733 | Â Â Â Â Â Â Â Â drawatom[dci-6:dci]Â =Â U |
---|
1734 | Â Â Â Â Â Â else: |
---|
1735 | Â Â Â Â Â Â Â Â X =Â G2spc.ApplyStringOps(opr,SGData,atxyz+wave) |
---|
1736 | Â Â Â Â Â Â Â Â drawatom[dcx:dcx+3]Â =Â X |
---|
1737 |       if generalData['Type'] == 'magnetic': |
---|
1738 | Â Â Â Â Â Â Â Â M =Â G2spc.ApplyStringOpsMom(opr,SGData,atmom+mom) |
---|
1739 | Â Â Â Â Â Â Â Â drawatom[dcx+3:dcx+6]Â =Â M |
---|
1740 |   return drawAtoms,Fade |
---|
1741 | Â Â |
---|
1742 | # gauleg.py Gauss Legendre numerical quadrature, x and w computation |
---|
1743 | # integrate from a to b using n evaluations of the function f(x)Â |
---|
1744 | # usage: from gauleg import gaulegf     |
---|
1745 | #Â Â Â Â x,w = gaulegf( a, b, n)Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â |
---|
1746 | #Â Â Â Â area = 0.0Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â |
---|
1747 | #    for i in range(1,n+1):     # yes, 1..n          |
---|
1748 | #Â Â Â Â Â area += w[i]*f(x[i])Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â |
---|
1749 | |
---|
1750 | def gaulegf(a, b, n): |
---|
1751 | Â Â x =Â range(n+1)Â # x[0] unused |
---|
1752 | Â Â w =Â range(n+1)Â # w[0] unused |
---|
1753 | Â Â eps =Â 3.0E-14 |
---|
1754 | Â Â m =Â (n+1)/2 |
---|
1755 | Â Â xm =Â 0.5*(b+a) |
---|
1756 | Â Â xl =Â 0.5*(b-a) |
---|
1757 |   for i in range(1,m+1): |
---|
1758 | Â Â Â Â z =Â math.cos(3.141592654*(i-0.25)/(n+0.5)) |
---|
1759 |     while True: |
---|
1760 | Â Â Â Â Â Â p1 =Â 1.0 |
---|
1761 | Â Â Â Â Â Â p2 =Â 0.0 |
---|
1762 |       for j in range(1,n+1): |
---|
1763 | Â Â Â Â Â Â Â Â p3 =Â p2 |
---|
1764 | Â Â Â Â Â Â Â Â p2 =Â p1 |
---|
1765 | Â Â Â Â Â Â Â Â p1 =Â ((2.0*j-1.0)*z*p2-(j-1.0)*p3)/j |
---|
1766 | Â Â Â Â |
---|
1767 | Â Â Â Â Â Â pp =Â n*(z*p1-p2)/(z*z-1.0) |
---|
1768 | Â Â Â Â Â Â z1 =Â z |
---|
1769 | Â Â Â Â Â Â z =Â z1 -Â p1/pp |
---|
1770 |       if abs(z-z1) <= eps: |
---|
1771 | Â Â Â Â Â Â Â Â break |
---|
1772 | |
---|
1773 | Â Â Â Â x[i]Â =Â xm -Â xl*z |
---|
1774 | Â Â Â Â x[n+1-i]Â =Â xm +Â xl*z |
---|
1775 | Â Â Â Â w[i]Â =Â 2.0*xl/((1.0-z*z)*pp*pp) |
---|
1776 | Â Â Â Â w[n+1-i]Â =Â w[i] |
---|
1777 |   return np.array(x), np.array(w) |
---|
1778 | # end gaulegf |
---|
1779 | Â Â |
---|
1780 | Â Â |
---|
1781 | def BessJn(nmax,x): |
---|
1782 | Â Â ''' compute Bessel function J(n,x) from scipy routine & recurrance relation |
---|
1783 | Â Â returns sequence of J(n,x) for n in range [-nmax...0...nmax] |
---|
1784 | Â Â |
---|
1785 |   :param integer nmax: maximul order for Jn(x) |
---|
1786 |   :param float x: argument for Jn(x) |
---|
1787 | Â Â |
---|
1788 | Â Â :returns numpy array: [J(-nmax,x)...J(0,x)...J(nmax,x)] |
---|
1789 | Â Â |
---|
1790 | Â Â ''' |
---|
1791 |   import scipy.special as sp |
---|
1792 | Â Â bessJn =Â np.zeros(2*nmax+1) |
---|
1793 | Â Â bessJn[nmax]Â =Â sp.j0(x) |
---|
1794 | Â Â bessJn[nmax+1]Â =Â sp.j1(x) |
---|
1795 | Â Â bessJn[nmax-1]Â =Â -bessJn[nmax+1] |
---|
1796 |   for i in range(2,nmax+1): |
---|
1797 | Â Â Â Â bessJn[i+nmax]Â =Â 2*(i-1)*bessJn[nmax+i-1]/x-bessJn[nmax+i-2] |
---|
1798 | Â Â Â Â bessJn[nmax-i]Â =Â bessJn[i+nmax]*(-1)**i |
---|
1799 |   return bessJn |
---|
1800 | Â Â |
---|
1801 | def BessIn(nmax,x): |
---|
1802 | Â Â ''' compute modified Bessel function I(n,x) from scipy routines & recurrance relation |
---|
1803 | Â Â returns sequence of I(n,x) for n in range [-nmax...0...nmax] |
---|
1804 | Â Â |
---|
1805 |   :param integer nmax: maximul order for In(x) |
---|
1806 |   :param float x: argument for In(x) |
---|
1807 | Â Â |
---|
1808 | Â Â :returns numpy array: [I(-nmax,x)...I(0,x)...I(nmax,x)] |
---|
1809 | Â Â |
---|
1810 | Â Â ''' |
---|
1811 |   import scipy.special as sp |
---|
1812 | Â Â bessIn =Â np.zeros(2*nmax+1) |
---|
1813 | Â Â bessIn[nmax]Â =Â sp.i0(x) |
---|
1814 | Â Â bessIn[nmax+1]Â =Â sp.i1(x) |
---|
1815 | Â Â bessIn[nmax-1]Â =Â bessIn[nmax+1] |
---|
1816 |   for i in range(2,nmax+1): |
---|
1817 | Â Â Â Â bessIn[i+nmax]Â =Â bessIn[nmax+i-2]-2*(i-1)*bessIn[nmax+i-1]/x |
---|
1818 | Â Â Â Â bessIn[nmax-i]Â =Â bessIn[i+nmax] |
---|
1819 |   return bessIn |
---|
1820 | Â Â Â Â |
---|
1821 | Â Â |
---|
1822 | ################################################################################ |
---|
1823 | ##### distance, angle, planes, torsion stuff |
---|
1824 | ################################################################################ |
---|
1825 | |
---|
1826 | def CalcDist(distance_dict, distance_atoms, parmDict): |
---|
1827 |   if not len(parmDict): |
---|
1828 |     return 0. |
---|
1829 | Â Â pId =Â distance_dict['pId'] |
---|
1830 |   A = [parmDict['%s::A%d'%(pId,i)] for i in range(6)] |
---|
1831 | Â Â Amat =Â G2lat.cell2AB(G2lat.A2cell(A))[0] |
---|
1832 |   Oxyz = [parmDict['%s::A%s:%d'%(pId,x,distance_atoms[0])] for x in ['x','y','z']] |
---|
1833 |   Txyz = [parmDict['%s::A%s:%d'%(pId,x,distance_atoms[1])] for x in ['x','y','z']] |
---|
1834 | Â Â inv =Â 1 |
---|
1835 | Â Â symNo =Â distance_dict['symNo'] |
---|
1836 |   if symNo < 0: |
---|
1837 | Â Â Â Â inv =Â -1 |
---|
1838 | Â Â Â Â symNo *=Â -1 |
---|
1839 | Â Â cen =Â symNo//100 |
---|
1840 | Â Â op =Â symNo%100-1 |
---|
1841 | Â Â M,T =Â distance_dict['SGData']['SGOps'][op] |
---|
1842 | Â Â D =Â T*inv+distance_dict['SGData']['SGCen'][cen] |
---|
1843 | Â Â D +=Â distance_dict['cellNo'] |
---|
1844 | Â Â Txyz =Â np.inner(M*inv,Txyz)+D |
---|
1845 | Â Â dist =Â np.sqrt(np.sum(np.inner(Amat,(Txyz-Oxyz))**2)) |
---|
1846 | #Â Â GSASIIpath.IPyBreak() |
---|
1847 |   return dist  |
---|
1848 | Â Â |
---|
1849 | def CalcDistDeriv(distance_dict, distance_atoms, parmDict): |
---|
1850 |   if not len(parmDict): |
---|
1851 |     return None |
---|
1852 | Â Â pId =Â distance_dict['pId'] |
---|
1853 |   A = [parmDict['%s::A%d'%(pId,i)] for i in range(6)] |
---|
1854 | Â Â Amat =Â G2lat.cell2AB(G2lat.A2cell(A))[0] |
---|
1855 |   Oxyz = [parmDict['%s::A%s:%d'%(pId,x,distance_atoms[0])] for x in ['x','y','z']] |
---|
1856 |   Txyz = [parmDict['%s::A%s:%d'%(pId,x,distance_atoms[1])] for x in ['x','y','z']] |
---|
1857 | Â Â symNo =Â distance_dict['symNo'] |
---|
1858 | Â Â Tunit =Â distance_dict['cellNo'] |
---|
1859 | Â Â SGData =Â distance_dict['SGData']Â Â |
---|
1860 | Â Â deriv =Â getDistDerv(Oxyz,Txyz,Amat,Tunit,symNo,SGData) |
---|
1861 |   return deriv |
---|
1862 | Â Â |
---|
1863 | def CalcAngle(angle_dict, angle_atoms, parmDict): |
---|
1864 |   if not len(parmDict): |
---|
1865 |     return 0. |
---|
1866 | Â Â pId =Â angle_dict['pId'] |
---|
1867 |   A = [parmDict['%s::A%d'%(pId,i)] for i in range(6)] |
---|
1868 | Â Â Amat =Â G2lat.cell2AB(G2lat.A2cell(A))[0] |
---|
1869 |   Oxyz = [parmDict['%s::A%s:%d'%(pId,x,angle_atoms[0])] for x in ['x','y','z']] |
---|
1870 |   Axyz = [parmDict['%s::A%s:%d'%(pId,x,angle_atoms[1][0])] for x in ['x','y','z']] |
---|
1871 |   Bxyz = [parmDict['%s::A%s:%d'%(pId,x,angle_atoms[1][1])] for x in ['x','y','z']] |
---|
1872 | Â Â ABxyz =Â [Axyz,Bxyz] |
---|
1873 | Â Â symNo =Â angle_dict['symNo'] |
---|
1874 | Â Â vec =Â np.zeros((2,3)) |
---|
1875 |   for i in range(2): |
---|
1876 | Â Â Â Â inv =Â 1 |
---|
1877 |     if symNo[i] < 0: |
---|
1878 | Â Â Â Â Â Â inv =Â -1 |
---|
1879 | Â Â Â Â cen =Â inv*symNo[i]//100 |
---|
1880 | Â Â Â Â op =Â inv*symNo[i]%100-1 |
---|
1881 | Â Â Â Â M,T =Â angle_dict['SGData']['SGOps'][op] |
---|
1882 | Â Â Â Â D =Â T*inv+angle_dict['SGData']['SGCen'][cen] |
---|
1883 | Â Â Â Â D +=Â angle_dict['cellNo'][i] |
---|
1884 | Â Â Â Â ABxyz[i]Â =Â np.inner(M*inv,ABxyz[i])+D |
---|
1885 | Â Â Â Â vec[i]Â =Â np.inner(Amat,(ABxyz[i]-Oxyz)) |
---|
1886 | Â Â Â Â dist =Â np.sqrt(np.sum(vec[i]**2)) |
---|
1887 |     if not dist: |
---|
1888 |       return 0. |
---|
1889 | Â Â Â Â vec[i]Â /=Â dist |
---|
1890 | Â Â angle =Â acosd(np.sum(vec[0]*vec[1])) |
---|
1891 | #Â Â GSASIIpath.IPyBreak() |
---|
1892 |   return angle |
---|
1893 | |
---|
1894 | def CalcAngleDeriv(angle_dict, angle_atoms, parmDict): |
---|
1895 |   if not len(parmDict): |
---|
1896 |     return None |
---|
1897 | Â Â pId =Â angle_dict['pId'] |
---|
1898 |   A = [parmDict['%s::A%d'%(pId,i)] for i in range(6)] |
---|
1899 | Â Â Amat =Â G2lat.cell2AB(G2lat.A2cell(A))[0] |
---|
1900 |   Oxyz = [parmDict['%s::A%s:%d'%(pId,x,angle_atoms[0])] for x in ['x','y','z']] |
---|
1901 |   Axyz = [parmDict['%s::A%s:%d'%(pId,x,angle_atoms[1][0])] for x in ['x','y','z']] |
---|
1902 |   Bxyz = [parmDict['%s::A%s:%d'%(pId,x,angle_atoms[1][1])] for x in ['x','y','z']] |
---|
1903 | Â Â symNo =Â angle_dict['symNo'] |
---|
1904 | Â Â Tunit =Â angle_dict['cellNo'] |
---|
1905 | Â Â SGData =Â angle_dict['SGData']Â Â |
---|
1906 | Â Â deriv =Â getAngleDerv(Oxyz,Axyz,Bxyz,Amat,Tunit,symNo,SGData) |
---|
1907 |   return deriv |
---|
1908 | |
---|
1909 | def getSyXYZ(XYZ,ops,SGData): |
---|
1910 | Â Â '''default doc |
---|
1911 | Â Â |
---|
1912 | Â Â :param type name: description |
---|
1913 | Â Â |
---|
1914 | Â Â :returns: type name: description |
---|
1915 | Â Â |
---|
1916 | Â Â ''' |
---|
1917 | Â Â XYZout =Â np.zeros_like(XYZ) |
---|
1918 |   for i,[xyz,op] in enumerate(zip(XYZ,ops)): |
---|
1919 |     if op == '1': |
---|
1920 | Â Â Â Â Â Â XYZout[i]Â =Â xyz |
---|
1921 | Â Â Â Â else: |
---|
1922 | Â Â Â Â Â Â oprs =Â op.split('+') |
---|
1923 | Â Â Â Â Â Â unit =Â [0,0,0] |
---|
1924 |       if len(oprs)>1: |
---|
1925 | Â Â Â Â Â Â Â Â unit =Â np.array(list(eval(oprs[1]))) |
---|
1926 | Â Â Â Â Â Â syop =int(oprs[0]) |
---|
1927 | Â Â Â Â Â Â inv =Â syop//abs(syop) |
---|
1928 | Â Â Â Â Â Â syop *=Â inv |
---|
1929 | Â Â Â Â Â Â cent =Â syop//100 |
---|
1930 | Â Â Â Â Â Â syop %=Â 100 |
---|
1931 | Â Â Â Â Â Â syop -=Â 1 |
---|
1932 | Â Â Â Â Â Â M,T =Â SGData['SGOps'][syop] |
---|
1933 | Â Â Â Â Â Â XYZout[i]Â =Â (np.inner(M,xyz)+T)*inv+SGData['SGCen'][cent]+unit |
---|
1934 |   return XYZout |
---|
1935 | Â Â |
---|
1936 | def getRestDist(XYZ,Amat): |
---|
1937 | Â Â '''default doc string |
---|
1938 | Â Â |
---|
1939 | Â Â :param type name: description |
---|
1940 | Â Â |
---|
1941 | Â Â :returns: type name: description |
---|
1942 | Â Â |
---|
1943 | Â Â ''' |
---|
1944 |   return np.sqrt(np.sum(np.inner(Amat,(XYZ[1]-XYZ[0]))**2)) |
---|
1945 | Â Â |
---|
1946 | def getRestDeriv(Func,XYZ,Amat,ops,SGData): |
---|
1947 | Â Â '''default doc string |
---|
1948 | Â Â |
---|
1949 | Â Â :param type name: description |
---|
1950 | Â Â |
---|
1951 | Â Â :returns: type name: description |
---|
1952 | Â Â |
---|
1953 | Â Â ''' |
---|
1954 | Â Â deriv =Â np.zeros((len(XYZ),3)) |
---|
1955 | Â Â dx =Â 0.00001 |
---|
1956 |   for j,xyz in enumerate(XYZ): |
---|
1957 |     for i,x in enumerate(np.array([[dx,0,0],[0,dx,0],[0,0,dx]])): |
---|
1958 | Â Â Â Â Â Â XYZ[j]Â -=Â x |
---|
1959 | Â Â Â Â Â Â d1 =Â Func(getSyXYZ(XYZ,ops,SGData),Amat) |
---|
1960 | Â Â Â Â Â Â XYZ[j]Â +=Â 2*x |
---|
1961 | Â Â Â Â Â Â d2 =Â Func(getSyXYZ(XYZ,ops,SGData),Amat) |
---|
1962 | Â Â Â Â Â Â XYZ[j]Â -=Â x |
---|
1963 | Â Â Â Â Â Â deriv[j][i]Â =Â (d1-d2)/(2*dx) |
---|
1964 |   return deriv.flatten() |
---|
1965 | |
---|
1966 | def getRestAngle(XYZ,Amat): |
---|
1967 | Â Â '''default doc string |
---|
1968 | Â Â |
---|
1969 | Â Â :param type name: description |
---|
1970 | Â Â |
---|
1971 | Â Â :returns: type name: description |
---|
1972 | Â Â |
---|
1973 | Â Â ''' |
---|
1974 | Â Â |
---|
1975 |   def calcVec(Ox,Tx,Amat): |
---|
1976 |     return np.inner(Amat,(Tx-Ox)) |
---|
1977 | |
---|
1978 | Â Â VecA =Â calcVec(XYZ[1],XYZ[0],Amat) |
---|
1979 | Â Â VecA /=Â np.sqrt(np.sum(VecA**2)) |
---|
1980 | Â Â VecB =Â calcVec(XYZ[1],XYZ[2],Amat) |
---|
1981 | Â Â VecB /=Â np.sqrt(np.sum(VecB**2)) |
---|
1982 | Â Â edge =Â VecB-VecA |
---|
1983 | Â Â edge =Â np.sum(edge**2) |
---|
1984 | Â Â angle =Â (2.-edge)/2. |
---|
1985 | Â Â angle =Â max(angle,-1.) |
---|
1986 |   return acosd(angle) |
---|
1987 | Â Â |
---|
1988 | def getRestPlane(XYZ,Amat): |
---|
1989 | Â Â '''default doc string |
---|
1990 | Â Â |
---|
1991 | Â Â :param type name: description |
---|
1992 | Â Â |
---|
1993 | Â Â :returns: type name: description |
---|
1994 | Â Â |
---|
1995 | Â Â ''' |
---|
1996 | Â Â sumXYZ =Â np.zeros(3) |
---|
1997 |   for xyz in XYZ: |
---|
1998 | Â Â Â Â sumXYZ +=Â xyz |
---|
1999 | Â Â sumXYZ /=Â len(XYZ) |
---|
2000 | Â Â XYZ =Â np.array(XYZ)-sumXYZ |
---|
2001 | Â Â XYZ =Â np.inner(Amat,XYZ).T |
---|
2002 | Â Â Zmat =Â np.zeros((3,3)) |
---|
2003 |   for i,xyz in enumerate(XYZ): |
---|
2004 | Â Â Â Â Zmat +=Â np.outer(xyz.T,xyz) |
---|
2005 | Â Â Evec,Emat =Â nl.eig(Zmat) |
---|
2006 | Â Â Evec =Â np.sqrt(Evec)/(len(XYZ)-3) |
---|
2007 | Â Â Order =Â np.argsort(Evec) |
---|
2008 |   return Evec[Order[0]] |
---|
2009 | Â Â |
---|
2010 | def getRestChiral(XYZ,Amat):  |
---|
2011 | Â Â '''default doc string |
---|
2012 | Â Â |
---|
2013 | Â Â :param type name: description |
---|
2014 | Â Â |
---|
2015 | Â Â :returns: type name: description |
---|
2016 | Â Â |
---|
2017 | Â Â ''' |
---|
2018 | Â Â VecA =Â np.empty((3,3))Â Â |
---|
2019 | Â Â VecA[0]Â =Â np.inner(XYZ[1]-XYZ[0],Amat) |
---|
2020 | Â Â VecA[1]Â =Â np.inner(XYZ[2]-XYZ[0],Amat) |
---|
2021 | Â Â VecA[2]Â =Â np.inner(XYZ[3]-XYZ[0],Amat) |
---|
2022 |   return nl.det(VecA) |
---|
2023 | Â Â |
---|
2024 | def getRestTorsion(XYZ,Amat): |
---|
2025 | Â Â '''default doc string |
---|
2026 | Â Â |
---|
2027 | Â Â :param type name: description |
---|
2028 | Â Â |
---|
2029 | Â Â :returns: type name: description |
---|
2030 | Â Â |
---|
2031 | Â Â ''' |
---|
2032 | Â Â VecA =Â np.empty((3,3)) |
---|
2033 | Â Â VecA[0]Â =Â np.inner(XYZ[1]-XYZ[0],Amat) |
---|
2034 | Â Â VecA[1]Â =Â np.inner(XYZ[2]-XYZ[1],Amat) |
---|
2035 | Â Â VecA[2]Â =Â np.inner(XYZ[3]-XYZ[2],Amat) |
---|
2036 | Â Â D =Â nl.det(VecA) |
---|
2037 | Â Â Mag =Â np.sqrt(np.sum(VecA*VecA,axis=1)) |
---|
2038 | Â Â P12 =Â np.sum(VecA[0]*VecA[1])/(Mag[0]*Mag[1]) |
---|
2039 | Â Â P13 =Â np.sum(VecA[0]*VecA[2])/(Mag[0]*Mag[2]) |
---|
2040 | Â Â P23 =Â np.sum(VecA[1]*VecA[2])/(Mag[1]*Mag[2]) |
---|
2041 | Â Â Ang =Â 1.0 |
---|
2042 |   if abs(P12) < 1.0 and abs(P23) < 1.0: |
---|
2043 | Â Â Â Â Ang =Â (P12*P23-P13)/(np.sqrt(1.-P12**2)*np.sqrt(1.-P23**2)) |
---|
2044 | Â Â TOR =Â (acosd(Ang)*D/abs(D)+720.)%360. |
---|
2045 |   return TOR |
---|
2046 | Â Â |
---|
2047 | def calcTorsionEnergy(TOR,Coeff=[]): |
---|
2048 | Â Â '''default doc string |
---|
2049 | Â Â |
---|
2050 | Â Â :param type name: description |
---|
2051 | Â Â |
---|
2052 | Â Â :returns: type name: description |
---|
2053 | Â Â |
---|
2054 | Â Â ''' |
---|
2055 |   sum = 0. |
---|
2056 |   if len(Coeff): |
---|
2057 | Â Â Â Â cof =Â np.reshape(Coeff,(3,3)).T |
---|
2058 | Â Â Â Â delt =Â TOR-cof[1] |
---|
2059 | Â Â Â Â delt =Â np.where(delt<-180.,delt+360.,delt) |
---|
2060 | Â Â Â Â delt =Â np.where(delt>180.,delt-360.,delt) |
---|
2061 | Â Â Â Â term =Â -cof[2]*delt**2 |
---|
2062 | Â Â Â Â val =Â cof[0]*np.exp(term/1000.0) |
---|
2063 | Â Â Â Â pMax =Â cof[0][np.argmin(val)] |
---|
2064 | Â Â Â Â Eval =Â np.sum(val) |
---|
2065 |     sum = Eval-pMax |
---|
2066 |   return sum,Eval |
---|
2067 | |
---|
2068 | def getTorsionDeriv(XYZ,Amat,Coeff): |
---|
2069 | Â Â '''default doc string |
---|
2070 | Â Â |
---|
2071 | Â Â :param type name: description |
---|
2072 | Â Â |
---|
2073 | Â Â :returns: type name: description |
---|
2074 | Â Â |
---|
2075 | Â Â ''' |
---|
2076 | Â Â deriv =Â np.zeros((len(XYZ),3)) |
---|
2077 | Â Â dx =Â 0.00001 |
---|
2078 |   for j,xyz in enumerate(XYZ): |
---|
2079 |     for i,x in enumerate(np.array([[dx,0,0],[0,dx,0],[0,0,dx]])): |
---|
2080 | Â Â Â Â Â Â XYZ[j]Â -=Â x |
---|
2081 | Â Â Â Â Â Â tor =Â getRestTorsion(XYZ,Amat) |
---|
2082 | Â Â Â Â Â Â p1,d1 =Â calcTorsionEnergy(tor,Coeff) |
---|
2083 | Â Â Â Â Â Â XYZ[j]Â +=Â 2*x |
---|
2084 | Â Â Â Â Â Â tor =Â getRestTorsion(XYZ,Amat) |
---|
2085 | Â Â Â Â Â Â p2,d2 =Â calcTorsionEnergy(tor,Coeff)Â Â Â Â Â Â |
---|
2086 | Â Â Â Â Â Â XYZ[j]Â -=Â x |
---|
2087 | Â Â Â Â Â Â deriv[j][i]Â =Â (p2-p1)/(2*dx) |
---|
2088 |   return deriv.flatten() |
---|
2089 | |
---|
2090 | def getRestRama(XYZ,Amat): |
---|
2091 | Â Â '''Computes a pair of torsion angles in a 5 atom string |
---|
2092 | Â Â |
---|
2093 | Â Â :param nparray XYZ: crystallographic coordinates of 5 atoms |
---|
2094 | Â Â :param nparray Amat: crystal to cartesian transformation matrix |
---|
2095 | Â Â |
---|
2096 | Â Â :returns: list (phi,psi) two torsion angles in degrees |
---|
2097 | Â Â |
---|
2098 | Â Â ''' |
---|
2099 | Â Â phi =Â getRestTorsion(XYZ[:5],Amat) |
---|
2100 | Â Â psi =Â getRestTorsion(XYZ[1:],Amat) |
---|
2101 |   return phi,psi |
---|
2102 | Â Â |
---|
2103 | def calcRamaEnergy(phi,psi,Coeff=[]): |
---|
2104 | Â Â '''Computes pseudo potential energy from a pair of torsion angles and a |
---|
2105 | Â Â numerical description of the potential energy surface. Used to create |
---|
2106 | Â Â penalty function in LS refinement:Â Â Â |
---|
2107 | Â Â :math:`Eval(\\phi,\\psi) = C[0]*exp(-V/1000)` |
---|
2108 | |
---|
2109 | Â Â where :math:`V = -C[3] * (\\phi-C[1])^2 - C[4]*(\\psi-C[2])^2 - 2*(\\phi-C[1])*(\\psi-C[2])` |
---|
2110 | Â Â |
---|
2111 | Â Â :param float phi: first torsion angle (:math:`\\phi`) |
---|
2112 | Â Â :param float psi: second torsion angle (:math:`\\psi`) |
---|
2113 | Â Â :param list Coeff: pseudo potential coefficients |
---|
2114 | Â Â |
---|
2115 | Â Â :returns: list (sum,Eval): pseudo-potential difference from minimum & value; |
---|
2116 | Â Â Â sum is used for penalty function. |
---|
2117 | Â Â |
---|
2118 | Â Â ''' |
---|
2119 |   sum = 0. |
---|
2120 | Â Â Eval =Â 0. |
---|
2121 |   if len(Coeff): |
---|
2122 | Â Â Â Â cof =Â Coeff.T |
---|
2123 | Â Â Â Â dPhi =Â phi-cof[1] |
---|
2124 | Â Â Â Â dPhi =Â np.where(dPhi<-180.,dPhi+360.,dPhi) |
---|
2125 | Â Â Â Â dPhi =Â np.where(dPhi>180.,dPhi-360.,dPhi) |
---|
2126 | Â Â Â Â dPsi =Â psi-cof[2] |
---|
2127 | Â Â Â Â dPsi =Â np.where(dPsi<-180.,dPsi+360.,dPsi) |
---|
2128 | Â Â Â Â dPsi =Â np.where(dPsi>180.,dPsi-360.,dPsi) |
---|
2129 | Â Â Â Â val =Â -cof[3]*dPhi**2-cof[4]*dPsi**2-2.0*cof[5]*dPhi*dPsi |
---|
2130 | Â Â Â Â val =Â cof[0]*np.exp(val/1000.) |
---|
2131 | Â Â Â Â pMax =Â cof[0][np.argmin(val)] |
---|
2132 | Â Â Â Â Eval =Â np.sum(val) |
---|
2133 |     sum = Eval-pMax |
---|
2134 |   return sum,Eval |
---|
2135 | |
---|
2136 | def getRamaDeriv(XYZ,Amat,Coeff): |
---|
2137 | Â Â '''Computes numerical derivatives of torsion angle pair pseudo potential |
---|
2138 | Â Â with respect of crystallographic atom coordinates of the 5 atom sequence |
---|
2139 | Â Â |
---|
2140 | Â Â :param nparray XYZ: crystallographic coordinates of 5 atoms |
---|
2141 | Â Â :param nparray Amat: crystal to cartesian transformation matrix |
---|
2142 | Â Â :param list Coeff: pseudo potential coefficients |
---|
2143 | Â Â |
---|
2144 | Â Â :returns: list (deriv) derivatives of pseudopotential with respect to 5 atom |
---|
2145 | Â Â Â crystallographic xyz coordinates. |
---|
2146 | Â Â |
---|
2147 | Â Â ''' |
---|
2148 | Â Â deriv =Â np.zeros((len(XYZ),3)) |
---|
2149 | Â Â dx =Â 0.00001 |
---|
2150 |   for j,xyz in enumerate(XYZ): |
---|
2151 |     for i,x in enumerate(np.array([[dx,0,0],[0,dx,0],[0,0,dx]])): |
---|
2152 | Â Â Â Â Â Â XYZ[j]Â -=Â x |
---|
2153 | Â Â Â Â Â Â phi,psi =Â getRestRama(XYZ,Amat) |
---|
2154 | Â Â Â Â Â Â p1,d1 =Â calcRamaEnergy(phi,psi,Coeff) |
---|
2155 | Â Â Â Â Â Â XYZ[j]Â +=Â 2*x |
---|
2156 | Â Â Â Â Â Â phi,psi =Â getRestRama(XYZ,Amat) |
---|
2157 | Â Â Â Â Â Â p2,d2 =Â calcRamaEnergy(phi,psi,Coeff) |
---|
2158 | Â Â Â Â Â Â XYZ[j]Â -=Â x |
---|
2159 | Â Â Â Â Â Â deriv[j][i]Â =Â (p2-p1)/(2*dx) |
---|
2160 |   return deriv.flatten() |
---|
2161 | |
---|
2162 | def getRestPolefig(ODFln,SamSym,Grid): |
---|
2163 | Â Â '''default doc string |
---|
2164 | Â Â |
---|
2165 | Â Â :param type name: description |
---|
2166 | Â Â |
---|
2167 | Â Â :returns: type name: description |
---|
2168 | Â Â |
---|
2169 | Â Â ''' |
---|
2170 | Â Â X,Y =Â np.meshgrid(np.linspace(1.,-1.,Grid),np.linspace(-1.,1.,Grid)) |
---|
2171 | Â Â R,P =Â np.sqrt(X**2+Y**2).flatten(),atan2d(Y,X).flatten() |
---|
2172 | Â Â R =Â np.where(R <=Â 1.,2.*atand(R),0.0) |
---|
2173 | Â Â Z =Â np.zeros_like(R) |
---|
2174 | Â Â Z =Â G2lat.polfcal(ODFln,SamSym,R,P) |
---|
2175 | Â Â Z =Â np.reshape(Z,(Grid,Grid)) |
---|
2176 |   return np.reshape(R,(Grid,Grid)),np.reshape(P,(Grid,Grid)),Z |
---|
2177 | |
---|
2178 | def getRestPolefigDerv(HKL,Grid,SHCoeff): |
---|
2179 | Â Â '''default doc string |
---|
2180 | Â Â |
---|
2181 | Â Â :param type name: description |
---|
2182 | Â Â |
---|
2183 | Â Â :returns: type name: description |
---|
2184 | Â Â |
---|
2185 | Â Â ''' |
---|
2186 | Â Â pass |
---|
2187 | Â Â Â Â |
---|
2188 | def getDistDerv(Oxyz,Txyz,Amat,Tunit,Top,SGData): |
---|
2189 | Â Â '''default doc string |
---|
2190 | Â Â |
---|
2191 | Â Â :param type name: description |
---|
2192 | Â Â |
---|
2193 | Â Â :returns: type name: description |
---|
2194 | Â Â |
---|
2195 | Â Â ''' |
---|
2196 |   def calcDist(Ox,Tx,U,inv,C,M,T,Amat): |
---|
2197 | Â Â Â Â TxT =Â inv*(np.inner(M,Tx)+T)+C+U |
---|
2198 |     return np.sqrt(np.sum(np.inner(Amat,(TxT-Ox))**2)) |
---|
2199 | Â Â Â Â |
---|
2200 | Â Â inv =Â Top/abs(Top) |
---|
2201 | Â Â cent =Â abs(Top)//100 |
---|
2202 | Â Â op =Â abs(Top)%100-1 |
---|
2203 | Â Â M,T =Â SGData['SGOps'][op] |
---|
2204 | Â Â C =Â SGData['SGCen'][cent] |
---|
2205 | Â Â dx =Â .00001 |
---|
2206 | Â Â deriv =Â np.zeros(6) |
---|
2207 |   for i in [0,1,2]: |
---|
2208 | Â Â Â Â Oxyz[i]Â -=Â dx |
---|
2209 | Â Â Â Â d0 =Â calcDist(Oxyz,Txyz,Tunit,inv,C,M,T,Amat) |
---|
2210 | Â Â Â Â Oxyz[i]Â +=Â 2*dx |
---|
2211 | Â Â Â Â deriv[i]Â =Â (calcDist(Oxyz,Txyz,Tunit,inv,C,M,T,Amat)-d0)/(2.*dx) |
---|
2212 | Â Â Â Â Oxyz[i]Â -=Â dx |
---|
2213 | Â Â Â Â Txyz[i]Â -=Â dx |
---|
2214 | Â Â Â Â d0 =Â calcDist(Oxyz,Txyz,Tunit,inv,C,M,T,Amat) |
---|
2215 | Â Â Â Â Txyz[i]Â +=Â 2*dx |
---|
2216 | Â Â Â Â deriv[i+3]Â =Â (calcDist(Oxyz,Txyz,Tunit,inv,C,M,T,Amat)-d0)/(2.*dx) |
---|
2217 | Â Â Â Â Txyz[i]Â -=Â dx |
---|
2218 |   return deriv |
---|
2219 | Â Â |
---|
2220 | def getAngleDerv(Oxyz,Axyz,Bxyz,Amat,Tunit,symNo,SGData): |
---|
2221 | Â Â |
---|
2222 |   def calcAngle(Oxyz,ABxyz,Amat,Tunit,symNo,SGData): |
---|
2223 | Â Â Â Â vec =Â np.zeros((2,3)) |
---|
2224 |     for i in range(2): |
---|
2225 | Â Â Â Â Â Â inv =Â 1 |
---|
2226 |       if symNo[i] < 0: |
---|
2227 | Â Â Â Â Â Â Â Â inv =Â -1 |
---|
2228 | Â Â Â Â Â Â cen =Â inv*symNo[i]//100 |
---|
2229 | Â Â Â Â Â Â op =Â inv*symNo[i]%100-1 |
---|
2230 | Â Â Â Â Â Â M,T =Â SGData['SGOps'][op] |
---|
2231 | Â Â Â Â Â Â D =Â T*inv+SGData['SGCen'][cen] |
---|
2232 | Â Â Â Â Â Â D +=Â Tunit[i] |
---|
2233 | Â Â Â Â Â Â ABxyz[i]Â =Â np.inner(M*inv,ABxyz[i])+D |
---|
2234 | Â Â Â Â Â Â vec[i]Â =Â np.inner(Amat,(ABxyz[i]-Oxyz)) |
---|
2235 | Â Â Â Â Â Â dist =Â np.sqrt(np.sum(vec[i]**2)) |
---|
2236 |       if not dist: |
---|
2237 |         return 0. |
---|
2238 | Â Â Â Â Â Â vec[i]Â /=Â dist |
---|
2239 | Â Â Â Â angle =Â acosd(np.sum(vec[0]*vec[1])) |
---|
2240 | Â Â #Â Â GSASIIpath.IPyBreak() |
---|
2241 |     return angle |
---|
2242 | Â Â Â Â |
---|
2243 | Â Â dx =Â .00001 |
---|
2244 | Â Â deriv =Â np.zeros(9) |
---|
2245 |   for i in [0,1,2]: |
---|
2246 | Â Â Â Â Oxyz[i]Â -=Â dx |
---|
2247 | Â Â Â Â a0 =Â calcAngle(Oxyz,[Axyz,Bxyz],Amat,Tunit,symNo,SGData) |
---|
2248 | Â Â Â Â Oxyz[i]Â +=Â 2*dx |
---|
2249 | Â Â Â Â deriv[i]Â =Â (calcAngle(Oxyz,[Axyz,Bxyz],Amat,Tunit,symNo,SGData)-a0)/(2.*dx) |
---|
2250 | Â Â Â Â Oxyz[i]Â -=Â dx |
---|
2251 | Â Â Â Â Axyz[i]Â -=Â dx |
---|
2252 | Â Â Â Â a0 =Â calcAngle(Oxyz,[Axyz,Bxyz],Amat,Tunit,symNo,SGData) |
---|
2253 | Â Â Â Â Axyz[i]Â +=Â 2*dx |
---|
2254 | Â Â Â Â deriv[i+3]Â =Â (calcAngle(Oxyz,[Axyz,Bxyz],Amat,Tunit,symNo,SGData)-a0)/(2.*dx) |
---|
2255 | Â Â Â Â Axyz[i]Â -=Â dx |
---|
2256 | Â Â Â Â Bxyz[i]Â -=Â dx |
---|
2257 | Â Â Â Â a0 =Â calcAngle(Oxyz,[Axyz,Bxyz],Amat,Tunit,symNo,SGData) |
---|
2258 | Â Â Â Â Bxyz[i]Â +=Â 2*dx |
---|
2259 | Â Â Â Â deriv[i+6]Â =Â (calcAngle(Oxyz,[Axyz,Bxyz],Amat,Tunit,symNo,SGData)-a0)/(2.*dx) |
---|
2260 | Â Â Â Â Bxyz[i]Â -=Â dx |
---|
2261 |   return deriv |
---|
2262 | Â Â |
---|
2263 | def getAngSig(VA,VB,Amat,SGData,covData={}): |
---|
2264 | Â Â '''default doc string |
---|
2265 | Â Â |
---|
2266 | Â Â :param type name: description |
---|
2267 | Â Â |
---|
2268 | Â Â :returns: type name: description |
---|
2269 | Â Â |
---|
2270 | Â Â ''' |
---|
2271 |   def calcVec(Ox,Tx,U,inv,C,M,T,Amat): |
---|
2272 | Â Â Â Â TxT =Â inv*(np.inner(M,Tx)+T)+C+U |
---|
2273 |     return np.inner(Amat,(TxT-Ox)) |
---|
2274 | Â Â Â Â |
---|
2275 |   def calcAngle(Ox,TxA,TxB,unitA,unitB,invA,CA,MA,TA,invB,CB,MB,TB,Amat): |
---|
2276 | Â Â Â Â VecA =Â calcVec(Ox,TxA,unitA,invA,CA,MA,TA,Amat) |
---|
2277 | Â Â Â Â VecA /=Â np.sqrt(np.sum(VecA**2)) |
---|
2278 | Â Â Â Â VecB =Â calcVec(Ox,TxB,unitB,invB,CB,MB,TB,Amat) |
---|
2279 | Â Â Â Â VecB /=Â np.sqrt(np.sum(VecB**2)) |
---|
2280 | Â Â Â Â edge =Â VecB-VecA |
---|
2281 | Â Â Â Â edge =Â np.sum(edge**2) |
---|
2282 | Â Â Â Â angle =Â (2.-edge)/2. |
---|
2283 | Â Â Â Â angle =Â max(angle,-1.) |
---|
2284 |     return acosd(angle) |
---|
2285 | Â Â Â Â |
---|
2286 | Â Â OxAN,OxA,TxAN,TxA,unitA,TopA =Â VA |
---|
2287 | Â Â OxBN,OxB,TxBN,TxB,unitB,TopB =Â VB |
---|
2288 | Â Â invA =Â invB =Â 1 |
---|
2289 | Â Â invA =Â TopA//abs(TopA) |
---|
2290 | Â Â invB =Â TopB//abs(TopB) |
---|
2291 | Â Â centA =Â abs(TopA)//100 |
---|
2292 | Â Â centB =Â abs(TopB)//100 |
---|
2293 | Â Â opA =Â abs(TopA)%100-1 |
---|
2294 | Â Â opB =Â abs(TopB)%100-1 |
---|
2295 | Â Â MA,TA =Â SGData['SGOps'][opA] |
---|
2296 | Â Â MB,TB =Â SGData['SGOps'][opB] |
---|
2297 | Â Â CA =Â SGData['SGCen'][centA] |
---|
2298 | Â Â CB =Â SGData['SGCen'][centB] |
---|
2299 |   if 'covMatrix' in covData: |
---|
2300 | Â Â Â Â covMatrix =Â covData['covMatrix'] |
---|
2301 | Â Â Â Â varyList =Â covData['varyList'] |
---|
2302 | Â Â Â Â AngVcov =Â getVCov(OxAN+TxAN+TxBN,varyList,covMatrix) |
---|
2303 | Â Â Â Â dx =Â .00001 |
---|
2304 | Â Â Â Â dadx =Â np.zeros(9) |
---|
2305 | Â Â Â Â Ang =Â calcAngle(OxA,TxA,TxB,unitA,unitB,invA,CA,MA,TA,invB,CB,MB,TB,Amat) |
---|
2306 |     for i in [0,1,2]: |
---|
2307 | Â Â Â Â Â Â OxA[i]Â -=Â dx |
---|
2308 | Â Â Â Â Â Â a0 =Â calcAngle(OxA,TxA,TxB,unitA,unitB,invA,CA,MA,TA,invB,CB,MB,TB,Amat) |
---|
2309 | Â Â Â Â Â Â OxA[i]Â +=Â 2*dx |
---|
2310 | Â Â Â Â Â Â dadx[i]Â =Â (calcAngle(OxA,TxA,TxB,unitA,unitB,invA,CA,MA,TA,invB,CB,MB,TB,Amat)-a0)/(2*dx) |
---|
2311 | Â Â Â Â Â Â OxA[i]Â -=Â dx |
---|
2312 | Â Â Â Â Â Â |
---|
2313 | Â Â Â Â Â Â TxA[i]Â -=Â dx |
---|
2314 | Â Â Â Â Â Â a0 =Â calcAngle(OxA,TxA,TxB,unitA,unitB,invA,CA,MA,TA,invB,CB,MB,TB,Amat) |
---|
2315 | Â Â Â Â Â Â TxA[i]Â +=Â 2*dx |
---|
2316 | Â Â Â Â Â Â dadx[i+3]Â =Â (calcAngle(OxA,TxA,TxB,unitA,unitB,invA,CA,MA,TA,invB,CB,MB,TB,Amat)-a0)/(2*dx) |
---|
2317 | Â Â Â Â Â Â TxA[i]Â -=Â dx |
---|
2318 | Â Â Â Â Â Â |
---|
2319 | Â Â Â Â Â Â TxB[i]Â -=Â dx |
---|
2320 | Â Â Â Â Â Â a0 =Â calcAngle(OxA,TxA,TxB,unitA,unitB,invA,CA,MA,TA,invB,CB,MB,TB,Amat) |
---|
2321 | Â Â Â Â Â Â TxB[i]Â +=Â 2*dx |
---|
2322 | Â Â Â Â Â Â dadx[i+6]Â =Â (calcAngle(OxA,TxA,TxB,unitA,unitB,invA,CA,MA,TA,invB,CB,MB,TB,Amat)-a0)/(2*dx) |
---|
2323 | Â Â Â Â Â Â TxB[i]Â -=Â dx |
---|
2324 | Â Â Â Â Â Â |
---|
2325 | Â Â Â Â sigAng =Â np.sqrt(np.inner(dadx,np.inner(AngVcov,dadx))) |
---|
2326 |     if sigAng < 0.01: |
---|
2327 | Â Â Â Â Â Â sigAng =Â 0.0 |
---|
2328 |     return Ang,sigAng |
---|
2329 | Â Â else: |
---|
2330 |     return calcAngle(OxA,TxA,TxB,unitA,unitB,invA,CA,MA,TA,invB,CB,MB,TB,Amat),0.0 |
---|
2331 | |
---|
2332 | def GetDistSig(Oatoms,Atoms,Amat,SGData,covData={}): |
---|
2333 | Â Â '''default doc string |
---|
2334 | Â Â |
---|
2335 | Â Â :param type name: description |
---|
2336 | Â Â |
---|
2337 | Â Â :returns: type name: description |
---|
2338 | Â Â |
---|
2339 | Â Â ''' |
---|
2340 |   def calcDist(Atoms,SyOps,Amat): |
---|
2341 | Â Â Â Â XYZ =Â [] |
---|
2342 |     for i,atom in enumerate(Atoms): |
---|
2343 | Â Â Â Â Â Â Inv,M,T,C,U =Â SyOps[i] |
---|
2344 | Â Â Â Â Â Â XYZ.append(np.array(atom[1:4])) |
---|
2345 | Â Â Â Â Â Â XYZ[-1]Â =Â Inv*(np.inner(M,np.array(XYZ[-1]))+T)+C+U |
---|
2346 | Â Â Â Â Â Â XYZ[-1]Â =Â np.inner(Amat,XYZ[-1]).T |
---|
2347 | Â Â Â Â V1 =Â XYZ[1]-XYZ[0] |
---|
2348 |     return np.sqrt(np.sum(V1**2)) |
---|
2349 | Â Â Â Â |
---|
2350 | Â Â SyOps =Â [] |
---|
2351 | Â Â names =Â [] |
---|
2352 |   for i,atom in enumerate(Oatoms): |
---|
2353 | Â Â Â Â names +=Â atom[-1] |
---|
2354 | Â Â Â Â Op,unit =Â Atoms[i][-1] |
---|
2355 | Â Â Â Â inv =Â Op//abs(Op) |
---|
2356 | Â Â Â Â m,t =Â SGData['SGOps'][abs(Op)%100-1] |
---|
2357 | Â Â Â Â c =Â SGData['SGCen'][abs(Op)//100] |
---|
2358 | Â Â Â Â SyOps.append([inv,m,t,c,unit]) |
---|
2359 | Â Â Dist =Â calcDist(Oatoms,SyOps,Amat) |
---|
2360 | Â Â |
---|
2361 | Â Â sig =Â -0.001 |
---|
2362 |   if 'covMatrix' in covData: |
---|
2363 | Â Â Â Â dx =Â .00001 |
---|
2364 | Â Â Â Â dadx =Â np.zeros(6) |
---|
2365 |     for i in range(6): |
---|
2366 | Â Â Â Â Â Â ia =Â i//3 |
---|
2367 | Â Â Â Â Â Â ix =Â i%3 |
---|
2368 | Â Â Â Â Â Â Oatoms[ia][ix+1]Â +=Â dx |
---|
2369 | Â Â Â Â Â Â a0 =Â calcDist(Oatoms,SyOps,Amat) |
---|
2370 | Â Â Â Â Â Â Oatoms[ia][ix+1]Â -=Â 2*dx |
---|
2371 | Â Â Â Â Â Â dadx[i]Â =Â (calcDist(Oatoms,SyOps,Amat)-a0)/(2.*dx) |
---|
2372 | Â Â Â Â covMatrix =Â covData['covMatrix'] |
---|
2373 | Â Â Â Â varyList =Â covData['varyList'] |
---|
2374 | Â Â Â Â DistVcov =Â getVCov(names,varyList,covMatrix) |
---|
2375 | Â Â Â Â sig =Â np.sqrt(np.inner(dadx,np.inner(DistVcov,dadx))) |
---|
2376 |     if sig < 0.001: |
---|
2377 | Â Â Â Â Â Â sig =Â -0.001 |
---|
2378 | Â Â |
---|
2379 |   return Dist,sig |
---|
2380 | |
---|
2381 | def GetAngleSig(Oatoms,Atoms,Amat,SGData,covData={}): |
---|
2382 | Â Â '''default doc string |
---|
2383 | Â Â |
---|
2384 | Â Â :param type name: description |
---|
2385 | Â Â |
---|
2386 | Â Â :returns: type name: description |
---|
2387 | Â Â |
---|
2388 | Â Â ''' |
---|
2389 | |
---|
2390 |   def calcAngle(Atoms,SyOps,Amat): |
---|
2391 | Â Â Â Â XYZ =Â [] |
---|
2392 |     for i,atom in enumerate(Atoms): |
---|
2393 | Â Â Â Â Â Â Inv,M,T,C,U =Â SyOps[i] |
---|
2394 | Â Â Â Â Â Â XYZ.append(np.array(atom[1:4])) |
---|
2395 | Â Â Â Â Â Â XYZ[-1]Â =Â Inv*(np.inner(M,np.array(XYZ[-1]))+T)+C+U |
---|
2396 | Â Â Â Â Â Â XYZ[-1]Â =Â np.inner(Amat,XYZ[-1]).T |
---|
2397 | Â Â Â Â V1 =Â XYZ[1]-XYZ[0] |
---|
2398 | Â Â Â Â V1 /=Â np.sqrt(np.sum(V1**2)) |
---|
2399 | Â Â Â Â V2 =Â XYZ[1]-XYZ[2] |
---|
2400 | Â Â Â Â V2 /=Â np.sqrt(np.sum(V2**2)) |
---|
2401 | Â Â Â Â V3 =Â V2-V1 |
---|
2402 | Â Â Â Â cang =Â min(1.,max((2.-np.sum(V3**2))/2.,-1.)) |
---|
2403 |     return acosd(cang) |
---|
2404 | |
---|
2405 | Â Â SyOps =Â [] |
---|
2406 | Â Â names =Â [] |
---|
2407 |   for i,atom in enumerate(Oatoms): |
---|
2408 | Â Â Â Â names +=Â atom[-1] |
---|
2409 | Â Â Â Â Op,unit =Â Atoms[i][-1] |
---|
2410 | Â Â Â Â inv =Â Op//abs(Op) |
---|
2411 | Â Â Â Â m,t =Â SGData['SGOps'][abs(Op)%100-1] |
---|
2412 | Â Â Â Â c =Â SGData['SGCen'][abs(Op)//100] |
---|
2413 | Â Â Â Â SyOps.append([inv,m,t,c,unit]) |
---|
2414 | Â Â Angle =Â calcAngle(Oatoms,SyOps,Amat) |
---|
2415 | Â Â |
---|
2416 | Â Â sig =Â -0.01 |
---|
2417 |   if 'covMatrix' in covData: |
---|
2418 | Â Â Â Â dx =Â .00001 |
---|
2419 | Â Â Â Â dadx =Â np.zeros(9) |
---|
2420 |     for i in range(9): |
---|
2421 | Â Â Â Â Â Â ia =Â i//3 |
---|
2422 | Â Â Â Â Â Â ix =Â i%3 |
---|
2423 | Â Â Â Â Â Â Oatoms[ia][ix+1]Â +=Â dx |
---|
2424 | Â Â Â Â Â Â a0 =Â calcAngle(Oatoms,SyOps,Amat) |
---|
2425 | Â Â Â Â Â Â Oatoms[ia][ix+1]Â -=Â 2*dx |
---|
2426 | Â Â Â Â Â Â dadx[i]Â =Â (calcAngle(Oatoms,SyOps,Amat)-a0)/(2.*dx) |
---|
2427 | Â Â Â Â covMatrix =Â covData['covMatrix'] |
---|
2428 | Â Â Â Â varyList =Â covData['varyList'] |
---|
2429 | Â Â Â Â AngVcov =Â getVCov(names,varyList,covMatrix) |
---|
2430 | Â Â Â Â sig =Â np.sqrt(np.inner(dadx,np.inner(AngVcov,dadx))) |
---|
2431 |     if sig < 0.01: |
---|
2432 | Â Â Â Â Â Â sig =Â -0.01 |
---|
2433 | Â Â |
---|
2434 |   return Angle,sig |
---|
2435 | |
---|
2436 | def GetTorsionSig(Oatoms,Atoms,Amat,SGData,covData={}): |
---|
2437 | Â Â '''default doc string |
---|
2438 | Â Â |
---|
2439 | Â Â :param type name: description |
---|
2440 | Â Â |
---|
2441 | Â Â :returns: type name: description |
---|
2442 | Â Â |
---|
2443 | Â Â ''' |
---|
2444 | |
---|
2445 |   def calcTorsion(Atoms,SyOps,Amat): |
---|
2446 | Â Â Â Â |
---|
2447 | Â Â Â Â XYZ =Â [] |
---|
2448 |     for i,atom in enumerate(Atoms): |
---|
2449 | Â Â Â Â Â Â Inv,M,T,C,U =Â SyOps[i] |
---|
2450 | Â Â Â Â Â Â XYZ.append(np.array(atom[1:4])) |
---|
2451 | Â Â Â Â Â Â XYZ[-1]Â =Â Inv*(np.inner(M,np.array(XYZ[-1]))+T)+C+U |
---|
2452 | Â Â Â Â Â Â XYZ[-1]Â =Â np.inner(Amat,XYZ[-1]).T |
---|
2453 | Â Â Â Â V1 =Â XYZ[1]-XYZ[0] |
---|
2454 | Â Â Â Â V2 =Â XYZ[2]-XYZ[1] |
---|
2455 | Â Â Â Â V3 =Â XYZ[3]-XYZ[2] |
---|
2456 | Â Â Â Â V1 /=Â np.sqrt(np.sum(V1**2)) |
---|
2457 | Â Â Â Â V2 /=Â np.sqrt(np.sum(V2**2)) |
---|
2458 | Â Â Â Â V3 /=Â np.sqrt(np.sum(V3**2)) |
---|
2459 | Â Â Â Â M =Â np.array([V1,V2,V3]) |
---|
2460 | Â Â Â Â D =Â nl.det(M) |
---|
2461 | Â Â Â Â P12 =Â np.dot(V1,V2) |
---|
2462 | Â Â Â Â P13 =Â np.dot(V1,V3) |
---|
2463 | Â Â Â Â P23 =Â np.dot(V2,V3) |
---|
2464 | Â Â Â Â Tors =Â acosd((P12*P23-P13)/(np.sqrt(1.-P12**2)*np.sqrt(1.-P23**2)))*D/abs(D) |
---|
2465 |     return Tors |
---|
2466 | Â Â Â Â Â Â |
---|
2467 | Â Â SyOps =Â [] |
---|
2468 | Â Â names =Â [] |
---|
2469 |   for i,atom in enumerate(Oatoms): |
---|
2470 | Â Â Â Â names +=Â atom[-1] |
---|
2471 | Â Â Â Â Op,unit =Â Atoms[i][-1] |
---|
2472 | Â Â Â Â inv =Â Op//abs(Op) |
---|
2473 | Â Â Â Â m,t =Â SGData['SGOps'][abs(Op)%100-1] |
---|
2474 | Â Â Â Â c =Â SGData['SGCen'][abs(Op)//100] |
---|
2475 | Â Â Â Â SyOps.append([inv,m,t,c,unit]) |
---|
2476 | Â Â Tors =Â calcTorsion(Oatoms,SyOps,Amat) |
---|
2477 | Â Â |
---|
2478 | Â Â sig =Â -0.01 |
---|
2479 |   if 'covMatrix' in covData: |
---|
2480 | Â Â Â Â dx =Â .00001 |
---|
2481 | Â Â Â Â dadx =Â np.zeros(12) |
---|
2482 |     for i in range(12): |
---|
2483 | Â Â Â Â Â Â ia =Â i//3 |
---|
2484 | Â Â Â Â Â Â ix =Â i%3 |
---|
2485 | Â Â Â Â Â Â Oatoms[ia][ix+1]Â -=Â dx |
---|
2486 | Â Â Â Â Â Â a0 =Â calcTorsion(Oatoms,SyOps,Amat) |
---|
2487 | Â Â Â Â Â Â Oatoms[ia][ix+1]Â +=Â 2*dx |
---|
2488 | Â Â Â Â Â Â dadx[i]Â =Â (calcTorsion(Oatoms,SyOps,Amat)-a0)/(2.*dx) |
---|
2489 |       Oatoms[ia][ix+1] -= dx      |
---|
2490 | Â Â Â Â covMatrix =Â covData['covMatrix'] |
---|
2491 | Â Â Â Â varyList =Â covData['varyList'] |
---|
2492 | Â Â Â Â TorVcov =Â getVCov(names,varyList,covMatrix) |
---|
2493 | Â Â Â Â sig =Â np.sqrt(np.inner(dadx,np.inner(TorVcov,dadx))) |
---|
2494 |     if sig < 0.01: |
---|
2495 | Â Â Â Â Â Â sig =Â -0.01 |
---|
2496 | Â Â |
---|
2497 |   return Tors,sig |
---|
2498 | Â Â Â Â |
---|
2499 | def GetDATSig(Oatoms,Atoms,Amat,SGData,covData={}): |
---|
2500 | Â Â '''default doc string |
---|
2501 | Â Â |
---|
2502 | Â Â :param type name: description |
---|
2503 | Â Â |
---|
2504 | Â Â :returns: type name: description |
---|
2505 | Â Â |
---|
2506 | Â Â ''' |
---|
2507 | |
---|
2508 |   def calcDist(Atoms,SyOps,Amat): |
---|
2509 | Â Â Â Â XYZ =Â [] |
---|
2510 |     for i,atom in enumerate(Atoms): |
---|
2511 | Â Â Â Â Â Â Inv,M,T,C,U =Â SyOps[i] |
---|
2512 | Â Â Â Â Â Â XYZ.append(np.array(atom[1:4])) |
---|
2513 | Â Â Â Â Â Â XYZ[-1]Â =Â Inv*(np.inner(M,np.array(XYZ[-1]))+T)+C+U |
---|
2514 | Â Â Â Â Â Â XYZ[-1]Â =Â np.inner(Amat,XYZ[-1]).T |
---|
2515 | Â Â Â Â V1 =Â XYZ[1]-XYZ[0] |
---|
2516 |     return np.sqrt(np.sum(V1**2)) |
---|
2517 | Â Â Â Â |
---|
2518 |   def calcAngle(Atoms,SyOps,Amat): |
---|
2519 | Â Â Â Â XYZ =Â [] |
---|
2520 |     for i,atom in enumerate(Atoms): |
---|
2521 | Â Â Â Â Â Â Inv,M,T,C,U =Â SyOps[i] |
---|
2522 | Â Â Â Â Â Â XYZ.append(np.array(atom[1:4])) |
---|
2523 | Â Â Â Â Â Â XYZ[-1]Â =Â Inv*(np.inner(M,np.array(XYZ[-1]))+T)+C+U |
---|
2524 | Â Â Â Â Â Â XYZ[-1]Â =Â np.inner(Amat,XYZ[-1]).T |
---|
2525 | Â Â Â Â V1 =Â XYZ[1]-XYZ[0] |
---|
2526 | Â Â Â Â V1 /=Â np.sqrt(np.sum(V1**2)) |
---|
2527 | Â Â Â Â V2 =Â XYZ[1]-XYZ[2] |
---|
2528 | Â Â Â Â V2 /=Â np.sqrt(np.sum(V2**2)) |
---|
2529 | Â Â Â Â V3 =Â V2-V1 |
---|
2530 | Â Â Â Â cang =Â min(1.,max((2.-np.sum(V3**2))/2.,-1.)) |
---|
2531 |     return acosd(cang) |
---|
2532 | |
---|
2533 |   def calcTorsion(Atoms,SyOps,Amat): |
---|
2534 | Â Â Â Â |
---|
2535 | Â Â Â Â XYZ =Â [] |
---|
2536 |     for i,atom in enumerate(Atoms): |
---|
2537 | Â Â Â Â Â Â Inv,M,T,C,U =Â SyOps[i] |
---|
2538 | Â Â Â Â Â Â XYZ.append(np.array(atom[1:4])) |
---|
2539 | Â Â Â Â Â Â XYZ[-1]Â =Â Inv*(np.inner(M,np.array(XYZ[-1]))+T)+C+U |
---|
2540 | Â Â Â Â Â Â XYZ[-1]Â =Â np.inner(Amat,XYZ[-1]).T |
---|
2541 | Â Â Â Â V1 =Â XYZ[1]-XYZ[0] |
---|
2542 | Â Â Â Â V2 =Â XYZ[2]-XYZ[1] |
---|
2543 | Â Â Â Â V3 =Â XYZ[3]-XYZ[2] |
---|
2544 | Â Â Â Â V1 /=Â np.sqrt(np.sum(V1**2)) |
---|
2545 | Â Â Â Â V2 /=Â np.sqrt(np.sum(V2**2)) |
---|
2546 | Â Â Â Â V3 /=Â np.sqrt(np.sum(V3**2)) |
---|
2547 | Â Â Â Â M =Â np.array([V1,V2,V3]) |
---|
2548 | Â Â Â Â D =Â nl.det(M) |
---|
2549 | Â Â Â Â P12 =Â np.dot(V1,V2) |
---|
2550 | Â Â Â Â P13 =Â np.dot(V1,V3) |
---|
2551 | Â Â Â Â P23 =Â np.dot(V2,V3) |
---|
2552 | Â Â Â Â Tors =Â acosd((P12*P23-P13)/(np.sqrt(1.-P12**2)*np.sqrt(1.-P23**2)))*D/abs(D) |
---|
2553 |     return Tors |
---|
2554 | Â Â Â Â Â Â |
---|
2555 | Â Â SyOps =Â [] |
---|
2556 | Â Â names =Â [] |
---|
2557 |   for i,atom in enumerate(Oatoms): |
---|
2558 | Â Â Â Â names +=Â atom[-1] |
---|
2559 | Â Â Â Â Op,unit =Â Atoms[i][-1] |
---|
2560 | Â Â Â Â inv =Â Op//abs(Op) |
---|
2561 | Â Â Â Â m,t =Â SGData['SGOps'][abs(Op)%100-1] |
---|
2562 | Â Â Â Â c =Â SGData['SGCen'][abs(Op)//100] |
---|
2563 | Â Â Â Â SyOps.append([inv,m,t,c,unit]) |
---|
2564 | Â Â M =Â len(Oatoms) |
---|
2565 |   if M == 2: |
---|
2566 | Â Â Â Â Val =Â calcDist(Oatoms,SyOps,Amat) |
---|
2567 |   elif M == 3: |
---|
2568 | Â Â Â Â Val =Â calcAngle(Oatoms,SyOps,Amat) |
---|
2569 | Â Â else: |
---|
2570 | Â Â Â Â Val =Â calcTorsion(Oatoms,SyOps,Amat) |
---|
2571 | Â Â |
---|
2572 | Â Â sigVals =Â [-0.001,-0.01,-0.01] |
---|
2573 | Â Â sig =Â sigVals[M-3] |
---|
2574 |   if 'covMatrix' in covData: |
---|
2575 | Â Â Â Â dx =Â .00001 |
---|
2576 | Â Â Â Â N =Â M*3 |
---|
2577 | Â Â Â Â dadx =Â np.zeros(N) |
---|
2578 |     for i in range(N): |
---|
2579 | Â Â Â Â Â Â ia =Â i//3 |
---|
2580 | Â Â Â Â Â Â ix =Â i%3 |
---|
2581 | Â Â Â Â Â Â Oatoms[ia][ix+1]Â +=Â dx |
---|
2582 |       if M == 2: |
---|
2583 | Â Â Â Â Â Â Â Â a0 =Â calcDist(Oatoms,SyOps,Amat) |
---|
2584 |       elif M == 3: |
---|
2585 | Â Â Â Â Â Â Â Â a0 =Â calcAngle(Oatoms,SyOps,Amat) |
---|
2586 | Â Â Â Â Â Â else: |
---|
2587 | Â Â Â Â Â Â Â Â a0 =Â calcTorsion(Oatoms,SyOps,Amat) |
---|
2588 | Â Â Â Â Â Â Oatoms[ia][ix+1]Â -=Â 2*dx |
---|
2589 |       if M == 2: |
---|
2590 | Â Â Â Â Â Â Â Â dadx[i]Â =Â (calcDist(Oatoms,SyOps,Amat)-a0)/(2.*dx)Â Â Â Â Â Â Â Â |
---|
2591 |       elif M == 3: |
---|
2592 | Â Â Â Â Â Â Â Â dadx[i]Â =Â (calcAngle(Oatoms,SyOps,Amat)-a0)/(2.*dx)Â Â Â Â Â Â Â Â |
---|
2593 | Â Â Â Â Â Â else: |
---|
2594 | Â Â Â Â Â Â Â Â dadx[i]Â =Â (calcTorsion(Oatoms,SyOps,Amat)-a0)/(2.*dx) |
---|
2595 | Â Â Â Â covMatrix =Â covData['covMatrix'] |
---|
2596 | Â Â Â Â varyList =Â covData['varyList'] |
---|
2597 | Â Â Â Â Vcov =Â getVCov(names,varyList,covMatrix) |
---|
2598 | Â Â Â Â sig =Â np.sqrt(np.inner(dadx,np.inner(Vcov,dadx))) |
---|
2599 |     if sig < sigVals[M-3]: |
---|
2600 | Â Â Â Â Â Â sig =Â sigVals[M-3] |
---|
2601 | Â Â |
---|
2602 |   return Val,sig |
---|
2603 | Â Â Â Â |
---|
2604 | def ValEsd(value,esd=0,nTZ=False): |
---|
2605 | Â Â '''Format a floating point number with a given level of precision or |
---|
2606 | Â Â with in crystallographic format with a "esd", as value(esd). If esd is |
---|
2607 | Â Â negative the number is formatted with the level of significant figures |
---|
2608 | Â Â appropriate if abs(esd) were the esd, but the esd is not included. |
---|
2609 | Â Â if the esd is zero, approximately 6 significant figures are printed. |
---|
2610 | Â Â nTZ=True causes "extra" zeros to be removed after the decimal place. |
---|
2611 | Â Â for example: |
---|
2612 | |
---|
2613 | Â Â Â * "1.235(3)" for value=1.2346 & esd=0.003 |
---|
2614 | Â Â Â * "1.235(3)e4" for value=12346. & esd=30 |
---|
2615 | Â Â Â * "1.235(3)e6" for value=0.12346e7 & esd=3000 |
---|
2616 | Â Â Â * "1.235" for value=1.2346 & esd=-0.003 |
---|
2617 | Â Â Â * "1.240" for value=1.2395 & esd=-0.003 |
---|
2618 | Â Â Â * "1.24" for value=1.2395 & esd=-0.003 with nTZ=True |
---|
2619 | Â Â Â * "1.23460" for value=1.2346 & esd=0.0 |
---|
2620 | |
---|
2621 | Â Â :param float value: number to be formatted |
---|
2622 | Â Â :param float esd: uncertainty or if esd < 0, specifies level of |
---|
2623 | Â Â Â precision to be shown e.g. esd=-0.01 gives 2 places beyond decimal |
---|
2624 | Â Â :param bool nTZ: True to remove trailing zeros (default is False) |
---|
2625 | Â Â :returns: value(esd) or value as a string |
---|
2626 | |
---|
2627 | Â Â ''' |
---|
2628 | Â Â # Note: this routine is Python 3 compatible -- I think |
---|
2629 | Â Â cutoff =Â 3.16228Â Â #=(sqrt(10); same as old GSASÂ Â was 1.95 |
---|
2630 |   if math.isnan(value): # invalid value, bail out |
---|
2631 |     return '?' |
---|
2632 |   if math.isnan(esd): # invalid esd, treat as zero |
---|
2633 | Â Â Â Â esd =Â 0 |
---|
2634 | Â Â Â Â esdoff =Â 5 |
---|
2635 | #Â Â if esd < 1.e-5: |
---|
2636 | #Â Â Â Â esd = 0 |
---|
2637 | #Â Â Â Â esdoff = 5 |
---|
2638 |   elif esd != 0: |
---|
2639 | Â Â Â Â # transform the esd to a one or two digit integer |
---|
2640 | Â Â Â Â l =Â math.log10(abs(esd))Â %Â 1. |
---|
2641 |     if l < math.log10(cutoff): l+= 1.    |
---|
2642 | Â Â Â Â intesd =Â int(round(10**l))Â # esd as integer |
---|
2643 | Â Â Â Â # determine the number of digits offset for the esd |
---|
2644 | Â Â Â Â esdoff =Â int(round(math.log10(intesd*1./abs(esd)))) |
---|
2645 | Â Â else: |
---|
2646 | Â Â Â Â esdoff =Â 5 |
---|
2647 | Â Â valoff =Â 0 |
---|
2648 |   if abs(value) < abs(esdoff): # value is effectively zero |
---|
2649 | Â Â Â Â pass |
---|
2650 |   elif esdoff < 0 or abs(value) > 1.0e6 or abs(value) < 1.0e-4: # use scientific notation |
---|
2651 | Â Â Â Â # where the digit offset is to the left of the decimal place or where too many |
---|
2652 | Â Â Â Â # digits are needed |
---|
2653 |     if abs(value) > 1: |
---|
2654 | Â Â Â Â Â Â valoff =Â int(math.log10(abs(value))) |
---|
2655 |     elif abs(value) > 0: |
---|
2656 | Â Â Â Â Â Â valoff =Â int(math.log10(abs(value))-0.9999999) |
---|
2657 | Â Â Â Â else: |
---|
2658 | Â Â Â Â Â Â valoff =Â 0 |
---|
2659 |   if esd != 0: |
---|
2660 |     if valoff+esdoff < 0: |
---|
2661 | Â Â Â Â Â Â valoff =Â esdoff =Â 0 |
---|
2662 | Â Â Â Â out =Â ("{:."+str(valoff+esdoff)+"f}").format(value/10**valoff)Â # format the value |
---|
2663 |   elif valoff != 0: # esd = 0; exponential notation ==> esdoff decimal places |
---|
2664 | Â Â Â Â out =Â ("{:."+str(esdoff)+"f}").format(value/10**valoff)Â # format the value |
---|
2665 | Â Â else:Â # esd = 0; non-exponential notation ==> esdoff+1 significant digits |
---|
2666 |     if abs(value) > 0:      |
---|
2667 | Â Â Â Â Â Â extra =Â -math.log10(abs(value)) |
---|
2668 | Â Â Â Â else: |
---|
2669 | Â Â Â Â Â Â extra =Â 0 |
---|
2670 |     if extra > 0: extra += 1 |
---|
2671 | Â Â Â Â out =Â ("{:."+str(max(0,esdoff+int(extra)))+"f}").format(value)Â # format the value |
---|
2672 |   if esd > 0: |
---|
2673 | Â Â Â Â out +=Â ("({:d})").format(intesd)Â # add the esd |
---|
2674 |   elif nTZ and '.' in out: |
---|
2675 | Â Â Â Â out =Â out.rstrip('0')Â # strip zeros to right of decimal |
---|
2676 | Â Â Â Â out =Â out.rstrip('.')Â # and decimal place when not needed |
---|
2677 |   if valoff != 0: |
---|
2678 | Â Â Â Â out +=Â ("e{:d}").format(valoff)Â # add an exponent, when needed |
---|
2679 |   return out |
---|
2680 | Â Â |
---|
2681 | ############################################################################### |
---|
2682 | ##### Protein validation - "ERRATV2" analysis |
---|
2683 | ############################################################################### |
---|
2684 | |
---|
2685 | def validProtein(Phase,old): |
---|
2686 | Â Â |
---|
2687 |   def sumintact(intact): |
---|
2688 |     return {'CC':intact['CC'],'NN':intact['NN'],'OO':intact['OO'], |
---|
2689 | Â Â Â Â 'CN':(intact['CN']+intact['NC']),'CO':(intact['CO']+intact['OC']), |
---|
2690 | Â Â Â Â 'NO':(intact['NO']+intact['ON'])} |
---|
2691 | Â Â Â Â |
---|
2692 | Â Â resNames =Â ['ALA','ARG','ASN','ASP','CYS','GLN','GLU','GLY','HIS','ILE', |
---|
2693 | Â Â Â Â 'LEU','LYS','MET','PHE','PRO','SER','THR','TRP','TYR','VAL','MSE'] |
---|
2694 | # data from errat.f |
---|
2695 | Â Â b1_old =Â np.array([Â |
---|
2696 |     [1154.343, 600.213, 1051.018, 1132.885, 960.738], |
---|
2697 |     [600.213, 1286.818, 1282.042, 957.156, 612.789], |
---|
2698 |     [1051.018, 1282.042, 3519.471, 991.974, 1226.491], |
---|
2699 |     [1132.885, 957.156, 991.974, 1798.672, 820.355], |
---|
2700 |     [960.738, 612.789, 1226.491, 820.355, 2428.966] |
---|
2701 | Â Â Â Â ]) |
---|
2702 |   avg_old = np.array([ 0.225, 0.281, 0.071, 0.237, 0.044])  #Table 1 3.5A Obsd. Fr. p 1513 |
---|
2703 | # data taken from erratv2.ccp |
---|
2704 | Â Â b1 =Â np.array([ |
---|
2705 |      [5040.279078850848200,    3408.805141583649400,  4152.904423767300600,  4236.200004171890200,  5054.781210204625500], |
---|
2706 |      [3408.805141583648900,    8491.906094010220800,  5958.881777877950300,  1521.387352718486200,  4304.078200827221700], |
---|
2707 |      [4152.904423767301500,    5958.881777877952100,  7637.167089335050100,  6620.715738223072500,  5287.691183798410700], |
---|
2708 |      [4236.200004171890200,    1521.387352718486200,  6620.715738223072500,  18368.343774298410000, 4050.797811118806700], |
---|
2709 |      [5054.781210204625500,    4304.078200827220800,  5287.691183798409800,  4050.797811118806700,  6666.856740479164700]]) |
---|
2710 |   avg = np.array([0.192765509919262, 0.195575208778518, 0.275322406824210, 0.059102357035642, 0.233154192767480]) |
---|
2711 | Â Â General =Â Phase['General'] |
---|
2712 | Â Â Amat,Bmat =Â G2lat.cell2AB(General['Cell'][1:7]) |
---|
2713 | Â Â cx,ct,cs,cia =Â General['AtomPtrs'] |
---|
2714 | Â Â Atoms =Â Phase['Atoms'] |
---|
2715 | Â Â cartAtoms =Â [] |
---|
2716 | Â Â xyzmin =Â 999.*np.ones(3) |
---|
2717 | Â Â xyzmax =Â -999.*np.ones(3) |
---|
2718 | Â Â #select residue atoms,S,Se --> O make cartesian |
---|
2719 |   for atom in Atoms: |
---|
2720 |     if atom[1] in resNames: |
---|
2721 | Â Â Â Â Â Â cartAtoms.append(atom[:cx+3]) |
---|
2722 |       if atom[4].strip() in ['S','Se']: |
---|
2723 |         if not old: |
---|
2724 |           continue    #S,Se skipped for erratv2? |
---|
2725 | Â Â Â Â Â Â Â Â cartAtoms[-1][3]Â =Â 'Os' |
---|
2726 | Â Â Â Â Â Â Â Â cartAtoms[-1][4]Â =Â 'O' |
---|
2727 | Â Â Â Â Â Â cartAtoms[-1][cx:cx+3]Â =Â np.inner(Amat,cartAtoms[-1][cx:cx+3]) |
---|
2728 | Â Â Â Â Â Â cartAtoms[-1].append(atom[cia+8]) |
---|
2729 |   XYZ = np.array([atom[cx:cx+3] for atom in cartAtoms]) |
---|
2730 |   xyzmin = np.array([np.min(XYZ.T[i]) for i in [0,1,2]]) |
---|
2731 |   xyzmax = np.array([np.max(XYZ.T[i]) for i in [0,1,2]]) |
---|
2732 | Â Â nbox =Â list(np.array(np.ceil((xyzmax-xyzmin)/4.),dtype=int))+[15,] |
---|
2733 | Â Â Boxes =Â np.zeros(nbox,dtype=int) |
---|
2734 |   iBox = np.array([np.trunc((XYZ.T[i]-xyzmin[i])/4.) for i in [0,1,2]],dtype=int).T |
---|
2735 |   for ib,box in enumerate(iBox): #put in a try for too many atoms in box (IndexError)? |
---|
2736 | Â Â Â Â try: |
---|
2737 | Â Â Â Â Â Â Boxes[box[0],box[1],box[2],0]Â +=Â 1 |
---|
2738 | Â Â Â Â Â Â Boxes[box[0],box[1],box[2],Boxes[box[0],box[1],box[2],0]]Â =Â ib |
---|
2739 |     except IndexError: |
---|
2740 | Â Â Â Â Â Â print('too many atoms in box'Â ) |
---|
2741 | Â Â Â Â Â Â continue |
---|
2742 | Â Â #Box content checks with errat.f $ erratv2.cpp ibox1 arrays |
---|
2743 | Â Â indices =Â (-1,0,1) |
---|
2744 |   Units = np.array([[h,k,l] for h in indices for k in indices for l in indices]) |
---|
2745 | Â Â dsmax =Â 3.75**2 |
---|
2746 |   if old: |
---|
2747 | Â Â Â Â dsmax =Â 3.5**2 |
---|
2748 | Â Â chains =Â [] |
---|
2749 | Â Â resIntAct =Â [] |
---|
2750 | Â Â chainIntAct =Â [] |
---|
2751 | Â Â res =Â [] |
---|
2752 | Â Â resNames =Â [] |
---|
2753 | Â Â resIDs =Â {} |
---|
2754 | Â Â resname =Â [] |
---|
2755 | Â Â resID =Â {} |
---|
2756 | Â Â newChain =Â True |
---|
2757 | Â Â intact =Â {'CC':0,'CN':0,'CO':0,'NN':0,'NO':0,'OO':0,'NC':0,'OC':0,'ON':0} |
---|
2758 |   for ia,atom in enumerate(cartAtoms): |
---|
2759 | Â Â Â Â jntact =Â {'CC':0,'CN':0,'CO':0,'NN':0,'NO':0,'OO':0,'NC':0,'OC':0,'ON':0} |
---|
2760 |     if atom[2] not in chains:  #get chain id & save residue sequence from last chain |
---|
2761 | Â Â Â Â Â Â chains.append(atom[2]) |
---|
2762 |       if len(resIntAct): |
---|
2763 | Â Â Â Â Â Â Â Â resIntAct.append(sumintact(intact)) |
---|
2764 | Â Â Â Â Â Â Â Â chainIntAct.append(resIntAct) |
---|
2765 | Â Â Â Â Â Â Â Â resNames +=Â resname |
---|
2766 | Â Â Â Â Â Â Â Â resIDs.update(resID) |
---|
2767 | Â Â Â Â Â Â Â Â res =Â [] |
---|
2768 | Â Â Â Â Â Â Â Â resname =Â [] |
---|
2769 | Â Â Â Â Â Â Â Â resID =Â {} |
---|
2770 | Â Â Â Â Â Â Â Â resIntAct =Â [] |
---|
2771 | Â Â Â Â Â Â Â Â intact =Â {'CC':0,'CN':0,'CO':0,'NN':0,'NO':0,'OO':0,'NC':0,'OC':0,'ON':0} |
---|
2772 | Â Â Â Â Â Â Â Â newChain =Â True |
---|
2773 |     if atom[0] not in res: #new residue, get residue no. |
---|
2774 |       if res and int(res[-1]) != int(atom[0])-1: #a gap in chain - not new chain |
---|
2775 | Â Â Â Â Â Â Â Â intact =Â {'CC':0,'CN':0,'CO':0,'NN':0,'NO':0,'OO':0,'NC':0,'OC':0,'ON':0} |
---|
2776 | Â Â Â Â Â Â Â Â ires =Â int(res[-1]) |
---|
2777 |         for i in range(int(atom[0])-ires-1): |
---|
2778 | Â Â Â Â Â Â Â Â Â Â res.append(str(ires+i+1)) |
---|
2779 | Â Â Â Â Â Â Â Â Â Â resname.append('') |
---|
2780 | Â Â Â Â Â Â Â Â Â Â resIntAct.append(sumintact(intact)) |
---|
2781 | Â Â Â Â Â Â res.append(atom[0]) |
---|
2782 | Â Â Â Â Â Â name =Â '%s-%s%s'%(atom[2],atom[0],atom[1]) |
---|
2783 | Â Â Â Â Â Â resname.append(name) |
---|
2784 | Â Â Â Â Â Â resID[name]Â =Â atom[-1] |
---|
2785 |       if not newChain: |
---|
2786 | Â Â Â Â Â Â Â Â resIntAct.append(sumintact(intact)) |
---|
2787 | Â Â Â Â Â Â intact =Â {'CC':0,'CN':0,'CO':0,'NN':0,'NO':0,'OO':0,'NC':0,'OC':0,'ON':0} |
---|
2788 | Â Â Â Â Â Â newChain =Â False |
---|
2789 | Â Â Â Â ibox =Â iBox[ia]Â Â Â Â Â #box location of atom |
---|
2790 | Â Â Â Â tgts =Â [] |
---|
2791 |     for unit in Units:   #assemble list of all possible target atoms |
---|
2792 | Â Â Â Â Â Â jbox =Â ibox+unit |
---|
2793 |       if np.all(jbox>=0) and np.all((jbox-nbox[:3])<0):        |
---|
2794 | Â Â Â Â Â Â Â Â tgts +=Â list(Boxes[jbox[0],jbox[1],jbox[2]]) |
---|
2795 | Â Â Â Â tgts =Â list(set(tgts)) |
---|
2796 |     tgts = [tgt for tgt in tgts if atom[:3] != cartAtoms[tgt][:3]]  #exclude same residue |
---|
2797 |     tgts = [tgt for tgt in tgts if np.sum((XYZ[ia]-XYZ[tgt])**2) < dsmax] |
---|
2798 | Â Â Â Â ires =Â int(atom[0]) |
---|
2799 |     if old: |
---|
2800 |       if atom[3].strip() == 'C': |
---|
2801 |         tgts = [tgt for tgt in tgts if not (cartAtoms[tgt][3].strip() == 'N' and int(cartAtoms[tgt][0]) in [ires-1,ires+1])] |
---|
2802 |       elif atom[3].strip() == 'N': |
---|
2803 |         tgts = [tgt for tgt in tgts if not (cartAtoms[tgt][3].strip() in ['C','CA'] and int(cartAtoms[tgt][0]) in [ires-1,ires+1])] |
---|
2804 |       elif atom[3].strip() == 'CA': |
---|
2805 |         tgts = [tgt for tgt in tgts if not (cartAtoms[tgt][3].strip() == 'N' and int(cartAtoms[tgt][0]) in [ires-1,ires+1])] |
---|
2806 | Â Â Â Â else: |
---|
2807 |       tgts = [tgt for tgt in tgts if not int(cartAtoms[tgt][0]) in [ires+1,ires+2,ires+3,ires+4,ires+5,ires+6,ires+7,ires+8]] |
---|
2808 |       if atom[3].strip() == 'C': |
---|
2809 |         tgts = [tgt for tgt in tgts if not (cartAtoms[tgt][3].strip() == 'N' and int(cartAtoms[tgt][0]) == ires+1)] |
---|
2810 |       elif atom[3].strip() == 'N': |
---|
2811 |         tgts = [tgt for tgt in tgts if not (cartAtoms[tgt][3].strip() == 'C' and int(cartAtoms[tgt][0]) == ires-1)] |
---|
2812 |     for tgt in tgts: |
---|
2813 | Â Â Â Â Â Â dsqt =Â np.sqrt(np.sum((XYZ[ia]-XYZ[tgt])**2)) |
---|
2814 | Â Â Â Â Â Â mult =Â 1.0 |
---|
2815 |       if dsqt > 3.25 and not old: |
---|
2816 | Â Â Â Â Â Â Â Â mult =Â 2.*(3.75-dsqt) |
---|
2817 | Â Â Â Â Â Â intype =Â atom[4].strip()+cartAtoms[tgt][4].strip() |
---|
2818 |       if 'S' not in intype: |
---|
2819 | Â Â Â Â Â Â Â Â intact[intype]Â +=Â mult |
---|
2820 | Â Â Â Â Â Â Â Â jntact[intype]Â +=Â mult |
---|
2821 | #Â Â Â Â print ia,atom[0]+atom[1]+atom[3],tgts,jntact['CC'],jntact['CN']+jntact['NC'],jntact['CO']+jntact['OC'],jntact['NN'],jntact['NO']+jntact['ON'] |
---|
2822 | Â Â resNames +=Â resname |
---|
2823 | Â Â resIDs.update(resID) |
---|
2824 | Â Â resIntAct.append(sumintact(intact)) |
---|
2825 | Â Â chainIntAct.append(resIntAct) |
---|
2826 | Â Â chainProb =Â [] |
---|
2827 |   for ich,chn in enumerate(chains): |
---|
2828 | Â Â Â Â IntAct =Â chainIntAct[ich] |
---|
2829 | Â Â Â Â nRes =Â len(IntAct) |
---|
2830 | Â Â Â Â Probs =Â [0.,0.,0.,0.]Â Â #skip 1st 4 residues in chain |
---|
2831 |     for i in range(4,nRes-4): |
---|
2832 |       if resNames[i]: |
---|
2833 | Â Â Â Â Â Â Â Â mtrx =Â np.zeros(5) |
---|
2834 | Â Â Â Â Â Â Â Â summ =Â 0. |
---|
2835 |         for j in range(i-4,i+5): |
---|
2836 | Â Â Â Â Â Â Â Â Â Â summ +=Â np.sum(np.array(list(IntAct[j].values()))) |
---|
2837 |           if old: |
---|
2838 | Â Â Â Â Â Â Â Â Â Â Â Â mtrx[0]Â +=Â IntAct[j]['CC'] |
---|
2839 | Â Â Â Â Â Â Â Â Â Â Â Â mtrx[1]Â +=Â IntAct[j]['CO'] |
---|
2840 | Â Â Â Â Â Â Â Â Â Â Â Â mtrx[2]Â +=Â IntAct[j]['NN'] |
---|
2841 | Â Â Â Â Â Â Â Â Â Â Â Â mtrx[3]Â +=Â IntAct[j]['NO'] |
---|
2842 | Â Â Â Â Â Â Â Â Â Â Â Â mtrx[4]Â +=Â IntAct[j]['OO'] |
---|
2843 | Â Â Â Â Â Â Â Â Â Â else: |
---|
2844 | Â Â Â Â Â Â Â Â Â Â Â Â mtrx[0]Â +=Â IntAct[j]['CC'] |
---|
2845 | Â Â Â Â Â Â Â Â Â Â Â Â mtrx[1]Â +=Â IntAct[j]['CN'] |
---|
2846 | Â Â Â Â Â Â Â Â Â Â Â Â mtrx[2]Â +=Â IntAct[j]['CO'] |
---|
2847 | Â Â Â Â Â Â Â Â Â Â Â Â mtrx[3]Â +=Â IntAct[j]['NN'] |
---|
2848 | Â Â Â Â Â Â Â Â Â Â Â Â mtrx[4]Â +=Â IntAct[j]['NO'] |
---|
2849 | Â Â Â Â Â Â Â Â mtrx /=Â summ |
---|
2850 | Â Â #Â Â Â Â Â Â print i+1,mtrx*summ |
---|
2851 |         if old: |
---|
2852 | Â Â Â Â Â Â Â Â Â Â mtrx -=Â avg_old |
---|
2853 | Â Â Â Â Â Â Â Â Â Â prob =Â np.inner(np.inner(mtrx,b1_old),mtrx) |
---|
2854 | Â Â Â Â Â Â Â Â else: |
---|
2855 | Â Â Â Â Â Â Â Â Â Â mtrx -=Â avg |
---|
2856 | Â Â Â Â Â Â Â Â Â Â prob =Â np.inner(np.inner(mtrx,b1),mtrx) |
---|
2857 | Â Â Â Â Â Â else:Â Â Â Â #skip the gaps |
---|
2858 | Â Â Â Â Â Â Â Â prob =Â 0.0 |
---|
2859 | Â Â Â Â Â Â Probs.append(prob) |
---|
2860 | Â Â Â Â Probs +=Â 4*[0.,]Â Â Â Â #skip last 4 residues in chain |
---|
2861 | Â Â Â Â chainProb +=Â Probs |
---|
2862 |   return resNames,chainProb,resIDs |
---|
2863 | Â Â |
---|
2864 | ################################################################################ |
---|
2865 | ##### Texture fitting stuff |
---|
2866 | ################################################################################ |
---|
2867 | |
---|
2868 | def FitTexture(General,Gangls,refData,keyList,pgbar): |
---|
2869 |   import pytexture as ptx |
---|
2870 | Â Â ptx.pyqlmninit()Â Â Â Â Â Â #initialize fortran arrays for spherical harmonics |
---|
2871 | Â Â |
---|
2872 |   def printSpHarm(textureData,SHtextureSig): |
---|
2873 |     print ('\n Spherical harmonics texture: Order:' + str(textureData['Order'])) |
---|
2874 | Â Â Â Â names =Â ['omega','chi','phi'] |
---|
2875 | Â Â Â Â namstr =Â 'Â names :' |
---|
2876 | Â Â Â Â ptstr =Â 'Â values:' |
---|
2877 |     sigstr = ' esds :' |
---|
2878 |     for name in names: |
---|
2879 | Â Â Â Â Â Â namstr +=Â '%12s'%('Sample '+name) |
---|
2880 | Â Â Â Â Â Â ptstr +=Â '%12.3f'%(textureData['Sample '+name][1]) |
---|
2881 |       if 'Sample '+name in SHtextureSig: |
---|
2882 | Â Â Â Â Â Â Â Â sigstr +=Â '%12.3f'%(SHtextureSig['Sample '+name]) |
---|
2883 | Â Â Â Â Â Â else: |
---|
2884 | Â Â Â Â Â Â Â Â sigstr +=Â 12*' ' |
---|
2885 |     print (namstr) |
---|
2886 |     print (ptstr) |
---|
2887 |     print (sigstr) |
---|
2888 |     print ('\n Texture coefficients:') |
---|
2889 | Â Â Â Â SHcoeff =Â textureData['SH Coeff'][1] |
---|
2890 | Â Â Â Â SHkeys =Â list(SHcoeff.keys()) |
---|
2891 | Â Â Â Â nCoeff =Â len(SHcoeff) |
---|
2892 | Â Â Â Â nBlock =Â nCoeff//10+1 |
---|
2893 | Â Â Â Â iBeg =Â 0 |
---|
2894 | Â Â Â Â iFin =Â min(iBeg+10,nCoeff) |
---|
2895 |     for block in range(nBlock): |
---|
2896 | Â Â Â Â Â Â namstr =Â 'Â names :' |
---|
2897 | Â Â Â Â Â Â ptstr =Â 'Â values:' |
---|
2898 |       sigstr = ' esds :' |
---|
2899 |       for name in SHkeys[iBeg:iFin]: |
---|
2900 |         if 'C' in name: |
---|
2901 | Â Â Â Â Â Â Â Â Â Â namstr +=Â '%12s'%(name) |
---|
2902 | Â Â Â Â Â Â Â Â Â Â ptstr +=Â '%12.3f'%(SHcoeff[name]) |
---|
2903 |           if name in SHtextureSig: |
---|
2904 | Â Â Â Â Â Â Â Â Â Â Â Â sigstr +=Â '%12.3f'%(SHtextureSig[name]) |
---|
2905 | Â Â Â Â Â Â Â Â Â Â else: |
---|
2906 | Â Â Â Â Â Â Â Â Â Â Â Â sigstr +=Â 12*' ' |
---|
2907 |       print (namstr) |
---|
2908 |       print (ptstr) |
---|
2909 |       print (sigstr) |
---|
2910 | Â Â Â Â Â Â iBeg +=Â 10 |
---|
2911 | Â Â Â Â Â Â iFin =Â min(iBeg+10,nCoeff) |
---|
2912 | Â Â Â Â Â Â |
---|
2913 |   def Dict2Values(parmdict, varylist): |
---|
2914 | Â Â Â Â '''Use before call to leastsq to setup list of values for the parameters |
---|
2915 | Â Â Â Â in parmdict, as selected by key in varylist''' |
---|
2916 |     return [parmdict[key] for key in varylist] |
---|
2917 | Â Â Â Â |
---|
2918 |   def Values2Dict(parmdict, varylist, values): |
---|
2919 | Â Â Â Â ''' Use after call to leastsq to update the parameter dictionary with |
---|
2920 | Â Â Â Â values corresponding to keys in varylist''' |
---|
2921 | Â Â Â Â parmdict.update(list(zip(varylist,values))) |
---|
2922 | Â Â Â Â |
---|
2923 |   def errSpHarm(values,SGData,cell,Gangls,shModel,refData,parmDict,varyList,pgbar): |
---|
2924 | Â Â Â Â parmDict.update(list(zip(varyList,values))) |
---|
2925 | Â Â Â Â Mat =Â np.empty(0) |
---|
2926 | Â Â Â Â sumObs =Â 0 |
---|
2927 | Â Â Â Â Sangls =Â [parmDict['Sample '+'omega'],parmDict['Sample '+'chi'],parmDict['Sample '+'phi']] |
---|
2928 |     for hist in Gangls.keys(): |
---|
2929 | Â Â Â Â Â Â Refs =Â refData[hist] |
---|
2930 | Â Â Â Â Â Â Refs[:,5]Â =Â np.where(Refs[:,5]>0.,Refs[:,5],0.) |
---|
2931 | Â Â Â Â Â Â wt =Â 1./np.sqrt(np.fmax(Refs[:,4],.25)) |
---|
2932 | #Â Â Â Â Â Â wt = 1./np.max(Refs[:,4],.25) |
---|
2933 | Â Â Â Â Â Â sumObs +=Â np.sum(wt*Refs[:,5]) |
---|
2934 | Â Â Â Â Â Â Refs[:,6]Â =Â 1. |
---|
2935 | Â Â Â Â Â Â H =Â Refs[:,:3] |
---|
2936 | Â Â Â Â Â Â phi,beta =Â G2lat.CrsAng(H,cell,SGData) |
---|
2937 | Â Â Â Â Â Â psi,gam,x,x =Â G2lat.SamAng(Refs[:,3]/2.,Gangls[hist],Sangls,False)Â #assume not Bragg-Brentano! |
---|
2938 |       for item in parmDict: |
---|
2939 |         if 'C' in item: |
---|
2940 | Â Â Â Â Â Â Â Â Â Â L,M,N =Â eval(item.strip('C')) |
---|
2941 | Â Â Â Â Â Â Â Â Â Â Kcl =Â G2lat.GetKcl(L,N,SGData['SGLaue'],phi,beta) |
---|
2942 | Â Â Â Â Â Â Â Â Â Â Ksl,x,x =Â G2lat.GetKsl(L,M,shModel,psi,gam) |
---|
2943 | Â Â Â Â Â Â Â Â Â Â Lnorm =Â G2lat.Lnorm(L) |
---|
2944 | Â Â Â Â Â Â Â Â Â Â Refs[:,6]Â +=Â parmDict[item]*Lnorm*Kcl*Ksl |
---|
2945 | Â Â Â Â Â Â mat =Â wt*(Refs[:,5]-Refs[:,6]) |
---|
2946 | Â Â Â Â Â Â Mat =Â np.concatenate((Mat,mat)) |
---|
2947 | Â Â Â Â sumD =Â np.sum(np.abs(Mat)) |
---|
2948 | Â Â Â Â R =Â min(100.,100.*sumD/sumObs) |
---|
2949 | Â Â Â Â pgbar.Update(R,newmsg='Residual = %5.2f'%(R)) |
---|
2950 |     print (' Residual: %.3f%%'%(R)) |
---|
2951 |     return Mat |
---|
2952 | Â Â Â Â |
---|
2953 |   def dervSpHarm(values,SGData,cell,Gangls,shModel,refData,parmDict,varyList,pgbar): |
---|
2954 | Â Â Â Â Mat =Â np.empty(0) |
---|
2955 | Â Â Â Â Sangls =Â [parmDict['Sample omega'],parmDict['Sample chi'],parmDict['Sample phi']] |
---|
2956 |     for hist in Gangls.keys(): |
---|
2957 | Â Â Â Â Â Â mat =Â np.zeros((len(varyList),len(refData[hist]))) |
---|
2958 | Â Â Â Â Â Â Refs =Â refData[hist] |
---|
2959 | Â Â Â Â Â Â H =Â Refs[:,:3] |
---|
2960 | Â Â Â Â Â Â wt =Â 1./np.sqrt(np.fmax(Refs[:,4],.25)) |
---|
2961 | #Â Â Â Â Â Â wt = 1./np.max(Refs[:,4],.25) |
---|
2962 | Â Â Â Â Â Â phi,beta =Â G2lat.CrsAng(H,cell,SGData) |
---|
2963 | Â Â Â Â Â Â psi,gam,dPdA,dGdA =Â G2lat.SamAng(Refs[:,3]/2.,Gangls[hist],Sangls,False)Â #assume not Bragg-Brentano! |
---|
2964 |       for j,item in enumerate(varyList): |
---|
2965 |         if 'C' in item: |
---|
2966 | Â Â Â Â Â Â Â Â Â Â L,M,N =Â eval(item.strip('C')) |
---|
2967 | Â Â Â Â Â Â Â Â Â Â Kcl =Â G2lat.GetKcl(L,N,SGData['SGLaue'],phi,beta) |
---|
2968 | Â Â Â Â Â Â Â Â Â Â Ksl,dKdp,dKdg =Â G2lat.GetKsl(L,M,shModel,psi,gam) |
---|
2969 | Â Â Â Â Â Â Â Â Â Â Lnorm =Â G2lat.Lnorm(L) |
---|
2970 | Â Â Â Â Â Â Â Â Â Â mat[j]Â =Â -wt*Lnorm*Kcl*Ksl |
---|
2971 |           for k,itema in enumerate(['Sample omega','Sample chi','Sample phi']): |
---|
2972 | Â Â Â Â Â Â Â Â Â Â Â Â try: |
---|
2973 | Â Â Â Â Â Â Â Â Â Â Â Â Â Â l =Â varyList.index(itema) |
---|
2974 | Â Â Â Â Â Â Â Â Â Â Â Â Â Â mat[l]Â -=Â parmDict[item]*wt*Lnorm*Kcl*(dKdp*dPdA[k]+dKdg*dGdA[k]) |
---|
2975 |             except ValueError: |
---|
2976 | Â Â Â Â Â Â Â Â Â Â Â Â Â Â pass |
---|
2977 |       if len(Mat): |
---|
2978 | Â Â Â Â Â Â Â Â Mat =Â np.concatenate((Mat,mat.T)) |
---|
2979 | Â Â Â Â Â Â else: |
---|
2980 | Â Â Â Â Â Â Â Â Mat =Â mat.T |
---|
2981 |     print ('deriv') |
---|
2982 |     return Mat |
---|
2983 | |
---|
2984 |   print (' Fit texture for '+General['Name']) |
---|
2985 | Â Â SGData =Â General['SGData'] |
---|
2986 | Â Â cell =Â General['Cell'][1:7] |
---|
2987 | Â Â Texture =Â General['SH Texture'] |
---|
2988 |   if not Texture['Order']: |
---|
2989 |     return 'No spherical harmonics coefficients' |
---|
2990 | Â Â varyList =Â [] |
---|
2991 | Â Â parmDict =Â copy.copy(Texture['SH Coeff'][1]) |
---|
2992 |   for item in ['Sample omega','Sample chi','Sample phi']: |
---|
2993 | Â Â Â Â parmDict[item]Â =Â Texture[item][1] |
---|
2994 |     if Texture[item][0]: |
---|
2995 | Â Â Â Â Â Â varyList.append(item) |
---|
2996 |   if Texture['SH Coeff'][0]: |
---|
2997 | Â Â Â Â varyList +=Â list(Texture['SH Coeff'][1].keys()) |
---|
2998 |   while True: |
---|
2999 | Â Â Â Â begin =Â time.time() |
---|
3000 |     values = np.array(Dict2Values(parmDict, varyList)) |
---|
3001 | Â Â Â Â result =Â so.leastsq(errSpHarm,values,Dfun=dervSpHarm,full_output=True,ftol=1.e-6, |
---|
3002 | Â Â Â Â Â Â args=(SGData,cell,Gangls,Texture['Model'],refData,parmDict,varyList,pgbar)) |
---|
3003 | Â Â Â Â ncyc =Â int(result[2]['nfev']//2) |
---|
3004 |     if ncyc: |
---|
3005 |       runtime = time.time()-begin  |
---|
3006 | Â Â Â Â Â Â chisq =Â np.sum(result[2]['fvec']**2) |
---|
3007 |       Values2Dict(parmDict, varyList, result[0]) |
---|
3008 | Â Â Â Â Â Â GOF =Â chisq/(len(result[2]['fvec'])-len(varyList))Â Â Â Â #reduced chi^2 |
---|
3009 |       print ('Number of function calls: %d Number of observations: %d Number of parameters: %d'%(result[2]['nfev'],len(result[2]['fvec']),len(varyList))) |
---|
3010 |       print ('refinement time = %8.3fs, %8.3fs/cycle'%(runtime,runtime/ncyc)) |
---|
3011 | Â Â Â Â Â Â try: |
---|
3012 | Â Â Â Â Â Â Â Â sig =Â np.sqrt(np.diag(result[1])*GOF) |
---|
3013 |         if np.any(np.isnan(sig)): |
---|
3014 |           print ('*** Least squares aborted - some invalid esds possible ***') |
---|
3015 |         break          #refinement succeeded - finish up! |
---|
3016 |       except ValueError:     #result[1] is None on singular matrix |
---|
3017 |         print ('**** Refinement failed - singular matrix ****') |
---|
3018 |         return None |
---|
3019 | Â Â Â Â else: |
---|
3020 | Â Â Â Â Â Â break |
---|
3021 | Â Â |
---|
3022 |   if ncyc: |
---|
3023 |     for parm in parmDict: |
---|
3024 |       if 'C' in parm: |
---|
3025 | Â Â Â Â Â Â Â Â Texture['SH Coeff'][1][parm]Â =Â parmDict[parm] |
---|
3026 | Â Â Â Â Â Â else: |
---|
3027 | Â Â Â Â Â Â Â Â Texture[parm][1]Â =Â parmDict[parm]Â |
---|
3028 | Â Â Â Â sigDict =Â dict(zip(varyList,sig)) |
---|
3029 | Â Â Â Â printSpHarm(Texture,sigDict) |
---|
3030 | Â Â Â Â |
---|
3031 |   return None |
---|
3032 | Â Â |
---|
3033 | ################################################################################ |
---|
3034 | ##### Fourier & charge flip stuff |
---|
3035 | ################################################################################ |
---|
3036 | |
---|
3037 | def adjHKLmax(SGData,Hmax): |
---|
3038 | Â Â '''default doc string |
---|
3039 | Â Â |
---|
3040 | Â Â :param type name: description |
---|
3041 | Â Â |
---|
3042 | Â Â :returns: type name: description |
---|
3043 | Â Â |
---|
3044 | Â Â ''' |
---|
3045 |   if SGData['SGLaue'] in ['3','3m1','31m','6/m','6/mmm']: |
---|
3046 | Â Â Â Â Hmax[0]Â =Â int(math.ceil(Hmax[0]/6.))*6 |
---|
3047 | Â Â Â Â Hmax[1]Â =Â int(math.ceil(Hmax[1]/6.))*6 |
---|
3048 | Â Â Â Â Hmax[2]Â =Â int(math.ceil(Hmax[2]/4.))*4 |
---|
3049 | Â Â else: |
---|
3050 | Â Â Â Â Hmax[0]Â =Â int(math.ceil(Hmax[0]/4.))*4 |
---|
3051 | Â Â Â Â Hmax[1]Â =Â int(math.ceil(Hmax[1]/4.))*4 |
---|
3052 | Â Â Â Â Hmax[2]Â =Â int(math.ceil(Hmax[2]/4.))*4 |
---|
3053 | |
---|
3054 | def OmitMap(data,reflDict,pgbar=None): |
---|
3055 | Â Â '''default doc string |
---|
3056 | Â Â |
---|
3057 | Â Â :param type name: description |
---|
3058 | Â Â |
---|
3059 | Â Â :returns: type name: description |
---|
3060 | Â Â |
---|
3061 | Â Â ''' |
---|
3062 | Â Â generalData =Â data['General'] |
---|
3063 |   if not generalData['Map']['MapType']: |
---|
3064 |     print ('**** ERROR - Fourier map not defined') |
---|
3065 | Â Â Â Â return |
---|
3066 | Â Â mapData =Â generalData['Map'] |
---|
3067 | Â Â dmin =Â mapData['Resolution'] |
---|
3068 | Â Â SGData =Â generalData['SGData'] |
---|
3069 |   SGMT = np.array([ops[0].T for ops in SGData['SGOps']]) |
---|
3070 |   SGT = np.array([ops[1] for ops in SGData['SGOps']]) |
---|
3071 | Â Â cell =Â generalData['Cell'][1:8]Â Â Â Â |
---|
3072 | Â Â A =Â G2lat.cell2A(cell[:6]) |
---|
3073 | Â Â Hmax =Â np.asarray(G2lat.getHKLmax(dmin,SGData,A),dtype='i')+1 |
---|
3074 | Â Â adjHKLmax(SGData,Hmax) |
---|
3075 | Â Â Fhkl =Â np.zeros(shape=2*Hmax,dtype='c16') |
---|
3076 | Â Â time0 =Â time.time() |
---|
3077 |   for iref,ref in enumerate(reflDict['RefList']): |
---|
3078 |     if ref[4] >= dmin: |
---|
3079 | Â Â Â Â Â Â Fosq,Fcsq,ph =Â ref[8:11] |
---|
3080 | Â Â Â Â Â Â Uniq =Â np.inner(ref[:3],SGMT) |
---|
3081 | Â Â Â Â Â Â Phi =Â np.inner(ref[:3],SGT) |
---|
3082 |       for i,hkl in enumerate(Uniq):    #uses uniq |
---|
3083 | Â Â Â Â Â Â Â Â hkl =Â np.asarray(hkl,dtype='i') |
---|
3084 | Â Â Â Â Â Â Â Â dp =Â 360.*Phi[i]Â Â Â Â Â Â Â Â #and phi |
---|
3085 | Â Â Â Â Â Â Â Â a =Â cosd(ph+dp) |
---|
3086 | Â Â Â Â Â Â Â Â b =Â sind(ph+dp) |
---|
3087 | Â Â Â Â Â Â Â Â phasep =Â complex(a,b) |
---|
3088 | Â Â Â Â Â Â Â Â phasem =Â complex(a,-b) |
---|
3089 |         if '2Fo-Fc' in mapData['MapType']: |
---|
3090 | Â Â Â Â Â Â Â Â Â Â F =Â 2.*np.sqrt(Fosq)-np.sqrt(Fcsq) |
---|
3091 | Â Â Â Â Â Â Â Â else: |
---|
3092 | Â Â Â Â Â Â Â Â Â Â F =Â np.sqrt(Fosq) |
---|
3093 | Â Â Â Â Â Â Â Â h,k,l =Â hkl+Hmax |
---|
3094 | Â Â Â Â Â Â Â Â Fhkl[h,k,l]Â =Â F*phasep |
---|
3095 | Â Â Â Â Â Â Â Â h,k,l =Â -hkl+Hmax |
---|
3096 | Â Â Â Â Â Â Â Â Fhkl[h,k,l]Â =Â F*phasem |
---|
3097 | Â Â rho0 =Â fft.fftn(fft.fftshift(Fhkl))/cell[6] |
---|
3098 | Â Â M =Â np.mgrid[0:4,0:4,0:4] |
---|
3099 | Â Â blkIds =Â np.array(list(zip(M[0].flatten(),M[1].flatten(),M[2].flatten()))) |
---|
3100 | Â Â iBeg =Â blkIds*rho0.shape//4 |
---|
3101 | Â Â iFin =Â (blkIds+1)*rho0.shape//4 |
---|
3102 | Â Â rho_omit =Â np.zeros_like(rho0) |
---|
3103 | Â Â nBlk =Â 0 |
---|
3104 |   for iB,iF in zip(iBeg,iFin): |
---|
3105 | Â Â Â Â rho1 =Â np.copy(rho0) |
---|
3106 | Â Â Â Â rho1[iB[0]:iF[0],iB[1]:iF[1],iB[2]:iF[2]]Â =Â 0. |
---|
3107 | Â Â Â Â Fnew =Â fft.ifftshift(fft.ifftn(rho1)) |
---|
3108 | Â Â Â Â Fnew =Â np.where(Fnew,Fnew,1.0)Â Â Â Â Â Â #avoid divide by zero |
---|
3109 | Â Â Â Â phase =Â Fnew/np.absolute(Fnew) |
---|
3110 | Â Â Â Â OFhkl =Â np.absolute(Fhkl)*phase |
---|
3111 | Â Â Â Â rho1 =Â np.real(fft.fftn(fft.fftshift(OFhkl)))*(1.+0j) |
---|
3112 | Â Â Â Â rho_omit[iB[0]:iF[0],iB[1]:iF[1],iB[2]:iF[2]]Â =Â np.copy(rho1[iB[0]:iF[0],iB[1]:iF[1],iB[2]:iF[2]]) |
---|
3113 | Â Â Â Â nBlk +=Â 1 |
---|
3114 | Â Â Â Â pgbar.Update(nBlk) |
---|
3115 | Â Â mapData['rho']Â =Â np.real(rho_omit)/cell[6] |
---|
3116 | Â Â mapData['rhoMax']Â =Â max(np.max(mapData['rho']),-np.min(mapData['rho'])) |
---|
3117 | Â Â mapData['minmax']Â =Â [np.max(mapData['rho']),np.min(mapData['rho'])] |
---|
3118 |   print ('Omit map time: %.4f no. elements: %d'%(time.time()-time0,Fhkl.size)) |
---|
3119 |   return mapData |
---|
3120 | Â Â |
---|
3121 | def FourierMap(data,reflDict): |
---|
3122 | Â Â '''default doc string |
---|
3123 | Â Â |
---|
3124 | Â Â :param type name: description |
---|
3125 | Â Â |
---|
3126 | Â Â :returns: type name: description |
---|
3127 | Â Â |
---|
3128 | Â Â ''' |
---|
3129 | Â Â generalData =Â data['General'] |
---|
3130 | Â Â mapData =Â generalData['Map'] |
---|
3131 | Â Â dmin =Â mapData['Resolution'] |
---|
3132 | Â Â SGData =Â generalData['SGData'] |
---|
3133 |   SGMT = np.array([ops[0].T for ops in SGData['SGOps']]) |
---|
3134 |   SGT = np.array([ops[1] for ops in SGData['SGOps']]) |
---|
3135 | Â Â cell =Â generalData['Cell'][1:8]Â Â Â Â |
---|
3136 | Â Â A =Â G2lat.cell2A(cell[:6]) |
---|
3137 | Â Â Hmax =Â np.asarray(G2lat.getHKLmax(dmin,SGData,A),dtype='i')+1 |
---|
3138 | Â Â adjHKLmax(SGData,Hmax) |
---|
3139 | Â Â Fhkl =Â np.zeros(shape=2*Hmax,dtype='c16') |
---|
3140 | #Â Â Fhkl[0,0,0] = generalData['F000X'] |
---|
3141 | Â Â time0 =Â time.time() |
---|
3142 |   for iref,ref in enumerate(reflDict['RefList']): |
---|
3143 |     if ref[4] > dmin: |
---|
3144 | Â Â Â Â Â Â Fosq,Fcsq,ph =Â ref[8:11] |
---|
3145 | Â Â Â Â Â Â Uniq =Â np.inner(ref[:3],SGMT) |
---|
3146 | Â Â Â Â Â Â Phi =Â np.inner(ref[:3],SGT) |
---|
3147 |       for i,hkl in enumerate(Uniq):    #uses uniq |
---|
3148 | Â Â Â Â Â Â Â Â hkl =Â np.asarray(hkl,dtype='i') |
---|
3149 | Â Â Â Â Â Â Â Â dp =Â 360.*Phi[i]Â Â Â Â Â Â Â Â #and phi |
---|
3150 | Â Â Â Â Â Â Â Â a =Â cosd(ph+dp) |
---|
3151 | Â Â Â Â Â Â Â Â b =Â sind(ph+dp) |
---|
3152 | Â Â Â Â Â Â Â Â phasep =Â complex(a,b) |
---|
3153 | Â Â Â Â Â Â Â Â phasem =Â complex(a,-b) |
---|
3154 |         if 'Fobs' in mapData['MapType']: |
---|
3155 | Â Â Â Â Â Â Â Â Â Â F =Â np.where(Fosq>0.,np.sqrt(Fosq),0.) |
---|
3156 | Â Â Â Â Â Â Â Â Â Â h,k,l =Â hkl+Hmax |
---|
3157 | Â Â Â Â Â Â Â Â Â Â Fhkl[h,k,l]Â =Â F*phasep |
---|
3158 | Â Â Â Â Â Â Â Â Â Â h,k,l =Â -hkl+Hmax |
---|
3159 | Â Â Â Â Â Â Â Â Â Â Fhkl[h,k,l]Â =Â F*phasem |
---|
3160 |         elif 'Fcalc' in mapData['MapType']: |
---|
3161 | Â Â Â Â Â Â Â Â Â Â F =Â np.sqrt(Fcsq) |
---|
3162 | Â Â Â Â Â Â Â Â Â Â h,k,l =Â hkl+Hmax |
---|
3163 | Â Â Â Â Â Â Â Â Â Â Fhkl[h,k,l]Â =Â F*phasep |
---|
3164 | Â Â Â Â Â Â Â Â Â Â h,k,l =Â -hkl+Hmax |
---|
3165 | Â Â Â Â Â Â Â Â Â Â Fhkl[h,k,l]Â =Â F*phasem |
---|
3166 |         elif 'delt-F' in mapData['MapType']: |
---|
3167 | Â Â Â Â Â Â Â Â Â Â dF =Â np.where(Fosq>0.,np.sqrt(Fosq),0.)-np.sqrt(Fcsq) |
---|
3168 | Â Â Â Â Â Â Â Â Â Â h,k,l =Â hkl+Hmax |
---|
3169 | Â Â Â Â Â Â Â Â Â Â Fhkl[h,k,l]Â =Â dF*phasep |
---|
3170 | Â Â Â Â Â Â Â Â Â Â h,k,l =Â -hkl+Hmax |
---|
3171 | Â Â Â Â Â Â Â Â Â Â Fhkl[h,k,l]Â =Â dF*phasem |
---|
3172 |         elif '2*Fo-Fc' in mapData['MapType']: |
---|
3173 | Â Â Â Â Â Â Â Â Â Â F =Â 2.*np.where(Fosq>0.,np.sqrt(Fosq),0.)-np.sqrt(Fcsq) |
---|
3174 | Â Â Â Â Â Â Â Â Â Â h,k,l =Â hkl+Hmax |
---|
3175 | Â Â Â Â Â Â Â Â Â Â Fhkl[h,k,l]Â =Â F*phasep |
---|
3176 | Â Â Â Â Â Â Â Â Â Â h,k,l =Â -hkl+Hmax |
---|
3177 | Â Â Â Â Â Â Â Â Â Â Fhkl[h,k,l]Â =Â F*phasem |
---|
3178 |         elif 'Patterson' in mapData['MapType']: |
---|
3179 | Â Â Â Â Â Â Â Â Â Â h,k,l =Â hkl+Hmax |
---|
3180 | Â Â Â Â Â Â Â Â Â Â Fhkl[h,k,l]Â =Â complex(Fosq,0.) |
---|
3181 | Â Â Â Â Â Â Â Â Â Â h,k,l =Â -hkl+Hmax |
---|
3182 | Â Â Â Â Â Â Â Â Â Â Fhkl[h,k,l]Â =Â complex(Fosq,0.) |
---|
3183 | Â Â rho =Â fft.fftn(fft.fftshift(Fhkl))/cell[6] |
---|
3184 |   print ('Fourier map time: %.4f'%(time.time()-time0),'no. elements: %d'%(Fhkl.size)) |
---|
3185 | Â Â mapData['Type']Â =Â reflDict['Type'] |
---|
3186 | Â Â mapData['rho']Â =Â np.real(rho) |
---|
3187 | Â Â mapData['rhoMax']Â =Â max(np.max(mapData['rho']),-np.min(mapData['rho'])) |
---|
3188 | Â Â mapData['minmax']Â =Â [np.max(mapData['rho']),np.min(mapData['rho'])] |
---|
3189 | Â Â |
---|
3190 | def Fourier4DMap(data,reflDict): |
---|
3191 | Â Â '''default doc string |
---|
3192 | Â Â |
---|
3193 | Â Â :param type name: description |
---|
3194 | Â Â |
---|
3195 | Â Â :returns: type name: description |
---|
3196 | Â Â |
---|
3197 | Â Â ''' |
---|
3198 | Â Â generalData =Â data['General'] |
---|
3199 | Â Â map4DData =Â generalData['4DmapData'] |
---|
3200 | Â Â mapData =Â generalData['Map'] |
---|
3201 | Â Â dmin =Â mapData['Resolution'] |
---|
3202 | Â Â SGData =Â generalData['SGData'] |
---|
3203 | Â Â SSGData =Â generalData['SSGData'] |
---|
3204 |   SSGMT = np.array([ops[0].T for ops in SSGData['SSGOps']]) |
---|
3205 |   SSGT = np.array([ops[1] for ops in SSGData['SSGOps']]) |
---|
3206 | Â Â cell =Â generalData['Cell'][1:8]Â Â Â Â |
---|
3207 | Â Â A =Â G2lat.cell2A(cell[:6]) |
---|
3208 | Â Â maxM =Â 4 |
---|
3209 | Â Â Hmax =Â G2lat.getHKLmax(dmin,SGData,A)+[maxM,] |
---|
3210 | Â Â adjHKLmax(SGData,Hmax) |
---|
3211 | Â Â Hmax =Â np.asarray(Hmax,dtype='i')+1 |
---|
3212 | Â Â Fhkl =Â np.zeros(shape=2*Hmax,dtype='c16') |
---|
3213 | Â Â time0 =Â time.time() |
---|
3214 |   for iref,ref in enumerate(reflDict['RefList']): |
---|
3215 |     if ref[5] > dmin: |
---|
3216 | Â Â Â Â Â Â Fosq,Fcsq,ph =Â ref[9:12] |
---|
3217 | Â Â Â Â Â Â Fosq =Â np.where(Fosq>0.,Fosq,0.)Â Â #can't use Fo^2 < 0 |
---|
3218 | Â Â Â Â Â Â Uniq =Â np.inner(ref[:4],SSGMT) |
---|
3219 | Â Â Â Â Â Â Phi =Â np.inner(ref[:4],SSGT) |
---|
3220 |       for i,hkl in enumerate(Uniq):    #uses uniq |
---|
3221 | Â Â Â Â Â Â Â Â hkl =Â np.asarray(hkl,dtype='i') |
---|
3222 | Â Â Â Â Â Â Â Â dp =Â 360.*Phi[i]Â Â Â Â Â Â Â Â #and phi |
---|
3223 | Â Â Â Â Â Â Â Â a =Â cosd(ph+dp) |
---|
3224 | Â Â Â Â Â Â Â Â b =Â sind(ph+dp) |
---|
3225 | Â Â Â Â Â Â Â Â phasep =Â complex(a,b) |
---|
3226 | Â Â Â Â Â Â Â Â phasem =Â complex(a,-b) |
---|
3227 |         if 'Fobs' in mapData['MapType']: |
---|
3228 | Â Â Â Â Â Â Â Â Â Â F =Â np.sqrt(Fosq) |
---|
3229 | Â Â Â Â Â Â Â Â Â Â h,k,l,m =Â hkl+Hmax |
---|
3230 | Â Â Â Â Â Â Â Â Â Â Fhkl[h,k,l,m]Â =Â F*phasep |
---|
3231 | Â Â Â Â Â Â Â Â Â Â h,k,l,m =Â -hkl+Hmax |
---|
3232 | Â Â Â Â Â Â Â Â Â Â Fhkl[h,k,l,m]Â =Â F*phasem |
---|
3233 |         elif 'Fcalc' in mapData['MapType']: |
---|
3234 | Â Â Â Â Â Â Â Â Â Â F =Â np.sqrt(Fcsq) |
---|
3235 | Â Â Â Â Â Â Â Â Â Â h,k,l,m =Â hkl+Hmax |
---|
3236 | Â Â Â Â Â Â Â Â Â Â Fhkl[h,k,l,m]Â =Â F*phasep |
---|
3237 | Â Â Â Â Â Â Â Â Â Â h,k,l,m =Â -hkl+Hmax |
---|
3238 |           Fhkl[h,k,l,m] = F*phasem          |
---|
3239 |         elif 'delt-F' in mapData['MapType']: |
---|
3240 | Â Â Â Â Â Â Â Â Â Â dF =Â np.sqrt(Fosq)-np.sqrt(Fcsq) |
---|
3241 | Â Â Â Â Â Â Â Â Â Â h,k,l,m =Â hkl+Hmax |
---|
3242 | Â Â Â Â Â Â Â Â Â Â Fhkl[h,k,l,m]Â =Â dF*phasep |
---|
3243 | Â Â Â Â Â Â Â Â Â Â h,k,l,m =Â -hkl+Hmax |
---|
3244 | Â Â Â Â Â Â Â Â Â Â Fhkl[h,k,l,m]Â =Â dF*phasem |
---|
3245 | Â Â SSrho =Â fft.fftn(fft.fftshift(Fhkl))/cell[6]Â Â Â Â Â #4D map |
---|
3246 | Â Â rho =Â fft.fftn(fft.fftshift(Fhkl[:,:,:,maxM+1]))/cell[6]Â Â #3D map |
---|
3247 | Â Â map4DData['rho']Â =Â np.real(SSrho) |
---|
3248 | Â Â map4DData['rhoMax']Â =Â max(np.max(map4DData['rho']),-np.min(map4DData['rho'])) |
---|
3249 | Â Â map4DData['minmax']Â =Â [np.max(map4DData['rho']),np.min(map4DData['rho'])] |
---|
3250 | Â Â map4DData['Type']Â =Â reflDict['Type'] |
---|
3251 | Â Â mapData['Type']Â =Â reflDict['Type'] |
---|
3252 | Â Â mapData['rho']Â =Â np.real(rho) |
---|
3253 | Â Â mapData['rhoMax']Â =Â max(np.max(mapData['rho']),-np.min(mapData['rho'])) |
---|
3254 | Â Â mapData['minmax']Â =Â [np.max(mapData['rho']),np.min(mapData['rho'])] |
---|
3255 |   print ('Fourier map time: %.4f'%(time.time()-time0),'no. elements: %d'%(Fhkl.size)) |
---|
3256 | |
---|
3257 | # map printing for testing purposes |
---|
3258 | def printRho(SGLaue,rho,rhoMax):             |
---|
3259 | Â Â '''default doc string |
---|
3260 | Â Â |
---|
3261 | Â Â :param type name: description |
---|
3262 | Â Â |
---|
3263 | Â Â :returns: type name: description |
---|
3264 | Â Â |
---|
3265 | Â Â ''' |
---|
3266 | Â Â dim =Â len(rho.shape) |
---|
3267 |   if dim == 2: |
---|
3268 | Â Â Â Â ix,jy =Â rho.shape |
---|
3269 |     for j in range(jy): |
---|
3270 | Â Â Â Â Â Â line =Â '' |
---|
3271 |       if SGLaue in ['3','3m1','31m','6/m','6/mmm']: |
---|
3272 | Â Â Â Â Â Â Â Â line +=Â (jy-j)*'Â ' |
---|
3273 |       for i in range(ix): |
---|
3274 | Â Â Â Â Â Â Â Â r =Â int(100*rho[i,j]/rhoMax) |
---|
3275 | Â Â Â Â Â Â Â Â line +=Â '%4d'%(r) |
---|
3276 |       print (line+'\n') |
---|
3277 | Â Â else: |
---|
3278 | Â Â Â Â ix,jy,kz =Â rho.shape |
---|
3279 |     for k in range(kz): |
---|
3280 |       print ('k = %d'%k) |
---|
3281 |       for j in range(jy): |
---|
3282 | Â Â Â Â Â Â Â Â line =Â '' |
---|
3283 |         if SGLaue in ['3','3m1','31m','6/m','6/mmm']: |
---|
3284 | Â Â Â Â Â Â Â Â Â Â line +=Â (jy-j)*'Â ' |
---|
3285 |         for i in range(ix): |
---|
3286 | Â Â Â Â Â Â Â Â Â Â r =Â int(100*rho[i,j,k]/rhoMax) |
---|
3287 | Â Â Â Â Â Â Â Â Â Â line +=Â '%4d'%(r) |
---|
3288 |         print (line+'\n') |
---|
3289 | ## keep this |
---|
3290 | Â Â Â Â Â Â Â Â |
---|
3291 | def findOffset(SGData,A,Fhkl):  |
---|
3292 | Â Â '''default doc string |
---|
3293 | Â Â |
---|
3294 | Â Â :param type name: description |
---|
3295 | Â Â |
---|
3296 | Â Â :returns: type name: description |
---|
3297 | Â Â |
---|
3298 | Â Â ''' |
---|
3299 |   if SGData['SpGrp'] == 'P 1': |
---|
3300 |     return [0,0,0]  |
---|
3301 | Â Â hklShape =Â Fhkl.shape |
---|
3302 | Â Â hklHalf =Â np.array(hklShape)/2 |
---|
3303 | Â Â sortHKL =Â np.argsort(Fhkl.flatten()) |
---|
3304 | Â Â Fdict =Â {} |
---|
3305 |   for hkl in sortHKL: |
---|
3306 | Â Â Â Â HKL =Â np.unravel_index(hkl,hklShape) |
---|
3307 | Â Â Â Â F =Â Fhkl[HKL[0]][HKL[1]][HKL[2]] |
---|
3308 |     if F == 0.: |
---|
3309 | Â Â Â Â Â Â break |
---|
3310 | Â Â Â Â Fdict['%.6f'%(np.absolute(F))]Â =Â hkl |
---|
3311 | Â Â Flist =Â np.flipud(np.sort(list(Fdict.keys()))) |
---|
3312 | Â Â F =Â str(1.e6) |
---|
3313 | Â Â i =Â 0 |
---|
3314 | Â Â DH =Â [] |
---|
3315 | Â Â Dphi =Â [] |
---|
3316 | Â Â Hmax =Â 2*np.asarray(G2lat.getHKLmax(3.5,SGData,A),dtype='i') |
---|
3317 |   for F in Flist: |
---|
3318 | Â Â Â Â hkl =Â np.unravel_index(Fdict[F],hklShape) |
---|
3319 |     if np.any(np.abs(hkl-hklHalf)-Hmax > 0): |
---|
3320 | Â Â Â Â Â Â continue |
---|
3321 | Â Â Â Â iabsnt,mulp,Uniq,Phi =Â G2spc.GenHKLf(list(hkl-hklHalf),SGData) |
---|
3322 | Â Â Â Â Uniq =Â np.array(Uniq,dtype='i') |
---|
3323 | Â Â Â Â Phi =Â np.array(Phi) |
---|
3324 |     Uniq = np.concatenate((Uniq,-Uniq))+hklHalf     # put in Friedel pairs & make as index to Farray |
---|
3325 | Â Â Â Â Phi =Â np.concatenate((Phi,-Phi))Â Â Â Â Â Â Â Â Â Â Â # and their phase shifts |
---|
3326 | Â Â Â Â Fh0 =Â Fhkl[hkl[0],hkl[1],hkl[2]] |
---|
3327 | Â Â Â Â ang0 =Â np.angle(Fh0,deg=True)/360. |
---|
3328 |     for H,phi in list(zip(Uniq,Phi))[1:]: |
---|
3329 | Â Â Â Â Â Â ang =Â (np.angle(Fhkl[int(H[0]),int(H[1]),int(H[2])],deg=True)/360.-phi) |
---|
3330 | Â Â Â Â Â Â dH =Â H-hkl |
---|
3331 | Â Â Â Â Â Â dang =Â ang-ang0 |
---|
3332 | Â Â Â Â Â Â DH.append(dH) |
---|
3333 | Â Â Â Â Â Â Dphi.append((dang+.5)Â %Â 1.0) |
---|
3334 |     if i > 20 or len(DH) > 30: |
---|
3335 | Â Â Â Â Â Â break |
---|
3336 | Â Â Â Â i +=Â 1 |
---|
3337 | Â Â DH =Â np.array(DH) |
---|
3338 |   print (' map offset no.of terms: %d from %d reflections'%(len(DH),len(Flist))) |
---|
3339 | Â Â Dphi =Â np.array(Dphi) |
---|
3340 | Â Â steps =Â np.array(hklShape) |
---|
3341 | Â Â X,Y,Z =Â np.mgrid[0:1:1./steps[0],0:1:1./steps[1],0:1:1./steps[2]] |
---|
3342 | Â Â XYZ =Â np.array(list(zip(X.flatten(),Y.flatten(),Z.flatten()))) |
---|
3343 | Â Â Dang =Â (np.dot(XYZ,DH.T)+.5)%1.-Dphi |
---|
3344 | Â Â Mmap =Â np.reshape(np.sum((Dang)**2,axis=1),newshape=steps)/len(DH) |
---|
3345 | Â Â hist,bins =Â np.histogram(Mmap,bins=1000) |
---|
3346 | #Â Â for i,item in enumerate(hist[:10]): |
---|
3347 | #Â Â Â Â print item,bins[i] |
---|
3348 | Â Â chisq =Â np.min(Mmap) |
---|
3349 | Â Â DX =Â -np.array(np.unravel_index(np.argmin(Mmap),Mmap.shape)) |
---|
3350 |   print (' map offset chi**2: %.3f, map offset: %d %d %d'%(chisq,DX[0],DX[1],DX[2])) |
---|
3351 | #Â Â print (np.dot(DX,DH.T)+.5)%1.-Dphi |
---|
3352 |   return DX |
---|
3353 | Â Â |
---|
3354 | def ChargeFlip(data,reflDict,pgbar): |
---|
3355 | Â Â '''default doc string |
---|
3356 | Â Â |
---|
3357 | Â Â :param type name: description |
---|
3358 | Â Â |
---|
3359 | Â Â :returns: type name: description |
---|
3360 | Â Â |
---|
3361 | Â Â ''' |
---|
3362 | Â Â generalData =Â data['General'] |
---|
3363 | Â Â mapData =Â generalData['Map'] |
---|
3364 | Â Â flipData =Â generalData['Flip'] |
---|
3365 | Â Â FFtable =Â {} |
---|
3366 |   if 'None' not in flipData['Norm element']: |
---|
3367 | Â Â Â Â normElem =Â flipData['Norm element'].upper() |
---|
3368 | Â Â Â Â FFs =Â G2el.GetFormFactorCoeff(normElem.split('+')[0].split('-')[0]) |
---|
3369 |     for ff in FFs: |
---|
3370 |       if ff['Symbol'] == normElem: |
---|
3371 | Â Â Â Â Â Â Â Â FFtable.update(ff) |
---|
3372 | Â Â dmin =Â flipData['Resolution'] |
---|
3373 | Â Â SGData =Â generalData['SGData'] |
---|
3374 |   SGMT = np.array([ops[0].T for ops in SGData['SGOps']]) |
---|
3375 |   SGT = np.array([ops[1] for ops in SGData['SGOps']]) |
---|
3376 | Â Â cell =Â generalData['Cell'][1:8]Â Â Â Â |
---|
3377 | Â Â A =Â G2lat.cell2A(cell[:6]) |
---|
3378 | Â Â Vol =Â cell[6] |
---|
3379 | Â Â im =Â 0 |
---|
3380 |   if generalData['Modulated'] == True: |
---|
3381 | Â Â Â Â im =Â 1 |
---|
3382 | Â Â Hmax =Â np.asarray(G2lat.getHKLmax(dmin,SGData,A),dtype='i')+1 |
---|
3383 | Â Â adjHKLmax(SGData,Hmax) |
---|
3384 | Â Â Ehkl =Â np.zeros(shape=2*Hmax,dtype='c16')Â Â Â Â #2X64bits per complex no. |
---|
3385 | Â Â time0 =Â time.time() |
---|
3386 |   for iref,ref in enumerate(reflDict['RefList']): |
---|
3387 | Â Â Â Â dsp =Â ref[4+im] |
---|
3388 |     if im and ref[3]:  #skip super lattice reflections - result is 3D projection |
---|
3389 | Â Â Â Â Â Â continue |
---|
3390 |     if dsp > dmin: |
---|
3391 |       ff = 0.1*Vol  #est. no. atoms for ~10A**3/atom |
---|
3392 |       if FFtable: |
---|
3393 | Â Â Â Â Â Â Â Â SQ =Â 0.25/dsp**2 |
---|
3394 | Â Â Â Â Â Â Â Â ff *=Â G2el.ScatFac(FFtable,SQ)[0] |
---|
3395 |       if ref[8+im] > 0.:     #use only +ve Fobs**2 |
---|
3396 | Â Â Â Â Â Â Â Â E =Â np.sqrt(ref[8+im])/ff |
---|
3397 | Â Â Â Â Â Â else: |
---|
3398 | Â Â Â Â Â Â Â Â E =Â 0. |
---|
3399 | Â Â Â Â Â Â ph =Â ref[10] |
---|
3400 | Â Â Â Â Â Â ph =Â rn.uniform(0.,360.) |
---|
3401 | Â Â Â Â Â Â Uniq =Â np.inner(ref[:3],SGMT) |
---|
3402 | Â Â Â Â Â Â Phi =Â np.inner(ref[:3],SGT) |
---|
3403 |       for i,hkl in enumerate(Uniq):    #uses uniq |
---|
3404 | Â Â Â Â Â Â Â Â hkl =Â np.asarray(hkl,dtype='i') |
---|
3405 | Â Â Â Â Â Â Â Â dp =Â 360.*Phi[i]Â Â Â Â Â Â Â Â #and phi |
---|
3406 | Â Â Â Â Â Â Â Â a =Â cosd(ph+dp) |
---|
3407 | Â Â Â Â Â Â Â Â b =Â sind(ph+dp) |
---|
3408 | Â Â Â Â Â Â Â Â phasep =Â complex(a,b) |
---|
3409 | Â Â Â Â Â Â Â Â phasem =Â complex(a,-b) |
---|
3410 | Â Â Â Â Â Â Â Â h,k,l =Â hkl+Hmax |
---|
3411 | Â Â Â Â Â Â Â Â Ehkl[h,k,l]Â =Â E*phasep |
---|
3412 | Â Â Â Â Â Â Â Â h,k,l =Â -hkl+Hmax |
---|
3413 | Â Â Â Â Â Â Â Â Ehkl[h,k,l]Â =Â E*phasem |
---|
3414 | #Â Â Ehkl[Hmax] = 0.00001Â Â Â Â Â Â #this to preserve F[0,0,0] |
---|
3415 | Â Â testHKL =Â np.array(flipData['testHKL'])+Hmax |
---|
3416 | Â Â CEhkl =Â copy.copy(Ehkl) |
---|
3417 | Â Â MEhkl =Â ma.array(Ehkl,mask=(Ehkl==0.0)) |
---|
3418 | Â Â Emask =Â ma.getmask(MEhkl) |
---|
3419 | Â Â sumE =Â np.sum(ma.array(np.absolute(CEhkl),mask=Emask)) |
---|
3420 | Â Â Ncyc =Â 0 |
---|
3421 | Â Â old =Â np.seterr(all='raise') |
---|
3422 | Â Â twophases =Â [] |
---|
3423 |   while True:    |
---|
3424 | Â Â Â Â CErho =Â np.real(fft.fftn(fft.fftshift(CEhkl)))*(1.+0j) |
---|
3425 | Â Â Â Â CEsig =Â np.std(CErho) |
---|
3426 | Â Â Â Â CFrho =Â np.where(np.real(CErho)Â >=Â flipData['k-factor']*CEsig,CErho,-CErho) |
---|
3427 | Â Â Â Â CFrho =Â np.where(np.real(CErho)Â <=Â flipData['k-Max']*CEsig,CFrho,-CFrho)Â Â Â #solves U atom problem! |
---|
3428 | Â Â Â Â CFhkl =Â fft.ifftshift(fft.ifftn(CFrho)) |
---|
3429 | Â Â Â Â CFhkl =Â np.where(CFhkl,CFhkl,1.0)Â Â Â Â Â Â #avoid divide by zero |
---|
3430 | Â Â Â Â phase =Â CFhkl/np.absolute(CFhkl) |
---|
3431 |     twophases.append([np.angle(phase[h,k,l]) for h,k,l in testHKL]) |
---|
3432 | Â Â Â Â CEhkl =Â np.absolute(Ehkl)*phase |
---|
3433 | Â Â Â Â Ncyc +=Â 1 |
---|
3434 | Â Â Â Â sumCF =Â np.sum(ma.array(np.absolute(CFhkl),mask=Emask)) |
---|
3435 | Â Â Â Â DEhkl =Â np.absolute(np.absolute(Ehkl)/sumE-np.absolute(CFhkl)/sumCF) |
---|
3436 | Â Â Â Â Rcf =Â min(100.,np.sum(ma.array(DEhkl,mask=Emask)*100.)) |
---|
3437 |     if Rcf < 5.: |
---|
3438 | Â Â Â Â Â Â break |
---|
3439 |     GoOn = pgbar.Update(Rcf,newmsg='%s%8.3f%s\n%s %d'%('Residual Rcf =',Rcf,'%','No.cycles = ',Ncyc))[0] |
---|
3440 |     if not GoOn or Ncyc > 10000: |
---|
3441 | Â Â Â Â Â Â break |
---|
3442 | Â Â np.seterr(**old) |
---|
3443 |   print (' Charge flip time: %.4f'%(time.time()-time0),'no. elements: %d'%(Ehkl.size)) |
---|
3444 |   CErho = np.real(fft.fftn(fft.fftshift(CEhkl)))/10. #? to get on same scale as e-map |
---|
3445 |   print (' No.cycles = %d Residual Rcf =%8.3f%s Map size: %s'%(Ncyc,Rcf,'%',str(CErho.shape))) |
---|
3446 | Â Â roll =Â findOffset(SGData,A,CEhkl)Â Â Â Â Â Â Â Â #CEhkl needs to be just the observed set, not the full set! |
---|
3447 | Â Â Â Â |
---|
3448 | Â Â mapData['Rcf']Â =Â Rcf |
---|
3449 | Â Â mapData['rho']Â =Â np.roll(np.roll(np.roll(CErho,roll[0],axis=0),roll[1],axis=1),roll[2],axis=2) |
---|
3450 | Â Â mapData['rhoMax']Â =Â max(np.max(mapData['rho']),-np.min(mapData['rho'])) |
---|
3451 | Â Â mapData['minmax']Â =Â [np.max(mapData['rho']),np.min(mapData['rho'])] |
---|
3452 | Â Â mapData['Type']Â =Â reflDict['Type'] |
---|
3453 |   return mapData,twophases |
---|
3454 | Â Â |
---|
3455 | def findSSOffset(SGData,SSGData,A,Fhklm):  |
---|
3456 | Â Â '''default doc string |
---|
3457 | Â Â |
---|
3458 | Â Â :param type name: description |
---|
3459 | Â Â |
---|
3460 | Â Â :returns: type name: description |
---|
3461 | Â Â |
---|
3462 | Â Â ''' |
---|
3463 |   if SGData['SpGrp'] == 'P 1': |
---|
3464 |     return [0,0,0,0]  |
---|
3465 | Â Â hklmShape =Â Fhklm.shape |
---|
3466 | Â Â hklmHalf =Â np.array(hklmShape)/2 |
---|
3467 | Â Â sortHKLM =Â np.argsort(Fhklm.flatten()) |
---|
3468 | Â Â Fdict =Â {} |
---|
3469 |   for hklm in sortHKLM: |
---|
3470 | Â Â Â Â HKLM =Â np.unravel_index(hklm,hklmShape) |
---|
3471 | Â Â Â Â F =Â Fhklm[HKLM[0]][HKLM[1]][HKLM[2]][HKLM[3]] |
---|
3472 |     if F == 0.: |
---|
3473 | Â Â Â Â Â Â break |
---|
3474 | Â Â Â Â Fdict['%.6f'%(np.absolute(F))]Â =Â hklm |
---|
3475 | Â Â Flist =Â np.flipud(np.sort(list(Fdict.keys()))) |
---|
3476 | Â Â F =Â str(1.e6) |
---|
3477 | Â Â i =Â 0 |
---|
3478 | Â Â DH =Â [] |
---|
3479 | Â Â Dphi =Â [] |
---|
3480 |   SSGMT = np.array([ops[0].T for ops in SSGData['SSGOps']]) |
---|
3481 |   SSGT = np.array([ops[1] for ops in SSGData['SSGOps']]) |
---|
3482 | Â Â Hmax =Â 2*np.asarray(G2lat.getHKLmax(3.5,SGData,A),dtype='i') |
---|
3483 |   for F in Flist: |
---|
3484 | Â Â Â Â hklm =Â np.unravel_index(Fdict[F],hklmShape) |
---|
3485 |     if np.any(np.abs(hklm-hklmHalf)[:3]-Hmax > 0): |
---|
3486 | Â Â Â Â Â Â continue |
---|
3487 | Â Â Â Â Uniq =Â np.inner(hklm-hklmHalf,SSGMT) |
---|
3488 | Â Â Â Â Phi =Â np.inner(hklm-hklmHalf,SSGT) |
---|
3489 |     Uniq = np.concatenate((Uniq,-Uniq))+hklmHalf     # put in Friedel pairs & make as index to Farray |
---|
3490 | Â Â Â Â Phi =Â np.concatenate((Phi,-Phi))Â Â Â Â Â Â Â Â Â Â Â # and their phase shifts |
---|
3491 | Â Â Â Â Fh0 =Â Fhklm[hklm[0],hklm[1],hklm[2],hklm[3]] |
---|
3492 | Â Â Â Â ang0 =Â np.angle(Fh0,deg=True)/360. |
---|
3493 |     for H,phi in list(zip(Uniq,Phi))[1:]: |
---|
3494 | Â Â Â Â Â Â H =Â np.array(H,dtype=int) |
---|
3495 | Â Â Â Â Â Â ang =Â (np.angle(Fhklm[H[0],H[1],H[2],H[3]],deg=True)/360.-phi) |
---|
3496 | Â Â Â Â Â Â dH =Â H-hklm |
---|
3497 | Â Â Â Â Â Â dang =Â ang-ang0 |
---|
3498 | Â Â Â Â Â Â DH.append(dH) |
---|
3499 | Â Â Â Â Â Â Dphi.append((dang+.5)Â %Â 1.0) |
---|
3500 |     if i > 20 or len(DH) > 30: |
---|
3501 | Â Â Â Â Â Â break |
---|
3502 | Â Â Â Â i +=Â 1 |
---|
3503 | Â Â DH =Â np.array(DH) |
---|
3504 |   print (' map offset no.of terms: %d from %d reflections'%(len(DH),len(Flist))) |
---|
3505 | Â Â Dphi =Â np.array(Dphi) |
---|
3506 | Â Â steps =Â np.array(hklmShape) |
---|
3507 | Â Â X,Y,Z,T =Â np.mgrid[0:1:1./steps[0],0:1:1./steps[1],0:1:1./steps[2],0:1:1./steps[3]] |
---|
3508 | Â Â XYZT =Â np.array(list(zip(X.flatten(),Y.flatten(),Z.flatten(),T.flatten()))) |
---|
3509 | Â Â Dang =Â (np.dot(XYZT,DH.T)+.5)%1.-Dphi |
---|
3510 | Â Â Mmap =Â np.reshape(np.sum((Dang)**2,axis=1),newshape=steps)/len(DH) |
---|
3511 | Â Â hist,bins =Â np.histogram(Mmap,bins=1000) |
---|
3512 | #Â Â for i,item in enumerate(hist[:10]): |
---|
3513 | #Â Â Â Â print item,bins[i] |
---|
3514 | Â Â chisq =Â np.min(Mmap) |
---|
3515 | Â Â DX =Â -np.array(np.unravel_index(np.argmin(Mmap),Mmap.shape)) |
---|
3516 |   print (' map offset chi**2: %.3f, map offset: %d %d %d %d'%(chisq,DX[0],DX[1],DX[2],DX[3])) |
---|
3517 | #Â Â print (np.dot(DX,DH.T)+.5)%1.-Dphi |
---|
3518 |   return DX |
---|
3519 | Â Â |
---|
3520 | def SSChargeFlip(data,reflDict,pgbar): |
---|
3521 | Â Â '''default doc string |
---|
3522 | Â Â |
---|
3523 | Â Â :param type name: description |
---|
3524 | Â Â |
---|
3525 | Â Â :returns: type name: description |
---|
3526 | Â Â |
---|
3527 | Â Â ''' |
---|
3528 | Â Â generalData =Â data['General'] |
---|
3529 | Â Â mapData =Â generalData['Map'] |
---|
3530 | Â Â map4DData =Â {} |
---|
3531 | Â Â flipData =Â generalData['Flip'] |
---|
3532 | Â Â FFtable =Â {} |
---|
3533 |   if 'None' not in flipData['Norm element']: |
---|
3534 | Â Â Â Â normElem =Â flipData['Norm element'].upper() |
---|
3535 | Â Â Â Â FFs =Â G2el.GetFormFactorCoeff(normElem.split('+')[0].split('-')[0]) |
---|
3536 |     for ff in FFs: |
---|
3537 |       if ff['Symbol'] == normElem: |
---|
3538 | Â Â Â Â Â Â Â Â FFtable.update(ff) |
---|
3539 | Â Â dmin =Â flipData['Resolution'] |
---|
3540 | Â Â SGData =Â generalData['SGData'] |
---|
3541 | Â Â SSGData =Â generalData['SSGData'] |
---|
3542 |   SSGMT = np.array([ops[0].T for ops in SSGData['SSGOps']]) |
---|
3543 |   SSGT = np.array([ops[1] for ops in SSGData['SSGOps']]) |
---|
3544 | Â Â cell =Â generalData['Cell'][1:8]Â Â Â Â |
---|
3545 | Â Â A =Â G2lat.cell2A(cell[:6]) |
---|
3546 | Â Â Vol =Â cell[6] |
---|
3547 | Â Â maxM =Â 4 |
---|
3548 | Â Â Hmax =Â np.asarray(G2lat.getHKLmax(dmin,SGData,A)+[maxM,],dtype='i')+1 |
---|
3549 | Â Â adjHKLmax(SGData,Hmax) |
---|
3550 | Â Â Ehkl =Â np.zeros(shape=2*Hmax,dtype='c16')Â Â Â Â #2X64bits per complex no. |
---|
3551 | Â Â time0 =Â time.time() |
---|
3552 |   for iref,ref in enumerate(reflDict['RefList']): |
---|
3553 | Â Â Â Â dsp =Â ref[5] |
---|
3554 |     if dsp > dmin: |
---|
3555 |       ff = 0.1*Vol  #est. no. atoms for ~10A**3/atom |
---|
3556 |       if FFtable: |
---|
3557 | Â Â Â Â Â Â Â Â SQ =Â 0.25/dsp**2 |
---|
3558 | Â Â Â Â Â Â Â Â ff *=Â G2el.ScatFac(FFtable,SQ)[0] |
---|
3559 |       if ref[9] > 0.:     #use only +ve Fobs**2 |
---|
3560 | Â Â Â Â Â Â Â Â E =Â np.sqrt(ref[9])/ff |
---|
3561 | Â Â Â Â Â Â else: |
---|
3562 | Â Â Â Â Â Â Â Â E =Â 0. |
---|
3563 | Â Â Â Â Â Â ph =Â ref[11] |
---|
3564 | Â Â Â Â Â Â ph =Â rn.uniform(0.,360.) |
---|
3565 | Â Â Â Â Â Â Uniq =Â np.inner(ref[:4],SSGMT) |
---|
3566 | Â Â Â Â Â Â Phi =Â np.inner(ref[:4],SSGT) |
---|
3567 |       for i,hklm in enumerate(Uniq):    #uses uniq |
---|
3568 | Â Â Â Â Â Â Â Â hklm =Â np.asarray(hklm,dtype='i') |
---|
3569 | Â Â Â Â Â Â Â Â dp =Â 360.*Phi[i]Â Â Â Â Â Â Â Â #and phi |
---|
3570 | Â Â Â Â Â Â Â Â a =Â cosd(ph+dp) |
---|
3571 | Â Â Â Â Â Â Â Â b =Â sind(ph+dp) |
---|
3572 | Â Â Â Â Â Â Â Â phasep =Â complex(a,b) |
---|
3573 | Â Â Â Â Â Â Â Â phasem =Â complex(a,-b) |
---|
3574 | Â Â Â Â Â Â Â Â h,k,l,m =Â hklm+Hmax |
---|
3575 | Â Â Â Â Â Â Â Â Ehkl[h,k,l,m]Â =Â E*phasep |
---|
3576 |         h,k,l,m = -hklm+Hmax    #Friedel pair refl. |
---|
3577 | Â Â Â Â Â Â Â Â Ehkl[h,k,l,m]Â =Â E*phasem |
---|
3578 | #Â Â Ehkl[Hmax] = 0.00001Â Â Â Â Â Â #this to preserve F[0,0,0] |
---|
3579 | Â Â CEhkl =Â copy.copy(Ehkl) |
---|
3580 | Â Â MEhkl =Â ma.array(Ehkl,mask=(Ehkl==0.0)) |
---|
3581 | Â Â Emask =Â ma.getmask(MEhkl) |
---|
3582 | Â Â sumE =Â np.sum(ma.array(np.absolute(CEhkl),mask=Emask)) |
---|
3583 | Â Â Ncyc =Â 0 |
---|
3584 | Â Â old =Â np.seterr(all='raise') |
---|
3585 |   while True:    |
---|
3586 | Â Â Â Â CErho =Â np.real(fft.fftn(fft.fftshift(CEhkl)))*(1.+0j) |
---|
3587 | Â Â Â Â CEsig =Â np.std(CErho) |
---|
3588 | Â Â Â Â CFrho =Â np.where(np.real(CErho)Â >=Â flipData['k-factor']*CEsig,CErho,-CErho) |
---|
3589 | Â Â Â Â CFrho =Â np.where(np.real(CErho)Â <=Â flipData['k-Max']*CEsig,CFrho,-CFrho)Â Â Â #solves U atom problem! |
---|
3590 | Â Â Â Â CFhkl =Â fft.ifftshift(fft.ifftn(CFrho)) |
---|
3591 | Â Â Â Â CFhkl =Â np.where(CFhkl,CFhkl,1.0)Â Â Â Â Â Â #avoid divide by zero |
---|
3592 | Â Â Â Â phase =Â CFhkl/np.absolute(CFhkl) |
---|
3593 | Â Â Â Â CEhkl =Â np.absolute(Ehkl)*phase |
---|
3594 | Â Â Â Â Ncyc +=Â 1 |
---|
3595 | Â Â Â Â sumCF =Â np.sum(ma.array(np.absolute(CFhkl),mask=Emask)) |
---|
3596 | Â Â Â Â DEhkl =Â np.absolute(np.absolute(Ehkl)/sumE-np.absolute(CFhkl)/sumCF) |
---|
3597 | Â Â Â Â Rcf =Â min(100.,np.sum(ma.array(DEhkl,mask=Emask)*100.)) |
---|
3598 |     if Rcf < 5.: |
---|
3599 | Â Â Â Â Â Â break |
---|
3600 |     GoOn = pgbar.Update(Rcf,newmsg='%s%8.3f%s\n%s %d'%('Residual Rcf =',Rcf,'%','No.cycles = ',Ncyc))[0] |
---|
3601 |     if not GoOn or Ncyc > 10000: |
---|
3602 | Â Â Â Â Â Â break |
---|
3603 | Â Â np.seterr(**old) |
---|
3604 |   print (' Charge flip time: %.4f no. elements: %d'%(time.time()-time0,Ehkl.size)) |
---|
3605 |   CErho = np.real(fft.fftn(fft.fftshift(CEhkl[:,:,:,maxM+1])))/10.  #? to get on same scale as e-map |
---|
3606 |   SSrho = np.real(fft.fftn(fft.fftshift(CEhkl)))/10.         #? ditto |
---|
3607 |   print (' No.cycles = %d Residual Rcf =%8.3f%s Map size: %s'%(Ncyc,Rcf,'%',str(CErho.shape))) |
---|
3608 | Â Â roll =Â findSSOffset(SGData,SSGData,A,CEhkl)Â Â Â Â Â Â Â Â #CEhkl needs to be just the observed set, not the full set! |
---|
3609 | |
---|
3610 | Â Â mapData['Rcf']Â =Â Rcf |
---|
3611 | Â Â mapData['rho']Â =Â np.roll(np.roll(np.roll(CErho,roll[0],axis=0),roll[1],axis=1),roll[2],axis=2) |
---|
3612 | Â Â mapData['rhoMax']Â =Â max(np.max(mapData['rho']),-np.min(mapData['rho'])) |
---|
3613 | Â Â mapData['minmax']Â =Â [np.max(mapData['rho']),np.min(mapData['rho'])] |
---|
3614 | Â Â mapData['Type']Â =Â reflDict['Type'] |
---|
3615 | |
---|
3616 | Â Â map4DData['Rcf']Â =Â Rcf |
---|
3617 | Â Â map4DData['rho']Â =Â np.real(np.roll(np.roll(np.roll(np.roll(SSrho,roll[0],axis=0),roll[1],axis=1),roll[2],axis=2),roll[3],axis=3)) |
---|
3618 | Â Â map4DData['rhoMax']Â =Â max(np.max(map4DData['rho']),-np.min(map4DData['rho'])) |
---|
3619 | Â Â map4DData['minmax']Â =Â [np.max(map4DData['rho']),np.min(map4DData['rho'])] |
---|
3620 | Â Â map4DData['Type']Â =Â reflDict['Type'] |
---|
3621 |   return mapData,map4DData |
---|
3622 | Â Â |
---|
3623 | def getRho(xyz,mapData): |
---|
3624 | Â Â ''' get scattering density at a point by 8-point interpolation |
---|
3625 | Â Â param xyz: coordinate to be probed |
---|
3626 | Â Â param: mapData: dict of map data |
---|
3627 | Â Â |
---|
3628 | Â Â :returns: density at xyz |
---|
3629 | Â Â ''' |
---|
3630 |   rollMap = lambda rho,roll: np.roll(np.roll(np.roll(rho,roll[0],axis=0),roll[1],axis=1),roll[2],axis=2) |
---|
3631 |   if not len(mapData): |
---|
3632 |     return 0.0 |
---|
3633 | Â Â rho =Â copy.copy(mapData['rho'])Â Â Â #don't mess up original |
---|
3634 |   if not len(rho): |
---|
3635 |     return 0.0 |
---|
3636 | Â Â mapShape =Â np.array(rho.shape) |
---|
3637 | Â Â mapStep =Â 1./mapShape |
---|
3638 |   X = np.array(xyz)%1.  #get into unit cell |
---|
3639 | Â Â I =Â np.array(X*mapShape,dtype='int') |
---|
3640 |   D = X-I*mapStep     #position inside map cell |
---|
3641 | Â Â D12 =Â D[0]*D[1] |
---|
3642 | Â Â D13 =Â D[0]*D[2] |
---|
3643 | Â Â D23 =Â D[1]*D[2] |
---|
3644 | Â Â D123 =Â np.prod(D) |
---|
3645 | Â Â Rho =Â rollMap(rho,-I)Â Â #shifts map so point is in corner |
---|
3646 | Â Â R =Â Rho[0,0,0]*(1.-np.sum(D))+Rho[1,0,0]*D[0]+Rho[0,1,0]*D[1]+Rho[0,0,1]*D[2]+Â \ |
---|
3647 | Â Â Â Â Rho[1,1,1]*D123+Rho[0,1,1]*(D23-D123)+Rho[1,0,1]*(D13-D123)+Rho[1,1,0]*(D12-D123)+Â \ |
---|
3648 | Â Â Â Â Rho[0,0,0]*(D12+D13+D23-D123)-Rho[0,0,1]*(D13+D23-D123)-Â Â \ |
---|
3649 | Â Â Â Â Rho[0,1,0]*(D23+D12-D123)-Rho[1,0,0]*(D13+D12-D123)Â Â |
---|
3650 |   return R |
---|
3651 | Â Â Â Â |
---|
3652 | def getRhos(XYZ,rho): |
---|
3653 | Â Â ''' get scattering density at an array of point by 8-point interpolation |
---|
3654 | Â Â param xyz:Â array coordinates to be probed Nx3 |
---|
3655 | Â Â param: rho: array copy of map (NB: don't use original!) |
---|
3656 | Â Â |
---|
3657 | Â Â :returns: density at xyz |
---|
3658 | Â Â ''' |
---|
3659 |   rollMap = lambda rho,roll: np.roll(np.roll(np.roll(rho,roll[0],axis=0),roll[1],axis=1),roll[2],axis=2)[:2,:2,:2] |
---|
3660 | Â Â mapShape =Â np.array(rho.shape) |
---|
3661 | Â Â mapStep =Â 1./mapShape |
---|
3662 |   X = XYZ%1.  #get into unit cell |
---|
3663 | Â Â I =Â np.array(np.rint(X*mapShape),dtype='int') |
---|
3664 | Â Â R =Â np.zeros(len(XYZ)) |
---|
3665 |   for i,x in enumerate(X): |
---|
3666 |     D = x-I[i]*mapStep     #position inside map cell |
---|
3667 | Â Â Â Â Rho =Â rollMap(rho,-I[i])Â Â #shifts map so point is in corner |
---|
3668 | Â Â Â Â RIJ =Â Rho[0,:2,:2]*(1.-D[0]) |
---|
3669 | Â Â Â Â RI =Â RIJ[0]*(1.-D[1])+RIJ[1]*D[1] |
---|
3670 | Â Â Â Â R[i]Â =Â RI[0]*(1.-D[2])+RI[1]*D[2] |
---|
3671 |   return R |
---|
3672 | Â Â Â Â |
---|
3673 | def SearchMap(generalData,drawingData,Neg=False): |
---|
3674 | Â Â '''Does a search of a density map for peaks meeting the criterion of peak |
---|
3675 | Â Â height is greater than mapData['cutOff']/100 of mapData['rhoMax'] where |
---|
3676 | Â Â mapData is data['General']['mapData']; the map is also in mapData. |
---|
3677 | |
---|
3678 | Â Â :param generalData: the phase data structure; includes the map |
---|
3679 | Â Â :param drawingData: the drawing data structure |
---|
3680 | Â Â :param Neg:Â if True then search for negative peaks (i.e. H-atoms & neutron data) |
---|
3681 | |
---|
3682 | Â Â :returns: (peaks,mags,dzeros) where |
---|
3683 | |
---|
3684 | Â Â Â Â * peaks : ndarray |
---|
3685 | Â Â Â Â Â x,y,z positions of the peaks found in the map |
---|
3686 | Â Â Â Â * mags : ndarray |
---|
3687 | Â Â Â Â Â the magnitudes of the peaks |
---|
3688 | Â Â Â Â * dzeros : ndarray |
---|
3689 |      the distance of the peaks from the unit cell origin |
---|
3690 | Â Â Â Â * dcent : ndarray |
---|
3691 |      the distance of the peaks from the unit cell center |
---|
3692 | |
---|
3693 | Â Â '''Â Â Â Â |
---|
3694 |   rollMap = lambda rho,roll: np.roll(np.roll(np.roll(rho,roll[0],axis=0),roll[1],axis=1),roll[2],axis=2) |
---|
3695 | Â Â |
---|
3696 | Â Â norm =Â 1./(np.sqrt(3.)*np.sqrt(2.*np.pi)**3) |
---|
3697 | Â Â |
---|
3698 |   def fixSpecialPos(xyz,SGData,Amat): |
---|
3699 | Â Â Â Â equivs =Â G2spc.GenAtom(xyz,SGData,Move=True) |
---|
3700 | Â Â Â Â X =Â [] |
---|
3701 |     xyzs = [equiv[0] for equiv in equivs] |
---|
3702 |     for x in xyzs: |
---|
3703 |       if np.sqrt(np.sum(np.inner(Amat,xyz-x)**2,axis=0))<0.5: |
---|
3704 | Â Â Â Â Â Â Â Â X.append(x) |
---|
3705 |     if len(X) > 1: |
---|
3706 |       return np.average(X,axis=0) |
---|
3707 | Â Â Â Â else: |
---|
3708 |       return xyz |
---|
3709 | Â Â Â Â |
---|
3710 |   def rhoCalc(parms,rX,rY,rZ,res,SGLaue): |
---|
3711 | Â Â Â Â Mag,x0,y0,z0,sig =Â parms |
---|
3712 | Â Â Â Â z =Â -((x0-rX)**2+(y0-rY)**2+(z0-rZ)**2)/(2.*sig**2) |
---|
3713 | #Â Â Â Â return norm*Mag*np.exp(z)/(sig*res**3)Â Â Â #not slower but some faults in LS |
---|
3714 |     return norm*Mag*(1.+z+z**2/2.)/(sig*res**3) |
---|
3715 | Â Â Â Â |
---|
3716 |   def peakFunc(parms,rX,rY,rZ,rho,res,SGLaue): |
---|
3717 | Â Â Â Â Mag,x0,y0,z0,sig =Â parms |
---|
3718 | Â Â Â Â M =Â rho-rhoCalc(parms,rX,rY,rZ,res,SGLaue) |
---|
3719 |     return M |
---|
3720 | Â Â Â Â |
---|
3721 |   def peakHess(parms,rX,rY,rZ,rho,res,SGLaue): |
---|
3722 | Â Â Â Â Mag,x0,y0,z0,sig =Â parms |
---|
3723 | Â Â Â Â dMdv =Â np.zeros(([5,]+list(rX.shape))) |
---|
3724 | Â Â Â Â delt =Â .01 |
---|
3725 |     for i in range(5): |
---|
3726 | Â Â Â Â Â Â parms[i]Â -=Â delt |
---|
3727 | Â Â Â Â Â Â rhoCm =Â rhoCalc(parms,rX,rY,rZ,res,SGLaue) |
---|
3728 | Â Â Â Â Â Â parms[i]Â +=Â 2.*delt |
---|
3729 | Â Â Â Â Â Â rhoCp =Â rhoCalc(parms,rX,rY,rZ,res,SGLaue) |
---|
3730 | Â Â Â Â Â Â parms[i]Â -=Â delt |
---|
3731 | Â Â Â Â Â Â dMdv[i]Â =Â (rhoCp-rhoCm)/(2.*delt) |
---|
3732 | Â Â Â Â rhoC =Â rhoCalc(parms,rX,rY,rZ,res,SGLaue) |
---|
3733 | Â Â Â Â Vec =Â np.sum(np.sum(np.sum(dMdv*(rho-rhoC),axis=3),axis=2),axis=1) |
---|
3734 | Â Â Â Â dMdv =Â np.reshape(dMdv,(5,rX.size)) |
---|
3735 | Â Â Â Â Hess =Â np.inner(dMdv,dMdv) |
---|
3736 | Â Â Â Â |
---|
3737 |     return Vec,Hess |
---|
3738 | Â Â Â Â |
---|
3739 | Â Â SGData =Â generalData['SGData'] |
---|
3740 | Â Â Amat,Bmat =Â G2lat.cell2AB(generalData['Cell'][1:7]) |
---|
3741 | Â Â peaks =Â [] |
---|
3742 | Â Â mags =Â [] |
---|
3743 | Â Â dzeros =Â [] |
---|
3744 | Â Â dcent =Â [] |
---|
3745 | Â Â try: |
---|
3746 | Â Â Â Â mapData =Â generalData['Map'] |
---|
3747 | Â Â Â Â contLevel =Â mapData['cutOff']*mapData['rhoMax']/100. |
---|
3748 |     if Neg: |
---|
3749 | Â Â Â Â Â Â rho =Â -copy.copy(mapData['rho'])Â Â Â #flip +/- |
---|
3750 | Â Â Â Â else: |
---|
3751 | Â Â Â Â Â Â rho =Â copy.copy(mapData['rho'])Â Â Â #don't mess up original |
---|
3752 | Â Â Â Â mapHalf =Â np.array(rho.shape)/2 |
---|
3753 | Â Â Â Â res =Â mapData['Resolution'] |
---|
3754 | Â Â Â Â incre =Â np.array(rho.shape,dtype=np.float) |
---|
3755 | Â Â Â Â step =Â max(1.0,1./res)+1 |
---|
3756 | Â Â Â Â steps =Â np.array((3*[step,]),dtype='int32') |
---|
3757 |   except KeyError: |
---|
3758 |     print ('**** ERROR - Fourier map not defined') |
---|
3759 |     return peaks,mags |
---|
3760 | Â Â rhoMask =Â ma.array(rho,mask=(rho<contLevel)) |
---|
3761 | Â Â indices =Â (-1,0,1) |
---|
3762 |   rolls = np.array([[h,k,l] for h in indices for k in indices for l in indices]) |
---|
3763 |   for roll in rolls: |
---|
3764 |     if np.any(roll): |
---|
3765 | Â Â Â Â Â Â rhoMask =Â ma.array(rhoMask,mask=(rhoMask-rollMap(rho,roll)<=0.)) |
---|
3766 | Â Â indx =Â np.transpose(rhoMask.nonzero()) |
---|
3767 | Â Â peaks =Â indx/incre |
---|
3768 | Â Â mags =Â rhoMask[rhoMask.nonzero()] |
---|
3769 |   for i,[ind,peak,mag] in enumerate(zip(indx,peaks,mags)): |
---|
3770 | Â Â Â Â rho =Â rollMap(rho,ind) |
---|
3771 | Â Â Â Â rMM =Â mapHalf-steps |
---|
3772 | Â Â Â Â rMP =Â mapHalf+steps+1 |
---|
3773 | Â Â Â Â rhoPeak =Â rho[int(rMM[0]):int(rMP[0]),int(rMM[1]):int(rMP[1]),int(rMM[2]):int(rMP[2])] |
---|
3774 | Â Â Â Â peakInt =Â np.sum(rhoPeak)*res**3 |
---|
3775 | Â Â Â Â rX,rY,rZ =Â np.mgrid[int(rMM[0]):int(rMP[0]),int(rMM[1]):int(rMP[1]),int(rMM[2]):int(rMP[2])] |
---|
3776 | Â Â Â Â x0 =Â [peakInt,mapHalf[0],mapHalf[1],mapHalf[2],2.0]Â Â Â Â Â #magnitude, position & width(sig) |
---|
3777 | Â Â Â Â result =Â HessianLSQ(peakFunc,x0,Hess=peakHess, |
---|
3778 | Â Â Â Â Â Â args=(rX,rY,rZ,rhoPeak,res,SGData['SGLaue']),ftol=.01,maxcyc=10) |
---|
3779 | Â Â Â Â x1 =Â result[0] |
---|
3780 |     if not np.any(x1 < 0): |
---|
3781 | Â Â Â Â Â Â peak =Â (np.array(x1[1:4])-ind)/incre |
---|
3782 | Â Â Â Â peak =Â fixSpecialPos(peak,SGData,Amat) |
---|
3783 | Â Â Â Â rho =Â rollMap(rho,-ind) |
---|
3784 | Â Â cent =Â np.ones(3)*.5Â Â Â |
---|
3785 | Â Â dzeros =Â np.sqrt(np.sum(np.inner(Amat,peaks)**2,axis=0)) |
---|
3786 | Â Â dcent =Â np.sqrt(np.sum(np.inner(Amat,peaks-cent)**2,axis=0)) |
---|
3787 |   if Neg:   #want negative magnitudes for negative peaks |
---|
3788 |     return np.array(peaks),-np.array([mags,]).T,np.array([dzeros,]).T,np.array([dcent,]).T |
---|
3789 | Â Â else: |
---|
3790 |     return np.array(peaks),np.array([mags,]).T,np.array([dzeros,]).T,np.array([dcent,]).T |
---|
3791 | Â Â |
---|
3792 | def sortArray(data,pos,reverse=False): |
---|
3793 | Â Â '''data is a list of items |
---|
3794 | Â Â sort by pos in list; reverse if True |
---|
3795 | Â Â ''' |
---|
3796 | Â Â T =Â [] |
---|
3797 |   for i,M in enumerate(data): |
---|
3798 | Â Â Â Â try: |
---|
3799 | Â Â Â Â Â Â T.append((M[pos],i)) |
---|
3800 |     except IndexError: |
---|
3801 |       return data |
---|
3802 | Â Â D =Â dict(zip(T,data)) |
---|
3803 | Â Â T.sort() |
---|
3804 |   if reverse: |
---|
3805 | Â Â Â Â T.reverse() |
---|
3806 | Â Â X =Â [] |
---|
3807 |   for key in T: |
---|
3808 | Â Â Â Â X.append(D[key]) |
---|
3809 |   return X |
---|
3810 | |
---|
3811 | def PeaksEquiv(data,Ind): |
---|
3812 | Â Â '''Find the equivalent map peaks for those selected. Works on the |
---|
3813 | Â Â contents of data['Map Peaks']. |
---|
3814 | |
---|
3815 | Â Â :param data: the phase data structure |
---|
3816 | Â Â :param list Ind: list of selected peak indices |
---|
3817 | Â Â :returns: augmented list of peaks including those related by symmetry to the |
---|
3818 | Â Â Â ones in Ind |
---|
3819 | |
---|
3820 | Â Â '''Â Â Â Â |
---|
3821 |   def Duplicate(xyz,peaks,Amat): |
---|
3822 |     if True in [np.allclose(np.inner(Amat,xyz),np.inner(Amat,peak),atol=0.5) for peak in peaks]: |
---|
3823 |       return True |
---|
3824 |     return False |
---|
3825 | Â Â Â Â Â Â Â Â Â Â Â Â Â Â |
---|
3826 | Â Â generalData =Â data['General'] |
---|
3827 | Â Â Amat,Bmat =Â G2lat.cell2AB(generalData['Cell'][1:7]) |
---|
3828 | Â Â SGData =Â generalData['SGData'] |
---|
3829 | Â Â mapPeaks =Â data['Map Peaks'] |
---|
3830 |   XYZ = np.array([xyz[1:4] for xyz in mapPeaks]) |
---|
3831 | Â Â Indx =Â {} |
---|
3832 |   for ind in Ind: |
---|
3833 | Â Â Â Â xyz =Â np.array(mapPeaks[ind][1:4]) |
---|
3834 |     xyzs = np.array([equiv[0] for equiv in G2spc.GenAtom(xyz,SGData,Move=True)]) |
---|
3835 |     for jnd,xyz in enumerate(XYZ):    |
---|
3836 | Â Â Â Â Â Â Indx[jnd]Â =Â Duplicate(xyz,xyzs,Amat) |
---|
3837 | Â Â Ind =Â [] |
---|
3838 |   for ind in Indx: |
---|
3839 |     if Indx[ind]: |
---|
3840 | Â Â Â Â Â Â Ind.append(ind) |
---|
3841 |   return Ind |
---|
3842 | Â Â Â Â Â Â Â Â |
---|
3843 | def PeaksUnique(data,Ind): |
---|
3844 | Â Â '''Finds the symmetry unique set of peaks from those selected. Works on the |
---|
3845 | Â Â contents of data['Map Peaks']. |
---|
3846 | |
---|
3847 | Â Â :param data: the phase data structure |
---|
3848 | Â Â :param list Ind: list of selected peak indices |
---|
3849 | Â Â :returns: the list of symmetry unique peaks from among those given in Ind |
---|
3850 | |
---|
3851 | Â Â '''Â Â Â Â |
---|
3852 | #Â Â XYZE = np.array([[equiv[0] for equiv in G2spc.GenAtom(xyz[1:4],SGData,Move=True)] for xyz in mapPeaks]) #keep this!! |
---|
3853 | |
---|
3854 |   def noDuplicate(xyz,peaks,Amat): |
---|
3855 |     if True in [np.allclose(np.inner(Amat,xyz),np.inner(Amat,peak),atol=0.5) for peak in peaks]: |
---|
3856 |       return False |
---|
3857 |     return True |
---|
3858 | Â Â Â Â Â Â Â Â Â Â Â Â Â Â |
---|
3859 | Â Â generalData =Â data['General'] |
---|
3860 | Â Â Amat,Bmat =Â G2lat.cell2AB(generalData['Cell'][1:7]) |
---|
3861 | Â Â SGData =Â generalData['SGData'] |
---|
3862 | Â Â mapPeaks =Â data['Map Peaks'] |
---|
3863 | Â Â Indx =Â {} |
---|
3864 | Â Â XYZ =Â {} |
---|
3865 |   for ind in Ind: |
---|
3866 | Â Â Â Â XYZ[ind]Â =Â np.array(mapPeaks[ind][1:4]) |
---|
3867 | Â Â Â Â Indx[ind]Â =Â True |
---|
3868 |   for ind in Ind: |
---|
3869 |     if Indx[ind]: |
---|
3870 | Â Â Â Â Â Â xyz =Â XYZ[ind] |
---|
3871 |       for jnd in Ind: |
---|
3872 |         if ind != jnd and Indx[jnd]:            |
---|
3873 | Â Â Â Â Â Â Â Â Â Â Equiv =Â G2spc.GenAtom(XYZ[jnd],SGData,Move=True) |
---|
3874 |           xyzs = np.array([equiv[0] for equiv in Equiv]) |
---|
3875 | Â Â Â Â Â Â Â Â Â Â Indx[jnd]Â =Â noDuplicate(xyz,xyzs,Amat) |
---|
3876 | Â Â Ind =Â [] |
---|
3877 |   for ind in Indx: |
---|
3878 |     if Indx[ind]: |
---|
3879 | Â Â Â Â Â Â Ind.append(ind) |
---|
3880 |   return Ind |
---|
3881 | Â Â |
---|
3882 | ################################################################################ |
---|
3883 | ##### single peak fitting profile fxn stuff |
---|
3884 | ################################################################################ |
---|
3885 | |
---|
3886 | def getCWsig(ins,pos): |
---|
3887 | Â Â '''get CW peak profile sigma^2 |
---|
3888 | Â Â |
---|
3889 | Â Â :param dict ins: instrument parameters with at least 'U', 'V', & 'W' |
---|
3890 | Â Â Â as values only |
---|
3891 | Â Â :param float pos: 2-theta of peak |
---|
3892 | Â Â :returns: float getCWsig: peak sigma^2 |
---|
3893 | Â Â |
---|
3894 | Â Â ''' |
---|
3895 | Â Â tp =Â tand(pos/2.0) |
---|
3896 |   return ins['U']*tp**2+ins['V']*tp+ins['W'] |
---|
3897 | Â Â |
---|
3898 | def getCWsigDeriv(pos): |
---|
3899 | Â Â '''get derivatives of CW peak profile sigma^2 wrt U,V, & W |
---|
3900 | Â Â |
---|
3901 | Â Â :param float pos: 2-theta of peak |
---|
3902 | Â Â |
---|
3903 | Â Â :returns: list getCWsigDeriv: d(sig^2)/dU, d(sig)/dV & d(sig)/dW |
---|
3904 | Â Â |
---|
3905 | Â Â ''' |
---|
3906 | Â Â tp =Â tand(pos/2.0) |
---|
3907 |   return tp**2,tp,1.0 |
---|
3908 | Â Â |
---|
3909 | def getCWgam(ins,pos): |
---|
3910 | Â Â '''get CW peak profile gamma |
---|
3911 | Â Â |
---|
3912 | Â Â :param dict ins: instrument parameters with at least 'X', 'Y' & 'Z' |
---|
3913 | Â Â Â as values only |
---|
3914 | Â Â :param float pos: 2-theta of peak |
---|
3915 | Â Â :returns: float getCWgam: peak gamma |
---|
3916 | Â Â |
---|
3917 | Â Â ''' |
---|
3918 |   return ins['X']/cosd(pos/2.0)+ins['Y']*tand(pos/2.0)+ins['Z'] |
---|
3919 | Â Â |
---|
3920 | def getCWgamDeriv(pos): |
---|
3921 | Â Â '''get derivatives of CW peak profile gamma wrt X, Y & Z |
---|
3922 | Â Â |
---|
3923 | Â Â :param float pos: 2-theta of peak |
---|
3924 | Â Â |
---|
3925 | Â Â :returns: list getCWgamDeriv: d(gam)/dX & d(gam)/dY |
---|
3926 | Â Â |
---|
3927 | Â Â ''' |
---|
3928 |   return 1./cosd(pos/2.0),tand(pos/2.0),1.0 |
---|
3929 | Â Â |
---|
3930 | def getTOFsig(ins,dsp): |
---|
3931 | Â Â '''get TOF peak profile sigma^2 |
---|
3932 | Â Â |
---|
3933 | Â Â :param dict ins: instrument parameters with at least 'sig-0', 'sig-1' & 'sig-q' |
---|
3934 | Â Â Â as values only |
---|
3935 | Â Â :param float dsp: d-spacing of peak |
---|
3936 | Â Â |
---|
3937 | Â Â :returns: float getTOFsig: peak sigma^2 |
---|
3938 | Â Â |
---|
3939 | Â Â ''' |
---|
3940 |   return ins['sig-0']+ins['sig-1']*dsp**2+ins['sig-2']*dsp**4+ins['sig-q']*dsp |
---|
3941 | Â Â |
---|
3942 | def getTOFsigDeriv(dsp): |
---|
3943 | Â Â '''get derivatives of TOF peak profile sigma^2 wrt sig-0, sig-1, & sig-q |
---|
3944 | Â Â |
---|
3945 | Â Â :param float dsp: d-spacing of peak |
---|
3946 | Â Â |
---|
3947 | Â Â :returns: list getTOFsigDeriv: d(sig0/d(sig-0), d(sig)/d(sig-1) & d(sig)/d(sig-q) |
---|
3948 | Â Â |
---|
3949 | Â Â ''' |
---|
3950 |   return 1.0,dsp**2,dsp**4,dsp |
---|
3951 | Â Â |
---|
3952 | def getTOFgamma(ins,dsp): |
---|
3953 | Â Â '''get TOF peak profile gamma |
---|
3954 | Â Â |
---|
3955 | Â Â :param dict ins: instrument parameters with at least 'X', 'Y' & 'Z' |
---|
3956 | Â Â Â as values only |
---|
3957 | Â Â :param float dsp: d-spacing of peak |
---|
3958 | Â Â |
---|
3959 | Â Â :returns: float getTOFgamma: peak gamma |
---|
3960 | Â Â |
---|
3961 | Â Â ''' |
---|
3962 |   return ins['Z']+ins['X']*dsp+ins['Y']*dsp**2 |
---|
3963 | Â Â |
---|
3964 | def getTOFgammaDeriv(dsp): |
---|
3965 | Â Â '''get derivatives of TOF peak profile gamma wrt X, Y & Z |
---|
3966 | Â Â |
---|
3967 | Â Â :param float dsp: d-spacing of peak |
---|
3968 | Â Â |
---|
3969 | Â Â :returns: list getTOFgammaDeriv: d(gam)/dX & d(gam)/dY |
---|
3970 | Â Â |
---|
3971 | Â Â ''' |
---|
3972 |   return dsp,dsp**2,1.0 |
---|
3973 | Â Â |
---|
3974 | def getTOFbeta(ins,dsp): |
---|
3975 | Â Â '''get TOF peak profile beta |
---|
3976 | Â Â |
---|
3977 | Â Â :param dict ins: instrument parameters with at least 'beat-0', 'beta-1' & 'beta-q' |
---|
3978 | Â Â Â as values only |
---|
3979 | Â Â :param float dsp: d-spacing of peak |
---|
3980 | Â Â |
---|
3981 | Â Â :returns: float getTOFbeta: peak beat |
---|
3982 | Â Â |
---|
3983 | Â Â ''' |
---|
3984 |   return ins['beta-0']+ins['beta-1']/dsp**4+ins['beta-q']/dsp**2 |
---|
3985 | Â Â |
---|
3986 | def getTOFbetaDeriv(dsp): |
---|
3987 | Â Â '''get derivatives of TOF peak profile beta wrt beta-0, beta-1, & beat-q |
---|
3988 | Â Â |
---|
3989 | Â Â :param float dsp: d-spacing of peak |
---|
3990 | Â Â |
---|
3991 | Â Â :returns: list getTOFbetaDeriv: d(beta)/d(beat-0), d(beta)/d(beta-1) & d(beta)/d(beta-q) |
---|
3992 | Â Â |
---|
3993 | Â Â ''' |
---|
3994 |   return 1.0,1./dsp**4,1./dsp**2 |
---|
3995 | Â Â |
---|
3996 | def getTOFalpha(ins,dsp): |
---|
3997 | Â Â '''get TOF peak profile alpha |
---|
3998 | Â Â |
---|
3999 | Â Â :param dict ins: instrument parameters with at least 'alpha' |
---|
4000 | Â Â Â as values only |
---|
4001 | Â Â :param float dsp: d-spacing of peak |
---|
4002 | Â Â |
---|
4003 | Â Â :returns: flaot getTOFalpha: peak alpha |
---|
4004 | Â Â |
---|
4005 | Â Â ''' |
---|
4006 |   return ins['alpha']/dsp |
---|
4007 | Â Â |
---|
4008 | def getTOFalphaDeriv(dsp): |
---|
4009 | Â Â '''get derivatives of TOF peak profile beta wrt alpha |
---|
4010 | Â Â |
---|
4011 | Â Â :param float dsp: d-spacing of peak |
---|
4012 | Â Â |
---|
4013 | Â Â :returns: float getTOFalphaDeriv: d(alp)/d(alpha) |
---|
4014 | Â Â |
---|
4015 | Â Â ''' |
---|
4016 |   return 1./dsp |
---|
4017 | Â Â |
---|
4018 | def setPeakparms(Parms,Parms2,pos,mag,ifQ=False,useFit=False): |
---|
4019 | Â Â '''set starting peak parameters for single peak fits from plot selection or auto selection |
---|
4020 | Â Â |
---|
4021 | Â Â :param dict Parms: instrument parameters dictionary |
---|
4022 | Â Â :param dict Parms2: table lookup for TOF profile coefficients |
---|
4023 | Â Â :param float pos: peak position in 2-theta, TOF or Q (ifQ=True) |
---|
4024 | Â Â :param float mag: peak top magnitude from pick |
---|
4025 | Â Â :param bool ifQ: True if pos in Q |
---|
4026 | Â Â :param bool useFit: True if use fitted CW Parms values (not defaults) |
---|
4027 | Â Â |
---|
4028 | Â Â :returns: list XY: peak list entry: |
---|
4029 | Â Â Â Â for CW: [pos,0,mag,1,sig,0,gam,0] |
---|
4030 | Â Â Â Â for TOF: [pos,0,mag,1,alp,0,bet,0,sig,0,gam,0] |
---|
4031 | Â Â Â Â NB: mag refinement set by default, all others off |
---|
4032 | Â Â |
---|
4033 | Â Â ''' |
---|
4034 | Â Â ind =Â 0 |
---|
4035 |   if useFit: |
---|
4036 | Â Â Â Â ind =Â 1 |
---|
4037 | Â Â ins =Â {} |
---|
4038 |   if 'C' in Parms['Type'][0]:              #CW data - TOF later in an else |
---|
4039 |     for x in ['U','V','W','X','Y','Z']: |
---|
4040 | Â Â Â Â Â Â ins[x]Â =Â Parms[x][ind] |
---|
4041 |     if ifQ:               #qplot - convert back to 2-theta |
---|
4042 | Â Â Â Â Â Â pos =Â 2.0*asind(pos*getWave(Parms)/(4*math.pi)) |
---|
4043 | Â Â Â Â sig =Â getCWsig(ins,pos) |
---|
4044 | Â Â Â Â gam =Â getCWgam(ins,pos)Â Â Â Â Â Â |
---|
4045 |     XY = [pos,0, mag,1, sig,0, gam,0]    #default refine intensity 1st |
---|
4046 | Â Â else: |
---|
4047 |     if ifQ: |
---|
4048 | Â Â Â Â Â Â dsp =Â 2.*np.pi/pos |
---|
4049 | Â Â Â Â Â Â pos =Â Parms['difC']*dsp |
---|
4050 | Â Â Â Â else: |
---|
4051 | Â Â Â Â Â Â dsp =Â pos/Parms['difC'][1] |
---|
4052 |     if 'Pdabc' in Parms2: |
---|
4053 |       for x in ['sig-0','sig-1','sig-2','sig-q','X','Y','Z']: |
---|
4054 | Â Â Â Â Â Â Â Â ins[x]Â =Â Parms[x][ind] |
---|
4055 | Â Â Â Â Â Â Pdabc =Â Parms2['Pdabc'].T |
---|
4056 | Â Â Â Â Â Â alp =Â np.interp(dsp,Pdabc[0],Pdabc[1]) |
---|
4057 | Â Â Â Â Â Â bet =Â np.interp(dsp,Pdabc[0],Pdabc[2]) |
---|
4058 | Â Â Â Â else: |
---|
4059 |       for x in ['alpha','beta-0','beta-1','beta-q','sig-0','sig-1','sig-2','sig-q','X','Y','Z']: |
---|
4060 | Â Â Â Â Â Â Â Â ins[x]Â =Â Parms[x][ind] |
---|
4061 | Â Â Â Â Â Â alp =Â getTOFalpha(ins,dsp) |
---|
4062 | Â Â Â Â Â Â bet =Â getTOFbeta(ins,dsp) |
---|
4063 | Â Â Â Â sig =Â getTOFsig(ins,dsp) |
---|
4064 | Â Â Â Â gam =Â getTOFgamma(ins,dsp) |
---|
4065 | Â Â Â Â XY =Â [pos,0,mag,1,alp,0,bet,0,sig,0,gam,0] |
---|
4066 |   return XY |
---|
4067 | Â Â |
---|
4068 | ################################################################################ |
---|
4069 | ##### MC/SA stuff |
---|
4070 | ################################################################################ |
---|
4071 | |
---|
4072 | #scipy/optimize/anneal.py code modified by R. Von Dreele 2013 |
---|
4073 | # Original Author: Travis Oliphant 2002 |
---|
4074 | # Bug-fixes in 2006 by Tim Leslie |
---|
4075 | |
---|
4076 | |
---|
4077 | import numpy |
---|
4078 | from numpy import asarray, exp, squeeze, sign, \ |
---|
4079 |    all, shape, array, where |
---|
4080 | from numpy import random |
---|
4081 | |
---|
4082 | #__all__ = ['anneal'] |
---|
4083 | |
---|
4084 | _double_min =Â numpy.finfo(float).min |
---|
4085 | _double_max =Â numpy.finfo(float).max |
---|
4086 | class base_schedule(object): |
---|
4087 |   def __init__(self): |
---|
4088 | Â Â Â Â self.dwell =Â 20 |
---|
4089 | Â Â Â Â self.lower =Â 0. |
---|
4090 | Â Â Â Â self.upper =Â 1. |
---|
4091 | Â Â Â Â self.Ninit =Â 50 |
---|
4092 | Â Â Â Â self.accepted =Â 0 |
---|
4093 | Â Â Â Â self.tests =Â 0 |
---|
4094 | Â Â Â Â self.feval =Â 0 |
---|
4095 | Â Â Â Â self.k =Â 0 |
---|
4096 | Â Â Â Â self.T =Â None |
---|
4097 | |
---|
4098 |   def init(self, **options): |
---|
4099 | Â Â Â Â self.__dict__.update(options) |
---|
4100 | Â Â Â Â self.lower =Â asarray(self.lower) |
---|
4101 |     self.lower = where(self.lower == numpy.NINF, -_double_max, self.lower) |
---|
4102 | Â Â Â Â self.upper =Â asarray(self.upper) |
---|
4103 |     self.upper = where(self.upper == numpy.PINF, _double_max, self.upper) |
---|
4104 | Â Â Â Â self.k =Â 0 |
---|
4105 | Â Â Â Â self.accepted =Â 0 |
---|
4106 | Â Â Â Â self.feval =Â 0 |
---|
4107 | Â Â Â Â self.tests =Â 0 |
---|
4108 | |
---|
4109 |   def getstart_temp(self, best_state): |
---|
4110 | Â Â Â Â """ Find a matching starting temperature and starting parameters vector |
---|
4111 | Â Â Â Â i.e. find x0 such that func(x0) = T0. |
---|
4112 | |
---|
4113 | Â Â Â Â :param best_state: _state |
---|
4114 | Â Â Â Â Â Â A _state object to store the function value and x0 found. |
---|
4115 | |
---|
4116 | Â Â Â Â :returns: x0 : array |
---|
4117 | Â Â Â Â Â Â The starting parameters vector. |
---|
4118 | Â Â Â Â """ |
---|
4119 | |
---|
4120 |     assert(not self.dims is None) |
---|
4121 | Â Â Â Â lrange =Â self.lower |
---|
4122 | Â Â Â Â urange =Â self.upper |
---|
4123 | Â Â Â Â fmax =Â _double_min |
---|
4124 | Â Â Â Â fmin =Â _double_max |
---|
4125 |     for _ in range(self.Ninit): |
---|
4126 | Â Â Â Â Â Â x0 =Â random.uniform(size=self.dims)*(urange-lrange)Â +Â lrange |
---|
4127 |       fval = self.func(x0, *self.args) |
---|
4128 | Â Â Â Â Â Â self.feval +=Â 1 |
---|
4129 |       if fval > fmax: |
---|
4130 | Â Â Â Â Â Â Â Â fmax =Â fval |
---|
4131 |       if fval < fmin: |
---|
4132 | Â Â Â Â Â Â Â Â fmin =Â fval |
---|
4133 | Â Â Â Â Â Â Â Â best_state.cost =Â fval |
---|
4134 | Â Â Â Â Â Â Â Â best_state.x =Â array(x0) |
---|
4135 | |
---|
4136 | Â Â Â Â self.T0 =Â (fmax-fmin)*1.5 |
---|
4137 |     return best_state.x |
---|
4138 | Â Â Â Â |
---|
4139 |   def set_range(self,x0,frac): |
---|
4140 | Â Â Â Â delrange =Â frac*(self.upper-self.lower) |
---|
4141 | Â Â Â Â self.upper =Â x0+delrange |
---|
4142 | Â Â Â Â self.lower =Â x0-delrange |
---|
4143 | |
---|
4144 |   def accept_test(self, dE): |
---|
4145 | Â Â Â Â T =Â self.T |
---|
4146 | Â Â Â Â self.tests +=Â 1 |
---|
4147 |     if dE < 0: |
---|
4148 | Â Â Â Â Â Â self.accepted +=Â 1 |
---|
4149 |       return 1 |
---|
4150 | Â Â Â Â p =Â exp(-dE*1.0/T) |
---|
4151 |     if (p > random.uniform(0.0, 1.0)): |
---|
4152 | Â Â Â Â Â Â self.accepted +=Â 1 |
---|
4153 |       return 1 |
---|
4154 |     return 0 |
---|
4155 | |
---|
4156 |   def update_guess(self, x0): |
---|
4157 |     return np.squeeze(np.random.uniform(0.,1.,size=self.dims))*(self.upper-self.lower)+self.lower |
---|
4158 | |
---|
4159 |   def update_temp(self, x0): |
---|
4160 | Â Â Â Â pass |
---|
4161 | |
---|
4162 | class fast_sa(base_schedule): |
---|
4163 |   def init(self, **options): |
---|
4164 | Â Â Â Â self.__dict__.update(options) |
---|
4165 | |
---|
4166 |   def update_guess(self, x0): |
---|
4167 | Â Â Â Â x0 =Â asarray(x0) |
---|
4168 |     u = squeeze(random.uniform(0.0, 1.0, size=self.dims)) |
---|
4169 | Â Â Â Â T =Â self.T |
---|
4170 | Â Â Â Â xc =Â (sign(u-0.5)*T*((1+1.0/T)**abs(2*u-1)-1.0)+1.0)/2.0 |
---|
4171 | Â Â Â Â xnew =Â xc*(self.upper -Â self.lower)+self.lower |
---|
4172 |     return xnew |
---|
4173 | |
---|
4174 |   def update_temp(self): |
---|
4175 | Â Â Â Â self.T =Â self.T0*exp(-self.c *Â self.k**(self.quench)) |
---|
4176 | Â Â Â Â self.k +=Â 1 |
---|
4177 | Â Â Â Â return |
---|
4178 | |
---|
4179 | class log_sa(base_schedule):    #OK |
---|
4180 | |
---|
4181 |   def init(self,**options): |
---|
4182 | Â Â Â Â self.__dict__.update(options) |
---|
4183 | Â Â Â Â |
---|
4184 |   def update_guess(self,x0):   #same as default #TODO - is this a reasonable update procedure? |
---|
4185 |     u = squeeze(random.uniform(0.0, 1.0, size=self.dims)) |
---|
4186 | Â Â Â Â T =Â self.T |
---|
4187 | Â Â Â Â xc =Â (sign(u-0.5)*T*((1+1.0/T)**abs(2*u-1)-1.0)+1.0)/2.0 |
---|
4188 | Â Â Â Â xnew =Â xc*(self.upper -Â self.lower)+self.lower |
---|
4189 |     return xnew |
---|
4190 | Â Â Â Â |
---|
4191 |   def update_temp(self): |
---|
4192 | Â Â Â Â self.k +=Â 1 |
---|
4193 | Â Â Â Â self.T =Â self.T0*self.slope**self.k |
---|
4194 | Â Â Â Â |
---|
4195 | class _state(object): |
---|
4196 |   def __init__(self): |
---|
4197 | Â Â Â Â self.x =Â None |
---|
4198 | Â Â Â Â self.cost =Â None |
---|
4199 | |
---|
4200 | def makeTsched(data): |
---|
4201 |   if data['Algorithm'] == 'fast': |
---|
4202 | Â Â Â Â sched =Â fast_sa() |
---|
4203 | Â Â Â Â sched.quench =Â data['fast parms'][0] |
---|
4204 | Â Â Â Â sched.c =Â data['fast parms'][1] |
---|
4205 |   elif data['Algorithm'] == 'log': |
---|
4206 | Â Â Â Â sched =Â log_sa() |
---|
4207 | Â Â Â Â sched.slope =Â data['log slope'] |
---|
4208 | Â Â sched.T0 =Â data['Annealing'][0] |
---|
4209 |   if not sched.T0: |
---|
4210 | Â Â Â Â sched.T0 =Â 50. |
---|
4211 | Â Â Tf =Â data['Annealing'][1] |
---|
4212 |   if not Tf: |
---|
4213 | Â Â Â Â Tf =Â 0.001 |
---|
4214 | Â Â Tsched =Â [sched.T0,] |
---|
4215 |   while Tsched[-1] > Tf: |
---|
4216 | Â Â Â Â sched.update_temp() |
---|
4217 | Â Â Â Â Tsched.append(sched.T) |
---|
4218 |   return Tsched[1:] |
---|
4219 | Â Â |
---|
4220 | def anneal(func, x0, args=(), schedule='fast', |
---|
4221 |       T0=None, Tf=1e-12, maxeval=None, maxaccept=None, maxiter=400, |
---|
4222 |       feps=1e-6, quench=1.0, c=1.0, |
---|
4223 |       lower=-100, upper=100, dwell=50, slope=0.9,ranStart=False, |
---|
4224 | Â Â Â Â Â Â ranRange=0.10,autoRan=False,dlg=None): |
---|
4225 | Â Â """Minimize a function using simulated annealing. |
---|
4226 | |
---|
4227 | Â Â Schedule is a schedule class implementing the annealing schedule. |
---|
4228 | Â Â Available ones are 'fast', 'cauchy', 'boltzmann' |
---|
4229 | |
---|
4230 | Â Â :param callable func: f(x, \*args) |
---|
4231 | Â Â Â Â Function to be optimized. |
---|
4232 | Â Â :param ndarray x0: |
---|
4233 | Â Â Â Â Initial guess. |
---|
4234 | Â Â :param tuple args: |
---|
4235 | Â Â Â Â Extra parameters to `func`. |
---|
4236 | Â Â :param base_schedule schedule: |
---|
4237 | Â Â Â Â Annealing schedule to use (a class). |
---|
4238 | Â Â :param float T0: |
---|
4239 | Â Â Â Â Initial Temperature (estimated as 1.2 times the largest |
---|
4240 | Â Â Â Â cost-function deviation over random points in the range). |
---|
4241 | Â Â :param float Tf: |
---|
4242 | Â Â Â Â Final goal temperature. |
---|
4243 | Â Â :param int maxeval: |
---|
4244 | Â Â Â Â Maximum function evaluations. |
---|
4245 | Â Â :param int maxaccept: |
---|
4246 | Â Â Â Â Maximum changes to accept. |
---|
4247 | Â Â :param int maxiter: |
---|
4248 | Â Â Â Â Maximum cooling iterations. |
---|
4249 | Â Â :param float feps: |
---|
4250 | Â Â Â Â Stopping relative error tolerance for the function value in |
---|
4251 | Â Â Â Â last four coolings. |
---|
4252 | Â Â :param float quench,c: |
---|
4253 | Â Â Â Â Parameters to alter fast_sa schedule. |
---|
4254 | Â Â :param float/ndarray lower,upper: |
---|
4255 | Â Â Â Â Lower and upper bounds on `x`. |
---|
4256 | Â Â :param int dwell: |
---|
4257 | Â Â Â Â The number of times to search the space at each temperature. |
---|
4258 | Â Â :param float slope: |
---|
4259 | Â Â Â Â Parameter for log schedule |
---|
4260 | Â Â :param bool ranStart=False: |
---|
4261 | Â Â Â Â True for set 10% of ranges about x |
---|
4262 | |
---|
4263 | Â Â :returns: (xmin, Jmin, T, feval, iters, accept, retval) where |
---|
4264 | |
---|
4265 | Â Â Â * xmin (ndarray): Point giving smallest value found. |
---|
4266 | Â Â Â * Jmin (float): Minimum value of function found. |
---|
4267 | Â Â Â * T (float): Final temperature. |
---|
4268 | Â Â Â * feval (int): Number of function evaluations. |
---|
4269 | Â Â Â * iters (int): Number of cooling iterations. |
---|
4270 | Â Â Â * accept (int): Number of tests accepted. |
---|
4271 | Â Â Â * retval (int): Flag indicating stopping condition: |
---|
4272 | |
---|
4273 | Â Â Â Â Â Â Â *Â 0: Points no longer changing |
---|
4274 | Â Â Â Â Â Â Â *Â 1: Cooled to final temperature |
---|
4275 | Â Â Â Â Â Â Â *Â 2: Maximum function evaluations |
---|
4276 | Â Â Â Â Â Â Â *Â 3: Maximum cooling iterations reached |
---|
4277 | Â Â Â Â Â Â Â *Â 4: Maximum accepted query locations reached |
---|
4278 | Â Â Â Â Â Â Â *Â 5: Final point not the minimum amongst encountered points |
---|
4279 | |
---|
4280 | Â Â *Notes*: |
---|
4281 | Â Â Simulated annealing is a random algorithm which uses no derivative |
---|
4282 | Â Â information from the function being optimized. In practice it has |
---|
4283 | Â Â been more useful in discrete optimization than continuous |
---|
4284 | Â Â optimization, as there are usually better algorithms for continuous |
---|
4285 | Â Â optimization problems. |
---|
4286 | |
---|
4287 | Â Â Some experimentation by trying the difference temperature |
---|
4288 | Â Â schedules and altering their parameters is likely required to |
---|
4289 | Â Â obtain good performance. |
---|
4290 | |
---|
4291 | Â Â The randomness in the algorithm comes from random sampling in numpy. |
---|
4292 | Â Â To obtain the same results you can call numpy.random.seed with the |
---|
4293 | Â Â same seed immediately before calling scipy.optimize.anneal. |
---|
4294 | |
---|
4295 | Â Â We give a brief description of how the three temperature schedules |
---|
4296 | Â Â generate new points and vary their temperature. Temperatures are |
---|
4297 | Â Â only updated with iterations in the outer loop. The inner loop is |
---|
4298 | Â Â over range(dwell), and new points are generated for |
---|
4299 | Â Â every iteration in the inner loop. (Though whether the proposed |
---|
4300 | Â Â new points are accepted is probabilistic.) |
---|
4301 | |
---|
4302 | Â Â For readability, let d denote the dimension of the inputs to func. |
---|
4303 | Â Â Also, let x_old denote the previous state, and k denote the |
---|
4304 | Â Â iteration number of the outer loop. All other variables not |
---|
4305 | Â Â defined below are input variables to scipy.optimize.anneal itself. |
---|
4306 | |
---|
4307 | Â Â In the 'fast' schedule the updates are :: |
---|
4308 | |
---|
4309 | Â Â Â Â u ~ Uniform(0, 1, size=d) |
---|
4310 | Â Â Â Â y = sgn(u - 0.5) * T * ((1+ 1/T)**abs(2u-1) -1.0) |
---|
4311 | Â Â Â Â xc = y * (upper - lower) |
---|
4312 | Â Â Â Â x_new = x_old + xc |
---|
4313 | |
---|
4314 | Â Â Â Â T_new = T0 * exp(-c * k**quench) |
---|
4315 | |
---|
4316 | Â Â """ |
---|
4317 | Â Â |
---|
4318 | Â Â ''' Scipy license: |
---|
4319 | Â Â Â Â Copyright (c) 2001, 2002 Enthought, Inc. |
---|
4320 | Â Â All rights reserved. |
---|
4321 | Â Â |
---|
4322 | Â Â Copyright (c) 2003-2016 SciPy Developers. |
---|
4323 | Â Â All rights reserved. |
---|
4324 | Â Â |
---|
4325 | Â Â Redistribution and use in source and binary forms, with or without |
---|
4326 | Â Â modification, are permitted provided that the following conditions are met: |
---|
4327 | Â Â |
---|
4328 | Â Â Â a. Redistributions of source code must retain the above copyright notice, |
---|
4329 | Â Â Â Â Â this list of conditions and the following disclaimer. |
---|
4330 | Â Â Â b. Redistributions in binary form must reproduce the above copyright |
---|
4331 | Â Â Â Â Â notice, this list of conditions and the following disclaimer in the |
---|
4332 | Â Â Â Â Â documentation and/or other materials provided with the distribution. |
---|
4333 | Â Â Â c. Neither the name of Enthought nor the names of the SciPy Developers |
---|
4334 | Â Â Â Â Â may be used to endorse or promote products derived from this software |
---|
4335 | Â Â Â Â Â without specific prior written permission. |
---|
4336 | Â Â ''' |
---|
4337 | Â Â x0 =Â asarray(x0) |
---|
4338 | Â Â lower =Â asarray(lower) |
---|
4339 | Â Â upper =Â asarray(upper) |
---|
4340 | |
---|
4341 | Â Â schedule =Â eval(schedule+'_sa()') |
---|
4342 | Â Â #Â Â initialize the schedule |
---|
4343 |   schedule.init(dims=shape(x0),func=func,args=args,T0=T0,lower=lower, upper=upper, |
---|
4344 |     c=c, quench=quench, dwell=dwell, slope=slope) |
---|
4345 | |
---|
4346 |   current_state, last_state, best_state = _state(), _state(), _state() |
---|
4347 |   if ranStart: |
---|
4348 | Â Â Â Â schedule.set_range(x0,ranRange) |
---|
4349 |   if T0 is None: |
---|
4350 | Â Â Â Â x0 =Â schedule.getstart_temp(best_state) |
---|
4351 | Â Â else: |
---|
4352 | Â Â Â Â x0 =Â random.uniform(size=len(x0))*(upper-lower)Â +Â lower |
---|
4353 | Â Â Â Â best_state.x =Â None |
---|
4354 | Â Â Â Â best_state.cost =Â numpy.Inf |
---|
4355 | |
---|
4356 | Â Â last_state.x =Â asarray(x0).copy() |
---|
4357 | Â Â fval =Â func(x0,*args) |
---|
4358 | Â Â schedule.feval +=Â 1 |
---|
4359 | Â Â last_state.cost =Â fval |
---|
4360 |   if last_state.cost < best_state.cost: |
---|
4361 | Â Â Â Â best_state.cost =Â fval |
---|
4362 | Â Â Â Â best_state.x =Â asarray(x0).copy() |
---|
4363 | Â Â schedule.T =Â schedule.T0 |
---|
4364 |   fqueue = [100, 300, 500, 700] |
---|
4365 | Â Â iters =Â 1 |
---|
4366 | Â Â keepGoing =Â True |
---|
4367 | Â Â bestn =Â 0 |
---|
4368 |   while keepGoing: |
---|
4369 | Â Â Â Â retval =Â 0 |
---|
4370 |     for n in range(dwell): |
---|
4371 | Â Â Â Â Â Â current_state.x =Â schedule.update_guess(last_state.x) |
---|
4372 | Â Â Â Â Â Â current_state.cost =Â func(current_state.x,*args) |
---|
4373 | Â Â Â Â Â Â schedule.feval +=Â 1 |
---|
4374 | |
---|
4375 | Â Â Â Â Â Â dE =Â current_state.cost -Â last_state.cost |
---|
4376 |       if schedule.accept_test(dE): |
---|
4377 | Â Â Â Â Â Â Â Â last_state.x =Â current_state.x.copy() |
---|
4378 | Â Â Â Â Â Â Â Â last_state.cost =Â current_state.cost |
---|
4379 |         if last_state.cost < best_state.cost: |
---|
4380 | Â Â Â Â Â Â Â Â Â Â best_state.x =Â last_state.x.copy() |
---|
4381 | Â Â Â Â Â Â Â Â Â Â best_state.cost =Â last_state.cost |
---|
4382 | Â Â Â Â Â Â Â Â Â Â bestn =Â n |
---|
4383 |           if best_state.cost < 1.0 and autoRan: |
---|
4384 | Â Â Â Â Â Â Â Â Â Â Â Â schedule.set_range(x0,best_state.cost/2.)Â Â Â Â Â Â Â Â Â Â Â Â |
---|
4385 |     if dlg: |
---|
4386 | Â Â Â Â Â Â GoOn =Â dlg.Update(min(100.,best_state.cost*100), |
---|
4387 |         newmsg='%s%8.5f, %s%d\n%s%8.4f%s'%('Temperature =',schedule.T, \ |
---|
4388 |           'Best trial:',bestn, \ |
---|
4389 |           'MC/SA Residual:',best_state.cost*100,'%', \ |
---|
4390 | Â Â Â Â Â Â Â Â Â Â ))[0] |
---|
4391 |       if not GoOn: |
---|
4392 | Â Â Â Â Â Â Â Â best_state.x =Â last_state.x.copy() |
---|
4393 | Â Â Â Â Â Â Â Â best_state.cost =Â last_state.cost |
---|
4394 | Â Â Â Â Â Â Â Â retval =Â 5 |
---|
4395 | Â Â Â Â schedule.update_temp() |
---|
4396 | Â Â Â Â iters +=Â 1 |
---|
4397 | Â Â Â Â # Stopping conditions |
---|
4398 | Â Â Â Â # 0) last saved values of f from each cooling step |
---|
4399 | Â Â Â Â #Â Â Â are all very similar (effectively cooled) |
---|
4400 | Â Â Â Â # 1) Tf is set and we are below it |
---|
4401 | Â Â Â Â # 2) maxeval is set and we are past it |
---|
4402 | Â Â Â Â # 3) maxiter is set and we are past it |
---|
4403 | Â Â Â Â # 4) maxaccept is set and we are past it |
---|
4404 | Â Â Â Â # 5) user canceled run via progress bar |
---|
4405 | |
---|
4406 | Â Â Â Â fqueue.append(squeeze(last_state.cost)) |
---|
4407 | Â Â Â Â fqueue.pop(0) |
---|
4408 | Â Â Â Â af =Â asarray(fqueue)*1.0 |
---|
4409 |     if retval == 5: |
---|
4410 |       print (' User terminated run; incomplete MC/SA') |
---|
4411 | Â Â Â Â Â Â keepGoing =Â False |
---|
4412 | Â Â Â Â Â Â break |
---|
4413 |     if all(abs((af-af[0])/af[0]) < feps): |
---|
4414 | Â Â Â Â Â Â retval =Â 0 |
---|
4415 |       if abs(af[-1]-best_state.cost) > feps*10: |
---|
4416 | Â Â Â Â Â Â Â Â retval =Â 5 |
---|
4417 |         print (" Warning: Cooled to %.4f > selected Tmin %.4f in %d steps"%(squeeze(last_state.cost),Tf,iters-1)) |
---|
4418 | Â Â Â Â Â Â break |
---|
4419 |     if (Tf is not None) and (schedule.T < Tf): |
---|
4420 | #Â Â Â Â Â Â print ' Minimum T reached in %d steps'%(iters-1) |
---|
4421 | Â Â Â Â Â Â retval =Â 1 |
---|
4422 | Â Â Â Â Â Â break |
---|
4423 |     if (maxeval is not None) and (schedule.feval > maxeval): |
---|
4424 | Â Â Â Â Â Â retval =Â 2 |
---|
4425 | Â Â Â Â Â Â break |
---|
4426 |     if (iters > maxiter): |
---|
4427 |       print (" Warning: Maximum number of iterations exceeded.") |
---|
4428 | Â Â Â Â Â Â retval =Â 3 |
---|
4429 | Â Â Â Â Â Â break |
---|
4430 |     if (maxaccept is not None) and (schedule.accepted > maxaccept): |
---|
4431 | Â Â Â Â Â Â retval =Â 4 |
---|
4432 | Â Â Â Â Â Â break |
---|
4433 | |
---|
4434 |   return best_state.x, best_state.cost, schedule.T, \ |
---|
4435 |       schedule.feval, iters, schedule.accepted, retval |
---|
4436 | |
---|
4437 | def worker(iCyc,data,RBdata,reflType,reflData,covData,out_q,out_t,out_n,nprocess=-1): |
---|
4438 | Â Â outlist =Â [] |
---|
4439 | Â Â timelist =Â [] |
---|
4440 | Â Â nsflist =Â [] |
---|
4441 | Â Â random.seed(int(time.time())%100000+nprocess)Â Â #make sure each process has a different random start |
---|
4442 |   for n in range(iCyc): |
---|
4443 | Â Â Â Â result =Â mcsaSearch(data,RBdata,reflType,reflData,covData,None,False)Â Â Â Â Â #mcsa result,time,rcov |
---|
4444 | Â Â Â Â outlist.append(result[0]) |
---|
4445 | Â Â Â Â timelist.append(result[1]) |
---|
4446 | Â Â Â Â nsflist.append(result[2]) |
---|
4447 |     print (' MC/SA final fit: %.3f%% structure factor time: %.3f'%(100*result[0][2],result[1])) |
---|
4448 | Â Â out_q.put(outlist) |
---|
4449 | Â Â out_t.put(timelist) |
---|
4450 | Â Â out_n.put(nsflist) |
---|
4451 | |
---|
4452 | def MPmcsaSearch(nCyc,data,RBdata,reflType,reflData,covData,nprocs): |
---|
4453 |   import multiprocessing as mp |
---|
4454 | Â Â |
---|
4455 | Â Â out_q =Â mp.Queue() |
---|
4456 | Â Â out_t =Â mp.Queue() |
---|
4457 | Â Â out_n =Â mp.Queue() |
---|
4458 | Â Â procs =Â [] |
---|
4459 | Â Â totsftime =Â 0. |
---|
4460 | Â Â totnsf =Â 0 |
---|
4461 | Â Â iCyc =Â np.zeros(nprocs) |
---|
4462 |   for i in range(nCyc): |
---|
4463 | Â Â Â Â iCyc[i%nprocs]Â +=Â 1 |
---|
4464 |   for i in range(nprocs): |
---|
4465 | Â Â Â Â p =Â mp.Process(target=worker,args=(int(iCyc[i]),data,RBdata,reflType,reflData,covData,out_q,out_t,out_n,i)) |
---|
4466 | Â Â Â Â procs.append(p) |
---|
4467 | Â Â Â Â p.start() |
---|
4468 | Â Â resultlist =Â [] |
---|
4469 |   for i in range(nprocs): |
---|
4470 | Â Â Â Â resultlist +=Â out_q.get() |
---|
4471 | Â Â Â Â totsftime +=Â np.sum(out_t.get()) |
---|
4472 | Â Â Â Â totnsf +=Â np.sum(out_n.get()) |
---|
4473 |   for p in procs: |
---|
4474 | Â Â Â Â p.join() |
---|
4475 |   return resultlist,totsftime,totnsf |
---|
4476 | |
---|
4477 | def mcsaSearch(data,RBdata,reflType,reflData,covData,pgbar,start=True): |
---|
4478 | Â Â '''default doc string |
---|
4479 | Â Â |
---|
4480 | Â Â :param type name: description |
---|
4481 | Â Â |
---|
4482 | Â Â :returns: type name: description |
---|
4483 | Â Â ''' |
---|
4484 | Â Â |
---|
4485 |   class RandomDisplacementBounds(object): |
---|
4486 | Â Â Â Â """random displacement with bounds""" |
---|
4487 |     def __init__(self, xmin, xmax, stepsize=0.5): |
---|
4488 | Â Â Â Â Â Â self.xmin =Â xmin |
---|
4489 | Â Â Â Â Â Â self.xmax =Â xmax |
---|
4490 | Â Â Â Â Â Â self.stepsize =Â stepsize |
---|
4491 | Â Â |
---|
4492 |     def __call__(self, x): |
---|
4493 | Â Â Â Â Â Â """take a random step but ensure the new position is within the bounds""" |
---|
4494 |       while True: |
---|
4495 | Â Â Â Â Â Â Â Â # this could be done in a much more clever way, but it will work for example purposes |
---|
4496 | Â Â Â Â Â Â Â Â steps =Â self.xmax-self.xmin |
---|
4497 |         xnew = x + np.random.uniform(-self.stepsize*steps, self.stepsize*steps, np.shape(x)) |
---|
4498 |         if np.all(xnew < self.xmax) and np.all(xnew > self.xmin): |
---|
4499 | Â Â Â Â Â Â Â Â Â Â break |
---|
4500 |       return xnew |
---|
4501 | Â Â |
---|
4502 |   global tsum,nsum |
---|
4503 | Â Â tsum =Â 0. |
---|
4504 | Â Â nsum =Â 0 |
---|
4505 | Â Â |
---|
4506 |   def getMDparms(item,pfx,parmDict,varyList): |
---|
4507 | Â Â Â Â parmDict[pfx+'MDaxis']Â =Â item['axis'] |
---|
4508 | Â Â Â Â parmDict[pfx+'MDval']Â =Â item['Coef'][0] |
---|
4509 |     if item['Coef'][1]: |
---|
4510 | Â Â Â Â Â Â varyList +=Â [pfx+'MDval',] |
---|
4511 | Â Â Â Â Â Â limits =Â item['Coef'][2] |
---|
4512 | Â Â Â Â Â Â lower.append(limits[0]) |
---|
4513 | Â Â Â Â Â Â upper.append(limits[1]) |
---|
4514 | Â Â Â Â Â Â Â Â Â Â Â Â |
---|
4515 |   def getAtomparms(item,pfx,aTypes,SGData,parmDict,varyList): |
---|
4516 | Â Â Â Â parmDict[pfx+'Atype']Â =Â item['atType'] |
---|
4517 | Â Â Â Â aTypes |=Â set([item['atType'],])Â |
---|
4518 | Â Â Â Â pstr =Â ['Ax','Ay','Az'] |
---|
4519 | Â Â Â Â XYZ =Â [0,0,0] |
---|
4520 |     for i in range(3): |
---|
4521 | Â Â Â Â Â Â name =Â pfx+pstr[i] |
---|
4522 | Â Â Â Â Â Â parmDict[name]Â =Â item['Pos'][0][i] |
---|
4523 | Â Â Â Â Â Â XYZ[i]Â =Â parmDict[name] |
---|
4524 |       if item['Pos'][1][i]: |
---|
4525 | Â Â Â Â Â Â Â Â varyList +=Â [name,] |
---|
4526 | Â Â Â Â Â Â Â Â limits =Â item['Pos'][2][i] |
---|
4527 | Â Â Â Â Â Â Â Â lower.append(limits[0]) |
---|
4528 | Â Â Â Â Â Â Â Â upper.append(limits[1]) |
---|
4529 | Â Â Â Â parmDict[pfx+'Amul']Â =Â len(G2spc.GenAtom(XYZ,SGData)) |
---|
4530 | Â Â Â Â Â Â |
---|
4531 |   def getRBparms(item,mfx,aTypes,RBdata,SGData,atNo,parmDict,varyList): |
---|
4532 | Â Â Â Â parmDict[mfx+'MolCent']Â =Â item['MolCent'] |
---|
4533 | Â Â Â Â parmDict[mfx+'RBId']Â =Â item['RBId'] |
---|
4534 | Â Â Â Â pstr =Â ['Px','Py','Pz'] |
---|
4535 | Â Â Â Â ostr =Â ['Qa','Qi','Qj','Qk']Â Â #angle,vector not quaternion |
---|
4536 |     for i in range(3): |
---|
4537 | Â Â Â Â Â Â name =Â mfx+pstr[i] |
---|
4538 | Â Â Â Â Â Â parmDict[name]Â =Â item['Pos'][0][i] |
---|
4539 |       if item['Pos'][1][i]: |
---|
4540 | Â Â Â Â Â Â Â Â varyList +=Â [name,] |
---|
4541 | Â Â Â Â Â Â Â Â limits =Â item['Pos'][2][i] |
---|
4542 | Â Â Â Â Â Â Â Â lower.append(limits[0]) |
---|
4543 | Â Â Â Â Â Â Â Â upper.append(limits[1]) |
---|
4544 | Â Â Â Â AV =Â item['Ori'][0] |
---|
4545 | Â Â Â Â A =Â AV[0] |
---|
4546 | Â Â Â Â V =Â AV[1:] |
---|
4547 |     for i in range(4): |
---|
4548 | Â Â Â Â Â Â name =Â mfx+ostr[i] |
---|
4549 |       if i: |
---|
4550 | Â Â Â Â Â Â Â Â parmDict[name]Â =Â V[i-1] |
---|
4551 | Â Â Â Â Â Â else: |
---|
4552 | Â Â Â Â Â Â Â Â parmDict[name]Â =Â A |
---|
4553 |       if item['Ovar'] == 'AV': |
---|
4554 | Â Â Â Â Â Â Â Â varyList +=Â [name,] |
---|
4555 | Â Â Â Â Â Â Â Â limits =Â item['Ori'][2][i] |
---|
4556 | Â Â Â Â Â Â Â Â lower.append(limits[0]) |
---|
4557 | Â Â Â Â Â Â Â Â upper.append(limits[1]) |
---|
4558 |       elif item['Ovar'] == 'A' and not i: |
---|
4559 | Â Â Â Â Â Â Â Â varyList +=Â [name,] |
---|
4560 | Â Â Â Â Â Â Â Â limits =Â item['Ori'][2][i] |
---|
4561 | Â Â Â Â Â Â Â Â lower.append(limits[0]) |
---|
4562 | Â Â Â Â Â Â Â Â upper.append(limits[1]) |
---|
4563 |     if 'Tor' in item:   #'Tor' not there for 'Vector' RBs |
---|
4564 |       for i in range(len(item['Tor'][0])): |
---|
4565 | Â Â Â Â Â Â Â Â name =Â mfx+'Tor'+str(i) |
---|
4566 | Â Â Â Â Â Â Â Â parmDict[name]Â =Â item['Tor'][0][i] |
---|
4567 |         if item['Tor'][1][i]: |
---|
4568 | Â Â Â Â Â Â Â Â Â Â varyList +=Â [name,] |
---|
4569 | Â Â Â Â Â Â Â Â Â |
---|