Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
601 views
unlisted
ubuntu2404
1
#!/usr/bin/env python3
2
# -*- coding: utf-8 -*-
3
"""
4
Created on Fri Nov 7 19:15:57 2025
5
6
@author: davide
7
"""
8
9
10
import numpy as np
11
from scipy import interpolate
12
from scipy.integrate import odeint
13
from scipy.optimize import curve_fit
14
15
16
def deltaC_einarsson15(r,Rep,dir='',IC=None,time=None,gammadot=None):
17
"""returns rotational dinamics from initial condition IC along time at Reynolds Rep for the spheroid with aspect ratio"""
18
###load the coefficients
19
b1,b2,b3,b4 = load_betas(dir,req=r,Rep=Rep)
20
###get the prediction
21
nnn,ttt = Einarsson_interface(IC=IC,time=time,gammadot=gammadot,r=r,b1=b1,b2=b2,b3=b3,b4=b4)
22
###split and measure C
23
return split_orbits_and_get_C(nnn[:,0],nnn[:,1],nnn[:,2],r)
24
25
def load_betas(folder,req,Rep):
26
"""Loads the graphically extrapolated coefficients from Einarsson et al., PoF 2015, Fig. 2"""
27
B1data = np.loadtxt(folder+'B1.txt') #Load the data for the beta_1 coefficient as a two-Dim array with format: r,b_1(r)/Rep
28
B2data = np.loadtxt(folder+'B2.txt') #Load the data for the beta_2 coefficient: r,b_2(r)
29
B3data = np.loadtxt(folder+'B3.txt') #Load the data for the beta_3 coefficient: r,b_3(r)
30
B4data = np.loadtxt(folder+'B4.txt') #Load the data for the beta_4 coefficient: r,b_4(r)
31
###Define the interpolating function and interpolate the four coefficients at the current aspect ratio
32
f1 = interpolate.interp1d(B1data[:,0], B1data[:,1]) #linear interpolation function for b_1
33
f2 = interpolate.interp1d(B2data[:,0], B2data[:,1]) #linear interpolation function for b_2
34
f3 = interpolate.interp1d(B3data[:,0], B3data[:,1]) #linear interpolation function for b_3
35
f4 = interpolate.interp1d(B4data[:,0], B4data[:,1]) #linear interpolation function for b_4
36
###calculate the coefficients at particle Reynolds number Rep
37
betas = np.array([f1(req),f2(req),f3(req),f4(req)])* Rep
38
return betas
39
40
def rotation_Einarsson(p,t,beta,gammadot,b1,b2,b3,b4):
41
"""Calculates the rotation rate according to Einarsson et al., PoF, 2015: eq. 39"""
42
Omega = np.array([[0, 0.5, 0],[-0.5, 0, 0],[ 0, 0, 0]]) * gammadot #Rate of rotation tensor
43
E = np.array([[0, 0.5, 0],[0.5, 0, 0],[ 0, 0, 0]]) * gammadot #Rate of strain tensor
44
pEp=np.dot(p,np.dot(E,p)) #Usefull term
45
pOEp=np.dot(p,np.dot(Omega,np.dot(E,p))) #Usefull term
46
pEEp=np.dot(p,np.dot(E,np.dot(E,p)))
47
b1/=gammadot;b2/=gammadot;b3/=gammadot;b4/=gammadot #Usefull term
48
return np.dot(Omega+beta*E,p)-beta*pEp*p+b1*pEp*(np.dot(E,p)-p*pEp)+b2*pEp*np.dot(Omega,p)+b3*(np.dot(Omega,np.dot(E,p))-pOEp*p)+b4*(np.dot(E,np.dot(E,p))-pEEp*p)
49
50
def Einarsson_interface(IC,time,gammadot,r,b1,b2,b3,b4):
51
"""Manages the integration of the Einarsson rotation rate from a given initial_value"""
52
beta = (r**2-1)/(r**2+1) #Calculate the geometrical parameter beta
53
simtime = time #time-range of integration
54
pinit=np.array([IC[0],IC[1],IC[2]]) ###initial conditions q0
55
ptheory = odeint(rotation_Einarsson,pinit,simtime,args=(beta,gammadot,b1,b2,b3,b4)) # solve the problem using odeint and calling the previously defined function rotation_Einarsson
56
return ptheory,simtime #return the direction vector and the integration time
57
58
59
60
def jeffery_model(phi, C, r):
61
return C * r / np.sqrt(np.cos(phi)**2 + r**2 * np.sin(phi)**2)
62
63
def fit_C(theta,phi,r):
64
def model(phi, C):
65
return jeffery_model(phi, C, r)
66
# Fit
67
try:
68
C_fit, cov = curve_fit(model, phi, np.tan(theta), bounds=[0, np.inf], p0=[1.0])
69
C_std = np.sqrt(np.diag(cov))[0] if cov.size else np.nan
70
return C_fit[0], C_std
71
except Exception:
72
return np.nan, np.nan
73
74
def split_orbits_and_get_C(n1,n2,n3,r):
75
"""Method to split orbits in semi-periods"""
76
# Identify where sign changes
77
if r > 1.0:
78
sign_change = np.diff(np.sign(n1)) != 0
79
else:
80
sign_change = np.diff(np.sign(n2)) != 0
81
orbit_labels = np.zeros_like(n1, dtype=int)
82
orbit_labels[1:] = np.cumsum(sign_change)
83
num_orbits = orbit_labels.max() + 1
84
C = []
85
for i in range(num_orbits):
86
orbit_inds = np.where(orbit_labels[:]==i)
87
# phi = np.arctan(n1[orbit_inds]/n2[orbit_inds])
88
phi = np.arctan2(n1[orbit_inds],n2[orbit_inds])
89
theta = np.arccos(n3[orbit_inds])
90
# tan_theta = np.tan(theta)
91
C.append(fit_C(theta,phi,r))
92
return np.array(C).T
93
94
95