add C function to integrate anisotropic diffusion

This commit is contained in:
Dominik Demuth
2025-05-02 13:20:35 +02:00
parent 11fe47bef1
commit 81357a3e4f
4 changed files with 56 additions and 2 deletions

View File

@ -0,0 +1,16 @@
/* integrands used in quadrature integration with scipy's LowLevelCallables */
#include <math.h>
double anistropicDiffusion(double x, void *user_data) {
double *c = (double *)user_data;
double q = c[0];
double t = c[1];
double d_perp = c[2];
double d_par = c[3];
double cos_theta = cos(x);
double sin_theta = sin(x);
return exp(-q * q * t * (d_par * cos_theta * cos_theta + d_perp * sin_theta * sin_theta)) * sin_theta;
}

BIN
src/nmreval/clib/diffusion.so Executable file

Binary file not shown.

View File

@ -5,6 +5,17 @@ from ctypes import CDLL, c_double, c_void_p
from ..lib.logger import logger from ..lib.logger import logger
diffusion_lib = None
try:
diffusion_lib = CDLL(str(Path(__file__).parents[1] / 'clib' / 'diffusion.so'))
diffusion_lib.anistropicDiffusion.restype = c_double
diffusion_lib.anistropicDiffusion.argtypes = (c_double, c_void_p)
HAS_C_FUNCS = True
except OSError:
HAS_C_FUNCS = False
lib = None lib = None
try: try:
lib = CDLL(str(Path(__file__).parents[1] / 'clib' / 'integrate.so')) lib = CDLL(str(Path(__file__).parents[1] / 'clib' / 'integrate.so'))
@ -39,7 +50,6 @@ try:
lib.energyDistSuscImag.restype = c_double lib.energyDistSuscImag.restype = c_double
lib.energyDistSuscImag.argtypes = (c_double, c_void_p) lib.energyDistSuscImag.argtypes = (c_double, c_void_p)
HAS_C_FUNCS = True HAS_C_FUNCS = True
logger.info('Use C functions') logger.info('Use C functions')
except OSError: except OSError:

View File

@ -1,7 +1,11 @@
from ctypes import c_double, cast, c_void_p, pointer
import numpy as np import numpy as np
from scipy import special as special from scipy import special as special, LowLevelCallable
from scipy.integrate import quad
from ..utils import gamma from ..utils import gamma
from nmreval.distributions.helper import HAS_C_FUNCS, diffusion_lib
class Diffusion: class Diffusion:
@ -111,6 +115,30 @@ class AnisotropicDiffusion(object):
return m0 * diffs * relax return m0 * diffs * relax
@staticmethod
def _integrate_c(x, m0, d_perp, d_par, trel, brel, g, t2, nucleus=2.67522128e8, t_axis='tm') -> np.ndarray:
diffusion_decay = np.zeros_like(x)
if t_axis == 'tm':
tm = x
tp = t2
relax = np.exp(-(tm/trel)**brel)
else:
tm = t2
tp = x
relax = np.exp(-(tp/trel)**brel)*np.exp(-(tp/trel)**brel)
q = g * nucleus * tp
t = 2 * tp / 3 + tm
for (i, t_i) in enumerate(t):
c = (c_double * 4)(q, t_i, d_perp, d_par)
user_data = cast(pointer(c), c_void_p)
diffusion_decay[i] = quad(LowLevelCallable(diffusion_lib.anistropicDiffusion, user_data), 0, np.pi, epsabs=1e-13)[0]
return m0 * diffusion_decay * relax
class Peschier: class Peschier:
name = 'Diffusion + Cross-Relaxation' name = 'Diffusion + Cross-Relaxation'