MFEM v4.10.0
Finite element discretization library
Loading...
Searching...
No Matches
transfer.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 "transfer.hpp"
13#include "bilinearform.hpp"
14#include "pbilinearform.hpp"
15#include "../general/forall.hpp"
16
17namespace mfem
18{
19
21 FiniteElementSpace &ran_fes_)
22 : dom_fes(dom_fes_), ran_fes(ran_fes_),
23 oper_type(Operator::ANY_TYPE),
24 fw_t_oper(), bw_t_oper(), use_ea(false), d_mt(Device::GetHostMemoryType())
25{
26#ifdef MFEM_USE_MPI
27 const bool par_dom = dynamic_cast<ParFiniteElementSpace*>(&dom_fes);
28 const bool par_ran = dynamic_cast<ParFiniteElementSpace*>(&ran_fes);
29 MFEM_VERIFY(par_dom == par_ran, "the domain and range FE spaces must both"
30 " be either serial or parallel");
31 parallel = par_dom;
32#endif
33}
34
36 FiniteElementSpace &fes_in, FiniteElementSpace &fes_out,
37 const Operator &oper, OperatorHandle &t_oper)
38{
39 if (t_oper.Ptr())
40 {
41 return *t_oper.Ptr();
42 }
43
44 if (!Parallel())
45 {
46 const SparseMatrix *in_cP = fes_in.GetConformingProlongation();
47 const SparseMatrix *out_cR = fes_out.GetConformingRestriction();
49 {
50 const SparseMatrix *mat = dynamic_cast<const SparseMatrix *>(&oper);
51 MFEM_VERIFY(mat != NULL, "Operator is not a SparseMatrix");
52 if (!out_cR)
53 {
54 t_oper.Reset(const_cast<SparseMatrix*>(mat), false);
55 }
56 else
57 {
58 t_oper.Reset(mfem::Mult(*out_cR, *mat));
59 }
60 if (in_cP)
61 {
62 t_oper.Reset(mfem::Mult(*t_oper.As<SparseMatrix>(), *in_cP));
63 }
64 }
65 else if (oper_type == Operator::ANY_TYPE)
66 {
67 const int RP_case = bool(out_cR) + 2*bool(in_cP);
68 switch (RP_case)
69 {
70 case 0:
71 t_oper.Reset(const_cast<Operator*>(&oper), false);
72 break;
73 case 1:
74 t_oper.Reset(
75 new ProductOperator(out_cR, &oper, false, false));
76 break;
77 case 2:
78 t_oper.Reset(
79 new ProductOperator(&oper, in_cP, false, false));
80 break;
81 case 3:
82 t_oper.Reset(
84 out_cR, &oper, in_cP, false, false, false));
85 break;
86 }
87 }
88 else
89 {
90 MFEM_ABORT("Operator::Type is not supported: " << oper_type);
91 }
92 }
93 else // Parallel() == true
94 {
95#ifdef MFEM_USE_MPI
97 {
98 const SparseMatrix *out_R = fes_out.GetRestrictionMatrix();
99 const ParFiniteElementSpace *pfes_in =
100 dynamic_cast<const ParFiniteElementSpace *>(&fes_in);
101 const ParFiniteElementSpace *pfes_out =
102 dynamic_cast<const ParFiniteElementSpace *>(&fes_out);
103 const SparseMatrix *sp_mat = dynamic_cast<const SparseMatrix *>(&oper);
104 const HypreParMatrix *hy_mat;
105 if (sp_mat)
106 {
107 SparseMatrix *RA = mfem::Mult(*out_R, *sp_mat);
108 t_oper.Reset(pfes_in->Dof_TrueDof_Matrix()->
109 LeftDiagMult(*RA, pfes_out->GetTrueDofOffsets()));
110 delete RA;
111 }
112 else if ((hy_mat = dynamic_cast<const HypreParMatrix *>(&oper)))
113 {
114 HypreParMatrix *RA =
115 hy_mat->LeftDiagMult(*out_R, pfes_out->GetTrueDofOffsets());
116 t_oper.Reset(mfem::ParMult(RA, pfes_in->Dof_TrueDof_Matrix()));
117 delete RA;
118 }
119 else
120 {
121 MFEM_ABORT("unknown Operator type");
122 }
123 }
124 else if (oper_type == Operator::ANY_TYPE)
125 {
126 const Operator *out_R = fes_out.GetRestrictionOperator();
127 t_oper.Reset(new TripleProductOperator(
128 out_R, &oper, fes_in.GetProlongationMatrix(),
129 false, false, false));
130 }
131 else
132 {
133 MFEM_ABORT("Operator::Type is not supported: " << oper_type);
134 }
135#endif
136 }
137
138 return *t_oper.Ptr();
139}
140
141
146
148 BilinearFormIntegrator *mass_integ_, bool own_mass_integ_)
149{
150 if (own_mass_integ) { delete mass_integ; }
151
152 mass_integ = mass_integ_;
153 own_mass_integ = own_mass_integ_;
154}
155
157{
158 if (F.Ptr())
159 {
160 return *F.Ptr();
161 }
162
163 // Construct F
165 {
167 }
169 {
170 Mesh::GeometryList elem_geoms(*ran_fes.GetMesh());
171
173 for (int i = 0; i < elem_geoms.Size(); i++)
174 {
176 localP[elem_geoms[i]]);
177 }
181 }
182 else
183 {
184 MFEM_ABORT("Operator::Type is not supported: " << oper_type);
185 }
186
187 return *F.Ptr();
188}
189
191{
192 if (B.Ptr())
193 {
194 return *B.Ptr();
195 }
196
197 // Construct B, if not set, define a suitable mass_integ
198 if (!mass_integ)
199 {
200 const FiniteElement *f_fe_0 = ran_fes.GetTypicalFE();
201 const int map_type = f_fe_0->GetMapType();
202 if (map_type == FiniteElement::VALUE ||
203 map_type == FiniteElement::INTEGRAL)
204 {
206 }
207 else if (map_type == FiniteElement::H_DIV ||
208 map_type == FiniteElement::H_CURL)
209 {
211 }
212 else
213 {
214 MFEM_ABORT("unknown type of FE space");
215 }
216 own_mass_integ = true;
217 }
219 {
222 }
223 else
224 {
225 MFEM_ABORT("Operator::Type is not supported: " << oper_type);
226 }
227
228 return *B.Ptr();
229}
230
231
233 const FiniteElementSpace &fes_ho_, const FiniteElementSpace &fes_lor_,
234 CoefficientWithOrder coeff_ho_, CoefficientWithOrder coeff_lor_,
235 MemoryType d_mt_)
236 : Operator(fes_lor_.GetVSize(), fes_ho_.GetVSize()),
237 fes_ho(fes_ho_), fes_lor(fes_lor_), coeff_ho(coeff_ho_),
238 coeff_lor(coeff_lor_), d_mt(d_mt_)
239{ }
240
242 int nel_ho, int nel_lor, const CoarseFineTransformations& cf_tr)
243{
244 // Construct the mapping from HO to LOR
245 // ho2lor.GetRow(iho) will give all the LOR elements contained in iho
246 ho2lor.MakeI(nel_ho);
247 for (int ilor = 0; ilor < nel_lor; ++ilor)
248 {
249 int iho = cf_tr.embeddings[ilor].parent;
250 ho2lor.AddAColumnInRow(iho);
251 }
252 ho2lor.MakeJ();
253 for (int ilor = 0; ilor < nel_lor; ++ilor)
254 {
255 int iho = cf_tr.embeddings[ilor].parent;
256 ho2lor.AddConnection(iho, ilor);
257 }
258 ho2lor.ShiftUpI();
259}
260
262 Geometry::Type geom, const FiniteElement& fe_ho,
263 const FiniteElement& fe_lor, ElementTransformation* tr_ho,
264 ElementTransformation* tr_lor,
266 DenseMatrix& M_mixed_el) const
267{
268 int order = fe_lor.GetOrder() + fe_ho.GetOrder() + tr_lor->OrderW() +
270 const IntegrationRule &ir = IntRules.Get(geom, order);
271 M_mixed_el = 0.0;
272 for (int i = 0; i < ir.GetNPoints(); i++)
273 {
274 const IntegrationPoint& ip_lor = ir.IntPoint(i);
275 IntegrationPoint ip_ho;
276 ip_tr.Transform(ip_lor, ip_ho);
277 Vector shape_lor(fe_lor.GetDof());
278 fe_lor.CalcShape(ip_lor, shape_lor);
279 Vector shape_ho(fe_ho.GetDof());
280 tr_ho->SetIntPoint(&ip_ho);
281 fe_ho.CalcPhysShape(*tr_ho, shape_ho);
282 tr_lor->SetIntPoint(&ip_lor);
283 // For now we use the geometry information from the LOR space, which means
284 // we won't be mass conservative if the mesh is curved
285 real_t w = ip_lor.weight;
286 if (fe_lor.GetMapType() == FiniteElement::VALUE)
287 {
288 w *= tr_lor->Weight();
289 }
290 if (coeff_ho)
291 {
292 w *= coeff_ho.coeff->Eval(*tr_ho, ip_ho);
293 }
294 shape_lor *= w;
295 AddMultVWt(shape_lor, shape_ho, M_mixed_el);
296 }
297}
298
300 Geometry::Type geom, const FiniteElement& fe_ho, const FiniteElement& fe_lor,
302 DenseMatrix& B_L, DenseMatrix& B_H) const
303{
304 for (int i = 0; i < ir.GetNPoints(); i++)
305 {
306 const IntegrationPoint& ip_lor = ir.IntPoint(i);
307 IntegrationPoint ip_ho;
308
309 // maps integration point ip_lor -> ip_ho
310 ip_tr.Transform(ip_lor, ip_ho);
311 Vector shape_lor(fe_lor.GetDof());
312 fe_lor.CalcShape(ip_lor, shape_lor);
313 Vector shape_ho(fe_ho.GetDof());
314 fe_ho.CalcShape(ip_ho, shape_ho);
315
316 for (int j=0; j<shape_lor.Size(); ++j)
317 {
318 B_L(i, j) = shape_lor(j);
319 }
320
321 for (int j=0; j<shape_ho.Size(); ++j)
322 {
323 B_H(i, j) = shape_ho(j);
324 }
325 }
326}
327
329 const FiniteElementSpace& fes_ho_ea,
330 const FiniteElementSpace& fes_lor_ea,
331 Vector &M_LH, MemoryType d_mt_)
332{
333 Mesh &mesh_ho = *fes_ho_ea.GetMesh();
334 Mesh &mesh_lor = *fes_lor_ea.GetMesh();
335
336 const int nel_ho = mesh_ho.GetNE();
337 const int nel_lor = mesh_lor.GetNE();
338
339 if (nel_ho == 0)
340 {
341 M_LH.SetSize(0);
342 return;
343 }
344
345 const CoarseFineTransformations& cf_tr = mesh_lor.GetRefinementTransforms();
346
347 int nref_max = 0;
349 mesh_ho.GetGeometries(mesh_ho.Dimension(), geoms);
350 for (int ig = 0; ig < geoms.Size(); ++ig)
351 {
352 Geometry::Type geom = geoms[ig];
353 nref_max = std::max(nref_max, cf_tr.point_matrices[geom].SizeK());
354 }
355
356 BuildHo2Lor(nel_ho, nel_lor, cf_tr);
357
359 IsoparametricTransformation &emb_tr = ip_tr.Transf;
360
361 // Gather basis functions (B_L, B_HO) and data at quadrature points
362 DenseTensor B_L, B_H, D;
363 {
364 // Assume all HO elements are LOR in the same way
365 const int iho = 0;
366 Array<int> lor_els;
367 ho2lor.GetRow(iho, lor_els);
368 const int nref = ho2lor.RowSize(iho);
369 MFEM_VERIFY(nel_ho*nref == nel_lor, "we expect nel_ho*nref == nel_lor");
370
371 Geometry::Type geom = mesh_ho.GetElementBaseGeometry(iho);
372
373 emb_tr.SetIdentityTransformation(geom);
374 const DenseTensor &pmats = cf_tr.point_matrices[geom];
375
376 const FiniteElement &fe_ho = *fes_ho_ea.GetFE(iho);
377 const FiniteElement &fe_lor = *fes_lor_ea.GetFE(lor_els[0]);
378
379 // Allocate space for DenseTensors
381 const int order = fe_lor.GetOrder() + fe_ho.GetOrder() + el_tr.OrderW()
382 + coeff_ho.order;
383 const IntegrationRule &ir_ea = IntRules.Get(geom, order);
384 const int qPts = ir_ea.GetNPoints();
385
386 // Containers for the basis functions sampled at quadrature points
387 B_L.SetSize(qPts, fe_lor.GetDof(), nref, d_mt);
388 B_H.SetSize(qPts, fe_ho.GetDof(), nref, d_mt);
389 D.SetSize(qPts, nref, nel_ho, d_mt);
390
391 const GeometricFactors *geo_facts =
393
394 Vector coeff_vec(qPts*nel_lor);
395 coeff_vec.UseDevice(true);
396
397 const int dim = mesh_ho.Dimension();
398 const int nq1d = (int)floor(pow(ir_ea.Size(), 1.0/dim) + 0.5);
399 const int nref_1d = (int)floor(pow(nref, 1.0/dim) + 0.5);
400
401 if (!coeff_ho)
402 {
403 coeff_vec = 1.0;
404 }
405 else if (UsesTensorBasis(fes_ho) &&
406 nq1d*nref_1d <= DeviceDofQuadLimits::Get().MAX_Q1D)
407 {
408 // Fast coefficient evaluation for tensor-product case. We create a
409 // "composite" quadrature rule in the high-order element that is the
410 // union of the quadrature rules within each of the low-order-refined
411 // subelements.
412 //
413 // NOTE: if the integration rule order is high and there are many LOR
414 // subelements, this can create a very big quadrature rule. That is
415 // why we need to check that we do not exceed MAX_Q1D. If we do, then
416 // we fall back on the slower "legacy" evaluation.
417
418 // Construct the composite rule as a tensor-product of the 1D LOR rule.
419 IntegrationRule ir_ho = [&]()
420 {
421 IntegrationRule ir_ho_1d(nq1d * nref_1d);
422 for (int iref = 0; iref < nref_1d; ++iref)
423 {
424 const real_t a = pmats(cf_tr.embeddings[iref].matrix)(0,0);
425 const real_t b = pmats(cf_tr.embeddings[iref].matrix)(0,1);
426 for (int iq = 0; iq < nq1d; ++iq)
427 {
428 ir_ho_1d[iq + iref*nq1d].x = a + ir_ea[iq].x*(b - a);
429 }
430 }
431 if (dim == 1) { return ir_ho_1d; }
432 else if (dim == 2) { return IntegrationRule(ir_ho_1d, ir_ho_1d); }
433 else { return IntegrationRule(ir_ho_1d, ir_ho_1d, ir_ho_1d); }
434 }();
435
436 // Project the high-order coefficient on the high-order composite rule.
437 QuadratureSpace qs(mesh_ho, ir_ho);
438 CoefficientVector coeff_vec_ho(*coeff_ho.coeff, qs);
439
440 // Permute the coefficient values to the expected LOR ordering.
441 const int nq_ho = ir_ho.Size();
442 const auto d_Q_ho = Reshape(coeff_vec_ho.Read(), nq_ho, nel_ho);
443 const auto d_Q = Reshape(coeff_vec.Write(), qPts, nel_lor);
444
445 mfem::forall(nq_ho * nel_ho, [=] MFEM_HOST_DEVICE (int ii)
446 {
447 const int e_ho = ii / nq_ho;
448 const int iq_ho = ii % nq_ho;
449
450 int iq_tensor = iq_ho;
451 int iq_lor = 0;
452 int iref = 0;
453 int iq_stride = 1;
454 int iref_stride = 1;
455 const int nq_ho_1d = nq1d*nref_1d;
456 for (int d = 0; d < dim; ++d)
457 {
458 const int iq_ho_1d = iq_tensor % nq_ho_1d;
459 iq_tensor /= nq_ho_1d;
460
461 iq_lor += (iq_ho_1d % nq1d)*iq_stride;
462 iref += (iq_ho_1d / nq1d)*iref_stride;
463 iq_stride *= nq1d;
464 iref_stride *= nref_1d;
465 }
466 const int e_lor = iref + e_ho*nref;
467
468 d_Q(iq_lor, e_lor) = d_Q_ho(iq_ho, e_ho);
469 });
470 }
471 else
472 {
473 // Legacy/fallback coefficient evaluation for non-tensor-product cases
474 // or when the number of quadrature points is too large for the device
475 // kernels.
476 IntegrationPoint ip_ho;
477 for (int e_ho = 0; e_ho < nel_ho; ++e_ho)
478 {
479 ElementTransformation &ho_tr = *mesh_ho.GetElementTransformation(e_ho);
480 for (int iref = 0; iref < nref; ++iref)
481 {
482 const int e_lor = iref + e_ho*nref;
483 emb_tr.SetPointMat(pmats(cf_tr.embeddings[e_lor].matrix));
484
485 for (int iq = 0; iq < qPts; ++iq)
486 {
487 const IntegrationPoint &ip_lor = ir_ea[iq];
488 ip_tr.Transform(ip_lor, ip_ho);
489 ho_tr.SetIntPoint(&ip_ho);
490 coeff_vec[iq + e_lor*qPts] = coeff_ho.coeff->Eval(ho_tr, ip_ho);
491 }
492 }
493 }
494 }
495
496 // Setup data at quadrature points
497 const auto W = Reshape(ir_ea.GetWeights().Read(), qPts);
498 const auto J = Reshape(geo_facts->detJ.Read(), qPts, nel_lor);
499 const auto d_D = Reshape(D.Write(), qPts, nref, nel_ho);
500 const auto d_Q = Reshape(coeff_vec.Read(), qPts, nel_lor);
501
502 mfem::forall(qPts * nref * nel_ho, [=] MFEM_HOST_DEVICE (int tid)
503 {
504 const int q = tid % qPts;
505 const int iref = (tid / qPts) % nref;
506 const int iho = (tid / (qPts * nref)) % nel_ho;
507
508 const int lo_el_id = iref + nref*iho;
509 const real_t detJ = J(q, lo_el_id);
510
511 d_D(q, iref, iho) = W(q) * d_Q(q, lo_el_id) * detJ;
512 });
513
514 // Collect the basis functions
515 for (int iref = 0; iref < nref; ++iref)
516 {
517 int ilor = lor_els[iref];
518 // Now assemble the block-row of the mixed mass matrix associated
519 // with integrating HO functions against LOR functions on the LOR
520 // sub-element.
521
522 // Create the transformation that embeds the fine low-order element
523 // within the coarse high-order element in reference space
524 emb_tr.SetPointMat(pmats(cf_tr.embeddings[ilor].matrix));
525
526 DenseMatrix &b_lo = B_L(ilor);
527 DenseMatrix &b_ho = B_H(ilor);
528
529 ElemMixedEvaluation(geom, fe_ho, fe_lor, ip_tr, ir_ea, b_lo, b_ho);
530 } // loop over subcells of ho element
531 // end of quadrature point setup
532 } // completed setup of basis function and quadrature point
533
534 // Assemble mixed mass matrix
535 int iho = 0;
536 Array<int> lor_els;
537 ho2lor.GetRow(iho, lor_els);
538 int nref = ho2lor.RowSize(iho);
539
540 const FiniteElement &fe_ho = *fes_ho_ea.GetFE(iho);
541 const FiniteElement &fe_lor = *fes_lor_ea.GetFE(lor_els[0]);
542 const int ndof_ho = fe_ho.GetDof();
543 const int ndof_lor = fe_lor.GetDof();
544
545 const int qPts = D.SizeI();
546
547 M_LH.SetSize(ndof_lor*ndof_ho*nref*nel_ho, d_mt);
548
549 // Rows x columns
550 // Recall MFEM is column major
551 // rows x columns is inverted - matrix is ndof_lor x ndof_ho
552 auto v_M_LH = Reshape(M_LH.Write(), ndof_lor, ndof_ho, nref,
553 nel_ho);
554
555 const int fe_ho_ndof = fe_ho.GetDof();
556 const int fe_lor_ndof = fe_lor.GetDof();
557
558 auto d_B_L = Reshape(B_L.Read(), qPts, fe_lor_ndof, nref);
559 auto d_B_H = Reshape(B_H.Read(), qPts, fe_ho_ndof, nref);
560 auto d_D = Reshape(D.Read(), qPts, nref, nel_ho);
561
562 mfem::forall(fe_ho_ndof*nref*nel_ho, [=] MFEM_HOST_DEVICE (int idx)
563 {
564 const int bh = idx % fe_ho_ndof;
565 const int iref = (idx / fe_ho_ndof) % nref;
566 const int iho = idx / fe_ho_ndof / nref;
567 // (B_lo_dofs x Q) x (Q x B_ho_dofs)
568 for (int bl = 0; bl < fe_lor_ndof; ++bl)
569 {
570 real_t dot = 0.0;
571 for (int qi=0; qi<qPts; ++qi)
572 {
573 dot += d_B_L(qi, bl, iref) * d_D(qi, iref, iho) * d_B_H(qi, bh, iref);
574 }
575 // column major storage
576 v_M_LH(bl, bh, iref, iho) = dot;
577 }
578 });
579}
580
582(const FiniteElementSpace &fes_ho_, const FiniteElementSpace &fes_lor_,
583 CoefficientWithOrder coeff_ho_, CoefficientWithOrder coeff_lor_,
584 const bool use_ea_, MemoryType d_mt_)
585 : L2Projection(fes_ho_, fes_lor_, coeff_ho_, coeff_lor_, d_mt_), use_ea(use_ea_)
586{
587 if (use_ea)
588 {
590 return;
591 }
592
593 Mesh *mesh_ho = fes_ho.GetMesh();
594 Mesh *mesh_lor = fes_lor.GetMesh();
595 int nel_ho = mesh_ho->GetNE();
596 int nel_lor = mesh_lor->GetNE();
597
598 // The prolongation operation is only well-defined when the LOR space has at
599 // least as many DOFs as the high-order space.
600 const bool build_P = fes_lor.GetTrueVSize() >= fes_ho.GetTrueVSize();
601
602 // If the local mesh is empty, skip all computations
603 if (nel_ho == 0) { return; }
604
605 const CoarseFineTransformations &cf_tr = mesh_lor->GetRefinementTransforms();
606
607 int nref_max = 0;
609 mesh_ho->GetGeometries(mesh_ho->Dimension(), geoms);
610 for (int ig = 0; ig < geoms.Size(); ++ig)
611 {
612 Geometry::Type geom = geoms[ig];
613 nref_max = std::max(nref_max, cf_tr.point_matrices[geom].SizeK());
614 }
615
616 BuildHo2Lor(nel_ho, nel_lor, cf_tr);
617
618 offsets.SetSize(nel_ho+1);
619 offsets[0] = 0;
620 for (int iho = 0; iho < nel_ho; ++iho)
621 {
622 int nref = ho2lor.RowSize(iho);
623 const FiniteElement &fe_ho = *fes_ho.GetFE(iho);
624 const FiniteElement &fe_lor = *fes_lor.GetFE(ho2lor.GetRow(iho)[0]);
625 offsets[iho+1] = offsets[iho] + fe_ho.GetDof()*fe_lor.GetDof()*nref;
626 }
627 // R will contain the restriction (L^2 projection operator) defined on each
628 // coarse HO element (and corresponding patch of LOR elements)
629 R.SetSize(offsets[nel_ho]);
630 if (build_P)
631 {
632 // P will contain the corresponding prolongation operator
633 P.SetSize(offsets[nel_ho]);
634 }
635
637 IsoparametricTransformation &emb_tr = ip_tr.Transf;
638
639 for (int iho = 0; iho < nel_ho; ++iho)
640 {
641 Array<int> lor_els;
642 ho2lor.GetRow(iho, lor_els);
643 int nref = ho2lor.RowSize(iho);
644
645 Geometry::Type geom = mesh_ho->GetElementBaseGeometry(iho);
646 const FiniteElement &fe_ho = *fes_ho.GetFE(iho);
647 const FiniteElement &fe_lor = *fes_lor.GetFE(lor_els[0]);
648 int ndof_ho = fe_ho.GetDof();
649 int ndof_lor = fe_lor.GetDof();
650
652
653 emb_tr.SetIdentityTransformation(geom);
654 const DenseTensor &pmats = cf_tr.point_matrices[geom];
655
656 DenseMatrix R_iho(&R[offsets[iho]], ndof_lor*nref, ndof_ho);
657
658 DenseMatrix Minv_lor(ndof_lor*nref, ndof_lor*nref);
659 DenseMatrix M_mixed(ndof_lor*nref, ndof_ho);
660
661 MassIntegrator mi = [&]()
662 {
664 }();
665
666 DenseMatrix M_lor_el(ndof_lor, ndof_lor);
667 DenseMatrixInverse Minv_lor_el(&M_lor_el);
668 DenseMatrix M_lor(ndof_lor*nref, ndof_lor*nref);
669 DenseMatrix M_mixed_el(ndof_lor, ndof_ho);
670
671 Minv_lor = 0.0;
672 M_lor = 0.0;
673
674 DenseMatrix RtMlor(ndof_ho, ndof_lor*nref);
675 DenseMatrix RtMlorR(ndof_ho, ndof_ho);
676 DenseMatrixInverse RtMlorR_inv(&RtMlorR);
677
678 for (int iref = 0; iref < nref; ++iref)
679 {
680 // Assemble the low-order refined mass matrix and invert locally
681 int ilor = lor_els[iref];
683
684 const int order = 2*fe_lor.GetOrder() + tr_lor->OrderW() + coeff_lor.order;
685 mi.SetIntegrationRule(IntRules.Get(geom, order));
686
687 mi.AssembleElementMatrix(fe_lor, *tr_lor, M_lor_el);
688 M_lor.CopyMN(M_lor_el, iref*ndof_lor, iref*ndof_lor);
689 Minv_lor_el.Factor();
690 Minv_lor_el.GetInverseMatrix(M_lor_el);
691 // Insert into the diagonal of the patch LOR mass matrix
692 Minv_lor.CopyMN(M_lor_el, iref*ndof_lor, iref*ndof_lor);
693
694 // Now assemble the block-row of the mixed mass matrix associated
695 // with integrating HO functions against LOR functions on the LOR
696 // sub-element.
697
698 // Create the transformation that embeds the fine low-order element
699 // within the coarse high-order element in reference space
700 emb_tr.SetPointMat(pmats(cf_tr.embeddings[ilor].matrix));
701
702 ElemMixedMass(geom, fe_ho, fe_lor, tr_ho, tr_lor, ip_tr, M_mixed_el);
703
704 M_mixed.CopyMN(M_mixed_el, iref*ndof_lor, 0);
705 }
706 mfem::Mult(Minv_lor, M_mixed, R_iho);
707
708 if (build_P)
709 {
710 DenseMatrix P_iho(&P[offsets[iho]], ndof_ho, ndof_lor*nref);
711
712 mfem::MultAtB(R_iho, M_lor, RtMlor);
713 mfem::Mult(RtMlor, R_iho, RtMlorR);
714 RtMlorR_inv.Factor();
715 RtMlorR_inv.Mult(RtMlor, P_iho);
716 }
717 }
718
719}
720
721
723{
724 Mesh *mesh_ho = fes_ho.GetMesh();
725 Mesh *mesh_lor = fes_lor.GetMesh();
726 int nel_ho = mesh_ho->GetNE();
727 int nel_lor = mesh_lor->GetNE();
728
729 // The prolongation operation is only well-defined when the LOR space has at
730 // least as many DOFs as the high-order space.
731 const bool build_P = fes_lor.GetTrueVSize() >= fes_ho.GetTrueVSize();
732
733 // If the local mesh is empty, skip all computations
734 if (nel_ho == 0) { return; }
735
736 const CoarseFineTransformations &cf_tr = mesh_lor->GetRefinementTransforms();
737
738 int nref_max = 0;
740 mesh_ho->GetGeometries(mesh_ho->Dimension(), geoms);
741 for (int ig = 0; ig < geoms.Size(); ++ig)
742 {
743 Geometry::Type geom = geoms[ig];
744 nref_max = std::max(nref_max, cf_tr.point_matrices[geom].SizeK());
745 }
746
747 BuildHo2Lor(nel_ho, nel_lor, cf_tr);
748
749 offsets.SetSize(nel_ho+1);
750 offsets[0] = 0;
751 for (int iho = 0; iho < nel_ho; ++iho)
752 {
753 int nref = ho2lor.RowSize(iho);
754 const FiniteElement &fe_ho = *fes_ho.GetFE(iho);
755 const FiniteElement &fe_lor = *fes_lor.GetFE(ho2lor.GetRow(iho)[0]);
756 offsets[iho+1] = offsets[iho] + fe_ho.GetDof()*fe_lor.GetDof()*nref;
757 }
758
759 // R will contain the restriction (L^2 projection operator) defined on each
760 // coarse HO element (and corresponding patch of LOR elements)
761 R.SetSize(offsets[nel_ho]);
762
763 if (build_P)
764 {
765 // P will contain the corresponding prolongation operator
766 P.SetSize(offsets[nel_ho]);
767 }
768
769 // Assemble mixed mass matrix
770 Vector M_mixed_all;
771 MixedMassEA(fes_ho, fes_lor, M_mixed_all, d_mt);
772
773
774 // R = inv(M_L) * M_mixed
775 // Need to compute M_L
776 // Note: Using user-inputted M_LH IntegrationRule ir
777 // (higher order than needed) in order to re-use coeff
778 MassIntegrator mi = [&]()
779 {
781 }();
782
783 const int order = 2*fes_lor.GetMaxElementOrder()
787 IntRules.Get(mesh_lor->GetTypicalElementGeometry(), order));
788
789 Vector M_ea_lor;
790 const int ndof_lor = fes_lor.GetTypicalFE()->GetDof();
791 const int ndof_ho = fes_ho.GetTypicalFE()->GetDof();
792 const int nref = ho2lor.RowSize(0);
793 M_ea_lor.SetSize(ndof_lor*ndof_lor*nel_lor, d_mt);
794
795 const bool add = false;
796 mi.AssembleEA(fes_lor, M_ea_lor, add);
797
798 DenseTensor Minv_ear_lor;
799 Minv_ear_lor.SetSize(ndof_lor, ndof_lor, nel_lor, d_mt);
800 Minv_ear_lor.GetMemory().CopyFrom(M_ea_lor.GetMemory(), M_ea_lor.Size());
801
802 BatchedLinAlg::Invert(Minv_ear_lor);
803 {
804 // Recall mfem is column major
805 // ndof_lor x ndof_ho
806 auto v_M_mixed_all = Reshape(M_mixed_all.Read(), ndof_lor, ndof_ho, nref,
807 nel_ho);
808
809 // matrix is symmetric
810 auto v_Minv_ear_lor = Reshape(Minv_ear_lor.Read(), ndof_lor, ndof_lor,
811 nel_lor);
812
813 // ndof_lor x ndof_ho
814 auto v_R = Reshape(R.Write(), ndof_lor, nref, ndof_ho, nel_ho);
815
816 MFEM_VERIFY(nel_lor==nel_ho*nref, "nel_lor != nel_ho*nref");
817
818 // (ndofs_lor x ndofs_lor) x (ndofs_lor x ndof_ho)
819 mfem::forall(ndof_lor * nref * ndof_ho * nel_ho, [=] MFEM_HOST_DEVICE (int tid)
820 {
821
822 const int i = tid % ndof_lor;
823 const int iref = (tid / ndof_lor) % nref;
824 const int j = (tid / (ndof_lor * nref) ) % ndof_ho;
825 const int iho = (tid / (ndof_lor * nref * ndof_ho)) % nel_ho;
826
827 const int lor_idx = iref + iho * nref;
828
829 //matrices are stored in the transpose position
830 real_t dot = 0.0;
831 for (int k=0; k<ndof_lor; ++k)
832 {
833 dot += v_Minv_ear_lor(i, k, lor_idx) * v_M_mixed_all(k, j, iref, iho);
834 }
835 v_R(i, iref, j, iho) = dot;
836
837 });
838 }
839
840 if (build_P)
841 {
842 // P = inv(R^T M_L R) * R^T M_L
843
844 // M_lor is size of ndof_lor x ndof_lor
845 // R is size of (ndof_lor x nref x ndof_ho)
846 auto v_M_ea_lor = Reshape(M_ea_lor.Read(), ndof_lor, ndof_lor, nel_lor);
847 auto v_R = Reshape(R.Read(), ndof_lor, nref, ndof_ho, nel_ho);
848 // R^T M_LO is of size nref x ndof_lor
849
850 // Compute R^T M_L
851 Vector RtM_L(ndof_ho*nref*ndof_lor*nel_ho, d_mt);
852 auto v_RtM_L = Reshape(RtM_L.Write(), ndof_ho, ndof_lor, nref, nel_ho);
853
854 mfem::forall(ndof_lor * nref * ndof_ho * nel_ho, [=] MFEM_HOST_DEVICE (int tid)
855 {
856
857 const int jlo = tid % ndof_lor;
858 const int iref = (tid / ndof_lor) % nref;
859 const int iho = (tid / (ndof_lor * nref)) % ndof_ho;
860 const int e = (tid / (ndof_lor * nref * ndof_ho)) % nel_ho;
861
862 const int lor_idx = iref + e * nref;
863
864 real_t dot = 0.0;
865 for (int t=0; t<ndof_lor; ++t)
866 {
867 dot += v_R(t, iref, iho, e) * v_M_ea_lor(t, jlo, lor_idx);
868 }
869
870 v_RtM_L(iho, jlo, iref, e) = dot;
871
872 });
873
874 // Resulting matrix should be: ndof_ho x ndof_ho
875 // R^T M_L x R
876 DenseTensor RtM_L_dt;
877 RtM_L_dt.NewMemoryAndSize(RtM_L.GetMemory(), ndof_ho, ndof_lor*nref,
878 nel_ho, false);
879 Vector R_vec;
880 R_vec.NewMemoryAndSize(R.GetMemory(), R.Size(), false);
881 Vector RtM_LR(ndof_ho * ndof_ho * nel_ho, d_mt);
882 BatchedLinAlg::Mult(RtM_L_dt, R_vec, RtM_LR);
883 // Ensure that changes to the alias R_vec are propagated to the base, R
884 R_vec.GetMemory().SyncAlias(R.GetMemory(), P.Size());
885
886 // Compute the inverse of InvRtM_LR
887 DenseTensor InvRtM_LR;
888 InvRtM_LR.NewMemoryAndSize(RtM_LR.GetMemory(), ndof_ho, ndof_ho, nel_ho, false);
889 BatchedLinAlg::Invert(InvRtM_LR);
890
891 // Form P
892 // P should be of dimension (ndof_ho x ndof_ho) x (ndof_ho x nref*ndof_lor)
893 // P ndof_ho x nref*ndof_lor
894 Vector P_vec;
895 P_vec.NewMemoryAndSize(P.GetMemory(), P.Size(), false);
896 BatchedLinAlg::Mult(InvRtM_LR, RtM_L, P_vec);
897 // Ensure that changes to the alias P_vec are propagated to the base, P
898 P_vec.GetMemory().SyncAlias(P.GetMemory(), P.Size());
899 }
900}
901
903 const Vector &x, Vector &y) const
904{
905
906 if (use_ea)
907 {
908 return EAMult(x,y);
909 }
910
911
912 int vdim = fes_ho.GetVDim();
913 Array<int> vdofs;
914 DenseMatrix xel_mat, yel_mat;
915 for (int iho = 0; iho < fes_ho.GetNE(); ++iho)
916 {
917 int nref = ho2lor.RowSize(iho);
918 int ndof_ho = fes_ho.GetFE(iho)->GetDof();
919 int ndof_lor = fes_lor.GetFE(ho2lor.GetRow(iho)[0])->GetDof();
920 xel_mat.SetSize(ndof_ho, vdim);
921 yel_mat.SetSize(ndof_lor*nref, vdim);
922 DenseMatrix R_iho(&R[offsets[iho]], ndof_lor*nref, ndof_ho);
923
924 fes_ho.GetElementVDofs(iho, vdofs);
925 x.GetSubVector(vdofs, xel_mat.GetData());
926 mfem::Mult(R_iho, xel_mat, yel_mat);
927 // Place result correctly into the low-order vector
928 for (int iref = 0; iref < nref; ++iref)
929 {
930 int ilor = ho2lor.GetRow(iho)[iref];
931 for (int vd=0; vd<vdim; ++vd)
932 {
933 fes_lor.GetElementDofs(ilor, vdofs);
934 fes_lor.DofsToVDofs(vd, vdofs);
935 y.SetSubVector(vdofs, &yel_mat(iref*ndof_lor,vd));
936 }
937 }
938 }
939}
940
942 const Vector &x, Vector &y) const
943{
944 const int nel_ho = fes_ho.GetMesh()->GetNE();
945
946 if (nel_ho == 0)
947 {
948 return;
949 }
950
951 const int iho = 0;
952 const int nref = ho2lor.RowSize(iho);
953 const int ndof_ho = fes_ho.GetFE(iho)->GetDof();
954 const int ndof_lor = fes_lor.GetFE(ho2lor.GetRow(iho)[0])->GetDof();
955
956 DenseTensor R_dt;
957 R_dt.NewMemoryAndSize(R.GetMemory(), ndof_lor*nref, ndof_ho, nel_ho, false);
958 BatchedLinAlg::Mult(R_dt, x, y);
959}
960
962 const Vector &x, Vector &y) const
963{
964
965 if (use_ea)
966 {
967 return EAMultTranspose(x,y);
968 }
969
970 int vdim = fes_ho.GetVDim();
971 Array<int> vdofs;
972 DenseMatrix xel_mat, yel_mat;
973 y = 0.0;
974 for (int iho = 0; iho < fes_ho.GetNE(); ++iho)
975 {
976 int nref = ho2lor.RowSize(iho);
977 int ndof_ho = fes_ho.GetFE(iho)->GetDof();
978 int ndof_lor = fes_lor.GetFE(ho2lor.GetRow(iho)[0])->GetDof();
979 xel_mat.SetSize(ndof_lor*nref, vdim);
980 yel_mat.SetSize(ndof_ho, vdim);
981 DenseMatrix R_iho(&R[offsets[iho]], ndof_lor*nref, ndof_ho);
982
983 // Extract the LOR DOFs
984 for (int iref=0; iref<nref; ++iref)
985 {
986 int ilor = ho2lor.GetRow(iho)[iref];
987 for (int vd=0; vd<vdim; ++vd)
988 {
989 fes_lor.GetElementDofs(ilor, vdofs);
990 fes_lor.DofsToVDofs(vd, vdofs);
991 x.GetSubVector(vdofs, &xel_mat(iref*ndof_lor, vd));
992 }
993 }
994 // Multiply locally by the transpose
995 mfem::MultAtB(R_iho, xel_mat, yel_mat);
996 // Place the result in the HO vector
997 fes_ho.GetElementVDofs(iho, vdofs);
998 y.AddElementVector(vdofs, yel_mat.GetData());
999 }
1000
1001}
1002
1004 const Vector &x, Vector &y) const
1005{
1006 const int nel_ho = fes_ho.GetMesh()->GetNE();
1007
1008 if (nel_ho == 0)
1009 {
1010 return;
1011 }
1012
1013 const int iho = 0;
1014 const int nref = ho2lor.RowSize(iho);
1015 const int ndof_ho = fes_ho.GetFE(iho)->GetDof();
1016 const int ndof_lor = fes_lor.GetFE(ho2lor.GetRow(iho)[0])->GetDof();
1017
1018 DenseTensor R_dt;
1019 R_dt.NewMemoryAndSize(R.GetMemory(), ndof_lor*nref, ndof_ho, nel_ho, false);
1020 BatchedLinAlg::MultTranspose(R_dt, x, y);
1021}
1022
1024 const Vector &x, Vector &y) const
1025{
1026 if (fes_ho.GetNE() == 0) { return; }
1027
1028 if (use_ea)
1029 {
1030 return EAProlongate(x,y);
1031 }
1032
1033 MFEM_VERIFY(P.Size() > 0, "Prolongation not supported for these spaces.")
1034 int vdim = fes_ho.GetVDim();
1035 Array<int> vdofs;
1036 DenseMatrix xel_mat,yel_mat;
1037 y = 0.0;
1038 for (int iho = 0; iho < fes_ho.GetNE(); ++iho)
1039 {
1040 int nref = ho2lor.RowSize(iho);
1041 int ndof_ho = fes_ho.GetFE(iho)->GetDof();
1042 int ndof_lor = fes_lor.GetFE(ho2lor.GetRow(iho)[0])->GetDof();
1043 xel_mat.SetSize(ndof_lor*nref, vdim);
1044 yel_mat.SetSize(ndof_ho, vdim);
1045 DenseMatrix P_iho(&P[offsets[iho]], ndof_ho, ndof_lor*nref);
1046
1047 // Extract the LOR DOFs
1048 for (int iref = 0; iref < nref; ++iref)
1049 {
1050 int ilor = ho2lor.GetRow(iho)[iref];
1051 for (int vd = 0; vd < vdim; ++vd)
1052 {
1053 fes_lor.GetElementDofs(ilor, vdofs);
1054 fes_lor.DofsToVDofs(vd, vdofs);
1055 x.GetSubVector(vdofs, &xel_mat(iref*ndof_lor, vd));
1056 }
1057 }
1058 // Locally prolongate
1059 mfem::Mult(P_iho, xel_mat, yel_mat);
1060 // Place the result in the HO vector
1061 fes_ho.GetElementVDofs(iho, vdofs);
1062 y.AddElementVector(vdofs, yel_mat.GetData());
1063 }
1064
1065}
1066
1068 const Vector &x, Vector &y) const
1069{
1070 const int iho = 0;
1071 const int nref = ho2lor.RowSize(iho);
1072 const int ndof_ho = fes_ho.GetFE(iho)->GetDof();
1073 const int ndof_lor = fes_lor.GetFE(ho2lor.GetRow(iho)[0])->GetDof();
1074 const int nel_ho = fes_ho.GetMesh()->GetNE();
1075
1076 DenseTensor P_dt;
1077 P_dt.NewMemoryAndSize(P.GetMemory(), ndof_ho, ndof_lor * nref, nel_ho, false);
1078 BatchedLinAlg::Mult(P_dt, x, y);
1079}
1080
1082 const Vector &x, Vector &y) const
1083{
1084 if (fes_ho.GetNE() == 0) { return; }
1085
1086 if (use_ea)
1087 {
1088 return EAProlongateTranspose(x,y);
1089 }
1090
1091 MFEM_VERIFY(P.Size() > 0, "Prolongation not supported for these spaces.")
1092 int vdim = fes_ho.GetVDim();
1093 Array<int> vdofs;
1094 DenseMatrix xel_mat,yel_mat;
1095 for (int iho = 0; iho < fes_ho.GetNE(); ++iho)
1096 {
1097 int nref = ho2lor.RowSize(iho);
1098 int ndof_ho = fes_ho.GetFE(iho)->GetDof();
1099 int ndof_lor = fes_lor.GetFE(ho2lor.GetRow(iho)[0])->GetDof();
1100 xel_mat.SetSize(ndof_ho, vdim);
1101 yel_mat.SetSize(ndof_lor*nref, vdim);
1102 DenseMatrix P_iho(&P[offsets[iho]], ndof_ho, ndof_lor*nref);
1103
1104 fes_ho.GetElementVDofs(iho, vdofs);
1105 x.GetSubVector(vdofs, xel_mat.GetData());
1106 mfem::MultAtB(P_iho, xel_mat, yel_mat);
1107
1108 // Place result correctly into the low-order vector
1109 for (int iref = 0; iref < nref; ++iref)
1110 {
1111 int ilor = ho2lor.GetRow(iho)[iref];
1112 for (int vd=0; vd<vdim; ++vd)
1113 {
1114 fes_lor.GetElementDofs(ilor, vdofs);
1115 fes_lor.DofsToVDofs(vd, vdofs);
1116 y.SetSubVector(vdofs, &yel_mat(iref*ndof_lor,vd));
1117 }
1118 }
1119 }
1120
1121}
1122
1124 const Vector &x, Vector &y) const
1125{
1126 const int iho = 0;
1127 const int nref = ho2lor.RowSize(iho);
1128 const int ndof_ho = fes_ho.GetFE(iho)->GetDof();
1129 const int ndof_lor = fes_lor.GetFE(ho2lor.GetRow(iho)[0])->GetDof();
1130 const int nel_ho = fes_ho.GetMesh()->GetNE();
1131
1132 DenseTensor P_dt;
1133 P_dt.NewMemoryAndSize(P.GetMemory(), ndof_ho, ndof_lor * nref, nel_ho, false);
1134 BatchedLinAlg::MultTranspose(P_dt, x, y);
1135}
1136
1138 const FiniteElementSpace& fes_ho_, const FiniteElementSpace& fes_lor_,
1139 CoefficientWithOrder coeff_ho_, CoefficientWithOrder coeff_lor_,
1140 const bool use_ea_, MemoryType d_mt_)
1141 : L2Projection(fes_ho_, fes_lor_, coeff_ho_, coeff_lor_, d_mt_),
1142 use_ea(use_ea_)
1143{
1144
1145 // need scalar to keep dimensions matching (operators are built to apply
1146 // individually on each vdim)
1147 // needed in both matrix and element based versions
1149 fes_ho.FEColl(), 1));
1151 fes_lor.FEColl(), 1));
1152
1153 if (use_ea)
1154 {
1156 return;
1157 }
1158
1159 std::unique_ptr<SparseMatrix> R_mat, M_LH_mat;
1160
1161 std::tie(R_mat, M_LH_mat) = ComputeSparseRAndM_LH();
1162
1163 const SparseMatrix *P_ho = fes_ho_scalar->GetConformingProlongation();
1164 const SparseMatrix *P_lor = fes_lor_scalar->GetConformingProlongation();
1165
1166 if (P_ho || P_lor)
1167 {
1168 if (P_ho && P_lor)
1169 {
1170 R_mat.reset(RAP(*P_lor, *R_mat, *P_ho));
1171 M_LH_mat.reset(RAP(*P_lor, *M_LH_mat, *P_ho));
1172 }
1173 else if (P_ho)
1174 {
1175 R_mat.reset(mfem::Mult(*R_mat, *P_ho));
1176 M_LH_mat.reset(mfem::Mult(*M_LH_mat, *P_ho));
1177 }
1178 else // P_lor != nullptr
1179 {
1180 R_mat.reset(mfem::Mult(*P_lor, *R_mat));
1181 M_LH_mat.reset(mfem::Mult(*P_lor, *M_LH_mat));
1182 }
1183 }
1184
1185 SparseMatrix *RTxM_LH_mat = TransposeMult(*R_mat, *M_LH_mat);
1186 precon.reset(new DSmoother(*RTxM_LH_mat));
1187
1188 // Set ownership
1189 RTxM_LH.reset(RTxM_LH_mat);
1190 R = std::move(R_mat);
1191 M_LH = std::move(M_LH_mat);
1192
1193 SetupPCG();
1194}
1195
1196#ifdef MFEM_USE_MPI
1197
1199 const ParFiniteElementSpace& pfes_ho, const ParFiniteElementSpace& pfes_lor,
1200 CoefficientWithOrder coeff_ho_, CoefficientWithOrder coeff_lor_,
1201 const bool use_ea_, MemoryType d_mt_)
1202 : L2Projection(pfes_ho, pfes_lor, coeff_ho_, coeff_lor_, d_mt_),
1203 use_ea(use_ea_), pcg(pfes_ho.GetComm())
1204{
1205
1206 // need scalar to keep dimensions matching (operators are built to apply
1207 // individually on each vdim)
1208 // needed in both matrix and element based versions
1210 pfes_ho.FEColl(), 1));
1212 pfes_lor.FEColl(), 1));
1213
1214 if (use_ea)
1215 {
1216 EAL2ProjectionH1Space(pfes_ho, pfes_lor);
1217 return;
1218 }
1219
1220 std::tie(R, M_LH) = ComputeSparseRAndM_LH();
1221
1222
1223 HypreParMatrix R_local = HypreParMatrix(pfes_ho.GetComm(),
1224 pfes_lor_scalar->GlobalVSize(),
1225 pfes_ho_scalar->GlobalVSize(),
1226 pfes_lor_scalar->GetDofOffsets(),
1227 pfes_ho_scalar->GetDofOffsets(),
1228 static_cast<SparseMatrix*>(R.get()));
1229 HypreParMatrix M_LH_local = HypreParMatrix(pfes_ho.GetComm(),
1230 pfes_lor_scalar->GlobalVSize(),
1231 pfes_ho_scalar->GlobalVSize(),
1232 pfes_lor_scalar->GetDofOffsets(),
1233 pfes_ho_scalar->GetDofOffsets(),
1234 static_cast<SparseMatrix*>(M_LH.get()));
1235
1236 HypreParMatrix *R_mat = RAP(pfes_lor_scalar->Dof_TrueDof_Matrix(),
1237 &R_local, pfes_ho_scalar->Dof_TrueDof_Matrix());
1238 HypreParMatrix *M_LH_mat = RAP(pfes_lor_scalar->Dof_TrueDof_Matrix(),
1239 &M_LH_local, pfes_ho_scalar->Dof_TrueDof_Matrix());
1240
1241 std::unique_ptr<HypreParMatrix> R_T(R_mat->Transpose());
1242 HypreParMatrix *RTxM_LH_mat = ParMult(R_T.get(), M_LH_mat, true);
1243
1244 HypreBoomerAMG *amg = new HypreBoomerAMG(*RTxM_LH_mat);
1245 amg->SetPrintLevel(0);
1246
1247 R.reset(R_mat);
1248 M_LH.reset(M_LH_mat);
1249 RTxM_LH.reset(RTxM_LH_mat);
1250 precon.reset(amg);
1251
1252 SetupPCG();
1255}
1256
1257#endif
1258
1260{
1261 // Basic PCG solver setup
1262 pcg.SetPrintLevel(0);
1263 // pcg.SetPrintLevel(IterativeSolver::PrintLevel().Summary());
1264 pcg.SetMaxIter(1000);
1265 // initial values for relative and absolute tolerance
1266 pcg.SetRelTol(1e-13);
1267 pcg.SetAbsTol(1e-13);
1268 pcg.SetPreconditioner(*precon);
1269 pcg.SetOperator(*RTxM_LH);
1270}
1271
1273{
1274 Mesh &mesh_ho = *fes_ho.GetMesh();
1275 Mesh &mesh_lor = *fes_lor.GetMesh();
1276 const int nel_ho = mesh_ho.GetNE();
1277 const int nel_lor = mesh_lor.GetNE();
1278 const int ndof_ho = fes_ho.GetNDofs();
1279 const int ndof_lor = fes_lor.GetNDofs();
1280
1281 // If the local mesh is empty, skip all computations
1282 if (nel_ho == 0)
1283 {
1284 return;
1285 }
1286
1287 const CoarseFineTransformations& cf_tr = mesh_lor.GetRefinementTransforms();
1288
1289 int nref_max = 0;
1291 mesh_ho.GetGeometries(mesh_ho.Dimension(), geoms);
1292 for (int ig = 0; ig < geoms.Size(); ++ig)
1293 {
1294 Geometry::Type geom = geoms[ig];
1295 nref_max = std::max(nref_max, cf_tr.point_matrices[geom].SizeK());
1296 }
1297
1298 BuildHo2Lor(nel_ho, nel_lor, cf_tr);
1299
1300 // lumped M_H and inv lumped M_L
1301
1302 // M_H contains the lumped (row sum) high order mass matrix. This is built for
1303 // preconditioning the inverse needed to build the prolongation operator P
1304 Vector M_H(ndof_ho);
1305 M_H = 0.0;
1306 // ML_inv_ea contains the inverse lumped (row sum) mass matrix. Note that the
1307 // method will also work with a full (consistent) mass matrix, though this is
1308 // not implemented here. L refers to the low-order refined mesh
1309 ML_inv_ea.SetSize(ndof_lor);
1310 ML_inv_ea = 0.0;
1311
1312 BilinearForm Mho(fes_ho_scalar.get());
1315 : new MassIntegrator);
1316 Mho.Assemble();
1317
1318 // Processor local lumped Mass
1319 Vector ones_ho(Mho.Width()); ones_ho = 1.0;
1320 M_H = 0.0;
1321 Mho.Mult(ones_ho, M_H);
1322
1323 BilinearForm Mlor(fes_lor_scalar.get());
1325 {
1327 : new MassIntegrator;
1328 const int order = 2*fes_lor.GetMaxElementOrder()
1330 + coeff_lor.order;
1332 IntRules.Get(mesh_lor.GetTypicalElementGeometry(), order));
1333 Mlor.AddDomainIntegrator(mi);
1334 }
1335 Mlor.Assemble();
1336
1337 Vector ones_lor(Mlor.Width()); ones_lor = 1.0;
1338 Mlor.Mult(ones_lor, ML_inv_ea);
1339
1340 // DOF by DOF inverse of non-zero entries
1341 LumpedMassInverse(ML_inv_ea);
1342
1343 // mixed mass M_LH
1344 MixedMassEA(fes_ho, fes_lor, M_LH_ea, d_mt);
1345
1346 // Set ownership
1347 M_LH.reset(new H1SpaceMixedMassOperator(fes_ho_scalar.get(),
1348 fes_lor_scalar.get(),
1349 &ho2lor,
1350 &M_LH_ea));
1351
1352 ML_inv_vea.reset(new H1SpaceLumpedMassOperator(fes_ho_scalar.get(),
1353 fes_lor_scalar.get(),
1354 ML_inv_ea));
1355 R.reset(new ProductOperator(ML_inv_vea.get(), M_LH.get(), false,
1356 false));
1357
1358 Array<int> ess_tdof_list; // leave empty
1359 precon.reset(new OperatorJacobiSmoother(M_H, ess_tdof_list));
1360
1361 TransposeOperator* RT = new TransposeOperator(R.get());
1362 RTxM_LH.reset(new ProductOperator(RT, M_LH.get(), true, false));
1363
1364 SetupPCG();
1365}
1366
1367#ifdef MFEM_USE_MPI
1369(const ParFiniteElementSpace& pfes_ho, const ParFiniteElementSpace& pfes_lor)
1370{
1371 Mesh &mesh_ho = *pfes_ho.GetParMesh();
1372 Mesh &mesh_lor = *pfes_lor.GetParMesh();
1373 int nel_ho = mesh_ho.GetNE();
1374 int nel_lor = mesh_lor.GetNE();
1375 int ndof_ho = pfes_ho.GetNDofs();
1376 int ndof_lor = pfes_lor.GetNDofs();
1377
1378 const CoarseFineTransformations& cf_tr = mesh_lor.GetRefinementTransforms();
1379
1380 int nref_max = 0;
1382 mesh_ho.GetGeometries(mesh_ho.Dimension(), geoms);
1383 for (int ig = 0; ig < geoms.Size(); ++ig)
1384 {
1385 Geometry::Type geom = geoms[ig];
1386 nref_max = std::max(nref_max, cf_tr.point_matrices[geom].SizeK());
1387 }
1388
1389 BuildHo2Lor(nel_ho, nel_lor, cf_tr);
1390
1391 // lumped M_H and inv lumped M_L
1392
1393 // M_H contains the lumped (row sum) high order mass matrix. This is built for
1394 // preconditioning the inverse needed to build the prolongation operator P
1395 Vector M_H(ndof_ho);
1396 M_H = 0.0;
1397 // ML_inv_ea contains the inverse lumped (row sum) mass matrix. Note that the
1398 // method will also work with a full (consistent) mass matrix, though this is
1399 // not implemented here. L refers to the low-order refined mesh
1400 ML_inv_ea.SetSize(ndof_lor);
1401 ML_inv_ea = 0.0;
1402
1403 ParBilinearForm pMho(pfes_ho_scalar.get());
1406 : new MassIntegrator);
1407 pMho.Assemble();
1408
1409 // Processor local lumped Mass
1410 Vector ones_ho(pMho.Width()); ones_ho = 1.0;
1411 M_H = 0.0;
1412 pMho.Mult(ones_ho, M_H);
1413
1414 ParBilinearForm pMlor(pfes_lor_scalar.get());
1416 {
1418 : new MassIntegrator;
1419 const int order = 2*fes_lor.GetMaxElementOrder()
1421 + coeff_lor.order;
1423 IntRules.Get(mesh_lor.GetTypicalElementGeometry(), order));
1424 pMlor.AddDomainIntegrator(mi);
1425 }
1426 pMlor.Assemble();
1427
1428 Vector ones_lor(pMlor.Width()); ones_lor = 1.0;
1429 pMlor.Mult(ones_lor, ML_inv_ea);
1430
1431
1432 // DOF by DOF inverse of non-zero entries
1433 LumpedMassInverse(ML_inv_ea);
1434
1435 // mixed mass M_LH
1436 MixedMassEA(*pfes_ho_scalar.get(), *pfes_lor_scalar.get(), M_LH_ea, d_mt);
1437
1438 // Set ownership
1439 M_LH_local_op = new H1SpaceMixedMassOperator(pfes_ho_scalar.get(),
1440 pfes_lor_scalar.get(),
1441 &ho2lor, &M_LH_ea);
1442
1443 const Operator *P_ho = pfes_ho_scalar->GetProlongationMatrix();
1444 const Operator *P_lor = pfes_lor_scalar->GetProlongationMatrix();
1445
1446 Array<int> ess_tdof_list; // leave empty
1447
1448 if (P_ho || P_lor)
1449 {
1450 if (P_ho && P_lor)
1451 {
1452 Operator *Pt_lor = new TransposeOperator(P_lor);
1453 RML_inv.SetSize(pfes_lor_scalar->GetTrueVSize());
1454 GetTDofs(*pfes_lor_scalar, ML_inv_ea, RML_inv);
1455 ML_inv_vea.reset(new H1SpaceLumpedMassOperator(pfes_ho_scalar.get(),
1456 pfes_lor_scalar.get(),
1457 RML_inv));
1458 M_LH.reset(new TripleProductOperator(Pt_lor, M_LH_local_op, P_ho, true,
1459 true, false));
1460
1461 Vector RM_H(pfes_ho_scalar->GetTrueVSize());
1462 GetTDofsTranspose(*pfes_ho_scalar, M_H, RM_H);
1463 precon.reset(new OperatorJacobiSmoother(RM_H, ess_tdof_list));
1464 }
1465 else if (P_ho)
1466 {
1467 ML_inv_vea.reset(new H1SpaceLumpedMassOperator(pfes_ho_scalar.get(),
1468 pfes_lor_scalar.get(),
1469 ML_inv_ea));
1470 M_LH.reset(new ProductOperator(M_LH_local_op, P_ho, true, false));
1471
1472 Vector RM_H(pfes_ho_scalar->GetTrueVSize());
1473 GetTDofsTranspose(*pfes_ho_scalar.get(), M_H, RM_H);
1474 precon.reset(new OperatorJacobiSmoother(RM_H, ess_tdof_list));
1475 }
1476 else if (P_lor)
1477 {
1478 Operator *Pt_lor = new TransposeOperator(P_lor);
1479 RML_inv.SetSize(pfes_lor_scalar->GetTrueVSize());
1480 GetTDofsTranspose(*pfes_lor_scalar, ML_inv_ea, RML_inv);
1481 ML_inv_vea.reset(new H1SpaceLumpedMassOperator(pfes_ho_scalar.get(),
1482 pfes_lor_scalar.get(),
1483 RML_inv));
1484 M_LH.reset(new ProductOperator(Pt_lor, M_LH_local_op, true, true));
1485 R.reset(new ProductOperator(ML_inv_vea.get(), M_LH.get(), false,
1486 false));
1487
1488 precon.reset(new OperatorJacobiSmoother(M_H, ess_tdof_list));
1489 }
1490 else
1491 {
1492 ML_inv_vea.reset(new H1SpaceLumpedMassOperator(pfes_ho_scalar.get(),
1493 pfes_lor_scalar.get(),
1494 ML_inv_ea));
1495 M_LH.reset(M_LH_local_op);
1496
1497 precon.reset(new OperatorJacobiSmoother(M_H, ess_tdof_list));
1498 }
1499 }
1500 R.reset(new ProductOperator(ML_inv_vea.get(), M_LH.get(), false,
1501 false));
1502
1503 TransposeOperator* RT = new TransposeOperator(R.get());
1504 RTxM_LH.reset(new ProductOperator(RT, M_LH.get(), true, false));
1505
1506 SetupPCG();
1507}
1508
1509#endif
1510
1512 const Vector& x, Vector& y) const
1513{
1514 Vector X(fes_ho.GetTrueVSize());
1515 Vector X_dim(R->Width());
1516
1517 Vector Y_dim(R->Height());
1518 Vector Y(fes_lor.GetTrueVSize());
1519
1520 Array<int> vdofs_list;
1521
1522 GetTDofs(fes_ho, x, X);
1523
1524 for (int d = 0; d < fes_ho.GetVDim(); ++d)
1525 {
1526 TDofsListByVDim(fes_ho, d, vdofs_list);
1527 X.GetSubVector(vdofs_list, X_dim);
1528 R->Mult(X_dim, Y_dim);
1529 TDofsListByVDim(fes_lor, d, vdofs_list);
1530 Y.SetSubVector(vdofs_list, Y_dim);
1531 }
1532
1533 SetFromTDofs(fes_lor, Y, y);
1534
1535}
1536
1538 const Vector& x, Vector& y) const
1539{
1540 Vector X(fes_lor.GetTrueVSize());
1541 Vector X_dim(R->Height());
1542
1543 Vector Y_dim(R->Width());
1544 Vector Y(fes_ho.GetTrueVSize());
1545
1546 Array<int> vdofs_list;
1547
1548 GetTDofsTranspose(fes_lor, x, X);
1549
1550 for (int d = 0; d < fes_ho.GetVDim(); ++d)
1551 {
1552 TDofsListByVDim(fes_lor, d, vdofs_list);
1553 X.GetSubVector(vdofs_list, X_dim);
1554 R->MultTranspose(X_dim, Y_dim);
1555 TDofsListByVDim(fes_ho, d, vdofs_list);
1556 Y.SetSubVector(vdofs_list, Y_dim);
1557 }
1558
1559 SetFromTDofsTranspose(fes_ho, Y, y);
1560
1561}
1562
1564 const Vector& x, Vector& y) const
1565{
1566
1567 Vector X(fes_lor.GetTrueVSize());
1568 Vector X_dim(M_LH->Height());
1569 Vector Xbar(pcg.Width());
1570
1571 Vector Y_dim(pcg.Height());
1572 Y_dim = 0.0;
1573 Vector Y(fes_ho.GetTrueVSize());
1574
1575 Array<int> vdofs_list;
1576
1577 GetTDofs(fes_lor, x, X);
1578
1579 for (int d = 0; d < fes_ho.GetVDim(); ++d)
1580 {
1581 TDofsListByVDim(fes_lor, d, vdofs_list);
1582 X.GetSubVector(vdofs_list, X_dim);
1583 // Compute y = P x = (R^T M_LH)^(-1) M_LH^T X = (R^T M_LH)^(-1) Xbar
1584 M_LH->MultTranspose(X_dim, Xbar);
1585 pcg.Mult(Xbar, Y_dim);
1586 TDofsListByVDim(fes_ho, d, vdofs_list);
1587 Y.SetSubVector(vdofs_list, Y_dim);
1588 }
1589
1590 SetFromTDofs(fes_ho, Y, y);
1591
1592}
1593
1595 const Vector& x, Vector& y) const
1596{
1597 Vector X(fes_ho.GetTrueVSize());
1598 Vector X_dim(pcg.Width());
1599 Vector Xbar(pcg.Height());
1600
1601 Vector Y_dim(M_LH->Height());
1602 Vector Y(fes_lor.GetTrueVSize());
1603
1604 Array<int> vdofs_list;
1605
1606 GetTDofsTranspose(fes_ho, x, X);
1607
1608 for (int d = 0; d < fes_ho.GetVDim(); ++d)
1609 {
1610 TDofsListByVDim(fes_ho, d, vdofs_list);
1611 X.GetSubVector(vdofs_list, X_dim);
1612 // Compute y = P^T x = M_LH (R^T M_LH)^(-1) X = M_LH Xbar
1613 Xbar = 0.0;
1614 pcg.Mult(X_dim, Xbar);
1615 M_LH->Mult(Xbar, Y_dim);
1616 TDofsListByVDim(fes_lor, d, vdofs_list);
1617 Y.SetSubVector(vdofs_list, Y_dim);
1618 }
1619
1620 SetFromTDofsTranspose(fes_lor, Y, y);
1621
1622}
1623
1625{
1626 pcg.SetRelTol(p_rtol_);
1627}
1628
1630{
1631 pcg.SetAbsTol(p_atol_);
1632}
1633
1634std::pair<
1635std::unique_ptr<SparseMatrix>,
1636std::unique_ptr<SparseMatrix>>
1638{
1639 std::pair<std::unique_ptr<SparseMatrix>,
1640 std::unique_ptr<SparseMatrix>> r_and_mlh;
1641
1642 Mesh* mesh_ho = fes_ho.GetMesh();
1643 Mesh* mesh_lor = fes_lor.GetMesh();
1644 int nel_ho = mesh_ho->GetNE();
1645 int nel_lor = mesh_lor->GetNE();
1646 int ndof_lor = fes_lor.GetNDofs();
1647
1648 // If the local mesh is empty, skip all computations
1649 if (nel_ho == 0)
1650 {
1651 return std::make_pair(
1652 std::unique_ptr<SparseMatrix>(new SparseMatrix),
1653 std::unique_ptr<SparseMatrix>(new SparseMatrix)
1654 );
1655 }
1656
1657 const CoarseFineTransformations& cf_tr = mesh_lor->GetRefinementTransforms();
1658
1659 int nref_max = 0;
1661 mesh_ho->GetGeometries(mesh_ho->Dimension(), geoms);
1662 for (int ig = 0; ig < geoms.Size(); ++ig)
1663 {
1664 Geometry::Type geom = geoms[ig];
1665 nref_max = std::max(nref_max, cf_tr.point_matrices[geom].SizeK());
1666 }
1667
1668 BuildHo2Lor(nel_ho, nel_lor, cf_tr);
1669
1670 // ML_inv contains the inverse lumped (row sum) mass matrix. Note that the
1671 // method will also work with a full (consistent) mass matrix, though this is
1672 // not implemented here. L refers to the low-order refined mesh
1673 Vector ML_inv(ndof_lor);
1674 ML_inv = 0.0;
1675
1676 // Compute ML_inv
1677 for (int iho = 0; iho < nel_ho; ++iho)
1678 {
1679 Array<int> lor_els;
1680 ho2lor.GetRow(iho, lor_els);
1681 int nref = ho2lor.RowSize(iho);
1682
1683 Geometry::Type geom = mesh_ho->GetElementBaseGeometry(iho);
1684 const FiniteElement& fe_lor = *fes_lor.GetFE(lor_els[0]);
1685 int nedof_lor = fe_lor.GetDof();
1686
1687 // Instead of using a MassIntegrator, manually loop over integration
1688 // points so we can row sum and store the diagonal as a Vector.
1689 Vector ML_el(nedof_lor);
1690 Vector shape_lor(nedof_lor);
1691 Array<int> dofs_lor(nedof_lor);
1692
1693 for (int iref = 0; iref < nref; ++iref)
1694 {
1695 int ilor = lor_els[iref];
1696 ElementTransformation* el_tr = fes_lor.GetElementTransformation(ilor);
1697
1698 int order = 2 * fe_lor.GetOrder() + el_tr->OrderW() + coeff_lor.order;
1699 const IntegrationRule* ir = &IntRules.Get(geom, order);
1700 ML_el = 0.0;
1701 for (int i = 0; i < ir->GetNPoints(); ++i)
1702 {
1703 const IntegrationPoint& ip_lor = ir->IntPoint(i);
1704 fe_lor.CalcShape(ip_lor, shape_lor);
1705 el_tr->SetIntPoint(&ip_lor);
1706 real_t w = ip_lor.weight;
1707 if (coeff_lor)
1708 {
1709 w *= coeff_lor.coeff->Eval(*el_tr, ip_lor);
1710 }
1711 shape_lor *= el_tr->Weight() * w;
1712 ML_el += shape_lor;
1713 }
1714 fes_lor.GetElementDofs(ilor, dofs_lor);
1715 ML_inv.AddElementVector(dofs_lor, ML_el);
1716 }
1717 }
1718 // DOF by DOF inverse of non-zero entries
1719 LumpedMassInverse(ML_inv);
1720
1721 // Compute sparsity pattern for R = M_L^(-1) M_LH and allocate
1722 r_and_mlh.first = AllocR();
1723 // Allocate M_LH (same sparsity pattern as R)
1724 // L refers to the low-order refined mesh (DOFs correspond to rows)
1725 // H refers to the higher-order mesh (DOFs correspond to columns)
1726 Memory<int> I(r_and_mlh.first->Height() + 1);
1727 for (int icol = 0; icol < r_and_mlh.first->Height() + 1; ++icol)
1728 {
1729 I[icol] = r_and_mlh.first->GetI()[icol];
1730 }
1731 Memory<int> J(r_and_mlh.first->NumNonZeroElems());
1732 for (int jcol = 0; jcol < r_and_mlh.first->NumNonZeroElems(); ++jcol)
1733 {
1734 J[jcol] = r_and_mlh.first->GetJ()[jcol];
1735 }
1736 r_and_mlh.second = std::unique_ptr<SparseMatrix>(
1737 new SparseMatrix(I, J, NULL, r_and_mlh.first->Height(),
1738 r_and_mlh.first->Width(), true, true, true));
1739
1741 IsoparametricTransformation& emb_tr = ip_tr.Transf;
1742
1743 // Compute M_LH and R
1744 offsets.SetSize(nel_ho+1);
1745 offsets[0] = 0;
1746 for (int iho = 0; iho < nel_ho; ++iho)
1747 {
1748 Array<int> lor_els;
1749 ho2lor.GetRow(iho, lor_els);
1750 int nref = ho2lor.RowSize(iho);
1751
1752 Geometry::Type geom = mesh_ho->GetElementBaseGeometry(iho);
1753 const FiniteElement& fe_ho = *fes_ho.GetFE(iho);
1754 const FiniteElement& fe_lor = *fes_lor.GetFE(lor_els[0]);
1755 offsets[iho+1] = offsets[iho] + fe_ho.GetDof()*fe_lor.GetDof()*nref;
1756
1757 ElementTransformation *tr_ho = fes_ho.GetElementTransformation(iho);
1758
1759 emb_tr.SetIdentityTransformation(geom);
1760 const DenseTensor& pmats = cf_tr.point_matrices[geom];
1761
1762 int nedof_ho = fe_ho.GetDof();
1763 int nedof_lor = fe_lor.GetDof();
1764 DenseMatrix M_LH_el(nedof_lor, nedof_ho);
1765 DenseMatrix R_el(nedof_lor, nedof_ho);
1766
1767 for (int iref = 0; iref < nref; ++iref)
1768 {
1769 int ilor = lor_els[iref];
1770 ElementTransformation* tr_lor = fes_lor.GetElementTransformation(ilor);
1771
1772 // Create the transformation that embeds the fine low-order element
1773 // within the coarse high-order element in reference space
1774 emb_tr.SetPointMat(pmats(cf_tr.embeddings[ilor].matrix));
1775
1776 ElemMixedMass(geom, fe_ho, fe_lor, tr_ho, tr_lor, ip_tr, M_LH_el);
1777
1778 Array<int> dofs_lor(nedof_lor);
1779 fes_lor.GetElementDofs(ilor, dofs_lor);
1780 Vector R_row;
1781 for (int i = 0; i < nedof_lor; ++i)
1782 {
1783 M_LH_el.GetRow(i, R_row);
1784 R_el.SetRow(i, R_row.Set(ML_inv[dofs_lor[i]], R_row));
1785 }
1786 Array<int> dofs_ho(nedof_ho);
1787 fes_ho.GetElementDofs(iho, dofs_ho);
1788 r_and_mlh.second->AddSubMatrix(dofs_lor, dofs_ho, M_LH_el);
1789 r_and_mlh.first->AddSubMatrix(dofs_lor, dofs_ho, R_el);
1790
1791 }
1792 }
1793
1794 return r_and_mlh;
1795}
1796
1798 const FiniteElementSpace& fes, const Vector& x, Vector& X) const
1799{
1800 const Operator* res = fes.GetRestrictionOperator();
1801 if (res)
1802 {
1803 res->Mult(x, X);
1804 }
1805 else
1806 {
1807 X = x;
1808 }
1809}
1810
1812 const FiniteElementSpace& fes, const Vector &X, Vector& x) const
1813{
1814 const Operator* P = fes.GetProlongationMatrix();
1815 if (P)
1816 {
1817 P->Mult(X, x);
1818 }
1819 else
1820 {
1821 x = X;
1822 }
1823}
1824
1826 const FiniteElementSpace& fes, const Vector& x, Vector& X) const
1827{
1828 const Operator* P = fes.GetProlongationMatrix();
1829 if (P)
1830 {
1831 P->MultTranspose(x, X);
1832 }
1833 else
1834 {
1835 X = x;
1836 }
1837}
1838
1840 const FiniteElementSpace& fes, const Vector &X, Vector& x) const
1841{
1842 const Operator *R_op = fes.GetRestrictionOperator();
1843 if (R_op)
1844 {
1845 R_op->MultTranspose(X, x);
1846 }
1847 else
1848 {
1849 x = X;
1850 }
1851}
1852
1854 const FiniteElementSpace& fes, int vdim, Array<int>& vdofs_list) const
1855{
1856 const SparseMatrix *R_mat = fes.GetRestrictionMatrix();
1857 if (R_mat)
1858 {
1859 Array<int> x_vdofs_list(fes.GetNDofs());
1860 Array<int> x_vdofs_marker(fes.GetVSize());
1861 Array<int> X_vdofs_marker(fes.GetTrueVSize());
1862 fes.GetVDofs(vdim, x_vdofs_list);
1863 FiniteElementSpace::ListToMarker(x_vdofs_list, fes.GetVSize(), x_vdofs_marker);
1864 R_mat->BooleanMult(x_vdofs_marker, X_vdofs_marker);
1865 FiniteElementSpace::MarkerToList(X_vdofs_marker, vdofs_list);
1866 }
1867 else
1868 {
1869 vdofs_list.SetSize(fes.GetNDofs());
1870 fes.GetVDofs(vdim, vdofs_list);
1871 }
1872}
1873
1875 Vector& ML_inv) const
1876{
1877#ifdef MFEM_USE_MPI
1878 // LumpedMassInverse may get called from serial and MPI parallel routines
1879 // since we do not know which code path is calling it we must check if
1880 // the pfes pointer is null when MPI is available.
1881 auto * fes = pfes_lor_scalar == nullptr ? fes_lor_scalar.get() :
1882 pfes_lor_scalar.get();
1883#else
1884 auto * fes = fes_lor_scalar.get();
1885#endif
1886 MFEM_ASSERT(fes != nullptr, "[p]fes_lor_scalar is nullptr");
1887
1888 Vector ML_inv_true(fes->GetTrueVSize());
1889 const Operator *P = fes->GetProlongationMatrix();
1890 if (P) { P->MultTranspose(ML_inv, ML_inv_true); }
1891 else { ML_inv_true = ML_inv; }
1892
1893 ML_inv_true.Reciprocal();
1894
1895 if (P) { P->Mult(ML_inv_true, ML_inv); }
1896 else { ML_inv = ML_inv_true; }
1897
1898}
1899
1900std::unique_ptr<SparseMatrix>
1902{
1903 const Table& elem_dof_ho = fes_ho.GetElementToDofTable();
1904 const Table& elem_dof_lor = fes_lor.GetElementToDofTable();
1905 const int ndof_ho = fes_ho.GetNDofs();
1906 const int ndof_lor = fes_lor.GetNDofs();
1907
1908 Table dof_elem_lor;
1909 Transpose(elem_dof_lor, dof_elem_lor, ndof_lor);
1910
1911 Mesh* mesh_lor = fes_lor.GetMesh();
1912 const CoarseFineTransformations& cf_tr = mesh_lor->GetRefinementTransforms();
1913
1914 // mfem::Mult but uses ho2lor to map HO elements to LOR elements
1915 const int* elem_dof_hoI = elem_dof_ho.GetI();
1916 const int* elem_dof_hoJ = elem_dof_ho.GetJ();
1917 const int* dof_elem_lorI = dof_elem_lor.GetI();
1918 const int* dof_elem_lorJ = dof_elem_lor.GetJ();
1919
1920 Array<int> I(ndof_lor + 1);
1921
1922 // figure out the size of J
1923 Array<int> dof_used_ho;
1924 dof_used_ho.SetSize(ndof_ho, -1);
1925
1926 int sizeJ = 0;
1927 for (int ilor = 0; ilor < ndof_lor; ++ilor)
1928 {
1929 for (int jlor = dof_elem_lorI[ilor]; jlor < dof_elem_lorI[ilor + 1]; ++jlor)
1930 {
1931 int el_lor = dof_elem_lorJ[jlor];
1932 int iho = cf_tr.embeddings[el_lor].parent;
1933 for (int jho = elem_dof_hoI[iho]; jho < elem_dof_hoI[iho + 1]; ++jho)
1934 {
1935 int dof_ho = elem_dof_hoJ[jho];
1936 if (dof_used_ho[dof_ho] != ilor)
1937 {
1938 dof_used_ho[dof_ho] = ilor;
1939 ++sizeJ;
1940 }
1941 }
1942 }
1943 }
1944
1945 // initialize dof_ho_dof_lor
1946 Table dof_lor_dof_ho;
1947 dof_lor_dof_ho.SetDims(ndof_lor, sizeJ);
1948
1949 for (int i = 0; i < ndof_ho; ++i)
1950 {
1951 dof_used_ho[i] = -1;
1952 }
1953
1954 // set values of J
1955 int* dof_dofI = dof_lor_dof_ho.GetI();
1956 int* dof_dofJ = dof_lor_dof_ho.GetJ();
1957 sizeJ = 0;
1958 for (int ilor = 0; ilor < ndof_lor; ++ilor)
1959 {
1960 dof_dofI[ilor] = sizeJ;
1961 for (int jlor = dof_elem_lorI[ilor]; jlor < dof_elem_lorI[ilor + 1]; ++jlor)
1962 {
1963 int el_lor = dof_elem_lorJ[jlor];
1964 int iho = cf_tr.embeddings[el_lor].parent;
1965 for (int jho = elem_dof_hoI[iho]; jho < elem_dof_hoI[iho + 1]; ++jho)
1966 {
1967 int dof_ho = elem_dof_hoJ[jho];
1968 if (dof_used_ho[dof_ho] != ilor)
1969 {
1970 dof_used_ho[dof_ho] = ilor;
1971 dof_dofJ[sizeJ] = dof_ho;
1972 ++sizeJ;
1973 }
1974 }
1975 }
1976 }
1977
1978 dof_lor_dof_ho.SortRows();
1979 real_t* data = Memory<real_t>(dof_dofI[ndof_lor]);
1980
1981 std::unique_ptr<SparseMatrix> R_local(new SparseMatrix(
1982 dof_dofI, dof_dofJ, data, ndof_lor,
1983 ndof_ho, true, true, true));
1984 (*R_local) = 0.0;
1985
1986 dof_lor_dof_ho.LoseData();
1987
1988 return R_local;
1989}
1990
1992 const FiniteElementSpace* fes_ho_, const FiniteElementSpace* fes_lor_,
1993 Table* ho2lor_, Vector* M_LH_ea_) :
1994 Operator(fes_lor_->GetElementRestriction(ElementDofOrdering::NATIVE)->Width(),
1995 fes_ho_->GetElementRestriction(ElementDofOrdering::NATIVE)->Width()),
1996 fes_ho(fes_ho_), fes_lor(fes_lor_), ho2lor(ho2lor_),
1997 M_LH_ea(M_LH_ea_)
1998{ }
1999
2001 Vector &y) const
2002{
2003 if (fes_ho->GetNE() == 0)
2004 {
2005 return;
2006 }
2007
2008 const Operator* elem_restrict_ho = fes_ho->GetElementRestriction(
2010 const Operator* elem_restrict_lor = fes_lor->GetElementRestriction(
2012
2013 const int vdim = fes_ho->GetVDim();
2014 const int iho = 0;
2015 const int nref = ho2lor->RowSize(iho);
2016 const int ndof_ho = fes_ho->GetFE(iho)->GetDof();
2017 const int ndof_lor = fes_lor->GetFE(ho2lor->GetRow(iho)[0])->GetDof();
2018 const Mesh *mesh_ho = fes_ho->GetMesh();
2019 const int nel_ho = mesh_ho->GetNE();
2020
2021 Vector tempx(elem_restrict_ho->Height());
2022 elem_restrict_ho->Mult(x, tempx);
2023
2024 Vector tempy(ndof_lor*nref*vdim*nel_ho);
2025
2026 auto v_M_mixed_ea = Reshape(M_LH_ea->Read(), ndof_lor, ndof_ho, nref,
2027 nel_ho);
2028 auto v_tempx = Reshape(tempx.Read(), ndof_ho, vdim, nel_ho);
2029 auto v_tempy = Reshape(tempy.Write(), ndof_lor, nref, vdim, nel_ho);
2030
2031
2032 mfem::forall(ndof_lor * nref * vdim * nel_ho, [=] MFEM_HOST_DEVICE (int tid)
2033 {
2034 const int j = tid % ndof_lor;
2035 const int i = (tid / ndof_lor) % nref;
2036 const int v = (tid / (ndof_lor * nref)) % vdim;
2037 const int iho = (tid / (ndof_lor * nref * vdim)) % nel_ho;
2038
2039 real_t dot = 0.0;
2040 for (int k=0; k<ndof_ho; ++k)
2041 {
2042 dot += v_M_mixed_ea(j, k, i, iho) * v_tempx(k, v, iho);
2043 }
2044
2045 v_tempy(j, i, v, iho) = dot;
2046 });
2047
2048 elem_restrict_lor->MultTranspose(tempy, y);
2049}
2050
2052 const Vector &x, Vector &y) const
2053{
2054 if (fes_ho->GetNE() == 0)
2055 {
2056 return;
2057 }
2058
2059 const Operator* elem_restrict_ho = fes_ho->GetElementRestriction(
2061 const Operator* elem_restrict_lor = fes_lor->GetElementRestriction(
2063
2064 const int vdim = fes_ho->GetVDim();
2065 const int iho = 0;
2066 const int nref = ho2lor->RowSize(iho);
2067 const int ndof_ho = fes_ho->GetFE(iho)->GetDof();
2068 const int ndof_lor = fes_lor->GetFE(ho2lor->GetRow(iho)[0])->GetDof();
2069 const Mesh *mesh_ho = fes_ho->GetMesh();
2070 const int nel_ho = mesh_ho->GetNE();
2071
2072 Vector tempx(elem_restrict_lor->Height());
2073 elem_restrict_lor->Mult(x, tempx);
2074
2075 Vector tempy(ndof_ho*vdim*nel_ho);
2076
2077 auto v_M_mixed_ea = Reshape(M_LH_ea->Read(), ndof_lor, ndof_ho, nref,
2078 nel_ho);
2079 auto v_tempx = Reshape(tempx.Read(), ndof_lor, nref, vdim, nel_ho);
2080 auto v_tempy = Reshape(tempy.Write(), ndof_ho, vdim, nel_ho);
2081
2082 mfem::forall(ndof_ho * vdim * nel_ho, [=] MFEM_HOST_DEVICE (int tid)
2083 {
2084 const int k = tid % ndof_ho;
2085 const int v = (tid / ndof_ho) % vdim;
2086 const int iho = (tid / (ndof_ho * vdim)) % nel_ho;
2087
2088 real_t dot = 0.0;
2089 for (int i=0; i<nref; ++i)
2090 {
2091 for (int j=0; j<ndof_lor; ++j)
2092 {
2093 dot += v_M_mixed_ea(j, k, i, iho) * v_tempx(j, i, v, iho);
2094 }
2095 v_tempy(k, v, iho) = dot;
2096 }
2097 });
2098
2099 elem_restrict_ho->MultTranspose(tempy, y);
2100}
2101
2103 const FiniteElementSpace* fes_ho_,
2104 const FiniteElementSpace* fes_lor_,
2105 Vector& ML_inv_) :
2106 Operator(ML_inv_.Size(), ML_inv_.Size()),
2107 fes_ho(fes_ho_), fes_lor(fes_lor_),
2108 ML_inv(&ML_inv_)
2109{ }
2110
2112 Vector &y) const
2113{
2114 MFEM_ASSERT(ML_inv->Size() == x.Size(), "sizes not the same");
2115 auto v_ML_inv = Reshape(ML_inv->Read(), ML_inv->Size());
2116 auto v_x = Reshape(x.Read(), x.Size());
2117 auto v_y = Reshape(y.Write(), y.Size());
2118
2119 mfem::forall(ML_inv->Size(), [=] MFEM_HOST_DEVICE(int i)
2120 { v_y(i) = v_ML_inv(i) * v_x(i); });
2121}
2122
2124 const Vector &x, Vector &y) const
2125{
2126 this->Mult(x,y); // lumped diagonal has the same Mult and MultTranspose behavior
2127}
2128
2130{
2131 delete F;
2132 delete B;
2133}
2134
2136{
2137 if (!F) { BuildF(); }
2138 return *F;
2139}
2140
2142{
2143 if (!B)
2144 {
2145 if (!F) { BuildF(); }
2146 B = new L2Prolongation(*F);
2147 }
2148 return *B;
2149}
2150
2151void L2ProjectionGridTransfer::BuildF()
2152{
2153 if (!force_l2_space &&
2155 {
2156 if (!Parallel())
2157 {
2158 F = new L2ProjectionH1Space(
2160 }
2161 else
2162 {
2163#ifdef MFEM_USE_MPI
2164 const mfem::ParFiniteElementSpace& dom_pfes =
2165 static_cast<mfem::ParFiniteElementSpace&>(dom_fes);
2166 const mfem::ParFiniteElementSpace& ran_pfes =
2167 static_cast<mfem::ParFiniteElementSpace&>(ran_fes);
2168 F = new L2ProjectionH1Space(
2169 dom_pfes, ran_pfes, coeff_ho, coeff_lor, use_ea, d_mt);
2170#endif
2171 }
2172 }
2173 else
2174 {
2175 F = new L2ProjectionL2Space(
2177 }
2178}
2179
2184
2185
2187 const FiniteElementSpace& hFESpace_)
2188 : Operator(hFESpace_.GetVSize(), lFESpace_.GetVSize())
2189{
2190 bool isvar_order = lFESpace_.IsVariableOrder() || hFESpace_.IsVariableOrder();
2191 bool is_trace_space =
2192 (dynamic_cast<const H1_Trace_FECollection*>(lFESpace_.FEColl()) ||
2193 dynamic_cast<const ND_Trace_FECollection*>(lFESpace_.FEColl()) ||
2194 dynamic_cast<const RT_Trace_FECollection*>(lFESpace_.FEColl()));
2195 if (lFESpace_.FEColl() == hFESpace_.FEColl() && !isvar_order)
2196 {
2198 hFESpace_.GetTransferOperator(lFESpace_, P);
2199 P.SetOperatorOwner(false);
2200 opr = P.Ptr();
2201 }
2202 else if (lFESpace_.GetVDim() == 1
2203 && hFESpace_.GetVDim() == 1
2204 && !is_trace_space
2205 && dynamic_cast<const TensorBasisElement*>(lFESpace_.GetTypicalFE())
2206 && dynamic_cast<const TensorBasisElement*>(hFESpace_.GetTypicalFE())
2207 && !isvar_order
2208 && (hFESpace_.FEColl()->GetContType() ==
2210 hFESpace_.FEColl()->GetContType() ==
2212 {
2213 opr = new TensorProductPRefinementTransferOperator(lFESpace_, hFESpace_);
2214 }
2215 else
2216 {
2217 opr = new PRefinementTransferOperator(lFESpace_, hFESpace_);
2218 }
2219}
2220
2222
2223void TransferOperator::Mult(const Vector& x, Vector& y) const
2224{
2225 opr->Mult(x, y);
2226}
2227
2229{
2230 opr->MultTranspose(x, y);
2231}
2232
2233
2235 const FiniteElementSpace& lFESpace_, const FiniteElementSpace& hFESpace_,
2236 bool assemble_matrix)
2237 : Operator(hFESpace_.GetVSize(), lFESpace_.GetVSize()), lFESpace(lFESpace_),
2238 hFESpace(hFESpace_)
2239{
2240 isvar_order = lFESpace_.IsVariableOrder() || hFESpace_.IsVariableOrder();
2241
2242 MFEM_VERIFY(lFESpace.FEColl()->GetContType() ==
2243 hFESpace.FEColl()->GetContType(),
2244 "Incompatible finite element space continuity types.");
2245
2246 is_trace_space =
2247 (dynamic_cast<const H1_Trace_FECollection*>(lFESpace.FEColl()) ||
2248 dynamic_cast<const ND_Trace_FECollection*>(lFESpace.FEColl()) ||
2249 dynamic_cast<const RT_Trace_FECollection*>(lFESpace.FEColl()));
2250
2251 if (assemble_matrix) { AssembleMatrix(); }
2252
2253}
2254
2255void PRefinementTransferOperator::AssembleMatrix()
2256{
2257 Mesh* mesh = hFESpace.GetMesh();
2258 const int nL = lFESpace.GetVSize();
2259 const int nH = hFESpace.GetVSize();
2260
2261 P.reset(new SparseMatrix(nH, nL));
2262 Array<int> l_dofs, h_dofs, l_vdofs, h_vdofs;
2263 DenseMatrix loc_prol;
2264
2265 Geometry::Type cached_geom = Geometry::INVALID;
2266 const FiniteElement* h_fe = nullptr;
2267 const FiniteElement* l_fe = nullptr;
2269
2270 int vdim = lFESpace.GetVDim();
2271
2272 const int iend = (is_trace_space) ? mesh->GetNumFaces() : mesh->GetNE();
2273 DofTransformation doftrans_h, doftrans_l;
2274 Vector w(nH); w = 0.0;
2275
2276 for (int i = 0; i < iend; i++)
2277 {
2278 if (is_trace_space)
2279 {
2280 hFESpace.GetFaceDofs(i, h_dofs);
2281 lFESpace.GetFaceDofs(i, l_dofs);
2282 }
2283 else
2284 {
2285 hFESpace.GetElementDofs(i, h_dofs, doftrans_h);
2286 lFESpace.GetElementDofs(i, l_dofs, doftrans_l);
2287 }
2288
2289 const Geometry::Type geom = (is_trace_space) ? mesh->GetFaceGeometry(i)
2290 : mesh->GetElementBaseGeometry(i);
2291
2292 if (geom != cached_geom || isvar_order)
2293 {
2294 h_fe = (is_trace_space) ? hFESpace.GetFaceElement(i) : hFESpace.GetFE(i);
2295 l_fe = (is_trace_space) ? lFESpace.GetFaceElement(i) : lFESpace.GetFE(i);
2297 h_fe->GetTransferMatrix(*l_fe, T, loc_prol);
2298 cached_geom = geom;
2299 }
2300
2301 DenseMatrix Aeff(loc_prol);
2302 TransformPrimal(doftrans_h, doftrans_l, Aeff);
2303 for (int vd = 0; vd < vdim; vd++)
2304 {
2305 DenseMatrix temp_Aeff(Aeff);
2306
2307 l_dofs.Copy(l_vdofs);
2308 lFESpace.DofsToVDofs(vd, l_vdofs);
2309
2310 h_dofs.Copy(h_vdofs);
2311 hFESpace.DofsToVDofs(vd, h_vdofs);
2312
2313 temp_Aeff.AdjustDofDirection(h_vdofs, l_vdofs);
2314
2315 P->AddSubMatrix(h_vdofs, l_vdofs, temp_Aeff);
2316
2317 for (int rr = 0; rr < h_vdofs.Size(); rr++)
2318 {
2319 w(h_vdofs[rr]) += 1.0;
2320 }
2321
2322 }
2323 }
2324
2325 P->Finalize();
2326
2327 Vector inv_w(nH);
2328 for (int i = 0; i < nH; i++)
2329 {
2330 inv_w(i) = (w(i) > 0.0) ? (1.0 / w(i)) : 1.0;
2331 }
2332
2333 P->ScaleRows(inv_w);
2334
2335 assembled = true;
2336
2337}
2338
2339std::unique_ptr<SparseMatrix>
2340PRefinementTransferOperator::BuildConformingTransferMatrix() const
2341{
2342 MFEM_VERIFY(assembled && P, "Matrix path requires assembled P.");
2343
2344 const SparseMatrix *Pl = lFESpace.GetConformingProlongation();
2345 const SparseMatrix *Rh = hFESpace.GetRestrictionMatrix();
2346
2347 if (Pl && Rh)
2348 {
2349 SparseMatrix *RhP = mfem::Mult(*Rh, *P);
2350 SparseMatrix *RhPPl = mfem::Mult(*RhP, *Pl);
2351 delete RhP;
2352 return std::unique_ptr<SparseMatrix>(RhPPl);
2353 }
2354 else if (Pl)
2355 {
2356 return std::unique_ptr<SparseMatrix>(mfem::Mult(*P, *Pl));
2357 }
2358 else if (Rh)
2359 {
2360 return std::unique_ptr<SparseMatrix>(mfem::Mult(*Rh, *P));
2361 }
2362 else
2363 {
2364 return std::make_unique<SparseMatrix>(*P);
2365 }
2366}
2367
2368std::unique_ptr<Operator>
2369PRefinementTransferOperator::BuildConformingTransferOperator() const
2370{
2371 const Operator *Pl = lFESpace.GetProlongationMatrix();
2372 const Operator *Rh = hFESpace.GetRestrictionOperator();
2373
2374 if (Pl && Rh)
2375 {
2376 return std::make_unique<TripleProductOperator>(Rh,
2377 const_cast<PRefinementTransferOperator*>(this), Pl,
2378 false, false, false);
2379 }
2380 else if (Pl)
2381 {
2382 return std::make_unique<ProductOperator>
2383 (const_cast<PRefinementTransferOperator*>(this), Pl,
2384 false, false);
2385 }
2386 else if (Rh)
2387 {
2388 return std::make_unique<ProductOperator>(Rh,
2389 const_cast<PRefinementTransferOperator*>(this),
2390 false, false);
2391 }
2392 else
2393 {
2394 // return nullptr to mean "identity/no-op wrapper", i.e. use `this`
2395 return nullptr;
2396 }
2397}
2398
2399Operator *
2401{
2402 if (tP) { return tP.get(); }
2403#ifdef MFEM_USE_MPI
2404 const ParFiniteElementSpace* lpfes = dynamic_cast<const ParFiniteElementSpace*>
2405 (&lFESpace);
2406 const ParFiniteElementSpace* hpfes = dynamic_cast<const ParFiniteElementSpace*>
2407 (&hFESpace);
2408 bool parallel = (lpfes) && (hpfes);
2409
2410 if (parallel)
2411 {
2412 if (assembled)
2413 {
2414 HypreParMatrix * Pl = lpfes->Dof_TrueDof_Matrix();
2415 const SparseMatrix * Rh = hpfes->GetRestrictionMatrix();
2416 // Rh * P
2417 SparseMatrix * RhP = mfem::Mult(*Rh, *P);
2418 HypreParMatrix * RhPh = new HypreParMatrix(hpfes->GetComm(),
2419 hpfes->GlobalTrueVSize(), lpfes->GlobalVSize(),
2420 hpfes->GetTrueDofOffsets(), lpfes->GetDofOffsets(), RhP);
2421 HypreStealOwnership(*RhPh, *RhP);
2422 delete RhP;
2423 HypreParMatrix * tmp = ParMult(RhPh, Pl, true);
2424 delete RhPh;
2425 tP.reset(tmp);
2426 return tP.get();
2427 }
2428 else
2429 {
2430 auto Pl = lpfes->GetProlongationMatrix();
2431 auto Rh = hpfes->GetRestrictionOperator();
2432 tP = std::make_unique<TripleProductOperator>(Rh, this, Pl, false, false, false);
2433 return tP.get();
2434 }
2435 }
2436 else
2437 {
2438 if (assembled)
2439 {
2440 auto M = BuildConformingTransferMatrix();
2441 tP.reset(M.release());
2442 return tP.get();
2443 }
2444 else
2445 {
2446 tP = BuildConformingTransferOperator();
2447 return tP ? tP.get() : this;
2448 }
2449 }
2450#else
2451 {
2452 if (assembled)
2453 {
2454 auto M = BuildConformingTransferMatrix();
2455 tP.reset(M.release());
2456 return tP.get();
2457 }
2458 else
2459 {
2460 tP = BuildConformingTransferOperator();
2461 return tP ? tP.get() : this;
2462 }
2463 }
2464#endif
2465}
2466
2467
2469{
2470 y = 0.0;
2471
2472 if (assembled) { P->Mult(x, y); return; }
2473
2474 Mesh* mesh = hFESpace.GetMesh();
2475 Array<int> l_dofs, h_dofs, l_vdofs, h_vdofs;
2476 DenseMatrix loc_prol;
2477 Vector subY, subX;
2478
2479 Geometry::Type cached_geom = Geometry::INVALID;
2480 const FiniteElement* h_fe = NULL;
2481 const FiniteElement* l_fe = NULL;
2483
2484 int vdim = lFESpace.GetVDim();
2485
2486
2487 DofTransformation doftrans_h, doftrans_l;
2488
2489 const int iend = (is_trace_space) ? mesh->GetNumFaces() : mesh->GetNE();
2490
2491 for (int i = 0; i < iend; i++)
2492 {
2493 if (is_trace_space)
2494 {
2495 hFESpace.GetFaceDofs(i, h_dofs);
2496 lFESpace.GetFaceDofs(i, l_dofs);
2497 }
2498 else
2499 {
2500 hFESpace.GetElementDofs(i, h_dofs, doftrans_h);
2501 lFESpace.GetElementDofs(i, l_dofs, doftrans_l);
2502 }
2503
2504 const Geometry::Type geom = (is_trace_space) ? mesh->GetFaceGeometry(i)
2505 : mesh->GetElementBaseGeometry(i);
2506
2507 if (geom != cached_geom || isvar_order)
2508 {
2509 h_fe = (is_trace_space) ? hFESpace.GetFaceElement(i) : hFESpace.GetFE(i);
2510 l_fe = (is_trace_space) ? lFESpace.GetFaceElement(i) : lFESpace.GetFE(i);
2512 h_fe->GetTransferMatrix(*l_fe, T, loc_prol);
2513 subY.SetSize(loc_prol.Height());
2514 cached_geom = geom;
2515 }
2516
2517 for (int vd = 0; vd < vdim; vd++)
2518 {
2519 l_dofs.Copy(l_vdofs);
2520 lFESpace.DofsToVDofs(vd, l_vdofs);
2521 h_dofs.Copy(h_vdofs);
2522 hFESpace.DofsToVDofs(vd, h_vdofs);
2523 x.GetSubVector(l_vdofs, subX);
2524 doftrans_l.InvTransformPrimal(subX);
2525
2526 loc_prol.Mult(subX, subY);
2527 doftrans_h.TransformPrimal(subY);
2528 y.SetSubVector(h_vdofs, subY);
2529 }
2530 }
2531}
2532
2534 Vector& y) const
2535{
2536 y = 0.0;
2537
2538 if (assembled)
2539 {
2540 P->MultTranspose(x, y);
2541 return;
2542 }
2543
2544 Mesh* mesh = hFESpace.GetMesh();
2545 Array<int> l_dofs, h_dofs, l_vdofs, h_vdofs;
2546 DenseMatrix loc_prol;
2547 Vector subY, subX;
2548
2549 Array<char> processed(hFESpace.GetVSize());
2550 processed = 0;
2551
2552 Geometry::Type cached_geom = Geometry::INVALID;
2553 const FiniteElement* h_fe = NULL;
2554 const FiniteElement* l_fe = NULL;
2556
2557 int vdim = lFESpace.GetVDim();
2558
2559 DofTransformation doftrans_h, doftrans_l;
2560
2561 int iend = (is_trace_space) ? mesh->GetNumFaces() : mesh->GetNE();
2562
2563 for (int i = 0; i < iend; i++)
2564 {
2565 if (is_trace_space)
2566 {
2567 hFESpace.GetFaceDofs(i, h_dofs);
2568 lFESpace.GetFaceDofs(i, l_dofs);
2569 }
2570 else
2571 {
2572 hFESpace.GetElementDofs(i, h_dofs, doftrans_h);
2573 lFESpace.GetElementDofs(i, l_dofs, doftrans_l);
2574 }
2575
2576 const Geometry::Type geom = (is_trace_space) ? mesh->GetFaceGeometry(i)
2577 : mesh->GetElementBaseGeometry(i);
2578
2579 if (geom != cached_geom || isvar_order)
2580 {
2581 h_fe = (is_trace_space) ? hFESpace.GetFaceElement(i) : hFESpace.GetFE(i);
2582 l_fe = (is_trace_space) ? lFESpace.GetFaceElement(i) : lFESpace.GetFE(i);
2584 h_fe->GetTransferMatrix(*l_fe, T, loc_prol);
2585 loc_prol.Transpose();
2586 subY.SetSize(loc_prol.Height());
2587 cached_geom = geom;
2588 }
2589
2590 for (int vd = 0; vd < vdim; vd++)
2591 {
2592 l_dofs.Copy(l_vdofs);
2593 lFESpace.DofsToVDofs(vd, l_vdofs);
2594 h_dofs.Copy(h_vdofs);
2595 hFESpace.DofsToVDofs(vd, h_vdofs);
2596
2597 x.GetSubVector(h_vdofs, subX);
2598 doftrans_h.InvTransformDual(subX);
2599 for (int p = 0; p < h_dofs.Size(); ++p)
2600 {
2601 if (processed[lFESpace.DecodeDof(h_dofs[p])])
2602 {
2603 subX[p] = 0.0;
2604 }
2605 }
2606
2607 loc_prol.Mult(subX, subY);
2608 doftrans_l.TransformDual(subY);
2609 y.AddElementVector(l_vdofs, subY);
2610 }
2611
2612 for (int p = 0; p < h_dofs.Size(); ++p)
2613 {
2614 processed[lFESpace.DecodeDof(h_dofs[p])] = 1;
2615 }
2616 }
2617}
2618
2619
2622 const FiniteElementSpace& lFESpace_,
2623 const FiniteElementSpace& hFESpace_)
2624 : Operator(hFESpace_.GetVSize(), lFESpace_.GetVSize()), lFESpace(lFESpace_),
2625 hFESpace(hFESpace_)
2626{
2627 // Assuming the same element type
2628 Mesh* mesh = lFESpace.GetMesh();
2629 dim = mesh->Dimension();
2630 const FiniteElement& el = *lFESpace.GetTypicalFE();
2631
2632 const TensorBasisElement* ltel =
2633 dynamic_cast<const TensorBasisElement*>(&el);
2634 MFEM_VERIFY(ltel, "Low order FE space must be tensor product space");
2635
2636 const TensorBasisElement* htel =
2637 dynamic_cast<const TensorBasisElement*>(hFESpace.GetTypicalFE());
2638 MFEM_VERIFY(htel, "High order FE space must be tensor product space");
2639 const Array<int>& hdofmap = htel->GetDofMap();
2640
2641 const IntegrationRule& ir = hFESpace.GetTypicalFE()->GetNodes();
2642 IntegrationRule irLex = ir;
2643
2644 // The quadrature points, or equivalently, the dofs of the high order space
2645 // must be sorted in lexicographical order
2646 for (int i = 0; i < ir.GetNPoints(); ++i)
2647 {
2648 int j = hdofmap[i] >=0 ? hdofmap[i] : -1 - hdofmap[i];
2649 irLex.IntPoint(i) = ir.IntPoint(j);
2650 }
2651
2652 NE = lFESpace.GetNE();
2653 const DofToQuad& maps = el.GetDofToQuad(irLex, DofToQuad::TENSOR);
2654
2655 D1D = maps.ndof;
2656 Q1D = maps.nqpt;
2657 B = maps.B;
2658 Bt = maps.Bt;
2659
2660 elem_restrict_lex_l =
2662
2663 MFEM_VERIFY(elem_restrict_lex_l,
2664 "Low order ElementRestriction not available");
2665
2666 elem_restrict_lex_h =
2668
2669 MFEM_VERIFY(elem_restrict_lex_h,
2670 "High order ElementRestriction not available");
2671
2672 localL.SetSize(elem_restrict_lex_l->Height(), Device::GetMemoryType());
2673 localH.SetSize(elem_restrict_lex_h->Height(), Device::GetMemoryType());
2674 localL.UseDevice(true);
2675 localH.UseDevice(true);
2676
2677 MFEM_VERIFY(dynamic_cast<const ElementRestriction*>(elem_restrict_lex_h),
2678 "High order element restriction is of unsupported type");
2679
2680 mask.SetSize(localH.Size(), Device::GetMemoryType());
2681 static_cast<const ElementRestriction*>(elem_restrict_lex_h)
2682 ->BooleanMask(mask);
2683 mask.UseDevice(true);
2684}
2685
2686namespace TransferKernels
2687{
2688void Prolongation2D(const int NE, const int D1D, const int Q1D,
2689 const Vector& localL, Vector& localH,
2690 const Array<real_t>& B, const Vector& mask)
2691{
2692 auto x_ = Reshape(localL.Read(), D1D, D1D, NE);
2693 auto y_ = Reshape(localH.Write(), Q1D, Q1D, NE);
2694 auto B_ = Reshape(B.Read(), Q1D, D1D);
2695 auto m_ = Reshape(mask.Read(), Q1D, Q1D, NE);
2696
2697 mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
2698 {
2699 for (int qy = 0; qy < Q1D; ++qy)
2700 {
2701 for (int qx = 0; qx < Q1D; ++qx)
2702 {
2703 y_(qx, qy, e) = 0.0;
2704 }
2705 }
2706
2707 for (int dy = 0; dy < D1D; ++dy)
2708 {
2709 real_t sol_x[DofQuadLimits::MAX_Q1D];
2710 for (int qy = 0; qy < Q1D; ++qy)
2711 {
2712 sol_x[qy] = 0.0;
2713 }
2714 for (int dx = 0; dx < D1D; ++dx)
2715 {
2716 const real_t s = x_(dx, dy, e);
2717 for (int qx = 0; qx < Q1D; ++qx)
2718 {
2719 sol_x[qx] += B_(qx, dx) * s;
2720 }
2721 }
2722 for (int qy = 0; qy < Q1D; ++qy)
2723 {
2724 const real_t d2q = B_(qy, dy);
2725 for (int qx = 0; qx < Q1D; ++qx)
2726 {
2727 y_(qx, qy, e) += d2q * sol_x[qx];
2728 }
2729 }
2730 }
2731 for (int qy = 0; qy < Q1D; ++qy)
2732 {
2733 for (int qx = 0; qx < Q1D; ++qx)
2734 {
2735 y_(qx, qy, e) *= m_(qx, qy, e);
2736 }
2737 }
2738 });
2739}
2740
2741void Prolongation3D(const int NE, const int D1D, const int Q1D,
2742 const Vector& localL, Vector& localH,
2743 const Array<real_t>& B, const Vector& mask)
2744{
2745 auto x_ = Reshape(localL.Read(), D1D, D1D, D1D, NE);
2746 auto y_ = Reshape(localH.Write(), Q1D, Q1D, Q1D, NE);
2747 auto B_ = Reshape(B.Read(), Q1D, D1D);
2748 auto m_ = Reshape(mask.Read(), Q1D, Q1D, Q1D, NE);
2749
2750 mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
2751 {
2752 for (int qz = 0; qz < Q1D; ++qz)
2753 {
2754 for (int qy = 0; qy < Q1D; ++qy)
2755 {
2756 for (int qx = 0; qx < Q1D; ++qx)
2757 {
2758 y_(qx, qy, qz, e) = 0.0;
2759 }
2760 }
2761 }
2762
2763 for (int dz = 0; dz < D1D; ++dz)
2764 {
2765 real_t sol_xy[DofQuadLimits::MAX_Q1D][DofQuadLimits::MAX_Q1D];
2766 for (int qy = 0; qy < Q1D; ++qy)
2767 {
2768 for (int qx = 0; qx < Q1D; ++qx)
2769 {
2770 sol_xy[qy][qx] = 0.0;
2771 }
2772 }
2773 for (int dy = 0; dy < D1D; ++dy)
2774 {
2775 real_t sol_x[DofQuadLimits::MAX_Q1D];
2776 for (int qx = 0; qx < Q1D; ++qx)
2777 {
2778 sol_x[qx] = 0;
2779 }
2780 for (int dx = 0; dx < D1D; ++dx)
2781 {
2782 const real_t s = x_(dx, dy, dz, e);
2783 for (int qx = 0; qx < Q1D; ++qx)
2784 {
2785 sol_x[qx] += B_(qx, dx) * s;
2786 }
2787 }
2788 for (int qy = 0; qy < Q1D; ++qy)
2789 {
2790 const real_t wy = B_(qy, dy);
2791 for (int qx = 0; qx < Q1D; ++qx)
2792 {
2793 sol_xy[qy][qx] += wy * sol_x[qx];
2794 }
2795 }
2796 }
2797 for (int qz = 0; qz < Q1D; ++qz)
2798 {
2799 const real_t wz = B_(qz, dz);
2800 for (int qy = 0; qy < Q1D; ++qy)
2801 {
2802 for (int qx = 0; qx < Q1D; ++qx)
2803 {
2804 y_(qx, qy, qz, e) += wz * sol_xy[qy][qx];
2805 }
2806 }
2807 }
2808 }
2809 for (int qz = 0; qz < Q1D; ++qz)
2810 {
2811 for (int qy = 0; qy < Q1D; ++qy)
2812 {
2813 for (int qx = 0; qx < Q1D; ++qx)
2814 {
2815 y_(qx, qy, qz, e) *= m_(qx, qy, qz, e);
2816 }
2817 }
2818 }
2819 });
2820}
2821
2822void Restriction2D(const int NE, const int D1D, const int Q1D,
2823 const Vector& localH, Vector& localL,
2824 const Array<real_t>& Bt, const Vector& mask)
2825{
2826 auto x_ = Reshape(localH.Read(), Q1D, Q1D, NE);
2827 auto y_ = Reshape(localL.Write(), D1D, D1D, NE);
2828 auto Bt_ = Reshape(Bt.Read(), D1D, Q1D);
2829 auto m_ = Reshape(mask.Read(), Q1D, Q1D, NE);
2830
2831 mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
2832 {
2833 for (int dy = 0; dy < D1D; ++dy)
2834 {
2835 for (int dx = 0; dx < D1D; ++dx)
2836 {
2837 y_(dx, dy, e) = 0.0;
2838 }
2839 }
2840
2841 for (int qy = 0; qy < Q1D; ++qy)
2842 {
2843 real_t sol_x[DofQuadLimits::MAX_D1D];
2844 for (int dx = 0; dx < D1D; ++dx)
2845 {
2846 sol_x[dx] = 0.0;
2847 }
2848 for (int qx = 0; qx < Q1D; ++qx)
2849 {
2850 const real_t s = m_(qx, qy, e) * x_(qx, qy, e);
2851 for (int dx = 0; dx < D1D; ++dx)
2852 {
2853 sol_x[dx] += Bt_(dx, qx) * s;
2854 }
2855 }
2856 for (int dy = 0; dy < D1D; ++dy)
2857 {
2858 const real_t q2d = Bt_(dy, qy);
2859 for (int dx = 0; dx < D1D; ++dx)
2860 {
2861 y_(dx, dy, e) += q2d * sol_x[dx];
2862 }
2863 }
2864 }
2865 });
2866}
2867void Restriction3D(const int NE, const int D1D, const int Q1D,
2868 const Vector& localH, Vector& localL,
2869 const Array<real_t>& Bt, const Vector& mask)
2870{
2871 auto x_ = Reshape(localH.Read(), Q1D, Q1D, Q1D, NE);
2872 auto y_ = Reshape(localL.Write(), D1D, D1D, D1D, NE);
2873 auto Bt_ = Reshape(Bt.Read(), D1D, Q1D);
2874 auto m_ = Reshape(mask.Read(), Q1D, Q1D, Q1D, NE);
2875
2876 mfem::forall(NE, [=] MFEM_HOST_DEVICE (int e)
2877 {
2878 for (int dz = 0; dz < D1D; ++dz)
2879 {
2880 for (int dy = 0; dy < D1D; ++dy)
2881 {
2882 for (int dx = 0; dx < D1D; ++dx)
2883 {
2884 y_(dx, dy, dz, e) = 0.0;
2885 }
2886 }
2887 }
2888
2889 for (int qz = 0; qz < Q1D; ++qz)
2890 {
2891 real_t sol_xy[DofQuadLimits::MAX_D1D][DofQuadLimits::MAX_D1D];
2892 for (int dy = 0; dy < D1D; ++dy)
2893 {
2894 for (int dx = 0; dx < D1D; ++dx)
2895 {
2896 sol_xy[dy][dx] = 0;
2897 }
2898 }
2899 for (int qy = 0; qy < Q1D; ++qy)
2900 {
2901 real_t sol_x[DofQuadLimits::MAX_D1D];
2902 for (int dx = 0; dx < D1D; ++dx)
2903 {
2904 sol_x[dx] = 0;
2905 }
2906 for (int qx = 0; qx < Q1D; ++qx)
2907 {
2908 const real_t s = m_(qx, qy, qz, e) * x_(qx, qy, qz, e);
2909 for (int dx = 0; dx < D1D; ++dx)
2910 {
2911 sol_x[dx] += Bt_(dx, qx) * s;
2912 }
2913 }
2914 for (int dy = 0; dy < D1D; ++dy)
2915 {
2916 const real_t wy = Bt_(dy, qy);
2917 for (int dx = 0; dx < D1D; ++dx)
2918 {
2919 sol_xy[dy][dx] += wy * sol_x[dx];
2920 }
2921 }
2922 }
2923 for (int dz = 0; dz < D1D; ++dz)
2924 {
2925 const real_t wz = Bt_(dz, qz);
2926 for (int dy = 0; dy < D1D; ++dy)
2927 {
2928 for (int dx = 0; dx < D1D; ++dx)
2929 {
2930 y_(dx, dy, dz, e) += wz * sol_xy[dy][dx];
2931 }
2932 }
2933 }
2934 }
2935 });
2936}
2937} // namespace TransferKernels
2938
2940 Vector& y) const
2941{
2942 if (lFESpace.GetMesh()->GetNE() == 0)
2943 {
2944 return;
2945 }
2946
2947 elem_restrict_lex_l->Mult(x, localL);
2948 if (dim == 2)
2949 {
2950 TransferKernels::Prolongation2D(NE, D1D, Q1D, localL, localH, B, mask);
2951 }
2952 else if (dim == 3)
2953 {
2954 TransferKernels::Prolongation3D(NE, D1D, Q1D, localL, localH, B, mask);
2955 }
2956 else
2957 {
2958 MFEM_ABORT("TensorProductPRefinementTransferOperator::Mult not "
2959 "implemented for dim = "
2960 << dim);
2961 }
2962 elem_restrict_lex_h->MultTranspose(localH, y);
2963}
2964
2966 Vector& y) const
2967{
2968 if (lFESpace.GetMesh()->GetNE() == 0)
2969 {
2970 return;
2971 }
2972
2973 elem_restrict_lex_h->Mult(x, localH);
2974 if (dim == 2)
2975 {
2976 TransferKernels::Restriction2D(NE, D1D, Q1D, localH, localL, Bt, mask);
2977 }
2978 else if (dim == 3)
2979 {
2980 TransferKernels::Restriction3D(NE, D1D, Q1D, localH, localL, Bt, mask);
2981 }
2982 else
2983 {
2984 MFEM_ABORT("TensorProductPRefinementTransferOperator::MultTranspose not "
2985 "implemented for dim = "
2986 << dim);
2987 }
2988 elem_restrict_lex_l->MultTranspose(localL, y);
2989}
2990
2991
2993 const FiniteElementSpace& hFESpace_)
2994 : Operator(hFESpace_.GetTrueVSize(), lFESpace_.GetTrueVSize()),
2995 lFESpace(lFESpace_),
2996 hFESpace(hFESpace_)
2997{
2998 localTransferOperator = new TransferOperator(lFESpace_, hFESpace_);
2999
3000 P = lFESpace.GetProlongationMatrix();
3001 R = hFESpace.IsVariableOrder() ? hFESpace.GetHpRestrictionMatrix() :
3002 hFESpace.GetRestrictionMatrix();
3003
3004 // P and R can be both null
3005 // P can be null and R not null
3006 // If P is not null it is assumed that R is not null as well
3007 if (P) { MFEM_VERIFY(R, "Both P and R have to be not NULL") }
3008
3009 if (P)
3010 {
3011 tmpL.SetSize(lFESpace_.GetVSize());
3012 tmpH.SetSize(hFESpace_.GetVSize());
3013 }
3014 // P can be null and R not null
3015 else if (R)
3016 {
3017 tmpH.SetSize(hFESpace_.GetVSize());
3018 }
3019}
3020
3022{
3023 delete localTransferOperator;
3024}
3025
3027{
3028 if (P)
3029 {
3030 P->Mult(x, tmpL);
3031 localTransferOperator->Mult(tmpL, tmpH);
3032 R->Mult(tmpH, y);
3033 }
3034 else if (R)
3035 {
3036 localTransferOperator->Mult(x, tmpH);
3037 R->Mult(tmpH, y);
3038 }
3039 else
3040 {
3041 localTransferOperator->Mult(x, y);
3042 }
3043}
3044
3046{
3047 if (P)
3048 {
3049 R->MultTranspose(x, tmpH);
3050 localTransferOperator->MultTranspose(tmpH, tmpL);
3051 P->MultTranspose(tmpL, y);
3052 }
3053 else if (R)
3054 {
3055 R->MultTranspose(x, tmpH);
3056 localTransferOperator->MultTranspose(tmpH, y);
3057 }
3058 else
3059 {
3060 localTransferOperator->MultTranspose(x, y);
3061 }
3062}
3063
3064} // 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 Copy(Array &copy) const
Create a copy of the internal array to the provided copy.
Definition array.hpp:1071
const T * Read(bool on_dev=true) const
Shortcut for mfem::Read(a.GetMemory(), a.Size(), on_dev).
Definition array.hpp:410
static void Mult(const DenseTensor &A, const Vector &x, Vector &y)
Computes (e.g. by calling AddMult(A,x,y,1,0,Op::N)).
Definition batched.cpp:61
static void MultTranspose(const DenseTensor &A, const Vector &x, Vector &y)
Computes (e.g. by calling AddMult(A,x,y,1,0,Op::T)).
Definition batched.cpp:66
static void Invert(DenseTensor &A)
Replaces the block diagonal matrix with its inverse .
Definition batched.cpp:72
Abstract base class BilinearFormIntegrator.
A "square matrix" operator for the associated FE space and BLFIntegrators The sum of all the BLFInteg...
void SetAssemblyLevel(AssemblyLevel assembly_level)
Set the desired assembly level.
void AddDomainIntegrator(BilinearFormIntegrator *bfi)
Adds new Domain Integrator. Assumes ownership of bfi.
void Assemble(int skip_zeros=1)
Assembles the form i.e. sums over all domain/bdr integrators.
void Mult(const Vector &x, Vector &y) const override
Matrix vector multiplication: .
void SetOperator(const Operator &op) override
Set/update the solver for the given operator.
Definition solvers.hpp:640
Class to represent a coefficient evaluated at quadrature points.
virtual real_t Eval(ElementTransformation &T, const IntegrationPoint &ip)=0
Evaluate the coefficient in the element described by T at the point ip.
Jacobi-type diagonal smoother of a sparse matrix.
void Factor()
Factor the current DenseMatrix, *a.
void Mult(const real_t *x, real_t *y) const
Matrix vector multiplication with the inverse of dense matrix.
void GetInverseMatrix(DenseMatrix &Ainv) const
Compute and return the inverse matrix in Ainv.
Data type dense matrix using column-major storage.
Definition densemat.hpp:24
void Mult(const real_t *x, real_t *y) const
Matrix vector multiplication.
Definition densemat.cpp:108
void Transpose()
(*this) = (*this)^t
void SetRow(int r, const real_t *row)
real_t * GetData() const
Returns the matrix data array. Warning: this method casts away constness.
Definition densemat.hpp:135
void SetSize(int s)
Change the size of the DenseMatrix to s x s.
Definition densemat.hpp:125
void CopyMN(const DenseMatrix &A, int m, int n, int Aro, int Aco)
Copy the m x n submatrix of A at row/col offsets Aro/Aco to *this.
void GetRow(int r, Vector &row) const
Rank 3 tensor (array of matrices)
void SetSize(int i, int j, int k, MemoryType mt_=MemoryType::PRESERVE)
Memory< real_t > & GetMemory()
void NewMemoryAndSize(const Memory< real_t > &mem, int i, int j, int k, bool own_mem)
Reset the DenseTensor to use the given external Memory mem and dimensions i, j, and k.
const real_t * Read(bool on_dev=true) const
Shortcut for mfem::Read( GetMemory(), TotalSize(), on_dev).
real_t * Write(bool on_dev=true)
Shortcut for mfem::Write(GetMemory(), TotalSize(), on_dev).
int SizeI() const
int SizeK() const
The MFEM Device class abstracts hardware devices such as GPUs, as well as programming models such as ...
Definition device.hpp:129
static MemoryType GetMemoryType()
(DEPRECATED) Equivalent to GetDeviceMemoryType().
Definition device.hpp:302
Structure representing the matrices/tensors needed to evaluate (in reference space) the values,...
Definition fe_base.hpp:141
@ TENSOR
Tensor product representation using 1D matrices/tensors with dimensions using 1D number of quadrature...
Definition fe_base.hpp:165
Array< real_t > B
Basis functions evaluated at quadrature points.
Definition fe_base.hpp:201
int ndof
Number of degrees of freedom = number of basis functions. When mode is TENSOR, this is the 1D number.
Definition fe_base.hpp:186
int nqpt
Number of quadrature points. When mode is TENSOR, this is the 1D number.
Definition fe_base.hpp:190
Array< real_t > Bt
Transpose of B.
Definition fe_base.hpp:207
void TransformDual(real_t *v) const
Definition doftrans.cpp:77
void InvTransformPrimal(real_t *v) const
Definition doftrans.cpp:47
void InvTransformDual(real_t *v) const
Definition doftrans.cpp:107
void TransformPrimal(real_t *v) const
Definition doftrans.cpp:17
Operator that converts FiniteElementSpace L-vectors to E-vectors.
real_t Weight()
Return the weight of the Jacobian matrix of the transformation at the currently set IntegrationPoint....
Definition eltrans.hpp:144
virtual int OrderW() const =0
Return the order of the determinant of the Jacobian (weight) of the transformation.
void SetIntPoint(const IntegrationPoint *ip)
Set the integration point ip that weights and Jacobians will be evaluated at.
Definition eltrans.hpp:106
virtual int GetContType() const =0
@ DISCONTINUOUS
Field is discontinuous across element interfaces.
Definition fe_coll.hpp:48
@ CONTINUOUS
Field is continuous across element interfaces.
Definition fe_coll.hpp:45
Derefinement operator, used by the friend class InterpolationGridTransfer.
Definition fespace.hpp:518
GridFunction interpolation operator applicable after mesh refinement.
Definition fespace.hpp:492
Class FiniteElementSpace - responsible for providing FEM view of the mesh, mainly managing the set of...
Definition fespace.hpp:210
void GetVDofs(int vd, Array< int > &dofs, int ndofs=-1) const
Returns the indices of all of the VDofs for the specified dimension 'vd'.
Definition fespace.cpp:212
const SparseMatrix * GetConformingRestriction() const
The returned SparseMatrix is owned by the FiniteElementSpace.
Definition fespace.cpp:1429
bool IsVariableOrder() const
Returns true if the space contains elements of varying polynomial orders.
Definition fespace.hpp:673
const Table & GetElementToDofTable() const
Return a reference to the internal Table that stores the lists of scalar dofs, for each mesh element,...
Definition fespace.hpp:1278
void DofsToVDofs(Array< int > &dofs, int ndofs=-1) const
Compute the full set of vdofs corresponding to each entry in dofs.
Definition fespace.cpp:232
virtual int GetTrueVSize() const
Return the number of vector true (conforming) dofs.
Definition fespace.hpp:827
DofTransformation * GetElementDofs(int elem, Array< int > &dofs) const
Returns indices of degrees of freedom of element 'elem'. The returned indices are offsets into an ldo...
Definition fespace.cpp:3538
ElementTransformation * GetElementTransformation(int i) const
Definition fespace.hpp:903
virtual const SparseMatrix * GetRestrictionMatrix() const
The returned SparseMatrix is owned by the FiniteElementSpace.
Definition fespace.hpp:714
virtual int GetFaceDofs(int face, Array< int > &dofs, int variant=0) const
Returns the indices of the degrees of freedom for the specified face, including the DOFs for the edge...
Definition fespace.cpp:3650
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
int GetNDofs() const
Returns number of degrees of freedom. This is the number of Local Degrees of Freedom.
Definition fespace.hpp:821
void GetLocalRefinementMatrices(Geometry::Type geom, DenseTensor &localP) const
Definition fespace.cpp:1788
void GetTransferOperator(const FiniteElementSpace &coarse_fes, OperatorHandle &T) const
Construct and return an Operator that can be used to transfer GridFunction data from coarse_fes,...
Definition fespace.cpp:4080
virtual const Operator * GetProlongationMatrix() const
Definition fespace.hpp:691
virtual const Operator * GetRestrictionOperator() const
An abstract operator that performs the same action as GetRestrictionMatrix.
Definition fespace.hpp:710
virtual const FiniteElement * GetFE(int i) const
Returns pointer to the FiniteElement in the FiniteElementCollection associated with i'th element in t...
Definition fespace.cpp:3860
int GetNE() const
Returns number of elements in the mesh.
Definition fespace.hpp:867
const ElementRestrictionOperator * GetElementRestriction(ElementDofOrdering e_ordering) const
Return an Operator that converts L-vectors to E-vectors.
Definition fespace.cpp:1476
SparseMatrix * RefinementMatrix_main(const int coarse_ndofs, const Table &coarse_elem_dof, const Table *coarse_elem_fos, const DenseTensor localP[]) const
Definition fespace.cpp:1663
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
const FiniteElement * GetFaceElement(int i) const
Returns pointer to the FiniteElement in the FiniteElementCollection associated with i'th face in the ...
Definition fespace.cpp:3949
const SparseMatrix * GetConformingProlongation() const
Definition fespace.cpp:1422
const FiniteElementCollection * FEColl() const
Definition fespace.hpp:854
Mesh * GetMesh() const
Returns the mesh.
Definition fespace.hpp:639
int GetVSize() const
Return the number of vector dofs, i.e. GetNDofs() x GetVDim().
Definition fespace.hpp:824
const Table * GetElementToFaceOrientationTable() const
Definition fespace.hpp:1274
int GetVDim() const
Returns the vector dimension of the finite element space.
Definition fespace.hpp:817
virtual const SparseMatrix * GetHpRestrictionMatrix() const
The returned SparseMatrix is owned by the FiniteElementSpace.
Definition fespace.hpp:718
const FiniteElement * GetTypicalFE() const
Return GetFE(0) if the local mesh is not empty; otherwise return a typical FE based on the Geometry t...
Definition fespace.cpp:3896
static int DecodeDof(int dof)
Helper to return the DOF associated with a sign encoded DOF.
Definition fespace.hpp:1153
Abstract class for all finite elements.
Definition fe_base.hpp:294
virtual const DofToQuad & GetDofToQuad(const IntegrationRule &ir, DofToQuad::Mode mode) const
Return a DofToQuad structure corresponding to the given IntegrationRule using the given DofToQuad::Mo...
Definition fe_base.cpp:373
int GetOrder() const
Returns the order of the finite element. In the case of anisotropic orders, returns the maximum order...
Definition fe_base.hpp:414
virtual void GetTransferMatrix(const FiniteElement &fe, ElementTransformation &Trans, DenseMatrix &I) const
Return interpolation matrix, I, which maps dofs from a coarse element, fe, to the fine dofs on this f...
Definition fe_base.cpp:129
int GetMapType() const
Returns the FiniteElement::MapType of the element describing how reference functions are mapped to ph...
Definition fe_base.hpp:436
const IntegrationRule & GetNodes() const
Get a const reference to the nodes of the element.
Definition fe_base.hpp:476
Geometry::Type GetGeomType() const
Returns the Geometry::Type of the reference element.
Definition fe_base.hpp:407
virtual void CalcShape(const IntegrationPoint &ip, Vector &shape) const =0
Evaluate the values of all shape functions of a scalar finite element in reference space at the given...
int GetDof() const
Returns the number of degrees of freedom in the finite element.
Definition fe_base.hpp:410
void CalcPhysShape(ElementTransformation &Trans, Vector &shape) const
Evaluate the values of all shape functions of a scalar finite element in physical space at the point ...
Definition fe_base.cpp:192
Structure for storing mesh geometric factors: coordinates, Jacobians, and determinants of the Jacobia...
Definition mesh.hpp:3119
Vector detJ
Determinants of the Jacobians at all quadrature points.
Definition mesh.hpp:3164
static const int NumGeom
Definition geom.hpp:46
bool Parallel() const
Definition transfer.hpp:52
FiniteElementSpace & dom_fes
Domain FE space.
Definition transfer.hpp:34
FiniteElementSpace & ran_fes
Range FE space.
Definition transfer.hpp:35
MemoryType d_mt
Definition transfer.hpp:47
Operator::Type oper_type
Desired Operator::Type for the construction of all operators defined by the underlying transfer algor...
Definition transfer.hpp:40
const Operator & MakeTrueOperator(FiniteElementSpace &fes_in, FiniteElementSpace &fes_out, const Operator &oper, OperatorHandle &t_oper)
Definition transfer.cpp:35
GridTransfer(FiniteElementSpace &dom_fes_, FiniteElementSpace &ran_fes_)
Definition transfer.cpp:20
Arbitrary order "H^{1/2}-conforming" trace finite elements defined on the interface between mesh elem...
Definition fe_coll.hpp:357
The BoomerAMG solver in hypre.
Definition hypre.hpp:1829
void SetPrintLevel(int print_level)
Definition hypre.hpp:1912
Wrapper for hypre's ParCSR matrix class.
Definition hypre.hpp:419
HypreParMatrix * LeftDiagMult(const SparseMatrix &D, HYPRE_BigInt *row_starts=NULL) const
Multiply the HypreParMatrix on the left by a block-diagonal parallel matrix D and return the result a...
Definition hypre.cpp:2052
HypreParMatrix * Transpose() const
Returns the transpose of *this.
Definition hypre.cpp:1742
IsoparametricTransformation Transf
Definition eltrans.hpp:733
void Transform(const IntegrationPoint &, IntegrationPoint &)
Definition eltrans.cpp:587
Class for integration point with weight.
Definition intrules.hpp:35
Class for an integration rule - an Array of IntegrationPoint.
Definition intrules.hpp:96
int GetNPoints() const
Returns the number of the points in the integration rule.
Definition intrules.hpp:255
const Array< real_t > & GetWeights() const
Return the quadrature weights in a contiguous array.
Definition intrules.cpp:98
IntegrationPoint & IntPoint(int i)
Returns a reference to the i-th integration point.
Definition intrules.hpp:258
const IntegrationRule & Get(int GeomType, int Order)
Returns an integration rule for given GeomType and Order.
void SetIntegrationRule(const IntegrationRule &ir)
Prescribe a fixed IntegrationRule to use. Sets the NURBS patch integration rule to null.
BilinearFormIntegrator * mass_integ
Ownership depends on own_mass_integ.
Definition transfer.hpp:141
OperatorHandle F
Forward, coarse-to-fine, operator.
Definition transfer.hpp:144
bool own_mass_integ
Ownership flag for mass_integ.
Definition transfer.hpp:142
const Operator & BackwardOperator() override
Return an Operator that transfers GridFunctions from the range FE space back to GridFunctions in the ...
Definition transfer.cpp:190
OperatorHandle B
Backward, fine-to-coarse, operator.
Definition transfer.hpp:145
void SetMassIntegrator(BilinearFormIntegrator *mass_integ_, bool own_mass_integ_=true)
Assign a mass integrator to be used in the construction of the backward, fine-to-coarse,...
Definition transfer.cpp:147
const Operator & ForwardOperator() override
Return an Operator that transfers GridFunctions from the domain FE space to GridFunctions in the rang...
Definition transfer.cpp:156
A standard isoparametric element transformation.
Definition eltrans.hpp:629
void SetPointMat(const DenseMatrix &pm)
Set the underlying point matrix describing the transformation.
Definition eltrans.hpp:668
void SetIdentityTransformation(Geometry::Type GeomType)
Set the FiniteElement Geometry for the reference elements being used.
Definition eltrans.cpp:417
virtual void SetPreconditioner(Solver &pr)
This should be called before SetOperator.
Definition solvers.cpp:178
void MultTranspose(const Vector &x, Vector &y) const
Action of the transpose operator: y=A^t(x). The default behavior in class Operator is to generate an ...
H1SpaceLumpedMassOperator(const FiniteElementSpace *fes_ho_, const FiniteElementSpace *fes_lor_, Vector &ML_inv_)
void Mult(const Vector &x, Vector &y) const
Operator application: y=A(x).
void Mult(const Vector &x, Vector &y) const
Operator application: y=A(x).
void MultTranspose(const Vector &x, Vector &y) const
Action of the transpose operator: y=A^t(x). The default behavior in class Operator is to generate an ...
H1SpaceMixedMassOperator(const FiniteElementSpace *fes_ho_, const FiniteElementSpace *fes_lor_, Table *ho2lor_, Vector *M_LH_ea_)
void Mult(const Vector &x, Vector &y) const override
void SetFromTDofsTranspose(const FiniteElementSpace &fes, const Vector &X, Vector &x) const
Sets dual field coefficients given a vector of dual field coefficients on the tdofs and a finite elem...
std::unique_ptr< FiniteElementSpace > fes_ho_scalar
Definition transfer.hpp:523
std::unique_ptr< ParFiniteElementSpace > pfes_ho_scalar
Definition transfer.hpp:531
void TDofsListByVDim(const FiniteElementSpace &fes, int vdim, Array< int > &vdofs_list) const
Fills the vdofs_list array with a list of vdofs for a given vdim and a given finite element space.
void SetupPCG()
Sets up the PCG solver (sets parameters, operator, and preconditioner)
void Prolongate(const Vector &x, Vector &y) const override
void GetTDofs(const FiniteElementSpace &fes, const Vector &x, Vector &X) const
Recovers vector of tdofs given a vector of dofs and a finite element space.
void SetFromTDofs(const FiniteElementSpace &fes, const Vector &X, Vector &x) const
Sets dof values given a vector of tdofs and a finite element space.
void GetTDofsTranspose(const FiniteElementSpace &fes, const Vector &x, Vector &X) const
Recovers a vector of dual field coefficients on the tdofs given a vector of dual coefficients and a f...
L2ProjectionH1Space(const FiniteElementSpace &fes_ho_, const FiniteElementSpace &fes_lor_, CoefficientWithOrder coeff_ho_, CoefficientWithOrder coeff_lor_, const bool use_ea_, MemoryType d_mt_=Device::GetHostMemoryType())
std::unique_ptr< SparseMatrix > AllocR()
Computes sparsity pattern and initializes R matrix. Based on BilinearForm::AllocMat(),...
void MultTranspose(const Vector &x, Vector &y) const override
void LumpedMassInverse(Vector &ML_inv) const
Returns the inverse of an on-rank lumped mass matrix.
std::unique_ptr< FiniteElementSpace > fes_lor_scalar
Definition transfer.hpp:524
void SetAbsTol(real_t p_atol_) override
Sets absolute tolerance in preconditioned conjugate gradient solver.
void ProlongateTranspose(const Vector &x, Vector &y) const override
std::pair< std::unique_ptr< SparseMatrix >, std::unique_ptr< SparseMatrix > > ComputeSparseRAndM_LH()
Computes on-rank R and M_LH matrices. If true, computes mixed mass and/or inverse lumped mass matrix ...
void SetRelTol(real_t p_rtol_) override
Sets relative tolerance in preconditioned conjugate gradient solver.
std::unique_ptr< ParFiniteElementSpace > pfes_lor_scalar
Definition transfer.hpp:532
void ProlongateTranspose(const Vector &x, Vector &y) const override
void EAMultTranspose(const Vector &x, Vector &y) const
void EAProlongate(const Vector &x, Vector &y) const
L2ProjectionL2Space(const FiniteElementSpace &fes_ho_, const FiniteElementSpace &fes_lor_, CoefficientWithOrder coeff_ho_, CoefficientWithOrder coeff_lor_, const bool use_ea_, MemoryType d_mt_=Device::GetHostMemoryType())
Definition transfer.cpp:582
void MultTranspose(const Vector &x, Vector &y) const override
Definition transfer.cpp:961
void EAMult(const Vector &x, Vector &y) const
Perform mult on the device (same as above)
Definition transfer.cpp:941
void EAProlongateTranspose(const Vector &x, Vector &y) const
void Prolongate(const Vector &x, Vector &y) const override
void Mult(const Vector &x, Vector &y) const override
Definition transfer.cpp:902
L2Projection(const FiniteElementSpace &fes_ho_, const FiniteElementSpace &fes_lor_, CoefficientWithOrder coeff_ho_, CoefficientWithOrder coeff_lor_, MemoryType d_mt_=Device::GetHostMemoryType())
Definition transfer.cpp:232
void BuildHo2Lor(int nel_ho, int nel_lor, const CoarseFineTransformations &cf_tr)
Definition transfer.cpp:241
void MixedMassEA(const FiniteElementSpace &fes_ho_, const FiniteElementSpace &fes_lor_, Vector &M_LH, MemoryType d_mt_=Device::GetHostMemoryType())
Definition transfer.cpp:328
void ElemMixedEvaluation(Geometry::Type geom, const FiniteElement &fe_ho, const FiniteElement &fe_lor, IntegrationPointTransformation &ip_tr, const IntegrationRule &ir, DenseMatrix &B_L, DenseMatrix &B_H) const
Definition transfer.cpp:299
void ElemMixedMass(Geometry::Type geom, const FiniteElement &fe_ho, const FiniteElement &fe_lor, ElementTransformation *tr_ho, ElementTransformation *tr_lor, IntegrationPointTransformation &ip_tr, DenseMatrix &M_mixed_el) const
Definition transfer.cpp:261
L2Projection * F
Forward, coarse-to-fine, operator.
Definition transfer.hpp:563
CoefficientWithOrder coeff_ho
Coefficient for the mixed L2 inner product.
Definition transfer.hpp:560
CoefficientWithOrder coeff_lor
Coefficient for the low-order L2 inner product.
Definition transfer.hpp:562
const Operator & BackwardOperator() override
Return an Operator that transfers GridFunctions from the range FE space back to GridFunctions in the ...
bool SupportsBackwardsOperator() const override
L2Prolongation * B
Backward, fine-to-coarse, operator.
Definition transfer.hpp:564
const Operator & ForwardOperator() override
Return an Operator that transfers GridFunctions from the domain FE space to GridFunctions in the rang...
void AssembleElementMatrix(const FiniteElement &el, ElementTransformation &Trans, DenseMatrix &elmat) override
void AssembleEA(const FiniteElementSpace &fes, Vector &emat, const bool add) override
Method defining element assembly.
Class used by MFEM to store pointers to host and/or device memory.
void SyncAlias(const Memory &base, int alias_size) const
Update the alias Memory *this to match the memory location (all valid locations) of its base Memory,...
void CopyFrom(const Memory &src, int size)
Copy size entries from src to *this.
List of mesh geometries stored as Array<Geometry::Type>.
Definition mesh.hpp:1603
Mesh data type.
Definition mesh.hpp:67
void GetGeometries(int dim, Array< Geometry::Type > &el_geoms) const
Return all element geometries of the given dimension present in the mesh.
Definition mesh.cpp:8025
int GetNumFaces() const
Return the number of faces (3D), edges (2D) or vertices (1D).
Definition mesh.cpp:7302
Geometry::Type GetFaceGeometry(int i) const
Return the Geometry::Type associated with face i.
Definition mesh.cpp:1651
Geometry::Type GetTypicalElementGeometry() const
If the local mesh is not empty, return GetElementGeometry(0); otherwise, return a typical Geometry pr...
Definition mesh.cpp:1705
const CoarseFineTransformations & GetRefinementTransforms() const
Definition mesh.cpp:12237
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
ElementTransformation * GetTypicalElementTransformation()
If the local mesh is not empty return GetElementTransformation(0); otherwise, return the identity tra...
Definition mesh.cpp:394
void GetElementTransformation(int i, IsoparametricTransformation *ElTr) const
Builds the transformation defining the i-th element in ElTr. ElTr must be allocated in advance and wi...
Definition mesh.cpp:361
const GeometricFactors * GetGeometricFactors(const IntegrationRule &ir, const int flags, MemoryType d_mt=MemoryType::DEFAULT)
Return the mesh geometric factors corresponding to the given integration rule.
Definition mesh.cpp:958
Geometry::Type GetElementBaseGeometry(int i) const
Definition mesh.hpp:1569
Arbitrary order H(curl)-trace finite elements defined on the interface between mesh elements (faces,...
Definition fe_coll.hpp:575
Pointer to an Operator of a specified type.
Definition handle.hpp:34
OpType * As() const
Return the Operator pointer statically cast to a specified OpType. Similar to the method Get().
Definition handle.hpp:104
void SetOperatorOwner(bool own=true)
Set the ownership flag for the held Operator.
Definition handle.hpp:120
Operator * Ptr() const
Access the underlying Operator pointer.
Definition handle.hpp:87
void Reset(OpType *A, bool own_A=true)
Reset the OperatorHandle to the given OpType pointer, A.
Definition handle.hpp:145
Jacobi smoothing for a given bilinear form (no matrix necessary).
Definition solvers.hpp:422
Abstract operator.
Definition operator.hpp:27
Operator(int s=0)
Construct a square Operator with given size s (default 0).
Definition operator.hpp:61
int Height() const
Get the height (size of output) of the Operator. Synonym with NumRows().
Definition operator.hpp:68
virtual void Mult(const Vector &x, Vector &y) const =0
Operator application: y=A(x).
int Width() const
Get the width (size of input) of the Operator. Synonym with NumCols().
Definition operator.hpp:74
@ ANY_TYPE
ID for the base class Operator, i.e. any type.
Definition operator.hpp:320
@ MFEM_SPARSEMAT
ID for class SparseMatrix.
Definition operator.hpp:321
@ Hypre_ParCSR
ID for class HypreParMatrix.
Definition operator.hpp:322
virtual void MultTranspose(const Vector &x, Vector &y) const
Action of the transpose operator: y=A^t(x). The default behavior in class Operator is to generate an ...
Definition operator.hpp:102
Matrix-free transfer operator between finite element spaces on the same mesh.
Definition transfer.hpp:636
void MultTranspose(const Vector &x, Vector &y) const override
Restriction by applying the transpose of the Mult method.
PRefinementTransferOperator(const FiniteElementSpace &lFESpace_, const FiniteElementSpace &hFESpace_, bool assemble_matrix=false)
Constructs a transfer operator from lFESpace to hFESpace which have different FE collections.
void Mult(const Vector &x, Vector &y) const override
Interpolation or prolongation of a vector x corresponding to the coarse space to the vector y corresp...
Operator * GetTrueTransferOperator()
Return the true-dof transfer operator.
Class for parallel bilinear form.
void Assemble(int skip_zeros=1)
Assemble the local matrix.
Abstract parallel finite element space.
Definition pfespace.hpp:31
MPI_Comm GetComm() const
Definition pfespace.hpp:337
HYPRE_BigInt * GetTrueDofOffsets() const
Definition pfespace.hpp:358
HYPRE_BigInt GlobalVSize() const
Definition pfespace.hpp:359
const Operator * GetRestrictionOperator() const override
HYPRE_BigInt GlobalTrueVSize() const
Definition pfespace.hpp:361
HYPRE_BigInt * GetDofOffsets() const
Definition pfespace.hpp:357
const Operator * GetProlongationMatrix() const override
HypreParMatrix * Dof_TrueDof_Matrix() const
The true dof-to-dof interpolation matrix.
Definition pfespace.hpp:403
const SparseMatrix * GetRestrictionMatrix() const override
Get the R matrix which restricts a local dof vector to true dof vector.
Definition pfespace.hpp:517
ParMesh * GetParMesh() const
Definition pfespace.hpp:341
General product operator: x -> (A*B)(x) = A(B(x)).
Definition operator.hpp:969
Class representing the storage layout of a QuadratureFunction.
Definition qspace.hpp:164
Arbitrary order "H^{-1/2}-conforming" face finite elements defined on the interface between mesh elem...
Definition fe_coll.hpp:492
Data type sparse matrix.
Definition sparsemat.hpp:51
void MultTranspose(const Vector &x, Vector &y) const override
Multiply a vector with the transposed matrix. y = At * x.
void BooleanMult(const Array< int > &x, Array< int > &y) const
y = A * x, treating all entries as booleans (zero=false, nonzero=true).
void Mult(const Vector &x, Vector &y) const override
Matrix vector multiplication.
Table stores the connectivity of elements of TYPE I to elements of TYPE II. For example,...
Definition table.hpp:43
void LoseData()
Releases ownership of and null-ifies the data.
Definition table.hpp:184
int * GetJ()
Definition table.hpp:128
int RowSize(int i) const
Definition table.hpp:122
void GetRow(int i, Array< int > &row) const
Return row i in array row (the Table must be finalized)
Definition table.cpp:233
int * GetI()
Definition table.hpp:127
void SortRows()
Sort the column (TYPE II) indices in each row.
Definition table.cpp:245
void SetDims(int rows, int nnz)
Set the rows and the number of all connections for the table.
Definition table.cpp:188
const Array< int > & GetDofMap() const
Get an Array<int> that maps lexicographically ordered indices to the indices of the respective nodes/...
Definition fe_base.hpp:1353
Matrix-free transfer operator between finite element spaces on the same mesh exploiting the tensor pr...
Definition transfer.hpp:690
void Mult(const Vector &x, Vector &y) const override
Interpolation or prolongation of a vector x corresponding to the coarse space to the vector y corresp...
TensorProductPRefinementTransferOperator(const FiniteElementSpace &lFESpace_, const FiniteElementSpace &hFESpace_)
Constructs a transfer operator from lFESpace to hFESpace which have different FE collections.
void MultTranspose(const Vector &x, Vector &y) const override
Restriction by applying the transpose of the Mult method.
Matrix-free transfer operator between finite element spaces.
Definition transfer.hpp:605
virtual ~TransferOperator()
Destructor.
void Mult(const Vector &x, Vector &y) const override
Interpolation or prolongation of a vector x corresponding to the coarse space to the vector y corresp...
void MultTranspose(const Vector &x, Vector &y) const override
Restriction by applying the transpose of the Mult method.
TransferOperator(const FiniteElementSpace &lFESpace, const FiniteElementSpace &hFESpace)
Constructs a transfer operator from lFESpace to hFESpace.
The transpose of a given operator. Switches the roles of the methods Mult() and MultTranspose().
Definition operator.hpp:922
General triple product operator x -> A*B*C*x, with ownership of the factors.
~TrueTransferOperator()
Destructor.
void MultTranspose(const Vector &x, Vector &y) const override
Restriction by applying the transpose of the Mult method.
TrueTransferOperator(const FiniteElementSpace &lFESpace_, const FiniteElementSpace &hFESpace_)
Constructs a transfer operator working on true degrees of freedom from lFESpace to hFESpace.
void Mult(const Vector &x, Vector &y) const override
Interpolation or prolongation of a true dof vector x to a true dof vector y.
Vector data type.
Definition vector.hpp:82
virtual const real_t * Read(bool on_dev=true) const
Shortcut for mfem::Read(vec.GetMemory(), vec.Size(), on_dev).
Definition vector.hpp:520
void SetSubVector(const Array< int > &dofs, const real_t value)
Set the entries listed in dofs to the given value.
Definition vector.cpp:702
Memory< real_t > & GetMemory()
Return a reference to the Memory object used by the Vector.
Definition vector.hpp:265
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
Vector & Set(const real_t a, const Vector &x)
(*this) = a * x
Definition vector.cpp:341
void NewMemoryAndSize(const Memory< real_t > &mem, int s, bool own_mem)
Reset the Vector to use the given external Memory mem and size s.
Definition vector.hpp:694
int Size() const
Returns the size of the vector.
Definition vector.hpp:234
virtual void UseDevice(bool use_dev) const
Enable execution of Vector operations using the mfem::Device.
Definition vector.hpp:145
void SetSize(int s)
Resize the vector to size s.
Definition vector.hpp:633
void Reciprocal()
(*this)(i) = 1.0 / (*this)(i)
Definition vector.cpp:384
void GetSubVector(const Array< int > &dofs, Vector &elemvect) const
Extract entries listed in dofs to the output Vector elemvect.
Definition vector.cpp:676
virtual real_t * Write(bool on_dev=true)
Shortcut for mfem::Write(vec.GetMemory(), vec.Size(), on_dev).
Definition vector.hpp:528
const int * ess_tdof_list
int dim
Definition ex24.cpp:53
real_t b
Definition lissajous.cpp:42
real_t a
Definition lissajous.cpp:41
void Prolongation2D(const int NE, const int D1D, const int Q1D, const Vector &localL, Vector &localH, const Array< real_t > &B, const Vector &mask)
void Restriction3D(const int NE, const int D1D, const int Q1D, const Vector &localH, Vector &localL, const Array< real_t > &Bt, const Vector &mask)
void Restriction2D(const int NE, const int D1D, const int Q1D, const Vector &localH, Vector &localL, const Array< real_t > &Bt, const Vector &mask)
void Prolongation3D(const int NE, const int D1D, const int Q1D, const Vector &localL, Vector &localH, const Array< real_t > &B, const Vector &mask)
void Mult(const Table &A, const Table &B, Table &C)
C = A * B (as boolean matrices)
Definition table.cpp:505
void add(const Vector &v1, const Vector &v2, Vector &v)
Definition vector.cpp:414
void Transpose(const Table &A, Table &At, int ncols_A_)
Transpose a Table.
Definition table.cpp:443
MFEM_HOST_DEVICE DeviceTensor< sizeof...(Dims), T > Reshape(T *ptr, Dims... dims)
Wrap a pointer as a DeviceTensor with automatically deduced template parameters.
Definition dtensor.hpp:138
void RAP(const DenseMatrix &A, const DenseMatrix &P, DenseMatrix &RAP)
void AddMultVWt(const Vector &v, const Vector &w, DenseMatrix &VWt)
VWt += v w^t.
void HypreStealOwnership(HypreParMatrix &A_hyp, SparseMatrix &A_diag)
Make A_hyp steal ownership of its diagonal part A_diag.
Definition hypre.cpp:2948
bool UsesTensorBasis(const FiniteElementSpace &fes)
Return true if the mesh contains only one topology and the elements are tensor elements.
Definition fespace.hpp:1644
HypreParMatrix * ParMult(const HypreParMatrix *A, const HypreParMatrix *B, bool own_matrix)
Definition hypre.cpp:3057
ComplexDenseMatrix * MultAtB(const ComplexDenseMatrix &A, const ComplexDenseMatrix &B)
Multiply the complex conjugate transpose of a matrix A with a matrix B. A^H*B.
float real_t
Definition config.hpp:46
void TransformPrimal(const DofTransformation &ran_dof_trans, const DofTransformation &dom_dof_trans, DenseMatrix &elmat)
Definition doftrans.cpp:137
MemoryType
Memory types supported by MFEM.
ElementDofOrdering
Constants describing the possible orderings of the DOFs in one element.
Definition fespace.hpp:49
@ NATIVE
Native ordering as defined by the FiniteElement.
SparseMatrix * TransposeMult(const SparseMatrix &A, const SparseMatrix &B)
C = A^T B.
void forall(int N, lambda &&body)
Definition forall.hpp:1134
IntegrationRules IntRules(0, Quadrature1D::GaussLegendre)
A global object with all integration rules (defined in intrules.cpp)
Definition intrules.hpp:549
real_t p(const Vector &x, real_t t)
Defines the coarse-fine transformations of all fine elements.
Definition ncmesh.hpp:90
Array< Embedding > embeddings
Fine element positions in their parents.
Definition ncmesh.hpp:92
DenseTensor point_matrices[Geometry::NumGeom]
Definition ncmesh.hpp:96
static const DeviceDofQuadLimits & Get()
Return a const reference to the DeviceDofQuadLimits singleton.
Definition forall.hpp:138
int MAX_Q1D
Maximum number of 1D quadrature points.
Definition forall.hpp:127