"""
Created on Fri Nov 7 18:39:55 2025
@author: davide
Methods that calculates the orbit variation delta_C for an oblate particle given its aspect ratio
"""
import sympy as sym
import numpy as np
k = sym.symbols('\kappa')
xi = sym.symbols('xi', positive=True)
xib= sym.symbols("\overline{xi}", positive=True)
C = sym.symbols('C')
def invcoth(val):
return 0.5 * sym.log((val+1)/(val-1))
F1p_def = (4*xi**4-7*xi**2+3)*(xi**2*invcoth(xi)+invcoth(xi)-xi)/(160*xi*(1-2*xi**2)**2)
F2p_def = xib**4*(invcoth(xi)+xi*(xi*invcoth(xi)-1))/(40*xi*(1-2*xi**2)**2)
F3p_def = - xib**2*(xi**2*invcoth(xi)+invcoth(xi)-xi)/(160*xi*(1-2*xi**2)**2)
F4p_def = F3p_def
F5p_def = -F3p_def / 2
F6p_def = F5p_def
G1p_def = -(3*xi**4-5*xi**2+2)*((xi**2+1)*invcoth(xi)-xi) / (40*xi*(1-2*xi**2)**2)
G2p_def = (xi*(-xi**3+xi+(xi**4-1)*invcoth(xi))) / (40*(1-2*xi**2)**2)
G3p_def = G2p_def / xi**2
G4p_def = - G2p_def / xi**2
F1f_def = (xi**(2)*(-648*xi**(12)+1350*xi**(10)-5571*xi**(8)+11841*xi**(6)-9269*xi**(4)+2263*xi**(2)+6) \
-27*xi**(2)*(24*xi**(8)-14*xi**(6)-19*xi**(4)+16*xi**(2)-3)*xib**(8)*invcoth(xi)**(4)+9*xi \
*(288*xi**(12)-564*xi**(10)-20*xi**(8)+799*xi**(6)-743*xi**(4)+261*xi**(2)-29)*xib**(4) \
* invcoth(xi)**(3)+xi*(2592*xi**(14)-7020*xi**(12)+13932*xi**(10)-21123*xi**(8)+14255*xi**(6) \
-577*xi**(4)-2711*xi**(2)+652)*invcoth(xi)-3*(1296*xi**(16)-4320*xi**(14)+5346*xi**(12) \
-1477*xi**(10)-4260*xi**(8)+6116*xi**(6)-3492*xi**(4)+849*xi**(2)-58)*invcoth(xi)**(2)) \
*(480*xi**(2)*(-1+2*xi**(2))**(3)*(-3*xi**(2)+3*xib**(2)*xi*invcoth(xi)+2) \
*(-3*xi**(3)+5*xi+3*xib**(4)*invcoth(xi))*((3*xi**(2)-1)*invcoth(xi)-3*xi))**(-1)
F2f_def = -(xib**(2)*(-9*xi**(9)+30*xi**(7)-115*xi**(5)+90*xi**(3)-12*xi \
+9*xib**(8)*(xi**(2)+1)*xi**(2)*invcoth(xi)**(3)-3*xib**(4)*(9*xi**(6)-10*xi**(4)-17*xi**(2)+14)*xi*invcoth(xi)**(2) \
+(27*xi**(10)-87*xi**(8)+133*xi**(6)-33*xi**(4)-52*xi**(2)+12)*invcoth(xi))) \
*(40*(xi-2*xi**(3))**(2)*(-3*xi**(2)+3*xib**(2)*xi*invcoth(xi)+2) \
*(-3*xi**(3)+5*xi+3*xib**(4)*invcoth(xi)))**(-1)
F3f_def = -(xi**(2)*(378*xi**(10)+801*xi**(8)-4731*xi**(6)+5551*xi**(4)-2369*xi**(2)+342) \
-27*xi**(2)*(6*xi**(6)+xi**(4)-4*xi**(2)+1)*xib**(8)*invcoth(xi)**(4)+9*xi*(12*xi**(10)+28*xi**(8)-201*xi**(6) \
+273*xi**(4)-147*xi**(2)+27)*xib**(4)*invcoth(xi)**(3)+(-972*xi**(13)-324*xi**(11)+7365*xi**(9) \
-10409*xi**(7)+5143*xi**(5)-847*xi**(3)+44*xi)*invcoth(xi)+3*(216*xi**(14)-378*xi**(12) \
+109*xi**(10)-412*xi**(8)+1204*xi**(6)-1028*xi**(4)+311*xi**(2)-22)*invcoth(xi)**(2)) \
*(480*xi**(2)*(-1+2*xi**(2))**(3)*(-3*xi**(2)+3*xib**(2)*xi*invcoth(xi)+2)*(-3*xi**(3)+5*xi \
+3*xib**(4)*invcoth(xi))*((3*xi**(2)-1)*invcoth(xi)-3*xi))**(-1)
F4f_def = F3f_def
F5f_def = - F3f_def / 2.0
F6f_def = - F3f_def / 2.0
G1f_def = (xi**(2)*(81*xi**(10)-414*xi**(8)+1074*xi**(6)-1162*xi**(4)+479*xi**(2)-54) \
+9*xi**(2)*(9*xi**(6)-7*xi**(2)+2)*xib**(8)*invcoth(xi)**(4)-3*xi*(108*xi**(10)-246*xi**(8)+69*xi**(6) \
+167*xi**(4)-129*xi**(2)+23)*xib**(4)*invcoth(xi)**(3)+(-324*xi**(13)+1566*xi**(11)-3309*xi**(9) \
+3133*xi**(7)-1023*xi**(5)-79*xi**(3)+36*xi)*invcoth(xi) \
+(486*xi**(14)-2214*xi**(12)+3819*xi**(10)-2568*xi**(8)-222*xi**(6)+1036*xi**(4)-355*xi**(2)+18) \
*invcoth(xi)**(2))*(40*(xi-2*xi**(3))**(2)*(-3*xi**(2)+3*xib**(2)*xi*invcoth(xi)+2) \
*(-3*xi**(3)+5*xi+3*xib**(4)*invcoth(xi))*((3*xi**(2)-1)*invcoth(xi)-3*xi))**(-1)
G2f_def = (-xi**(2)*(27*xi**(10)-180*xi**(8)+204*xi**(6)+68*xi**(4)-133*xi**(2)+18) \
-9*xi**(4)*(3*xi**(4)+2*xi**(2)-1)*xib**(8)*invcoth(xi)**(4)+3*xi \
*(36*xi**(10)-78*xi**(8)+73*xi**(6)-69*xi**(4)+35*xi**(2)-5)*xib**(4)*invcoth(xi)**(3) \
+xi*(108*xi**(12)-630*xi**(10)+1041*xi**(8)-617*xi**(6)+115*xi**(4)-29*xi**(2)+12) \
*invcoth(xi)+(-162*xi**(14)+810*xi**(12)-1551*xi**(10)+1600*xi**(8) \
-1054*xi**(6)+448*xi**(4)-97*xi**(2)+6)*invcoth(xi)**(2)) \
*(40*(xi-2*xi**(3))**(2)*(-3*xi**(2)+3*xib**(2)*xi*invcoth(xi)+2) \
*(-3*xi**(3)+5*xi+3*xib**(4)*invcoth(xi))*((3*xi**(2)-1)*invcoth(xi)-3*xi))**(-1)
G3f_def = (xi**(2)*(378*xi**(10)+801*xi**(8)-4731*xi**(6)+5551*xi**(4)-2369*xi**(2)+342) \
-27*xi**(2)*(6*xi**(6)+xi**(4)-4*xi**(2)+1)*xib**(8)*invcoth(xi)**(4) \
+9*xi*(12*xi**(10)+28*xi**(8)-201*xi**(6)+273*xi**(4)-147*xi**(2)+27)*xib**(4)*invcoth(xi)**(3) \
+(-972*xi**(13)-324*xi**(11)+7365*xi**(9)-10409*xi**(7)+5143*xi**(5)-847*xi**(3)+44*xi) \
*invcoth(xi)+3*(216*xi**(14)-378*xi**(12)+109*xi**(10)-412*xi**(8)+1204*xi**(6)-1028*xi**(4) \
+311*xi**(2)-22)*invcoth(xi)**(2))*(120*xi**(2)*(2*xi**(2)-1)**(3)*(-3*xi**(2)+3*xib**(2)*xi*invcoth(xi)+2) \
*(-3*xi**(3)+5*xi+3*xib**(4)*invcoth(xi))*((3*xi**(2)-1)*invcoth(xi)-3*xi))**(-1)
G4f_def = - G3f_def
I1=2*sym.pi
I2=2*sym.pi*(k-1)*(k+1)**(-1)
I3=2*sym.pi*(2*((C**(2)+1)*(C**(2)*k**(2)+1))**(-1/2)-1)
I4=2*sym.pi*(k-1)**(2)*(k+1)**(-2)
I5I6 = -(4*sym.pi*(2*k**(2)*(3*sym.sqrt((C**(2)+1)*(C**(2)*k**(2)+1))-8*C**(2)-6) \
+4*k*sym.sqrt((C**(2)+1)*(C**(2)*k**(2)+1)) \
+sym.sqrt((C**(2)+1)*(C**(2)*k**(2)+1))+4*(4*C**(2)+1)*k**(3)*sym.sqrt((C**(2)+1)*(C**(2)*k**(2)+1)) \
+k**(4)*(sym.sqrt((C**(2)+1)*(C**(2)*k**(2)+1))-16*(C**(4)+C**(2))-2)-2)) \
*((k**(2)-1)**(2)*sym.sqrt((C**(2)+1)*(C**(2)*k**(2)+1)))**(-1)
J1=sym.pi*(k**(2)-1)*(k+1)**(-2)
J2 = -sym.pi*(-4*((C**2+1)*(C**2*k**2+1))**0.5+C**2*(k+1)**2+4)*C**(-2)*(k**2-1)**(-1)
J3=sym.pi*(k-1)**(2)*(k+1)**(-2)
J4 = -sym.pi*(k**(2)-1)*(8*C**(4)*k**(3)+C**(2)*((k+1)**(4)-8*k**(2)*sym.sqrt((C**(2)+1)*(C**(2)*k**(2)+1))) \
-4*(k**(2)+1)*(sym.sqrt((C**(2)+1)*(C**(2)*k**(2)+1))-1))*C**(-2)*(k**(2)-1)**(-3)
def shape_coeffs(r,e0):
"""returns the shape-dependent coefficients"""
if(r>1.0):
F1p_eff = F1p_def.subs({xib:(xi**2-1)**0.5,xi:e0}).evalf()
F2p_eff = F2p_def.subs({xib:(xi**2-1)**0.5,xi:e0}).evalf()
F3p_eff = F3p_def.subs({xib:(xi**2-1)**0.5,xi:e0}).evalf()
F4p_eff = F4p_def.subs({xib:(xi**2-1)**0.5,xi:e0}).evalf()
F5p_eff = F5p_def.subs({xib:(xi**2-1)**0.5,xi:e0}).evalf()
F6p_eff = F6p_def.subs({xib:(xi**2-1)**0.5,xi:e0}).evalf()
G1p_eff = G1p_def.subs({xib:(xi**2-1)**0.5,xi:e0}).evalf()
G2p_eff = G2p_def.subs({xib:(xi**2-1)**0.5,xi:e0}).evalf()
G3p_eff = G3p_def.subs({xib:(xi**2-1)**0.5,xi:e0}).evalf()
G4p_eff = G4p_def.subs({xib:(xi**2-1)**0.5,xi:e0}).evalf()
F1f_eff = F1f_def.subs({xib:(xi**2-1)**0.5,xi:e0}).evalf()
F2f_eff = F2f_def.subs({xib:(xi**2-1)**0.5,xi:e0}).evalf()
F3f_eff = F3f_def.subs({xib:(xi**2-1)**0.5,xi:e0}).evalf()
F4f_eff = F4f_def.subs({xib:(xi**2-1)**0.5,xi:e0}).evalf()
F5f_eff = F5f_def.subs({xib:(xi**2-1)**0.5,xi:e0}).evalf()
F6f_eff = F6f_def.subs({xib:(xi**2-1)**0.5,xi:e0}).evalf()
G1f_eff = G1f_def.subs({xib:(xi**2-1)**0.5,xi:e0}).evalf()
G2f_eff = G2f_def.subs({xib:(xi**2-1)**0.5,xi:e0}).evalf()
G3f_eff = G3f_def.subs({xib:(xi**2-1)**0.5,xi:e0}).evalf()
G4f_eff = G4f_def.subs({xib:(xi**2-1)**0.5,xi:e0}).evalf()
else:
F1p_tmp = ((F1p_def*xi**2).subs({xib:(xi**2-1)**0.5,xi:sym.I*(xi**2-1)**0.5}))/(xi**2)
F1p_eff = -sym.re(F1p_tmp.subs({xi:e0}).evalf())
F2p_tmp = ((F2p_def*xi**2).subs({xib:(xi**2-1)**0.5,xi:sym.I*(xi**2-1)**0.5}))/(xi**2)
F2p_eff = -sym.re(F2p_tmp.subs({xi:e0}).evalf())
F3p_tmp = ((F3p_def*xi**2).subs({xib:(xi**2-1)**0.5,xi:sym.I*(xi**2-1)**0.5}))/(xi**2)
F3p_eff = -sym.re(F3p_tmp.subs({xi:e0}).evalf())
F4p_tmp = ((F4p_def*xi**2).subs({xib:(xi**2-1)**0.5,xi:sym.I*(xi**2-1)**0.5}))/(xi**2)
F4p_eff = -sym.re(F4p_tmp.subs({xi:e0}).evalf())
F5p_tmp = ((F5p_def*xi**2).subs({xib:(xi**2-1)**0.5,xi:sym.I*(xi**2-1)**0.5}))/(xi**2)
F5p_eff = -sym.re(F5p_tmp.subs({xi:e0}).evalf())
F6p_tmp = ((F6p_def*xi**2).subs({xib:(xi**2-1)**0.5,xi:sym.I*(xi**2-1)**0.5}))/(xi**2)
F6p_eff = -sym.re(F6p_tmp.subs({xi:e0}).evalf())
G1p_tmp = ((G1p_def*xi**2).subs({xib:(xi**2-1)**0.5,xi:sym.I*(xi**2-1)**0.5}))/(xi**2)
G1p_eff = -sym.re(G1p_tmp.subs({xi:e0}).evalf())
G2p_tmp = ((G2p_def*xi**2).subs({xib:(xi**2-1)**0.5,xi:sym.I*(xi**2-1)**0.5}))/(xi**2)
G2p_eff = -sym.re(G2p_tmp.subs({xi:e0}).evalf())
G3p_tmp = ((G3p_def*xi**2).subs({xib:(xi**2-1)**0.5,xi:sym.I*(xi**2-1)**0.5}))/(xi**2)
G3p_eff = -sym.re(G3p_tmp.subs({xi:e0}).evalf())
G4p_tmp = ((G4p_def*xi**2).subs({xib:(xi**2-1)**0.5,xi:sym.I*(xi**2-1)**0.5}))/(xi**2)
G4p_eff = -sym.re(G4p_tmp.subs({xi:e0}).evalf())
F1f_tmp = ((F1f_def * xi**2).subs({xib:(xi**2-1)**0.5,xi:sym.I*(xi**2-1)**0.5}))/(xi**2)
F1f_eff = -sym.re(F1f_tmp.subs({xi:e0}).evalf())
F2f_tmp = ((F2f_def * xi**2).subs({xib:(xi**2-1)**0.5,xi:sym.I*(xi**2-1)**0.5}))/(xi**2)
F2f_eff = -sym.re(F2f_tmp.subs({xi:e0}).evalf())
F3f_tmp = ((F3f_def * xi**2).subs({xib:(xi**2-1)**0.5,xi:sym.I*(xi**2-1)**0.5}))/(xi**2)
F3f_eff = -sym.re(F3f_tmp.subs({xi:e0}).evalf())
F4f_tmp = ((F4f_def * xi**2).subs({xib:(xi**2-1)**0.5,xi:sym.I*(xi**2-1)**0.5}))/(xi**2)
F4f_eff = -sym.re(F4f_tmp.subs({xi:e0}).evalf())
F5f_tmp = ((F5f_def * xi**2).subs({xib:(xi**2-1)**0.5,xi:sym.I*(xi**2-1)**0.5}))/(xi**2)
F5f_eff = -sym.re(F5f_tmp.subs({xi:e0}).evalf())
F6f_tmp = ((F6f_def * xi**2).subs({xib:(xi**2-1)**0.5,xi:sym.I*(xi**2-1)**0.5}))/(xi**2)
F6f_eff = -sym.re(F6f_tmp.subs({xi:e0}).evalf())
G1f_tmp = ((G1f_def * xi**2).subs({xib:(xi**2-1)**0.5,xi:sym.I*(xi**2-1)**0.5}))/(xi**2)
G1f_eff = -sym.re(G1f_tmp.subs({xi:e0}).evalf())
G2f_tmp = ((G2f_def * xi**2).subs({xib:(xi**2-1)**0.5,xi:sym.I*(xi**2-1)**0.5}))/(xi**2)
G2f_eff = -sym.re(G2f_tmp.subs({xi:e0}).evalf())
G3f_tmp = ((G3f_def * xi**2).subs({xib:(xi**2-1)**0.5,xi:sym.I*(xi**2-1)**0.5}))/(xi**2)
G3f_eff = -sym.re(G3f_tmp.subs({xi:e0}).evalf())
G4f_tmp = ((G4f_def * xi**2).subs({xib:(xi**2-1)**0.5,xi:sym.I*(xi**2-1)**0.5}))/(xi**2)
G4f_eff = -sym.re(G4f_tmp.subs({xi:e0}).evalf())
return (F1p_eff,F2p_eff,F3p_eff,F4p_eff,F5p_eff,F6p_eff,G1p_eff,G2p_eff,G3p_eff,G4p_eff,
F1f_eff,F2f_eff,F3f_eff,F4f_eff,F5f_eff,F6f_eff,G1f_eff,G2f_eff,G3f_eff,G4f_eff)
def inertial_contributions(r,ee):
F1p,F2p,F3p,F4p,F5p,F6p,G1p,G2p,G3p,G4p,F1f,F2f,F3f,F4f,F5f,F6f,G1f,G2f,G3f,G4f = shape_coeffs(r,ee)
particle_inertia_prolate = (C*(2*xi**2-1)/(xi*xib)*((I1*F1p+I2*F2p+I3*F3p+I4*F4p+(I5I6)*F5p) \
+(J1*G1p+J2*G2p+J3*G3p+J4*G4p))).subs({xib:(xi**2-1)**0.5,xi:ee,k:r}).evalf()
fluid_inertia_prolate = (C*(2*xi**2-1)/(xi*xib)*((I1*F1f+I2*F2f+I3*F3f+I4*F4f+(I5I6)*F5f) \
+(J1*G1f+J2*G2f+J3*G3f+J4*G4f))).subs({xib:(xi**2-1)**0.5,xi:ee,k:r}).evalf()
particle_inertia_oblate = (C*(2*xi**2-1)/(xi*xib)*((I1*F1p+I2*F2p+I3*F3p+I4*F4p+(I5I6)*F5p) \
+(J1*G1p+J2*G2p+J3*G3p+J4*G4p))).subs({xib:(xi**2-1)**0.5,xi:ee,k:r}).evalf()
fluid_inertia_oblate = (C*(2*xi**2-1)/(xi*xib)*((I1*F1f+I2*F2f+I3*F3f+I4*F4f+(I5I6)*F5f) \
+(J1*G1f+J2*G2f+J3*G3f+J4*G4f))).subs({xib:(xi**2-1)**0.5,xi:ee,k:r}).evalf()
if r>1.0:
return particle_inertia_prolate,fluid_inertia_prolate
elif r>0.0 and r<1.0:
return particle_inertia_oblate,fluid_inertia_oblate
def calculate_eccentricity(r):
"""calculate particle eccentricity from aspect ratio"""
if r > 1.0:
return r/(r**2-1)**0.5
elif r < 1.0 and r > 0.0:
return 1/(1-r**2)**0.5
else:
raise ValueError('Please pass a valid aspect ratio > 0.0 and != 1.0')
def deltaC_dabade16(r=0.56,Crange=None):
"""returns particle and fluid inertia orbit variations for the given aspect ratio and range of orbit costants"""
ee = calculate_eccentricity(r)
PINE,FINE = inertial_contributions(r,ee)
if Crange is None:
Crange = np.concatenate((np.linspace(0.00001,0.9,100),np.linspace(1,4,100)))
Crange = np.concatenate((Crange,np.linspace(4,100,100)))
CDC_pine = []
CDC_fine = []
for j in range(len(Crange)):
CVAL = Crange[j]
data = PINE.subs({C:CVAL})
CDC_pine.append([CVAL,data])
data = FINE.subs({C:CVAL})
CDC_fine.append(data)
CDC_pine = np.array(CDC_pine)
CDC_fine = np.array(CDC_fine)
return np.column_stack((CDC_pine,CDC_fine))