firedrakeproject / firedrake

Firedrake is an automated system for the portable solution of partial differential equations using the finite element method (FEM)
https://firedrakeproject.org
Other
520 stars 160 forks source link

BUG: Immersed manifold point evaluation gets wrong result for N1curl, fails for N1div #3089

Open ReubenHill opened 1 year ago

ReubenHill commented 1 year ago

Describe the bug Point evaluation fails to get the expected answer when using an immersed sphere with certain function spaces:

from firedrake import *
import numpy as np

m = UnitIcosahedralSphereMesh(refinement_level=2, name='immersedsphere')
m.init_cell_orientations(SpatialCoordinate(m))
V = FunctionSpace(m, 'N1curl', 2)  # also fails with N2curl
expr = 2 * SpatialCoordinate(m)
f = Function(V).interpolate(expr)
point = m.coordinates.dat.data_ro[0]  # array([-0.52573111, 0.85065081, 0.0]) - definitely on the manifold!
f.at(point)  # array([ 2.36328118e-01,  2.03143488e-01, -6.67673661e-16])
2*point  # array([-1.05146222,  1.70130162,  0.0])
assert np.allclose(f.at(point), 2*point)  # fails

I get the same result if I interpolate onto a vertex-only mesh (see #3068).

If I switch to N1div or N2div I get loopy.diagnostic.TypeInferenceFailure: name not known in type inference: cell_orientations when using f.at(point).

With vertex-only mesh interpolation, I raise this runtime error https://github.com/firedrakeproject/firedrake/blob/35f2b3cce725d0d6a3ed277ea8bda3a287e00476/firedrake/mesh.py#L2313 when target mesh cell orientations are requested https://github.com/firedrakeproject/firedrake/blob/35f2b3cce725d0d6a3ed277ea8bda3a287e00476/firedrake/interpolation.py#L960 despite them being set in the script.

Expected behavior Either the correct answer or a NotImplementedError

Error message See above.

Environment:

ReubenHill commented 1 year ago

Also get the loopy error for

V = FunctionSpace(m, 'BDM', 2)

and get the wrong answer for Regge:

from firedrake import *
import numpy as np

m = UnitIcosahedralSphereMesh(refinement_level=2, name='immersedsphere')
m.init_cell_orientations(SpatialCoordinate(m))
V = FunctionSpace(m, 'Regge', 2)
x = SpatialCoordinate(m)
expr = outer(x, x)
f = Function(V).interpolate(expr)
point = m.coordinates.dat.data_ro[0]  # array([-0.52573111, 0.85065081, 0.0])
f.at(point)
# array([[ 1.39627448e-02,  1.20021295e-02, -1.68957223e-17],
#        [ 1.20021295e-02,  1.03168192e-02, -1.40488013e-17],
#        [-1.55534977e-17, -1.33695127e-17, -1.52575501e-17]])
np.outer(point, point)
# array([[ 0.2763932, -0.4472136, -0.       ],
#        [-0.4472136,  0.7236068,  0.       ],
#        [-0.       ,  0.       ,  0.       ]])
assert np.allclose(f.at(point), np.outer(point, point))  # fails
ReubenHill commented 1 year ago

Update: N1curl/N2curl result is not necessarily wrong. We need a complete polynomial space for point evaluation to give an the naively expected result. A plane in R^3 (at z=0) with N1curl (degree 2), N2curl (degree 1) BDM (degree 1), RT (degree 2) should all give us the answer we expect in the test above.

Other issues need to be debugged.