Flow123d
linsys_BDDC.cc
Go to the documentation of this file.
1 /*!
2  *
3  * Copyright (C) 2007 Technical University of Liberec. All rights reserved.
4  *
5  * Please make a following refer to Flow123d on your project site if you use the program for any purpose,
6  * especially for academic research:
7  * Flow123d, Research Centre: Advanced Remedial Technologies, Technical University of Liberec, Czech Republic
8  *
9  * This program is free software; you can redistribute it and/or modify it under the terms
10  * of the GNU General Public License version 3 as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
13  * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14  * See the GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License along with this program; if not,
17  * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 021110-1307, USA.
18  *
19  *
20  * $Id: la_linsys.hh 1299 2011-08-23 21:42:50Z jakub.sistek $
21  * $Revision: 1299 $
22  * $LastChangedBy: jakub.sistek $
23  * $LastChangedDate: 2011-08-23 23:42:50 +0200 (Tue, 23 Aug 2011) $
24  *
25  * @file
26  * @brief Solver based on Multilevel BDDC - using corresponding class of OpenFTL package
27  * @author Jakub Sistek
28  *
29  *
30  */
31 
32 #include <mpi.h>
33 
34 // need BDDCML wrapper
35 #ifdef HAVE_BDDCML
36  #include <map>
37  #include "la/bddcml_wrapper.hpp"
38 #endif // HAVE_BDDCML
39 
40 #include "la/linsys.hh"
41 #include "la/linsys_BDDC.hh"
42 
43 
44 
45 namespace it = Input::Type;
46 
47 
48 it::Record LinSys_BDDC::input_type = it::Record("Bddc", "Solver setting.")
50  .declare_key("max_nondecr_it", it::Integer(0), it::Default("30"),
51  "Maximum number of iterations of the linear solver with non-decreasing residual.")
52  .declare_key("number_of_levels", it::Integer(0), it::Default("2"),
53  "Number of levels in the multilevel method (=2 for the standard BDDC).")
54  .declare_key("use_adaptive_bddc", it::Bool(), it::Default("false"),
55  "Use adaptive selection of constraints in BDDCML.")
56  .declare_key("bddcml_verbosity_level", it::Integer(0,2), it::Default("0"),
57  "Level of verbosity of the BDDCML library: 0 - no output, 1 - mild output, 2 - detailed output.");
58 
59 
60 
61 LinSys_BDDC::LinSys_BDDC( const unsigned numDofsSub,
62  const Distribution * rows_ds,
63  const int matrixTypeInt,
64  const int numSubLoc,
65  const bool swap_sign )
66  : LinSys( rows_ds ),
67  swap_sign_(swap_sign)
68 {
69 #ifdef HAVE_BDDCML
70  // set type
71  //type = LinSys::BDDC;
72 
73  // from the point of view of assembly, BDDC linsys is in the ADD state
75 
77  switch ( matrixTypeInt ) {
78  case 0:
79  matrixType = la::BddcmlWrapper::GENERAL;
80  break;
81  case 1:
82  matrixType = la::BddcmlWrapper::SPD;
83  break;
84  case 2:
86  break;
87  case 3:
89  break;
90  default:
91  ASSERT( true, "Unknown matrix type %d", matrixTypeInt );
92  }
93 
94  bddcml_ = new Bddcml_( size_,
95  numDofsSub,
96  matrixType,
97  rows_ds->get_comm(),
98  numSubLoc );
99 
100  // prepare space for local solution
101  locSolution_.resize( numDofsSub );
102 
103  // identify it with PETSc vector
104  PetscErrorCode ierr;
105  PetscInt numDofsSubInt = static_cast<PetscInt>( numDofsSub );
106  ierr = VecCreateSeq( PETSC_COMM_SELF, numDofsSubInt, &locSolVec_ );
107  CHKERRV( ierr );
108 #else
109  xprintf(UsrErr, "Compiled without support for BDDCML solver.\n");
110 #endif // HAVE_BDDCML
111 }
112 
113 void LinSys_BDDC::load_mesh( const int nDim, const int numNodes, const int numDofs,
114  const std::vector<int> & inet,
115  const std::vector<int> & nnet,
116  const std::vector<int> & nndf,
117  const std::vector<int> & isegn,
118  const std::vector<int> & isngn,
119  const std::vector<int> & isvgvn,
120  const std::vector<double> & xyz,
121  const std::vector<double> & element_permeability,
122  const int meshDim )
123 {
124 #ifdef HAVE_BDDCML
125  // simply pass the data to BDDCML solver
126  isngn_.resize(isngn.size());
127  std::copy( isngn.begin(), isngn.end(), isngn_.begin() );
128  ASSERT( numDofs == size_, "Global problem size mismatch!" );
129 
130  bddcml_ -> loadRawMesh( nDim, numNodes, numDofs, inet, nnet, nndf, isegn, isngn, isvgvn, xyz, element_permeability, meshDim );
131 
132  // create a map for BDDCML to PETSc vector
133  PetscErrorCode ierr;
134 
135  // local index set
136  PetscInt numDofsSubInt = static_cast<int>( isngn_.size( ) );
138 
139  //std::cout << "IDX: \n";
140  //std::copy( idx.begin(), idx.end(), std::ostream_iterator<PetscInt>( std::cout, " " ) );
141 
142  ISLocalToGlobalMapping subdomainMapping;
143  ierr = ISLocalToGlobalMappingCreate( comm_, numDofsSubInt, &(idx[0]), PETSC_COPY_VALUES, &subdomainMapping ); CHKERRV( ierr );
144 
145  IS subdomainIndexSet;
146  IS from;
147  ierr = ISCreateStride( PETSC_COMM_SELF, numDofsSubInt, 0, 1, &subdomainIndexSet );
148  ierr = ISLocalToGlobalMappingApplyIS( subdomainMapping, subdomainIndexSet, &from );
149 
150  //ierr = ISCreateGeneral( comm_, numDofsSubInt, &(idx[0]), PETSC_COPY_VALUES, &subdomainMapping ); CHKERRV( ierr );
151  //ISView( subdomainIndexSet, PETSC_VIEWER_STDOUT_WORLD);
152 
153 
154  // create scatter from parallel PETSc vector to local indices of subdomain
155  ierr = VecScatterCreate( solution_, from, locSolVec_, subdomainIndexSet, &VSpetscToSubScatter_ ); CHKERRV( ierr );
156  ierr = ISDestroy( &subdomainIndexSet ); CHKERRV( ierr );
157  ierr = ISDestroy( &from ); CHKERRV( ierr );
158 
159  //VecScatterView(VSpetscToSubScatter_,PETSC_VIEWER_STDOUT_SELF);
160 
161  double * locSolVecArray;
162  ierr = VecGetArray( locSolVec_, &locSolVecArray ); CHKERRV( ierr );
163  std::copy( locSolution_.begin(), locSolution_.end(), locSolVecArray );
164  ierr = VecRestoreArray( locSolVec_, &locSolVecArray ); CHKERRV( ierr );
165 
166  // scatter local solutions back to global one
167  VecScatterBegin( VSpetscToSubScatter_, locSolVec_, solution_, INSERT_VALUES, SCATTER_REVERSE );
168  VecScatterEnd( VSpetscToSubScatter_, locSolVec_, solution_, INSERT_VALUES, SCATTER_REVERSE );
169 #endif // HAVE_BDDCML
170 }
171 
172 void LinSys_BDDC::mat_set_values( int nrow, int *rows, int ncol, int *cols, double *vals )
173 {
174 #ifdef HAVE_BDDCML
175  namespace ublas = boost::numeric::ublas;
176 
177  std::vector< unsigned > myRows( nrow );
178  std::vector< unsigned > myCols( ncol );
179  ublas::matrix< double > mat( nrow, ncol );
180 
181  std::copy( &(rows[0]), &(rows[nrow]), myRows.begin() );
182  std::copy( &(cols[0]), &(cols[ncol]), myCols.begin() );
183 
184  for ( unsigned i = 0; i < nrow; i++ ) {
185  for ( unsigned j = 0; j < ncol; j++ ) {
186  mat( i, j ) = vals[i*ncol + j];
187  }
188  }
189  if (swap_sign_) {
190  mat = -mat;
191  }
192 
193  bddcml_ -> insertToMatrix( mat, myRows, myCols );
194 #endif // HAVE_BDDCML
195 }
196 
197 void LinSys_BDDC::rhs_set_values( int nrow, int *rows, double *vals)
198 {
199 #ifdef HAVE_BDDCML
200  namespace ublas = boost::numeric::ublas;
201 
202  std::vector< unsigned > myRows( nrow );
203  ublas::vector< double > vec( nrow );
204 
205  std::copy( &(rows[0]), &(rows[nrow]), myRows.begin() );
206 
207  for ( unsigned i = 0; i < nrow; i++ ) {
208  vec( i ) = vals[i];
209  }
210  if (swap_sign_) {
211  vec = -vec;
212  }
213 
214  bddcml_ -> insertToRhs( vec, myRows );
215 #endif // HAVE_BDDCML
216 }
217 
218 void LinSys_BDDC::diagonal_weights_set_value( int global_index, double value )
219 {
220 #ifdef HAVE_BDDCML
221  bddcml_ -> insertToDiagonalWeights( global_index, value );
222 #endif // HAVE_BDDCML
223 }
224 
226 {
227 #ifdef HAVE_BDDCML
228  bddcml_ -> clearMatrix( );
229 #endif // HAVE_BDDCML
230 }
231 
233 {
234 #ifdef HAVE_BDDCML
235  bddcml_ -> clearRhs( );
236 #endif // HAVE_BDDCML
237 }
238 
240 {
241 #ifdef HAVE_BDDCML
242  bddcml_ -> finishMatAssembly( );
243 #endif // HAVE_BDDCML
244 }
245 
246 void LinSys_BDDC::apply_constrains( double scalar )
247 {
248 #ifdef HAVE_BDDCML
249  bddcml_ -> applyConstraints( constraints_, 1., scalar );
250 #endif // HAVE_BDDCML
251 }
252 
253 int LinSys_BDDC::solve() // ! params are not currently used
254 {
255 #ifdef HAVE_BDDCML
256  std::vector<int> * numSubAtLevels = NULL; //!< number of subdomains at levels
257 
259 
260  DBGMSG("BDDCML converged reason: %d ( 0 means OK ) \n", bddcml_ -> giveConvergedReason() );
261  DBGMSG("BDDCML converged in %d iterations. \n", bddcml_ -> giveNumIterations() );
262  DBGMSG("BDDCML estimated condition number is %f \n", bddcml_ -> giveCondNumber() );
263 
264  // download local solution
265  bddcml_ -> giveSolution( isngn_, locSolution_ );
266 
267 
268  double * locSolVecArray;
269  PetscErrorCode ierr;
270  ierr = VecGetArray( locSolVec_, &locSolVecArray );
271  std::copy( locSolution_.begin(), locSolution_.end(), locSolVecArray );
272  ierr = VecRestoreArray( locSolVec_, &locSolVecArray );
273 
274  // scatter local solutions back to global one
275  VecScatterBegin( VSpetscToSubScatter_, locSolVec_, solution_, INSERT_VALUES, SCATTER_REVERSE );
276  VecScatterEnd( VSpetscToSubScatter_, locSolVec_, solution_, INSERT_VALUES, SCATTER_REVERSE );
277 
278  // upper bound on the residual error
280 
281  return bddcml_ -> giveConvergedReason();
282 #else
283  return 0;
284 #endif // HAVE_BDDCML
285 
286 }
287 
289 {
290 #ifdef HAVE_BDDCML
291  this -> gatherSolution_( );
292  globalSolution.resize( globalSolution_.size( ) );
293  std::copy( globalSolution_.begin(), globalSolution_.end(), globalSolution.begin() );
294 #endif // HAVE_BDDCML
295 }
296 
298 {
299 #ifdef HAVE_BDDCML
300  globalSolution_.resize( globalSolution.size( ) );
301  std::copy( globalSolution.begin(), globalSolution.end(), globalSolution_.begin() );
302 #endif // HAVE_BDDCML
303 }
304 
306 {
307  // common values
308  r_tol_ = in_rec.val<double>("r_tol");
309  max_it_ = in_rec.val<int>("max_it");
310 
311  // BDDCML specific parameters
312  max_nondecr_it_ = in_rec.val<int>("max_nondecr_it");
313  number_of_levels_ = in_rec.val<int>("number_of_levels");
314  use_adaptive_bddc_ = in_rec.val<bool>("use_adaptive_bddc");
315  bddcml_verbosity_level_ = in_rec.val<int>("bddcml_verbosity_level");
316 }
317 
319 {
320 #ifdef HAVE_BDDCML
321  isngn_.clear();
322  locSolution_.clear();
323 
324  PetscErrorCode ierr;
325  ierr = VecDestroy( &locSolVec_ ); CHKERRV( ierr );
326 
327  ierr = VecScatterDestroy( &VSpetscToSubScatter_ ); CHKERRV( ierr );
328 
329  delete bddcml_;
330 #endif // HAVE_BDDCML
331 };
332 
333 // construct global solution
335 {
336 #ifdef HAVE_BDDCML
337  int ierr;
338 
339  // merge solution on root
340  int rank;
341  MPI_Comm_rank( comm_, &rank );
342  int nProc;
343  MPI_Comm_size( comm_, &nProc );
344 
345  globalSolution_.resize( size_ );
346  std::vector<double> locSolutionNeib;
347  if ( rank == 0 ) {
348  // merge my own data
349  for ( int i = 0; i < isngn_.size(); i++ ) {
350  int ind = isngn_[i];
351  globalSolution_[ind] = locSolution_[i];
352  }
353  for ( int iProc = 1; iProc < nProc; iProc++ ) {
354  // receive length
355  int length;
357  ierr = MPI_Recv( &length, 1, MPI_INT, iProc, iProc, comm_, &status );
358 
359  // receive indices
360  std::vector<int> inds( length );
361  ierr = MPI_Recv( &(inds[0]), length, MPI_INT, iProc, iProc, comm_, &status );
362 
363  // receive local solution
364  locSolutionNeib.resize( length );
365  ierr = MPI_Recv( &(locSolutionNeib[0]), length, MPI_DOUBLE, iProc, iProc, comm_, &status );
366 
367  // merge data
368  for ( int i = 0; i < length; i++ ) {
369  int ind = inds[i];
370  globalSolution_[ind] = locSolutionNeib[i];
371  }
372  }
373  }
374  else {
375  // send my solution to root
376  int length = isngn_.size();
377  ierr = MPI_Send( &length, 1, MPI_INT, 0, rank, comm_ );
378  ierr = MPI_Send( &(isngn_[0]), length, MPI_INT, 0, rank, comm_ );
379  ierr = MPI_Send( &(locSolution_[0]), length, MPI_DOUBLE, 0, rank, comm_ );
380  }
381  // broadcast global solution from root
382  ierr = MPI_Bcast( &(globalSolution_[0]), globalSolution_.size(), MPI_DOUBLE, 0, comm_ );
383 #endif // HAVE_BDDCML
384 }
385 
387 {
388  double bnorm=0.0;
389  VecNorm(locSolVec_, NORM_2, &bnorm);
390 
391  return max(a_tol_, r_tol_*bnorm);
392 }
393 
394