-
Praetorius, Simon authoredPraetorius, Simon authored
DOFVector.cc 37.62 KiB
//
// Software License for AMDiS
//
// Copyright (c) 2010 Dresden University of Technology
// All rights reserved.
// Authors: Simon Vey, Thomas Witkowski et al.
//
// This file is part of AMDiS
//
// See also license.opensource.txt in the distribution.
#include <boost/numeric/mtl/mtl.hpp>
#include "DOFVector.h"
#include "Traverse.h"
#include "DualTraverse.h"
#include "FixVec.h"
namespace AMDiS {
template<>
void DOFVector<double>::coarseRestrict(RCNeighbourList& list, int n)
{
FUNCNAME("DOFVector<double>::coarseRestrict()");
switch (coarsenOperation) {
case NO_OPERATION:
return;
break;
case COARSE_RESTRICT:
(const_cast<BasisFunction*>(feSpace->getBasisFcts()))->coarseRestr(this, &list, n);
break;
case COARSE_INTERPOL:
TEST_EXIT_DBG(feSpace)("Should not happen!\n");
TEST_EXIT_DBG(feSpace->getBasisFcts())("Shoud not happen!\n");
(const_cast<BasisFunction*>(feSpace->getBasisFcts()))->coarseInter(this, &list, n);
break;
default:
WARNING("Invalid coarsen operation \"%d\" in vector \"%s\"\n",
coarsenOperation, this->name.c_str());
}
}
template<>
void DOFVector<double>::refineInterpol(RCNeighbourList& list, int n)
{
(const_cast<BasisFunction*>(feSpace->getBasisFcts()))->refineInter(this, &list, n);
}
template<>
void DOFVector<WorldVector<double> >::refineInterpol(RCNeighbourList& list, int n)
{
if (n < 1)
return;
Element *el = list.getElement(0);
int n0 = feSpace->getAdmin()->getNumberOfPreDofs(VERTEX);
DegreeOfFreedom dof0 = el->getDof(0, n0);
DegreeOfFreedom dof1 = el->getDof(1, n0);
DegreeOfFreedom dof_new = el->getChild(0)->getDof(feSpace->getMesh()->getDim(), n0);
vec[dof_new] = vec[dof0];
vec[dof_new] += vec[dof1];
vec[dof_new] *= 0.5;
}
template<>
const double& DOFVector<double>::evalAtPoint(WorldVector<double> &p, ElInfo *oldElInfo, double* values) const
{
FUNCNAME("DOFVector<double>::evalAtCoords()");
Mesh *mesh = feSpace->getMesh();
const BasisFunction *basFcts = feSpace->getBasisFcts();
int dim = mesh->getDim();
int nBasFcts = basFcts->getNumber();
DegreeOfFreedom *localIndices = new DegreeOfFreedom[nBasFcts];
DimVec<double> lambda(dim, NO_INIT);
ElInfo *elInfo = mesh->createNewElInfo();
static double value = 0.0;
bool inside = false;
if (oldElInfo && oldElInfo->getMacroElement()) {
inside = mesh->findElInfoAtPoint(p, elInfo, lambda, oldElInfo->getMacroElement(), NULL, NULL);
delete oldElInfo;
} else
inside = mesh->findElInfoAtPoint(p, elInfo, lambda, NULL, NULL, NULL);
if (oldElInfo)
oldElInfo = elInfo;
if (inside) {
basFcts->getLocalIndices(elInfo->getElement(), feSpace->getAdmin(), localIndices);
ElementVector uh(lambda.size());
for (int i = 0; i < lambda.size(); i++)
uh[i] = operator[](localIndices[i]);
value = basFcts->evalUh(lambda, uh);
} else
throw(std::runtime_error("Can not eval DOFVector at point p, because point is outside geometry."));
delete [] localIndices;
if (oldElInfo == NULL)
delete elInfo;
if (values != NULL)
*values = value;
return value;
};
template<>
const WorldVector<double>& DOFVector<WorldVector<double> >::evalAtPoint(WorldVector<double> &p, ElInfo *oldElInfo, WorldVector<double>* values) const
{
FUNCNAME("DOFVector<double>::evalAtCoords()");
Mesh *mesh = feSpace->getMesh();
const BasisFunction *basFcts = feSpace->getBasisFcts();
int dim = mesh->getDim();
int nBasFcts = basFcts->getNumber();
DegreeOfFreedom *localIndices = new DegreeOfFreedom[nBasFcts];
DimVec<double> lambda(dim, NO_INIT);
ElInfo *elInfo = mesh->createNewElInfo();
static WorldVector<double> Values(DEFAULT_VALUE, 0.0);
WorldVector<double> *val = (NULL != values) ? values : &Values;
bool inside = false;
if (oldElInfo && oldElInfo->getMacroElement()) {
inside = mesh->findElInfoAtPoint(p, elInfo, lambda, oldElInfo->getMacroElement(), NULL, NULL);
delete oldElInfo;
} else
inside = mesh->findElInfoAtPoint(p, elInfo, lambda, NULL, NULL, NULL);
if (oldElInfo)
oldElInfo = elInfo;
if (inside) {
basFcts->getLocalIndices(elInfo->getElement(), feSpace->getAdmin(), localIndices);
mtl::dense_vector<WorldVector<double> > uh(lambda.size());
for (int i = 0; i < lambda.size(); i++)
uh[i] = operator[](localIndices[i]);
basFcts->evalUh(lambda, uh, val);
} else
throw(std::runtime_error("Can not eval DOFVector at point p, because point is outside geometry."));
delete [] localIndices;
if (oldElInfo == NULL)
delete elInfo;
return ((*val));
};
template<>
double DOFVector<double>::IntOnBoundary(BoundaryType boundaryType,
Quadrature* q) const
{
FUNCNAME("DOFVector<T>::IntOnBoundary()");
Mesh* mesh = this->feSpace->getMesh();
int dim = mesh->getDim();
if (!q) {
int deg = 2 * this->feSpace->getBasisFcts()->getDegree();
q = Quadrature::provideQuadrature(dim - 1, deg);
} else {
TEST_EXIT(q->getDim() == dim-1)
("Provided quadrature has wrong dimension for surfaceQuadrature!\n");
}
// create barycentric coords for each vertex of each side
const Element *refElement = Global::getReferenceElement(dim);
VectorOfFixVecs<DimVec<double> >**coords;
coords = new VectorOfFixVecs<DimVec<double> >*[dim + 1];
// for all element sides
for (int i = 0; i < dim + 1; i++) {
coords[i] = new VectorOfFixVecs<DimVec<double> >(dim, dim, DEFAULT_VALUE,
DimVec<double>(dim, DEFAULT_VALUE, 0.0));
// for each vertex of the side
for (int k = 0; k < dim; k++) {
int index = refElement->getVertexOfPosition(INDEX_OF_DIM(dim - 1, dim),
i, k);
(*coords[i])[k][index] = 1.0;
}
}
std::vector<SurfaceQuadrature*> quadSurfaces(dim + 1);
for (int i = 0; i < dim + 1; i++)
quadSurfaces[i] = new SurfaceQuadrature(q, *coords[i]);
double result = 0.0;
TraverseStack stack;
ElInfo *elInfo = stack.traverseFirst(mesh, -1,
Mesh::CALL_LEAF_EL | Mesh::FILL_BOUND | Mesh::FILL_COORDS);
while (elInfo) {
for (int face = 0; face < dim + 1; face++) {
if (elInfo->getBoundary(face) == boundaryType) {
int nPoints = quadSurfaces[face]->getNumPoints();
mtl::dense_vector<double> uh_vec(nPoints);
double det = elInfo->calcSurfaceDet(*coords[face]);
double normT = 0.0;
this->getVecAtQPs(elInfo, quadSurfaces[face], NULL, uh_vec);
for (int iq = 0; iq < nPoints; iq++)
normT += quadSurfaces[face]->getWeight(iq) * (uh_vec[iq]);
result += det * normT;
}
}
elInfo = stack.traverseNext(elInfo);
}
#ifdef HAVE_PARALLEL_DOMAIN_AMDIS
double localResult = result;
MPI::COMM_WORLD.Allreduce(&localResult, &result, 1, MPI_DOUBLE, MPI_SUM);
#endif
return result;
}
template<>
double DOFVector<WorldVector<double> >::IntOnBoundaryNormal(
BoundaryType boundaryType, Quadrature* q) const
{
FUNCNAME("DOFVector<T>::IntOnBoundary()");
Mesh* mesh = this->feSpace->getMesh();
int dim = mesh->getDim();
if (!q) {
int deg = 2 * this->feSpace->getBasisFcts()->getDegree();
q = Quadrature::provideQuadrature(dim - 1, deg);
} else {
TEST_EXIT(q->getDim() == dim-1)
("Provided quadrature has wrong dimension for surfaceQuadrature!\n");
}
// create barycentric coords for each vertex of each side
const Element *refElement = Global::getReferenceElement(dim);
VectorOfFixVecs<DimVec<double> >**coords;
coords = new VectorOfFixVecs<DimVec<double> >*[dim + 1];
// for all element sides
for (int i = 0; i < dim + 1; i++) {
coords[i] = new VectorOfFixVecs<DimVec<double> >(dim, dim, DEFAULT_VALUE,
DimVec<double>(dim, DEFAULT_VALUE, 0.0));
// for each vertex of the side
for (int k = 0; k < dim; k++) {
int index = refElement->getVertexOfPosition(INDEX_OF_DIM(dim - 1, dim),
i, k);
(*coords[i])[k][index] = 1.0;
}
}
std::vector<SurfaceQuadrature*> quadSurfaces(dim + 1);
for (int i = 0; i < dim + 1; i++)
quadSurfaces[i] = new SurfaceQuadrature(q, *coords[i]);
double result = 0.0;
WorldVector<double> normal;
TraverseStack stack;
ElInfo *elInfo = stack.traverseFirst(mesh, -1,
Mesh::CALL_LEAF_EL | Mesh::FILL_BOUND | Mesh::FILL_COORDS);
while (elInfo) {
for (int face = 0; face < dim + 1; face++) {
if (elInfo->getBoundary(face) == boundaryType) {
elInfo->getNormal(face, normal);
double det = elInfo->calcSurfaceDet(*coords[face]);
int nPoints = quadSurfaces[face]->getNumPoints();
mtl::dense_vector<WorldVector<double> > uh_vec(nPoints);
WorldVector<double> normT; normT.set(0.0);
this->getVecAtQPs(elInfo, quadSurfaces[face], NULL, uh_vec);
for (int iq = 0; iq < nPoints; iq++)
normT += quadSurfaces[face]->getWeight(iq) * (uh_vec[iq]);
// scalar product between vector-valued solution and normal vector
result += det * (normT * normal);
}
}
elInfo = stack.traverseNext(elInfo);
}
#ifdef HAVE_PARALLEL_DOMAIN_AMDIS
double localResult = result;
MPI::COMM_WORLD.Allreduce(&localResult, &result, 1, MPI_DOUBLE, MPI_SUM);
#endif
return result;
}
template<>
DOFVector<WorldVector<double> >*
DOFVector<double>::getGradient(DOFVector<WorldVector<double> > *grad) const
{
FUNCNAME("DOFVector<double>::getGradient()");
// define result vector
static DOFVector<WorldVector<double> > *result = NULL;
if (grad) {
result = grad;
} else {
if(result && result->getFeSpace() != feSpace) {
delete result;
result = new DOFVector<WorldVector<double> >(feSpace, "gradient");
}
}
Mesh *mesh = feSpace->getMesh();
int dim = mesh->getDim();
const BasisFunction *basFcts = feSpace->getBasisFcts();
DOFAdmin *admin = feSpace->getAdmin();
// count number of nodes and dofs per node
std::vector<int> nNodeDOFs;
std::vector<int> nNodePreDofs;
std::vector<DimVec<double>*> bary;
int nNodes = 0;
int nDofs = 0;
for (int i = 0; i < dim + 1; i++) {
GeoIndex geoIndex = INDEX_OF_DIM(i, dim);
int nPositions = mesh->getGeo(geoIndex);
int numPreDofs = admin->getNumberOfPreDofs(i);
for (int j = 0; j < nPositions; j++) {
int dofs = basFcts->getNumberOfDofs(geoIndex);
nNodeDOFs.push_back(dofs);
nDofs += dofs;
nNodePreDofs.push_back(numPreDofs);
}
nNodes += nPositions;
}
TEST_EXIT_DBG(nDofs == basFcts->getNumber())
("number of dofs != number of basis functions\n");
for (int i = 0; i < nDofs; i++)
bary.push_back(basFcts->getCoords(i));
ElementVector localUh(basFcts->getNumber());
// traverse mesh
std::vector<bool> visited(getUsedSize(), false);
TraverseStack stack;
Flag fillFlag = Mesh::CALL_LEAF_EL | Mesh::FILL_GRD_LAMBDA | Mesh::FILL_COORDS;
ElInfo *elInfo = stack.traverseFirst(mesh, -1, fillFlag);
while (elInfo) {
const DegreeOfFreedom **dof = elInfo->getElement()->getDof();
const DimVec<WorldVector<double> > &grdLambda = elInfo->getGrdLambda();
getLocalVector(elInfo->getElement(), localUh);
int localDOFNr = 0;
for (int i = 0; i < nNodes; i++) { // for all nodes
for (int j = 0; j < nNodeDOFs[i]; j++) { // for all dofs at this node
DegreeOfFreedom dofIndex = dof[i][nNodePreDofs[i] + j];
if (!visited[dofIndex]) {
basFcts->evalGrdUh(*(bary[localDOFNr]), grdLambda,
localUh, &((*result)[dofIndex]));
visited[dofIndex] = true;
}
localDOFNr++;
}
}
elInfo = stack.traverseNext(elInfo);
}
return result;
}
template<>
DOFVector<WorldVector<double> >*
DOFVector<double>::getRecoveryGradient(DOFVector<WorldVector<double> > *grad) const
{
FUNCNAME("DOFVector<double>::getRecoveryGradient()");
// define result vector
static DOFVector<WorldVector<double> > *vec = NULL;
DOFVector<WorldVector<double> > *result = grad;
if (!result) {
if (vec && vec->getFeSpace() != feSpace) {
delete vec;
vec = NULL;
}
if (!vec)
vec = new DOFVector<WorldVector<double> >(feSpace, "gradient");
result = vec;
}
result->set(WorldVector<double>(DEFAULT_VALUE, 0.0));
DOFVector<double> volume(feSpace, "volume");
volume.set(0.0);
const BasisFunction *basFcts = feSpace->getBasisFcts();
int nPreDofs = feSpace->getAdmin()->getNumberOfPreDofs(VERTEX);
DimVec<double> bary(dim, DEFAULT_VALUE, (1.0 / (dim + 1.0)));
WorldVector<double> grd;
// traverse mesh
Mesh *mesh = feSpace->getMesh();
TraverseStack stack;
ElInfo *elInfo = stack.traverseFirst(mesh, -1,
Mesh::CALL_LEAF_EL | Mesh::FILL_DET |
Mesh::FILL_GRD_LAMBDA | Mesh::FILL_COORDS);
ElementVector localUh(basFcts->getNumber());
while (elInfo) {
double det = elInfo->getDet();
const DegreeOfFreedom **dof = elInfo->getElement()->getDof();
const DimVec<WorldVector<double> > &grdLambda = elInfo->getGrdLambda();
getLocalVector(elInfo->getElement(), localUh);
basFcts->evalGrdUh(bary, grdLambda, localUh, &grd);
for (int i = 0; i < dim + 1; i++) {
DegreeOfFreedom dofIndex = dof[i][nPreDofs];
(*result)[dofIndex] += grd * det;
volume[dofIndex] += det;
}
elInfo = stack.traverseNext(elInfo);
}
DOFVector<double>::Iterator volIt(&volume, USED_DOFS);
DOFVector<WorldVector<double> >::Iterator grdIt(result, USED_DOFS);
for (volIt.reset(), grdIt.reset(); !volIt.end(); ++volIt, ++grdIt)
if (*volIt != 0.0)
*grdIt *= 1.0 / (*volIt);
return result;
}
template<>
const WorldVector<double> *DOFVectorBase<double>::getGrdAtQPs(const ElInfo *elInfo,
const Quadrature *quad,
const FastQuadrature *quadFast,
WorldVector<double> *grdAtQPs) const
{
FUNCNAME("DOFVector<double>::getGrdAtQPs()");
TEST_EXIT_DBG(quad || quadFast)("neither quad nor quadFast defined\n");
if (quad && quadFast) {
TEST_EXIT_DBG(quad == quadFast->getQuadrature())
("quad != quadFast->quadrature\n");
}
TEST_EXIT_DBG(!quadFast || quadFast->getBasisFunctions() == feSpace->getBasisFcts())
("invalid basis functions");
int dow = Global::getGeo(WORLD);
int nPoints = quadFast ? quadFast->getQuadrature()->getNumPoints() : quad->getNumPoints();
static WorldVector<double> *grd = NULL;
WorldVector<double> *result;
if (grdAtQPs) {
result = grdAtQPs;
} else {
if (grd)
delete [] grd;
grd = new WorldVector<double>[nPoints];
for (int i = 0; i < nPoints; i++)
grd[i].set(0.0);
result = grd;
}
ElementVector localVec(nBasFcts);
getLocalVector(elInfo->getElement(), localVec);
mtl::dense_vector<double> grd1(dim + 1);
int parts = Global::getGeo(PARTS, dim);
const DimVec<WorldVector<double> > &grdLambda = elInfo->getGrdLambda();
if (quadFast) {
for (int i = 0; i < nPoints; i++) {
grd1 = 0.0;
for (int j = 0; j < nBasFcts; j++)
for (int k = 0; k < parts; k++)
grd1[k] += quadFast->getGradient(i, j, k) * localVec[j];
for (int l=0; l < dow; l++) {
result[i][l] = 0.0;
for (int k = 0; k < parts; k++)
result[i][l] += grdLambda[k][l] * grd1[k];
}
}
} else {
const BasisFunction *basFcts = feSpace->getBasisFcts();
mtl::dense_vector<double> grdPhi(dim + 1);
for (int i = 0; i < nPoints; i++) {
grd1 = 0.0;
for (int j = 0; j < nBasFcts; j++) {
(*(basFcts->getGrdPhi(j)))(quad->getLambda(i), grdPhi);
for (int k = 0; k < parts; k++)
grd1[k] += grdPhi[k] * localVec[j];
}
for (int l = 0; l < dow; l++) {
result[i][l] = 0.0;
for (int k = 0; k < parts; k++)
result[i][l] += grdLambda[k][l] * grd1[k];
}
}
}
return const_cast<const WorldVector<double>*>(result);
}
template<>
const WorldVector<double> *DOFVectorBase<double>::getGrdAtQPs(const ElInfo *smallElInfo,
const ElInfo *largeElInfo,
const Quadrature *quad,
const FastQuadrature *quadFast,
WorldVector<double> *grdAtQPs) const
{
FUNCNAME("DOFVector<double>::getGrdAtQPs()");
TEST_EXIT_DBG(quad || quadFast)("neither quad nor quadFast defined\n");
if (quad && quadFast) {
TEST_EXIT_DBG(quad == quadFast->getQuadrature())("quad != quadFast->quadrature\n");
}
TEST_EXIT_DBG(!quadFast || quadFast->getBasisFunctions() == feSpace->getBasisFcts())
("invalid basis functions");
int dow = Global::getGeo(WORLD);
int nPoints = quadFast ? quadFast->getQuadrature()->getNumPoints() : quad->getNumPoints();
static WorldVector<double> *grd = NULL;
WorldVector<double> *result;
if (grdAtQPs) {
result = grdAtQPs;
} else {
if (grd)
delete [] grd;
grd = new WorldVector<double>[nPoints];
for (int i = 0; i < nPoints; i++)
grd[i].set(0.0);
result = grd;
}
ElementVector localVec(nBasFcts);
getLocalVector(largeElInfo->getElement(), localVec);
const BasisFunction *basFcts = feSpace->getBasisFcts();
mtl::dense2D<double> &m = smallElInfo->getSubElemCoordsMat(basFcts->getDegree());
int parts = Global::getGeo(PARTS, dim);
const DimVec<WorldVector<double> > &grdLambda = largeElInfo->getGrdLambda();
mtl::dense_vector<double> grd1(dim + 1);
mtl::dense_vector<double> grdPhi(dim + 1);
mtl::dense_vector<double> tmp(dim + 1);
for (int i = 0; i < nPoints; i++) {
grd1 = 0.0;
for (int j = 0; j < nBasFcts; j++) {
grdPhi = 0.0;
for (int k = 0; k < nBasFcts; k++) {
(*(basFcts->getGrdPhi(k)))(quad->getLambda(i), tmp);
tmp *= m[j][k];
grdPhi += tmp;
}
for (int k = 0; k < parts; k++)
grd1[k] += grdPhi[k] * localVec[j];
}
for (int l = 0; l < dow; l++) {
result[i][l] = 0.0;
for (int k = 0; k < parts; k++)
result[i][l] += grdLambda[k][l] * grd1[k];
}
}
return const_cast<const WorldVector<double>*>(result);
}
template<>
const WorldMatrix<double> *DOFVectorBase<double>::getD2AtQPs(const ElInfo *elInfo,
const Quadrature *quad,
const FastQuadrature *quadFast,
WorldMatrix<double> *d2AtQPs) const
{
FUNCNAME("DOFVector<double>::getD2AtQPs()");
TEST_EXIT_DBG(quad || quadFast)("neither quad nor quadFast defined\n");
if (quad && quadFast) {
TEST_EXIT_DBG(quad == quadFast->getQuadrature())
("quad != quadFast->quadrature\n");
}
TEST_EXIT_DBG(!quadFast || quadFast->getBasisFunctions() == feSpace->getBasisFcts())
("invalid basis functions");
Element *el = elInfo->getElement();
int dow = Global::getGeo(WORLD);
int nPoints = quadFast ? quadFast->getQuadrature()->getNumPoints() : quad->getNumPoints();
static WorldMatrix<double> *vec = NULL;
WorldMatrix<double> *result;
if (d2AtQPs) {
result = d2AtQPs;
} else {
if(vec) delete [] vec;
vec = new WorldMatrix<double>[nPoints];
for (int i = 0; i < nPoints; i++) {
vec[i].set(0.0);
}
result = vec;
}
ElementVector localVec(nBasFcts);
getLocalVector(el, localVec);
DimMat<double> D2Tmp(dim, DEFAULT_VALUE, 0.0);
int parts = Global::getGeo(PARTS, dim);
const DimVec<WorldVector<double> > &grdLambda = elInfo->getGrdLambda();
if (quadFast) {
for (int iq = 0; iq < nPoints; iq++) {
for (int k = 0; k < parts; k++)
for (int l = 0; l < parts; l++)
D2Tmp[k][l] = 0.0;
for (int i = 0; i < nBasFcts; i++) {
for (int k = 0; k < parts; k++)
for (int l = 0; l < parts; l++)
D2Tmp[k][l] += localVec[i] * quadFast->getSecDer(iq, i, k, l);
}
for (int i = 0; i < dow; i++)
for (int j = 0; j < dow; j++) {
result[iq][i][j] = 0.0;
for (int k = 0; k < parts; k++)
for (int l = 0; l < parts; l++)
result[iq][i][j] += grdLambda[k][i]*grdLambda[l][j]*D2Tmp[k][l];
}
}
} else {
const BasisFunction *basFcts = feSpace->getBasisFcts();
DimMat<double> D2Phi(dim, NO_INIT);
for (int iq = 0; iq < nPoints; iq++) {
for (int k = 0; k < parts; k++)
for (int l = 0; l < parts; l++)
D2Tmp[k][l] = 0.0;
for (int i = 0; i < nBasFcts; i++) {
WARNING("not tested after index correction\n");
(*(basFcts->getD2Phi(i)))(quad->getLambda(iq), D2Phi);
for (int k = 0; k < parts; k++)
for (int l = 0; l < parts; l++)
D2Tmp[k][l] += localVec[i] * D2Phi[k][l];
}
for (int i = 0; i < dow; i++)
for (int j = 0; j < dow; j++) {
result[iq][i][j] = 0.0;
for (int k = 0; k < parts; k++)
for (int l = 0; l < parts; l++)
result[iq][i][j] += grdLambda[k][i] * grdLambda[l][j] * D2Tmp[k][l];
}
}
}
return const_cast<const WorldMatrix<double>*>(result);
}
template<>
void DOFVector<double>::interpol(DOFVector<double> *source, double factor)
{
FUNCNAME("DOFVector<double>::interpol()");
const FiniteElemSpace *sourceFeSpace = source->getFeSpace();
const BasisFunction *basisFcts = feSpace->getBasisFcts();
const BasisFunction *sourceBasisFcts = sourceFeSpace->getBasisFcts();
int nBasisFcts = basisFcts->getNumber();
int nSourceBasisFcts = sourceBasisFcts->getNumber();
this->set(0.0);
std::vector<DegreeOfFreedom> myLocalIndices(nBasisFcts);
ElementVector sourceLocalCoeffs(nSourceBasisFcts);
if (feSpace->getMesh() == sourceFeSpace->getMesh()) {
DimVec<double> *coords = NULL;
TraverseStack stack;
ElInfo *elInfo = stack.traverseFirst(feSpace->getMesh(), -1,
Mesh::CALL_LEAF_EL |
Mesh::FILL_COORDS);
while (elInfo) {
Element *el = elInfo->getElement();
basisFcts->getLocalIndices(el, feSpace->getAdmin(), myLocalIndices);
source->getLocalVector(el, sourceLocalCoeffs);
for (int i = 0; i < nBasisFcts; i++) {
if (vec[myLocalIndices[i]] == 0.0) {
coords = basisFcts->getCoords(i);
vec[myLocalIndices[i]] = sourceBasisFcts->evalUh(*coords, sourceLocalCoeffs) * factor;
}
}
elInfo = stack.traverseNext(elInfo);
}
} else {
DimVec<double> coords2(feSpace->getMesh()->getDim(), NO_INIT);
DualTraverse dualStack;
ElInfo *elInfo1, *elInfo2;
ElInfo *elInfoSmall, *elInfoLarge;
WorldVector<double> worldVec;
bool nextTraverse = dualStack.traverseFirst(feSpace->getMesh(),
sourceFeSpace->getMesh(),
-1, -1,
Mesh::CALL_LEAF_EL | Mesh::FILL_COORDS,
Mesh::CALL_LEAF_EL | Mesh::FILL_COORDS,
&elInfo1, &elInfo2,
&elInfoSmall, &elInfoLarge);
while (nextTraverse) {
basisFcts->getLocalIndices(elInfo1->getElement(), feSpace->getAdmin(),
myLocalIndices);
source->getLocalVector(elInfo2->getElement(), sourceLocalCoeffs);
for (int i = 0; i < nBasisFcts; i++) {
if (vec[myLocalIndices[i]] == 0.0) {
elInfo1->coordToWorld(*(basisFcts->getCoords(i)), worldVec);
elInfo2->worldToCoord(worldVec, &coords2);
bool isPositive = true;
for (int j = 0; j < coords2.size(); j++) {
if (coords2[j] < -0.00001) {
isPositive = false;
break;
}
}
if (isPositive)
vec[myLocalIndices[i]] =
sourceBasisFcts->evalUh(coords2, sourceLocalCoeffs);
}
}
nextTraverse =
dualStack.traverseNext(&elInfo1, &elInfo2, &elInfoSmall, &elInfoLarge);
}
}
}
template<>
void DOFVector<WorldVector<double> >::interpol(DOFVector<WorldVector<double> > *v,
double factor)
{
WorldVector<double> nul(DEFAULT_VALUE,0.0);
this->set(nul);
DimVec<double> *coords = NULL;
const FiniteElemSpace *vFeSpace = v->getFeSpace();
if (feSpace == vFeSpace)
WARNING("same FE-spaces\n");
const BasisFunction *basFcts = feSpace->getBasisFcts();
const BasisFunction *vBasFcts = vFeSpace->getBasisFcts();
int nBasFcts = basFcts->getNumber();
int vNumBasFcts = vBasFcts->getNumber();
if (feSpace->getMesh() == vFeSpace->getMesh()) {
std::vector<DegreeOfFreedom> myLocalIndices(nBasFcts);
mtl::dense_vector<WorldVector<double> > vLocalCoeffs(vNumBasFcts);
Mesh *mesh = feSpace->getMesh();
TraverseStack stack;
ElInfo *elInfo =
stack.traverseFirst(mesh, -1, Mesh::CALL_LEAF_EL | Mesh::FILL_COORDS);
while (elInfo) {
Element *el = elInfo->getElement();
basFcts->getLocalIndices(el, feSpace->getAdmin(), myLocalIndices);
v->getLocalVector(el, vLocalCoeffs);
for (int i = 0; i < nBasFcts; i++) {
if (vec[myLocalIndices[i]] == nul) {
coords = basFcts->getCoords(i);
vec[myLocalIndices[i]] += vBasFcts->evalUh(*coords, vLocalCoeffs, NULL) * factor;
}
}
elInfo = stack.traverseNext(elInfo);
}
} else {
ERROR_EXIT("not yet for dual traverse\n");
}
}
template<>
WorldVector<DOFVector<double>*> *DOFVector<double>::getGradient(WorldVector<DOFVector<double>*> *grad) const
{
FUNCNAME("DOFVector<double>::getGradient()");
Mesh *mesh = feSpace->getMesh();
int dim = mesh->getDim();
int dow = Global::getGeo(WORLD);
const BasisFunction *basFcts = feSpace->getBasisFcts();
DOFAdmin *admin = feSpace->getAdmin();
// define result vector
static WorldVector<DOFVector<double>*> *result = NULL;
if (grad) {
result = grad;
} else {
if (!result) {
result = new WorldVector<DOFVector<double>*>;
result->set(NULL);
}
for (int i = 0; i < dow; i++) {
if ((*result)[i] && (*result)[i]->getFeSpace() != feSpace) {
delete (*result)[i];
(*result)[i] = new DOFVector<double>(feSpace, "gradient");
}
}
}
// count number of nodes and dofs per node
std::vector<int> nNodeDOFs;
std::vector<int> nNodePreDofs;
std::vector<DimVec<double>*> bary;
int nNodes = 0;
int nDofs = 0;
for (int i = 0; i < dim + 1; i++) {
GeoIndex geoIndex = INDEX_OF_DIM(i, dim);
int numPositionNodes = mesh->getGeo(geoIndex);
int numPreDofs = admin->getNumberOfPreDofs(i);
for (int j = 0; j < numPositionNodes; j++) {
int dofs = basFcts->getNumberOfDofs(geoIndex);
nNodeDOFs.push_back(dofs);
nDofs += dofs;
nNodePreDofs.push_back(numPreDofs);
}
nNodes += numPositionNodes;
}
TEST_EXIT_DBG(nDofs == basFcts->getNumber())
("number of dofs != number of basis functions\n");
for (int i = 0; i < nDofs; i++)
bary.push_back(basFcts->getCoords(i));
// traverse mesh
std::vector<bool> visited(getUsedSize(), false);
TraverseStack stack;
Flag fillFlag = Mesh::CALL_LEAF_EL | Mesh::FILL_GRD_LAMBDA | Mesh::FILL_COORDS;
ElInfo *elInfo = stack.traverseFirst(mesh, -1, fillFlag);
WorldVector<double> grd;
ElementVector localUh(basFcts->getNumber());
while (elInfo) {
const DegreeOfFreedom **dof = elInfo->getElement()->getDof();
getLocalVector(elInfo->getElement(), localUh);
const DimVec<WorldVector<double> > &grdLambda = elInfo->getGrdLambda();
int localDOFNr = 0;
for (int i = 0; i < nNodes; i++) { // for all nodes
for (int j = 0; j < nNodeDOFs[i]; j++) { // for all dofs at this node
DegreeOfFreedom dofIndex = dof[i][nNodePreDofs[i] + j];
if (!visited[dofIndex]) {
basFcts->evalGrdUh(*(bary[localDOFNr]), grdLambda, localUh, &grd);
for (int k = 0; k < dow; k++)
(*(*result)[k])[dofIndex] = grd[k];
visited[dofIndex] = true;
}
localDOFNr++;
}
}
elInfo = stack.traverseNext(elInfo);
}
return result;
}
DOFVectorDOF::DOFVectorDOF() :
DOFVector<DegreeOfFreedom>()
{}
void DOFVectorDOF::freeDOFContent(DegreeOfFreedom dof)
{}
WorldVector<DOFVector<double>*> *transform(DOFVector<WorldVector<double> > *vec,
WorldVector<DOFVector<double>*> *res)
{
FUNCNAME("DOFVector<double>::transform()");
TEST_EXIT_DBG(vec)("no vector\n");
int dow = Global::getGeo(WORLD);
static WorldVector<DOFVector<double>*> *result = NULL;
if (!res && !result) {
result = new WorldVector<DOFVector<double>*>;
for (int i = 0; i < dow; i++)
(*result)[i] = new DOFVector<double>(vec->getFeSpace(), "transform");
}
WorldVector<DOFVector<double>*> *r = res ? res : result;
int vecSize = vec->getSize();
for (int i = 0; i < vecSize; i++)
for (int j = 0; j < dow; j++)
(*((*r)[j]))[i] = (*vec)[i][j];
return r;
}
template<>
void DOFVectorBase<double>::getVecAtQPs(const ElInfo *smallElInfo,
const ElInfo *largeElInfo,
const Quadrature *quad,
const FastQuadrature *quadFast,
mtl::dense_vector<double>& vecAtQPs) const
{
FUNCNAME("DOFVector<double>::getVecAtQPs()");
TEST_EXIT_DBG(quad || quadFast)("neither quad nor quadFast defined\n");
if (quad && quadFast) {
TEST_EXIT_DBG(quad == quadFast->getQuadrature())
("quad != quadFast->quadrature\n");
}
TEST_EXIT_DBG(!quadFast || quadFast->getBasisFunctions() == feSpace->getBasisFcts())
("invalid basis functions");
if (smallElInfo->getMesh() == feSpace->getMesh())
return getVecAtQPs(smallElInfo, quad, quadFast, vecAtQPs);
const BasisFunction *basFcts = feSpace->getBasisFcts();
int nPoints =
quadFast ? quadFast->getQuadrature()->getNumPoints() : quad->getNumPoints();
vecAtQPs.change_dim(nPoints);
ElementVector localVec(nBasFcts);
getLocalVector(largeElInfo->getElement(), localVec);
mtl::dense2D<double> &m = smallElInfo->getSubElemCoordsMat(basFcts->getDegree());
for (int i = 0; i < nPoints; i++) {
vecAtQPs[i] = 0.0;
for (int j = 0; j < nBasFcts; j++) {
double val = 0.0;
for (int k = 0; k < nBasFcts; k++)
val += m[j][k] * (*(basFcts->getPhi(k)))(quad->getLambda(i));
vecAtQPs[i] += localVec[j] * val;
}
}
}
template<>
void DOFVectorBase<double>::assemble(double factor, ElInfo *elInfo,
const BoundaryType *bound,
Operator *op)
{
FUNCNAME("DOFVector::assemble()");
if (!(op || this->operators.size()))
return;
set_to_zero(this->elementVector);
bool addVector = false;
if (op) {
op->getElementVector(elInfo, this->elementVector);
addVector = true;
} else {
std::vector<Operator*>::iterator it;
std::vector<double*>::iterator factorIt;
for (it = this->operators.begin(), factorIt = this->operatorFactor.begin();
it != this->operators.end();
++it, ++factorIt)
if ((*it)->getNeedDualTraverse() == false) {
(*it)->getElementVector(elInfo, this->elementVector,
*factorIt ? **factorIt : 1.0);
addVector = true;
}
}
if (addVector)
addElementVector(factor, this->elementVector, bound, elInfo);
}
template<>
void DOFVectorBase<double>::assemble2(double factor,
ElInfo *mainElInfo, ElInfo *auxElInfo,
ElInfo *smallElInfo, ElInfo *largeElInfo,
const BoundaryType *bound,
Operator *op)
{
FUNCNAME("DOFVector::assemble2()");
if (!(op || this->operators.size()))
return;
set_to_zero(this->elementVector);
bool addVector = false;
TEST_EXIT(!op)("Not yet implemented!\n");
std::vector<Operator*>::iterator it;
std::vector<double*>::iterator factorIt;
for (it = this->operators.begin(), factorIt = this->operatorFactor.begin();
it != this->operators.end();
++it, ++factorIt)
if ((*it)->getNeedDualTraverse()) {
(*it)->getElementVector(mainElInfo, auxElInfo,
smallElInfo, largeElInfo,
this->elementVector,
*factorIt ? **factorIt : 1.0);
addVector = true;
}
if (addVector)
addElementVector(factor, this->elementVector, bound, mainElInfo);
}
double integrate(const DOFVector<double> &vec1,
const DOFVector<double> &vec2,
BinaryAbstractFunction<double, double, double> *fct)
{
if (vec1.getFeSpace()->getMesh() == vec2.getFeSpace()->getMesh())
return intSingleMesh(vec1, vec2, fct);
else
return intDualMesh(vec1, vec2, fct);
}
double intSingleMesh(const DOFVector<double> &vec1,
const DOFVector<double> &vec2,
BinaryAbstractFunction<double, double, double> *fct)
{
FUNCNAME("intDualmesh()");
TEST_EXIT(fct)("No function defined!\n");
int deg = std::max(fct->getDegree(),
2 * vec1.getFeSpace()->getBasisFcts()->getDegree());
Quadrature* quad =
Quadrature::provideQuadrature(vec1.getFeSpace()->getMesh()->getDim(), deg);
FastQuadrature *fastQuad =
FastQuadrature::provideFastQuadrature(vec1.getFeSpace()->getBasisFcts(), *quad, INIT_PHI);
mtl::dense_vector<double> qp1(fastQuad->getNumPoints());
mtl::dense_vector<double> qp2(fastQuad->getNumPoints());
double value = 0.0;
Flag traverseFlag = Mesh::CALL_LEAF_EL | Mesh::FILL_COORDS | Mesh::FILL_DET;
TraverseStack stack;
ElInfo *elInfo = stack.traverseFirst(vec1.getFeSpace()->getMesh(), -1, traverseFlag);
while (elInfo) {
vec1.getVecAtQPs(elInfo, quad, fastQuad, qp1);
vec2.getVecAtQPs(elInfo, quad, fastQuad, qp2);
double tmp = 0.0;
for (int iq = 0; iq < fastQuad->getNumPoints(); iq++)
tmp += fastQuad->getWeight(iq) * (*fct)(qp1[iq], qp2[iq]);
value += tmp * elInfo->getDet();
elInfo = stack.traverseNext(elInfo);
}
#ifdef HAVE_PARALLEL_DOMAIN_AMDIS
double localValue = value;
MPI::COMM_WORLD.Allreduce(&localValue, &value, 1, MPI_DOUBLE, MPI_SUM);
#endif
return value;
}
double intDualMesh(const DOFVector<double> &vec1,
const DOFVector<double> &vec2,
BinaryAbstractFunction<double, double, double> *fct)
{
FUNCNAME("intDualmesh()");
TEST_EXIT(fct)("No function defined!\n");
int deg = std::max(fct->getDegree(),
2 * vec1.getFeSpace()->getBasisFcts()->getDegree());
Quadrature* quad =
Quadrature::provideQuadrature(vec1.getFeSpace()->getMesh()->getDim(), deg);
FastQuadrature *fastQuad =
FastQuadrature::provideFastQuadrature(vec1.getFeSpace()->getBasisFcts(), *quad, INIT_PHI);
mtl::dense_vector<double> qp1(fastQuad->getNumPoints());
mtl::dense_vector<double> qp2(fastQuad->getNumPoints());
double value = 0.0;
Flag traverseFlag = Mesh::CALL_LEAF_EL | Mesh::FILL_COORDS | Mesh::FILL_DET;
DualTraverse dualTraverse;
DualElInfo dualElInfo;
bool cont = dualTraverse.traverseFirst(vec1.getFeSpace()->getMesh(),
vec2.getFeSpace()->getMesh(),
-1, -1, traverseFlag, traverseFlag,
dualElInfo);
while (cont) {
vec1.getVecAtQPs(dualElInfo.smallElInfo, dualElInfo.largeElInfo, quad, NULL, qp1);
vec2.getVecAtQPs(dualElInfo.smallElInfo, dualElInfo.largeElInfo, quad, NULL, qp2);
double tmp = 0.0;
for (int iq = 0; iq < quad->getNumPoints(); iq++)
tmp += quad->getWeight(iq) * (*fct)(qp1[iq], qp2[iq]);
value += tmp * dualElInfo.smallElInfo->getDet();
cont = dualTraverse.traverseNext(dualElInfo);
}
#ifdef HAVE_PARALLEL_DOMAIN_AMDIS
double localValue = value;
MPI::COMM_WORLD.Allreduce(&localValue, &value, 1, MPI_DOUBLE, MPI_SUM);
#endif
return value;
}
double integrate(const DOFVector<double> &vec,
AbstractFunction<double, WorldVector<double> > *fct)
{
FUNCNAME("integrate()");
TEST_EXIT(fct)("No function defined!\n");
const FiniteElemSpace *feSpace = vec.getFeSpace();
Mesh *mesh = feSpace->getMesh();
int deg = std::max(fct->getDegree(), 2 * feSpace->getBasisFcts()->getDegree());
Quadrature* quad = Quadrature::provideQuadrature(mesh->getDim(), deg);
FastQuadrature *fastQuad =
FastQuadrature::provideFastQuadrature(feSpace->getBasisFcts(), *quad, INIT_PHI);
mtl::dense_vector<double> qp(fastQuad->getNumPoints());
WorldVector<double> coords;
double value = 0.0;
Flag traverseFlag = Mesh::CALL_LEAF_EL | Mesh::FILL_COORDS | Mesh::FILL_DET;
TraverseStack stack;
ElInfo *elInfo = stack.traverseFirst(mesh, -1, traverseFlag);
while (elInfo) {
vec.getVecAtQPs(elInfo, quad, fastQuad, qp);
double tmp = 0.0;
for (int iq = 0; iq < fastQuad->getNumPoints(); iq++) {
elInfo->coordToWorld(fastQuad->getLambda(iq), coords);
tmp += fastQuad->getWeight(iq) * (qp[iq] * (*fct)(coords));
}
value += tmp * elInfo->getDet();
elInfo = stack.traverseNext(elInfo);
}
#ifdef HAVE_PARALLEL_DOMAIN_AMDIS
double localValue = value;
MPI::COMM_WORLD.Allreduce(&localValue, &value, 1, MPI_DOUBLE, MPI_SUM);
#endif
return value;
}
double integrate(const FiniteElemSpace* feSpace,
AbstractFunction<double, WorldVector<double> > *fct)
{
FUNCNAME("integrate()");
TEST_EXIT(fct)("No function defined!\n");
int deg = std::max(fct->getDegree(), feSpace->getBasisFcts()->getDegree());
Quadrature* quad =
Quadrature::provideQuadrature(feSpace->getMesh()->getDim(), deg);
FastQuadrature *fastQuad =
FastQuadrature::provideFastQuadrature(feSpace->getBasisFcts(), *quad, INIT_PHI);
WorldVector<double> coords;
double value = 0.0;
Flag traverseFlag = Mesh::CALL_LEAF_EL | Mesh::FILL_COORDS | Mesh::FILL_DET;
TraverseStack stack;
ElInfo *elInfo = stack.traverseFirst(feSpace->getMesh(), -1, traverseFlag);
while (elInfo) {
double tmp = 0.0;
for (int iq = 0; iq < fastQuad->getNumPoints(); iq++) {
elInfo->coordToWorld(fastQuad->getLambda(iq), coords);
tmp += fastQuad->getWeight(iq) * (*fct)(coords);
}
value += tmp * elInfo->getDet();
elInfo = stack.traverseNext(elInfo);
}
#ifdef HAVE_PARALLEL_DOMAIN_AMDIS
double localValue = value;
MPI::COMM_WORLD.Allreduce(&localValue, &value, 1, MPI_DOUBLE, MPI_SUM);
#endif
return value;
}
}