4 Commits

2 changed files with 93 additions and 17 deletions

View File

@@ -18,7 +18,7 @@ def log_indices(first: int, last: int, num: int = 100) -> np.ndarray:
return np.unique(np.int_(ls) - 1 + first)
@autosave_data(2)
@autosave_data(nargs=2, kwargs_keys=('selector', 'segments', 'skip', 'window', 'average', 'points',), version=1.0)
def shifted_correlation(
function: Callable,
frames: Coordinates,
@@ -199,7 +199,7 @@ def msd(
raise ValueError('Parameter axis has to be ether "all", "x", "y", or "z"!')
def isf(
def isf_raw(
start_frame: CoordinateFrame,
end_frame: CoordinateFrame,
q: float = 22.7,
@@ -216,29 +216,59 @@ def isf(
displacements = displacements_without_drift(start_frame, end_frame, trajectory)
if axis == "all":
distance = (displacements**2).sum(axis=1) ** 0.5
return np.sinc(distance * q / np.pi).mean()
return np.sinc(distance * q / np.pi)
elif axis == "xy" or axis == "yx":
distance = (displacements[:, [0, 1]]**2).sum(axis=1) ** 0.5
return np.real(jn(0, distance * q)).mean()
return np.real(jn(0, distance * q))
elif axis == "xz" or axis == "zx":
distance = (displacements[:, [0, 2]]**2).sum(axis=1) ** 0.5
return np.real(jn(0, distance * q)).mean()
return np.real(jn(0, distance * q))
elif axis == "yz" or axis == "zy":
distance = (displacements[:, [1, 2]]**2).sum(axis=1) ** 0.5
return np.real(jn(0, distance * q)).mean()
return np.real(jn(0, distance * q))
elif axis == "x":
distance = np.abs(displacements[:, 0])
return np.mean(np.cos(np.abs(q * distance)))
return np.cos(np.abs(q * distance))
elif axis == "y":
distance = np.abs(displacements[:, 1])
return np.mean(np.cos(np.abs(q * distance)))
return np.cos(np.abs(q * distance))
elif axis == "z":
distance = np.abs(displacements[:, 2])
return np.mean(np.cos(np.abs(q * distance)))
return np.cos(np.abs(q * distance))
else:
raise ValueError('Parameter axis has to be ether "all", "x", "y", or "z"!')
def isf(
start_frame: CoordinateFrame,
end_frame: CoordinateFrame,
q: float = 22.7,
trajectory: Coordinates = None,
axis: str = "all",
) -> float:
"""
Incoherent intermediate scattering function averaged over all particles.
See isf_raw for details.
"""
return isf_raw(start_frame, end_frame, q=q, trajectory=trajectory, axis=axis).mean()
def isf_mean_var(
start_frame: CoordinateFrame,
end_frame: CoordinateFrame,
q: float = 22.7,
trajectory: Coordinates = None,
axis: str = "all",
) -> float:
"""
Incoherent intermediate scattering function averaged over all particles and the
variance.
See isf_raw for details.
"""
values = isf_raw(start_frame, end_frame, q=q, trajectory=trajectory, axis=axis)
return values.mean(), values.var()
def rotational_autocorrelation(
start_frame: CoordinateFrame, end_frame: CoordinateFrame, order: int = 2
) -> float:
@@ -430,6 +460,7 @@ def non_gaussian_parameter(
end_frame: CoordinateFrame,
trajectory: Coordinates = None,
axis: str = "all",
full_output = False,
) -> float:
r"""
Calculate the non-Gaussian parameter.
@@ -442,27 +473,41 @@ def non_gaussian_parameter(
else:
vectors = displacements_without_drift(start_frame, end_frame, trajectory)
if axis == "all":
r = (vectors**2).sum(axis=1)
r2 = (vectors**2).sum(axis=1)
dimensions = 3
elif axis == "xy" or axis == "yx":
r = (vectors[:, [0, 1]]**2).sum(axis=1)
r2 = (vectors[:, [0, 1]]**2).sum(axis=1)
dimensions = 2
elif axis == "xz" or axis == "zx":
r = (vectors[:, [0, 2]]**2).sum(axis=1)
r2 = (vectors[:, [0, 2]]**2).sum(axis=1)
dimensions = 2
elif axis == "yz" or axis == "zy":
r = (vectors[:, [1, 2]]**2).sum(axis=1)
r2 = (vectors[:, [1, 2]]**2).sum(axis=1)
dimensions = 2
elif axis == "x":
r = vectors[:, 0] ** 2
r2 = vectors[:, 0] ** 2
dimensions = 1
elif axis == "y":
r = vectors[:, 1] ** 2
r2 = vectors[:, 1] ** 2
dimensions = 1
elif axis == "z":
r = vectors[:, 2] ** 2
r2 = vectors[:, 2] ** 2
dimensions = 1
else:
raise ValueError('Parameter axis has to be ether "all", "x", "y", or "z"!')
return (np.mean(r**2) / ((1 + 2 / dimensions) * (np.mean(r) ** 2))) - 1
m2 = np.mean(r2)
m4 = np.mean(r2**2)
if m2 == 0.0:
if full_output:
return 0.0, 0.0, 0.0
else:
return 0.0
alpha_2 = (m4 / ((1 + 2 / dimensions) * m2**2)) - 1
if full_output:
return alpha_2, m2, m4
else:
return alpha_2

View File

@@ -357,6 +357,37 @@ def quick1etau(t: ArrayLike, C: ArrayLike, n: int = 7) -> float:
return tau_est
def quicknongaussfit(t, C, width=2):
"""
Estimates the time and height of the peak in the non-Gaussian function.
C is C(t) the correlation function
"""
def ffunc(t,y0,A_main,log_tau_main,sig_main):
main_peak = A_main*np.exp(-(t - log_tau_main)**2 / (2 * sig_main**2))
return y0 + main_peak
# first rough estimate, the closest time. This is returned if the interpolation fails!
tau_est = t[np.argmax(C)]
nG_max = np.amax(C)
try:
with np.errstate(invalid='ignore'):
corr = C[t > 0]
time = np.log10(t[t > 0])
tau = time[np.argmax(corr)]
mask = (time>tau-width/2) & (time<tau+width/2)
time = time[mask] ; corr = corr[mask]
nG_min = C[t > 0].min()
guess = [nG_min, nG_max-nG_min, tau, 0.6]
popt = curve_fit(ffunc, time, corr, p0=guess, maxfev=10000)[0]
tau_est = 10**popt[-2]
nG_max = popt[0] + popt[1]
except:
pass
if np.isnan(tau_est):
tau_est = np.inf
return tau_est, nG_max
def susceptibility(
time: NDArray, correlation: NDArray, **kwargs
) -> tuple[NDArray, NDArray]: