Time dependent Dirichlet boundary conditions FEniCSx

Hello people,
I am confused on how Dirichlet boundary conditions are applied in several examples I’ve seen, with dolfinx. I have a code like the one at Computing fluxes accurately - #4 by dokken but the difference is that I am changing the part:

T_left = 100


# Define Dirichlet boundary conditions to the facets corresponding to the left end of the rod.
left_facets = facet_markers.find(T_fixed_surface)
left_dofs = locate_dofs_topological(V, mesh.topology.dim-1, left_facets)
bc = dirichletbc(ScalarType(T_left), left_dofs, V)
bcs = [bc]

To a time dependent boundary condition, say T_left = 10 * np.sin(t). Obviously it isn’t as simple at this simple statement.

One of my numerous attempt is:

    # Define Dirichlet boundary conditions to the facets corresponding to the left end of the rod.
    class time_dependent_T_left:
        def __init__(self, t):
            self.t = 0.0

        def eval(self, x):
            return np.full(x.shape[1], 10 * np.sin(self.t), dtype = ScalarType)
            #return np.full(x.shape[1], 10 * np.sin(self.t)) 
    T_left_expr = time_dependent_T_left()
    T_left_expr.t = 0.0
    bc_fun = Function(V)
    bc_fun.interpolate(T_left_expr.eval)
    
    left_facets = facet_markers.find(T_fixed_surface)
    left_dofs = locate_dofs_topological(V, mesh.topology.dim-1, left_facets)
    #print(dir(T_left_expr))
    #exit()
    bc = dirichletbc(bc_fun, left_dofs, V)

The errors I get are of the kind

Traceback (most recent call last):
  File "/usr/local/dolfinx-real/lib/python3.10/dist-packages/dolfinx/fem/bcs.py", line 175, in dirichletbc
    bc = bctype(_value, dofs, V)
TypeError: __init__(): incompatible constructor arguments. The following argument types are supported:
    1. dolfinx.cpp.fem.DirichletBC_float64(g: numpy.ndarray[numpy.float64], dofs: numpy.ndarray[numpy.int32], V: dolfinx::fem::FunctionSpace<double>)
    2. dolfinx.cpp.fem.DirichletBC_float64(g: dolfinx::fem::Constant<double>, dofs: numpy.ndarray[numpy.int32], V: dolfinx::fem::FunctionSpace<double>)
    3. dolfinx.cpp.fem.DirichletBC_float64(g: dolfinx::fem::Function<double, double>, dofs: numpy.ndarray[numpy.int32])
    4. dolfinx.cpp.fem.DirichletBC_float64(g: dolfinx::fem::Function<double, double>, dofs: Annotated[List[numpy.ndarray[numpy.int32]], FixedSize(2)], V: dolfinx::fem::FunctionSpace<double>)

Invoked with: <dolfinx.cpp.fem.Function_float64 object at 0x7f148725d070>, array([418, 422, 427, 428, 429, 430, 439, 443, 444, 445, 447, 448, 452],
      dtype=int32), FunctionSpace(Mesh(blocked element (Basix element (P, tetrahedron, 1, equispaced, unset, False), (3,)), 0), Basix element (P, tetrahedron, 2, gll_warped, unset, False))

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/root/shared/results.py", line 15, in <module>
    simulation = thermal_simulation(heat_transfers, mesh_options, saving_options)
  File "/root/shared/barra_calor.py", line 121, in thermal_simulation
    bc = dirichletbc(bc_fun, left_dofs, V)
  File "/usr/local/dolfinx-real/lib/python3.10/dist-packages/dolfinx/fem/bcs.py", line 177, in dirichletbc
    bc = bctype(_value, dofs, V._cpp_object)
TypeError: __init__(): incompatible constructor arguments. The following argument types are supported:
    1. dolfinx.cpp.fem.DirichletBC_float64(g: numpy.ndarray[numpy.float64], dofs: numpy.ndarray[numpy.int32], V: dolfinx::fem::FunctionSpace<double>)
    2. dolfinx.cpp.fem.DirichletBC_float64(g: dolfinx::fem::Constant<double>, dofs: numpy.ndarray[numpy.int32], V: dolfinx::fem::FunctionSpace<double>)
    3. dolfinx.cpp.fem.DirichletBC_float64(g: dolfinx::fem::Function<double, double>, dofs: numpy.ndarray[numpy.int32])
    4. dolfinx.cpp.fem.DirichletBC_float64(g: dolfinx::fem::Function<double, double>, dofs: Annotated[List[numpy.ndarray[numpy.int32]], FixedSize(2)], V: dolfinx::fem::FunctionSpace<double>)

Invoked with: <dolfinx.cpp.fem.Function_float64 object at 0x7f148725d070>, array([418, 422, 427, 428, 429, 430, 439, 443, 444, 445, 447, 448, 452],
      dtype=int32), <dolfinx.cpp.fem.FunctionSpace_float64 object at 0x7f1487251b30>

I don’t really understand what “x” stands for. It has shape (3, 1980), and the mesh has:

Info    : 27 entities
Info    : 86 nodes
Info    : 366 elements

