Eigenvalues and Eigenvectors of BlockSparse Matrix

98 views
Skip to first unread message

Animesh Rastogi IIT Gandhinagar

unread,
Sep 23, 2020, 2:53:06 PM9/23/20
to deal.II User Group
Hi All,

I am trying to play with the code of Quassi Static Finite Strain Compressibility. I want to calculate the eigenvalues and eigenvectors of the System Tangent Matrix (BlockSparseMatrix<double> tangent_matrix) that we get at every time step after the Newton method has converged. However, I could not find any function to calculate the eigenvalues and eigenvectors of the BlockSparse Matrix. Could someone please help me with this?

Thanks!

AR

Jean-Paul Pelteret

unread,
Sep 23, 2020, 3:40:35 PM9/23/20
to dea...@googlegroups.com
Hi Animesh,

Although in that code-gallery example the system is assembled into a BlockSparseMatrix<double>, the system actually has only one block. So you can retrieve the underlying SparseMatrix<double> (and Vector<double> for the RHS) via
tangent_matrix.block(u_dof, u_dof);
system_rhs.block(u_dof);
and use them with one of the standard eigensolvers (maybe ArpackSolver, since you want both the eigenvalues and eigenvectors).

I hope that this helps you!

Best,
Jean-Paul

--
The deal.II project is located at http://www.dealii.org/
For mailing list/forum options, see https://groups.google.com/d/forum/dealii?hl=en
---
You received this message because you are subscribed to the Google Groups "deal.II User Group" group.
To unsubscribe from this group and stop receiving emails from it, send an email to dealii+un...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/dealii/987eb63a-333e-43b3-a9e0-fbcbae2d567en%40googlegroups.com.

Animesh Rastogi IIT Gandhinagar

unread,
Sep 24, 2020, 2:26:24 AM9/24/20
to deal.II User Group
Hi Jean,

Thanks a lot for your response. I am trying as you suggested. I have added the following code inside the linear solver so that I can get the eigenvalues at every newton step.

std::vector<std::complex<double>>   eigenvalues;
      std::vector<Vector<double> >        eigenvectors;
      SparseMatrix<double> identity (IdentityMatrix(u_dof));
      SparseDirectUMFPACK inverse;
      inverse.initialize (tangent_matrix.block(u_dof,u_dof));
      const int eigensolver_its = static_cast<unsigned int>(
                                tangent_matrix.block(u_dof, u_dof).m()
                                * parameters.max_iterations_lin);
      SolverControl solver_control(eigensolver_its, 1e-9);
      ArpackSolver::ArpackSolver eigensolver(solver_control);
      eigensolver.solve(tangent_matrix.block(u_dof,u_dof), identity, inverse, eigenvalues, eigenvectors);


However, I am getting the follwing error while compiling.

error: ‘ArpackSolver’ has not been declared

I have included the header file #include <deal.II/lac/arpack_solver.h>.

Also, could you please let me know if I have declared the identity matrix correctly? I am replacing the mass matrix B with the Identity matrix to compute the eigenvalues and eigenvectors.

Thanks!

Animesh

Animesh Rastogi IIT Gandhinagar

unread,
Sep 24, 2020, 7:10:47 AM9/24/20
to deal.II User Group
Hi Jean,

It turns out that I did not configure dealii with ARPACK. So I followed the readme instructions and installed and compiled ARPACK as suggested. I also tried to run the examples in the ARPACK directory and they are running without any errors. However, when I tried to reconfigure deallii using the selfcompiled version, it says the following error.

Could not find the arpack library!

  Please ensure that a suitable arpack library is installed on your computer.

  If the library is not at a default location, either provide some hints for
  autodetection,

      $ ARPACK_DIR="..." cmake <...>
      $ cmake -DARPACK_DIR="..." <...>

  or set the relevant variables by hand in ccmake.

I used the following cmake command to configure dealii again  -

