2210 lines
57 KiB
C++
2210 lines
57 KiB
C++
// Copyright (c) 2010-2025, 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.
|
|
|
|
// Implementation of Coefficient class
|
|
|
|
#include "fem.hpp"
|
|
#include "../general/forall.hpp"
|
|
|
|
#include <cmath>
|
|
#include <limits>
|
|
|
|
namespace mfem
|
|
{
|
|
|
|
using namespace std;
|
|
|
|
// Given an ElementTransformation and IntegrationPoint in a refined mesh,
|
|
// return the ElementTransformation of the parent coarse element, and set
|
|
// coarse_ip to the location of the original ip within the coarse element.
|
|
ElementTransformation *RefinedToCoarse(
|
|
Mesh &coarse_mesh, const ElementTransformation &T,
|
|
const IntegrationPoint &ip, IntegrationPoint &coarse_ip)
|
|
{
|
|
const Mesh &fine_mesh = *T.mesh;
|
|
// Get the element transformation of the coarse element containing the
|
|
// fine element.
|
|
int fine_element = T.ElementNo;
|
|
const CoarseFineTransformations &cf = fine_mesh.GetRefinementTransforms();
|
|
int coarse_element = cf.embeddings[fine_element].parent;
|
|
ElementTransformation *coarse_T = coarse_mesh.GetElementTransformation(
|
|
coarse_element);
|
|
// Transform the integration point from fine element coordinates to coarse
|
|
// element coordinates.
|
|
Geometry::Type geom = T.GetGeometryType();
|
|
IntegrationPointTransformation fine_to_coarse;
|
|
IsoparametricTransformation &emb_tr = fine_to_coarse.Transf;
|
|
emb_tr.SetIdentityTransformation(geom);
|
|
emb_tr.SetPointMat(cf.point_matrices[geom](cf.embeddings[fine_element].matrix));
|
|
fine_to_coarse.Transform(ip, coarse_ip);
|
|
coarse_T->SetIntPoint(&coarse_ip);
|
|
return coarse_T;
|
|
}
|
|
|
|
void Coefficient::Project(QuadratureFunction &qf)
|
|
{
|
|
QuadratureSpaceBase &qspace = *qf.GetSpace();
|
|
const int ne = qspace.GetNE();
|
|
Vector values;
|
|
// GetValues makes a reference, but we need it to be valid on Host
|
|
qf.HostWrite();
|
|
for (int iel = 0; iel < ne; ++iel)
|
|
{
|
|
qf.GetValues(iel, values);
|
|
const IntegrationRule &ir = qspace.GetIntRule(iel);
|
|
ElementTransformation& T = *qspace.GetTransformation(iel);
|
|
for (int iq = 0; iq < ir.Size(); ++iq)
|
|
{
|
|
const IntegrationPoint &ip = ir[iq];
|
|
T.SetIntPoint(&ip);
|
|
const int iq_p = qspace.GetPermutedIndex(iel, iq);
|
|
values[iq_p] = Eval(T, ip);
|
|
}
|
|
}
|
|
}
|
|
|
|
void ConstantCoefficient::Project(QuadratureFunction &qf)
|
|
{
|
|
qf = constant;
|
|
}
|
|
|
|
real_t PWConstCoefficient::Eval(ElementTransformation & T,
|
|
const IntegrationPoint & ip)
|
|
{
|
|
int att = T.Attribute;
|
|
return (constants(att-1));
|
|
}
|
|
|
|
void PWConstCoefficient::Project(QuadratureFunction &qf)
|
|
{
|
|
auto &qs = *qf.GetSpace();
|
|
|
|
const bool compressed =
|
|
qs.Offsets(QSpaceOffsetStorage::COMPRESSED).Size() == 1;
|
|
const int *offsets = qs.Offsets(QSpaceOffsetStorage::COMPRESSED).Read();
|
|
const int ne = qs.GetNE();
|
|
|
|
const int *attributes = [&]()
|
|
{
|
|
if (dynamic_cast<QuadratureSpace*>(&qs) != nullptr)
|
|
{
|
|
return qs.GetMesh()->GetElementAttributes().Read();
|
|
}
|
|
else if (auto *qs_f = dynamic_cast<FaceQuadratureSpace*>(&qs))
|
|
{
|
|
MFEM_VERIFY(qs_f->GetFaceType() == FaceType::Boundary,
|
|
"Interior faces do not have attributes.");
|
|
return qs.GetMesh()->GetBdrFaceAttributes().Read();
|
|
}
|
|
else
|
|
{
|
|
MFEM_ABORT("Unsupported case.");
|
|
}
|
|
}();
|
|
|
|
const real_t *d_c = constants.Read();
|
|
real_t *d_qf = qf.Write();
|
|
|
|
mfem::forall(ne, [=] MFEM_HOST_DEVICE (int e)
|
|
{
|
|
const int a = attributes[e];
|
|
const real_t elementConstant = d_c[a - 1];
|
|
const int begin = compressed ? e*offsets[0] : offsets[e];
|
|
const int end = compressed ? (e+1)*offsets[0] : offsets[e+1];
|
|
for (int i = begin; i < end; ++i)
|
|
{
|
|
d_qf[i] = elementConstant;
|
|
}
|
|
});
|
|
}
|
|
|
|
void PWCoefficient::InitMap(const Array<int> & attr,
|
|
const Array<Coefficient*> & coefs)
|
|
{
|
|
MFEM_VERIFY(attr.Size() == coefs.Size(),
|
|
"PWCoefficient: "
|
|
"Attribute and coefficient arrays have incompatible "
|
|
"dimensions.");
|
|
|
|
for (int i=0; i<attr.Size(); i++)
|
|
{
|
|
if (coefs[i] != NULL)
|
|
{
|
|
UpdateCoefficient(attr[i], *coefs[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
void PWCoefficient::SetTime(real_t t)
|
|
{
|
|
Coefficient::SetTime(t);
|
|
|
|
std::map<int, Coefficient*>::iterator p = pieces.begin();
|
|
for (; p != pieces.end(); p++)
|
|
{
|
|
if (p->second != NULL)
|
|
{
|
|
p->second->SetTime(t);
|
|
}
|
|
}
|
|
}
|
|
|
|
real_t PWCoefficient::Eval(ElementTransformation &T,
|
|
const IntegrationPoint &ip)
|
|
{
|
|
const int att = T.Attribute;
|
|
std::map<int, Coefficient*>::const_iterator p = pieces.find(att);
|
|
if (p != pieces.end())
|
|
{
|
|
if ( p->second != NULL)
|
|
{
|
|
return p->second->Eval(T, ip);
|
|
}
|
|
}
|
|
return 0.0;
|
|
}
|
|
|
|
real_t FunctionCoefficient::Eval(ElementTransformation & T,
|
|
const IntegrationPoint & ip)
|
|
{
|
|
real_t x[3];
|
|
Vector transip(x, 3);
|
|
|
|
T.Transform(ip, transip);
|
|
|
|
if (Function)
|
|
{
|
|
return Function(transip);
|
|
}
|
|
else
|
|
{
|
|
return TDFunction(transip, GetTime());
|
|
}
|
|
}
|
|
|
|
real_t CartesianCoefficient::Eval(ElementTransformation & T,
|
|
const IntegrationPoint & ip)
|
|
{
|
|
T.Transform(ip, transip);
|
|
return transip[comp];
|
|
}
|
|
|
|
real_t CylindricalRadialCoefficient::Eval(ElementTransformation & T,
|
|
const IntegrationPoint & ip)
|
|
{
|
|
T.Transform(ip, transip);
|
|
return sqrt(transip[0] * transip[0] + transip[1] * transip[1]);
|
|
}
|
|
|
|
real_t CylindricalAzimuthalCoefficient::Eval(ElementTransformation & T,
|
|
const IntegrationPoint & ip)
|
|
{
|
|
T.Transform(ip, transip);
|
|
return atan2(transip[1], transip[0]);
|
|
}
|
|
|
|
real_t SphericalRadialCoefficient::Eval(ElementTransformation & T,
|
|
const IntegrationPoint & ip)
|
|
{
|
|
T.Transform(ip, transip);
|
|
return sqrt(transip * transip);
|
|
}
|
|
|
|
real_t SphericalAzimuthalCoefficient::Eval(ElementTransformation & T,
|
|
const IntegrationPoint & ip)
|
|
{
|
|
T.Transform(ip, transip);
|
|
return atan2(transip[1], transip[0]);
|
|
}
|
|
|
|
real_t SphericalPolarCoefficient::Eval(ElementTransformation & T,
|
|
const IntegrationPoint & ip)
|
|
{
|
|
T.Transform(ip, transip);
|
|
return atan2(sqrt(transip[0] * transip[0] + transip[1] * transip[1]),
|
|
transip[2]);
|
|
}
|
|
|
|
real_t GridFunctionCoefficient::Eval (ElementTransformation &T,
|
|
const IntegrationPoint &ip)
|
|
{
|
|
Mesh *gf_mesh = GridF->FESpace()->GetMesh();
|
|
if (T.mesh->GetNE() == gf_mesh->GetNE())
|
|
{
|
|
return GridF->GetValue(T, ip, Component);
|
|
}
|
|
else
|
|
{
|
|
IntegrationPoint coarse_ip;
|
|
ElementTransformation *coarse_T = RefinedToCoarse(*gf_mesh, T, ip, coarse_ip);
|
|
return GridF->GetValue(*coarse_T, coarse_ip, Component);
|
|
}
|
|
}
|
|
|
|
void GridFunctionCoefficient::Project(QuadratureFunction &qf)
|
|
{
|
|
qf.ProjectGridFunction(*GridF);
|
|
}
|
|
|
|
void TransformedCoefficient::SetTime(real_t t)
|
|
{
|
|
if (Q1) { Q1->SetTime(t); }
|
|
if (Q2) { Q2->SetTime(t); }
|
|
this->Coefficient::SetTime(t);
|
|
}
|
|
|
|
real_t TransformedCoefficient::Eval(ElementTransformation &T,
|
|
const IntegrationPoint &ip)
|
|
{
|
|
if (Q2)
|
|
{
|
|
return Transform2(Q1->Eval(T, ip, GetTime()),
|
|
Q2->Eval(T, ip, GetTime()));
|
|
}
|
|
else
|
|
{
|
|
return Transform1(Q1->Eval(T, ip, GetTime()));
|
|
}
|
|
}
|
|
|
|
void DeltaCoefficient::SetTime(real_t t)
|
|
{
|
|
if (weight) { weight->SetTime(t); }
|
|
this->Coefficient::SetTime(t);
|
|
}
|
|
|
|
void DeltaCoefficient::SetDeltaCenter(const Vector& vcenter)
|
|
{
|
|
MFEM_VERIFY(vcenter.Size() <= 3,
|
|
"SetDeltaCenter::Maximum number of dim supported is 3")
|
|
for (int i = 0; i < vcenter.Size(); i++) { center[i] = vcenter[i]; }
|
|
sdim = vcenter.Size();
|
|
}
|
|
|
|
void DeltaCoefficient::GetDeltaCenter(Vector& vcenter)
|
|
{
|
|
vcenter.SetSize(sdim);
|
|
vcenter = center;
|
|
}
|
|
|
|
real_t DeltaCoefficient::EvalDelta(ElementTransformation &T,
|
|
const IntegrationPoint &ip)
|
|
{
|
|
real_t w = Scale();
|
|
return weight ? weight->Eval(T, ip, GetTime())*w : w;
|
|
}
|
|
|
|
void RestrictedCoefficient::SetTime(real_t t)
|
|
{
|
|
if (c) { c->SetTime(t); }
|
|
this->Coefficient::SetTime(t);
|
|
}
|
|
|
|
void VectorCoefficient::Eval(DenseMatrix &M, ElementTransformation &T,
|
|
const IntegrationRule &ir)
|
|
{
|
|
Vector Mi;
|
|
M.SetSize(vdim, ir.GetNPoints());
|
|
for (int i = 0; i < ir.GetNPoints(); i++)
|
|
{
|
|
M.GetColumnReference(i, Mi);
|
|
const IntegrationPoint &ip = ir.IntPoint(i);
|
|
T.SetIntPoint(&ip);
|
|
Eval(Mi, T, ip);
|
|
}
|
|
}
|
|
|
|
void VectorCoefficient::Project(QuadratureFunction &qf)
|
|
{
|
|
MFEM_VERIFY(vdim == qf.GetVDim(), "Wrong sizes.");
|
|
QuadratureSpaceBase &qspace = *qf.GetSpace();
|
|
const int ne = qspace.GetNE();
|
|
DenseMatrix values;
|
|
Vector col;
|
|
// GetValues makes a reference, but we need it to be valid on Host
|
|
qf.HostWrite();
|
|
for (int iel = 0; iel < ne; ++iel)
|
|
{
|
|
qf.GetValues(iel, values);
|
|
const IntegrationRule &ir = qspace.GetIntRule(iel);
|
|
ElementTransformation& T = *qspace.GetTransformation(iel);
|
|
for (int iq = 0; iq < ir.Size(); ++iq)
|
|
{
|
|
const IntegrationPoint &ip = ir[iq];
|
|
T.SetIntPoint(&ip);
|
|
const int iq_p = qspace.GetPermutedIndex(iel, iq);
|
|
values.GetColumnReference(iq_p, col);
|
|
Eval(col, T, ip);
|
|
}
|
|
}
|
|
}
|
|
|
|
void PWVectorCoefficient::InitMap(const Array<int> & attr,
|
|
const Array<VectorCoefficient*> & coefs)
|
|
{
|
|
MFEM_VERIFY(attr.Size() == coefs.Size(),
|
|
"PWVectorCoefficient: "
|
|
"Attribute and coefficient arrays have incompatible "
|
|
"dimensions.");
|
|
|
|
for (int i=0; i<attr.Size(); i++)
|
|
{
|
|
if (coefs[i] != NULL)
|
|
{
|
|
UpdateCoefficient(attr[i], *coefs[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
void PWVectorCoefficient::UpdateCoefficient(int attr, VectorCoefficient & coef)
|
|
{
|
|
MFEM_VERIFY(coef.GetVDim() == vdim,
|
|
"PWVectorCoefficient::UpdateCoefficient: "
|
|
"VectorCoefficient has incompatible dimension.");
|
|
pieces[attr] = &coef;
|
|
}
|
|
|
|
void PWVectorCoefficient::SetTime(real_t t)
|
|
{
|
|
VectorCoefficient::SetTime(t);
|
|
|
|
std::map<int, VectorCoefficient*>::iterator p = pieces.begin();
|
|
for (; p != pieces.end(); p++)
|
|
{
|
|
if (p->second != NULL)
|
|
{
|
|
p->second->SetTime(t);
|
|
}
|
|
}
|
|
}
|
|
|
|
void PWVectorCoefficient::Eval(Vector &V, ElementTransformation &T,
|
|
const IntegrationPoint &ip)
|
|
{
|
|
const int att = T.Attribute;
|
|
std::map<int, VectorCoefficient*>::const_iterator p = pieces.find(att);
|
|
if (p != pieces.end())
|
|
{
|
|
if ( p->second != NULL)
|
|
{
|
|
p->second->Eval(V, T, ip);
|
|
return;
|
|
}
|
|
}
|
|
|
|
V.SetSize(vdim);
|
|
V = 0.0;
|
|
}
|
|
|
|
void PositionVectorCoefficient::Eval(Vector &V, ElementTransformation &T,
|
|
const IntegrationPoint &ip)
|
|
{
|
|
V.SetSize(vdim);
|
|
T.Transform(ip, V);
|
|
}
|
|
|
|
void VectorFunctionCoefficient::Eval(Vector &V, ElementTransformation &T,
|
|
const IntegrationPoint &ip)
|
|
{
|
|
real_t x[3];
|
|
Vector transip(x, 3);
|
|
|
|
T.Transform(ip, transip);
|
|
|
|
V.SetSize(vdim);
|
|
if (Function)
|
|
{
|
|
Function(transip, V);
|
|
}
|
|
else
|
|
{
|
|
TDFunction(transip, GetTime(), V);
|
|
}
|
|
if (Q)
|
|
{
|
|
V *= Q->Eval(T, ip, GetTime());
|
|
}
|
|
}
|
|
|
|
VectorArrayCoefficient::VectorArrayCoefficient (int dim)
|
|
: VectorCoefficient(dim), Coeff(dim), ownCoeff(dim)
|
|
{
|
|
for (int i = 0; i < dim; i++)
|
|
{
|
|
Coeff[i] = NULL;
|
|
ownCoeff[i] = true;
|
|
}
|
|
}
|
|
|
|
void VectorArrayCoefficient::SetTime(real_t t)
|
|
{
|
|
for (int i = 0; i < vdim; i++)
|
|
{
|
|
if (Coeff[i]) { Coeff[i]->SetTime(t); }
|
|
}
|
|
this->VectorCoefficient::SetTime(t);
|
|
}
|
|
|
|
void VectorArrayCoefficient::Set(int i, Coefficient *c, bool own)
|
|
{
|
|
if (ownCoeff[i]) { delete Coeff[i]; }
|
|
Coeff[i] = c;
|
|
ownCoeff[i] = own;
|
|
}
|
|
|
|
VectorArrayCoefficient::~VectorArrayCoefficient()
|
|
{
|
|
for (int i = 0; i < vdim; i++)
|
|
{
|
|
if (ownCoeff[i]) { delete Coeff[i]; }
|
|
}
|
|
}
|
|
|
|
void VectorArrayCoefficient::Eval(Vector &V, ElementTransformation &T,
|
|
const IntegrationPoint &ip)
|
|
{
|
|
V.SetSize(vdim);
|
|
for (int i = 0; i < vdim; i++)
|
|
{
|
|
V(i) = this->Eval(i, T, ip);
|
|
}
|
|
}
|
|
|
|
VectorGridFunctionCoefficient::VectorGridFunctionCoefficient (
|
|
const GridFunction *gf)
|
|
: VectorCoefficient ((gf) ? gf -> VectorDim() : 0)
|
|
{
|
|
GridFunc = gf;
|
|
}
|
|
|
|
void VectorGridFunctionCoefficient::SetGridFunction(const GridFunction *gf)
|
|
{
|
|
GridFunc = gf; vdim = (gf) ? gf -> VectorDim() : 0;
|
|
}
|
|
|
|
void VectorGridFunctionCoefficient::Eval(Vector &V, ElementTransformation &T,
|
|
const IntegrationPoint &ip)
|
|
{
|
|
Mesh *gf_mesh = GridFunc->FESpace()->GetMesh();
|
|
if (T.mesh->GetNE() == gf_mesh->GetNE())
|
|
{
|
|
GridFunc->GetVectorValue(T, ip, V);
|
|
}
|
|
else
|
|
{
|
|
IntegrationPoint coarse_ip;
|
|
ElementTransformation *coarse_T = RefinedToCoarse(*gf_mesh, T, ip, coarse_ip);
|
|
GridFunc->GetVectorValue(*coarse_T, coarse_ip, V);
|
|
}
|
|
}
|
|
|
|
void VectorGridFunctionCoefficient::Eval(
|
|
DenseMatrix &M, ElementTransformation &T, const IntegrationRule &ir)
|
|
{
|
|
if (T.mesh == GridFunc->FESpace()->GetMesh())
|
|
{
|
|
GridFunc->GetVectorValues(T, ir, M);
|
|
}
|
|
else
|
|
{
|
|
VectorCoefficient::Eval(M, T, ir);
|
|
}
|
|
}
|
|
|
|
void VectorGridFunctionCoefficient::Project(QuadratureFunction &qf)
|
|
{
|
|
qf.ProjectGridFunction(*GridFunc);
|
|
}
|
|
|
|
GradientGridFunctionCoefficient::GradientGridFunctionCoefficient (
|
|
const GridFunction *gf)
|
|
: VectorCoefficient((gf) ?
|
|
gf -> FESpace() -> GetMesh() -> SpaceDimension() : 0)
|
|
{
|
|
GridFunc = gf;
|
|
}
|
|
|
|
void GradientGridFunctionCoefficient::SetGridFunction(const GridFunction *gf)
|
|
{
|
|
GridFunc = gf; vdim = (gf) ?
|
|
gf -> FESpace() -> GetMesh() -> SpaceDimension() : 0;
|
|
}
|
|
|
|
void GradientGridFunctionCoefficient::Eval(Vector &V, ElementTransformation &T,
|
|
const IntegrationPoint &ip)
|
|
{
|
|
Mesh *gf_mesh = GridFunc->FESpace()->GetMesh();
|
|
if (T.mesh->GetNE() == gf_mesh->GetNE())
|
|
{
|
|
GridFunc->GetGradient(T, V);
|
|
}
|
|
else
|
|
{
|
|
IntegrationPoint coarse_ip;
|
|
ElementTransformation *coarse_T = RefinedToCoarse(*gf_mesh, T, ip, coarse_ip);
|
|
GridFunc->GetGradient(*coarse_T, V);
|
|
}
|
|
}
|
|
|
|
void GradientGridFunctionCoefficient::Eval(
|
|
DenseMatrix &M, ElementTransformation &T, const IntegrationRule &ir)
|
|
{
|
|
if (T.mesh == GridFunc->FESpace()->GetMesh())
|
|
{
|
|
GridFunc->GetGradients(T, ir, M);
|
|
}
|
|
else
|
|
{
|
|
VectorCoefficient::Eval(M, T, ir);
|
|
}
|
|
}
|
|
|
|
void GradientGridFunctionCoefficient::Project(QuadratureFunction &qf)
|
|
{
|
|
const FiniteElementSpace &fes = *GridFunc->FESpace();
|
|
const Mesh &mesh = *fes.GetMesh();
|
|
const int sdim = mesh.SpaceDimension();
|
|
const int gf_vdim = fes.GetVDim(); // assumed to be 1 in this class
|
|
qf.SetVDim(sdim*gf_vdim);
|
|
if (mesh.GetNE() == 0) { return; }
|
|
// All mesh element must be the same type:
|
|
MFEM_VERIFY(mesh.GetNumGeometries(mesh.Dimension()) == 1,
|
|
"All mesh elements must be the same type!");
|
|
const IntegrationRule &ir = qf.GetIntRule(0);
|
|
// All elements must use the same quadrature rule:
|
|
MFEM_VERIFY(qf.Size() == sdim*gf_vdim*ir.GetNPoints()*mesh.GetNE(),
|
|
"All mesh elements must use the same quadrature rule!");
|
|
// QuadratureFunction uses the layout qf_vdim x nq x ne, i.e.
|
|
// gf_vdim x sdim x nq x nq, so we need to request QVectorLayout::byVDIM:
|
|
GridFunc->GetGradients(ir, qf, QVectorLayout::byVDIM);
|
|
}
|
|
|
|
CurlGridFunctionCoefficient::CurlGridFunctionCoefficient(
|
|
const GridFunction *gf)
|
|
: VectorCoefficient(0)
|
|
{
|
|
SetGridFunction(gf);
|
|
}
|
|
|
|
void CurlGridFunctionCoefficient::SetGridFunction(const GridFunction *gf)
|
|
{
|
|
GridFunc = gf; vdim = (gf) ? gf -> CurlDim() : 0;
|
|
}
|
|
|
|
void CurlGridFunctionCoefficient::Eval(Vector &V, ElementTransformation &T,
|
|
const IntegrationPoint &ip)
|
|
{
|
|
Mesh *gf_mesh = GridFunc->FESpace()->GetMesh();
|
|
if (T.mesh->GetNE() == gf_mesh->GetNE())
|
|
{
|
|
GridFunc->GetCurl(T, V);
|
|
}
|
|
else
|
|
{
|
|
IntegrationPoint coarse_ip;
|
|
ElementTransformation *coarse_T = RefinedToCoarse(*gf_mesh, T, ip, coarse_ip);
|
|
GridFunc->GetCurl(*coarse_T, V);
|
|
}
|
|
}
|
|
|
|
DivergenceGridFunctionCoefficient::DivergenceGridFunctionCoefficient (
|
|
const GridFunction *gf) : Coefficient()
|
|
{
|
|
GridFunc = gf;
|
|
}
|
|
|
|
real_t DivergenceGridFunctionCoefficient::Eval(ElementTransformation &T,
|
|
const IntegrationPoint &ip)
|
|
{
|
|
Mesh *gf_mesh = GridFunc->FESpace()->GetMesh();
|
|
if (T.mesh->GetNE() == gf_mesh->GetNE())
|
|
{
|
|
return GridFunc->GetDivergence(T);
|
|
}
|
|
else
|
|
{
|
|
IntegrationPoint coarse_ip;
|
|
ElementTransformation *coarse_T = RefinedToCoarse(*gf_mesh, T, ip, coarse_ip);
|
|
return GridFunc->GetDivergence(*coarse_T);
|
|
}
|
|
}
|
|
|
|
void VectorDeltaCoefficient::SetTime(real_t t)
|
|
{
|
|
d.SetTime(t);
|
|
this->VectorCoefficient::SetTime(t);
|
|
}
|
|
|
|
void VectorDeltaCoefficient::SetDirection(const Vector &d_)
|
|
{
|
|
dir = d_;
|
|
(*this).vdim = dir.Size();
|
|
}
|
|
|
|
void VectorDeltaCoefficient::EvalDelta(
|
|
Vector &V, ElementTransformation &T, const IntegrationPoint &ip)
|
|
{
|
|
V = dir;
|
|
d.SetTime(GetTime());
|
|
V *= d.EvalDelta(T, ip);
|
|
}
|
|
|
|
void VectorRestrictedCoefficient::SetTime(real_t t)
|
|
{
|
|
if (c) { c->SetTime(t); }
|
|
this->VectorCoefficient::SetTime(t);
|
|
}
|
|
|
|
void VectorRestrictedCoefficient::Eval(Vector &V, ElementTransformation &T,
|
|
const IntegrationPoint &ip)
|
|
{
|
|
V.SetSize(vdim);
|
|
if (active_attr[T.Attribute-1])
|
|
{
|
|
c->SetTime(GetTime());
|
|
c->Eval(V, T, ip);
|
|
}
|
|
else
|
|
{
|
|
V = 0.0;
|
|
}
|
|
}
|
|
|
|
void VectorRestrictedCoefficient::Eval(
|
|
DenseMatrix &M, ElementTransformation &T, const IntegrationRule &ir)
|
|
{
|
|
if (active_attr[T.Attribute-1])
|
|
{
|
|
c->SetTime(GetTime());
|
|
c->Eval(M, T, ir);
|
|
}
|
|
else
|
|
{
|
|
M.SetSize(vdim, ir.GetNPoints());
|
|
M = 0.0;
|
|
}
|
|
}
|
|
|
|
void MatrixCoefficient::Project(QuadratureFunction &qf, bool transpose)
|
|
{
|
|
MFEM_VERIFY(qf.GetVDim() == height*width, "Wrong sizes.");
|
|
QuadratureSpaceBase &qspace = *qf.GetSpace();
|
|
const int ne = qspace.GetNE();
|
|
DenseMatrix values, matrix;
|
|
// GetValues makes a reference, but we need it to be valid on Host
|
|
qf.HostWrite();
|
|
for (int iel = 0; iel < ne; ++iel)
|
|
{
|
|
qf.GetValues(iel, values);
|
|
const IntegrationRule &ir = qspace.GetIntRule(iel);
|
|
ElementTransformation& T = *qspace.GetTransformation(iel);
|
|
for (int iq = 0; iq < ir.Size(); ++iq)
|
|
{
|
|
const IntegrationPoint &ip = ir[iq];
|
|
T.SetIntPoint(&ip);
|
|
const int iq_p = qspace.GetPermutedIndex(iel, iq);
|
|
matrix.UseExternalData(&values(0, iq_p), height, width);
|
|
Eval(matrix, T, ip);
|
|
if (transpose) { matrix.Transpose(); }
|
|
}
|
|
}
|
|
}
|
|
|
|
void PWMatrixCoefficient::InitMap(const Array<int> & attr,
|
|
const Array<MatrixCoefficient*> & coefs)
|
|
{
|
|
MFEM_VERIFY(attr.Size() == coefs.Size(),
|
|
"PWMatrixCoefficient: "
|
|
"Attribute and coefficient arrays have incompatible "
|
|
"dimensions.");
|
|
|
|
for (int i=0; i<attr.Size(); i++)
|
|
{
|
|
if (coefs[i] != NULL)
|
|
{
|
|
UpdateCoefficient(attr[i], *coefs[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
void PWMatrixCoefficient::UpdateCoefficient(int attr, MatrixCoefficient & coef)
|
|
{
|
|
MFEM_VERIFY(coef.GetHeight() == height,
|
|
"PWMatrixCoefficient::UpdateCoefficient: "
|
|
"MatrixCoefficient has incompatible height.");
|
|
MFEM_VERIFY(coef.GetWidth() == width,
|
|
"PWMatrixCoefficient::UpdateCoefficient: "
|
|
"MatrixCoefficient has incompatible width.");
|
|
if (symmetric)
|
|
{
|
|
MFEM_VERIFY(coef.IsSymmetric(),
|
|
"PWMatrixCoefficient::UpdateCoefficient: "
|
|
"MatrixCoefficient has incompatible symmetry.");
|
|
}
|
|
pieces[attr] = &coef;
|
|
}
|
|
|
|
void PWMatrixCoefficient::SetTime(real_t t)
|
|
{
|
|
MatrixCoefficient::SetTime(t);
|
|
|
|
std::map<int, MatrixCoefficient*>::iterator p = pieces.begin();
|
|
for (; p != pieces.end(); p++)
|
|
{
|
|
if (p->second != NULL)
|
|
{
|
|
p->second->SetTime(t);
|
|
}
|
|
}
|
|
}
|
|
|
|
void PWMatrixCoefficient::Eval(DenseMatrix &K, ElementTransformation &T,
|
|
const IntegrationPoint &ip)
|
|
{
|
|
const int att = T.Attribute;
|
|
std::map<int, MatrixCoefficient*>::const_iterator p = pieces.find(att);
|
|
if (p != pieces.end())
|
|
{
|
|
if ( p->second != NULL)
|
|
{
|
|
p->second->Eval(K, T, ip);
|
|
return;
|
|
}
|
|
}
|
|
|
|
K.SetSize(height, width);
|
|
K = 0.0;
|
|
}
|
|
|
|
void MatrixFunctionCoefficient::SetTime(real_t t)
|
|
{
|
|
if (Q) { Q->SetTime(t); }
|
|
this->MatrixCoefficient::SetTime(t);
|
|
}
|
|
|
|
void MatrixFunctionCoefficient::Eval(DenseMatrix &K, ElementTransformation &T,
|
|
const IntegrationPoint &ip)
|
|
{
|
|
real_t x[3];
|
|
Vector transip(x, 3);
|
|
|
|
T.Transform(ip, transip);
|
|
|
|
K.SetSize(height, width);
|
|
|
|
if (symmetric) // Use SymmFunction (deprecated version)
|
|
{
|
|
MFEM_VERIFY(height == width && SymmFunction,
|
|
"MatrixFunctionCoefficient is not symmetric");
|
|
|
|
Vector Ksym((width * (width + 1)) / 2); // 1x1: 1, 2x2: 3, 3x3: 6
|
|
|
|
SymmFunction(transip, Ksym);
|
|
|
|
// Copy upper triangular values from Ksym to the full matrix K
|
|
int os = 0;
|
|
for (int i=0; i<height; ++i)
|
|
{
|
|
for (int j=i; j<width; ++j)
|
|
{
|
|
const real_t Kij = Ksym[j - i + os];
|
|
K(i,j) = Kij;
|
|
if (j != i) { K(j,i) = Kij; }
|
|
}
|
|
|
|
os += width - i;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (Function)
|
|
{
|
|
Function(transip, K);
|
|
}
|
|
else if (TDFunction)
|
|
{
|
|
TDFunction(transip, GetTime(), K);
|
|
}
|
|
else
|
|
{
|
|
K = mat;
|
|
}
|
|
}
|
|
|
|
if (Q)
|
|
{
|
|
K *= Q->Eval(T, ip, GetTime());
|
|
}
|
|
}
|
|
|
|
void MatrixFunctionCoefficient::EvalSymmetric(Vector &K,
|
|
ElementTransformation &T,
|
|
const IntegrationPoint &ip)
|
|
{
|
|
MFEM_VERIFY(symmetric && height == width && SymmFunction,
|
|
"MatrixFunctionCoefficient is not symmetric");
|
|
|
|
real_t x[3];
|
|
Vector transip(x, 3);
|
|
|
|
T.Transform(ip, transip);
|
|
|
|
K.SetSize((width * (width + 1)) / 2); // 1x1: 1, 2x2: 3, 3x3: 6
|
|
|
|
if (SymmFunction)
|
|
{
|
|
SymmFunction(transip, K);
|
|
}
|
|
|
|
if (Q)
|
|
{
|
|
K *= Q->Eval(T, ip, GetTime());
|
|
}
|
|
}
|
|
|
|
void SymmetricMatrixCoefficient::ProjectSymmetric(QuadratureFunction &qf)
|
|
{
|
|
const int vdim = qf.GetVDim();
|
|
MFEM_VERIFY(vdim == height*(height+1)/2, "Wrong sizes.");
|
|
|
|
QuadratureSpaceBase &qspace = *qf.GetSpace();
|
|
const int ne = qspace.GetNE();
|
|
qf.HostWrite();
|
|
DenseMatrix values;
|
|
DenseSymmetricMatrix matrix;
|
|
for (int iel = 0; iel < ne; ++iel)
|
|
{
|
|
qf.GetValues(iel, values);
|
|
const IntegrationRule &ir = qspace.GetIntRule(iel);
|
|
ElementTransformation& T = *qspace.GetTransformation(iel);
|
|
for (int iq = 0; iq < ir.Size(); ++iq)
|
|
{
|
|
const IntegrationPoint &ip = ir[iq];
|
|
T.SetIntPoint(&ip);
|
|
matrix.UseExternalData(&values(0, iq), height);
|
|
Eval(matrix, T, ip);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void SymmetricMatrixCoefficient::Eval(DenseMatrix &K, ElementTransformation &T,
|
|
const IntegrationPoint &ip)
|
|
{
|
|
Eval(mat_aux, T, ip);
|
|
for (int j = 0; j < width; ++j)
|
|
{
|
|
for (int i = 0; i < height; ++ i)
|
|
{
|
|
K(i, j) = mat_aux(i, j);
|
|
}
|
|
}
|
|
}
|
|
|
|
void SymmetricMatrixFunctionCoefficient::SetTime(real_t t)
|
|
{
|
|
if (Q) { Q->SetTime(t); }
|
|
MatrixCoefficient::SetTime(t);
|
|
}
|
|
|
|
void SymmetricMatrixFunctionCoefficient::Eval(DenseSymmetricMatrix &K,
|
|
ElementTransformation &T,
|
|
const IntegrationPoint &ip)
|
|
{
|
|
real_t x[3];
|
|
Vector transip(x, 3);
|
|
|
|
T.Transform(ip, transip);
|
|
|
|
K.SetSize(height);
|
|
|
|
if (Function)
|
|
{
|
|
Function(transip, K);
|
|
}
|
|
else if (TDFunction)
|
|
{
|
|
TDFunction(transip, GetTime(), K);
|
|
}
|
|
else
|
|
{
|
|
K = mat;
|
|
}
|
|
|
|
if (Q)
|
|
{
|
|
K *= Q->Eval(T, ip, GetTime());
|
|
}
|
|
}
|
|
|
|
MatrixArrayCoefficient::MatrixArrayCoefficient (int dim)
|
|
: MatrixCoefficient (dim)
|
|
{
|
|
Coeff.SetSize(height*width);
|
|
ownCoeff.SetSize(height*width);
|
|
for (int i = 0; i < (height*width); i++)
|
|
{
|
|
Coeff[i] = NULL;
|
|
ownCoeff[i] = true;
|
|
}
|
|
}
|
|
|
|
void MatrixArrayCoefficient::SetTime(real_t t)
|
|
{
|
|
for (int i=0; i < height*width; i++)
|
|
{
|
|
if (Coeff[i]) { Coeff[i]->SetTime(t); }
|
|
}
|
|
this->MatrixCoefficient::SetTime(t);
|
|
}
|
|
|
|
void MatrixArrayCoefficient::Set(int i, int j, Coefficient * c, bool own)
|
|
{
|
|
if (ownCoeff[i*width+j]) { delete Coeff[i*width+j]; }
|
|
Coeff[i*width+j] = c;
|
|
ownCoeff[i*width+j] = own;
|
|
}
|
|
|
|
MatrixArrayCoefficient::~MatrixArrayCoefficient ()
|
|
{
|
|
for (int i=0; i < height*width; i++)
|
|
{
|
|
if (ownCoeff[i]) { delete Coeff[i]; }
|
|
}
|
|
}
|
|
|
|
void MatrixArrayCoefficient::Eval(DenseMatrix &K, ElementTransformation &T,
|
|
const IntegrationPoint &ip)
|
|
{
|
|
K.SetSize(height, width);
|
|
for (int i = 0; i < height; i++)
|
|
{
|
|
for (int j = 0; j < width; j++)
|
|
{
|
|
K(i,j) = this->Eval(i, j, T, ip);
|
|
}
|
|
}
|
|
}
|
|
|
|
MatrixArrayVectorCoefficient::MatrixArrayVectorCoefficient (int dim)
|
|
: MatrixCoefficient (dim)
|
|
{
|
|
Coeff.SetSize(height);
|
|
ownCoeff.SetSize(height);
|
|
for (int i = 0; i < height; i++)
|
|
{
|
|
Coeff[i] = NULL;
|
|
ownCoeff[i] = true;
|
|
}
|
|
}
|
|
|
|
void MatrixArrayVectorCoefficient::SetTime(real_t t)
|
|
{
|
|
for (int i=0; i < height; i++)
|
|
{
|
|
if (Coeff[i]) { Coeff[i]->SetTime(t); }
|
|
}
|
|
this->MatrixCoefficient::SetTime(t);
|
|
}
|
|
|
|
void MatrixArrayVectorCoefficient::Set(int i, VectorCoefficient * c, bool own)
|
|
{
|
|
MFEM_ASSERT(i < height && i >= 0, "Row "
|
|
<< i << " does not exist. " <<
|
|
"Matrix height = " << height << ".");
|
|
if (ownCoeff[i]) { delete Coeff[i]; }
|
|
Coeff[i] = c;
|
|
ownCoeff[i] = own;
|
|
}
|
|
|
|
MatrixArrayVectorCoefficient::~MatrixArrayVectorCoefficient ()
|
|
{
|
|
for (int i=0; i < height; i++)
|
|
{
|
|
if (ownCoeff[i]) { delete Coeff[i]; }
|
|
}
|
|
}
|
|
|
|
void MatrixArrayVectorCoefficient::Eval(int i, Vector &V,
|
|
ElementTransformation &T,
|
|
const IntegrationPoint &ip)
|
|
{
|
|
MFEM_ASSERT(i < height && i >= 0, "Row "
|
|
<< i << " does not exist. " <<
|
|
"Matrix height = " << height << ".");
|
|
if (Coeff[i])
|
|
{
|
|
Coeff[i] -> Eval(V, T, ip);
|
|
}
|
|
else
|
|
{
|
|
V = 0.0;
|
|
}
|
|
}
|
|
|
|
void MatrixArrayVectorCoefficient::Eval(DenseMatrix &K,
|
|
ElementTransformation &T,
|
|
const IntegrationPoint &ip)
|
|
{
|
|
K.SetSize(height, width);
|
|
Vector V(width);
|
|
for (int i = 0; i < height; i++)
|
|
{
|
|
this->Eval(i, V, T, ip);
|
|
K.SetRow(i, V);
|
|
}
|
|
}
|
|
|
|
void MatrixRestrictedCoefficient::SetTime(real_t t)
|
|
{
|
|
if (c) { c->SetTime(t); }
|
|
this->MatrixCoefficient::SetTime(t);
|
|
}
|
|
|
|
void MatrixRestrictedCoefficient::Eval(DenseMatrix &K, ElementTransformation &T,
|
|
const IntegrationPoint &ip)
|
|
{
|
|
if (active_attr[T.Attribute-1])
|
|
{
|
|
c->SetTime(GetTime());
|
|
c->Eval(K, T, ip);
|
|
}
|
|
else
|
|
{
|
|
K.SetSize(height, width);
|
|
K = 0.0;
|
|
}
|
|
}
|
|
|
|
void SumCoefficient::SetTime(real_t t)
|
|
{
|
|
if (a) { a->SetTime(t); }
|
|
if (b) { b->SetTime(t); }
|
|
this->Coefficient::SetTime(t);
|
|
}
|
|
|
|
void SumCoefficient::Project(QuadratureFunction &qf)
|
|
{
|
|
if (a == nullptr)
|
|
{
|
|
// qf = alpha*aConst + beta * b
|
|
const real_t d_alpha_a = aConst*alpha;
|
|
const real_t d_beta = beta;
|
|
b->Project(qf);
|
|
auto d_qf = qf.ReadWrite();
|
|
mfem::forall(qf.Size(), [=] MFEM_HOST_DEVICE (int i)
|
|
{
|
|
d_qf[i] = d_alpha_a + d_beta*d_qf[i];
|
|
});
|
|
}
|
|
else
|
|
{
|
|
a->Project(qf);
|
|
QuadratureFunction qf_b(*qf.GetSpace());
|
|
b->Project(qf_b);
|
|
add(alpha, qf, beta, qf_b, qf);
|
|
}
|
|
}
|
|
|
|
void ProductCoefficient::SetTime(real_t t)
|
|
{
|
|
if (a) { a->SetTime(t); }
|
|
if (b) { b->SetTime(t); }
|
|
this->Coefficient::SetTime(t);
|
|
}
|
|
|
|
void ProductCoefficient::Project(QuadratureFunction &qf)
|
|
{
|
|
if (a == nullptr)
|
|
{
|
|
// qf = aConst * b
|
|
b->Project(qf);
|
|
qf *= aConst;
|
|
}
|
|
else
|
|
{
|
|
a->Project(qf);
|
|
QuadratureFunction qf_b(qf.GetSpace());
|
|
b->Project(qf_b);
|
|
qf *= qf_b;
|
|
}
|
|
}
|
|
|
|
void RatioCoefficient::SetTime(real_t t)
|
|
{
|
|
if (a) { a->SetTime(t); }
|
|
if (b) { b->SetTime(t); }
|
|
this->Coefficient::SetTime(t);
|
|
}
|
|
|
|
void RatioCoefficient::Project(QuadratureFunction &qf)
|
|
{
|
|
if (b == nullptr)
|
|
{
|
|
if (a == nullptr)
|
|
{
|
|
qf = aConst / bConst;
|
|
}
|
|
else
|
|
{
|
|
a->Project(qf);
|
|
qf *= 1.0/bConst;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (a == nullptr)
|
|
{
|
|
b->Project(qf);
|
|
qf.Reciprocal();
|
|
qf *= aConst;
|
|
}
|
|
else
|
|
{
|
|
a->Project(qf);
|
|
QuadratureFunction qf_b(qf.GetSpace());
|
|
b->Project(qf_b);
|
|
qf /= qf_b;
|
|
}
|
|
}
|
|
}
|
|
|
|
void PowerCoefficient::SetTime(real_t t)
|
|
{
|
|
if (a) { a->SetTime(t); }
|
|
this->Coefficient::SetTime(t);
|
|
}
|
|
|
|
InnerProductCoefficient::InnerProductCoefficient(VectorCoefficient &A,
|
|
VectorCoefficient &B)
|
|
: a(&A), b(&B), va(A.GetVDim()), vb(B.GetVDim())
|
|
{
|
|
MFEM_ASSERT(A.GetVDim() == B.GetVDim(),
|
|
"InnerProductCoefficient: "
|
|
"Arguments have incompatible dimensions.");
|
|
}
|
|
|
|
void InnerProductCoefficient::SetTime(real_t t)
|
|
{
|
|
if (a) { a->SetTime(t); }
|
|
if (b) { b->SetTime(t); }
|
|
this->Coefficient::SetTime(t);
|
|
}
|
|
|
|
real_t InnerProductCoefficient::Eval(ElementTransformation &T,
|
|
const IntegrationPoint &ip)
|
|
{
|
|
a->Eval(va, T, ip);
|
|
b->Eval(vb, T, ip);
|
|
return va * vb;
|
|
}
|
|
|
|
void InnerProductCoefficient::Project(QuadratureFunction &qf)
|
|
{
|
|
MFEM_VERIFY(a->GetVDim() == b->GetVDim(),
|
|
"Incompatible vector coefficients: a->GetVDim(): "
|
|
<< a->GetVDim() << ", b->GetVDim(): " << b->GetVDim());
|
|
|
|
const int vdim = a->GetVDim();
|
|
MFEM_VERIFY(vdim >= 1, "invalid vdim: " << vdim);
|
|
|
|
// When running on device, make sure the output data is allocated before any
|
|
// local temporary data to reduce potential heap fragmentation:
|
|
auto dot_d = qf.Write();
|
|
|
|
QuadratureFunction qf_a(qf.GetSpace(), vdim);
|
|
QuadratureFunction qf_b(qf.GetSpace(), vdim);
|
|
|
|
a->Project(qf_a);
|
|
b->Project(qf_b);
|
|
|
|
auto a_d = qf_a.Read();
|
|
auto b_d = qf_b.Read();
|
|
|
|
mfem::forall(qf.GetSpace()->GetSize(), [=] MFEM_HOST_DEVICE (int i)
|
|
{
|
|
const real_t *ai = a_d + i*vdim;
|
|
const real_t *bi = b_d + i*vdim;
|
|
real_t dot = ai[0]*bi[0];
|
|
for (int d = 1; d < vdim; d++)
|
|
{
|
|
dot += ai[d]*bi[d];
|
|
}
|
|
dot_d[i] = dot;
|
|
});
|
|
}
|
|
|
|
VectorRotProductCoefficient::VectorRotProductCoefficient(VectorCoefficient &A,
|
|
VectorCoefficient &B)
|
|
: a(&A), b(&B), va(A.GetVDim()), vb(B.GetVDim())
|
|
{
|
|
MFEM_ASSERT(A.GetVDim() == 2 && B.GetVDim() == 2,
|
|
"VectorRotProductCoefficient: "
|
|
"Arguments must have dimension equal to two.");
|
|
}
|
|
|
|
void VectorRotProductCoefficient::SetTime(real_t t)
|
|
{
|
|
if (a) { a->SetTime(t); }
|
|
if (b) { b->SetTime(t); }
|
|
this->Coefficient::SetTime(t);
|
|
}
|
|
|
|
real_t VectorRotProductCoefficient::Eval(ElementTransformation &T,
|
|
const IntegrationPoint &ip)
|
|
{
|
|
a->Eval(va, T, ip);
|
|
b->Eval(vb, T, ip);
|
|
return va[0] * vb[1] - va[1] * vb[0];
|
|
}
|
|
|
|
DeterminantCoefficient::DeterminantCoefficient(MatrixCoefficient &A)
|
|
: a(&A), ma(A.GetHeight(), A.GetWidth())
|
|
{
|
|
MFEM_ASSERT(A.GetHeight() == A.GetWidth(),
|
|
"DeterminantCoefficient: "
|
|
"Argument must be a square matrix.");
|
|
}
|
|
|
|
void DeterminantCoefficient::SetTime(real_t t)
|
|
{
|
|
if (a) { a->SetTime(t); }
|
|
this->Coefficient::SetTime(t);
|
|
}
|
|
|
|
real_t DeterminantCoefficient::Eval(ElementTransformation &T,
|
|
const IntegrationPoint &ip)
|
|
{
|
|
a->Eval(ma, T, ip);
|
|
return ma.Det();
|
|
}
|
|
|
|
TraceCoefficient::TraceCoefficient(MatrixCoefficient &A)
|
|
: a(&A), ma(A.GetHeight(), A.GetWidth())
|
|
{
|
|
MFEM_ASSERT(A.GetHeight() == A.GetWidth(),
|
|
"TraceCoefficient: "
|
|
"Argument must be a square matrix.");
|
|
}
|
|
|
|
void TraceCoefficient::SetTime(real_t t)
|
|
{
|
|
if (a) { a->SetTime(t); }
|
|
this->Coefficient::SetTime(t);
|
|
}
|
|
|
|
real_t TraceCoefficient::Eval(ElementTransformation &T,
|
|
const IntegrationPoint &ip)
|
|
{
|
|
a->Eval(ma, T, ip);
|
|
return ma.Trace();
|
|
}
|
|
|
|
VectorComponentCoefficient::VectorComponentCoefficient(VectorCoefficient &A,
|
|
int c)
|
|
: a(&A), va(A.GetVDim())
|
|
{
|
|
SetComponent(c);
|
|
}
|
|
|
|
void VectorComponentCoefficient::SetComponent(int c)
|
|
{
|
|
MFEM_ASSERT(c < a->GetVDim() && c >= 0,
|
|
"VectorComponentCoefficient: "
|
|
"Index not in range.");
|
|
|
|
component = c;
|
|
}
|
|
|
|
void VectorComponentCoefficient::SetTime(real_t t)
|
|
{
|
|
if (a) { a->SetTime(t); }
|
|
this->Coefficient::SetTime(t);
|
|
}
|
|
|
|
real_t VectorComponentCoefficient::Eval(ElementTransformation &T,
|
|
const IntegrationPoint &ip)
|
|
{
|
|
a->Eval(va, T, ip);
|
|
return va[component];
|
|
}
|
|
|
|
MatrixComponentCoefficient::MatrixComponentCoefficient(MatrixCoefficient &A,
|
|
int ri, int ci)
|
|
: a(&A), ma(A.GetHeight(), A.GetWidth())
|
|
{
|
|
SetRowIndex(ri);
|
|
SetColumnIndex(ci);
|
|
}
|
|
|
|
void MatrixComponentCoefficient::SetRowIndex(int ri)
|
|
{
|
|
MFEM_ASSERT(ri < a->GetHeight() && ri >= 0,
|
|
"MatrixComponentCoefficient: "
|
|
"Row index not in range.");
|
|
|
|
row_idx = ri;
|
|
}
|
|
|
|
void MatrixComponentCoefficient::SetColumnIndex(int ci)
|
|
{
|
|
MFEM_ASSERT(ci < a->GetWidth() && ci >= 0,
|
|
"MatrixComponentCoefficient: "
|
|
"Column index not in range.");
|
|
col_idx = ci;
|
|
}
|
|
|
|
void MatrixComponentCoefficient::SetTime(real_t t)
|
|
{
|
|
if (a) { a->SetTime(t); }
|
|
this->Coefficient::SetTime(t);
|
|
}
|
|
|
|
real_t MatrixComponentCoefficient::Eval(ElementTransformation &T,
|
|
const IntegrationPoint &ip)
|
|
{
|
|
a->Eval(ma, T, ip);
|
|
return ma(row_idx,col_idx);
|
|
}
|
|
|
|
VectorSumCoefficient::VectorSumCoefficient(int dim)
|
|
: VectorCoefficient(dim),
|
|
ACoef(NULL), BCoef(NULL),
|
|
A(dim), B(dim),
|
|
alphaCoef(NULL), betaCoef(NULL),
|
|
alpha(1.0), beta(1.0)
|
|
{
|
|
A = 0.0; B = 0.0;
|
|
}
|
|
|
|
VectorSumCoefficient::VectorSumCoefficient(VectorCoefficient &A_,
|
|
VectorCoefficient &B_,
|
|
real_t alpha_, real_t beta_)
|
|
: VectorCoefficient(A_.GetVDim()),
|
|
ACoef(&A_), BCoef(&B_),
|
|
A(A_.GetVDim()), B(A_.GetVDim()),
|
|
alphaCoef(NULL), betaCoef(NULL),
|
|
alpha(alpha_), beta(beta_)
|
|
{
|
|
MFEM_ASSERT(A_.GetVDim() == B_.GetVDim(),
|
|
"VectorSumCoefficient: "
|
|
"Arguments must have the same dimension.");
|
|
}
|
|
|
|
VectorSumCoefficient::VectorSumCoefficient(VectorCoefficient &A_,
|
|
VectorCoefficient &B_,
|
|
Coefficient &alpha_,
|
|
Coefficient &beta_)
|
|
: VectorCoefficient(A_.GetVDim()),
|
|
ACoef(&A_), BCoef(&B_),
|
|
A(A_.GetVDim()),
|
|
B(A_.GetVDim()),
|
|
alphaCoef(&alpha_),
|
|
betaCoef(&beta_),
|
|
alpha(0.0), beta(0.0)
|
|
{
|
|
MFEM_ASSERT(A_.GetVDim() == B_.GetVDim(),
|
|
"VectorSumCoefficient: "
|
|
"Arguments must have the same dimension.");
|
|
}
|
|
|
|
void VectorSumCoefficient::SetTime(real_t t)
|
|
{
|
|
if (ACoef) { ACoef->SetTime(t); }
|
|
if (BCoef) { BCoef->SetTime(t); }
|
|
if (alphaCoef) { alphaCoef->SetTime(t); }
|
|
if (betaCoef) { betaCoef->SetTime(t); }
|
|
this->VectorCoefficient::SetTime(t);
|
|
}
|
|
|
|
void VectorSumCoefficient::Eval(Vector &V, ElementTransformation &T,
|
|
const IntegrationPoint &ip)
|
|
{
|
|
V.SetSize(A.Size());
|
|
if ( ACoef) { ACoef->Eval(A, T, ip); }
|
|
if ( BCoef) { BCoef->Eval(B, T, ip); }
|
|
if (alphaCoef) { alpha = alphaCoef->Eval(T, ip); }
|
|
if ( betaCoef) { beta = betaCoef->Eval(T, ip); }
|
|
add(alpha, A, beta, B, V);
|
|
}
|
|
|
|
ScalarVectorProductCoefficient::ScalarVectorProductCoefficient(
|
|
real_t A,
|
|
VectorCoefficient &B)
|
|
: VectorCoefficient(B.GetVDim()), aConst(A), a(NULL), b(&B)
|
|
{}
|
|
|
|
ScalarVectorProductCoefficient::ScalarVectorProductCoefficient(
|
|
Coefficient &A,
|
|
VectorCoefficient &B)
|
|
: VectorCoefficient(B.GetVDim()), aConst(0.0), a(&A), b(&B)
|
|
{}
|
|
|
|
void ScalarVectorProductCoefficient::SetTime(real_t t)
|
|
{
|
|
if (a) { a->SetTime(t); }
|
|
if (b) { b->SetTime(t); }
|
|
this->VectorCoefficient::SetTime(t);
|
|
}
|
|
|
|
void ScalarVectorProductCoefficient::Eval(Vector &V, ElementTransformation &T,
|
|
const IntegrationPoint &ip)
|
|
{
|
|
real_t sa = (a == NULL) ? aConst : a->Eval(T, ip);
|
|
b->Eval(V, T, ip);
|
|
V *= sa;
|
|
}
|
|
|
|
NormalizedVectorCoefficient::NormalizedVectorCoefficient(VectorCoefficient &A,
|
|
real_t tol_)
|
|
: VectorCoefficient(A.GetVDim()), a(&A), tol(tol_)
|
|
{}
|
|
|
|
void NormalizedVectorCoefficient::SetTime(real_t t)
|
|
{
|
|
if (a) { a->SetTime(t); }
|
|
this->VectorCoefficient::SetTime(t);
|
|
}
|
|
|
|
void NormalizedVectorCoefficient::Eval(Vector &V, ElementTransformation &T,
|
|
const IntegrationPoint &ip)
|
|
{
|
|
a->Eval(V, T, ip);
|
|
real_t nv = V.Norml2();
|
|
V *= (nv > tol) ? (1.0/nv) : 0.0;
|
|
}
|
|
|
|
VectorCrossProductCoefficient::VectorCrossProductCoefficient(
|
|
VectorCoefficient &A,
|
|
VectorCoefficient &B)
|
|
: VectorCoefficient(3), a(&A), b(&B), va(A.GetVDim()), vb(B.GetVDim())
|
|
{
|
|
MFEM_ASSERT(A.GetVDim() == 3 && B.GetVDim() == 3,
|
|
"VectorCrossProductCoefficient: "
|
|
"Arguments must have dimension equal to three.");
|
|
}
|
|
|
|
void VectorCrossProductCoefficient::SetTime(real_t t)
|
|
{
|
|
if (a) { a->SetTime(t); }
|
|
if (b) { b->SetTime(t); }
|
|
this->VectorCoefficient::SetTime(t);
|
|
}
|
|
|
|
void VectorCrossProductCoefficient::Eval(Vector &V, ElementTransformation &T,
|
|
const IntegrationPoint &ip)
|
|
{
|
|
a->Eval(va, T, ip);
|
|
b->Eval(vb, T, ip);
|
|
V.SetSize(3);
|
|
V[0] = va[1] * vb[2] - va[2] * vb[1];
|
|
V[1] = va[2] * vb[0] - va[0] * vb[2];
|
|
V[2] = va[0] * vb[1] - va[1] * vb[0];
|
|
}
|
|
|
|
MatrixVectorProductCoefficient::MatrixVectorProductCoefficient(
|
|
MatrixCoefficient &A, VectorCoefficient &B)
|
|
: VectorCoefficient(A.GetHeight()), a(&A), b(&B),
|
|
ma(A.GetHeight(), A.GetWidth()), vb(B.GetVDim())
|
|
{
|
|
MFEM_ASSERT(A.GetWidth() == B.GetVDim(),
|
|
"MatrixVectorProductCoefficient: "
|
|
"Arguments have incompatible dimensions.");
|
|
}
|
|
|
|
void MatrixVectorProductCoefficient::SetTime(real_t t)
|
|
{
|
|
if (a) { a->SetTime(t); }
|
|
if (b) { b->SetTime(t); }
|
|
this->VectorCoefficient::SetTime(t);
|
|
}
|
|
|
|
void MatrixVectorProductCoefficient::Eval(Vector &V, ElementTransformation &T,
|
|
const IntegrationPoint &ip)
|
|
{
|
|
a->Eval(ma, T, ip);
|
|
b->Eval(vb, T, ip);
|
|
V.SetSize(vdim);
|
|
ma.Mult(vb, V);
|
|
}
|
|
|
|
void IdentityMatrixCoefficient::Eval(DenseMatrix &M, ElementTransformation &T,
|
|
const IntegrationPoint &ip)
|
|
{
|
|
M.SetSize(dim);
|
|
M = 0.0;
|
|
for (int d=0; d<dim; d++) { M(d,d) = 1.0; }
|
|
}
|
|
|
|
MatrixSumCoefficient::MatrixSumCoefficient(MatrixCoefficient &A,
|
|
MatrixCoefficient &B,
|
|
real_t alpha_, real_t beta_)
|
|
: MatrixCoefficient(A.GetHeight(), A.GetWidth()),
|
|
a(&A), b(&B), alpha(alpha_), beta(beta_),
|
|
ma(A.GetHeight(), A.GetWidth())
|
|
{
|
|
MFEM_ASSERT(A.GetHeight() == B.GetHeight() && A.GetWidth() == B.GetWidth(),
|
|
"MatrixSumCoefficient: "
|
|
"Arguments must have the same dimensions.");
|
|
}
|
|
|
|
void MatrixSumCoefficient::SetTime(real_t t)
|
|
{
|
|
if (a) { a->SetTime(t); }
|
|
if (b) { b->SetTime(t); }
|
|
this->MatrixCoefficient::SetTime(t);
|
|
}
|
|
|
|
void MatrixSumCoefficient::Eval(DenseMatrix &M, ElementTransformation &T,
|
|
const IntegrationPoint &ip)
|
|
{
|
|
b->Eval(M, T, ip);
|
|
if ( beta != 1.0 ) { M *= beta; }
|
|
a->Eval(ma, T, ip);
|
|
M.Add(alpha, ma);
|
|
}
|
|
|
|
MatrixProductCoefficient::MatrixProductCoefficient(MatrixCoefficient &A,
|
|
MatrixCoefficient &B)
|
|
: MatrixCoefficient(A.GetHeight(), B.GetWidth()),
|
|
a(&A), b(&B),
|
|
ma(A.GetHeight(), A.GetWidth()),
|
|
mb(B.GetHeight(), B.GetWidth())
|
|
{
|
|
MFEM_ASSERT(A.GetWidth() == B.GetHeight(),
|
|
"MatrixProductCoefficient: "
|
|
"Arguments must have compatible dimensions.");
|
|
}
|
|
|
|
void MatrixProductCoefficient::Eval(DenseMatrix &M, ElementTransformation &T,
|
|
const IntegrationPoint &ip)
|
|
{
|
|
a->Eval(ma, T, ip);
|
|
b->Eval(mb, T, ip);
|
|
Mult(ma, mb, M);
|
|
}
|
|
|
|
ScalarMatrixProductCoefficient::ScalarMatrixProductCoefficient(
|
|
real_t A,
|
|
MatrixCoefficient &B)
|
|
: MatrixCoefficient(B.GetHeight(), B.GetWidth()), aConst(A), a(NULL), b(&B)
|
|
{}
|
|
|
|
ScalarMatrixProductCoefficient::ScalarMatrixProductCoefficient(
|
|
Coefficient &A,
|
|
MatrixCoefficient &B)
|
|
: MatrixCoefficient(B.GetHeight(), B.GetWidth()), aConst(0.0), a(&A), b(&B)
|
|
{}
|
|
|
|
void ScalarMatrixProductCoefficient::SetTime(real_t t)
|
|
{
|
|
if (a) { a->SetTime(t); }
|
|
if (b) { b->SetTime(t); }
|
|
this->MatrixCoefficient::SetTime(t);
|
|
}
|
|
|
|
void ScalarMatrixProductCoefficient::Eval(DenseMatrix &M,
|
|
ElementTransformation &T,
|
|
const IntegrationPoint &ip)
|
|
{
|
|
real_t sa = (a == NULL) ? aConst : a->Eval(T, ip);
|
|
b->Eval(M, T, ip);
|
|
M *= sa;
|
|
}
|
|
|
|
TransposeMatrixCoefficient::TransposeMatrixCoefficient(MatrixCoefficient &A)
|
|
: MatrixCoefficient(A.GetWidth(), A.GetHeight()), a(&A)
|
|
{}
|
|
|
|
void TransposeMatrixCoefficient::SetTime(real_t t)
|
|
{
|
|
if (a) { a->SetTime(t); }
|
|
this->MatrixCoefficient::SetTime(t);
|
|
}
|
|
|
|
void TransposeMatrixCoefficient::Eval(DenseMatrix &M,
|
|
ElementTransformation &T,
|
|
const IntegrationPoint &ip)
|
|
{
|
|
a->Eval(M, T, ip);
|
|
M.Transpose();
|
|
}
|
|
|
|
InverseMatrixCoefficient::InverseMatrixCoefficient(MatrixCoefficient &A)
|
|
: MatrixCoefficient(A.GetHeight(), A.GetWidth()), a(&A)
|
|
{
|
|
MFEM_ASSERT(A.GetHeight() == A.GetWidth(),
|
|
"InverseMatrixCoefficient: "
|
|
"Argument must be a square matrix.");
|
|
}
|
|
|
|
void InverseMatrixCoefficient::SetTime(real_t t)
|
|
{
|
|
if (a) { a->SetTime(t); }
|
|
this->MatrixCoefficient::SetTime(t);
|
|
}
|
|
|
|
void InverseMatrixCoefficient::Eval(DenseMatrix &M,
|
|
ElementTransformation &T,
|
|
const IntegrationPoint &ip)
|
|
{
|
|
a->Eval(M, T, ip);
|
|
M.Invert();
|
|
}
|
|
|
|
ExponentialMatrixCoefficient::ExponentialMatrixCoefficient(MatrixCoefficient &A)
|
|
: MatrixCoefficient(A.GetHeight(), A.GetWidth()), a(&A)
|
|
{
|
|
MFEM_ASSERT(A.GetHeight() == A.GetWidth() && A.GetHeight() == 2,
|
|
"ExponentialMatrixCoefficient: "
|
|
<< "Argument must be a square 2x2 matrix."
|
|
<< " Height = " << A.GetHeight()
|
|
<< ", Width = " << A.GetWidth());
|
|
}
|
|
|
|
void ExponentialMatrixCoefficient::SetTime(real_t t)
|
|
{
|
|
if (a) { a->SetTime(t); }
|
|
this->MatrixCoefficient::SetTime(t);
|
|
}
|
|
|
|
void ExponentialMatrixCoefficient::Eval(DenseMatrix &M,
|
|
ElementTransformation &T,
|
|
const IntegrationPoint &ip)
|
|
{
|
|
a->Eval(M, T, ip);
|
|
M.Exponential();
|
|
}
|
|
|
|
OuterProductCoefficient::OuterProductCoefficient(VectorCoefficient &A,
|
|
VectorCoefficient &B)
|
|
: MatrixCoefficient(A.GetVDim(), B.GetVDim()), a(&A), b(&B),
|
|
va(A.GetVDim()), vb(B.GetVDim())
|
|
{}
|
|
|
|
void OuterProductCoefficient::SetTime(real_t t)
|
|
{
|
|
if (a) { a->SetTime(t); }
|
|
if (b) { b->SetTime(t); }
|
|
this->MatrixCoefficient::SetTime(t);
|
|
}
|
|
|
|
void OuterProductCoefficient::Eval(DenseMatrix &M, ElementTransformation &T,
|
|
const IntegrationPoint &ip)
|
|
{
|
|
a->Eval(va, T, ip);
|
|
b->Eval(vb, T, ip);
|
|
M.SetSize(va.Size(), vb.Size());
|
|
for (int i=0; i<va.Size(); i++)
|
|
{
|
|
for (int j=0; j<vb.Size(); j++)
|
|
{
|
|
M(i, j) = va[i] * vb[j];
|
|
}
|
|
}
|
|
}
|
|
|
|
CrossCrossCoefficient::CrossCrossCoefficient(real_t A, VectorCoefficient &K)
|
|
: MatrixCoefficient(K.GetVDim(), K.GetVDim()), aConst(A), a(NULL), k(&K),
|
|
vk(K.GetVDim())
|
|
{}
|
|
|
|
CrossCrossCoefficient::CrossCrossCoefficient(Coefficient &A,
|
|
VectorCoefficient &K)
|
|
: MatrixCoefficient(K.GetVDim(), K.GetVDim()), aConst(0.0), a(&A), k(&K),
|
|
vk(K.GetVDim())
|
|
{}
|
|
|
|
void CrossCrossCoefficient::SetTime(real_t t)
|
|
{
|
|
if (a) { a->SetTime(t); }
|
|
if (k) { k->SetTime(t); }
|
|
this->MatrixCoefficient::SetTime(t);
|
|
}
|
|
|
|
void CrossCrossCoefficient::Eval(DenseMatrix &M, ElementTransformation &T,
|
|
const IntegrationPoint &ip)
|
|
{
|
|
k->Eval(vk, T, ip);
|
|
M.SetSize(vk.Size(), vk.Size());
|
|
M = 0.0;
|
|
real_t k2 = vk*vk;
|
|
for (int i=0; i<vk.Size(); i++)
|
|
{
|
|
M(i, i) = k2;
|
|
for (int j=0; j<vk.Size(); j++)
|
|
{
|
|
M(i, j) -= vk[i] * vk[j];
|
|
}
|
|
}
|
|
M *= ((a == NULL ) ? aConst : a->Eval(T, ip) );
|
|
}
|
|
|
|
real_t LpNormLoop(real_t p, Coefficient &coeff, Mesh &mesh,
|
|
const IntegrationRule *irs[])
|
|
{
|
|
real_t norm = 0.0;
|
|
ElementTransformation *tr;
|
|
|
|
for (int i = 0; i < mesh.GetNE(); i++)
|
|
{
|
|
tr = mesh.GetElementTransformation(i);
|
|
const IntegrationRule &ir = *irs[mesh.GetElementType(i)];
|
|
for (int j = 0; j < ir.GetNPoints(); j++)
|
|
{
|
|
const IntegrationPoint &ip = ir.IntPoint(j);
|
|
tr->SetIntPoint(&ip);
|
|
real_t val = fabs(coeff.Eval(*tr, ip));
|
|
if (p < infinity())
|
|
{
|
|
norm += ip.weight * tr->Weight() * pow(val, p);
|
|
}
|
|
else
|
|
{
|
|
if (norm < val)
|
|
{
|
|
norm = val;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return norm;
|
|
}
|
|
|
|
real_t LpNormLoop(real_t p, VectorCoefficient &coeff, Mesh &mesh,
|
|
const IntegrationRule *irs[])
|
|
{
|
|
real_t norm = 0.0;
|
|
ElementTransformation *tr;
|
|
int vdim = coeff.GetVDim();
|
|
Vector vval(vdim);
|
|
real_t val;
|
|
|
|
for (int i = 0; i < mesh.GetNE(); i++)
|
|
{
|
|
tr = mesh.GetElementTransformation(i);
|
|
const IntegrationRule &ir = *irs[mesh.GetElementType(i)];
|
|
for (int j = 0; j < ir.GetNPoints(); j++)
|
|
{
|
|
const IntegrationPoint &ip = ir.IntPoint(j);
|
|
tr->SetIntPoint(&ip);
|
|
coeff.Eval(vval, *tr, ip);
|
|
if (p < infinity())
|
|
{
|
|
for (int idim(0); idim < vdim; ++idim)
|
|
{
|
|
norm += ip.weight * tr->Weight() * pow(fabs( vval(idim) ), p);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (int idim(0); idim < vdim; ++idim)
|
|
{
|
|
val = fabs(vval(idim));
|
|
if (norm < val)
|
|
{
|
|
norm = val;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return norm;
|
|
}
|
|
|
|
real_t ComputeLpNorm(real_t p, Coefficient &coeff, Mesh &mesh,
|
|
const IntegrationRule *irs[])
|
|
{
|
|
real_t norm = LpNormLoop(p, coeff, mesh, irs);
|
|
|
|
if (p < infinity())
|
|
{
|
|
// negative quadrature weights may cause norm to be negative
|
|
if (norm < 0.0)
|
|
{
|
|
norm = -pow(-norm, 1.0/p);
|
|
}
|
|
else
|
|
{
|
|
norm = pow(norm, 1.0/p);
|
|
}
|
|
}
|
|
|
|
return norm;
|
|
}
|
|
|
|
real_t ComputeLpNorm(real_t p, VectorCoefficient &coeff, Mesh &mesh,
|
|
const IntegrationRule *irs[])
|
|
{
|
|
real_t norm = LpNormLoop(p, coeff, mesh, irs);
|
|
|
|
if (p < infinity())
|
|
{
|
|
// negative quadrature weights may cause norm to be negative
|
|
if (norm < 0.0)
|
|
{
|
|
norm = -pow(-norm, 1.0/p);
|
|
}
|
|
else
|
|
{
|
|
norm = pow(norm, 1.0/p);
|
|
}
|
|
}
|
|
|
|
return norm;
|
|
}
|
|
|
|
#ifdef MFEM_USE_MPI
|
|
real_t ComputeGlobalLpNorm(real_t p, Coefficient &coeff, ParMesh &pmesh,
|
|
const IntegrationRule *irs[])
|
|
{
|
|
real_t loc_norm = LpNormLoop(p, coeff, pmesh, irs);
|
|
real_t glob_norm = 0;
|
|
|
|
MPI_Comm comm = pmesh.GetComm();
|
|
|
|
if (p < infinity())
|
|
{
|
|
MPI_Allreduce(&loc_norm, &glob_norm, 1, MPITypeMap<real_t>::mpi_type, MPI_SUM,
|
|
comm);
|
|
|
|
// negative quadrature weights may cause norm to be negative
|
|
if (glob_norm < 0.0)
|
|
{
|
|
glob_norm = -pow(-glob_norm, 1.0/p);
|
|
}
|
|
else
|
|
{
|
|
glob_norm = pow(glob_norm, 1.0/p);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
MPI_Allreduce(&loc_norm, &glob_norm, 1, MPITypeMap<real_t>::mpi_type, MPI_MAX,
|
|
comm);
|
|
}
|
|
|
|
return glob_norm;
|
|
}
|
|
|
|
real_t ComputeGlobalLpNorm(real_t p, VectorCoefficient &coeff, ParMesh &pmesh,
|
|
const IntegrationRule *irs[])
|
|
{
|
|
real_t loc_norm = LpNormLoop(p, coeff, pmesh, irs);
|
|
real_t glob_norm = 0;
|
|
|
|
MPI_Comm comm = pmesh.GetComm();
|
|
|
|
if (p < infinity())
|
|
{
|
|
MPI_Allreduce(&loc_norm, &glob_norm, 1, MPITypeMap<real_t>::mpi_type, MPI_SUM,
|
|
comm);
|
|
|
|
// negative quadrature weights may cause norm to be negative
|
|
if (glob_norm < 0.0)
|
|
{
|
|
glob_norm = -pow(-glob_norm, 1.0/p);
|
|
}
|
|
else
|
|
{
|
|
glob_norm = pow(glob_norm, 1.0/p);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
MPI_Allreduce(&loc_norm, &glob_norm, 1, MPITypeMap<real_t>::mpi_type, MPI_MAX,
|
|
comm);
|
|
}
|
|
|
|
return glob_norm;
|
|
}
|
|
#endif
|
|
|
|
VectorQuadratureFunctionCoefficient::VectorQuadratureFunctionCoefficient(
|
|
const QuadratureFunction &qf)
|
|
: VectorCoefficient(qf.GetVDim()), QuadF(qf), index(0) { }
|
|
|
|
void VectorQuadratureFunctionCoefficient::SetComponent(int index_, int length_)
|
|
{
|
|
MFEM_VERIFY(index_ >= 0, "Index must be >= 0");
|
|
MFEM_VERIFY(index_ < QuadF.GetVDim(),
|
|
"Index must be < QuadratureFunction length");
|
|
index = index_;
|
|
|
|
MFEM_VERIFY(length_ > 0, "Length must be > 0");
|
|
MFEM_VERIFY(length_ <= QuadF.GetVDim() - index,
|
|
"Length must be <= (QuadratureFunction length - index)");
|
|
|
|
vdim = length_;
|
|
}
|
|
|
|
void VectorQuadratureFunctionCoefficient::Eval(Vector &V,
|
|
ElementTransformation &T,
|
|
const IntegrationPoint &ip)
|
|
{
|
|
QuadF.HostRead();
|
|
|
|
const int el_idx = QuadF.GetSpace()->GetEntityIndex(T);
|
|
// Handle the case of "interior boundary elements" and FaceQuadratureSpace
|
|
// with FaceType::Boundary.
|
|
if (el_idx < 0) { V = 0.0; return; }
|
|
|
|
const int ip_idx = QuadF.GetSpace()->GetPermutedIndex(el_idx, ip.index);
|
|
|
|
if (index == 0 && vdim == QuadF.GetVDim())
|
|
{
|
|
QuadF.GetValues(el_idx, ip_idx, V);
|
|
}
|
|
else
|
|
{
|
|
Vector temp;
|
|
QuadF.GetValues(el_idx, ip_idx, temp);
|
|
V.SetSize(vdim);
|
|
for (int i = 0; i < vdim; i++)
|
|
{
|
|
V(i) = temp(index + i);
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
void VectorQuadratureFunctionCoefficient::Project(QuadratureFunction &qf)
|
|
{
|
|
qf = QuadF;
|
|
}
|
|
|
|
QuadratureFunctionCoefficient::QuadratureFunctionCoefficient(
|
|
const QuadratureFunction &qf) : QuadF(qf)
|
|
{
|
|
MFEM_VERIFY(qf.GetVDim() == 1, "QuadratureFunction's vdim must be 1");
|
|
}
|
|
|
|
real_t QuadratureFunctionCoefficient::Eval(ElementTransformation &T,
|
|
const IntegrationPoint &ip)
|
|
{
|
|
QuadF.HostRead();
|
|
Vector temp(1);
|
|
const int el_idx = QuadF.GetSpace()->GetEntityIndex(T);
|
|
// Handle the case of "interior boundary elements" and FaceQuadratureSpace
|
|
// with FaceType::Boundary.
|
|
if (el_idx < 0) { return 0.0; }
|
|
const int ip_idx = QuadF.GetSpace()->GetPermutedIndex(el_idx, ip.index);
|
|
QuadF.GetValues(el_idx, ip_idx, temp);
|
|
return temp[0];
|
|
}
|
|
|
|
void QuadratureFunctionCoefficient::Project(QuadratureFunction &qf)
|
|
{
|
|
qf = QuadF;
|
|
}
|
|
|
|
|
|
CoefficientVector::CoefficientVector(
|
|
QuadratureSpaceBase &qs_, CoefficientStorage storage_)
|
|
: Vector(), storage(storage_), vdim(0), qs(qs_), qf(NULL)
|
|
{
|
|
UseDevice(true);
|
|
}
|
|
|
|
CoefficientVector::CoefficientVector(Coefficient *coeff,
|
|
QuadratureSpaceBase &qs_,
|
|
CoefficientStorage storage_)
|
|
: CoefficientVector(qs_, storage_)
|
|
{
|
|
if (coeff == NULL)
|
|
{
|
|
SetConstant(1.0);
|
|
}
|
|
else
|
|
{
|
|
Project(*coeff);
|
|
}
|
|
}
|
|
|
|
CoefficientVector::CoefficientVector(Coefficient &coeff,
|
|
QuadratureSpaceBase &qs_,
|
|
CoefficientStorage storage_)
|
|
: CoefficientVector(qs_, storage_)
|
|
{
|
|
Project(coeff);
|
|
}
|
|
|
|
CoefficientVector::CoefficientVector(VectorCoefficient &coeff,
|
|
QuadratureSpaceBase &qs_,
|
|
CoefficientStorage storage_)
|
|
: CoefficientVector(qs_, storage_)
|
|
{
|
|
Project(coeff);
|
|
}
|
|
|
|
CoefficientVector::CoefficientVector(MatrixCoefficient &coeff,
|
|
QuadratureSpaceBase &qs_,
|
|
CoefficientStorage storage_)
|
|
: CoefficientVector(qs_, storage_)
|
|
{
|
|
Project(coeff);
|
|
}
|
|
|
|
void CoefficientVector::Project(Coefficient &coeff)
|
|
{
|
|
vdim = 1;
|
|
if (auto *const_coeff = dynamic_cast<ConstantCoefficient*>(&coeff))
|
|
{
|
|
SetConstant(const_coeff->constant);
|
|
}
|
|
else if (auto *qf_coeff = dynamic_cast<QuadratureFunctionCoefficient*>(&coeff))
|
|
{
|
|
MakeRef(qf_coeff->GetQuadFunction());
|
|
}
|
|
else
|
|
{
|
|
if (qf == nullptr) { qf = new QuadratureFunction(qs); }
|
|
qf->SetVDim(1);
|
|
coeff.Project(*qf);
|
|
Vector::MakeRef(*qf, 0, qf->Size());
|
|
}
|
|
}
|
|
|
|
void CoefficientVector::Project(VectorCoefficient &coeff)
|
|
{
|
|
vdim = coeff.GetVDim();
|
|
if (auto *const_coeff = dynamic_cast<VectorConstantCoefficient*>(&coeff))
|
|
{
|
|
SetConstant(const_coeff->GetVec());
|
|
}
|
|
else if (auto *qf_coeff =
|
|
dynamic_cast<VectorQuadratureFunctionCoefficient*>(&coeff))
|
|
{
|
|
MakeRef(qf_coeff->GetQuadFunction());
|
|
}
|
|
else
|
|
{
|
|
if (qf == nullptr) { qf = new QuadratureFunction(qs, vdim); }
|
|
qf->SetVDim(vdim);
|
|
coeff.Project(*qf);
|
|
Vector::MakeRef(*qf, 0, qf->Size());
|
|
}
|
|
}
|
|
|
|
void CoefficientVector::Project(MatrixCoefficient &coeff, bool transpose)
|
|
{
|
|
if (auto *const_coeff = dynamic_cast<MatrixConstantCoefficient*>(&coeff))
|
|
{
|
|
SetConstant(const_coeff->GetMatrix(), transpose);
|
|
}
|
|
else if (auto *const_sym_coeff =
|
|
dynamic_cast<SymmetricMatrixConstantCoefficient*>(&coeff))
|
|
{
|
|
SetConstant(const_sym_coeff->GetMatrix());
|
|
}
|
|
else
|
|
{
|
|
auto *sym_coeff = dynamic_cast<SymmetricMatrixCoefficient*>(&coeff);
|
|
const bool sym = sym_coeff && (storage & CoefficientStorage::SYMMETRIC);
|
|
const int height = coeff.GetHeight();
|
|
const int width = coeff.GetWidth();
|
|
vdim = sym ? height*(height + 1)/2 : width*height;
|
|
|
|
if (qf == nullptr) { qf = new QuadratureFunction(qs, vdim); }
|
|
qf->SetVDim(vdim);
|
|
if (sym) { sym_coeff->ProjectSymmetric(*qf); }
|
|
else { coeff.Project(*qf, transpose); }
|
|
Vector::MakeRef(*qf, 0, qf->Size());
|
|
}
|
|
}
|
|
|
|
void CoefficientVector::ProjectTranspose(MatrixCoefficient &coeff)
|
|
{
|
|
Project(coeff, true);
|
|
}
|
|
|
|
void CoefficientVector::MakeRef(const QuadratureFunction &qf_)
|
|
{
|
|
vdim = qf_.GetVDim();
|
|
const QuadratureSpaceBase *qs2 = qf_.GetSpace();
|
|
MFEM_CONTRACT_VAR(qs2); // qs2 used only for asserts
|
|
MFEM_VERIFY(qs2 != NULL, "Invalid QuadratureSpace.")
|
|
MFEM_VERIFY(qs2->GetMesh() == qs.GetMesh(), "Meshes differ.");
|
|
MFEM_VERIFY(qs2->GetOrder() == qs.GetOrder(), "Orders differ.");
|
|
Vector::MakeRef(const_cast<QuadratureFunction&>(qf_), 0, qf_.Size());
|
|
}
|
|
|
|
void CoefficientVector::SetConstant(real_t constant)
|
|
{
|
|
const int nq = (storage & CoefficientStorage::CONSTANTS) ? 1 : qs.GetSize();
|
|
vdim = 1;
|
|
SetSize(nq);
|
|
Vector::operator=(constant);
|
|
}
|
|
|
|
void CoefficientVector::SetConstant(const Vector &constant)
|
|
{
|
|
const int nq = (storage & CoefficientStorage::CONSTANTS) ? 1 : qs.GetSize();
|
|
vdim = constant.Size();
|
|
SetSize(nq*vdim);
|
|
for (int iq = 0; iq < nq; ++iq)
|
|
{
|
|
for (int vd = 0; vd<vdim; ++vd)
|
|
{
|
|
(*this)[vd + iq*vdim] = constant[vd];
|
|
}
|
|
}
|
|
}
|
|
|
|
void CoefficientVector::SetConstant(const DenseMatrix &constant, bool transpose)
|
|
{
|
|
const int nq = (storage & CoefficientStorage::CONSTANTS) ? 1 : qs.GetSize();
|
|
const int width = constant.Width();
|
|
const int height = constant.Height();
|
|
vdim = width*height;
|
|
SetSize(nq*vdim);
|
|
for (int iq = 0; iq < nq; ++iq)
|
|
{
|
|
for (int j = 0; j < width; ++j)
|
|
{
|
|
for (int i = 0; i < height; ++i)
|
|
{
|
|
const real_t val = transpose ? constant(j,i) : constant(i,j);
|
|
(*this)[i + j*height + iq*vdim] = val;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void CoefficientVector::SetConstant(const DenseSymmetricMatrix &constant)
|
|
{
|
|
const int nq = (storage & CoefficientStorage::CONSTANTS) ? 1 : qs.GetSize();
|
|
const int height = constant.Height();
|
|
const bool sym = storage & CoefficientStorage::SYMMETRIC;
|
|
vdim = sym ? height*(height + 1)/2 : height*height;
|
|
SetSize(nq*vdim);
|
|
for (int iq = 0; iq < nq; ++iq)
|
|
{
|
|
for (int vd = 0; vd < vdim; ++vd)
|
|
{
|
|
const real_t value = sym ? constant.GetData()[vd] : constant(vd % height,
|
|
vd / height);
|
|
(*this)[vd + iq*vdim] = value;
|
|
}
|
|
}
|
|
}
|
|
|
|
int CoefficientVector::GetVDim() const { return vdim; }
|
|
|
|
CoefficientVector::~CoefficientVector()
|
|
{
|
|
delete qf;
|
|
}
|
|
|
|
}
|