MFEM v4.9.0
Finite element discretization library
Loading...
Searching...
No Matches
pnonlinearform.cpp
Go to the documentation of this file.
1// Copyright (c) 2010-2025, 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#include "../config/config.hpp"
13
14#ifdef MFEM_USE_MPI
15
16#include "fem.hpp"
17#include "../general/forall.hpp"
18
19namespace mfem
20{
21
23 : NonlinearForm(pf), pGrad(Operator::Hypre_ParCSR)
24{
25 X.MakeRef(pf, NULL);
26 Y.MakeRef(pf, NULL);
27 MFEM_VERIFY(!Serial(), "internal MFEM error");
28}
29
31{
32 real_t loc_energy, glob_energy;
33
34 loc_energy = GetGridFunctionEnergy(x);
35
36 if (fnfi.Size())
37 {
38 MFEM_ABORT("TODO: add energy contribution from shared faces");
39 }
40
41 MPI_Allreduce(&loc_energy, &glob_energy, 1, MPITypeMap<real_t>::mpi_type,
42 MPI_SUM,
43 ParFESpace()->GetComm());
44
45 return glob_energy;
46}
47
48void ParNonlinearForm::Mult(const Vector &x, Vector &y) const
49{
50 NonlinearForm::Mult(x, y); // x --(P)--> aux1 --(A_local)--> aux2
51
52 if (fnfi.Size())
53 {
54 MFEM_VERIFY(!NonlinearForm::ext, "Not implemented (extensions + faces");
55 // Terms over shared interior faces in parallel.
57 ParMesh *pmesh = pfes->GetParMesh();
59 const FiniteElement *fe1, *fe2;
60 Array<int> vdofs1, vdofs2;
61 Vector el_x, el_y;
62
64 X.MakeRef(aux1, 0); // aux1 contains P.x
66 const int n_shared_faces = pmesh->GetNSharedFaces();
67 for (int i = 0; i < n_shared_faces; i++)
68 {
69 tr = pmesh->GetSharedFaceTransformations(i, true);
70 int Elem2NbrNo = tr->Elem2No - pmesh->GetNE();
71
72 fe1 = pfes->GetFE(tr->Elem1No);
73 fe2 = pfes->GetFaceNbrFE(Elem2NbrNo);
74
75 pfes->GetElementVDofs(tr->Elem1No, vdofs1);
76 pfes->GetFaceNbrElementVDofs(Elem2NbrNo, vdofs2);
77
78 el_x.SetSize(vdofs1.Size() + vdofs2.Size());
79 X.GetSubVector(vdofs1, el_x.GetData());
80 X.FaceNbrData().GetSubVector(vdofs2, el_x.GetData() + vdofs1.Size());
81
82 for (int k = 0; k < fnfi.Size(); k++)
83 {
84 fnfi[k]->AssembleFaceVector(*fe1, *fe2, *tr, el_x, el_y);
85 aux2.AddElementVector(vdofs1, el_y.GetData());
86 }
87 }
88 }
89
90 P->MultTranspose(aux2, y);
91
92 const int N = ess_tdof_list.Size();
93 const auto idx = ess_tdof_list.Read();
94 auto Y_RW = y.ReadWrite();
95 mfem::forall(N, [=] MFEM_HOST_DEVICE (int i) { Y_RW[idx[i]] = 0.0; });
96}
97
99{
100 MFEM_VERIFY(NonlinearForm::ext == nullptr,
101 "this method is not supported yet with partial assembly");
102
103 NonlinearForm::GetGradient(x); // (re)assemble Grad, no b.c.
104
105 return *Grad;
106}
107
109 int skip_zeros) const
110{
112 ParMesh *pmesh = pfes->GetParMesh();
114 Array<int> vdofs1, vdofs2, vdofs_all;
115 DenseMatrix elemmat;
116 Vector el_x, nbr_x, face_x;
117 const Vector &px = Prolongate(x);
118
119 ParGridFunction pgf(pfes, const_cast<Vector&>(px), 0);
121
122 int nfaces = pmesh->GetNSharedFaces();
123 for (int i = 0; i < nfaces; i++)
124 {
125 T = pmesh->GetSharedFaceTransformations(i);
126 int Elem2NbrNo = T->Elem2No - pmesh->GetNE();
127
128 pfes->GetElementVDofs(T->Elem1No, vdofs1);
129 pfes->GetFaceNbrElementVDofs(Elem2NbrNo, vdofs2);
130 face_x.SetSize(vdofs1.Size() + vdofs2.Size());
131
132 el_x.MakeRef(face_x, 0, vdofs1.Size());
133 pgf.GetSubVector(vdofs1, el_x);
134
135 nbr_x.MakeRef(face_x, vdofs1.Size(), vdofs2.Size());
136 pgf.FaceNbrData().GetSubVector(vdofs2, nbr_x);
137
138 vdofs1.Copy(vdofs_all);
139 for (int j = 0; j < vdofs2.Size(); j++)
140 {
141 if (vdofs2[j] >= 0)
142 {
143 vdofs2[j] += height;
144 }
145 else
146 {
147 vdofs2[j] -= height;
148 }
149 }
150 vdofs_all.Append(vdofs2);
151 for (int k = 0; k < fnfi.Size(); k++)
152 {
153 fnfi[k]->AssembleFaceGrad(*pfes->GetFE(T->Elem1No),
154 *pfes->GetFaceNbrFE(Elem2NbrNo),
155 *T, face_x, elemmat);
156 Grad->AddSubMatrix(vdofs1, vdofs_all, elemmat, skip_zeros);
157 }
158 }
159}
160
162{
164
166
167 pGrad.Clear();
168 OperatorHandle dA(pGrad.Type()), Ph(pGrad.Type()), hdA;
169
170 if (fnfi.Size())
171 {
172 const int skip_zeros = 0;
173
174 pfes->ExchangeFaceNbrData();
175 if (Grad == NULL)
176 {
177 int nbr_size = pfes->GetFaceNbrVSize();
178 Grad = new SparseMatrix(pfes->GetVSize(), pfes->GetVSize() + nbr_size);
179 }
180
181 NonlinearForm::GetGradient(x, false); // (re)assemble Grad, no b.c.
182
183 GradientSharedFaces(x, skip_zeros);
184
185 Grad->Finalize(skip_zeros);
186
187 // handle the case when 'a' contains off-diagonal
188 int lvsize = pfes->GetVSize();
189 const HYPRE_BigInt *face_nbr_glob_ldof = pfes->GetFaceNbrGlobalDofMap();
190 HYPRE_BigInt ldof_offset = pfes->GetMyDofOffset();
191
193 int *J = Grad->GetJ();
194 for (int i = 0; i < glob_J.Size(); i++)
195 {
196 if (J[i] < lvsize)
197 {
198 glob_J[i] = J[i] + ldof_offset;
199 }
200 else
201 {
202 glob_J[i] = face_nbr_glob_ldof[J[i] - lvsize];
203 }
204 }
205
206 // TODO - construct dA directly in the A format
207 hdA.Reset(
208 new HypreParMatrix(pfes->GetComm(), lvsize, pfes->GlobalVSize(),
209 pfes->GlobalVSize(), Grad->GetI(), glob_J,
210 Grad->GetData(), pfes->GetDofOffsets(),
211 pfes->GetDofOffsets()));
212 // - hdA owns the new HypreParMatrix
213 // - the above constructor copies all input arrays
214 glob_J.DeleteAll();
215 dA.ConvertFrom(hdA);
216 }
217 else
218 {
219 NonlinearForm::GetGradient(x); // (re)assemble Grad, no b.c.
220
221 dA.MakeSquareBlockDiag(pfes->GetComm(), pfes->GlobalVSize(),
222 pfes->GetDofOffsets(), Grad);
223 }
224
225 // RAP the local gradient dA.
226 // TODO - construct Dof_TrueDof_Matrix directly in the pGrad format
227 Ph.ConvertFrom(pfes->Dof_TrueDof_Matrix());
228 pGrad.MakePtAP(dA, Ph);
229
230 // Impose b.c. on pGrad
231 OperatorHandle pGrad_e;
233
234 return *pGrad.Ptr();
235}
236
238{
239 Y.MakeRef(ParFESpace(), NULL);
240 X.MakeRef(ParFESpace(), NULL);
241 pGrad.Clear();
243}
244
245
252
254{
255 delete pBlockGrad;
256 pBlockGrad = NULL;
257
258 for (int s1=0; s1<fes.Size(); ++s1)
259 {
260 for (int s2=0; s2<fes.Size(); ++s2)
261 {
262 delete phBlockGrad(s1,s2);
263 }
264 }
265
266 Array<FiniteElementSpace *> serialSpaces(pf.Size());
267
268 for (int s=0; s<pf.Size(); s++)
269 {
270 serialSpaces[s] = (FiniteElementSpace *) pf[s];
271 }
272
273 SetSpaces(serialSpaces);
274
275 phBlockGrad.SetSize(fes.Size(), fes.Size());
276
277 for (int s1=0; s1<fes.Size(); ++s1)
278 {
279 for (int s2=0; s2<fes.Size(); ++s2)
280 {
282 }
283 }
284}
285
290
292{
293 return (const ParFiniteElementSpace *)fes[k];
294}
295
296// Here, rhs is a true dof vector
298 const Array<Array<int>*> &bdr_attr_is_ess, Array<Vector*> &rhs)
299{
300 Array<Vector *> nullarray(fes.Size());
301 nullarray = NULL;
302
303 BlockNonlinearForm::SetEssentialBC(bdr_attr_is_ess, nullarray);
304
305 for (int s = 0; s < fes.Size(); ++s)
306 {
307 if (rhs[s])
308 {
309 rhs[s]->SetSubVector(*ess_tdofs[s], 0.0);
310 }
311 }
312}
313
315 const Array<Array<int>*> &ess_tdof_list, Array<Vector*> &rhs)
316{
317 Array<Vector *> nullarray(fes.Size());
318 nullarray = nullptr;
319
320 BlockNonlinearForm::SetEssentialTrueDofs(ess_tdof_list, nullarray);
321
322 for (int s = 0; s < fes.Size(); ++s)
323 {
324 if (rhs[s])
325 {
326 rhs[s]->SetSubVector(*ess_tdofs[s], 0.0);
327 }
328 }
329}
330
332{
333 // xs_true is not modified, so const_cast is okay
334 xs_true.Update(const_cast<Vector &>(x), block_trueOffsets);
336
337 for (int s = 0; s < fes.Size(); ++s)
338 {
339 fes[s]->GetProlongationMatrix()->Mult(xs_true.GetBlock(s), xs.GetBlock(s));
340 }
341
343 real_t englo = 0.0;
344
345 MPI_Allreduce(&enloc, &englo, 1, MPITypeMap<real_t>::mpi_type, MPI_SUM,
346 ParFESpace(0)->GetComm());
347
348 return englo;
349}
350
352{
353 // xs_true is not modified, so const_cast is okay
354 xs_true.Update(const_cast<Vector &>(x), block_trueOffsets);
358
359 for (int s=0; s<fes.Size(); ++s)
360 {
361 fes[s]->GetProlongationMatrix()->Mult(
362 xs_true.GetBlock(s), xs.GetBlock(s));
363 }
364
366
367 if (fnfi.Size() > 0)
368 {
369 // Terms over shared interior faces in parallel.
370 ParMesh *pmesh = ParFESpace(0)->GetParMesh();
372
373 Array<Array<int> *>vdofs(fes.Size());
374 Array<Array<int> *>vdofs2(fes.Size());
375 Array<Vector *> el_x(fes.Size());
376 Array<const Vector *> el_x_const(fes.Size());
377 Array<Vector *> el_y(fes.Size());
380 Array<ParGridFunction *> pgfs(fes.Size());
381 for (int s=0; s<fes.Size(); ++s)
382 {
383 el_x_const[s] = el_x[s] = new Vector();
384 el_y[s] = new Vector();
385 vdofs[s] = new Array<int>;
386 vdofs2[s] = new Array<int>;
387 pgfs[s] = new ParGridFunction(const_cast<ParFiniteElementSpace*>(ParFESpace(s)),
388 xs.GetBlock(s));
389 pgfs[s]->ExchangeFaceNbrData();
390 }
391
392 const int n_shared_faces = pmesh->GetNSharedFaces();
393 for (int i = 0; i < n_shared_faces; i++)
394 {
395 tr = pmesh->GetSharedFaceTransformations(i, true);
396 int Elem2NbrNo = tr->Elem2No - pmesh->GetNE();
397
398 for (int s=0; s<fes.Size(); ++s)
399 {
400 const ParFiniteElementSpace *pfes = ParFESpace(s);
401 fe[s] = pfes->GetFE(tr->Elem1No);
402 fe2[s] = pfes->GetFaceNbrFE(Elem2NbrNo);
403
404 pfes->GetElementVDofs(tr->Elem1No, *(vdofs[s]));
405 pfes->GetFaceNbrElementVDofs(Elem2NbrNo, *(vdofs2[s]));
406
407 el_x[s]->SetSize(vdofs[s]->Size() + vdofs2[s]->Size());
408 xs.GetBlock(s).GetSubVector(*(vdofs[s]), el_x[s]->GetData());
409 pgfs[s]->FaceNbrData().GetSubVector(*(vdofs2[s]),
410 el_x[s]->GetData() + vdofs[s]->Size());
411 }
412
413 for (int k = 0; k < fnfi.Size(); ++k)
414 {
415 fnfi[k]->AssembleFaceVector(fe, fe2, *tr, el_x_const, el_y);
416
417 for (int s=0; s<fes.Size(); ++s)
418 {
419 if (el_y[s]->Size() == 0) { continue; }
420 ys.GetBlock(s).AddElementVector(*(vdofs[s]), *el_y[s]);
421 }
422 }
423 }
424
425 for (int s=0; s<fes.Size(); ++s)
426 {
427 delete pgfs[s];
428 delete vdofs2[s];
429 delete vdofs[s];
430 delete el_y[s];
431 delete el_x[s];
432 }
433 }
434
435 for (int s=0; s<fes.Size(); ++s)
436 {
437 fes[s]->GetProlongationMatrix()->MultTranspose(
438 ys.GetBlock(s), ys_true.GetBlock(s));
439
441 }
442
445}
446
447/// Return the local gradient matrix for the given true-dof vector x
449 const Vector &x) const
450{
451 // xs_true is not modified, so const_cast is okay
452 xs_true.Update(const_cast<Vector &>(x), block_trueOffsets);
454
455 for (int s=0; s<fes.Size(); ++s)
456 {
457 fes[s]->GetProlongationMatrix()->Mult(
458 xs_true.GetBlock(s), xs.GetBlock(s));
459 }
460
461 // (re)assemble Grad without b.c. into 'Grads'
463
464 delete BlockGrad;
466
467 for (int i = 0; i < fes.Size(); ++i)
468 {
469 for (int j = 0; j < fes.Size(); ++j)
470 {
471 BlockGrad->SetBlock(i, j, Grads(i, j));
472 }
473 }
474 return *BlockGrad;
475}
476
477// Set the operator type id for the parallel gradient matrix/operator.
479{
480 for (int s1=0; s1<fes.Size(); ++s1)
481 {
482 for (int s2=0; s2<fes.Size(); ++s2)
483 {
484 phBlockGrad(s1,s2)->SetType(tid);
485 }
486 }
487}
488
490 int skip_zeros) const
491{
492 // Terms over shared interior faces in parallel.
493 ParMesh *pmesh = ParFESpace(0)->GetParMesh();
495
496 Array<Array<int> *>vdofs(fes.Size());
497 Array<Array<int> *>vdofs2(fes.Size());
498 Array<Array<int> *>vdofs_all(fes.Size());
499 Array<Vector *> el_x(fes.Size());
500 Array<const Vector *> el_x_const(fes.Size());
501 Array2D<DenseMatrix *> elmats(fes.Size(), fes.Size());
504 Array<ParGridFunction *> pgfs(fes.Size());
505
506 for (int s1=0; s1<fes.Size(); ++s1)
507 {
508 el_x_const[s1] = el_x[s1] = new Vector();
509 vdofs[s1] = new Array<int>;
510 vdofs2[s1] = new Array<int>;
511 vdofs_all[s1] = new Array<int>;
512 pgfs[s1] = new ParGridFunction(
513 const_cast<ParFiniteElementSpace*>(ParFESpace(s1)),
514 const_cast<Vector&>(xs.GetBlock(s1)));
515 pgfs[s1]->ExchangeFaceNbrData();
516 for (int s2=0; s2<fes.Size(); ++s2)
517 {
518 elmats(s1,s2) = new DenseMatrix();
519 }
520 }
521
522 const int n_shared_faces = pmesh->GetNSharedFaces();
523 for (int i = 0; i < n_shared_faces; i++)
524 {
525 tr = pmesh->GetSharedFaceTransformations(i, true);
526 int Elem2NbrNo = tr->Elem2No - pmesh->GetNE();
527
528 for (int s=0; s<fes.Size(); ++s)
529 {
530 const ParFiniteElementSpace *pfes = ParFESpace(s);
531 fe[s] = pfes->GetFE(tr->Elem1No);
532 fe2[s] = pfes->GetFaceNbrFE(Elem2NbrNo);
533
534 pfes->GetElementVDofs(tr->Elem1No, *(vdofs[s]));
535 pfes->GetFaceNbrElementVDofs(Elem2NbrNo, *(vdofs2[s]));
536
537 el_x[s]->SetSize(vdofs[s]->Size() + vdofs2[s]->Size());
538 xs.GetBlock(s).GetSubVector(*(vdofs[s]), el_x[s]->GetData());
539 pgfs[s]->FaceNbrData().GetSubVector(*(vdofs2[s]),
540 el_x[s]->GetData() + vdofs[s]->Size());
541
542 vdofs[s]->Copy(*vdofs_all[s]);
543
544 const int lvsize = pfes->GetVSize();
545 for (int j = 0; j < vdofs2[s]->Size(); j++)
546 {
547 if ((*vdofs2[s])[j] >= 0)
548 {
549 (*vdofs2[s])[j] += lvsize;
550 }
551 else
552 {
553 (*vdofs2[s])[j] -= lvsize;
554 }
555 }
556 vdofs_all[s]->Append(*(vdofs2[s]));
557 }
558
559 for (int k = 0; k < fnfi.Size(); ++k)
560 {
561 fnfi[k]->AssembleFaceGrad(fe, fe2, *tr, el_x_const, elmats);
562
563 for (int s1=0; s1<fes.Size(); ++s1)
564 {
565 for (int s2=0; s2<fes.Size(); ++s2)
566 {
567 if (elmats(s1,s2)->Height() == 0) { continue; }
568 Grads(s1,s2)->AddSubMatrix(*vdofs[s1], *vdofs_all[s2],
569 *elmats(s1,s2), skip_zeros);
570 }
571 }
572 }
573 }
574
575 for (int s1=0; s1<fes.Size(); ++s1)
576 {
577 delete pgfs[s1];
578 delete vdofs_all[s1];
579 delete vdofs2[s1];
580 delete vdofs[s1];
581 delete el_x[s1];
582 for (int s2=0; s2<fes.Size(); ++s2)
583 {
584 delete elmats(s1,s2);
585 }
586 }
587}
588
590{
591 if (pBlockGrad == NULL)
592 {
594 }
595
597
598 for (int s1=0; s1<fes.Size(); ++s1)
599 {
600 pfes[s1] = ParFESpace(s1);
601
602 for (int s2=0; s2<fes.Size(); ++s2)
603 {
604 phBlockGrad(s1,s2)->Clear();
605 }
606 }
607
608 // xs_true is not modified, so const_cast is okay
609 xs_true.Update(const_cast<Vector &>(x), block_trueOffsets);
611
612 for (int s=0; s<fes.Size(); ++s)
613 {
614 fes[s]->GetProlongationMatrix()->Mult(
615 xs_true.GetBlock(s), xs.GetBlock(s));
616 }
617
618 if (fnfi.Size() > 0)
619 {
620 const int skip_zeros = 0;
621
622 for (int s=0; s<fes.Size(); ++s)
623 {
624 const_cast<ParFiniteElementSpace*>(pfes[s])->ExchangeFaceNbrData();
625 }
626
627 for (int s1=0; s1<fes.Size(); ++s1)
628 {
629 for (int s2=0; s2<fes.Size(); ++s2)
630 {
631 if (Grads(s1,s2) == NULL)
632 {
633 int nbr_size = pfes[s2]->GetFaceNbrVSize();
634 Grads(s1,s2) = new SparseMatrix(pfes[s1]->GetVSize(),
635 pfes[s2]->GetVSize() + nbr_size);
636 }
637 }
638 }
639
640 // (re)assemble Grad without b.c. into 'Grads'
642
643 GradientSharedFaces(xs, skip_zeros);
644
645 // finalize the gradients
646 for (int s1=0; s1<fes.Size(); ++s1)
647 for (int s2=0; s2<fes.Size(); ++s2)
648 {
649 Grads(s1,s2)->Finalize(skip_zeros);
650 }
651
652 for (int s1=0; s1<fes.Size(); ++s1)
653 {
654 for (int s2=0; s2<fes.Size(); ++s2)
655 {
656 OperatorHandle hdA;
657 OperatorHandle dA(phBlockGrad(s1,s2)->Type()),
658 Ph(phBlockGrad(s1,s2)->Type()),
659 Rh(phBlockGrad(s1,s2)->Type());
660
661 // handle the case when 'a' contains off-diagonal
662 int lvsize = pfes[s2]->GetVSize();
663 const HYPRE_BigInt *face_nbr_glob_ldof =
664 const_cast<ParFiniteElementSpace*>(pfes[s2])->GetFaceNbrGlobalDofMap();
665 HYPRE_BigInt ldof_offset = pfes[s2]->GetMyDofOffset();
666
667 Array<HYPRE_BigInt> glob_J(Grads(s1,s2)->NumNonZeroElems());
668 int *J = Grads(s1,s2)->GetJ();
669 for (int i = 0; i < glob_J.Size(); i++)
670 {
671 if (J[i] < lvsize)
672 {
673 glob_J[i] = J[i] + ldof_offset;
674 }
675 else
676 {
677 glob_J[i] = face_nbr_glob_ldof[J[i] - lvsize];
678 }
679 }
680
681 // TODO - construct dA directly in the A format
682 hdA.Reset(
683 new HypreParMatrix(pfes[s2]->GetComm(), pfes[s1]->GetVSize(),
684 pfes[s1]->GlobalVSize(), pfes[s2]->GlobalVSize(),
685 Grads(s1,s2)->GetI(), glob_J, Grads(s1,s2)->GetData(),
686 pfes[s1]->GetDofOffsets(), pfes[s2]->GetDofOffsets()));
687 // - hdA owns the new HypreParMatrix
688 // - the above constructor copies all input arrays
689 glob_J.DeleteAll();
690 dA.ConvertFrom(hdA);
691
692 if (s1 == s2)
693 {
694 Ph.ConvertFrom(pfes[s1]->Dof_TrueDof_Matrix());
695 phBlockGrad(s1,s1)->MakePtAP(dA, Ph);
696
698 Ae.EliminateRowsCols(*phBlockGrad(s1,s1), *ess_tdofs[s1]);
699 }
700 else
701 {
702 Rh.ConvertFrom(pfes[s1]->Dof_TrueDof_Matrix());
703 Ph.ConvertFrom(pfes[s2]->Dof_TrueDof_Matrix());
704
705 phBlockGrad(s1,s2)->MakeRAP(Rh, dA, Ph);
706
707 phBlockGrad(s1,s2)->EliminateRows(*ess_tdofs[s1]);
708 phBlockGrad(s1,s2)->EliminateCols(*ess_tdofs[s2]);
709 }
710
711 pBlockGrad->SetBlock(s1, s2, phBlockGrad(s1,s2)->Ptr());
712 }
713 }
714 }
715 else
716 {
717 // (re)assemble Grad without b.c. into 'Grads'
719
720 for (int s1=0; s1<fes.Size(); ++s1)
721 {
722 for (int s2=0; s2<fes.Size(); ++s2)
723 {
724 OperatorHandle dA(phBlockGrad(s1,s2)->Type()),
725 Ph(phBlockGrad(s1,s2)->Type()),
726 Rh(phBlockGrad(s1,s2)->Type());
727
728 if (s1 == s2)
729 {
730 dA.MakeSquareBlockDiag(pfes[s1]->GetComm(), pfes[s1]->GlobalVSize(),
731 pfes[s1]->GetDofOffsets(), Grads(s1,s1));
732 Ph.ConvertFrom(pfes[s1]->Dof_TrueDof_Matrix());
733 phBlockGrad(s1,s1)->MakePtAP(dA, Ph);
734
736 Ae.EliminateRowsCols(*phBlockGrad(s1,s1), *ess_tdofs[s1]);
737 }
738 else
739 {
740 dA.MakeRectangularBlockDiag(pfes[s1]->GetComm(),
741 pfes[s1]->GlobalVSize(),
742 pfes[s2]->GlobalVSize(),
743 pfes[s1]->GetDofOffsets(),
744 pfes[s2]->GetDofOffsets(),
745 Grads(s1,s2));
746 Rh.ConvertFrom(pfes[s1]->Dof_TrueDof_Matrix());
747 Ph.ConvertFrom(pfes[s2]->Dof_TrueDof_Matrix());
748
749 phBlockGrad(s1,s2)->MakeRAP(Rh, dA, Ph);
750
751 phBlockGrad(s1,s2)->EliminateRows(*ess_tdofs[s1]);
752 phBlockGrad(s1,s2)->EliminateCols(*ess_tdofs[s2]);
753 }
754
755 pBlockGrad->SetBlock(s1, s2, phBlockGrad(s1,s2)->Ptr());
756 }
757 }
758 }
759
760 return *pBlockGrad;
761}
762
764{
765 delete pBlockGrad;
766 for (int s1=0; s1<fes.Size(); ++s1)
767 {
768 for (int s2=0; s2<fes.Size(); ++s2)
769 {
770 delete phBlockGrad(s1,s2);
771 }
772 }
773}
774
775}
776
777#endif
Dynamic 2D array using row-major layout.
Definition array.hpp:430
void SetSize(int nsize)
Change the logical size of the array, keep existing entries.
Definition array.hpp:840
int Size() const
Return the logical size of the array.
Definition array.hpp:166
void DeleteAll()
Delete the whole array.
Definition array.hpp:1033
int Append(const T &el)
Append element 'el' to array, resize if necessary.
Definition array.hpp:912
void Copy(Array &copy) const
Create a copy of the internal array to the provided copy.
Definition array.hpp:1042
const T * Read(bool on_dev=true) const
Shortcut for mfem::Read(a.GetMemory(), a.Size(), on_dev).
Definition array.hpp:381
A class representing a general block nonlinear operator defined on the Cartesian product of multiple ...
Array< FiniteElementSpace * > fes
FE spaces on which the form lives.
real_t GetEnergyBlocked(const BlockVector &bx) const
Specialized version of GetEnergy() for BlockVectors.
void ComputeGradientBlocked(const BlockVector &bx, bool finalize=true) const
Specialized version of GetGradient() for BlockVector.
void SetSpaces(Array< FiniteElementSpace * > &f)
(Re)initialize the BlockNonlinearForm.
Array2D< SparseMatrix * > Grads
void MultBlocked(const BlockVector &bx, BlockVector &by) const
Array< BlockNonlinearFormIntegrator * > fnfi
Set of interior face Integrators to be assembled (added).
virtual void SetEssentialBC(const Array< Array< int > * > &bdr_attr_is_ess, Array< Vector * > &rhs)
Set essential boundary conditions to each finite element space using boundary attribute markers.
virtual void SetEssentialTrueDofs(const Array< Array< int > * > &ess_tdof_list, Array< Vector * > &rhs)
Set essential boundary conditions to each finite element space using essential true dof lists.
Array< Array< int > * > ess_tdofs
A class to handle Block systems in a matrix-free implementation.
void SetBlock(int iRow, int iCol, Operator *op, real_t c=1.0)
Add a block op in the block-entry (iblock, jblock).
A class to handle Vectors in a block fashion.
void Update(real_t *data, const Array< int > &bOffsets)
Update method.
void SyncFromBlocks() const
Synchronize the memory location flags (i.e. the memory validity flags) of the big/monolithic block-ve...
Vector & GetBlock(int i)
Get the i-th vector in the block.
Data type dense matrix using column-major storage.
Definition densemat.hpp:24
A specialized ElementTransformation class representing a face and its two neighboring elements.
Definition eltrans.hpp:750
Class FiniteElementSpace - responsible for providing FEM view of the mesh, mainly managing the set of...
Definition fespace.hpp:208
DofTransformation * GetElementVDofs(int i, Array< int > &vdofs) const
Returns indices of degrees of freedom for the i'th element. The returned indices are offsets into an ...
Definition fespace.cpp:304
int GetVSize() const
Return the number of vector dofs, i.e. GetNDofs() x GetVDim().
Definition fespace.hpp:826
Abstract class for all finite elements.
Definition fe_base.hpp:247
Wrapper for hypre's ParCSR matrix class.
Definition hypre.hpp:419
int GetNE() const
Returns number of elements.
Definition mesh.hpp:1377
SparseMatrix * Grad
const Vector & Prolongate(const Vector &x) const
Vector aux1
Auxiliary Vectors.
NonlinearFormExtension * ext
Extension for supporting different AssemblyLevels.
Operator & GetGradient(const Vector &x) const override
Compute the gradient Operator of the NonlinearForm corresponding to the state x.
const Operator * P
Pointer to the prolongation matrix of fes, may be NULL.
virtual void Update()
Update the NonlinearForm to propagate updates of the associated FE space.
Array< int > ess_tdof_list
A list of all essential true dofs.
void Mult(const Vector &x, Vector &y) const override
Evaluate the action of the NonlinearForm.
Array< NonlinearFormIntegrator * > fnfi
Set of interior face Integrators to be assembled (added).
real_t GetGridFunctionEnergy(const Vector &x) const
Compute the energy corresponding to the state x.
Pointer to an Operator of a specified type.
Definition handle.hpp:34
void EliminateRowsCols(OperatorHandle &A, const Array< int > &ess_dof_list)
Reset the OperatorHandle to be the eliminated part of A after elimination of the essential dofs ess_d...
Definition handle.cpp:255
void ConvertFrom(OperatorHandle &A)
Convert the given OperatorHandle A to the currently set type id.
Definition handle.cpp:203
void MakePtAP(OperatorHandle &A, OperatorHandle &P)
Reset the OperatorHandle to hold the product P^t A P.
Definition handle.cpp:124
Operator * Ptr() const
Access the underlying Operator pointer.
Definition handle.hpp:87
void Clear()
Clear the OperatorHandle, deleting the held Operator (if owned), while leaving the type id unchanged.
Definition handle.hpp:124
void Reset(OpType *A, bool own_A=true)
Reset the OperatorHandle to the given OpType pointer, A.
Definition handle.hpp:145
Operator::Type Type() const
Get the currently set operator type id.
Definition handle.hpp:99
Abstract operator.
Definition operator.hpp:25
int height
Dimension of the output / number of rows in the matrix.
Definition operator.hpp:27
Type
Enumeration defining IDs for some classes derived from Operator.
Definition operator.hpp:296
@ Hypre_ParCSR
ID for class HypreParMatrix.
Definition operator.hpp:299
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:100
const BlockOperator & GetLocalGradient(const Vector &x) const
Return the local block gradient matrix for the given true-dof vector x.
void Mult(const Vector &x, Vector &y) const override
Block T-Vector to Block T-Vector.
virtual void SetEssentialTrueDofs(const Array< Array< int > * > &ess_tdof_list, Array< Vector * > &rhs) override
Set essential boundary conditions to each finite element space using essential true dof lists.
Array2D< OperatorHandle * > phBlockGrad
void GradientSharedFaces(const BlockVector &xs, int skip_zeros) const
ParFiniteElementSpace * ParFESpace(int k)
Return the k-th parallel FE space of the ParBlockNonlinearForm.
ParBlockNonlinearForm()
Construct an empty ParBlockNonlinearForm. Initialize with SetParSpaces().
real_t GetEnergy(const Vector &x) const override
Computes the energy of the system.
virtual ~ParBlockNonlinearForm()
Destructor.
void SetParSpaces(Array< ParFiniteElementSpace * > &pf)
After a call to SetParSpaces(), the essential b.c. and the gradient-type (if different from the defau...
BlockOperator & GetGradient(const Vector &x) const override
virtual void SetEssentialBC(const Array< Array< int > * > &bdr_attr_is_ess, Array< Vector * > &rhs) override
Set essential boundary conditions to each finite element space using boundary attribute markers.
void SetGradientType(Operator::Type tid)
Set the operator type id for the blocks of the parallel gradient matrix/operator. The default type is...
Abstract parallel finite element space.
Definition pfespace.hpp:31
MPI_Comm GetComm() const
Definition pfespace.hpp:337
HYPRE_BigInt GlobalVSize() const
Definition pfespace.hpp:347
const FiniteElement * GetFaceNbrFE(int i, int ndofs=0) const
HYPRE_BigInt GetMyDofOffset() const
HYPRE_BigInt * GetDofOffsets() const
Definition pfespace.hpp:345
HypreParMatrix * Dof_TrueDof_Matrix() const
The true dof-to-dof interpolation matrix.
Definition pfespace.hpp:391
void GetFaceNbrElementVDofs(int i, Array< int > &vdofs, DofTransformation &doftrans) const
const HYPRE_BigInt * GetFaceNbrGlobalDofMap()
Definition pfespace.hpp:485
ParMesh * GetParMesh() const
Definition pfespace.hpp:341
const FiniteElement * GetFE(int i) const override
Definition pfespace.cpp:632
Class for parallel grid function.
Definition pgridfunc.hpp:50
void MakeRef(FiniteElementSpace *f, real_t *v) override
Make the ParGridFunction reference external data on a new FiniteElementSpace.
Class for parallel meshes.
Definition pmesh.hpp:34
int GetNSharedFaces() const
Return the number of shared faces (3D), edges (2D), vertices (1D)
Definition pmesh.cpp:3164
FaceElementTransformations * GetSharedFaceTransformations(int sf, bool fill2=true)
Get the FaceElementTransformations for the given shared face (edge 2D) using the shared face index sf...
Definition pmesh.cpp:2933
const SparseMatrix & GetLocalGradient(const Vector &x) const
Return the local gradient matrix for the given true-dof vector x.
ParNonlinearForm(ParFiniteElementSpace *pf)
real_t GetParGridFunctionEnergy(const Vector &x) const
Compute the energy corresponding to the state x.
Operator & GetGradient(const Vector &x) const override
Compute the gradient Operator of the NonlinearForm corresponding to the state x.
ParFiniteElementSpace * ParFESpace() const
void GradientSharedFaces(const Vector &x, int skip_zeros=1) const
void Update() override
Update the ParNonlinearForm to propagate updates of the associated parallel FE space.
void Mult(const Vector &x, Vector &y) const override
Evaluate the action of the NonlinearForm.
Data type sparse matrix.
Definition sparsemat.hpp:51
int NumNonZeroElems() const override
Returns the number of the nonzero elements in the matrix.
void AddSubMatrix(const Array< int > &rows, const Array< int > &cols, const DenseMatrix &subm, int skip_zeros=1)
real_t * GetData()
Return the element data, i.e. the array A.
void Finalize(int skip_zeros=1) override
Finalize the matrix initialization, switching the storage format from LIL to CSR.
int * GetJ()
Return the array J.
int * GetI()
Return the array I.
Vector data type.
Definition vector.hpp:82
virtual real_t * ReadWrite(bool on_dev=true)
Shortcut for mfem::ReadWrite(vec.GetMemory(), vec.Size(), on_dev).
Definition vector.hpp:536
void SetSubVector(const Array< int > &dofs, const real_t value)
Set the entries listed in dofs to the given value.
Definition vector.cpp:702
void AddElementVector(const Array< int > &dofs, const Vector &elemvect)
Add elements of the elemvect Vector to the entries listed in dofs. Negative dof values cause the -dof...
Definition vector.cpp:785
void SyncMemory(const Vector &v) const
Update the memory location of the vector to match v.
Definition vector.hpp:272
void SetSize(int s)
Resize the vector to size s.
Definition vector.hpp:584
real_t * GetData() const
Return a pointer to the beginning of the Vector data.
Definition vector.hpp:243
virtual real_t * HostReadWrite()
Shortcut for mfem::ReadWrite(vec.GetMemory(), vec.Size(), false).
Definition vector.hpp:540
void GetSubVector(const Array< int > &dofs, Vector &elemvect) const
Extract entries listed in dofs to the output Vector elemvect.
Definition vector.cpp:676
void MakeRef(Vector &base, int offset, int size)
Reset the Vector to be a reference to a sub-vector of base.
Definition vector.hpp:660
HYPRE_Int HYPRE_BigInt
float real_t
Definition config.hpp:46
void forall(int N, lambda &&body)
Definition forall.hpp:839
Helper struct to convert a C++ type to an MPI type.