-
Notifications
You must be signed in to change notification settings - Fork 52
/
fenics.py
92 lines (77 loc) · 3.05 KB
/
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
"""Solve nonlinear corrections to Darcy flow
"""
import dolfin as df
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.ticker as ticker
import sys
import os
from time import time
def solve_nonlinear_poisson(input, alpha1, alpha2, save_dir):
if not os.path.exists(save_dir):
os.makedirs(save_dir)
perm = input
flux_order = 3
ngy, ngx = perm.shape[0], perm.shape[1]
# Create mesh and define function space
mesh = df.UnitSquareMesh(ngy-1, ngx-1)
K_CG = df.FunctionSpace(mesh, "Lagrange", 1)
K = df.Function(K_CG)
ordering = df.dof_to_vertex_map(K_CG)
K.vector()[:] = perm.flatten(order='C')[ordering]
def boundary(x, on_boundary):
return x[0] < df.DOLFIN_EPS or x[0] > 1.0 - df.DOLFIN_EPS
left = df.CompiledSubDomain("near(x[0], 0.0) && on_boundary")
right = df.CompiledSubDomain("near(x[0], 1.0) && on_boundary")
top = df.CompiledSubDomain("near(x[1], 1.0) && on_boundary")
bottom = df.CompiledSubDomain("near(x[1], 0.0) && on_boundary")
boundaries = df.MeshFunction("size_t", mesh, mesh.topology().dim() - 1, 0)
# boundaries.set_all(0)
left.mark(boundaries, 1)
top.mark(boundaries, 2)
right.mark(boundaries, 3)
bottom.mark(boundaries, 4)
ds = df.Measure("ds", domain=mesh, subdomain_data=boundaries)
# Discontinuous Raviart-Thomas
DRT = df.FiniteElement("DRT", mesh.ufl_cell(), flux_order)
# Lagrange
CG = df.FiniteElement("CG", mesh.ufl_cell(), flux_order + 1)
W = df.FunctionSpace(mesh, DRT * CG)
ww = df.Function(W)
sigma, u = df.split(ww)
tau, v = df.TestFunctions(W)
dw = df.TrialFunction(W)
# Define boundary condition
gamma = df.Expression("1.0 - x[0]", degree=1)
bc = df.DirichletBC(W.sub(1), gamma, boundary)
g = df.Constant(0.0)
f = df.Constant(0.0)
def flux(sigma):
s1 = sigma[0]
s2 = sigma[1]
nonlinear1 = alpha1 * df.sqrt(K) * df.as_vector([s1 ** 2, s2 ** 2])
nonlinear2 = alpha2 * K * df.as_vector([s1 ** 3, s2 ** 3])
nonlinear = nonlinear1 + nonlinear2
return nonlinear
F = (df.dot(sigma, tau) + df.dot(K * df.grad(u), tau) + df.dot(flux(sigma), tau)\
+ df.dot(sigma, df.grad(v)) + f * v) * df.dx + g * v * ds(2) + g * v * ds(4)
J = df.derivative(F, ww, dw)
# Compute solution
problem = df.NonlinearVariationalProblem(F, ww, bc, J)
solver = df.NonlinearVariationalSolver(problem)
prm = solver.parameters
prm['newton_solver']['absolute_tolerance'] = 1E-8
prm['newton_solver']['relative_tolerance'] = 1E-6
prm['newton_solver']['maximum_iterations'] = 10
prm['newton_solver']['relaxation_parameter'] = 1.0
tic = time()
solver.solve()
print(f'time taken {time()-tic} seconds')
(sigma_, u_) = ww.split()
u_mat = u_.compute_vertex_values(mesh).reshape(64, 64)
grad_u = sigma_.compute_vertex_values(mesh)
sigma1 = grad_u[:4096].reshape(64, 64)
sigma2 = grad_u[4096:].reshape(64, 64)
output = np.stack((u_mat, sigma1, sigma2))
print('output shape: {output.shape}')
return output