77import precice
88
99
10- def main (side = 'Dirichlet' , n = 10 , degree = 1 , timestep = .1 , alpha = 3. , beta = 1.2 ):
11-
12- if side == 'Dirichlet' :
13- x_grid = np .linspace (0 , 1 , n )
14- elif side == 'Neumann' :
15- x_grid = np .linspace (1 , 2 , n )
16- else :
17- raise Exception ('invalid side {!r}' .format (side ))
10+ def main (n = 10 , degree = 1 , timestep = .1 , alpha = 3. , beta = 1.2 ):
11+
12+ x_grid = np .linspace (0 , 1 , n )
1813 y_grid = np .linspace (0 , 1 , n )
1914
2015 # define the Nutils mesh
2116 domain , geom = mesh .rectilinear ([x_grid , y_grid ])
22- coupling_boundary = domain .boundary ['right' if side ==
23- 'Dirichlet' else 'left' ]
17+ coupling_boundary = domain .boundary ['right' ]
2418 coupling_sample = coupling_boundary .sample ('gauss' , degree = degree * 2 )
2519
2620 # Nutils namespace
@@ -44,56 +38,51 @@ def main(side='Dirichlet', n=10, degree=1, timestep=.1, alpha=3., beta=1.2):
4438
4539 # set boundary conditions at non-coupling boundaries
4640 # top and bottom boundary are non-coupling for both sides
47- sqr = domain .boundary ['top,bottom,left' if side == 'Dirichlet' else 'top,bottom,right' ].integral (
48- '(u - uexact)^2 d:x' @ ns , degree = degree * 2 )
41+ sqr = domain .boundary ['top,bottom,left' ].integral ('(u - uexact)^2 d:x' @ ns , degree = degree * 2 )
4942
50- if side == 'Dirichlet' :
51- sqr += coupling_sample .integral ('(u - readfunc)^2 d:x' @ ns )
52- else :
53- res += coupling_sample .integral ('basis_n readfunc d:x' @ ns )
43+ sqr += coupling_sample .integral ('(u - readfunc)^2 d:x' @ ns )
5444
5545 # preCICE setup
56- participant = precice .Participant (side , "../precice-config.xml" , 0 , 1 )
57- mesh_name = side + " -Mesh"
46+ participant = precice .Participant ('Dirichlet' , "../precice-config.xml" , 0 , 1 )
47+ mesh_name = "Dirichlet -Mesh"
5848 vertex_ids = participant .set_mesh_vertices (
5949 mesh_name , coupling_sample .eval (ns .x ))
6050 precice_write = functools .partial (
6151 participant .write_data ,
6252 mesh_name ,
63- "Temperature" if side == "Neumann" else " Heat-Flux" ,
53+ "Heat-Flux" ,
6454 vertex_ids )
6555 precice_read = functools .partial (
6656 participant .read_data ,
6757 mesh_name ,
68- "Heat-Flux" if side == "Neumann" else " Temperature" ,
58+ "Temperature" ,
6959 vertex_ids )
7060
7161 # helper functions to project heat flux to coupling boundary
72- if side == 'Dirichlet' :
73- # To communicate the flux to the Neumann side we should not simply
74- # evaluate u_,i n_i as this is an unbounded term leading to suboptimal
75- # convergence. Instead we project ∀ v: ∫_Γ v flux = ∫_Γ v u_,i n_i and
76- # evaluate flux. While the right-hand-side contains the same unbounded
77- # term, we can use the strong identity du/dt - u_,ii = f to rewrite it
78- # to ∫_Ω [v (du/dt - f) + v_,i u_,i] - ∫_∂Ω\Γ v u_,k n_k, in which we
79- # recognize the residual and an integral over the exterior boundary.
80- # While the latter still contains the problematic unbounded term, we
81- # can use the fact that the flux is a known value at the top and bottom
82- # via the Dirichlet boundary condition, and impose it as constraints.
83- rightsqr = domain .boundary ['right' ].integral (
84- 'flux^2 d:x' @ ns , degree = degree * 2 )
85- rightcons = solver .optimize ('fluxdofs' , rightsqr , droptol = 1e-10 )
86- # rightcons is NaN in dofs that are NOT supported on the right boundary
87- fluxsqr = domain .boundary ['right' ].boundary ['top,bottom' ].integral (
88- '(flux - uexact_,0)^2 d:x' @ ns , degree = degree * 2 )
89- fluxcons = solver .optimize ('fluxdofs' ,
90- fluxsqr ,
91- droptol = 1e-10 ,
92- constrain = np .choose (np .isnan (rightcons ),
93- [np .nan ,
94- 0. ]))
95- # fluxcons is NaN in dofs that are supported on ONLY the right boundary
96- fluxres = coupling_sample .integral ('basis_n flux d:x' @ ns ) - res
62+ # To communicate the flux to the Neumann side we should not simply
63+ # evaluate u_,i n_i as this is an unbounded term leading to suboptimal
64+ # convergence. Instead we project ∀ v: ∫_Γ v flux = ∫_Γ v u_,i n_i and
65+ # evaluate flux. While the right-hand-side contains the same unbounded
66+ # term, we can use the strong identity du/dt - u_,ii = f to rewrite it
67+ # to ∫_Ω [v (du/dt - f) + v_,i u_,i] - ∫_∂Ω\Γ v u_,k n_k, in which we
68+ # recognize the residual and an integral over the exterior boundary.
69+ # While the latter still contains the problematic unbounded term, we
70+ # can use the fact that the flux is a known value at the top and bottom
71+ # via the Dirichlet boundary condition, and impose it as constraints.
72+ rightsqr = domain .boundary ['right' ].integral (
73+ 'flux^2 d:x' @ ns , degree = degree * 2 )
74+ rightcons = solver .optimize ('fluxdofs' , rightsqr , droptol = 1e-10 )
75+ # rightcons is NaN in dofs that are NOT supported on the right boundary
76+ fluxsqr = domain .boundary ['right' ].boundary ['top,bottom' ].integral (
77+ '(flux - uexact_,0)^2 d:x' @ ns , degree = degree * 2 )
78+ fluxcons = solver .optimize ('fluxdofs' ,
79+ fluxsqr ,
80+ droptol = 1e-10 ,
81+ constrain = np .choose (np .isnan (rightcons ),
82+ [np .nan ,
83+ 0. ]))
84+ # fluxcons is NaN in dofs that are supported on ONLY the right boundary
85+ fluxres = coupling_sample .integral ('basis_n flux d:x' @ ns ) - res
9786
9887 # write initial data
9988 if participant .requires_initial_data ():
@@ -118,8 +107,7 @@ def main(side='Dirichlet', n=10, degree=1, timestep=.1, alpha=3., beta=1.2):
118107 x , u , uexact = bezier .eval (['x_i' , 'u' , 'uexact' ] @ ns , lhs = lhs , t = t )
119108 with treelog .add (treelog .DataLog ()):
120109 export .vtk (
121- side +
122- "-" +
110+ "Dirichlet-" +
123111 str (istep ),
124112 bezier .tri ,
125113 x ,
@@ -157,14 +145,12 @@ def main(side='Dirichlet', n=10, degree=1, timestep=.1, alpha=3., beta=1.2):
157145 lhs0 = lhs0 , dt = dt , t = t , readdata = readdata ))
158146
159147 # write data to participant
160- if side == 'Dirichlet' :
161- fluxdofs = solver .solve_linear (
162- 'fluxdofs' , fluxres , arguments = dict (
163- lhs0 = lhs0 , lhs = lhs , dt = dt , t = t ), constrain = fluxcons )
164- write_data = coupling_sample .eval (
165- 'flux' @ ns , fluxdofs = fluxdofs )
166- else :
167- write_data = coupling_sample .eval ('u' @ ns , lhs = lhs )
148+ fluxdofs = solver .solve_linear (
149+ 'fluxdofs' , fluxres , arguments = dict (
150+ lhs0 = lhs0 , lhs = lhs , dt = dt , t = t ), constrain = fluxcons )
151+ write_data = coupling_sample .eval (
152+ 'flux' @ ns , fluxdofs = fluxdofs )
153+
168154 precice_write (write_data )
169155
170156 # do the coupling
0 commit comments