deal.II version GIT relicensing-6960-g70e9c5b7be 2026-10-22 20:10:01+00:00
\(\newcommand{\dealvcentcolon}{\mathrel{\mathop{:}}}\) \(\newcommand{\dealcoloneq}{\dealvcentcolon\mathrel{\mkern-1.2mu}=}\) \(\newcommand{\jump}[1]{\left[\!\left[ #1 \right]\!\right]}\) \(\newcommand{\average}[1]{\left\{\!\left\{ #1 \right\}\!\right\}}\)
Loading...
Searching...
No Matches
arpack_solver.h
Go to the documentation of this file.
1// -----------------------------------------------------------------------------
2//
3// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception OR LGPL-2.1-or-later
4// Copyright (C) 2010 - 2026 by the deal.II authors
5//
6// This file is part of the deal.II library.
7//
8// Detailed license information governing the source code and contributions
9// can be found in LICENSE.md and CONTRIBUTING.md at the top level directory.
10//
11// -----------------------------------------------------------------------------
12
13#ifndef dealii_arpack_solver_h
14#define dealii_arpack_solver_h
15
16#include <deal.II/base/config.h>
17
21#include <deal.II/base/types.h>
22
24
25#include <complex>
26#include <cstring>
27
28
30
31#ifdef DEAL_II_WITH_ARPACK
32extern "C" void
33dnaupd_(int *ido,
34 char *bmat,
35 unsigned int *n,
36 char *which,
37 unsigned int *nev,
38 const double *tol,
39 double *resid,
40 int *ncv,
41 double *v,
42 int *ldv,
43 int *iparam,
44 int *ipntr,
45 double *workd,
46 double *workl,
47 int *lworkl,
48 int *info);
49
50extern "C" void
51dsaupd_(int *ido,
52 char *bmat,
53 unsigned int *n,
54 char *which,
55 unsigned int *nev,
56 double *tol,
57 double *resid,
58 int *ncv,
59 double *v,
60 int *ldv,
61 int *iparam,
62 int *ipntr,
63 double *workd,
64 double *workl,
65 int *lworkl,
66 int *info);
67
68extern "C" void
69dneupd_(int *rvec,
70 char *howmany,
71 int *select,
72 double *d,
73 double *di,
74 double *z,
75 int *ldz,
76 double *sigmar,
77 double *sigmai,
78 double *workev,
79 char *bmat,
80 unsigned int *n,
81 char *which,
82 unsigned int *nev,
83 double *tol,
84 double *resid,
85 int *ncv,
86 double *v,
87 int *ldv,
88 int *iparam,
89 int *ipntr,
90 double *workd,
91 double *workl,
92 int *lworkl,
93 int *info);
94
95extern "C" void
96dseupd_(int *rvec,
97 char *howmany,
98 int *select,
99 double *d,
100 double *z,
101 int *ldz,
102 double *sigmar,
103 char *bmat,
104 unsigned int *n,
105 char *which,
106 unsigned int *nev,
107 double *tol,
108 double *resid,
109 int *ncv,
110 double *v,
111 int *ldv,
112 int *iparam,
113 int *ipntr,
114 double *workd,
115 double *workl,
116 int *lworkl,
117 int *info);
118
167{
168public:
173
174
221
226 {
232 explicit AdditionalData(
233 const unsigned int number_of_arnoldi_vectors = 15,
235 const bool symmetric = false);
236
242 const unsigned int number_of_arnoldi_vectors;
243
248
252 const bool symmetric;
253 };
254
259 control() const;
260
266
270 template <typename VectorType>
271 void
272 set_initial_vector(const VectorType &vec);
273
279 void
280 set_shift(const std::complex<double> sigma);
281
329 template <typename VectorType, typename MatrixType, typename INVERSE>
330 void
331 solve(const MatrixType &B,
332 const INVERSE &inverse,
333 std::vector<std::complex<double>> &eigenvalues,
334 std::vector<VectorType> &eigenvectors,
335 const unsigned int n_eigenvalues = 0);
336
343 template <typename VectorType,
344 typename MatrixType1,
345 typename MatrixType2,
346 typename INVERSE>
348 "Use solve() without the system matrix argument.")
349 void solve(const MatrixType1 &A,
350 const MatrixType2 &B,
351 const INVERSE &inverse,
352 std::vector<std::complex<double>> &eigenvalues,
353 std::vector<VectorType> &eigenvectors,
354 const unsigned int n_eigenvalues = 0);
355
356protected:
362
367
372 std::vector<double> resid;
373
377 double sigmar;
378
382 double sigmai;
383
384
385private:
390 int,
391 int,
392 << "Number of wanted eigenvalues " << arg1
393 << " is larger that the size of the matrix " << arg2);
394
396 int,
397 int,
398 << "Number of wanted eigenvalues " << arg1
399 << " is larger that the size of eigenvectors " << arg2);
400
403 int,
404 int,
405 << "To store the real and complex parts of " << arg1
406 << " eigenvectors in real-valued vectors, their size (currently set to "
407 << arg2 << ") should be greater than or equal to " << arg1 + 1);
408
410 int,
411 int,
412 << "Number of wanted eigenvalues " << arg1
413 << " is larger that the size of eigenvalues " << arg2);
414
416 int,
417 int,
418 << "Number of Arnoldi vectors " << arg1
419 << " is larger that the size of the matrix " << arg2);
420
422 int,
423 int,
424 << "Number of Arnoldi vectors " << arg1
425 << " is too small to obtain " << arg2 << " eigenvalues");
426
428 int,
429 << "This ido " << arg1
430 << " is not supported. Check documentation of ARPACK");
431
433 int,
434 << "This mode " << arg1
435 << " is not supported. Check documentation of ARPACK");
436
438 int,
439 << "Error with dsaupd, info " << arg1
440 << ". Check documentation of ARPACK");
441
443 int,
444 << "Error with dnaupd, info " << arg1
445 << ". Check documentation of ARPACK");
446
448 int,
449 << "Error with dseupd, info " << arg1
450 << ". Check documentation of ARPACK");
451
453 int,
454 << "Error with dneupd, info " << arg1
455 << ". Check documentation of ARPACK");
456
458 int,
459 << "Maximum number " << arg1 << " of iterations reached.");
460
462 "No shifts could be applied during implicit"
463 " Arnoldi update, try increasing the number of"
464 " Arnoldi vectors.");
465};
466
467
469 const unsigned int number_of_arnoldi_vectors,
470 const WhichEigenvalues eigenvalue_of_interest,
471 const bool symmetric)
472 : number_of_arnoldi_vectors(number_of_arnoldi_vectors)
473 , eigenvalue_of_interest(eigenvalue_of_interest)
474 , symmetric(symmetric)
475{
476 // Check for possible options for symmetric problems
477 if (symmetric)
478 {
479 Assert(
480 eigenvalue_of_interest != largest_real_part,
482 "'largest real part' can only be used for non-symmetric problems!"));
483 Assert(
484 eigenvalue_of_interest != smallest_real_part,
486 "'smallest real part' can only be used for non-symmetric problems!"));
487 Assert(
488 eigenvalue_of_interest != largest_imaginary_part,
490 "'largest imaginary part' can only be used for non-symmetric problems!"));
491 Assert(
492 eigenvalue_of_interest != smallest_imaginary_part,
494 "'smallest imaginary part' can only be used for non-symmetric problems!"));
495 }
496 // Check for possible options for asymmetric problems
497 else
498 {
499 Assert(
500 eigenvalue_of_interest != algebraically_largest,
502 "'largest algebraic part' can only be used for symmetric problems!"));
503 Assert(
504 eigenvalue_of_interest != algebraically_smallest,
506 "'smallest algebraic part' can only be used for symmetric problems!"));
507 Assert(eigenvalue_of_interest != both_ends,
509 "'both ends' can only be used for symmetric problems!"));
510 }
511}
512
513
522
523
524
525inline void
526ArpackSolver::set_shift(const std::complex<double> sigma)
527{
528 sigmar = sigma.real();
529 sigmai = sigma.imag();
530}
531
532
533
534template <typename VectorType>
535inline void
537{
539 resid.resize(vec.size());
540 for (size_type i = 0; i < vec.size(); ++i)
541 resid[i] = vec[i];
542}
543
544
545template <typename VectorType,
546 typename MatrixType1,
547 typename MatrixType2,
548 typename INVERSE>
549inline void
550ArpackSolver::solve(const MatrixType1 & /*system_matrix*/,
551 const MatrixType2 &mass_matrix,
552 const INVERSE &inverse,
553 std::vector<std::complex<double>> &eigenvalues,
554 std::vector<VectorType> &eigenvectors,
555 const unsigned int n_eigenvalues)
556{
557 solve(mass_matrix, inverse, eigenvalues, eigenvectors, n_eigenvalues);
558}
559
560
561
562template <typename VectorType, typename MatrixType, typename INVERSE>
563inline void
564ArpackSolver::solve(const MatrixType &mass_matrix,
565 const INVERSE &inverse,
566 std::vector<std::complex<double>> &eigenvalues,
567 std::vector<VectorType> &eigenvectors,
568 const unsigned int n_eigenvalues)
569{
570 // Problem size
571 unsigned int n = eigenvectors[0].size();
572
573 // Number of eigenvalues
574 const unsigned int nev_const =
575 (n_eigenvalues == 0) ? eigenvalues.size() : n_eigenvalues;
576 // nev for arpack, which might change by plus one during dneupd
577 unsigned int nev = nev_const;
578
579 // check input sizes
581 {
582 Assert(nev <= eigenvectors.size(),
584 }
585 else
586 Assert(nev + 1 <= eigenvectors.size(),
588 eigenvectors.size()));
589
590 Assert(nev <= eigenvalues.size(),
592
593 // check large enough problem size
595
599
600 // check whether we have enough Arnoldi vectors
604
605 // ARPACK mode for dsaupd/dnaupd, here only mode 3, i.e. shift-invert mode
606 int mode = 3;
607
608 // reverse communication parameter
609 int ido = 0;
610
611 // 'G' generalized eigenvalue problem 'I' standard eigenvalue problem
612 char bmat[2] = "G";
613
614 // Specify the eigenvalues of interest, possible parameters "LA" algebraically
615 // largest "SA" algebraically smallest "LM" largest magnitude "SM" smallest
616 // magnitude "LR" largest real part "SR" smallest real part "LI" largest
617 // imaginary part "SI" smallest imaginary part "BE" both ends of spectrum
618 // simultaneous.
619 char which[3];
621 {
623 std::strcpy(which, "LA");
624 break;
626 std::strcpy(which, "SA");
627 break;
629 std::strcpy(which, "LM");
630 break;
632 std::strcpy(which, "SM");
633 break;
635 std::strcpy(which, "LR");
636 break;
638 std::strcpy(which, "SR");
639 break;
641 std::strcpy(which, "LI");
642 break;
644 std::strcpy(which, "SI");
645 break;
646 case both_ends:
647 std::strcpy(which, "BE");
648 break;
649 }
650
651 // tolerance for ARPACK
652 double tol = control().tolerance();
653
654 // if the starting vector is used it has to be in resid
655 if (!initial_vector_provided || resid.size() != n)
656 resid.resize(n, 1.);
657
658 // number of Arnoldi basis vectors specified
659 // in additional_data
661
662 int ldv = n;
663 std::vector<double> v(ldv * ncv, 0.0);
664
665 // information to the routines
666 std::vector<int> iparam(11, 0);
667
668 iparam[0] = 1; // shift strategy
669
670 // maximum number of iterations
671 iparam[2] = control().max_steps();
672
673 // Set the mode of dsaupd. 1 is exact shifting, 2 is user-supplied shifts,
674 // 3 is shift-invert mode, 4 is buckling mode, 5 is Cayley mode.
675
676 iparam[6] = mode;
677 std::vector<int> ipntr(14, 0);
678
679 // work arrays for ARPACK
680 std::vector<double> workd(3 * n, 0.);
681 int lworkl =
682 additional_data.symmetric ? ncv * ncv + 8 * ncv : 3 * ncv * ncv + 6 * ncv;
683 std::vector<double> workl(lworkl, 0.);
684
685 // information out of the iteration
686 int info = 1;
687
688 while (ido != 99)
689 {
690 // call of ARPACK dsaupd/dnaupd routine
692 dsaupd_(&ido,
693 bmat,
694 &n,
695 which,
696 &nev,
697 &tol,
698 resid.data(),
699 &ncv,
700 v.data(),
701 &ldv,
702 iparam.data(),
703 ipntr.data(),
704 workd.data(),
705 workl.data(),
706 &lworkl,
707 &info);
708 else
709 dnaupd_(&ido,
710 bmat,
711 &n,
712 which,
713 &nev,
714 &tol,
715 resid.data(),
716 &ncv,
717 v.data(),
718 &ldv,
719 iparam.data(),
720 ipntr.data(),
721 workd.data(),
722 workl.data(),
723 &lworkl,
724 &info);
725
726 if (ido == 99)
727 break;
728
729 switch (mode)
730 {
731 case 3:
732 {
733 switch (ido)
734 {
735 case -1:
736 {
737 VectorType src, dst, tmp;
738 src.reinit(eigenvectors[0]);
739 dst.reinit(src);
740 tmp.reinit(src);
741
742
743 for (size_type i = 0; i < src.size(); ++i)
744 src(i) = workd[ipntr[0] - 1 + i];
745
746 // multiplication with mass matrix M
747 mass_matrix.vmult(tmp, src);
748 // solving linear system
749 inverse.vmult(dst, tmp);
750
751 for (size_type i = 0; i < dst.size(); ++i)
752 workd[ipntr[1] - 1 + i] = dst(i);
753 }
754 break;
755
756 case 1:
757 {
758 VectorType src, dst, tmp, tmp2;
759 src.reinit(eigenvectors[0]);
760 dst.reinit(src);
761 tmp.reinit(src);
762 tmp2.reinit(src);
763
764 for (size_type i = 0; i < src.size(); ++i)
765 {
766 src(i) = workd[ipntr[2] - 1 + i];
767 tmp(i) = workd[ipntr[0] - 1 + i];
768 }
769 // solving linear system
770 inverse.vmult(dst, src);
771
772 for (size_type i = 0; i < dst.size(); ++i)
773 workd[ipntr[1] - 1 + i] = dst(i);
774 }
775 break;
776
777 case 2:
778 {
779 VectorType src, dst;
780 src.reinit(eigenvectors[0]);
781 dst.reinit(src);
782
783 for (size_type i = 0; i < src.size(); ++i)
784 src(i) = workd[ipntr[0] - 1 + i];
785
786 // Multiplication with mass matrix M
787 mass_matrix.vmult(dst, src);
788
789 for (size_type i = 0; i < dst.size(); ++i)
790 workd[ipntr[1] - 1 + i] = dst(i);
791 }
792 break;
793
794 default:
795 Assert(false, ArpackExcArpackIdo(ido));
796 break;
797 }
798 }
799 break;
800 default:
801 Assert(false, ArpackExcArpackMode(mode));
802 break;
803 }
804 }
805
806 // Set number of used iterations in SolverControl
807 control().check(iparam[2], 0.);
808
809 if (info < 0)
810 {
812 {
813 Assert(false, ArpackExcArpackInfodsaupd(info));
814 }
815 else
816 Assert(false, ArpackExcArpackInfodnaupd(info));
817 }
818 else
819 {
820 // 1 - compute eigenvectors, 0 - only eigenvalues
821 int rvec = 1;
822
823 // which eigenvectors
824 char howmany = 'A';
825
826 std::vector<int> select(ncv, 1);
827
828 int ldz = n;
829
830 std::vector<double> eigenvalues_real(nev + 1, 0.);
831 std::vector<double> eigenvalues_im(nev + 1, 0.);
832
833 // call of ARPACK dseupd/dneupd routine
835 {
836 std::vector<double> z(ldz * nev, 0.);
837 dseupd_(&rvec,
838 &howmany,
839 select.data(),
840 eigenvalues_real.data(),
841 z.data(),
842 &ldz,
843 &sigmar,
844 bmat,
845 &n,
846 which,
847 &nev,
848 &tol,
849 resid.data(),
850 &ncv,
851 v.data(),
852 &ldv,
853 iparam.data(),
854 ipntr.data(),
855 workd.data(),
856 workl.data(),
857 &lworkl,
858 &info);
859 }
860 else
861 {
862 std::vector<double> workev(3 * ncv, 0.);
863 dneupd_(&rvec,
864 &howmany,
865 select.data(),
866 eigenvalues_real.data(),
867 eigenvalues_im.data(),
868 v.data(),
869 &ldz,
870 &sigmar,
871 &sigmai,
872 workev.data(),
873 bmat,
874 &n,
875 which,
876 &nev,
877 &tol,
878 resid.data(),
879 &ncv,
880 v.data(),
881 &ldv,
882 iparam.data(),
883 ipntr.data(),
884 workd.data(),
885 workl.data(),
886 &lworkl,
887 &info);
888 }
889
890 if (info == 1)
891 {
892 Assert(false, ArpackExcArpackInfoMaxIt(control().max_steps()));
893 }
894 else if (info == 3)
895 {
897 }
898 else if (info != 0)
899 {
901 {
902 Assert(false, ArpackExcArpackInfodseupd(info));
903 }
904 else
905 Assert(false, ArpackExcArpackInfodneupd(info));
906 }
907
908 for (unsigned int i = 0; i < nev; ++i)
909 for (unsigned int j = 0; j < n; ++j)
910 eigenvectors[i](j) = v[i * n + j];
911
912 for (unsigned int i = 0; i < nev_const; ++i)
913 eigenvalues[i] =
914 std::complex<double>(eigenvalues_real[i], eigenvalues_im[i]);
915 }
916}
917
918
919inline SolverControl &
921{
922 return solver_control;
923}
924
925#endif
926
928#endif
*  x_component_mask set(0, true)
void dseupd_(int *rvec, char *howmany, int *select, double *d, double *z, int *ldz, double *sigmar, char *bmat, unsigned int *n, char *which, unsigned int *nev, double *tol, double *resid, int *ncv, double *v, int *ldv, int *iparam, int *ipntr, double *workd, double *workl, int *lworkl, int *info)
void dsaupd_(int *ido, char *bmat, unsigned int *n, char *which, unsigned int *nev, double *tol, double *resid, int *ncv, double *v, int *ldv, int *iparam, int *ipntr, double *workd, double *workl, int *lworkl, int *info)
void dnaupd_(int *ido, char *bmat, unsigned int *n, char *which, unsigned int *nev, const double *tol, double *resid, int *ncv, double *v, int *ldv, int *iparam, int *ipntr, double *workd, double *workl, int *lworkl, int *info)
void dneupd_(int *rvec, char *howmany, int *select, double *d, double *di, double *z, int *ldz, double *sigmar, double *sigmai, double *workev, char *bmat, unsigned int *n, char *which, unsigned int *nev, double *tol, double *resid, int *ncv, double *v, int *ldv, int *iparam, int *ipntr, double *workd, double *workl, int *lworkl, int *info)
SolverControl & control() const
void set_initial_vector(const VectorType &vec)
bool initial_vector_provided
ArpackSolver(SolverControl &control, const AdditionalData &data=AdditionalData())
std::vector< double > resid
void solve(const MatrixType &B, const INVERSE &inverse, std::vector< std::complex< double > > &eigenvalues, std::vector< VectorType > &eigenvectors, const unsigned int n_eigenvalues=0)
SolverControl & solver_control
void set_shift(const std::complex< double > sigma)
const AdditionalData additional_data
virtual State check(const unsigned int step, const double check_value)
unsigned int max_steps() const
double tolerance() const
#define DEAL_II_NAMESPACE_OPEN
Definition config.h:38
#define DEAL_II_DEPRECATED_WITH_COMMENT(comment)
Definition config.h:295
#define DEAL_II_NAMESPACE_CLOSE
Definition config.h:39
static ::ExceptionBase & ArpackExcInvalidEigenvalueSize(int arg1, int arg2)
static ::ExceptionBase & ArpackExcArpackInfoMaxIt(int arg1)
static ::ExceptionBase & ArpackExcInvalidNumberofArnoldiVectors(int arg1, int arg2)
static ::ExceptionBase & ArpackExcInvalidEigenvectorSizeNonsymmetric(int arg1, int arg2)
static ::ExceptionBase & ArpackExcSmallNumberofArnoldiVectors(int arg1, int arg2)
static ::ExceptionBase & ArpackExcArpackNoShifts()
static ::ExceptionBase & ArpackExcInvalidEigenvectorSize(int arg1, int arg2)
static ::ExceptionBase & ArpackExcArpackMode(int arg1)
static ::ExceptionBase & ArpackExcInvalidNumberofEigenvalues(int arg1, int arg2)
#define Assert(cond, exc)
static ::ExceptionBase & ArpackExcArpackInfodneupd(int arg1)
#define DeclException2(Exception2, type1, type2, outsequence)
static ::ExceptionBase & ArpackExcArpackInfodsaupd(int arg1)
static ::ExceptionBase & ArpackExcArpackInfodnaupd(int arg1)
#define DeclExceptionMsg(Exception, defaulttext)
static ::ExceptionBase & ArpackExcArpackInfodseupd(int arg1)
static ::ExceptionBase & ArpackExcArpackIdo(int arg1)
#define DeclException1(Exception1, type1, outsequence)
static ::ExceptionBase & ExcMessage(std::string arg1)
std::vector< index_type > data
Definition mpi.cc:734
std::size_t size
Definition mpi.cc:733
STL namespace.
unsigned int global_dof_index
Definition types.h:92
const WhichEigenvalues eigenvalue_of_interest
const unsigned int number_of_arnoldi_vectors
std::array< Number, 1 > eigenvalues(const SymmetricTensor< 2, 1, Number > &T)
std::array< std::pair< Number, Tensor< 1, dim, Number > >, dim > eigenvectors(const SymmetricTensor< 2, dim, Number > &T, const SymmetricTensorEigenvectorMethod method=SymmetricTensorEigenvectorMethod::ql_implicit_shifts)