How to add latent heat term in FiPy? - python

I have been trying to simulate Two Temperature Model using fipy
the math of the model:
C_e(∂T_e)/∂t=∇[k_e∇T_e ]-G(T_e-T_ph )+ A(r,t)
C_ph(∂T_ph)/∂t=∇[k_ph∇T_ph] + G(T_e-T_ph)
the source supposed to heat the electrons T_e, then the heat transferred to phonons T_ph through G, when T_ph reach melting point for example 2700 K, some of heat (360000 J) goes as latent heat before melting.
here is my code:
from fipy.tools import numerix
import scipy
import fipy
import numpy as np
from fipy import CylindricalGrid1D
from fipy import Variable, CellVariable, TransientTerm, DiffusionTerm, Viewer, LinearLUSolver, LinearPCGSolver, \
LinearGMRESSolver, ImplicitDiffusionTerm, Grid1D, ImplicitSourceTerm
## Mesh
nr = 50
dr = 1e-7
# r = nr * dr
mesh = CylindricalGrid1D(nr=nr, dr=dr, origin=0)
x = mesh.cellCenters[0]
# Variables
T_e = CellVariable(name="electronTemp", mesh=mesh,hasOld=True)
T_e.setValue(300)
T_ph = CellVariable(name="phononTemp", mesh=mesh, hasOld=True)
T_ph.setValue(300)
G = CellVariable(name="EPC", mesh=mesh)
t = Variable()
# Material parameters
C_e = CellVariable(name="C_e", mesh=mesh)
k_e = CellVariable(name="k_e", mesh=mesh)
C_ph = CellVariable(name="C_ph", mesh=mesh)
k_ph = CellVariable(name="k_ph", mesh=mesh)
C_e = 4.15303 - (4.06897 * numerix.exp(T_e / -85120.8644))
C_ph = 4.10446 - 3.886 * numerix.exp(-T_ph / 373.8)
k_e = 0.1549 * T_e**-0.052
k_ph =1.24 + 16.29 * numerix.exp(-T_ph / 151.57)
G = numerix.exp(21.87 + 10.062 * numerix.log(numerix.log(T_e )- 5.4))
# Boundary conditions
T_e.constrain(300, where=mesh.facesRight)
T_ph.constrain(300, where=mesh.facesRight)
# Source 𝐴(𝑟,𝑡) = 𝑎𝐷(𝑟)𝜏−1 𝑒−𝑡/𝜏 , 𝐷(𝑟) = 𝑆𝑒 exp (−𝑟2/𝜎2)/√2𝜋𝜎2
sig = 1.0e-6
tau = 1e-15
S_e = 35
d_r = (S_e * 1.6e-9 * numerix.exp(-x**2 /sig**2)) / (numerix.sqrt(2. * 3.14 * sig**2))
A_t = numerix.exp(-t/tau)
a = (numerix.sqrt(2. * 3.14)) / (3.14 * sig)
A_r = a * d_r * tau**-1 * A_t
eq0 = (
TransientTerm(var=T_e, coeff=C_e) == \
DiffusionTerm(var=T_e, coeff=k_e) - \
ImplicitSourceTerm(coeff=G, var=T_e) + \
ImplicitSourceTerm(var=T_ph, coeff=G) + \
A_r)
eq1 = (TransientTerm(var=T_ph, coeff=C_ph) == DiffusionTerm(var=T_ph, coeff=k_ph) + ImplicitSourceTerm(var=T_e, coeff=G) - ImplicitSourceTerm(coeff=G, var=T_ph))
eq = eq0 & eq1
dt = 1e-18
steps = 7000
elapsed = 0.
vi = Viewer((T_e, T_ph), datamin=0., datamax=2e4)
for step in range(steps):
T_e.updateOld()
T_ph.updateOld()
vi.plot()
res = 1e100
dt *= 1.01
count = 0
while res > 1:
res = eq.sweep(dt=dt, underRelaxation=0.5)
print(t, res)
t.setValue(t + dt)
As I understood I can include the latent heat as source term as sink in eq1, or add a gaussian peak to C_ph and the peak center should be around melting point.
I have no idea which one is better and more stable, I have no idea how to implement any one of them .
please help me with that

