diff --git a/deerlab/dipolarkernel.py b/deerlab/dipolarkernel.py index 33d815f1..8ee3d387 100644 --- a/deerlab/dipolarkernel.py +++ b/deerlab/dipolarkernel.py @@ -367,7 +367,7 @@ def dipolarkernel(t, r, *, pathways=None, mod=None, bg=None, method='fresnel', e if tinterp is not None: # Construct interpolator, this way elementarykernel_twospin is executed only once independently of how many pathways there are - Kinterpolator = [interp1d(tinterp,elementarykernel_twospin(tinterp,r_q,method,excbandwidth,gridsize,g,orisel,complex),axis=0,kind='cubic') for r_q in r] + Kinterpolator = _elementarykernel_twospin_interp(tinterp,r,method,excbandwidth,gridsize,g,orisel,complex) withinInterpolation = lambda tdip: np.all((np.max(tinterp) >= np.max(tdip)) & (np.min(tinterp) <= np.min(tdip))) # Define kernel matrix auxiliary functions @@ -435,8 +435,14 @@ def K0_3spin(tdip): return K #============================================================================== - - +@cached(max_size=100) +def _elementarykernel_twospin_interp(tinterp,r,method,excbandwidth,gridsize,g,orisel,complex): + """ + Construct interpolator, this way elementarykernel_twospin is executed only once independently of how many pathways there are + Cached for performance reasons, interpolation is slow. + """ + Kinterpolator = [interp1d(tinterp,elementarykernel_twospin(tinterp,r_q,method,excbandwidth,gridsize,g,orisel,complex),axis=0,kind='cubic') for r_q in r] + return Kinterpolator #============================================================================== # TWO-SPIN ELEMENTARY DIPOLAR KERNEL @@ -468,14 +474,15 @@ def elementarykernel_twospin(tdip,r,method,ωex,gridsize,g,Pθ,complex): ωr = (μ0/2)*μB**2*g[0]*g[1]/h*1e21/(r**3) # rad μs^-1 # Orientation selection - orientationselection = Pθ is not None - if orientationselection: - # Ensure zero-derivatives at [0,π/2] - θ = np.linspace(0,π/2,50) # rad - Pθ_ = make_interp_spline(θ, Pθ(θ),bc_type="clamped") - # Ensure normalization of probability density function (∫P(cosθ)dcosθ=1) - Pθnorm,_ = quad(lambda cosθ: Pθ_(np.arccos(cosθ)),0,1,limit=1000) - Pθ = lambda θ: Pθ_(θ)/Pθnorm + if method != 'fresnel': + orientationselection = Pθ is not None + if orientationselection: + # Ensure zero-derivatives at [0,π/2] + θ = np.linspace(0,π/2,50) # rad + Pθ_ = make_interp_spline(θ, Pθ(θ),bc_type="clamped") + # Ensure normalization of probability density function (∫P(cosθ)dcosθ=1) + Pθnorm,_ = quad(lambda cosθ: Pθ_(np.arccos(cosθ)),0,1,limit=1000) + Pθ = lambda θ: Pθ_(θ)/Pθnorm def elementarykernel_fresnel(tdip): #------------------------------------------------------------------------ diff --git a/docsrc/source/changelog.rst b/docsrc/source/changelog.rst index 252ef0fc..3aa92232 100644 --- a/docsrc/source/changelog.rst +++ b/docsrc/source/changelog.rst @@ -27,6 +27,7 @@ Release Notes Release ``v1.1.3`` - Ongoing ------------------------------------------ - |fix| : Removes unnecessary files from the docs +- |efficiency| : Improves the performance of the ``dipolarkernel`` function by 10-30% (:pr:`473`), by caching the interpolation of he effective dipolar evolution time vector. Release ``v1.1.2`` - November 2023 ------------------------------------------