Flow123d  jenkins-Flow123d-windows32-release-multijob-51
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  // create PETSC vectors:
54  PetscErrorCode ierr;
55  // rhs
56  v_rhs_= new double[ rows_ds_->lsize() + 1 ];
57  ierr = VecCreateMPIWithArray( comm_, 1, rows_ds_->lsize(), PETSC_DECIDE, v_rhs_, &rhs_ ); CHKERRV( ierr );
58  ierr = VecZeroEntries( rhs_ ); CHKERRV( ierr );
59 
60  params_ = "";
61  matrix_ = NULL;
62  solution_precision_ = std::numeric_limits<double>::infinity();
63  matrix_changed_ = true;
64  rhs_changed_ = true;
65 }
66 
68  : LinSys(other), params_(other.params_), v_rhs_(NULL), solution_precision_(other.solution_precision_)
69 {
70  MatCopy(other.matrix_, matrix_, DIFFERENT_NONZERO_PATTERN);
71  VecCopy(other.rhs_, rhs_);
72  VecCopy(other.on_vec_, on_vec_);
73  VecCopy(other.off_vec_, off_vec_);
74 }
75 
77 {
78  PetscErrorCode ierr;
79 
80  ierr = VecCreateMPI( comm_, rows_ds_->lsize(), PETSC_DECIDE, &(on_vec_) ); CHKERRV( ierr );
81  ierr = VecDuplicate( on_vec_, &(off_vec_) ); CHKERRV( ierr );
82  status_ = ALLOCATE;
83 }
84 
86 {
87  switch ( status_ ) {
88  case ALLOCATE:
89  this->preallocate_matrix( );
90  break;
91  case INSERT:
92  this->finish_assembly( MAT_FLUSH_ASSEMBLY );
93  break;
94  case ADD:
95  case DONE:
96  break;
97  default:
98  ASSERT( false, "Can not set values. Matrix is not preallocated.\n");
99  }
100  status_ = ADD;
101 }
102 
104 {
105  switch ( status_ ) {
106  case ALLOCATE:
107  this->preallocate_matrix();
108  break;
109  case ADD:
110  this->finish_assembly( MAT_FLUSH_ASSEMBLY );
111  break;
112  case INSERT:
113  case DONE:
114  break;
115  default:
116  ASSERT( false, "Can not set values. Matrix is not preallocated.\n");
117  }
118  status_ = INSERT;
119 }
120 
121 void LinSys_PETSC::mat_set_values( int nrow, int *rows, int ncol, int *cols, double *vals )
122 {
123  PetscErrorCode ierr;
124 
125  // here vals would need to be converted from double to PetscScalar if it was ever something else than double :-)
126  switch (status_) {
127  case INSERT:
128  case ADD:
129  ierr = MatSetValues(matrix_,nrow,rows,ncol,cols,vals,(InsertMode)status_); CHKERRV( ierr );
130  break;
131  case ALLOCATE:
132  this->preallocate_values(nrow,rows,ncol,cols);
133  break;
134  default: DBGMSG("LS SetValues with non allowed insert mode.\n");
135  }
136 
137  matrix_changed_ = true;
138 }
139 
140 void LinSys_PETSC::rhs_set_values( int nrow, int *rows, double *vals )
141 {
142  PetscErrorCode ierr;
143 
144  switch (status_) {
145  case INSERT:
146  case ADD:
147  ierr = VecSetValues(rhs_,nrow,rows,vals,(InsertMode)status_); CHKERRV( ierr );
148  break;
149  case ALLOCATE:
150  break;
151  default: ASSERT(false, "LinSys's status disallow set values.\n");
152  }
153 
154  rhs_changed_ = true;
155 }
156 
157 void LinSys_PETSC::preallocate_values(int nrow,int *rows,int ncol,int *cols)
158 {
159  int i,j;
160  int col;
161  PetscInt row;
162 
163  for (i=0; i<nrow; i++) {
164  row=rows[i];
165  for(j=0; j<ncol; j++) {
166  col = cols[j];
167  if (rows_ds_->get_proc(row) == rows_ds_->get_proc(col))
168  VecSetValue(on_vec_,row,1.0,ADD_VALUES);
169  else
170  VecSetValue(off_vec_,row,1.0,ADD_VALUES);
171  }
172  }
173 }
174 
176 {
177  ASSERT(status_ == ALLOCATE, "Linear system has to be in ALLOCATE status.");
178 
179  PetscErrorCode ierr;
180  PetscInt *on_nz, *off_nz;
181  PetscScalar *on_array, *off_array;
182 
183  // assembly and get values from counting vectors, destroy them
184  VecAssemblyBegin(on_vec_);
185  VecAssemblyBegin(off_vec_);
186 
187  on_nz = new PetscInt[ rows_ds_->lsize() ];
188  off_nz = new PetscInt[ rows_ds_->lsize() ];
189 
190  VecAssemblyEnd(on_vec_);
191  VecAssemblyEnd(off_vec_);
192 
193  VecGetArray( on_vec_, &on_array );
194  VecGetArray( off_vec_, &off_array );
195 
196  for ( unsigned int i=0; i<rows_ds_->lsize(); i++ ) {
197  on_nz[i] = static_cast<PetscInt>( on_array[i]+0.1 ); // small fraction to ensure correct rounding
198  off_nz[i] = static_cast<PetscInt>( off_array[i]+0.1 );
199  }
200 
201  VecRestoreArray(on_vec_,&on_array);
202  VecRestoreArray(off_vec_,&off_array);
203  VecDestroy(&on_vec_);
204  VecDestroy(&off_vec_);
205 
206  // create PETSC matrix with preallocation
207  if (matrix_ != NULL)
208  {
209  ierr = MatDestroy(&matrix_); CHKERRV( ierr );
210  }
211  ierr = MatCreateAIJ(PETSC_COMM_WORLD, rows_ds_->lsize(), rows_ds_->lsize(), PETSC_DETERMINE, PETSC_DETERMINE,
212  0, on_nz, 0, off_nz, &matrix_); CHKERRV( ierr );
213 
214  if (symmetric_) MatSetOption(matrix_, MAT_SYMMETRIC, PETSC_TRUE);
215  MatSetOption(matrix_, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_TRUE);
216 
217  delete[] on_nz;
218  delete[] off_nz;
219 }
220 
222 {
223  MatAssemblyType assemblyType = MAT_FINAL_ASSEMBLY;
224  this->finish_assembly( assemblyType );
225 }
226 
227 void LinSys_PETSC::finish_assembly( MatAssemblyType assembly_type )
228 {
229  PetscErrorCode ierr;
230 
231  if (status_ == ALLOCATE) {
232  xprintf(Warn, "Finalizing linear system without setting values.\n");
233  this->preallocate_matrix();
234  }
235  ierr = MatAssemblyBegin(matrix_, assembly_type); CHKERRV( ierr );
236  ierr = VecAssemblyBegin(rhs_); CHKERRV( ierr );
237  ierr = MatAssemblyEnd(matrix_, assembly_type); CHKERRV( ierr );
238  ierr = VecAssemblyEnd(rhs_); CHKERRV( ierr );
239 
240  if (assembly_type == MAT_FINAL_ASSEMBLY) status_ = DONE;
241 
242  matrix_changed_ = true;
243  rhs_changed_ = true;
244 }
245 
246 void LinSys_PETSC::apply_constrains( double scalar )
247 {
248  PetscErrorCode ierr;
249 
250  // check that system matrix is assembled
251  ASSERT ( status_ == DONE, "System matrix and right-hand side are not assembled when applying constraints." );
252 
253  // number of constraints
254  PetscInt numConstraints = static_cast<PetscInt>( constraints_.size() );
255 
256  // Additional multiplier for numerical reasons (criterion to be established)
257  const PetscScalar diagScalar = static_cast<PetscScalar>( scalar );
258 
259  std::vector<PetscInt> globalDofs;
261 
262  // Constraint iterators
263  ConstraintVec_::const_iterator cIter = constraints_.begin( );
264  ConstraintVec_::const_iterator cEnd = constraints_.end( );
265  // collect global dof indices and the correpsonding values
266  for ( ; cIter != cEnd; ++cIter ) {
267  globalDofs.push_back( static_cast<PetscInt>( cIter -> first ) );
268  values.push_back( static_cast<PetscScalar>( cIter -> second ) * diagScalar );
269  }
270 
271  // prepare pointers to be passed to PETSc
272  PetscInt * globalDofPtr = this->makePetscPointer_( globalDofs );
273  PetscScalar * valuePtr = this->makePetscPointer_( values );
274 
275  // set matrix rows to zero
276  ierr = MatZeroRows( matrix_, numConstraints, globalDofPtr, diagScalar, PETSC_NULL, PETSC_NULL ); CHKERRV( ierr );
277  matrix_changed_ = true;
278 
279  // set RHS entries to values (crashes if called with NULL pointers)
280  if ( numConstraints ) {
281  ierr = VecSetValues( rhs_, numConstraints, globalDofPtr, valuePtr, INSERT_VALUES ); CHKERRV( ierr );
282  rhs_changed_ = true;
283  }
284 
285  // perform communication in the rhs vector
286  ierr = VecAssemblyBegin( rhs_ ); CHKERRV( ierr );
287  ierr = VecAssemblyEnd( rhs_ ); CHKERRV( ierr );
288 }
289 
290 
292 {
293  init_guess_nonzero = set_nonzero;
294 }
295 
296 
298 {
299  KSP system;
300  KSPConvergedReason reason;
301 
302  const char *petsc_dflt_opt;
303  int nits;
304 
305  // -mat_no_inode ... inodes are usefull only for
306  // vector problems e.g. MH without Schur complement reduction
307  if (rows_ds_->np() > 1) {
308  // parallel setting
309  if (this->is_positive_definite())
310  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";
311  //petsc_dflt_opt="-ksp_type preonly -pc_type cholesky -pc_factor_mat_solver_package mumps -mat_mumps_sym 1";
312  // -ksp_type preonly -pc_type lu
313  else
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";
315 
316  }
317  else {
318  // serial setting
319  if (this->is_positive_definite())
320  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";
321  else
322  petsc_dflt_opt="-ksp_type bcgs -pc_type ilu -pc_factor_levels 5 -ksp_diagonal_scale_fix -pc_factor_shift_positive_definite";
323  }
324 
325  if (params_ == "") params_ = petsc_dflt_opt;
326  xprintf(MsgLog,"inserting petsc options: %s\n",params_.c_str());
327  PetscOptionsInsertString(params_.c_str()); // overwrites previous options values
328 
329  MatSetOption( matrix_, MAT_USE_INODES, PETSC_FALSE );
330 
331  KSPCreate( comm_, &system );
332  KSPSetOperators(system, matrix_, matrix_, DIFFERENT_NONZERO_PATTERN);
333 
334  // TODO take care of tolerances - shall we support both input file and command line petsc setting
335  KSPSetTolerances(system, r_tol_, a_tol_, PETSC_DEFAULT,PETSC_DEFAULT);
336  KSPSetFromOptions(system);
337  // We set the KSP flag set_initial_guess_nonzero
338  // unless KSP type is preonly.
339  // In such case PETSc fails (version 3.4.1)
340  if (init_guess_nonzero)
341  {
342  KSPType type;
343  KSPGetType(system, &type);
344  if (strcmp(type, KSPPREONLY) != 0)
345  KSPSetInitialGuessNonzero(system, PETSC_TRUE);
346  }
347 
348  KSPSolve(system, rhs_, solution_ );
349  KSPGetConvergedReason(system,&reason);
350  KSPGetIterationNumber(system,&nits);
351 
352  // substitute by PETSc call for residual
353  VecNorm(rhs_, NORM_2, &residual_norm_);
354 
355  xprintf(MsgLog,"convergence reason %d, number of iterations is %d\n", reason, nits);
356 
357  // get residual norm
358  KSPGetResidualNorm(system, &solution_precision_);
359 
360  // TODO: I do not understand this
361  //Profiler::instance()->set_timer_subframes("SOLVING MH SYSTEM", nits);
362 
363  KSPDestroy(&system);
364 
365  return static_cast<int>(reason);
366 
367 }
368 
370 {
371  std::string matFileName = "flow123d_matrix.m";
372  std::string rhsFileName = "flow123d_rhs.m";
373  std::string solFileName = "flow123d_sol.m";
374 
375  PetscViewer myViewer;
376 
377  PetscViewerASCIIOpen(comm_,matFileName.c_str(),&myViewer);
378  PetscViewerSetFormat(myViewer,PETSC_VIEWER_ASCII_MATLAB);
379  MatView( matrix_, myViewer );
380  PetscViewerDestroy(&myViewer);
381 
382  PetscViewerASCIIOpen(comm_,rhsFileName.c_str(),&myViewer);
383  PetscViewerSetFormat(myViewer,PETSC_VIEWER_ASCII_MATLAB);
384  VecView( rhs_, myViewer );
385  PetscViewerDestroy(&myViewer);
386 
387  if ( solution_ != NULL ) {
388  PetscViewerASCIIOpen(comm_,solFileName.c_str(),&myViewer);
389  PetscViewerSetFormat(myViewer,PETSC_VIEWER_ASCII_MATLAB);
390  VecView( solution_, myViewer );
391  PetscViewerDestroy(&myViewer);
392  }
393 }
394 
396 {
397  PetscErrorCode ierr;
398 
399  if (matrix_ != NULL) { ierr = MatDestroy(&matrix_); CHKERRV( ierr ); }
400  ierr = VecDestroy(&rhs_); CHKERRV( ierr );
401 
402  if (v_rhs_ != NULL) delete[] v_rhs_;
403 }
404 
406 {
407  if (! in_rec.is_empty()) {
408  // common values
409  LinSys::set_from_input( in_rec );
410 
411  // PETSc specific setting
412  a_tol_ = in_rec.val<double>("a_tol");
413  params_ = in_rec.val<string>("options");
414  }
415 }
416 
417 
419 {
420  return solution_precision_;
421 }
422 
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:570
#define DBGMSG(...)
Definition: global_defs.h:196
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:542
bool matrix_changed_
true if the matrix was changed since the last solve
Definition: linsys.hh:582
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:577
ConstraintVec_ constraints_
Definition: linsys.hh:591
Vec rhs_
PETSc vector constructed with vx array.
Record & derive_from(AbstractRecord &parent)
Definition: type_record.cc:169
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:583
Definition: system.hh:72
#define ASSERT(...)
Definition: global_defs.h:121
Class for declaration of the input data that are floating point numbers.
Definition: type_base.hh:376
MPI_Comm comm_
Definition: linsys.hh:569
Definition: system.hh:72
static Input::Type::AbstractRecord input_type
Definition: linsys.hh:90
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:100
const Distribution * rows_ds_
final distribution of rows of MH matrix
Definition: linsys.hh:575
double a_tol_
Definition: linsys.hh:566
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:589
Vec on_vec_
Vectors for counting non-zero entries in diagonal block.
void preallocate_matrix()
void start_allocation()
Definition: linsys_PETSC.cc:76
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:85
Vec off_vec_
Vectors for counting non-zero entries in off-diagonal block.
double r_tol_
Definition: linsys.hh:565
double get_solution_precision()
Abstract linear system class.
bool is_positive_definite()
Definition: linsys.hh:498
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:585
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:386