Flow123d
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:
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:
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");
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);
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  F_ENTRY;
157 
158  // output matrix
159  MatGetInfo(ls->A,MAT_GLOBAL_SUM,&info);
160  MPI_Barrier(PETSC_COMM_WORLD);
161  if (ls->ds->myp() == 0) {
162  f=xfopen("matrix.dat","w");
163  xfprintf(f,"%d %d 0.0\n",ls->size, ls->size);
164  //xfprintf(f,"zzz=zeros(%d,3)\n",(int)(info.nz_used));
165  //xfprintf(f,"zzz=[\n");
166  xfclose(f);
167  }
168  for(n=0;n<ls->ds->np();n++) {
169  MPI_Barrier(PETSC_COMM_WORLD);
170  if (n==ls->ds->myp()) {
171  f=xfopen("matrix.dat","a");
172  for(i=ls->ds->begin(); i<ls->ds->end();i++) {
173  MatGetRow(ls->A,i,&ncols,&cols,&vals);
174  for(j=0;j<ncols;j++)
175  xfprintf(f,"%d %d %f\n",ls->old_4_new[i]+1,ls->old_4_new[cols[j]]+1,vals[j]);
176  MatRestoreRow(ls->A,i,&ncols,&cols,&vals);
177  }
178  xfclose(f);
179  }
180  }
181  MPI_Barrier(PETSC_COMM_WORLD);
182  if (ls->ds->myp() == 0) {
183  f=xfopen("rhs.m","w");
184  xfprintf(f,"yyy = zeros(%d,2)\n yyy=[\n",ls->size);
185  xfclose(f);
186  }
187  // output vec
188  for(n=0; n<ls->ds->np(); n++) {
189  MPI_Barrier(PETSC_COMM_WORLD);
190  if (n==ls->ds->myp()) {
191  f=xfopen("rhs.m","a");
192  for(i=ls->ds->begin(); i<ls->ds->end(); i++) {
193  xfprintf(f,"%d %f\n",ls->old_4_new[i]+1,ls->vb[i-ls->ds->begin()]);
194  }
195  xfclose(f);
196  }
197  }
198  MPI_Barrier(PETSC_COMM_WORLD);
199  if (ls->ds->myp() == 0) {
200  f=xfopen("rhs.m","a");
201  xfprintf(f,"];\n xxx=sortrows(yyy); Vec=xxx(:,2);\n");
202  xfclose(f);
203  }
204 }
205 
206 // ======================================================================================
207 // LSView - output assembled system in side,el,edge ordering
208 
209 void MyVecView(Vec v,int *order,const char* fname) {
210 
211 FILE *f;
212 
213 
214 int i,n;
215 double *array;
216 
217 
218  F_ENTRY;
219  Distribution ds(v); // get distribution of the vector
220 
221 
222  if (ds.myp() == 0) {
223  f=xfopen(fname,"w");
224  xfprintf(f,"yyy = zeros(%d,2)\n yyy=[\n",ds.size());
225  xfclose(f);
226  }
227  // output vec
228  for(n=0; n<ds.np(); n++) {
229  MPI_Barrier(PETSC_COMM_WORLD);
230  if (n==ds.myp()) {
231  VecGetArray(v,&array);
232  f=xfopen(fname,"a");
233  for(i=ds.begin(); i<ds.end(); i++) {
234  xfprintf(f,"%d %f\n",order[i]+1,array[i-ds.begin()]);
235  }
236  VecRestoreArray(v,&array);
237  xfclose(f);
238  }
239  }
240  MPI_Barrier(PETSC_COMM_WORLD);
241  if (ds.myp() == 0) {
242  f=xfopen(fname,"a");
243  xfprintf(f,"];\n xxx=sortrows(yyy); Vec=xxx(:,2);\n");
244  xfclose(f);
245  }
246 }
247 */
248 
249 //=========================================================================================
250 /*! @brief convert linear system to pure CSR format
251  *
252  * - allocate CSR arrays according to MatGetInfo
253  * - indexes are form 0
254  * - make CSR format of the matrix (i.e. I,J,A vectors) from the PETSC format
255  */
256 
257 void LSSetCSR( LinSystem *mtx )
258 {
259  int i,pos,row,nnz;
260  PetscInt nnz_loc;
261  const PetscInt *cols;
262  const PetscScalar *vals;
263  MatInfo info;
264 
265  F_ENTRY;
266 
267  MatGetInfo(mtx->A,MAT_LOCAL,&info);
268  nnz=(int)(info.nz_used)+1; // allocate one more to be sure
269  // allocate
270  if (mtx->i == NULL) mtx->i=(int *)xmalloc( (mtx->size+1)*sizeof(int) );
271  if (mtx->j == NULL) mtx->j=(int *)xmalloc( nnz*sizeof(int) );
272  if (mtx->a == NULL) mtx->a=(double *)xmalloc( nnz*sizeof(double) );
273  DBGMSG("mtx size: %d nnz: %d\n",mtx->size,nnz);
274  // setup matrix from PETSC SeqAIJ format
275  pos=0;
276  for( row=0; row< mtx->size; row++ ) {
277  mtx->i[row]=pos;
278  MatGetRow(mtx->A,row,&nnz_loc,&cols,&vals);
279  DBGMSG("CSR row: %d nnz_loc %d\n",row,nnz_loc);
280  for(i=0; i<nnz_loc; i++) {
281  ASSERT(pos<nnz,"More nonzeroes then allocated! row: %d entry: %d\n",row,i);
282  mtx->j[pos]=cols[i];
283  mtx->a[pos]=vals[i];
284  pos++;
285  }
286  MatRestoreRow(mtx->A,row,&nnz_loc,&cols,&vals);
287  }
288  mtx->i[row]=pos;
289 }
290 
291 void LSFreeCSR( LinSystem *mtx )
292 {
293  xfree(mtx->i);
294  xfree(mtx->j);
295  xfree(mtx->a);
296 }
297 
298 
299 //**********************************************************************************************
300 
301 
303 {
304  if (status != NONE) {
305  // reinit linear system
306 
307  }
308  VecCreateMPI(PETSC_COMM_WORLD, vec_ds.lsize(), PETSC_DECIDE, &(on_vec));
309  VecDuplicate(on_vec,&(off_vec));
311 
312 }
313 
315 {
316  ASSERT(status == ALLOCATE, "Linear system has to be in ALLOCATE status.");
317 
318  PetscScalar *on_array, *off_array;
319  int *on_nz, *off_nz;
320  int i;
321 
322  // assembly and get values from counting vectors, destroy them
323  VecAssemblyBegin(on_vec);
324  VecAssemblyBegin(off_vec);
325 
326  on_nz=(int *)xmalloc( 2 * vec_ds.lsize() * sizeof(int));
327  off_nz=on_nz + vec_ds.lsize();
328 
329  VecAssemblyEnd(on_vec);
330  VecAssemblyEnd(off_vec);
331 
332  VecGetArray(on_vec,&on_array);
333  VecGetArray(off_vec,&off_array);
334 
335  for(i=0; i<vec_ds.lsize(); i++) {
336  on_nz[i]=min((unsigned int)(on_array[i]+0.1),vec_ds.lsize()); // small fraction to ensure correct rounding
337  off_nz[i]=(int)(off_array[i]+0.1);
338  }
339 
340  VecRestoreArray(on_vec,&on_array);
341  VecRestoreArray(off_vec,&off_array);
342  VecDestroy(&on_vec);
343  VecDestroy(&off_vec);
344 
345  // create PETSC matrix with preallocation
346  MatCreateAIJ(PETSC_COMM_WORLD, vec_ds.lsize(), vec_ds.lsize(), PETSC_DETERMINE, PETSC_DETERMINE,
347  0, on_nz, 0, off_nz, &matrix);
348 
349  if (symmetric) MatSetOption(matrix, MAT_SYMMETRIC, PETSC_TRUE);
350  MatSetOption(matrix, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_TRUE);
351 
352 
353  xfree(on_nz);
354 }
355 
356 void LinSys_MPIAIJ::preallocate_values(int nrow,int *rows,int ncol,int *cols)
357 {
358  int i,j,row,col;
359 
360  for (i=0; i<nrow; i++) {
361  row=rows[i];
362  for(j=0; j<ncol; j++) {
363  col=cols[j];
364  if (vec_ds.get_proc(row) == vec_ds.get_proc(col))
365  VecSetValue(on_vec,row,1.0,ADD_VALUES);
366  else
367  VecSetValue(off_vec,row,1.0,ADD_VALUES);
368  }
369  }
370 }
371 
373 {
374  // print local subdomain matrix
375  xprintf(Msg,"Printing of local matrix is not supported yet for MPIAIJ matrix. \n");
376 
377 }
378 
379 
381 {
382  if (status == ALLOCATE) {
383  VecDestroy(&on_vec);
384  VecDestroy(&off_vec);
385  }
386 }
387 
388 //**********************************************************************************************
389 
390 LinSys_MATIS::LinSys_MATIS(boost::shared_ptr<LocalToGlobalMap> global_row_4_sub_row, double *sol_array)
391 : LinSys(global_row_4_sub_row->get_distr()->lsize(), sol_array), lg_map(global_row_4_sub_row)
392 {
393  PetscErrorCode err;
394 
395  //xprintf(Msg,"sub size %d \n",subdomain_size);
396 
397  // vytvorit mapping v PETSc z global_row_4_sub_row
398  // check possible index range of lg_map to fit into signed int type
399  if (lg_map->get_distr()->size() > numeric_limits<PetscInt>::max()) xprintf(Err,"Index range doesn't fit into signed int!");
400  err = ISLocalToGlobalMappingCreate(PETSC_COMM_WORLD,
401  lg_map->size(),
402  (const PetscInt*)(&(lg_map->get_map_vector()[0])),
403  PETSC_COPY_VALUES, &map_local_to_global);
404 
405  ASSERT(err == 0,"Error in ISLocalToGlobalMappingCreate.");
406 
407  // initialize loc_rows array
408  loc_rows_size=100;
409  loc_rows = new int[loc_rows_size];
410 
411  type = MAT_IS;
412 };
413 
414 
416 {
417  ASSERT(0, "Not implemented");
418  /*
419  PetscErrorCode err;
420 
421  if (status != NONE) {
422  // reinit linear system
423 
424  }
425  err = MatCreateIS(PETSC_COMM_WORLD, 1, vec_ds.lsize(), vec_ds.lsize(), vec_ds.size(), vec_ds.size(),
426  map_local_to_global, &matrix);
427  ASSERT(err == 0,"Error in MatCreateIS.");
428 
429  err = MatISGetLocalMat(matrix, &local_matrix);
430  ASSERT(err == 0,"Error in MatISGetLocalMat.");
431 
432  // extract scatter
433  MatMyIS *mis = (MatMyIS*) matrix->data;
434  sub_scatter = mis->ctx;
435 
436  subdomain_nz= new int[subdomain_size]; // count local nozero for every row of subdomain matrix
437  SET_ARRAY_ZERO(subdomain_nz,subdomain_size); // set zeros to the array
438 
439  status=ALLOCATE;
440 
441  DBGMSG("allocation started\n");
442  */
443 }
444 
446 {
447  ASSERT(status == ALLOCATE, "Linear system has to be in ALLOCATE status.");
448 
449  // printing subdomain_nz
450  //DBGPRINT_INT("subdomain_nz",subdomain_size,subdomain_nz);
451 
452 
453  // preallocation of local subdomain matrix
454  MatSeqAIJSetPreallocation(local_matrix, 0, subdomain_nz);
455 
456  if (symmetric) MatSetOption(matrix, MAT_SYMMETRIC, PETSC_TRUE);
457  MatSetOption(matrix, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_TRUE);
458 
459  delete[] subdomain_nz;
460 }
461 
462 void LinSys_MATIS::preallocate_values(int nrow,int *rows,int ncol,int *cols)
463 {
464  int i,row, n_loc_rows;
465  PetscErrorCode err;
466 
467  if (loc_rows_size < nrow) {
468  delete[] loc_rows;
469  loc_rows_size=nrow;
470  loc_rows=new int[loc_rows_size];
471 
472  }
473 
474  // translate from global to local indexes
475  err = ISGlobalToLocalMappingApply(map_local_to_global, IS_GTOLM_DROP, nrow, rows, &n_loc_rows, loc_rows);
476  ASSERT(err == 0,"Error in ISGlobalToLocalMappingApply.");
477  ASSERT(nrow == n_loc_rows,"Not all global indices translated to local indices.");
478  // printing subdomain_embedding
479  //DBGPRINT_INT("embed_element_to",nrow,loc_rows);
480 
481 
482  /* We don't need columns for preallocation.
483 
484  if (loc_cols_size < ncol) {
485  delete loc_cols;
486  loc_cols_size=ncol;
487  loc_cols=new int[loc_cols_size];
488  }
489 
490  // translate from global to local indexes
491  ISGlobalToLocalMappingApply(local_to_global, IS_GTOLM_DROP, ncol, cols, &n_loc_cols, loc_cols);
492  */
493  for (i=0; i<n_loc_rows; i++) {
494  row=loc_rows[i];
495  subdomain_nz[row] = subdomain_nz[row] + ncol;
496  }
497 }
498 
500 {
501  PetscErrorCode err;
502 // PetscViewer lab;
503 // char numstring[6] = "00000";
504 // int myid;
505 // int ierr;
506 
507 // err = PetscViewerSetFormat(PETSC_VIEWER_STDOUT_SELF,PETSC_VIEWER_ASCII_DENSE);
508 // ASSERT(err == 0,"Error in PetscViewerSetFormat.");
509 
510  // print local subdomain matrix
511  err = MatView(local_matrix,PETSC_VIEWER_STDOUT_SELF);
512  ASSERT(err == 0,"Error in MatView.");
513 //
514 // ierr=MPI_Comm_rank(PETSC_COMM_WORLD, &(myid));
515 // ASSERT( ! ierr , "Can not get MPI rank.\n" );
516 //
517 // sprintf(numstring,"%5.5d",myid);
518 // printf("Nunstring is >>>%s<<<\n",numstring);
519 //
520 // PetscViewerASCIIOpen(PETSC_COMM_SELF,numstring,&lab);
521 //
522 // ASSERT(!(loc_rows == NULL),"Local matrix is not assigned.");
523 // err = PetscViewerSetFormat(lab,PETSC_VIEWER_ASCII_DENSE);
524 // ASSERT(err == 0,"Error in PetscViewerSetFormat.");
525 //
526 // // print local subdomain matrix
527 // err = MatView(local_matrix,lab);
528 // ASSERT(err == 0,"Error in MatView.");
529 //
530 // PetscViewerDestroy(lab);
531 }
532 
534 {
535  PetscErrorCode err;
536 
537  // destroy mapping
538  err = ISLocalToGlobalMappingDestroy(&map_local_to_global);
539  ASSERT(err == 0,"Error in ISLocalToGlobalMappingDestroy.");
540  xprintf(Msg,"Error code %d \n",err);
541 
542 
543  delete[] loc_rows;
544  delete[] subdomain_indices;
545  if (status == ALLOCATE) {
546  delete subdomain_nz;
547  }
548 
549 }
550 
551 #endif
552 
553 
554 #ifdef HAVE_ATLAS_ONLY_LAPACK
555 /*
556  * This is a workaround to build Flow with PETSC 3.0 and ATLAS, since one particular and unimportant preconditioner (asa)
557  * needs this Lapack function, which is not implemented in ATLAS.
558  */
559 extern "C" {
560 
561 void dgeqrf_(int m, int n, double **A, double *TAU, double *work, int lwork, int info)
562 {
563 }
564 
565 }
566 #endif
567