so I don’t know where the 1980 comes from. I guess I could fix the error I get by modifying the return statement in the time_dependent_T_left class, but I’m not sure how… Any guide is welcome.

Wrap T_left as a dolfinx.fem.Constant, i.e.

T_left = dolfinx.fem.Constant(mesh, ScalarType(0))

bc = dirichletbc(T_left, left_dofs, V)
bcs = [bc]

t = 1
T_left.value = 100 * np.sin(t)
t += 0.1
T_left.value = 100 * np.sin(t)

or change the function code from

to
bc = dirichletbc(bc_fun, left_dofs)

I will try your 1st solution.
I tried your 2nd solution, adding the line Temp.interpolate(V) just before the line `xdmf.write_function(Temp, t), but I get the error:

Traceback (most recent call last):
  File "/usr/local/dolfinx-real/lib/python3.10/dist-packages/dolfinx/fem/function.py", line 397, in interpolate
    _interpolate(u, cells)
  File "/usr/lib/python3.10/functools.py", line 889, in wrapper
    return dispatch(args[0].__class__)(*args, **kw)
  File "/usr/local/dolfinx-real/lib/python3.10/dist-packages/dolfinx/fem/function.py", line 373, in _interpolate
    self._cpp_object.interpolate(u, cells, nmm_interpolation_data)
TypeError: interpolate(): incompatible function arguments. The following argument types are supported:
    1. (self: dolfinx.cpp.fem.Function_float64, f: numpy.ndarray[numpy.float64], cells: numpy.ndarray[numpy.int32]) -> None
    2. (self: dolfinx.cpp.fem.Function_float64, u: dolfinx.cpp.fem.Function_float64, cells: numpy.ndarray[numpy.int32], nmm_interpolation_data: Tuple[List[int], List[int], List[float], List[int]]) -> None
    3. (self: dolfinx.cpp.fem.Function_float64, expr: dolfinx::fem::Expression<double, double>, cells: numpy.ndarray[numpy.int32]) -> None

Invoked with: <dolfinx.cpp.fem.Function_float64 object at 0x7f9463b70170>, FunctionSpace(Mesh(blocked element (Basix element (P, tetrahedron, 1, equispaced, unset, False), (3,)), 0), Basix element (P, tetrahedron, 2, gll_warped, unset, False)), array([  0,   1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12,
        13,  14,  15,  16,  17,  18,  19,  20,  21,  22,  23,  24,  25,
        26,  27,  28,  29,  30,  31,  32,  33,  34,  35,  36,  37,  38,
        39,  40,  41,  42,  43,  44,  45,  46,  47,  48,  49,  50,  51,
        52,  53,  54,  55,  56,  57,  58,  59,  60,  61,  62,  63,  64,
        65,  66,  67,  68,  69,  70,  71,  72,  73,  74,  75,  76,  77,
        78,  79,  80,  81,  82,  83,  84,  85,  86,  87,  88,  89,  90,
        91,  92,  93,  94,  95,  96,  97,  98,  99, 100, 101, 102, 103,
       104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116,
       117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129,
       130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142,
       143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155,
       156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168,
       169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181,
       182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194,
       195, 196, 197], dtype=int32), ((), (), (), ())

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/root/shared/results.py", line 15, in <module>
    simulation = thermal_simulation(heat_transfers, mesh_options, saving_options)
  File "/root/shared/barra_calor.py", line 200, in thermal_simulation
    Temp.interpolate(V)
  File "/usr/local/dolfinx-real/lib/python3.10/dist-packages/dolfinx/fem/function.py", line 400, in interpolate
    assert callable(u)
AssertionError

I’ll let you know how your 1st suggestion goes.

I tried both ways. It seems to work at a first glance (no error with your suggestion), but I get an error when interpolating “Temp” onto V, right before saving as xdmf. I know xdmf support will cease to exist, so I’ll eventually try another format, but for now I’d like this to work. How could I correctly interpolate?

This does not make sense as a command if Temp is a function and V is a function space.

You haven’t really provided a reproducible code, so Im not sure what you are attempting here.

XDMFFile supports writing first order Lagrange Spaces, thus, you should create an appropriate function space W, being a scalar/vector/tensor space of first order Lagrange elements (depending on the use case), then make a function w in W, and call w.interpolate(Temp) to transfer Temp into a compatible space.

1 Like

Thanks, this works, I didn’t realize it had to be 1st order elements…
There are many things I don’t understand. The thing about 1980 (the shape of x). Also, if I defined Temp to be in a 2nd order function space, solve the problem, and save the solution as xdmf using an interpolation to transfer Temp to a suitable 1st order space, do I lose all the accuracy of 2nd order function space compared to a 1st order? That would be terrible. I guess not?

Take every cell of the mesh, count all the dofs in all the cells (including duplicate counting for dofs at facets and vertices) when looking at a Lagrange element. For more general elements, the x will be an array of shape (3, number_of_interpolation_points).

You do lose most of the information of the second order space. You only Get the dof values at the vertices, and any quadratic data in between vertices are lost. Therefore we recommend using VTXWriter or VTKFile, as They support higher order Lagrange elements (and DG)

1 Like