-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathsimulation_series.py
More file actions
153 lines (123 loc) · 4.99 KB
/
simulation_series.py
File metadata and controls
153 lines (123 loc) · 4.99 KB
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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
import os
from ast import Interactive
from fenics import *
from dolfin import *
# from mshr import *
import matplotlib.pyplot as plt
from utils import *
# Define symmetric gradient
def epsilon(u):
return sym(nabla_grad(u))
# Define stress tensor
def sigma(u, p):
return 2*mu*epsilon(u) - p*Identity(len(u))
def solve_geometry_domain(mesh_file_name, directory, save_file_dir, inflow_profile, num_steps, dt, mu, rho):
'''
Solves target geometry domain with FEniCS.
mesh_file_name: the prefix of mesh file, for 'cylinder.xdmf' simply input 'cylinder'. DO NOT INCLUDE directory here.
directory: dir to mesh file
save_file_dir: dir to output file. Output would be stored by nodal values in 'velocity_series' and 'pressure_series' separately.
inflow_profile: inflow profile defined in FEniCS format, or a string defining the inflow function, e.g. '4.0*1.5*x[1]*(10 - x[1]) / 100'
'''
mesh, mf_boundaries, association_table = import_mesh(prefix=mesh_file_name, subdomains=False, directory=directory)
inflow_id = association_table['inflow']
outflow_id = association_table['outflow']
walls_id = association_table['walls']
cylinder_id = association_table['circle']
# Define function spaces
V = VectorFunctionSpace(mesh, 'P', 2)
Q = FunctionSpace(mesh, 'P', 1)
# Define inflow profile
inflow_profile = inflow_profile
# Define boundary conditions
bcu_inflow = DirichletBC(V, Expression(inflow_profile, degree=2), mf_boundaries, inflow_id)
# bcu_inflow = DirichletBC(V, Expression(inflow_profile, degree=2), df_inflow)
bcu_walls = DirichletBC(V, Constant((0, 0)), mf_boundaries, walls_id)
bcu_cylinder = DirichletBC(V, Constant((0, 0)), mf_boundaries, cylinder_id)
bcp_outflow = DirichletBC(Q, Constant(0), mf_boundaries, outflow_id)
bcu = [bcu_inflow, bcu_walls, bcu_cylinder]
bcp = [bcp_outflow]
# Define trial and test functions
u = TrialFunction(V)
v = TestFunction(V)
p = TrialFunction(Q)
q = TestFunction(Q)
# Define functions for solutions at previous and current time steps
u_n = Function(V)
u_ = Function(V)
p_n = Function(Q)
p_ = Function(Q)
# Define expressions used in variational forms
U = 0.5*(u_n + u)
n = FacetNormal(mesh)
f = Constant((0, 0))
k = Constant(dt)
mu = Constant(mu)
rho = Constant(rho)
# Define variational problem for step 1
F1 = rho*dot((u - u_n) / k, v)*dx \
+ rho*dot(dot(u_n, nabla_grad(u_n)), v)*dx \
+ inner(sigma(U, p_n), epsilon(v))*dx \
+ dot(p_n*n, v)*ds - dot(mu*nabla_grad(U)*n, v)*ds \
- dot(f, v)*dx
a1 = lhs(F1)
L1 = rhs(F1)
# Define variational problem for step 2
a2 = dot(nabla_grad(p), nabla_grad(q))*dx
L2 = dot(nabla_grad(p_n), nabla_grad(q))*dx - (1/k)*div(u_)*q*dx
# Define variational problem for step 3
a3 = dot(u, v)*dx
L3 = dot(u_, v)*dx - k*dot(nabla_grad(p_ - p_n), v)*dx
# Assemble matrices
A1 = assemble(a1)
A2 = assemble(a2)
A3 = assemble(a3)
# Apply boundary conditions to matrices
[bc.apply(A1) for bc in bcu]
[bc.apply(A2) for bc in bcp]
# Create time series (for use in reaction_system.py)
timeseries_u = TimeSeries(os.path.join(save_file_dir, 'velocity_series'))
timeseries_p = TimeSeries(os.path.join(save_file_dir, 'pressure_series'))
# Create progress bar
progress = Progress('Time-stepping')
# set_log_level(PROGRESS)
# Time-stepping
t = 0
for n in range(num_steps):
# Update current time
t += dt
# Step 1: Tentative velocity step
b1 = assemble(L1)
[bc.apply(b1) for bc in bcu]
solve(A1, u_.vector(), b1, 'bicgstab', 'hypre_amg')
# Step 2: Pressure correction step
b2 = assemble(L2)
[bc.apply(b2) for bc in bcp]
solve(A2, p_.vector(), b2, 'bicgstab', 'hypre_amg')
# Step 3: Velocity correction step
b3 = assemble(L3)
solve(A3, u_.vector(), b3, 'cg', 'sor')
# Save nodal values to file
timeseries_u.store(u_.vector(), t)
timeseries_p.store(p_.vector(), t)
# Update previous solution
u_n.assign(u_)
p_n.assign(p_)
# Update progress bar
# progress.update(t / T)
print('u max:', u_.vector().get_local().max())
if __name__ == "__main__":
T = 10 # final time
num_steps = 8000 # number of time steps
dt = T / num_steps # time step size
mu = 0.001 # dynamic viscosity
rho = 1 # density
directory = 'io_operations/data221120/'
inflow_profile = ('4.0*1.5*x[1]*(10 - x[1]) / 100', '0')
for i in range(2, 3):
mesh_file_name = 'circle_{}'.format(i)
mesh_directory = os.path.join(directory, 'has')
save_file_dir = 'navier_stokes_cylinder/sol221111_{}_has'.format(i)
if not os.path.exists(save_file_dir):
os.makedirs(save_file_dir)
solve_geometry_domain(mesh_file_name, mesh_directory, save_file_dir, inflow_profile, num_steps, dt, mu, rho)