#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(); } }