3
3
"""
4
4
5
5
from __future__ import print_function , division
6
- from fenics import Function , SubDomain , RectangleMesh , BoxMesh , FunctionSpace , Point , Expression , Constant , DirichletBC , \
7
- TrialFunction , TestFunction , File , solve , plot , lhs , rhs , grad , inner , dot , dx , ds , assemble , interpolate , project , \
8
- near
9
- from fenicsadapter import Adapter
6
+ from fenics import Function , SubDomain , RectangleMesh , BoxMesh , FunctionSpace , VectorFunctionSpace , Point , \
7
+ Expression , Constant , DirichletBC , \
8
+ TrialFunction , TestFunction , File , solve , plot , lhs , rhs , grad , inner , dot , dx , ds , interpolate , project , \
9
+ near , MeshFunction , MPI
10
+ from fenicsprecice import Adapter
10
11
import numpy as np
11
12
12
13
@@ -59,27 +60,21 @@ def inside(self, x, on_boundary):
59
60
return False
60
61
61
62
62
- def fluxes_from_temperature_full_domain (f , v_vec , k ):
63
- """Computes flux from weak form (see p.3 in Toselli, Andrea, and Olof
64
- Widlund. Domain decomposition methods-algorithms and theory. Vol. 34.
65
- Springer Science & Business Media, 2006.).
66
-
67
- :param f: weak form with known u^{n+1}
68
- :param v_vec: vector function space
63
+ def determine_heat_flux (V_g , u , k , flux ):
64
+ """
65
+ compute flux following http://hplgit.github.io/INF5620/doc/pub/fenics_tutorial1.1/tu2.html#tut-poisson-gradu
66
+ :param V_g: Vector function space
67
+ :param u: solution where gradient is to be determined
69
68
:param k: thermal conductivity
70
- :return: fluxes function
69
+ :param flux: returns calculated flux into this value
71
70
"""
72
- fluxes_vector = assemble (f ) # assemble weak form -> evaluate integral
73
- v = TestFunction (v_vec )
74
- fluxes = Function (v_vec ) # create function for flux
75
- area = assemble (v * ds ).get_local ()
76
- for i in range (area .shape [0 ]):
77
- if area [i ] != 0 : # put weight from assemble on function
78
- fluxes .vector ()[i ] = - k * fluxes_vector [i ] / area [i ] # scale by surface area
79
- else :
80
- assert (abs (fluxes_vector [i ]) < 1E-9 ) # for non surface parts, we expect zero flux
81
- fluxes .vector ()[i ] = - k * fluxes_vector [i ]
82
- return fluxes
71
+
72
+ w = TrialFunction (V_g )
73
+ v = TestFunction (V_g )
74
+
75
+ a = inner (w , v ) * dx
76
+ L = inner (- k * grad (u ), v ) * dx
77
+ solve (a == L , flux )
83
78
84
79
85
80
# Create mesh and define function space
@@ -88,7 +83,7 @@ def fluxes_from_temperature_full_domain(f, v_vec, k):
88
83
nz = 1
89
84
90
85
fenics_dt = 0.01 # time step size
91
- dt_out = 0.2
86
+ dt_out = 0.2 # interval for writing VTK files
92
87
y_top = 0
93
88
y_bottom = y_top - .25
94
89
x_left = 0
@@ -99,16 +94,16 @@ def fluxes_from_temperature_full_domain(f, v_vec, k):
99
94
100
95
mesh = RectangleMesh (p0 , p1 , nx , ny )
101
96
V = FunctionSpace (mesh , 'P' , 1 )
97
+ V_g = VectorFunctionSpace (mesh , 'P' , 1 )
102
98
103
99
alpha = 1 # m^2/s, https://en.wikipedia.org/wiki/Thermal_diffusivity
104
100
k = 100 # kg * m / s^3 / K, https://en.wikipedia.org/wiki/Thermal_conductivity
105
101
106
102
# Define boundary condition
107
103
u_D = Constant ('310' )
108
104
u_D_function = interpolate (u_D , V )
109
- # Define flux in x direction on coupling interface (grad(u_D) in normal direction)
110
- f_N = Constant ('0' )
111
- f_N_function = interpolate (f_N , V )
105
+ # We will only exchange flux in y direction on coupling interface. No initialization necessary.
106
+ V_flux_y = V_g .sub (1 )
112
107
113
108
coupling_boundary = TopBoundary ()
114
109
bottom_boundary = BottomBoundary ()
@@ -120,7 +115,7 @@ def fluxes_from_temperature_full_domain(f, v_vec, k):
120
115
# Adapter definition and initialization
121
116
precice = Adapter (adapter_config_filename = "precice-adapter-config.json" )
122
117
123
- precice_dt = precice .initialize (coupling_boundary , mesh , V )
118
+ precice_dt = precice .initialize (coupling_boundary , read_function_space = V , write_object = V_flux_y )
124
119
125
120
# Create a FEniCS Expression to define and control the coupling boundary values
126
121
coupling_expression = precice .create_coupling_expression ()
@@ -142,13 +137,26 @@ def fluxes_from_temperature_full_domain(f, v_vec, k):
142
137
143
138
# Time-stepping
144
139
u_np1 = Function (V )
145
- F_known_u = u_np1 * v / dt * dx + alpha * dot (grad (u_np1 ), grad (v )) * dx - u_n * v / dt * dx
146
140
t = 0
147
141
u_D .t = t + dt
148
142
143
+ # mark mesh w.r.t ranks
144
+ ranks = File ("Solid/VTK/ranks%s.pvd.pvd" % precice .get_participant_name ())
145
+ mesh_rank = MeshFunction ("size_t" , mesh , mesh .topology ().dim ())
146
+ mesh_rank .set_all (MPI .rank (MPI .comm_world ))
147
+ mesh_rank .rename ("myRank" , "" )
148
+ ranks << mesh_rank
149
+
150
+ # Create output file
149
151
file_out = File ("Solid/VTK/%s.pvd" % precice .get_participant_name ())
152
+ file_out << u_n
153
+
154
+ print ("output vtk for time = {}" .format (float (t )))
150
155
n = 0
151
156
157
+ fluxes = Function (V_g )
158
+ fluxes .rename ("Fluxes" , "" )
159
+
152
160
while precice .is_coupling_ongoing ():
153
161
154
162
if precice .is_action_required (precice .action_write_iteration_checkpoint ()): # write checkpoint
@@ -165,8 +173,9 @@ def fluxes_from_temperature_full_domain(f, v_vec, k):
165
173
solve (a == L , u_np1 , bcs )
166
174
167
175
# Dirichlet problem obtains flux from solution and sends flux on boundary to Neumann problem
168
- fluxes = fluxes_from_temperature_full_domain (F_known_u , V , k )
169
- precice .write_data (fluxes )
176
+ determine_heat_flux (V_g , u_np1 , k , fluxes )
177
+ fluxes_y = fluxes .sub (1 ) # only exchange y component of flux.
178
+ precice .write_data (fluxes_y )
170
179
171
180
precice_dt = precice .advance (dt (0 ))
172
181
@@ -177,17 +186,17 @@ def fluxes_from_temperature_full_domain(f, v_vec, k):
177
186
n = n_cp
178
187
else : # update solution
179
188
u_n .assign (u_np1 )
180
- t += dt
189
+ t += float ( dt )
181
190
n += 1
182
191
183
192
if precice .is_time_window_complete ():
184
- # if abs(t % dt_out) < 10e-5: # output if t is a multiple of dt_out
193
+ tol = 10e-5 # we need some tolerance, since otherwise output might be skipped.
194
+ if abs ((t + tol ) % dt_out ) < 2 * tol : # output if t is a multiple of dt_out
195
+ print ("output vtk for time = {}" .format (float (t )))
185
196
file_out << u_n
186
197
187
198
# Update dirichlet BC
188
- u_D .t = t + dt (0 )
189
-
190
- file_out << u_n
199
+ u_D .t = t + float (dt )
191
200
192
201
# Hold plot
193
202
precice .finalize ()
0 commit comments