MFEM  v4.5.2
Finite element discretization library
transfer.cpp
Go to the documentation of this file.
1 // Copyright (c) 2010-2023, 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 "../general/forall.hpp"
15 
16 namespace mfem
17 {
18 
20  FiniteElementSpace &ran_fes_)
21  : dom_fes(dom_fes_), ran_fes(ran_fes_),
22  oper_type(Operator::ANY_TYPE),
23  fw_t_oper(), bw_t_oper()
24 {
25 #ifdef MFEM_USE_MPI
26  const bool par_dom = dynamic_cast<ParFiniteElementSpace*>(&dom_fes);
27  const bool par_ran = dynamic_cast<ParFiniteElementSpace*>(&ran_fes);
28  MFEM_VERIFY(par_dom == par_ran, "the domain and range FE spaces must both"
29  " be either serial or parallel");
30  parallel = par_dom;
31 #endif
32 }
33 
35  FiniteElementSpace &fes_in, FiniteElementSpace &fes_out,
36  const Operator &oper, OperatorHandle &t_oper)
37 {
38  if (t_oper.Ptr())
39  {
40  return *t_oper.Ptr();
41  }
42 
43  if (!Parallel())
44  {
45  const SparseMatrix *in_cP = fes_in.GetConformingProlongation();
46  const SparseMatrix *out_cR = fes_out.GetConformingRestriction();
48  {
49  const SparseMatrix *mat = dynamic_cast<const SparseMatrix *>(&oper);
50  MFEM_VERIFY(mat != NULL, "Operator is not a SparseMatrix");
51  if (!out_cR)
52  {
53  t_oper.Reset(const_cast<SparseMatrix*>(mat), false);
54  }
55  else
56  {
57  t_oper.Reset(mfem::Mult(*out_cR, *mat));
58  }
59  if (in_cP)
60  {
61  t_oper.Reset(mfem::Mult(*t_oper.As<SparseMatrix>(), *in_cP));
62  }
63  }
64  else if (oper_type == Operator::ANY_TYPE)
65  {
66  const int RP_case = bool(out_cR) + 2*bool(in_cP);
67  switch (RP_case)
68  {
69  case 0:
70  t_oper.Reset(const_cast<Operator*>(&oper), false);
71  break;
72  case 1:
73  t_oper.Reset(
74  new ProductOperator(out_cR, &oper, false, false));
75  break;
76  case 2:
77  t_oper.Reset(
78  new ProductOperator(&oper, in_cP, false, false));
79  break;
80  case 3:
81  t_oper.Reset(
83  out_cR, &oper, in_cP, false, false, false));
84  break;
85  }
86  }
87  else
88  {
89  MFEM_ABORT("Operator::Type is not supported: " << oper_type);
90  }
91  }
92  else // Parallel() == true
93  {
94 #ifdef MFEM_USE_MPI
96  {
97  const SparseMatrix *out_R = fes_out.GetRestrictionMatrix();
98  const ParFiniteElementSpace *pfes_in =
99  dynamic_cast<const ParFiniteElementSpace *>(&fes_in);
100  const ParFiniteElementSpace *pfes_out =
101  dynamic_cast<const ParFiniteElementSpace *>(&fes_out);
102  const SparseMatrix *sp_mat = dynamic_cast<const SparseMatrix *>(&oper);
103  const HypreParMatrix *hy_mat;
104  if (sp_mat)
105  {
106  SparseMatrix *RA = mfem::Mult(*out_R, *sp_mat);
107  t_oper.Reset(pfes_in->Dof_TrueDof_Matrix()->
108  LeftDiagMult(*RA, pfes_out->GetTrueDofOffsets()));
109  delete RA;
110  }
111  else if ((hy_mat = dynamic_cast<const HypreParMatrix *>(&oper)))
112  {
113  HypreParMatrix *RA =
114  hy_mat->LeftDiagMult(*out_R, pfes_out->GetTrueDofOffsets());
115  t_oper.Reset(mfem::ParMult(RA, pfes_in->Dof_TrueDof_Matrix()));
116  delete RA;
117  }
118  else
119  {
120  MFEM_ABORT("unknown Operator type");
121  }
122  }
123  else if (oper_type == Operator::ANY_TYPE)
124  {
125  const Operator *out_R = fes_out.GetRestrictionOperator();
126  t_oper.Reset(new TripleProductOperator(
127  out_R, &oper, fes_in.GetProlongationMatrix(),
128  false, false, false));
129  }
130  else
131  {
132  MFEM_ABORT("Operator::Type is not supported: " << oper_type);
133  }
134 #endif
135  }
136 
137  return *t_oper.Ptr();
138 }
139 
140 
142 {
143  if (own_mass_integ) { delete mass_integ; }
144 }
145 
147  BilinearFormIntegrator *mass_integ_, bool own_mass_integ_)
148 {
149  if (own_mass_integ) { delete mass_integ; }
150 
151  mass_integ = mass_integ_;
152  own_mass_integ = own_mass_integ_;
153 }
154 
156 {
157  if (F.Ptr())
158  {
159  return *F.Ptr();
160  }
161 
162  // Construct F
164  {
166  }
168  {
169  Mesh::GeometryList elem_geoms(*ran_fes.GetMesh());
170 
172  for (int i = 0; i < elem_geoms.Size(); i++)
173  {
175  localP[elem_geoms[i]]);
176  }
180  }
181  else
182  {
183  MFEM_ABORT("Operator::Type is not supported: " << oper_type);
184  }
185 
186  return *F.Ptr();
187 }
188 
190 {
191  if (B.Ptr())
192  {
193  return *B.Ptr();
194  }
195 
196  // Construct B, if not set, define a suitable mass_integ
197  if (!mass_integ && ran_fes.GetNE() > 0)
198  {
199  const FiniteElement *f_fe_0 = ran_fes.GetFE(0);
200  const int map_type = f_fe_0->GetMapType();
201  if (map_type == FiniteElement::VALUE ||
202  map_type == FiniteElement::INTEGRAL)
203  {
205  }
206  else if (map_type == FiniteElement::H_DIV ||
207  map_type == FiniteElement::H_CURL)
208  {
210  }
211  else
212  {
213  MFEM_ABORT("unknown type of FE space");
214  }
215  own_mass_integ = true;
216  }
218  {
220  &ran_fes, &dom_fes, mass_integ));
221  }
222  else
223  {
224  MFEM_ABORT("Operator::Type is not supported: " << oper_type);
225  }
226 
227  return *B.Ptr();
228 }
229 
230 
232  const FiniteElementSpace &fes_ho_, const FiniteElementSpace &fes_lor_)
233  : Operator(fes_lor_.GetVSize(), fes_ho_.GetVSize()),
234  fes_ho(fes_ho_),
235  fes_lor(fes_lor_)
236 { }
237 
239  int nel_ho, int nel_lor, const CoarseFineTransformations& cf_tr)
240 {
241  // Construct the mapping from HO to LOR
242  // ho2lor.GetRow(iho) will give all the LOR elements contained in iho
243  ho2lor.MakeI(nel_ho);
244  for (int ilor = 0; ilor < nel_lor; ++ilor)
245  {
246  int iho = cf_tr.embeddings[ilor].parent;
247  ho2lor.AddAColumnInRow(iho);
248  }
249  ho2lor.MakeJ();
250  for (int ilor = 0; ilor < nel_lor; ++ilor)
251  {
252  int iho = cf_tr.embeddings[ilor].parent;
253  ho2lor.AddConnection(iho, ilor);
254  }
255  ho2lor.ShiftUpI();
256 }
257 
259  Geometry::Type geom, const FiniteElement& fe_ho,
260  const FiniteElement& fe_lor, ElementTransformation* el_tr,
262  DenseMatrix& M_mixed_el) const
263 {
264  int order = fe_lor.GetOrder() + fe_ho.GetOrder() + el_tr->OrderW();
265  const IntegrationRule* ir = &IntRules.Get(geom, order);
266  M_mixed_el = 0.0;
267  for (int i = 0; i < ir->GetNPoints(); i++)
268  {
269  const IntegrationPoint& ip_lor = ir->IntPoint(i);
270  IntegrationPoint ip_ho;
271  ip_tr.Transform(ip_lor, ip_ho);
272  Vector shape_lor(fe_lor.GetDof());
273  fe_lor.CalcShape(ip_lor, shape_lor);
274  Vector shape_ho(fe_ho.GetDof());
275  fe_ho.CalcShape(ip_ho, shape_ho);
276  el_tr->SetIntPoint(&ip_lor);
277  // For now we use the geometry information from the LOR space, which means
278  // we won't be mass conservative if the mesh is curved
279  double w = el_tr->Weight() * ip_lor.weight;
280  shape_lor *= w;
281  AddMultVWt(shape_lor, shape_ho, M_mixed_el);
282  }
283 }
284 
286  const FiniteElementSpace &fes_ho_, const FiniteElementSpace &fes_lor_)
287  : L2Projection(fes_ho_, fes_lor_)
288 {
289  Mesh *mesh_ho = fes_ho.GetMesh();
290  Mesh *mesh_lor = fes_lor.GetMesh();
291  int nel_ho = mesh_ho->GetNE();
292  int nel_lor = mesh_lor->GetNE();
293 
294  // The prolongation operation is only well-defined when the LOR space has at
295  // least as many DOFs as the high-order space.
296  const bool build_P = fes_lor.GetTrueVSize() >= fes_ho.GetTrueVSize();
297 
298  // If the local mesh is empty, skip all computations
299  if (nel_ho == 0) { return; }
300 
301  const CoarseFineTransformations &cf_tr = mesh_lor->GetRefinementTransforms();
302 
303  int nref_max = 0;
304  Array<Geometry::Type> geoms;
305  mesh_ho->GetGeometries(mesh_ho->Dimension(), geoms);
306  for (int ig = 0; ig < geoms.Size(); ++ig)
307  {
308  Geometry::Type geom = geoms[ig];
309  nref_max = std::max(nref_max, cf_tr.point_matrices[geom].SizeK());
310  }
311 
312  BuildHo2Lor(nel_ho, nel_lor, cf_tr);
313 
314  offsets.SetSize(nel_ho+1);
315  offsets[0] = 0;
316  for (int iho = 0; iho < nel_ho; ++iho)
317  {
318  int nref = ho2lor.RowSize(iho);
319  const FiniteElement &fe_ho = *fes_ho.GetFE(iho);
320  const FiniteElement &fe_lor = *fes_lor.GetFE(ho2lor.GetRow(iho)[0]);
321  offsets[iho+1] = offsets[iho] + fe_ho.GetDof()*fe_lor.GetDof()*nref;
322  }
323  // R will contain the restriction (L^2 projection operator) defined on each
324  // coarse HO element (and corresponding patch of LOR elements)
325  R.SetSize(offsets[nel_ho]);
326  if (build_P)
327  {
328  // P will contain the corresponding prolongation operator
329  P.SetSize(offsets[nel_ho]);
330  }
331 
333  IsoparametricTransformation &emb_tr = ip_tr.Transf;
334 
335  for (int iho = 0; iho < nel_ho; ++iho)
336  {
337  Array<int> lor_els;
338  ho2lor.GetRow(iho, lor_els);
339  int nref = ho2lor.RowSize(iho);
340 
341  Geometry::Type geom = mesh_ho->GetElementBaseGeometry(iho);
342  const FiniteElement &fe_ho = *fes_ho.GetFE(iho);
343  const FiniteElement &fe_lor = *fes_lor.GetFE(lor_els[0]);
344  int ndof_ho = fe_ho.GetDof();
345  int ndof_lor = fe_lor.GetDof();
346 
347  emb_tr.SetIdentityTransformation(geom);
348  const DenseTensor &pmats = cf_tr.point_matrices[geom];
349 
350  DenseMatrix R_iho(&R[offsets[iho]], ndof_lor*nref, ndof_ho);
351 
352  DenseMatrix Minv_lor(ndof_lor*nref, ndof_lor*nref);
353  DenseMatrix M_mixed(ndof_lor*nref, ndof_ho);
354 
355  MassIntegrator mi;
356  DenseMatrix M_lor_el(ndof_lor, ndof_lor);
357  DenseMatrixInverse Minv_lor_el(&M_lor_el);
358  DenseMatrix M_lor(ndof_lor*nref, ndof_lor*nref);
359  DenseMatrix M_mixed_el(ndof_lor, ndof_ho);
360 
361  Minv_lor = 0.0;
362  M_lor = 0.0;
363 
364  DenseMatrix RtMlor(ndof_ho, ndof_lor*nref);
365  DenseMatrix RtMlorR(ndof_ho, ndof_ho);
366  DenseMatrixInverse RtMlorR_inv(&RtMlorR);
367 
368  for (int iref = 0; iref < nref; ++iref)
369  {
370  // Assemble the low-order refined mass matrix and invert locally
371  int ilor = lor_els[iref];
373  mi.AssembleElementMatrix(fe_lor, *el_tr, M_lor_el);
374  M_lor.CopyMN(M_lor_el, iref*ndof_lor, iref*ndof_lor);
375  Minv_lor_el.Factor();
376  Minv_lor_el.GetInverseMatrix(M_lor_el);
377  // Insert into the diagonal of the patch LOR mass matrix
378  Minv_lor.CopyMN(M_lor_el, iref*ndof_lor, iref*ndof_lor);
379 
380  // Now assemble the block-row of the mixed mass matrix associated
381  // with integrating HO functions against LOR functions on the LOR
382  // sub-element.
383 
384  // Create the transformation that embeds the fine low-order element
385  // within the coarse high-order element in reference space
386  emb_tr.SetPointMat(pmats(cf_tr.embeddings[ilor].matrix));
387 
388  ElemMixedMass(geom, fe_ho, fe_lor, el_tr, ip_tr, M_mixed_el);
389 
390  M_mixed.CopyMN(M_mixed_el, iref*ndof_lor, 0);
391  }
392  mfem::Mult(Minv_lor, M_mixed, R_iho);
393 
394  if (build_P)
395  {
396  DenseMatrix P_iho(&P[offsets[iho]], ndof_ho, ndof_lor*nref);
397 
398  mfem::MultAtB(R_iho, M_lor, RtMlor);
399  mfem::Mult(RtMlor, R_iho, RtMlorR);
400  RtMlorR_inv.Factor();
401  RtMlorR_inv.Mult(RtMlor, P_iho);
402  }
403  }
404 }
405 
407  const Vector &x, Vector &y) const
408 {
409  int vdim = fes_ho.GetVDim();
410  Array<int> vdofs;
411  DenseMatrix xel_mat, yel_mat;
412  for (int iho = 0; iho < fes_ho.GetNE(); ++iho)
413  {
414  int nref = ho2lor.RowSize(iho);
415  int ndof_ho = fes_ho.GetFE(iho)->GetDof();
416  int ndof_lor = fes_lor.GetFE(ho2lor.GetRow(iho)[0])->GetDof();
417  xel_mat.SetSize(ndof_ho, vdim);
418  yel_mat.SetSize(ndof_lor*nref, vdim);
419  DenseMatrix R_iho(&R[offsets[iho]], ndof_lor*nref, ndof_ho);
420 
421  fes_ho.GetElementVDofs(iho, vdofs);
422  x.GetSubVector(vdofs, xel_mat.GetData());
423  mfem::Mult(R_iho, xel_mat, yel_mat);
424  // Place result correctly into the low-order vector
425  for (int iref = 0; iref < nref; ++iref)
426  {
427  int ilor = ho2lor.GetRow(iho)[iref];
428  for (int vd=0; vd<vdim; ++vd)
429  {
430  fes_lor.GetElementDofs(ilor, vdofs);
431  fes_lor.DofsToVDofs(vd, vdofs);
432  y.SetSubVector(vdofs, &yel_mat(iref*ndof_lor,vd));
433  }
434  }
435  }
436 }
437 
439  const Vector &x, Vector &y) const
440 {
441  int vdim = fes_ho.GetVDim();
442  Array<int> vdofs;
443  DenseMatrix xel_mat, yel_mat;
444  y = 0.0;
445  for (int iho = 0; iho < fes_ho.GetNE(); ++iho)
446  {
447  int nref = ho2lor.RowSize(iho);
448  int ndof_ho = fes_ho.GetFE(iho)->GetDof();
449  int ndof_lor = fes_lor.GetFE(ho2lor.GetRow(iho)[0])->GetDof();
450  xel_mat.SetSize(ndof_lor*nref, vdim);
451  yel_mat.SetSize(ndof_ho, vdim);
452  DenseMatrix R_iho(&R[offsets[iho]], ndof_lor*nref, ndof_ho);
453 
454  // Extract the LOR DOFs
455  for (int iref=0; iref<nref; ++iref)
456  {
457  int ilor = ho2lor.GetRow(iho)[iref];
458  for (int vd=0; vd<vdim; ++vd)
459  {
460  fes_lor.GetElementDofs(ilor, vdofs);
461  fes_lor.DofsToVDofs(vd, vdofs);
462  x.GetSubVector(vdofs, &xel_mat(iref*ndof_lor, vd));
463  }
464  }
465  // Multiply locally by the transpose
466  mfem::MultAtB(R_iho, xel_mat, yel_mat);
467  // Place the result in the HO vector
468  fes_ho.GetElementVDofs(iho, vdofs);
469  y.AddElementVector(vdofs, yel_mat.GetData());
470  }
471 }
472 
474  const Vector &x, Vector &y) const
475 {
476  if (fes_ho.GetNE() == 0) { return; }
477  MFEM_VERIFY(P.Size() > 0, "Prolongation not supported for these spaces.")
478  int vdim = fes_ho.GetVDim();
479  Array<int> vdofs;
480  DenseMatrix xel_mat,yel_mat;
481  y = 0.0;
482  for (int iho = 0; iho < fes_ho.GetNE(); ++iho)
483  {
484  int nref = ho2lor.RowSize(iho);
485  int ndof_ho = fes_ho.GetFE(iho)->GetDof();
486  int ndof_lor = fes_lor.GetFE(ho2lor.GetRow(iho)[0])->GetDof();
487  xel_mat.SetSize(ndof_lor*nref, vdim);
488  yel_mat.SetSize(ndof_ho, vdim);
489  DenseMatrix P_iho(&P[offsets[iho]], ndof_ho, ndof_lor*nref);
490 
491  // Extract the LOR DOFs
492  for (int iref = 0; iref < nref; ++iref)
493  {
494  int ilor = ho2lor.GetRow(iho)[iref];
495  for (int vd = 0; vd < vdim; ++vd)
496  {
497  fes_lor.GetElementDofs(ilor, vdofs);
498  fes_lor.DofsToVDofs(vd, vdofs);
499  x.GetSubVector(vdofs, &xel_mat(iref*ndof_lor, vd));
500  }
501  }
502  // Locally prolongate
503  mfem::Mult(P_iho, xel_mat, yel_mat);
504  // Place the result in the HO vector
505  fes_ho.GetElementVDofs(iho, vdofs);
506  y.AddElementVector(vdofs, yel_mat.GetData());
507  }
508 }
509 
511  const Vector &x, Vector &y) const
512 {
513  if (fes_ho.GetNE() == 0) { return; }
514  MFEM_VERIFY(P.Size() > 0, "Prolongation not supported for these spaces.")
515  int vdim = fes_ho.GetVDim();
516  Array<int> vdofs;
517  DenseMatrix xel_mat,yel_mat;
518  for (int iho = 0; iho < fes_ho.GetNE(); ++iho)
519  {
520  int nref = ho2lor.RowSize(iho);
521  int ndof_ho = fes_ho.GetFE(iho)->GetDof();
522  int ndof_lor = fes_lor.GetFE(ho2lor.GetRow(iho)[0])->GetDof();
523  xel_mat.SetSize(ndof_ho, vdim);
524  yel_mat.SetSize(ndof_lor*nref, vdim);
525  DenseMatrix P_iho(&P[offsets[iho]], ndof_ho, ndof_lor*nref);
526 
527  fes_ho.GetElementVDofs(iho, vdofs);
528  x.GetSubVector(vdofs, xel_mat.GetData());
529  mfem::MultAtB(P_iho, xel_mat, yel_mat);
530 
531  // Place result correctly into the low-order vector
532  for (int iref = 0; iref < nref; ++iref)
533  {
534  int ilor = ho2lor.GetRow(iho)[iref];
535  for (int vd=0; vd<vdim; ++vd)
536  {
537  fes_lor.GetElementDofs(ilor, vdofs);
538  fes_lor.DofsToVDofs(vd, vdofs);
539  y.SetSubVector(vdofs, &yel_mat(iref*ndof_lor,vd));
540  }
541  }
542  }
543 }
544 
546  const FiniteElementSpace& fes_ho_, const FiniteElementSpace& fes_lor_)
547  : L2Projection(fes_ho_, fes_lor_)
548 {
549  Mesh* mesh_ho = fes_ho.GetMesh();
550  Mesh* mesh_lor = fes_lor.GetMesh();
551  int nel_ho = mesh_ho->GetNE();
552  int nel_lor = mesh_lor->GetNE();
553  int ndof_lor = fes_lor.GetNDofs();
554 
555  // If the local mesh is empty, skip all computations
556  if (nel_ho == 0) { return; }
557 
558  const CoarseFineTransformations& cf_tr = mesh_lor->GetRefinementTransforms();
559 
560  int nref_max = 0;
561  Array<Geometry::Type> geoms;
562  mesh_ho->GetGeometries(mesh_ho->Dimension(), geoms);
563  for (int ig = 0; ig < geoms.Size(); ++ig)
564  {
565  Geometry::Type geom = geoms[ig];
566  nref_max = std::max(nref_max, cf_tr.point_matrices[geom].SizeK());
567  }
568 
569  BuildHo2Lor(nel_ho, nel_lor, cf_tr);
570 
571  // ML_inv contains the inverse lumped (row sum) mass matrix. Note that the
572  // method will also work with a full (consistent) mass matrix, though this is
573  // not implemented here. L refers to the low-order refined mesh
574  Vector ML_inv(ndof_lor);
575  ML_inv = 0.0;
576 
577  // Compute ML_inv
578  for (int iho = 0; iho < nel_ho; ++iho)
579  {
580  Array<int> lor_els;
581  ho2lor.GetRow(iho, lor_els);
582  int nref = ho2lor.RowSize(iho);
583 
584  Geometry::Type geom = mesh_ho->GetElementBaseGeometry(iho);
585  const FiniteElement& fe_lor = *fes_lor.GetFE(lor_els[0]);
586  int nedof_lor = fe_lor.GetDof();
587 
588  // Instead of using a MassIntegrator, manually loop over integration
589  // points so we can row sum and store the diagonal as a Vector.
590  Vector ML_el(nedof_lor);
591  Vector shape_lor(nedof_lor);
592  Array<int> dofs_lor(nedof_lor);
593 
594  for (int iref = 0; iref < nref; ++iref)
595  {
596  int ilor = lor_els[iref];
598 
599  int order = 2 * fe_lor.GetOrder() + el_tr->OrderW();
600  const IntegrationRule* ir = &IntRules.Get(geom, order);
601  ML_el = 0.0;
602  for (int i = 0; i < ir->GetNPoints(); ++i)
603  {
604  const IntegrationPoint& ip_lor = ir->IntPoint(i);
605  fe_lor.CalcShape(ip_lor, shape_lor);
606  el_tr->SetIntPoint(&ip_lor);
607  ML_el += (shape_lor *= (el_tr->Weight() * ip_lor.weight));
608  }
609  fes_lor.GetElementDofs(ilor, dofs_lor);
610  ML_inv.AddElementVector(dofs_lor, ML_el);
611  }
612  }
613  // DOF by DOF inverse of non-zero entries
614  for (int i = 0; i < ndof_lor; ++i)
615  {
616  ML_inv[i] = 1.0 / ML_inv[i];
617  }
618 
619  // Compute sparsity pattern for R = M_L^(-1) M_LH and allocate
620  AllocR();
621  // Allocate M_LH (same sparsity pattern as R)
622  // L refers to the low-order refined mesh (DOFs correspond to rows)
623  // H refers to the higher-order mesh (DOFs correspond to columns)
624  M_LH = SparseMatrix(R.GetI(), R.GetJ(), NULL,
625  R.Height(), R.Width(), false, true, true);
626 
628  IsoparametricTransformation& emb_tr = ip_tr.Transf;
629 
630  // Compute M_LH and R
631  for (int iho = 0; iho < nel_ho; ++iho)
632  {
633  Array<int> lor_els;
634  ho2lor.GetRow(iho, lor_els);
635  int nref = ho2lor.RowSize(iho);
636 
637  Geometry::Type geom = mesh_ho->GetElementBaseGeometry(iho);
638  const FiniteElement& fe_ho = *fes_ho.GetFE(iho);
639  const FiniteElement& fe_lor = *fes_lor.GetFE(lor_els[0]);
640 
641  emb_tr.SetIdentityTransformation(geom);
642  const DenseTensor& pmats = cf_tr.point_matrices[geom];
643 
644  int nedof_ho = fe_ho.GetDof();
645  int nedof_lor = fe_lor.GetDof();
646  DenseMatrix M_LH_el(nedof_lor, nedof_ho);
647  DenseMatrix R_el(nedof_lor, nedof_ho);
648 
649  for (int iref = 0; iref < nref; ++iref)
650  {
651  int ilor = lor_els[iref];
653 
654  // Create the transformation that embeds the fine low-order element
655  // within the coarse high-order element in reference space
656  emb_tr.SetPointMat(pmats(cf_tr.embeddings[ilor].matrix));
657 
658  ElemMixedMass(geom, fe_ho, fe_lor, el_tr, ip_tr, M_LH_el);
659 
660  Array<int> dofs_lor(nedof_lor);
661  fes_lor.GetElementDofs(ilor, dofs_lor);
662  Vector R_row;
663  for (int i = 0; i < nedof_lor; ++i)
664  {
665  M_LH_el.GetRow(i, R_row);
666  R_el.SetRow(i, R_row.Set(ML_inv[dofs_lor[i]], R_row));
667  }
668  Array<int> dofs_ho(nedof_ho);
669  fes_ho.GetElementDofs(iho, dofs_ho);
670  M_LH.AddSubMatrix(dofs_lor, dofs_ho, M_LH_el);
671  R.AddSubMatrix(dofs_lor, dofs_ho, R_el);
672  }
673  }
674 
675  // Create PCG solver
676  RTxM_LH = TransposeMult(R, M_LH);
677  pcg.SetPrintLevel(0);
678  pcg.SetMaxIter(1000);
679  // initial values for relative and absolute tolerance
680  SetRelTol(1e-13);
681  SetAbsTol(1e-13);
682  Ds = DSmoother(*RTxM_LH);
683  pcg.SetPreconditioner(Ds);
684  pcg.SetOperator(*RTxM_LH);
685 }
686 
688 {
689  delete RTxM_LH;
690 }
691 
693  const Vector& x, Vector& y) const
694 {
695  int vdim = fes_ho.GetVDim();
696  const int ndof_ho = fes_ho.GetNDofs();
697  const int ndof_lor = fes_lor.GetNDofs();
698  Array<int> dofs_ho(ndof_ho);
699  Array<int> dofs_lor(ndof_lor);
700  Vector x_dim(ndof_ho);
701  Vector y_dim(ndof_lor);
702 
703  for (int d = 0; d < vdim; ++d)
704  {
705  fes_ho.GetVDofs(d, dofs_ho);
706  fes_lor.GetVDofs(d, dofs_lor);
707  x.GetSubVector(dofs_ho, x_dim);
708  R.Mult(x_dim, y_dim);
709  y.SetSubVector(dofs_lor, y_dim);
710  }
711 }
712 
714  const Vector& x, Vector& y) const
715 {
716  int vdim = fes_ho.GetVDim();
717  const int ndof_ho = fes_ho.GetNDofs();
718  const int ndof_lor = fes_lor.GetNDofs();
719  Array<int> dofs_ho(ndof_ho);
720  Array<int> dofs_lor(ndof_lor);
721  Vector x_dim(ndof_lor);
722  Vector y_dim(ndof_ho);
723 
724  for (int d = 0; d < vdim; ++d)
725  {
726  fes_ho.GetVDofs(d, dofs_ho);
727  fes_lor.GetVDofs(d, dofs_lor);
728  x.GetSubVector(dofs_lor, x_dim);
729  R.MultTranspose(x_dim, y_dim);
730  y.SetSubVector(dofs_ho, y_dim);
731  }
732 }
733 
735  const Vector& x, Vector& y) const
736 {
737  int vdim = fes_ho.GetVDim();
738  const int ndof_ho = fes_ho.GetNDofs();
739  const int ndof_lor = fes_lor.GetNDofs();
740  Array<int> dofs_ho(ndof_ho);
741  Array<int> dofs_lor(ndof_lor);
742  Vector x_dim(ndof_lor);
743  Vector y_dim(ndof_ho);
744  Vector xbar(ndof_ho);
745 
746  for (int d = 0; d < vdim; ++d)
747  {
748  fes_lor.GetVDofs(d, dofs_lor);
749  x.GetSubVector(dofs_lor, x_dim);
750  // Compute y = P x = (R^T M_LH)^(-1) M_LH^T x = (R^T M_LH)^(-1) xbar
751  M_LH.MultTranspose(x_dim, xbar);
752  y_dim = 0.0;
753  pcg.Mult(xbar, y_dim);
754  fes_ho.GetVDofs(d, dofs_ho);
755  y.SetSubVector(dofs_ho, y_dim);
756  }
757 }
758 
760  const Vector& x, Vector& y) const
761 {
762  int vdim = fes_ho.GetVDim();
763  const int ndof_ho = fes_ho.GetNDofs();
764  const int ndof_lor = fes_lor.GetNDofs();
765  Array<int> dofs_ho(ndof_ho);
766  Array<int> dofs_lor(ndof_lor);
767  Vector x_dim(ndof_ho);
768  Vector y_dim(ndof_lor);
769  Vector xbar(ndof_ho);
770 
771  for (int d = 0; d < vdim; ++d)
772  {
773  fes_ho.GetVDofs(d, dofs_ho);
774  x.GetSubVector(dofs_ho, x_dim);
775  // Compute y = P^T x = M_LH (R^T M_LH)^(-1) x = M_LH xbar
776  xbar = 0.0;
777  pcg.Mult(x_dim, xbar);
778  M_LH.Mult(xbar, y_dim);
779  fes_lor.GetVDofs(d, dofs_lor);
780  y.SetSubVector(dofs_lor, y_dim);
781  }
782 }
783 
785 {
786  pcg.SetRelTol(p_rtol_);
787 }
788 
790 {
791  pcg.SetAbsTol(p_atol_);
792 }
793 
794 void L2ProjectionGridTransfer::L2ProjectionH1Space::AllocR()
795 {
796  const Table& elem_dof_ho = fes_ho.GetElementToDofTable();
797  const Table& elem_dof_lor = fes_lor.GetElementToDofTable();
798  const int ndof_ho = fes_ho.GetNDofs();
799  const int ndof_lor = fes_lor.GetNDofs();
800 
801  Table dof_elem_lor;
802  Transpose(elem_dof_lor, dof_elem_lor, ndof_lor);
803 
804  Mesh* mesh_lor = fes_lor.GetMesh();
805  const CoarseFineTransformations& cf_tr = mesh_lor->GetRefinementTransforms();
806 
807  // mfem::Mult but uses ho2lor to map HO elements to LOR elements
808  const int* elem_dof_hoI = elem_dof_ho.GetI();
809  const int* elem_dof_hoJ = elem_dof_ho.GetJ();
810  const int* dof_elem_lorI = dof_elem_lor.GetI();
811  const int* dof_elem_lorJ = dof_elem_lor.GetJ();
812 
813  Array<int> I(ndof_lor + 1);
814 
815  // figure out the size of J
816  Array<int> dof_used_ho;
817  dof_used_ho.SetSize(ndof_ho, -1);
818 
819  int sizeJ = 0;
820  for (int ilor = 0; ilor < ndof_lor; ++ilor)
821  {
822  for (int jlor = dof_elem_lorI[ilor]; jlor < dof_elem_lorI[ilor + 1]; ++jlor)
823  {
824  int el_lor = dof_elem_lorJ[jlor];
825  int iho = cf_tr.embeddings[el_lor].parent;
826  for (int jho = elem_dof_hoI[iho]; jho < elem_dof_hoI[iho + 1]; ++jho)
827  {
828  int dof_ho = elem_dof_hoJ[jho];
829  if (dof_used_ho[dof_ho] != ilor)
830  {
831  dof_used_ho[dof_ho] = ilor;
832  ++sizeJ;
833  }
834  }
835  }
836  }
837 
838  // initialize dof_ho_dof_lor
839  Table dof_lor_dof_ho;
840  dof_lor_dof_ho.SetDims(ndof_lor, sizeJ);
841 
842  for (int i = 0; i < ndof_ho; ++i)
843  {
844  dof_used_ho[i] = -1;
845  }
846 
847  // set values of J
848  int* dof_dofI = dof_lor_dof_ho.GetI();
849  int* dof_dofJ = dof_lor_dof_ho.GetJ();
850  sizeJ = 0;
851  for (int ilor = 0; ilor < ndof_lor; ++ilor)
852  {
853  dof_dofI[ilor] = sizeJ;
854  for (int jlor = dof_elem_lorI[ilor]; jlor < dof_elem_lorI[ilor + 1]; ++jlor)
855  {
856  int el_lor = dof_elem_lorJ[jlor];
857  int iho = cf_tr.embeddings[el_lor].parent;
858  for (int jho = elem_dof_hoI[iho]; jho < elem_dof_hoI[iho + 1]; ++jho)
859  {
860  int dof_ho = elem_dof_hoJ[jho];
861  if (dof_used_ho[dof_ho] != ilor)
862  {
863  dof_used_ho[dof_ho] = ilor;
864  dof_dofJ[sizeJ] = dof_ho;
865  ++sizeJ;
866  }
867  }
868  }
869  }
870 
871  dof_lor_dof_ho.SortRows();
872  double* data = Memory<double>(dof_dofI[ndof_lor]);
873 
874  R = SparseMatrix(dof_dofI, dof_dofJ, data, ndof_lor, ndof_ho,
875  true, true, true);
876  R = 0.0;
877 
878  dof_lor_dof_ho.LoseData();
879 }
880 
882 {
883  delete F;
884  delete B;
885 }
886 
888 {
889  if (!F) { BuildF(); }
890  return *F;
891 }
892 
894 {
895  if (!B)
896  {
897  if (!F) { BuildF(); }
898  B = new L2Prolongation(*F);
899  }
900  return *B;
901 }
902 
903 void L2ProjectionGridTransfer::BuildF()
904 {
905  if (!force_l2_space &&
907  {
908  F = new L2ProjectionH1Space(dom_fes, ran_fes);
909  }
910  else
911  {
912  F = new L2ProjectionL2Space(dom_fes, ran_fes);
913  }
914 }
915 
917 {
919 }
920 
921 
923  const FiniteElementSpace& hFESpace_)
924  : Operator(hFESpace_.GetVSize(), lFESpace_.GetVSize())
925 {
926  bool isvar_order = lFESpace_.IsVariableOrder() || hFESpace_.IsVariableOrder();
927  if (lFESpace_.FEColl() == hFESpace_.FEColl() && !isvar_order)
928  {
930  hFESpace_.GetTransferOperator(lFESpace_, P);
931  P.SetOperatorOwner(false);
932  opr = P.Ptr();
933  }
934  else if (lFESpace_.GetMesh()->GetNE() > 0
935  && hFESpace_.GetMesh()->GetNE() > 0
936  && lFESpace_.GetVDim() == 1
937  && hFESpace_.GetVDim() == 1
938  && dynamic_cast<const TensorBasisElement*>(lFESpace_.GetFE(0))
939  && dynamic_cast<const TensorBasisElement*>(hFESpace_.GetFE(0))
940  && !isvar_order
941  && (hFESpace_.FEColl()->GetContType() ==
943  hFESpace_.FEColl()->GetContType() ==
945  {
946  opr = new TensorProductPRefinementTransferOperator(lFESpace_, hFESpace_);
947  }
948  else
949  {
950  opr = new PRefinementTransferOperator(lFESpace_, hFESpace_);
951  }
952 }
953 
955 
956 void TransferOperator::Mult(const Vector& x, Vector& y) const
957 {
958  opr->Mult(x, y);
959 }
960 
962 {
963  opr->MultTranspose(x, y);
964 }
965 
966 
968  const FiniteElementSpace& lFESpace_, const FiniteElementSpace& hFESpace_)
969  : Operator(hFESpace_.GetVSize(), lFESpace_.GetVSize()), lFESpace(lFESpace_),
970  hFESpace(hFESpace_)
971 {
972  isvar_order = lFESpace_.IsVariableOrder() || hFESpace_.IsVariableOrder();
973 }
974 
976 
978 {
979  Mesh* mesh = hFESpace.GetMesh();
980  Array<int> l_dofs, h_dofs, l_vdofs, h_vdofs;
981  DenseMatrix loc_prol;
982  Vector subY, subX;
983 
984  Geometry::Type cached_geom = Geometry::INVALID;
985  const FiniteElement* h_fe = NULL;
986  const FiniteElement* l_fe = NULL;
988 
989  int vdim = lFESpace.GetVDim();
990 
991  for (int i = 0; i < mesh->GetNE(); i++)
992  {
993  DofTransformation * doftrans_h = hFESpace.GetElementDofs(i, h_dofs);
994  DofTransformation * doftrans_l = lFESpace.GetElementDofs(i, l_dofs);
995 
996  const Geometry::Type geom = mesh->GetElementBaseGeometry(i);
997  if (geom != cached_geom || isvar_order)
998  {
999  h_fe = hFESpace.GetFE(i);
1000  l_fe = lFESpace.GetFE(i);
1001  T.SetIdentityTransformation(h_fe->GetGeomType());
1002  h_fe->GetTransferMatrix(*l_fe, T, loc_prol);
1003  subY.SetSize(loc_prol.Height());
1004  cached_geom = geom;
1005  }
1006 
1007  for (int vd = 0; vd < vdim; vd++)
1008  {
1009  l_dofs.Copy(l_vdofs);
1010  lFESpace.DofsToVDofs(vd, l_vdofs);
1011  h_dofs.Copy(h_vdofs);
1012  hFESpace.DofsToVDofs(vd, h_vdofs);
1013  x.GetSubVector(l_vdofs, subX);
1014  if (doftrans_l)
1015  {
1016  doftrans_l->InvTransformPrimal(subX);
1017  }
1018  loc_prol.Mult(subX, subY);
1019  if (doftrans_h)
1020  {
1021  doftrans_h->TransformPrimal(subY);
1022  }
1023  y.SetSubVector(h_vdofs, subY);
1024  }
1025  }
1026 }
1027 
1029  Vector& y) const
1030 {
1031  y = 0.0;
1032 
1033  Mesh* mesh = hFESpace.GetMesh();
1034  Array<int> l_dofs, h_dofs, l_vdofs, h_vdofs;
1035  DenseMatrix loc_prol;
1036  Vector subY, subX;
1037 
1038  Array<char> processed(hFESpace.GetVSize());
1039  processed = 0;
1040 
1041  Geometry::Type cached_geom = Geometry::INVALID;
1042  const FiniteElement* h_fe = NULL;
1043  const FiniteElement* l_fe = NULL;
1045 
1046  int vdim = lFESpace.GetVDim();
1047 
1048  for (int i = 0; i < mesh->GetNE(); i++)
1049  {
1050  DofTransformation * doftrans_h = hFESpace.GetElementDofs(i, h_dofs);
1051  DofTransformation * doftrans_l = lFESpace.GetElementDofs(i, l_dofs);
1052 
1053  const Geometry::Type geom = mesh->GetElementBaseGeometry(i);
1054  if (geom != cached_geom || isvar_order)
1055  {
1056  h_fe = hFESpace.GetFE(i);
1057  l_fe = lFESpace.GetFE(i);
1058  T.SetIdentityTransformation(h_fe->GetGeomType());
1059  h_fe->GetTransferMatrix(*l_fe, T, loc_prol);
1060  loc_prol.Transpose();
1061  subY.SetSize(loc_prol.Height());
1062  cached_geom = geom;
1063  }
1064 
1065  for (int vd = 0; vd < vdim; vd++)
1066  {
1067  l_dofs.Copy(l_vdofs);
1068  lFESpace.DofsToVDofs(vd, l_vdofs);
1069  h_dofs.Copy(h_vdofs);
1070  hFESpace.DofsToVDofs(vd, h_vdofs);
1071 
1072  x.GetSubVector(h_vdofs, subX);
1073  if (doftrans_h)
1074  {
1075  doftrans_h->InvTransformDual(subX);
1076  }
1077  for (int p = 0; p < h_dofs.Size(); ++p)
1078  {
1079  if (processed[lFESpace.DecodeDof(h_dofs[p])])
1080  {
1081  subX[p] = 0.0;
1082  }
1083  }
1084 
1085  loc_prol.Mult(subX, subY);
1086  if (doftrans_l)
1087  {
1088  doftrans_l->TransformDual(subY);
1089  }
1090  y.AddElementVector(l_vdofs, subY);
1091  }
1092 
1093  for (int p = 0; p < h_dofs.Size(); ++p)
1094  {
1095  processed[lFESpace.DecodeDof(h_dofs[p])] = 1;
1096  }
1097  }
1098 }
1099 
1100 
1103  const FiniteElementSpace& lFESpace_,
1104  const FiniteElementSpace& hFESpace_)
1105  : Operator(hFESpace_.GetVSize(), lFESpace_.GetVSize()), lFESpace(lFESpace_),
1106  hFESpace(hFESpace_)
1107 {
1108  // Assuming the same element type
1109  Mesh* mesh = lFESpace.GetMesh();
1110  dim = mesh->Dimension();
1111  if (mesh->GetNE() == 0)
1112  {
1113  return;
1114  }
1115  const FiniteElement& el = *lFESpace.GetFE(0);
1116 
1117  const TensorBasisElement* ltel =
1118  dynamic_cast<const TensorBasisElement*>(&el);
1119  MFEM_VERIFY(ltel, "Low order FE space must be tensor product space");
1120 
1121  const TensorBasisElement* htel =
1122  dynamic_cast<const TensorBasisElement*>(hFESpace.GetFE(0));
1123  MFEM_VERIFY(htel, "High order FE space must be tensor product space");
1124  const Array<int>& hdofmap = htel->GetDofMap();
1125 
1126  const IntegrationRule& ir = hFESpace.GetFE(0)->GetNodes();
1127  IntegrationRule irLex = ir;
1128 
1129  // The quadrature points, or equivalently, the dofs of the high order space
1130  // must be sorted in lexicographical order
1131  for (int i = 0; i < ir.GetNPoints(); ++i)
1132  {
1133  int j = hdofmap[i] >=0 ? hdofmap[i] : -1 - hdofmap[i];
1134  irLex.IntPoint(i) = ir.IntPoint(j);
1135  }
1136 
1137  NE = lFESpace.GetNE();
1138  const DofToQuad& maps = el.GetDofToQuad(irLex, DofToQuad::TENSOR);
1139 
1140  D1D = maps.ndof;
1141  Q1D = maps.nqpt;
1142  B = maps.B;
1143  Bt = maps.Bt;
1144 
1145  elem_restrict_lex_l =
1147 
1148  MFEM_VERIFY(elem_restrict_lex_l,
1149  "Low order ElementRestriction not available");
1150 
1151  elem_restrict_lex_h =
1153 
1154  MFEM_VERIFY(elem_restrict_lex_h,
1155  "High order ElementRestriction not available");
1156 
1157  localL.SetSize(elem_restrict_lex_l->Height(), Device::GetMemoryType());
1158  localH.SetSize(elem_restrict_lex_h->Height(), Device::GetMemoryType());
1159  localL.UseDevice(true);
1160  localH.UseDevice(true);
1161 
1162  MFEM_VERIFY(dynamic_cast<const ElementRestriction*>(elem_restrict_lex_h),
1163  "High order element restriction is of unsupported type");
1164 
1165  mask.SetSize(localH.Size(), Device::GetMemoryType());
1166  static_cast<const ElementRestriction*>(elem_restrict_lex_h)
1167  ->BooleanMask(mask);
1168  mask.UseDevice(true);
1169 }
1170 
1171 namespace TransferKernels
1172 {
1173 void Prolongation2D(const int NE, const int D1D, const int Q1D,
1174  const Vector& localL, Vector& localH,
1175  const Array<double>& B, const Vector& mask)
1176 {
1177  auto x_ = Reshape(localL.Read(), D1D, D1D, NE);
1178  auto y_ = Reshape(localH.ReadWrite(), Q1D, Q1D, NE);
1179  auto B_ = Reshape(B.Read(), Q1D, D1D);
1180  auto m_ = Reshape(mask.Read(), Q1D, Q1D, NE);
1181 
1182  localH = 0.0;
1183 
1184  MFEM_FORALL(e, NE,
1185  {
1186  for (int dy = 0; dy < D1D; ++dy)
1187  {
1188  double sol_x[MAX_Q1D];
1189  for (int qy = 0; qy < Q1D; ++qy)
1190  {
1191  sol_x[qy] = 0.0;
1192  }
1193  for (int dx = 0; dx < D1D; ++dx)
1194  {
1195  const double s = x_(dx, dy, e);
1196  for (int qx = 0; qx < Q1D; ++qx)
1197  {
1198  sol_x[qx] += B_(qx, dx) * s;
1199  }
1200  }
1201  for (int qy = 0; qy < Q1D; ++qy)
1202  {
1203  const double d2q = B_(qy, dy);
1204  for (int qx = 0; qx < Q1D; ++qx)
1205  {
1206  y_(qx, qy, e) += d2q * sol_x[qx];
1207  }
1208  }
1209  }
1210  for (int qy = 0; qy < Q1D; ++qy)
1211  {
1212  for (int qx = 0; qx < Q1D; ++qx)
1213  {
1214  y_(qx, qy, e) *= m_(qx, qy, e);
1215  }
1216  }
1217  });
1218 }
1219 
1220 void Prolongation3D(const int NE, const int D1D, const int Q1D,
1221  const Vector& localL, Vector& localH,
1222  const Array<double>& B, const Vector& mask)
1223 {
1224  auto x_ = Reshape(localL.Read(), D1D, D1D, D1D, NE);
1225  auto y_ = Reshape(localH.ReadWrite(), Q1D, Q1D, Q1D, NE);
1226  auto B_ = Reshape(B.Read(), Q1D, D1D);
1227  auto m_ = Reshape(mask.Read(), Q1D, Q1D, Q1D, NE);
1228 
1229  localH = 0.0;
1230 
1231  MFEM_FORALL(e, NE,
1232  {
1233  for (int dz = 0; dz < D1D; ++dz)
1234  {
1235  double sol_xy[MAX_Q1D][MAX_Q1D];
1236  for (int qy = 0; qy < Q1D; ++qy)
1237  {
1238  for (int qx = 0; qx < Q1D; ++qx)
1239  {
1240  sol_xy[qy][qx] = 0.0;
1241  }
1242  }
1243  for (int dy = 0; dy < D1D; ++dy)
1244  {
1245  double sol_x[MAX_Q1D];
1246  for (int qx = 0; qx < Q1D; ++qx)
1247  {
1248  sol_x[qx] = 0;
1249  }
1250  for (int dx = 0; dx < D1D; ++dx)
1251  {
1252  const double s = x_(dx, dy, dz, e);
1253  for (int qx = 0; qx < Q1D; ++qx)
1254  {
1255  sol_x[qx] += B_(qx, dx) * s;
1256  }
1257  }
1258  for (int qy = 0; qy < Q1D; ++qy)
1259  {
1260  const double wy = B_(qy, dy);
1261  for (int qx = 0; qx < Q1D; ++qx)
1262  {
1263  sol_xy[qy][qx] += wy * sol_x[qx];
1264  }
1265  }
1266  }
1267  for (int qz = 0; qz < Q1D; ++qz)
1268  {
1269  const double wz = B_(qz, dz);
1270  for (int qy = 0; qy < Q1D; ++qy)
1271  {
1272  for (int qx = 0; qx < Q1D; ++qx)
1273  {
1274  y_(qx, qy, qz, e) += wz * sol_xy[qy][qx];
1275  }
1276  }
1277  }
1278  }
1279  for (int qz = 0; qz < Q1D; ++qz)
1280  {
1281  for (int qy = 0; qy < Q1D; ++qy)
1282  {
1283  for (int qx = 0; qx < Q1D; ++qx)
1284  {
1285  y_(qx, qy, qz, e) *= m_(qx, qy, qz, e);
1286  }
1287  }
1288  }
1289  });
1290 }
1291 
1292 void Restriction2D(const int NE, const int D1D, const int Q1D,
1293  const Vector& localH, Vector& localL,
1294  const Array<double>& Bt, const Vector& mask)
1295 {
1296  auto x_ = Reshape(localH.Read(), Q1D, Q1D, NE);
1297  auto y_ = Reshape(localL.ReadWrite(), D1D, D1D, NE);
1298  auto Bt_ = Reshape(Bt.Read(), D1D, Q1D);
1299  auto m_ = Reshape(mask.Read(), Q1D, Q1D, NE);
1300 
1301  localL = 0.0;
1302 
1303  MFEM_FORALL(e, NE,
1304  {
1305  for (int qy = 0; qy < Q1D; ++qy)
1306  {
1307  double sol_x[MAX_D1D];
1308  for (int dx = 0; dx < D1D; ++dx)
1309  {
1310  sol_x[dx] = 0.0;
1311  }
1312  for (int qx = 0; qx < Q1D; ++qx)
1313  {
1314  const double s = m_(qx, qy, e) * x_(qx, qy, e);
1315  for (int dx = 0; dx < D1D; ++dx)
1316  {
1317  sol_x[dx] += Bt_(dx, qx) * s;
1318  }
1319  }
1320  for (int dy = 0; dy < D1D; ++dy)
1321  {
1322  const double q2d = Bt_(dy, qy);
1323  for (int dx = 0; dx < D1D; ++dx)
1324  {
1325  y_(dx, dy, e) += q2d * sol_x[dx];
1326  }
1327  }
1328  }
1329  });
1330 }
1331 void Restriction3D(const int NE, const int D1D, const int Q1D,
1332  const Vector& localH, Vector& localL,
1333  const Array<double>& Bt, const Vector& mask)
1334 {
1335  auto x_ = Reshape(localH.Read(), Q1D, Q1D, Q1D, NE);
1336  auto y_ = Reshape(localL.ReadWrite(), D1D, D1D, D1D, NE);
1337  auto Bt_ = Reshape(Bt.Read(), D1D, Q1D);
1338  auto m_ = Reshape(mask.Read(), Q1D, Q1D, Q1D, NE);
1339 
1340  localL = 0.0;
1341 
1342  MFEM_FORALL(e, NE,
1343  {
1344  for (int qz = 0; qz < Q1D; ++qz)
1345  {
1346  double sol_xy[MAX_D1D][MAX_D1D];
1347  for (int dy = 0; dy < D1D; ++dy)
1348  {
1349  for (int dx = 0; dx < D1D; ++dx)
1350  {
1351  sol_xy[dy][dx] = 0;
1352  }
1353  }
1354  for (int qy = 0; qy < Q1D; ++qy)
1355  {
1356  double sol_x[MAX_D1D];
1357  for (int dx = 0; dx < D1D; ++dx)
1358  {
1359  sol_x[dx] = 0;
1360  }
1361  for (int qx = 0; qx < Q1D; ++qx)
1362  {
1363  const double s = m_(qx, qy, qz, e) * x_(qx, qy, qz, e);
1364  for (int dx = 0; dx < D1D; ++dx)
1365  {
1366  sol_x[dx] += Bt_(dx, qx) * s;
1367  }
1368  }
1369  for (int dy = 0; dy < D1D; ++dy)
1370  {
1371  const double wy = Bt_(dy, qy);
1372  for (int dx = 0; dx < D1D; ++dx)
1373  {
1374  sol_xy[dy][dx] += wy * sol_x[dx];
1375  }
1376  }
1377  }
1378  for (int dz = 0; dz < D1D; ++dz)
1379  {
1380  const double wz = Bt_(dz, qz);
1381  for (int dy = 0; dy < D1D; ++dy)
1382  {
1383  for (int dx = 0; dx < D1D; ++dx)
1384  {
1385  y_(dx, dy, dz, e) += wz * sol_xy[dy][dx];
1386  }
1387  }
1388  }
1389  }
1390  });
1391 }
1392 } // namespace TransferKernels
1393 
1394 
1397 {
1398 }
1399 
1401  Vector& y) const
1402 {
1403  if (lFESpace.GetMesh()->GetNE() == 0)
1404  {
1405  return;
1406  }
1407 
1408  elem_restrict_lex_l->Mult(x, localL);
1409  if (dim == 2)
1410  {
1411  TransferKernels::Prolongation2D(NE, D1D, Q1D, localL, localH, B, mask);
1412  }
1413  else if (dim == 3)
1414  {
1415  TransferKernels::Prolongation3D(NE, D1D, Q1D, localL, localH, B, mask);
1416  }
1417  else
1418  {
1419  MFEM_ABORT("TensorProductPRefinementTransferOperator::Mult not "
1420  "implemented for dim = "
1421  << dim);
1422  }
1423  elem_restrict_lex_h->MultTranspose(localH, y);
1424 }
1425 
1427  Vector& y) const
1428 {
1429  if (lFESpace.GetMesh()->GetNE() == 0)
1430  {
1431  return;
1432  }
1433 
1434  elem_restrict_lex_h->Mult(x, localH);
1435  if (dim == 2)
1436  {
1437  TransferKernels::Restriction2D(NE, D1D, Q1D, localH, localL, Bt, mask);
1438  }
1439  else if (dim == 3)
1440  {
1441  TransferKernels::Restriction3D(NE, D1D, Q1D, localH, localL, Bt, mask);
1442  }
1443  else
1444  {
1445  MFEM_ABORT("TensorProductPRefinementTransferOperator::MultTranspose not "
1446  "implemented for dim = "
1447  << dim);
1448  }
1449  elem_restrict_lex_l->MultTranspose(localL, y);
1450 }
1451 
1452 
1454  const FiniteElementSpace& hFESpace_)
1455  : Operator(hFESpace_.GetTrueVSize(), lFESpace_.GetTrueVSize()),
1456  lFESpace(lFESpace_),
1457  hFESpace(hFESpace_)
1458 {
1459  localTransferOperator = new TransferOperator(lFESpace_, hFESpace_);
1460 
1461  P = lFESpace.GetProlongationMatrix();
1462  R = hFESpace.IsVariableOrder() ? hFESpace.GetHpRestrictionMatrix() :
1463  hFESpace.GetRestrictionMatrix();
1464 
1465  // P and R can be both null
1466  // P can be null and R not null
1467  // If P is not null it is assumed that R is not null as well
1468  if (P) { MFEM_VERIFY(R, "Both P and R have to be not NULL") }
1469 
1470  if (P)
1471  {
1472  tmpL.SetSize(lFESpace_.GetVSize());
1473  tmpH.SetSize(hFESpace_.GetVSize());
1474  }
1475  // P can be null and R not null
1476  else if (R)
1477  {
1478  tmpH.SetSize(hFESpace_.GetVSize());
1479  }
1480 }
1481 
1483 {
1484  delete localTransferOperator;
1485 }
1486 
1487 void TrueTransferOperator::Mult(const Vector& x, Vector& y) const
1488 {
1489  if (P)
1490  {
1491  P->Mult(x, tmpL);
1492  localTransferOperator->Mult(tmpL, tmpH);
1493  R->Mult(tmpH, y);
1494  }
1495  else if (R)
1496  {
1497  localTransferOperator->Mult(x, tmpH);
1498  R->Mult(tmpH, y);
1499  }
1500  else
1501  {
1502  localTransferOperator->Mult(x, y);
1503  }
1504 }
1505 
1507 {
1508  if (P)
1509  {
1510  R->MultTranspose(x, tmpH);
1511  localTransferOperator->MultTranspose(tmpH, tmpL);
1512  P->MultTranspose(tmpL, y);
1513  }
1514  else if (R)
1515  {
1516  R->MultTranspose(x, tmpH);
1517  localTransferOperator->MultTranspose(tmpH, y);
1518  }
1519  else
1520  {
1521  localTransferOperator->MultTranspose(x, y);
1522  }
1523 }
1524 
1525 } // namespace mfem
const T * Read(bool on_dev=true) const
Shortcut for mfem::Read(a.GetMemory(), a.Size(), on_dev).
Definition: array.hpp:307
Abstract class for all finite elements.
Definition: fe_base.hpp:232
const Operator & MakeTrueOperator(FiniteElementSpace &fes_in, FiniteElementSpace &fes_out, const Operator &oper, OperatorHandle &t_oper)
Definition: transfer.cpp:34
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:93
virtual void Prolongate(const Vector &x, Vector &y) const
Definition: transfer.cpp:473
void SetSubVector(const Array< int > &dofs, const double value)
Set the entries listed in dofs to the given value.
Definition: vector.cpp:574
int GetNPoints() const
Returns the number of the points in the integration rule.
Definition: intrules.hpp:247
void AddMultVWt(const Vector &v, const Vector &w, DenseMatrix &VWt)
VWt += v w^t.
Definition: densemat.cpp:3166
int * GetJ()
Definition: table.hpp:114
Class for an integration rule - an Array of IntegrationPoint.
Definition: intrules.hpp:90
bool IsVariableOrder() const
Returns true if the space contains elements of varying polynomial orders.
Definition: fespace.hpp:463
virtual void MultTranspose(const Vector &x, Vector &y) const override
Restriction by applying the transpose of the Mult method.
Definition: transfer.cpp:1426
Data type for scaled Jacobi-type smoother of sparse matrix.
virtual int OrderW() const =0
Return the order of the determinant of the Jacobian (weight) of the transformation.
const IntegrationRule & Get(int GeomType, int Order)
Returns an integration rule for given GeomType and Order.
Definition: intrules.cpp:923
BilinearFormIntegrator * mass_integ
Ownership depends on own_mass_integ.
Definition: transfer.hpp:126
Tensor product representation using 1D matrices/tensors with dimensions using 1D number of quadrature...
Definition: fe_base.hpp:160
L2ProjectionH1Space(const FiniteElementSpace &fes_ho_, const FiniteElementSpace &fes_lor_)
Definition: transfer.cpp:545
void SetRow(int r, const double *row)
Definition: densemat.cpp:2178
virtual ~TensorProductPRefinementTransferOperator()
Destructor.
Definition: transfer.cpp:1396
Geometry::Type GetElementBaseGeometry(int i) const
Definition: mesh.hpp:1108
Field is discontinuous across element interfaces.
Definition: fe_coll.hpp:48
virtual void Mult(const Vector &x, Vector &y) const
Definition: transfer.cpp:692
static const int NumGeom
Definition: geom.hpp:42
FiniteElementSpace & dom_fes
Domain FE space.
Definition: transfer.hpp:32
int Dimension() const
Definition: mesh.hpp:1047
virtual int GetContType() const =0
Matrix-free transfer operator between finite element spaces on the same mesh.
Definition: transfer.hpp:389
void Mult(const double *x, double *y) const
Matrix vector multiplication with the inverse of dense matrix.
Definition: densemat.cpp:3963
void SetSize(int s)
Resize the vector to size s.
Definition: vector.hpp:512
void GetInverseMatrix(DenseMatrix &Ainv) const
Compute and return the inverse matrix in Ainv.
Definition: densemat.cpp:3929
static int DecodeDof(int dof)
Helpers to remove encoded sign from a DOF.
Definition: fespace.hpp:262
const SparseMatrix * GetConformingRestriction() const
The returned SparseMatrix is owned by the FiniteElementSpace.
Definition: fespace.cpp:1239
virtual void UseDevice(bool use_dev) const
Enable execution of Vector operations using the mfem::Device.
Definition: vector.hpp:117
void Mult(const Table &A, const Table &B, Table &C)
C = A * B (as boolean matrices)
Definition: table.cpp:475
Pointer to an Operator of a specified type.
Definition: handle.hpp:33
int * GetJ()
Return the array J.
Definition: sparsemat.hpp:227
int Width() const
Get the width (size of input) of the Operator. Synonym with NumCols().
Definition: operator.hpp:72
virtual void MultTranspose(const Vector &x, Vector &y) const override
Restriction by applying the transpose of the Mult method.
Definition: transfer.cpp:1506
void SetIntPoint(const IntegrationPoint *ip)
Set the integration point ip that weights and Jacobians will be evaluated at.
Definition: eltrans.hpp:93
int Size() const
Returns the size of the vector.
Definition: vector.hpp:199
virtual const Operator * GetRestrictionOperator() const
An abstract operator that performs the same action as GetRestrictionMatrix.
Definition: fespace.hpp:491
int nqpt
Number of quadrature points. When mode is TENSOR, this is the 1D number.
Definition: fe_base.hpp:172
Data type dense matrix using column-major storage.
Definition: densemat.hpp:23
virtual ~TransferOperator()
Destructor.
Definition: transfer.cpp:954
Operator::Type oper_type
Desired Operator::Type for the construction of all operators defined by the underlying transfer algor...
Definition: transfer.hpp:38
int GetNDofs() const
Returns number of degrees of freedom.
Definition: fespace.hpp:584
virtual const double * Read(bool on_dev=true) const
Shortcut for mfem::Read(vec.GetMemory(), vec.Size(), on_dev).
Definition: vector.hpp:448
int ndof
Number of degrees of freedom = number of basis functions. When mode is TENSOR, this is the 1D number...
Definition: fe_base.hpp:168
int * GetI()
Return the array I.
Definition: sparsemat.hpp:222
~TrueTransferOperator()
Destructor.
Definition: transfer.cpp:1482
virtual 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...
Definition: transfer.cpp:956
virtual void Mult(const Vector &x, Vector &y) const =0
Operator application: y=A(x).
Abstract parallel finite element space.
Definition: pfespace.hpp:28
virtual const Operator & ForwardOperator()
Return an Operator that transfers GridFunctions from the domain FE space to GridFunctions in the rang...
Definition: transfer.cpp:887
void Factor()
Factor the current DenseMatrix, *a.
Definition: densemat.cpp:3917
void GetSubVector(const Array< int > &dofs, Vector &elemvect) const
Extract entries listed in dofs to the output Vector elemvect.
Definition: vector.cpp:548
virtual void Prolongate(const Vector &x, Vector &y) const
Definition: transfer.cpp:734
HypreParMatrix * ParMult(const HypreParMatrix *A, const HypreParMatrix *B, bool own_matrix)
Definition: hypre.cpp:2850
virtual void ProlongateTranspose(const Vector &x, Vector &y) const
Definition: transfer.cpp:510
int RowSize(int i) const
Definition: table.hpp:108
virtual const FiniteElement * GetFE(int i) const
Returns pointer to the FiniteElement in the FiniteElementCollection associated with i&#39;th element in t...
Definition: fespace.cpp:2783
void BuildHo2Lor(int nel_ho, int nel_lor, const CoarseFineTransformations &cf_tr)
Definition: transfer.cpp:238
virtual ~PRefinementTransferOperator()
Destructor.
Definition: transfer.cpp:975
IntegrationRules IntRules(0, Quadrature1D::GaussLegendre)
A global object with all integration rules (defined in intrules.cpp)
Definition: intrules.hpp:379
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:1188
Derefinement operator, used by the friend class InterpolationGridTransfer.
Definition: fespace.hpp:324
const ElementRestrictionOperator * GetElementRestriction(ElementDofOrdering e_ordering) const
Return an Operator that converts L-vectors to E-vectors.
Definition: fespace.cpp:1259
FiniteElementSpace & ran_fes
Range FE space.
Definition: transfer.hpp:33
Geometry::Type GetGeomType() const
Returns the Geometry::Type of the reference element.
Definition: fe_base.hpp:319
ID for class SparseMatrix.
Definition: operator.hpp:286
const Table * GetElementToFaceOrientationTable() const
Definition: fespace.hpp:746
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:364
IntegrationPoint & IntPoint(int i)
Returns a reference to the i-th integration point.
Definition: intrules.hpp:250
virtual const Operator & BackwardOperator()
Return an Operator that transfers GridFunctions from the range FE space back to GridFunctions in the ...
Definition: transfer.cpp:189
void SetPointMat(const DenseMatrix &pm)
Set the underlying point matrix describing the transformation.
Definition: eltrans.hpp:401
virtual void AssembleElementMatrix(const FiniteElement &el, ElementTransformation &Trans, DenseMatrix &elmat)
General product operator: x -> (A*B)(x) = A(B(x)).
Definition: operator.hpp:774
ID for the base class Operator, i.e. any type.
Definition: operator.hpp:285
virtual void SetPrintLevel(int print_lvl)
Legacy method to set the level of verbosity of the solver output.
Definition: solvers.cpp:71
virtual void MultTranspose(const Vector &x, Vector &y) const override
Restriction by applying the transpose of the Mult method.
Definition: transfer.cpp:961
double * GetData() const
Returns the matrix data array.
Definition: densemat.hpp:115
DenseTensor point_matrices[Geometry::NumGeom]
Definition: ncmesh.hpp:77
Data type sparse matrix.
Definition: sparsemat.hpp:50
const int MAX_Q1D
Definition: forall.hpp:29
void ElemMixedMass(Geometry::Type geom, const FiniteElement &fe_ho, const FiniteElement &fe_lor, ElementTransformation *el_tr, IntegrationPointTransformation &ip_tr, DenseMatrix &M_mixed_el) const
Definition: transfer.cpp:258
const FiniteElementCollection * FEColl() const
Definition: fespace.hpp:601
OperatorHandle F
Forward, coarse-to-fine, operator.
Definition: transfer.hpp:129
GridTransfer(FiniteElementSpace &dom_fes_, FiniteElementSpace &ran_fes_)
Definition: transfer.cpp:19
virtual const SparseMatrix * GetRestrictionMatrix() const
The returned SparseMatrix is owned by the FiniteElementSpace.
Definition: fespace.hpp:495
static MemoryType GetMemoryType()
(DEPRECATED) Equivalent to GetDeviceMemoryType().
Definition: device.hpp:277
void SetMaxIter(int max_it)
Definition: solvers.hpp:201
TensorProductPRefinementTransferOperator(const FiniteElementSpace &lFESpace_, const FiniteElementSpace &hFESpace_)
Constructs a transfer operator from lFESpace to hFESpace which have different FE collections.
Definition: transfer.cpp:1102
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...
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:1912
void Restriction2D(const int NE, const int D1D, const int Q1D, const Vector &localH, Vector &localL, const Array< double > &Bt, const Vector &mask)
Definition: transfer.cpp:1292
const SparseMatrix * GetConformingProlongation() const
The returned SparseMatrix is owned by the FiniteElementSpace.
Definition: fespace.cpp:1232
Array< Embedding > embeddings
Fine element positions in their parents.
Definition: ncmesh.hpp:73
L2Projection(const FiniteElementSpace &fes_ho_, const FiniteElementSpace &fes_lor_)
Definition: transfer.cpp:231
double Weight()
Return the weight of the Jacobian matrix of the transformation at the currently set IntegrationPoint...
Definition: eltrans.hpp:131
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:118
virtual void Mult(const Vector &x, Vector &y) const
Definition: transfer.cpp:406
void GetRow(int i, Array< int > &row) const
Return row i in array row (the Table must be finalized)
Definition: table.cpp:187
void Mult(const double *x, double *y) const
Matrix vector multiplication.
Definition: densemat.cpp:173
int GetNE() const
Returns number of elements in the mesh.
Definition: fespace.hpp:614
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:640
void AddSubMatrix(const Array< int > &rows, const Array< int > &cols, const DenseMatrix &subm, int skip_zeros=1)
Definition: sparsemat.cpp:2722
OperatorHandle B
Backward, fine-to-coarse, operator.
Definition: transfer.hpp:130
List of mesh geometries stored as Array<Geometry::Type>.
Definition: mesh.hpp:1131
int GetVDim() const
Returns vector dimension.
Definition: fespace.hpp:581
virtual const Operator & BackwardOperator()
Return an Operator that transfers GridFunctions from the range FE space back to GridFunctions in the ...
Definition: transfer.cpp:893
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, transfer operator.
Definition: transfer.cpp:146
Array< double > Bt
Transpose of B.
Definition: fe_base.hpp:189
virtual int GetTrueVSize() const
Return the number of vector true (conforming) dofs.
Definition: fespace.hpp:590
Mesh * GetMesh() const
Returns the mesh.
Definition: fespace.hpp:441
virtual void InvTransformPrimal(double *v) const =0
Abstract base class BilinearFormIntegrator.
Definition: bilininteg.hpp:35
virtual void MultTranspose(const Vector &x, Vector &y) const override
Restriction by applying the transpose of the Mult method.
Definition: transfer.cpp:1028
void Transpose()
(*this) = (*this)^t
Definition: densemat.cpp:1420
void SetIdentityTransformation(Geometry::Type GeomType)
Set the FiniteElement Geometry for the reference elements being used.
Definition: eltrans.cpp:383
ComplexDenseMatrix * MultAtB(const ComplexDenseMatrix &A, const ComplexDenseMatrix &B)
Multiply the complex conjugate transpose of a matrix A with a matrix B. A^H*B.
Matrix-free transfer operator between finite element spaces.
Definition: transfer.hpp:358
Operator that converts FiniteElementSpace L-vectors to E-vectors.
Definition: restriction.hpp:37
Class FiniteElementSpace - responsible for providing FEM view of the mesh, mainly managing the set of...
Definition: fespace.hpp:96
SparseMatrix * RefinementMatrix_main(const int coarse_ndofs, const Table &coarse_elem_dof, const Table *coarse_elem_fos, const DenseTensor localP[]) const
Definition: fespace.cpp:1387
Matrix-free transfer operator between finite element spaces on the same mesh exploiting the tensor pr...
Definition: transfer.hpp:420
void GetRow(int r, Vector &row) const
Definition: densemat.cpp:1315
virtual void TransformPrimal(double *v) const =0
void SetSize(int nsize)
Change the logical size of the array, keep existing entries.
Definition: array.hpp:684
virtual 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...
Definition: transfer.cpp:1400
L2Prolongation * B
Backward, fine-to-coarse, operator.
Definition: transfer.hpp:336
void Transpose(const Table &A, Table &At, int ncols_A_)
Transpose a Table.
Definition: table.cpp:413
void Transform(const IntegrationPoint &, IntegrationPoint &)
Definition: eltrans.cpp:546
void Restriction3D(const int NE, const int D1D, const int Q1D, const Vector &localH, Vector &localL, const Array< double > &Bt, const Vector &mask)
Definition: transfer.cpp:1331
int GetDof() const
Returns the number of degrees of freedom in the finite element.
Definition: fe_base.hpp:322
int Height() const
Get the height (size of output) of the Operator. Synonym with NumRows().
Definition: operator.hpp:66
Structure representing the matrices/tensors needed to evaluate (in reference space) the values...
Definition: fe_base.hpp:135
virtual DofTransformation * GetElementDofs(int elem, Array< int > &dofs) const
Returns indices of degrees of freedom of element &#39;elem&#39;.
Definition: fespace.cpp:2680
bool own_mass_integ
Ownership flag for mass_integ.
Definition: transfer.hpp:127
const CoarseFineTransformations & GetRefinementTransforms()
Definition: mesh.cpp:9990
Vector & Set(const double a, const Vector &x)
(*this) = a * x
Definition: vector.cpp:268
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:5932
virtual void MultTranspose(const Vector &x, Vector &y) const
Definition: transfer.cpp:438
L2Projection * F
Forward, coarse-to-fine, operator.
Definition: transfer.hpp:335
Array< double > B
Basis functions evaluated at quadrature points.
Definition: fe_base.hpp:183
int GetNE() const
Returns number of elements.
Definition: mesh.hpp:936
virtual const Operator * GetProlongationMatrix() const
The returned Operator is owned by the FiniteElementSpace.
Definition: fespace.hpp:479
virtual const Operator & ForwardOperator()
Return an Operator that transfers GridFunctions from the domain FE space to GridFunctions in the rang...
Definition: transfer.cpp:155
virtual double * ReadWrite(bool on_dev=true)
Shortcut for mfem::ReadWrite(vec.GetMemory(), vec.Size(), on_dev).
Definition: vector.hpp:464
Class for integration point with weight.
Definition: intrules.hpp:25
void SetOperatorOwner(bool own=true)
Set the ownership flag for the held Operator.
Definition: handle.hpp:120
A standard isoparametric element transformation.
Definition: eltrans.hpp:361
OpType * As() const
Return the Operator pointer statically cast to a specified OpType. Similar to the method Get()...
Definition: handle.hpp:104
GridFunction interpolation operator applicable after mesh refinement.
Definition: fespace.hpp:298
virtual 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...
Definition: transfer.cpp:977
SparseMatrix * TransposeMult(const SparseMatrix &A, const SparseMatrix &B)
C = A^T B.
Definition: sparsemat.cpp:3767
const FiniteElementSpace & fes_lor
Definition: transfer.hpp:189
General triple product operator x -> A*B*C*x, with ownership of the factors.
Definition: operator.hpp:838
PRefinementTransferOperator(const FiniteElementSpace &lFESpace_, const FiniteElementSpace &hFESpace_)
Constructs a transfer operator from lFESpace to hFESpace which have different FE collections.
Definition: transfer.cpp:967
const int MAX_D1D
Definition: forall.hpp:28
TrueTransferOperator(const FiniteElementSpace &lFESpace_, const FiniteElementSpace &hFESpace_)
Constructs a transfer operator working on true degrees of freedom from lFESpace to hFESpace...
Definition: transfer.cpp:1453
IsoparametricTransformation Transf
Definition: eltrans.hpp:464
virtual void Mult(const Vector &x, Vector &y) const override
Interpolation or prolongation of a true dof vector x to a true dof vector y.
Definition: transfer.cpp:1487
void Copy(Array &copy) const
Create a copy of the internal array to the provided copy.
Definition: array.hpp:861
int GetVSize() const
Return the number of vector dofs, i.e. GetNDofs() x GetVDim().
Definition: fespace.hpp:587
int GetMapType() const
Returns the FiniteElement::MapType of the element describing how reference functions are mapped to ph...
Definition: fe_base.hpp:348
Lexicographic ordering for tensor-product FiniteElements.
Operator * Ptr() const
Access the underlying Operator pointer.
Definition: handle.hpp:87
bool Parallel() const
Definition: transfer.hpp:46
int Size() const
Return the logical size of the array.
Definition: array.hpp:141
virtual void SetOperator(const Operator &op)
Also calls SetOperator for the preconditioner if there is one.
Definition: solvers.hpp:507
Vector data type.
Definition: vector.hpp:60
ID for class HypreParMatrix.
Definition: operator.hpp:287
virtual void SetPreconditioner(Solver &pr)
This should be called before SetOperator.
Definition: solvers.cpp:173
int SizeK() const
Definition: densemat.hpp:1026
int * GetI()
Definition: table.hpp:113
virtual void ProlongateTranspose(const Vector &x, Vector &y) const
Definition: transfer.cpp:759
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.
Definition: densemat.cpp:1592
Defines the coarse-fine transformations of all fine elements.
Definition: ncmesh.hpp:70
RefCoord s[3]
Field is continuous across element interfaces.
Definition: fe_coll.hpp:45
HypreParMatrix * Dof_TrueDof_Matrix() const
The true dof-to-dof interpolation matrix.
Definition: pfespace.hpp:321
void SetSize(int s)
Change the size of the DenseMatrix to s x s.
Definition: densemat.hpp:105
virtual void InvTransformDual(double *v) const =0
Abstract operator.
Definition: operator.hpp:24
Wrapper for hypre&#39;s ParCSR matrix class.
Definition: hypre.hpp:343
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:131
const IntegrationRule & GetNodes() const
Get a const reference to the nodes of the element.
Definition: fe_base.hpp:388
Rank 3 tensor (array of matrices)
Definition: densemat.hpp:978
L2ProjectionL2Space(const FiniteElementSpace &fes_ho_, const FiniteElementSpace &fes_lor_)
Definition: transfer.cpp:285
HYPRE_BigInt * GetTrueDofOffsets() const
Definition: pfespace.hpp:282
void Prolongation2D(const int NE, const int D1D, const int Q1D, const Vector &localL, Vector &localH, const Array< double > &B, const Vector &mask)
Definition: transfer.cpp:1173
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:750
virtual void TransformDual(double *v) const =0
virtual const SparseMatrix * GetHpRestrictionMatrix() const
The returned SparseMatrix is owned by the FiniteElementSpace.
Definition: fespace.hpp:499
void GetLocalRefinementMatrices(Geometry::Type geom, DenseTensor &localP) const
Definition: fespace.cpp:1451
void DofsToVDofs(Array< int > &dofs, int ndofs=-1) const
Definition: fespace.cpp:215
int GetOrder() const
Returns the order of the finite element. In the case of anisotropic orders, returns the maximum order...
Definition: fe_base.hpp:326
virtual bool SupportsBackwardsOperator() const
Definition: transfer.cpp:916
TransferOperator(const FiniteElementSpace &lFESpace, const FiniteElementSpace &hFESpace)
Constructs a transfer operator from lFESpace to hFESpace.
Definition: transfer.cpp:922
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:3246
virtual void MultTranspose(const Vector &x, Vector &y) const
Definition: transfer.cpp:713
void Reset(OpType *A, bool own_A=true)
Reset the OperatorHandle to the given OpType pointer, A.
Definition: handle.hpp:145
void Prolongation3D(const int NE, const int D1D, const int Q1D, const Vector &localL, Vector &localH, const Array< double > &B, const Vector &mask)
Definition: transfer.cpp:1220
ElementTransformation * GetElementTransformation(int i) const
Returns ElementTransformation for the i-th element.
Definition: fespace.hpp:647