You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
A NIST user recently noticed that they were getting incorrect answers when using the lognormal distribution with a very large dispersity. After a lot of work to track down they realized it is because all polydispersity distributions use a linear point spacing for the integration when in fact something like lognormal (or the Schulz-Zim) distribution should be using a log spacing of points, particularly with large dispersity values.
It may be that for low values of the dispersity the spacing should still be linear. This needs a bit of investigation. In the meantime the user fixed their problem by altering the sasmodels code. I include the code snippets here as they look good to me and could make for a quick patch?
Below are the distribution points for a lognormal distribution (using the default sphere radius to be polydisperse) for a pd of 2, 1 and 0.5 respectively
PD 2.0
PD 1.0
PD 0.5
CODE
First add a new _logspace method to the Dispersion class in weights.py immediately following the existing _linspace method (and mostly copied form it)
def_logspace(self, center, sigma, lb, ub):
"""helper function to provide log(e) spaced weight points within range"""npts, nsigmas=self.npts, self.nsigmas# sigma in the lognormal function is in ln(R) space, thus needs convertingsig=np.fabs(sigma/center)
x=np.logspace(np.log(center)-nsigmas*sig, np.log(center)+nsigmas*sig, npts,base=np.e)
x=x[(x>=lb) & (x<=ub)]
returnx
Next, replace the call to _linspace with a call to _logspace in the LogNormalDispersion class. The same should probably be done for the SchulzDispersion class. Note that he also added 4 new lines at the end just before the return to transform x and px which should probably be folded directly into the way x and px are calculated?
classLogNormalDispersion(Dispersion):
r"""log Gaussian dispersion, with 1-$\sigma$ width... math::w = \frac{\exp\left(-\tfrac12 (\ln x - c)^2/\sigma^2\right)}{x\sigma}"""type="lognormal"default=dict(npts=80, width=0, nsigmas=8)
def_weights(self, center, sigma, lb, ub):
x=self._logspace(center, sigma, max(lb, 1e-8), max(ub, 1e-8))
# sigma in the lognormal function is in ln(R) space, thus needs convertingsig=np.fabs(sigma/center)
px=np.exp(-0.5*((np.log(x)-np.log(center))/sig)**2)/(x*sig)
x1= (x[1:] +x[:-1])*0.5px1=0.5*(px[1:]+px[:-1])*(x[1:]-x[:-1])
norm=sum(px1)
px1=px1/normreturnx1, px1
The text was updated successfully, but these errors were encountered:
Which models were they looking at and how did they determine the correct values?
For the polydispersity integral ∫p(r) F²(q;r) dr with lognormal p and sphere F we can plot the integrand p(r) F²(q;r) to see how it behaves. The result suggests we do want linear spacing, and further that we want to restrict PD to be less than about 0.5.
plot ( exp( -((ln(r)-ln(100))/σ)^2/2 )/(σr*sqrt(2π)) (r^2/10 j1(r/10))^2 ) from 1 to 600 for σ = ΔR/R = 0.5, 1.0 and 2.0
With R=100, ΔR/R = 0.5, nsigma = 8, the integral ranges from 0 to 500, which covers most of the function. Unfortunately the integrand is positive everywhere so we will always underestimate the true result.
A NIST user recently noticed that they were getting incorrect answers when using the lognormal distribution with a very large dispersity. After a lot of work to track down they realized it is because all polydispersity distributions use a linear point spacing for the integration when in fact something like lognormal (or the Schulz-Zim) distribution should be using a log spacing of points, particularly with large dispersity values.
It may be that for low values of the dispersity the spacing should still be linear. This needs a bit of investigation. In the meantime the user fixed their problem by altering the sasmodels code. I include the code snippets here as they look good to me and could make for a quick patch?
Below are the distribution points for a lognormal distribution (using the default sphere radius to be polydisperse) for a pd of 2, 1 and 0.5 respectively
PD 2.0

PD 1.0

PD 0.5

CODE
First add a new
_logspace
method to the Dispersion class inweights.py
immediately following the existing_linspace
method (and mostly copied form it)Next, replace the call to
_linspace
with a call to_logspace
in theLogNormalDispersion
class. The same should probably be done for theSchulzDispersion
class. Note that he also added 4 new lines at the end just before the return to transform x and px which should probably be folded directly into the way x and px are calculated?The text was updated successfully, but these errors were encountered: