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