From be9310322e1fa187e205c2ce2c9adfe65afa5011 Mon Sep 17 00:00:00 2001 From: Will Pazner Date: Wed, 6 Mar 2019 13:51:54 -0800 Subject: [PATCH] Add L2 projection and mass-conserving left-inverse --- fem/fespace.cpp | 159 ++++++++++++++++++++++++++++++++++++++++++++++++ fem/fespace.hpp | 41 +++++++++++++ 2 files changed, 200 insertions(+) diff --git a/fem/fespace.cpp b/fem/fespace.cpp index 083687834a..e595b1ecbe 100644 --- a/fem/fespace.cpp +++ b/fem/fespace.cpp @@ -2181,5 +2181,164 @@ void QuadratureSpace::Save(std::ostream &out) const << "Order: " << order << '\n'; } +L2Projection::L2Projection(const FiniteElementSpace &fes_ho_, + const FiniteElementSpace &fes_lor_) + : fes_ho(fes_ho_), fes_lor(fes_lor_) +{ + ndof_lor = fes_lor.GetFE(0)->GetDof(); + ndof_ho = fes_ho.GetFE(0)->GetDof(); + + nel_lor = fes_lor.GetNE(); + nel_ho = fes_ho.GetNE(); + + nref = nel_lor/nel_ho; + + // Construct the mapping from HO to LOR and reverse + // lor2ho[ilor] will give the unique HO coarse element cotaining the ilor + // ho2lor.GetRow(iho) will give all the LOR elements contained in iho + lor2ho.SetSize(nel_lor); + ho2lor.SetSize(nel_ho, nref); + const CoarseFineTransformations &cf_tr + = fes_lor.GetMesh()->GetRefinementTransforms(); + for (int ilor=0; ilorGetGeomType(); + const DenseTensor &pmats = cf_tr.GetPointMatrices(geom); + const FiniteElement *fe_lor = fes_lor.FEColl()->FiniteElementForGeometry(geom); + const FiniteElement *fe_ho = fes_ho.FEColl()->FiniteElementForGeometry(geom); + emb_tr.SetIdentityTransformation(geom); + for (int iref=0; irefGetOrder() + fe_ho->GetOrder() + el_tr->OrderW(); + const IntegrationRule *ir = &IntRules.Get(geom, order); + M_mixed_el = 0.0; + for (int i = 0; i < ir->GetNPoints(); i++) + { + const IntegrationPoint &ip_lor = ir->IntPoint(i); + IntegrationPoint ip_ho; + ip_tr.Transform(ip_lor, ip_ho); + fe_lor->CalcShape(ip_lor, shape_lor); + fe_ho->CalcShape(ip_ho, shape_ho); + el_tr->SetIntPoint(&ip_lor); + // For now we use the geometry information from the LOR space + // which means we won't be mass conservative if the mesh is curved + double w = el_tr->Weight()*ip_lor.weight; + shape_lor *= w; + AddMultVWt(shape_lor, shape_ho, M_mixed_el); + } + M_mixed.CopyMN(M_mixed_el, iref*ndof_lor, 0); + } + mfem::Mult(Minv_lor, M_mixed, R(iho)); + + mfem::MultAtB(R(iho), M_lor, RtMlor); + mfem::Mult(RtMlor, R(iho), RtMlorR); + RtMlorR_inv.Factor(); + RtMlorR_inv.Mult(RtMlor, P(iho)); + } +} + +void L2Projection::Mult(const Vector &x, Vector &y) const +{ + Array vdofs; + Vector xel(ndof_ho); + Vector yel(ndof_lor*nref); + for (int iho=0; iho vdofs; + Vector xel(ndof_lor*nref); + Vector yel(ndof_ho); + for (int iho=0; iho lor2ho; + Table ho2lor; + + DenseTensor R, P; +public: + L2Projection(const FiniteElementSpace &fes_ho_, + const FiniteElementSpace &fes_lor_); + /// Perform the L2 projection onto the LOR space + virtual void Mult(const Vector &x, Vector &y) const; + /// Perform the mass conservative left-inverse prolongation operation. + /// This functionality is also provided as an Operator by L2Prolongation. + void Prolongate(const Vector &x, Vector &y) const; + virtual ~L2Projection() { } +}; + +/** Mass-conservative prolongation operator going in the opposite direction + * as L2Projection. This operator is a left inverse to the L2Projection. */ +class L2Prolongation : public Operator +{ + const L2Projection &l2proj; +public: + L2Prolongation(const L2Projection &l2proj_) : l2proj(l2proj_) { } + void Mult(const Vector &x, Vector &y) const + { + l2proj.Prolongate(x, y); + } + virtual ~L2Prolongation() { } +}; + } #endif