#include #include #include "Assembler.h" #include "SecondOrderAssembler.h" #include "Operator.h" #include "QPsiPhi.h" #include "FiniteElemSpace.h" #include "Quadrature.h" #include "DOFVector.h" #include "OpenMP.h" namespace AMDiS { std::vector SecondOrderAssembler::optimizedSubAssemblers; std::vector SecondOrderAssembler::standardSubAssemblers; SecondOrderAssembler::SecondOrderAssembler(Operator *op, Assembler *assembler, Quadrature *quad, bool optimized) : SubAssembler(op, assembler, quad, 2, optimized) {} SecondOrderAssembler* SecondOrderAssembler::getSubAssembler(Operator* op, Assembler *assembler, Quadrature *quad, bool optimized) { int myRank = omp_get_thread_num(); // check if a assembler is needed at all if (op->secondOrder[myRank].size() == 0) return NULL; SecondOrderAssembler *newAssembler; std::vector *subAssemblers = optimized ? &optimizedSubAssemblers : &standardSubAssemblers; std::vector opTerms = op->zeroOrder[myRank]; sort(opTerms.begin(), opTerms.end()); // check if a new assembler is needed for (int i = 0; i < static_cast(subAssemblers->size()); i++) { std::vector assTerms = *((*subAssemblers)[i]->getTerms()); sort(assTerms.begin(), assTerms.end()); if (opTerms == assTerms && (*subAssemblers)[i]->getQuadrature() == quad) return dynamic_cast((*subAssemblers)[i]); } // check if all terms are pw_const bool pwConst = true; for (int i = 0; i < static_cast(op->secondOrder[myRank].size()); i++) { if (!op->secondOrder[myRank][i]->isPWConst()) { pwConst = false; break; } } // create new assembler if (!optimized) { newAssembler = new Stand2(op, assembler, quad); } else { if (pwConst) { newAssembler = new Pre2(op, assembler, quad); } else { newAssembler = new Quad2(op, assembler, quad); } } subAssemblers->push_back(newAssembler); return newAssembler; } Pre2::Pre2(Operator *op, Assembler *assembler, Quadrature *quad) : SecondOrderAssembler(op, assembler, quad, true) { name = "precalculated second order assembler"; q11 = Q11PsiPhi::provideQ11PsiPhi(rowFeSpace->getBasisFcts(), colFeSpace->getBasisFcts(), quadrature); tmpLALt.resize(omp_get_overall_max_threads()); for (int i = 0; i < omp_get_overall_max_threads(); i++) { tmpLALt[i] = new DimMat*; *(tmpLALt[i]) = new DimMat(dim, NO_INIT); } } Pre2::~Pre2() { for (int i = 0; i < static_cast(tmpLALt.size()); i++) { delete *(tmpLALt[i]); delete tmpLALt[i]; } } void Pre2::calculateElementMatrix(const ElInfo *elInfo, ElementMatrix& mat) { const int **nEntries; const int *k, *l; const double *values; int myRank = omp_get_thread_num(); DimMat **LALt = tmpLALt[0]; DimMat &tmpMat = *LALt[0]; tmpMat.set(0.0); for (int i = 0; i < static_cast(terms[myRank].size()); i++) { (static_cast(terms[myRank][i]))->getLALt(elInfo, 1, LALt); } tmpMat *= elInfo->getDet(); nEntries = q11->getNumberEntries(); if (symmetric) { TEST_EXIT_DBG(nCol == nRow)("nCol != nRow, but symmetric assembling!\n"); for (int i = 0; i < nRow; i++) { k = q11->getKVec(i, i); l = q11->getLVec(i, i); values = q11->getValVec(i, i); double val = 0.0; for (int m = 0; m < nEntries[i][i]; m++) { val += values[m] * tmpMat[k[m]][l[m]]; } mat[i][i] += val; for (int j = i + 1; j < nCol; j++) { k = q11->getKVec(i, j); l = q11->getLVec(i, j); values = q11->getValVec(i, j); val = 0.0; for (int m = 0; m < nEntries[i][j]; m++) { val += values[m] * tmpMat[k[m]][l[m]]; } mat[i][j] += val; mat[j][i] += val; } } } else { /* A not symmetric or psi != phi */ for (int i = 0; i < nRow; i++) { for (int j = 0; j < nCol; j++) { k = q11->getKVec(i, j); l = q11->getLVec(i, j); values = q11->getValVec(i, j); double val = 0.0; for (int m = 0; m < nEntries[i][j]; m++) { val += values[m] * tmpMat[k[m]][l[m]]; } mat[i][j] += val; } } } } Quad2::Quad2(Operator *op, Assembler *assembler, Quadrature *quad) : SecondOrderAssembler(op, assembler, quad, true) { name = "fast quadrature second order assembler"; tmpVec.resize(omp_get_overall_max_threads()); tmpLALt.resize(omp_get_overall_max_threads()); } Quad2::~Quad2() { if (!firstCall) { int nPoints = quadrature->getNumPoints(); for (int i = 0; i < static_cast(tmpLALt.size()); i++) { for (int j = 0; j < nPoints; j++) delete tmpLALt[i][j]; delete [] tmpLALt[i]; } } } void Quad2::calculateElementMatrix(const ElInfo *elInfo, ElementMatrix& mat) { int nPoints = quadrature->getNumPoints(); int myRank = omp_get_thread_num(); if (firstCall) { tmpVec[myRank] = new DimVec(dim, NO_INIT); tmpLALt[myRank] = new DimMat*[nPoints]; for (int j = 0; j < nPoints; j++) tmpLALt[myRank][j] = new DimMat(dim, NO_INIT); #ifdef _OPENMP #pragma omp critical #endif { psiFast = updateFastQuadrature(psiFast, rowFeSpace->getBasisFcts(), INIT_GRD_PHI); phiFast = updateFastQuadrature(phiFast, rowFeSpace->getBasisFcts(), INIT_GRD_PHI); } firstCall = false; } DimMat **LALt = tmpLALt[myRank]; DimVec &dimVec = *(tmpVec[myRank]); for (int i = 0; i < nPoints; i++) LALt[i]->set(0.0); for (int i = 0; i < static_cast(terms[myRank].size()); i++) (static_cast(terms[myRank][i]))->getLALt(elInfo, nPoints, LALt); VectorOfFixVecs< DimVec > *grdPsi, *grdPhi; if (symmetric) { // === Symmetric assembling. === TEST_EXIT_DBG(nCol == nRow)("nCol != nRow, but symmetric assembling!\n"); for (int iq = 0; iq < nPoints; iq++) { (*LALt[iq]) *= elInfo->getDet(); grdPsi = psiFast->getGradient(iq); grdPhi = phiFast->getGradient(iq); for (int i = 0; i < nCol; i++) { amv(quadrature->getWeight(iq), (*LALt[iq]), (*grdPhi)[i], dimVec); mat[i][i] += (*grdPsi)[i] * dimVec; for (int j = i + 1; j < nRow; j++) { double tmp = (*grdPhi)[j] * dimVec; mat[i][j] += tmp; mat[j][i] += tmp; } } } } else { // === Non symmetric assembling. === for (int iq = 0; iq < nPoints; iq++) { (*LALt[iq]) *= elInfo->getDet(); grdPsi = psiFast->getGradient(iq); grdPhi = phiFast->getGradient(iq); for (int i = 0; i < nRow; i++) for (int j = 0; j < nCol; j++) mat[i][j] += quadrature->getWeight(iq) * xAy((*grdPsi)[i], (*LALt[iq]), (*grdPhi)[j]); } } } Stand2::Stand2(Operator *op, Assembler *assembler, Quadrature *quad) : SecondOrderAssembler(op, assembler, quad, false) { name = "standard second order assembler"; } void Stand2::calculateElementMatrix(const ElInfo *elInfo, ElementMatrix& mat) { DimVec grdPsi(dim, NO_INIT); VectorOfFixVecs > grdPhi(dim, nCol, NO_INIT); const BasisFunction *psi = rowFeSpace->getBasisFcts(); const BasisFunction *phi = colFeSpace->getBasisFcts(); int nPoints = quadrature->getNumPoints(); DimMat **LALt = new DimMat*[nPoints]; for (int iq = 0; iq < nPoints; iq++) { LALt[iq] = new DimMat(dim, NO_INIT); LALt[iq]->set(0.0); } int myRank = omp_get_thread_num(); for (int i = 0; i < static_cast(terms[myRank].size()); i++) (static_cast(terms[myRank][i]))->getLALt(elInfo, nPoints, LALt); if (symmetric) { TEST_EXIT_DBG(nCol == nRow)("nCol != nRow, but symmetric assembling!\n"); for (int iq = 0; iq < nPoints; iq++) { (*LALt[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++) { (*(psi->getGrdPhi(i)))(quadrature->getLambda(iq), grdPsi); mat[i][i] += quadrature->getWeight(iq) * (grdPsi * ((*LALt[iq]) * grdPhi[i])); for (int j = i + 1; j < nCol; j++) { double val = quadrature->getWeight(iq) * (grdPsi * ((*LALt[iq]) * grdPhi[j])); mat[i][j] += val; mat[j][i] += val; } } } } else { /* non symmetric assembling */ for (int iq = 0; iq < nPoints; iq++) { (*LALt[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++) { (*(psi->getGrdPhi(i)))(quadrature->getLambda(iq), grdPsi); for (int j = 0; j < nCol; j++) { mat[i][j] += quadrature->getWeight(iq) * (grdPsi * ((*LALt[iq]) * grdPhi[j])); } } } } for (int iq = 0; iq < nPoints; iq++) delete LALt[iq]; delete [] LALt; } }