Newer
Older

Thomas Witkowski
committed
//
// 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 <vector>
#include <boost/numeric/mtl/mtl.hpp>
#include "Assembler.h"
#include "FirstOrderAssembler.h"
#include "Operator.h"
#include "QPsiPhi.h"
#include "FiniteElemSpace.h"
#include "Quadrature.h"
#include "DOFVector.h"
namespace AMDiS {
std::vector<SubAssembler*> FirstOrderAssembler::optimizedSubAssemblersGrdPhi;
std::vector<SubAssembler*> FirstOrderAssembler::optimizedSubAssemblersGrdPsi;
std::vector<SubAssembler*> FirstOrderAssembler::standardSubAssemblersGrdPhi;
std::vector<SubAssembler*> FirstOrderAssembler::standardSubAssemblersGrdPsi;
FirstOrderAssembler::FirstOrderAssembler(Operator *op,
Assembler *assembler,
Quadrature *quad,
bool optimized,
FirstOrderType type)
: SubAssembler(op, assembler, quad, 1, optimized, type)

Thomas Witkowski
committed
FUNCNAME("FirstOrderAssmebler::FirstOrderAssembler()");
TEST_EXIT_DBG(dim > 0)("Should not happen!\n");
Lb.resize(1);
Lb[0].change_dim(dim + 1);
FirstOrderAssembler* FirstOrderAssembler::getSubAssembler(Operator* op,
Assembler *assembler,
Quadrature *quad,
FirstOrderType type,
bool optimized)
{
std::vector<SubAssembler*> *subAssemblers =

Thomas Witkowski
committed
optimized ?
(type == GRD_PSI ?
&optimizedSubAssemblersGrdPsi :
&optimizedSubAssemblersGrdPhi) :
(type == GRD_PSI ?
&standardSubAssemblersGrdPsi :
&standardSubAssemblersGrdPhi);

Thomas Witkowski
committed
(type == GRD_PSI) ? op->firstOrderGrdPsi : op->firstOrderGrdPhi;
// check if a assembler is needed at all
if (opTerms.size() == 0)
return NULL;
sort(opTerms.begin(), opTerms.end());
FirstOrderAssembler *newAssembler;
// check if a new assembler is needed
for (unsigned int i = 0; i < subAssemblers->size(); i++) {
std::vector<OperatorTerm*> assTerms = *((*subAssemblers)[i]->getTerms());
sort(assTerms.begin(), assTerms.end());

Thomas Witkowski
committed
if (opTerms == assTerms && (*subAssemblers)[i]->getQuadrature() == quad)
return dynamic_cast<FirstOrderAssembler*>((*subAssemblers)[i]);
}
// check if all terms are pw_const
bool pwConst = true;
for (unsigned int i = 0; i < opTerms.size(); i++) {
if (!(opTerms[i])->isPWConst()) {
pwConst = false;
break;
}
}
// create new assembler
if (!optimized) {
newAssembler =
(type == GRD_PSI) ?
dynamic_cast<FirstOrderAssembler*>(new Stand10(op, assembler, quad)) :
dynamic_cast<FirstOrderAssembler*>(new Stand01(op, assembler, quad));
} else {
if (pwConst) {
newAssembler =
(type == GRD_PSI) ?
dynamic_cast<FirstOrderAssembler*>(new Pre10(op, assembler, quad)) :
dynamic_cast<FirstOrderAssembler*>(new Pre01(op, assembler, quad));
} else {
newAssembler =
(type == GRD_PSI) ?
dynamic_cast<FirstOrderAssembler*>(new Quad10(op, assembler, quad)) :
dynamic_cast<FirstOrderAssembler*>(new Quad01(op, assembler, quad));
}
}
subAssemblers->push_back(newAssembler);
return newAssembler;
Stand10::Stand10(Operator *op, Assembler *assembler, Quadrature *quad)
: FirstOrderAssembler(op, assembler, quad, false, GRD_PSI)
name = "standard first order assembler";
psi = rowFeSpace->getBasisFcts();
phi = colFeSpace->getBasisFcts();
void Stand10::calculateElementMatrix(const ElInfo *elInfo, ElementMatrix& mat)

Thomas Witkowski
committed
mtl::dense_vector<double> grdPsi(dim + 1, 0.0);
int nPoints = quadrature->getNumPoints();
Lb.resize(nPoints);
std::vector<double> phival(nCol);

Thomas Witkowski
committed
for (int iq = 0; iq < nPoints; iq++) {
Lb[iq].change_dim(dim + 1);
Lb[iq] = 0.0;
}
for (unsigned int i = 0; i < terms.size(); i++)
(static_cast<FirstOrderTerm*>((terms[i])))->getLb(elInfo, Lb);
for (int iq = 0; iq < nPoints; iq++) {
Lb[iq] *= elInfo->getDet();
for (int i = 0; i < nCol; i++)
phival[i] = (*(phi->getPhi(i)))(quadrature->getLambda(iq));
for (int i = 0; i < nRow; i++) {
(*(psi->getGrdPhi(i)))(quadrature->getLambda(iq), grdPsi);
for (int j = 0; j < nCol; j++)

Thomas Witkowski
committed
mat[i][j] += quadrature->getWeight(iq) * phival[j] * dot(Lb[iq], grdPsi);
}
}
}
void Stand10::calculateElementVector(const ElInfo *elInfo, ElementVector& vec)

Thomas Witkowski
committed
mtl::dense_vector<double> grdPsi(dim + 1, 0.0);
int nPoints = quadrature->getNumPoints();
Lb.resize(nPoints);

Thomas Witkowski
committed
for (int iq = 0; iq < nPoints; iq++) {
Lb[iq].change_dim(dim + 1);
Lb[iq] = 0.0;
}
for (unsigned int i = 0; i < terms.size(); i++)
(static_cast<FirstOrderTerm*>((terms[i])))->getLb(elInfo, Lb);
for (int iq = 0; iq < nPoints; iq++) {
Lb[iq] *= elInfo->getDet();
for (int i = 0; i < nRow; i++) {
(*(psi->getGrdPhi(i)))(quadrature->getLambda(iq), grdPsi);

Thomas Witkowski
committed
vec[i] += quadrature->getWeight(iq) * dot(Lb[iq], grdPsi);
}
}
}
Quad10::Quad10(Operator *op, Assembler *assembler, Quadrature *quad)
: FirstOrderAssembler(op, assembler, quad, true, GRD_PSI)
{
name = "fast quadrature first order assembler";
}
void Quad10::calculateElementMatrix(const ElInfo *elInfo, ElementMatrix& mat)
{
if (firstCall) {

Thomas Witkowski
committed
const BasisFunction *basFcts = rowFeSpace->getBasisFcts();
psiFast = updateFastQuadrature(psiFast, basFcts, INIT_GRD_PHI);
basFcts = colFeSpace->getBasisFcts();
phiFast = updateFastQuadrature(phiFast, basFcts, INIT_PHI);
firstCall = false;
}
int nPoints = quadrature->getNumPoints();
Lb.resize(nPoints);

Thomas Witkowski
committed
for (int iq = 0; iq < nPoints; iq++) {
Lb[iq].change_dim(dim + 1);
Lb[iq] = 0.0;
}

Thomas Witkowski
committed
for (unsigned int i = 0; i < terms.size(); i++)
(static_cast<FirstOrderTerm*>((terms[i])))->getLb(elInfo, Lb);
const mtl::dense2D<double>& phi = phiFast->getPhi();
for (int iq = 0; iq < nPoints; iq++) {
Lb[iq] *= elInfo->getDet();

Thomas Witkowski
committed
const vector<mtl::dense_vector<double> >& grdPsi = psiFast->getGradient(iq);
double factor = quadrature->getWeight(iq);
for (int j = 0; j < nCol; j++)

Thomas Witkowski
committed
mat[i][j] += factor * phi[iq][j] * dot(Lb[iq], grdPsi[i]);
void Quad10::calculateElementVector(const ElInfo *elInfo, ElementVector& vec)
{
if (firstCall) {

Thomas Witkowski
committed
const BasisFunction *basFcts = rowFeSpace->getBasisFcts();
psiFast = updateFastQuadrature(psiFast, basFcts, INIT_GRD_PHI);
basFcts = colFeSpace->getBasisFcts();
phiFast = updateFastQuadrature(phiFast, basFcts, INIT_PHI);
firstCall = false;
}
int nPoints = quadrature->getNumPoints();
Lb.resize(nPoints);

Thomas Witkowski
committed
for (int iq = 0; iq < nPoints; iq++) {
Lb[iq].change_dim(dim + 1);
Lb[iq] = 0.0;
}

Thomas Witkowski
committed
for (unsigned int i = 0; i < terms.size(); i++)
(static_cast<FirstOrderTerm*>((terms[i])))->getLb(elInfo, Lb);
for (int iq = 0; iq < nPoints; iq++) {
Lb[iq] *= elInfo->getDet();

Thomas Witkowski
committed
const vector<mtl::dense_vector<double> >& grdPsi = psiFast->getGradient(iq);

Thomas Witkowski
committed
vec[i] += quadrature->getWeight(iq) * dot(Lb[iq], grdPsi[i]);
Pre10::Pre10(Operator *op, Assembler *assembler, Quadrature *quad)
: FirstOrderAssembler(op, assembler, quad, true, GRD_PSI)
{
name = "precalculated first order assembler";
void Pre10::calculateElementMatrix(const ElInfo *elInfo, ElementMatrix& mat)
{
const int *k;
const double *values;
if (firstCall) {
q10 = Q10PsiPhi::provideQ10PsiPhi(rowFeSpace->getBasisFcts(),
colFeSpace->getBasisFcts(),
quadrature);
q1 = Q1Psi::provideQ1Psi(rowFeSpace->getBasisFcts(), quadrature);
firstCall = false;
}
const int **nEntries = q10->getNumberEntries();
// Do not need do resize Lb, because it's size is always at least one.

Thomas Witkowski
committed
Lb[0] = 0.0;

Thomas Witkowski
committed
for (unsigned int i = 0; i < terms.size(); i++)
(static_cast<FirstOrderTerm*>((terms[i])))->getLb(elInfo, Lb);
Lb[0] *= elInfo->getDet();
for (int i = 0; i < nRow; i++) {
for (int j = 0; j < nCol; j++) {
k = q10->getKVec(i, j);
values = q10->getValVec(i, j);
double val = 0.0;
for (int m = 0; m < nEntries[i][j]; m++)
val += values[m] * Lb[0][k[m]];
mat[i][j] += val;
}
}
}

Thomas Witkowski
committed
Stand01::Stand01(Operator *op, Assembler *assembler, Quadrature *quad)
: FirstOrderAssembler(op, assembler, quad, false, GRD_PHI)

Thomas Witkowski
committed
FUNCNAME("Stand01::Stand01()");
TEST_EXIT_DBG(dim > 0)("Should not happen!\n");
grdPhi.resize(nCol);
for (int i = 0; i < nCol; i++)
grdPhi[i].change_dim(dim + 1);
psi = rowFeSpace->getBasisFcts();
phi = colFeSpace->getBasisFcts();

Thomas Witkowski
committed
void Stand01::calculateElementMatrix(const ElInfo *elInfo, ElementMatrix& mat)
{
int nPoints = quadrature->getNumPoints();
Lb.resize(nPoints);

Thomas Witkowski
committed
for (int iq = 0; iq < nPoints; iq++) {
Lb[iq].change_dim(dim + 1);
Lb[iq] = 0.0;
}

Thomas Witkowski
committed
for (int i = 0; i < static_cast<int>(terms.size()); i++)
(static_cast<FirstOrderTerm*>((terms[i])))->getLb(elInfo, Lb);
for (int iq = 0; iq < nPoints; iq++) {
Lb[iq] *= elInfo->getDet();
for (int i = 0; i < nCol; i++)
(*(phi->getGrdPhi(i)))(quadrature->getLambda(iq), grdPhi[i]);
for (int i = 0; i < nRow; i++) {
double psival = (*(psi->getPhi(i)))(quadrature->getLambda(iq));
for (int j = 0; j < nCol; j++)

Thomas Witkowski
committed
mat[i][j] += quadrature->getWeight(iq) * psival * dot(Lb[iq], grdPhi[j]);
}
}
}
Quad01::Quad01(Operator *op, Assembler *assembler, Quadrature *quad)
: FirstOrderAssembler(op, assembler, quad, true, GRD_PHI)
{
name = "fast quadrature first order assembler";
}
void Quad01::calculateElementMatrix(const ElInfo *elInfo, ElementMatrix& mat)
{
if (firstCall) {
const BasisFunction *basFcts = rowFeSpace->getBasisFcts();
psiFast = updateFastQuadrature(psiFast, basFcts, INIT_PHI);
basFcts = colFeSpace->getBasisFcts();
phiFast = updateFastQuadrature(phiFast, basFcts, INIT_GRD_PHI);
firstCall = false;
}
int nPoints = quadrature->getNumPoints();
Lb.resize(nPoints);

Thomas Witkowski
committed
for (int iq = 0; iq < nPoints; iq++) {
Lb[iq].change_dim(dim + 1);
Lb[iq] = 0.0;
}

Thomas Witkowski
committed
for (int i = 0; i < static_cast<int>(terms.size()); i++)
(static_cast<FirstOrderTerm*>((terms[i])))->getLb(elInfo, Lb);

Thomas Witkowski
committed
const mtl::dense2D<double>& psi = psiFast->getPhi();

Thomas Witkowski
committed
mtl::dense2D<double> facMat(nPoints, nCol);
for (int iq = 0; iq < nPoints; iq++) {

Thomas Witkowski
committed
double weight = quadrature->getWeight(iq);
mtl::dense_vector<double>& Lb_iq = Lb[iq];
const vector<mtl::dense_vector<double> >& grdPsi = phiFast->getGradient(iq);

Thomas Witkowski
committed
Lb_iq *= elInfo->getDet();
for (int i = 0; i < nCol; i++)
facMat[iq][i] = weight * dot(Lb_iq, grdPsi[i]);

Thomas Witkowski
committed
mat += trans(psi) * facMat;
Pre01::Pre01(Operator *op, Assembler *assembler, Quadrature *quad)
: FirstOrderAssembler(op, assembler, quad, true, GRD_PHI)
{
name = "precalculated first order assembler";
}
void Pre01::calculateElementMatrix(const ElInfo *elInfo, ElementMatrix& mat)
{
const int *l;
const double *values;
if (firstCall) {
q01 = Q01PsiPhi::provideQ01PsiPhi(rowFeSpace->getBasisFcts(),
colFeSpace->getBasisFcts(),
quadrature);
q1 = Q1Psi::provideQ1Psi(rowFeSpace->getBasisFcts(), quadrature);
firstCall = false;
}
const int **nEntries = q01->getNumberEntries();
// Do not need to resize Lb, because it's size is always at least one!

Thomas Witkowski
committed
Lb[0] = 0.0;

Thomas Witkowski
committed
for (int i = 0; i < static_cast<int>( terms.size()); i++)
(static_cast<FirstOrderTerm*>((terms[i])))->getLb(elInfo, Lb);
Lb[0] *= elInfo->getDet();
for (int i = 0; i < nRow; i++) {
for (int j = 0; j < nCol; j++) {
l = q01->getLVec(i, j);
values = q01->getValVec(i, j);
double val = 0.0;
for (int m = 0; m < nEntries[i][j]; m++) {
val += values[m] * Lb[0][l[m]];
}
mat[i][j] += val;
}
}
}
void Pre10::calculateElementVector(const ElInfo *elInfo, ElementVector& vec)
{
const int *k;
const double *values;
if (firstCall) {
q10 = Q10PsiPhi::provideQ10PsiPhi(rowFeSpace->getBasisFcts(),
colFeSpace->getBasisFcts(),
quadrature);
q1 = Q1Psi::provideQ1Psi(rowFeSpace->getBasisFcts(), quadrature);
firstCall = false;
}
const int *nEntries = q1->getNumberEntries();
// Do not need to resize Lb, because it's size is always at least one!

Thomas Witkowski
committed
Lb[0] = 0.0;

Thomas Witkowski
committed
for (int i = 0; i < static_cast<int>(terms.size()); i++)
(static_cast<FirstOrderTerm*>(terms[i]))->getLb(elInfo, Lb);
Lb[0] *= elInfo->getDet();
for (int i = 0; i < nRow; i++) {
k = q1->getKVec(i);
values = q1->getValVec(i);
double val = 0.0;
for (int m = 0; m < nEntries[i]; m++) {
val += values[m] * Lb[0][k[m]];
}
vec[i] += val;
}
}
}