Based on the comments (please edit that into the question), change eq1 to
eq1 = (TransientTerm(var=T_ph, coeff=C_ph)
== DiffusionTerm(var=T_ph, coeff=k_ph)
+ ImplicitSourceTerm(var=T_e, coeff=G)
- ImplicitSourceTerm(coeff=G, var=T_ph)
+ (1/numerix.sqrt(2*numerix.pi * sig2)) * numerix.exp(-(T_ph - 1850)**2 / 2 * sig2)))
It will be evaluated explicitly, but it will update whenever T_ph updates.

Related

solve_ivp error : Required step size is less than spacing between numbers

I have been trying to implement a model of unstable glacier flow in Python, solving the ODEs in scipy, with the RK45 method.
The original model publication can be found here.
Now, I think I understand what is going on with the error but I cannot find a way to fix it.
I don't know if it comes from my implementation or from the ODEs themselves.
I've been through the units several times, checking that all times were in seconds, all distances in meters and so on.
I've tried with different t_eval and even different values of certain constants, but not been able to solve my problem.
I started by creating a class with all constants.
import numpy as np
import scipy.integrate
import matplotlib.pyplot as plt
import astropy.units as u
SECONDS_PER_YEAR = 3600*24*365.15
class Cst:
#Glenn's flow Law
A = 2.4e-25
n = 3.
#Standard physical constants
g = 10.#*(u.m)*(u.second**-2)
rho = 916#*(u.kilogram*(u.m**-3))
#Thermodynamics
cp = 2000#**(u.Joule)*(u.kilogram**-1)*(u.Kelvin**-1)
L = 3.3e5#*(u.Joule)*(u.kilogram**-1)
k = 2.1 #*(u.Watt)*(u.m**-1)*'(u.Kelvin**-1)'
DDF = 0.1/SECONDS_PER_YEAR #*(u.m)*(u.yr**-1)*'(u.Kelvin**-1)
K = 2.3e-47#*((3600*24*365.15)**9)#*((u.kilogram**-5)*(u.m**2)*(u.second**9))
C = 9.2e13#*((u.Pascal)*(u.Joule)*(u.m**-2))
#Weertman friction law
q = 1
p = 1/3
R = 15.7#*((u.m**(-1/3))*(u.second**(1/3)))
d = 10#*u.m
sin_theta = 0.05
Tm = 0+273.15 #*u.Kelvin
T_offset = -10+273.15#*u.Kelvin
w = 0.6 #u.m
Wc = 1000.#*u.m
#Velocities
u1 = 0/SECONDS_PER_YEAR #m/s
u2 = 100/SECONDS_PER_YEAR # m/s
#Dimensionless parameters
alpha = 5.
Then I declared the problem-specific parameters specified in the paper:
#All values are from Table 1
a0 = 1./SECONDS_PER_YEAR#* m/s (u.meter*((u.second)**-1))
l0 = 10000#*(u.meter)
E0 = 1.8e8#(Cst.g*Cst.sin_theta*a0*(l0**2))/(Cst.L*Cst.K))**(1/Cst.alpha)#*(u.Joule/u.m**2)
T0 = 10#E0/(Cst.rho*Cst.cp*Cst.d)#*u.Kelvin
w0 = 0.6#E0/(Cst.rho*Cst.L)#*u.m
N0 = 0.5#Cst.C/E0#*u.Pascal
H0 = 200 #((Cst.R*(Cst.C**Cst.q)*(a0**Cst.p)*(l0**Cst.p))/(Cst.rho*Cst.g*Cst.sin_theta*(E0**Cst.q)))**(1/(Cst.p+1))
t0 = 200 #H0/a0
u0 = 50/SECONDS_PER_YEAR#((Cst.rho*Cst.g*Cst.sin_theta*(E0**Cst.q)*a0*l0)/(Cst.R*(Cst.C**Cst.q)))**(1/(Cst.p+1))
Q0 = (Cst.g*Cst.sin_theta*a0*(l0**2))/Cst.L
S0 = ((Cst.g*Cst.sin_theta*a0*(l0**2)*Cst.Wc)/(Cst.L*Cst.K*((Cst.rho*Cst.g*Cst.sin_theta)**(1/2))))**(3/4)
lamb = ((2.*Cst.A*(Cst.rho*Cst.g*Cst.sin_theta)**Cst.n)*(H0**(Cst.n+1)))/((Cst.n+2)*u0)
chi = N0/(Cst.rho*Cst.g*H0)
gamma = 0.41
kappa = 0.7
phi = 0.2
delta = 66
mu = 0.2
Define the model :
def model(t, x):
#Initial values
H_hat = x[0]
E_hat = x[1]
#Thickness
H = H_hat*H0
#Enthalpy
E_hat_plus = max(E_hat, 0)
E_hat_minus = min(E_hat, 0)
E_plus = E_hat_plus*E0
E_minus = E_hat_minus*E0
a_hat = 1.
theta_hat = Cst.sin_theta/Cst.sin_theta
l_hat =l0/l0
T_a = 0+273.15
T = -10+273.15
# Equation 3
m_hat = (Cst.DDF*(T_a-Cst.T_offset))/a0
S_hat = 0.
T_a_hat = T_a/T0
#Equation A7
if E_plus > 0:
N = min(H/chi, 1./E_plus)
else:
N = H/chi
phi = min(1., E_plus/(H/chi))
#Equation 8
inv_p = 1./Cst.p
u = (Cst.rho*Cst.g*Cst.sin_theta/Cst.R * H * (N**(-Cst.q)))**inv_p
#Equation A7
beta = min(max(0, (u-Cst.u1)/(Cst.u2-Cst.u1)), 1)
#Equation A4
dHdt_hat = (
a_hat - m_hat
+ 1./l_hat*(
theta_hat**inv_p
* H_hat**(1.+inv_p)
* N**(-Cst.q*inv_p)
+ lamb*(theta_hat**Cst.n)
)
)
#Equation A5
dEdt_hat = 1./mu*(
theta_hat**(1+inv_p) * H_hat**(1.+inv_p) * N**(-Cst.q*inv_p)
+ gamma
+ kappa*(E_hat_minus - T_a_hat)/H_hat
- 1./l_hat * (
theta_hat * E_hat_plus**Cst.alpha
+ phi * theta_hat**(1./2) * S_hat**(4/3.)
)
+ delta * beta * m_hat
)
return [dHdt_hat, dEdt_hat]
And finally call it :
tmax = 200*SECONDS_PER_YEAR# *u.years
t = np.linspace(0, tmax, 10000)
sol = scipy.integrate.solve_ivp(model, t_span=[t[0], t[-1]], y0=[1, 1], t_eval=t, method='RK23')
print(sol)
Which yields
message: 'Required step size is less than spacing between numbers.'
nfev: 539
njev: 0
nlu: 0
sol: None
status: -1
success: False
t: array([0.])
t_events: None
y: array([[1.],
[1.]])
y_events: None

