MFEM  v3.3
Finite element discretization library
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Pages
petsc.cpp
Go to the documentation of this file.
1 // Copyright (c) 2016, Lawrence Livermore National Security, LLC. Produced at
2 // the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
3 // reserved. See file COPYRIGHT for details.
4 //
5 // This file is part of the MFEM library. For more information and source code
6 // availability see http://mfem.org.
7 //
8 // MFEM is free software; you can redistribute it and/or modify it under the
9 // terms of the GNU Lesser General Public License (as published by the Free
10 // Software Foundation) version 2.1 dated February 1999.
11 
12 // Author: Stefano Zampini <stefano.zampini@gmail.com>
13 
14 #include "../config/config.hpp"
15 
16 #ifdef MFEM_USE_MPI
17 #ifdef MFEM_USE_PETSC
18 
19 #include "linalg.hpp"
20 #if defined(PETSC_HAVE_HYPRE)
21 #include "petscmathypre.h"
22 #endif
23 #include "../fem/fem.hpp"
24 
25 #include <fstream>
26 #include <iomanip>
27 #include <cmath>
28 #include <cstdlib>
29 // Note: there are additional #include statements below.
30 
31 // Error handling
32 // Prints PETSc's stacktrace and then calls MFEM_ABORT
33 // We cannot use PETSc's CHKERRQ since it returns a PetscErrorCode
34 #define PCHKERRQ(obj,err) do { \
35  if ((err)) \
36  { \
37  PetscError(PetscObjectComm((PetscObject)obj),__LINE__,_MFEM_FUNC_NAME, \
38  __FILE__,err,PETSC_ERROR_REPEAT,NULL); \
39  MFEM_ABORT("Error in PETSc. See stacktrace above."); \
40  } \
41  } while(0);
42 #define CCHKERRQ(comm,err) do { \
43  if ((err)) \
44  { \
45  PetscError(comm,__LINE__,_MFEM_FUNC_NAME, \
46  __FILE__,err,PETSC_ERROR_REPEAT,NULL); \
47  MFEM_ABORT("Error in PETSc. See stacktrace above."); \
48  } \
49  } while(0);
50 
51 // Callback functions: these functions will be called by PETSc
52 static PetscErrorCode __mfem_ts_monitor(TS,PetscInt,PetscReal,Vec,void*);
53 static PetscErrorCode __mfem_ts_rhsfunction(TS,PetscReal,Vec,Vec,void*);
54 static PetscErrorCode __mfem_ts_rhsjacobian(TS,PetscReal,Vec,Mat,Mat,
55  void*);
56 static PetscErrorCode __mfem_ts_ifunction(TS,PetscReal,Vec,Vec,Vec,void*);
57 static PetscErrorCode __mfem_ts_ijacobian(TS,PetscReal,Vec,Vec,
58  PetscReal,Mat,
59  Mat,void*);
60 static PetscErrorCode __mfem_snes_jacobian(SNES,Vec,Mat,Mat,void*);
61 static PetscErrorCode __mfem_snes_function(SNES,Vec,Vec,void*);
62 static PetscErrorCode __mfem_ksp_monitor(KSP,PetscInt,PetscReal,void*);
63 static PetscErrorCode __mfem_pc_shell_apply(PC,Vec,Vec);
64 static PetscErrorCode __mfem_pc_shell_apply_transpose(PC,Vec,Vec);
65 static PetscErrorCode __mfem_pc_shell_setup(PC);
66 static PetscErrorCode __mfem_pc_shell_destroy(PC);
67 static PetscErrorCode __mfem_mat_shell_apply(Mat,Vec,Vec);
68 static PetscErrorCode __mfem_mat_shell_apply_transpose(Mat,Vec,Vec);
69 static PetscErrorCode __mfem_mat_shell_destroy(Mat);
70 static PetscErrorCode __mfem_array_container_destroy(void*);
71 static PetscErrorCode __mfem_matarray_container_destroy(void*);
72 
73 // auxiliary functions
74 static PetscErrorCode Convert_Array_IS(MPI_Comm,bool,const mfem::Array<int>*,
75  PetscInt,IS*);
76 static PetscErrorCode Convert_Vmarks_IS(MPI_Comm,mfem::Array<Mat>&,
77  const mfem::Array<int>*,PetscInt,IS*);
78 
79 // Equivalent functions are present in PETSc source code
80 // if PETSc has been compiled with hypre support
81 // We provide them here in case PETSC_HAVE_HYPRE is not defined
82 #if !defined(PETSC_HAVE_HYPRE)
83 static PetscErrorCode MatConvert_hypreParCSR_AIJ(hypre_ParCSRMatrix*,Mat*);
84 static PetscErrorCode MatConvert_hypreParCSR_IS(hypre_ParCSRMatrix*,Mat*);
85 #endif
86 
87 // structs used by PETSc code
88 typedef struct
89 {
90  mfem::Operator *op;
91 } mat_shell_ctx;
92 
93 typedef struct
94 {
95  mfem::Solver *op;
96 } solver_shell_ctx;
97 
98 // use global scope ierr to check PETSc errors inside mfem calls
99 PetscErrorCode ierr;
100 
101 using namespace std;
102 
103 namespace mfem
104 {
105 
106 // PetscParVector methods
107 
108 void PetscParVector::_SetDataAndSize_()
109 {
110  const PetscScalar *array;
111  PetscInt n;
112 
113  ierr = VecGetArrayRead(x,&array); PCHKERRQ(x,ierr);
114  ierr = VecGetLocalSize(x,&n); PCHKERRQ(x,ierr);
115  SetDataAndSize((PetscScalar*)array,n);
116  ierr = VecRestoreArrayRead(x,&array); PCHKERRQ(x,ierr);
117 }
118 
119 PetscInt PetscParVector::GlobalSize() const
120 {
121  PetscInt N;
122  ierr = VecGetSize(x,&N); PCHKERRQ(x,ierr);
123  return N;
124 }
125 
126 PetscParVector::PetscParVector(MPI_Comm comm, PetscInt glob_size,
127  PetscInt *col) : Vector()
128 {
129  ierr = VecCreate(comm,&x); CCHKERRQ(comm,ierr);
130  if (col)
131  {
132  PetscMPIInt myid;
133  MPI_Comm_rank(comm, &myid);
134  ierr = VecSetSizes(x,col[myid+1]-col[myid],PETSC_DECIDE); PCHKERRQ(x,ierr);
135  }
136  else
137  {
138  ierr = VecSetSizes(x,PETSC_DECIDE,glob_size); PCHKERRQ(x,ierr);
139  }
140  ierr = VecSetType(x,VECSTANDARD); PCHKERRQ(x,ierr);
142 }
143 
145 {
146  MPI_Comm comm = PetscObjectComm((PetscObject)x);
147  ierr = VecDestroy(&x); CCHKERRQ(comm,ierr);
148 }
149 
150 PetscParVector::PetscParVector(MPI_Comm comm, PetscInt glob_size,
151  PetscScalar *_data, PetscInt *col) : Vector()
152 {
153  MFEM_VERIFY(col,"Missing distribution");
154  PetscMPIInt myid;
155  MPI_Comm_rank(comm, &myid);
156  ierr = VecCreateMPIWithArray(comm,1,col[myid+1]-col[myid],glob_size,_data,
157  &x); CCHKERRQ(comm,ierr)
159 }
160 
162 {
163  ierr = VecDuplicate(y.x,&x); PCHKERRQ(x,ierr);
165 }
166 
167 PetscParVector::PetscParVector(MPI_Comm comm, const Operator &op,
168  bool transpose, bool allocate) : Vector()
169 {
170  PetscInt loc = transpose ? op.Height() : op.Width();
171  if (allocate)
172  {
173  ierr = VecCreate(comm,&x);
174  CCHKERRQ(comm,ierr);
175  ierr = VecSetSizes(x,loc,PETSC_DECIDE);
176  PCHKERRQ(x,ierr);
177  ierr = VecSetType(x,VECSTANDARD);
178  PCHKERRQ(x,ierr);
179  ierr = VecSetUp(x);
180  PCHKERRQ(x,ierr);
181  }
182  else
183  {
184  ierr = VecCreateMPIWithArray(comm,1,loc,PETSC_DECIDE,NULL,
185  &x); CCHKERRQ(comm,ierr);
186  }
188 }
189 
191  bool transpose, bool allocate) : Vector()
192 {
193  Mat pA = const_cast<PetscParMatrix&>(A);
194  if (!transpose)
195  {
196  ierr = MatCreateVecs(pA,&x,NULL);
197  }
198  else
199  {
200  ierr = MatCreateVecs(pA,NULL,&x);
201  }
202  if (!allocate)
203  {
204  ierr = VecReplaceArray(x,NULL); PCHKERRQ(x,ierr);
205  }
206  PCHKERRQ(pA,ierr);
208 }
209 
211 {
212  if (ref)
213  {
214  ierr = PetscObjectReference((PetscObject)y); PCHKERRQ(y,ierr);
215  }
216  x = y;
218 }
219 
221 {
222 
223  HYPRE_Int* offsets = pfes->GetTrueDofOffsets();
224  MPI_Comm comm = pfes->GetComm();
225  ierr = VecCreate(comm,&x); CCHKERRQ(comm,ierr);
226 
227  PetscMPIInt myid = 0;
228  if (!HYPRE_AssumedPartitionCheck())
229  {
230  MPI_Comm_rank(comm,&myid);
231  }
232  ierr = VecSetSizes(x,offsets[myid+1]-offsets[myid],PETSC_DECIDE);
233  PCHKERRQ(x,ierr);
234  ierr = VecSetType(x,VECSTANDARD); PCHKERRQ(x,ierr);
236 }
237 
239 {
240  VecScatter scctx;
241  Vec vout;
242  PetscScalar *array;
243  PetscInt size;
244 
245  ierr = VecScatterCreateToAll(x,&scctx,&vout); PCHKERRQ(x,ierr);
246  ierr = VecScatterBegin(scctx,x,vout,INSERT_VALUES,SCATTER_FORWARD);
247  PCHKERRQ(x,ierr);
248  ierr = VecScatterEnd(scctx,x,vout,INSERT_VALUES,SCATTER_FORWARD);
249  PCHKERRQ(x,ierr);
250  ierr = VecScatterDestroy(&scctx); PCHKERRQ(x,ierr);
251  ierr = VecGetArray(vout,&array); PCHKERRQ(x,ierr);
252  ierr = VecGetLocalSize(vout,&size); PCHKERRQ(x,ierr);
253  Array<PetscScalar> data(size);
254  data.Assign(array);
255  ierr = VecRestoreArray(vout,&array); PCHKERRQ(x,ierr);
256  ierr = VecDestroy(&vout); PCHKERRQ(x,ierr);
257  Vector *v = new Vector(data, internal::to_int(size));
258  v->MakeDataOwner();
259  data.LoseData();
260  return v;
261 }
262 
264 {
265  ierr = VecSet(x,d); PCHKERRQ(x,ierr);
266  return *this;
267 }
268 
270 {
271  ierr = VecCopy(y.x,x); PCHKERRQ(x,ierr);
272  return *this;
273 }
274 
275 void PetscParVector::PlaceArray(PetscScalar *temp_data)
276 {
277  ierr = VecPlaceArray(x,temp_data); PCHKERRQ(x,ierr);
278 }
279 
281 {
282  ierr = VecResetArray(x); PCHKERRQ(x,ierr);
283 }
284 
285 void PetscParVector::Randomize(PetscInt seed)
286 {
287  PetscRandom rctx;
288 
289  ierr = PetscRandomCreate(PetscObjectComm((PetscObject)x),&rctx);
290  PCHKERRQ(x,ierr);
291  ierr = PetscRandomSetSeed(rctx,(unsigned long)seed); PCHKERRQ(x,ierr);
292  ierr = PetscRandomSeed(rctx); PCHKERRQ(x,ierr);
293  ierr = VecSetRandom(x,rctx); PCHKERRQ(x,ierr);
294  ierr = PetscRandomDestroy(&rctx); PCHKERRQ(x,ierr);
295 }
296 
297 void PetscParVector::Print(const char *fname, bool binary) const
298 {
299  if (fname)
300  {
301  PetscViewer view;
302 
303  if (binary)
304  {
305  ierr = PetscViewerBinaryOpen(PetscObjectComm((PetscObject)x),fname,
306  FILE_MODE_WRITE,&view);
307  }
308  else
309  {
310  ierr = PetscViewerASCIIOpen(PetscObjectComm((PetscObject)x),fname,&view);
311  }
312  PCHKERRQ(x,ierr);
313  ierr = VecView(x,view); PCHKERRQ(x,ierr);
314  ierr = PetscViewerDestroy(&view); PCHKERRQ(x,ierr);
315  }
316  else
317  {
318  ierr = VecView(x,NULL); PCHKERRQ(x,ierr);
319  }
320 }
321 
322 // PetscParMatrix methods
323 
325 {
326  PetscInt N;
327  ierr = MatGetLocalSize(A,&N,NULL); PCHKERRQ(A,ierr);
328  return N;
329 }
330 
332 {
333  PetscInt N;
334  ierr = MatGetLocalSize(A,NULL,&N); PCHKERRQ(A,ierr);
335  return N;
336 }
337 
338 PetscInt PetscParMatrix::M() const
339 {
340  PetscInt N;
341  ierr = MatGetSize(A,&N,NULL); PCHKERRQ(A,ierr);
342  return N;
343 }
344 
345 PetscInt PetscParMatrix::N() const
346 {
347  PetscInt N;
348  ierr = MatGetSize(A,NULL,&N); PCHKERRQ(A,ierr);
349  return N;
350 }
351 
352 PetscInt PetscParMatrix::NNZ() const
353 {
354  MatInfo info;
355  ierr = MatGetInfo(A,MAT_GLOBAL_SUM,&info); PCHKERRQ(A,ierr);
356  return (PetscInt)info.nz_used;
357 }
358 
360 {
361  A = NULL;
362  X = Y = NULL;
363  height = width = 0;
364 }
365 
367 {
368  Init();
369 }
370 
372 {
373  Init();
374  height = ha->Height();
375  width = ha->Width();
376  switch (tid)
377  {
381  break;
383  MakeWrapper(ha->GetComm(),ha,&A);
384  break;
385  default:
386  MFEM_ABORT("unsupported PETSc format: type id = " << tid);
387  }
388 }
389 
390 PetscParMatrix::PetscParMatrix(MPI_Comm comm, const Operator *op,
391  Operator::Type tid)
392 {
393  Init();
394  PetscParMatrix *pA = const_cast<PetscParMatrix *>
395  (dynamic_cast<const PetscParMatrix *>(op));
396  height = op->Height();
397  width = op->Width();
398  if (tid == PETSC_MATSHELL && !pA) { MakeWrapper(comm,op,&A); }
399  else { ConvertOperator(comm,*op,&A,tid==PETSC_MATAIJ); }
400 }
401 
402 PetscParMatrix::PetscParMatrix(MPI_Comm comm, PetscInt glob_size,
403  PetscInt *row_starts, SparseMatrix *diag,
404  Operator::Type tid)
405 {
406  Init();
407  BlockDiagonalConstructor(comm,row_starts,row_starts,diag,
408  tid==PETSC_MATAIJ,&A);
409  // update base class
410  height = GetNumRows();
411  width = GetNumCols();
412 }
413 
414 PetscParMatrix::PetscParMatrix(MPI_Comm comm, PetscInt global_num_rows,
415  PetscInt global_num_cols, PetscInt *row_starts,
416  PetscInt *col_starts, SparseMatrix *diag,
417  Operator::Type tid)
418 {
419  Init();
420  BlockDiagonalConstructor(comm,row_starts,col_starts,diag,
421  tid==PETSC_MATAIJ,&A);
422  // update base class
423  height = GetNumRows();
424  width = GetNumCols();
425 }
426 
428 {
429  if (A)
430  {
431  MPI_Comm comm = PetscObjectComm((PetscObject)A);
432  ierr = MatDestroy(&A); CCHKERRQ(comm,ierr);
433  if (X) { delete X; }
434  if (Y) { delete Y; }
435  X = Y = NULL;
436  }
437  height = B.Height();
438  width = B.Width();
439 #if defined(PETSC_HAVE_HYPRE)
440  ierr = MatCreateFromParCSR(B,MATAIJ,PETSC_USE_POINTER,&A);
441 #else
442  ierr = MatConvert_hypreParCSR_AIJ(B,&A); CCHKERRQ(B.GetComm(),ierr);
443 #endif
444  return *this;
445 }
446 
448 {
449  if (A)
450  {
451  MPI_Comm comm = PetscObjectComm((PetscObject)A);
452  ierr = MatDestroy(&A); CCHKERRQ(comm,ierr);
453  if (X) { delete X; }
454  if (Y) { delete Y; }
455  X = Y = NULL;
456  }
457  height = B.Height();
458  width = B.Width();
459  ierr = MatDuplicate(B,MAT_COPY_VALUES,&A); CCHKERRQ(B.GetComm(),ierr);
460  return *this;
461 }
462 
464 {
465  if (!A)
466  {
467  ierr = MatDuplicate(B,MAT_COPY_VALUES,&A); CCHKERRQ(B.GetComm(),ierr);
468  }
469  else
470  {
471  MFEM_VERIFY(height == B.Height(),"Invalid number of local rows");
472  MFEM_VERIFY(width == B.Width(), "Invalid number of local columns");
473  ierr = MatAXPY(A,1.0,B,DIFFERENT_NONZERO_PATTERN); CCHKERRQ(B.GetComm(),ierr);
474  }
475  return *this;
476 }
477 
478 void PetscParMatrix::
479 BlockDiagonalConstructor(MPI_Comm comm,
480  PetscInt *row_starts, PetscInt *col_starts,
481  SparseMatrix *diag, bool assembled, Mat* Ad)
482 {
483  Mat A;
484  PetscInt lrsize,lcsize,rstart,cstart;
485  PetscMPIInt myid = 0,commsize;
486 
487  ierr = MPI_Comm_size(comm,&commsize); CCHKERRQ(comm,ierr);
488  if (!HYPRE_AssumedPartitionCheck())
489  {
490  ierr = MPI_Comm_rank(comm,&myid); CCHKERRQ(comm,ierr);
491  }
492  lrsize = row_starts[myid+1]-row_starts[myid];
493  rstart = row_starts[myid];
494  lcsize = col_starts[myid+1]-col_starts[myid];
495  cstart = col_starts[myid];
496 
497  if (!assembled)
498  {
499  IS is;
500  ierr = ISCreateStride(comm,diag->Height(),rstart,1,&is); CCHKERRQ(comm,ierr);
501  ISLocalToGlobalMapping rl2g,cl2g;
502  ierr = ISLocalToGlobalMappingCreateIS(is,&rl2g); PCHKERRQ(is,ierr);
503  ierr = ISDestroy(&is); CCHKERRQ(comm,ierr);
504  if (row_starts != col_starts)
505  {
506  ierr = ISCreateStride(comm,diag->Width(),cstart,1,&is);
507  CCHKERRQ(comm,ierr);
508  ierr = ISLocalToGlobalMappingCreateIS(is,&cl2g); PCHKERRQ(is,ierr);
509  ierr = ISDestroy(&is); CCHKERRQ(comm,ierr);
510  }
511  else
512  {
513  ierr = PetscObjectReference((PetscObject)rl2g); PCHKERRQ(rl2g,ierr);
514  cl2g = rl2g;
515  }
516 
517  // Create the PETSc object (MATIS format)
518  ierr = MatCreate(comm,&A); CCHKERRQ(comm,ierr);
519  ierr = MatSetSizes(A,lrsize,lcsize,PETSC_DECIDE,PETSC_DECIDE);
520  PCHKERRQ(A,ierr);
521  ierr = MatSetType(A,MATIS); PCHKERRQ(A,ierr);
522  ierr = MatSetLocalToGlobalMapping(A,rl2g,cl2g); PCHKERRQ(A,ierr);
523  ierr = ISLocalToGlobalMappingDestroy(&rl2g); PCHKERRQ(A,ierr)
524  ierr = ISLocalToGlobalMappingDestroy(&cl2g); PCHKERRQ(A,ierr)
525 
526  // Copy SparseMatrix into PETSc SeqAIJ format
527  Mat lA;
528  ierr = MatISGetLocalMat(A,&lA); PCHKERRQ(A,ierr);
529  if (sizeof(PetscInt) == sizeof(int))
530  {
531  ierr = MatSeqAIJSetPreallocationCSR(lA,diag->GetI(),diag->GetJ(),
532  diag->GetData()); PCHKERRQ(lA,ierr);
533  }
534  else
535  {
536  MFEM_ABORT("64bit indices not yet supported");
537  }
538  }
539  else
540  {
541  PetscScalar *da;
542  PetscInt *dii,*djj,*oii,
543  m = diag->Height()+1, nnz = diag->NumNonZeroElems();
544 
545  diag->SortColumnIndices();
546  // if we can take ownership of the SparseMatrix arrays, we can avoid this
547  // step
548  ierr = PetscMalloc1(m,&dii); CCHKERRQ(PETSC_COMM_SELF,ierr);
549  ierr = PetscMalloc1(nnz,&djj); CCHKERRQ(PETSC_COMM_SELF,ierr);
550  ierr = PetscMalloc1(nnz,&da); CCHKERRQ(PETSC_COMM_SELF,ierr);
551  if (sizeof(PetscInt) == sizeof(int))
552  {
553  ierr = PetscMemcpy(dii,diag->GetI(),m*sizeof(PetscInt));
554  CCHKERRQ(PETSC_COMM_SELF,ierr);
555  ierr = PetscMemcpy(djj,diag->GetJ(),nnz*sizeof(PetscInt));
556  CCHKERRQ(PETSC_COMM_SELF,ierr);
557  ierr = PetscMemcpy(da,diag->GetData(),nnz*sizeof(PetscScalar));
558  CCHKERRQ(PETSC_COMM_SELF,ierr);
559  }
560  else
561  {
562  MFEM_ABORT("64bit indices not yet supported");
563  }
564  ierr = PetscCalloc1(m,&oii);
565  CCHKERRQ(PETSC_COMM_SELF,ierr);
566  if (commsize > 1)
567  {
568  ierr = MatCreateMPIAIJWithSplitArrays(comm,lrsize,lcsize,PETSC_DECIDE,
569  PETSC_DECIDE,
570  dii,djj,da,oii,NULL,NULL,&A);
571  CCHKERRQ(comm,ierr);
572  }
573  else
574  {
575  ierr = MatCreateSeqAIJWithArrays(comm,lrsize,lcsize,dii,djj,da,&A);
576  CCHKERRQ(comm,ierr);
577  }
578 
579  void *ptrs[4] = {dii,djj,da,oii};
580  const char *names[4] = {"_mfem_csr_dii",
581  "_mfem_csr_djj",
582  "_mfem_csr_da",
583  "_mfem_csr_oii",
584  };
585  for (PetscInt i=0; i<4; i++)
586  {
587  PetscContainer c;
588 
589  ierr = PetscContainerCreate(comm,&c); CCHKERRQ(comm,ierr);
590  ierr = PetscContainerSetPointer(c,ptrs[i]); CCHKERRQ(comm,ierr);
591  ierr = PetscContainerSetUserDestroy(c,__mfem_array_container_destroy);
592  CCHKERRQ(comm,ierr);
593  ierr = PetscObjectCompose((PetscObject)A,names[i],(PetscObject)c);
594  CCHKERRQ(comm,ierr);
595  ierr = PetscContainerDestroy(&c); CCHKERRQ(comm,ierr);
596  }
597  }
598 
599  // Tell PETSc the matrix is ready to be used
600  ierr = MatAssemblyBegin(A,MAT_FINAL_ASSEMBLY); PCHKERRQ(A,ierr);
601  ierr = MatAssemblyEnd(A,MAT_FINAL_ASSEMBLY); PCHKERRQ(A,ierr);
602 
603  *Ad = A;
604 }
605 
606 // TODO ADD THIS CONSTRUCTOR
607 //PetscParMatrix::PetscParMatrix(MPI_Comm comm, int nrows, PetscInt glob_nrows,
608 // PetscInt glob_ncols, int *I, PetscInt *J,
609 // double *data, PetscInt *rows, PetscInt *cols)
610 //{
611 //}
612 
613 // TODO This should take a reference on op but how?
614 void PetscParMatrix::MakeWrapper(MPI_Comm comm, const Operator* op, Mat *A)
615 {
616  mat_shell_ctx *ctx = new mat_shell_ctx;
617  ierr = MatCreate(comm,A); CCHKERRQ(comm,ierr);
618  ierr = MatSetSizes(*A,op->Height(),op->Width(),
619  PETSC_DECIDE,PETSC_DECIDE); PCHKERRQ(A,ierr);
620  ierr = MatSetType(*A,MATSHELL); PCHKERRQ(A,ierr);
621  ierr = MatShellSetContext(*A,(void *)ctx); PCHKERRQ(A,ierr);
622  ierr = MatShellSetOperation(*A,MATOP_MULT,
623  (void (*)())__mfem_mat_shell_apply);
624  PCHKERRQ(A,ierr);
625  ierr = MatShellSetOperation(*A,MATOP_MULT_TRANSPOSE,
626  (void (*)())__mfem_mat_shell_apply_transpose);
627  PCHKERRQ(A,ierr);
628  ierr = MatShellSetOperation(*A,MATOP_DESTROY,
629  (void (*)())__mfem_mat_shell_destroy);
630  PCHKERRQ(A,ierr);
631  ierr = MatSetUp(*A); PCHKERRQ(*A,ierr);
632  ctx->op = const_cast<Operator *>(op);
633 }
634 
635 void PetscParMatrix::ConvertOperator(MPI_Comm comm, const Operator &op, Mat* A,
636  bool assembled)
637 {
638  PetscParMatrix *pA = const_cast<PetscParMatrix *>
639  (dynamic_cast<const PetscParMatrix *>(&op));
640  HypreParMatrix *pH = const_cast<HypreParMatrix *>
641  (dynamic_cast<const HypreParMatrix *>(&op));
642  BlockOperator *pB = const_cast<BlockOperator *>
643  (dynamic_cast<const BlockOperator *>(&op));
644  IdentityOperator *pI = const_cast<IdentityOperator *>
645  (dynamic_cast<const IdentityOperator *>(&op));
646  if (pA)
647  {
648  Mat At = NULL;
649  PetscBool ismatis,istrans;
650 
651  ierr = PetscObjectTypeCompare((PetscObject)(pA->A),MATTRANSPOSEMAT,&istrans);
652  CCHKERRQ(pA->GetComm(),ierr);
653  if (!istrans)
654  {
655  ierr = PetscObjectTypeCompare((PetscObject)(pA->A),MATIS,&ismatis);
656  CCHKERRQ(pA->GetComm(),ierr);
657  }
658  else
659  {
660  ierr = MatTransposeGetMat(pA->A,&At); CCHKERRQ(pA->GetComm(),ierr);
661  ierr = PetscObjectTypeCompare((PetscObject)(At),MATIS,&ismatis);
662  CCHKERRQ(pA->GetComm(),ierr);
663  }
664  if (assembled && ismatis)
665  {
666  if (At)
667  {
668  Mat B;
669 
670  ierr = MatISGetMPIXAIJ(At,MAT_INITIAL_MATRIX,&B); PCHKERRQ(pA->A,ierr);
671  ierr = MatCreateTranspose(B,A); PCHKERRQ(pA->A,ierr);
672  ierr = MatDestroy(&B); PCHKERRQ(pA->A,ierr);
673  }
674  else
675  {
676  ierr = MatISGetMPIXAIJ(pA->A,MAT_INITIAL_MATRIX,A);
677  PCHKERRQ(pA->A,ierr);
678  }
679  }
680  else
681  {
682  if ((!assembled && !ismatis))
683  {
684  // call MatConvert and see if a converter is available
685  ierr = MatConvert(pA->A,MATIS,MAT_INITIAL_MATRIX,A);
686  CCHKERRQ(comm,ierr);
687  }
688  else
689  {
690  ierr = PetscObjectReference((PetscObject)(pA->A));
691  CCHKERRQ(pA->GetComm(),ierr);
692  *A = pA->A;
693  }
694  }
695  }
696  else if (pH)
697  {
698  if (assembled)
699  {
700 #if defined(PETSC_HAVE_HYPRE)
701  ierr = MatCreateFromParCSR(const_cast<HypreParMatrix&>(*pH),MATAIJ,
702  PETSC_USE_POINTER,A);
703 #else
704  ierr = MatConvert_hypreParCSR_AIJ(const_cast<HypreParMatrix&>(*pH),A);
705 #endif
706  }
707  else
708  {
709 #if defined(PETSC_HAVE_HYPRE)
710  ierr = MatCreateFromParCSR(const_cast<HypreParMatrix&>(*pH),MATIS,
711  PETSC_USE_POINTER,A);
712 #else
713  ierr = MatConvert_hypreParCSR_IS(const_cast<HypreParMatrix&>(*pH),A);
714 #endif
715  }
716  CCHKERRQ(pH->GetComm(),ierr);
717  }
718  else if (pB)
719  {
720  Mat *mats,*matsl2l = NULL;
721  PetscInt i,j,nr,nc;
722 
723  nr = pB->NumRowBlocks();
724  nc = pB->NumColBlocks();
725  ierr = PetscCalloc1(nr*nc,&mats); CCHKERRQ(PETSC_COMM_SELF,ierr);
726  if (!assembled)
727  {
728  ierr = PetscCalloc1(nr,&matsl2l); CCHKERRQ(PETSC_COMM_SELF,ierr);
729  }
730  for (i=0; i<nr; i++)
731  {
732  PetscBool needl2l = PETSC_TRUE;
733 
734  for (j=0; j<nc; j++)
735  {
736  if (!pB->IsZeroBlock(i,j))
737  {
738  ConvertOperator(comm,pB->GetBlock(i,j),&mats[i*nc+j],assembled);
739  if (!assembled && needl2l)
740  {
741  PetscContainer c;
742  ierr = PetscObjectQuery((PetscObject)mats[i*nc+j],"__mfem_l2l",
743  (PetscObject*)&c);
744  PCHKERRQ(mats[i*nc+j],ierr);
745  // special case for block operators: the local Vdofs should be
746  // ordered as:
747  // [f1_1,...f1_N1,f2_1,...,f2_N2,...,fm_1,...,fm_Nm]
748  // with m fields, Ni the number of Vdofs for the i-th field
749  if (c)
750  {
751  Array<Mat> *l2l = NULL;
752  ierr = PetscContainerGetPointer(c,(void**)&l2l);
753  PCHKERRQ(c,ierr);
754  MFEM_VERIFY(l2l->Size() == 1,"Unexpected size "
755  << l2l->Size() << " for block row " << i );
756  ierr = PetscObjectReference((PetscObject)(*l2l)[0]);
757  PCHKERRQ(c,ierr);
758  matsl2l[i] = (*l2l)[0];
759  needl2l = PETSC_FALSE;
760  }
761  }
762  }
763  }
764  }
765  ierr = MatCreateNest(comm,nr,NULL,nc,NULL,mats,A); CCHKERRQ(comm,ierr);
766  if (!assembled)
767  {
768  ierr = MatConvert(*A,MATIS,MAT_INPLACE_MATRIX,A); CCHKERRQ(comm,ierr);
769 
770  mfem::Array<Mat> *vmatsl2l = new mfem::Array<Mat>(nr);
771  for (PetscInt i=0; i<nr; i++) { (*vmatsl2l)[i] = matsl2l[i]; }
772  ierr = PetscFree(matsl2l); CCHKERRQ(PETSC_COMM_SELF,ierr);
773 
774  PetscContainer c;
775  ierr = PetscContainerCreate(comm,&c); CCHKERRQ(comm,ierr);
776  ierr = PetscContainerSetPointer(c,vmatsl2l); PCHKERRQ(c,ierr);
777  ierr = PetscContainerSetUserDestroy(c,__mfem_matarray_container_destroy);
778  PCHKERRQ(c,ierr);
779  ierr = PetscObjectCompose((PetscObject)(*A),"__mfem_l2l",(PetscObject)c);
780  PCHKERRQ((*A),ierr);
781  ierr = PetscContainerDestroy(&c); CCHKERRQ(comm,ierr);
782  }
783  for (i=0; i<nr*nc; i++) { ierr = MatDestroy(&mats[i]); CCHKERRQ(comm,ierr); }
784  ierr = PetscFree(mats); CCHKERRQ(PETSC_COMM_SELF,ierr);
785  }
786  else if (pI)
787  {
788  MFEM_VERIFY(assembled,"Unsupported operation");
789  PetscInt rst;
790 
791  ierr = MatCreate(comm,A); CCHKERRQ(comm,ierr);
792  ierr = MatSetSizes(*A,pI->Height(),pI->Width(),PETSC_DECIDE,PETSC_DECIDE);
793  PCHKERRQ(A,ierr);
794  ierr = MatSetType(*A,MATAIJ); PCHKERRQ(*A,ierr);
795  ierr = MatMPIAIJSetPreallocation(*A,1,NULL,0,NULL); PCHKERRQ(*A,ierr);
796  ierr = MatSeqAIJSetPreallocation(*A,1,NULL); PCHKERRQ(*A,ierr);
797  ierr = MatSetOption(*A,MAT_NO_OFF_PROC_ENTRIES,PETSC_TRUE); PCHKERRQ(*A,ierr);
798  ierr = MatGetOwnershipRange(*A,&rst,NULL); PCHKERRQ(*A,ierr);
799  for (PetscInt i = rst; i < rst+pI->Height(); i++)
800  {
801  ierr = MatSetValue(*A,i,i,1.,INSERT_VALUES); PCHKERRQ(*A,ierr);
802  }
803  ierr = MatAssemblyBegin(*A,MAT_FINAL_ASSEMBLY); PCHKERRQ(*A,ierr);
804  ierr = MatAssemblyEnd(*A,MAT_FINAL_ASSEMBLY); PCHKERRQ(*A,ierr);
805  }
806  else
807  {
808  // fallback to MatShell
809  MakeWrapper(comm,&op,A);
810  }
811 }
812 
814 {
815  if (A != NULL)
816  {
817  MPI_Comm comm = MPI_COMM_NULL;
818  ierr = PetscObjectGetComm((PetscObject)A,&comm); PCHKERRQ(A,ierr);
819  ierr = MatDestroy(&A); CCHKERRQ(comm,ierr);
820  }
821  delete X;
822  delete Y;
823  X = Y = NULL;
824 }
825 
827 {
828  if (ref)
829  {
830  ierr = PetscObjectReference((PetscObject)a); PCHKERRQ(a,ierr);
831  }
832  Init();
833  A = a;
834  height = GetNumRows();
835  width = GetNumCols();
836 }
837 
838 // Computes y = alpha * A * x + beta * y
839 // or y = alpha * A^T* x + beta * y
840 static void MatMultKernel(Mat A,PetscScalar a,Vec X,PetscScalar b,Vec Y,
841  bool transpose)
842 {
843  PetscErrorCode (*f)(Mat,Vec,Vec);
844  PetscErrorCode (*fadd)(Mat,Vec,Vec,Vec);
845  if (transpose)
846  {
847  f = MatMultTranspose;
848  fadd = MatMultTransposeAdd;
849  }
850  else
851  {
852  f = MatMult;
853  fadd = MatMultAdd;
854  }
855  if (a != 0.)
856  {
857  if (b == 1.)
858  {
859  ierr = VecScale(X,a); PCHKERRQ(A,ierr);
860  ierr = (*fadd)(A,X,Y,Y); PCHKERRQ(A,ierr);
861  ierr = VecScale(X,1./a); PCHKERRQ(A,ierr);
862  }
863  else if (b != 0.)
864  {
865  ierr = VecScale(X,a); PCHKERRQ(A,ierr);
866  ierr = VecScale(Y,b); PCHKERRQ(A,ierr);
867  ierr = (*fadd)(A,X,Y,Y); PCHKERRQ(A,ierr);
868  ierr = VecScale(X,1./a); PCHKERRQ(A,ierr);
869  }
870  else
871  {
872  ierr = (*f)(A,X,Y); PCHKERRQ(A,ierr);
873  if (a != 1.)
874  {
875  ierr = VecScale(Y,a); PCHKERRQ(A,ierr);
876  }
877  }
878  }
879  else
880  {
881  if (b == 1.)
882  {
883  // do nothing
884  }
885  else if (b != 0.)
886  {
887  ierr = VecScale(Y,b); PCHKERRQ(A,ierr);
888  }
889  else
890  {
891  ierr = VecSet(Y,0.); PCHKERRQ(A,ierr);
892  }
893  }
894 }
895 
897 {
898  ierr = PetscObjectReference((PetscObject)master.A); PCHKERRQ(master.A,ierr);
899  Destroy();
900  Init();
901  A = master.A;
902  height = master.height;
903  width = master.width;
904 }
905 
907 {
908  if (!X)
909  {
910  MFEM_VERIFY(A,"Mat not present");
911  X = new PetscParVector(*this,false); PCHKERRQ(A,ierr);
912  }
913  return X;
914 }
915 
917 {
918  if (!Y)
919  {
920  MFEM_VERIFY(A,"Mat not present");
921  Y = new PetscParVector(*this,true); PCHKERRQ(A,ierr);
922  }
923  return Y;
924 }
925 
927 {
928  Mat B;
929  if (action)
930  {
931  ierr = MatCreateTranspose(A,&B); PCHKERRQ(A,ierr);
932  }
933  else
934  {
935  ierr = MatTranspose(A,MAT_INITIAL_MATRIX,&B); PCHKERRQ(A,ierr);
936  }
937  return new PetscParMatrix(B,false);
938 }
939 
941 {
942  ierr = MatScale(A,s); PCHKERRQ(A,ierr);
943 }
944 
945 void PetscParMatrix::Mult(double a, const Vector &x, double b, Vector &y) const
946 {
947  MFEM_ASSERT(x.Size() == Width(), "invalid x.Size() = " << x.Size()
948  << ", expected size = " << Width());
949  MFEM_ASSERT(y.Size() == Height(), "invalid y.Size() = " << y.Size()
950  << ", expected size = " << Height());
951 
952  PetscParVector *XX = GetX();
953  PetscParVector *YY = GetY();
954  XX->PlaceArray(x.GetData());
955  YY->PlaceArray(y.GetData());
956  MatMultKernel(A,a,XX->x,b,YY->x,false);
957  XX->ResetArray();
958  YY->ResetArray();
959 }
960 
961 void PetscParMatrix::MultTranspose(double a, const Vector &x, double b,
962  Vector &y) const
963 {
964  MFEM_ASSERT(x.Size() == Height(), "invalid x.Size() = " << x.Size()
965  << ", expected size = " << Height());
966  MFEM_ASSERT(y.Size() == Width(), "invalid y.Size() = " << y.Size()
967  << ", expected size = " << Width());
968 
969  PetscParVector *XX = GetX();
970  PetscParVector *YY = GetY();
971  YY->PlaceArray(x.GetData());
972  XX->PlaceArray(y.GetData());
973  MatMultKernel(A,a,YY->x,b,XX->x,true);
974  XX->ResetArray();
975  YY->ResetArray();
976 }
977 
978 void PetscParMatrix::Print(const char *fname, bool binary) const
979 {
980  if (fname)
981  {
982  PetscViewer view;
983 
984  if (binary)
985  {
986  ierr = PetscViewerBinaryOpen(PetscObjectComm((PetscObject)A),fname,
987  FILE_MODE_WRITE,&view);
988  }
989  else
990  {
991  ierr = PetscViewerASCIIOpen(PetscObjectComm((PetscObject)A),fname,&view);
992  }
993  PCHKERRQ(A,ierr);
994  ierr = MatView(A,view); PCHKERRQ(A,ierr);
995  ierr = PetscViewerDestroy(&view); PCHKERRQ(A,ierr);
996  }
997  else
998  {
999  ierr = MatView(A,NULL); PCHKERRQ(A,ierr);
1000  }
1001 }
1002 
1003 
1005 {
1006  Mat pA = *A,pP = *P,pRt = *Rt;
1007  Mat B;
1008  PetscBool Aismatis,Pismatis,Rtismatis;
1009 
1010  MFEM_VERIFY(A->Width() == P->Height(),
1011  "Petsc RAP: Number of local cols of A " << A->Width() <<
1012  " differs from number of local rows of P " << P->Height());
1013  MFEM_VERIFY(A->Height() == Rt->Height(),
1014  "Petsc RAP: Number of local rows of A " << A->Height() <<
1015  " differs from number of local rows of Rt " << Rt->Height());
1016  ierr = PetscObjectTypeCompare((PetscObject)pA,MATIS,&Aismatis);
1017  PCHKERRQ(pA,ierr);
1018  ierr = PetscObjectTypeCompare((PetscObject)pP,MATIS,&Pismatis);
1019  PCHKERRQ(pA,ierr);
1020  ierr = PetscObjectTypeCompare((PetscObject)pRt,MATIS,&Rtismatis);
1021  PCHKERRQ(pA,ierr);
1022  if (Aismatis &&
1023  Pismatis &&
1024  Rtismatis) // handle special case (this code will eventually go into PETSc)
1025  {
1026  Mat lA,lP,lB,lRt;
1027  ISLocalToGlobalMapping cl2gP,cl2gRt;
1028  PetscInt rlsize,clsize,rsize,csize;
1029 
1030  ierr = MatGetLocalToGlobalMapping(pP,NULL,&cl2gP); PCHKERRQ(pA,ierr);
1031  ierr = MatGetLocalToGlobalMapping(pRt,NULL,&cl2gRt); PCHKERRQ(pA,ierr);
1032  ierr = MatGetLocalSize(pP,NULL,&clsize); PCHKERRQ(pP,ierr);
1033  ierr = MatGetLocalSize(pRt,NULL,&rlsize); PCHKERRQ(pRt,ierr);
1034  ierr = MatGetSize(pP,NULL,&csize); PCHKERRQ(pP,ierr);
1035  ierr = MatGetSize(pRt,NULL,&rsize); PCHKERRQ(pRt,ierr);
1036  ierr = MatCreate(A->GetComm(),&B); PCHKERRQ(pA,ierr);
1037  ierr = MatSetSizes(B,rlsize,clsize,rsize,csize); PCHKERRQ(B,ierr);
1038  ierr = MatSetType(B,MATIS); PCHKERRQ(B,ierr);
1039  ierr = MatSetLocalToGlobalMapping(B,cl2gRt,cl2gP); PCHKERRQ(B,ierr);
1040  ierr = MatISGetLocalMat(pA,&lA); PCHKERRQ(pA,ierr);
1041  ierr = MatISGetLocalMat(pP,&lP); PCHKERRQ(pA,ierr);
1042  ierr = MatISGetLocalMat(pRt,&lRt); PCHKERRQ(pA,ierr);
1043  if (lRt == lP)
1044  {
1045  ierr = MatPtAP(lA,lP,MAT_INITIAL_MATRIX,PETSC_DEFAULT,&lB);
1046  PCHKERRQ(lA,ierr);
1047  }
1048  else
1049  {
1050  Mat lR;
1051  ierr = MatTranspose(lRt,MAT_INITIAL_MATRIX,&lR); PCHKERRQ(lRt,ierr);
1052  ierr = MatMatMatMult(lR,lA,lP,MAT_INITIAL_MATRIX,PETSC_DEFAULT,&lB);
1053  PCHKERRQ(lRt,ierr);
1054  ierr = MatDestroy(&lR); PCHKERRQ(lRt,ierr);
1055  }
1056 
1057  // attach lRt matrix to the subdomain local matrix
1058  // it may be used if markers on vdofs have to be mapped on
1059  // subdomain true dofs
1060  {
1061  mfem::Array<Mat> *vmatsl2l = new mfem::Array<Mat>(1);
1062  ierr = PetscObjectReference((PetscObject)lRt); PCHKERRQ(lRt,ierr);
1063  (*vmatsl2l)[0] = lRt;
1064 
1065  PetscContainer c;
1066  ierr = PetscContainerCreate(PetscObjectComm((PetscObject)B),&c);
1067  PCHKERRQ(B,ierr);
1068  ierr = PetscContainerSetPointer(c,vmatsl2l); PCHKERRQ(c,ierr);
1069  ierr = PetscContainerSetUserDestroy(c,__mfem_matarray_container_destroy);
1070  PCHKERRQ(c,ierr);
1071  ierr = PetscObjectCompose((PetscObject)B,"__mfem_l2l",(PetscObject)c);
1072  PCHKERRQ(B,ierr);
1073  ierr = PetscContainerDestroy(&c); PCHKERRQ(B,ierr);
1074  }
1075 
1076  // Set local problem
1077  ierr = MatISSetLocalMat(B,lB); PCHKERRQ(lB,ierr);
1078  ierr = MatDestroy(&lB); PCHKERRQ(lA,ierr);
1079  ierr = MatAssemblyBegin(B,MAT_FINAL_ASSEMBLY); PCHKERRQ(B,ierr);
1080  ierr = MatAssemblyEnd(B,MAT_FINAL_ASSEMBLY); PCHKERRQ(B,ierr);
1081  }
1082  else // it raises an error if the PtAP is not supported in PETSc
1083  {
1084  if (pP == pRt)
1085  {
1086  ierr = MatPtAP(pA,pP,MAT_INITIAL_MATRIX,PETSC_DEFAULT,&B);
1087  PCHKERRQ(pA,ierr);
1088  }
1089  else
1090  {
1091  Mat pR;
1092  ierr = MatTranspose(pRt,MAT_INITIAL_MATRIX,&pR); PCHKERRQ(Rt,ierr);
1093  ierr = MatMatMatMult(pR,pA,pP,MAT_INITIAL_MATRIX,PETSC_DEFAULT,&B);
1094  PCHKERRQ(pRt,ierr);
1095  ierr = MatDestroy(&pR); PCHKERRQ(pRt,ierr);
1096  }
1097  }
1098  return new PetscParMatrix(B);
1099 }
1100 
1102 {
1103  PetscParMatrix *out = RAP(P,A,P);
1104  return out;
1105 }
1106 
1108 {
1109  Mat Ae;
1110  const int *data;
1111  PetscInt M,N,i,n,*idxs,rst;
1112 
1113  ierr = MatGetSize(A,&M,&N); PCHKERRQ(A,ierr);
1114  MFEM_VERIFY(M == N,"Rectangular case unsupported");
1115  ierr = MatGetOwnershipRange(A,&rst,NULL); PCHKERRQ(A,ierr);
1116  ierr = MatDuplicate(A,MAT_COPY_VALUES,&Ae); PCHKERRQ(A,ierr);
1117  ierr = MatSetOption(A,MAT_NO_OFF_PROC_ZERO_ROWS,PETSC_TRUE); PCHKERRQ(A,ierr);
1118  // rows need to be in global numbering
1119  n = rows_cols.Size();
1120  data = rows_cols.GetData();
1121  ierr = PetscMalloc1(n,&idxs); PCHKERRQ(A,ierr);
1122  for (i=0; i<n; i++) { idxs[i] = data[i] + rst; }
1123  ierr = MatZeroRowsColumns(A,n,idxs,1.,NULL,NULL); PCHKERRQ(A,ierr);
1124  ierr = PetscFree(idxs); PCHKERRQ(A,ierr);
1125  ierr = MatAXPY(Ae,-1.,A,SAME_NONZERO_PATTERN); PCHKERRQ(A,ierr);
1126  return new PetscParMatrix(Ae);
1127 }
1128 
1130  const HypreParVector &X,
1131  HypreParVector &B)
1132 {
1133  MFEM_ABORT("To be implemented");
1134 }
1135 
1136 Mat PetscParMatrix::ReleaseMat(bool dereference)
1137 {
1138 
1139  Mat B = A;
1140  if (dereference)
1141  {
1142  MPI_Comm comm = GetComm();
1143  ierr = PetscObjectDereference((PetscObject)A); CCHKERRQ(comm,ierr);
1144  }
1145  A = NULL;
1146  return B;
1147 }
1148 
1150 {
1151  PetscBool ok;
1152  MFEM_VERIFY(A, "no associated PETSc Mat object");
1153  PetscObject oA = (PetscObject)(this->A);
1154  // map all of MATAIJ, MATSEQAIJ, and MATMPIAIJ to -> PETSC_MATAIJ
1155  ierr = PetscObjectTypeCompare(oA, MATAIJ, &ok); PCHKERRQ(A,ierr);
1156  if (ok == PETSC_TRUE) { return PETSC_MATAIJ; }
1157  ierr = PetscObjectTypeCompare(oA, MATSEQAIJ, &ok); PCHKERRQ(A,ierr);
1158  if (ok == PETSC_TRUE) { return PETSC_MATAIJ; }
1159  ierr = PetscObjectTypeCompare(oA, MATMPIAIJ, &ok); PCHKERRQ(A,ierr);
1160  if (ok == PETSC_TRUE) { return PETSC_MATAIJ; }
1161  ierr = PetscObjectTypeCompare(oA, MATIS, &ok); PCHKERRQ(A,ierr);
1162  if (ok == PETSC_TRUE) { return PETSC_MATIS; }
1163  ierr = PetscObjectTypeCompare(oA, MATSHELL, &ok); PCHKERRQ(A,ierr);
1164  if (ok == PETSC_TRUE) { return PETSC_MATSHELL; }
1165  ierr = PetscObjectTypeCompare(oA, MATNEST, &ok); PCHKERRQ(A,ierr);
1166  if (ok == PETSC_TRUE) { return PETSC_MATNEST; }
1167  MatType mat_type; // char *
1168  ierr = MatGetType(A, &mat_type); PCHKERRQ(A,ierr);
1169  MFEM_ABORT("PETSc matrix type = '" << mat_type << "' is not implemented");
1170  return PETSC_MATAIJ;
1171 }
1172 
1174  const Array<int> &ess_dof_list,
1175  const Vector &X, Vector &B)
1176 {
1177  const PetscScalar *array;
1178  Mat pA = const_cast<PetscParMatrix&>(A);
1179 
1180  // B -= Ae*X
1181  Ae.Mult(-1.0, X, 1.0, B);
1182 
1183  Vec diag = const_cast<PetscParVector&>((*A.GetX()));
1184  ierr = MatGetDiagonal(pA,diag); PCHKERRQ(pA,ierr);
1185  ierr = VecGetArrayRead(diag,&array); PCHKERRQ(diag,ierr);
1186  for (int i = 0; i < ess_dof_list.Size(); i++)
1187  {
1188  int r = ess_dof_list[i];
1189  B(r) = array[r] * X(r);
1190  }
1191  ierr = VecRestoreArrayRead(diag,&array); PCHKERRQ(diag,ierr);
1192 }
1193 
1194 // PetscSolver methods
1195 
1196 PetscSolver::PetscSolver() : clcustom(false)
1197 {
1198  obj = NULL;
1199  B = X = NULL;
1200  cid = -1;
1201  monitor_ctx = NULL;
1202  operatorset = false;
1203 }
1204 
1206 {
1207  delete B;
1208  delete X;
1209 }
1210 
1211 void PetscSolver::SetTol(double tol)
1212 {
1213  SetRelTol(tol);
1214 }
1215 
1216 void PetscSolver::SetRelTol(double tol)
1217 {
1218  if (cid == KSP_CLASSID)
1219  {
1220  KSP ksp = (KSP)obj;
1221  ierr = KSPSetTolerances(ksp,tol,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT);
1222  }
1223  else if (cid == SNES_CLASSID)
1224  {
1225  SNES snes = (SNES)obj;
1226  ierr = SNESSetTolerances(snes,PETSC_DEFAULT,tol,PETSC_DEFAULT,PETSC_DEFAULT,
1227  PETSC_DEFAULT);
1228  }
1229  else if (cid == TS_CLASSID)
1230  {
1231  TS ts = (TS)obj;
1232  ierr = TSSetTolerances(ts,PETSC_DECIDE,NULL,tol,NULL);
1233  }
1234  else
1235  {
1236  MFEM_ABORT("CLASSID = " << cid << " is not implemented!");
1237  }
1238  PCHKERRQ(obj,ierr);
1239 }
1240 
1241 void PetscSolver::SetAbsTol(double tol)
1242 {
1243  if (cid == KSP_CLASSID)
1244  {
1245  KSP ksp = (KSP)obj;
1246  ierr = KSPSetTolerances(ksp,PETSC_DEFAULT,tol,PETSC_DEFAULT,PETSC_DEFAULT);
1247  }
1248  else if (cid == SNES_CLASSID)
1249  {
1250  SNES snes = (SNES)obj;
1251  ierr = SNESSetTolerances(snes,tol,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT,
1252  PETSC_DEFAULT);
1253  }
1254  else if (cid == TS_CLASSID)
1255  {
1256  TS ts = (TS)obj;
1257  ierr = TSSetTolerances(ts,tol,NULL,PETSC_DECIDE,NULL);
1258  }
1259  else
1260  {
1261  MFEM_ABORT("CLASSID = " << cid << " is not implemented!");
1262  }
1263  PCHKERRQ(obj,ierr);
1264 }
1265 
1266 void PetscSolver::SetMaxIter(int max_iter)
1267 {
1268  if (cid == KSP_CLASSID)
1269  {
1270  KSP ksp = (KSP)obj;
1271  ierr = KSPSetTolerances(ksp,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT,
1272  max_iter);
1273  }
1274  else if (cid == SNES_CLASSID)
1275  {
1276  SNES snes = (SNES)obj;
1277  ierr = SNESSetTolerances(snes,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT,
1278  max_iter,PETSC_DEFAULT);
1279  }
1280  else if (cid == TS_CLASSID)
1281  {
1282  TS ts = (TS)obj;
1283  ierr = TSSetDuration(ts,max_iter,PETSC_DEFAULT);
1284  }
1285  else
1286  {
1287  MFEM_ABORT("CLASSID = " << cid << " is not implemented!");
1288  }
1289  PCHKERRQ(obj,ierr);
1290 }
1291 
1292 
1294 {
1295  typedef PetscErrorCode (*myPetscFunc)(void**);
1296  PetscViewerAndFormat *vf;
1297  PetscViewer viewer = PETSC_VIEWER_STDOUT_(PetscObjectComm(obj));
1298 
1299  ierr = PetscViewerAndFormatCreate(viewer,PETSC_VIEWER_DEFAULT,&vf);
1300  PCHKERRQ(obj,ierr);
1301  if (cid == KSP_CLASSID)
1302  {
1303  // there are many other options, see the function KSPSetFromOptions() in
1304  // src/ksp/ksp/interface/itcl.c
1305  typedef PetscErrorCode (*myMonitor)(KSP,PetscInt,PetscReal,void*);
1306  KSP ksp = (KSP)obj;
1307  if (plev >= 0)
1308  {
1309  ierr = KSPMonitorCancel(ksp); PCHKERRQ(ksp,ierr);
1310  }
1311  if (plev == 1)
1312  {
1313  ierr = KSPMonitorSet(ksp,(myMonitor)KSPMonitorDefault,vf,
1314  (myPetscFunc)PetscViewerAndFormatDestroy);
1315  PCHKERRQ(ksp,ierr);
1316  }
1317  else if (plev > 1)
1318  {
1319  ierr = KSPSetComputeSingularValues(ksp,PETSC_TRUE); PCHKERRQ(ksp,ierr);
1320  ierr = KSPMonitorSet(ksp,(myMonitor)KSPMonitorSingularValue,vf,
1321  (myPetscFunc)PetscViewerAndFormatDestroy);
1322  PCHKERRQ(ksp,ierr);
1323  if (plev > 2)
1324  {
1325  ierr = PetscViewerAndFormatCreate(viewer,PETSC_VIEWER_DEFAULT,&vf);
1326  PCHKERRQ(viewer,ierr);
1327  ierr = KSPMonitorSet(ksp,(myMonitor)KSPMonitorTrueResidualNorm,vf,
1328  (myPetscFunc)PetscViewerAndFormatDestroy);
1329  PCHKERRQ(ksp,ierr);
1330  }
1331  }
1332  // user defined monitor
1333  if (monitor_ctx)
1334  {
1335  ierr = KSPMonitorSet(ksp,__mfem_ksp_monitor,monitor_ctx,NULL);
1336  PCHKERRQ(ksp,ierr);
1337  }
1338  }
1339  else if (cid == SNES_CLASSID)
1340  {
1341  typedef PetscErrorCode (*myMonitor)(SNES,PetscInt,PetscReal,void*);
1342  SNES snes = (SNES)obj;
1343  if (plev >= 0)
1344  {
1345  ierr = SNESMonitorCancel(snes); PCHKERRQ(snes,ierr);
1346  }
1347  if (plev > 0)
1348  {
1349  ierr = SNESMonitorSet(snes,(myMonitor)SNESMonitorDefault,vf,
1350  (myPetscFunc)PetscViewerAndFormatDestroy);
1351  PCHKERRQ(snes,ierr);
1352  }
1353  }
1354  else if (cid == TS_CLASSID)
1355  {
1356  TS ts = (TS)obj;
1357  if (plev >= 0)
1358  {
1359  ierr = TSMonitorCancel(ts); PCHKERRQ(ts,ierr);
1360  }
1361  // user defined monitor
1362  if (monitor_ctx)
1363  {
1364  ierr = TSMonitorSet(ts,__mfem_ts_monitor,monitor_ctx,NULL);
1365  PCHKERRQ(ts,ierr);
1366  }
1367  }
1368  else
1369  {
1370  MFEM_ABORT("CLASSID = " << cid << " is not implemented!");
1371  }
1372 }
1373 
1375 {
1376  monitor_ctx = ctx;
1377  SetPrintLevel(-1);
1378 }
1379 
1380 void PetscSolver::Customize(bool customize) const
1381 {
1382  if (!customize) { clcustom = true; }
1383  if (!clcustom)
1384  {
1385  if (cid == PC_CLASSID)
1386  {
1387  PC pc = (PC)obj;
1388  ierr = PCSetFromOptions(pc); PCHKERRQ(pc, ierr);
1389  }
1390  else if (cid == KSP_CLASSID)
1391  {
1392  KSP ksp = (KSP)obj;
1393  ierr = KSPSetFromOptions(ksp); PCHKERRQ(ksp, ierr);
1394  }
1395  else if (cid == SNES_CLASSID)
1396  {
1397  SNES snes = (SNES)obj;
1398  ierr = SNESSetFromOptions(snes); PCHKERRQ(snes, ierr);
1399  }
1400  else if (cid == TS_CLASSID)
1401  {
1402  TS ts = (TS)obj;
1403  ierr = TSSetFromOptions(ts); PCHKERRQ(ts, ierr);
1404  }
1405  else
1406  {
1407  MFEM_ABORT("CLASSID = " << cid << " is not implemented!");
1408  }
1409  }
1410  clcustom = true;
1411 }
1412 
1414 {
1415  if (cid == KSP_CLASSID)
1416  {
1417  KSP ksp = (KSP)obj;
1418  KSPConvergedReason reason;
1419  ierr = KSPGetConvergedReason(ksp,&reason);
1420  PCHKERRQ(ksp,ierr);
1421  return reason > 0 ? 1 : 0;
1422  }
1423  else if (cid == SNES_CLASSID)
1424  {
1425  SNES snes = (SNES)obj;
1426  SNESConvergedReason reason;
1427  ierr = SNESGetConvergedReason(snes,&reason);
1428  PCHKERRQ(snes,ierr);
1429  return reason > 0 ? 1 : 0;
1430  }
1431  else if (cid == TS_CLASSID)
1432  {
1433  TS ts = (TS)obj;
1434  TSConvergedReason reason;
1435  ierr = TSGetConvergedReason(ts,&reason);
1436  PCHKERRQ(ts,ierr);
1437  return reason > 0 ? 1 : 0;
1438  }
1439  else
1440  {
1441  MFEM_ABORT("CLASSID = " << cid << " is not implemented!");
1442  return -1;
1443  }
1444 }
1445 
1447 {
1448  if (cid == KSP_CLASSID)
1449  {
1450  KSP ksp = (KSP)obj;
1451  PetscInt its;
1452  ierr = KSPGetIterationNumber(ksp,&its);
1453  PCHKERRQ(ksp,ierr);
1454  return its;
1455  }
1456  else if (cid == SNES_CLASSID)
1457  {
1458  SNES snes = (SNES)obj;
1459  PetscInt its;
1460  ierr = SNESGetIterationNumber(snes,&its);
1461  PCHKERRQ(snes,ierr);
1462  return its;
1463  }
1464  else if (cid == TS_CLASSID)
1465  {
1466  TS ts = (TS)obj;
1467  PetscInt its;
1468  ierr = TSGetTotalSteps(ts,&its);
1469  PCHKERRQ(ts,ierr);
1470  return its;
1471  }
1472  else
1473  {
1474  MFEM_ABORT("CLASSID = " << cid << " is not implemented!");
1475  return -1;
1476  }
1477 }
1478 
1480 {
1481  if (cid == KSP_CLASSID)
1482  {
1483  KSP ksp = (KSP)obj;
1484  PetscReal norm;
1485  ierr = KSPGetResidualNorm(ksp,&norm);
1486  PCHKERRQ(ksp,ierr);
1487  return norm;
1488  }
1489  if (cid == SNES_CLASSID)
1490  {
1491  SNES snes = (SNES)obj;
1492  PetscReal norm;
1493  ierr = SNESGetFunctionNorm(snes,&norm);
1494  PCHKERRQ(snes,ierr);
1495  return norm;
1496  }
1497  else
1498  {
1499  MFEM_ABORT("CLASSID = " << cid << " is not implemented!");
1500  return PETSC_MAX_REAL;
1501  }
1502 }
1503 
1504 // PetscLinearSolver methods
1505 
1506 PetscLinearSolver::PetscLinearSolver(MPI_Comm comm, const std::string &prefix)
1507  : PetscSolver(), Solver(), wrap(false)
1508 {
1509  KSP ksp;
1510  ierr = KSPCreate(comm,&ksp); CCHKERRQ(comm,ierr);
1511  obj = (PetscObject)ksp;
1512  ierr = PetscObjectGetClassId(obj,&cid); PCHKERRQ(obj,ierr);
1513  ierr = KSPSetOptionsPrefix(ksp, prefix.c_str()); PCHKERRQ(ksp, ierr);
1514 }
1515 
1517  const std::string &prefix)
1518  : PetscSolver(), Solver(), wrap(false)
1519 {
1520  KSP ksp;
1521  ierr = KSPCreate(A.GetComm(),&ksp); CCHKERRQ(A.GetComm(),ierr);
1522  obj = (PetscObject)ksp;
1523  ierr = PetscObjectGetClassId(obj,&cid); PCHKERRQ(obj,ierr);
1524  ierr = KSPSetOptionsPrefix(ksp, prefix.c_str()); PCHKERRQ(ksp, ierr);
1525  SetOperator(A);
1526 }
1527 
1529  const std::string &prefix)
1530  : PetscSolver(), Solver(), wrap(wrapin)
1531 {
1532  KSP ksp;
1533  ierr = KSPCreate(A.GetComm(),&ksp); CCHKERRQ(A.GetComm(),ierr);
1534  obj = (PetscObject)ksp;
1535  ierr = PetscObjectGetClassId(obj, &cid); PCHKERRQ(obj, ierr);
1536  ierr = KSPSetOptionsPrefix(ksp, prefix.c_str()); PCHKERRQ(ksp, ierr);
1537  SetOperator(A);
1538 }
1539 
1541 {
1542  const HypreParMatrix *hA = dynamic_cast<const HypreParMatrix *>(&op);
1543  PetscParMatrix *pA = const_cast<PetscParMatrix *>
1544  (dynamic_cast<const PetscParMatrix *>(&op));
1545  const Operator *oA = dynamic_cast<const Operator *>(&op);
1546  // update base classes: Operator, Solver, PetscLinearSolver
1547  bool delete_pA = false;
1548  if (!pA)
1549  {
1550  if (hA)
1551  {
1552  // Create MATSHELL object or convert
1553  // into PETSc AIJ format depending on wrap
1554  pA = new PetscParMatrix(hA, wrap ? PETSC_MATSHELL : PETSC_MATAIJ);
1555  delete_pA = true;
1556  }
1557  else if (oA) // fallback to general operator
1558  {
1559  // Create MATSHELL or MATNEST object
1560  pA = new PetscParMatrix(PetscObjectComm(obj),oA, PETSC_MATSHELL);
1561  delete_pA = true;
1562  }
1563  }
1564  MFEM_VERIFY(pA, "Unsupported operation!");
1565 
1566  // Set operators into PETSc KSP
1567  KSP ksp = (KSP)obj;
1568  Mat A = pA->A;
1569  if (operatorset)
1570  {
1571  Mat C;
1572  PetscInt nheight,nwidth,oheight,owidth;
1573 
1574  ierr = KSPGetOperators(ksp,&C,NULL); PCHKERRQ(ksp,ierr);
1575  ierr = MatGetSize(A,&nheight,&nwidth); PCHKERRQ(A,ierr);
1576  ierr = MatGetSize(C,&oheight,&owidth); PCHKERRQ(A,ierr);
1577  if (nheight != oheight || nwidth != owidth)
1578  {
1579  // reinit without destroying the KSP
1580  // communicator remains the same
1581  ierr = KSPReset(ksp); PCHKERRQ(ksp,ierr);
1582  delete X;
1583  delete B;
1584  X = B = NULL;
1585  wrap = false;
1586  }
1587  }
1588  ierr = KSPSetOperators(ksp,A,A); PCHKERRQ(ksp,ierr);
1589 
1590  // Update PetscSolver
1591  operatorset = true;
1592 
1593  // Update the Operator fields.
1594  height = pA->Height();
1595  width = pA->Width();
1596 
1597  if (delete_pA) { delete pA; }
1598 }
1599 
1601 {
1602  KSP ksp = (KSP)obj;
1603  PetscPreconditioner *ppc = dynamic_cast<PetscPreconditioner *>(&precond);
1604  if (ppc)
1605  {
1606  ierr = KSPSetPC(ksp,*ppc); PCHKERRQ(ksp,ierr);
1607  }
1608  else // wrap the Solver action
1609  {
1610  PC pc;
1611  ierr = KSPGetPC(ksp,&pc); PCHKERRQ(ksp,ierr);
1612  ierr = PCSetType(pc,PCSHELL); PCHKERRQ(pc,ierr);
1613  solver_shell_ctx *ctx = new solver_shell_ctx;
1614  ctx->op = &precond;
1615  ierr = PCShellSetContext(pc,(void *)ctx); PCHKERRQ(pc,ierr);
1616  ierr = PCShellSetApply(pc,__mfem_pc_shell_apply); PCHKERRQ(pc,ierr);
1617  ierr = PCShellSetApplyTranspose(pc,__mfem_pc_shell_apply_transpose);
1618  PCHKERRQ(pc,ierr);
1619  ierr = PCShellSetSetUp(pc,__mfem_pc_shell_setup); PCHKERRQ(pc,ierr);
1620  ierr = PCShellSetDestroy(pc,__mfem_pc_shell_destroy); PCHKERRQ(pc,ierr);
1621  }
1622 }
1623 
1624 void PetscLinearSolver::Mult(const Vector &b, Vector &x) const
1625 {
1626  KSP ksp = (KSP)obj;
1627 
1628  if (!B || !X)
1629  {
1630  Mat pA = NULL;
1631  ierr = KSPGetOperators(ksp, &pA, NULL); PCHKERRQ(obj, ierr);
1632  if (!B)
1633  {
1634  PetscParMatrix A = PetscParMatrix(pA, true);
1635  B = new PetscParVector(A, true, false);
1636  }
1637  if (!X)
1638  {
1639  PetscParMatrix A = PetscParMatrix(pA, true);
1640  X = new PetscParVector(A, false, false);
1641  }
1642  }
1643  B->PlaceArray(b.GetData());
1644  X->PlaceArray(x.GetData());
1645 
1646  Customize();
1647 
1648  ierr = KSPSetInitialGuessNonzero(ksp, (PetscBool)iterative_mode);
1649  PCHKERRQ(ksp, ierr);
1650 
1651  // Solve the system.
1652  ierr = KSPSolve(ksp, B->x, X->x); PCHKERRQ(ksp,ierr);
1653  B->ResetArray();
1654  X->ResetArray();
1655 }
1656 
1658 {
1659  MPI_Comm comm;
1660  KSP ksp = (KSP)obj;
1661  ierr = PetscObjectGetComm((PetscObject)ksp,&comm); PCHKERRQ(ksp,ierr);
1662  ierr = KSPDestroy(&ksp); CCHKERRQ(comm,ierr);
1663 }
1664 
1665 // PetscPCGSolver methods
1666 
1667 PetscPCGSolver::PetscPCGSolver(MPI_Comm comm, const std::string &prefix)
1668  : PetscLinearSolver(comm,prefix)
1669 {
1670  KSP ksp = (KSP)obj;
1671  ierr = KSPSetType(ksp,KSPCG); PCHKERRQ(ksp,ierr);
1672  // this is to obtain a textbook PCG
1673  ierr = KSPSetNormType(ksp,KSP_NORM_NATURAL); PCHKERRQ(ksp,ierr);
1674 }
1675 
1676 PetscPCGSolver::PetscPCGSolver(PetscParMatrix& A, const std::string &prefix)
1677  : PetscLinearSolver(A,prefix)
1678 {
1679  KSP ksp = (KSP)obj;
1680  ierr = KSPSetType(ksp,KSPCG); PCHKERRQ(ksp,ierr);
1681  // this is to obtain a textbook PCG
1682  ierr = KSPSetNormType(ksp,KSP_NORM_NATURAL); PCHKERRQ(ksp,ierr);
1683 }
1684 
1686  const std::string &prefix)
1687  : PetscLinearSolver(A,wrap,prefix)
1688 {
1689  KSP ksp = (KSP)obj;
1690  ierr = KSPSetType(ksp,KSPCG); PCHKERRQ(ksp,ierr);
1691  // this is to obtain a textbook PCG
1692  ierr = KSPSetNormType(ksp,KSP_NORM_NATURAL); PCHKERRQ(ksp,ierr);
1693 }
1694 
1695 // PetscPreconditioner methods
1696 
1698  const std::string &prefix)
1699  : PetscSolver(), Solver()
1700 {
1701  PC pc;
1702  ierr = PCCreate(comm,&pc); CCHKERRQ(comm,ierr);
1703  obj = (PetscObject)pc;
1704  ierr = PetscObjectGetClassId(obj,&cid); PCHKERRQ(obj,ierr);
1705  ierr = PCSetOptionsPrefix(pc, prefix.c_str()); PCHKERRQ(pc, ierr);
1706 }
1707 
1709  const string &prefix)
1710  : PetscSolver(), Solver()
1711 {
1712  PC pc;
1713  ierr = PCCreate(A.GetComm(),&pc); CCHKERRQ(A.GetComm(),ierr);
1714  obj = (PetscObject)pc;
1715  ierr = PetscObjectGetClassId(obj,&cid); PCHKERRQ(obj,ierr);
1716  ierr = PCSetOptionsPrefix(pc, prefix.c_str()); PCHKERRQ(pc, ierr);
1717  SetOperator(A);
1718 }
1719 
1721  const string &prefix)
1722  : PetscSolver(), Solver()
1723 {
1724  PC pc;
1725  ierr = PCCreate(comm,&pc); CCHKERRQ(comm,ierr);
1726  obj = (PetscObject)pc;
1727  ierr = PetscObjectGetClassId(obj,&cid); PCHKERRQ(obj,ierr);
1728  ierr = PCSetOptionsPrefix(pc, prefix.c_str()); PCHKERRQ(pc, ierr);
1729  SetOperator(op);
1730 }
1731 
1733 {
1734  bool delete_pA = false;
1735  PetscParMatrix *pA = const_cast<PetscParMatrix *>
1736  (dynamic_cast<const PetscParMatrix *>(&op));
1737  if (!pA)
1738  {
1739  pA = new PetscParMatrix(PetscObjectComm(obj),&op, PETSC_MATAIJ);
1740  delete_pA = true;
1741  }
1742 
1743  // Set operators into PETSc PC
1744  PC pc = (PC)obj;
1745  Mat A = pA->A;
1746  if (operatorset)
1747  {
1748  Mat C;
1749  PetscInt nheight,nwidth,oheight,owidth;
1750 
1751  ierr = PCGetOperators(pc,&C,NULL); PCHKERRQ(pc,ierr);
1752  ierr = MatGetSize(A,&nheight,&nwidth); PCHKERRQ(A,ierr);
1753  ierr = MatGetSize(C,&oheight,&owidth); PCHKERRQ(A,ierr);
1754  if (nheight != oheight || nwidth != owidth)
1755  {
1756  // reinit without destroying the PC
1757  // communicator remains the same
1758  ierr = PCReset(pc); PCHKERRQ(pc,ierr);
1759  delete X;
1760  delete B;
1761  X = B = NULL;
1762  }
1763  }
1764  ierr = PCSetOperators(pc,pA->A,pA->A); PCHKERRQ(obj,ierr);
1765 
1766  // Update PetscSolver
1767  operatorset = true;
1768 
1769  // Update the Operator fields.
1770  height = pA->Height();
1771  width = pA->Width();
1772 
1773  if (delete_pA) { delete pA; };
1774 }
1775 
1776 void PetscPreconditioner::Mult(const Vector &b, Vector &x) const
1777 {
1778  PC pc = (PC)obj;
1779 
1780  if (!B || !X)
1781  {
1782  Mat pA = NULL;
1783  ierr = PCGetOperators(pc, NULL, &pA); PCHKERRQ(obj, ierr);
1784  if (!B)
1785  {
1786  PetscParMatrix A(pA, true);
1787  B = new PetscParVector(A, true, false);
1788  }
1789  if (!X)
1790  {
1791  PetscParMatrix A(pA, true);
1792  X = new PetscParVector(A, false, false);
1793  }
1794  }
1795  B->PlaceArray(b.GetData());
1796  X->PlaceArray(x.GetData());
1797 
1798  Customize();
1799 
1800  // Apply the preconditioner.
1801  ierr = PCApply(pc, B->x, X->x); PCHKERRQ(pc, ierr);
1802  B->ResetArray();
1803  X->ResetArray();
1804 }
1805 
1807 {
1808  MPI_Comm comm;
1809  PC pc = (PC)obj;
1810  ierr = PetscObjectGetComm((PetscObject)pc,&comm); PCHKERRQ(pc,ierr);
1811  ierr = PCDestroy(&pc); CCHKERRQ(comm,ierr);
1812 }
1813 
1814 // PetscBDDCSolver methods
1815 
1816 void PetscBDDCSolver::BDDCSolverConstructor(const PetscBDDCSolverParams &opts)
1817 {
1818  MPI_Comm comm = PetscObjectComm(obj);
1819 
1820  // get PETSc object
1821  PC pc = (PC)obj;
1822  Mat pA;
1823  ierr = PCGetOperators(pc,NULL,&pA); PCHKERRQ(pc,ierr);
1824 
1825  // matrix type should be of type MATIS
1826  PetscBool ismatis;
1827  ierr = PetscObjectTypeCompare((PetscObject)pA,MATIS,&ismatis);
1828  PCHKERRQ(pA,ierr);
1829  MFEM_VERIFY(ismatis,"PetscBDDCSolver needs the matrix in unassembled format");
1830 
1831  // set PETSc PC type to PCBDDC
1832  ierr = PCSetType(pc,PCBDDC); PCHKERRQ(obj,ierr);
1833 
1834  // index sets for fields splitting
1835  IS *fields = NULL;
1836  PetscInt nf = 0;
1837 
1838  // index sets for boundary dofs specification (Essential = dir, Natural = neu)
1839  IS dir = NULL, neu = NULL;
1840  PetscInt rst;
1841 
1842  // Extract l2l matrices
1843  Array<Mat> *l2l = NULL;
1844  if (opts.ess_dof_local || opts.nat_dof_local)
1845  {
1846  PetscContainer c;
1847 
1848  ierr = PetscObjectQuery((PetscObject)pA,"__mfem_l2l",(PetscObject*)&c);
1849  MFEM_VERIFY(c,"Local-to-local PETSc container not present");
1850  ierr = PetscContainerGetPointer(c,(void**)&l2l); PCHKERRQ(c,ierr);
1851  }
1852 
1853  // check information about index sets (essential dofs, fields, etc.)
1854 #ifdef MFEM_DEBUG
1855  {
1856  // make sure ess/nat_dof have been collectively set
1857  PetscBool lpr = PETSC_FALSE,pr;
1858  if (opts.ess_dof) { lpr = PETSC_TRUE; }
1859  ierr = MPI_Allreduce(&lpr,&pr,1,MPIU_BOOL,MPI_LOR,comm);
1860  PCHKERRQ(pA,ierr);
1861  MFEM_VERIFY(lpr == pr,"ess_dof should be collectively set");
1862  lpr = PETSC_FALSE;
1863  if (opts.nat_dof) { lpr = PETSC_TRUE; }
1864  ierr = MPI_Allreduce(&lpr,&pr,1,MPIU_BOOL,MPI_LOR,comm);
1865  PCHKERRQ(pA,ierr);
1866  MFEM_VERIFY(lpr == pr,"nat_dof should be collectively set");
1867  // make sure fields have been collectively set
1868  PetscInt ms[2],Ms[2];
1869  ms[0] = -nf; ms[1] = nf;
1870  ierr = MPI_Allreduce(&ms,&Ms,2,MPIU_INT,MPI_MAX,comm);
1871  PCHKERRQ(pA,ierr);
1872  MFEM_VERIFY(-Ms[0] == Ms[1],
1873  "number of fields should be the same across processes");
1874  }
1875 #endif
1876 
1877  // boundary sets
1878  ierr = MatGetOwnershipRange(pA,&rst,NULL); PCHKERRQ(pA,ierr);
1879  if (opts.ess_dof)
1880  {
1881  PetscInt st = opts.ess_dof_local ? 0 : rst;
1882  if (!opts.ess_dof_local)
1883  {
1884  // need to compute the boundary dofs in global ordering
1885  ierr = Convert_Array_IS(comm,true,opts.ess_dof,st,&dir);
1886  CCHKERRQ(comm,ierr);
1887  ierr = PCBDDCSetDirichletBoundaries(pc,dir); PCHKERRQ(pc,ierr);
1888  }
1889  else
1890  {
1891  // need to compute a list for the marked boundary dofs in local ordering
1892  ierr = Convert_Vmarks_IS(comm,*l2l,opts.ess_dof,st,&dir);
1893  CCHKERRQ(comm,ierr);
1894  ierr = PCBDDCSetDirichletBoundariesLocal(pc,dir); PCHKERRQ(pc,ierr);
1895  }
1896  }
1897  if (opts.nat_dof)
1898  {
1899  PetscInt st = opts.nat_dof_local ? 0 : rst;
1900  if (!opts.nat_dof_local)
1901  {
1902  // need to compute the boundary dofs in global ordering
1903  ierr = Convert_Array_IS(comm,true,opts.nat_dof,st,&neu);
1904  CCHKERRQ(comm,ierr);
1905  ierr = PCBDDCSetNeumannBoundaries(pc,neu); PCHKERRQ(pc,ierr);
1906  }
1907  else
1908  {
1909  // need to compute a list for the marked boundary dofs in local ordering
1910  ierr = Convert_Vmarks_IS(comm,*l2l,opts.nat_dof,st,&neu);
1911  CCHKERRQ(comm,ierr);
1912  ierr = PCBDDCSetNeumannBoundariesLocal(pc,neu); PCHKERRQ(pc,ierr);
1913  }
1914  }
1915 
1916  // field splitting
1917  if (nf)
1918  {
1919  ierr = PCBDDCSetDofsSplitting(pc,nf,fields); PCHKERRQ(pc,ierr);
1920  for (int i = 0; i < nf; i++)
1921  {
1922  ierr = ISDestroy(&fields[i]); CCHKERRQ(comm,ierr);
1923  }
1924  ierr = PetscFree(fields); PCHKERRQ(pc,ierr);
1925  }
1926 
1927  // code for block size is disabled since we cannot change the matrix
1928  // block size after it has been setup
1929  // int bs = 1;
1930 
1931  // Customize using the finite element space (if any)
1932  ParFiniteElementSpace *fespace = opts.fespace;
1933  if (fespace)
1934  {
1935  const FiniteElementCollection *fec = fespace->FEColl();
1936  bool edgespace, rtspace;
1937  bool needint = false;
1938  bool tracespace, rt_tracespace, edge_tracespace;
1939  int dim , p;
1940  PetscBool B_is_Trans = PETSC_FALSE;
1941 
1942  ParMesh *pmesh = (ParMesh *) fespace->GetMesh();
1943  dim = pmesh->Dimension();
1944  // bs = fec->DofForGeometry(Geometry::POINT);
1945  // bs = bs ? bs : 1;
1946  rtspace = dynamic_cast<const RT_FECollection*>(fec);
1947  edgespace = dynamic_cast<const ND_FECollection*>(fec);
1948  edge_tracespace = dynamic_cast<const ND_Trace_FECollection*>(fec);
1949  rt_tracespace = dynamic_cast<const RT_Trace_FECollection*>(fec);
1950  tracespace = edge_tracespace || rt_tracespace;
1951 
1952  p = 1;
1953  if (fespace->GetNE() > 0)
1954  {
1955  if (!tracespace)
1956  {
1957  p = fespace->GetOrder(0);
1958  }
1959  else
1960  {
1961  p = fespace->GetFaceOrder(0);
1962  if (dim == 2) { p++; }
1963  }
1964  }
1965 
1966  if (edgespace) // H(curl)
1967  {
1968  if (dim == 2)
1969  {
1970  needint = true;
1971  if (tracespace)
1972  {
1973  MFEM_WARNING("Tracespace case doesn't work for H(curl) and p=2,"
1974  " not using auxiliary quadrature");
1975  needint = false;
1976  }
1977  }
1978  else
1979  {
1980  FiniteElementCollection *vfec;
1981  if (tracespace)
1982  {
1983  vfec = new H1_Trace_FECollection(p,dim);
1984  }
1985  else
1986  {
1987  vfec = new H1_FECollection(p,dim);
1988  }
1989  ParFiniteElementSpace *vfespace = new ParFiniteElementSpace(pmesh,vfec);
1990  ParDiscreteLinearOperator *grad;
1991  grad = new ParDiscreteLinearOperator(vfespace,fespace);
1992  if (tracespace)
1993  {
1994  grad->AddTraceFaceInterpolator(new GradientInterpolator);
1995  }
1996  else
1997  {
1998  grad->AddDomainInterpolator(new GradientInterpolator);
1999  }
2000  grad->Assemble();
2001  grad->Finalize();
2002  HypreParMatrix *hG = grad->ParallelAssemble();
2003  PetscParMatrix *G = new PetscParMatrix(hG,PETSC_MATAIJ);
2004  delete hG;
2005  delete grad;
2006 
2007  PetscBool conforming = PETSC_TRUE;
2008  if (pmesh->Nonconforming()) { conforming = PETSC_FALSE; }
2009  ierr = PCBDDCSetDiscreteGradient(pc,*G,p,0,PETSC_TRUE,conforming);
2010  PCHKERRQ(pc,ierr);
2011  delete vfec;
2012  delete vfespace;
2013  delete G;
2014  }
2015  }
2016  else if (rtspace) // H(div)
2017  {
2018  needint = true;
2019  if (tracespace)
2020  {
2021  MFEM_WARNING("Tracespace case doesn't work for H(div), not using"
2022  " auxiliary quadrature");
2023  needint = false;
2024  }
2025  }
2026  //else if (bs == dim) // Elasticity?
2027  //{
2028  // needint = true;
2029  //}
2030 
2031  PetscParMatrix *B = NULL;
2032  if (needint)
2033  {
2034  // Generate bilinear form in unassembled format which is used to
2035  // compute the net-flux across subdomain boundaries for H(div) and
2036  // Elasticity, and the line integral \int u x n of 2D H(curl) fields
2037  FiniteElementCollection *auxcoll;
2038  if (tracespace) { auxcoll = new RT_Trace_FECollection(p,dim); }
2039  else { auxcoll = new L2_FECollection(p,dim); };
2040  ParFiniteElementSpace *pspace = new ParFiniteElementSpace(pmesh,auxcoll);
2041  ParMixedBilinearForm *b = new ParMixedBilinearForm(fespace,pspace);
2042 
2043  if (edgespace)
2044  {
2045  if (tracespace)
2046  {
2047  b->AddTraceFaceIntegrator(new VectorFECurlIntegrator);
2048  }
2049  else
2050  {
2051  b->AddDomainIntegrator(new VectorFECurlIntegrator);
2052  }
2053  }
2054  else
2055  {
2056  if (tracespace)
2057  {
2058  b->AddTraceFaceIntegrator(new VectorFEDivergenceIntegrator);
2059  }
2060  else
2061  {
2062  b->AddDomainIntegrator(new VectorFEDivergenceIntegrator);
2063  }
2064  }
2065  b->Assemble();
2066  b->Finalize();
2067  OperatorHandle Bh(Operator::PETSC_MATIS);
2068  b->ParallelAssemble(Bh);
2069  Bh.Get(B);
2070  Bh.SetOperatorOwner(false);
2071 
2072  if (dir) // if essential dofs are present, we need to zero the columns
2073  {
2074  Mat pB = *B;
2075  ierr = MatTranspose(pB,MAT_INPLACE_MATRIX,&pB); PCHKERRQ(pA,ierr);
2076  if (!opts.ess_dof_local)
2077  {
2078  ierr = MatZeroRowsIS(pB,dir,0.,NULL,NULL); PCHKERRQ(pA,ierr);
2079  }
2080  else
2081  {
2082  ierr = MatZeroRowsLocalIS(pB,dir,0.,NULL,NULL); PCHKERRQ(pA,ierr);
2083  }
2084  B_is_Trans = PETSC_TRUE;
2085  }
2086  delete b;
2087  delete pspace;
2088  delete auxcoll;
2089  }
2090 
2091  if (B)
2092  {
2093  ierr = PCBDDCSetDivergenceMat(pc,*B,B_is_Trans,NULL); PCHKERRQ(pc,ierr);
2094  }
2095  delete B;
2096  }
2097  ierr = ISDestroy(&dir); PCHKERRQ(pc,ierr);
2098  ierr = ISDestroy(&neu); PCHKERRQ(pc,ierr);
2099 }
2100 
2102  const PetscBDDCSolverParams &opts,
2103  const std::string &prefix)
2104  : PetscPreconditioner(A,prefix)
2105 {
2106  BDDCSolverConstructor(opts);
2107  Customize();
2108 }
2109 
2111  const PetscBDDCSolverParams &opts,
2112  const std::string &prefix)
2113  : PetscPreconditioner(comm,op,prefix)
2114 {
2115  BDDCSolverConstructor(opts);
2116  Customize();
2117 }
2118 
2120  const string &prefix)
2121  : PetscPreconditioner(comm,op,prefix)
2122 {
2123  PC pc = (PC)obj;
2124 
2125  Mat pA;
2126  ierr = PCGetOperators(pc,&pA,NULL); PCHKERRQ(pc,ierr);
2127 
2128  // Check if pA is of type MATNEST
2129  // (this requirement can be removed when we can pass fields).
2130  PetscBool isnest;
2131  ierr = PetscObjectTypeCompare((PetscObject)pA,MATNEST,&isnest);
2132  PCHKERRQ(pA,ierr);
2133  MFEM_VERIFY(isnest,
2134  "PetscFieldSplitSolver needs the matrix in nested format.");
2135 
2136  PetscInt nr;
2137  IS *isrow;
2138  ierr = PCSetType(pc,PCFIELDSPLIT); PCHKERRQ(pc,ierr);
2139  ierr = MatNestGetSize(pA,&nr,NULL); PCHKERRQ(pc,ierr);
2140  ierr = PetscCalloc1(nr,&isrow); CCHKERRQ(PETSC_COMM_SELF,ierr);
2141  ierr = MatNestGetISs(pA,isrow,NULL); PCHKERRQ(pc,ierr);
2142 
2143  // We need to customize here, before setting the index sets.
2144  Customize();
2145 
2146  for (PetscInt i=0; i<nr; i++)
2147  {
2148  ierr = PCFieldSplitSetIS(pc,NULL,isrow[i]); PCHKERRQ(pc,ierr);
2149  }
2150  ierr = PetscFree(isrow); CCHKERRQ(PETSC_COMM_SELF,ierr);
2151 }
2152 
2153 // PetscNonlinearSolver methods
2154 
2156  const std::string &prefix)
2157  : PetscSolver(), Solver()
2158 {
2159  SNES snes;
2160  ierr = SNESCreate(comm, &snes); CCHKERRQ(comm, ierr);
2161  obj = (PetscObject)snes;
2162  ierr = PetscObjectGetClassId(obj, &cid); PCHKERRQ(obj, ierr);
2163  ierr = SNESSetOptionsPrefix(snes, prefix.c_str()); PCHKERRQ(snes, ierr);
2164 }
2165 
2167  const std::string &prefix)
2168  : PetscSolver(), Solver()
2169 {
2170  SNES snes;
2171  ierr = SNESCreate(comm, &snes); CCHKERRQ(comm, ierr);
2172  obj = (PetscObject)snes;
2173  ierr = PetscObjectGetClassId(obj, &cid); PCHKERRQ(obj, ierr);
2174  ierr = SNESSetOptionsPrefix(snes, prefix.c_str()); PCHKERRQ(snes, ierr);
2175  SetOperator(op);
2176 }
2177 
2179 {
2180  MPI_Comm comm;
2181  SNES snes = (SNES)obj;
2182  ierr = PetscObjectGetComm(obj,&comm); PCHKERRQ(obj, ierr);
2183  ierr = SNESDestroy(&snes); CCHKERRQ(comm, ierr);
2184 }
2185 
2187 {
2188  SNES snes = (SNES)obj;
2189 
2190  if (operatorset)
2191  {
2192  PetscBool ls,gs;
2193  void *fctx,*jctx;
2194 
2195  ierr = SNESGetFunction(snes, NULL, NULL, &fctx);
2196  PCHKERRQ(snes, ierr);
2197  ierr = SNESGetJacobian(snes, NULL, NULL, NULL, &jctx);
2198  PCHKERRQ(snes, ierr);
2199 
2200  ls = (PetscBool)(height == op.Height() && width == op.Width() &&
2201  (void*)&op == fctx && (void*)&op == jctx);
2202  ierr = MPI_Allreduce(&ls,&gs,1,MPIU_BOOL,MPI_LAND,
2203  PetscObjectComm((PetscObject)snes));
2204  PCHKERRQ(snes,ierr);
2205  if (!gs)
2206  {
2207  ierr = SNESReset(snes); PCHKERRQ(snes,ierr);
2208  delete X;
2209  delete B;
2210  X = B = NULL;
2211  }
2212  }
2213 
2214  ierr = SNESSetFunction(snes, NULL, __mfem_snes_function, (void *)&op);
2215  PCHKERRQ(snes, ierr);
2216  ierr = SNESSetJacobian(snes, NULL, NULL, __mfem_snes_jacobian, (void *)&op);
2217  PCHKERRQ(snes, ierr);
2218 
2219  // Update PetscSolver
2220  operatorset = true;
2221 
2222  // Update the Operator fields.
2223  height = op.Height();
2224  width = op.Width();
2225 }
2226 
2227 void PetscNonlinearSolver::Mult(const Vector &b, Vector &x) const
2228 {
2229  SNES snes = (SNES)obj;
2230 
2231  bool b_nonempty = b.Size();
2232  if (!B) { B = new PetscParVector(PetscObjectComm(obj), *this, true); }
2233  if (!X) { X = new PetscParVector(PetscObjectComm(obj), *this, false, false); }
2234  X->PlaceArray(x.GetData());
2235  if (b_nonempty) { B->PlaceArray(b.GetData()); }
2236  else { *B = 0.0; }
2237 
2238  Customize();
2239 
2240  if (!iterative_mode) { *X = 0.; }
2241 
2242  // Solve the system.
2243  ierr = SNESSolve(snes, B->x, X->x); PCHKERRQ(snes, ierr);
2244  X->ResetArray();
2245  if (b_nonempty) { B->ResetArray(); }
2246 }
2247 
2248 // PetscODESolver methods
2249 
2250 PetscODESolver::PetscODESolver(MPI_Comm comm, const string &prefix)
2251  : PetscSolver(), ODESolver()
2252 {
2253  TS ts;
2254  ierr = TSCreate(comm,&ts); CCHKERRQ(comm,ierr);
2255  obj = (PetscObject)ts;
2256  ierr = PetscObjectGetClassId(obj,&cid); PCHKERRQ(obj,ierr);
2257  ierr = TSSetOptionsPrefix(ts, prefix.c_str()); PCHKERRQ(ts, ierr);
2258 
2259  // Default options, to comply with the current interface to ODESolver.
2260  ierr = TSSetExactFinalTime(ts,TS_EXACTFINALTIME_STEPOVER);
2261  PCHKERRQ(ts,ierr);
2262  TSAdapt tsad;
2263  ierr = TSGetAdapt(ts,&tsad);
2264  PCHKERRQ(ts,ierr);
2265  ierr = TSAdaptSetType(tsad,TSADAPTNONE);
2266  PCHKERRQ(ts,ierr);
2267 }
2268 
2270 {
2271  MPI_Comm comm;
2272  TS ts = (TS)obj;
2273  ierr = PetscObjectGetComm(obj,&comm); PCHKERRQ(obj,ierr);
2274  ierr = TSDestroy(&ts); CCHKERRQ(comm,ierr);
2275 }
2276 
2278 {
2279  TS ts = (TS)obj;
2280 
2281  if (operatorset)
2282  {
2283  PetscBool ls,gs;
2284  void *fctx = NULL,*jctx = NULL,*rfctx = NULL,*rjctx = NULL;
2285 
2286  if (f->isImplicit())
2287  {
2288  ierr = TSGetIFunction(ts, NULL, NULL, &fctx);
2289  PCHKERRQ(ts, ierr);
2290  ierr = TSGetIJacobian(ts, NULL, NULL, NULL, &jctx);
2291  PCHKERRQ(ts, ierr);
2292  }
2293  if (!f->isHomogeneous())
2294  {
2295  ierr = TSGetRHSFunction(ts, NULL, NULL, &rfctx);
2296  PCHKERRQ(ts, ierr);
2297  ierr = TSGetRHSJacobian(ts, NULL, NULL, NULL, &rjctx);
2298  PCHKERRQ(ts, ierr);
2299  }
2300  ls = (PetscBool)(f->Height() == f_.Height() &&
2301  f->Width() == f_.Width() &&
2302  f->isImplicit() == f_.isImplicit() &&
2303  f->isHomogeneous() == f_.isHomogeneous());
2304  if (ls && f_.isImplicit())
2305  {
2306  ls = (PetscBool)(ls && (void*)&f_ == fctx && (void*)&f_ == jctx);
2307  }
2308  if (ls && !f_.isHomogeneous())
2309  {
2310  ls = (PetscBool)(ls && (void*)&f_ == rfctx && (void*)&f_ == rjctx);
2311  }
2312  ierr = MPI_Allreduce(&ls,&gs,1,MPIU_BOOL,MPI_LAND,
2313  PetscObjectComm((PetscObject)ts));
2314  PCHKERRQ(ts,ierr);
2315  if (!gs)
2316  {
2317  ierr = TSReset(ts); PCHKERRQ(ts,ierr);
2318  delete X;
2319  X = NULL;
2320  }
2321  }
2322  f = &f_;
2323 
2324  if (f->isImplicit())
2325  {
2326  ierr = TSSetIFunction(ts, NULL, __mfem_ts_ifunction, (void *)f);
2327  PCHKERRQ(ts, ierr);
2328  ierr = TSSetIJacobian(ts, NULL, NULL, __mfem_ts_ijacobian, (void *)f);
2329  PCHKERRQ(ts, ierr);
2330  ierr = TSSetEquationType(ts, TS_EQ_IMPLICIT);
2331  PCHKERRQ(ts, ierr);
2332  }
2333  if (!f->isHomogeneous())
2334  {
2335  ierr = TSSetRHSFunction(ts, NULL, __mfem_ts_rhsfunction, (void *)f);
2336  PCHKERRQ(ts, ierr);
2337  ierr = TSSetRHSJacobian(ts, NULL, NULL, __mfem_ts_rhsjacobian, (void *)f);
2338  PCHKERRQ(ts, ierr);
2339  }
2340  operatorset = true;
2341 }
2342 
2343 void PetscODESolver::Step(Vector &x, double &t, double &dt)
2344 {
2345  // Pass the parameters to PETSc.
2346  TS ts = (TS)obj;
2347  ierr = TSSetTime(ts, t); PCHKERRQ(ts, ierr);
2348  ierr = TSSetTimeStep(ts, dt); PCHKERRQ(ts, ierr);
2349 
2350  if (!X) { X = new PetscParVector(PetscObjectComm(obj), *f, false, false); }
2351  X->PlaceArray(x.GetData());
2352 
2353  Customize();
2354 
2355  // Take the step.
2356  ierr = TSSetSolution(ts, *X); PCHKERRQ(ts, ierr);
2357  ierr = TSStep(ts); PCHKERRQ(ts, ierr);
2358  X->ResetArray();
2359 
2360  // Get back current time and time step to caller.
2361  PetscReal pt;
2362  ierr = TSGetTime(ts,&pt); PCHKERRQ(ts,ierr);
2363  t = pt;
2364  ierr = TSGetTimeStep(ts,&pt); PCHKERRQ(ts,ierr);
2365  dt = pt;
2366 }
2367 
2368 void PetscODESolver::Run(Vector &x, double &t, double &dt, double t_final)
2369 {
2370  // Give the parameters to PETSc.
2371  TS ts = (TS)obj;
2372  ierr = TSSetTime(ts, t); PCHKERRQ(ts, ierr);
2373  ierr = TSSetTimeStep(ts, dt); PCHKERRQ(ts, ierr);
2374  ierr = TSSetDuration(ts, PETSC_DECIDE, t_final); PCHKERRQ(ts, ierr);
2375  ierr = TSSetExactFinalTime(ts, TS_EXACTFINALTIME_MATCHSTEP);
2376  PCHKERRQ(ts, ierr);
2377 
2378  if (!X) { X = new PetscParVector(PetscObjectComm(obj), *f, false, false); }
2379  X->PlaceArray(x.GetData());
2380 
2381  Customize();
2382 
2383  // Take the steps.
2384  ierr = VecCopy(X->x, X->x); PCHKERRQ(ts, ierr);
2385  ierr = TSSolve(ts, X->x); PCHKERRQ(ts, ierr);
2386  X->ResetArray();
2387 
2388  // Get back final time and time step to caller.
2389  PetscReal pt;
2390  ierr = TSGetTime(ts, &pt); PCHKERRQ(ts,ierr);
2391  t = pt;
2392  ierr = TSGetTimeStep(ts,&pt); PCHKERRQ(ts,ierr);
2393  dt = pt;
2394 }
2395 
2396 } // namespace mfem
2397 
2398 #include "petsc/private/petscimpl.h"
2399 
2400 // auxiliary functions
2401 #undef __FUNCT__
2402 #define __FUNCT__ "__mfem_ts_monitor"
2403 static PetscErrorCode __mfem_ts_monitor(TS ts, PetscInt it, PetscReal t, Vec x,
2404  void* ctx)
2405 {
2406  mfem::PetscSolverMonitor *monitor_ctx = (mfem::PetscSolverMonitor *)ctx;
2407 
2408  PetscFunctionBeginUser;
2409  if (!ctx)
2410  {
2411  SETERRQ(PETSC_COMM_SELF,PETSC_ERR_USER, "No monitor context provided");
2412  }
2413  if (monitor_ctx->mon_sol)
2414  {
2415  mfem::PetscParVector V(x,true);
2416  monitor_ctx->MonitorSolution(it,t,V);
2417  }
2418  if (monitor_ctx->mon_res)
2419  {
2420  SETERRQ(PetscObjectComm((PetscObject)ts),PETSC_ERR_SUP,
2421  "Cannot monitor the residual with TS");
2422  }
2423  PetscFunctionReturn(0);
2424 }
2425 
2426 #undef __FUNCT__
2427 #define __FUNCT__ "__mfem_ksp_monitor"
2428 static PetscErrorCode __mfem_ksp_monitor(KSP ksp, PetscInt it, PetscReal res,
2429  void* ctx)
2430 {
2431  mfem::PetscSolverMonitor *monitor_ctx = (mfem::PetscSolverMonitor *)ctx;
2432  Vec x;
2433  PetscErrorCode ierr;
2434 
2435  PetscFunctionBeginUser;
2436  if (!ctx)
2437  {
2438  SETERRQ(PETSC_COMM_SELF,PETSC_ERR_USER,"No monitor context provided");
2439  }
2440  if (monitor_ctx->mon_sol)
2441  {
2442  ierr = KSPBuildSolution(ksp,NULL,&x); CHKERRQ(ierr);
2443  mfem::PetscParVector V(x,true);
2444  monitor_ctx->MonitorSolution(it,res,V);
2445  }
2446  if (monitor_ctx->mon_res)
2447  {
2448  ierr = KSPBuildResidual(ksp,NULL,NULL,&x); CHKERRQ(ierr);
2449  mfem::PetscParVector V(x,true);
2450  monitor_ctx->MonitorResidual(it,res,V);
2451  }
2452  PetscFunctionReturn(0);
2453 }
2454 
2455 #undef __FUNCT__
2456 #define __FUNCT__ "__mfem_ts_ifunction"
2457 static PetscErrorCode __mfem_ts_ifunction(TS ts, PetscReal t, Vec x, Vec xp,
2458  Vec f,void *ctx)
2459 {
2460  PetscErrorCode ierr;
2461 
2462  PetscFunctionBeginUser;
2463  mfem::PetscParVector xx(x,true);
2464  mfem::PetscParVector yy(xp,true);
2465  mfem::PetscParVector ff(f,true);
2466 
2468  op->SetTime(t);
2469 
2470  // use the ImplicitMult method of the class
2471  op->ImplicitMult(xx,yy,ff);
2472 
2473  // need to tell PETSc the Vec has been updated
2474  ierr = PetscObjectStateIncrease((PetscObject)f); CHKERRQ(ierr);
2475  PetscFunctionReturn(0);
2476 }
2477 
2478 #undef __FUNCT__
2479 #define __FUNCT__ "__mfem_ts_rhsfunction"
2480 static PetscErrorCode __mfem_ts_rhsfunction(TS ts, PetscReal t, Vec x, Vec f,
2481  void *ctx)
2482 {
2483  PetscErrorCode ierr;
2484 
2485  PetscFunctionBeginUser;
2486  mfem::PetscParVector xx(x,true);
2487  mfem::PetscParVector ff(f,true);
2488 
2490  top->SetTime(t);
2491 
2492  // use the ExplicitMult method - compute the RHS function
2493  top->ExplicitMult(xx,ff);
2494 
2495  // need to tell PETSc the Vec has been updated
2496  ierr = PetscObjectStateIncrease((PetscObject)f); CHKERRQ(ierr);
2497  PetscFunctionReturn(0);
2498 }
2499 
2500 #undef __FUNCT__
2501 #define __FUNCT__ "__mfem_ts_ijacobian"
2502 static PetscErrorCode __mfem_ts_ijacobian(TS ts, PetscReal t, Vec x,
2503  Vec xp, PetscReal shift, Mat A, Mat P,
2504  void *ctx)
2505 {
2506  PetscScalar *array;
2507  PetscInt n;
2508  PetscErrorCode ierr;
2509 
2510  PetscFunctionBeginUser;
2511  // wrap Vecs with Vectors
2512  ierr = VecGetLocalSize(x,&n); CHKERRQ(ierr);
2513  ierr = VecGetArrayRead(x,(const PetscScalar**)&array); CHKERRQ(ierr);
2514  mfem::Vector xx(array,n);
2515  ierr = VecRestoreArrayRead(x,(const PetscScalar**)&array); CHKERRQ(ierr);
2516  ierr = VecGetArrayRead(xp,(const PetscScalar**)&array); CHKERRQ(ierr);
2517  mfem::Vector yy(array,n);
2518  ierr = VecRestoreArrayRead(xp,(const PetscScalar**)&array); CHKERRQ(ierr);
2519 
2520  // update time
2522  op->SetTime(t);
2523 
2524  // Use TimeDependentOperator::GetImplicitGradient(x,y,s)
2525  mfem::Operator& J = op->GetImplicitGradient(xx,yy,shift);
2526 
2527  // Avoid unneeded copy of the matrix by hacking
2528  Mat B;
2529  mfem::PetscParMatrix *pA = const_cast<mfem::PetscParMatrix *>
2530  (dynamic_cast<const mfem::PetscParMatrix *>(&J));
2531  if (pA)
2532  {
2533  B = pA->ReleaseMat(false);
2534  }
2535  else
2536  {
2537  mfem::PetscParMatrix p2A(PetscObjectComm((PetscObject)ts),&J,
2539  B = p2A.ReleaseMat(false);
2540  }
2541  ierr = MatHeaderReplace(A,&B); CHKERRQ(ierr);
2542  PetscFunctionReturn(0);
2543 }
2544 
2545 #undef __FUNCT__
2546 #define __FUNCT__ "__mfem_ts_rhsjacobian"
2547 static PetscErrorCode __mfem_ts_rhsjacobian(TS ts, PetscReal t, Vec x,
2548  Mat A, Mat P, void *ctx)
2549 {
2550  PetscScalar *array;
2551  PetscInt n;
2552  PetscErrorCode ierr;
2553 
2554  PetscFunctionBeginUser;
2555  // wrap Vec with Vector
2556  ierr = VecGetLocalSize(x,&n); CHKERRQ(ierr);
2557  ierr = VecGetArrayRead(x,(const PetscScalar**)&array); CHKERRQ(ierr);
2558  mfem::Vector xx(array,n);
2559  ierr = VecRestoreArrayRead(x,(const PetscScalar**)&array); CHKERRQ(ierr);
2560 
2561  // update time
2563  top->SetTime(t);
2564 
2565  mfem::Operator& J = top->GetExplicitGradient(xx);
2566 
2567  // Avoid unneeded copy of the matrix by hacking
2568  Mat B;
2569  mfem::PetscParMatrix *pA = const_cast<mfem::PetscParMatrix *>
2570  (dynamic_cast<const mfem::PetscParMatrix *>(&J));
2571  if (pA)
2572  {
2573  B = pA->ReleaseMat(false);
2574  }
2575  else
2576  {
2577  mfem::PetscParMatrix p2A(PetscObjectComm((PetscObject)ts),&J,
2579  B = p2A.ReleaseMat(false);
2580  }
2581  ierr = MatHeaderReplace(A,&B); CHKERRQ(ierr);
2582  PetscFunctionReturn(0);
2583 }
2584 
2585 #undef __FUNCT__
2586 #define __FUNCT__ "__mfem_snes_jacobian"
2587 static PetscErrorCode __mfem_snes_jacobian(SNES snes, Vec x, Mat A, Mat P,
2588  void *ctx)
2589 {
2590  PetscScalar *array;
2591  PetscInt n;
2592  PetscErrorCode ierr;
2593 
2594  PetscFunctionBeginUser;
2595  // wrap Vec with Vector
2596  ierr = VecGetLocalSize(x,&n); CHKERRQ(ierr);
2597  ierr = VecGetArrayRead(x,(const PetscScalar**)&array); CHKERRQ(ierr);
2598  mfem::Vector xx(array,n);
2599  ierr = VecRestoreArrayRead(x,(const PetscScalar**)&array); CHKERRQ(ierr);
2600 
2601  // Use Operator::GetGradient(x)
2602  mfem::Operator *op = (mfem::Operator*)ctx;
2603  mfem::Operator& J = op->GetGradient(xx);
2604 
2605  // Avoid unneeded copy of the matrix by hacking
2606  Mat B;
2607  mfem::PetscParMatrix *pA = const_cast<mfem::PetscParMatrix *>
2608  (dynamic_cast<const mfem::PetscParMatrix *>(&J));
2609  if (pA)
2610  {
2611  B = pA->ReleaseMat(false);
2612  }
2613  else
2614  {
2615  mfem::PetscParMatrix p2A(PetscObjectComm((PetscObject)snes),&J,
2617  B = p2A.ReleaseMat(false);
2618  }
2619  ierr = MatHeaderReplace(A,&B); CHKERRQ(ierr);
2620  //// No need to copy to A, we can update the snes matrices
2621  //mfem::PetscParMatrix pA(PetscObjectComm((PetscObject)snes),
2622  // &op->GetGradient(xx),false);
2623  //ierr = SNESSetJacobian(snes,pA,pA,snes_jacobian,ctx); CHKERRQ(ierr);
2624  PetscFunctionReturn(0);
2625 }
2626 
2627 #undef __FUNCT__
2628 #define __FUNCT__ "__mfem_snes_function"
2629 static PetscErrorCode __mfem_snes_function(SNES snes, Vec x, Vec f, void *ctx)
2630 {
2631  PetscFunctionBeginUser;
2632  mfem::PetscParVector xx(x,true);
2633  mfem::PetscParVector ff(f,true);
2634  mfem::Operator *op = (mfem::Operator*)ctx;
2635  op->Mult(xx,ff);
2636  // need to tell PETSc the Vec has been updated
2637  ierr = PetscObjectStateIncrease((PetscObject)f); CHKERRQ(ierr);
2638  PetscFunctionReturn(0);
2639 }
2640 
2641 #undef __FUNCT__
2642 #define __FUNCT__ "__mfem_mat_shell_apply"
2643 static PetscErrorCode __mfem_mat_shell_apply(Mat A, Vec x, Vec y)
2644 {
2645  mat_shell_ctx *ctx;
2646  PetscErrorCode ierr;
2647 
2648  PetscFunctionBeginUser;
2649  ierr = MatShellGetContext(A,(void **)&ctx); PCHKERRQ(A,ierr);
2650  mfem::PetscParVector xx(x,true);
2651  mfem::PetscParVector yy(y,true);
2652  ctx->op->Mult(xx,yy);
2653  // need to tell PETSc the Vec has been updated
2654  ierr = PetscObjectStateIncrease((PetscObject)y); CHKERRQ(ierr);
2655  PetscFunctionReturn(0);
2656 }
2657 
2658 #undef __FUNCT__
2659 #define __FUNCT__ "__mfem_mat_shell_apply_transpose"
2660 static PetscErrorCode __mfem_mat_shell_apply_transpose(Mat A, Vec x, Vec y)
2661 {
2662  mat_shell_ctx *ctx;
2663  PetscErrorCode ierr;
2664 
2665  PetscFunctionBeginUser;
2666  ierr = MatShellGetContext(A,(void **)&ctx); PCHKERRQ(A,ierr);
2667  mfem::PetscParVector xx(x,true);
2668  mfem::PetscParVector yy(y,true);
2669  ctx->op->MultTranspose(xx,yy);
2670  // need to tell PETSc the Vec has been updated
2671  ierr = PetscObjectStateIncrease((PetscObject)y); CHKERRQ(ierr);
2672  PetscFunctionReturn(0);
2673 }
2674 
2675 #undef __FUNCT__
2676 #define __FUNCT__ "__mfem_mat_shell_destroy"
2677 static PetscErrorCode __mfem_mat_shell_destroy(Mat A)
2678 {
2679  mat_shell_ctx *ctx;
2680  PetscErrorCode ierr;
2681 
2682  PetscFunctionBeginUser;
2683  ierr = MatShellGetContext(A,(void **)&ctx); PCHKERRQ(A,ierr);
2684  delete ctx;
2685  PetscFunctionReturn(0);
2686 }
2687 
2688 #undef __FUNCT__
2689 #define __FUNCT__ "__mfem_pc_shell_apply"
2690 static PetscErrorCode __mfem_pc_shell_apply(PC pc, Vec x, Vec y)
2691 {
2692  solver_shell_ctx *ctx;
2693  PetscErrorCode ierr;
2694 
2695  PetscFunctionBeginUser;
2696  ierr = PCShellGetContext(pc,(void **)&ctx); PCHKERRQ(pc,ierr);
2697  mfem::PetscParVector xx(x,true);
2698  mfem::PetscParVector yy(y,true);
2699  ctx->op->Mult(xx,yy);
2700  // need to tell PETSc the Vec has been updated
2701  ierr = PetscObjectStateIncrease((PetscObject)y); CHKERRQ(ierr);
2702  PetscFunctionReturn(0);
2703 }
2704 
2705 #undef __FUNCT__
2706 #define __FUNCT__ "__mfem_pc_shell_apply_transpose"
2707 static PetscErrorCode __mfem_pc_shell_apply_transpose(PC pc, Vec x, Vec y)
2708 {
2709  solver_shell_ctx *ctx;
2710  PetscErrorCode ierr;
2711 
2712  PetscFunctionBeginUser;
2713  ierr = PCShellGetContext(pc,(void **)&ctx); PCHKERRQ(pc,ierr);
2714  mfem::PetscParVector xx(x,true);
2715  mfem::PetscParVector yy(y,true);
2716  ctx->op->MultTranspose(xx,yy);
2717  // need to tell PETSc the Vec has been updated
2718  ierr = PetscObjectStateIncrease((PetscObject)y); CHKERRQ(ierr);
2719  PetscFunctionReturn(0);
2720 }
2721 
2722 #undef __FUNCT__
2723 #define __FUNCT__ "__mfem_pc_shell_setup"
2724 static PetscErrorCode __mfem_pc_shell_setup(PC pc)
2725 {
2726  PetscFunctionBeginUser;
2727  PetscFunctionReturn(0);
2728 }
2729 
2730 #undef __FUNCT__
2731 #define __FUNCT__ "__mfem_pc_shell_destroy"
2732 static PetscErrorCode __mfem_pc_shell_destroy(PC pc)
2733 {
2734  solver_shell_ctx *ctx;
2735  PetscErrorCode ierr;
2736 
2737  PetscFunctionBeginUser;
2738  ierr = PCShellGetContext(pc,(void **)&ctx); PCHKERRQ(pc,ierr);
2739  delete ctx;
2740  PetscFunctionReturn(0);
2741 }
2742 
2743 #undef __FUNCT__
2744 #define __FUNCT__ "__mfem_array_container_destroy"
2745 static PetscErrorCode __mfem_array_container_destroy(void *ptr)
2746 {
2747  PetscErrorCode ierr;
2748 
2749  PetscFunctionBeginUser;
2750  ierr = PetscFree(ptr); CHKERRQ(ierr);
2751  PetscFunctionReturn(0);
2752 }
2753 
2754 #undef __FUNCT__
2755 #define __FUNCT__ "__mfem_matarray_container_destroy"
2756 static PetscErrorCode __mfem_matarray_container_destroy(void *ptr)
2757 {
2759  PetscErrorCode ierr;
2760 
2761  PetscFunctionBeginUser;
2762  for (int i=0; i<a->Size(); i++)
2763  {
2764  Mat M = (*a)[i];
2765  MPI_Comm comm = PetscObjectComm((PetscObject)M);
2766  ierr = MatDestroy(&M); CCHKERRQ(comm,ierr);
2767  }
2768  delete a;
2769  PetscFunctionReturn(0);
2770 }
2771 
2772 // Converts from a list (or a marked Array if islist is false) to an IS
2773 // st indicates the offset where to start numbering
2774 #undef __FUNCT__
2775 #define __FUNCT__ "Convert_Array_IS"
2776 static PetscErrorCode Convert_Array_IS(MPI_Comm comm, bool islist,
2777  const mfem::Array<int> *list,
2778  PetscInt st, IS* is)
2779 {
2780  PetscInt n = list->Size(),*idxs;
2781  const int *data = list->GetData();
2782  PetscErrorCode ierr;
2783 
2784  PetscFunctionBeginUser;
2785  ierr = PetscMalloc1(n,&idxs); CHKERRQ(ierr);
2786  if (islist)
2787  {
2788  for (PetscInt i=0; i<n; i++) { idxs[i] = data[i] + st; }
2789  }
2790  else
2791  {
2792  PetscInt cum = 0;
2793  for (PetscInt i=0; i<n; i++)
2794  {
2795  if (data[i]) { idxs[cum++] = i+st; }
2796  }
2797  n = cum;
2798  }
2799  ierr = ISCreateGeneral(comm,n,idxs,PETSC_OWN_POINTER,is);
2800  CHKERRQ(ierr);
2801  PetscFunctionReturn(0);
2802 }
2803 
2804 // Converts from a marked Array of Vdofs to an IS
2805 // st indicates the offset where to start numbering
2806 // l2l is a vector of matrices generated during RAP
2807 #undef __FUNCT__
2808 #define __FUNCT__ "Convert_Vmarks_IS"
2809 static PetscErrorCode Convert_Vmarks_IS(MPI_Comm comm,
2810  mfem::Array<Mat> &pl2l,
2811  const mfem::Array<int> *mark,
2812  PetscInt st, IS* is)
2813 {
2814  mfem::Array<int> sub_dof_marker;
2816  PetscInt nl;
2817  PetscErrorCode ierr;
2818 
2819  PetscFunctionBeginUser;
2820  for (int i = 0; i < pl2l.Size(); i++)
2821  {
2822  PetscInt m,n,*ii,*jj;
2823  PetscBool done;
2824  ierr = MatGetRowIJ(pl2l[i],0,PETSC_FALSE,PETSC_FALSE,&m,(const PetscInt**)&ii,
2825  (const PetscInt**)&jj,&done); CHKERRQ(ierr);
2826  MFEM_VERIFY(done,"Unable to perform MatGetRowIJ on " << i << " l2l matrix");
2827  ierr = MatGetSize(pl2l[i],NULL,&n); CHKERRQ(ierr);
2828  l2l[i] = new mfem::SparseMatrix(ii,jj,NULL,m,n,false,true,true);
2829  }
2830  nl = 0;
2831  for (int i = 0; i < l2l.Size(); i++) { nl += l2l[i]->Width(); }
2832  sub_dof_marker.SetSize(nl);
2833  const int* vdata = mark->GetData();
2834  int* sdata = sub_dof_marker.GetData();
2835  int cumh = 0, cumw = 0;
2836  for (int i = 0; i < l2l.Size(); i++)
2837  {
2838  const mfem::Array<int> vf_marker(const_cast<int*>(vdata)+cumh,
2839  l2l[i]->Height());
2840  mfem::Array<int> sf_marker(sdata+cumw,l2l[i]->Width());
2841  l2l[i]->BooleanMultTranspose(vf_marker,sf_marker);
2842  cumh += l2l[i]->Height();
2843  cumw += l2l[i]->Width();
2844  }
2845  ierr = Convert_Array_IS(comm,false,&sub_dof_marker,st,is); CCHKERRQ(comm,ierr);
2846  for (int i = 0; i < pl2l.Size(); i++)
2847  {
2848  PetscInt m = l2l[i]->Height();
2849  PetscInt *ii = l2l[i]->GetI(),*jj = l2l[i]->GetJ();
2850  PetscBool done;
2851  ierr = MatRestoreRowIJ(pl2l[i],0,PETSC_FALSE,PETSC_FALSE,&m,
2852  (const PetscInt**)&ii,
2853  (const PetscInt**)&jj,&done); CHKERRQ(ierr);
2854  MFEM_VERIFY(done,"Unable to perform MatRestoreRowIJ on "
2855  << i << " l2l matrix");
2856  delete l2l[i];
2857  }
2858  PetscFunctionReturn(0);
2859 }
2860 
2861 #if !defined(PETSC_HAVE_HYPRE)
2862 
2863 #include "_hypre_parcsr_mv.h"
2864 #undef __FUNCT__
2865 #define __FUNCT__ "MatConvert_hypreParCSR_AIJ"
2866 static PetscErrorCode MatConvert_hypreParCSR_AIJ(hypre_ParCSRMatrix* hA,Mat* pA)
2867 {
2868  MPI_Comm comm = hypre_ParCSRMatrixComm(hA);
2869  hypre_CSRMatrix *hdiag,*hoffd;
2870  PetscScalar *da,*oa,*aptr;
2871  PetscInt *dii,*djj,*oii,*ojj,*iptr;
2872  PetscInt i,dnnz,onnz,m,n;
2873  PetscMPIInt size;
2874  PetscErrorCode ierr;
2875 
2876  PetscFunctionBeginUser;
2877  hdiag = hypre_ParCSRMatrixDiag(hA);
2878  hoffd = hypre_ParCSRMatrixOffd(hA);
2879  m = hypre_CSRMatrixNumRows(hdiag);
2880  n = hypre_CSRMatrixNumCols(hdiag);
2881  dnnz = hypre_CSRMatrixNumNonzeros(hdiag);
2882  onnz = hypre_CSRMatrixNumNonzeros(hoffd);
2883  ierr = PetscMalloc1(m+1,&dii); CHKERRQ(ierr);
2884  ierr = PetscMalloc1(dnnz,&djj); CHKERRQ(ierr);
2885  ierr = PetscMalloc1(dnnz,&da); CHKERRQ(ierr);
2886  ierr = PetscMemcpy(dii,hypre_CSRMatrixI(hdiag),(m+1)*sizeof(PetscInt));
2887  CHKERRQ(ierr);
2888  ierr = PetscMemcpy(djj,hypre_CSRMatrixJ(hdiag),dnnz*sizeof(PetscInt));
2889  CHKERRQ(ierr);
2890  ierr = PetscMemcpy(da,hypre_CSRMatrixData(hdiag),dnnz*sizeof(PetscScalar));
2891  CHKERRQ(ierr);
2892  iptr = djj;
2893  aptr = da;
2894  for (i=0; i<m; i++)
2895  {
2896  PetscInt nc = dii[i+1]-dii[i];
2897  ierr = PetscSortIntWithScalarArray(nc,iptr,aptr); CHKERRQ(ierr);
2898  iptr += nc;
2899  aptr += nc;
2900  }
2901  ierr = MPI_Comm_size(comm,&size); CHKERRQ(ierr);
2902  if (size > 1)
2903  {
2904  PetscInt *offdj,*coffd;
2905 
2906  ierr = PetscMalloc1(m+1,&oii); CHKERRQ(ierr);
2907  ierr = PetscMalloc1(onnz,&ojj); CHKERRQ(ierr);
2908  ierr = PetscMalloc1(onnz,&oa); CHKERRQ(ierr);
2909  ierr = PetscMemcpy(oii,hypre_CSRMatrixI(hoffd),(m+1)*sizeof(PetscInt));
2910  CHKERRQ(ierr);
2911  offdj = hypre_CSRMatrixJ(hoffd);
2912  coffd = hypre_ParCSRMatrixColMapOffd(hA);
2913  for (i=0; i<onnz; i++) { ojj[i] = coffd[offdj[i]]; }
2914  ierr = PetscMemcpy(oa,hypre_CSRMatrixData(hoffd),onnz*sizeof(PetscScalar));
2915  CHKERRQ(ierr);
2916  iptr = ojj;
2917  aptr = oa;
2918  for (i=0; i<m; i++)
2919  {
2920  PetscInt nc = oii[i+1]-oii[i];
2921  ierr = PetscSortIntWithScalarArray(nc,iptr,aptr); CHKERRQ(ierr);
2922  iptr += nc;
2923  aptr += nc;
2924  }
2925  ierr = MatCreateMPIAIJWithSplitArrays(comm,m,n,PETSC_DECIDE,PETSC_DECIDE,dii,
2926  djj,da,oii,ojj,oa,pA); CHKERRQ(ierr);
2927  }
2928  else
2929  {
2930  oii = ojj = NULL;
2931  oa = NULL;
2932  ierr = MatCreateSeqAIJWithArrays(comm,m,n,dii,djj,da,pA); CHKERRQ(ierr);
2933  }
2934  /* We are responsible to free the CSR arrays. However, since we can take
2935  references of a PetscParMatrix but we cannot take reference of PETSc
2936  arrays, we need to create a PetscContainer object to take reference of
2937  these arrays in reference objects */
2938  void *ptrs[6] = {dii,djj,da,oii,ojj,oa};
2939  const char *names[6] = {"_mfem_csr_dii",
2940  "_mfem_csr_djj",
2941  "_mfem_csr_da",
2942  "_mfem_csr_oii",
2943  "_mfem_csr_ojj",
2944  "_mfem_csr_oa"
2945  };
2946  for (i=0; i<6; i++)
2947  {
2948  PetscContainer c;
2949 
2950  ierr = PetscContainerCreate(comm,&c); CHKERRQ(ierr);
2951  ierr = PetscContainerSetPointer(c,ptrs[i]); CHKERRQ(ierr);
2952  ierr = PetscContainerSetUserDestroy(c,__mfem_array_container_destroy);
2953  CHKERRQ(ierr);
2954  ierr = PetscObjectCompose((PetscObject)(*pA),names[i],(PetscObject)c);
2955  CHKERRQ(ierr);
2956  ierr = PetscContainerDestroy(&c); CHKERRQ(ierr);
2957  }
2958  PetscFunctionReturn(0);
2959 }
2960 
2961 #undef __FUNCT__
2962 #define __FUNCT__ "MatConvert_hypreParCSR_IS"
2963 static PetscErrorCode MatConvert_hypreParCSR_IS(hypre_ParCSRMatrix* hA,Mat* pA)
2964 {
2965  Mat lA;
2966  ISLocalToGlobalMapping rl2g,cl2g;
2967  IS is;
2968  hypre_CSRMatrix *hdiag,*hoffd;
2969  MPI_Comm comm = hypre_ParCSRMatrixComm(hA);
2970  void *ptrs[2];
2971  const char *names[2] = {"_mfem_csr_aux",
2972  "_mfem_csr_data"
2973  };
2974  PetscScalar *hdd,*hod,*aa,*data;
2975  PetscInt *col_map_offd,*hdi,*hdj,*hoi,*hoj;
2976  PetscInt *aux,*ii,*jj;
2977  PetscInt cum,dr,dc,oc,str,stc,nnz,i,jd,jo;
2978  PetscErrorCode ierr;
2979 
2980  PetscFunctionBeginUser;
2981  /* access relevant information in ParCSR */
2982  str = hypre_ParCSRMatrixFirstRowIndex(hA);
2983  stc = hypre_ParCSRMatrixFirstColDiag(hA);
2984  hdiag = hypre_ParCSRMatrixDiag(hA);
2985  hoffd = hypre_ParCSRMatrixOffd(hA);
2986  dr = hypre_CSRMatrixNumRows(hdiag);
2987  dc = hypre_CSRMatrixNumCols(hdiag);
2988  nnz = hypre_CSRMatrixNumNonzeros(hdiag);
2989  hdi = hypre_CSRMatrixI(hdiag);
2990  hdj = hypre_CSRMatrixJ(hdiag);
2991  hdd = hypre_CSRMatrixData(hdiag);
2992  oc = hypre_CSRMatrixNumCols(hoffd);
2993  nnz += hypre_CSRMatrixNumNonzeros(hoffd);
2994  hoi = hypre_CSRMatrixI(hoffd);
2995  hoj = hypre_CSRMatrixJ(hoffd);
2996  hod = hypre_CSRMatrixData(hoffd);
2997 
2998  /* generate l2g maps for rows and cols */
2999  ierr = ISCreateStride(comm,dr,str,1,&is); CHKERRQ(ierr);
3000  ierr = ISLocalToGlobalMappingCreateIS(is,&rl2g); CHKERRQ(ierr);
3001  ierr = ISDestroy(&is); CHKERRQ(ierr);
3002  col_map_offd = hypre_ParCSRMatrixColMapOffd(hA);
3003  ierr = PetscMalloc1(dc+oc,&aux); CHKERRQ(ierr);
3004  for (i=0; i<dc; i++) { aux[i] = i+stc; }
3005  for (i=0; i<oc; i++) { aux[i+dc] = col_map_offd[i]; }
3006  ierr = ISCreateGeneral(comm,dc+oc,aux,PETSC_OWN_POINTER,&is); CHKERRQ(ierr);
3007  ierr = ISLocalToGlobalMappingCreateIS(is,&cl2g); CHKERRQ(ierr);
3008  ierr = ISDestroy(&is); CHKERRQ(ierr);
3009 
3010  /* create MATIS object */
3011  ierr = MatCreate(comm,pA); CHKERRQ(ierr);
3012  ierr = MatSetSizes(*pA,dr,dc,PETSC_DECIDE,PETSC_DECIDE); CHKERRQ(ierr);
3013  ierr = MatSetType(*pA,MATIS); CHKERRQ(ierr);
3014  ierr = MatSetLocalToGlobalMapping(*pA,rl2g,cl2g); CHKERRQ(ierr);
3015  ierr = ISLocalToGlobalMappingDestroy(&rl2g); CHKERRQ(ierr);
3016  ierr = ISLocalToGlobalMappingDestroy(&cl2g); CHKERRQ(ierr);
3017 
3018  /* merge local matrices */
3019  ierr = PetscMalloc1(nnz+dr+1,&aux); CHKERRQ(ierr);
3020  ierr = PetscMalloc1(nnz,&data); CHKERRQ(ierr);
3021  ii = aux;
3022  jj = aux+dr+1;
3023  aa = data;
3024  *ii = *(hdi++) + *(hoi++);
3025  for (jd=0,jo=0,cum=0; *ii<nnz; cum++)
3026  {
3027  PetscScalar *aold = aa;
3028  PetscInt *jold = jj,nc = jd+jo;
3029  for (; jd<*hdi; jd++) { *jj++ = *hdj++; *aa++ = *hdd++; }
3030  for (; jo<*hoi; jo++) { *jj++ = *hoj++ + dc; *aa++ = *hod++; }
3031  *(++ii) = *(hdi++) + *(hoi++);
3032  ierr = PetscSortIntWithScalarArray(jd+jo-nc,jold,aold); CHKERRQ(ierr);
3033  }
3034  for (; cum<dr; cum++) { *(++ii) = nnz; }
3035  ii = aux;
3036  jj = aux+dr+1;
3037  aa = data;
3038  ierr = MatCreateSeqAIJWithArrays(PETSC_COMM_SELF,dr,dc+oc,ii,jj,aa,&lA);
3039  CHKERRQ(ierr);
3040  ptrs[0] = aux;
3041  ptrs[1] = data;
3042  for (i=0; i<2; i++)
3043  {
3044  PetscContainer c;
3045 
3046  ierr = PetscContainerCreate(PETSC_COMM_SELF,&c); CHKERRQ(ierr);
3047  ierr = PetscContainerSetPointer(c,ptrs[i]); CHKERRQ(ierr);
3048  ierr = PetscContainerSetUserDestroy(c,__mfem_array_container_destroy);
3049  CHKERRQ(ierr);
3050  ierr = PetscObjectCompose((PetscObject)lA,names[i],(PetscObject)c);
3051  CHKERRQ(ierr);
3052  ierr = PetscContainerDestroy(&c); CHKERRQ(ierr);
3053  }
3054  ierr = MatISSetLocalMat(*pA,lA); CHKERRQ(ierr);
3055  ierr = MatDestroy(&lA); CHKERRQ(ierr);
3056  ierr = MatAssemblyBegin(*pA,MAT_FINAL_ASSEMBLY); CHKERRQ(ierr);
3057  ierr = MatAssemblyEnd(*pA,MAT_FINAL_ASSEMBLY); CHKERRQ(ierr);
3058  PetscFunctionReturn(0);
3059 }
3060 #endif
3061 
3062 #endif // MFEM_USE_PETSC
3063 #endif // MFEM_USE_MPI
int Size() const
Logical size of the array.
Definition: array.hpp:109
virtual void SetPreconditioner(Solver &precond)
Definition: petsc.cpp:1600
void SetPrintLevel(int plev)
Definition: petsc.cpp:1293
virtual int NumNonZeroElems() const
Returns the number of the nonzero elements in the matrix.
Definition: sparsemat.cpp:972
PetscParVector * B
Right-hand side and solution vector.
Definition: petsc.hpp:334
void Print(const char *fname=NULL, bool binary=false) const
Prints the matrix (to stdout if fname is NULL)
Definition: petsc.cpp:978
Vector()
Default constructor for Vector. Sets size = 0 and data = NULL.
Definition: vector.hpp:46
MPI_Comm GetComm() const
MPI communicator.
Definition: hypre.hpp:295
bool isImplicit() const
True if type is IMPLICIT or HOMOGENEOUS.
Definition: operator.hpp:175
bool isHomogeneous() const
True if type is HOMOGENEOUS.
Definition: operator.hpp:177
virtual void SetOperator(const Operator &op)
Specification of the nonlinear operator.
Definition: petsc.cpp:2186
Abstract class for PETSc&#39;s preconditioners.
Definition: petsc.hpp:418
PetscParMatrix & operator+=(const PetscParMatrix &B)
Definition: petsc.cpp:463
PetscParVector(MPI_Comm comm, PetscInt glob_size, PetscInt *col)
Creates vector with given global size and partitioning of the columns.
Definition: petsc.cpp:126
virtual void SetOperator(const Operator &op)
Set/update the solver for the given operator.
Definition: petsc.cpp:1540
bool clcustom
Boolean to handle SetFromOptions calls.
Definition: petsc.hpp:325
double GetFinalNorm()
Definition: petsc.cpp:1479
Wrapper for PETSc&#39;s matrix class.
Definition: petsc.hpp:128
const Array< int > * nat_dof
Definition: petsc.hpp:446
Abstract class for PETSc&#39;s linear solvers.
Definition: petsc.hpp:377
Vec x
The actual PETSc object.
Definition: petsc.hpp:36
Abstract class for PETSc&#39;s solvers.
Definition: petsc.hpp:321
virtual void Run(Vector &x, double &t, double &dt, double t_final)
Perform time integration from time t [in] to time tf [in].
Definition: petsc.cpp:2368
ParFiniteElementSpace * fespace
Definition: petsc.hpp:443
Base abstract class for time dependent operators.
Definition: operator.hpp:140
PetscInt GetNumCols() const
Returns the local number of columns.
Definition: petsc.cpp:331
virtual Operator & GetGradient(const Vector &x) const
Evaluate the gradient operator at the point x. The default behavior in class Operator is to generate ...
Definition: operator.hpp:57
void MakeDataOwner()
Definition: vector.hpp:100
int Width() const
Get the width (size of input) of the Operator. Synonym with NumCols().
Definition: operator.hpp:42
void Mult(double a, const Vector &x, double b, Vector &y) const
Matvec: y = a A x + b y.
Definition: petsc.cpp:945
PetscBDDCSolver(MPI_Comm comm, Operator &op, const PetscBDDCSolverParams &opts=PetscBDDCSolverParams(), const std::string &prefix=std::string())
Definition: petsc.cpp:2110
virtual ~PetscSolver()
Destroy the PetscParVectors allocated (if any).
Definition: petsc.cpp:1205
PetscNonlinearSolver(MPI_Comm comm, const std::string &prefix=std::string())
Definition: petsc.cpp:2155
T * GetData()
Returns the data.
Definition: array.hpp:91
Type GetType() const
Definition: petsc.cpp:1149
virtual void SetTime(const double _t)
Set the current time.
Definition: operator.hpp:170
int Size() const
Returns the size of the vector.
Definition: vector.hpp:106
virtual void Step(Vector &x, double &t, double &dt)
Perform a time step from time t [in] to time t [out] based on the requested step size dt [in]...
Definition: petsc.cpp:2343
Abstract class for solving systems of ODEs: dx/dt = f(x,t)
Definition: ode.hpp:22
void Init()
Initialize with defaults. Does not initialize inherited members.
Definition: petsc.cpp:359
PetscPreconditioner(MPI_Comm comm, const std::string &prefix=std::string())
Definition: petsc.cpp:1697
PetscClassId cid
The class id of the actual PETSc object.
Definition: petsc.hpp:331
virtual void Mult(const Vector &x, Vector &y) const =0
Operator application: y=A(x).
int IsZeroBlock(int i, int j) const
Check if block (i,j) is a zero block.
Abstract parallel finite element space.
Definition: pfespace.hpp:28
void SetRelTol(double tol)
Definition: petsc.cpp:1216
bool iterative_mode
If true, use the second argument of Mult() as an initial guess.
Definition: operator.hpp:261
PetscPCGSolver(MPI_Comm comm, const std::string &prefix=std::string())
Definition: petsc.cpp:1667
void Destroy()
Delete all owned data. Does not perform re-initialization with defaults.
Definition: petsc.cpp:813
virtual Operator & GetExplicitGradient(const Vector &x) const
Return an Operator representing dG/dx at the given point x and the currently set time.
Definition: operator.hpp:246
void SetMonitor(PetscSolverMonitor *ctx)
Sets user-defined monitoring routine.
Definition: petsc.cpp:1374
void SetMaxIter(int max_iter)
Definition: petsc.cpp:1266
double * GetData() const
Definition: vector.hpp:114
void SortColumnIndices()
Sort the column indices corresponding to each row.
Definition: sparsemat.cpp:326
Wrapper for PETSc&#39;s vector class.
Definition: petsc.hpp:32
void Customize(bool customize=true) const
Customize object with options set.
Definition: petsc.cpp:1380
PetscInt M() const
Returns the global number of rows.
Definition: petsc.cpp:338
Operator & GetBlock(int i, int j)
Return a reference to block i,j.
virtual void Mult(const Vector &b, Vector &x) const
Application of the solver.
Definition: petsc.cpp:2227
PetscParVector * Y
Definition: petsc.hpp:135
virtual ~PetscLinearSolver()
Definition: petsc.cpp:1657
HYPRE_Int * GetTrueDofOffsets()
Definition: pfespace.hpp:170
PetscInt GetNumRows() const
Returns the local number of rows.
Definition: petsc.cpp:324
void Randomize(PetscInt seed)
Set random values.
Definition: petsc.cpp:285
void Print(const char *fname=NULL, bool binary=false) const
Prints the vector (to stdout if fname is NULL)
Definition: petsc.cpp:297
void EliminateBC(HypreParMatrix &A, HypreParMatrix &Ae, const Array< int > &ess_dof_list, const Vector &X, Vector &B)
Definition: hypre.cpp:1435
void ResetArray()
Reset the PETSc Vec object to use its default data. Call this method after the use of PlaceArray()...
Definition: petsc.cpp:280
virtual Operator & GetImplicitGradient(const Vector &x, const Vector &k, double shift) const
Return an Operator representing (dF/dk shift + dF/dx) at the given x, k, and the currently set time...
Definition: operator.hpp:233
PetscParMatrix * Transpose(bool action=false)
Returns the transpose of the PetscParMatrix.
Definition: petsc.cpp:926
int dim
Definition: ex3.cpp:47
PetscObject obj
The actual PETSc object (KSP, PC, SNES or TS).
Definition: petsc.hpp:328
Abstract class for monitoring PETSc&#39;s solvers.
Definition: petsc.hpp:537
Data type sparse matrix.
Definition: sparsemat.hpp:38
int Height() const
Get the height (size of output) of the Operator. Synonym with NumRows().
Definition: operator.hpp:36
int to_int(const std::string &str)
Definition: text.hpp:68
Auxiliary class for BDDC customization.
Definition: petsc.hpp:440
virtual ~PetscPreconditioner()
Definition: petsc.cpp:1806
MPI_Comm GetComm() const
Get the associated MPI communicator.
Definition: petsc.hpp:232
void LoseData()
NULL-ifies the data.
Definition: array.hpp:103
HypreParMatrix * RAP(HypreParMatrix *A, HypreParMatrix *P)
Returns the matrix P^t * A * P.
Definition: hypre.cpp:1385
PetscParMatrix & operator=(const PetscParMatrix &B)
Definition: petsc.cpp:447
virtual ~PetscParVector()
Calls PETSc&#39;s destroy function.
Definition: petsc.cpp:144
PetscFieldSplitSolver(MPI_Comm comm, Operator &op, const std::string &prefix=std::string())
Definition: petsc.cpp:2119
void Assign(const T *)
Copy data from a pointer. Size() elements are copied.
Definition: array.hpp:536
double * GetData() const
Return element data, i.e. array A.
Definition: sparsemat.hpp:135
int * GetI() const
Return the array I.
Definition: sparsemat.hpp:131
PetscParMatrix()
Create an empty matrix to be used as a reference to an existing matrix.
Definition: petsc.cpp:366
int GetNumIterations()
Definition: petsc.cpp:1446
PetscLinearSolver(MPI_Comm comm, const std::string &prefix=std::string())
Definition: petsc.cpp:1506
Wrapper for hypre&#39;s parallel vector class.
Definition: hypre.hpp:72
Type
Enumeration defining IDs for some classes derived from Operator.
Definition: operator.hpp:123
PetscInt NNZ() const
Returns the number of nonzeros.
Definition: petsc.cpp:352
virtual void ExplicitMult(const Vector &x, Vector &y) const
Perform the action of the explicit part of the operator, G: y = G(x, t) where t is the current time...
Definition: operator.hpp:184
virtual void Mult(const Vector &b, Vector &x) const
Application of the preconditioner.
Definition: petsc.cpp:1776
void SetSize(int nsize)
Change logical size of the array, keep existing entries.
Definition: array.hpp:349
Mat A
The actual PETSc object.
Definition: petsc.hpp:132
PetscInt N() const
Returns the global number of columns.
Definition: petsc.cpp:345
PetscParVector * GetY() const
Returns the inner vector in the range of A (it creates it if needed)
Definition: petsc.cpp:916
void MakeWrapper(MPI_Comm comm, const Operator *op, Mat *B)
Creates a wrapper around a mfem::Operator op using PETSc&#39;s MATSHELL object and returns the Mat in B...
Definition: petsc.cpp:614
bool operatorset
Boolean to handle SetOperator calls.
Definition: petsc.hpp:340
PetscParVector * X
Auxiliary vectors for typecasting.
Definition: petsc.hpp:135
void MultTranspose(double a, const Vector &x, double b, Vector &y) const
Matvec transpose: y = a A^T x + b y.
Definition: petsc.cpp:961
virtual void Init(TimeDependentOperator &f_)
Associate a TimeDependentOperator with the ODE solver.
Definition: petsc.cpp:2277
int height
Dimension of the output / number of rows in the matrix.
Definition: operator.hpp:24
virtual ~PetscNonlinearSolver()
Definition: petsc.cpp:2178
virtual ~PetscODESolver()
Definition: petsc.cpp:2269
int GetConverged()
Definition: petsc.cpp:1413
PetscSolver()
Construct an empty PetscSolver. Initialize protected objects to NULL.
Definition: petsc.cpp:1196
Mat ReleaseMat(bool dereference)
Release the PETSc Mat object. If dereference is true, decrement the refcount of the Mat object...
Definition: petsc.cpp:1136
virtual void MonitorSolution(PetscInt it, PetscReal norm, const Vector &x)
Monitor the solution vector x.
Definition: petsc.hpp:547
virtual void SetOperator(const Operator &op)
Set/update the solver for the given operator.
Definition: petsc.cpp:1732
PetscParVector * X
Definition: petsc.hpp:334
const Array< int > * ess_dof
Definition: petsc.hpp:444
void _SetDataAndSize_()
Definition: petsc.cpp:108
void SetAbsTol(double tol)
Definition: petsc.cpp:1241
void EliminateRowsCols(const Array< int > &rows_cols, const HypreParVector &X, HypreParVector &B)
Eliminate rows and columns from the matrix, and rows from the vector B. Modify B with the BC values i...
Definition: petsc.cpp:1129
PetscParVector * GetX() const
Returns the inner vector in the domain of A (it creates it if needed)
Definition: petsc.cpp:906
void SetTol(double tol)
Definition: petsc.cpp:1211
PetscParVector & operator=(PetscScalar d)
Set constant values.
Definition: petsc.cpp:263
virtual void MonitorResidual(PetscInt it, PetscReal norm, const Vector &r)
Monitor the residual vector r.
Definition: petsc.hpp:553
int NumRowBlocks() const
Return the number of row blocks.
Vector data type.
Definition: vector.hpp:36
const FiniteElementCollection * FEColl() const
Definition: fespace.hpp:177
Identity Operator I: x -&gt; x.
Definition: operator.hpp:280
void PlaceArray(PetscScalar *temp_data)
Temporarily replace the data of the PETSc Vec object. To return to the original data array...
Definition: petsc.cpp:275
TimeDependentOperator * f
Pointer to the associated TimeDependentOperator.
Definition: ode.hpp:26
Vector * GlobalVector() const
Returns the global vector in each processor.
Definition: petsc.cpp:238
PetscODESolver(MPI_Comm comm, const std::string &prefix=std::string())
Definition: petsc.cpp:2250
Base class for solvers.
Definition: operator.hpp:257
double * data
Definition: vector.hpp:41
PetscSolverMonitor * monitor_ctx
Monitor context.
Definition: petsc.hpp:337
Abstract operator.
Definition: operator.hpp:21
Wrapper for hypre&#39;s ParCSR matrix class.
Definition: hypre.hpp:174
A class to handle Block systems in a matrix-free implementation.
int * GetJ() const
Return the array J.
Definition: sparsemat.hpp:133
virtual void Mult(const Vector &b, Vector &x) const
Application of the solver.
Definition: petsc.cpp:1624
void operator*=(double s)
Scale all entries by s: A_scaled = s*A.
Definition: petsc.cpp:940
int NumColBlocks() const
Return the number of column blocks.
void ConvertOperator(MPI_Comm comm, const Operator &op, Mat *B, bool assembled)
Convert an mfem::Operator into a Mat B; op can be destroyed.
Definition: petsc.cpp:635
PetscErrorCode ierr
Definition: petsc.cpp:99
int width
Dimension of the input / number of columns in the matrix.
Definition: operator.hpp:25
void MakeRef(const PetscParMatrix &master)
Makes this object a reference to another PetscParMatrix.
Definition: petsc.cpp:896
virtual void ImplicitMult(const Vector &x, const Vector &k, Vector &y) const
Perform the action of the implicit part of the operator, F: y = F(x, k, t) where t is the current tim...
Definition: operator.hpp:194