#include #include #include #include "Assembler.h" #include "Operator.h" #include "Element.h" #include "QPsiPhi.h" #include "DOFVector.h" #include "OpenMP.h" 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(nRow, nCol), elementVector(nRow), lastMatEl(NULL), lastVecEl(NULL), lastTraverseId(-1) {} Assembler::~Assembler() {} 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) set_to_zero(elementMatrix); lastMatEl = el; } else { if (rememberElMat) { userMat += factor * elementMatrix; 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 += factor * elementMatrix; } 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) set_to_zero(elementMatrix); lastMatEl = el; } else { if (rememberElMat) { userMat += factor * elementMatrix; return; } } ElementMatrix& mat = rememberElMat ? elementMatrix : userMat; TEST_EXIT(zeroOrderAssembler)("Not yet implemented for not zero order assembler!\n"); if (secondOrderAssembler) secondOrderAssembler->calculateElementMatrix(smallElInfo, mat); if (firstOrderAssemblerGrdPsi) firstOrderAssemblerGrdPsi->calculateElementMatrix(smallElInfo, mat); if (firstOrderAssemblerGrdPhi) firstOrderAssemblerGrdPhi->calculateElementMatrix(smallElInfo, mat); if (zeroOrderAssembler) zeroOrderAssembler->calculateElementMatrix(smallElInfo, mat); const mtl::dense2D& m = smallElInfo->getSubElemCoordsMat(); ElementMatrix tmpMat(nRow, nRow); tmpMat = m * mat; mat = tmpMat; if (rememberElMat) userMat += factor * elementMatrix; } 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) set_to_zero(elementVector); lastVecEl = el; } else { if (rememberElVec) { userVec += factor * elementVector; return; } } ElementVector& vec = rememberElVec ? elementVector : userVec; if (operat->uhOld && remember) { matVecAssemble(elInfo, vec); if (rememberElVec) { userVec += factor * elementVector; } return; } if (firstOrderAssemblerGrdPsi) firstOrderAssemblerGrdPsi->calculateElementVector(elInfo, vec); if (zeroOrderAssembler) zeroOrderAssembler->calculateElementVector(elInfo, vec); if (rememberElVec) userVec += factor * elementVector; } 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) set_to_zero(elementVector); lastVecEl = el; } else { if (rememberElVec) { userVec += factor * elementVector; 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) { userVec += factor * elementVector; } 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, elementMatrix); 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); const mtl::dense2D& 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, elementMatrix); } 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::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(); } }