MFEM v4.9.0
Finite element discretization library
Loading...
Searching...
No Matches
pgridfunc.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 <iostream>
18#include <limits>
19#include "../general/forall.hpp"
20using namespace std;
21
22namespace mfem
23{
24
30
36
38 const int *partitioning)
39{
40 const FiniteElementSpace *glob_fes = gf->FESpace();
41 // duplicate the FiniteElementCollection from 'gf'
43 // create a local ParFiniteElementSpace from the global one:
44 fes = pfes = new ParFiniteElementSpace(pmesh, glob_fes, partitioning,
45 fec_owned);
47
48 if (partitioning)
49 {
50 // Assumption: the map "local element id" -> "global element id" is
51 // increasing, i.e. the local numbering preserves the element order from
52 // the global numbering.
53 Array<int> gvdofs, lvdofs;
54 Vector lnodes;
55 int element_counter = 0;
56 const int MyRank = pfes->GetMyRank();
57 const int glob_ne = glob_fes->GetNE();
58 DofTransformation ltrans, gtrans;
59 for (int i = 0; i < glob_ne; i++)
60 {
61 if (partitioning[i] == MyRank)
62 {
63 pfes->GetElementVDofs(element_counter, lvdofs, ltrans);
64 glob_fes->GetElementVDofs(i, gvdofs, gtrans);
65 gf->GetSubVector(gvdofs, lnodes);
66 gtrans.InvTransformPrimal(lnodes);
67 ltrans.TransformPrimal(lnodes);
68 SetSubVector(lvdofs, lnodes);
69 element_counter++;
70 }
71 }
72 }
73}
74
75ParGridFunction::ParGridFunction(ParMesh *pmesh, std::istream &input)
76 : GridFunction(pmesh, input)
77{
78 // Convert the FiniteElementSpace, fes, to a ParFiniteElementSpace:
80 fes->GetOrdering());
81 delete fes;
82 fes = pfes;
83}
84
90
92{
95 pfes = dynamic_cast<ParFiniteElementSpace*>(f);
96 MFEM_ASSERT(pfes != NULL, "not a ParFiniteElementSpace");
97}
98
105
107{
110 pfes = dynamic_cast<ParFiniteElementSpace*>(f);
111 MFEM_ASSERT(pfes != NULL, "not a ParFiniteElementSpace");
112}
113
120
122{
124 GridFunction::MakeRef(f, v, v_offset);
125 pfes = dynamic_cast<ParFiniteElementSpace*>(f);
126 MFEM_ASSERT(pfes != NULL, "not a ParFiniteElementSpace");
127}
128
130{
132 GridFunction::MakeRef(f, v, v_offset);
133 pfes = f;
134}
135
137{
138 const Operator *prolong = pfes->GetProlongationMatrix();
139 prolong->Mult(*tv, *this);
140}
141
143{
144 pfes->Dof_TrueDof_Matrix()->Mult(a, *tv, 1.0, *this);
145}
146
148{
150 GetTrueDofs(*tv);
151 return tv;
152}
153
155{
156 MFEM_VERIFY(pfes->Conforming(), "not implemented for NC meshes");
159}
160
162{
163 MFEM_VERIFY(pfes->Conforming(), "not implemented for NC meshes");
166}
167
174
176{
177 pfes->GetRestrictionMatrix()->Mult(*this, tv);
178}
179
184
191
196
201
208
210{
212
213 if (pfes->GetFaceNbrVSize() <= 0)
214 {
215 return;
216 }
217
218 ParMesh *pmesh = pfes->GetParMesh();
219
222
223 int *send_offset = pfes->send_face_nbr_ldof.GetI();
224 const int *d_send_ldof = mfem::Read(pfes->send_face_nbr_ldof.GetJMemory(),
225 send_data.Size());
226 int *recv_offset = pfes->face_nbr_ldof.GetI();
227 MPI_Comm MyComm = pfes->GetComm();
228
229 const int num_face_nbrs = pmesh->GetNFaceNeighbors();
230 MPI_Request *requests = new MPI_Request[2*num_face_nbrs];
231 MPI_Request *send_requests = requests;
232 MPI_Request *recv_requests = requests + num_face_nbrs;
233 MPI_Status *statuses = new MPI_Status[num_face_nbrs];
234
235 auto d_data = this->Read();
236 auto d_send_data = send_data.Write();
237 mfem::forall(send_data.Size(), [=] MFEM_HOST_DEVICE (int i)
238 {
239 const int ldof = d_send_ldof[i];
240 d_send_data[i] = d_data[ldof >= 0 ? ldof : -1-ldof];
241 });
242
243 const bool mpi_gpu_aware = Device::GetGPUAwareMPI();
244 auto send_data_ptr = mpi_gpu_aware ? send_data.Read() : send_data.HostRead();
245 auto face_nbr_data_ptr = mpi_gpu_aware ? face_nbr_data.Write() :
247 // Wait for the kernel to be done since it updates what's sent and it may be async
248 if (mpi_gpu_aware) { MFEM_STREAM_SYNC; }
249 for (int fn = 0; fn < num_face_nbrs; fn++)
250 {
251 int nbr_rank = pmesh->GetFaceNbrRank(fn);
252 int tag = 0;
253
254 MPI_Isend(&send_data_ptr[send_offset[fn]],
255 send_offset[fn+1] - send_offset[fn],
256 MPITypeMap<real_t>::mpi_type, nbr_rank, tag, MyComm, &send_requests[fn]);
257
258 MPI_Irecv(&face_nbr_data_ptr[recv_offset[fn]],
259 recv_offset[fn+1] - recv_offset[fn],
260 MPITypeMap<real_t>::mpi_type, nbr_rank, tag, MyComm, &recv_requests[fn]);
261 }
262
263 MPI_Waitall(num_face_nbrs, send_requests, statuses);
264 MPI_Waitall(num_face_nbrs, recv_requests, statuses);
265
266 delete [] statuses;
267 delete [] requests;
268}
269
271const
272{
273 Array<int> dofs;
274 Vector DofVal, LocVec;
275 const int nbr_el_no = i - pfes->GetParMesh()->GetNE();
276 DofTransformation doftrans;
277 if (nbr_el_no >= 0)
278 {
279 int fes_vdim = pfes->GetVDim();
280 pfes->GetFaceNbrElementVDofs(nbr_el_no, dofs, doftrans);
281 // Choose fe to be of the order whose number of DOFs matches dofs.Size(),
282 // in the variable order case.
283 const int ndofs = pfes->IsVariableOrder() ? dofs.Size() : 0;
284 const FiniteElement *fe = pfes->GetFaceNbrFE(nbr_el_no, fes_vdim * ndofs);
285
286 if (fes_vdim > 1)
287 {
288 int s = dofs.Size()/fes_vdim;
289 Array<int> dofs_(&dofs[(vdim-1)*s], s);
290 face_nbr_data.GetSubVector(dofs_, LocVec);
291
292 DofVal.SetSize(s);
293 }
294 else
295 {
296 face_nbr_data.GetSubVector(dofs, LocVec);
297 DofVal.SetSize(dofs.Size());
298 }
299 doftrans.InvTransformPrimal(LocVec);
300
301 if (fe->GetMapType() == FiniteElement::VALUE)
302 {
303 fe->CalcShape(ip, DofVal);
304 }
305 else
306 {
309 Tr->SetIntPoint(&ip);
310 fe->CalcPhysShape(*Tr, DofVal);
311 }
312 }
313 else
314 {
315 fes->GetElementDofs(i, dofs, doftrans);
316 fes->DofsToVDofs(vdim-1, dofs);
317 DofVal.SetSize(dofs.Size());
318 const FiniteElement *fe = fes->GetFE(i);
319 if (fe->GetMapType() == FiniteElement::VALUE)
320 {
321 fe->CalcShape(ip, DofVal);
322 }
323 else
324 {
326 Tr->SetIntPoint(&ip);
327 fe->CalcPhysShape(*Tr, DofVal);
328 }
329 GetSubVector(dofs, LocVec);
330 doftrans.InvTransformPrimal(LocVec);
331 }
332
333 return (DofVal * LocVec);
334}
335
337 Vector &val) const
338{
339 const int nbr_el_no = i - pfes->GetParMesh()->GetNE();
340 if (nbr_el_no >= 0)
341 {
342 Array<int> dofs;
343 DofTransformation doftrans;
344 pfes->GetFaceNbrElementVDofs(nbr_el_no, dofs, doftrans);
345 Vector loc_data;
346 face_nbr_data.GetSubVector(dofs, loc_data);
347 doftrans.InvTransformPrimal(loc_data);
348 const FiniteElement *FElem = pfes->GetFaceNbrFE(nbr_el_no);
349 int dof = FElem->GetDof();
350 if (FElem->GetRangeType() == FiniteElement::SCALAR)
351 {
352 Vector shape(dof);
353 if (FElem->GetMapType() == FiniteElement::VALUE)
354 {
355 FElem->CalcShape(ip, shape);
356 }
357 else
358 {
361 Tr->SetIntPoint(&ip);
362 FElem->CalcPhysShape(*Tr, shape);
363 }
364 int vdim = fes->GetVDim();
365 val.SetSize(vdim);
366 for (int k = 0; k < vdim; k++)
367 {
368 val(k) = shape * (&loc_data[dof * k]);
369 }
370 }
371 else
372 {
373 int spaceDim = fes->GetMesh()->SpaceDimension();
374 DenseMatrix vshape(dof, spaceDim);
377 Tr->SetIntPoint(&ip);
378 FElem->CalcVShape(*Tr, vshape);
379 val.SetSize(spaceDim);
380 vshape.MultTranspose(loc_data, val);
381 }
382 }
383 else
384 {
386 }
387}
388
390 const IntegrationPoint &ip,
391 int comp, Vector *tr) const
392{
393 // We can assume faces and edges are local
395 {
396 return GridFunction::GetValue(T, ip, comp, tr);
397 }
398
399 // Check for evaluation in a local element
400 const int nbr_el_no = T.ElementNo - pfes->GetParMesh()->GetNE();
401 if (nbr_el_no < 0)
402 {
403 return GridFunction::GetValue(T, ip, comp, tr);
404 }
405
406 // Evaluate using DoFs from a neighboring element
407 if (tr)
408 {
409 T.SetIntPoint(&ip);
410 T.Transform(ip, *tr);
411 }
412
413 Array<int> dofs;
414 const FiniteElement * fe = pfes->GetFaceNbrFE(nbr_el_no);
415 DofTransformation doftrans;
416 pfes->GetFaceNbrElementVDofs(nbr_el_no, dofs, doftrans);
417
418 pfes->DofsToVDofs(comp-1, dofs);
419 Vector DofVal(dofs.Size()), LocVec;
420 if (fe->GetMapType() == FiniteElement::VALUE)
421 {
422 fe->CalcShape(ip, DofVal);
423 }
424 else
425 {
426 fe->CalcPhysShape(T, DofVal);
427 }
428 face_nbr_data.GetSubVector(dofs, LocVec);
429 doftrans.InvTransformPrimal(LocVec);
430
431
432 return (DofVal * LocVec);
433}
434
436 const IntegrationPoint &ip,
437 Vector &val, Vector *tr) const
438{
439 // We can assume faces and edges are local
441 {
442 return GridFunction::GetVectorValue(T, ip, val, tr);
443 }
444
445 // Check for evaluation in a local element
446 const int nbr_el_no = T.ElementNo - pfes->GetParMesh()->GetNE();
447 if (nbr_el_no < 0)
448 {
449 return GridFunction::GetVectorValue(T, ip, val, tr);
450 }
451
452 // Evaluate using DoFs from a neighboring element
453 if (tr)
454 {
455 T.SetIntPoint(&ip);
456 T.Transform(ip, *tr);
457 }
458
459 Array<int> vdofs;
460 DofTransformation doftrans;
461 pfes->GetFaceNbrElementVDofs(nbr_el_no, vdofs, doftrans);
462 Vector loc_data;
463 face_nbr_data.GetSubVector(vdofs, loc_data);
464 doftrans.InvTransformPrimal(loc_data);
465
466 const FiniteElement *fe = pfes->GetFaceNbrFE(nbr_el_no);
467 const int dof = fe->GetDof();
469 {
470 Vector shape(dof);
471 if (fe->GetMapType() == FiniteElement::VALUE)
472 {
473 fe->CalcShape(ip, shape);
474 }
475 else
476 {
477 fe->CalcPhysShape(T, shape);
478 }
479 int vdim = pfes->GetVDim();
480 val.SetSize(vdim);
481 for (int k = 0; k < vdim; k++)
482 {
483 val(k) = shape * (&loc_data[dof * k]);
484 }
485 }
486 else
487 {
488 int spaceDim = pfes->GetMesh()->SpaceDimension();
489 int vdim = std::max(spaceDim, fe->GetRangeDim());
490 DenseMatrix vshape(dof, vdim);
491 fe->CalcVShape(T, vshape);
492 val.SetSize(vdim);
493 vshape.MultTranspose(loc_data, val);
494 }
495}
496
498{
500 // Count the zones globally.
501 GroupCommunicator &gcomm = this->ParFESpace()->GroupComm();
502 gcomm.Reduce<int>(elem_per_vdof, GroupCommunicator::Sum);
503 gcomm.Bcast(elem_per_vdof);
504}
505
506void ParGridFunction::GetDerivative(int comp, int der_comp,
507 ParGridFunction &der) const
508{
509 Array<int> overlap;
510 AccumulateAndCountDerivativeValues(comp, der_comp, der, overlap);
511
512 // Count the zones globally.
513 GroupCommunicator &gcomm = der.ParFESpace()->GroupComm();
514 gcomm.Reduce<int>(overlap, GroupCommunicator::Sum);
515 gcomm.Bcast(overlap);
516
517 // Accumulate for all dofs.
519 gcomm.Bcast<real_t>(der.HostReadWrite());
520
521 for (int i = 0; i < overlap.Size(); i++)
522 {
523 der(i) /= overlap[i];
524 }
525}
526
527void ParGridFunction::GetElementDofValues(int el, Vector &dof_vals) const
528{
529 int ne = fes->GetNE();
530 if (el >= ne)
531 {
532 MFEM_ASSERT(face_nbr_data.Size() > 0,
533 "ParGridFunction::GetElementDofValues: ExchangeFaceNbrData "
534 "must be called before accessing face neighbor elements.");
535 // Face neighbor element
536 Array<int> dof_idx;
537 pfes->GetFaceNbrElementVDofs(el - ne, dof_idx);
538 face_nbr_data.GetSubVector(dof_idx, dof_vals);
539 }
540 else
541 {
543 }
544}
545
547{
548 DeltaCoefficient *delta_c = dynamic_cast<DeltaCoefficient *>(&coeff);
549
550 if (delta_c == NULL)
551 {
553 }
554 else
555 {
556 real_t loc_integral, glob_integral;
557
558 ProjectDeltaCoefficient(*delta_c, loc_integral);
559
560 MPI_Allreduce(&loc_integral, &glob_integral, 1, MPITypeMap<real_t>::mpi_type,
561 MPI_SUM,
562 pfes->GetComm());
563
564 (*this) *= (delta_c->Scale() / glob_integral);
565 }
566}
567
569{
570 // local maximal element attribute for each dof
571 Array<int> ldof_attr;
572
573 // local projection
574 GridFunction::ProjectDiscCoefficient(coeff, ldof_attr);
575
576 // global maximal element attribute for each dof
577 Array<int> gdof_attr;
578 ldof_attr.Copy(gdof_attr);
579 GroupCommunicator &gcomm = pfes->GroupComm();
580 gcomm.Reduce<int>(gdof_attr, GroupCommunicator::Max);
581 gcomm.Bcast(gdof_attr);
582
583 // set local value to zero if global maximal element attribute is larger than
584 // the local one, and mark (in gdof_attr) if we have the correct value
585 for (int i = 0; i < pfes->GetVSize(); i++)
586 {
587 if (gdof_attr[i] > ldof_attr[i])
588 {
589 (*this)(i) = 0.0;
590 gdof_attr[i] = 0;
591 }
592 else
593 {
594 gdof_attr[i] = 1;
595 }
596 }
597
598 // parallel averaging plus interpolation to determine final values
600 gcomm.Reduce<int>(gdof_attr, GroupCommunicator::Sum);
601 gcomm.Bcast(gdof_attr);
602 for (int i = 0; i < fes->GetVSize(); i++)
603 {
604 (*this)(i) /= gdof_attr[i];
605 }
606 this->ParallelAssemble(*tv);
607 this->Distribute(tv);
608 delete tv;
609}
610
611
613{
614 // Harmonic (x1 ... xn) = [ (1/x1 + ... + 1/xn) / n ]^-1.
615 // Arithmetic(x1 ... xn) = (x1 + ... + xn) / n.
616
617 // Number of zones that contain a given dof.
618 Array<int> zones_per_vdof;
619 AccumulateAndCountZones(coeff, type, zones_per_vdof);
620
621 // Count the zones globally.
622 GroupCommunicator &gcomm = pfes->GroupComm();
623 gcomm.Reduce<int>(zones_per_vdof, GroupCommunicator::Sum);
624 gcomm.Bcast(zones_per_vdof);
625
626 // Accumulate for all vdofs.
628 gcomm.Bcast<real_t>(data);
629
630 ComputeMeans(type, zones_per_vdof);
631}
632
634 AvgType type)
635{
636 // Harmonic (x1 ... xn) = [ (1/x1 + ... + 1/xn) / n ]^-1.
637 // Arithmetic(x1 ... xn) = (x1 + ... + xn) / n.
638
639 // Number of zones that contain a given dof.
640 Array<int> zones_per_vdof;
641 AccumulateAndCountZones(vcoeff, type, zones_per_vdof);
642
643 // Count the zones globally.
644 GroupCommunicator &gcomm = pfes->GroupComm();
645 gcomm.Reduce<int>(zones_per_vdof, GroupCommunicator::Sum);
646 gcomm.Bcast(zones_per_vdof);
647
648 // Accumulate for all vdofs.
650 gcomm.Bcast<real_t>(data);
651
652 ComputeMeans(type, zones_per_vdof);
653}
654
656 Coefficient *coeff[], VectorCoefficient *vcoeff, const Array<int> &attr)
657{
658 Array<int> values_counter;
659 AccumulateAndCountBdrValues(coeff, vcoeff, attr, values_counter);
660
661 Vector values(Size());
662 for (int i = 0; i < values.Size(); i++)
663 {
664 values(i) = values_counter[i] ? (*this)(i) : 0.0;
665 }
666
667 // Count the values globally.
668 GroupCommunicator &gcomm = pfes->GroupComm();
669 gcomm.Reduce<int>(values_counter.HostReadWrite(), GroupCommunicator::Sum);
670 // Accumulate the values globally.
672
673 for (int i = 0; i < values.Size(); i++)
674 {
675 if (values_counter[i])
676 {
677 (*this)(i) = values(i)/values_counter[i];
678 }
679 }
680 // Broadcast values to other processors to have a consistent GridFunction
681 gcomm.Bcast<real_t>((*this).HostReadWrite());
682
683#ifdef MFEM_DEBUG
684 Array<int> ess_vdofs_marker;
685 if (vcoeff) { pfes->GetEssentialVDofs(attr, ess_vdofs_marker); }
686 else
687 {
688 ess_vdofs_marker.SetSize(Size());
689 ess_vdofs_marker = 0;
690 for (int i = 0; i < fes->GetVDim(); i++)
691 {
692 if (!coeff[i]) { continue; }
693 Array<int> component_dof_marker;
694 pfes->GetEssentialVDofs(attr, component_dof_marker,i);
695 for (int j = 0; j<Size(); j++)
696 {
697 ess_vdofs_marker[j] = bool(ess_vdofs_marker[j]) ||
698 bool(component_dof_marker[j]);
699 }
700 }
701 }
702 gcomm.Bcast<int>(values_counter.HostReadWrite());
703 for (int i = 0; i < values_counter.Size(); i++)
704 {
705 MFEM_ASSERT(bool(values_counter[i]) == bool(ess_vdofs_marker[i]),
706 "internal error");
707 }
708#endif
709}
710
712 const Array<int> &bdr_attr)
713{
714 Array<int> values_counter;
715 AccumulateAndCountBdrTangentValues(vcoeff, bdr_attr, values_counter);
716
717 Vector values(Size());
718 for (int i = 0; i < values.Size(); i++)
719 {
720 values(i) = values_counter[i] ? (*this)(i) : 0.0;
721 }
722
723 // Count the values globally.
724 GroupCommunicator &gcomm = pfes->GroupComm();
725 gcomm.Reduce<int>(values_counter.HostReadWrite(), GroupCommunicator::Sum);
726 // Accumulate the values globally.
728
729 for (int i = 0; i < values.Size(); i++)
730 {
731 if (values_counter[i])
732 {
733 (*this)(i) = values(i)/values_counter[i];
734 }
735 }
736 // Broadcast values to other processors to have a consistent GridFunction
737 gcomm.Bcast<real_t>((*this).HostReadWrite());
738
739#ifdef MFEM_DEBUG
740 Array<int> ess_vdofs_marker;
741 pfes->GetEssentialVDofs(bdr_attr, ess_vdofs_marker);
742 gcomm.Bcast<int>(values_counter.HostReadWrite());
743 for (int i = 0; i < values_counter.Size(); i++)
744 {
745 MFEM_ASSERT(bool(values_counter[i]) == bool(ess_vdofs_marker[i]),
746 "internal error: " << pfes->GetLocalTDofNumber(i) << ' ' << bool(
747 values_counter[i]));
748 }
749#endif
750}
751
753 Coefficient *ell_coeff,
754 JumpScaling jump_scaling,
755 const IntegrationRule *irs[]) const
756{
757 const_cast<ParGridFunction *>(this)->ExchangeFaceNbrData();
758
759 int fdof, intorder, k;
760 ElementTransformation *transf;
761 Vector shape, el_dofs, err_val, ell_coeff_val;
762 Array<int> vdofs;
764 real_t error = 0.0;
765
766 ParMesh *mesh = pfes->GetParMesh();
767
768 std::map<int,int> local_to_shared;
769 for (int i = 0; i < mesh->GetNSharedFaces(); ++i)
770 {
771 int i_local = mesh->GetSharedFace(i);
772 local_to_shared[i_local] = i;
773 }
774
775 for (int i = 0; i < mesh->GetNumFaces(); i++)
776 {
777 real_t shared_face_factor = 1.0;
778 bool shared_face = false;
779 int iel1, iel2, info1, info2;
780 mesh->GetFaceElements(i, &iel1, &iel2);
781 mesh->GetFaceInfos(i, &info1, &info2);
782
783 real_t h = mesh->GetElementSize(iel1);
784 intorder = fes->GetFE(iel1)->GetOrder();
785
786 FaceElementTransformations *face_elem_transf;
787 const FiniteElement *fe1, *fe2;
788 if (info2 >= 0 && iel2 < 0)
789 {
790 int ishared = local_to_shared[i];
791 face_elem_transf = mesh->GetSharedFaceTransformations(ishared);
792 iel2 = face_elem_transf->Elem2No - mesh->GetNE();
793 fe2 = pfes->GetFaceNbrFE(iel2);
794 if ( (k = fe2->GetOrder()) > intorder )
795 {
796 intorder = k;
797 }
798 shared_face = true;
799 shared_face_factor = 0.5;
800 h = std::min(h, mesh->GetFaceNbrElementSize(iel2));
801 }
802 else
803 {
804 if (iel2 >= 0)
805 {
806 fe2 = pfes->GetFE(iel2);
807 if ( (k = fe2->GetOrder()) > intorder )
808 {
809 intorder = k;
810 }
811 h = std::min(h, mesh->GetElementSize(iel2));
812 }
813 else
814 {
815 fe2 = NULL;
816 }
817 face_elem_transf = mesh->GetFaceElementTransformations(i);
818 }
819 int p = intorder;
820
821 intorder = 2 * intorder; // <-------------
822 const IntegrationRule *ir;
823 if (irs)
824 {
825 ir = irs[face_elem_transf->GetGeometryType()];
826 }
827 else
828 {
829 ir = &(IntRules.Get(face_elem_transf->GetGeometryType(), intorder));
830 }
831 err_val.SetSize(ir->GetNPoints());
832 ell_coeff_val.SetSize(ir->GetNPoints());
833 // side 1
834 transf = face_elem_transf->Elem1;
835 fe1 = fes->GetFE(iel1);
836 fdof = fe1->GetDof();
837 fes->GetElementVDofs(iel1, vdofs);
838 shape.SetSize(fdof);
839 el_dofs.SetSize(fdof);
840 for (k = 0; k < fdof; k++)
841 if (vdofs[k] >= 0)
842 {
843 el_dofs(k) = (*this)(vdofs[k]);
844 }
845 else
846 {
847 el_dofs(k) = - (*this)(-1-vdofs[k]);
848 }
849 for (int j = 0; j < ir->GetNPoints(); j++)
850 {
851 face_elem_transf->Loc1.Transform(ir->IntPoint(j), eip);
852 fe1->CalcShape(eip, shape);
853 transf->SetIntPoint(&eip);
854 ell_coeff_val(j) = ell_coeff->Eval(*transf, eip);
855 err_val(j) = exsol->Eval(*transf, eip) - (shape * el_dofs);
856 }
857 if (fe2 != NULL)
858 {
859 // side 2
860 transf = face_elem_transf->Elem2;
861 fdof = fe2->GetDof();
862 shape.SetSize(fdof);
863 el_dofs.SetSize(fdof);
864 if (shared_face)
865 {
866 pfes->GetFaceNbrElementVDofs(iel2, vdofs);
867 for (k = 0; k < fdof; k++)
868 if (vdofs[k] >= 0)
869 {
870 el_dofs(k) = face_nbr_data[vdofs[k]];
871 }
872 else
873 {
874 el_dofs(k) = - face_nbr_data[-1-vdofs[k]];
875 }
876 }
877 else
878 {
879 pfes->GetElementVDofs(iel2, vdofs);
880 for (k = 0; k < fdof; k++)
881 if (vdofs[k] >= 0)
882 {
883 el_dofs(k) = (*this)(vdofs[k]);
884 }
885 else
886 {
887 el_dofs(k) = - (*this)(-1 - vdofs[k]);
888 }
889 }
890 for (int j = 0; j < ir->GetNPoints(); j++)
891 {
892 face_elem_transf->Loc2.Transform(ir->IntPoint(j), eip);
893 fe2->CalcShape(eip, shape);
894 transf->SetIntPoint(&eip);
895 ell_coeff_val(j) += ell_coeff->Eval(*transf, eip);
896 ell_coeff_val(j) *= 0.5;
897 err_val(j) -= (exsol->Eval(*transf, eip) - (shape * el_dofs));
898 }
899 }
900 real_t face_error = 0.0;
901 transf = face_elem_transf;
902 for (int j = 0; j < ir->GetNPoints(); j++)
903 {
904 const IntegrationPoint &ip = ir->IntPoint(j);
905 transf->SetIntPoint(&ip);
906 real_t nu = jump_scaling.Eval(h, p);
907 face_error += shared_face_factor*(ip.weight * nu * ell_coeff_val(j) *
908 transf->Weight() *
909 err_val(j) * err_val(j));
910 }
911 // negative quadrature weights may cause the error to be negative
912 error += fabs(face_error);
913 }
914
915 error = sqrt(error);
916 return GlobalLpNorm(2.0, error, pfes->GetComm());
917}
918
919void ParGridFunction::Save(std::ostream &os) const
920{
921 real_t *data_ = const_cast<real_t*>(HostRead());
922 for (int i = 0; i < size; i++)
923 {
924 if (pfes->GetDofSign(i) < 0) { data_[i] = -data_[i]; }
925 }
926
928
929 for (int i = 0; i < size; i++)
930 {
931 if (pfes->GetDofSign(i) < 0) { data_[i] = -data_[i]; }
932 }
933}
934
935void ParGridFunction::Save(const char *fname, int precision) const
936{
937 int rank = pfes->GetMyRank();
938 ostringstream fname_with_suffix;
939 fname_with_suffix << fname << "." << setfill('0') << setw(6) << rank;
940 ofstream ofs(fname_with_suffix.str().c_str());
941 ofs.precision(precision);
942 Save(ofs);
943}
944
945void ParGridFunction::SaveAsOne(const char *fname, int precision) const
946{
947 ofstream ofs;
948 int rank = pfes->GetMyRank();
949 if (rank == 0)
950 {
951 ofs.open(fname);
952 ofs.precision(precision);
953 }
954 SaveAsOne(ofs);
955}
956
957void ParGridFunction::SaveAsSerial(const char *fname, int precision,
958 int save_rank) const
959{
960 ParMesh *pmesh = ParFESpace()->GetParMesh();
961 Mesh serial_mesh = pmesh->GetSerialMesh(save_rank);
962 GridFunction serialgf = GetSerialGridFunction(save_rank, serial_mesh);
963
964 if (pmesh->GetMyRank() == save_rank)
965 {
966 serialgf.Save(fname, precision);
967 }
968 MPI_Barrier(pmesh->GetComm());
969}
970
972 int save_rank, FiniteElementSpace &serial_fes) const
973{
974 ParFiniteElementSpace *pfespace = ParFESpace();
975 ParMesh *pmesh = pfespace->GetParMesh();
976
977 GridFunction serial_gf(&serial_fes);
978
979 Array<real_t> vals;
980 Array<int> dofs;
981 MPI_Status status;
982
983 const int vdim = pfespace->GetVDim();
984
985 const int my_rank = pmesh->GetMyRank();
986 const int nranks = pmesh->GetNRanks();
987 MPI_Comm comm = pmesh->GetComm();
988
989 if (my_rank == save_rank)
990 {
991 int elem_count = 0; // To keep track of element count in serial mesh
992
993 Vector nodeval;
994 for (int e = 0; e < pmesh->GetNE(); e++)
995 {
996 GetElementDofValues(e, nodeval);
997 serial_fes.GetElementVDofs(elem_count++, dofs);
998 serial_gf.SetSubVector(dofs, nodeval);
999 }
1000
1001 for (int p = 0; p < nranks; p++)
1002 {
1003 if (p == save_rank) { continue; }
1004 int n_send_recv;
1005 MPI_Recv(&n_send_recv, 1, MPI_INT, p, 448, comm, &status);
1006 vals.SetSize(n_send_recv);
1007 if (n_send_recv)
1008 {
1009 MPI_Recv(&vals[0], n_send_recv, MPITypeMap<real_t>::mpi_type, p, 449, comm,
1010 &status);
1011 }
1012 for (int i = 0; i < n_send_recv; )
1013 {
1014 serial_fes.GetElementVDofs(elem_count++, dofs);
1015 serial_gf.SetSubVector(dofs, &vals[i]);
1016 i += dofs.Size();
1017 }
1018 }
1019 } // my_rank == save_rank
1020 else
1021 {
1022 int n_send_recv = 0;
1023 Vector nodeval;
1024 for (int e = 0; e < pmesh->GetNE(); e++)
1025 {
1026 const FiniteElement *fe = pfespace->GetFE(e);
1027 n_send_recv += vdim*fe->GetDof();
1028 }
1029 MPI_Send(&n_send_recv, 1, MPI_INT, save_rank, 448, comm);
1030 vals.Reserve(n_send_recv);
1031 vals.SetSize(0);
1032 for (int e = 0; e < pmesh->GetNE(); e++)
1033 {
1034 GetElementDofValues(e, nodeval);
1035 for (int j = 0; j < nodeval.Size(); j++)
1036 {
1037 vals.Append(nodeval(j));
1038 }
1039 }
1040 if (n_send_recv)
1041 {
1042 MPI_Send(&vals[0], n_send_recv, MPITypeMap<real_t>::mpi_type, save_rank, 449,
1043 comm);
1044 }
1045 }
1046
1047 return serial_gf;
1048}
1049
1051 Mesh &serial_mesh) const
1052{
1053 auto *serial_fec = pfes->FEColl()->Clone(pfes->FEColl()->GetOrder());
1054 auto *serial_fes = new FiniteElementSpace(&serial_mesh,
1055 serial_fec,
1056 pfes->GetVDim(),
1057 pfes->GetOrdering());
1058 GridFunction serial_gf = GetSerialGridFunction(save_rank, *serial_fes);
1059 serial_gf.MakeOwner(serial_fec); // Also assumes ownership of serial_fes
1060 return serial_gf;
1061}
1062
1063#ifdef MFEM_USE_ADIOS2
1065 const std::string& variable_name,
1066 const adios2stream::data_type type) const
1067{
1068 real_t *data_ = const_cast<real_t*>(HostRead());
1069 for (int i = 0; i < size; i++)
1070 {
1071 if (pfes->GetDofSign(i) < 0) { data_[i] = -data_[i]; }
1072 }
1073
1074 GridFunction::Save(os, variable_name, type);
1075
1076 for (int i = 0; i < size; i++)
1077 {
1078 if (pfes->GetDofSign(i) < 0) { data_[i] = -data_[i]; }
1079 }
1080}
1081#endif
1082
1083void ParGridFunction::SaveAsOne(std::ostream &os) const
1084{
1085 int i, p;
1086
1087 MPI_Comm MyComm;
1088 MPI_Status status;
1089 int MyRank, NRanks;
1090
1091 MyComm = pfes -> GetComm();
1092
1093 MPI_Comm_size(MyComm, &NRanks);
1094 MPI_Comm_rank(MyComm, &MyRank);
1095
1096 real_t **values = new real_t*[NRanks];
1097 int *nv = new int[NRanks];
1098 int *nvdofs = new int[NRanks];
1099 int *nedofs = new int[NRanks];
1100 int *nfdofs = new int[NRanks];
1101 int *nrdofs = new int[NRanks];
1102
1103 real_t * h_data = const_cast<real_t *>(this->HostRead());
1104
1105 values[0] = h_data;
1106 nv[0] = pfes -> GetVSize();
1107 nvdofs[0] = pfes -> GetNVDofs();
1108 nedofs[0] = pfes -> GetNEDofs();
1109 nfdofs[0] = pfes -> GetNFDofs();
1110
1111 if (MyRank == 0)
1112 {
1113 pfes -> Save(os);
1114 os << '\n';
1115
1116 for (p = 1; p < NRanks; p++)
1117 {
1118 MPI_Recv(&nv[p], 1, MPI_INT, p, 455, MyComm, &status);
1119 MPI_Recv(&nvdofs[p], 1, MPI_INT, p, 456, MyComm, &status);
1120 MPI_Recv(&nedofs[p], 1, MPI_INT, p, 457, MyComm, &status);
1121 MPI_Recv(&nfdofs[p], 1, MPI_INT, p, 458, MyComm, &status);
1122 values[p] = new real_t[nv[p]];
1123 MPI_Recv(values[p], nv[p], MPITypeMap<real_t>::mpi_type, p, 460, MyComm,
1124 &status);
1125 }
1126
1127 int vdim = pfes -> GetVDim();
1128
1129 for (p = 0; p < NRanks; p++)
1130 {
1131 nrdofs[p] = nv[p]/vdim - nvdofs[p] - nedofs[p] - nfdofs[p];
1132 }
1133
1135 {
1136 for (int d = 0; d < vdim; d++)
1137 {
1138 for (p = 0; p < NRanks; p++)
1139 for (i = 0; i < nvdofs[p]; i++)
1140 {
1141 os << *values[p]++ << '\n';
1142 }
1143
1144 for (p = 0; p < NRanks; p++)
1145 for (i = 0; i < nedofs[p]; i++)
1146 {
1147 os << *values[p]++ << '\n';
1148 }
1149
1150 for (p = 0; p < NRanks; p++)
1151 for (i = 0; i < nfdofs[p]; i++)
1152 {
1153 os << *values[p]++ << '\n';
1154 }
1155
1156 for (p = 0; p < NRanks; p++)
1157 for (i = 0; i < nrdofs[p]; i++)
1158 {
1159 os << *values[p]++ << '\n';
1160 }
1161 }
1162 }
1163 else
1164 {
1165 for (p = 0; p < NRanks; p++)
1166 for (i = 0; i < nvdofs[p]; i++)
1167 for (int d = 0; d < vdim; d++)
1168 {
1169 os << *values[p]++ << '\n';
1170 }
1171
1172 for (p = 0; p < NRanks; p++)
1173 for (i = 0; i < nedofs[p]; i++)
1174 for (int d = 0; d < vdim; d++)
1175 {
1176 os << *values[p]++ << '\n';
1177 }
1178
1179 for (p = 0; p < NRanks; p++)
1180 for (i = 0; i < nfdofs[p]; i++)
1181 for (int d = 0; d < vdim; d++)
1182 {
1183 os << *values[p]++ << '\n';
1184 }
1185
1186 for (p = 0; p < NRanks; p++)
1187 for (i = 0; i < nrdofs[p]; i++)
1188 for (int d = 0; d < vdim; d++)
1189 {
1190 os << *values[p]++ << '\n';
1191 }
1192 }
1193
1194 for (p = 1; p < NRanks; p++)
1195 {
1196 values[p] -= nv[p];
1197 delete [] values[p];
1198 }
1199 os.flush();
1200 }
1201 else
1202 {
1203 MPI_Send(&nv[0], 1, MPI_INT, 0, 455, MyComm);
1204 MPI_Send(&nvdofs[0], 1, MPI_INT, 0, 456, MyComm);
1205 MPI_Send(&nedofs[0], 1, MPI_INT, 0, 457, MyComm);
1206 MPI_Send(&nfdofs[0], 1, MPI_INT, 0, 458, MyComm);
1207 MPI_Send(h_data, nv[0], MPITypeMap<real_t>::mpi_type, 0, 460, MyComm);
1208 }
1209
1210 delete [] values;
1211 delete [] nv;
1212 delete [] nvdofs;
1213 delete [] nedofs;
1214 delete [] nfdofs;
1215 delete [] nrdofs;
1216}
1217
1218real_t GlobalLpNorm(const real_t p, real_t loc_norm, MPI_Comm comm)
1219{
1220 real_t glob_norm;
1221
1222 // negative quadrature weights may cause the local norm to be negative
1223 loc_norm = fabs(loc_norm);
1224
1225 if (p < infinity())
1226 {
1227 loc_norm = pow(loc_norm, p);
1228
1229 MPI_Allreduce(&loc_norm, &glob_norm, 1, MPITypeMap<real_t>::mpi_type,
1230 MPI_SUM, comm);
1231
1232 glob_norm = pow(fabs(glob_norm), 1.0/p);
1233 }
1234 else
1235 {
1236 MPI_Allreduce(&loc_norm, &glob_norm, 1, MPITypeMap<real_t>::mpi_type,
1237 MPI_MAX, comm);
1238 }
1239
1240 return glob_norm;
1241}
1242
1245 GridFunction &flux, bool wcoef, int subdomain)
1246{
1247 ParFiniteElementSpace *ffes =
1248 dynamic_cast<ParFiniteElementSpace*>(flux.FESpace());
1249 MFEM_VERIFY(ffes, "the flux FE space must be ParFiniteElementSpace");
1250
1251 Array<int> count(flux.Size());
1252 SumFluxAndCount(blfi, flux, count, wcoef, subdomain);
1253
1254 // Accumulate flux and counts in parallel
1256 ffes->GroupComm().Bcast<real_t>(flux.HostReadWrite());
1257
1259 ffes->GroupComm().Bcast<int>(count.HostReadWrite());
1260
1261 // complete averaging
1262 for (int i = 0; i < count.Size(); i++)
1263 {
1264 if (count[i] != 0) { flux(i) /= count[i]; }
1265 }
1266
1267 if (ffes->Nonconforming())
1268 {
1269 // On a partially conforming flux space, project on the conforming space.
1270 // Using this code may lead to worse refinements in ex6, so we do not use
1271 // it by default.
1272
1273 // Vector conf_flux;
1274 // flux.ConformingProject(conf_flux);
1275 // flux.ConformingProlongate(conf_flux);
1276 }
1277}
1278
1279std::unique_ptr<ParGridFunction> ParGridFunction::ProlongateToMaxOrder() const
1280{
1281 ParMesh *mesh = pfes->GetParMesh();
1282 const FiniteElementCollection *pfesc = pfes->FEColl();
1283 const int vdim = pfes->GetVDim();
1284
1285 // Find the max order in the space
1286 const int maxOrder = pfes->GetMaxElementOrder();
1287
1288 // Create a visualization space of max order for all elements
1289 FiniteElementCollection *fecMax = pfesc->Clone(maxOrder);
1290 ParFiniteElementSpace *pfesMax = new ParFiniteElementSpace(mesh, fecMax, vdim,
1291 pfes->GetOrdering());
1292
1293 ParGridFunction *xMax = new ParGridFunction(pfesMax);
1294
1295 // Interpolate in the maximum-order space
1296 PRefinementTransferOperator P(*pfes, *pfesMax);
1297 P.Mult(*this, *xMax);
1298
1299 xMax->MakeOwner(fecMax);
1300 return std::unique_ptr<ParGridFunction>(xMax);
1301}
1302
1304 const ParGridFunction &x,
1305 ParFiniteElementSpace &smooth_flux_fes,
1306 ParFiniteElementSpace &flux_fes,
1307 Vector &errors,
1308 int norm_p, real_t solver_tol, int solver_max_it)
1309{
1310 // Compute fluxes in discontinuous space
1311 GridFunction flux(&flux_fes);
1312 flux = 0.0;
1313
1315 Array<int> xdofs, fdofs;
1316 Vector el_x, el_f;
1317 DofTransformation xtrans, ftrans;
1318
1319 for (int i = 0; i < xfes->GetNE(); i++)
1320 {
1321 xfes->GetElementVDofs(i, xdofs, xtrans);
1322 x.GetSubVector(xdofs, el_x);
1323 xtrans.InvTransformPrimal(el_x);
1324
1326 flux_integrator.ComputeElementFlux(*xfes->GetFE(i), *Transf, el_x,
1327 *flux_fes.GetFE(i), el_f, false);
1328
1329 flux_fes.GetElementVDofs(i, fdofs, ftrans);
1330 ftrans.TransformPrimal(el_f);
1331 flux.SetSubVector(fdofs, el_f);
1332 }
1333
1334 // Assemble the linear system for L2 projection into the "smooth" space
1335 ParBilinearForm *a = new ParBilinearForm(&smooth_flux_fes);
1336 ParLinearForm *b = new ParLinearForm(&smooth_flux_fes);
1338
1339 const FiniteElement *smooth_flux_fe = smooth_flux_fes.GetTypicalFE();
1340
1341 if (smooth_flux_fe->GetRangeType() == FiniteElement::SCALAR)
1342 {
1344 vmass->SetVDim(smooth_flux_fes.GetVDim());
1345 a->AddDomainIntegrator(vmass);
1346 b->AddDomainIntegrator(new VectorDomainLFIntegrator(f));
1347 }
1348 else
1349 {
1350 a->AddDomainIntegrator(new VectorFEMassIntegrator);
1351 b->AddDomainIntegrator(new VectorFEDomainLFIntegrator(f));
1352 }
1353
1354 b->Assemble();
1355 a->Assemble();
1356 a->Finalize();
1357
1358 // The destination of the projected discontinuous flux
1359 ParGridFunction smooth_flux(&smooth_flux_fes);
1360 smooth_flux = 0.0;
1361
1362 HypreParMatrix* A = a->ParallelAssemble();
1363 HypreParVector* B = b->ParallelAssemble();
1364 HypreParVector* X = smooth_flux.ParallelProject();
1365
1366 delete a;
1367 delete b;
1368
1369 // Define and apply a parallel PCG solver for AX=B with the BoomerAMG
1370 // preconditioner from hypre.
1371 HypreBoomerAMG *amg = new HypreBoomerAMG(*A);
1372 amg->SetPrintLevel(0);
1373 HyprePCG *pcg = new HyprePCG(*A);
1374 pcg->SetTol(solver_tol);
1375 pcg->SetMaxIter(solver_max_it);
1376 pcg->SetPrintLevel(0);
1377 pcg->SetPreconditioner(*amg);
1378 pcg->Mult(*B, *X);
1379
1380 // Extract the parallel grid function corresponding to the finite element
1381 // approximation X. This is the local solution on each processor.
1382 smooth_flux = *X;
1383
1384 delete A;
1385 delete B;
1386 delete X;
1387 delete amg;
1388 delete pcg;
1389
1390 // Proceed through the elements one by one, and find the Lp norm differences
1391 // between the flux as computed per element and the flux projected onto the
1392 // smooth_flux_fes space.
1393 real_t total_error = 0.0;
1394 errors.SetSize(xfes->GetNE());
1395 for (int i = 0; i < xfes->GetNE(); i++)
1396 {
1397 errors(i) = ComputeElementLpDistance(norm_p, i, smooth_flux, flux);
1398 total_error += pow(errors(i), norm_p);
1399 }
1400
1401 real_t glob_error;
1402 MPI_Allreduce(&total_error, &glob_error, 1, MPITypeMap<real_t>::mpi_type,
1403 MPI_SUM,
1404 xfes->GetComm());
1405
1406 return pow(glob_error, 1.0/norm_p);
1407}
1408
1410 const int ref_factor, const int vdim) const
1411{
1412 PLBound plb = GridFunction::GetBounds(lower, upper, ref_factor, vdim);
1413 int siz = vdim > 0 ? 1 : fes->GetVDim();
1414 MPI_Allreduce(MPI_IN_PLACE, lower.HostReadWrite(), siz,
1415 MFEM_MPI_REAL_T, MPI_MIN, pfes->GetComm());
1416 MPI_Allreduce(MPI_IN_PLACE, upper.HostReadWrite(), siz,
1417 MFEM_MPI_REAL_T, MPI_MAX, pfes->GetComm());
1418 return plb;
1419}
1420
1421} // namespace mfem
1422
1423#endif // MFEM_USE_MPI
void Reserve(int capacity)
Ensures that the allocated size is at least the given size.
Definition array.hpp:184
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
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
T * HostReadWrite()
Shortcut for mfem::ReadWrite(a.GetMemory(), a.Size(), false).
Definition array.hpp:401
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.
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:298
void InvTransformPrimal(real_t *v) const
Definition doftrans.cpp:47
void TransformPrimal(real_t *v) const
Definition doftrans.cpp:17
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
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:244
virtual FiniteElementCollection * Clone(int p) const
Instantiate a new collection of the same type with a different order.
Definition fe_coll.cpp:432
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:208
bool IsVariableOrder() const
Returns true if the space contains elements of varying polynomial orders.
Definition fespace.hpp:678
void DofsToVDofs(Array< int > &dofs, int ndofs=-1) const
Compute the full set of vdofs corresponding to each entry in dofs.
Definition fespace.cpp:230
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:3502
ElementTransformation * GetElementTransformation(int i) const
Definition fespace.hpp:905
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
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:3824
Ordering::Type GetOrdering() const
Return the ordering method.
Definition fespace.hpp:854
int GetNE() const
Returns number of elements in the mesh.
Definition fespace.hpp:869
const FiniteElementCollection * FEColl() const
Definition fespace.hpp:856
Mesh * GetMesh() const
Returns the mesh.
Definition fespace.hpp:644
int GetVSize() const
Return the number of vector dofs, i.e. GetNDofs() x GetVDim().
Definition fespace.hpp:826
int GetVDim() const
Returns the vector dimension of the finite element space.
Definition fespace.hpp:819
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:3860
Abstract class for all finite elements.
Definition fe_base.hpp:247
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:328
int GetOrder() const
Returns the order of the finite element. In the case of anisotropic orders, returns the maximum order...
Definition fe_base.hpp:341
int GetMapType() const
Returns the FiniteElement::MapType of the element describing how reference functions are mapped to ph...
Definition fe_base.hpp:363
int GetRangeType() const
Returns the FiniteElement::RangeType of the element, one of {SCALAR, VECTOR}.
Definition fe_base.hpp:354
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:337
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:32
void ComputeMeans(AvgType type, Array< int > &zones_per_vdof)
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:449
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:168
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:234
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:123
virtual void GetElementDofValues(int el, Vector &dof_vals) const
FiniteElementSpace * FESpace()
virtual void ProjectCoefficient(Coefficient &coeff)
Project coeff Coefficient to this GridFunction. The projection computation depends on the choice of t...
void ProjectDeltaCoefficient(DeltaCoefficient &delta_coeff, real_t &integral)
void ProjectDiscCoefficient(VectorCoefficient &coeff, Array< int > &dof_attr)
FiniteElementSpace * fes
FE space on which the grid function lives. Owned if fec_owned is not NULL.
Definition gridfunc.hpp:35
FiniteElementCollection * fec_owned
Used when the grid function is read from a file. It can also be set explicitly, see MakeOwner().
Definition gridfunc.hpp:41
void SumFluxAndCount(BilinearFormIntegrator &blfi, GridFunction &flux, Array< int > &counts, bool wcoef, int subdomain)
Definition gridfunc.cpp:282
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...
virtual void GetVectorValue(int i, const IntegrationPoint &ip, Vector &val) const
Definition gridfunc.cpp:474
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:226
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.
static void Sum(OpData< T >)
Reduce operation Sum, instantiated for int and double.
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 and double.
The BoomerAMG solver in hypre.
Definition hypre.hpp:1737
void SetPrintLevel(int print_level)
Definition hypre.hpp:1817
PCG solver in hypre.
Definition hypre.hpp:1321
void Mult(const HypreParVector &b, HypreParVector &x) const override
Solve Ax=b with hypre's PCG.
Definition hypre.cpp:4258
void SetPrintLevel(int print_lvl)
Definition hypre.cpp:4230
void SetPreconditioner(HypreSolver &precond)
Set the hypre solver to be used as a preconditioner.
Definition hypre.cpp:4235
void SetMaxIter(int max_iter)
Definition hypre.cpp:4220
void SetTol(real_t tol)
Definition hypre.cpp:4210
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:1863
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:100
int GetNPoints() const
Returns the number of the points in the integration rule.
Definition intrules.hpp:256
IntegrationPoint & IntPoint(int i)
Returns a reference to the i-th integration point.
Definition intrules.hpp:259
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:65
void GetFaceInfos(int Face, int *Inf1, int *Inf2) const
Definition mesh.cpp:1563
int GetNumFaces() const
Return the number of faces (3D), edges (2D) or vertices (1D).
Definition mesh.cpp:6846
int GetNE() const
Returns number of elements.
Definition mesh.hpp:1377
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:110
void GetFaceElements(int Face, int *Elem1, int *Elem2) const
Definition mesh.cpp:1557
int SpaceDimension() const
Dimension of the physical space containing the mesh.
Definition mesh.hpp:1309
Abstract operator.
Definition operator.hpp:25
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:100
Matrix-free transfer operator between finite element spaces on the same mesh.
Definition transfer.hpp:567
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
void DivideByGroupSize(real_t *vec)
Scale a vector of true dofs.
HypreParVector * NewTrueDofVector()
Definition pfespace.hpp:401
const FiniteElement * GetFaceNbrFE(int i, int ndofs=0) const
GroupCommunicator & GroupComm()
Return a reference to the internal GroupCommunicator (on VDofs)
Definition pfespace.hpp:408
const Operator * GetProlongationMatrix() const override
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:391
void GetFaceNbrElementVDofs(int i, Array< int > &vdofs, DofTransformation &doftrans) const
const SparseMatrix * GetRestrictionMatrix() const override
Get the R matrix which restricts a local dof vector to true dof vector.
Definition pfespace.hpp:470
ParMesh * GetParMesh() const
Definition pfespace.hpp:341
const FiniteElement * GetFE(int i) const override
Definition pfespace.cpp:632
ElementTransformation * GetFaceNbrElementTransformation(int i) const
Definition pfespace.hpp:486
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 ProjectDiscCoefficient(VectorCoefficient &coeff) override
Project a discontinuous vector coefficient as a grid function on a continuous finite element space....
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 ComputeFlux(BilinearFormIntegrator &blfi, GridFunction &flux, bool wcoef=true, int subdomain=-1) override
void ProjectBdrCoefficient(Coefficient *coeff[], VectorCoefficient *vcoeff, const Array< int > &attr)
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.
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
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 ProjectCoefficient(Coefficient &coeff) override
Project coeff Coefficient to this GridFunction. The projection computation depends on the choice of t...
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:85
void SetSpace(FiniteElementSpace *f) override
Associate a new FiniteElementSpace with the ParGridFunction.
Definition pgridfunc.cpp:91
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. Only boundary attri...
Class for parallel linear form.
Class for parallel meshes.
Definition pmesh.hpp:34
Mesh GetSerialMesh(int save_rank) const
Definition pmesh.cpp:5319
ElementTransformation * GetFaceNbrElementTransformation(int FaceNo)
Returns a pointer to the transformation defining the i-th face neighbor.
Definition pmesh.cpp:3098
MPI_Comm GetComm() const
Definition pmesh.hpp:405
int GetMyRank() const
Definition pmesh.hpp:407
int GetNSharedFaces() const
Return the number of shared faces (3D), edges (2D), vertices (1D)
Definition pmesh.cpp:3164
int GetNRanks() const
Definition pmesh.hpp:406
FaceElementTransformations * GetFaceElementTransformations(int FaceNo, int mask=31) override
Definition pmesh.cpp:2907
int GetSharedFace(int sface) const
Return the local face index for the given shared face.
Definition pmesh.cpp:3183
int GetNFaceNeighbors() const
Definition pmesh.hpp:576
real_t GetFaceNbrElementSize(int i, int type=0)
Definition pmesh.cpp:3159
int GetFaceNbrRank(int fn) const
Definition pmesh.cpp:2806
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
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.
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
Memory< real_t > data
Definition vector.hpp:85
void Destroy()
Destroy a vector.
Definition vector.hpp:673
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:584
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
real_t b
Definition lissajous.cpp:42
real_t a
Definition lissajous.cpp:41
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:348
real_t infinity()
Define a shortcut for std::numeric_limits<double>::infinity()
Definition vector.hpp:47
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:839
IntegrationRules IntRules(0, Quadrature1D::GaussLegendre)
A global object with all integration rules (defined in intrules.cpp)
Definition intrules.hpp:492
real_t p(const Vector &x, real_t t)
Helper struct to convert a C++ type to an MPI type.