final modification
Strange!
If we use Mathematicas FEM capabilities step by step, introducing DirichletConditions at the end, we get better results:
Needs["NDSolve`FEM`"]
mesh
mesh = ToElementMesh[Rectangle[],"MeshElementType" -> "TriangleElement","MeshOrder" -> 1]
mreg = MeshRegion[mesh];
pts = MeshCoordinates[mreg];
boundary DirichletCondition
rand = MeshCells[MeshRegion[mesh], {0, "Boundary"}][[All, 1]];
randD = Select[rand, (pts[[# ]][[1]] == 0 || pts[[# ]][[2]] == 0 &)]
rand1 = MeshCells[MeshRegion[mesh], {1, "Boundary"}][[All, 1]];
discretization(Mathematica buildin)
nr = ToNumericalRegion[mesh];
vd = NDSolve`VariableData[{"DependentVariables" -> {u},"Space" -> {x, y}}];
sd = NDSolve`SolutionData[{"Space" -> nr}];
coefficients = {"DiffusionCoefficients" -> {{-{{0, -1/2}, { -1/2,0}}}}, "LoadCoefficients" -> {{1}}};
initCoeffs =InitializePDECoefficients[vd, sd, coefficients];
methodData = InitializePDEMethodData[vd, sd];
discretePDE = DiscretizePDE[initCoeffs, methodData, sd];
M11 = discretePDE["StiffnessMatrix"] // Normal;
rS = Flatten[discretePDE["LoadVector"] // Normal, 1];
solution M11.p-rS==0 && dirichlet==0
p = Table[u[i], {i, Length[pts]}]; (* unkowns*)
dirichlet = Table[p[[i]] == 0, {i, randD}]; (* DirchletCondition*)
mini = NMinimize[{# . # &[M11 . p - rS], dirichlet}, p];
Plot3D[Evaluate@ElementMeshInterpolation[mesh, Values[mini[[2]]]][x, y],Element[{x, y}, mreg]]
Result approximates expected function u[x,y]==x y
much better than "terrible" NDSolve result.
final addendum
Thanks @AlexTrounev for his helpful comment
discretePDE["StiffnessMatrix"]
only evaluates the first part of Green's identity, assuming second part(line integral) equal zero(NeumannValue==0)
To get the correct discretization we have to add second part of Green's identity
I don't know if discretePDE
provides this integral somewhere, that's why I choose a selfmade numerical approach
line integration(Gaussian)
linienintegralGaussNeumann[rand_, funx_, funy_,
pi_] := (*rand besteht aus Indexpaaren des Randes *)
Block[{w0 = 8/18, w1 = 5/18, gt = 1/2,
gdt = Sqrt[3/5]/2,(*Gausspunkte tt-dtt,tt,tt+dtt*)
x0, y0, x1, y1, x2, y2, p1, p2, nx, ny},
Total@Map[(
{p1, p2} = pi[[# ]];(*Punkte Randelement*)
{nx, ny} = #/Sqrt[# . #] &[Cross[p2 - p1]];(*
Normalenvektor *)
(* 3Gausspunkte*)
{x0, y0} = (1 - gt) p1 + gt p2;
{x1, y1} = (1 - (gt - gdt )) p1 + (gt - gdt ) p2;
{x2, y2} = (1 - (gt + gdt)) p1 + (gt + gdt) p2;
1/2 Norm[p2 - p1](*
Sehnenlänge*)(nx (funx[x1, y1] w1 + funx[x0, y0] w0 +
funx[x2, y2] w1) +
ny (funy[x1, y1] w1 + funy[x0, y0] w0 +
funy[x2, y2] w1) )) &, rand ](*//Rationalize[#,0]&*)/.
0. -> 0
]
boundary
\[Phi]i =Map[ElementMeshInterpolation[mesh, #] &,IdentityMatrix[Length[pts]]] ;
\[Phi] = Map[ # [x, y] &, \[Phi]i] ;
\[Phi]x = Map[Derivative[1, 0][#][x, y] &, \[Phi]i] ;
\[Phi]y = Map[Derivative[0, 1][#][x, y] &, \[Phi]i] ;
intGreen =
linienintegralGaussNeumann[rand1 ,
Function[{x, y}, Outer[Times, \[Phi] , \[Phi]y] // Evaluate],
Function[{x, y}, Outer[Times, \[Phi] , \[Phi]x] // Evaluate], pts];
p = Table[u[i], {i, Length[pts]}];
dirichlet = Table[p[[i]] == 0, {i, randD}];
mini = NMinimize[{# . # &[ ((M11 - intGreen) . p - rS) ],dirichlet},
p];
Plot3D[Evaluate@ElementMeshInterpolation[mesh, Values[mini[[2]]]][x, y], Element[{x, y}, mesh]]
Plot shows correct result of modified FEM (Galerkin method)!
Hope it helps!
NDSolve
:) . And a critical evidence is,solref["ElementMesh"]
returnsNone
; another critical evidence is: i.sstatic.net/lEHjwX9F.png For comparison, the solution returned by FEM is: i.sstatic.net/nSb0NvhP.png $\endgroup$MethodOfLines
andFiniteElement
are the only two methods available inNDSolve
for PDE solving. $\endgroup$solmol = NDSolveValue[sys, u, {x, 0, 1}, {y, 0, 1}, Method -> "MethodOfLines"]; solmol === solref
evaluates toTrue
. It's unlikely distinct numerical methods produce identical solutions. In any case, an explicit MOL produces the same result. $\endgroup$