MFEM v4.9.0
Finite element discretization library
Loading...
Searching...
No Matches
complexstaticcond.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 "complexstaticcond.hpp"
13
14namespace mfem
15{
16
19 fes_)
20{
21 SetSpaces(fes_);
22
23 Array<int> rvdofs;
24 Array<int> vdofs;
25 Array<int> rdof_edof0;
26 for (int k = 0; k<nblocks; k++)
27 {
28 if (!tr_fes[k]) { continue; }
29 rdof_edof0.SetSize(tr_fes[k]->GetVSize());
30 for (int i = 0; i < mesh->GetNE(); i++)
31 {
32 fes[k]->GetElementVDofs(i, vdofs);
33 tr_fes[k]->GetElementVDofs(i, rvdofs);
34 const int vdim = fes[k]->GetVDim();
35 const int nsd = vdofs.Size()/vdim;
36 const int nsrd = rvdofs.Size()/vdim;
37 for (int vd = 0; vd < vdim; vd++)
38 {
39 for (int j = 0; j < nsrd; j++)
40 {
41 int rvdof = rvdofs[j+nsrd*vd];
42 int vdof = vdofs[j+nsd*vd];
43 if (rvdof < 0)
44 {
45 rvdof = -1-rvdof;
46 vdof = -1-vdof;
47 }
48 MFEM_ASSERT(vdof >= 0, "incompatible volume and trace FE spaces");
49 rdof_edof0[rvdof] = vdof + dof_offsets[k];
50 }
51 }
52 }
53 rdof_edof.Append(rdof_edof0);
54 }
55}
56
57void ComplexBlockStaticCondensation::SetSpaces(Array<FiniteElementSpace*> &
58 fes_)
59{
60#ifdef MFEM_USE_MPI
61 ParMesh *pmesh = nullptr;
62 parallel = false;
63 if (dynamic_cast<ParFiniteElementSpace *>(fes_[0]))
64 {
65 parallel = true;
66 }
67#else
68 parallel = false;
69#endif
70 fes=fes_;
71 nblocks = fes.Size();
72 rblocks = 0;
73 tr_fes.SetSize(nblocks);
74 mesh = fes[0]->GetMesh();
75
76 IsTraceSpace.SetSize(nblocks);
77 const FiniteElementCollection * fec;
78 for (int i = 0; i < nblocks; i++)
79 {
80 fec = fes[i]->FEColl();
81 IsTraceSpace[i] =
82 (dynamic_cast<const H1_Trace_FECollection*>(fec) ||
83 dynamic_cast<const ND_Trace_FECollection*>(fec) ||
84 dynamic_cast<const RT_Trace_FECollection*>(fec));
85#ifdef MFEM_USE_MPI
86 if (parallel)
87 {
88 pmesh = dynamic_cast<ParMesh *>(mesh);
89 tr_fes[i] = (fec->GetContType() == FiniteElementCollection::DISCONTINUOUS) ?
90 nullptr : (IsTraceSpace[i]) ? fes[i] :
91 new ParFiniteElementSpace(pmesh, fec->GetTraceCollection(), fes[i]->GetVDim(),
92 fes[i]->GetOrdering());
93 }
94 else
95 {
96 tr_fes[i] = (fec->GetContType() == FiniteElementCollection::DISCONTINUOUS) ?
97 nullptr : (IsTraceSpace[i]) ? fes[i] :
98 new FiniteElementSpace(mesh, fec->GetTraceCollection(), fes[i]->GetVDim(),
99 fes[i]->GetOrdering());
100 }
101#else
102 // skip if it's an L2 space (no trace space to construct)
103 tr_fes[i] = (fec->GetContType() == FiniteElementCollection::DISCONTINUOUS) ?
104 nullptr : (IsTraceSpace[i]) ? fes[i] :
105 new FiniteElementSpace(mesh, fec->GetTraceCollection(), fes[i]->GetVDim(),
106 fes[i]->GetOrdering());
107#endif
108 if (tr_fes[i]) { rblocks++; }
109 }
110 if (parallel)
111 {
112 ess_tdofs.SetSize(rblocks);
113 for (int i = 0; i<rblocks; i++)
114 {
115 ess_tdofs[i] = new Array<int>();
116 }
117 }
118 Init();
119}
120
121void ComplexBlockStaticCondensation::ComputeOffsets()
122{
123 dof_offsets.SetSize(nblocks+1);
124 tdof_offsets.SetSize(nblocks+1);
125 dof_offsets[0] = 0;
126 tdof_offsets[0] = 0;
127
128 rdof_offsets.SetSize(rblocks+1);
129 rtdof_offsets.SetSize(rblocks+1);
130 rdof_offsets[0] = 0;
131 rtdof_offsets[0] = 0;
132
133 int j=0;
134 for (int i =0; i<nblocks; i++)
135 {
136 dof_offsets[i+1] = fes[i]->GetVSize();
137 tdof_offsets[i+1] = fes[i]->GetTrueVSize();
138 if (tr_fes[i])
139 {
140 rdof_offsets[j+1] = tr_fes[i]->GetVSize();
141 rtdof_offsets[j+1] = tr_fes[i]->GetTrueVSize();
142 j++;
143 }
144 }
145 rdof_offsets.PartialSum();
146 rtdof_offsets.PartialSum();
147 dof_offsets.PartialSum();
148 tdof_offsets.PartialSum();
149}
150
151void ComplexBlockStaticCondensation::Init()
152{
153 lmat.SetSize(mesh->GetNE());
154 lvec.SetSize(mesh->GetNE());
155 for (int i = 0; i < mesh->GetNE(); i++)
156 {
157 lmat[i] = nullptr;
158 lvec[i] = nullptr;
159 }
160
161 ComputeOffsets();
162
163 S_r = new BlockMatrix(rdof_offsets);
164 S_r->owns_blocks = 1;
165 S_i = new BlockMatrix(rdof_offsets);
166 S_i->owns_blocks = 1;
167
168 for (int i = 0; i<S_r->NumRowBlocks(); i++)
169 {
170 int h = rdof_offsets[i+1] - rdof_offsets[i];
171 for (int j = 0; j<S_r->NumColBlocks(); j++)
172 {
173 int w = rdof_offsets[j+1] - rdof_offsets[j];
174 S_r->SetBlock(i,j,new SparseMatrix(h, w));
175 S_i->SetBlock(i,j,new SparseMatrix(h, w));
176 }
177 }
178
179 y = new Vector(2*rdof_offsets.Last());
180 *y=0.;
181 y_r = new BlockVector(*y, rdof_offsets);
182 y_i = new BlockVector(*y, rdof_offsets.Last(), rdof_offsets);
183}
184
185void ComplexBlockStaticCondensation::GetReduceElementIndicesAndOffsets(int el,
186 Array<int> & trace_ldofs,
187 Array<int> & interior_ldofs,
188 Array<int> & offsets) const
189{
190 int dim = mesh->Dimension();
191 offsets.SetSize(tr_fes.Size()+1); offsets = 0;
192 Array<int> dofs;
193 Array<int> faces, ori;
194 if (dim == 1)
195 {
196 mesh->GetElementVertices(el, faces);
197 }
198 else if (dim == 2)
199 {
200 mesh->GetElementEdges(el, faces, ori);
201 }
202 else if (dim == 3)
203 {
204 mesh->GetElementFaces(el,faces,ori);
205 }
206 else
207 {
208 MFEM_ABORT("ComplexBlockStaticCondensation::GetReduceElementIndicesAndOffsets: "
209 "dim > 3 not supported");
210 }
211 int numfaces = faces.Size();
212
213 trace_ldofs.SetSize(0);
214 interior_ldofs.SetSize(0);
215 // construct Array of bubble dofs to be extracted
216 int skip=0;
217 Array<int> tr_dofs;
218 Array<int> int_dofs;
219 for (int i = 0; i<tr_fes.Size(); i++)
220 {
221 int td = 0;
222 int ndof;
223 // if it's an L2 space (bubbles)
224 if (!tr_fes[i])
225 {
226 ndof = fes[i]->GetVDim()*fes[i]->GetFE(el)->GetDof();
227 td = 0;
228 }
229 else if (IsTraceSpace[i])
230 {
231 for (int iface = 0; iface < numfaces; iface++)
232 {
233 td += fes[i]->GetVDim()*fes[i]->GetFaceElement(faces[iface])->GetDof();
234 }
235 ndof = td;
236 }
237 else
238 {
239 Array<int> trace_dofs;
240 ndof = fes[i]->GetVDim()*fes[i]->GetFE(el)->GetDof();
241 tr_fes[i]->GetElementVDofs(el, trace_dofs);
242 td = trace_dofs.Size(); // number of trace dofs
243 }
244 offsets[i+1] = td;
245 tr_dofs.SetSize(td);
246 int_dofs.SetSize(ndof - td);
247 for (int j = 0; j<td; j++)
248 {
249 tr_dofs[j] = skip + j;
250 }
251 for (int j = 0; j<ndof-td; j++)
252 {
253 int_dofs[j] = skip + td + j;
254 }
255 skip+=ndof;
256
257 trace_ldofs.Append(tr_dofs);
258 interior_ldofs.Append(int_dofs);
259 }
260 offsets.PartialSum();
261}
262
263
264void ComplexBlockStaticCondensation::GetReduceElementVDofs(int el,
265 Array<int> & rdofs) const
266{
267 Array<int> faces, ori;
268 int dim = mesh->Dimension();
269 if (dim == 1)
270 {
271 mesh->GetElementVertices(el, faces);
272 }
273 else if (dim == 2)
274 {
275 mesh->GetElementEdges(el, faces, ori);
276 }
277 else if (dim == 3)
278 {
279 mesh->GetElementFaces(el,faces,ori);
280 }
281 else
282 {
283 MFEM_ABORT("ComplexBlockStaticCondensation::GetReduceElementVDofs: "
284 "dim > 3 not supported");
285 }
286 int numfaces = faces.Size();
287 rdofs.SetSize(0);
288 int skip = 0;
289 for (int i = 0; i<tr_fes.Size(); i++)
290 {
291 if (!tr_fes[i]) { continue; }
292 Array<int> vdofs;
293 if (IsTraceSpace[i])
294 {
295 Array<int> face_vdofs;
296 for (int k = 0; k < numfaces; k++)
297 {
298 int iface = faces[k];
299 tr_fes[i]->GetFaceVDofs(iface, face_vdofs);
300 vdofs.Append(face_vdofs);
301 }
302 }
303 else
304 {
305 tr_fes[i]->GetElementVDofs(el, vdofs);
306 }
307 for (int j=0; j<vdofs.Size(); j++)
308 {
309 vdofs[j] = (vdofs[j]>=0) ? vdofs[j]+rdof_offsets[skip] :
310 vdofs[j]-rdof_offsets[skip];
311 }
312 skip++;
313 rdofs.Append(vdofs);
314 }
315}
316void ComplexBlockStaticCondensation::GetElementVDofs(int el,
317 Array<int> & vdofs) const
318{
319 Array<int> faces, ori;
320 int dim = mesh->Dimension();
321 if (dim == 1)
322 {
323 mesh->GetElementVertices(el, faces);
324 }
325 else if (dim == 2)
326 {
327 mesh->GetElementEdges(el, faces, ori);
328 }
329 else if (dim == 3)
330 {
331 mesh->GetElementFaces(el,faces,ori);
332 }
333 else
334 {
335 MFEM_ABORT("ComplexBlockStaticCondensation::GetElementVDofs: "
336 "dim > 3 not supported");
337 }
338 int numfaces = faces.Size();
339 vdofs.SetSize(0);
340 for (int i = 0; i<tr_fes.Size(); i++)
341 {
342 Array<int> dofs;
343 if (IsTraceSpace[i])
344 {
345 Array<int> face_vdofs;
346 for (int k = 0; k < numfaces; k++)
347 {
348 int iface = faces[k];
349 fes[i]->GetFaceVDofs(iface, face_vdofs);
350 dofs.Append(face_vdofs);
351 }
352 }
353 else
354 {
355 fes[i]->GetElementVDofs(el, dofs);
356 }
357 for (int j=0; j<dofs.Size(); j++)
358 {
359 dofs[j] = (dofs[j]>=0) ? dofs[j]+dof_offsets[i] :
360 dofs[j]-dof_offsets[i];
361 }
362 vdofs.Append(dofs);
363 }
364}
365
366
367ComplexDenseMatrix * ComplexBlockStaticCondensation::GetLocalShurComplement(
368 int el,
369 const Array<int> & tr_idx, const Array<int> & int_idx,
370 const ComplexDenseMatrix & elmat,
371 const Vector & elvect_real, const Vector & elvect_imag,
372 Vector & rvect_real, Vector & rvect_imag)
373{
374 int rdofs = tr_idx.Size();
375 int idofs = int_idx.Size();
376 MFEM_VERIFY(idofs != 0, "Number of interior dofs is zero");
377 MFEM_VERIFY(rdofs != 0, "Number of interface dofs is zero");
378
379 DenseMatrix A_tt_real, A_ti_real, A_it_real, A_ii_real;
380 DenseMatrix A_tt_imag, A_ti_imag, A_it_imag, A_ii_imag;
381
382
383 Vector yt(2*rdofs);
384 Vector yi(2*idofs);
385
386 Vector yt_real(yt, 0,rdofs);
387 Vector yt_imag(yt, rdofs, rdofs);
388
389 Vector yi_real(yi, 0, idofs);
390 Vector yi_imag(yi,idofs, idofs);
391
392 // real part of Matrix and vectors
393 elmat.real().GetSubMatrix(tr_idx,A_tt_real);
394 elmat.real().GetSubMatrix(tr_idx,int_idx, A_ti_real);
395 elmat.real().GetSubMatrix(int_idx, tr_idx, A_it_real);
396 elmat.real().GetSubMatrix(int_idx, A_ii_real);
397
398 elvect_real.GetSubVector(tr_idx, yt_real);
399 elvect_real.GetSubVector(int_idx, yi_real);
400
401 // imag part of Matrix and vectors
402 elmat.imag().GetSubMatrix(tr_idx,A_tt_imag);
403 elmat.imag().GetSubMatrix(tr_idx,int_idx, A_ti_imag);
404 elmat.imag().GetSubMatrix(int_idx, tr_idx, A_it_imag);
405 elmat.imag().GetSubMatrix(int_idx, A_ii_imag);
406
407 elvect_imag.GetSubVector(tr_idx, yt_imag);
408 elvect_imag.GetSubVector(int_idx, yi_imag);
409
410 // construct complex
411 ComplexDenseMatrix A_tt(&A_tt_real,&A_tt_imag,false,false);
412 ComplexDenseMatrix A_ti(&A_ti_real,&A_ti_imag,false,false);
413 ComplexDenseMatrix A_it(&A_it_real,&A_it_imag,false,false);
414 ComplexDenseMatrix A_ii(&A_ii_real,&A_ii_imag,false,false);
415
416 ComplexDenseMatrix * invA_ii = A_ii.ComputeInverse();
417
418 // LHS
419 lmat[el] = mfem::Mult(*invA_ii,A_it);
420 ComplexDenseMatrix * rmat = mfem::Mult(A_ti,*lmat[el]);
421 rmat->real().Neg();
422 rmat->imag().Neg();
423 rmat->real().Add(1., A_tt.real());
424 rmat->imag().Add(1., A_tt.imag());
425
426 // RHS
427 lvec[el] = new Vector(2*idofs);
428 invA_ii->Mult(yi,*lvec[el]);
429 delete invA_ii;
430
431 Vector rvect(2*rdofs);
432 A_ti.Mult(*lvec[el], rvect);
433 rvect_real.SetSize(rdofs);
434 rvect_imag.SetSize(rdofs);
435 for (int i = 0; i<rdofs; i++)
436 {
437 rvect_real(i) = yt_real(i) - rvect(i);
438 rvect_imag(i) = yt_imag(i) - rvect(i+rdofs);
439 }
440 return rmat;
441}
442
443
445 ComplexDenseMatrix &elmat,
446 Vector & elvect_r, Vector & elvect_i)
447{
448 // Get Shur Complement
449 Array<int> tr_idx, int_idx;
450 Array<int> offsets;
451 // Get local element idx and offsets for global assembly
452 GetReduceElementIndicesAndOffsets(el, tr_idx,int_idx, offsets);
453
454 ComplexDenseMatrix *rmat = nullptr;
455 Vector rvec_real, *rvecptr_real;
456 Vector rvec_imag, *rvecptr_imag;
457 // Extract the reduced matrices based on tr_idx and int_idx
458 if (int_idx.Size()!=0)
459 {
460 rmat = GetLocalShurComplement(el,tr_idx,int_idx, elmat, elvect_r, elvect_i,
461 rvec_real,rvec_imag);
462 rvecptr_real = &rvec_real;
463 rvecptr_imag = &rvec_imag;
464 }
465 else
466 {
467 rmat = &elmat;
468 rvecptr_real = &elvect_r;
469 rvecptr_imag = &elvect_i;
470 }
471
472 // Assemble global mat and rhs
473 DofTransformation doftrans_i, doftrans_j;
474
475 Array<int> faces, ori;
476 int dim = mesh->Dimension();
477 if (dim == 1)
478 {
479 mesh->GetElementVertices(el, faces);
480 }
481 else if (dim == 2)
482 {
483 mesh->GetElementEdges(el, faces, ori);
484 }
485 else if (dim == 3)
486 {
487 mesh->GetElementFaces(el,faces,ori);
488 }
489 else
490 {
491 MFEM_ABORT("ComplexBlockStaticCondensation::AssembleReducedSystem: "
492 "dim > 3 not supported");
493 }
494 int numfaces = faces.Size();
495
496 int skip_i=0;
497 for (int i = 0; i<tr_fes.Size(); i++)
498 {
499 if (!tr_fes[i]) { continue; }
500 Array<int> vdofs_i;
501 doftrans_i.SetDofTransformation(nullptr);
502 if (IsTraceSpace[i])
503 {
504 Array<int> face_vdofs;
505 for (int k = 0; k < numfaces; k++)
506 {
507 int iface = faces[k];
508 tr_fes[i]->GetFaceVDofs(iface, face_vdofs);
509 vdofs_i.Append(face_vdofs);
510 }
511 }
512 else
513 {
514 tr_fes[i]->GetElementVDofs(el, vdofs_i, doftrans_i);
515 }
516 int skip_j=0;
517 for (int j = 0; j<tr_fes.Size(); j++)
518 {
519 if (!tr_fes[j]) { continue; }
520 Array<int> vdofs_j;
521 doftrans_j.SetDofTransformation(nullptr);
522
523 if (IsTraceSpace[j])
524 {
525 Array<int> face_vdofs;
526 for (int k = 0; k < numfaces; k++)
527 {
528 int iface = faces[k];
529 tr_fes[j]->GetFaceVDofs(iface, face_vdofs);
530 vdofs_j.Append(face_vdofs);
531 }
532 }
533 else
534 {
535 tr_fes[j]->GetElementVDofs(el, vdofs_j, doftrans_j);
536 }
537
538 DenseMatrix Ae_r, Ae_i;
539 rmat->real().GetSubMatrix(offsets[i],offsets[i+1],
540 offsets[j],offsets[j+1], Ae_r);
541 rmat->imag().GetSubMatrix(offsets[i],offsets[i+1],
542 offsets[j],offsets[j+1], Ae_i);
543 TransformDual(doftrans_i, doftrans_j, Ae_r);
544 TransformDual(doftrans_i, doftrans_j, Ae_i);
545 S_r->GetBlock(skip_i,skip_j).AddSubMatrix(vdofs_i,vdofs_j, Ae_r);
546 S_i->GetBlock(skip_i,skip_j).AddSubMatrix(vdofs_i,vdofs_j, Ae_i);
547 skip_j++;
548 }
549
550 // assemble rhs
551 Vector vec1_r(*rvecptr_real, offsets[i], offsets[i+1]-offsets[i]);
552 Vector vec1_i(*rvecptr_imag, offsets[i], offsets[i+1]-offsets[i]);
553 // ref subvector
554 doftrans_i.TransformDual(vec1_r);
555 doftrans_i.TransformDual(vec1_i);
556 y_r->GetBlock(skip_i).AddElementVector(vdofs_i,vec1_r);
557 y_i->GetBlock(skip_i).AddElementVector(vdofs_i,vec1_i);
558 skip_i++;
559 }
560 if (int_idx.Size()!=0) { delete rmat; }
561}
562
563void ComplexBlockStaticCondensation::BuildProlongation()
564{
565 P = new BlockMatrix(rdof_offsets, rtdof_offsets);
566 R = new BlockMatrix(rtdof_offsets, rdof_offsets);
567 P->owns_blocks = 0;
568 R->owns_blocks = 0;
569 int skip = 0;
570 for (int i = 0; i<nblocks; i++)
571 {
572 if (!tr_fes[i]) { continue; }
573 const SparseMatrix *P_ = tr_fes[i]->GetConformingProlongation();
574 if (P_)
575 {
576 const SparseMatrix *R_ = tr_fes[i]->GetRestrictionMatrix();
577 P->SetBlock(skip,skip,const_cast<SparseMatrix*>(P_));
578 R->SetBlock(skip,skip,const_cast<SparseMatrix*>(R_));
579 }
580 skip++;
581 }
582}
583
584#ifdef MFEM_USE_MPI
585void ComplexBlockStaticCondensation::BuildParallelProlongation()
586{
587 MFEM_VERIFY(parallel, "BuildParallelProlongation: wrong code path");
588 pP = new BlockOperator(rdof_offsets, rtdof_offsets);
589 R = new BlockMatrix(rtdof_offsets, rdof_offsets);
590 pP->owns_blocks = 0;
591 R->owns_blocks = 0;
592 int skip = 0;
593 for (int i = 0; i<nblocks; i++)
594 {
595 if (!tr_fes[i]) { continue; }
596 const HypreParMatrix *P_ =
597 dynamic_cast<ParFiniteElementSpace *>(tr_fes[i])->Dof_TrueDof_Matrix();
598 if (P_)
599 {
600 const SparseMatrix *R_ = tr_fes[i]->GetRestrictionMatrix();
601 pP->SetBlock(skip,skip,const_cast<HypreParMatrix*>(P_));
602 R->SetBlock(skip,skip,const_cast<SparseMatrix*>(R_));
603 }
604 skip++;
605 }
606}
607
609 BlockMatrix *m_i)
610{
611
612 if (!pP) { BuildParallelProlongation(); }
613
614 pS_r = new BlockOperator(rtdof_offsets);
615 pS_e_r = new BlockOperator(rtdof_offsets);
616 pS_i = new BlockOperator(rtdof_offsets);
617 pS_e_i = new BlockOperator(rtdof_offsets);
618 pS_r->owns_blocks = 1;
619 pS_i->owns_blocks = 1;
620 pS_e_r->owns_blocks = 1;
621 pS_e_i->owns_blocks = 1;
622 HypreParMatrix * A_r = nullptr;
623 HypreParMatrix * A_i = nullptr;
624 HypreParMatrix * PtAP_r = nullptr;
625 HypreParMatrix * PtAP_i = nullptr;
626 int skip_i=0;
627 ParFiniteElementSpace * pfes_i = nullptr;
628 ParFiniteElementSpace * pfes_j = nullptr;
629 for (int i = 0; i<nblocks; i++)
630 {
631 if (!tr_fes[i]) { continue; }
632 pfes_i = dynamic_cast<ParFiniteElementSpace*>(tr_fes[i]);
633 HypreParMatrix * Pi = (HypreParMatrix*)(&pP->GetBlock(skip_i,skip_i));
634 int skip_j=0;
635 for (int j = 0; j<nblocks; j++)
636 {
637 if (!tr_fes[j]) { continue; }
638 if (m_r->IsZeroBlock(skip_i,skip_j)) { continue; }
639 if (skip_i == skip_j)
640 {
641 // Make block diagonal square hypre matrix
642 A_r = new HypreParMatrix(pfes_i->GetComm(), pfes_i->GlobalVSize(),
643 pfes_i->GetDofOffsets(),&m_r->GetBlock(skip_i,skip_i));
644 PtAP_r = RAP(A_r,Pi);
645 delete A_r;
646
647 pS_e_r->SetBlock(skip_i,skip_i,PtAP_r->EliminateRowsCols(*ess_tdofs[skip_i]));
648
649 A_i = new HypreParMatrix(pfes_i->GetComm(), pfes_i->GlobalVSize(),
650 pfes_i->GetDofOffsets(),&m_i->GetBlock(skip_i,skip_i));
651 PtAP_i = RAP(A_i,Pi);
652 delete A_i;
653 pS_e_i->SetBlock(skip_i,skip_j,PtAP_i->EliminateCols(*ess_tdofs[skip_j]));
654 PtAP_i->EliminateRows(*ess_tdofs[skip_i]);
655 }
656 else
657 {
658 pfes_j = dynamic_cast<ParFiniteElementSpace*>(tr_fes[j]);
659 HypreParMatrix * Pj = (HypreParMatrix*)(&pP->GetBlock(skip_j,skip_j));
660 A_r = new HypreParMatrix(pfes_i->GetComm(), pfes_i->GlobalVSize(),
661 pfes_j->GlobalVSize(), pfes_i->GetDofOffsets(),
662 pfes_j->GetDofOffsets(), &m_r->GetBlock(skip_i,skip_j));
663 PtAP_r = RAP(Pi,A_r,Pj);
664 delete A_r;
665 pS_e_r->SetBlock(skip_i,skip_j,PtAP_r->EliminateCols(*ess_tdofs[skip_j]));
666 PtAP_r->EliminateRows(*ess_tdofs[skip_i]);
667
668 A_i = new HypreParMatrix(pfes_i->GetComm(), pfes_i->GlobalVSize(),
669 pfes_j->GlobalVSize(), pfes_i->GetDofOffsets(),
670 pfes_j->GetDofOffsets(), &m_i->GetBlock(skip_i,skip_j));
671 PtAP_i = RAP(Pi,A_i,Pj);
672 delete A_i;
673 pS_e_i->SetBlock(skip_i,skip_j,PtAP_i->EliminateCols(*ess_tdofs[skip_j]));
674 PtAP_i->EliminateRows(*ess_tdofs[skip_i]);
675
676 }
677 pS_r->SetBlock(skip_i,skip_j,PtAP_r);
678 pS_i->SetBlock(skip_i,skip_j,PtAP_i);
679 skip_j++;
680 }
681 skip_i++;
682 }
683}
684
685#endif
686
687
688void ComplexBlockStaticCondensation::ConformingAssemble(int skip_zeros)
689{
690 Finalize(0);
691 if (!P) { BuildProlongation(); }
692
693 BlockMatrix * Pt = Transpose(*P);
694 BlockMatrix * PtA_r = mfem::Mult(*Pt, *S_r);
695 BlockMatrix * PtA_i = mfem::Mult(*Pt, *S_i);
696 delete S_r;
697 delete S_i;
698 if (S_e_r)
699 {
700 BlockMatrix *PtAe_r = mfem::Mult(*Pt, *S_e_r);
701 BlockMatrix *PtAe_i = mfem::Mult(*Pt, *S_e_i);
702 delete S_e_r;
703 delete S_e_i;
704 S_e_r = PtAe_r;
705 S_e_i = PtAe_i;
706 }
707 delete Pt;
708 S_r = mfem::Mult(*PtA_r, *P);
709 S_i = mfem::Mult(*PtA_i, *P);
710 delete PtA_r;
711 delete PtA_i;
712
713 if (S_e_r)
714 {
715 BlockMatrix *PtAeP_r = mfem::Mult(*S_e_r, *P);
716 BlockMatrix *PtAeP_i = mfem::Mult(*S_e_i, *P);
717 S_e_r = PtAeP_r;
718 S_e_i = PtAeP_i;
719 }
720 height = 2*S_r->Height();
721 width = 2*S_r->Width();
722}
723
725{
726 if (S_r)
727 {
728 S_r->Finalize(skip_zeros);
729 S_i->Finalize(skip_zeros);
730 }
731 if (S_e_r)
732 {
733 S_e_r->Finalize(skip_zeros);
734 S_e_i->Finalize(skip_zeros);
735 }
736}
737
739 diag_policy)
740{
741
742 if (!parallel)
743 {
744 if (!S_e_r)
745 {
746 bool conforming = true;
747 for (int i = 0; i<nblocks; i++)
748 {
749 if (!tr_fes[i]) { continue; }
750 const SparseMatrix *P_ = tr_fes[i]->GetConformingProlongation();
751 if (P_)
752 {
753 conforming = false;
754 break;
755 }
756 }
757 if (!conforming) { ConformingAssemble(0); }
758 const int remove_zeros = 0;
759 EliminateReducedTrueDofs(ess_rtdof_list, diag_policy);
760 Finalize(remove_zeros);
761 }
762 }
763 else
764 {
765#ifdef MFEM_USE_MPI
766 FillEssTdofLists(ess_rtdof_list);
767 if (S_r)
768 {
769 const int remove_zeros = 0;
770 Finalize(remove_zeros);
771 ParallelAssemble(S_r, S_i);
772 delete S_r; S_r=nullptr;
773 delete S_i; S_i=nullptr;
774 delete S_e_r; S_e_r = nullptr;
775 delete S_e_i; S_e_i = nullptr;
776 }
777#endif
778 }
779}
780
781void ComplexBlockStaticCondensation::ConvertMarkerToReducedTrueDofs(
782 Array<int> & tdof_marker,
783 Array<int> & rtdof_marker)
784{
785 // convert tdof_marker to dof_marker
786 rtdof_marker.SetSize(0);
787 Array<int> tdof_marker0;
788 Array<int> dof_marker0;
789 Array<int> dof_marker;
790
791 for (int i = 0; i<nblocks; i++)
792 {
793 tdof_marker0.MakeRef(&tdof_marker[tdof_offsets[i]],
794 tdof_offsets[i+1]-tdof_offsets[i]);
795 const SparseMatrix * R_ = fes[i]->GetRestrictionMatrix();
796 if (!R_)
797 {
798 dof_marker0.MakeRef(tdof_marker0);
799 }
800 else
801 {
802 dof_marker0.SetSize(fes[i]->GetVSize());
803 R_->BooleanMultTranspose(tdof_marker0, dof_marker0);
804 }
805 dof_marker.Append(dof_marker0);
806 }
807
808 int rdofs = rdof_edof.Size();
809 Array<int> rdof_marker(rdofs);
810
811 for (int i = 0; i < rdofs; i++)
812 {
813 rdof_marker[i] = dof_marker[rdof_edof[i]];
814 }
815
816 // convert rdof_marker to rtdof_marker
817 Array<int> rtdof_marker0;
818 Array<int> rdof_marker0;
819 int k=0;
820 for (int i = 0; i<nblocks; i++)
821 {
822 if (!tr_fes[i]) { continue; }
823 rdof_marker0.MakeRef(&rdof_marker[rdof_offsets[k]],
824 rdof_offsets[k+1]-rdof_offsets[k]);
825 const SparseMatrix *tr_R = tr_fes[i]->GetRestrictionMatrix();
826 if (!tr_R)
827 {
828 rtdof_marker0.MakeRef(rdof_marker0);
829 }
830 else
831 {
832 rtdof_marker0.SetSize(tr_fes[i]->GetTrueVSize());
833 tr_R->BooleanMult(rdof_marker0, rtdof_marker0);
834 }
835 rtdof_marker.Append(rtdof_marker0);
836 k++;
837 }
838}
839
840void ComplexBlockStaticCondensation::FillEssTdofLists(const Array<int> &
841 ess_tdof_list)
842{
843 int j;
844 for (int i = 0; i<ess_tdof_list.Size(); i++)
845 {
846 int tdof = ess_tdof_list[i];
847 for (j = 0; j < rblocks; j++)
848 {
849 if (rtdof_offsets[j+1] > tdof) { break; }
850 }
851 ess_tdofs[j]->Append(tdof-rtdof_offsets[j]);
852 }
853}
854
856 &ess_tdof_list)
857{
858 Array<int> tdof_marker;
859 Array<int> rtdof_marker;
860 FiniteElementSpace::ListToMarker(ess_tdof_list,tdof_offsets.Last(),tdof_marker);
861 ConvertMarkerToReducedTrueDofs(tdof_marker, rtdof_marker);
862 FiniteElementSpace::MarkerToList(rtdof_marker,ess_rtdof_list);
863}
864
866 &ess_rtdof_list_,
868{
869
870 MFEM_VERIFY(!parallel, "EliminateReducedTrueDofs::Wrong code path");
871
872 if (S_e_r == NULL)
873 {
874 Array<int> offsets;
875
876 offsets.MakeRef( (P) ? rtdof_offsets : rdof_offsets);
877
878 S_e_r = new BlockMatrix(offsets);
879 S_e_i = new BlockMatrix(offsets);
880 S_e_r->owns_blocks = 1;
881 S_e_i->owns_blocks = 1;
882 for (int i = 0; i<S_e_r->NumRowBlocks(); i++)
883 {
884 int h = offsets[i+1] - offsets[i];
885 for (int j = 0; j<S_e_r->NumColBlocks(); j++)
886 {
887 int w = offsets[j+1] - offsets[j];
888 S_e_r->SetBlock(i,j,new SparseMatrix(h, w));
889 S_e_i->SetBlock(i,j,new SparseMatrix(h, w));
890 }
891 }
892 }
893 S_r->EliminateRowCols(ess_rtdof_list_,S_e_r,dpolicy);
894 S_i->EliminateRowCols(ess_rtdof_list_,S_e_i,
896}
897
899 Vector &sc_sol) const
900{
901 MFEM_ASSERT(sol.Size() == 2*dof_offsets.Last(), "'sol' has incorrect size");
902 const int nrdofs = rdof_offsets.Last();
903
904 Vector sol_r_real;
905 Vector sol_r_imag;
906
907 if (!R)
908 {
909 sc_sol.SetSize(2*nrdofs);
910 sol_r_real.MakeRef(sc_sol, 0, nrdofs);
911 sol_r_imag.MakeRef(sc_sol, nrdofs, nrdofs);
912 }
913 else
914 {
915 sol_r_real.SetSize(nrdofs);
916 sol_r_imag.SetSize(nrdofs);
917 }
918 for (int i = 0; i < nrdofs; i++)
919 {
920 sol_r_real(i) = sol(rdof_edof[i]);
921 sol_r_imag(i) = sol(rdof_edof[i] + dof_offsets.Last());
922 }
923
924 if (R)
925 {
926 int n = R->Height();
927 sc_sol.SetSize(2*n);
928 Vector sc_real(sc_sol, 0, n);
929 Vector sc_imag(sc_sol, n, n);
930
931 // wrap vector into a block vector
932 BlockVector blsol_r_real(sol_r_real,rdof_offsets);
933 BlockVector blsol_r_imag(sol_r_imag,rdof_offsets);
934 R->Mult(blsol_r_real, sc_real);
935 R->Mult(blsol_r_imag, sc_imag);
936 }
937}
938
940 Vector &B,
941 int copy_interior) const
942{
943 ReduceSolution(x, X);
944 Vector X_r(X,0, X.Size()/2);
945 Vector X_i(X, X.Size()/2, X.Size()/2);
946
947 if (!parallel)
948 {
949 if (!P)
950 {
951
952 S_e_r->AddMult(X_r,*y_r,-1.);
953 S_e_i->AddMult(X_i,*y_r,1.);
954 S_e_r->AddMult(X_i,*y_i,-1.);
955 S_e_i->AddMult(X_r,*y_i,-1.);
956
957 S_r->PartMult(ess_rtdof_list,X_r,*y_r);
958 S_r->PartMult(ess_rtdof_list,X_i,*y_i);
959 B.MakeRef(*y, 0, y->Size());
960 }
961 else
962 {
963 B.SetSize(2*P->Width());
964 Vector B_r(B, 0, P->Width());
965 Vector B_i(B, P->Width(), P->Width());
966
967 P->MultTranspose(*y_r, B_r);
968 P->MultTranspose(*y_i, B_i);
969
970 S_e_r->AddMult(X_r,B_r,-1.);
971 S_e_i->AddMult(X_i,B_r,1.);
972 S_e_r->AddMult(X_i,B_i,-1.);
973 S_e_i->AddMult(X_r,B_i,-1.);
974 S_r->PartMult(ess_rtdof_list,X_r,B_r);
975 S_r->PartMult(ess_rtdof_list,X_i,B_i);
976 }
977 }
978 else
979 {
980#ifdef MFEM_USE_MPI
981 int n = pP->Width();
982 B.SetSize(2*n);
983 Vector B_r(B, 0, n);
984 Vector B_i(B, n, n);
985
986 pP->MultTranspose(*y_r,B_r);
987 pP->MultTranspose(*y_i,B_i);
988
989 Vector tmp(B_r.Size());
990 pS_e_r->Mult(X_r,tmp); B_r-=tmp;
991 pS_e_i->Mult(X_i,tmp); B_r+=tmp;
992
993 pS_e_i->Mult(X_r,tmp); B_i-=tmp;
994 pS_e_r->Mult(X_i,tmp); B_i-=tmp;
995
996 for (int j = 0; j<rblocks; j++)
997 {
998 if (!ess_tdofs[j]->Size()) { continue; }
999 for (int i = 0; i < ess_tdofs[j]->Size(); i++)
1000 {
1001 int tdof = (*ess_tdofs[j])[i];
1002 int gdof = tdof + rtdof_offsets[j];
1003 B_r(gdof) = X_r(gdof);
1004 B_i(gdof) = X_i(gdof);
1005 }
1006 }
1007#endif
1008 }
1009 if (!copy_interior)
1010 {
1011 X_r.SetSubVectorComplement(ess_rtdof_list, 0.0);
1012 X_i.SetSubVectorComplement(ess_rtdof_list, 0.0);
1013 }
1014}
1015
1016
1018 Vector &sol) const
1019{
1020
1021 const int nrdofs = rdof_offsets.Last();
1022 const int nrtdofs = rtdof_offsets.Last();
1023 MFEM_VERIFY(sc_sol.Size() == 2*nrtdofs, "'sc_sol' has incorrect size");
1024
1025 Vector sol_r_real;
1026 Vector sol_r_imag;
1027 if (!parallel)
1028 {
1029 if (!P)
1030 {
1031 sol_r_real.MakeRef(const_cast<Vector &>(sc_sol), 0, sc_sol.Size()/2);
1032 sol_r_imag.MakeRef(const_cast<Vector &>(sc_sol), sc_sol.Size()/2,
1033 sc_sol.Size()/2);
1034 }
1035 else
1036 {
1037 Vector sc_real(const_cast<Vector &>(sc_sol),0, nrtdofs);
1038 Vector sc_imag(const_cast<Vector &>(sc_sol),nrtdofs, nrtdofs);
1039 sol_r_real.SetSize(nrdofs);
1040 sol_r_imag.SetSize(nrdofs);
1041 P->Mult(sc_real, sol_r_real);
1042 P->Mult(sc_imag, sol_r_imag);
1043 }
1044 }
1045 else
1046 {
1047#ifdef MFEM_USE_MPI
1048 Vector sc_real(const_cast<Vector &>(sc_sol),0, nrtdofs);
1049 Vector sc_imag(const_cast<Vector &>(sc_sol),nrtdofs, nrtdofs);
1050 sol_r_real.SetSize(nrdofs);
1051 sol_r_imag.SetSize(nrdofs);
1052 pP->Mult(sc_real, sol_r_real);
1053 pP->Mult(sc_imag, sol_r_imag);
1054#endif
1055 }
1056
1057 sol.SetSize(2*dof_offsets.Last());
1058 Vector sol_real(sol,0,dof_offsets.Last());
1059 Vector sol_imag(sol,dof_offsets.Last(),dof_offsets.Last());
1060
1061 if (rdof_offsets.Last() == dof_offsets.Last())
1062 {
1063 sol_real = sol_r_real;
1064 sol_imag = sol_r_imag;
1065 return;
1066 }
1067
1068 Vector lsr; // element (local) sc solution vector
1069 Vector lsr_real; // element (local) sc solution vector
1070 Vector lsr_imag; // element (local) sc solution vector
1071 Vector lsi; // element (local) interior solution vector
1072 Vector lsi_real; // element (local) interior solution vector
1073 Vector lsi_imag; // element (local) interior solution vector
1074
1075 const int NE = mesh->GetNE();
1076
1077 Array<int> trace_vdofs;
1078 Array<int> vdofs;
1079 Array<int> tr_offsets;
1080 Vector lsol;
1081 Vector lsol_real;
1082 Vector lsol_imag;
1083 for (int iel = 0; iel < NE; iel++)
1084 {
1085 GetReduceElementVDofs(iel, trace_vdofs);
1086
1087 int n = trace_vdofs.Size();
1088 lsr.SetSize(2*n);
1089 lsr_real.MakeRef(lsr, 0, n);
1090 lsr_imag.MakeRef(lsr, n, n);
1091 sol_r_real.GetSubVector(trace_vdofs, lsr_real);
1092 sol_r_imag.GetSubVector(trace_vdofs, lsr_imag);
1093
1094 // complete the interior dofs
1095 int m = lmat[iel]->Height()/2;
1096 lsi.SetSize(2*m);
1097 lsi_real.MakeRef(lsi, 0, m);
1098 lsi_imag.MakeRef(lsi, m, m);
1099 lmat[iel]->Mult(lsr,lsi);
1100 lsi.Neg();
1101 lsi+=*lvec[iel];
1102
1103 Array<int> tr_idx,int_idx,idx_offs;
1104 GetReduceElementIndicesAndOffsets(iel,tr_idx, int_idx, idx_offs);
1105
1106 // complete all the dofs in the element
1107 int k = (lmat[iel]->Width() + lmat[iel]->Height())/2;
1108 lsol.SetSize(2*k);
1109 lsol_real.MakeRef(lsol, 0, k);
1110 lsol_imag.MakeRef(lsol, k, k);
1111
1112 lsol_real.SetSubVector(tr_idx,lsr_real);
1113 lsol_real.SetSubVector(int_idx,lsi_real);
1114 lsol_imag.SetSubVector(tr_idx,lsr_imag);
1115 lsol_imag.SetSubVector(int_idx,lsi_imag);
1116
1117 GetElementVDofs(iel, vdofs);
1118
1119 // complete all the dofs in the global vector
1120 sol_real.SetSubVector(vdofs,lsol_real);
1121 sol_imag.SetSubVector(vdofs,lsol_imag);
1122 }
1123}
1124
1126{
1127 delete S_e_r; S_e_r = nullptr;
1128 delete S_e_i; S_e_i = nullptr;
1129 delete S_r; S_r = nullptr;
1130 delete S_i; S_i = nullptr;
1131 delete S; S=nullptr;
1132 delete y_r; y_r=nullptr;
1133 delete y_i; y_i=nullptr;
1134 delete y; y=nullptr;
1135
1136 if (P) { delete P; } P=nullptr;
1137 if (R) { delete R; } R=nullptr;
1138
1139#ifdef MFEM_USE_MPI
1140 if (parallel)
1141 {
1142 // The Complex Operator (S) is deleted above
1143 delete pS_e_r; pS_e_r=nullptr;
1144 delete pS_e_i; pS_e_i=nullptr;
1145 delete pS_r; pS_r=nullptr;
1146 delete pS_i; pS_i=nullptr;
1147 for (int i = 0; i<rblocks; i++)
1148 {
1149 delete ess_tdofs[i];
1150 }
1151 delete pP; pP = nullptr;
1152 }
1153#endif
1154
1155 for (int i=0; i<lmat.Size(); i++)
1156 {
1157 delete lmat[i]; lmat[i] = nullptr;
1158 delete lvec[i]; lvec[i] = nullptr;
1159 }
1160}
1161
1162}
void SetSize(int nsize)
Change the logical size of the array, keep existing entries.
Definition array.hpp:840
int Size() const
Return the logical size of the array.
Definition array.hpp:166
void PartialSum()
Fill the entries of the array with the cumulative sum of the entries.
Definition array.cpp:104
void MakeRef(T *data_, int size_, bool own_data=false)
Make this Array a reference to a pointer.
Definition array.hpp:1053
int Append(const T &el)
Append element 'el' to array, resize if necessary.
Definition array.hpp:912
T & Last()
Return the last element in the array.
Definition array.hpp:945
void MultTranspose(const Vector &x, Vector &y) const override
MatrixTranspose-Vector Multiplication y = A'*x.
void PartMult(const Array< int > &rows, const Vector &x, Vector &y) const
Partial matrix vector multiplication of (*this) with x involving only the rows given by rows....
void SetBlock(int i, int j, SparseMatrix *mat)
Set A(i,j) = mat.
void Mult(const Vector &x, Vector &y) const override
Matrix-Vector Multiplication y = A*x.
int NumColBlocks() const
Return the number of column blocks.
int IsZeroBlock(int i, int j) const
Check if block (i,j) is a zero block.
void EliminateRowCols(const Array< int > &vdofs, BlockMatrix *Ae, DiagonalPolicy dpolicy=DIAG_ONE)
Eliminate the rows and columns corresponding to the entries in vdofs + save the eliminated entries in...
SparseMatrix & GetBlock(int i, int j)
Return a reference to block (i,j). Reference may be invalid if Aij(i,j) == NULL.
void AddMult(const Vector &x, Vector &y, const real_t val=1.) const override
Matrix-Vector Multiplication y = y + val*A*x.
int owns_blocks
If owns_blocks the SparseMatrix objects Aij will be deallocated.
void Finalize(int skip_zeros=1) override
Finalize all the submatrices.
int NumRowBlocks() const
Return the number of row blocks.
A class to handle Block systems in a matrix-free implementation.
void Mult(const Vector &x, Vector &y) const override
Operator application.
void SetBlock(int iRow, int iCol, Operator *op, real_t c=1.0)
Add a block op in the block-entry (iblock, jblock).
Operator & GetBlock(int i, int j)
Return a reference to block i,j.
void MultTranspose(const Vector &x, Vector &y) const override
Action of the transpose operator.
A class to handle Vectors in a block fashion.
Vector & GetBlock(int i)
Get the i-th vector in the block.
void EliminateReducedTrueDofs(const Array< int > &ess_rtdof_list, Matrix::DiagonalPolicy dpolicy)
Eliminate the given reduced true dofs from the Schur complement matrix S.
ComplexBlockStaticCondensation(Array< FiniteElementSpace * > &fes_)
void ParallelAssemble(BlockMatrix *m_r, BlockMatrix *m_i)
void Finalize(int skip_zeros=0)
Finalize the construction of the Schur complement matrix.
void AssembleReducedSystem(int el, ComplexDenseMatrix &elmat, Vector &elvect_r, Vector &elvect_i)
void FormSystemMatrix(Operator::DiagonalPolicy diag_policy)
void SetEssentialTrueDofs(const Array< int > &ess_tdof_list)
Determine and save internally essential reduced true dofs.
void ComputeSolution(const Vector &sc_sol, Vector &sol) const
void ReduceSystem(Vector &x, Vector &X, Vector &B, int copy_interior=0) const
Set the reduced solution X and r.h.s B vectors from the full linear system solution x and r....
void ReduceSolution(const Vector &sol, Vector &sc_sol) const
Specialization of the ComplexOperator built from a pair of Dense Matrices. The purpose of this specia...
DenseMatrix & imag() override
DenseMatrix & real() override
Real or imaginary part accessor methods.
Data type dense matrix using column-major storage.
Definition densemat.hpp:24
void GetSubMatrix(const Array< int > &idx, DenseMatrix &A) const
void TransformDual(real_t *v) const
Definition doftrans.cpp:77
void SetDofTransformation(const StatelessDofTransformation &dof_trans)
Set or change the nested StatelessDofTransformation object.
Definition doftrans.hpp:176
@ DISCONTINUOUS
Field is discontinuous across element interfaces.
Definition fe_coll.hpp:48
static void ListToMarker(const Array< int > &list, int marker_size, Array< int > &marker, int mark_val=-1)
Convert an array of indices (list) to a Boolean marker array where all indices in the list are marked...
Definition fespace.cpp:779
static void MarkerToList(const Array< int > &marker, Array< int > &list)
Convert a Boolean marker array to a list containing all marked indices.
Definition fespace.cpp:760
Wrapper for hypre's ParCSR matrix class.
Definition hypre.hpp:419
void EliminateRows(const Array< int > &rows)
Eliminate rows from the diagonal and off-diagonal blocks of the matrix.
Definition hypre.cpp:2438
void EliminateRowsCols(const Array< int > &rows_cols, const HypreParVector &X, HypreParVector &B)
Definition hypre.cpp:2399
HypreParMatrix * EliminateCols(const Array< int > &cols)
Definition hypre.cpp:2424
void GetElementVertices(int i, Array< int > &v) const
Returns the indices of the vertices of element i.
Definition mesh.hpp:1609
int GetNE() const
Returns number of elements.
Definition mesh.hpp:1377
int Dimension() const
Dimension of the reference space used within the elements.
Definition mesh.hpp:1306
void GetElementFaces(int i, Array< int > &faces, Array< int > &ori) const
Return the indices and the orientations of all faces of element i.
Definition mesh.cpp:7835
void GetElementEdges(int i, Array< int > &edges, Array< int > &cor) const
Return the indices and the orientations of all edges of element i.
Definition mesh.cpp:7588
int Height() const
Get the height (size of output) of the Operator. Synonym with NumRows().
Definition operator.hpp:66
DiagonalPolicy
Defines operator diagonal policy upon elimination of rows and/or columns.
Definition operator.hpp:48
@ DIAG_ZERO
Set the diagonal value to zero.
Definition operator.hpp:49
int Width() const
Get the width (size of input) of the Operator. Synonym with NumCols().
Definition operator.hpp:72
Abstract parallel finite element space.
Definition pfespace.hpp:31
MPI_Comm GetComm() const
Definition pfespace.hpp:337
HYPRE_BigInt GlobalVSize() const
Definition pfespace.hpp:347
HYPRE_BigInt * GetDofOffsets() const
Definition pfespace.hpp:345
Class for parallel meshes.
Definition pmesh.hpp:34
Data type sparse matrix.
Definition sparsemat.hpp:51
void BooleanMultTranspose(const Array< int > &x, Array< int > &y) const
y = At * x, treating all entries as booleans (zero=false, nonzero=true).
void AddSubMatrix(const Array< int > &rows, const Array< int > &cols, const DenseMatrix &subm, int skip_zeros=1)
Vector data type.
Definition vector.hpp:82
void Neg()
(*this) = -(*this)
Definition vector.cpp:376
void SetSubVector(const Array< int > &dofs, const real_t value)
Set the entries listed in dofs to the given value.
Definition vector.cpp:702
void AddElementVector(const Array< int > &dofs, const Vector &elemvect)
Add elements of the elemvect Vector to the entries listed in dofs. Negative dof values cause the -dof...
Definition vector.cpp:785
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
void SetSubVectorComplement(const Array< int > &dofs, const real_t val)
Set all vector entries NOT in the dofs Array to the given val.
Definition vector.cpp:854
void GetSubVector(const Array< int > &dofs, Vector &elemvect) const
Extract entries listed in dofs to the output Vector elemvect.
Definition vector.cpp:676
void MakeRef(Vector &base, int offset, int size)
Reset the Vector to be a reference to a sub-vector of base.
Definition vector.hpp:660
int dim
Definition ex24.cpp:53
int GetVDim(const FieldDescriptor &f)
Get the vdim of a field descriptor.
Definition util.hpp:864
int GetTrueVSize(const FieldDescriptor &f)
Get the true dof size of a field descriptor.
Definition util.hpp:829
void Mult(const Table &A, const Table &B, Table &C)
C = A * B (as boolean matrices)
Definition table.cpp:505
void TransformDual(const DofTransformation &ran_dof_trans, const DofTransformation &dom_dof_trans, DenseMatrix &elmat)
Definition doftrans.cpp:152
void Transpose(const Table &A, Table &At, int ncols_A_)
Transpose a Table.
Definition table.cpp:443
void RAP(const DenseMatrix &A, const DenseMatrix &P, DenseMatrix &RAP)