MFEM v4.9.0
Finite element discretization library
Loading...
Searching...
No Matches
blockstaticcond.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 "blockstaticcond.hpp"
13
14namespace mfem
15{
16
18 fes_)
19{
20 SetSpaces(fes_);
21
22 Array<int> rvdofs;
23 Array<int> vdofs;
24 Array<int> rdof_edof0;
25 for (int k = 0; k<nblocks; k++)
26 {
27 if (!tr_fes[k]) { continue; }
28 rdof_edof0.SetSize(tr_fes[k]->GetVSize());
29 for (int i = 0; i < mesh->GetNE(); i++)
30 {
31 fes[k]->GetElementVDofs(i, vdofs);
32 tr_fes[k]->GetElementVDofs(i, rvdofs);
33 const int vdim = fes[k]->GetVDim();
34 const int nsd = vdofs.Size()/vdim;
35 const int nsrd = rvdofs.Size()/vdim;
36 for (int vd = 0; vd < vdim; vd++)
37 {
38 for (int j = 0; j < nsrd; j++)
39 {
40 int rvdof = rvdofs[j+nsrd*vd];
41 int vdof = vdofs[j+nsd*vd];
42 if (rvdof < 0)
43 {
44 rvdof = -1-rvdof;
45 vdof = -1-vdof;
46 }
47 MFEM_ASSERT(vdof >= 0, "incompatible volume and trace FE spaces");
48 rdof_edof0[rvdof] = vdof + dof_offsets[k];
49 }
50 }
51 }
52 rdof_edof.Append(rdof_edof0);
53 }
54}
55
56void BlockStaticCondensation::SetSpaces(Array<FiniteElementSpace*> & fes_)
57{
58#ifdef MFEM_USE_MPI
59 ParMesh *pmesh = nullptr;
60 parallel = false;
61 if (dynamic_cast<ParFiniteElementSpace *>(fes_[0]))
62 {
63 parallel = true;
64 }
65#else
66 parallel = false;
67#endif
68 fes=fes_;
69 nblocks = fes.Size();
70 rblocks = 0;
71 tr_fes.SetSize(nblocks);
72 mesh = fes[0]->GetMesh();
73
74 IsTraceSpace.SetSize(nblocks);
75 const FiniteElementCollection * fec;
76 for (int i = 0; i < nblocks; i++)
77 {
78 fec = fes[i]->FEColl();
79 IsTraceSpace[i] =
80 (dynamic_cast<const H1_Trace_FECollection*>(fec) ||
81 dynamic_cast<const ND_Trace_FECollection*>(fec) ||
82 dynamic_cast<const RT_Trace_FECollection*>(fec));
83#ifdef MFEM_USE_MPI
84 if (parallel)
85 {
86 pmesh = dynamic_cast<ParMesh *>(mesh);
87 tr_fes[i] = (fec->GetContType() == FiniteElementCollection::DISCONTINUOUS) ?
88 nullptr : (IsTraceSpace[i]) ? fes[i] :
89 new ParFiniteElementSpace(pmesh, fec->GetTraceCollection(), fes[i]->GetVDim(),
90 fes[i]->GetOrdering());
91 }
92 else
93 {
94 tr_fes[i] = (fec->GetContType() == FiniteElementCollection::DISCONTINUOUS) ?
95 nullptr : (IsTraceSpace[i]) ? fes[i] :
96 new FiniteElementSpace(mesh, fec->GetTraceCollection(), fes[i]->GetVDim(),
97 fes[i]->GetOrdering());
98 }
99#else
100 // skip if it's an L2 space (no trace space to construct)
101 tr_fes[i] = (fec->GetContType() == FiniteElementCollection::DISCONTINUOUS) ?
102 nullptr : (IsTraceSpace[i]) ? fes[i] :
103 new FiniteElementSpace(mesh, fec->GetTraceCollection(), fes[i]->GetVDim(),
104 fes[i]->GetOrdering());
105#endif
106 if (tr_fes[i]) { rblocks++; }
107 }
108 if (parallel)
109 {
110 ess_tdofs.SetSize(rblocks);
111 for (int i = 0; i<rblocks; i++)
112 {
113 ess_tdofs[i] = new Array<int>();
114 }
115 }
116 Init();
117}
118
119void BlockStaticCondensation::ComputeOffsets()
120{
121 dof_offsets.SetSize(nblocks+1);
122 tdof_offsets.SetSize(nblocks+1);
123 dof_offsets[0] = 0;
124 tdof_offsets[0] = 0;
125
126 rdof_offsets.SetSize(rblocks+1);
127 rtdof_offsets.SetSize(rblocks+1);
128 rdof_offsets[0] = 0;
129 rtdof_offsets[0] = 0;
130
131 int j=0;
132 for (int i =0; i<nblocks; i++)
133 {
134 dof_offsets[i+1] = fes[i]->GetVSize();
135 tdof_offsets[i+1] = fes[i]->GetTrueVSize();
136 if (tr_fes[i])
137 {
138 rdof_offsets[j+1] = tr_fes[i]->GetVSize();
139 rtdof_offsets[j+1] = tr_fes[i]->GetTrueVSize();
140 j++;
141 }
142 }
143 rdof_offsets.PartialSum();
144 rtdof_offsets.PartialSum();
145 dof_offsets.PartialSum();
146 tdof_offsets.PartialSum();
147}
148
149
150void BlockStaticCondensation::Init()
151{
152 lmat.SetSize(mesh->GetNE());
153 lvec.SetSize(mesh->GetNE());
154 for (int i = 0; i < mesh->GetNE(); i++)
155 {
156 lmat[i] = nullptr;
157 lvec[i] = nullptr;
158 }
159
160 ComputeOffsets();
161
162 S = new BlockMatrix(rdof_offsets);
163 S->owns_blocks = 1;
164
165 for (int i = 0; i<S->NumRowBlocks(); i++)
166 {
167 int h = rdof_offsets[i+1] - rdof_offsets[i];
168 for (int j = 0; j<S->NumColBlocks(); j++)
169 {
170 int w = rdof_offsets[j+1] - rdof_offsets[j];
171 S->SetBlock(i,j,new SparseMatrix(h, w));
172 }
173 }
174 y = new BlockVector(rdof_offsets);
175 *y = 0.;
176}
177
178void BlockStaticCondensation::GetReducedElementIndicesAndOffsets(int el,
179 Array<int> & trace_ldofs,
180 Array<int> & interior_ldofs,
181 Array<int> & offsets) const
182{
183 int dim = mesh->Dimension();
184 offsets.SetSize(tr_fes.Size()+1); offsets = 0;
185 Array<int> dofs;
186 Array<int> faces, ori;
187 if (dim == 1)
188 {
189 mesh->GetElementVertices(el, faces);
190 }
191 else if (dim == 2)
192 {
193 mesh->GetElementEdges(el, faces, ori);
194 }
195 else if (dim == 3)
196 {
197 mesh->GetElementFaces(el,faces,ori);
198 }
199 else
200 {
201 MFEM_ABORT("BlockStaticCondensation::GetReducedElementIndicesAndOffsets: "
202 "dim > 3 not supported");
203 }
204 int numfaces = faces.Size();
205
206 trace_ldofs.SetSize(0);
207 interior_ldofs.SetSize(0);
208 // construct Array of bubble dofs to be extracted
209 int skip=0;
210 Array<int> tr_dofs;
211 Array<int> int_dofs;
212 for (int i = 0; i<tr_fes.Size(); i++)
213 {
214 int td = 0;
215 int ndof;
216 // if it's an L2 space (bubbles)
217 if (!tr_fes[i])
218 {
219 ndof = fes[i]->GetVDim()*fes[i]->GetFE(el)->GetDof();
220 td = 0;
221 }
222 else if (IsTraceSpace[i])
223 {
224 for (int iface = 0; iface < numfaces; iface++)
225 {
226 td += fes[i]->GetVDim()*fes[i]->GetFaceElement(faces[iface])->GetDof();
227 }
228 ndof = td;
229 }
230 else
231 {
232 Array<int> trace_dofs;
233 ndof = fes[i]->GetVDim()*fes[i]->GetFE(el)->GetDof();
234 tr_fes[i]->GetElementVDofs(el, trace_dofs);
235 td = trace_dofs.Size(); // number of trace dofs
236 }
237 offsets[i+1] = td;
238 tr_dofs.SetSize(td);
239 int_dofs.SetSize(ndof - td);
240 for (int j = 0; j<td; j++)
241 {
242 tr_dofs[j] = skip + j;
243 }
244 for (int j = 0; j<ndof-td; j++)
245 {
246 int_dofs[j] = skip + td + j;
247 }
248 skip+=ndof;
249
250 trace_ldofs.Append(tr_dofs);
251 interior_ldofs.Append(int_dofs);
252 }
253 offsets.PartialSum();
254}
255
256
257void BlockStaticCondensation::GetReducedElementVDofs(int el,
258 Array<int> & rdofs) const
259{
260 Array<int> faces, ori;
261 int dim = mesh->Dimension();
262 if (dim == 1)
263 {
264 mesh->GetElementVertices(el, faces);
265 }
266 else if (dim == 2)
267 {
268 mesh->GetElementEdges(el, faces, ori);
269 }
270 else if (dim == 3)
271 {
272 mesh->GetElementFaces(el,faces,ori);
273 }
274 else
275 {
276 MFEM_ABORT("BlockStaticCondensation::GetReducedElementVDofs: "
277 "dim > 3 not supported");
278 }
279 int numfaces = faces.Size();
280 rdofs.SetSize(0);
281 int skip = 0;
282 for (int i = 0; i<tr_fes.Size(); i++)
283 {
284 if (!tr_fes[i]) { continue; }
285 Array<int> vdofs;
286 if (IsTraceSpace[i])
287 {
288 Array<int> face_vdofs;
289 for (int k = 0; k < numfaces; k++)
290 {
291 int iface = faces[k];
292 tr_fes[i]->GetFaceVDofs(iface, face_vdofs);
293 vdofs.Append(face_vdofs);
294 }
295 }
296 else
297 {
298 tr_fes[i]->GetElementVDofs(el, vdofs);
299 }
300 for (int j=0; j<vdofs.Size(); j++)
301 {
302 vdofs[j] = (vdofs[j]>=0) ? vdofs[j]+rdof_offsets[skip] :
303 vdofs[j]-rdof_offsets[skip];
304 }
305 skip++;
306 rdofs.Append(vdofs);
307 }
308}
309
310void BlockStaticCondensation::GetElementVDofs(int el, Array<int> & vdofs) const
311{
312 Array<int> faces, ori;
313 int dim = mesh->Dimension();
314 if (dim == 1)
315 {
316 mesh->GetElementVertices(el, faces);
317 }
318 else if (dim == 2)
319 {
320 mesh->GetElementEdges(el, faces, ori);
321 }
322 else if (dim == 3)
323 {
324 mesh->GetElementFaces(el,faces,ori);
325 }
326 else
327 {
328 MFEM_ABORT("BlockStaticCondensation::GetElementVDofs: "
329 "dim > 3 not supported");
330 }
331 int numfaces = faces.Size();
332 vdofs.SetSize(0);
333 for (int i = 0; i<tr_fes.Size(); i++)
334 {
335 Array<int> dofs;
336 if (IsTraceSpace[i])
337 {
338 Array<int> face_vdofs;
339 for (int k = 0; k < numfaces; k++)
340 {
341 int iface = faces[k];
342 fes[i]->GetFaceVDofs(iface, face_vdofs);
343 dofs.Append(face_vdofs);
344 }
345 }
346 else
347 {
348 fes[i]->GetElementVDofs(el, dofs);
349 }
350 for (int j=0; j<dofs.Size(); j++)
351 {
352 dofs[j] = (dofs[j]>=0) ? dofs[j]+dof_offsets[i] :
353 dofs[j]-dof_offsets[i];
354 }
355 vdofs.Append(dofs);
356 }
357}
358
359
360void BlockStaticCondensation::GetLocalSchurComplement(int el,
361 const Array<int> & tr_idx,
362 const Array<int> & int_idx,
363 const DenseMatrix & elmat,
364 const Vector & elvect,
365 DenseMatrix & rmat,
366 Vector & rvect)
367{
368 int rdofs = tr_idx.Size();
369 int idofs = int_idx.Size();
370 MFEM_VERIFY(idofs != 0, "Number of interior dofs is zero");
371 MFEM_VERIFY(rdofs != 0, "Number of interface dofs is zero");
372
373 rmat.SetSize(rdofs);
374 rvect.SetSize(rdofs);
375
376 DenseMatrix A_tt, A_ti, A_it, A_ii;
377 Vector y_t, y_i;
378
379 elmat.GetSubMatrix(tr_idx,A_tt);
380 elmat.GetSubMatrix(tr_idx,int_idx, A_ti);
381 elmat.GetSubMatrix(int_idx, tr_idx, A_it);
382 elmat.GetSubMatrix(int_idx, A_ii);
383
384 elvect.GetSubVector(tr_idx, y_t);
385 elvect.GetSubVector(int_idx, y_i);
386
387 DenseMatrixInverse lu(A_ii);
388 lu.Factor();
389 lmat[el] = new DenseMatrix(idofs,rdofs);
390 lvec[el] = new Vector(idofs);
391
392 lu.Mult(A_it,*lmat[el]);
393 lu.Mult(y_i,*lvec[el]);
394
395 // LHS
396 mfem::Mult(A_ti,*lmat[el],rmat);
397
398 rmat.Neg();
399 rmat.Add(1., A_tt);
400
401 // RHS
402 A_ti.Mult(*lvec[el], rvect);
403 rvect.Neg();
404 rvect.Add(1., y_t);
405}
406
407
409 DenseMatrix &elmat,
410 Vector & elvect)
411{
412 // Get Schur Complement
413 Array<int> tr_idx, int_idx;
414 Array<int> offsets;
415 // Get local element idx and offsets for global assembly
416 GetReducedElementIndicesAndOffsets(el, tr_idx,int_idx, offsets);
417
418 DenseMatrix rmat, *rmatptr;
419 Vector rvec, *rvecptr;
420 // Extract the reduced matrices based on tr_idx and int_idx
421 if (int_idx.Size()!=0)
422 {
423 GetLocalSchurComplement(el,tr_idx,int_idx, elmat, elvect, rmat, rvec);
424 rmatptr = &rmat;
425 rvecptr = &rvec;
426 }
427 else
428 {
429 rmatptr = &elmat;
430 rvecptr = &elvect;
431 }
432
433 // Assemble global mat and rhs
434 DofTransformation doftrans_i, doftrans_j;
435
436 Array<int> faces, ori;
437 int dim = mesh->Dimension();
438 if (dim == 1)
439 {
440 mesh->GetElementVertices(el, faces);
441 }
442 else if (dim == 2)
443 {
444 mesh->GetElementEdges(el, faces, ori);
445 }
446 else if (dim == 3)
447 {
448 mesh->GetElementFaces(el,faces,ori);
449 }
450 else
451 {
452 MFEM_ABORT("BlockStaticCondensation::AssembleReducedSystem: "
453 "dim > 3 not supported");
454 }
455 int numfaces = faces.Size();
456
457 int skip_i=0;
458 for (int i = 0; i<tr_fes.Size(); i++)
459 {
460 if (!tr_fes[i]) { continue; }
461 Array<int> vdofs_i;
462 doftrans_i.SetDofTransformation(nullptr);
463 if (IsTraceSpace[i])
464 {
465 Array<int> face_vdofs;
466 for (int k = 0; k < numfaces; k++)
467 {
468 int iface = faces[k];
469 tr_fes[i]->GetFaceVDofs(iface, face_vdofs);
470 vdofs_i.Append(face_vdofs);
471 }
472 }
473 else
474 {
475 tr_fes[i]->GetElementVDofs(el, vdofs_i, doftrans_i);
476 }
477 int skip_j=0;
478 for (int j = 0; j<tr_fes.Size(); j++)
479 {
480 if (!tr_fes[j]) { continue; }
481 Array<int> vdofs_j;
482 doftrans_j.SetDofTransformation(nullptr);
483
484 if (IsTraceSpace[j])
485 {
486 Array<int> face_vdofs;
487 for (int k = 0; k < numfaces; k++)
488 {
489 int iface = faces[k];
490 tr_fes[j]->GetFaceVDofs(iface, face_vdofs);
491 vdofs_j.Append(face_vdofs);
492 }
493 }
494 else
495 {
496 tr_fes[j]->GetElementVDofs(el, vdofs_j, doftrans_j);
497 }
498
499 DenseMatrix Ae;
500 rmatptr->GetSubMatrix(offsets[i],offsets[i+1],
501 offsets[j],offsets[j+1], Ae);
502 TransformDual(doftrans_i, doftrans_j, Ae);
503 S->GetBlock(skip_i,skip_j).AddSubMatrix(vdofs_i,vdofs_j, Ae);
504 skip_j++;
505 }
506
507 // assemble rhs
508 real_t * data = rvecptr->GetData();
509 Vector vec1;
510 // ref subvector
511 vec1.SetDataAndSize(&data[offsets[i]],
512 offsets[i+1]-offsets[i]);
513 doftrans_i.TransformDual(vec1);
514 y->GetBlock(skip_i).AddElementVector(vdofs_i,vec1);
515 skip_i++;
516 }
517}
518
519void BlockStaticCondensation::BuildProlongation()
520{
521 P = new BlockMatrix(rdof_offsets, rtdof_offsets);
522 R = new BlockMatrix(rtdof_offsets, rdof_offsets);
523 P->owns_blocks = 0;
524 R->owns_blocks = 0;
525 int skip = 0;
526 for (int i = 0; i<nblocks; i++)
527 {
528 if (!tr_fes[i]) { continue; }
529 const SparseMatrix *P_ = tr_fes[i]->GetConformingProlongation();
530 if (P_)
531 {
532 const SparseMatrix *R_ = tr_fes[i]->GetRestrictionMatrix();
533 P->SetBlock(skip,skip,const_cast<SparseMatrix*>(P_));
534 R->SetBlock(skip,skip,const_cast<SparseMatrix*>(R_));
535 }
536 skip++;
537 }
538}
539
540#ifdef MFEM_USE_MPI
541void BlockStaticCondensation::BuildParallelProlongation()
542{
543 MFEM_VERIFY(parallel, "BuildParallelProlongation: wrong code path");
544 pP = new BlockOperator(rdof_offsets, rtdof_offsets);
545 R = new BlockMatrix(rtdof_offsets, rdof_offsets);
546 pP->owns_blocks = 0;
547 R->owns_blocks = 0;
548 int skip = 0;
549 for (int i = 0; i<nblocks; i++)
550 {
551 if (!tr_fes[i]) { continue; }
552 const HypreParMatrix *P_ =
553 dynamic_cast<ParFiniteElementSpace *>(tr_fes[i])->Dof_TrueDof_Matrix();
554 if (P_)
555 {
556 const SparseMatrix *R_ = tr_fes[i]->GetRestrictionMatrix();
557 pP->SetBlock(skip,skip,const_cast<HypreParMatrix*>(P_));
558 R->SetBlock(skip,skip,const_cast<SparseMatrix*>(R_));
559 }
560 skip++;
561 }
562}
563
565{
566 if (!pP) { BuildParallelProlongation(); }
567
568 pS = new BlockOperator(rtdof_offsets);
569 pS_e = new BlockOperator(rtdof_offsets);
570 pS->owns_blocks = 1;
571 pS_e->owns_blocks = 1;
572 HypreParMatrix * A = nullptr;
573 HypreParMatrix * PtAP = nullptr;
574 int skip_i=0;
575 ParFiniteElementSpace * pfes_i = nullptr;
576 ParFiniteElementSpace * pfes_j = nullptr;
577 for (int i = 0; i<nblocks; i++)
578 {
579 if (!tr_fes[i]) { continue; }
580 pfes_i = dynamic_cast<ParFiniteElementSpace*>(tr_fes[i]);
581 HypreParMatrix * Pi = (HypreParMatrix*)(&pP->GetBlock(skip_i,skip_i));
582 int skip_j=0;
583 for (int j = 0; j<nblocks; j++)
584 {
585 if (!tr_fes[j]) { continue; }
586 if (m->IsZeroBlock(skip_i,skip_j)) { continue; }
587 if (skip_i == skip_j)
588 {
589 // Make block diagonal square hypre matrix
590 A = new HypreParMatrix(pfes_i->GetComm(), pfes_i->GlobalVSize(),
591 pfes_i->GetDofOffsets(),&m->GetBlock(skip_i,skip_i));
592 PtAP = RAP(A,Pi);
593 delete A;
594 pS_e->SetBlock(skip_i,skip_i,PtAP->EliminateRowsCols(*ess_tdofs[skip_i]));
595 }
596 else
597 {
598 pfes_j = dynamic_cast<ParFiniteElementSpace*>(tr_fes[j]);
599 HypreParMatrix * Pj = (HypreParMatrix*)(&pP->GetBlock(skip_j,skip_j));
600 A = new HypreParMatrix(pfes_i->GetComm(), pfes_i->GlobalVSize(),
601 pfes_j->GlobalVSize(), pfes_i->GetDofOffsets(),
602 pfes_j->GetDofOffsets(), &m->GetBlock(skip_i,skip_j));
603 PtAP = RAP(Pi,A,Pj);
604 delete A;
605 pS_e->SetBlock(skip_i,skip_j,PtAP->EliminateCols(*ess_tdofs[skip_j]));
606 PtAP->EliminateRows(*ess_tdofs[skip_i]);
607 }
608 pS->SetBlock(skip_i,skip_j,PtAP);
609 skip_j++;
610 }
611 skip_i++;
612 }
613}
614
615#endif
616
617
618void BlockStaticCondensation::ConformingAssemble(int skip_zeros)
619{
620 Finalize(0);
621 if (!P) { BuildProlongation(); }
622
623 BlockMatrix * Pt = Transpose(*P);
624 BlockMatrix * PtA = mfem::Mult(*Pt, *S);
625 delete S;
626 if (S_e)
627 {
628 BlockMatrix *PtAe = mfem::Mult(*Pt, *S_e);
629 delete S_e;
630 S_e = PtAe;
631 }
632 delete Pt;
633 S = mfem::Mult(*PtA, *P);
634 delete PtA;
635
636 if (S_e)
637 {
638 BlockMatrix *PtAeP = mfem::Mult(*S_e, *P);
639 S_e = PtAeP;
640 }
641 height = S->Height();
642 width = S->Width();
643}
644
646{
647 if (S) { S->Finalize(skip_zeros); }
648 if (S_e) { S_e->Finalize(skip_zeros); }
649}
650
652 diag_policy)
653{
654 if (!parallel)
655 {
656 if (!S_e)
657 {
658 bool conforming = true;
659 for (int i = 0; i<nblocks; i++)
660 {
661 if (!tr_fes[i]) { continue; }
662 const SparseMatrix *P_ = tr_fes[i]->GetConformingProlongation();
663 if (P_)
664 {
665 conforming = false;
666 break;
667 }
668 }
669 if (!conforming) { ConformingAssemble(0); }
670 const int remove_zeros = 0;
671 EliminateReducedTrueDofs(ess_rtdof_list, diag_policy);
672 Finalize(remove_zeros);
673 }
674 }
675 else
676 {
677#ifdef MFEM_USE_MPI
678 FillEssTdofLists(ess_rtdof_list);
679 if (S)
680 {
681 const int remove_zeros = 0;
682 Finalize(remove_zeros);
684 delete S; S=nullptr;
685 delete S_e; S_e = nullptr;
686 }
687#endif
688 }
689}
690
691
692void BlockStaticCondensation::ConvertMarkerToReducedTrueDofs(
693 Array<int> & tdof_marker,
694 Array<int> & rtdof_marker)
695{
696 // convert tdof_marker to dof_marker
697 rtdof_marker.SetSize(0);
698 Array<int> tdof_marker0;
699 Array<int> dof_marker0;
700 Array<int> dof_marker;
701 int * data = tdof_marker.GetData();
702 for (int i = 0; i<nblocks; i++)
703 {
704 tdof_marker0.MakeRef(&data[tdof_offsets[i]],tdof_offsets[i+1]-tdof_offsets[i]);
705 const SparseMatrix * R_ = fes[i]->GetRestrictionMatrix();
706 if (!R_)
707 {
708 dof_marker0.MakeRef(tdof_marker0);
709 }
710 else
711 {
712 dof_marker0.SetSize(fes[i]->GetVSize());
713 R_->BooleanMultTranspose(tdof_marker0, dof_marker0);
714 }
715 dof_marker.Append(dof_marker0);
716 }
717
718 int rdofs = rdof_edof.Size();
719 Array<int> rdof_marker(rdofs);
720
721 for (int i = 0; i < rdofs; i++)
722 {
723 rdof_marker[i] = dof_marker[rdof_edof[i]];
724 }
725
726 // convert rdof_marker to rtdof_marker
727 Array<int> rtdof_marker0;
728 Array<int> rdof_marker0;
729 int * rdata = rdof_marker.GetData();
730 int k=0;
731 for (int i = 0; i<nblocks; i++)
732 {
733 if (!tr_fes[i]) { continue; }
734 rdof_marker0.MakeRef(&rdata[rdof_offsets[k]],rdof_offsets[k+1]-rdof_offsets[k]);
735 const SparseMatrix *tr_R = tr_fes[i]->GetRestrictionMatrix();
736 if (!tr_R)
737 {
738 rtdof_marker0.MakeRef(rdof_marker0);
739 }
740 else
741 {
742 rtdof_marker0.SetSize(tr_fes[i]->GetTrueVSize());
743 tr_R->BooleanMult(rdof_marker0, rtdof_marker0);
744 }
745 rtdof_marker.Append(rtdof_marker0);
746 k++;
747 }
748}
749
750void BlockStaticCondensation::FillEssTdofLists(const Array<int> & ess_tdof_list)
751{
752 int j;
753 for (int i = 0; i<ess_tdof_list.Size(); i++)
754 {
755 int tdof = ess_tdof_list[i];
756 for (j = 0; j < rblocks; j++)
757 {
758 if (rtdof_offsets[j+1] > tdof) { break; }
759 }
760 ess_tdofs[j]->Append(tdof-rtdof_offsets[j]);
761 }
762}
763
765 &ess_tdof_list)
766{
767 Array<int> tdof_marker;
768 Array<int> rtdof_marker;
769 FiniteElementSpace::ListToMarker(ess_tdof_list,tdof_offsets.Last(),tdof_marker);
770 ConvertMarkerToReducedTrueDofs(tdof_marker, rtdof_marker);
771 FiniteElementSpace::MarkerToList(rtdof_marker,ess_rtdof_list);
772}
773
775 &ess_rtdof_list_,
777{
778 MFEM_VERIFY(!parallel, "EliminateReducedTrueDofs::Wrong Code path");
779
780 if (S_e == NULL)
781 {
782 Array<int> offsets;
783
784 offsets.MakeRef( (P) ? rtdof_offsets : rdof_offsets);
785
786 S_e = new BlockMatrix(offsets);
787 S_e->owns_blocks = 1;
788 for (int i = 0; i<S_e->NumRowBlocks(); i++)
789 {
790 int h = offsets[i+1] - offsets[i];
791 for (int j = 0; j<S_e->NumColBlocks(); j++)
792 {
793 int w = offsets[j+1] - offsets[j];
794 S_e->SetBlock(i,j,new SparseMatrix(h, w));
795 }
796 }
797 }
798 S->EliminateRowCols(ess_rtdof_list_,S_e,dpolicy);
799}
800
802 Vector &sc_sol) const
803{
804 MFEM_ASSERT(sol.Size() == dof_offsets.Last(), "'sol' has incorrect size");
805 const int nrdofs = rdof_offsets.Last();
806 Vector sol_r;
807 if (!R)
808 {
809 sc_sol.SetSize(nrdofs);
810 sol_r.SetDataAndSize(sc_sol.GetData(), sc_sol.Size());
811 }
812 else
813 {
814 sol_r.SetSize(nrdofs);
815 }
816 for (int i = 0; i < nrdofs; i++)
817 {
818 sol_r(i) = sol(rdof_edof[i]);
819 }
820 if (R)
821 {
822 // wrap vector into a block vector
823 BlockVector blsol_r(sol_r,rdof_offsets);
824 sc_sol.SetSize(R->Height());
825 R->Mult(blsol_r, sc_sol);
826 }
827}
828
830 Vector &B,
831 int copy_interior) const
832{
833 ReduceSolution(x, X);
834 if (!parallel)
835 {
836 if (!P)
837 {
838 S_e->AddMult(X,*y,-1.);
839 S->PartMult(ess_rtdof_list,X,*y);
840 B.MakeRef(*y, 0, y->Size());
841 }
842 else
843 {
844 B.SetSize(P->Width());
845 P->MultTranspose(*y, B);
846 S_e->AddMult(X,B,-1.);
847 S->PartMult(ess_rtdof_list,X,B);
848 }
849 }
850 else
851 {
852#ifdef MFEM_USE_MPI
853 B.SetSize(pP->Width());
854 pP->MultTranspose(*y,B);
855
856 Vector tmp(B.Size());
857 pS_e->Mult(X,tmp);
858 B-=tmp;
859 for (int j = 0; j<rblocks; j++)
860 {
861 if (!ess_tdofs[j]->Size()) { continue; }
862 HypreParMatrix *Ah = (HypreParMatrix *)(&pS->GetBlock(j,j));
863 Vector diag;
864 Ah->GetDiag(diag);
865 for (int i = 0; i < ess_tdofs[j]->Size(); i++)
866 {
867 int tdof = (*ess_tdofs[j])[i];
868 int gdof = tdof + rtdof_offsets[j];
869 B(gdof) = diag(tdof)*X(gdof);
870 }
871 }
872#endif
873 }
874 if (!copy_interior) { X.SetSubVectorComplement(ess_rtdof_list, 0.0); }
875}
876
877
879 Vector &sol) const
880{
881
882 const int nrdofs = rdof_offsets.Last();
883 const int nrtdofs = rtdof_offsets.Last();
884 MFEM_VERIFY(sc_sol.Size() == nrtdofs, "'sc_sol' has incorrect size");
885
886 Vector sol_r;
887 if (!parallel)
888 {
889 if (!P)
890 {
891 sol_r.SetDataAndSize(sc_sol.GetData(), sc_sol.Size());
892 }
893 else
894 {
895 sol_r.SetSize(nrdofs);
896 P->Mult(sc_sol, sol_r);
897 }
898 }
899 else
900 {
901#ifdef MFEM_USE_MPI
902 sol_r.SetSize(nrdofs);
903 pP->Mult(sc_sol, sol_r);
904#endif
905 }
906
907 if (rdof_offsets.Last() == dof_offsets.Last())
908 {
909 sol = sol_r;
910 return;
911 }
912 else
913 {
914 sol.SetSize(dof_offsets.Last());
915 }
916
917 Vector lsr; // element (local) sc solution vector
918 Vector lsi; // element (local) interior solution vector
919 const int NE = mesh->GetNE();
920
921 Array<int> trace_vdofs;
922 Array<int> vdofs;
923 Array<int> tr_offsets;
924 Vector lsol;
925 for (int iel = 0; iel < NE; iel++)
926 {
927 lsol.SetSize(lmat[iel]->Width() + lmat[iel]->Height());
928 GetReducedElementVDofs(iel, trace_vdofs);
929
930 lsr.SetSize(trace_vdofs.Size());
931 sol_r.GetSubVector(trace_vdofs, lsr);
932
933 // complete the interior dofs
934 lsi.SetSize(lmat[iel]->Height());
935 lmat[iel]->Mult(lsr,lsi);
936 lsi.Neg();
937 lsi+=*lvec[iel];
938
939 Array<int> tr_idx,int_idx,idx_offs;
940 GetReducedElementIndicesAndOffsets(iel,tr_idx, int_idx, idx_offs);
941 lsol.SetSubVector(tr_idx,lsr);
942
943 lsol.SetSubVector(int_idx,lsi);
944
945 GetElementVDofs(iel, vdofs);
946 sol.SetSubVector(vdofs,lsol);
947
948 }
949
950}
951
953{
954 delete S_e; S_e = nullptr;
955 delete S; S=nullptr;
956 delete y; y=nullptr;
957
958 if (P) { delete P; } P=nullptr;
959 if (R) { delete R; } R=nullptr;
960
961#ifdef MFEM_USE_MPI
962 if (parallel)
963 {
964 delete pS; pS=nullptr;
965 delete pS_e; pS_e=nullptr;
966 for (int i = 0; i<rblocks; i++)
967 {
968 delete ess_tdofs[i];
969 }
970 delete pP; pP=nullptr;
971 }
972#endif
973
974 for (int i=0; i<lmat.Size(); i++)
975 {
976 delete lmat[i]; lmat[i] = nullptr;
977 delete lvec[i]; lvec[i] = nullptr;
978 }
979}
980
981} // namespace mfem
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 * GetData()
Returns the data.
Definition array.hpp:140
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.
void FormSystemMatrix(Operator::DiagonalPolicy diag_policy)
void EliminateReducedTrueDofs(const Array< int > &ess_rtdof_list, Matrix::DiagonalPolicy dpolicy)
Eliminate the given reduced true dofs from the Schur complement matrix S.
void SetEssentialTrueDofs(const Array< int > &ess_tdof_list)
Determine and save internally essential reduced true dofs.
BlockStaticCondensation(Array< FiniteElementSpace * > &fes_)
void ParallelAssemble(BlockMatrix *m)
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 ComputeSolution(const Vector &sc_sol, Vector &sol) const
void ReduceSolution(const Vector &sol, Vector &sc_sol) const
void Finalize(int skip_zeros=0)
Finalize the construction of the Schur complement matrix.
void AssembleReducedSystem(int el, DenseMatrix &elmat, Vector &elvect)
A class to handle Vectors in a block fashion.
Vector & GetBlock(int i)
Get the i-th vector in the block.
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 GetDiag(Vector &diag) const
Get the local diagonal of the matrix.
Definition hypre.cpp:1607
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
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 SetDataAndSize(real_t *d, int s)
Set the Vector data and size.
Definition vector.hpp:191
void SetSubVector(const Array< int > &dofs, const real_t value)
Set the entries listed in dofs to the given value.
Definition vector.cpp:702
void 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
real_t * GetData() const
Return a pointer to the beginning of the Vector data.
Definition vector.hpp:243
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)
float real_t
Definition config.hpp:46