Applying boundary control term only on boundary

Hello Everyone

I am rather new to fenics and am trying to solve a problem, where I want to achieve a given heat-distribution (z) within my domain by optimising a boundary-term (g). My problem is that my boundary-term g only appears in the surface-integrals (ds) and in none of the dx. I cheated a bit and put an extra volume-integral with a tiny constant into the bilinear form, which set g (not on boundary) to basically 0 and made the code run. Otherwise the two print() in the end of the code printed “inf inf”.

So I’m wondering what the best way is to solve this problem, without artificially setting the inner g = 0. I have tried to create subdomains and “remove” the inner DoFs of g, but have not gotten it to work yet. Below is the code with the reg_term that works.

I’m using dolfinx & basix 0.10.0. Thank you for your help!

"""
1) Mesh and parameters
"""
domain = mesh.create_rectangle(
    MPI.COMM_WORLD,
    [(0.0, 0.0),
     (2.0, 1.0)],
     [40, 20],
     cell_type=mesh.CellType.triangle,
)

# Parameters
rho = Constant(domain, PETSc.ScalarType(50))
alpha = Constant(domain, PETSc.ScalarType(1e-3))

# Desired Temperature Distribution
x = ufl.SpatialCoordinate(domain)
z = (x[0] - 1) ** 2


"""
2) Mixed functionspace
"""
# Base-element
E = element("Lagrange", domain.basix_cell(), 1)

# Mixed element space for (T, g, phi)
ME = mixed_element([E, E, E])
W = functionspace(domain, ME)

# Unknowns and Testfunctons
T, g, phi = TrialFunctions(W)
t, h, psi = TestFunctions(W)


"""
3) Bilinear & Linear form
"""
a = (
    T * t * dx + inner(grad(t), grad(phi)) * dx + rho * phi * t * ds
    + alpha * g * h * ds - rho * phi * h * ds
    + inner(grad(T), grad(psi)) * dx + rho * psi * (T - g) * ds
)

L = z * t * dx


"""
4) Solve linear problem
"""
reg_term = Constant(domain, PETSc.ScalarType(1e-8))
a += reg_term * g * h * dx

problem = LinearProblem(a, L, petsc_options_prefix="heat_", petsc_options={"ksp_type": "gmres", "pc_type": "ilu"})
uh = problem.solve()


"""
5) Results
"""
V_T, map_T = W.sub(0).collapse()
V_g, map_g = W.sub(1).collapse()

T_function = Function(V_T, name="T")
g_function = Function(V_g, name="g")

T_function.x.array[:] = uh.x.array[map_T]
g_function.x.array[:] = uh.x.array[map_g]

print("uh min/max:", float(np.min(uh.x.array)), float(np.max(uh.x.array)))
print("T min/max:",  float(np.min(T_function.x.array)), float(np.max(T_function.x.array)))

If g is only defined on the boundary, you should use a submesh, similar to what is done in: Coupling PDEs of multiple dimensions — FEniCS Workshop

That makes sense, thank you. So what I have now is:

def boundary(x):
    return np.isclose(x[0], 0) | np.isclose(x[1], 0) | np.isclose(x[0], 2) | np.isclose(x[1], 1)

tdim = domain.topology.dim
fdim = tdim - 1
gdim = domain.geometry.dim

facets = locate_entities_boundary(domain, fdim, boundary)
sdomain, sdomain_to_domain = create_submesh(domain, fdim, facets)[0:2]

V = functionspace(domain, ("Lagrange", 1)) # both spaces scalar valued
Q = functionspace(sdomain, ("Lagrange", 1))
W = ufl.MixedFunctionSpace(V, V, Q)

dx = Measure("dx", domain=domain)
ds = Measure("ds", domain=domain, subdomain_data=facets)

T, phi, g = TrialFunctions(W)
t, psi, h = TestFunctions(W)

My MixedFunctionSpace consists of two Vs because I have 3 unnowns (T, phi, g) and I only want g on my submesh Q.

Does this make sense so far? And can I still solve the problem with LinearProblem? Because at the moment I’m getting an Error: AttributeError: 'LinearProblem' object has no attribute '_solver'

Please provide a full reproducible example, along with what version of DOLFINx you are using. Please also provide the full error trackback

Hey, yeah of course, sorry. I’m using DOLFINx 0.10.0

from mpi4py import MPI
from petsc4py import PETSc
import numpy as np
from dolfinx.fem import (
    Constant,
    Function,
    dirichletbc,
    functionspace,
    locate_dofs_geometrical,
    locate_dofs_topological,
)

from dolfinx.fem.petsc import LinearProblem
from dolfinx.mesh import locate_entities_boundary, locate_entities, meshtags, create_submesh
from dolfinx import mesh, io
from basix.ufl import element, mixed_element
import ufl
from ufl import (
    ds,
    dx,
    grad,
    dot,
    inner,
    TestFunction,
    TestFunctions,
    TrialFunction,
    TrialFunctions,
    split,
    Measure,
)



