#include "ElInfo2d.h" #include "BasisFunction.h" #include "Element.h" #include "Line.h" #include "Triangle.h" #include "Tetrahedron.h" #include "FiniteElemSpace.h" #include "Flag.h" #include "MacroElement.h" #include "Mesh.h" #include "Global.h" #include "FixVec.h" #include "DOFVector.h" namespace AMDiS { void ElInfo2d::fillMacroInfo(const MacroElement * mel) { FUNCNAME("ElInfo::fillMacroInfo()"); macroElement_ = const_cast(mel); element_ = const_cast(mel->getElement()); parent_ = NULL; level_ = 0; if (fillFlag_.isSet(Mesh::FILL_COORDS) || fillFlag_.isSet(Mesh::FILL_DET) || fillFlag_.isSet(Mesh::FILL_GRD_LAMBDA)) { int vertices = mesh_->getGeo(VERTEX); for (int i = 0; i < vertices; i++) { coord_[i] = mel->coord[i]; } } // if(fillFlag_.isSet(Mesh::FILL_DET) || fillFlag_.isSet(Mesh::FILL_GRD_LAMBDA)) { // det = calcGrdLambda(*Lambda); // } int neighbours = mesh_->getGeo(NEIGH); if (fillFlag_.isSet(Mesh::FILL_OPP_COORDS) || fillFlag_.isSet(Mesh::FILL_NEIGH)) { bool fill_opp_coords = (fillFlag_.isSet(Mesh::FILL_OPP_COORDS)); for (int i = 0; i < neighbours; i++) { MacroElement *macroNeighbour = mel->getNeighbour(i); if (macroNeighbour) { neighbour_[i] = macroNeighbour->getElement(); Element *nb = const_cast(neighbour_[i]); int edgeNo = oppVertex_[i] = mel->getOppVertex(i); if (nb->getFirstChild() && (edgeNo != 2)) { // make nb nearest el. if (edgeNo == 0) { nb = neighbour_[i] = nb->getSecondChild(); } else { nb = neighbour_[i] = nb->getFirstChild(); } oppVertex_[i] = 2; if (fill_opp_coords) { if (nb->getNewCoord(-1)) { oppCoord_[i] = *(nb->getNewCoord()); } else { oppCoord_[i] = (macroNeighbour->coord[0] + macroNeighbour->coord[1]) * 0.5; } switch (i) { case 0: if (*(macroNeighbour->getElement()->getDOF(2)) == *(element_->getDOF(2))) { neighbourCoord_[i][0] = macroNeighbour->coord[2]; neighbourCoord_[i][1] = macroNeighbour->coord[0]; } else if (*(macroNeighbour->getElement()->getDOF(2)) == *(element_->getDOF(1))) { neighbourCoord_[i][0] = macroNeighbour->coord[1]; neighbourCoord_[i][1] = macroNeighbour->coord[2]; } else { ERROR_EXIT("should not happen!\n"); } neighbourCoord_[i][2] = oppCoord_[i]; break; case 1: if (*(macroNeighbour->getElement()->getDOF(2)) == *(element_->getDOF(2))) { neighbourCoord_[i][0] = macroNeighbour->coord[1]; neighbourCoord_[i][1] = macroNeighbour->coord[2]; } else if (*(macroNeighbour->getElement()->getDOF(2)) == *(element_->getDOF(0))) { neighbourCoord_[i][0] = macroNeighbour->coord[2]; neighbourCoord_[i][1] = macroNeighbour->coord[0]; } else { ERROR_EXIT("should not happen!\n"); } neighbourCoord_[i][2] = oppCoord_[i]; break; default: ERROR_EXIT("should not happen!\n"); break; } } } else { if (fill_opp_coords) { oppCoord_[i] = macroNeighbour->coord[edgeNo]; neighbourCoord_[i] = macroNeighbour->coord; } } } else { neighbour_[i] = NULL; } } } if (fillFlag_.isSet(Mesh::FILL_BOUND)) { for (int i = 0; i < element_->getGeo(BOUNDARY); i++) { boundary_[i] = mel->getBoundary(i); } for (int i = 0; i < element_->getGeo(PROJECTION); i++) { projection_[i] = mel->getProjection(i); } } } /****************************************************************************/ /* fill ElInfo structure for one child of an element */ /****************************************************************************/ void ElInfo2d::fillElInfo(int ichild, const ElInfo *elinfo_old) { FUNCNAME("ElInfo::fillElInfo()"); Element *elem = elinfo_old->element_; Element *nb; Flag fill_flag = elinfo_old->fillFlag_; TEST_EXIT(elem->getFirstChild())("no children?\n"); TEST_EXIT(element_ = const_cast((ichild == 0) ? elem->getFirstChild() : elem->getSecondChild())) ("missing child %d?\n", ichild); macroElement_ = elinfo_old->macroElement_; fillFlag_ = fill_flag; parent_ = elem; level_ = elinfo_old->level_ + 1; int dow = Global::getGeo(WORLD); if (fillFlag_.isSet(Mesh::FILL_COORDS) || fillFlag_.isSet(Mesh::FILL_DET) || fillFlag_.isSet(Mesh::FILL_GRD_LAMBDA)) { if (elem->getNewCoord(-1)) { coord_[2] = *(elem->getNewCoord()); } else { coord_[2].setMidpoint(elinfo_old->coord_[0], elinfo_old->coord_[1]); } if (ichild == 0) { coord_[0] = elinfo_old->coord_[2]; coord_[1] = elinfo_old->coord_[0]; } else { coord_[0] = elinfo_old->coord_[1]; coord_[1] = elinfo_old->coord_[2]; } } bool fill_opp_coords = (fill_flag.isSet(Mesh::FILL_OPP_COORDS)); if (fill_flag.isSet(Mesh::FILL_NEIGH) || fill_opp_coords) { if (ichild == 0) { // Calculation of the neighbour 2, its oppCoords and the // cooresponding oppVertex. neighbour_[2] = elinfo_old->neighbour_[1]; oppVertex_[2] = elinfo_old->oppVertex_[1]; if (neighbour_[2] && fill_opp_coords) { oppCoord_[2] = elinfo_old->oppCoord_[1]; neighbourCoord_[2] = elinfo_old->neighbourCoord_[1]; } // Calculation of the neighbour 1, its oppCoords and the // cooresponding oppVertex. if (elem->getFirstChild() && elem->getSecondChild()->getFirstChild() && elem->getSecondChild()->getFirstChild()) { neighbour_[1] = elem->getSecondChild()->getSecondChild(); oppVertex_[1] = 2; if (fill_opp_coords) { if (elem->getSecondChild()->getNewCoord(-1)) { oppCoord_[1] = *(elem->getSecondChild()->getNewCoord()); } else { oppCoord_[1].setMidpoint(elinfo_old->coord_[1], elinfo_old->coord_[2]); } neighbourCoord_[1][0] = coord_[0]; neighbourCoord_[1][1] = coord_[2]; neighbourCoord_[1][2] = oppCoord_[1]; } } else { neighbour_[1] = elem->getSecondChild(); oppVertex_[1] = 0; if (fill_opp_coords) { oppCoord_[1] = elinfo_old->coord_[1]; neighbourCoord_[1][0] = elinfo_old->coord_[1]; neighbourCoord_[1][1] = elinfo_old->coord_[2]; neighbourCoord_[1][2] = coord_[2]; } } // Calculation of the neighbour 0, its oppCoords and the // cooresponding oppVertex. nb = elinfo_old->neighbour_[2]; if (nb) { TEST(elinfo_old->oppVertex_[2] == 2)("invalid neighbour\n"); TEST_EXIT(nb->getFirstChild())("missing first child?\n"); TEST_EXIT(nb->getSecondChild())("missing second child?\n"); nb = nb->getSecondChild(); if (nb->getFirstChild()) { oppVertex_[0] = 2; if (fill_opp_coords) { if (nb->getNewCoord(-1)) { oppCoord_[0] = *(nb->getNewCoord()); } else { oppCoord_[0].setMidpoint(elinfo_old->neighbourCoord_[2][1], elinfo_old->neighbourCoord_[2][2]); } neighbourCoord_[0][0].setMidpoint(elinfo_old->neighbourCoord_[2][0], elinfo_old->neighbourCoord_[2][1]); neighbourCoord_[0][1] = elinfo_old->neighbourCoord_[2][1]; neighbourCoord_[0][2] = oppCoord_[0]; } nb = nb->getFirstChild(); } else { oppVertex_[0] = 1; if (fill_opp_coords) { oppCoord_[0] = elinfo_old->oppCoord_[2]; neighbourCoord_[0][0] = elinfo_old->neighbourCoord_[2][0]; neighbourCoord_[0][1] = elinfo_old->neighbourCoord_[2][2]; neighbourCoord_[0][2].setMidpoint(elinfo_old->neighbourCoord_[2][0], elinfo_old->neighbourCoord_[2][1]); } } } neighbour_[0] = nb; } else { /* ichild == 1 */ // Calculation of the neighbour 2, its oppCoords and the // cooresponding oppVertex. neighbour_[2] = elinfo_old->neighbour_[0]; oppVertex_[2] = elinfo_old->oppVertex_[0]; if (neighbour_[2] && fill_opp_coords) { oppCoord_[2] = elinfo_old->oppCoord_[0]; neighbourCoord_[2] = elinfo_old->neighbourCoord_[0]; } // Calculation of the neighbour 0, its oppCoords and the // cooresponding oppVertex. if (elem->getFirstChild()->getFirstChild()) { neighbour_[0] = elem->getFirstChild()->getFirstChild(); oppVertex_[0] = 2; if (fill_opp_coords) { if (elem->getFirstChild()->getNewCoord(-1)) { oppCoord_[0] = *(elem->getFirstChild()->getNewCoord()); } else { oppCoord_[0].setMidpoint(elinfo_old->coord_[0], elinfo_old->coord_[2]); } neighbourCoord_[0][0] = coord_[2]; neighbourCoord_[0][1] = coord_[1]; neighbourCoord_[0][2] = oppCoord_[0]; } } else { neighbour_[0] = elem->getFirstChild(); oppVertex_[0] = 1; if (fill_opp_coords) { oppCoord_[0] = elinfo_old->coord_[0]; neighbourCoord_[0][0] = elinfo_old->coord_[2]; neighbourCoord_[0][1] = elinfo_old->coord_[0]; neighbourCoord_[0][2] = coord_[2]; } } // Calculation of the neighbour 1, its oppCoords and the // cooresponding oppVertex. nb = elinfo_old->neighbour_[2]; if (nb) { TEST(elinfo_old->oppVertex_[2] == 2)("invalid neighbour\n"); TEST((nb = nb->getFirstChild()))("missing child?\n"); if (nb->getFirstChild()) { oppVertex_[1] = 2; if (fill_opp_coords) { if (nb->getNewCoord(-1)) { oppCoord_[1] = *(nb->getNewCoord()); } else { oppCoord_[1].setMidpoint(elinfo_old->neighbourCoord_[2][0], elinfo_old->neighbourCoord_[2][2]); } neighbourCoord_[1][0] = elinfo_old->neighbourCoord_[2][0]; neighbourCoord_[1][1].setMidpoint(elinfo_old->neighbourCoord_[2][0], elinfo_old->neighbourCoord_[2][1]); neighbourCoord_[1][2] = oppCoord_[1]; } nb = nb->getSecondChild(); } else { oppVertex_[1] = 0; if (fill_opp_coords) { oppCoord_[1] = elinfo_old->oppCoord_[2]; neighbourCoord_[1][0] = elinfo_old->neighbourCoord_[2][2]; neighbourCoord_[1][1] = elinfo_old->neighbourCoord_[2][0]; neighbourCoord_[1][2].setMidpoint(elinfo_old->neighbourCoord_[2][0], elinfo_old->neighbourCoord_[2][1]); } } } neighbour_[1] = nb; } // if (ichild == 0) {} else } // if (fill_flag.isSet(Mesh::FILL_NEIGH) || fillFlag_.isSet(Mesh::FILL_OPP_COORDS)) if (fill_flag.isSet(Mesh::FILL_BOUND)) { if (elinfo_old->getBoundary(2)) { boundary_[5] = elinfo_old->getBoundary(2); } else { boundary_[5] = INTERIOR; } if (ichild == 0) { boundary_[3] = elinfo_old->getBoundary(5); boundary_[4] = elinfo_old->getBoundary(3); boundary_[0] = elinfo_old->getBoundary(2); boundary_[1] = INTERIOR; boundary_[2] = elinfo_old->getBoundary(1); } else { boundary_[3] = elinfo_old->getBoundary(4); boundary_[4] = elinfo_old->getBoundary(5); boundary_[0] = INTERIOR; boundary_[1] = elinfo_old->getBoundary(2); boundary_[2] = elinfo_old->getBoundary(0); } if (elinfo_old->getProjection(0) && elinfo_old->getProjection(0)->getType() == VOLUME_PROJECTION) { projection_[0] = elinfo_old->getProjection(0); } else { // boundary projection if (ichild == 0) { projection_[0] = elinfo_old->getProjection(2); projection_[1] = NULL; projection_[2] = elinfo_old->getProjection(1); } else { projection_[0] = NULL; projection_[1] = elinfo_old->getProjection(2); projection_[2] = elinfo_old->getProjection(0); } } } } double ElInfo2d::calcGrdLambda(DimVec >& grd_lam) const { FUNCNAME("ElInfo2d::calcGrdLambda"); // TEST_EXIT(Global::getGeo(WORLD) == 2) // ("dim != dim_of_world ! use parametric elements!\n"); WorldVector e1, e2; double adet = 0.0; const WorldVector v0 = coord_[0]; testFlag(Mesh::FILL_COORDS); int dow = Global::getGeo(WORLD); int dim = mesh_->getDim(); for (int i = 0; i < dow; i++) { e1[i] = coord_[1][i] - v0[i]; e2[i] = coord_[2][i] - v0[i]; } if (dow == 2) { double sdet = e1[0] * e2[1] - e1[1] * e2[0]; adet = abs(sdet); if (adet < 1.0E-25) { MSG("abs(det) = %f\n", adet); for (int i = 0; i <= dim; i++) for (int j = 0; j < dow; j++) grd_lam[i][j] = 0.0; } else { double det1 = 1.0 / sdet; double a11 = e2[1] * det1; /* (a_ij) = A^{-T} */ double a21 = -e2[0] * det1; double a12 = -e1[1] * det1; double a22 = e1[0] * det1; grd_lam[1][0] = a11; grd_lam[1][1] = a21; grd_lam[2][0] = a12; grd_lam[2][1] = a22; grd_lam[0][0] = - grd_lam[1][0] - grd_lam[2][0]; grd_lam[0][1] = - grd_lam[1][1] - grd_lam[2][1]; } } else { WorldVector normal; vectorProduct(e1, e2, normal); adet = norm(&normal); if (adet < 1.0E-15) { MSG("abs(det) = %lf\n", adet); for (int i = 0; i <= dim; i++) for (int j = 0; j < dow; j++) grd_lam[i][j] = 0.0; } else { vectorProduct(e2, normal, grd_lam[1]); vectorProduct(normal, e1, grd_lam[2]); double adet2 = 1.0 / (adet * adet); for (int i = 0; i < dow; i++) { grd_lam[1][i] *= adet2; grd_lam[2][i] *= adet2; } grd_lam[0][0] = - grd_lam[1][0] - grd_lam[2][0]; grd_lam[0][1] = - grd_lam[1][1] - grd_lam[2][1]; grd_lam[0][2] = - grd_lam[1][2] - grd_lam[2][2]; } } return adet; } const int ElInfo2d::worldToCoord(const WorldVector& xy, DimVec* lambda) const { FUNCNAME("ElInfo::worldToCoord()"); TEST_EXIT(lambda)("lambda must not be NULL\n"); DimVec > edge(mesh_->getDim(), NO_INIT); WorldVector x; static DimVec vec(mesh_->getDim(), NO_INIT); int dim = mesh_->getDim(); int dimOfWorld = Global::getGeo(WORLD); for (int j = 0; j < dimOfWorld; j++) { double x0 = coord_[dim][j]; x[j] = xy[j] - x0; for (int i = 0; i < dim; i++) edge[i][j] = coord_[i][j] - x0; } double det = edge[0][0] * edge[1][1] - edge[0][1] * edge[1][0]; double det0 = x[0] * edge[1][1] - x[1] * edge[1][0]; double det1 = edge[0][0] * x[1] - edge[0][1] * x[0]; if (abs(det) < DBL_TOL) { ERROR("det = %le; abort\n", det); for (int i = 0; i <= dim; i++) (*lambda)[i] = 1.0/dim; return 0; } (*lambda)[0] = det0 / det; (*lambda)[1] = det1 / det; (*lambda)[2] = 1.0 - (*lambda)[0] - (*lambda)[1]; int k = -1; double lmin = 0.0; for (int i = 0; i <= dim; i++) { if ((*lambda)[i] < -1.E-5) { if ((*lambda)[i] < lmin) { k = i; lmin = (*lambda)[i]; } } } return k; } double ElInfo2d::getNormal(int side, WorldVector &normal) const { FUNCNAME("ElInfo::getNormal()"); int i0 = (side + 1) % 3; int i1 = (side + 2) % 3; if (Global::getGeo(WORLD) == 2){ normal[0] = coord_[i1][1] - coord_[i0][1]; normal[1] = coord_[i0][0] - coord_[i1][0]; } else { // dow == 3 WorldVector e0, e1,e2, elementNormal; e0 = coord_[i1]; e0 -= coord_[i0]; e1 = coord_[i1]; e1 -= coord_[side]; e2 = coord_[i0]; e2 -= coord_[side]; vectorProduct(e1, e2, elementNormal); vectorProduct(elementNormal, e0, normal); } double det = norm(&normal); TEST_EXIT(det > 1.e-30)("det = 0 on face %d\n", side); normal *= 1.0 / det; return(det); } /****************************************************************************/ /* calculate the normal of the element for dim of world = dim + 1 */ /* return the absulute value of the determinant from the */ /* transformation to the reference element */ /****************************************************************************/ double ElInfo2d::getElementNormal( WorldVector &elementNormal) const { FUNCNAME("ElInfo::getElementNormal()"); TEST_EXIT(Global::getGeo(WORLD) == 3)(" element normal only well defined for DIM_OF_WORLD = DIM + 1 !!"); WorldVector e0 = coord_[1] - coord_[0]; WorldVector e1 = coord_[2] - coord_[0]; vectorProduct(e0, e1, elementNormal); double det = norm(&elementNormal); TEST_EXIT(det > 1.e-30)("det = 0"); elementNormal *= 1.0 / det; return(det); } }