MFEM v4.8.0
Finite element discretization library
Loading...
Searching...
No Matches
hybridization.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 "hybridization.hpp"
13#include "hybridization_ext.hpp"
14#include "gridfunc.hpp"
15
16#ifdef MFEM_USE_MPI
17#include "pfespace.hpp"
18#endif
19
20#include <map>
21
22// uncomment next line for debugging: write C and P to file
23// #define MFEM_DEBUG_HYBRIDIZATION_CP
24#ifdef MFEM_DEBUG_HYBRIDIZATION_CP
25#include <fstream>
26#endif
27
28namespace mfem
29{
30
32 FiniteElementSpace *c_fespace)
33 : fes(*fespace), c_fes(*c_fespace)
34{
35#ifdef MFEM_USE_MPI
37#endif
38}
39
41{
43 {
44 for (size_t k=0; k < boundary_constraint_integs.size(); k++)
45 { delete boundary_constraint_integs[k]; }
46 }
47}
48
53
55{
56 const int NE = fes.GetNE();
57 int num_hat_dofs = hat_offsets[NE];
58 Array<int> vdofs, c_vdofs;
59
60#if defined(MFEM_USE_DOUBLE)
61 constexpr real_t mtol = 1e-12;
62#elif defined(MFEM_USE_SINGLE)
63 constexpr real_t mtol = 4e-6;
64#else
65#error "Only single and double precision are supported!"
66 constexpr real_t mtol = 1.;
67#endif
68
69 int c_num_face_nbr_dofs = 0;
70#ifdef MFEM_USE_MPI
71 ParFiniteElementSpace *c_pfes = dynamic_cast<ParFiniteElementSpace*>(&c_fes);
72 ParMesh *pmesh = c_pfes ? c_pfes->GetParMesh() : NULL;
73 HYPRE_BigInt num_shared_slave_faces = 0, glob_num_shared_slave_faces = 0;
74 if (c_pfes)
75 {
76 if (pmesh->Nonconforming())
77 {
78 const int dim = pmesh->Dimension();
79 const NCMesh::NCList &shared = pmesh->pncmesh->GetSharedList(dim-1);
80 num_shared_slave_faces = (HYPRE_BigInt) shared.slaves.Size();
81 MPI_Allreduce(&num_shared_slave_faces, &glob_num_shared_slave_faces, 1,
82 HYPRE_MPI_BIG_INT, MPI_SUM, pmesh->GetComm());
83 MFEM_ASSERT(glob_num_shared_slave_faces%2 == 0, "");
84 glob_num_shared_slave_faces /= 2;
85 if (glob_num_shared_slave_faces)
86 {
87 c_pfes->ExchangeFaceNbrData();
88 c_num_face_nbr_dofs = c_pfes->GetFaceNbrVSize();
89 }
90#ifdef MFEM_DEBUG_HERE
91 MFEM_WARNING('[' << c_pfes->GetMyRank() <<
92 "] num_shared_slave_faces = " << num_shared_slave_faces
93 << ", glob_num_shared_slave_faces = "
94 << glob_num_shared_slave_faces
95 << "\n num_face_nbr_dofs = " << c_num_face_nbr_dofs
96 << ", num_shared_faces = " << pmesh->GetNSharedFaces());
97#undef MFEM_DEBUG_HERE
98#endif
99 }
100 }
101#endif
102
103 const int c_vsize = c_fes.GetVSize();
104 Ct.reset(new SparseMatrix(num_hat_dofs, c_vsize + c_num_face_nbr_dofs));
105
106 if (c_bfi)
107 {
108 const int skip_zeros = 1;
109 DenseMatrix elmat;
111 Mesh *mesh = fes.GetMesh();
112 int num_faces = mesh->GetNumFaces();
113 for (int i = 0; i < num_faces; i++)
114 {
115 FTr = mesh->GetInteriorFaceTransformations(i);
116 if (!FTr) { continue; }
117
118 int o1 = hat_offsets[FTr->Elem1No];
119 int s1 = hat_offsets[FTr->Elem1No+1] - o1;
120 int o2 = hat_offsets[FTr->Elem2No];
121 int s2 = hat_offsets[FTr->Elem2No+1] - o2;
122 vdofs.SetSize(s1 + s2);
123 for (int j = 0; j < s1; j++)
124 {
125 vdofs[j] = o1 + j;
126 }
127 for (int j = 0; j < s2; j++)
128 {
129 vdofs[s1+j] = o2 + j;
130 }
131 c_fes.GetFaceVDofs(i, c_vdofs);
132 c_bfi->AssembleFaceMatrix(*c_fes.GetFaceElement(i),
133 *fes.GetFE(FTr->Elem1No),
134 *fes.GetFE(FTr->Elem2No),
135 *FTr, elmat);
136 // zero-out small elements in elmat
137 elmat.Threshold(mtol * elmat.MaxMaxNorm());
138 Ct->AddSubMatrix(vdofs, c_vdofs, elmat, skip_zeros);
139 }
140
141 if (!boundary_constraint_integs.empty())
142 {
143 const FiniteElement *fe1, *fe2;
144 const FiniteElement *face_el;
145
146 // Which boundary attributes need to be processed?
147 Array<int> bdr_attr_marker(mesh->bdr_attributes.Size() ?
148 mesh->bdr_attributes.Max() : 0);
149 bdr_attr_marker = 0;
150 for (size_t k = 0; k < boundary_constraint_integs.size(); k++)
151 {
153 {
154 bdr_attr_marker = 1;
155 break;
156 }
158 MFEM_ASSERT(bdr_marker.Size() == bdr_attr_marker.Size(),
159 "invalid boundary marker for boundary face integrator #"
160 << k << ", counting from zero");
161 for (int i = 0; i < bdr_attr_marker.Size(); i++)
162 {
163 bdr_attr_marker[i] |= bdr_marker[i];
164 }
165 }
166
167 for (int i = 0; i < fes.GetNBE(); i++)
168 {
169 const int bdr_attr = mesh->GetBdrAttribute(i);
170 if (bdr_attr_marker[bdr_attr-1] == 0) { continue; }
171
172 FTr = mesh->GetBdrFaceTransformations(i);
173 if (!FTr) { continue; }
174
175 int o1 = hat_offsets[FTr->Elem1No];
176 int s1 = hat_offsets[FTr->Elem1No+1] - o1;
177
178 vdofs.SetSize(s1);
179 for (int j = 0; j < s1; j++)
180 {
181 vdofs[j] = o1 + j;
182 }
183 int iface = mesh->GetBdrElementFaceIndex(i);
184 c_fes.GetFaceVDofs(iface, c_vdofs);
185 face_el = c_fes.GetFaceElement(iface);
186 fe1 = fes.GetFE(FTr -> Elem1No);
187 // The fe2 object is really a dummy and not used on the boundaries,
188 // but we can't dereference a NULL pointer, and we don't want to
189 // actually make a fake element.
190 fe2 = fe1;
191 for (size_t k = 0; k < boundary_constraint_integs.size(); k++)
192 {
194 (*boundary_constraint_integs_marker[k])[bdr_attr-1] == 0) { continue; }
195
196 boundary_constraint_integs[k]->AssembleFaceMatrix(*face_el, *fe1, *fe2, *FTr,
197 elmat);
198 // zero-out small elements in elmat
199 elmat.Threshold(mtol * elmat.MaxMaxNorm());
200 Ct->AddSubMatrix(vdofs, c_vdofs, elmat, skip_zeros);
201 }
202 }
203 }
204#ifdef MFEM_USE_MPI
205 if (pmesh)
206 {
207 // Assemble local contribution to Ct from shared faces
208 const int num_shared_faces = pmesh->GetNSharedFaces();
209 for (int i = 0; i < num_shared_faces; i++)
210 {
211 const int face_no = pmesh->GetSharedFace(i);
212 const bool ghost_sface = (face_no >= num_faces);
213 const FiniteElement *fe, *face_fe;
214 if (!ghost_sface)
215 {
216 FTr = pmesh->GetFaceElementTransformations(face_no);
217 MFEM_ASSERT(FTr->Elem2No < 0, "");
218 face_fe = c_fes.GetFaceElement(face_no);
219 c_fes.GetFaceVDofs(face_no, c_vdofs);
220 }
221 else
222 {
223 const int fill2 = false; // only need side "1" data
224 FTr = pmesh->GetSharedFaceTransformations(i, fill2);
225 face_fe = c_pfes->GetFaceNbrFaceFE(face_no);
226 c_pfes->GetFaceNbrFaceVDofs(face_no, c_vdofs);
228 for (int j = 0; j < c_vdofs.Size(); j++)
229 {
230 c_vdofs[j] += c_vsize;
231 }
232 }
233 int o1 = hat_offsets[FTr->Elem1No];
234 int s1 = hat_offsets[FTr->Elem1No+1] - o1;
235 vdofs.SetSize(s1);
236 for (int j = 0; j < s1; j++)
237 {
238 vdofs[j] = o1 + j;
239 }
240 fe = fes.GetFE(FTr->Elem1No);
241 c_bfi->AssembleFaceMatrix(*face_fe, *fe, *fe, *FTr, elmat);
242 // zero-out small elements in elmat
243 elmat.Threshold(mtol * elmat.MaxMaxNorm());
244 Ct->AddSubMatrix(vdofs, c_vdofs, elmat, skip_zeros);
245 }
246 if (glob_num_shared_slave_faces)
247 {
248 // Convert Ct to parallel and then transpose it:
249 Ct->Finalize(skip_zeros);
250 HYPRE_BigInt Ct_num_rows = Ct->Height();
251 Array<HYPRE_BigInt> Ct_rows;
252 Array<HYPRE_BigInt> *offsets[1] = { &Ct_rows };
253 pmesh->GenerateOffsets(1, &Ct_num_rows, offsets);
254 Array<HYPRE_BigInt> Ct_J(Ct->NumNonZeroElems());
255 HYPRE_BigInt c_ldof_offset = c_pfes->GetMyDofOffset();
256 const HYPRE_BigInt *c_face_nbr_glob_ldof =
257 c_pfes->GetFaceNbrGlobalDofMap();
258 int *J = Ct->GetJ();
259 for (int i = 0; i < Ct_J.Size(); i++)
260 {
261 Ct_J[i] = J[i] < c_vsize ?
262 J[i] + c_ldof_offset :
263 c_face_nbr_glob_ldof[J[i] - c_vsize];
264 }
265 HypreParMatrix pCt(pmesh->GetComm(), Ct->Height(),
266 Ct_rows.Last(), c_pfes->GlobalVSize(),
267 Ct->GetI(), Ct_J.GetData(), Ct->GetData(),
268 Ct_rows, c_pfes->GetDofOffsets());
269 Ct_J.DeleteAll();
270 pC.reset(pCt.Transpose());
271 }
272 if (pmesh->Nonconforming())
273 {
274 // TODO - Construct P_pc directly in the pH format
276 }
277 }
278#endif
279 Ct->Finalize(skip_zeros);
280 }
281 else
282 {
283 // Check if c_fes is really needed here.
284 MFEM_ABORT("TODO: algebraic definition of C");
285 }
286}
287
288void Hybridization::Init(const Array<int> &ess_tdof_list)
289{
290 if (Ct) { return; }
291
292 if (ext)
293 {
294 ext->Init(ess_tdof_list);
295 return;
296 }
297
298 // count the number of dofs in the discontinuous version of fes:
299 const int NE = fes.GetNE();
300 Array<int> vdofs;
301 int num_hat_dofs = 0;
302 hat_offsets.SetSize(NE+1);
303 hat_offsets[0] = 0;
304 for (int i = 0; i < NE; i++)
305 {
306 fes.GetElementVDofs(i, vdofs);
307 num_hat_dofs += vdofs.Size();
308 hat_offsets[i+1] = num_hat_dofs;
309 }
310
311 // Assemble the constraint matrix C
312 ConstructC();
313
314#ifdef MFEM_DEBUG_HYBRIDIZATION_CP
315 // Debug: write C and P to file
316 {
317 std::ofstream C_file("C_matrix.txt");
319 C->PrintMatlab(C_file);
320 delete C;
321
323 if (P)
324 {
325 std::ofstream P_file("P_matrix.txt");
326 P->PrintMatlab(P_file);
327 }
328 }
329#endif
330
331 // Define the "free" (0) and "essential" (1) hat_dofs.
332 // The "essential" hat_dofs are those that depend only on essential cdofs;
333 // all other hat_dofs are "free".
334 hat_dofs_marker.SetSize(num_hat_dofs);
335 Array<int> free_tdof_marker;
336#ifdef MFEM_USE_MPI
337 ParFiniteElementSpace *pfes = dynamic_cast<ParFiniteElementSpace*>(&fes);
338 free_tdof_marker.SetSize(pfes ? pfes->TrueVSize() :
340#else
341 free_tdof_marker.SetSize(fes.GetConformingVSize());
342#endif
343 free_tdof_marker = 1;
344 for (int i = 0; i < ess_tdof_list.Size(); i++)
345 {
346 free_tdof_marker[ess_tdof_list[i]] = 0;
347 }
348 Array<int> free_vdofs_marker;
349#ifdef MFEM_USE_MPI
350 if (!pfes)
351 {
353 if (!cP)
354 {
355 free_vdofs_marker.MakeRef(free_tdof_marker);
356 }
357 else
358 {
359 free_vdofs_marker.SetSize(fes.GetVSize());
360 cP->BooleanMult(free_tdof_marker, free_vdofs_marker);
361 }
362 }
363 else
364 {
366 free_vdofs_marker.SetSize(fes.GetVSize());
367 P->BooleanMult(1, free_tdof_marker, 0, free_vdofs_marker);
368 }
369#else
371 if (!cP)
372 {
373 free_vdofs_marker.MakeRef(free_tdof_marker);
374 }
375 else
376 {
377 free_vdofs_marker.SetSize(fes.GetVSize());
378 cP->BooleanMult(free_tdof_marker, free_vdofs_marker);
379 }
380#endif
381 for (int i = 0; i < NE; i++)
382 {
383 fes.GetElementVDofs(i, vdofs);
385 for (int j = 0; j < vdofs.Size(); j++)
386 {
387 hat_dofs_marker[hat_offsets[i]+j] = ! free_vdofs_marker[vdofs[j]];
388 }
389 }
390#ifndef MFEM_DEBUG
391 // In DEBUG mode this array is used below.
392 free_tdof_marker.DeleteAll();
393#endif
394 free_vdofs_marker.DeleteAll();
395 // Split the "free" (0) hat_dofs into "internal" (0) or "boundary" (-1).
396 // The "internal" hat_dofs are those "free" hat_dofs for which the
397 // corresponding column in C is zero; otherwise the free hat_dof is
398 // "boundary".
399 for (int i = 0; i < num_hat_dofs; i++)
400 {
401 // skip "essential" hat_dofs and empty rows in Ct
402 if (hat_dofs_marker[i] != 1 && Ct->RowSize(i) > 0)
403 {
404 hat_dofs_marker[i] = -1; // mark this hat_dof as "boundary"
405 }
406 }
407
408 // Define Af_offsets and Af_f_offsets
409 Af_offsets.SetSize(NE+1);
410 Af_offsets[0] = 0;
411 Af_f_offsets.SetSize(NE+1);
412 Af_f_offsets[0] = 0;
413 // #define MFEM_DEBUG_HERE // uncomment to enable printing of hat dofs stats
414#ifdef MFEM_DEBUG_HERE
415 int b_size = 0;
416#endif
417 for (int i = 0; i < NE; i++)
418 {
419 int f_size = 0; // count the "free" hat_dofs in element i
420 for (int j = hat_offsets[i]; j < hat_offsets[i+1]; j++)
421 {
422 if (hat_dofs_marker[j] != 1) { f_size++; }
423#ifdef MFEM_DEBUG_HERE
424 if (hat_dofs_marker[j] == -1) { b_size++; }
425#endif
426 }
427 Af_offsets[i+1] = Af_offsets[i] + f_size*f_size;
428 Af_f_offsets[i+1] = Af_f_offsets[i] + f_size;
429 }
430
431#ifdef MFEM_DEBUG_HERE
432#ifndef MFEM_USE_MPI
433 int myid = 0;
434#else
435 int myid = pmesh ? pmesh->GetMyRank() : 0;
436#endif
437 int i_size = Af_f_offsets[NE] - b_size;
438 int e_size = num_hat_dofs - (i_size + b_size);
439 mfem::out << "\nHybridization::Init:"
440 << " [" << myid << "] hat dofs - \"internal\": " << i_size
441 << ", \"boundary\": " << b_size
442 << ", \"essential\": " << e_size << '\n' << std::endl;
443#undef MFEM_DEBUG_HERE
444#endif
445
448
449#ifdef MFEM_DEBUG
450 // check that Ref = 0
452 if (!R) { return; }
453 Array<int> vdof_marker(fes.GetVSize()); // 0 - f, 1 - e
454 vdof_marker = 0;
455 for (int i = 0; i < NE; i++)
456 {
457 fes.GetElementVDofs(i, vdofs);
459 for (int j = 0; j < vdofs.Size(); j++)
460 {
461 if (hat_dofs_marker[hat_offsets[i]+j] == 1) // "essential" hat dof
462 {
463 vdof_marker[vdofs[j]] = 1;
464 }
465 }
466 }
467 for (int tdof = 0; tdof < R->Height(); tdof++)
468 {
469 if (free_tdof_marker[tdof]) { continue; }
470
471 const int ncols = R->RowSize(tdof);
472 const int *cols = R->GetRowColumns(tdof);
473 const real_t *vals = R->GetRowEntries(tdof);
474 for (int j = 0; j < ncols; j++)
475 {
476 if (std::abs(vals[j]) != 0.0 && vdof_marker[cols[j]] == 0)
477 {
478 MFEM_ABORT("Ref != 0");
479 }
480 }
481 }
482#endif
483}
484
486 int el, Array<int> &i_dofs, Array<int> &b_dofs) const
487{
488 // returns local indices in i_dofs and b_dofs
489 int h_start, h_end;
490
491 h_start = hat_offsets[el];
492 h_end = hat_offsets[el+1];
493 i_dofs.Reserve(h_end-h_start);
494 i_dofs.SetSize(0);
495 b_dofs.Reserve(h_end-h_start);
496 b_dofs.SetSize(0);
497 for (int i = h_start; i < h_end; i++)
498 {
499 int mark = hat_dofs_marker[i];
500 if (mark == 0) { i_dofs.Append(i-h_start); }
501 else if (mark == -1) { b_dofs.Append(i-h_start); }
502 }
503}
504
505void Hybridization::GetBDofs(int el, int &num_idofs, Array<int> &b_dofs) const
506{
507 // returns global indices in b_dofs
508 const int h_start = hat_offsets[el];
509 const int h_end = hat_offsets[el+1];
510 b_dofs.Reserve(h_end-h_start);
511 b_dofs.SetSize(0);
512 num_idofs = 0;
513 for (int i = h_start; i < h_end; i++)
514 {
515 int mark = hat_dofs_marker[i];
516 if (mark == 0) { num_idofs++; }
517 else if (mark == -1) { b_dofs.Append(i); }
518 }
519}
520
522{
523 if (ext)
524 {
525 ext->AssembleMatrix(el, A);
526 return;
527 }
528
529 Array<int> i_dofs, b_dofs;
530
531 GetIBDofs(el, i_dofs, b_dofs);
532
533 DenseMatrix A_ii(&Af_data[Af_offsets[el]], i_dofs.Size(), i_dofs.Size());
534 DenseMatrix A_ib(A_ii.Data() + i_dofs.Size()*i_dofs.Size(),
535 i_dofs.Size(), b_dofs.Size());
536 DenseMatrix A_bi(A_ib.Data() + i_dofs.Size()*b_dofs.Size(),
537 b_dofs.Size(), i_dofs.Size());
538 DenseMatrix A_bb(A_bi.Data() + b_dofs.Size()*i_dofs.Size(),
539 b_dofs.Size(), b_dofs.Size());
540
541 for (int j = 0; j < i_dofs.Size(); j++)
542 {
543 int j_dof = i_dofs[j];
544 for (int i = 0; i < i_dofs.Size(); i++)
545 {
546 A_ii(i,j) = A(i_dofs[i],j_dof);
547 }
548 for (int i = 0; i < b_dofs.Size(); i++)
549 {
550 A_bi(i,j) = A(b_dofs[i],j_dof);
551 }
552 }
553 for (int j = 0; j < b_dofs.Size(); j++)
554 {
555 int j_dof = b_dofs[j];
556 for (int i = 0; i < i_dofs.Size(); i++)
557 {
558 A_ib(i,j) = A(i_dofs[i],j_dof);
559 }
560 for (int i = 0; i < b_dofs.Size(); i++)
561 {
562 A_bb(i,j) = A(b_dofs[i],j_dof);
563 }
564 }
565}
566
568{
569 if (ext)
570 {
571 ext->AssembleElementMatrices(el_mats);
572 return;
573 }
574
575 for (int e = 0; e < el_mats.SizeK(); ++e)
576 {
577 AssembleMatrix(e, el_mats(e));
578 }
579}
580
582{
583 if (ext)
584 {
585 ext->AssembleBdrMatrix(bdr_el, A);
586 return;
587 }
588
589 // Not tested.
590#ifdef MFEM_DEBUG
591 Array<int> vdofs, bvdofs;
592 fes.GetBdrElementVDofs(bdr_el, bvdofs);
593#endif
594
595 int el;
596 DenseMatrix B(A);
597 Array<int> i_dofs, b_dofs, e2f;
598
599 {
600 int info, vdim = fes.GetVDim();
601 Array<int> lvdofs;
602 Mesh *mesh = fes.GetMesh();
603 mesh->GetBdrElementAdjacentElement(bdr_el, el, info);
604 e2f.SetSize(hat_offsets[el+1]-hat_offsets[el], -1);
605 lvdofs.Reserve(A.Height());
607 mesh->Dimension()-1, info, lvdofs);
608 // Convert local element dofs to local element vdofs.
609 Ordering::DofsToVDofs<Ordering::byNODES>(e2f.Size()/vdim, vdim, lvdofs);
610 MFEM_ASSERT(lvdofs.Size() == A.Height(), "internal error");
611#ifdef MFEM_DEBUG
612 fes.GetElementVDofs(el, vdofs);
613 for (int i = 0; i < lvdofs.Size(); i++)
614 {
615 int bd = lvdofs[i];
616 bd = (bd >= 0) ? vdofs[bd] : -1-vdofs[-1-bd];
617 MFEM_ASSERT(bvdofs[i] == bd, "internal error");
618 }
619#endif
620 B.AdjustDofDirection(lvdofs);
622 // Create a map from local element vdofs to local boundary (face) vdofs.
623 for (int i = 0; i < lvdofs.Size(); i++)
624 {
625 e2f[lvdofs[i]] = i;
626 }
627 }
628
629 GetIBDofs(el, i_dofs, b_dofs);
630
631 DenseMatrix A_ii(&Af_data[Af_offsets[el]], i_dofs.Size(), i_dofs.Size());
632 DenseMatrix A_ib(A_ii.Data() + i_dofs.Size()*i_dofs.Size(),
633 i_dofs.Size(), b_dofs.Size());
634 DenseMatrix A_bi(A_ib.Data() + i_dofs.Size()*b_dofs.Size(),
635 b_dofs.Size(), i_dofs.Size());
636 DenseMatrix A_bb(A_bi.Data() + b_dofs.Size()*i_dofs.Size(),
637 b_dofs.Size(), b_dofs.Size());
638
639 for (int j = 0; j < i_dofs.Size(); j++)
640 {
641 int j_f = e2f[i_dofs[j]];
642 if (j_f == -1) { continue; }
643 for (int i = 0; i < i_dofs.Size(); i++)
644 {
645 int i_f = e2f[i_dofs[i]];
646 if (i_f == -1) { continue; }
647 A_ii(i,j) += B(i_f,j_f);
648 }
649 for (int i = 0; i < b_dofs.Size(); i++)
650 {
651 int i_f = e2f[b_dofs[i]];
652 if (i_f == -1) { continue; }
653 A_bi(i,j) += B(i_f,j_f);
654 }
655 }
656 for (int j = 0; j < b_dofs.Size(); j++)
657 {
658 int j_f = e2f[b_dofs[j]];
659 if (j_f == -1) { continue; }
660 for (int i = 0; i < i_dofs.Size(); i++)
661 {
662 int i_f = e2f[i_dofs[i]];
663 if (i_f == -1) { continue; }
664 A_ib(i,j) += B(i_f,j_f);
665 }
666 for (int i = 0; i < b_dofs.Size(); i++)
667 {
668 int i_f = e2f[b_dofs[i]];
669 if (i_f == -1) { continue; }
670 A_bb(i,j) += B(i_f,j_f);
671 }
672 }
673}
674
676{
677 if (ext)
678 {
679 ext->ConstructH();
680 return;
681 }
682
683 const int skip_zeros = 1;
684 Array<int> c_dof_marker(Ct->Width());
685 Array<int> b_dofs, c_dofs;
686 const int NE = fes.GetNE();
687 DenseMatrix Cb_t, Sb_inv_Cb_t, Hb;
688#ifndef MFEM_USE_MPI
689 H.reset(new SparseMatrix(Ct->Width()));
690#else
691 if (!pC)
692 {
693 H.reset(new SparseMatrix(Ct->Width()));
694 }
695 // V = Sb^{-1} Cb^T, for parallel non-conforming meshes
696 SparseMatrix *V = pC ? new SparseMatrix(Ct->Height(), Ct->Width()) : NULL;
697#endif
698
699 c_dof_marker = -1;
700 int c_mark_start = 0;
701 for (int el = 0; el < NE; el++)
702 {
703 int i_dofs_size;
704 GetBDofs(el, i_dofs_size, b_dofs);
705
706 LUFactors LU_ii(&Af_data[Af_offsets[el]], Af_ipiv + Af_f_offsets[el]);
707 real_t *A_ib_data = LU_ii.data + i_dofs_size*i_dofs_size;
708 real_t *A_bi_data = A_ib_data + i_dofs_size*b_dofs.Size();
709 LUFactors LU_bb(A_bi_data + i_dofs_size*b_dofs.Size(),
710 LU_ii.ipiv + i_dofs_size);
711
712 LU_ii.Factor(i_dofs_size);
713 LU_ii.BlockFactor(i_dofs_size, b_dofs.Size(),
714 A_ib_data, A_bi_data, LU_bb.data);
715 LU_bb.Factor(b_dofs.Size());
716
717 // Extract Cb_t from Ct, define c_dofs
718 c_dofs.SetSize(0);
719 for (int i = 0; i < b_dofs.Size(); i++)
720 {
721 const int row = b_dofs[i];
722 const int ncols = Ct->RowSize(row);
723 const int *cols = Ct->GetRowColumns(row);
724 for (int j = 0; j < ncols; j++)
725 {
726 const int c_dof = cols[j];
727 if (c_dof_marker[c_dof] < c_mark_start)
728 {
729 c_dof_marker[c_dof] = c_mark_start + c_dofs.Size();
730 c_dofs.Append(c_dof);
731 }
732 }
733 }
734 Cb_t.SetSize(b_dofs.Size(), c_dofs.Size());
735 Cb_t = 0.0;
736 for (int i = 0; i < b_dofs.Size(); i++)
737 {
738 const int row = b_dofs[i];
739 const int ncols = Ct->RowSize(row);
740 const int *cols = Ct->GetRowColumns(row);
741 const real_t *vals = Ct->GetRowEntries(row);
742 for (int j = 0; j < ncols; j++)
743 {
744 const int loc_j = c_dof_marker[cols[j]] - c_mark_start;
745 Cb_t(i,loc_j) = vals[j];
746 }
747 }
748
749 // Compute Hb = Cb Sb^{-1} Cb^t
750 Sb_inv_Cb_t = Cb_t;
751 LU_bb.Solve(Cb_t.Height(), Cb_t.Width(), Sb_inv_Cb_t.Data());
752#ifdef MFEM_USE_MPI
753 if (!pC)
754#endif
755 {
756 Hb.SetSize(Cb_t.Width());
757 MultAtB(Cb_t, Sb_inv_Cb_t, Hb);
758
759 // Assemble Hb into H
760 H->AddSubMatrix(c_dofs, c_dofs, Hb, skip_zeros);
761 }
762#ifdef MFEM_USE_MPI
763 else
764 {
765 V->AddSubMatrix(b_dofs, c_dofs, Sb_inv_Cb_t, skip_zeros);
766 }
767#endif
768
769 c_mark_start += c_dofs.Size();
770 MFEM_VERIFY(c_mark_start >= 0, "overflow"); // check for overflow
771 }
772 const bool fix_empty_rows = true;
773#ifndef MFEM_USE_MPI
774 H->Finalize(skip_zeros, fix_empty_rows);
775#else
776 ParFiniteElementSpace *c_pfes = dynamic_cast<ParFiniteElementSpace*>(&c_fes);
777 if (!pC)
778 {
779 H->Finalize(skip_zeros, fix_empty_rows);
780 if (!c_pfes) { return; }
781
782 OperatorHandle pP(pH.Type()), dH(pH.Type());
783 // TODO - construct P_pc / Dof_TrueDof_Matrix directly in the pH format
784 pP.ConvertFrom(P_pc ? P_pc.get() : c_pfes->Dof_TrueDof_Matrix());
785 dH.MakeSquareBlockDiag(c_pfes->GetComm(),c_pfes->GlobalVSize(),
786 c_pfes->GetDofOffsets(), H.get());
787 pH.MakePtAP(dH, pP);
788 H.reset();
789 }
790 else
791 {
792 // TODO: add ones on the diagonal of zero rows
793 V->Finalize();
795 MFEM_ASSERT(c_pfes, "");
796 const int c_vsize = c_fes.GetVSize();
797 HYPRE_BigInt c_ldof_offset = c_pfes->GetMyDofOffset();
798 const HYPRE_BigInt *c_face_nbr_glob_ldof = c_pfes->GetFaceNbrGlobalDofMap();
799 int *J = V->GetJ();
800 for (int i = 0; i < V_J.Size(); i++)
801 {
802 V_J[i] = J[i] < c_vsize ?
803 J[i] + c_ldof_offset :
804 c_face_nbr_glob_ldof[J[i] - c_vsize];
805 }
806 // TODO - lpH directly in the pH format
807 HypreParMatrix *lpH;
808 {
809 HypreParMatrix pV(c_pfes->GetComm(), V->Height(),
810 pC->GetGlobalNumCols(), pC->GetGlobalNumRows(),
811 V->GetI(), V_J.GetData(), V->GetData(),
812 pC->ColPart(), pC->RowPart());
813 // The above constructor makes copies of all input arrays, so we can
814 // safely delete V_J and V:
815 V_J.DeleteAll();
816 delete V;
817 lpH = ParMult(pC.get(), &pV);
818 }
819 OperatorHandle pP(pH.Type()), plpH(pH.Type());
820 // TODO - construct P_pc directly in the pH format
821 pP.ConvertFrom(P_pc.get());
822 plpH.ConvertFrom(lpH);
823 MFEM_VERIFY(pH.Type() != Operator::PETSC_MATIS, "To be implemented");
824 pH.MakePtAP(plpH, pP);
825 delete lpH;
826 }
827#endif
828}
829
831{
832#ifndef MFEM_USE_MPI
833 if (!H) { ComputeH(); }
834#else
835 if (!H && !pH.Ptr()) { ComputeH(); }
836#endif
837}
838
839void Hybridization::MultAfInv(const Vector &b, const Vector &lambda, Vector &bf,
840 int mode) const
841{
842 // b1 = Rf^t b (assuming that Ref = 0)
843 Vector b1;
845 if (!R)
846 {
847 b1.SetDataAndSize(b.GetData(), b.Size());
848 }
849 else
850 {
851 b1.SetSize(fes.GetVSize());
852 R->MultTranspose(b, b1);
853 }
854
855 const int NE = fes.GetMesh()->GetNE();
856 Array<int> vdofs, i_dofs, b_dofs;
857 Vector el_vals, bf_i, i_vals, b_vals;
858 bf.SetSize(hat_offsets[NE]);
859 if (mode == 1)
860 {
861#ifdef MFEM_USE_MPI
862 ParFiniteElementSpace *c_pfes =
863 dynamic_cast<ParFiniteElementSpace*>(&c_fes);
864 if (!c_pfes)
865 {
866 Ct->Mult(lambda, bf);
867 }
868 else
869 {
870 Vector L(c_pfes->GetVSize());
871 (P_pc ? P_pc.get() : c_pfes->GetProlongationMatrix())->Mult(lambda, L);
872 pC ? pC->MultTranspose(L, bf) : Ct->Mult(L, bf);
873 }
874#else
875 Ct->Mult(lambda, bf);
876#endif
877 }
878 // Apply Af^{-1}
879 Array<bool> vdof_marker(b1.Size());
880 vdof_marker = false;
881 for (int i = 0; i < NE; i++)
882 {
883 fes.GetElementVDofs(i, vdofs);
884 b1.GetSubVector(vdofs, el_vals);
885 for (int j = 0; j < vdofs.Size(); j++)
886 {
887 int vdof = vdofs[j];
888 if (vdof < 0) { vdof = -1 - vdof; }
889 if (vdof_marker[vdof]) { el_vals(j) = 0.0; }
890 else { vdof_marker[vdof] = true; }
891 }
892 bf_i.MakeRef(bf, hat_offsets[i], vdofs.Size());
893 if (mode == 1)
894 {
895 el_vals -= bf_i;
896 }
897 GetIBDofs(i, i_dofs, b_dofs);
898 el_vals.GetSubVector(i_dofs, i_vals);
899 el_vals.GetSubVector(b_dofs, b_vals);
900
901 real_t *Af_data_ptr = const_cast<real_t*>(&Af_data[Af_offsets[i]]);
902 int *Af_ipiv_ptr = const_cast<int*>(&Af_ipiv[Af_f_offsets[i]]);
903 LUFactors LU_ii(Af_data_ptr, Af_ipiv_ptr);
904 real_t *U_ib = LU_ii.data + i_dofs.Size()*i_dofs.Size();
905 real_t *L_bi = U_ib + i_dofs.Size()*b_dofs.Size();
906 LUFactors LU_bb(L_bi + b_dofs.Size()*i_dofs.Size(),
907 LU_ii.ipiv + i_dofs.Size());
908 LU_ii.BlockForwSolve(i_dofs.Size(), b_dofs.Size(), 1, L_bi,
909 i_vals.GetData(), b_vals.GetData());
910 LU_bb.Solve(b_dofs.Size(), 1, b_vals.GetData());
911 bf_i = 0.0;
912 if (mode == 1)
913 {
914 LU_ii.BlockBackSolve(i_dofs.Size(), b_dofs.Size(), 1, U_ib,
915 b_vals.GetData(), i_vals.GetData());
916 bf_i.SetSubVector(i_dofs, i_vals);
917 }
918 bf_i.SetSubVector(b_dofs, b_vals);
919 }
920}
921
922void Hybridization::ReduceRHS(const Vector &b, Vector &b_r) const
923{
924 if (ext)
925 {
926 ext->ReduceRHS(b, b_r);
927 return;
928 }
929
930 // bf = Af^{-1} Rf^t b
931 Vector bf;
932 MultAfInv(b, b, bf, 0);
933
934 // b_r = Cf bf
935#ifdef MFEM_USE_MPI
936 ParFiniteElementSpace *c_pfes = dynamic_cast<ParFiniteElementSpace*>(&c_fes);
937 if (!c_pfes)
938 {
939 b_r.SetSize(Ct->Width());
940 Ct->MultTranspose(bf, b_r);
941 }
942 else
943 {
944 Vector bl(pC ? pC->Height() : Ct->Width());
945 if (pC)
946 {
947 pC->Mult(bf, bl);
948 }
949 else
950 {
951 Ct->MultTranspose(bf, bl);
952 }
953 b_r.SetSize(pH.Ptr()->Height());
954 (P_pc ? P_pc.get() : c_pfes->GetProlongationMatrix())->MultTranspose(bl, b_r);
955 }
956#else
957 b_r.SetSize(Ct->Width());
958 Ct->MultTranspose(bf, b_r);
959#endif
960}
961
963 Vector &sol) const
964{
965 if (ext)
966 {
967 ext->ComputeSolution(b, sol_r, sol);
968 return;
969 }
970
971 // bf = Af^{-1} ( Rf^t b - Cf^t sol_r )
972 Vector bf;
973 MultAfInv(b, sol_r, bf, 1);
974
975 // sol = Rf bf
976 GridFunction s;
978 if (!R)
979 {
980 MFEM_ASSERT(sol.Size() == fes.GetVSize(), "");
981 s.MakeRef(&fes, sol, 0);
982 }
983 else
984 {
985 s.SetSpace(&fes);
986 R->MultTranspose(sol, s);
987 }
988 const int NE = fes.GetMesh()->GetNE();
989 Array<int> vdofs;
990 for (int i = 0; i < NE; i++)
991 {
992 fes.GetElementVDofs(i, vdofs);
993 for (int j = hat_offsets[i]; j < hat_offsets[i+1]; j++)
994 {
995 if (hat_dofs_marker[j] == 1) { continue; } // skip essential b.c.
996 int vdof = vdofs[j-hat_offsets[i]];
997 if (vdof >= 0) { s(vdof) = bf(j); }
998 else { s(-1-vdof) = -bf(j); }
999 }
1000 }
1001 if (R)
1002 {
1003 R->Mult(s, sol); // assuming that Ref = 0
1004 }
1005}
1006
1008{
1009 H.reset();
1010#ifdef MFEM_USE_MPI
1011 pH.Clear();
1012#endif
1013 if (ext) { ext->Reset(); }
1014}
1015
1016}
T Max() const
Find the maximal element in the array, using the comparison operator < for class T.
Definition array.cpp:68
void Reserve(int capacity)
Ensures that the allocated size is at least the given size.
Definition array.hpp:165
void SetSize(int nsize)
Change the logical size of the array, keep existing entries.
Definition array.hpp:758
int Size() const
Return the logical size of the array.
Definition array.hpp:147
void MakeRef(T *data_, int size_, bool own_data=false)
Make this Array a reference to a pointer.
Definition array.hpp:943
void DeleteAll()
Delete the whole array.
Definition array.hpp:925
int Append(const T &el)
Append element 'el' to array, resize if necessary.
Definition array.hpp:830
T * GetData()
Returns the data.
Definition array.hpp:121
T & Last()
Return the last element in the array.
Definition array.hpp:863
Data type dense matrix using column-major storage.
Definition densemat.hpp:24
void Threshold(real_t eps)
Replace small entries, abs(a_ij) <= eps, with zero.
real_t * Data() const
Returns the matrix data array.
Definition densemat.hpp:114
void SetSize(int s)
Change the size of the DenseMatrix to s x s.
Definition densemat.hpp:108
void AdjustDofDirection(Array< int > &dofs)
real_t MaxMaxNorm() const
Compute the norm ||A|| = max_{ij} |A_{ij}|.
Definition densemat.cpp:875
Rank 3 tensor (array of matrices)
int SizeK() const
A specialized ElementTransformation class representing a face and its two neighboring elements.
Definition eltrans.hpp:750
real_t * data
Definition densemat.hpp:637
void SubDofOrder(Geometry::Type Geom, int SDim, int Info, Array< int > &dofs) const
Get the local dofs for a given sub-manifold.
Definition fe_coll.cpp:512
Class FiniteElementSpace - responsible for providing FEM view of the mesh, mainly managing the set of...
Definition fespace.hpp:244
virtual const SparseMatrix * GetRestrictionMatrix() const
The returned SparseMatrix is owned by the FiniteElementSpace.
Definition fespace.hpp:750
static void AdjustVDofs(Array< int > &vdofs)
Remove the orientation information encoded into an array of dofs Some basis function types have a rel...
Definition fespace.cpp:310
int GetNBE() const
Returns number of boundary elements in the mesh.
Definition fespace.hpp:900
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:332
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:3835
int GetNE() const
Returns number of elements in the mesh.
Definition fespace.hpp:891
int GetConformingVSize() const
Definition fespace.hpp:857
void GetFaceVDofs(int i, Array< int > &vdofs) const
Returns the indices of the degrees of freedom for the specified face, including the DOFs for the edge...
Definition fespace.cpp:361
const FiniteElement * GetFaceElement(int i) const
Returns pointer to the FiniteElement in the FiniteElementCollection associated with i'th face in the ...
Definition fespace.cpp:3914
const SparseMatrix * GetConformingProlongation() const
Definition fespace.cpp:1456
const FiniteElementCollection * FEColl() const
Definition fespace.hpp:878
Mesh * GetMesh() const
Returns the mesh.
Definition fespace.hpp:679
int GetVSize() const
Return the number of vector dofs, i.e. GetNDofs() x GetVDim().
Definition fespace.hpp:848
int GetVDim() const
Returns the vector dimension of the finite element space.
Definition fespace.hpp:841
DofTransformation * GetBdrElementVDofs(int i, Array< int > &vdofs) const
Returns indices of degrees of freedom for i'th boundary element. The returned indices are offsets int...
Definition fespace.cpp:348
Abstract class for all finite elements.
Definition fe_base.hpp:244
Class for grid function - Vector with associated FE space.
Definition gridfunc.hpp:31
virtual void MakeRef(FiniteElementSpace *f, real_t *v)
Make the GridFunction reference external data on a new FiniteElementSpace.
Definition gridfunc.cpp:233
virtual void SetSpace(FiniteElementSpace *f)
Associate a new FiniteElementSpace with the GridFunction.
Definition gridfunc.cpp:225
void Reset()
Destroy the current hybridization matrix while preserving the computed constraint matrix and the set ...
Array< int > hat_offsets
void AssembleElementMatrices(const class DenseTensor &el_mats)
Assemble all of the element matrices given in the form of a DenseTensor.
~Hybridization()
Destructor.
void Init(const Array< int > &ess_tdof_list)
Prepare the Hybridization object for assembly.
std::unique_ptr< HypreParMatrix > pC
void EnableDeviceExecution()
Turns on device execution.
FiniteElementSpace & c_fes
std::vector< BilinearFormIntegrator * > boundary_constraint_integs
The constraint boundary face integrators.
void AssembleBdrMatrix(int bdr_el, const DenseMatrix &A)
Assemble the boundary element matrix A into the hybridized system matrix.
friend class HybridizationExtension
bool extern_bdr_constr_integs
Indicates if the boundary_constraint_integs integrators are owned externally.
std::unique_ptr< SparseMatrix > Ct
The constraint matrix.
void AssembleMatrix(int el, const DenseMatrix &A)
Assemble the element matrix A into the hybridized system matrix.
void MultAfInv(const Vector &b, const Vector &lambda, Vector &bf, int mode) const
std::unique_ptr< HypreParMatrix > P_pc
std::unique_ptr< SparseMatrix > H
The Schur complement system for the Lagrange multiplier.
void GetIBDofs(int el, Array< int > &i_dofs, Array< int > &b_dofs) const
Returns the local indices of the i-dofs and b-dofs of element el.
void ComputeH()
Construct the Schur complement system.
std::unique_ptr< class HybridizationExtension > ext
Extension for device execution.
Array< int > hat_dofs_marker
void ComputeSolution(const Vector &b, const Vector &sol_r, Vector &sol) const
Reconstruct the solution of the original system sol from solution of the hybridized system sol_r and ...
Array< int > Af_f_offsets
FiniteElementSpace & fes
The finite element space.
Array< int > Af_offsets
void Finalize()
Finalize the construction of the hybridized matrix.
Hybridization(FiniteElementSpace *fespace, FiniteElementSpace *c_fespace)
Constructor.
std::vector< Array< int > * > boundary_constraint_integs_marker
Boundary markers for constraint face integrators.
void GetBDofs(int el, int &num_idofs, Array< int > &b_dofs) const
Returns global indices of the b-dofs of element el.
void ConstructC()
Construct the constraint matrix.
Array< real_t > Af_data
std::unique_ptr< BilinearFormIntegrator > c_bfi
The constraint integrator.
void ReduceRHS(const Vector &b, Vector &b_r) const
Perform the reduction of the given right-hand side b to a right-hand side vector b_r for the hybridiz...
Wrapper for hypre's ParCSR matrix class.
Definition hypre.hpp:408
void BooleanMult(int alpha, const int *x, int beta, int *y)
The "Boolean" analog of y = alpha * A * x + beta * y, where elements in the sparsity pattern of the m...
Definition hypre.hpp:787
HypreParMatrix * Transpose() const
Returns the transpose of *this.
Definition hypre.cpp:1730
bool Factor(int m, real_t TOL=0.0) override
Compute the LU factorization of the current matrix.
void BlockFactor(int m, int n, real_t *A12, real_t *A21, real_t *A22) const
void BlockForwSolve(int m, int n, int r, const real_t *L21, real_t *B1, real_t *B2) const
void Solve(int m, int n, real_t *X) const override
void BlockBackSolve(int m, int n, int r, const real_t *U12, const real_t *X2, real_t *Y1) const
Mesh data type.
Definition mesh.hpp:64
Array< int > bdr_attributes
A list of all unique boundary attributes used by the Mesh.
Definition mesh.hpp:290
int GetNumFaces() const
Return the number of faces (3D), edges (2D) or vertices (1D).
Definition mesh.cpp:6531
bool Nonconforming() const
Return a bool indicating whether this mesh is nonconforming.
Definition mesh.hpp:2367
int GetBdrAttribute(int i) const
Return the attribute of boundary element i.
Definition mesh.hpp:1395
int GetBdrElementFaceIndex(int be_idx) const
Return the local face (codimension-1) index for the given boundary element index.
Definition mesh.hpp:1588
int GetNE() const
Returns number of elements.
Definition mesh.hpp:1282
int Dimension() const
Dimension of the reference space used within the elements.
Definition mesh.hpp:1216
FaceElementTransformations * GetBdrFaceTransformations(int BdrElemNo)
Builds the transformation defining the given boundary face.
Definition mesh.cpp:1123
void GetBdrElementAdjacentElement(int bdr_el, int &el, int &info) const
For the given boundary element, bdr_el, return its adjacent element and its info, i....
Definition mesh.cpp:7584
FaceElementTransformations * GetInteriorFaceTransformations(int FaceNo)
See GetFaceElementTransformations().
Definition mesh.cpp:1103
Geometry::Type GetElementBaseGeometry(int i) const
Definition mesh.hpp:1455
Pointer to an Operator of a specified type.
Definition handle.hpp:34
void ConvertFrom(OperatorHandle &A)
Convert the given OperatorHandle A to the currently set type id.
Definition handle.cpp:203
void SetType(Operator::Type tid)
Invoke Clear() and set a new type id.
Definition handle.hpp:132
void MakePtAP(OperatorHandle &A, OperatorHandle &P)
Reset the OperatorHandle to hold the product P^t A P.
Definition handle.cpp:124
void MakeSquareBlockDiag(MPI_Comm comm, HYPRE_BigInt glob_size, HYPRE_BigInt *row_starts, SparseMatrix *diag)
Reset the OperatorHandle to hold a parallel square block-diagonal matrix using the currently set type...
Definition handle.cpp:61
Operator * Ptr() const
Access the underlying Operator pointer.
Definition handle.hpp:87
void Clear()
Clear the OperatorHandle, deleting the held Operator (if owned), while leaving the type id unchanged.
Definition handle.hpp:124
Operator::Type Type() const
Get the currently set operator type id.
Definition handle.hpp:99
int Height() const
Get the height (size of output) of the Operator. Synonym with NumRows().
Definition operator.hpp:66
int Width() const
Get the width (size of input) of the Operator. Synonym with NumCols().
Definition operator.hpp:72
@ PETSC_MATIS
ID for class PetscParMatrix, MATIS format.
Definition operator.hpp:289
@ Hypre_ParCSR
ID for class HypreParMatrix.
Definition operator.hpp:287
Abstract parallel finite element space.
Definition pfespace.hpp:29
MPI_Comm GetComm() const
Definition pfespace.hpp:334
HYPRE_BigInt GlobalVSize() const
Definition pfespace.hpp:344
HYPRE_BigInt GetMyDofOffset() const
HYPRE_BigInt * GetDofOffsets() const
Definition pfespace.hpp:342
void GetFaceNbrFaceVDofs(int i, Array< int > &vdofs) const
const Operator * GetProlongationMatrix() const override
HypreParMatrix * Dof_TrueDof_Matrix() const
The true dof-to-dof interpolation matrix.
Definition pfespace.hpp:388
const HYPRE_BigInt * GetFaceNbrGlobalDofMap()
Definition pfespace.hpp:481
ParMesh * GetParMesh() const
Definition pfespace.hpp:338
HypreParMatrix * GetPartialConformingInterpolation()
For a non-conforming mesh, construct and return the interpolation matrix from the partially conformin...
int TrueVSize() const
Obsolete, kept for backward compatibility.
Definition pfespace.hpp:524
const FiniteElement * GetFaceNbrFaceFE(int i) const
Class for parallel meshes.
Definition pmesh.hpp:34
MPI_Comm GetComm() const
Definition pmesh.hpp:402
int GetNSharedFaces() const
Return the number of shared faces (3D), edges (2D), vertices (1D)
Definition pmesh.cpp:3152
FaceElementTransformations * GetFaceElementTransformations(int FaceNo, int mask=31) override
Definition pmesh.cpp:2896
int GetSharedFace(int sface) const
Return the local face index for the given shared face.
Definition pmesh.cpp:3171
void GenerateOffsets(int N, HYPRE_BigInt loc_sizes[], Array< HYPRE_BigInt > *offsets[]) const
Definition pmesh.cpp:1942
ParNCMesh * pncmesh
Definition pmesh.hpp:469
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:2922
const NCList & GetSharedList(int entity)
Helper to get shared vertices/edges/faces ('entity' == 0/1/2 resp.).
Definition pncmesh.hpp:132
Data type sparse matrix.
Definition sparsemat.hpp:51
void MultTranspose(const Vector &x, Vector &y) const override
Multiply a vector with the transposed matrix. y = At * x.
int NumNonZeroElems() const override
Returns the number of the nonzero elements in the matrix.
void PrintMatlab(std::ostream &out=mfem::out) const override
Prints matrix in matlab format.
void AddSubMatrix(const Array< int > &rows, const Array< int > &cols, const DenseMatrix &subm, int skip_zeros=1)
void BooleanMult(const Array< int > &x, Array< int > &y) const
y = A * x, treating all entries as booleans (zero=false, nonzero=true).
int * GetRowColumns(const int row)
Return a pointer to the column indices in a row.
int RowSize(const int i) const
Returns the number of elements in row i.
void Mult(const Vector &x, Vector &y) const override
Matrix vector multiplication.
real_t * GetRowEntries(const int row)
Return a pointer to the entries in a row.
real_t * GetData()
Return the element data, i.e. the array A.
void Finalize(int skip_zeros=1) override
Finalize the matrix initialization, switching the storage format from LIL to CSR.
int * GetJ()
Return the array J.
int * GetI()
Return the array I.
Vector data type.
Definition vector.hpp:82
void SetDataAndSize(real_t *d, int s)
Set the Vector data and size.
Definition vector.hpp:183
void SetSubVector(const Array< int > &dofs, const real_t value)
Set the entries listed in dofs to the given value.
Definition vector.cpp:679
int Size() const
Returns the size of the vector.
Definition vector.hpp:226
void SetSize(int s)
Resize the vector to size s.
Definition vector.hpp:558
real_t * GetData() const
Return a pointer to the beginning of the Vector data.
Definition vector.hpp:235
void GetSubVector(const Array< int > &dofs, Vector &elemvect) const
Extract entries listed in dofs to the output Vector elemvect.
Definition vector.cpp:653
void MakeRef(Vector &base, int offset, int size)
Reset the Vector to be a reference to a sub-vector of base.
Definition vector.hpp:622
int dim
Definition ex24.cpp:53
HYPRE_Int HYPRE_BigInt
real_t b
Definition lissajous.cpp:42
void Mult(const Table &A, const Table &B, Table &C)
C = A * B (as boolean matrices)
Definition table.cpp:548
OutStream out(std::cout)
Global stream used by the library for standard output. Initially it uses the same std::streambuf as s...
Definition globals.hpp:66
void Transpose(const Table &A, Table &At, int ncols_A_)
Transpose a Table.
Definition table.cpp:486
HypreParMatrix * ParMult(const HypreParMatrix *A, const HypreParMatrix *B, bool own_matrix)
Definition hypre.cpp:3007
ComplexDenseMatrix * MultAtB(const ComplexDenseMatrix &A, const ComplexDenseMatrix &B)
Multiply the complex conjugate transpose of a matrix A with a matrix B. A^H*B.
float real_t
Definition config.hpp:43
Lists all edges/faces in the nonconforming mesh.
Definition ncmesh.hpp:251
Array< Slave > slaves
All MeshIds corresponding to slave faces.
Definition ncmesh.hpp:254