gimli-org / gimli

Geophysical Inversion and Modeling Library :earth_africa:

Home Page:https://www.pygimli.org

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

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 $u: \mathbb R^2 \mapsto \mathbb R$ with exact values given at the boundaries, we expect to obtain the exact solution in the interior of the computational domain.

In our case the function is

$$u(x,y) = -x - y.$$

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:

image

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))

image

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