cmake -DDEAL_II_WITH_PETSC=ON -DPETSC_DIR=/home/animesh/Documents/petsc-3.13.5 -DPETSC_ARCH=arch-linux-c-debug -DDEAL_II_WITH_METIS=ON -DDEAL_II_WITH_MPI=ON -DDEAL_II_WITH_ARPACK=ON -DARPACK_DIR=/home/animesh/Documents/ARPACK ..

I checked that the path of the directory of ARPACK that I am giving here is correct.

I followed the instructions in this page - https://www.dealii.org/current/external-libs/arpack.html.
Also, I couldn't figure out what it means when it says "For compilation of ARPACK we emphasize adding the compiler flag -fPIC". What is -fPIC and where should I use this flag?

Could you please help me with this and the question about identity matrix asked in the previous mail of this thread?

Thanks a lot!

Animesh

Animesh Rastogi IIT Gandhinagar

unread,
Sep 24, 2020, 2:45:29 PM9/24/20
to deal.II User Group
I could finally configure dealii using ARPACK. I am facing issues in initialising the identity matrix that is to be given to the eigensolver.solve(). I am trying to replace the mass matrix with an identity matrix..

I am copying the code again in this thread..

std::vector<std::complex<double>>   eigenvalues;
      std::vector<Vector<double> >        eigenvectors;
      SparseMatrix<double> identity (IdentityMatrix(u_dof));
      SparseDirectUMFPACK inverse;
      inverse.initialize (tangent_matrix.block(u_dof,u_dof));
      const int eigensolver_its = static_cast<unsigned int>(
                                tangent_matrix.block(u_dof, u_dof).m()
                                * parameters.max_iterations_lin);
      SolverControl solver_control(eigensolver_its, 1e-9);
      ArpackSolver::ArpackSolver eigensolver(solver_control);
      eigensolver.solve(tangent_matrix.block(u_dof,u_dof), identity, inverse, eigenvalues, eigenvectors);

I am getting the following error for this -

error: request for member ‘vmult’ in ‘mass_matrix’, which is of non-class type ‘dealii::BlockSparseMatrix<double>(dealii::IdentityMatrix)’
                       mass_matrix.vmult(tmp, src);

Could someone please help me with this?

Thanks!

Animesh

Animesh Rastogi IIT Gandhinagar

unread,
Sep 25, 2020, 2:36:33 AM9/25/20
to deal.II User Group
Hi,

I could figure out how to give Identity Matrix instead of the mass matrix to solve the Standard Eigen value problem. However, on running, I am getting the folllowing error.

Timestep 1 @ 0.1s
_______________________________________________________________________________________
    SOLVER STEP     |  LIN_IT   LIN_RES    RES_NORM     RES_U     NU_NORM      NU_U
_______________________________________________________________________________________
  0  CST  ASM  SLV    CMakeFiles/run.dir/build.make:57: recipe for target 'CMakeFiles/run' failed
make[3]: *** [CMakeFiles/run] Segmentation fault (core dumped)
CMakeFiles/Makefile2:131: recipe for target 'CMakeFiles/run.dir/all' failed
make[2]: *** [CMakeFiles/run.dir/all] Error 2
CMakeFiles/Makefile2:138: recipe for target 'CMakeFiles/run.dir/rule' failed
make[1]: *** [CMakeFiles/run.dir/rule] Error 2
Makefile:144: recipe for target 'run' failed
make: *** [run] Error 2




I am copying here the solve_linear_system function and the part that I updated is blue in color. Also, I wish to calculate the eigenvalues after the newton method has converged. I am a bit confused of where actually to solve the standard eigenvalue problem in the code for my purpose. Could someone please help me with these questions?

