#include "ElInfo3d.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 ElInfo3d::fillMacroInfo(const MacroElement * mel) { FUNCNAME("ElInfo3d::fillMacroInfo"); Element *nb; MacroElement *mnb; Flag fill_opp_coords; macroElement_ = const_cast<MacroElement*>( mel); element_ = const_cast<Element*>( mel->getElement()); parent_ = NULL; level_ = 0; el_type = const_cast<MacroElement*>(mel)->getElType(); int vertices = mesh_->getGeo(VERTEX); if (fillFlag_.isSet(Mesh::FILL_COORDS) || fillFlag_.isSet(Mesh::FILL_DET) || fillFlag_.isSet(Mesh::FILL_GRD_LAMBDA)) { for (int i = 0; i < vertices; i++) { coord_[i] = mel->coord[i]; } } int neighbours = mesh_->getGeo(NEIGH); if (fillFlag_.isSet(Mesh::FILL_OPP_COORDS) || fillFlag_.isSet(Mesh::FILL_NEIGH)) { fill_opp_coords.setFlags(fillFlag_ & Mesh::FILL_OPP_COORDS); for (int i = 0; i < neighbours; i++) { if ((mnb = const_cast<MacroElement*>( mel->getNeighbour(i)))) { neighbour_[i] = const_cast<Element*>( mel->getNeighbour(i)->getElement()); nb = const_cast<Element*>( neighbour_[i]); int k; k = oppVertex_[i] = mel->getOppVertex(i); if (nb->getChild(0) && (k < 2)) { /*make nb nearest element.*/ if (k == 1) { neighbour_[i] = const_cast<Element*>( nb->getChild(0)); nb = const_cast<Element*>( neighbour_[i]); } else { neighbour_[i] = const_cast<Element*>( nb->getChild(1)); nb = const_cast<Element*>( neighbour_[i]); } k = oppVertex_[i] = 3; if (fill_opp_coords.isAnySet()) { /* always edge between vertices 0 and 1 is bisected! */ if (mnb->getElement()->isNewCoordSet()) oppCoord_[i] = *(mnb->getElement()->getNewCoord()); else oppCoord_[i] = (mnb->coord[0] + mnb->coord[1]) * 0.5; } } else { if (fill_opp_coords.isAnySet()) { oppCoord_[i] = mnb->coord[k]; } } } 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); } } if (fillFlag_.isSet(Mesh::FILL_ORIENTATION)) { WorldVector<WorldVector<double> > a; double s; for (int i = 0; i < 3; i++) { a[i] = mel->coord[i + 1]; a[i] -= mel->coord[0]; } s = (a[0][1] * a[1][2] - a[0][2] * a[1][1]) * a[2][0] + (a[0][2] * a[1][0] - a[0][0] * a[1][2]) * a[2][1] + (a[0][0] * a[1][1] - a[0][1] * a[1][0]) * a[2][2]; if (s >= 0) orientation = 1; else orientation = -1; } } double ElInfo3d::calcGrdLambda(DimVec<WorldVector<double> >& grd_lam) { FUNCNAME("ElInfo3d::calcGrdLambda()"); TEST_EXIT_DBG(dimOfWorld == 3) ("dim != dim_of_world ! use parametric elements!\n"); WorldVector<double> *e1 = &tmpWorldVecs[0]; WorldVector<double> *e2 = &tmpWorldVecs[1]; WorldVector<double> *e3 = &tmpWorldVecs[2]; WorldVector<double> *v0 = &tmpWorldVecs[3]; double det, adet; double a11, a12, a13, a21, a22, a23, a31, a32, a33; testFlag(Mesh::FILL_COORDS); *v0 = coord_[0]; for (int i = 0; i < 3; i++) { (*e1)[i] = coord_[1][i] - (*v0)[i]; (*e2)[i] = coord_[2][i] - (*v0)[i]; (*e3)[i] = coord_[3][i] - (*v0)[i]; } det = (*e1)[0] * ((*e2)[1] * (*e3)[2] - (*e2)[2] * (*e3)[1]) - (*e1)[1] * ((*e2)[0] * (*e3)[2] - (*e2)[2] * (*e3)[0]) + (*e1)[2] * ((*e2)[0] * (*e3)[1] - (*e2)[1] * (*e3)[0]); adet = abs(det); if (adet < 1.0E-25) { MSG("abs(det) = %f\n",adet); for (int i = 0; i < 4; i++) for (int j = 0; j < 3; j++) grd_lam[i][j] = 0.0; } else { det = 1.0 / det; a11 = ((*e2)[1] * (*e3)[2] - (*e2)[2] * (*e3)[1]) * det; /* (a_ij) = A^{-T} */ a12 = ((*e2)[2] * (*e3)[0] - (*e2)[0] * (*e3)[2]) * det; a13 = ((*e2)[0] * (*e3)[1] - (*e2)[1] * (*e3)[0]) * det; a21 = ((*e1)[2] * (*e3)[1] - (*e1)[1] * (*e3)[2]) * det; a22 = ((*e1)[0] * (*e3)[2] - (*e1)[2] * (*e3)[0]) * det; a23 = ((*e1)[1] * (*e3)[0] - (*e1)[0] * (*e3)[1]) * det; a31 = ((*e1)[1] * (*e2)[2] - (*e1)[2] * (*e2)[1]) * det; a32 = ((*e1)[2] * (*e2)[0] - (*e1)[0] * (*e2)[2]) * det; a33 = ((*e1)[0] * (*e2)[1] - (*e1)[1] * (*e2)[0]) * det; grd_lam[1][0] = a11; grd_lam[1][1] = a12; grd_lam[1][2] = a13; grd_lam[2][0] = a21; grd_lam[2][1] = a22; grd_lam[2][2] = a23; grd_lam[3][0] = a31; grd_lam[3][1] = a32; grd_lam[3][2] = a33; grd_lam[0][0] = -grd_lam[1][0] - grd_lam[2][0] - grd_lam[3][0]; grd_lam[0][1] = -grd_lam[1][1] - grd_lam[2][1] - grd_lam[3][1]; grd_lam[0][2] = -grd_lam[1][2] - grd_lam[2][2] - grd_lam[3][2]; } return adet; } const int ElInfo3d::worldToCoord(const WorldVector<double>& xy, DimVec<double>* lambda) const { FUNCNAME("ElInfo::worldToCoord()"); DimVec<WorldVector<double> > edge(mesh_->getDim(), NO_INIT); WorldVector<double> x; double x0, det, det0, det1, det2; static DimVec<double> vec(mesh_->getDim(), NO_INIT); TEST_EXIT_DBG(lambda)("lambda must not be NULL\n"); int dim = mesh_->getDim(); TEST_EXIT_DBG(dim == dimOfWorld)("dim!=dimOfWorld not yet implemented\n"); /* wir haben das gleichungssystem zu loesen: */ /* ( q1x q2x q3x) (lambda1) (qx) */ /* ( q1y q2y q3y) (lambda2) = (qy) */ /* ( q1z q2z q3z) (lambda3) (qz) */ /* mit qi=pi-p3, q=xy-p3 */ for (int j = 0; j < dimOfWorld; j++) { x0 = coord_[dim][j]; x[j] = xy[j] - x0; for (int i = 0; i < dim; i++) edge[i][j] = coord_[i][j] - x0; } det = edge[0][0] * edge[1][1] * edge[2][2] + edge[0][1] * edge[1][2] * edge[2][0] + edge[0][2] * edge[1][0] * edge[2][1] - edge[0][2] * edge[1][1] * edge[2][0] - edge[0][0] * edge[1][2] * edge[2][1] - edge[0][1] * edge[1][0] * edge[2][2]; det0 = x[0] * edge[1][1] * edge[2][2] + x[1] * edge[1][2] * edge[2][0] + x[2] * edge[1][0] * edge[2][1] - x[2] * edge[1][1] * edge[2][0] - x[0] * edge[1][2] * edge[2][1] - x[1] * edge[1][0] * edge[2][2]; det1 = edge[0][0] * x[1] * edge[2][2] + edge[0][1] * x[2] * edge[2][0] + edge[0][2] * x[0] * edge[2][1] - edge[0][2] * x[1] * edge[2][0] - edge[0][0] * x[2] * edge[2][1] - edge[0][1] * x[0] * edge[2][2]; det2 = edge[0][0] * edge[1][1] * x[2] + edge[0][1] * edge[1][2] * x[0] + edge[0][2] * edge[1][0] * x[1] - edge[0][2] * edge[1][1] * x[0] - edge[0][0] * edge[1][2] * x[1] - edge[0][1] * edge[1][0] * x[2]; 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] = det2 / det; (*lambda)[3] = 1.0 - (*lambda)[0] - (*lambda)[1] - (*lambda)[2]; 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; } /****************************************************************************/ /* update EL_INFO structure after refinement (of some neighbours) */ /****************************************************************************/ void ElInfo3d::update() { FUNCNAME("ElInfo::update()"); int neighbours = mesh_->getGeo(NEIGH); int vertices = mesh_->getGeo(VERTEX); if (fillFlag_.isSet(Mesh::FILL_NEIGH) || fillFlag_.isSet(Mesh::FILL_OPP_COORDS)) { Tetrahedron *nb; Flag fill_opp_coords = fillFlag_ & Mesh::FILL_OPP_COORDS; for (int ineigh = 0; ineigh < neighbours; ineigh++) { if ((nb = dynamic_cast<Tetrahedron*>(const_cast<Element*>(neighbour_[ineigh])))) { int ov = oppVertex_[ineigh]; if (ov < 2 && nb->getFirstChild()) { if (fill_opp_coords != Flag(0)) { int k = -1; for (int j = 0; j < vertices; j++) if (element_->getDOF(j) == nb->getDOF(1 - ov)) k = j; if (k == -1) { for (int j = 0; j < vertices; j++) { if (mesh_->associated(element_->getDOF(j, 0), nb->getDOF(1 - ov, 0))) { k = j; } } } TEST_EXIT_DBG(k >= 0)("neighbour dof not found\n"); if (nb->isNewCoordSet()) oppCoord_[ineigh] = *(nb->getNewCoord()); else for (int j = 0; j < dimOfWorld; j++) oppCoord_[ineigh][j] = (oppCoord_[ineigh][j] + coord_[k][j]) / 2; } neighbour_[ineigh] = dynamic_cast<Tetrahedron*>(const_cast<Element*>(nb->getChild(1-ov))); oppVertex_[ineigh] = 3; } } } } } double ElInfo3d::getNormal(int face, WorldVector<double> &normal) { FUNCNAME("ElInfo3d::getNormal()"); double det = 0.0; WorldVector<double> *e0 = &tmpWorldVecs[0]; WorldVector<double> *e1 = &tmpWorldVecs[1]; WorldVector<double> *e2 = &tmpWorldVecs[2]; if (dimOfWorld == 3) { int i0 = (face + 1) % 4; int i1 = (face + 2) % 4; int i2 = (face + 3) % 4; for (int i = 0; i < dimOfWorld; i++) { (*e0)[i] = coord_[i1][i] - coord_[i0][i]; (*e1)[i] = coord_[i2][i] - coord_[i0][i]; (*e2)[i] = coord_[face][i] - coord_[i0][i]; } vectorProduct(*e0, *e1, normal); if ((*e2 * normal) < 0.0) for (int i = 0; i < dimOfWorld; i++) normal[i] = -normal[i]; det = norm(&normal); TEST_EXIT_DBG(det > 1.e-30)("det = 0 on face %d\n", face); normal[0] /= det; normal[1] /= det; normal[2] /= det; } else { MSG("not implemented for DIM_OF_WORLD = %d in 3d\n", dimOfWorld); } return(det); } void ElInfo3d::fillElInfo(int ichild, const ElInfo *elinfo_old) { FUNCNAME("ElInfo3d::fillElInfo()"); int ochild = 0; /* index of other child = 1-ichild */ int *cv = NULL; /* cv = child_vertex[el_type][ichild] */ const int (*cvg)[4] = NULL; /* cvg = child_vertex[el_type] */ int *ce; /* ce = child_edge[el_type][ichild] */ Element *nb, *nbk; Element *el_old = elinfo_old->element_; Flag fillFlag__local = elinfo_old->fillFlag_; DegreeOfFreedom *dof; int ov = -1; Mesh *mesh = elinfo_old->getMesh(); TEST_EXIT_DBG(el_old->getChild(0))("missing child?\n"); element_ = const_cast<Element*>( el_old->getChild(ichild)); macroElement_ = elinfo_old->macroElement_; fillFlag_ = fillFlag__local; parent_ = el_old; level_ = elinfo_old->level_ + 1; int el_type_local = (dynamic_cast<const ElInfo3d*>(elinfo_old))->getType(); el_type = (el_type_local + 1) % 3; TEST_EXIT_DBG(element_)("missing child %d?\n", ichild); if (fillFlag__local.isAnySet()) { cvg = Tetrahedron::childVertex[el_type_local]; cv = const_cast<int*>(cvg[ichild]); ochild = 1 - ichild; } if (fillFlag__local.isSet(Mesh::FILL_COORDS) || fillFlag_.isSet(Mesh::FILL_DET) || fillFlag_.isSet(Mesh::FILL_GRD_LAMBDA)) { for (int i = 0; i < 3; i++) { for (int j = 0; j < dimOfWorld; j++) { coord_[i][j] = elinfo_old->coord_[cv[i]][j]; } } if (el_old->getNewCoord()) { coord_[3] = *(el_old->getNewCoord()); } else { for (int j = 0; j < dimOfWorld; j++) { coord_[3][j] = (elinfo_old->coord_[0][j] + elinfo_old->coord_[1][j]) / 2; } } } if (fillFlag__local.isSet(Mesh::FILL_NEIGH) || fillFlag_.isSet(Mesh::FILL_OPP_COORDS)) { FixVec<Element*, NEIGH> *neigh_local = &neighbour_; const FixVec<Element*, NEIGH> *neigh_old = &elinfo_old->neighbour_; Flag fill_opp_coords; fill_opp_coords.setFlags(fillFlag__local & Mesh::FILL_OPP_COORDS); /*----- nb[0] is other child --------------------------------------------*/ /* if (nb = el_old->child[ochild]) old version */ if (el_old->getChild(0) && (nb = const_cast<Element*>( el_old->getChild(ochild)))) { if (nb->getChild(0)) { /* go down one level for direct neighbour */ if (fill_opp_coords.isAnySet()) { if (nb->getNewCoord()) { oppCoord_[0]= *(nb->getNewCoord()); } else { int k = cvg[ochild][1]; for (int j = 0; j < dimOfWorld; j++) { oppCoord_[0][j] = (elinfo_old->coord_[ochild][j] + elinfo_old->coord_[k][j]) / 2; } } } (*neigh_local)[0] = const_cast<Element*>( nb->getChild(1)); oppVertex_[0] = 3; } else { if (fill_opp_coords.isAnySet()) { for (int j = 0; j < dimOfWorld; j++) { oppCoord_[0][j] = elinfo_old->coord_[ochild][j]; } } (*neigh_local)[0] = nb; oppVertex_[0] = 0; } } else { ERROR_EXIT("no other child"); (*neigh_local)[0] = NULL; } /*----- nb[1],nb[2] are childs of old neighbours nb_old[cv[i]] ----------*/ for (int i = 1; i < 3; i++) { if ((nb = const_cast<Element*>( (*neigh_old)[cv[i]]))) { TEST_EXIT_DBG(nb->getChild(0))("nonconforming triangulation\n"); int k; for (k = 0; k < 2; k++) { /* look at both childs of old neighbour */ nbk = const_cast<Element*>( nb->getChild(k)); if (nbk->getDOF(0) == el_old->getDOF(ichild)) { /* opp. vertex */ dof = const_cast<int*>(nb->getDOF(elinfo_old->oppVertex_[cv[i]])); if (dof == nbk->getDOF(1)) { ov = 1; if (nbk->getChild(0)) { if (fill_opp_coords.isAnySet()) { if (nbk->getNewCoord()) { oppCoord_[i] = *(nbk->getNewCoord()); } else { for (int j = 0; j < dimOfWorld; j++) { oppCoord_[i][j] = (elinfo_old->oppCoord_[cv[i]][j] + elinfo_old->coord_[ichild][j]) / 2; } } } (*neigh_local)[i] = nbk->getChild(0); oppVertex_[i] = 3; break; } } else { if (dof != nbk->getDOF(2)) { ov = -1; break; } ov = 2; } if (fill_opp_coords.isAnySet()) { for (int j = 0; j < dimOfWorld; j++) { oppCoord_[i][j] = elinfo_old->oppCoord_[cv[i]][j]; } } (*neigh_local)[i] = nbk; oppVertex_[i] = ov; break; } } /* end for k */ // periodic ? if (k == 2 || ov == -1) { for (k = 0; k < 2; k++) { /* look at both childs of old neighbour */ nbk = const_cast<Element*>( nb->getChild(k)); if (nbk->getDOF(0) == el_old->getDOF(ichild) || mesh->associated(nbk->getDOF(0, 0), el_old->getDOF(ichild, 0))) { /* opp. vertex */ dof = const_cast<int*>(nb->getDOF(elinfo_old->oppVertex_[cv[i]])); if (dof == nbk->getDOF(1) || mesh->associated(dof[0], nbk->getDOF(1, 0))) { ov = 1; if (nbk->getChild(0)) { if (fill_opp_coords.isAnySet()) { if (nbk->getNewCoord()) { oppCoord_[i] = *(nbk->getNewCoord()); } else { for (int j = 0; j < dimOfWorld; j++) { oppCoord_[i][j] = (elinfo_old->oppCoord_[cv[i]][j] + elinfo_old->coord_[ichild][j]) / 2; } } } (*neigh_local)[i] = nbk->getChild(0); oppVertex_[i] = 3; break; } } else { TEST_EXIT_DBG(dof == nbk->getDOF(2) || mesh->associated(dof[0], nbk->getDOF(2, 0))) ("opp_vertex not found\n"); ov = 2; } if (fill_opp_coords.isAnySet()) { for (int j = 0; j < dimOfWorld; j++) { oppCoord_[i][j] = elinfo_old->oppCoord_[cv[i]][j]; } } (*neigh_local)[i] = nbk; oppVertex_[i] = ov; break; } } /* end for k */ TEST_EXIT_DBG(k < 2)("child not found with vertex\n"); } } else { (*neigh_local)[i] = NULL; } } /* end for i */ /*----- nb[3] is old neighbour neigh_old[ochild] ------------------------*/ if (((*neigh_local)[3] = (*neigh_old)[ochild])) { oppVertex_[3] = elinfo_old->oppVertex_[ochild]; if (fill_opp_coords.isAnySet()) { for (int j = 0; j < dimOfWorld; j++) { oppCoord_[3][j] = elinfo_old->oppCoord_[ochild][j]; } } } } if (fillFlag__local.isSet(Mesh::FILL_BOUND)) { for (int i = 0; i < 3; i++) { boundary_[10 + i] = elinfo_old->getBoundary(10 + cv[i]); } boundary_[13] = elinfo_old->getBoundary(4); boundary_[0] = INTERIOR; boundary_[1] = elinfo_old->getBoundary(cv[1]); boundary_[2] = elinfo_old->getBoundary(cv[2]); boundary_[3] = elinfo_old->getBoundary(ochild); int geoFace = mesh_->getGeo(FACE); ce = const_cast<int*>(Tetrahedron::childEdge[el_type_local][ichild]); for (int iedge = 0; iedge < 4; iedge++) { boundary_[geoFace + iedge] = elinfo_old->getBoundary(geoFace + ce[iedge]); } for (int iedge = 4; iedge < 6; iedge++) { int i = 5 - cv[iedge - 3]; /* old vertex opposite new edge */ boundary_[geoFace + iedge] = elinfo_old->getBoundary(i); } if (elinfo_old->getProjection(0) && elinfo_old->getProjection(0)->getType() == VOLUME_PROJECTION) { projection_[0] = elinfo_old->getProjection(0); } else { // boundary projection projection_[0] = NULL; projection_[1] = elinfo_old->getProjection(cv[1]); projection_[2] = elinfo_old->getProjection(cv[2]); projection_[3] = elinfo_old->getProjection(ochild); for (int iedge = 0; iedge < 4; iedge++) { projection_[geoFace + iedge] = elinfo_old->getProjection(geoFace + ce[iedge]); } for (int iedge = 4; iedge < 6; iedge++) { projection_[geoFace + iedge] = elinfo_old->getProjection(5 - cv[iedge - 3]); } } } if (fillFlag_.isSet(Mesh::FILL_ORIENTATION)) { orientation = ( dynamic_cast<ElInfo3d*>(const_cast<ElInfo*>(elinfo_old)))->orientation * Tetrahedron::childOrientation[el_type_local][ichild]; } } }