Files
mfem/fem/gridfunc.cpp
T
2011-04-08 15:27:24 -07:00

1561 lines
44 KiB
C++

// Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at
// the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights
// reserved. See file COPYRIGHT for details.
//
// This file is part of the MFEM library. For more information and source code
// availability see http://mfem.googlecode.com.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the GNU Lesser General Public License (as published by the Free
// Software Foundation) version 2.1 dated February 1999.
// Implementation of GridFunction
#include "fem.hpp"
#include <math.h>
GridFunction::GridFunction(Mesh *m, istream &input)
: Vector()
{
const int bufflen = 256;
char buff[bufflen];
int vdim;
input.getline(buff, bufflen); // 'FiniteElementSpace'
if (strcmp(buff, "FiniteElementSpace"))
mfem_error("GridFunction::GridFunction():"
" input stream is not a GridFunction!");
input.getline(buff, bufflen, ' '); // 'FiniteElementCollection:'
input >> ws;
input.getline(buff, bufflen);
fec = FiniteElementCollection::New(buff);
input.getline(buff, bufflen, ' '); // 'VDim:'
input >> vdim;
input.getline(buff, bufflen, ' '); // 'Ordering:'
int ordering;
input >> ordering;
input.getline(buff, bufflen); // read the empty line
fes = new FiniteElementSpace(m, fec, vdim, ordering);
Vector::Load(input, fes->GetVSize());
}
GridFunction::~GridFunction()
{
if (fec)
{
delete fes;
delete fec;
}
}
void GridFunction::Update(FiniteElementSpace *f)
{
if (fec)
{
delete fes;
delete fec;
fec = NULL;
}
fes = f;
SetSize(fes->GetVSize());
}
void GridFunction::Update(FiniteElementSpace *f, Vector &v, int v_offset)
{
if (fec)
{
delete fes;
delete fec;
fec = NULL;
}
fes = f;
SetDataAndSize((double *)v + v_offset, fes->GetVSize());
}
int GridFunction::VectorDim() const
{
const FiniteElement *fe = fes->GetFE(0);
if (fe->GetRangeType() == FiniteElement::SCALAR)
return fes->GetVDim();
return fe->GetDim();
}
void GridFunction::GetNodalValues(int i, Array<double> &nval, int vdim) const
{
Array<int> dofs;
int k;
fes->GetElementVDofs(i, dofs);
const FiniteElement *FElem = fes->GetFE(i);
const IntegrationRule *ElemVert =
Geometries.GetVertices(FElem->GetGeomType());
int dof = FElem->GetDof();
Vector DofVal(dof);
int n = ElemVert->GetNPoints();
nval.SetSize(n);
vdim--;
for (k = 0; k < n; k++)
{
FElem->CalcShape(ElemVert->IntPoint(k), DofVal);
nval[k] = 0.0;
for (int j = 0; j < dof; j++)
if (dofs[dof*vdim+j] >= 0)
nval[k] += DofVal(j) * data[dofs[dof*vdim+j]];
else
nval[k] -= DofVal(j) * data[-1-dofs[dof*vdim+j]];
}
}
double GridFunction::GetValue(int i, const IntegrationPoint &ip, int vdim)
const
{
Array<int> dofs;
fes->GetElementDofs(i, dofs);
fes->DofsToVDofs(vdim-1, dofs);
Vector DofVal(dofs.Size()), LocVec;
fes->GetFE(i)->CalcShape(ip, DofVal);
GetSubVector(dofs, LocVec);
return (DofVal * LocVec);
}
void GridFunction::GetVectorValue(int i, const IntegrationPoint &ip,
Vector &val) const
{
const FiniteElement *FElem = fes->GetFE(i);
int dof = FElem->GetDof();
Array<int> vdofs;
fes->GetElementVDofs(i, vdofs);
Vector loc_data;
GetSubVector(vdofs, loc_data);
if (FElem->GetRangeType() == FiniteElement::SCALAR)
{
Vector shape(dof);
FElem->CalcShape(ip, shape);
int vdim = fes->GetVDim();
val.SetSize(vdim);
for (int k = 0; k < vdim; k++)
{
val(k) = shape * ((const double *)loc_data + dof * k);
}
}
else
{
int dim = FElem->GetDim();
DenseMatrix vshape(dof, dim);
ElementTransformation *Tr = fes->GetElementTransformation(i);
Tr->SetIntPoint(&ip);
FElem->CalcVShape(*Tr, vshape);
val.SetSize(dim);
vshape.MultTranspose(loc_data, val);
}
}
void GridFunction::GetValues(int i, const IntegrationRule &ir, Vector &vals,
DenseMatrix &tr, int vdim)
const
{
Array<int> dofs;
int k, n;
n = ir.GetNPoints();
vals.SetSize(n);
fes->GetElementVDofs(i, dofs);
const FiniteElement *FElem = fes->GetFE(i);
ElementTransformation *ET;
ET = fes->GetElementTransformation(i);
ET->Transform(ir, tr);
int dof = FElem->GetDof();
Vector DofVal(dof);
vdim--;
for (k = 0; k < n; k++)
{
FElem->CalcShape(ir.IntPoint(k), DofVal);
vals(k) = 0.0;
for (int j = 0; j < dof; j++)
if (dofs[dof*vdim+j] >= 0)
vals(k) += DofVal(j) * data[dofs[dof*vdim+j]];
else
vals(k) -= DofVal(j) * data[-1-dofs[dof*vdim+j]];
}
}
int GridFunction::GetFaceValues(int i, int side, const IntegrationRule &ir,
Vector &vals, DenseMatrix &tr,
int vdim) const
{
int n, di;
FaceElementTransformations *Transf;
n = ir.GetNPoints();
IntegrationRule eir(n); // ---
Transf = fes->GetMesh()->GetFaceElementTransformations(i);
if (Transf->Elem2No < 0)
di = 0;
else
if ( fes->GetAttribute(Transf->Elem1No) <=
fes->GetAttribute(Transf->Elem2No) )
di = 0;
else
di = 1;
if (side == 2)
side = di;
if (side == 0)
{
Transf->Loc1.Transform(ir, eir);
GetValues(Transf->Elem1No, eir, vals, tr, vdim);
}
else
{
Transf->Loc2.Transform(ir, eir);
GetValues(Transf->Elem2No, eir, vals, tr, vdim);
}
return di;
}
void GridFunction::GetVectorValues(int i, const IntegrationRule &ir,
DenseMatrix &vals, DenseMatrix &tr)
const
{
const FiniteElement *FElem = fes->GetFE(i);
int dof = FElem->GetDof();
Array<int> vdofs;
fes->GetElementVDofs(i, vdofs);
Vector loc_data;
GetSubVector(vdofs, loc_data);
int nip = ir.GetNPoints();
ElementTransformation *Tr = fes->GetElementTransformation(i);
Tr->Transform(ir, tr);
if (FElem->GetRangeType() == FiniteElement::SCALAR)
{
Vector shape(dof);
int vdim = fes->GetVDim();
vals.SetSize(vdim, nip);
for (int j = 0; j < nip; j++)
{
const IntegrationPoint &ip = ir.IntPoint(j);
FElem->CalcShape(ip, shape);
for (int k = 0; k < vdim; k++)
{
vals(k,j) = shape * ((const double *)loc_data + dof * k);
}
}
}
else
{
int dim = FElem->GetDim();
DenseMatrix vshape(dof, dim);
vals.SetSize(dim, nip);
Vector val_j;
for (int j = 0; j < nip; j++)
{
const IntegrationPoint &ip = ir.IntPoint(j);
Tr->SetIntPoint(&ip);
FElem->CalcVShape(*Tr, vshape);
vals.GetColumnReference(j, val_j);
vshape.MultTranspose(loc_data, val_j);
}
}
}
int GridFunction::GetFaceVectorValues(
int i, int side, const IntegrationRule &ir,
DenseMatrix &vals, DenseMatrix &tr) const
{
int n, di;
FaceElementTransformations *Transf;
n = ir.GetNPoints();
IntegrationRule eir(n); // ---
Transf = fes->GetMesh()->GetFaceElementTransformations(i);
if (Transf->Elem2No < 0)
di = 0;
else
if ( fes->GetAttribute(Transf->Elem1No) <=
fes->GetAttribute(Transf->Elem2No) )
di = 0;
else
di = 1;
if (side == 2)
side = di;
if (side == 0)
{
Transf->Loc1.Transform(ir, eir);
GetVectorValues(Transf->Elem1No, eir, vals, tr);
}
else
{
Transf->Loc2.Transform(ir, eir);
GetVectorValues(Transf->Elem2No, eir, vals, tr);
}
return di;
}
void GridFunction::GetValuesFrom(GridFunction &orig_func)
{
// Without averaging ...
FiniteElementSpace *orig_fes = orig_func.FESpace();
Array<int> vdofs, orig_vdofs;
Vector shape, loc_values, orig_loc_values;
int i, j, d, ne, dof, odof, vdim;
ne = fes->GetNE();
vdim = fes->GetVDim();
for (i = 0; i < ne; i++)
{
fes->GetElementVDofs(i, vdofs);
orig_fes->GetElementVDofs(i, orig_vdofs);
orig_func.GetSubVector(orig_vdofs, orig_loc_values);
const FiniteElement *fe = fes->GetFE(i);
const FiniteElement *orig_fe = orig_fes->GetFE(i);
dof = fe->GetDof();
odof = orig_fe->GetDof();
loc_values.SetSize(dof * vdim);
shape.SetSize(odof);
const IntegrationRule &ir = fe->GetNodes();
for (j = 0; j < dof; j++)
{
const IntegrationPoint &ip = ir.IntPoint(j);
orig_fe->CalcShape(ip, shape);
for (d = 0; d < vdim; d++)
{
loc_values(d*dof+j) =
shape * ((const double *)orig_loc_values + d * odof) ;
}
}
SetSubVector(vdofs, loc_values);
}
}
void GridFunction::GetBdrValuesFrom(GridFunction &orig_func)
{
// Without averaging ...
FiniteElementSpace *orig_fes = orig_func.FESpace();
Array<int> vdofs, orig_vdofs;
Vector shape, loc_values, orig_loc_values;
int i, j, d, nbe, dof, odof, vdim;
nbe = fes->GetNBE();
vdim = fes->GetVDim();
for (i = 0; i < nbe; i++)
{
fes->GetBdrElementVDofs(i, vdofs);
orig_fes->GetBdrElementVDofs(i, orig_vdofs);
orig_func.GetSubVector(orig_vdofs, orig_loc_values);
const FiniteElement *fe = fes->GetBE(i);
const FiniteElement *orig_fe = orig_fes->GetBE(i);
dof = fe->GetDof();
odof = orig_fe->GetDof();
loc_values.SetSize(dof * vdim);
shape.SetSize(odof);
const IntegrationRule &ir = fe->GetNodes();
for (j = 0; j < dof; j++)
{
const IntegrationPoint &ip = ir.IntPoint(j);
orig_fe->CalcShape(ip, shape);
for (d = 0; d < vdim; d++)
{
loc_values(d*dof+j) =
shape * ((const double *)orig_loc_values + d * odof);
}
}
SetSubVector(vdofs, loc_values);
}
}
void GridFunction::GetVectorFieldValues(
int i, const IntegrationRule &ir, DenseMatrix &vals,
DenseMatrix &tr, int comp) const
{
Array<int> vdofs;
ElementTransformation *transf;
int d, j, k, n, dim, dof, ind;
n = ir.GetNPoints();
fes->GetElementVDofs(i, vdofs);
const FiniteElement *fe = fes->GetFE(i);
dof = fe->GetDof();
dim = fe->GetDim();
int *dofs = &vdofs[comp*dof];
transf = fes->GetElementTransformation(i);
transf->Transform(ir, tr);
vals.SetSize(n, dim);
DenseMatrix vshape(dof, dim);
double a;
for (k = 0; k < n; k++)
{
const IntegrationPoint &ip = ir.IntPoint(k);
transf->SetIntPoint(&ip);
fe->CalcVShape(*transf, vshape);
for (d = 0; d < dim; d++)
{
a = 0.0;
for (j = 0; j < dof; j++)
if ( (ind=dofs[j]) >= 0 )
a += vshape(j, d) * data[ind];
else
a -= vshape(j, d) * data[-1-ind];
vals(k, d) = a;
}
}
}
void GridFunction::ReorderByNodes()
{
if (fes->GetOrdering() == Ordering::byNODES)
return;
int i, j, k;
int vdim = fes->GetVDim();
int ndofs = fes->GetNDofs();
double *temp = new double[size];
k = 0;
for (j = 0; j < ndofs; j++)
for (i = 0; i < vdim; i++)
temp[j+i*ndofs] = data[k++];
for (i = 0; i < size; i++)
data[i] = temp[i];
delete [] temp;
}
void GridFunction::GetVectorFieldNodalValues(Vector &val, int comp) const
{
int i, k;
Array<int> overlap(fes->GetNV());
Array<int> vertices;
DenseMatrix vals, tr;
val.SetSize(overlap.Size());
overlap = 0;
val = 0.0;
comp--;
for (i = 0; i < fes->GetNE(); i++)
{
const IntegrationRule *ir =
Geometries.GetVertices(fes->GetFE(i)->GetGeomType());
fes->GetElementVertices(i, vertices);
GetVectorFieldValues(i, *ir, vals, tr);
for (k = 0; k < ir->GetNPoints(); k++)
{
val(vertices[k]) += vals(k, comp);
overlap[vertices[k]]++;
}
}
for (i = 0; i < overlap.Size(); i++)
val(i) /= overlap[i];
}
void GridFunction::ProjectVectorFieldOn(GridFunction &vec_field, int comp)
{
FiniteElementSpace *new_fes = vec_field.FESpace();
int d, i, k, ind, dof;
Array<int> overlap(new_fes->GetVSize());
Array<int> new_vdofs;
DenseMatrix vals, tr;
overlap = 0;
vec_field = 0.0;
for (i = 0; i < new_fes->GetNE(); i++)
{
const FiniteElement *fe = new_fes->GetFE(i);
const IntegrationRule &ir = fe->GetNodes();
GetVectorFieldValues(i, ir, vals, tr, comp);
new_fes->GetElementVDofs(i, new_vdofs);
dof = fe->GetDof();
for (d = 0; d < fe->GetDim(); d++)
for (k = 0; k < dof; k++)
{
if ( (ind=new_vdofs[dof*d+k]) < 0 )
ind = -1-ind, vals(k, d) = - vals(k, d);
vec_field(ind) += vals(k, d);
overlap[ind]++;
}
}
for (i = 0; i < overlap.Size(); i++)
vec_field(i) /= overlap[i];
}
void GridFunction::GetDerivative(int comp, int der_comp, GridFunction &der)
{
FiniteElementSpace * der_fes = der.FESpace();
ElementTransformation * transf;
Array<int> overlap(der_fes->GetVSize());
Array<int> der_dofs, vdofs;
DenseMatrix dshape, inv_jac;
Vector pt_grad, loc_func;
int i, j, k, dim, dof, der_dof, ind;
double a;
for (i = 0; i < overlap.Size(); i++)
overlap[i] = 0;
der = 0.0;
comp--;
for (i = 0; i < der_fes->GetNE(); i++)
{
const FiniteElement *der_fe = der_fes->GetFE(i);
const FiniteElement *fe = fes->GetFE(i);
const IntegrationRule &ir = der_fe->GetNodes();
der_fes->GetElementDofs(i, der_dofs);
fes->GetElementVDofs(i, vdofs);
dim = fe->GetDim();
dof = fe->GetDof();
der_dof = der_fe->GetDof();
dshape.SetSize(dof, dim);
inv_jac.SetSize(dim);
pt_grad.SetSize(dim);
loc_func.SetSize(dof);
transf = fes->GetElementTransformation(i);
for (j = 0; j < dof; j++)
loc_func(j) = ( (ind=vdofs[comp*dof+j]) >= 0 ) ?
(data[ind]) : (-data[-1-ind]);
for (k = 0; k < der_dof; k++)
{
const IntegrationPoint &ip = ir.IntPoint(k);
fe->CalcDShape(ip, dshape);
dshape.MultTranspose(loc_func, pt_grad);
transf->SetIntPoint(&ip);
CalcInverse(transf->Jacobian(), inv_jac);
a = 0.0;
for (j = 0; j < dim; j++)
a += inv_jac(j, der_comp) * pt_grad(j);
der(der_dofs[k]) += a;
overlap[der_dofs[k]]++;
}
}
for (i = 0; i < overlap.Size(); i++)
der(i) /= overlap[i];
}
void GridFunction::GetVectorGradientHat(
ElementTransformation &T, DenseMatrix &gh)
{
int elNo = T.ElementNo;
const FiniteElement *FElem = fes->GetFE(elNo);
int dim = FElem->GetDim(), dof = FElem->GetDof();
Array<int> vdofs;
fes->GetElementVDofs(elNo, vdofs);
Vector loc_data;
GetSubVector(vdofs, loc_data);
// assuming scalar FE
DenseMatrix dshape(dof, dim);
FElem->CalcDShape(T.GetIntPoint(), dshape);
gh.SetSize(dim);
for (int i = 0; i < dim; i++)
for (int j = 0; j < dim; j++)
{
double gij = 0.0;
for (int k = 0; k < dof; k++)
gij += loc_data(i * dof + k) * dshape(k, j);
gh(i, j) = gij;
}
}
double GridFunction::GetDivergence(ElementTransformation &tr)
{
DenseMatrix grad_hat;
GetVectorGradientHat(tr, grad_hat);
int dim = grad_hat.Size();
DenseMatrix Jinv(dim);
CalcInverse(tr.Jacobian(), Jinv);
double div_v = 0.0;
for (int i = 0; i < dim; i++)
for (int j = 0; j < dim; j++)
div_v += grad_hat(i, j) * Jinv(j, i);
return div_v;
}
void GridFunction::GetGradient(ElementTransformation &tr, Vector &grad)
{
mfem_error("GridFunction::GetGradient(...) is not implemented!");
}
void GridFunction::GetGradients(const int elem, const IntegrationRule &ir,
DenseMatrix &grad)
{
const FiniteElement *fe = fes->GetFE(elem);
ElementTransformation *Tr = fes->GetElementTransformation(elem);
DenseMatrix dshape(fe->GetDof(), fe->GetDim());
DenseMatrix Jinv(fe->GetDim());
Vector lval, gh(fe->GetDim()), gcol;
Array<int> dofs;
fes->GetElementDofs(elem, dofs);
GetSubVector(dofs, lval);
grad.SetSize(fe->GetDim(), ir.GetNPoints());
for (int i = 0; i < ir.GetNPoints(); i++)
{
const IntegrationPoint &ip = ir.IntPoint(i);
fe->CalcDShape(ip, dshape);
dshape.MultTranspose(lval, gh);
Tr->SetIntPoint(&ip);
grad.GetColumnReference(i, gcol);
CalcInverse(Tr->Jacobian(), Jinv);
Jinv.MultTranspose(gh, gcol);
}
}
void GridFunction::GetVectorGradient(
ElementTransformation &tr, DenseMatrix &grad)
{
DenseMatrix grad_hat;
GetVectorGradientHat(tr, grad_hat);
DenseMatrix Jinv(grad_hat.Size());
CalcInverse(tr.Jacobian(), Jinv);
grad.SetSize(grad_hat.Size());
Mult(grad_hat, Jinv, grad);
}
void GridFunction::GetElementAverages(GridFunction &avgs)
{
MassIntegrator Mi;
DenseMatrix loc_mass;
Array<int> te_dofs, tr_dofs;
Vector loc_avgs, loc_this;
Vector int_psi(avgs.Size());
avgs = 0.0;
int_psi = 0.0;
for (int i = 0; i < fes->GetNE(); i++)
{
Mi.AssembleElementMatrix2(*fes->GetFE(i), *avgs.FESpace()->GetFE(i),
*fes->GetElementTransformation(i), loc_mass);
fes->GetElementDofs(i, tr_dofs);
avgs.FESpace()->GetElementDofs(i, te_dofs);
GetSubVector(tr_dofs, loc_this);
loc_avgs.SetSize(te_dofs.Size());
loc_mass.Mult(loc_this, loc_avgs);
avgs.AddElementVector(te_dofs, loc_avgs);
loc_this = 1.0; // assume the local basis for 'this' sums to 1
loc_mass.Mult(loc_this, loc_avgs);
int_psi.AddElementVector(te_dofs, loc_avgs);
}
for (int i = 0; i < avgs.Size(); i++)
avgs(i) /= int_psi(i);
}
void GridFunction::GetNodalValues(Vector &nval, int vdim) const
{
int i, j;
Array<int> vertices;
Array<double> values;
Array<int> overlap(fes->GetNV());
nval.SetSize(fes->GetNV());
for (i = 0; i < overlap.Size(); i++)
{
nval(i) = 0.0;
overlap[i] = 0;
}
for (i = 0; i < fes->GetNE(); i++)
{
fes->GetElementVertices(i, vertices);
GetNodalValues(i, values, vdim);
for (j = 0; j < vertices.Size(); j++)
{
nval(vertices[j]) += values[j];
overlap[vertices[j]]++;
}
}
for (i = 0; i < overlap.Size(); i++)
nval(i) /= overlap[i];
}
void GridFunction::ProjectCoefficient(Coefficient &coeff)
{
int i;
Array<int> vdofs;
Vector vals;
DeltaCoefficient *delta_c = dynamic_cast<DeltaCoefficient *>(&coeff);
if (delta_c == NULL)
{
for (i = 0; i < fes->GetNE(); i++)
{
fes->GetElementVDofs(i, vdofs);
vals.SetSize(vdofs.Size());
fes->GetFE(i)->Project(coeff, *fes->GetElementTransformation(i), vals);
SetSubVector(vdofs, vals);
}
}
else
{
Mesh *mesh = fes->GetMesh();
const int dim = mesh->Dimension();
const double *center = delta_c->Center();
const double *vert = mesh->GetVertex(0);
double min_dist, dist;
int v_idx = 0;
// find the vertex closest to the center of the delta function
min_dist = Distance(center, vert, dim);
for (int i = 0; i < mesh->GetNV(); i++)
{
vert = mesh->GetVertex(i);
dist = Distance(center, vert, dim);
if (dist < min_dist)
{
min_dist = dist;
v_idx = i;
}
}
(*this) = 0.0;
// find the elements that have 'v_idx' as a vertex
MassIntegrator Mi(*delta_c->Weight());
DenseMatrix loc_mass;
Array<int> vertices;
Vector loc_mass_vals;
double integral = 0.0;
for (int i = 0; i < mesh->GetNE(); i++)
{
mesh->GetElementVertices(i, vertices);
for (int j = 0; j < vertices.Size(); j++)
if (vertices[j] == v_idx)
{
const FiniteElement *fe = fes->GetFE(i);
Mi.AssembleElementMatrix(*fe, *fes->GetElementTransformation(i),
loc_mass);
vals.SetSize(fe->GetDof());
fe->ProjectDelta(j, vals);
fes->GetElementVDofs(i, vdofs);
SetSubVector(vdofs, vals);
loc_mass_vals.SetSize(vals.Size());
loc_mass.Mult(vals, loc_mass_vals);
for (int k = 0; k < loc_mass_vals.Size(); k++)
integral += loc_mass_vals(k);
break;
}
}
(*this) *= (delta_c->Scale() / integral);
}
}
void GridFunction::ProjectCoefficient(
Coefficient &coeff, Array<int> &dofs, int vd)
{
int el = -1;
ElementTransformation *T = NULL;
const FiniteElement *fe = NULL;
for (int i = 0; i < dofs.Size(); i++)
{
int dof = dofs[i], j = fes->GetElementForDof(dof);
if (el != j)
{
el = j;
T = fes->GetElementTransformation(el);
fe = fes->GetFE(el);
}
int vdof = fes->DofToVDof(dof, vd);
int ld = fes->GetLocalDofForDof(dof);
const IntegrationPoint &ip = fe->GetNodes().IntPoint(ld);
T->SetIntPoint(&ip);
(*this)(vdof) = coeff.Eval(*T, ip);
}
}
void GridFunction::ProjectCoefficient(VectorCoefficient &vcoeff)
{
int i;
Array<int> vdofs;
Vector vals;
for (i = 0; i < fes->GetNE(); i++)
{
fes->GetElementVDofs(i, vdofs);
vals.SetSize(vdofs.Size());
fes->GetFE(i)->Project(vcoeff, *fes->GetElementTransformation(i), vals);
SetSubVector(vdofs, vals);
}
}
void GridFunction::ProjectCoefficient(Coefficient *coeff[])
{
int i, j, fdof, d, ind;
double val;
const FiniteElement *fe;
ElementTransformation *transf;
Array<int> vdofs;
for (i = 0; i < fes->GetNE(); i++)
{
fe = fes->GetFE(i);
fdof = fe->GetDof();
transf = fes->GetElementTransformation(i);
const IntegrationRule &ir = fe->GetNodes();
fes->GetElementVDofs(i, vdofs);
for (j = 0; j < fdof; j++)
{
const IntegrationPoint &ip = ir.IntPoint(j);
transf->SetIntPoint(&ip);
for (d = 0; d < fes->GetVDim(); d++)
{
val = coeff[d]->Eval(*transf, ip);
if ( (ind = vdofs[fdof*d+j]) < 0 )
val = -val, ind = -1-ind;
(*this)(ind) = val;
}
}
}
}
void GridFunction::ProjectBdrCoefficient(
Coefficient *coeff[], Array<int> &attr)
{
int i, j, fdof, d, ind;
double val;
const FiniteElement *fe;
ElementTransformation *transf;
Array<int> vdofs;
for (i = 0; i < fes->GetNBE(); i++)
{
if ( attr[fes->GetBdrAttribute(i)-1] )
{
fe = fes->GetBE(i);
fdof = fe->GetDof();
transf = fes->GetBdrElementTransformation(i);
const IntegrationRule &ir = fe->GetNodes();
fes->GetBdrElementVDofs(i, vdofs);
for (j = 0; j < fdof; j++)
{
const IntegrationPoint &ip = ir.IntPoint(j);
transf->SetIntPoint(&ip);
for (d = 0; d < fes->GetVDim(); d++)
{
val = coeff[d]->Eval(*transf, ip);
if ( (ind = vdofs[fdof*d+j]) < 0 )
val = -val, ind = -1-ind;
(*this)(ind) = val;
}
}
}
}
}
double GridFunction::ComputeL2Error(
Coefficient *exsol[], const IntegrationRule *irs[]) const
{
double error = 0.0, a;
const FiniteElement *fe;
ElementTransformation *transf;
Vector shape;
Array<int> vdofs;
int fdof, d, i, intorder, j, k;
for (i = 0; i < fes->GetNE(); i++)
{
fe = fes->GetFE(i);
fdof = fe->GetDof();
transf = fes->GetElementTransformation(i);
shape.SetSize(fdof);
intorder = fe->GetOrder()+2; // <----------
const IntegrationRule *ir;
if (irs)
ir = irs[fe->GetGeomType()];
else
ir = &(IntRules.Get(fe->GetGeomType(), intorder));
fes->GetElementVDofs(i, vdofs);
for (j = 0; j < ir->GetNPoints(); j++)
{
const IntegrationPoint &ip = ir->IntPoint(j);
fe->CalcShape(ip, shape);
for (d = 0; d < fes->GetVDim(); d++)
{
a = 0;
for (k = 0; k < fdof; k++)
if (vdofs[fdof*d+k] >= 0)
a += (*this)(vdofs[fdof*d+k]) * shape(k);
else
a -= (*this)(-1-vdofs[fdof*d+k]) * shape(k);
transf->SetIntPoint(&ip);
a -= exsol[d]->Eval(*transf, ip);
error += ip.weight * transf->Weight() * a * a;
}
}
}
if (error < 0.0)
return -sqrt(-error);
return sqrt(error);
}
double GridFunction::ComputeL2Error(
VectorCoefficient &exsol, const IntegrationRule *irs[],
Array<int> *elems) const
{
double error = 0.0;
const FiniteElement *fe;
ElementTransformation *T;
DenseMatrix vals, exact_vals, tr;
Vector loc_errs;
for (int i = 0; i < fes->GetNE(); i++)
{
if (elems != NULL && (*elems)[i] == 0) continue;
fe = fes->GetFE(i);
int intorder = fe->GetOrder()+2; // <----------
const IntegrationRule *ir;
if (irs)
ir = irs[fe->GetGeomType()];
else
ir = &(IntRules.Get(fe->GetGeomType(), intorder));
GetVectorValues(i, *ir, vals, tr);
T = fes->GetElementTransformation(i);
exsol.Eval(exact_vals, *T, *ir);
vals -= exact_vals;
loc_errs.SetSize(vals.Width());
vals.Norm2(loc_errs);
for (int j = 0; j < ir->GetNPoints(); j++)
{
const IntegrationPoint &ip = ir->IntPoint(j);
T->SetIntPoint(&ip);
error += ip.weight * T->Weight() * (loc_errs(j) * loc_errs(j));
}
}
if (error < 0.0)
return -sqrt(-error);
return sqrt(error);
}
double GridFunction::ComputeH1Error(
Coefficient *exsol, VectorCoefficient *exgrad,
Coefficient *ell_coeff, double Nu, int norm_type) const
{
// assuming vdim is 1
int i, fdof, dim, intorder, j, k;
Mesh *mesh;
const FiniteElement *fe;
ElementTransformation *transf;
FaceElementTransformations *face_elem_transf;
Vector e_grad, a_grad, shape, el_dofs, err_val, ell_coeff_val;
DenseMatrix dshape, dshapet, Jinv;
Array<int> vdofs;
IntegrationPoint eip;
double error = 0.0;
mesh = fes->GetMesh();
dim = mesh->Dimension();
e_grad.SetSize(dim);
a_grad.SetSize(dim);
Jinv.SetSize(dim);
if (norm_type & 1)
for (i = 0; i < mesh->GetNE(); i++)
{
fe = fes->GetFE(i);
fdof = fe->GetDof();
transf = mesh->GetElementTransformation(i);
el_dofs.SetSize(fdof);
dshape.SetSize(fdof, dim);
dshapet.SetSize(fdof, dim);
intorder = 2 * fe->GetOrder(); // <----------
const IntegrationRule &ir = IntRules.Get(fe->GetGeomType(), intorder);
fes->GetElementVDofs(i, vdofs);
for (k = 0; k < fdof; k++)
if (vdofs[k] >= 0)
el_dofs(k) = (*this)(vdofs[k]);
else
el_dofs(k) = - (*this)(-1-vdofs[k]);
for (j = 0; j < ir.GetNPoints(); j++)
{
const IntegrationPoint &ip = ir.IntPoint(j);
fe->CalcDShape(ip, dshape);
transf->SetIntPoint(&ip);
exgrad->Eval(e_grad, *transf, ip);
CalcInverse(transf->Jacobian(), Jinv);
Mult(dshape, Jinv, dshapet);
dshapet.MultTranspose(el_dofs, a_grad);
e_grad -= a_grad;
error += (ip.weight * transf->Weight() *
ell_coeff->Eval(*transf, ip) *
(e_grad * e_grad));
}
}
if (norm_type & 2)
for (i = 0; i < mesh->GetNFaces(); i++)
{
face_elem_transf = mesh->GetFaceElementTransformations(i);
int i1 = face_elem_transf->Elem1No;
int i2 = face_elem_transf->Elem2No;
intorder = fes->GetFE(i1)->GetOrder();
if (i2 >= 0)
if ( (k = fes->GetFE(i2)->GetOrder()) > intorder )
intorder = k;
intorder = 2 * intorder; // <-------------
const IntegrationRule &ir =
IntRules.Get(face_elem_transf->FaceGeom, intorder);
err_val.SetSize(ir.GetNPoints());
ell_coeff_val.SetSize(ir.GetNPoints());
// side 1
transf = face_elem_transf->Elem1;
fe = fes->GetFE(i1);
fdof = fe->GetDof();
fes->GetElementVDofs(i1, vdofs);
shape.SetSize(fdof);
el_dofs.SetSize(fdof);
for (k = 0; k < fdof; k++)
if (vdofs[k] >= 0)
el_dofs(k) = (*this)(vdofs[k]);
else
el_dofs(k) = - (*this)(-1-vdofs[k]);
for (j = 0; j < ir.GetNPoints(); j++)
{
face_elem_transf->Loc1.Transform(ir.IntPoint(j), eip);
fe->CalcShape(eip, shape);
transf->SetIntPoint(&eip);
ell_coeff_val(j) = ell_coeff->Eval(*transf, eip);
err_val(j) = exsol->Eval(*transf, eip) - (shape * el_dofs);
}
if (i2 >= 0)
{
// side 2
transf = face_elem_transf->Elem2;
fe = fes->GetFE(i2);
fdof = fe->GetDof();
fes->GetElementVDofs(i2, vdofs);
shape.SetSize(fdof);
el_dofs.SetSize(fdof);
for (k = 0; k < fdof; k++)
if (vdofs[k] >= 0)
el_dofs(k) = (*this)(vdofs[k]);
else
el_dofs(k) = - (*this)(-1-vdofs[k]);
for (j = 0; j < ir.GetNPoints(); j++)
{
face_elem_transf->Loc2.Transform(ir.IntPoint(j), eip);
fe->CalcShape(eip, shape);
transf->SetIntPoint(&eip);
ell_coeff_val(j) += ell_coeff->Eval(*transf, eip);
ell_coeff_val(j) *= 0.5;
err_val(j) -= (exsol->Eval(*transf, eip) - (shape * el_dofs));
}
}
transf = face_elem_transf->Face;
for (j = 0; j < ir.GetNPoints(); j++)
{
const IntegrationPoint &ip = ir.IntPoint(j);
transf->SetIntPoint(&ip);
error += (ip.weight * Nu * ell_coeff_val(j) *
pow(transf->Weight(), 1.0-1.0/(dim-1)) *
err_val(j) * err_val(j));
}
}
if (error < 0.0)
return -sqrt(-error);
return sqrt(error);
}
double GridFunction::ComputeMaxError(
Coefficient *exsol[], const IntegrationRule *irs[]) const
{
double error = 0.0, a;
const FiniteElement *fe;
ElementTransformation *transf;
Vector shape;
Array<int> vdofs;
int fdof, d, i, intorder, j, k;
for (i = 0; i < fes->GetNE(); i++)
{
fe = fes->GetFE(i);
fdof = fe->GetDof();
transf = fes->GetElementTransformation(i);
shape.SetSize(fdof);
intorder = fe->GetOrder()+2; // <----------
const IntegrationRule *ir;
if (irs)
ir = irs[fe->GetGeomType()];
else
ir = &(IntRules.Get(fe->GetGeomType(), intorder));
fes->GetElementVDofs(i, vdofs);
for (j = 0; j < ir->GetNPoints(); j++)
{
const IntegrationPoint &ip = ir->IntPoint(j);
fe->CalcShape(ip, shape);
transf->SetIntPoint(&ip);
for (d = 0; d < fes->GetVDim(); d++)
{
a = 0;
for (k = 0; k < fdof; k++)
if (vdofs[fdof*d+k] >= 0)
a += (*this)(vdofs[fdof*d+k]) * shape(k);
else
a -= (*this)(-1-vdofs[fdof*d+k]) * shape(k);
a -= exsol[d]->Eval(*transf, ip);
a = fabs(a);
if (error < a)
error = a;
}
}
}
return error;
}
double GridFunction::ComputeMaxError(
VectorCoefficient &exsol, const IntegrationRule *irs[]) const
{
double error = 0.0;
const FiniteElement *fe;
ElementTransformation *T;
DenseMatrix vals, exact_vals, tr;
Vector loc_errs;
for (int i = 0; i < fes->GetNE(); i++)
{
fe = fes->GetFE(i);
int intorder = fe->GetOrder()+2; // <----------
const IntegrationRule *ir;
if (irs)
ir = irs[fe->GetGeomType()];
else
ir = &(IntRules.Get(fe->GetGeomType(), intorder));
GetVectorValues(i, *ir, vals, tr);
T = fes->GetElementTransformation(i);
exsol.Eval(exact_vals, *T, *ir);
vals -= exact_vals;
loc_errs.SetSize(vals.Width());
// compute the lengths of the errors at the integration points
// thus the vector max. norm is rotationally invariant
vals.Norm2(loc_errs);
double loc_error = loc_errs.Normlinf();
if (error < loc_error)
error = loc_error;
}
return error;
}
double GridFunction::ComputeW11Error(
Coefficient *exsol, VectorCoefficient *exgrad, int norm_type,
Array<int> *elems, const IntegrationRule *irs[]) const
{
// assuming vdim is 1
int i, fdof, dim, intorder, j, k;
Mesh *mesh;
const FiniteElement *fe;
ElementTransformation *transf;
Vector e_grad, a_grad, shape, el_dofs, err_val, ell_coeff_val;
DenseMatrix dshape, dshapet, Jinv;
Array<int> vdofs;
double a, error = 0.0;
mesh = fes->GetMesh();
dim = mesh->Dimension();
e_grad.SetSize(dim);
a_grad.SetSize(dim);
Jinv.SetSize(dim);
if (norm_type & 1) // L_1 norm
for (i = 0; i < mesh->GetNE(); i++)
{
if (elems != NULL && (*elems)[i] == 0) continue;
fe = fes->GetFE(i);
fdof = fe->GetDof();
transf = fes->GetElementTransformation(i);
el_dofs.SetSize(fdof);
shape.SetSize(fdof);
intorder = fe->GetOrder() + 1; // <----------
const IntegrationRule *ir;
if (irs)
ir = irs[fe->GetGeomType()];
else
ir = &(IntRules.Get(fe->GetGeomType(), intorder));
fes->GetElementVDofs(i, vdofs);
for (k = 0; k < fdof; k++)
if (vdofs[k] >= 0)
el_dofs(k) = (*this)(vdofs[k]);
else
el_dofs(k) = -(*this)(-1-vdofs[k]);
for (j = 0; j < ir->GetNPoints(); j++)
{
const IntegrationPoint &ip = ir->IntPoint(j);
fe->CalcShape(ip, shape);
transf->SetIntPoint(&ip);
a = (el_dofs * shape) - (exsol->Eval(*transf, ip));
error += ip.weight * transf->Weight() * fabs(a);
}
}
if (norm_type & 2) // W^1_1 seminorm
for (i = 0; i < mesh->GetNE(); i++)
{
if (elems != NULL && (*elems)[i] == 0) continue;
fe = fes->GetFE(i);
fdof = fe->GetDof();
transf = mesh->GetElementTransformation(i);
el_dofs.SetSize(fdof);
dshape.SetSize(fdof, dim);
dshapet.SetSize(fdof, dim);
intorder = fe->GetOrder() + 1; // <----------
const IntegrationRule *ir;
if (irs)
ir = irs[fe->GetGeomType()];
else
ir = &(IntRules.Get(fe->GetGeomType(), intorder));
fes->GetElementVDofs(i, vdofs);
for (k = 0; k < fdof; k++)
if (vdofs[k] >= 0)
el_dofs(k) = (*this)(vdofs[k]);
else
el_dofs(k) = -(*this)(-1-vdofs[k]);
for (j = 0; j < ir->GetNPoints(); j++)
{
const IntegrationPoint &ip = ir->IntPoint(j);
fe->CalcDShape(ip, dshape);
transf->SetIntPoint(&ip);
exgrad->Eval(e_grad, *transf, ip);
CalcInverse(transf->Jacobian(), Jinv);
Mult(dshape, Jinv, dshapet);
dshapet.MultTranspose(el_dofs, a_grad);
e_grad -= a_grad;
error += ip.weight * transf->Weight() * e_grad.Norml1();
}
}
return error;
}
double GridFunction::ComputeL1Error(
VectorCoefficient &exsol, const IntegrationRule *irs[]) const
{
double error = 0.0;
const FiniteElement *fe;
ElementTransformation *T;
DenseMatrix vals, exact_vals, tr;
Vector loc_errs;
for (int i = 0; i < fes->GetNE(); i++)
{
fe = fes->GetFE(i);
int intorder = fe->GetOrder()+2; // <----------
const IntegrationRule *ir;
if (irs)
ir = irs[fe->GetGeomType()];
else
ir = &(IntRules.Get(fe->GetGeomType(), intorder));
GetVectorValues(i, *ir, vals, tr);
T = fes->GetElementTransformation(i);
exsol.Eval(exact_vals, *T, *ir);
vals -= exact_vals;
loc_errs.SetSize(vals.Width());
// compute the lengths of the errors at the integration points
// thus the vector L_1 norm is rotationally invariant
vals.Norm2(loc_errs);
for (int j = 0; j < ir->GetNPoints(); j++)
{
const IntegrationPoint &ip = ir->IntPoint(j);
T->SetIntPoint(&ip);
error += ip.weight * T->Weight() * loc_errs(j);
}
}
return error;
}
GridFunction & GridFunction::operator=(double value)
{
for (int i = 0; i < size; i++)
data[i] = value;
return *this;
}
GridFunction & GridFunction::operator=(const Vector &v)
{
for (int i = 0; i < size; i++)
data[i] = v(i);
return *this;
}
GridFunction & GridFunction::operator=(const GridFunction &v)
{
return this->operator=((const Vector &)v);
}
void GridFunction::Save(ostream &out)
{
fes->Save(out);
out << endl;
Vector::Print(out, 1);
}
void GridFunction::SaveVTK(ostream &out, const string &field_name, int ref)
{
Mesh *mesh = fes->GetMesh();
RefinedGeometry *RefG;
Vector val;
DenseMatrix vval, pmat;
if (VectorDim() == 1)
{
// scalar data
out << "SCALARS " << field_name << " double 1\n"
<< "LOOKUP_TABLE default\n";
for (int i = 0; i < mesh->GetNE(); i++)
{
RefG = GlobGeometryRefiner.Refine(
mesh->GetElementBaseGeometry(i), ref, 1);
GetValues(i, RefG->RefPts, val, pmat);
for (int j = 0; j < val.Size(); j++)
{
out << val(j) << '\n';
}
}
}
else
{
// vector data
out << "VECTORS " << field_name << " double\n";
for (int i = 0; i < mesh->GetNE(); i++)
{
RefG = GlobGeometryRefiner.Refine(
mesh->GetElementBaseGeometry(i), ref, 1);
GetVectorValues(i, RefG->RefPts, vval, pmat);
for (int j = 0; j < vval.Width(); j++)
{
out << vval(0, j) << ' ' << vval(1, j) << ' ';
if (vval.Height() == 2)
out << 0.0;
else
out << vval(2, j);
out << '\n';
}
}
}
}
void GridFunction::SaveSTLTri(ostream &out, double p1[], double p2[],
double p3[])
{
double v1[3] = { p2[0] - p1[0], p2[1] - p1[1], p2[2] - p1[2] };
double v2[3] = { p3[0] - p1[0], p3[1] - p1[1], p3[2] - p1[2] };
double n[] = { v1[1] * v2[2] - v1[2] * v2[1],
v1[2] * v2[0] - v1[0] * v2[2],
v1[0] * v2[1] - v1[1] * v2[0] };
double rl = 1.0 / sqrt(n[0] * n[0] + n[1] * n[1] + n[2] * n[2]);
n[0] *= rl; n[1] *= rl; n[2] *= rl;
out << " facet normal " << n[0] << ' ' << n[1] << ' ' << n[2]
<< "\n outer loop"
<< "\n vertex " << p1[0] << ' ' << p1[1] << ' ' << p1[2]
<< "\n vertex " << p2[0] << ' ' << p2[1] << ' ' << p2[2]
<< "\n vertex " << p3[0] << ' ' << p3[1] << ' ' << p3[2]
<< "\n endloop\n endfacet\n";
}
void GridFunction::SaveSTL(ostream &out, int TimesToRefine)
{
Mesh *mesh = fes->GetMesh();
if (mesh->Dimension() != 2)
return;
int i, j, k, l, n;
DenseMatrix pointmat;
Vector values;
RefinedGeometry * RefG;
double pts[4][3], bbox[3][2];
out << "solid GridFunction\n";
bbox[0][0] = bbox[0][1] = bbox[1][0] = bbox[1][1] =
bbox[2][0] = bbox[2][1] = 0.0;
for (i = 0; i < mesh->GetNE(); i++)
{
n = fes->GetFE(i)->GetGeomType();
RefG = GlobGeometryRefiner.Refine(n, TimesToRefine);
GetValues(i, RefG->RefPts, values, pointmat);
Array<int> &RG = RefG->RefGeoms;
n = Geometries.NumBdr(n);
for (k = 0; k < RG.Size()/n; k++)
{
for (j = 0; j < n; j++)
{
l = RG[n*k+j];
pts[j][0] = pointmat(0,l);
pts[j][1] = pointmat(1,l);
pts[j][2] = values(l);
}
if (n == 3)
{
SaveSTLTri(out, pts[0], pts[1], pts[2]);
}
else
{
SaveSTLTri(out, pts[0], pts[1], pts[2]);
SaveSTLTri(out, pts[0], pts[2], pts[3]);
}
}
if (i == 0)
{
bbox[0][0] = pointmat(0,0);
bbox[0][1] = pointmat(0,0);
bbox[1][0] = pointmat(1,0);
bbox[1][1] = pointmat(1,0);
bbox[2][0] = values(0);
bbox[2][1] = values(0);
}
for (j = 0; j < values.Size(); j++)
{
if (bbox[0][0] > pointmat(0,j))
bbox[0][0] = pointmat(0,j);
if (bbox[0][1] < pointmat(0,j))
bbox[0][1] = pointmat(0,j);
if (bbox[1][0] > pointmat(1,j))
bbox[1][0] = pointmat(1,j);
if (bbox[1][1] < pointmat(1,j))
bbox[1][1] = pointmat(1,j);
if (bbox[2][0] > values(j))
bbox[2][0] = values(j);
if (bbox[2][1] < values(j))
bbox[2][1] = values(j);
}
}
cout << "[xmin,xmax] = [" << bbox[0][0] << ',' << bbox[0][1] << "]\n"
<< "[ymin,ymax] = [" << bbox[1][0] << ',' << bbox[1][1] << "]\n"
<< "[zmin,zmax] = [" << bbox[2][0] << ',' << bbox[2][1] << ']'
<< endl;
out << "endsolid GridFunction" << endl;
}
void ComputeFlux(BilinearFormIntegrator &blfi,
GridFunction &u,
GridFunction &flux, int wcoef, int sd)
{
int i, j, nfe;
FiniteElementSpace *ufes, *ffes;
ElementTransformation *Transf;
ufes = u.FESpace();
ffes = flux.FESpace();
nfe = ufes->GetNE();
Array<int> udofs;
Array<int> fdofs;
Array<int> overlap(flux.Size());
Vector ul, fl;
flux = 0.0;
for (i = 0; i < overlap.Size(); i++)
overlap[i] = 0;
for (i = 0; i < nfe; i++)
if (sd < 0 || ufes->GetAttribute(i) == sd)
{
ufes->GetElementVDofs(i, udofs);
ffes->GetElementVDofs(i, fdofs);
ul.SetSize(udofs.Size());
for (j = 0; j < ul.Size(); j++)
ul(j) = u(udofs[j]);
Transf = ufes->GetElementTransformation(i);
blfi.ComputeElementFlux(*ufes->GetFE(i), *Transf, ul,
*ffes->GetFE(i), fl, wcoef);
flux.AddElementVector(fdofs, fl);
for (j = 0; j < fdofs.Size(); j++)
overlap[fdofs[j]]++;
}
for (i = 0; i < overlap.Size(); i++)
if (overlap[i] != 0)
flux(i) /= overlap[i];
}
void ZZErrorEstimator(BilinearFormIntegrator &blfi,
GridFunction &u,
GridFunction &flux, Vector &ErrorEstimates,
int wsd)
{
int i, j, s, nfe, nsd;
FiniteElementSpace *ufes, *ffes;
ElementTransformation *Transf;
ufes = u.FESpace();
ffes = flux.FESpace();
nfe = ufes->GetNE();
Array<int> udofs;
Array<int> fdofs;
Vector ul, fl, fla;
ErrorEstimates.SetSize(nfe);
nsd = 1;
if (wsd)
for (i = 0; i < nfe; i++)
if ( (j=ufes->GetAttribute(i)) > nsd)
nsd = j;
for (s = 1; s <= nsd; s++)
{
if (wsd)
ComputeFlux(blfi, u, flux, 0, s);
else
ComputeFlux(blfi, u, flux, 0);
for (i = 0; i < nfe; i++)
if (!wsd || ufes->GetAttribute(i) == s)
{
ufes->GetElementVDofs(i, udofs);
ffes->GetElementVDofs(i, fdofs);
ul.SetSize(udofs.Size());
for (j = 0; j < ul.Size(); j++)
ul(j) = u(udofs[j]);
fla.SetSize(fdofs.Size());
for (j = 0; j < fla.Size(); j++)
fla(j) = flux(fdofs[j]);
Transf = ufes->GetElementTransformation(i);
blfi.ComputeElementFlux(*ufes->GetFE(i), *Transf, ul,
*ffes->GetFE(i), fl, 0);
fl -= fla;
ErrorEstimates(i) = blfi.ComputeFluxEnergy(*ffes->GetFE(i),
*Transf, fl);
}
}
}