------------------------------------------------
template <int dim,typename NumberType>
  std::pair<unsigned int, double>
  Solid<dim,NumberType>::solve_linear_system(BlockVector<double> &newton_update)
  {
    BlockVector<double> A(dofs_per_block);
    BlockVector<double> B(dofs_per_block);

    unsigned int lin_it = 0;
    double lin_res = 0.0;
    {
      timer.enter_subsection("Linear solver");
      std::cout << " SLV " << std::flush;
      if (parameters.type_lin == "CG")
        {
          const int solver_its = static_cast<unsigned int>(
                                    tangent_matrix.block(u_dof, u_dof).m()
                                    * parameters.max_iterations_lin);
          const double tol_sol = parameters.tol_lin
                                 * system_rhs.block(u_dof).l2_norm();

          SolverControl solver_control(solver_its, tol_sol);

          GrowingVectorMemory<Vector<double> > GVM;
          SolverCG<Vector<double> > solver_CG(solver_control, GVM);

          PreconditionSelector<SparseMatrix<double>, Vector<double> >
          preconditioner (parameters.preconditioner_type,
                          parameters.preconditioner_relaxation);
          preconditioner.use_matrix(tangent_matrix.block(u_dof, u_dof));

          solver_CG.solve(tangent_matrix.block(u_dof, u_dof),
                          newton_update.block(u_dof),
                          system_rhs.block(u_dof),
                          preconditioner);

          lin_it = solver_control.last_step();
          lin_res = solver_control.last_value();
        }
      else if (parameters.type_lin == "Direct")
        {
 
          SparseDirectUMFPACK A_direct;
          A_direct.initialize(tangent_matrix.block(u_dof, u_dof));
          A_direct.vmult(newton_update.block(u_dof), system_rhs.block(u_dof));

          lin_it = 1;
          lin_res = 0.0;
        }
      else
        Assert (false, ExcMessage("Linear solver type not implemented"));

   std::vector<std::complex<double>>   eigenvalues;
   std::vector<Vector<double> >        eigenvectors;
   SparseDirectUMFPACK inverse;
   inverse.initialize (tangent_matrix.block(u_dof,u_dof));
      SolverControl solver_control(1000, 1e-9);

     ArpackSolver eigensolver(solver_control,    ArpackSolver::AdditionalData(ArpackSolver::WhichEigenvalues::algebraically_smallest));
     eigensolver.solve(tangent_matrix.block(u_dof,u_dof), IdentityMatrix(), inverse, eigenvalues, eigenvectors,eigenvalues.size());


      timer.leave_subsection();
    }
---------------------------------------------

Jean-Paul Pelteret

unread,
Sep 25, 2020, 4:19:10 PM9/25/20
to dea...@googlegroups.com
Hi Animesh,

I’m glad to hear that you’ve gotten Arpack working, and that you’re getting somewhere with your implementation. When you encounter a crash like this, its best to run the program in debug mode (better yet, do all of your development in debug mode). In debug mode, there are a lot of additional checks that can help you find the source of issues. You can read more about this here.

I see that you invoke the identity matrix inline with the solve() step like this: IdentityMatrix() . According to the documentation, this is incorrect because the matrix is zero sized (i.e. holds no entries). You probably want to use this constructor, and because the matrix should have the same size as the tangent matrix you would call it like this: IdentityMatrix(tangent_matrix.block(u_dof,u_dof).m()).

I am a bit confused of where actually to solve the standard eigenvalue problem in the code for my purpose.

Well, from your original post it sounds to me like you want to investigate some properties of the equilibrium state of your problem. That makes sense. So really what you probably want to do is let the nonlinear solver iterate until convergence, and then keep the system matrix and RHS vector around (i.e. don’t clear them) and finally as a post-processing step solve the eigenvalue problem. So I would suggest that the entire code block that you added to the solve_linear_system() method simply be moved to the output_results() method, or to some new method that is invoked between solve_nonlinear_timestep() and time.increment() inside the main run() function.

Best,
Jean-Paul

Animesh Rastogi IIT Gandhinagar

unread,
Sep 27, 2020, 11:06:20 AM9/27/20
to deal.II User Group
Hi Jean,

Thanks a lot for your detailed answer. Using this idea, I was able to solve the standard eigenvalue problem.

Thanks again!

Animesh

Animesh Rastogi IIT Gandhinagar

unread,
Sep 27, 2020, 3:47:53 PM9/27/20
to deal.II User Group
Hi Jean,

I need a few more clarifications. Sorry to bother you again.

In my code, when I am using the argument - "smallest_magnitude" for the type of eigenvalue, I am getting a large eigenvalue than when I am using the argument "largest_eigenvalue". I looked at some of the previous discussions on this issue, and found this threads.



I can understand it has something to do with the "inverse" argument in the solve() function. I was wondering what exactly is the argument "inverse" is when we give it to the solve() function. The document says the following which is not clear.

inverse - This is the possibly shifted inverse that is actually used instead of A. Only its function vmult() is used.

Should I consider that the largest_magnitude is indeed the smallest_magnitude eigenvalue in my case? More generally, how should I interpret the results of the ARPACK solver..

I am adding the function that I have written below for your reference -

template <int dim,typename NumberType>
  void Solid<dim,NumberType>::solve_eigenvalue_problem(BlockSparseMatrix<double> &tangent_matrix)
  {


        std::vector<std::complex<double>>   eigenvalues;
        std::vector<Vector<double> >        eigenvectors;
        eigenvalues.resize(1);
        eigenvectors.resize(1);
        for (unsigned int i = 0; i < eigenvectors.size(); ++i)
            eigenvectors[i].reinit(tangent_matrix.block(u_dof,u_dof).m());

        const unsigned int num_arnoldi_vectors = 20;
        FullMatrix<double> identity (IdentityMatrix(tangent_matrix.block(u_dof,u_dof).m()));

        SparseDirectUMFPACK inverse;
        inverse.initialize (tangent_matrix.block(u_dof,u_dof));
        SolverControl solver_control(1000, 1e-9);
        const bool symmetric=true;

        ArpackSolver eigensolver(solver_control, ArpackSolver::AdditionalData(num_arnoldi_vectors, ArpackSolver::WhichEigenvalues::smallest_magnitude, symmetric));

        std::cout<<"Calculating the smallest eigenvalue and corresponding eigenvector at  "<<time.current()<<std::endl;
        eigensolver.solve(tangent_matrix.block(u_dof,u_dof), identity, inverse, eigenvalues,   eigenvectors,eigenvalues.size());

         for (unsigned int i = 0; i < eigenvalues.size(); ++i)
             std::cout<<"Eigenvalue "<<i<<" is "<< eigenvalues[i]<<std::endl;

  }

Thanks a lot!

AR

Jean-Paul Pelteret

unread,
Sep 28, 2020, 1:50:06 AM9/28/20
to dea...@googlegroups.com
I’m afraid I’m not familiar with the working of the Arpack solver so I can’t be of much more help to you. As you’ve pointed out, it looks like there may be some open questions that correlate with the questions you’ve asked. Maybe someone who actually uses, or has used, this solver might be able to assist you further?

Bruno Turcksin

unread,
Sep 28, 2020, 3:44:37 PM9/28/20
to deal.II User Group
Animesh,

Yes, the name are reversed. Basically what happens is that ARPACK uses a method called shift inverse which uses the inverse of the operator you care. In practice, this means that ARPACK is not using your matrix A but only A^{-1} because the largest eigenvalue of A^{-1} is related to the smallest eigenvalue of A. When you ask for the largest the eigenvalue you get the eigenvalue related to the largest eigenvalue of A^{-1} which is the smallest eigenvalue of A.

Best,

Bruno

Animesh Rastogi IIT Gandhinagar

unread,
Sep 29, 2020, 7:33:43 AM9/29/20
to deal.II User Group
Hi Bruno and Jean,

Thanks a lot for your help with the eigenvalue problem. I am able to solve the standard eigenvalue problem, and have tested my code on simple problems. The results are matching (compared them with the MATLAB eigenvalue analysis).

Thanks again!

Animesh
Reply all
Reply to author
Forward
0 new messages