33"""
44
55from __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
1011import numpy as np
1112
1213
@@ -59,27 +60,21 @@ def inside(self, x, on_boundary):
5960 return False
6061
6162
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
6968 :param k: thermal conductivity
70- :return: fluxes function
69+ :param flux: returns calculated flux into this value
7170 """
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 )
8378
8479
8580# Create mesh and define function space
@@ -88,7 +83,7 @@ def fluxes_from_temperature_full_domain(f, v_vec, k):
8883nz = 1
8984
9085fenics_dt = 0.01 # time step size
91- dt_out = 0.2
86+ dt_out = 0.2 # interval for writing VTK files
9287y_top = 0
9388y_bottom = y_top - .25
9489x_left = 0
@@ -99,16 +94,16 @@ def fluxes_from_temperature_full_domain(f, v_vec, k):
9994
10095mesh = RectangleMesh (p0 , p1 , nx , ny )
10196V = FunctionSpace (mesh , 'P' , 1 )
97+ V_g = VectorFunctionSpace (mesh , 'P' , 1 )
10298
10399alpha = 1 # m^2/s, https://en.wikipedia.org/wiki/Thermal_diffusivity
104100k = 100 # kg * m / s^3 / K, https://en.wikipedia.org/wiki/Thermal_conductivity
105101
106102# Define boundary condition
107103u_D = Constant ('310' )
108104u_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 )
112107
113108coupling_boundary = TopBoundary ()
114109bottom_boundary = BottomBoundary ()
@@ -120,7 +115,7 @@ def fluxes_from_temperature_full_domain(f, v_vec, k):
120115# Adapter definition and initialization
121116precice = Adapter (adapter_config_filename = "precice-adapter-config.json" )
122117
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 )
124119
125120# Create a FEniCS Expression to define and control the coupling boundary values
126121coupling_expression = precice .create_coupling_expression ()
@@ -142,13 +137,26 @@ def fluxes_from_temperature_full_domain(f, v_vec, k):
142137
143138# Time-stepping
144139u_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
146140t = 0
147141u_D .t = t + dt
148142
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
149151file_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 )))
150155n = 0
151156
157+ fluxes = Function (V_g )
158+ fluxes .rename ("Fluxes" , "" )
159+
152160while precice .is_coupling_ongoing ():
153161
154162 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):
165173 solve (a == L , u_np1 , bcs )
166174
167175 # 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 )
170179
171180 precice_dt = precice .advance (dt (0 ))
172181
@@ -177,17 +186,17 @@ def fluxes_from_temperature_full_domain(f, v_vec, k):
177186 n = n_cp
178187 else : # update solution
179188 u_n .assign (u_np1 )
180- t += dt
189+ t += float ( dt )
181190 n += 1
182191
183192 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 )))
185196 file_out << u_n
186197
187198 # Update dirichlet BC
188- u_D .t = t + dt (0 )
189-
190- file_out << u_n
199+ u_D .t = t + float (dt )
191200
192201# Hold plot
193202precice .finalize ()
0 commit comments