Is it possible to define a CoefficientFunction in NGSolve using a mapping instead of an explicit expression?
Suppose I have a real-valued mapping defined on a domain Ω, meaning that for every point (x, y) ∈ Ω, I know the corresponding value f(x, y) ∈ R.
However, f(x, y) involves complex pointwise operations. For example,
(A) it is a piecewise function, or
(B) it is a composition of a smooth function R^2 → R and a one-dimensional finite element function.
As a result, f(x, y) does not have an explicit formula, so I cannot define it using a mathematical expression. However, I do know the function values at any given point (x, y) ∈ Ω.
In this case, is there a way to define a CoefficientFunction in NGSolve based only on known function values at each point, without requiring an explicit mathematical expression?
Any suggestions would be greatly appreciated. Thank you very much!
you can do all that with ngsolve expressions, but maybe it would be easier to showcase in an example? What exactly to you have in mind?
piecewise function per domain or on a grid? How and what kind of composition? where do you need it and how efficient do you need evaluation…
I’ve been having the same problem. What I found is the function VoxelCoefficient(p1, p2, values) where p1 are the starting coordinates of your quadrature, p2 the ending coordinates, and values the values of the function in your quadrature. I haven’t been able to get it to work, so I’ll stay and read more comments. If you could tell me if it worked for you and how you configured your gridfunction based on your Voxelcoefficient, I would greatly appreciate it.
Thanks for sharing your approach! What I currently know is something that Prof. Joachim Schöberl suggested a few days ago. It is possible to define barycentric coordinates as follows:
However, this is still an interpolation approximation, which introduces interpolation errors. Ideally, I would like it to be as accurate as possible.
Moreover, using this approach, writing out higher-order nodal basis functions becomes quite complex. Additionally, I am not sure whether this method would lead to instability for arbitrary higher-order approximations.
There were some small things missing for the creation of occ 1d meshes which are now on the current master pushed. With this this code is running and I think does what you were aiming for:
from netgen.occ import *
from ngsolve import *
from ngsolve.fem import CoordinateTrafo
r = Rectangle(2,2).Face().Move((-1,-1,0))
r.edges.Min(X).name = "left"
r.edges.Max(X).name = "right"
r.edges.Min(Y).name = "bottom"
r.edges.Max(Y).name = "top"
mesh2d = Mesh(OCCGeometry(r, dim=2).GenerateMesh(maxh=0.1))
edge = Segment((-pi/2,0,0), (pi/2,0,0))
edge.name = "edge"
mesh1d = Mesh(OCCGeometry(edge, dim=1).GenerateMesh(maxh=0.1))
fes2d = H1(mesh2d, order=2)
fes1d = H1(mesh1d, order=2)
gf1d = GridFunction(fes1d)
gf1d.Set(cos(x))
gf2d = GridFunction(fes2d)
# to cut of numeric values > 1 that lead to nans...
asin_no_nan = IfPos(y**2-1, 0, asin(y))
f = gf1d(CoordinateTrafo(CF((asin_no_nan,0,0)), mesh1d.Materials(".*")))
gf2d.Set(f)
Draw(gf2d)
if you created the 1d mesh by hand it should already work with current releases.
best
for performance reasons (this evaluate with CoordinateTrafo is a bit expensive) it is most of the times good to interpolate the transformed function into a gf on the mesh before doing further things.