I'm trying to solve a very tricky issue in my function. The function needs the NDSolve`FEM`
framework.
Here is a minimal example:
Quit[]
GetBoundaryMesh[obj_] := Module[{bmesh},
Needs["NDSolve`FEM`"];
bmesh = ToBoundaryMesh @ obj;
MeshPrimitives[MeshRegion @ bmesh, 1]
]
GetBoundaryMesh[Disk[]]
MeshPrimitives[MeshRegion[Global`ToBoundaryMesh[Disk[{0,0}]]],1]
Something went wrong, I was expecting a list of Lines
which I can get by executing this code manually:
Quit[]
Needs["NDSolve`FEM`"];
bmesh = ToBoundaryMesh @ obj;
MeshPrimitives[MeshRegion @ bmesh, 1]
{Line[{{1.,0.},{0.991575,0.129537}}],<<46>>,Line[{{<<19>>,-<<20>>},{<<1>>}}]}
To me it seems like it isn't importing the NDSolve`FEM
package correctly, but that's just my best guess.
Loose thoughts
When I close MMa and open my notebook again, if I do $Packages
, FEM`NDSolve
isn't there (as expected):
{"GetFEKernelInit`", "StreamingLoader`", "IconizeLoader`", \
"CloudObjectLoader`", "ResourceLocator`", "PacletManager`", \
"System`", "Global`"}
Even after I evaluate the cell that holds all my functions, it's still not in $Packages
. At this point, if I run my function, it gives the same problem, because apparently it has not loaded the package (despite it being the first line in the function it runs...?).
However, after I run the function once (and it gives its error), if I check $Packages
, it is there! So it seems like it is loading it, but somehow the function isn't seeing that in time when it's called..?
Okay, I managed to solve the problem kind of by explicitly calling ToBoundaryMesh
this way:
NDSolve`FEM`ToBoundaryMesh@ashape;
That seems to work on the first try, but why didn't it work without explicitly calling it? Why isn't it in the $Packages
list for the function once Needs[]
is called?
I was reading here about packages and context but I didn't really see the answer.
GetBoundaryMesh
is parsed before the call toNeeds
, and therefore the symbolToBoundaryMesh
is not found anywhere on the$ContextPath
and is considered a new symbol. So, it is created in the current working context ("Global`"
in this case). If you callNeeds
before definingGetBoundaryMesh
, then by the time the code ofGetBoundaryMesh
is parsed, the contextNDSolve`FEM`
is already on the$ContextPath
. So, in this case, the symbol is found there and bound to the right one. $\endgroup$FEM
? It seems like that would make the most sense, because it has some definition for NDSolveFEM
at that point, but no definition in Global. Anyway, I think my solution (calling it explicitly) should work fine, right? $\endgroup$$ContextPath
. If no symbol with this name is found there, the symbol is created in the current context. So, you have to load your dependencies before your code is parsed, so that they are added to the$ContextPath
. And yes, your solution will work. $\endgroup$