351 lines
14 KiB
C++
351 lines
14 KiB
C++
// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
|
|
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
|
|
// LICENSE and NOTICE for details. LLNL-CODE-806117.
|
|
//
|
|
// This file is part of the MFEM library. For more information and source code
|
|
// availability visit https://mfem.org.
|
|
//
|
|
// MFEM is free software; you can redistribute it and/or modify it under the
|
|
// terms of the BSD-3 license. We welcome feedback and contributions, see file
|
|
// CONTRIBUTING.md for details.
|
|
|
|
#ifndef MFEM_PGRIDFUNC
|
|
#define MFEM_PGRIDFUNC
|
|
|
|
#include "../config/config.hpp"
|
|
|
|
#ifdef MFEM_USE_MPI
|
|
|
|
#include "../general/globals.hpp"
|
|
#include "pfespace.hpp"
|
|
#include "gridfunc.hpp"
|
|
#include <iostream>
|
|
#include <limits>
|
|
|
|
namespace mfem
|
|
{
|
|
|
|
/// Compute a global Lp norm from the local Lp norms computed by each processor
|
|
double GlobalLpNorm(const double p, double loc_norm, MPI_Comm comm);
|
|
|
|
/// Class for parallel grid function
|
|
class ParGridFunction : public GridFunction
|
|
{
|
|
protected:
|
|
ParFiniteElementSpace *pfes; ///< Points to the same object as #fes
|
|
|
|
/** @brief Vector used to store data from face-neighbor processors,
|
|
initialized by ExchangeFaceNbrData(). */
|
|
Vector face_nbr_data;
|
|
|
|
void ProjectBdrCoefficient(Coefficient *coeff[], VectorCoefficient *vcoeff,
|
|
Array<int> &attr);
|
|
|
|
public:
|
|
ParGridFunction() { pfes = NULL; }
|
|
|
|
/// Copy constructor. The internal vector #face_nbr_data is not copied.
|
|
ParGridFunction(const ParGridFunction &orig)
|
|
: GridFunction(orig), pfes(orig.pfes) { }
|
|
|
|
ParGridFunction(ParFiniteElementSpace *pf) : GridFunction(pf), pfes(pf) { }
|
|
|
|
/// Construct a ParGridFunction using previously allocated array @a data.
|
|
/** The ParGridFunction does not assume ownership of @a data which is assumed
|
|
to be of size at least `pf->GetVSize()`. Similar to the GridFunction and
|
|
Vector constructors for externally allocated array, the pointer @a data
|
|
can be NULL. The data array can be replaced later using the method
|
|
SetData().
|
|
*/
|
|
ParGridFunction(ParFiniteElementSpace *pf, double *data) :
|
|
GridFunction(pf, data), pfes(pf) { }
|
|
|
|
/// Construct a ParGridFunction using a GridFunction as external data.
|
|
/** The parallel space @a *pf and the space used by @a *gf should match. The
|
|
data from @a *gf is used as the local data of the ParGridFunction on each
|
|
processor. The ParGridFunction does not assume ownership of the data. */
|
|
ParGridFunction(ParFiniteElementSpace *pf, GridFunction *gf);
|
|
|
|
/** @brief Creates grid function on (all) dofs from a given vector on the
|
|
true dofs, i.e. P tv. */
|
|
ParGridFunction(ParFiniteElementSpace *pf, HypreParVector *tv);
|
|
|
|
/** @brief Construct a local ParGridFunction from the given *global*
|
|
GridFunction. If @a partitioning is NULL (default), the data from @a gf
|
|
is NOT copied. */
|
|
ParGridFunction(ParMesh *pmesh, const GridFunction *gf,
|
|
const int *partitioning = NULL);
|
|
|
|
/** @brief Construct a ParGridFunction on a given ParMesh, @a pmesh, reading
|
|
from an std::istream.
|
|
|
|
In the process, a ParFiniteElementSpace and a FiniteElementCollection are
|
|
constructed. The new ParGridFunction assumes ownership of both. */
|
|
ParGridFunction(ParMesh *pmesh, std::istream &input);
|
|
|
|
/// Copy assignment. Only the data of the base class Vector is copied.
|
|
/** It is assumed that this object and @a rhs use ParFiniteElementSpace%s
|
|
that have the same size.
|
|
|
|
@note Defining this method overwrites the implicitly defined copy
|
|
assignment operator. */
|
|
ParGridFunction &operator=(const ParGridFunction &rhs)
|
|
{ return operator=((const Vector &)rhs); }
|
|
|
|
/// Assign constant values to the ParGridFunction data.
|
|
ParGridFunction &operator=(double value)
|
|
{ GridFunction::operator=(value); return *this; }
|
|
|
|
/// Copy the data from a Vector to the ParGridFunction data.
|
|
ParGridFunction &operator=(const Vector &v)
|
|
{ GridFunction::operator=(v); return *this; }
|
|
|
|
ParFiniteElementSpace *ParFESpace() const { return pfes; }
|
|
|
|
virtual void Update();
|
|
|
|
/// Associate a new FiniteElementSpace with the ParGridFunction.
|
|
/** The ParGridFunction is resized using the SetSize() method. The new space
|
|
@a f is expected to be a ParFiniteElementSpace. */
|
|
virtual void SetSpace(FiniteElementSpace *f);
|
|
|
|
/// Associate a new parallel space with the ParGridFunction.
|
|
void SetSpace(ParFiniteElementSpace *f);
|
|
|
|
using GridFunction::MakeRef;
|
|
|
|
/** @brief Make the ParGridFunction reference external data on a new
|
|
FiniteElementSpace. */
|
|
/** This method changes the FiniteElementSpace associated with the
|
|
ParGridFunction and sets the pointer @a v as external data in the
|
|
ParGridFunction. The new space @a f is expected to be a
|
|
ParFiniteElementSpace. */
|
|
virtual void MakeRef(FiniteElementSpace *f, double *v);
|
|
|
|
/** @brief Make the ParGridFunction reference external data on a new
|
|
ParFiniteElementSpace. */
|
|
/** This method changes the ParFiniteElementSpace associated with the
|
|
ParGridFunction and sets the pointer @a v as external data in the
|
|
ParGridFunction. */
|
|
void MakeRef(ParFiniteElementSpace *f, double *v);
|
|
|
|
/** @brief Make the ParGridFunction reference external data on a new
|
|
FiniteElementSpace. */
|
|
/** This method changes the FiniteElementSpace associated with the
|
|
ParGridFunction and sets the data of the Vector @a v (plus the @a
|
|
v_offset) as external data in the ParGridFunction. The new space @a f is
|
|
expected to be a ParFiniteElementSpace.
|
|
@note This version of the method will also perform bounds checks when
|
|
the build option MFEM_DEBUG is enabled. */
|
|
virtual void MakeRef(FiniteElementSpace *f, Vector &v, int v_offset);
|
|
|
|
/** @brief Make the ParGridFunction reference external data on a new
|
|
ParFiniteElementSpace. */
|
|
/** This method changes the ParFiniteElementSpace associated with the
|
|
ParGridFunction and sets the data of the Vector @a v (plus the
|
|
@a v_offset) as external data in the ParGridFunction.
|
|
@note This version of the method will also perform bounds checks when
|
|
the build option MFEM_DEBUG is enabled. */
|
|
void MakeRef(ParFiniteElementSpace *f, Vector &v, int v_offset);
|
|
|
|
/** Set the grid function on (all) dofs from a given vector on the
|
|
true dofs, i.e. P tv. */
|
|
void Distribute(const Vector *tv);
|
|
void Distribute(const Vector &tv) { Distribute(&tv); }
|
|
void AddDistribute(double a, const Vector *tv);
|
|
void AddDistribute(double a, const Vector &tv) { AddDistribute(a, &tv); }
|
|
|
|
/// Set the GridFunction from the given true-dof vector.
|
|
virtual void SetFromTrueDofs(const Vector &tv) { Distribute(tv); }
|
|
|
|
/// Short semantic for Distribute()
|
|
ParGridFunction &operator=(const HypreParVector &tv)
|
|
{ Distribute(&tv); return (*this); }
|
|
|
|
using GridFunction::GetTrueDofs;
|
|
|
|
/// Returns the true dofs in a new HypreParVector
|
|
HypreParVector *GetTrueDofs() const;
|
|
|
|
/// Returns the vector averaged on the true dofs.
|
|
void ParallelAverage(Vector &tv) const;
|
|
|
|
/// Returns the vector averaged on the true dofs.
|
|
void ParallelAverage(HypreParVector &tv) const;
|
|
|
|
/// Returns a new vector averaged on the true dofs.
|
|
HypreParVector *ParallelAverage() const;
|
|
|
|
/// Returns the vector restricted to the true dofs.
|
|
void ParallelProject(Vector &tv) const;
|
|
|
|
/// Returns the vector restricted to the true dofs.
|
|
void ParallelProject(HypreParVector &tv) const;
|
|
|
|
/// Returns a new vector restricted to the true dofs.
|
|
HypreParVector *ParallelProject() const;
|
|
|
|
/// Returns the vector assembled on the true dofs.
|
|
void ParallelAssemble(Vector &tv) const;
|
|
|
|
/// Returns the vector assembled on the true dofs.
|
|
void ParallelAssemble(HypreParVector &tv) const;
|
|
|
|
/// Returns a new vector assembled on the true dofs.
|
|
HypreParVector *ParallelAssemble() const;
|
|
|
|
void ExchangeFaceNbrData();
|
|
Vector &FaceNbrData() { return face_nbr_data; }
|
|
const Vector &FaceNbrData() const { return face_nbr_data; }
|
|
|
|
// Redefine to handle the case when i is a face-neighbor element
|
|
virtual double GetValue(int i, const IntegrationPoint &ip,
|
|
int vdim = 1) const;
|
|
double GetValue(ElementTransformation &T)
|
|
{ return GetValue(T.ElementNo, T.GetIntPoint()); }
|
|
|
|
using GridFunction::ProjectCoefficient;
|
|
virtual void ProjectCoefficient(Coefficient &coeff);
|
|
|
|
using GridFunction::ProjectDiscCoefficient;
|
|
/** @brief Project a discontinuous vector coefficient as a grid function on
|
|
a continuous finite element space. The values in shared dofs are
|
|
determined from the element with maximal attribute. */
|
|
virtual void ProjectDiscCoefficient(VectorCoefficient &coeff);
|
|
|
|
virtual void ProjectDiscCoefficient(Coefficient &coeff, AvgType type);
|
|
|
|
virtual void ProjectDiscCoefficient(VectorCoefficient &vcoeff, AvgType type);
|
|
|
|
using GridFunction::ProjectBdrCoefficient;
|
|
|
|
// Only the values in the master are guaranteed to be correct!
|
|
virtual void ProjectBdrCoefficient(VectorCoefficient &vcoeff,
|
|
Array<int> &attr)
|
|
{ ProjectBdrCoefficient(NULL, &vcoeff, attr); }
|
|
|
|
// Only the values in the master are guaranteed to be correct!
|
|
virtual void ProjectBdrCoefficient(Coefficient *coeff[], Array<int> &attr)
|
|
{ ProjectBdrCoefficient(coeff, NULL, attr); }
|
|
|
|
// Only the values in the master are guaranteed to be correct!
|
|
virtual void ProjectBdrCoefficientTangent(VectorCoefficient &vcoeff,
|
|
Array<int> &bdr_attr);
|
|
|
|
virtual double ComputeL1Error(Coefficient *exsol[],
|
|
const IntegrationRule *irs[] = NULL) const
|
|
{
|
|
return GlobalLpNorm(1.0, GridFunction::ComputeW11Error(
|
|
*exsol, NULL, 1, NULL, irs), pfes->GetComm());
|
|
}
|
|
|
|
virtual double ComputeL1Error(Coefficient &exsol,
|
|
const IntegrationRule *irs[] = NULL) const
|
|
{ return ComputeLpError(1.0, exsol, NULL, irs); }
|
|
|
|
virtual double ComputeL1Error(VectorCoefficient &exsol,
|
|
const IntegrationRule *irs[] = NULL) const
|
|
{ return ComputeLpError(1.0, exsol, NULL, NULL, irs); }
|
|
|
|
virtual double ComputeL2Error(Coefficient *exsol[],
|
|
const IntegrationRule *irs[] = NULL) const
|
|
{
|
|
return GlobalLpNorm(2.0, GridFunction::ComputeL2Error(exsol, irs),
|
|
pfes->GetComm());
|
|
}
|
|
|
|
virtual double ComputeL2Error(Coefficient &exsol,
|
|
const IntegrationRule *irs[] = NULL) const
|
|
{ return ComputeLpError(2.0, exsol, NULL, irs); }
|
|
|
|
virtual double ComputeL2Error(VectorCoefficient &exsol,
|
|
const IntegrationRule *irs[] = NULL,
|
|
Array<int> *elems = NULL) const
|
|
{
|
|
return GlobalLpNorm(2.0, GridFunction::ComputeL2Error(exsol, irs, elems),
|
|
pfes->GetComm());
|
|
}
|
|
|
|
virtual double ComputeMaxError(Coefficient *exsol[],
|
|
const IntegrationRule *irs[] = NULL) const
|
|
{
|
|
return GlobalLpNorm(infinity(),
|
|
GridFunction::ComputeMaxError(exsol, irs),
|
|
pfes->GetComm());
|
|
}
|
|
|
|
virtual double ComputeMaxError(Coefficient &exsol,
|
|
const IntegrationRule *irs[] = NULL) const
|
|
{
|
|
return ComputeLpError(infinity(), exsol, NULL, irs);
|
|
}
|
|
|
|
virtual double ComputeMaxError(VectorCoefficient &exsol,
|
|
const IntegrationRule *irs[] = NULL) const
|
|
{
|
|
return ComputeLpError(infinity(), exsol, NULL, NULL, irs);
|
|
}
|
|
|
|
virtual double ComputeLpError(const double p, Coefficient &exsol,
|
|
Coefficient *weight = NULL,
|
|
const IntegrationRule *irs[] = NULL) const
|
|
{
|
|
return GlobalLpNorm(p, GridFunction::ComputeLpError(
|
|
p, exsol, weight, irs), pfes->GetComm());
|
|
}
|
|
|
|
/** When given a vector weight, compute the pointwise (scalar) error as the
|
|
dot product of the vector error with the vector weight. Otherwise, the
|
|
scalar error is the l_2 norm of the vector error. */
|
|
virtual double ComputeLpError(const double p, VectorCoefficient &exsol,
|
|
Coefficient *weight = NULL,
|
|
VectorCoefficient *v_weight = NULL,
|
|
const IntegrationRule *irs[] = NULL) const
|
|
{
|
|
return GlobalLpNorm(p, GridFunction::ComputeLpError(
|
|
p, exsol, weight, v_weight, irs), pfes->GetComm());
|
|
}
|
|
|
|
virtual void ComputeFlux(BilinearFormIntegrator &blfi,
|
|
GridFunction &flux,
|
|
bool wcoef = true, int subdomain = -1);
|
|
|
|
/** Save the local portion of the ParGridFunction. This differs from the
|
|
serial GridFunction::Save in that it takes into account the signs of
|
|
the local dofs. */
|
|
virtual void Save(std::ostream &out) const;
|
|
|
|
#ifdef MFEM_USE_ADIOS2
|
|
/** Save the local portion of the ParGridFunction. This differs from the
|
|
serial GridFunction::Save in that it takes into account the signs of
|
|
the local dofs. */
|
|
virtual void Save(
|
|
adios2stream &out, const std::string &variable_name,
|
|
const adios2stream::data_type type = adios2stream::data_type::point_data) const;
|
|
#endif
|
|
|
|
/// Merge the local grid functions
|
|
void SaveAsOne(std::ostream &out = mfem::out);
|
|
|
|
virtual ~ParGridFunction() { }
|
|
};
|
|
|
|
|
|
/** Performs a global L2 projection (through a HypreBoomerAMG solve) of flux
|
|
from supplied discontinuous space into supplied smooth (continuous, or at
|
|
least conforming) space, and computes the Lp norms of the differences
|
|
between them on each element. This is one approach to handling conforming
|
|
and non-conforming elements in parallel. Returns the total error estimate. */
|
|
double L2ZZErrorEstimator(BilinearFormIntegrator &flux_integrator,
|
|
const ParGridFunction &x,
|
|
ParFiniteElementSpace &smooth_flux_fes,
|
|
ParFiniteElementSpace &flux_fes,
|
|
Vector &errors, int norm_p = 2, double solver_tol = 1e-12,
|
|
int solver_max_it = 200);
|
|
|
|
}
|
|
|
|
#endif // MFEM_USE_MPI
|
|
|
|
#endif
|