I tried this, but my answers were similar for the two kernels
from __future__ import print_function
from fenics import *
import numpy as np
import matplotlib.pyplot as plt
T = 100.0 # final time
num_steps = 500 # number of time steps
dt = T / num_steps # time step size
# Create mesh and define function space
nx = ny = 32
mesh = RectangleMesh(Point(-1, -1), Point(1, 1), nx, ny)
# diffusivity contants
D_g = 0.0035 # m^2 per seconds
D_f = 0.0008 #m^2 per seconds
# fraction of volume space ocuupied by each specie
w_g = 1.0
w_f = 1.0
# taxis
chi_f = 0.08
# Define function space for system of concentrations
P1 = FiniteElement('P', triangle, 1)
P2 = FiniteElement('P', triangle, 2)
P0 = FiniteElement('DG', triangle, 0)
element = MixedElement([P1, P1])
element2 = MixedElement([P2, P2])
V = FunctionSpace(mesh, element2)
V1 = FunctionSpace(mesh, P1)
V0 = FunctionSpace(mesh, P0)
V2 = FunctionSpace(mesh, P2)
# Define test functions
v_g, v_f = TestFunctions(V)
# Define functions
u = Function(V)
u_0 = Expression(('0.1',
'0.4*((0.5+0.5*tanh(20*x[0]-3))+(0.5+0.5*tanh(-20*x[0]-3)))'), degree=2)
u_n = interpolate(u_0, V)
# Split system functions to access components
g, f = split(u)
g_n, f_n = split(u_n)
# define the Neumann boundary conditions for g and f
Nbc_g = Constant(0)
Nbc_f = Constant(0)
# starting time
t = 0
# The LHS of the trapezoidal rule
a_b = (g - g_n)*v_g*dx + (f - f_n)*v_f*dx
# interaction radius
R = 0.1
# defining the weak form
func_g = dot(D_g*grad(g), grad(v_g))*dx + D_g*Nbc_g*v_g*ds
func_f = dot(D_f*grad(f), grad(v_f))*dx - D_f*Nbc_f*v_f*ds
# tolerance
tol = 10*DOLFIN_EPS
# to play with a mesh e.g, generate subdomain, we creat a MeshFunction
materials = MeshFunction("size_t", mesh, mesh.topology().dim()) # over cells f
bd = MeshFunction("size_t", mesh, mesh.topology().dim()-1) # over facets for boundary
# define the measures for the intending subdomain and its boundary
ds = Measure('ds', domain=mesh, subdomain_data=bd)
dx = Measure('dx', domain=mesh, subdomain_data = materials)
# no
Af_n = (0.5*w_f*f_n*chi_f)*grad(f_n)
# define DG order 0 element, one value per cell since we want to assign a constant value to each cell
DG_Function_f1 = Function(V0) # for the two kernels
DG_Function_f2 = Function(V0)
# Functions to keep the weight of every cell in the subdomains
DG_S_f1 = Function(V0)
DG_S_f2 = Function(V0)
# create a subdomain class
class Interaction_range(SubDomain):
def __init__(self, cell_bc, r, **kwargs):
super().__init__(**kwargs)
self.r = r
self.cell_bc = cell_bc
def inside(self, x, on_boundary):
return (x[0]-self.cell_bc[0])*(x[0]-self.cell_bc[0]) +\
(x[1]-self.cell_bc[1])*(x[1]-self.cell_bc[1]) <= self.r*self.r + tol
# mark value for the subdomain
mark_value = 5
# a list of lists to store all the triangles in each sudomain generated by each triangles in the fine mesh globally
global_cells = []
# iterate over the triangles in the fine mesh
for cell in cells(mesh):
#if cell.index()==0:
#define the barycenterof the triangle
cell_bc = cell.midpoint()
# create subdomain class of radius r for each cell on the mesh
subdomain = Interaction_range(cell_bc, R)
# mark the triangles as zero
materials.set_all(0)
# mark all the triangles in the interaction region of the chosen triangle
subdomain.mark(materials, mark_value)
# keep the marked triangles in the interaction region of the chosen triangle in a list
local_cells = list(np.flatnonzero(materials.array()==mark_value)) # get the triangles in the subdomain as a list
global_cells.append(local_cells) # store the list of the triangles for each subdomain in a global list
# step into to time
for n in range(num_steps):
# Update current time
t += dt
for cell in cells(mesh):# type: ignore
# mark all as zero
materials.set_all(0)
cell_bc = cell.midpoint()
# pick the appropriate subdomain (conisting of triangles) for each triangle by specifying the corresponding index and marking it
materials.array()[global_cells[cell.index()]] = mark_value
ele_list = np.where(materials.array()==mark_value) # get the index of the elements in the subdomain
ele_list = np.array(ele_list).tolist() # to convert a turple to a list
# a radius to make sure only the present cell remain in the sudomaim (checked and verified)
R_1 = 0.05
# loop throught the cells in each the subdoamin
for j in ele_list[0]: # picked the first element becuase I got a list of lists [[a, b]] and I need [a, b]
sem = MeshEntity(mesh, 2, j).midpoint() # get the barycentre of each element in the subdomain
# make each element a subdomain consisting of only the element
subdomain_s = Interaction_range(sem, R_1)
# mark the triangles as zero
materials.set_all(0)
# mark a single triangle
subdomain_s.mark(materials, mark_value)
# kernels of interaction
k_1 = 3/(pi*R*R)*(1 - np.linalg.norm(sem.array()-cell_bc.array())/R)
s = 0.04 # std of the Gaussian kernel
# Gaussian kernel
k_2 = 1/(2*pi*s*s)*exp(-(1/(2*s*s))*(np.linalg.norm(sem.array()-cell_bc.array()))**2)
# Carry out this expressions for each cell (subdomain) for each of the kernels
DG_S_f1.vector()[j] = assemble(chi_f*0.5*(f_n*div(f_n*Af_n)*k_1*dx(mark_value)))
DG_S_f2.vector()[j] = assemble(chi_f*0.5*(f_n*div(f_n*Af_n)*k_2*dx(mark_value)))
# Step out to the main subdomain
materials.set_all(0)
materials.array()[global_cells[cell.index()]] = mark_value
# integrate over the marked subdomain
nonlocal_interaction_f1 = DG_S_f1*dx(mark_value)
nonlocal_interaction_f2 = DG_S_f2*dx(mark_value)
DG_Function_f1.vector()[cell.index()]=assemble(nonlocal_interaction_f1)
DG_Function_f2.vector()[cell.index()]=assemble(nonlocal_interaction_f2)
# project it to a V1 space
Nonlocal_interaction_f1=interpolate(DG_Function_f1, V1)
Nonlocal_interaction_f2=interpolate(DG_Function_f2, V1)
# get the weak form and add it to the rest of the weak form
func_f+=Nonlocal_interaction_f1*v_f*dx
# uncomment to use the second kerne;
#func_f+=Nonlocal_interaction_f2*v_f*dx
# Adding the functions (weak forms) together
f_u = func_g + func_f
# Euler
F = a_b + dt*f_u
# solve
du = TrialFunction(V)
J = derivative(F, u, du)
Problem = NonlinearVariationalProblem(F, u, J = J)
Solver = NonlinearVariationalSolver(Problem)
Solver.parameters['newton_solver']['convergence_criterion'] = 'incremental'
Solver.parameters['newton_solver']['linear_solver'] = 'mumps'
Solver.parameters['newton_solver']['relative_tolerance'] = 1.e-10
Solver.parameters['newton_solver']['absolute_tolerance'] = 1.e-11
Solver.parameters['newton_solver']['maximum_iterations'] = 100
# Compute solution
Solver.solve()
# Extract the solutions from u
gn_sol, fn_sol = u.split()
# save the solutions for external view
File('non_local_trial/trial_growth_factor.pvd') << (gn_sol,t)
File('non_local_trial/trial_fibroblast.pvd') << (fn_sol,t)
# Update previous solution
u_n.assign(u)
Does it make sense to assign value to each cell in the subdomain by doing this
# loop throught the cells in each the subdoamin
for j in ele_list[0]: # picked the first element becuase I got a list of lists [[a, b]] and I need [a, b]
sem = MeshEntity(mesh, 2, j).midpoint() # get the barycentre of each element in the subdomain
# make each element a subdomain consisting of only the element
subdomain_s = Interaction_range(sem, R_1)
# mark the triangles as zero
materials.set_all(0)
# mark a single triangle
subdomain_s.mark(materials, mark_value)
# kernels of interaction
k_1 = 3/(pi*R*R)*(1 - np.linalg.norm(sem.array()-cell_bc.array())/R)
s = 0.04 # std of the Gaussian kernel
# Gaussian kernel
k_2 = 1/(2*pi*s*s)*exp(-(1/(2*s*s))*(np.linalg.norm(sem.array()-cell_bc.array()))**2)
# Carry out this expressions for each cell (subdomain) for each of the kernels
DG_S_f1.vector()[j] = assemble(chi_f*0.5*(f_n*div(f_n*Af_n)*k_1*dx(mark_value)))
DG_S_f2.vector()[j] = assemble(chi_f*0.5*(f_n*div(f_n*Af_n)*k_2*dx(mark_value)))