-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy path2D_HJB_Fenics.py
100 lines (75 loc) · 2.69 KB
/
2D_HJB_Fenics.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
"""
Solving 2D HJB PDE
"""
from fenics import *
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.animation as animation
# Create mesh and build function space
nx, ny = 149,149
mesh = RectangleMesh(Point(-3., -3.), Point(3., 3.), nx, ny) #
# keep dof in serial order (see https://fenicsproject.org/qa/3258/manually-setting-values-to-a-function/)
parameters["reorder_dofs_serial"] = False
V = FunctionSpace(mesh, "Lagrange", 1)
# Create boundary markers
tol = 1E-14
tdim = mesh.topology().dim()
boundary_parts = MeshFunction('size_t', mesh, tdim-1)
left = AutoSubDomain(lambda x: near(x[0], 0.0, tol))
right = AutoSubDomain(lambda x: near(x[0], 1.0, tol))
bottom = AutoSubDomain(lambda x: near(x[1], 0.0, tol))
top = AutoSubDomain(lambda x: near(x[1], 1.0, tol))
left.mark(boundary_parts, 1)
right.mark(boundary_parts, 1)
bottom.mark(boundary_parts, 1)
bottom.mark(boundary_parts, 1)
boundary_file = File("conc_diff/boundaries.pvd")
boundary_file << boundary_parts
# Terminal condition and right-hand side
spc = SpatialCoordinate(mesh)
denom = (2*pi)* 0.4
num = 50* exp(-0.5 * ((spc[0]**2+spc[1]**2) / 0.4 ))
f = num/denom
# Equation coefficients
K = Expression((("0.2","-0.16"),("-0.16","0.2")), degree = 0) # diffusion matrix
g = Constant(0.0) # Neumann bc
# Define boundary measure on Neumann part of boundary
dsN = Measure("ds", subdomain_id=1, subdomain_data=boundary_parts)
# Define trial and test function and solution at previous time-step
u = Function(V)
v = TestFunction(V)
u0 = Function(V)
# Time-stepping parameters
t_end = 1
dt = 0.001
# Define time discretized equation
F = inner(u0-u, v)*dx- 0.5*dt*inner(K*grad(u), grad(v))*dx + dt*f*v*dx -0.5 *dt*dot(nabla_grad(u),nabla_grad(u))*v*dx
# Prepare solution function and solver
# Time-stepping
t = 1.0
u.rename("u", "temperature")
u0.vector()[:] = 50*np.sum((V.tabulate_dof_coordinates()-np.array([[1.5,1.5]]))**2,1)
# Open figure for plots
fig = plt.figure()
plt.show(block=False)
# save solution at each time step; including the final time
sol_array = np.array(u0.vector().get_local().reshape(ny+1,nx+1)).reshape(1,ny+1,nx+1)
while t >dt:
# Solve the problem
solve(F==0,u,
solver_parameters={"newton_solver": {"relative_tolerance": 1e-6}})
# plot solution
p = plot(u, title='Solution at t = %g' % (t))
if p is not None:
plt.colorbar(p)
fig.canvas.draw()
plt.show()
plt.clf()
# Move to next time step
u0.assign(u)
t -= dt
info('t = %g' % t)
sol_array = np.append(sol_array,u0.vector().get_local().reshape(ny+1,nx+1).reshape(1,ny+1,nx+1),0)
dof_coord = V.tabulate_dof_coordinates()
np.save('dof_coord.npy',dof_coord)
np.save('sol_array.npy',sol_array)