// // 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 "RobinBC.h" #include "Assembler.h" #include "DOFVector.h" #include "DOFMatrix.h" #include "SurfaceOperator.h" #include "est/Estimator.h" #include namespace AMDiS { RobinBC::RobinBC(BoundaryType type, AbstractFunction > *j, AbstractFunction > *alpha, FiniteElemSpace *rowFeSpace_, FiniteElemSpace *colFeSpace_) : BoundaryCondition(type, rowFeSpace_, colFeSpace_), neumannOperators(NULL), robinOperators(NULL) { int dim = rowFeSpace->getMesh()->getDim(); // create barycentric coords for each vertex of each side const Element *refElement = Global::getReferenceElement(dim); coords = new VectorOfFixVecs >*[dim + 1]; // for all element sides for (int i = 0; i < dim + 1; i++) { coords[i] = new VectorOfFixVecs >(dim, dim, DEFAULT_VALUE, DimVec(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; } } if (j) { Operator *jOp = new Operator(rowFeSpace); jOp->addZeroOrderTerm(new CoordsAtQP_ZOT(j)); neumannOperators = new DimVec(dim, NO_INIT); for (int i = 0; i < dim + 1; i++) (*neumannOperators)[i] = new SurfaceOperator(jOp, *coords[i]); delete jOp; } if (alpha) { Operator *alphaOp = new Operator(rowFeSpace, colFeSpace); alphaOp->addZeroOrderTerm(new CoordsAtQP_ZOT(alpha)); robinOperators = new DimVec(dim, NO_INIT); for (int i = 0; i < dim + 1; i++) (*robinOperators)[i] = new SurfaceOperator(alphaOp, *coords[i]); delete alphaOp; } } RobinBC::RobinBC(BoundaryType type, DOFVectorBase *j, DOFVectorBase *alpha, FiniteElemSpace *rowFeSpace_, FiniteElemSpace *colFeSpace_) : BoundaryCondition(type, rowFeSpace_, colFeSpace_), neumannOperators(NULL), robinOperators(NULL) { int dim = rowFeSpace->getMesh()->getDim(); // create barycentric coords for each vertex of each side const Element *refElement = Global::getReferenceElement(dim); coords = new VectorOfFixVecs >*[dim+1]; // for all element sides for (int i = 0; i < dim + 1; i++) { coords[i] = new VectorOfFixVecs >(dim, dim, DEFAULT_VALUE, DimVec(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; } } if (j) { Operator *jOp = new Operator(rowFeSpace); jOp->addZeroOrderTerm(new VecAtQP_ZOT(j, NULL)); neumannOperators = new DimVec(dim, NO_INIT); for (int i = 0; i < dim + 1; i++) (*neumannOperators)[i] = new SurfaceOperator(jOp, *coords[i]); delete jOp; } if (alpha) { Operator *alphaOp = new Operator(rowFeSpace, colFeSpace); alphaOp->addZeroOrderTerm(new VecAtQP_ZOT(alpha, NULL)); robinOperators = new DimVec(dim, NO_INIT); for (int i = 0; i < dim + 1; i++) (*robinOperators)[i] = new SurfaceOperator(alphaOp, *coords[i]); delete alphaOp; } } RobinBC::RobinBC(BoundaryType type, Operator* jOp, Operator* alphaOp, FiniteElemSpace *rowFeSpace_, FiniteElemSpace *colFeSpace_) : BoundaryCondition(type, rowFeSpace_, colFeSpace_), neumannOperators(NULL), robinOperators(NULL) { int dim = rowFeSpace->getMesh()->getDim(); // create barycentric coords for each vertex of each side const Element *refElement = Global::getReferenceElement(dim); coords = new VectorOfFixVecs >*[dim+1]; // for all element sides for (int i = 0; i < dim + 1; i++) { coords[i] = new VectorOfFixVecs >(dim, dim, DEFAULT_VALUE, DimVec(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; } } if (jOp) { neumannOperators = new DimVec(dim, NO_INIT); for (int i = 0; i < dim + 1; i++) (*neumannOperators)[i] = new SurfaceOperator(jOp, *coords[i]); } if (alphaOp) { robinOperators = new DimVec(dim, NO_INIT); for (int i = 0; i < dim + 1; i++) (*robinOperators)[i] = new SurfaceOperator(alphaOp, *coords[i]); } } void RobinBC::fillBoundaryCondition(DOFVectorBase* vector, ElInfo* elInfo, const DegreeOfFreedom* dofIndices, const BoundaryType* localBound, int nBasFcts) { FUNCNAME("RobinBC::fillBoundaryCondition()"); TEST_EXIT_DBG(vector->getFeSpace() == rowFeSpace)("invalid row fe space\n"); int dim = elInfo->getMesh()->getDim(); if (neumannOperators) for (int i = 0; i < dim + 1; i++) if (elInfo->getBoundary(i) == boundaryType) vector->assemble(1.0, elInfo, localBound, (*neumannOperators)[i]); } void RobinBC::fillBoundaryCondition(DOFMatrix* matrix, ElInfo* elInfo, const DegreeOfFreedom* dofIndices, const BoundaryType* localBound, int nBasFcts) { if (robinOperators) { int dim = elInfo->getMesh()->getDim(); for (int i = 0; i < dim + 1; i++) if (elInfo->getBoundary(i) == boundaryType) matrix->assemble(-1.0, elInfo, localBound, (*robinOperators)[i]); } } double RobinBC::boundResidual(ElInfo *elInfo, DOFMatrix *matrix, const DOFVectorBase *dv) { FUNCNAME("RobinBC::fillBoundaryCondition()"); TEST_EXIT(matrix->getRowFeSpace() == rowFeSpace)("invalid row fe space\n"); TEST_EXIT(matrix->getColFeSpace() == colFeSpace)("invalid col fe space\n"); int dim = elInfo->getMesh()->getDim(); DimVec lambda(dim, NO_INIT); double n_A_grdUh, val = 0.0; WorldVector normal; const DimVec > &Lambda = elInfo->getGrdLambda(); double det = elInfo->getDet(); bool neumannQuad = false; const BasisFunction *basFcts = dv->getFeSpace()->getBasisFcts(); TEST_EXIT(basFcts == rowFeSpace->getBasisFcts())("invalid basFcts\n"); ElementVector uhEl(basFcts->getNumber()); dv->getLocalVector(elInfo->getElement(), uhEl); TEST_EXIT(neumannOperators || robinOperators) ("neither neumann nor robin operators set!\n"); if (!robinOperators) { neumannQuad = true; } else { if (neumannOperators) { if ((*neumannOperators)[0]->getAssembler()-> getZeroOrderAssembler()->getQuadrature()->getNumPoints() > (*robinOperators)[0]->getAssembler()-> getZeroOrderAssembler()->getQuadrature()->getNumPoints()) neumannQuad = true; } } std::vector::iterator op; for (op = matrix->getOperatorsBegin(); op != matrix->getOperatorsEnd(); ++op) (*op)->getAssembler()->initElement(elInfo); for (int face = 0; face < dim + 1; face++) { elInfo->getNormal(face, normal); Quadrature *quadrature = neumannQuad ? (*neumannOperators)[face]->getAssembler()-> getZeroOrderAssembler()->getQuadrature() : (*robinOperators)[face]->getAssembler()-> getZeroOrderAssembler()->getQuadrature(); if (elInfo->getBoundary(face) == boundaryType) { (*neumannOperators)[face]->getAssembler()-> getZeroOrderAssembler()->initElement(elInfo); int nPoints = quadrature->getNumPoints(); mtl::dense_vector uhAtQp(nPoints); dv->getVecAtQPs(elInfo, quadrature, NULL, uhAtQp); ElementVector f(nPoints); f = 0.0; if (robinOperators) (*robinOperators)[face]->evalZeroOrder(nPoints, uhAtQp, NULL, NULL, f, 1.0); std::vector > grdUh(nPoints); std::vector > A_grdUh(nPoints); for (int iq = 0; iq < nPoints; iq++) { A_grdUh[iq].set(0.0); lambda = quadrature->getLambda(iq); basFcts->evalGrdUh(lambda, Lambda, uhEl, &grdUh[iq]); } for (op = matrix->getOperatorsBegin(); op != matrix->getOperatorsEnd(); ++op) (*op)->weakEvalSecondOrder(grdUh, A_grdUh); if (neumannOperators) (*neumannOperators)[face]->getC(elInfo, nPoints, f); val = 0.0; for (int iq = 0; iq < nPoints; iq++) { n_A_grdUh = (normal * A_grdUh[iq]) - f[iq]; val += quadrature->getWeight(iq) * sqr(n_A_grdUh); } } } return det * val; } }