Skip to content

Commit c0e15d7

Browse files
Merge branch 'develop' into systemtests/add-nearest-projection-case-clean
2 parents e4eca61 + 11f444c commit c0e15d7

File tree

108 files changed

+3952
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

108 files changed

+3952
-0
lines changed

changelog-entries/660.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
- Added a new Partitioned Water Hammer tutorial including 1D–3D, 3D–1D, 1D–1D, and 3D–3D coupling configurations using OpenFOAM and Nutils [#660](https://github.com/precice/tutorials/pull/660)

changelog-entries/677.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
- Added a new Partitioned Pipe Multiscale tutorial including 1D–3D, 3D–1D, 1D–1D, and 3D–3D coupling configurations using OpenFOAM and Nutils [#677](https://github.com/precice/tutorials/pull/677)

changelog-entries/688.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
- Added FEniCSx-based solver for the flow over heated plate tutorial following the [FEniCS solver](https://github.com/precice/tutorials/tree/develop/flow-over-heated-plate/solid-fenics)

flow-over-heated-plate/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ Solid participant:
4141

4242
* FEniCS. For more information, have a look at the [FeniCS adapter documentation](https://precice.org/adapter-fenics.html).
4343

44+
* FEniCSx. For more information, have a look at the [FeniCSx adapter documentation](https://precice.org/adapter-fenicsx.html).
45+
4446
* Nutils. For more information, have a look at the [Nutils adapter documentation](https://precice.org/adapter-nutils.html).
4547

4648
* Dune-Fem. For more information, have a look at the [official documentation of Dune-Fem](https://www.dune-project.org/sphinx/dune-fem/). The `run.sh` script installs the solver from [PyPI](https://pypi.org/project/dune-fem/) into a Python virtual environment. Please note that Dune-Fem uses just-in-time compilation: The first time you run the solver script, it will take some time.
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#!/bin/sh
2+
set -e -u
3+
4+
. ../../tools/cleaning-tools.sh
5+
6+
clean_fenicsx .
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"participant_name": "Solid",
3+
"precice_config_file_path": "../precice-config.xml",
4+
"interfaces": [
5+
{
6+
"mesh_name": "Solid-Mesh",
7+
"write_data": [
8+
{
9+
"name": "Heat-Flux"
10+
}
11+
],
12+
"read_data": [
13+
{
14+
"name": "Temperature"
15+
}
16+
]
17+
}
18+
]
19+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
numpy
2+
fenicsxprecice
3+
mpi4py>=3
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#!/bin/sh
2+
set -e -u
3+
4+
python3 -m venv --system-site-packages .venv
5+
. .venv/bin/activate
6+
pip install -r requirements.txt
7+
8+
python3 solid.py
Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
import numpy as np
2+
from mpi4py import MPI
3+
import basix.ufl
4+
from petsc4py import PETSc
5+
import ufl
6+
from dolfinx import fem, io, mesh as msh, default_scalar_type
7+
from dolfinx.fem.petsc import assemble_matrix, assemble_vector, apply_lifting, create_vector, set_bc, LinearProblem
8+
from dolfinx.mesh import create_rectangle
9+
import basix
10+
from fenicsxprecice import Adapter, CouplingMesh
11+
12+
13+
# geometry
14+
nx = 100
15+
ny = 25
16+
nz = 1
17+
18+
y_top = 0
19+
y_bottom = y_top - .25
20+
x_left = 0
21+
x_right = x_left + 1
22+
23+
fenics_dt = 0.01 # time step size
24+
25+
26+
def top_boundary(x):
27+
tol = 1E-14
28+
return np.isclose(x[1], y_top, tol)
29+
30+
31+
def bottom_boundary(x):
32+
tol = 1E-14
33+
return np.isclose(x[1], y_bottom, tol)
34+
35+
36+
class initial_value():
37+
def __init__(self, constant):
38+
self.constant = constant
39+
40+
def __call__(self, x):
41+
return np.full(x[0].shape, self.constant)
42+
43+
44+
class GradientSolver:
45+
"""
46+
compute flux following http://hplgit.github.io/INF5620/doc/pub/fenics_tutorial1.1/tu2.html#tut-poisson-gradu
47+
The solver has been changed since the original version from the link above introduces larger errors
48+
49+
:param V_g: Vector function space
50+
:param u: solution where gradient is to be determined
51+
"""
52+
53+
def __init__(self, domain, V_g):
54+
self.domain = domain,
55+
self.V_g = V_g
56+
57+
w = ufl.TrialFunction(V_g)
58+
self.v = ufl.TestFunction(V_g)
59+
a = fem.form(ufl.inner(w, self.v) * ufl.dx)
60+
self.A = assemble_matrix(a)
61+
self.A.assemble()
62+
63+
self.solver = PETSc.KSP().create(domain.comm)
64+
self.solver.setOperators(self.A)
65+
self.solver.setType(PETSc.KSP.Type.PREONLY)
66+
self.solver.getPC().setType(PETSc.PC.Type.LU)
67+
68+
self.returnValue = fem.Function(V_g)
69+
70+
def compute(self, u, k):
71+
L = fem.form(ufl.inner(-k * ufl.grad(u), self.v) * ufl.dx)
72+
b = create_vector(fem.extract_function_spaces(L))
73+
assemble_vector(b, L)
74+
b.ghostUpdate(addv=PETSc.InsertMode.ADD_VALUES, mode=PETSc.ScatterMode.REVERSE)
75+
self.solver.solve(b, self.returnValue.x.petsc_vec)
76+
return self.returnValue
77+
78+
79+
p0 = (x_left, y_bottom)
80+
p1 = (x_right, y_top)
81+
82+
mesh = create_rectangle(MPI.COMM_WORLD, [np.asarray(p0), np.asarray(p1)], [nx, ny], msh.CellType.triangle)
83+
V = fem.functionspace(mesh, ('P', 2))
84+
# for the vector function space
85+
element = basix.ufl.element("Lagrange", mesh.topology.cell_name(), 1, shape=(mesh.geometry.dim,))
86+
V_g = fem.functionspace(mesh, element)
87+
W, map_to_W = V_g.sub(1).collapse()
88+
89+
gradient_solver = GradientSolver(mesh, V_g)
90+
91+
alpha = 1 # m^2/s, https://en.wikipedia.org/wiki/Thermal_diffusivity
92+
k = 100 # kg * m / s^3 / K, https://en.wikipedia.org/wiki/Thermal_conductivity
93+
94+
# We will only exchange flux in y direction on coupling interface. No initialization necessary.
95+
flux_y = fem.Function(W)
96+
97+
# Define initial value
98+
u_n = fem.Function(V)
99+
u_n.name = "T"
100+
u_n.interpolate(initial_value(310))
101+
102+
tdim = mesh.topology.dim
103+
fdim = tdim - 1
104+
mesh.topology.create_connectivity(fdim, tdim)
105+
dofs_coupling = fem.locate_dofs_geometrical(V, top_boundary)
106+
dofs_bottom = fem.locate_dofs_geometrical(V, bottom_boundary)
107+
108+
# Adapter definition and initialization
109+
precice = Adapter(adapter_config_filename="precice-adapter-config.json", mpi_comm=MPI.COMM_WORLD)
110+
111+
# top_boundary is coupling boundary
112+
coupling_mesh = CouplingMesh("Solid-Mesh", top_boundary, {"Temperature": V}, {"Heat-Flux": flux_y})
113+
precice.initialize([coupling_mesh])
114+
115+
# boundary function for the coupling interface
116+
coupling_function = fem.Function(V)
117+
118+
# Assigning appropriate dt
119+
precice_dt = precice.get_max_time_step_size()
120+
dt = np.min([fenics_dt, precice_dt])
121+
122+
# Define variational problem
123+
u = ufl.TrialFunction(V)
124+
v = ufl.TestFunction(V)
125+
F = u * v / dt * ufl.dx + alpha * ufl.dot(ufl.grad(u), ufl.grad(v)) * ufl.dx - u_n * v / dt * ufl.dx
126+
127+
# apply constant Dirichlet boundary condition at bottom edge
128+
# apply Dirichlet boundary condition on coupling interface
129+
bcs = [fem.dirichletbc(coupling_function, dofs_coupling), fem.dirichletbc(default_scalar_type(310), dofs_bottom, V)]
130+
131+
a = fem.form(ufl.lhs(F))
132+
L = fem.form(ufl.rhs(F))
133+
134+
A = assemble_matrix(a, bcs=bcs)
135+
A.assemble()
136+
b = create_vector(fem.extract_function_spaces(L))
137+
uh = fem.Function(V)
138+
solver = PETSc.KSP().create(mesh.comm)
139+
solver.setOperators(A)
140+
solver.setType(PETSc.KSP.Type.PREONLY)
141+
solver.getPC().setType(PETSc.PC.Type.LU)
142+
143+
144+
# Time-stepping
145+
t = 0
146+
147+
vtxwriter = io.VTXWriter(MPI.COMM_WORLD, f"output_solid.bp", [u_n])
148+
vtxwriter.write(t)
149+
150+
n = 0
151+
152+
flux = fem.Function(V_g)
153+
154+
while precice.is_coupling_ongoing():
155+
156+
if precice.requires_writing_checkpoint():
157+
precice.store_checkpoint(u_n, t, 0)
158+
159+
precice_dt = precice.get_max_time_step_size()
160+
dt = np.min([fenics_dt, precice_dt])
161+
precice.read_data(coupling_mesh.get_name(), "Temperature", dt, coupling_function)
162+
163+
# Update the right hand side reusing the initial vector
164+
with b.localForm() as loc_b:
165+
loc_b.set(0)
166+
assemble_vector(b, L)
167+
168+
apply_lifting(b, [a], [bcs])
169+
set_bc(b, bcs)
170+
171+
# Solve linear problem
172+
solver.solve(b, uh.x.petsc_vec)
173+
174+
# Dirichlet problem obtains flux from solution and sends flux on boundary to Neumann problem
175+
flux = gradient_solver.compute(u_n, k)
176+
flux_y.interpolate(flux.sub(1))
177+
precice.write_data(coupling_mesh.get_name(), "Heat-Flux", flux_y)
178+
179+
precice.advance(dt)
180+
181+
if precice.requires_reading_checkpoint():
182+
u_cp, t_cp, _ = precice.retrieve_checkpoint()
183+
u_n.x.array[:] = u_cp.x.array
184+
t = t_cp
185+
else: # update solution
186+
# Update solution at previous time step (u_n)
187+
u_n.x.array[:] = uh.x.array
188+
t += float(dt)
189+
n += 1
190+
if n % 20 == 0:
191+
vtxwriter.write(t)
192+
193+
194+
precice.finalize()
195+
vtxwriter.close()

0 commit comments

Comments
 (0)