# -*- coding: utf-8 -*-
# models/kholodenko.py
from __future__ import absolute_import
import logging
import numpy
from scipy.special import j1 as bessel_j1
from scipy.integrate import quad
from utils.parameter import FitParameter
from bases.model import SASModel
from bases.algorithm import RandomUniform, RandomExponential
from utils.units import Length
LASTMSG = set()
[docs]def core(z, qValue, kuhnLength, x):
if z <= 0.0 or x <= 0.0:
return 1.0
ratio = 3.0 / kuhnLength
if qValue < ratio:
e = numpy.sqrt(1.0 - qValue*qValue*kuhnLength*kuhnLength/9.)
fz = numpy.sinh(e*z) / (e*numpy.sinh(z))
elif qValue > ratio:
f = numpy.sqrt(qValue*qValue*kuhnLength*kuhnLength/9. - 1.0)
fz = numpy.sin(f*z) / (f*numpy.sinh(z))
else: # qValue == ratio
fz = z / numpy.sinh(z)
res = fz * (2./x) * (1.0 - z/x)
return res
[docs]def coreIntegral(qValue, kuhnLength, x):
res = quad(core, 0, x,
args = (qValue, kuhnLength, x),
limit = 10000, full_output = 1, epsabs = 0.0, epsrel = 1e-10)
if len(res) > 3:
LASTMSG.add(res[-1])
return numpy.sqrt(res[0])
vectorizedCoreIntegral = numpy.vectorize(coreIntegral)
[docs]def calcPcs(u):
if u <= 0.0:
return 1.0
res = 2. * bessel_j1(u) / u
return res
vectorizedPcs = numpy.vectorize(calcPcs)
[docs]class Kholodenko(SASModel):
r"""Form factor of a worm-like structure after [Kholodenko93]_
.. [Kholodenko93] `A. L. Kholodenko. Analytical calculation of the
scattering function for polymers of arbitrary flexibility using the
dirac propagator. Macromolecules, 26:4179–4183, 1993.
<http://dx.doi.org/10.1021/ma00068a017>`_
"""
shortName = "Kholodenko Worm"
parameters = (
FitParameter("radius", Length(u'nm').toSi(1.), unit = Length(u'nm'),
displayName = "Radius",
generator = RandomExponential,
valueRange = (0., numpy.inf),
activeRange = Length(u'nm').toSi((1, 5))), # preset
FitParameter("lenKuhn", Length(u'nm').toSi(1.), unit = Length(u'nm'),
displayName = "kuhn length",
generator = RandomUniform,
valueRange = (0., numpy.inf),
activeRange = Length(u'nm').toSi((10, 50))), # preset
FitParameter("lenContour", Length(u'nm').toSi(2.), unit = Length(u'nm'),
displayName = "contour length",
generator = RandomUniform,
valueRange = (0., numpy.inf),
activeRange = Length(u'nm').toSi((100, 1000))), # preset
)
def __init__(self):
super(Kholodenko, self).__init__()
# some presets of parameters to fit
self.radius.setActive(True)
self.lenKuhn.setActive(True)
self.lenContour.setActive(True)
[docs] def volume(self):
volume = numpy.pi * self.lenContour() * self.radius()**2
return volume
Kholodenko.factory()
[docs]def test():
# volume is already included in the model, how to exclude it?
Kholodenko.testVolExp = 0.0
for fn in ("sasfit_kho-1-10-1000.dat",
):
yield Kholodenko.test, fn
# vim: set ts=4 sts=4 sw=4 tw=0: