scikit-fem icon indicating copy to clipboard operation
scikit-fem copied to clipboard

ElementLinePp(2) plotting incorrect

Open Vinc0110 opened this issue 2 years ago • 8 comments

Comparing a one-dimensional simulation with higher order elements, I noticed a strange behavior of ElementLinePp() when used with p=2. Other values for p seem to be fine. Of course, in this special case it would anyways be better to use ElementLineP2(), as stated in the warning message.

ElementLinePp2 ElementLineP2

Example code:

import skfem
from skfem.models.poisson import laplace
from skfem.visuals.matplotlib import plot, show

mesh = skfem.MeshLine(p=[0, 0.2, 0.5, 1.0])

#element = skfem.ElementLineP2()
element = skfem.ElementLinePp(2)
basis = skfem.Basis(mesh, element)

A = skfem.asm(laplace, basis)
b = basis.zeros()
phi = basis.zeros()
phi[basis.get_dofs(lambda x: x == 0)] = -0.5
phi[basis.get_dofs(lambda x: x == 1.0)] = 2.0

phi = skfem.solve(*skfem.condense(A, b, x=phi, D=basis.get_dofs()))

ax = plot(basis, phi)
ax.set_title(f'{type(element).__name__}')
show()

Vinc0110 avatar Jan 06 '23 20:01 Vinc0110

It remainds me of #969. Perhaps related or not.

kinnala avatar Jan 07 '23 10:01 kinnala

Yes, it's again something to do with 1D plotting. Here is a workaround:

ax = plot(basis, phi, nrefs=0)

kinnala avatar Jan 07 '23 10:01 kinnala

With nrefs=0 the plot does look correct, thanks for that hint!

Regardless of the plotting, the calculated values are still not identical:

With ElementLineP2():

phi = array([-5.00000000e-01,  8.32667268e-17,  7.50000000e-01,  2.00000000e+00, 
-2.50000000e-01,  3.75000000e-01,  1.37500000e+00])

With ElementLinePp(2):

phi = array([-5.00000000e-01,  5.55111512e-17,  7.50000000e-01,  2.00000000e+00,
0.00000000e+00,  0.00000000e+00,  0.00000000e+00])

By the way, my code above was slightly wrong: I messed up the boundary identification. Replace

phi[basis.get_dofs(lambda x: x == 0)] = -0.5
phi[basis.get_dofs(lambda x: x == 1.0)] = 2.0

with

phi[basis.get_dofs(lambda x: x[0] == 0)] = -0.5
phi[basis.get_dofs(lambda x: x[0] == 1.0)] = 2.0

Vinc0110 avatar Jan 07 '23 13:01 Vinc0110

I believe that the difference is because ElementLineP2 uses nodal basis and ElementLinePp uses hierarchical basis.

kinnala avatar Jan 07 '23 14:01 kinnala

I'm not entirely sure what that means. Is ElementLinePp(2) simply different from ElementLineP2() and cannot be used as a universal (but slower) substitute? In a larger simulation, where I'm trying to calculate eigenmodes in 1d, I also get different results when using ElementLinePp(2) instead of ElementLineP2().

Vinc0110 avatar Jan 07 '23 19:01 Vinc0110

In most applications you can use either one of those but they don't give exactly the same result because the basis functions are different. There are infinite different bases you can use to represent quadratic polynomials. There are many different choices that are used in FEM depending on the use case.

kinnala avatar Jan 07 '23 20:01 kinnala

Understood. Thanks for the help!

Vinc0110 avatar Jan 08 '23 10:01 Vinc0110

We can leave this open because of the bug in skfem.visuals.matplotlib.plot for MeshLine1.

kinnala avatar Jan 08 '23 10:01 kinnala

I cannot remember what was the remaining work and cannot deduce it by reading this, closing. The workaround is to specify nrefs=0, hierarchical bases cannot use nrefs>0.

kinnala avatar Jun 06 '24 07:06 kinnala