""" Functions for extracting viscoelasticity from microrheology measurements """
from derivative import dxdt
import numpy as np
import numpy.typing as npt
[docs]
def msd_to_g_star(times: npt.NDArray[float],
msd: npt.NDArray[float],
radius: float,
viscosity: float = 0,
method: str = "evans",
**kwargs) -> (npt.NDArray[float], npt.NDArray[complex]):
"""
Extracts Complex Shear Modulus G* (in Pa) from the MSD of a probe.
Mason's method: Approximate G* using a truncated power-law expansion. Ref: :func:`_msd_to_g_star_mason`
1. Mason, T. G. Estimating the viscoelastic moduli of complex fluids using the generalized Stokes–Einstein equation. Rheol. Acta 39, 371–378 (2000).
Evans' method: Extract G* using a DTFT on the creep compliance J(t). Ref: :func:`_msd_to_g_star_mason`
2. Evans, R. M. L., Tassieri, M., Auhl, D. & Waigh, T. A. Direct conversion of rheological compliance measurements into storage and loss moduli. Phys. Rev. E 80, 012501 (2009).
:param times: npt.NDArray[float], an array of timepoints (unit: s)
:param msd: npt.NDArray[float], an array of MSD values (unit: um^2)
:param radius: float, radius of the bead (unit: um)
:param viscosity: (for Evans' method only) float, viscosity of medium (unit: pN.s/um^2)
:param method: str, method to use for extracting G*. Must be one of ["evans", "mason"]
:returns: npt.NDArray[float], npt.NDArray[complex], an array of omegas (unit: Hz), an array of G* (G' + iG'') (unit: Pa)
"""
match method:
case "evans":
omegas, g_star = _msd_to_g_star_evans(times, msd, radius, viscosity, **kwargs)
case "mason":
omegas, g_star = _msd_to_g_star_mason(times, msd, radius, **kwargs)
case _:
raise ValueError("Method Unknown: Failed to convert MSD to G*")
return omegas, g_star
[docs]
def _msd_to_g_star_evans(times: npt.NDArray[float],
msd: npt.NDArray[float],
radius: float,
viscosity: float = 0,
**kwargs) -> (npt.NDArray[float], npt.NDArray[complex]):
"""
Extract G* from MSD using Evans' method
"""
omegas = []
g_star = []
raise NotImplementedError("Evans Method: To be Implemented")
return omegas, g_star
[docs]
def _msd_to_g_star_mason(times: npt.NDArray[float],
msd: npt.NDArray[float],
radius: float,
**kwargs) -> (npt.NDArray[float], npt.NDArray[complex]):
"""
Extract G* from MSD using Mason's method
1. Mason, T. G. Estimating the viscoelastic moduli of complex fluids using the generalized Stokes–Einstein equation. Rheol. Acta 39, 371–378 (2000).
"""
# remove entries where time <= 0
# Mason's method does 1/t and negative
# frequencies are un-physical
msd = msd[np.where(times > 0)]
times = times[times > 0]
omegas = 1/times
log_times = np.log(times)
log_msd = np.log(msd)
def gamma(alpha): # from [1]
return 0.457*np.power((1+alpha),2) - 1.36*(1+alpha) + 1.9
# TO-DO: Possibly allow tuning of dxdt parameters? Currently chosen to match previous
# hand-rolled derivative calculation
alphas = dxdt(log_msd, log_times, kind="savitzky_golay", left=0.5, right=0.5, order=2)
g_elastic = 0.0042*np.cos(np.pi*alphas/2) / (np.pi * radius * msd * gamma(alphas))
g_viscous = 0.0042*np.sin(np.pi*alphas/2) / (np.pi * radius * msd * gamma(alphas))
g_star = g_elastic + 1j*g_viscous
return omegas, g_star