Flow123d  jenkins-Flow123d-linux-release-multijob-282
linsys.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$
21  * $Revision$
22  * $LastChangedBy$
23  * $LastChangedDate$
24  *
25  * @file
26  * @ingroup la
27  * @brief Wrappers for linear systems based on MPIAIJ and MATIS format.
28  * @author Jan Brezina
29  *
30  */
31 
32 #include <algorithm>
33 #include <limits>
34 #include <petscmat.h>
35 #include "system/system.hh"
36 #include "la/linsys.hh"
37 
38 
39 namespace it = Input::Type;
40 
41 it::AbstractRecord LinSys::input_type = it::AbstractRecord("LinSys", "Linear solver setting.")
42  .declare_key("r_tol", it::Double(0.0, 1.0), it::Default("1.0e-7"),
43  "Relative residual tolerance (to initial error).")
44  .declare_key("max_it", it::Integer(0), it::Default("10000"),
45  "Maximum number of outer iterations of the linear solver.");
46 
47 #if 0
48 
49 /**
50  * @brief Constructs a parallel system with given local size.
51  *
52  * By the parameter @p vec_lsize we initialize distribution of the rhs and solution vectors.
53  * For MPIAIJ matrix this is also distribution of its rows, but for IS matrix this is only size of
54  * principial local part without interface.
55  */
56 LinSys::LinSys(unsigned int vec_lsize, double *sol_array)
57 :type(MAT_MPIAIJ),
58  matrix(NULL),
59  vec_ds(vec_lsize, PETSC_COMM_WORLD),
60  symmetric(false),
61  positive_definite(false),
62  status(NONE)
63 {
64  // create PETSC vectors
65  v_rhs=(double *) xmalloc(sizeof(double) * (this->vec_lsize() + 1) );
66  VecCreateMPIWithArray(PETSC_COMM_WORLD,1, this->vec_lsize(), PETSC_DECIDE, v_rhs, &rhs);
67  VecZeroEntries(rhs);
68 
69  if (sol_array == NULL) v_solution=(double *)xmalloc(sizeof(double) * (this->vec_lsize() + 1));
70  else v_solution=sol_array;
71  VecCreateMPIWithArray(PETSC_COMM_WORLD,1, this->vec_lsize(), PETSC_DECIDE, v_solution, &solution);
72  own_solution=false;
73  //VecZeroEntries(solution);
74 }
75 
76 
78 {
79  switch (status) {
80  case ALLOCATE:
81  preallocate_matrix();
82  break;
83  case INSERT:
84  finalize(MAT_FLUSH_ASSEMBLY);
85  break;
86  case ADD:
87  case DONE:
88  break;
89  default:
90  ASSERT(0, "Can not set values. Matrix is not preallocated.\n");
91  }
92  status=ADD;
93 }
94 
96 {
97  switch (status) {
98  case ALLOCATE:
99  preallocate_matrix();
100  break;
101  case ADD:
102  finalize(MAT_FLUSH_ASSEMBLY);
103  break;
104  case INSERT:
105  case DONE:
106  break;
107  default:
108  ASSERT(0, "Can not set values. Matrix is not preallocated.\n");
109  }
110  status=INSERT;
111 }
112 
113 
114 void LinSys::finalize(MatAssemblyType assembly_type)
115 {
116  if (status == ALLOCATE) {
117  xprintf(Warn, "Finalizing linear system without setting values.\n");
118  preallocate_matrix();
119  }
120  MatAssemblyBegin(matrix, assembly_type);
121  VecAssemblyBegin(rhs);
122  if (assembly_type == MAT_FINAL_ASSEMBLY) status=DONE;
123  MatAssemblyEnd(matrix, assembly_type);
124  VecAssemblyEnd(rhs);
125 }
126 
127 void view(std::ostream output_stream, int * output_mapping = NULL)
128 {
129 
130 }
131 
133 {
134 
135  if (matrix) MatDestroy(&matrix);
136  VecDestroy(&rhs);
137  VecDestroy(&solution);
138 
139  xfree(v_rhs);
140  if (own_solution) xfree(v_solution);
141 }
142 
143 
144 // ======================================================================================
145 // LSView - output assembled system in side,el,edge ordering
146 
147 void LSView(LinSystem *ls)
148 {
149  FILE *f;
150  int i, j, n;
151  PetscInt ncols;
152  const PetscInt *cols;
153  const PetscScalar *vals;
154  MatInfo info;
155 
156  // output matrix
157  MatGetInfo(ls->A,MAT_GLOBAL_SUM,&info);
158  MPI_Barrier(PETSC_COMM_WORLD);
159  if (ls->ds->myp() == 0) {
160  f=xfopen("matrix.dat","w");
161  xfprintf(f,"%d %d 0.0\n",ls->size, ls->size);
162  //xfprintf(f,"zzz=zeros(%d,3)\n",(int)(info.nz_used));
163  //xfprintf(f,"zzz=[\n");
164  xfclose(f);
165  }
166  for(n=0;n<ls->ds->np();n++) {
167  MPI_Barrier(PETSC_COMM_WORLD);
168  if (n==ls->ds->myp()) {
169  f=xfopen("matrix.dat","a");
170  for(i=ls->ds->begin(); i<ls->ds->end();i++) {
171  MatGetRow(ls->A,i,&ncols,&cols,&vals);
172  for(j=0;j<ncols;j++)
173  xfprintf(f,"%d %d %f\n",ls->old_4_new[i]+1,ls->old_4_new[cols[j]]+1,vals[j]);
174  MatRestoreRow(ls->A,i,&ncols,&cols,&vals);
175  }
176  xfclose(f);
177  }
178  }
179  MPI_Barrier(PETSC_COMM_WORLD);
180  if (ls->ds->myp() == 0) {
181  f=xfopen("rhs.m","w");
182  xfprintf(f,"yyy = zeros(%d,2)\n yyy=[\n",ls->size);
183  xfclose(f);
184  }
185  // output vec
186  for(n=0; n<ls->ds->np(); n++) {
187  MPI_Barrier(PETSC_COMM_WORLD);
188  if (n==ls->ds->myp()) {
189  f=xfopen("rhs.m","a");
190  for(i=ls->ds->begin(); i<ls->ds->end(); i++) {
191  xfprintf(f,"%d %f\n",ls->old_4_new[i]+1,ls->vb[i-ls->ds->begin()]);
192  }
193  xfclose(f);
194  }
195  }
196  MPI_Barrier(PETSC_COMM_WORLD);
197  if (ls->ds->myp() == 0) {
198  f=xfopen("rhs.m","a");
199  xfprintf(f,"];\n xxx=sortrows(yyy); Vec=xxx(:,2);\n");
200  xfclose(f);
201  }
202 }
203 
204 // ======================================================================================
205 // LSView - output assembled system in side,el,edge ordering
206 
207 void MyVecView(Vec v,int *order,const char* fname) {
208 
209 FILE *f;
210 
211 
212 int i,n;
213 double *array;
214 
215 
216  Distribution ds(v); // get distribution of the vector
217 
218 
219  if (ds.myp() == 0) {
220  f=xfopen(fname,"w");
221  xfprintf(f,"yyy = zeros(%d,2)\n yyy=[\n",ds.size());
222  xfclose(f);
223  }
224  // output vec
225  for(n=0; n<ds.np(); n++) {
226  MPI_Barrier(PETSC_COMM_WORLD);
227  if (n==ds.myp()) {
228  VecGetArray(v,&array);
229  f=xfopen(fname,"a");
230  for(i=ds.begin(); i<ds.end(); i++) {
231  xfprintf(f,"%d %f\n",order[i]+1,array[i-ds.begin()]);
232  }
233  VecRestoreArray(v,&array);
234  xfclose(f);
235  }
236  }
237  MPI_Barrier(PETSC_COMM_WORLD);
238  if (ds.myp() == 0) {
239  f=xfopen(fname,"a");
240  xfprintf(f,"];\n xxx=sortrows(yyy); Vec=xxx(:,2);\n");
241  xfclose(f);
242  }
243 }
244 */
245 
246 //=========================================================================================
247 /*! @brief convert linear system to pure CSR format
248  *
249  * - allocate CSR arrays according to MatGetInfo
250  * - indexes are form 0
251  * - make CSR format of the matrix (i.e. I,J,A vectors) from the PETSC format
252  */
253 
254 void LSSetCSR( LinSystem *mtx )
255 {
256  int i,pos,row,nnz;
257  PetscInt nnz_loc;
258  const PetscInt *cols;
259  const PetscScalar *vals;
260  MatInfo info;
261 
262  MatGetInfo(mtx->A,MAT_LOCAL,&info);
263  nnz=(int)(info.nz_used)+1; // allocate one more to be sure
264  // allocate
265  if (mtx->i == NULL) mtx->i=(int *)xmalloc( (mtx->size+1)*sizeof(int) );
266  if (mtx->j == NULL) mtx->j=(int *)xmalloc( nnz*sizeof(int) );
267  if (mtx->a == NULL) mtx->a=(double *)xmalloc( nnz*sizeof(double) );
268  DBGMSG("mtx size: %d nnz: %d\n",mtx->size,nnz);
269  // setup matrix from PETSC SeqAIJ format
270  pos=0;
271  for( row=0; row< mtx->size; row++ ) {
272  mtx->i[row]=pos;
273  MatGetRow(mtx->A,row,&nnz_loc,&cols,&vals);
274  DBGMSG("CSR row: %d nnz_loc %d\n",row,nnz_loc);
275  for(i=0; i<nnz_loc; i++) {
276  ASSERT(pos<nnz,"More nonzeroes then allocated! row: %d entry: %d\n",row,i);
277  mtx->j[pos]=cols[i];
278  mtx->a[pos]=vals[i];
279  pos++;
280  }
281  MatRestoreRow(mtx->A,row,&nnz_loc,&cols,&vals);
282  }
283  mtx->i[row]=pos;
284 }
285 
286 void LSFreeCSR( LinSystem *mtx )
287 {
288  xfree(mtx->i);
289  xfree(mtx->j);
290  xfree(mtx->a);
291 }
292 
293 
294 //**********************************************************************************************
295 
296 
297 void LinSys_MPIAIJ::start_allocation()
298 {
299  if (status != NONE) {
300  // reinit linear system
301 
302  }
303  VecCreateMPI(PETSC_COMM_WORLD, vec_ds.lsize(), PETSC_DECIDE, &(on_vec));
304  VecDuplicate(on_vec,&(off_vec));
305  status=ALLOCATE;
306 
307 }
308 
309 void LinSys_MPIAIJ::preallocate_matrix()
310 {
311  ASSERT(status == ALLOCATE, "Linear system has to be in ALLOCATE status.");
312 
313  PetscScalar *on_array, *off_array;
314  int *on_nz, *off_nz;
315  int i;
316 
317  // assembly and get values from counting vectors, destroy them
318  VecAssemblyBegin(on_vec);
319  VecAssemblyBegin(off_vec);
320 
321  on_nz=(int *)xmalloc( 2 * vec_ds.lsize() * sizeof(int));
322  off_nz=on_nz + vec_ds.lsize();
323 
324  VecAssemblyEnd(on_vec);
325  VecAssemblyEnd(off_vec);
326 
327  VecGetArray(on_vec,&on_array);
328  VecGetArray(off_vec,&off_array);
329 
330  for(i=0; i<vec_ds.lsize(); i++) {
331  on_nz[i]=min((unsigned int)(on_array[i]+0.1),vec_ds.lsize()); // small fraction to ensure correct rounding
332  off_nz[i]=(int)(off_array[i]+0.1);
333  }
334 
335  VecRestoreArray(on_vec,&on_array);
336  VecRestoreArray(off_vec,&off_array);
337  VecDestroy(&on_vec);
338  VecDestroy(&off_vec);
339 
340  // create PETSC matrix with preallocation
341  MatCreateAIJ(PETSC_COMM_WORLD, vec_ds.lsize(), vec_ds.lsize(), PETSC_DETERMINE, PETSC_DETERMINE,
342  0, on_nz, 0, off_nz, &matrix);
343 
344  if (symmetric) MatSetOption(matrix, MAT_SYMMETRIC, PETSC_TRUE);
345  MatSetOption(matrix, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_TRUE);
346 
347 
348  xfree(on_nz);
349 }
350 
351 void LinSys_MPIAIJ::preallocate_values(int nrow,int *rows,int ncol,int *cols)
352 {
353  int i,j,row,col;
354 
355  for (i=0; i<nrow; i++) {
356  row=rows[i];
357  for(j=0; j<ncol; j++) {
358  col=cols[j];
359  if (vec_ds.get_proc(row) == vec_ds.get_proc(col))
360  VecSetValue(on_vec,row,1.0,ADD_VALUES);
361  else
362  VecSetValue(off_vec,row,1.0,ADD_VALUES);
363  }
364  }
365 }
366 
367 void LinSys_MPIAIJ::view_local_matrix()
368 {
369  // print local subdomain matrix
370  xprintf(Msg,"Printing of local matrix is not supported yet for MPIAIJ matrix. \n");
371 
372 }
373 
374 
375 LinSys_MPIAIJ:: ~LinSys_MPIAIJ()
376 {
377  if (status == ALLOCATE) {
378  VecDestroy(&on_vec);
379  VecDestroy(&off_vec);
380  }
381 }
382 
383 //**********************************************************************************************
384 
385 LinSys_MATIS::LinSys_MATIS(boost::shared_ptr<LocalToGlobalMap> global_row_4_sub_row, double *sol_array)
386 : LinSys(global_row_4_sub_row->get_distr()->lsize(), sol_array), lg_map(global_row_4_sub_row)
387 {
388  PetscErrorCode err;
389 
390  //xprintf(Msg,"sub size %d \n",subdomain_size);
391 
392  // vytvorit mapping v PETSc z global_row_4_sub_row
393  // check possible index range of lg_map to fit into signed int type
394  if (lg_map->get_distr()->size() > numeric_limits<PetscInt>::max()) xprintf(Err,"Index range doesn't fit into signed int!");
395  err = ISLocalToGlobalMappingCreate(PETSC_COMM_WORLD,
396  lg_map->size(),
397  (const PetscInt*)(&(lg_map->get_map_vector()[0])),
398  PETSC_COPY_VALUES, &map_local_to_global);
399 
400  ASSERT(err == 0,"Error in ISLocalToGlobalMappingCreate.");
401 
402  // initialize loc_rows array
403  loc_rows_size=100;
404  loc_rows = new int[loc_rows_size];
405 
406  type = MAT_IS;
407 };
408 
409 
410 void LinSys_MATIS::start_allocation()
411 {
412  ASSERT(0, "Not implemented");
413  /*
414  PetscErrorCode err;
415 
416  if (status != NONE) {
417  // reinit linear system
418 
419  }
420  err = MatCreateIS(PETSC_COMM_WORLD, 1, vec_ds.lsize(), vec_ds.lsize(), vec_ds.size(), vec_ds.size(),
421  map_local_to_global, &matrix);
422  ASSERT(err == 0,"Error in MatCreateIS.");
423 
424  err = MatISGetLocalMat(matrix, &local_matrix);
425  ASSERT(err == 0,"Error in MatISGetLocalMat.");
426 
427  // extract scatter
428  MatMyIS *mis = (MatMyIS*) matrix->data;
429  sub_scatter = mis->ctx;
430 
431  subdomain_nz= new int[subdomain_size]; // count local nozero for every row of subdomain matrix
432  SET_ARRAY_ZERO(subdomain_nz,subdomain_size); // set zeros to the array
433 
434  status=ALLOCATE;
435 
436  DBGMSG("allocation started\n");
437  */
438 }
439 
440 void LinSys_MATIS::preallocate_matrix()
441 {
442  ASSERT(status == ALLOCATE, "Linear system has to be in ALLOCATE status.");
443 
444  // printing subdomain_nz
445  //DBGPRINT_INT("subdomain_nz",subdomain_size,subdomain_nz);
446 
447 
448  // preallocation of local subdomain matrix
449  MatSeqAIJSetPreallocation(local_matrix, 0, subdomain_nz);
450 
451  if (symmetric) MatSetOption(matrix, MAT_SYMMETRIC, PETSC_TRUE);
452  MatSetOption(matrix, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_TRUE);
453 
454  delete[] subdomain_nz;
455 }
456 
457 void LinSys_MATIS::preallocate_values(int nrow,int *rows,int ncol,int *cols)
458 {
459  int i,row, n_loc_rows;
460  PetscErrorCode err;
461 
462  if (loc_rows_size < nrow) {
463  delete[] loc_rows;
464  loc_rows_size=nrow;
465  loc_rows=new int[loc_rows_size];
466 
467  }
468 
469  // translate from global to local indexes
470  err = ISGlobalToLocalMappingApply(map_local_to_global, IS_GTOLM_DROP, nrow, rows, &n_loc_rows, loc_rows);
471  ASSERT(err == 0,"Error in ISGlobalToLocalMappingApply.");
472  ASSERT(nrow == n_loc_rows,"Not all global indices translated to local indices.");
473  // printing subdomain_embedding
474  //DBGPRINT_INT("embed_element_to",nrow,loc_rows);
475 
476 
477  /* We don't need columns for preallocation.
478 
479  if (loc_cols_size < ncol) {
480  delete loc_cols;
481  loc_cols_size=ncol;
482  loc_cols=new int[loc_cols_size];
483  }
484 
485  // translate from global to local indexes
486  ISGlobalToLocalMappingApply(local_to_global, IS_GTOLM_DROP, ncol, cols, &n_loc_cols, loc_cols);
487  */
488  for (i=0; i<n_loc_rows; i++) {
489  row=loc_rows[i];
490  subdomain_nz[row] = subdomain_nz[row] + ncol;
491  }
492 }
493 
494 void LinSys_MATIS::view_local_matrix()
495 {
496  PetscErrorCode err;
497 // PetscViewer lab;
498 // char numstring[6] = "00000";
499 // int myid;
500 // int ierr;
501 
502 // err = PetscViewerSetFormat(PETSC_VIEWER_STDOUT_SELF,PETSC_VIEWER_ASCII_DENSE);
503 // ASSERT(err == 0,"Error in PetscViewerSetFormat.");
504 
505  // print local subdomain matrix
506  err = MatView(local_matrix,PETSC_VIEWER_STDOUT_SELF);
507  ASSERT(err == 0,"Error in MatView.");
508 //
509 // ierr=MPI_Comm_rank(PETSC_COMM_WORLD, &(myid));
510 // ASSERT( ! ierr , "Can not get MPI rank.\n" );
511 //
512 // sprintf(numstring,"%5.5d",myid);
513 // printf("Nunstring is >>>%s<<<\n",numstring);
514 //
515 // PetscViewerASCIIOpen(PETSC_COMM_SELF,numstring,&lab);
516 //
517 // ASSERT(!(loc_rows == NULL),"Local matrix is not assigned.");
518 // err = PetscViewerSetFormat(lab,PETSC_VIEWER_ASCII_DENSE);
519 // ASSERT(err == 0,"Error in PetscViewerSetFormat.");
520 //
521 // // print local subdomain matrix
522 // err = MatView(local_matrix,lab);
523 // ASSERT(err == 0,"Error in MatView.");
524 //
525 // PetscViewerDestroy(lab);
526 }
527 
528 LinSys_MATIS:: ~LinSys_MATIS()
529 {
530  PetscErrorCode err;
531 
532  // destroy mapping
533  err = ISLocalToGlobalMappingDestroy(&map_local_to_global);
534  ASSERT(err == 0,"Error in ISLocalToGlobalMappingDestroy.");
535  xprintf(Msg,"Error code %d \n",err);
536 
537 
538  delete[] loc_rows;
539  delete[] subdomain_indices;
540  if (status == ALLOCATE) {
541  delete subdomain_nz;
542  }
543 
544 }
545 
546 #endif
547 
548 
549 #ifdef HAVE_ATLAS_ONLY_LAPACK
550 /*
551  * This is a workaround to build Flow with PETSC 3.0 and ATLAS, since one particular and unimportant preconditioner (asa)
552  * needs this Lapack function, which is not implemented in ATLAS.
553  */
554 extern "C" {
555 
556 void dgeqrf_(int m, int n, double **A, double *TAU, double *work, int lwork, int info)
557 {
558 }
559 
560 }
561 #endif
562 
virtual void start_insert_assembly()
Definition: linsys.hh:304
#define DBGMSG(...)
Definition: global_defs.h:196
Definition: system.hh:72
Class Input::Type::Default specifies default value of keys of a Input::Type::Record.
Definition: type_record.hh:39
virtual void start_add_assembly()
Definition: linsys.hh:296
int xfclose(FILE *stream)
FCLOSE WITH ERROR HANDLING.
Definition: xio.cc:309
Wrappers for linear systems based on MPIAIJ and MATIS format.
unsigned int vec_lsize()
Definition: linsys.hh:155
int xfprintf(FILE *out, const char *fmt,...)
FPRINTF WITH ERROR HANDLING.
Definition: xio.cc:395
Class for declaration of the integral input data.
Definition: type_base.hh:355
LinSys(const Distribution *rows_ds)
Definition: linsys.hh:115
virtual ~LinSys()
Definition: linsys.hh:563
#define ASSERT(...)
Definition: global_defs.h:121
Class for declaration of the input data that are floating point numbers.
Definition: type_base.hh:392
Definition: system.hh:72
static Input::Type::AbstractRecord input_type
Definition: linsys.hh:90
#define xprintf(...)
Definition: system.hh:100
Class for declaration of polymorphic Record.
Definition: type_record.hh:487
AbstractRecord & declare_key(const string &key, const KeyType &type, const Default &default_value, const string &description)
Definition: type_record.cc:466
void * xmalloc(size_t size)
Memory allocation with checking.
Definition: system.cc:209
Abstract linear system class.
Definition: system.hh:72
#define xfree(p)
Definition: system.hh:108
#define MPI_Barrier(comm)
Definition: mpi.h:531
FILE * xfopen(const std::string &fname, const char *mode)
Definition: xio.cc:246