I would like to solve an eigenvalue problem in the form of sigma^2 B x = A x using PETSc The matrices A and B are symmetric and positive definite. The catch is that I would like the vector ‘x’ be independent of the mesh size, lets say a size (3,1) vector. I can specify the action of the matrices B and A using the ‘‘‘func’’’ feature of FreeFEM; but to do that I need a PETSc Mat of the same size. The issue is that I want the (3,1) input vector to be the same on all processes, but naturally if I define a B matrix with size (3,1) each process will have its separate unknowns. I think defining a (3,1) vector on rank 0 would resolve the issue but I cannot seem to have zero size matrices on the other processes (I cannot seem to create a PETSc MAT from a FreeFEM Mat that way). Any suggestions are welcome how to resolve this issue!
Your notation are not consistent, what is a size (3,1) vector and how can you have both this and a B matrix with size (3,1)? Anyway, here is how to define a Mat of size m \times n, exclusively stored on rank p:
load "PETSc"
int p = 0;
int m = 4;
int n = 3;
Mat A(mpirank == p ? m : 0, mpirank == p ? n : 0);
Thanks for the prompt reply, I really appreciate it. The method you suggested works well to define the matrices, but there is a following step in which I am stuck.
I want to use EPSSolve so that the eigenproblem is defined for a few unknowns, like 3, but the application of the operator requires solution of large linear systems of equations. Thus, I think the shell capability FreeFEM/PETSc should be used. However, I cannot manage to make it work the way I want.
The MWE below illustrates the behavior I do not understand. I would imagine that the function applyM is being called to apply multiplication with the matrix M; however, that does not seem to be the case. What am I missing?
load "PETSc"
include "getARGV.idp"
/* matrix creation */
int n = 3;
matrix MinFF(n,n);
for(int i=0; i<n; i++){
for(int j=0; j<n; j++){
MinFF(i,j) = 10*i + j;
}
}
Mat Min(n,n);
Min = MinFF;
/* shell function for successive operations */
int lab;
func real[int] applyM(real[int]& inPETSc) {
cout << "Rank " << mpirank << "/" << mpisize << ", M appliead" << endl;
real[int] outPETSc(n);
MatMult(Min,inPETSc,outPETSc);
return outPETSc;
}
Mat Mmat(Min, applyM);
ObjectView(Min);
ObjectView(Mmat);
/* testing the B matrix application - seems OK */
real[int] testOut(n);
real[int] testIn(n);
testIn = [1,2,3];
real evtol = getARGV("-evtol", 1e-6);
int nev = getARGV("-nev", 2);
int ncv = getARGV("-ncv", 6);
int nIter = getARGV("-nIter", 10);
string params = " -eps_non_hermitian -eps_tol " + evtol + " -eps_nev " + nev + " -eps_ncv " + ncv + " -eps_max_it " + nIter +
" -eps_largest_magnitude -eps_type krylovschur -eps_monitor_conv -eps_monitor_all -eps_converged_reason";
real[int] eval(nev); // array to store eigenvalues
real[int] evalErrors(nev); // array to store eigenvalues
real[int,int] eigenvec(n,nev); // array to store singular values
int k = EPSSolve(Mmat, array = eigenvec, values = eval, sparams = params, errorestimate = evalErrors);
I need to look into this some more, but as a temporary workaround, you can replace Mat Mmat(Min, applyM); by Mat Mmat(Min, Min, applyM); and your functor will be called.