How to implement inhomogeneous Dirichlet boundary conditions?
ruboerner opened this issue · comments
Problem description
I'm trying to solve the Laplace equation on a unit square.
It is unclear how to project the exact solution as Dirichlet boundary condition onto the FE space.
Your environment
--------------------------------------------------------------------------------
Date: Fri Mar 15 13:25:18 2024 CET
OS : Darwin
CPU(s) : 8
Machine : arm64
Architecture : 64bit
RAM : 16.0 GiB
Environment : Jupyter
File system : apfs
Python 3.11.8 | packaged by conda-forge | (main, Feb 16 2024, 20:49:36)
[Clang 16.0.6 ]
pygimli : 1.5.0
pgcore : 1.5.0
numpy : 1.26.4
matplotlib : 3.8.3
scipy : 1.12.0
IPython : 8.20.0
pyvista : 0.43.3
--------------------------------------------------------------------------------
Steps to reproduce
import numpy as np
import pygimli as pg
from pygimli import meshtools as mt # import a module
from pygimli.viewer import showMesh # import a function
geometry = mt.createWorld(start=[0, 0], end=[1, 1], worldMarker=False)
mesh = mt.createMesh(geometry, area=0.005, quality=33, smooth=True)
mesh = mesh.createP2()
X = 1
Y = 1
def BC(boundary):
return (-X * boundary.nodes()[0][0] -Y * boundary.nodes()[0][1])
bc={'Dirichlet': {1: BC,
2: BC,
3: BC,
4: BC}}
u = pg.solve(mesh, a=[[1, 1]], bc=bc, verbose=True)
showMesh(mesh, data=u, showMesh=True,
contourLines=False, nCols=41, cMap='RdBu_r');
Expected behavior
As the solution of the considered Laplace problem we assume a simple linear function
In our case the function is
Actual behavior
It can be observed from the MWE that (probably) not all DOFs at the boundaries have been assigned the desired boundary values.
If possible, please add one or more labels to your issue, e.g. if you expect that your issue is rather a question than a problem with the code, please add the label "question".
I can confirm the issue.
A quick test with the new fea implementation (yet unpublished) shows the resulting field need to be exact and mesh independend due to the bilinear field characteristics:
Its a little unclear where this comes from and when I will have time to fix it. In the meantime you can set the Dirichlet values to the nodes directly which seems to work as expected.
def BCN(node):
return (-X * node.x() -Y * node.y())
bc={'Node': [[b.node(0).id(), BCN(b.node(0))] for b in mesh.findBoundaryByMarker(1,5)]}
uh = pg.solve(mesh, a=[[1, 1]], bc=bc, verbose=True)
u = (-pg.x(mesh) - pg.y(mesh))
print('normL2(u-uh):', pg.solver.normL2(u-uh, mesh))
Also there seems an issue with the showMesh
keyword argument in the current release which I need to fix.
Many thanks for reporting,
Carsten
Edit: Added the code for normL2 calculation
Edit 2: The workarround only works for p=1 meshes, for p=2 also the middle node (b.node(2)) need to be considered.
The problem comes from the numbering directions of the boundary nodes. Not every node(0) is connected to node(1) from its neighbour, some are screwed due to triangle. So if you assign the value for one boundary to its node(0) might lead to wrong assigments. This is unfortunately broken be 'very old design' and I'm unsure if this can be fixed with moderate afford. Until the new implementation comes online, the little bit unconveniant direct node assignment will work.
Hi @carsten-forty2,
thanks for the quick and insightful response!
The news about a re-implementation of the FE code basis is great!
Cheers,
Ralph