MFEM v4.10.0
Finite element discretization library
Loading...
Searching...
No Matches
pgridfunc.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#include "../config/config.hpp"
13
14#ifdef MFEM_USE_MPI
15
16#include "fem.hpp"
17#include <iostream>
18#include <limits>
19#include "../general/forall.hpp"
20using namespace std;
21
22namespace mfem
23{
24
26 bool preserve)
27{
28 fes = pfes = pf;
29 SetDataAndSize(gf->GetData(), gf->Size());
30
31 if (pfes->HaveDofSigns())
32 {
33 MFEM_VERIFY(!preserve, "Differing sign conventions for the serial and "
34 "parallel grid functions will prevent preserving the serial "
35 "GridFunctions in this context.");
36
38 }
39}
40
46
48 const int *partitioning)
49{
50 const FiniteElementSpace *glob_fes = gf->FESpace();
51 // duplicate the FiniteElementCollection from 'gf'
53 // create a local ParFiniteElementSpace from the global one:
54 fes = pfes = new ParFiniteElementSpace(pmesh, glob_fes, partitioning,
55 fec_owned);
57
58 if (partitioning)
59 {
60 // Assumption: the map "local element id" -> "global element id" is
61 // increasing, i.e. the local numbering preserves the element order from
62 // the global numbering.
63 Array<int> gvdofs, lvdofs;
64 Vector lnodes;
65 int element_counter = 0;
66 const int MyRank = pfes->GetMyRank();
67 const int glob_ne = glob_fes->GetNE();
68 DofTransformation ltrans, gtrans;
69 for (int i = 0; i < glob_ne; i++)
70 {
71 if (partitioning[i] == MyRank)
72 {
73 pfes->GetElementVDofs(element_counter, lvdofs, ltrans);
74 glob_fes->GetElementVDofs(i, gvdofs, gtrans);
75 gf->GetSubVector(gvdofs, lnodes);
76 gtrans.InvTransformPrimal(lnodes);
77 ltrans.TransformPrimal(lnodes);
78 SetSubVector(lvdofs, lnodes);
79 element_counter++;
80 }
81 }
82 }
83}
84
85ParGridFunction::ParGridFunction(ParMesh *pmesh, std::istream &input)
86 : GridFunction(pmesh, input)
87{
88 // Convert the FiniteElementSpace, fes, to a ParFiniteElementSpace:
90 fes->GetOrdering());
91 delete fes;
92 fes = pfes;
93
95}
96
102
104{
107 pfes = dynamic_cast<ParFiniteElementSpace*>(f);
108 MFEM_ASSERT(pfes != NULL, "not a ParFiniteElementSpace");
109}
110
117
119{
122 pfes = dynamic_cast<ParFiniteElementSpace*>(f);
123 MFEM_ASSERT(pfes != NULL, "not a ParFiniteElementSpace");
124}
125
132
134{
136 GridFunction::MakeRef(f, v, v_offset);
137 pfes = dynamic_cast<ParFiniteElementSpace*>(f);
138 MFEM_ASSERT(pfes != NULL, "not a ParFiniteElementSpace");
139}
140
142{
144 GridFunction::MakeRef(f, v, v_offset);
145 pfes = f;
146}
147
149{
150 const Operator *prolong = pfes->GetProlongationMatrix();
151 prolong->Mult(*tv, *this);
152}
153
155{
156 pfes->Dof_TrueDof_Matrix()->Mult(a, *tv, 1.0, *this);
157}
158
160{
162 GetTrueDofs(*tv);
163 return tv;
164}
165
167{
168 MFEM_VERIFY(pfes->Conforming(), "not implemented for NC meshes");
171}
172
174{
175 MFEM_VERIFY(pfes->Conforming(), "not implemented for NC meshes");
178}
179
186
188{
189 pfes->GetRestrictionMatrix()->Mult(*this, tv);
190}
191
196
203
208
213
220
222{
224
225 if (pfes->GetFaceNbrVSize() <= 0)
226 {
227 return;
228 }
229
230 ParMesh *pmesh = pfes->GetParMesh();
231
234
235 int *send_offset = pfes->send_face_nbr_ldof.GetI();
236 const int *d_send_ldof = mfem::Read(pfes->send_face_nbr_ldof.GetJMemory(),
237 send_data.Size());
238 int *recv_offset = pfes->face_nbr_ldof.GetI();
239 MPI_Comm MyComm = pfes->GetComm();
240
241 const int num_face_nbrs = pmesh->GetNFaceNeighbors();
242 MPI_Request *requests = new MPI_Request[2*num_face_nbrs];
243 MPI_Request *send_requests = requests;
244 MPI_Request *recv_requests = requests + num_face_nbrs;
245 MPI_Status *statuses = new MPI_Status[num_face_nbrs];
246
247 auto d_data = this->Read();
248 auto d_send_data = send_data.Write();
249 mfem::forall(send_data.Size(), [=] MFEM_HOST_DEVICE (int i)
250 {
251 const int ldof = d_send_ldof[i];
252 d_send_data[i] = d_data[ldof >= 0 ? ldof : -1-ldof];
253 });
254
255 const bool mpi_gpu_aware = Device::GetGPUAwareMPI();
256 auto send_data_ptr = mpi_gpu_aware ? send_data.Read() : send_data.HostRead();
257 auto face_nbr_data_ptr = mpi_gpu_aware ? face_nbr_data.Write() :
259 // Wait for the kernel to be done since it updates what's sent and it may be async
260 if (mpi_gpu_aware) { MFEM_STREAM_SYNC; }
261 for (int fn = 0; fn < num_face_nbrs; fn++)
262 {
263 int nbr_rank = pmesh->GetFaceNbrRank(fn);
264 int tag = 0;
265
266 MPI_Isend(&send_data_ptr[send_offset[fn]],
267 send_offset[fn+1] - send_offset[fn],
268 MPITypeMap<real_t>::mpi_type, nbr_rank, tag, MyComm, &send_requests[fn]);
269
270 MPI_Irecv(&face_nbr_data_ptr[recv_offset[fn]],
271 recv_offset[fn+1] - recv_offset[fn],
272 MPITypeMap<real_t>::mpi_type, nbr_rank, tag, MyComm, &recv_requests[fn]);
273 }
274
275 MPI_Waitall(num_face_nbrs, send_requests, statuses);
276 MPI_Waitall(num_face_nbrs, recv_requests, statuses);
277
278 delete [] statuses;
279 delete [] requests;
280}
281
283const
284{
285 Array<int> dofs;
286 Vector DofVal, LocVec;
287 const int nbr_el_no = i - pfes->GetParMesh()->GetNE();
288 DofTransformation doftrans;
289 if (nbr_el_no >= 0)
290 {
291 int fes_vdim = pfes->GetVDim();
292 pfes->GetFaceNbrElementVDofs(nbr_el_no, dofs, doftrans);
293 // Choose fe to be of the order whose number of DOFs matches dofs.Size(),
294 // in the variable order case.
295 const int ndofs = pfes->IsVariableOrder() ? dofs.Size() : 0;
296 const FiniteElement *fe = pfes->GetFaceNbrFE(nbr_el_no, fes_vdim * ndofs);
297
298 if (fes_vdim > 1)
299 {
300 int s = dofs.Size()/fes_vdim;
301 Array<int> dofs_(&dofs[(vdim-1)*s], s);
302 face_nbr_data.GetSubVector(dofs_, LocVec);
303
304 DofVal.SetSize(s);
305 }
306 else
307 {
308 face_nbr_data.GetSubVector(dofs, LocVec);
309 DofVal.SetSize(dofs.Size());
310 }
311 doftrans.InvTransformPrimal(LocVec);
312
313 if (fe->GetMapType() == FiniteElement::VALUE)
314 {
315 fe->CalcShape(ip, DofVal);
316 }
317 else
318 {
321 Tr->SetIntPoint(&ip);
322 fe->CalcPhysShape(*Tr, DofVal);
323 }
324 }
325 else
326 {
327 fes->GetElementDofs(i, dofs, doftrans);
328 fes->DofsToVDofs(vdim-1, dofs);
329 DofVal.SetSize(dofs.Size());
330 const FiniteElement *fe = fes->GetFE(i);
331 if (fe->GetMapType() == FiniteElement::VALUE)
332 {
333 fe->CalcShape(ip, DofVal);
334 }
335 else
336 {
338 Tr->SetIntPoint(&ip);
339 fe->CalcPhysShape(*Tr, DofVal);
340 }
341 GetSubVector(dofs, LocVec);
342 doftrans.InvTransformPrimal(LocVec);
343 }
344
345 return (DofVal * LocVec);
346}
347
349 Vector &val) const
350{
351 const int nbr_el_no = i - pfes->GetParMesh()->GetNE();
352 if (nbr_el_no >= 0)
353 {
354 Array<int> dofs;
355 DofTransformation doftrans;
356 pfes->GetFaceNbrElementVDofs(nbr_el_no, dofs, doftrans);
357 Vector loc_data;
358 face_nbr_data.GetSubVector(dofs, loc_data);
359 doftrans.InvTransformPrimal(loc_data);
360 const FiniteElement *FElem = pfes->GetFaceNbrFE(nbr_el_no);
361 int dof = FElem->GetDof();
362 if (FElem->GetRangeType() == FiniteElement::SCALAR)
363 {
364 Vector shape(dof);
365 if (FElem->GetMapType() == FiniteElement::VALUE)
366 {
367 FElem->CalcShape(ip, shape);
368 }
369 else
370 {
373 Tr->SetIntPoint(&ip);
374 FElem->CalcPhysShape(*Tr, shape);
375 }
376 int vdim = fes->GetVDim();
377 val.SetSize(vdim);
378 for (int k = 0; k < vdim; k++)
379 {
380 val(k) = shape * (&loc_data[dof * k]);
381 }
382 }
383 else
384 {
385 int spaceDim = fes->GetMesh()->SpaceDimension();
386 DenseMatrix vshape(dof, spaceDim);
389 Tr->SetIntPoint(&ip);
390 FElem->CalcVShape(*Tr, vshape);
391 val.SetSize(spaceDim);
392 vshape.MultTranspose(loc_data, val);
393 }
394 }
395 else
396 {
398 }
399}
400
402 const IntegrationPoint &ip,
403 int comp, Vector *tr) const
404{
405 // We can assume faces and edges are local
407 {
408 return GridFunction::GetValue(T, ip, comp, tr);
409 }
410
411 // Check for evaluation in a local element
412 const int nbr_el_no = T.ElementNo - pfes->GetParMesh()->GetNE();
413 if (nbr_el_no < 0)
414 {
415 return GridFunction::GetValue(T, ip, comp, tr);
416 }
417
418 // Evaluate using DoFs from a neighboring element
419 if (tr)
420 {
421 T.SetIntPoint(&ip);
422 T.Transform(ip, *tr);
423 }
424
425 Array<int> dofs;
426 const FiniteElement * fe = pfes->GetFaceNbrFE(nbr_el_no);
427 DofTransformation doftrans;
428 pfes->GetFaceNbrElementVDofs(nbr_el_no, dofs, doftrans);
429
430 pfes->DofsToVDofs(comp-1, dofs);
431 Vector DofVal(dofs.Size()), LocVec;
432 if (fe->GetMapType() == FiniteElement::VALUE)
433 {
434 fe->CalcShape(ip, DofVal);
435 }
436 else
437 {
438 fe->CalcPhysShape(T, DofVal);
439 }
440 face_nbr_data.GetSubVector(dofs, LocVec);
441 doftrans.InvTransformPrimal(LocVec);
442
443
444 return (DofVal * LocVec);
445}
446
448 const IntegrationPoint &ip,
449 Vector &val, Vector *tr) const
450{
451 // We can assume faces and edges are local
453 {
454 return GridFunction::GetVectorValue(T, ip, val, tr);
455 }
456
457 // Check for evaluation in a local element
458 const int nbr_el_no = T.ElementNo - pfes->GetParMesh()->GetNE();
459 if (nbr_el_no < 0)
460 {
461 return GridFunction::GetVectorValue(T, ip, val, tr);
462 }
463
464 // Evaluate using DoFs from a neighboring element
465 if (tr)
466 {
467 T.SetIntPoint(&ip);
468 T.Transform(ip, *tr);
469 }
470
471 Array<int> vdofs;
472 DofTransformation doftrans;
473 pfes->GetFaceNbrElementVDofs(nbr_el_no, vdofs, doftrans);
474 Vector loc_data;
475 face_nbr_data.GetSubVector(vdofs, loc_data);
476 doftrans.InvTransformPrimal(loc_data);
477
478 const FiniteElement *fe = pfes->GetFaceNbrFE(nbr_el_no);
479 const int dof = fe->GetDof();
481 {
482 Vector shape(dof);
483 if (fe->GetMapType() == FiniteElement::VALUE)
484 {
485 fe->CalcShape(ip, shape);
486 }
487 else
488 {
489 fe->CalcPhysShape(T, shape);
490 }
491 int vdim = pfes->GetVDim();
492 val.SetSize(vdim);
493 for (int k = 0; k < vdim; k++)
494 {
495 val(k) = shape * (&loc_data[dof * k]);
496 }
497 }
498 else
499 {
500 int spaceDim = pfes->GetMesh()->SpaceDimension();
501 int vdim = std::max(spaceDim, fe->GetRangeDim());
502 DenseMatrix vshape(dof, vdim);
503 fe->CalcVShape(T, vshape);
504 val.SetSize(vdim);
505 vshape.MultTranspose(loc_data, val);
506 }
507}
508
510{
512 // Count the zones globally.
513 GroupCommunicator &gcomm = this->ParFESpace()->GroupComm();
514 gcomm.Reduce<int>(elem_per_vdof, GroupCommunicator::Sum);
515 gcomm.Bcast(elem_per_vdof);
516}
517
518void ParGridFunction::GetDerivative(int comp, int der_comp,
519 ParGridFunction &der) const
520{
521 Array<int> overlap;
522 AccumulateAndCountDerivativeValues(comp, der_comp, der, overlap);
523
524 // Count the zones globally.
525 GroupCommunicator &gcomm = der.ParFESpace()->GroupComm();
526 gcomm.Reduce<int>(overlap, GroupCommunicator::Sum);
527 gcomm.Bcast(overlap);
528
529 // Accumulate for all dofs.
531 gcomm.Bcast<real_t>(der.HostReadWrite());
532
533 for (int i = 0; i < overlap.Size(); i++)
534 {
535 der(i) /= overlap[i];
536 }
537}
538
539void ParGridFunction::GetElementDofValues(int el, Vector &dof_vals) const
540{
541 int ne = fes->GetNE();
542 if (el >= ne)
543 {
544 MFEM_ASSERT(face_nbr_data.Size() > 0,
545 "ParGridFunction::GetElementDofValues: ExchangeFaceNbrData "
546 "must be called before accessing face neighbor elements.");
547 // Face neighbor element
548 Array<int> dof_idx;
549 pfes->GetFaceNbrElementVDofs(el - ne, dof_idx);
550 face_nbr_data.GetSubVector(dof_idx, dof_vals);
551 }
552 else
553 {
555 }
556}
557
559{
560 MFEM_VERIFY(VectorDim() == 1,
561 "Cannot project scalar coefficient onto vector ParGridFunction");
562 DeltaCoefficient *delta_c = dynamic_cast<DeltaCoefficient *>(&coeff);
563
564 if (delta_c == NULL)
565 {
566 if (pfes->GetNURBSext())
567 {
568 // The serial ProjectCoefficient() may not initialize every dof. Such
569 // dofs will be set using the neighbor communication below.
570 (*this) = -infinity();
571 }
572
574
575 if (pfes->GetNURBSext())
576 {
577 // Replace uninitialized values with real values from neighbor ranks.
578 GroupCommunicator &gcomm = pfes->GroupComm();
580 gcomm.Bcast<real_t>(HostReadWrite());
581 }
582 }
583 else
584 {
585 real_t loc_integral, glob_integral;
586
587 ProjectDeltaCoefficient(*delta_c, loc_integral);
588
589 MPI_Allreduce(&loc_integral, &glob_integral, 1, MPITypeMap<real_t>::mpi_type,
590 MPI_SUM,
591 pfes->GetComm());
592
593 (*this) *= (delta_c->Scale() / glob_integral);
594 }
595}
596
598 ProjectType type)
599{
600 if (pfes->GetNURBSext())
601 {
602 // The serial ProjectCoefficient() may not initialize every dof. Such
603 // dofs will be set using the neighbor communication below.
604 (*this) = -infinity();
605 }
606
608
609 if (pfes->GetNURBSext())
610 {
611 // Replace uninitialized values with real values from neighbor ranks.
612 GroupCommunicator &gcomm = pfes->GroupComm();
614 gcomm.Bcast<real_t>(HostReadWrite());
615 }
616}
617
619 real_t rtol,
620 int iter)
621{
622 // Define and assemble linear form
624 b.AddDomainIntegrator(new DomainLFIntegrator(coeff));
625 b.Assemble();
626
627 // Define and assemble bilinear form
629 a.AddDomainIntegrator(new MassIntegrator());
630 a.Assemble();
631
632 // Configure solver
633 OperatorPtr A;
634 Vector B, X, &x(*this);
636 a.FormLinearSystem(ess_tdof_list, x, b, A, X, B);
637 Solver *prec = new HypreBoomerAMG;
638 CGSolver cg(pfes->GetComm());
639 cg.SetRelTol(rtol);
640 cg.SetMaxIter(iter);
641 cg.SetPrintLevel(0);
642 cg.SetPreconditioner(*prec);
643 cg.SetOperator(*A);
644 cg.Mult(B, X);
645 a.RecoverFEMSolution(X, b, x);
646 delete prec;
647}
648
650{
651 Vector Va;
652 ProjectCoefficientElementL2_(coeff, *this, Va);
653
654 GroupCommunicator &gcomm = pfes->GroupComm();
656 gcomm.Bcast<real_t>(HostReadWrite());
657
659 gcomm.Bcast<real_t>(Va.HostReadWrite());
660 (*this)/=Va;
661}
662
664 real_t rtol, int iter)
665{
666 // Define and assemble linear form
669
670 // Dimension argument to GetRangeType is arbitrary to be 3, could also be 2.
672 {
673 b.AddDomainIntegrator(new VectorFEDomainLFIntegrator(vcoeff));
674 a.AddDomainIntegrator(new VectorFEMassIntegrator());
675 }
676 else
677 {
678 b.AddDomainIntegrator(new VectorDomainLFIntegrator(vcoeff));
679 a.AddDomainIntegrator(new VectorMassIntegrator());
680 }
681 b.Assemble();
682 a.Assemble();
683
684 // Configure solver
685 OperatorPtr A;
686 Vector B, X, &x(*this);
687 x = 0.0;
689 a.FormLinearSystem(ess_tdof_list, x, b, A, X, B);
690 Solver *prec = new HypreBoomerAMG;
691 CGSolver cg(pfes->GetComm());
692 cg.SetRelTol(rtol);
693 cg.SetMaxIter(iter);
694 cg.SetPrintLevel(0);
695 cg.SetPreconditioner(*prec);
696 cg.SetOperator(*A);
697 cg.Mult(B, X);
698 a.RecoverFEMSolution(X, b, x);
699 delete prec;
700}
701
703{
705 {
706 Vector Va;
707 ProjectCoefficientElementL2_(vcoeff, *this, Va);
708
709 GroupCommunicator &gcomm = pfes->GroupComm();
711 gcomm.Bcast<real_t>(HostReadWrite());
712
714 gcomm.Bcast<real_t>(Va.HostReadWrite());
715 (*this)/=Va;
716 }
717 else
718 {
719 Array<int> vdofs(fes->GetNDofs());
720 Vector x, Va, gVa(Size());
721 VectorComponentCoefficient coeff(vcoeff,0);
722 *this = 0.0;
723 gVa = 0.0;
724 for (int v = 0; v < VectorDim(); v++)
725 {
726 coeff.SetComponent(v);
727 ProjectCoefficientElementL2_(coeff, x, Va);
728 fes->GetVDofs(v, vdofs);
729 SetSubVector(vdofs, x);
730 gVa.SetSubVector(vdofs, Va);
731 }
732
733 GroupCommunicator &gcomm = pfes->GroupComm();
735 gcomm.Bcast<real_t>(HostReadWrite());
736
738 gcomm.Bcast<real_t>(gVa.HostReadWrite());
739 *this /= gVa;
740 }
741}
742
743
745 std::variant<Coefficient*, VectorCoefficient*> coeff)
746{
747 // local maximal element attribute for each dof
748 Array<int> ldof_attr;
749
750 // local projection
751 GridFunction::ProjectDiscCoefficient(coeff, ldof_attr);
752
753 // global maximal element attribute for each dof
754 Array<int> gdof_attr;
755 ldof_attr.Copy(gdof_attr);
756 GroupCommunicator &gcomm = pfes->GroupComm();
757 gcomm.Reduce<int>(gdof_attr, GroupCommunicator::Max);
758 gcomm.Bcast(gdof_attr);
759
760 // set local value to zero if global maximal element attribute is larger than
761 // the local one, and mark (in gdof_attr) if we have the correct value
762 for (int i = 0; i < pfes->GetVSize(); i++)
763 {
764 if (gdof_attr[i] > ldof_attr[i])
765 {
766 (*this)(i) = 0.0;
767 gdof_attr[i] = 0;
768 }
769 else
770 {
771 gdof_attr[i] = 1;
772 }
773 }
774
775 // parallel averaging plus interpolation to determine final values
777 gcomm.Reduce<int>(gdof_attr, GroupCommunicator::Sum);
778 gcomm.Bcast(gdof_attr);
780 for (int i = 0; i < fes->GetVSize(); i++)
781 {
782 (*this)(i) /= gdof_attr[i];
783 }
784 this->ParallelAssemble(*tv);
785 this->Distribute(tv);
786 delete tv;
787}
788
789
791{
792 MFEM_VERIFY(
793 VectorDim() == 1,
794 "Cannot project scalar coefficient onto a vector ParGridFunction");
795 // Harmonic (x1 ... xn) = [ (1/x1 + ... + 1/xn) / n ]^-1.
796 // Arithmetic(x1 ... xn) = (x1 + ... + xn) / n.
797
798 // Number of zones that contain a given dof.
799 Array<int> zones_per_vdof;
800 AccumulateAndCountZones(coeff, type, zones_per_vdof);
801
802 // Count the zones globally.
803 GroupCommunicator &gcomm = pfes->GroupComm();
804 gcomm.Reduce<int>(zones_per_vdof, GroupCommunicator::Sum);
805 gcomm.Bcast(zones_per_vdof);
806
807 // Accumulate for all vdofs.
809 gcomm.Bcast(HostReadWrite());
810
811 ComputeMeans(type, zones_per_vdof);
812}
813
815 AvgType type)
816{
817 // Harmonic (x1 ... xn) = [ (1/x1 + ... + 1/xn) / n ]^-1.
818 // Arithmetic(x1 ... xn) = (x1 + ... + xn) / n.
819
820 MFEM_VERIFY(VectorDim() == vcoeff.GetVDim(), "vcoeff vdim != VectorDim()");
821
822 // Number of zones that contain a given dof.
823 Array<int> zones_per_vdof;
824 AccumulateAndCountZones(vcoeff, type, zones_per_vdof);
825
826 // Count the zones globally.
827 GroupCommunicator &gcomm = pfes->GroupComm();
828 gcomm.Reduce<int>(zones_per_vdof, GroupCommunicator::Sum);
829 gcomm.Bcast(zones_per_vdof);
830
831 // Accumulate for all vdofs.
833 gcomm.Bcast(HostReadWrite());
834
835 ComputeMeans(type, zones_per_vdof);
836}
837
839 Coefficient *coeff[], VectorCoefficient *vcoeff, const Array<int> &attr)
840{
841 Array<int> values_counter;
842 AccumulateAndCountBdrValues(coeff, vcoeff, attr, values_counter);
843
844 Vector values(Size());
845 for (int i = 0; i < values.Size(); i++)
846 {
847 values(i) = values_counter[i] ? (*this)(i) : 0.0;
848 }
849
850 // Count the values globally.
851 GroupCommunicator &gcomm = pfes->GroupComm();
852 gcomm.Reduce<int>(values_counter.HostReadWrite(), GroupCommunicator::Sum);
853 // Accumulate the values globally.
855
856 for (int i = 0; i < values.Size(); i++)
857 {
858 if (values_counter[i])
859 {
860 (*this)(i) = values(i)/values_counter[i];
861 }
862 }
863 // Broadcast values to other processors to have a consistent GridFunction
864 gcomm.Bcast<real_t>((*this).HostReadWrite());
865
866#ifdef MFEM_DEBUG
867 Array<int> ess_vdofs_marker;
868 if (vcoeff) { pfes->GetEssentialVDofs(attr, ess_vdofs_marker); }
869 else
870 {
871 ess_vdofs_marker.SetSize(Size());
872 ess_vdofs_marker = 0;
873 for (int i = 0; i < fes->GetVDim(); i++)
874 {
875 if (!coeff[i]) { continue; }
876 Array<int> component_dof_marker;
877 pfes->GetEssentialVDofs(attr, component_dof_marker,i);
878 for (int j = 0; j<Size(); j++)
879 {
880 ess_vdofs_marker[j] = bool(ess_vdofs_marker[j]) ||
881 bool(component_dof_marker[j]);
882 }
883 }
884 }
885 gcomm.Bcast<int>(values_counter.HostReadWrite());
886 for (int i = 0; i < values_counter.Size(); i++)
887 {
888 MFEM_ASSERT(bool(values_counter[i]) == bool(ess_vdofs_marker[i]),
889 "internal error");
890 }
891#endif
892}
893
895 const Array<int> &attr)
896{
897 ProjectBdrCoefficient(NULL, &vcoeff, attr);
898}
899
901 const Array<int> &bdr_attr)
902{
903 Array<int> values_counter;
904 AccumulateAndCountBdrTangentValues(vcoeff, bdr_attr, values_counter);
905
906 Vector values(Size());
907 for (int i = 0; i < values.Size(); i++)
908 {
909 values(i) = values_counter[i] ? (*this)(i) : 0.0;
910 }
911
912 // Count the values globally.
913 GroupCommunicator &gcomm = pfes->GroupComm();
914 gcomm.Reduce<int>(values_counter.HostReadWrite(), GroupCommunicator::Sum);
915 // Accumulate the values globally.
917
918 for (int i = 0; i < values.Size(); i++)
919 {
920 if (values_counter[i])
921 {
922 (*this)(i) = values(i)/values_counter[i];
923 }
924 }
925 // Broadcast values to other processors to have a consistent GridFunction
926 gcomm.Bcast<real_t>((*this).HostReadWrite());
927
928#ifdef MFEM_DEBUG
929 Array<int> ess_vdofs_marker;
930 pfes->GetEssentialVDofs(bdr_attr, ess_vdofs_marker);
931 gcomm.Bcast<int>(values_counter.HostReadWrite());
932 for (int i = 0; i < values_counter.Size(); i++)
933 {
934 MFEM_ASSERT(bool(values_counter[i]) == bool(ess_vdofs_marker[i]),
935 "internal error: " << pfes->GetLocalTDofNumber(i) << ' ' << bool(
936 values_counter[i]));
937 }
938#endif
939}
940
942 Coefficient *ell_coeff,
943 JumpScaling jump_scaling,
944 const IntegrationRule *irs[]) const
945{
946 const_cast<ParGridFunction *>(this)->ExchangeFaceNbrData();
947
948 int fdof, intorder, k;
949 ElementTransformation *transf;
950 Vector shape, el_dofs, err_val, ell_coeff_val;
951 Array<int> vdofs;
953 real_t error = 0.0;
954
955 ParMesh *mesh = pfes->GetParMesh();
956
957 std::map<int,int> local_to_shared;
958 for (int i = 0; i < mesh->GetNSharedFaces(); ++i)
959 {
960 int i_local = mesh->GetSharedFace(i);
961 local_to_shared[i_local] = i;
962 }
963
964 for (int i = 0; i < mesh->GetNumFaces(); i++)
965 {
966 real_t shared_face_factor = 1.0;
967 bool shared_face = false;
968 int iel1, iel2, info1, info2;
969 mesh->GetFaceElements(i, &iel1, &iel2);
970 mesh->GetFaceInfos(i, &info1, &info2);
971
972 real_t h = mesh->GetElementSize(iel1);
973 intorder = fes->GetFE(iel1)->GetOrder();
974
975 FaceElementTransformations *face_elem_transf;
976 const FiniteElement *fe1, *fe2;
977 if (info2 >= 0 && iel2 < 0)
978 {
979 int ishared = local_to_shared[i];
980 face_elem_transf = mesh->GetSharedFaceTransformations(ishared);
981 iel2 = face_elem_transf->Elem2No - mesh->GetNE();
982 fe2 = pfes->GetFaceNbrFE(iel2);
983 if ( (k = fe2->GetOrder()) > intorder )
984 {
985 intorder = k;
986 }
987 shared_face = true;
988 shared_face_factor = 0.5;
989 h = std::min(h, mesh->GetFaceNbrElementSize(iel2));
990 }
991 else
992 {
993 if (iel2 >= 0)
994 {
995 fe2 = pfes->GetFE(iel2);
996 if ( (k = fe2->GetOrder()) > intorder )
997 {
998 intorder = k;
999 }
1000 h = std::min(h, mesh->GetElementSize(iel2));
1001 }
1002 else
1003 {
1004 fe2 = NULL;
1005 }
1006 face_elem_transf = mesh->GetFaceElementTransformations(i);
1007 }
1008 int p = intorder;
1009
1010 intorder = 2 * intorder; // <-------------
1011 const IntegrationRule *ir;
1012 if (irs)
1013 {
1014 ir = irs[face_elem_transf->GetGeometryType()];
1015 }
1016 else
1017 {
1018 ir = &(IntRules.Get(face_elem_transf->GetGeometryType(), intorder));
1019 }
1020 err_val.SetSize(ir->GetNPoints());
1021 ell_coeff_val.SetSize(ir->GetNPoints());
1022 // side 1
1023 transf = face_elem_transf->Elem1;
1024 fe1 = fes->GetFE(iel1);
1025 fdof = fe1->GetDof();
1026 fes->GetElementVDofs(iel1, vdofs);
1027 shape.SetSize(fdof);
1028 el_dofs.SetSize(fdof);
1029 for (k = 0; k < fdof; k++)
1030 if (vdofs[k] >= 0)
1031 {
1032 el_dofs(k) = (*this)(vdofs[k]);
1033 }
1034 else
1035 {
1036 el_dofs(k) = - (*this)(-1-vdofs[k]);
1037 }
1038 for (int j = 0; j < ir->GetNPoints(); j++)
1039 {
1040 face_elem_transf->Loc1.Transform(ir->IntPoint(j), eip);
1041 fe1->CalcShape(eip, shape);
1042 transf->SetIntPoint(&eip);
1043 ell_coeff_val(j) = ell_coeff->Eval(*transf, eip);
1044 err_val(j) = exsol->Eval(*transf, eip) - (shape * el_dofs);
1045 }
1046 if (fe2 != NULL)
1047 {
1048 // side 2
1049 transf = face_elem_transf->Elem2;
1050 fdof = fe2->GetDof();
1051 shape.SetSize(fdof);
1052 el_dofs.SetSize(fdof);
1053 if (shared_face)
1054 {
1055 pfes->GetFaceNbrElementVDofs(iel2, vdofs);
1056 for (k = 0; k < fdof; k++)
1057 if (vdofs[k] >= 0)
1058 {
1059 el_dofs(k) = face_nbr_data[vdofs[k]];
1060 }
1061 else
1062 {
1063 el_dofs(k) = - face_nbr_data[-1-vdofs[k]];
1064 }
1065 }
1066 else
1067 {
1068 pfes->GetElementVDofs(iel2, vdofs);
1069 for (k = 0; k < fdof; k++)
1070 if (vdofs[k] >= 0)
1071 {
1072 el_dofs(k) = (*this)(vdofs[k]);
1073 }
1074 else
1075 {
1076 el_dofs(k) = - (*this)(-1 - vdofs[k]);
1077 }
1078 }
1079 for (int j = 0; j < ir->GetNPoints(); j++)
1080 {
1081 face_elem_transf->Loc2.Transform(ir->IntPoint(j), eip);
1082 fe2->CalcShape(eip, shape);
1083 transf->SetIntPoint(&eip);
1084 ell_coeff_val(j) += ell_coeff->Eval(*transf, eip);
1085 ell_coeff_val(j) *= 0.5;
1086 err_val(j) -= (exsol->Eval(*transf, eip) - (shape * el_dofs));
1087 }
1088 }
1089 real_t face_error = 0.0;
1090 transf = face_elem_transf;
1091 for (int j = 0; j < ir->GetNPoints(); j++)
1092 {
1093 const IntegrationPoint &ip = ir->IntPoint(j);
1094 transf->SetIntPoint(&ip);
1095 real_t nu = jump_scaling.Eval(h, p);
1096 face_error += shared_face_factor*(ip.weight * nu * ell_coeff_val(j) *
1097 transf->Weight() *
1098 err_val(j) * err_val(j));
1099 }
1100 // negative quadrature weights may cause the error to be negative
1101 error += fabs(face_error);
1102 }
1103
1104 error = sqrt(error);
1105 return GlobalLpNorm(2.0, error, pfes->GetComm());
1106}
1107
1108void ParGridFunction::Save(std::ostream &os) const
1109{
1110 // We use const_cast + HostRead (instead of HostReadWrite) because we only
1111 // need to change the host data temporarily and this way we do not invalidate
1112 // the data if it is on device. If we use HostReadWrite here, later calls to
1113 // Read or ReadWrite will need to copy the data from host to device. With the
1114 // approach used here, the host-to-device copy is avoided.
1115 real_t *h_data = const_cast<real_t*>(HostRead());
1116 pfes->ApplyDofSigns(h_data);
1117
1119
1120 pfes->ApplyDofSigns(h_data);
1121}
1122
1123void ParGridFunction::Save(const char *fname, int precision) const
1124{
1125 int rank = pfes->GetMyRank();
1126 ostringstream fname_with_suffix;
1127 fname_with_suffix << fname << "." << setfill('0') << setw(6) << rank;
1128 ofstream ofs(fname_with_suffix.str().c_str());
1129 ofs.precision(precision);
1130 Save(ofs);
1131}
1132
1133void ParGridFunction::SaveAsOne(const char *fname, int precision) const
1134{
1135 ofstream ofs;
1136 int rank = pfes->GetMyRank();
1137 if (rank == 0)
1138 {
1139 ofs.open(fname);
1140 ofs.precision(precision);
1141 }
1142 SaveAsOne(ofs);
1143}
1144
1145void ParGridFunction::SaveAsSerial(const char *fname, int precision,
1146 int save_rank) const
1147{
1148 ParMesh *pmesh = ParFESpace()->GetParMesh();
1149 Mesh serial_mesh = pmesh->GetSerialMesh(save_rank);
1150 GridFunction serialgf = GetSerialGridFunction(save_rank, serial_mesh);
1151
1152 if (pmesh->GetMyRank() == save_rank)
1153 {
1154 serialgf.Save(fname, precision);
1155 }
1156 MPI_Barrier(pmesh->GetComm());
1157}
1158
1160 int save_rank, FiniteElementSpace &serial_fes) const
1161{
1162 ParFiniteElementSpace *pfespace = ParFESpace();
1163 ParMesh *pmesh = pfespace->GetParMesh();
1164
1165 GridFunction serial_gf(&serial_fes);
1166
1167 Array<real_t> vals;
1168 Array<int> dofs;
1169 MPI_Status status;
1170
1171 const int vdim = pfespace->GetVDim();
1172
1173 const int my_rank = pmesh->GetMyRank();
1174 const int nranks = pmesh->GetNRanks();
1175 MPI_Comm comm = pmesh->GetComm();
1176
1177 if (my_rank == save_rank)
1178 {
1179 int elem_count = 0; // To keep track of element count in serial mesh
1180
1181 Vector nodeval;
1182 for (int e = 0; e < pmesh->GetNE(); e++)
1183 {
1184 GetElementDofValues(e, nodeval);
1185 serial_fes.GetElementVDofs(elem_count++, dofs);
1186 serial_gf.SetSubVector(dofs, nodeval);
1187 }
1188
1189 for (int p = 0; p < nranks; p++)
1190 {
1191 if (p == save_rank) { continue; }
1192 int n_send_recv;
1193 MPI_Recv(&n_send_recv, 1, MPI_INT, p, 448, comm, &status);
1194 vals.SetSize(n_send_recv);
1195 if (n_send_recv)
1196 {
1197 MPI_Recv(&vals[0], n_send_recv, MPITypeMap<real_t>::mpi_type, p, 449, comm,
1198 &status);
1199 }
1200 for (int i = 0; i < n_send_recv; )
1201 {
1202 serial_fes.GetElementVDofs(elem_count++, dofs);
1203 serial_gf.SetSubVector(dofs, &vals[i]);
1204 i += dofs.Size();
1205 }
1206 }
1207 } // my_rank == save_rank
1208 else
1209 {
1210 int n_send_recv = 0;
1211 Vector nodeval;
1212 for (int e = 0; e < pmesh->GetNE(); e++)
1213 {
1214 const FiniteElement *fe = pfespace->GetFE(e);
1215 n_send_recv += vdim*fe->GetDof();
1216 }
1217 MPI_Send(&n_send_recv, 1, MPI_INT, save_rank, 448, comm);
1218 vals.Reserve(n_send_recv);
1219 vals.SetSize(0);
1220 for (int e = 0; e < pmesh->GetNE(); e++)
1221 {
1222 GetElementDofValues(e, nodeval);
1223 for (int j = 0; j < nodeval.Size(); j++)
1224 {
1225 vals.Append(nodeval(j));
1226 }
1227 }
1228 if (n_send_recv)
1229 {
1230 MPI_Send(&vals[0], n_send_recv, MPITypeMap<real_t>::mpi_type, save_rank, 449,
1231 comm);
1232 }
1233 }
1234
1235 return serial_gf;
1236}
1237
1239 Mesh &serial_mesh) const
1240{
1241 auto *serial_fec = pfes->FEColl()->Clone(pfes->FEColl()->GetOrder());
1242 auto *serial_fes = new FiniteElementSpace(&serial_mesh,
1243 serial_fec,
1244 pfes->GetVDim(),
1245 pfes->GetOrdering());
1246 GridFunction serial_gf = GetSerialGridFunction(save_rank, *serial_fes);
1247 serial_gf.MakeOwner(serial_fec); // Also assumes ownership of serial_fes
1248 return serial_gf;
1249}
1250
1251#ifdef MFEM_USE_ADIOS2
1253 const std::string& variable_name,
1254 const adios2stream::data_type type) const
1255{
1256 real_t *data_ = const_cast<real_t*>(HostRead());
1257 for (int i = 0; i < size; i++)
1258 {
1259 if (pfes->GetDofSign(i) < 0) { data_[i] = -data_[i]; }
1260 }
1261
1262 GridFunction::Save(os, variable_name, type);
1263
1264 for (int i = 0; i < size; i++)
1265 {
1266 if (pfes->GetDofSign(i) < 0) { data_[i] = -data_[i]; }
1267 }
1268}
1269#endif
1270
1271void ParGridFunction::SaveAsOne(std::ostream &os) const
1272{
1273 int i, p;
1274
1275 MPI_Comm MyComm;
1276 MPI_Status status;
1277 int MyRank, NRanks;
1278
1279 MyComm = pfes -> GetComm();
1280
1281 MPI_Comm_size(MyComm, &NRanks);
1282 MPI_Comm_rank(MyComm, &MyRank);
1283
1284 real_t **values = new real_t*[NRanks];
1285 int *nv = new int[NRanks];
1286 int *nvdofs = new int[NRanks];
1287 int *nedofs = new int[NRanks];
1288 int *nfdofs = new int[NRanks];
1289 int *nrdofs = new int[NRanks];
1290
1291 // We use const_cast + HostRead (instead of HostReadWrite) because we only
1292 // need to change the host data temporarily and this way we do not invalidate
1293 // the data if it is on device. If we use HostReadWrite here, later calls to
1294 // Read or ReadWrite will need to copy the data from host to device. With the
1295 // approach used here, the host-to-device copy is avoided.
1296 real_t * h_data = const_cast<real_t *>(this->HostRead());
1297 pfes->ApplyDofSigns(h_data); // temporarily flip the dof signs
1298
1299 values[0] = h_data;
1300 nv[0] = pfes -> GetVSize();
1301 nvdofs[0] = pfes -> GetNVDofs();
1302 nedofs[0] = pfes -> GetNEDofs();
1303 nfdofs[0] = pfes -> GetNFDofs();
1304
1305 if (MyRank == 0)
1306 {
1307 pfes -> Save(os);
1308 os << '\n';
1309
1310 for (p = 1; p < NRanks; p++)
1311 {
1312 MPI_Recv(&nv[p], 1, MPI_INT, p, 455, MyComm, &status);
1313 MPI_Recv(&nvdofs[p], 1, MPI_INT, p, 456, MyComm, &status);
1314 MPI_Recv(&nedofs[p], 1, MPI_INT, p, 457, MyComm, &status);
1315 MPI_Recv(&nfdofs[p], 1, MPI_INT, p, 458, MyComm, &status);
1316 values[p] = new real_t[nv[p]];
1317 MPI_Recv(values[p], nv[p], MPITypeMap<real_t>::mpi_type, p, 460, MyComm,
1318 &status);
1319 }
1320
1321 int vdim = pfes -> GetVDim();
1322
1323 for (p = 0; p < NRanks; p++)
1324 {
1325 nrdofs[p] = nv[p]/vdim - nvdofs[p] - nedofs[p] - nfdofs[p];
1326 }
1327
1329 {
1330 for (int d = 0; d < vdim; d++)
1331 {
1332 for (p = 0; p < NRanks; p++)
1333 for (i = 0; i < nvdofs[p]; i++)
1334 {
1335 os << *values[p]++ << '\n';
1336 }
1337
1338 for (p = 0; p < NRanks; p++)
1339 for (i = 0; i < nedofs[p]; i++)
1340 {
1341 os << *values[p]++ << '\n';
1342 }
1343
1344 for (p = 0; p < NRanks; p++)
1345 for (i = 0; i < nfdofs[p]; i++)
1346 {
1347 os << *values[p]++ << '\n';
1348 }
1349
1350 for (p = 0; p < NRanks; p++)
1351 for (i = 0; i < nrdofs[p]; i++)
1352 {
1353 os << *values[p]++ << '\n';
1354 }
1355 }
1356 }
1357 else
1358 {
1359 for (p = 0; p < NRanks; p++)
1360 for (i = 0; i < nvdofs[p]; i++)
1361 for (int d = 0; d < vdim; d++)
1362 {
1363 os << *values[p]++ << '\n';
1364 }
1365
1366 for (p = 0; p < NRanks; p++)
1367 for (i = 0; i < nedofs[p]; i++)
1368 for (int d = 0; d < vdim; d++)
1369 {
1370 os << *values[p]++ << '\n';
1371 }
1372
1373 for (p = 0; p < NRanks; p++)
1374 for (i = 0; i < nfdofs[p]; i++)
1375 for (int d = 0; d < vdim; d++)
1376 {
1377 os << *values[p]++ << '\n';
1378 }
1379
1380 for (p = 0; p < NRanks; p++)
1381 for (i = 0; i < nrdofs[p]; i++)
1382 for (int d = 0; d < vdim; d++)
1383 {
1384 os << *values[p]++ << '\n';
1385 }
1386 }
1387
1388 for (p = 1; p < NRanks; p++)
1389 {
1390 values[p] -= nv[p];
1391 delete [] values[p];
1392 }
1393 os.flush();
1394 }
1395 else
1396 {
1397 MPI_Send(&nv[0], 1, MPI_INT, 0, 455, MyComm);
1398 MPI_Send(&nvdofs[0], 1, MPI_INT, 0, 456, MyComm);
1399 MPI_Send(&nedofs[0], 1, MPI_INT, 0, 457, MyComm);
1400 MPI_Send(&nfdofs[0], 1, MPI_INT, 0, 458, MyComm);
1401 MPI_Send(h_data, nv[0], MPITypeMap<real_t>::mpi_type, 0, 460, MyComm);
1402 }
1403
1404 pfes->ApplyDofSigns(h_data); // restore the original h_data
1405
1406 delete [] values;
1407 delete [] nv;
1408 delete [] nvdofs;
1409 delete [] nedofs;
1410 delete [] nfdofs;
1411 delete [] nrdofs;
1412}
1413
1414real_t GlobalLpNorm(const real_t p, real_t loc_norm, MPI_Comm comm)
1415{
1416 real_t glob_norm;
1417
1418 // negative quadrature weights may cause the local norm to be negative
1419 loc_norm = fabs(loc_norm);
1420
1421 if (p < infinity())
1422 {
1423 loc_norm = pow(loc_norm, p);
1424
1425 MPI_Allreduce(&loc_norm, &glob_norm, 1, MPITypeMap<real_t>::mpi_type,
1426 MPI_SUM, comm);
1427
1428 glob_norm = pow(fabs(glob_norm), 1.0/p);
1429 }
1430 else
1431 {
1432 MPI_Allreduce(&loc_norm, &glob_norm, 1, MPITypeMap<real_t>::mpi_type,
1433 MPI_MAX, comm);
1434 }
1435
1436 return glob_norm;
1437}
1438
1441 GridFunction &flux, bool wcoef, int subdomain)
1442{
1443 ParFiniteElementSpace *ffes =
1444 dynamic_cast<ParFiniteElementSpace*>(flux.FESpace());
1445 MFEM_VERIFY(ffes, "the flux FE space must be ParFiniteElementSpace");
1446
1447 Array<int> count(flux.Size());
1448 SumFluxAndCount(blfi, flux, count, wcoef, subdomain);
1449
1450 // Accumulate flux and counts in parallel
1452 ffes->GroupComm().Bcast<real_t>(flux.HostReadWrite());
1453
1455 ffes->GroupComm().Bcast<int>(count.HostReadWrite());
1456
1457 // complete averaging
1458 for (int i = 0; i < count.Size(); i++)
1459 {
1460 if (count[i] != 0) { flux(i) /= count[i]; }
1461 }
1462
1463 if (ffes->Nonconforming())
1464 {
1465 // On a partially conforming flux space, project on the conforming space.
1466 // Using this code may lead to worse refinements in ex6, so we do not use
1467 // it by default.
1468
1469 // Vector conf_flux;
1470 // flux.ConformingProject(conf_flux);
1471 // flux.ConformingProlongate(conf_flux);
1472 }
1473}
1474
1475std::unique_ptr<ParGridFunction> ParGridFunction::ProlongateToMaxOrder() const
1476{
1477 ParMesh *mesh = pfes->GetParMesh();
1478 const FiniteElementCollection *pfesc = pfes->FEColl();
1479 const int vdim = pfes->GetVDim();
1480
1481 // Find the max order in the space
1482 const int maxOrder = pfes->GetMaxElementOrder();
1483
1484 // Create a visualization space of max order for all elements
1485 FiniteElementCollection *fecMax = pfesc->Clone(maxOrder);
1486 ParFiniteElementSpace *pfesMax = new ParFiniteElementSpace(mesh, fecMax, vdim,
1487 pfes->GetOrdering());
1488
1489 ParGridFunction *xMax = new ParGridFunction(pfesMax);
1490
1491 // Interpolate in the maximum-order space
1492 PRefinementTransferOperator P(*pfes, *pfesMax);
1493 P.Mult(*this, *xMax);
1494
1495 xMax->MakeOwner(fecMax);
1496 return std::unique_ptr<ParGridFunction>(xMax);
1497}
1498
1500 const ParGridFunction &x,
1501 ParFiniteElementSpace &smooth_flux_fes,
1502 ParFiniteElementSpace &flux_fes,
1503 Vector &errors,
1504 int norm_p, real_t solver_tol, int solver_max_it)
1505{
1506 // Compute fluxes in discontinuous space
1507 GridFunction flux(&flux_fes);
1508 flux = 0.0;
1509
1511 Array<int> xdofs, fdofs;
1512 Vector el_x, el_f;
1513 DofTransformation xtrans, ftrans;
1514
1515 for (int i = 0; i < xfes->GetNE(); i++)
1516 {
1517 xfes->GetElementVDofs(i, xdofs, xtrans);
1518 x.GetSubVector(xdofs, el_x);
1519 xtrans.InvTransformPrimal(el_x);
1520
1522 flux_integrator.ComputeElementFlux(*xfes->GetFE(i), *Transf, el_x,
1523 *flux_fes.GetFE(i), el_f, false);
1524
1525 flux_fes.GetElementVDofs(i, fdofs, ftrans);
1526 ftrans.TransformPrimal(el_f);
1527 flux.SetSubVector(fdofs, el_f);
1528 }
1529
1530 // Assemble the linear system for L2 projection into the "smooth" space
1531 ParBilinearForm *a = new ParBilinearForm(&smooth_flux_fes);
1532 ParLinearForm *b = new ParLinearForm(&smooth_flux_fes);
1534
1535 const FiniteElement *smooth_flux_fe = smooth_flux_fes.GetTypicalFE();
1536
1537 if (smooth_flux_fe->GetRangeType() == FiniteElement::SCALAR)
1538 {
1540 vmass->SetVDim(smooth_flux_fes.GetVDim());
1541 a->AddDomainIntegrator(vmass);
1542 b->AddDomainIntegrator(new VectorDomainLFIntegrator(f));
1543 }
1544 else
1545 {
1546 a->AddDomainIntegrator(new VectorFEMassIntegrator);
1547 b->AddDomainIntegrator(new VectorFEDomainLFIntegrator(f));
1548 }
1549
1550 b->Assemble();
1551 a->Assemble();
1552 a->Finalize();
1553
1554 // The destination of the projected discontinuous flux
1555 ParGridFunction smooth_flux(&smooth_flux_fes);
1556 smooth_flux = 0.0;
1557
1558 HypreParMatrix* A = a->ParallelAssemble();
1559 HypreParVector* B = b->ParallelAssemble();
1560 HypreParVector* X = smooth_flux.ParallelProject();
1561
1562 delete a;
1563 delete b;
1564
1565 // Define and apply a parallel PCG solver for AX=B with the BoomerAMG
1566 // preconditioner from hypre.
1567 HypreBoomerAMG *amg = new HypreBoomerAMG(*A);
1568 amg->SetPrintLevel(0);
1569 HyprePCG *pcg = new HyprePCG(*A);
1570 pcg->SetTol(solver_tol);
1571 pcg->SetMaxIter(solver_max_it);
1572 pcg->SetPrintLevel(0);
1573 pcg->SetPreconditioner(*amg);
1574 pcg->Mult(*B, *X);
1575
1576 // Extract the parallel grid function corresponding to the finite element
1577 // approximation X. This is the local solution on each processor.
1578 smooth_flux = *X;
1579
1580 delete A;
1581 delete B;
1582 delete X;
1583 delete amg;
1584 delete pcg;
1585
1586 // Proceed through the elements one by one, and find the Lp norm differences
1587 // between the flux as computed per element and the flux projected onto the
1588 // smooth_flux_fes space.
1589 real_t total_error = 0.0;
1590 errors.SetSize(xfes->GetNE());
1591 for (int i = 0; i < xfes->GetNE(); i++)
1592 {
1593 errors(i) = ComputeElementLpDistance(norm_p, i, smooth_flux, flux);
1594 total_error += pow(errors(i), norm_p);
1595 }
1596
1597 real_t glob_error;
1598 MPI_Allreduce(&total_error, &glob_error, 1, MPITypeMap<real_t>::mpi_type,
1599 MPI_SUM,
1600 xfes->GetComm());
1601
1602 return pow(glob_error, 1.0/norm_p);
1603}
1604
1606 const int ref_factor, const int vdim) const
1607{
1608 PLBound plb = GridFunction::GetBounds(lower, upper, ref_factor, vdim);
1609 int siz = vdim > 0 ? 1 : fes->GetVDim();
1610 MPI_Allreduce(MPI_IN_PLACE, lower.HostReadWrite(), siz,
1611 MFEM_MPI_REAL_T, MPI_MIN, pfes->GetComm());
1612 MPI_Allreduce(MPI_IN_PLACE, upper.HostReadWrite(), siz,
1613 MFEM_MPI_REAL_T, MPI_MAX, pfes->GetComm());
1614 return plb;
1615}
1616
1618 const int vdim, const PLBound &plb, const int max_depth,
1619 const real_t tol) const
1620{
1621 std::pair<real_t, real_t> minmax =
1622 GridFunction::EstimateFunctionMinimum(vdim, plb, max_depth, tol);
1623
1624 real_t glob_min_lower = minmax.first;
1625 real_t glob_min_upper = minmax.second;
1626 MPI_Allreduce(MPI_IN_PLACE, &glob_min_lower, 1,
1627 MFEM_MPI_REAL_T, MPI_MIN, pfes->GetComm());
1628 MPI_Allreduce(MPI_IN_PLACE, &glob_min_upper, 1,
1629 MFEM_MPI_REAL_T, MPI_MIN, pfes->GetComm());
1630
1631 return std::make_pair(glob_min_lower, glob_min_upper);
1632}
1633
1635 const int vdim, const PLBound &plb, const int max_depth,
1636 const real_t tol) const
1637{
1638 std::pair<real_t, real_t> minmax =
1639 GridFunction::EstimateFunctionMaximum(vdim, plb, max_depth, tol);
1640
1641 real_t glob_max_lower = minmax.first;
1642 real_t glob_max_upper = minmax.second;
1643 MPI_Allreduce(MPI_IN_PLACE, &glob_max_lower, 1,
1644 MFEM_MPI_REAL_T, MPI_MAX, pfes->GetComm());
1645 MPI_Allreduce(MPI_IN_PLACE, &glob_max_upper, 1,
1646 MFEM_MPI_REAL_T, MPI_MAX, pfes->GetComm());
1647 return std::make_pair(glob_max_lower, glob_max_upper);
1648}
1649
1650} // namespace mfem
1651
1652#endif // MFEM_USE_MPI
void Reserve(int capacity)
Ensures that the allocated size is at least the given size.
Definition array.hpp:210
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
int Append(const T &el)
Append element 'el' to array, resize if necessary.
Definition array.hpp:941
void Copy(Array &copy) const
Create a copy of the internal array to the provided copy.
Definition array.hpp:1071
T * HostReadWrite()
Shortcut for mfem::ReadWrite(a.GetMemory(), a.Size(), false).
Definition array.hpp:430
Abstract base class BilinearFormIntegrator.
virtual void ComputeElementFlux(const FiniteElement &el, ElementTransformation &Trans, Vector &u, const FiniteElement &fluxelem, Vector &flux, bool with_coef=true, const IntegrationRule *ir=NULL)
Virtual method required for Zienkiewicz-Zhu type error estimators.
Conjugate gradient method.
Definition solvers.hpp:627
Base class Coefficients that optionally depend on space and time. These are used by the BilinearFormI...
virtual real_t Eval(ElementTransformation &T, const IntegrationPoint &ip)=0
Evaluate the coefficient in the element described by T at the point ip.
Delta function coefficient optionally multiplied by a weight coefficient and a scaled time dependent ...
real_t Scale()
Return the scale factor times the optional time dependent function. Returns with when not set by th...
Data type dense matrix using column-major storage.
Definition densemat.hpp:24
void MultTranspose(const real_t *x, real_t *y) const
Multiply a vector with the transpose matrix.
Definition densemat.cpp:158
static bool GetGPUAwareMPI()
Get the status of GPU-aware MPI flag.
Definition device.hpp:319
void InvTransformPrimal(real_t *v) const
Definition doftrans.cpp:47
void TransformPrimal(real_t *v) const
Definition doftrans.cpp:17
Class for domain integration .
Definition lininteg.hpp:108
Geometry::Type GetGeometryType() const
Return the Geometry::Type of the reference element.
Definition eltrans.hpp:175
real_t Weight()
Return the weight of the Jacobian matrix of the transformation at the currently set IntegrationPoint....
Definition eltrans.hpp:144
void SetIntPoint(const IntegrationPoint *ip)
Set the integration point ip that weights and Jacobians will be evaluated at.
Definition eltrans.hpp:106
virtual void Transform(const IntegrationPoint &, Vector &)=0
Transform integration point from reference coordinates to physical coordinates and store them in the ...
A specialized ElementTransformation class representing a face and its two neighboring elements.
Definition eltrans.hpp:750
ElementTransformation * Elem2
Definition eltrans.hpp:791
ElementTransformation * Elem1
Definition eltrans.hpp:791
IntegrationPointTransformation Loc1
Definition eltrans.hpp:793
IntegrationPointTransformation Loc2
Definition eltrans.hpp:793
Collection of finite elements from the same family in multiple dimensions. This class is used to matc...
Definition fe_coll.hpp:27
int GetRangeType(int dim) const
Definition fe_coll.cpp:40
static FiniteElementCollection * New(const char *name)
Factory method: return a newly allocated FiniteElementCollection according to the given name.
Definition fe_coll.cpp:124
int GetOrder() const
Return the order (polynomial degree) of the FE collection, corresponding to the order/degree returned...
Definition fe_coll.hpp:248
virtual FiniteElementCollection * Clone(int p) const
Instantiate a new collection of the same type with a different order.
Definition fe_coll.cpp:462
virtual const char * Name() const
Definition fe_coll.hpp:79
Class FiniteElementSpace - responsible for providing FEM view of the mesh, mainly managing the set of...
Definition fespace.hpp:210
void GetVDofs(int vd, Array< int > &dofs, int ndofs=-1) const
Returns the indices of all of the VDofs for the specified dimension 'vd'.
Definition fespace.cpp:212
bool IsVariableOrder() const
Returns true if the space contains elements of varying polynomial orders.
Definition fespace.hpp:673
void DofsToVDofs(Array< int > &dofs, int ndofs=-1) const
Compute the full set of vdofs corresponding to each entry in dofs.
Definition fespace.cpp:232
DofTransformation * GetElementDofs(int elem, Array< int > &dofs) const
Returns indices of degrees of freedom of element 'elem'. The returned indices are offsets into an ldo...
Definition fespace.cpp:3538
ElementTransformation * GetElementTransformation(int i) const
Definition fespace.hpp:903
int GetNDofs() const
Returns number of degrees of freedom. This is the number of Local Degrees of Freedom.
Definition fespace.hpp:821
const NURBSExtension * GetNURBSext() const
Definition fespace.hpp:641
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:299
virtual const FiniteElement * GetFE(int i) const
Returns pointer to the FiniteElement in the FiniteElementCollection associated with i'th element in t...
Definition fespace.cpp:3860
Ordering::Type GetOrdering() const
Return the ordering method.
Definition fespace.hpp:852
int GetNE() const
Returns number of elements in the mesh.
Definition fespace.hpp:867
const FiniteElementCollection * FEColl() const
Definition fespace.hpp:854
Mesh * GetMesh() const
Returns the mesh.
Definition fespace.hpp:639
int GetVSize() const
Return the number of vector dofs, i.e. GetNDofs() x GetVDim().
Definition fespace.hpp:824
int GetVDim() const
Returns the vector dimension of the finite element space.
Definition fespace.hpp:817
const FiniteElement * GetTypicalFE() const
Return GetFE(0) if the local mesh is not empty; otherwise return a typical FE based on the Geometry t...
Definition fespace.cpp:3896
Abstract class for all finite elements.
Definition fe_base.hpp:294
virtual void CalcVShape(const IntegrationPoint &ip, DenseMatrix &shape) const
Evaluate the values of all shape functions of a vector finite element in reference space at the given...
Definition fe_base.cpp:50
int GetRangeDim() const
Returns the vector dimension for vector-valued finite elements, which is also the dimension of the in...
Definition fe_base.hpp:387
int GetOrder() const
Returns the order of the finite element. In the case of anisotropic orders, returns the maximum order...
Definition fe_base.hpp:414
int GetMapType() const
Returns the FiniteElement::MapType of the element describing how reference functions are mapped to ph...
Definition fe_base.hpp:436
int GetRangeType() const
Returns the FiniteElement::RangeType of the element, one of {SCALAR, VECTOR}.
Definition fe_base.hpp:427
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const =0
Evaluate the values of all shape functions of a scalar finite element in reference space at the given...
int GetDof() const
Returns the number of degrees of freedom in the finite element.
Definition fe_base.hpp:410
void CalcPhysShape(ElementTransformation &Trans, Vector &shape) const
Evaluate the values of all shape functions of a scalar finite element in physical space at the point ...
Definition fe_base.cpp:192
Class for grid function - Vector with associated FE space.
Definition gridfunc.hpp:53
void AccumulateAndCountBdrTangentValues(VectorCoefficient &vcoeff, const Array< int > &bdr_attr, Array< int > &values_counter)
virtual void CountElementsPerVDof(Array< int > &elem_per_vdof) const
For each vdof, counts how many elements contain the vdof, as containment is determined by FiniteEleme...
virtual real_t GetValue(int i, const IntegrationPoint &ip, int vdim=1) const
Definition gridfunc.cpp:429
void AccumulateAndCountBdrValues(Coefficient *coeff[], VectorCoefficient *vcoeff, const Array< int > &attr, Array< int > &values_counter)
virtual void Update()
Transform by the Space UpdateMatrix (e.g., on Mesh change).
Definition gridfunc.cpp:169
virtual PLBound GetBounds(Vector &lower, Vector &upper, const int ref_factor=1, const int vdim=-1) const
virtual void MakeRef(FiniteElementSpace *f, real_t *v)
Make the GridFunction reference external data on a new FiniteElementSpace.
Definition gridfunc.cpp:235
virtual void Save(std::ostream &out) const
Save the GridFunction to an output stream.
void MakeOwner(FiniteElementCollection *fec_)
Make the GridFunction the owner of fec_owned and fes.
Definition gridfunc.hpp:160
virtual void GetElementDofValues(int el, Vector &dof_vals) const
virtual void ProjectDiscCoefficient(std::variant< Coefficient *, VectorCoefficient * > coeff, Array< int > &dof_attr)
Project a discontinuous (vector) coefficient as a grid function on a continuous finite element space....
FiniteElementSpace * FESpace()
std::pair< real_t, real_t > EstimateFunctionMinimum(const int elem, const PLBound &plb, const int vdim, const int max_depth, const real_t tol, real_t &min_threshold) const
Estimate the minimum value of the GridFunction in element elem if it is below a certain min_threshold...
void ComputeMeans(AvgType type, const Array< int > &zones_per_vdof)
std::pair< real_t, real_t > EstimateFunctionMaximum(const int elem, const PLBound &plb, const int vdim, const int max_depth, const real_t tol, real_t &max_threshold) const
Estimate the maximum value of the GridFunction in element elem if it is above a certain max_threshold...
void ProjectDeltaCoefficient(DeltaCoefficient &delta_coeff, real_t &integral)
FiniteElementSpace * fes
FE space on which the grid function lives. Owned if fec_owned is not NULL.
Definition gridfunc.hpp:56
int VectorDim() const
Shortcut for calling FiniteElementSpace::GetVectorDim() on the underlying fes.
Definition gridfunc.hpp:166
FiniteElementCollection * fec_owned
Used when the grid function is read from a file. It can also be set explicitly, see MakeOwner().
Definition gridfunc.hpp:62
void SumFluxAndCount(BilinearFormIntegrator &blfi, GridFunction &flux, Array< int > &counts, bool wcoef, int subdomain)
Definition gridfunc.cpp:283
virtual void ProjectCoefficient(Coefficient &coeff, ProjectType type=ProjectType::DEFAULT)
Project coeff Coefficient to this GridFunction. The projection computation depends on the choice of t...
void AccumulateAndCountDerivativeValues(int comp, int der_comp, GridFunction &der, Array< int > &zones_per_dof) const
Used for the serial and parallel implementations of the GetDerivative() method; see its documentation...
void ProjectCoefficientElementL2_(Coefficient &coeff, Vector &sol, Vector &Va)
virtual void GetVectorValue(int i, const IntegrationPoint &ip, Vector &val) const
Definition gridfunc.cpp:454
void AccumulateAndCountZones(Coefficient &coeff, AvgType type, Array< int > &zones_per_vdof)
Accumulates (depending on type) the values of coeff at all shared vdofs and counts in how many zones ...
virtual void SetSpace(FiniteElementSpace *f)
Associate a new FiniteElementSpace with the GridFunction.
Definition gridfunc.cpp:227
Communicator performing operations within groups defined by a GroupTopology with arbitrary-size data ...
void Reduce(T *ldata, void(*Op)(OpData< T >)) const
Reduce within each group where the master is the root, host version.
static void Sum(OpData< T >)
Reduce operation Sum, instantiated for int, double and float.
void Bcast(T *ldata, int layout) const
Broadcast within each group where the master is the root.
static void Max(OpData< T >)
Reduce operation Max, instantiated for int, double and float.
The BoomerAMG solver in hypre.
Definition hypre.hpp:1829
void SetPrintLevel(int print_level)
Definition hypre.hpp:1912
void Mult(const HypreParVector &b, HypreParVector &x) const override
Solve Ax=b with hypre's PCG.
Definition hypre.cpp:4373
void SetPrintLevel(int print_lvl)
Definition hypre.cpp:4345
void SetPreconditioner(HypreSolver &precond)
Set the hypre solver to be used as a preconditioner.
Definition hypre.cpp:4350
void SetMaxIter(int max_iter)
Definition hypre.cpp:4328
void SetTol(real_t tol)
Definition hypre.cpp:4304
Wrapper for hypre's ParCSR matrix class.
Definition hypre.hpp:419
HYPRE_Int Mult(HypreParVector &x, HypreParVector &y, real_t alpha=1.0, real_t beta=0.0) const
Computes y = alpha * A * x + beta * y.
Definition hypre.cpp:1873
Wrapper for hypre's parallel vector class.
Definition hypre.hpp:230
void Transform(const IntegrationPoint &, IntegrationPoint &)
Definition eltrans.cpp:587
Class for integration point with weight.
Definition intrules.hpp:35
Class for an integration rule - an Array of IntegrationPoint.
Definition intrules.hpp:96
int GetNPoints() const
Returns the number of the points in the integration rule.
Definition intrules.hpp:255
IntegrationPoint & IntPoint(int i)
Returns a reference to the i-th integration point.
Definition intrules.hpp:258
const IntegrationRule & Get(int GeomType, int Order)
Returns an integration rule for given GeomType and Order.
real_t Eval(real_t h, int p) const
Mesh data type.
Definition mesh.hpp:67
void GetFaceInfos(int Face, int *Inf1, int *Inf2) const
Definition mesh.cpp:1638
int GetNumFaces() const
Return the number of faces (3D), edges (2D) or vertices (1D).
Definition mesh.cpp:7302
int GetNE() const
Returns number of elements.
Definition mesh.hpp:1390
real_t GetElementSize(int i, int type=0)
Get the size of the i-th element relative to the perfect reference element.
Definition mesh.cpp:111
void GetFaceElements(int Face, int *Elem1, int *Elem2) const
Return the indices of the elements sharing face Face.
Definition mesh.cpp:1632
int SpaceDimension() const
Dimension of the physical space containing the mesh.
Definition mesh.hpp:1317
Pointer to an Operator of a specified type.
Definition handle.hpp:34
Abstract operator.
Definition operator.hpp:27
virtual void Mult(const Vector &x, Vector &y) const =0
Operator application: y=A(x).
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
Matrix-free transfer operator between finite element spaces on the same mesh.
Definition transfer.hpp:636
void Mult(const Vector &x, Vector &y) const override
Interpolation or prolongation of a vector x corresponding to the coarse space to the vector y corresp...
Class for parallel bilinear form.
Abstract parallel finite element space.
Definition pfespace.hpp:31
MPI_Comm GetComm() const
Definition pfespace.hpp:337
int GetMaxElementOrder() const override
Returns the maximum polynomial order over all elements globally.
int GetLocalTDofNumber(int ldof) const
int GetDofSign(int i) const
Return -1 if the given (vector) DOF i has a sign opposite of the DOF in the respective serial FE spac...
Definition pfespace.hpp:354
void DivideByGroupSize(real_t *vec)
Scale a vector of true dofs.
HypreParVector * NewTrueDofVector()
Definition pfespace.hpp:413
const FiniteElement * GetFaceNbrFE(int i, int ndofs=0) const
GroupCommunicator & GroupComm()
Return a reference to the internal GroupCommunicator (on VDofs)
Definition pfespace.hpp:420
const Operator * GetProlongationMatrix() const override
bool HaveDofSigns() const
Return true if the parallel FE space has DOFs with signs opposite of the DOFs in the respective seria...
Definition pfespace.hpp:345
void GetEssentialVDofs(const Array< int > &bdr_attr_is_ess, Array< int > &ess_dofs, int component=-1) const override
Determine the boundary degrees of freedom.
HypreParMatrix * Dof_TrueDof_Matrix() const
The true dof-to-dof interpolation matrix.
Definition pfespace.hpp:403
void GetFaceNbrElementVDofs(int i, Array< int > &vdofs, DofTransformation &doftrans) const
void ApplyDofSigns(real_t *h_data) const
Apply the DOF signs to the given host data h_data which must be of size GetVSize() if HaveDofSigns() ...
Definition pfespace.cpp:575
const SparseMatrix * GetRestrictionMatrix() const override
Get the R matrix which restricts a local dof vector to true dof vector.
Definition pfespace.hpp:517
ParMesh * GetParMesh() const
Definition pfespace.hpp:341
const FiniteElement * GetFE(int i) const override
Definition pfespace.cpp:663
ElementTransformation * GetFaceNbrElementTransformation(int i) const
Definition pfespace.hpp:535
Class for parallel grid function.
Definition pgridfunc.hpp:50
void CountElementsPerVDof(Array< int > &elem_per_vdof) const override
For each vdof, counts how many elements contain the vdof, as containment is determined by FiniteEleme...
void GetDerivative(int comp, int der_comp, ParGridFunction &der) const
Parallel version of GridFunction::GetDerivative(); see its documentation.
HypreParVector * ParallelAverage() const
Returns a new vector averaged on the true dofs.
real_t ComputeDGFaceJumpError(Coefficient *exsol, Coefficient *ell_coeff, JumpScaling jump_scaling, const IntegrationRule *irs[]=NULL) const override
Returns the Face Jumps error for L2 elements.
void Save(std::ostream &out) const override
void ProjectCoefficient(Coefficient &coeff, ProjectType type=ProjectType::DEFAULT) override
Project coeff Coefficient to this GridFunction. The projection computation depends on the choice of t...
real_t GetValue(int i, const IntegrationPoint &ip, int vdim=1) const override
HypreParVector * GetTrueDofs() const
Returns the true dofs in a new HypreParVector.
void ProjectCoefficientGlobalL2(Coefficient &coeff, real_t rtol=1e-12, int iter=1000) override
Project coeff Coefficient to this GridFunction. The projection is a global L2 projection....
void ComputeFlux(BilinearFormIntegrator &blfi, GridFunction &flux, bool wcoef=true, int subdomain=-1) override
void ProjectBdrCoefficient(Coefficient *coeff[], VectorCoefficient *vcoeff, const Array< int > &attr)
std::pair< real_t, real_t > EstimateFunctionMaximum(const int vdim, const PLBound &plb, const int max_depth, const real_t tol) const override
Estimate the GridFunction maximum across all elements.
ParFiniteElementSpace * pfes
Points to the same object as fes.
Definition pgridfunc.hpp:52
Vector send_data
Vector used as an MPI buffer to send face-neighbor data in ExchangeFaceNbrData() to neighboring proce...
Definition pgridfunc.hpp:61
HypreParVector * ParallelProject() const
Returns a new vector restricted to the true dofs.
HypreParVector * ParallelAssemble() const
Returns a new vector assembled on the true dofs.
std::pair< real_t, real_t > EstimateFunctionMinimum(const int vdim, const PLBound &plb, const int max_depth, const real_t tol) const override
Estimate the GridFunction minimum across all elements.
ParFiniteElementSpace * ParFESpace() const
void AddDistribute(real_t a, const Vector *tv)
void MakeRef(FiniteElementSpace *f, real_t *v) override
Make the ParGridFunction reference external data on a new FiniteElementSpace.
void GetVectorValue(int i, const IntegrationPoint &ip, Vector &val) const override
virtual void ProjectDiscCoefficient(std::variant< Coefficient *, VectorCoefficient * > coeff) override
Project a discontinuous (vector) coefficient as a grid function on a continuous finite element space....
void ProjectCoefficientElementL2(Coefficient &coeff) override
Project coeff Coefficient to this GridFunction. The projection is an element local L2 projection,...
void SaveAsSerial(const char *fname, int precision=16, int save_rank=0) const
Vector face_nbr_data
Vector used to store data from face-neighbor processors, initialized by ExchangeFaceNbrData().
Definition pgridfunc.hpp:56
void SaveAsOne(const char *fname, int precision=16) const
GridFunction GetSerialGridFunction(int save_rank, Mesh &serial_mesh) const
Returns a GridFunction on MPI rank save_rank that does not have any duplication of vertices/nodes at ...
PLBound GetBounds(Vector &lower, Vector &upper, const int ref_factor=1, const int vdim=-1) const override
void ParallelProject(Vector &tv) const
Returns the vector restricted to the true dofs.
void Update() override
Transform by the Space UpdateMatrix (e.g., on Mesh change).
Definition pgridfunc.cpp:97
void SetSpace(FiniteElementSpace *f) override
Associate a new FiniteElementSpace with the ParGridFunction.
void Distribute(const Vector *tv)
std::unique_ptr< ParGridFunction > ProlongateToMaxOrder() const
Return a GridFunction with the values of this, prolongated to the maximum order of all elements in th...
void GetElementDofValues(int el, Vector &dof_vals) const override
void ProjectBdrCoefficientTangent(VectorCoefficient &vcoeff, const Array< int > &bdr_attr) override
Project the tangential components of the given VectorCoefficient on the boundary.
Class for parallel linear form.
Class for parallel meshes.
Definition pmesh.hpp:35
Mesh GetSerialMesh(int save_rank) const
Definition pmesh.cpp:5551
ElementTransformation * GetFaceNbrElementTransformation(int FaceNo)
Returns a pointer to the transformation defining the i-th face neighbor.
Definition pmesh.cpp:3127
MPI_Comm GetComm() const
Definition pmesh.hpp:403
int GetMyRank() const
Definition pmesh.hpp:405
int GetNSharedFaces() const
Return the number of shared faces (3D), edges (2D), vertices (1D)
Definition pmesh.cpp:3193
int GetNRanks() const
Definition pmesh.hpp:404
FaceElementTransformations * GetFaceElementTransformations(int FaceNo, int mask=31) override
Definition pmesh.cpp:2926
int GetSharedFace(int sface) const
Return the local face index for the given shared face.
Definition pmesh.cpp:3212
int GetNFaceNeighbors() const
Definition pmesh.hpp:578
real_t GetFaceNbrElementSize(int i, int type=0)
Definition pmesh.cpp:3188
int GetFaceNbrRank(int fn) const
Definition pmesh.cpp:2825
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:2952
Base class for solvers.
Definition operator.hpp:855
void Mult(const Vector &x, Vector &y) const override
Matrix vector multiplication.
int Size_of_connections() const
Returns the number of connections in the table.
Definition table.hpp:110
Memory< int > & GetJMemory()
Definition table.hpp:133
int * GetI()
Definition table.hpp:127
Base class for vector Coefficients that optionally depend on time and space.
int GetVDim()
Returns dimension of the vector.
Scalar coefficient defined as component of a vector coefficient.
void SetComponent(int c)
Set the component.
for VectorFiniteElements (Nedelec, Raviart-Thomas)
Definition lininteg.hpp:365
Vector coefficient defined by a vector GridFunction.
Vector data type.
Definition vector.hpp:82
virtual const real_t * HostRead() const
Shortcut for mfem::Read(vec.GetMemory(), vec.Size(), false).
Definition vector.hpp:524
virtual const real_t * Read(bool on_dev=true) const
Shortcut for mfem::Read(vec.GetMemory(), vec.Size(), on_dev).
Definition vector.hpp:520
void SetDataAndSize(real_t *d, int s)
Set the Vector data and size.
Definition vector.hpp:191
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 Destroy()
Destroy a vector.
Definition vector.hpp:722
int Size() const
Returns the size of the vector.
Definition vector.hpp:234
void SetSize(int s)
Resize the vector to size s.
Definition vector.hpp:633
virtual real_t * HostWrite()
Shortcut for mfem::Write(vec.GetMemory(), vec.Size(), false).
Definition vector.hpp:532
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
virtual real_t * Write(bool on_dev=true)
Shortcut for mfem::Write(vec.GetMemory(), vec.Size(), on_dev).
Definition vector.hpp:528
const int * ess_tdof_list
real_t b
Definition lissajous.cpp:42
real_t a
Definition lissajous.cpp:41
ProjectType
This enumerated type describes the main projection types used by GridFunction::ProjectCoefficient():
Definition gridfunc.hpp:49
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
real_t L2ZZErrorEstimator(BilinearFormIntegrator &flux_integrator, const ParGridFunction &x, ParFiniteElementSpace &smooth_flux_fes, ParFiniteElementSpace &flux_fes, Vector &errors, int norm_p, real_t solver_tol, int solver_max_it)
real_t GlobalLpNorm(const real_t p, real_t loc_norm, MPI_Comm comm)
Compute a global Lp norm from the local Lp norms computed by each processor.
real_t ComputeElementLpDistance(real_t p, int i, GridFunction &gf1, GridFunction &gf2)
Compute the Lp distance between two grid functions on the given element.
float real_t
Definition config.hpp:46
std::function< real_t(const Vector &)> f(real_t mass_coeff)
Definition lor_mms.hpp:30
void forall(int N, lambda &&body)
Definition forall.hpp:1134
constexpr real_t infinity()
Define a shortcut for std::numeric_limits<double>::infinity()
Definition vector.hpp:47
IntegrationRules IntRules(0, Quadrature1D::GaussLegendre)
A global object with all integration rules (defined in intrules.cpp)
Definition intrules.hpp:549
STL namespace.
real_t p(const Vector &x, real_t t)
Helper struct to convert a C++ type to an MPI type.