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