New to python and looking for a hint to solve a syntax error

I'm trying to figure out whats wrong about the following code sample. Running this I end up with a syntax error on line 18. Can't figure out why though.
import numpy as np
from scipy.integrate import odeint
import matplotlib.pyplot as plt
def hex(x, A):
Tf = x[0]
Tk = x[1]
Nk = 0.1
Tg = 300
b = 0.2
ag = 30
k = 20
Hvap = 80000
cpg = 100
cpk = 600
ng = 30
cpf = 600
q = k * (Tf-Tk)
n1 = ng * b * np.log(y2f/y2b)
dTfdA = (ag * phi * (Hvap/cpg + (Tg-Tf)/(1-np.exp(-phi))) - q / (Nf * cpf)
dTkdA = -q / (Nk * cpk)
return [dTfdA, dTkdA]
I think you're missing a bracket
dTfdA = (ag * phi * (Hvap/cpg + (Tg-Tf)/(1-np.exp(-phi))) - q / (Nf * cpf)
to
dTfdA = (ag * phi * (Hvap/cpg + (Tg-Tf)/(1-np.exp(-phi))) - q / (Nf * cpf))
You should write the equation as:
dTkdA = 0 - q / (Nk * cpk)

Cannot add scalar and a vector error in VPyhton (GlowScript)

I'm implementing a solar system with VPython in GlowScript. Now I have received this error when running: Error cannot add scalar and a vector. I think I've done all correctly. Do I have to change something with the pos. ?
Here is the code:
GlowScript 2.7 VPython
from visual import *
scene = display(width = 800, height = 800, center = vec(0,0.5,0))
#sun
sonne = sphere(pos = vec (0,0,0), radius=8, color = color.orange, shininess=1)
#earth
erde = sphere(pos = vec (50,0,0), radius=1.5, color = color.blue, make_trail=True)
erdeV = vector(0,0,5)
#masses
erdeM = 5.97*10**24
sonneM = 1.989*10**30
#Grav-constant
G = 6.67259*10**-11
for i in range (1000):
rate(1000)
erde.pos = erde.pos + erdeV
#distance
entfernung = sqrt(erde.pos.y**2 + erde.pos.z**2)
#Gravitational law F = G * m * M / r*r --> G*s*e/AE*AE ae=Astr. Einheit
Fgrav = G *( erdeM * sonneM) / (entfernung*entfernung)
erdeV = erdeV + Fgrav
erde.pos += erdeV
if entfernung <= sonne.radius: break
Problem lines:
Fgrav = G *( erdeM * sonneM) / (entfernung*entfernung)
erdeV = erdeV + Fgrav
Fgrav here is a scalar (strength of gravitational force) whereas erdeV is a vector. To remedy this, include the direction of the force:
Fgrav = (-G * (erdeM * sonneM) / (entfernung ** 3)) * erde.pos
erdeV = erdeV + Fgrav

Using scipy.integrate.ode to solve protoplanetary hydrostatic equilibria

I have written code to solve the protoplanetary hydrostatic equilibria equations using first order euler method, and the results are as expected. I now want to rewrite it using fourth order Runge-Kutta solution, which is builtin to scipy.integrate.ode
Expected result, attained by using a custom written euler method:
import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import ode
universalGasConstant = 8.31
gravitationalConstant = 6.67 * 10**-11
astronomicalUnit = 1.5 * (10**11)
coreMass = 5.9 * 10**24
sunMass = 2 * (10**30)
coreRadius = 0
coreDensity = 5500.0
semiMajorAxis = 5 * astronomicalUnit
gasMeanMolecularMass = 2.3 * 10**-3
coreRadius = (coreMass / ((4 / 3) * np.pi * coreDensity))**(1 / 3)
print('coreradius is', coreRadius)
hillSphere = (1**-4)*(semiMajorAxis) * (((coreMass) / (3 * sunMass))**(1 / 3))
print('hillsphere is', hillSphere)#THIS IS THE HILLSPHERE
numberOfSlices = 100000000 #NUMBER OF SLICES
deltaRadius = hillSphere / numberOfSlices
print('slice length is', deltaRadius)
#gravitationalForce = ((gravitationalConstant * coreMass) /
#(coreRadius + (deltaRadius)))
sunSurfaceTemperature = 5800
sunRadius = 6.96 * 10**8
equilibriumTemperature = sunSurfaceTemperature * \
(sunRadius / (2 * semiMajorAxis))**(1 / 2)
print('equilibrium temperature at', semiMajorAxis,
'metres is', equilibriumTemperature, 'kelvin')
pressureAtRadius = 0
initialDensity = 10.0 #INITIAL DENSITY
densityAtRadius = 0
muOverRT = gasMeanMolecularMass/(equilibriumTemperature * universalGasConstant)
print('muOverRT is', muOverRT)
totalMass = coreMass
densityAtRadius = initialDensity
def function(y, r):
totalMass = y[0]
distanceFromCOG = y[1]
# the differential equations
dRhodr = -(((gravitationalConstant*totalMass*
densityAtRadius*muOverRT))/(distanceFromCOG**2))
dMdr = 4*np.pi*gravitationalConstant*densityAtRadius
#dPdr = (1/(muOverRT))*dRhodr
return [dRhodr, dMdr]
distanceFromCOG = coreRadius+np.linspace(0,numberOfSlices) #number of points
initialDensity = [0,0]
solution = ode(function,initialDensity,distanceFromCOG).set_integrator('vode', method = 'dopri5')
plt.plot(solution)
solution.set_integrator('dopri5')

Python fsolve highly dependent on initial values (more than matlab)

I am new to python, transiting from Matlab. I wrote the following code to solve a nonlinear equation system but somehow failed in python. It worked in matlab fsolve for many initial values unless I put an extremely large number. But it only works for python fsolve if the initial value is close enough to the solution. I don't always have good initial guess to the problem so I want it to work most of the time. Thank you very much! Solution is [0.003,0.0053] according to Matlab.
Python code
param = {'r': 0.04,
'mu': 0.112,
'delta': 0.02,
'alpha': 0.35,
'g': 0.0187 + 0.5*0.16*0.16,
'sigma': 0.20,
'xi0': 0.02,
'xi1':1.05,
'lambda0':0.02,
'lambda1':1.05};
param['sgsq'] = 0.5*param['sigma']**2;
param['g0'] = param['g'] - (param['mu'] - param['r']) - param['sgsq'];
#%% Polynomial
import numpy as np
import numpy.polynomial.polynomial as poly
import scipy.optimize as spyopt
param['coef'] = (- (param['r']+param['delta']), (param['g0']+param['delta']
-param['sgsq']), param['sgsq'])
charfun = poly.Polynomial(param['coef'])
param['psi'] = np.max(poly.polyroots(param['coef']))
param['halpha'] = poly.polyval(param['alpha'],param['coef'])
def lumpyfun(x0, param0):
xstar,B = x0
AIPx = - np.power(xstar,param0['alpha']) / param0['halpha']
BigA = ((1.0-param0['alpha'])*(B**param0['alpha'])/(1.0-param0['psi'])/param0['halpha']
+ (param0['lambda1']-param0['lambda0'])/(1.0-param0['psi']))
vprimex = param0['alpha']*AIPx/xstar + param0['psi']*np.power((xstar/B),(param0['psi']-1.0)) * BigA/B
vprimeB = (param0['psi']-param0['alpha'])*np.power(B,param0['alpha']-1.0)/(1.0-param0['psi'])/param0['halpha'] + param0['psi']*(param0['lambda1']-param0['lambda0'])/(1.0-param0['psi'])/B
diffy = (AIPx + np.power(xstar/B,param0['psi']) * BigA - xstar*vprimex - param0['lambda1'], vprimex - vprimeB)
return diffy`def lumpyfun(x0, param0):
#%% Solve the problem
#worked
x0 = np.multiply(np.sqrt(-param['halpha']),(1.0,2.0))/100.0
#lumpyfun(x0,param)
spyopt.fsolve(lumpyfun, x0, args=param)
# not worked
x0 = np.multiply(np.sqrt(-param['halpha']),(1.0,2.0))/10.0
spyopt.fsolve(lumpyfun, x0, args=param, maxfev = 5000000)
Matlab code:
r = 0.04;
mu = 0.112;
delta = 0.02;
alpha = 0.35;
g = 0.0187 + 0.5*0.16*0.16 ; % 0.0187 + 0.5*sigma*sigma;
sigma = 0.20; % 0.16 default;
a2 = 0.5*sigma*sigma;
g0 = g - (mu-r) - a2; % risk-neutral growth;
lambda0 = 0.02;
lambda1 = 1.05;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%h = #(x) sgsq05*x^2 + (mu+delta-sgsq05)*x - (r+delta);
coef = [a2, (g0+delta-a2), - (r+delta)];
halpha = polyval(coef,alpha);
phi = max(roots(coef))
x0 = realsqrt(-halpha)*[1;2]/10;
options = optimoptions('fsolve','Display','off','MaxFunEvals',2000);
sol = fsolve(#(x) diffinvestmentoption(x,phi,alpha,lambda1,lambda0,halpha), x0, options);
function [diffy,X] = diffinvestmentoption(xin,phi,alpha,lambda1,lambda0,halpha)
xstar = xin(1);
B = xin(2);
AIPx = -xstar.^alpha / halpha;
%AIPB = -B.^alpha / halpha;
BigA = (1-alpha)*(B^alpha)/(1-phi)/halpha + (lambda1-lambda0)/(1-phi);
vprimex = alpha*AIPx/xstar + phi*(xstar/B)^(phi-1) * BigA/B;
vprimeB = (phi-alpha)*(B^(alpha-1))/(1-phi)/halpha + phi*(lambda1-lambda0)/(1-phi)/B;
diffy = [AIPx + (xstar/B)^phi * BigA - xstar*vprimex - lambda1;
vprimex - vprimeB];

Categories

Resources