Dear FreeFem community,
I hope you are all doing well.
I am trying to solve the following generalized eigenvalue problem on a simplicial mesh \mathcal{T}_h: for each K \in \mathcal{T}_h, find \lambda \in \mathbb{R} and u_h \in \mathbb{P}_k(K)/\mathbb{R} such that
(\nabla \cdot (\mathcal{A} \nabla u_h), \nabla \cdot (\mathcal{A} \nabla v_h))_{0,K} = \lambda\, (\mathcal{A} \nabla u_h, \mathcal{A} \nabla v_h)_{0,K} \quad \forall\, v_h \in \mathbb{P}_k(K)/\mathbb{R}.
Here, \mathcal{A} is a differentiable, elliptic tensor. For each K \in \mathcal{T}_h, I want to compute the local eigenvalues, and extract the maximum one called \lambda_K, which I plan to use in a stabilized method. It is very important for me to associate the maximum eigenvalue to its corresponding element K, since the stabilization may differ from one triangle to another.
Below is my current code for the case \mathcal{A} := I_d:
//----Loop in each triangle
Rh fespace(calP, P0);
Rh lambdaK;
/*
mesh[int] Th(NbTriangles);
for(int K = 0; K < NbTriangles; K++) {
real coordX0, coordX1, coordX2;
real coordY0, coordY1, coordY2;
for(int i = 0; i< NbVertices; i++){
if(elemNodesGlobal(K,0) == i){
coordX0 = calP(i).x;
coordY0 = calP(i).y;
}
if(elemNodesGlobal(K,1) == i){
coordX1 = calP(i).x;
coordY1 = calP(i).y;
}
if(elemNodesGlobal(K,2) == i){
coordX2 = calP(i).x;
coordY2 = calP(i).y;
}
}
real[int, int] nodes = [[coordX0, coordY0], [coordX1,coordY1], [coordX2, coordY2]];
border f0(t=0,1){P.x=nodes(2,0)*t + nodes(1,0)*(1-t);P.y=nodes(2,1)*t + nodes(1,1)*(1-t); label=11;};
border f1(t=0,1){P.x=nodes(0,0)*t + nodes(2,0)*(1-t);P.y=nodes(0,1)*t + nodes(2,1)*(1-t); label=22;};
border f2(t=0,1){P.x=nodes(1,0)*t + nodes(0,0)*(1-t);P.y=nodes(1,1)*t + nodes(0,1)*(1-t); label=33;};
Th[K] = buildmesh(f0(1) + f1(1) + f2(1));
int NbTrianglesLocal = Th[K].nt;
fespace VhK(Th[K], Pk);
int ndof = VhK.ndof;
VhK wh, v;
varf a(wh,v)= int2d(Th[K])( (dxx(wh)+dyy(wh)) * (dxx(v)+dyy(v)) );
varf b(wh,v)= int2d(Th[K])( dx(wh)*dx(v) + dy(wh)*dy(v) );
matrix A = a(VhK, VhK);
matrix B = b(VhK, VhK);
int fixedDOF = 0; // We have to fix one DOF to avoid singularity of B
A(fixedDOF, fixedDOF) = 1e30;
B(fixedDOF, fixedDOF) = 1e-30;
for(int j = 0; j < ndof; j++) {
if(j != fixedDOF) {
A(fixedDOF, j) = 0;
A(j, fixedDOF) = 0;
B(fixedDOF, j) = 0;
B(j, fixedDOF) = 0;
}
}
// Using LAPACK to compute the eigenvalues and eigenvectors
// Creating full matrices for LAPACK
real[int,int] fullA(ndof, ndof);
real[int,int] fullB(ndof, ndof);
for(int i = 0; i < ndof; i++) {
for(int j = 0; j < ndof; j++) {
fullA(i,j) = A(i,j);
fullB(i,j) = B(i,j);
}
}
real[int] nev(ndof );
complex[int] cnev(ndof );
complex[int,int] cneV(ndof, ndof );
dggev(fullA, fullB, cnev, nev, cneV);
// Convert complex eigenvalues to real and sort them
real[int] realEigenvalues(ndof);
for(int i = 0; i < ndof; i++) {
realEigenvalues[i] = real(cnev[i]);
}
real[int] sortedEigenvalues;
int[int] indices = sortEigenvaluesDescending(realEigenvalues, sortedEigenvalues);
lambdaK[][K] = sortedEigenvalues[1];
}
*/
//cout << "lambdaK: " << lambdaK[] << endl;
I find this implementation quite complicated, and I would like to take advantage of some of FreeFem’s built-in features to simplify and clean up the code. Is there a better or more elegant way to do this?