I am trying to solve four coupled PDEs (two scalar density fields and one vector field- but I solve it component wise).
where the second term in first equation is given by
Now, in the Fipy code (the \rho and the vector components are denoted as by m, px and py respectively) I am writing them down as:
mesh = PeriodicGrid2D(dx, dy, nx, ny)
# Variables to use
c = CellVariable(name='c', mesh=mesh, hasOld=1)
m = CellVariable(name='m', mesh=mesh, hasOld=1)
px = CellVariable(name='px', mesh=mesh, hasOld=1)
py = CellVariable(name='py', mesh=mesh, hasOld=1)
x_hat = [1.0, 0.0]
y_hat = [0.0, 1.0]
#-------------------------------------------------------------------------
eq_c = (TransientTerm(var=c) ==
W*(c.grad.dot(x_hat)*m.grad.dot(x_hat) + c.grad.dot(y_hat)*m.grad.dot(y_hat))
- ExponentialConvectionTerm(coeff=x_hat * px*v0 + y_hat * py*v0, var=c)
+ DiffusionTerm(coeff=Da, var=c) + DiffusionTerm(coeff=W*c, var=m) )
eq_m = (TransientTerm(var=m) ==
kb*(c/(c+ch)) - ImplicitSourceTerm(coeff=ku, var=m)
- ExponentialConvectionTerm(coeff=x_hat * px*v0 + y_hat * py*v0, var=m)
+ DiffusionTerm(coeff=Dm, var=m) )
eq_px = (TransientTerm(var=px) ==
DiffusionTerm(coeff=K, var=px) - zeta0*c.grad.dot(x_hat) + zeta*m.grad.dot(x_hat)
+ ImplicitSourceTerm(coeff=((c/cs)-1 -((c/cs)+1)*(px*px+py*py)), var=px) )
eq_py = (TransientTerm(var=py) ==
DiffusionTerm(coeff=K, var=py) - zeta0*c.grad.dot(y_hat) + zeta*m.grad.dot(y_hat)
+ ImplicitSourceTerm(coeff=((c/cs)-1 -((c/cs)+1)*(px*px+py*py)), var=py) )
# Couple them into one big equation
eq = eq_c & eq_m & eq_px & eq_py
Is the Fipy implementation of the second term in c-equation correct? The code does not thow up any error but I am not getting expected results should be an aster as described in this paper. But I get solutions that show aster initially but diffusion takes over and in long term I get homogeneous solutions. I have seen the previous related questions here and here, but not entirely sure how to make use of them. Thanks in advance and sorry for the poor figures!
Here is a minimal working code:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
First version with no polarity dynamics, no equation for n-field
"""
from fipy import (CellVariable, PeriodicGrid2D, TransientTerm, DiffusionTerm, ExplicitDiffusionTerm,
UniformNoiseVariable, Variable, FaceVariable, ImplicitSourceTerm, ExponentialConvectionTerm)
import matplotlib.pyplot as plt
import matplotlib
from matplotlib import cm
matplotlib.rcParams.update({'font.size': 16})
import numpy as np
def run_sim(savename,K,zeta):
#------------ parameters -------------
Da=1.0
Dm=1.0
W=-30.0
kb=1.0/4.0
ku=1.0/8.0
ch=1.0/4.0
cs=1.0/64.0
zeta0=1.0
# zeta=1.0
v0=0.1
#-------------- Mesh --------------------
duration=1
dt=0.5
# Define mesh size and number of points
nx = 60
ny = nx
L = 20
dx = L / nx
dy = dx
mesh = PeriodicGrid2D(dx, dy, nx, ny)
xval = mesh.x
yval = mesh.y
# Variables to use
c = CellVariable(name='c', mesh=mesh, hasOld=1)
m = CellVariable(name='m', mesh=mesh, hasOld=1)
px = CellVariable(name='px', mesh=mesh, hasOld=1)
py = CellVariable(name='py', mesh=mesh, hasOld=1)
# Initial condition + some random noise
c.setValue( 0.1*np.exp(-0.25*(mesh.x-L/2)*(mesh.x-L/2)-0.25*(mesh.y-L/2)*(mesh.y-L/2)) )
m.setValue( UniformNoiseVariable(mesh=mesh, minimum=0.4*(kb/ku), maximum=0.5*(kb/ku)) )
px.setValue( UniformNoiseVariable(mesh=mesh, minimum=0.0, maximum=0.1) )
py.setValue( UniformNoiseVariable(mesh=mesh, minimum=0.0, maximum=0.1) )
x_hat = [1.0, 0.0]
y_hat = [0.0, 1.0]
#-------------------------------------------------------------------------
eq_c = (TransientTerm(var=c) ==
W*(c.grad.dot(x_hat)*m.grad.dot(x_hat) + c.grad.dot(y_hat)*m.grad.dot(y_hat))
- ExponentialConvectionTerm(coeff=x_hat * px*v0 + y_hat * py*v0, var=c)
+ DiffusionTerm(coeff=Da, var=c) + DiffusionTerm(coeff=W*c, var=m) )
eq_m = (TransientTerm(var=m) ==
kb*(c/(c+ch)) - ImplicitSourceTerm(coeff=ku, var=m)
- ExponentialConvectionTerm(coeff=x_hat * px*v0 + y_hat * py*v0, var=m)
+ DiffusionTerm(coeff=Dm, var=m) )
eq_px = (TransientTerm(var=px) ==
DiffusionTerm(coeff=K, var=px) - zeta0*c.grad.dot(x_hat) + zeta*m.grad.dot(x_hat)
+ ImplicitSourceTerm(coeff=((c/cs)-1 -((c/cs)+1)*(px*px+py*py)), var=px) )
eq_py = (TransientTerm(var=py) ==
DiffusionTerm(coeff=K, var=py) - zeta0*c.grad.dot(y_hat) + zeta*m.grad.dot(y_hat)
+ ImplicitSourceTerm(coeff=((c/cs)-1 -((c/cs)+1)*(px*px+py*py)), var=py) )
# Couple them into one big equation
eq = eq_c & eq_m & eq_px & eq_py
elapsed = 0.0
while elapsed < duration:
c.updateOld()
m.updateOld()
px.updateOld()
py.updateOld()
elapsed += dt
res = 1e5
old_res = res * 2
step = 0
while res > 1e-5 and step < 15 and old_res / res > 1.01:
old_res = res
res = eq.sweep(dt=dt)
step += 1
if __name__ == '__main__':
"""
comments
"""
path = 'result/'
def name(K, zeta):
return 'K_{:.2f}_zeta_{:.2f}'.format(K, zeta)
Ks = [1]
zetas = [30.0]
for K in Ks:
for zeta in zetas:
run_sim(name(K, zeta), K=K, zeta=zeta)
Is the Fipy implementation of the second term in c-equation correct?
No. The term DiffusionTerm(coeff=W*c, var=m)
represents . There is no reason to run the chain rule to obtain the explicit parts; it is, in fact, undesirable to do so.
Further converting the orientation to a rank-1 CellVariable
results in somewhat cleaner equations. FiPy cannot couple scalar c
and m
with vector p
, but the px
and py
equations weren't coupled, anyway.
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
First version with no polarity dynamics, no equation for n-field
"""
from fipy import (CellVariable, Grid2D, PeriodicGrid2D, TransientTerm, DiffusionTerm, ExplicitDiffusionTerm,
UniformNoiseVariable, Variable, FaceVariable, ImplicitSourceTerm, ExponentialConvectionTerm, Viewer)
import matplotlib.pyplot as plt
import matplotlib
from matplotlib import cm
matplotlib.rcParams.update({'font.size': 16})
import numpy as np
def run_sim(savename,K,zeta):
#------------ parameters -------------
Da=1.0
Dm=1.0
W=-30.0
kb=1.0/4.0
ku=1.0/8.0
ch=1.0/4.0
cs=1.0/64.0
zeta0=1.0
# zeta=1.0
v0=0.1
#-------------- Mesh --------------------
duration=1
dt=0.05
# Define mesh size and number of points
nx = 60
ny = nx
L = 20
dx = L / nx
dy = dx
mesh = Grid2D(dx, dy, nx, ny)
xval = mesh.x
yval = mesh.y
# Variables to use
c = CellVariable(name='c', mesh=mesh, hasOld=1)
m = CellVariable(name='m', mesh=mesh, hasOld=1)
p = CellVariable(name='p', mesh=mesh, rank=1, hasOld=True)
# Initial condition + some random noise
c.setValue( 0.1*np.exp(-0.25*(mesh.x-L/2)*(mesh.x-L/2)-0.25*(mesh.y-L/2)*(mesh.y-L/2)) )
m.setValue( UniformNoiseVariable(mesh=mesh, minimum=0.4*(kb/ku), maximum=0.5*(kb/ku)) )
p[0] = UniformNoiseVariable(mesh=mesh, minimum=0.0, maximum=0.1)
p[1] = UniformNoiseVariable(mesh=mesh, minimum=0.0, maximum=0.1)
x_hat = [1.0, 0.0]
y_hat = [0.0, 1.0]
#-------------------------------------------------------------------------
eq_c = (TransientTerm(var=c) ==
- ExponentialConvectionTerm(coeff=p*v0, var=c)
+ DiffusionTerm(coeff=Da, var=c) + DiffusionTerm(coeff=W*c, var=m) )
eq_m = (TransientTerm(var=m) ==
ImplicitSourceTerm(coeff=kb/(c+ch), var=c) - ImplicitSourceTerm(coeff=ku, var=m)
- ExponentialConvectionTerm(coeff=p*v0, var=m)
+ DiffusionTerm(coeff=Dm, var=m) )
eq_p = (TransientTerm(var=p) ==
DiffusionTerm(coeff=[[[K, 0],
[0, K]]], var=p) - zeta0*c.grad + zeta*m.grad
+ ImplicitSourceTerm(coeff=((c/cs)-1 -((c/cs)+1)*p.mag**2), var=p) )
# Couple them into one big equation
eq = eq_c & eq_m
elapsed = 0.0
viewer = Viewer(vars=c)
viewer.plot()
while elapsed < duration:
c.updateOld()
m.updateOld()
p.updateOld()
elapsed += dt
res = 1e5
old_res = res * 2
step = 0
while res > 1e-5 and step < 15 and old_res / res > 1.01:
old_res = res
res = eq.sweep(dt=dt)
eq_p.sweep(dt=dt)
step += 1
viewer.plot()
if __name__ == '__main__':
"""
comments
"""
path = 'result/'
def name(K, zeta):
return 'K_{:.2f}_zeta_{:.2f}'.format(K, zeta)
Ks = [1]
zetas = [30.0]
for K in Ks:
for zeta in zetas:
run_sim(name(K, zeta), K=K, zeta=zeta)