Flow123d  jenkins-Flow123d-windows32-release-multijob-28
linsys_PETSC.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 the original PETSc solver using MPIAIJ matrix and succesive Schur complement construction
27  * @author Jakub Sistek
28  *
29  *
30  */
31 
32 // derived from base linsys
33 #include "la/linsys_PETSC.hh"
34 #include "petscvec.h"
35 #include "petscksp.h"
36 #include "petscmat.h"
37 
38 #include <boost/bind.hpp>
39 
40 namespace it = Input::Type;
41 
42 it::Record LinSys_PETSC::input_type = it::Record("Petsc", "Solver setting.")
44  .declare_key("a_tol", it::Double(0.0), it::Default("1.0e-9"), "Absolute residual tolerance.")
45  .declare_key("options", it::String(), it::Default(""), "Options passed to PETSC before creating KSP instead of default setting.");
46 
47 
49  : LinSys( rows_ds ),
50  init_guess_nonzero(false),
51  matrix_(0)
52 {
53  // set type
54  //type = LinSys::PETSC;
55 
56  // create PETSC vectors:
57  PetscErrorCode ierr;
58  // rhs
59  v_rhs_= new double[ rows_ds_->lsize() + 1 ];
60  ierr = VecCreateMPIWithArray( comm_, 1, rows_ds_->lsize(), PETSC_DECIDE, v_rhs_, &rhs_ ); CHKERRV( ierr );
61  ierr = VecZeroEntries( rhs_ ); CHKERRV( ierr );
62 
63  params_ = "";
64  matrix_ = NULL;
65  solution_precision_ = std::numeric_limits<double>::infinity();
66  matrix_changed_ = true;
67  rhs_changed_ = true;
68 }
69 
71  : LinSys(other), params_(other.params_), v_rhs_(NULL), solution_precision_(other.solution_precision_)
72 {
73  MatCopy(other.matrix_, matrix_, DIFFERENT_NONZERO_PATTERN);
74  VecCopy(other.rhs_, rhs_);
75  VecCopy(other.on_vec_, on_vec_);
76  VecCopy(other.off_vec_, off_vec_);
77 }
78 
80 {
81  PetscErrorCode ierr;
82 
83  ierr = VecCreateMPI( comm_, rows_ds_->lsize(), PETSC_DECIDE, &(on_vec_) ); CHKERRV( ierr );
84  ierr = VecDuplicate( on_vec_, &(off_vec_) ); CHKERRV( ierr );
85  status_ = ALLOCATE;
86 }
87 
89 {
90  switch ( status_ ) {
91  case ALLOCATE:
92  this->preallocate_matrix( );
93  break;
94  case INSERT:
95  this->finish_assembly( MAT_FLUSH_ASSEMBLY );
96  break;
97  case ADD:
98  case DONE:
99  break;
100  default:
101  ASSERT( false, "Can not set values. Matrix is not preallocated.\n");
102  }
103  status_ = ADD;
104 }
105 
107 {
108  switch ( status_ ) {
109  case ALLOCATE:
110  this->preallocate_matrix();
111  break;
112  case ADD:
113  this->finish_assembly( MAT_FLUSH_ASSEMBLY );
114  break;
115  case INSERT:
116  case DONE:
117  break;
118  default:
119  ASSERT( false, "Can not set values. Matrix is not preallocated.\n");
120  }
121  status_ = INSERT;
122 }
123 
124 void LinSys_PETSC::mat_set_values( int nrow, int *rows, int ncol, int *cols, double *vals )
125 {
126  PetscErrorCode ierr;
127 
128  // here vals would need to be converted from double to PetscScalar if it was ever something else than double :-)
129  switch (status_) {
130  case INSERT:
131  case ADD:
132  ierr = MatSetValues(matrix_,nrow,rows,ncol,cols,vals,(InsertMode)status_); CHKERRV( ierr );
133  break;
134  case ALLOCATE:
135  this->preallocate_values(nrow,rows,ncol,cols);
136  break;
137  default: DBGMSG("LS SetValues with non allowed insert mode.\n");
138  }
139 
140  matrix_changed_ = true;
141 }
142 
143 void LinSys_PETSC::rhs_set_values( int nrow, int *rows, double *vals )
144 {
145  PetscErrorCode ierr;
146 
147  switch (status_) {
148  case INSERT:
149  case ADD:
150  ierr = VecSetValues(rhs_,nrow,rows,vals,(InsertMode)status_); CHKERRV( ierr );
151  break;
152  case ALLOCATE:
153  break;
154  default: ASSERT(false, "LinSys's status disallow set values.\n");
155  }
156 
157  rhs_changed_ = true;
158 }
159 
160 void LinSys_PETSC::preallocate_values(int nrow,int *rows,int ncol,int *cols)
161 {
162  int i,j;
163  int col;
164  PetscInt row;
165 
166  for (i=0; i<nrow; i++) {
167  row=rows[i];
168  for(j=0; j<ncol; j++) {
169  col = cols[j];
170  if (rows_ds_->get_proc(row) == rows_ds_->get_proc(col))
171  VecSetValue(on_vec_,row,1.0,ADD_VALUES);
172  else
173  VecSetValue(off_vec_,row,1.0,ADD_VALUES);
174  }
175  }
176 }
177 
179 {
180  ASSERT(status_ == ALLOCATE, "Linear system has to be in ALLOCATE status.");
181 
182  PetscErrorCode ierr;
183  PetscInt *on_nz, *off_nz;
184  PetscScalar *on_array, *off_array;
185 
186  // assembly and get values from counting vectors, destroy them
187  VecAssemblyBegin(on_vec_);
188  VecAssemblyBegin(off_vec_);
189 
190  on_nz = new PetscInt[ rows_ds_->lsize() ];
191  off_nz = new PetscInt[ rows_ds_->lsize() ];
192 
193  VecAssemblyEnd(on_vec_);
194  VecAssemblyEnd(off_vec_);
195 
196  VecGetArray( on_vec_, &on_array );
197  VecGetArray( off_vec_, &off_array );
198 
199  for ( unsigned int i=0; i<rows_ds_->lsize(); i++ ) {
200  on_nz[i] = static_cast<PetscInt>( on_array[i]+0.1 ); // small fraction to ensure correct rounding
201  off_nz[i] = static_cast<PetscInt>( off_array[i]+0.1 );
202  }
203 
204  VecRestoreArray(on_vec_,&on_array);
205  VecRestoreArray(off_vec_,&off_array);
206  VecDestroy(&on_vec_);
207  VecDestroy(&off_vec_);
208 
209  // create PETSC matrix with preallocation
210  if (matrix_ != NULL)
211  {
212  ierr = MatDestroy(&matrix_); CHKERRV( ierr );
213  }
214  ierr = MatCreateAIJ(PETSC_COMM_WORLD, rows_ds_->lsize(), rows_ds_->lsize(), PETSC_DETERMINE, PETSC_DETERMINE,
215  0, on_nz, 0, off_nz, &matrix_); CHKERRV( ierr );
216 
217  if (symmetric_) MatSetOption(matrix_, MAT_SYMMETRIC, PETSC_TRUE);
218  MatSetOption(matrix_, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_TRUE);
219 
220  delete[] on_nz;
221  delete[] off_nz;
222 }
223 
225 {
226  MatAssemblyType assemblyType = MAT_FINAL_ASSEMBLY;
227  this->finish_assembly( assemblyType );
228 }
229 
230 void LinSys_PETSC::finish_assembly( MatAssemblyType assembly_type )
231 {
232  PetscErrorCode ierr;
233 
234  if (status_ == ALLOCATE) {
235  xprintf(Warn, "Finalizing linear system without setting values.\n");
236  this->preallocate_matrix();
237  }
238  ierr = MatAssemblyBegin(matrix_, assembly_type); CHKERRV( ierr );
239  ierr = VecAssemblyBegin(rhs_); CHKERRV( ierr );
240  ierr = MatAssemblyEnd(matrix_, assembly_type); CHKERRV( ierr );
241  ierr = VecAssemblyEnd(rhs_); CHKERRV( ierr );
242 
243  if (assembly_type == MAT_FINAL_ASSEMBLY) status_ = DONE;
244 
245  matrix_changed_ = true;
246  rhs_changed_ = true;
247 }
248 
249 void LinSys_PETSC::apply_constrains( double scalar )
250 {
251  PetscErrorCode ierr;
252 
253  // check that system matrix is assembled
254  ASSERT ( status_ == DONE, "System matrix and right-hand side are not assembled when applying constraints." );
255 
256  // number of constraints
257  PetscInt numConstraints = static_cast<PetscInt>( constraints_.size() );
258 
259  // Additional multiplier for numerical reasons (criterion to be established)
260  const PetscScalar diagScalar = static_cast<PetscScalar>( scalar );
261 
262  std::vector<PetscInt> globalDofs;
264 
265  // Constraint iterators
266  ConstraintVec_::const_iterator cIter = constraints_.begin( );
267  ConstraintVec_::const_iterator cEnd = constraints_.end( );
268  // collect global dof indices and the correpsonding values
269  for ( ; cIter != cEnd; ++cIter ) {
270  globalDofs.push_back( static_cast<PetscInt>( cIter -> first ) );
271  values.push_back( static_cast<PetscScalar>( cIter -> second ) * diagScalar );
272  }
273 
274  // prepare pointers to be passed to PETSc
275  PetscInt * globalDofPtr = this->makePetscPointer_( globalDofs );
276  PetscScalar * valuePtr = this->makePetscPointer_( values );
277 
278  // set matrix rows to zero
279  ierr = MatZeroRows( matrix_, numConstraints, globalDofPtr, diagScalar, PETSC_NULL, PETSC_NULL ); CHKERRV( ierr );
280  matrix_changed_ = true;
281 
282  // set RHS entries to values (crashes if called with NULL pointers)
283  if ( numConstraints ) {
284  ierr = VecSetValues( rhs_, numConstraints, globalDofPtr, valuePtr, INSERT_VALUES ); CHKERRV( ierr );
285  rhs_changed_ = true;
286  }
287 
288  // perform communication in the rhs vector
289  ierr = VecAssemblyBegin( rhs_ ); CHKERRV( ierr );
290  ierr = VecAssemblyEnd( rhs_ ); CHKERRV( ierr );
291 }
292 
293 
295 {
296  init_guess_nonzero = set_nonzero;
297 }
298 
299 
301 {
302  KSP system;
303  KSPConvergedReason reason;
304 
305  const char *petsc_dflt_opt;
306  //const char *petsc_str;
307  int nits;
308 
309  // -mat_no_inode ... inodes are usefull only for
310  // vector problems e.g. MH without Schur complement reduction
311  if (rows_ds_->np() > 1) {
312  // parallel setting
313  if (this->is_positive_definite())
314  petsc_dflt_opt="-ksp_type bcgs -ksp_diagonal_scale_fix -pc_type asm -pc_asm_overlap 4 -sub_pc_type ilu -sub_pc_factor_levels 3 -sub_pc_factor_fill 6.0";
315  //petsc_dflt_opt="-ksp_type preonly -pc_type cholesky -pc_factor_mat_solver_package mumps -mat_mumps_sym 1";
316  // -ksp_type preonly -pc_type lu
317  else
318  petsc_dflt_opt="-ksp_type bcgs -ksp_diagonal_scale_fix -pc_type asm -pc_asm_overlap 4 -sub_pc_type ilu -sub_pc_factor_levels 3";
319 
320  }
321  else {
322  // serial setting
323  if (this->is_positive_definite())
324  petsc_dflt_opt="-ksp_type cg -pc_type ilu -pc_factor_levels 3 -ksp_diagonal_scale_fix -pc_factor_shift_positive_definite -pc_factor_fill 6.0";
325  else
326  petsc_dflt_opt="-ksp_type bcgs -pc_type ilu -pc_factor_levels 5 -ksp_diagonal_scale_fix -pc_factor_shift_positive_definite";
327  }
328 
329  if (params_ == "") params_ = petsc_dflt_opt;
330  //petsc_str = params.c_str();
331  xprintf(MsgLog,"inserting petsc options: %s\n",params_.c_str());
332  PetscOptionsInsertString(params_.c_str()); // overwrites previous options values
333  //xfree(petsc_str);
334 
335  MatSetOption( matrix_, MAT_USE_INODES, PETSC_FALSE );
336 
337  KSPCreate( comm_, &system );
338  KSPSetOperators(system, matrix_, matrix_, DIFFERENT_NONZERO_PATTERN);
339 
340  // TODO take care of tolerances - shall we support both input file and command line petsc setting
341  //double solver_accurany = OptGetDbl("Solver","Solver_accurancy","1.0e-7");
342  //double r_tol = OptGetDbl("Solver", "r_tol", "-1" );
343  //if (r_tol < 0) r_tol=solver_accuracy;
344  //double a_tol = OptGetDbl("Solver", "a_tol", "1.0e-9" );
345  KSPSetTolerances(system, r_tol_, a_tol_, PETSC_DEFAULT,PETSC_DEFAULT);
346  KSPSetFromOptions(system);
347  // We set the KSP flag set_initial_guess_nonzero
348  // unless KSP type is preonly.
349  // In such case PETSc fails (version 3.4.1)
350  if (init_guess_nonzero)
351  {
352  KSPType type;
353  KSPGetType(system, &type);
354  if (strcmp(type, KSPPREONLY) != 0)
355  KSPSetInitialGuessNonzero(system, PETSC_TRUE);
356  }
357 
358  KSPSolve(system, rhs_, solution_ );
359  KSPGetConvergedReason(system,&reason);
360  KSPGetIterationNumber(system,&nits);
361 
362  // substitute by PETSc call for residual
363  VecNorm(rhs_, NORM_2, &residual_norm_);
364 
365  xprintf(MsgLog,"convergence reason %d, number of iterations is %d\n", reason, nits);
366 
367  // get residual norm
368  KSPGetResidualNorm(system, &solution_precision_);
369 
370  // TODO: I do not understand this
371  //Profiler::instance()->set_timer_subframes("SOLVING MH SYSTEM", nits);
372 
373  KSPDestroy(&system);
374 
375  return static_cast<int>(reason);
376 
377 }
378 
380 {
381  this -> gatherSolution_( );
382  globalSolution.resize( globalSolution_.size( ) );
383  std::copy( globalSolution_.begin(), globalSolution_.end(), globalSolution.begin() );
384 }
385 
387 {
388  std::string matFileName = "flow123d_matrix.m";
389  std::string rhsFileName = "flow123d_rhs.m";
390  std::string solFileName = "flow123d_sol.m";
391 
392  PetscViewer myViewer;
393 
394  PetscViewerASCIIOpen(comm_,matFileName.c_str(),&myViewer);
395  PetscViewerSetFormat(myViewer,PETSC_VIEWER_ASCII_MATLAB);
396  MatView( matrix_, myViewer );
397  PetscViewerDestroy(&myViewer);
398 
399  PetscViewerASCIIOpen(comm_,rhsFileName.c_str(),&myViewer);
400  PetscViewerSetFormat(myViewer,PETSC_VIEWER_ASCII_MATLAB);
401  VecView( rhs_, myViewer );
402  PetscViewerDestroy(&myViewer);
403 
404  if ( solution_ != NULL ) {
405  PetscViewerASCIIOpen(comm_,solFileName.c_str(),&myViewer);
406  PetscViewerSetFormat(myViewer,PETSC_VIEWER_ASCII_MATLAB);
407  VecView( solution_, myViewer );
408  PetscViewerDestroy(&myViewer);
409  }
410 }
411 
413 {
414  PetscErrorCode ierr;
415 
416  if (matrix_ != NULL) { ierr = MatDestroy(&matrix_); CHKERRV( ierr ); }
417  ierr = VecDestroy(&rhs_); CHKERRV( ierr );
418 
419  if (v_rhs_ != NULL) delete[] v_rhs_;
420 }
421 
423 {
424  // unsigned
425  unsigned globalSize = rows_ds_->size( );
426 
427  // create a large local solution vector for gathering
428  PetscErrorCode ierr;
429  Vec solutionGathered; //!< large vector of global solution stored locally
430  //ierr = VecCreateSeq( PETSC_COMM_SELF, globalSize, &solutionGathered ); CHKERRV( ierr );
431 
432  // prepare gathering scatter
433  VecScatter VSdistToLarge; //!< scatter for gathering local parts into large vector
434  ierr = VecScatterCreateToAll( solution_, &VSdistToLarge, &solutionGathered ); CHKERRV( ierr );
435  //ierr = VecScatterCreate( solution_, PETSC_NULL, solutionGathered, PETSC_NULL, &VSdistToLarge ); CHKERRV( ierr );
436 
437  // get global solution vector at each process
438  ierr = VecScatterBegin( VSdistToLarge, solution_, solutionGathered, INSERT_VALUES, SCATTER_FORWARD ); CHKERRV( ierr );
439  ierr = VecScatterEnd( VSdistToLarge, solution_, solutionGathered, INSERT_VALUES, SCATTER_FORWARD ); CHKERRV( ierr );
440 
441  // extract array of global solution for copy
442  PetscScalar *solutionGatheredArray;
443  ierr = VecGetArray( solutionGathered, &solutionGatheredArray );
444 
445  // copy the result to calling routine
446  //std::transform( &(solutionGatheredArray[0]), &(solutionGatheredArray[ globalSize ]), sol_disordered.begin( ),
447  // LinSys_PETSC::PetscScalar2Double_( ) ) ;
448 
449  //reorder solution
450  globalSolution_.resize( globalSize );
451  for ( unsigned int i = 0; i < globalSize; i++ ) {
452  globalSolution_[i] = static_cast<double>( solutionGatheredArray[i] );
453  }
454 
455  // release array
456  ierr = VecRestoreArray( solutionGathered, &solutionGatheredArray );
457 
458  // destroy PETSc objects
459  ierr = VecDestroy( &solutionGathered ); CHKERRV( ierr );
460  ierr = VecScatterDestroy( &VSdistToLarge ); CHKERRV( ierr );
461 }
462 
463 
465 {
466  if (! in_rec.is_empty()) {
467  // common values
468  LinSys::set_from_input( in_rec );
469 
470  // PETSc specific setting
471  a_tol_ = in_rec.val<double>("a_tol");
472  params_ = in_rec.val<string>("options");
473  }
474 }
475 
476 
478 {
479  return solution_precision_;
480 }
481 
std::vector< double > globalSolution_
global solution in numbering for linear system
Definition: linsys.hh:621
unsigned int size() const
get global size
unsigned int get_proc(unsigned int idx) const
get processor of the given index
SetValuesMode status_
Set value status of the linear system.
Definition: linsys.hh:598
#define DBGMSG(...)
Definition: global_defs.h:195
void start_insert_assembly()
void apply_constrains(double scalar=1.)
Solver based on the original PETSc solver using MPIAIJ matrix and succesive Schur complement construc...
virtual void set_from_input(const Input::Record in_rec)
Definition: linsys.hh:570
bool matrix_changed_
true if the matrix was changed since the last solve
Definition: linsys.hh:610
double * v_rhs_
local RHS array pointing to Vec rhs_
Class Input::Type::Default specifies default value of keys of a Input::Type::Record.
Definition: type_record.hh:39
LinSys_PETSC(const Distribution *rows_ds)
Definition: linsys_PETSC.cc:48
bool symmetric_
Definition: linsys.hh:605
ConstraintVec_ constraints_
Definition: linsys.hh:619
Vec rhs_
PETSc vector constructed with vx array.
Record & derive_from(AbstractRecord &parent)
Definition: type_record.cc:172
static Input::Type::Record input_type
Definition: linsys_PETSC.hh:46
void set_from_input(const Input::Record in_rec)
void preallocate_values(int nrow, int *rows, int ncol, int *cols)
void rhs_set_values(int nrow, int *rows, double *vals)
bool rhs_changed_
true if the right hand side was changed since the last solve
Definition: linsys.hh:611
Definition: system.hh:75
void gatherSolution_()
#define ASSERT(...)
Definition: global_defs.h:120
Class for declaration of the input data that are floating point numbers.
Definition: type_base.hh:376
MPI_Comm comm_
Definition: linsys.hh:597
Definition: system.hh:75
static Input::Type::AbstractRecord input_type
Definition: linsys.hh:92
T * makePetscPointer_(std::vector< T > &array)
Accessor to the data with type Type::Record.
Definition: accessors.hh:308
const Ret val(const string &key) const
#define xprintf(...)
Definition: system.hh:104
const Distribution * rows_ds_
final distribution of rows of MH matrix
Definition: linsys.hh:603
double a_tol_
Definition: linsys.hh:594
void finish_assembly()
bool is_empty() const
Definition: accessors.hh:382
unsigned int np() const
get num of processors
double residual_norm_
local solution array pointing into Vec solution_
Definition: linsys.hh:617
Vec on_vec_
Vectors for counting non-zero entries in diagonal block.
void preallocate_matrix()
void start_allocation()
Definition: linsys_PETSC.cc:79
void get_whole_solution(std::vector< double > &globalSolution)
LinSysType type
Particular type of the linear system.
std::string params_
command-line-like options for the PETSc solver
void mat_set_values(int nrow, int *rows, int ncol, int *cols, double *vals)
void start_add_assembly()
Definition: linsys_PETSC.cc:88
Vec off_vec_
Vectors for counting non-zero entries in off-diagonal block.
double r_tol_
Definition: linsys.hh:593
double get_solution_precision()
Abstract linear system class.
bool is_positive_definite()
Definition: linsys.hh:525
void set_initial_guess_nonzero(bool set_nonzero=true)
Mat matrix_
Petsc matrix of the problem.
Record type proxy class.
Definition: type_record.hh:161
bool init_guess_nonzero
flag for starting from nonzero guess
Vec solution_
PETSc vector constructed with vb array.
Definition: linsys.hh:613
double solution_precision_
unsigned int lsize(int proc) const
get local size
Record & declare_key(const string &key, const KeyType &type, const Default &default_value, const string &description)
Definition: type_record.cc:390