domain = mesh.create_rectangle(
    MPI.COMM_WORLD,
    [(0.0, 0.0),
     (2.0, 1.0)],
     [40, 20],
     cell_type=mesh.CellType.triangle,
)

# Parameter
rho = Constant(domain, PETSc.ScalarType(50))
alpha = Constant(domain, PETSc.ScalarType(1e-3))

# Desired Temperature Distribution
x = ufl.SpatialCoordinate(domain)
z = (x[0] - 1) ** 2


def boundary(x):
    return np.isclose(x[0], 0) | np.isclose(x[1], 0) | np.isclose(x[0], 2) | np.isclose(x[1], 1)

tdim = domain.topology.dim
fdim = tdim - 1
gdim = domain.geometry.dim

facets = locate_entities_boundary(domain, fdim, boundary)
sdomain, sdomain_to_domain = create_submesh(domain, fdim, facets)[0:2]


V = functionspace(domain, ("Lagrange", 1))
Q = functionspace(sdomain, ("Lagrange", 1))
W = ufl.MixedFunctionSpace(V, V, Q)


dx = Measure("dx", domain=domain)
ds = Measure("ds", domain=domain, subdomain_data=facets)


# Unknowns and Testfunctons
T, phi, g = TrialFunctions(W)
t, psi, h = TestFunctions(W)


a = (
    T * t * dx + inner(grad(t), grad(phi)) * dx + rho * phi * t * ds
    + alpha * g * h * ds - rho * phi * h * ds
    + inner(grad(T), grad(psi)) * dx + rho * psi * (T - g) * ds
)

L = z * t * dx


problem = LinearProblem(a, L, petsc_options_prefix="heat_", petsc_options={"ksp_type": "gmres", "pc_type": "ilu"})
uh = problem.solve()

Here the (realtively) long error traceback:

Traceback (most recent call last):
  File "/miniforge3/envs/fenicsx-trace/lib/python3.12/site-packages/ffcx/codegeneration/jit.py", line 97, in get_cached_module
    with open(c_filename, "x"):
         ^^^^^^^^^^^^^^^^^^^^^
FileExistsError: [Errno 17] File exists: '/.cache/fenics/libffcx_forms_714703e574ba6eb074d4fa7c500dd3a5b220c92b.c'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/optimales_heizen_3.py", line 121, in <module>
    problem = LinearProblem(a, L, petsc_options_prefix="heat_", petsc_options={"ksp_type": "gmres", "pc_type": "ilu"})
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/miniforge3/envs/fenicsx-trace/lib/python3.12/site-packages/dolfinx/fem/petsc.py", line 792, in __init__
    self._a = _create_form(
              ^^^^^^^^^^^^^
  File "/miniforge3/envs/fenicsx-trace/lib/python3.12/site-packages/dolfinx/fem/forms.py", line 449, in form
    return _create_form(form)
           ^^^^^^^^^^^^^^^^^^
  File "/miniforge3/envs/fenicsx-trace/lib/python3.12/site-packages/dolfinx/fem/forms.py", line 441, in _create_form
    return _form(form)
           ^^^^^^^^^^^
  File "/miniforge3/envs/fenicsx-trace/lib/python3.12/site-packages/dolfinx/fem/forms.py", line 361, in _form
    ufcx_form, module, code = jit.ffcx_jit(
                              ^^^^^^^^^^^^^
  File "/Users/fabianthaler/miniforge3/envs/fenicsx-trace/lib/python3.12/site-packages/dolfinx/jit.py", line 60, in mpi_jit
    return local_jit(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/miniforge3/envs/fenicsx-trace/lib/python3.12/site-packages/dolfinx/jit.py", line 215, in ffcx_jit
    r = ffcx.codegeneration.jit.compile_forms([ufl_object], options=p_ffcx, **p_jit)
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/miniforge3/envs/fenicsx-trace/lib/python3.12/site-packages/ffcx/codegeneration/jit.py", line 207, in compile_forms
    obj, mod = get_cached_module(module_name, form_names, cache_dir, timeout)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/miniforge3/envs/fenicsx-trace/lib/python3.12/site-packages/ffcx/codegeneration/jit.py", line 122, in get_cached_module
    raise TimeoutError(
TimeoutError: JIT compilation timed out, probably due to a failed previous compile. Try cleaning cache (e.g. remove /.cache/fenics/libffcx_forms_714703e574ba6eb074d4fa7c500dd3a5b220c92b.c) or increase timeout option.
Exception ignored in: <function LinearProblem.__del__ at 0x117cbbce0>
Traceback (most recent call last):
  File "/miniforge3/envs/fenicsx-trace/lib/python3.12/site-packages/dolfinx/fem/petsc.py", line 883, in __del__
    lambda obj: obj is not None, (self._solver, self._A, self._b, self._x, self._P_mat)
                                  ^^^^^^^^^^^^
AttributeError: 'LinearProblem' object has no attribute '_solver'

I know I’m a bit lost, sorry, I appreciate all help!