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