Hello,
I know there are few examples of the use of submesh:
- That post: Imposing a discontinuity at interface using DG method - #20 by Quentin but the submesh concerns only the face on the cell.
- that example: Multiphysics: Solving PDEs on subdomains — FEniCS Workshop but there is no coupling between the domains.
So I created a MWE below where DG is used. We solve the scalar advection domain on a 1D domain (so that the solution simply converges towards the inflow value, here 2.5). The mesh is divided into a left domain and a right domain. Lax-Friedrich flux is used (even at the interface between the two domains).
from scifem import BlockedNewtonSolver
import dolfinx
import numpy as np
import pylab as plt
#
import ufl
#
from mpi4py import MPI
from packaging.version import Version
# Mesh
msh = dolfinx.mesh.create_interval(comm=MPI.COMM_WORLD, points=(0.0, 1.0), nx=4)
gdim = msh.geometry.dim
n = ufl.dot(ufl.FacetNormal(msh), ufl.as_vector([1.0]))
# Convective velocity
velocity_norm = 1.0
velocity = ufl.as_vector([velocity_norm])
# Value at inflow
f_inflow = dolfinx.fem.Constant(msh, 2.5)
# Create submeshes (left and right)
LEFT = 1
RIGHT = 2
cells = dolfinx.mesh.locate_entities(msh, gdim, lambda x: np.full_like(x[0], 1, dtype=np.int8))
midpoints = dolfinx.mesh.compute_midpoints(msh, gdim, cells)
marker = np.full(midpoints.shape[0], -1, dtype=np.int32)
marker[(midpoints[:,0] <= 0.5)] = LEFT
marker[(midpoints[:,0] > 0.5)] = RIGHT
assert(np.all(marker!=-1))
cell_tag = dolfinx.mesh.meshtags(msh, gdim, np.arange(midpoints.shape[0], dtype=np.int32), marker)
dx = ufl.Measure("dx", domain=msh, subdomain_data=cell_tag)
left_mesh, left_mesh_cell_map, left_mesh_vertex_map, _ = dolfinx.mesh.create_submesh(msh, gdim, cell_tag.find(LEFT))
right_mesh, right_mesh_cell_map, right_mesh_vertex_map, _ = dolfinx.mesh.create_submesh(msh, gdim, cell_tag.find(RIGHT))
if (Version(dolfinx.__version__) >= Version('0.10')):
left_mesh_cell_map = left_mesh_cell_map.sub_topology_to_topology(np.arange(np.where(cell_tag==LEFT)[0].size), False)
right_mesh_cell_map = right_mesh_cell_map.sub_topology_to_topology(np.arange(np.where(cell_tag==RIGHT)[0].size), False)
parent_to_sub_left = np.full(midpoints.shape[0], -1, dtype=np.int32)
parent_to_sub_left[left_mesh_cell_map] = np.arange(len(left_mesh_cell_map), dtype=np.int32)
parent_to_sub_right = np.full(midpoints.shape[0], -1, dtype=np.int32)
parent_to_sub_right[right_mesh_cell_map] = np.arange(len(right_mesh_cell_map), dtype=np.int32)
entity_maps = {left_mesh: parent_to_sub_left, right_mesh: parent_to_sub_right}
# Defining the function spaces
V_left, V_right = dolfinx.fem.functionspace(left_mesh, ("DG", 1)), dolfinx.fem.functionspace(right_mesh, ("DG", 1))
W = ufl.MixedFunctionSpace(V_left, V_right)
f_left_test, f_right_test = ufl.TestFunctions(W)
f_left_state, f_right_state = dolfinx.fem.Function(V_left), dolfinx.fem.Function(V_right)
# boundary marker
LEFT_BC_MARKER = 1
RIGHT_BC_MARKER = 2
bdry_facets = dolfinx.mesh.locate_entities_boundary(msh, gdim-1, lambda x: np.full_like(x[0], 1, dtype=np.int8))
midpoints = dolfinx.mesh.compute_midpoints(msh, gdim-1, bdry_facets)
bcMarkers = np.full(midpoints.shape[0], -1, dtype='int32')
bcMarkers[(midpoints[:,0] == 0.0)] = LEFT_BC_MARKER
bcMarkers[(midpoints[:,0] == 1.0)] = RIGHT_BC_MARKER
assert(np.where(bcMarkers==LEFT_BC_MARKER)[0].size==1)
fts = dolfinx.mesh.meshtags(msh, gdim-1, bdry_facets, bcMarkers)
ds = ufl.Measure("ds", domain=msh, subdomain_data=fts)
# Inner markers
INTERFACE = 3
inner_facets = dolfinx.mesh.locate_entities(msh, gdim-1, lambda x: np.full_like(x[0], 1, dtype=np.int8))
midpoints = dolfinx.mesh.compute_midpoints(msh, gdim-1, inner_facets)
inner_markers = np.zeros(midpoints.shape[0], dtype='int32')
inner_markers[(midpoints[:,0] < 0.5)] = LEFT
inner_markers[(midpoints[:,0] > 0.5)] = RIGHT
inner_markers[(midpoints[:,0] == 0.5)] = INTERFACE
inner_facet_tags = dolfinx.mesh.meshtags(msh, gdim-1, inner_facets, inner_markers)
dS = ufl.Measure("dS", msh, subdomain_data=inner_facet_tags)
# Create from
def flux_LF(f_int, f_ext, n): # Lax Friedrich flux
return 0.5 * (f_int + f_ext) * velocity_norm * n + 0.5 * velocity_norm * (f_int - f_ext)
F = ufl.inner(-velocity * f_left_state, ufl.grad(f_left_test))*dx(LEFT)\
+ ufl.inner(-velocity * f_right_state, ufl.grad(f_right_test))*dx(RIGHT)
F += ufl.inner(flux_LF(f_left_state('+'), f_left_state('-'), n('+')), f_left_test('+')) * dS(LEFT)
F += ufl.inner(flux_LF(f_left_state('-'), f_left_state('+'), n('-')), f_left_test('-')) * dS(LEFT)
F += ufl.inner(flux_LF(f_right_state('+'), f_right_state('-'), n('+')), f_right_test('+')) * dS(RIGHT)
F += ufl.inner(flux_LF(f_right_state('-'), f_right_state('+'), n('-')), f_right_test('-')) * dS(RIGHT)
F += ufl.inner(flux_LF(f_left_state('+'), f_right_state('-'), n('+')), f_left_test('+')) * dS(INTERFACE)
F += ufl.inner(flux_LF(f_right_test('+'), f_left_state('-'), n('-')), f_right_test('+')) * dS(INTERFACE)
F += ufl.inner(flux_LF(f_left_state, f_inflow, n), f_left_test) * ds(LEFT_BC_MARKER)
F += ufl.inner(flux_LF(f_right_state, dolfinx.fem.Constant(msh, 0.0) , n), f_right_test) * ds(RIGHT_BC_MARKER) # dummy ext value (not used)
F_block = dolfinx.fem.form(ufl.extract_blocks(F), entity_maps=entity_maps)
J_block = dolfinx.fem.form(ufl.extract_blocks(ufl.derivative(F, [f_left_state, f_right_state], ufl.TrialFunctions(W))), entity_maps=entity_maps)
petsc_options = {"ksp_type": "preonly", "pc_type": "lu", "pc_factor_mat_solver_type": "mumps"}
solver = BlockedNewtonSolver(F_block, [f_left_state, f_right_state], J=J_block, petsc_options=petsc_options)
solver.solve()
coords = V_left.tabulate_dof_coordinates()
ids = np.argsort(coords[:,0])
plt.plot(coords[ids,0], f_left_state.x.array[ids], 'b')
coords = V_right.tabulate_dof_coordinates()
ids = np.argsort(coords[:,0])
plt.plot(coords[ids,0], f_right_state.x.array[ids], 'r')
plt.show()
Unfortunately this script fails (dolfinx v0.9) with the error:
Traceback (most recent call last):
File “/stck/fpascal/Python/Code/FENICS/Generic/advection_1D_submesh.py”, line 99, in
F_block = dolfinx.fem.form(ufl.extract_blocks(F), entity_maps=entity_maps)
File “/tmp_user/juno/fpascal/Softwares/FE_libraries/dolfinx/Dist/real/lib/python3.10/site-packages/dolfinx/fem/forms.py”, line 337, in form
return _create_form(form)
File “/tmp_user/juno/fpascal/Softwares/FE_libraries/dolfinx/Dist/real/lib/python3.10/site-packages/dolfinx/fem/forms.py”, line 333, in _create_form
return list(map(lambda sub_form: _create_form(sub_form), form))
File “/tmp_user/juno/fpascal/Softwares/FE_libraries/dolfinx/Dist/real/lib/python3.10/site-packages/dolfinx/fem/forms.py”, line 333, in
return list(map(lambda sub_form: _create_form(sub_form), form))
File “/tmp_user/juno/fpascal/Softwares/FE_libraries/dolfinx/Dist/real/lib/python3.10/site-packages/dolfinx/fem/forms.py”, line 331, in _create_form
return _form(form)
File “/tmp_user/juno/fpascal/Softwares/FE_libraries/dolfinx/Dist/real/lib/python3.10/site-packages/dolfinx/fem/forms.py”, line 254, in _form
ufcx_form, module, code = jit.ffcx_jit(
File “/tmp_user/juno/fpascal/Softwares/FE_libraries/dolfinx/Dist/real/lib/python3.10/site-packages/dolfinx/jit.py”, line 62, in mpi_jit
return local_jit(*args, **kwargs)
File “/tmp_user/juno/fpascal/Softwares/FE_libraries/dolfinx/Dist/real/lib/python3.10/site-packages/dolfinx/jit.py”, line 212, in ffcx_jit
r = ffcx.codegeneration.jit.compile_forms([ufl_object], options=p_ffcx, **p_jit)
File “/tmp_user/juno/fpascal/Softwares/FE_libraries/dolfinx/Dist/real/lib/python3.10/site-packages/ffcx/codegeneration/jit.py”, line 225, in compile_forms
raise e
File “/tmp_user/juno/fpascal/Softwares/FE_libraries/dolfinx/Dist/real/lib/python3.10/site-packages/ffcx/codegeneration/jit.py”, line 205, in compile_forms
impl = _compile_objects(
File “/tmp_user/juno/fpascal/Softwares/FE_libraries/dolfinx/Dist/real/lib/python3.10/site-packages/ffcx/codegeneration/jit.py”, line 330, in _compile_objects
_, code_body = ffcx.compiler.compile_ufl_objects(
File “/tmp_user/juno/fpascal/Softwares/FE_libraries/dolfinx/Dist/real/lib/python3.10/site-packages/ffcx/compiler.py”, line 108, in compile_ufl_objects
analysis = analyze_ufl_objects(ufl_objects, options[“scalar_type”]) # type: ignore
File “/tmp_user/juno/fpascal/Softwares/FE_libraries/dolfinx/Dist/real/lib/python3.10/site-packages/ffcx/analysis.py”, line 94, in analyze_ufl_objects
form_data = tuple(_analyze_form(form, scalar_type) for form in forms)
File “/tmp_user/juno/fpascal/Softwares/FE_libraries/dolfinx/Dist/real/lib/python3.10/site-packages/ffcx/analysis.py”, line 94, in
form_data = tuple(_analyze_form(form, scalar_type) for form in forms)
File “/tmp_user/juno/fpascal/Softwares/FE_libraries/dolfinx/Dist/real/lib/python3.10/site-packages/ffcx/analysis.py”, line 180, in _analyze_form
form_data = ufl.algorithms.compute_form_data(
File “/tmp_user/juno/fpascal/Softwares/FE_libraries/dolfinx/Dist/real/lib/python3.10/site-packages/ufl/algorithms/compute_form_data.py”, line 427, in compute_form_data
check_form_arity(preprocessed_form, self.original_form.arguments(), complex_mode)
File “/tmp_user/juno/fpascal/Softwares/FE_libraries/dolfinx/Dist/real/lib/python3.10/site-packages/ufl/algorithms/check_arities.py”, line 213, in check_form_arity
check_integrand_arity(itg.integrand(), arguments, complex_mode)
File “/tmp_user/juno/fpascal/Softwares/FE_libraries/dolfinx/Dist/real/lib/python3.10/site-packages/ufl/algorithms/check_arities.py”, line 194, in check_integrand_arity
arg_tuples = map_expr_dag(rules, expr, compress=False)
File “/tmp_user/juno/fpascal/Softwares/FE_libraries/dolfinx/Dist/real/lib/python3.10/site-packages/ufl/corealg/map_dag.py”, line 35, in map_expr_dag
(result,) = map_expr_dags(
File “/tmp_user/juno/fpascal/Softwares/FE_libraries/dolfinx/Dist/real/lib/python3.10/site-packages/ufl/corealg/map_dag.py”, line 103, in map_expr_dags
r = handlers[v.ufl_typecode](v, *[vcache[u] for u in v.ufl_operands])
File “/tmp_user/juno/fpascal/Softwares/FE_libraries/dolfinx/Dist/real/lib/python3.10/site-packages/ufl/algorithms/check_arities.py”, line 60, in sum
f"Adding expressions with non-matching form arguments {_afmt(a)} vs {_afmt(b)}."
File “/tmp_user/juno/fpascal/Softwares/FE_libraries/dolfinx/Dist/real/lib/python3.10/site-packages/ufl/algorithms/check_arities.py”, line 20, in _afmt
arg, conj = atuple
ValueError: not enough values to unpack (expected 2, got 1)
If I comment the part with dS(INTERFACE) the error becomes:
Traceback (most recent call last):
File "/stck/fpascal/Python/Code/FENICS/Generic/advection_1D_submesh.py", line 103, in <module>
solver.solve()
File "/tmp_user/juno/fpascal/Softwares/FE_libraries/dolfinx/Dist/real/lib/python3.10/site-packages/scifem/solvers.py", line 437, in solve
n, converged = super().solve(self._x)
RuntimeError: Failed to successfully call PETSc function 'KSPSolve'. PETSc error code is: 76, Error in external library
If in addition I comment the ds part the script runs fine (but obviously a wrong solution is obtained).
So I guess I’m not far from having a working script, could you please help to me to correct what is wrong here?
Lucas