Source code for atsim.potentials._util
[docs]def deriv(r, func, h = 0.1e-5):
"""Evaluates the derivative of a unary callable, `func` at a value of `r`.
If the object `func` has a unary method `deriv(r)`, this will be used to evauluate
the derivative (allowing analytical derivatives to be used).
If `func` does not have a specific `deriv(r)` method then its numerical-derivative of
will be taken by calling num_deriv()
:param r: Value at which derivative of `func` should be evaluated.
:param func: Function whose derivative is to be evaluated.
:param h: Step size used when performing numerical differentiation.
:return: Derivative of func at `r`."""
if hasattr(func, "deriv"):
return func.deriv(r)
return num_deriv(r, func, h)
[docs]def num_deriv(r, func, h = 0.1e-5):
"""Returns numerical derivative of the callable `func`
:param r: Value at which derivative of `func` should be evaluated.
:param func: Function whose gradient is to be evaluated.
:param h: Step size used when performing numerical differentiation.
:return: Numerical derivative of func at `r`."""
r1 = r-(h/2.0)
r2 = r+(h/2.0)
dr = r2 -r1
dU = func(r2) - func(r1)
dUdr = dU/dr
return dUdr
class _GradientWrapper(object):
"""Callable class instantiated by gradient()
Dynamically adds a deriv() method if wrapped function
has a deriv2() method"""
def __init__(self, func, h):
self._wrapped = func
self._h = h
if hasattr(self._wrapped, "deriv2"):
# Add a deriv() method to this object
def deriv(self, r):
return self._wrapped.deriv2(r)
#... bind this to the object
self.deriv = deriv.__get__(self)
def __call__(self, r):
return deriv(r, self._wrapped, self._h)
[docs]def gradient(func, h = 0.1e-5):
"""Function wrapper that returns derivative of func.
If the callable, `func` provides a `.deriv(r)` method this will be used
to evaluate the derivative of the function, if not the returned function
will use num_deriv() in gradient evaluation.
If the callable additionally provides a `.deriv2(r)` method, representing
its second derivative, the function returned by this routine will have a `deriv()`
method which will delegate to func.deriv2() when called.
By providing .deriv() and .deriv2() on the `func` callable analytical descriptions
of a potential's first and second derivatives may be specified.
:param func: Function to be wrapped
:param h: Step size used when performing numerical differentiation
:return: Function that returns derivative of func"""
wrapped = _GradientWrapper(func, h)
return wrapped
import functools
class _rpartial(functools.partial):
def __call__(self, *args, **kwargs):
kw = self.keywords.copy()
kw.update(kwargs)
return self.func(*(args + self.args), **kwargs)