KASKADE 7 development version
bddc.hh
Go to the documentation of this file.
1
2/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
3/* */
4/* This file is part of the library KASKADE 7 */
5/* https://www.zib.de/research/projects/kaskade7-finite-element-toolbox */
6/* */
7/* Copyright (C) 2022-2024 Zuse Institute Berlin */
8/* */
9/* KASKADE 7 is distributed under the terms of the ZIB Academic License. */
10/* see $KASKADE/academic.txt */
11/* */
12/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
13
14#ifndef BDDC_HH
15#define BDDC_HH
16
17#include "fem/firstless.hh"
18#include "linalg/direct.hh"
21#include "utilities/enums.hh"
22
23#include "dune/istl/bcrsmatrix.hh"
24
32namespace Kaskade::BDDC
33{
41 using CoarseConstraints = std::vector<std::pair<std::vector<int>,int>>;
42
54 struct LocalDof
55 {
56 int s; // subdomain number
57 int i; // local dof index in subdomain
58 };
59
64 enum InterfaceType { CORNER = 1, EDGE = 2, FACE = 4 };
65
73 template <int m=1, class Index=size_t>
75 {
76 public:
77 constexpr static int components = m;
78
88 InterfaceAverages(std::vector<std::vector<LocalDof>> const& sharedDofs,
89 std::vector<Index> const& subdomainSize,
90 int types = CORNER | FACE);
91
97 Interfaces const& interfaces(int id) const;
98
107 template <class Scalar=double>
109
117
121 std::array<int,3> interfaceCount() const
122 {
123 return ifCount;
124 }
125
126 private:
127 std::vector<Interfaces> ifs;
129 std::vector<Index> subdomainSize;
130
131 std::vector<std::vector<std::vector<int>>> cifs; // coarse interfaces
132 std::array<int,3> ifCount; // number of corners, edges, faces
133 };
134
135 // ----------------------------------------------------------------------------------------------
136
137
138 // ----------------------------------------------------------------------------------------------
139
140
177 template <int m, class Scalar_=double, class CoarseScalar=Scalar_,
178 class Transfer=SpaceTransfer<m,Scalar_> >
180 {
181 public:
185 static const int components = m;
186
190 using Scalar = Scalar_;
191
195
199 using TransmissionType = typename Transfer::TransmissionType;
200
201
203
206
226 template <int cComponents>
227 Subdomain(int id, AMatrix const& A,
228 Interfaces const& interfaces,
230
231 template <class Interface>
232 Subdomain(int id, AMatrix const& A, Interface const& ifs);
233
236
241 void update_rhs(XVector const& f);
242
248 void getInterfaceAveragingWeights(int s, XVector& rho) const
249 {
250 trans.getInterfaceAveragingWeights(s,rho);
251 }
252
258 void setInterfaceAveragingWeights(int s, XVector const& rho)
259 {
260 trans.setInterfaceAveragingWeights(s,rho);
261 }
262
270 std::vector<int> neighbors() const;
271
314
322 {
323 trans.getInterfaceResidualUpdate(s,dres);
324 }
325
332 {
333 trans.setInterfaceResidualUpdate(s,dres);
334 }
335
339 void restrict();
340
342
359 void getS(SMatrix& S) const;
360
374 void getSchurResidual(Vector& lambda) const;
375
379 void setCorrection(Vector const& c);
380
382
417 {
418 trans.preProlongate(du);
419 }
420
425 void getInterfaceValues(int s, TransmissionType& values) const
426 {
427 trans.getInterfaceValues(s,values);
428 }
429
435 void setInterfaceValues(int s, TransmissionType const& values)
436 {
437 trans.setInterfaceValues(s,values);
438 }
439
440 void setActiveId(bool active){
441 activeId = active;
442 }
451
453
457 void updateSearchDirection(double beta);
458
460
465
471 void getSolution(XVector& x) const;
472
482
486 void set_solver_type(bool cg_solver);
487 void updateIteration(int cg_itr);
493 void getCorrection(XVector& dx) const;
494 void getRawCorrection(XVector& dx) const;
495 void getResidual(XVector& rr) const;
496 Vector const& getRestrictedResidual() const { return restrictedResidual; }
497
498
499 std::vector<bool> getActiveSubdomains()
500 {
501 return activeSubdomains_sub;
502 }
503
504 void setActiveSubdomains_sub(std::vector<bool> & activeSubdomains_)
505 {
506 activeSubdomains_sub.resize(activeSubdomains_.size());
507 // std::cout<< "activeSubdomains_.size() = "<<activeSubdomains_.size() <<std::endl;
508 for (int i = 0; i < activeSubdomains_.size(); ++i)
509 {
510 activeSubdomains_sub[i] = activeSubdomains_[i];
511 }
512 }
513
514
515 private:
517
518 // These variables describe problem size and connectivity
519 int id; // my own subdomain number
520 int N;
521 int nx, nc; // number of dofs and of constraints
522 Interfaces interfaces; // list of pairs (s,ids) of adjacent subdomain s and shared dofs
523 Transfer trans; // manages data conversion and averaging
524
525 Vector f; // the right hand side
526 Vector u; // approximate solution [x,lambda]
527 Vector r; // current residual [f-Au,0]
528 Vector rRes; // restricted residual
529
530 Vector q; // search direction for [CG]
531 Vector q_pre; // search direction for [CG]
532 Vector Aq; // for [CG]
533 Vector r_bar; // previous residual for [CG]
534 Scalar alpha; // step size for [CG]
535 bool cg_solver; // cg = false -> steepest descent method with BDDC, cg = true -> CG with BDDC
536 int cg_itr;
537
538 Vector du; // correction [dx,0]
539 Vector Adu; // matrix times correction
540
541 BMatrix A;
542 BMatrix C;
543 DirectSolver<Vector,Vector> Binv; // [ A C^T; C 0 ]^{-1}
544
545 bool activeId = true;
546
547 std::vector<int> interiorDofs; // the interior dof indices
548 std::vector<int> interfaceDofs; // the boundary/interface dof indices
549 std::vector<bool> activeSubdomains_sub;
550 // for debugging purposes
551 Vector rawCorrection, residual, restrictedResidual;
552
553 std::vector<int> globalIndex_notActive;
554
555BMatrix Aii;
557std::vector<int> cIndices;
558mutable DynamicMatrix<double> X; // const hack, move computation to constructor
559
560 // Solves the homogeneous Dirichlet problem A_ii x_i = r_i for the interior nodes only.
561 // Non-zero boundary values x_D can be imposed by exploiting the splitting
562 // [Aii AiD] [x_i x_D]^T = r_i <=> Aii x_i = r_i - AiD xD, i.e. modifying the right hand side.
563 // The interface nodes of x are not touched, nor is the constraint/multiplier part.
564 void solveDirichlet(Vector& x, Vector const& rhs) const;
565 };
566
567 // ----------------------------------------------------------------------------------------------
568 // ----------------------------------------------------------------------------------------------
569
574 template <class Subdomain>
576 {
577 public:
579 using Scalar = typename Subdom::Scalar;
580 using Vector = typename Subdom::Vector;
581 using XVector = typename Subdom::XVector;
582 static constexpr int m = Subdom::components;
583
584 SharedMemoryDomain(std::vector<Subdom>& subdomains);
585
594
601 void restrict();
602
603 void updateSearchDirection(double beta); // CG
604
608 int size() const
609 {
610 return subdomains->size();
611 }
612
613 std::vector<DynamicMatrix<Dune::FieldMatrix<Scalar,1,1>>> getS() const;
614 std::vector<Vector> getSchurResiduals();
615 void setCorrections(std::vector<Vector> const& dcs);
616
619
620 void set_solver_type(bool cg_solver);
622
623 std::vector<bool> getActiveSubdomains()
624 {
625 return activeSubdomains;
626 }
627
628 void setActiveSubdomains(std::vector<int> & activeIds)
629 {
630 std::cout << "activeIds.size() = " << activeIds.size() <<std::endl;
631 activeSubdomains.resize(size());
632 for (int i = 0; i < activeIds.size(); ++i)
633 {
634 activeSubdomains[activeIds[i]] = true;
635 }
636 }
645 std::array<int,6> traffic() const
646 {
647 return std::array<int,6>{exchangeCount,transfers,initTraffic,restrictionTraffic,
648 prolongationTraffic,coarseGridTraffic};
649 }
650
651 private:
652 std::vector<Subdom>* subdomains;
653 std::vector<std::pair<int,int>> neighbors;
654 std::vector<bool> activeSubdomains;
655
656 // Support for monitoring the amount of data exchanged between subdomains.
657 std::mutex mutex;
658 int exchangeCount = 0; // number of iterations
659 int transfers = 0; // number of bidirectional data transfers
660 int initTraffic = 0; // amount of data (in bytes) sent during initialization
661 int restrictionTraffic = 0; // amount of data (in bytes) sent during restriction
662 int prolongationTraffic = 0; // amount of data (in bytes) sent during prolongation
663 int coarseGridTraffic = 0; // amount of data (in bytes) sent to coarse grid solver
664 };
665
666 // ----------------------------------------------------------------------------------------------
667 // ----------------------------------------------------------------------------------------------
668
760 template <class Domain>
762 {
763 public:
764 using Scalar = typename Domain::Scalar;
765 using Constraint = std::tuple<int,int,int>;
766
767 private:
769
770 public:
778 KKTSolver(Domain& domain_,
779 CoarseConstraints const& constr)
780 : domain(&domain_)
781 , constraints(domain->size())
782 , localConstraintsSize(domain->size())
783 , sOffsets(constr.size()+1)
784 {
785 // Compute the offsets of individual slack vectors s_ij into the global slack vector
786 // and the constraints in which each subdomain is involved.
787 sOffsets[0] = 0;
788 for (int k=0; k<constr.size(); ++k)
789 {
790 auto const& [s,m] = constr[k];
791 for (auto i: s)
792 {
793 assert(0<=i && i<domain->size());
794 constraints[i].push_back(k);
795 localConstraintsSize[i] += m;
796 }
797 sOffsets[k+1] = m;
798 }
799 std::partial_sum(begin(sOffsets),end(sOffsets),begin(sOffsets));
800
801 // Create Schur complement matrix B. This is sparse, since each constraint, i.e.
802 // slack variable, is only affected by two subdomains.
803 int const ns = sOffsets.back(); // Total number of slacks.
804 if (ns == 0) // If there are no coarse constraints,
805 return; // we're done - there's nothing to do.
806 NumaCRSPatternCreator<> sCreator(ns,ns,false,2);
807 for (auto const& ss: constraints) // For each subdoman find all pairs
808 for (int sRow: ss) // of incident slacks and add the
809 for (int sCol: ss) // corresponding dense block into
810 sCreator.addDenseBlock(sOffsets[sRow],sOffsets[sRow+1], // the sparsity pattern of S.
811 sOffsets[sCol],sOffsets[sCol+1]);
812
813 using Entry = Dune::FieldMatrix<Scalar,1,1>;
814 NumaBCRSMatrix<Entry> S(sCreator); // And then create the matrix.
815
816 // Assemble the Schur complement matrix.
817 using SortedIdx = std::vector<std::pair<int,int>>;
819 auto localSchurComplements = domain->getS();
820 for (int i=0; i<domain->size(); ++i)
821 {
822 SortedIdx rows;
823 int localIndex = 0 ;
824 for (int k: constraints[i])
825 for (int l=sOffsets[k]; l<sOffsets[k+1]; ++l)
826 rows.push_back({l,localIndex++});
827 assert(std::is_sorted(rows.begin(),rows.end(),FirstLess()));
828 lm.push_back(rows,rows);
829 lm.back() = localSchurComplements[i]; // add local stiffness matrix Si
830 }
831 lm.scatter();
832 S *= -1.0; // take care of correct Schur complement sign
833
836 }
837
844 void solve()
845 {
846 int const ns = sOffsets.back(); // Total number of slacks.
847
848 if (ns==0)
849 return;
850 // std::cout << "ns---> " << ns <<std::endl;
851 // Obtain right hand side of the Schur complement system. This is the sum of right
852 // hand sides from the subdomains, scattered into appropriate positions in the
853 // right hand side vector f.
854 Timings& timer = Timings::instance();
855 timer.start("get Schur rhs");
856 Vector f(ns);
857 getRightHandSide(f);
858 timer.stop("get Schur rhs");
859
860
861 std::vector<int> d(ns,1);
862 for (int i=0; i<domain->size(); ++i)
863 {
864 if(not domain->getActiveSubdomains()[i]) // vector d is a {0,1} where zero is for the interfaces
865 { // belongs to inactive subdomains
866 for (auto const k: constraints[i])
867 {
868 int const off = sOffsets[k];
869 int const nsk = sOffsets[k+1]-off;
870 for (int l=0; l<nsk; ++l)
871 d[l+off] = 0;
872 }
873 }
874 }
875
876 for (int i=0; i<ns; ++i) // assign zero on the rhs for those belongs to
877 f[i] *= d[i]; // inactive subdomains via vector d
878
879 timer.start("solve Schur system");
880 Vector s(ns); // Create zero initial slack vector
881 Sinv.apply(s,f); // and solve the global Schur system.
882 timer.stop("solve Schur system");
883
884
885 for (int i=0; i<ns; ++i) // assign zero on the slacks corresponding to
886 s[i] *= d[i]; // inactive subdomains via vector d
887
888
889 timer.start("set corrections");
890 std::vector<Vector> dcs(domain->size());
891 for (int i=0; i<domain->size(); ++i)
892 {
893 if(domain->getActiveSubdomains()[i])
894 {
895 Vector si(localConstraintsSize[i]); // gather the slacks corresponding to the
896 int pos = 0; // constraints affecting active subdomain i
897 for (auto const k: constraints[i]) // by concatenating all the slacks
898 { // corresponding to constraints in which
899 int const off = sOffsets[k]; // subdomain i is involved.
900 int const nsk = sOffsets[k+1]-off;
901 for (int l=0; l<nsk; ++l)
902 si[pos++] = s[l+off];
903 }
904 dcs[i] = si;
905 }
906 }
907 domain->setCorrections(dcs);
908 timer.stop("set corrections");
909 }
910
911
912 private:
913
914 void getRightHandSide(Vector& f) const
915 {
916 f = 0;
917 auto floc = domain->getSchurResiduals();
918
919 for (int i=0; i<domain->size(); ++i)
920 {
921 if(domain->getActiveSubdomains()[i])
922 {
923 int pos = 0; // scatter the lambda solution component
924 for (auto const k: constraints[i]) // into the right hand side vector
925 {
926 int const off = sOffsets[k];
927 int const nsk = sOffsets[k+1]-off;
928 for (int l=0; l<nsk; ++l)
929 f[l+off] += floc[i][pos++];
930 }
931 }
932 }
933 }
934
935
936 Domain* domain;
937 std::vector<std::vector<int>> constraints; // involved constraints by subdomain id
938 std::vector<int> localConstraintsSize; // total number of constraints for subdomain id
939 std::vector<int> sOffsets; // offset of slack vector in total slacks
940 DirectSolver<Vector,Vector> Sinv; // inverse of Schur complement
941 };
942
943
1070 template <class Subdomain>
1071 class BDDCSolver // TODO: implement in terms of SymmetricPreconditioner
1072 {
1073 public:
1074
1075
1077 using Scalar = typename Subdom::Scalar;
1078 using Vector = typename Subdom::Vector;
1079 static constexpr int m = Subdom::components;
1080
1086
1093 BDDCSolver(std::vector<Subdomain>& subdomains,
1094 CoarseConstraints const& constraints,
1095 std::vector<int> & activeIds,
1096 bool cg_solver=false,
1097 bool BDDC_verbose=false);
1098
1103 void update_rhs(std::vector<XVector> & Fs)
1104 {
1105 parallelFor(0,subdomains->size(),[&](int i)
1106 {
1107 (*subdomains)[i].update_rhs(Fs[i]);
1108 });
1109 }
1115 double solve();
1116
1125 std::array<int,6> traffic() const
1126 {
1127 return domain.traffic();
1128 }
1129
1130 private:
1131 using Domain = SharedMemoryDomain<Subdomain>;
1132 std::vector<Subdomain>* subdomains;
1133 Domain domain;
1134 CoarseConstraints constraints;
1135 KKTSolver<Domain> coarseSolver;
1136 std::vector<XVector> const Fs;
1137 bool cg_solver;
1138 double sigma_pre = 0;
1139 double BDDC_verbose = false;
1140 };
1141
1142}
1143
1144#endif
1145
Balanced Domain Decomposition with Constraints preconditioner.
Definition: bddc.hh:1072
BDDCSolver(std::vector< Subdomain > &subdomains, CoarseConstraints const &constraints, std::vector< int > &activeIds, bool cg_solver=false, bool BDDC_verbose=false)
Constructor.
typename Subdom::Vector Vector
Definition: bddc.hh:1078
static constexpr int m
Definition: bddc.hh:1079
double solve()
Performs a gradient step.
void update_rhs(std::vector< XVector > &Fs)
update rhs for each subdomain
Definition: bddc.hh:1103
std::array< int, 6 > traffic() const
Reports the amount of data exchanged between subdomains.
Definition: bddc.hh:1125
typename Subdom::Scalar Scalar
Definition: bddc.hh:1077
A class for computing and providing BDDC coarse space constraints (interface averages).
Definition: bddc.hh:75
CoarseConstraints coarseConstraints() const
Provides information about subdomains sharing coarse constraints.
std::array< int, 3 > interfaceCount() const
Reports on number of corners, edges, and faces.
Definition: bddc.hh:121
NumaBCRSMatrix< Dune::FieldMatrix< Scalar, m, m > > coarseConstraint(int id) const
Creates the subdomain-local constraints defining the coarse space.
static constexpr int components
Definition: bddc.hh:77
InterfaceAverages(std::vector< std::vector< LocalDof > > const &sharedDofs, std::vector< Index > const &subdomainSize, int types=CORNER|FACE)
Constructor.
Interfaces const & interfaces(int id) const
For the given subdomain, tells with which neighboring domain which dofs are shared.
A class for solving a block-diagonal-structured KKT system.
Definition: bddc.hh:762
void solve()
solves the system.
Definition: bddc.hh:844
KKTSolver(Domain &domain_, CoarseConstraints const &constr)
Constructor.
Definition: bddc.hh:778
std::tuple< int, int, int > Constraint
Definition: bddc.hh:765
typename Domain::Scalar Scalar
Definition: bddc.hh:764
A class that orchestrates the exchange of data between BDDC subdomains.
Definition: bddc.hh:576
void updateSolution(Scalar alpha)
std::array< int, 6 > traffic() const
Reports the amount of data exchanged between subdomains.
Definition: bddc.hh:645
std::vector< Vector > getSchurResiduals()
std::vector< bool > getActiveSubdomains()
Definition: bddc.hh:623
typename Subdom::XVector XVector
Definition: bddc.hh:581
void restrict()
Performs restriction in BDDC.
Dune::FieldVector< double, 2 > prolongate()
Performs prolongation in BDDC.
std::vector< DynamicMatrix< Dune::FieldMatrix< Scalar, 1, 1 > > > getS() const
Dune::FieldVector< double, 1 > updateSearchDirectionNorm()
void updateSearchDirection(double beta)
void set_solver_type(bool cg_solver)
void setActiveSubdomains(std::vector< int > &activeIds)
Definition: bddc.hh:628
SharedMemoryDomain(std::vector< Subdom > &subdomains)
typename Subdom::Vector Vector
Definition: bddc.hh:580
typename Subdom::Scalar Scalar
Definition: bddc.hh:579
static constexpr int m
Definition: bddc.hh:582
void setCorrections(std::vector< Vector > const &dcs)
int size() const
Reports the number of subdomains.
Definition: bddc.hh:608
A class representing small KKT systems on a single subdomain.
Definition: bddc.hh:180
void setCorrection(Vector const &c)
Computes the correction vector .
Subdomain(int id, AMatrix const &A, Interfaces const &interfaces, NumaBCRSMatrix< Dune::FieldMatrix< Scalar, cComponents, components > > const &C)
Constructor.
Dune::FieldVector< double, 1 > updateSearchDirectionNorm()
std::vector< int > neighbors() const
Reports a list of its neighbor subdomains.
XVector getSolution() const
Provides the current solution vector .
void updateSolution(Scalar alpha)
Updates the solution approximation.
void preRestrict()
First step of the restriction: Dirichlet solve.
void setInterfaceAveragingWeights(int s, XVector const &rho)
Accumulates interface weights of adjacent subdomains.
Definition: bddc.hh:258
void getRawCorrection(XVector &dx) const
void setActiveId(bool active)
Definition: bddc.hh:440
Dune::BlockVector< Dune::FieldVector< Scalar, 1 > > Vector
Definition: bddc.hh:194
void getCorrection(XVector &dx) const
Provides the current correction vector .
Vector const & getRestrictedResidual() const
Definition: bddc.hh:496
Dune::FieldVector< double, 2 > prolongate()
Perform averaging on the shared interfaces, projecting the solution to the subspace of functions cont...
Subdomain(int id, AMatrix const &A, Interface const &ifs)
void getS(SMatrix &S) const
Compute .
static const int components
Number of (vectorial) components of .
Definition: bddc.hh:185
void getResidual(XVector &rr) const
void set_solver_type(bool cg_solver)
Set solver type.
void preProlongate()
Prepares the exchange of interface values.
Definition: bddc.hh:416
void setInterfaceResidualUpdate(int s, TransmissionType const &dres)
Sets interface residual of the correction from neighboring subdomains.
Definition: bddc.hh:331
std::vector< bool > getActiveSubdomains()
Definition: bddc.hh:499
Scalar_ Scalar
The scalar field type used in coefficients.
Definition: bddc.hh:190
void getInterfaceAveragingWeights(int s, XVector &rho) const
Reports own interface averaging weights.
Definition: bddc.hh:248
void getSolution(XVector &x) const
Provides the current solution vector .
Dune::BlockVector< XEntry > XVector
Definition: bddc.hh:193
void update_rhs(XVector const &f)
update rhs for the current subdomain
void imposeDC_inActiveInterface(Vector &Aq, Vector &q)
void imposeDCq(Vector &q)
void getSchurResidual(Vector &lambda) const
Provides the Schur residual.
void updateSearchDirection(double beta)
Update search direction q for cg solver.
void getInterfaceResidualUpdate(int s, TransmissionType &dres) const
Gets interface residual that shall be shared with neighboring subdomain.
Definition: bddc.hh:321
void updateIteration(int cg_itr)
typename Transfer::TransmissionType TransmissionType
A container type used for exchanging coefficients between subdomains.
Definition: bddc.hh:199
void setActiveSubdomains_sub(std::vector< bool > &activeSubdomains_)
Definition: bddc.hh:504
void restrict()
Performs the restriction of the residual vector.
void getInterfaceValues(int s, TransmissionType &values) const
Gets boundary values that shall be shared with neighboring subdomain.
Definition: bddc.hh:425
void setInterfaceValues(int s, TransmissionType const &values)
Sets boundary values of the correction from neighboring subdomains.
Definition: bddc.hh:435
A structure for holding a sequence of several local matrices to be filled sequentially and to be scat...
void scatter()
Scatters the local matrices into the global one and removes them from the local container.
value_type & back()
A reference to the last pushed local matrix.
void push_back(SortedRowIdx const &ridx, SortedColIdx const &cidx)
Appends another (zero-initialized) local matrix.
A NUMA-aware compressed row storage matrix adhering mostly to the Dune ISTL interface (to complete....
A NUMA-aware creator for matrix sparsity patterns.
void addDenseBlock(Index fromRow, Index toRow, Index fromCol, Index toCol)
Enters a contiguous dense block into the sparsity pattern.
Supports gathering and reporting execution times information for nested program parts.
Definition: timing.hh:64
static Timings & instance()
Returns a reference to a single default instance.
void stop(std::string const &name)
Stops the timing of given section.
struct Times const * start(std::string const &name)
Starts or continues the timing of given section.
@ UMFPACK
UMFPack from SuiteSparse, using 32 bit integer indices.
InterfaceType
Discrimination of different interface types.
Definition: bddc.hh:64
std::vector< std::pair< int, std::vector< int > > > Interfaces
A data structure describing the interfaces of a subdomain.
void parallelFor(Func const &f, int maxTasks=std::numeric_limits< int >::max())
A parallel for loop that executes the given functor in parallel on different CPUs.
Definition: threading.hh:489
std::vector< std::pair< std::vector< int >, int > > CoarseConstraints
A data structure describing coarse constraints.
Definition: bddc.hh:41
A pair of subdomain id and local dof index denotes a subdomain-local reference to a global dof.
Definition: bddc.hh:55
A comparator functor that supports sorting std::pair by their first component.
Definition: firstless.hh:22