MFEM v4.10.0
Finite element discretization library
Loading...
Searching...
No Matches
petsc.cpp
Go to the documentation of this file.
1// Copyright (c) 2010-2026, Lawrence Livermore National Security, LLC. Produced
2// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
3// LICENSE and NOTICE for details. LLNL-CODE-806117.
4//
5// This file is part of the MFEM library. For more information and source code
6// availability visit https://mfem.org.
7//
8// MFEM is free software; you can redistribute it and/or modify it under the
9// terms of the BSD-3 license. We welcome feedback and contributions, see file
10// CONTRIBUTING.md for details.
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#include "../fem/fem.hpp"
21
22#include "petsc.h"
23#include "petscmathypre.h"
24
25// Backward compatibility
26#if PETSC_VERSION_LT(3,11,0)
27#define VecLockReadPush VecLockPush
28#define VecLockReadPop VecLockPop
29#endif
30#if PETSC_VERSION_LT(3,12,0)
31#define VecGetArrayWrite VecGetArray
32#define VecRestoreArrayWrite VecRestoreArray
33#define MatComputeOperator(A,B,C) MatComputeExplicitOperator(A,C)
34#define MatComputeOperatorTranspose(A,B,C) MatComputeExplicitOperatorTranspose(A,C)
35#endif
36#if PETSC_VERSION_LT(3,19,0)
37#define PETSC_SUCCESS 0
38#endif
39#if PETSC_VERSION_LT(3,23,0)
40#define PetscContainerSetCtxDestroy(A,B) PetscContainerSetUserDestroy(A,B)
41typedef PetscErrorCode (PetscCtxDestroyFn)(void**);
42#endif
43#if PETSC_VERSION_LT(3,24,0)
44typedef PetscErrorCode KSPMonitorFn(KSP,PetscInt,PetscReal,void*);
45#endif
46
47#include <fstream>
48#include <iomanip>
49#include <cmath>
50#include <cstdlib>
51
52// Note: there are additional #include statements below.
53
54#include "petscinternals.hpp"
55
56// Callback functions: these functions will be called by PETSc
57static PetscErrorCode __mfem_ts_monitor(TS,PetscInt,PetscReal,Vec,void*);
58static PetscErrorCode __mfem_ts_rhsfunction(TS,PetscReal,Vec,Vec,void*);
59static PetscErrorCode __mfem_ts_rhsjacobian(TS,PetscReal,Vec,Mat,Mat,
60 void*);
61static PetscErrorCode __mfem_ts_ifunction(TS,PetscReal,Vec,Vec,Vec,void*);
62static PetscErrorCode __mfem_ts_ijacobian(TS,PetscReal,Vec,Vec,
63 PetscReal,Mat,
64 Mat,void*);
65static PetscErrorCode __mfem_ts_computesplits(TS,PetscReal,Vec,Vec,
66 Mat,Mat,Mat,Mat);
67static PetscErrorCode __mfem_snes_monitor(SNES,PetscInt,PetscReal,void*);
68static PetscErrorCode __mfem_snes_jacobian(SNES,Vec,Mat,Mat,void*);
69static PetscErrorCode __mfem_snes_function(SNES,Vec,Vec,void*);
70static PetscErrorCode __mfem_snes_objective(SNES,Vec,PetscReal*,void*);
71static PetscErrorCode __mfem_snes_update(SNES,PetscInt);
72static PetscErrorCode __mfem_snes_postcheck(SNESLineSearch,Vec,Vec,Vec,
73 PetscBool*,PetscBool*,void*);
74static PetscErrorCode __mfem_ksp_monitor(KSP,PetscInt,PetscReal,void*);
75static PetscErrorCode __mfem_pc_shell_apply(PC,Vec,Vec);
76static PetscErrorCode __mfem_pc_shell_apply_transpose(PC,Vec,Vec);
77static PetscErrorCode __mfem_pc_shell_setup(PC);
78static PetscErrorCode __mfem_pc_shell_destroy(PC);
79static PetscErrorCode __mfem_pc_shell_view(PC,PetscViewer);
80static PetscErrorCode __mfem_mat_shell_apply(Mat,Vec,Vec);
81static PetscErrorCode __mfem_mat_shell_apply_transpose(Mat,Vec,Vec);
82static PetscErrorCode __mfem_mat_shell_destroy(Mat);
83static PetscErrorCode __mfem_mat_shell_copy(Mat,Mat,MatStructure);
84#if PETSC_VERSION_LT(3,23,0)
85typedef void *PetscCtxRt;
86#elif PETSC_VERSION_LT(3,25,0)
87typedef void **PetscCtxRt;
88#endif
89static PetscErrorCode __mfem_array_container_destroy(PetscCtxRt);
90static PetscErrorCode __mfem_matarray_container_destroy(PetscCtxRt);
91#if PETSC_VERSION_LT(3,23,0)
92static PetscErrorCode __mfem_monitor_ctx_destroy(void**);
93#else
94static PetscErrorCode __mfem_monitor_ctx_destroy(PetscCtxRt);
95#endif
96
97// auxiliary functions
98static PetscErrorCode Convert_Array_IS(MPI_Comm,bool,const mfem::Array<int>*,
99 PetscInt,IS*);
100static PetscErrorCode Convert_Vmarks_IS(MPI_Comm,mfem::Array<Mat>&,
101 const mfem::Array<int>*,PetscInt,IS*);
102static PetscErrorCode MakeShellPC(PC,mfem::Solver&,bool);
103static PetscErrorCode MakeShellPCWithFactory(PC,
105
106#if PETSC_VERSION_GE(3,15,0) && defined(PETSC_HAVE_DEVICE)
107#if defined(MFEM_USE_CUDA) && defined(PETSC_HAVE_CUDA)
108#define _USE_DEVICE
109#define PETSC_VECDEVICE VECCUDA
110#define PETSC_MATAIJDEVICE MATAIJCUSPARSE
111#define VecDeviceGetArrayRead VecCUDAGetArrayRead
112#define VecDeviceGetArrayWrite VecCUDAGetArrayWrite
113#define VecDeviceGetArray VecCUDAGetArray
114#define VecDeviceRestoreArrayRead VecCUDARestoreArrayRead
115#define VecDeviceRestoreArrayWrite VecCUDARestoreArrayWrite
116#define VecDeviceRestoreArray VecCUDARestoreArray
117#define VecDevicePlaceArray VecCUDAPlaceArray
118#define VecDeviceResetArray VecCUDAResetArray
119#elif defined(MFEM_USE_HIP) && defined(PETSC_HAVE_HIP)
120#define _USE_DEVICE
121#define PETSC_VECDEVICE VECHIP
122#define PETSC_MATAIJDEVICE MATAIJHIPSPARSE
123#define VecDeviceGetArrayRead VecHIPGetArrayRead
124#define VecDeviceGetArrayWrite VecHIPGetArrayWrite
125#define VecDeviceGetArray VecHIPGetArray
126#define VecDeviceRestoreArrayRead VecHIPRestoreArrayRead
127#define VecDeviceRestoreArrayWrite VecHIPRestoreArrayWrite
128#define VecDeviceRestoreArray VecHIPRestoreArray
129#define VecDevicePlaceArray VecHIPPlaceArray
130#define VecDeviceResetArray VecHIPResetArray
131#else
132#define VecDeviceGetArrayRead VecGetArrayRead
133#define VecDeviceGetArrayWrite VecGetArrayWrite
134#define VecDeviceGetArray VecGetArray
135#define VecDeviceRestoreArrayRead VecRestoreArrayRead
136#define VecDeviceRestoreArrayWrite VecRestoreArrayWrite
137#define VecDeviceRestoreArray VecRestoreArray
138#define VecDevicePlaceArray VecPlaceArray
139#define VecDeviceResetArray VecResetArray
140#endif
141#endif
142
143#if defined(PETSC_HAVE_DEVICE)
144static PetscErrorCode __mfem_VecSetOffloadMask(Vec,PetscOffloadMask);
145#endif
146static PetscErrorCode __mfem_VecBoundToCPU(Vec,PetscBool*);
147static PetscErrorCode __mfem_PetscObjectStateIncrease(PetscObject);
148static PetscErrorCode __mfem_MatCreateDummy(MPI_Comm,PetscInt,PetscInt,Mat*);
149
150// structs used by PETSc code
151typedef struct
152{
153 mfem::Solver *op;
155 bool ownsop;
156 unsigned long int numprec;
157} __mfem_pc_shell_ctx;
158
159typedef struct
160{
161 mfem::Operator *op; // The nonlinear operator
162 mfem::PetscBCHandler *bchandler; // Handling of essential bc
163 mfem::Vector *work; // Work vector
164 mfem::Operator::Type jacType; // OperatorType for the Jacobian
165 // Objective for line search
166 void (*objective)(mfem::Operator *op, const mfem::Vector&, mfem::real_t*);
167 // PostCheck function (to be called after successful line search)
168 void (*postcheck)(mfem::Operator *op, const mfem::Vector&, mfem::Vector&,
169 mfem::Vector&, bool&, bool&);
170 // General purpose update function (to be called at the beginning of
171 // each nonlinear step)
172 void (*update)(mfem::Operator *op, int,
173 const mfem::Vector&, const mfem::Vector&,
174 const mfem::Vector&, const mfem::Vector&);
175} __mfem_snes_ctx;
176
177typedef struct
178{
179 mfem::TimeDependentOperator *op; // The time-dependent operator
180 mfem::PetscBCHandler *bchandler; // Handling of essential bc
181 mfem::Vector *work; // Work vector
182 mfem::Vector *work2; // Work vector
183 mfem::Operator::Type jacType; // OperatorType for the Jacobian
185 PetscReal cached_shift;
186 PetscObjectState cached_ijacstate;
187 PetscObjectState cached_rhsjacstate;
188 PetscObjectState cached_splits_xstate;
189 PetscObjectState cached_splits_xdotstate;
190} __mfem_ts_ctx;
191
192typedef struct
193{
194 mfem::PetscSolver *solver; // The solver object
195 mfem::PetscSolverMonitor *monitor; // The user-defined monitor class
196} __mfem_monitor_ctx;
197
198// use global scope ierr to check PETSc errors inside mfem calls
199static PetscErrorCode ierr;
200static PetscMPIInt mpiierr;
201
202using namespace std;
203
204namespace mfem
205{
206
208{
209 MFEMInitializePetsc(NULL,NULL,NULL,NULL);
210}
211
212void MFEMInitializePetsc(int *argc,char*** argv)
213{
214 MFEMInitializePetsc(argc,argv,NULL,NULL);
215}
216
217void MFEMInitializePetsc(int *argc,char ***argv,const char rc_file[],
218 const char help[])
219{
220 // Tell PETSc to use the same CUDA or HIP device as MFEM:
222 {
223#if PETSC_VERSION_LT(3,17,0)
224 const char *opts = "-cuda_device";
225#else
226 const char *opts = "-device_select_cuda";
227#endif
228 ierr = PetscOptionsSetValue(NULL,opts,
229 to_string(mfem::Device::GetId()).c_str());
230 MFEM_VERIFY(!ierr,"Unable to set initial option value to PETSc");
231 }
233 {
234#if PETSC_VERSION_LT(3,17,0)
235 const char *opts = "-hip_device";
236#else
237 const char *opts = "-device_select_hip";
238#endif
239 ierr = PetscOptionsSetValue(NULL,opts,
240 to_string(mfem::Device::GetId()).c_str());
241 MFEM_VERIFY(!ierr,"Unable to set initial option value to PETSc");
242 }
243 ierr = PetscInitialize(argc,argv,rc_file,help);
244 MFEM_VERIFY(!ierr,"Unable to initialize PETSc");
245}
246
248{
249 ierr = PetscFinalize();
250 MFEM_VERIFY(!ierr,"Unable to finalize PETSc");
251}
252
254{
255 int oflags = flags;
256 SetHostValid();
257 const mfem::real_t *v = mfem::Read(*this,Capacity(),false);
258 flags = oflags;
259 return v;
260}
261
263{
264 int oflags = flags;
266 const mfem::real_t *v = mfem::Read(*this,Capacity(),true);
267 flags = oflags;
268 return v;
269}
270
271// PetscParVector methods
272
274{
275 PetscScalar *array;
276 PetscInt n;
277 PetscBool isnest;
278
279 MFEM_VERIFY(x,"Missing Vec");
280 ierr = VecSetUp(x); PCHKERRQ(x,ierr);
281 ierr = PetscObjectTypeCompare((PetscObject)x,VECNEST,&isnest); PCHKERRQ(x,ierr);
282 MFEM_VERIFY(!isnest,"Not for type nest");
283 ierr = VecGetLocalSize(x,&n); PCHKERRQ(x,ierr);
284 MFEM_VERIFY(n >= 0,"Invalid local size");
285 size = n;
286#if defined(PETSC_HAVE_DEVICE)
287 PetscOffloadMask omask;
288 PetscBool isdevice;
289
290 ierr = VecGetOffloadMask(x,&omask); PCHKERRQ(x,ierr);
291 if (omask != PETSC_OFFLOAD_BOTH)
292 {
293 ierr = __mfem_VecSetOffloadMask(x,PETSC_OFFLOAD_CPU); PCHKERRQ(x,ierr);
294 }
295#endif
296 ierr = VecGetArrayRead(x,(const PetscScalar**)&array); PCHKERRQ(x,ierr);
297#if defined(PETSC_HAVE_DEVICE)
298 ierr = PetscObjectTypeCompareAny((PetscObject)x,&isdevice,
299 VECSEQCUDA,VECMPICUDA,VECSEQHIP,VECMPIHIP,
300 ""); PCHKERRQ(x,ierr);
301 if (isdevice)
302 {
303 if (omask != PETSC_OFFLOAD_BOTH)
304 {
305 ierr = __mfem_VecSetOffloadMask(x,PETSC_OFFLOAD_GPU); PCHKERRQ(x,ierr);
306 }
307 PetscScalar *darray;
308 ierr = VecDeviceGetArrayRead(x,(const PetscScalar**)&darray);
309 PCHKERRQ(x,ierr);
310 pdata.Wrap(array,darray,size,MemoryType::HOST,false);
311 ierr = VecDeviceRestoreArrayRead(x,(const PetscScalar**)&darray);
312 PCHKERRQ(x,ierr);
313 }
314 else
315#endif
316 {
317 pdata.Wrap(array,size,MemoryType::HOST,false);
318 }
319 ierr = VecRestoreArrayRead(x,(const PetscScalar**)&array); PCHKERRQ(x,ierr);
320
321#if defined(PETSC_HAVE_DEVICE)
322 if (omask == PETSC_OFFLOAD_UNALLOCATED && isdevice) { omask = PETSC_OFFLOAD_CPU; }
323 ierr = __mfem_VecSetOffloadMask(x,omask); PCHKERRQ(x,ierr);
324#endif
327}
328
330{
331 MFEM_VERIFY(x,"Missing Vec");
332#if defined(_USE_DEVICE)
333 PetscOffloadMask mask;
334 PetscBool isdevice;
335 ierr = PetscObjectTypeCompareAny((PetscObject)x,&isdevice,
336 VECSEQCUDA,VECMPICUDA,VECSEQHIP,VECMPIHIP,
337 ""); PCHKERRQ(x,ierr);
338 ierr = VecGetOffloadMask(x,&mask); PCHKERRQ(x,ierr);
339 if (isdevice)
340 {
341 switch (mask)
342 {
343 case PETSC_OFFLOAD_CPU:
346 break;
347 case PETSC_OFFLOAD_GPU:
350 break;
351 case PETSC_OFFLOAD_BOTH:
354 break;
355 default:
356 MFEM_ABORT("Unhandled case " << mask);
357 }
358 }
359#endif
360 data.Sync(pdata);
361}
362
364{
365 MFEM_VERIFY(x,"Missing Vec");
366 ierr = __mfem_PetscObjectStateIncrease((PetscObject)x); PCHKERRQ(x,ierr);
367#if defined(_USE_DEVICE)
368 PetscBool isdevice;
369 ierr = PetscObjectTypeCompareAny((PetscObject)x,&isdevice,
370 VECSEQCUDA,VECMPICUDA,VECSEQHIP,VECMPIHIP,
371 ""); PCHKERRQ(x,ierr);
372 if (isdevice)
373 {
374 bool dv = pdata.DeviceIsValid();
375 bool hv = pdata.HostIsValid();
376 PetscOffloadMask mask;
377 if (dv && hv) { mask = PETSC_OFFLOAD_BOTH; }
378 else if (dv) { mask = PETSC_OFFLOAD_GPU; }
379 else { mask = PETSC_OFFLOAD_CPU; }
380 ierr = __mfem_VecSetOffloadMask(x,mask); PCHKERRQ(x,ierr);
381 }
382 else
383#endif
384 {
385 /* Just make sure we have an up-to-date copy on the CPU for PETSc */
386 PetscScalar *v;
387 ierr = VecGetArrayWrite(x,&v); PCHKERRQ(x,ierr);
389 ierr = VecRestoreArrayWrite(x,&v); PCHKERRQ(x,ierr);
390 }
391}
392
394{
395 VecType vectype;
396 MFEM_VERIFY(x,"Missing Vec");
397 ierr = VecGetType(x,&vectype); PCHKERRQ(x,ierr);
398#if defined(_USE_DEVICE)
400 {
403 ierr = VecSetType(x,PETSC_VECDEVICE); PCHKERRQ(x,ierr);
404 break;
405 default:
406 ierr = VecSetType(x,VECSTANDARD); PCHKERRQ(x,ierr);
407 break;
408 }
409#else
410 if (!vectype)
411 {
412 ierr = VecSetType(x,VECSTANDARD); PCHKERRQ(x,ierr);
413 }
414#endif
415}
416
417const mfem::real_t* PetscParVector::Read(bool on_dev) const
418{
419 const PetscScalar *dummy;
420 MFEM_VERIFY(x,"Missing Vec");
421#if defined(PETSC_HAVE_DEVICE)
422 PetscBool isdevice;
423 ierr = PetscObjectTypeCompareAny((PetscObject)x,&isdevice,
424 VECSEQCUDA,VECMPICUDA,VECSEQHIP,VECMPIHIP,
425 ""); PCHKERRQ(x,ierr);
426 if (on_dev && isdevice)
427 {
428 ierr = VecDeviceGetArrayRead(x,&dummy); PCHKERRQ(x,ierr);
429 ierr = VecDeviceRestoreArrayRead(x,&dummy); PCHKERRQ(x,ierr);
430 }
431 else
432#endif
433 {
434 ierr = VecGetArrayRead(x,&dummy); PCHKERRQ(x,ierr);
435 ierr = VecRestoreArrayRead(x,&dummy); PCHKERRQ(x,ierr);
436 }
438 return mfem::Read(pdata, size, on_dev);
439}
440
442{
443 return Read(false);
444}
445
447{
448 PetscScalar *dummy;
449 MFEM_VERIFY(x,"Missing Vec");
450#if defined(PETSC_HAVE_DEVICE)
451 PetscBool isdevice;
452 ierr = PetscObjectTypeCompareAny((PetscObject)x,&isdevice,
453 VECSEQCUDA,VECMPICUDA,VECSEQHIP,VECMPIHIP,
454 ""); PCHKERRQ(x,ierr);
455 if (on_dev && isdevice)
456 {
457 ierr = VecDeviceGetArrayWrite(x,&dummy); PCHKERRQ(x,ierr);
458 ierr = VecDeviceRestoreArrayWrite(x,&dummy); PCHKERRQ(x,ierr);
459 }
460 else
461#endif
462 {
463 ierr = VecGetArrayWrite(x,&dummy); PCHKERRQ(x,ierr);
464 ierr = VecRestoreArrayWrite(x,&dummy); PCHKERRQ(x,ierr);
465 }
466 ierr = __mfem_PetscObjectStateIncrease((PetscObject)x); PCHKERRQ(x,ierr);
468 return mfem::Write(pdata, size, on_dev);
469}
470
472{
473 return Write(false);
474}
475
477{
478 PetscScalar *dummy;
479 MFEM_VERIFY(x,"Missing Vec");
480#if defined(PETSC_HAVE_DEVICE)
481 PetscBool isdevice;
482 ierr = PetscObjectTypeCompareAny((PetscObject)x,&isdevice,
483 VECSEQCUDA,VECMPICUDA,VECSEQHIP,VECMPIHIP,
484 ""); PCHKERRQ(x,ierr);
485 if (on_dev && isdevice)
486 {
487 ierr = VecDeviceGetArray(x,&dummy); PCHKERRQ(x,ierr);
488 ierr = VecDeviceRestoreArray(x,&dummy); PCHKERRQ(x,ierr);
489 }
490 else
491#endif
492 {
493 ierr = VecGetArray(x,&dummy); PCHKERRQ(x,ierr);
494 ierr = VecRestoreArray(x,&dummy); PCHKERRQ(x,ierr);
495 }
496 ierr = __mfem_PetscObjectStateIncrease((PetscObject)x); PCHKERRQ(x,ierr);
498 return mfem::ReadWrite(pdata, size, on_dev);
499}
500
505
506void PetscParVector::UseDevice(bool dev) const
507{
508 MFEM_VERIFY(x,"Missing Vec");
509#if defined(PETSC_HAVE_DEVICE)
510 ierr = VecBindToCPU(x,!dev ? PETSC_TRUE : PETSC_FALSE); PCHKERRQ(x,ierr);
512#endif
513}
514
516{
517 PetscBool flg;
518 MFEM_VERIFY(x,"Missing Vec");
519 ierr = __mfem_VecBoundToCPU(x,&flg); PCHKERRQ(x,ierr);
520 return flg ? false : true;
521}
522
524{
525 PetscInt N;
526 ierr = VecGetSize(x,&N); PCHKERRQ(x,ierr);
527 return N;
528}
529
531{
532 ierr = VecSetBlockSize(x,bs); PCHKERRQ(x,ierr);
533}
534
535PetscParVector::PetscParVector(MPI_Comm comm, const Vector &x_,
536 bool copy) : Vector()
537{
538 PetscBool isdevice;
539
540 int n = x_.Size();
541 ierr = VecCreate(comm,&x); CCHKERRQ(comm,ierr);
542 ierr = VecSetSizes(x,n,PETSC_DECIDE); PCHKERRQ(x,ierr);
543 SetVecType_();
545 ierr = PetscObjectTypeCompareAny((PetscObject)x,&isdevice,
546 VECSEQCUDA,VECMPICUDA,VECSEQHIP,VECMPIHIP,
547 ""); PCHKERRQ(x,ierr);
548 if (copy)
549 {
550 /* we use PETSc accessors to flag valid memory location to PETSc */
551 PetscErrorCode (*rest)(Vec,PetscScalar**);
552 PetscScalar *array;
553#if defined(PETSC_HAVE_DEVICE)
554 if (isdevice && x_.UseDevice())
555 {
556 UseDevice(true);
557 ierr = VecDeviceGetArrayWrite(x,&array); PCHKERRQ(x,ierr);
558 rest = VecDeviceRestoreArrayWrite;
559 }
560 else
561#endif
562 {
563 UseDevice(false);
564 ierr = VecGetArrayWrite(x,&array); PCHKERRQ(x,ierr);
565 rest = VecRestoreArrayWrite;
566 }
567 pdata.CopyFrom(x_.GetMemory(), n);
568 ierr = (*rest)(x,&array); PCHKERRQ(x,ierr);
570 }
571 else // don't copy, just set the device flag
572 {
573 if (isdevice && x_.UseDevice())
574 {
575 UseDevice(true);
576 }
577 else
578 {
579 UseDevice(false);
580 }
581 }
582}
583
585 PetscInt *col) : Vector()
586{
587 ierr = VecCreate(comm,&x); CCHKERRQ(comm,ierr);
588 if (col)
589 {
590 PetscMPIInt myid;
591 mpiierr = MPI_Comm_rank(comm, &myid); CCHKERRQ(comm, mpiierr);
592 ierr = VecSetSizes(x,col[myid+1]-col[myid],PETSC_DECIDE); PCHKERRQ(x,ierr);
593 }
594 else
595 {
596 ierr = VecSetSizes(x,PETSC_DECIDE,glob_size); PCHKERRQ(x,ierr);
597 }
598 SetVecType_();
600}
601
603{
604 MPI_Comm comm = PetscObjectComm((PetscObject)x);
605 ierr = VecDestroy(&x); CCHKERRQ(comm,ierr);
606 pdata.Delete();
607}
608
610 PetscScalar *data_, PetscInt *col) : Vector()
611{
612 MFEM_VERIFY(col,"Missing distribution");
613 PetscMPIInt myid;
614 mpiierr = MPI_Comm_rank(comm, &myid); CCHKERRQ(comm, mpiierr);
615 ierr = VecCreateMPIWithArray(comm,1,col[myid+1]-col[myid],glob_size,data_,
616 &x); CCHKERRQ(comm,ierr)
617 SetVecType_();
619}
620
622{
623 ierr = VecDuplicate(y.x,&x); PCHKERRQ(x,ierr);
625}
626
628 bool transpose, bool allocate) : Vector()
629{
630 PetscInt loc = transpose ? op.Height() : op.Width();
631
632 ierr = VecCreate(comm,&x);
633 CCHKERRQ(comm,ierr);
634 ierr = VecSetSizes(x,loc,PETSC_DECIDE);
635 PCHKERRQ(x,ierr);
636
637 SetVecType_();
638 if (allocate)
639 {
641 }
642 else /* Vector intended to be used with Place/ResetMemory calls */
643 {
644 size = loc;
645 }
646}
647
649 bool transpose, bool allocate) : Vector()
650{
651 Mat pA = const_cast<PetscParMatrix&>(A);
652 if (!transpose)
653 {
654 ierr = MatCreateVecs(pA,&x,NULL); PCHKERRQ(pA,ierr);
655 }
656 else
657 {
658 ierr = MatCreateVecs(pA,NULL,&x); PCHKERRQ(pA,ierr);
659 }
660 SetVecType_();
661 if (!allocate) /* Vector intended to be used with Place/ResetMemory calls */
662 {
663 PetscInt n;
664 ierr = VecGetLocalSize(x,&n); PCHKERRQ(x,ierr);
665 size = n;
666 }
667 else
668 {
670 }
671}
672
674{
675 if (ref)
676 {
677 ierr = PetscObjectReference((PetscObject)y); PCHKERRQ(y,ierr);
678 }
679 x = y;
681}
682
684{
685 HYPRE_BigInt* offsets = pfes->GetTrueDofOffsets();
686 MPI_Comm comm = pfes->GetComm();
687 ierr = VecCreate(comm,&x); CCHKERRQ(comm,ierr);
688
689 PetscMPIInt myid = 0;
690 if (!HYPRE_AssumedPartitionCheck())
691 {
692 mpiierr = MPI_Comm_rank(comm, &myid); CCHKERRQ(comm, mpiierr);
693 }
694 ierr = VecSetSizes(x,offsets[myid+1]-offsets[myid],PETSC_DECIDE);
695 PCHKERRQ(x,ierr);
696 SetVecType_();
698}
699
701{
702 return x ? PetscObjectComm((PetscObject)x) : MPI_COMM_NULL;
703}
704
706{
707 VecScatter scctx;
708 Vec vout;
709 const PetscScalar *array;
711
712 ierr = VecScatterCreateToAll(x,&scctx,&vout); PCHKERRQ(x,ierr);
713 ierr = VecScatterBegin(scctx,x,vout,INSERT_VALUES,SCATTER_FORWARD);
714 PCHKERRQ(x,ierr);
715 ierr = VecScatterEnd(scctx,x,vout,INSERT_VALUES,SCATTER_FORWARD);
716 PCHKERRQ(x,ierr);
717 ierr = VecScatterDestroy(&scctx); PCHKERRQ(x,ierr);
718 ierr = VecGetArrayRead(vout,&array); PCHKERRQ(x,ierr);
719 ierr = VecGetLocalSize(vout,&size); PCHKERRQ(x,ierr);
721 data.Assign(array);
722 ierr = VecRestoreArrayRead(vout,&array); PCHKERRQ(x,ierr);
723 ierr = VecDestroy(&vout); PCHKERRQ(x,ierr);
724 Vector *v = new Vector(data, internal::to_int(size));
725 v->MakeDataOwner();
726 data.LoseData();
727 return v;
728}
729
731{
732 ierr = VecSet(x,d); PCHKERRQ(x,ierr);
734 return *this;
735}
736
738 const Array<PetscScalar>& vals)
739{
740 MFEM_VERIFY(idx.Size() == vals.Size(),
741 "Size mismatch between indices and values");
742 PetscInt n = idx.Size();
743 ierr = VecSetValues(x,n,idx.GetData(),vals.GetData(),INSERT_VALUES);
744 PCHKERRQ(x,ierr);
745 ierr = VecAssemblyBegin(x); PCHKERRQ(x,ierr);
746 ierr = VecAssemblyEnd(x); PCHKERRQ(x,ierr);
748 return *this;
749}
750
752 const Array<PetscScalar>& vals)
753{
754 MFEM_VERIFY(idx.Size() == vals.Size(),
755 "Size mismatch between indices and values");
756 PetscInt n = idx.Size();
757 ierr = VecSetValues(x,n,idx.GetData(),vals.GetData(),ADD_VALUES);
758 PCHKERRQ(x,ierr);
759 ierr = VecAssemblyBegin(x); PCHKERRQ(x,ierr);
760 ierr = VecAssemblyEnd(x); PCHKERRQ(x,ierr);
762 return *this;
763}
764
766{
767 ierr = VecCopy(y.x,x); PCHKERRQ(x,ierr);
769 return *this;
770}
771
773{
774 ierr = VecAXPY(x,1.0,y.x); PCHKERRQ(x,ierr);
776 return *this;
777}
778
780{
781 ierr = VecAXPY(x,-1.0,y.x); PCHKERRQ(x,ierr);
783 return *this;
784}
785
787{
788 ierr = VecScale(x,s); PCHKERRQ(x,ierr);
790 return *this;
791}
792
794{
795 ierr = VecShift(x,s); PCHKERRQ(x,ierr);
797 return *this;
798}
799
801{
802 ierr = VecPlaceArray(x,temp_data); PCHKERRQ(x,ierr);
803}
804
806{
807 ierr = VecResetArray(x); PCHKERRQ(x,ierr);
808}
809
811{
812 PetscInt n;
813
814 ierr = VecGetLocalSize(x,&n); PCHKERRQ(x,ierr);
815 MFEM_VERIFY(n <= mem.Capacity(),
816 "Memory size " << mem.Capacity() << " < " << n << " vector size!");
817 MFEM_VERIFY(pdata.Empty(),"Vector data is not empty");
818 MFEM_VERIFY(data.Empty(),"Vector data is not empty");
819#if defined(_USE_DEVICE)
820 PetscBool isdevice;
821 ierr = PetscObjectTypeCompareAny((PetscObject)x,&isdevice,
822 VECSEQCUDA,VECMPICUDA,VECSEQHIP,VECMPIHIP,
823 ""); PCHKERRQ(x,ierr);
824 if (isdevice)
825 {
826 bool usedev = mem.DeviceIsValid() || (!rw && mem.UseDevice());
827 pdata.MakeAliasForSync(mem,0,n,rw,true,usedev);
828 if (usedev)
829 {
830 ierr = __mfem_VecSetOffloadMask(x,PETSC_OFFLOAD_GPU); PCHKERRQ(x,ierr);
831 ierr = VecDevicePlaceArray(x,pdata.GetDevicePointer()); PCHKERRQ(x,ierr);
832 }
833 else
834 {
835 ierr = __mfem_VecSetOffloadMask(x,PETSC_OFFLOAD_CPU); PCHKERRQ(x,ierr);
836 ierr = VecPlaceArray(x,pdata.GetHostPointer()); PCHKERRQ(x,ierr);
837 }
838 }
839 else
840#endif
841 {
843 size);
844 pdata.MakeAliasForSync(mem,0,n,rw,true,false);
845#if defined(PETSC_HAVE_DEVICE)
846 ierr = __mfem_VecSetOffloadMask(x,PETSC_OFFLOAD_CPU); PCHKERRQ(x,ierr);
847#endif
848 ierr = VecPlaceArray(x,w); PCHKERRQ(x,ierr);
849 }
850 ierr = __mfem_PetscObjectStateIncrease((PetscObject)x); PCHKERRQ(x,ierr);
852}
853
855{
856 PetscInt n;
857
858 ierr = VecGetLocalSize(x,&n); PCHKERRQ(x,ierr);
859 MFEM_VERIFY(n <= mem.Capacity(),
860 "Memory size " << mem.Capacity() << " < " << n << " vector size!");
861 MFEM_VERIFY(pdata.Empty(),"Vector data is not empty");
862 MFEM_VERIFY(data.Empty(),"Vector data is not empty");
863#if defined(_USE_DEVICE)
864 PetscBool isdevice;
865 ierr = PetscObjectTypeCompareAny((PetscObject)x,&isdevice,
866 VECSEQCUDA,VECMPICUDA,VECSEQHIP,VECMPIHIP,
867 ""); PCHKERRQ(x,ierr);
868 if (isdevice)
869 {
870 pdata.MakeAliasForSync(mem,0,n,mem.DeviceIsValid());
871 if (mem.DeviceIsValid())
872 {
873 ierr = __mfem_VecSetOffloadMask(x,PETSC_OFFLOAD_GPU); PCHKERRQ(x,ierr);
874 ierr = VecDevicePlaceArray(x,pdata.GetDevicePointer()); PCHKERRQ(x,ierr);
875 }
876 else
877 {
878 ierr = __mfem_VecSetOffloadMask(x,PETSC_OFFLOAD_CPU); PCHKERRQ(x,ierr);
879 ierr = VecPlaceArray(x,pdata.GetHostPointer()); PCHKERRQ(x,ierr);
880 }
881 }
882 else
883#endif
884 {
885 const mfem::real_t *w = mfem::HostRead(mem,size);
886 pdata.MakeAliasForSync(mem,0,n,false);
887#if defined(PETSC_HAVE_DEVICE)
888 ierr = __mfem_VecSetOffloadMask(x,PETSC_OFFLOAD_CPU); PCHKERRQ(x,ierr);
889#endif
890 ierr = VecPlaceArray(x,w); PCHKERRQ(x,ierr);
891 }
893 ierr = __mfem_PetscObjectStateIncrease((PetscObject)x); PCHKERRQ(x,ierr);
894 ierr = VecLockReadPush(x); PCHKERRQ(x,ierr);
895}
896
898{
899 MFEM_VERIFY(pdata.IsAliasForSync(),"Vector data is not an alias");
900 MFEM_VERIFY(!pdata.Empty(),"Vector data is empty");
901 bool read = pdata.ReadRequested();
902 bool usedev = pdata.DeviceRequested();
903 bool write = pdata.WriteRequested();
904 /*
905 check for strange corner cases
906 - device memory used but somehow PETSc ended up putting up to date data on host
907 - host memory used but somehow PETSc ended up putting up to date data on device
908 */
909 if (write)
910 {
911 const PetscScalar *v;
912#if defined(PETSC_HAVE_DEVICE)
913 PetscOffloadMask mask;
914 ierr = VecGetOffloadMask(x,&mask); PCHKERRQ(x,ierr);
915 if ((usedev && (mask != PETSC_OFFLOAD_GPU && mask != PETSC_OFFLOAD_BOTH)) ||
916 (!usedev && (mask != PETSC_OFFLOAD_CPU && mask != PETSC_OFFLOAD_BOTH)))
917#endif
918 {
919 ierr = VecGetArrayRead(x,&v); PCHKERRQ(x,ierr);
921 ierr = VecRestoreArrayRead(x,&v); PCHKERRQ(x,ierr);
922 }
923 }
925 data.Reset();
926 if (read && !write) { ierr = VecLockReadPop(x); PCHKERRQ(x,ierr); }
927 if (usedev)
928 {
929#if defined(PETSC_HAVE_DEVICE)
930 ierr = VecDeviceResetArray(x); PCHKERRQ(x,ierr);
931#else
932 MFEM_VERIFY(false,"This should not happen");
933#endif
934 }
935 else
936 {
937 ierr = VecResetArray(x); PCHKERRQ(x,ierr);
938 }
939}
940
942{
943 PetscRandom rctx = NULL;
944
945 if (seed)
946 {
947 ierr = PetscRandomCreate(PetscObjectComm((PetscObject)x),&rctx);
948 PCHKERRQ(x,ierr);
949 ierr = PetscRandomSetSeed(rctx,(unsigned long)seed); PCHKERRQ(x,ierr);
950 ierr = PetscRandomSeed(rctx); PCHKERRQ(x,ierr);
951 }
952 ierr = VecSetRandom(x,rctx); PCHKERRQ(x,ierr);
953 ierr = PetscRandomDestroy(&rctx); PCHKERRQ(x,ierr);
954}
955
956void PetscParVector::Print(const char *fname, bool binary) const
957{
958 if (fname)
959 {
960 PetscViewer view;
961
962 if (binary)
963 {
964 ierr = PetscViewerBinaryOpen(PetscObjectComm((PetscObject)x),fname,
965 FILE_MODE_WRITE,&view);
966 }
967 else
968 {
969 ierr = PetscViewerASCIIOpen(PetscObjectComm((PetscObject)x),fname,&view);
970 }
971 PCHKERRQ(x,ierr);
972 ierr = VecView(x,view); PCHKERRQ(x,ierr);
973 ierr = PetscViewerDestroy(&view); PCHKERRQ(x,ierr);
974 }
975 else
976 {
977 ierr = VecView(x,NULL); PCHKERRQ(x,ierr);
978 }
979}
980
981// PetscParMatrix methods
982
984{
985 PetscInt N;
986 ierr = MatGetOwnershipRange(A,&N,NULL); PCHKERRQ(A,ierr);
987 return N;
988}
989
991{
992 PetscInt N;
993 ierr = MatGetOwnershipRangeColumn(A,&N,NULL); PCHKERRQ(A,ierr);
994 return N;
995}
996
998{
999 PetscInt N;
1000 ierr = MatGetLocalSize(A,&N,NULL); PCHKERRQ(A,ierr);
1001 return N;
1002}
1003
1005{
1006 PetscInt N;
1007 ierr = MatGetLocalSize(A,NULL,&N); PCHKERRQ(A,ierr);
1008 return N;
1009}
1010
1012{
1013 PetscInt N;
1014 ierr = MatGetSize(A,&N,NULL); PCHKERRQ(A,ierr);
1015 return N;
1016}
1017
1019{
1020 PetscInt N;
1021 ierr = MatGetSize(A,NULL,&N); PCHKERRQ(A,ierr);
1022 return N;
1023}
1024
1026{
1027 MatInfo info;
1028 ierr = MatGetInfo(A,MAT_GLOBAL_SUM,&info); PCHKERRQ(A,ierr);
1029 return (PetscInt)info.nz_used;
1030}
1031
1033{
1034 if (cbs < 0) { cbs = rbs; }
1035 ierr = MatSetBlockSizes(A,rbs,cbs); PCHKERRQ(A,ierr);
1036}
1037
1039{
1040 A = NULL;
1041 X = Y = NULL;
1042 height = width = 0;
1043}
1044
1049
1051 const mfem::Array<PetscInt>& rows, const mfem::Array<PetscInt>& cols)
1052{
1053 Init();
1054
1055 Mat B = const_cast<PetscParMatrix&>(pB);
1056
1057 IS isr,isc;
1058 ierr = ISCreateGeneral(PetscObjectComm((PetscObject)B),rows.Size(),
1059 rows.GetData(),PETSC_USE_POINTER,&isr); PCHKERRQ(B,ierr);
1060 ierr = ISCreateGeneral(PetscObjectComm((PetscObject)B),cols.Size(),
1061 cols.GetData(),PETSC_USE_POINTER,&isc); PCHKERRQ(B,ierr);
1062 ierr = MatCreateSubMatrix(B,isr,isc,MAT_INITIAL_MATRIX,&A); PCHKERRQ(B,ierr);
1063 ierr = ISDestroy(&isr); PCHKERRQ(B,ierr);
1064 ierr = ISDestroy(&isc); PCHKERRQ(B,ierr);
1065
1066 height = GetNumRows();
1067 width = GetNumCols();
1068}
1069
1071{
1072 Init();
1073 height = pa->Height();
1074 width = pa->Width();
1075 ConvertOperator(pa->GetComm(),*pa,&A,tid);
1076}
1077
1079{
1080 Init();
1081 height = ha->Height();
1082 width = ha->Width();
1083 ConvertOperator(ha->GetComm(),*ha,&A,tid);
1084}
1085
1087{
1088 Init();
1089 height = sa->Height();
1090 width = sa->Width();
1091 ConvertOperator(PETSC_COMM_SELF,*sa,&A,tid);
1092}
1093
1095 Operator::Type tid)
1096{
1097 Init();
1098 height = op->Height();
1099 width = op->Width();
1100 ConvertOperator(comm,*op,&A,tid);
1101}
1102
1104 PetscInt *row_starts, SparseMatrix *diag,
1105 Operator::Type tid)
1106{
1107 Init();
1108 BlockDiagonalConstructor(comm,row_starts,row_starts,diag,
1109 tid==PETSC_MATAIJ,&A);
1110 SetUpForDevice();
1111 // update base class
1112 height = GetNumRows();
1113 width = GetNumCols();
1114}
1115
1116PetscParMatrix::PetscParMatrix(MPI_Comm comm, PetscInt global_num_rows,
1117 PetscInt global_num_cols, PetscInt *row_starts,
1118 PetscInt *col_starts, SparseMatrix *diag,
1119 Operator::Type tid)
1120{
1121 Init();
1122 BlockDiagonalConstructor(comm,row_starts,col_starts,diag,
1123 tid==PETSC_MATAIJ,&A);
1124 SetUpForDevice();
1125 // update base class
1126 height = GetNumRows();
1127 width = GetNumCols();
1128}
1129
1131{
1132 if (A)
1133 {
1134 MPI_Comm comm = PetscObjectComm((PetscObject)A);
1135 ierr = MatDestroy(&A); CCHKERRQ(comm,ierr);
1136 if (X) { delete X; }
1137 if (Y) { delete Y; }
1138 X = Y = NULL;
1139 }
1140 height = B.Height();
1141 width = B.Width();
1142
1143 ierr = MatCreateFromParCSR(B,MATAIJ,PETSC_USE_POINTER,&A);
1144 CCHKERRQ(B.GetComm(),ierr);
1145
1146 SetUpForDevice();
1147 return *this;
1148}
1149
1151{
1152 if (A)
1153 {
1154 MPI_Comm comm = PetscObjectComm((PetscObject)A);
1155 ierr = MatDestroy(&A); CCHKERRQ(comm,ierr);
1156 if (X) { delete X; }
1157 if (Y) { delete Y; }
1158 X = Y = NULL;
1159 }
1160 height = B.Height();
1161 width = B.Width();
1162 ierr = MatDuplicate(B,MAT_COPY_VALUES,&A); CCHKERRQ(B.GetComm(),ierr);
1163 return *this;
1164}
1165
1167{
1168 if (!A)
1169 {
1170 ierr = MatDuplicate(B,MAT_COPY_VALUES,&A); CCHKERRQ(B.GetComm(),ierr);
1171 }
1172 else
1173 {
1174 MFEM_VERIFY(height == B.Height(),"Invalid number of local rows");
1175 MFEM_VERIFY(width == B.Width(), "Invalid number of local columns");
1176 ierr = MatAXPY(A,1.0,B,DIFFERENT_NONZERO_PATTERN); CCHKERRQ(B.GetComm(),ierr);
1177 }
1178 return *this;
1179}
1180
1182{
1183 if (!A)
1184 {
1185 ierr = MatDuplicate(B,MAT_COPY_VALUES,&A); CCHKERRQ(B.GetComm(),ierr);
1186 ierr = MatScale(A,-1.0); PCHKERRQ(A,ierr);
1187 }
1188 else
1189 {
1190 MFEM_VERIFY(height == B.Height(),"Invalid number of local rows");
1191 MFEM_VERIFY(width == B.Width(), "Invalid number of local columns");
1192 ierr = MatAXPY(A,-1.0,B,DIFFERENT_NONZERO_PATTERN); CCHKERRQ(B.GetComm(),ierr);
1193 }
1194 return *this;
1195}
1196
1197void PetscParMatrix::
1198BlockDiagonalConstructor(MPI_Comm comm,
1199 PetscInt *row_starts, PetscInt *col_starts,
1200 SparseMatrix *diag, bool assembled, Mat* Ad)
1201{
1202 Mat A;
1203 PetscInt lrsize,lcsize,rstart,cstart;
1204 PetscMPIInt myid = 0,commsize;
1205
1206 mpiierr = MPI_Comm_size(comm,&commsize); CCHKERRQ(comm,mpiierr);
1207 if (!HYPRE_AssumedPartitionCheck())
1208 {
1209 mpiierr = MPI_Comm_rank(comm,&myid); CCHKERRQ(comm,mpiierr);
1210 }
1211 lrsize = row_starts[myid+1]-row_starts[myid];
1212 rstart = row_starts[myid];
1213 lcsize = col_starts[myid+1]-col_starts[myid];
1214 cstart = col_starts[myid];
1215
1216 if (!assembled)
1217 {
1218 IS is;
1219 ierr = ISCreateStride(comm,diag->Height(),rstart,1,&is); CCHKERRQ(comm,ierr);
1220 ISLocalToGlobalMapping rl2g,cl2g;
1221 ierr = ISLocalToGlobalMappingCreateIS(is,&rl2g); PCHKERRQ(is,ierr);
1222 ierr = ISDestroy(&is); CCHKERRQ(comm,ierr);
1223 if (row_starts != col_starts)
1224 {
1225 ierr = ISCreateStride(comm,diag->Width(),cstart,1,&is);
1226 CCHKERRQ(comm,ierr);
1227 ierr = ISLocalToGlobalMappingCreateIS(is,&cl2g); PCHKERRQ(is,ierr);
1228 ierr = ISDestroy(&is); CCHKERRQ(comm,ierr);
1229 }
1230 else
1231 {
1232 ierr = PetscObjectReference((PetscObject)rl2g); PCHKERRQ(rl2g,ierr);
1233 cl2g = rl2g;
1234 }
1235
1236 // Create the PETSc object (MATIS format)
1237 ierr = MatCreate(comm,&A); CCHKERRQ(comm,ierr);
1238 ierr = MatSetSizes(A,lrsize,lcsize,PETSC_DECIDE,PETSC_DECIDE);
1239 PCHKERRQ(A,ierr);
1240 ierr = MatSetType(A,MATIS); PCHKERRQ(A,ierr);
1241 ierr = MatSetLocalToGlobalMapping(A,rl2g,cl2g); PCHKERRQ(A,ierr);
1242 ierr = ISLocalToGlobalMappingDestroy(&rl2g); PCHKERRQ(A,ierr)
1243 ierr = ISLocalToGlobalMappingDestroy(&cl2g); PCHKERRQ(A,ierr)
1244
1245 // Copy SparseMatrix into PETSc SeqAIJ format
1246 // pass through host for now
1247 Mat lA;
1248 ierr = MatISGetLocalMat(A,&lA); PCHKERRQ(A,ierr);
1249 const int *II = diag->HostReadI();
1250 const int *JJ = diag->HostReadJ();
1251#if defined(PETSC_USE_64BIT_INDICES)
1252 PetscInt *pII,*pJJ;
1253 int m = diag->Height()+1, nnz = II[diag->Height()];
1254 ierr = PetscMalloc2(m,&pII,nnz,&pJJ); PCHKERRQ(lA,ierr);
1255 for (int i = 0; i < m; i++) { pII[i] = II[i]; }
1256 for (int i = 0; i < nnz; i++) { pJJ[i] = JJ[i]; }
1257 ierr = MatSeqAIJSetPreallocationCSR(lA,pII,pJJ,
1258 diag->HostReadData()); PCHKERRQ(lA,ierr);
1259 ierr = PetscFree2(pII,pJJ); PCHKERRQ(lA,ierr);
1260#else
1261 ierr = MatSeqAIJSetPreallocationCSR(lA,II,JJ,
1262 diag->HostReadData()); PCHKERRQ(lA,ierr);
1263#endif
1264 }
1265 else
1266 {
1267 PetscScalar *da;
1268 PetscInt *dii,*djj,*oii,
1269 m = diag->Height()+1, nnz = diag->NumNonZeroElems();
1270
1271 diag->SortColumnIndices();
1272 // if we can take ownership of the SparseMatrix arrays, we can avoid this
1273 // step
1274 ierr = PetscMalloc1(m,&dii); CCHKERRQ(PETSC_COMM_SELF,ierr);
1275 ierr = PetscMalloc1(nnz,&djj); CCHKERRQ(PETSC_COMM_SELF,ierr);
1276 ierr = PetscMalloc1(nnz,&da); CCHKERRQ(PETSC_COMM_SELF,ierr);
1277 if (sizeof(PetscInt) == sizeof(int))
1278 {
1279 ierr = PetscMemcpy(dii,diag->HostReadI(),m*sizeof(PetscInt));
1280 CCHKERRQ(PETSC_COMM_SELF,ierr);
1281 ierr = PetscMemcpy(djj,diag->HostReadJ(),nnz*sizeof(PetscInt));
1282 CCHKERRQ(PETSC_COMM_SELF,ierr);
1283 }
1284 else
1285 {
1286 const int *iii = diag->HostReadI();
1287 const int *jjj = diag->HostReadJ();
1288 for (int i = 0; i < m; i++) { dii[i] = iii[i]; }
1289 for (int i = 0; i < nnz; i++) { djj[i] = jjj[i]; }
1290 }
1291 ierr = PetscMemcpy(da,diag->HostReadData(),nnz*sizeof(PetscScalar));
1292 CCHKERRQ(PETSC_COMM_SELF,ierr);
1293 ierr = PetscCalloc1(m,&oii);
1294 CCHKERRQ(PETSC_COMM_SELF,ierr);
1295 if (commsize > 1)
1296 {
1297 ierr = MatCreateMPIAIJWithSplitArrays(comm,lrsize,lcsize,PETSC_DECIDE,
1298 PETSC_DECIDE,
1299 dii,djj,da,oii,NULL,NULL,&A);
1300 CCHKERRQ(comm,ierr);
1301 }
1302 else
1303 {
1304 ierr = MatCreateSeqAIJWithArrays(comm,lrsize,lcsize,dii,djj,da,&A);
1305 CCHKERRQ(comm,ierr);
1306 }
1307
1308 void *ptrs[4] = {dii,djj,da,oii};
1309 const char *names[4] = {"_mfem_csr_dii",
1310 "_mfem_csr_djj",
1311 "_mfem_csr_da",
1312 "_mfem_csr_oii",
1313 };
1314 for (PetscInt i=0; i<4; i++)
1315 {
1316 PetscContainer c;
1317
1318 ierr = PetscContainerCreate(comm,&c); CCHKERRQ(comm,ierr);
1319 ierr = PetscContainerSetPointer(c,ptrs[i]); CCHKERRQ(comm,ierr);
1320 ierr = PetscContainerSetCtxDestroy(c,__mfem_array_container_destroy);
1321 CCHKERRQ(comm,ierr);
1322 ierr = PetscObjectCompose((PetscObject)A,names[i],(PetscObject)c);
1323 CCHKERRQ(comm,ierr);
1324 ierr = PetscContainerDestroy(&c); CCHKERRQ(comm,ierr);
1325 }
1326 }
1327
1328 // Tell PETSc the matrix is ready to be used
1329 ierr = MatAssemblyBegin(A,MAT_FINAL_ASSEMBLY); PCHKERRQ(A,ierr);
1330 ierr = MatAssemblyEnd(A,MAT_FINAL_ASSEMBLY); PCHKERRQ(A,ierr);
1331
1332 *Ad = A;
1333}
1334
1336{
1337 return A ? PetscObjectComm((PetscObject)A) : MPI_COMM_NULL;
1338}
1339
1340// TODO ADD THIS CONSTRUCTOR
1341//PetscParMatrix::PetscParMatrix(MPI_Comm comm, int nrows, PetscInt glob_nrows,
1342// PetscInt glob_ncols, int *I, PetscInt *J,
1343// mfem::real_t *data, PetscInt *rows, PetscInt *cols)
1344//{
1345//}
1346
1347// TODO This should take a reference on op but how?
1348void PetscParMatrix::MakeWrapper(MPI_Comm comm, const Operator* op, Mat *A)
1349{
1350 ierr = MatCreate(comm,A); CCHKERRQ(comm,ierr);
1351 ierr = MatSetSizes(*A,op->Height(),op->Width(),
1352 PETSC_DECIDE,PETSC_DECIDE); PCHKERRQ(A,ierr);
1353 ierr = MatSetType(*A,MATSHELL); PCHKERRQ(A,ierr);
1354 ierr = MatShellSetContext(*A,(void *)op); PCHKERRQ(A,ierr);
1355#if PETSC_VERSION_LT(3,24,0)
1356 ierr = MatShellSetOperation(*A,MATOP_MULT,
1357 (void (*)())__mfem_mat_shell_apply);
1358 PCHKERRQ(A,ierr);
1359 ierr = MatShellSetOperation(*A,MATOP_MULT_TRANSPOSE,
1360 (void (*)())__mfem_mat_shell_apply_transpose);
1361 PCHKERRQ(A,ierr);
1362 ierr = MatShellSetOperation(*A,MATOP_COPY,
1363 (void (*)())__mfem_mat_shell_copy);
1364 PCHKERRQ(A,ierr);
1365 ierr = MatShellSetOperation(*A,MATOP_DESTROY,
1366 (void (*)())__mfem_mat_shell_destroy);
1367#else
1368 ierr = MatShellSetOperation(*A,MATOP_MULT,
1369 (PetscErrorCodeFn*)__mfem_mat_shell_apply);
1370 PCHKERRQ(A,ierr);
1371 ierr = MatShellSetOperation(*A,MATOP_MULT_TRANSPOSE,
1372 (PetscErrorCodeFn*)__mfem_mat_shell_apply_transpose);
1373 PCHKERRQ(A,ierr);
1374 ierr = MatShellSetOperation(*A,MATOP_COPY,
1375 (PetscErrorCodeFn*)__mfem_mat_shell_copy);
1376 PCHKERRQ(A,ierr);
1377 ierr = MatShellSetOperation(*A,MATOP_DESTROY,
1378 (PetscErrorCodeFn*)__mfem_mat_shell_destroy);
1379#endif
1380#if defined(_USE_DEVICE)
1382 if (mt == MemoryType::DEVICE || mt == MemoryType::MANAGED)
1383 {
1384 ierr = MatShellSetVecType(*A,PETSC_VECDEVICE); PCHKERRQ(A,ierr);
1385 ierr = MatBindToCPU(*A,PETSC_FALSE); PCHKERRQ(A,ierr);
1386 }
1387 else
1388 {
1389 ierr = MatBindToCPU(*A,PETSC_TRUE); PCHKERRQ(A,ierr);
1390 }
1391#endif
1392 PCHKERRQ(A,ierr);
1393 ierr = MatSetUp(*A); PCHKERRQ(*A,ierr);
1394}
1395
1396void PetscParMatrix::ConvertOperator(MPI_Comm comm, const Operator &op, Mat* A,
1397 Operator::Type tid)
1398{
1399 PetscParMatrix *pA = const_cast<PetscParMatrix *>
1400 (dynamic_cast<const PetscParMatrix *>(&op));
1401 HypreParMatrix *pH = const_cast<HypreParMatrix *>
1402 (dynamic_cast<const HypreParMatrix *>(&op));
1403 BlockOperator *pB = const_cast<BlockOperator *>
1404 (dynamic_cast<const BlockOperator *>(&op));
1405 IdentityOperator *pI = const_cast<IdentityOperator *>
1406 (dynamic_cast<const IdentityOperator *>(&op));
1407 SparseMatrix *pS = const_cast<SparseMatrix *>
1408 (dynamic_cast<const SparseMatrix *>(&op));
1409
1410 if (pA && tid == ANY_TYPE) // use same object and return
1411 {
1412 ierr = PetscObjectReference((PetscObject)(pA->A));
1413 CCHKERRQ(pA->GetComm(),ierr);
1414 *A = pA->A;
1415 return;
1416 }
1417
1418 PetscBool avoidmatconvert = PETSC_FALSE;
1419 if (pA) // we test for these types since MatConvert will fail
1420 {
1421 ierr = PetscObjectTypeCompareAny((PetscObject)(pA->A),&avoidmatconvert,MATMFFD,
1422 MATSHELL,"");
1423 CCHKERRQ(comm,ierr);
1424 }
1425 if (pA && !avoidmatconvert)
1426 {
1427 Mat At = NULL;
1428 PetscBool istrans;
1429#if PETSC_VERSION_LT(3,10,0)
1430 PetscBool ismatis;
1431#endif
1432
1433#if PETSC_VERSION_LT(3,18,0)
1434 ierr = PetscObjectTypeCompare((PetscObject)(pA->A),MATTRANSPOSEMAT,&istrans);
1435#else
1436 ierr = PetscObjectTypeCompare((PetscObject)(pA->A),MATTRANSPOSEVIRTUAL,
1437 &istrans);
1438#endif
1439 CCHKERRQ(pA->GetComm(),ierr);
1440 if (!istrans)
1441 {
1442 if (tid == pA->GetType()) // use same object and return
1443 {
1444 ierr = PetscObjectReference((PetscObject)(pA->A));
1445 CCHKERRQ(pA->GetComm(),ierr);
1446 *A = pA->A;
1447 return;
1448 }
1449#if PETSC_VERSION_LT(3,10,0)
1450 ierr = PetscObjectTypeCompare((PetscObject)(pA->A),MATIS,&ismatis);
1451 CCHKERRQ(pA->GetComm(),ierr);
1452#endif
1453 }
1454 else
1455 {
1456 ierr = MatTransposeGetMat(pA->A,&At); CCHKERRQ(pA->GetComm(),ierr);
1457#if PETSC_VERSION_LT(3,10,0)
1458 ierr = PetscObjectTypeCompare((PetscObject)(At),MATIS,&ismatis);
1459#endif
1460 CCHKERRQ(pA->GetComm(),ierr);
1461 }
1462
1463 // Try to convert
1464 if (tid == PETSC_MATAIJ)
1465 {
1466#if PETSC_VERSION_LT(3,10,0)
1467 if (ismatis)
1468 {
1469 if (istrans)
1470 {
1471 Mat B;
1472
1473 ierr = MatISGetMPIXAIJ(At,MAT_INITIAL_MATRIX,&B); PCHKERRQ(pA->A,ierr);
1474 ierr = MatCreateTranspose(B,A); PCHKERRQ(pA->A,ierr);
1475 ierr = MatDestroy(&B); PCHKERRQ(pA->A,ierr);
1476 }
1477 else
1478 {
1479 ierr = MatISGetMPIXAIJ(pA->A,MAT_INITIAL_MATRIX,A);
1480 PCHKERRQ(pA->A,ierr);
1481 }
1482 }
1483 else
1484#endif
1485 {
1486 PetscMPIInt size;
1487 mpiierr = MPI_Comm_size(comm,&size); CCHKERRQ(comm,mpiierr);
1488
1489 // call MatConvert and see if a converter is available
1490 if (istrans)
1491 {
1492 Mat B;
1493 ierr = MatConvert(At,size > 1 ? MATMPIAIJ : MATSEQAIJ,MAT_INITIAL_MATRIX,&B);
1494 PCHKERRQ(pA->A,ierr);
1495 ierr = MatCreateTranspose(B,A); PCHKERRQ(pA->A,ierr);
1496 ierr = MatDestroy(&B); PCHKERRQ(pA->A,ierr);
1497 }
1498 else
1499 {
1500 ierr = MatConvert(pA->A, size > 1 ? MATMPIAIJ : MATSEQAIJ,MAT_INITIAL_MATRIX,A);
1501 PCHKERRQ(pA->A,ierr);
1502 }
1503 }
1504 }
1505 else if (tid == PETSC_MATIS)
1506 {
1507 if (istrans)
1508 {
1509 Mat B;
1510 ierr = MatConvert(At,MATIS,MAT_INITIAL_MATRIX,&B); PCHKERRQ(pA->A,ierr);
1511 ierr = MatCreateTranspose(B,A); PCHKERRQ(pA->A,ierr);
1512 ierr = MatDestroy(&B); PCHKERRQ(pA->A,ierr);
1513 }
1514 else
1515 {
1516 ierr = MatConvert(pA->A,MATIS,MAT_INITIAL_MATRIX,A); PCHKERRQ(pA->A,ierr);
1517 }
1518 }
1519 else if (tid == PETSC_MATHYPRE)
1520 {
1521 if (istrans)
1522 {
1523 Mat B;
1524 ierr = MatConvert(At,MATHYPRE,MAT_INITIAL_MATRIX,&B); PCHKERRQ(pA->A,ierr);
1525 ierr = MatCreateTranspose(B,A); PCHKERRQ(pA->A,ierr);
1526 ierr = MatDestroy(&B); PCHKERRQ(pA->A,ierr);
1527 }
1528 else
1529 {
1530 ierr = MatConvert(pA->A,MATHYPRE,MAT_INITIAL_MATRIX,A); PCHKERRQ(pA->A,ierr);
1531 }
1532 }
1533 else if (tid == PETSC_MATSHELL)
1534 {
1535 MakeWrapper(comm,&op,A);
1536 }
1537 else
1538 {
1539 MFEM_ABORT("Unsupported operator type conversion " << tid)
1540 }
1541 }
1542 else if (pH)
1543 {
1544 if (tid == PETSC_MATAIJ)
1545 {
1546 ierr = MatCreateFromParCSR(const_cast<HypreParMatrix&>(*pH),MATAIJ,
1547 PETSC_USE_POINTER,A);
1548 CCHKERRQ(pH->GetComm(),ierr);
1549 }
1550 else if (tid == PETSC_MATIS)
1551 {
1552 ierr = MatCreateFromParCSR(const_cast<HypreParMatrix&>(*pH),MATIS,
1553 PETSC_USE_POINTER,A);
1554 CCHKERRQ(pH->GetComm(),ierr);
1555 }
1556 else if (tid == PETSC_MATHYPRE || tid == ANY_TYPE)
1557 {
1558 ierr = MatCreateFromParCSR(const_cast<HypreParMatrix&>(*pH),MATHYPRE,
1559 PETSC_USE_POINTER,A);
1560 CCHKERRQ(pH->GetComm(),ierr);
1561 }
1562 else if (tid == PETSC_MATSHELL)
1563 {
1564 MakeWrapper(comm,&op,A);
1565 }
1566 else
1567 {
1568 MFEM_ABORT("Conversion from HypreParCSR to operator type = " << tid <<
1569 " is not implemented");
1570 }
1571 }
1572 else if (pB)
1573 {
1574 Mat *mats,*matsl2l = NULL;
1575 PetscInt i,j,nr,nc;
1576
1577 nr = pB->NumRowBlocks();
1578 nc = pB->NumColBlocks();
1579 ierr = PetscCalloc1(nr*nc,&mats); CCHKERRQ(PETSC_COMM_SELF,ierr);
1580 if (tid == PETSC_MATIS)
1581 {
1582 ierr = PetscCalloc1(nr,&matsl2l); CCHKERRQ(PETSC_COMM_SELF,ierr);
1583 }
1584 for (i=0; i<nr; i++)
1585 {
1586 PetscBool needl2l = PETSC_TRUE;
1587
1588 for (j=0; j<nc; j++)
1589 {
1590 if (!pB->IsZeroBlock(i,j))
1591 {
1592 ConvertOperator(comm,pB->GetBlock(i,j),&mats[i*nc+j],tid);
1593 if (tid == PETSC_MATIS && needl2l)
1594 {
1595 PetscContainer c;
1596 ierr = PetscObjectQuery((PetscObject)mats[i*nc+j],"_MatIS_PtAP_l2l",
1597 (PetscObject*)&c);
1598 PCHKERRQ(mats[i*nc+j],ierr);
1599 // special case for block operators: the local Vdofs should be
1600 // ordered as:
1601 // [f1_1,...f1_N1,f2_1,...,f2_N2,...,fm_1,...,fm_Nm]
1602 // with m fields, Ni the number of Vdofs for the i-th field
1603 if (c)
1604 {
1605 Array<Mat> *l2l = NULL;
1606 ierr = PetscContainerGetPointer(c,(void**)&l2l);
1607 PCHKERRQ(c,ierr);
1608 MFEM_VERIFY(l2l->Size() == 1,"Unexpected size "
1609 << l2l->Size() << " for block row " << i );
1610 ierr = PetscObjectReference((PetscObject)(*l2l)[0]);
1611 PCHKERRQ(c,ierr);
1612 matsl2l[i] = (*l2l)[0];
1613 needl2l = PETSC_FALSE;
1614 }
1615 }
1616 }
1617 }
1618 }
1619 ierr = MatCreateNest(comm,nr,NULL,nc,NULL,mats,A); CCHKERRQ(comm,ierr);
1620 if (tid == PETSC_MATIS)
1621 {
1622 ierr = MatConvert(*A,MATIS,MAT_INPLACE_MATRIX,A); CCHKERRQ(comm,ierr);
1623
1624 mfem::Array<Mat> *vmatsl2l = new mfem::Array<Mat>(nr);
1625 for (int i=0; i<(int)nr; i++) { (*vmatsl2l)[i] = matsl2l[i]; }
1626 ierr = PetscFree(matsl2l); CCHKERRQ(PETSC_COMM_SELF,ierr);
1627
1628 PetscContainer c;
1629 ierr = PetscContainerCreate(comm,&c); CCHKERRQ(comm,ierr);
1630 ierr = PetscContainerSetPointer(c,vmatsl2l); PCHKERRQ(c,ierr);
1631 ierr = PetscContainerSetCtxDestroy(c,__mfem_matarray_container_destroy);
1632 PCHKERRQ(c,ierr);
1633 ierr = PetscObjectCompose((PetscObject)(*A),"_MatIS_PtAP_l2l",(PetscObject)c);
1634 PCHKERRQ((*A),ierr);
1635 ierr = PetscContainerDestroy(&c); CCHKERRQ(comm,ierr);
1636 }
1637 for (i=0; i<nr*nc; i++) { ierr = MatDestroy(&mats[i]); CCHKERRQ(comm,ierr); }
1638 ierr = PetscFree(mats); CCHKERRQ(PETSC_COMM_SELF,ierr);
1639 }
1640 else if (pI && tid == PETSC_MATAIJ)
1641 {
1642 PetscInt rst;
1643
1644 ierr = MatCreate(comm,A); CCHKERRQ(comm,ierr);
1645 ierr = MatSetSizes(*A,pI->Height(),pI->Width(),PETSC_DECIDE,PETSC_DECIDE);
1646 PCHKERRQ(A,ierr);
1647 ierr = MatSetType(*A,MATAIJ); PCHKERRQ(*A,ierr);
1648 ierr = MatMPIAIJSetPreallocation(*A,1,NULL,0,NULL); PCHKERRQ(*A,ierr);
1649 ierr = MatSeqAIJSetPreallocation(*A,1,NULL); PCHKERRQ(*A,ierr);
1650 ierr = MatSetOption(*A,MAT_NO_OFF_PROC_ENTRIES,PETSC_TRUE); PCHKERRQ(*A,ierr);
1651 ierr = MatGetOwnershipRange(*A,&rst,NULL); PCHKERRQ(*A,ierr);
1652 for (PetscInt i = rst; i < rst+pI->Height(); i++)
1653 {
1654 ierr = MatSetValue(*A,i,i,1.,INSERT_VALUES); PCHKERRQ(*A,ierr);
1655 }
1656 ierr = MatAssemblyBegin(*A,MAT_FINAL_ASSEMBLY); PCHKERRQ(*A,ierr);
1657 ierr = MatAssemblyEnd(*A,MAT_FINAL_ASSEMBLY); PCHKERRQ(*A,ierr);
1658 }
1659 else if (pS)
1660 {
1661 if (tid == PETSC_MATSHELL)
1662 {
1663 MakeWrapper(comm,&op,A);
1664 }
1665 else
1666 {
1667 /* from SparseMatrix to SEQAIJ -> always pass through host for now */
1668 Mat B;
1669 PetscScalar *pdata;
1670 PetscInt *pii,*pjj,*oii;
1671 PetscMPIInt size;
1672
1673 int m = pS->Height();
1674 int n = pS->Width();
1675 const int *ii = pS->HostReadI();
1676 const int *jj = pS->HostReadJ();
1677 const mfem::real_t *data = pS->HostReadData();
1678
1679 ierr = PetscMalloc1(m+1,&pii); CCHKERRQ(PETSC_COMM_SELF,ierr);
1680 ierr = PetscMalloc1(ii[m],&pjj); CCHKERRQ(PETSC_COMM_SELF,ierr);
1681 ierr = PetscMalloc1(ii[m],&pdata); CCHKERRQ(PETSC_COMM_SELF,ierr);
1682 pii[0] = ii[0];
1683 for (int i = 0; i < m; i++)
1684 {
1685 bool issorted = true;
1686 pii[i+1] = ii[i+1];
1687 for (int j = ii[i]; j < ii[i+1]; j++)
1688 {
1689 pjj[j] = jj[j];
1690 if (issorted && j != ii[i]) { issorted = (pjj[j] > pjj[j-1]); }
1691 pdata[j] = data[j];
1692 }
1693 if (!issorted)
1694 {
1695 ierr = PetscSortIntWithScalarArray(pii[i+1]-pii[i],pjj + pii[i],pdata + pii[i]);
1696 CCHKERRQ(PETSC_COMM_SELF,ierr);
1697 }
1698 }
1699
1700 mpiierr = MPI_Comm_size(comm,&size); CCHKERRQ(comm,mpiierr);
1701 if (size == 1)
1702 {
1703 ierr = MatCreateSeqAIJWithArrays(comm,m,n,pii,pjj,pdata,&B);
1704 CCHKERRQ(comm,ierr);
1705 oii = NULL;
1706 }
1707 else // block diagonal constructor
1708 {
1709 ierr = PetscCalloc1(m+1,&oii); CCHKERRQ(PETSC_COMM_SELF,ierr);
1710 ierr = MatCreateMPIAIJWithSplitArrays(comm,m,n,PETSC_DECIDE,
1711 PETSC_DECIDE,
1712 pii,pjj,pdata,oii,NULL,NULL,&B);
1713 CCHKERRQ(comm,ierr);
1714 }
1715 void *ptrs[4] = {pii,pjj,pdata,oii};
1716 const char *names[4] = {"_mfem_csr_pii",
1717 "_mfem_csr_pjj",
1718 "_mfem_csr_pdata",
1719 "_mfem_csr_oii"
1720 };
1721 for (int i=0; i<4; i++)
1722 {
1723 PetscContainer c;
1724
1725 ierr = PetscContainerCreate(PETSC_COMM_SELF,&c); PCHKERRQ(B,ierr);
1726 ierr = PetscContainerSetPointer(c,ptrs[i]); PCHKERRQ(B,ierr);
1727 ierr = PetscContainerSetCtxDestroy(c,__mfem_array_container_destroy);
1728 PCHKERRQ(B,ierr);
1729 ierr = PetscObjectCompose((PetscObject)(B),names[i],(PetscObject)c);
1730 PCHKERRQ(B,ierr);
1731 ierr = PetscContainerDestroy(&c); PCHKERRQ(B,ierr);
1732 }
1733 if (tid == PETSC_MATAIJ)
1734 {
1735 *A = B;
1736 }
1737 else if (tid == PETSC_MATHYPRE)
1738 {
1739 ierr = MatConvert(B,MATHYPRE,MAT_INITIAL_MATRIX,A); PCHKERRQ(B,ierr);
1740 ierr = MatDestroy(&B); PCHKERRQ(*A,ierr);
1741 }
1742 else if (tid == PETSC_MATIS)
1743 {
1744 ierr = MatConvert(B,MATIS,MAT_INITIAL_MATRIX,A); PCHKERRQ(B,ierr);
1745 ierr = MatDestroy(&B); PCHKERRQ(*A,ierr);
1746 }
1747 else
1748 {
1749 MFEM_ABORT("Unsupported operator type conversion " << tid)
1750 }
1751 }
1752 }
1753 else // fallback to general operator
1754 {
1755 MFEM_VERIFY(tid == PETSC_MATSHELL || tid == PETSC_MATAIJ || tid == ANY_TYPE,
1756 "Supported types are ANY_TYPE, PETSC_MATSHELL or PETSC_MATAIJ");
1757 MakeWrapper(comm,&op,A);
1758 if (tid == PETSC_MATAIJ)
1759 {
1760 Mat B;
1761 PetscBool isaij;
1762
1763 ierr = MatComputeOperator(*A,MATMPIAIJ,&B); CCHKERRQ(comm,ierr);
1764 ierr = PetscObjectTypeCompare((PetscObject)B,MATMPIAIJ,&isaij);
1765 CCHKERRQ(comm,ierr);
1766 ierr = MatDestroy(A); CCHKERRQ(comm,ierr);
1767 if (!isaij)
1768 {
1769 ierr = MatConvert(B,MATAIJ,MAT_INITIAL_MATRIX,A); CCHKERRQ(comm,ierr);
1770 ierr = MatDestroy(&B); CCHKERRQ(comm,ierr);
1771 }
1772 else
1773 {
1774 *A = B;
1775 }
1776 }
1777 }
1778 SetUpForDevice();
1779}
1780
1782{
1783 if (A != NULL)
1784 {
1785 MPI_Comm comm = MPI_COMM_NULL;
1786 ierr = PetscObjectGetComm((PetscObject)A,&comm); PCHKERRQ(A,ierr);
1787 ierr = MatDestroy(&A); CCHKERRQ(comm,ierr);
1788 }
1789 delete X;
1790 delete Y;
1791 X = Y = NULL;
1792}
1793
1795{
1796 if (ref)
1797 {
1798 ierr = PetscObjectReference((PetscObject)a); PCHKERRQ(a,ierr);
1799 }
1800 Init();
1801 A = a;
1802 height = GetNumRows();
1803 width = GetNumCols();
1804}
1805
1807{
1808 if (A_ == A) { return; }
1809 Destroy();
1810 ierr = PetscObjectReference((PetscObject)A_); PCHKERRQ(A_,ierr);
1811 A = A_;
1812 height = GetNumRows();
1813 width = GetNumCols();
1814}
1815
1816void PetscParMatrix::SetUpForDevice()
1817{
1818#if !defined(_USE_DEVICE)
1819 return;
1820#else
1821 if (!A || (!Device::Allows(Backend::CUDA_MASK) &&
1823 {
1824 if (A) { ierr = MatBindToCPU(A, PETSC_TRUE); PCHKERRQ(A,ierr); }
1825 return;
1826 }
1827 PetscBool ismatis,isnest,isaij;
1828 ierr = PetscObjectTypeCompare((PetscObject)A,MATIS,&ismatis);
1829 PCHKERRQ(A,ierr);
1830 ierr = PetscObjectTypeCompare((PetscObject)A,MATNEST,&isnest);
1831 PCHKERRQ(A,ierr);
1832 Mat tA = A;
1833 if (ismatis)
1834 {
1835 ierr = MatISGetLocalMat(A,&tA); PCHKERRQ(A,ierr);
1836 ierr = PetscObjectTypeCompare((PetscObject)tA,MATNEST,&isnest);
1837 PCHKERRQ(tA,ierr);
1838 }
1839 if (isnest)
1840 {
1841 PetscInt n,m;
1842 Mat **sub;
1843 ierr = MatNestGetSubMats(tA,&n,&m,&sub); PCHKERRQ(tA,ierr);
1844 bool dvec = false;
1845 for (PetscInt i = 0; i < n; i++)
1846 {
1847 for (PetscInt j = 0; j < m; j++)
1848 {
1849 if (sub[i][j])
1850 {
1851 bool expT = false;
1852 Mat sA = sub[i][j];
1853 ierr = PetscObjectTypeCompareAny((PetscObject)sA,&isaij,MATSEQAIJ,MATMPIAIJ,"");
1854 PCHKERRQ(sA,ierr);
1855 if (isaij)
1856 {
1857 ierr = MatSetType(sA,PETSC_MATAIJDEVICE); PCHKERRQ(sA,ierr);
1858 dvec = true;
1859 expT = true;
1860 }
1861 if (expT)
1862 {
1863 ierr = MatSetOption(sA,MAT_FORM_EXPLICIT_TRANSPOSE,
1864 PETSC_TRUE); PCHKERRQ(sA,ierr);
1865 }
1866 }
1867 }
1868 }
1869 if (dvec)
1870 {
1871 ierr = MatSetVecType(tA,PETSC_VECDEVICE); PCHKERRQ(tA,ierr);
1872 }
1873 }
1874 else
1875 {
1876 bool expT = false;
1877 ierr = PetscObjectTypeCompareAny((PetscObject)tA,&isaij,MATSEQAIJ,MATMPIAIJ,"");
1878 PCHKERRQ(tA,ierr);
1879 if (isaij)
1880 {
1881 ierr = MatSetType(tA,PETSC_MATAIJDEVICE); PCHKERRQ(tA,ierr);
1882 expT = true;
1883 }
1884 if (expT)
1885 {
1886 ierr = MatSetOption(tA,MAT_FORM_EXPLICIT_TRANSPOSE,
1887 PETSC_TRUE); PCHKERRQ(tA,ierr);
1888 }
1889 }
1890#endif
1891}
1892
1893// Computes y = alpha * A * x + beta * y
1894// or y = alpha * A^T* x + beta * y
1895static void MatMultKernel(Mat A,PetscScalar a,Vec X,PetscScalar b,Vec Y,
1896 bool transpose)
1897{
1898 PetscErrorCode (*f)(Mat,Vec,Vec);
1899 PetscErrorCode (*fadd)(Mat,Vec,Vec,Vec);
1900 if (transpose)
1901 {
1902 f = MatMultTranspose;
1903 fadd = MatMultTransposeAdd;
1904 }
1905 else
1906 {
1907 f = MatMult;
1908 fadd = MatMultAdd;
1909 }
1910 if (a != 0.)
1911 {
1912 if (b != 0.)
1913 {
1914 ierr = VecScale(Y,b/a); PCHKERRQ(A,ierr);
1915 ierr = (*fadd)(A,X,Y,Y); PCHKERRQ(A,ierr);
1916 ierr = VecScale(Y,a); PCHKERRQ(A,ierr);
1917 }
1918 else
1919 {
1920 ierr = (*f)(A,X,Y); PCHKERRQ(A,ierr);
1921 ierr = VecScale(Y,a); PCHKERRQ(A,ierr);
1922 }
1923 }
1924 else
1925 {
1926 if (b == 1.)
1927 {
1928 // do nothing
1929 }
1930 else if (b != 0.)
1931 {
1932 ierr = VecScale(Y,b); PCHKERRQ(A,ierr);
1933 }
1934 else
1935 {
1936 ierr = VecSet(Y,0.); PCHKERRQ(A,ierr);
1937 }
1938 }
1939}
1940
1942{
1943 ierr = PetscObjectReference((PetscObject)master.A); PCHKERRQ(master.A,ierr);
1944 Destroy();
1945 Init();
1946 A = master.A;
1947 height = master.height;
1948 width = master.width;
1949}
1950
1952{
1953 if (!X)
1954 {
1955 MFEM_VERIFY(A,"Mat not present");
1956 X = new PetscParVector(*this,false,false); PCHKERRQ(A,ierr);
1957 }
1958 return X;
1959}
1960
1962{
1963 if (!Y)
1964 {
1965 MFEM_VERIFY(A,"Mat not present");
1966 Y = new PetscParVector(*this,true,false); PCHKERRQ(A,ierr);
1967 }
1968 return Y;
1969}
1970
1972{
1973 Mat B;
1974 if (action)
1975 {
1976 ierr = MatCreateTranspose(A,&B); PCHKERRQ(A,ierr);
1977 }
1978 else
1979 {
1980 ierr = MatTranspose(A,MAT_INITIAL_MATRIX,&B); PCHKERRQ(A,ierr);
1981 }
1982 return new PetscParMatrix(B,false);
1983}
1984
1986{
1987 ierr = MatScale(A,s); PCHKERRQ(A,ierr);
1988}
1989
1991 Vector &y) const
1992{
1993 MFEM_ASSERT(x.Size() == Width(), "invalid x.Size() = " << x.Size()
1994 << ", expected size = " << Width());
1995 MFEM_ASSERT(y.Size() == Height(), "invalid y.Size() = " << y.Size()
1996 << ", expected size = " << Height());
1997
1998 PetscParVector *XX = GetX();
1999 PetscParVector *YY = GetY();
2000 bool rw = (b != 0.0);
2001 XX->PlaceMemory(x.GetMemory());
2002 YY->PlaceMemory(y.GetMemory(),rw);
2003 MatMultKernel(A,a,XX->x,b,YY->x,false);
2004 XX->ResetMemory();
2005 YY->ResetMemory();
2006}
2007
2010 Vector &y) const
2011{
2012 MFEM_ASSERT(x.Size() == Height(), "invalid x.Size() = " << x.Size()
2013 << ", expected size = " << Height());
2014 MFEM_ASSERT(y.Size() == Width(), "invalid y.Size() = " << y.Size()
2015 << ", expected size = " << Width());
2016
2017 PetscParVector *XX = GetX();
2018 PetscParVector *YY = GetY();
2019 bool rw = (b != 0.0);
2020 XX->PlaceMemory(y.GetMemory(),rw);
2021 YY->PlaceMemory(x.GetMemory());
2022 MatMultKernel(A,a,YY->x,b,XX->x,true);
2023 XX->ResetMemory();
2024 YY->ResetMemory();
2025}
2026
2027void PetscParMatrix::Print(const char *fname, bool binary) const
2028{
2029 if (fname)
2030 {
2031 PetscViewer view;
2032
2033 if (binary)
2034 {
2035 ierr = PetscViewerBinaryOpen(PetscObjectComm((PetscObject)A),fname,
2036 FILE_MODE_WRITE,&view);
2037 }
2038 else
2039 {
2040 ierr = PetscViewerASCIIOpen(PetscObjectComm((PetscObject)A),fname,&view);
2041 }
2042 PCHKERRQ(A,ierr);
2043 ierr = MatView(A,view); PCHKERRQ(A,ierr);
2044 ierr = PetscViewerDestroy(&view); PCHKERRQ(A,ierr);
2045 }
2046 else
2047 {
2048 ierr = MatView(A,NULL); PCHKERRQ(A,ierr);
2049 }
2050}
2051
2053{
2054 MFEM_ASSERT(s.Size() == Height(), "invalid s.Size() = " << s.Size()
2055 << ", expected size = " << Height());
2056
2057 PetscParVector *YY = GetY();
2058 YY->PlaceMemory(s.GetMemory());
2059 ierr = MatDiagonalScale(A,*YY,NULL); PCHKERRQ(A,ierr);
2060 YY->ResetMemory();
2061}
2062
2064{
2065 MFEM_ASSERT(s.Size() == Width(), "invalid s.Size() = " << s.Size()
2066 << ", expected size = " << Width());
2067
2068 PetscParVector *XX = GetX();
2069 XX->PlaceMemory(s.GetMemory());
2070 ierr = MatDiagonalScale(A,NULL,*XX); PCHKERRQ(A,ierr);
2071 XX->ResetMemory();
2072}
2073
2075{
2076 ierr = MatShift(A,(PetscScalar)s); PCHKERRQ(A,ierr);
2077}
2078
2080{
2081 // for matrices with square diagonal blocks only
2082 MFEM_ASSERT(s.Size() == Height(), "invalid s.Size() = " << s.Size()
2083 << ", expected size = " << Height());
2084 MFEM_ASSERT(s.Size() == Width(), "invalid s.Size() = " << s.Size()
2085 << ", expected size = " << Width());
2086
2087 PetscParVector *XX = GetX();
2088 XX->PlaceMemory(s.GetMemory());
2089 ierr = MatDiagonalSet(A,*XX,ADD_VALUES); PCHKERRQ(A,ierr);
2090 XX->ResetMemory();
2091}
2092
2094 PetscParMatrix *P)
2095{
2096 MFEM_VERIFY(A->Width() == P->Height(),
2097 "Petsc TripleMatrixProduct: Number of local cols of A " << A->Width() <<
2098 " differs from number of local rows of P " << P->Height());
2099 MFEM_VERIFY(A->Height() == R->Width(),
2100 "Petsc TripleMatrixProduct: Number of local rows of A " << A->Height() <<
2101 " differs from number of local cols of R " << R->Width());
2102 Mat B;
2103 ierr = MatMatMatMult(*R,*A,*P,MAT_INITIAL_MATRIX,PETSC_DEFAULT,&B);
2104 PCHKERRQ(*R,ierr);
2105 return new PetscParMatrix(B);
2106}
2107
2109{
2110 Mat pA = *A,pP = *P,pRt = *Rt;
2111 Mat B;
2112 PetscBool Aismatis,Pismatis,Rtismatis;
2113
2114 MFEM_VERIFY(A->Width() == P->Height(),
2115 "Petsc RAP: Number of local cols of A " << A->Width() <<
2116 " differs from number of local rows of P " << P->Height());
2117 MFEM_VERIFY(A->Height() == Rt->Height(),
2118 "Petsc RAP: Number of local rows of A " << A->Height() <<
2119 " differs from number of local rows of Rt " << Rt->Height());
2120 ierr = PetscObjectTypeCompare((PetscObject)pA,MATIS,&Aismatis);
2121 PCHKERRQ(pA,ierr);
2122 ierr = PetscObjectTypeCompare((PetscObject)pP,MATIS,&Pismatis);
2123 PCHKERRQ(pA,ierr);
2124 ierr = PetscObjectTypeCompare((PetscObject)pRt,MATIS,&Rtismatis);
2125 PCHKERRQ(pA,ierr);
2126 if (Aismatis &&
2127 Pismatis &&
2128 Rtismatis) // handle special case (this code will eventually go into PETSc)
2129 {
2130 Mat lA,lP,lB,lRt;
2131 ISLocalToGlobalMapping cl2gP,cl2gRt;
2132 PetscInt rlsize,clsize,rsize,csize;
2133
2134 ierr = MatGetLocalToGlobalMapping(pP,NULL,&cl2gP); PCHKERRQ(pA,ierr);
2135 ierr = MatGetLocalToGlobalMapping(pRt,NULL,&cl2gRt); PCHKERRQ(pA,ierr);
2136 ierr = MatGetLocalSize(pP,NULL,&clsize); PCHKERRQ(pP,ierr);
2137 ierr = MatGetLocalSize(pRt,NULL,&rlsize); PCHKERRQ(pRt,ierr);
2138 ierr = MatGetSize(pP,NULL,&csize); PCHKERRQ(pP,ierr);
2139 ierr = MatGetSize(pRt,NULL,&rsize); PCHKERRQ(pRt,ierr);
2140 ierr = MatCreate(A->GetComm(),&B); PCHKERRQ(pA,ierr);
2141 ierr = MatSetSizes(B,rlsize,clsize,rsize,csize); PCHKERRQ(B,ierr);
2142 ierr = MatSetType(B,MATIS); PCHKERRQ(B,ierr);
2143 ierr = MatSetLocalToGlobalMapping(B,cl2gRt,cl2gP); PCHKERRQ(B,ierr);
2144 ierr = MatISGetLocalMat(pA,&lA); PCHKERRQ(pA,ierr);
2145 ierr = MatISGetLocalMat(pP,&lP); PCHKERRQ(pA,ierr);
2146 ierr = MatISGetLocalMat(pRt,&lRt); PCHKERRQ(pA,ierr);
2147 if (lRt == lP)
2148 {
2149 ierr = MatPtAP(lA,lP,MAT_INITIAL_MATRIX,PETSC_DEFAULT,&lB);
2150 PCHKERRQ(lA,ierr);
2151 }
2152 else
2153 {
2154 Mat lR;
2155 ierr = MatTranspose(lRt,MAT_INITIAL_MATRIX,&lR); PCHKERRQ(lRt,ierr);
2156 ierr = MatMatMatMult(lR,lA,lP,MAT_INITIAL_MATRIX,PETSC_DEFAULT,&lB);
2157 PCHKERRQ(lRt,ierr);
2158 ierr = MatDestroy(&lR); PCHKERRQ(lRt,ierr);
2159 }
2160
2161 // attach lRt matrix to the subdomain local matrix
2162 // it may be used if markers on vdofs have to be mapped on
2163 // subdomain true dofs
2164 {
2165 mfem::Array<Mat> *vmatsl2l = new mfem::Array<Mat>(1);
2166 ierr = PetscObjectReference((PetscObject)lRt); PCHKERRQ(lRt,ierr);
2167 (*vmatsl2l)[0] = lRt;
2168
2169 PetscContainer c;
2170 ierr = PetscContainerCreate(PetscObjectComm((PetscObject)B),&c);
2171 PCHKERRQ(B,ierr);
2172 ierr = PetscContainerSetPointer(c,vmatsl2l); PCHKERRQ(c,ierr);
2173 ierr = PetscContainerSetCtxDestroy(c,__mfem_matarray_container_destroy);
2174 PCHKERRQ(c,ierr);
2175 ierr = PetscObjectCompose((PetscObject)B,"_MatIS_PtAP_l2l",(PetscObject)c);
2176 PCHKERRQ(B,ierr);
2177 ierr = PetscContainerDestroy(&c); PCHKERRQ(B,ierr);
2178 }
2179
2180 // Set local problem
2181 ierr = MatISSetLocalMat(B,lB); PCHKERRQ(lB,ierr);
2182 ierr = MatDestroy(&lB); PCHKERRQ(lA,ierr);
2183 ierr = MatAssemblyBegin(B,MAT_FINAL_ASSEMBLY); PCHKERRQ(B,ierr);
2184 ierr = MatAssemblyEnd(B,MAT_FINAL_ASSEMBLY); PCHKERRQ(B,ierr);
2185 }
2186 else // it raises an error if the PtAP is not supported in PETSc
2187 {
2188 if (pP == pRt)
2189 {
2190 ierr = MatPtAP(pA,pP,MAT_INITIAL_MATRIX,PETSC_DEFAULT,&B);
2191 PCHKERRQ(pA,ierr);
2192 }
2193 else
2194 {
2195 Mat pR;
2196 ierr = MatTranspose(pRt,MAT_INITIAL_MATRIX,&pR); PCHKERRQ(Rt,ierr);
2197 ierr = MatMatMatMult(pR,pA,pP,MAT_INITIAL_MATRIX,PETSC_DEFAULT,&B);
2198 PCHKERRQ(pRt,ierr);
2199 ierr = MatDestroy(&pR); PCHKERRQ(pRt,ierr);
2200 }
2201 }
2202 return new PetscParMatrix(B);
2203}
2204
2206{
2207 PetscParMatrix *out = RAP(P,A,P);
2208 return out;
2209}
2210
2212{
2213 PetscParMatrix *out,*A;
2215 out = RAP(P,A,P);
2216 delete A;
2217 return out;
2218}
2219
2220
2222{
2223 Mat AB;
2224
2225 ierr = MatMatMult(*A,*B,MAT_INITIAL_MATRIX,PETSC_DEFAULT,&AB);
2226 CCHKERRQ(A->GetComm(),ierr);
2227 return new PetscParMatrix(AB);
2228}
2229
2231{
2232 Mat Ae;
2233
2234 PetscParVector dummy(GetComm(),0);
2235 ierr = MatDuplicate(A,MAT_COPY_VALUES,&Ae); PCHKERRQ(A,ierr);
2236 EliminateRowsCols(rows_cols,dummy,dummy);
2237 ierr = MatAXPY(Ae,-1.,A,SAME_NONZERO_PATTERN); PCHKERRQ(A,ierr);
2238 return new PetscParMatrix(Ae);
2239}
2240
2242 const HypreParVector &X,
2243 HypreParVector &B,
2244 mfem::real_t diag)
2245{
2246 MFEM_ABORT("Missing PetscParMatrix::EliminateRowsCols() with HypreParVectors");
2247}
2248
2250 const PetscParVector &X,
2251 PetscParVector &B,
2252 mfem::real_t diag)
2253{
2254 PetscInt M,N;
2255 ierr = MatGetSize(A,&M,&N); PCHKERRQ(A,ierr);
2256 MFEM_VERIFY(M == N,"Rectangular case unsupported");
2257
2258 // TODO: what if a diagonal term is not present?
2259 ierr = MatSetOption(A,MAT_NO_OFF_PROC_ZERO_ROWS,PETSC_TRUE); PCHKERRQ(A,ierr);
2260
2261 // rows need to be in global numbering
2262 PetscInt rst;
2263 ierr = MatGetOwnershipRange(A,&rst,NULL); PCHKERRQ(A,ierr);
2264
2265 IS dir;
2266 ierr = Convert_Array_IS(GetComm(),true,&rows_cols,rst,&dir); PCHKERRQ(A,ierr);
2267 if (!X.GlobalSize() && !B.GlobalSize())
2268 {
2269 ierr = MatZeroRowsColumnsIS(A,dir,diag,NULL,NULL); PCHKERRQ(A,ierr);
2270 }
2271 else
2272 {
2273 ierr = MatZeroRowsColumnsIS(A,dir,diag,X,B); PCHKERRQ(A,ierr);
2274 }
2275 ierr = ISDestroy(&dir); PCHKERRQ(A,ierr);
2276}
2277
2279{
2280 ierr = MatSetOption(A,MAT_NO_OFF_PROC_ZERO_ROWS,PETSC_TRUE); PCHKERRQ(A,ierr);
2281
2282 // rows need to be in global numbering
2283 PetscInt rst;
2284 ierr = MatGetOwnershipRange(A,&rst,NULL); PCHKERRQ(A,ierr);
2285
2286 IS dir;
2287 ierr = Convert_Array_IS(GetComm(),true,&rows,rst,&dir); PCHKERRQ(A,ierr);
2288 ierr = MatZeroRowsIS(A,dir,0.0,NULL,NULL); PCHKERRQ(A,ierr);
2289 ierr = ISDestroy(&dir); PCHKERRQ(A,ierr);
2290}
2291
2292Mat PetscParMatrix::ReleaseMat(bool dereference)
2293{
2294
2295 Mat B = A;
2296 if (dereference)
2297 {
2298 MPI_Comm comm = GetComm();
2299 ierr = PetscObjectDereference((PetscObject)A); CCHKERRQ(comm,ierr);
2300 }
2301 A = NULL;
2302 return B;
2303}
2304
2306{
2307 PetscBool ok;
2308 MFEM_VERIFY(A, "no associated PETSc Mat object");
2309 PetscObject oA = (PetscObject)(this->A);
2310 // map all of MATAIJ, MATSEQAIJ, and MATMPIAIJ to -> PETSC_MATAIJ
2311 ierr = PetscObjectBaseTypeCompare(oA, MATSEQAIJ, &ok); PCHKERRQ(A,ierr);
2312 if (ok == PETSC_TRUE) { return PETSC_MATAIJ; }
2313 ierr = PetscObjectBaseTypeCompare(oA, MATMPIAIJ, &ok); PCHKERRQ(A,ierr);
2314 if (ok == PETSC_TRUE) { return PETSC_MATAIJ; }
2315 ierr = PetscObjectTypeCompare(oA, MATIS, &ok); PCHKERRQ(A,ierr);
2316 if (ok == PETSC_TRUE) { return PETSC_MATIS; }
2317 ierr = PetscObjectTypeCompare(oA, MATSHELL, &ok); PCHKERRQ(A,ierr);
2318 if (ok == PETSC_TRUE) { return PETSC_MATSHELL; }
2319 ierr = PetscObjectTypeCompare(oA, MATNEST, &ok); PCHKERRQ(A,ierr);
2320 if (ok == PETSC_TRUE) { return PETSC_MATNEST; }
2321 ierr = PetscObjectTypeCompare(oA, MATHYPRE, &ok); PCHKERRQ(A,ierr);
2322 if (ok == PETSC_TRUE) { return PETSC_MATHYPRE; }
2323 return PETSC_MATGENERIC;
2324}
2325
2327 const Array<int> &ess_dof_list,
2328 const Vector &X, Vector &B)
2329{
2330 const PetscScalar *array;
2331 Mat pA = const_cast<PetscParMatrix&>(A);
2332
2333 // B -= Ae*X
2334 Ae.Mult(-1.0, X, 1.0, B);
2335
2336 Vec diag = const_cast<PetscParVector&>((*A.GetX()));
2337 ierr = MatGetDiagonal(pA,diag); PCHKERRQ(pA,ierr);
2338 ierr = VecGetArrayRead(diag,&array); PCHKERRQ(diag,ierr);
2339 for (int i = 0; i < ess_dof_list.Size(); i++)
2340 {
2341 int r = ess_dof_list[i];
2342 B(r) = array[r] * X(r);
2343 }
2344 ierr = VecRestoreArrayRead(diag,&array); PCHKERRQ(diag,ierr);
2345}
2346
2347// PetscSolver methods
2348
2349PetscSolver::PetscSolver() : clcustom(false)
2350{
2351 obj = NULL;
2352 B = X = NULL;
2353 cid = -1;
2354 operatorset = false;
2355 bchandler = NULL;
2356 private_ctx = NULL;
2357}
2358
2360{
2361 delete B;
2362 delete X;
2364}
2365
2367{
2368 SetRelTol(tol);
2369}
2370
2372{
2373 if (cid == KSP_CLASSID)
2374 {
2375 KSP ksp = (KSP)obj;
2376 ierr = KSPSetTolerances(ksp,tol,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT);
2377 }
2378 else if (cid == SNES_CLASSID)
2379 {
2380 SNES snes = (SNES)obj;
2381 ierr = SNESSetTolerances(snes,PETSC_DEFAULT,tol,PETSC_DEFAULT,PETSC_DEFAULT,
2382 PETSC_DEFAULT);
2383 }
2384 else if (cid == TS_CLASSID)
2385 {
2386 TS ts = (TS)obj;
2387 ierr = TSSetTolerances(ts,PETSC_DECIDE,NULL,tol,NULL);
2388 }
2389 else
2390 {
2391 MFEM_ABORT("CLASSID = " << cid << " is not implemented!");
2392 }
2393 PCHKERRQ(obj,ierr);
2394}
2395
2397{
2398 if (cid == KSP_CLASSID)
2399 {
2400 KSP ksp = (KSP)obj;
2401 ierr = KSPSetTolerances(ksp,PETSC_DEFAULT,tol,PETSC_DEFAULT,PETSC_DEFAULT);
2402 }
2403 else if (cid == SNES_CLASSID)
2404 {
2405 SNES snes = (SNES)obj;
2406 ierr = SNESSetTolerances(snes,tol,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT,
2407 PETSC_DEFAULT);
2408 }
2409 else if (cid == TS_CLASSID)
2410 {
2411 TS ts = (TS)obj;
2412 ierr = TSSetTolerances(ts,tol,NULL,PETSC_DECIDE,NULL);
2413 }
2414 else
2415 {
2416 MFEM_ABORT("CLASSID = " << cid << " is not implemented!");
2417 }
2418 PCHKERRQ(obj,ierr);
2419}
2420
2421void PetscSolver::SetMaxIter(int max_iter)
2422{
2423 if (cid == KSP_CLASSID)
2424 {
2425 KSP ksp = (KSP)obj;
2426 ierr = KSPSetTolerances(ksp,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT,
2427 max_iter);
2428 }
2429 else if (cid == SNES_CLASSID)
2430 {
2431 SNES snes = (SNES)obj;
2432 ierr = SNESSetTolerances(snes,PETSC_DEFAULT,PETSC_DEFAULT,PETSC_DEFAULT,
2433 max_iter,PETSC_DEFAULT);
2434 }
2435 else if (cid == TS_CLASSID)
2436 {
2437 TS ts = (TS)obj;
2438 ierr = TSSetMaxSteps(ts,max_iter);
2439 }
2440 else
2441 {
2442 MFEM_ABORT("CLASSID = " << cid << " is not implemented!");
2443 }
2444 PCHKERRQ(obj,ierr);
2445}
2446
2447
2449{
2450 PetscViewerAndFormat *vf = NULL;
2451 PetscViewer viewer = PETSC_VIEWER_STDOUT_(PetscObjectComm(obj));
2452
2453 if (plev > 0)
2454 {
2455 ierr = PetscViewerAndFormatCreate(viewer,PETSC_VIEWER_DEFAULT,&vf);
2456 PCHKERRQ(obj,ierr);
2457 }
2458 if (cid == KSP_CLASSID)
2459 {
2460 // there are many other options, see the function KSPSetFromOptions() in
2461 // src/ksp/ksp/interface/itcl.c
2462 KSP ksp = (KSP)obj;
2463 if (plev >= 0)
2464 {
2465 ierr = KSPMonitorCancel(ksp); PCHKERRQ(ksp,ierr);
2466 }
2467 if (plev == 1)
2468 {
2469#if PETSC_VERSION_LT(3,15,0)
2470 ierr = KSPMonitorSet(ksp,(KSPMonitorFn *)KSPMonitorDefault,vf,
2471#else
2472 ierr = KSPMonitorSet(ksp,(KSPMonitorFn *)KSPMonitorResidual,vf,
2473#endif
2474 (PetscCtxDestroyFn *)PetscViewerAndFormatDestroy);
2475 PCHKERRQ(ksp,ierr);
2476 }
2477 else if (plev > 1)
2478 {
2479 ierr = KSPSetComputeSingularValues(ksp,PETSC_TRUE); PCHKERRQ(ksp,ierr);
2480 ierr = KSPMonitorSet(ksp,(KSPMonitorFn *)KSPMonitorSingularValue,vf,
2481 (PetscCtxDestroyFn *)PetscViewerAndFormatDestroy);
2482 PCHKERRQ(ksp,ierr);
2483 if (plev > 2)
2484 {
2485 ierr = PetscViewerAndFormatCreate(viewer,PETSC_VIEWER_DEFAULT,&vf);
2486 PCHKERRQ(viewer,ierr);
2487#if PETSC_VERSION_LT(3,15,0)
2488 ierr = KSPMonitorSet(ksp,(KSPMonitorFn *)KSPMonitorTrueResidualNorm,vf,
2489#else
2490 ierr = KSPMonitorSet(ksp,(KSPMonitorFn *)KSPMonitorTrueResidual,vf,
2491#endif
2492 (PetscCtxDestroyFn *)PetscViewerAndFormatDestroy);
2493 PCHKERRQ(ksp,ierr);
2494 }
2495 }
2496 }
2497 else if (cid == SNES_CLASSID)
2498 {
2499 typedef PetscErrorCode (*myMonitor)(SNES,PetscInt,PetscReal,void*);
2500 SNES snes = (SNES)obj;
2501 if (plev >= 0)
2502 {
2503 ierr = SNESMonitorCancel(snes); PCHKERRQ(snes,ierr);
2504 }
2505 if (plev > 0)
2506 {
2507 ierr = SNESMonitorSet(snes,(myMonitor)SNESMonitorDefault,vf,
2508 (PetscCtxDestroyFn *)PetscViewerAndFormatDestroy);
2509 PCHKERRQ(snes,ierr);
2510 }
2511 }
2512 else if (cid == TS_CLASSID)
2513 {
2514 TS ts = (TS)obj;
2515 if (plev >= 0)
2516 {
2517 ierr = TSMonitorCancel(ts); PCHKERRQ(ts,ierr);
2518 }
2519 }
2520 else
2521 {
2522 MFEM_ABORT("CLASSID = " << cid << " is not implemented!");
2523 }
2524}
2525
2526MPI_Comm PetscSolver::GetComm() const
2527{
2528 return obj ? PetscObjectComm(obj) : MPI_COMM_NULL;
2529}
2530
2532{
2533 __mfem_monitor_ctx *monctx;
2534 ierr = PetscNew(&monctx); CCHKERRQ(PETSC_COMM_SELF,ierr);
2535 monctx->solver = this;
2536 monctx->monitor = ctx;
2537 if (cid == KSP_CLASSID)
2538 {
2539 ierr = KSPMonitorSet((KSP)obj,__mfem_ksp_monitor,monctx,
2540 __mfem_monitor_ctx_destroy);
2541 PCHKERRQ(obj,ierr);
2542 }
2543 else if (cid == SNES_CLASSID)
2544 {
2545 ierr = SNESMonitorSet((SNES)obj,__mfem_snes_monitor,monctx,
2546 __mfem_monitor_ctx_destroy);
2547 PCHKERRQ(obj,ierr);
2548 }
2549 else if (cid == TS_CLASSID)
2550 {
2551 ierr = TSMonitorSet((TS)obj,__mfem_ts_monitor,monctx,
2552 __mfem_monitor_ctx_destroy);
2553 PCHKERRQ(obj,ierr);
2554 }
2555 else
2556 {
2557 MFEM_ABORT("CLASSID = " << cid << " is not implemented!");
2558 }
2559}
2560
2562{
2563 bchandler = bch;
2564 if (cid == SNES_CLASSID)
2565 {
2566 __mfem_snes_ctx* snes_ctx = (__mfem_snes_ctx*)private_ctx;
2567 snes_ctx->bchandler = bchandler;
2568 }
2569 else if (cid == TS_CLASSID)
2570 {
2571 __mfem_ts_ctx* ts_ctx = (__mfem_ts_ctx*)private_ctx;
2572 ts_ctx->bchandler = bchandler;
2573 }
2574 else
2575 {
2576 MFEM_ABORT("Handling of essential bc only implemented for nonlinear and time-dependent solvers");
2577 }
2578}
2579
2581{
2582 PC pc = NULL;
2583 if (cid == TS_CLASSID)
2584 {
2585 SNES snes;
2586 KSP ksp;
2587
2588 ierr = TSGetSNES((TS)obj,&snes); PCHKERRQ(obj,ierr);
2589 ierr = SNESGetKSP(snes,&ksp); PCHKERRQ(obj,ierr);
2590 ierr = KSPGetPC(ksp,&pc); PCHKERRQ(obj,ierr);
2591 }
2592 else if (cid == SNES_CLASSID)
2593 {
2594 KSP ksp;
2595
2596 ierr = SNESGetKSP((SNES)obj,&ksp); PCHKERRQ(obj,ierr);
2597 ierr = KSPGetPC(ksp,&pc); PCHKERRQ(obj,ierr);
2598 }
2599 else if (cid == KSP_CLASSID)
2600 {
2601 ierr = KSPGetPC((KSP)obj,&pc); PCHKERRQ(obj,ierr);
2602 }
2603 else if (cid == PC_CLASSID)
2604 {
2605 pc = (PC)obj;
2606 }
2607 else
2608 {
2609 MFEM_ABORT("No support for PetscPreconditionerFactory for this object");
2610 }
2611 if (factory)
2612 {
2613 ierr = MakeShellPCWithFactory(pc,factory); PCHKERRQ(pc,ierr);
2614 }
2615 else
2616 {
2617 ierr = PCSetType(pc, PCNONE); PCHKERRQ(pc,ierr);
2618 }
2619}
2620
2621void PetscSolver::Customize(bool customize) const
2622{
2623 if (!customize) { clcustom = true; }
2624 if (!clcustom)
2625 {
2626 if (cid == PC_CLASSID)
2627 {
2628 PC pc = (PC)obj;
2629 ierr = PCSetFromOptions(pc); PCHKERRQ(pc, ierr);
2630 }
2631 else if (cid == KSP_CLASSID)
2632 {
2633 KSP ksp = (KSP)obj;
2634 ierr = KSPSetFromOptions(ksp); PCHKERRQ(ksp, ierr);
2635 }
2636 else if (cid == SNES_CLASSID)
2637 {
2638 SNES snes = (SNES)obj;
2639 ierr = SNESSetFromOptions(snes); PCHKERRQ(snes, ierr);
2640 }
2641 else if (cid == TS_CLASSID)
2642 {
2643 TS ts = (TS)obj;
2644 ierr = TSSetFromOptions(ts); PCHKERRQ(ts, ierr);
2645 }
2646 else
2647 {
2648 MFEM_ABORT("CLASSID = " << cid << " is not implemented!");
2649 }
2650 }
2651 clcustom = true;
2652}
2653
2655{
2656 if (cid == KSP_CLASSID)
2657 {
2658 KSP ksp = (KSP)obj;
2659 KSPConvergedReason reason;
2660 ierr = KSPGetConvergedReason(ksp,&reason);
2661 PCHKERRQ(ksp,ierr);
2662 return reason > 0 ? 1 : 0;
2663 }
2664 else if (cid == SNES_CLASSID)
2665 {
2666 SNES snes = (SNES)obj;
2667 SNESConvergedReason reason;
2668 ierr = SNESGetConvergedReason(snes,&reason);
2669 PCHKERRQ(snes,ierr);
2670 return reason > 0 ? 1 : 0;
2671 }
2672 else if (cid == TS_CLASSID)
2673 {
2674 TS ts = (TS)obj;
2675 TSConvergedReason reason;
2676 ierr = TSGetConvergedReason(ts,&reason);
2677 PCHKERRQ(ts,ierr);
2678 return reason > 0 ? 1 : 0;
2679 }
2680 else
2681 {
2682 MFEM_ABORT("CLASSID = " << cid << " is not implemented!");
2683 return -1;
2684 }
2685}
2686
2688{
2689 if (cid == KSP_CLASSID)
2690 {
2691 KSP ksp = (KSP)obj;
2692 PetscInt its;
2693 ierr = KSPGetIterationNumber(ksp,&its);
2694 PCHKERRQ(ksp,ierr);
2695 return its;
2696 }
2697 else if (cid == SNES_CLASSID)
2698 {
2699 SNES snes = (SNES)obj;
2700 PetscInt its;
2701 ierr = SNESGetIterationNumber(snes,&its);
2702 PCHKERRQ(snes,ierr);
2703 return its;
2704 }
2705 else if (cid == TS_CLASSID)
2706 {
2707 TS ts = (TS)obj;
2708 PetscInt its;
2709 ierr = TSGetStepNumber(ts,&its);
2710 PCHKERRQ(ts,ierr);
2711 return its;
2712 }
2713 else
2714 {
2715 MFEM_ABORT("CLASSID = " << cid << " is not implemented!");
2716 return -1;
2717 }
2718}
2719
2721{
2722 if (cid == KSP_CLASSID)
2723 {
2724 KSP ksp = (KSP)obj;
2726 ierr = KSPGetResidualNorm(ksp,&norm);
2727 PCHKERRQ(ksp,ierr);
2728 return norm;
2729 }
2730 if (cid == SNES_CLASSID)
2731 {
2732 SNES snes = (SNES)obj;
2734 ierr = SNESGetFunctionNorm(snes,&norm);
2735 PCHKERRQ(snes,ierr);
2736 return norm;
2737 }
2738 else
2739 {
2740 MFEM_ABORT("CLASSID = " << cid << " is not implemented!");
2741 return PETSC_MAX_REAL;
2742 }
2743}
2744
2746{
2748 if (cid == SNES_CLASSID)
2749 {
2750 __mfem_snes_ctx *snes_ctx;
2751 ierr = PetscNew(&snes_ctx); CCHKERRQ(PETSC_COMM_SELF,ierr);
2752 snes_ctx->op = NULL;
2753 snes_ctx->bchandler = NULL;
2754 snes_ctx->work = NULL;
2755 snes_ctx->jacType = Operator::PETSC_MATAIJ;
2756 private_ctx = (void*) snes_ctx;
2757 }
2758 else if (cid == TS_CLASSID)
2759 {
2760 __mfem_ts_ctx *ts_ctx;
2761 ierr = PetscNew(&ts_ctx); CCHKERRQ(PETSC_COMM_SELF,ierr);
2762 ts_ctx->op = NULL;
2763 ts_ctx->bchandler = NULL;
2764 ts_ctx->work = NULL;
2765 ts_ctx->work2 = NULL;
2766 ts_ctx->cached_shift = std::numeric_limits<PetscReal>::min();
2767 ts_ctx->cached_ijacstate = -1;
2768 ts_ctx->cached_rhsjacstate = -1;
2769 ts_ctx->cached_splits_xstate = -1;
2770 ts_ctx->cached_splits_xdotstate = -1;
2772 ts_ctx->jacType = Operator::PETSC_MATAIJ;
2773 private_ctx = (void*) ts_ctx;
2774 }
2775}
2776
2778{
2779 if (!private_ctx) { return; }
2780 // free private context's owned objects
2781 if (cid == SNES_CLASSID)
2782 {
2783 __mfem_snes_ctx *snes_ctx = (__mfem_snes_ctx *)private_ctx;
2784 delete snes_ctx->work;
2785 }
2786 else if (cid == TS_CLASSID)
2787 {
2788 __mfem_ts_ctx *ts_ctx = (__mfem_ts_ctx *)private_ctx;
2789 delete ts_ctx->work;
2790 delete ts_ctx->work2;
2791 }
2792 ierr = PetscFree(private_ctx); CCHKERRQ(PETSC_COMM_SELF,ierr);
2793}
2794
2795// PetscBCHandler methods
2796
2798 enum PetscBCHandler::Type type_)
2799 : bctype(type_), setup(false), eval_t(0.0),
2800 eval_t_cached(std::numeric_limits<mfem::real_t>::min())
2801{
2803}
2804
2806{
2807 ess_tdof_list.SetSize(list.Size());
2808 ess_tdof_list.Assign(list);
2809 setup = false;
2810}
2811
2813{
2814 if (setup) { return; }
2815 if (bctype == CONSTANT)
2816 {
2817 eval_g.SetSize(n);
2818 this->Eval(eval_t,eval_g);
2819 eval_t_cached = eval_t;
2820 }
2821 else if (bctype == TIME_DEPENDENT)
2822 {
2823 eval_g.SetSize(n);
2824 }
2825 setup = true;
2826}
2827
2829{
2830 (*this).SetUp(x.Size());
2831 y = x;
2832 if (bctype == ZERO)
2833 {
2834 for (int i = 0; i < ess_tdof_list.Size(); ++i)
2835 {
2836 y[ess_tdof_list[i]] = 0.0;
2837 }
2838 }
2839 else
2840 {
2841 if (bctype != CONSTANT && eval_t != eval_t_cached)
2842 {
2843 Eval(eval_t,eval_g);
2844 eval_t_cached = eval_t;
2845 }
2846 for (int i = 0; i < ess_tdof_list.Size(); ++i)
2847 {
2848 y[ess_tdof_list[i]] = eval_g[ess_tdof_list[i]];
2849 }
2850 }
2851}
2852
2854{
2855 (*this).SetUp(x.Size());
2856 if (bctype == ZERO)
2857 {
2858 for (int i = 0; i < ess_tdof_list.Size(); ++i)
2859 {
2860 x[ess_tdof_list[i]] = 0.0;
2861 }
2862 }
2863 else
2864 {
2865 if (bctype != CONSTANT && eval_t != eval_t_cached)
2866 {
2867 Eval(eval_t,eval_g);
2868 eval_t_cached = eval_t;
2869 }
2870 for (int i = 0; i < ess_tdof_list.Size(); ++i)
2871 {
2872 x[ess_tdof_list[i]] = eval_g[ess_tdof_list[i]];
2873 }
2874 }
2875}
2876
2878{
2879 (*this).SetUp(x.Size());
2880 if (bctype == ZERO)
2881 {
2882 for (int i = 0; i < ess_tdof_list.Size(); ++i)
2883 {
2884 y[ess_tdof_list[i]] = x[ess_tdof_list[i]];
2885 }
2886 }
2887 else
2888 {
2889 for (int i = 0; i < ess_tdof_list.Size(); ++i)
2890 {
2891 y[ess_tdof_list[i]] = x[ess_tdof_list[i]] - eval_g[ess_tdof_list[i]];
2892 }
2893 }
2894}
2895
2897{
2898 (*this).SetUp(x.Size());
2899 for (int i = 0; i < ess_tdof_list.Size(); ++i)
2900 {
2901 x[ess_tdof_list[i]] = 0.0;
2902 }
2903}
2904
2906{
2907 (*this).SetUp(x.Size());
2908 y = x;
2909 for (int i = 0; i < ess_tdof_list.Size(); ++i)
2910 {
2911 y[ess_tdof_list[i]] = 0.0;
2912 }
2913}
2914
2915// PetscLinearSolver methods
2916
2917PetscLinearSolver::PetscLinearSolver(MPI_Comm comm, const std::string &prefix,
2918 bool wrapin, bool iter_mode)
2919 : PetscSolver(), Solver(0,iter_mode), wrap(wrapin)
2920{
2921 KSP ksp;
2922 ierr = KSPCreate(comm,&ksp); CCHKERRQ(comm,ierr);
2923 obj = (PetscObject)ksp;
2924 ierr = PetscObjectGetClassId(obj,&cid); PCHKERRQ(obj,ierr);
2925 ierr = KSPSetOptionsPrefix(ksp, prefix.c_str()); PCHKERRQ(ksp, ierr);
2926 ierr = KSPSetInitialGuessNonzero(ksp, (PetscBool)iterative_mode);
2927 PCHKERRQ(ksp, ierr);
2928}
2929
2931 const std::string &prefix, bool iter_mode)
2932 : PetscSolver(), Solver(0,iter_mode), wrap(false)
2933{
2934 KSP ksp;
2935 ierr = KSPCreate(A.GetComm(),&ksp); CCHKERRQ(A.GetComm(),ierr);
2936 obj = (PetscObject)ksp;
2937 ierr = PetscObjectGetClassId(obj,&cid); PCHKERRQ(obj,ierr);
2938 ierr = KSPSetOptionsPrefix(ksp, prefix.c_str()); PCHKERRQ(ksp, ierr);
2939 ierr = KSPSetInitialGuessNonzero(ksp, (PetscBool)iterative_mode);
2940 PCHKERRQ(ksp, ierr);
2941 SetOperator(A);
2942}
2943
2945 const std::string &prefix, bool iter_mode)
2946 : PetscSolver(), Solver(0,iter_mode), wrap(wrapin)
2947{
2948 KSP ksp;
2949 ierr = KSPCreate(A.GetComm(),&ksp); CCHKERRQ(A.GetComm(),ierr);
2950 obj = (PetscObject)ksp;
2951 ierr = PetscObjectGetClassId(obj, &cid); PCHKERRQ(obj, ierr);
2952 ierr = KSPSetOptionsPrefix(ksp, prefix.c_str()); PCHKERRQ(ksp, ierr);
2953 ierr = KSPSetInitialGuessNonzero(ksp, (PetscBool)iterative_mode);
2954 PCHKERRQ(ksp, ierr);
2955 SetOperator(A);
2956}
2957
2959{
2960 const HypreParMatrix *hA = dynamic_cast<const HypreParMatrix *>(&op);
2961 PetscParMatrix *pA = const_cast<PetscParMatrix *>
2962 (dynamic_cast<const PetscParMatrix *>(&op));
2963 const Operator *oA = dynamic_cast<const Operator *>(&op);
2964
2965 // update base classes: Operator, Solver, PetscLinearSolver
2966 bool delete_pA = false;
2967 if (!pA)
2968 {
2969 if (hA)
2970 {
2971 // Create MATSHELL object or convert into a format suitable to construct preconditioners
2972 pA = new PetscParMatrix(hA, wrap ? PETSC_MATSHELL : PETSC_MATAIJ);
2973 delete_pA = true;
2974 }
2975 else if (oA) // fallback to general operator
2976 {
2977 // Create MATSHELL or MATNEST (if oA is a BlockOperator) object
2978 // If oA is a BlockOperator, Operator::Type is relevant to the subblocks
2979 pA = new PetscParMatrix(PetscObjectComm(obj),oA,
2980 wrap ? PETSC_MATSHELL : PETSC_MATAIJ);
2981 delete_pA = true;
2982 }
2983 }
2984 MFEM_VERIFY(pA, "Unsupported operation!");
2985
2986 // Set operators into PETSc KSP
2987 KSP ksp = (KSP)obj;
2988 Mat A = pA->A;
2989 if (operatorset)
2990 {
2991 Mat C;
2992 PetscInt nheight,nwidth,oheight,owidth;
2993
2994 ierr = KSPGetOperators(ksp,&C,NULL); PCHKERRQ(ksp,ierr);
2995 ierr = MatGetSize(A,&nheight,&nwidth); PCHKERRQ(A,ierr);
2996 ierr = MatGetSize(C,&oheight,&owidth); PCHKERRQ(A,ierr);
2997 if (nheight != oheight || nwidth != owidth)
2998 {
2999 // reinit without destroying the KSP
3000 // communicator remains the same
3001 ierr = KSPReset(ksp); PCHKERRQ(ksp,ierr);
3002 delete X;
3003 delete B;
3004 X = B = NULL;
3005 }
3006 }
3007 ierr = KSPSetOperators(ksp,A,A); PCHKERRQ(ksp,ierr);
3008
3009 // Update PetscSolver
3010 operatorset = true;
3011
3012 // Update the Operator fields.
3013 height = pA->Height();
3014 width = pA->Width();
3015
3016 if (delete_pA) { delete pA; }
3017}
3018
3020{
3021 const HypreParMatrix *hA = dynamic_cast<const HypreParMatrix *>(&op);
3022 PetscParMatrix *pA = const_cast<PetscParMatrix *>
3023 (dynamic_cast<const PetscParMatrix *>(&op));
3024 const Operator *oA = dynamic_cast<const Operator *>(&op);
3025
3026 PetscParMatrix *ppA = const_cast<PetscParMatrix *>
3027 (dynamic_cast<const PetscParMatrix *>(&pop));
3028 const Operator *poA = dynamic_cast<const Operator *>(&pop);
3029
3030 // Convert Operator for linear system
3031 bool delete_pA = false;
3032 if (!pA)
3033 {
3034 if (hA)
3035 {
3036 // Create MATSHELL object or convert into a format suitable to construct preconditioners
3037 pA = new PetscParMatrix(hA, wrap ? PETSC_MATSHELL : PETSC_MATAIJ);
3038 delete_pA = true;
3039 }
3040 else if (oA) // fallback to general operator
3041 {
3042 // Create MATSHELL or MATNEST (if oA is a BlockOperator) object
3043 // If oA is a BlockOperator, Operator::Type is relevant to the subblocks
3044 pA = new PetscParMatrix(PetscObjectComm(obj),oA,
3045 wrap ? PETSC_MATSHELL : PETSC_MATAIJ);
3046 delete_pA = true;
3047 }
3048 }
3049 MFEM_VERIFY(pA, "Unsupported operation!");
3050
3051 // Convert Operator to be preconditioned
3052 bool delete_ppA = false;
3053 if (!ppA)
3054 {
3055 if (oA == poA && !wrap) // Same operator, already converted
3056 {
3057 ppA = pA;
3058 }
3059 else
3060 {
3061 ppA = new PetscParMatrix(PetscObjectComm(obj), poA, PETSC_MATAIJ);
3062 delete_ppA = true;
3063 }
3064 }
3065 MFEM_VERIFY(ppA, "Unsupported operation!");
3066
3067 // Set operators into PETSc KSP
3068 KSP ksp = (KSP)obj;
3069 Mat A = pA->A;
3070 Mat P = ppA->A;
3071 if (operatorset)
3072 {
3073 Mat C;
3074 PetscInt nheight,nwidth,oheight,owidth;
3075
3076 ierr = KSPGetOperators(ksp,&C,NULL); PCHKERRQ(ksp,ierr);
3077 ierr = MatGetSize(A,&nheight,&nwidth); PCHKERRQ(A,ierr);
3078 ierr = MatGetSize(C,&oheight,&owidth); PCHKERRQ(A,ierr);
3079 if (nheight != oheight || nwidth != owidth)
3080 {
3081 // reinit without destroying the KSP
3082 // communicator remains the same
3083 ierr = KSPReset(ksp); PCHKERRQ(ksp,ierr);
3084 delete X;
3085 delete B;
3086 X = B = NULL;
3087 wrap = false;
3088 }
3089 }
3090 ierr = KSPSetOperators(ksp,A,P); PCHKERRQ(ksp,ierr);
3091
3092 // Update PetscSolver
3093 operatorset = true;
3094
3095 // Update the Operator fields.
3096 height = pA->Height();
3097 width = pA->Width();
3098
3099 if (delete_pA) { delete pA; }
3100 if (delete_ppA) { delete ppA; }
3101}
3102
3104{
3105 KSP ksp = (KSP)obj;
3106
3107 // Preserve Amat if already set
3108 Mat A = NULL;
3109 PetscBool amat;
3110 ierr = KSPGetOperatorsSet(ksp,&amat,NULL); PCHKERRQ(ksp,ierr);
3111 if (amat)
3112 {
3113 ierr = KSPGetOperators(ksp,&A,NULL); PCHKERRQ(ksp,ierr);
3114 ierr = PetscObjectReference((PetscObject)A); PCHKERRQ(ksp,ierr);
3115 }
3116 PetscPreconditioner *ppc = dynamic_cast<PetscPreconditioner *>(&precond);
3117 if (ppc)
3118 {
3119 ierr = KSPSetPC(ksp,*ppc); PCHKERRQ(ksp,ierr);
3120 }
3121 else
3122 {
3123 // wrap the Solver action
3124 // Solver is assumed to be already setup
3125 // ownership of precond is not transferred,
3126 // consistently with other MFEM's linear solvers
3127 PC pc;
3128 ierr = KSPGetPC(ksp,&pc); PCHKERRQ(ksp,ierr);
3129 ierr = MakeShellPC(pc,precond,false); PCHKERRQ(ksp,ierr);
3130 }
3131 if (A)
3132 {
3133 Mat P;
3134
3135 ierr = KSPGetOperators(ksp,NULL,&P); PCHKERRQ(ksp,ierr);
3136 ierr = PetscObjectReference((PetscObject)P); PCHKERRQ(ksp,ierr);
3137 ierr = KSPSetOperators(ksp,A,P); PCHKERRQ(ksp,ierr);
3138 ierr = MatDestroy(&A); PCHKERRQ(ksp,ierr);
3139 ierr = MatDestroy(&P); PCHKERRQ(ksp,ierr);
3140 }
3141}
3142
3143void PetscLinearSolver::MultKernel(const Vector &b, Vector &x, bool trans) const
3144{
3145 KSP ksp = (KSP)obj;
3146
3147 if (!B || !X)
3148 {
3149 Mat pA = NULL;
3150 ierr = KSPGetOperators(ksp, &pA, NULL); PCHKERRQ(obj, ierr);
3151 if (!B)
3152 {
3153 PetscParMatrix A = PetscParMatrix(pA, true);
3154 B = new PetscParVector(A, true, false);
3155 }
3156 if (!X)
3157 {
3158 PetscParMatrix A = PetscParMatrix(pA, true);
3159 X = new PetscParVector(A, false, false);
3160 }
3161 }
3162 B->PlaceMemory(b.GetMemory());
3163
3164 Customize();
3165
3166 PetscBool flg;
3167 ierr = KSPGetInitialGuessNonzero(ksp, &flg);
3168 X->PlaceMemory(x.GetMemory(),flg);
3169
3170 // Solve the system.
3171 if (trans)
3172 {
3173 ierr = KSPSolveTranspose(ksp, B->x, X->x); PCHKERRQ(ksp,ierr);
3174 }
3175 else
3176 {
3177 ierr = KSPSolve(ksp, B->x, X->x); PCHKERRQ(ksp,ierr);
3178 }
3179 B->ResetMemory();
3180 X->ResetMemory();
3181}
3182
3184{
3185 (*this).MultKernel(b,x,false);
3186}
3187
3189{
3190 (*this).MultKernel(b,x,true);
3191}
3192
3194{
3195 MPI_Comm comm;
3196 KSP ksp = (KSP)obj;
3197 ierr = PetscObjectGetComm((PetscObject)ksp,&comm); PCHKERRQ(ksp,ierr);
3198 ierr = KSPDestroy(&ksp); CCHKERRQ(comm,ierr);
3199}
3200
3201// PetscPCGSolver methods
3202
3203PetscPCGSolver::PetscPCGSolver(MPI_Comm comm, const std::string &prefix,
3204 bool iter_mode)
3205 : PetscLinearSolver(comm,prefix,true,iter_mode)
3206{
3207 KSP ksp = (KSP)obj;
3208 ierr = KSPSetType(ksp,KSPCG); PCHKERRQ(ksp,ierr);
3209 // this is to obtain a textbook PCG
3210 ierr = KSPSetNormType(ksp,KSP_NORM_NATURAL); PCHKERRQ(ksp,ierr);
3211}
3212
3214 bool iter_mode)
3215 : PetscLinearSolver(A,prefix,iter_mode)
3216{
3217 KSP ksp = (KSP)obj;
3218 ierr = KSPSetType(ksp,KSPCG); PCHKERRQ(ksp,ierr);
3219 // this is to obtain a textbook PCG
3220 ierr = KSPSetNormType(ksp,KSP_NORM_NATURAL); PCHKERRQ(ksp,ierr);
3221}
3222
3224 const std::string &prefix, bool iter_mode)
3225 : PetscLinearSolver(A,wrap,prefix,iter_mode)
3226{
3227 KSP ksp = (KSP)obj;
3228 ierr = KSPSetType(ksp,KSPCG); PCHKERRQ(ksp,ierr);
3229 // this is to obtain a textbook PCG
3230 ierr = KSPSetNormType(ksp,KSP_NORM_NATURAL); PCHKERRQ(ksp,ierr);
3231}
3232
3233// PetscPreconditioner methods
3234
3236 const std::string &prefix)
3237 : PetscSolver(), Solver()
3238{
3239 PC pc;
3240 ierr = PCCreate(comm,&pc); CCHKERRQ(comm,ierr);
3241 obj = (PetscObject)pc;
3242 ierr = PetscObjectGetClassId(obj,&cid); PCHKERRQ(obj,ierr);
3243 ierr = PCSetOptionsPrefix(pc, prefix.c_str()); PCHKERRQ(pc, ierr);
3244}
3245
3247 const string &prefix)
3248 : PetscSolver(), Solver()
3249{
3250 PC pc;
3251 ierr = PCCreate(A.GetComm(),&pc); CCHKERRQ(A.GetComm(),ierr);
3252 obj = (PetscObject)pc;
3253 ierr = PetscObjectGetClassId(obj,&cid); PCHKERRQ(obj,ierr);
3254 ierr = PCSetOptionsPrefix(pc, prefix.c_str()); PCHKERRQ(pc, ierr);
3255 SetOperator(A);
3256}
3257
3259 const string &prefix)
3260 : PetscSolver(), Solver()
3261{
3262 PC pc;
3263 ierr = PCCreate(comm,&pc); CCHKERRQ(comm,ierr);
3264 obj = (PetscObject)pc;
3265 ierr = PetscObjectGetClassId(obj,&cid); PCHKERRQ(obj,ierr);
3266 ierr = PCSetOptionsPrefix(pc, prefix.c_str()); PCHKERRQ(pc, ierr);
3267 SetOperator(op);
3268}
3269
3271{
3272 bool delete_pA = false;
3273 PetscParMatrix *pA = const_cast<PetscParMatrix *>
3274 (dynamic_cast<const PetscParMatrix *>(&op));
3275
3276 if (!pA)
3277 {
3278 const Operator *cop = dynamic_cast<const Operator *>(&op);
3279 pA = new PetscParMatrix(PetscObjectComm(obj),cop,PETSC_MATAIJ);
3280 delete_pA = true;
3281 }
3282
3283 // Set operators into PETSc PC
3284 PC pc = (PC)obj;
3285 Mat A = pA->A;
3286 if (operatorset)
3287 {
3288 Mat C;
3289 PetscInt nheight,nwidth,oheight,owidth;
3290
3291 ierr = PCGetOperators(pc,&C,NULL); PCHKERRQ(pc,ierr);
3292 ierr = MatGetSize(A,&nheight,&nwidth); PCHKERRQ(A,ierr);
3293 ierr = MatGetSize(C,&oheight,&owidth); PCHKERRQ(A,ierr);
3294 if (nheight != oheight || nwidth != owidth)
3295 {
3296 // reinit without destroying the PC
3297 // communicator remains the same
3298 ierr = PCReset(pc); PCHKERRQ(pc,ierr);
3299 delete X;
3300 delete B;
3301 X = B = NULL;
3302 }
3303 }
3304 ierr = PCSetOperators(pc,pA->A,pA->A); PCHKERRQ(obj,ierr);
3305
3306 // Update PetscSolver
3307 operatorset = true;
3308
3309 // Update the Operator fields.
3310 height = pA->Height();
3311 width = pA->Width();
3312
3313 if (delete_pA) { delete pA; };
3314}
3315
3316void PetscPreconditioner::MultKernel(const Vector &b, Vector &x,
3317 bool trans) const
3318{
3319 MFEM_VERIFY(!iterative_mode,
3320 "Iterative mode not supported for PetscPreconditioner");
3321 PC pc = (PC)obj;
3322
3323 if (!B || !X)
3324 {
3325 Mat pA = NULL;
3326 ierr = PCGetOperators(pc, NULL, &pA); PCHKERRQ(obj, ierr);
3327 if (!B)
3328 {
3329 PetscParMatrix A(pA, true);
3330 B = new PetscParVector(A, true, false);
3331 }
3332 if (!X)
3333 {
3334 PetscParMatrix A(pA, true);
3335 X = new PetscParVector(A, false, false);
3336 }
3337 }
3338 B->PlaceMemory(b.GetMemory());
3339 X->PlaceMemory(x.GetMemory());
3340
3341 Customize();
3342
3343 // Apply the preconditioner.
3344 if (trans)
3345 {
3346 ierr = PCApplyTranspose(pc, B->x, X->x); PCHKERRQ(pc, ierr);
3347 }
3348 else
3349 {
3350 ierr = PCApply(pc, B->x, X->x); PCHKERRQ(pc, ierr);
3351 }
3352 B->ResetMemory();
3353 X->ResetMemory();
3354}
3355
3357{
3358 (*this).MultKernel(b,x,false);
3359}
3360
3362{
3363 (*this).MultKernel(b,x,true);
3364}
3365
3367{
3368 MPI_Comm comm;
3369 PC pc = (PC)obj;
3370 ierr = PetscObjectGetComm((PetscObject)pc,&comm); PCHKERRQ(pc,ierr);
3371 ierr = PCDestroy(&pc); CCHKERRQ(comm,ierr);
3372}
3373
3374// PetscBDDCSolver methods
3375
3376// Coordinates sampling function
3377static void func_coords(const Vector &x, Vector &y)
3378{
3379 y = x;
3380}
3381
3382void PetscBDDCSolver::BDDCSolverConstructor(const PetscBDDCSolverParams &opts)
3383{
3384 MPI_Comm comm = PetscObjectComm(obj);
3385
3386 // get PETSc object
3387 PC pc = (PC)obj;
3388 Mat pA;
3389 ierr = PCGetOperators(pc,NULL,&pA); PCHKERRQ(pc,ierr);
3390
3391 // matrix type should be of type MATIS
3392 PetscBool ismatis;
3393 ierr = PetscObjectTypeCompare((PetscObject)pA,MATIS,&ismatis);
3394 PCHKERRQ(pA,ierr);
3395 MFEM_VERIFY(ismatis,"PetscBDDCSolver needs the matrix in unassembled format");
3396
3397 // Check options
3398 ParFiniteElementSpace *fespace = opts.fespace;
3399 if (opts.netflux && !fespace)
3400 {
3401 MFEM_WARNING("Don't know how to compute an auxiliary quadrature form without a ParFiniteElementSpace");
3402 }
3403
3404 // Attach default near-null space to local matrices
3405 {
3406 MatNullSpace nnsp;
3407 Mat lA;
3408 ierr = MatISGetLocalMat(pA,&lA); CCHKERRQ(comm,ierr);
3409 ierr = MatNullSpaceCreate(PetscObjectComm((PetscObject)lA),PETSC_TRUE,0,NULL,
3410 &nnsp); CCHKERRQ(PETSC_COMM_SELF,ierr);
3411 ierr = MatSetNearNullSpace(lA,nnsp); CCHKERRQ(PETSC_COMM_SELF,ierr);
3412 ierr = MatNullSpaceDestroy(&nnsp); CCHKERRQ(PETSC_COMM_SELF,ierr);
3413 }
3414
3415 // set PETSc PC type to PCBDDC
3416 ierr = PCSetType(pc,PCBDDC); PCHKERRQ(obj,ierr);
3417
3418 PetscInt rst,nl;
3419 ierr = MatGetOwnershipRange(pA,&rst,NULL); PCHKERRQ(pA,ierr);
3420 ierr = MatGetLocalSize(pA,&nl,NULL); PCHKERRQ(pA,ierr);
3421
3422 // index sets for fields splitting and coordinates for nodal spaces
3423 IS *fields = NULL;
3424 PetscInt nf = 0;
3425 PetscInt sdim = 0;
3426 PetscReal *coords = NULL;
3427 if (fespace)
3428 {
3429 int vdim = fespace->GetVDim();
3430
3431 // Ideally, the block size should be set at matrix creation
3432 // but the MFEM assembly does not allow to do so
3433 if (fespace->GetOrdering() == Ordering::byVDIM)
3434 {
3435 Mat lA;
3436 ierr = MatSetBlockSize(pA,vdim); PCHKERRQ(pA,ierr);
3437 ierr = MatISGetLocalMat(pA,&lA); CCHKERRQ(PETSC_COMM_SELF,ierr);
3438 ierr = MatSetBlockSize(lA,vdim); PCHKERRQ(pA,ierr);
3439 }
3440
3441 // fields
3442 if (vdim > 1)
3443 {
3444 PetscInt st = rst, bs, inc, nlf;
3445 nf = vdim;
3446 nlf = nl/nf;
3447 ierr = PetscMalloc1(nf,&fields); CCHKERRQ(PETSC_COMM_SELF,ierr);
3448 if (fespace->GetOrdering() == Ordering::byVDIM)
3449 {
3450 inc = 1;
3451 bs = vdim;
3452 }
3453 else
3454 {
3455 inc = nlf;
3456 bs = 1;
3457 }
3458 for (PetscInt i = 0; i < nf; i++)
3459 {
3460 ierr = ISCreateStride(comm,nlf,st,bs,&fields[i]); CCHKERRQ(comm,ierr);
3461 st += inc;
3462 }
3463 }
3464
3465 // coordinates
3466 const FiniteElementCollection *fec = fespace->FEColl();
3467 bool h1space = dynamic_cast<const H1_FECollection*>(fec);
3468 if (h1space)
3469 {
3470 ParFiniteElementSpace *fespace_coords = fespace;
3471
3472 sdim = fespace->GetParMesh()->SpaceDimension();
3473 if (vdim != sdim || fespace->GetOrdering() != Ordering::byVDIM)
3474 {
3475 fespace_coords = new ParFiniteElementSpace(fespace->GetParMesh(),fec,sdim,
3477 }
3478 VectorFunctionCoefficient coeff_coords(sdim, func_coords);
3479 ParGridFunction gf_coords(fespace_coords);
3480 gf_coords.ProjectCoefficient(coeff_coords);
3481 HypreParVector *hvec_coords = gf_coords.ParallelProject();
3482 PetscScalar *data_coords = (PetscScalar*)mfem::Read(hvec_coords->GetMemory(),
3483 hvec_coords->Size(),false);
3484
3485 // likely elasticity -> we attach rigid-body modes as near-null space information to the local matrices
3486 // and to the global matrix
3487 if (vdim == sdim)
3488 {
3489 MatNullSpace nnsp;
3490 Mat lA;
3491 Vec pvec_coords,lvec_coords;
3492 ISLocalToGlobalMapping l2g;
3493 PetscSF sf;
3494 PetscLayout rmap;
3495 const PetscInt *gidxs;
3496 PetscInt nleaves;
3497
3498 ierr = VecCreateMPIWithArray(comm,sdim,hvec_coords->Size(),
3499 hvec_coords->GlobalSize(),data_coords,&pvec_coords);
3500 CCHKERRQ(comm,ierr);
3501 ierr = MatGetNearNullSpace(pA,&nnsp); CCHKERRQ(comm,ierr);
3502 if (!nnsp)
3503 {
3504 ierr = MatNullSpaceCreateRigidBody(pvec_coords,&nnsp);
3505 CCHKERRQ(comm,ierr);
3506 ierr = MatSetNearNullSpace(pA,nnsp); CCHKERRQ(comm,ierr);
3507 ierr = MatNullSpaceDestroy(&nnsp); CCHKERRQ(comm,ierr);
3508 }
3509 ierr = MatISGetLocalMat(pA,&lA); CCHKERRQ(comm,ierr);
3510 ierr = MatCreateVecs(lA,&lvec_coords,NULL); CCHKERRQ(PETSC_COMM_SELF,ierr);
3511 ierr = VecSetBlockSize(lvec_coords,sdim); CCHKERRQ(PETSC_COMM_SELF,ierr);
3512 ierr = MatGetLocalToGlobalMapping(pA,&l2g,NULL); CCHKERRQ(comm,ierr);
3513 ierr = MatGetLayouts(pA,&rmap,NULL); CCHKERRQ(comm,ierr);
3514 ierr = PetscSFCreate(comm,&sf); CCHKERRQ(comm,ierr);
3515 ierr = ISLocalToGlobalMappingGetIndices(l2g,&gidxs); CCHKERRQ(comm,ierr);
3516 ierr = ISLocalToGlobalMappingGetSize(l2g,&nleaves); CCHKERRQ(comm,ierr);
3517 ierr = PetscSFSetGraphLayout(sf,rmap,nleaves,NULL,PETSC_OWN_POINTER,gidxs);
3518 CCHKERRQ(comm,ierr);
3519 ierr = ISLocalToGlobalMappingRestoreIndices(l2g,&gidxs); CCHKERRQ(comm,ierr);
3520 {
3521 const PetscScalar *garray;
3522 PetscScalar *larray;
3523
3524 ierr = VecGetArrayRead(pvec_coords,&garray); CCHKERRQ(PETSC_COMM_SELF,ierr);
3525 ierr = VecGetArray(lvec_coords,&larray); CCHKERRQ(PETSC_COMM_SELF,ierr);
3526#if PETSC_VERSION_LT(3,15,0)
3527 ierr = PetscSFBcastBegin(sf,MPIU_SCALAR,garray,larray); CCHKERRQ(comm,ierr);
3528 ierr = PetscSFBcastEnd(sf,MPIU_SCALAR,garray,larray); CCHKERRQ(comm,ierr);
3529#else
3530 ierr = PetscSFBcastBegin(sf,MPIU_SCALAR,garray,larray,MPI_REPLACE);
3531 CCHKERRQ(comm,ierr);
3532 ierr = PetscSFBcastEnd(sf,MPIU_SCALAR,garray,larray,MPI_REPLACE);
3533 CCHKERRQ(comm,ierr);
3534#endif
3535 ierr = VecRestoreArrayRead(pvec_coords,&garray); CCHKERRQ(PETSC_COMM_SELF,ierr);
3536 ierr = VecRestoreArray(lvec_coords,&larray); CCHKERRQ(PETSC_COMM_SELF,ierr);
3537 }
3538 ierr = VecDestroy(&pvec_coords); CCHKERRQ(comm,ierr);
3539 ierr = MatNullSpaceCreateRigidBody(lvec_coords,&nnsp);
3540 CCHKERRQ(PETSC_COMM_SELF,ierr);
3541 ierr = VecDestroy(&lvec_coords); CCHKERRQ(PETSC_COMM_SELF,ierr);
3542 ierr = MatSetNearNullSpace(lA,nnsp); CCHKERRQ(PETSC_COMM_SELF,ierr);
3543 ierr = MatNullSpaceDestroy(&nnsp); CCHKERRQ(PETSC_COMM_SELF,ierr);
3544 ierr = PetscSFDestroy(&sf); CCHKERRQ(PETSC_COMM_SELF,ierr);
3545 }
3546
3547 // each single dof has associated a tuple of coordinates
3548 ierr = PetscMalloc1(nl*sdim,&coords); CCHKERRQ(PETSC_COMM_SELF,ierr);
3549 if (nf > 0)
3550 {
3551 for (PetscInt i = 0; i < nf; i++)
3552 {
3553 const PetscInt *idxs;
3554 PetscInt nn;
3555
3556 // It also handles the case of fespace not ordered by VDIM
3557 ierr = ISGetLocalSize(fields[i],&nn); CCHKERRQ(comm,ierr);
3558 ierr = ISGetIndices(fields[i],&idxs); CCHKERRQ(comm,ierr);
3559 for (PetscInt j = 0; j < nn; j++)
3560 {
3561 PetscInt idx = idxs[j]-rst;
3562 for (PetscInt d = 0; d < sdim; d++)
3563 {
3564 coords[sdim*idx+d] = PetscRealPart(data_coords[sdim*j+d]);
3565 }
3566 }
3567 ierr = ISRestoreIndices(fields[i],&idxs); CCHKERRQ(comm,ierr);
3568 }
3569 }
3570 else
3571 {
3572 for (PetscInt j = 0; j < nl*sdim; j++) { coords[j] = PetscRealPart(data_coords[j]); }
3573 }
3574 if (fespace_coords != fespace)
3575 {
3576 delete fespace_coords;
3577 }
3578 delete hvec_coords;
3579 }
3580 }
3581
3582 // index sets for boundary dofs specification (Essential = dir, Natural = neu)
3583 IS dir = NULL, neu = NULL;
3584
3585 // Extract l2l matrices
3586 Array<Mat> *l2l = NULL;
3587 if (opts.ess_dof_local || opts.nat_dof_local)
3588 {
3589 PetscContainer c;
3590
3591 ierr = PetscObjectQuery((PetscObject)pA,"_MatIS_PtAP_l2l",(PetscObject*)&c);
3592 MFEM_VERIFY(c,"Local-to-local PETSc container not present");
3593 ierr = PetscContainerGetPointer(c,(void**)&l2l); PCHKERRQ(c,ierr);
3594 }
3595
3596 // check information about index sets (essential dofs, fields, etc.)
3597#ifdef MFEM_DEBUG
3598 {
3599 // make sure ess/nat_dof have been collectively set
3600 PetscBool lpr = PETSC_FALSE,pr;
3601 if (opts.ess_dof) { lpr = PETSC_TRUE; }
3602#if PETSC_VERSION_LT(3,24,0)
3603 mpiierr = MPI_Allreduce(&lpr,&pr,1,MPIU_BOOL,MPI_LOR,comm);
3604#else
3605 mpiierr = MPI_Allreduce(&lpr,&pr,1,MPI_C_BOOL,MPI_LOR,comm);
3606#endif
3607 CCHKERRQ(comm,mpiierr);
3608 MFEM_VERIFY(lpr == pr,"ess_dof should be collectively set");
3609 lpr = PETSC_FALSE;
3610 if (opts.nat_dof) { lpr = PETSC_TRUE; }
3611#if PETSC_VERSION_LT(3,24,0)
3612 mpiierr = MPI_Allreduce(&lpr,&pr,1,MPIU_BOOL,MPI_LOR,comm);
3613#else
3614 mpiierr = MPI_Allreduce(&lpr,&pr,1,MPI_C_BOOL,MPI_LOR,comm);
3615#endif
3616 CCHKERRQ(comm,mpiierr);
3617 MFEM_VERIFY(lpr == pr,"nat_dof should be collectively set");
3618 // make sure fields have been collectively set
3619 PetscInt ms[2],Ms[2];
3620 ms[0] = -nf; ms[1] = nf;
3621 mpiierr = MPI_Allreduce(&ms,&Ms,2,MPIU_INT,MPI_MAX,comm);
3622 CCHKERRQ(comm,mpiierr);
3623 MFEM_VERIFY(-Ms[0] == Ms[1],
3624 "number of fields should be the same across processes");
3625 }
3626#endif
3627
3628 // boundary sets
3629 if (opts.ess_dof)
3630 {
3631 PetscInt st = opts.ess_dof_local ? 0 : rst;
3632 if (!opts.ess_dof_local)
3633 {
3634 // need to compute the boundary dofs in global ordering
3635 ierr = Convert_Array_IS(comm,true,opts.ess_dof,st,&dir);
3636 CCHKERRQ(comm,ierr);
3637 ierr = PCBDDCSetDirichletBoundaries(pc,dir); PCHKERRQ(pc,ierr);
3638 }
3639 else
3640 {
3641 // need to compute a list for the marked boundary dofs in local ordering
3642 ierr = Convert_Vmarks_IS(comm,*l2l,opts.ess_dof,st,&dir);
3643 CCHKERRQ(comm,ierr);
3644 ierr = PCBDDCSetDirichletBoundariesLocal(pc,dir); PCHKERRQ(pc,ierr);
3645 }
3646 }
3647 if (opts.nat_dof)
3648 {
3649 PetscInt st = opts.nat_dof_local ? 0 : rst;
3650 if (!opts.nat_dof_local)
3651 {
3652 // need to compute the boundary dofs in global ordering
3653 ierr = Convert_Array_IS(comm,true,opts.nat_dof,st,&neu);
3654 CCHKERRQ(comm,ierr);
3655 ierr = PCBDDCSetNeumannBoundaries(pc,neu); PCHKERRQ(pc,ierr);
3656 }
3657 else
3658 {
3659 // need to compute a list for the marked boundary dofs in local ordering
3660 ierr = Convert_Vmarks_IS(comm,*l2l,opts.nat_dof,st,&neu);
3661 CCHKERRQ(comm,ierr);
3662 ierr = PCBDDCSetNeumannBoundariesLocal(pc,neu); PCHKERRQ(pc,ierr);
3663 }
3664 }
3665
3666 // field splitting
3667 if (fields)
3668 {
3669 ierr = PCBDDCSetDofsSplitting(pc,nf,fields); PCHKERRQ(pc,ierr);
3670 }
3671 for (PetscInt i = 0; i < nf; i++)
3672 {
3673 ierr = ISDestroy(&fields[i]); CCHKERRQ(comm,ierr);
3674 }
3675 ierr = PetscFree(fields); CCHKERRQ(PETSC_COMM_SELF,ierr);
3676
3677 // coordinates
3678 if (coords)
3679 {
3680 ierr = PCSetCoordinates(pc,sdim,nl,coords); PCHKERRQ(pc,ierr);
3681 }
3682 ierr = PetscFree(coords); CCHKERRQ(PETSC_COMM_SELF,ierr);
3683
3684 // code for block size is disabled since we cannot change the matrix
3685 // block size after it has been setup
3686 // int bs = 1;
3687
3688 // Customize using the finite element space (if any)
3689 if (fespace)
3690 {
3691 const FiniteElementCollection *fec = fespace->FEColl();
3692 bool edgespace, rtspace, h1space;
3693 bool needint = opts.netflux;
3694 bool tracespace, rt_tracespace, edge_tracespace;
3695 int vdim, dim, p;
3696 PetscBool B_is_Trans = PETSC_FALSE;
3697
3698 ParMesh *pmesh = (ParMesh *) fespace->GetMesh();
3699 dim = pmesh->Dimension();
3700 vdim = fespace->GetVDim();
3701 h1space = dynamic_cast<const H1_FECollection*>(fec);
3702 rtspace = dynamic_cast<const RT_FECollection*>(fec);
3703 edgespace = dynamic_cast<const ND_FECollection*>(fec);
3704 edge_tracespace = dynamic_cast<const ND_Trace_FECollection*>(fec);
3705 rt_tracespace = dynamic_cast<const RT_Trace_FECollection*>(fec);
3706 tracespace = edge_tracespace || rt_tracespace;
3707
3708 p = 1;
3709 if (fespace->GetNE() > 0)
3710 {
3711 if (!tracespace)
3712 {
3713 p = fespace->GetElementOrder(0);
3714 }
3715 else
3716 {
3717 p = fespace->GetFaceOrder(0);
3718 if (dim == 2) { p++; }
3719 }
3720 }
3721
3722 if (edgespace) // H(curl)
3723 {
3724 if (dim == 2)
3725 {
3726 needint = true;
3727 if (tracespace)
3728 {
3729 MFEM_WARNING("Tracespace case doesn't work for H(curl) and p=2,"
3730 " not using auxiliary quadrature");
3731 needint = false;
3732 }
3733 }
3734 else
3735 {
3736 FiniteElementCollection *vfec;
3737 if (tracespace)
3738 {
3739 vfec = new H1_Trace_FECollection(p,dim);
3740 }
3741 else
3742 {
3743 vfec = new H1_FECollection(p,dim);
3744 }
3745 ParFiniteElementSpace *vfespace = new ParFiniteElementSpace(pmesh,vfec);
3746 ParDiscreteLinearOperator *grad;
3747 grad = new ParDiscreteLinearOperator(vfespace,fespace);
3748 if (tracespace)
3749 {
3750 grad->AddTraceFaceInterpolator(new GradientInterpolator);
3751 }
3752 else
3753 {
3754 grad->AddDomainInterpolator(new GradientInterpolator);
3755 }
3756 grad->Assemble();
3757 grad->Finalize();
3758 HypreParMatrix *hG = grad->ParallelAssemble();
3759 PetscParMatrix *G = new PetscParMatrix(hG,PETSC_MATAIJ);
3760 delete hG;
3761 delete grad;
3762
3763 PetscBool conforming = PETSC_TRUE;
3764 if (pmesh->Nonconforming()) { conforming = PETSC_FALSE; }
3765 ierr = PCBDDCSetDiscreteGradient(pc,*G,p,0,PETSC_TRUE,conforming);
3766 PCHKERRQ(pc,ierr);
3767 delete vfec;
3768 delete vfespace;
3769 delete G;
3770 }
3771 }
3772 else if (rtspace) // H(div)
3773 {
3774 needint = true;
3775 if (tracespace)
3776 {
3777 MFEM_WARNING("Tracespace case doesn't work for H(div), not using"
3778 " auxiliary quadrature");
3779 needint = false;
3780 }
3781 }
3782 else if (h1space) // H(grad), only for the vector case
3783 {
3784 if (vdim != dim) { needint = false; }
3785 }
3786
3787 PetscParMatrix *B = NULL;
3788 if (needint)
3789 {
3790 // Generate bilinear form in unassembled format which is used to
3791 // compute the net-flux across subdomain boundaries for H(div) and
3792 // Elasticity/Stokes, and the line integral \int u x n of 2D H(curl) fields
3793 FiniteElementCollection *auxcoll;
3794 if (tracespace) { auxcoll = new RT_Trace_FECollection(p,dim); }
3795 else
3796 {
3797 if (h1space)
3798 {
3799 auxcoll = new H1_FECollection(std::max(p-1,1),dim);
3800 }
3801 else
3802 {
3803 auxcoll = new L2_FECollection(p,dim);
3804 }
3805 }
3806 ParFiniteElementSpace *pspace = new ParFiniteElementSpace(pmesh,auxcoll);
3807 ParMixedBilinearForm *b = new ParMixedBilinearForm(fespace,pspace);
3808
3809 if (edgespace)
3810 {
3811 if (tracespace)
3812 {
3813 b->AddTraceFaceIntegrator(new VectorFECurlIntegrator);
3814 }
3815 else
3816 {
3817 b->AddDomainIntegrator(new VectorFECurlIntegrator);
3818 }
3819 }
3820 else if (rtspace)
3821 {
3822 if (tracespace)
3823 {
3824 b->AddTraceFaceIntegrator(new VectorFEDivergenceIntegrator);
3825 }
3826 else
3827 {
3828 b->AddDomainIntegrator(new VectorFEDivergenceIntegrator);
3829 }
3830 }
3831 else
3832 {
3833 b->AddDomainIntegrator(new VectorDivergenceIntegrator);
3834 }
3835 b->Assemble();
3836 b->Finalize();
3837 OperatorHandle Bh(Operator::PETSC_MATIS);
3838 b->ParallelAssemble(Bh);
3839 Bh.Get(B);
3840 Bh.SetOperatorOwner(false);
3841
3842 if (dir) // if essential dofs are present, we need to zero the columns
3843 {
3844 Mat pB = *B;
3845 ierr = MatTranspose(pB,MAT_INPLACE_MATRIX,&pB); PCHKERRQ(pA,ierr);
3846 if (!opts.ess_dof_local)
3847 {
3848 ierr = MatZeroRowsIS(pB,dir,0.,NULL,NULL); PCHKERRQ(pA,ierr);
3849 }
3850 else
3851 {
3852 ierr = MatZeroRowsLocalIS(pB,dir,0.,NULL,NULL); PCHKERRQ(pA,ierr);
3853 }
3854 B_is_Trans = PETSC_TRUE;
3855 }
3856 delete b;
3857 delete pspace;
3858 delete auxcoll;
3859 }
3860
3861 if (B)
3862 {
3863 ierr = PCBDDCSetDivergenceMat(pc,*B,B_is_Trans,NULL); PCHKERRQ(pc,ierr);
3864 }
3865 delete B;
3866 }
3867 ierr = ISDestroy(&dir); PCHKERRQ(pc,ierr);
3868 ierr = ISDestroy(&neu); PCHKERRQ(pc,ierr);
3869}
3870
3872 const PetscBDDCSolverParams &opts,
3873 const std::string &prefix)
3874 : PetscPreconditioner(A,prefix)
3875{
3876 BDDCSolverConstructor(opts);
3877 Customize();
3878}
3879
3881 const PetscBDDCSolverParams &opts,
3882 const std::string &prefix)
3883 : PetscPreconditioner(comm,op,prefix)
3884{
3885 BDDCSolverConstructor(opts);
3886 Customize();
3887}
3888
3890 const string &prefix)
3891 : PetscPreconditioner(comm,op,prefix)
3892{
3893 PC pc = (PC)obj;
3894 ierr = PCSetType(pc,PCFIELDSPLIT); PCHKERRQ(pc,ierr);
3895
3896 Mat pA;
3897 ierr = PCGetOperators(pc,&pA,NULL); PCHKERRQ(pc,ierr);
3898
3899 // Check if pA is of type MATNEST
3900 PetscBool isnest;
3901 ierr = PetscObjectTypeCompare((PetscObject)pA,MATNEST,&isnest);
3902
3903 PetscInt nr = 0;
3904 IS *isrow = NULL;
3905 if (isnest) // we know the fields
3906 {
3907 ierr = MatNestGetSize(pA,&nr,NULL); PCHKERRQ(pc,ierr);
3908 ierr = PetscCalloc1(nr,&isrow); CCHKERRQ(PETSC_COMM_SELF,ierr);
3909 ierr = MatNestGetISs(pA,isrow,NULL); PCHKERRQ(pc,ierr);
3910 }
3911
3912 // We need to customize here, before setting the index sets.
3913 // This is because PCFieldSplitSetType customizes the function
3914 // pointers. SubSolver options will be processed during PCApply
3915 Customize();
3916
3917 for (PetscInt i=0; i<nr; i++)
3918 {
3919 ierr = PCFieldSplitSetIS(pc,NULL,isrow[i]); PCHKERRQ(pc,ierr);
3920 }
3921 ierr = PetscFree(isrow); CCHKERRQ(PETSC_COMM_SELF,ierr);
3922}
3923
3926 const std::string &prefix)
3927 : PetscPreconditioner(fes->GetParMesh()->GetComm(),prefix)
3928{
3930 ierr = MatSetOption(A,MAT_SYMMETRIC,PETSC_TRUE); PCHKERRQ(A,ierr);
3931 ierr = MatSetOption(A,MAT_SYMMETRY_ETERNAL,PETSC_TRUE); PCHKERRQ(A,ierr);
3932 SetOperator(A);
3933 H2SolverConstructor(fes);
3934 Customize();
3935}
3936
3937void PetscH2Solver::H2SolverConstructor(ParFiniteElementSpace *fes)
3938{
3939#if defined(PETSC_HAVE_H2OPUS)
3940 int sdim = fes->GetParMesh()->SpaceDimension();
3941 int vdim = fes->GetVDim();
3942 const FiniteElementCollection *fec = fes->FEColl();
3943 ParFiniteElementSpace *fes_coords = NULL;
3944
3945 if (vdim != sdim || fes->GetOrdering() != Ordering::byVDIM)
3946 {
3947 fes_coords = new ParFiniteElementSpace(fes->GetParMesh(),fec,sdim,
3949 fes = fes_coords;
3950 }
3951 VectorFunctionCoefficient ccoords(sdim, func_coords);
3952
3953 ParGridFunction coords(fes);
3954 coords.ProjectCoefficient(ccoords);
3955 Vector c(fes->GetTrueVSize());
3956 coords.ParallelProject(c);
3957 delete fes_coords;
3958
3959 PC pc = (PC)obj;
3960 ierr = PCSetType(pc,PCH2OPUS); PCHKERRQ(obj, ierr);
3961 ierr = PCSetCoordinates(pc,sdim,c.Size()/sdim,
3962 (PetscReal*)mfem::Read(c.GetMemory(),
3963 c.Size(),false));
3964 ierr = PCSetFromOptions(pc); PCHKERRQ(obj, ierr);
3965#else
3966 MFEM_ABORT("Need PETSc configured with --download-h2opus");
3967#endif
3968}
3969
3970// PetscNonlinearSolver methods
3971
3973 const std::string &prefix)
3974 : PetscSolver(), Solver()
3975{
3976 // Create the actual solver object
3977 SNES snes;
3978 ierr = SNESCreate(comm, &snes); CCHKERRQ(comm, ierr);
3979 obj = (PetscObject)snes;
3980 ierr = PetscObjectGetClassId(obj, &cid); PCHKERRQ(obj, ierr);
3981 ierr = SNESSetOptionsPrefix(snes, prefix.c_str()); PCHKERRQ(snes, ierr);
3982
3983 // Allocate private solver context
3985}
3986
3988 const std::string &prefix)
3989 : PetscSolver(), Solver()
3990{
3991 // Create the actual solver object
3992 SNES snes;
3993 ierr = SNESCreate(comm, &snes); CCHKERRQ(comm, ierr);
3994 obj = (PetscObject)snes;
3995 ierr = PetscObjectGetClassId(obj, &cid); PCHKERRQ(obj, ierr);
3996 ierr = SNESSetOptionsPrefix(snes, prefix.c_str()); PCHKERRQ(snes, ierr);
3997
3998 // Allocate private solver context
4000
4001 SetOperator(op);
4002}
4003
4005{
4006 MPI_Comm comm;
4007 SNES snes = (SNES)obj;
4008 ierr = PetscObjectGetComm(obj,&comm); PCHKERRQ(obj, ierr);
4009 ierr = SNESDestroy(&snes); CCHKERRQ(comm, ierr);
4010}
4011
4013{
4014 SNES snes = (SNES)obj;
4015
4016 if (operatorset)
4017 {
4018 PetscBool ls,gs;
4019 void *fctx,*jctx;
4020
4021 ierr = SNESGetFunction(snes, NULL, NULL, &fctx);
4022 PCHKERRQ(snes, ierr);
4023 ierr = SNESGetJacobian(snes, NULL, NULL, NULL, &jctx);
4024 PCHKERRQ(snes, ierr);
4025
4026 ls = (PetscBool)(height == op.Height() && width == op.Width() &&
4027 (void*)&op == fctx &&
4028 (void*)&op == jctx);
4029#if PETSC_VERSION_LT(3,24,0)
4030 mpiierr = MPI_Allreduce(&ls,&gs,1,MPIU_BOOL,MPI_LAND,
4031 PetscObjectComm((PetscObject)snes));
4032#else
4033 mpiierr = MPI_Allreduce(&ls,&gs,1,MPI_C_BOOL,MPI_LAND,
4034 PetscObjectComm((PetscObject)snes));
4035#endif
4036 CCHKERRQ(PetscObjectComm((PetscObject)snes),mpiierr);
4037 if (!gs)
4038 {
4039 ierr = SNESReset(snes); PCHKERRQ(snes,ierr);
4040 delete X;
4041 delete B;
4042 X = B = NULL;
4043 }
4044 }
4045 else
4046 {
4047 /* PETSc sets the linesearch type to basic (i.e. no linesearch) if not
4048 yet set. We default to backtracking */
4049 SNESLineSearch ls;
4050 ierr = SNESGetLineSearch(snes, &ls); PCHKERRQ(snes,ierr);
4051 ierr = SNESLineSearchSetType(ls, SNESLINESEARCHBT); PCHKERRQ(snes,ierr);
4052 }
4053
4054 // If we do not pass matrices in, the default matrix type for DMShell is MATDENSE
4055 // in 3.15, which may cause issues.
4056 Mat dummy;
4057 ierr = __mfem_MatCreateDummy(PetscObjectComm((PetscObject)snes),op.Height(),
4058 op.Height(),&dummy);
4059
4060 __mfem_snes_ctx *snes_ctx = (__mfem_snes_ctx*)private_ctx;
4061 snes_ctx->op = (Operator*)&op;
4062 ierr = SNESSetFunction(snes, NULL, __mfem_snes_function, (void *)snes_ctx);
4063 PCHKERRQ(snes, ierr);
4064 ierr = SNESSetJacobian(snes, dummy, dummy, __mfem_snes_jacobian,
4065 (void *)snes_ctx);
4066 PCHKERRQ(snes, ierr);
4067
4068 ierr = MatDestroy(&dummy);
4069 PCHKERRQ(snes, ierr);
4070
4071 // Update PetscSolver
4072 operatorset = true;
4073
4074 // Update the Operator fields.
4075 height = op.Height();
4076 width = op.Width();
4077}
4078
4080{
4081 __mfem_snes_ctx *snes_ctx = (__mfem_snes_ctx*)private_ctx;
4082 snes_ctx->jacType = jacType;
4083}
4084
4086 mfem::real_t*))
4087{
4088 __mfem_snes_ctx *snes_ctx = (__mfem_snes_ctx*)private_ctx;
4089 snes_ctx->objective = objfn;
4090
4091 SNES snes = (SNES)obj;
4092 ierr = SNESSetObjective(snes, __mfem_snes_objective, (void *)snes_ctx);
4093 PCHKERRQ(snes, ierr);
4094}
4095
4097 Vector&, Vector&,
4098 bool&, bool&))
4099{
4100 __mfem_snes_ctx *snes_ctx = (__mfem_snes_ctx*)private_ctx;
4101 snes_ctx->postcheck = post;
4102
4103 SNES snes = (SNES)obj;
4104 SNESLineSearch ls;
4105 ierr = SNESGetLineSearch(snes, &ls); PCHKERRQ(snes,ierr);
4106 ierr = SNESLineSearchSetPostCheck(ls, __mfem_snes_postcheck, (void *)snes_ctx);
4107 PCHKERRQ(ls, ierr);
4108}
4109
4111 const Vector&,
4112 const Vector&,
4113 const Vector&,
4114 const Vector&))
4115{
4116 __mfem_snes_ctx *snes_ctx = (__mfem_snes_ctx*)private_ctx;
4117 snes_ctx->update = update;
4118
4119 SNES snes = (SNES)obj;
4120 ierr = SNESSetUpdate(snes, __mfem_snes_update); PCHKERRQ(snes, ierr);
4121}
4122
4124{
4125 SNES snes = (SNES)obj;
4126 MPI_Comm comm = PetscObjectComm(obj);
4127
4128 // Reduction needed: some processes may have null local size while others don't,
4129 // and VecPlaceArray (used by PlaceMemory) is a logically collective operation.
4130 PetscBool b_nonempty = b.Size() ? PETSC_TRUE : PETSC_FALSE;
4131#if PETSC_VERSION_LT(3,24,0)
4132 mpiierr = MPI_Allreduce(MPI_IN_PLACE,&b_nonempty,1,MPIU_BOOL,MPI_LOR,comm);
4133#else
4134 mpiierr = MPI_Allreduce(MPI_IN_PLACE,&b_nonempty,1,MPI_C_BOOL,MPI_LOR,comm);
4135#endif
4136 CCHKERRQ(comm,mpiierr);
4137
4138 // Always create B with allocate=false so that PlaceMemory can be called on
4139 // it regardless of whether b was empty on a previous call.
4140 if (!B) { B = new PetscParVector(comm, *this, true, false); }
4141 if (!X) { X = new PetscParVector(comm, *this, false, false); }
4143 if (b_nonempty) { B->PlaceMemory(b.GetMemory()); }
4144
4145 Customize();
4146
4147 if (!iterative_mode) { *X = 0.; }
4148
4149 // Solve the system. Pass nullptr for b when empty (PETSc treats it as zero RHS).
4150 ierr = SNESSolve(snes, b_nonempty ? B->x : nullptr, X->x); PCHKERRQ(snes, ierr);
4151 X->ResetMemory();
4152 if (b_nonempty) { B->ResetMemory(); }
4153}
4154
4155// PetscODESolver methods
4156
4157PetscODESolver::PetscODESolver(MPI_Comm comm, const string &prefix)
4158 : PetscSolver(), ODESolver()
4159{
4160 // Create the actual solver object
4161 TS ts;
4162 ierr = TSCreate(comm,&ts); CCHKERRQ(comm,ierr);
4163 obj = (PetscObject)ts;
4164 ierr = PetscObjectGetClassId(obj,&cid); PCHKERRQ(obj,ierr);
4165 ierr = TSSetOptionsPrefix(ts, prefix.c_str()); PCHKERRQ(ts, ierr);
4166
4167 // Allocate private solver context
4169
4170 // Default options, to comply with the current interface to ODESolver.
4171 ierr = TSSetMaxSteps(ts,PETSC_MAX_INT-1);
4172 PCHKERRQ(ts,ierr);
4173 ierr = TSSetExactFinalTime(ts,TS_EXACTFINALTIME_STEPOVER);
4174 PCHKERRQ(ts,ierr);
4175 TSAdapt tsad;
4176 ierr = TSGetAdapt(ts,&tsad);
4177 PCHKERRQ(ts,ierr);
4178 ierr = TSAdaptSetType(tsad,TSADAPTNONE);
4179 PCHKERRQ(ts,ierr);
4180}
4181
4183{
4184 MPI_Comm comm;
4185 TS ts = (TS)obj;
4186 ierr = PetscObjectGetComm(obj,&comm); PCHKERRQ(obj,ierr);
4187 ierr = TSDestroy(&ts); CCHKERRQ(comm,ierr);
4188}
4189
4191 enum PetscODESolver::Type type)
4192{
4193 TS ts = (TS)obj;
4194
4195 __mfem_ts_ctx *ts_ctx = (__mfem_ts_ctx*)private_ctx;
4196 if (operatorset)
4197 {
4198 ierr = TSReset(ts); PCHKERRQ(ts,ierr);
4199 delete X;
4200 X = NULL;
4201 ts_ctx->cached_shift = std::numeric_limits<PetscReal>::min();
4202 ts_ctx->cached_ijacstate = -1;
4203 ts_ctx->cached_rhsjacstate = -1;
4204 ts_ctx->cached_splits_xstate = -1;
4205 ts_ctx->cached_splits_xdotstate = -1;
4206 }
4207 f = &f_;
4208
4209 // Set functions in TS
4210 ts_ctx->op = &f_;
4211 if (f_.isImplicit())
4212 {
4213 Mat dummy;
4214 ierr = __mfem_MatCreateDummy(PetscObjectComm((PetscObject)ts),f_.Height(),
4215 f_.Height(),&dummy);
4216 PCHKERRQ(ts, ierr);
4217 ierr = TSSetIFunction(ts, NULL, __mfem_ts_ifunction, (void *)ts_ctx);
4218 PCHKERRQ(ts, ierr);
4219 ierr = TSSetIJacobian(ts, dummy, dummy, __mfem_ts_ijacobian, (void *)ts_ctx);
4220 PCHKERRQ(ts, ierr);
4221 ierr = TSSetEquationType(ts, TS_EQ_IMPLICIT);
4222 PCHKERRQ(ts, ierr);
4223 ierr = MatDestroy(&dummy);
4224 PCHKERRQ(ts, ierr);
4225 }
4226 if (!f_.isHomogeneous())
4227 {
4228 Mat dummy = NULL;
4229 if (!f_.isImplicit())
4230 {
4231 ierr = TSSetEquationType(ts, TS_EQ_EXPLICIT);
4232 PCHKERRQ(ts, ierr);
4233 }
4234 else
4235 {
4236 ierr = __mfem_MatCreateDummy(PetscObjectComm((PetscObject)ts),f_.Height(),
4237 f_.Height(),&dummy);
4238 PCHKERRQ(ts, ierr);
4239 }
4240 ierr = TSSetRHSFunction(ts, NULL, __mfem_ts_rhsfunction, (void *)ts_ctx);
4241 PCHKERRQ(ts, ierr);
4242 ierr = TSSetRHSJacobian(ts, dummy, dummy, __mfem_ts_rhsjacobian,
4243 (void *)ts_ctx);
4244 PCHKERRQ(ts, ierr);
4245 ierr = MatDestroy(&dummy);
4246 PCHKERRQ(ts, ierr);
4247 }
4248 operatorset = true;
4249
4250 SetType(type);
4251
4252 // Set solution vector
4253 PetscParVector X(PetscObjectComm(obj),*f,false,true);
4254 ierr = TSSetSolution(ts,X); PCHKERRQ(ts,ierr);
4255
4256 // Compose special purpose function for PDE-constrained optimization
4257 PetscBool use = PETSC_TRUE;
4258 ierr = PetscOptionsGetBool(NULL,NULL,"-mfem_use_splitjac",&use,NULL);
4259 if (use && f_.isImplicit())
4260 {
4261 ierr = PetscObjectComposeFunction((PetscObject)ts,"TSComputeSplitJacobians_C",
4262 __mfem_ts_computesplits);
4263 PCHKERRQ(ts,ierr);
4264 }
4265 else
4266 {
4267 ierr = PetscObjectComposeFunction((PetscObject)ts,"TSComputeSplitJacobians_C",
4268 NULL);
4269 PCHKERRQ(ts,ierr);
4270 }
4271}
4272
4274{
4275 __mfem_ts_ctx *ts_ctx = (__mfem_ts_ctx*)private_ctx;
4276 ts_ctx->jacType = jacType;
4277}
4278
4280{
4281 __mfem_ts_ctx *ts_ctx = (__mfem_ts_ctx*)private_ctx;
4282 return ts_ctx->type;
4283}
4284
4286{
4287 __mfem_ts_ctx *ts_ctx = (__mfem_ts_ctx*)private_ctx;
4288
4289 TS ts = (TS)obj;
4290 ts_ctx->type = type;
4291 if (type == ODE_SOLVER_LINEAR)
4292 {
4293 ierr = TSSetProblemType(ts, TS_LINEAR);
4294 PCHKERRQ(ts, ierr);
4295 }
4296 else
4297 {
4298 ierr = TSSetProblemType(ts, TS_NONLINEAR);
4299 PCHKERRQ(ts, ierr);
4300 }
4301}
4302
4304{
4305 // Pass the parameters to PETSc.
4306 TS ts = (TS)obj;
4307 ierr = TSSetTime(ts, t); PCHKERRQ(ts, ierr);
4308 ierr = TSSetTimeStep(ts, dt); PCHKERRQ(ts, ierr);
4309
4310 PetscInt i;
4311 ierr = TSGetStepNumber(ts, &i); PCHKERRQ(ts,ierr);
4312
4313 if (!X) { X = new PetscParVector(PetscObjectComm(obj), *f, false, false); }
4314 X->PlaceMemory(x.GetMemory(),true);
4315
4316 Customize();
4317
4318 // Monitor initial step
4319 if (!i)
4320 {
4321 ierr = TSMonitor(ts, i, t, *X); PCHKERRQ(ts,ierr);
4322 }
4323
4324 // Take the step.
4325 ierr = TSSetSolution(ts, *X); PCHKERRQ(ts, ierr);
4326 ierr = TSStep(ts); PCHKERRQ(ts, ierr);
4327
4328 // Get back current time and the time step used to caller.
4329 // We cannot use TSGetTimeStep() as it returns the next candidate step
4330 PetscReal pt;
4331 ierr = TSGetTime(ts, &pt); PCHKERRQ(ts,ierr);
4332 dt = pt - (PetscReal)t;
4333 t = pt;
4334
4335 // Monitor current step
4336 ierr = TSMonitor(ts, i+1, pt, *X); PCHKERRQ(ts,ierr);
4337
4338 X->ResetMemory();
4339}
4340
4342 mfem::real_t t_final)
4343{
4344 // Give the parameters to PETSc.
4345 TS ts = (TS)obj;
4346 ierr = TSSetTime(ts, t); PCHKERRQ(ts, ierr);
4347 ierr = TSSetTimeStep(ts, dt); PCHKERRQ(ts, ierr);
4348 ierr = TSSetMaxTime(ts, t_final); PCHKERRQ(ts, ierr);
4349 ierr = TSSetExactFinalTime(ts, TS_EXACTFINALTIME_MATCHSTEP);
4350 PCHKERRQ(ts, ierr);
4351
4352 if (!X) { X = new PetscParVector(PetscObjectComm(obj), *f, false, false); }
4353 X->PlaceMemory(x.GetMemory(),true);
4354
4355 Customize();
4356
4357 // Reset Jacobian caching since the user may have changed
4358 // the parameters of the solver
4359 // We don't do this in the Step method because two consecutive
4360 // Step() calls are done with the same operator
4361 __mfem_ts_ctx *ts_ctx = (__mfem_ts_ctx*)private_ctx;
4362 ts_ctx->cached_shift = std::numeric_limits<PetscReal>::min();
4363 ts_ctx->cached_ijacstate = -1;
4364 ts_ctx->cached_rhsjacstate = -1;
4365 ts_ctx->cached_splits_xstate = -1;
4366 ts_ctx->cached_splits_xdotstate = -1;
4367
4368 // Take the steps.
4369 ierr = TSSolve(ts, X->x); PCHKERRQ(ts, ierr);
4370 X->ResetMemory();
4371
4372 // Get back final time and time step to caller.
4373 PetscReal pt;
4374 ierr = TSGetTime(ts, &pt); PCHKERRQ(ts,ierr);
4375 t = pt;
4376 ierr = TSGetTimeStep(ts,&pt); PCHKERRQ(ts,ierr);
4377 dt = pt;
4378}
4379
4380} // namespace mfem
4381
4382#include "petsc/private/petscimpl.h"
4383#include "petsc/private/matimpl.h"
4384
4385// auxiliary functions
4386static PetscErrorCode __mfem_ts_monitor(TS ts, PetscInt it, PetscReal t, Vec x,
4387 void* ctx)
4388{
4389 __mfem_monitor_ctx *monctx = (__mfem_monitor_ctx*)ctx;
4390
4391 PetscFunctionBeginUser;
4392 if (!monctx)
4393 {
4394 SETERRQ(PETSC_COMM_SELF,PETSC_ERR_USER,"Missing monitor context");
4395 }
4396 mfem::PetscSolver *solver = (mfem::PetscSolver*)(monctx->solver);
4398 monctx->monitor);
4399
4400 if (user_monitor->mon_sol)
4401 {
4402 mfem::PetscParVector V(x,true);
4403 user_monitor->MonitorSolution(it,t,V);
4404 }
4405 user_monitor->MonitorSolver(solver);
4406 PetscFunctionReturn(PETSC_SUCCESS);
4407}
4408
4409static PetscErrorCode __mfem_ts_ifunction(TS ts, PetscReal t, Vec x, Vec xp,
4410 Vec f,void *ctx)
4411{
4412 __mfem_ts_ctx* ts_ctx = (__mfem_ts_ctx*)ctx;
4413
4414 PetscFunctionBeginUser;
4415 mfem::PetscParVector xx(x,true);
4416 mfem::PetscParVector yy(xp,true);
4417 mfem::PetscParVector ff(f,true);
4418
4419 mfem::TimeDependentOperator *op = ts_ctx->op;
4420 op->SetTime(t);
4421
4422 if (ts_ctx->bchandler)
4423 {
4424 // we evaluate the ImplicitMult method with the correct bc
4425 // this means the correct time derivative for essential boundary
4426 // dofs is zero
4427 if (!ts_ctx->work) { ts_ctx->work = new mfem::Vector(xx.Size()); }
4428 if (!ts_ctx->work2) { ts_ctx->work2 = new mfem::Vector(xx.Size()); }
4429 mfem::PetscBCHandler *bchandler = ts_ctx->bchandler;
4430 mfem::Vector* txx = ts_ctx->work;
4431 mfem::Vector* txp = ts_ctx->work2;
4432 bchandler->SetTime(t);
4433 bchandler->ApplyBC(xx,*txx);
4434 bchandler->ZeroBC(yy,*txp);
4435 op->ImplicitMult(*txx,*txp,ff);
4436 // and fix the residual (i.e. f_\partial\Omega = u - g(t))
4437 bchandler->FixResidualBC(xx,ff);
4438 }
4439 else
4440 {
4441 // use the ImplicitMult method of the class
4442 op->ImplicitMult(xx,yy,ff);
4443 }
4444 ff.UpdateVecFromFlags();
4445 PetscFunctionReturn(PETSC_SUCCESS);
4446}
4447
4448static PetscErrorCode __mfem_ts_rhsfunction(TS ts, PetscReal t, Vec x, Vec f,
4449 void *ctx)
4450{
4451 __mfem_ts_ctx* ts_ctx = (__mfem_ts_ctx*)ctx;
4452
4453 PetscFunctionBeginUser;
4454 if (ts_ctx->bchandler) { MFEM_ABORT("RHS evaluation with bc not implemented"); } // TODO
4455 mfem::PetscParVector xx(x,true);
4456 mfem::PetscParVector ff(f,true);
4457 mfem::TimeDependentOperator *top = ts_ctx->op;
4458 top->SetTime(t);
4459
4460 // use the ExplicitMult method - compute the RHS function
4461 top->ExplicitMult(xx,ff);
4462
4463 ff.UpdateVecFromFlags();
4464 PetscFunctionReturn(PETSC_SUCCESS);
4465}
4466
4467static PetscErrorCode __mfem_ts_ijacobian(TS ts, PetscReal t, Vec x,
4468 Vec xp, PetscReal shift, Mat A, Mat P,
4469 void *ctx)
4470{
4471 __mfem_ts_ctx* ts_ctx = (__mfem_ts_ctx*)ctx;
4472 mfem::Vector *xx;
4473 PetscScalar *array;
4474 PetscReal eps = 0.001; /* 0.1% difference */
4475 PetscInt n;
4476 PetscObjectState state;
4477 PetscErrorCode ierr;
4478
4479 PetscFunctionBeginUser;
4480 // Matrix-free case
4481 if (A && A != P)
4482 {
4483 ierr = MatAssemblyBegin(A,MAT_FINAL_ASSEMBLY); CHKERRQ(ierr);
4484 ierr = MatAssemblyEnd(A,MAT_FINAL_ASSEMBLY); CHKERRQ(ierr);
4485 }
4486
4487 // prevent to recompute a Jacobian if we already did so
4488 // the relative tolerance comparison should be fine given the fact
4489 // that two consecutive shifts should have similar magnitude
4490 ierr = PetscObjectStateGet((PetscObject)P,&state); CHKERRQ(ierr);
4491 if (ts_ctx->type == mfem::PetscODESolver::ODE_SOLVER_LINEAR &&
4492 std::abs(ts_ctx->cached_shift/shift - 1.0) < eps &&
4493 state == ts_ctx->cached_ijacstate) { PetscFunctionReturn(PETSC_SUCCESS); }
4494
4495 // update time
4496 mfem::TimeDependentOperator *op = ts_ctx->op;
4497 op->SetTime(t);
4498
4499 // wrap Vecs with Vectors
4500 ierr = VecGetLocalSize(x,&n); CHKERRQ(ierr);
4501 ierr = VecGetArrayRead(xp,(const PetscScalar**)&array); CHKERRQ(ierr);
4502 mfem::Vector yy(array,n);
4503 ierr = VecRestoreArrayRead(xp,(const PetscScalar**)&array); CHKERRQ(ierr);
4504 ierr = VecGetArrayRead(x,(const PetscScalar**)&array); CHKERRQ(ierr);
4505 if (!ts_ctx->bchandler)
4506 {
4507 xx = new mfem::Vector(array,n);
4508 }
4509 else
4510 {
4511 // make sure we compute a Jacobian with the correct boundary values
4512 if (!ts_ctx->work) { ts_ctx->work = new mfem::Vector(n); }
4513 mfem::Vector txx(array,n);
4514 mfem::PetscBCHandler *bchandler = ts_ctx->bchandler;
4515 xx = ts_ctx->work;
4516 bchandler->SetTime(t);
4517 bchandler->ApplyBC(txx,*xx);
4518 }
4519 ierr = VecRestoreArrayRead(x,(const PetscScalar**)&array); CHKERRQ(ierr);
4520
4521 // Use TimeDependentOperator::GetImplicitGradient(x,y,s)
4522 mfem::Operator& J = op->GetImplicitGradient(*xx,yy,shift);
4523 if (!ts_ctx->bchandler) { delete xx; }
4524 ts_ctx->cached_shift = shift;
4525
4526 // Convert to the operator type requested if needed
4527 bool delete_pA = false;
4528 mfem::PetscParMatrix *pA = const_cast<mfem::PetscParMatrix *>
4529 (dynamic_cast<const mfem::PetscParMatrix *>(&J));
4530 if (!pA || (ts_ctx->jacType != mfem::Operator::ANY_TYPE &&
4531 pA->GetType() != ts_ctx->jacType))
4532 {
4533 pA = new mfem::PetscParMatrix(PetscObjectComm((PetscObject)ts),&J,
4534 ts_ctx->jacType);
4535 delete_pA = true;
4536 }
4537
4538 // Eliminate essential dofs
4539 if (ts_ctx->bchandler)
4540 {
4541 mfem::PetscBCHandler *bchandler = ts_ctx->bchandler;
4542 mfem::PetscParVector dummy(PetscObjectComm((PetscObject)ts),0);
4543 pA->EliminateRowsCols(bchandler->GetTDofs(),dummy,dummy);
4544 }
4545
4546 // Get nonzerostate
4547 PetscObjectState nonzerostate;
4548 ierr = MatGetNonzeroState(P,&nonzerostate); CHKERRQ(ierr);
4549
4550 // Avoid unneeded copy of the matrix by hacking
4551 Mat B;
4552 B = pA->ReleaseMat(false);
4553 ierr = MatHeaderReplace(P,&B); CHKERRQ(ierr);
4554 if (delete_pA) { delete pA; }
4555
4556 // When using MATNEST and PCFIELDSPLIT, the second setup of the
4557 // preconditioner fails because MatCreateSubMatrix_Nest does not
4558 // actually return a matrix. Instead, for efficiency reasons,
4559 // it returns a reference to the submatrix. The second time it
4560 // is called, MAT_REUSE_MATRIX is used and MatCreateSubMatrix_Nest
4561 // aborts since the two submatrices are actually different.
4562 // We circumvent this issue by incrementing the nonzero state
4563 // (i.e. PETSc thinks the operator sparsity pattern has changed)
4564 // This does not impact performances in the case of MATNEST
4565 PetscBool isnest;
4566 ierr = PetscObjectTypeCompare((PetscObject)P,MATNEST,&isnest);
4567 CHKERRQ(ierr);
4568 if (isnest) { P->nonzerostate = nonzerostate + 1; }
4569
4570 // Jacobian reusage
4571 ierr = PetscObjectStateGet((PetscObject)P,&ts_ctx->cached_ijacstate);
4572 CHKERRQ(ierr);
4573
4574 // Fool DM
4575 DM dm;
4576 MatType mtype;
4577 ierr = MatGetType(P,&mtype); CHKERRQ(ierr);
4578 ierr = TSGetDM(ts,&dm); CHKERRQ(ierr);
4579 ierr = DMSetMatType(dm,mtype); CHKERRQ(ierr);
4580 ierr = DMShellSetMatrix(dm,P); CHKERRQ(ierr);
4581 PetscFunctionReturn(PETSC_SUCCESS);
4582}
4583
4584static PetscErrorCode __mfem_ts_computesplits(TS ts,PetscReal t,Vec x,Vec xp,
4585 Mat Ax,Mat Jx,
4586 Mat Axp,Mat Jxp)
4587{
4588 __mfem_ts_ctx* ts_ctx;
4589 mfem::Vector *xx;
4590 PetscScalar *array;
4591 PetscInt n;
4592 PetscObjectState state;
4593 PetscBool rx = PETSC_TRUE, rxp = PETSC_TRUE;
4594 PetscBool assembled;
4595 PetscErrorCode ierr;
4596
4597 PetscFunctionBeginUser;
4598 // Matrix-free cases
4599 if (Ax && Ax != Jx)
4600 {
4601 ierr = MatAssemblyBegin(Ax,MAT_FINAL_ASSEMBLY); CHKERRQ(ierr);
4602 ierr = MatAssemblyEnd(Ax,MAT_FINAL_ASSEMBLY); CHKERRQ(ierr);
4603 }
4604 if (Axp && Axp != Jxp)
4605 {
4606 ierr = MatAssemblyBegin(Axp,MAT_FINAL_ASSEMBLY); CHKERRQ(ierr);
4607 ierr = MatAssemblyEnd(Axp,MAT_FINAL_ASSEMBLY); CHKERRQ(ierr);
4608 }
4609
4610 ierr = TSGetIJacobian(ts,NULL,NULL,NULL,(void**)&ts_ctx); CHKERRQ(ierr);
4611
4612 // prevent to recompute the Jacobians if we already did so
4613 ierr = PetscObjectStateGet((PetscObject)Jx,&state); CHKERRQ(ierr);
4614 if (ts_ctx->type == mfem::PetscODESolver::ODE_SOLVER_LINEAR &&
4615 state == ts_ctx->cached_splits_xstate) { rx = PETSC_FALSE; }
4616 ierr = PetscObjectStateGet((PetscObject)Jxp,&state); CHKERRQ(ierr);
4617 if (ts_ctx->type == mfem::PetscODESolver::ODE_SOLVER_LINEAR &&
4618 state == ts_ctx->cached_splits_xdotstate) { rxp = PETSC_FALSE; }
4619 if (!rx && !rxp) { PetscFunctionReturn(PETSC_SUCCESS); }
4620
4621 // update time
4622 mfem::TimeDependentOperator *op = ts_ctx->op;
4623 op->SetTime(t);
4624
4625 // wrap Vecs with Vectors
4626 ierr = VecGetLocalSize(x,&n); CHKERRQ(ierr);
4627 ierr = VecGetArrayRead(xp,(const PetscScalar**)&array); CHKERRQ(ierr);
4628 mfem::Vector yy(array,n);
4629 ierr = VecRestoreArrayRead(xp,(const PetscScalar**)&array); CHKERRQ(ierr);
4630 ierr = VecGetArrayRead(x,(const PetscScalar**)&array); CHKERRQ(ierr);
4631 if (!ts_ctx->bchandler)
4632 {
4633 xx = new mfem::Vector(array,n);
4634 }
4635 else
4636 {
4637 // make sure we compute a Jacobian with the correct boundary values
4638 if (!ts_ctx->work) { ts_ctx->work = new mfem::Vector(n); }
4639 mfem::Vector txx(array,n);
4640 mfem::PetscBCHandler *bchandler = ts_ctx->bchandler;
4641 xx = ts_ctx->work;
4642 bchandler->SetTime(t);
4643 bchandler->ApplyBC(txx,*xx);
4644 }
4645 ierr = VecRestoreArrayRead(x,(const PetscScalar**)&array); CHKERRQ(ierr);
4646
4647 // We don't have a specialized interface, so we just compute the split jacobians
4648 // evaluating twice the implicit gradient method with the correct shifts
4649
4650 // first we do the state jacobian
4651 mfem::Operator& oJx = op->GetImplicitGradient(*xx,yy,0.0);
4652
4653 // Convert to the operator type requested if needed
4654 bool delete_mat = false;
4655 mfem::PetscParMatrix *pJx = const_cast<mfem::PetscParMatrix *>
4656 (dynamic_cast<const mfem::PetscParMatrix *>(&oJx));
4657 if (!pJx || (ts_ctx->jacType != mfem::Operator::ANY_TYPE &&
4658 pJx->GetType() != ts_ctx->jacType))
4659 {
4660 if (pJx)
4661 {
4662 Mat B = *pJx;
4663 ierr = PetscObjectReference((PetscObject)B); CHKERRQ(ierr);
4664 }
4665 pJx = new mfem::PetscParMatrix(PetscObjectComm((PetscObject)ts),&oJx,
4666 ts_ctx->jacType);
4667 delete_mat = true;
4668 }
4669 if (rx)
4670 {
4671 ierr = MatAssembled(Jx,&assembled); CHKERRQ(ierr);
4672 if (assembled)
4673 {
4674 ierr = MatCopy(*pJx,Jx,SAME_NONZERO_PATTERN); CHKERRQ(ierr);
4675 }
4676 else
4677 {
4678 Mat B;
4679 ierr = MatDuplicate(*pJx,MAT_COPY_VALUES,&B); CHKERRQ(ierr);
4680 ierr = MatHeaderReplace(Jx,&B); CHKERRQ(ierr);
4681 }
4682 }
4683 if (delete_mat) { delete pJx; }
4684 pJx = new mfem::PetscParMatrix(Jx,true);
4685
4686 // Eliminate essential dofs
4687 if (ts_ctx->bchandler)
4688 {
4689 mfem::PetscBCHandler *bchandler = ts_ctx->bchandler;
4690 mfem::PetscParVector dummy(PetscObjectComm((PetscObject)ts),0);
4691 pJx->EliminateRowsCols(bchandler->GetTDofs(),dummy,dummy);
4692 }
4693
4694 // Then we do the jacobian wrt the time derivative of the state
4695 // Note that this is usually the mass matrix
4696 mfem::PetscParMatrix *pJxp = NULL;
4697 if (rxp)
4698 {
4699 delete_mat = false;
4700 mfem::Operator& oJxp = op->GetImplicitGradient(*xx,yy,1.0);
4701 pJxp = const_cast<mfem::PetscParMatrix *>
4702 (dynamic_cast<const mfem::PetscParMatrix *>(&oJxp));
4703 if (!pJxp || (ts_ctx->jacType != mfem::Operator::ANY_TYPE &&
4704 pJxp->GetType() != ts_ctx->jacType))
4705 {
4706 if (pJxp)
4707 {
4708 Mat B = *pJxp;
4709 ierr = PetscObjectReference((PetscObject)B); CHKERRQ(ierr);
4710 }
4711 pJxp = new mfem::PetscParMatrix(PetscObjectComm((PetscObject)ts),
4712 &oJxp,ts_ctx->jacType);
4713 delete_mat = true;
4714 }
4715
4716 ierr = MatAssembled(Jxp,&assembled); CHKERRQ(ierr);
4717 if (assembled)
4718 {
4719 ierr = MatCopy(*pJxp,Jxp,SAME_NONZERO_PATTERN); CHKERRQ(ierr);
4720 }
4721 else
4722 {
4723 Mat B;
4724 ierr = MatDuplicate(*pJxp,MAT_COPY_VALUES,&B); CHKERRQ(ierr);
4725 ierr = MatHeaderReplace(Jxp,&B); CHKERRQ(ierr);
4726 }
4727 if (delete_mat) { delete pJxp; }
4728 pJxp = new mfem::PetscParMatrix(Jxp,true);
4729
4730 // Eliminate essential dofs
4731 if (ts_ctx->bchandler)
4732 {
4733 mfem::PetscBCHandler *bchandler = ts_ctx->bchandler;
4734 mfem::PetscParVector dummy(PetscObjectComm((PetscObject)ts),0);
4735 pJxp->EliminateRowsCols(bchandler->GetTDofs(),dummy,dummy,2.0);
4736 }
4737
4738 // Obtain the time dependent part of the jacobian by subtracting
4739 // the state jacobian
4740 // We don't do it with the class operator "-=" since we know that
4741 // the sparsity pattern of the two matrices is the same
4742 ierr = MatAXPY(*pJxp,-1.0,*pJx,SAME_NONZERO_PATTERN); PCHKERRQ(ts,ierr);
4743 }
4744
4745 // Jacobian reusage
4746 ierr = PetscObjectStateGet((PetscObject)Jx,&ts_ctx->cached_splits_xstate);
4747 CHKERRQ(ierr);
4748 ierr = PetscObjectStateGet((PetscObject)Jxp,&ts_ctx->cached_splits_xdotstate);
4749 CHKERRQ(ierr);
4750
4751 delete pJx;
4752 delete pJxp;
4753 if (!ts_ctx->bchandler) { delete xx; }
4754 PetscFunctionReturn(PETSC_SUCCESS);
4755}
4756
4757static PetscErrorCode __mfem_ts_rhsjacobian(TS ts, PetscReal t, Vec x,
4758 Mat A, Mat P, void *ctx)
4759{
4760 __mfem_ts_ctx* ts_ctx = (__mfem_ts_ctx*)ctx;
4761 mfem::Vector *xx;
4762 PetscScalar *array;
4763 PetscInt n;
4764 PetscObjectState state;
4765 PetscErrorCode ierr;
4766
4767 PetscFunctionBeginUser;
4768 // Matrix-free case
4769 if (A && A != P)
4770 {
4771 ierr = MatAssemblyBegin(A,MAT_FINAL_ASSEMBLY); CHKERRQ(ierr);
4772 ierr = MatAssemblyEnd(A,MAT_FINAL_ASSEMBLY); CHKERRQ(ierr);
4773 }
4774
4775 // prevent to recompute a Jacobian if we already did so
4776 ierr = PetscObjectStateGet((PetscObject)P,&state); CHKERRQ(ierr);
4777 if (ts_ctx->type == mfem::PetscODESolver::ODE_SOLVER_LINEAR &&
4778 state == ts_ctx->cached_rhsjacstate) { PetscFunctionReturn(PETSC_SUCCESS); }
4779
4780 // update time
4781 mfem::TimeDependentOperator *op = ts_ctx->op;
4782 op->SetTime(t);
4783
4784 // wrap Vec with Vector
4785 ierr = VecGetLocalSize(x,&n); CHKERRQ(ierr);
4786 ierr = VecGetArrayRead(x,(const PetscScalar**)&array); CHKERRQ(ierr);
4787 if (!ts_ctx->bchandler)
4788 {
4789 xx = new mfem::Vector(array,n);
4790 }
4791 else
4792 {
4793 // make sure we compute a Jacobian with the correct boundary values
4794 if (!ts_ctx->work) { ts_ctx->work = new mfem::Vector(n); }
4795 mfem::Vector txx(array,n);
4796 mfem::PetscBCHandler *bchandler = ts_ctx->bchandler;
4797 xx = ts_ctx->work;
4798 bchandler->SetTime(t);
4799 bchandler->ApplyBC(txx,*xx);
4800 }
4801 ierr = VecRestoreArrayRead(x,(const PetscScalar**)&array); CHKERRQ(ierr);
4802
4803 // Use TimeDependentOperator::GetExplicitGradient(x)
4804 mfem::Operator& J = op->GetExplicitGradient(*xx);
4805 if (!ts_ctx->bchandler) { delete xx; }
4806
4807 // Convert to the operator type requested if needed
4808 bool delete_pA = false;
4809 mfem::PetscParMatrix *pA = const_cast<mfem::PetscParMatrix *>
4810 (dynamic_cast<const mfem::PetscParMatrix *>(&J));
4811 if (!pA || (ts_ctx->jacType != mfem::Operator::ANY_TYPE &&
4812 pA->GetType() != ts_ctx->jacType))
4813 {
4814 pA = new mfem::PetscParMatrix(PetscObjectComm((PetscObject)ts),&J,
4815 ts_ctx->jacType);
4816 delete_pA = true;
4817 }
4818
4819 // Eliminate essential dofs
4820 if (ts_ctx->bchandler)
4821 {
4822 mfem::PetscBCHandler *bchandler = ts_ctx->bchandler;
4823 mfem::PetscParVector dummy(PetscObjectComm((PetscObject)ts),0);
4824 pA->EliminateRowsCols(bchandler->GetTDofs(),dummy,dummy);
4825 }
4826
4827 // Get nonzerostate
4828 PetscObjectState nonzerostate;
4829 ierr = MatGetNonzeroState(P,&nonzerostate); CHKERRQ(ierr);
4830
4831 // Avoid unneeded copy of the matrix by hacking
4832 Mat B;
4833 B = pA->ReleaseMat(false);
4834 ierr = MatHeaderReplace(P,&B); CHKERRQ(ierr);
4835 if (delete_pA) { delete pA; }
4836
4837 // When using MATNEST and PCFIELDSPLIT, the second setup of the
4838 // preconditioner fails because MatCreateSubMatrix_Nest does not
4839 // actually return a matrix. Instead, for efficiency reasons,
4840 // it returns a reference to the submatrix. The second time it
4841 // is called, MAT_REUSE_MATRIX is used and MatCreateSubMatrix_Nest
4842 // aborts since the two submatrices are actually different.
4843 // We circumvent this issue by incrementing the nonzero state
4844 // (i.e. PETSc thinks the operator sparsity pattern has changed)
4845 // This does not impact performances in the case of MATNEST
4846 PetscBool isnest;
4847 ierr = PetscObjectTypeCompare((PetscObject)P,MATNEST,&isnest);
4848 CHKERRQ(ierr);
4849 if (isnest) { P->nonzerostate = nonzerostate + 1; }
4850
4851 // Jacobian reusage
4852 if (ts_ctx->type == mfem::PetscODESolver::ODE_SOLVER_LINEAR)
4853 {
4854 ierr = TSRHSJacobianSetReuse(ts,PETSC_TRUE); PCHKERRQ(ts,ierr);
4855 }
4856 ierr = PetscObjectStateGet((PetscObject)P,&ts_ctx->cached_rhsjacstate);
4857 CHKERRQ(ierr);
4858
4859 // Fool DM
4860 DM dm;
4861 MatType mtype;
4862 ierr = MatGetType(P,&mtype); CHKERRQ(ierr);
4863 ierr = TSGetDM(ts,&dm); CHKERRQ(ierr);
4864 ierr = DMSetMatType(dm,mtype); CHKERRQ(ierr);
4865 ierr = DMShellSetMatrix(dm,P); CHKERRQ(ierr);
4866 PetscFunctionReturn(PETSC_SUCCESS);
4867}
4868
4869static PetscErrorCode __mfem_snes_monitor(SNES snes, PetscInt it, PetscReal res,
4870 void* ctx)
4871{
4872 __mfem_monitor_ctx *monctx = (__mfem_monitor_ctx*)ctx;
4873
4874 PetscFunctionBeginUser;
4875 if (!monctx)
4876 {
4877 SETERRQ(PETSC_COMM_SELF,PETSC_ERR_USER,"Missing monitor context");
4878 }
4879
4880 mfem::PetscSolver *solver = (mfem::PetscSolver*)(monctx->solver);
4882 monctx->monitor);
4883 if (user_monitor->mon_sol)
4884 {
4885 Vec x;
4886 PetscErrorCode ierr;
4887
4888 ierr = SNESGetSolution(snes,&x); CHKERRQ(ierr);
4889 mfem::PetscParVector V(x,true);
4890 user_monitor->MonitorSolution(it,res,V);
4891 }
4892 if (user_monitor->mon_res)
4893 {
4894 Vec x;
4895 PetscErrorCode ierr;
4896
4897 ierr = SNESGetFunction(snes,&x,NULL,NULL); CHKERRQ(ierr);
4898 mfem::PetscParVector V(x,true);
4899 user_monitor->MonitorResidual(it,res,V);
4900 }
4901 user_monitor->MonitorSolver(solver);
4902 PetscFunctionReturn(PETSC_SUCCESS);
4903}
4904
4905static PetscErrorCode __mfem_snes_jacobian(SNES snes, Vec x, Mat A, Mat P,
4906 void *ctx)
4907{
4908 PetscScalar *array;
4909 PetscInt n;
4910 PetscErrorCode ierr;
4911 mfem::Vector *xx;
4912 __mfem_snes_ctx *snes_ctx = (__mfem_snes_ctx*)ctx;
4913
4914 PetscFunctionBeginUser;
4915 ierr = VecGetArrayRead(x,(const PetscScalar**)&array); CHKERRQ(ierr);
4916 ierr = VecGetLocalSize(x,&n); CHKERRQ(ierr);
4917 if (!snes_ctx->bchandler)
4918 {
4919 xx = new mfem::Vector(array,n);
4920 }
4921 else
4922 {
4923 // make sure we compute a Jacobian with the correct boundary values
4924 if (!snes_ctx->work) { snes_ctx->work = new mfem::Vector(n); }
4925 mfem::Vector txx(array,n);
4926 mfem::PetscBCHandler *bchandler = snes_ctx->bchandler;
4927 xx = snes_ctx->work;
4928 bchandler->ApplyBC(txx,*xx);
4929 }
4930
4931 // Use Operator::GetGradient(x)
4932 mfem::Operator& J = snes_ctx->op->GetGradient(*xx);
4933 ierr = VecRestoreArrayRead(x,(const PetscScalar**)&array); CHKERRQ(ierr);
4934 if (!snes_ctx->bchandler) { delete xx; }
4935
4936 // Convert to the operator type requested if needed
4937 bool delete_pA = false;
4938 mfem::PetscParMatrix *pA = const_cast<mfem::PetscParMatrix *>
4939 (dynamic_cast<const mfem::PetscParMatrix *>(&J));
4940 if (!pA || (snes_ctx->jacType != mfem::Operator::ANY_TYPE &&
4941 pA->GetType() != snes_ctx->jacType))
4942 {
4943 pA = new mfem::PetscParMatrix(PetscObjectComm((PetscObject)snes),&J,
4944 snes_ctx->jacType);
4945 delete_pA = true;
4946 }
4947
4948 // Eliminate essential dofs
4949 if (snes_ctx->bchandler)
4950 {
4951 mfem::PetscBCHandler *bchandler = snes_ctx->bchandler;
4952 mfem::PetscParVector dummy(PetscObjectComm((PetscObject)snes),0);
4953 pA->EliminateRowsCols(bchandler->GetTDofs(),dummy,dummy);
4954 }
4955
4956 // Get nonzerostate
4957 PetscObjectState nonzerostate;
4958 ierr = MatGetNonzeroState(P,&nonzerostate); CHKERRQ(ierr);
4959
4960 // Avoid unneeded copy of the matrix by hacking
4961 Mat B = pA->ReleaseMat(false);
4962 ierr = MatHeaderReplace(P,&B); CHKERRQ(ierr);
4963 if (delete_pA) { delete pA; }
4964
4965 // When using MATNEST and PCFIELDSPLIT, the second setup of the
4966 // preconditioner fails because MatCreateSubMatrix_Nest does not
4967 // actually return a matrix. Instead, for efficiency reasons,
4968 // it returns a reference to the submatrix. The second time it
4969 // is called, MAT_REUSE_MATRIX is used and MatCreateSubMatrix_Nest
4970 // aborts since the two submatrices are actually different.
4971 // We circumvent this issue by incrementing the nonzero state
4972 // (i.e. PETSc thinks the operator sparsity pattern has changed)
4973 // This does not impact performances in the case of MATNEST
4974 PetscBool isnest;
4975 ierr = PetscObjectTypeCompare((PetscObject)P,MATNEST,&isnest);
4976 CHKERRQ(ierr);
4977 if (isnest) { P->nonzerostate = nonzerostate + 1; }
4978
4979 // Matrix-free case
4980 if (A && A != P)
4981 {
4982 ierr = MatAssemblyBegin(A,MAT_FINAL_ASSEMBLY); CHKERRQ(ierr);
4983 ierr = MatAssemblyEnd(A,MAT_FINAL_ASSEMBLY); CHKERRQ(ierr);
4984 }
4985
4986 // Fool DM
4987 DM dm;
4988 MatType mtype;
4989 ierr = MatGetType(P,&mtype); CHKERRQ(ierr);
4990 ierr = SNESGetDM(snes,&dm); CHKERRQ(ierr);
4991 ierr = DMSetMatType(dm,mtype); CHKERRQ(ierr);
4992 ierr = DMShellSetMatrix(dm,P); CHKERRQ(ierr);
4993 PetscFunctionReturn(PETSC_SUCCESS);
4994}
4995
4996static PetscErrorCode __mfem_snes_function(SNES snes, Vec x, Vec f, void *ctx)
4997{
4998 __mfem_snes_ctx* snes_ctx = (__mfem_snes_ctx*)ctx;
4999
5000 PetscFunctionBeginUser;
5001 mfem::PetscParVector xx(x,true);
5002 mfem::PetscParVector ff(f,true);
5003 if (snes_ctx->bchandler)
5004 {
5005 // we evaluate the Mult method with the correct bc
5006 if (!snes_ctx->work) { snes_ctx->work = new mfem::Vector(xx.Size()); }
5007 mfem::PetscBCHandler *bchandler = snes_ctx->bchandler;
5008 mfem::Vector* txx = snes_ctx->work;
5009 bchandler->ApplyBC(xx,*txx);
5010 snes_ctx->op->Mult(*txx,ff);
5011 // and fix the residual (i.e. f_\partial\Omega = u - g)
5012 bchandler->FixResidualBC(xx,ff);
5013 }
5014 else
5015 {
5016 // use the Mult method of the class
5017 snes_ctx->op->Mult(xx,ff);
5018 }
5019 ff.UpdateVecFromFlags();
5020 PetscFunctionReturn(PETSC_SUCCESS);
5021}
5022
5023static PetscErrorCode __mfem_snes_objective(SNES snes, Vec x, PetscReal *f,
5024 void *ctx)
5025{
5026 __mfem_snes_ctx* snes_ctx = (__mfem_snes_ctx*)ctx;
5027
5028 PetscFunctionBeginUser;
5029 if (!snes_ctx->objective)
5030 {
5031 SETERRQ(PETSC_COMM_SELF,PETSC_ERR_USER,"Missing objective function");
5032 }
5033 mfem::PetscParVector xx(x,true);
5034 mfem::real_t lf;
5035 (*snes_ctx->objective)(snes_ctx->op,xx,&lf);
5036 *f = (PetscReal)lf;
5037 PetscFunctionReturn(PETSC_SUCCESS);
5038}
5039
5040static PetscErrorCode __mfem_snes_postcheck(SNESLineSearch ls,Vec X,Vec Y,Vec W,
5041 PetscBool *cy,PetscBool *cw, void* ctx)
5042{
5043 __mfem_snes_ctx* snes_ctx = (__mfem_snes_ctx*)ctx;
5044 bool lcy = false,lcw = false;
5045
5046 PetscFunctionBeginUser;
5047 mfem::PetscParVector x(X,true);
5048 mfem::PetscParVector y(Y,true);
5049 mfem::PetscParVector w(W,true);
5050 (*snes_ctx->postcheck)(snes_ctx->op,x,y,w,lcy,lcw);
5051 if (lcy) { y.UpdateVecFromFlags(); *cy = PETSC_TRUE; }
5052 if (lcw) { w.UpdateVecFromFlags(); *cw = PETSC_TRUE; }
5053 PetscFunctionReturn(PETSC_SUCCESS);
5054}
5055
5056static PetscErrorCode __mfem_snes_update(SNES snes, PetscInt it)
5057{
5058 Vec F,X,dX,pX;
5059 __mfem_snes_ctx* snes_ctx;
5060
5061 PetscFunctionBeginUser;
5062 /* Update callback does not use the context */
5063 ierr = SNESGetFunction(snes,&F,NULL,(void **)&snes_ctx); CHKERRQ(ierr);
5064 ierr = SNESGetSolution(snes,&X); CHKERRQ(ierr);
5065 if (!it)
5066 {
5067 ierr = VecDuplicate(X,&pX); CHKERRQ(ierr);
5068 ierr = PetscObjectCompose((PetscObject)snes,"_mfem_snes_xp",(PetscObject)pX);
5069 CHKERRQ(ierr);
5070 ierr = VecDestroy(&pX); CHKERRQ(ierr);
5071 }
5072 ierr = PetscObjectQuery((PetscObject)snes,"_mfem_snes_xp",(PetscObject*)&pX);
5073 CHKERRQ(ierr);
5074 if (!pX) SETERRQ(PetscObjectComm((PetscObject)snes),PETSC_ERR_USER,
5075 "Missing previous solution");
5076 ierr = SNESGetSolutionUpdate(snes,&dX); CHKERRQ(ierr);
5077 mfem::PetscParVector f(F,true);
5078 mfem::PetscParVector x(X,true);
5079 mfem::PetscParVector dx(dX,true);
5080 mfem::PetscParVector px(pX,true);
5081 (*snes_ctx->update)(snes_ctx->op,it,f,x,dx,px);
5082 /* Store previous solution */
5083 ierr = VecCopy(X,pX); CHKERRQ(ierr);
5084 PetscFunctionReturn(PETSC_SUCCESS);
5085}
5086
5087static PetscErrorCode __mfem_ksp_monitor(KSP ksp, PetscInt it, PetscReal res,
5088 void* ctx)
5089{
5090 __mfem_monitor_ctx *monctx = (__mfem_monitor_ctx*)ctx;
5091
5092 PetscFunctionBeginUser;
5093 if (!monctx)
5094 {
5095 SETERRQ(PETSC_COMM_SELF,PETSC_ERR_USER,"Missing monitor context");
5096 }
5097
5098 mfem::PetscSolver *solver = (mfem::PetscSolver*)(monctx->solver);
5100 monctx->monitor);
5101 if (user_monitor->mon_sol)
5102 {
5103 Vec x;
5104 PetscErrorCode ierr;
5105
5106 ierr = KSPBuildSolution(ksp,NULL,&x); CHKERRQ(ierr);
5107 mfem::PetscParVector V(x,true);
5108 user_monitor->MonitorSolution(it,res,V);
5109 }
5110 if (user_monitor->mon_res)
5111 {
5112 Vec x;
5113 PetscErrorCode ierr;
5114
5115 ierr = KSPBuildResidual(ksp,NULL,NULL,&x); CHKERRQ(ierr);
5116 mfem::PetscParVector V(x,true);
5117 user_monitor->MonitorResidual(it,res,V);
5118 }
5119 user_monitor->MonitorSolver(solver);
5120 PetscFunctionReturn(PETSC_SUCCESS);
5121}
5122
5123static PetscErrorCode __mfem_mat_shell_apply(Mat A, Vec x, Vec y)
5124{
5125 mfem::Operator *op;
5126 PetscErrorCode ierr;
5127
5128 PetscFunctionBeginUser;
5129 ierr = MatShellGetContext(A,(void **)&op); CHKERRQ(ierr);
5130 if (!op) { SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_LIB,"Missing operator"); }
5131 mfem::PetscParVector xx(x,true);
5132 mfem::PetscParVector yy(y,true);
5133 op->Mult(xx,yy);
5134 yy.UpdateVecFromFlags();
5135 PetscFunctionReturn(PETSC_SUCCESS);
5136}
5137
5138static PetscErrorCode __mfem_mat_shell_apply_transpose(Mat A, Vec x, Vec y)
5139{
5140 mfem::Operator *op;
5141 PetscErrorCode ierr;
5142 PetscBool flg,symm;
5143
5144 PetscFunctionBeginUser;
5145 ierr = MatShellGetContext(A,(void **)&op); CHKERRQ(ierr);
5146 if (!op) { SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_LIB,"Missing operator"); }
5147 mfem::PetscParVector xx(x,true);
5148 mfem::PetscParVector yy(y,true);
5149 ierr = MatIsSymmetricKnown(A,&flg,&symm); CHKERRQ(ierr);
5150 if (flg && symm)
5151 {
5152 op->Mult(xx,yy);
5153 }
5154 else
5155 {
5156 op->MultTranspose(xx,yy);
5157 }
5158 yy.UpdateVecFromFlags();
5159 PetscFunctionReturn(PETSC_SUCCESS);
5160}
5161
5162static PetscErrorCode __mfem_mat_shell_copy(Mat A, Mat B, MatStructure str)
5163{
5164 mfem::Operator *op;
5165 PetscErrorCode ierr;
5166
5167 PetscFunctionBeginUser;
5168 ierr = MatShellGetContext(A,(void **)&op); CHKERRQ(ierr);
5169 if (!op) { SETERRQ(PetscObjectComm((PetscObject)A),PETSC_ERR_LIB,"Missing operator"); }
5170 ierr = MatShellSetContext(B,(void *)op); CHKERRQ(ierr);
5171 PetscFunctionReturn(PETSC_SUCCESS);
5172}
5173
5174static PetscErrorCode __mfem_mat_shell_destroy(Mat A)
5175{
5176 PetscFunctionBeginUser;
5177 PetscFunctionReturn(PETSC_SUCCESS);
5178}
5179
5180static PetscErrorCode __mfem_pc_shell_view(PC pc, PetscViewer viewer)
5181{
5182 __mfem_pc_shell_ctx *ctx;
5183 PetscErrorCode ierr;
5184
5185 PetscFunctionBeginUser;
5186 ierr = PCShellGetContext(pc,(void **)&ctx); CHKERRQ(ierr);
5187 if (ctx->op)
5188 {
5189 PetscBool isascii;
5190 ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&isascii);
5191 CHKERRQ(ierr);
5192
5194 (ctx->op);
5195 if (ppc)
5196 {
5197 ierr = PCView(*ppc,viewer); CHKERRQ(ierr);
5198 }
5199 else
5200 {
5201 if (isascii)
5202 {
5203 ierr = PetscViewerASCIIPrintf(viewer,
5204 "No information available on the mfem::Solver\n");
5205 CHKERRQ(ierr);
5206 }
5207 }
5208 if (isascii && ctx->factory)
5209 {
5210 ierr = PetscViewerASCIIPrintf(viewer,
5211 "Number of preconditioners created by the factory %lu\n",ctx->numprec);
5212 CHKERRQ(ierr);
5213 }
5214 }
5215 PetscFunctionReturn(PETSC_SUCCESS);
5216}
5217
5218static PetscErrorCode __mfem_pc_shell_apply(PC pc, Vec x, Vec y)
5219{
5220 __mfem_pc_shell_ctx *ctx;
5221 PetscErrorCode ierr;
5222
5223 PetscFunctionBeginUser;
5224 mfem::PetscParVector xx(x,true);
5225 mfem::PetscParVector yy(y,true);
5226 ierr = PCShellGetContext(pc,(void **)&ctx); CHKERRQ(ierr);
5227 if (ctx->op)
5228 {
5229 ctx->op->Mult(xx,yy);
5230 yy.UpdateVecFromFlags();
5231 }
5232 else // operator is not present, copy x
5233 {
5234 yy = xx;
5235 }
5236 PetscFunctionReturn(PETSC_SUCCESS);
5237}
5238
5239static PetscErrorCode __mfem_pc_shell_apply_transpose(PC pc, Vec x, Vec y)
5240{
5241 __mfem_pc_shell_ctx *ctx;
5242 PetscErrorCode ierr;
5243
5244 PetscFunctionBeginUser;
5245 mfem::PetscParVector xx(x,true);
5246 mfem::PetscParVector yy(y,true);
5247 ierr = PCShellGetContext(pc,(void **)&ctx); CHKERRQ(ierr);
5248 if (ctx->op)
5249 {
5250 ctx->op->MultTranspose(xx,yy);
5251 yy.UpdateVecFromFlags();
5252 }
5253 else // operator is not present, copy x
5254 {
5255 yy = xx;
5256 }
5257 PetscFunctionReturn(PETSC_SUCCESS);
5258}
5259
5260static PetscErrorCode __mfem_pc_shell_setup(PC pc)
5261{
5262 __mfem_pc_shell_ctx *ctx;
5263
5264 PetscFunctionBeginUser;
5265 ierr = PCShellGetContext(pc,(void **)&ctx); CHKERRQ(ierr);
5266 if (ctx->factory)
5267 {
5268 // Delete any owned operator
5269 if (ctx->ownsop)
5270 {
5271 delete ctx->op;
5272 }
5273
5274 // Get current preconditioning Mat
5275 Mat B;
5276 ierr = PCGetOperators(pc,NULL,&B); CHKERRQ(ierr);
5277
5278 // Call user-defined setup
5279 mfem::OperatorHandle hB(new mfem::PetscParMatrix(B,true),true);
5280 mfem::PetscPreconditionerFactory *factory = ctx->factory;
5281 ctx->op = factory->NewPreconditioner(hB);
5282 ctx->ownsop = true;
5283 ctx->numprec++;
5284 }
5285 PetscFunctionReturn(PETSC_SUCCESS);
5286}
5287
5288static PetscErrorCode __mfem_pc_shell_destroy(PC pc)
5289{
5290 __mfem_pc_shell_ctx *ctx;
5291 PetscErrorCode ierr;
5292
5293 PetscFunctionBeginUser;
5294 ierr = PCShellGetContext(pc,(void **)&ctx); CHKERRQ(ierr);
5295 if (ctx->ownsop)
5296 {
5297 delete ctx->op;
5298 }
5299 delete ctx;
5300 PetscFunctionReturn(PETSC_SUCCESS);
5301}
5302
5303static PetscErrorCode __mfem_array_container_destroy(PetscCtxRt ptr)
5304{
5305 PetscErrorCode ierr;
5306
5307 PetscFunctionBeginUser;
5308#if PETSC_VERSION_LT(3,23,0)
5309 ierr = PetscFree(ptr); CHKERRQ(ierr);
5310#else
5311 ierr = PetscFree(*(void**)ptr); CHKERRQ(ierr);
5312#endif
5313 PetscFunctionReturn(PETSC_SUCCESS);
5314}
5315
5316static PetscErrorCode __mfem_matarray_container_destroy(PetscCtxRt ptr)
5317{
5318#if PETSC_VERSION_LT(3,23,0)
5320#else
5322#endif
5323 PetscErrorCode ierr;
5324
5325 PetscFunctionBeginUser;
5326 for (int i=0; i<a->Size(); i++)
5327 {
5328 Mat M = (*a)[i];
5329 MPI_Comm comm = PetscObjectComm((PetscObject)M);
5330 ierr = MatDestroy(&M); CCHKERRQ(comm,ierr);
5331 }
5332 delete a;
5333 PetscFunctionReturn(PETSC_SUCCESS);
5334}
5335
5336#if PETSC_VERSION_LT(3,23,0)
5337static PetscErrorCode __mfem_monitor_ctx_destroy(void **ctx)
5338#else
5339static PetscErrorCode __mfem_monitor_ctx_destroy(PetscCtxRt ctx)
5340#endif
5341{
5342 PetscErrorCode ierr;
5343
5344 PetscFunctionBeginUser;
5345 ierr = PetscFree(*(void**)ctx); CHKERRQ(ierr);
5346 PetscFunctionReturn(PETSC_SUCCESS);
5347}
5348
5349// Sets the type of PC to PCSHELL and wraps the solver action
5350// if ownsop is true, ownership of precond is transferred to the PETSc object
5351PetscErrorCode MakeShellPC(PC pc, mfem::Solver &precond, bool ownsop)
5352{
5353 PetscFunctionBeginUser;
5354 __mfem_pc_shell_ctx *ctx = new __mfem_pc_shell_ctx;
5355 ctx->op = &precond;
5356 ctx->ownsop = ownsop;
5357 ctx->factory = NULL;
5358 ctx->numprec = 0;
5359
5360 // In case the PC was already of type SHELL, this will destroy any
5361 // previous user-defined data structure
5362 // We cannot call PCReset as it will wipe out any operator already set
5363 ierr = PCSetType(pc,PCNONE); CHKERRQ(ierr);
5364
5365 ierr = PCSetType(pc,PCSHELL); CHKERRQ(ierr);
5366 ierr = PCShellSetName(pc,"MFEM Solver (unknown Pmat)"); CHKERRQ(ierr);
5367 ierr = PCShellSetContext(pc,(void *)ctx); CHKERRQ(ierr);
5368 ierr = PCShellSetApply(pc,__mfem_pc_shell_apply); CHKERRQ(ierr);
5369 ierr = PCShellSetApplyTranspose(pc,__mfem_pc_shell_apply_transpose);
5370 CHKERRQ(ierr);
5371 ierr = PCShellSetSetUp(pc,__mfem_pc_shell_setup); CHKERRQ(ierr);
5372 ierr = PCShellSetView(pc,__mfem_pc_shell_view); CHKERRQ(ierr);
5373 ierr = PCShellSetDestroy(pc,__mfem_pc_shell_destroy); CHKERRQ(ierr);
5374 PetscFunctionReturn(PETSC_SUCCESS);
5375}
5376
5377// Sets the type of PC to PCSHELL. Uses a PetscPreconditionerFactory to construct the solver
5378// Takes ownership of the solver created by the factory
5379PetscErrorCode MakeShellPCWithFactory(PC pc,
5381{
5382 PetscFunctionBeginUser;
5383 __mfem_pc_shell_ctx *ctx = new __mfem_pc_shell_ctx;
5384 ctx->op = NULL;
5385 ctx->ownsop = true;
5386 ctx->factory = factory;
5387 ctx->numprec = 0;
5388
5389 // In case the PC was already of type SHELL, this will destroy any
5390 // previous user-defined data structure
5391 // We cannot call PCReset as it will wipe out any operator already set
5392 ierr = PCSetType(pc,PCNONE); CHKERRQ(ierr);
5393
5394 ierr = PCSetType(pc,PCSHELL); CHKERRQ(ierr);
5395 ierr = PCShellSetName(pc,factory->GetName()); CHKERRQ(ierr);
5396 ierr = PCShellSetContext(pc,(void *)ctx); CHKERRQ(ierr);
5397 ierr = PCShellSetApply(pc,__mfem_pc_shell_apply); CHKERRQ(ierr);
5398 ierr = PCShellSetApplyTranspose(pc,__mfem_pc_shell_apply_transpose);
5399 CHKERRQ(ierr);
5400 ierr = PCShellSetSetUp(pc,__mfem_pc_shell_setup); CHKERRQ(ierr);
5401 ierr = PCShellSetView(pc,__mfem_pc_shell_view); CHKERRQ(ierr);
5402 ierr = PCShellSetDestroy(pc,__mfem_pc_shell_destroy); CHKERRQ(ierr);
5403 PetscFunctionReturn(PETSC_SUCCESS);
5404}
5405
5406// Converts from a list (or a marked Array if islist is false) to an IS
5407// st indicates the offset where to start numbering
5408static PetscErrorCode Convert_Array_IS(MPI_Comm comm, bool islist,
5409 const mfem::Array<int> *list,
5410 PetscInt st, IS* is)
5411{
5412 PetscInt n = list ? list->Size() : 0,*idxs;
5413 const int *data = list ? list->GetData() : NULL;
5414 PetscErrorCode ierr;
5415
5416 PetscFunctionBeginUser;
5417 ierr = PetscMalloc1(n,&idxs); CHKERRQ(ierr);
5418 if (islist)
5419 {
5420 for (PetscInt i=0; i<n; i++) { idxs[i] = data[i] + st; }
5421 }
5422 else
5423 {
5424 PetscInt cum = 0;
5425 for (PetscInt i=0; i<n; i++)
5426 {
5427 if (data[i]) { idxs[cum++] = i+st; }
5428 }
5429 n = cum;
5430 }
5431 ierr = ISCreateGeneral(comm,n,idxs,PETSC_OWN_POINTER,is);
5432 CHKERRQ(ierr);
5433 PetscFunctionReturn(PETSC_SUCCESS);
5434}
5435
5436// Converts from a marked Array of Vdofs to an IS
5437// st indicates the offset where to start numbering
5438// l2l is a vector of matrices generated during RAP
5439static PetscErrorCode Convert_Vmarks_IS(MPI_Comm comm,
5440 mfem::Array<Mat> &pl2l,
5441 const mfem::Array<int> *mark,
5442 PetscInt st, IS* is)
5443{
5444 mfem::Array<int> sub_dof_marker;
5446 PetscInt nl;
5447 PetscErrorCode ierr;
5448
5449 PetscFunctionBeginUser;
5450 for (int i = 0; i < pl2l.Size(); i++)
5451 {
5452 PetscInt m,n,*ii,*jj;
5453 PetscBool done;
5454 ierr = MatGetRowIJ(pl2l[i],0,PETSC_FALSE,PETSC_FALSE,&m,(const PetscInt**)&ii,
5455 (const PetscInt**)&jj,&done); CHKERRQ(ierr);
5456 MFEM_VERIFY(done,"Unable to perform MatGetRowIJ on " << i << " l2l matrix");
5457 ierr = MatGetSize(pl2l[i],NULL,&n); CHKERRQ(ierr);
5458#if defined(PETSC_USE_64BIT_INDICES)
5459 int nnz = (int)ii[m];
5460 int *mii = new int[m+1];
5461 int *mjj = new int[nnz];
5462 for (int j = 0; j < m+1; j++) { mii[j] = (int)ii[j]; }
5463 for (int j = 0; j < nnz; j++) { mjj[j] = (int)jj[j]; }
5464 l2l[i] = new mfem::SparseMatrix(mii,mjj,NULL,m,n,true,true,true);
5465#else
5466 l2l[i] = new mfem::SparseMatrix(ii,jj,NULL,m,n,false,true,true);
5467#endif
5468 ierr = MatRestoreRowIJ(pl2l[i],0,PETSC_FALSE,PETSC_FALSE,&m,
5469 (const PetscInt**)&ii,
5470 (const PetscInt**)&jj,&done); CHKERRQ(ierr);
5471 MFEM_VERIFY(done,"Unable to perform MatRestoreRowIJ on "
5472 << i << " l2l matrix");
5473 }
5474 nl = 0;
5475 for (int i = 0; i < l2l.Size(); i++) { nl += l2l[i]->Width(); }
5476 sub_dof_marker.SetSize(nl);
5477 const int* vdata = mark->GetData();
5478 int* sdata = sub_dof_marker.GetData();
5479 int cumh = 0, cumw = 0;
5480 for (int i = 0; i < l2l.Size(); i++)
5481 {
5482 const mfem::Array<int> vf_marker(const_cast<int*>(vdata)+cumh,
5483 l2l[i]->Height());
5484 mfem::Array<int> sf_marker(sdata+cumw,l2l[i]->Width());
5485 l2l[i]->BooleanMultTranspose(vf_marker,sf_marker);
5486 cumh += l2l[i]->Height();
5487 cumw += l2l[i]->Width();
5488 }
5489 ierr = Convert_Array_IS(comm,false,&sub_dof_marker,st,is); CCHKERRQ(comm,ierr);
5490 for (int i = 0; i < pl2l.Size(); i++)
5491 {
5492 delete l2l[i];
5493 }
5494 PetscFunctionReturn(PETSC_SUCCESS);
5495}
5496
5497#include <petsc/private/matimpl.h>
5498
5499static PetscErrorCode __mfem_MatCreateDummy(MPI_Comm comm, PetscInt m,
5500 PetscInt n, Mat *A)
5501{
5502 PetscFunctionBegin;
5503 ierr = MatCreate(comm,A); CHKERRQ(ierr);
5504 ierr = MatSetSizes(*A,m,n,PETSC_DECIDE,PETSC_DECIDE); CHKERRQ(ierr);
5505 ierr = PetscObjectChangeTypeName((PetscObject)*A,"mfemdummy"); CHKERRQ(ierr);
5506 (*A)->preallocated = PETSC_TRUE;
5507 ierr = MatSetUp(*A); CHKERRQ(ierr);
5508 PetscFunctionReturn(PETSC_SUCCESS);
5509}
5510
5511#include <petsc/private/vecimpl.h>
5512
5513#if defined(PETSC_HAVE_DEVICE)
5514static PetscErrorCode __mfem_VecSetOffloadMask(Vec v, PetscOffloadMask m)
5515{
5516 PetscFunctionBegin;
5517 v->offloadmask = m;
5518 PetscFunctionReturn(PETSC_SUCCESS);
5519}
5520#endif
5521
5522static PetscErrorCode __mfem_VecBoundToCPU(Vec v, PetscBool *flg)
5523{
5524 PetscFunctionBegin;
5525#if defined(PETSC_HAVE_DEVICE)
5526 *flg = v->boundtocpu;
5527#else
5528 *flg = PETSC_TRUE;
5529#endif
5530 PetscFunctionReturn(PETSC_SUCCESS);
5531}
5532
5533static PetscErrorCode __mfem_PetscObjectStateIncrease(PetscObject o)
5534{
5535 PetscErrorCode ierr;
5536
5537 PetscFunctionBegin;
5538 ierr = PetscObjectStateIncrease(o); CHKERRQ(ierr);
5539 PetscFunctionReturn(PETSC_SUCCESS);
5540}
5541
5542#endif // MFEM_USE_PETSC
5543#endif // MFEM_USE_MPI
void Assign(const T *)
Copy data from a pointer. 'Size()' elements are copied.
Definition array.hpp:1149
void SetSize(int nsize)
Change the logical size of the array, keep existing entries.
Definition array.hpp:869
int Size() const
Return the logical size of the array.
Definition array.hpp:192
T * GetData()
Returns the data.
Definition array.hpp:159
A class to handle Block systems in a matrix-free implementation.
int IsZeroBlock(int i, int j) const
Check if block (i,j) is a zero block.
Operator & GetBlock(int i, int j)
Return a reference to block i,j.
int NumRowBlocks() const
Return the number of row blocks.
int NumColBlocks() const
Return the number of column blocks.
static bool Allows(unsigned long b_mask)
Return true if any of the backends in the backend mask, b_mask, are allowed.
Definition device.hpp:271
static int GetId()
Get the device ID of the configured device.
Definition device.hpp:258
static MemoryType GetDeviceMemoryType()
Get the current Device MemoryType. This is the MemoryType used by most MFEM classes when allocating m...
Definition device.hpp:298
Collection of finite elements from the same family in multiple dimensions. This class is used to matc...
Definition fe_coll.hpp:27
Ordering::Type GetOrdering() const
Return the ordering method.
Definition fespace.hpp:852
const FiniteElementCollection * FEColl() const
Definition fespace.hpp:854
int GetVDim() const
Returns the vector dimension of the finite element space.
Definition fespace.hpp:817
Wrapper for hypre's ParCSR matrix class.
Definition hypre.hpp:419
MPI_Comm GetComm() const
MPI communicator.
Definition hypre.hpp:610
Wrapper for hypre's parallel vector class.
Definition hypre.hpp:230
Identity Operator I: x -> x.
Definition operator.hpp:878
Class used by MFEM to store pointers to host and/or device memory.
bool DeviceIsValid() const
Return true if device pointer is valid.
void CopyFromHost(const T *src, int size)
Copy size entries from the host pointer src to *this.
void MakeAlias(const Memory &base, int offset, int size)
Create a memory object that points inside the memory object base.
bool HostIsValid() const
Return true if host pointer is valid.
bool UseDevice() const
Read the internal device flag.
void CopyToHost(T *dest, int size) const
Copy size entries from *this to the host pointer dest.
bool Empty() const
Return true if the Memory object is empty, see Reset().
void Sync(const Memory &other) const
Copy the host/device pointer validity flags from other to *this.
void CopyFrom(const Memory &src, int size)
Copy size entries from src to *this.
void Reset()
Reset the memory to be empty, ensuring that Delete() will be a no-op.
void Wrap(T *ptr, int size, bool own)
Wrap an externally allocated host pointer, ptr with the current host memory type returned by MemoryMa...
void Delete()
Delete the owned pointers and reset the Memory object.
int SpaceDimension() const
Dimension of the physical space containing the mesh.
Definition mesh.hpp:1317
Abstract class for solving systems of ODEs: dx/dt = f(x,t)
Definition ode.hpp:121
TimeDependentOperator * f
Pointer to the associated TimeDependentOperator.
Definition ode.hpp:125
Pointer to an Operator of a specified type.
Definition handle.hpp:34
Abstract operator.
Definition operator.hpp:27
virtual MemoryClass GetMemoryClass() const
Return the MemoryClass preferred by the Operator.
Definition operator.hpp:88
int width
Dimension of the input / number of columns in the matrix.
Definition operator.hpp:30
int Height() const
Get the height (size of output) of the Operator. Synonym with NumRows().
Definition operator.hpp:68
int height
Dimension of the output / number of rows in the matrix.
Definition operator.hpp:29
virtual void Mult(const Vector &x, Vector &y) const =0
Operator application: y=A(x).
int Width() const
Get the width (size of input) of the Operator. Synonym with NumCols().
Definition operator.hpp:74
Type
Enumeration defining IDs for some classes derived from Operator.
Definition operator.hpp:319
@ ANY_TYPE
ID for the base class Operator, i.e. any type.
Definition operator.hpp:320
@ PETSC_MATIS
ID for class PetscParMatrix, MATIS format.
Definition operator.hpp:324
@ PETSC_MATHYPRE
ID for class PetscParMatrix, MATHYPRE format.
Definition operator.hpp:327
@ PETSC_MATGENERIC
ID for class PetscParMatrix, unspecified format.
Definition operator.hpp:328
@ PETSC_MATAIJ
ID for class PetscParMatrix, MATAIJ format.
Definition operator.hpp:323
@ PETSC_MATNEST
ID for class PetscParMatrix, MATNEST format.
Definition operator.hpp:326
@ PETSC_MATSHELL
ID for class PetscParMatrix, MATSHELL format.
Definition operator.hpp:325
virtual void MultTranspose(const Vector &x, Vector &y) const
Action of the transpose operator: y=A^t(x). The default behavior in class Operator is to generate an ...
Definition operator.hpp:102
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:150
Abstract parallel finite element space.
Definition pfespace.hpp:31
MPI_Comm GetComm() const
Definition pfespace.hpp:337
HYPRE_BigInt * GetTrueDofOffsets() const
Definition pfespace.hpp:358
int GetTrueVSize() const override
Return the number of local vector true dofs.
Definition pfespace.hpp:365
ParMesh * GetParMesh() const
Definition pfespace.hpp:341
Helper class for handling essential boundary conditions.
Definition petsc.hpp:595
PetscBCHandler(Type type_=ZERO)
Definition petsc.hpp:604
@ CONSTANT
Constant in time b.c.
Definition petsc.hpp:600
void SetTDofs(Array< int > &list)
Sets essential dofs (local, per-process numbering)
Definition petsc.cpp:2805
virtual void Eval(real_t t, Vector &g)
Boundary conditions evaluation.
Definition petsc.hpp:620
void SetTime(real_t t)
Sets the current time.
Definition petsc.hpp:630
void SetUp(PetscInt n)
SetUp the helper object, where n is the size of the solution vector.
Definition petsc.cpp:2812
void ZeroBC(const Vector &x, Vector &y)
y = x on ess_tdof_list_c and y = 0 on ess_tdof_list
Definition petsc.cpp:2905
Array< int > & GetTDofs()
Gets essential dofs (local, per-process numbering)
Definition petsc.hpp:627
void FixResidualBC(const Vector &x, Vector &y)
y = x-g on ess_tdof_list, the rest of y is unchanged
Definition petsc.cpp:2877
void ApplyBC(const Vector &x, Vector &y)
y = x on ess_tdof_list_c and y = g (internally evaluated) on ess_tdof_list
Definition petsc.cpp:2828
void Zero(Vector &x)
Replace boundary dofs with 0.
Definition petsc.cpp:2896
Auxiliary class for BDDC customization.
Definition petsc.hpp:834
PetscBDDCSolver(MPI_Comm comm, Operator &op, const PetscBDDCSolverParams &opts=PetscBDDCSolverParams(), const std::string &prefix=std::string())
Definition petsc.cpp:3880
PetscFieldSplitSolver(MPI_Comm comm, Operator &op, const std::string &prefix=std::string())
Definition petsc.cpp:3889
PetscH2Solver(Operator &op, ParFiniteElementSpace *fes, const std::string &prefix=std::string())
Definition petsc.cpp:3924
Abstract class for PETSc's linear solvers.
Definition petsc.hpp:753
void SetOperator(const Operator &op) override
Definition petsc.cpp:2958
operator petsc::KSP() const
Conversion function to PETSc's KSP type.
Definition petsc.hpp:790
virtual ~PetscLinearSolver()
Definition petsc.cpp:3193
void MultTranspose(const Vector &b, Vector &x) const override
Action of the transpose operator: y=A^t(x). The default behavior in class Operator is to generate an ...
Definition petsc.cpp:3188
PetscLinearSolver(MPI_Comm comm, const std::string &prefix=std::string(), bool wrap=true, bool iter_mode=false)
Definition petsc.cpp:2917
void SetPreconditioner(Solver &precond)
Definition petsc.cpp:3103
void Mult(const Vector &b, Vector &x) const override
Application of the solver.
Definition petsc.cpp:3183
bool DeviceRequested() const
Definition petsc.hpp:146
void SetHostInvalid() const
Definition petsc.hpp:101
void SetHostValid() const
Definition petsc.hpp:99
bool WriteRequested() const
Definition petsc.hpp:141
const real_t * GetDevicePointer() const
Definition petsc.cpp:262
const real_t * GetHostPointer() const
Definition petsc.cpp:253
void SyncBaseAndReset()
Definition petsc.hpp:130
bool IsAliasForSync() const
Definition petsc.hpp:103
void MakeAliasForSync(const Memory< real_t > &base_, int offset_, int size_, bool usedev_)
Definition petsc.hpp:105
void SetDeviceInvalid() const
Definition petsc.hpp:102
bool ReadRequested() const
Definition petsc.hpp:136
void SetDeviceValid() const
Definition petsc.hpp:100
void Mult(const Vector &b, Vector &x) const override
Application of the solver.
Definition petsc.cpp:4123
void SetPostCheck(void(*post)(Operator *op, const Vector &X, Vector &Y, Vector &W, bool &changed_y, bool &changed_w))
Definition petsc.cpp:4096
void SetObjective(void(*obj)(Operator *op, const Vector &x, real_t *f))
Specification of an objective function to be used for line search.
Definition petsc.cpp:4085
operator petsc::SNES() const
Conversion function to PETSc's SNES type.
Definition petsc.hpp:947
virtual ~PetscNonlinearSolver()
Definition petsc.cpp:4004
void SetJacobianType(Operator::Type type)
Definition petsc.cpp:4079
void SetUpdate(void(*update)(Operator *op, int it, const Vector &F, const Vector &X, const Vector &D, const Vector &P))
Definition petsc.cpp:4110
PetscNonlinearSolver(MPI_Comm comm, const std::string &prefix=std::string())
Definition petsc.cpp:3972
void SetOperator(const Operator &op) override
Specification of the nonlinear operator.
Definition petsc.cpp:4012
virtual void Init(TimeDependentOperator &f_, enum PetscODESolver::Type type)
Initialize the ODE solver.
Definition petsc.cpp:4190
virtual void Run(Vector &x, real_t &t, real_t &dt, real_t t_final)
Perform time integration from time t [in] to time tf [in].
Definition petsc.cpp:4341
virtual void Step(Vector &x, real_t &t, real_t &dt)
Perform a time step from time t [in] to time t [out] based on the requested step size dt [in].
Definition petsc.cpp:4303
operator petsc::TS() const
Conversion function to PETSc's TS type.
Definition petsc.hpp:982
void SetType(PetscODESolver::Type)
Definition petsc.cpp:4285
PetscODESolver::Type GetType() const
Definition petsc.cpp:4279
PetscODESolver(MPI_Comm comm, const std::string &prefix=std::string())
Definition petsc.cpp:4157
void SetJacobianType(Operator::Type type)
Definition petsc.cpp:4273
virtual ~PetscODESolver()
Definition petsc.cpp:4182
PetscPCGSolver(MPI_Comm comm, const std::string &prefix=std::string(), bool iter_mode=false)
Definition petsc.cpp:3203
Wrapper for PETSc's matrix class.
Definition petsc.hpp:322
void Print(const char *fname=NULL, bool binary=false) const
Prints the matrix (to stdout if fname is NULL)
Definition petsc.cpp:2027
PetscInt GetNumRows() const
Returns the local number of rows.
Definition petsc.cpp:997
void ScaleCols(const Vector &s)
Scale the local col i by s(i).
Definition petsc.cpp:2063
void MakeRef(const PetscParMatrix &master)
Makes this object a reference to another PetscParMatrix.
Definition petsc.cpp:1941
void EliminateRows(const Array< int > &rows)
Eliminate only the rows from the matrix.
Definition petsc.cpp:2278
void ConvertOperator(MPI_Comm comm, const Operator &op, petsc::Mat *B, Operator::Type tid)
Definition petsc.cpp:1396
PetscParMatrix & operator-=(const PetscParMatrix &B)
Definition petsc.cpp:1181
void Mult(real_t a, const Vector &x, real_t b, Vector &y) const
Matvec: y = a A x + b y.
Definition petsc.cpp:1990
PetscInt GetColStart() const
Returns the global index of the first local column.
Definition petsc.cpp:990
PetscInt M() const
Returns the global number of rows.
Definition petsc.cpp:1011
void EliminateRowsCols(const Array< int > &rows_cols, const PetscParVector &X, PetscParVector &B, real_t diag=1.)
Eliminate rows and columns from the matrix, and rows from the vector B. Modify B with the BC values i...
Definition petsc.cpp:2249
PetscParVector * GetY() const
Returns the inner vector in the range of A (it creates it if needed)
Definition petsc.cpp:1961
MPI_Comm GetComm() const
Get the associated MPI communicator.
Definition petsc.cpp:1335
Type GetType() const
Definition petsc.cpp:2305
PetscParMatrix & operator=(const PetscParMatrix &B)
Definition petsc.cpp:1150
petsc::Mat ReleaseMat(bool dereference)
Release the PETSc Mat object. If dereference is true, decrement the refcount of the Mat object.
Definition petsc.cpp:2292
void MakeWrapper(MPI_Comm comm, const Operator *op, petsc::Mat *B)
Creates a wrapper around a mfem::Operator op using PETSc's MATSHELL object and returns the Mat in B.
Definition petsc.cpp:1348
PetscInt GetNumCols() const
Returns the local number of columns.
Definition petsc.cpp:1004
PetscInt NNZ() const
Returns the number of nonzeros.
Definition petsc.cpp:1025
petsc::Mat A
The actual PETSc object.
Definition petsc.hpp:325
PetscParVector * GetX() const
Returns the inner vector in the domain of A (it creates it if needed)
Definition petsc.cpp:1951
void Shift(real_t s)
Shift diagonal by a constant.
Definition petsc.cpp:2074
PetscParVector * Y
Definition petsc.hpp:328
PetscParVector * X
Auxiliary vectors for typecasting.
Definition petsc.hpp:328
PetscParMatrix()
Create an empty matrix to be used as a reference to an existing matrix.
Definition petsc.cpp:1045
operator petsc::Mat() const
Typecasting to PETSc's Mat type.
Definition petsc.hpp:468
void SetMat(petsc::Mat newA)
Replace the inner Mat Object. The reference count of newA is increased.
Definition petsc.cpp:1806
void operator*=(real_t s)
Scale all entries by s: A_scaled = s*A.
Definition petsc.cpp:1985
void SetBlockSize(PetscInt rbs, PetscInt cbs=-1)
Set row and column block sizes of a matrix.
Definition petsc.cpp:1032
PetscInt N() const
Returns the global number of columns.
Definition petsc.cpp:1018
PetscParMatrix * Transpose(bool action=false)
Returns the transpose of the PetscParMatrix.
Definition petsc.cpp:1971
void Init()
Initialize with defaults. Does not initialize inherited members.
Definition petsc.cpp:1038
void Destroy()
Delete all owned data. Does not perform re-initialization with defaults.
Definition petsc.cpp:1781
PetscInt GetRowStart() const
Returns the global index of the first local row.
Definition petsc.cpp:983
void MultTranspose(real_t a, const Vector &x, real_t b, Vector &y) const
Matvec transpose: y = a A^T x + b y.
Definition petsc.cpp:2008
PetscParMatrix & operator+=(const PetscParMatrix &B)
Definition petsc.cpp:1166
void ScaleRows(const Vector &s)
Scale the local row i by s(i).
Definition petsc.cpp:2052
void ResetMemory()
Completes the operation started with PlaceMemory.
Definition petsc.cpp:897
void SetFlagsFromMask_() const
Definition petsc.cpp:329
void PlaceMemory(Memory< real_t > &, bool=false)
This requests write access from where the memory is valid and temporarily replaces the corresponding ...
Definition petsc.cpp:810
void Randomize(PetscInt seed=0)
Set random values.
Definition petsc.cpp:941
void SetBlockSize(PetscInt bs)
Set block size of a vector.
Definition petsc.cpp:530
bool UseDevice() const override
Return the device flag of the Memory object used by the Vector.
Definition petsc.cpp:515
real_t * HostReadWrite() override
Shortcut for mfem::ReadWrite(vec.GetMemory(), vec.Size(), false).
Definition petsc.cpp:501
PetscMemory pdata
Definition petsc.hpp:165
void PlaceArray(PetscScalar *temp_data)
Temporarily replace the data of the PETSc Vec object. To return to the original data array,...
Definition petsc.cpp:800
PetscInt GlobalSize() const
Returns the global number of rows.
Definition petsc.cpp:523
PetscParVector & operator-=(const PetscParVector &y)
Definition petsc.cpp:779
real_t * Write(bool=true) override
Shortcut for mfem::Write(vec.GetMemory(), vec.Size(), on_dev).
Definition petsc.cpp:446
void UpdateVecFromFlags()
Update PETSc's Vec after having accessed its data via GetMemory()
Definition petsc.cpp:363
void Print(const char *fname=NULL, bool binary=false) const
Prints the vector (to stdout if fname is NULL)
Definition petsc.cpp:956
real_t * ReadWrite(bool=true) override
Shortcut for mfem::ReadWrite(vec.GetMemory(), vec.Size(), on_dev).
Definition petsc.cpp:476
const real_t * HostRead() const override
Shortcut for mfem::Read(vec.GetMemory(), vec.Size(), false).
Definition petsc.cpp:441
const real_t * Read(bool=true) const override
Shortcut for mfem::Read(vec.GetMemory(), vec.Size(), on_dev).
Definition petsc.cpp:417
real_t * HostWrite() override
Shortcut for mfem::Write(vec.GetMemory(), vec.Size(), false).
Definition petsc.cpp:471
PetscParVector & operator+=(const PetscParVector &y)
Definition petsc.cpp:772
petsc::Vec x
The actual PETSc object.
Definition petsc.hpp:163
MPI_Comm GetComm() const
Get the associated MPI communicator.
Definition petsc.cpp:700
virtual ~PetscParVector()
Calls PETSc's destroy function.
Definition petsc.cpp:602
void ResetArray()
Reset the PETSc Vec object to use its default data. Call this method after the use of PlaceArray().
Definition petsc.cpp:805
Vector * GlobalVector() const
Returns the global vector in each processor.
Definition petsc.cpp:705
operator petsc::Vec() const
Typecasting to PETSc's Vec type.
Definition petsc.hpp:237
PetscParVector & AddValues(const Array< PetscInt > &, const Array< PetscScalar > &)
Add values in a vector.
Definition petsc.cpp:751
PetscParVector(MPI_Comm comm, PetscInt glob_size, PetscInt *col=NULL)
Creates vector with given global size and partitioning of the columns.
Definition petsc.cpp:584
PetscParVector & SetValues(const Array< PetscInt > &, const Array< PetscScalar > &)
Set values in a vector.
Definition petsc.cpp:737
PetscParVector & operator*=(PetscScalar d)
Definition petsc.cpp:786
PetscParVector & operator=(PetscScalar d)
Set constant values.
Definition petsc.cpp:730
virtual Solver * NewPreconditioner(const OperatorHandle &oh)=0
Abstract class for PETSc's preconditioners.
Definition petsc.hpp:808
void Mult(const Vector &b, Vector &x) const override
Application of the preconditioner.
Definition petsc.cpp:3356
virtual ~PetscPreconditioner()
Definition petsc.cpp:3366
void SetOperator(const Operator &op) override
Set/update the solver for the given operator.
Definition petsc.cpp:3270
PetscPreconditioner(MPI_Comm comm, const std::string &prefix=std::string())
Definition petsc.cpp:3235
operator petsc::PC() const
Conversion function to PETSc's PC type.
Definition petsc.hpp:828
void MultTranspose(const Vector &b, Vector &x) const override
Action of the transpose operator: y=A^t(x). The default behavior in class Operator is to generate an ...
Definition petsc.cpp:3361
Abstract class for monitoring PETSc's solvers.
Definition petsc.hpp:988
virtual void MonitorResidual(PetscInt it, PetscReal norm, const Vector &r)
Monitor the residual vector r.
Definition petsc.hpp:1003
virtual void MonitorSolution(PetscInt it, PetscReal norm, const Vector &x)
Monitor the solution vector x.
Definition petsc.hpp:997
virtual void MonitorSolver(PetscSolver *solver)
Generic monitor to take access to the solver.
Definition petsc.hpp:1009
Abstract class for PETSc's solvers.
Definition petsc.hpp:679
PetscClassId cid
The class id of the actual PETSc object.
Definition petsc.hpp:688
void SetAbsTol(real_t tol)
Definition petsc.cpp:2396
void SetTol(real_t tol)
Definition petsc.cpp:2366
void * private_ctx
Private context for solver.
Definition petsc.hpp:697
void SetPrintLevel(int plev)
Definition petsc.cpp:2448
void SetBCHandler(PetscBCHandler *bch)
Sets the object to handle essential boundary conditions.
Definition petsc.cpp:2561
void SetMaxIter(int max_iter)
Definition petsc.cpp:2421
void SetRelTol(real_t tol)
Definition petsc.cpp:2371
PetscParVector * X
Definition petsc.hpp:691
void CreatePrivateContext()
Definition petsc.cpp:2745
virtual ~PetscSolver()
Destroy the PetscParVectors allocated (if any).
Definition petsc.cpp:2359
int GetNumIterations()
Definition petsc.cpp:2687
real_t GetFinalNorm()
Definition petsc.cpp:2720
MPI_Comm GetComm() const
Get the associated MPI communicator.
Definition petsc.cpp:2526
PetscSolver()
Construct an empty PetscSolver. Initialize protected objects to NULL.
Definition petsc.cpp:2349
PetscObject obj
The actual PETSc object (KSP, PC, SNES or TS).
Definition petsc.hpp:685
bool clcustom
Boolean to handle SetFromOptions calls.
Definition petsc.hpp:682
bool operatorset
Boolean to handle SetOperator calls.
Definition petsc.hpp:700
void Customize(bool customize=true) const
Customize object with options set.
Definition petsc.cpp:2621
void SetMonitor(PetscSolverMonitor *ctx)
Sets user-defined monitoring routine.
Definition petsc.cpp:2531
void FreePrivateContext()
Definition petsc.cpp:2777
PetscBCHandler * bchandler
Handler for boundary conditions.
Definition petsc.hpp:694
void SetPreconditionerFactory(PetscPreconditionerFactory *factory)
Sets the object for the creation of the preconditioner.
Definition petsc.cpp:2580
PetscParVector * B
Right-hand side and solution vector.
Definition petsc.hpp:691
Base class for solvers.
Definition operator.hpp:855
bool iterative_mode
If true, use the second argument of Mult() as an initial guess.
Definition operator.hpp:858
Data type sparse matrix.
Definition sparsemat.hpp:51
const int * HostReadJ() const
int NumNonZeroElems() const override
Returns the number of the nonzero elements in the matrix.
const real_t * HostReadData() const
void SortColumnIndices()
Sort the column indices corresponding to each row.
const int * HostReadI() const
Base abstract class for first order time dependent operators.
Definition operator.hpp:367
bool isHomogeneous() const
True if type is HOMOGENEOUS.
Definition operator.hpp:449
virtual Operator & GetExplicitGradient(const Vector &u) const
Return an Operator representing dG/du at the given point u and the currently set time.
Definition operator.cpp:327
bool isImplicit() const
True if type is IMPLICIT or HOMOGENEOUS.
Definition operator.hpp:447
virtual void ExplicitMult(const Vector &u, Vector &v) const
Perform the action of the explicit part of the operator, G: v = G(u, t) where t is the current time.
Definition operator.cpp:297
virtual Operator & GetImplicitGradient(const Vector &u, const Vector &k, real_t shift) const
Return an Operator representing (dF/dk shift + dF/du) at the given u, k, and the currently set time.
Definition operator.cpp:319
virtual void SetTime(const real_t t_)
Set the current time.
Definition operator.hpp:442
virtual void ImplicitMult(const Vector &u, const Vector &k, Vector &v) const
Perform the action of the implicit part of the operator, F: v = F(u, k, t) where t is the current tim...
Definition operator.cpp:302
Vector data type.
Definition vector.hpp:82
void MakeDataOwner() const
Set the Vector data (host pointer) ownership flag.
Definition vector.hpp:222
Memory< real_t > & GetMemory()
Return a reference to the Memory object used by the Vector.
Definition vector.hpp:265
Memory< real_t > data
Definition vector.hpp:85
int Size() const
Returns the size of the vector.
Definition vector.hpp:234
virtual void UseDevice(bool use_dev) const
Enable execution of Vector operations using the mfem::Device.
Definition vector.hpp:145
void SetSize(int s)
Resize the vector to size s.
Definition vector.hpp:633
const int * ess_tdof_list
int dim
Definition ex24.cpp:53
void trans(const Vector &u, Vector &x)
Definition ex27.cpp:412
HYPRE_Int HYPRE_BigInt
real_t b
Definition lissajous.cpp:42
real_t a
Definition lissajous.cpp:41
struct LorentzContext ctx
real_t f(const Vector &p)
void write(std::ostream &os, T value)
Write 'value' to stream.
Definition binaryio.hpp:37
T read(std::istream &is)
Read a value from the stream and return it.
Definition binaryio.hpp:44
MFEM_HOST_DEVICE constexpr auto type(const tuple< T... > &t)
a function intended to be used for extracting the ith type from a tuple.
Definition tuple.hpp:376
struct ::_p_Vec * Vec
Definition petsc.hpp:75
struct ::_p_Mat * Mat
Definition petsc.hpp:76
const T * Read(const Memory< T > &mem, int size, bool on_dev=true)
Get a pointer for read access to mem with the mfem::Device's DeviceMemoryClass, if on_dev = true,...
Definition device.hpp:369
T * HostReadWrite(Memory< T > &mem, int size)
Shortcut to ReadWrite(Memory<T> &mem, int size, false)
Definition device.hpp:410
const T * HostRead(const Memory< T > &mem, int size)
Shortcut to Read(const Memory<T> &mem, int size, false)
Definition device.hpp:376
T * Write(Memory< T > &mem, int size, bool on_dev=true)
Get a pointer for write access to mem with the mfem::Device's DeviceMemoryClass, if on_dev = true,...
Definition device.hpp:386
OutStream out(std::cout)
Global stream used by the library for standard output. Initially it uses the same std::streambuf as s...
Definition globals.hpp:66
PetscParMatrix * TripleMatrixProduct(PetscParMatrix *R, PetscParMatrix *A, PetscParMatrix *P)
Returns the matrix R * A * P.
Definition petsc.cpp:2093
T * ReadWrite(Memory< T > &mem, int size, bool on_dev=true)
Get a pointer for read+write access to mem with the mfem::Device's DeviceMemoryClass,...
Definition device.hpp:403
void RAP(const DenseMatrix &A, const DenseMatrix &P, DenseMatrix &RAP)
void MFEMInitializePetsc()
Convenience functions to initialize/finalize PETSc.
Definition petsc.cpp:207
void MFEMFinalizePetsc()
Definition petsc.cpp:247
MemoryType GetMemoryType(MemoryClass mc)
Return a suitable MemoryType for a given MemoryClass.
T * HostWrite(Memory< T > &mem, int size)
Shortcut to Write(const Memory<T> &mem, int size, false)
Definition device.hpp:393
HypreParMatrix * ParMult(const HypreParMatrix *A, const HypreParMatrix *B, bool own_matrix)
Definition hypre.cpp:3057
float real_t
Definition config.hpp:46
MemoryType
Memory types supported by MFEM.
@ HOST
Host memory; using new[] and delete[].
@ DEVICE
Device memory; using CUDA or HIP *Malloc and *Free.
void EliminateBC(const HypreParMatrix &A, const HypreParMatrix &Ae, const Array< int > &ess_dof_list, const Vector &X, Vector &B)
Eliminate essential BC specified by ess_dof_list from the solution X to the r.h.s....
Definition hypre.cpp:3489
std::function< real_t(const Vector &)> f(real_t mass_coeff)
Definition lor_mms.hpp:30
STL namespace.
real_t p(const Vector &x, real_t t)
PetscErrorCode PetscCtxDestroyFn(void **)
Definition petsc.cpp:41
PetscErrorCode KSPMonitorFn(KSP, PetscInt, PetscReal, void *)
Definition petsc.cpp:44
void * PetscCtxRt
Definition petsc.cpp:85
HYPRE_Int PetscInt
Definition petsc.hpp:53
struct _p_PetscObject * PetscObject
Definition petsc.hpp:57
real_t PetscScalar
Definition petsc.hpp:54
real_t PetscReal
Definition petsc.hpp:55
MFEM_HOST_DEVICE real_t norm(const Complex &z)
@ HIP_MASK
Biwise-OR of all HIP backends.
Definition device.hpp:98
@ CUDA_MASK
Biwise-OR of all CUDA backends.
Definition device.hpp:96