-
Thomas Witkowski authoredThomas Witkowski authored
Assembler.cc 13.14 KiB
#include "Assembler.h"
#include "Operator.h"
#include "Element.h"
#include "QPsiPhi.h"
#include "ElementMatrix.h"
#include "ElementVector.h"
#include "DOFVector.h"
#include "OpenMP.h"
#include <vector>
#include <algorithm>
namespace AMDiS {
Assembler::Assembler(Operator *op,
const FiniteElemSpace *row,
const FiniteElemSpace *col)
: operat(op),
rowFESpace(row),
colFESpace(col ? col : row),
nRow(rowFESpace->getBasisFcts()->getNumber()),
nCol(colFESpace->getBasisFcts()->getNumber()),
remember(true),
rememberElMat(false),
rememberElVec(false),
elementMatrix(NULL),
elementVector(NULL),
lastMatEl(NULL),
lastVecEl(NULL),
lastTraverseId(-1)
{
elementMatrix = NEW ElementMatrix(nRow, nCol);
elementVector = NEW ElementVector(nRow);
}
Assembler::~Assembler()
{
if (elementMatrix)
DELETE elementMatrix;
if (elementVector)
DELETE elementVector;
}
void Assembler::calculateElementMatrix(const ElInfo *elInfo,
ElementMatrix *userMat,
double factor)
{
FUNCNAME("Assembler::calculateElementMatrix()");
if (remember && (factor != 1.0 || operat->uhOld)) {
rememberElMat = true;
}
Element *el = elInfo->getElement();
if ((el != lastMatEl && el != lastVecEl) || !operat->isOptimized()) {
initElement(elInfo);
}
if (el != lastMatEl || !operat->isOptimized()) {
if (rememberElMat) {
elementMatrix->set(0.0);
}
lastMatEl = el;
} else {
if (rememberElMat) {
axpy(factor, *elementMatrix, *userMat);
return;
}
}
ElementMatrix *mat = rememberElMat ? elementMatrix : userMat;
if (secondOrderAssembler)
secondOrderAssembler->calculateElementMatrix(elInfo, mat);
if (firstOrderAssemblerGrdPsi)
firstOrderAssemblerGrdPsi->calculateElementMatrix(elInfo, mat);
if (firstOrderAssemblerGrdPhi)
firstOrderAssemblerGrdPhi->calculateElementMatrix(elInfo, mat);
if (zeroOrderAssembler)
zeroOrderAssembler->calculateElementMatrix(elInfo, mat);
if (rememberElMat && userMat) {
axpy(factor, *elementMatrix, *userMat);
}
}
void Assembler::calculateElementMatrix(const ElInfo *rowElInfo,
const ElInfo *colElInfo,
const ElInfo *smallElInfo,
const ElInfo *largeElInfo,
ElementMatrix *userMat,
double factor)
{
FUNCNAME("Assembler::calculateElementMatrix()");
if (remember && ((factor != 1.0) || (operat->uhOld))) {
rememberElMat = true;
}
Element *el = smallElInfo->getElement();
lastVecEl = lastMatEl = NULL;
if ((el != lastMatEl && el != lastVecEl) || !operat->isOptimized()) {
initElement(smallElInfo, largeElInfo);
}
if (el != lastMatEl || !operat->isOptimized()) {
if (rememberElMat) {
elementMatrix->set(0.0);
}
lastMatEl = el;
} else {
if (rememberElMat) {
axpy(factor, *elementMatrix, *userMat);
return;
}
}
ElementMatrix *mat = rememberElMat ? elementMatrix : userMat;
if (secondOrderAssembler)
secondOrderAssembler->calculateElementMatrix(rowElInfo, colElInfo,
smallElInfo, largeElInfo, mat);
if (firstOrderAssemblerGrdPsi)
firstOrderAssemblerGrdPsi->calculateElementMatrix(rowElInfo, colElInfo,
smallElInfo, largeElInfo, mat);
if (firstOrderAssemblerGrdPhi)
firstOrderAssemblerGrdPhi->calculateElementMatrix(rowElInfo, colElInfo,
smallElInfo, largeElInfo, mat);
if (zeroOrderAssembler)
zeroOrderAssembler->calculateElementMatrix(rowElInfo, colElInfo,
smallElInfo, largeElInfo, mat);
if (rememberElMat && userMat) {
axpy(factor, *elementMatrix, *userMat);
}
}
void Assembler::calculateElementVector(const ElInfo *elInfo,
ElementVector *userVec,
double factor)
{
FUNCNAME("Assembler::calculateElementVector()");
if (remember && factor != 1.0) {
rememberElVec = true;
}
Element *el = elInfo->getElement();
if ((el != lastMatEl && el != lastVecEl) || !operat->isOptimized()) {
initElement(elInfo);
}
if (el != lastVecEl || !operat->isOptimized()) {
if (rememberElVec) {
elementVector->set(0.0);
}
lastVecEl = el;
} else {
if (rememberElVec) {
axpy(factor, *elementVector, *userVec);
return;
}
}
ElementVector *vec = rememberElVec ? elementVector : userVec;
if (operat->uhOld && remember) {
matVecAssemble(elInfo, vec);
if (rememberElVec) {
axpy(factor, *elementVector, *userVec);
}
return;
}
if (firstOrderAssemblerGrdPsi) {
firstOrderAssemblerGrdPsi->calculateElementVector(elInfo, vec);
}
if (zeroOrderAssembler) {
zeroOrderAssembler->calculateElementVector(elInfo, vec);
}
if (rememberElVec) {
axpy(factor, *elementVector, *userVec);
}
}
void Assembler::calculateElementVector(const ElInfo *mainElInfo,
const ElInfo *auxElInfo,
const ElInfo *smallElInfo,
const ElInfo *largeElInfo,
ElementVector *userVec,
double factor)
{
FUNCNAME("Assembler::calculateElementVector()");
if (remember && factor != 1.0) {
rememberElVec = true;
}
Element *el = mainElInfo->getElement();
if ((el != lastMatEl && el != lastVecEl) || !operat->isOptimized()) {
initElement(auxElInfo);
}
if (el != lastVecEl || !operat->isOptimized()) {
if (rememberElVec) {
elementVector->set(0.0);
}
lastVecEl = el;
} else {
if (rememberElVec) {
axpy(factor, *elementVector, *userVec);
return;
}
}
ElementVector *vec = rememberElVec ? elementVector : userVec;
if (operat->uhOld && remember) {
if (smallElInfo->getLevel() == largeElInfo->getLevel()) {
matVecAssemble(auxElInfo, vec);
} else {
matVecAssemble(mainElInfo, auxElInfo, smallElInfo, largeElInfo, vec);
}
if (rememberElVec) {
axpy(factor, *elementVector, *userVec);
}
return;
}
ERROR_EXIT("Not yet implemented!\n");
// if (firstOrderAssemblerGrdPsi) {
// firstOrderAssemblerGrdPsi->calculateElementVector(elInfo, vec);
// }
// if (zeroOrderAssembler) {
// zeroOrderAssembler->calculateElementVector(elInfo, vec);
// }
// if (rememberElVec) {
// axpy(factor, *elementVector, *userVec);
// }
}
void Assembler::matVecAssemble(const ElInfo *elInfo, ElementVector *vec)
{
FUNCNAME("Assembler::matVecAssemble()");
Element *el = elInfo->getElement();
const BasisFunction *basFcts = rowFESpace->getBasisFcts();
int nBasFcts = basFcts->getNumber();
double *uhOldLoc = new double[nBasFcts];
operat->uhOld->getLocalVector(el, uhOldLoc);
if (el != lastMatEl) {
calculateElementMatrix(elInfo, NULL);
}
for (int i = 0; i < nBasFcts; i++) {
double val = 0.0;
for (int j = 0; j < nBasFcts; j++) {
val += (*elementMatrix)[i][j] * uhOldLoc[j];
}
(*vec)[i] += val;
}
delete [] uhOldLoc;
}
void Assembler::matVecAssemble(const ElInfo *mainElInfo, const ElInfo *auxElInfo,
const ElInfo *smallElInfo, const ElInfo *largeElInfo,
ElementVector *vec)
{
FUNCNAME("Assembler::matVecAssemble()");
TEST_EXIT(rowFESpace->getBasisFcts() == colFESpace->getBasisFcts())
("Works only for equal basis functions for different components!\n");
TEST_EXIT(operat->uhOld->getFESpace()->getMesh() == auxElInfo->getMesh())
("Da stimmt was nicht!\n");
Element *mainEl = mainElInfo->getElement();
Element *auxEl = auxElInfo->getElement();
const BasisFunction *basFcts = rowFESpace->getBasisFcts();
int nBasFcts = basFcts->getNumber();
double *uhOldLoc = new double[nBasFcts];
double *uhOldLoc2 = new double[nBasFcts];
operat->uhOld->getLocalVector(auxEl, uhOldLoc);
DimMat<double> *m = smallElInfo->getSubElemCoordsMat();
for (int i = 0; i < nBasFcts; i++) {
uhOldLoc2[i] = 0.0;
for (int j = 0; j < nBasFcts; j++) {
uhOldLoc2[i] += (*m)[j][i] * uhOldLoc[i];
}
}
if (mainEl != lastMatEl) {
calculateElementMatrix(mainElInfo, auxElInfo, smallElInfo, largeElInfo, NULL);
}
for (int i = 0; i < nBasFcts; i++) {
double val = 0.0;
for (int j = 0; j < nBasFcts; j++) {
val += (*elementMatrix)[i][j] * uhOldLoc2[j];
}
(*vec)[i] += val;
}
delete [] uhOldLoc;
delete [] uhOldLoc2;
}
void Assembler::initElement(const ElInfo *smallElInfo,
const ElInfo *largeElInfo,
Quadrature *quad)
{
if (secondOrderAssembler)
secondOrderAssembler->initElement(smallElInfo, largeElInfo, quad);
if (firstOrderAssemblerGrdPsi)
firstOrderAssemblerGrdPsi->initElement(smallElInfo, largeElInfo, quad);
if (firstOrderAssemblerGrdPhi)
firstOrderAssemblerGrdPhi->initElement(smallElInfo, largeElInfo, quad);
if (zeroOrderAssembler)
zeroOrderAssembler->initElement(smallElInfo, largeElInfo, quad);
}
void Assembler::initElementMatrix(ElementMatrix *elMat,
const ElInfo *rowElInfo,
const ElInfo *colElInfo)
{
TEST_EXIT_DBG(elMat)("No ElementMatrix!\n");
elMat->set(0.0);
rowFESpace->getBasisFcts()->getLocalIndicesVec(rowElInfo->getElement(),
rowFESpace->getAdmin(),
&(elMat->rowIndices));
if (rowFESpace == colFESpace) {
elMat->colIndices = elMat->rowIndices;
} else {
if (colElInfo) {
colFESpace->getBasisFcts()->getLocalIndicesVec(colElInfo->getElement(),
colFESpace->getAdmin(),
&(elMat->colIndices));
} else {
// If there is no colElInfo pointer, use rowElInfo the get the indices.
colFESpace->getBasisFcts()->getLocalIndicesVec(rowElInfo->getElement(),
colFESpace->getAdmin(),
&(elMat->colIndices));
}
}
}
void Assembler::initElementVector(ElementVector *elVec, const ElInfo *elInfo)
{
TEST_EXIT_DBG(elVec)("No ElementVector!\n");
elVec->set(0.0);
rowFESpace->getBasisFcts()->getLocalIndicesVec(elInfo->getElement(),
rowFESpace->getAdmin(),
&(elVec->dofIndices));
}
void Assembler::checkQuadratures()
{
if (secondOrderAssembler) {
// create quadrature
if (!secondOrderAssembler->getQuadrature()) {
int dim = rowFESpace->getMesh()->getDim();
int degree = operat->getQuadratureDegree(2);
Quadrature *quadrature = Quadrature::provideQuadrature(dim, degree);
secondOrderAssembler->setQuadrature(quadrature);
}
}
if (firstOrderAssemblerGrdPsi) {
// create quadrature
if (!firstOrderAssemblerGrdPsi->getQuadrature()) {
int dim = rowFESpace->getMesh()->getDim();
int degree = operat->getQuadratureDegree(1, GRD_PSI);
Quadrature *quadrature = Quadrature::provideQuadrature(dim, degree);
firstOrderAssemblerGrdPsi->setQuadrature(quadrature);
}
}
if (firstOrderAssemblerGrdPhi) {
// create quadrature
if (!firstOrderAssemblerGrdPhi->getQuadrature()) {
int dim = rowFESpace->getMesh()->getDim();
int degree = operat->getQuadratureDegree(1, GRD_PHI);
Quadrature *quadrature = Quadrature::provideQuadrature(dim, degree);
firstOrderAssemblerGrdPhi->setQuadrature(quadrature);
}
}
if (zeroOrderAssembler) {
// create quadrature
if (!zeroOrderAssembler->getQuadrature()) {
int dim = rowFESpace->getMesh()->getDim();
int degree = operat->getQuadratureDegree(0);
Quadrature *quadrature = Quadrature::provideQuadrature(dim, degree);
zeroOrderAssembler->setQuadrature(quadrature);
}
}
}
void Assembler::finishAssembling()
{
lastVecEl = NULL;
lastMatEl = NULL;
}
OptimizedAssembler::OptimizedAssembler(Operator *op,
Quadrature *quad2,
Quadrature *quad1GrdPsi,
Quadrature *quad1GrdPhi,
Quadrature *quad0,
const FiniteElemSpace *row,
const FiniteElemSpace *col)
: Assembler(op, row, col)
{
bool opt = (row == col);
// create sub assemblers
secondOrderAssembler =
SecondOrderAssembler::getSubAssembler(op, this, quad2, opt);
firstOrderAssemblerGrdPsi =
FirstOrderAssembler::getSubAssembler(op, this, quad1GrdPsi, GRD_PSI, opt);
firstOrderAssemblerGrdPhi =
FirstOrderAssembler::getSubAssembler(op, this, quad1GrdPhi, GRD_PHI, opt);
zeroOrderAssembler =
ZeroOrderAssembler::getSubAssembler(op, this, quad0, opt);
checkQuadratures();
}
StandardAssembler::StandardAssembler(Operator *op,
Quadrature *quad2,
Quadrature *quad1GrdPsi,
Quadrature *quad1GrdPhi,
Quadrature *quad0,
const FiniteElemSpace *row,
const FiniteElemSpace *col)
: Assembler(op, row, col)
{
remember = false;
// create sub assemblers
secondOrderAssembler =
SecondOrderAssembler::getSubAssembler(op, this, quad2, false);
firstOrderAssemblerGrdPsi =
FirstOrderAssembler::getSubAssembler(op, this, quad1GrdPsi, GRD_PSI, false);
firstOrderAssemblerGrdPhi =
FirstOrderAssembler::getSubAssembler(op, this, quad1GrdPhi, GRD_PHI, false);
zeroOrderAssembler =
ZeroOrderAssembler::getSubAssembler(op, this, quad0, false);
checkQuadratures();
}
}