// // 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 <boost/numeric/mtl/mtl.hpp> #include "DOFVector.h" #include "Traverse.h" #include "DualTraverse.h" #include "FixVec.h" namespace AMDiS { template<> void DOFVector<double>::coarseRestrict(RCNeighbourList& list, int n) { FUNCNAME("DOFVector<double>::coarseRestrict()"); switch (coarsenOperation) { case NO_OPERATION: return; break; case COARSE_RESTRICT: (const_cast<BasisFunction*>(feSpace->getBasisFcts()))->coarseRestr(this, &list, n); break; case COARSE_INTERPOL: TEST_EXIT_DBG(feSpace)("Should not happen!\n"); TEST_EXIT_DBG(feSpace->getBasisFcts())("Shoud not happen!\n"); (const_cast<BasisFunction*>(feSpace->getBasisFcts()))->coarseInter(this, &list, n); break; default: WARNING("Invalid coarsen operation \"%d\" in vector \"%s\"\n", coarsenOperation, this->name.c_str()); } } template<> void DOFVector<double>::refineInterpol(RCNeighbourList& list, int n) { (const_cast<BasisFunction*>(feSpace->getBasisFcts()))->refineInter(this, &list, n); } template<> void DOFVector<WorldVector<double> >::refineInterpol(RCNeighbourList& list, int n) { if (n < 1) return; Element *el = list.getElement(0); int n0 = feSpace->getAdmin()->getNumberOfPreDofs(VERTEX); DegreeOfFreedom dof0 = el->getDof(0, n0); DegreeOfFreedom dof1 = el->getDof(1, n0); DegreeOfFreedom dof_new = el->getChild(0)->getDof(feSpace->getMesh()->getDim(), n0); vec[dof_new] = vec[dof0]; vec[dof_new] += vec[dof1]; vec[dof_new] *= 0.5; } template<> const double& DOFVector<double>::evalAtPoint(WorldVector<double> &p, ElInfo *oldElInfo, double* values) const { FUNCNAME("DOFVector<double>::evalAtCoords()"); Mesh *mesh = feSpace->getMesh(); const BasisFunction *basFcts = feSpace->getBasisFcts(); int dim = mesh->getDim(); int nBasFcts = basFcts->getNumber(); DegreeOfFreedom *localIndices = new DegreeOfFreedom[nBasFcts]; DimVec<double> lambda(dim, NO_INIT); ElInfo *elInfo = mesh->createNewElInfo(); static double value = 0.0; bool inside = false; if (oldElInfo && oldElInfo->getMacroElement()) { inside = mesh->findElInfoAtPoint(p, elInfo, lambda, oldElInfo->getMacroElement(), NULL, NULL); delete oldElInfo; } else inside = mesh->findElInfoAtPoint(p, elInfo, lambda, NULL, NULL, NULL); if (oldElInfo) oldElInfo = elInfo; if (inside) { basFcts->getLocalIndices(elInfo->getElement(), feSpace->getAdmin(), localIndices); ElementVector uh(lambda.size()); for (int i = 0; i < lambda.size(); i++) uh[i] = operator[](localIndices[i]); value = basFcts->evalUh(lambda, uh); } else throw(std::runtime_error("Can not eval DOFVector at point p, because point is outside geometry.")); delete [] localIndices; if (oldElInfo == NULL) delete elInfo; if (values != NULL) *values = value; return value; }; template<> const WorldVector<double>& DOFVector<WorldVector<double> >::evalAtPoint(WorldVector<double> &p, ElInfo *oldElInfo, WorldVector<double>* values) const { FUNCNAME("DOFVector<double>::evalAtCoords()"); Mesh *mesh = feSpace->getMesh(); const BasisFunction *basFcts = feSpace->getBasisFcts(); int dim = mesh->getDim(); int nBasFcts = basFcts->getNumber(); DegreeOfFreedom *localIndices = new DegreeOfFreedom[nBasFcts]; DimVec<double> lambda(dim, NO_INIT); ElInfo *elInfo = mesh->createNewElInfo(); static WorldVector<double> Values(DEFAULT_VALUE, 0.0); WorldVector<double> *val = (NULL != values) ? values : &Values; bool inside = false; if (oldElInfo && oldElInfo->getMacroElement()) { inside = mesh->findElInfoAtPoint(p, elInfo, lambda, oldElInfo->getMacroElement(), NULL, NULL); delete oldElInfo; } else inside = mesh->findElInfoAtPoint(p, elInfo, lambda, NULL, NULL, NULL); if (oldElInfo) oldElInfo = elInfo; if (inside) { basFcts->getLocalIndices(elInfo->getElement(), feSpace->getAdmin(), localIndices); mtl::dense_vector<WorldVector<double> > uh(lambda.size()); for (int i = 0; i < lambda.size(); i++) uh[i] = operator[](localIndices[i]); basFcts->evalUh(lambda, uh, val); } else throw(std::runtime_error("Can not eval DOFVector at point p, because point is outside geometry.")); delete [] localIndices; if (oldElInfo == NULL) delete elInfo; return ((*val)); }; template<> double DOFVector<double>::IntOnBoundary(BoundaryType boundaryType, Quadrature* q) const { FUNCNAME("DOFVector<T>::IntOnBoundary()"); Mesh* mesh = this->feSpace->getMesh(); int dim = mesh->getDim(); if (!q) { int deg = 2 * this->feSpace->getBasisFcts()->getDegree(); q = Quadrature::provideQuadrature(dim - 1, deg); } else { TEST_EXIT(q->getDim() == dim-1) ("Provided quadrature has wrong dimension for surfaceQuadrature!\n"); } // create barycentric coords for each vertex of each side const Element *refElement = Global::getReferenceElement(dim); VectorOfFixVecs<DimVec<double> >**coords; coords = new VectorOfFixVecs<DimVec<double> >*[dim + 1]; // for all element sides for (int i = 0; i < dim + 1; i++) { coords[i] = new VectorOfFixVecs<DimVec<double> >(dim, dim, DEFAULT_VALUE, DimVec<double>(dim, DEFAULT_VALUE, 0.0)); // for each vertex of the side for (int k = 0; k < dim; k++) { int index = refElement->getVertexOfPosition(INDEX_OF_DIM(dim - 1, dim), i, k); (*coords[i])[k][index] = 1.0; } } std::vector<SurfaceQuadrature*> quadSurfaces(dim + 1); for (int i = 0; i < dim + 1; i++) quadSurfaces[i] = new SurfaceQuadrature(q, *coords[i]); double result = 0.0; TraverseStack stack; ElInfo *elInfo = stack.traverseFirst(mesh, -1, Mesh::CALL_LEAF_EL | Mesh::FILL_BOUND | Mesh::FILL_COORDS); while (elInfo) { for (int face = 0; face < dim + 1; face++) { if (elInfo->getBoundary(face) == boundaryType) { int nPoints = quadSurfaces[face]->getNumPoints(); mtl::dense_vector<double> uh_vec(nPoints); double det = elInfo->calcSurfaceDet(*coords[face]); double normT = 0.0; this->getVecAtQPs(elInfo, quadSurfaces[face], NULL, uh_vec); for (int iq = 0; iq < nPoints; iq++) normT += quadSurfaces[face]->getWeight(iq) * (uh_vec[iq]); result += det * normT; } } elInfo = stack.traverseNext(elInfo); } #ifdef HAVE_PARALLEL_DOMAIN_AMDIS double localResult = result; MPI::COMM_WORLD.Allreduce(&localResult, &result, 1, MPI_DOUBLE, MPI_SUM); #endif return result; } template<> double DOFVector<WorldVector<double> >::IntOnBoundaryNormal( BoundaryType boundaryType, Quadrature* q) const { FUNCNAME("DOFVector<T>::IntOnBoundary()"); Mesh* mesh = this->feSpace->getMesh(); int dim = mesh->getDim(); if (!q) { int deg = 2 * this->feSpace->getBasisFcts()->getDegree(); q = Quadrature::provideQuadrature(dim - 1, deg); } else { TEST_EXIT(q->getDim() == dim-1) ("Provided quadrature has wrong dimension for surfaceQuadrature!\n"); } // create barycentric coords for each vertex of each side const Element *refElement = Global::getReferenceElement(dim); VectorOfFixVecs<DimVec<double> >**coords; coords = new VectorOfFixVecs<DimVec<double> >*[dim + 1]; // for all element sides for (int i = 0; i < dim + 1; i++) { coords[i] = new VectorOfFixVecs<DimVec<double> >(dim, dim, DEFAULT_VALUE, DimVec<double>(dim, DEFAULT_VALUE, 0.0)); // for each vertex of the side for (int k = 0; k < dim; k++) { int index = refElement->getVertexOfPosition(INDEX_OF_DIM(dim - 1, dim), i, k); (*coords[i])[k][index] = 1.0; } } std::vector<SurfaceQuadrature*> quadSurfaces(dim + 1); for (int i = 0; i < dim + 1; i++) quadSurfaces[i] = new SurfaceQuadrature(q, *coords[i]); double result = 0.0; WorldVector<double> normal; TraverseStack stack; ElInfo *elInfo = stack.traverseFirst(mesh, -1, Mesh::CALL_LEAF_EL | Mesh::FILL_BOUND | Mesh::FILL_COORDS); while (elInfo) { for (int face = 0; face < dim + 1; face++) { if (elInfo->getBoundary(face) == boundaryType) { elInfo->getNormal(face, normal); double det = elInfo->calcSurfaceDet(*coords[face]); int nPoints = quadSurfaces[face]->getNumPoints(); mtl::dense_vector<WorldVector<double> > uh_vec(nPoints); WorldVector<double> normT; normT.set(0.0); this->getVecAtQPs(elInfo, quadSurfaces[face], NULL, uh_vec); for (int iq = 0; iq < nPoints; iq++) normT += quadSurfaces[face]->getWeight(iq) * (uh_vec[iq]); // scalar product between vector-valued solution and normal vector result += det * (normT * normal); } } elInfo = stack.traverseNext(elInfo); } #ifdef HAVE_PARALLEL_DOMAIN_AMDIS double localResult = result; MPI::COMM_WORLD.Allreduce(&localResult, &result, 1, MPI_DOUBLE, MPI_SUM); #endif return result; } template<> DOFVector<WorldVector<double> >* DOFVector<double>::getGradient(DOFVector<WorldVector<double> > *grad) const { FUNCNAME("DOFVector<double>::getGradient()"); // define result vector static DOFVector<WorldVector<double> > *result = NULL; if (grad) { result = grad; } else { if(result && result->getFeSpace() != feSpace) { delete result; result = new DOFVector<WorldVector<double> >(feSpace, "gradient"); } } Mesh *mesh = feSpace->getMesh(); int dim = mesh->getDim(); const BasisFunction *basFcts = feSpace->getBasisFcts(); DOFAdmin *admin = feSpace->getAdmin(); // count number of nodes and dofs per node std::vector<int> nNodeDOFs; std::vector<int> nNodePreDofs; std::vector<DimVec<double>*> bary; int nNodes = 0; int nDofs = 0; for (int i = 0; i < dim + 1; i++) { GeoIndex geoIndex = INDEX_OF_DIM(i, dim); int nPositions = mesh->getGeo(geoIndex); int numPreDofs = admin->getNumberOfPreDofs(i); for (int j = 0; j < nPositions; j++) { int dofs = basFcts->getNumberOfDofs(geoIndex); nNodeDOFs.push_back(dofs); nDofs += dofs; nNodePreDofs.push_back(numPreDofs); } nNodes += nPositions; } TEST_EXIT_DBG(nDofs == basFcts->getNumber()) ("number of dofs != number of basis functions\n"); for (int i = 0; i < nDofs; i++) bary.push_back(basFcts->getCoords(i)); ElementVector localUh(basFcts->getNumber()); // traverse mesh std::vector<bool> visited(getUsedSize(), false); TraverseStack stack; Flag fillFlag = Mesh::CALL_LEAF_EL | Mesh::FILL_GRD_LAMBDA | Mesh::FILL_COORDS; ElInfo *elInfo = stack.traverseFirst(mesh, -1, fillFlag); while (elInfo) { const DegreeOfFreedom **dof = elInfo->getElement()->getDof(); const DimVec<WorldVector<double> > &grdLambda = elInfo->getGrdLambda(); getLocalVector(elInfo->getElement(), localUh); int localDOFNr = 0; for (int i = 0; i < nNodes; i++) { // for all nodes for (int j = 0; j < nNodeDOFs[i]; j++) { // for all dofs at this node DegreeOfFreedom dofIndex = dof[i][nNodePreDofs[i] + j]; if (!visited[dofIndex]) { basFcts->evalGrdUh(*(bary[localDOFNr]), grdLambda, localUh, &((*result)[dofIndex])); visited[dofIndex] = true; } localDOFNr++; } } elInfo = stack.traverseNext(elInfo); } return result; } template<> DOFVector<WorldVector<double> >* DOFVector<double>::getRecoveryGradient(DOFVector<WorldVector<double> > *grad) const { FUNCNAME("DOFVector<double>::getRecoveryGradient()"); // define result vector static DOFVector<WorldVector<double> > *vec = NULL; DOFVector<WorldVector<double> > *result = grad; if (!result) { if (vec && vec->getFeSpace() != feSpace) { delete vec; vec = NULL; } if (!vec) vec = new DOFVector<WorldVector<double> >(feSpace, "gradient"); result = vec; } result->set(WorldVector<double>(DEFAULT_VALUE, 0.0)); DOFVector<double> volume(feSpace, "volume"); volume.set(0.0); const BasisFunction *basFcts = feSpace->getBasisFcts(); int nPreDofs = feSpace->getAdmin()->getNumberOfPreDofs(VERTEX); DimVec<double> bary(dim, DEFAULT_VALUE, (1.0 / (dim + 1.0))); WorldVector<double> grd; // traverse mesh Mesh *mesh = feSpace->getMesh(); TraverseStack stack; ElInfo *elInfo = stack.traverseFirst(mesh, -1, Mesh::CALL_LEAF_EL | Mesh::FILL_DET | Mesh::FILL_GRD_LAMBDA | Mesh::FILL_COORDS); ElementVector localUh(basFcts->getNumber()); while (elInfo) { double det = elInfo->getDet(); const DegreeOfFreedom **dof = elInfo->getElement()->getDof(); const DimVec<WorldVector<double> > &grdLambda = elInfo->getGrdLambda(); getLocalVector(elInfo->getElement(), localUh); basFcts->evalGrdUh(bary, grdLambda, localUh, &grd); for (int i = 0; i < dim + 1; i++) { DegreeOfFreedom dofIndex = dof[i][nPreDofs]; (*result)[dofIndex] += grd * det; volume[dofIndex] += det; } elInfo = stack.traverseNext(elInfo); } DOFVector<double>::Iterator volIt(&volume, USED_DOFS); DOFVector<WorldVector<double> >::Iterator grdIt(result, USED_DOFS); for (volIt.reset(), grdIt.reset(); !volIt.end(); ++volIt, ++grdIt) if (*volIt != 0.0) *grdIt *= 1.0 / (*volIt); return result; } template<> const WorldVector<double> *DOFVectorBase<double>::getGrdAtQPs(const ElInfo *elInfo, const Quadrature *quad, const FastQuadrature *quadFast, WorldVector<double> *grdAtQPs) const { FUNCNAME("DOFVector<double>::getGrdAtQPs()"); TEST_EXIT_DBG(quad || quadFast)("neither quad nor quadFast defined\n"); if (quad && quadFast) { TEST_EXIT_DBG(quad == quadFast->getQuadrature()) ("quad != quadFast->quadrature\n"); } TEST_EXIT_DBG(!quadFast || quadFast->getBasisFunctions() == feSpace->getBasisFcts()) ("invalid basis functions"); int dow = Global::getGeo(WORLD); int nPoints = quadFast ? quadFast->getQuadrature()->getNumPoints() : quad->getNumPoints(); static WorldVector<double> *grd = NULL; WorldVector<double> *result; if (grdAtQPs) { result = grdAtQPs; } else { if (grd) delete [] grd; grd = new WorldVector<double>[nPoints]; for (int i = 0; i < nPoints; i++) grd[i].set(0.0); result = grd; } ElementVector localVec(nBasFcts); getLocalVector(elInfo->getElement(), localVec); mtl::dense_vector<double> grd1(dim + 1); int parts = Global::getGeo(PARTS, dim); const DimVec<WorldVector<double> > &grdLambda = elInfo->getGrdLambda(); if (quadFast) { for (int i = 0; i < nPoints; i++) { grd1 = 0.0; for (int j = 0; j < nBasFcts; j++) for (int k = 0; k < parts; k++) grd1[k] += quadFast->getGradient(i, j, k) * localVec[j]; for (int l=0; l < dow; l++) { result[i][l] = 0.0; for (int k = 0; k < parts; k++) result[i][l] += grdLambda[k][l] * grd1[k]; } } } else { const BasisFunction *basFcts = feSpace->getBasisFcts(); mtl::dense_vector<double> grdPhi(dim + 1); for (int i = 0; i < nPoints; i++) { grd1 = 0.0; for (int j = 0; j < nBasFcts; j++) { (*(basFcts->getGrdPhi(j)))(quad->getLambda(i), grdPhi); for (int k = 0; k < parts; k++) grd1[k] += grdPhi[k] * localVec[j]; } for (int l = 0; l < dow; l++) { result[i][l] = 0.0; for (int k = 0; k < parts; k++) result[i][l] += grdLambda[k][l] * grd1[k]; } } } return const_cast<const WorldVector<double>*>(result); } template<> const WorldVector<double> *DOFVectorBase<double>::getGrdAtQPs(const ElInfo *smallElInfo, const ElInfo *largeElInfo, const Quadrature *quad, const FastQuadrature *quadFast, WorldVector<double> *grdAtQPs) const { FUNCNAME("DOFVector<double>::getGrdAtQPs()"); TEST_EXIT_DBG(quad || quadFast)("neither quad nor quadFast defined\n"); if (quad && quadFast) { TEST_EXIT_DBG(quad == quadFast->getQuadrature())("quad != quadFast->quadrature\n"); } TEST_EXIT_DBG(!quadFast || quadFast->getBasisFunctions() == feSpace->getBasisFcts()) ("invalid basis functions"); int dow = Global::getGeo(WORLD); int nPoints = quadFast ? quadFast->getQuadrature()->getNumPoints() : quad->getNumPoints(); static WorldVector<double> *grd = NULL; WorldVector<double> *result; if (grdAtQPs) { result = grdAtQPs; } else { if (grd) delete [] grd; grd = new WorldVector<double>[nPoints]; for (int i = 0; i < nPoints; i++) grd[i].set(0.0); result = grd; } ElementVector localVec(nBasFcts); getLocalVector(largeElInfo->getElement(), localVec); const BasisFunction *basFcts = feSpace->getBasisFcts(); mtl::dense2D<double> &m = smallElInfo->getSubElemCoordsMat(basFcts->getDegree()); int parts = Global::getGeo(PARTS, dim); const DimVec<WorldVector<double> > &grdLambda = largeElInfo->getGrdLambda(); mtl::dense_vector<double> grd1(dim + 1); mtl::dense_vector<double> grdPhi(dim + 1); mtl::dense_vector<double> tmp(dim + 1); for (int i = 0; i < nPoints; i++) { grd1 = 0.0; for (int j = 0; j < nBasFcts; j++) { grdPhi = 0.0; for (int k = 0; k < nBasFcts; k++) { (*(basFcts->getGrdPhi(k)))(quad->getLambda(i), tmp); tmp *= m[j][k]; grdPhi += tmp; } for (int k = 0; k < parts; k++) grd1[k] += grdPhi[k] * localVec[j]; } for (int l = 0; l < dow; l++) { result[i][l] = 0.0; for (int k = 0; k < parts; k++) result[i][l] += grdLambda[k][l] * grd1[k]; } } return const_cast<const WorldVector<double>*>(result); } template<> const WorldMatrix<double> *DOFVectorBase<double>::getD2AtQPs(const ElInfo *elInfo, const Quadrature *quad, const FastQuadrature *quadFast, WorldMatrix<double> *d2AtQPs) const { FUNCNAME("DOFVector<double>::getD2AtQPs()"); TEST_EXIT_DBG(quad || quadFast)("neither quad nor quadFast defined\n"); if (quad && quadFast) { TEST_EXIT_DBG(quad == quadFast->getQuadrature()) ("quad != quadFast->quadrature\n"); } TEST_EXIT_DBG(!quadFast || quadFast->getBasisFunctions() == feSpace->getBasisFcts()) ("invalid basis functions"); Element *el = elInfo->getElement(); int dow = Global::getGeo(WORLD); int nPoints = quadFast ? quadFast->getQuadrature()->getNumPoints() : quad->getNumPoints(); static WorldMatrix<double> *vec = NULL; WorldMatrix<double> *result; if (d2AtQPs) { result = d2AtQPs; } else { if(vec) delete [] vec; vec = new WorldMatrix<double>[nPoints]; for (int i = 0; i < nPoints; i++) { vec[i].set(0.0); } result = vec; } ElementVector localVec(nBasFcts); getLocalVector(el, localVec); DimMat<double> D2Tmp(dim, DEFAULT_VALUE, 0.0); int parts = Global::getGeo(PARTS, dim); const DimVec<WorldVector<double> > &grdLambda = elInfo->getGrdLambda(); if (quadFast) { for (int iq = 0; iq < nPoints; iq++) { for (int k = 0; k < parts; k++) for (int l = 0; l < parts; l++) D2Tmp[k][l] = 0.0; for (int i = 0; i < nBasFcts; i++) { for (int k = 0; k < parts; k++) for (int l = 0; l < parts; l++) D2Tmp[k][l] += localVec[i] * quadFast->getSecDer(iq, i, k, l); } for (int i = 0; i < dow; i++) for (int j = 0; j < dow; j++) { result[iq][i][j] = 0.0; for (int k = 0; k < parts; k++) for (int l = 0; l < parts; l++) result[iq][i][j] += grdLambda[k][i]*grdLambda[l][j]*D2Tmp[k][l]; } } } else { const BasisFunction *basFcts = feSpace->getBasisFcts(); DimMat<double> D2Phi(dim, NO_INIT); for (int iq = 0; iq < nPoints; iq++) { for (int k = 0; k < parts; k++) for (int l = 0; l < parts; l++) D2Tmp[k][l] = 0.0; for (int i = 0; i < nBasFcts; i++) { WARNING("not tested after index correction\n"); (*(basFcts->getD2Phi(i)))(quad->getLambda(iq), D2Phi); for (int k = 0; k < parts; k++) for (int l = 0; l < parts; l++) D2Tmp[k][l] += localVec[i] * D2Phi[k][l]; } for (int i = 0; i < dow; i++) for (int j = 0; j < dow; j++) { result[iq][i][j] = 0.0; for (int k = 0; k < parts; k++) for (int l = 0; l < parts; l++) result[iq][i][j] += grdLambda[k][i] * grdLambda[l][j] * D2Tmp[k][l]; } } } return const_cast<const WorldMatrix<double>*>(result); } template<> void DOFVector<double>::interpol(DOFVector<double> *source, double factor) { FUNCNAME("DOFVector<double>::interpol()"); const FiniteElemSpace *sourceFeSpace = source->getFeSpace(); const BasisFunction *basisFcts = feSpace->getBasisFcts(); const BasisFunction *sourceBasisFcts = sourceFeSpace->getBasisFcts(); int nBasisFcts = basisFcts->getNumber(); int nSourceBasisFcts = sourceBasisFcts->getNumber(); this->set(0.0); std::vector<DegreeOfFreedom> myLocalIndices(nBasisFcts); ElementVector sourceLocalCoeffs(nSourceBasisFcts); if (feSpace->getMesh() == sourceFeSpace->getMesh()) { DimVec<double> *coords = NULL; TraverseStack stack; ElInfo *elInfo = stack.traverseFirst(feSpace->getMesh(), -1, Mesh::CALL_LEAF_EL | Mesh::FILL_COORDS); while (elInfo) { Element *el = elInfo->getElement(); basisFcts->getLocalIndices(el, feSpace->getAdmin(), myLocalIndices); source->getLocalVector(el, sourceLocalCoeffs); for (int i = 0; i < nBasisFcts; i++) { if (vec[myLocalIndices[i]] == 0.0) { coords = basisFcts->getCoords(i); vec[myLocalIndices[i]] = sourceBasisFcts->evalUh(*coords, sourceLocalCoeffs) * factor; } } elInfo = stack.traverseNext(elInfo); } } else { DimVec<double> coords2(feSpace->getMesh()->getDim(), NO_INIT); DualTraverse dualStack; ElInfo *elInfo1, *elInfo2; ElInfo *elInfoSmall, *elInfoLarge; WorldVector<double> worldVec; bool nextTraverse = dualStack.traverseFirst(feSpace->getMesh(), sourceFeSpace->getMesh(), -1, -1, Mesh::CALL_LEAF_EL | Mesh::FILL_COORDS, Mesh::CALL_LEAF_EL | Mesh::FILL_COORDS, &elInfo1, &elInfo2, &elInfoSmall, &elInfoLarge); while (nextTraverse) { basisFcts->getLocalIndices(elInfo1->getElement(), feSpace->getAdmin(), myLocalIndices); source->getLocalVector(elInfo2->getElement(), sourceLocalCoeffs); for (int i = 0; i < nBasisFcts; i++) { if (vec[myLocalIndices[i]] == 0.0) { elInfo1->coordToWorld(*(basisFcts->getCoords(i)), worldVec); elInfo2->worldToCoord(worldVec, &coords2); bool isPositive = true; for (int j = 0; j < coords2.size(); j++) { if (coords2[j] < -0.00001) { isPositive = false; break; } } if (isPositive) vec[myLocalIndices[i]] = sourceBasisFcts->evalUh(coords2, sourceLocalCoeffs); } } nextTraverse = dualStack.traverseNext(&elInfo1, &elInfo2, &elInfoSmall, &elInfoLarge); } } } template<> void DOFVector<WorldVector<double> >::interpol(DOFVector<WorldVector<double> > *v, double factor) { WorldVector<double> nul(DEFAULT_VALUE,0.0); this->set(nul); DimVec<double> *coords = NULL; const FiniteElemSpace *vFeSpace = v->getFeSpace(); if (feSpace == vFeSpace) WARNING("same FE-spaces\n"); const BasisFunction *basFcts = feSpace->getBasisFcts(); const BasisFunction *vBasFcts = vFeSpace->getBasisFcts(); int nBasFcts = basFcts->getNumber(); int vNumBasFcts = vBasFcts->getNumber(); if (feSpace->getMesh() == vFeSpace->getMesh()) { std::vector<DegreeOfFreedom> myLocalIndices(nBasFcts); mtl::dense_vector<WorldVector<double> > vLocalCoeffs(vNumBasFcts); Mesh *mesh = feSpace->getMesh(); TraverseStack stack; ElInfo *elInfo = stack.traverseFirst(mesh, -1, Mesh::CALL_LEAF_EL | Mesh::FILL_COORDS); while (elInfo) { Element *el = elInfo->getElement(); basFcts->getLocalIndices(el, feSpace->getAdmin(), myLocalIndices); v->getLocalVector(el, vLocalCoeffs); for (int i = 0; i < nBasFcts; i++) { if (vec[myLocalIndices[i]] == nul) { coords = basFcts->getCoords(i); vec[myLocalIndices[i]] += vBasFcts->evalUh(*coords, vLocalCoeffs, NULL) * factor; } } elInfo = stack.traverseNext(elInfo); } } else { ERROR_EXIT("not yet for dual traverse\n"); } } template<> WorldVector<DOFVector<double>*> *DOFVector<double>::getGradient(WorldVector<DOFVector<double>*> *grad) const { FUNCNAME("DOFVector<double>::getGradient()"); Mesh *mesh = feSpace->getMesh(); int dim = mesh->getDim(); int dow = Global::getGeo(WORLD); const BasisFunction *basFcts = feSpace->getBasisFcts(); DOFAdmin *admin = feSpace->getAdmin(); // define result vector static WorldVector<DOFVector<double>*> *result = NULL; if (grad) { result = grad; } else { if (!result) { result = new WorldVector<DOFVector<double>*>; result->set(NULL); } for (int i = 0; i < dow; i++) { if ((*result)[i] && (*result)[i]->getFeSpace() != feSpace) { delete (*result)[i]; (*result)[i] = new DOFVector<double>(feSpace, "gradient"); } } } // count number of nodes and dofs per node std::vector<int> nNodeDOFs; std::vector<int> nNodePreDofs; std::vector<DimVec<double>*> bary; int nNodes = 0; int nDofs = 0; for (int i = 0; i < dim + 1; i++) { GeoIndex geoIndex = INDEX_OF_DIM(i, dim); int numPositionNodes = mesh->getGeo(geoIndex); int numPreDofs = admin->getNumberOfPreDofs(i); for (int j = 0; j < numPositionNodes; j++) { int dofs = basFcts->getNumberOfDofs(geoIndex); nNodeDOFs.push_back(dofs); nDofs += dofs; nNodePreDofs.push_back(numPreDofs); } nNodes += numPositionNodes; } TEST_EXIT_DBG(nDofs == basFcts->getNumber()) ("number of dofs != number of basis functions\n"); for (int i = 0; i < nDofs; i++) bary.push_back(basFcts->getCoords(i)); // traverse mesh std::vector<bool> visited(getUsedSize(), false); TraverseStack stack; Flag fillFlag = Mesh::CALL_LEAF_EL | Mesh::FILL_GRD_LAMBDA | Mesh::FILL_COORDS; ElInfo *elInfo = stack.traverseFirst(mesh, -1, fillFlag); WorldVector<double> grd; ElementVector localUh(basFcts->getNumber()); while (elInfo) { const DegreeOfFreedom **dof = elInfo->getElement()->getDof(); getLocalVector(elInfo->getElement(), localUh); const DimVec<WorldVector<double> > &grdLambda = elInfo->getGrdLambda(); int localDOFNr = 0; for (int i = 0; i < nNodes; i++) { // for all nodes for (int j = 0; j < nNodeDOFs[i]; j++) { // for all dofs at this node DegreeOfFreedom dofIndex = dof[i][nNodePreDofs[i] + j]; if (!visited[dofIndex]) { basFcts->evalGrdUh(*(bary[localDOFNr]), grdLambda, localUh, &grd); for (int k = 0; k < dow; k++) (*(*result)[k])[dofIndex] = grd[k]; visited[dofIndex] = true; } localDOFNr++; } } elInfo = stack.traverseNext(elInfo); } return result; } DOFVectorDOF::DOFVectorDOF() : DOFVector<DegreeOfFreedom>() {} void DOFVectorDOF::freeDOFContent(DegreeOfFreedom dof) {} WorldVector<DOFVector<double>*> *transform(DOFVector<WorldVector<double> > *vec, WorldVector<DOFVector<double>*> *res) { FUNCNAME("DOFVector<double>::transform()"); TEST_EXIT_DBG(vec)("no vector\n"); int dow = Global::getGeo(WORLD); static WorldVector<DOFVector<double>*> *result = NULL; if (!res && !result) { result = new WorldVector<DOFVector<double>*>; for (int i = 0; i < dow; i++) (*result)[i] = new DOFVector<double>(vec->getFeSpace(), "transform"); } WorldVector<DOFVector<double>*> *r = res ? res : result; int vecSize = vec->getSize(); for (int i = 0; i < vecSize; i++) for (int j = 0; j < dow; j++) (*((*r)[j]))[i] = (*vec)[i][j]; return r; } template<> void DOFVectorBase<double>::getVecAtQPs(const ElInfo *smallElInfo, const ElInfo *largeElInfo, const Quadrature *quad, const FastQuadrature *quadFast, mtl::dense_vector<double>& vecAtQPs) const { FUNCNAME("DOFVector<double>::getVecAtQPs()"); TEST_EXIT_DBG(quad || quadFast)("neither quad nor quadFast defined\n"); if (quad && quadFast) { TEST_EXIT_DBG(quad == quadFast->getQuadrature()) ("quad != quadFast->quadrature\n"); } TEST_EXIT_DBG(!quadFast || quadFast->getBasisFunctions() == feSpace->getBasisFcts()) ("invalid basis functions"); if (smallElInfo->getMesh() == feSpace->getMesh()) return getVecAtQPs(smallElInfo, quad, quadFast, vecAtQPs); const BasisFunction *basFcts = feSpace->getBasisFcts(); int nPoints = quadFast ? quadFast->getQuadrature()->getNumPoints() : quad->getNumPoints(); vecAtQPs.change_dim(nPoints); ElementVector localVec(nBasFcts); getLocalVector(largeElInfo->getElement(), localVec); mtl::dense2D<double> &m = smallElInfo->getSubElemCoordsMat(basFcts->getDegree()); for (int i = 0; i < nPoints; i++) { vecAtQPs[i] = 0.0; for (int j = 0; j < nBasFcts; j++) { double val = 0.0; for (int k = 0; k < nBasFcts; k++) val += m[j][k] * (*(basFcts->getPhi(k)))(quad->getLambda(i)); vecAtQPs[i] += localVec[j] * val; } } } template<> void DOFVectorBase<double>::assemble(double factor, ElInfo *elInfo, const BoundaryType *bound, Operator *op) { FUNCNAME("DOFVector::assemble()"); if (!(op || this->operators.size())) return; set_to_zero(this->elementVector); bool addVector = false; if (op) { op->getElementVector(elInfo, this->elementVector); addVector = true; } else { std::vector<Operator*>::iterator it; std::vector<double*>::iterator factorIt; for (it = this->operators.begin(), factorIt = this->operatorFactor.begin(); it != this->operators.end(); ++it, ++factorIt) if ((*it)->getNeedDualTraverse() == false) { (*it)->getElementVector(elInfo, this->elementVector, *factorIt ? **factorIt : 1.0); addVector = true; } } if (addVector) addElementVector(factor, this->elementVector, bound, elInfo); } template<> void DOFVectorBase<double>::assemble2(double factor, ElInfo *mainElInfo, ElInfo *auxElInfo, ElInfo *smallElInfo, ElInfo *largeElInfo, const BoundaryType *bound, Operator *op) { FUNCNAME("DOFVector::assemble2()"); if (!(op || this->operators.size())) return; set_to_zero(this->elementVector); bool addVector = false; TEST_EXIT(!op)("Not yet implemented!\n"); std::vector<Operator*>::iterator it; std::vector<double*>::iterator factorIt; for (it = this->operators.begin(), factorIt = this->operatorFactor.begin(); it != this->operators.end(); ++it, ++factorIt) if ((*it)->getNeedDualTraverse()) { (*it)->getElementVector(mainElInfo, auxElInfo, smallElInfo, largeElInfo, this->elementVector, *factorIt ? **factorIt : 1.0); addVector = true; } if (addVector) addElementVector(factor, this->elementVector, bound, mainElInfo); } double integrate(const DOFVector<double> &vec1, const DOFVector<double> &vec2, BinaryAbstractFunction<double, double, double> *fct) { if (vec1.getFeSpace()->getMesh() == vec2.getFeSpace()->getMesh()) return intSingleMesh(vec1, vec2, fct); else return intDualMesh(vec1, vec2, fct); } double intSingleMesh(const DOFVector<double> &vec1, const DOFVector<double> &vec2, BinaryAbstractFunction<double, double, double> *fct) { FUNCNAME("intDualmesh()"); TEST_EXIT(fct)("No function defined!\n"); int deg = std::max(fct->getDegree(), 2 * vec1.getFeSpace()->getBasisFcts()->getDegree()); Quadrature* quad = Quadrature::provideQuadrature(vec1.getFeSpace()->getMesh()->getDim(), deg); FastQuadrature *fastQuad = FastQuadrature::provideFastQuadrature(vec1.getFeSpace()->getBasisFcts(), *quad, INIT_PHI); mtl::dense_vector<double> qp1(fastQuad->getNumPoints()); mtl::dense_vector<double> qp2(fastQuad->getNumPoints()); double value = 0.0; Flag traverseFlag = Mesh::CALL_LEAF_EL | Mesh::FILL_COORDS | Mesh::FILL_DET; TraverseStack stack; ElInfo *elInfo = stack.traverseFirst(vec1.getFeSpace()->getMesh(), -1, traverseFlag); while (elInfo) { vec1.getVecAtQPs(elInfo, quad, fastQuad, qp1); vec2.getVecAtQPs(elInfo, quad, fastQuad, qp2); double tmp = 0.0; for (int iq = 0; iq < fastQuad->getNumPoints(); iq++) tmp += fastQuad->getWeight(iq) * (*fct)(qp1[iq], qp2[iq]); value += tmp * elInfo->getDet(); elInfo = stack.traverseNext(elInfo); } #ifdef HAVE_PARALLEL_DOMAIN_AMDIS double localValue = value; MPI::COMM_WORLD.Allreduce(&localValue, &value, 1, MPI_DOUBLE, MPI_SUM); #endif return value; } double intDualMesh(const DOFVector<double> &vec1, const DOFVector<double> &vec2, BinaryAbstractFunction<double, double, double> *fct) { FUNCNAME("intDualmesh()"); TEST_EXIT(fct)("No function defined!\n"); int deg = std::max(fct->getDegree(), 2 * vec1.getFeSpace()->getBasisFcts()->getDegree()); Quadrature* quad = Quadrature::provideQuadrature(vec1.getFeSpace()->getMesh()->getDim(), deg); FastQuadrature *fastQuad = FastQuadrature::provideFastQuadrature(vec1.getFeSpace()->getBasisFcts(), *quad, INIT_PHI); mtl::dense_vector<double> qp1(fastQuad->getNumPoints()); mtl::dense_vector<double> qp2(fastQuad->getNumPoints()); double value = 0.0; Flag traverseFlag = Mesh::CALL_LEAF_EL | Mesh::FILL_COORDS | Mesh::FILL_DET; DualTraverse dualTraverse; DualElInfo dualElInfo; bool cont = dualTraverse.traverseFirst(vec1.getFeSpace()->getMesh(), vec2.getFeSpace()->getMesh(), -1, -1, traverseFlag, traverseFlag, dualElInfo); while (cont) { vec1.getVecAtQPs(dualElInfo.smallElInfo, dualElInfo.largeElInfo, quad, NULL, qp1); vec2.getVecAtQPs(dualElInfo.smallElInfo, dualElInfo.largeElInfo, quad, NULL, qp2); double tmp = 0.0; for (int iq = 0; iq < quad->getNumPoints(); iq++) tmp += quad->getWeight(iq) * (*fct)(qp1[iq], qp2[iq]); value += tmp * dualElInfo.smallElInfo->getDet(); cont = dualTraverse.traverseNext(dualElInfo); } #ifdef HAVE_PARALLEL_DOMAIN_AMDIS double localValue = value; MPI::COMM_WORLD.Allreduce(&localValue, &value, 1, MPI_DOUBLE, MPI_SUM); #endif return value; } double integrate(const DOFVector<double> &vec, AbstractFunction<double, WorldVector<double> > *fct) { FUNCNAME("integrate()"); TEST_EXIT(fct)("No function defined!\n"); const FiniteElemSpace *feSpace = vec.getFeSpace(); Mesh *mesh = feSpace->getMesh(); int deg = std::max(fct->getDegree(), 2 * feSpace->getBasisFcts()->getDegree()); Quadrature* quad = Quadrature::provideQuadrature(mesh->getDim(), deg); FastQuadrature *fastQuad = FastQuadrature::provideFastQuadrature(feSpace->getBasisFcts(), *quad, INIT_PHI); mtl::dense_vector<double> qp(fastQuad->getNumPoints()); WorldVector<double> coords; double value = 0.0; Flag traverseFlag = Mesh::CALL_LEAF_EL | Mesh::FILL_COORDS | Mesh::FILL_DET; TraverseStack stack; ElInfo *elInfo = stack.traverseFirst(mesh, -1, traverseFlag); while (elInfo) { vec.getVecAtQPs(elInfo, quad, fastQuad, qp); double tmp = 0.0; for (int iq = 0; iq < fastQuad->getNumPoints(); iq++) { elInfo->coordToWorld(fastQuad->getLambda(iq), coords); tmp += fastQuad->getWeight(iq) * (qp[iq] * (*fct)(coords)); } value += tmp * elInfo->getDet(); elInfo = stack.traverseNext(elInfo); } #ifdef HAVE_PARALLEL_DOMAIN_AMDIS double localValue = value; MPI::COMM_WORLD.Allreduce(&localValue, &value, 1, MPI_DOUBLE, MPI_SUM); #endif return value; } double integrate(const FiniteElemSpace* feSpace, AbstractFunction<double, WorldVector<double> > *fct) { FUNCNAME("integrate()"); TEST_EXIT(fct)("No function defined!\n"); int deg = std::max(fct->getDegree(), feSpace->getBasisFcts()->getDegree()); Quadrature* quad = Quadrature::provideQuadrature(feSpace->getMesh()->getDim(), deg); FastQuadrature *fastQuad = FastQuadrature::provideFastQuadrature(feSpace->getBasisFcts(), *quad, INIT_PHI); WorldVector<double> coords; double value = 0.0; Flag traverseFlag = Mesh::CALL_LEAF_EL | Mesh::FILL_COORDS | Mesh::FILL_DET; TraverseStack stack; ElInfo *elInfo = stack.traverseFirst(feSpace->getMesh(), -1, traverseFlag); while (elInfo) { double tmp = 0.0; for (int iq = 0; iq < fastQuad->getNumPoints(); iq++) { elInfo->coordToWorld(fastQuad->getLambda(iq), coords); tmp += fastQuad->getWeight(iq) * (*fct)(coords); } value += tmp * elInfo->getDet(); elInfo = stack.traverseNext(elInfo); } #ifdef HAVE_PARALLEL_DOMAIN_AMDIS double localValue = value; MPI::COMM_WORLD.Allreduce(&localValue, &value, 1, MPI_DOUBLE, MPI_SUM); #endif return value; } }